ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.72
Committed: Thu Nov 8 19:43:29 2007 UTC (16 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_4, rel-2_5, rel-2_32, rel-2_43, rel-2_42, rel-2_41
Changes since 1.71: +4 -4 lines
Log Message:
update copyrights and other minor stuff to deliantra

File Contents

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