ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.21
Committed: Wed Dec 20 09:14:22 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.20: +7 -7 lines
Log Message:
- minor cleanups
- minor optimisations (in_player vs. is_player_inv)
- added P_PLAYER map flag
- some (dead) concept code

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