ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.29
Committed: Mon Jan 29 16:11:48 2007 UTC (17 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.28: +8 -5 lines
Log Message:
- add visibility_at to players (only), might/should be an object method
- mood spells only affect visible spaces now.

File Contents

# Content
1 /*
2 * CrossFire, A Multiplayer game for X-windows
3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5 * Copyright (C) 2002-2003 Mark Wedel & Crossfire Development Team
6 * Copyright (C) 1992 Frank Tore Johansen
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * The authors can be reached via e-mail at <crossfire@schmorp.de>
23 */
24
25 /* This file contains all the spell attack code. Grouping this code
26 * together should hopefully make it easier to find the relevent bits
27 * of code
28 */
29
30 #include <global.h>
31 #include <object.h>
32 #include <living.h>
33 #include <sproto.h>
34 #include <spells.h>
35 #include <sounds.h>
36
37 /* this function checks to see if a spell pushes objects as well
38 * as flies over and damages them (only used for cones for now)
39 * but moved here so it could be applied to bolts too
40 * op is the spell object.
41 */
42
43 void
44 check_spell_knockback (object *op)
45 {
46 object *tmp, *tmp2; /* object on the map */
47 int weight_move;
48 int frictionmod = 2; /*poor man's physics - multipy targets weight by this amount */
49
50 if (!op->weight)
51 { /*shouldn't happen but if cone object has no weight drop out */
52 /*LOG (llevDebug, "DEBUG: arch weighs nothing\n"); */
53 return;
54 }
55 else
56 {
57 weight_move = op->weight + (op->weight * op->level) / 3;
58 /*LOG (llevDebug, "DEBUG: arch weighs %d and masses %d (%s,level %d)\n", op->weight,weight_move,op->name,op->level); */
59 }
60
61 for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above)
62 {
63 int num_sections = 1;
64
65 /* don't move DM */
66 if (QUERY_FLAG (tmp, FLAG_WIZ))
67 return;
68
69 /* don't move parts of objects */
70 if (tmp->head)
71 continue;
72
73 /* don't move floors or immobile objects */
74 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR) || (!QUERY_FLAG (tmp, FLAG_ALIVE) && QUERY_FLAG (tmp, FLAG_NO_PICK)))
75 continue;
76
77 /* count the object's sections */
78 for (tmp2 = tmp; tmp2 != NULL; tmp2 = tmp2->more)
79 num_sections++;
80
81 /* I'm not sure if it makes sense to divide by num_sections - bigger
82 * objects should be harder to move, and we are moving the entire
83 * object, not just the head, so the total weight should be relevant.
84 */
85
86 /* surface area? -tm */
87
88 if (tmp->move_type & MOVE_FLYING)
89 frictionmod = 1; /* flying objects loose the friction modifier */
90
91 if (rndm (0, weight_move - 1) > ((tmp->weight / num_sections) * frictionmod))
92 { /* move it. */
93 /* move_object is really for monsters, but looking at
94 * the move_object function, it appears that it should
95 * also be safe for objects.
96 * This does return if successful or not, but
97 * I don't see us doing anything useful with that information
98 * right now.
99 */
100 move_object (tmp, absdir (op->stats.sp));
101 }
102
103 }
104 }
105
106 /***************************************************************************
107 *
108 * BOLT CODE
109 *
110 ***************************************************************************/
111
112 /* Causes op to fork. op is the original bolt, tmp
113 * is the first piece of the fork.
114 */
115
116 void
117 forklightning (object *op, object *tmp)
118 {
119 int new_dir = 1; /* direction or -1 for left, +1 for right 0 if no new bolt */
120 int t_dir; /* stores temporary dir calculation */
121 maptile *m;
122 sint16 sx, sy;
123 object *new_bolt;
124
125 /* pick a fork direction. tmp->stats.Con is the left bias
126 * i.e., the chance in 100 of forking LEFT
127 * Should start out at 50, down to 25 for one already going left
128 * down to 0 for one going 90 degrees left off original path
129 */
130
131 if (rndm (0, 99) < tmp->stats.Con) /* fork left */
132 new_dir = -1;
133
134 /* check the new dir for a wall and in the map */
135 t_dir = absdir (tmp->direction + new_dir);
136
137 if (get_map_flags (tmp->map, &m, tmp->x + freearr_x[t_dir], tmp->y + freearr_y[t_dir], &sx, &sy) & P_OUT_OF_MAP)
138 return;
139
140 if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (m, sx, sy)))
141 return;
142
143 /* OK, we made a fork */
144 new_bolt = tmp->clone ();
145
146 /* reduce chances of subsequent forking */
147 new_bolt->stats.Dex -= 10;
148 tmp->stats.Dex -= 10; /* less forks from main bolt too */
149 new_bolt->stats.Con += 25 * new_dir; /* adjust the left bias */
150 new_bolt->speed_left = -0.1;
151 new_bolt->direction = t_dir;
152 new_bolt->duration++;
153 new_bolt->stats.dam /= 2; /* reduce daughter bolt damage */
154 new_bolt->stats.dam++;
155 tmp->stats.dam /= 2; /* reduce father bolt damage */
156 tmp->stats.dam++;
157 if ((new_bolt = m->insert (new_bolt, sx, sy, op)))
158 update_turn_face (new_bolt);
159 }
160
161 /* move_bolt: moves bolt 'op'. Basically, it just advances a space,
162 * and checks for various things that may stop it.
163 */
164
165 void
166 move_bolt (object *op)
167 {
168 object *tmp;
169 int mflags;
170 sint16 x, y;
171 maptile *m;
172
173 if (--op->duration < 0)
174 {
175 op->destroy ();
176 return;
177 }
178
179 hit_map (op, 0, op->attacktype, 1);
180
181 if (!op->direction)
182 return;
183
184 if (--op->range < 0)
185 op->range = 0;
186 else
187 {
188 x = op->x + DIRX (op);
189 y = op->y + DIRY (op);
190 m = op->map;
191 mflags = get_map_flags (m, &m, x, y, &x, &y);
192
193 if (mflags & P_OUT_OF_MAP)
194 return;
195
196 /* We are about to run into something - we may bounce */
197 /* Calling reflwall is pretty costly, as it has to look at all the objects
198 * on the space. So only call reflwall if we think the data it returns
199 * will be useful.
200 */
201 if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y)) || ((mflags & P_IS_ALIVE) && reflwall (m, x, y, op)))
202 {
203 if (!QUERY_FLAG (op, FLAG_REFLECTING))
204 return;
205
206 /* Since walls don't run diagonal, if the bolt is in
207 * one of 4 main directions, it just reflects back in the
208 * opposite direction. However, if the bolt is travelling
209 * on the diagonal, it is trickier - eg, a bolt travelling
210 * northwest bounces different if it hits a north/south
211 * wall (bounces to northeast) vs an east/west (bounces
212 * to the southwest.
213 */
214 if (op->direction & 1)
215 op->direction = absdir (op->direction + 4);
216 else
217 {
218 int left, right;
219 int mflags;
220
221 /* Need to check for P_OUT_OF_MAP: if the bolt is tavelling
222 * over a corner in a tiled map, it is possible that
223 * op->direction is within an adjacent map but either
224 * op->direction-1 or op->direction+1 does not exist.
225 */
226 mflags = get_map_flags (op->map, &m, op->x + freearr_x[absdir (op->direction - 1)],
227 op->y + freearr_y[absdir (op->direction - 1)], &x, &y);
228
229 left = (mflags & P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y));
230
231 mflags = get_map_flags (op->map, &m, op->x + freearr_x[absdir (op->direction + 1)],
232 op->y + freearr_y[absdir (op->direction + 1)], &x, &y);
233 right = (mflags & P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y));
234
235 if (left == right)
236 op->direction = absdir (op->direction + 4);
237 else if (left)
238 op->direction = absdir (op->direction + 2);
239 else if (right)
240 op->direction = absdir (op->direction - 2);
241 }
242
243 update_turn_face (op); /* A bolt *must* be IS_TURNABLE */
244 return;
245 }
246 else
247 { /* Create a copy of this object and put it ahead */
248 object *tmp = op->clone ();
249
250 m->insert (tmp, x, y, op);
251 tmp->speed_left = -0.1;
252 /* To make up for the decrease at the top of the function */
253 tmp->duration++;
254
255 /* New forking code. Possibly create forks of this object
256 * going off in other directions.
257 */
258 if (rndm (0, 99) < tmp->stats.Dex)
259 { /* stats.Dex % of forking */
260 forklightning (op, tmp);
261 }
262
263 /* In this way, the object left behind sticks on the space, but
264 * doesn't create any bolts that continue to move onward.
265 */
266 op->range = 0;
267 } /* copy object and move it along */
268 } /* if move bolt along */
269 }
270
271 /* fire_bolt
272 * object op (cast from caster) files a bolt in dir.
273 * spob is the spell object for the bolt.
274 * we remove the magic flag - that can be derived from
275 * spob->attacktype.
276 * This function sets up the appropriate owner and skill
277 * pointers.
278 */
279 int
280 fire_bolt (object *op, object *caster, int dir, object *spob, object *skill)
281 {
282 object *tmp = NULL;
283 int mflags;
284
285 if (!spob->other_arch)
286 return 0;
287
288 tmp = arch_to_object (spob->other_arch);
289 if (tmp == NULL)
290 return 0;
291
292 /* peterm: level dependency for bolts */
293 tmp->stats.dam = spob->stats.dam + SP_level_dam_adjust (caster, spob);
294 tmp->attacktype = spob->attacktype;
295 if (spob->slaying)
296 tmp->slaying = spob->slaying;
297 tmp->range = spob->range + SP_level_range_adjust (caster, spob);
298 tmp->duration = spob->duration + SP_level_duration_adjust (caster, spob);
299 tmp->stats.Dex = spob->stats.Dex;
300 tmp->stats.Con = spob->stats.Con;
301
302 tmp->direction = dir;
303 if (QUERY_FLAG (tmp, FLAG_IS_TURNABLE))
304 SET_ANIMATION (tmp, dir);
305
306 tmp->set_owner (op);
307 set_spell_skill (op, caster, spob, tmp);
308
309 tmp->x = op->x + DIRX (tmp);
310 tmp->y = op->y + DIRY (tmp);
311 tmp->map = op->map;
312
313 maptile *newmap;
314 mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y);
315 if (mflags & P_OUT_OF_MAP)
316 {
317 tmp->destroy ();
318 return 0;
319 }
320
321 tmp->map = newmap;
322
323 if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y)))
324 {
325 if (!QUERY_FLAG (tmp, FLAG_REFLECTING))
326 {
327 tmp->destroy ();
328 return 0;
329 }
330
331 tmp->x = op->x;
332 tmp->y = op->y;
333 tmp->direction = absdir (tmp->direction + 4);
334 tmp->map = op->map;
335 }
336
337 if ((tmp = tmp->insert_at (tmp, op)))
338 move_bolt (tmp);
339
340 return 1;
341 }
342
343
344
345 /***************************************************************************
346 *
347 * BULLET/BALL CODE
348 *
349 ***************************************************************************/
350
351 /* expands an explosion. op is a piece of the
352 * explosion - this expans it in the different directions.
353 * At least that is what I think this does.
354 */
355 void
356 explosion (object *op)
357 {
358 maptile *m = op->map;
359 int i;
360
361 if (--op->duration < 0)
362 {
363 op->destroy ();
364 return;
365 }
366
367 hit_map (op, 0, op->attacktype, 0);
368
369 if (op->range > 0)
370 {
371 for (i = 1; i < 9; i++)
372 {
373 sint16 dx, dy;
374
375 dx = op->x + freearr_x[i];
376 dy = op->y + freearr_y[i];
377
378 /* ok_to_put_more already does things like checks for walls,
379 * out of map, etc.
380 */
381 if (ok_to_put_more (op->map, dx, dy, op, op->attacktype))
382 {
383 object *tmp = op->clone ();
384
385 tmp->state = 0;
386 tmp->speed_left = -0.21;
387 tmp->range--;
388 tmp->value = 0;
389
390 m->insert (tmp, dx, dy, op);
391 }
392 }
393 }
394 }
395
396
397 /* Causes an object to explode, eg, a firebullet,
398 * poison cloud ball, etc. op is the object to
399 * explode.
400 */
401 void
402 explode_bullet (object *op)
403 {
404 object *tmp, *owner;
405
406 if (op->other_arch == NULL)
407 {
408 LOG (llevError, "BUG: explode_bullet(): op without other_arch\n");
409 op->destroy ();
410 return;
411 }
412
413 if (op->env)
414 {
415 object *env = object_get_env_recursive (op);
416 if (env->map == NULL || out_of_map (env->map, env->x, env->y))
417 {
418 LOG (llevError, "BUG: explode_bullet(): env out of map\n");
419 op->destroy ();
420 return;
421 }
422
423 op->insert_at (env, op, INS_NO_MERGE | INS_NO_WALK_ON);
424 }
425 else if (out_of_map (op->map, op->x, op->y))
426 {
427 LOG (llevError, "BUG: explode_bullet(): op out of map\n");
428 op->destroy ();
429 return;
430 }
431
432 // elmex Tue Aug 15 17:46:51 CEST 2006: Prevent explosions of any kind on safe maps
433 // NOTE: If this breaks something important: remove this. I can't think of anything
434 // bad at the moment that might happen from this.
435 if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE)
436 {
437 op->destroy ();
438 return;
439 }
440
441 if (op->attacktype)
442 {
443 hit_map (op, 0, op->attacktype, 1);
444 if (op->destroyed ())
445 return;
446 }
447
448 /* other_arch contains what this explodes into */
449 tmp = arch_to_object (op->other_arch);
450
451 tmp->set_owner (op);
452 tmp->skill = op->skill;
453
454 owner = op->owner;
455
456 if ((tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER) && owner && !tailor_god_spell (tmp, owner))
457 {
458 op->destroy ();
459 return;
460 }
461
462 /* special for bombs - it actually has sane values for these */
463 if (op->type == SPELL_EFFECT && op->subtype == SP_BOMB)
464 {
465 tmp->attacktype = op->attacktype;
466 tmp->range = op->range;
467 tmp->stats.dam = op->stats.dam;
468 tmp->duration = op->duration;
469 }
470 else
471 {
472 if (op->attacktype & AT_MAGIC)
473 tmp->attacktype |= AT_MAGIC;
474
475 /* Spell doc describes what is going on here */
476 tmp->stats.dam = op->dam_modifier;
477 tmp->range = op->stats.maxhp;
478 tmp->duration = op->stats.hp;
479 /* Used for spell tracking - just need a unique val for this spell -
480 * the count of the parent should work fine.
481 */
482 tmp->stats.maxhp = op->count;
483 }
484
485 /* Set direction of cone explosion */
486 if (tmp->type == SPELL_EFFECT && tmp->subtype == SP_CONE)
487 tmp->stats.sp = op->direction;
488
489 /* Prevent recursion */
490 op->move_on = 0;
491
492 tmp->insert_at (op, op);
493 /* remove the firebullet */
494 op->destroy ();
495 }
496
497 /* checks to see what op should do, given the space it is on
498 * (eg, explode, damage player, etc)
499 */
500 void
501 check_bullet (object *op)
502 {
503 object *tmp;
504 int dam, mflags;
505 maptile *m;
506 sint16 sx, sy;
507
508 mflags = get_map_flags (op->map, &m, op->x, op->y, &sx, &sy);
509
510 if (!(mflags & P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, sx, sy)))
511 return;
512
513 if (op->other_arch)
514 {
515 /* explode object will also remove op */
516 explode_bullet (op);
517 return;
518 }
519
520 /* If nothing alive on this space, no reason to do anything further */
521 if (!(mflags & P_IS_ALIVE))
522 return;
523
524 for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above)
525 {
526 if (QUERY_FLAG (tmp, FLAG_ALIVE))
527 {
528 dam = hit_player (tmp, op->stats.dam, op, op->attacktype, 1);
529 if (op->destroyed () || !tmp->destroyed () || (op->stats.dam -= dam) < 0)
530 {
531 if (!QUERY_FLAG (op, FLAG_REMOVED))
532 {
533 op->destroy ();
534 return;
535 }
536 }
537 }
538 }
539 }
540
541 /* Basically, we move 'op' one square, and if it hits something,
542 * call check_bullet.
543 * This function is only applicable to bullets, but not to all
544 * fired arches (eg, bolts).
545 */
546 void
547 move_bullet (object *op)
548 {
549 sint16 new_x, new_y;
550 int mflags;
551 maptile *m;
552
553 #if 0
554 /* We need a better general purpose way to do this */
555
556 /* peterm: added to make comet leave a trail of burnouts
557 it's an unadulterated hack, but the effect is cool. */
558 if (op->stats.sp == SP_METEOR)
559 {
560 replace_insert_ob_in_map ("fire_trail", op);
561 if (op->destroyed ())
562 return;
563 } /* end addition. */
564 #endif
565
566 /* Reached the end of its life - remove it */
567 if (--op->range <= 0)
568 {
569 if (op->other_arch)
570 explode_bullet (op);
571 else
572 op->destroy ();
573
574 return;
575 }
576
577 new_x = op->x + DIRX (op);
578 new_y = op->y + DIRY (op);
579 m = op->map;
580 mflags = get_map_flags (m, &m, new_x, new_y, &new_x, &new_y);
581
582 if (mflags & P_OUT_OF_MAP)
583 {
584 op->destroy ();
585 return;
586 }
587
588 if (!op->direction || OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, new_x, new_y)))
589 {
590 if (op->other_arch)
591 explode_bullet (op);
592 else
593 op->destroy ();
594
595 return;
596 }
597
598 if (!(op = m->insert (op, new_x, new_y, op)))
599 return;
600
601 if (reflwall (op->map, op->x, op->y, op))
602 {
603 op->direction = absdir (op->direction + 4);
604 update_turn_face (op);
605 }
606 else
607 check_bullet (op);
608 }
609
610
611
612
613 /* fire_bullet
614 * object op (cast from caster) files a bolt in dir.
615 * spob is the spell object for the bolt.
616 * we remove the magic flag - that can be derived from
617 * spob->attacktype.
618 * This function sets up the appropriate owner and skill
619 * pointers.
620 */
621
622 int
623 fire_bullet (object *op, object *caster, int dir, object *spob)
624 {
625 object *tmp = NULL;
626 int mflags;
627
628 if (!spob->other_arch)
629 return 0;
630
631 tmp = arch_to_object (spob->other_arch);
632 if (tmp == NULL)
633 return 0;
634
635 /* peterm: level dependency for bolts */
636 tmp->stats.dam = spob->stats.dam + SP_level_dam_adjust (caster, spob);
637 tmp->attacktype = spob->attacktype;
638 if (spob->slaying)
639 tmp->slaying = spob->slaying;
640
641 tmp->range = 50;
642
643 /* Need to store duration/range for the ball to use */
644 tmp->stats.hp = spob->duration + SP_level_duration_adjust (caster, spob);
645 tmp->stats.maxhp = spob->range + SP_level_range_adjust (caster, spob);
646 tmp->dam_modifier = spob->stats.food + SP_level_dam_adjust (caster, spob);
647
648 tmp->direction = dir;
649 if (QUERY_FLAG (tmp, FLAG_IS_TURNABLE))
650 SET_ANIMATION (tmp, dir);
651
652 tmp->set_owner (op);
653 set_spell_skill (op, caster, spob, tmp);
654
655 tmp->x = op->x + freearr_x[dir];
656 tmp->y = op->y + freearr_y[dir];
657 tmp->map = op->map;
658
659 maptile *newmap;
660 mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y);
661 if (mflags & P_OUT_OF_MAP)
662 {
663 tmp->destroy ();
664 return 0;
665 }
666
667 tmp->map = newmap;
668
669 if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y)))
670 {
671 if (!QUERY_FLAG (tmp, FLAG_REFLECTING))
672 {
673 tmp->destroy ();
674 return 0;
675 }
676
677 tmp->x = op->x;
678 tmp->y = op->y;
679 tmp->direction = absdir (tmp->direction + 4);
680 tmp->map = op->map;
681 }
682
683 if ((tmp = tmp->insert_at (tmp, op)))
684 check_bullet (tmp);
685
686 return 1;
687 }
688
689
690
691
692 /*****************************************************************************
693 *
694 * CONE RELATED FUNCTIONS
695 *
696 *****************************************************************************/
697
698
699 /* drops an object based on what is in the cone's "other_arch" */
700 void
701 cone_drop (object *op)
702 {
703 object *new_ob = arch_to_object (op->other_arch);
704
705 new_ob->level = op->level;
706 new_ob->set_owner (op->owner);
707
708 /* preserve skill ownership */
709 if (op->skill && op->skill != new_ob->skill)
710 new_ob->skill = op->skill;
711
712 new_ob->insert_at (op, op);
713 }
714
715 /* move_cone: causes cone object 'op' to move a space/hit creatures */
716
717 void
718 move_cone (object *op)
719 {
720 int i;
721
722 /* if no map then hit_map will crash so just ignore object */
723 if (!op->map)
724 {
725 LOG (llevError, "Tried to move_cone object %s without a map.\n", op->name ? &op->name : "unknown");
726 op->set_speed (0);
727 return;
728 }
729
730 /* lava saves it's life, but not yours :) */
731 if (QUERY_FLAG (op, FLAG_LIFESAVE))
732 {
733 hit_map (op, 0, op->attacktype, 0);
734 return;
735 }
736
737 #if 0
738 /* Disable this - enabling it makes monsters easier, as
739 * when their cone dies when they die.
740 */
741 /* If no owner left, the spell dies out. */
742 if (op->owner == NULL)
743 {
744 op->destroy ();
745 return;
746 }
747 #endif
748
749 hit_map (op, 0, op->attacktype, 0);
750
751 /* Check to see if we should push anything.
752 * Spell objects with weight push whatever they encounter to some
753 * degree.
754 */
755 if (op->weight)
756 check_spell_knockback (op);
757
758 if (op->destroyed ())
759 return;
760
761 if ((op->duration--) < 0)
762 {
763 op->destroy ();
764 return;
765 }
766 /* Object has hit maximum range, so don't have it move
767 * any further. When the duration above expires,
768 * then the object will get removed.
769 */
770 if (--op->range < 0)
771 {
772 op->range = 0; /* just so it doesn't wrap */
773 return;
774 }
775
776 for (i = -1; i < 2; i++)
777 {
778 sint16 x = op->x + freearr_x[absdir (op->stats.sp + i)], y = op->y + freearr_y[absdir (op->stats.sp + i)];
779
780 if (ok_to_put_more (op->map, x, y, op, op->attacktype))
781 {
782 object *tmp = op->clone ();
783
784 tmp->duration = op->duration + 1;
785
786 /* Use for spell tracking - see ok_to_put_more() */
787 tmp->stats.maxhp = op->stats.maxhp;
788
789 op->map->insert (tmp, x, y, op);
790
791 if (tmp->other_arch)
792 cone_drop (tmp);
793 }
794 }
795 }
796
797 /* cast_cone: casts a cone spell.
798 * op: person firing the object.
799 * caster: object casting the spell.
800 * dir: direction to fire in.
801 * spell: spell that is being fired. It uses other_arch for the archetype
802 * to fire.
803 * returns 0 on failure, 1 on success.
804 */
805 int
806 cast_cone (object *op, object *caster, int dir, object *spell)
807 {
808 object *tmp;
809 int i, success = 0, range_min = -1, range_max = 1;
810 maptile *m;
811 sint16 sx, sy;
812 MoveType movetype;
813
814 if (!spell->other_arch)
815 return 0;
816
817 if (op->type == PLAYER && QUERY_FLAG (op, FLAG_UNDEAD) && op->attacktype & AT_TURN_UNDEAD)
818 {
819 new_draw_info (NDI_UNIQUE, 0, op, "Your undead nature prevents you from turning undead!");
820 return 0;
821 }
822
823 if (!dir)
824 {
825 range_min = 0;
826 range_max = 8;
827 }
828
829 /* Need to know what the movetype of the object we are about
830 * to create is, so we can know if the space we are about to
831 * insert it into is blocked.
832 */
833 movetype = spell->other_arch->clone.move_type;
834
835 for (i = range_min; i <= range_max; i++)
836 {
837 sint16 x, y, d;
838
839 /* We can't use absdir here, because it never returns
840 * 0. If this is a rune, we want to hit the person on top
841 * of the trap (d==0). If it is not a rune, then we don't want
842 * to hit that person.
843 */
844 d = dir + i;
845 while (d < 0)
846 d += 8;
847 while (d > 8)
848 d -= 8;
849
850 /* If it's not a rune, we don't want to blast the caster.
851 * In that case, we have to see - if dir is specified,
852 * turn this into direction 8. If dir is not specified (all
853 * direction) skip - otherwise, one line would do more damage
854 * becase 0 direction will go through 9 directions - necessary
855 * for the rune code.
856 */
857 if (caster->type != RUNE && d == 0)
858 {
859 if (dir != 0)
860 d = 8;
861 else
862 continue;
863 }
864
865 x = op->x + freearr_x[d];
866 y = op->y + freearr_y[d];
867
868 if (get_map_flags (op->map, &m, x, y, &sx, &sy) & P_OUT_OF_MAP)
869 continue;
870
871 if ((movetype & GET_MAP_MOVE_BLOCK (m, sx, sy)) == movetype)
872 continue;
873
874 success = 1;
875 tmp = arch_to_object (spell->other_arch);
876 tmp->set_owner (op);
877 set_spell_skill (op, caster, spell, tmp);
878 tmp->level = caster_level (caster, spell);
879 tmp->attacktype = spell->attacktype;
880
881 /* holy word stuff */
882 if ((tmp->attacktype & AT_HOLYWORD) || (tmp->attacktype & AT_GODPOWER))
883 if (!tailor_god_spell (tmp, op))
884 return 0;
885
886 if (dir)
887 tmp->stats.sp = dir;
888 else
889 tmp->stats.sp = i;
890
891 tmp->range = spell->range + SP_level_range_adjust (caster, spell);
892
893 /* If casting it in all directions, it doesn't go as far */
894 if (dir == 0)
895 {
896 tmp->range /= 4;
897 if (tmp->range < 2 && spell->range >= 2)
898 tmp->range = 2;
899 }
900
901 tmp->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
902 tmp->duration = spell->duration + SP_level_duration_adjust (caster, spell);
903
904 /* Special bonus for fear attacks */
905 if (tmp->attacktype & AT_FEAR)
906 {
907 if (caster->type == PLAYER)
908 tmp->duration += fear_bonus[caster->stats.Cha];
909 else
910 tmp->duration += caster->level / 3;
911 }
912
913 if (tmp->attacktype & (AT_HOLYWORD | AT_TURN_UNDEAD))
914 {
915 if (caster->type == PLAYER)
916 tmp->duration += turn_bonus[caster->stats.Wis] / 5;
917 else
918 tmp->duration += caster->level / 3;
919 }
920
921 if (!(tmp->move_type & MOVE_FLY_LOW))
922 LOG (llevDebug, "cast_cone(): arch %s doesn't have flying 1\n", &spell->other_arch->name);
923
924 if (!tmp->move_on && tmp->stats.dam)
925 LOG (llevDebug, "cast_cone(): arch %s doesn't have move_on set\n", &spell->other_arch->name);
926
927 m->insert (tmp, sx, sy, op);
928
929 /* This is used for tracking spells so that one effect doesn't hit
930 * a single space too many times.
931 */
932 tmp->stats.maxhp = tmp->count;
933
934 if (tmp->other_arch)
935 cone_drop (tmp);
936 }
937
938 return success;
939 }
940
941 /****************************************************************************
942 *
943 * BOMB related code
944 *
945 ****************************************************************************/
946
947
948 /* This handles an exploding bomb.
949 * op is the original bomb object.
950 */
951 void
952 animate_bomb (object *op)
953 {
954 int i;
955 object *env, *tmp;
956
957 if (op->state != NUM_ANIMATIONS (op) - 1)
958 return;
959
960 env = object_get_env_recursive (op);
961
962 if (op->env)
963 {
964 if (env->map == NULL)
965 return;
966
967 if (env->type == PLAYER)
968 esrv_del_item (env->contr, op->count);
969
970 if (!(op = op->insert_at (env, op)))
971 return;
972 }
973
974 // elmex Tue Aug 15 17:46:51 CEST 2006: Prevent bomb from exploding
975 // on a safe map. I don't like this special casing, but it seems to be neccessary
976 // as bombs can be carried.
977 if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE)
978 {
979 op->destroy ();
980 return;
981 }
982
983 /* This copies a lot of the code from the fire bullet,
984 * but using the cast_bullet isn't really feasible,
985 * so just set up the appropriate values.
986 */
987 if (archetype *at = archetype::find (SPLINT))
988 {
989 for (i = 1; i < 9; i++)
990 {
991 if (out_of_map (op->map, op->x + freearr_x[i], op->y + freearr_x[i]))
992 continue;
993
994 tmp = arch_to_object (at);
995 tmp->direction = i;
996 tmp->range = op->range;
997 tmp->stats.dam = op->stats.dam;
998 tmp->duration = op->duration;
999 tmp->attacktype = op->attacktype;
1000 tmp->set_owner (op);
1001 if (op->skill && op->skill != tmp->skill)
1002 tmp->skill = op->skill;
1003
1004 if (QUERY_FLAG (tmp, FLAG_IS_TURNABLE))
1005 SET_ANIMATION (tmp, i);
1006
1007 op->map->insert (tmp, op->x + freearr_x[i], op->y + freearr_x[i], op);
1008 move_bullet (tmp);
1009 }
1010 }
1011
1012 explode_bullet (op);
1013 }
1014
1015 int
1016 create_bomb (object *op, object *caster, int dir, object *spell)
1017 {
1018
1019 object *tmp;
1020 int mflags;
1021 sint16 dx = op->x + freearr_x[dir], dy = op->y + freearr_y[dir];
1022 maptile *m;
1023
1024 mflags = get_map_flags (op->map, &m, dx, dy, &dx, &dy);
1025 if ((mflags & P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK (m, dx, dy) & MOVE_WALK))
1026 {
1027 new_draw_info (NDI_UNIQUE, 0, op, "There is something in the way.");
1028 return 0;
1029 }
1030 tmp = arch_to_object (spell->other_arch);
1031
1032 /* level dependencies for bomb */
1033 tmp->range = spell->range + SP_level_range_adjust (caster, spell);
1034 tmp->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1035 tmp->duration = spell->duration + SP_level_duration_adjust (caster, spell);
1036 tmp->attacktype = spell->attacktype;
1037
1038 tmp->set_owner (op);
1039 set_spell_skill (op, caster, spell, tmp);
1040
1041 m->insert (tmp, dx, dy, op);
1042 return 1;
1043 }
1044
1045 /****************************************************************************
1046 *
1047 * smite related spell code.
1048 *
1049 ****************************************************************************/
1050
1051 /* get_pointed_target() - this is used by finger of death
1052 * and the 'smite' spells. Returns the pointer to the first
1053 * monster in the direction which is pointed to by op. b.t.
1054 * op is the caster - really only used for the source location.
1055 * dir is the direction to look in.
1056 * range is how far out to look.
1057 * type is the type of spell - either SPELL_MANA or SPELL_GRACE.
1058 * this info is used for blocked magic/unholy spaces.
1059 */
1060
1061 object *
1062 get_pointed_target (object *op, int dir, int range, int type)
1063 {
1064 object *target;
1065 sint16 x, y;
1066 int dist, mflags;
1067 maptile *mp;
1068
1069 if (dir == 0)
1070 return NULL;
1071
1072 for (dist = 1; dist < range; dist++)
1073 {
1074 x = op->x + freearr_x[dir] * dist;
1075 y = op->y + freearr_y[dir] * dist;
1076 mp = op->map;
1077 mflags = get_map_flags (op->map, &mp, x, y, &x, &y);
1078
1079 if (mflags & P_OUT_OF_MAP)
1080 return NULL;
1081 if ((type & SPELL_MANA) && (mflags & P_NO_MAGIC))
1082 return NULL;
1083 if ((type & SPELL_GRACE) && (mflags & P_NO_CLERIC))
1084 return NULL;
1085 if (GET_MAP_MOVE_BLOCK (mp, x, y) & MOVE_FLY_LOW)
1086 return NULL;
1087
1088 if (mflags & P_IS_ALIVE)
1089 {
1090 for (target = GET_MAP_OB (mp, x, y); target; target = target->above)
1091 {
1092 if (QUERY_FLAG (target->head ? target->head : target, FLAG_MONSTER))
1093 {
1094 return target;
1095 }
1096 }
1097 }
1098 }
1099 return NULL;
1100 }
1101
1102
1103 /* cast_smite_arch() - the priest points to a creature and causes
1104 * a 'godly curse' to decend.
1105 * usual params -
1106 * op = player
1107 * caster = object casting the spell.
1108 * dir = direction being cast
1109 * spell = spell object
1110 */
1111
1112 int
1113 cast_smite_spell (object *op, object *caster, int dir, object *spell)
1114 {
1115 object *effect, *target;
1116 object *god = find_god (determine_god (op));
1117 int range;
1118
1119 range = spell->range + SP_level_range_adjust (caster, spell);
1120 target = get_pointed_target (op, dir, 50, spell->stats.grace ? SPELL_GRACE : SPELL_MANA);
1121
1122 /* Bunch of conditions for casting this spell. Note that only
1123 * require a god if this is a cleric spell (requires grace).
1124 * This makes this spell much more general purpose - it can be used
1125 * by wizards also, which is good, because I think this is a very
1126 * interesting spell.
1127 * if it is a cleric spell, you need a god, and the creature
1128 * can't be friendly to your god.
1129 */
1130
1131 if (!target || QUERY_FLAG (target, FLAG_REFL_SPELL)
1132 || (!god && spell->stats.grace)
1133 || (target->title && god && !strcmp (target->title, god->name)) || (target->race && god && strstr (target->race, god->race)))
1134 {
1135 new_draw_info (NDI_UNIQUE, 0, op, "Your request is unheeded.");
1136 return 0;
1137 }
1138
1139 if (spell->other_arch)
1140 effect = arch_to_object (spell->other_arch);
1141 else
1142 return 0;
1143
1144 /* tailor the effect by priest level and worshipped God */
1145 effect->level = caster_level (caster, spell);
1146 effect->attacktype = spell->attacktype;
1147 if (effect->attacktype & (AT_HOLYWORD | AT_GODPOWER))
1148 {
1149 if (tailor_god_spell (effect, op))
1150 new_draw_info_format (NDI_UNIQUE, 0, op, "%s answers your call!", determine_god (op));
1151 else
1152 {
1153 new_draw_info (NDI_UNIQUE, 0, op, "Your request is ignored.");
1154 return 0;
1155 }
1156 }
1157
1158 /* size of the area of destruction */
1159 effect->range = spell->range + SP_level_range_adjust (caster, spell);
1160 effect->duration = spell->duration + SP_level_range_adjust (caster, spell);
1161
1162 if (effect->attacktype & AT_DEATH)
1163 {
1164 effect->level = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1165
1166 /* casting death spells at undead isn't a good thing */
1167 if (QUERY_FLAG (target, FLAG_UNDEAD))
1168 {
1169 if (random_roll (0, 2, op, PREFER_LOW))
1170 {
1171 new_draw_info (NDI_UNIQUE, 0, op, "Idiot! Your spell boomerangs!");
1172 effect->x = op->x;
1173 effect->y = op->y;
1174 }
1175 else
1176 {
1177 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s looks stronger!", query_name (target));
1178 target->stats.hp = target->stats.maxhp * 2;
1179 effect->destroy ();
1180 return 0;
1181 }
1182 }
1183 }
1184 else
1185 {
1186 /* how much woe to inflict :) */
1187 effect->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1188 }
1189
1190 effect->set_owner (op);
1191 set_spell_skill (op, caster, spell, effect);
1192
1193 /* ok, tell it where to be, and insert! */
1194 effect->insert_at (target, op);
1195
1196 return 1;
1197 }
1198
1199
1200 /****************************************************************************
1201 *
1202 * MAGIC MISSILE code.
1203 * note that the fire_bullet is used to fire the missile. The
1204 * code here is just to move the missile.
1205 ****************************************************************************/
1206
1207 /* op is a missile that needs to be moved */
1208 void
1209 move_missile (object *op)
1210 {
1211 int i, mflags;
1212 object *owner;
1213 sint16 new_x, new_y;
1214 maptile *m;
1215
1216 if (op->range-- <= 0)
1217 {
1218 op->destroy ();
1219 return;
1220 }
1221
1222 owner = op->owner;
1223 #if 0
1224 /* It'd make things nastier if this wasn't here - spells cast by
1225 * monster that are then killed would continue to survive
1226 */
1227 if (owner == NULL)
1228 {
1229 op->destroy ();
1230 return;
1231 }
1232 #endif
1233
1234 new_x = op->x + DIRX (op);
1235 new_y = op->y + DIRY (op);
1236
1237 mflags = get_map_flags (op->map, &m, new_x, new_y, &new_x, &new_y);
1238
1239 if (!(mflags & P_OUT_OF_MAP) && ((mflags & P_IS_ALIVE) || OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, new_x, new_y))))
1240 {
1241 hit_map (op, op->direction, AT_MAGIC, 1);
1242 /* Basically, missile only hits one thing then goes away.
1243 * we need to remove it if someone hasn't already done so.
1244 */
1245 if (!op->destroyed ())
1246 op->destroy ();
1247
1248 return;
1249 }
1250
1251 op->remove ();
1252
1253 if (!op->direction || (mflags & P_OUT_OF_MAP))
1254 {
1255 op->destroy ();
1256 return;
1257 }
1258
1259 i = spell_find_dir (m, new_x, new_y, op->owner);
1260 if (i > 0 && i != op->direction)
1261 {
1262 op->direction = i;
1263 SET_ANIMATION (op, op->direction);
1264 }
1265
1266 m->insert (op, new_x, new_y, op);
1267 }
1268
1269 /****************************************************************************
1270 * Destruction
1271 ****************************************************************************/
1272
1273 /* make_object_glow() - currently only makes living objects glow.
1274 * we do this by creating a force and inserting it in the
1275 * object. if time is 0, the object glows permanently. To truely
1276 * make this work for non-living objects, we would have to
1277 * give them the capability to have an inventory. b.t.
1278 */
1279
1280 int
1281 make_object_glow (object *op, int radius, int time)
1282 {
1283 object *tmp;
1284
1285 /* some things are unaffected... */
1286 if (op->path_denied & PATH_LIGHT)
1287 return 0;
1288
1289 tmp = get_archetype (FORCE_NAME);
1290 tmp->speed = 0.01;
1291 tmp->stats.food = time;
1292 SET_FLAG (tmp, FLAG_IS_USED_UP);
1293 tmp->glow_radius = radius;
1294 if (tmp->glow_radius > MAX_LIGHT_RADII)
1295 tmp->glow_radius = MAX_LIGHT_RADII;
1296
1297 tmp->x = op->x;
1298 tmp->y = op->y;
1299 if (tmp->speed < MIN_ACTIVE_SPEED)
1300 tmp->speed = MIN_ACTIVE_SPEED; /* safety */
1301 tmp = insert_ob_in_ob (tmp, op);
1302 if (tmp->glow_radius > op->glow_radius)
1303 op->glow_radius = tmp->glow_radius;
1304
1305 if (!tmp->env || op != tmp->env)
1306 {
1307 LOG (llevError, "make_object_glow() failed to insert glowing force in %s\n", &op->name);
1308 return 0;
1309 }
1310 return 1;
1311 }
1312
1313
1314
1315
1316 int
1317 cast_destruction (object *op, object *caster, object *spell_ob)
1318 {
1319 int i, j, range, mflags, friendly = 0, dam, dur;
1320 sint16 sx, sy;
1321 maptile *m;
1322 object *tmp;
1323 const char *skill;
1324
1325 range = spell_ob->range + SP_level_range_adjust (caster, spell_ob);
1326 dam = spell_ob->stats.dam + SP_level_dam_adjust (caster, spell_ob);
1327 dur = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob);
1328 if (QUERY_FLAG (op, FLAG_FRIENDLY) || op->type == PLAYER)
1329 friendly = 1;
1330
1331 /* destruction doesn't use another spell object, so we need
1332 * update op's skill pointer so that exp is properly awarded.
1333 * We do some shortcuts here - since this is just temporary
1334 * and we'll reset the values back, we don't need to go through
1335 * the full share string/free_string route.
1336 */
1337 skill = op->skill;
1338 if (caster == op)
1339 op->skill = spell_ob->skill;
1340 else if (caster->skill)
1341 op->skill = caster->skill;
1342 else
1343 op->skill = NULL;
1344
1345 change_skill (op, find_skill_by_name (op, op->skill), 1);
1346
1347 for (i = -range; i < range; i++)
1348 {
1349 for (j = -range; j < range; j++)
1350 {
1351 m = op->map;
1352 sx = op->x + i;
1353 sy = op->y + j;
1354
1355 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
1356 if (mflags & P_OUT_OF_MAP)
1357 continue;
1358
1359 if (mflags & P_IS_ALIVE)
1360 {
1361 for (tmp = GET_MAP_OB (m, sx, sy); tmp; tmp = tmp->above)
1362 if (QUERY_FLAG (tmp, FLAG_ALIVE) || tmp->type == PLAYER)
1363 break;
1364
1365 if (tmp)
1366 {
1367 if (tmp->head)
1368 tmp = tmp->head;
1369
1370 if ((friendly && !QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->type != PLAYER) ||
1371 (!friendly && (QUERY_FLAG (tmp, FLAG_FRIENDLY) || tmp->type == PLAYER)))
1372 {
1373 if (spell_ob->subtype == SP_DESTRUCTION)
1374 {
1375 hit_player (tmp, dam, op, spell_ob->attacktype, 0);
1376 if (spell_ob->other_arch)
1377 m->insert (arch_to_object (spell_ob->other_arch), sx, sy, op);
1378 }
1379 else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist[ATNR_MAGIC] != 100)
1380 {
1381 if (make_object_glow (tmp, 1, dur) && spell_ob->other_arch)
1382 m->insert (arch_to_object (spell_ob->other_arch), sx, sy, op);
1383 }
1384 }
1385 }
1386 }
1387 }
1388 }
1389
1390 op->skill = skill;
1391 return 1;
1392 }
1393
1394 /***************************************************************************
1395 *
1396 * CURSE
1397 *
1398 ***************************************************************************/
1399
1400 int
1401 cast_curse (object *op, object *caster, object *spell_ob, int dir)
1402 {
1403 object *god = find_god (determine_god (op));
1404 object *tmp, *force;
1405
1406 tmp = get_pointed_target (op, (dir == 0) ? op->direction : dir, spell_ob->range, SPELL_GRACE);
1407 if (!tmp)
1408 {
1409 new_draw_info (NDI_UNIQUE, 0, op, "There is no one in that direction to curse.");
1410 return 0;
1411 }
1412
1413 /* If we've already got a force of this type, don't add a new one. */
1414 for (force = tmp->inv; force != NULL; force = force->below)
1415 {
1416 if (force->type == FORCE && force->subtype == FORCE_CHANGE_ABILITY)
1417 {
1418 if (force->name == spell_ob->name)
1419 {
1420 break;
1421 }
1422 else if (spell_ob->race && spell_ob->race == force->name)
1423 {
1424 new_draw_info_format (NDI_UNIQUE, 0, op, "You can not cast %s while %s is in effect", &spell_ob->name, &force->name_pl);
1425 return 0;
1426 }
1427 }
1428 }
1429
1430 if (force == NULL)
1431 {
1432 force = get_archetype (FORCE_NAME);
1433 force->subtype = FORCE_CHANGE_ABILITY;
1434 if (spell_ob->race)
1435 force->name = spell_ob->race;
1436 else
1437 force->name = spell_ob->name;
1438
1439 force->name_pl = spell_ob->name;
1440
1441 }
1442 else
1443 {
1444 int duration;
1445
1446 duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1447 if (duration > force->duration)
1448 {
1449 force->duration = duration;
1450 new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
1451 }
1452 else
1453 {
1454 new_draw_info (NDI_UNIQUE, 0, op, "Recasting the spell had no effect.");
1455 }
1456 return 1;
1457 }
1458 force->duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1459 force->speed = 1.0;
1460 force->speed_left = -1.0;
1461 SET_FLAG (force, FLAG_APPLIED);
1462
1463 if (god)
1464 {
1465 if (spell_ob->last_grace)
1466 force->path_repelled = god->path_repelled;
1467 if (spell_ob->last_grace)
1468 force->path_denied = god->path_denied;
1469 new_draw_info_format (NDI_UNIQUE, 0, tmp, "You are a victim of %s's curse!", &god->name);
1470 }
1471 else
1472 new_draw_info (NDI_UNIQUE, 0, op, "Your curse seems empty.");
1473
1474
1475 if (tmp != op && op->type == PLAYER)
1476 new_draw_info_format (NDI_UNIQUE, 0, op, "You curse %s!", &tmp->name);
1477
1478 force->stats.ac = spell_ob->stats.ac;
1479 force->stats.wc = spell_ob->stats.wc;
1480
1481 change_abil (tmp, force); /* Mostly to display any messages */
1482 insert_ob_in_ob (force, tmp);
1483 tmp->update_stats ();
1484 return 1;
1485
1486 }
1487
1488 /**********************************************************************
1489 * mood change
1490 * Arguably, this may or may not be an attack spell. But since it
1491 * effects monsters, it seems best to put it into this file
1492 ***********************************************************************/
1493
1494 /* This covers the various spells that change the moods of monsters -
1495 * makes them angry, peacful, friendly, etc.
1496 */
1497 int
1498 mood_change (object *op, object *caster, object *spell)
1499 {
1500 object *tmp, *god, *head;
1501 int done_one, range, mflags, level, at, best_at;
1502 sint16 x, y, nx, ny;
1503 maptile *m;
1504 const char *race;
1505
1506 /* We precompute some values here so that we don't have to keep
1507 * doing it over and over again.
1508 */
1509 god = find_god (determine_god (op));
1510 level = caster_level (caster, spell);
1511 range = spell->range + SP_level_range_adjust (caster, spell);
1512
1513 /* On the bright side, no monster should ever have a race of GOD_...
1514 * so even if the player doesn't worship a god, if race=GOD_.., it
1515 * won't ever match anything.
1516 */
1517 if (!spell->race)
1518 race = NULL;
1519 else if (god && !strcmp (spell->race, "GOD_SLAYING"))
1520 race = god->slaying;
1521 else if (god && !strcmp (spell->race, "GOD_FRIEND"))
1522 race = god->race;
1523 else
1524 race = spell->race;
1525
1526 for (x = op->x - range; x <= op->x + range; x++)
1527 for (y = op->y - range; y <= op->y + range; y++)
1528 {
1529 done_one = 0;
1530 m = op->map;
1531 nx = x;
1532 ny = y;
1533 mflags = get_map_flags (m, &m, x, y, &nx, &ny);
1534 if (mflags & P_OUT_OF_MAP)
1535 continue;
1536
1537 /* If there is nothing living on this space, no need to go further */
1538 if (!(mflags & P_IS_ALIVE))
1539 continue;
1540
1541 // players can only affect spaces that they can actually see
1542 if (caster && caster->contr
1543 && caster->contr->visibility_at (m, nx, ny) < 70)
1544 continue;
1545
1546 for (tmp = GET_MAP_TOP (m, nx, ny); tmp; tmp = tmp->below)
1547 if (QUERY_FLAG (tmp, FLAG_MONSTER))
1548 break;
1549
1550 /* There can be living objects that are not monsters */
1551 if (!tmp || tmp->type == PLAYER)
1552 continue;
1553
1554 /* Only the head has meaningful data, so resolve to that */
1555 if (tmp->head)
1556 head = tmp->head;
1557 else
1558 head = tmp;
1559
1560 /* Make sure the race is OK. Likewise, only effect undead if spell specifically allows it */
1561 if (race && head->race && !strstr (race, head->race))
1562 continue;
1563
1564 if (QUERY_FLAG (head, FLAG_UNDEAD) && !QUERY_FLAG (spell, FLAG_UNDEAD))
1565 continue;
1566
1567 /* Now do a bunch of stuff related to saving throws */
1568 best_at = -1;
1569 if (spell->attacktype)
1570 {
1571 for (at = 0; at < NROFATTACKS; at++)
1572 if (spell->attacktype & (1 << at))
1573 if (best_at == -1 || head->resist[at] > head->resist[best_at])
1574 best_at = at;
1575
1576 if (best_at == -1)
1577 at = 0;
1578 else
1579 {
1580 if (head->resist[best_at] == 100)
1581 continue;
1582 else
1583 at = head->resist[best_at] / 5;
1584 }
1585 at -= level / 5;
1586 if (did_make_save (head, head->level, at))
1587 continue;
1588 }
1589 else /* spell->attacktype */
1590 /*
1591 Spell has no attacktype (charm & such), so we'll have a specific saving:
1592 * if spell level < monster level, no go
1593 * else, chance of effect = 20 + min( 50, 2 * ( spell level - monster level ) )
1594
1595 The chance will then be in the range [20-70] percent, not too bad.
1596
1597 This is required to fix the 'charm monster' abuse, where a player level 1 can
1598 charm a level 125 monster...
1599
1600 Ryo, august 14th
1601 */
1602 {
1603 if (head->level > level)
1604 continue;
1605 if (random_roll (0, 100, caster, PREFER_LOW) >= (20 + MIN (50, 2 * (level - head->level))))
1606 /* Failed, no effect */
1607 continue;
1608 }
1609
1610 /* Done with saving throw. Now start affecting the monster */
1611
1612 /* aggravation */
1613 if (QUERY_FLAG (spell, FLAG_MONSTER))
1614 {
1615 CLEAR_FLAG (head, FLAG_SLEEP);
1616 if (QUERY_FLAG (head, FLAG_FRIENDLY))
1617 remove_friendly_object (head);
1618
1619 done_one = 1;
1620 head->enemy = op;
1621 }
1622
1623 /* calm monsters */
1624 if (QUERY_FLAG (spell, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (head, FLAG_UNAGGRESSIVE))
1625 {
1626 SET_FLAG (head, FLAG_UNAGGRESSIVE);
1627 head->enemy = NULL;
1628 done_one = 1;
1629 }
1630
1631 /* berserk monsters */
1632 if (QUERY_FLAG (spell, FLAG_BERSERK) && !QUERY_FLAG (head, FLAG_BERSERK))
1633 {
1634 SET_FLAG (head, FLAG_BERSERK);
1635 done_one = 1;
1636 }
1637
1638 /* charm */
1639 if (QUERY_FLAG (spell, FLAG_NO_ATTACK) && !QUERY_FLAG (head, FLAG_FRIENDLY))
1640 {
1641 /* Prevent uncontolled outbreaks of self replicating monsters.
1642 Typical use case is charm, go somwhere, use aggravation to make hostile.
1643 This could lead to fun stuff like mice outbreak in bigworld and server crawl. */
1644 CLEAR_FLAG (head, FLAG_GENERATOR);
1645 head->set_owner (op);
1646 set_spell_skill (op, caster, spell, head);
1647 add_friendly_object (head);
1648 head->attack_movement = PETMOVE;
1649 done_one = 1;
1650 change_exp (op, head->stats.exp / 2, head->skill, SK_EXP_ADD_SKILL);
1651 head->stats.exp = 0;
1652 }
1653
1654 /* If a monster was effected, put an effect in */
1655 if (done_one && spell->other_arch)
1656 m->insert (arch_to_object (spell->other_arch), nx, ny, op);
1657 } /* for y */
1658
1659 return 1;
1660 }
1661
1662
1663 /* Move_ball_spell: This handles ball type spells that just sort of wander
1664 * about. was called move_ball_lightning, but since more than the ball
1665 * lightning spell used it, that seemed misnamed.
1666 * op is the spell effect.
1667 * note that duration is handled by process_object() in time.c
1668 */
1669
1670 void
1671 move_ball_spell (object *op)
1672 {
1673 int i, j, dam_save, dir, mflags;
1674 sint16 nx, ny, hx, hy;
1675 object *owner;
1676 maptile *m;
1677
1678 owner = op->owner;
1679
1680 /* the following logic makes sure that the ball doesn't move into a wall,
1681 * and makes sure that it will move along a wall to try and get at it's
1682 * victim. The block immediately below more or less chooses a random
1683 * offset to move the ball, eg, keep it mostly on course, with some
1684 * deviations.
1685 */
1686
1687 dir = 0;
1688 if (!(rndm (0, 3)))
1689 j = rndm (0, 1);
1690 else
1691 j = 0;
1692
1693 for (i = 1; i < 9; i++)
1694 {
1695 /* i bit 0: alters sign of offset
1696 * other bits (i / 2): absolute value of offset
1697 */
1698
1699 int offset = ((i ^ j) & 1) ? (i / 2) : -(i / 2);
1700 int tmpdir = absdir (op->direction + offset);
1701
1702 nx = op->x + freearr_x[tmpdir];
1703 ny = op->y + freearr_y[tmpdir];
1704 if (!(get_map_flags (op->map, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP) && !(OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, nx, ny))))
1705 {
1706 dir = tmpdir;
1707 break;
1708 }
1709 }
1710 if (dir == 0)
1711 {
1712 nx = op->x;
1713 ny = op->y;
1714 m = op->map;
1715 }
1716
1717 m->insert (op, nx, ny, op);
1718
1719 dam_save = op->stats.dam; /* save the original dam: we do halfdam on
1720 surrounding squares */
1721
1722 /* loop over current square and neighbors to hit.
1723 * if this has an other_arch field, we insert that in
1724 * the surround spaces.
1725 */
1726 for (j = 0; j < 9; j++)
1727 {
1728 object *new_ob;
1729
1730 hx = nx + freearr_x[j];
1731 hy = ny + freearr_y[j];
1732
1733 m = op->map;
1734 mflags = get_map_flags (m, &m, hx, hy, &hx, &hy);
1735
1736 if (mflags & P_OUT_OF_MAP)
1737 continue;
1738
1739 /* first, don't ever, ever hit the owner. Don't hit out
1740 * of the map either.
1741 */
1742
1743 if ((mflags & P_IS_ALIVE) && (!owner || owner->x != hx || owner->y != hy || !on_same_map (owner, op)))
1744 {
1745 if (j)
1746 op->stats.dam = dam_save / 2;
1747 hit_map (op, j, op->attacktype, 1);
1748
1749 }
1750
1751 /* insert the other arch */
1752 if (op->other_arch && !(OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy))))
1753 m->insert (arch_to_object (op->other_arch), hx, hy, op);
1754 }
1755
1756 /* restore to the center location and damage */
1757 op->stats.dam = dam_save;
1758
1759 i = spell_find_dir (op->map, op->x, op->y, op->owner);
1760
1761 if (i >= 0)
1762 { /* we have a preferred direction! */
1763 /* pick another direction if the preferred dir is blocked. */
1764 if (get_map_flags (op->map, &m, nx + freearr_x[i], ny + freearr_y[i], &hx, &hy) & P_OUT_OF_MAP ||
1765 OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy)))
1766 i = absdir (i + rndm (0, 2) - 1); /* -1, 0, +1 */
1767
1768 op->direction = i;
1769 }
1770 }
1771
1772
1773 /* move_swarm_spell: peterm
1774 * This is an implementation of the swarm spell. It was written for
1775 * meteor swarm, but it could be used for any swarm. A swarm spell
1776 * is a special type of object that casts swarms of other types
1777 * of spells. Which spell it casts is flexible. It fires the spells
1778 * from a set of squares surrounding the caster, in a given direction.
1779 */
1780
1781 void
1782 move_swarm_spell (object *op)
1783 {
1784 #if 0
1785 static int cardinal_adjust[9] = { -3, -2, -1, 0, 0, 0, 1, 2, 3 };
1786 static int diagonal_adjust[10] = { -3, -2, -2, -1, 0, 0, 1, 2, 2, 3 };
1787 sint16 target_x, target_y, origin_x, origin_y;
1788 int adjustdir;
1789 maptile *m;
1790 #endif
1791 int basedir;
1792 object *owner;
1793
1794 owner = op->owner;
1795 if (op->duration == 0 || owner == NULL)
1796 {
1797 op->destroy ();
1798 return;
1799 }
1800
1801 op->duration--;
1802
1803 basedir = op->direction;
1804 if (basedir == 0)
1805 {
1806 /* spray in all directions! 8) */
1807 basedir = rndm (1, 8);
1808 }
1809
1810 #if 0
1811 // this is bogus: it causes wrong places to be checked below
1812 // (a wall 2 cells away will block the effect...) and
1813 // doesn't work for SP_BULLET anyhow, so again tests the wrong
1814 // space.
1815 // should be fixed later, but correctness before featurs...
1816 // (schmorp)
1817
1818 /* new offset calculation to make swarm element distribution
1819 * more uniform
1820 */
1821 if (op->duration)
1822 {
1823 if (basedir & 1)
1824 {
1825 adjustdir = cardinal_adjust[rndm (0, 8)];
1826 }
1827 else
1828 {
1829 adjustdir = diagonal_adjust[rndm (0, 9)];
1830 }
1831 }
1832 else
1833 {
1834 adjustdir = 0; /* fire the last one from forward. */
1835 }
1836
1837 target_x = op->x + freearr_x[absdir (basedir + adjustdir)];
1838 target_y = op->y + freearr_y[absdir (basedir + adjustdir)];
1839
1840 /* back up one space so we can hit point-blank targets, but this
1841 * necessitates extra out_of_map check below
1842 */
1843 origin_x = target_x - freearr_x[basedir];
1844 origin_y = target_y - freearr_y[basedir];
1845
1846
1847 /* spell pointer is set up for the spell this casts. Since this
1848 * should just be a pointer to the spell in some inventory,
1849 * it is unlikely to disappear by the time we need it. However,
1850 * do some sanity checking anyways.
1851 */
1852
1853 if (op->spell && op->spell->type == SPELL &&
1854 !(get_map_flags (op->map, &m, target_x, target_y, &target_x, &target_y) & P_OUT_OF_MAP) &&
1855 !(OB_TYPE_MOVE_BLOCK (op->spell, GET_MAP_MOVE_BLOCK (m, target_x, target_y))))
1856 {
1857
1858 /* Bullet spells have a bunch more customization that needs to be done */
1859 if (op->spell->subtype == SP_BULLET)
1860 fire_bullet (owner, op, basedir, op->spell);
1861 else if (op->spell->subtype == SP_MAGIC_MISSILE)
1862 fire_arch_from_position (owner, op, origin_x, origin_y, basedir, op->spell);
1863 }
1864 #endif
1865
1866 /* spell pointer is set up for the spell this casts. Since this
1867 * should just be a pointer to the spell in some inventory,
1868 * it is unlikely to disappear by the time we need it. However,
1869 * do some sanity checking anyways.
1870 */
1871
1872 if (op->spell && op->spell->type == SPELL)
1873 {
1874 /* Bullet spells have a bunch more customization that needs to be done */
1875 if (op->spell->subtype == SP_BULLET)
1876 fire_bullet (owner, op, basedir, op->spell);
1877 else if (op->spell->subtype == SP_MAGIC_MISSILE)
1878 fire_arch_from_position (owner, op, op->x, op->y, basedir, op->spell);
1879 }
1880 }
1881
1882
1883
1884
1885 /* fire_swarm:
1886 * The following routine creates a swarm of objects. It actually
1887 * sets up a specific swarm object, which then fires off all
1888 * the parts of the swarm.
1889 *
1890 * op: the owner
1891 * caster: the caster (owner, wand, rod, scroll)
1892 * dir: the direction everything will be fired in
1893 * spell - the spell that is this spell.
1894 * n: the number to be fired.
1895 */
1896
1897 int
1898 fire_swarm (object *op, object *caster, object *spell, int dir)
1899 {
1900 object *tmp;
1901 int i;
1902
1903 if (!spell->other_arch)
1904 return 0;
1905
1906 tmp = get_archetype (SWARM_SPELL);
1907 tmp->set_owner (op); /* needed so that if swarm elements kill, caster gets xp. */
1908 set_spell_skill (op, caster, spell, tmp);
1909
1910 tmp->level = caster_level (caster, spell); /*needed later, to get level dep. right. */
1911 tmp->spell = arch_to_object (spell->other_arch);
1912
1913 tmp->attacktype = tmp->spell->attacktype;
1914
1915 if (tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER)
1916 if (!tailor_god_spell (tmp, op))
1917 return 1;
1918
1919 tmp->duration = SP_level_duration_adjust (caster, spell);
1920 for (i = 0; i < spell->duration; i++)
1921 tmp->duration += die_roll (1, 3, op, PREFER_HIGH);
1922
1923 tmp->direction = dir;
1924 tmp->invisible = 1;
1925
1926 tmp->insert_at (op, op);
1927 return 1;
1928 }
1929
1930
1931 /* See the spells documentation file for why this is its own
1932 * function.
1933 */
1934 int
1935 cast_light (object *op, object *caster, object *spell, int dir)
1936 {
1937 object *target = NULL, *tmp = NULL;
1938 sint16 x, y;
1939 int dam, mflags;
1940 maptile *m;
1941
1942 dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1943
1944 if (!dir)
1945 {
1946 new_draw_info (NDI_UNIQUE, 0, op, "In what direction?");
1947 return 0;
1948 }
1949
1950 x = op->x + freearr_x[dir];
1951 y = op->y + freearr_y[dir];
1952 m = op->map;
1953
1954 mflags = get_map_flags (m, &m, x, y, &x, &y);
1955
1956 if (mflags & P_OUT_OF_MAP)
1957 {
1958 new_draw_info (NDI_UNIQUE, 0, op, "Nothing is there.");
1959 return 0;
1960 }
1961
1962 if (mflags & P_IS_ALIVE && spell->attacktype)
1963 {
1964 for (target = GET_MAP_OB (m, x, y); target; target = target->above)
1965 if (QUERY_FLAG (target, FLAG_MONSTER))
1966 {
1967 /* oky doky. got a target monster. Lets make a blinding attack */
1968 if (target->head)
1969 target = target->head;
1970 (void) hit_player (target, dam, op, spell->attacktype, 1);
1971 return 1; /* one success only! */
1972 }
1973 }
1974
1975 /* no live target, perhaps a wall is in the way? */
1976 if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y)))
1977 {
1978 new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way.");
1979 return 0;
1980 }
1981
1982 /* ok, looks groovy to just insert a new light on the map */
1983 tmp = arch_to_object (spell->other_arch);
1984 if (!tmp)
1985 {
1986 LOG (llevError, "Error: spell arch for cast_light() missing.\n");
1987 return 0;
1988 }
1989 tmp->stats.food = spell->duration + SP_level_duration_adjust (caster, spell);
1990 if (tmp->glow_radius)
1991 {
1992 tmp->glow_radius = spell->range + SP_level_range_adjust (caster, spell);
1993 if (tmp->glow_radius > MAX_LIGHT_RADII)
1994 tmp->glow_radius = MAX_LIGHT_RADII;
1995 }
1996
1997 m->insert (tmp, x, y, op);
1998 return 1;
1999 }
2000
2001
2002
2003
2004 /* cast_cause_disease: this spell looks along <dir> from the
2005 * player and infects someone.
2006 * op is the player/monster, caster is the object, dir is the direction
2007 * to cast, disease_arch is the specific disease, and type is the spell number
2008 * perhaps this should actually be in disease.c?
2009 */
2010
2011 int
2012 cast_cause_disease (object *op, object *caster, object *spell, int dir)
2013 {
2014 sint16 x, y;
2015 int i, mflags, range, dam_mod, dur_mod;
2016 object *walk;
2017 maptile *m;
2018
2019 x = op->x;
2020 y = op->y;
2021
2022 /* If casting from a scroll, no direction will be available, so refer to the
2023 * direction the player is pointing.
2024 */
2025 if (!dir)
2026 dir = op->facing;
2027 if (!dir)
2028 return 0; /* won't find anything if casting on ourself, so just return */
2029
2030 /* Calculate these once here */
2031 range = spell->range + SP_level_range_adjust (caster, spell);
2032 dam_mod = SP_level_dam_adjust (caster, spell);
2033 dur_mod = SP_level_duration_adjust (caster, spell);
2034
2035 /* search in a line for a victim */
2036 for (i = 1; i < range; i++)
2037 {
2038 x = op->x + i * freearr_x[dir];
2039 y = op->y + i * freearr_y[dir];
2040 m = op->map;
2041
2042 mflags = get_map_flags (m, &m, x, y, &x, &y);
2043
2044 if (mflags & P_OUT_OF_MAP)
2045 return 0;
2046
2047 /* don't go through walls - presume diseases are airborne */
2048 if (GET_MAP_MOVE_BLOCK (m, x, y) & MOVE_FLY_LOW)
2049 return 0;
2050
2051 /* Only bother looking on this space if there is something living here */
2052 if (mflags & P_IS_ALIVE)
2053 {
2054 /* search this square for a victim */
2055 for (walk = GET_MAP_OB (m, x, y); walk; walk = walk->above)
2056 if (QUERY_FLAG (walk, FLAG_MONSTER) || (walk->type == PLAYER))
2057 { /* found a victim */
2058 object *disease = arch_to_object (spell->other_arch);
2059
2060 disease->set_owner (op);
2061 set_spell_skill (op, caster, spell, disease);
2062 disease->stats.exp = 0;
2063 disease->level = caster_level (caster, spell);
2064
2065 /* do level adjustments */
2066 if (disease->stats.wc)
2067 disease->stats.wc += dur_mod / 2;
2068
2069 if (disease->magic > 0)
2070 disease->magic += dur_mod / 4;
2071
2072 if (disease->stats.maxhp > 0)
2073 disease->stats.maxhp += dur_mod;
2074
2075 if (disease->stats.maxgrace > 0)
2076 disease->stats.maxgrace += dur_mod;
2077
2078 if (disease->stats.dam)
2079 {
2080 if (disease->stats.dam > 0)
2081 disease->stats.dam += dam_mod;
2082 else
2083 disease->stats.dam -= dam_mod;
2084 }
2085
2086 if (disease->last_sp)
2087 {
2088 disease->last_sp -= 2 * dam_mod;
2089 if (disease->last_sp < 1)
2090 disease->last_sp = 1;
2091 }
2092
2093 if (disease->stats.maxsp)
2094 {
2095 if (disease->stats.maxsp > 0)
2096 disease->stats.maxsp += dam_mod;
2097 else
2098 disease->stats.maxsp -= dam_mod;
2099 }
2100
2101 if (disease->stats.ac)
2102 disease->stats.ac += dam_mod;
2103
2104 if (disease->last_eat)
2105 disease->last_eat -= dam_mod;
2106
2107 if (disease->stats.hp)
2108 disease->stats.hp -= dam_mod;
2109
2110 if (disease->stats.sp)
2111 disease->stats.sp -= dam_mod;
2112
2113 if (infect_object (walk, disease, 1))
2114 {
2115 object *flash; /* visual effect for inflicting disease */
2116
2117 new_draw_info_format (NDI_UNIQUE, 0, op, "You inflict %s on %s!", &disease->name, &walk->name);
2118
2119 disease->destroy (); /* don't need this one anymore */
2120 walk->map->insert (get_archetype (ARCH_DETECT_MAGIC), x, y, op);
2121 return 1;
2122 }
2123
2124 disease->destroy ();
2125 }
2126 } /* if living creature */
2127 } /* for range of spaces */
2128
2129 new_draw_info (NDI_UNIQUE, 0, op, "No one caught anything!");
2130 return 1;
2131 }