ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.15
Committed: Sat Sep 16 22:24:13 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.14: +15 -15 lines
Log Message:
mapstruct => maptile
removed many ytypedefs in favor of structure tags

File Contents

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