From 24fb0ebd331448769658842ec0ad8bb2d04eaa19 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sun, 4 Oct 2026 15:39:52 +0200 Subject: [PATCH] feat: profile jedi knight and tomb raider ports --- emulators/openjk.yml | 118 ++++++++ emulators/openjkdf2.yml | 199 +++++++++++++ emulators/openmohaa.yml | 181 +++++++++++ emulators/tr1x.yml | 628 ++++++++++++++++++++++++++++++++++++++ emulators/tr2x.yml | 646 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1772 insertions(+) create mode 100644 emulators/openjk.yml create mode 100644 emulators/openjkdf2.yml create mode 100644 emulators/openmohaa.yml create mode 100644 emulators/tr1x.yml create mode 100644 emulators/tr2x.yml diff --git a/emulators/openjk.yml b/emulators/openjk.yml new file mode 100644 index 00000000..bb5ddd50 --- /dev/null +++ b/emulators/openjk.yml @@ -0,0 +1,118 @@ +emulator: openjk +type: standalone +core_classification: game_engine +source: "https://github.com/JACoders/OpenJK" +upstream: "https://github.com/JACoders/OpenJK" +profiled_date: "2026-10-04" +source_commit: "260c59c2907187af555a676fe0cc798893bf7757" +display_name: "OpenJK" +cores: [openjk] +systems: [jediacademy, jediknight2] + +notes: | + id Tech 3 source port for Star Wars Jedi Knight: Jedi Academy (JKA, single + and multiplayer) and Star Wars Jedi Knight II: Jedi Outcast (JK2, single + player only; JK2 MP is not supported, upstream points users to JK2MV). + + One source tree, three binaries: + openjk_sp JKA SP, built from code/ with BuildSPEngine + openjk JKA MP, built from codemp/ with BuildMPEngine + openjo_sp JK2 SP, built from code/ with BuildJK2SPEngine + (same translation units, JK2_MODE defined, + CMakeLists.txt:450-453) + + BASEGAME = "base" (code/qcommon/q_shared.h:86). FS_Startup( BASEGAME ) + adds base/ from cdpath, basepath, apppath, homepath via + FS_AddGameDirectory (code/qcommon/files.cpp:2730) which enumerates every + *.pk3 found there with Sys_ListFiles (code/qcommon/files.cpp:2770). No + specific pak filename is hard-coded in the loader: the retail archives + listed below are the files the stock games ship under base/, not a list + the engine looks up by name. + + Hard engine dependency: default.cfg (SP) or mpdefault.cfg (MP) must be + readable through the virtual filesystem, otherwise FS_Startup aborts + with Com_Error( ERR_FATAL, "Couldn't load default.cfg" ) at + code/qcommon/files.cpp:3002,3041 and codemp/qcommon/files.cpp:4040,4089. + Both config files live inside the retail assets0.pk3. + + Pure-server pak reference list uses NUM_ID_PAKS = 9 + (codemp/qcommon/qcommon.h:567, codemp/qcommon/files.cpp:3169): the MP + client treats base/assets0.pk3 through base/assets8.pk3 as official id + paks and refuses to auto-download them, but this only governs server + compatibility, not file requirement. + +files: + # ================================================================ + # Jedi Academy retail (base/, assets0.pk3 through assets3.pk3) + # Shared by openjk_sp (SP) and openjk (MP) — same base/ directory. + # ================================================================ + + - name: "assets0.pk3" + category: game_data + system: jediacademy + path: "base/assets0.pk3" + required: true + source_ref: "code/qcommon/files.cpp:3002 (default.cfg ERR_FATAL), codemp/qcommon/files.cpp:4040 (mpdefault.cfg ERR_FATAL), codemp/qcommon/files.cpp:3169 (NUM_ID_PAKS index 0)" + note: "Carries default.cfg and mpdefault.cfg — the only files the SP and MP engines refuse to start without. Also holds the base menus, shaders, strings and the cgamex86.dll / jagamex86.dll VMs." + + - name: "assets1.pk3" + category: game_data + system: jediacademy + path: "base/assets1.pk3" + required: false + source_ref: "codemp/qcommon/files.cpp:3169 (NUM_ID_PAKS index 1)" + note: "Retail JKA base content (audio). Loader scans the directory, no hard reference." + + - name: "assets2.pk3" + category: game_data + system: jediacademy + path: "base/assets2.pk3" + required: false + source_ref: "codemp/qcommon/files.cpp:3169 (NUM_ID_PAKS index 2)" + note: "Retail JKA base content (video/cinematics)." + + - name: "assets3.pk3" + category: game_data + system: jediacademy + path: "base/assets3.pk3" + required: false + source_ref: "codemp/qcommon/files.cpp:3169 (NUM_ID_PAKS index 3)" + note: "Retail JKA patch 1.01 content." + + # ================================================================ + # Jedi Outcast retail (base/, assets0.pk3, assets1.pk3, assets2.pk3, + # assets5.pk3). Loaded by openjo_sp (JK2_MODE); openjk upstream does + # not build a JK2 MP engine. + # ================================================================ + + - name: "assets0.pk3" + category: game_data + system: jediknight2 + path: "base/assets0.pk3" + required: true + source_ref: "code/qcommon/files.cpp:3002 (default.cfg ERR_FATAL, built with JK2_MODE via CMakeLists.txt:450-453)" + note: "Retail JK2 base archive. Carries default.cfg; openjo_sp aborts without it." + + - name: "assets1.pk3" + category: game_data + system: jediknight2 + path: "base/assets1.pk3" + required: false + source_ref: "code/qcommon/files.cpp:2770 (Sys_ListFiles(curpath, \".pk3\", ...))" + note: "Retail JK2 base content." + + - name: "assets2.pk3" + category: game_data + system: jediknight2 + path: "base/assets2.pk3" + required: false + source_ref: "code/qcommon/files.cpp:2770 (Sys_ListFiles(curpath, \".pk3\", ...))" + note: "Retail JK2 base content." + + - name: "assets5.pk3" + category: game_data + system: jediknight2 + path: "base/assets5.pk3" + required: false + source_ref: "code/qcommon/files.cpp:2770 (Sys_ListFiles(curpath, \".pk3\", ...))" + note: "Retail JK2 patch 1.04 content." diff --git a/emulators/openjkdf2.yml b/emulators/openjkdf2.yml new file mode 100644 index 00000000..9c5059a3 --- /dev/null +++ b/emulators/openjkdf2.yml @@ -0,0 +1,199 @@ +emulator: OpenJKDF2 +type: standalone +core_classification: game_engine +source: "https://github.com/shinyquagsire23/OpenJKDF2" +upstream: "https://github.com/shinyquagsire23/OpenJKDF2" +profiled_date: "2026-10-04" +source_commit: "02297602cb289b113df27be33b5a7dddbe3d91c1" +core_version: "0.9.9.0" +display_name: "OpenJKDF2" +cores: [] +systems: + - dark-forces-ii + - mysteries-of-the-sith + - droidworks + +notes: | + Reimplementation of LucasArts' Sith engine. Runs Star Wars Jedi Knight: + Dark Forces II (1997), its Mysteries of the Sith expansion (1998) with + the `-motsCompat` switch, and Star Wars DroidWorks (1998) via the + DroidWorks branch of the build. + + Resource mounting (src/Main/jkRes.c): + aGobDirectories[3] "resource" root, auto-mounted at startup + (src/Main/jkRes.c:37 jkRes_LoadNew) + aGobDirectories[1] "episode\.gob" / ".goo" for the active + episode, mounted by jkRes_LoadGob + (src/Main/jkRes.c:103-106) + aGobDirectories[4] gamedata\resource (CD overlay), mounted by + jkRes_LoadCd (src/Main/jkRes.c:130-131) + + Required-asset lists are declared in src/Main/InstallHelper.c and + checked by InstallHelper_CheckInstalled / AttemptInstallFromExisting; + a missing entry aborts installation (src/Main/InstallHelper.c:748-756, + 1091-1097, 1229-1256). + + JK.EXE / JKM.EXE are only consumed by the 32-bit static-recomp build + (src/main.c:696-718, gated by `!ARCH_64BIT && !ARCH_WASM && + !TARGET_ANDROID`), which mmaps the retail binary at 0x400000 and + patches it via do_hooks(). The 64-bit, WASM and Android builds skip + that path and do not read JK.EXE at all. + +files: + # ================================================================ + # Jedi Knight: Dark Forces II (base game) + # ================================================================ + + - name: "JK1.gob" + path: "episode/JK1.gob" + system: dark-forces-ii + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:34 (aRequiredAssets)" + note: "Single-player episode data." + + - name: "JK1CTF.gob" + path: "episode/JK1CTF.gob" + system: dark-forces-ii + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:35 (aRequiredAssets)" + note: "Multiplayer CTF episode." + + - name: "JK1MP.gob" + path: "episode/JK1MP.gob" + system: dark-forces-ii + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:36 (aRequiredAssets)" + note: "Multiplayer deathmatch episode. Default -episode value in Main.c:120." + + - name: "Res1hi.gob" + path: "resource/Res1hi.gob" + system: dark-forces-ii + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:37 (aRequiredAssets)" + note: "High-resolution textures and sprites." + + - name: "Res2.gob" + path: "resource/Res2.gob" + system: dark-forces-ii + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:38 (aRequiredAssets)" + note: "Shared engine resources: sounds, 3DOs, materials." + + - name: "jk_.cd" + path: "resource/jk_.cd" + system: dark-forces-ii + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:39 (aRequiredAssets), src/Main/jkRes.c:234" + note: "CD key marker read by jkRes_ReadKeyFromFile." + + - name: "Res1low.gob" + path: "resource/Res1low.gob" + system: dark-forces-ii + category: game_data + required: false + source_ref: "src/Main/InstallHelper.c:71 (aDiskAssetMap)" + note: "Low-resolution textures shipped on the CD under MININSTALL/." + + - name: "JK.EXE" + system: dark-forces-ii + category: game_data + required: false + source_ref: "src/main.c:696-718, src/Main/InstallHelper.c:494 (aInstallOptionalAssets)" + note: | + Retail executable mmap'd at 0x400000 and patched by do_hooks() in the + 32-bit static-recomp build. Not read by the 64-bit, WASM or Android + builds. + + # ================================================================ + # Mysteries of the Sith (expansion, -motsCompat) + # ================================================================ + + - name: "JKM.goo" + path: "episode/JKM.goo" + system: mysteries-of-the-sith + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:48 (aRequiredAssetsMots)" + note: "Main MoTS single-player episode." + + - name: "JKM_KFY.goo" + path: "episode/JKM_KFY.goo" + system: mysteries-of-the-sith + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:45 (aRequiredAssetsMots)" + + - name: "JKM_MP.goo" + path: "episode/JKM_MP.goo" + system: mysteries-of-the-sith + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:46 (aRequiredAssetsMots)" + + - name: "JKM_SABER.goo" + path: "episode/JKM_SABER.goo" + system: mysteries-of-the-sith + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:47 (aRequiredAssetsMots)" + + - name: "Jkmres.goo" + path: "resource/Jkmres.goo" + system: mysteries-of-the-sith + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:49 (aRequiredAssetsMots)" + note: "Shared MoTS engine resources." + + - name: "JKMsndLO.goo" + path: "resource/JKMsndLO.goo" + system: mysteries-of-the-sith + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:50 (aRequiredAssetsMots)" + note: "Low-quality sound bank (MININSTALL/JKMSNDLO.GOO on the CD)." + + - name: "JKM.EXE" + system: mysteries-of-the-sith + category: game_data + required: false + source_ref: "src/main.c:696-718, src/Main/InstallHelper.c:495 (aInstallOptionalAssets)" + note: "MoTS retail executable, used only by the 32-bit static-recomp build." + + # ================================================================ + # Star Wars DroidWorks (Main_bDroidWorks branch) + # ================================================================ + + - name: "dwCD.GOB" + system: droidworks + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:58 (aRequiredAssetsDroidworks), src/Dw/dwInits.cpp:67-93" + note: "CD-image data archive, mounted by dwGob." + + - name: "dwHD.GOB" + system: droidworks + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:59 (aRequiredAssetsDroidworks), src/Dw/dwInits.cpp:67-93" + note: "Hard-drive install archive." + + - name: "dwMin.GOB" + system: droidworks + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:60 (aRequiredAssetsDroidworks), src/Dw/dwInits.cpp:67-93" + note: "Minimum-install archive." + + - name: "dwStream.GOB" + system: droidworks + category: game_data + required: true + source_ref: "src/Main/InstallHelper.c:61 (aRequiredAssetsDroidworks), src/Dw/dwInits.cpp:93" + note: "Streamed WAV audio, listed only in the WAV ext search path." diff --git a/emulators/openmohaa.yml b/emulators/openmohaa.yml new file mode 100644 index 00000000..d8f9b78c --- /dev/null +++ b/emulators/openmohaa.yml @@ -0,0 +1,181 @@ +emulator: OpenMoHAA +type: standalone +core_classification: game_engine +source: "https://github.com/openmoh/openmohaa" +upstream: "https://github.com/openmoh/openmohaa" +profiled_date: "2026-10-04" +source_commit: "a2f340195975f4f042e28a60b62561dd9a0b2700" +upstream_commit: "a2f340195975f4f042e28a60b62561dd9a0b2700" +display_name: "OpenMoHAA" +cores: [] +systems: [mohaa, mohaa-spearhead, mohaa-breakthrough] + +notes: | + Reimplementation of the id Tech 3-derived engine that powers Medal of + Honor: Allied Assault (2002) and its expansions Spearhead and + Breakthrough. BASEGAME = "main" (code/qcommon/q_shared.h:35); the target + game is selected at startup via the com_target_game cvar (0 = Allied + Assault / TG_MOH, 1 = Spearhead / TG_MOHTA, 2 = Breakthrough / TG_MOHTT, + code/qcommon/common.c:3164-3237). + + FS_AddGameDirectory (code/qcommon/files.cpp:3106) scans the game folder + for every "*.pk3" via Sys_ListFiles(curpath, ".pk3", ...) at line 3136, + sorts them with paksort and mounts each one. It does not look up + individual retail names and does not refuse an unknown pak. FS_Startup + (code/qcommon/files.cpp:3640-3650) always loads com_basegame = "main"; + Spearhead additionally sets fs_basegame = "mainta" (common.c:3200) and + Breakthrough sets fs_basegame = "maintt" (common.c:3227), which triggers + a second FS_AddGameDirectories call for that folder. + + The only hard failure during init is "Couldn't load default.cfg" + (code/qcommon/files.cpp:4108), i.e. no pak in the active search path + provides default.cfg. Retail Pak0.pk3 (main/) carries it; Spearhead and + Breakthrough ship a default.cfg inside their own pak1.pk3 so they can + run with or without a main/ install under openmohaa. + + The retail pak names are documented in-source as reference arrays + fs_originalPaks_main / fs_originalPaks_mainta / fs_originalPaks_maintt + (code/qcommon/files.cpp:324-350). They are declared but not currently + consulted by the loader; they encode the files the engine was authored + against. Capitalisation ("Pak0.pk3" under main/, "pak1.pk3" under + mainta/ and maintt/) matches the retail ISO filenames and is preserved + below for case-sensitive filesystems. FS_FilenameCompare and + Sys_ListFiles are case-insensitive, so Windows installs match either + casing. + + FS_CheckPak0 (code/qcommon/files.cpp:3707) is a documented stub: the + comment at 3710-3712 notes that MOHAA ships in too many localised pak + versions to pin a checksum, so no CRC / MD5 is enforced on the paks. + +files: + # ================================================================ + # Medal of Honor: Allied Assault retail (BASEGAME = "main") + # Reference list: fs_originalPaks_main[] at code/qcommon/files.cpp:324 + # ================================================================ + + - name: "Pak0.pk3" + category: game_data + system: mohaa + path: "main/Pak0.pk3" + required: true + source_ref: "code/qcommon/files.cpp:326 (fs_originalPaks_main[0]), 4108 (Couldn't load default.cfg)" + note: "Carries default.cfg; without it FS_Startup aborts with ERR_FATAL." + + - name: "Pak1.pk3" + category: game_data + system: mohaa + path: "main/Pak1.pk3" + required: false + source_ref: "code/qcommon/files.cpp:327 (fs_originalPaks_main[1])" + + - name: "Pak2.pk3" + category: game_data + system: mohaa + path: "main/Pak2.pk3" + required: false + source_ref: "code/qcommon/files.cpp:328 (fs_originalPaks_main[2])" + + - name: "Pak3.pk3" + category: game_data + system: mohaa + path: "main/Pak3.pk3" + required: false + source_ref: "code/qcommon/files.cpp:329 (fs_originalPaks_main[3])" + + - name: "Pak4.pk3" + category: game_data + system: mohaa + path: "main/Pak4.pk3" + required: false + source_ref: "code/qcommon/files.cpp:330 (fs_originalPaks_main[4])" + + - name: "Pak5.pk3" + category: game_data + system: mohaa + path: "main/Pak5.pk3" + required: false + source_ref: "code/qcommon/files.cpp:331 (fs_originalPaks_main[5])" + + - name: "Pak6.pk3" + category: game_data + system: mohaa + path: "main/Pak6.pk3" + required: false + source_ref: "code/qcommon/files.cpp:332 (fs_originalPaks_main[6])" + + # ================================================================ + # Spearhead expansion (fs_basegame = "mainta", TG_MOHTA) + # Reference list: fs_originalPaks_mainta[] at code/qcommon/files.cpp:335 + # Set com_target_game 1 to load this branch. + # ================================================================ + + - name: "pak1.pk3" + category: game_data + system: mohaa-spearhead + path: "mainta/pak1.pk3" + required: true + source_ref: "code/qcommon/files.cpp:337 (fs_originalPaks_mainta[0]), 3200 (fs_basegame=mainta), 4108" + note: "Spearhead default.cfg lives here; required when com_target_game=1." + + - name: "pak2.pk3" + category: game_data + system: mohaa-spearhead + path: "mainta/pak2.pk3" + required: false + source_ref: "code/qcommon/files.cpp:338 (fs_originalPaks_mainta[1])" + + - name: "pak3.pk3" + category: game_data + system: mohaa-spearhead + path: "mainta/pak3.pk3" + required: false + source_ref: "code/qcommon/files.cpp:339 (fs_originalPaks_mainta[2])" + + - name: "pak4.pk3" + category: game_data + system: mohaa-spearhead + path: "mainta/pak4.pk3" + required: false + source_ref: "code/qcommon/files.cpp:340 (fs_originalPaks_mainta[3])" + + - name: "pak5.pk3" + category: game_data + system: mohaa-spearhead + path: "mainta/pak5.pk3" + required: false + source_ref: "code/qcommon/files.cpp:341 (fs_originalPaks_mainta[4])" + + # ================================================================ + # Breakthrough expansion (fs_basegame = "maintt", TG_MOHTT) + # Reference list: fs_originalPaks_maintt[] at code/qcommon/files.cpp:344 + # Set com_target_game 2 to load this branch. + # ================================================================ + + - name: "pak1.pk3" + category: game_data + system: mohaa-breakthrough + path: "maintt/pak1.pk3" + required: true + source_ref: "code/qcommon/files.cpp:346 (fs_originalPaks_maintt[0]), 3227 (fs_basegame=maintt), 4108" + note: "Breakthrough default.cfg lives here; required when com_target_game=2." + + - name: "pak2.pk3" + category: game_data + system: mohaa-breakthrough + path: "maintt/pak2.pk3" + required: false + source_ref: "code/qcommon/files.cpp:347 (fs_originalPaks_maintt[1])" + + - name: "pak3.pk3" + category: game_data + system: mohaa-breakthrough + path: "maintt/pak3.pk3" + required: false + source_ref: "code/qcommon/files.cpp:348 (fs_originalPaks_maintt[2])" + + - name: "pak4.pk3" + category: game_data + system: mohaa-breakthrough + path: "maintt/pak4.pk3" + required: false + source_ref: "code/qcommon/files.cpp:349 (fs_originalPaks_maintt[3])" diff --git a/emulators/tr1x.yml b/emulators/tr1x.yml new file mode 100644 index 00000000..f414ab79 --- /dev/null +++ b/emulators/tr1x.yml @@ -0,0 +1,628 @@ +emulator: TR1X +display_name: "TR1X" +type: standalone +core_classification: game_engine +source: "https://github.com/LostArtefacts/TRX" +upstream: "https://github.com/LostArtefacts/TRX" +source_commit: "c43c1cc875277324dff44a9e57e4fdd58fd3fb4c" +upstream_commit: "c43c1cc875277324dff44a9e57e4fdd58fd3fb4c" +profiled_date: "2026-10-04" +cores: [] +systems: + - tomb-raider-1 + +notes: | + Enhanced engine for Tomb Raider 1 (1996), part of the TRX monorepo + that also hosts TR2X and TR3X. Loads retail .phd level files, music + tracks and FMV cutscenes from a Steam, GOG or disc install of TR1. + + Path resolution (src/trx/game/paths.c): + levels %mod_dir%/levels/ GAME_DYNAMIC_PATH_LEVEL_FILE + fmv %mod_dir%/fmv/ GAME_DYNAMIC_PATH_FMV_FILE + music %mod_dir%/music/ GAME_DYNAMIC_PATH_MUSIC_DIR + with %mod_dir% = games/tr1 under the TRX root. The game-flow file, + the catalog_*.csv tables, string tables, injections, images and + shaders ship inside the TRX zip (data/trx/ship/) and are not user + files. + + FMV extension probing (src/trx/game/paths.c:76-79): + .mp4 .mkv .mpeg .avi .webm .ogv .rpl .fmv .bik + The retail Core/Eidos cutscenes are .rpl; the gameflow still names + them .avi, resolution picks whichever extension exists. + + Music backend (src/trx/game/music/backend_files.c:25-49): + extensions .flac .ogg .mp3 .wav .wma + file name trackNN. (two-digit) or N. + Retail TR1 CD rips yield track02..track60. + + TR1 keeps every sample inlined in the .phd level files, so no + main.sfx accompanies the levels. + +files: + # Levels + # Enumerated by data/trx/ship/games/tr1/gameflow.json5 "levels" array. + - name: "title.phd" + path: "games/tr1/levels/title.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:38" + + - name: "gym.phd" + path: "games/tr1/levels/gym.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:59" + + - name: "level1.phd" + path: "games/tr1/levels/level1.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:95" + note: "Caves" + + - name: "level2.phd" + path: "games/tr1/levels/level2.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:116" + note: "City of Vilcabamba" + + - name: "level3a.phd" + path: "games/tr1/levels/level3a.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:134" + note: "Lost Valley" + + - name: "level3b.phd" + path: "games/tr1/levels/level3b.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:153" + note: "Tomb of Qualopec" + + - name: "level4.phd" + path: "games/tr1/levels/level4.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:173" + note: "St. Francis' Folly" + + - name: "level5.phd" + path: "games/tr1/levels/level5.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:194" + note: "Colosseum" + + - name: "level6.phd" + path: "games/tr1/levels/level6.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:214" + note: "Palace Midas" + + - name: "level7a.phd" + path: "games/tr1/levels/level7a.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:232" + note: "The Cistern" + + - name: "level7b.phd" + path: "games/tr1/levels/level7b.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:252" + note: "Tomb of Tihocan" + + - name: "level8a.phd" + path: "games/tr1/levels/level8a.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:278" + note: "City of Khamoon" + + - name: "level8b.phd" + path: "games/tr1/levels/level8b.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:300" + note: "Obelisk of Khamoon" + + - name: "level8c.phd" + path: "games/tr1/levels/level8c.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:321" + note: "Sanctuary of the Scion" + + - name: "level10a.phd" + path: "games/tr1/levels/level10a.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:343" + note: "Natla's Mines" + + - name: "level10b.phd" + path: "games/tr1/levels/level10b.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:376" + note: "Atlantis" + + - name: "level10c.phd" + path: "games/tr1/levels/level10c.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:401" + note: "The Great Pyramid" + + - name: "cut1.phd" + path: "games/tr1/levels/cut1.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:490" + note: "Cutscene level 1 (after Qualopec)" + + - name: "cut2.phd" + path: "games/tr1/levels/cut2.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:511" + note: "Cutscene level 2 (after Tihocan)" + + - name: "cut3.phd" + path: "games/tr1/levels/cut3.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:531" + note: "Cutscene level 3 (Khamoon ambush)" + + - name: "cut4.phd" + path: "games/tr1/levels/cut4.phd" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:552" + note: "Cutscene level 4 (Natla's mines)" + + # FMV cutscenes + # Enumerated by data/trx/ship/games/tr1/gameflow.json5 "fmvs" array. + # The retail files on disc carry a .rpl extension; the gameflow still + # lists .avi, resolution picks whichever extension is present. + - name: "core.avi" + aliases: [core.rpl] + path: "games/tr1/fmv/core.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:576" + note: "Core Design legal screen." + + - name: "escape.avi" + aliases: [escape.rpl] + path: "games/tr1/fmv/escape.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:577" + note: "Eidos legal screen." + + - name: "cafe.avi" + aliases: [cafe.rpl] + path: "games/tr1/fmv/cafe.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:578" + note: "Intro cutscene." + + - name: "mansion.avi" + aliases: [mansion.rpl] + path: "games/tr1/fmv/mansion.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:579" + + - name: "snow.avi" + aliases: [snow.rpl] + path: "games/tr1/fmv/snow.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:580" + + - name: "lift.avi" + aliases: [lift.rpl] + path: "games/tr1/fmv/lift.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:581" + + - name: "vision.avi" + aliases: [vision.rpl] + path: "games/tr1/fmv/vision.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:582" + + - name: "canyon.avi" + aliases: [canyon.rpl] + path: "games/tr1/fmv/canyon.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:583" + + - name: "pyramid.avi" + aliases: [pyramid.rpl] + path: "games/tr1/fmv/pyramid.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:584" + + - name: "prison.avi" + aliases: [prison.rpl] + path: "games/tr1/fmv/prison.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:585" + + - name: "end.avi" + aliases: [end.rpl] + path: "games/tr1/fmv/end.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr1/gameflow.json5:586" + + # Music tracks (retail CD audio, ripped as trackNN.). + # Enumerated by the ship tree in docs/trx/INSTALLING.md. + # The code accepts .flac .ogg .mp3 .wav .wma under either trackNN or N. + - name: "track02.flac" + path: "games/tr1/music/track02.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track03.flac" + path: "games/tr1/music/track03.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track04.flac" + path: "games/tr1/music/track04.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track05.flac" + path: "games/tr1/music/track05.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track06.flac" + path: "games/tr1/music/track06.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track07.flac" + path: "games/tr1/music/track07.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track08.flac" + path: "games/tr1/music/track08.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track09.flac" + path: "games/tr1/music/track09.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track10.flac" + path: "games/tr1/music/track10.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track11.flac" + path: "games/tr1/music/track11.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track12.flac" + path: "games/tr1/music/track12.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track13.flac" + path: "games/tr1/music/track13.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track14.flac" + path: "games/tr1/music/track14.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track15.flac" + path: "games/tr1/music/track15.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track16.flac" + path: "games/tr1/music/track16.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track17.flac" + path: "games/tr1/music/track17.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track18.flac" + path: "games/tr1/music/track18.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track19.flac" + path: "games/tr1/music/track19.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track20.flac" + path: "games/tr1/music/track20.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track21.flac" + path: "games/tr1/music/track21.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track22.flac" + path: "games/tr1/music/track22.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track23.flac" + path: "games/tr1/music/track23.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track24.flac" + path: "games/tr1/music/track24.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track25.flac" + path: "games/tr1/music/track25.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track26.flac" + path: "games/tr1/music/track26.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track27.flac" + path: "games/tr1/music/track27.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track28.flac" + path: "games/tr1/music/track28.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track29.flac" + path: "games/tr1/music/track29.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track30.flac" + path: "games/tr1/music/track30.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track31.flac" + path: "games/tr1/music/track31.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track32.flac" + path: "games/tr1/music/track32.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track33.flac" + path: "games/tr1/music/track33.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track34.flac" + path: "games/tr1/music/track34.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track35.flac" + path: "games/tr1/music/track35.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track36.flac" + path: "games/tr1/music/track36.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track37.flac" + path: "games/tr1/music/track37.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track38.flac" + path: "games/tr1/music/track38.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track39.flac" + path: "games/tr1/music/track39.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track40.flac" + path: "games/tr1/music/track40.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track41.flac" + path: "games/tr1/music/track41.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track42.flac" + path: "games/tr1/music/track42.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track43.flac" + path: "games/tr1/music/track43.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track44.flac" + path: "games/tr1/music/track44.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track45.flac" + path: "games/tr1/music/track45.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track46.flac" + path: "games/tr1/music/track46.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track47.flac" + path: "games/tr1/music/track47.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track48.flac" + path: "games/tr1/music/track48.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track49.flac" + path: "games/tr1/music/track49.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track50.flac" + path: "games/tr1/music/track50.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track51.flac" + path: "games/tr1/music/track51.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track52.flac" + path: "games/tr1/music/track52.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track53.flac" + path: "games/tr1/music/track53.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track54.flac" + path: "games/tr1/music/track54.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track55.flac" + path: "games/tr1/music/track55.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track56.flac" + path: "games/tr1/music/track56.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track57.flac" + path: "games/tr1/music/track57.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track58.flac" + path: "games/tr1/music/track58.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track59.flac" + path: "games/tr1/music/track59.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" + + - name: "track60.flac" + path: "games/tr1/music/track60.flac" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:43" diff --git a/emulators/tr2x.yml b/emulators/tr2x.yml new file mode 100644 index 00000000..38e42c1f --- /dev/null +++ b/emulators/tr2x.yml @@ -0,0 +1,646 @@ +emulator: TR2X +display_name: "TR2X" +type: standalone +core_classification: game_engine +source: "https://github.com/LostArtefacts/TRX" +upstream: "https://github.com/LostArtefacts/TRX" +source_commit: "c43c1cc875277324dff44a9e57e4fdd58fd3fb4c" +upstream_commit: "c43c1cc875277324dff44a9e57e4fdd58fd3fb4c" +profiled_date: "2026-10-04" +cores: [] +systems: + - tomb-raider-2 + +notes: | + Enhanced engine for Tomb Raider 2 (1997), part of the TRX monorepo + that also hosts TR1X and TR3X. Loads retail .tr2 level files, the + main.sfx soundbank, music tracks and FMV cutscenes from a Steam, GOG + or disc install of TR2. + + Path resolution (src/trx/game/paths.c): + levels %mod_dir%/levels/ GAME_DYNAMIC_PATH_LEVEL_FILE + sfx %mod_dir%/ GAME_DYNAMIC_PATH_SFX_FILE + fmv %mod_dir%/fmv/ GAME_DYNAMIC_PATH_FMV_FILE + music %mod_dir%/music/ GAME_DYNAMIC_PATH_MUSIC_DIR + with %mod_dir% = games/tr2 under the TRX root. The gameflow.json5, + the catalog_*.csv tables, string tables, injections, images and + shaders ship inside the TRX zip (data/trx/ship/) and are not user + files. + + main.sfx is TR2's sample bank. The gameflow sets sfx_path to it + (data/trx/ship/games/tr2/gameflow.json5:33) and the level pipeline + reads it per level (src/trx/game/level/pipeline.c:179). + + FMV extension probing (src/trx/game/paths.c:76-79): + .mp4 .mkv .mpeg .avi .webm .ogv .rpl .fmv .bik + The retail Core/Eidos cutscenes are .rpl; the gameflow still names + them .AVI, resolution picks whichever extension exists. + + Music backend (src/trx/game/music/backend_files.c:25-49): + extensions .flac .ogg .mp3 .wav .wma + file name trackNN. (two-digit) or N. + Retail TR2 CD rips yield 2.mp3 through 61.mp3 (bare-number form, + per docs/trx/INSTALLING.md ship tree). + +files: + # Soundbank + - name: "main.sfx" + path: "games/tr2/main.sfx" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:33" + note: "Shared sample bank, loaded for every level." + + # Levels + # Enumerated by data/trx/ship/games/tr2/gameflow.json5 "levels" array. + - name: "title.tr2" + path: "games/tr2/levels/title.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:15" + + - name: "assault.tr2" + path: "games/tr2/levels/assault.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:54" + note: "Lara's Home / assault course." + + - name: "wall.tr2" + path: "games/tr2/levels/wall.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:84" + note: "The Great Wall" + + - name: "boat.tr2" + path: "games/tr2/levels/boat.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:119" + note: "Venice" + + - name: "venice.tr2" + path: "games/tr2/levels/venice.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:144" + note: "Bartoli's Hideout" + + - name: "opera.tr2" + path: "games/tr2/levels/opera.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:171" + note: "Opera House" + + - name: "rig.tr2" + path: "games/tr2/levels/rig.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:202" + note: "Offshore Rig" + + - name: "platform.tr2" + path: "games/tr2/levels/platform.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:231" + note: "Diving Area" + + - name: "unwater.tr2" + path: "games/tr2/levels/unwater.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:260" + note: "40 Fathoms" + + - name: "keel.tr2" + path: "games/tr2/levels/keel.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:289" + note: "Wreck of the Maria Doria" + + - name: "living.tr2" + path: "games/tr2/levels/living.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:321" + note: "Living Quarters" + + - name: "deck.tr2" + path: "games/tr2/levels/deck.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:351" + note: "The Deck" + + - name: "skidoo.tr2" + path: "games/tr2/levels/skidoo.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:383" + note: "Tibetan Foothills" + + - name: "monastry.tr2" + path: "games/tr2/levels/monastry.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:411" + note: "Barkhang Monastery" + + - name: "catacomb.tr2" + path: "games/tr2/levels/catacomb.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:440" + note: "Catacombs of the Talion" + + - name: "icecave.tr2" + path: "games/tr2/levels/icecave.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:468" + note: "Ice Palace" + + - name: "emprtomb.tr2" + path: "games/tr2/levels/emprtomb.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:496" + note: "Temple of Xian" + + - name: "floating.tr2" + path: "games/tr2/levels/floating.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:526" + note: "Floating Islands" + + - name: "xian.tr2" + path: "games/tr2/levels/xian.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:552" + note: "The Dragon's Lair" + + - name: "house.tr2" + path: "games/tr2/levels/house.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:578" + note: "Home Sweet Home" + + - name: "cut1.tr2" + path: "games/tr2/levels/cut1.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:691" + note: "Cutscene level 1" + + - name: "cut2.tr2" + path: "games/tr2/levels/cut2.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:706" + note: "Cutscene level 2" + + - name: "cut3.tr2" + path: "games/tr2/levels/cut3.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:721" + note: "Cutscene level 3" + + - name: "cut4.tr2" + path: "games/tr2/levels/cut4.tr2" + required: true + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:737" + note: "Cutscene level 4" + + # FMV cutscenes + # Enumerated by data/trx/ship/games/tr2/gameflow.json5 "fmvs" array. + # The retail files on disc carry a .rpl extension; the gameflow still + # lists .AVI, resolution picks whichever extension is present. + - name: "LOGO.AVI" + aliases: [logo.rpl] + path: "games/tr2/fmv/logo.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:756" + note: "Eidos legal screen." + + - name: "ANCIENT.AVI" + aliases: [ancient.rpl] + path: "games/tr2/fmv/ancient.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:757" + note: "Intro cutscene." + + - name: "MODERN.AVI" + aliases: [modern.rpl] + path: "games/tr2/fmv/modern.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:758" + + - name: "LANDING.AVI" + aliases: [landing.rpl] + path: "games/tr2/fmv/landing.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:759" + + - name: "MS.AVI" + aliases: [ms.rpl] + path: "games/tr2/fmv/ms.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:760" + + - name: "CRASH.AVI" + aliases: [crash.rpl] + path: "games/tr2/fmv/crash.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:761" + + - name: "JEEP.AVI" + aliases: [jeep.rpl] + path: "games/tr2/fmv/jeep.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:762" + + - name: "END.AVI" + aliases: [end.rpl] + path: "games/tr2/fmv/end.rpl" + required: false + category: game_data + source_ref: "data/trx/ship/games/tr2/gameflow.json5:763" + + # Music tracks (retail CD audio, ripped as N.). + # Enumerated by the ship tree in docs/trx/INSTALLING.md (TR2 uses the + # bare-number form, not the trackNN form; the loader accepts either). + - name: "2.mp3" + path: "games/tr2/music/2.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "3.mp3" + path: "games/tr2/music/3.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "4.mp3" + path: "games/tr2/music/4.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "5.mp3" + path: "games/tr2/music/5.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "6.mp3" + path: "games/tr2/music/6.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "7.mp3" + path: "games/tr2/music/7.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "8.mp3" + path: "games/tr2/music/8.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "9.mp3" + path: "games/tr2/music/9.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "10.mp3" + path: "games/tr2/music/10.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "11.mp3" + path: "games/tr2/music/11.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "12.mp3" + path: "games/tr2/music/12.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "13.mp3" + path: "games/tr2/music/13.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "14.mp3" + path: "games/tr2/music/14.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "15.mp3" + path: "games/tr2/music/15.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "16.mp3" + path: "games/tr2/music/16.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "17.mp3" + path: "games/tr2/music/17.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "18.mp3" + path: "games/tr2/music/18.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "19.mp3" + path: "games/tr2/music/19.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "20.mp3" + path: "games/tr2/music/20.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "21.mp3" + path: "games/tr2/music/21.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "22.mp3" + path: "games/tr2/music/22.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "23.mp3" + path: "games/tr2/music/23.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "24.mp3" + path: "games/tr2/music/24.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "25.mp3" + path: "games/tr2/music/25.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "26.mp3" + path: "games/tr2/music/26.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "27.mp3" + path: "games/tr2/music/27.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "28.mp3" + path: "games/tr2/music/28.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "29.mp3" + path: "games/tr2/music/29.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "30.mp3" + path: "games/tr2/music/30.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "31.mp3" + path: "games/tr2/music/31.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "32.mp3" + path: "games/tr2/music/32.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "33.mp3" + path: "games/tr2/music/33.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "34.mp3" + path: "games/tr2/music/34.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "35.mp3" + path: "games/tr2/music/35.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "36.mp3" + path: "games/tr2/music/36.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "37.mp3" + path: "games/tr2/music/37.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "38.mp3" + path: "games/tr2/music/38.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "39.mp3" + path: "games/tr2/music/39.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "40.mp3" + path: "games/tr2/music/40.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "41.mp3" + path: "games/tr2/music/41.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "42.mp3" + path: "games/tr2/music/42.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "43.mp3" + path: "games/tr2/music/43.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "44.mp3" + path: "games/tr2/music/44.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "45.mp3" + path: "games/tr2/music/45.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "46.mp3" + path: "games/tr2/music/46.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "47.mp3" + path: "games/tr2/music/47.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "48.mp3" + path: "games/tr2/music/48.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "49.mp3" + path: "games/tr2/music/49.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "50.mp3" + path: "games/tr2/music/50.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "51.mp3" + path: "games/tr2/music/51.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "52.mp3" + path: "games/tr2/music/52.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "53.mp3" + path: "games/tr2/music/53.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "54.mp3" + path: "games/tr2/music/54.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "55.mp3" + path: "games/tr2/music/55.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "56.mp3" + path: "games/tr2/music/56.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "57.mp3" + path: "games/tr2/music/57.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "58.mp3" + path: "games/tr2/music/58.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "59.mp3" + path: "games/tr2/music/59.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "60.mp3" + path: "games/tr2/music/60.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48" + + - name: "61.mp3" + path: "games/tr2/music/61.mp3" + required: false + category: game_data + source_ref: "src/trx/game/music/backend_files.c:48"