ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.17
Committed: Tue Dec 12 21:39:57 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.16: +52 -66 lines
Log Message:
- more ooficiation
- removed now superfluous remove calls

File Contents

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