ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.12
Committed: Thu Sep 14 22:34:05 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.11: +1 -7 lines
Log Message:
indent

File Contents

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