ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.12
Committed: Thu Sep 14 21:16:13 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.11: +2 -2 lines
Log Message:
cleanup

File Contents

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