ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.32
Committed: Wed Jan 3 00:56:40 2007 UTC (17 years, 4 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.31: +2 -1 lines
Log Message:
small formatting change

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