ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.79
Committed: Thu Jan 1 16:05:13 2009 UTC (15 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.78: +2 -2 lines
Log Message:
rmeove most shstr-strcmps

File Contents

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