ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.72
Committed: Sat Dec 27 08:01:07 2008 UTC (15 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.71: +1 -1 lines
Log Message:
better understanding leads to better understanding

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     * 0. If this is a rune, we want to hit the person on top
837     * of the trap (d==0). If it is not a rune, then we don't want
838     * to hit that person.
839     */
840     d = dir + i;
841     while (d < 0)
842     d += 8;
843     while (d > 8)
844     d -= 8;
845    
846     /* If it's not a rune, we don't want to blast the caster.
847     * In that case, we have to see - if dir is specified,
848     * turn this into direction 8. If dir is not specified (all
849     * direction) skip - otherwise, one line would do more damage
850     * becase 0 direction will go through 9 directions - necessary
851     * for the rune code.
852     */
853     if (caster->type != RUNE && d == 0)
854     {
855     if (dir != 0)
856     d = 8;
857     else
858 root 1.6 continue;
859 root 1.9 }
860 elmex 1.1
861 root 1.9 x = op->x + freearr_x[d];
862     y = op->y + freearr_y[d];
863 root 1.6
864 root 1.9 if (get_map_flags (op->map, &m, x, y, &sx, &sy) & P_OUT_OF_MAP)
865     continue;
866 root 1.6
867 root 1.9 if ((movetype & GET_MAP_MOVE_BLOCK (m, sx, sy)) == movetype)
868     continue;
869 root 1.6
870 root 1.9 success = 1;
871     tmp = arch_to_object (spell->other_arch);
872 root 1.19 tmp->set_owner (op);
873 root 1.9 set_spell_skill (op, caster, spell, tmp);
874 root 1.64 tmp->level = casting_level (caster, spell);
875 root 1.9 tmp->attacktype = spell->attacktype;
876    
877     /* holy word stuff */
878     if ((tmp->attacktype & AT_HOLYWORD) || (tmp->attacktype & AT_GODPOWER))
879 root 1.10 if (!tailor_god_spell (tmp, op))
880     return 0;
881 root 1.6
882 root 1.9 if (dir)
883     tmp->stats.sp = dir;
884     else
885     tmp->stats.sp = i;
886    
887     tmp->range = spell->range + SP_level_range_adjust (caster, spell);
888    
889     /* If casting it in all directions, it doesn't go as far */
890     if (dir == 0)
891     {
892     tmp->range /= 4;
893     if (tmp->range < 2 && spell->range >= 2)
894     tmp->range = 2;
895     }
896 root 1.10
897 root 1.9 tmp->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
898     tmp->duration = spell->duration + SP_level_duration_adjust (caster, spell);
899    
900     /* Special bonus for fear attacks */
901     if (tmp->attacktype & AT_FEAR)
902     {
903     if (caster->type == PLAYER)
904     tmp->duration += fear_bonus[caster->stats.Cha];
905     else
906     tmp->duration += caster->level / 3;
907     }
908 root 1.10
909 root 1.9 if (tmp->attacktype & (AT_HOLYWORD | AT_TURN_UNDEAD))
910     {
911     if (caster->type == PLAYER)
912     tmp->duration += turn_bonus[caster->stats.Wis] / 5;
913     else
914     tmp->duration += caster->level / 3;
915 root 1.6 }
916    
917 root 1.9 if (!(tmp->move_type & MOVE_FLY_LOW))
918 root 1.38 LOG (llevDebug, "cast_cone(): arch %s doesn't have flying 1\n", &spell->other_arch->archname);
919 root 1.9
920     if (!tmp->move_on && tmp->stats.dam)
921 root 1.38 LOG (llevDebug, "cast_cone(): arch %s doesn't have move_on set\n", &spell->other_arch->archname);
922 root 1.10
923 root 1.25 m->insert (tmp, sx, sy, op);
924 root 1.9
925     /* This is used for tracking spells so that one effect doesn't hit
926     * a single space too many times.
927     */
928     tmp->stats.maxhp = tmp->count;
929 root 1.6
930 root 1.9 if (tmp->other_arch)
931     cone_drop (tmp);
932 elmex 1.1 }
933 root 1.10
934 root 1.9 return success;
935 elmex 1.1 }
936    
937     /****************************************************************************
938     *
939     * BOMB related code
940     *
941     ****************************************************************************/
942    
943     /* This handles an exploding bomb.
944     * op is the original bomb object.
945     */
946 root 1.9 void
947     animate_bomb (object *op)
948     {
949     if (op->state != NUM_ANIMATIONS (op) - 1)
950     return;
951 elmex 1.1
952 root 1.50 object *env = op->outer_env ();
953 elmex 1.1
954 root 1.9 if (op->env)
955     {
956     if (env->map == NULL)
957     return;
958 elmex 1.1
959 root 1.25 if (!(op = op->insert_at (env, op)))
960 root 1.9 return;
961 elmex 1.1 }
962    
963 root 1.9 // elmex Tue Aug 15 17:46:51 CEST 2006: Prevent bomb from exploding
964     // on a safe map. I don't like this special casing, but it seems to be neccessary
965     // as bombs can be carried.
966     if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE)
967     {
968 root 1.67 op->destroy ();
969 root 1.9 return;
970     }
971 elmex 1.3
972 root 1.9 /* This copies a lot of the code from the fire bullet,
973     * but using the cast_bullet isn't really feasible,
974     * so just set up the appropriate values.
975     */
976 root 1.25 if (archetype *at = archetype::find (SPLINT))
977 root 1.9 {
978 root 1.50 for (int i = 1; i < 9; i++)
979 root 1.9 {
980     if (out_of_map (op->map, op->x + freearr_x[i], op->y + freearr_x[i]))
981     continue;
982 root 1.25
983 root 1.50 object *tmp = arch_to_object (at);
984 root 1.9 tmp->direction = i;
985     tmp->range = op->range;
986     tmp->stats.dam = op->stats.dam;
987     tmp->duration = op->duration;
988     tmp->attacktype = op->attacktype;
989 root 1.19 tmp->set_owner (op);
990 root 1.9 if (op->skill && op->skill != tmp->skill)
991 root 1.25 tmp->skill = op->skill;
992    
993 root 1.9 if (QUERY_FLAG (tmp, FLAG_IS_TURNABLE))
994     SET_ANIMATION (tmp, i);
995 root 1.25
996     op->map->insert (tmp, op->x + freearr_x[i], op->y + freearr_x[i], op);
997 root 1.9 move_bullet (tmp);
998 root 1.6 }
999 elmex 1.1 }
1000    
1001 root 1.9 explode_bullet (op);
1002 elmex 1.1 }
1003    
1004 root 1.9 int
1005     create_bomb (object *op, object *caster, int dir, object *spell)
1006     {
1007     object *tmp;
1008     int mflags;
1009     sint16 dx = op->x + freearr_x[dir], dy = op->y + freearr_y[dir];
1010 root 1.15 maptile *m;
1011 elmex 1.1
1012 root 1.9 mflags = get_map_flags (op->map, &m, dx, dy, &dx, &dy);
1013 elmex 1.70
1014     // when creating a bomb below ourself it should always work, even
1015     // when movement is blocked (somehow we got here, somehow we are here,
1016     // so we should also be able to make a bomb here). (originally added
1017     // to fix create bomb traps in doors, which cast with dir=0).
1018     if (dir)
1019 root 1.9 {
1020 elmex 1.70 if ((mflags & P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK (m, dx, dy) & MOVE_WALK))
1021     {
1022     new_draw_info (NDI_UNIQUE, 0, op, "There is something in the way.");
1023     return 0;
1024     }
1025 elmex 1.1 }
1026 root 1.51
1027 root 1.9 tmp = arch_to_object (spell->other_arch);
1028 elmex 1.1
1029 root 1.9 /* level dependencies for bomb */
1030     tmp->range = spell->range + SP_level_range_adjust (caster, spell);
1031     tmp->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1032     tmp->duration = spell->duration + SP_level_duration_adjust (caster, spell);
1033     tmp->attacktype = spell->attacktype;
1034    
1035 root 1.19 tmp->set_owner (op);
1036 root 1.9 set_spell_skill (op, caster, spell, tmp);
1037 root 1.25
1038     m->insert (tmp, dx, dy, op);
1039 root 1.9 return 1;
1040 elmex 1.1 }
1041    
1042     /****************************************************************************
1043     *
1044     * smite related spell code.
1045     *
1046     ****************************************************************************/
1047    
1048     /* get_pointed_target() - this is used by finger of death
1049     * and the 'smite' spells. Returns the pointer to the first
1050     * monster in the direction which is pointed to by op. b.t.
1051     * op is the caster - really only used for the source location.
1052     * dir is the direction to look in.
1053     * range is how far out to look.
1054     * type is the type of spell - either SPELL_MANA or SPELL_GRACE.
1055     * this info is used for blocked magic/unholy spaces.
1056     */
1057 root 1.9 object *
1058     get_pointed_target (object *op, int dir, int range, int type)
1059     {
1060     object *target;
1061     sint16 x, y;
1062     int dist, mflags;
1063 root 1.15 maptile *mp;
1064 root 1.9
1065     if (dir == 0)
1066     return NULL;
1067    
1068     for (dist = 1; dist < range; dist++)
1069     {
1070     x = op->x + freearr_x[dir] * dist;
1071     y = op->y + freearr_y[dir] * dist;
1072     mp = op->map;
1073     mflags = get_map_flags (op->map, &mp, x, y, &x, &y);
1074    
1075     if (mflags & P_OUT_OF_MAP)
1076     return NULL;
1077     if ((type & SPELL_MANA) && (mflags & P_NO_MAGIC))
1078     return NULL;
1079     if ((type & SPELL_GRACE) && (mflags & P_NO_CLERIC))
1080     return NULL;
1081     if (GET_MAP_MOVE_BLOCK (mp, x, y) & MOVE_FLY_LOW)
1082     return NULL;
1083    
1084     if (mflags & P_IS_ALIVE)
1085 root 1.41 for (target = GET_MAP_OB (mp, x, y); target; target = target->above)
1086     if (QUERY_FLAG (target, FLAG_MONSTER))
1087     return target;
1088 elmex 1.1 }
1089 root 1.41
1090 root 1.9 return NULL;
1091 elmex 1.1 }
1092    
1093     /* cast_smite_arch() - the priest points to a creature and causes
1094     * a 'godly curse' to decend.
1095     * usual params -
1096     * op = player
1097     * caster = object casting the spell.
1098     * dir = direction being cast
1099     * spell = spell object
1100     */
1101 root 1.9 int
1102     cast_smite_spell (object *op, object *caster, int dir, object *spell)
1103     {
1104     object *effect, *target;
1105     object *god = find_god (determine_god (op));
1106     int range;
1107    
1108     range = spell->range + SP_level_range_adjust (caster, spell);
1109     target = get_pointed_target (op, dir, 50, spell->stats.grace ? SPELL_GRACE : SPELL_MANA);
1110    
1111     /* Bunch of conditions for casting this spell. Note that only
1112     * require a god if this is a cleric spell (requires grace).
1113     * This makes this spell much more general purpose - it can be used
1114     * by wizards also, which is good, because I think this is a very
1115     * interesting spell.
1116     * if it is a cleric spell, you need a god, and the creature
1117     * can't be friendly to your god.
1118     */
1119    
1120     if (!target || QUERY_FLAG (target, FLAG_REFL_SPELL)
1121     || (!god && spell->stats.grace)
1122     || (target->title && god && !strcmp (target->title, god->name)) || (target->race && god && strstr (target->race, god->race)))
1123     {
1124     new_draw_info (NDI_UNIQUE, 0, op, "Your request is unheeded.");
1125     return 0;
1126     }
1127    
1128     if (spell->other_arch)
1129     effect = arch_to_object (spell->other_arch);
1130     else
1131     return 0;
1132    
1133     /* tailor the effect by priest level and worshipped God */
1134 root 1.64 effect->level = casting_level (caster, spell);
1135 root 1.9 effect->attacktype = spell->attacktype;
1136     if (effect->attacktype & (AT_HOLYWORD | AT_GODPOWER))
1137     {
1138     if (tailor_god_spell (effect, op))
1139     new_draw_info_format (NDI_UNIQUE, 0, op, "%s answers your call!", determine_god (op));
1140     else
1141     {
1142     new_draw_info (NDI_UNIQUE, 0, op, "Your request is ignored.");
1143     return 0;
1144     }
1145 elmex 1.1 }
1146    
1147 root 1.9 /* size of the area of destruction */
1148     effect->range = spell->range + SP_level_range_adjust (caster, spell);
1149     effect->duration = spell->duration + SP_level_range_adjust (caster, spell);
1150    
1151     if (effect->attacktype & AT_DEATH)
1152     {
1153     effect->level = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1154 elmex 1.1
1155 root 1.9 /* casting death spells at undead isn't a good thing */
1156 root 1.20 if (QUERY_FLAG (target, FLAG_UNDEAD))
1157 root 1.9 {
1158     if (random_roll (0, 2, op, PREFER_LOW))
1159     {
1160     new_draw_info (NDI_UNIQUE, 0, op, "Idiot! Your spell boomerangs!");
1161     effect->x = op->x;
1162     effect->y = op->y;
1163     }
1164     else
1165     {
1166     new_draw_info_format (NDI_UNIQUE, 0, op, "The %s looks stronger!", query_name (target));
1167     target->stats.hp = target->stats.maxhp * 2;
1168 root 1.67 effect->destroy ();
1169 root 1.9 return 0;
1170 root 1.6 }
1171     }
1172 elmex 1.1 }
1173 root 1.9 else
1174     {
1175     /* how much woe to inflict :) */
1176     effect->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1177     }
1178    
1179 root 1.19 effect->set_owner (op);
1180 root 1.9 set_spell_skill (op, caster, spell, effect);
1181    
1182     /* ok, tell it where to be, and insert! */
1183 root 1.25 effect->insert_at (target, op);
1184 elmex 1.1
1185 root 1.9 return 1;
1186 elmex 1.1 }
1187    
1188     /****************************************************************************
1189     *
1190     * MAGIC MISSILE code.
1191     * note that the fire_bullet is used to fire the missile. The
1192     * code here is just to move the missile.
1193     ****************************************************************************/
1194    
1195     /* op is a missile that needs to be moved */
1196 root 1.9 void
1197     move_missile (object *op)
1198     {
1199     if (op->range-- <= 0)
1200     {
1201 root 1.66 op->drop_and_destroy ();
1202 root 1.9 return;
1203 elmex 1.1 }
1204    
1205 root 1.58 mapxy pos (op);
1206     pos.move (op->direction);
1207    
1208     if (!pos.normalise ())
1209 root 1.9 {
1210 root 1.67 op->destroy ();
1211 root 1.9 return;
1212 elmex 1.1 }
1213    
1214 root 1.58 mapspace &ms = pos.ms ();
1215 root 1.9
1216 root 1.58 if (ms.flags () & P_IS_ALIVE || ms.blocks (op))
1217 root 1.9 {
1218     hit_map (op, op->direction, AT_MAGIC, 1);
1219     /* Basically, missile only hits one thing then goes away.
1220     * we need to remove it if someone hasn't already done so.
1221     */
1222 root 1.67 op->destroy ();
1223 root 1.9 return;
1224 elmex 1.1 }
1225    
1226 root 1.58 if (!op->direction)
1227 root 1.9 {
1228 root 1.67 op->destroy ();
1229 root 1.9 return;
1230 elmex 1.1 }
1231 root 1.14
1232 root 1.58 int i = spell_find_dir (pos.m, pos.x, pos.y, op->owner);
1233 root 1.9 if (i > 0 && i != op->direction)
1234     {
1235     op->direction = i;
1236     SET_ANIMATION (op, op->direction);
1237 elmex 1.1 }
1238 root 1.14
1239 root 1.58 pos.insert (op, op);
1240 elmex 1.1 }
1241    
1242     /****************************************************************************
1243     * Destruction
1244     ****************************************************************************/
1245 root 1.9
1246 elmex 1.1 /* make_object_glow() - currently only makes living objects glow.
1247     * we do this by creating a force and inserting it in the
1248     * object. if time is 0, the object glows permanently. To truely
1249     * make this work for non-living objects, we would have to
1250     * give them the capability to have an inventory. b.t.
1251     */
1252 root 1.9 int
1253     make_object_glow (object *op, int radius, int time)
1254     {
1255     /* some things are unaffected... */
1256     if (op->path_denied & PATH_LIGHT)
1257     return 0;
1258    
1259 root 1.43 object *tmp = get_archetype (FORCE_NAME);
1260 root 1.9 tmp->speed = 0.01;
1261     tmp->stats.food = time;
1262     SET_FLAG (tmp, FLAG_IS_USED_UP);
1263 root 1.69 tmp->glow_radius = min (MAX_LIGHT_RADIUS, radius);
1264 root 1.9 tmp = insert_ob_in_ob (tmp, op);
1265 root 1.43
1266 root 1.9 if (tmp->glow_radius > op->glow_radius)
1267     op->glow_radius = tmp->glow_radius;
1268    
1269     return 1;
1270     }
1271    
1272     int
1273     cast_destruction (object *op, object *caster, object *spell_ob)
1274     {
1275     int i, j, range, mflags, friendly = 0, dam, dur;
1276     sint16 sx, sy;
1277 root 1.15 maptile *m;
1278 root 1.9 object *tmp;
1279     const char *skill;
1280    
1281     range = spell_ob->range + SP_level_range_adjust (caster, spell_ob);
1282     dam = spell_ob->stats.dam + SP_level_dam_adjust (caster, spell_ob);
1283     dur = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob);
1284     if (QUERY_FLAG (op, FLAG_FRIENDLY) || op->type == PLAYER)
1285     friendly = 1;
1286    
1287     /* destruction doesn't use another spell object, so we need
1288     * update op's skill pointer so that exp is properly awarded.
1289     * We do some shortcuts here - since this is just temporary
1290     * and we'll reset the values back, we don't need to go through
1291     * the full share string/free_string route.
1292     */
1293     skill = op->skill;
1294     if (caster == op)
1295     op->skill = spell_ob->skill;
1296     else if (caster->skill)
1297     op->skill = caster->skill;
1298     else
1299     op->skill = NULL;
1300 elmex 1.1
1301 root 1.35 op->change_skill (find_skill_by_name (op, op->skill));
1302 elmex 1.1
1303 root 1.58 for (i = -range; i <= range; i++)
1304 root 1.9 {
1305 root 1.58 for (j = -range; j <= range; j++)
1306 root 1.9 {
1307     m = op->map;
1308     sx = op->x + i;
1309     sy = op->y + j;
1310 root 1.25
1311 root 1.9 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
1312     if (mflags & P_OUT_OF_MAP)
1313     continue;
1314 root 1.25
1315 root 1.9 if (mflags & P_IS_ALIVE)
1316     {
1317 root 1.21 for (tmp = GET_MAP_OB (m, sx, sy); tmp; tmp = tmp->above)
1318 root 1.25 if (QUERY_FLAG (tmp, FLAG_ALIVE) || tmp->type == PLAYER)
1319     break;
1320    
1321 root 1.9 if (tmp)
1322     {
1323     if (tmp->head)
1324     tmp = tmp->head;
1325    
1326     if ((friendly && !QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->type != PLAYER) ||
1327     (!friendly && (QUERY_FLAG (tmp, FLAG_FRIENDLY) || tmp->type == PLAYER)))
1328     {
1329     if (spell_ob->subtype == SP_DESTRUCTION)
1330     {
1331     hit_player (tmp, dam, op, spell_ob->attacktype, 0);
1332 root 1.58
1333 root 1.9 if (spell_ob->other_arch)
1334 root 1.25 m->insert (arch_to_object (spell_ob->other_arch), sx, sy, op);
1335 root 1.6 }
1336 root 1.9 else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist[ATNR_MAGIC] != 100)
1337     {
1338     if (make_object_glow (tmp, 1, dur) && spell_ob->other_arch)
1339 root 1.25 m->insert (arch_to_object (spell_ob->other_arch), sx, sy, op);
1340 root 1.6 }
1341     }
1342     }
1343     }
1344     }
1345 elmex 1.1 }
1346 root 1.25
1347 root 1.9 op->skill = skill;
1348     return 1;
1349 elmex 1.1 }
1350    
1351     /***************************************************************************
1352     *
1353     * CURSE
1354     *
1355     ***************************************************************************/
1356    
1357 root 1.9 int
1358     cast_curse (object *op, object *caster, object *spell_ob, int dir)
1359     {
1360     object *god = find_god (determine_god (op));
1361     object *tmp, *force;
1362    
1363     tmp = get_pointed_target (op, (dir == 0) ? op->direction : dir, spell_ob->range, SPELL_GRACE);
1364     if (!tmp)
1365     {
1366     new_draw_info (NDI_UNIQUE, 0, op, "There is no one in that direction to curse.");
1367     return 0;
1368 elmex 1.1 }
1369    
1370 root 1.47 tmp = tmp->head_ ();
1371    
1372 root 1.9 /* If we've already got a force of this type, don't add a new one. */
1373 root 1.47 for (force = tmp->inv; force; force = force->below)
1374 root 1.9 {
1375     if (force->type == FORCE && force->subtype == FORCE_CHANGE_ABILITY)
1376     {
1377     if (force->name == spell_ob->name)
1378     {
1379     break;
1380 root 1.6 }
1381 root 1.9 else if (spell_ob->race && spell_ob->race == force->name)
1382     {
1383     new_draw_info_format (NDI_UNIQUE, 0, op, "You can not cast %s while %s is in effect", &spell_ob->name, &force->name_pl);
1384     return 0;
1385 root 1.6 }
1386     }
1387 elmex 1.1 }
1388    
1389 root 1.47 if (!force)
1390 root 1.9 {
1391     force = get_archetype (FORCE_NAME);
1392     force->subtype = FORCE_CHANGE_ABILITY;
1393 root 1.47
1394 root 1.9 if (spell_ob->race)
1395     force->name = spell_ob->race;
1396     else
1397     force->name = spell_ob->name;
1398 root 1.7
1399 root 1.9 force->name_pl = spell_ob->name;
1400 elmex 1.1
1401 root 1.9 }
1402     else
1403     {
1404     int duration;
1405    
1406     duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1407     if (duration > force->duration)
1408     {
1409     force->duration = duration;
1410     new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
1411     }
1412     else
1413 root 1.47 new_draw_info (NDI_UNIQUE, 0, op, "Recasting the spell had no effect.");
1414    
1415 root 1.9 return 1;
1416     }
1417 root 1.47
1418 root 1.9 force->duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1419 root 1.33 force->speed = 1.f;
1420     force->speed_left = -1.f;
1421 root 1.9 SET_FLAG (force, FLAG_APPLIED);
1422 elmex 1.1
1423 root 1.9 if (god)
1424     {
1425     if (spell_ob->last_grace)
1426     force->path_repelled = god->path_repelled;
1427     if (spell_ob->last_grace)
1428     force->path_denied = god->path_denied;
1429     new_draw_info_format (NDI_UNIQUE, 0, tmp, "You are a victim of %s's curse!", &god->name);
1430     }
1431     else
1432     new_draw_info (NDI_UNIQUE, 0, op, "Your curse seems empty.");
1433    
1434    
1435     if (tmp != op && op->type == PLAYER)
1436     new_draw_info_format (NDI_UNIQUE, 0, op, "You curse %s!", &tmp->name);
1437    
1438     force->stats.ac = spell_ob->stats.ac;
1439     force->stats.wc = spell_ob->stats.wc;
1440    
1441     change_abil (tmp, force); /* Mostly to display any messages */
1442     insert_ob_in_ob (force, tmp);
1443 root 1.22 tmp->update_stats ();
1444 root 1.9 return 1;
1445 elmex 1.1
1446     }
1447    
1448     /**********************************************************************
1449     * mood change
1450     * Arguably, this may or may not be an attack spell. But since it
1451     * effects monsters, it seems best to put it into this file
1452     ***********************************************************************/
1453    
1454     /* This covers the various spells that change the moods of monsters -
1455     * makes them angry, peacful, friendly, etc.
1456     */
1457 root 1.9 int
1458     mood_change (object *op, object *caster, object *spell)
1459     {
1460     object *tmp, *god, *head;
1461     int done_one, range, mflags, level, at, best_at;
1462     sint16 x, y, nx, ny;
1463 root 1.15 maptile *m;
1464 root 1.9 const char *race;
1465    
1466     /* We precompute some values here so that we don't have to keep
1467     * doing it over and over again.
1468     */
1469     god = find_god (determine_god (op));
1470 root 1.64 level = casting_level (caster, spell);
1471 root 1.9 range = spell->range + SP_level_range_adjust (caster, spell);
1472    
1473     /* On the bright side, no monster should ever have a race of GOD_...
1474     * so even if the player doesn't worship a god, if race=GOD_.., it
1475     * won't ever match anything.
1476     */
1477     if (!spell->race)
1478     race = NULL;
1479     else if (god && !strcmp (spell->race, "GOD_SLAYING"))
1480     race = god->slaying;
1481     else if (god && !strcmp (spell->race, "GOD_FRIEND"))
1482     race = god->race;
1483     else
1484     race = spell->race;
1485 elmex 1.1
1486 root 1.9 for (x = op->x - range; x <= op->x + range; x++)
1487     for (y = op->y - range; y <= op->y + range; y++)
1488     {
1489     done_one = 0;
1490     m = op->map;
1491     nx = x;
1492     ny = y;
1493     mflags = get_map_flags (m, &m, x, y, &nx, &ny);
1494     if (mflags & P_OUT_OF_MAP)
1495     continue;
1496    
1497     /* If there is nothing living on this space, no need to go further */
1498     if (!(mflags & P_IS_ALIVE))
1499     continue;
1500 elmex 1.1
1501 root 1.29 // players can only affect spaces that they can actually see
1502     if (caster && caster->contr
1503 root 1.72 && caster->contr->darkness_at (m, nx, ny) == LOS_BLOCKED)
1504 root 1.29 continue;
1505    
1506     for (tmp = GET_MAP_TOP (m, nx, ny); tmp; tmp = tmp->below)
1507 root 1.9 if (QUERY_FLAG (tmp, FLAG_MONSTER))
1508     break;
1509 root 1.6
1510 root 1.9 /* There can be living objects that are not monsters */
1511     if (!tmp || tmp->type == PLAYER)
1512     continue;
1513    
1514     /* Only the head has meaningful data, so resolve to that */
1515     if (tmp->head)
1516     head = tmp->head;
1517     else
1518     head = tmp;
1519 root 1.6
1520 root 1.9 /* Make sure the race is OK. Likewise, only effect undead if spell specifically allows it */
1521     if (race && head->race && !strstr (race, head->race))
1522     continue;
1523 root 1.29
1524 root 1.9 if (QUERY_FLAG (head, FLAG_UNDEAD) && !QUERY_FLAG (spell, FLAG_UNDEAD))
1525     continue;
1526    
1527     /* Now do a bunch of stuff related to saving throws */
1528     best_at = -1;
1529     if (spell->attacktype)
1530     {
1531     for (at = 0; at < NROFATTACKS; at++)
1532     if (spell->attacktype & (1 << at))
1533     if (best_at == -1 || head->resist[at] > head->resist[best_at])
1534     best_at = at;
1535 elmex 1.1
1536 root 1.9 if (best_at == -1)
1537     at = 0;
1538     else
1539     {
1540     if (head->resist[best_at] == 100)
1541     continue;
1542     else
1543     at = head->resist[best_at] / 5;
1544     }
1545     at -= level / 5;
1546     if (did_make_save (head, head->level, at))
1547     continue;
1548     }
1549     else /* spell->attacktype */
1550 root 1.36 {
1551     /*
1552     Spell has no attacktype (charm & such), so we'll have a specific saving:
1553     * if spell level < monster level, no go
1554     * else, chance of effect = 20 + min( 50, 2 * ( spell level - monster level ) )
1555 root 1.9
1556 root 1.36 The chance will then be in the range [20-70] percent, not too bad.
1557 root 1.9
1558 root 1.36 This is required to fix the 'charm monster' abuse, where a player level 1 can
1559     charm a level 125 monster...
1560 root 1.9
1561 root 1.36 Ryo, august 14th
1562     */
1563 root 1.9 if (head->level > level)
1564     continue;
1565 root 1.36
1566 root 1.9 if (random_roll (0, 100, caster, PREFER_LOW) >= (20 + MIN (50, 2 * (level - head->level))))
1567     /* Failed, no effect */
1568     continue;
1569     }
1570    
1571 root 1.29 /* Done with saving throw. Now start affecting the monster */
1572 root 1.9
1573     /* aggravation */
1574     if (QUERY_FLAG (spell, FLAG_MONSTER))
1575     {
1576     CLEAR_FLAG (head, FLAG_SLEEP);
1577 root 1.32 remove_friendly_object (head);
1578 root 1.9 done_one = 1;
1579     head->enemy = op;
1580     }
1581    
1582     /* calm monsters */
1583     if (QUERY_FLAG (spell, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (head, FLAG_UNAGGRESSIVE))
1584     {
1585     SET_FLAG (head, FLAG_UNAGGRESSIVE);
1586     head->enemy = NULL;
1587     done_one = 1;
1588     }
1589    
1590     /* berserk monsters */
1591     if (QUERY_FLAG (spell, FLAG_BERSERK) && !QUERY_FLAG (head, FLAG_BERSERK))
1592     {
1593     SET_FLAG (head, FLAG_BERSERK);
1594     done_one = 1;
1595     }
1596 root 1.27
1597 root 1.9 /* charm */
1598     if (QUERY_FLAG (spell, FLAG_NO_ATTACK) && !QUERY_FLAG (head, FLAG_FRIENDLY))
1599     {
1600 root 1.54 INVOKE_OBJECT (KILL, head, ARG_OBJECT (caster));
1601    
1602     /* Prevent uncontrolled outbreaks of self replicating monsters.
1603 root 1.9 Typical use case is charm, go somwhere, use aggravation to make hostile.
1604     This could lead to fun stuff like mice outbreak in bigworld and server crawl. */
1605     CLEAR_FLAG (head, FLAG_GENERATOR);
1606 root 1.19 head->set_owner (op);
1607 root 1.9 set_spell_skill (op, caster, spell, head);
1608     add_friendly_object (head);
1609     head->attack_movement = PETMOVE;
1610     done_one = 1;
1611     change_exp (op, head->stats.exp / 2, head->skill, SK_EXP_ADD_SKILL);
1612     head->stats.exp = 0;
1613     }
1614    
1615     /* If a monster was effected, put an effect in */
1616     if (done_one && spell->other_arch)
1617 root 1.25 m->insert (arch_to_object (spell->other_arch), nx, ny, op);
1618 root 1.9 } /* for y */
1619 elmex 1.1
1620 root 1.9 return 1;
1621 elmex 1.1 }
1622    
1623     /* Move_ball_spell: This handles ball type spells that just sort of wander
1624     * about. was called move_ball_lightning, but since more than the ball
1625     * lightning spell used it, that seemed misnamed.
1626     * op is the spell effect.
1627     * note that duration is handled by process_object() in time.c
1628     */
1629 root 1.9 void
1630     move_ball_spell (object *op)
1631     {
1632     int i, j, dam_save, dir, mflags;
1633     sint16 nx, ny, hx, hy;
1634     object *owner;
1635 root 1.15 maptile *m;
1636 root 1.9
1637 root 1.19 owner = op->owner;
1638 root 1.9
1639     /* the following logic makes sure that the ball doesn't move into a wall,
1640     * and makes sure that it will move along a wall to try and get at it's
1641     * victim. The block immediately below more or less chooses a random
1642     * offset to move the ball, eg, keep it mostly on course, with some
1643     * deviations.
1644     */
1645    
1646     dir = 0;
1647     if (!(rndm (0, 3)))
1648     j = rndm (0, 1);
1649     else
1650     j = 0;
1651    
1652     for (i = 1; i < 9; i++)
1653     {
1654     /* i bit 0: alters sign of offset
1655     * other bits (i / 2): absolute value of offset
1656     */
1657     int offset = ((i ^ j) & 1) ? (i / 2) : -(i / 2);
1658     int tmpdir = absdir (op->direction + offset);
1659    
1660     nx = op->x + freearr_x[tmpdir];
1661     ny = op->y + freearr_y[tmpdir];
1662     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))))
1663     {
1664     dir = tmpdir;
1665     break;
1666 root 1.6 }
1667 elmex 1.1 }
1668 root 1.71
1669 root 1.9 if (dir == 0)
1670     {
1671     nx = op->x;
1672     ny = op->y;
1673     m = op->map;
1674     }
1675    
1676 root 1.25 m->insert (op, nx, ny, op);
1677 root 1.9
1678     dam_save = op->stats.dam; /* save the original dam: we do halfdam on
1679     surrounding squares */
1680    
1681     /* loop over current square and neighbors to hit.
1682     * if this has an other_arch field, we insert that in
1683     * the surround spaces.
1684     */
1685     for (j = 0; j < 9; j++)
1686     {
1687     hx = nx + freearr_x[j];
1688     hy = ny + freearr_y[j];
1689 elmex 1.1
1690 root 1.9 m = op->map;
1691     mflags = get_map_flags (m, &m, hx, hy, &hx, &hy);
1692 elmex 1.1
1693 root 1.9 if (mflags & P_OUT_OF_MAP)
1694     continue;
1695 elmex 1.1
1696 root 1.9 /* first, don't ever, ever hit the owner. Don't hit out
1697     * of the map either.
1698     */
1699 elmex 1.1
1700 root 1.9 if ((mflags & P_IS_ALIVE) && (!owner || owner->x != hx || owner->y != hy || !on_same_map (owner, op)))
1701     {
1702     if (j)
1703     op->stats.dam = dam_save / 2;
1704 root 1.58
1705 root 1.9 hit_map (op, j, op->attacktype, 1);
1706 root 1.6 }
1707 elmex 1.1
1708 root 1.9 /* insert the other arch */
1709     if (op->other_arch && !(OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy))))
1710 root 1.25 m->insert (arch_to_object (op->other_arch), hx, hy, op);
1711 elmex 1.1 }
1712    
1713 root 1.9 /* restore to the center location and damage */
1714     op->stats.dam = dam_save;
1715 elmex 1.1
1716 root 1.19 i = spell_find_dir (op->map, op->x, op->y, op->owner);
1717 elmex 1.1
1718 root 1.9 if (i >= 0)
1719     { /* we have a preferred direction! */
1720     /* pick another direction if the preferred dir is blocked. */
1721     if (get_map_flags (op->map, &m, nx + freearr_x[i], ny + freearr_y[i], &hx, &hy) & P_OUT_OF_MAP ||
1722     OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy)))
1723 root 1.25 i = absdir (i + rndm (0, 2) - 1); /* -1, 0, +1 */
1724    
1725 root 1.9 op->direction = i;
1726 elmex 1.1 }
1727     }
1728    
1729 root 1.55 /* move_swarm_spell: peterm
1730 elmex 1.1 * This is an implementation of the swarm spell. It was written for
1731 root 1.55 * meteor swarm, but it could be used for any swarm. A swarm spell
1732 elmex 1.1 * is a special type of object that casts swarms of other types
1733 root 1.55 * of spells. Which spell it casts is flexible. It fires the spells
1734 elmex 1.1 * from a set of squares surrounding the caster, in a given direction.
1735     */
1736 root 1.9 void
1737     move_swarm_spell (object *op)
1738 elmex 1.1 {
1739 pippijn 1.8 #if 0
1740 root 1.9 static int cardinal_adjust[9] = { -3, -2, -1, 0, 0, 0, 1, 2, 3 };
1741     static int diagonal_adjust[10] = { -3, -2, -2, -1, 0, 0, 1, 2, 2, 3 };
1742     sint16 target_x, target_y, origin_x, origin_y;
1743     int adjustdir;
1744 root 1.15 maptile *m;
1745 pippijn 1.8 #endif
1746 root 1.55 object *owner = op->env;
1747 elmex 1.1
1748 root 1.59 if (!owner) // MUST not happen, remove when true TODO
1749     {
1750     LOG (llevError, "swarm spell found outside inventory: %s\n", op->debug_desc ());
1751 root 1.67 op->destroy ();
1752 root 1.59 return;
1753     }
1754    
1755 root 1.55 if (!op->duration || !owner->is_on_map ())
1756 root 1.9 {
1757 root 1.66 op->drop_and_destroy ();
1758 root 1.9 return;
1759 elmex 1.1 }
1760 root 1.17
1761 root 1.9 op->duration--;
1762 elmex 1.1
1763 root 1.55 int basedir = op->direction;
1764     if (!basedir)
1765 root 1.61 {
1766     /* spray in all directions! 8) */
1767     op->facing = (op->facing + op->state) & 7;
1768     basedir = op->facing + 1;
1769     }
1770 elmex 1.1
1771     #if 0
1772 root 1.9 // this is bogus: it causes wrong places to be checked below
1773     // (a wall 2 cells away will block the effect...) and
1774     // doesn't work for SP_BULLET anyhow, so again tests the wrong
1775     // space.
1776 root 1.31 // should be fixed later, but correctness before features...
1777 root 1.9 // (schmorp)
1778    
1779     /* new offset calculation to make swarm element distribution
1780     * more uniform
1781     */
1782     if (op->duration)
1783     {
1784     if (basedir & 1)
1785     {
1786     adjustdir = cardinal_adjust[rndm (0, 8)];
1787     }
1788     else
1789     {
1790     adjustdir = diagonal_adjust[rndm (0, 9)];
1791     }
1792     }
1793     else
1794     {
1795     adjustdir = 0; /* fire the last one from forward. */
1796     }
1797    
1798     target_x = op->x + freearr_x[absdir (basedir + adjustdir)];
1799     target_y = op->y + freearr_y[absdir (basedir + adjustdir)];
1800    
1801     /* back up one space so we can hit point-blank targets, but this
1802     * necessitates extra out_of_map check below
1803     */
1804     origin_x = target_x - freearr_x[basedir];
1805     origin_y = target_y - freearr_y[basedir];
1806    
1807    
1808     /* spell pointer is set up for the spell this casts. Since this
1809     * should just be a pointer to the spell in some inventory,
1810     * it is unlikely to disappear by the time we need it. However,
1811     * do some sanity checking anyways.
1812     */
1813    
1814     if (op->spell && op->spell->type == SPELL &&
1815     !(get_map_flags (op->map, &m, target_x, target_y, &target_x, &target_y) & P_OUT_OF_MAP) &&
1816     !(OB_TYPE_MOVE_BLOCK (op->spell, GET_MAP_MOVE_BLOCK (m, target_x, target_y))))
1817     {
1818    
1819     /* Bullet spells have a bunch more customization that needs to be done */
1820     if (op->spell->subtype == SP_BULLET)
1821     fire_bullet (owner, op, basedir, op->spell);
1822     else if (op->spell->subtype == SP_MAGIC_MISSILE)
1823     fire_arch_from_position (owner, op, origin_x, origin_y, basedir, op->spell);
1824 elmex 1.1 }
1825     #endif
1826    
1827 root 1.9 /* spell pointer is set up for the spell this casts. Since this
1828     * should just be a pointer to the spell in some inventory,
1829     * it is unlikely to disappear by the time we need it. However,
1830     * do some sanity checking anyways.
1831     */
1832    
1833     if (op->spell && op->spell->type == SPELL)
1834     {
1835     /* Bullet spells have a bunch more customization that needs to be done */
1836     if (op->spell->subtype == SP_BULLET)
1837     fire_bullet (owner, op, basedir, op->spell);
1838     else if (op->spell->subtype == SP_MAGIC_MISSILE)
1839 root 1.57 fire_arch_from_position (owner, op, owner->x, owner->y, basedir, op->spell);
1840 root 1.9 }
1841 elmex 1.1 }
1842    
1843     /* fire_swarm:
1844     * The following routine creates a swarm of objects. It actually
1845     * sets up a specific swarm object, which then fires off all
1846     * the parts of the swarm.
1847     *
1848     * op: the owner
1849     * caster: the caster (owner, wand, rod, scroll)
1850     * dir: the direction everything will be fired in
1851     * spell - the spell that is this spell.
1852     * n: the number to be fired.
1853     */
1854 root 1.9 int
1855     fire_swarm (object *op, object *caster, object *spell, int dir)
1856 elmex 1.1 {
1857 root 1.9 if (!spell->other_arch)
1858     return 0;
1859 elmex 1.1
1860 root 1.55 object *tmp = archetype::get (SWARM_SPELL);
1861 root 1.61
1862 root 1.9 set_spell_skill (op, caster, spell, tmp);
1863 root 1.64 tmp->level = casting_level (caster, spell); /* needed later, to get level dep. right. */
1864 root 1.55 tmp->spell = spell->other_arch->instance ();
1865 root 1.9 tmp->attacktype = tmp->spell->attacktype;
1866 elmex 1.1
1867 root 1.9 if (tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER)
1868 root 1.25 if (!tailor_god_spell (tmp, op))
1869     return 1;
1870    
1871 root 1.9 tmp->duration = SP_level_duration_adjust (caster, spell);
1872 root 1.55 for (int i = 0; i < spell->duration; i++)
1873 root 1.9 tmp->duration += die_roll (1, 3, op, PREFER_HIGH);
1874    
1875 root 1.59 tmp->invisible = 1;
1876     tmp->flag [FLAG_NO_DROP] = 1; // make sure it stays in inv, or else
1877 root 1.9 tmp->direction = dir;
1878 root 1.57 tmp->facing = rndm (1, 8); // initial firing direction
1879 root 1.56 tmp->state = rndm (4) * 2 + 1; // direction increment
1880 root 1.25
1881 root 1.55 op->insert (tmp);
1882    
1883 root 1.9 return 1;
1884 elmex 1.1 }
1885    
1886     /* See the spells documentation file for why this is its own
1887     * function.
1888     */
1889 root 1.9 int
1890     cast_light (object *op, object *caster, object *spell, int dir)
1891     {
1892     object *target = NULL, *tmp = NULL;
1893     sint16 x, y;
1894     int dam, mflags;
1895 root 1.15 maptile *m;
1896 elmex 1.1
1897 root 1.9 dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1898 elmex 1.1
1899 root 1.69 if (dir)
1900 root 1.9 {
1901 root 1.69 x = op->x + freearr_x[dir];
1902     y = op->y + freearr_y[dir];
1903     m = op->map;
1904 elmex 1.1
1905 root 1.69 mflags = get_map_flags (m, &m, x, y, &x, &y);
1906 elmex 1.1
1907 root 1.69 if (mflags & P_OUT_OF_MAP)
1908     {
1909     new_draw_info (NDI_UNIQUE, 0, op, "Nothing is there.");
1910     return 0;
1911     }
1912 elmex 1.1
1913 root 1.69 if (mflags & P_IS_ALIVE && spell->attacktype)
1914     {
1915     for (target = GET_MAP_OB (m, x, y); target; target = target->above)
1916     if (QUERY_FLAG (target, FLAG_MONSTER))
1917     {
1918     /* oky doky. got a target monster. Lets make a blinding attack */
1919     if (target->head)
1920     target = target->head;
1921 elmex 1.1
1922 root 1.69 hit_player (target, dam, op, spell->attacktype, 1);
1923     return 1; /* one success only! */
1924     }
1925     }
1926 root 1.58
1927 root 1.69 /* no live target, perhaps a wall is in the way? */
1928     if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y)))
1929     {
1930     new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way.");
1931     return 0;
1932     }
1933 elmex 1.1 }
1934    
1935 root 1.9 /* ok, looks groovy to just insert a new light on the map */
1936     tmp = arch_to_object (spell->other_arch);
1937     if (!tmp)
1938     {
1939     LOG (llevError, "Error: spell arch for cast_light() missing.\n");
1940     return 0;
1941     }
1942 root 1.69
1943 root 1.9 tmp->stats.food = spell->duration + SP_level_duration_adjust (caster, spell);
1944 root 1.69
1945 root 1.9 if (tmp->glow_radius)
1946 root 1.69 tmp->glow_radius = min (MAX_LIGHT_RADIUS, spell->range + SP_level_range_adjust (caster, spell));
1947    
1948     if (dir)
1949     m->insert (tmp, x, y, op);
1950     else
1951     caster->outer_env ()->insert (tmp);
1952 root 1.25
1953 root 1.9 return 1;
1954 elmex 1.1 }
1955    
1956     /* cast_cause_disease: this spell looks along <dir> from the
1957     * player and infects someone.
1958     * op is the player/monster, caster is the object, dir is the direction
1959     * to cast, disease_arch is the specific disease, and type is the spell number
1960     * perhaps this should actually be in disease.c?
1961     */
1962 root 1.9 int
1963     cast_cause_disease (object *op, object *caster, object *spell, int dir)
1964     {
1965     sint16 x, y;
1966     int i, mflags, range, dam_mod, dur_mod;
1967     object *walk;
1968 root 1.15 maptile *m;
1969 root 1.9
1970     x = op->x;
1971     y = op->y;
1972    
1973     /* If casting from a scroll, no direction will be available, so refer to the
1974     * direction the player is pointing.
1975     */
1976     if (!dir)
1977     dir = op->facing;
1978 root 1.48
1979 root 1.9 if (!dir)
1980     return 0; /* won't find anything if casting on ourself, so just return */
1981    
1982     /* Calculate these once here */
1983     range = spell->range + SP_level_range_adjust (caster, spell);
1984     dam_mod = SP_level_dam_adjust (caster, spell);
1985     dur_mod = SP_level_duration_adjust (caster, spell);
1986    
1987     /* search in a line for a victim */
1988     for (i = 1; i < range; i++)
1989     {
1990     x = op->x + i * freearr_x[dir];
1991     y = op->y + i * freearr_y[dir];
1992     m = op->map;
1993    
1994     mflags = get_map_flags (m, &m, x, y, &x, &y);
1995    
1996     if (mflags & P_OUT_OF_MAP)
1997     return 0;
1998    
1999     /* don't go through walls - presume diseases are airborne */
2000     if (GET_MAP_MOVE_BLOCK (m, x, y) & MOVE_FLY_LOW)
2001     return 0;
2002    
2003     /* Only bother looking on this space if there is something living here */
2004     if (mflags & P_IS_ALIVE)
2005     {
2006     /* search this square for a victim */
2007 root 1.21 for (walk = GET_MAP_OB (m, x, y); walk; walk = walk->above)
2008 root 1.9 if (QUERY_FLAG (walk, FLAG_MONSTER) || (walk->type == PLAYER))
2009     { /* found a victim */
2010     object *disease = arch_to_object (spell->other_arch);
2011    
2012 root 1.19 disease->set_owner (op);
2013 root 1.9 set_spell_skill (op, caster, spell, disease);
2014     disease->stats.exp = 0;
2015 root 1.64 disease->level = casting_level (caster, spell);
2016 root 1.9
2017     /* do level adjustments */
2018     if (disease->stats.wc)
2019     disease->stats.wc += dur_mod / 2;
2020    
2021     if (disease->magic > 0)
2022 root 1.48 disease->magic += dur_mod / 8;
2023 root 1.9
2024     if (disease->stats.maxhp > 0)
2025     disease->stats.maxhp += dur_mod;
2026    
2027     if (disease->stats.maxgrace > 0)
2028     disease->stats.maxgrace += dur_mod;
2029    
2030     if (disease->stats.dam)
2031     {
2032     if (disease->stats.dam > 0)
2033     disease->stats.dam += dam_mod;
2034     else
2035     disease->stats.dam -= dam_mod;
2036     }
2037 root 1.6
2038 root 1.9 if (disease->last_sp)
2039     {
2040     disease->last_sp -= 2 * dam_mod;
2041     if (disease->last_sp < 1)
2042     disease->last_sp = 1;
2043     }
2044 root 1.6
2045 root 1.9 if (disease->stats.maxsp)
2046     {
2047     if (disease->stats.maxsp > 0)
2048     disease->stats.maxsp += dam_mod;
2049     else
2050     disease->stats.maxsp -= dam_mod;
2051     }
2052 root 1.6
2053 root 1.9 if (disease->stats.ac)
2054     disease->stats.ac += dam_mod;
2055 root 1.6
2056 root 1.9 if (disease->last_eat)
2057     disease->last_eat -= dam_mod;
2058 root 1.6
2059 root 1.9 if (disease->stats.hp)
2060     disease->stats.hp -= dam_mod;
2061 root 1.6
2062 root 1.9 if (disease->stats.sp)
2063     disease->stats.sp -= dam_mod;
2064    
2065     if (infect_object (walk, disease, 1))
2066     {
2067     new_draw_info_format (NDI_UNIQUE, 0, op, "You inflict %s on %s!", &disease->name, &walk->name);
2068    
2069 root 1.67 disease->destroy (); /* don't need this one anymore */
2070 root 1.40 walk->map->insert (get_archetype ("detect_magic"), x, y, op);
2071 root 1.9 return 1;
2072 root 1.6 }
2073 root 1.17
2074 root 1.67 disease->destroy ();
2075 root 1.9 }
2076     } /* if living creature */
2077     } /* for range of spaces */
2078 root 1.25
2079 root 1.9 new_draw_info (NDI_UNIQUE, 0, op, "No one caught anything!");
2080     return 1;
2081 elmex 1.1 }