ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.40
Committed: Thu Jun 7 18:58:30 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.39: +1 -1 lines
Log Message:
un-insanify

File Contents

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