ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.41
Committed: Sat Jun 9 21:16:12 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.40: +4 -16 lines
Log Message:
- inherit some flags from the head (probably should inherit everything,
  the whole object, but thats for later).
  this makes speed-relevant code faster and simpler.

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