mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 20:58:07 +03:00
tr2/savegame: implement BSON saves
This implements BSON save games, similar to TR1, and opts for it to be used in place of legacy for writing. Saves will also be stored in a separate saves directory.
This commit is contained in:
parent
5b524faec9
commit
0d80ca8f8f
16 changed files with 1299 additions and 29 deletions
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
"main_menu_picture": "data/images/title_eu.png",
|
"main_menu_picture": "data/images/title_eu.png",
|
||||||
"savegame_fmt_legacy": "savegame.%d",
|
"savegame_fmt_legacy": "savegame.%d",
|
||||||
|
"savegame_fmt_bson": "save_tr2_%02d.dat",
|
||||||
|
|
||||||
"cmd_init": {"action": "exit_to_title"},
|
"cmd_init": {"action": "exit_to_title"},
|
||||||
"cmd_title": {"action": "noop"},
|
"cmd_title": {"action": "noop"},
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
"main_menu_picture": "data/images/title_eu_gm.png",
|
"main_menu_picture": "data/images/title_eu_gm.png",
|
||||||
"savegame_fmt_legacy": "savegame_gm.%d",
|
"savegame_fmt_legacy": "savegame_gm.%d",
|
||||||
|
"savegame_fmt_bson": "save_trgm_%02d.dat",
|
||||||
|
|
||||||
"cmd_init": {"action": "exit_to_title"},
|
"cmd_init": {"action": "exit_to_title"},
|
||||||
"cmd_title": {"action": "noop"},
|
"cmd_title": {"action": "noop"},
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
// This file is used to enable the -l argument support.
|
// This file is used to enable the -l argument support.
|
||||||
|
|
||||||
"main_menu_picture": "data/images/title_eu.png",
|
"main_menu_picture": "data/images/title_eu.png",
|
||||||
"savegame_fmt_legacy": "savegame.%d",
|
"savegame_fmt_legacy": "savegame_custom.%d",
|
||||||
|
"savegame_fmt_bson": "save_tr2_custom_%02d.dat",
|
||||||
|
|
||||||
"cmd_init": {"action": "exit_to_title"},
|
"cmd_init": {"action": "exit_to_title"},
|
||||||
"cmd_title": {"action": "noop"},
|
"cmd_title": {"action": "noop"},
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
- added an installer for Windows (#2681)
|
- added an installer for Windows (#2681)
|
||||||
- added the bonus level game flow type, which allows for levels to be unlocked if all main game secrets are found (#2668)
|
- added the bonus level game flow type, which allows for levels to be unlocked if all main game secrets are found (#2668)
|
||||||
- added the ability for custom levels to have up to two of each secret type per level (#2674)
|
- added the ability for custom levels to have up to two of each secret type per level (#2674)
|
||||||
|
- added BSON savegame support, removing the limits imposed by the OG 8KB file size, so allowing for storing more data and offering improved feature support (legacy save files can still be read, similar to TR1) (#2662)
|
||||||
|
- changed savegame files to be stored in the `saves` directory (#2087)
|
||||||
- fixed the final two levels not allowing for secrets to be counted in the statistics (#1582)
|
- fixed the final two levels not allowing for secrets to be counted in the statistics (#1582)
|
||||||
- fixed Lara's holsters being empty if a game flow level removes all weapons but also re-adds the pistols (#2677)
|
- fixed Lara's holsters being empty if a game flow level removes all weapons but also re-adds the pistols (#2677)
|
||||||
- fixed the console opening when remapping its key (#2641)
|
- fixed the console opening when remapping its key (#2641)
|
||||||
|
|
|
@ -310,6 +310,7 @@ as Notepad.
|
||||||
- added Linux builds
|
- added Linux builds
|
||||||
- added macOS builds
|
- added macOS builds
|
||||||
- added .jpeg/.png screenshots
|
- added .jpeg/.png screenshots
|
||||||
|
- added BSON savegame support, removing the limits imposed by the OG 8KB file size, so allowing for storing more data and offering improved feature support
|
||||||
- added ability to skip FMVs with both the Action key
|
- added ability to skip FMVs with both the Action key
|
||||||
- added ability to skip end credits with the Action and Escape keys
|
- added ability to skip end credits with the Action and Escape keys
|
||||||
- added the ability to specify per-level SFX files rather than enforcing the default (main.sfx) on all levels
|
- added the ability to specify per-level SFX files rather than enforcing the default (main.sfx) on all levels
|
||||||
|
|
|
@ -91,9 +91,8 @@ void GF_Shutdown(void)
|
||||||
|
|
||||||
Memory_FreePointer(&gf->main_menu_background_path);
|
Memory_FreePointer(&gf->main_menu_background_path);
|
||||||
Memory_FreePointer(&gf->savegame_fmt_legacy);
|
Memory_FreePointer(&gf->savegame_fmt_legacy);
|
||||||
#if TR_VERSION == 1
|
|
||||||
Memory_FreePointer(&gf->savegame_fmt_bson);
|
Memory_FreePointer(&gf->savegame_fmt_bson);
|
||||||
#else
|
#if TR_VERSION == 2
|
||||||
Memory_FreePointer(&gf->settings.sfx_path);
|
Memory_FreePointer(&gf->settings.sfx_path);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,12 @@ static void M_LoadCommonRoot(JSON_OBJECT *const obj, GAME_FLOW *const gf)
|
||||||
Shell_ExitSystem("'savegame_fmt_legacy' must be a string");
|
Shell_ExitSystem("'savegame_fmt_legacy' must be a string");
|
||||||
}
|
}
|
||||||
gf->savegame_fmt_legacy = Memory_DupStr(tmp_s);
|
gf->savegame_fmt_legacy = Memory_DupStr(tmp_s);
|
||||||
|
|
||||||
|
tmp_s = JSON_ObjectGetString(obj, "savegame_fmt_bson", JSON_INVALID_STRING);
|
||||||
|
if (tmp_s == JSON_INVALID_STRING) {
|
||||||
|
Shell_ExitSystem("'savegame_fmt_bson' must be a string");
|
||||||
|
}
|
||||||
|
gf->savegame_fmt_bson = Memory_DupStr(tmp_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DECLARE_SEQUENCE_EVENT_HANDLER_FUNC(M_HandleIntEvent)
|
static DECLARE_SEQUENCE_EVENT_HANDLER_FUNC(M_HandleIntEvent)
|
||||||
|
|
|
@ -228,16 +228,9 @@ static void M_LoadLevelItemDrops(
|
||||||
|
|
||||||
static void M_LoadRoot(JSON_OBJECT *const obj, GAME_FLOW *const gf)
|
static void M_LoadRoot(JSON_OBJECT *const obj, GAME_FLOW *const gf)
|
||||||
{
|
{
|
||||||
const char *tmp_s;
|
|
||||||
double tmp_d;
|
double tmp_d;
|
||||||
JSON_ARRAY *tmp_arr;
|
JSON_ARRAY *tmp_arr;
|
||||||
|
|
||||||
tmp_s = JSON_ObjectGetString(obj, "savegame_fmt_bson", JSON_INVALID_STRING);
|
|
||||||
if (tmp_s == JSON_INVALID_STRING) {
|
|
||||||
Shell_ExitSystem("'savegame_fmt_bson' must be a string");
|
|
||||||
}
|
|
||||||
gf->savegame_fmt_bson = Memory_DupStr(tmp_s);
|
|
||||||
|
|
||||||
tmp_d = JSON_ObjectGetDouble(obj, "demo_delay", -1.0);
|
tmp_d = JSON_ObjectGetDouble(obj, "demo_delay", -1.0);
|
||||||
if (tmp_d < 0.0) {
|
if (tmp_d < 0.0) {
|
||||||
Shell_ExitSystem("'demo_delay' must be a positive number");
|
Shell_ExitSystem("'demo_delay' must be a positive number");
|
||||||
|
|
|
@ -142,13 +142,13 @@ typedef struct {
|
||||||
GF_FMV *fmvs;
|
GF_FMV *fmvs;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if TR_VERSION == 1
|
|
||||||
// savegame settings
|
// savegame settings
|
||||||
struct {
|
struct {
|
||||||
char *savegame_fmt_legacy;
|
char *savegame_fmt_legacy;
|
||||||
char *savegame_fmt_bson;
|
char *savegame_fmt_bson;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if TR_VERSION == 1
|
||||||
// global settings
|
// global settings
|
||||||
struct {
|
struct {
|
||||||
float demo_delay;
|
float demo_delay;
|
||||||
|
@ -168,11 +168,6 @@ typedef struct {
|
||||||
GF_COMMAND cmd_demo_end;
|
GF_COMMAND cmd_demo_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
// savegame settings
|
|
||||||
struct {
|
|
||||||
char *savegame_fmt_legacy;
|
|
||||||
};
|
|
||||||
|
|
||||||
// global settings
|
// global settings
|
||||||
struct {
|
struct {
|
||||||
float demo_delay;
|
float demo_delay;
|
||||||
|
|
|
@ -56,6 +56,9 @@ static DECLARE_GF_EVENT_HANDLER(M_HandlePlayLevel)
|
||||||
|
|
||||||
case GFSC_SAVED:
|
case GFSC_SAVED:
|
||||||
GF_InventoryModifier_Scan(level);
|
GF_InventoryModifier_Scan(level);
|
||||||
|
// reset current info to the defaults so that we do not do
|
||||||
|
// Item_GlobalReplace in the inventory initialization routines too early
|
||||||
|
Savegame_InitCurrentInfo();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GFSC_SELECT: {
|
case GFSC_SELECT: {
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
#include <libtrx/filesystem.h>
|
#include <libtrx/filesystem.h>
|
||||||
#include <libtrx/game/savegame.h>
|
#include <libtrx/game/savegame.h>
|
||||||
|
|
||||||
#define SAVEGAME_CURRENT_VERSION -1
|
#define SAVEGAME_CURRENT_VERSION 0
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
VERSION_LEGACY = -1,
|
VERSION_LEGACY = -1,
|
||||||
|
VERSION_0 = 0,
|
||||||
} SAVEGAME_VERSION;
|
} SAVEGAME_VERSION;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "game/game_flow.h"
|
#include "game/game_flow.h"
|
||||||
#include "game/game_string.h"
|
#include "game/game_string.h"
|
||||||
#include "game/inventory.h"
|
#include "game/inventory.h"
|
||||||
|
#include "game/lara/misc.h"
|
||||||
#include "game/requester.h"
|
#include "game/requester.h"
|
||||||
#include "game/savegame.h"
|
#include "game/savegame.h"
|
||||||
#include "global/vars.h"
|
#include "global/vars.h"
|
||||||
|
@ -10,6 +11,7 @@
|
||||||
#include <libtrx/debug.h>
|
#include <libtrx/debug.h>
|
||||||
#include <libtrx/enum_map.h>
|
#include <libtrx/enum_map.h>
|
||||||
#include <libtrx/filesystem.h>
|
#include <libtrx/filesystem.h>
|
||||||
|
#include <libtrx/game/lara.h>
|
||||||
#include <libtrx/game/objects/traps/movable_block.h>
|
#include <libtrx/game/objects/traps/movable_block.h>
|
||||||
#include <libtrx/game/savegame.h>
|
#include <libtrx/game/savegame.h>
|
||||||
#include <libtrx/log.h>
|
#include <libtrx/log.h>
|
||||||
|
@ -17,7 +19,8 @@
|
||||||
#include <libtrx/strings.h>
|
#include <libtrx/strings.h>
|
||||||
#include <libtrx/utils.h>
|
#include <libtrx/utils.h>
|
||||||
|
|
||||||
#define MAX_STRATEGIES 1
|
#define MAX_STRATEGIES 2
|
||||||
|
#define SAVES_DIR "saves"
|
||||||
|
|
||||||
static STATS_COMMON *m_DefaultStats = nullptr;
|
static STATS_COMMON *m_DefaultStats = nullptr;
|
||||||
static RESUME_INFO *m_ResumeInfos = nullptr;
|
static RESUME_INFO *m_ResumeInfos = nullptr;
|
||||||
|
@ -136,13 +139,15 @@ static void M_LoadPostprocess(void)
|
||||||
if (obj->save_flags != 0) {
|
if (obj->save_flags != 0) {
|
||||||
item->flags &= 0xFF00;
|
item->flags &= 0xFF00;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->handle_save_func != nullptr) {
|
|
||||||
obj->handle_save_func(item, SAVEGAME_STAGE_AFTER_LOAD);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MovableBlock_SetupFloor();
|
MovableBlock_SetupFloor();
|
||||||
|
|
||||||
|
LARA_INFO *const lara = Lara_GetLaraInfo();
|
||||||
|
if (lara->burn) {
|
||||||
|
lara->burn = 0;
|
||||||
|
Lara_CatchFire();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Savegame_RegisterStrategy(const SAVEGAME_STRATEGY strategy)
|
void Savegame_RegisterStrategy(const SAVEGAME_STRATEGY strategy)
|
||||||
|
@ -206,6 +211,7 @@ void Savegame_ScanSavedGames(void)
|
||||||
m_SavedGames = 0;
|
m_SavedGames = 0;
|
||||||
m_NewestSlot = -1;
|
m_NewestSlot = -1;
|
||||||
|
|
||||||
|
M_ScanSavedGamesDir(SAVES_DIR);
|
||||||
M_ScanSavedGamesDir(".");
|
M_ScanSavedGamesDir(".");
|
||||||
|
|
||||||
for (int32_t i = 0; i < m_SaveSlots; i++) {
|
for (int32_t i = 0; i < m_SaveSlots; i++) {
|
||||||
|
@ -530,6 +536,8 @@ bool Savegame_Save(const int32_t slot_idx)
|
||||||
bool result = false;
|
bool result = false;
|
||||||
Savegame_BindSlot(slot_idx);
|
Savegame_BindSlot(slot_idx);
|
||||||
|
|
||||||
|
File_CreateDirectory(SAVES_DIR);
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -547,7 +555,8 @@ bool Savegame_Save(const int32_t slot_idx)
|
||||||
|
|
||||||
char *file_name =
|
char *file_name =
|
||||||
String_Format(strategy.get_save_file_pattern_func(), slot_idx);
|
String_Format(strategy.get_save_file_pattern_func(), slot_idx);
|
||||||
MYFILE *const fp = File_Open(file_name, FILE_OPEN_WRITE);
|
char *full_path = String_Format("%s/%s", SAVES_DIR, file_name);
|
||||||
|
MYFILE *const fp = File_Open(full_path, FILE_OPEN_WRITE);
|
||||||
if (fp != nullptr) {
|
if (fp != nullptr) {
|
||||||
strategy.save_to_file_func(fp);
|
strategy.save_to_file_func(fp);
|
||||||
savegame_info->format = strategy.format;
|
savegame_info->format = strategy.format;
|
||||||
|
@ -562,6 +571,7 @@ bool Savegame_Save(const int32_t slot_idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory_FreePointer(&file_name);
|
Memory_FreePointer(&file_name);
|
||||||
|
Memory_FreePointer(&full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
|
1257
src/tr2/game/savegame/savegame_bson.c
Normal file
1257
src/tr2/game/savegame/savegame_bson.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -82,7 +82,7 @@ static bool M_LoadFromFile(MYFILE *fp);
|
||||||
static SAVEGAME_STRATEGY m_Strategy = {
|
static SAVEGAME_STRATEGY m_Strategy = {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
.allow_load = true,
|
.allow_load = true,
|
||||||
.allow_save = true,
|
.allow_save = false,
|
||||||
.format = SAVEGAME_FORMAT_LEGACY,
|
.format = SAVEGAME_FORMAT_LEGACY,
|
||||||
.get_save_file_pattern_func = M_GetSaveFilePattern,
|
.get_save_file_pattern_func = M_GetSaveFilePattern,
|
||||||
.fill_info_func = M_FillInfo,
|
.fill_info_func = M_FillInfo,
|
||||||
|
@ -282,6 +282,10 @@ static void M_ReadItems(void)
|
||||||
M_Read(item->data, sizeof(LIFT_INFO));
|
M_Read(item->data, sizeof(LIFT_INFO));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj->handle_save_func != nullptr) {
|
||||||
|
obj->handle_save_func(item, SAVEGAME_STAGE_AFTER_LOAD);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -852,11 +856,6 @@ static bool M_LoadFromFile(MYFILE *const fp)
|
||||||
weapon_item->room_num = NO_ROOM;
|
weapon_item->room_num = NO_ROOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_Lara.burn) {
|
|
||||||
g_Lara.burn = 0;
|
|
||||||
Lara_CatchFire();
|
|
||||||
}
|
|
||||||
|
|
||||||
Room_SetFlipEffect(M_ReadS32());
|
Room_SetFlipEffect(M_ReadS32());
|
||||||
Room_SetFlipTimer(M_ReadS32());
|
Room_SetFlipTimer(M_ReadS32());
|
||||||
g_IsMonkAngry = M_ReadS32();
|
g_IsMonkAngry = M_ReadS32();
|
||||||
|
|
|
@ -266,6 +266,7 @@ sources = [
|
||||||
'game/room.c',
|
'game/room.c',
|
||||||
'game/room_draw.c',
|
'game/room_draw.c',
|
||||||
'game/savegame/common.c',
|
'game/savegame/common.c',
|
||||||
|
'game/savegame/savegame_bson.c',
|
||||||
'game/savegame/savegame_legacy.c',
|
'game/savegame/savegame_legacy.c',
|
||||||
'game/scaler.c',
|
'game/scaler.c',
|
||||||
'game/shell/common.c',
|
'game/shell/common.c',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue