ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.16
Committed: Tue Dec 12 20:53:03 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.15: +42 -42 lines
Log Message:
replace some function- by method-calls

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