ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.51
Committed: Sun Apr 20 23:25:43 2008 UTC (16 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.50: +1 -1 lines
Log Message:
minor refactoring

File Contents

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