ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.17
Committed: Tue Dec 12 21:39:57 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.16: +52 -66 lines
Log Message:
- more ooficiation
- removed now superfluous remove calls

File Contents

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