ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.11
Committed: Thu Sep 14 01:12:28 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.10: +2 -1 lines
Log Message:
aggressively use refcounted pointers for object references - seems to fix all random stomping. also reduced size of object further from originally 656 to 624 bytes

File Contents

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