ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.56
Committed: Sat May 17 01:05:57 2008 UTC (16 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.55: +3 -1 lines
Log Message:
*** empty log message ***

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