ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.93
Committed: Thu Sep 17 01:57:31 2009 UTC (14 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.92: +3 -3 lines
Log Message:
just a simplification

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