ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.27
Committed: Tue Dec 26 09:52:40 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.26: +2 -2 lines
Log Message:
more cleanups and bugfixes, we are reaching a local peak of stability now

File Contents

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