From fb26660da1ef13d86187f772c55a77cdf4ebaba2 Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Wed, 29 Jan 2025 13:25:04 +0100 Subject: [PATCH] tr1/game-flow: fix crash with /load and /play Resolves #2411. --- docs/tr1/CHANGELOG.md | 1 + src/libtrx/game/phase/executor.c | 6 ++++++ src/libtrx/include/libtrx/game/savegame.h | 1 + src/tr1/game/inventory_ring/control.c | 2 +- src/tr1/game/option/option_passport.c | 4 ++-- src/tr1/game/savegame/savegame.c | 5 +++++ src/tr1/game/shell.c | 2 -- src/tr2/decomp/savegame.c | 4 ++++ 8 files changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/tr1/CHANGELOG.md b/docs/tr1/CHANGELOG.md index 10eccc679..8045b734a 100644 --- a/docs/tr1/CHANGELOG.md +++ b/docs/tr1/CHANGELOG.md @@ -43,6 +43,7 @@ - fixed health bar continuing to show when the inventory ring rotates (#1991, regression from 4.0) - fixed header and arrows disappearing when the inventory ring rotates (#2352, regression from 4.4) - fixed Story So Far feature not playing opening FMVs from the current level (#2360, regression from 4.2) +- fixed `/play` command crashing the game when used after loading a level (#2411, regression) - fixed `/demo` command crashing the game if no demos are present (regression from 4.1) - fixed Lara not being able to jump or stop swimming if the related responsive config options are enabled, but enhanced animations are not present (#2397, regression from 4.6) - improved pause screen compatibility with PS1 (#2248) diff --git a/src/libtrx/game/phase/executor.c b/src/libtrx/game/phase/executor.c index a7f596a51..702759bae 100644 --- a/src/libtrx/game/phase/executor.c +++ b/src/libtrx/game/phase/executor.c @@ -7,6 +7,7 @@ #include "game/game_flow.h" #include "game/interpolation.h" #include "game/output.h" +#include "game/savegame.h" #include "game/shell.h" #include "game/text.h" @@ -27,6 +28,11 @@ static PHASE_CONTROL M_Control(PHASE *const phase, const int32_t nframes) if (gf_override_cmd.action != GF_NOOP) { const GF_COMMAND gf_cmd = gf_override_cmd; GF_OverrideCommand((GF_COMMAND) { .action = GF_NOOP }); + + // A change in the game flow is not natural. Force features like death + // counter to break from the currently active savegame file. + Savegame_ClearCurrentSlot(); + return (PHASE_CONTROL) { .action = PHASE_ACTION_END, .gf_cmd = gf_cmd }; } diff --git a/src/libtrx/include/libtrx/game/savegame.h b/src/libtrx/include/libtrx/game/savegame.h index 32d15d572..31ec2bd62 100644 --- a/src/libtrx/include/libtrx/game/savegame.h +++ b/src/libtrx/include/libtrx/game/savegame.h @@ -6,3 +6,4 @@ extern int32_t Savegame_GetSlotCount(void); extern bool Savegame_IsSlotFree(int32_t slot_num); extern bool Savegame_Load(int32_t slot_num); extern bool Savegame_Save(int32_t slot_num); +extern void Savegame_ClearCurrentSlot(void); diff --git a/src/tr1/game/inventory_ring/control.c b/src/tr1/game/inventory_ring/control.c index e623171d8..bb505793a 100644 --- a/src/tr1/game/inventory_ring/control.c +++ b/src/tr1/game/inventory_ring/control.c @@ -300,7 +300,7 @@ static GF_COMMAND M_Finish(INV_RING *const ring, const bool apply_changes) case O_PHOTO_OPTION: if (apply_changes) { - g_GameInfo.current_save_slot = -1; + Savegame_ClearCurrentSlot(); } if (GF_GetGymLevel() != NULL) { return (GF_COMMAND) { diff --git a/src/tr1/game/option/option_passport.c b/src/tr1/game/option/option_passport.c index 1110b0350..25d4d0290 100644 --- a/src/tr1/game/option/option_passport.c +++ b/src/tr1/game/option/option_passport.c @@ -534,7 +534,7 @@ static void M_NewGame(void) } else { g_GameInfo.save_initial_version = SAVEGAME_CURRENT_VERSION; g_GameInfo.bonus_level_unlock = false; - g_GameInfo.current_save_slot = -1; + Savegame_ClearCurrentSlot(); g_GameInfo.passport_selection = PASSPORT_MODE_NEW_GAME; } } else if (m_PassportStatus.mode == PASSPORT_MODE_NEW_GAME) { @@ -559,7 +559,7 @@ static void M_NewGame(void) break; } g_GameInfo.bonus_level_unlock = false; - g_GameInfo.current_save_slot = -1; + Savegame_ClearCurrentSlot(); g_GameInfo.passport_selection = PASSPORT_MODE_NEW_GAME; g_GameInfo.save_initial_version = SAVEGAME_CURRENT_VERSION; } else if ( diff --git a/src/tr1/game/savegame/savegame.c b/src/tr1/game/savegame/savegame.c index f2c717407..a32887238 100644 --- a/src/tr1/game/savegame/savegame.c +++ b/src/tr1/game/savegame/savegame.c @@ -686,3 +686,8 @@ bool Savegame_RestartAvailable(int32_t slot_num) SAVEGAME_INFO *savegame_info = &m_SavegameInfo[slot_num]; return savegame_info->features.restart; } + +void Savegame_ClearCurrentSlot(void) +{ + g_GameInfo.current_save_slot = -1; +} diff --git a/src/tr1/game/shell.c b/src/tr1/game/shell.c index 28898fb5e..a964483b9 100644 --- a/src/tr1/game/shell.c +++ b/src/tr1/game/shell.c @@ -190,8 +190,6 @@ void Shell_Main(void) m_ModPaths[m_ActiveMod].game_flow_path, m_ModPaths[m_ActiveMod].game_strings_path); - g_GameInfo.current_save_slot = -1; - GF_COMMAND gf_cmd = GF_DoFrontendSequence(); bool loop_continue = !Shell_IsExiting(); while (loop_continue) { diff --git a/src/tr2/decomp/savegame.c b/src/tr2/decomp/savegame.c index 4b486cbb6..2054ce015 100644 --- a/src/tr2/decomp/savegame.c +++ b/src/tr2/decomp/savegame.c @@ -1093,3 +1093,7 @@ int32_t S_LoadGame(const int32_t slot_num) File_Close(fp); return true; } + +void Savegame_ClearCurrentSlot(void) +{ +}