ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.65
Committed: Mon Sep 29 10:20:49 2008 UTC (15 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.64: +38 -29 lines
Log Message:
do the same everywhere else

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