ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.111
Committed: Fri Jan 27 22:01:46 2012 UTC (12 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.110: +1 -1 lines
Log Message:
Jonathan Neuschäfer [PATCH 1/9] common/item: remove redundant "type == ROD"
Jonathan Neuschäfer [PATCH 2/9] common/readable: remove fixed-size buffers in spellpath_msg
Jonathan Neuschäfer [PATCH 3/9] server/attack: remove unused struct att_msg_str
Jonathan Neuschäfer [PATCH 4/9] server/c_misc: remove unused typedef'd struct chars_names
Jonathan Neuschäfer [PATCH 5/9] server/attack: hit_map: return retflag, as promised
Jonathan Neuschäfer [PATCH 6/9] random_maps/wall: remove redundant check
Jonathan Neuschäfer [PATCH 7/9] server/spell_attack: fix function name in comment
Jonathan Neuschäfer [PATCH 9/9] socket/info: fix memory leak in error path

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