Skip to content

Commit

Permalink
tr1/level: replace GFL_*_DEMO_PC with heuristics
Browse files Browse the repository at this point in the history
  • Loading branch information
rr- committed Jan 25, 2025
1 parent b5ca7ce commit 3a1357e
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 37 deletions.
3 changes: 1 addition & 2 deletions data/tr1/ship/cfg/TR1X_gameflow_demo_pc.json5
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

"title": {
"path": "data_demo_pc/title.phd",
"type": "title_demo_pc",
"music_track": 0,
"inherit_injections": false,
"injections": [
Expand All @@ -42,7 +41,7 @@
// Level 2: City of Vilcabamba
{
"path": "data_demo_pc/level2.phd",
"type": "level_demo_pc",
"type": "normal",
"music_track": 0,
"injections": [
"data/injections/vilcabamba_itemrots.bin",
Expand Down
6 changes: 0 additions & 6 deletions src/libtrx/game/game_string_table/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,8 @@ void GameStringTable_Apply(const GAME_FLOW_LEVEL *const level)
const GS_LEVEL_TABLE *level_table = NULL;
switch (level->type) {
case GFL_TITLE:
#if TR_VERSION == 1
case GFL_TITLE_DEMO_PC:
#endif
level_table = NULL;
break;
#if TR_VERSION == 1
case GFL_LEVEL_DEMO_PC:
#endif
case GFL_NORMAL:
case GFL_SAVED:
level_table = &gs_file->levels;
Expand Down
2 changes: 0 additions & 2 deletions src/libtrx/include/libtrx/game/game_flow/enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ typedef enum {
#if TR_VERSION == 1
GFL_GYM,
GFL_BONUS,
GFL_TITLE_DEMO_PC,
GFL_LEVEL_DEMO_PC,
#endif

#if TR_VERSION == 1
Expand Down
9 changes: 9 additions & 0 deletions src/libtrx/include/libtrx/virtual_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,12 @@ int32_t VFile_ReadS32(VFILE *file);
uint8_t VFile_ReadU8(VFILE *file);
uint16_t VFile_ReadU16(VFILE *file);
uint32_t VFile_ReadU32(VFILE *file);

bool VFile_TrySkip(VFILE *file, int32_t offset);
bool VFile_TryRead(VFILE *file, void *target, size_t size);
bool VFile_TryReadS8(VFILE *file, int8_t *dst);
bool VFile_TryReadS16(VFILE *file, int16_t *dst);
bool VFile_TryReadS32(VFILE *file, int32_t *dst);
bool VFile_TryReadU8(VFILE *file, uint8_t *dst);
bool VFile_TryReadU16(VFILE *file, uint16_t *dst);
bool VFile_TryReadU32(VFILE *file, uint32_t *dst);
37 changes: 33 additions & 4 deletions src/libtrx/virtual_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,35 @@ void VFile_SetPos(VFILE *const file, const size_t pos)
file->cur_ptr = file->content + pos;
}

void VFile_Skip(VFILE *file, int32_t offset)
void VFile_Skip(VFILE *const file, const int32_t offset)
{
ASSERT(VFile_TrySkip(file, offset));
}

bool VFile_TrySkip(VFILE *const file, const int32_t offset)
{
const size_t cur_pos = VFile_GetPos(file);
ASSERT(cur_pos + offset <= file->size);
if (cur_pos + offset > file->size) {
return false;
}
file->cur_ptr += offset;
return true;
}

void VFile_Read(VFILE *file, void *target, size_t size)
void VFile_Read(VFILE *const file, void *const target, const size_t size)
{
ASSERT(VFile_TryRead(file, target, size));
}

bool VFile_TryRead(VFILE *const file, void *const target, const size_t size)
{
const size_t cur_pos = VFile_GetPos(file);
ASSERT(cur_pos + size <= file->size);
if (cur_pos + size > file->size) {
return false;
}
memcpy(target, file->cur_ptr, size);
file->cur_ptr += size;
return true;
}

int8_t VFile_ReadS8(VFILE *file)
Expand Down Expand Up @@ -116,3 +132,16 @@ uint32_t VFile_ReadU32(VFILE *file)
VFile_Read(file, &result, sizeof(result));
return result;
}

#define DEFINE_TRY_READ(name, type) \
bool name(VFILE *const file, type *const dst) \
{ \
return VFile_TryRead(file, dst, sizeof(type)); \
}

DEFINE_TRY_READ(VFile_TryReadS8, int8_t)
DEFINE_TRY_READ(VFile_TryReadS16, int16_t)
DEFINE_TRY_READ(VFile_TryReadS32, int32_t)
DEFINE_TRY_READ(VFile_TryReadU8, uint8_t)
DEFINE_TRY_READ(VFile_TryReadU16, uint16_t)
DEFINE_TRY_READ(VFile_TryReadU32, uint32_t)
2 changes: 0 additions & 2 deletions src/tr1/game/game_flow/reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,6 @@ static void M_LoadLevel(
gf->gym_level_num = level->num;
break;

case GFL_LEVEL_DEMO_PC:
case GFL_NORMAL:
if (gf->first_level_num == -1) {
gf->first_level_num = level->num;
Expand All @@ -576,7 +575,6 @@ static void M_LoadLevel(
break;

case GFL_TITLE:
case GFL_TITLE_DEMO_PC:
case GFL_BONUS:
case GFL_DEMO:
case GFL_CUTSCENE:
Expand Down
157 changes: 138 additions & 19 deletions src/tr1/game/level.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,19 @@
#include <stdio.h>
#include <string.h>

typedef enum {
LEVEL_LAYOUT_UNKNOWN = -1,
LEVEL_LAYOUT_TR1,
LEVEL_LAYOUT_TR1_DEMO_PC,
LEVEL_LAYOUT_NUMBER_OF,
} LEVEL_LAYOUT;

static LEVEL_INFO m_LevelInfo = {};
static INJECTION_INFO *m_InjectionInfo = NULL;

static void M_LoadFromFile(const GAME_FLOW_LEVEL *level, bool is_demo);
static bool M_TryLayout(VFILE *file, LEVEL_LAYOUT layout);
static LEVEL_LAYOUT M_GuessLayout(VFILE *file);
static void M_LoadFromFile(const GAME_FLOW_LEVEL *level);
static void M_LoadTexturePages(VFILE *file);
static void M_LoadRooms(VFILE *file);
static void M_LoadObjectMeshes(VFILE *file);
Expand All @@ -60,7 +69,7 @@ static void M_LoadSoundEffects(VFILE *file);
static void M_LoadBoxes(VFILE *file);
static void M_LoadAnimatedTextures(VFILE *file);
static void M_LoadItems(VFILE *file);
static void M_LoadDepthQ(VFILE *file);
static void M_LoadLightTable(VFILE *file);
static void M_LoadPalette(VFILE *file);
static void M_LoadCinematic(VFILE *file);
static void M_LoadDemo(VFILE *file);
Expand All @@ -69,23 +78,136 @@ static void M_CompleteSetup(const GAME_FLOW_LEVEL *level);
static void M_MarkWaterEdgeVertices(void);
static size_t M_CalculateMaxVertices(void);

static void M_LoadFromFile(
const GAME_FLOW_LEVEL *const level, const bool is_demo)
static bool M_TryLayout(VFILE *const file, const LEVEL_LAYOUT layout)
{
#define TRY_OR_FAIL(call) \
if (!call) { \
return false; \
}
#define TRY_OR_FAIL_ARR_S32(size) \
{ \
int32_t num; \
TRY_OR_FAIL(VFile_TryReadS32(file, &num)); \
TRY_OR_FAIL(VFile_TrySkip(file, num *size)); \
}
#define TRY_OR_FAIL_ARR_U16(size) \
{ \
uint16_t num; \
TRY_OR_FAIL(VFile_TryReadU16(file, &num)); \
TRY_OR_FAIL(VFile_TrySkip(file, num *size)); \
}

VFile_SetPos(file, 0);

int32_t version;
TRY_OR_FAIL(VFile_TryReadS32(file, &version));
if (version != 32) {
LOG_ERROR(
"Unknown level version identifier: %d, expected 32", version, 32);
return false;
}

TRY_OR_FAIL_ARR_S32(TEXTURE_PAGE_SIZE); // textures
TRY_OR_FAIL(VFile_TrySkip(file, 4));

uint16_t room_count;
TRY_OR_FAIL(VFile_TryReadU16(file, &room_count));
for (int32_t i = 0; i < room_count; i++) {
TRY_OR_FAIL(VFile_TrySkip(file, 16));
TRY_OR_FAIL_ARR_S32(2); // meshes
TRY_OR_FAIL_ARR_U16(32); // portals

int16_t size_z;
int16_t size_x;
TRY_OR_FAIL(VFile_TryReadS16(file, &size_z));
TRY_OR_FAIL(VFile_TryReadS16(file, &size_x));
TRY_OR_FAIL(VFile_TrySkip(file, size_z * size_x * 8));
TRY_OR_FAIL(VFile_TrySkip(file, 2));

TRY_OR_FAIL_ARR_U16(18); // lights
TRY_OR_FAIL_ARR_U16(18); // static meshes
TRY_OR_FAIL(VFile_TrySkip(file, 4));
}

TRY_OR_FAIL_ARR_S32(2); // floor data
TRY_OR_FAIL_ARR_S32(2); // object meshes
TRY_OR_FAIL_ARR_S32(4); // object mesh pointers
TRY_OR_FAIL_ARR_S32(32); // animations
TRY_OR_FAIL_ARR_S32(6); // animation changes
TRY_OR_FAIL_ARR_S32(8); // animation ranges
TRY_OR_FAIL_ARR_S32(2); // animation commands
TRY_OR_FAIL_ARR_S32(4); // animation bones
TRY_OR_FAIL_ARR_S32(2); // animation frames
TRY_OR_FAIL_ARR_S32(18); // objects
TRY_OR_FAIL_ARR_S32(32); // static objects
TRY_OR_FAIL_ARR_S32(20); // textures
TRY_OR_FAIL_ARR_S32(16); // sprites
TRY_OR_FAIL_ARR_S32(8); // sprites sequences

if (layout == LEVEL_LAYOUT_TR1_DEMO_PC) {
TRY_OR_FAIL(VFile_TrySkip(file, 768)); // palette
}

TRY_OR_FAIL_ARR_S32(16); // cameras
TRY_OR_FAIL_ARR_S32(16); // sound effects

int32_t box_count;
TRY_OR_FAIL(VFile_TryReadS32(file, &box_count));
TRY_OR_FAIL(VFile_TrySkip(file, box_count * 20));
TRY_OR_FAIL_ARR_S32(2); // overlaps
TRY_OR_FAIL(VFile_TrySkip(file, box_count * 12)); // zones

TRY_OR_FAIL_ARR_S32(2); // animated texture ranges
TRY_OR_FAIL_ARR_S32(22); // items

TRY_OR_FAIL(VFile_TrySkip(file, 32 * 256)); // light table

if (layout != LEVEL_LAYOUT_TR1_DEMO_PC) {
TRY_OR_FAIL(VFile_TrySkip(file, 768)); // palette
}

TRY_OR_FAIL_ARR_U16(16); // cinematic frames
TRY_OR_FAIL_ARR_U16(1); // demo data

TRY_OR_FAIL(VFile_TrySkip(file, 2 * MAX_SAMPLES)); // sample lut
TRY_OR_FAIL_ARR_S32(8); // sample infos
TRY_OR_FAIL_ARR_S32(1); // sample data
TRY_OR_FAIL_ARR_S32(4); // samples

#undef TRY_OR_FAIL
#undef TRY_OR_FAIL_ARR_U16
#undef TRY_OR_FAIL_ARR_S32
return true;
}

static LEVEL_LAYOUT M_GuessLayout(VFILE *const file)
{
LEVEL_LAYOUT result = LEVEL_LAYOUT_UNKNOWN;
BENCHMARK *const benchmark = Benchmark_Start();
for (LEVEL_LAYOUT layout = 0; layout < LEVEL_LAYOUT_NUMBER_OF; layout++) {
if (M_TryLayout(file, layout)) {
result = layout;
break;
}
}
Benchmark_End(benchmark, NULL);
return result;
}

static void M_LoadFromFile(const GAME_FLOW_LEVEL *const level)
{
GameBuf_Reset();

VFILE *file = VFile_CreateFromPath(level->path);
if (!file) {
Shell_ExitSystemFmt("M_LoadFromFile(): Could not open %s", level->path);
Shell_ExitSystemFmt("Could not open %s", level->path);
}

const int32_t version = VFile_ReadS32(file);
if (version != 32) {
Shell_ExitSystemFmt(
"Level %d (%s) is version %d (this game code is version %d)",
level->num, level->path, version, 32);
const LEVEL_LAYOUT layout = M_GuessLayout(file);
if (layout == LEVEL_LAYOUT_UNKNOWN) {
Shell_ExitSystemFmt("Failed to load %s", level->path);
}

VFile_SetPos(file, 4);
M_LoadTexturePages(file);

const int32_t file_level_num = VFile_ReadS32(file);
Expand All @@ -104,7 +226,7 @@ static void M_LoadFromFile(
M_LoadTextures(file);
M_LoadSprites(file);

if (is_demo) {
if (layout == LEVEL_LAYOUT_TR1_DEMO_PC) {
M_LoadPalette(file);
}

Expand All @@ -114,9 +236,9 @@ static void M_LoadFromFile(
M_LoadAnimatedTextures(file);
M_LoadItems(file);
Stats_ObserveItemsLoad();
M_LoadDepthQ(file);
M_LoadLightTable(file);

if (!is_demo) {
if (layout != LEVEL_LAYOUT_TR1_DEMO_PC) {
M_LoadPalette(file);
}

Expand Down Expand Up @@ -565,7 +687,7 @@ static void M_LoadItems(VFILE *file)
Benchmark_End(benchmark, NULL);
}

static void M_LoadDepthQ(VFILE *file)
static void M_LoadLightTable(VFILE *file)
{
BENCHMARK *const benchmark = Benchmark_Start();
LOG_INFO("");
Expand Down Expand Up @@ -865,10 +987,7 @@ void Level_Load(const GAME_FLOW_LEVEL *const level)
Inject_Init(
level->injections.count, level->injections.data_paths, m_InjectionInfo);

const bool is_demo =
(level->type == GFL_TITLE_DEMO_PC) | (level->type == GFL_LEVEL_DEMO_PC);

M_LoadFromFile(level, is_demo);
M_LoadFromFile(level);
M_CompleteSetup(level);

Inject_Cleanup();
Expand Down
2 changes: 0 additions & 2 deletions src/tr1/global/enum_map.def
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,3 @@ ENUM_MAP_DEFINE(GAME_FLOW_LEVEL_TYPE, GFL_GYM, "gym")
ENUM_MAP_DEFINE(GAME_FLOW_LEVEL_TYPE, GFL_DUMMY, "dummy")
ENUM_MAP_DEFINE(GAME_FLOW_LEVEL_TYPE, GFL_CURRENT, "current")
ENUM_MAP_DEFINE(GAME_FLOW_LEVEL_TYPE, GFL_BONUS, "bonus")
ENUM_MAP_DEFINE(GAME_FLOW_LEVEL_TYPE, GFL_TITLE_DEMO_PC, "title_demo_pc")
ENUM_MAP_DEFINE(GAME_FLOW_LEVEL_TYPE, GFL_LEVEL_DEMO_PC, "level_demo_pc")

0 comments on commit 3a1357e

Please sign in to comment.