ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.2
Committed: Tue Aug 15 15:00:20 2006 UTC (17 years, 10 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.1: +8 -1 lines
Log Message:
added a safe_map flag which prevents bad effects on maps that should be
safe, like some shops and for example the trade shop in scorn.

File Contents

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