ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.41
Committed: Sat Jun 9 21:16:12 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.40: +4 -16 lines
Log Message:
- inherit some flags from the head (probably should inherit everything,
  the whole object, but thats for later).
  this makes speed-relevant code faster and simpler.

File Contents

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