ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.67
Committed: Tue Sep 4 08:42:58 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_2
Changes since 1.66: +21 -24 lines
Log Message:
- clean up stuff
- get rid of map_load lock
- improve change_object

File Contents

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