ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.47
Committed: Wed Aug 15 18:06:32 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.46: +8 -5 lines
Log Message:
fix cast curse w.r.t. head

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 root 1.46 * explosion - this expands it in the different directions.
349 elmex 1.1 * 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.45 tmp->play_sound (tmp->sound);
489    
490 root 1.9 /* remove the firebullet */
491 root 1.25 op->destroy ();
492 elmex 1.1 }
493    
494     /* checks to see what op should do, given the space it is on
495     * (eg, explode, damage player, etc)
496     */
497 root 1.9 void
498     check_bullet (object *op)
499 elmex 1.1 {
500 root 1.9 object *tmp;
501     int dam, mflags;
502 root 1.15 maptile *m;
503 root 1.9 sint16 sx, sy;
504 elmex 1.1
505 root 1.9 mflags = get_map_flags (op->map, &m, op->x, op->y, &sx, &sy);
506 elmex 1.1
507 root 1.9 if (!(mflags & P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, sx, sy)))
508     return;
509 elmex 1.1
510 root 1.9 if (op->other_arch)
511     {
512     /* explode object will also remove op */
513     explode_bullet (op);
514     return;
515 elmex 1.1 }
516    
517 root 1.9 /* If nothing alive on this space, no reason to do anything further */
518     if (!(mflags & P_IS_ALIVE))
519     return;
520 elmex 1.1
521 root 1.31 for (tmp = op->ms ().bot; tmp; tmp = tmp->above)
522 elmex 1.1 {
523 root 1.9 if (QUERY_FLAG (tmp, FLAG_ALIVE))
524     {
525     dam = hit_player (tmp, op->stats.dam, op, op->attacktype, 1);
526 root 1.14 if (op->destroyed () || !tmp->destroyed () || (op->stats.dam -= dam) < 0)
527 elmex 1.1 {
528 root 1.9 if (!QUERY_FLAG (op, FLAG_REMOVED))
529     {
530 root 1.17 op->destroy ();
531 root 1.9 return;
532 root 1.6 }
533 elmex 1.1 }
534     }
535     }
536     }
537    
538     /* Basically, we move 'op' one square, and if it hits something,
539     * call check_bullet.
540     * This function is only applicable to bullets, but not to all
541     * fired arches (eg, bolts).
542     */
543 root 1.9 void
544     move_bullet (object *op)
545 elmex 1.1 {
546 root 1.9 sint16 new_x, new_y;
547     int mflags;
548 root 1.15 maptile *m;
549 elmex 1.1
550     #if 0
551 root 1.9 /* We need a better general purpose way to do this */
552 elmex 1.1
553 root 1.9 /* peterm: added to make comet leave a trail of burnouts
554     it's an unadulterated hack, but the effect is cool. */
555     if (op->stats.sp == SP_METEOR)
556     {
557     replace_insert_ob_in_map ("fire_trail", op);
558 root 1.14 if (op->destroyed ())
559 elmex 1.1 return;
560 root 1.9 } /* end addition. */
561 elmex 1.1 #endif
562    
563 root 1.9 /* Reached the end of its life - remove it */
564     if (--op->range <= 0)
565     {
566     if (op->other_arch)
567 root 1.17 explode_bullet (op);
568 root 1.9 else
569 root 1.17 op->destroy ();
570    
571 root 1.9 return;
572 elmex 1.1 }
573    
574 root 1.9 new_x = op->x + DIRX (op);
575     new_y = op->y + DIRY (op);
576     m = op->map;
577     mflags = get_map_flags (m, &m, new_x, new_y, &new_x, &new_y);
578    
579     if (mflags & P_OUT_OF_MAP)
580     {
581 root 1.17 op->destroy ();
582 root 1.9 return;
583 elmex 1.1 }
584    
585 root 1.9 if (!op->direction || OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, new_x, new_y)))
586     {
587     if (op->other_arch)
588 root 1.17 explode_bullet (op);
589 root 1.9 else
590 root 1.17 op->destroy ();
591    
592 root 1.9 return;
593 elmex 1.1 }
594    
595 root 1.25 if (!(op = m->insert (op, new_x, new_y, op)))
596 root 1.9 return;
597 elmex 1.1
598 root 1.9 if (reflwall (op->map, op->x, op->y, op))
599     {
600     op->direction = absdir (op->direction + 4);
601     update_turn_face (op);
602     }
603     else
604 root 1.23 check_bullet (op);
605 elmex 1.1 }
606    
607     /* fire_bullet
608     * object op (cast from caster) files a bolt in dir.
609     * spob is the spell object for the bolt.
610     * we remove the magic flag - that can be derived from
611     * spob->attacktype.
612     * This function sets up the appropriate owner and skill
613     * pointers.
614     */
615 root 1.9 int
616     fire_bullet (object *op, object *caster, int dir, object *spob)
617     {
618     object *tmp = NULL;
619     int mflags;
620 elmex 1.1
621 root 1.9 if (!spob->other_arch)
622     return 0;
623 elmex 1.1
624 root 1.9 tmp = arch_to_object (spob->other_arch);
625     if (tmp == NULL)
626     return 0;
627    
628     /* peterm: level dependency for bolts */
629     tmp->stats.dam = spob->stats.dam + SP_level_dam_adjust (caster, spob);
630     tmp->attacktype = spob->attacktype;
631     if (spob->slaying)
632     tmp->slaying = spob->slaying;
633    
634     tmp->range = 50;
635    
636     /* Need to store duration/range for the ball to use */
637     tmp->stats.hp = spob->duration + SP_level_duration_adjust (caster, spob);
638     tmp->stats.maxhp = spob->range + SP_level_range_adjust (caster, spob);
639     tmp->dam_modifier = spob->stats.food + SP_level_dam_adjust (caster, spob);
640    
641     tmp->direction = dir;
642     if (QUERY_FLAG (tmp, FLAG_IS_TURNABLE))
643     SET_ANIMATION (tmp, dir);
644    
645 root 1.19 tmp->set_owner (op);
646 root 1.9 set_spell_skill (op, caster, spob, tmp);
647    
648     tmp->x = op->x + freearr_x[dir];
649     tmp->y = op->y + freearr_y[dir];
650     tmp->map = op->map;
651 elmex 1.1
652 root 1.23 maptile *newmap;
653     mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y);
654 root 1.9 if (mflags & P_OUT_OF_MAP)
655     {
656 root 1.17 tmp->destroy ();
657 root 1.9 return 0;
658 elmex 1.1 }
659 root 1.17
660 root 1.23 tmp->map = newmap;
661    
662 root 1.9 if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y)))
663     {
664     if (!QUERY_FLAG (tmp, FLAG_REFLECTING))
665     {
666 root 1.17 tmp->destroy ();
667 root 1.9 return 0;
668     }
669 root 1.17
670 root 1.9 tmp->x = op->x;
671     tmp->y = op->y;
672     tmp->direction = absdir (tmp->direction + 4);
673     tmp->map = op->map;
674 elmex 1.1 }
675 root 1.17
676 root 1.25 if ((tmp = tmp->insert_at (tmp, op)))
677 root 1.17 check_bullet (tmp);
678    
679 root 1.9 return 1;
680 elmex 1.1 }
681    
682     /*****************************************************************************
683     *
684     * CONE RELATED FUNCTIONS
685     *
686     *****************************************************************************/
687    
688     /* drops an object based on what is in the cone's "other_arch" */
689 root 1.9 void
690     cone_drop (object *op)
691     {
692     object *new_ob = arch_to_object (op->other_arch);
693 elmex 1.1
694 root 1.9 new_ob->level = op->level;
695 root 1.19 new_ob->set_owner (op->owner);
696 root 1.9
697     /* preserve skill ownership */
698     if (op->skill && op->skill != new_ob->skill)
699 root 1.25 new_ob->skill = op->skill;
700 root 1.9
701 root 1.25 new_ob->insert_at (op, op);
702 elmex 1.1 }
703    
704     /* move_cone: causes cone object 'op' to move a space/hit creatures */
705    
706 root 1.9 void
707     move_cone (object *op)
708     {
709     int i;
710    
711     /* if no map then hit_map will crash so just ignore object */
712     if (!op->map)
713     {
714     LOG (llevError, "Tried to move_cone object %s without a map.\n", op->name ? &op->name : "unknown");
715 root 1.24 op->set_speed (0);
716 root 1.9 return;
717 elmex 1.1 }
718    
719 root 1.9 /* lava saves it's life, but not yours :) */
720     if (QUERY_FLAG (op, FLAG_LIFESAVE))
721     {
722     hit_map (op, 0, op->attacktype, 0);
723     return;
724 elmex 1.1 }
725    
726     #if 0
727 root 1.9 /* Disable this - enabling it makes monsters easier, as
728     * when their cone dies when they die.
729     */
730     /* If no owner left, the spell dies out. */
731 root 1.19 if (op->owner == NULL)
732 root 1.9 {
733 root 1.17 op->destroy ();
734 root 1.9 return;
735 elmex 1.1 }
736     #endif
737    
738 root 1.9 hit_map (op, 0, op->attacktype, 0);
739 elmex 1.1
740 root 1.9 /* Check to see if we should push anything.
741     * Spell objects with weight push whatever they encounter to some
742     * degree.
743     */
744     if (op->weight)
745     check_spell_knockback (op);
746 elmex 1.1
747 root 1.14 if (op->destroyed ())
748 root 1.9 return;
749 elmex 1.1
750 root 1.9 if ((op->duration--) < 0)
751     {
752 root 1.17 op->destroy ();
753 root 1.9 return;
754     }
755     /* Object has hit maximum range, so don't have it move
756     * any further. When the duration above expires,
757     * then the object will get removed.
758     */
759     if (--op->range < 0)
760     {
761     op->range = 0; /* just so it doesn't wrap */
762     return;
763 elmex 1.1 }
764    
765 root 1.9 for (i = -1; i < 2; i++)
766     {
767     sint16 x = op->x + freearr_x[absdir (op->stats.sp + i)], y = op->y + freearr_y[absdir (op->stats.sp + i)];
768    
769     if (ok_to_put_more (op->map, x, y, op, op->attacktype))
770     {
771 root 1.18 object *tmp = op->clone ();
772 root 1.9
773     tmp->duration = op->duration + 1;
774    
775     /* Use for spell tracking - see ok_to_put_more() */
776     tmp->stats.maxhp = op->stats.maxhp;
777 root 1.25
778     op->map->insert (tmp, x, y, op);
779    
780 root 1.9 if (tmp->other_arch)
781     cone_drop (tmp);
782 root 1.6 }
783 elmex 1.1 }
784     }
785    
786     /* cast_cone: casts a cone spell.
787     * op: person firing the object.
788     * caster: object casting the spell.
789     * dir: direction to fire in.
790     * spell: spell that is being fired. It uses other_arch for the archetype
791     * to fire.
792     * returns 0 on failure, 1 on success.
793     */
794 root 1.9 int
795     cast_cone (object *op, object *caster, int dir, object *spell)
796 elmex 1.1 {
797 root 1.9 object *tmp;
798     int i, success = 0, range_min = -1, range_max = 1;
799 root 1.15 maptile *m;
800 root 1.9 sint16 sx, sy;
801     MoveType movetype;
802    
803     if (!spell->other_arch)
804     return 0;
805    
806     if (op->type == PLAYER && QUERY_FLAG (op, FLAG_UNDEAD) && op->attacktype & AT_TURN_UNDEAD)
807     {
808     new_draw_info (NDI_UNIQUE, 0, op, "Your undead nature prevents you from turning undead!");
809     return 0;
810     }
811    
812     if (!dir)
813     {
814     range_min = 0;
815     range_max = 8;
816 elmex 1.1 }
817    
818 root 1.9 /* Need to know what the movetype of the object we are about
819     * to create is, so we can know if the space we are about to
820     * insert it into is blocked.
821     */
822 root 1.39 movetype = spell->other_arch->move_type;
823 root 1.6
824 root 1.9 for (i = range_min; i <= range_max; i++)
825     {
826     sint16 x, y, d;
827 elmex 1.1
828 root 1.9 /* We can't use absdir here, because it never returns
829     * 0. If this is a rune, we want to hit the person on top
830     * of the trap (d==0). If it is not a rune, then we don't want
831     * to hit that person.
832     */
833     d = dir + i;
834     while (d < 0)
835     d += 8;
836     while (d > 8)
837     d -= 8;
838    
839     /* If it's not a rune, we don't want to blast the caster.
840     * In that case, we have to see - if dir is specified,
841     * turn this into direction 8. If dir is not specified (all
842     * direction) skip - otherwise, one line would do more damage
843     * becase 0 direction will go through 9 directions - necessary
844     * for the rune code.
845     */
846     if (caster->type != RUNE && d == 0)
847     {
848     if (dir != 0)
849     d = 8;
850     else
851 root 1.6 continue;
852 root 1.9 }
853 elmex 1.1
854 root 1.9 x = op->x + freearr_x[d];
855     y = op->y + freearr_y[d];
856 root 1.6
857 root 1.9 if (get_map_flags (op->map, &m, x, y, &sx, &sy) & P_OUT_OF_MAP)
858     continue;
859 root 1.6
860 root 1.9 if ((movetype & GET_MAP_MOVE_BLOCK (m, sx, sy)) == movetype)
861     continue;
862 root 1.6
863 root 1.9 success = 1;
864     tmp = arch_to_object (spell->other_arch);
865 root 1.19 tmp->set_owner (op);
866 root 1.9 set_spell_skill (op, caster, spell, tmp);
867     tmp->level = caster_level (caster, spell);
868     tmp->attacktype = spell->attacktype;
869    
870     /* holy word stuff */
871     if ((tmp->attacktype & AT_HOLYWORD) || (tmp->attacktype & AT_GODPOWER))
872 root 1.10 if (!tailor_god_spell (tmp, op))
873     return 0;
874 root 1.6
875 root 1.9 if (dir)
876     tmp->stats.sp = dir;
877     else
878     tmp->stats.sp = i;
879    
880     tmp->range = spell->range + SP_level_range_adjust (caster, spell);
881    
882     /* If casting it in all directions, it doesn't go as far */
883     if (dir == 0)
884     {
885     tmp->range /= 4;
886     if (tmp->range < 2 && spell->range >= 2)
887     tmp->range = 2;
888     }
889 root 1.10
890 root 1.9 tmp->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
891     tmp->duration = spell->duration + SP_level_duration_adjust (caster, spell);
892    
893     /* Special bonus for fear attacks */
894     if (tmp->attacktype & AT_FEAR)
895     {
896     if (caster->type == PLAYER)
897     tmp->duration += fear_bonus[caster->stats.Cha];
898     else
899     tmp->duration += caster->level / 3;
900     }
901 root 1.10
902 root 1.9 if (tmp->attacktype & (AT_HOLYWORD | AT_TURN_UNDEAD))
903     {
904     if (caster->type == PLAYER)
905     tmp->duration += turn_bonus[caster->stats.Wis] / 5;
906     else
907     tmp->duration += caster->level / 3;
908 root 1.6 }
909    
910 root 1.9 if (!(tmp->move_type & MOVE_FLY_LOW))
911 root 1.38 LOG (llevDebug, "cast_cone(): arch %s doesn't have flying 1\n", &spell->other_arch->archname);
912 root 1.9
913     if (!tmp->move_on && tmp->stats.dam)
914 root 1.38 LOG (llevDebug, "cast_cone(): arch %s doesn't have move_on set\n", &spell->other_arch->archname);
915 root 1.10
916 root 1.25 m->insert (tmp, sx, sy, op);
917 root 1.9
918     /* This is used for tracking spells so that one effect doesn't hit
919     * a single space too many times.
920     */
921     tmp->stats.maxhp = tmp->count;
922 root 1.6
923 root 1.9 if (tmp->other_arch)
924     cone_drop (tmp);
925 elmex 1.1 }
926 root 1.10
927 root 1.9 return success;
928 elmex 1.1 }
929    
930     /****************************************************************************
931     *
932     * BOMB related code
933     *
934     ****************************************************************************/
935    
936     /* This handles an exploding bomb.
937     * op is the original bomb object.
938     */
939 root 1.9 void
940     animate_bomb (object *op)
941     {
942     int i;
943     object *env, *tmp;
944 elmex 1.1
945 root 1.9 if (op->state != NUM_ANIMATIONS (op) - 1)
946     return;
947 elmex 1.1
948 root 1.9 env = object_get_env_recursive (op);
949 elmex 1.1
950 root 1.9 if (op->env)
951     {
952     if (env->map == NULL)
953     return;
954 elmex 1.1
955 root 1.9 if (env->type == PLAYER)
956     esrv_del_item (env->contr, op->count);
957 elmex 1.1
958 root 1.25 if (!(op = op->insert_at (env, op)))
959 root 1.9 return;
960 elmex 1.1 }
961    
962 root 1.9 // elmex Tue Aug 15 17:46:51 CEST 2006: Prevent bomb from exploding
963     // on a safe map. I don't like this special casing, but it seems to be neccessary
964     // as bombs can be carried.
965     if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE)
966     {
967 root 1.17 op->destroy ();
968 root 1.9 return;
969     }
970 elmex 1.3
971 root 1.9 /* This copies a lot of the code from the fire bullet,
972     * but using the cast_bullet isn't really feasible,
973     * so just set up the appropriate values.
974     */
975 root 1.25 if (archetype *at = archetype::find (SPLINT))
976 root 1.9 {
977     for (i = 1; i < 9; i++)
978     {
979     if (out_of_map (op->map, op->x + freearr_x[i], op->y + freearr_x[i]))
980     continue;
981 root 1.25
982 root 1.9 tmp = arch_to_object (at);
983     tmp->direction = i;
984     tmp->range = op->range;
985     tmp->stats.dam = op->stats.dam;
986     tmp->duration = op->duration;
987     tmp->attacktype = op->attacktype;
988 root 1.19 tmp->set_owner (op);
989 root 1.9 if (op->skill && op->skill != tmp->skill)
990 root 1.25 tmp->skill = op->skill;
991    
992 root 1.9 if (QUERY_FLAG (tmp, FLAG_IS_TURNABLE))
993     SET_ANIMATION (tmp, i);
994 root 1.25
995     op->map->insert (tmp, op->x + freearr_x[i], op->y + freearr_x[i], op);
996 root 1.9 move_bullet (tmp);
997 root 1.6 }
998 elmex 1.1 }
999    
1000 root 1.9 explode_bullet (op);
1001 elmex 1.1 }
1002    
1003 root 1.9 int
1004     create_bomb (object *op, object *caster, int dir, object *spell)
1005     {
1006 elmex 1.1
1007 root 1.9 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     if ((mflags & P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK (m, dx, dy) & MOVE_WALK))
1014     {
1015     new_draw_info (NDI_UNIQUE, 0, op, "There is something in the way.");
1016     return 0;
1017 elmex 1.1 }
1018 root 1.9 tmp = arch_to_object (spell->other_arch);
1019 elmex 1.1
1020 root 1.9 /* level dependencies for bomb */
1021     tmp->range = spell->range + SP_level_range_adjust (caster, spell);
1022     tmp->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1023     tmp->duration = spell->duration + SP_level_duration_adjust (caster, spell);
1024     tmp->attacktype = spell->attacktype;
1025    
1026 root 1.19 tmp->set_owner (op);
1027 root 1.9 set_spell_skill (op, caster, spell, tmp);
1028 root 1.25
1029     m->insert (tmp, dx, dy, op);
1030 root 1.9 return 1;
1031 elmex 1.1 }
1032    
1033     /****************************************************************************
1034     *
1035     * smite related spell code.
1036     *
1037     ****************************************************************************/
1038    
1039     /* get_pointed_target() - this is used by finger of death
1040     * and the 'smite' spells. Returns the pointer to the first
1041     * monster in the direction which is pointed to by op. b.t.
1042     * op is the caster - really only used for the source location.
1043     * dir is the direction to look in.
1044     * range is how far out to look.
1045     * type is the type of spell - either SPELL_MANA or SPELL_GRACE.
1046     * this info is used for blocked magic/unholy spaces.
1047     */
1048 root 1.9 object *
1049     get_pointed_target (object *op, int dir, int range, int type)
1050     {
1051     object *target;
1052     sint16 x, y;
1053     int dist, mflags;
1054 root 1.15 maptile *mp;
1055 root 1.9
1056     if (dir == 0)
1057     return NULL;
1058    
1059     for (dist = 1; dist < range; dist++)
1060     {
1061     x = op->x + freearr_x[dir] * dist;
1062     y = op->y + freearr_y[dir] * dist;
1063     mp = op->map;
1064     mflags = get_map_flags (op->map, &mp, x, y, &x, &y);
1065    
1066     if (mflags & P_OUT_OF_MAP)
1067     return NULL;
1068     if ((type & SPELL_MANA) && (mflags & P_NO_MAGIC))
1069     return NULL;
1070     if ((type & SPELL_GRACE) && (mflags & P_NO_CLERIC))
1071     return NULL;
1072     if (GET_MAP_MOVE_BLOCK (mp, x, y) & MOVE_FLY_LOW)
1073     return NULL;
1074    
1075     if (mflags & P_IS_ALIVE)
1076 root 1.41 for (target = GET_MAP_OB (mp, x, y); target; target = target->above)
1077     if (QUERY_FLAG (target, FLAG_MONSTER))
1078     return target;
1079 elmex 1.1 }
1080 root 1.41
1081 root 1.9 return NULL;
1082 elmex 1.1 }
1083    
1084     /* cast_smite_arch() - the priest points to a creature and causes
1085     * a 'godly curse' to decend.
1086     * usual params -
1087     * op = player
1088     * caster = object casting the spell.
1089     * dir = direction being cast
1090     * spell = spell object
1091     */
1092 root 1.9 int
1093     cast_smite_spell (object *op, object *caster, int dir, object *spell)
1094     {
1095     object *effect, *target;
1096     object *god = find_god (determine_god (op));
1097     int range;
1098    
1099     range = spell->range + SP_level_range_adjust (caster, spell);
1100     target = get_pointed_target (op, dir, 50, spell->stats.grace ? SPELL_GRACE : SPELL_MANA);
1101    
1102     /* Bunch of conditions for casting this spell. Note that only
1103     * require a god if this is a cleric spell (requires grace).
1104     * This makes this spell much more general purpose - it can be used
1105     * by wizards also, which is good, because I think this is a very
1106     * interesting spell.
1107     * if it is a cleric spell, you need a god, and the creature
1108     * can't be friendly to your god.
1109     */
1110    
1111     if (!target || QUERY_FLAG (target, FLAG_REFL_SPELL)
1112     || (!god && spell->stats.grace)
1113     || (target->title && god && !strcmp (target->title, god->name)) || (target->race && god && strstr (target->race, god->race)))
1114     {
1115     new_draw_info (NDI_UNIQUE, 0, op, "Your request is unheeded.");
1116     return 0;
1117     }
1118    
1119     if (spell->other_arch)
1120     effect = arch_to_object (spell->other_arch);
1121     else
1122     return 0;
1123    
1124     /* tailor the effect by priest level and worshipped God */
1125     effect->level = caster_level (caster, spell);
1126     effect->attacktype = spell->attacktype;
1127     if (effect->attacktype & (AT_HOLYWORD | AT_GODPOWER))
1128     {
1129     if (tailor_god_spell (effect, op))
1130     new_draw_info_format (NDI_UNIQUE, 0, op, "%s answers your call!", determine_god (op));
1131     else
1132     {
1133     new_draw_info (NDI_UNIQUE, 0, op, "Your request is ignored.");
1134     return 0;
1135     }
1136 elmex 1.1 }
1137    
1138 root 1.9 /* size of the area of destruction */
1139     effect->range = spell->range + SP_level_range_adjust (caster, spell);
1140     effect->duration = spell->duration + SP_level_range_adjust (caster, spell);
1141    
1142     if (effect->attacktype & AT_DEATH)
1143     {
1144     effect->level = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1145 elmex 1.1
1146 root 1.9 /* casting death spells at undead isn't a good thing */
1147 root 1.20 if (QUERY_FLAG (target, FLAG_UNDEAD))
1148 root 1.9 {
1149     if (random_roll (0, 2, op, PREFER_LOW))
1150     {
1151     new_draw_info (NDI_UNIQUE, 0, op, "Idiot! Your spell boomerangs!");
1152     effect->x = op->x;
1153     effect->y = op->y;
1154     }
1155     else
1156     {
1157     new_draw_info_format (NDI_UNIQUE, 0, op, "The %s looks stronger!", query_name (target));
1158     target->stats.hp = target->stats.maxhp * 2;
1159 root 1.17 effect->destroy ();
1160 root 1.9 return 0;
1161 root 1.6 }
1162     }
1163 elmex 1.1 }
1164 root 1.9 else
1165     {
1166     /* how much woe to inflict :) */
1167     effect->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1168     }
1169    
1170 root 1.19 effect->set_owner (op);
1171 root 1.9 set_spell_skill (op, caster, spell, effect);
1172    
1173     /* ok, tell it where to be, and insert! */
1174 root 1.25 effect->insert_at (target, op);
1175 elmex 1.1
1176 root 1.9 return 1;
1177 elmex 1.1 }
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 root 1.9 int
1259     make_object_glow (object *op, int radius, int time)
1260     {
1261     /* some things are unaffected... */
1262     if (op->path_denied & PATH_LIGHT)
1263     return 0;
1264    
1265 root 1.43 object *tmp = get_archetype (FORCE_NAME);
1266 root 1.9 tmp->speed = 0.01;
1267     tmp->stats.food = time;
1268     SET_FLAG (tmp, FLAG_IS_USED_UP);
1269     tmp->glow_radius = radius;
1270     if (tmp->glow_radius > MAX_LIGHT_RADII)
1271     tmp->glow_radius = MAX_LIGHT_RADII;
1272    
1273     tmp = insert_ob_in_ob (tmp, op);
1274 root 1.43
1275 root 1.9 if (tmp->glow_radius > op->glow_radius)
1276     op->glow_radius = tmp->glow_radius;
1277    
1278     return 1;
1279     }
1280    
1281     int
1282     cast_destruction (object *op, object *caster, object *spell_ob)
1283     {
1284     int i, j, range, mflags, friendly = 0, dam, dur;
1285     sint16 sx, sy;
1286 root 1.15 maptile *m;
1287 root 1.9 object *tmp;
1288     const char *skill;
1289    
1290     range = spell_ob->range + SP_level_range_adjust (caster, spell_ob);
1291     dam = spell_ob->stats.dam + SP_level_dam_adjust (caster, spell_ob);
1292     dur = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob);
1293     if (QUERY_FLAG (op, FLAG_FRIENDLY) || op->type == PLAYER)
1294     friendly = 1;
1295    
1296     /* destruction doesn't use another spell object, so we need
1297     * update op's skill pointer so that exp is properly awarded.
1298     * We do some shortcuts here - since this is just temporary
1299     * and we'll reset the values back, we don't need to go through
1300     * the full share string/free_string route.
1301     */
1302     skill = op->skill;
1303     if (caster == op)
1304     op->skill = spell_ob->skill;
1305     else if (caster->skill)
1306     op->skill = caster->skill;
1307     else
1308     op->skill = NULL;
1309 elmex 1.1
1310 root 1.35 op->change_skill (find_skill_by_name (op, op->skill));
1311 elmex 1.1
1312 root 1.9 for (i = -range; i < range; i++)
1313     {
1314     for (j = -range; j < range; j++)
1315     {
1316     m = op->map;
1317     sx = op->x + i;
1318     sy = op->y + j;
1319 root 1.25
1320 root 1.9 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
1321     if (mflags & P_OUT_OF_MAP)
1322     continue;
1323 root 1.25
1324 root 1.9 if (mflags & P_IS_ALIVE)
1325     {
1326 root 1.21 for (tmp = GET_MAP_OB (m, sx, sy); tmp; tmp = tmp->above)
1327 root 1.25 if (QUERY_FLAG (tmp, FLAG_ALIVE) || tmp->type == PLAYER)
1328     break;
1329    
1330 root 1.9 if (tmp)
1331     {
1332     if (tmp->head)
1333     tmp = tmp->head;
1334    
1335     if ((friendly && !QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->type != PLAYER) ||
1336     (!friendly && (QUERY_FLAG (tmp, FLAG_FRIENDLY) || tmp->type == PLAYER)))
1337     {
1338     if (spell_ob->subtype == SP_DESTRUCTION)
1339     {
1340     hit_player (tmp, dam, op, spell_ob->attacktype, 0);
1341     if (spell_ob->other_arch)
1342 root 1.25 m->insert (arch_to_object (spell_ob->other_arch), sx, sy, op);
1343 root 1.6 }
1344 root 1.9 else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist[ATNR_MAGIC] != 100)
1345     {
1346     if (make_object_glow (tmp, 1, dur) && spell_ob->other_arch)
1347 root 1.25 m->insert (arch_to_object (spell_ob->other_arch), sx, sy, op);
1348 root 1.6 }
1349     }
1350     }
1351     }
1352     }
1353 elmex 1.1 }
1354 root 1.25
1355 root 1.9 op->skill = skill;
1356     return 1;
1357 elmex 1.1 }
1358    
1359     /***************************************************************************
1360     *
1361     * CURSE
1362     *
1363     ***************************************************************************/
1364    
1365 root 1.9 int
1366     cast_curse (object *op, object *caster, object *spell_ob, int dir)
1367     {
1368     object *god = find_god (determine_god (op));
1369     object *tmp, *force;
1370    
1371     tmp = get_pointed_target (op, (dir == 0) ? op->direction : dir, spell_ob->range, SPELL_GRACE);
1372     if (!tmp)
1373     {
1374     new_draw_info (NDI_UNIQUE, 0, op, "There is no one in that direction to curse.");
1375     return 0;
1376 elmex 1.1 }
1377    
1378 root 1.47 tmp = tmp->head_ ();
1379    
1380 root 1.9 /* If we've already got a force of this type, don't add a new one. */
1381 root 1.47 for (force = tmp->inv; force; force = force->below)
1382 root 1.9 {
1383     if (force->type == FORCE && force->subtype == FORCE_CHANGE_ABILITY)
1384     {
1385     if (force->name == spell_ob->name)
1386     {
1387     break;
1388 root 1.6 }
1389 root 1.9 else if (spell_ob->race && spell_ob->race == force->name)
1390     {
1391     new_draw_info_format (NDI_UNIQUE, 0, op, "You can not cast %s while %s is in effect", &spell_ob->name, &force->name_pl);
1392     return 0;
1393 root 1.6 }
1394     }
1395 elmex 1.1 }
1396    
1397 root 1.47 if (!force)
1398 root 1.9 {
1399     force = get_archetype (FORCE_NAME);
1400     force->subtype = FORCE_CHANGE_ABILITY;
1401 root 1.47
1402 root 1.9 if (spell_ob->race)
1403     force->name = spell_ob->race;
1404     else
1405     force->name = spell_ob->name;
1406 root 1.7
1407 root 1.9 force->name_pl = spell_ob->name;
1408 elmex 1.1
1409 root 1.9 }
1410     else
1411     {
1412     int duration;
1413    
1414     duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1415     if (duration > force->duration)
1416     {
1417     force->duration = duration;
1418     new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
1419     }
1420     else
1421 root 1.47 new_draw_info (NDI_UNIQUE, 0, op, "Recasting the spell had no effect.");
1422    
1423 root 1.9 return 1;
1424     }
1425 root 1.47
1426 root 1.9 force->duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1427 root 1.33 force->speed = 1.f;
1428     force->speed_left = -1.f;
1429 root 1.9 SET_FLAG (force, FLAG_APPLIED);
1430 elmex 1.1
1431 root 1.9 if (god)
1432     {
1433     if (spell_ob->last_grace)
1434     force->path_repelled = god->path_repelled;
1435     if (spell_ob->last_grace)
1436     force->path_denied = god->path_denied;
1437     new_draw_info_format (NDI_UNIQUE, 0, tmp, "You are a victim of %s's curse!", &god->name);
1438     }
1439     else
1440     new_draw_info (NDI_UNIQUE, 0, op, "Your curse seems empty.");
1441    
1442    
1443     if (tmp != op && op->type == PLAYER)
1444     new_draw_info_format (NDI_UNIQUE, 0, op, "You curse %s!", &tmp->name);
1445    
1446     force->stats.ac = spell_ob->stats.ac;
1447     force->stats.wc = spell_ob->stats.wc;
1448    
1449     change_abil (tmp, force); /* Mostly to display any messages */
1450     insert_ob_in_ob (force, tmp);
1451 root 1.22 tmp->update_stats ();
1452 root 1.9 return 1;
1453 elmex 1.1
1454     }
1455    
1456     /**********************************************************************
1457     * mood change
1458     * Arguably, this may or may not be an attack spell. But since it
1459     * effects monsters, it seems best to put it into this file
1460     ***********************************************************************/
1461    
1462     /* This covers the various spells that change the moods of monsters -
1463     * makes them angry, peacful, friendly, etc.
1464     */
1465 root 1.9 int
1466     mood_change (object *op, object *caster, object *spell)
1467     {
1468     object *tmp, *god, *head;
1469     int done_one, range, mflags, level, at, best_at;
1470     sint16 x, y, nx, ny;
1471 root 1.15 maptile *m;
1472 root 1.9 const char *race;
1473    
1474     /* We precompute some values here so that we don't have to keep
1475     * doing it over and over again.
1476     */
1477     god = find_god (determine_god (op));
1478     level = caster_level (caster, spell);
1479     range = spell->range + SP_level_range_adjust (caster, spell);
1480    
1481     /* On the bright side, no monster should ever have a race of GOD_...
1482     * so even if the player doesn't worship a god, if race=GOD_.., it
1483     * won't ever match anything.
1484     */
1485     if (!spell->race)
1486     race = NULL;
1487     else if (god && !strcmp (spell->race, "GOD_SLAYING"))
1488     race = god->slaying;
1489     else if (god && !strcmp (spell->race, "GOD_FRIEND"))
1490     race = god->race;
1491     else
1492     race = spell->race;
1493 elmex 1.1
1494 root 1.9 for (x = op->x - range; x <= op->x + range; x++)
1495     for (y = op->y - range; y <= op->y + range; y++)
1496     {
1497     done_one = 0;
1498     m = op->map;
1499     nx = x;
1500     ny = y;
1501     mflags = get_map_flags (m, &m, x, y, &nx, &ny);
1502     if (mflags & P_OUT_OF_MAP)
1503     continue;
1504    
1505     /* If there is nothing living on this space, no need to go further */
1506     if (!(mflags & P_IS_ALIVE))
1507     continue;
1508 elmex 1.1
1509 root 1.29 // players can only affect spaces that they can actually see
1510     if (caster && caster->contr
1511     && caster->contr->visibility_at (m, nx, ny) < 70)
1512     continue;
1513    
1514     for (tmp = GET_MAP_TOP (m, nx, ny); tmp; tmp = tmp->below)
1515 root 1.9 if (QUERY_FLAG (tmp, FLAG_MONSTER))
1516     break;
1517 root 1.6
1518 root 1.9 /* There can be living objects that are not monsters */
1519     if (!tmp || tmp->type == PLAYER)
1520     continue;
1521    
1522     /* Only the head has meaningful data, so resolve to that */
1523     if (tmp->head)
1524     head = tmp->head;
1525     else
1526     head = tmp;
1527 root 1.6
1528 root 1.9 /* Make sure the race is OK. Likewise, only effect undead if spell specifically allows it */
1529     if (race && head->race && !strstr (race, head->race))
1530     continue;
1531 root 1.29
1532 root 1.9 if (QUERY_FLAG (head, FLAG_UNDEAD) && !QUERY_FLAG (spell, FLAG_UNDEAD))
1533     continue;
1534    
1535     /* Now do a bunch of stuff related to saving throws */
1536     best_at = -1;
1537     if (spell->attacktype)
1538     {
1539     for (at = 0; at < NROFATTACKS; at++)
1540     if (spell->attacktype & (1 << at))
1541     if (best_at == -1 || head->resist[at] > head->resist[best_at])
1542     best_at = at;
1543 elmex 1.1
1544 root 1.9 if (best_at == -1)
1545     at = 0;
1546     else
1547     {
1548     if (head->resist[best_at] == 100)
1549     continue;
1550     else
1551     at = head->resist[best_at] / 5;
1552     }
1553     at -= level / 5;
1554     if (did_make_save (head, head->level, at))
1555     continue;
1556     }
1557     else /* spell->attacktype */
1558 root 1.36 {
1559     /*
1560     Spell has no attacktype (charm & such), so we'll have a specific saving:
1561     * if spell level < monster level, no go
1562     * else, chance of effect = 20 + min( 50, 2 * ( spell level - monster level ) )
1563 root 1.9
1564 root 1.36 The chance will then be in the range [20-70] percent, not too bad.
1565 root 1.9
1566 root 1.36 This is required to fix the 'charm monster' abuse, where a player level 1 can
1567     charm a level 125 monster...
1568 root 1.9
1569 root 1.36 Ryo, august 14th
1570     */
1571 root 1.9 if (head->level > level)
1572     continue;
1573 root 1.36
1574 root 1.9 if (random_roll (0, 100, caster, PREFER_LOW) >= (20 + MIN (50, 2 * (level - head->level))))
1575     /* Failed, no effect */
1576     continue;
1577     }
1578    
1579 root 1.29 /* Done with saving throw. Now start affecting the monster */
1580 root 1.9
1581     /* aggravation */
1582     if (QUERY_FLAG (spell, FLAG_MONSTER))
1583     {
1584     CLEAR_FLAG (head, FLAG_SLEEP);
1585 root 1.32 remove_friendly_object (head);
1586 root 1.9 done_one = 1;
1587     head->enemy = op;
1588     }
1589    
1590     /* calm monsters */
1591     if (QUERY_FLAG (spell, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (head, FLAG_UNAGGRESSIVE))
1592     {
1593     SET_FLAG (head, FLAG_UNAGGRESSIVE);
1594     head->enemy = NULL;
1595     done_one = 1;
1596     }
1597    
1598     /* berserk monsters */
1599     if (QUERY_FLAG (spell, FLAG_BERSERK) && !QUERY_FLAG (head, FLAG_BERSERK))
1600     {
1601     SET_FLAG (head, FLAG_BERSERK);
1602     done_one = 1;
1603     }
1604 root 1.27
1605 root 1.9 /* charm */
1606     if (QUERY_FLAG (spell, FLAG_NO_ATTACK) && !QUERY_FLAG (head, FLAG_FRIENDLY))
1607     {
1608     /* Prevent uncontolled outbreaks of self replicating monsters.
1609     Typical use case is charm, go somwhere, use aggravation to make hostile.
1610     This could lead to fun stuff like mice outbreak in bigworld and server crawl. */
1611     CLEAR_FLAG (head, FLAG_GENERATOR);
1612 root 1.19 head->set_owner (op);
1613 root 1.9 set_spell_skill (op, caster, spell, head);
1614     add_friendly_object (head);
1615     head->attack_movement = PETMOVE;
1616     done_one = 1;
1617     change_exp (op, head->stats.exp / 2, head->skill, SK_EXP_ADD_SKILL);
1618     head->stats.exp = 0;
1619     }
1620    
1621     /* If a monster was effected, put an effect in */
1622     if (done_one && spell->other_arch)
1623 root 1.25 m->insert (arch_to_object (spell->other_arch), nx, ny, op);
1624 root 1.9 } /* for y */
1625 elmex 1.1
1626 root 1.9 return 1;
1627 elmex 1.1 }
1628    
1629    
1630     /* Move_ball_spell: This handles ball type spells that just sort of wander
1631     * about. was called move_ball_lightning, but since more than the ball
1632     * lightning spell used it, that seemed misnamed.
1633     * op is the spell effect.
1634     * note that duration is handled by process_object() in time.c
1635     */
1636    
1637 root 1.9 void
1638     move_ball_spell (object *op)
1639     {
1640     int i, j, dam_save, dir, mflags;
1641     sint16 nx, ny, hx, hy;
1642     object *owner;
1643 root 1.15 maptile *m;
1644 root 1.9
1645 root 1.19 owner = op->owner;
1646 root 1.9
1647     /* the following logic makes sure that the ball doesn't move into a wall,
1648     * and makes sure that it will move along a wall to try and get at it's
1649     * victim. The block immediately below more or less chooses a random
1650     * offset to move the ball, eg, keep it mostly on course, with some
1651     * deviations.
1652     */
1653    
1654     dir = 0;
1655     if (!(rndm (0, 3)))
1656     j = rndm (0, 1);
1657     else
1658     j = 0;
1659    
1660     for (i = 1; i < 9; i++)
1661     {
1662     /* i bit 0: alters sign of offset
1663     * other bits (i / 2): absolute value of offset
1664     */
1665    
1666     int offset = ((i ^ j) & 1) ? (i / 2) : -(i / 2);
1667     int tmpdir = absdir (op->direction + offset);
1668    
1669     nx = op->x + freearr_x[tmpdir];
1670     ny = op->y + freearr_y[tmpdir];
1671     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))))
1672     {
1673     dir = tmpdir;
1674     break;
1675 root 1.6 }
1676 elmex 1.1 }
1677 root 1.9 if (dir == 0)
1678     {
1679     nx = op->x;
1680     ny = op->y;
1681     m = op->map;
1682     }
1683    
1684 root 1.25 m->insert (op, nx, ny, op);
1685 root 1.9
1686     dam_save = op->stats.dam; /* save the original dam: we do halfdam on
1687     surrounding squares */
1688    
1689     /* loop over current square and neighbors to hit.
1690     * if this has an other_arch field, we insert that in
1691     * the surround spaces.
1692     */
1693     for (j = 0; j < 9; j++)
1694     {
1695     hx = nx + freearr_x[j];
1696     hy = ny + freearr_y[j];
1697 elmex 1.1
1698 root 1.9 m = op->map;
1699     mflags = get_map_flags (m, &m, hx, hy, &hx, &hy);
1700 elmex 1.1
1701 root 1.9 if (mflags & P_OUT_OF_MAP)
1702     continue;
1703 elmex 1.1
1704 root 1.9 /* first, don't ever, ever hit the owner. Don't hit out
1705     * of the map either.
1706     */
1707 elmex 1.1
1708 root 1.9 if ((mflags & P_IS_ALIVE) && (!owner || owner->x != hx || owner->y != hy || !on_same_map (owner, op)))
1709     {
1710     if (j)
1711     op->stats.dam = dam_save / 2;
1712     hit_map (op, j, op->attacktype, 1);
1713 elmex 1.1
1714 root 1.6 }
1715 elmex 1.1
1716 root 1.9 /* insert the other arch */
1717     if (op->other_arch && !(OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy))))
1718 root 1.25 m->insert (arch_to_object (op->other_arch), hx, hy, op);
1719 elmex 1.1 }
1720    
1721 root 1.9 /* restore to the center location and damage */
1722     op->stats.dam = dam_save;
1723 elmex 1.1
1724 root 1.19 i = spell_find_dir (op->map, op->x, op->y, op->owner);
1725 elmex 1.1
1726 root 1.9 if (i >= 0)
1727     { /* we have a preferred direction! */
1728     /* pick another direction if the preferred dir is blocked. */
1729     if (get_map_flags (op->map, &m, nx + freearr_x[i], ny + freearr_y[i], &hx, &hy) & P_OUT_OF_MAP ||
1730     OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy)))
1731 root 1.25 i = absdir (i + rndm (0, 2) - 1); /* -1, 0, +1 */
1732    
1733 root 1.9 op->direction = i;
1734 elmex 1.1 }
1735     }
1736    
1737    
1738     /* move_swarm_spell: peterm
1739     * This is an implementation of the swarm spell. It was written for
1740     * meteor swarm, but it could be used for any swarm. A swarm spell
1741     * is a special type of object that casts swarms of other types
1742     * of spells. Which spell it casts is flexible. It fires the spells
1743     * from a set of squares surrounding the caster, in a given direction.
1744     */
1745    
1746 root 1.9 void
1747     move_swarm_spell (object *op)
1748 elmex 1.1 {
1749 pippijn 1.8 #if 0
1750 root 1.9 static int cardinal_adjust[9] = { -3, -2, -1, 0, 0, 0, 1, 2, 3 };
1751     static int diagonal_adjust[10] = { -3, -2, -2, -1, 0, 0, 1, 2, 2, 3 };
1752     sint16 target_x, target_y, origin_x, origin_y;
1753     int adjustdir;
1754 root 1.15 maptile *m;
1755 pippijn 1.8 #endif
1756 root 1.9 int basedir;
1757     object *owner;
1758 elmex 1.1
1759 root 1.19 owner = op->owner;
1760 root 1.9 if (op->duration == 0 || owner == NULL)
1761     {
1762 root 1.17 op->destroy ();
1763 root 1.9 return;
1764 elmex 1.1 }
1765 root 1.17
1766 root 1.9 op->duration--;
1767 elmex 1.1
1768 root 1.9 basedir = op->direction;
1769     if (basedir == 0)
1770     {
1771     /* spray in all directions! 8) */
1772     basedir = rndm (1, 8);
1773 elmex 1.1 }
1774    
1775     #if 0
1776 root 1.9 // this is bogus: it causes wrong places to be checked below
1777     // (a wall 2 cells away will block the effect...) and
1778     // doesn't work for SP_BULLET anyhow, so again tests the wrong
1779     // space.
1780 root 1.31 // should be fixed later, but correctness before features...
1781 root 1.9 // (schmorp)
1782    
1783     /* new offset calculation to make swarm element distribution
1784     * more uniform
1785     */
1786     if (op->duration)
1787     {
1788     if (basedir & 1)
1789     {
1790     adjustdir = cardinal_adjust[rndm (0, 8)];
1791     }
1792     else
1793     {
1794     adjustdir = diagonal_adjust[rndm (0, 9)];
1795     }
1796     }
1797     else
1798     {
1799     adjustdir = 0; /* fire the last one from forward. */
1800     }
1801    
1802     target_x = op->x + freearr_x[absdir (basedir + adjustdir)];
1803     target_y = op->y + freearr_y[absdir (basedir + adjustdir)];
1804    
1805     /* back up one space so we can hit point-blank targets, but this
1806     * necessitates extra out_of_map check below
1807     */
1808     origin_x = target_x - freearr_x[basedir];
1809     origin_y = target_y - freearr_y[basedir];
1810    
1811    
1812     /* spell pointer is set up for the spell this casts. Since this
1813     * should just be a pointer to the spell in some inventory,
1814     * it is unlikely to disappear by the time we need it. However,
1815     * do some sanity checking anyways.
1816     */
1817    
1818     if (op->spell && op->spell->type == SPELL &&
1819     !(get_map_flags (op->map, &m, target_x, target_y, &target_x, &target_y) & P_OUT_OF_MAP) &&
1820     !(OB_TYPE_MOVE_BLOCK (op->spell, GET_MAP_MOVE_BLOCK (m, target_x, target_y))))
1821     {
1822    
1823     /* Bullet spells have a bunch more customization that needs to be done */
1824     if (op->spell->subtype == SP_BULLET)
1825     fire_bullet (owner, op, basedir, op->spell);
1826     else if (op->spell->subtype == SP_MAGIC_MISSILE)
1827     fire_arch_from_position (owner, op, origin_x, origin_y, basedir, op->spell);
1828 elmex 1.1 }
1829     #endif
1830    
1831 root 1.9 /* spell pointer is set up for the spell this casts. Since this
1832     * should just be a pointer to the spell in some inventory,
1833     * it is unlikely to disappear by the time we need it. However,
1834     * do some sanity checking anyways.
1835     */
1836    
1837     if (op->spell && op->spell->type == SPELL)
1838     {
1839     /* Bullet spells have a bunch more customization that needs to be done */
1840     if (op->spell->subtype == SP_BULLET)
1841     fire_bullet (owner, op, basedir, op->spell);
1842     else if (op->spell->subtype == SP_MAGIC_MISSILE)
1843     fire_arch_from_position (owner, op, op->x, op->y, basedir, op->spell);
1844     }
1845 elmex 1.1 }
1846    
1847    
1848    
1849    
1850     /* fire_swarm:
1851     * The following routine creates a swarm of objects. It actually
1852     * sets up a specific swarm object, which then fires off all
1853     * the parts of the swarm.
1854     *
1855     * op: the owner
1856     * caster: the caster (owner, wand, rod, scroll)
1857     * dir: the direction everything will be fired in
1858     * spell - the spell that is this spell.
1859     * n: the number to be fired.
1860     */
1861    
1862 root 1.9 int
1863     fire_swarm (object *op, object *caster, object *spell, int dir)
1864 elmex 1.1 {
1865 root 1.9 object *tmp;
1866     int i;
1867 elmex 1.1
1868 root 1.9 if (!spell->other_arch)
1869     return 0;
1870 elmex 1.1
1871 root 1.9 tmp = get_archetype (SWARM_SPELL);
1872 root 1.19 tmp->set_owner (op); /* needed so that if swarm elements kill, caster gets xp. */
1873 root 1.9 set_spell_skill (op, caster, spell, tmp);
1874 elmex 1.1
1875 root 1.9 tmp->level = caster_level (caster, spell); /*needed later, to get level dep. right. */
1876     tmp->spell = arch_to_object (spell->other_arch);
1877 elmex 1.1
1878 root 1.9 tmp->attacktype = tmp->spell->attacktype;
1879 elmex 1.1
1880 root 1.9 if (tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER)
1881 root 1.25 if (!tailor_god_spell (tmp, op))
1882     return 1;
1883    
1884 root 1.9 tmp->duration = SP_level_duration_adjust (caster, spell);
1885     for (i = 0; i < spell->duration; i++)
1886     tmp->duration += die_roll (1, 3, op, PREFER_HIGH);
1887    
1888     tmp->direction = dir;
1889     tmp->invisible = 1;
1890 root 1.25
1891     tmp->insert_at (op, op);
1892 root 1.9 return 1;
1893 elmex 1.1 }
1894    
1895    
1896     /* See the spells documentation file for why this is its own
1897     * function.
1898     */
1899 root 1.9 int
1900     cast_light (object *op, object *caster, object *spell, int dir)
1901     {
1902     object *target = NULL, *tmp = NULL;
1903     sint16 x, y;
1904     int dam, mflags;
1905 root 1.15 maptile *m;
1906 elmex 1.1
1907 root 1.9 dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1908 elmex 1.1
1909 root 1.9 if (!dir)
1910     {
1911     new_draw_info (NDI_UNIQUE, 0, op, "In what direction?");
1912     return 0;
1913 elmex 1.1 }
1914    
1915 root 1.9 x = op->x + freearr_x[dir];
1916     y = op->y + freearr_y[dir];
1917     m = op->map;
1918 elmex 1.1
1919 root 1.9 mflags = get_map_flags (m, &m, x, y, &x, &y);
1920 elmex 1.1
1921 root 1.9 if (mflags & P_OUT_OF_MAP)
1922     {
1923     new_draw_info (NDI_UNIQUE, 0, op, "Nothing is there.");
1924     return 0;
1925 elmex 1.1 }
1926    
1927 root 1.9 if (mflags & P_IS_ALIVE && spell->attacktype)
1928     {
1929 root 1.21 for (target = GET_MAP_OB (m, x, y); target; target = target->above)
1930 root 1.9 if (QUERY_FLAG (target, FLAG_MONSTER))
1931     {
1932     /* oky doky. got a target monster. Lets make a blinding attack */
1933     if (target->head)
1934     target = target->head;
1935     (void) hit_player (target, dam, op, spell->attacktype, 1);
1936     return 1; /* one success only! */
1937     }
1938 elmex 1.1 }
1939    
1940 root 1.9 /* no live target, perhaps a wall is in the way? */
1941     if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y)))
1942     {
1943     new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way.");
1944     return 0;
1945 elmex 1.1 }
1946    
1947 root 1.9 /* ok, looks groovy to just insert a new light on the map */
1948     tmp = arch_to_object (spell->other_arch);
1949     if (!tmp)
1950     {
1951     LOG (llevError, "Error: spell arch for cast_light() missing.\n");
1952     return 0;
1953     }
1954     tmp->stats.food = spell->duration + SP_level_duration_adjust (caster, spell);
1955     if (tmp->glow_radius)
1956     {
1957     tmp->glow_radius = spell->range + SP_level_range_adjust (caster, spell);
1958     if (tmp->glow_radius > MAX_LIGHT_RADII)
1959     tmp->glow_radius = MAX_LIGHT_RADII;
1960 elmex 1.1 }
1961 root 1.25
1962     m->insert (tmp, x, y, op);
1963 root 1.9 return 1;
1964 elmex 1.1 }
1965    
1966    
1967    
1968    
1969     /* cast_cause_disease: this spell looks along <dir> from the
1970     * player and infects someone.
1971     * op is the player/monster, caster is the object, dir is the direction
1972     * to cast, disease_arch is the specific disease, and type is the spell number
1973     * perhaps this should actually be in disease.c?
1974     */
1975    
1976 root 1.9 int
1977     cast_cause_disease (object *op, object *caster, object *spell, int dir)
1978     {
1979     sint16 x, y;
1980     int i, mflags, range, dam_mod, dur_mod;
1981     object *walk;
1982 root 1.15 maptile *m;
1983 root 1.9
1984     x = op->x;
1985     y = op->y;
1986    
1987     /* If casting from a scroll, no direction will be available, so refer to the
1988     * direction the player is pointing.
1989     */
1990     if (!dir)
1991     dir = op->facing;
1992     if (!dir)
1993     return 0; /* won't find anything if casting on ourself, so just return */
1994    
1995     /* Calculate these once here */
1996     range = spell->range + SP_level_range_adjust (caster, spell);
1997     dam_mod = SP_level_dam_adjust (caster, spell);
1998     dur_mod = SP_level_duration_adjust (caster, spell);
1999    
2000     /* search in a line for a victim */
2001     for (i = 1; i < range; i++)
2002     {
2003     x = op->x + i * freearr_x[dir];
2004     y = op->y + i * freearr_y[dir];
2005     m = op->map;
2006    
2007     mflags = get_map_flags (m, &m, x, y, &x, &y);
2008    
2009     if (mflags & P_OUT_OF_MAP)
2010     return 0;
2011    
2012     /* don't go through walls - presume diseases are airborne */
2013     if (GET_MAP_MOVE_BLOCK (m, x, y) & MOVE_FLY_LOW)
2014     return 0;
2015    
2016     /* Only bother looking on this space if there is something living here */
2017     if (mflags & P_IS_ALIVE)
2018     {
2019     /* search this square for a victim */
2020 root 1.21 for (walk = GET_MAP_OB (m, x, y); walk; walk = walk->above)
2021 root 1.9 if (QUERY_FLAG (walk, FLAG_MONSTER) || (walk->type == PLAYER))
2022     { /* found a victim */
2023     object *disease = arch_to_object (spell->other_arch);
2024    
2025 root 1.19 disease->set_owner (op);
2026 root 1.9 set_spell_skill (op, caster, spell, disease);
2027     disease->stats.exp = 0;
2028     disease->level = caster_level (caster, spell);
2029    
2030     /* do level adjustments */
2031     if (disease->stats.wc)
2032     disease->stats.wc += dur_mod / 2;
2033    
2034     if (disease->magic > 0)
2035     disease->magic += dur_mod / 4;
2036    
2037     if (disease->stats.maxhp > 0)
2038     disease->stats.maxhp += dur_mod;
2039    
2040     if (disease->stats.maxgrace > 0)
2041     disease->stats.maxgrace += dur_mod;
2042    
2043     if (disease->stats.dam)
2044     {
2045     if (disease->stats.dam > 0)
2046     disease->stats.dam += dam_mod;
2047     else
2048     disease->stats.dam -= dam_mod;
2049     }
2050 root 1.6
2051 root 1.9 if (disease->last_sp)
2052     {
2053     disease->last_sp -= 2 * dam_mod;
2054     if (disease->last_sp < 1)
2055     disease->last_sp = 1;
2056     }
2057 root 1.6
2058 root 1.9 if (disease->stats.maxsp)
2059     {
2060     if (disease->stats.maxsp > 0)
2061     disease->stats.maxsp += dam_mod;
2062     else
2063     disease->stats.maxsp -= dam_mod;
2064     }
2065 root 1.6
2066 root 1.9 if (disease->stats.ac)
2067     disease->stats.ac += dam_mod;
2068 root 1.6
2069 root 1.9 if (disease->last_eat)
2070     disease->last_eat -= dam_mod;
2071 root 1.6
2072 root 1.9 if (disease->stats.hp)
2073     disease->stats.hp -= dam_mod;
2074 root 1.6
2075 root 1.9 if (disease->stats.sp)
2076     disease->stats.sp -= dam_mod;
2077    
2078     if (infect_object (walk, disease, 1))
2079     {
2080     new_draw_info_format (NDI_UNIQUE, 0, op, "You inflict %s on %s!", &disease->name, &walk->name);
2081    
2082 root 1.17 disease->destroy (); /* don't need this one anymore */
2083 root 1.40 walk->map->insert (get_archetype ("detect_magic"), x, y, op);
2084 root 1.9 return 1;
2085 root 1.6 }
2086 root 1.17
2087     disease->destroy ();
2088 root 1.9 }
2089     } /* if living creature */
2090     } /* for range of spaces */
2091 root 1.25
2092 root 1.9 new_draw_info (NDI_UNIQUE, 0, op, "No one caught anything!");
2093     return 1;
2094 elmex 1.1 }