ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.119
Committed: Mon Oct 29 23:55:57 2012 UTC (11 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_1
Changes since 1.118: +5 -5 lines
Log Message:
trailing space removal

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