ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.60
Committed: Thu Jul 5 08:10:30 2007 UTC (16 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.59: +6 -33 lines
Log Message:
- unbundle marker code into force_find/force_add
- use completely different (more efficient) speed logic
- make those methods available to perl
- to avoid numerical errors use an exact fp number for MIN_ACTIVE_SPEED.

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