ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.39
Committed: Sun Mar 11 02:12:45 2007 UTC (17 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.38: +2 -2 lines
Log Message:
- MAJOR CHANGE
- you now need to use cfutil to install arches.
- former bigfaces are broken in the server
- bigfaces are no longer supported. at all.
- use face numbers instead of pointers
  * saves lotsa space
  * saves lotsa indirections
  * saves lots(?) cpu cycles
- completely rewrote face handling
- faces can now be added at runtime
- reload will add new faces
- this does not apply to animations
- use a hastable instead of binary search (faster) for faces
- face caching is broken
- facesets are gone
- server always reports MAX_FACES to any client who asks

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