ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.123
Committed: Thu Nov 17 04:59:33 2016 UTC (7 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.122: +2 -0 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.119 *
4 root 1.121 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 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 root 1.122 /* The following removes doors. The functions check to see if similar
34 elmex 1.1 * 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.123 op->clr_flag (FLAG_NO_PICK); /* fire_bow makes arrows NO_PICK so monsters (or anything else) don't pick them mid-flight */
615    
616 root 1.40 update_object (op, UP_OBJ_CHANGE);
617 root 1.91
618 root 1.9 return op;
619 elmex 1.1 }
620    
621     /* stop_arrow() - what to do when a non-living flying object
622     * has to stop. Sept 96 - I added in thrown object code in
623     * here too. -b.t.
624     *
625     * Returns a pointer to the stopped object (which will have been removed
626     * from maps or inventories), or NULL if was destroyed.
627     */
628 root 1.9 static void
629     stop_arrow (object *op)
630 elmex 1.1 {
631 root 1.9 if (INVOKE_OBJECT (STOP, op))
632     return;
633    
634     if (op->inv)
635     {
636 root 1.80 // replace this by straightforward drop to ground?
637 root 1.9 object *payload = op->inv;
638 root 1.4
639 root 1.18 payload->owner = 0;
640 root 1.9 insert_ob_in_map (payload, op->map, payload, 0);
641 root 1.82 op->destroy ();
642 root 1.9 }
643     else
644     {
645     op = fix_stopped_arrow (op);
646 root 1.47
647 root 1.9 if (op)
648 root 1.47 merge_ob (op, 0);
649 elmex 1.1 }
650     }
651    
652 root 1.107 /* Move an arrow or throwen_obj along its course. op is the arrow or thrown object.
653 elmex 1.1 */
654 root 1.9 void
655     move_arrow (object *op)
656     {
657 root 1.66 int was_reflected;
658 root 1.9
659 root 1.66 if (!op->map)
660 root 1.9 {
661 root 1.113 LOG (llevError | logBacktrace, "BUG: Arrow %s had no map.\n", op->debug_desc ());
662 root 1.82 op->destroy ();
663 root 1.9 return;
664 elmex 1.1 }
665    
666 root 1.9 /* we need to stop thrown objects at some point. Like here. */
667     if (op->type == THROWN_OBJ)
668     {
669     /* If the object that the THROWN_OBJ encapsulates disappears,
670     * we need to have this object go away also - otherwise, you get
671     * left over remnants on the map. Where this currently happens
672     * is if the player throws a bomb - the bomb explodes on its own,
673     * but this object sticks around. We could handle the cleanup in the
674     * bomb code, but there are potential other cases where that could happen,
675     * and it is easy enough to clean it up here.
676     */
677 root 1.80 if (!op->inv)
678 root 1.9 {
679 root 1.82 op->destroy ();
680 root 1.9 return;
681 root 1.6 }
682 root 1.14
683 root 1.9 if (op->last_sp-- < 0)
684     {
685     stop_arrow (op);
686     return;
687 root 1.6 }
688 elmex 1.1 }
689    
690 root 1.107 /* decrease the speed as it flies. 0.05 means a standard bow will shoot
691     * about 17 squares. Tune as needed.
692     */
693 root 1.111 op->set_speed (op->speed - 0.05);
694 root 1.107
695 root 1.9 /* if the arrow is moving too slow.. stop it. 0.5 was chosen as lower
696 root 1.120 values look ridiculous. */
697 root 1.111 if (op->speed < (op->type == ARROW ? 0.5 : MIN_ACTIVE_SPEED))
698 root 1.9 {
699     stop_arrow (op);
700     return;
701 elmex 1.1 }
702    
703 root 1.9 /* Calculate target map square */
704     was_reflected = 0;
705 elmex 1.1
706 root 1.66 mapxy pos (op); pos.move (op->direction);
707 elmex 1.1
708 root 1.66 if (!pos.normalise ())
709 root 1.9 {
710     stop_arrow (op);
711     return;
712 elmex 1.1 }
713    
714 root 1.9 /* only need to look for living creatures if this flag is set */
715 root 1.66 if (pos->flags () & P_IS_ALIVE)
716 root 1.9 {
717 root 1.66 object *tmp;
718    
719     for (tmp = pos->bot; tmp; tmp = tmp->above)
720 root 1.120 if (tmp->flag [FLAG_ALIVE] && tmp != op->owner)
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    
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     if (tmp->flag [FLAG_REFL_MISSILE] && (rndm (0, 99)) < (90 - op->level / 10))
732     {
733     op->direction = absdir (op->direction + 4);
734     update_turn_face (op);
735     was_reflected = 1; /* skip normal movement calculations */
736     }
737     else
738     {
739     /* Attack the object. */
740     op = hit_with_arrow (op, tmp);
741 root 1.9
742 root 1.120 if (!op)
743     return;
744     }
745 root 1.14
746 root 1.120 break;
747     }
748     }
749 root 1.6
750 root 1.66 if (OB_TYPE_MOVE_BLOCK (op, pos->move_block))
751 root 1.9 {
752     int retry = 0;
753    
754     /* if the object doesn't reflect, stop the arrow from moving
755     * note that this code will now catch cases where a monster is
756     * on a wall but has reflecting - the arrow won't reflect.
757     * Mapmakers shouldn't put monsters on top of wall in the first
758     * place, so I don't consider that a problem.
759     */
760 root 1.107 if (!op->flag [FLAG_REFLECTING] || !rndm (0, 19))
761 root 1.9 {
762     stop_arrow (op);
763     return;
764     }
765     else
766     {
767     /* If one of the major directions (n,s,e,w), just reverse it */
768     if (op->direction & 1)
769     {
770     op->direction = absdir (op->direction + 4);
771     retry = 1;
772     }
773 root 1.66
774 root 1.9 /* There were two blocks with identical code -
775     * use this retry here to make this one block
776     * that did the same thing.
777     */
778     while (retry < 2)
779     {
780     retry++;
781    
782 root 1.66 /* Need to check for P_OUT_OF_MAP: if the arrow is travelling
783 root 1.9 * over a corner in a tiled map, it is possible that
784     * op->direction is within an adjacent map but either
785     * op->direction-1 or op->direction+1 does not exist.
786     */
787 root 1.66 mapxy pos1 (pos); pos1.move (absdir (op->direction - 1));
788     bool left = pos1.normalise () && OB_TYPE_MOVE_BLOCK (op, pos1->move_block);
789    
790     mapxy pos2 (pos); pos2.move (absdir (op->direction + 1));
791     bool right = pos2.normalise () && OB_TYPE_MOVE_BLOCK (op, pos2->move_block);
792 root 1.9
793     if (left == right)
794     op->direction = absdir (op->direction + 4);
795     else if (left)
796     op->direction = absdir (op->direction + 2);
797     else if (right)
798     op->direction = absdir (op->direction - 2);
799    
800     /* If this space is not out of the map and not blocked, valid space -
801     * don't need to retry again.
802     */
803 root 1.66 mapxy pos3 (pos); pos3.move (op->direction);
804     if (pos3.normalise () && !OB_TYPE_MOVE_BLOCK (op, pos3->move_block))
805 root 1.9 break;
806 root 1.66 }
807 root 1.6
808 root 1.9 /* Couldn't find a direction to move the arrow to - just
809 root 1.66 * stop it from moving.
810 root 1.9 */
811     if (retry == 2)
812     {
813     stop_arrow (op);
814     return;
815     }
816 root 1.66
817 root 1.9 /* update object image for new facing */
818     /* many thrown objects *don't* have more than one face */
819 root 1.90 if (op->has_anim ())
820     op->set_anim_frame (op->direction);
821 root 1.9 } /* object is reflected */
822     } /* object ran into a wall */
823    
824 root 1.66 /* Move the arrow. */
825     op->move_to (pos);
826 elmex 1.1 }
827    
828 root 1.97 static void
829 root 1.9 change_object (object *op)
830     { /* Doesn`t handle linked objs yet */
831 root 1.67 if (!op->other_arch)
832 root 1.9 {
833 root 1.67 LOG (llevError, "Change object (%s) without other_arch error.\n", op->debug_desc ());
834 root 1.9 return;
835     }
836    
837     /* In non-living items only change when food value is 0 */
838 root 1.106 if (!op->flag [FLAG_ALIVE])
839 root 1.9 {
840     if (op->stats.food-- > 0)
841     return;
842 root 1.67
843     op->stats.food = 1; /* so 1 other_arch is made */
844 root 1.9 }
845 root 1.20
846     object *env = op->env;
847    
848 root 1.16 op->remove ();
849 root 1.101 for (int i = 0; i < op->stats.food; i++)
850 root 1.9 {
851 root 1.101 object *tmp = op->other_arch->instance ();
852 root 1.20
853 root 1.9 tmp->stats.hp = op->stats.hp; /* The only variable it keeps. */
854 root 1.74
855 root 1.9 if (env)
856 root 1.74 env->insert (tmp);
857 root 1.9 else
858     {
859 root 1.101 int j = find_first_free_spot (tmp, op->map, op->x, op->y);
860    
861 root 1.67 if (j < 0) /* No free spot */
862 root 1.82 tmp->destroy ();
863 root 1.9 else
864     {
865 root 1.67 mapxy pos (op); pos.move (j);
866    
867     if (pos.normalise ())
868     pos.insert (tmp, op);
869 root 1.9 }
870     }
871     }
872 root 1.17
873 root 1.82 op->destroy ();
874 root 1.9 }
875    
876     void
877     move_teleporter (object *op)
878     {
879     object *tmp, *head = op;
880 elmex 1.1
881 root 1.9 /* if this is a multipart teleporter, handle the other parts
882     * The check for speed isn't strictly needed - basically, if
883     * there is an old multipart teleporter in which the other parts
884     * have speed, we don't really want to call it twice for the same
885     * function - in fact, as written below, part N would get called
886     * N times without the speed check.
887     */
888 elmex 1.29 if (op->more && !op->more->has_active_speed ())
889 root 1.9 move_teleporter (op->more);
890    
891     if (op->head)
892     head = op->head;
893    
894 root 1.57 for (tmp = op->above; tmp; tmp = tmp->above)
895 root 1.106 if (!tmp->flag [FLAG_IS_FLOOR])
896 root 1.9 break;
897    
898     /* If nothing above us to move, nothing to do */
899 root 1.106 if (!tmp || tmp->flag [FLAG_WIZPASS])
900 elmex 1.1 return;
901    
902 root 1.9 if (EXIT_PATH (head))
903     {
904     if (tmp->type == PLAYER)
905     {
906     if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
907     return;
908 root 1.3
909 root 1.28 tmp->enter_exit (head);
910 root 1.6 }
911 root 1.9 else
912     /* Currently only players can transfer maps */
913     return;
914 elmex 1.1 }
915 root 1.9 else if (EXIT_X (head) || EXIT_Y (head))
916     {
917     if (out_of_map (head->map, EXIT_X (head), EXIT_Y (head)))
918     {
919     LOG (llevError, "Removed illegal teleporter.\n");
920 root 1.82 head->destroy ();
921 root 1.9 return;
922 root 1.6 }
923 root 1.17
924 root 1.9 if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
925     return;
926 root 1.17
927 root 1.9 transfer_ob (tmp, EXIT_X (head), EXIT_Y (head), 0, head);
928 elmex 1.1 }
929 root 1.9 else
930     {
931     /* Random teleporter */
932     if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
933     return;
934 root 1.76
935 root 1.9 teleport (head, TELEPORTER, tmp);
936 elmex 1.1 }
937     }
938    
939     /* This object will teleport someone to a different map
940     and will also apply changes to the player from its inventory.
941     This was invented for giving classes, but there's no reason it
942     can't be generalized.
943     */
944 root 1.98 static void
945 root 1.9 move_player_changer (object *op)
946     {
947     if (!op->above || !EXIT_PATH (op))
948     return;
949    
950     /* This isn't all that great - means that the player_mover
951     * needs to be on top.
952     */
953     if (op->above->type == PLAYER)
954     {
955 root 1.99 object *player = op->above;
956    
957 root 1.9 if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (player)))
958 root 1.34 return;
959    
960 root 1.99 for (object *walk = op->inv; walk; walk = walk->below)
961 root 1.9 apply_changes_to_player (player, walk);
962    
963 root 1.23 player->update_stats ();
964 root 1.9
965     esrv_send_inventory (op->above, op->above);
966     esrv_update_item (UPD_FACE, op->above, op->above);
967    
968     /* update players death & WoR home-position */
969 root 1.35 if (*EXIT_PATH (op) == '/')
970 root 1.9 {
971 root 1.30 player->contr->savebed_map = EXIT_PATH (op);
972     player->contr->bed_x = EXIT_X (op);
973     player->contr->bed_y = EXIT_Y (op);
974 root 1.9 }
975     else
976     LOG (llevDebug, "WARNING: destination '%s' in player_changer must be an absolute path!\n", &EXIT_PATH (op));
977    
978 root 1.28 op->above->enter_exit (op);
979 elmex 1.1 }
980     }
981    
982     /* firewalls fire other spells.
983     * The direction of the wall is stored in op->stats.sp.
984     * walls can have hp, so they can be torn down.
985     */
986 root 1.9 void
987     move_firewall (object *op)
988     {
989     object *spell;
990 elmex 1.1
991 root 1.9 if (!op->map)
992     return; /* dm has created a firewall in his inventory */
993 elmex 1.1
994 root 1.9 spell = op->inv;
995 root 1.24
996 root 1.9 if (!spell || spell->type != SPELL)
997 root 1.56 spell = op->other_arch;
998 root 1.24
999 root 1.9 if (!spell)
1000     {
1001 root 1.28 LOG (llevError, "move_firewall: no spell specified (%s, %s, %d, %d)\n", &op->name, &op->map->name, op->x, op->y);
1002 root 1.9 return;
1003 elmex 1.1 }
1004    
1005 root 1.9 cast_spell (op, op, op->stats.sp ? op->stats.sp : rndm (1, 8), spell, NULL);
1006 elmex 1.1 }
1007    
1008 root 1.108 /* move_player_mover: this function takes a "player mover" as an
1009 elmex 1.1 * argument, and performs the function of a player mover, which is:
1010     *
1011     * a player mover finds any players that are sitting on it. It
1012     * moves them in the op->stats.sp direction. speed is how often it'll move.
1013     * If attacktype is nonzero it will paralyze the player. If lifesave is set,
1014     * it'll dissapear after hp+1 moves. If hp is set and attacktype is set,
1015     * it'll paralyze the victim for hp*his speed/op->speed
1016     */
1017 root 1.98 static void
1018 root 1.9 move_player_mover (object *op)
1019     {
1020 root 1.108 int dir = 0;
1021 root 1.9
1022 root 1.50 for (object *victim = op->ms ().bot; victim; victim = victim->above)
1023 root 1.9 {
1024 root 1.108 if (victim->flag [FLAG_ALIVE]
1025     && !victim->flag [FLAG_WIZPASS]
1026     && (victim->move_type & op->move_type || !victim->move_type))
1027 root 1.9 {
1028 root 1.106 if (op->flag [FLAG_LIFESAVE] && op->stats.hp-- < 0)
1029 root 1.9 {
1030 root 1.108 op->destroy ();
1031 root 1.9 return;
1032     }
1033 root 1.17
1034 root 1.108 /* Determine direction only once so we do the right thing */
1035     // why is it the right thing, though?
1036     if (!dir)
1037     dir = op->stats.sp ? op->stats.sp : rndm (1, 8);
1038    
1039     sint16 nx = op->x + freearr_x[dir];
1040     sint16 ny = op->y + freearr_y[dir];
1041     maptile *m = op->map;
1042 root 1.9 if (get_map_flags (m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP)
1043     {
1044 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);
1045 root 1.9 return;
1046 root 1.6 }
1047 root 1.9
1048 root 1.108 if (victim->head)
1049     victim = victim->head;
1050    
1051 root 1.9 if (should_director_abort (op, victim))
1052     return;
1053    
1054 root 1.50 for (object *nextmover = m->at (nx, ny).bot; nextmover; nextmover = nextmover->above)
1055 root 1.9 {
1056     if (nextmover->type == PLAYERMOVER)
1057 root 1.50 nextmover->speed_left = -.99f;
1058    
1059 root 1.106 if (nextmover->flag [FLAG_ALIVE])
1060 root 1.50 op->speed_left = -1.1f; /* wait until the next thing gets out of the way */
1061 root 1.6 }
1062    
1063 root 1.9 if (victim->type == PLAYER)
1064     {
1065     /* only level >=1 movers move people */
1066     if (op->level)
1067     {
1068     /* Following is a bit of hack. We need to make sure it
1069     * is cleared, otherwise the player will get stuck in
1070 root 1.96 * place. This can happen if the player used a spell to
1071 root 1.9 * get to this space.
1072     */
1073     victim->contr->fire_on = 0;
1074 root 1.52 victim->speed_left = 1.f;
1075 root 1.9 move_player (victim, dir);
1076 root 1.6 }
1077 root 1.9 else
1078     return;
1079 root 1.6 }
1080 root 1.9 else
1081 root 1.103 victim->move (dir);
1082 root 1.6
1083 root 1.9 if (!op->stats.maxsp && op->attacktype)
1084     op->stats.maxsp = 2;
1085 root 1.6
1086 root 1.9 if (op->attacktype)
1087     { /* flag to paralyze the player */
1088 root 1.100 victim->speed_left = max (-5.f, -op->stats.maxsp * victim->speed / op->speed);
1089 root 1.6 }
1090     }
1091 elmex 1.1 }
1092     }
1093    
1094     /*
1095     * Will duplicate a specified object placed on top of it.
1096     * connected: what will trigger it.
1097     * level: multiplier. 0 to destroy.
1098     * other_arch: the object to look for and duplicate.
1099     */
1100    
1101 root 1.9 void
1102     move_duplicator (object *op)
1103     {
1104     object *tmp;
1105 elmex 1.1
1106 root 1.9 if (!op->other_arch)
1107     {
1108 root 1.28 LOG (llevInfo, "Duplicator with no other_arch! %d %d %s\n", op->x, op->y, op->map ? &op->map->path : "nullmap");
1109 root 1.9 return;
1110 elmex 1.1 }
1111    
1112 root 1.9 if (op->above == NULL)
1113     return;
1114 root 1.37
1115     for (tmp = op->above; tmp; tmp = tmp->above)
1116 root 1.9 {
1117 root 1.55 if (op->other_arch->archname == tmp->arch->archname)
1118 root 1.9 {
1119     if (op->level <= 0)
1120 root 1.82 tmp->destroy ();
1121 root 1.9 else
1122     {
1123     uint64 new_nrof = (uint64) tmp->nrof * op->level;
1124    
1125     if (new_nrof >= 1UL << 31)
1126     new_nrof = 1UL << 31;
1127 root 1.17
1128 root 1.9 tmp->nrof = new_nrof;
1129 root 1.6 }
1130 root 1.17
1131 root 1.9 break;
1132 root 1.6 }
1133 elmex 1.1 }
1134     }
1135    
1136     /* move_creator (by peterm)
1137     * it has the creator object create it's other_arch right on top of it.
1138     * connected: what will trigger it
1139     * hp: how many times it may create before stopping
1140     * lifesave: if set, it'll never disappear but will go on creating
1141     * everytime it's triggered
1142     * other_arch: the object to create
1143     * Note this can create large objects, however, in that case, it
1144     * has to make sure that there is in fact space for the object.
1145     * It should really do this for small objects also, but there is
1146     * more concern with large objects, most notably a part being placed
1147     * outside of the map which would cause the server to crash
1148     */
1149 root 1.9 void
1150     move_creator (object *creator)
1151     {
1152     object *new_ob;
1153 elmex 1.1
1154 root 1.106 if (!creator->flag [FLAG_LIFESAVE] && --creator->stats.hp < 0)
1155 root 1.9 {
1156     creator->stats.hp = -1;
1157     return;
1158 elmex 1.1 }
1159    
1160 root 1.81 if (creator->inv)
1161 root 1.9 {
1162     object *ob;
1163     int i;
1164     object *ob_to_copy;
1165    
1166     /* select random object from inventory to copy */
1167     ob_to_copy = creator->inv;
1168 root 1.112 for (ob = creator->inv->below, i = 1; ob; ob = ob->below, i++)
1169 root 1.9 {
1170     if (rndm (0, i) == 0)
1171     {
1172     ob_to_copy = ob;
1173     }
1174     }
1175 root 1.112
1176 root 1.75 new_ob = ob_to_copy->deep_clone ();
1177 root 1.106 new_ob->clr_flag (FLAG_IS_A_TEMPLATE);
1178 root 1.9 unflag_inv (new_ob, FLAG_IS_A_TEMPLATE);
1179     }
1180     else
1181     {
1182 root 1.78 if (!creator->other_arch)
1183 root 1.9 {
1184 root 1.28 LOG (llevError, "move_creator: Creator doesn't have other arch set: %s (%s, %d, %d)\n",
1185     &creator->name, &creator->map->path, creator->x, creator->y);
1186 root 1.9 return;
1187 root 1.6 }
1188 elmex 1.1
1189 root 1.9 new_ob = object_create_arch (creator->other_arch);
1190     fix_generated_item (new_ob, creator, 0, 0, GT_MINIMAL);
1191 elmex 1.1 }
1192    
1193 root 1.9 /* Make sure this multipart object fits */
1194 root 1.68 if (new_ob->arch->more && new_ob->blocked (creator->map, creator->x, creator->y))
1195 root 1.9 {
1196 root 1.81 new_ob->destroy ();
1197 root 1.9 return;
1198 elmex 1.1 }
1199    
1200 elmex 1.62 // for now lets try to identify everything generated here, it mostly
1201     // happens automated, so this will at least fix many identify-experience holes
1202 root 1.112 if (new_ob->need_identify ())
1203     new_ob->set_flag (FLAG_IDENTIFIED);
1204 elmex 1.62
1205 root 1.9 insert_ob_in_map_at (new_ob, creator->map, creator, 0, creator->x, creator->y);
1206 root 1.106 if (new_ob->flag [FLAG_FREED])
1207 root 1.9 return;
1208 elmex 1.1
1209 root 1.9 if (creator->slaying)
1210 root 1.80 new_ob->name = new_ob->title = creator->slaying;
1211 elmex 1.1 }
1212    
1213     /* move_marker --peterm@soda.csua.berkeley.edu
1214     when moved, a marker will search for a player sitting above
1215     it, and insert an invisible, weightless force into him
1216     with a specific code as the slaying field.
1217     At that time, it writes the contents of its own message
1218     field to the player. The marker will decrement hp to
1219     0 and then delete itself every time it grants a mark.
1220     unless hp was zero to start with, in which case it is infinite.*/
1221 root 1.9 void
1222     move_marker (object *op)
1223     {
1224 root 1.22 if (object *tmp = op->ms ().player ())
1225     {
1226     /* remove an old force with a slaying field == op->name */
1227 root 1.60 if (object *force = tmp->force_find (op->name))
1228 root 1.82 force->destroy ();
1229 root 1.9
1230 root 1.95 if (op->slaying && !tmp->force_find (op->slaying))
1231 root 1.22 {
1232 root 1.60 tmp->force_add (op->slaying, op->stats.food);
1233 root 1.26
1234 root 1.22 if (op->msg)
1235     new_draw_info (NDI_UNIQUE | NDI_NAVY, 0, tmp, op->msg);
1236 root 1.9
1237 root 1.22 if (op->stats.hp > 0)
1238 root 1.9 {
1239 root 1.22 op->stats.hp--;
1240 root 1.60
1241 root 1.22 if (op->stats.hp == 0)
1242 root 1.9 {
1243 root 1.22 /* marker expires--granted mark number limit */
1244 root 1.82 op->destroy ();
1245 root 1.22 return;
1246 root 1.6 }
1247 root 1.22 }
1248     }
1249     }
1250 root 1.9 }
1251    
1252 root 1.84 // mapscript objects activate themselves (only) then their timer fires
1253     // TODO: maybe they should simply trigger the link like any other object?
1254 root 1.98 static void
1255 root 1.84 move_mapscript (object *op)
1256     {
1257     op->set_speed (0);
1258     cfperl_mapscript_activate (op, true, op, 0);
1259     }
1260    
1261 root 1.98 static void
1262     move_lamp (object *op)
1263 elmex 1.85 {
1264     // if the lamp/torch is off, we should disable it.
1265     if (!op->glow_radius)
1266     {
1267     op->set_speed (0);
1268     return;
1269     }
1270 elmex 1.88 else
1271     {
1272 root 1.93 // check whether the face might need to be updated
1273 elmex 1.88 // (currently this is needed to have already switched on torches
1274 root 1.93 // on maps, as they just set the glow_radius in the archetype)
1275 elmex 1.88 if (op->other_arch
1276     && (
1277 elmex 1.89 (op->flag [FLAG_ANIMATE] != op->other_arch->flag [FLAG_ANIMATE])
1278     || (op->flag [FLAG_ANIMATE]
1279     ? (op->animation_id != op->other_arch->animation_id)
1280     : (op->face != op->other_arch->face))
1281 elmex 1.88 ))
1282     get_animation_from_arch (op, op->other_arch);
1283     }
1284 elmex 1.85
1285 root 1.93 // lamps and torches on maps don't use up their fuel
1286 elmex 1.85 if (op->is_on_map ())
1287     return;
1288    
1289     if (op->stats.food > 0)
1290     {
1291     op->stats.food--;
1292     return;
1293     }
1294    
1295     apply_lamp (op, false);
1296     }
1297    
1298 root 1.51 void
1299 root 1.9 process_object (object *op)
1300     {
1301 root 1.106 if (expect_false (op->flag [FLAG_IS_A_TEMPLATE]))
1302 root 1.51 return;
1303 root 1.9
1304 root 1.54 if (expect_false (INVOKE_OBJECT (TICK, op)))
1305 root 1.51 return;
1306 root 1.9
1307 root 1.106 if (op->flag [FLAG_MONSTER])
1308     if (move_monster (op) || op->flag [FLAG_FREED])
1309 root 1.51 return;
1310 root 1.9
1311 root 1.106 if (op->flag [FLAG_ANIMATE] && op->anim_speed == 0)
1312 root 1.9 {
1313 root 1.48 animate_object (op, op->contr ? op->facing : op->direction);
1314 root 1.9
1315 root 1.106 if (op->flag [FLAG_SEE_ANYWHERE])
1316 root 1.9 make_sure_seen (op);
1317     }
1318 root 1.10
1319 root 1.54 if (expect_false (
1320     op->flag [FLAG_GENERATOR]
1321     || op->flag [FLAG_CHANGING]
1322     || op->flag [FLAG_IS_USED_UP]
1323     ))
1324 root 1.9 {
1325 root 1.106 if (op->flag [FLAG_CHANGING] && !op->state)
1326 root 1.51 {
1327     change_object (op);
1328     return;
1329     }
1330 root 1.10
1331 root 1.106 if (op->flag [FLAG_GENERATOR] && !op->flag [FLAG_FRIENDLY])
1332 root 1.51 generate_monster (op);
1333 root 1.9
1334 root 1.106 if (op->flag [FLAG_IS_USED_UP] && --op->stats.food <= 0)
1335 root 1.9 {
1336 root 1.106 if (op->flag [FLAG_APPLIED])
1337 root 1.51 remove_force (op);
1338     else
1339     {
1340 root 1.80 op->remove (); // TODO: really necessary?
1341 root 1.10
1342 root 1.106 if (op->flag [FLAG_SEE_ANYWHERE])
1343 root 1.51 make_sure_not_seen (op);
1344 root 1.10
1345 root 1.81 op->drop_and_destroy ();
1346 root 1.51 }
1347    
1348     return;
1349 root 1.6 }
1350 elmex 1.1 }
1351 root 1.11
1352 root 1.9 switch (op->type)
1353     {
1354 root 1.10 case SPELL_EFFECT:
1355     move_spell_effect (op);
1356 root 1.51 break;
1357 root 1.10
1358     case ROD:
1359     case HORN:
1360     regenerate_rod (op);
1361 root 1.51 break;
1362 root 1.10
1363     case FORCE:
1364     case POTION_EFFECT:
1365     remove_force (op);
1366 root 1.51 break;
1367 elmex 1.1
1368 root 1.10 case BLINDNESS:
1369     remove_blindness (op);
1370 root 1.51 break;
1371 root 1.10
1372     case POISONING:
1373     poison_more (op);
1374 root 1.51 break;
1375 root 1.10
1376     case DISEASE:
1377     move_disease (op);
1378 root 1.51 break;
1379 root 1.10
1380     case SYMPTOM:
1381     move_symptom (op);
1382 root 1.51 break;
1383 root 1.10
1384     case THROWN_OBJ:
1385     case ARROW:
1386     move_arrow (op);
1387 root 1.51 break;
1388 root 1.10
1389     case DOOR:
1390     remove_door (op);
1391 root 1.51 break;
1392 root 1.10
1393     case LOCKED_DOOR:
1394     remove_door2 (op);
1395 root 1.51 break;
1396 root 1.10
1397     case TELEPORTER:
1398     move_teleporter (op);
1399 root 1.51 break;
1400 root 1.10
1401     case GOLEM:
1402     move_golem (op);
1403 root 1.51 break;
1404 root 1.10
1405     case EARTHWALL:
1406     hit_player (op, 2, op, AT_PHYSICAL, 1);
1407 root 1.51 break;
1408 root 1.10
1409     case FIREWALL:
1410     move_firewall (op);
1411     if (op->stats.maxsp)
1412     animate_turning (op);
1413 root 1.51 break;
1414 root 1.10
1415     case MOOD_FLOOR:
1416     do_mood_floor (op);
1417 root 1.51 break;
1418 root 1.10
1419     case GATE:
1420     move_gate (op);
1421 root 1.51 break;
1422 root 1.10
1423     case TIMED_GATE:
1424     move_timed_gate (op);
1425 root 1.51 break;
1426 root 1.10
1427     case TRIGGER:
1428     case TRIGGER_BUTTON:
1429     case TRIGGER_PEDESTAL:
1430     case TRIGGER_ALTAR:
1431     animate_trigger (op);
1432 root 1.51 break;
1433 root 1.10
1434     case DETECTOR:
1435     move_detector (op);
1436    
1437     case DIRECTOR:
1438     if (op->stats.maxsp)
1439     animate_turning (op);
1440 root 1.51 break;
1441 root 1.10
1442     case HOLE:
1443     move_hole (op);
1444 root 1.51 break;
1445 root 1.10
1446     case DEEP_SWAMP:
1447     move_deep_swamp (op);
1448 root 1.51 break;
1449 root 1.10
1450     case RUNE:
1451     case TRAP:
1452     move_rune (op);
1453 root 1.51 break;
1454 root 1.10
1455     case PLAYERMOVER:
1456     move_player_mover (op);
1457 root 1.51 break;
1458 root 1.10
1459     case CREATOR:
1460     move_creator (op);
1461 root 1.51 break;
1462 root 1.10
1463     case MARKER:
1464     move_marker (op);
1465 root 1.51 break;
1466 root 1.10
1467     case PLAYER_CHANGER:
1468     move_player_changer (op);
1469 root 1.51 break;
1470 root 1.10
1471     case PEACEMAKER:
1472     move_peacemaker (op);
1473 root 1.51 break;
1474    
1475     case PLAYER:
1476     // players have their own speed-management, so undo the --speed_left
1477     ++op->speed_left;
1478     break;
1479 root 1.84
1480     case MAPSCRIPT:
1481     move_mapscript (op);
1482     break;
1483 elmex 1.85
1484     case LAMP:
1485     case TORCH:
1486     move_lamp (op);
1487     break;
1488 root 1.115
1489     case PHYSICS: // hmm, bad naming
1490     move_physics (op);
1491     break;
1492 elmex 1.1 }
1493     }
1494 root 1.48