ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.45
Committed: Wed Aug 1 00:26:03 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.44: +2 -0 lines
Log Message:
allow exploding thingy effect

File Contents

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