ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.15
Committed: Sat Sep 16 22:24:13 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.14: +15 -15 lines
Log Message:
mapstruct => maptile
removed many ytypedefs in favor of structure tags

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