ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.113
Committed: Tue Oct 12 05:30:12 2010 UTC (13 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.112: +1 -1 lines
Log Message:
*** empty log message ***

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.105 * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.104 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992 Frank Tore Johansen
7 root 1.53 *
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.102 object *tmp = op->other_arch->instance ();
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 root 1.102 tmp = op->other_arch->instance ();
85 root 1.9 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.98 static void
96 root 1.45 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 root 1.106 if (gen->flag [FLAG_CONTENT_ON_GEN])
113 root 1.45 {
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 root 1.106 op->clr_flag (FLAG_IS_A_TEMPLATE);
131 root 1.45 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.102 op = gen->other_arch->instance ();
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 root 1.98 static void
164 root 1.9 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 root 1.106 op->env->clr_flag (FLAG_CONFUSED);
174 root 1.25 new_draw_info (NDI_UNIQUE, 0, op->env, "You regain your senses.\n");
175 root 1.6
176 root 1.25 default:
177 root 1.106 op->clr_flag (FLAG_APPLIED);
178 root 1.25 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.98 static void
186 root 1.9 remove_blindness (object *op)
187     {
188     if (--op->stats.food > 0)
189 elmex 1.1 return;
190 root 1.17
191 root 1.106 op->clr_flag (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.98 static void
203 root 1.9 poison_more (object *op)
204     {
205 root 1.106 if (op->env == NULL || !op->env->flag [FLAG_ALIVE] || op->env->stats.hp < 0)
206 root 1.9 {
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 root 1.106 op->clr_flag (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.98 static void
238 root 1.9 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.99 if (op->arch->has_active_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 root 1.106 op->clr_flag (FLAG_BLOCKSVIEW);
264 root 1.9 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.106 if (!tmp->flag [FLAG_NO_PICK] || tmp->flag [FLAG_CAN_ROLL] || tmp->flag [FLAG_ALIVE])
286 root 1.9 break;
287 root 1.6
288 root 1.65 if (!tmp)
289 root 1.9 {
290 root 1.99 if (op->arch->has_active_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 root 1.106 if (tmp->flag [FLAG_ALIVE])
327 root 1.9 {
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.106 else if (!tmp->flag [FLAG_ALIVE] && (!tmp->flag [FLAG_NO_PICK] || tmp->flag [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.106 if (!tmp->flag [FLAG_NO_PICK] || tmp->flag [FLAG_CAN_ROLL] || tmp->flag [FLAG_ALIVE])
357 root 1.9 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.106 op->set_flag (FLAG_BLOCKSVIEW);
368 root 1.9 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.98 static void
382 root 1.9 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 root 1.98 static void
411 root 1.9 move_detector (object *op)
412 elmex 1.1 {
413 root 1.9 object *tmp;
414     int last = op->value;
415     int detected;
416    
417     detected = 0;
418    
419 root 1.66 for (tmp = op->ms ().bot; tmp && !detected; tmp = tmp->above)
420 root 1.9 {
421     object *tmp2;
422    
423     if (op->stats.hp)
424     {
425     for (tmp2 = tmp->inv; tmp2; tmp2 = tmp2->below)
426     {
427 root 1.37 if (op->slaying && op->slaying == tmp->name)
428 root 1.9 detected = 1;
429 root 1.37
430     if (tmp2->type == FORCE && tmp2->slaying && tmp2->slaying == op->slaying)
431 root 1.9 detected = 1;
432     }
433     }
434 root 1.37
435     if (op->slaying && op->slaying == tmp->name)
436     detected = 1;
437 root 1.9 else if (tmp->type == SPECIAL_KEY && tmp->slaying == op->slaying)
438     detected = 1;
439 elmex 1.1 }
440    
441 root 1.9 /* the detector sets the button if detection is found */
442     if (op->stats.sp == 1)
443     {
444     if (detected && last == 0)
445     {
446     op->value = 1;
447 root 1.84 push_button (op, tmp);
448 root 1.6 }
449 root 1.65
450 root 1.9 if (!detected && last == 1)
451     {
452     op->value = 0;
453 root 1.84 push_button (op, tmp);
454 root 1.6 }
455 elmex 1.1 }
456 root 1.9 else
457     { /* in this case, we unset buttons */
458     if (detected && last == 1)
459     {
460     op->value = 0;
461 root 1.84 push_button (op, tmp);
462 root 1.6 }
463 root 1.65
464 root 1.9 if (!detected && last == 0)
465     {
466     op->value = 1;
467 root 1.84 push_button (op, tmp);
468 root 1.6 }
469 elmex 1.1 }
470     }
471    
472 root 1.9 void
473     animate_trigger (object *op)
474 elmex 1.1 {
475 root 1.9 if ((unsigned char) ++op->stats.wc >= NUM_ANIMATIONS (op))
476     {
477     op->stats.wc = 0;
478     check_trigger (op, NULL);
479     }
480     else
481     {
482     SET_ANIMATION (op, op->stats.wc);
483     update_object (op, UP_OBJ_FACE);
484     }
485 elmex 1.1 }
486    
487 root 1.98 static void
488 root 1.9 move_hole (object *op)
489     { /* 1 = opening, 0 = closing */
490     if (op->value)
491     { /* We're opening */
492     if (--op->stats.wc <= 0)
493     { /* Opened, let's stop */
494     op->stats.wc = 0;
495 root 1.26 op->set_speed (0);
496 root 1.9
497     /* Hard coding this makes sense for holes I suppose */
498     op->move_on = MOVE_WALK;
499 root 1.77 for (object *next, *tmp = op->above; tmp; tmp = next)
500 root 1.9 {
501     next = tmp->above;
502     move_apply (op, tmp, tmp);
503 root 1.6 }
504     }
505 root 1.26
506 root 1.9 SET_ANIMATION (op, op->stats.wc);
507 root 1.109 update_object (op, UP_OBJ_CHANGE);
508 root 1.9 return;
509 elmex 1.1 }
510 root 1.66
511 root 1.9 /* We're closing */
512     op->move_on = 0;
513 elmex 1.1
514 root 1.9 op->stats.wc++;
515 root 1.109 if (op->stats.wc >= NUM_ANIMATIONS (op))
516 root 1.9 op->stats.wc = NUM_ANIMATIONS (op) - 1;
517 root 1.26
518 root 1.9 SET_ANIMATION (op, op->stats.wc);
519 root 1.109 update_object (op, UP_OBJ_CHANGE);
520     if (op->stats.wc == (NUM_ANIMATIONS (op) - 1))
521 root 1.26 op->set_speed (0); /* closed, let's stop */
522 elmex 1.1 }
523    
524    
525     /* stop_item() returns a pointer to the stopped object. The stopped object
526     * may or may not have been removed from maps or inventories. It will not
527     * have been merged with other items.
528     *
529     * This function assumes that only items on maps need special treatment.
530     *
531     * If the object can't be stopped, or it was destroyed while trying to stop
532     * it, NULL is returned.
533     *
534     * fix_stopped_item() should be used if the stopped item should be put on
535     * the map.
536     */
537 root 1.9 object *
538     stop_item (object *op)
539 elmex 1.1 {
540 root 1.9 if (op->map == NULL)
541     return op;
542 elmex 1.1
543 root 1.9 switch (op->type)
544 elmex 1.1 {
545 root 1.10 case THROWN_OBJ:
546     {
547     object *payload = op->inv;
548 root 1.9
549 root 1.10 if (payload == NULL)
550     return NULL;
551 root 1.79
552 root 1.16 payload->remove ();
553 root 1.82 op->destroy ();
554 root 1.10 return payload;
555     }
556 elmex 1.1
557 root 1.10 case ARROW:
558 elmex 1.29 if (op->has_active_speed ())
559 root 1.10 op = fix_stopped_arrow (op);
560     return op;
561 elmex 1.1
562 root 1.10 default:
563     return op;
564 elmex 1.1 }
565     }
566    
567     /* fix_stopped_item() - put stopped item where stop_item() had found it.
568     * Inserts item into the old map, or merges it if it already is on the map.
569     *
570     * 'map' must be the value of op->map before stop_item() was called.
571     */
572 root 1.9 void
573 root 1.13 fix_stopped_item (object *op, maptile *map, object *originator)
574 elmex 1.1 {
575 root 1.9 if (map == NULL)
576     return;
577 root 1.40
578 root 1.106 if (op->flag [FLAG_REMOVED])
579 root 1.9 insert_ob_in_map (op, map, originator, 0);
580     else if (op->type == ARROW)
581     merge_ob (op, NULL); /* only some arrows actually need this */
582 elmex 1.1 }
583    
584 root 1.9 object *
585     fix_stopped_arrow (object *op)
586     {
587     if (rndm (0, 99) < op->stats.food)
588     {
589     /* Small chance of breaking */
590 root 1.82 op->destroy ();
591 root 1.9 return NULL;
592     }
593    
594 root 1.26 op->set_speed (0);
595 root 1.9 op->direction = 0;
596 root 1.47 op->move_on = 0;
597 root 1.9 op->move_type = 0;
598 root 1.47 op->skill = 0; // really?
599    
600     // restore original wc, dam, attacktype and slaying
601     op->stats.wc = op->stats.sp;
602     op->stats.dam = op->stats.hp;
603 root 1.9 op->attacktype = op->stats.grace;
604 root 1.92 op->slaying = op->custom_name;
605 root 1.9
606 root 1.91 /* Reset these to defaults, so that object::can_merge will work properly */
607 root 1.92 op->custom_name = 0;
608 root 1.91 op->stats.sp = 0;
609     op->stats.hp = 0;
610     op->stats.grace = 0;
611     op->level = 0;
612     op->face = op->arch->face;
613     op->owner = 0;
614 root 1.9
615 root 1.40 update_object (op, UP_OBJ_CHANGE);
616 root 1.91
617 root 1.9 return op;
618 elmex 1.1 }
619    
620     /* stop_arrow() - what to do when a non-living flying object
621     * has to stop. Sept 96 - I added in thrown object code in
622     * here too. -b.t.
623     *
624     * Returns a pointer to the stopped object (which will have been removed
625     * from maps or inventories), or NULL if was destroyed.
626     */
627 root 1.9 static void
628     stop_arrow (object *op)
629 elmex 1.1 {
630 root 1.9 if (INVOKE_OBJECT (STOP, op))
631     return;
632    
633     if (op->inv)
634     {
635 root 1.80 // replace this by straightforward drop to ground?
636 root 1.9 object *payload = op->inv;
637 root 1.4
638 root 1.18 payload->owner = 0;
639 root 1.9 insert_ob_in_map (payload, op->map, payload, 0);
640 root 1.82 op->destroy ();
641 root 1.9 }
642     else
643     {
644     op = fix_stopped_arrow (op);
645 root 1.47
646 root 1.9 if (op)
647 root 1.47 merge_ob (op, 0);
648 elmex 1.1 }
649     }
650    
651 root 1.107 /* Move an arrow or throwen_obj along its course. op is the arrow or thrown object.
652 elmex 1.1 */
653 root 1.9 void
654     move_arrow (object *op)
655     {
656 root 1.66 int was_reflected;
657 root 1.9
658 root 1.66 if (!op->map)
659 root 1.9 {
660 root 1.113 LOG (llevError | logBacktrace, "BUG: Arrow %s had no map.\n", op->debug_desc ());
661 root 1.82 op->destroy ();
662 root 1.9 return;
663 elmex 1.1 }
664    
665 root 1.9 /* we need to stop thrown objects at some point. Like here. */
666     if (op->type == THROWN_OBJ)
667     {
668     /* If the object that the THROWN_OBJ encapsulates disappears,
669     * we need to have this object go away also - otherwise, you get
670     * left over remnants on the map. Where this currently happens
671     * is if the player throws a bomb - the bomb explodes on its own,
672     * but this object sticks around. We could handle the cleanup in the
673     * bomb code, but there are potential other cases where that could happen,
674     * and it is easy enough to clean it up here.
675     */
676 root 1.80 if (!op->inv)
677 root 1.9 {
678 root 1.82 op->destroy ();
679 root 1.9 return;
680 root 1.6 }
681 root 1.14
682 root 1.9 if (op->last_sp-- < 0)
683     {
684     stop_arrow (op);
685     return;
686 root 1.6 }
687 elmex 1.1 }
688    
689 root 1.107 /* decrease the speed as it flies. 0.05 means a standard bow will shoot
690     * about 17 squares. Tune as needed.
691     */
692 root 1.111 op->set_speed (op->speed - 0.05);
693 root 1.107
694 root 1.9 /* if the arrow is moving too slow.. stop it. 0.5 was chosen as lower
695     values look rediculous. */
696 root 1.111 if (op->speed < (op->type == ARROW ? 0.5 : MIN_ACTIVE_SPEED))
697 root 1.9 {
698     stop_arrow (op);
699     return;
700 elmex 1.1 }
701    
702 root 1.9 /* Calculate target map square */
703     was_reflected = 0;
704 elmex 1.1
705 root 1.66 mapxy pos (op); pos.move (op->direction);
706 elmex 1.1
707 root 1.66 if (!pos.normalise ())
708 root 1.9 {
709     stop_arrow (op);
710     return;
711 elmex 1.1 }
712    
713 root 1.9 /* only need to look for living creatures if this flag is set */
714 root 1.66 if (pos->flags () & P_IS_ALIVE)
715 root 1.9 {
716 root 1.66 object *tmp;
717    
718     for (tmp = pos->bot; tmp; tmp = tmp->above)
719 root 1.106 if (tmp->flag [FLAG_ALIVE])
720 root 1.9 break;
721    
722     /* Not really fair, but don't let monsters hit themselves with
723     * their own arrow - this can be because they fire it then
724     * move into it.
725     */
726 root 1.14 if (tmp && tmp != op->owner)
727 root 1.9 {
728     /* Found living object, but it is reflecting the missile. Update
729     * as below. (Note that for living creatures there is a small
730     * chance that reflect_missile fails.)
731     */
732 root 1.106 if (tmp->flag [FLAG_REFL_MISSILE] && (rndm (0, 99)) < (90 - op->level / 10))
733 root 1.9 {
734 root 1.39 int number = op->face;
735 root 1.9
736     op->direction = absdir (op->direction + 4);
737 root 1.41 update_turn_face (op);
738 root 1.9 was_reflected = 1; /* skip normal movement calculations */
739 root 1.6 }
740 root 1.9 else
741     {
742     /* Attack the object. */
743     op = hit_with_arrow (op, tmp);
744 root 1.14
745     if (!op)
746 root 1.9 return;
747     }
748     } /* if this is not hitting its owner */
749     } /* if there is something alive on this space */
750 root 1.6
751 root 1.66 if (OB_TYPE_MOVE_BLOCK (op, pos->move_block))
752 root 1.9 {
753     int retry = 0;
754    
755     /* if the object doesn't reflect, stop the arrow from moving
756     * note that this code will now catch cases where a monster is
757     * on a wall but has reflecting - the arrow won't reflect.
758     * Mapmakers shouldn't put monsters on top of wall in the first
759     * place, so I don't consider that a problem.
760     */
761 root 1.107 if (!op->flag [FLAG_REFLECTING] || !rndm (0, 19))
762 root 1.9 {
763     stop_arrow (op);
764     return;
765     }
766     else
767     {
768     /* If one of the major directions (n,s,e,w), just reverse it */
769     if (op->direction & 1)
770     {
771     op->direction = absdir (op->direction + 4);
772     retry = 1;
773     }
774 root 1.66
775 root 1.9 /* There were two blocks with identical code -
776     * use this retry here to make this one block
777     * that did the same thing.
778     */
779     while (retry < 2)
780     {
781     retry++;
782    
783 root 1.66 /* Need to check for P_OUT_OF_MAP: if the arrow is travelling
784 root 1.9 * over a corner in a tiled map, it is possible that
785     * op->direction is within an adjacent map but either
786     * op->direction-1 or op->direction+1 does not exist.
787     */
788 root 1.66 mapxy pos1 (pos); pos1.move (absdir (op->direction - 1));
789     bool left = pos1.normalise () && OB_TYPE_MOVE_BLOCK (op, pos1->move_block);
790    
791     mapxy pos2 (pos); pos2.move (absdir (op->direction + 1));
792     bool right = pos2.normalise () && OB_TYPE_MOVE_BLOCK (op, pos2->move_block);
793 root 1.9
794     if (left == right)
795     op->direction = absdir (op->direction + 4);
796     else if (left)
797     op->direction = absdir (op->direction + 2);
798     else if (right)
799     op->direction = absdir (op->direction - 2);
800    
801     /* If this space is not out of the map and not blocked, valid space -
802     * don't need to retry again.
803     */
804 root 1.66 mapxy pos3 (pos); pos3.move (op->direction);
805     if (pos3.normalise () && !OB_TYPE_MOVE_BLOCK (op, pos3->move_block))
806 root 1.9 break;
807 root 1.66 }
808 root 1.6
809 root 1.9 /* Couldn't find a direction to move the arrow to - just
810 root 1.66 * stop it from moving.
811 root 1.9 */
812     if (retry == 2)
813     {
814     stop_arrow (op);
815     return;
816     }
817 root 1.66
818 root 1.9 /* update object image for new facing */
819     /* many thrown objects *don't* have more than one face */
820 root 1.90 if (op->has_anim ())
821     op->set_anim_frame (op->direction);
822 root 1.9 } /* object is reflected */
823     } /* object ran into a wall */
824    
825 root 1.66 /* Move the arrow. */
826     op->move_to (pos);
827 elmex 1.1 }
828    
829 root 1.97 static void
830 root 1.9 change_object (object *op)
831     { /* Doesn`t handle linked objs yet */
832 root 1.67 if (!op->other_arch)
833 root 1.9 {
834 root 1.67 LOG (llevError, "Change object (%s) without other_arch error.\n", op->debug_desc ());
835 root 1.9 return;
836     }
837    
838     /* In non-living items only change when food value is 0 */
839 root 1.106 if (!op->flag [FLAG_ALIVE])
840 root 1.9 {
841     if (op->stats.food-- > 0)
842     return;
843 root 1.67
844     op->stats.food = 1; /* so 1 other_arch is made */
845 root 1.9 }
846 root 1.20
847     object *env = op->env;
848    
849 root 1.16 op->remove ();
850 root 1.101 for (int i = 0; i < op->stats.food; i++)
851 root 1.9 {
852 root 1.101 object *tmp = op->other_arch->instance ();
853 root 1.20
854 root 1.9 tmp->stats.hp = op->stats.hp; /* The only variable it keeps. */
855 root 1.74
856 root 1.9 if (env)
857 root 1.74 env->insert (tmp);
858 root 1.9 else
859     {
860 root 1.101 int j = find_first_free_spot (tmp, op->map, op->x, op->y);
861    
862 root 1.67 if (j < 0) /* No free spot */
863 root 1.82 tmp->destroy ();
864 root 1.9 else
865     {
866 root 1.67 mapxy pos (op); pos.move (j);
867    
868     if (pos.normalise ())
869     pos.insert (tmp, op);
870 root 1.9 }
871     }
872     }
873 root 1.17
874 root 1.82 op->destroy ();
875 root 1.9 }
876    
877     void
878     move_teleporter (object *op)
879     {
880     object *tmp, *head = op;
881 elmex 1.1
882 root 1.9 /* if this is a multipart teleporter, handle the other parts
883     * The check for speed isn't strictly needed - basically, if
884     * there is an old multipart teleporter in which the other parts
885     * have speed, we don't really want to call it twice for the same
886     * function - in fact, as written below, part N would get called
887     * N times without the speed check.
888     */
889 elmex 1.29 if (op->more && !op->more->has_active_speed ())
890 root 1.9 move_teleporter (op->more);
891    
892     if (op->head)
893     head = op->head;
894    
895 root 1.57 for (tmp = op->above; tmp; tmp = tmp->above)
896 root 1.106 if (!tmp->flag [FLAG_IS_FLOOR])
897 root 1.9 break;
898    
899     /* If nothing above us to move, nothing to do */
900 root 1.106 if (!tmp || tmp->flag [FLAG_WIZPASS])
901 elmex 1.1 return;
902    
903 root 1.9 if (EXIT_PATH (head))
904     {
905     if (tmp->type == PLAYER)
906     {
907     if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
908     return;
909 root 1.3
910 root 1.28 tmp->enter_exit (head);
911 root 1.6 }
912 root 1.9 else
913     /* Currently only players can transfer maps */
914     return;
915 elmex 1.1 }
916 root 1.9 else if (EXIT_X (head) || EXIT_Y (head))
917     {
918     if (out_of_map (head->map, EXIT_X (head), EXIT_Y (head)))
919     {
920     LOG (llevError, "Removed illegal teleporter.\n");
921 root 1.82 head->destroy ();
922 root 1.9 return;
923 root 1.6 }
924 root 1.17
925 root 1.9 if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
926     return;
927 root 1.17
928 root 1.9 transfer_ob (tmp, EXIT_X (head), EXIT_Y (head), 0, head);
929 elmex 1.1 }
930 root 1.9 else
931     {
932     /* Random teleporter */
933     if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
934     return;
935 root 1.76
936 root 1.9 teleport (head, TELEPORTER, tmp);
937 elmex 1.1 }
938     }
939    
940     /* This object will teleport someone to a different map
941     and will also apply changes to the player from its inventory.
942     This was invented for giving classes, but there's no reason it
943     can't be generalized.
944     */
945 root 1.98 static void
946 root 1.9 move_player_changer (object *op)
947     {
948     if (!op->above || !EXIT_PATH (op))
949     return;
950    
951     /* This isn't all that great - means that the player_mover
952     * needs to be on top.
953     */
954     if (op->above->type == PLAYER)
955     {
956 root 1.99 object *player = op->above;
957    
958 root 1.9 if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (player)))
959 root 1.34 return;
960    
961 root 1.99 for (object *walk = op->inv; walk; walk = walk->below)
962 root 1.9 apply_changes_to_player (player, walk);
963    
964 root 1.23 player->update_stats ();
965 root 1.9
966     esrv_send_inventory (op->above, op->above);
967     esrv_update_item (UPD_FACE, op->above, op->above);
968    
969     /* update players death & WoR home-position */
970 root 1.35 if (*EXIT_PATH (op) == '/')
971 root 1.9 {
972 root 1.30 player->contr->savebed_map = EXIT_PATH (op);
973     player->contr->bed_x = EXIT_X (op);
974     player->contr->bed_y = EXIT_Y (op);
975 root 1.9 }
976     else
977     LOG (llevDebug, "WARNING: destination '%s' in player_changer must be an absolute path!\n", &EXIT_PATH (op));
978    
979 root 1.28 op->above->enter_exit (op);
980 elmex 1.1 }
981     }
982    
983     /* firewalls fire other spells.
984     * The direction of the wall is stored in op->stats.sp.
985     * walls can have hp, so they can be torn down.
986     */
987 root 1.9 void
988     move_firewall (object *op)
989     {
990     object *spell;
991 elmex 1.1
992 root 1.9 if (!op->map)
993     return; /* dm has created a firewall in his inventory */
994 elmex 1.1
995 root 1.9 spell = op->inv;
996 root 1.24
997 root 1.9 if (!spell || spell->type != SPELL)
998 root 1.56 spell = op->other_arch;
999 root 1.24
1000 root 1.9 if (!spell)
1001     {
1002 root 1.28 LOG (llevError, "move_firewall: no spell specified (%s, %s, %d, %d)\n", &op->name, &op->map->name, op->x, op->y);
1003 root 1.9 return;
1004 elmex 1.1 }
1005    
1006 root 1.9 cast_spell (op, op, op->stats.sp ? op->stats.sp : rndm (1, 8), spell, NULL);
1007 elmex 1.1 }
1008    
1009 root 1.108 /* move_player_mover: this function takes a "player mover" as an
1010 elmex 1.1 * argument, and performs the function of a player mover, which is:
1011     *
1012     * a player mover finds any players that are sitting on it. It
1013     * moves them in the op->stats.sp direction. speed is how often it'll move.
1014     * If attacktype is nonzero it will paralyze the player. If lifesave is set,
1015     * it'll dissapear after hp+1 moves. If hp is set and attacktype is set,
1016     * it'll paralyze the victim for hp*his speed/op->speed
1017     */
1018 root 1.98 static void
1019 root 1.9 move_player_mover (object *op)
1020     {
1021 root 1.108 int dir = 0;
1022 root 1.9
1023 root 1.50 for (object *victim = op->ms ().bot; victim; victim = victim->above)
1024 root 1.9 {
1025 root 1.108 if (victim->flag [FLAG_ALIVE]
1026     && !victim->flag [FLAG_WIZPASS]
1027     && (victim->move_type & op->move_type || !victim->move_type))
1028 root 1.9 {
1029 root 1.106 if (op->flag [FLAG_LIFESAVE] && op->stats.hp-- < 0)
1030 root 1.9 {
1031 root 1.108 op->destroy ();
1032 root 1.9 return;
1033     }
1034 root 1.17
1035 root 1.108 /* Determine direction only once so we do the right thing */
1036     // why is it the right thing, though?
1037     if (!dir)
1038     dir = op->stats.sp ? op->stats.sp : rndm (1, 8);
1039    
1040     sint16 nx = op->x + freearr_x[dir];
1041     sint16 ny = op->y + freearr_y[dir];
1042     maptile *m = op->map;
1043 root 1.9 if (get_map_flags (m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP)
1044     {
1045 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);
1046 root 1.9 return;
1047 root 1.6 }
1048 root 1.9
1049 root 1.108 if (victim->head)
1050     victim = victim->head;
1051    
1052 root 1.9 if (should_director_abort (op, victim))
1053     return;
1054    
1055 root 1.50 for (object *nextmover = m->at (nx, ny).bot; nextmover; nextmover = nextmover->above)
1056 root 1.9 {
1057     if (nextmover->type == PLAYERMOVER)
1058 root 1.50 nextmover->speed_left = -.99f;
1059    
1060 root 1.106 if (nextmover->flag [FLAG_ALIVE])
1061 root 1.50 op->speed_left = -1.1f; /* wait until the next thing gets out of the way */
1062 root 1.6 }
1063    
1064 root 1.9 if (victim->type == PLAYER)
1065     {
1066     /* only level >=1 movers move people */
1067     if (op->level)
1068     {
1069     /* Following is a bit of hack. We need to make sure it
1070     * is cleared, otherwise the player will get stuck in
1071 root 1.96 * place. This can happen if the player used a spell to
1072 root 1.9 * get to this space.
1073     */
1074     victim->contr->fire_on = 0;
1075 root 1.52 victim->speed_left = 1.f;
1076 root 1.9 move_player (victim, dir);
1077 root 1.6 }
1078 root 1.9 else
1079     return;
1080 root 1.6 }
1081 root 1.9 else
1082 root 1.103 victim->move (dir);
1083 root 1.6
1084 root 1.9 if (!op->stats.maxsp && op->attacktype)
1085     op->stats.maxsp = 2;
1086 root 1.6
1087 root 1.9 if (op->attacktype)
1088     { /* flag to paralyze the player */
1089 root 1.100 victim->speed_left = max (-5.f, -op->stats.maxsp * victim->speed / op->speed);
1090 root 1.6 }
1091     }
1092 elmex 1.1 }
1093     }
1094    
1095     /*
1096     * Will duplicate a specified object placed on top of it.
1097     * connected: what will trigger it.
1098     * level: multiplier. 0 to destroy.
1099     * other_arch: the object to look for and duplicate.
1100     */
1101    
1102 root 1.9 void
1103     move_duplicator (object *op)
1104     {
1105     object *tmp;
1106 elmex 1.1
1107 root 1.9 if (!op->other_arch)
1108     {
1109 root 1.28 LOG (llevInfo, "Duplicator with no other_arch! %d %d %s\n", op->x, op->y, op->map ? &op->map->path : "nullmap");
1110 root 1.9 return;
1111 elmex 1.1 }
1112    
1113 root 1.9 if (op->above == NULL)
1114     return;
1115 root 1.37
1116     for (tmp = op->above; tmp; tmp = tmp->above)
1117 root 1.9 {
1118 root 1.55 if (op->other_arch->archname == tmp->arch->archname)
1119 root 1.9 {
1120     if (op->level <= 0)
1121 root 1.82 tmp->destroy ();
1122 root 1.9 else
1123     {
1124     uint64 new_nrof = (uint64) tmp->nrof * op->level;
1125    
1126     if (new_nrof >= 1UL << 31)
1127     new_nrof = 1UL << 31;
1128 root 1.17
1129 root 1.9 tmp->nrof = new_nrof;
1130 root 1.6 }
1131 root 1.17
1132 root 1.9 break;
1133 root 1.6 }
1134 elmex 1.1 }
1135     }
1136    
1137     /* move_creator (by peterm)
1138     * it has the creator object create it's other_arch right on top of it.
1139     * connected: what will trigger it
1140     * hp: how many times it may create before stopping
1141     * lifesave: if set, it'll never disappear but will go on creating
1142     * everytime it's triggered
1143     * other_arch: the object to create
1144     * Note this can create large objects, however, in that case, it
1145     * has to make sure that there is in fact space for the object.
1146     * It should really do this for small objects also, but there is
1147     * more concern with large objects, most notably a part being placed
1148     * outside of the map which would cause the server to crash
1149     */
1150 root 1.9 void
1151     move_creator (object *creator)
1152     {
1153     object *new_ob;
1154 elmex 1.1
1155 root 1.106 if (!creator->flag [FLAG_LIFESAVE] && --creator->stats.hp < 0)
1156 root 1.9 {
1157     creator->stats.hp = -1;
1158     return;
1159 elmex 1.1 }
1160    
1161 root 1.81 if (creator->inv)
1162 root 1.9 {
1163     object *ob;
1164     int i;
1165     object *ob_to_copy;
1166    
1167     /* select random object from inventory to copy */
1168     ob_to_copy = creator->inv;
1169 root 1.112 for (ob = creator->inv->below, i = 1; ob; ob = ob->below, i++)
1170 root 1.9 {
1171     if (rndm (0, i) == 0)
1172     {
1173     ob_to_copy = ob;
1174     }
1175     }
1176 root 1.112
1177 root 1.75 new_ob = ob_to_copy->deep_clone ();
1178 root 1.106 new_ob->clr_flag (FLAG_IS_A_TEMPLATE);
1179 root 1.9 unflag_inv (new_ob, FLAG_IS_A_TEMPLATE);
1180     }
1181     else
1182     {
1183 root 1.78 if (!creator->other_arch)
1184 root 1.9 {
1185 root 1.28 LOG (llevError, "move_creator: Creator doesn't have other arch set: %s (%s, %d, %d)\n",
1186     &creator->name, &creator->map->path, creator->x, creator->y);
1187 root 1.9 return;
1188 root 1.6 }
1189 elmex 1.1
1190 root 1.9 new_ob = object_create_arch (creator->other_arch);
1191     fix_generated_item (new_ob, creator, 0, 0, GT_MINIMAL);
1192 elmex 1.1 }
1193    
1194 root 1.9 /* Make sure this multipart object fits */
1195 root 1.68 if (new_ob->arch->more && new_ob->blocked (creator->map, creator->x, creator->y))
1196 root 1.9 {
1197 root 1.81 new_ob->destroy ();
1198 root 1.9 return;
1199 elmex 1.1 }
1200    
1201 elmex 1.62 // for now lets try to identify everything generated here, it mostly
1202     // happens automated, so this will at least fix many identify-experience holes
1203 root 1.112 if (new_ob->need_identify ())
1204     new_ob->set_flag (FLAG_IDENTIFIED);
1205 elmex 1.62
1206 root 1.9 insert_ob_in_map_at (new_ob, creator->map, creator, 0, creator->x, creator->y);
1207 root 1.106 if (new_ob->flag [FLAG_FREED])
1208 root 1.9 return;
1209 elmex 1.1
1210 root 1.9 if (creator->slaying)
1211 root 1.80 new_ob->name = new_ob->title = creator->slaying;
1212 elmex 1.1 }
1213    
1214     /* move_marker --peterm@soda.csua.berkeley.edu
1215     when moved, a marker will search for a player sitting above
1216     it, and insert an invisible, weightless force into him
1217     with a specific code as the slaying field.
1218     At that time, it writes the contents of its own message
1219     field to the player. The marker will decrement hp to
1220     0 and then delete itself every time it grants a mark.
1221     unless hp was zero to start with, in which case it is infinite.*/
1222 root 1.9 void
1223     move_marker (object *op)
1224     {
1225 root 1.22 if (object *tmp = op->ms ().player ())
1226     {
1227     /* remove an old force with a slaying field == op->name */
1228 root 1.60 if (object *force = tmp->force_find (op->name))
1229 root 1.82 force->destroy ();
1230 root 1.9
1231 root 1.95 if (op->slaying && !tmp->force_find (op->slaying))
1232 root 1.22 {
1233 root 1.60 tmp->force_add (op->slaying, op->stats.food);
1234 root 1.26
1235 root 1.22 if (op->msg)
1236     new_draw_info (NDI_UNIQUE | NDI_NAVY, 0, tmp, op->msg);
1237 root 1.9
1238 root 1.22 if (op->stats.hp > 0)
1239 root 1.9 {
1240 root 1.22 op->stats.hp--;
1241 root 1.60
1242 root 1.22 if (op->stats.hp == 0)
1243 root 1.9 {
1244 root 1.22 /* marker expires--granted mark number limit */
1245 root 1.82 op->destroy ();
1246 root 1.22 return;
1247 root 1.6 }
1248 root 1.22 }
1249     }
1250     }
1251 root 1.9 }
1252    
1253 root 1.84 // mapscript objects activate themselves (only) then their timer fires
1254     // TODO: maybe they should simply trigger the link like any other object?
1255 root 1.98 static void
1256 root 1.84 move_mapscript (object *op)
1257     {
1258     op->set_speed (0);
1259     cfperl_mapscript_activate (op, true, op, 0);
1260     }
1261    
1262 root 1.98 static void
1263     move_lamp (object *op)
1264 elmex 1.85 {
1265     // if the lamp/torch is off, we should disable it.
1266     if (!op->glow_radius)
1267     {
1268     op->set_speed (0);
1269     return;
1270     }
1271 elmex 1.88 else
1272     {
1273 root 1.93 // check whether the face might need to be updated
1274 elmex 1.88 // (currently this is needed to have already switched on torches
1275 root 1.93 // on maps, as they just set the glow_radius in the archetype)
1276 elmex 1.88 if (op->other_arch
1277     && (
1278 elmex 1.89 (op->flag [FLAG_ANIMATE] != op->other_arch->flag [FLAG_ANIMATE])
1279     || (op->flag [FLAG_ANIMATE]
1280     ? (op->animation_id != op->other_arch->animation_id)
1281     : (op->face != op->other_arch->face))
1282 elmex 1.88 ))
1283     get_animation_from_arch (op, op->other_arch);
1284     }
1285 elmex 1.85
1286 root 1.93 // lamps and torches on maps don't use up their fuel
1287 elmex 1.85 if (op->is_on_map ())
1288     return;
1289    
1290     if (op->stats.food > 0)
1291     {
1292     op->stats.food--;
1293     return;
1294     }
1295    
1296     apply_lamp (op, false);
1297     }
1298    
1299 root 1.51 void
1300 root 1.9 process_object (object *op)
1301     {
1302 root 1.106 if (expect_false (op->flag [FLAG_IS_A_TEMPLATE]))
1303 root 1.51 return;
1304 root 1.9
1305 root 1.54 if (expect_false (INVOKE_OBJECT (TICK, op)))
1306 root 1.51 return;
1307 root 1.9
1308 root 1.106 if (op->flag [FLAG_MONSTER])
1309     if (move_monster (op) || op->flag [FLAG_FREED])
1310 root 1.51 return;
1311 root 1.9
1312 root 1.106 if (op->flag [FLAG_ANIMATE] && op->anim_speed == 0)
1313 root 1.9 {
1314 root 1.48 animate_object (op, op->contr ? op->facing : op->direction);
1315 root 1.9
1316 root 1.106 if (op->flag [FLAG_SEE_ANYWHERE])
1317 root 1.9 make_sure_seen (op);
1318     }
1319 root 1.10
1320 root 1.54 if (expect_false (
1321     op->flag [FLAG_GENERATOR]
1322     || op->flag [FLAG_CHANGING]
1323     || op->flag [FLAG_IS_USED_UP]
1324     ))
1325 root 1.9 {
1326 root 1.106 if (op->flag [FLAG_CHANGING] && !op->state)
1327 root 1.51 {
1328     change_object (op);
1329     return;
1330     }
1331 root 1.10
1332 root 1.106 if (op->flag [FLAG_GENERATOR] && !op->flag [FLAG_FRIENDLY])
1333 root 1.51 generate_monster (op);
1334 root 1.9
1335 root 1.106 if (op->flag [FLAG_IS_USED_UP] && --op->stats.food <= 0)
1336 root 1.9 {
1337 root 1.106 if (op->flag [FLAG_APPLIED])
1338 root 1.51 remove_force (op);
1339     else
1340     {
1341 root 1.80 op->remove (); // TODO: really necessary?
1342 root 1.10
1343 root 1.106 if (op->flag [FLAG_SEE_ANYWHERE])
1344 root 1.51 make_sure_not_seen (op);
1345 root 1.10
1346 root 1.81 op->drop_and_destroy ();
1347 root 1.51 }
1348    
1349     return;
1350 root 1.6 }
1351 elmex 1.1 }
1352 root 1.11
1353 root 1.9 switch (op->type)
1354     {
1355 root 1.10 case SPELL_EFFECT:
1356     move_spell_effect (op);
1357 root 1.51 break;
1358 root 1.10
1359     case ROD:
1360     case HORN:
1361     regenerate_rod (op);
1362 root 1.51 break;
1363 root 1.10
1364     case FORCE:
1365     case POTION_EFFECT:
1366     remove_force (op);
1367 root 1.51 break;
1368 elmex 1.1
1369 root 1.10 case BLINDNESS:
1370     remove_blindness (op);
1371 root 1.51 break;
1372 root 1.10
1373     case POISONING:
1374     poison_more (op);
1375 root 1.51 break;
1376 root 1.10
1377     case DISEASE:
1378     move_disease (op);
1379 root 1.51 break;
1380 root 1.10
1381     case SYMPTOM:
1382     move_symptom (op);
1383 root 1.51 break;
1384 root 1.10
1385     case THROWN_OBJ:
1386     case ARROW:
1387     move_arrow (op);
1388 root 1.51 break;
1389 root 1.10
1390     case DOOR:
1391     remove_door (op);
1392 root 1.51 break;
1393 root 1.10
1394     case LOCKED_DOOR:
1395     remove_door2 (op);
1396 root 1.51 break;
1397 root 1.10
1398     case TELEPORTER:
1399     move_teleporter (op);
1400 root 1.51 break;
1401 root 1.10
1402     case GOLEM:
1403     move_golem (op);
1404 root 1.51 break;
1405 root 1.10
1406     case EARTHWALL:
1407     hit_player (op, 2, op, AT_PHYSICAL, 1);
1408 root 1.51 break;
1409 root 1.10
1410     case FIREWALL:
1411     move_firewall (op);
1412     if (op->stats.maxsp)
1413     animate_turning (op);
1414 root 1.51 break;
1415 root 1.10
1416     case MOOD_FLOOR:
1417     do_mood_floor (op);
1418 root 1.51 break;
1419 root 1.10
1420     case GATE:
1421     move_gate (op);
1422 root 1.51 break;
1423 root 1.10
1424     case TIMED_GATE:
1425     move_timed_gate (op);
1426 root 1.51 break;
1427 root 1.10
1428     case TRIGGER:
1429     case TRIGGER_BUTTON:
1430     case TRIGGER_PEDESTAL:
1431     case TRIGGER_ALTAR:
1432     animate_trigger (op);
1433 root 1.51 break;
1434 root 1.10
1435     case DETECTOR:
1436     move_detector (op);
1437    
1438     case DIRECTOR:
1439     if (op->stats.maxsp)
1440     animate_turning (op);
1441 root 1.51 break;
1442 root 1.10
1443     case HOLE:
1444     move_hole (op);
1445 root 1.51 break;
1446 root 1.10
1447     case DEEP_SWAMP:
1448     move_deep_swamp (op);
1449 root 1.51 break;
1450 root 1.10
1451     case RUNE:
1452     case TRAP:
1453     move_rune (op);
1454 root 1.51 break;
1455 root 1.10
1456     case PLAYERMOVER:
1457     move_player_mover (op);
1458 root 1.51 break;
1459 root 1.10
1460     case CREATOR:
1461     move_creator (op);
1462 root 1.51 break;
1463 root 1.10
1464     case MARKER:
1465     move_marker (op);
1466 root 1.51 break;
1467 root 1.10
1468     case PLAYER_CHANGER:
1469     move_player_changer (op);
1470 root 1.51 break;
1471 root 1.10
1472     case PEACEMAKER:
1473     move_peacemaker (op);
1474 root 1.51 break;
1475    
1476     case PLAYER:
1477     // players have their own speed-management, so undo the --speed_left
1478     ++op->speed_left;
1479     break;
1480 root 1.84
1481     case MAPSCRIPT:
1482     move_mapscript (op);
1483     break;
1484 elmex 1.85
1485     case LAMP:
1486     case TORCH:
1487     move_lamp (op);
1488     break;
1489 elmex 1.1 }
1490     }
1491 root 1.48