ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.13
Committed: Thu Sep 14 22:34:05 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.12: +1 -8 lines
Log Message:
indent

File Contents

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