ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.41
Committed: Sat Mar 17 20:34:19 2007 UTC (17 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.40: +1 -12 lines
Log Message:
fix broken images on missile reflection by using the right function for the job

File Contents

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