ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.14
Committed: Thu Sep 21 18:58:39 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +8 -7 lines
Log Message:
fix yet another crash bug

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