ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
Revision: 1.4
Committed: Tue Aug 15 17:35:51 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.3: +3 -3 lines
Log Message:
removed P_SAFE_MAP and added P_SAFE as map flag set by an item with type SAFE_FLOOR (165)

File Contents

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