shell: improve support for CLI options

- Adds documentation
- Adds a --help switch
- Tidies short/long option form conventions
This commit is contained in:
Marcin Kurczewski 2025-04-26 09:47:36 +02:00
parent 890c7f76bb
commit 6911640dad
No known key found for this signature in database
GPG key ID: CC65E6FD28CAE42A
9 changed files with 94 additions and 22 deletions

20
docs/COMMAND_LINE.md Normal file
View file

@ -0,0 +1,20 @@
# Command line options
Currently the following command line interface options are available:
`-g/--gold` (legacy: `-gold`):
Runs the Unfinished Business or the Golden Mask expansion pack, depending
on the game.
`--demo-pc` (TR1X only, legacy: `-demo_pc`):
Runs the PC demo level.
`-l/--level <path>`:
Runs the game immediately launching it into the specified level.
The path should be absolute. Internally, this option uses
`TR*X_gameflow_level.json5` as a template instructing it how to run the
game.
`-s/--save <num>`:
Runs the game immediately loading a specific save slot. The first save
starts at `num=1`. This option can be combined with `-l/--level`.

View file

@ -6,6 +6,8 @@
- added support for aspect ratio-specific images (#1840)
- added an option to wraparound when scrolling UI dialogs, such as save/load (#2834)
- changed the `draw_distance_fade` and `draw_distance_max` to `fog_start` and `fog_end`
- added aliases to CLI options (`-gold` becomes `-g/--gold`, `-demo_pc` becomes `--demo-pc`)
- added a `--help` CLI option (may not output anything on Windows machines  OS bug)
- changed `Select Detail` dialog title to `Graphic Options`
- changed the number of static mesh slots from 50 to 256 (#2734)
- changed the "enable EIDOS logo" option to disable the Core Design and Bink Video Codec FMVs as well; renamed to "enable legal" (#2741)

View file

@ -1,4 +1,6 @@
## [Unreleased](https://github.com/LostArtefacts/TRX/compare/tr2-1.0.1...develop) - ××××-××-××
- added aliases to CLI options (`-gold` becomes `-g/--gold`)
- added a `--help` CLI option (may not output anything on Windows machines  OS bug)
- changed the sound dialog appearance (repositioned, added text labels and arrows)
- fixed Lara voiding if she stops on a tile with a closing door, and the door isn't on a portal (#2848)
- fixed guns carried by enemies not being converted to ammo if Lara has picked up the same gun elsewhere in the same level (#2856)

View file

@ -21,13 +21,11 @@ int main(int argc, char *argv[])
Log_Init(log_path);
Memory_FreePointer(&log_path);
LOG_INFO("Game directory: %s", File_GetGameDirectory());
m_ArgCount = argc;
m_ArgStrings = (const char **)argv;
Shell_Setup();
Shell_Main();
Shell_Terminate(0);
return 0;
int32_t exit_code = Shell_Main();
Shell_Terminate(exit_code);
return exit_code;
}

View file

@ -12,7 +12,7 @@ extern void Shell_Shutdown(void);
extern SDL_Window *Shell_GetWindow(void);
void Shell_Setup(void);
extern void Shell_Main(void);
extern int32_t Shell_Main(void);
void Shell_Terminate(int32_t exit_code);
void Shell_ExitSystem(const char *message);
void Shell_ExitSystemFmt(const char *fmt, ...);

View file

@ -49,6 +49,7 @@ typedef struct {
int32_t thickness;
} LIGHTNING;
static bool m_Initialized = false;
static int32_t m_LightningCount = 0;
static LIGHTNING m_LightningTable[MAX_LIGHTNINGS];
static int32_t m_TextureMap[GFX_MAX_TEXTURES] = { GFX_NO_TEXTURE };
@ -385,6 +386,11 @@ static void M_DrawSprite(
bool Output_Init(void)
{
if (m_Initialized) {
return true;
}
m_Initialized = true;
for (int32_t i = 0; i < GFX_MAX_TEXTURES; i++) {
m_TextureMap[i] = GFX_NO_TEXTURE;
m_TextureSurfaces[i] = nullptr;
@ -406,6 +412,11 @@ bool Output_Init(void)
void Output_Shutdown(void)
{
if (!m_Initialized) {
return;
}
m_Initialized = false;
Output_Meshes_Shutdown();
Output_Sprites_Shutdown();
Output_Textures_Shutdown();

View file

@ -81,11 +81,22 @@ static SHELL_ARGS m_Args = {
static const char *m_CurrentGameFlowPath;
static void M_ParseArgs(SHELL_ARGS *out_args);
static void M_ShowHelp(void);
static bool M_ParseArgs(SHELL_ARGS *out_args);
static void M_LoadConfig(void);
static void M_HandleConfigChange(const EVENT *event, void *data);
static void M_ParseArgs(SHELL_ARGS *const out_args)
static void M_ShowHelp(void)
{
puts("Currently available options:");
puts("");
puts("-g/--gold: launch The Unfinished Business expansion pack.");
puts(" --demo-pc: launch the PC demo level file.");
puts("-l/--level <PATH>: launch a specific level file.");
puts("-s/--save <NUM>: launch from a specific save slot (starts at 1).");
}
static bool M_ParseArgs(SHELL_ARGS *const out_args)
{
const char **args = nullptr;
int32_t arg_count = 0;
@ -94,10 +105,15 @@ static void M_ParseArgs(SHELL_ARGS *const out_args)
out_args->mod = M_MOD_OG;
for (int32_t i = 0; i < arg_count; i++) {
if (!strcmp(args[i], "-gold")) {
if (!strcmp(args[i], "-h") || !strcmp(args[i], "--help")) {
M_ShowHelp();
return false;
}
if (!strcmp(args[i], "-g") || !strcmp(args[i], "--gold")
|| !strcmp(args[i], "-gold")) {
out_args->mod = M_MOD_UB;
}
if (!strcmp(args[i], "-demo_pc")) {
if (!strcmp(args[i], "--demo-pc") || !strcmp(args[i], "-demo_pc")) {
out_args->mod = M_MOD_DEMO_PC;
}
if ((!strcmp(args[i], "-l") || !strcmp(args[i], "--level"))
@ -112,6 +128,7 @@ static void M_ParseArgs(SHELL_ARGS *const out_args)
}
}
}
return true;
}
static void M_HandleConfigChange(const EVENT *const event, void *const data)
@ -174,9 +191,11 @@ const char *Shell_GetGameFlowPath(void)
return m_ModPaths[m_Args.mod].game_flow_path;
}
void Shell_Main(void)
int32_t Shell_Main(void)
{
M_ParseArgs(&m_Args);
if (!M_ParseArgs(&m_Args)) {
return 0;
}
GameString_Init();
EnumMap_Init();
@ -200,7 +219,7 @@ void Shell_Main(void)
if (!Output_Init()) {
Shell_ExitSystem("Could not initialise video system");
return;
return 1;
}
Screen_Init();
@ -312,6 +331,7 @@ void Shell_Main(void)
if (m_Args.level_to_play != nullptr) {
Memory_FreePointer(&g_GameFlow.level_tables[GFLT_MAIN].levels[0].path);
}
return 0;
}
void Shell_ProcessInput(void)

View file

@ -45,7 +45,6 @@ static RENDERER *M_GetRenderer(void)
} else if (g_Config.rendering.render_mode == RM_HARDWARE) {
r = &m_Renderer_HW;
}
ASSERT(r != nullptr);
return r;
}
@ -124,7 +123,6 @@ void Render_Init(void)
void Render_Shutdown(void)
{
LOG_DEBUG("");
RENDERER *const r = M_GetRenderer();
if (r != nullptr) {
r->Close(r);

View file

@ -99,7 +99,8 @@ static void M_HandleQuit(void);
static void M_ConfigureOpenGL(void);
static bool M_CreateGameWindow(void);
static void M_ParseArgs(SHELL_ARGS *out_args);
static void M_ShowHelp(void);
static bool M_ParseArgs(SHELL_ARGS *out_args);
static void M_LoadConfig(void);
static void M_HandleConfigChange(const EVENT *event, void *data);
@ -342,7 +343,16 @@ static bool M_CreateGameWindow(void)
return true;
}
static void M_ParseArgs(SHELL_ARGS *const out_args)
static void M_ShowHelp(void)
{
puts("Currently available options:");
puts("");
puts("-g/--gold: launch The Golden Mask expansion pack.");
puts("-l/--level <PATH>: launch a specific level file.");
puts("-s/--save <NUM>: launch from a specific save slot (starts at 1).");
}
static bool M_ParseArgs(SHELL_ARGS *const out_args)
{
const char **args = nullptr;
int32_t arg_count = 0;
@ -351,7 +361,12 @@ static void M_ParseArgs(SHELL_ARGS *const out_args)
out_args->mod = M_MOD_OG;
for (int32_t i = 0; i < arg_count; i++) {
if (!strcmp(args[i], "-gold")) {
if (!strcmp(args[i], "-h") || !strcmp(args[i], "--help")) {
M_ShowHelp();
return false;
}
if (!strcmp(args[i], "-g") || !strcmp(args[i], "--gold")
|| !strcmp(args[i], "-gold")) {
out_args->mod = M_MOD_GM;
}
if ((!strcmp(args[i], "-l") || !strcmp(args[i], "--level"))
@ -366,6 +381,7 @@ static void M_ParseArgs(SHELL_ARGS *const out_args)
}
}
}
return true;
}
static void M_LoadConfig(void)
@ -434,9 +450,13 @@ static void M_HandleConfigChange(const EVENT *const event, void *const data)
}
// TODO: refactor the hell out of me
void Shell_Main(void)
int32_t Shell_Main(void)
{
M_ParseArgs(&m_Args);
if (!M_ParseArgs(&m_Args)) {
return 0;
}
LOG_INFO("Game directory: %s", File_GetGameDirectory());
if (m_Args.mod == M_MOD_GM) {
Object_Get(O_MONK_3)->setup_func = Monk3_Setup;
@ -465,7 +485,7 @@ void Shell_Main(void)
if (!M_CreateGameWindow()) {
Shell_ExitSystem("Failed to create game window");
return;
return 1;
}
Random_Seed();
@ -556,7 +576,7 @@ void Shell_Main(void)
if (gf_cmd.action == GF_NOOP
|| gf_cmd.action == GF_EXIT_TO_TITLE) {
Shell_ExitSystem("Title disabled & no replacement");
return;
return 1;
}
} else {
gf_cmd = GF_RunTitle();
@ -578,6 +598,7 @@ void Shell_Main(void)
if (m_Args.level_to_play != nullptr) {
Memory_FreePointer(&g_GameFlow.level_tables[GFLT_MAIN].levels[0].path);
}
return 0;
}
void Shell_Shutdown(void)