ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.128
Committed: Wed Dec 5 19:03:27 2018 UTC (5 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.127: +3 -3 lines
Log Message:
some bugfixes

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.57 for (tmp = op->above; tmp; tmp = tmp->above)
889 root 1.106 if (!tmp->flag [FLAG_IS_FLOOR])
890 root 1.9 break;
891    
892     /* If nothing above us to move, nothing to do */
893 root 1.106 if (!tmp || tmp->flag [FLAG_WIZPASS])
894 elmex 1.1 return;
895    
896 root 1.9 if (EXIT_PATH (head))
897     {
898     if (tmp->type == PLAYER)
899     {
900     if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
901     return;
902 root 1.3
903 root 1.28 tmp->enter_exit (head);
904 root 1.6 }
905 root 1.9 else
906     /* Currently only players can transfer maps */
907     return;
908 elmex 1.1 }
909 root 1.9 else if (EXIT_X (head) || EXIT_Y (head))
910     {
911     if (out_of_map (head->map, EXIT_X (head), EXIT_Y (head)))
912     {
913     LOG (llevError, "Removed illegal teleporter.\n");
914 root 1.82 head->destroy ();
915 root 1.9 return;
916 root 1.6 }
917 root 1.17
918 root 1.9 if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
919     return;
920 root 1.17
921 root 1.9 transfer_ob (tmp, EXIT_X (head), EXIT_Y (head), 0, head);
922 elmex 1.1 }
923 root 1.9 else
924     {
925     /* Random teleporter */
926     if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (tmp)))
927     return;
928 root 1.76
929 root 1.9 teleport (head, TELEPORTER, tmp);
930 elmex 1.1 }
931     }
932    
933     /* This object will teleport someone to a different map
934     and will also apply changes to the player from its inventory.
935     This was invented for giving classes, but there's no reason it
936     can't be generalized.
937     */
938 root 1.98 static void
939 root 1.9 move_player_changer (object *op)
940     {
941     if (!op->above || !EXIT_PATH (op))
942     return;
943    
944     /* This isn't all that great - means that the player_mover
945     * needs to be on top.
946     */
947     if (op->above->type == PLAYER)
948     {
949 root 1.99 object *player = op->above;
950    
951 root 1.9 if (INVOKE_OBJECT (TRIGGER, op, ARG_OBJECT (player)))
952 root 1.34 return;
953    
954 root 1.99 for (object *walk = op->inv; walk; walk = walk->below)
955 root 1.9 apply_changes_to_player (player, walk);
956    
957 root 1.23 player->update_stats ();
958 root 1.9
959     esrv_send_inventory (op->above, op->above);
960     esrv_update_item (UPD_FACE, op->above, op->above);
961    
962     /* update players death & WoR home-position */
963 root 1.35 if (*EXIT_PATH (op) == '/')
964 root 1.9 {
965 root 1.30 player->contr->savebed_map = EXIT_PATH (op);
966     player->contr->bed_x = EXIT_X (op);
967     player->contr->bed_y = EXIT_Y (op);
968 root 1.9 }
969     else
970     LOG (llevDebug, "WARNING: destination '%s' in player_changer must be an absolute path!\n", &EXIT_PATH (op));
971    
972 root 1.28 op->above->enter_exit (op);
973 elmex 1.1 }
974     }
975    
976     /* firewalls fire other spells.
977     * The direction of the wall is stored in op->stats.sp.
978     * walls can have hp, so they can be torn down.
979     */
980 root 1.9 void
981     move_firewall (object *op)
982     {
983     object *spell;
984 elmex 1.1
985 root 1.9 if (!op->map)
986     return; /* dm has created a firewall in his inventory */
987 elmex 1.1
988 root 1.9 spell = op->inv;
989 root 1.24
990 root 1.9 if (!spell || spell->type != SPELL)
991 root 1.56 spell = op->other_arch;
992 root 1.24
993 root 1.9 if (!spell)
994     {
995 root 1.28 LOG (llevError, "move_firewall: no spell specified (%s, %s, %d, %d)\n", &op->name, &op->map->name, op->x, op->y);
996 root 1.9 return;
997 elmex 1.1 }
998    
999 root 1.9 cast_spell (op, op, op->stats.sp ? op->stats.sp : rndm (1, 8), spell, NULL);
1000 elmex 1.1 }
1001    
1002 root 1.108 /* move_player_mover: this function takes a "player mover" as an
1003 elmex 1.1 * argument, and performs the function of a player mover, which is:
1004     *
1005     * a player mover finds any players that are sitting on it. It
1006     * moves them in the op->stats.sp direction. speed is how often it'll move.
1007     * If attacktype is nonzero it will paralyze the player. If lifesave is set,
1008     * it'll dissapear after hp+1 moves. If hp is set and attacktype is set,
1009     * it'll paralyze the victim for hp*his speed/op->speed
1010     */
1011 root 1.98 static void
1012 root 1.9 move_player_mover (object *op)
1013     {
1014 root 1.108 int dir = 0;
1015 root 1.9
1016 root 1.50 for (object *victim = op->ms ().bot; victim; victim = victim->above)
1017 root 1.9 {
1018 root 1.108 if (victim->flag [FLAG_ALIVE]
1019     && !victim->flag [FLAG_WIZPASS]
1020     && (victim->move_type & op->move_type || !victim->move_type))
1021 root 1.9 {
1022 root 1.106 if (op->flag [FLAG_LIFESAVE] && op->stats.hp-- < 0)
1023 root 1.9 {
1024 root 1.108 op->destroy ();
1025 root 1.9 return;
1026     }
1027 root 1.17
1028 root 1.108 /* Determine direction only once so we do the right thing */
1029     // why is it the right thing, though?
1030     if (!dir)
1031     dir = op->stats.sp ? op->stats.sp : rndm (1, 8);
1032    
1033 root 1.125 sint16 nx = op->x + DIRX (dir);
1034     sint16 ny = op->y + DIRY (dir);
1035 root 1.108 maptile *m = op->map;
1036 root 1.9 if (get_map_flags (m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP)
1037     {
1038 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);
1039 root 1.9 return;
1040 root 1.6 }
1041 root 1.9
1042 root 1.108 if (victim->head)
1043     victim = victim->head;
1044    
1045 root 1.9 if (should_director_abort (op, victim))
1046     return;
1047    
1048 root 1.50 for (object *nextmover = m->at (nx, ny).bot; nextmover; nextmover = nextmover->above)
1049 root 1.9 {
1050     if (nextmover->type == PLAYERMOVER)
1051 root 1.50 nextmover->speed_left = -.99f;
1052    
1053 root 1.106 if (nextmover->flag [FLAG_ALIVE])
1054 root 1.50 op->speed_left = -1.1f; /* wait until the next thing gets out of the way */
1055 root 1.6 }
1056    
1057 root 1.9 if (victim->type == PLAYER)
1058     {
1059     /* only level >=1 movers move people */
1060     if (op->level)
1061     {
1062     /* Following is a bit of hack. We need to make sure it
1063     * is cleared, otherwise the player will get stuck in
1064 root 1.96 * place. This can happen if the player used a spell to
1065 root 1.9 * get to this space.
1066     */
1067     victim->contr->fire_on = 0;
1068 root 1.52 victim->speed_left = 1.f;
1069 root 1.9 move_player (victim, dir);
1070 root 1.6 }
1071 root 1.9 else
1072     return;
1073 root 1.6 }
1074 root 1.9 else
1075 root 1.103 victim->move (dir);
1076 root 1.6
1077 root 1.9 if (!op->stats.maxsp && op->attacktype)
1078     op->stats.maxsp = 2;
1079 root 1.6
1080 root 1.9 if (op->attacktype)
1081     { /* flag to paralyze the player */
1082 root 1.100 victim->speed_left = max (-5.f, -op->stats.maxsp * victim->speed / op->speed);
1083 root 1.6 }
1084     }
1085 elmex 1.1 }
1086     }
1087    
1088     /*
1089     * Will duplicate a specified object placed on top of it.
1090     * connected: what will trigger it.
1091     * level: multiplier. 0 to destroy.
1092     * other_arch: the object to look for and duplicate.
1093     */
1094    
1095 root 1.9 void
1096     move_duplicator (object *op)
1097     {
1098     object *tmp;
1099 elmex 1.1
1100 root 1.9 if (!op->other_arch)
1101     {
1102 root 1.28 LOG (llevInfo, "Duplicator with no other_arch! %d %d %s\n", op->x, op->y, op->map ? &op->map->path : "nullmap");
1103 root 1.9 return;
1104 elmex 1.1 }
1105    
1106 root 1.9 if (op->above == NULL)
1107     return;
1108 root 1.37
1109     for (tmp = op->above; tmp; tmp = tmp->above)
1110 root 1.9 {
1111 root 1.55 if (op->other_arch->archname == tmp->arch->archname)
1112 root 1.9 {
1113     if (op->level <= 0)
1114 root 1.82 tmp->destroy ();
1115 root 1.9 else
1116     {
1117     uint64 new_nrof = (uint64) tmp->nrof * op->level;
1118    
1119     if (new_nrof >= 1UL << 31)
1120     new_nrof = 1UL << 31;
1121 root 1.17
1122 root 1.9 tmp->nrof = new_nrof;
1123 root 1.6 }
1124 root 1.17
1125 root 1.9 break;
1126 root 1.6 }
1127 elmex 1.1 }
1128     }
1129    
1130 root 1.124 /* move_creator (by peterm)
1131 elmex 1.1 * it has the creator object create it's other_arch right on top of it.
1132     * connected: what will trigger it
1133     * hp: how many times it may create before stopping
1134     * lifesave: if set, it'll never disappear but will go on creating
1135     * everytime it's triggered
1136     * other_arch: the object to create
1137     * Note this can create large objects, however, in that case, it
1138     * has to make sure that there is in fact space for the object.
1139     * It should really do this for small objects also, but there is
1140     * more concern with large objects, most notably a part being placed
1141     * outside of the map which would cause the server to crash
1142     */
1143 root 1.9 void
1144     move_creator (object *creator)
1145     {
1146     object *new_ob;
1147 elmex 1.1
1148 root 1.106 if (!creator->flag [FLAG_LIFESAVE] && --creator->stats.hp < 0)
1149 root 1.9 {
1150     creator->stats.hp = -1;
1151     return;
1152 elmex 1.1 }
1153    
1154 root 1.81 if (creator->inv)
1155 root 1.9 {
1156     object *ob;
1157     int i;
1158     object *ob_to_copy;
1159    
1160     /* select random object from inventory to copy */
1161     ob_to_copy = creator->inv;
1162 root 1.112 for (ob = creator->inv->below, i = 1; ob; ob = ob->below, i++)
1163 root 1.9 {
1164     if (rndm (0, i) == 0)
1165     {
1166     ob_to_copy = ob;
1167     }
1168     }
1169 root 1.112
1170 root 1.75 new_ob = ob_to_copy->deep_clone ();
1171 root 1.106 new_ob->clr_flag (FLAG_IS_A_TEMPLATE);
1172 root 1.9 unflag_inv (new_ob, FLAG_IS_A_TEMPLATE);
1173     }
1174     else
1175     {
1176 root 1.78 if (!creator->other_arch)
1177 root 1.9 {
1178 root 1.28 LOG (llevError, "move_creator: Creator doesn't have other arch set: %s (%s, %d, %d)\n",
1179     &creator->name, &creator->map->path, creator->x, creator->y);
1180 root 1.9 return;
1181 root 1.6 }
1182 elmex 1.1
1183 root 1.9 new_ob = object_create_arch (creator->other_arch);
1184     fix_generated_item (new_ob, creator, 0, 0, GT_MINIMAL);
1185 elmex 1.1 }
1186    
1187 root 1.9 /* Make sure this multipart object fits */
1188 root 1.68 if (new_ob->arch->more && new_ob->blocked (creator->map, creator->x, creator->y))
1189 root 1.9 {
1190 root 1.81 new_ob->destroy ();
1191 root 1.9 return;
1192 elmex 1.1 }
1193    
1194 elmex 1.62 // for now lets try to identify everything generated here, it mostly
1195     // happens automated, so this will at least fix many identify-experience holes
1196 root 1.112 if (new_ob->need_identify ())
1197     new_ob->set_flag (FLAG_IDENTIFIED);
1198 elmex 1.62
1199 root 1.9 insert_ob_in_map_at (new_ob, creator->map, creator, 0, creator->x, creator->y);
1200 root 1.106 if (new_ob->flag [FLAG_FREED])
1201 root 1.9 return;
1202 elmex 1.1
1203 root 1.9 if (creator->slaying)
1204 root 1.80 new_ob->name = new_ob->title = creator->slaying;
1205 elmex 1.1 }
1206    
1207     /* move_marker --peterm@soda.csua.berkeley.edu
1208     when moved, a marker will search for a player sitting above
1209     it, and insert an invisible, weightless force into him
1210     with a specific code as the slaying field.
1211     At that time, it writes the contents of its own message
1212     field to the player. The marker will decrement hp to
1213     0 and then delete itself every time it grants a mark.
1214     unless hp was zero to start with, in which case it is infinite.*/
1215 root 1.9 void
1216     move_marker (object *op)
1217     {
1218 root 1.22 if (object *tmp = op->ms ().player ())
1219     {
1220     /* remove an old force with a slaying field == op->name */
1221 root 1.60 if (object *force = tmp->force_find (op->name))
1222 root 1.82 force->destroy ();
1223 root 1.9
1224 root 1.95 if (op->slaying && !tmp->force_find (op->slaying))
1225 root 1.22 {
1226 root 1.60 tmp->force_add (op->slaying, op->stats.food);
1227 root 1.26
1228 root 1.22 if (op->msg)
1229     new_draw_info (NDI_UNIQUE | NDI_NAVY, 0, tmp, op->msg);
1230 root 1.9
1231 root 1.22 if (op->stats.hp > 0)
1232 root 1.9 {
1233 root 1.22 op->stats.hp--;
1234 root 1.60
1235 root 1.22 if (op->stats.hp == 0)
1236 root 1.9 {
1237 root 1.22 /* marker expires--granted mark number limit */
1238 root 1.82 op->destroy ();
1239 root 1.22 return;
1240 root 1.6 }
1241 root 1.22 }
1242     }
1243     }
1244 root 1.9 }
1245    
1246 root 1.84 // mapscript objects activate themselves (only) then their timer fires
1247     // TODO: maybe they should simply trigger the link like any other object?
1248 root 1.98 static void
1249 root 1.84 move_mapscript (object *op)
1250     {
1251     op->set_speed (0);
1252     cfperl_mapscript_activate (op, true, op, 0);
1253     }
1254    
1255 root 1.98 static void
1256     move_lamp (object *op)
1257 elmex 1.85 {
1258     // if the lamp/torch is off, we should disable it.
1259     if (!op->glow_radius)
1260     {
1261     op->set_speed (0);
1262     return;
1263     }
1264 elmex 1.88 else
1265     {
1266 root 1.93 // check whether the face might need to be updated
1267 elmex 1.88 // (currently this is needed to have already switched on torches
1268 root 1.93 // on maps, as they just set the glow_radius in the archetype)
1269 elmex 1.88 if (op->other_arch
1270     && (
1271 elmex 1.89 (op->flag [FLAG_ANIMATE] != op->other_arch->flag [FLAG_ANIMATE])
1272     || (op->flag [FLAG_ANIMATE]
1273     ? (op->animation_id != op->other_arch->animation_id)
1274     : (op->face != op->other_arch->face))
1275 elmex 1.88 ))
1276     get_animation_from_arch (op, op->other_arch);
1277     }
1278 elmex 1.85
1279 root 1.93 // lamps and torches on maps don't use up their fuel
1280 elmex 1.85 if (op->is_on_map ())
1281     return;
1282    
1283     if (op->stats.food > 0)
1284     {
1285     op->stats.food--;
1286     return;
1287     }
1288    
1289     apply_lamp (op, false);
1290     }
1291    
1292 root 1.51 void
1293 root 1.9 process_object (object *op)
1294     {
1295 root 1.128 if (ecb_expect_false (op->flag [FLAG_IS_A_TEMPLATE]))
1296 root 1.51 return;
1297 root 1.9
1298 root 1.128 if (ecb_expect_false (INVOKE_OBJECT (TICK, op)))
1299 root 1.51 return;
1300 root 1.9
1301 root 1.106 if (op->flag [FLAG_MONSTER])
1302     if (move_monster (op) || op->flag [FLAG_FREED])
1303 root 1.51 return;
1304 root 1.9
1305 root 1.106 if (op->flag [FLAG_ANIMATE] && op->anim_speed == 0)
1306 root 1.9 {
1307 root 1.48 animate_object (op, op->contr ? op->facing : op->direction);
1308 root 1.9
1309 root 1.106 if (op->flag [FLAG_SEE_ANYWHERE])
1310 root 1.9 make_sure_seen (op);
1311     }
1312 root 1.10
1313 root 1.128 if (ecb_expect_false (
1314 root 1.54 op->flag [FLAG_GENERATOR]
1315     || op->flag [FLAG_CHANGING]
1316     || op->flag [FLAG_IS_USED_UP]
1317     ))
1318 root 1.9 {
1319 root 1.106 if (op->flag [FLAG_CHANGING] && !op->state)
1320 root 1.51 {
1321     change_object (op);
1322     return;
1323     }
1324 root 1.10
1325 root 1.106 if (op->flag [FLAG_GENERATOR] && !op->flag [FLAG_FRIENDLY])
1326 root 1.51 generate_monster (op);
1327 root 1.9
1328 root 1.106 if (op->flag [FLAG_IS_USED_UP] && --op->stats.food <= 0)
1329 root 1.9 {
1330 root 1.106 if (op->flag [FLAG_APPLIED])
1331 root 1.51 remove_force (op);
1332     else
1333     {
1334 root 1.80 op->remove (); // TODO: really necessary?
1335 root 1.10
1336 root 1.106 if (op->flag [FLAG_SEE_ANYWHERE])
1337 root 1.51 make_sure_not_seen (op);
1338 root 1.10
1339 root 1.81 op->drop_and_destroy ();
1340 root 1.51 }
1341    
1342     return;
1343 root 1.6 }
1344 elmex 1.1 }
1345 root 1.11
1346 root 1.9 switch (op->type)
1347     {
1348 root 1.10 case SPELL_EFFECT:
1349     move_spell_effect (op);
1350 root 1.51 break;
1351 root 1.10
1352     case ROD:
1353     case HORN:
1354     regenerate_rod (op);
1355 root 1.51 break;
1356 root 1.10
1357     case FORCE:
1358     case POTION_EFFECT:
1359     remove_force (op);
1360 root 1.51 break;
1361 elmex 1.1
1362 root 1.10 case BLINDNESS:
1363     remove_blindness (op);
1364 root 1.51 break;
1365 root 1.10
1366     case POISONING:
1367     poison_more (op);
1368 root 1.51 break;
1369 root 1.10
1370     case DISEASE:
1371     move_disease (op);
1372 root 1.51 break;
1373 root 1.10
1374     case SYMPTOM:
1375     move_symptom (op);
1376 root 1.51 break;
1377 root 1.10
1378     case THROWN_OBJ:
1379     case ARROW:
1380     move_arrow (op);
1381 root 1.51 break;
1382 root 1.10
1383     case DOOR:
1384     remove_door (op);
1385 root 1.51 break;
1386 root 1.10
1387     case LOCKED_DOOR:
1388     remove_door2 (op);
1389 root 1.51 break;
1390 root 1.10
1391     case TELEPORTER:
1392     move_teleporter (op);
1393 root 1.51 break;
1394 root 1.10
1395     case GOLEM:
1396     move_golem (op);
1397 root 1.51 break;
1398 root 1.10
1399     case EARTHWALL:
1400     hit_player (op, 2, op, AT_PHYSICAL, 1);
1401 root 1.51 break;
1402 root 1.10
1403     case FIREWALL:
1404     move_firewall (op);
1405     if (op->stats.maxsp)
1406     animate_turning (op);
1407 root 1.51 break;
1408 root 1.10
1409     case MOOD_FLOOR:
1410     do_mood_floor (op);
1411 root 1.51 break;
1412 root 1.10
1413     case GATE:
1414     move_gate (op);
1415 root 1.51 break;
1416 root 1.10
1417     case TIMED_GATE:
1418     move_timed_gate (op);
1419 root 1.51 break;
1420 root 1.10
1421     case TRIGGER:
1422     case TRIGGER_BUTTON:
1423     case TRIGGER_PEDESTAL:
1424     case TRIGGER_ALTAR:
1425     animate_trigger (op);
1426 root 1.51 break;
1427 root 1.10
1428     case DETECTOR:
1429     move_detector (op);
1430    
1431     case DIRECTOR:
1432     if (op->stats.maxsp)
1433     animate_turning (op);
1434 root 1.51 break;
1435 root 1.10
1436     case HOLE:
1437     move_hole (op);
1438 root 1.51 break;
1439 root 1.10
1440     case DEEP_SWAMP:
1441     move_deep_swamp (op);
1442 root 1.51 break;
1443 root 1.10
1444     case RUNE:
1445     case TRAP:
1446     move_rune (op);
1447 root 1.51 break;
1448 root 1.10
1449     case PLAYERMOVER:
1450     move_player_mover (op);
1451 root 1.51 break;
1452 root 1.10
1453     case CREATOR:
1454     move_creator (op);
1455 root 1.51 break;
1456 root 1.10
1457     case MARKER:
1458     move_marker (op);
1459 root 1.51 break;
1460 root 1.10
1461     case PLAYER_CHANGER:
1462     move_player_changer (op);
1463 root 1.51 break;
1464 root 1.10
1465     case PEACEMAKER:
1466     move_peacemaker (op);
1467 root 1.51 break;
1468    
1469     case PLAYER:
1470     // players have their own speed-management, so undo the --speed_left
1471     ++op->speed_left;
1472     break;
1473 root 1.84
1474     case MAPSCRIPT:
1475     move_mapscript (op);
1476     break;
1477 elmex 1.85
1478     case LAMP:
1479     case TORCH:
1480     move_lamp (op);
1481     break;
1482 root 1.115
1483     case PHYSICS: // hmm, bad naming
1484     move_physics (op);
1485     break;
1486 elmex 1.1 }
1487     }
1488 root 1.48