ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.65
Committed: Mon Sep 29 10:20:49 2008 UTC (15 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.64: +38 -29 lines
Log Message:
do the same everywhere else

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