ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.18
Committed: Wed Dec 13 03:28:42 2006 UTC (17 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.17: +2 -2 lines
Log Message:
further cleanups and oofication

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