ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.27
Committed: Mon Jan 8 01:19:04 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.26: +1 -1 lines
Log Message:
more preperations for player eviction

File Contents

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