added support for "player is moving up/down" graphics for BD engine
[rocksndiamonds.git] / src / game.c
index d6ff2454cff5f4fcfe07cf5c3aa4efd82d771194..506def33ce0682ae91f3903b2802715300dcba56 100644 (file)
@@ -89,7 +89,7 @@
 // game panel display and control definitions
 #define GAME_PANEL_LEVEL_NUMBER                        0
 #define GAME_PANEL_GEMS                                1
-#define GAME_PANEL_GEMS_TOTAL                  2
+#define GAME_PANEL_GEMS_NEEDED                 2
 #define GAME_PANEL_GEMS_COLLECTED              3
 #define GAME_PANEL_GEMS_SCORE                  4
 #define GAME_PANEL_INVENTORY_COUNT             5
@@ -246,8 +246,8 @@ static struct GamePanelControlInfo game_panel_controls[] =
     TYPE_INTEGER,
   },
   {
-    GAME_PANEL_GEMS_TOTAL,
-    &game.panel.gems_total,
+    GAME_PANEL_GEMS_NEEDED,
+    &game.panel.gems_needed,
     TYPE_INTEGER,
   },
   {
@@ -1835,6 +1835,29 @@ static void InitPlayerField(int x, int y, int element, boolean init_game)
   }
 }
 
+static void InitFieldForEngine_RND(int x, int y)
+{
+  int element = Tile[x][y];
+
+  // convert BD engine elements to corresponding R'n'D engine elements
+  element = (element == EL_BD_EMPTY            ? EL_EMPTY :
+            element == EL_BD_PLAYER            ? EL_PLAYER_1 :
+            element == EL_BD_INBOX             ? EL_PLAYER_1 :
+            element == EL_BD_SAND              ? EL_SAND :
+            element == EL_BD_STEELWALL         ? EL_STEELWALL :
+            element == EL_BD_EXIT_CLOSED       ? EL_EXIT_CLOSED :
+            element == EL_BD_EXIT_OPEN         ? EL_EXIT_OPEN :
+            element);
+
+  Tile[x][y] = element;
+}
+
+static void InitFieldForEngine(int x, int y)
+{
+  if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
+    InitFieldForEngine_RND(x, y);
+}
+
 static void InitField(int x, int y, boolean init_game)
 {
   int element = Tile[x][y];
@@ -2291,10 +2314,10 @@ static void UpdateGameControlValues(void)
              level.game_engine_type == GAME_ENGINE_TYPE_MM ?
              game_mm.kettles_still_needed :
              game.gems_still_needed);
-  int gems_total = level.gems_needed;
+  int gems_needed = level.gems_needed;
   int gems_collected = (level.game_engine_type == GAME_ENGINE_TYPE_BD ?
                        game_bd.game->cave->diamonds_collected :
-                       gems_total - gems);
+                       gems_needed - gems);
   int gems_score = (level.game_engine_type == GAME_ENGINE_TYPE_BD ?
                    game_bd.game->cave->diamond_value :
                    level.score[SC_EMERALD]);
@@ -2325,7 +2348,7 @@ static void UpdateGameControlValues(void)
   // used instead of "level_nr" (for network games)
   game_panel_controls[GAME_PANEL_LEVEL_NUMBER].value = levelset.level_nr;
   game_panel_controls[GAME_PANEL_GEMS].value = gems;
-  game_panel_controls[GAME_PANEL_GEMS_TOTAL].value = gems_total;
+  game_panel_controls[GAME_PANEL_GEMS_NEEDED].value = gems_needed;
   game_panel_controls[GAME_PANEL_GEMS_COLLECTED].value = gems_collected;
   game_panel_controls[GAME_PANEL_GEMS_SCORE].value = gems_score;
 
@@ -2722,7 +2745,7 @@ static void DisplayGameControlValues(void)
     if (PANEL_DEACTIVATED(pos))
       continue;
 
-    if (pos->class == get_hash_from_key("extra_panel_items") &&
+    if (pos->class == get_hash_from_string("extra_panel_items") &&
        !setup.prefer_extra_panel_items)
       continue;
 
@@ -2814,7 +2837,7 @@ static void DisplayGameControlValues(void)
       int width, height;
       int dst_x = PANEL_XPOS(pos);
       int dst_y = PANEL_YPOS(pos);
-      boolean skip = (pos->class == get_hash_from_key("mm_engine_only") &&
+      boolean skip = (pos->class == get_hash_from_string("mm_engine_only") &&
                      level.game_engine_type != GAME_ENGINE_TYPE_MM);
 
       if (graphic != IMG_UNDEFINED && !skip)
@@ -3951,8 +3974,6 @@ void InitGame(void)
 
   game.explosions_delayed = TRUE;
 
-  game.envelope_active = FALSE;
-
   // special case: set custom artwork setting to initial value
   game.use_masked_elements = game.use_masked_elements_initial;
 
@@ -4007,6 +4028,8 @@ void InitGame(void)
 
   SCAN_PLAYFIELD(x, y)
   {
+    InitFieldForEngine(x, y);
+
     if (emulate_bd && !IS_BD_ELEMENT(Tile[x][y]))
       emulate_bd = FALSE;
     if (emulate_sp && !IS_SP_ELEMENT(Tile[x][y]))
@@ -4597,6 +4620,8 @@ void InitGame(void)
 
   game.restart_level = FALSE;
   game.request_active = FALSE;
+  game.envelope_active = FALSE;
+  game.any_door_active = FALSE;
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
     InitGameActions_MM();
@@ -4881,6 +4906,31 @@ static void LevelSolved(void)
   LevelSolved_SetFinalGameValues();
 }
 
+static boolean AdvanceToNextLevel(void)
+{
+  if (setup.increment_levels &&
+      level_nr < leveldir_current->last_level &&
+      !network_playing)
+  {
+    level_nr++;                // advance to next level
+    TapeErase();       // start with empty tape
+
+    if (setup.auto_play_next_level)
+    {
+      scores.continue_playing = TRUE;
+      scores.next_level_nr = level_nr;
+
+      LoadLevel(level_nr);
+
+      SaveLevelSetup_SeriesInfo();
+    }
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
 void GameWon(void)
 {
   static int time_count_steps;
@@ -5111,8 +5161,21 @@ void GameEnd(void)
   // used instead of "level_nr" (needed for network games)
   int last_level_nr = levelset.level_nr;
   boolean tape_saved = FALSE;
+  boolean game_over = checkGameFailed();
+
+  // Important note: This function is not only called after "GameWon()", but also after
+  // "game over" (if automatically asking for restarting the game is disabled in setup)
+
+  // do not handle game end if game over and automatically asking for game restart
+  if (game_over && setup.ask_on_game_over)
+    return;
+
+  // do not handle game end if request dialog is already active
+  if (checkRequestActive())
+    return;
 
-  game.LevelSolved_GameEnd = TRUE;
+  if (game.LevelSolved)
+    game.LevelSolved_GameEnd = TRUE;
 
   if (game.LevelSolved_SaveTape && !score_info_tape_play)
   {
@@ -5139,7 +5202,7 @@ void GameEnd(void)
     return;
   }
 
-  if (!game.LevelSolved_SaveScore)
+  if (!game.GamePlayed || (!game.LevelSolved_SaveScore && !level.bd_intermission))
   {
     SetGameStatus(GAME_MODE_MAIN);
 
@@ -5156,27 +5219,13 @@ void GameEnd(void)
   }
 
   // save score and score tape before potentially erasing tape below
-  NewHighScore(last_level_nr, tape_saved);
+  if (game.LevelSolved_SaveScore)
+    NewHighScore(last_level_nr, tape_saved);
 
-  if (setup.increment_levels &&
-      level_nr < leveldir_current->last_level &&
-      !network_playing)
-  {
-    level_nr++;                // advance to next level
-    TapeErase();       // start with empty tape
-
-    if (setup.auto_play_next_level)
-    {
-      scores.continue_playing = TRUE;
-      scores.next_level_nr = level_nr;
-
-      LoadLevel(level_nr);
-
-      SaveLevelSetup_SeriesInfo();
-    }
-  }
+  // increment and load next level (if possible and not configured otherwise)
+  AdvanceToNextLevel();
 
-  if (scores.last_added >= 0 && setup.show_scores_after_game)
+  if (game.LevelSolved_SaveScore && scores.last_added >= 0 && setup.show_scores_after_game)
   {
     SetGameStatus(GAME_MODE_SCORES);
 
@@ -15537,56 +15586,81 @@ static int getSoundAction_BD(int sample)
 {
   switch (sample)
   {
-    case GD_S_STONE:
-    case GD_S_NUT:
-    case GD_S_DIRT_BALL:
-    case GD_S_NITRO:
-    case GD_S_FALLING_WALL:
+    case GD_S_STONE_PUSHING:
+    case GD_S_MEGA_STONE_PUSHING:
+    case GD_S_FLYING_STONE_PUSHING:
+    case GD_S_WAITING_STONE_PUSHING:
+    case GD_S_CHASING_STONE_PUSHING:
+    case GD_S_NUT_PUSHING:
+    case GD_S_NITRO_PACK_PUSHING:
+    case GD_S_BLADDER_PUSHING:
+    case GD_S_BOX_PUSHING:
+      return ACTION_PUSHING;
+
+    case GD_S_STONE_FALLING:
+    case GD_S_MEGA_STONE_FALLING:
+    case GD_S_FLYING_STONE_FALLING:
+    case GD_S_NUT_FALLING:
+    case GD_S_DIRT_BALL_FALLING:
+    case GD_S_DIRT_LOOSE_FALLING:
+    case GD_S_NITRO_PACK_FALLING:
+    case GD_S_FALLING_WALL_FALLING:
+      return ACTION_FALLING;
+
+    case GD_S_STONE_IMPACT:
+    case GD_S_MEGA_STONE_IMPACT:
+    case GD_S_FLYING_STONE_IMPACT:
+    case GD_S_NUT_IMPACT:
+    case GD_S_DIRT_BALL_IMPACT:
+    case GD_S_DIRT_LOOSE_IMPACT:
+    case GD_S_NITRO_PACK_IMPACT:
+    case GD_S_FALLING_WALL_IMPACT:
       return ACTION_IMPACT;
 
-    case GD_S_NUT_CRACK:
+    case GD_S_NUT_CRACKING:
       return ACTION_BREAKING;
 
     case GD_S_EXPANDING_WALL:
-    case GD_S_WALL_REAPPEAR:
+    case GD_S_WALL_REAPPEARING:
     case GD_S_SLIME:
     case GD_S_LAVA:
-    case GD_S_ACID_SPREAD:
+    case GD_S_ACID_SPREADING:
       return ACTION_GROWING;
 
-    case GD_S_DIAMOND_COLLECT:
-    case GD_S_SKELETON_COLLECT:
-    case GD_S_PNEUMATIC_COLLECT:
-    case GD_S_BOMB_COLLECT:
-    case GD_S_CLOCK_COLLECT:
-    case GD_S_SWEET_COLLECT:
-    case GD_S_KEY_COLLECT:
-    case GD_S_DIAMOND_KEY_COLLECT:
+    case GD_S_DIAMOND_COLLECTING:
+    case GD_S_FLYING_DIAMOND_COLLECTING:
+    case GD_S_SKELETON_COLLECTING:
+    case GD_S_PNEUMATIC_COLLECTING:
+    case GD_S_BOMB_COLLECTING:
+    case GD_S_CLOCK_COLLECTING:
+    case GD_S_SWEET_COLLECTING:
+    case GD_S_KEY_COLLECTING:
+    case GD_S_DIAMOND_KEY_COLLECTING:
       return ACTION_COLLECTING;
 
-    case GD_S_BOMB_PLACE:
+    case GD_S_BOMB_PLACING:
     case GD_S_REPLICATOR:
       return ACTION_DROPPING;
 
-    case GD_S_BLADDER_MOVE:
+    case GD_S_BLADDER_MOVING:
       return ACTION_MOVING;
 
     case GD_S_BLADDER_SPENDER:
-    case GD_S_BLADDER_CONVERT:
-    case GD_S_GRAVITY_CHANGE:
+    case GD_S_BLADDER_CONVERTING:
+    case GD_S_GRAVITY_CHANGING:
       return ACTION_CHANGING;
 
-    case GD_S_BITER_EAT:
+    case GD_S_BITER_EATING:
       return ACTION_EATING;
 
-    case GD_S_DOOR_OPEN:
-    case GD_S_CRACK:
+    case GD_S_DOOR_OPENING:
+    case GD_S_CRACKING:
       return ACTION_OPENING;
 
-    case GD_S_WALK_EARTH:
+    case GD_S_DIRT_WALKING:
       return ACTION_DIGGING;
 
-    case GD_S_WALK_EMPTY:
+    case GD_S_EMPTY_WALKING:
       return ACTION_WALKING;
 
     case GD_S_SWITCH_BITER:
@@ -15598,36 +15672,59 @@ static int getSoundAction_BD(int sample)
     case GD_S_STIRRING:
       return ACTION_ACTIVATING;
 
-    case GD_S_BOX_PUSH:
-      return ACTION_PUSHING;
-
     case GD_S_TELEPORTER:
       return ACTION_PASSING;
 
-    case GD_S_EXPLOSION:
-    case GD_S_BOMB_EXPLOSION:
-    case GD_S_GHOST_EXPLOSION:
-    case GD_S_VOODOO_EXPLOSION:
-    case GD_S_NITRO_EXPLOSION:
+    case GD_S_EXPLODING:
+    case GD_S_BOMB_EXPLODING:
+    case GD_S_GHOST_EXPLODING:
+    case GD_S_VOODOO_EXPLODING:
+    case GD_S_NITRO_PACK_EXPLODING:
       return ACTION_EXPLODING;
 
-    case GD_S_COVER:
+    case GD_S_COVERING:
     case GD_S_AMOEBA:
-    case GD_S_AMOEBA_MAGIC:
     case GD_S_MAGIC_WALL:
     case GD_S_PNEUMATIC_HAMMER:
     case GD_S_WATER:
       return ACTION_ACTIVE;
 
-    case GD_S_DIAMOND_RANDOM:
-    case GD_S_DIAMOND_1:
-    case GD_S_DIAMOND_2:
-    case GD_S_DIAMOND_3:
-    case GD_S_DIAMOND_4:
-    case GD_S_DIAMOND_5:
-    case GD_S_DIAMOND_6:
-    case GD_S_DIAMOND_7:
-    case GD_S_DIAMOND_8:
+    case GD_S_DIAMOND_FALLING_RANDOM:
+    case GD_S_DIAMOND_FALLING_1:
+    case GD_S_DIAMOND_FALLING_2:
+    case GD_S_DIAMOND_FALLING_3:
+    case GD_S_DIAMOND_FALLING_4:
+    case GD_S_DIAMOND_FALLING_5:
+    case GD_S_DIAMOND_FALLING_6:
+    case GD_S_DIAMOND_FALLING_7:
+    case GD_S_DIAMOND_FALLING_8:
+    case GD_S_DIAMOND_IMPACT_RANDOM:
+    case GD_S_DIAMOND_IMPACT_1:
+    case GD_S_DIAMOND_IMPACT_2:
+    case GD_S_DIAMOND_IMPACT_3:
+    case GD_S_DIAMOND_IMPACT_4:
+    case GD_S_DIAMOND_IMPACT_5:
+    case GD_S_DIAMOND_IMPACT_6:
+    case GD_S_DIAMOND_IMPACT_7:
+    case GD_S_DIAMOND_IMPACT_8:
+    case GD_S_FLYING_DIAMOND_FALLING_RANDOM:
+    case GD_S_FLYING_DIAMOND_FALLING_1:
+    case GD_S_FLYING_DIAMOND_FALLING_2:
+    case GD_S_FLYING_DIAMOND_FALLING_3:
+    case GD_S_FLYING_DIAMOND_FALLING_4:
+    case GD_S_FLYING_DIAMOND_FALLING_5:
+    case GD_S_FLYING_DIAMOND_FALLING_6:
+    case GD_S_FLYING_DIAMOND_FALLING_7:
+    case GD_S_FLYING_DIAMOND_FALLING_8:
+    case GD_S_FLYING_DIAMOND_IMPACT_RANDOM:
+    case GD_S_FLYING_DIAMOND_IMPACT_1:
+    case GD_S_FLYING_DIAMOND_IMPACT_2:
+    case GD_S_FLYING_DIAMOND_IMPACT_3:
+    case GD_S_FLYING_DIAMOND_IMPACT_4:
+    case GD_S_FLYING_DIAMOND_IMPACT_5:
+    case GD_S_FLYING_DIAMOND_IMPACT_6:
+    case GD_S_FLYING_DIAMOND_IMPACT_7:
+    case GD_S_FLYING_DIAMOND_IMPACT_8:
     case GD_S_TIMEOUT_0:
     case GD_S_TIMEOUT_1:
     case GD_S_TIMEOUT_2:
@@ -15640,10 +15737,12 @@ static int getSoundAction_BD(int sample)
     case GD_S_TIMEOUT_9:
     case GD_S_TIMEOUT_10:
     case GD_S_BONUS_LIFE:
-      // kludge to prevent playing as loop sound
+      // trigger special post-processing (and force sound to be non-looping)
       return ACTION_OTHER;
 
+    case GD_S_AMOEBA_MAGIC:
     case GD_S_FINISHED:
+      // trigger special post-processing (and force sound to be looping)
       return ACTION_DEFAULT;
 
     default:
@@ -15662,32 +15761,77 @@ static int getSoundEffect_BD(int element_bd, int sample)
       sound_action != ACTION_DEFAULT)
     return sound_effect;
 
-  // special sounds
+  // special post-processing for some sounds
   switch (sample)
   {
-    case GD_S_DIAMOND_RANDOM:
-      nr = GetSimpleRandom(8);
-      sound_effect = SND_BD_DIAMOND_IMPACT_RANDOM_1 + nr;
+    case GD_S_DIAMOND_FALLING_RANDOM:
+    case GD_S_DIAMOND_FALLING_1:
+    case GD_S_DIAMOND_FALLING_2:
+    case GD_S_DIAMOND_FALLING_3:
+    case GD_S_DIAMOND_FALLING_4:
+    case GD_S_DIAMOND_FALLING_5:
+    case GD_S_DIAMOND_FALLING_6:
+    case GD_S_DIAMOND_FALLING_7:
+    case GD_S_DIAMOND_FALLING_8:
+      nr = (sample == GD_S_DIAMOND_FALLING_RANDOM ? GetSimpleRandom(8) :
+           sample - GD_S_DIAMOND_FALLING_1);
+      sound_effect = SND_BD_DIAMOND_FALLING_RANDOM_1 + nr;
 
       if (getSoundInfoEntryFilename(sound_effect) == NULL)
-       sound_effect = SND_BD_DIAMOND_IMPACT;
+       sound_effect = SND_BD_DIAMOND_FALLING;
       break;
 
-    case GD_S_DIAMOND_1:
-    case GD_S_DIAMOND_2:
-    case GD_S_DIAMOND_3:
-    case GD_S_DIAMOND_4:
-    case GD_S_DIAMOND_5:
-    case GD_S_DIAMOND_6:
-    case GD_S_DIAMOND_7:
-    case GD_S_DIAMOND_8:
-      nr = sample - GD_S_DIAMOND_1;
+    case GD_S_DIAMOND_IMPACT_RANDOM:
+    case GD_S_DIAMOND_IMPACT_1:
+    case GD_S_DIAMOND_IMPACT_2:
+    case GD_S_DIAMOND_IMPACT_3:
+    case GD_S_DIAMOND_IMPACT_4:
+    case GD_S_DIAMOND_IMPACT_5:
+    case GD_S_DIAMOND_IMPACT_6:
+    case GD_S_DIAMOND_IMPACT_7:
+    case GD_S_DIAMOND_IMPACT_8:
+      nr = (sample == GD_S_DIAMOND_IMPACT_RANDOM ? GetSimpleRandom(8) :
+           sample - GD_S_DIAMOND_IMPACT_1);
       sound_effect = SND_BD_DIAMOND_IMPACT_RANDOM_1 + nr;
 
       if (getSoundInfoEntryFilename(sound_effect) == NULL)
        sound_effect = SND_BD_DIAMOND_IMPACT;
       break;
 
+    case GD_S_FLYING_DIAMOND_FALLING_RANDOM:
+    case GD_S_FLYING_DIAMOND_FALLING_1:
+    case GD_S_FLYING_DIAMOND_FALLING_2:
+    case GD_S_FLYING_DIAMOND_FALLING_3:
+    case GD_S_FLYING_DIAMOND_FALLING_4:
+    case GD_S_FLYING_DIAMOND_FALLING_5:
+    case GD_S_FLYING_DIAMOND_FALLING_6:
+    case GD_S_FLYING_DIAMOND_FALLING_7:
+    case GD_S_FLYING_DIAMOND_FALLING_8:
+      nr = (sample == GD_S_FLYING_DIAMOND_FALLING_RANDOM ? GetSimpleRandom(8) :
+           sample - GD_S_FLYING_DIAMOND_FALLING_1);
+      sound_effect = SND_BD_FLYING_DIAMOND_FALLING_RANDOM_1 + nr;
+
+      if (getSoundInfoEntryFilename(sound_effect) == NULL)
+       sound_effect = SND_BD_FLYING_DIAMOND_FALLING;
+      break;
+
+    case GD_S_FLYING_DIAMOND_IMPACT_RANDOM:
+    case GD_S_FLYING_DIAMOND_IMPACT_1:
+    case GD_S_FLYING_DIAMOND_IMPACT_2:
+    case GD_S_FLYING_DIAMOND_IMPACT_3:
+    case GD_S_FLYING_DIAMOND_IMPACT_4:
+    case GD_S_FLYING_DIAMOND_IMPACT_5:
+    case GD_S_FLYING_DIAMOND_IMPACT_6:
+    case GD_S_FLYING_DIAMOND_IMPACT_7:
+    case GD_S_FLYING_DIAMOND_IMPACT_8:
+      nr = (sample == GD_S_FLYING_DIAMOND_IMPACT_RANDOM ? GetSimpleRandom(8) :
+           sample - GD_S_FLYING_DIAMOND_IMPACT_1);
+      sound_effect = SND_BD_FLYING_DIAMOND_IMPACT_RANDOM_1 + nr;
+
+      if (getSoundInfoEntryFilename(sound_effect) == NULL)
+       sound_effect = SND_BD_FLYING_DIAMOND_IMPACT;
+      break;
+
     case GD_S_TIMEOUT_0:
     case GD_S_TIMEOUT_1:
     case GD_S_TIMEOUT_2:
@@ -15706,14 +15850,18 @@ static int getSoundEffect_BD(int element_bd, int sample)
        sound_effect = SND_GAME_RUNNING_OUT_OF_TIME;
       break;
 
-    case GD_S_FINISHED:
-      sound_effect = SND_GAME_LEVELTIME_BONUS;
-      break;
-
     case GD_S_BONUS_LIFE:
       sound_effect = SND_GAME_HEALTH_BONUS;
       break;
 
+    case GD_S_AMOEBA_MAGIC:
+      sound_effect = SND_BD_AMOEBA_OTHER;
+      break;
+
+    case GD_S_FINISHED:
+      sound_effect = SND_GAME_LEVELTIME_BONUS;
+      break;
+
     default:
       sound_effect = SND_UNDEFINED;
       break;
@@ -15724,7 +15872,7 @@ static int getSoundEffect_BD(int element_bd, int sample)
 
 void PlayLevelSound_BD(int xx, int yy, int element_bd, int sample)
 {
-  int element = (element_bd > -1 ? map_element_BD_to_RND(element_bd) : 0);
+  int element = (element_bd > -1 ? map_element_BD_to_RND_game(element_bd) : 0);
   int sound_effect = getSoundEffect_BD(element, sample);
   int sound_action = getSoundAction_BD(sample);
   boolean is_loop_sound = IS_LOOP_SOUND(sound_effect);
@@ -15732,7 +15880,14 @@ void PlayLevelSound_BD(int xx, int yy, int element_bd, int sample)
   int x = xx - offset;
   int y = yy - offset;
 
-  if (sound_action == ACTION_OTHER)
+  // some sound actions are always looping in native BD game engine
+  if (sound_action == ACTION_DEFAULT)
+    is_loop_sound = TRUE;
+
+  // some sound actions are always non-looping in native BD game engine
+  if (sound_action == ACTION_FALLING ||
+      sound_action == ACTION_MOVING ||
+      sound_action == ACTION_OTHER)
     is_loop_sound = FALSE;
 
   if (sound_effect != SND_UNDEFINED)
@@ -15741,7 +15896,7 @@ void PlayLevelSound_BD(int xx, int yy, int element_bd, int sample)
 
 void StopSound_BD(int element_bd, int sample)
 {
-  int element = (element_bd > -1 ? map_element_BD_to_RND(element_bd) : 0);
+  int element = (element_bd > -1 ? map_element_BD_to_RND_game(element_bd) : 0);
   int sound_effect = getSoundEffect_BD(element, sample);
 
   if (sound_effect != SND_UNDEFINED)
@@ -15750,7 +15905,7 @@ void StopSound_BD(int element_bd, int sample)
 
 boolean isSoundPlaying_BD(int element_bd, int sample)
 {
-  int element = (element_bd > -1 ? map_element_BD_to_RND(element_bd) : 0);
+  int element = (element_bd > -1 ? map_element_BD_to_RND_game(element_bd) : 0);
   int sound_effect = getSoundEffect_BD(element, sample);
 
   if (sound_effect != SND_UNDEFINED)
@@ -16143,7 +16298,17 @@ static void RequestRestartGame(void)
   int request_mode = (has_started_game ? REQ_ASK : REQ_CONFIRM);
   int door_state = DOOR_CLOSE_1;
 
-  if (Request(message, request_mode | REQ_STAY_OPEN) && has_started_game)
+  boolean restart_wanted = (Request(message, request_mode | REQ_STAY_OPEN) && has_started_game);
+
+  // if no restart wanted, continue with next level for BD style intermission levels
+  if (!restart_wanted && !level_editor_test_game && level.bd_intermission)
+  {
+    boolean success = AdvanceToNextLevel();
+
+    restart_wanted = (success && setup.auto_play_next_level);
+  }
+
+  if (restart_wanted)
   {
     CloseDoor(door_state);
 
@@ -16187,7 +16352,7 @@ boolean CheckRestartGame(void)
   }
 
   // do not ask to play again if request dialog is already active
-  if (game.request_active)
+  if (checkRequestActive())
     return FALSE;
 
   // do not ask to play again if request dialog already handled
@@ -16256,6 +16421,11 @@ boolean checkGameEnded(void)
   return (checkGameSolved() || checkGameFailed());
 }
 
+boolean checkRequestActive(void)
+{
+  return (game.request_active || game.envelope_active || game.any_door_active);
+}
+
 
 // ----------------------------------------------------------------------------
 // random generator functions