ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.55
Committed: Mon Jun 4 12:19:09 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.54: +1 -1 lines
Log Message:
rename arch->name to arch->archname for preparation of subclassing object

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