ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.42
Committed: Sun Jul 1 05:00:20 2007 UTC (16 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.41: +10 -11 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

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