ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.117
Committed: Sat Nov 17 23:40:04 2018 UTC (5 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.116: +1 -0 lines
Log Message:
copyright update 2018

File Contents

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