From c8389f06e000fa3d3ff6d838b06d2482faf1b245 Mon Sep 17 00:00:00 2001 From: Luciano Ciccariello Date: Fri, 11 Oct 2024 17:31:10 +0100 Subject: [PATCH] Add cmdline arguments --- CMakeLists.txt | 3 +- src/pc/main.c | 156 ++++++++++++++++++++++++++++++++++++++++++ src/pc/null.c | 16 ----- src/pc/pc.c | 9 --- src/pc/pc.h | 18 ++++- src/pc/psxsdk/libcd.c | 3 +- src/pc/render_gl.c | 7 +- src/pc/render_soft.c | 7 +- src/pc/sdl2.c | 23 +------ src/pc/sim_pc.c | 31 +++++++-- src/pc/sotn.c | 11 ++- 11 files changed, 224 insertions(+), 60 deletions(-) create mode 100644 src/pc/main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f578ef599..d8561afcc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.10) -project(Sound) +project(sotn) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -30,6 +30,7 @@ endif() find_package(SDL2 REQUIRED) set(SOURCE_FILES_PC + src/pc/main.c src/pc/log.c src/pc/stubs.c src/pc/sotn.c diff --git a/src/pc/main.c b/src/pc/main.c new file mode 100644 index 0000000000..1110ba98fa --- /dev/null +++ b/src/pc/main.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +#include +#include "pc.h" +#include +#include +#include +#include +#include +#include + +static const char* allowed_stages[] = { + "no0", "no1", "lib", "cat", "no2", "chi", + "dai", "np3", "cen", "no4", "are", "top", + "nz0", "nz1", "wrp", "no1_alt", "no0_alt", "", + "dre", "nz0_demo", "nz1_demo", "lib_demo", "bo7", "mar", + "bo6", "bo5", "bo4", "bo3", "bo2", "bo1", + "bo0", "st0", "rno0", "rno1", "rlib", "rcat", + "rno2", "rchi", "rdai", "rno3", "rcen", "rno4", + "rare", "rtop", "rnz0", "rnz1", "rwrp", "", + "", "", "", "", "", "rnz1_demo", + "rbo8", "rbo7", "rbo6", "rbo5", "rbo4", "rbo3", + "rbo2", "rbo1", "rbo0", "", "mad", "no3", + "iwa_load", "iga_load", "hagi_load", "sel", "te1", "te2", + "te3", "te4", "te5", "top_alt"}; +static const char* allowed_players[] = {"alu", "ric", "mar"}; +static const char* allowed_tests[] = {"sndlib"}; +#define PARSE_PARAM(param, allowed) parseStrParam(param, allowed, LEN(allowed)) +static int parseIntParam(const char* param) { + long i = strtol(param, NULL, 10); + if (i != LONG_MIN && i != LONG_MAX && i >= 0) { + return (int)i; + } + return -1; +} +static int parseStrParam( + const char* param, const char* allowedValues[], int n) { + long i; + if (isdigit(param[0])) { + i = strtol(param, NULL, 10); + if (i != LONG_MIN && i != LONG_MAX && i >= 0) { + return (int)i; + } + } else { + for (i = 0; i < n; i++) { + if (allowedValues[i][0] == '\0') { + continue; + } + if (!strcmp(param, allowedValues[i])) { + return i; + } + } + } + return -1; +} +static void printHelp(void) { + printf("Usage: ./sotn [OPTIONS]\n"); + printf("Options:\n"); + printf(" --disk file name of the second track\n"); + printf(" --stage stage name or ID (e.g., nz0)\n"); + printf(" --player player name or ID (e.g. ric)\n"); + printf(" --scale game resolution integer scale (default 2)\n"); + printf(" --test run automated tests\n"); + printf(" sndlib test sound library\n"); + printf(" --help show this help message\n"); +} +static void printAllowedParams(const char* allowedValues[], int n) { + int i; + printf("allowed params are: "); + for (i = 0; i < n - 1; i++) { + if (allowedValues[i][0] == '\0') { + continue; + } + printf("%s, ", allowedValues[i]); + } + printf("%s\n", allowedValues[i - 1]); +} +static bool parseArgs( + struct InitGameParams* outParams, int argc, char* argv[]) { + assert(!!outParams); + outParams->diskPath = NULL; + outParams->testMode = NO_TEST; + outParams->stage = -1; + outParams->player = -1; + outParams->scale = 2; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--help") == 0) { + printHelp(); + exit(0); + } + if (strcmp(argv[i], "--disk") == 0 && i + 1 < argc) { + outParams->diskPath = argv[++i]; + } else if (strcmp(argv[i], "--stage") == 0 && i + 1 < argc) { + outParams->stage = PARSE_PARAM(argv[++i], allowed_stages); + if (outParams->stage < 0) { + printf("stage '%s' is invalid or not recognized\n", argv[i]); + printAllowedParams(allowed_stages, LEN(allowed_stages)); + return false; + } + } else if (strcmp(argv[i], "--player") == 0 && i + 1 < argc) { + outParams->player = PARSE_PARAM(argv[++i], allowed_players); + if (outParams->player < 0) { + printf("player '%s' is invalid or not recognized\n", argv[i]); + printAllowedParams(allowed_players, LEN(allowed_players)); + return false; + } + } else if (strcmp(argv[i], "--scale") == 0 && i + 1 < argc) { + outParams->scale = parseIntParam(argv[++i]); + if (outParams->scale < 1 || outParams->scale > 16) { + printf("invalid resolution scale %s\n", argv[i]); + return false; + } + } else if (strcmp(argv[i], "--test") == 0 && i + 1 < argc) { + outParams->testMode = PARSE_PARAM(argv[++i], allowed_tests) + 1; + if (outParams->testMode < 0) { + printf("test '%s' is invalid or not recognized\n", argv[i]); + printAllowedParams(allowed_tests, LEN(allowed_tests)); + return false; + } + } else { + printf("argument %s not recognized", argv[i]); + return false; + } + } + return true; +} + +static void testSndLib(void) { +#ifdef WANT_LIBSND_LLE + run_tests(); + exit(0); +#else + printf("this test is only available for LLE builds\n"); + exit(-1); +#endif +} + +int main(int argc, char* argv[]) { + struct InitGameParams params; + if (!parseArgs(¶ms, argc, argv)) { + printHelp(); + return -1; + } + switch (params.testMode) { + case NO_TEST: + break; + case TEST_SNDLIB: + testSndLib(); + break; + } + if (!InitGame(¶ms)) { + return -1; + } + MainGame(); + ResetGame(); +} diff --git a/src/pc/null.c b/src/pc/null.c index 2762642381..b202bea7c6 100644 --- a/src/pc/null.c +++ b/src/pc/null.c @@ -33,20 +33,4 @@ DRAWENV* MyPutDrawEnv(DRAWENV* env) {} void MyDrawOTag(OT_TYPE* p) {} -int main(int argc, char* argv[]) { - const char* filename; - - if (argc < 2) { - filename = "disks/sotn.us.bin"; - } else { - filename = argv[1]; - } - OpenCd(filename); - - if (InitGame()) { - MainGame(); - } - ResetGame(); -} - int MyMoveImage(RECT* rect, int x, int y) {} diff --git a/src/pc/pc.c b/src/pc/pc.c index 2179c29850..33919ddc9b 100644 --- a/src/pc/pc.c +++ b/src/pc/pc.c @@ -9,15 +9,6 @@ bool g_IsQuitRequested; // controls whenever MainGame should quit bool g_TimedExit = false; // should we exit after some time? int g_TimeLimit = 0; // number of frames before exiting -FILE* cd_fp = NULL; -void OpenCd(char* filename) { - cd_fp = fopen(filename, "rb"); - - if (!cd_fp) { - DEBUGF("Couldn't open CD.\n"); - } -} - int CdReading(); void ExecCd(); void MyAudioCallback(void* data, u8* buffer, int length) { diff --git a/src/pc/pc.h b/src/pc/pc.h index fb6259cd7f..9b43646398 100644 --- a/src/pc/pc.h +++ b/src/pc/pc.h @@ -15,12 +15,23 @@ #define DISP_WIDTH 256 #define DISP_HEIGHT 256 -#define SCREEN_SCALE 4 #define VRAM_W 1024 #define VRAM_H 512 #define VRAM_STRIDE 2048 +enum TestMode { + NO_TEST, + TEST_SNDLIB, +}; +struct InitGameParams { + const char* diskPath; + enum TestMode testMode; + int stage; + int player; + int scale; +}; + struct FileOpenRead { const char* filename; FILE* file; @@ -42,6 +53,11 @@ typedef struct FileUseContent { void* param; } FileLoad; +extern struct InitGameParams g_GameParams; +bool InitGame(struct InitGameParams* params); +void MainGame(void); +void ResetGame(void); + bool FileOpenRead( bool (*cb)(const struct FileOpenRead*), const char* filename, void* param); int FileReadToBuf(const char* filename, void* dst, int offset, size_t maxlen); diff --git a/src/pc/psxsdk/libcd.c b/src/pc/psxsdk/libcd.c index 8e50df9666..5f6795267c 100644 --- a/src/pc/psxsdk/libcd.c +++ b/src/pc/psxsdk/libcd.c @@ -58,7 +58,8 @@ int CdControl(u_char com, u_char* param, u_char* result) { CdlLOC* pos; if (!cd_fp) { - DEBUGF("Cd not open.\n"); + WARNF("Cd not open.\n"); + return 1; } switch (com) { diff --git a/src/pc/render_gl.c b/src/pc/render_gl.c index 21b0d8d186..ab4b9e367f 100644 --- a/src/pc/render_gl.c +++ b/src/pc/render_gl.c @@ -132,6 +132,7 @@ void ShowVram4bpp(void) { SDL_DestroyTexture(t); } +extern struct InitGameParams g_GameParams; int GlDrawSync(int mode) { switch (g_DebugSdl) { case DEBUG_SDL_SHOW_VRAM_16bpp: @@ -146,7 +147,7 @@ int GlDrawSync(int mode) { } SDL_RenderPresent(g_Renderer); - SDL_RenderSetScale(g_Renderer, SCREEN_SCALE, SCREEN_SCALE); + SDL_RenderSetScale(g_Renderer, g_GameParams.scale, g_GameParams.scale); // SDL event handling SDL_Event event; @@ -168,8 +169,8 @@ int GlDrawSync(int mode) { } DISPENV* GlPutDispEnv(DISPENV* env) { - int w = env->disp.w * SCREEN_SCALE; - int h = env->disp.h * SCREEN_SCALE; + int w = env->disp.w * g_GameParams.scale; + int h = env->disp.h * g_GameParams.scale; if (g_WndWidth == w && g_WndHeight == h) { return env; } diff --git a/src/pc/render_soft.c b/src/pc/render_soft.c index 000ada4034..c58b190da8 100644 --- a/src/pc/render_soft.c +++ b/src/pc/render_soft.c @@ -65,11 +65,12 @@ void CopyVram(void) { SDL_DestroyTexture(t); } +extern struct InitGameParams g_GameParams; int SoftDrawSync(int mode) { CopyVram(); SDL_RenderPresent(g_Renderer); - SDL_RenderSetScale(g_Renderer, SCREEN_SCALE, SCREEN_SCALE); + SDL_RenderSetScale(g_Renderer, g_GameParams.scale, g_GameParams.scale); // SDL event handling SDL_Event event; @@ -87,8 +88,8 @@ int SoftDrawSync(int mode) { } DISPENV* SoftPutDispEnv(DISPENV* env) { - int w = env->disp.w * SCREEN_SCALE; - int h = env->disp.h * SCREEN_SCALE; + int w = env->disp.w * g_GameParams.scale; + int h = env->disp.h * g_GameParams.scale; if (g_WndWidth == w && g_WndHeight == h) { return env; } diff --git a/src/pc/sdl2.c b/src/pc/sdl2.c index 5518fbd6cf..a91ba4c09b 100644 --- a/src/pc/sdl2.c +++ b/src/pc/sdl2.c @@ -13,6 +13,7 @@ #include "sdl_defs.h" #include "sdl2_macros.h" +extern struct InitGameParams g_GameParams; extern bool g_IsQuitRequested; extern u16 g_RawVram[VRAM_W * VRAM_H]; SDL_Window* g_Window = NULL; @@ -40,7 +41,7 @@ bool InitPlatform() { g_Window = SDL_CreateWindow( "SOTN", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - DISP_WIDTH * SCREEN_SCALE, DISP_HEIGHT * SCREEN_SCALE, + DISP_WIDTH * g_GameParams.scale, DISP_HEIGHT * g_GameParams.scale, SDL_WINDOW_SHOWN); if (!g_Window) { ERRORF("SDL_CreateWindow: %s", SDL_GetError()); @@ -227,23 +228,3 @@ u_long MyPadRead(int id) { return pressed; } - -int main(int argc, char* argv[]) { - const char* filename; - - if (argc < 2) { - filename = "disks/sotn.us.bin"; - } else if (argc == 2 && !strcmp(argv[1], "test")) { -#ifdef WANT_LIBSND_LLE - run_tests(); -#endif - } else { - filename = argv[1]; - } - OpenCd(filename); - - if (InitGame()) { - MainGame(); - } - ResetGame(); -} diff --git a/src/pc/sim_pc.c b/src/pc/sim_pc.c index f675b84ea6..e3dbf742fa 100644 --- a/src/pc/sim_pc.c +++ b/src/pc/sim_pc.c @@ -202,10 +202,6 @@ void InitPlayerArc(const struct FileUseContent* file); void InitPlayerRic(void); void func_80131EBC(const char* str, s16 arg1); s32 LoadFileSimToMem(SimKind kind) { - char pad[0x20]; - s32 i; - u32* pDst; - u32* pSrc; u16* clutAddr; switch (kind) { @@ -355,6 +351,23 @@ int readToBuf(const char* filename, char* dest) { return 0; } +static bool isFirstBoot() { + // when needing to load stage and player + if (g_StageId == STAGE_SEL && g_GameState == Game_Init) { + return true; + } + + // when needing to load the default weapons + if (g_GameState == Game_NowLoading && g_GameStep == 11) { + return true; + } + if (g_GameState == Game_NowLoading && g_GameStep == 13) { + return true; + } + + return false; +} + s32 LoadFileSim(s32 fileId, SimFileType type) { char smolbuf[48]; char buf[128]; @@ -399,6 +412,16 @@ s32 LoadFileSim(s32 fileId, SimFileType type) { } break; case SimFileType_StagePrg: + if (isFirstBoot()) { + if (g_GameParams.player >= 0) { + g_PlayableCharacter = g_GameParams.player; + } + if (g_GameParams.stage >= 0) { + g_StageId = g_GameParams.stage; + SetGameState(Game_NowLoading); + g_GameStep = 1; + } + } switch (g_StageId) { case STAGE_SEL: InitStageSEL(&g_api.o); diff --git a/src/pc/sotn.c b/src/pc/sotn.c index 48453927af..d4fe36f21a 100644 --- a/src/pc/sotn.c +++ b/src/pc/sotn.c @@ -127,7 +127,16 @@ static bool InitBlueprintData(struct FileAsString* file); s32 func_800EDB58(u8 primType, s32 count); -bool InitGame(void) { +FILE* cd_fp = NULL; +struct InitGameParams g_GameParams; +bool InitGame(struct InitGameParams* params) { + g_GameParams = *params; + if (params->diskPath) { + cd_fp = fopen(params->diskPath, "rb"); + if (!cd_fp) { + WARNF("couldn't open CD at '%s'", params->diskPath); + } + } if (!InitPlatform()) { return false; }