ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.57
Committed: Sat May 17 14:11:13 2008 UTC (16 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.56: +4 -6 lines
Log Message:
fix missile swarm, improve blockign logic

File Contents

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