ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.57
Committed: Sat May 17 14:11:13 2008 UTC (16 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.56: +4 -6 lines
Log Message:
fix missile swarm, improve blockign logic

File Contents

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