ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.97
Committed: Fri Nov 6 12:49:19 2009 UTC (14 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.96: +1 -1 lines
Log Message:
make effectively static symbols actually static, part 1

File Contents

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