ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.21
Committed: Wed Dec 20 11:20:50 2006 UTC (17 years, 5 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.20: +0 -4 lines
Log Message:
removed QUEST and LIGHTNING types.

File Contents

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