Skip to content

Commit

Permalink
tr2/game-string: read cutscenes and demos
Browse files Browse the repository at this point in the history
  • Loading branch information
rr- committed Jan 24, 2025
1 parent 99a2f4e commit bee88c6
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 38 deletions.
38 changes: 38 additions & 0 deletions data/tr2/ship/cfg/TR2X_strings.json5
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,44 @@
},
],

"demos": [
{
"title": "Venice",
"objects": {
"key_1": {"name": "Boathouse Key"},
"key_2": {"name": "Steel Key"},
"key_3": {"name": "Iron Key"},
},
},

{
"title": "Wreck of the Maria Doria",
"objects": {
"key_1": {"name": "Rest Room Key"},
"key_2": {"name": "Rusty Key"},
"key_3": {"name": "Cabin Key"},
"puzzle_1": {"name": "Circuit Breaker"},
},
},

{
"title": "Tibetan Foothills",
"objects": {
"tiger": {"name": "Snow Leopard"},
"key_1": {"name": "Drawbridge Key"},
"key_2": {"name": "Hut Key"},
"puzzle_4": {"name": "The Seraph"},
},
},
],

"cutscenes": [
{"title": "Cutscene 1"},
{"title": "Cutscene 2"},
{"title": "Cutscene 3"},
{"title": "Cutscene 4"},
],

"objects": {
"small_medipack": {"name": "Small Medipack"},
"large_medipack": {"name": "Large Medipack"},
Expand Down
57 changes: 46 additions & 11 deletions src/libtrx/game/game_string_table/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,24 +81,59 @@ static void M_Apply(const GS_TABLE *const table)
}
}

void GameStringTable_Apply(const int32_t level_num)
void GameStringTable_Apply(const GAME_FLOW_LEVEL *const level)
{
const GS_FILE *const gs_file = &g_GST_File;

if (level_num < -1 || level_num >= gs_file->level_count) {
LOG_WARNING(
"Trying to apply unavailable strings for level %d", level_num);
return;
}

LOG_DEBUG("loading file %d", level_num);
Object_ResetNames();
M_Apply(&gs_file->global);
for (int32_t i = 0; i < GF_GetLevelCount(GFL_NORMAL); i++) {
GF_SetLevelTitle(GF_GetLevel(i, GFL_NORMAL), gs_file->levels[i].title);
GF_SetLevelTitle(
GF_GetLevel(i, GFL_NORMAL), gs_file->levels.entries[i].title);
}

#if TR_VERSION == 2
// TODO: TR1 still has everything in a single linear sequence
for (int32_t i = 0; i < GF_GetLevelCount(GFL_DEMO); i++) {
GF_SetLevelTitle(
GF_GetLevel(i, GFL_DEMO), gs_file->demos.entries[i].title);
}
for (int32_t i = 0; i < GF_GetLevelCount(GFL_CUTSCENE); i++) {
GF_SetLevelTitle(
GF_GetLevel(i, GFL_CUTSCENE), gs_file->cutscenes.entries[i].title);
}
if (level_num != -1) {
M_Apply(&gs_file->levels[level_num].table);
#endif

if (level != NULL) {
#if TR_VERSION == 1
// TODO: TR1 still has everything in a single linear sequence
const GS_LEVEL_TABLE *const level_table = &gs_file->levels;
#elif TR_VERSION == 2
const GS_LEVEL_TABLE *level_table = NULL;
switch (level->type) {
case GFL_NORMAL:
case GFL_SAVED:
level_table = &gs_file->levels;
break;
case GFL_DEMO:
level_table = &gs_file->demos;
break;
case GFL_CUTSCENE:
level_table = &gs_file->cutscenes;
break;
case GFL_TITLE:
level_table = NULL;
break;
default:
ASSERT_FAIL();
}
#endif

if (level_table != NULL) {
ASSERT(level->num >= 0);
ASSERT(level->num < level_table->count);
M_Apply(&level_table->entries[level->num].table);
}
}
M_DoObjectAliases();
}
Expand Down
25 changes: 16 additions & 9 deletions src/libtrx/game/game_string_table/priv.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include "memory.h"

void GS_Table_Free(GS_TABLE *const gs_table)
static void M_FreeTable(GS_TABLE *const gs_table)
{
if (gs_table == NULL) {
return;
Expand Down Expand Up @@ -31,18 +31,25 @@ void GS_Table_Free(GS_TABLE *const gs_table)
}
}

static void M_FreeLevelsTable(GS_LEVEL_TABLE *const levels)
{
if (levels->entries != NULL) {
for (int32_t i = 0; i < levels->count; i++) {
Memory_FreePointer(&levels->entries[i].title);
M_FreeTable(&levels->entries[i].table);
}
}
levels->count = 0;
}

void GS_File_Free(GS_FILE *const gs_file)
{
if (gs_file == NULL) {
return;
}
GS_Table_Free(&gs_file->global);
if (gs_file->levels != NULL) {
for (int32_t i = 0; i < gs_file->level_count; i++) {
Memory_FreePointer(&gs_file->levels[i].title);
GS_Table_Free(&gs_file->levels[i].table);
}
}
M_FreeTable(&gs_file->global);
M_FreeLevelsTable(&gs_file->levels);
M_FreeLevelsTable(&gs_file->demos);
M_FreeLevelsTable(&gs_file->cutscenes);
Memory_FreePointer(&gs_file->levels);
gs_file->level_count = 0;
}
10 changes: 8 additions & 2 deletions src/libtrx/game/game_string_table/priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@ typedef struct {
} GS_LEVEL;

typedef struct {
int32_t level_count;
int32_t count;
GS_LEVEL *entries;
} GS_LEVEL_TABLE;

typedef struct {
GS_TABLE global;
GS_LEVEL *levels;
GS_LEVEL_TABLE levels;
GS_LEVEL_TABLE demos;
GS_LEVEL_TABLE cutscenes;
} GS_FILE;

extern GS_FILE g_GST_File;
Expand Down
32 changes: 21 additions & 11 deletions src/libtrx/game/game_string_table/reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
#include "memory.h"

static void M_LoadTableFromJSON(JSON_OBJECT *root_obj, GS_TABLE *out_table);
static void M_LoadLevelsFromJSON(JSON_OBJECT *obj, GS_FILE *gs_file);
static void M_LoadLevelsFromJSON(
JSON_OBJECT *obj, const char *key, GAME_FLOW_LEVEL_TYPE level_type,
GS_LEVEL_TABLE *gs_level_table);

static void M_LoadTableFromJSON(
JSON_OBJECT *const root_obj, GS_TABLE *const out_table)
Expand Down Expand Up @@ -76,27 +78,29 @@ static void M_LoadTableFromJSON(
}
}

static void M_LoadLevelsFromJSON(JSON_OBJECT *const obj, GS_FILE *const gs_file)
static void M_LoadLevelsFromJSON(
JSON_OBJECT *const obj, const char *const key,
const GAME_FLOW_LEVEL_TYPE level_type, GS_LEVEL_TABLE *const gs_level_table)
{
JSON_ARRAY *const jlvl_arr = JSON_ObjectGetArray(obj, "levels");
JSON_ARRAY *const jlvl_arr = JSON_ObjectGetArray(obj, key);
if (jlvl_arr == NULL) {
Shell_ExitSystem("'levels' must be a list");
Shell_ExitSystemFmt("'%s' must be a list", key);
return;
}

if (jlvl_arr->length != (size_t)GF_GetLevelCount(GFL_NORMAL)) {
if (jlvl_arr->length != (size_t)GF_GetLevelCount(level_type)) {
Shell_ExitSystemFmt(
"'levels' length must match with the game flow level count (got: "
"'%s' length must match with the game flow level count (got: "
"%d, expected: %d)",
jlvl_arr->length, GF_GetLevelCount(GFL_NORMAL));
key, jlvl_arr->length, GF_GetLevelCount(level_type));
}

gs_file->level_count = jlvl_arr->length;
gs_file->levels = Memory_Alloc(sizeof(GS_LEVEL) * jlvl_arr->length);
gs_level_table->count = jlvl_arr->length;
gs_level_table->entries = Memory_Alloc(sizeof(GS_LEVEL) * jlvl_arr->length);

JSON_ARRAY_ELEMENT *jlvl_elem = jlvl_arr->start;
for (size_t i = 0; i < jlvl_arr->length; i++, jlvl_elem = jlvl_elem->next) {
GS_LEVEL *const level = &gs_file->levels[i];
GS_LEVEL *const level = &gs_level_table->entries[i];

JSON_OBJECT *const jlvl_obj = JSON_ValueAsObject(jlvl_elem->value);
if (jlvl_obj == NULL) {
Expand Down Expand Up @@ -141,7 +145,13 @@ void GameStringTable_LoadFromFile(const char *const path)
GS_FILE *const gs_file = &g_GST_File;
JSON_OBJECT *root_obj = JSON_ValueAsObject(root);
M_LoadTableFromJSON(root_obj, &gs_file->global);
M_LoadLevelsFromJSON(root_obj, gs_file);
M_LoadLevelsFromJSON(root_obj, "levels", GFL_NORMAL, &gs_file->levels);
#if TR_VERSION == 2
// TODO: TR1 still has everything in a single linear sequence
M_LoadLevelsFromJSON(root_obj, "demos", GFL_DEMO, &gs_file->demos);
M_LoadLevelsFromJSON(
root_obj, "cutscenes", GFL_CUTSCENE, &gs_file->cutscenes);
#endif

if (root != NULL) {
JSON_ValueFree(root);
Expand Down
2 changes: 1 addition & 1 deletion src/libtrx/include/libtrx/game/game_string_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
#include <stdint.h>

void GameStringTable_LoadFromFile(const char *path);
void GameStringTable_Apply(int32_t level_num);
void GameStringTable_Apply(const GAME_FLOW_LEVEL *level);
void GameStringTable_Shutdown(void);
2 changes: 1 addition & 1 deletion src/tr1/game/level.c
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@ bool Level_Initialise(const GAME_FLOW_LEVEL *const level)

Lara_InitialiseLoad(NO_ITEM);
Level_Load(level);
GameStringTable_Apply(level_num);
GameStringTable_Apply(level);

if (g_Lara.item_num != NO_ITEM) {
Lara_Initialise(level);
Expand Down
2 changes: 1 addition & 1 deletion src/tr2/decomp/decomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ static CAMERA_INFO m_LocalCamera = {};

GAME_FLOW_COMMAND TitleSequence(void)
{
GameStringTable_Apply(-1);
GameStringTable_Apply(NULL);
if (!Level_Initialise(0, GFL_TITLE)) {
return (GAME_FLOW_COMMAND) { .action = GF_EXIT_GAME };
}
Expand Down
2 changes: 0 additions & 2 deletions src/tr2/game/game_flow/sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ GAME_FLOW_COMMAND GF_DoCutsceneSequence(const int32_t cutscene_num)

bool GF_DoFrontendSequence(void)
{
GameStringTable_Apply(-1);
if (g_GameFlow.title_level == NULL) {
return false;
}
Expand All @@ -45,7 +44,6 @@ bool GF_DoFrontendSequence(void)
GAME_FLOW_COMMAND GF_DoLevelSequence(
const int32_t start_level, const GAME_FLOW_LEVEL_TYPE type)
{
GameStringTable_Apply(start_level);
int32_t current_level = start_level;
while (true) {
if (current_level > GF_GetLevelCount(GFL_NORMAL) - 1) {
Expand Down
2 changes: 2 additions & 0 deletions src/tr2/game/level.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <libtrx/engine/audio.h>
#include <libtrx/filesystem.h>
#include <libtrx/game/game_buf.h>
#include <libtrx/game/game_string_table.h>
#include <libtrx/game/level.h>
#include <libtrx/log.h>
#include <libtrx/memory.h>
Expand Down Expand Up @@ -811,6 +812,7 @@ bool Level_Initialise(
if (!Level_Load(level)) {
return false;
}
GameStringTable_Apply(level);

if (g_Lara.item_num != NO_ITEM) {
Lara_Initialise(level);
Expand Down

0 comments on commit bee88c6

Please sign in to comment.