ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.88
Committed: Mon Oct 12 14:00:59 2009 UTC (14 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_82, rel-2_81
Changes since 1.87: +7 -6 lines
Log Message:
clarify license

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