ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.129
Committed: Mon Jun 10 17:51:29 2024 UTC (3 days, 2 hours ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.128: +4 -1 lines
Log Message:
teleporter tries harder to teleport players

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