ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.43
Committed: Sat Apr 21 16:56:32 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.42: +6 -0 lines
Log Message:
having a) monsters as treasures b) multipart monsters as treasures
and c) multipart monsters as terasures on tiled maps... hit a big
pile of bugs again.

this change:

- implements a per-map active flag. when items are being inserted
  they are activated or deactivated according to that flag.
  this could get rid of most or even all of the explicit
  activate/deactivate calls.
- implement some glue to make instantiating multipart objects easier
  (this is used inside fix_multipart_objects and might make it possible
  to put multipart objects at map borders - those were winged before)
- do finer-grained locking as to not lead to deadlocks when insert
  recurses e.g. when loading tiled maps.

File Contents

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