ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.23
Committed: Mon Dec 25 11:25:50 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.22: +10 -9 lines
Log Message:
- small, but subtle, rewrite of object management
- perl will now keep attachable objects alive
- objects are now refcounted
- refcouts need to be tested explicitly (refcnt_chk)
- explicit destroy is required current
- explicit destroy asks "nicely" for the object to self destruct, if possible
- refcounts will be used during mortal killing
- minor bugfixes, optimisations etc.
- some former hacks removed.

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