ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.c
Revision: 1.3
Committed: Wed Mar 15 15:35:52 2006 UTC (18 years, 2 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.2: +4 -3 lines
Log Message:
UPSTREAM merge from 15.03.2006

File Contents

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