ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.44
Committed: Sat Apr 21 22:01:57 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.43: +38 -82 lines
Log Message:
rewrote and greatly simplified generator code. if there were any issues with
elmex' monster-in-inventory stuff then they should be fixed by now.

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