ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.88
Committed: Tue Jan 13 12:17:01 2009 UTC (15 years, 4 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.87: +13 -0 lines
Log Message:
reenabled 'hack' again, it's neccessary ;-/

File Contents

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