2 * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Lava absorbs everything going into it. Everything.
24 * But it does not "pull" elements; only the things disappear which
25 * _do_ go directly into it. So if the player steps into the lava,
26 * he will die. If a dragonfly flies over it, it will not.
28 * This behavior is implemented in the is_space_dir and the store
29 * functions. is_space_dir returns true for the lava, too. The store
30 * function ignores any store requests into the lava.
31 * The player_get function will also behave for lava as it does for space.
39 #include "cavesound.h"
40 #include "caveengine.h"
46 static const GdDirection ccw_eighth
[]={ MV_STILL
, MV_UP_LEFT
, MV_UP
, MV_UP_RIGHT
, MV_RIGHT
, MV_DOWN_RIGHT
, MV_DOWN
, MV_DOWN_LEFT
};
47 static const GdDirection ccw_fourth
[]={ MV_STILL
, MV_LEFT
, MV_UP_LEFT
, MV_UP
, MV_UP_RIGHT
, MV_RIGHT
, MV_DOWN_RIGHT
, MV_DOWN
, MV_DOWN_LEFT
, MV_LEFT
};
48 static const GdDirection cw_eighth
[]={ MV_STILL
, MV_UP_RIGHT
, MV_RIGHT
, MV_DOWN_RIGHT
, MV_DOWN
, MV_DOWN_LEFT
, MV_LEFT
, MV_UP_LEFT
, MV_UP
};
49 static const GdDirection cw_fourth
[]={ MV_STILL
, MV_RIGHT
, MV_DOWN_RIGHT
, MV_DOWN
, MV_DOWN_LEFT
, MV_LEFT
, MV_UP_LEFT
, MV_UP
, MV_UP_RIGHT
};
51 static const GdDirection opposite
[]={ MV_STILL
, MV_DOWN
, MV_DOWN_LEFT
, MV_LEFT
, MV_UP_LEFT
, MV_UP
, MV_UP_RIGHT
, MV_RIGHT
, MV_DOWN_RIGHT
};
54 /* sets timeout sound. */
56 gd_cave_set_seconds_sound(GdCave
*cave
)
58 /* this is an integer division, so 0 seconds can be 0.5 seconds... */
59 /* also, when this reaches 8, the player still has 8.9999 seconds. so the sound is played at almost t=9s. */
60 switch(cave
->time
/cave
->timing_factor
) {
61 case 8: gd_sound_play(cave
, GD_S_TIMEOUT_1
); break;
62 case 7: gd_sound_play(cave
, GD_S_TIMEOUT_2
); break;
63 case 6: gd_sound_play(cave
, GD_S_TIMEOUT_3
); break;
64 case 5: gd_sound_play(cave
, GD_S_TIMEOUT_4
); break;
65 case 4: gd_sound_play(cave
, GD_S_TIMEOUT_5
); break;
66 case 3: gd_sound_play(cave
, GD_S_TIMEOUT_6
); break;
67 case 2: gd_sound_play(cave
, GD_S_TIMEOUT_7
); break;
68 case 1: gd_sound_play(cave
, GD_S_TIMEOUT_8
); break;
69 case 0: gd_sound_play(cave
, GD_S_TIMEOUT_9
); break;
73 /* play diamond or stone sound of given element. */
75 play_sound_of_element(GdCave
*cave
, GdElement element
)
77 /* stone and diamond fall sounds. */
82 gd_sound_play(cave
, GD_S_NUT
);
87 case O_FLYING_STONE_F
:
92 if (cave
->stone_sound
)
93 gd_sound_play(cave
, GD_S_STONE
);
98 if (cave
->nitro_sound
)
99 gd_sound_play(cave
, GD_S_NITRO
);
103 case O_FALLING_WALL_F
:
104 if (cave
->falling_wall_sound
)
105 gd_sound_play(cave
, GD_S_FALLING_WALL
);
108 case O_H_EXPANDING_WALL
:
109 case O_V_EXPANDING_WALL
:
110 case O_EXPANDING_WALL
:
111 case O_H_EXPANDING_STEEL_WALL
:
112 case O_V_EXPANDING_STEEL_WALL
:
113 case O_EXPANDING_STEEL_WALL
:
114 if (cave
->expanding_wall_sound
)
115 gd_sound_play(cave
, GD_S_EXPANDING_WALL
);
120 case O_FLYING_DIAMOND
:
121 case O_FLYING_DIAMOND_F
:
122 if (cave
->diamond_sound
)
123 gd_sound_play(cave
, GD_S_DIAMOND_RANDOM
);
126 case O_BLADDER_SPENDER
:
127 if (cave
->bladder_spender_sound
)
128 gd_sound_play(cave
, GD_S_BLADDER_SPENDER
);
132 if (cave
->bladder_convert_sound
)
133 gd_sound_play(cave
, GD_S_BLADDER_CONVERT
);
137 if (cave
->slime_sound
)
138 gd_sound_play(cave
, GD_S_SLIME
);
142 if (cave
->lava_sound
)
143 gd_sound_play(cave
, GD_S_LAVA
);
147 if (cave
->acid_spread_sound
)
148 gd_sound_play(cave
, GD_S_ACID_SPREAD
);
152 if (cave
->bladder_sound
)
153 gd_sound_play(cave
, GD_S_BLADDER_MOVE
);
160 if (cave
->biter_sound
)
161 gd_sound_play(cave
, GD_S_BITER_EAT
);
168 gd_sound_play(cave
, GD_S_DIRT_BALL
);
182 static inline GdElement
*
183 getp(const GdCave
*cave
, const int x
, const int y
)
185 return cave
->getp(cave
, x
, y
);
189 perfect (non-lineshifting) GET function. returns a pointer to a selected cave element by its coordinates.
191 static inline GdElement
*
192 getp_perfect(const GdCave
*cave
, const int x
, const int y
)
194 /* (x+n) mod n: this wors also for x>=n and -n+1<x<0 */
195 return &(cave
->map
[(y
+cave
->h
)%cave
->h
][(x
+cave
->w
)%cave
->w
]);
199 line shifting GET function; returns a pointer to the selected cave element.
200 this is used to emulate the line-shifting behaviour of original games, so that
201 the player entering one side will appear one row above or below on the other.
203 static inline GdElement
*
204 getp_shift(const GdCave
*cave
, int x
, int y
)
214 y
=(y
+cave
->h
)%cave
->h
;
215 return &(cave
->map
[y
][x
]);
219 static inline GdElement
220 get(const GdCave
*cave
, const int x
, const int y
)
222 return *getp(cave
, x
, y
);
225 /* returns an element which is somewhere near x,y */
226 static inline GdElement
227 get_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
)
229 return get(cave
, x
+gd_dx
[dir
], y
+gd_dy
[dir
]);
236 static inline gboolean
237 explodes_by_hit_dir(const GdCave
*cave
, const int x
, const int y
, GdDirection dir
)
239 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_EXPLODES_BY_HIT
)!=0;
242 /* returns true if the element is not explodable, for example the steel wall */
243 static inline gboolean
244 non_explodable(const GdCave
*cave
, const int x
, const int y
)
246 return (gd_elements
[get(cave
, x
,y
)&O_MASK
].properties
&P_NON_EXPLODABLE
)!=0;
249 /* returns true if the element can be eaten by the amoeba, eg. space and dirt. */
250 static inline gboolean
251 amoeba_eats_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
)
253 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_AMOEBA_CONSUMES
)!=0;
256 /* returns true if the element is sloped, so stones and diamonds roll down on it. for example a stone or brick wall */
257 static inline gboolean
258 sloped_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
, const GdDirection slop
)
262 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_SLOPED_LEFT
)!=0;
264 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_SLOPED_RIGHT
)!=0;
266 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_SLOPED_UP
)!=0;
268 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_SLOPED_DOWN
)!=0;
276 /* returns true if the element is sloped for bladder movement (brick=yes, diamond=no, for example) */
277 static inline gboolean
278 sloped_for_bladder_dir (const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
)
280 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_BLADDER_SLOPED
)!=0;
283 static inline gboolean
284 blows_up_flies_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
)
286 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_BLOWS_UP_FLIES
)!=0;
289 /* returns true if the element is a counter-clockwise creature */
290 static inline gboolean
291 rotates_ccw (const GdCave
*cave
, const int x
, const int y
)
293 return (gd_elements
[get(cave
, x
, y
)&O_MASK
].properties
&P_CCW
)!=0;
296 /* returns true if the element is a player */
297 static inline gboolean
298 is_player(const GdCave
*cave
, const int x
, const int y
)
300 return (gd_elements
[get(cave
, x
, y
)&O_MASK
].properties
&P_PLAYER
)!=0;
303 /* returns true if the element is a player */
304 static inline gboolean
305 is_player_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
)
307 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_PLAYER
)!=0;
310 static inline gboolean
311 can_be_hammered_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
)
313 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_CAN_BE_HAMMERED
)!=0;
317 /* returns true if the element is explodable and explodes to space, for example the player */
318 static inline gboolean
319 is_first_stage_of_explosion(const GdCave
*cave
, const int x
, const int y
)
321 return (gd_elements
[get(cave
, x
, y
)&O_MASK
].properties
&P_EXPLOSION_FIRST_STAGE
)!=0;
324 /* returns true if the element is moved by the conveyor belt */
325 static inline gboolean
326 moved_by_conveyor_top_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
)
328 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_MOVED_BY_CONVEYOR_TOP
)!=0;
331 /* returns true if the element is moved by the conveyor belt */
332 static inline gboolean
333 moved_by_conveyor_bottom_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
)
335 return (gd_elements
[get_dir(cave
, x
, y
, dir
)&O_MASK
].properties
&P_MOVED_BY_CONVEYOR_BOTTOM
)!=0;
338 static inline gboolean
339 is_scanned_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
)
341 return (get_dir(cave
, x
, y
, dir
)&SCANNED
) != 0;
349 /* returns true if neighbouring element is "e" */
350 /* treats dirt specially */
351 /* treats lava specially */
352 static inline gboolean
353 is_element_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
, GdElement e
)
355 GdElement examined
=get_dir(cave
, x
, y
, dir
);
357 /* if it is a dirt-like, change to dirt, so equality will evaluate to true */
358 if (gd_elements
[examined
& O_MASK
].properties
& P_DIRT
)
360 if (gd_elements
[e
& O_MASK
].properties
& P_DIRT
)
362 /* if the element on the map is a lava, it should be like space */
363 if (examined
==O_LAVA
)
368 /* returns true if neighbouring element is space */
369 static inline gboolean
370 is_space_dir(const GdCave
*cave
, const int x
, const int y
, const GdDirection dir
)
372 GdElement e
=get_dir(cave
, x
, y
, dir
)&O_MASK
;
374 return e
==O_SPACE
|| e
==O_LAVA
;
380 /* store an element at the given position */
382 store(GdCave
*cave
, const int x
, const int y
, const GdElement element
)
384 GdElement
*e
=getp(cave
, x
, y
);
387 play_sound_of_element(cave
, O_LAVA
);
393 /* store an element with SCANNED flag turned on */
395 store_sc(GdCave
*cave
, const int x
, const int y
, const GdElement element
)
397 store(cave
, x
, y
, element
|SCANNED
);
400 /* store an element to a neighbouring cell */
402 store_dir(GdCave
*cave
, const int x
, const int y
, const GdDirection dir
, const GdElement element
)
404 store(cave
, x
+gd_dx
[dir
], y
+gd_dy
[dir
], element
|SCANNED
);
407 /* store an element to a neighbouring cell */
409 store_dir_no_scanned(GdCave
*cave
, const int x
, const int y
, const GdDirection dir
, const GdElement element
)
411 store(cave
, x
+gd_dx
[dir
], y
+gd_dy
[dir
], element
);
414 /* move element to direction; then place space at x, y */
416 move(GdCave
*cave
, const int x
, const int y
, const GdDirection dir
, const GdElement e
)
418 store_dir(cave
, x
, y
, dir
, e
);
419 store(cave
, x
, y
, O_SPACE
);
422 /* increment a cave element; can be used for elements which are one after the other, for example bladder1, bladder2, bladder3... */
424 next(GdCave
*cave
, const int x
, const int y
)
426 (*getp(cave
, x
, y
))++;
445 cell_explode(GdCave
*cave
, int x
, int y
, GdElement explode_to
)
447 if (non_explodable (cave
, x
, y
))
450 if (cave
->voodoo_any_hurt_kills_player
&& get(cave
, x
, y
)==O_VOODOO
)
451 cave
->voodoo_touched
=TRUE
;
453 if (get(cave
, x
, y
)==O_VOODOO
&& !cave
->voodoo_disappear_in_explosion
)
454 /* voodoo turns into a time penalty */
455 store_sc(cave
, x
, y
, O_TIME_PENALTY
);
456 else if (get(cave
, x
, y
)==O_NITRO_PACK
|| get(cave
, x
, y
)==O_NITRO_PACK_F
)
457 /* nitro pack inside an explosion - it is now triggered */
458 store_sc(cave
, x
, y
, O_NITRO_PACK_EXPLODE
);
460 /* for everything else */
461 store_sc(cave
, x
, y
, explode_to
);
464 /* a creature explodes to a 3x3 something. */
466 creature_explode(GdCave
*cave
, int x
, int y
, GdElement explode_to
)
470 /* the processing of an explosion took pretty much time: processing 3x3=9 elements */
472 gd_sound_play(cave
, GD_S_EXPLOSION
);
474 for (yy
=y
-1; yy
<=y
+1; yy
++)
475 for (xx
=x
-1; xx
<=x
+1; xx
++)
476 cell_explode(cave
, xx
, yy
, explode_to
);
480 nitro_explode(GdCave
*cave
, int x
, int y
)
484 /* the processing of an explosion took pretty much time: processing 3x3=9 elements */
486 gd_sound_play(cave
, GD_S_NITRO_EXPLOSION
);
488 for (yy
=y
-1; yy
<=y
+1; yy
++)
489 for (xx
=x
-1; xx
<=x
+1; xx
++)
490 cell_explode(cave
, xx
, yy
, O_NITRO_EXPL_1
);
491 /* the current cell is explicitly changed into a nitro expl, as cell_explode changes it to a triggered nitro pack */
492 store_sc(cave
, x
, y
, O_NITRO_EXPL_1
);
495 /* a voodoo explodes, leaving a 3x3 steel and a time penalty behind. */
497 voodoo_explode(GdCave
*cave
, int x
, int y
)
501 /* the processing of an explosion took pretty much time: processing 3x3=9 elements */
504 gd_sound_play(cave
, GD_S_VOODOO_EXPLOSION
);
505 if (cave
->voodoo_any_hurt_kills_player
)
506 cave
->voodoo_touched
=TRUE
;
508 /* voodoo explodes to 3x3 steel */
509 for (yy
=y
-1; yy
<=y
+1; yy
++)
510 for (xx
=x
-1; xx
<=x
+1; xx
++)
511 store_sc(cave
, xx
, yy
, O_PRE_STEEL_1
);
512 /* middle is a time penalty (which will be turned into a gravestone) */
513 store_sc(cave
, x
, y
, O_TIME_PENALTY
);
516 /* a bomb does not explode the voodoo, neither does the ghost.
517 this function check this, and stores the new element or not.
518 destroying the voodoo is also controlled by the voodoo_disappear_in_explosion flag. */
520 explode_try_skip_voodoo(GdCave
*cave
, const int x
, const int y
, const GdElement expl
)
522 if (non_explodable (cave
, x
, y
))
524 /* bomb does not explode voodoo */
525 if (!cave
->voodoo_disappear_in_explosion
&& get(cave
, x
, y
)==O_VOODOO
)
527 if (cave
->voodoo_any_hurt_kills_player
&& get(cave
, x
, y
)==O_VOODOO
)
528 cave
->voodoo_touched
=TRUE
;
529 store_sc (cave
, x
, y
, expl
);
532 /* X shaped ghost explosion; does not touch voodoo! */
534 ghost_explode(GdCave
*cave
, const int x
, const int y
)
536 gd_sound_play(cave
, GD_S_GHOST_EXPLOSION
);
538 /* the processing of an explosion took pretty much time: processing 5 elements */
541 explode_try_skip_voodoo(cave
, x
, y
, O_GHOST_EXPL_1
);
542 explode_try_skip_voodoo(cave
, x
-1, y
-1, O_GHOST_EXPL_1
);
543 explode_try_skip_voodoo(cave
, x
+1, y
+1, O_GHOST_EXPL_1
);
544 explode_try_skip_voodoo(cave
, x
-1, y
+1, O_GHOST_EXPL_1
);
545 explode_try_skip_voodoo(cave
, x
+1, y
-1, O_GHOST_EXPL_1
);
548 /*+shaped bomb explosion; does not touch voodoo! */
550 bomb_explode(GdCave
*cave
, const int x
, const int y
)
552 gd_sound_play(cave
, GD_S_BOMB_EXPLOSION
);
554 /* the processing of an explosion took pretty much time: processing 5 elements */
557 explode_try_skip_voodoo(cave
, x
, y
, O_BOMB_EXPL_1
);
558 explode_try_skip_voodoo(cave
, x
-1, y
, O_BOMB_EXPL_1
);
559 explode_try_skip_voodoo(cave
, x
+1, y
, O_BOMB_EXPL_1
);
560 explode_try_skip_voodoo(cave
, x
, y
+1, O_BOMB_EXPL_1
);
561 explode_try_skip_voodoo(cave
, x
, y
-1, O_BOMB_EXPL_1
);
565 explode an element with the appropriate type of exlposion.
568 explode(GdCave
*cave
, int x
, int y
)
570 GdElement e
=get(cave
, x
, y
)&O_MASK
;
574 ghost_explode(cave
, x
, y
);
578 bomb_explode(cave
, x
, y
);
582 voodoo_explode(cave
, x
, y
);
587 case O_NITRO_PACK_EXPLODE
:
588 nitro_explode(cave
, x
, y
);
592 creature_explode(cave
, x
, y
, O_AMOEBA_2_EXPL_1
);
595 case O_FALLING_WALL_F
:
596 creature_explode(cave
, x
, y
, O_EXPLODE_1
);
603 creature_explode(cave
, x
, y
, cave
->butterfly_explode_to
);
610 creature_explode(cave
, x
, y
, cave
->alt_butterfly_explode_to
);
617 creature_explode(cave
, x
, y
, cave
->firefly_explode_to
);
620 case O_ALT_FIREFLY_1
:
621 case O_ALT_FIREFLY_2
:
622 case O_ALT_FIREFLY_3
:
623 case O_ALT_FIREFLY_4
:
624 creature_explode(cave
, x
, y
, cave
->alt_firefly_explode_to
);
630 case O_PLAYER_STIRRING
:
631 case O_PLAYER_PNEUMATIC_LEFT
:
632 case O_PLAYER_PNEUMATIC_RIGHT
:
633 creature_explode(cave
, x
, y
, O_EXPLODE_1
);
640 creature_explode(cave
, x
, y
, cave
->stonefly_explode_to
);
647 creature_explode(cave
, x
, y
, cave
->dragonfly_explode_to
);
651 g_assert_not_reached();
657 explode_dir(GdCave
*cave
, const int x
, const int y
, GdDirection dir
)
659 explode(cave
, x
+gd_dx
[dir
], y
+gd_dy
[dir
]);
664 player eats specified object.
665 returns O_SPACE if he eats it (diamond, dirt, space, outbox)
666 returns other element if something other appears there and he can't move.
667 cave pointer is needed to know the diamond values.
670 player_get_element (GdCave
* cave
, const GdElement object
)
676 cave
->diamond_key_collected
=TRUE
;
677 gd_sound_play(cave
, GD_S_DIAMOND_KEY_COLLECT
);
682 gd_sound_play(cave
, GD_S_KEY_COLLECT
);
686 gd_sound_play(cave
, GD_S_KEY_COLLECT
);
690 gd_sound_play(cave
, GD_S_KEY_COLLECT
);
696 gd_sound_play(cave
, GD_S_DOOR_OPEN
);
702 gd_sound_play(cave
, GD_S_DOOR_OPEN
);
708 gd_sound_play(cave
, GD_S_DOOR_OPEN
);
713 case O_CREATURE_SWITCH
: /* creatures change direction. */
714 gd_sound_play(cave
, GD_S_SWITCH_CREATURES
);
715 cave
->creatures_backwards
=!cave
->creatures_backwards
;
717 case O_EXPANDING_WALL_SWITCH
: /* expanding wall change direction. */
718 gd_sound_play(cave
, GD_S_SWITCH_EXPANDING
);
719 cave
->expanding_wall_changed
=!cave
->expanding_wall_changed
;
721 case O_BITER_SWITCH
: /* biter change delay */
722 gd_sound_play(cave
, GD_S_SWITCH_BITER
);
723 cave
->biter_delay_frame
++;
724 if (cave
->biter_delay_frame
==4)
725 cave
->biter_delay_frame
=0;
727 case O_REPLICATOR_SWITCH
: /* replicator on/off switch */
728 gd_sound_play(cave
, GD_S_SWITCH_REPLICATOR
);
729 cave
->replicators_active
=!cave
->replicators_active
;
731 case O_CONVEYOR_SWITCH
: /* conveyor belts on/off */
732 gd_sound_play(cave
, GD_S_SWITCH_CONVEYOR
);
733 cave
->conveyor_belts_active
=!cave
->conveyor_belts_active
;
735 case O_CONVEYOR_DIR_SWITCH
: /* conveyor belts switch direction */
736 gd_sound_play(cave
, GD_S_SWITCH_CONVEYOR
);
737 cave
->conveyor_belts_direction_changed
=!cave
->conveyor_belts_direction_changed
;
743 case O_STEEL_EATABLE
:
744 case O_BRICK_EATABLE
:
745 case O_DIRT_SLOPED_UP_RIGHT
:
746 case O_DIRT_SLOPED_UP_LEFT
:
747 case O_DIRT_SLOPED_DOWN_LEFT
:
748 case O_DIRT_SLOPED_DOWN_RIGHT
:
751 gd_sound_play(cave
, GD_S_WALK_EARTH
);
755 gd_sound_play(cave
, GD_S_SWEET_COLLECT
);
756 cave
->sweet_eaten
=TRUE
;
759 case O_PNEUMATIC_HAMMER
:
760 gd_sound_play(cave
, GD_S_PNEUMATIC_COLLECT
);
761 cave
->got_pneumatic_hammer
=TRUE
;
766 gd_sound_play(cave
, GD_S_CLOCK_COLLECT
);
767 cave
->time
+=cave
->time_bonus
*cave
->timing_factor
;
768 if (cave
->time
>cave
->max_time
*cave
->timing_factor
)
769 cave
->time
-=cave
->max_time
*cave
->timing_factor
;
770 /* no space, rather a dirt remains there... */
773 case O_FLYING_DIAMOND
:
774 gd_sound_play(cave
, GD_S_DIAMOND_COLLECT
);
775 cave
->score
+=cave
->diamond_value
;
776 cave
->diamonds_collected
++;
777 if (cave
->diamonds_needed
==cave
->diamonds_collected
) {
778 cave
->gate_open
=TRUE
;
779 cave
->diamond_value
=cave
->extra_diamond_value
; /* extra is worth more points. */
780 cave
->gate_open_flash
=1;
781 cave
->sound3
=GD_S_CRACK
;
785 cave
->skeletons_collected
++;
786 for (i
=0; i
<cave
->skeletons_worth_diamonds
; i
++)
787 player_get_element(cave
, O_DIAMOND
); /* as if player got a diamond */
788 gd_sound_play(cave
, GD_S_SKELETON_COLLECT
); /* _after_ calling get_element for the fake diamonds, so we overwrite its sounds */
792 cave
->player_state
=GD_PL_EXITED
; /* player now exits the cave! */
795 case O_LAVA
: /* player goes into lava, as if it was space */
796 gd_sound_play(cave
, GD_S_WALK_EMPTY
);
800 /* the object will remain there. */
806 process a crazy dream-style teleporter.
807 called from gd_cave_iterate, for a player or a player_bomb.
808 player is standing at px, py, and trying to move in the direction player_move,
809 where there is a teleporter.
810 we check the whole cave, from px+1,py, till we get back to px,py (by wrapping
811 around). the first teleporter we find, and which is suitable, will be the destination.
812 return TRUE if teleporter worked, FALSE if cound not find any suitable teleporter.
815 do_teleporter(GdCave
*cave
, int px
, int py
, GdDirection player_move
)
823 /* jump to next element; wrap around columns and rows. */
831 /* if we found a teleporter... */
832 if (get(cave
, tx
, ty
)==O_TELEPORTER
&& is_space_dir(cave
, tx
, ty
, player_move
)) {
833 store_dir(cave
, tx
, ty
, player_move
, get(cave
, px
, py
)); /* new player appears near teleporter found */
834 store(cave
, px
, py
, O_SPACE
); /* current player disappears */
835 gd_sound_play(cave
, GD_S_TELEPORTER
);
836 return TRUE
; /* return true as teleporter worked */
838 } while (tx
!=px
|| ty
!=py
); /* loop until we get back to original coordinates */
839 return FALSE
; /* return false as we did not find any usable teleporter */
843 try to push an element.
844 returns true if the push is possible; also does move the specified _element_.
845 up to the caller to move the _player_itself_.
849 do_push(GdCave
*cave
, int x
, int y
, GdDirection player_move
, gboolean player_fire
)
852 GdElement what
=get_dir(cave
, x
, y
, player_move
);
853 GdDirection grav_compat
=cave
->gravity_affects_all
?cave
->gravity
:MV_DOWN
; /* gravity for falling wall, bladder, ... */
858 case O_WAITING_STONE
:
861 case O_CHASING_STONE
:
865 /* pushing some kind of stone or nut */
866 /* directions possible: 90degrees cw or ccw to current gravity. */
867 /* only push if player dir is orthogonal to gravity, ie. gravity down, pushing left&right possible */
868 if (player_move
==ccw_fourth
[cave
->gravity
] || player_move
==cw_fourth
[cave
->gravity
]) {
872 /* different probabilities for different elements. */
874 case O_WAITING_STONE
:
875 prob
=1000000; /* waiting stones are light, can always push */
877 case O_CHASING_STONE
:
878 if (cave
->sweet_eaten
) /* chasing can be pushed if player is turbo */
882 if (cave
->mega_stones_pushable_with_sweet
&& cave
->sweet_eaten
) /* mega may(!) be pushed if player is turbo */
889 if (cave
->sweet_eaten
)
890 prob
=cave
->pushing_stone_prob_sweet
*1000000; /* probability with sweet */
892 prob
=cave
->pushing_stone_prob
*1000000; /* probability without sweet. */
895 g_assert_not_reached();
899 if (is_space_dir(cave
, x
, y
, MV_TWICE
+player_move
) && g_rand_int_range(cave
->random
, 0, 1000000)<prob
) {
900 /* if decided that he will be able to push, */
901 store_dir(cave
, x
, y
, MV_TWICE
+player_move
, what
);
902 play_sound_of_element(cave
, what
);
917 /* pushing a bladder. keep in mind that after pushing, we always get an O_BLADDER,
918 * not an O_BLADDER_x. */
919 /* there is no "delayed" state of a bladder, so we use store_dir_no_scanned! */
921 /* first check: we cannot push a bladder "up" */
922 if (player_move
!=opposite
[grav_compat
]) {
923 /* pushing a bladder "down". p=player, o=bladder, 1, 2, 3=directions to check. */
924 /* player moving in the direction of gravity. */
928 if (player_move
==grav_compat
) {
929 if (is_space_dir(cave
, x
, y
, MV_TWICE
+player_move
)) /* pushing bladder down */
930 store_dir_no_scanned(cave
, x
, y
, MV_TWICE
+player_move
, O_BLADDER
), result
=TRUE
;
931 else if (is_space_dir(cave
, x
, y
, cw_eighth
[grav_compat
])) /* if no space to push down, maybe left (down-left to player) */
932 /* left is "down, turned right (cw)" */
933 store_dir_no_scanned(cave
, x
, y
, cw_eighth
[grav_compat
], O_BLADDER
), result
=TRUE
;
934 else if (is_space_dir(cave
, x
, y
, ccw_eighth
[grav_compat
])) /* if not, maybe right (down-right to player) */
935 store_dir_no_scanned(cave
, x
, y
, ccw_eighth
[grav_compat
], O_BLADDER
), result
=TRUE
;
937 /* pushing a bladder "left". p=player, o=bladder, 1, 2, 3=directions to check. */
941 else if (player_move
==cw_fourth
[grav_compat
]) {
942 if (is_space_dir(cave
, x
, y
, MV_TWICE
+cw_fourth
[grav_compat
])) /* pushing it left */
943 store_dir_no_scanned(cave
, x
, y
, MV_TWICE
+cw_fourth
[grav_compat
], O_BLADDER
), result
=TRUE
;
944 else if (is_space_dir(cave
, x
, y
, cw_eighth
[grav_compat
])) /* maybe down, and player will move left */
945 store_dir_no_scanned(cave
, x
, y
, cw_eighth
[grav_compat
], O_BLADDER
), result
=TRUE
;
946 else if (is_space_dir(cave
, x
, y
, cw_eighth
[player_move
])) /* maybe up, and player will move left */
947 store_dir_no_scanned(cave
, x
, y
, cw_eighth
[player_move
], O_BLADDER
), result
=TRUE
;
949 /* pushing a bladder "right". p=player, o=bladder, 1, 2, 3=directions to check. */
953 else if (player_move
==ccw_fourth
[grav_compat
]) {
954 if (is_space_dir(cave
, x
, y
, MV_TWICE
+player_move
)) /* pushing it right */
955 store_dir_no_scanned(cave
, x
, y
, MV_TWICE
+player_move
, O_BLADDER
), result
=TRUE
;
956 else if (is_space_dir(cave
, x
, y
, ccw_eighth
[grav_compat
])) /* maybe down, and player will move right */
957 store_dir_no_scanned(cave
, x
, y
, ccw_eighth
[grav_compat
], O_BLADDER
), result
=TRUE
;
958 else if (is_space_dir(cave
, x
, y
, ccw_eighth
[player_move
])) /* maybe up, and player will move right */
959 store_dir_no_scanned(cave
, x
, y
, ccw_eighth
[player_move
], O_BLADDER
), result
=TRUE
;
963 play_sound_of_element(cave
, O_BLADDER
);
968 /* a box is only pushed with the fire pressed */
970 /* but always with 100% probability */
971 switch (player_move
) {
976 /* pushing in some dir, two steps in that dir - is there space? */
977 if (is_space_dir(cave
, x
, y
, player_move
+MV_TWICE
)) {
979 store_dir(cave
, x
, y
, player_move
+MV_TWICE
, O_BOX
);
981 gd_sound_play(cave
, GD_S_BOX_PUSH
);
985 /* push in no other directions possible */
991 /* pushing of other elements not possible */
999 /* from the key press booleans, create a direction */
1001 gd_direction_from_keypress(gboolean up
, gboolean down
, gboolean left
, gboolean right
)
1003 GdDirection player_move
;
1005 /* from the key press booleans, create a direction */
1007 player_move
=MV_UP_RIGHT
;
1008 else if (down
&& right
)
1009 player_move
=MV_DOWN_RIGHT
;
1010 else if (down
&& left
)
1011 player_move
=MV_DOWN_LEFT
;
1012 else if (up
&& left
)
1013 player_move
=MV_UP_LEFT
;
1017 player_move
=MV_DOWN
;
1019 player_move
=MV_LEFT
;
1021 player_move
=MV_RIGHT
;
1023 player_move
=MV_STILL
;
1029 /* clear these to no sound; and they will be set during iteration. */
1031 gd_cave_clear_sounds(GdCave
*cave
)
1033 cave
->sound1
=GD_S_NONE
;
1034 cave
->sound2
=GD_S_NONE
;
1035 cave
->sound3
=GD_S_NONE
;
1038 /* process a cave. */
1040 gd_cave_iterate(GdCave
*cave
, GdDirection player_move
, gboolean player_fire
, gboolean suicide
)
1043 int ymin
, ymax
; /* for border scan */
1044 gboolean amoeba_found_enclosed
, amoeba_2_found_enclosed
; /* amoeba found to be enclosed. if not, this is cleared */
1045 int amoeba_count
, amoeba_2_count
; /* counting the number of amoebas. after scan, check if too much */
1046 gboolean found_water
; /* cave scan found water - for sound */
1047 gboolean inbox_toggle
;
1048 gboolean start_signal
;
1049 GdDirection grav_compat
=cave
->gravity_affects_all
?cave
->gravity
:MV_DOWN
; /* gravity for falling wall, bladder, ... */
1050 /* directions for o_something_1, 2, 3 and 4 (creatures) */
1051 static const GdDirection creature_dir
[]={ MV_LEFT
, MV_UP
, MV_RIGHT
, MV_DOWN
};
1052 static const GdDirection creature_chdir
[]={ MV_RIGHT
, MV_DOWN
, MV_LEFT
, MV_UP
};
1053 int time_decrement_sec
;
1054 GdElement biter_try
[]={ O_DIRT
, cave
->biter_eat
, O_SPACE
, O_STONE
}; /* biters eating elements preference, they try to go in this order */
1055 gboolean amoeba_sound
, magic_sound
;
1057 gd_cave_clear_sounds(cave
);
1059 /* if diagonal movements not allowed, */
1060 /* horizontal movements have precedence. [BROADRIBB] */
1061 if (!cave
->diagonal_movements
) {
1062 switch (player_move
) {
1065 player_move
=MV_RIGHT
;
1069 player_move
=MV_LEFT
;
1072 /* no correction needed */
1077 /* set cave get function; to implement perfect or lineshifting borders */
1078 if (cave
->lineshift
)
1079 cave
->getp
=getp_shift
;
1081 cave
->getp
=getp_perfect
;
1083 /* increment this. if the scan routine comes across player, clears it (sets to zero). */
1084 if (cave
->player_seen_ago
<100)
1085 cave
->player_seen_ago
++;
1087 if (cave
->pneumatic_hammer_active_delay
>0)
1088 cave
->pneumatic_hammer_active_delay
--;
1090 /* inboxes and outboxes flash with the rhythm of the game, not the display.
1091 * also, a player can be born only from an open, not from a steel-wall-like inbox. */
1092 cave
->inbox_flash_toggle
=!cave
->inbox_flash_toggle
;
1093 inbox_toggle
=cave
->inbox_flash_toggle
;
1095 if (cave
->gate_open_flash
>0)
1096 cave
->gate_open_flash
--;
1098 /* score collected this frame */
1101 /* suicide only kills the active player */
1102 /* player_x, player_y was set by the previous iterate routine, or the cave setup. */
1103 /* we must check if there is a player or not - he may have exploded or something like that */
1104 if (suicide
&& cave
->player_state
==GD_PL_LIVING
&& is_player(cave
, cave
->player_x
, cave
->player_y
))
1105 store(cave
, cave
->player_x
, cave
->player_y
, O_EXPLODE_1
);
1107 /* check for walls reappearing */
1108 if (cave
->hammered_reappear
)
1109 for (y
=0; y
<cave
->h
; y
++)
1110 for (x
=0; x
<cave
->w
; x
++) {
1111 /* timer for the cell > 0? */
1112 if (cave
->hammered_reappear
[y
][x
]>0) {
1113 /* decrease timer */
1114 cave
->hammered_reappear
[y
][x
]--;
1115 /* check if it became zero */
1116 if (cave
->hammered_reappear
[y
][x
]==0) {
1117 store(cave
, x
, y
, O_BRICK
);
1118 gd_sound_play(cave
, GD_S_WALL_REAPPEAR
);
1123 /* variables to check during the scan */
1124 amoeba_found_enclosed
=TRUE
; /* will be set to false if any of the amoeba is found free. */
1125 amoeba_2_found_enclosed
=TRUE
;
1130 time_decrement_sec
=0;
1132 /* check whether to scan the first and last line */
1133 if (cave
->border_scan_first_and_last
) {
1140 /* the cave scan routine */
1141 for (y
=ymin
; y
<=ymax
; y
++)
1142 for (x
=0; x
<cave
->w
; x
++) {
1143 /* if we find a scanned element, change it to the normal one, and that's all. */
1144 /* this is required, for example for chasing stones, which have moved, always passing slime! */
1145 if (get(cave
, x
, y
)&SCANNED
) {
1146 store(cave
, x
, y
, get(cave
, x
, y
)& ~SCANNED
);
1150 /* add the ckdelay correction value for every element seen. */
1151 cave
->ckdelay
+=gd_elements
[get(cave
, x
, y
)].ckdelay
;
1153 switch (get(cave
, x
, y
)) {
1158 if (cave
->kill_player
) {
1159 explode (cave
, x
, y
);
1162 cave
->player_seen_ago
=0;
1163 /* bd4 intermission caves have many players. so if one of them has exited,
1164 * do not change the flag anymore. so this if () is needed */
1165 if (cave
->player_state
!=GD_PL_EXITED
)
1166 cave
->player_state
=GD_PL_LIVING
;
1168 /* check for pneumatic hammer things */
1169 /* 1) press fire, 2) have pneumatic hammer 4) space on left or right for hammer 5) stand on something */
1170 if (player_fire
&& cave
->got_pneumatic_hammer
&& is_space_dir(cave
, x
, y
, player_move
)
1171 && !is_space_dir(cave
, x
, y
, MV_DOWN
)) {
1172 if (player_move
==MV_LEFT
&& can_be_hammered_dir(cave
, x
, y
, MV_DOWN_LEFT
)) {
1173 cave
->pneumatic_hammer_active_delay
=cave
->pneumatic_hammer_frame
;
1174 store_dir(cave
, x
, y
, MV_LEFT
, O_PNEUMATIC_ACTIVE_LEFT
);
1175 store(cave
, x
, y
, O_PLAYER_PNEUMATIC_LEFT
);
1176 break; /* finished. */
1178 if (player_move
==MV_RIGHT
&& can_be_hammered_dir(cave
, x
, y
, MV_DOWN_RIGHT
)) {
1179 cave
->pneumatic_hammer_active_delay
=cave
->pneumatic_hammer_frame
;
1180 store_dir(cave
, x
, y
, MV_RIGHT
, O_PNEUMATIC_ACTIVE_RIGHT
);
1181 store(cave
, x
, y
, O_PLAYER_PNEUMATIC_RIGHT
);
1182 break; /* finished. */
1186 if (player_move
!=MV_STILL
) {
1187 /* only do every check if he is not moving */
1188 GdElement what
=get_dir(cave
, x
, y
, player_move
);
1189 GdElement remains
=what
;
1192 /* if we are 'eating' a teleporter, and the function returns true (teleporting worked), break here */
1193 if (what
==O_TELEPORTER
&& do_teleporter(cave
, x
, y
, player_move
))
1196 /* try to push element; if successful, break */
1197 push
=do_push(cave
, x
, y
, player_move
, player_fire
);
1203 /* if its a bomb, remember he now has one. */
1204 /* we do not change the "remains" and "what" variables, so that part of the code will be ineffective */
1205 gd_sound_play(cave
, GD_S_BOMB_COLLECT
);
1206 store_dir(cave
, x
, y
, player_move
, O_SPACE
);
1208 store(cave
, x
, y
, O_PLAYER_BOMB
);
1210 move(cave
, x
, y
, player_move
, O_PLAYER_BOMB
);
1214 /* we do not change the "remains" and "what" variables, so that part of the code will be ineffective */
1215 if (!player_fire
&& !cave
->gravity_switch_active
&& cave
->skeletons_collected
>=cave
->skeletons_needed_for_pot
) {
1216 cave
->skeletons_collected
-=cave
->skeletons_needed_for_pot
;
1217 move(cave
, x
, y
, player_move
, O_PLAYER_STIRRING
);
1218 cave
->gravity_disabled
=TRUE
;
1222 case O_GRAVITY_SWITCH
:
1223 /* (we cannot use player_get for this as it does not have player_move parameter) */
1224 /* only allow changing direction if the new dir is not diagonal */
1225 if (cave
->gravity_switch_active
&& (player_move
==MV_LEFT
|| player_move
==MV_RIGHT
|| player_move
==MV_UP
|| player_move
==MV_DOWN
)) {
1226 gd_sound_play(cave
, GD_S_SWITCH_GRAVITY
);
1227 cave
->gravity_will_change
=cave
->gravity_change_time
*cave
->timing_factor
;
1228 cave
->gravity_next_direction
=player_move
;
1229 cave
->gravity_switch_active
=FALSE
;
1234 /* get element - process others. if cannot get, player_get_element will return the same */
1235 remains
=player_get_element (cave
, what
);
1239 if (remains
!=what
|| remains
==O_SPACE
) {
1240 /* if anything changed, apply the change. */
1242 /* if snapping anything and we have snapping explosions set. but these is not true for pushing. */
1243 if (remains
==O_SPACE
&& player_fire
&& !push
)
1244 remains
=cave
->snap_element
;
1245 if (remains
!=O_SPACE
|| player_fire
)
1246 /* if any other element than space, player cannot move. also if pressing fire, will not move. */
1247 store_dir(cave
, x
, y
, player_move
, remains
);
1249 /* if space remains there, the player moves. */
1250 move(cave
, x
, y
, player_move
, O_PLAYER
);
1257 /* much simpler; cannot steal stones */
1258 if (cave
->kill_player
) {
1259 explode (cave
, x
, y
);
1262 cave
->player_seen_ago
=0;
1263 /* bd4 intermission caves have many players. so if one of them has exited,
1264 * do not change the flag anymore. so this if () is needed */
1265 if (cave
->player_state
!=GD_PL_EXITED
)
1266 cave
->player_state
=GD_PL_LIVING
;
1268 if (player_move
!=MV_STILL
) { /* if the player does not move, nothing to do */
1269 GdElement what
=get_dir(cave
, x
, y
, player_move
);
1270 GdElement remains
=what
;
1273 /* placing a bomb into empty space or dirt */
1274 if (is_space_dir(cave
, x
, y
, player_move
) || is_element_dir(cave
, x
, y
, player_move
, O_DIRT
)) {
1275 store_dir(cave
, x
, y
, player_move
, O_BOMB_TICK_1
);
1276 /* placed bomb, he is normal player again */
1277 store(cave
, x
, y
, O_PLAYER
);
1278 gd_sound_play(cave
, GD_S_BOMB_PLACE
);
1283 /* pushing and collecting */
1284 /* if we are 'eating' a teleporter, and the function returns true (teleporting worked), break here */
1285 if (what
==O_TELEPORTER
&& do_teleporter(cave
, x
, y
, player_move
))
1288 if (do_push(cave
, x
, y
, player_move
, FALSE
)) /* player fire is false... */
1292 case O_GRAVITY_SWITCH
:
1293 /* (we cannot use player_get for this as it does not have player_move parameter) */
1294 /* only allow changing direction if the new dir is not diagonal */
1295 if (cave
->gravity_switch_active
&& (player_move
==MV_LEFT
|| player_move
==MV_RIGHT
|| player_move
==MV_UP
|| player_move
==MV_DOWN
)) {
1296 gd_sound_play(cave
, GD_S_SWITCH_GRAVITY
);
1297 cave
->gravity_will_change
=cave
->gravity_change_time
*cave
->timing_factor
;
1298 cave
->gravity_next_direction
=player_move
;
1299 cave
->gravity_switch_active
=FALSE
;
1303 /* get element. if cannot get, player_get_element will return the same */
1304 remains
=player_get_element (cave
, what
);
1309 /* if element changed, OR there is space, move. */
1310 if (remains
!=what
|| remains
==O_SPACE
) {
1311 /* if anything changed, apply the change. */
1312 move(cave
, x
, y
, player_move
, O_PLAYER_BOMB
);
1317 case O_PLAYER_STIRRING
:
1318 if (cave
->kill_player
) {
1319 explode (cave
, x
, y
);
1322 gd_sound_play(cave
, GD_S_STIRRING
); /* stirring sound, if no other walking sound or explosion */
1323 cave
->player_seen_ago
=0;
1324 /* bd4 intermission caves have many players. so if one of them has exited,
1325 * do not change the flag anymore. so this if () is needed */
1326 if (cave
->player_state
!=GD_PL_EXITED
)
1327 cave
->player_state
=GD_PL_LIVING
;
1329 /* player "exits" stirring the pot by pressing fire */
1330 cave
->gravity_disabled
=FALSE
;
1331 store(cave
, x
, y
, O_PLAYER
);
1332 cave
->gravity_switch_active
=TRUE
;
1336 /* player holding pneumatic hammer */
1337 case O_PLAYER_PNEUMATIC_LEFT
:
1338 case O_PLAYER_PNEUMATIC_RIGHT
:
1339 /* usual player stuff */
1340 if (cave
->kill_player
) {
1341 explode (cave
, x
, y
);
1344 cave
->player_seen_ago
=0;
1345 if (cave
->player_state
!=GD_PL_EXITED
)
1346 cave
->player_state
=GD_PL_LIVING
;
1347 if (cave
->pneumatic_hammer_active_delay
==0) /* if hammering time is up, becomes a normal player again. */
1348 store(cave
, x
, y
, O_PLAYER
);
1351 /* the active pneumatic hammer itself */
1352 case O_PNEUMATIC_ACTIVE_RIGHT
:
1353 case O_PNEUMATIC_ACTIVE_LEFT
:
1354 if (cave
->pneumatic_hammer_active_delay
==0) {
1357 store(cave
, x
, y
, O_SPACE
); /* pneumatic hammer element disappears */
1358 /* which is the new element which appears after that one is hammered? */
1359 new_elem
=gd_element_get_hammered(get_dir(cave
, x
, y
, MV_DOWN
));
1360 /* if there is a new element, display it */
1361 /* O_NONE might be returned, for example if the element being hammered explodes during hammering (by a nearby explosion) */
1362 if (new_elem
!=O_NONE
) {
1363 store_dir(cave
, x
, y
, MV_DOWN
, new_elem
);
1365 /* and if walls reappear, remember it in array */
1366 if (cave
->hammered_walls_reappear
) {
1369 wall_y
=(y
+1)%cave
->h
;
1370 cave
->hammered_reappear
[wall_y
][x
]=cave
->hammered_wall_reappear_frame
;
1378 * S T O N E S, D I A M O N D S
1380 case O_STONE
: /* standing stone */
1381 case O_MEGA_STONE
: /* standing mega_stone */
1382 case O_DIAMOND
: /* standing diamond */
1383 case O_NUT
: /* standing nut */
1384 if (!cave
->gravity_disabled
) {
1385 /* if gravity is enabled, the stone might fall. */
1388 switch (get(cave
, x
, y
)) {
1390 falling
=cave
->stone_falling_effect
;
1393 falling
=O_MEGA_STONE_F
;
1396 falling
=cave
->diamond_falling_effect
;
1402 g_assert_not_reached();
1405 if (is_space_dir(cave
, x
, y
, cave
->gravity
)) { /* beginning to fall */
1406 play_sound_of_element(cave
, get(cave
, x
, y
));
1407 move(cave
, x
, y
, cave
->gravity
, falling
);
1409 /* check if it is on a sloped element, and it can roll. */
1410 /* for example, sloped wall looks like: */
1413 /* this is tagged as sloped up&left. */
1414 /* first check if the stone or diamond is coming from "up" (ie. opposite of gravity) */
1415 /* then check the direction to roll (left or right) */
1416 /* this way, gravity can also be pointing right, and the above slope will work as one would expect */
1417 else if (sloped_dir(cave
, x
, y
, cave
->gravity
, opposite
[cave
->gravity
])) { /* rolling down, if sitting on a sloped object */
1418 if (sloped_dir(cave
, x
, y
, cave
->gravity
, cw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, cw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, cw_eighth
[cave
->gravity
])) {
1419 /* rolling left? - keep in mind that ccw_fourth rotates gravity ccw, so here we use cw_fourth */
1420 play_sound_of_element(cave
, get(cave
, x
, y
));
1421 move(cave
, x
, y
, cw_fourth
[cave
->gravity
], falling
);
1423 else if (sloped_dir(cave
, x
, y
, cave
->gravity
, ccw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, ccw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, ccw_eighth
[cave
->gravity
])) {
1424 /* rolling right? */
1425 play_sound_of_element(cave
, get(cave
, x
, y
));
1426 move(cave
, x
, y
, ccw_fourth
[cave
->gravity
], falling
);
1431 case O_STONE_F
: /* falling stone */
1432 case O_MEGA_STONE_F
: /* falling mega stone */
1433 case O_DIAMOND_F
: /* falling diamond */
1434 case O_NUT_F
: /* falling nut */
1435 if (!cave
->gravity_disabled
) {
1438 switch (get(cave
, x
, y
)) {
1439 case O_STONE_F
: bouncing
=cave
->stone_bouncing_effect
; break;
1440 case O_MEGA_STONE_F
: bouncing
=O_MEGA_STONE
; break;
1441 case O_DIAMOND_F
: bouncing
=cave
->diamond_bouncing_effect
; break;
1442 case O_NUT_F
: bouncing
=O_NUT
; break;
1443 default: g_assert_not_reached();
1446 if (is_space_dir(cave
, x
, y
, cave
->gravity
)) /* falling further */
1447 move(cave
, x
, y
, cave
->gravity
, get(cave
, x
, y
));
1448 else if (get(cave
, x
, y
)==O_DIAMOND_F
&& get_dir(cave
, x
, y
, cave
->gravity
)==O_VOODOO
&& cave
->voodoo_collects_diamonds
) {
1449 /* this is a 1stB-style voodoo. explodes by stone, collects diamonds */
1450 player_get_element (cave
, O_DIAMOND
); /* as if player got diamond */
1451 store(cave
, x
, y
, O_SPACE
); /* diamond disappears */
1453 else if ((get(cave
, x
, y
)==O_STONE_F
|| get(cave
, x
, y
)==O_MEGA_STONE_F
) && get_dir(cave
, x
, y
, cave
->gravity
)==O_NUT
) {
1454 /* mega stones and normal stones crack nuts */
1455 store(cave
, x
, y
, bouncing
);
1456 store_dir(cave
, x
, y
, cave
->gravity
, O_NUT_EXPL_1
);
1457 if (cave
->nut_sound
)
1458 gd_sound_play(cave
, GD_S_NUT_CRACK
);
1460 else if ((get(cave
, x
, y
)==O_STONE_F
|| get(cave
, x
, y
)==O_MEGA_STONE_F
) && get_dir(cave
, x
, y
, cave
->gravity
)==O_VOODOO
&& cave
->voodoo_dies_by_stone
) {
1461 /* this is a 1stB-style vodo. explodes by stone, collects diamonds */
1462 explode_dir (cave
, x
, y
, cave
->gravity
);
1464 else if (get_dir(cave
, x
, y
, cave
->gravity
)==O_MAGIC_WALL
) {
1465 play_sound_of_element(cave
, O_DIAMOND
); /* always play diamond sound */
1466 if (cave
->magic_wall_state
==GD_MW_DORMANT
)
1467 cave
->magic_wall_state
=GD_MW_ACTIVE
;
1468 if (cave
->magic_wall_state
==GD_MW_ACTIVE
&& is_space_dir(cave
, x
, y
, MV_TWICE
+cave
->gravity
)) {
1469 /* if magic wall active and place underneath, */
1470 /* it turns boulder into diamond and vice versa. or anything the effect says to do. */
1473 switch (get(cave
, x
, y
)) {
1475 magic
=cave
->magic_stone_to
;
1477 case O_MEGA_STONE_F
:
1478 magic
=cave
->magic_mega_stone_to
;
1481 magic
=cave
->magic_diamond_to
;
1487 g_assert_not_reached();
1490 store_dir(cave
, x
, y
, MV_TWICE
+cave
->gravity
, magic
);
1492 store(cave
, x
, y
, O_SPACE
); /* active or non-active or anything, element falling in will always disappear */
1494 else if (explodes_by_hit_dir(cave
, x
, y
, cave
->gravity
))
1495 explode_dir(cave
, x
, y
, cave
->gravity
);
1496 else if (sloped_dir(cave
, x
, y
, cave
->gravity
, opposite
[cave
->gravity
])) { /* sloped element, falling to left or right */
1497 if (sloped_dir(cave
, x
, y
, cave
->gravity
, cw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, cw_eighth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, cw_fourth
[cave
->gravity
])) {
1498 play_sound_of_element(cave
, get(cave
, x
, y
));
1499 move(cave
, x
, y
, cw_fourth
[cave
->gravity
], get(cave
, x
, y
)); /* try to roll left first - see O_STONE to understand why cw_fourth */
1501 else if (sloped_dir(cave
, x
, y
, cave
->gravity
, ccw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, ccw_eighth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, ccw_fourth
[cave
->gravity
])) {
1502 play_sound_of_element(cave
, get(cave
, x
, y
));
1503 move(cave
, x
, y
, ccw_fourth
[cave
->gravity
], get(cave
, x
, y
)); /* if not, try to roll right */
1506 /* cannot roll in any direction, so it stops */
1507 play_sound_of_element(cave
, get(cave
, x
, y
));
1508 store(cave
, x
, y
, bouncing
);
1512 /* any other element, stops */
1513 play_sound_of_element(cave
, get(cave
, x
, y
));
1514 store(cave
, x
, y
, bouncing
);
1519 /* DIRT BALL AND LOOSE DIRT */
1520 case O_DIRT_BALL
: /* standing dirt ball */
1521 case O_DIRT_LOOSE
: /* standing loose dirt */
1522 if (!cave
->gravity_disabled
) {
1523 /* if gravity is enabled, the stone might fall. */
1526 switch (get(cave
, x
, y
)) {
1527 case O_DIRT_BALL
: falling
=O_DIRT_BALL_F
; break;
1528 case O_DIRT_LOOSE
: falling
=O_DIRT_LOOSE_F
; break;
1529 default: g_assert_not_reached();
1532 if (is_space_dir(cave
, x
, y
, cave
->gravity
)) { /* beginning to fall */
1533 play_sound_of_element(cave
, get(cave
, x
, y
));
1534 move(cave
, x
, y
, cave
->gravity
, falling
);
1536 /* check if it is on a sloped element, and it can roll. */
1537 /* for example, sloped wall looks like: */
1540 /* this is tagged as sloped up&left. */
1541 /* first check if the stone or diamond is coming from "up" (ie. opposite of gravity) */
1542 /* then check the direction to roll (left or right) */
1543 /* this way, gravity can also be pointing right, and the above slope will work as one would expect */
1544 else if (sloped_dir(cave
, x
, y
, cave
->gravity
, opposite
[cave
->gravity
])) { /* rolling down, if sitting on a sloped object */
1545 if (sloped_dir(cave
, x
, y
, cave
->gravity
, cw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, cw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, cw_eighth
[cave
->gravity
])) {
1546 /* rolling left? - keep in mind that ccw_fourth rotates gravity ccw, so here we use cw_fourth */
1547 play_sound_of_element(cave
, get(cave
, x
, y
));
1548 move(cave
, x
, y
, cw_fourth
[cave
->gravity
], falling
);
1550 else if (sloped_dir(cave
, x
, y
, cave
->gravity
, ccw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, ccw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, ccw_eighth
[cave
->gravity
])) {
1551 /* rolling right? */
1552 play_sound_of_element(cave
, get(cave
, x
, y
));
1553 move(cave
, x
, y
, ccw_fourth
[cave
->gravity
], falling
);
1558 case O_DIRT_BALL_F
: /* falling stone */
1559 case O_DIRT_LOOSE_F
: /* falling mega stone */
1560 if (!cave
->gravity_disabled
) {
1563 switch (get(cave
, x
, y
)) {
1564 case O_DIRT_BALL_F
: bouncing
=O_DIRT_BALL
; break;
1565 case O_DIRT_LOOSE_F
: bouncing
=O_DIRT_LOOSE
; break;
1566 default: g_assert_not_reached();
1569 if (is_space_dir(cave
, x
, y
, cave
->gravity
)) /* falling further */
1570 move(cave
, x
, y
, cave
->gravity
, get(cave
, x
, y
));
1571 else if (sloped_dir(cave
, x
, y
, cave
->gravity
, opposite
[cave
->gravity
])) { /* sloped element, falling to left or right */
1572 if (sloped_dir(cave
, x
, y
, cave
->gravity
, cw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, cw_eighth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, cw_fourth
[cave
->gravity
])) {
1573 play_sound_of_element(cave
, get(cave
, x
, y
));
1574 move(cave
, x
, y
, cw_fourth
[cave
->gravity
], get(cave
, x
, y
)); /* try to roll left first - see O_STONE to understand why cw_fourth */
1576 else if (sloped_dir(cave
, x
, y
, cave
->gravity
, ccw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, ccw_eighth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, ccw_fourth
[cave
->gravity
])) {
1577 play_sound_of_element(cave
, get(cave
, x
, y
));
1578 move(cave
, x
, y
, ccw_fourth
[cave
->gravity
], get(cave
, x
, y
)); /* if not, try to roll right */
1581 /* cannot roll in any direction, so it stops */
1582 play_sound_of_element(cave
, get(cave
, x
, y
));
1583 store(cave
, x
, y
, bouncing
);
1587 /* any other element, stops */
1588 play_sound_of_element(cave
, get(cave
, x
, y
));
1589 store(cave
, x
, y
, bouncing
);
1596 * F L Y I N G S T O N E S, D I A M O N D S
1598 case O_FLYING_STONE
: /* standing stone */
1599 case O_FLYING_DIAMOND
: /* standing diamond */
1600 if (!cave
->gravity_disabled
) {
1601 GdDirection fall_dir
=opposite
[cave
->gravity
]; /* these elements fall "up" */
1602 GdElement falling
; /* if gravity is enabled, the stone might fall. */
1604 switch (get(cave
, x
, y
)) {
1605 case O_FLYING_STONE
: falling
=O_FLYING_STONE_F
; break;
1606 case O_FLYING_DIAMOND
: falling
=O_FLYING_DIAMOND_F
; break;
1607 default: g_assert_not_reached();
1610 if (is_space_dir(cave
, x
, y
, fall_dir
)) { /* beginning to fall */
1611 play_sound_of_element(cave
, get(cave
, x
, y
));
1612 move(cave
, x
, y
, fall_dir
, falling
);
1614 /* check if it is on a sloped element, and it can roll. */
1615 /* for example, sloped wall looks like: */
1618 /* this is tagged as sloped up&left. */
1619 /* first check if the stone or diamond is coming from "up" (ie. opposite of gravity) */
1620 /* then check the direction to roll (left or right) */
1621 /* this way, gravity can also be pointing right, and the above slope will work as one would expect */
1622 else if (sloped_dir(cave
, x
, y
, fall_dir
, opposite
[fall_dir
])) { /* rolling down, if sitting on a sloped object */
1623 if (sloped_dir(cave
, x
, y
, fall_dir
, cw_fourth
[fall_dir
]) && is_space_dir(cave
, x
, y
, cw_fourth
[fall_dir
]) && is_space_dir(cave
, x
, y
, cw_eighth
[fall_dir
])) {
1624 /* rolling left? - keep in mind that ccw_fourth rotates gravity ccw, so here we use cw_fourth */
1625 play_sound_of_element(cave
, get(cave
, x
, y
));
1626 move(cave
, x
, y
, cw_fourth
[fall_dir
], falling
);
1628 else if (sloped_dir(cave
, x
, y
, fall_dir
, ccw_fourth
[fall_dir
]) && is_space_dir(cave
, x
, y
, ccw_fourth
[fall_dir
]) && is_space_dir(cave
, x
, y
, ccw_eighth
[fall_dir
])) {
1629 /* rolling right? */
1630 play_sound_of_element(cave
, get(cave
, x
, y
));
1631 move(cave
, x
, y
, ccw_fourth
[fall_dir
], falling
);
1636 case O_FLYING_STONE_F
: /* falling stone */
1637 case O_FLYING_DIAMOND_F
: /* falling diamond */
1638 if (!cave
->gravity_disabled
) {
1640 GdDirection fall_dir
=opposite
[cave
->gravity
]; /* these elements fall "up" */
1642 switch (get(cave
, x
, y
)) {
1643 case O_FLYING_STONE_F
: bouncing
=O_FLYING_STONE
; break;
1644 case O_FLYING_DIAMOND_F
: bouncing
=O_FLYING_DIAMOND
; break;
1645 default: g_assert_not_reached();
1648 if (is_space_dir(cave
, x
, y
, fall_dir
)) /* falling further */
1649 move(cave
, x
, y
, fall_dir
, get(cave
, x
, y
));
1650 else if (get(cave
, x
, y
)==O_FLYING_DIAMOND_F
&& get_dir(cave
, x
, y
, fall_dir
)==O_VOODOO
&& cave
->voodoo_collects_diamonds
) {
1651 /* this is a 1stB-style voodoo. explodes by stone, collects diamonds */
1652 player_get_element(cave
, O_FLYING_DIAMOND
); /* as if player got diamond */
1653 store(cave
, x
, y
, O_SPACE
); /* diamond disappears */
1655 else if (get(cave
, x
, y
)==O_FLYING_STONE_F
&& get_dir(cave
, x
, y
, fall_dir
)==O_VOODOO
&& cave
->voodoo_dies_by_stone
) {
1656 /* this is a 1stB-style vodo. explodes by stone, collects diamonds */
1657 explode_dir (cave
, x
, y
, fall_dir
);
1659 else if (get_dir(cave
, x
, y
, fall_dir
)==O_MAGIC_WALL
) {
1660 play_sound_of_element(cave
, O_DIAMOND
); /* always play diamond sound */
1661 if (cave
->magic_wall_state
==GD_MW_DORMANT
)
1662 cave
->magic_wall_state
=GD_MW_ACTIVE
;
1663 if (cave
->magic_wall_state
==GD_MW_ACTIVE
&& is_space_dir(cave
, x
, y
, MV_TWICE
+fall_dir
)) {
1664 /* if magic wall active and place underneath, */
1665 /* it turns boulder into diamond and vice versa. or anything the effect says to do. */
1668 switch (get(cave
, x
, y
)) {
1669 case O_FLYING_STONE_F
: magic
=cave
->magic_flying_stone_to
; break;
1670 case O_FLYING_DIAMOND_F
: magic
=cave
->magic_flying_diamond_to
; break;
1671 default: g_assert_not_reached();
1674 store_dir(cave
, x
, y
, MV_TWICE
+fall_dir
, magic
);
1676 store(cave
, x
, y
, O_SPACE
); /* active or non-active or anything, element falling in will always disappear */
1678 else if (explodes_by_hit_dir(cave
, x
, y
, fall_dir
))
1679 explode_dir(cave
, x
, y
, fall_dir
);
1680 else if (sloped_dir(cave
, x
, y
, fall_dir
, opposite
[fall_dir
])) { /* sloped element, falling to left or right */
1681 if (sloped_dir(cave
, x
, y
, fall_dir
, cw_fourth
[fall_dir
]) && is_space_dir(cave
, x
, y
, cw_eighth
[fall_dir
]) && is_space_dir(cave
, x
, y
, cw_fourth
[fall_dir
])) {
1682 play_sound_of_element(cave
, get(cave
, x
, y
));
1683 move(cave
, x
, y
, cw_fourth
[fall_dir
], get(cave
, x
, y
)); /* try to roll left first - see O_STONE to understand why cw_fourth */
1685 else if (sloped_dir(cave
, x
, y
, fall_dir
, ccw_fourth
[fall_dir
]) && is_space_dir(cave
, x
, y
, ccw_eighth
[fall_dir
]) && is_space_dir(cave
, x
, y
, ccw_fourth
[fall_dir
])) {
1686 play_sound_of_element(cave
, get(cave
, x
, y
));
1687 move(cave
, x
, y
, ccw_fourth
[fall_dir
], get(cave
, x
, y
)); /* if not, try to roll right */
1690 /* cannot roll in any direction, so it stops */
1691 play_sound_of_element(cave
, get(cave
, x
, y
));
1692 store(cave
, x
, y
, bouncing
);
1696 /* any other element, stops */
1697 play_sound_of_element(cave
, get(cave
, x
, y
));
1698 store(cave
, x
, y
, bouncing
);
1708 case O_NITRO_PACK
: /* standing nitro pack */
1709 if (!cave
->gravity_disabled
) {
1710 /* if gravity is enabled, the stone might fall. */
1713 falling
=O_NITRO_PACK_F
;
1714 if (is_space_dir(cave
, x
, y
, cave
->gravity
)) { /* beginning to fall */
1715 play_sound_of_element(cave
, get(cave
, x
, y
));
1716 move(cave
, x
, y
, cave
->gravity
, falling
);
1718 /* check if it is on a sloped element, and it can roll. */
1719 /* for example, sloped wall looks like: */
1722 /* this is tagged as sloped up&left. */
1723 /* first check if the stone or diamond is coming from "up" (ie. opposite of gravity) */
1724 /* then check the direction to roll (left or right) */
1725 /* this way, gravity can also be pointing right, and the above slope will work as one would expect */
1726 else if (sloped_dir(cave
, x
, y
, cave
->gravity
, opposite
[cave
->gravity
])) { /* rolling down, if sitting on a sloped object */
1727 if (sloped_dir(cave
, x
, y
, cave
->gravity
, cw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, cw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, cw_eighth
[cave
->gravity
])) {
1728 /* rolling left? - keep in mind that ccw_fourth rotates gravity ccw, so here we use cw_fourth */
1729 play_sound_of_element(cave
, get(cave
, x
, y
));
1730 move(cave
, x
, y
, cw_fourth
[cave
->gravity
], falling
);
1732 else if (sloped_dir(cave
, x
, y
, cave
->gravity
, ccw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, ccw_fourth
[cave
->gravity
]) && is_space_dir(cave
, x
, y
, ccw_eighth
[cave
->gravity
])) {
1733 /* rolling right? */
1734 play_sound_of_element(cave
, get(cave
, x
, y
));
1735 move(cave
, x
, y
, ccw_fourth
[cave
->gravity
], falling
);
1740 case O_NITRO_PACK_F
: /* falling nitro pack */
1741 if (!cave
->gravity_disabled
) {
1744 bouncing
=O_NITRO_PACK
;
1745 if (is_space_dir(cave
, x
, y
, cave
->gravity
))
1746 /* if space, falling further */
1747 move(cave
, x
, y
, cave
->gravity
, get(cave
, x
, y
));
1748 else if (is_element_dir(cave
, x
, y
, cave
->gravity
, O_MAGIC_WALL
)) {
1749 /* if magic wall, it transforms it. */
1750 play_sound_of_element(cave
, O_DIAMOND
); /* always play diamond sound */
1751 if (cave
->magic_wall_state
==GD_MW_DORMANT
)
1752 cave
->magic_wall_state
=GD_MW_ACTIVE
;
1753 if (cave
->magic_wall_state
==GD_MW_ACTIVE
&& is_space_dir(cave
, x
, y
, MV_TWICE
+cave
->gravity
))
1754 store_dir(cave
, x
, y
, MV_TWICE
+cave
->gravity
, cave
->magic_nitro_pack_to
);
1755 store(cave
, x
, y
, O_SPACE
); /* active or non-active or anything, element falling in will always disappear */
1757 else if (is_element_dir(cave
, x
, y
, cave
->gravity
, O_DIRT
)) {
1758 /* falling on a dirt, it does NOT explode - just stops at its place. */
1759 play_sound_of_element(cave
, bouncing
);
1760 store(cave
, x
, y
, bouncing
);
1763 /* falling on any other element it explodes */
1764 explode(cave
, x
, y
);
1767 case O_NITRO_PACK_EXPLODE
: /* a triggered nitro pack */
1768 explode(cave
, x
, y
);
1781 /* if cannot move in any direction, becomes an enclosed cow */
1782 if (!is_space_dir(cave
, x
, y
, MV_UP
) && !is_space_dir(cave
, x
, y
, MV_DOWN
)
1783 && !is_space_dir(cave
, x
, y
, MV_LEFT
) && !is_space_dir(cave
, x
, y
, MV_RIGHT
))
1784 store(cave
, x
, y
, O_COW_ENCLOSED_1
);
1786 /* THIS IS THE CREATURE MOVE thing copied. */
1787 const GdDirection
*creature_move
;
1788 gboolean ccw
=rotates_ccw(cave
, x
, y
); /* check if default is counterclockwise */
1789 GdElement base
; /* base element number (which is like O_***_1) */
1790 int dir
, dirn
, dirp
; /* direction */
1794 dir
=get(cave
, x
, y
)-base
; /* facing where */
1795 creature_move
=cave
->creatures_backwards
? creature_chdir
:creature_dir
;
1797 /* now change direction if backwards */
1798 if (cave
->creatures_backwards
)
1802 dirn
=(dir
+3)&3; /* fast turn */
1803 dirp
=(dir
+1)&3; /* slow turn */
1805 dirn
=(dir
+1)&3; /* fast turn */
1806 dirp
=(dir
+3)&3; /* slow turn */
1809 if (is_space_dir(cave
, x
, y
, creature_move
[dirn
]))
1810 move(cave
, x
, y
, creature_move
[dirn
], base
+dirn
); /* turn and move to preferred dir */
1811 else if (is_space_dir(cave
, x
, y
, creature_move
[dir
]))
1812 move(cave
, x
, y
, creature_move
[dir
], base
+dir
); /* go on */
1814 store(cave
, x
, y
, base
+dirp
); /* turn in place if nothing else possible */
1817 /* enclosed cows wait some time before turning to a skeleton */
1818 case O_COW_ENCLOSED_1
:
1819 case O_COW_ENCLOSED_2
:
1820 case O_COW_ENCLOSED_3
:
1821 case O_COW_ENCLOSED_4
:
1822 case O_COW_ENCLOSED_5
:
1823 case O_COW_ENCLOSED_6
:
1824 if (is_space_dir(cave
, x
, y
, MV_UP
) || is_space_dir(cave
, x
, y
, MV_LEFT
) || is_space_dir(cave
, x
, y
, MV_RIGHT
) || is_space_dir(cave
, x
, y
, MV_DOWN
))
1825 store(cave
, x
, y
, O_COW_1
);
1829 case O_COW_ENCLOSED_7
:
1830 if (is_space_dir(cave
, x
, y
, MV_UP
) || is_space_dir(cave
, x
, y
, MV_LEFT
) || is_space_dir(cave
, x
, y
, MV_RIGHT
) || is_space_dir(cave
, x
, y
, MV_DOWN
))
1831 store(cave
, x
, y
, O_COW_1
);
1833 store(cave
, x
, y
, O_SKELETON
);
1840 case O_ALT_FIREFLY_1
:
1841 case O_ALT_FIREFLY_2
:
1842 case O_ALT_FIREFLY_3
:
1843 case O_ALT_FIREFLY_4
:
1848 case O_ALT_BUTTER_1
:
1849 case O_ALT_BUTTER_2
:
1850 case O_ALT_BUTTER_3
:
1851 case O_ALT_BUTTER_4
:
1856 /* check if touches a voodoo */
1857 if (get_dir(cave
, x
, y
, MV_LEFT
)==O_VOODOO
|| get_dir(cave
, x
, y
, MV_RIGHT
)==O_VOODOO
|| get_dir(cave
, x
, y
, MV_UP
)==O_VOODOO
|| get_dir(cave
, x
, y
, MV_DOWN
)==O_VOODOO
)
1858 cave
->voodoo_touched
=TRUE
;
1859 /* check if touches something bad and should explode (includes voodoo by the flags) */
1860 if (blows_up_flies_dir(cave
, x
, y
, MV_DOWN
) || blows_up_flies_dir(cave
, x
, y
, MV_UP
)
1861 || blows_up_flies_dir(cave
, x
, y
, MV_LEFT
) || blows_up_flies_dir(cave
, x
, y
, MV_RIGHT
))
1862 explode (cave
, x
, y
);
1863 /* otherwise move */
1865 const GdDirection
*creature_move
;
1866 gboolean ccw
=rotates_ccw(cave
, x
, y
); /* check if default is counterclockwise */
1867 GdElement base
; /* base element number (which is like O_***_1) */
1868 int dir
, dirn
, dirp
; /* direction */
1870 if (get(cave
, x
, y
)>=O_FIREFLY_1
&& get(cave
, x
, y
)<=O_FIREFLY_4
)
1872 else if (get(cave
, x
, y
)>=O_BUTTER_1
&& get(cave
, x
, y
)<=O_BUTTER_4
)
1874 else if (get(cave
, x
, y
)>=O_STONEFLY_1
&& get(cave
, x
, y
)<=O_STONEFLY_4
)
1876 else if (get(cave
, x
, y
)>=O_ALT_FIREFLY_1
&& get(cave
, x
, y
)<=O_ALT_FIREFLY_4
)
1877 base
=O_ALT_FIREFLY_1
;
1878 else if (get(cave
, x
, y
)>=O_ALT_BUTTER_1
&& get(cave
, x
, y
)<=O_ALT_BUTTER_4
)
1879 base
=O_ALT_BUTTER_1
;
1881 g_assert_not_reached();
1883 dir
=get(cave
, x
, y
)-base
; /* facing where */
1884 creature_move
=cave
->creatures_backwards
? creature_chdir
:creature_dir
;
1886 /* now change direction if backwards */
1887 if (cave
->creatures_backwards
)
1891 dirn
=(dir
+3)&3; /* fast turn */
1892 dirp
=(dir
+1)&3; /* slow turn */
1894 dirn
=(dir
+1)&3; /* fast turn */
1895 dirp
=(dir
+3)&3; /* slow turn */
1898 if (is_space_dir(cave
, x
, y
, creature_move
[dirn
]))
1899 move(cave
, x
, y
, creature_move
[dirn
], base
+dirn
); /* turn and move to preferred dir */
1900 else if (is_space_dir(cave
, x
, y
, creature_move
[dir
]))
1901 move(cave
, x
, y
, creature_move
[dir
], base
+dir
); /* go on */
1903 store(cave
, x
, y
, base
+dirp
); /* turn in place if nothing else possible */
1907 case O_WAITING_STONE
:
1908 if (is_space_dir(cave
, x
, y
, grav_compat
)) { /* beginning to fall */
1910 move(cave
, x
, y
, grav_compat
, O_CHASING_STONE
);
1912 else if (sloped_dir(cave
, x
, y
, grav_compat
, opposite
[grav_compat
])) { /* rolling down a brick wall or a stone */
1913 if (sloped_dir(cave
, x
, y
, grav_compat
, cw_fourth
[grav_compat
]) && is_space_dir(cave
, x
, y
, cw_fourth
[grav_compat
]) && is_space_dir(cave
, x
, y
, cw_eighth
[grav_compat
])) {
1914 /* maybe rolling left - see case O_STONE to understand why we use cw_fourth here */
1915 move(cave
, x
, y
, cw_fourth
[grav_compat
], O_WAITING_STONE
);
1917 else if (sloped_dir(cave
, x
, y
, grav_compat
, ccw_fourth
[grav_compat
]) && is_space_dir(cave
, x
, y
, ccw_fourth
[grav_compat
]) && is_space_dir(cave
, x
, y
, ccw_eighth
[grav_compat
])) {
1918 /* or maybe right */
1919 move(cave
, x
, y
, ccw_fourth
[grav_compat
], O_WAITING_STONE
);
1924 case O_CHASING_STONE
:
1928 gboolean horizontal
=g_rand_boolean(cave
->random
);
1929 gboolean dont_move
=FALSE
;
1932 /* try to move... */
1934 if (horizontal
) { /*********************************/
1935 /* check for a horizontal movement */
1937 /* if coordinates are the same */
1939 horizontal
=!horizontal
;
1943 if (px
>x
&& is_space_dir(cave
, x
, y
, MV_RIGHT
)) {
1944 move(cave
, x
, y
, MV_RIGHT
, O_CHASING_STONE
);
1948 if (px
<x
&& is_space_dir(cave
, x
, y
, MV_LEFT
)) {
1949 move(cave
, x
, y
, MV_LEFT
, O_CHASING_STONE
);
1955 horizontal
=!horizontal
;
1960 } else { /********************************/
1961 /* check for a vertical movement */
1963 /* if coordinates are the same */
1965 horizontal
=!horizontal
;
1969 if (py
>y
&& is_space_dir(cave
, x
, y
, MV_DOWN
)) {
1970 move(cave
, x
, y
, MV_DOWN
, O_CHASING_STONE
);
1974 if (py
<y
&& is_space_dir(cave
, x
, y
, MV_UP
)) {
1975 move(cave
, x
, y
, MV_UP
, O_CHASING_STONE
);
1981 horizontal
=!horizontal
;
1992 /* if we should move in both directions, but can not move in any, stop. */
1994 if (horizontal
) { /* check for horizontal */
1996 if (is_space_dir(cave
, x
, y
, MV_UP
) && is_space_dir(cave
, x
, y
, MV_UP_LEFT
))
1997 move(cave
, x
, y
, MV_UP
, O_CHASING_STONE
);
1999 if (is_space_dir(cave
, x
, y
, MV_DOWN
) && is_space_dir(cave
, x
, y
, MV_DOWN_LEFT
))
2000 move(cave
, x
, y
, MV_DOWN
, O_CHASING_STONE
);
2002 if (is_space_dir(cave
, x
, y
, MV_UP
) && is_space_dir(cave
, x
, y
, MV_UP_RIGHT
))
2003 move(cave
, x
, y
, MV_UP
, O_CHASING_STONE
);
2005 if (is_space_dir(cave
, x
, y
, MV_DOWN
) && is_space_dir(cave
, x
, y
, MV_DOWN_RIGHT
))
2006 move(cave
, x
, y
, MV_DOWN
, O_CHASING_STONE
);
2008 } else { /* check for vertical */
2010 if (is_space_dir(cave
, x
, y
, MV_LEFT
) && is_space_dir(cave
, x
, y
, MV_UP_LEFT
))
2011 move(cave
, x
, y
, MV_LEFT
, O_CHASING_STONE
);
2013 if (is_space_dir(cave
, x
, y
, MV_RIGHT
) && is_space_dir(cave
, x
, y
, MV_UP_RIGHT
))
2014 move(cave
, x
, y
, MV_RIGHT
, O_CHASING_STONE
);
2016 if (is_space_dir(cave
, x
, y
, MV_LEFT
) && is_space_dir(cave
, x
, y
, MV_DOWN_LEFT
))
2017 move(cave
, x
, y
, MV_LEFT
, O_CHASING_STONE
);
2019 if (is_space_dir(cave
, x
, y
, MV_RIGHT
) && is_space_dir(cave
, x
, y
, MV_DOWN_RIGHT
))
2020 move(cave
, x
, y
, MV_RIGHT
, O_CHASING_STONE
);
2028 if (cave
->replicators_wait_frame
==0 && cave
->replicators_active
&& !cave
->gravity_disabled
) {
2029 /* only replicate, if space is under it. */
2030 /* do not replicate players! */
2031 /* also obeys gravity settings. */
2032 /* only replicate element if it is not a scanned one */
2033 /* do not replicate space... that condition looks like it makes no sense,
2034 but otherwise it generates SCANNED spaces, which cannot be "collected" by the player, so he cannot run under a replicator */
2035 if (is_space_dir(cave
, x
, y
, cave
->gravity
) && !is_player_dir(cave
, x
, y
, opposite
[cave
->gravity
])
2036 && !is_space_dir(cave
, x
, y
, opposite
[cave
->gravity
])) {
2037 store_dir(cave
, x
, y
, cave
->gravity
, get_dir(cave
, x
, y
, opposite
[cave
->gravity
]));
2038 gd_sound_play(cave
, GD_S_REPLICATOR
);
2047 if (cave
->biters_wait_frame
==0) {
2048 static GdDirection biter_move
[]={ MV_UP
, MV_RIGHT
, MV_DOWN
, MV_LEFT
};
2049 int dir
=get(cave
, x
, y
)-O_BITER_1
; /* direction, last two bits 0..3 */
2053 GdElement made_sound_of
=O_NONE
;
2055 for (i
=0; i
<G_N_ELEMENTS (biter_try
); i
++) {
2056 if (is_element_dir(cave
, x
, y
, biter_move
[dir
], biter_try
[i
])) {
2057 move(cave
, x
, y
, biter_move
[dir
], O_BITER_1
+dir
);
2058 if (biter_try
[i
]!=O_SPACE
)
2059 made_sound_of
=O_BITER_1
; /* sound of a biter eating */
2062 else if (is_element_dir(cave
, x
, y
, biter_move
[dirn
], biter_try
[i
])) {
2063 move(cave
, x
, y
, biter_move
[dirn
], O_BITER_1
+dirn
);
2064 if (biter_try
[i
]!=O_SPACE
)
2065 made_sound_of
=O_BITER_1
; /* sound of a biter eating */
2068 else if (is_element_dir(cave
, x
, y
, biter_move
[dirp
], biter_try
[i
])) {
2069 move(cave
, x
, y
, biter_move
[dirp
], O_BITER_1
+dirp
);
2070 if (biter_try
[i
]!=O_SPACE
)
2071 made_sound_of
=O_BITER_1
; /* sound of a biter eating */
2075 if (i
==G_N_ELEMENTS (biter_try
))
2076 /* i=number of elements in array: could not move, so just turn */
2077 store(cave
, x
, y
, O_BITER_1
+dirp
);
2078 else if (biter_try
[i
]==O_STONE
) {
2079 /* if there was a stone there, where we moved... do not eat stones, just throw them back */
2080 store(cave
, x
, y
, O_STONE
);
2081 made_sound_of
=O_STONE
;
2084 /* if biter did move, we had sound. play it. */
2085 if (made_sound_of
!=O_NONE
)
2086 play_sound_of_element(cave
, made_sound_of
);
2094 /* check if touches a voodoo */
2095 if (get_dir(cave
, x
, y
, MV_LEFT
)==O_VOODOO
|| get_dir(cave
, x
, y
, MV_RIGHT
)==O_VOODOO
|| get_dir(cave
, x
, y
, MV_UP
)==O_VOODOO
|| get_dir(cave
, x
, y
, MV_DOWN
)==O_VOODOO
)
2096 cave
->voodoo_touched
=TRUE
;
2097 /* check if touches something bad and should explode (includes voodoo by the flags) */
2098 if (blows_up_flies_dir(cave
, x
, y
, MV_DOWN
) || blows_up_flies_dir(cave
, x
, y
, MV_UP
)
2099 || blows_up_flies_dir(cave
, x
, y
, MV_LEFT
) || blows_up_flies_dir(cave
, x
, y
, MV_RIGHT
))
2100 explode (cave
, x
, y
);
2101 /* otherwise move */
2103 const GdDirection
*creature_move
;
2104 gboolean ccw
=rotates_ccw(cave
, x
, y
); /* check if default is counterclockwise */
2105 GdElement base
=O_DRAGONFLY_1
; /* base element number (which is like O_***_1) */
2106 int dir
, dirn
; /* direction */
2108 dir
=get(cave
, x
, y
)-base
; /* facing where */
2109 creature_move
=cave
->creatures_backwards
? creature_chdir
:creature_dir
;
2111 /* now change direction if backwards */
2112 if (cave
->creatures_backwards
)
2116 dirn
=(dir
+3)&3; /* fast turn */
2118 dirn
=(dir
+1)&3; /* fast turn */
2120 /* if can move forward, does so. */
2121 if (is_space_dir(cave
, x
, y
, creature_move
[dir
]))
2122 move(cave
, x
, y
, creature_move
[dir
], base
+dir
);
2124 /* otherwise turns 90 degrees in place. */
2125 store(cave
, x
, y
, base
+dirn
);
2131 store(cave
, x
, y
, O_BLADDER_1
);
2142 /* bladder with any delay state: try to convert to clock. */
2143 if (is_element_dir(cave
, x
, y
, opposite
[grav_compat
], cave
->bladder_converts_by
)
2144 || is_element_dir(cave
, x
, y
, cw_fourth
[grav_compat
], cave
->bladder_converts_by
)
2145 || is_element_dir(cave
, x
, y
, ccw_fourth
[grav_compat
], cave
->bladder_converts_by
)) {
2146 /* if touches the specified element, let it be a clock */
2147 store(cave
, x
, y
, O_PRE_CLOCK_1
);
2148 play_sound_of_element(cave
, O_PRE_CLOCK_1
); /* plays the bladder convert sound */
2150 /* is space over the bladder? */
2151 if (is_space_dir(cave
, x
, y
, opposite
[grav_compat
])) {
2152 if (get(cave
, x
, y
)==O_BLADDER_8
) {
2153 /* if it is a bladder 8, really move up */
2154 move(cave
, x
, y
, opposite
[grav_compat
], O_BLADDER_1
);
2155 play_sound_of_element(cave
, O_BLADDER
);
2158 /* if smaller delay, just increase delay. */
2162 /* if not space, is something sloped over the bladder? */
2163 if (sloped_for_bladder_dir(cave
, x
, y
, opposite
[grav_compat
]) && sloped_dir(cave
, x
, y
, opposite
[grav_compat
], opposite
[grav_compat
])) {
2164 if (sloped_dir(cave
, x
, y
, opposite
[grav_compat
], ccw_fourth
[opposite
[grav_compat
]])
2165 && is_space_dir(cave
, x
, y
, ccw_fourth
[opposite
[grav_compat
]])
2166 && is_space_dir(cave
, x
, y
, ccw_eighth
[opposite
[grav_compat
]])) {
2167 /* rolling up, to left */
2168 if (get(cave
, x
, y
)==O_BLADDER_8
) {
2169 /* if it is a bladder 8, really roll */
2170 move(cave
, x
, y
, ccw_fourth
[opposite
[grav_compat
]], O_BLADDER_8
);
2171 play_sound_of_element(cave
, O_BLADDER
);
2173 /* if smaller delay, just increase delay. */
2177 if (sloped_dir(cave
, x
, y
, opposite
[grav_compat
], cw_fourth
[opposite
[grav_compat
]])
2178 && is_space_dir(cave
, x
, y
, cw_fourth
[opposite
[grav_compat
]])
2179 && is_space_dir(cave
, x
, y
, cw_eighth
[opposite
[grav_compat
]])) {
2180 /* rolling up, to left */
2181 if (get(cave
, x
, y
)==O_BLADDER_8
) {
2182 /* if it is a bladder 8, really roll */
2183 move(cave
, x
, y
, cw_fourth
[opposite
[grav_compat
]], O_BLADDER_8
);
2184 play_sound_of_element(cave
, O_BLADDER
);
2186 /* if smaller delay, just increase delay. */
2190 /* no space, no sloped thing over it - store bladder 1 and that is for now. */
2192 store(cave
, x
, y
, O_BLADDER_1
);
2197 if (blows_up_flies_dir(cave
, x
, y
, MV_DOWN
) || blows_up_flies_dir(cave
, x
, y
, MV_UP
)
2198 || blows_up_flies_dir(cave
, x
, y
, MV_LEFT
) || blows_up_flies_dir(cave
, x
, y
, MV_RIGHT
))
2199 explode (cave
, x
, y
);
2203 /* the ghost is given four possibilities to move. */
2204 for (i
=0; i
<4; i
++) {
2205 static GdDirection dirs
[]={MV_UP
, MV_DOWN
, MV_LEFT
, MV_RIGHT
};
2206 GdDirection random_dir
;
2208 random_dir
=dirs
[g_rand_int_range(cave
->random
, 0, G_N_ELEMENTS(dirs
))];
2209 if (is_space_dir(cave
, x
, y
, random_dir
)) {
2210 move(cave
, x
, y
, random_dir
, O_GHOST
);
2211 break; /* ghost did move -> exit loop */
2220 * A C T I V E E L E M E N T S
2225 switch (cave
->amoeba_state
) {
2227 store(cave
, x
, y
, cave
->amoeba_too_big_effect
);
2229 case GD_AM_ENCLOSED
:
2230 store(cave
, x
, y
, cave
->amoeba_enclosed_effect
);
2232 case GD_AM_SLEEPING
:
2234 /* if no amoeba found during THIS SCAN yet, which was able to grow, check this one. */
2235 if (amoeba_found_enclosed
)
2236 /* if still found enclosed, check all four directions, if this one is able to grow. */
2237 if (amoeba_eats_dir(cave
, x
, y
, MV_UP
) || amoeba_eats_dir(cave
, x
, y
, MV_DOWN
)
2238 || amoeba_eats_dir(cave
, x
, y
, MV_LEFT
) || amoeba_eats_dir(cave
, x
, y
, MV_RIGHT
)) {
2239 amoeba_found_enclosed
=FALSE
; /* not enclosed. this is a local (per scan) flag! */
2240 cave
->amoeba_state
=GD_AM_AWAKE
;
2243 /* if alive, check in which dir to grow (or not) */
2244 if (cave
->amoeba_state
==GD_AM_AWAKE
) {
2245 if (g_rand_int_range(cave
->random
, 0, 1000000)<cave
->amoeba_growth_prob
*1000000) {
2246 switch (g_rand_int_range(cave
->random
, 0, 4)) { /* decided to grow, choose a random direction. */
2247 case 0: /* let this be up. numbers indifferent. */
2248 if (amoeba_eats_dir(cave
, x
, y
, MV_UP
))
2249 store_dir(cave
, x
, y
, MV_UP
, O_AMOEBA
);
2252 if (amoeba_eats_dir(cave
, x
, y
, MV_DOWN
))
2253 store_dir(cave
, x
, y
, MV_DOWN
, O_AMOEBA
);
2256 if (amoeba_eats_dir(cave
, x
, y
, MV_LEFT
))
2257 store_dir(cave
, x
, y
, MV_LEFT
, O_AMOEBA
);
2260 if (amoeba_eats_dir(cave
, x
, y
, MV_RIGHT
))
2261 store_dir(cave
, x
, y
, MV_RIGHT
, O_AMOEBA
);
2272 /* check if it is touching an amoeba, and explosion is enabled */
2273 if (cave
->amoeba_2_explodes_by_amoeba
2274 && (is_element_dir(cave
, x
, y
, MV_DOWN
, O_AMOEBA
) || is_element_dir(cave
, x
, y
, MV_UP
, O_AMOEBA
)
2275 || is_element_dir(cave
, x
, y
, MV_LEFT
, O_AMOEBA
) || is_element_dir(cave
, x
, y
, MV_RIGHT
, O_AMOEBA
)))
2276 explode (cave
, x
, y
);
2278 switch (cave
->amoeba_2_state
) {
2280 store(cave
, x
, y
, cave
->amoeba_2_too_big_effect
);
2282 case GD_AM_ENCLOSED
:
2283 store(cave
, x
, y
, cave
->amoeba_2_enclosed_effect
);
2285 case GD_AM_SLEEPING
:
2287 /* if no amoeba found during THIS SCAN yet, which was able to grow, check this one. */
2288 if (amoeba_2_found_enclosed
)
2289 if (amoeba_eats_dir(cave
, x
, y
, MV_UP
) || amoeba_eats_dir(cave
, x
, y
, MV_DOWN
)
2290 || amoeba_eats_dir(cave
, x
, y
, MV_LEFT
) || amoeba_eats_dir(cave
, x
, y
, MV_RIGHT
)) {
2291 amoeba_2_found_enclosed
=FALSE
; /* not enclosed. this is a local (per scan) flag! */
2292 cave
->amoeba_2_state
=GD_AM_AWAKE
;
2295 if (cave
->amoeba_2_state
==GD_AM_AWAKE
) /* if it is alive, decide if it attempts to grow */
2296 if (g_rand_int_range(cave
->random
, 0, 1000000)<cave
->amoeba_2_growth_prob
*1000000) {
2297 switch (g_rand_int_range(cave
->random
, 0, 4)) { /* decided to grow, choose a random direction. */
2298 case 0: /* let this be up. numbers indifferent. */
2299 if (amoeba_eats_dir(cave
, x
, y
, MV_UP
))
2300 store_dir(cave
, x
, y
, MV_UP
, O_AMOEBA_2
);
2303 if (amoeba_eats_dir(cave
, x
, y
, MV_DOWN
))
2304 store_dir(cave
, x
, y
, MV_DOWN
, O_AMOEBA_2
);
2307 if (amoeba_eats_dir(cave
, x
, y
, MV_LEFT
))
2308 store_dir(cave
, x
, y
, MV_LEFT
, O_AMOEBA_2
);
2311 if (amoeba_eats_dir(cave
, x
, y
, MV_RIGHT
))
2312 store_dir(cave
, x
, y
, MV_RIGHT
, O_AMOEBA_2
);
2321 /* choose randomly, if it spreads */
2322 if (g_rand_int_range(cave
->random
, 0, 1000000)<=cave
->acid_spread_ratio
*1000000) {
2323 /* the current one explodes */
2324 store(cave
, x
, y
, cave
->acid_turns_to
);
2325 /* and if neighbours are eaten, put acid there. */
2326 if (is_element_dir(cave
, x
, y
, MV_UP
, cave
->acid_eats_this
)) {
2327 play_sound_of_element(cave
, O_ACID
);
2328 store_dir(cave
, x
, y
, MV_UP
, O_ACID
);
2330 if (is_element_dir(cave
, x
, y
, MV_DOWN
, cave
->acid_eats_this
)) {
2331 play_sound_of_element(cave
, O_ACID
);
2332 store_dir(cave
, x
, y
, MV_DOWN
, O_ACID
);
2334 if (is_element_dir(cave
, x
, y
, MV_LEFT
, cave
->acid_eats_this
)) {
2335 play_sound_of_element(cave
, O_ACID
);
2336 store_dir(cave
, x
, y
, MV_LEFT
, O_ACID
);
2338 if (is_element_dir(cave
, x
, y
, MV_RIGHT
, cave
->acid_eats_this
)) {
2339 play_sound_of_element(cave
, O_ACID
);
2340 store_dir(cave
, x
, y
, MV_RIGHT
, O_ACID
);
2347 if (!cave
->water_does_not_flow_down
&& is_space_dir(cave
, x
, y
, MV_DOWN
)) /* emulating the odd behaviour in crdr */
2348 store_dir(cave
, x
, y
, MV_DOWN
, O_WATER_1
);
2349 if (is_space_dir(cave
, x
, y
, MV_UP
))
2350 store_dir(cave
, x
, y
, MV_UP
, O_WATER_1
);
2351 if (is_space_dir(cave
, x
, y
, MV_LEFT
))
2352 store_dir(cave
, x
, y
, MV_LEFT
, O_WATER_1
);
2353 if (is_space_dir(cave
, x
, y
, MV_RIGHT
))
2354 store_dir(cave
, x
, y
, MV_RIGHT
, O_WATER_1
);
2358 store(cave
, x
, y
, O_WATER
);
2361 case O_H_EXPANDING_WALL
:
2362 case O_V_EXPANDING_WALL
:
2363 case O_H_EXPANDING_STEEL_WALL
:
2364 case O_V_EXPANDING_STEEL_WALL
:
2365 /* checks first if direction is changed. */
2366 if (((get(cave
, x
, y
)==O_H_EXPANDING_WALL
|| get(cave
, x
, y
)==O_H_EXPANDING_STEEL_WALL
) && !cave
->expanding_wall_changed
)
2367 || ((get(cave
, x
, y
)==O_V_EXPANDING_WALL
|| get(cave
, x
, y
)==O_V_EXPANDING_STEEL_WALL
) && cave
->expanding_wall_changed
)) {
2368 if (is_space_dir(cave
, x
, y
, MV_LEFT
)) {
2369 store_dir(cave
, x
, y
, MV_LEFT
, get(cave
, x
, y
));
2370 play_sound_of_element(cave
, get(cave
, x
, y
));
2372 if (is_space_dir(cave
, x
, y
, MV_RIGHT
)) {
2373 store_dir(cave
, x
, y
, MV_RIGHT
, get(cave
, x
, y
));
2374 play_sound_of_element(cave
, get(cave
, x
, y
));
2378 if (is_space_dir(cave
, x
, y
, MV_UP
)) {
2379 store_dir(cave
, x
, y
, MV_UP
, get(cave
, x
, y
));
2380 play_sound_of_element(cave
, get(cave
, x
, y
));
2382 if (is_space_dir(cave
, x
, y
, MV_DOWN
)) {
2383 store_dir(cave
, x
, y
, MV_DOWN
, get(cave
, x
, y
));
2384 play_sound_of_element(cave
, get(cave
, x
, y
));
2389 case O_EXPANDING_WALL
:
2390 case O_EXPANDING_STEEL_WALL
:
2391 /* the wall which grows in all four directions. */
2392 if (is_space_dir(cave
, x
, y
, MV_LEFT
)) {
2393 store_dir(cave
, x
, y
, MV_LEFT
, get(cave
, x
, y
));
2394 play_sound_of_element(cave
, get(cave
, x
, y
));
2396 if (is_space_dir(cave
, x
, y
, MV_RIGHT
)) {
2397 store_dir(cave
, x
, y
, MV_RIGHT
, get(cave
, x
, y
));
2398 play_sound_of_element(cave
, get(cave
, x
, y
));
2400 if (is_space_dir(cave
, x
, y
, MV_UP
)) {
2401 store_dir(cave
, x
, y
, MV_UP
, get(cave
, x
, y
));
2402 play_sound_of_element(cave
, get(cave
, x
, y
));
2404 if (is_space_dir(cave
, x
, y
, MV_DOWN
)) {
2405 store_dir(cave
, x
, y
, MV_DOWN
, get(cave
, x
, y
));
2406 play_sound_of_element(cave
, get(cave
, x
, y
));
2412 * unpredictable: g_rand_int
2413 * predictable: c64 predictable random generator.
2414 * for predictable, a random number is generated, whether or not it is even possible that the stone
2415 * will be able to pass.
2417 if (cave
->slime_predictable
? ((gd_cave_c64_random (cave
)&cave
->slime_permeability_c64
)==0) : g_rand_int_range(cave
->random
, 0, 1000000)<cave
->slime_permeability
*1000000) {
2418 GdDirection grav
=cave
->gravity
;
2419 GdDirection oppos
=opposite
[cave
->gravity
];
2421 /* space under the slime? elements may pass from top to bottom then. */
2422 if (is_space_dir(cave
, x
, y
, grav
)) {
2423 if (get_dir(cave
, x
, y
, oppos
)==cave
->slime_eats_1
) {
2424 store_dir(cave
, x
, y
, grav
, cave
->slime_converts_1
); /* output a falling xy under */
2425 store_dir(cave
, x
, y
, oppos
, O_SPACE
);
2426 play_sound_of_element(cave
, O_SLIME
);
2428 else if (get_dir(cave
, x
, y
, oppos
)==cave
->slime_eats_2
) {
2429 store_dir(cave
, x
, y
, grav
, cave
->slime_converts_2
);
2430 store_dir(cave
, x
, y
, oppos
, O_SPACE
);
2431 play_sound_of_element(cave
, O_SLIME
);
2433 else if (get_dir(cave
, x
, y
, oppos
)==O_WAITING_STONE
) { /* waiting stones pass without awakening */
2434 store_dir(cave
, x
, y
, grav
, O_WAITING_STONE
);
2435 store_dir(cave
, x
, y
, oppos
, O_SPACE
);
2436 play_sound_of_element(cave
, O_SLIME
);
2438 else if (get_dir(cave
, x
, y
, oppos
)==O_CHASING_STONE
) { /* chasing stones pass */
2439 store_dir(cave
, x
, y
, grav
, O_CHASING_STONE
);
2440 store_dir(cave
, x
, y
, oppos
, O_SPACE
);
2441 play_sound_of_element(cave
, O_SLIME
);
2444 /* or space over the slime? elements may pass from bottom to up then. */
2445 if (is_space_dir(cave
, x
, y
, oppos
)) {
2446 if (get_dir(cave
, x
, y
, grav
)==O_BLADDER
) { /* bladders move UP the slime */
2447 store_dir(cave
, x
, y
, grav
, O_SPACE
);
2448 store_dir(cave
, x
, y
, oppos
, O_BLADDER_1
);
2449 play_sound_of_element(cave
, O_SLIME
);
2451 if (get_dir(cave
, x
, y
, grav
)==O_FLYING_STONE
) {
2452 store_dir(cave
, x
, y
, grav
, O_SPACE
);
2453 store_dir(cave
, x
, y
, oppos
, O_FLYING_STONE_F
);
2454 play_sound_of_element(cave
, O_SLIME
);
2456 if (get_dir(cave
, x
, y
, grav
)==O_FLYING_DIAMOND
) {
2457 store_dir(cave
, x
, y
, grav
, O_SPACE
);
2458 store_dir(cave
, x
, y
, oppos
, O_FLYING_DIAMOND_F
);
2459 play_sound_of_element(cave
, O_SLIME
);
2465 case O_FALLING_WALL
:
2466 if (is_space_dir(cave
, x
, y
, grav_compat
)) {
2467 /* try falling if space under. */
2469 for (yy
=y
+1; yy
<y
+cave
->h
; yy
++)
2470 /* yy<y+cave->h is to check everything OVER the wall - since caves wrap around !! */
2471 if (get(cave
, x
, yy
)!=O_SPACE
)
2472 /* stop cycle when other than space */
2474 /* if scanning stopped by a player... start falling! */
2475 if (get(cave
, x
, yy
)==O_PLAYER
|| get(cave
, x
, yy
)==O_PLAYER_GLUED
|| get(cave
, x
, yy
)==O_PLAYER_BOMB
) {
2476 move(cave
, x
, y
, grav_compat
, O_FALLING_WALL_F
);
2477 /* no sound when the falling wall starts falling! */
2482 case O_FALLING_WALL_F
:
2483 switch (get_dir(cave
, x
, y
, grav_compat
)) {
2485 case O_PLAYER_GLUED
:
2487 /* if player under, it explodes - the falling wall, not the player! */
2488 explode (cave
, x
, y
);
2491 /* continue falling */
2492 move(cave
, x
, y
, grav_compat
, O_FALLING_WALL_F
);
2496 play_sound_of_element(cave
, get(cave
, x
, y
));
2497 store(cave
, x
, y
, O_FALLING_WALL
);
2504 * C O N V E Y O R B E L T S
2506 case O_CONVEYOR_RIGHT
:
2507 case O_CONVEYOR_LEFT
:
2508 /* only works if gravity is up or down!!! */
2509 /* first, check for gravity and running belts. */
2510 if (!cave
->gravity_disabled
&& cave
->conveyor_belts_active
) {
2511 const GdDirection
*dir
;
2514 /* decide direction */
2515 left
=get(cave
, x
, y
)!=O_CONVEYOR_RIGHT
;
2516 if (cave
->conveyor_belts_direction_changed
)
2518 dir
=left
?ccw_eighth
:cw_eighth
;
2520 /* CHECK IF IT CONVEYS THE ELEMENT ABOVE IT */
2521 /* if gravity is normal, and the conveyor belt has something ABOVE which can be moved
2523 the gravity is up, so anything that should float now goes DOWN and touches the conveyor */
2524 if ((cave
->gravity
==MV_DOWN
&& moved_by_conveyor_top_dir(cave
, x
, y
, MV_UP
))
2525 || (cave
->gravity
==MV_UP
&& moved_by_conveyor_bottom_dir(cave
, x
, y
, MV_UP
))) {
2526 if (!is_scanned_dir(cave
, x
, y
, MV_UP
) && is_space_dir(cave
, x
, y
, dir
[MV_UP
]))
2528 store_dir(cave
, x
, y
, dir
[MV_UP
], get_dir(cave
, x
, y
, MV_UP
)); /* move */
2529 store_dir(cave
, x
, y
, MV_UP
, O_SPACE
); /* and place a space. */
2532 /* CHECK IF IT CONVEYS THE ELEMENT BELOW IT */
2533 if ((cave
->gravity
==MV_UP
&& moved_by_conveyor_top_dir(cave
, x
, y
, MV_DOWN
))
2534 || (cave
->gravity
==MV_DOWN
&& moved_by_conveyor_bottom_dir(cave
, x
, y
, MV_DOWN
))) {
2535 if (!is_scanned_dir(cave
, x
, y
, MV_DOWN
) && is_space_dir(cave
, x
, y
, dir
[MV_DOWN
]))
2537 store_dir(cave
, x
, y
, dir
[MV_DOWN
], get_dir(cave
, x
, y
, MV_DOWN
)); /* move */
2538 store_dir(cave
, x
, y
, MV_DOWN
, O_SPACE
); /* and clear. */
2545 * S I M P L E C H A N G I N G; E X P L O S I O N S
2548 store(cave
, x
, y
, cave
->explosion_effect
);
2551 store(cave
, x
, y
, O_DIAMOND
);
2554 store(cave
, x
, y
, cave
->diamond_birth_effect
);
2557 store(cave
, x
, y
, O_STONE
);
2560 case O_NITRO_EXPL_4
:
2561 store(cave
, x
, y
, cave
->nitro_explosion_effect
);
2564 store(cave
, x
, y
, cave
->bomb_explosion_effect
);
2566 case O_AMOEBA_2_EXPL_4
:
2567 store(cave
, x
, y
, cave
->amoeba_2_explosion_effect
);
2570 case O_GHOST_EXPL_4
:
2572 static GdElement ghost_explode
[]={
2573 O_SPACE
, O_SPACE
, O_DIRT
, O_DIRT
, O_CLOCK
, O_CLOCK
, O_PRE_OUTBOX
,
2574 O_BOMB
, O_BOMB
, O_PLAYER
, O_GHOST
, O_BLADDER
, O_DIAMOND
, O_SWEET
,
2575 O_WAITING_STONE
, O_BITER_1
2578 store(cave
, x
, y
, ghost_explode
[g_rand_int_range(cave
->random
, 0, G_N_ELEMENTS(ghost_explode
))]);
2582 store(cave
, x
, y
, O_STEEL
);
2585 store(cave
, x
, y
, O_CLOCK
);
2588 explode(cave
, x
, y
);
2591 case O_TRAPPED_DIAMOND
:
2592 if (cave
->diamond_key_collected
)
2593 store(cave
, x
, y
, O_DIAMOND
);
2597 if (cave
->gate_open
) /* if no more diamonds needed */
2598 store(cave
, x
, y
, O_OUTBOX
); /* open outbox */
2600 case O_PRE_INVIS_OUTBOX
:
2601 if (cave
->gate_open
) /* if no more diamonds needed */
2602 store(cave
, x
, y
, O_INVIS_OUTBOX
); /* open outbox. invisible one :P */
2605 if (cave
->hatched
&& !inbox_toggle
) /* if it is time of birth */
2606 store(cave
, x
, y
, O_PRE_PL_1
);
2607 inbox_toggle
=!inbox_toggle
;
2610 store(cave
, x
, y
, O_PLAYER
);
2635 case O_GHOST_EXPL_1
:
2636 case O_GHOST_EXPL_2
:
2637 case O_GHOST_EXPL_3
:
2647 case O_NITRO_EXPL_1
:
2648 case O_NITRO_EXPL_2
:
2649 case O_NITRO_EXPL_3
:
2650 case O_AMOEBA_2_EXPL_1
:
2651 case O_AMOEBA_2_EXPL_2
:
2652 case O_AMOEBA_2_EXPL_3
:
2653 /* simply the next identifier */
2671 found_water
=TRUE
; /* for sound */
2672 /* simply the next identifier */
2676 case O_BLADDER_SPENDER
:
2677 if (is_space_dir(cave
, x
, y
, opposite
[grav_compat
])) {
2678 store_dir(cave
, x
, y
, opposite
[grav_compat
], O_BLADDER
);
2679 store(cave
, x
, y
, O_PRE_STEEL_1
);
2680 play_sound_of_element(cave
, O_BLADDER_SPENDER
);
2687 /* other inanimate elements that do nothing */
2692 /* POSTPROCESSING */
2694 /* another scan-like routine: */
2695 /* short explosions (for example, in bd1) started with explode_2. */
2696 /* internally we use explode_1; and change it to explode_2 if needed. */
2697 if (cave
->short_explosions
)
2698 for (y
=0; y
<cave
->h
; y
++)
2699 for (x
=0; x
<cave
->w
; x
++)
2700 if (is_first_stage_of_explosion(cave
, x
, y
)) {
2702 store(cave
, x
, y
, get(cave
, x
, y
)&~SCANNED
);
2705 /* finally: forget "scanned" flags for objects. */
2706 /* also, check for time penalties. */
2707 /* these is something like an effect table, but we do not really use one. */
2708 for (y
=0; y
<cave
->h
; y
++)
2709 for (x
=0; x
<cave
->w
; x
++) {
2710 if (get(cave
, x
, y
)&SCANNED
)
2711 store(cave
, x
, y
, get(cave
, x
, y
)&~SCANNED
);
2712 if (get(cave
, x
, y
)==O_TIME_PENALTY
) {
2713 store(cave
, x
, y
, O_GRAVESTONE
);
2714 time_decrement_sec
+=cave
->time_penalty
; /* there is time penalty for destroying the voodoo */
2719 /* this loop finds the coordinates of the player. needed for scrolling and chasing stone.*/
2720 /* but we only do this, if a living player was found. if not yet, the setup routine coordinates are used */
2721 if (cave
->player_state
==GD_PL_LIVING
) {
2722 if (cave
->active_is_first_found
) {
2723 /* to be 1stb compatible, we do everything backwards. */
2724 for (y
=cave
->h
-1; y
>=0; y
--)
2725 for (x
=cave
->w
-1; x
>=0; x
--)
2726 if (is_player(cave
, x
, y
)) {
2727 /* here we remember the coordinates. */
2734 /* as in the original: look for the last one */
2735 for (y
=0; y
<cave
->h
; y
++)
2736 for (x
=0; x
<cave
->w
; x
++)
2737 if (is_player(cave
, x
, y
)) {
2738 /* here we remember the coordinates. */
2745 /* record coordinates of player for chasing stone */
2746 for (i
=0; i
<G_N_ELEMENTS(cave
->px
)-1; i
++) {
2747 cave
->px
[i
]=cave
->px
[i
+1];
2748 cave
->py
[i
]=cave
->py
[i
+1];
2750 cave
->px
[G_N_ELEMENTS(cave
->px
)-1]=cave
->player_x
;
2751 cave
->py
[G_N_ELEMENTS(cave
->py
)-1]=cave
->player_y
;
2755 /* update timing calculated by iterating and counting elements which
2756 were slow to process on c64 */
2757 switch (cave
->scheduling
) {
2758 case GD_SCHEDULING_MILLISECONDS
:
2759 /* cave->speed already contains the milliseconds value, do not touch it */
2762 case GD_SCHEDULING_BD1
:
2763 if (!cave
->intermission
)
2764 /* non-intermissions */
2765 cave
->speed
=(88+3.66*cave
->c64_timing
+(cave
->ckdelay
+cave
->ckdelay_extra_for_animation
)/1000);
2767 /* intermissions were quicker, as only lines 1-12 were processed by the engine. */
2768 cave
->speed
=(60+3.66*cave
->c64_timing
+(cave
->ckdelay
+cave
->ckdelay_extra_for_animation
)/1000);
2771 case GD_SCHEDULING_BD1_ATARI
:
2772 /* about 20ms/frame faster than c64 version */
2773 if (!cave
->intermission
)
2774 cave
->speed
=(74+3.2*cave
->c64_timing
+(cave
->ckdelay
)/1000); /* non-intermissions */
2776 cave
->speed
=(65+2.88*cave
->c64_timing
+(cave
->ckdelay
)/1000); /* for intermissions */
2779 case GD_SCHEDULING_BD2
:
2780 /* 60 is a guess. */
2781 cave
->speed
=MAX(60+(cave
->ckdelay
+cave
->ckdelay_extra_for_animation
)/1000, cave
->c64_timing
*20);
2784 case GD_SCHEDULING_PLCK
:
2785 /* 65 is totally empty cave in construction kit, with delay=0) */
2786 cave
->speed
=MAX(65+cave
->ckdelay
/1000, cave
->c64_timing
*20);
2789 case GD_SCHEDULING_BD2_PLCK_ATARI
:
2790 /* a really fast engine; timing works like c64 plck. */
2791 /* 40 ms was measured in the construction kit, with delay=0 */
2792 cave
->speed
=MAX(40+cave
->ckdelay
/1000, cave
->c64_timing
*20);
2795 case GD_SCHEDULING_CRDR
:
2796 if (cave
->hammered_walls_reappear
)
2797 cave
->ckdelay
+=60000;
2798 cave
->speed
=MAX(130+cave
->ckdelay
/1000, cave
->c64_timing
*20);
2801 case GD_SCHEDULING_MAX
:
2802 /* to avoid compiler warning */
2803 g_assert_not_reached();
2807 /* cave 3 sounds. precedence is controlled by the sound_play function. */
2808 /* but we have to check amoeba&magic together as they had a different gritty sound when mixed */
2809 if (found_water
&& cave
->water_sound
)
2810 gd_sound_play(cave
, GD_S_WATER
);
2811 magic_sound
=cave
->magic_wall_state
==GD_MW_ACTIVE
&& cave
->magic_wall_sound
;
2812 amoeba_sound
=cave
->hatched
&& cave
->amoeba_sound
&& ((amoeba_count
>0 && cave
->amoeba_state
==GD_AM_AWAKE
) || (amoeba_2_count
>0 && cave
->amoeba_2_state
==GD_AM_AWAKE
));
2813 if (amoeba_sound
&& magic_sound
)
2814 gd_sound_play(cave
, GD_S_AMOEBA_MAGIC
);
2817 gd_sound_play(cave
, GD_S_AMOEBA
);
2820 gd_sound_play(cave
, GD_S_MAGIC_WALL
);
2822 if ((amoeba_count
>0 && cave
->amoeba_state
==GD_AM_AWAKE
)
2823 || (amoeba_2_count
>0 && cave
->amoeba_2_state
==GD_AM_AWAKE
))
2824 play_sound_of_element(cave
, O_AMOEBA
);
2825 /* pneumatic hammer sound - overrides everything. */
2826 if (cave
->pneumatic_hammer_active_delay
>0 && cave
->pneumatic_hammer_sound
)
2827 gd_sound_play(cave
, GD_S_PNEUMATIC_HAMMER
);
2829 /* CAVE VARIABLES */
2832 if ((cave
->player_state
==GD_PL_LIVING
&& cave
->player_seen_ago
>15) || cave
->kill_player
) /* check if player is alive. */
2833 cave
->player_state
=GD_PL_DIED
;
2834 if (cave
->voodoo_touched
) /* check if any voodoo exploded, and kill players the next scan if that happended. */
2835 cave
->kill_player
=TRUE
;
2838 if (cave
->amoeba_state
==GD_AM_AWAKE
) {
2839 /* check flags after evaluating. */
2840 if (amoeba_count
>=cave
->amoeba_max_count
)
2841 cave
->amoeba_state
=GD_AM_TOO_BIG
;
2842 if (amoeba_found_enclosed
)
2843 cave
->amoeba_state
=GD_AM_ENCLOSED
;
2845 /* amoeba can also be turned into diamond by magic wall */
2846 if (cave
->magic_wall_stops_amoeba
&& cave
->magic_wall_state
==GD_MW_ACTIVE
)
2847 cave
->amoeba_state
=GD_AM_ENCLOSED
;
2849 if (cave
->amoeba_2_state
==GD_AM_AWAKE
) {
2850 /* check flags after evaluating. */
2851 if (amoeba_2_count
>=cave
->amoeba_2_max_count
)
2852 cave
->amoeba_2_state
=GD_AM_TOO_BIG
;
2853 if (amoeba_2_found_enclosed
)
2854 cave
->amoeba_2_state
=GD_AM_ENCLOSED
;
2856 /* amoeba 2 can also be turned into diamond by magic wall */
2857 if (cave
->magic_wall_stops_amoeba
&& cave
->magic_wall_state
==GD_MW_ACTIVE
)
2858 cave
->amoeba_2_state
=GD_AM_ENCLOSED
;
2861 /* now check times. --------------------------- */
2862 /* decrement time if a voodoo was killed. */
2863 cave
->time
-=time_decrement_sec
*cave
->timing_factor
;
2867 /* only decrement time when player is already born. */
2868 if (cave
->hatched
) {
2869 int secondsbefore
, secondsafter
;
2871 secondsbefore
=cave
->time
/cave
->timing_factor
;
2872 cave
->time
-=cave
->speed
;
2875 secondsafter
=cave
->time
/cave
->timing_factor
;
2876 if (cave
->time
/cave
->timing_factor
<10)
2877 /* if less than 10 seconds, no walking sound, but play explosion sound */
2878 gd_sound_play(cave
, GD_S_NONE
);
2879 if (secondsbefore
!=secondsafter
)
2880 gd_cave_set_seconds_sound(cave
);
2882 /* a gravity switch was activated; seconds counting down */
2883 if (cave
->gravity_will_change
>0) {
2884 cave
->gravity_will_change
-=cave
->speed
;
2885 if (cave
->gravity_will_change
<0)
2886 cave
->gravity_will_change
=0;
2888 if (cave
->gravity_will_change
==0) {
2889 cave
->gravity
=cave
->gravity_next_direction
;
2890 if (cave
->gravity_change_sound
)
2891 gd_sound_play(cave
, GD_S_GRAVITY_CHANGE
); /* takes precedence over amoeba and magic wall sound */
2895 /* creatures direction automatically change */
2896 if (cave
->creatures_direction_will_change
>0) {
2897 cave
->creatures_direction_will_change
-=cave
->speed
;
2898 if (cave
->creatures_direction_will_change
<0)
2899 cave
->creatures_direction_will_change
=0;
2901 if (cave
->creatures_direction_will_change
==0) {
2902 if (cave
->creature_direction_auto_change_sound
)
2903 gd_sound_play(cave
, GD_S_SWITCH_CREATURES
);
2904 cave
->creatures_backwards
=!cave
->creatures_backwards
;
2905 cave
->creatures_direction_will_change
=cave
->creatures_direction_auto_change_time
*cave
->timing_factor
;
2909 /* magic wall; if active&wait or not wait for hatching */
2910 if (cave
->magic_wall_state
==GD_MW_ACTIVE
&& (cave
->hatched
|| !cave
->magic_timer_wait_for_hatching
)) {
2911 cave
->magic_wall_time
-=cave
->speed
;
2912 if (cave
->magic_wall_time
<0)
2913 cave
->magic_wall_time
=0;
2914 if (cave
->magic_wall_time
==0)
2915 cave
->magic_wall_state
=GD_MW_EXPIRED
;
2917 /* we may wait for hatching, when starting amoeba */
2918 if (cave
->amoeba_timer_started_immediately
|| (cave
->amoeba_state
==GD_AM_AWAKE
&& (cave
->hatched
|| !cave
->amoeba_timer_wait_for_hatching
))) {
2919 cave
->amoeba_time
-=cave
->speed
;
2920 if (cave
->amoeba_time
<0)
2921 cave
->amoeba_time
=0;
2922 if (cave
->amoeba_time
==0)
2923 cave
->amoeba_growth_prob
=cave
->amoeba_fast_growth_prob
;
2925 /* we may wait for hatching, when starting amoeba */
2926 if (cave
->amoeba_timer_started_immediately
|| (cave
->amoeba_2_state
==GD_AM_AWAKE
&& (cave
->hatched
|| !cave
->amoeba_timer_wait_for_hatching
))) {
2927 cave
->amoeba_2_time
-=cave
->speed
;
2928 if (cave
->amoeba_2_time
<0)
2929 cave
->amoeba_2_time
=0;
2930 if (cave
->amoeba_2_time
==0)
2931 cave
->amoeba_2_growth_prob
=cave
->amoeba_2_fast_growth_prob
;
2934 /* check for player hatching. */
2936 /* if not the c64 scheduling, but the correct frametime is used, hatching delay should always be decremented. */
2937 /* otherwise, the if (millisecs...) condition below will set this. */
2938 if (cave
->scheduling
==GD_SCHEDULING_MILLISECONDS
) { /* NON-C64 scheduling */
2939 if (cave
->hatching_delay_frame
>0) {
2940 cave
->hatching_delay_frame
--; /* for milliseconds-based, non-c64 schedulings, hatching delay means frames. */
2941 if (cave
->hatching_delay_frame
==0)
2945 else { /* C64 scheduling */
2946 if (cave
->hatching_delay_time
>0) {
2947 cave
->hatching_delay_time
-=cave
->speed
; /* for c64 schedulings, hatching delay means milliseconds. */
2948 if (cave
->hatching_delay_time
<=0) {
2949 cave
->hatching_delay_time
=0;
2955 /* if decremented hatching, and it became zero: */
2956 if (start_signal
) { /* THIS IS THE CAVE START SIGNAL */
2957 cave
->hatched
=TRUE
; /* record that now the cave is in its normal state */
2959 gd_cave_count_diamonds(cave
); /* if diamonds needed is below zero, we count the available diamonds now. */
2961 /* setup direction auto change */
2962 if (cave
->creatures_direction_auto_change_time
) {
2963 cave
->creatures_direction_will_change
=cave
->creatures_direction_auto_change_time
*cave
->timing_factor
;
2965 if (cave
->creatures_direction_auto_change_on_start
)
2966 cave
->creatures_backwards
=!cave
->creatures_backwards
;
2969 gd_sound_play(cave
, GD_S_CRACK
);
2973 if (cave
->biters_wait_frame
==0)
2974 cave
->biters_wait_frame
=cave
->biter_delay_frame
;
2976 cave
->biters_wait_frame
--;
2977 /* replicators delay */
2978 if (cave
->replicators_wait_frame
==0)
2979 cave
->replicators_wait_frame
=cave
->replicator_delay_frame
;
2981 cave
->replicators_wait_frame
--;
2986 /* check if cave failed by timeout */
2987 if (cave
->player_state
==GD_PL_LIVING
&& cave
->time
==0) {
2988 gd_cave_clear_sounds(cave
);
2989 cave
->player_state
=GD_PL_TIMEOUT
;
2990 gd_sound_play(cave
, GD_S_TIMEOUT
);
2993 /* set these for drawing. */
2994 cave
->last_direction
=player_move
;
2995 /* here we remember last movements for animation. this is needed here, as animation
2996 is in sync with the game, not the keyboard directly. (for example, after exiting
2997 the cave, the player was "running" in the original, till bonus points were counted
2998 for remaining time and so on. */
2999 if (player_move
==MV_LEFT
|| player_move
==MV_UP_LEFT
|| player_move
==MV_DOWN_LEFT
)
3000 cave
->last_horizontal_direction
=MV_LEFT
;
3001 if (player_move
==MV_RIGHT
|| player_move
==MV_UP_RIGHT
|| player_move
==MV_DOWN_RIGHT
)
3002 cave
->last_horizontal_direction
=MV_RIGHT
;