added single step support for BD engine
[rocksndiamonds.git] / src / game_bd / bd_caveengine.c
index 46c97e57551043390c027b787f9cacadbfeff6a6..5b2bfcdfcd1292268083f70c45a5fa64fd235469 100644 (file)
@@ -126,9 +126,19 @@ void gd_cave_set_seconds_sound(GdCave *cave)
   }
 }
 
+// returns true if the element can fall
+static inline boolean el_can_fall(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_CAN_FALL) != 0;
+}
+
 // play diamond or stone sound of given element.
 static void play_sound_of_element(GdCave *cave, GdElement element, int x, int y)
 {
+  // check if sound should be skipped for falling elements (and only be played on impact)
+  if (el_can_fall(element) && !use_bd_falling_sounds())
+    return;
+
   // stone and diamond fall sounds.
   switch (element)
   {
@@ -449,7 +459,7 @@ static inline boolean rotates_ccw (const GdCave *cave, const int x, const int y)
 }
 
 // returns true if the element is a player
-static inline boolean is_player(const GdCave *cave, const int x, const int y)
+boolean is_player(const GdCave *cave, const int x, const int y)
 {
   return (gd_elements[get(cave, x, y) & O_MASK].properties & P_PLAYER) != 0;
 }
@@ -467,6 +477,13 @@ static inline boolean can_be_hammered_dir(const GdCave *cave, const int x, const
   return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_CAN_BE_HAMMERED) != 0;
 }
 
+// returns true if the element can be pushed
+boolean can_be_pushed_dir(const GdCave *cave, const int x, const int y,
+                         const GdDirection dir)
+{
+  return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_PUSHABLE) != 0;
+}
+
 // returns true if the element is explodable and explodes to space, for example the player
 static inline boolean is_first_stage_of_explosion(const GdCave *cave, const int x, const int y)
 {
@@ -1371,6 +1388,9 @@ static boolean do_fall_try_magic(GdCave *cave, int x, int y,
     // active or non-active or anything, element falling in will always disappear
     store(cave, x, y, O_SPACE);
 
+    if (cave->magic_wall_breakscan && cave->amoeba_state == GD_AM_AWAKE)
+      cave->convert_amoeba_this_frame = TRUE;
+
     return TRUE;
   }
   else
@@ -1550,6 +1570,9 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
 
   gd_cave_clear_sounds(cave);
 
+  game_bd.player_moving = FALSE;
+  game_bd.player_snapping = FALSE;
+
   // if diagonal movements not allowed,
   // horizontal movements have precedence. [BROADRIBB]
   if (!cave->diagonal_movements)
@@ -1604,6 +1627,9 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
   // score collected this frame
   cave->score = 0;
 
+  // to implement buggy bd1 amoeba+magic wall behaviour
+  cave->convert_amoeba_this_frame = FALSE;
+
   // suicide only kills the active player
   // player_x, player_y was set by the previous iterate routine, or the cave setup.
   // we must check if there is a player or not - he may have exploded or something like that
@@ -1812,15 +1838,25 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
              // if snapping anything and we have snapping explosions set.
              // but these is not true for pushing.
              if (remains == O_SPACE && player_fire && !push)
+              {
                remains = cave->snap_element;
 
+               game_bd.player_snapping = TRUE;
+              }
+
              if (remains != O_SPACE || player_fire)
+              {
                // if any other element than space, player cannot move.
                // also if pressing fire, will not move.
                store_dir(cave, x, y, player_move, remains);
+              }
              else
+              {
                // if space remains there, the player moves.
                move(cave, x, y, player_move, O_PLAYER);
+
+               game_bd.player_moving = TRUE;
+              }
            }
          }
          break;
@@ -2847,6 +2883,13 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
          // ============================================================================
 
        case O_AMOEBA:
+         // emulating BD1 amoeba+magic wall bug
+         if (cave->convert_amoeba_this_frame && amoeba_found_enclosed)
+         {
+           store(cave, x, y, cave->amoeba_enclosed_effect);
+           break;
+         }
+
          amoeba_count++;
          switch (cave->amoeba_state)
          {
@@ -3603,7 +3646,7 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
   {
     if ((amoeba_count   > 0 && cave->amoeba_state   == GD_AM_AWAKE) ||
        (amoeba_2_count > 0 && cave->amoeba_2_state == GD_AM_AWAKE))
-      play_sound_of_element(cave, O_AMOEBA, x, y);
+      play_sound_of_element(cave, O_AMOEBA, -1, -1);
   }
 
   // pneumatic hammer sound - overrides everything.