ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.58
Committed: Sat May 17 14:57:23 2008 UTC (16 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.57: +25 -40 lines
Log Message:
*** empty log message ***

File Contents

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