ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.80
Committed: Mon Sep 29 10:20:49 2008 UTC (15 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.79: +26 -24 lines
Log Message:
do the same everywhere else

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