ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.45
Committed: Sun Apr 22 13:06:45 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.44: +36 -49 lines
Log Message:
combine all the generator functions that became really small now into a single one

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