ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.70
Committed: Mon Oct 22 20:59:25 2007 UTC (16 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.69: +11 -6 lines
Log Message:
correctly check wether enoughbourign map spaces exist when removing doors

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 root 1.70 for (i = 1; i < SIZEOFFREE1 + 1; i += 2)
43     {
44     mapxy pos (op);
45     pos.move (i);
46     if (pos.normalise ()
47     && present (DOOR, pos.m, pos.x, pos.y))
48     {
49     tmp->set_speed (0.1f);
50     tmp->speed_left = -0.2f;
51     }
52     }
53 root 1.9
54     if (op->other_arch)
55     {
56     tmp = arch_to_object (op->other_arch);
57     tmp->x = op->x;
58     tmp->y = op->y;
59     tmp->map = op->map;
60     tmp->level = op->level;
61     insert_ob_in_map (tmp, op->map, op, 0);
62     }
63 root 1.17
64     op->destroy ();
65 elmex 1.1 }
66    
67 root 1.9 void
68     remove_door2 (object *op)
69     {
70 elmex 1.1 int i;
71     object *tmp;
72 root 1.9
73     for (i = 1; i < 9; i += 2)
74     {
75     tmp = present (LOCKED_DOOR, op->map, op->x + freearr_x[i], op->y + freearr_y[i]);
76     if (tmp && tmp->slaying == op->slaying)
77     { /* same key both doors */
78 root 1.49 tmp->set_speed (0.1f);
79     tmp->speed_left = -0.2f;
80 root 1.9 }
81     }
82 root 1.27
83 root 1.9 if (op->other_arch)
84     {
85     tmp = arch_to_object (op->other_arch);
86     tmp->x = op->x;
87     tmp->y = op->y;
88     tmp->map = op->map;
89     tmp->level = op->level;
90     insert_ob_in_map (tmp, op->map, op, 0);
91     }
92 root 1.17
93     op->destroy ();
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.45 op = object_create_clone (op);
125    
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.44 op->destroy ();
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     op->destroy ();
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     op->destroy ();
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.17 op->destroy ();
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     op->destroy ();
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     object *next, *tmp;
488    
489     if (op->value)
490     { /* We're opening */
491     if (--op->stats.wc <= 0)
492     { /* Opened, let's stop */
493     op->stats.wc = 0;
494 root 1.26 op->set_speed (0);
495 root 1.9
496     /* Hard coding this makes sense for holes I suppose */
497     op->move_on = MOVE_WALK;
498     for (tmp = op->above; tmp != NULL; tmp = next)
499     {
500     next = tmp->above;
501     move_apply (op, tmp, tmp);
502 root 1.6 }
503     }
504 root 1.26
505 root 1.9 SET_ANIMATION (op, op->stats.wc);
506     update_object (op, UP_OBJ_FACE);
507     return;
508 elmex 1.1 }
509 root 1.66
510 root 1.9 /* We're closing */
511     op->move_on = 0;
512 elmex 1.1
513 root 1.9 op->stats.wc++;
514     if ((int) op->stats.wc >= NUM_ANIMATIONS (op))
515     op->stats.wc = NUM_ANIMATIONS (op) - 1;
516 root 1.26
517 root 1.9 SET_ANIMATION (op, op->stats.wc);
518     update_object (op, UP_OBJ_FACE);
519     if ((unsigned char) op->stats.wc == (NUM_ANIMATIONS (op) - 1))
520 root 1.26 op->set_speed (0); /* closed, let's stop */
521 elmex 1.1 }
522    
523    
524     /* stop_item() returns a pointer to the stopped object. The stopped object
525     * may or may not have been removed from maps or inventories. It will not
526     * have been merged with other items.
527     *
528     * This function assumes that only items on maps need special treatment.
529     *
530     * If the object can't be stopped, or it was destroyed while trying to stop
531     * it, NULL is returned.
532     *
533     * fix_stopped_item() should be used if the stopped item should be put on
534     * the map.
535     */
536 root 1.9 object *
537     stop_item (object *op)
538 elmex 1.1 {
539 root 1.9 if (op->map == NULL)
540     return op;
541 elmex 1.1
542 root 1.9 switch (op->type)
543 elmex 1.1 {
544 root 1.10 case THROWN_OBJ:
545     {
546     object *payload = op->inv;
547 root 1.9
548 root 1.10 if (payload == NULL)
549     return NULL;
550 root 1.16 payload->remove ();
551 root 1.17 op->destroy ();
552 root 1.10 return payload;
553     }
554 elmex 1.1
555 root 1.10 case ARROW:
556 elmex 1.29 if (op->has_active_speed ())
557 root 1.10 op = fix_stopped_arrow (op);
558     return op;
559 elmex 1.1
560 root 1.10 default:
561     return op;
562 elmex 1.1 }
563     }
564    
565     /* fix_stopped_item() - put stopped item where stop_item() had found it.
566     * Inserts item into the old map, or merges it if it already is on the map.
567     *
568     * 'map' must be the value of op->map before stop_item() was called.
569     */
570 root 1.9 void
571 root 1.13 fix_stopped_item (object *op, maptile *map, object *originator)
572 elmex 1.1 {
573 root 1.9 if (map == NULL)
574     return;
575 root 1.40
576 root 1.9 if (QUERY_FLAG (op, FLAG_REMOVED))
577     insert_ob_in_map (op, map, originator, 0);
578     else if (op->type == ARROW)
579     merge_ob (op, NULL); /* only some arrows actually need this */
580 elmex 1.1 }
581    
582 root 1.9 object *
583     fix_stopped_arrow (object *op)
584     {
585     if (rndm (0, 99) < op->stats.food)
586     {
587     /* Small chance of breaking */
588 root 1.17 op->destroy ();
589 root 1.9 return NULL;
590     }
591    
592 root 1.26 op->set_speed (0);
593 root 1.9 op->direction = 0;
594 root 1.47 op->move_on = 0;
595 root 1.9 op->move_type = 0;
596 root 1.47 op->skill = 0; // really?
597    
598     // restore original wc, dam, attacktype and slaying
599     op->stats.wc = op->stats.sp;
600     op->stats.dam = op->stats.hp;
601 root 1.9 op->attacktype = op->stats.grace;
602    
603 root 1.47 if (op->spellarg)
604 root 1.9 {
605     op->slaying = op->spellarg;
606     free (op->spellarg);
607 root 1.47 op->spellarg = 0;
608 root 1.9 }
609     else
610 root 1.47 op->slaying = 0;
611 root 1.9
612 root 1.18 /* Reset these to zero, so that object::can_merge will work properly */
613 root 1.9 op->spellarg = NULL;
614     op->stats.sp = 0;
615     op->stats.hp = 0;
616     op->stats.grace = 0;
617     op->level = 0;
618 root 1.56 op->face = op->arch->face;
619 root 1.9 op->owner = NULL; /* So that stopped arrows will be saved */
620 root 1.40 update_object (op, UP_OBJ_CHANGE);
621 root 1.9 return op;
622 elmex 1.1 }
623    
624     /* stop_arrow() - what to do when a non-living flying object
625     * has to stop. Sept 96 - I added in thrown object code in
626     * here too. -b.t.
627     *
628     * Returns a pointer to the stopped object (which will have been removed
629     * from maps or inventories), or NULL if was destroyed.
630     */
631 root 1.9 static void
632     stop_arrow (object *op)
633 elmex 1.1 {
634 root 1.9 if (INVOKE_OBJECT (STOP, op))
635     return;
636    
637     if (op->inv)
638     {
639     object *payload = op->inv;
640 root 1.4
641 root 1.16 payload->remove ();
642 root 1.18 payload->owner = 0;
643 root 1.9 insert_ob_in_map (payload, op->map, payload, 0);
644 root 1.17 op->destroy ();
645 root 1.9 }
646     else
647     {
648     op = fix_stopped_arrow (op);
649 root 1.47
650 root 1.9 if (op)
651 root 1.47 merge_ob (op, 0);
652 elmex 1.1 }
653     }
654    
655     /* Move an arrow along its course. op is the arrow or thrown object.
656     */
657 root 1.9 void
658     move_arrow (object *op)
659     {
660 root 1.66 int was_reflected;
661 root 1.9
662 root 1.66 if (!op->map)
663 root 1.9 {
664     LOG (llevError, "BUG: Arrow had no map.\n");
665 root 1.17 op->destroy ();
666 root 1.9 return;
667 elmex 1.1 }
668    
669 root 1.9 /* we need to stop thrown objects at some point. Like here. */
670     if (op->type == THROWN_OBJ)
671     {
672     /* If the object that the THROWN_OBJ encapsulates disappears,
673     * we need to have this object go away also - otherwise, you get
674     * left over remnants on the map. Where this currently happens
675     * is if the player throws a bomb - the bomb explodes on its own,
676     * but this object sticks around. We could handle the cleanup in the
677     * bomb code, but there are potential other cases where that could happen,
678     * and it is easy enough to clean it up here.
679     */
680     if (op->inv == NULL)
681     {
682 root 1.17 op->destroy ();
683 root 1.9 return;
684 root 1.6 }
685 root 1.14
686 root 1.9 if (op->last_sp-- < 0)
687     {
688     stop_arrow (op);
689     return;
690 root 1.6 }
691 elmex 1.1 }
692    
693 root 1.9 /* if the arrow is moving too slow.. stop it. 0.5 was chosen as lower
694     values look rediculous. */
695     if (op->speed < 0.5 && op->type == ARROW)
696     {
697     stop_arrow (op);
698     return;
699 elmex 1.1 }
700    
701 root 1.9 /* Calculate target map square */
702     was_reflected = 0;
703 elmex 1.1
704 root 1.66 mapxy pos (op); pos.move (op->direction);
705 elmex 1.1
706 root 1.66 if (!pos.normalise ())
707 root 1.9 {
708     stop_arrow (op);
709     return;
710 elmex 1.1 }
711    
712 root 1.9 /* only need to look for living creatures if this flag is set */
713 root 1.66 if (pos->flags () & P_IS_ALIVE)
714 root 1.9 {
715 root 1.66 object *tmp;
716    
717     for (tmp = pos->bot; tmp; tmp = tmp->above)
718 root 1.9 if (QUERY_FLAG (tmp, FLAG_ALIVE))
719     break;
720    
721     /* Not really fair, but don't let monsters hit themselves with
722     * their own arrow - this can be because they fire it then
723     * move into it.
724     */
725 root 1.14 if (tmp && tmp != op->owner)
726 root 1.9 {
727     /* Found living object, but it is reflecting the missile. Update
728     * as below. (Note that for living creatures there is a small
729     * chance that reflect_missile fails.)
730     */
731     if (QUERY_FLAG (tmp, FLAG_REFL_MISSILE) && (rndm (0, 99)) < (90 - op->level / 10))
732     {
733 root 1.39 int number = op->face;
734 root 1.9
735     op->direction = absdir (op->direction + 4);
736 root 1.41 update_turn_face (op);
737 root 1.9 was_reflected = 1; /* skip normal movement calculations */
738 root 1.6 }
739 root 1.9 else
740     {
741     /* Attack the object. */
742     op = hit_with_arrow (op, tmp);
743 root 1.14
744     if (!op)
745 root 1.9 return;
746     }
747     } /* if this is not hitting its owner */
748     } /* if there is something alive on this space */
749 root 1.6
750 root 1.66 if (OB_TYPE_MOVE_BLOCK (op, pos->move_block))
751 root 1.9 {
752     int retry = 0;
753    
754     /* if the object doesn't reflect, stop the arrow from moving
755     * note that this code will now catch cases where a monster is
756     * on a wall but has reflecting - the arrow won't reflect.
757     * Mapmakers shouldn't put monsters on top of wall in the first
758     * place, so I don't consider that a problem.
759     */
760     if (!QUERY_FLAG (op, FLAG_REFLECTING) || !(rndm (0, 19)))
761     {
762     stop_arrow (op);
763     return;
764     }
765     else
766     {
767     /* If one of the major directions (n,s,e,w), just reverse it */
768     if (op->direction & 1)
769     {
770     op->direction = absdir (op->direction + 4);
771     retry = 1;
772     }
773 root 1.66
774 root 1.9 /* There were two blocks with identical code -
775     * use this retry here to make this one block
776     * that did the same thing.
777     */
778     while (retry < 2)
779     {
780     retry++;
781    
782 root 1.66 /* Need to check for P_OUT_OF_MAP: if the arrow is travelling
783 root 1.9 * over a corner in a tiled map, it is possible that
784     * op->direction is within an adjacent map but either
785     * op->direction-1 or op->direction+1 does not exist.
786     */
787 root 1.66 mapxy pos1 (pos); pos1.move (absdir (op->direction - 1));
788     bool left = pos1.normalise () && OB_TYPE_MOVE_BLOCK (op, pos1->move_block);
789    
790     mapxy pos2 (pos); pos2.move (absdir (op->direction + 1));
791     bool right = pos2.normalise () && OB_TYPE_MOVE_BLOCK (op, pos2->move_block);
792 root 1.9
793     if (left == right)
794     op->direction = absdir (op->direction + 4);
795     else if (left)
796     op->direction = absdir (op->direction + 2);
797     else if (right)
798     op->direction = absdir (op->direction - 2);
799    
800     /* If this space is not out of the map and not blocked, valid space -
801     * don't need to retry again.
802     */
803 root 1.66 mapxy pos3 (pos); pos3.move (op->direction);
804     if (pos3.normalise () && !OB_TYPE_MOVE_BLOCK (op, pos3->move_block))
805 root 1.9 break;
806 root 1.66 }
807 root 1.6
808 root 1.9 /* Couldn't find a direction to move the arrow to - just
809 root 1.66 * stop it from moving.
810 root 1.9 */
811     if (retry == 2)
812     {
813     stop_arrow (op);
814     return;
815     }
816 root 1.66
817 root 1.9 /* update object image for new facing */
818     /* many thrown objects *don't* have more than one face */
819     if (GET_ANIM_ID (op))
820     SET_ANIMATION (op, op->direction);
821     } /* object is reflected */
822     } /* object ran into a wall */
823    
824     /* decrease the speed as it flies. 0.05 means a standard bow will shoot
825     * about 17 squares. Tune as needed.
826     */
827     op->speed -= 0.05;
828 root 1.66
829     /* Move the arrow. */
830     op->move_to (pos);
831 elmex 1.1 }
832    
833 root 1.9 void
834     change_object (object *op)
835     { /* Doesn`t handle linked objs yet */
836     int i, j;
837    
838 root 1.67 if (!op->other_arch)
839 root 1.9 {
840 root 1.67 LOG (llevError, "Change object (%s) without other_arch error.\n", op->debug_desc ());
841 root 1.9 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 root 1.67
850     op->stats.food = 1; /* so 1 other_arch is made */
851 root 1.9 }
852 root 1.20
853     object *env = op->env;
854    
855 root 1.16 op->remove ();
856 root 1.67 for (i = 0; i < op->stats.food; i++)
857 root 1.9 {
858 root 1.20 object *tmp = arch_to_object (op->other_arch);
859    
860 root 1.9 if (op->type == LAMP)
861     tmp->stats.food = op->stats.food - 1;
862 root 1.20
863 root 1.9 tmp->stats.hp = op->stats.hp; /* The only variable it keeps. */
864     if (env)
865     {
866 root 1.67 tmp = env->insert (tmp);
867 root 1.20
868 root 1.9 /* If this object is the players inventory, we need to tell the
869     * client of the change. Insert_ob_in_map takes care of the
870     * updating the client, so we don't need to do that below.
871     */
872 root 1.67 if (object *pl = op->in_player ())
873 root 1.9 {
874     esrv_del_item (pl->contr, op->count);
875     esrv_send_item (pl, tmp);
876     }
877     }
878     else
879     {
880     j = find_first_free_spot (tmp, op->map, op->x, op->y);
881 root 1.67 if (j < 0) /* No free spot */
882 root 1.17 tmp->destroy ();
883 root 1.9 else
884     {
885 root 1.67 mapxy pos (op); pos.move (j);
886    
887     if (pos.normalise ())
888     pos.insert (tmp, op);
889 root 1.9 }
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 root 1.9 void
1173     move_creator (object *creator)
1174     {
1175     object *new_ob;
1176 elmex 1.1
1177 root 1.9 if (!QUERY_FLAG (creator, FLAG_LIFESAVE) && --creator->stats.hp < 0)
1178     {
1179     creator->stats.hp = -1;
1180     return;
1181 elmex 1.1 }
1182    
1183 root 1.9 if (creator->inv != NULL)
1184     {
1185     object *ob;
1186     int i;
1187     object *ob_to_copy;
1188    
1189     /* select random object from inventory to copy */
1190     ob_to_copy = creator->inv;
1191     for (ob = creator->inv->below, i = 1; ob != NULL; ob = ob->below, i++)
1192     {
1193     if (rndm (0, i) == 0)
1194     {
1195     ob_to_copy = ob;
1196     }
1197     }
1198     new_ob = object_create_clone (ob_to_copy);
1199     CLEAR_FLAG (new_ob, FLAG_IS_A_TEMPLATE);
1200     unflag_inv (new_ob, FLAG_IS_A_TEMPLATE);
1201     }
1202     else
1203     {
1204     if (creator->other_arch == NULL)
1205     {
1206 root 1.28 LOG (llevError, "move_creator: Creator doesn't have other arch set: %s (%s, %d, %d)\n",
1207     &creator->name, &creator->map->path, creator->x, creator->y);
1208 root 1.9 return;
1209 root 1.6 }
1210 elmex 1.1
1211 root 1.9 new_ob = object_create_arch (creator->other_arch);
1212     fix_generated_item (new_ob, creator, 0, 0, GT_MINIMAL);
1213 elmex 1.1 }
1214    
1215 root 1.9 /* Make sure this multipart object fits */
1216 root 1.68 if (new_ob->arch->more && new_ob->blocked (creator->map, creator->x, creator->y))
1217 root 1.9 {
1218 root 1.17 new_ob->destroy ();
1219 root 1.9 return;
1220 elmex 1.1 }
1221    
1222 elmex 1.62 // for now lets try to identify everything generated here, it mostly
1223     // happens automated, so this will at least fix many identify-experience holes
1224     SET_FLAG (new_ob, FLAG_IDENTIFIED);
1225    
1226 root 1.9 insert_ob_in_map_at (new_ob, creator->map, creator, 0, creator->x, creator->y);
1227     if (QUERY_FLAG (new_ob, FLAG_FREED))
1228     return;
1229 elmex 1.1
1230 root 1.9 if (creator->slaying)
1231     {
1232     new_ob->name = new_ob->title = creator->slaying;
1233 elmex 1.1 }
1234     }
1235    
1236     /* move_marker --peterm@soda.csua.berkeley.edu
1237     when moved, a marker will search for a player sitting above
1238     it, and insert an invisible, weightless force into him
1239     with a specific code as the slaying field.
1240     At that time, it writes the contents of its own message
1241     field to the player. The marker will decrement hp to
1242     0 and then delete itself every time it grants a mark.
1243     unless hp was zero to start with, in which case it is infinite.*/
1244 root 1.9 void
1245     move_marker (object *op)
1246     {
1247 root 1.22 if (object *tmp = op->ms ().player ())
1248     {
1249     /* remove an old force with a slaying field == op->name */
1250 root 1.60 if (object *force = tmp->force_find (op->name))
1251     force->destroy ();
1252 root 1.9
1253 root 1.60 if (!tmp->force_find (op->slaying))
1254 root 1.22 {
1255 root 1.60 tmp->force_add (op->slaying, op->stats.food);
1256 root 1.26
1257 root 1.22 if (op->msg)
1258     new_draw_info (NDI_UNIQUE | NDI_NAVY, 0, tmp, op->msg);
1259 root 1.9
1260 root 1.22 if (op->stats.hp > 0)
1261 root 1.9 {
1262 root 1.22 op->stats.hp--;
1263 root 1.60
1264 root 1.22 if (op->stats.hp == 0)
1265 root 1.9 {
1266 root 1.22 /* marker expires--granted mark number limit */
1267     op->destroy ();
1268     return;
1269 root 1.6 }
1270 root 1.22 }
1271     }
1272     }
1273 root 1.9 }
1274    
1275 root 1.51 void
1276 root 1.9 process_object (object *op)
1277     {
1278 root 1.54 if (expect_false (QUERY_FLAG (op, FLAG_IS_A_TEMPLATE)))
1279 root 1.51 return;
1280 root 1.9
1281 root 1.54 if (expect_false (INVOKE_OBJECT (TICK, op)))
1282 root 1.51 return;
1283 root 1.9
1284     if (QUERY_FLAG (op, FLAG_MONSTER))
1285     if (move_monster (op) || QUERY_FLAG (op, FLAG_FREED))
1286 root 1.51 return;
1287 root 1.9
1288     if (QUERY_FLAG (op, FLAG_ANIMATE) && op->anim_speed == 0)
1289     {
1290 root 1.48 animate_object (op, op->contr ? op->facing : op->direction);
1291 root 1.9
1292     if (QUERY_FLAG (op, FLAG_SEE_ANYWHERE))
1293     make_sure_seen (op);
1294     }
1295 root 1.10
1296 root 1.54 if (expect_false (
1297     op->flag [FLAG_GENERATOR]
1298     || op->flag [FLAG_CHANGING]
1299     || op->flag [FLAG_IS_USED_UP]
1300     ))
1301 root 1.9 {
1302 root 1.51 if (QUERY_FLAG (op, FLAG_CHANGING) && !op->state)
1303     {
1304     change_object (op);
1305     return;
1306     }
1307 root 1.10
1308 root 1.51 if (QUERY_FLAG (op, FLAG_GENERATOR) && !QUERY_FLAG (op, FLAG_FRIENDLY))
1309     generate_monster (op);
1310 root 1.9
1311 root 1.51 if (QUERY_FLAG (op, FLAG_IS_USED_UP) && --op->stats.food <= 0)
1312 root 1.9 {
1313 root 1.51 if (QUERY_FLAG (op, FLAG_APPLIED))
1314     remove_force (op);
1315     else
1316     {
1317     /* If necessary, delete the item from the players inventory */
1318 root 1.67 if (object *pl = op->in_player ())
1319 root 1.51 esrv_del_item (pl->contr, op->count);
1320 root 1.10
1321 root 1.51 op->remove ();
1322 root 1.10
1323 root 1.51 if (QUERY_FLAG (op, FLAG_SEE_ANYWHERE))
1324     make_sure_not_seen (op);
1325 root 1.10
1326 root 1.51 op->destroy ();
1327     }
1328    
1329     return;
1330 root 1.6 }
1331 elmex 1.1 }
1332 root 1.11
1333 root 1.9 switch (op->type)
1334     {
1335 root 1.10 case SPELL_EFFECT:
1336     move_spell_effect (op);
1337 root 1.51 break;
1338 root 1.10
1339     case ROD:
1340     case HORN:
1341     regenerate_rod (op);
1342 root 1.51 break;
1343 root 1.10
1344     case FORCE:
1345     case POTION_EFFECT:
1346     remove_force (op);
1347 root 1.51 break;
1348 elmex 1.1
1349 root 1.10 case BLINDNESS:
1350     remove_blindness (op);
1351 root 1.51 break;
1352 root 1.10
1353     case POISONING:
1354     poison_more (op);
1355 root 1.51 break;
1356 root 1.10
1357     case DISEASE:
1358     move_disease (op);
1359 root 1.51 break;
1360 root 1.10
1361     case SYMPTOM:
1362     move_symptom (op);
1363 root 1.51 break;
1364 root 1.10
1365     case THROWN_OBJ:
1366     case ARROW:
1367     move_arrow (op);
1368 root 1.51 break;
1369 root 1.10
1370     case DOOR:
1371     remove_door (op);
1372 root 1.51 break;
1373 root 1.10
1374     case LOCKED_DOOR:
1375     remove_door2 (op);
1376 root 1.51 break;
1377 root 1.10
1378     case TELEPORTER:
1379     move_teleporter (op);
1380 root 1.51 break;
1381 root 1.10
1382     case GOLEM:
1383     move_golem (op);
1384 root 1.51 break;
1385 root 1.10
1386     case EARTHWALL:
1387     hit_player (op, 2, op, AT_PHYSICAL, 1);
1388 root 1.51 break;
1389 root 1.10
1390     case FIREWALL:
1391     move_firewall (op);
1392     if (op->stats.maxsp)
1393     animate_turning (op);
1394 root 1.51 break;
1395 root 1.10
1396     case MOOD_FLOOR:
1397     do_mood_floor (op);
1398 root 1.51 break;
1399 root 1.10
1400     case GATE:
1401     move_gate (op);
1402 root 1.51 break;
1403 root 1.10
1404     case TIMED_GATE:
1405     move_timed_gate (op);
1406 root 1.51 break;
1407 root 1.10
1408     case TRIGGER:
1409     case TRIGGER_BUTTON:
1410     case TRIGGER_PEDESTAL:
1411     case TRIGGER_ALTAR:
1412     animate_trigger (op);
1413 root 1.51 break;
1414 root 1.10
1415     case DETECTOR:
1416     move_detector (op);
1417    
1418     case DIRECTOR:
1419     if (op->stats.maxsp)
1420     animate_turning (op);
1421 root 1.51 break;
1422 root 1.10
1423     case HOLE:
1424     move_hole (op);
1425 root 1.51 break;
1426 root 1.10
1427     case DEEP_SWAMP:
1428     move_deep_swamp (op);
1429 root 1.51 break;
1430 root 1.10
1431     case RUNE:
1432     case TRAP:
1433     move_rune (op);
1434 root 1.51 break;
1435 root 1.10
1436     case PLAYERMOVER:
1437     move_player_mover (op);
1438 root 1.51 break;
1439 root 1.10
1440     case CREATOR:
1441     move_creator (op);
1442 root 1.51 break;
1443 root 1.10
1444     case MARKER:
1445     move_marker (op);
1446 root 1.51 break;
1447 root 1.10
1448     case PLAYER_CHANGER:
1449     move_player_changer (op);
1450 root 1.51 break;
1451 root 1.10
1452     case PEACEMAKER:
1453     move_peacemaker (op);
1454 root 1.51 break;
1455    
1456     case PLAYER:
1457     // players have their own speed-management, so undo the --speed_left
1458     ++op->speed_left;
1459     break;
1460 elmex 1.1 }
1461     }
1462 root 1.48