Skip to content

Commit

Permalink
tr1/savegame: fix death counter support
Browse files Browse the repository at this point in the history
Resolves #2412.
  • Loading branch information
rr- committed Jan 29, 2025
1 parent 66254db commit 6f3de98
Show file tree
Hide file tree
Showing 23 changed files with 110 additions and 93 deletions.
1 change: 1 addition & 0 deletions docs/tr1/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
- 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 various death counter problems (existing saves will have the count reset) (#2412, regression from 2.6)
- 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)
Expand Down
2 changes: 1 addition & 1 deletion src/libtrx/game/phase/executor.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ static PHASE_CONTROL M_Control(PHASE *const phase, const int32_t nframes)

// A change in the game flow is not natural. Force features like death
// counter to break from the currently active savegame file.
Savegame_ClearCurrentSlot();
Savegame_UnbindSlot();

return (PHASE_CONTROL) { .action = PHASE_ACTION_END, .gf_cmd = gf_cmd };
}
Expand Down
22 changes: 22 additions & 0 deletions src/libtrx/game/savegame.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "game/savegame.h"

#include "log.h"

static int32_t m_BoundSlot = -1;

void Savegame_BindSlot(const int32_t slot_num)
{
m_BoundSlot = slot_num;
LOG_DEBUG("Binding save slot %d", slot_num);
}

void Savegame_UnbindSlot(void)
{
LOG_DEBUG("Resetting the save slot");
m_BoundSlot = -1;
}

int32_t Savegame_GetBoundSlot(void)
{
return m_BoundSlot;
}
12 changes: 11 additions & 1 deletion src/libtrx/include/libtrx/game/savegame.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@

#include <stdint.h>

// Remembers the slot used when the player starts a loaded game.
// Persists across level reloads.
void Savegame_BindSlot(int32_t slot_num);

// Removes the binding of the current slot. Used when the player exits to
// title, issues a command like `/play` etc.
void Savegame_UnbindSlot(void);

// Returns the currently bound slot number. If there is none, returns -1.
int32_t Savegame_GetBoundSlot(void);

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);
1 change: 1 addition & 0 deletions src/libtrx/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ sources = [
'game/phase/phase_stats.c',
'game/random.c',
'game/rooms/common.c',
'game/savegame.c',
'game/shell/common.c',
'game/sound.c',
'game/text.c',
Expand Down
4 changes: 2 additions & 2 deletions src/tr1/game/game/game.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ GF_COMMAND Game_Stop_Legacy(void)
if (g_GameInfo.passport_selection == PASSPORT_MODE_LOAD_GAME) {
return (GF_COMMAND) {
.action = GF_START_SAVED_GAME,
.param = g_GameInfo.current_save_slot,
.param = g_GameInfo.select_save_slot,
};
} else if (g_GameInfo.passport_selection == PASSPORT_MODE_SELECT_LEVEL) {
return (GF_COMMAND) {
Expand All @@ -127,7 +127,7 @@ GF_COMMAND Game_Stop_Legacy(void)
} else if (g_GameInfo.passport_selection == PASSPORT_MODE_STORY_SO_FAR) {
return (GF_COMMAND) {
.action = GF_STORY_SO_FAR,
.param = g_GameInfo.current_save_slot,
.param = g_GameInfo.select_save_slot,
};
} else if (g_GameInfo.passport_selection == PASSPORT_MODE_RESTART) {
return (GF_COMMAND) {
Expand Down
7 changes: 4 additions & 3 deletions src/tr1/game/game_flow/sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,14 @@ static DECLARE_EVENT_HANDLER(M_HandleLoadLevel)
// reset current info to the defaults so that we do not do
// Item_GlobalReplace in the inventory initialization routines too early
Savegame_InitCurrentInfo();
const int16_t slot_num = Savegame_GetBoundSlot();

if (!Level_Initialise(level)) {
Game_SetCurrentLevel(NULL);
GF_SetCurrentLevel(NULL);
return (GF_COMMAND) { .action = GF_EXIT_TO_TITLE };
}
if (!Savegame_Load(g_GameInfo.current_save_slot)) {
if (!Savegame_Load(slot_num)) {
LOG_ERROR("Failed to load save file!");
Game_SetCurrentLevel(NULL);
GF_SetCurrentLevel(NULL);
Expand All @@ -119,12 +120,12 @@ static DECLARE_EVENT_HANDLER(M_HandleLoadLevel)
break;

case GFSC_SELECT:
if (g_GameInfo.current_save_slot != -1) {
if (Savegame_GetBoundSlot() != -1) {
// select level feature
Savegame_InitCurrentInfo();
if (level->num > GF_GetFirstLevel()->num) {
Savegame_LoadOnlyResumeInfo(
g_GameInfo.current_save_slot, &g_GameInfo);
Savegame_GetBoundSlot(), &g_GameInfo);
const GF_LEVEL *tmp_level = level;
while (tmp_level != NULL) {
Savegame_ResetCurrentInfo(tmp_level);
Expand Down
1 change: 1 addition & 0 deletions src/tr1/game/game_flow/sequencer_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

GF_COMMAND GF_TitleSequence(void)
{
Savegame_UnbindSlot();
GameStringTable_Apply(nullptr);
const GF_LEVEL *const title_level = GF_GetTitleLevel();
if (!Level_Initialise(title_level)) {
Expand Down
8 changes: 4 additions & 4 deletions src/tr1/game/inventory_ring/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ static GF_COMMAND M_Finish(INV_RING *const ring, const bool apply_changes)
case PASSPORT_MODE_LOAD_GAME:
return (GF_COMMAND) {
.action = GF_START_SAVED_GAME,
.param = g_GameInfo.current_save_slot,
.param = g_GameInfo.select_save_slot,
};

case PASSPORT_MODE_SELECT_LEVEL:
Expand All @@ -262,7 +262,7 @@ static GF_COMMAND M_Finish(INV_RING *const ring, const bool apply_changes)
case PASSPORT_MODE_STORY_SO_FAR:
return (GF_COMMAND) {
.action = GF_STORY_SO_FAR,
.param = g_GameInfo.current_save_slot,
.param = g_GameInfo.select_save_slot,
};

case PASSPORT_MODE_NEW_GAME:
Expand All @@ -276,7 +276,7 @@ static GF_COMMAND M_Finish(INV_RING *const ring, const bool apply_changes)

case PASSPORT_MODE_SAVE_GAME:
if (apply_changes) {
Savegame_Save(g_GameInfo.current_save_slot);
Savegame_Save(g_GameInfo.select_save_slot);
}
return (GF_COMMAND) { .action = GF_NOOP };

Expand All @@ -300,7 +300,7 @@ static GF_COMMAND M_Finish(INV_RING *const ring, const bool apply_changes)

case O_PHOTO_OPTION:
if (apply_changes) {
Savegame_ClearCurrentSlot();
Savegame_UnbindSlot();
}
if (GF_GetGymLevel() != NULL) {
return (GF_COMMAND) {
Expand Down
6 changes: 3 additions & 3 deletions src/tr1/game/lara/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,10 @@ void Lara_Control(void)
item->hit_points = -1;
if (!g_Lara.death_timer) {
Music_Stop();
GF_GetResumeInfo(Game_GetCurrentLevel())->stats.death_count++;
if (g_GameInfo.current_save_slot != -1) {
g_GameInfo.death_count++;
if (Savegame_GetBoundSlot() != -1) {
Savegame_UpdateDeathCounters(
g_GameInfo.current_save_slot, &g_GameInfo);
Savegame_GetBoundSlot(), &g_GameInfo);
}
}
g_Lara.death_timer++;
Expand Down
4 changes: 0 additions & 4 deletions src/tr1/game/level.c
Original file line number Diff line number Diff line change
Expand Up @@ -974,9 +974,6 @@ bool Level_Initialise(const GF_LEVEL *const level)
BENCHMARK *const benchmark = Benchmark_Start();
LOG_DEBUG("num=%d (%s)", level->num, level->path);

// loading a save can override it to false
g_GameInfo.death_counter_supported = true;

g_GameInfo.select_level_num = -1;
const int32_t level_num = level->num;
RESUME_INFO *const resume = GF_GetResumeInfo(level);
Expand All @@ -986,7 +983,6 @@ bool Level_Initialise(const GF_LEVEL *const level)
resume->stats.secret_count = 0;
resume->stats.pickup_count = 0;
resume->stats.kill_count = 0;
resume->stats.death_count = 0;
}

g_LevelComplete = false;
Expand Down
12 changes: 6 additions & 6 deletions src/tr1/game/option/option_passport.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ static void M_ShowSaves(PASSPORT_MODE pending_mode)
g_InputDB = (INPUT_STATE) {};
} else if (select > 0) {
m_PassportStatus.mode = PASSPORT_MODE_BROWSE;
g_GameInfo.current_save_slot = select - 1;
g_GameInfo.select_save_slot = select - 1;
g_GameInfo.passport_selection = pending_mode;
} else if (
g_InvMode != INV_SAVE_MODE && g_InvMode != INV_SAVE_CRYSTAL_MODE
Expand All @@ -400,7 +400,7 @@ static void M_ShowSelectLevel(void)
int32_t select = Requester_Display(&m_SelectLevelRequester);
if (select) {
if (select - 1 + GF_GetFirstLevel()->num
== Savegame_GetLevelNumber(g_GameInfo.current_save_slot) + 1) {
== Savegame_GetLevelNumber(g_GameInfo.select_save_slot) + 1) {
g_GameInfo.passport_selection = PASSPORT_MODE_STORY_SO_FAR;
} else if (select > 0) {
g_GameInfo.select_level_num = select - 1 + GF_GetFirstLevel()->num;
Expand Down Expand Up @@ -435,7 +435,7 @@ static void M_LoadGame(void)
if (!g_SavegameRequester.items[g_SavegameRequester.requested].is_blocked
|| !g_SavegameRequester.is_blockable) {
if (g_InputDB.menu_right) {
g_GameInfo.current_save_slot = g_SavegameRequester.requested;
g_GameInfo.select_save_slot = g_SavegameRequester.requested;
Text_Hide(m_Text[TEXT_LEVEL_ARROW_RIGHT], true);
Requester_ClearTextstrings(&g_SavegameRequester);
M_InitSelectLevelRequester();
Expand Down Expand Up @@ -534,7 +534,7 @@ static void M_NewGame(void)
} else {
g_GameInfo.save_initial_version = SAVEGAME_CURRENT_VERSION;
g_GameInfo.bonus_level_unlock = false;
Savegame_ClearCurrentSlot();
Savegame_UnbindSlot();
g_GameInfo.passport_selection = PASSPORT_MODE_NEW_GAME;
}
} else if (m_PassportStatus.mode == PASSPORT_MODE_NEW_GAME) {
Expand All @@ -559,7 +559,7 @@ static void M_NewGame(void)
break;
}
g_GameInfo.bonus_level_unlock = false;
Savegame_ClearCurrentSlot();
Savegame_UnbindSlot();
g_GameInfo.passport_selection = PASSPORT_MODE_NEW_GAME;
g_GameInfo.save_initial_version = SAVEGAME_CURRENT_VERSION;
} else if (
Expand All @@ -580,7 +580,7 @@ static void M_Restart(INVENTORY_ITEM *inv_item)
{
M_ChangePageTextContent(GS(PASSPORT_RESTART_LEVEL));

if (Savegame_RestartAvailable(g_GameInfo.current_save_slot)) {
if (Savegame_RestartAvailable(g_GameInfo.select_save_slot)) {
if (g_InputDB.menu_confirm) {
g_GameInfo.passport_selection = PASSPORT_MODE_RESTART;
}
Expand Down
20 changes: 10 additions & 10 deletions src/tr1/game/savegame/savegame.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ void Savegame_ProcessItemsBeforeSave(void)

void Savegame_InitCurrentInfo(void)
{
g_GameInfo.death_count = 0;
const GF_LEVEL_TABLE *const level_table = GF_GetLevelTable(GFLT_MAIN);
for (int32_t i = 0; i < level_table->count; i++) {
const GF_LEVEL *const level = &level_table->levels[i];
Expand Down Expand Up @@ -351,9 +352,9 @@ void Savegame_CarryCurrentInfoToNextLevel(
LOG_INFO(
"Copying resume info from level #%d to level #%d", src_level->num,
dst_level->num);
memcpy(
GF_GetResumeInfo(dst_level), GF_GetResumeInfo(src_level),
sizeof(RESUME_INFO));
RESUME_INFO *const src_resume = GF_GetResumeInfo(src_level);
RESUME_INFO *const dst_resume = GF_GetResumeInfo(dst_level);
memcpy(dst_resume, src_resume, sizeof(RESUME_INFO));
}

void Savegame_PersistGameToCurrentInfo(const GF_LEVEL *const level)
Expand Down Expand Up @@ -462,6 +463,7 @@ bool Savegame_Save(const int32_t slot_num)
{
GAME_INFO *const game_info = &g_GameInfo;
bool ret = true;
Savegame_BindSlot(slot_num);

File_CreateDirectory(SAVES_DIR);

Expand Down Expand Up @@ -644,9 +646,12 @@ void Savegame_ScanSavedGames(void)

void Savegame_ScanAvailableLevels(REQUEST_INFO *req)
{
SAVEGAME_INFO *savegame_info =
&m_SavegameInfo[g_GameInfo.current_save_slot];
const int32_t slot_num = Savegame_GetBoundSlot();
if (slot_num == -1) {
return;
}

const SAVEGAME_INFO *const savegame_info = &m_SavegameInfo[slot_num];
if (!savegame_info->features.select_level) {
Requester_AddItem(req, true, "%s", GS(PASSPORT_LEGACY_SELECT_LEVEL_1));
Requester_AddItem(req, true, "%s", GS(PASSPORT_LEGACY_SELECT_LEVEL_2));
Expand Down Expand Up @@ -686,8 +691,3 @@ 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;
}
Loading

0 comments on commit 6f3de98

Please sign in to comment.