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