tr1/savegame: move resume info storage

This moves storage of resume info into the savegame module rather than
in the global game info.
This commit is contained in:
lahm86 2025-04-07 19:33:40 +01:00
parent 287fddea7e
commit c853f43fa4
6 changed files with 50 additions and 43 deletions

View file

@ -38,6 +38,7 @@ void Savegame_Shutdown(void);
bool Savegame_IsInitialised(void);
void Savegame_InitCurrentInfo(void);
void Savegame_SetCurrentInfo(int32_t current_slot, int32_t src_slot);
int32_t Savegame_GetLevelNumber(int32_t slot_num);

View file

@ -46,6 +46,7 @@ typedef struct {
static int32_t m_SaveSlots = 0;
static int16_t m_NewestSlot = -1;
static SAVEGAME_INFO *m_SavegameInfo = nullptr;
static RESUME_INFO *m_ResumeInfo = nullptr;
static const SAVEGAME_STRATEGY m_Strategies[] = {
{
@ -195,7 +196,7 @@ static void M_LoadPostprocess(void)
void Savegame_Init(void)
{
g_GameInfo.current = Memory_Alloc(
m_ResumeInfo = Memory_Alloc(
sizeof(RESUME_INFO)
* (GF_GetLevelTable(GFLT_MAIN)->count
+ (GF_GetLevelTable(GFLT_DEMOS)->count >= 0 ? 1 : 0)));
@ -229,11 +230,12 @@ void Savegame_Init(void)
RESUME_INFO *Savegame_GetCurrentInfo(const GF_LEVEL *const level)
{
ASSERT(m_ResumeInfo != nullptr);
ASSERT(level != nullptr);
if (GF_GetLevelTableType(level->type) == GFLT_MAIN) {
return &g_GameInfo.current[level->num];
return &m_ResumeInfo[level->num];
} else if (level->type == GFL_DEMO) {
return &g_GameInfo.current[GF_GetLevelTable(GFLT_MAIN)->count];
return &m_ResumeInfo[GF_GetLevelTable(GFLT_MAIN)->count];
}
LOG_WARNING(
"Warning: unable to get resume info for level %d (type=%s)", level->num,
@ -241,11 +243,16 @@ RESUME_INFO *Savegame_GetCurrentInfo(const GF_LEVEL *const level)
return nullptr;
}
void Savegame_SetCurrentInfo(const int32_t current_slot, const int32_t src_slot)
{
m_ResumeInfo[current_slot] = m_ResumeInfo[src_slot];
}
void Savegame_Shutdown(void)
{
M_ClearSlots();
Memory_FreePointer(&m_SavegameInfo);
Memory_FreePointer(&g_GameInfo.current);
Memory_FreePointer(&m_ResumeInfo);
}
bool Savegame_IsInitialised(void)
@ -524,7 +531,7 @@ bool Savegame_Save(const int32_t slot_num)
for (int32_t i = 0; i < level_table->count; i++) {
const GF_LEVEL *const level = &level_table->levels[i];
if (level->type == GFL_CURRENT) {
game_info->current[i] = game_info->current[current_level->num];
Savegame_SetCurrentInfo(i, current_level->num);
}
}
const char *const level_title = Game_GetCurrentLevel()->title;

View file

@ -57,12 +57,9 @@ static void M_SaveRaw(MYFILE *fp, JSON_VALUE *root, int32_t version);
static JSON_VALUE *M_ParseFromBuffer(
const char *buffer, size_t buffer_size, int32_t *version_out);
static JSON_VALUE *M_ParseFromFile(MYFILE *fp, int32_t *version_out);
static bool M_LoadResumeInfo(
JSON_ARRAY *levels_arr, RESUME_INFO *resume_info, uint16_t header_version);
static bool M_LoadDiscontinuedStartInfo(
JSON_ARRAY *start_arr, GAME_INFO *game_info);
static bool M_LoadDiscontinuedEndInfo(
JSON_ARRAY *end_arr, GAME_INFO *game_info);
static bool M_LoadResumeInfo(JSON_ARRAY *levels_arr, uint16_t header_version);
static bool M_LoadDiscontinuedStartInfo(JSON_ARRAY *start_arr);
static bool M_LoadDiscontinuedEndInfo(JSON_ARRAY *end_arr);
static bool M_LoadMisc(
JSON_OBJECT *misc_obj, GAME_INFO *game_info, uint16_t header_version);
static bool M_LoadInventory(JSON_OBJECT *inv_obj);
@ -77,7 +74,7 @@ static bool M_LoadLara(
JSON_OBJECT *lara_obj, LARA_INFO *lara, uint16_t header_version);
static bool M_LoadCurrentMusic(JSON_OBJECT *music_obj);
static bool M_LoadMusicTrackFlags(JSON_ARRAY *music_track_arr);
static JSON_ARRAY *M_DumpResumeInfo(RESUME_INFO *game_info);
static JSON_ARRAY *M_DumpResumeInfo(void);
static JSON_OBJECT *M_DumpMisc(GAME_INFO *game_info);
static JSON_OBJECT *M_DumpInventory(void);
static JSON_OBJECT *M_DumpFlipmaps(void);
@ -224,9 +221,8 @@ static JSON_VALUE *M_ParseFromFile(MYFILE *fp, int32_t *version_out)
}
static bool M_LoadResumeInfo(
JSON_ARRAY *resume_arr, RESUME_INFO *resume_info, uint16_t header_version)
JSON_ARRAY *const resume_arr, const uint16_t header_version)
{
ASSERT(resume_info != nullptr);
if (!resume_arr) {
LOG_ERROR("Malformed save: invalid or missing resume array");
return false;
@ -243,7 +239,9 @@ static bool M_LoadResumeInfo(
LOG_ERROR("Malformed save: invalid resume info");
return false;
}
RESUME_INFO *resume = &resume_info[i];
const GF_LEVEL *const level = GF_GetLevel(GFLT_MAIN, i);
RESUME_INFO *const resume = Savegame_GetCurrentInfo(level);
resume->lara_hitpoints = JSON_ObjectGetInt(
resume_obj, "lara_hitpoints",
g_Config.gameplay.start_lara_hitpoints);
@ -303,13 +301,10 @@ static bool M_LoadResumeInfo(
return true;
}
static bool M_LoadDiscontinuedStartInfo(
JSON_ARRAY *start_arr, GAME_INFO *game_info)
static bool M_LoadDiscontinuedStartInfo(JSON_ARRAY *const start_arr)
{
// This function solely exists for backward compatibility with 2.6 and 2.7
// saves.
ASSERT(game_info != nullptr);
ASSERT(game_info->current != nullptr);
if (!start_arr) {
LOG_ERROR(
"Malformed save: invalid or missing discontinued start array");
@ -327,7 +322,8 @@ static bool M_LoadDiscontinuedStartInfo(
LOG_ERROR("Malformed save: invalid discontinued start info");
return false;
}
RESUME_INFO *start = &game_info->current[i];
const GF_LEVEL *const level = GF_GetLevel(GFLT_MAIN, i);
RESUME_INFO *const start = Savegame_GetCurrentInfo(level);
start->lara_hitpoints = JSON_ObjectGetInt(
start_obj, "lara_hitpoints",
g_Config.gameplay.start_lara_hitpoints);
@ -356,12 +352,10 @@ static bool M_LoadDiscontinuedStartInfo(
return true;
}
static bool M_LoadDiscontinuedEndInfo(JSON_ARRAY *end_arr, GAME_INFO *game_info)
static bool M_LoadDiscontinuedEndInfo(JSON_ARRAY *end_arr)
{
// This function solely exists for backward compatibility with 2.6 and 2.7
// saves.
ASSERT(game_info != nullptr);
ASSERT(game_info->current != nullptr);
if (!end_arr) {
LOG_ERROR("Malformed save: invalid or missing resume info array");
return false;
@ -378,7 +372,10 @@ static bool M_LoadDiscontinuedEndInfo(JSON_ARRAY *end_arr, GAME_INFO *game_info)
LOG_ERROR("Malformed save: invalid resume info");
return false;
}
LEVEL_STATS *end = &game_info->current[i].stats;
const GF_LEVEL *const level = GF_GetLevel(GFLT_MAIN, i);
RESUME_INFO *const resume = Savegame_GetCurrentInfo(level);
LEVEL_STATS *const end = &resume->stats;
end->timer = JSON_ObjectGetInt(end_obj, "timer", end->timer);
end->secret_flags =
JSON_ObjectGetInt(end_obj, "secrets", end->secret_flags);
@ -979,12 +976,12 @@ static bool M_LoadMusicTrackFlags(JSON_ARRAY *music_track_arr)
return true;
}
static JSON_ARRAY *M_DumpResumeInfo(RESUME_INFO *resume_info)
static JSON_ARRAY *M_DumpResumeInfo(void)
{
JSON_ARRAY *resume_arr = JSON_ArrayNew();
ASSERT(resume_info != nullptr);
for (int i = 0; i < GF_GetLevelTable(GFLT_MAIN)->count; i++) {
RESUME_INFO *resume = &resume_info[i];
const GF_LEVEL *const level = GF_GetLevel(GFLT_MAIN, i);
const RESUME_INFO *const resume = Savegame_GetCurrentInfo(level);
JSON_OBJECT *resume_obj = JSON_ObjectNew();
JSON_ObjectAppendInt(
resume_obj, "lara_hitpoints", resume->lara_hitpoints);
@ -1405,18 +1402,17 @@ bool Savegame_BSON_LoadFromFile(MYFILE *fp, GAME_INFO *game_info)
}
if (!M_LoadResumeInfo(
JSON_ObjectGetArray(root_obj, "current_info"), game_info->current,
version)) {
JSON_ObjectGetArray(root_obj, "current_info"), version)) {
LOG_WARNING(
"Failed to load RESUME_INFO current properly. "
"Checking if save is legacy.");
// Check for 2.6 and 2.7 legacy start and end info.
if (!M_LoadDiscontinuedStartInfo(
JSON_ObjectGetArray(root_obj, "start_info"), game_info)) {
JSON_ObjectGetArray(root_obj, "start_info"))) {
goto cleanup;
}
if (!M_LoadDiscontinuedEndInfo(
JSON_ObjectGetArray(root_obj, "end_info"), game_info)) {
JSON_ObjectGetArray(root_obj, "end_info"))) {
goto cleanup;
}
}
@ -1487,18 +1483,17 @@ bool Savegame_BSON_LoadOnlyResumeInfo(MYFILE *fp, GAME_INFO *game_info)
}
if (!M_LoadResumeInfo(
JSON_ObjectGetArray(root_obj, "current_info"), game_info->current,
version)) {
JSON_ObjectGetArray(root_obj, "current_info"), version)) {
LOG_WARNING(
"Failed to load RESUME_INFO current properly. Checking if "
"save is legacy.");
// Check for 2.6 and 2.7 legacy start and end info.
if (!M_LoadDiscontinuedStartInfo(
JSON_ObjectGetArray(root_obj, "start_info"), game_info)) {
JSON_ObjectGetArray(root_obj, "start_info"))) {
goto cleanup;
}
if (!M_LoadDiscontinuedEndInfo(
JSON_ObjectGetArray(root_obj, "end_info"), game_info)) {
JSON_ObjectGetArray(root_obj, "end_info"))) {
goto cleanup;
}
}
@ -1524,8 +1519,7 @@ void Savegame_BSON_SaveToFile(
JSON_ObjectAppendInt(root_obj, "level_num", current_level->num);
JSON_ObjectAppendObject(root_obj, "misc", M_DumpMisc(game_info));
JSON_ObjectAppendArray(
root_obj, "current_info", M_DumpResumeInfo(game_info->current));
JSON_ObjectAppendArray(root_obj, "current_info", M_DumpResumeInfo());
JSON_ObjectAppendObject(root_obj, "inventory", M_DumpInventory());
JSON_ObjectAppendObject(root_obj, "flipmap", M_DumpFlipmaps());
JSON_ObjectAppendArray(root_obj, "cameras", M_DumpCameras());

View file

@ -325,14 +325,13 @@ static void M_SetCurrentPosition(const int32_t level_num)
for (int32_t i = 0; i < level_table->count; i++) {
const GF_LEVEL *const level = &level_table->levels[i];
if (level->type == GFL_CURRENT) {
g_GameInfo.current[current_level->num] = g_GameInfo.current[i];
Savegame_SetCurrentInfo(current_level->num, i);
}
}
}
static void M_ReadResumeInfo(MYFILE *const fp, GAME_INFO *const game_info)
{
ASSERT(game_info->current != nullptr);
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];

View file

@ -3,6 +3,7 @@
#include "game/game_flow.h"
#include "game/game_string.h"
#include "game/input.h"
#include "game/savegame.h"
#include "game/stats.h"
#include "global/vars.h"
@ -241,8 +242,11 @@ static void M_AddCommonRows(
static void M_AddLevelStatsRows(UI_STATS_DIALOG *const self)
{
const STATS_COMMON *stats =
(STATS_COMMON *)&g_GameInfo.current[self->args.level_num].stats;
const GF_LEVEL *const current_level =
GF_GetLevel(GFLT_MAIN, self->args.level_num);
const RESUME_INFO *const current_info =
Savegame_GetCurrentInfo(current_level);
const STATS_COMMON *const stats = (STATS_COMMON *)&current_info->stats;
M_AddCommonRows(self, stats, &g_GameInfo);
}
@ -264,7 +268,10 @@ static void M_UpdateTimerRow(UI_STATS_DIALOG *const self)
continue;
}
char buf[50];
M_FormatTime(buf, g_GameInfo.current[self->args.level_num].stats.timer);
const GF_LEVEL *const level =
GF_GetLevel(GFLT_MAIN, self->args.level_num);
const RESUME_INFO *const current_info = Savegame_GetCurrentInfo(level);
M_FormatTime(buf, current_info->stats.timer);
UI_Label_ChangeText(self->rows[i].value_label, buf);
return;
}

View file

@ -158,7 +158,6 @@ typedef struct {
} RESUME_INFO;
typedef struct {
RESUME_INFO *current;
int32_t death_count;
bool bonus_level_unlock;