ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/time.C
Revision: 1.66
Committed: Mon Aug 27 06:29:18 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.65: +26 -39 lines
Log Message:
- create a new class, mapxy, which abstracts a mapspace position.
- rewrite move_arrow to take advantage of this new experiemntal
  class. I don't understand move_arrow, but the code without doubt
  became clearer and simpler. this opens the way of rewriting
  the rather clumsy get_map_flags etc. API into something more efficient
  below mapxy.

File Contents

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