ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.12
Committed: Thu Sep 14 21:16:13 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.11: +2 -2 lines
Log Message:
cleanup

File Contents

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