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