moved code to check for file in level directories to separate function
[rocksndiamonds.git] / src / game.c
index 83b0c1f3cb94a98767c21573f527dcdaac6ee1c2..a516155ce76b269b2704d5ecc3ffe2112899e4c1 100644 (file)
@@ -1840,13 +1840,30 @@ 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 = (element == EL_BDX_EMPTY                           ? EL_EMPTY :
+            element == EL_BDX_PLAYER                           ? EL_PLAYER_1 :
+            element == EL_BDX_INBOX                            ? EL_PLAYER_1 :
+            element == EL_BDX_SAND_1                           ? EL_SAND :
+            element == EL_BDX_WALL                             ? EL_BD_WALL :
+            element == EL_BDX_STEELWALL                        ? EL_STEELWALL :
+            element == EL_BDX_ROCK                             ? EL_BD_ROCK :
+            element == EL_BDX_DIAMOND                          ? EL_BD_DIAMOND :
+            element == EL_BDX_AMOEBA_1                         ? EL_BD_AMOEBA :
+            element == EL_BDX_MAGIC_WALL                       ? EL_BD_MAGIC_WALL :
+            element == EL_BDX_BUTTERFLY_1_RIGHT                ? EL_BD_BUTTERFLY_RIGHT :
+            element == EL_BDX_BUTTERFLY_1_UP                   ? EL_BD_BUTTERFLY_UP :
+            element == EL_BDX_BUTTERFLY_1_LEFT                 ? EL_BD_BUTTERFLY_LEFT :
+            element == EL_BDX_BUTTERFLY_1_DOWN                 ? EL_BD_BUTTERFLY_DOWN :
+            element == EL_BDX_BUTTERFLY_1                      ? EL_BD_BUTTERFLY :
+            element == EL_BDX_FIREFLY_1_RIGHT                  ? EL_BD_FIREFLY_RIGHT :
+            element == EL_BDX_FIREFLY_1_UP                     ? EL_BD_FIREFLY_UP :
+            element == EL_BDX_FIREFLY_1_LEFT                   ? EL_BD_FIREFLY_LEFT :
+            element == EL_BDX_FIREFLY_1_DOWN                   ? EL_BD_FIREFLY_DOWN :
+            element == EL_BDX_FIREFLY_1                        ? EL_BD_FIREFLY :
+            element == EL_BDX_EXPANDABLE_WALL_HORIZONTAL       ? EL_BD_EXPANDABLE_WALL :
+            element == EL_BDX_WALL_DIAMOND                     ? EL_WALL_BD_DIAMOND :
+            element == EL_BDX_EXIT_CLOSED                      ? EL_EXIT_CLOSED :
+            element == EL_BDX_EXIT_OPEN                        ? EL_EXIT_OPEN :
             element);
 
   Tile[x][y] = element;
@@ -2286,7 +2303,7 @@ static void UpdateGameControlValues(void)
   int time = (game.LevelSolved ?
              game.LevelSolved_CountingTime :
              level.game_engine_type == GAME_ENGINE_TYPE_BD ?
-             game_bd.time_played :
+             game_bd.time_left :
              level.game_engine_type == GAME_ENGINE_TYPE_EM ?
              game_em.lev->time :
              level.game_engine_type == GAME_ENGINE_TYPE_SP ?
@@ -3676,6 +3693,9 @@ void InitGame(void)
   else
   {
     SetGameStatus(GAME_MODE_PLAYING);
+
+    // do not cover screen before fading out when starting from main menu
+    game_bd.cover_screen = FALSE;
   }
 
   if (level_editor_test_game)
@@ -3974,8 +3994,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;
 
@@ -4622,6 +4640,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();
@@ -4859,9 +4879,10 @@ void InitAmoebaNr(int x, int y)
 
 static void LevelSolved_SetFinalGameValues(void)
 {
-  game.time_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.time_played :
+  game.time_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.time_left :
                     game.no_level_time_limit ? TimePlayed : TimeLeft);
-  game.score_time_final = (level.use_step_counter ? TimePlayed :
+  game.score_time_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.frames_played :
+                           level.use_step_counter ? TimePlayed :
                           TimePlayed * FRAMES_PER_SECOND + TimeFrames);
 
   game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.score :
@@ -4906,7 +4927,7 @@ static void LevelSolved(void)
   LevelSolved_SetFinalGameValues();
 }
 
-static void AdvanceToNextLevel(void)
+static boolean AdvanceToNextLevel(void)
 {
   if (setup.increment_levels &&
       level_nr < leveldir_current->last_level &&
@@ -4924,7 +4945,11 @@ static void AdvanceToNextLevel(void)
 
       SaveLevelSetup_SeriesInfo();
     }
+
+    return TRUE;
   }
+
+  return FALSE;
 }
 
 void GameWon(void)
@@ -5157,8 +5182,30 @@ 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();
 
-  game.LevelSolved_GameEnd = TRUE;
+  // 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)
+  {
+    // (this is a special case: player pressed "return" key or fire button shortly before
+    // automatically asking to restart the game, so skip asking and restart right away)
+
+    CloseDoor(DOOR_CLOSE_1);
+
+    StartGameActions(network.enabled, setup.autorecord, level.random_seed);
+
+    return;
+  }
+
+  // do not handle game end if request dialog is already active
+  if (checkRequestActive())
+    return;
+
+  if (game.LevelSolved)
+    game.LevelSolved_GameEnd = TRUE;
 
   if (game.LevelSolved_SaveTape && !score_info_tape_play)
   {
@@ -5185,7 +5232,7 @@ void GameEnd(void)
     return;
   }
 
-  if (!game.LevelSolved_SaveScore)
+  if (!game.GamePlayed || (!game.LevelSolved_SaveScore && !level.bd_intermission))
   {
     SetGameStatus(GAME_MODE_MAIN);
 
@@ -5202,12 +5249,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);
 
   // 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);
 
@@ -11805,6 +11853,9 @@ static void CheckLevelTime(void)
     // if last second running, wait for native engine time to exactly reach zero
     if (getTimeLeft_BD() == 1 && TimeLeft == 1)
       TimeFrames = frames_per_second - 1;
+
+    // needed to store final time after solving game (before counting down remaining time)
+    SetTimeFrames_BD(TimePlayed * FRAMES_PER_SECOND + TimeFrames);
   }
 
   if (TimeFrames >= frames_per_second)
@@ -15757,10 +15808,10 @@ static int getSoundEffect_BD(int element_bd, int sample)
     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;
+      sound_effect = SND_BDX_DIAMOND_FALLING_RANDOM_1 + nr;
 
       if (getSoundInfoEntryFilename(sound_effect) == NULL)
-       sound_effect = SND_BD_DIAMOND_FALLING;
+       sound_effect = SND_BDX_DIAMOND_FALLING;
       break;
 
     case GD_S_DIAMOND_IMPACT_RANDOM:
@@ -15774,10 +15825,10 @@ static int getSoundEffect_BD(int element_bd, int sample)
     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;
+      sound_effect = SND_BDX_DIAMOND_IMPACT_RANDOM_1 + nr;
 
       if (getSoundInfoEntryFilename(sound_effect) == NULL)
-       sound_effect = SND_BD_DIAMOND_IMPACT;
+       sound_effect = SND_BDX_DIAMOND_IMPACT;
       break;
 
     case GD_S_FLYING_DIAMOND_FALLING_RANDOM:
@@ -15791,10 +15842,10 @@ static int getSoundEffect_BD(int element_bd, int sample)
     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;
+      sound_effect = SND_BDX_FLYING_DIAMOND_FALLING_RANDOM_1 + nr;
 
       if (getSoundInfoEntryFilename(sound_effect) == NULL)
-       sound_effect = SND_BD_FLYING_DIAMOND_FALLING;
+       sound_effect = SND_BDX_FLYING_DIAMOND_FALLING;
       break;
 
     case GD_S_FLYING_DIAMOND_IMPACT_RANDOM:
@@ -15808,10 +15859,10 @@ static int getSoundEffect_BD(int element_bd, int sample)
     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;
+      sound_effect = SND_BDX_FLYING_DIAMOND_IMPACT_RANDOM_1 + nr;
 
       if (getSoundInfoEntryFilename(sound_effect) == NULL)
-       sound_effect = SND_BD_FLYING_DIAMOND_IMPACT;
+       sound_effect = SND_BDX_FLYING_DIAMOND_IMPACT;
       break;
 
     case GD_S_TIMEOUT_0:
@@ -15837,7 +15888,7 @@ static int getSoundEffect_BD(int element_bd, int sample)
       break;
 
     case GD_S_AMOEBA_MAGIC:
-      sound_effect = SND_BD_AMOEBA_OTHER;
+      sound_effect = SND_BDX_AMOEBA_1_OTHER;
       break;
 
     case GD_S_FINISHED:
@@ -15854,7 +15905,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);
@@ -15878,7 +15929,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)
@@ -15887,7 +15938,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)
@@ -16280,7 +16331,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);
 
@@ -16324,7 +16385,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
@@ -16393,6 +16454,11 @@ boolean checkGameEnded(void)
   return (checkGameSolved() || checkGameFailed());
 }
 
+boolean checkRequestActive(void)
+{
+  return (game.request_active || game.envelope_active || game.any_door_active);
+}
+
 
 // ----------------------------------------------------------------------------
 // random generator functions
@@ -16546,6 +16612,8 @@ static ListNode *SaveEngineSnapshotBuffers(void)
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
     SaveEngineSnapshotValues_RND();
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    SaveEngineSnapshotValues_BD();
   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
     SaveEngineSnapshotValues_EM();
   if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
@@ -16557,6 +16625,8 @@ static ListNode *SaveEngineSnapshotBuffers(void)
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
     SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd));
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_bd));
   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
     SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em));
   if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
@@ -16696,6 +16766,8 @@ static void LoadEngineSnapshotValues(void)
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
     LoadEngineSnapshotValues_RND();
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    LoadEngineSnapshotValues_BD();
   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
     LoadEngineSnapshotValues_EM();
   if (level.game_engine_type == GAME_ENGINE_TYPE_SP)