mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 20:58:07 +03:00
tr2/savegame: introduce strategy concept
This introduces the concept of savegame strategies, like TR1X, with the legacy strategy being the only one currently.
This commit is contained in:
parent
49ad919de3
commit
699c1d9873
6 changed files with 214 additions and 101 deletions
|
@ -115,14 +115,13 @@ static DECLARE_GF_EVENT_HANDLER(M_HandlePlayLevel)
|
||||||
const int16_t slot_num = Savegame_GetBoundSlot();
|
const int16_t slot_num = Savegame_GetBoundSlot();
|
||||||
if (!Savegame_Load(slot_num)) {
|
if (!Savegame_Load(slot_num)) {
|
||||||
LOG_ERROR("Failed to load save file!");
|
LOG_ERROR("Failed to load save file!");
|
||||||
Game_SetCurrentLevel(nullptr);
|
|
||||||
GF_SetCurrentLevel(nullptr);
|
|
||||||
return (GF_COMMAND) { .action = GF_EXIT_TO_TITLE };
|
return (GF_COMMAND) { .action = GF_EXIT_TO_TITLE };
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (level->type == GFL_NORMAL || level->type == GFL_BONUS) {
|
if (level->type == GFL_NORMAL || level->type == GFL_BONUS) {
|
||||||
|
Savegame_SetInitialVersion(SAVEGAME_CURRENT_VERSION);
|
||||||
GF_InventoryModifier_Scan(Game_GetCurrentLevel());
|
GF_InventoryModifier_Scan(Game_GetCurrentLevel());
|
||||||
GF_InventoryModifier_Apply(Game_GetCurrentLevel(), GF_INV_REGULAR);
|
GF_InventoryModifier_Apply(Game_GetCurrentLevel(), GF_INV_REGULAR);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,43 @@
|
||||||
|
|
||||||
#include "game/game_flow/types.h"
|
#include "game/game_flow/types.h"
|
||||||
|
|
||||||
|
#include <libtrx/filesystem.h>
|
||||||
#include <libtrx/game/savegame.h>
|
#include <libtrx/game/savegame.h>
|
||||||
|
|
||||||
|
#define SAVEGAME_CURRENT_VERSION -1
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VERSION_LEGACY = -1,
|
||||||
|
} SAVEGAME_VERSION;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SAVEGAME_FORMAT_INVALID = 0,
|
||||||
|
SAVEGAME_FORMAT_LEGACY = 1,
|
||||||
|
SAVEGAME_FORMAT_BSON = 2,
|
||||||
|
} SAVEGAME_FORMAT;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SAVEGAME_FORMAT format;
|
||||||
|
char *full_path;
|
||||||
|
int32_t counter;
|
||||||
|
int32_t level_num;
|
||||||
|
char *level_title;
|
||||||
|
int16_t initial_version;
|
||||||
|
} SAVEGAME_INFO;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool allow_load;
|
||||||
|
bool allow_save;
|
||||||
|
SAVEGAME_FORMAT format;
|
||||||
|
const char *(*get_save_file_pattern_func)(void);
|
||||||
|
bool (*fill_info_func)(MYFILE *fp, SAVEGAME_INFO *info);
|
||||||
|
bool (*load_from_file_func)(MYFILE *fp);
|
||||||
|
void (*save_to_file_func)(MYFILE *fp);
|
||||||
|
} SAVEGAME_STRATEGY;
|
||||||
|
|
||||||
void Savegame_Init(void);
|
void Savegame_Init(void);
|
||||||
void Savegame_Shutdown(void);
|
void Savegame_Shutdown(void);
|
||||||
|
void Savegame_RegisterStrategy(SAVEGAME_STRATEGY strategy);
|
||||||
|
|
||||||
void Savegame_InitCurrentInfo(void);
|
void Savegame_InitCurrentInfo(void);
|
||||||
|
|
||||||
|
@ -22,9 +55,17 @@ void Savegame_HighlightNewestSlot(void);
|
||||||
int32_t Savegame_GetLevelNumber(int32_t slot_idx);
|
int32_t Savegame_GetLevelNumber(int32_t slot_idx);
|
||||||
int32_t Savegame_GetCounter(void);
|
int32_t Savegame_GetCounter(void);
|
||||||
int32_t Savegame_GetTotalCount(void);
|
int32_t Savegame_GetTotalCount(void);
|
||||||
|
SAVEGAME_VERSION Savegame_GetInitialVersion(void);
|
||||||
|
void Savegame_SetInitialVersion(SAVEGAME_VERSION version);
|
||||||
|
|
||||||
void Savegame_ProcessItemsBeforeSave(void);
|
void Savegame_ProcessItemsBeforeSave(void);
|
||||||
void Savegame_ProcessItemsBeforeLoad(void);
|
void Savegame_ProcessItemsBeforeLoad(void);
|
||||||
|
|
||||||
void Savegame_SetDefaultStats(const GF_LEVEL *level, STATS_COMMON stats);
|
void Savegame_SetDefaultStats(const GF_LEVEL *level, STATS_COMMON stats);
|
||||||
STATS_COMMON Savegame_GetDefaultStats(const GF_LEVEL *level);
|
STATS_COMMON Savegame_GetDefaultStats(const GF_LEVEL *level);
|
||||||
|
|
||||||
|
#define REGISTER_SAVEGAME_STRATEGY(strategy_) \
|
||||||
|
__attribute__((__constructor__)) static void M_Register(void) \
|
||||||
|
{ \
|
||||||
|
Savegame_RegisterStrategy(strategy_); \
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "game/inventory.h"
|
#include "game/inventory.h"
|
||||||
#include "game/requester.h"
|
#include "game/requester.h"
|
||||||
#include "game/savegame.h"
|
#include "game/savegame.h"
|
||||||
#include "game/savegame/savegame_legacy.h"
|
|
||||||
#include "global/vars.h"
|
#include "global/vars.h"
|
||||||
|
|
||||||
#include <libtrx/benchmark.h>
|
#include <libtrx/benchmark.h>
|
||||||
|
@ -18,6 +17,8 @@
|
||||||
#include <libtrx/strings.h>
|
#include <libtrx/strings.h>
|
||||||
#include <libtrx/utils.h>
|
#include <libtrx/utils.h>
|
||||||
|
|
||||||
|
#define MAX_STRATEGIES 1
|
||||||
|
|
||||||
static STATS_COMMON *m_DefaultStats = nullptr;
|
static STATS_COMMON *m_DefaultStats = nullptr;
|
||||||
static RESUME_INFO *m_ResumeInfos = nullptr;
|
static RESUME_INFO *m_ResumeInfos = nullptr;
|
||||||
static int32_t m_SaveSlots = 0;
|
static int32_t m_SaveSlots = 0;
|
||||||
|
@ -29,9 +30,14 @@ static SAVEGAME_INFO *m_SavegameInfo = nullptr;
|
||||||
static uint32_t m_ReqFlags1[MAX_REQUESTER_ITEMS] = {};
|
static uint32_t m_ReqFlags1[MAX_REQUESTER_ITEMS] = {};
|
||||||
static uint32_t m_ReqFlags2[MAX_REQUESTER_ITEMS] = {};
|
static uint32_t m_ReqFlags2[MAX_REQUESTER_ITEMS] = {};
|
||||||
|
|
||||||
|
static int32_t m_StrategyCount = 0;
|
||||||
|
static SAVEGAME_STRATEGY m_Strategies[MAX_STRATEGIES];
|
||||||
|
static SAVEGAME_VERSION m_InitialVersion = VERSION_LEGACY;
|
||||||
|
|
||||||
static void M_ClearSlots(void);
|
static void M_ClearSlots(void);
|
||||||
static bool M_FillSlot(const int32_t slot_num, const char *const path);
|
static bool M_FillSlot(
|
||||||
static void M_ScanSavedGamesDir(const char *const dir_path);
|
SAVEGAME_STRATEGY strategy, int32_t slot_num, const char *path);
|
||||||
|
static void M_ScanSavedGamesDir(const char *dir_path);
|
||||||
|
|
||||||
static void M_ClearSlots(void)
|
static void M_ClearSlots(void)
|
||||||
{
|
{
|
||||||
|
@ -41,6 +47,7 @@ static void M_ClearSlots(void)
|
||||||
|
|
||||||
for (int32_t i = 0; i < m_SaveSlots; i++) {
|
for (int32_t i = 0; i < m_SaveSlots; i++) {
|
||||||
SAVEGAME_INFO *const savegame_info = &m_SavegameInfo[i];
|
SAVEGAME_INFO *const savegame_info = &m_SavegameInfo[i];
|
||||||
|
savegame_info->format = SAVEGAME_FORMAT_INVALID;
|
||||||
savegame_info->counter = -1;
|
savegame_info->counter = -1;
|
||||||
savegame_info->level_num = -1;
|
savegame_info->level_num = -1;
|
||||||
Memory_FreePointer(&savegame_info->full_path);
|
Memory_FreePointer(&savegame_info->full_path);
|
||||||
|
@ -48,58 +55,24 @@ static void M_ClearSlots(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool M_FillSlot(const int32_t slot_num, const char *const path)
|
static bool M_FillSlot(
|
||||||
|
const SAVEGAME_STRATEGY strategy, const int32_t slot_num,
|
||||||
|
const char *const path)
|
||||||
{
|
{
|
||||||
SAVEGAME_INFO *const savegame_info = &m_SavegameInfo[slot_num];
|
SAVEGAME_INFO *const savegame_info = &m_SavegameInfo[slot_num];
|
||||||
|
if (strategy.format <= savegame_info->format) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
MYFILE *const fp = File_Open(path, FILE_OPEN_READ);
|
MYFILE *const fp = File_Open(path, FILE_OPEN_READ);
|
||||||
if (fp != nullptr) {
|
if (fp != nullptr) {
|
||||||
// TODO: make strategy->fill_info
|
if (strategy.fill_info_func(fp, savegame_info)) {
|
||||||
{
|
savegame_info->format = strategy.format;
|
||||||
char level_title[75];
|
Memory_FreePointer(&savegame_info->full_path);
|
||||||
File_ReadData(fp, level_title, 75);
|
savegame_info->full_path = Memory_DupStr(path);
|
||||||
savegame_info->level_title = Memory_DupStr(level_title);
|
result = true;
|
||||||
savegame_info->counter = File_ReadS32(fp);
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < 24; i++) {
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // pistol ammo
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // magnum ammo
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // uzi ammo
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // shotgun ammo
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // m16 ammo
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // grenade ammo
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // harpoon ammo
|
|
||||||
File_Skip(fp, sizeof(uint8_t)); // small medis
|
|
||||||
File_Skip(fp, sizeof(uint8_t)); // big medis
|
|
||||||
File_Skip(fp, sizeof(uint8_t)); // reserved
|
|
||||||
File_Skip(fp, sizeof(uint8_t)); // flares
|
|
||||||
File_Skip(fp, sizeof(int8_t)); // gun status
|
|
||||||
File_Skip(fp, sizeof(int8_t)); // gun type
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // flags
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // unused
|
|
||||||
File_Skip(fp, sizeof(uint32_t)); // timer
|
|
||||||
File_Skip(fp, sizeof(uint32_t)); // ammo used
|
|
||||||
File_Skip(fp, sizeof(uint32_t)); // hits
|
|
||||||
File_Skip(fp, sizeof(uint32_t)); // distance
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // kills
|
|
||||||
File_Skip(fp, sizeof(uint8_t)); // secret flags
|
|
||||||
File_Skip(fp, sizeof(uint8_t)); // medis used
|
|
||||||
}
|
|
||||||
|
|
||||||
File_Skip(fp, sizeof(uint32_t)); // timer
|
|
||||||
File_Skip(fp, sizeof(uint32_t)); // ammo used
|
|
||||||
File_Skip(fp, sizeof(uint32_t)); // hits
|
|
||||||
File_Skip(fp, sizeof(uint32_t)); // distance
|
|
||||||
File_Skip(fp, sizeof(uint16_t)); // kills
|
|
||||||
File_Skip(fp, sizeof(uint8_t)); // secret flags
|
|
||||||
File_Skip(fp, sizeof(uint8_t)); // medis used
|
|
||||||
|
|
||||||
savegame_info->level_num = File_ReadS16(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory_FreePointer(&savegame_info->full_path);
|
|
||||||
savegame_info->full_path = Memory_DupStr(path);
|
|
||||||
result = true;
|
|
||||||
File_Close(fp);
|
File_Close(fp);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -121,13 +94,20 @@ static void M_ScanSavedGamesDir(const char *const dir_path)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t slot = -1;
|
for (int32_t i = 0; i < m_StrategyCount; i++) {
|
||||||
int32_t parsed =
|
const SAVEGAME_STRATEGY strategy = m_Strategies[i];
|
||||||
sscanf(file_name, g_GameFlow.savegame_fmt_legacy, &slot);
|
if (!strategy.allow_load) {
|
||||||
if (parsed == 1 && slot >= 0 && slot < m_SaveSlots) {
|
continue;
|
||||||
char *file_path = String_Format("%s/%s", dir_path, file_name);
|
}
|
||||||
M_FillSlot(slot, file_path);
|
|
||||||
Memory_FreePointer(&file_path);
|
int32_t slot = -1;
|
||||||
|
const int32_t parsed =
|
||||||
|
sscanf(file_name, strategy.get_save_file_pattern_func(), &slot);
|
||||||
|
if (parsed == 1 && slot >= 0 && slot < m_SaveSlots) {
|
||||||
|
char *file_path = String_Format("%s/%s", dir_path, file_name);
|
||||||
|
M_FillSlot(strategy, slot, file_path);
|
||||||
|
Memory_FreePointer(&file_path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +145,13 @@ static void M_LoadPostprocess(void)
|
||||||
MovableBlock_SetupFloor();
|
MovableBlock_SetupFloor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Savegame_RegisterStrategy(const SAVEGAME_STRATEGY strategy)
|
||||||
|
{
|
||||||
|
ASSERT(m_StrategyCount < MAX_STRATEGIES);
|
||||||
|
m_Strategies[m_StrategyCount] = strategy;
|
||||||
|
m_StrategyCount++;
|
||||||
|
}
|
||||||
|
|
||||||
void Savegame_Init(void)
|
void Savegame_Init(void)
|
||||||
{
|
{
|
||||||
m_ResumeInfos = Memory_Alloc(
|
m_ResumeInfos = Memory_Alloc(
|
||||||
|
@ -277,6 +264,16 @@ int32_t Savegame_GetTotalCount(void)
|
||||||
return m_SavedGames;
|
return m_SavedGames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SAVEGAME_VERSION Savegame_GetInitialVersion(void)
|
||||||
|
{
|
||||||
|
return m_InitialVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Savegame_SetInitialVersion(const SAVEGAME_VERSION version)
|
||||||
|
{
|
||||||
|
m_InitialVersion = version;
|
||||||
|
}
|
||||||
|
|
||||||
void Savegame_ProcessItemsBeforeSave(void)
|
void Savegame_ProcessItemsBeforeSave(void)
|
||||||
{
|
{
|
||||||
for (int32_t i = 0; i < Item_GetLevelCount(); i++) {
|
for (int32_t i = 0; i < Item_GetLevelCount(); i++) {
|
||||||
|
@ -530,7 +527,8 @@ void Savegame_PersistGameToCurrentInfo(const GF_LEVEL *const level)
|
||||||
|
|
||||||
bool Savegame_Save(const int32_t slot_idx)
|
bool Savegame_Save(const int32_t slot_idx)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool result = false;
|
||||||
|
Savegame_BindSlot(slot_idx);
|
||||||
|
|
||||||
const GF_LEVEL *const current_level = Game_GetCurrentLevel();
|
const GF_LEVEL *const current_level = Game_GetCurrentLevel();
|
||||||
const char *const level_title = current_level->title;
|
const char *const level_title = current_level->title;
|
||||||
|
@ -540,24 +538,33 @@ bool Savegame_Save(const int32_t slot_idx)
|
||||||
SAVEGAME_INFO *const savegame_info = &m_SavegameInfo[slot_idx];
|
SAVEGAME_INFO *const savegame_info = &m_SavegameInfo[slot_idx];
|
||||||
const bool was_slot_empty = savegame_info->full_path == nullptr;
|
const bool was_slot_empty = savegame_info->full_path == nullptr;
|
||||||
|
|
||||||
char *file_name = String_Format(g_GameFlow.savegame_fmt_legacy, slot_idx);
|
m_SaveCounter++;
|
||||||
MYFILE *const fp = File_Open(file_name, FILE_OPEN_WRITE);
|
for (int32_t i = 0; i < m_StrategyCount; i++) {
|
||||||
if (fp != nullptr) {
|
const SAVEGAME_STRATEGY strategy = m_Strategies[i];
|
||||||
m_SaveCounter++;
|
if (!strategy.allow_save || strategy.save_to_file_func == nullptr) {
|
||||||
Savegame_Legacy_SaveToFile(fp);
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Memory_FreePointer(&savegame_info->full_path);
|
char *file_name =
|
||||||
savegame_info->full_path = Memory_DupStr(File_GetPath(fp));
|
String_Format(strategy.get_save_file_pattern_func(), slot_idx);
|
||||||
savegame_info->counter = m_SaveCounter;
|
MYFILE *const fp = File_Open(file_name, FILE_OPEN_WRITE);
|
||||||
savegame_info->level_num = current_level->num;
|
if (fp != nullptr) {
|
||||||
savegame_info->level_title =
|
strategy.save_to_file_func(fp);
|
||||||
level_title != nullptr ? Memory_DupStr(level_title) : nullptr;
|
savegame_info->format = strategy.format;
|
||||||
File_Close(fp);
|
Memory_FreePointer(&savegame_info->full_path);
|
||||||
ret = true;
|
savegame_info->full_path = Memory_DupStr(File_GetPath(fp));
|
||||||
|
savegame_info->counter = m_SaveCounter;
|
||||||
|
savegame_info->level_num = current_level->num;
|
||||||
|
savegame_info->level_title =
|
||||||
|
level_title != nullptr ? Memory_DupStr(level_title) : nullptr;
|
||||||
|
File_Close(fp);
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory_FreePointer(&file_name);
|
||||||
}
|
}
|
||||||
Memory_FreePointer(&file_name);
|
|
||||||
|
|
||||||
if (ret) {
|
if (result) {
|
||||||
char save_num_text[16];
|
char save_num_text[16];
|
||||||
sprintf(save_num_text, "%d", m_SaveCounter);
|
sprintf(save_num_text, "%d", m_SaveCounter);
|
||||||
Requester_ChangeItem(
|
Requester_ChangeItem(
|
||||||
|
@ -572,27 +579,37 @@ bool Savegame_Save(const int32_t slot_idx)
|
||||||
m_SavedGames++;
|
m_SavedGames++;
|
||||||
}
|
}
|
||||||
Savegame_HighlightNewestSlot();
|
Savegame_HighlightNewestSlot();
|
||||||
|
} else {
|
||||||
|
m_SaveCounter--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Savegame_Load(const int32_t slot_idx)
|
bool Savegame_Load(const int32_t slot_idx)
|
||||||
{
|
{
|
||||||
|
const SAVEGAME_INFO *const savegame_info = &m_SavegameInfo[slot_idx];
|
||||||
|
ASSERT(savegame_info->format != 0);
|
||||||
|
|
||||||
M_LoadPreprocess();
|
M_LoadPreprocess();
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
char *file_name = String_Format(g_GameFlow.savegame_fmt_legacy, slot_idx);
|
for (int32_t i = 0; i < m_StrategyCount; i++) {
|
||||||
MYFILE *const fp = File_Open(file_name, FILE_OPEN_READ);
|
const SAVEGAME_STRATEGY strategy = m_Strategies[i];
|
||||||
if (fp != nullptr) {
|
if (strategy.format != savegame_info->format) {
|
||||||
Savegame_Legacy_LoadFromFile(fp);
|
continue;
|
||||||
File_Close(fp);
|
}
|
||||||
result = true;
|
|
||||||
|
MYFILE *const fp = File_Open(savegame_info->full_path, FILE_OPEN_READ);
|
||||||
|
if (fp != nullptr) {
|
||||||
|
result = strategy.load_from_file_func(fp);
|
||||||
|
File_Close(fp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
M_LoadPostprocess();
|
||||||
M_LoadPostprocess();
|
Savegame_SetInitialVersion(m_SavegameInfo[slot_idx].initial_version);
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#include "game/savegame/savegame_legacy.h"
|
|
||||||
|
|
||||||
#include "game/camera.h"
|
#include "game/camera.h"
|
||||||
#include "game/game.h"
|
#include "game/game.h"
|
||||||
#include "game/game_flow.h"
|
#include "game/game_flow.h"
|
||||||
|
@ -76,6 +74,23 @@ static void M_WriteLaraArm(const LARA_ARM *arm);
|
||||||
static void M_WriteAmmoInfo(const AMMO_INFO *ammo_info);
|
static void M_WriteAmmoInfo(const AMMO_INFO *ammo_info);
|
||||||
static void M_WriteFlares(void);
|
static void M_WriteFlares(void);
|
||||||
|
|
||||||
|
static const char *M_GetSaveFilePattern(void);
|
||||||
|
static bool M_FillInfo(MYFILE *fp, SAVEGAME_INFO *info);
|
||||||
|
static void M_SaveToFile(MYFILE *fp);
|
||||||
|
static bool M_LoadFromFile(MYFILE *fp);
|
||||||
|
|
||||||
|
static SAVEGAME_STRATEGY m_Strategy = {
|
||||||
|
// clang-format off
|
||||||
|
.allow_load = true,
|
||||||
|
.allow_save = true,
|
||||||
|
.format = SAVEGAME_FORMAT_LEGACY,
|
||||||
|
.get_save_file_pattern_func = M_GetSaveFilePattern,
|
||||||
|
.fill_info_func = M_FillInfo,
|
||||||
|
.load_from_file_func = M_LoadFromFile,
|
||||||
|
.save_to_file_func = M_SaveToFile,
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
|
||||||
static void M_Reset(char *const buffer)
|
static void M_Reset(char *const buffer)
|
||||||
{
|
{
|
||||||
m_BufPos = 0;
|
m_BufPos = 0;
|
||||||
|
@ -642,7 +657,58 @@ static void M_WriteFlares(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Savegame_Legacy_SaveToFile(MYFILE *const fp)
|
static const char *M_GetSaveFilePattern(void)
|
||||||
|
{
|
||||||
|
return g_GameFlow.savegame_fmt_legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool M_FillInfo(MYFILE *const fp, SAVEGAME_INFO *const savegame_info)
|
||||||
|
{
|
||||||
|
char level_title[75];
|
||||||
|
File_ReadData(fp, level_title, 75);
|
||||||
|
savegame_info->level_title = Memory_DupStr(level_title);
|
||||||
|
savegame_info->counter = File_ReadS32(fp);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < 24; i++) {
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // pistol ammo
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // magnum ammo
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // uzi ammo
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // shotgun ammo
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // m16 ammo
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // grenade ammo
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // harpoon ammo
|
||||||
|
File_Skip(fp, sizeof(uint8_t)); // small medis
|
||||||
|
File_Skip(fp, sizeof(uint8_t)); // big medis
|
||||||
|
File_Skip(fp, sizeof(uint8_t)); // reserved
|
||||||
|
File_Skip(fp, sizeof(uint8_t)); // flares
|
||||||
|
File_Skip(fp, sizeof(int8_t)); // gun status
|
||||||
|
File_Skip(fp, sizeof(int8_t)); // gun type
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // flags
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // unused
|
||||||
|
File_Skip(fp, sizeof(uint32_t)); // timer
|
||||||
|
File_Skip(fp, sizeof(uint32_t)); // ammo used
|
||||||
|
File_Skip(fp, sizeof(uint32_t)); // hits
|
||||||
|
File_Skip(fp, sizeof(uint32_t)); // distance
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // kills
|
||||||
|
File_Skip(fp, sizeof(uint8_t)); // secret flags
|
||||||
|
File_Skip(fp, sizeof(uint8_t)); // medis used
|
||||||
|
}
|
||||||
|
|
||||||
|
File_Skip(fp, sizeof(uint32_t)); // timer
|
||||||
|
File_Skip(fp, sizeof(uint32_t)); // ammo used
|
||||||
|
File_Skip(fp, sizeof(uint32_t)); // hits
|
||||||
|
File_Skip(fp, sizeof(uint32_t)); // distance
|
||||||
|
File_Skip(fp, sizeof(uint16_t)); // kills
|
||||||
|
File_Skip(fp, sizeof(uint8_t)); // secret flags
|
||||||
|
File_Skip(fp, sizeof(uint8_t)); // medis used
|
||||||
|
|
||||||
|
savegame_info->level_num = File_ReadS16(fp);
|
||||||
|
savegame_info->initial_version = VERSION_LEGACY;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void M_SaveToFile(MYFILE *const fp)
|
||||||
{
|
{
|
||||||
char *buffer = Memory_Alloc(SAVEGAME_LEGACY_TOTAL_SIZE);
|
char *buffer = Memory_Alloc(SAVEGAME_LEGACY_TOTAL_SIZE);
|
||||||
M_Reset(buffer);
|
M_Reset(buffer);
|
||||||
|
@ -712,7 +778,7 @@ void Savegame_Legacy_SaveToFile(MYFILE *const fp)
|
||||||
Memory_FreePointer(&buffer);
|
Memory_FreePointer(&buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Savegame_Legacy_LoadFromFile(MYFILE *const fp)
|
static bool M_LoadFromFile(MYFILE *const fp)
|
||||||
{
|
{
|
||||||
char *buffer = Memory_Alloc(File_Size(fp));
|
char *buffer = Memory_Alloc(File_Size(fp));
|
||||||
File_Seek(fp, 0, FILE_SEEK_SET);
|
File_Seek(fp, 0, FILE_SEEK_SET);
|
||||||
|
@ -798,4 +864,7 @@ void Savegame_Legacy_LoadFromFile(MYFILE *const fp)
|
||||||
M_ReadFlares();
|
M_ReadFlares();
|
||||||
|
|
||||||
Memory_FreePointer(&buffer);
|
Memory_FreePointer(&buffer);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
REGISTER_SAVEGAME_STRATEGY(m_Strategy)
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <libtrx/filesystem.h>
|
|
||||||
|
|
||||||
void Savegame_Legacy_SaveToFile(MYFILE *fp);
|
|
||||||
void Savegame_Legacy_LoadFromFile(MYFILE *fp);
|
|
|
@ -128,13 +128,6 @@ typedef struct {
|
||||||
LEVEL_STATS stats;
|
LEVEL_STATS stats;
|
||||||
} RESUME_INFO;
|
} RESUME_INFO;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *full_path;
|
|
||||||
int32_t counter;
|
|
||||||
int32_t level_num;
|
|
||||||
char *level_title;
|
|
||||||
} SAVEGAME_INFO;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int16_t lock_angles[4];
|
int16_t lock_angles[4];
|
||||||
int16_t left_angles[4];
|
int16_t left_angles[4];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue