game-strings: move level titles to game strings

This commit is contained in:
Marcin Kurczewski 2025-01-17 12:00:21 +01:00
parent f7a21610ad
commit 2f647000c6
25 changed files with 219 additions and 191 deletions

View file

@ -26,9 +26,8 @@
"enable_killer_pushblocks": true,
"levels": [
// Level 0
// Level 0: Lara's Home
{
"title": "Lara's Home",
"file": "data/gym.phd",
"type": "gym",
"music": 0,
@ -53,9 +52,8 @@
],
},
// Level 1
// Level 1: Caves
{
"title": "Caves",
"file": "data/level1.phd",
"type": "normal",
"music": 57,
@ -75,9 +73,8 @@
],
},
// Level 2
// Level 2: City of Vilcabamba
{
"title": "City of Vilcabamba",
"file": "data/level2.phd",
"type": "normal",
"music": 57,
@ -96,9 +93,8 @@
"demo": true,
},
// Level 3
// Level 3: Lost Valley
{
"title": "Lost Valley",
"file": "data/level3a.phd",
"type": "normal",
"music": 57,
@ -119,9 +115,8 @@
"demo": true,
},
// Level 4
// Level 4: Tomb of Qualopec
{
"title": "Tomb of Qualopec",
"file": "data/level3b.phd",
"type": "normal",
"music": 57,
@ -140,9 +135,8 @@
],
},
// Level 5
// Level 5: St. Francis' Folly
{
"title": "St. Francis' Folly",
"file": "data/level4.phd",
"type": "normal",
"music": 59,
@ -162,9 +156,8 @@
],
},
// Level 6
// Level 6: Colosseum
{
"title": "Colosseum",
"file": "data/level5.phd",
"type": "normal",
"music": 59,
@ -185,9 +178,8 @@
],
},
// Level 7
// Level 7: Palace Midas
{
"title": "Palace Midas",
"file": "data/level6.phd",
"type": "normal",
"music": 59,
@ -206,9 +198,8 @@
"unobtainable_pickups": 1,
},
// Level 8
// Level 8: The Cistern
{
"title": "The Cistern",
"file": "data/level7a.phd",
"type": "normal",
"music": 58,
@ -228,9 +219,8 @@
],
},
// Level 9
// Level 9: Tomb of Tihocan
{
"title": "Tomb of Tihocan",
"file": "data/level7b.phd",
"type": "normal",
"music": 58,
@ -252,9 +242,8 @@
],
},
// Level 10
// Level 10: City of Khamoon
{
"title": "City of Khamoon",
"file": "data/level8a.phd",
"type": "normal",
"music": 59,
@ -274,9 +263,8 @@
],
},
// Level 11
// Level 11: Obelisk of Khamoon
{
"title": "Obelisk of Khamoon",
"file": "data/level8b.phd",
"type": "normal",
"music": 59,
@ -297,9 +285,8 @@
],
},
// Level 12
// Level 12: Sanctuary of the Scion
{
"title": "Sanctuary of the Scion",
"file": "data/level8c.phd",
"type": "normal",
"music": 59,
@ -318,9 +305,8 @@
],
},
// Level 13
// Level 13: Natla's Mines
{
"title": "Natla's Mines",
"file": "data/level10a.phd",
"type": "normal",
"music": 58,
@ -353,9 +339,8 @@
],
},
// Level 14
// Level 14: Atlantis
{
"title": "Atlantis",
"file": "data/level10b.phd",
"type": "normal",
"music": 60,
@ -377,9 +362,8 @@
"unobtainable_pickups": 3,
},
// Level 15
// Level 15: The Great Pyramid
{
"title": "The Great Pyramid",
"file": "data/level10c.phd",
"type": "normal",
"music": 60,
@ -405,9 +389,8 @@
],
},
// Level 16
// Level 16: Cut Scene 1
{
"title": "Cut Scene 1",
"file": "data/cut1.phd",
"type": "cutscene",
"music": 0,
@ -431,9 +414,8 @@
],
},
// Level 17
// Level 17: Cut Scene 2
{
"title": "Cut Scene 2",
"file": "data/cut2.phd",
"type": "cutscene",
"music": 0,
@ -459,9 +441,8 @@
],
},
// Level 18
// Level 18: Cut Scene 3
{
"title": "Cut Scene 3",
"file": "data/cut3.phd",
"type": "cutscene",
"music": 0,
@ -481,9 +462,8 @@
],
},
// Level 19
// Level 19: Cut Scene 4
{
"title": "Cut Scene 4",
"file": "data/cut4.phd",
"type": "cutscene",
"music": 0,
@ -510,9 +490,8 @@
],
},
// Level 20
// Level 20: Title
{
"title": "Title",
"file": "data/title.phd",
"type": "title",
"music": 2,
@ -530,9 +509,13 @@
],
},
// Level 21
// Level 21: Current Position
// This level is necessary to read TombATI's save files!
// OG has a special level called LV_CURRENT to handle save/load logic.
// TR1X does away without this hack. However, the existing save games
// expect the level count to match, otherwise the game will crash.
// Hence this dummy level.
{
"title": "Current Position",
"file": "data/current.phd",
"type": "current",
"music": 0,

View file

@ -26,9 +26,8 @@
"enable_killer_pushblocks": true,
"levels": [
// Level 2
// Level 2: City of Vilcabamba
{
"title": "City of Vilcabamba",
"file": "data_demo_pc/level2.phd",
"type": "level_demo_pc",
"music": 0,
@ -47,9 +46,8 @@
"demo": true,
},
// Level 3
// Level 3: Title
{
"title": "Title",
"file": "data_demo_pc/title.phd",
"type": "title_demo_pc",
"music": 0,
@ -62,9 +60,8 @@
],
},
// Level 4
// Level 4: Current Position
{
"title": "Current Position",
"file": "data/current.phd",
"type": "current",
"music": 0,

View file

@ -29,9 +29,8 @@
},
"levels": [
// Level 0
// Level 0: Return to Egypt
{
"title": "Return to Egypt",
"file": "data/egypt.phd",
"type": "normal",
"music": 59,
@ -52,9 +51,8 @@
"unobtainable_kills": 1,
},
// Level 1
// Level 1: Temple of the Cat
{
"title": "Temple of the Cat",
"file": "data/cat.phd",
"type": "normal",
"music": 59,
@ -76,9 +74,8 @@
"unobtainable_pickups": 1,
},
// Level 2
// Level 2: Atlantean Stronghold
{
"title": "Atlantean Stronghold",
"file": "data/end.phd",
"type": "normal",
"music": 60,
@ -97,9 +94,8 @@
"unobtainable_kills": 1,
},
// Level 3
// Level 3: The Hive
{
"title": "The Hive",
"file": "data/end2.phd",
"type": "normal",
"music": 60,
@ -124,9 +120,8 @@
],
},
// Level 4
// Level 4: Title
{
"title": "Title",
"file": "data/title.phd",
"type": "title",
"music": 2,
@ -142,12 +137,7 @@
],
},
// Level 5
// This level is necessary to read TombATI's save files!
// OG has a special level called LV_CURRENT to handle save/load logic.
// TR1X does away without this hack. However, the existing save games
// expect the level count to match, otherwise the game will crash.
// Hence this dummy level.
// Level 5: Current Position
{
"title": "Current Position",
"file": "data/current.phd",

View file

@ -4,13 +4,18 @@
"levels": [
// Level 0: Lara's Home
{},
{
"title": "Lara's Home",
},
// Level 1: Caves
{},
{
"title": "Caves",
},
// Level 2: City of Vilcabamba
{
"title": "City of Vilcabamba",
"objects": {
"key_1": {"name": "Silver Key"},
"puzzle_1": {"name": "Gold Idol"},
@ -19,16 +24,20 @@
// Level 3: Lost Valley
{
"title": "Lost Valley",
"objects": {
"puzzle_1": {"name": "Machine Cog"},
},
},
// Level 4: Tomb of Qualopec
{},
{
"title": "Tomb of Qualopec",
},
// Level 5: St. Francis' Folly
{
"title": "St. Francis' Folly",
"objects": {
"key_1": {"name": "Neptune Key"},
"key_2": {"name": "Atlas Key"},
@ -39,6 +48,7 @@
// Level 6: Colosseum
{
"title": "Colosseum",
"objects": {
"key_1": {"name": "Rusty Key"},
},
@ -46,6 +56,7 @@
// Level 7: Palace Midas
{
"title": "Palace Midas",
"objects": {
"puzzle_1": {"name": "Gold Bar"},
},
@ -53,6 +64,7 @@
// Level 8: The Cistern
{
"title": "The Cistern",
"objects": {
"key_1": {"name": "Gold Key"},
"key_2": {"name": "Silver Key"},
@ -62,6 +74,7 @@
// Level 9: Tomb of Tihocan
{
"title": "Tomb of Tihocan",
"objects": {
"key_1": {"name": "Gold Key"},
"key_2": {"name": "Rusty Key"},
@ -71,6 +84,7 @@
// Level 10: City of Khamoon
{
"title": "City of Khamoon",
"objects": {
"key_1": {"name": "Sapphire Key"},
},
@ -78,6 +92,7 @@
// Level 11: Obelisk of Khamoon
{
"title": "Obelisk of Khamoon",
"objects": {
"key_1": {"name": "Sapphire Key"},
"puzzle_1": {"name": "Eye of Horus"},
@ -89,6 +104,7 @@
// Level 12: Sanctuary of the Scion
{
"title": "Sanctuary of the Scion",
"objects": {
"key_1": {"name": "Gold Key"},
"puzzle_1": {"name": "Ankh"},
@ -98,6 +114,7 @@
// Level 13: Natla's Mines
{
"title": "Natla's Mines",
"objects": {
"puzzle_1": {"name": "Fuse"},
"puzzle_2": {"name": "Pyramid Key"},
@ -105,28 +122,44 @@
},
// Level 14: Atlantis
{},
{
"title": "Atlantis",
},
// Level 15: The Great Pyramid
{},
{
"title": "The Great Pyramid",
},
// Level 16: Cut Scene 1
{},
{
"title": "Cut Scene 1",
},
// Level 17: Cut Scene 2
{},
{
"title": "Cut Scene 2",
},
// Level 18: Cut Scene 3
{},
{
"title": "Cut Scene 3",
},
// Level 19: Cut Scene 4
{},
{
"title": "Cut Scene 4",
},
// Level 20: Title
{},
{
"title": "Title",
},
// Level 21: Current Position
{},
{
"title": "Current Position",
},
],
"objects": {

View file

@ -2,6 +2,7 @@
"levels": [
// Level 2: City of Vilcabamba
{
"title": "City of Vilcabamba",
"objects": {
"key_1": {"name": "Silver Key"},
"puzzle_1": {"name": "Gold Idol"},
@ -9,9 +10,13 @@
},
// Level 3: Title
{},
{
"title": "Title",
},
// Level 4: Current Position
{},
{
"title": "Current Position",
},
],
}

View file

@ -2,6 +2,7 @@
"levels": [
// Level 0: Return to Egypt
{
"title": "Return to Egypt",
"objects": {
"key_1": {"name": "Gold Key"},
},
@ -9,21 +10,30 @@
// Level 1: Temple of the Cat
{
"title": "Temple of the Cat",
"objects": {
"key_1": {"name": "Ornate Key"},
},
},
// Level 2: Atlantean Stronghold
{},
{
"title": "Atlantean Stronghold",
},
// Level 3: The Hive
{},
{
"title": "The Hive",
},
// Level 4: Title
{},
{
"title": "Title",
},
// Level 5: Current Position
{},
{
"title": "Current Position",
},
],
}

View file

@ -4,10 +4,13 @@
"levels": [
// 0. Lara's Home
{},
{
"title": "Lara's Home",
},
// 1. The Great Wall
{
"title": "The Great Wall",
"objects": {
"key_1": {"name": "Guardhouse Key"},
"key_2": {"name": "Rusty Key"},
@ -16,6 +19,7 @@
// 2. Venice
{
"title": "Venice",
"objects": {
"key_1": {"name": "Boathouse Key"},
"key_2": {"name": "Steel Key"},
@ -25,6 +29,7 @@
// 3. Bartoli's Hideout
{
"title": "Bartoli's Hideout",
"objects": {
"key_1": {"name": "Library Key"},
"key_2": {"name": "Detonator Key"},
@ -33,6 +38,7 @@
// 4. Opera House
{
"title": "Opera House",
"objects": {
"key_1": {"name": "Ornate Key"},
"puzzle_1": {"name": "Relay Box"},
@ -42,6 +48,7 @@
// 5. Offshore Rig
{
"title": "Offshore Rig",
"objects": {
"key_1": {"name": "Red Pass Card"},
"key_2": {"name": "Yellow Pass Card"},
@ -51,6 +58,7 @@
// 6. Diving Area
{
"title": "Diving Area",
"objects": {
"key_1": {"name": "Red Pass Card"},
"key_4": {"name": "Blue Pass Card"},
@ -59,10 +67,13 @@
},
// 7. 40 Fathoms
{},
{
"title": "40 Fathoms",
},
// 8. Wreck of the Maria Doria
{
"title": "Wreck of the Maria Doria",
"objects": {
"key_1": {"name": "Rest Room Key"},
"key_2": {"name": "Rusty Key"},
@ -73,6 +84,7 @@
// 9. Living Quarters
{
"title": "Living Quarters",
"objects": {
"key_1": {"name": "Theatre Key"},
"key_2": {"name": "Rusty Key"},
@ -81,6 +93,7 @@
// 10. The Deck
{
"title": "The Deck",
"objects": {
"key_2": {"name": "Stern Key"},
"key_3": {"name": "Storage Key"},
@ -91,6 +104,7 @@
// 11. Tibetan Foothills
{
"title": "Tibetan Foothills",
"objects": {
"tiger": {"name": "Snow Leopard"},
"key_1": {"name": "Drawbridge Key"},
@ -101,6 +115,7 @@
// 12. Barkhang Monastery
{
"title": "Barkhang Monastery",
"objects": {
"key_1": {"name": "Strongroom Key"},
"key_2": {"name": "Trapdoor Key"},
@ -114,6 +129,7 @@
// 13. Catacombs of the Talion
{
"title": "Catacombs of the Talion",
"objects": {
"tiger": {"name": "Snow Leopard"},
"pickup_1": {"name": "Gong Hammer"},
@ -123,6 +139,7 @@
// 14. Ice Palace
{
"title": "Ice Palace",
"objects": {
"tiger": {"name": "Snow Leopard"},
"key_2": {"name": "Gong Hammer"},
@ -133,6 +150,7 @@
// 15. Temple of Xian
{
"title": "Temple of Xian",
"objects": {
"key_2": {"name": "Gold Key"},
"key_3": {"name": "Silver Key"},
@ -143,6 +161,7 @@
// 16. Floating Islands
{
"title": "Floating Islands",
"objects": {
"puzzle_1": {"name": "Mystic Plaque"},
"puzzle_2": {"name": "Mystic Plaque"},
@ -151,6 +170,7 @@
// 17. The Dragon's Lair
{
"title": "The Dragon's Lair",
"objects": {
"puzzle_1": {"name": "Mystic Plaque"},
"puzzle_2": {"name": "Dagger of Xian"},
@ -159,6 +179,7 @@
// 18. Home Sweet Home
{
"title": "Home Sweet Home",
"objects": {
"key_1": {"name": "Gun Cupboard Key"},
"puzzle_1": {"name": "Dagger of Xian"},
@ -167,6 +188,7 @@
// 19. Demo 1
{
"title": "Venice",
"objects": {
"key_1": {"name": "Boathouse Key"},
"key_2": {"name": "Steel Key"},
@ -176,6 +198,7 @@
// 20. Demo 2
{
"title": "Wreck of the Maria Doria",
"objects": {
"key_1": {"name": "Rest Room Key"},
"key_2": {"name": "Rusty Key"},
@ -186,6 +209,7 @@
// 21. Demo 3
{
"title": "Tibetan Foothills",
"objects": {
"key_1": {"name": "Drawbridge Key"},
"key_2": {"name": "Hut Key"},

View file

@ -14,6 +14,7 @@ The document is organized as follows:
{
"levels": {
{
"title": "City of Vilcabamba",
"objects": {
"key_1": {
"name": "Silver Key",
@ -29,7 +30,7 @@ The document is organized as follows:
// etc
},
"game_strings": {
"STATS_TIME_TAKEN": "...",
"STATS_TIME_TAKEN": "Time Taken",
// etc
},
},
@ -40,7 +41,7 @@ The document is organized as follows:
// etc
},
"game_strings": {
"STATS_TIME_TAKEN": "...",
"STATS_TIME_TAKEN": "Time Taken",
// etc
},
}
@ -69,6 +70,15 @@ The document is organized as follows:
</td>
</tr>
<tr valign="top">
<td>
<code>title</code>
</td>
<td>String</td>
<td>Yes</td>
<td colspan="2">The title of the level.</td>
</tr>
<tr valign="top">
<td>
<code>objects</code>
@ -147,12 +157,14 @@ The document is organized as follows:
## Usage Guidelines
- Levels are zero-indexed and match the order with the game flow file.
- It doesn't make sense to ship a custom level with all of the strings defined.
Actually, your file should be as small as possible - the game will fall back to the
built-in defaults for you! For example - the following document is perfectly fine:
We encourage you to make your strings file as small as possible - the game
will fall back to the built-in defaults for you! For example, the following
document is perfectly fine:
```json5
{
"levels": [
{
"title": "City of Vilcabamba",
"objects": {
{"name": "key_1": "Gold Key"},
},

View file

@ -1,9 +1,14 @@
## [Unreleased](https://github.com/LostArtefacts/TRX/compare/tr1-4.7.1...develop) - ××××-××-××
>[!WARNING]
>There is a backwards incompatible change important for level builders, that changes where to place key item names and level titles.
>Please refer to the [documentation](../GAME_STRINGS.md) to see how to upgrade your level files.
- added the ability to hold forward/back to move through menus more quickly (#2298)
- added an option for pickup aids, which will show an intermittent twinkle when Lara is nearby pickup items (#2076)
- added an optional demo number argument to the `/demo` command
- added pause screen support to demos
- added a fade-out effect when exiting the game from the pause screen
- ⚠️ changed the game data to use a separate strings file for text information, removing it from the game flow file
- changed demo to be interrupted only by esc or action keys
- changed the turbo cheat to also affect ingame timer (#2167)
- changed the pause screen to wait before yielding control during fade out effect

View file

@ -38,7 +38,7 @@ various pieces of global behaviour.
},
"levels": [
{
"title": "Caves",
"file": "data/gym.phd",
// etc
}
],
@ -217,7 +217,6 @@ Following are each of the properties available within a level.
```json5
{
"title": "Example Level",
"file": "data/example.phd",
"type": "normal",
"music": 57,
@ -359,14 +358,6 @@ Following are each of the properties available within a level.
<a href="#sequences">Sequences</a> for full details.
</td>
</tr>
<tr valign="top">
<td>
<code>title</code>
</td>
<td>String</td>
<td>Yes</td>
<td colspan="2">The title of the level.</td>
</tr>
<tr valign="top">
<td rowspan="8">
<code>type</code>
@ -802,7 +793,6 @@ game will exit to title.
},
{
"title": "Level 1",
"file": "data/level1.phd",
"type": "normal",
"music": 57,
@ -816,7 +806,6 @@ game will exit to title.
},
{
"title": "Level 2",
"file": "data/level2.phd",
"type": "normal",
"music": 57,
@ -830,7 +819,6 @@ game will exit to title.
},
{
"title": "Level 3",
"file": "data/level3.phd",
"type": "normal",
"music": 57,
@ -850,7 +838,6 @@ game will exit to title.
},
{
"title": "Level 4",
"file": "data/bonus1.phd",
"type": "bonus",
"music": 57,
@ -864,7 +851,6 @@ game will exit to title.
},
{
"title": "Level 5",
"file": "data/bonus2.phd",
"type": "bonus",
"music": 57,
@ -880,7 +866,6 @@ game will exit to title.
},
{
"title": "Bonus Cut Scene",
"file": "data/bonuscut1.phd",
"type": "cutscene",
"music": 0,
@ -921,7 +906,6 @@ the engine's overall item limit).
```json5
{
"title": "Example Level",
"file": "data/example.phd",
"type": "normal",
"music": 57,

View file

@ -1,13 +1,12 @@
#include "debug.h"
#include "enum_map.h"
#include "game/game_string.h"
#include "game/game_string_table.h"
#include "game/game_string_table/priv.h"
#include "game/gameflow.h"
#include "game/objects/names.h"
#include "log.h"
#include "memory.h"
#include <stddef.h>
#include <string.h>
typedef void (*M_LOAD_STRING_FUNC)(const char *, const char *);
@ -119,8 +118,11 @@ void GameStringTable_Apply(const int32_t level_num)
LOG_DEBUG("loading file %d", level_num);
Object_ResetNames();
M_Apply(&gs_file->global);
for (int32_t i = 0; i < GameFlow_GetLevelCount(); i++) {
GameFlow_SetLevelTitle(i, gs_file->levels[i].title);
}
if (level_num != -1) {
M_Apply(&gs_file->levels[level_num]);
M_Apply(&gs_file->levels[level_num].table);
}
M_DoObjectAliases();
}

View file

@ -39,7 +39,8 @@ void GS_File_Free(GS_FILE *const gs_file)
GS_Table_Free(&gs_file->global);
if (gs_file->levels != NULL) {
for (int32_t i = 0; i < gs_file->level_count; i++) {
GS_Table_Free(&gs_file->levels[i]);
Memory_FreePointer(&gs_file->levels[i].title);
GS_Table_Free(&gs_file->levels[i].table);
}
}
Memory_FreePointer(&gs_file->levels);

View file

@ -18,10 +18,15 @@ typedef struct {
GS_GAME_STRING_ENTRY *game_strings;
} GS_TABLE;
typedef struct {
const char *title;
GS_TABLE table;
} GS_LEVEL;
typedef struct {
int32_t level_count;
GS_TABLE global;
GS_TABLE *levels;
GS_LEVEL *levels;
} GS_FILE;
extern GS_FILE g_GST_File;

View file

@ -1,20 +1,18 @@
#include "filesystem.h"
#include "game/game_string_table.h"
#include "game/game_string_table/priv.h"
#include "game/gameflow.h"
#include "game/shell.h"
#include "json.h"
#include "log.h"
#include "memory.h"
#include <string.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 bool M_LoadTableFromJSON(JSON_OBJECT *root_obj, GS_TABLE *out_table);
static bool M_LoadLevelsFromJSON(JSON_OBJECT *obj, GS_FILE *gs_file);
static bool M_LoadTableFromJSON(
static void M_LoadTableFromJSON(
JSON_OBJECT *const root_obj, GS_TABLE *const out_table)
{
bool result = true;
// Load objects
JSON_OBJECT *const jobjs = JSON_ObjectGetObject(root_obj, "objects");
if (jobjs != NULL) {
@ -76,60 +74,57 @@ static bool M_LoadTableFromJSON(
}
}
}
end:
if (!result) {
if (out_table != NULL) {
GS_Table_Free(out_table);
}
}
return result;
}
static bool M_LoadLevelsFromJSON(JSON_OBJECT *const obj, GS_FILE *const gs_file)
static void M_LoadLevelsFromJSON(JSON_OBJECT *const obj, GS_FILE *const gs_file)
{
bool result = true;
JSON_ARRAY *const jlvl_arr = JSON_ObjectGetArray(obj, "levels");
if (jlvl_arr == NULL) {
LOG_ERROR("'levels' must be a list");
result = false;
goto end;
Shell_ExitSystem("'levels' must be a list");
return;
}
if (jlvl_arr->length != (size_t)GameFlow_GetLevelCount()) {
Shell_ExitSystemFmt(
"'levels' length must match with the game flow level count (got: "
"%d, expected: %d)",
jlvl_arr->length, GameFlow_GetLevelCount());
}
gs_file->level_count = jlvl_arr->length;
gs_file->levels = Memory_Alloc(sizeof(GS_TABLE) * jlvl_arr->length);
gs_file->levels = 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_TABLE *const level_table = &gs_file->levels[i];
GS_LEVEL *const level = &gs_file->levels[i];
JSON_OBJECT *const jlvl_obj = JSON_ValueAsObject(jlvl_elem->value);
if (jlvl_obj == NULL) {
LOG_ERROR("'levels' elements must be dictionaries");
result = false;
goto end;
Shell_ExitSystem("'levels' elements must be dictionaries");
return;
}
result &= M_LoadTableFromJSON(jlvl_obj, level_table);
}
const char *const title =
JSON_ObjectGetString(jlvl_obj, "title", JSON_INVALID_STRING);
if (title == JSON_INVALID_STRING) {
Shell_ExitSystemFmt("Level %d is missing title.", i);
return;
}
level->title = Memory_DupStr(title);
end:
return result;
M_LoadTableFromJSON(jlvl_obj, &level->table);
}
}
bool GameStringTable_LoadFromFile(const char *const path)
void GameStringTable_LoadFromFile(const char *const path)
{
GameStringTable_Shutdown();
bool result = true;
JSON_VALUE *root = NULL;
char *script_data = NULL;
if (!File_Load(path, &script_data, NULL)) {
LOG_ERROR("failed to open strings file");
result = false;
goto end;
Shell_ExitSystemFmt("failed to open strings file (path: %d)", path);
}
JSON_PARSE_RESULT parse_result;
@ -137,29 +132,20 @@ bool GameStringTable_LoadFromFile(const char *const path)
script_data, strlen(script_data), JSON_PARSE_FLAGS_ALLOW_JSON5, NULL,
NULL, &parse_result);
if (root == NULL) {
LOG_ERROR(
"failed to parse script file: %s in line %d, char %d",
Shell_ExitSystemFmt(
"Failed to parse script file: %s in line %d, char %d",
JSON_GetErrorDescription(parse_result.error),
parse_result.error_line_no, parse_result.error_row_no, script_data);
result = false;
goto end;
}
GS_FILE *const gs_file = &g_GST_File;
JSON_OBJECT *root_obj = JSON_ValueAsObject(root);
result &= M_LoadTableFromJSON(root_obj, &gs_file->global);
result &= M_LoadLevelsFromJSON(root_obj, gs_file);
M_LoadTableFromJSON(root_obj, &gs_file->global);
M_LoadLevelsFromJSON(root_obj, gs_file);
end:
if (root != NULL) {
JSON_ValueFree(root);
root = NULL;
}
if (!result) {
GameStringTable_Shutdown();
}
Memory_FreePointer(&script_data);
return result;
}

View file

@ -2,6 +2,6 @@
#include <stdint.h>
bool GameStringTable_LoadFromFile(const char *path);
void GameStringTable_LoadFromFile(const char *path);
void GameStringTable_Apply(int32_t level_num);
void GameStringTable_Shutdown(void);

View file

@ -6,6 +6,7 @@ extern int32_t GameFlow_GetLevelCount(void);
extern int32_t GameFlow_GetDemoCount(void);
extern const char *GameFlow_GetLevelFileName(int32_t level_num);
extern const char *GameFlow_GetLevelTitle(int32_t level_num);
extern void GameFlow_SetLevelTitle(int32_t level_num, const char *title);
extern int32_t GameFlow_GetGymLevelNum(void);
extern void GameFlow_OverrideCommand(GAME_FLOW_COMMAND action);

View file

@ -2,7 +2,6 @@
#include "game/fmv.h"
#include "game/game.h"
#include "game/game_string.h"
#include "game/inventory.h"
#include "game/inventory_ring.h"
#include "game/lara/common.h"
@ -10,19 +9,12 @@
#include "game/music.h"
#include "game/objects/creatures/bacon_lara.h"
#include "game/objects/vars.h"
#include "game/output.h"
#include "game/phase.h"
#include "game/room.h"
#include "game/savegame.h"
#include "global/vars.h"
#include <libtrx/config.h>
#include <libtrx/debug.h>
#include <libtrx/enum_map.h>
#include <libtrx/filesystem.h>
#include <libtrx/game/objects/names.h>
#include <libtrx/game/phase.h>
#include <libtrx/json.h>
#include <libtrx/log.h>
#include <libtrx/memory.h>
@ -526,13 +518,6 @@ static bool M_LoadScriptLevels(JSON_OBJECT *obj)
}
cur->level_file = Memory_DupStr(tmp_s);
tmp_s = JSON_ObjectGetString(jlvl_obj, "title", JSON_INVALID_STRING);
if (tmp_s == JSON_INVALID_STRING) {
LOG_ERROR("level %d: 'title' must be a string", level_num);
return false;
}
cur->level_title = Memory_DupStr(tmp_s);
tmp_s = JSON_ObjectGetString(jlvl_obj, "type", JSON_INVALID_STRING);
if (tmp_s == JSON_INVALID_STRING) {
LOG_ERROR("level %d: 'type' must be a string", level_num);
@ -1274,11 +1259,18 @@ const char *GameFlow_GetLevelFileName(int32_t level_num)
return g_GameFlow.levels[level_num].level_file;
}
const char *GameFlow_GetLevelTitle(int32_t level_num)
const char *GameFlow_GetLevelTitle(const int32_t level_num)
{
return g_GameFlow.levels[level_num].level_title;
}
void GameFlow_SetLevelTitle(const int32_t level_num, const char *const title)
{
Memory_FreePointer(&g_GameFlow.levels[level_num].level_title);
g_GameFlow.levels[level_num].level_title =
title != NULL ? Memory_DupStr(title) : NULL;
}
int32_t GameFlow_GetGymLevelNum(void)
{
return g_GameFlow.gym_level_num;

View file

@ -2,6 +2,7 @@
#include "global/types.h"
#include <libtrx/game/gameflow.h>
#include <libtrx/game/inventory_ring/types.h>
#include <stdint.h>

View file

@ -36,7 +36,6 @@
#include <string.h>
#define GAMEBUF_MEM_CAP 0x8000000
#define LEVEL_TITLE_SIZE 25
#define TIMESTAMP_SIZE 20
typedef enum {

View file

@ -85,7 +85,7 @@ static const char *M_GetDialogTitle(UI_STATS_DIALOG *const self)
{
switch (self->args.mode) {
case UI_STATS_DIALOG_MODE_LEVEL:
return g_GameFlow.levels[self->args.level_num].level_title;
return GameFlow_GetLevelTitle(self->args.level_num);
case UI_STATS_DIALOG_MODE_FINAL:
return self->level_type == GFL_BONUS ? GS(STATS_BONUS_STATISTICS)

View file

@ -2,10 +2,8 @@
#include "decomp/decomp.h"
#include "decomp/savegame.h"
#include "decomp/stats.h"
#include "game/demo.h"
#include "game/fmv.h"
#include "game/game.h"
#include "game/gun/gun.h"
#include "game/inventory.h"
#include "game/inventory_ring.h"
@ -13,7 +11,6 @@
#include "game/objects/vars.h"
#include "game/overlay.h"
#include "game/phase.h"
#include "gameflow/gameflow_new.h"
#include "global/vars.h"
#include <libtrx/benchmark.h>
@ -24,8 +21,6 @@
#include <libtrx/memory.h>
#include <libtrx/virtual_file.h>
#include <stdio.h>
#define GF_CURRENT_VERSION 3
static int16_t m_LevelOffsets[200] = {};
@ -271,8 +266,8 @@ bool GF_LoadFromFile(const char *const file_name)
g_GameFlow.level_complete_track = VFile_ReadU8(file);
VFile_Skip(file, 4);
M_ReadStringTable(
file, g_GameFlow.num_levels, &g_GF_LevelNames, &g_GF_LevelNamesBuf);
g_GF_LevelNames = Memory_Alloc(sizeof(char *) * g_GameFlow.num_levels);
M_ReadStringTable(file, g_GameFlow.num_levels, NULL, NULL);
// picture filename strings
M_ReadStringTable(file, g_GameFlow.num_pictures, NULL, NULL);
M_ReadStringTable(

View file

@ -1,8 +1,9 @@
#include "game/gameflow/gameflow_new.h"
#include "game/game_string.h"
#include "global/vars.h"
#include <libtrx/memory.h>
GAME_FLOW_NEW g_GameFlowNew;
GAME_INFO g_GameInfo;
@ -21,11 +22,17 @@ const char *GameFlow_GetLevelFileName(int32_t level_num)
return g_GF_LevelFileNames[level_num];
}
const char *GameFlow_GetLevelTitle(int32_t level_num)
const char *GameFlow_GetLevelTitle(const int32_t level_num)
{
return g_GF_LevelNames[level_num];
}
void GameFlow_SetLevelTitle(const int32_t level_num, const char *const title)
{
Memory_FreePointer(&g_GF_LevelNames[level_num]);
g_GF_LevelNames[level_num] = title != NULL ? Memory_DupStr(title) : NULL;
}
int32_t GameFlow_GetGymLevelNum(void)
{
return g_GameFlow.gym_enabled ? LV_GYM : -1;

View file

@ -1,6 +1,4 @@
#pragma once
#include <stdint.h>
bool GF_N_Load(const char *path);
void GF_N_Shutdown(void);

View file

@ -334,7 +334,6 @@ char **g_GF_TitleFileNames = NULL;
char *g_GF_CutsceneFileNamesBuf = NULL;
char *g_GF_FMVFilenamesBuf = NULL;
char *g_GF_LevelFileNamesBuf = NULL;
char *g_GF_LevelNamesBuf = NULL;
char *g_GF_TitleFileNamesBuf = NULL;
bool g_GF_DeadlyWater = false;

View file

@ -143,7 +143,6 @@ extern char **g_GF_TitleFileNames;
extern char *g_GF_CutsceneFileNamesBuf;
extern char *g_GF_FMVFilenamesBuf;
extern char *g_GF_LevelFileNamesBuf;
extern char *g_GF_LevelNamesBuf;
extern char *g_GF_TitleFileNamesBuf;
extern bool g_GF_DeadlyWater;