ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.5
Committed: Sat Aug 26 23:36:34 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +1 -2 lines
Log Message:
intermediate check-in, per-object events work

File Contents

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