ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.c
Revision: 1.2
Committed: Tue Feb 21 11:00:07 2006 UTC (18 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.1: +21 -22 lines
Log Message:
*** empty log message ***

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