ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.24
Committed: Tue Dec 26 08:55:00 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.23: +2 -5 lines
Log Message:
replace update_ob_speed by ->set_speed

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