ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.66
Committed: Mon Sep 29 10:31:32 2008 UTC (15 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.65: +5 -10 lines
Log Message:
introduce drop_and_destroy and use it

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