ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.64
Committed: Thu Aug 23 15:20:34 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.63: +0 -1 lines
Log Message:
do not regenerate hp and sp when food is zero, this is ridiculous. the logic seems rather convoluted and broken, too

File Contents

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