ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.9
Committed: Sun Sep 10 15:59:57 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.8: +1692 -1447 lines
Log Message:
indent

File Contents

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