ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.46
Committed: Sat Apr 28 21:34:38 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.45: +6 -4 lines
Log Message:
cleanup

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.34 * CrossFire, A Multiplayer game
3     *
4     * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5     * Copyright (C) 2002 Mark Wedel & Crossfire Development Team
6     * Copyright (C) 1992 Frank Tore Johansen
7     *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     *
22     * The authors can be reached via e-mail at <crossfire@schmorp.de>
23     */
24 elmex 1.1
25     /*
26     * Routines that is executed from objects based on their speed have been
27     * collected in this file.
28     */
29     #include <global.h>
30     #include <spells.h>
31 root 1.28 #include <sproto.h>
32 elmex 1.1
33     /* The following removes doors. The functions check to see if similar
34     * doors are next to the one that is being removed, and if so, set it
35     * so those will be removed shortly (in a cascade like fashion.)
36     */
37 root 1.9 void
38     remove_door (object *op)
39     {
40 elmex 1.1 int i;
41     object *tmp;
42 root 1.9
43     for (i = 1; i < 9; i += 2)
44     if ((tmp = present (DOOR, op->map, op->x + freearr_x[i], op->y + freearr_y[i])) != NULL)
45     {
46 root 1.26 tmp->set_speed (0.1);
47 root 1.9 tmp->speed_left = -0.2;
48     }
49    
50     if (op->other_arch)
51     {
52     tmp = arch_to_object (op->other_arch);
53     tmp->x = op->x;
54     tmp->y = op->y;
55     tmp->map = op->map;
56     tmp->level = op->level;
57     insert_ob_in_map (tmp, op->map, op, 0);
58     }
59 root 1.17
60     op->destroy ();
61 elmex 1.1 }
62    
63 root 1.9 void
64     remove_door2 (object *op)
65     {
66 elmex 1.1 int i;
67     object *tmp;
68 root 1.9
69     for (i = 1; i < 9; i += 2)
70     {
71     tmp = present (LOCKED_DOOR, op->map, op->x + freearr_x[i], op->y + freearr_y[i]);
72     if (tmp && tmp->slaying == op->slaying)
73     { /* same key both doors */
74 root 1.26 tmp->set_speed (0.1);
75 root 1.9 tmp->speed_left = -0.2;
76     }
77     }
78 root 1.27
79 root 1.9 if (op->other_arch)
80     {
81     tmp = arch_to_object (op->other_arch);
82     tmp->x = op->x;
83     tmp->y = op->y;
84     tmp->map = op->map;
85     tmp->level = op->level;
86     insert_ob_in_map (tmp, op->map, op, 0);
87     }
88 root 1.17
89     op->destroy ();
90 elmex 1.1 }
91    
92 root 1.45 void
93     generate_monster (object *gen)
94 root 1.9 {
95 root 1.45 if (!gen->map)
96     return;
97    
98     if (GENERATE_SPEED (gen) && rndm (0, GENERATE_SPEED (gen) - 1))
99     return;
100    
101     object *op;
102    
103     if (QUERY_FLAG (gen, FLAG_CONTENT_ON_GEN))
104     {
105     // either copy one item form the inventory...
106     if (!gen->inv)
107     return;
108    
109     // first select one item from the inventory
110     int index = 0;
111     for (object *tmp = gen->inv; tmp; tmp = tmp->below)
112     if (!rndm (++index))
113     op = tmp;
114    
115     op = object_create_clone (op);
116    
117     CLEAR_FLAG (op, FLAG_IS_A_TEMPLATE);
118     unflag_inv (op, FLAG_IS_A_TEMPLATE);
119     }
120     else
121     {
122     // ...or use other_arch
123     if (archetype *at = gen->other_arch)
124     op = arch_to_object (at);
125     else
126     return;
127     }
128    
129 root 1.44 op->expand_tail ();
130 root 1.9
131 root 1.44 int i = find_free_spot (op, gen->map, gen->x, gen->y, 1, 9);
132     if (i >= 0)
133 root 1.9 {
134 root 1.44 if (insert_ob_in_map_at (op, gen->map, gen, 0, gen->x + freearr_x[i], gen->y + freearr_y[i]))
135     {
136     if (rndm (0, 9))
137     generate_artifact (op, gen->map->difficulty);
138 root 1.43
139 root 1.44 if (op->has_random_items ())
140     create_treasure (op->randomitems, op, GT_APPLY, gen->map->difficulty);
141 root 1.43
142 root 1.44 return;
143     }
144 elmex 1.1 }
145 root 1.43
146 root 1.44 op->destroy ();
147 root 1.9 }
148    
149     void
150     remove_force (object *op)
151     {
152     if (--op->duration > 0)
153     return;
154 elmex 1.1
155 root 1.25 if (op->env)
156     switch (op->subtype)
157     {
158     case FORCE_CONFUSION:
159     CLEAR_FLAG (op->env, FLAG_CONFUSED);
160     new_draw_info (NDI_UNIQUE, 0, op->env, "You regain your senses.\n");
161 root 1.6
162 root 1.25 default:
163     CLEAR_FLAG (op, FLAG_APPLIED);
164     change_abil (op->env, op);
165     op->env->update_stats ();
166     }
167 root 1.17
168     op->destroy ();
169 elmex 1.1 }
170    
171 root 1.9 void
172     remove_blindness (object *op)
173     {
174     if (--op->stats.food > 0)
175 elmex 1.1 return;
176 root 1.17
177 root 1.9 CLEAR_FLAG (op, FLAG_APPLIED);
178 root 1.17
179 root 1.27 if (op->env)
180 root 1.9 {
181     change_abil (op->env, op);
182 root 1.23 op->env->update_stats ();
183 root 1.9 }
184 root 1.17
185     op->destroy ();
186 elmex 1.1 }
187    
188 root 1.9 void
189     poison_more (object *op)
190     {
191     if (op->env == NULL || !QUERY_FLAG (op->env, FLAG_ALIVE) || op->env->stats.hp < 0)
192     {
193 root 1.17 op->destroy ();
194 root 1.9 return;
195     }
196 root 1.17
197 root 1.9 if (op->stats.food == 1)
198     {
199 root 1.38 /* need to unapply the object before update_stats is called, else fix_player
200 root 1.9 * will not do anything.
201     */
202     if (op->env->type == PLAYER)
203     {
204     CLEAR_FLAG (op, FLAG_APPLIED);
205 root 1.23 op->env->update_stats ();
206 root 1.9 new_draw_info (NDI_UNIQUE, 0, op->env, "You feel much better now.");
207     }
208 root 1.17
209     op->destroy ();
210 root 1.9 return;
211     }
212 root 1.17
213 root 1.9 if (op->env->type == PLAYER)
214     {
215     op->env->stats.food--;
216     new_draw_info (NDI_UNIQUE, 0, op->env, "You feel very sick...");
217 elmex 1.1 }
218 elmex 1.32
219     hit_player (op->env, op->stats.dam, op, AT_INTERNAL, 1);
220 elmex 1.1 }
221    
222    
223 root 1.9 void
224     move_gate (object *op)
225 root 1.46 { /* 1 = going down, 0 = going up */
226 root 1.9 object *tmp;
227    
228     if (op->stats.wc < 0 || (int) op->stats.wc >= NUM_ANIMATIONS (op))
229     {
230     LOG (llevError, "Gate error: animation was %d, max=%d\n", op->stats.wc, NUM_ANIMATIONS (op));
231     op->stats.wc = 0;
232     }
233    
234     /* We're going down */
235     if (op->value)
236     {
237     if (--op->stats.wc <= 0)
238     { /* Reached bottom, let's stop */
239     op->stats.wc = 0;
240     if (op->arch->clone.speed)
241     op->value = 0;
242     else
243 root 1.26 op->set_speed (0);
244 root 1.6 }
245 root 1.26
246 root 1.9 if ((int) op->stats.wc < (NUM_ANIMATIONS (op) / 2 + 1))
247     {
248     op->move_block = 0;
249     CLEAR_FLAG (op, FLAG_BLOCKSVIEW);
250     update_all_los (op->map, op->x, op->y);
251     }
252 root 1.26
253 root 1.9 SET_ANIMATION (op, op->stats.wc);
254     update_object (op, UP_OBJ_CHANGE);
255     return;
256 elmex 1.1 }
257    
258 root 1.9 /* We're going up */
259 elmex 1.1
260 root 1.9 /* First, lets see if we are already at the top */
261     if ((unsigned char) op->stats.wc == (NUM_ANIMATIONS (op) - 1))
262     {
263 elmex 1.1
264 root 1.9 /* Check to make sure that only non pickable and non rollable
265     * objects are above the gate. If so, we finish closing the gate,
266     * otherwise, we fall through to the code below which should lower
267     * the gate slightly.
268     */
269    
270     for (tmp = op->above; tmp != NULL; tmp = tmp->above)
271     if (!QUERY_FLAG (tmp, FLAG_NO_PICK) || QUERY_FLAG (tmp, FLAG_CAN_ROLL) || QUERY_FLAG (tmp, FLAG_ALIVE))
272     break;
273 root 1.6
274 root 1.9 if (tmp == NULL)
275     {
276     if (op->arch->clone.speed)
277     op->value = 1;
278     else
279 root 1.26 op->set_speed (0);
280    
281 root 1.9 return;
282     }
283     }
284    
285     if (op->stats.food)
286     { /* The gate is going temporarily down */
287     if (--op->stats.wc <= 0)
288     { /* Gone all the way down? */
289     op->stats.food = 0; /* Then let's try again */
290     op->stats.wc = 0;
291 root 1.6 }
292 elmex 1.1 }
293 root 1.9 else
294     { /* The gate is still going up */
295     op->stats.wc++;
296 elmex 1.1
297 root 1.9 if ((int) op->stats.wc >= (NUM_ANIMATIONS (op)))
298     op->stats.wc = (signed char) NUM_ANIMATIONS (op) - 1;
299    
300     /* If there is something on top of the gate, we try to roll it off.
301     * If a player/monster, we don't roll, we just hit them with damage
302     */
303     if ((int) op->stats.wc >= NUM_ANIMATIONS (op) / 2)
304     {
305     /* Halfway or further, check blocks */
306     /* First, get the top object on the square. */
307 root 1.46 for (tmp = op->above; tmp && tmp->above; tmp = tmp->above)
308     ;
309 root 1.9
310 root 1.46 if (tmp)
311 root 1.9 {
312     if (QUERY_FLAG (tmp, FLAG_ALIVE))
313     {
314 root 1.46 hit_player (tmp, random_roll (0, op->stats.dam, tmp, PREFER_LOW), op, AT_PHYSICAL, 1);
315    
316 root 1.9 if (tmp->type == PLAYER)
317     new_draw_info_format (NDI_UNIQUE, 0, tmp, "You are crushed by the %s!", &op->name);
318     }
319     else
320     /* If the object is not alive, and the object either can
321     * be picked up or the object rolls, move the object
322     * off the gate.
323     */
324     if (!QUERY_FLAG (tmp, FLAG_ALIVE) && (!QUERY_FLAG (tmp, FLAG_NO_PICK) || QUERY_FLAG (tmp, FLAG_CAN_ROLL)))
325     {
326     /* If it has speed, it should move itself, otherwise: */
327     int i = find_free_spot (tmp, op->map, op->x, op->y, 1, 9);
328    
329     /* If there is a free spot, move the object someplace */
330     if (i != -1)
331     {
332 root 1.16 tmp->remove ();
333 root 1.9 tmp->x += freearr_x[i], tmp->y += freearr_y[i];
334     insert_ob_in_map (tmp, op->map, op, 0);
335 root 1.6 }
336     }
337     }
338    
339 root 1.9 /* See if there is still anything blocking the gate */
340     for (tmp = op->above; tmp != NULL; tmp = tmp->above)
341     if (!QUERY_FLAG (tmp, FLAG_NO_PICK) || QUERY_FLAG (tmp, FLAG_CAN_ROLL) || QUERY_FLAG (tmp, FLAG_ALIVE))
342     break;
343    
344     /* IF there is, start putting the gate down */
345     if (tmp)
346     {
347     op->stats.food = 1;
348     }
349     else
350     {
351     op->move_block = MOVE_ALL;
352     if (!op->arch->clone.stats.ac)
353     SET_FLAG (op, FLAG_BLOCKSVIEW);
354     update_all_los (op->map, op->x, op->y);
355     }
356     } /* gate is halfway up */
357    
358     SET_ANIMATION (op, op->stats.wc);
359     update_object (op, UP_OBJ_CHANGE);
360     } /* gate is going up */
361 elmex 1.1 }
362    
363     /* hp : how long door is open/closed
364     * maxhp : initial value for hp
365     * sp : 1 = open, 0 = close
366     */
367 root 1.9 void
368     move_timed_gate (object *op)
369 elmex 1.1 {
370     int v = op->value;
371    
372 root 1.9 if (op->stats.sp)
373     {
374     move_gate (op);
375     if (op->value != v) /* change direction ? */
376     op->stats.sp = 0;
377     return;
378     }
379     if (--op->stats.hp <= 0)
380     { /* keep gate down */
381     move_gate (op);
382     if (op->value != v)
383 root 1.26 op->set_speed (0);
384 elmex 1.1 }
385     }
386    
387     /* slaying: name of the thing the detector is to look for
388     * speed: frequency of 'glances'
389     * connected: connected value of detector
390     * sp: 1 if detection sets buttons
391     * -1 if detection unsets buttons
392     */
393    
394 root 1.9 void
395     move_detector (object *op)
396 elmex 1.1 {
397 root 1.9 object *tmp;
398     int last = op->value;
399     int detected;
400    
401     detected = 0;
402    
403 root 1.20 for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL && !detected; tmp = tmp->above)
404 root 1.9 {
405     object *tmp2;
406    
407     if (op->stats.hp)
408     {
409     for (tmp2 = tmp->inv; tmp2; tmp2 = tmp2->below)
410     {
411 root 1.37 if (op->slaying && op->slaying == tmp->name)
412 root 1.9 detected = 1;
413 root 1.37
414     if (tmp2->type == FORCE && tmp2->slaying && tmp2->slaying == op->slaying)
415 root 1.9 detected = 1;
416     }
417     }
418 root 1.37
419     if (op->slaying && op->slaying == tmp->name)
420     detected = 1;
421 root 1.9 else if (tmp->type == SPECIAL_KEY && tmp->slaying == op->slaying)
422     detected = 1;
423 elmex 1.1 }
424    
425 root 1.9 /* the detector sets the button if detection is found */
426     if (op->stats.sp == 1)
427     {
428     if (detected && last == 0)
429     {
430     op->value = 1;
431     push_button (op);
432 root 1.6 }
433 root 1.9 if (!detected && last == 1)
434     {
435     op->value = 0;
436     push_button (op);
437 root 1.6 }
438 elmex 1.1 }
439 root 1.9 else
440     { /* in this case, we unset buttons */
441     if (detected && last == 1)
442     {
443     op->value = 0;
444     push_button (op);
445 root 1.6 }
446 root 1.9 if (!detected && last == 0)
447     {
448     op->value = 1;
449     push_button (op);
450 root 1.6 }
451 elmex 1.1 }
452     }
453    
454    
455 root 1.9 void
456     animate_trigger (object *op)
457 elmex 1.1 {
458 root 1.9 if ((unsigned char) ++op->stats.wc >= NUM_ANIMATIONS (op))
459     {
460     op->stats.wc = 0;
461     check_trigger (op, NULL);
462     }
463     else
464     {
465     SET_ANIMATION (op, op->stats.wc);
466     update_object (op, UP_OBJ_FACE);
467     }
468 elmex 1.1 }
469    
470 root 1.9 void
471     move_hole (object *op)
472     { /* 1 = opening, 0 = closing */
473     object *next, *tmp;
474    
475     if (op->value)
476     { /* We're opening */
477     if (--op->stats.wc <= 0)
478     { /* Opened, let's stop */
479     op->stats.wc = 0;
480 root 1.26 op->set_speed (0);
481 root 1.9
482     /* Hard coding this makes sense for holes I suppose */
483     op->move_on = MOVE_WALK;
484     for (tmp = op->above; tmp != NULL; tmp = next)
485     {
486     next = tmp->above;
487     move_apply (op, tmp, tmp);
488 root 1.6 }
489     }
490 root 1.26
491 root 1.9 SET_ANIMATION (op, op->stats.wc);
492     update_object (op, UP_OBJ_FACE);
493     return;
494 elmex 1.1 }
495 root 1.9 /* We're closing */
496     op->move_on = 0;
497 elmex 1.1
498 root 1.9 op->stats.wc++;
499     if ((int) op->stats.wc >= NUM_ANIMATIONS (op))
500     op->stats.wc = NUM_ANIMATIONS (op) - 1;
501 root 1.26
502 root 1.9 SET_ANIMATION (op, op->stats.wc);
503     update_object (op, UP_OBJ_FACE);
504     if ((unsigned char) op->stats.wc == (NUM_ANIMATIONS (op) - 1))
505 root 1.26 op->set_speed (0); /* closed, let's stop */
506 elmex 1.1 }
507    
508    
509     /* stop_item() returns a pointer to the stopped object. The stopped object
510     * may or may not have been removed from maps or inventories. It will not
511     * have been merged with other items.
512     *
513     * This function assumes that only items on maps need special treatment.
514     *
515     * If the object can't be stopped, or it was destroyed while trying to stop
516     * it, NULL is returned.
517     *
518     * fix_stopped_item() should be used if the stopped item should be put on
519     * the map.
520     */
521 root 1.9 object *
522     stop_item (object *op)
523 elmex 1.1 {
524 root 1.9 if (op->map == NULL)
525     return op;
526 elmex 1.1
527 root 1.9 switch (op->type)
528 elmex 1.1 {
529 root 1.10 case THROWN_OBJ:
530     {
531     object *payload = op->inv;
532 root 1.9
533 root 1.10 if (payload == NULL)
534     return NULL;
535 root 1.16 payload->remove ();
536 root 1.17 op->destroy ();
537 root 1.10 return payload;
538     }
539 elmex 1.1
540 root 1.10 case ARROW:
541 elmex 1.29 if (op->has_active_speed ())
542 root 1.10 op = fix_stopped_arrow (op);
543     return op;
544 elmex 1.1
545 root 1.10 default:
546     return op;
547 elmex 1.1 }
548     }
549    
550     /* fix_stopped_item() - put stopped item where stop_item() had found it.
551     * Inserts item into the old map, or merges it if it already is on the map.
552     *
553     * 'map' must be the value of op->map before stop_item() was called.
554     */
555 root 1.9 void
556 root 1.13 fix_stopped_item (object *op, maptile *map, object *originator)
557 elmex 1.1 {
558 root 1.9 if (map == NULL)
559     return;
560 root 1.40
561 root 1.9 if (QUERY_FLAG (op, FLAG_REMOVED))
562     insert_ob_in_map (op, map, originator, 0);
563     else if (op->type == ARROW)
564     merge_ob (op, NULL); /* only some arrows actually need this */
565 elmex 1.1 }
566    
567 root 1.9 object *
568     fix_stopped_arrow (object *op)
569     {
570     if (rndm (0, 99) < op->stats.food)
571     {
572     /* Small chance of breaking */
573 root 1.17 op->destroy ();
574 root 1.9 return NULL;
575     }
576    
577 root 1.26 op->set_speed (0);
578 root 1.9 op->direction = 0;
579     op->move_on = 0;
580     op->move_type = 0;
581     op->stats.wc = op->stats.sp;
582     op->stats.dam = op->stats.hp;
583     op->attacktype = op->stats.grace;
584     op->slaying = 0;
585     op->skill = 0;
586    
587     if (op->spellarg != NULL)
588     {
589     op->slaying = op->spellarg;
590     free (op->spellarg);
591     op->spellarg = NULL;
592     }
593     else
594     op->slaying = NULL;
595    
596 root 1.18 /* Reset these to zero, so that object::can_merge will work properly */
597 root 1.9 op->spellarg = NULL;
598     op->stats.sp = 0;
599     op->stats.hp = 0;
600     op->stats.grace = 0;
601     op->level = 0;
602     op->face = op->arch->clone.face;
603     op->owner = NULL; /* So that stopped arrows will be saved */
604 root 1.40 update_object (op, UP_OBJ_CHANGE);
605 root 1.9 return op;
606 elmex 1.1 }
607    
608     /* stop_arrow() - what to do when a non-living flying object
609     * has to stop. Sept 96 - I added in thrown object code in
610     * here too. -b.t.
611     *
612     * Returns a pointer to the stopped object (which will have been removed
613     * from maps or inventories), or NULL if was destroyed.
614     */
615 root 1.9 static void
616     stop_arrow (object *op)
617 elmex 1.1 {
618 root 1.9 if (INVOKE_OBJECT (STOP, op))
619     return;
620    
621     if (op->inv)
622     {
623     object *payload = op->inv;
624 root 1.4
625 root 1.16 payload->remove ();
626 root 1.18 payload->owner = 0;
627 root 1.9 insert_ob_in_map (payload, op->map, payload, 0);
628 root 1.17 op->destroy ();
629 root 1.9 }
630     else
631     {
632     op = fix_stopped_arrow (op);
633     if (op)
634     merge_ob (op, NULL);
635 elmex 1.1 }
636     }
637    
638     /* Move an arrow along its course. op is the arrow or thrown object.
639     */
640 root 1.9 void
641     move_arrow (object *op)
642     {
643     object *tmp;
644     sint16 new_x, new_y;
645     int was_reflected, mflags;
646 root 1.13 maptile *m;
647 root 1.9
648     if (op->map == NULL)
649     {
650     LOG (llevError, "BUG: Arrow had no map.\n");
651 root 1.17 op->destroy ();
652 root 1.9 return;
653 elmex 1.1 }
654    
655 root 1.9 /* we need to stop thrown objects at some point. Like here. */
656     if (op->type == THROWN_OBJ)
657     {
658     /* If the object that the THROWN_OBJ encapsulates disappears,
659     * we need to have this object go away also - otherwise, you get
660     * left over remnants on the map. Where this currently happens
661     * is if the player throws a bomb - the bomb explodes on its own,
662     * but this object sticks around. We could handle the cleanup in the
663     * bomb code, but there are potential other cases where that could happen,
664     * and it is easy enough to clean it up here.
665     */
666     if (op->inv == NULL)
667     {
668 root 1.17 op->destroy ();
669 root 1.9 return;
670 root 1.6 }
671 root 1.14
672 root 1.9 if (op->last_sp-- < 0)
673     {
674     stop_arrow (op);
675     return;
676 root 1.6 }
677 elmex 1.1 }
678    
679 root 1.9 /* if the arrow is moving too slow.. stop it. 0.5 was chosen as lower
680     values look rediculous. */
681     if (op->speed < 0.5 && op->type == ARROW)
682     {
683     stop_arrow (op);
684     return;
685 elmex 1.1 }
686    
687 root 1.9 /* Calculate target map square */
688     new_x = op->x + DIRX (op);
689     new_y = op->y + DIRY (op);
690     was_reflected = 0;
691 elmex 1.1
692 root 1.9 m = op->map;
693     mflags = get_map_flags (m, &m, new_x, new_y, &new_x, &new_y);
694 elmex 1.1
695 root 1.9 if (mflags & P_OUT_OF_MAP)
696     {
697     stop_arrow (op);
698     return;
699 elmex 1.1 }
700    
701 root 1.9 /* only need to look for living creatures if this flag is set */
702     if (mflags & P_IS_ALIVE)
703     {
704 root 1.20 for (tmp = GET_MAP_OB (m, new_x, new_y); tmp != NULL; tmp = tmp->above)
705 root 1.9 if (QUERY_FLAG (tmp, FLAG_ALIVE))
706     break;
707    
708     /* Not really fair, but don't let monsters hit themselves with
709     * their own arrow - this can be because they fire it then
710     * move into it.
711     */
712 root 1.14 if (tmp && tmp != op->owner)
713 root 1.9 {
714     /* Found living object, but it is reflecting the missile. Update
715     * as below. (Note that for living creatures there is a small
716     * chance that reflect_missile fails.)
717     */
718     if (QUERY_FLAG (tmp, FLAG_REFL_MISSILE) && (rndm (0, 99)) < (90 - op->level / 10))
719     {
720 root 1.39 int number = op->face;
721 root 1.9
722     op->direction = absdir (op->direction + 4);
723 root 1.41 update_turn_face (op);
724 root 1.9 was_reflected = 1; /* skip normal movement calculations */
725 root 1.6 }
726 root 1.9 else
727     {
728     /* Attack the object. */
729     op = hit_with_arrow (op, tmp);
730 root 1.14
731     if (!op)
732 root 1.9 return;
733     }
734     } /* if this is not hitting its owner */
735     } /* if there is something alive on this space */
736 root 1.6
737 root 1.9 if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, new_x, new_y)))
738     {
739     int retry = 0;
740    
741     /* if the object doesn't reflect, stop the arrow from moving
742     * note that this code will now catch cases where a monster is
743     * on a wall but has reflecting - the arrow won't reflect.
744     * Mapmakers shouldn't put monsters on top of wall in the first
745     * place, so I don't consider that a problem.
746     */
747     if (!QUERY_FLAG (op, FLAG_REFLECTING) || !(rndm (0, 19)))
748     {
749     stop_arrow (op);
750     return;
751     }
752     else
753     {
754     /* If one of the major directions (n,s,e,w), just reverse it */
755     if (op->direction & 1)
756     {
757     op->direction = absdir (op->direction + 4);
758     retry = 1;
759     }
760     /* There were two blocks with identical code -
761     * use this retry here to make this one block
762     * that did the same thing.
763     */
764     while (retry < 2)
765     {
766     int left, right, mflags;
767 root 1.13 maptile *m1;
768 root 1.9 sint16 x1, y1;
769    
770     retry++;
771    
772     /* Need to check for P_OUT_OF_MAP: if the arrow is tavelling
773     * over a corner in a tiled map, it is possible that
774     * op->direction is within an adjacent map but either
775     * op->direction-1 or op->direction+1 does not exist.
776     */
777     mflags = get_map_flags (op->map, &m1, op->x + freearr_x[absdir (op->direction - 1)],
778     op->y + freearr_y[absdir (op->direction - 1)], &x1, &y1);
779     left = (mflags & P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK (op, (GET_MAP_MOVE_BLOCK (m1, x1, y1)));
780    
781     mflags = get_map_flags (op->map, &m1, op->x + freearr_x[absdir (op->direction + 1)],
782     op->y + freearr_y[absdir (op->direction + 1)], &x1, &y1);
783     right = (mflags & P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK (op, (GET_MAP_MOVE_BLOCK (m1, x1, y1)));
784    
785     if (left == right)
786     op->direction = absdir (op->direction + 4);
787     else if (left)
788     op->direction = absdir (op->direction + 2);
789     else if (right)
790     op->direction = absdir (op->direction - 2);
791    
792     mflags = get_map_flags (op->map, &m1, op->x + DIRX (op), op->y + DIRY (op), &x1, &y1);
793    
794     /* If this space is not out of the map and not blocked, valid space -
795     * don't need to retry again.
796     */
797     if (!(mflags & P_OUT_OF_MAP) && !OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m1, x1, y1)))
798     break;
799 root 1.6
800     }
801 root 1.9 /* Couldn't find a direction to move the arrow to - just
802     * top it from moving.
803     */
804     if (retry == 2)
805     {
806     stop_arrow (op);
807     return;
808     }
809     /* update object image for new facing */
810     /* many thrown objects *don't* have more than one face */
811     if (GET_ANIM_ID (op))
812     SET_ANIMATION (op, op->direction);
813     } /* object is reflected */
814     } /* object ran into a wall */
815    
816     /* Move the arrow. */
817 root 1.16 op->remove ();
818 root 1.9 op->x = new_x;
819     op->y = new_y;
820    
821     /* decrease the speed as it flies. 0.05 means a standard bow will shoot
822     * about 17 squares. Tune as needed.
823     */
824     op->speed -= 0.05;
825     insert_ob_in_map (op, m, op, 0);
826 elmex 1.1 }
827    
828     /* This routine doesnt seem to work for "inanimate" objects that
829     * are being carried, ie a held torch leaps from your hands!.
830     * Modified this routine to allow held objects. b.t. */
831    
832 root 1.9 void
833     change_object (object *op)
834     { /* Doesn`t handle linked objs yet */
835     int i, j;
836    
837     if (op->other_arch == NULL)
838     {
839     LOG (llevError, "Change object (%s) without other_arch error.\n", &op->name);
840     return;
841     }
842    
843     /* In non-living items only change when food value is 0 */
844     if (!QUERY_FLAG (op, FLAG_ALIVE))
845     {
846     if (op->stats.food-- > 0)
847     return;
848     else
849     op->stats.food = 1; /* so 1 other_arch is made */
850     }
851 root 1.20
852     object *pl = op->in_player ();
853     object *env = op->env;
854    
855 root 1.16 op->remove ();
856 root 1.9 for (i = 0; i < NROFNEWOBJS (op); i++)
857     {
858 root 1.20 object *tmp = arch_to_object (op->other_arch);
859    
860 root 1.9 if (op->type == LAMP)
861     tmp->stats.food = op->stats.food - 1;
862 root 1.20
863 root 1.9 tmp->stats.hp = op->stats.hp; /* The only variable it keeps. */
864     if (env)
865     {
866     tmp->x = env->x, tmp->y = env->y;
867     tmp = insert_ob_in_ob (tmp, env);
868 root 1.20
869 root 1.9 /* If this object is the players inventory, we need to tell the
870     * client of the change. Insert_ob_in_map takes care of the
871     * updating the client, so we don't need to do that below.
872     */
873 root 1.20 if (pl)
874 root 1.9 {
875     esrv_del_item (pl->contr, op->count);
876     esrv_send_item (pl, tmp);
877     }
878     }
879     else
880     {
881     j = find_first_free_spot (tmp, op->map, op->x, op->y);
882     if (j == -1) /* No free spot */
883 root 1.17 tmp->destroy ();
884 root 1.9 else
885     {
886     tmp->x = op->x + freearr_x[j], tmp->y = op->y + freearr_y[j];
887     insert_ob_in_map (tmp, op->map, op, 0);
888     }
889     }
890     }
891 root 1.17
892     op->destroy ();
893 root 1.9 }
894    
895     void
896     move_teleporter (object *op)
897     {
898     object *tmp, *head = op;
899 elmex 1.1
900 root 1.9 /* if this is a multipart teleporter, handle the other parts
901     * The check for speed isn't strictly needed - basically, if
902     * there is an old multipart teleporter in which the other parts
903     * have speed, we don't really want to call it twice for the same
904     * function - in fact, as written below, part N would get called
905     * N times without the speed check.
906     */
907 elmex 1.29 if (op->more && !op->more->has_active_speed ())
908 root 1.9 move_teleporter (op->more);
909    
910     if (op->head)
911     head = op->head;
912    
913     for (tmp = op->above; tmp != NULL; tmp = tmp->above)
914     if (!QUERY_FLAG (tmp, FLAG_IS_FLOOR))
915     break;
916    
917     /* If nothing above us to move, nothing to do */
918     if (!tmp || QUERY_FLAG (tmp, FLAG_WIZPASS))
919 elmex 1.1 return;
920    
921 root 1.9 if (EXIT_PATH (head))
922     {
923     if (tmp->type == PLAYER)
924     {
925     if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
926     return;
927 root 1.3
928 root 1.28 tmp->enter_exit (head);
929 root 1.6 }
930 root 1.9 else
931     /* Currently only players can transfer maps */
932     return;
933 elmex 1.1 }
934 root 1.9 else if (EXIT_X (head) || EXIT_Y (head))
935     {
936     if (out_of_map (head->map, EXIT_X (head), EXIT_Y (head)))
937     {
938     LOG (llevError, "Removed illegal teleporter.\n");
939 root 1.17 head->destroy ();
940 root 1.9 return;
941 root 1.6 }
942 root 1.17
943 root 1.9 if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
944     return;
945 root 1.17
946 root 1.9 transfer_ob (tmp, EXIT_X (head), EXIT_Y (head), 0, head);
947 elmex 1.1 }
948 root 1.9 else
949     {
950     /* Random teleporter */
951     if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
952     return;
953     teleport (head, TELEPORTER, tmp);
954 elmex 1.1 }
955     }
956    
957    
958     /* This object will teleport someone to a different map
959     and will also apply changes to the player from its inventory.
960     This was invented for giving classes, but there's no reason it
961     can't be generalized.
962     */
963 root 1.9 void
964     move_player_changer (object *op)
965     {
966     object *player;
967     object *walk;
968    
969     if (!op->above || !EXIT_PATH (op))
970     return;
971    
972     /* This isn't all that great - means that the player_mover
973     * needs to be on top.
974     */
975     if (op->above->type == PLAYER)
976     {
977     if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (player)))
978 root 1.34 return;
979    
980 root 1.9 player = op->above;
981    
982 root 1.35 for (walk = op->inv; walk; walk = walk->below)
983 root 1.9 apply_changes_to_player (player, walk);
984    
985 root 1.23 player->update_stats ();
986 root 1.9
987     esrv_send_inventory (op->above, op->above);
988     esrv_update_item (UPD_FACE, op->above, op->above);
989    
990     /* update players death & WoR home-position */
991 root 1.35 if (*EXIT_PATH (op) == '/')
992 root 1.9 {
993 root 1.30 player->contr->savebed_map = EXIT_PATH (op);
994     player->contr->bed_x = EXIT_X (op);
995     player->contr->bed_y = EXIT_Y (op);
996 root 1.9 }
997     else
998     LOG (llevDebug, "WARNING: destination '%s' in player_changer must be an absolute path!\n", &EXIT_PATH (op));
999    
1000 root 1.28 op->above->enter_exit (op);
1001 elmex 1.1 }
1002     }
1003    
1004     /* firewalls fire other spells.
1005     * The direction of the wall is stored in op->stats.sp.
1006     * walls can have hp, so they can be torn down.
1007     */
1008 root 1.9 void
1009     move_firewall (object *op)
1010     {
1011     object *spell;
1012 elmex 1.1
1013 root 1.9 if (!op->map)
1014     return; /* dm has created a firewall in his inventory */
1015 elmex 1.1
1016 root 1.9 spell = op->inv;
1017 root 1.24
1018 root 1.9 if (!spell || spell->type != SPELL)
1019     spell = &op->other_arch->clone;
1020 root 1.24
1021 root 1.9 if (!spell)
1022     {
1023 root 1.28 LOG (llevError, "move_firewall: no spell specified (%s, %s, %d, %d)\n", &op->name, &op->map->name, op->x, op->y);
1024 root 1.9 return;
1025 elmex 1.1 }
1026    
1027 root 1.9 cast_spell (op, op, op->stats.sp ? op->stats.sp : rndm (1, 8), spell, NULL);
1028 elmex 1.1 }
1029    
1030     /* move_player_mover: this function takes a "player mover" as an
1031     * argument, and performs the function of a player mover, which is:
1032     *
1033     * a player mover finds any players that are sitting on it. It
1034     * moves them in the op->stats.sp direction. speed is how often it'll move.
1035     * If attacktype is nonzero it will paralyze the player. If lifesave is set,
1036     * it'll dissapear after hp+1 moves. If hp is set and attacktype is set,
1037     * it'll paralyze the victim for hp*his speed/op->speed
1038     */
1039 root 1.9 void
1040     move_player_mover (object *op)
1041     {
1042     object *victim, *nextmover;
1043     int dir = op->stats.sp;
1044     sint16 nx, ny;
1045 root 1.13 maptile *m;
1046 root 1.9
1047     /* Determine direction now for random movers so we do the right thing */
1048     if (!dir)
1049     dir = rndm (1, 8);
1050    
1051 root 1.20 for (victim = GET_MAP_OB (op->map, op->x, op->y); victim != NULL; victim = victim->above)
1052 root 1.9 {
1053     if (QUERY_FLAG (victim, FLAG_ALIVE) && !QUERY_FLAG (victim, FLAG_WIZPASS) &&
1054     (victim->move_type & op->move_type || !victim->move_type))
1055     {
1056    
1057     if (victim->head)
1058     victim = victim->head;
1059    
1060     if (QUERY_FLAG (op, FLAG_LIFESAVE) && op->stats.hp-- < 0)
1061     {
1062 root 1.16 op->remove ();
1063 root 1.9 return;
1064     }
1065 root 1.17
1066 root 1.9 nx = op->x + freearr_x[dir];
1067     ny = op->y + freearr_y[dir];
1068     m = op->map;
1069     if (get_map_flags (m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP)
1070     {
1071 root 1.28 LOG (llevError, "move_player_mover: Trying to push player off the map! map=%s (%d, %d)\n", &m->path, op->x, op->y);
1072 root 1.9 return;
1073 root 1.6 }
1074 root 1.9
1075     if (should_director_abort (op, victim))
1076     return;
1077    
1078 root 1.20 for (nextmover = GET_MAP_OB (m, nx, ny); nextmover != NULL; nextmover = nextmover->above)
1079 root 1.9 {
1080     if (nextmover->type == PLAYERMOVER)
1081     nextmover->speed_left = -.99;
1082     if (QUERY_FLAG (nextmover, FLAG_ALIVE))
1083     {
1084     op->speed_left = -1.1; /* wait until the next thing gets out of the way */
1085 root 1.6 }
1086     }
1087    
1088 root 1.9 if (victim->type == PLAYER)
1089     {
1090     /* only level >=1 movers move people */
1091     if (op->level)
1092     {
1093     /* Following is a bit of hack. We need to make sure it
1094     * is cleared, otherwise the player will get stuck in
1095     * place. This can happen if the player used a spell to
1096     * get to this space.
1097     */
1098     victim->contr->fire_on = 0;
1099     victim->speed_left = -FABS (victim->speed);
1100     move_player (victim, dir);
1101 root 1.6 }
1102 root 1.9 else
1103     return;
1104 root 1.6 }
1105 root 1.9 else
1106     move_object (victim, dir);
1107 root 1.6
1108 root 1.9 if (!op->stats.maxsp && op->attacktype)
1109     op->stats.maxsp = 2;
1110 root 1.6
1111 root 1.9 if (op->attacktype)
1112     { /* flag to paralyze the player */
1113 root 1.6
1114 root 1.9 victim->speed_left = -FABS (op->stats.maxsp * victim->speed / op->speed);
1115     /* Not sure why, but for some chars on metalforge, they
1116     * would sometimes get -inf speed_left, and from the
1117     * description, it could only happen here, so just put
1118     * a lower sanity limit. My only guess is that the
1119     * mover has 0 speed.
1120     */
1121     if (victim->speed_left < -5.0)
1122     victim->speed_left = -5.0;
1123 root 1.6 }
1124     }
1125 elmex 1.1 }
1126     }
1127    
1128     /*
1129     * Will duplicate a specified object placed on top of it.
1130     * connected: what will trigger it.
1131     * level: multiplier. 0 to destroy.
1132     * other_arch: the object to look for and duplicate.
1133     */
1134    
1135 root 1.9 void
1136     move_duplicator (object *op)
1137     {
1138     object *tmp;
1139 elmex 1.1
1140 root 1.9 if (!op->other_arch)
1141     {
1142 root 1.28 LOG (llevInfo, "Duplicator with no other_arch! %d %d %s\n", op->x, op->y, op->map ? &op->map->path : "nullmap");
1143 root 1.9 return;
1144 elmex 1.1 }
1145    
1146 root 1.9 if (op->above == NULL)
1147     return;
1148 root 1.37
1149     for (tmp = op->above; tmp; tmp = tmp->above)
1150 root 1.9 {
1151 root 1.37 if (op->other_arch->name == tmp->arch->name)
1152 root 1.9 {
1153     if (op->level <= 0)
1154 root 1.17 tmp->destroy ();
1155 root 1.9 else
1156     {
1157     uint64 new_nrof = (uint64) tmp->nrof * op->level;
1158    
1159     if (new_nrof >= 1UL << 31)
1160     new_nrof = 1UL << 31;
1161 root 1.17
1162 root 1.9 tmp->nrof = new_nrof;
1163 root 1.6 }
1164 root 1.17
1165 root 1.9 break;
1166 root 1.6 }
1167 elmex 1.1 }
1168     }
1169    
1170     /* move_creator (by peterm)
1171     * it has the creator object create it's other_arch right on top of it.
1172     * connected: what will trigger it
1173     * hp: how many times it may create before stopping
1174     * lifesave: if set, it'll never disappear but will go on creating
1175     * everytime it's triggered
1176     * other_arch: the object to create
1177     * Note this can create large objects, however, in that case, it
1178     * has to make sure that there is in fact space for the object.
1179     * It should really do this for small objects also, but there is
1180     * more concern with large objects, most notably a part being placed
1181     * outside of the map which would cause the server to crash
1182     */
1183    
1184 root 1.9 void
1185     move_creator (object *creator)
1186     {
1187     object *new_ob;
1188 elmex 1.1
1189 root 1.9 if (!QUERY_FLAG (creator, FLAG_LIFESAVE) && --creator->stats.hp < 0)
1190     {
1191     creator->stats.hp = -1;
1192     return;
1193 elmex 1.1 }
1194    
1195 root 1.9 if (creator->inv != NULL)
1196     {
1197     object *ob;
1198     int i;
1199     object *ob_to_copy;
1200    
1201     /* select random object from inventory to copy */
1202     ob_to_copy = creator->inv;
1203     for (ob = creator->inv->below, i = 1; ob != NULL; ob = ob->below, i++)
1204     {
1205     if (rndm (0, i) == 0)
1206     {
1207     ob_to_copy = ob;
1208     }
1209     }
1210     new_ob = object_create_clone (ob_to_copy);
1211     CLEAR_FLAG (new_ob, FLAG_IS_A_TEMPLATE);
1212     unflag_inv (new_ob, FLAG_IS_A_TEMPLATE);
1213     }
1214     else
1215     {
1216     if (creator->other_arch == NULL)
1217     {
1218 root 1.28 LOG (llevError, "move_creator: Creator doesn't have other arch set: %s (%s, %d, %d)\n",
1219     &creator->name, &creator->map->path, creator->x, creator->y);
1220 root 1.9 return;
1221 root 1.6 }
1222 elmex 1.1
1223 root 1.9 new_ob = object_create_arch (creator->other_arch);
1224     fix_generated_item (new_ob, creator, 0, 0, GT_MINIMAL);
1225 elmex 1.1 }
1226    
1227 root 1.9 /* Make sure this multipart object fits */
1228     if (new_ob->arch->more && ob_blocked (new_ob, creator->map, creator->x, creator->y))
1229     {
1230 root 1.17 new_ob->destroy ();
1231 root 1.9 return;
1232 elmex 1.1 }
1233    
1234 root 1.9 insert_ob_in_map_at (new_ob, creator->map, creator, 0, creator->x, creator->y);
1235     if (QUERY_FLAG (new_ob, FLAG_FREED))
1236     return;
1237 elmex 1.1
1238 root 1.9 if (creator->slaying)
1239     {
1240     new_ob->name = new_ob->title = creator->slaying;
1241 elmex 1.1 }
1242     }
1243    
1244     /* move_marker --peterm@soda.csua.berkeley.edu
1245     when moved, a marker will search for a player sitting above
1246     it, and insert an invisible, weightless force into him
1247     with a specific code as the slaying field.
1248     At that time, it writes the contents of its own message
1249     field to the player. The marker will decrement hp to
1250     0 and then delete itself every time it grants a mark.
1251     unless hp was zero to start with, in which case it is infinite.*/
1252 root 1.9 void
1253     move_marker (object *op)
1254     {
1255 root 1.22 if (object *tmp = op->ms ().player ())
1256     {
1257     object *tmp2;
1258 root 1.9
1259 root 1.22 /* remove an old force with a slaying field == op->name */
1260     for (tmp2 = tmp->inv; tmp2; tmp2 = tmp2->below)
1261 root 1.36 if (tmp2->type == FORCE && tmp2->slaying && tmp2->slaying == op->name)
1262 root 1.22 {
1263     tmp2->destroy ();
1264     break;
1265     }
1266 root 1.9
1267 root 1.22 /* cycle through his inventory to look for the MARK we want to
1268     * place
1269     */
1270     for (tmp2 = tmp->inv; tmp2; tmp2 = tmp2->below)
1271 root 1.36 if (tmp2->type == FORCE && tmp2->slaying && tmp2->slaying == op->slaying)
1272 root 1.22 break;
1273 root 1.9
1274 root 1.22 /* if we didn't find our own MARK */
1275 root 1.36 if (!tmp2)
1276 root 1.22 {
1277     object *force = get_archetype (FORCE_NAME);
1278 root 1.9
1279 root 1.22 if (op->stats.food)
1280 root 1.9 {
1281 root 1.26 force->set_speed (0.01);
1282 root 1.22 force->speed_left = -op->stats.food;
1283 root 1.9 }
1284 root 1.26 else
1285     force->set_speed (0);
1286    
1287 root 1.22 /* put in the lock code */
1288     force->slaying = op->slaying;
1289    
1290     if (op->lore)
1291     force->lore = op->lore;
1292    
1293     insert_ob_in_ob (force, tmp);
1294     if (op->msg)
1295     new_draw_info (NDI_UNIQUE | NDI_NAVY, 0, tmp, op->msg);
1296 root 1.9
1297 root 1.22 if (op->stats.hp > 0)
1298 root 1.9 {
1299 root 1.22 op->stats.hp--;
1300     if (op->stats.hp == 0)
1301 root 1.9 {
1302 root 1.22 /* marker expires--granted mark number limit */
1303     op->destroy ();
1304     return;
1305 root 1.6 }
1306 root 1.22 }
1307     }
1308     }
1309 root 1.9 }
1310    
1311     int
1312     process_object (object *op)
1313     {
1314     if (QUERY_FLAG (op, FLAG_IS_A_TEMPLATE))
1315     return 0;
1316    
1317     if (INVOKE_OBJECT (TICK, op))
1318     return 0;
1319    
1320     if (QUERY_FLAG (op, FLAG_MONSTER))
1321     if (move_monster (op) || QUERY_FLAG (op, FLAG_FREED))
1322     return 1;
1323    
1324     if (QUERY_FLAG (op, FLAG_ANIMATE) && op->anim_speed == 0)
1325     {
1326     if (op->type == PLAYER)
1327     animate_object (op, op->facing);
1328     else
1329     animate_object (op, op->direction);
1330    
1331     if (QUERY_FLAG (op, FLAG_SEE_ANYWHERE))
1332     make_sure_seen (op);
1333     }
1334 root 1.10
1335 root 1.9 if (QUERY_FLAG (op, FLAG_CHANGING) && !op->state)
1336     {
1337     change_object (op);
1338     return 1;
1339     }
1340 root 1.10
1341 root 1.9 if (QUERY_FLAG (op, FLAG_GENERATOR) && !QUERY_FLAG (op, FLAG_FRIENDLY))
1342     generate_monster (op);
1343    
1344     if (QUERY_FLAG (op, FLAG_IS_USED_UP) && --op->stats.food <= 0)
1345     {
1346     if (QUERY_FLAG (op, FLAG_APPLIED))
1347     remove_force (op);
1348     else
1349     {
1350     /* IF necessary, delete the item from the players inventory */
1351 root 1.20 object *pl = op->in_player ();
1352 root 1.9
1353     if (pl)
1354     esrv_del_item (pl->contr, op->count);
1355 root 1.10
1356 root 1.16 op->remove ();
1357 root 1.10
1358 root 1.9 if (QUERY_FLAG (op, FLAG_SEE_ANYWHERE))
1359     make_sure_not_seen (op);
1360 root 1.10
1361 root 1.17 op->destroy ();
1362 root 1.6 }
1363 root 1.10
1364 root 1.9 return 1;
1365 elmex 1.1 }
1366 root 1.11
1367 root 1.9 switch (op->type)
1368     {
1369 root 1.10 case SPELL_EFFECT:
1370     move_spell_effect (op);
1371     return 1;
1372    
1373     case ROD:
1374     case HORN:
1375     regenerate_rod (op);
1376     return 1;
1377    
1378     case FORCE:
1379     case POTION_EFFECT:
1380     remove_force (op);
1381     return 1;
1382 elmex 1.1
1383 root 1.10 case BLINDNESS:
1384     remove_blindness (op);
1385     return 0;
1386    
1387     case POISONING:
1388     poison_more (op);
1389     return 0;
1390    
1391     case DISEASE:
1392     move_disease (op);
1393     return 0;
1394    
1395     case SYMPTOM:
1396     move_symptom (op);
1397     return 0;
1398    
1399     case THROWN_OBJ:
1400     case ARROW:
1401     move_arrow (op);
1402     return 0;
1403    
1404     case DOOR:
1405     remove_door (op);
1406     return 0;
1407    
1408     case LOCKED_DOOR:
1409     remove_door2 (op);
1410     return 0;
1411    
1412     case TELEPORTER:
1413     move_teleporter (op);
1414     return 0;
1415    
1416     case GOLEM:
1417     move_golem (op);
1418     return 0;
1419    
1420     case EARTHWALL:
1421     hit_player (op, 2, op, AT_PHYSICAL, 1);
1422     return 0;
1423    
1424     case FIREWALL:
1425     move_firewall (op);
1426     if (op->stats.maxsp)
1427     animate_turning (op);
1428     return 0;
1429    
1430     case MOOD_FLOOR:
1431     do_mood_floor (op);
1432     return 0;
1433    
1434     case GATE:
1435     move_gate (op);
1436     return 0;
1437    
1438     case TIMED_GATE:
1439     move_timed_gate (op);
1440     return 0;
1441    
1442     case TRIGGER:
1443     case TRIGGER_BUTTON:
1444     case TRIGGER_PEDESTAL:
1445     case TRIGGER_ALTAR:
1446     animate_trigger (op);
1447     return 0;
1448    
1449     case DETECTOR:
1450     move_detector (op);
1451    
1452     case DIRECTOR:
1453     if (op->stats.maxsp)
1454     animate_turning (op);
1455     return 0;
1456    
1457     case HOLE:
1458     move_hole (op);
1459     return 0;
1460    
1461     case DEEP_SWAMP:
1462     move_deep_swamp (op);
1463     return 0;
1464    
1465     case RUNE:
1466     case TRAP:
1467     move_rune (op);
1468     return 0;
1469    
1470     case PLAYERMOVER:
1471     move_player_mover (op);
1472     return 0;
1473    
1474     case CREATOR:
1475     move_creator (op);
1476     return 0;
1477    
1478     case MARKER:
1479     move_marker (op);
1480     return 0;
1481    
1482     case PLAYER_CHANGER:
1483     move_player_changer (op);
1484     return 0;
1485    
1486     case PEACEMAKER:
1487     move_peacemaker (op);
1488     return 0;
1489 elmex 1.1 }
1490    
1491 root 1.9 return 0;
1492 elmex 1.1 }