ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.61
Committed: Thu Jul 12 19:42:14 2007 UTC (16 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.60: +0 -1 lines
Log Message:
*** empty log message ***

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    
102     if (QUERY_FLAG (gen, FLAG_CONTENT_ON_GEN))
103     {
104 root 1.58 // either copy one item from the inventory...
105 root 1.45 if (!gen->inv)
106     return;
107    
108     // first select one item from the inventory
109     int index = 0;
110     for (object *tmp = gen->inv; tmp; tmp = tmp->below)
111     if (!rndm (++index))
112     op = tmp;
113    
114     op = object_create_clone (op);
115    
116     CLEAR_FLAG (op, FLAG_IS_A_TEMPLATE);
117     unflag_inv (op, FLAG_IS_A_TEMPLATE);
118     }
119 root 1.58 else if (gen->other_arch)
120 root 1.45 {
121     // ...or use other_arch
122 root 1.58 op = arch_to_object (gen->other_arch);
123 root 1.45 }
124 root 1.58 else
125     return;
126 root 1.45
127 root 1.44 op->expand_tail ();
128 root 1.9
129 root 1.44 int i = find_free_spot (op, gen->map, gen->x, gen->y, 1, 9);
130     if (i >= 0)
131 root 1.9 {
132 root 1.44 if (insert_ob_in_map_at (op, gen->map, gen, 0, gen->x + freearr_x[i], gen->y + freearr_y[i]))
133     {
134     if (rndm (0, 9))
135     generate_artifact (op, gen->map->difficulty);
136 root 1.43
137 root 1.44 if (op->has_random_items ())
138     create_treasure (op->randomitems, op, GT_APPLY, gen->map->difficulty);
139 root 1.43
140 root 1.44 return;
141     }
142 elmex 1.1 }
143 root 1.43
144 root 1.44 op->destroy ();
145 root 1.9 }
146    
147     void
148     remove_force (object *op)
149     {
150     if (--op->duration > 0)
151     return;
152 elmex 1.1
153 root 1.25 if (op->env)
154     switch (op->subtype)
155     {
156     case FORCE_CONFUSION:
157     CLEAR_FLAG (op->env, FLAG_CONFUSED);
158     new_draw_info (NDI_UNIQUE, 0, op->env, "You regain your senses.\n");
159 root 1.6
160 root 1.25 default:
161     CLEAR_FLAG (op, FLAG_APPLIED);
162     change_abil (op->env, op);
163     op->env->update_stats ();
164     }
165 root 1.17
166     op->destroy ();
167 elmex 1.1 }
168    
169 root 1.9 void
170     remove_blindness (object *op)
171     {
172     if (--op->stats.food > 0)
173 elmex 1.1 return;
174 root 1.17
175 root 1.9 CLEAR_FLAG (op, FLAG_APPLIED);
176 root 1.17
177 root 1.27 if (op->env)
178 root 1.9 {
179     change_abil (op->env, op);
180 root 1.23 op->env->update_stats ();
181 root 1.9 }
182 root 1.17
183     op->destroy ();
184 elmex 1.1 }
185    
186 root 1.9 void
187     poison_more (object *op)
188     {
189     if (op->env == NULL || !QUERY_FLAG (op->env, FLAG_ALIVE) || op->env->stats.hp < 0)
190     {
191 root 1.17 op->destroy ();
192 root 1.9 return;
193     }
194 root 1.17
195 root 1.9 if (op->stats.food == 1)
196     {
197 root 1.38 /* need to unapply the object before update_stats is called, else fix_player
198 root 1.9 * will not do anything.
199     */
200     if (op->env->type == PLAYER)
201     {
202     CLEAR_FLAG (op, FLAG_APPLIED);
203 root 1.23 op->env->update_stats ();
204 root 1.9 new_draw_info (NDI_UNIQUE, 0, op->env, "You feel much better now.");
205     }
206 root 1.17
207     op->destroy ();
208 root 1.9 return;
209     }
210 root 1.17
211 root 1.9 if (op->env->type == PLAYER)
212     {
213     op->env->stats.food--;
214     new_draw_info (NDI_UNIQUE, 0, op->env, "You feel very sick...");
215 elmex 1.1 }
216 elmex 1.32
217     hit_player (op->env, op->stats.dam, op, AT_INTERNAL, 1);
218 elmex 1.1 }
219    
220    
221 root 1.9 void
222     move_gate (object *op)
223 root 1.46 { /* 1 = going down, 0 = going up */
224 root 1.9 object *tmp;
225    
226     if (op->stats.wc < 0 || (int) op->stats.wc >= NUM_ANIMATIONS (op))
227     {
228     LOG (llevError, "Gate error: animation was %d, max=%d\n", op->stats.wc, NUM_ANIMATIONS (op));
229     op->stats.wc = 0;
230     }
231    
232     /* We're going down */
233     if (op->value)
234     {
235     if (--op->stats.wc <= 0)
236     { /* Reached bottom, let's stop */
237     op->stats.wc = 0;
238 root 1.56 if (op->arch->speed)
239 root 1.9 op->value = 0;
240     else
241 root 1.26 op->set_speed (0);
242 root 1.6 }
243 root 1.26
244 root 1.9 if ((int) op->stats.wc < (NUM_ANIMATIONS (op) / 2 + 1))
245     {
246     op->move_block = 0;
247     CLEAR_FLAG (op, FLAG_BLOCKSVIEW);
248     update_all_los (op->map, op->x, op->y);
249     }
250 root 1.26
251 root 1.9 SET_ANIMATION (op, op->stats.wc);
252     update_object (op, UP_OBJ_CHANGE);
253     return;
254 elmex 1.1 }
255    
256 root 1.9 /* We're going up */
257 elmex 1.1
258 root 1.9 /* First, lets see if we are already at the top */
259     if ((unsigned char) op->stats.wc == (NUM_ANIMATIONS (op) - 1))
260     {
261 elmex 1.1
262 root 1.9 /* Check to make sure that only non pickable and non rollable
263     * objects are above the gate. If so, we finish closing the gate,
264     * otherwise, we fall through to the code below which should lower
265     * the gate slightly.
266     */
267    
268     for (tmp = op->above; tmp != NULL; tmp = tmp->above)
269     if (!QUERY_FLAG (tmp, FLAG_NO_PICK) || QUERY_FLAG (tmp, FLAG_CAN_ROLL) || QUERY_FLAG (tmp, FLAG_ALIVE))
270     break;
271 root 1.6
272 root 1.9 if (tmp == NULL)
273     {
274 root 1.56 if (op->arch->speed)
275 root 1.9 op->value = 1;
276     else
277 root 1.26 op->set_speed (0);
278    
279 root 1.9 return;
280     }
281     }
282    
283     if (op->stats.food)
284     { /* The gate is going temporarily down */
285     if (--op->stats.wc <= 0)
286     { /* Gone all the way down? */
287     op->stats.food = 0; /* Then let's try again */
288     op->stats.wc = 0;
289 root 1.6 }
290 elmex 1.1 }
291 root 1.9 else
292     { /* The gate is still going up */
293     op->stats.wc++;
294 elmex 1.1
295 root 1.9 if ((int) op->stats.wc >= (NUM_ANIMATIONS (op)))
296     op->stats.wc = (signed char) NUM_ANIMATIONS (op) - 1;
297    
298     /* If there is something on top of the gate, we try to roll it off.
299     * If a player/monster, we don't roll, we just hit them with damage
300     */
301     if ((int) op->stats.wc >= NUM_ANIMATIONS (op) / 2)
302     {
303     /* Halfway or further, check blocks */
304     /* First, get the top object on the square. */
305 root 1.46 for (tmp = op->above; tmp && tmp->above; tmp = tmp->above)
306     ;
307 root 1.9
308 root 1.46 if (tmp)
309 root 1.9 {
310     if (QUERY_FLAG (tmp, FLAG_ALIVE))
311     {
312 root 1.46 hit_player (tmp, random_roll (0, op->stats.dam, tmp, PREFER_LOW), op, AT_PHYSICAL, 1);
313    
314 root 1.9 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 root 1.56 if (!op->arch->stats.ac)
351 root 1.9 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 root 1.47 op->move_on = 0;
578 root 1.9 op->move_type = 0;
579 root 1.47 op->skill = 0; // really?
580    
581     // restore original wc, dam, attacktype and slaying
582     op->stats.wc = op->stats.sp;
583     op->stats.dam = op->stats.hp;
584 root 1.9 op->attacktype = op->stats.grace;
585    
586 root 1.47 if (op->spellarg)
587 root 1.9 {
588     op->slaying = op->spellarg;
589     free (op->spellarg);
590 root 1.47 op->spellarg = 0;
591 root 1.9 }
592     else
593 root 1.47 op->slaying = 0;
594 root 1.9
595 root 1.18 /* Reset these to zero, so that object::can_merge will work properly */
596 root 1.9 op->spellarg = NULL;
597     op->stats.sp = 0;
598     op->stats.hp = 0;
599     op->stats.grace = 0;
600     op->level = 0;
601 root 1.56 op->face = op->arch->face;
602 root 1.9 op->owner = NULL; /* So that stopped arrows will be saved */
603 root 1.40 update_object (op, UP_OBJ_CHANGE);
604 root 1.9 return op;
605 elmex 1.1 }
606    
607     /* stop_arrow() - what to do when a non-living flying object
608     * has to stop. Sept 96 - I added in thrown object code in
609     * here too. -b.t.
610     *
611     * Returns a pointer to the stopped object (which will have been removed
612     * from maps or inventories), or NULL if was destroyed.
613     */
614 root 1.9 static void
615     stop_arrow (object *op)
616 elmex 1.1 {
617 root 1.9 if (INVOKE_OBJECT (STOP, op))
618     return;
619    
620     if (op->inv)
621     {
622     object *payload = op->inv;
623 root 1.4
624 root 1.16 payload->remove ();
625 root 1.18 payload->owner = 0;
626 root 1.9 insert_ob_in_map (payload, op->map, payload, 0);
627 root 1.17 op->destroy ();
628 root 1.9 }
629     else
630     {
631     op = fix_stopped_arrow (op);
632 root 1.47
633 root 1.9 if (op)
634 root 1.47 merge_ob (op, 0);
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 root 1.57 for (tmp = op->above; tmp; tmp = tmp->above)
914 root 1.9 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     /* This object will teleport someone to a different map
958     and will also apply changes to the player from its inventory.
959     This was invented for giving classes, but there's no reason it
960     can't be generalized.
961     */
962 root 1.9 void
963     move_player_changer (object *op)
964     {
965     object *player;
966     object *walk;
967    
968     if (!op->above || !EXIT_PATH (op))
969     return;
970    
971     /* This isn't all that great - means that the player_mover
972     * needs to be on top.
973     */
974     if (op->above->type == PLAYER)
975     {
976     if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (player)))
977 root 1.34 return;
978    
979 root 1.9 player = op->above;
980    
981 root 1.35 for (walk = op->inv; walk; walk = walk->below)
982 root 1.9 apply_changes_to_player (player, walk);
983    
984 root 1.23 player->update_stats ();
985 root 1.9
986     esrv_send_inventory (op->above, op->above);
987     esrv_update_item (UPD_FACE, op->above, op->above);
988    
989     /* update players death & WoR home-position */
990 root 1.35 if (*EXIT_PATH (op) == '/')
991 root 1.9 {
992 root 1.30 player->contr->savebed_map = EXIT_PATH (op);
993     player->contr->bed_x = EXIT_X (op);
994     player->contr->bed_y = EXIT_Y (op);
995 root 1.9 }
996     else
997     LOG (llevDebug, "WARNING: destination '%s' in player_changer must be an absolute path!\n", &EXIT_PATH (op));
998    
999 root 1.28 op->above->enter_exit (op);
1000 elmex 1.1 }
1001     }
1002    
1003     /* firewalls fire other spells.
1004     * The direction of the wall is stored in op->stats.sp.
1005     * walls can have hp, so they can be torn down.
1006     */
1007 root 1.9 void
1008     move_firewall (object *op)
1009     {
1010     object *spell;
1011 elmex 1.1
1012 root 1.9 if (!op->map)
1013     return; /* dm has created a firewall in his inventory */
1014 elmex 1.1
1015 root 1.9 spell = op->inv;
1016 root 1.24
1017 root 1.9 if (!spell || spell->type != SPELL)
1018 root 1.56 spell = op->other_arch;
1019 root 1.24
1020 root 1.9 if (!spell)
1021     {
1022 root 1.28 LOG (llevError, "move_firewall: no spell specified (%s, %s, %d, %d)\n", &op->name, &op->map->name, op->x, op->y);
1023 root 1.9 return;
1024 elmex 1.1 }
1025    
1026 root 1.9 cast_spell (op, op, op->stats.sp ? op->stats.sp : rndm (1, 8), spell, NULL);
1027 elmex 1.1 }
1028    
1029     /* move_player_mover: this function takes a "player mover" as an
1030     * argument, and performs the function of a player mover, which is:
1031     *
1032     * a player mover finds any players that are sitting on it. It
1033     * moves them in the op->stats.sp direction. speed is how often it'll move.
1034     * If attacktype is nonzero it will paralyze the player. If lifesave is set,
1035     * it'll dissapear after hp+1 moves. If hp is set and attacktype is set,
1036     * it'll paralyze the victim for hp*his speed/op->speed
1037     */
1038 root 1.9 void
1039     move_player_mover (object *op)
1040     {
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.50 for (object *victim = op->ms ().bot; victim; 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.50 for (object *nextmover = m->at (nx, ny).bot; nextmover; nextmover = nextmover->above)
1077 root 1.9 {
1078     if (nextmover->type == PLAYERMOVER)
1079 root 1.50 nextmover->speed_left = -.99f;
1080    
1081 root 1.9 if (QUERY_FLAG (nextmover, FLAG_ALIVE))
1082 root 1.50 op->speed_left = -1.1f; /* wait until the next thing gets out of the way */
1083 root 1.6 }
1084    
1085 root 1.9 if (victim->type == PLAYER)
1086     {
1087     /* only level >=1 movers move people */
1088     if (op->level)
1089     {
1090     /* Following is a bit of hack. We need to make sure it
1091     * is cleared, otherwise the player will get stuck in
1092     * place. This can happen if the player used a spell to
1093     * get to this space.
1094     */
1095     victim->contr->fire_on = 0;
1096 root 1.52 victim->speed_left = 1.f;
1097 root 1.9 move_player (victim, dir);
1098 root 1.6 }
1099 root 1.9 else
1100     return;
1101 root 1.6 }
1102 root 1.9 else
1103     move_object (victim, dir);
1104 root 1.6
1105 root 1.9 if (!op->stats.maxsp && op->attacktype)
1106     op->stats.maxsp = 2;
1107 root 1.6
1108 root 1.9 if (op->attacktype)
1109     { /* flag to paralyze the player */
1110 root 1.50 victim->speed_left = max (-5.f, -FABS (op->stats.maxsp * victim->speed / op->speed));
1111 root 1.6 }
1112     }
1113 elmex 1.1 }
1114     }
1115    
1116     /*
1117     * Will duplicate a specified object placed on top of it.
1118     * connected: what will trigger it.
1119     * level: multiplier. 0 to destroy.
1120     * other_arch: the object to look for and duplicate.
1121     */
1122    
1123 root 1.9 void
1124     move_duplicator (object *op)
1125     {
1126     object *tmp;
1127 elmex 1.1
1128 root 1.9 if (!op->other_arch)
1129     {
1130 root 1.28 LOG (llevInfo, "Duplicator with no other_arch! %d %d %s\n", op->x, op->y, op->map ? &op->map->path : "nullmap");
1131 root 1.9 return;
1132 elmex 1.1 }
1133    
1134 root 1.9 if (op->above == NULL)
1135     return;
1136 root 1.37
1137     for (tmp = op->above; tmp; tmp = tmp->above)
1138 root 1.9 {
1139 root 1.55 if (op->other_arch->archname == tmp->arch->archname)
1140 root 1.9 {
1141     if (op->level <= 0)
1142 root 1.17 tmp->destroy ();
1143 root 1.9 else
1144     {
1145     uint64 new_nrof = (uint64) tmp->nrof * op->level;
1146    
1147     if (new_nrof >= 1UL << 31)
1148     new_nrof = 1UL << 31;
1149 root 1.17
1150 root 1.9 tmp->nrof = new_nrof;
1151 root 1.6 }
1152 root 1.17
1153 root 1.9 break;
1154 root 1.6 }
1155 elmex 1.1 }
1156     }
1157    
1158     /* move_creator (by peterm)
1159     * it has the creator object create it's other_arch right on top of it.
1160     * connected: what will trigger it
1161     * hp: how many times it may create before stopping
1162     * lifesave: if set, it'll never disappear but will go on creating
1163     * everytime it's triggered
1164     * other_arch: the object to create
1165     * Note this can create large objects, however, in that case, it
1166     * has to make sure that there is in fact space for the object.
1167     * It should really do this for small objects also, but there is
1168     * more concern with large objects, most notably a part being placed
1169     * outside of the map which would cause the server to crash
1170     */
1171    
1172 root 1.9 void
1173     move_creator (object *creator)
1174     {
1175     object *new_ob;
1176 elmex 1.1
1177 root 1.9 if (!QUERY_FLAG (creator, FLAG_LIFESAVE) && --creator->stats.hp < 0)
1178     {
1179     creator->stats.hp = -1;
1180     return;
1181 elmex 1.1 }
1182    
1183 root 1.9 if (creator->inv != NULL)
1184     {
1185     object *ob;
1186     int i;
1187     object *ob_to_copy;
1188    
1189     /* select random object from inventory to copy */
1190     ob_to_copy = creator->inv;
1191     for (ob = creator->inv->below, i = 1; ob != NULL; ob = ob->below, i++)
1192     {
1193     if (rndm (0, i) == 0)
1194     {
1195     ob_to_copy = ob;
1196     }
1197     }
1198     new_ob = object_create_clone (ob_to_copy);
1199     CLEAR_FLAG (new_ob, FLAG_IS_A_TEMPLATE);
1200     unflag_inv (new_ob, FLAG_IS_A_TEMPLATE);
1201     }
1202     else
1203     {
1204     if (creator->other_arch == NULL)
1205     {
1206 root 1.28 LOG (llevError, "move_creator: Creator doesn't have other arch set: %s (%s, %d, %d)\n",
1207     &creator->name, &creator->map->path, creator->x, creator->y);
1208 root 1.9 return;
1209 root 1.6 }
1210 elmex 1.1
1211 root 1.9 new_ob = object_create_arch (creator->other_arch);
1212     fix_generated_item (new_ob, creator, 0, 0, GT_MINIMAL);
1213 elmex 1.1 }
1214    
1215 root 1.9 /* Make sure this multipart object fits */
1216     if (new_ob->arch->more && ob_blocked (new_ob, creator->map, creator->x, creator->y))
1217     {
1218 root 1.17 new_ob->destroy ();
1219 root 1.9 return;
1220 elmex 1.1 }
1221    
1222 root 1.9 insert_ob_in_map_at (new_ob, creator->map, creator, 0, creator->x, creator->y);
1223     if (QUERY_FLAG (new_ob, FLAG_FREED))
1224     return;
1225 elmex 1.1
1226 root 1.9 if (creator->slaying)
1227     {
1228     new_ob->name = new_ob->title = creator->slaying;
1229 elmex 1.1 }
1230     }
1231    
1232     /* move_marker --peterm@soda.csua.berkeley.edu
1233     when moved, a marker will search for a player sitting above
1234     it, and insert an invisible, weightless force into him
1235     with a specific code as the slaying field.
1236     At that time, it writes the contents of its own message
1237     field to the player. The marker will decrement hp to
1238     0 and then delete itself every time it grants a mark.
1239     unless hp was zero to start with, in which case it is infinite.*/
1240 root 1.9 void
1241     move_marker (object *op)
1242     {
1243 root 1.22 if (object *tmp = op->ms ().player ())
1244     {
1245     /* remove an old force with a slaying field == op->name */
1246 root 1.60 if (object *force = tmp->force_find (op->name))
1247     force->destroy ();
1248 root 1.9
1249 root 1.60 if (!tmp->force_find (op->slaying))
1250 root 1.22 {
1251 root 1.60 tmp->force_add (op->slaying, op->stats.food);
1252 root 1.26
1253 root 1.22 if (op->msg)
1254     new_draw_info (NDI_UNIQUE | NDI_NAVY, 0, tmp, op->msg);
1255 root 1.9
1256 root 1.22 if (op->stats.hp > 0)
1257 root 1.9 {
1258 root 1.22 op->stats.hp--;
1259 root 1.60
1260 root 1.22 if (op->stats.hp == 0)
1261 root 1.9 {
1262 root 1.22 /* marker expires--granted mark number limit */
1263     op->destroy ();
1264     return;
1265 root 1.6 }
1266 root 1.22 }
1267     }
1268     }
1269 root 1.9 }
1270    
1271 root 1.51 void
1272 root 1.9 process_object (object *op)
1273     {
1274 root 1.54 if (expect_false (QUERY_FLAG (op, FLAG_IS_A_TEMPLATE)))
1275 root 1.51 return;
1276 root 1.9
1277 root 1.54 if (expect_false (INVOKE_OBJECT (TICK, op)))
1278 root 1.51 return;
1279 root 1.9
1280     if (QUERY_FLAG (op, FLAG_MONSTER))
1281     if (move_monster (op) || QUERY_FLAG (op, FLAG_FREED))
1282 root 1.51 return;
1283 root 1.9
1284     if (QUERY_FLAG (op, FLAG_ANIMATE) && op->anim_speed == 0)
1285     {
1286 root 1.48 animate_object (op, op->contr ? op->facing : op->direction);
1287 root 1.9
1288     if (QUERY_FLAG (op, FLAG_SEE_ANYWHERE))
1289     make_sure_seen (op);
1290     }
1291 root 1.10
1292 root 1.54 if (expect_false (
1293     op->flag [FLAG_GENERATOR]
1294     || op->flag [FLAG_CHANGING]
1295     || op->flag [FLAG_IS_USED_UP]
1296     ))
1297 root 1.9 {
1298 root 1.51 if (QUERY_FLAG (op, FLAG_CHANGING) && !op->state)
1299     {
1300     change_object (op);
1301     return;
1302     }
1303 root 1.10
1304 root 1.51 if (QUERY_FLAG (op, FLAG_GENERATOR) && !QUERY_FLAG (op, FLAG_FRIENDLY))
1305     generate_monster (op);
1306 root 1.9
1307 root 1.51 if (QUERY_FLAG (op, FLAG_IS_USED_UP) && --op->stats.food <= 0)
1308 root 1.9 {
1309 root 1.51 if (QUERY_FLAG (op, FLAG_APPLIED))
1310     remove_force (op);
1311     else
1312     {
1313     /* If necessary, delete the item from the players inventory */
1314     object *pl = op->in_player ();
1315 root 1.9
1316 root 1.51 if (pl)
1317     esrv_del_item (pl->contr, op->count);
1318 root 1.10
1319 root 1.51 op->remove ();
1320 root 1.10
1321 root 1.51 if (QUERY_FLAG (op, FLAG_SEE_ANYWHERE))
1322     make_sure_not_seen (op);
1323 root 1.10
1324 root 1.51 op->destroy ();
1325     }
1326    
1327     return;
1328 root 1.6 }
1329 elmex 1.1 }
1330 root 1.11
1331 root 1.9 switch (op->type)
1332     {
1333 root 1.10 case SPELL_EFFECT:
1334     move_spell_effect (op);
1335 root 1.51 break;
1336 root 1.10
1337     case ROD:
1338     case HORN:
1339     regenerate_rod (op);
1340 root 1.51 break;
1341 root 1.10
1342     case FORCE:
1343     case POTION_EFFECT:
1344     remove_force (op);
1345 root 1.51 break;
1346 elmex 1.1
1347 root 1.10 case BLINDNESS:
1348     remove_blindness (op);
1349 root 1.51 break;
1350 root 1.10
1351     case POISONING:
1352     poison_more (op);
1353 root 1.51 break;
1354 root 1.10
1355     case DISEASE:
1356     move_disease (op);
1357 root 1.51 break;
1358 root 1.10
1359     case SYMPTOM:
1360     move_symptom (op);
1361 root 1.51 break;
1362 root 1.10
1363     case THROWN_OBJ:
1364     case ARROW:
1365     move_arrow (op);
1366 root 1.51 break;
1367 root 1.10
1368     case DOOR:
1369     remove_door (op);
1370 root 1.51 break;
1371 root 1.10
1372     case LOCKED_DOOR:
1373     remove_door2 (op);
1374 root 1.51 break;
1375 root 1.10
1376     case TELEPORTER:
1377     move_teleporter (op);
1378 root 1.51 break;
1379 root 1.10
1380     case GOLEM:
1381     move_golem (op);
1382 root 1.51 break;
1383 root 1.10
1384     case EARTHWALL:
1385     hit_player (op, 2, op, AT_PHYSICAL, 1);
1386 root 1.51 break;
1387 root 1.10
1388     case FIREWALL:
1389     move_firewall (op);
1390     if (op->stats.maxsp)
1391     animate_turning (op);
1392 root 1.51 break;
1393 root 1.10
1394     case MOOD_FLOOR:
1395     do_mood_floor (op);
1396 root 1.51 break;
1397 root 1.10
1398     case GATE:
1399     move_gate (op);
1400 root 1.51 break;
1401 root 1.10
1402     case TIMED_GATE:
1403     move_timed_gate (op);
1404 root 1.51 break;
1405 root 1.10
1406     case TRIGGER:
1407     case TRIGGER_BUTTON:
1408     case TRIGGER_PEDESTAL:
1409     case TRIGGER_ALTAR:
1410     animate_trigger (op);
1411 root 1.51 break;
1412 root 1.10
1413     case DETECTOR:
1414     move_detector (op);
1415    
1416     case DIRECTOR:
1417     if (op->stats.maxsp)
1418     animate_turning (op);
1419 root 1.51 break;
1420 root 1.10
1421     case HOLE:
1422     move_hole (op);
1423 root 1.51 break;
1424 root 1.10
1425     case DEEP_SWAMP:
1426     move_deep_swamp (op);
1427 root 1.51 break;
1428 root 1.10
1429     case RUNE:
1430     case TRAP:
1431     move_rune (op);
1432 root 1.51 break;
1433 root 1.10
1434     case PLAYERMOVER:
1435     move_player_mover (op);
1436 root 1.51 break;
1437 root 1.10
1438     case CREATOR:
1439     move_creator (op);
1440 root 1.51 break;
1441 root 1.10
1442     case MARKER:
1443     move_marker (op);
1444 root 1.51 break;
1445 root 1.10
1446     case PLAYER_CHANGER:
1447     move_player_changer (op);
1448 root 1.51 break;
1449 root 1.10
1450     case PEACEMAKER:
1451     move_peacemaker (op);
1452 root 1.51 break;
1453    
1454     case PLAYER:
1455     // players have their own speed-management, so undo the --speed_left
1456     ++op->speed_left;
1457     break;
1458 elmex 1.1 }
1459     }
1460 root 1.48