From e65f46d081b83ded445248efbf8ea9304a2760f6 Mon Sep 17 00:00:00 2001 From: peerchemist Date: Tue, 18 Mar 2025 08:47:29 +0100 Subject: [PATCH 01/34] Update c-cpp.yml It hardly makes sense to use 32bit binary for flatpak. --- .github/workflows/c-cpp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 6ae34ca94..94989b5ba 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -266,7 +266,7 @@ jobs: build-flatpak-bundle: name: "Build flatpak bundle" runs-on: ubuntu-latest - needs: [build-i686-linux, build-x86_64-linux] + needs: [build-x86_64-linux] container: image: bilelmoussaoui/flatpak-github-actions:freedesktop-23.08 options: --privileged @@ -274,7 +274,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: - name: pd-i686-linux + name: pd-x86_64-linux path: dist/linux/bin/ - uses: flatpak/flatpak-github-actions/flatpak-builder@v6 From 6c29e7ecc817689ebcebf354c65ba3dda199d9ba Mon Sep 17 00:00:00 2001 From: peerchemist Date: Tue, 18 Mar 2025 09:00:38 +0100 Subject: [PATCH 02/34] Update io.github.fgsfdsfgs.perfect_dark.sh --- dist/linux/io.github.fgsfdsfgs.perfect_dark.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/linux/io.github.fgsfdsfgs.perfect_dark.sh b/dist/linux/io.github.fgsfdsfgs.perfect_dark.sh index 9269fbd70..719a7fbee 100644 --- a/dist/linux/io.github.fgsfdsfgs.perfect_dark.sh +++ b/dist/linux/io.github.fgsfdsfgs.perfect_dark.sh @@ -11,14 +11,14 @@ done # Default to pd as executable but switch to jpn/pal if the NTSC rom # is missing but JPN/PAL are present. # TODO: Other arch -executable="pd.i686" +executable="pd.x86_64" if [ -f ${XDG_DATA_HOME}/roms/pd.ntsc-final.z64 ] | \ [ -f ${XDG_DATA_HOME}/roms/pd.ntsc-1.0.z64 ]; then - executable="pd.i686" + executable="pd.x86_64" elif [ -f ${XDG_DATA_HOME}/roms/pd.jpn-final.z64 ]; then - executable="pd.jpn.i686" + executable="pd.jpn.x" elif [ -f ${XDG_DATA_HOME}/roms/pd.pal-final.z64 ]; then - executable="pd.pal.i686" + executable="pd.pal.x86_64" fi # If first parameter passed to this script is one of the pd executables, From 4019bd59cf6466a8bcea9ace9f946e6931dc29b4 Mon Sep 17 00:00:00 2001 From: peerchemist Date: Tue, 18 Mar 2025 09:13:23 +0100 Subject: [PATCH 03/34] Update io.github.fgsfdsfgs.perfect_dark.yaml --- .../io.github.fgsfdsfgs.perfect_dark.yaml | 62 ++----------------- 1 file changed, 6 insertions(+), 56 deletions(-) diff --git a/dist/linux/io.github.fgsfdsfgs.perfect_dark.yaml b/dist/linux/io.github.fgsfdsfgs.perfect_dark.yaml index c9d1d4f1d..213f146d3 100644 --- a/dist/linux/io.github.fgsfdsfgs.perfect_dark.yaml +++ b/dist/linux/io.github.fgsfdsfgs.perfect_dark.yaml @@ -1,13 +1,11 @@ app-id: io.github.fgsfdsfgs.perfect_dark runtime: org.freedesktop.Platform -runtime-version: &runtime-version '23.08' +runtime-version: "23.08" sdk: org.freedesktop.Sdk command: io.github.fgsfdsfgs.perfect_dark.sh finish-args: - # hardware 3D and controller access - --device=all - # X11 + XShm access - --share=ipc - --socket=x11 # Audio @@ -15,59 +13,16 @@ finish-args: # Enable network for multiplayer - --share=network -# Parameters for 32-bit extensions -x-gl-version: &gl-version '1.4' -x-gl-versions: &gl-versions 23.08;1.4 -x-gl-merge-dirs: &gl-merge-dirs vulkan/icd.d;glvnd/egl_vendor.d;egl/egl_external_platform.d;OpenCL/vendors;lib/dri;lib/d3d;lib/gbm;vulkan/explicit_layer.d;vulkan/implicit_layer.d - -add-extensions: - org.freedesktop.Platform.Compat.i386: - directory: lib/i386-linux-gnu - version: '23.08' - - org.freedesktop.Platform.GL32: - directory: lib/i386-linux-gnu/GL - version: *gl-version - versions: *gl-versions - subdirectories: true - no-autodownload: true - autodelete: false - add-ld-path: lib - merge-dirs: *gl-merge-dirs - download-if: active-gl-driver - enable-if: active-gl-driver - autoprune-unless: active-gl-driver - - org.freedesktop.Platform.GL32.Debug: - directory: lib/debug/lib/i386-linux-gnu/GL - version: *gl-version - versions: *gl-versions - subdirectories: true - no-autodownload: true - merge-dirs: *gl-merge-dirs - enable-if: active-gl-driver - autoprune-unless: active-gl-driver - - org.freedesktop.Platform.VAAPI.Intel.i386: - directory: lib/i386-linux-gnu/dri/intel-vaapi-driver - version: *runtime-version - versions: *runtime-version - autodelete: false - no-autodownload: true - add-ld-path: lib - download-if: have-intel-gpu - autoprune-unless: have-intel-gpu - modules: - name: perfect_dark buildsystem: simple sources: - type: file - path: bin/pd.i686 + path: bin/pd.x86_64 - type: file - path: bin/pd.jpn.i686 + path: bin/pd.jpn.x86_64 - type: file - path: bin/pd.pal.i686 + path: bin/pd.pal.x86_64 - type: file path: io.github.fgsfdsfgs.perfect_dark.sh - type: file @@ -78,13 +33,8 @@ modules: path: io.github.fgsfdsfgs.perfect_dark.desktop build-commands: [] post-install: - # create extension mountpoints - - mkdir -p /app/lib/i386-linux-gnu - - mkdir -p /app/lib/i386-linux-gnu/GL - - mkdir -p /app/lib/debug/lib/i386-linux-gnu/GL - - mkdir -p /app/lib/i386-linux-gnu/dri/intel-vaapi-driver - # port - - install -Dm 755 -t /app/bin/ pd* + # Install the binaries + - install -Dm 755 -t /app/bin/ pd.* - install -Dm 755 ${FLATPAK_ID}.sh /app/bin/${FLATPAK_ID}.sh - install -Dm 644 ${FLATPAK_ID}.desktop /app/share/applications/${FLATPAK_ID}.desktop - install -Dm 644 ${FLATPAK_ID}.metainfo.xml /app/share/metainfo/${FLATPAK_ID}.metainfo.xml From f5d851f7c2d6a491b866f75e087a88d93e6f53c8 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Mon, 24 Mar 2025 03:33:34 +0800 Subject: [PATCH 04/34] mpsetupfile (not 100% functional yet): load/save setup file, save new setups/groups, increased mp options/scenario data width --- .gitignore | 1 + port/include/mpsetups.h | 10 + port/src/mpsetups.c | 363 +++++++++++++++++++ src/game/filemgr.c | 11 - src/game/menuitem.c | 9 + src/game/mplayer/mplayer.c | 61 +--- src/game/mplayer/scenarios.c | 2 +- src/game/mplayer/scenarios/kingofthehill.inc | 4 +- src/game/mplayer/setup.c | 107 +++--- src/include/constants.h | 5 + src/include/data.h | 4 + src/include/game/mplayer/mplayer.h | 1 - src/include/types.h | 18 + 13 files changed, 484 insertions(+), 112 deletions(-) create mode 100644 port/include/mpsetups.h create mode 100644 port/src/mpsetups.c diff --git a/.gitignore b/.gitignore index 3d0bebd42..bb7c0cff9 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ tools/mkrom/mkrom /.vs CppProperties.json .idea +cmake-build-debug diff --git a/port/include/mpsetups.h b/port/include/mpsetups.h new file mode 100644 index 000000000..0341658a2 --- /dev/null +++ b/port/include/mpsetups.h @@ -0,0 +1,10 @@ +#ifndef _IN_MPSETUPS_H +#define _IN_MPSETUPS_H + +#include "types.h" + +s32 mpsetupLoadFile(); +void mpsetupLoadSetup(s32 index); +s32 mpsetupSaveFile(const char *name, u8 overwrite); + +#endif diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c new file mode 100644 index 000000000..8702d362e --- /dev/null +++ b/port/src/mpsetups.c @@ -0,0 +1,363 @@ +#include "types.h" +#include "constants.h" +#include "game/menu.h" +#include "game/savebuffer.h" +#include "game/mplayer/mplayer.h" +#include +#include "fs.h" +#include "system.h" + +/* +MP Setup File Format + # header + [version{1}] + [defaultsetup{1}] + [numsetups{1}] + [numgroups{1}] + # setups + [setup_1{64}] + ... + [setup_n{64}] + # groups + [offset_index_1{1}] + [name_1{1-32}] + ... + [offset_index_n{1}] + [name_n{1-32}] + */ + +extern struct menudialogdef g_MpSaveSetupNameMenuDialog; +struct menudialogdef g_MpGroupNameMenuDialog; + +#define MPSETUP_FILE "mpsetups.bin" +u8 filebuffer[sizeof(struct mpsetupfile)]; + +struct mpsetupfile g_MpSetupFile; +s16 g_MpCurrentSetup = -1; +s16 g_MpCurrentGroup = -1; + +#define BUF_READ(dst, buf, type) { dst = *(type*)((buf)); buf += sizeof(type); } +#define BUF_WRITE(src, buf, type) { *((type*)(buf)) = src; buf += sizeof(type); } +#define BUF_WRITEBLOCK(buf, src, size) { \ + memcpy(buf, src, size); \ + buf += size; } + +// #### Group List +MenuItemHandlerResult mpSelectGroupHandler(s32 operation, struct menuitem *item, union handlerdata *data); + +struct menuitem g_MpSetupGroupsDialogItems[] = { + { + MENUITEMTYPE_LIST, + 0, + MENUITEMFLAG_LABEL_CUSTOMCOLOUR, + 0x00000078, + 0x00000042, + mpSelectGroupHandler, + }, + { MENUITEMTYPE_END }, +}; + +struct menudialogdef g_MpSetupGroupsDialog = { + MENUDIALOGTYPE_DEFAULT, + (uintptr_t) "Groups", + g_MpSetupGroupsDialogItems, + NULL, + MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_CLOSEONSELECT, + NULL, +}; + +MenuItemHandlerResult mpSelectGroupHandler(s32 operation, struct menuitem *item, union handlerdata *data) +{ + switch (operation) { + case MENUOP_GETCOLOUR: { + u8 disabled = data->list.value == g_MpSetupFile.numgroups && g_MpSetupFile.numsetups == 0; + u32 colour = data->list.unk04; + data->list.unk04 = disabled ? 0xff333300 | (colour & 0xff) : colour; + } + case MENUOP_GETOPTIONCOUNT: + data->list.value = g_MpSetupFile.numgroups + 1; + break; + case MENUOP_GETOPTIONTEXT: + if (data->list.value == g_MpSetupFile.numgroups) { + return (uintptr_t) "[New Group]\n"; + } + return (uintptr_t) g_MpSetupFile.groups[data->list.value].name; + case MENUOP_SET: + { + u8 newgroupdisabled = data->list.value == g_MpSetupFile.numgroups && g_MpSetupFile.numsetups == 0; + if (newgroupdisabled) { + return 0; + } + + menuPopDialog(); + if (data->list.value == g_MpSetupFile.numgroups) { + menuPushDialog(&g_MpGroupNameMenuDialog); + } + else { + g_MpCurrentGroup = data->list.value; + menuPushDialog(&g_MpSaveSetupNameMenuDialog); + } + } + case MENUOP_GETSELECTEDINDEX: + data->list.value = 0xfffff; + break; + } + + return 0; +} + +static void createGroup(char *name) +{ + g_MpCurrentGroup = g_MpSetupFile.numgroups++; + struct setupgroup *group = &g_MpSetupFile.groups[g_MpCurrentGroup]; + strcpy(group->name, name); + group->offset_index = g_MpSetupFile.numsetups; +} + +// #### Group name dialog +MenuItemHandlerResult menuhandlerMpSetupGroupName(s32 operation, struct menuitem *item, union handlerdata *data) +{ + char *name = data->keyboard.string; + struct setupgroup *group = &g_MpSetupFile.groups[g_MpSetupFile.numgroups]; + + switch (operation) { + case MENUOP_GETTEXT: + strcpy(name, group->name); + break; + case MENUOP_SETTEXT: + strcpy(group->name, name); + break; + case MENUOP_SET: + createGroup(name); + menuPushDialog(&g_MpSaveSetupNameMenuDialog); + break; + } + + return 0; +} + +struct menuitem g_MpGroupNameMenuItems[] = { +#if VERSION != VERSION_JPN_FINAL + { + MENUITEMTYPE_LABEL, + 0, + MENUITEMFLAG_LESSLEFTPADDING | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t) "Enter the group name:\n", + 0, + NULL, + }, +#endif + { + MENUITEMTYPE_KEYBOARD, + 0, + 0, + 0, + 0, + menuhandlerMpSetupGroupName, + }, + { MENUITEMTYPE_END }, +}; + +struct menudialogdef g_MpGroupNameMenuDialog = { + MENUDIALOGTYPE_DEFAULT, + (uintptr_t) "Group Name\n", + g_MpGroupNameMenuItems, + NULL, + MENUDIALOGFLAG_LITERAL_TEXT, + NULL, +}; + + +static size_t readStr(char *dst, char *src) +{ + char *start = dst; + while (*src) { + *dst = *src; + dst++; + src++; + } + *dst = '\0'; + dst++; + return dst - start; +} + +static void mpsetupfileRead(struct mpsetupfile *setupfile, u8 *buffer) +{ + BUF_READ(setupfile->version, buffer, u8); + BUF_READ(setupfile->defaultsetup, buffer, u8); + BUF_READ(setupfile->numsetups, buffer, u8); + BUF_READ(setupfile->numgroups, buffer, u8); + + for (int i = 0; i < setupfile->numsetups; ++i) { + memcpy(setupfile->setups[i].bytes, buffer, MPSETUP_BLOCKSIZE); + buffer += MPSETUP_BLOCKSIZE; + } + + for (int i = 0; i < setupfile->numgroups; ++i) { + struct setupgroup *group = &setupfile->groups[i]; + BUF_READ(group->offset_index, buffer, u8); + buffer += readStr(group->name, buffer); + } +} + +void mpsetupfileWrite(u8 *buffer, struct mpsetupfile *setupfile, struct savebuffer *setup, u8 setupidx, u8 overwrite) +{ + BUF_WRITE(setupfile->version, buffer, u8); + BUF_WRITE(setupfile->defaultsetup, buffer, u8); + BUF_WRITE(setupfile->numsetups, buffer, u8); + BUF_WRITE(setupfile->numgroups, buffer, u8); + + for (int i = 0; i < setupfile->numsetups; ++i) { + if (i == setupidx) { + BUF_WRITEBLOCK(buffer, setup->bytes, MPSETUP_BLOCKSIZE); + + if (!overwrite) { + BUF_WRITEBLOCK(buffer, setupfile->setups[i].bytes, MPSETUP_BLOCKSIZE) + } + continue; + } + + BUF_WRITEBLOCK(buffer, setupfile->setups[i].bytes, MPSETUP_BLOCKSIZE) + } + + for (int i = 0; i < setupfile->numgroups; ++i) { + struct setupgroup *group = &setupfile->groups[i]; + BUF_WRITE(group->offset_index, buffer, u8); + buffer += readStr(buffer, group->name); + } +} + +static FILE *openMpSetupFile(u8 mode) { + FILE *f; + + if (fsFileSize(MPSETUP_FILE) < 0) { + // setup file doesn't exist: create one + f = fsFileOpenWrite(MPSETUP_FILE); + fsFileFree(f); + } + + if (mode == 'r') { + f = fsFileOpenRead(MPSETUP_FILE); + } + else if (mode == 'w') { + f = fsFileOpenWrite(MPSETUP_FILE); + } + else { + sysLogPrintf(LOG_ERROR, "openMpSetupFile: invalid file mode"); + return NULL; + } + + if (f == NULL) { + sysLogPrintf(LOG_NOTE, "Unable to open mp setup file"); + return NULL; + } + + return f; +} + +void zeroFileBuffer() +{ + memset(filebuffer, 0, sizeof(struct mpsetupfile)); +} + +s32 mpsetupLoadFile() +{ + FILE *f = openMpSetupFile('r'); + if (f == NULL) { + return -1; + } + + zeroFileBuffer(); + + fseek(f, 0L, SEEK_END); + size_t size = ftell(f); + fseek(f, 0, SEEK_SET); + + fread(filebuffer, 1, size, f); + + mpsetupfileRead(&g_MpSetupFile, filebuffer); + + if (g_MpSetupFile.defaultsetup != 0) { + g_MpCurrentSetup = g_MpSetupFile.defaultsetup; + } + + // setup a default group if there is none + if (g_MpSetupFile.numgroups == 0) { + g_MpSetupFile.numgroups++; + strcpy(g_MpSetupFile.groups[0].name, "Default\n"); + g_MpSetupFile.groups[0].offset_index = 0; + g_MpCurrentSetup = -1; + } + + fsFileFree(f); + + return 0; +} + +static s32 getNewSetupIndex() +{ + if (g_MpSetupFile.numsetups == 0) { + return 0; + } + + if (g_MpCurrentGroup == g_MpSetupFile.numgroups - 1) + return g_MpSetupFile.numsetups; + + return g_MpSetupFile.groups[g_MpCurrentGroup + 1].offset_index; +} + +static s32 getGroupIndex(s32 setupIndex) +{ + s32 index = 0; + struct setupgroup *groups = g_MpSetupFile.groups; + for (int i = 0; i < g_MpSetupFile.numgroups; ++i) { + if (setupIndex >= groups[i].offset_index) { + index = groups[i].offset_index; + } + } + + return index; +} + +s32 mpsetupSaveFile(const char *name, u8 overwrite) +{ + struct savebuffer setup; + + if (!overwrite) { + g_MpCurrentSetup = getNewSetupIndex(); + g_MpSetupFile.numsetups++; + + for (int i = g_MpCurrentGroup + 1; i < g_MpSetupFile.numgroups; ++i) { + g_MpSetupFile.groups[i].offset_index++; + } + } + + savebufferClear(&setup); + mpsetupfileSaveWad(&setup); + + zeroFileBuffer(); + mpsetupfileWrite(filebuffer, &g_MpSetupFile, &setup, g_MpCurrentSetup, overwrite); + + FILE *f = openMpSetupFile('w'); + if (f == NULL) { + return -1; + } + + fwrite(filebuffer, sizeof(struct mpsetupfile), 1, f); + fsFileFree(f); + + // reload the file to update in-memory structs + mpsetupLoadFile(); + return 0; +} + +void mpsetupLoadSetup(s32 index) +{ + struct savebuffer buffer; + savebufferClear(&buffer); + struct setupblock *block = &g_MpSetupFile.setups[index]; + memcpy(&buffer.bytes, block->bytes, MPSETUP_BLOCKSIZE); + mpsetupfileLoadWad(&buffer); + g_MpCurrentSetup = index; + g_MpCurrentGroup = getGroupIndex(index); +} diff --git a/src/game/filemgr.c b/src/game/filemgr.c index e82d7af15..9c87e071d 100644 --- a/src/game/filemgr.c +++ b/src/game/filemgr.c @@ -816,12 +816,6 @@ bool filemgrAttemptOperation(s32 device, bool closeonsuccess) g_Menus[g_MpPlayerNum].fm.fileid, g_Menus[g_MpPlayerNum].fm.deviceserial); break; - case FILEOP_SAVE_MPSETUP: - errnum = mpsetupfileSave(device, - g_Menus[g_MpPlayerNum].fm.fileid, - g_Menus[g_MpPlayerNum].fm.deviceserial); - showfilesaved = true; - break; case FILEOP_WRITE_GAME: case FILEOP_WRITE_MPSETUP: case FILEOP_WRITE_MPPLAYER: @@ -845,11 +839,6 @@ bool filemgrAttemptOperation(s32 device, bool closeonsuccess) g_Menus[g_MpPlayerNum].fm.fileid, g_Menus[g_MpPlayerNum].fm.deviceserial); break; - case FILEOP_LOAD_MPSETUP: - errnum = mpsetupfileLoad(device, - g_Menus[g_MpPlayerNum].fm.fileid, - g_Menus[g_MpPlayerNum].fm.deviceserial); - break; case FILEOP_READ_GAME: case FILEOP_READ_MPSETUP: case FILEOP_READ_MPPLAYER: diff --git a/src/game/menuitem.c b/src/game/menuitem.c index 72c24573a..18f80c1a6 100644 --- a/src/game/menuitem.c +++ b/src/game/menuitem.c @@ -614,6 +614,15 @@ Gfx *menuitemListRender(Gfx *gdl, struct menurendercontext *context) height = 0; } + // reuse the label color flag here + if (context->item->flags & MENUITEMFLAG_LABEL_CUSTOMCOLOUR) { + u32 savedunk04 = sp15c.list.unk04; + sp15c.list.unk04 = colour; + context->item->handler(MENUOP_GETCOLOUR, context->item, &sp15c); + colour = sp15c.list.unk04; + sp15c.list.unk04 = savedunk04; + } + gdl = textRenderProjected(gdl, &x, &y, text2, chars, font, colour, context->width - left + context->x, height, sp128, 0); // Consider a checkbox diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index b329f51db..3d9381522 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -28,6 +28,9 @@ #include "lib/lib_317f0.h" #include "data.h" #include "types.h" +#include "fs.h" +#include "system.h" +#include "mpsetups.h" // bss struct chrdata *g_MpAllChrPtrs[MAX_MPCHRS]; @@ -3924,7 +3927,7 @@ void mpsetupfileLoadWad(struct savebuffer *buffer) scenarioInit(); scenarioReadSave(buffer); - g_MpSetup.options = savebufferReadBits(buffer, 21); + g_MpSetup.options = savebufferReadBits(buffer, 32); g_MpSetup.chrslots &= 0x000f; for (i = 0; i < MAX_BOTS; i++) { @@ -3984,7 +3987,7 @@ void mpsetupfileSaveWad(struct savebuffer *buffer) scenarioWriteSave(buffer); - savebufferOr(buffer, g_MpSetup.options, 21); + savebufferOr(buffer, g_MpSetup.options, 32); for (i = 0; i < MAX_BOTS; i++) { savebufferOr(buffer, g_BotConfigsArray[i].type, 5); @@ -4039,60 +4042,6 @@ void mpsetupfileGetOverview(char *arg0, char *filename, u16 *numsims, u16 *stage *scenarionum = savebufferReadBits(&buffer, 3); } -s32 mpsetupfileSave(s32 device, s32 fileid, u16 deviceserial) -{ - s32 ret; - s32 newfileid; - struct savebuffer buffer; - - if (device >= 0) { - savebufferClear(&buffer); - mpsetupfileSaveWad(&buffer); - func0f0d54c4(&buffer); - - ret = pakSaveAtGuid(device, fileid, PAKFILETYPE_MPSETUP, buffer.bytes, &newfileid, 0); - var80075bd0[1] = true; - - if (ret == 0) { - g_MpSetup.fileguid.fileid = newfileid; - g_MpSetup.fileguid.deviceserial = deviceserial; - return 0; - } - - g_FilemgrLastPakError = ret; - return -1; - } - - return -1; -} - -s32 mpsetupfileLoad(s32 device, s32 fileid, u16 deviceserial) -{ - s32 ret; - struct savebuffer buffer; - - if (device >= 0) { - savebufferClear(&buffer); - ret = pakReadBodyAtGuid(device, fileid, buffer.bytes, 0); - - if (ret == 0) { - g_MpSetup.fileguid.fileid = fileid; - g_MpSetup.fileguid.deviceserial = deviceserial; - - mpsetupfileLoadWad(&buffer); - func0f0d54c4(&buffer); - - return 0; - } - - g_FilemgrLastPakError = ret; - - return -1; - } - - return -1; -} - void func0f18e558(void) { s32 i; diff --git a/src/game/mplayer/scenarios.c b/src/game/mplayer/scenarios.c index 60a4f85f5..f7a504382 100644 --- a/src/game/mplayer/scenarios.c +++ b/src/game/mplayer/scenarios.c @@ -438,7 +438,7 @@ void scenarioWriteSave(struct savebuffer *buffer) if (g_MpScenarios[g_MpSetup.scenario].writesavefunc) { g_MpScenarios[g_MpSetup.scenario].writesavefunc(buffer); } else { - savebufferOr(buffer, 0, 8); + savebufferOr(buffer, 0, 32); } } diff --git a/src/game/mplayer/scenarios/kingofthehill.inc b/src/game/mplayer/scenarios/kingofthehill.inc index 0160c7632..721550423 100644 --- a/src/game/mplayer/scenarios/kingofthehill.inc +++ b/src/game/mplayer/scenarios/kingofthehill.inc @@ -183,12 +183,12 @@ struct menudialogdef g_KohOptionsMenuDialog = { void kohReadSave(struct savebuffer *buffer) { - g_Vars.mphilltime = savebufferReadBits(buffer, 8); + g_Vars.mphilltime = savebufferReadBits(buffer, 32); } void kohWriteSave(struct savebuffer *buffer) { - savebufferOr(buffer, g_Vars.mphilltime, 8); + savebufferOr(buffer, g_Vars.mphilltime, 32); } void kohInit(void) diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index cae26d3c7..a94d32dd1 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -23,6 +23,8 @@ #include "data.h" #include "gbiex.h" #include "types.h" +#include "system.h" +#include "mpsetups.h" struct menuitem g_MpCharacterMenuItems[]; struct menudialogdef g_MpAddSimulantMenuDialog; @@ -31,6 +33,10 @@ struct menudialogdef g_MpChangeTeamNameMenuDialog; struct menudialogdef g_MpEditSimulantMenuDialog; struct menudialogdef g_MpSaveSetupNameMenuDialog; +extern struct menudialogdef g_MpSetupGroupsDialog; +extern struct menudialogdef g_FilemgrFileSavedMenuDialog; +extern struct menudialogdef g_FilemgrErrorMenuDialog; + #ifndef PLATFORM_N64 extern s32 g_MpWeaponSetNum; #endif @@ -454,6 +460,7 @@ MenuItemHandlerResult menuhandlerMpConfirmSaveChr(s32 operation, struct menuitem MenuItemHandlerResult menuhandlerMpSetupName(s32 operation, struct menuitem *item, union handlerdata *data) { char *name = data->keyboard.string; + s32 err; switch (operation) { case MENUOP_GETTEXT: @@ -463,7 +470,14 @@ MenuItemHandlerResult menuhandlerMpSetupName(s32 operation, struct menuitem *ite strcpy(g_MpSetup.name, name); break; case MENUOP_SET: - filemgrPushSelectLocationDialog(7, FILETYPE_MPSETUP); + err = mpsetupSaveFile(name, false); + if (!err) { + menuPushDialog(&g_FilemgrFileSavedMenuDialog); + } + else { +// menuPushDialog(&g_FilemgrErrorMenuDialog); + // TODO + } break; } @@ -474,7 +488,7 @@ MenuItemHandlerResult menuhandlerMpSaveSetupOverwrite(s32 operation, struct menu { if (operation == MENUOP_SET) { menuPopDialog(); - filemgrSaveOrLoad(&g_MpSetup.fileguid, FILEOP_SAVE_MPSETUP, 0); + mpsetupSaveFile(g_MpSetupFile.setups[g_MpCurrentSetup].bytes, true); } return 0; @@ -484,7 +498,7 @@ MenuItemHandlerResult menuhandlerMpSaveSetupCopy(s32 operation, struct menuitem { if (operation == MENUOP_SET) { menuPopDialog(); - menuPushDialog(&g_MpSaveSetupNameMenuDialog); + menuPushDialog(&g_MpSetupGroupsDialog); } return 0; @@ -1112,10 +1126,10 @@ struct menuitem g_MpSaveSetupExistsMenuItems[] = { NULL, }, { - MENUITEMTYPE_LABEL, + MENUITEMTYPE_SEPARATOR, + 0, + 0, 0, - MENUITEMFLAG_LESSLEFTPADDING | MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_SMALLFONT, - (uintptr_t)&filemgrMenuTextDeviceName, 0, NULL, }, @@ -1123,8 +1137,16 @@ struct menuitem g_MpSaveSetupExistsMenuItems[] = { { MENUITEMTYPE_LABEL, 0, - MENUITEMFLAG_LESSLEFTPADDING, - L_MPMENU_184, // "Do you want to save over your original game file?" + MENUITEMFLAG_LESSLEFTPADDING | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Save over your\noriginal setup?\n", + 0, + NULL, + }, + { + MENUITEMTYPE_SEPARATOR, + 0, + 0, + 0, 0, NULL, }, @@ -2232,17 +2254,15 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * switch (operation) { case MENUOP_GETOPTIONCOUNT: data->list.value = mpGetNumUnlockedPresets(); - - if (g_FileLists[1] != NULL) { - data->list.value += g_FileLists[1]->numfiles; - } + data->list.value += g_MpSetupFile.numsetups; break; case MENUOP_GETOPTIONTEXT: if (data->list.value < mpGetNumUnlockedPresets()) { return (uintptr_t)mpGetPresetNameBySlot(data->list.value); } - if (g_FileLists[1] != NULL) { - func0f0d564c(g_FileLists[1]->files[data->list.value - mpGetNumUnlockedPresets()].name, g_StringPointer, false); + if (g_MpSetupFile.numsetups > 0) { + struct setupblock *block = &g_MpSetupFile.setups[data->list.value - mpGetNumUnlockedPresets()]; + func0f0d564c(block->bytes, g_StringPointer, false); return (uintptr_t)g_StringPointer; } break; @@ -2251,14 +2271,10 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * if (data->list.value < mpGetNumUnlockedPresets()) { mp0f18dec4(data->list.value); - } else if (g_FileLists[1] != NULL) { - struct filelistfile *file = &g_FileLists[1]->files[data->list.value - mpGetNumUnlockedPresets()]; - struct fileguid guid; - - guid.fileid = file->fileid; - guid.deviceserial = file->deviceserial; - - filemgrSaveOrLoad(&guid, FILEOP_LOAD_MPSETUP, 0); + g_MpCurrentSetup = -1; + } + else { + mpsetupLoadSetup(data->list.value - mpGetNumUnlockedPresets()); } if (item->param == 1) { @@ -2273,19 +2289,14 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * data->list.value = 0xfffff; break; case MENUOP_GETOPTGROUPCOUNT: - data->list.value = 1; - - if (g_FileLists[1] != NULL) { - data->list.value += g_FileLists[1]->numdevices; - } + data->list.value = g_MpSetupFile.numgroups + 1; break; case MENUOP_GETOPTGROUPTEXT: if (data->list.value == 0) { return (uintptr_t)langGet(L_MPMENU_141); // "Presets" } - if (g_FileLists[1] != NULL) { - return (uintptr_t)filemgrGetDeviceNameOrStartIndex(1, operation, data->list.value - 1); - } + + return (uintptr_t)&g_MpSetupFile.groups[data->list.value - 1].name; break; case MENUOP_GETGROUPSTARTINDEX: if (data->list.value == 0) { @@ -2293,16 +2304,14 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * } else { data->list.groupstartindex = mpGetNumUnlockedPresets(); - if (g_FileLists[1] != NULL) { - data->list.groupstartindex += filemgrGetDeviceNameOrStartIndex(1, operation, data->list.value - 1); + if (g_MpSetupFile.numgroups > 0) { + data->list.groupstartindex += g_MpSetupFile.groups[data->list.value - 1].offset_index; } } break; case MENUOP_LISTITEMFOCUS: if (data->list.value < mpGetNumUnlockedPresets()) { g_Menus[g_MpPlayerNum].mpsetup.slotindex = 0xffff; - } else { - g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value - mpGetNumUnlockedPresets(); } break; } @@ -2630,6 +2639,22 @@ struct menuitem g_MpLoadSettingsMenuItems[] = { 0, NULL, }, + { + MENUITEMTYPE_SEPARATOR, + 0, + MENUITEMFLAG_00000002, + 0, + 0, + NULL, + }, + { + MENUITEMTYPE_LABEL, + 0, + MENUITEMFLAG_00000002 | MENUITEMFLAG_SELECTABLE_CENTRE, + L_MPMENU_414, // "Press the B Button to go back." + 0, + NULL, + }, { MENUITEMTYPE_END }, }; @@ -5013,13 +5038,10 @@ MenuItemHandlerResult menuhandler0017ef30(s32 operation, struct menuitem *item, MenuItemHandlerResult menuhandlerMpSaveSettings(s32 operation, struct menuitem *item, union handlerdata *data) { if (operation == MENUOP_SET) { - if (g_MpSetup.fileguid.fileid == 0) { - menuPushDialog(&g_MpSaveSetupNameMenuDialog); - } else { -#if VERSION >= VERSION_NTSC_1_0 - filemgrSetDevice1BySerial(g_MpSetup.fileguid.deviceserial); -#endif - + if (g_MpCurrentSetup < 0) { + menuPushDialog(&g_MpSetupGroupsDialog); + } + else { menuPushDialog(&g_MpSaveSetupExistsMenuDialog); } } @@ -5362,6 +5384,9 @@ MenuDialogHandlerResult menudialogCombatSimulator(s32 operation, struct menudial g_Vars.waitingtojoin[1] = false; g_Vars.waitingtojoin[2] = false; g_Vars.waitingtojoin[3] = false; + + // load the setup file when entering the Combat Simulator + mpsetupLoadFile(); } if (g_Menus[g_MpPlayerNum].curdialog diff --git a/src/include/constants.h b/src/include/constants.h index 110e88f5b..1baa3d998 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -4754,6 +4754,11 @@ enum weaponnum { #define EXTRA_SLEEP_TIME 1000LL // 100us +#define MPSETUP_MAXSETUPS 100 +#define MPSETUP_MAXGROUPS 100 +#define MPSETUP_MAXGROUPNAME 33 +#define MPSETUP_BLOCKSIZE 64 + #endif #endif diff --git a/src/include/data.h b/src/include/data.h index 0bc0f12b3..8b71f7fdd 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -562,6 +562,10 @@ extern s32 g_FileAutoSelect; extern u8 g_MpWeaponSetRandomFilters[NUM_MPWEAPONS]; extern s32 g_MpWeaponRandomFilterNum; +extern struct mpsetupfile g_MpSetupFile; +extern s16 g_MpCurrentSetup; +extern s16 g_MpCurrentGroup; + #define PLAYER_EXTCFG() g_PlayerExtCfg[g_Vars.currentplayerstats->mpindex & 3] #define PLAYER_DEFAULT_FOV (PLAYER_EXTCFG().fovy) diff --git a/src/include/game/mplayer/mplayer.h b/src/include/game/mplayer/mplayer.h index 3d2591ca7..b097e5a39 100644 --- a/src/include/game/mplayer/mplayer.h +++ b/src/include/game/mplayer/mplayer.h @@ -122,7 +122,6 @@ void mpsetupfileLoadWad(struct savebuffer *buffer); void mpsetupfileSaveWad(struct savebuffer *buffer); void mpsetupfileGetOverview(char *arg0, char *filename, u16 *numsims, u16 *stagenum, u16 *scenarionum); s32 mpsetupfileSave(s32 device, s32 filenum, u16 deviceserial); -s32 mpsetupfileLoad(s32 device, s32 filenum, u16 deviceserial); void func0f18e558(void); struct modeldef *func0f18e57c(s32 index, s32 *headnum); diff --git a/src/include/types.h b/src/include/types.h index 1da61867b..c5496911b 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -6156,6 +6156,24 @@ struct extplayerconfig { s32 usereloads; }; +struct setupblock { + u8 bytes[MPSETUP_BLOCKSIZE]; +}; + +struct setupgroup { + char name[MPSETUP_MAXGROUPNAME]; + u8 offset_index; +}; + +struct mpsetupfile { + u8 version; + u8 defaultsetup; + u8 numsetups; + u8 numgroups; + struct setupblock setups[MPSETUP_MAXSETUPS]; + struct setupgroup groups[MPSETUP_MAXGROUPS]; +}; + #endif #endif From 355f0ed0eedcfda50c5e77990947fe5bfb052425 Mon Sep 17 00:00:00 2001 From: Catherine Reprobate Date: Sun, 24 Nov 2024 17:51:53 -0800 Subject: [PATCH 05/34] IR Goggle support for 4player and 1-2p draw fixes - allocate memory for 4player's IR goggle scanlines - fixes IR goggle alignment - fixes IR lens for players 2 and 4 - fixes off-by-one rendering error for top two players (bottom of screen) - fixes off-by-one rendering error for right-side players (right side of semicircle thing) - fixes dark area flickering; use resolved shading for props if not wearing goggles - port: fix IR goggle off-by-one draw issues --- src/game/bondview.c | 31 +++++++++++++++++++++++++++++-- src/game/propobj.c | 4 ++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/game/bondview.c b/src/game/bondview.c index ed527006c..9dbae8e06 100644 --- a/src/game/bondview.c +++ b/src/game/bondview.c @@ -31,7 +31,7 @@ char var800a41c0[26]; char var800a41c0[24]; #endif -u8 g_IrScanlines[2][480]; +u8 g_IrScanlines[4][480]; #if VERSION < VERSION_NTSC_1_0 u8 var800a8b58nb[0x1c0]; @@ -2356,6 +2356,10 @@ Gfx *bviewDrawIrLens(Gfx *gdl) gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT); #endif + // fixes off by one error w/ two top players + if (g_Vars.currentplayernum == 0 || g_Vars.currentplayernum == 1) { + scanbottom++; + } for (i = scantop; i < scanbottom; i++) { #if VERSION >= VERSION_NTSC_1_0 if (i & 1) { @@ -2392,6 +2396,10 @@ Gfx *bviewDrawIrLens(Gfx *gdl) s32 semicirclewidth = sqrtf(sqinnerradius - (s32) (f0 * f0)) * (viewwidth / (f32) SCREEN_WIDTH_LO); s32 semicircleright = viewcentrex + semicirclewidth; s32 rightsidewidth = viewwidth - semicircleright; + // if playernum is 1 or 3, shift to the right by viewwidth + if (g_Vars.currentplayernum == 1 || g_Vars.currentplayernum == 3) { + rightsidewidth += viewwidth; + } #ifdef PLATFORM_N64 // Left and right of semicircle @@ -2405,14 +2413,22 @@ Gfx *bviewDrawIrLens(Gfx *gdl) gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewwidth); } #else - // Left and right of semicircle + + // Scanlines to the left and right of the semicircle gDPFillRectangle(gdl++, viewleft, i, viewcentrex, i + 1); + if (PLAYERCOUNT() <= 2 && g_Vars.currentplayernum == 0 && i == viewcentrey) { + semicircleright -= 1; + } + else if (PLAYERCOUNT() > 2 && (g_Vars.currentplayernum == 1 || g_Vars.currentplayernum == 3 ) && i == viewcentrey) { + semicircleright -= 1; + } gDPFillRectangle(gdl++, semicircleright, i, semicircleright + rightsidewidth, i + 1); // The semicircle itself has a static colour gDPSetPrimColorViaWord(gdl++, 0, 0, 0xee0000ff); gDPFillRectangle(gdl++, viewcentrex, i, viewcentrex + semicirclewidth, i + 1); } else { + // scanlines above and below the semicircle gDPFillRectangle(gdl++, viewleft, i, viewleft + viewwidth, i + 1); } #endif @@ -2781,6 +2797,10 @@ Gfx *bviewDrawIrBinoculars(Gfx *gdl) s32 viewleft = viGetViewLeft(); s32 viewright = viewleft + viewwidth; s32 viewbottom = viewtop + viewheight; + // fixes off by one error w/ two top players + if (g_Vars.currentplayernum == 0 || g_Vars.currentplayernum == 1) { + viewbottom++; + } s32 leftx = viewleft + viewwidth / 3; s32 rightx = viewleft + (viewwidth * 2) / 3; s32 centrey = (viewtop + viewbottom) / 2; @@ -2798,6 +2818,13 @@ Gfx *bviewDrawIrBinoculars(Gfx *gdl) for (y = viewtop; y < viewbottom; y++) { s32 ytocentre = centrey - y; s32 sqytocentre = ytocentre * ytocentre; + if (PLAYERCOUNT() <= 2) { + sqytocentre += 1; + } else if (PLAYERCOUNT() > 2) { + if (g_Vars.currentplayernum == 1 || g_Vars.currentplayernum == 3) { + sqytocentre += 1; + } + } if (sqytocentre < sqradius) { s32 xoffset = (viewwidth / (f32) SCREEN_WIDTH_LO) * sqrtf(sqradius - sqytocentre); diff --git a/src/game/propobj.c b/src/game/propobj.c index 01687817e..9c6c8d864 100644 --- a/src/game/propobj.c +++ b/src/game/propobj.c @@ -1616,9 +1616,9 @@ void propCalculateShadeColour(struct prop *prop, u8 *nextcol, u16 floorcol) { s32 shade = func0f068fc8(prop, 0); - // fix props flickering in split screen when one of the players has night vision on + // fix props flickering in split screen when one of the players has night vision or IR Goggles on if (prop->type != PROPTYPE_PLAYER || g_Vars.currentplayer->prop != prop) { - if (USINGDEVICE(DEVICE_NIGHTVISION)) { + if (USINGDEVICE(DEVICE_NIGHTVISION) || USINGDEVICE(DEVICE_IRSCANNER)) { if (prop->rooms[0] >= 0) { shade = g_Rooms[prop->rooms[0]].br_settled_regional; } From 4f55a41d99660f6cec2da883515f9cc26d335a46 Mon Sep 17 00:00:00 2001 From: Catherine Reprobate Date: Fri, 21 Mar 2025 10:22:09 -0700 Subject: [PATCH 06/34] add NVGs and IRGs to CS - fixes n64-bug: NVGs and IR goggles should not be dual-wieldable --- src/game/invitems.c | 4 ++-- src/game/mplayer/mplayer.c | 28 +++++++++++++++------------- src/include/constants.h | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/game/invitems.c b/src/game/invitems.c index 89c7b0ed4..7597195bf 100644 --- a/src/game/invitems.c +++ b/src/game/invitems.c @@ -5118,7 +5118,7 @@ struct weapon invitem_nightvision = { L_GUN_059, // name L_GUN_000, // manufacturer L_GUN_191, // description - WEAPONFLAG_ONEHANDED | WEAPONFLAG_AICANUSE | WEAPONFLAG_00000080 | WEAPONFLAG_DUALWIELD | WEAPONFLAG_UNDROPPABLE, + WEAPONFLAG_ONEHANDED | WEAPONFLAG_AICANUSE | WEAPONFLAG_00000080 | WEAPONFLAG_UNDROPPABLE, }; struct weaponfunc invfunc_horizonscanner_primary = { @@ -5344,7 +5344,7 @@ struct weapon invitem_irscanner = { L_GUN_069, // name L_GUN_000, // manufacturer L_GUN_194, // description - WEAPONFLAG_ONEHANDED | WEAPONFLAG_AICANUSE | WEAPONFLAG_00000040 | WEAPONFLAG_DUALWIELD | WEAPONFLAG_UNDROPPABLE, + WEAPONFLAG_ONEHANDED | WEAPONFLAG_AICANUSE | WEAPONFLAG_00000040 | WEAPONFLAG_UNDROPPABLE, }; struct weaponfunc invfunc_disguise_primary = { diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index b329f51db..9d9c73b53 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -100,23 +100,25 @@ struct mpweapon g_MpWeapons[NUM_MPWEAPONS] = { #ifndef PLATFORM_N64 // fix X-Ray Scanner model /*0x22*/ { WEAPON_XRAYSCANNER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_XRAYSCANNER, MODEL_XRAYSPECS, 256 }, + /*0x23*/ { WEAPON_NIGHTVISION, 0, 0, 0, 0, 1, 0, MODEL_CHRNIGHTSIGHT, 256 }, + /*0x24*/ { WEAPON_IRSCANNER, 0, 0, 0, 0, 1, 0, MODEL_MISC_IRSPECS, 256 }, #else /*0x22*/ { WEAPON_XRAYSCANNER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_XRAYSCANNER, MODEL_CHRNIGHTSIGHT, 256 }, #endif - /*0x23*/ { WEAPON_CLOAKINGDEVICE, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_CLOAKINGDEVICE, MODEL_CHRCLOAKER, 256 }, - /*0x24*/ { WEAPON_COMBATBOOST, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_COMBATBOOST, MODEL_CHRSPEEDPILL, 256 }, + /*0x25*/ { WEAPON_CLOAKINGDEVICE, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_CLOAKINGDEVICE, MODEL_CHRCLOAKER, 256 }, + /*0x26*/ { WEAPON_COMBATBOOST, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_COMBATBOOST, MODEL_CHRSPEEDPILL, 256 }, #ifndef PLATFORM_N64 - /*0x25*/ { WEAPON_PP9I, AMMOTYPE_PISTOL, 80, 0, 0, 1, 0, MODEL_CHRWPPK, 256 }, - /*0x26*/ { WEAPON_CC13, AMMOTYPE_PISTOL, 80, 0, 0, 1, 0, MODEL_CHRTT33, 256 }, - /*0x27*/ { WEAPON_KL01313, AMMOTYPE_SMG, 100, 0, 0, 1, 0, MODEL_CHRSKORPION, 256 }, - /*0x28*/ { WEAPON_KF7SPECIAL, AMMOTYPE_RIFLE, 100, 0, 0, 1, 0, MODEL_CHRKALASH, 256 }, - /*0x29*/ { WEAPON_ZZT, AMMOTYPE_SMG, 100, 0, 0, 1, 0, MODEL_CHRUZI, 256 }, - /*0x2a*/ { WEAPON_DMC, AMMOTYPE_SMG, 100, 0, 0, 1, 0, MODEL_CHRMP5K, 256 }, - /*0x2b*/ { WEAPON_AR53, AMMOTYPE_RIFLE, 150, 0, 0, 1, 0, MODEL_CHRM16, 256 }, - /*0x2c*/ { WEAPON_RCP45, AMMOTYPE_SMG, 150, 0, 0, 1, 0, MODEL_CHRFNP90, 256 }, + /*0x27*/ { WEAPON_PP9I, AMMOTYPE_PISTOL, 80, 0, 0, 1, 0, MODEL_CHRWPPK, 256 }, + /*0x28*/ { WEAPON_CC13, AMMOTYPE_PISTOL, 80, 0, 0, 1, 0, MODEL_CHRTT33, 256 }, + /*0x29*/ { WEAPON_KL01313, AMMOTYPE_SMG, 100, 0, 0, 1, 0, MODEL_CHRSKORPION, 256 }, + /*0x2a*/ { WEAPON_KF7SPECIAL, AMMOTYPE_RIFLE, 100, 0, 0, 1, 0, MODEL_CHRKALASH, 256 }, + /*0x2b*/ { WEAPON_ZZT, AMMOTYPE_SMG, 100, 0, 0, 1, 0, MODEL_CHRUZI, 256 }, + /*0x2c*/ { WEAPON_DMC, AMMOTYPE_SMG, 100, 0, 0, 1, 0, MODEL_CHRMP5K, 256 }, + /*0x2d*/ { WEAPON_AR53, AMMOTYPE_RIFLE, 150, 0, 0, 1, 0, MODEL_CHRM16, 256 }, + /*0x2e*/ { WEAPON_RCP45, AMMOTYPE_SMG, 150, 0, 0, 1, 0, MODEL_CHRFNP90, 256 }, #endif - /*0x2d*/ { WEAPON_MPSHIELD, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_SHIELD, MODEL_CHRSHIELD, 256 }, - /*0x2e*/ { WEAPON_DISABLED }, // 0x25 on N64 + /*0x2f*/ { WEAPON_MPSHIELD, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_SHIELD, MODEL_CHRSHIELD, 256 }, + /*0x30*/ { WEAPON_DISABLED }, // 0x25 on N64 }; #ifndef PLATFORM_N64 @@ -138,7 +140,7 @@ struct mpweapon g_MpWeapons[NUM_MPWEAPONS] = { .usereloads = false, \ } -struct extplayerconfig g_PlayerExtCfg[MAX_PLAYERS] = { +struct extplayerconfig g_PlayerExtCfg[MAX_PLAYERS] = { PLAYER_EXT_CFG_DEFAULT, PLAYER_EXT_CFG_DEFAULT, PLAYER_EXT_CFG_DEFAULT, diff --git a/src/include/constants.h b/src/include/constants.h index 110e88f5b..32452ddab 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -3016,7 +3016,7 @@ #define MPWEAPON_RCP45 0x2c #define MPWEAPON_SHIELD 0x2d #define MPWEAPON_DISABLED 0x2e -#define NUM_MPWEAPONS 0x2f +#define NUM_MPWEAPONS 0x31 #endif #define MUSICEVENTTYPE_PLAY 1 From ad9ed9ff3b766878087463f99d3d656c4a540c48 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Tue, 25 Mar 2025 01:05:57 +0800 Subject: [PATCH 07/34] mpsetupfile: scrapped groups, manage settings: rename/delete --- port/include/mpsetups.h | 4 +- port/src/mpsetups.c | 414 ++++++++++++++++++++++----------------- src/game/mplayer/setup.c | 51 ++--- src/include/data.h | 1 - src/include/types.h | 7 - 5 files changed, 257 insertions(+), 220 deletions(-) diff --git a/port/include/mpsetups.h b/port/include/mpsetups.h index 0341658a2..5c7455c4d 100644 --- a/port/include/mpsetups.h +++ b/port/include/mpsetups.h @@ -4,7 +4,7 @@ #include "types.h" s32 mpsetupLoadFile(); -void mpsetupLoadSetup(s32 index); -s32 mpsetupSaveFile(const char *name, u8 overwrite); +void mpsetupLoadSetup(s32 slotindex); +s32 mpsetupSaveSetup(s32 slotindex); #endif diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index 8702d362e..1609007d2 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -1,11 +1,13 @@ #include "types.h" #include "constants.h" +#include "bss.h" #include "game/menu.h" #include "game/savebuffer.h" #include "game/mplayer/mplayer.h" #include #include "fs.h" #include "system.h" +#include "mpsetups.h" /* MP Setup File Format @@ -13,28 +15,19 @@ MP Setup File Format [version{1}] [defaultsetup{1}] [numsetups{1}] - [numgroups{1}] # setups [setup_1{64}] ... [setup_n{64}] - # groups - [offset_index_1{1}] - [name_1{1-32}] - ... - [offset_index_n{1}] - [name_n{1-32}] */ extern struct menudialogdef g_MpSaveSetupNameMenuDialog; -struct menudialogdef g_MpGroupNameMenuDialog; #define MPSETUP_FILE "mpsetups.bin" u8 filebuffer[sizeof(struct mpsetupfile)]; struct mpsetupfile g_MpSetupFile; s16 g_MpCurrentSetup = -1; -s16 g_MpCurrentGroup = -1; #define BUF_READ(dst, buf, type) { dst = *(type*)((buf)); buf += sizeof(type); } #define BUF_WRITE(src, buf, type) { *((type*)(buf)) = src; buf += sizeof(type); } @@ -42,62 +35,139 @@ s16 g_MpCurrentGroup = -1; memcpy(buf, src, size); \ buf += size; } -// #### Group List -MenuItemHandlerResult mpSelectGroupHandler(s32 operation, struct menuitem *item, union handlerdata *data); +// #### Rename setup dialogue +MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data) +{ + char *name = data->keyboard.string; + s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex; + struct setupblock *setup = &g_MpSetupFile.setups[slotindex]; + s32 err; -struct menuitem g_MpSetupGroupsDialogItems[] = { + switch (operation) { + case MENUOP_GETTEXT: +// strcpy(name, g_MpSetup.name); + strcpy(name, setup->bytes); + break; + case MENUOP_SETTEXT: + strcpy(g_MpSetup.name, name); + break; + case MENUOP_SET: + strcpy(setup->bytes, name); + err = mpsetupSaveSetup(slotindex); + if (!err) { + menuPopDialog(); + } + else { + // TODO +// menuPushDialog(&g_FilemgrFileSavedMenuDialog); + } + break; + } + + return 0; +} + +struct menuitem g_RenameSetupItems[] = { +#if VERSION != VERSION_JPN_FINAL { - MENUITEMTYPE_LIST, + MENUITEMTYPE_LABEL, 0, - MENUITEMFLAG_LABEL_CUSTOMCOLOUR, - 0x00000078, - 0x00000042, - mpSelectGroupHandler, + MENUITEMFLAG_LESSLEFTPADDING, + L_MPMENU_189, // "Enter a name for your game setup file:" + 0, + NULL, + }, +#endif + { + MENUITEMTYPE_KEYBOARD, + 0, + 0, + 0, + 0, + menuhandlerRenameSetup, }, { MENUITEMTYPE_END }, }; -struct menudialogdef g_MpSetupGroupsDialog = { +struct menudialogdef g_RenameSetupDialog = { MENUDIALOGTYPE_DEFAULT, - (uintptr_t) "Groups", - g_MpSetupGroupsDialogItems, + (uintptr_t)"Setup Name:\n", + g_RenameSetupItems, NULL, - MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_CLOSEONSELECT, + MENUDIALOGFLAG_LITERAL_TEXT, NULL, }; -MenuItemHandlerResult mpSelectGroupHandler(s32 operation, struct menuitem *item, union handlerdata *data) +// #### Delete setup dialog +static s32 deleteSetup(); +MenuItemHandlerResult menuhandlerDeleteSetup(s32 operation, struct menuitem *item, union handlerdata *data) { - switch (operation) { - case MENUOP_GETCOLOUR: { - u8 disabled = data->list.value == g_MpSetupFile.numgroups && g_MpSetupFile.numsetups == 0; - u32 colour = data->list.unk04; - data->list.unk04 = disabled ? 0xff333300 | (colour & 0xff) : colour; - } - case MENUOP_GETOPTIONCOUNT: - data->list.value = g_MpSetupFile.numgroups + 1; - break; - case MENUOP_GETOPTIONTEXT: - if (data->list.value == g_MpSetupFile.numgroups) { - return (uintptr_t) "[New Group]\n"; - } - return (uintptr_t) g_MpSetupFile.groups[data->list.value].name; - case MENUOP_SET: - { - u8 newgroupdisabled = data->list.value == g_MpSetupFile.numgroups && g_MpSetupFile.numsetups == 0; - if (newgroupdisabled) { - return 0; - } - - menuPopDialog(); - if (data->list.value == g_MpSetupFile.numgroups) { - menuPushDialog(&g_MpGroupNameMenuDialog); + if (operation == MENUOP_SET) { + s32 err = deleteSetup(); + if (!err) { + menuPopDialog(); + menuPopDialog(); } else { - g_MpCurrentGroup = data->list.value; - menuPushDialog(&g_MpSaveSetupNameMenuDialog); + // TODO } } + + return 0; +} + +struct menuitem g_DeleteSetupItems[] = { + { + MENUITEMTYPE_LABEL, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING, + (uintptr_t)"Delete Setup?\n", + 0, + NULL, + }, + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE, + L_OPTIONS_385, // "No" + 0, + NULL, + }, + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_SELECTABLE_CENTRE, + L_OPTIONS_386, // "Yes" + 0, + menuhandlerDeleteSetup, + }, + { MENUITEMTYPE_END }, +}; + +struct menudialogdef g_DeleteSetupDialog = { + MENUDIALOGTYPE_DANGER, + (uintptr_t)"Delete Setup\n", + g_DeleteSetupItems, + NULL, + MENUDIALOGFLAG_LITERAL_TEXT, + NULL, +}; + +// #### Manage settings dialog +struct menudialogdef g_ManageSetupDialog; +MenuItemHandlerResult mpSelectSettingHandler(s32 operation, struct menuitem *item, union handlerdata *data) +{ + switch (operation) { + case MENUOP_GETOPTIONCOUNT: + data->list.value = g_MpSetupFile.numsetups; + break; + case MENUOP_GETOPTIONTEXT: + return (uintptr_t) g_MpSetupFile.setups[data->list.value].bytes; + case MENUOP_SET: + { + g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value; + menuPushDialog(&g_ManageSetupDialog); + } case MENUOP_GETSELECTEDINDEX: data->list.value = 0xfffff; break; @@ -106,68 +176,93 @@ MenuItemHandlerResult mpSelectGroupHandler(s32 operation, struct menuitem *item, return 0; } -static void createGroup(char *name) -{ - g_MpCurrentGroup = g_MpSetupFile.numgroups++; - struct setupgroup *group = &g_MpSetupFile.groups[g_MpCurrentGroup]; - strcpy(group->name, name); - group->offset_index = g_MpSetupFile.numsetups; -} +struct menuitem g_MpManageSettingsListItems[] = { + { + MENUITEMTYPE_LIST, + 0, + 0, + 0x00000078, + 0x00000042, + mpSelectSettingHandler, + }, + { MENUITEMTYPE_END }, -// #### Group name dialog -MenuItemHandlerResult menuhandlerMpSetupGroupName(s32 operation, struct menuitem *item, union handlerdata *data) -{ - char *name = data->keyboard.string; - struct setupgroup *group = &g_MpSetupFile.groups[g_MpSetupFile.numgroups]; +}; - switch (operation) { - case MENUOP_GETTEXT: - strcpy(name, group->name); - break; - case MENUOP_SETTEXT: - strcpy(group->name, name); - break; - case MENUOP_SET: - createGroup(name); - menuPushDialog(&g_MpSaveSetupNameMenuDialog); - break; +struct menudialogdef g_MpManageSettingsDialog = { + MENUDIALOGTYPE_DEFAULT, + (uintptr_t) "Manage Settings\n", + g_MpManageSettingsListItems, + NULL, + MENUDIALOGFLAG_LITERAL_TEXT, + NULL, +}; + +struct menudialogdef g_RenameSetupDialog; +static MenuItemHandlerResult menuhandlerSetupRename(s32 operation, struct menuitem *item, union handlerdata *data) +{ + if (operation == MENUOP_SET) { + menuPushDialog(&g_RenameSetupDialog); } return 0; } -struct menuitem g_MpGroupNameMenuItems[] = { -#if VERSION != VERSION_JPN_FINAL - { - MENUITEMTYPE_LABEL, - 0, - MENUITEMFLAG_LESSLEFTPADDING | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t) "Enter the group name:\n", - 0, - NULL, - }, -#endif - { - MENUITEMTYPE_KEYBOARD, - 0, - 0, - 0, - 0, - menuhandlerMpSetupGroupName, - }, - { MENUITEMTYPE_END }, +static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuitem *item, union handlerdata *data) +{ + if (operation == MENUOP_SET) { + menuPushDialog(&g_DeleteSetupDialog); + } + + return 0; +} + +struct menuitem g_ManageSetupItems[] = { + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Rename\n", + 0, + menuhandlerSetupRename, + }, + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Delete\n", + 0, + menuhandlerSetupDelete, + }, + { + MENUITEMTYPE_SEPARATOR, + 0, + 0, + 0, + 0, + NULL, + }, + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_SELECTABLE_CLOSESDIALOG, + L_OPTIONS_213, // "Back" + 0, + NULL, + }, + { MENUITEMTYPE_END }, }; -struct menudialogdef g_MpGroupNameMenuDialog = { - MENUDIALOGTYPE_DEFAULT, - (uintptr_t) "Group Name\n", - g_MpGroupNameMenuItems, - NULL, - MENUDIALOGFLAG_LITERAL_TEXT, - NULL, +struct menudialogdef g_ManageSetupDialog = { + MENUDIALOGTYPE_DEFAULT, + (uintptr_t)"Manage Setup", + g_ManageSetupItems, + NULL, + MENUDIALOGFLAG_LITERAL_TEXT, + NULL, }; - +// ----------------------- static size_t readStr(char *dst, char *src) { char *start = dst; @@ -181,50 +276,49 @@ static size_t readStr(char *dst, char *src) return dst - start; } -static void mpsetupfileRead(struct mpsetupfile *setupfile, u8 *buffer) +static void mpsetupDeserialize(struct mpsetupfile *setupfile, u8 *buffer) { BUF_READ(setupfile->version, buffer, u8); BUF_READ(setupfile->defaultsetup, buffer, u8); BUF_READ(setupfile->numsetups, buffer, u8); - BUF_READ(setupfile->numgroups, buffer, u8); for (int i = 0; i < setupfile->numsetups; ++i) { memcpy(setupfile->setups[i].bytes, buffer, MPSETUP_BLOCKSIZE); buffer += MPSETUP_BLOCKSIZE; } - - for (int i = 0; i < setupfile->numgroups; ++i) { - struct setupgroup *group = &setupfile->groups[i]; - BUF_READ(group->offset_index, buffer, u8); - buffer += readStr(group->name, buffer); - } } -void mpsetupfileWrite(u8 *buffer, struct mpsetupfile *setupfile, struct savebuffer *setup, u8 setupidx, u8 overwrite) +void mpsetupSerialize(u8 *buffer, struct mpsetupfile *setupfile) { BUF_WRITE(setupfile->version, buffer, u8); BUF_WRITE(setupfile->defaultsetup, buffer, u8); BUF_WRITE(setupfile->numsetups, buffer, u8); - BUF_WRITE(setupfile->numgroups, buffer, u8); for (int i = 0; i < setupfile->numsetups; ++i) { - if (i == setupidx) { - BUF_WRITEBLOCK(buffer, setup->bytes, MPSETUP_BLOCKSIZE); - - if (!overwrite) { - BUF_WRITEBLOCK(buffer, setupfile->setups[i].bytes, MPSETUP_BLOCKSIZE) - } - continue; - } - BUF_WRITEBLOCK(buffer, setupfile->setups[i].bytes, MPSETUP_BLOCKSIZE) } +} - for (int i = 0; i < setupfile->numgroups; ++i) { - struct setupgroup *group = &setupfile->groups[i]; - BUF_WRITE(group->offset_index, buffer, u8); - buffer += readStr(buffer, group->name); +static s32 mpsetupSaveFile(); +static s32 deleteSetup() +{ + s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex; + for (int i = slotindex; i < g_MpSetupFile.numsetups - 1; ++i) { + u8* dst = g_MpSetupFile.setups[i].bytes; + u8* src = g_MpSetupFile.setups[i+1].bytes; + + memcpy(dst, src, MPSETUP_BLOCKSIZE); } + + if (g_MpCurrentSetup > slotindex) { + g_MpCurrentSetup--; + } + else if (g_MpCurrentSetup == slotindex) { + g_MpCurrentSetup = -1; + } + + g_MpSetupFile.numsetups--; + return mpsetupSaveFile(); } static FILE *openMpSetupFile(u8 mode) { @@ -248,7 +342,7 @@ static FILE *openMpSetupFile(u8 mode) { } if (f == NULL) { - sysLogPrintf(LOG_NOTE, "Unable to open mp setup file"); + sysLogPrintf(LOG_ERROR, "Unable to open mp setup file"); return NULL; } @@ -275,68 +369,21 @@ s32 mpsetupLoadFile() fread(filebuffer, 1, size, f); - mpsetupfileRead(&g_MpSetupFile, filebuffer); + mpsetupDeserialize(&g_MpSetupFile, filebuffer); if (g_MpSetupFile.defaultsetup != 0) { g_MpCurrentSetup = g_MpSetupFile.defaultsetup; } - // setup a default group if there is none - if (g_MpSetupFile.numgroups == 0) { - g_MpSetupFile.numgroups++; - strcpy(g_MpSetupFile.groups[0].name, "Default\n"); - g_MpSetupFile.groups[0].offset_index = 0; - g_MpCurrentSetup = -1; - } - fsFileFree(f); return 0; } -static s32 getNewSetupIndex() +static s32 mpsetupSaveFile() { - if (g_MpSetupFile.numsetups == 0) { - return 0; - } - - if (g_MpCurrentGroup == g_MpSetupFile.numgroups - 1) - return g_MpSetupFile.numsetups; - - return g_MpSetupFile.groups[g_MpCurrentGroup + 1].offset_index; -} - -static s32 getGroupIndex(s32 setupIndex) -{ - s32 index = 0; - struct setupgroup *groups = g_MpSetupFile.groups; - for (int i = 0; i < g_MpSetupFile.numgroups; ++i) { - if (setupIndex >= groups[i].offset_index) { - index = groups[i].offset_index; - } - } - - return index; -} - -s32 mpsetupSaveFile(const char *name, u8 overwrite) -{ - struct savebuffer setup; - - if (!overwrite) { - g_MpCurrentSetup = getNewSetupIndex(); - g_MpSetupFile.numsetups++; - - for (int i = g_MpCurrentGroup + 1; i < g_MpSetupFile.numgroups; ++i) { - g_MpSetupFile.groups[i].offset_index++; - } - } - - savebufferClear(&setup); - mpsetupfileSaveWad(&setup); - zeroFileBuffer(); - mpsetupfileWrite(filebuffer, &g_MpSetupFile, &setup, g_MpCurrentSetup, overwrite); + mpsetupSerialize(filebuffer, &g_MpSetupFile); FILE *f = openMpSetupFile('w'); if (f == NULL) { @@ -347,8 +394,24 @@ s32 mpsetupSaveFile(const char *name, u8 overwrite) fsFileFree(f); // reload the file to update in-memory structs - mpsetupLoadFile(); - return 0; + return mpsetupLoadFile(); +} + +s32 mpsetupSaveSetup(s32 slotindex) +{ + struct savebuffer setup; + + // request to add a new setup + if (slotindex == g_MpSetupFile.numsetups) { + g_MpCurrentSetup = g_MpSetupFile.numsetups++; + } + + savebufferClear(&setup); + mpsetupfileSaveWad(&setup); + + memcpy(g_MpSetupFile.setups[slotindex].bytes, &setup.bytes, MPSETUP_BLOCKSIZE); + + return mpsetupSaveFile(); } void mpsetupLoadSetup(s32 index) @@ -359,5 +422,4 @@ void mpsetupLoadSetup(s32 index) memcpy(&buffer.bytes, block->bytes, MPSETUP_BLOCKSIZE); mpsetupfileLoadWad(&buffer); g_MpCurrentSetup = index; - g_MpCurrentGroup = getGroupIndex(index); } diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index a94d32dd1..12c387cbc 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -33,7 +33,7 @@ struct menudialogdef g_MpChangeTeamNameMenuDialog; struct menudialogdef g_MpEditSimulantMenuDialog; struct menudialogdef g_MpSaveSetupNameMenuDialog; -extern struct menudialogdef g_MpSetupGroupsDialog; +extern struct menudialogdef g_MpManageSettingsDialog; extern struct menudialogdef g_FilemgrFileSavedMenuDialog; extern struct menudialogdef g_FilemgrErrorMenuDialog; @@ -470,7 +470,7 @@ MenuItemHandlerResult menuhandlerMpSetupName(s32 operation, struct menuitem *ite strcpy(g_MpSetup.name, name); break; case MENUOP_SET: - err = mpsetupSaveFile(name, false); + err = mpsetupSaveSetup(g_MpSetupFile.numsetups); if (!err) { menuPushDialog(&g_FilemgrFileSavedMenuDialog); } @@ -488,7 +488,8 @@ MenuItemHandlerResult menuhandlerMpSaveSetupOverwrite(s32 operation, struct menu { if (operation == MENUOP_SET) { menuPopDialog(); - mpsetupSaveFile(g_MpSetupFile.setups[g_MpCurrentSetup].bytes, true); + mpsetupSaveSetup(g_MpCurrentSetup); + menuPushDialog(&g_FilemgrFileSavedMenuDialog); } return 0; @@ -498,7 +499,7 @@ MenuItemHandlerResult menuhandlerMpSaveSetupCopy(s32 operation, struct menuitem { if (operation == MENUOP_SET) { menuPopDialog(); - menuPushDialog(&g_MpSetupGroupsDialog); + menuPushDialog(&g_MpSaveSetupNameMenuDialog); } return 0; @@ -2289,25 +2290,15 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * data->list.value = 0xfffff; break; case MENUOP_GETOPTGROUPCOUNT: - data->list.value = g_MpSetupFile.numgroups + 1; + data->list.value = 2; break; case MENUOP_GETOPTGROUPTEXT: if (data->list.value == 0) { return (uintptr_t)langGet(L_MPMENU_141); // "Presets" } - - return (uintptr_t)&g_MpSetupFile.groups[data->list.value - 1].name; - break; + return (uintptr_t)"Custom"; case MENUOP_GETGROUPSTARTINDEX: - if (data->list.value == 0) { - data->list.groupstartindex = 0; - } else { - data->list.groupstartindex = mpGetNumUnlockedPresets(); - - if (g_MpSetupFile.numgroups > 0) { - data->list.groupstartindex += g_MpSetupFile.groups[data->list.value - 1].offset_index; - } - } + data->list.groupstartindex = data->list.value == 0 ? 0 : mpGetNumUnlockedPresets(); break; case MENUOP_LISTITEMFOCUS: if (data->list.value < mpGetNumUnlockedPresets()) { @@ -2639,22 +2630,6 @@ struct menuitem g_MpLoadSettingsMenuItems[] = { 0, NULL, }, - { - MENUITEMTYPE_SEPARATOR, - 0, - MENUITEMFLAG_00000002, - 0, - 0, - NULL, - }, - { - MENUITEMTYPE_LABEL, - 0, - MENUITEMFLAG_00000002 | MENUITEMFLAG_SELECTABLE_CENTRE, - L_MPMENU_414, // "Press the B Button to go back." - 0, - NULL, - }, { MENUITEMTYPE_END }, }; @@ -5039,7 +5014,7 @@ MenuItemHandlerResult menuhandlerMpSaveSettings(s32 operation, struct menuitem * { if (operation == MENUOP_SET) { if (g_MpCurrentSetup < 0) { - menuPushDialog(&g_MpSetupGroupsDialog); + menuPushDialog(&g_MpSaveSetupNameMenuDialog); } else { menuPushDialog(&g_MpSaveSetupExistsMenuDialog); @@ -5779,6 +5754,14 @@ struct menuitem g_MpAdvancedSetupMenuItems[] = { 0, NULL, }, + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_OPENSDIALOG | MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LOCKABLEMAJOR, + (uintptr_t)"Manage Settings\n", + 0, + (void *)&g_MpManageSettingsDialog, + }, { MENUITEMTYPE_SELECTABLE, 0, diff --git a/src/include/data.h b/src/include/data.h index 8b71f7fdd..f576e606b 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -564,7 +564,6 @@ extern s32 g_MpWeaponRandomFilterNum; extern struct mpsetupfile g_MpSetupFile; extern s16 g_MpCurrentSetup; -extern s16 g_MpCurrentGroup; #define PLAYER_EXTCFG() g_PlayerExtCfg[g_Vars.currentplayerstats->mpindex & 3] #define PLAYER_DEFAULT_FOV (PLAYER_EXTCFG().fovy) diff --git a/src/include/types.h b/src/include/types.h index c5496911b..f5de55dd2 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -6160,18 +6160,11 @@ struct setupblock { u8 bytes[MPSETUP_BLOCKSIZE]; }; -struct setupgroup { - char name[MPSETUP_MAXGROUPNAME]; - u8 offset_index; -}; - struct mpsetupfile { u8 version; u8 defaultsetup; u8 numsetups; - u8 numgroups; struct setupblock setups[MPSETUP_MAXSETUPS]; - struct setupgroup groups[MPSETUP_MAXGROUPS]; }; #endif From 3d75365f2b4017ee394f3689d06ffcdf771c03e2 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Wed, 26 Mar 2025 23:43:42 +0800 Subject: [PATCH 08/34] mpsetups: increased max name length to 18 --- port/src/mpsetups.c | 8 ++++---- src/game/challenge.c | 3 +++ src/game/menuitem.c | 7 ++++--- src/{ => game}/mpconfigs.c | 0 src/game/mplayer/mplayer.c | 4 ++-- src/game/mplayer/setup.c | 11 +++++------ src/game/savebuffer.c | 29 ++++++++++++++++++++++------- src/include/constants.h | 5 ++--- src/include/game/savebuffer.h | 3 +++ src/include/types.h | 4 ++-- 10 files changed, 47 insertions(+), 27 deletions(-) rename src/{ => game}/mpconfigs.c (100%) diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index 1609007d2..b3d1aa063 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -35,7 +35,7 @@ s16 g_MpCurrentSetup = -1; memcpy(buf, src, size); \ buf += size; } -// #### Rename setup dialogue +// #### Rename setup dialog MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data) { char *name = data->keyboard.string; @@ -80,10 +80,10 @@ struct menuitem g_RenameSetupItems[] = { #endif { MENUITEMTYPE_KEYBOARD, + 18, 0, 0, - 0, - 0, + 1, menuhandlerRenameSetup, }, { MENUITEMTYPE_END }, @@ -181,7 +181,7 @@ struct menuitem g_MpManageSettingsListItems[] = { MENUITEMTYPE_LIST, 0, 0, - 0x00000078, + 160, 0x00000042, mpSelectSettingHandler, }, diff --git a/src/game/challenge.c b/src/game/challenge.c index 8c738105f..2377e43ff 100644 --- a/src/game/challenge.c +++ b/src/game/challenge.c @@ -400,6 +400,8 @@ struct mpconfigfull *challengeLoadConfig(s32 confignum, u8 *buffer, s32 len) extern struct mpstrings EXT_SEG _mpstringsSSegmentRomEnd; extern struct mpstrings EXT_SEG _mpstringsISegmentRomEnd; + extern struct mpconfig g_MpConfigs[]; + BTYPE banks[][2] = { { (BTYPE)REF_SEG _mpstringsESegmentRomStart, (BTYPE)REF_SEG _mpstringsESegmentRomEnd }, { (BTYPE)REF_SEG _mpstringsJSegmentRomStart, (BTYPE)REF_SEG _mpstringsJSegmentRomEnd }, @@ -421,6 +423,7 @@ struct mpconfigfull *challengeLoadConfig(s32 confignum, u8 *buffer, s32 len) bank = banks[language_id][0]; loadedstrings = dmaExecWithAutoAlign(buffer2, bank + confignum * sizeof(struct mpstrings), sizeof(struct mpstrings)); + mpconfig->config = g_MpConfigs[confignum]; mpconfig->strings = *loadedstrings; return mpconfig; diff --git a/src/game/menuitem.c b/src/game/menuitem.c index 18f80c1a6..85fa18105 100644 --- a/src/game/menuitem.c +++ b/src/game/menuitem.c @@ -1529,6 +1529,7 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32 inputs->start = false; } + u8 maxlen = item->param == 0 ? 10 : item->param; #ifndef PLATFORM_N64 if (g_MenuKeyboardPlayer == g_MpPlayerNum) { // match caps state to keyboard shift/caps if typing with keyboard @@ -1540,7 +1541,7 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32 // handle text input s32 prevpos = strlen(kb->string); s32 pos = prevpos; - s32 result = inputTextHandler(kb->string, sizeof(kb->string), &pos, true); + s32 result = inputTextHandler(kb->string, maxlen-1, &pos, true); if (result == -1) { // cancel kb->row = 5; @@ -1617,7 +1618,7 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32 s32 textwidth; s32 textheight; - if (kb->string[9] == '\0') { + if (kb->string[maxlen-1] == '\0') { // String is not full i = 0; @@ -1653,7 +1654,7 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32 // Handle deleting if (delete && kb->string[0] != '\0') { s32 deleted = false; - s32 i = 10; + s32 i = maxlen; menuPlaySound(MENUSOUND_FOCUS); diff --git a/src/mpconfigs.c b/src/game/mpconfigs.c similarity index 100% rename from src/mpconfigs.c rename to src/game/mpconfigs.c diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index 3d9381522..a9ea46998 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -3918,7 +3918,7 @@ void mpsetupfileLoadWad(struct savebuffer *buffer) s32 i; s32 j; - savebufferReadString(buffer, g_MpSetup.name, false); + savebufferReadString_ext(buffer, g_MpSetup.name, false, MPSETUP_MAXSETUPS+1); savebufferReadBits(buffer, 4); g_MpSetup.stagenum = savebufferReadBits(buffer, 7); @@ -3973,7 +3973,7 @@ void mpsetupfileSaveWad(struct savebuffer *buffer) s32 mpbodynum; s32 i; - func0f0d55a4(buffer, g_MpSetup.name); + func0f0d55a4_ext(buffer, g_MpSetup.name, MPSETUP_MAXSETUPS+1); for (i = 0; i < MAX_BOTS; i++) { if (g_MpSetup.chrslots & (1 << (i + 4))) { diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index 12c387cbc..2f129d7b4 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -1098,10 +1098,10 @@ struct menuitem g_MpSaveSetupNameMenuItems[] = { #endif { MENUITEMTYPE_KEYBOARD, + MPSETUP_MAXNAME, 0, 0, - 0, - 0, + 1, menuhandlerMpSetupName, }, { MENUITEMTYPE_END }, @@ -2254,8 +2254,7 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * { switch (operation) { case MENUOP_GETOPTIONCOUNT: - data->list.value = mpGetNumUnlockedPresets(); - data->list.value += g_MpSetupFile.numsetups; + data->list.value = mpGetNumUnlockedPresets() + g_MpSetupFile.numsetups; break; case MENUOP_GETOPTIONTEXT: if (data->list.value < mpGetNumUnlockedPresets()) { @@ -2263,7 +2262,7 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * } if (g_MpSetupFile.numsetups > 0) { struct setupblock *block = &g_MpSetupFile.setups[data->list.value - mpGetNumUnlockedPresets()]; - func0f0d564c(block->bytes, g_StringPointer, false); + func0f0d564c_ext(block->bytes, g_StringPointer, false, MPSETUP_MAXSETUPS+1); return (uintptr_t)g_StringPointer; } break; @@ -2618,7 +2617,7 @@ struct menuitem g_MpLoadSettingsMenuItems[] = { MENUITEMTYPE_LIST, 0, 0, - 0x00000078, + 160, 0x00000042, mpLoadSettingsMenuHandler, }, diff --git a/src/game/savebuffer.c b/src/game/savebuffer.c index f9d4705fd..0dc22dee5 100644 --- a/src/game/savebuffer.c +++ b/src/game/savebuffer.c @@ -481,13 +481,13 @@ void func0f0d54c4(struct savebuffer *buffer) * Read a zero-terminated string from the buffer and move the buffer's internal * pointer past the end of the string. */ -void savebufferReadString(struct savebuffer *buffer, char *dst, bool addlinebreak) +void savebufferReadString_ext(struct savebuffer *buffer, char *dst, bool addlinebreak, u8 len) { bool foundnull = false; s32 index = 0; s32 i; - for (i = 0; i < 10; i++) { + for (i = 0; i < len; i++) { s32 byte = savebufferReadBits(buffer, 8); if (!foundnull) { @@ -509,12 +509,17 @@ void savebufferReadString(struct savebuffer *buffer, char *dst, bool addlinebrea dst[index] = '\0'; } -void func0f0d55a4(struct savebuffer *buffer, char *src) +void savebufferReadString(struct savebuffer *buffer, char *dst, bool addlinebreak) +{ + savebufferReadString_ext(buffer, dst, addlinebreak, 10); +} + +void func0f0d55a4_ext(struct savebuffer *buffer, char *src, u8 len) { bool done = false; s32 i; - for (i = 0; i < 10; i++) { + for (i = 0; i < len; i++) { if (!done) { if (src[i] == '\0') { done = true; @@ -532,12 +537,22 @@ void func0f0d55a4(struct savebuffer *buffer, char *src) } } -void func0f0d564c(u8 *data, char *dst, bool addlinebreak) +void func0f0d55a4(struct savebuffer *buffer, char *src) +{ + func0f0d55a4_ext(buffer, src, 10); +} + +void func0f0d564c_ext(u8 *data, char *dst, bool addlinebreak, u8 len) { struct savebuffer buffer; - savebufferWriteData(&buffer, data, 10); - savebufferReadString(&buffer, dst, addlinebreak); + savebufferWriteData(&buffer, data, len); + savebufferReadString_ext(&buffer, dst, addlinebreak, len); +} + +void func0f0d564c(u8 *data, char *dst, bool addlinebreak) +{ + func0f0d564c_ext(data, dst, addlinebreak, 10); } #if VERSION >= VERSION_NTSC_1_0 diff --git a/src/include/constants.h b/src/include/constants.h index 1baa3d998..e1c4b4ea3 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -4754,9 +4754,8 @@ enum weaponnum { #define EXTRA_SLEEP_TIME 1000LL // 100us -#define MPSETUP_MAXSETUPS 100 -#define MPSETUP_MAXGROUPS 100 -#define MPSETUP_MAXGROUPNAME 33 +#define MPSETUP_MAXSETUPS 128 +#define MPSETUP_MAXNAME 18 #define MPSETUP_BLOCKSIZE 64 #endif diff --git a/src/include/game/savebuffer.h b/src/include/game/savebuffer.h index 9529248ce..320708af2 100644 --- a/src/include/game/savebuffer.h +++ b/src/include/game/savebuffer.h @@ -17,8 +17,11 @@ u32 savebufferReadBits(struct savebuffer *buffer, s32 offset); void savebufferClear(struct savebuffer *buffer); void savebufferWriteData(struct savebuffer *buffer, u8 *data, u8 len); void func0f0d54c4(struct savebuffer *buffer); +void savebufferReadString_ext(struct savebuffer *buffer, char *dst, bool addlinebreak, u8 len); void savebufferReadString(struct savebuffer *buffer, char *dst, bool addlinebreak); +void func0f0d55a4_ext(struct savebuffer *buffer, char *src, u8 len); void func0f0d55a4(struct savebuffer *buffer, char *src); +void func0f0d564c_ext(u8 *data, char *dst, bool addlinebreak, u8 len); void func0f0d564c(u8 *data, char *dst, bool addlinebreak); void func0f0d5690(u8 *dst, char *buffer); void savebufferWriteGuid(struct savebuffer *buffer, struct fileguid *guid); diff --git a/src/include/types.h b/src/include/types.h index f5de55dd2..61d8a96f5 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -3295,7 +3295,7 @@ struct menuitemdata_dropdown { }; struct menuitemdata_keyboard { - char string[11]; + char string[MPSETUP_MAXNAME+1]; s8 col; s8 row; u8 capslock : 1; // Pressed A on caps button @@ -4080,7 +4080,7 @@ struct missionconfig { }; struct mpsetup { - /*0x800acb88*/ char name[12]; + /*0x800acb88*/ char name[MPSETUP_MAXNAME+1]; /*0x800acb94*/ u32 options; /*0x800acb98*/ u8 scenario; /*0x800acb99*/ u8 stagenum; From a26260e9328d438b80f36f417af0050196015948 Mon Sep 17 00:00:00 2001 From: AL2009man <67606569+AL2009man@users.noreply.github.com> Date: Thu, 27 Mar 2025 01:47:49 -0400 Subject: [PATCH 09/34] added SDL Hints field For some reason: this sourceport isn't using SDL Hints. this is very crucial inorder to implement features sets like Gyro Aiming. Thus: most of the important hints will be forcefully enabled while improving Contorller compatibility when using RawInput --- port/src/input.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/port/src/input.c b/port/src/input.c index cfee620a5..6c00f829c 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -678,6 +678,19 @@ s32 inputInit(void) SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC); } + // Set SDL hints before loading controller mappings + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); // This hint will enable PlayStation's more advanced feature sets when using Bluetooth connecivity, this includes Motion Sensors. + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); // same case as PS4_Rumble hint. + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT, "1"); + // try to load controller db from an external file in the save folder if (fsFileSize("$S/" CONTROLLERDB_FNAME)) { const char *dbpath = fsFullPath("$S/" CONTROLLERDB_FNAME); From 1a5e42e55f3fda6e7ca3e543ce9cf71a06eadea6 Mon Sep 17 00:00:00 2001 From: AL2009man <67606569+AL2009man@users.noreply.github.com> Date: Thu, 27 Mar 2025 01:49:28 -0400 Subject: [PATCH 10/34] changed note --- port/src/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/port/src/input.c b/port/src/input.c index 6c00f829c..ed953dc28 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -683,7 +683,7 @@ s32 inputInit(void) SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); // This hint will enable PlayStation's more advanced feature sets when using Bluetooth connecivity, this includes Motion Sensors. + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); // Enables Rumble and Motion Sensor functionality when under Bluetooth connectivity. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); // same case as PS4_Rumble hint. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "1"); From c44704e2af1b0af6fa3ba9094ef5a945d9763c82 Mon Sep 17 00:00:00 2001 From: AL2009man <67606569+AL2009man@users.noreply.github.com> Date: Thu, 27 Mar 2025 01:55:25 -0400 Subject: [PATCH 11/34] added SDL Hint for Wii Controllers --- port/src/input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/port/src/input.c b/port/src/input.c index ed953dc28..7475c2b2b 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -688,6 +688,7 @@ s32 inputInit(void) SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT, "1"); From dcef8deed8deb168efbddee3b82088c6c989ebc8 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Fri, 28 Mar 2025 21:08:18 +0800 Subject: [PATCH 12/34] mpsetups: import/export settings --- port/include/fs.h | 1 + port/include/mpsetups.h | 2 +- port/src/fs.c | 11 + port/src/mpsetups.c | 468 ++++++++++++++++++++++++++++++++++++--- src/game/mplayer/setup.c | 6 +- 5 files changed, 448 insertions(+), 40 deletions(-) diff --git a/port/include/fs.h b/port/include/fs.h index bfb21b3ec..05b91aa04 100644 --- a/port/include/fs.h +++ b/port/include/fs.h @@ -22,5 +22,6 @@ FILE *fsFileOpenRead(const char *name); void fsFileFree(FILE *f); const char *fsGetModDir(void); +s32 fsCreateDir(const char *path); #endif diff --git a/port/include/mpsetups.h b/port/include/mpsetups.h index 5c7455c4d..c2a24056f 100644 --- a/port/include/mpsetups.h +++ b/port/include/mpsetups.h @@ -3,7 +3,7 @@ #include "types.h" -s32 mpsetupLoadFile(); +s32 mpsetupLoadCurrentSetupFile(); void mpsetupLoadSetup(s32 slotindex); s32 mpsetupSaveSetup(s32 slotindex); diff --git a/port/src/fs.c b/port/src/fs.c index 40335a3fa..7d4507aa7 100644 --- a/port/src/fs.c +++ b/port/src/fs.c @@ -11,6 +11,9 @@ #include "platform.h" #include "utils.h" #include "fs.h" +#ifdef PLATFORM_WIN32 +#include +#endif #define DEFAULT_BASEDIR_NAME "data" @@ -280,3 +283,11 @@ void fsFileFree(FILE *f) { fclose(f); } + +s32 fsCreateDir(const char *path) { +#ifdef PLATFORM_WIN32 + return _mkdir(fsFullPath(path)); +#else + return mkdir(fsFullPath(path), S_IRWXU | S_IRWXG) +#endif +} diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index b3d1aa063..27eb82c6b 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -21,13 +21,27 @@ MP Setup File Format [setup_n{64}] */ +#define MPSETUP_EXPORTDIR "$S/exported/" +#define MPSETUP_FILENAME "mpsetups" +#define MPSETUP_FILENAME_EXP "mpsetups-ext" + +#define MPSETUP_OP_DEFAULT 0 +#define MPSETUP_OP_IMPORT 1 +#define MPSETUP_OP_EXPORT 2 + +#define MPSETUP_IMPORT_OVERWRITE 0 +#define MPSETUP_IMPORT_ADD 1 + +#define MPSETUP_IMPORT_CONFLICT 0x1313 + extern struct menudialogdef g_MpSaveSetupNameMenuDialog; -#define MPSETUP_FILE "mpsetups.bin" u8 filebuffer[sizeof(struct mpsetupfile)]; struct mpsetupfile g_MpSetupFile; +struct mpsetupfile g_ImportMpSetupFile; s16 g_MpCurrentSetup = -1; +u64 g_MpImportExportFilter[2]; #define BUF_READ(dst, buf, type) { dst = *(type*)((buf)); buf += sizeof(type); } #define BUF_WRITE(src, buf, type) { *((type*)(buf)) = src; buf += sizeof(type); } @@ -35,6 +49,70 @@ s16 g_MpCurrentSetup = -1; memcpy(buf, src, size); \ buf += size; } +static inline void zeroFileBuffer() +{ + memset(filebuffer, 0, sizeof(struct mpsetupfile)); +} + +char g_StatusText[128]; +struct menuitem g_StatusOkMenuItems[] = { + { + MENUITEMTYPE_LABEL, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING, + (uintptr_t)g_StatusText, + 0, + NULL, + }, + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE, + L_OPTIONS_347, // "OK" + 0, + NULL, + }, + { MENUITEMTYPE_END }, +}; + +struct menudialogdef g_StatusOkDialog = { + MENUDIALOGTYPE_SUCCESS, + L_OPTIONS_345, // "Cool!" + g_StatusOkMenuItems, + NULL, + MENUDIALOGFLAG_DISABLEBANNER, + NULL, +}; + +struct menuitem g_StatusErrorMenuItems[] = { + { + MENUITEMTYPE_LABEL, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING, + (uintptr_t)g_StatusText, + 0, + NULL, + }, + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE, + L_OPTIONS_347, // "OK" + 0, + NULL, + }, + { MENUITEMTYPE_END }, +}; + +struct menudialogdef g_StatusErrorDialog = { + MENUDIALOGTYPE_DANGER, + L_OPTIONS_277, // "Failed" + g_StatusErrorMenuItems, + NULL, + MENUDIALOGFLAG_DISABLEBANNER, + NULL, +}; + // #### Rename setup dialog MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data) { @@ -153,6 +231,194 @@ struct menudialogdef g_DeleteSetupDialog = { NULL, }; +// #### Import (or Export) settings dialog +s32 importMpSetupFile(u8 op, u8 skipOverlap); +s32 exportMpSetupFile(); +struct menudialogdef g_ManageSettingsDialog; +struct menudialogdef g_ImportOverrideDialog; +MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct menuitem *item, union handlerdata *data) +{ + static const char *labels[] = { + "Select All", + "Select None", + "Import", + "Export", + }; + + s32 op = g_Menus[g_MpPlayerNum].mpsetup.unke24; + + struct mpsetupfile *setupfile = op == MPSETUP_OP_IMPORT ? &g_ImportMpSetupFile : &g_MpSetupFile; + + u8 numsetups = setupfile->numsetups; + u8 numitems = numsetups + 3; + u8 bank = data->list.value < 64 ? 0 : 1; + u8 bit = data->list.value - bank * 64; + u8 hasselection = (g_MpImportExportFilter[0] | g_MpImportExportFilter[1]) != 0; + s32 err; + + switch (operation) { + case MENUOP_GETCOLOUR: { + u32 colour = data->list.unk04; + if (data->list.value == numitems - 1) { + data->list.unk04 = hasselection ? colour : (colour & 0xffffff00) | 0x66; + } + break; + } + case MENUOP_GETOPTIONCOUNT: + data->list.value = numitems; + break; + case MENUOP_GETOPTIONTEXT: + if (data->list.value < numsetups) { + return (uintptr_t) setupfile->setups[data->list.value].bytes; + } + else { + // creates an offset to select the "Export" or "Import" label for the last item + u8 ofs = (data->list.value == numitems - 1) ? op - 1 : 0; + return (intptr_t)labels[data->list.value - numsetups + ofs]; + } + case MENUOP_SET: { + if (data->list.value < setupfile->numsetups) { + g_MpImportExportFilter[bank] ^= (1 << bit); + } + else { + s32 index = data->list.value - setupfile->numsetups; + + switch (index) { + // Select All + case 0: + g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1; + break; + // Select None + case 1: + g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = 0; + break; + // Export (or Import) + case 2: + if (hasselection) { + err = op == MPSETUP_OP_IMPORT ? importMpSetupFile(0, false) : exportMpSetupFile(); + if (!err) { + menuPopDialog(); + if (op == MPSETUP_OP_IMPORT) { + // back to the 'Manage Settings' screen + menuPopDialog(); + menuPushDialog(&g_ManageSettingsDialog); + } + else { + sprintf(g_StatusText, "File %s.bin\nwritten to the folder 'exported'\n", MPSETUP_FILENAME_EXP); + menuPushDialog(&g_StatusOkDialog); + } + } + else { + if (err == MPSETUP_IMPORT_CONFLICT) { + menuPushDialog(&g_ImportOverrideDialog); + } + else { + menuPushDialog(&g_StatusErrorDialog); + } + } + } + break; + } + } + } + case MENUOP_GETSELECTEDINDEX: + data->list.value = 0x000fffff; + break; + case MENUOP_GETLISTITEMCHECKBOX: { + if (data->list.value < numsetups) { + data->list.unk04 = (g_MpImportExportFilter[bank] & (1 << bit)); + } + break; + } + } + + return 0; +} + +struct menuitem g_ImportExportItems[] = { + { + MENUITEMTYPE_LIST, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LABEL_CUSTOMCOLOUR, + 140, + 0x0000004d, + menuhandlerImportOrExportSettings, + }, + { MENUITEMTYPE_END }, +}; + +char g_TitleImportExportDialog[20]; +struct menudialogdef g_ImportExportDialog = { + MENUDIALOGTYPE_DEFAULT, + (uintptr_t) g_TitleImportExportDialog, + g_ImportExportItems, + NULL, + MENUDIALOGFLAG_LITERAL_TEXT, + NULL, +}; + + +// #### Manage Import/Export settings dialog +s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op); +MenuItemHandlerResult menuhandlerOpenImportExportDialog(s32 operation, struct menuitem *item, union handlerdata *data) +{ + switch (operation) { + case MENUOP_SET: + { + if (item->param == MPSETUP_OP_IMPORT) { + strcpy(g_TitleImportExportDialog, "Import Settings\n"); + if (fsFileSize("$S/" MPSETUP_FILENAME_EXP ".bin") < 0) { + sprintf(g_StatusText, + "No import file found.\n" + "Place the file %s.bin\n" + "Next to your %s.bin file\n", MPSETUP_FILENAME_EXP, MPSETUP_FILENAME); + menuPushDialog(&g_StatusErrorDialog); + return 0; + } + + mpsetupLoadFile(&g_ImportMpSetupFile, MPSETUP_OP_IMPORT); + } + else { + strcpy(g_TitleImportExportDialog, "Export Settings\n"); + } + g_Menus[g_MpPlayerNum].mpsetup.unke24 = item->param; + g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1; + menuPushDialog(&g_ImportExportDialog); + } + } + + return 0; +} + +struct menuitem g_ManageImportExportItems[] = { + { + MENUITEMTYPE_SELECTABLE, + MPSETUP_OP_IMPORT, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Import Settings\n", + 0, + menuhandlerOpenImportExportDialog, + }, + { + MENUITEMTYPE_SELECTABLE, + MPSETUP_OP_EXPORT, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Export Settings\n", + 0, + menuhandlerOpenImportExportDialog, + }, + { MENUITEMTYPE_END }, +}; + +struct menudialogdef g_ManageImportExportDialog = { + MENUDIALOGTYPE_DEFAULT, + (uintptr_t) "Import/Export\n", + g_ManageImportExportItems, + NULL, + MENUDIALOGFLAG_LITERAL_TEXT, + NULL, +}; + // #### Manage settings dialog struct menudialogdef g_ManageSetupDialog; MenuItemHandlerResult mpSelectSettingHandler(s32 operation, struct menuitem *item, union handlerdata *data) @@ -189,13 +455,13 @@ struct menuitem g_MpManageSettingsListItems[] = { }; -struct menudialogdef g_MpManageSettingsDialog = { +struct menudialogdef g_ManageSettingsDialog = { MENUDIALOGTYPE_DEFAULT, (uintptr_t) "Manage Settings\n", g_MpManageSettingsListItems, NULL, MENUDIALOGFLAG_LITERAL_TEXT, - NULL, + &g_ManageImportExportDialog, }; struct menudialogdef g_RenameSetupDialog; @@ -262,20 +528,61 @@ struct menudialogdef g_ManageSetupDialog = { NULL, }; -// ----------------------- -static size_t readStr(char *dst, char *src) +// #### Import: overwrite dialog +MenuItemHandlerResult menuhandlerImportAction(s32 operation, struct menuitem *item, union handlerdata *data) { - char *start = dst; - while (*src) { - *dst = *src; - dst++; - src++; + if (operation == MENUOP_SET) { + s32 err = importMpSetupFile(item->param, true); + if (!err) { + menuPopDialog(); + menuPushDialog(&g_ManageSettingsDialog); + } + else { + menuPushDialog(&g_StatusErrorDialog); + } } - *dst = '\0'; - dst++; - return dst - start; + + return 0; } +struct menuitem g_ImportOverrideItems[] = { + { + MENUITEMTYPE_LABEL, + 0, +// MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING | MENUITEMFLAG_SMALLFONT, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING, + (uintptr_t) "How to resolve setups\nwith the same name?\n", + 0, + NULL, + }, + { + MENUITEMTYPE_SELECTABLE, + MPSETUP_IMPORT_ADD, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG, + (uintptr_t) "Add\n", + 0, + menuhandlerImportAction, + }, + { + MENUITEMTYPE_SELECTABLE, + MPSETUP_IMPORT_OVERWRITE, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG, + (uintptr_t) "Overwrite\n", + 0, + menuhandlerImportAction, + }, + { MENUITEMTYPE_END }, +}; + +struct menudialogdef g_ImportOverrideDialog = { + MENUDIALOGTYPE_DEFAULT, + (uintptr_t)"Name Conflicts\n", + g_ImportOverrideItems, + NULL, + MENUDIALOGFLAG_LITERAL_TEXT, + NULL, +}; +// -------------------------------------------------------- static void mpsetupDeserialize(struct mpsetupfile *setupfile, u8 *buffer) { BUF_READ(setupfile->version, buffer, u8); @@ -299,7 +606,7 @@ void mpsetupSerialize(u8 *buffer, struct mpsetupfile *setupfile) } } -static s32 mpsetupSaveFile(); +static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile); static s32 deleteSetup() { s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex; @@ -318,23 +625,39 @@ static s32 deleteSetup() } g_MpSetupFile.numsetups--; - return mpsetupSaveFile(); + return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile); } -static FILE *openMpSetupFile(u8 mode) { +static FILE *openMpSetupFile(u8 mode, u8 op) { + const char *filename = fsFullPath("$S/" MPSETUP_FILENAME ".bin"); + + if (op == MPSETUP_OP_EXPORT) { + // create export directory if it doesn't exist + if (fsFileSize(MPSETUP_EXPORTDIR) < 0) { + if (fsCreateDir(MPSETUP_EXPORTDIR) != 0) { + return NULL; + } + } + filename = fsFullPath(MPSETUP_EXPORTDIR MPSETUP_FILENAME_EXP ".bin"); + } + else if (op == MPSETUP_OP_IMPORT) { + // same name as export but different folder + filename = fsFullPath("$S/" MPSETUP_FILENAME_EXP ".bin"); + } + FILE *f; - if (fsFileSize(MPSETUP_FILE) < 0) { + if (fsFileSize(filename) < 0) { // setup file doesn't exist: create one - f = fsFileOpenWrite(MPSETUP_FILE); + f = fsFileOpenWrite(filename); fsFileFree(f); } if (mode == 'r') { - f = fsFileOpenRead(MPSETUP_FILE); + f = fsFileOpenRead(filename); } else if (mode == 'w') { - f = fsFileOpenWrite(MPSETUP_FILE); + f = fsFileOpenWrite(filename); } else { sysLogPrintf(LOG_ERROR, "openMpSetupFile: invalid file mode"); @@ -349,14 +672,9 @@ static FILE *openMpSetupFile(u8 mode) { return f; } -void zeroFileBuffer() +s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op) { - memset(filebuffer, 0, sizeof(struct mpsetupfile)); -} - -s32 mpsetupLoadFile() -{ - FILE *f = openMpSetupFile('r'); + FILE *f = openMpSetupFile('r', op); if (f == NULL) { return -1; } @@ -369,10 +687,10 @@ s32 mpsetupLoadFile() fread(filebuffer, 1, size, f); - mpsetupDeserialize(&g_MpSetupFile, filebuffer); + mpsetupDeserialize(setupfile, filebuffer); - if (g_MpSetupFile.defaultsetup != 0) { - g_MpCurrentSetup = g_MpSetupFile.defaultsetup; + if (op == MPSETUP_OP_DEFAULT && setupfile->defaultsetup != 0) { + g_MpCurrentSetup = setupfile->defaultsetup; } fsFileFree(f); @@ -380,21 +698,99 @@ s32 mpsetupLoadFile() return 0; } -static s32 mpsetupSaveFile() +s32 mpsetupLoadCurrentSetupFile() +{ + return mpsetupLoadFile(&g_MpSetupFile, MPSETUP_OP_DEFAULT); +} + +s32 importMpSetupFile(u8 op, u8 skipOverlap) +{ + if (!skipOverlap) { + // check for names overlap + u8 overlap = false; + for (int i = 0; i < g_ImportMpSetupFile.numsetups; ++i) { + for (int j = 0; j < g_MpSetupFile.numsetups; ++j) { + if (strcmp(g_ImportMpSetupFile.setups[i].bytes, g_MpSetupFile.setups[j].bytes) == 0) { + overlap = true; + return MPSETUP_IMPORT_CONFLICT; + } + } + } + } + + for (int i = 0; i < g_ImportMpSetupFile.numsetups; ++i) { + s16 overlapIdx = -1; + for (int j = g_MpSetupFile.numsetups-1; j >= 0; --j) { + if (strcmp(g_ImportMpSetupFile.setups[i].bytes, g_MpSetupFile.setups[j].bytes) == 0) { + overlapIdx = j; + break; + } + } + + s16 importIdx = overlapIdx; + if (overlapIdx < 0 || op == MPSETUP_IMPORT_ADD) { + if (g_MpSetupFile.numsetups == MPSETUP_MAXSETUPS) { + sprintf(g_StatusText, "Number of setups exceeds %d\n", MPSETUP_MAXSETUPS); + return -1; + } + importIdx = g_MpSetupFile.numsetups++; + } + + memcpy(g_MpSetupFile.setups[importIdx].bytes, g_ImportMpSetupFile.setups[i].bytes, MPSETUP_BLOCKSIZE); + } + + return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile); +} + +s32 exportMpSetupFile() +{ + struct mpsetupfile expMpSetupFile; + expMpSetupFile.numsetups = 0; + + u8 maxsetups = g_MpImportExportFilter[1] == 0 ? 64 : 128; + maxsetups = MIN(maxsetups, g_MpSetupFile.numsetups); + for (int i = 0; i < maxsetups; ++i) { + u8 bank = i < 64 ? 0 : 1; + u8 bit = i - bank * 64; + if (g_MpImportExportFilter[bank] & (1 << bit)) { + u8 n = expMpSetupFile.numsetups; + expMpSetupFile.numsetups++; + char *name = g_MpSetupFile.setups[i].bytes; + sysLogPrintf(LOG_NOTE, "%s", name); + memcpy(expMpSetupFile.setups[n].bytes, g_MpSetupFile.setups[i].bytes, MPSETUP_BLOCKSIZE); + expMpSetupFile.numsetups = n + 1; + } + } + + s32 err = mpsetupSaveFile(MPSETUP_OP_EXPORT, &expMpSetupFile); + if (err) { + sprintf(g_StatusText, "Unable to write\nsetup file\n"); + } + + return err; +} + +static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile) { zeroFileBuffer(); - mpsetupSerialize(filebuffer, &g_MpSetupFile); + mpsetupSerialize(filebuffer, setupfile); - FILE *f = openMpSetupFile('w'); + FILE *f = openMpSetupFile('w', op); if (f == NULL) { return -1; } - fwrite(filebuffer, sizeof(struct mpsetupfile), 1, f); + size_t nwritten = fwrite(filebuffer, sizeof(struct mpsetupfile), 1, f); + if (nwritten < 1) { + fsFileFree(f); + sysLogPrintf(LOG_ERROR, "Unable to write the MP setup file"); + return -1; + } + fsFileFree(f); // reload the file to update in-memory structs - return mpsetupLoadFile(); + return mpsetupLoadFile(&g_MpSetupFile, MPSETUP_OP_DEFAULT); } s32 mpsetupSaveSetup(s32 slotindex) @@ -411,7 +807,7 @@ s32 mpsetupSaveSetup(s32 slotindex) memcpy(g_MpSetupFile.setups[slotindex].bytes, &setup.bytes, MPSETUP_BLOCKSIZE); - return mpsetupSaveFile(); + return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile); } void mpsetupLoadSetup(s32 index) diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index 2f129d7b4..694b72649 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -33,7 +33,7 @@ struct menudialogdef g_MpChangeTeamNameMenuDialog; struct menudialogdef g_MpEditSimulantMenuDialog; struct menudialogdef g_MpSaveSetupNameMenuDialog; -extern struct menudialogdef g_MpManageSettingsDialog; +extern struct menudialogdef g_ManageSettingsDialog; extern struct menudialogdef g_FilemgrFileSavedMenuDialog; extern struct menudialogdef g_FilemgrErrorMenuDialog; @@ -5360,7 +5360,7 @@ MenuDialogHandlerResult menudialogCombatSimulator(s32 operation, struct menudial g_Vars.waitingtojoin[3] = false; // load the setup file when entering the Combat Simulator - mpsetupLoadFile(); + mpsetupLoadCurrentSetupFile(); } if (g_Menus[g_MpPlayerNum].curdialog @@ -5759,7 +5759,7 @@ struct menuitem g_MpAdvancedSetupMenuItems[] = { MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_OPENSDIALOG | MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LOCKABLEMAJOR, (uintptr_t)"Manage Settings\n", 0, - (void *)&g_MpManageSettingsDialog, + (void *)&g_ManageSettingsDialog, }, { MENUITEMTYPE_SELECTABLE, From 9e19055348eb07383ffccb483ac1d892f091c516 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Sat, 29 Mar 2025 04:17:36 +0800 Subject: [PATCH 13/34] mpsetups: fixed bugs caused by using a wrong constant + fixed the setup marquee display --- src/game/mplayer/mplayer.c | 8 ++++---- src/game/mplayer/scenarios.c | 2 +- src/game/mplayer/setup.c | 9 ++++++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index a9ea46998..c324afb47 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -3918,7 +3918,7 @@ void mpsetupfileLoadWad(struct savebuffer *buffer) s32 i; s32 j; - savebufferReadString_ext(buffer, g_MpSetup.name, false, MPSETUP_MAXSETUPS+1); + savebufferReadString_ext(buffer, g_MpSetup.name, false, MPSETUP_MAXNAME+1); savebufferReadBits(buffer, 4); g_MpSetup.stagenum = savebufferReadBits(buffer, 7); @@ -3973,7 +3973,7 @@ void mpsetupfileSaveWad(struct savebuffer *buffer) s32 mpbodynum; s32 i; - func0f0d55a4_ext(buffer, g_MpSetup.name, MPSETUP_MAXSETUPS+1); + func0f0d55a4_ext(buffer, g_MpSetup.name, MPSETUP_MAXNAME+1); for (i = 0; i < MAX_BOTS; i++) { if (g_MpSetup.chrslots & (1 << (i + 4))) { @@ -4033,9 +4033,9 @@ void mpsetupfileGetOverview(char *arg0, char *filename, u16 *numsims, u16 *stage { struct savebuffer buffer; - savebufferWriteData(&buffer, arg0, 15); + savebufferWriteData(&buffer, arg0, 22); - savebufferReadString(&buffer, filename, 0); + savebufferReadString_ext(&buffer, filename, 0, MPSETUP_MAXNAME+1); *numsims = savebufferReadBits(&buffer, 4); *stagenum = savebufferReadBits(&buffer, 7); diff --git a/src/game/mplayer/scenarios.c b/src/game/mplayer/scenarios.c index f7a504382..0c4df1f51 100644 --- a/src/game/mplayer/scenarios.c +++ b/src/game/mplayer/scenarios.c @@ -421,7 +421,7 @@ void scenarioReadSave(struct savebuffer *buffer) if (g_MpScenarios[g_MpSetup.scenario].readsavefunc) { g_MpScenarios[g_MpSetup.scenario].readsavefunc(buffer); } else { - savebufferReadBits(buffer, 8); + savebufferReadBits(buffer, 32); } } diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index 694b72649..02ec00730 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -2262,7 +2262,7 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * } if (g_MpSetupFile.numsetups > 0) { struct setupblock *block = &g_MpSetupFile.setups[data->list.value - mpGetNumUnlockedPresets()]; - func0f0d564c_ext(block->bytes, g_StringPointer, false, MPSETUP_MAXSETUPS+1); + func0f0d564c_ext(block->bytes, g_StringPointer, false, MPSETUP_MAXNAME+1); return (uintptr_t)g_StringPointer; } break; @@ -2303,6 +2303,9 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * if (data->list.value < mpGetNumUnlockedPresets()) { g_Menus[g_MpPlayerNum].mpsetup.slotindex = 0xffff; } + else { + g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value - mpGetNumUnlockedPresets(); + } break; } @@ -2318,14 +2321,14 @@ char *mpMenuTextMpconfigMarquee(struct menuitem *item) s32 arenanum; s32 i; - if (g_Menus[g_MpPlayerNum].mpsetup.slotindex < 0xffff && g_FileLists[1]) { + if (g_Menus[g_MpPlayerNum].mpsetup.slotindex < 0xffff && g_MpSetupFile.numsetups > 0) { #if VERSION >= VERSION_NTSC_1_0 arenanum = -1; #else arenanum = 0; #endif - mpsetupfileGetOverview(g_FileLists[1]->files[g_Menus[g_MpPlayerNum].mpsetup.slotindex].name, + mpsetupfileGetOverview(g_MpSetupFile.setups[g_Menus[g_MpPlayerNum].mpsetup.slotindex].bytes, filename, &numsims, &stagenum, &scenarionum); for (i = 0; i < ARRAYCOUNT(g_MpArenas); i++) { From dace9fd634ff2f2c117e3eb18b04c3223292a42a Mon Sep 17 00:00:00 2001 From: peerchemist Date: Sat, 29 Mar 2025 11:02:55 +0100 Subject: [PATCH 14/34] x86_64 --- dist/linux/io.github.fgsfdsfgs.perfect_dark.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/linux/io.github.fgsfdsfgs.perfect_dark.sh b/dist/linux/io.github.fgsfdsfgs.perfect_dark.sh index 719a7fbee..28ff8213b 100644 --- a/dist/linux/io.github.fgsfdsfgs.perfect_dark.sh +++ b/dist/linux/io.github.fgsfdsfgs.perfect_dark.sh @@ -16,7 +16,7 @@ if [ -f ${XDG_DATA_HOME}/roms/pd.ntsc-final.z64 ] | \ [ -f ${XDG_DATA_HOME}/roms/pd.ntsc-1.0.z64 ]; then executable="pd.x86_64" elif [ -f ${XDG_DATA_HOME}/roms/pd.jpn-final.z64 ]; then - executable="pd.jpn.x" + executable="pd.jpn.x86_64" elif [ -f ${XDG_DATA_HOME}/roms/pd.pal-final.z64 ]; then executable="pd.pal.x86_64" fi From 9a853077a0b87bd9c057b5905edc755b889a49e0 Mon Sep 17 00:00:00 2001 From: peerchemist Date: Sat, 29 Mar 2025 11:15:57 +0100 Subject: [PATCH 15/34] correct Exec name --- dist/linux/io.github.fgsfdsfgs.perfect_dark.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/linux/io.github.fgsfdsfgs.perfect_dark.desktop b/dist/linux/io.github.fgsfdsfgs.perfect_dark.desktop index 663933b7e..94c45ca9c 100755 --- a/dist/linux/io.github.fgsfdsfgs.perfect_dark.desktop +++ b/dist/linux/io.github.fgsfdsfgs.perfect_dark.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Name=Perfect Dark Comment=Modern source port of Perfect Dark -Exec=pd +Exec=io.github.fgsfdsfgs.perfect_dark.sh Icon=io.github.fgsfdsfgs.perfect_dark Terminal=false Type=Application From a1d6916871be190e61cedc15171cf10689ddfe8c Mon Sep 17 00:00:00 2001 From: Raf <> Date: Sat, 29 Mar 2025 04:19:46 +0800 Subject: [PATCH 16/34] mpsetups: manage default setup + save the selected random weapons --- port/include/mpsetups.h | 3 +- port/src/mpsetups.c | 72 ++++++++++++++++++++++++++++++++------ src/game/mplayer/mplayer.c | 23 ++++++++++++ src/game/mplayer/setup.c | 2 +- 4 files changed, 87 insertions(+), 13 deletions(-) diff --git a/port/include/mpsetups.h b/port/include/mpsetups.h index c2a24056f..9a2b2f58a 100644 --- a/port/include/mpsetups.h +++ b/port/include/mpsetups.h @@ -3,7 +3,8 @@ #include "types.h" -s32 mpsetupLoadCurrentSetupFile(); +s32 mpsetupLoadCurrentFile(); +s32 mpsetupSaveCurrentFile(); void mpsetupLoadSetup(s32 slotindex); s32 mpsetupSaveSetup(s32 slotindex); diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index 27eb82c6b..a1c9d658d 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -421,9 +421,17 @@ struct menudialogdef g_ManageImportExportDialog = { // #### Manage settings dialog struct menudialogdef g_ManageSetupDialog; -MenuItemHandlerResult mpSelectSettingHandler(s32 operation, struct menuitem *item, union handlerdata *data) +char g_LabelSetDefault[20] = "Set Default\n"; +MenuItemHandlerResult mpSelectSetupHandler(s32 operation, struct menuitem *item, union handlerdata *data) { switch (operation) { + case MENUOP_GETCOLOUR: { + u32 colour = data->list.unk04; + if (data->list.value + 1 == g_MpSetupFile.defaultsetup) { + data->list.unk04 = (colour & 0xffff0000) | 0xff; + } + break; + } case MENUOP_GETOPTIONCOUNT: data->list.value = g_MpSetupFile.numsetups; break; @@ -432,6 +440,12 @@ MenuItemHandlerResult mpSelectSettingHandler(s32 operation, struct menuitem *ite case MENUOP_SET: { g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value; + if (data->list.value == g_MpSetupFile.defaultsetup - 1) { + strcpy(g_LabelSetDefault, "Clear Default\n"); + } + else { + strcpy(g_LabelSetDefault, "Set Default\n"); + } menuPushDialog(&g_ManageSetupDialog); } case MENUOP_GETSELECTEDINDEX: @@ -446,10 +460,10 @@ struct menuitem g_MpManageSettingsListItems[] = { { MENUITEMTYPE_LIST, 0, - 0, + MENUITEMFLAG_LABEL_CUSTOMCOLOUR, 160, 0x00000042, - mpSelectSettingHandler, + mpSelectSetupHandler, }, { MENUITEMTYPE_END }, @@ -483,6 +497,25 @@ static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuit return 0; } +static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct menuitem *item, union handlerdata *data) +{ + if (operation == MENUOP_SET) { + s32 selected = g_Menus[g_MpPlayerNum].mpsetup.slotindex; + if (selected == g_MpSetupFile.defaultsetup - 1) { + strcpy(g_LabelSetDefault, "Set Default\n"); + g_MpSetupFile.defaultsetup = -1; + } + else { + strcpy(g_LabelSetDefault, "Clear Default\n"); + g_MpSetupFile.defaultsetup = selected + 1; + } + + mpsetupSaveCurrentFile(); + } + + return 0; +} + struct menuitem g_ManageSetupItems[] = { { MENUITEMTYPE_SELECTABLE, @@ -500,6 +533,14 @@ struct menuitem g_ManageSetupItems[] = { 0, menuhandlerSetupDelete, }, + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)g_LabelSetDefault, + 0, + menuhandlerSetupSetDefault, + }, { MENUITEMTYPE_SEPARATOR, 0, @@ -624,8 +665,12 @@ static s32 deleteSetup() g_MpCurrentSetup = -1; } + if (g_MpSetupFile.defaultsetup == slotindex + 1) { + g_MpSetupFile.defaultsetup = 0; + } + g_MpSetupFile.numsetups--; - return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile); + return mpsetupSaveCurrentFile(); } static FILE *openMpSetupFile(u8 mode, u8 op) { @@ -689,8 +734,8 @@ s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op) mpsetupDeserialize(setupfile, filebuffer); - if (op == MPSETUP_OP_DEFAULT && setupfile->defaultsetup != 0) { - g_MpCurrentSetup = setupfile->defaultsetup; + if (op == MPSETUP_OP_DEFAULT && setupfile->defaultsetup > 0) { + mpsetupLoadSetup(setupfile->defaultsetup - 1); } fsFileFree(f); @@ -698,11 +743,16 @@ s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op) return 0; } -s32 mpsetupLoadCurrentSetupFile() +s32 mpsetupLoadCurrentFile() { return mpsetupLoadFile(&g_MpSetupFile, MPSETUP_OP_DEFAULT); } +s32 mpsetupSaveCurrentFile() +{ + return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile); +} + s32 importMpSetupFile(u8 op, u8 skipOverlap) { if (!skipOverlap) { @@ -739,7 +789,7 @@ s32 importMpSetupFile(u8 op, u8 skipOverlap) memcpy(g_MpSetupFile.setups[importIdx].bytes, g_ImportMpSetupFile.setups[i].bytes, MPSETUP_BLOCKSIZE); } - return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile); + return mpsetupSaveCurrentFile(); } s32 exportMpSetupFile() @@ -790,7 +840,7 @@ static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile) fsFileFree(f); // reload the file to update in-memory structs - return mpsetupLoadFile(&g_MpSetupFile, MPSETUP_OP_DEFAULT); + return mpsetupLoadCurrentFile(); } s32 mpsetupSaveSetup(s32 slotindex) @@ -805,9 +855,9 @@ s32 mpsetupSaveSetup(s32 slotindex) savebufferClear(&setup); mpsetupfileSaveWad(&setup); - memcpy(g_MpSetupFile.setups[slotindex].bytes, &setup.bytes, MPSETUP_BLOCKSIZE); + memcpy(g_MpSetupFile.setups[slotindex].bytes, setup.bytes, MPSETUP_BLOCKSIZE); - return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile); + return mpsetupSaveCurrentFile(); } void mpsetupLoadSetup(s32 index) diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index c324afb47..a8629c8e4 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -3913,6 +3913,23 @@ void mp0f18dec4(s32 slot) #endif } +static u64 packWeaponSetRandomFilters() +{ + u64 packed = 0; + for (int i = 0; i < NUM_MPWEAPONS; ++i) { + packed |= g_MpWeaponSetRandomFilters[i] != 0 ? (1 << i) : 0; + } + + return packed; +} + +static void unpackWeaponSetRandomFilters(u64 packed) +{ + for (int i = 0; i < NUM_MPWEAPONS; ++i) { + g_MpWeaponSetRandomFilters[i] = (packed & (1 << i)) >> i; + } +} + void mpsetupfileLoadWad(struct savebuffer *buffer) { s32 i; @@ -3954,6 +3971,9 @@ void mpsetupfileLoadWad(struct savebuffer *buffer) g_MpSetup.weapons[i] = savebufferReadBits(buffer, 7); } + u64 wpnRndPacked = savebufferReadBits(buffer, 64); + unpackWeaponSetRandomFilters(wpnRndPacked); + func0f18913c(); g_MpSetup.timelimit = savebufferReadBits(buffer, 6); @@ -4020,6 +4040,9 @@ void mpsetupfileSaveWad(struct savebuffer *buffer) savebufferOr(buffer, g_MpSetup.weapons[i], 7); } + u64 wpnRndPacked = packWeaponSetRandomFilters(); + savebufferOr(buffer, wpnRndPacked, 64); + savebufferOr(buffer, g_MpSetup.timelimit, 6); savebufferOr(buffer, g_MpSetup.scorelimit, 7); savebufferOr(buffer, g_MpSetup.teamscorelimit, 9); diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index 02ec00730..a70087eda 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -5363,7 +5363,7 @@ MenuDialogHandlerResult menudialogCombatSimulator(s32 operation, struct menudial g_Vars.waitingtojoin[3] = false; // load the setup file when entering the Combat Simulator - mpsetupLoadCurrentSetupFile(); + mpsetupLoadCurrentFile(); } if (g_Menus[g_MpPlayerNum].curdialog From be4d8330bd32a490ad58b9e90c85a67a280fb28a Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 29 Mar 2025 12:29:14 +0100 Subject: [PATCH 17/34] port: add settings for HIDAPI and raw input --- port/src/input.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/port/src/input.c b/port/src/input.c index 7475c2b2b..ce6f4b5b9 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -74,6 +74,9 @@ static s32 connectedMask = 0; static s32 numJoysticks = 0; +static s32 useHIDAPI = 1; +static s32 useRawInput = 1; + static s32 mouseEnabled = 1; static s32 mouseX, mouseY; static s32 mouseDX, mouseDY; @@ -674,24 +677,29 @@ static inline void inputLoadBinds(void) s32 inputInit(void) { + // Set SDL hints before initializing the controller subsystem. + if (useHIDAPI) { + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1"); + // the two hints below enable Rumble and Motion Sensor for PS4/5 pads connected via bluetooth + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + } + if (useRawInput) { + SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT, "1"); + } + if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC)) { SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC); } - // Set SDL hints before loading controller mappings - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); // Enables Rumble and Motion Sensor functionality when under Bluetooth connectivity. - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); // same case as PS4_Rumble hint. - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT, "1"); - // try to load controller db from an external file in the save folder if (fsFileSize("$S/" CONTROLLERDB_FNAME)) { const char *dbpath = fsFullPath("$S/" CONTROLLERDB_FNAME); @@ -1496,6 +1504,8 @@ PD_CONSTRUCTOR static void inputConfigInit(void) configRegisterFloat("Input.MouseSpeedY", &mouseSensY, -10.f, 10.f); configRegisterInt("Input.FakeGamepads", &fakeControllers, 0, 4); configRegisterInt("Input.FirstGamepadNum", &firstController, 0, 3); + configRegisterInt("Input.UseHIDAPI", &useHIDAPI, 0, 1); + configRegisterInt("Input.UseRawInput", &useRawInput, 0, 1); char secname[] = "Input.Player1.Binds"; char keyname[256] = { 0 }; From e32d719c16cbd487d460aab0944b1548c8ee3ed6 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 29 Mar 2025 12:48:38 +0100 Subject: [PATCH 18/34] port: only enable SDL hints on SDL versions that support them --- port/src/input.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/port/src/input.c b/port/src/input.c index ce6f4b5b9..2bacbd646 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -679,17 +679,30 @@ s32 inputInit(void) { // Set SDL hints before initializing the controller subsystem. if (useHIDAPI) { - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); +#if SDL_VERSION_ATLEAST(2, 0, 12) + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, "1"); +#endif +#if SDL_VERSION_ATLEAST(2, 0, 14) SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5, "1"); +#endif +#if SDL_VERSION_ATLEAST(2, 0, 22) + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1"); // the two hints below enable Rumble and Motion Sensor for PS4/5 pads connected via bluetooth SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); +#endif +#if SDL_VERSION_ATLEAST(2, 23, 2) + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "1"); +#endif +#if SDL_VERSION_ATLEAST(2, 25, 1) + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1"); +#endif +#if SDL_VERSION_ATLEAST(2, 26, 0) + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1"); +#endif } if (useRawInput) { SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "1"); From edd58c8925946b28e3b771b2b5eb8e92e9197197 Mon Sep 17 00:00:00 2001 From: Jonaeru Date: Sun, 30 Mar 2025 22:31:51 +0900 Subject: [PATCH 19/34] Fix offset in weapon set by adding IR Scanner and Night Vision --- port/src/preprocess/misc.c | 12 ++++++++++-- src/include/constants.h | 28 +++++++++++++++------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/port/src/preprocess/misc.c b/port/src/preprocess/misc.c index c3361e90b..23e345266 100644 --- a/port/src/preprocess/misc.c +++ b/port/src/preprocess/misc.c @@ -57,18 +57,26 @@ u8 *preprocessMpConfigs(u8* data, u32 size, u32* outSize) for (s32 j = 0; j < ARRAYCOUNT(cfg->setup.weapons); ++j) { #if VERSION == VERSION_JPN_FINAL /* TODO: replace with runtime check */ if (cfg->setup.weapons[j] >= 0x24) { - // weapons after and including the shield need to be shifted + // weapons after and including the shield need to be shifted (for classic weapons) cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I); } + if (cfg->setup.weapons[j] >= 0x22) { + // weapons after and including the cloaking device need to be shifted (for IR Scanner and Night Vision) + cfg->setup.weapons[j] += (MPWEAPON_CLOAKINGDEVICE - MPWEAPON_NIGHTVISION); + } if (cfg->setup.weapons[j] >= 0x19) { // weapons after the combat knife also need to be shifted up in JPN cfg->setup.weapons[j]++; } #else - // in other versions we only care about the shield and above if (cfg->setup.weapons[j] >= 0x25) { + // weapons after and including the shield need to be shifted (for classic weapons) cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I); } + if (cfg->setup.weapons[j] >= 0x23) { + // weapons after and including the cloaking device need to be shifted (for IR Scanner and Night Vision) + cfg->setup.weapons[j] += (MPWEAPON_CLOAKINGDEVICE - MPWEAPON_NIGHTVISION); + } #endif } } diff --git a/src/include/constants.h b/src/include/constants.h index 32452ddab..2ff7b0658 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -2993,7 +2993,7 @@ #define MPWEAPON_SHIELD (VERSION == VERSION_JPN_FINAL ? 0x24 : 0x25) #define MPWEAPON_DISABLED (VERSION == VERSION_JPN_FINAL ? 0x25 : 0x26) #define NUM_MPWEAPONS (VERSION == VERSION_JPN_FINAL ? 0x26 : 0x27) -#else // add all classic weapons to multiplayer and allow combat knife in JPN +#else // add all classic weapons to multiplayer and allow combat knife in JPN and add IR Scanner and Night Vision #define MPWEAPON_COMBATKNIFE 0x19 #define MPWEAPON_CROSSBOW 0x1a #define MPWEAPON_TRANQUILIZER 0x1b @@ -3004,18 +3004,20 @@ #define MPWEAPON_REMOTEMINE 0x20 #define MPWEAPON_LASER 0x21 #define MPWEAPON_XRAYSCANNER 0x22 -#define MPWEAPON_CLOAKINGDEVICE 0x23 -#define MPWEAPON_COMBATBOOST 0x24 -#define MPWEAPON_PP9I 0x25 -#define MPWEAPON_CC13 0x26 -#define MPWEAPON_KL01313 0x27 -#define MPWEAPON_KF7SPECIAL 0x28 -#define MPWEAPON_ZZT 0x29 -#define MPWEAPON_DMC 0x2a -#define MPWEAPON_AR53 0x2b -#define MPWEAPON_RCP45 0x2c -#define MPWEAPON_SHIELD 0x2d -#define MPWEAPON_DISABLED 0x2e +#define MPWEAPON_NIGHTVISION 0x23 +#define MPWEAPON_IRSCANNER 0x24 +#define MPWEAPON_CLOAKINGDEVICE 0x25 +#define MPWEAPON_COMBATBOOST 0x26 +#define MPWEAPON_PP9I 0x27 +#define MPWEAPON_CC13 0x28 +#define MPWEAPON_KL01313 0x29 +#define MPWEAPON_KF7SPECIAL 0x2a +#define MPWEAPON_ZZT 0x2b +#define MPWEAPON_DMC 0x2c +#define MPWEAPON_AR53 0x2d +#define MPWEAPON_RCP45 0x2e +#define MPWEAPON_SHIELD 0x2f +#define MPWEAPON_DISABLED 0x30 #define NUM_MPWEAPONS 0x31 #endif From 33c5194a1bf4be610155d56f5d7b30b8f2d7f560 Mon Sep 17 00:00:00 2001 From: Jonaeru Date: Sun, 30 Mar 2025 22:48:14 +0900 Subject: [PATCH 20/34] Fix "Select Dark" in Select Random Weapons feature to not select IR Scanner and Night Vision --- src/game/mplayer/setup.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index cae26d3c7..962d05392 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -1214,7 +1214,10 @@ MenuItemHandlerResult mpSelectRandomWeaponListHandler(s32 operation, struct menu case 0: // Select Dark for (i = 0; i < ARRAYCOUNT(g_MpWeapons); i++) { - if ((i >= MPWEAPON_NONE && i <= MPWEAPON_COMBATBOOST) || i >= MPWEAPON_SHIELD) { + if ((i >= MPWEAPON_NONE && i <= MPWEAPON_XRAYSCANNER) + || i == MPWEAPON_CLOAKINGDEVICE + || i == MPWEAPON_COMBATBOOST + || i >= MPWEAPON_SHIELD) { g_MpWeaponSetRandomFilters[i] = 1; } else { g_MpWeaponSetRandomFilters[i] = 0; From 4d4fa8f68104b50d7071716b7ef66fb0cc3487a5 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Sun, 30 Mar 2025 23:21:52 +0800 Subject: [PATCH 21/34] savebuffer: extended read/write to accept 64 bits, renamed a function, removed an unused function --- src/game/bossfile.c | 6 +----- src/game/gamefile.c | 6 +----- src/game/mplayer/mplayer.c | 14 +++++-------- src/game/savebuffer.c | 33 ++++++++++++------------------ src/include/game/mplayer/mplayer.h | 2 +- src/include/game/savebuffer.h | 11 +++++----- 6 files changed, 26 insertions(+), 46 deletions(-) diff --git a/src/game/bossfile.c b/src/game/bossfile.c index 9c8e99705..0a9690bed 100644 --- a/src/game/bossfile.c +++ b/src/game/bossfile.c @@ -138,8 +138,6 @@ void bossfileLoad(void) g_BossFile.usingmultipletunes = savebufferReadBits(&buffer, 1); g_AltTitleUnlocked = savebufferReadBits(&buffer, 1); g_AltTitleEnabled = savebufferReadBits(&buffer, 1); - - func0f0d54c4(&buffer); } if (failed) { @@ -168,7 +166,7 @@ void bossfileSave(void) savebufferOr(&buffer, g_Vars.language, 4); for (i = 0; i < ARRAYCOUNT(g_BossFile.teamnames); i++) { - func0f0d55a4(&buffer, g_BossFile.teamnames[i]); + savebufferWriteString(&buffer, g_BossFile.teamnames[i]); } if (g_BossFile.tracknum == -1) { @@ -185,8 +183,6 @@ void bossfileSave(void) savebufferOr(&buffer, g_AltTitleUnlocked, 1); savebufferOr(&buffer, g_AltTitleEnabled, 1); - func0f0d54c4(&buffer); - fileid = bossfileFindFileId(); if (fileid == 0) { diff --git a/src/game/gamefile.c b/src/game/gamefile.c index e17411d6b..ed6ac2c98 100644 --- a/src/game/gamefile.c +++ b/src/game/gamefile.c @@ -395,8 +395,6 @@ s32 gamefileLoad(s32 device) frSetWeaponFound(WEAPON_REMOTEMINE); } #endif - - func0f0d54c4(&buffer); gamefileApplyOptions(&g_GameFile); return 0; @@ -499,7 +497,7 @@ s32 gamefileSave(s32 device, s32 fileid, u16 deviceserial) if (device >= 0) { savebufferClear(&buffer); - func0f0d55a4(&buffer, g_GameFile.name); + savebufferWriteString(&buffer, g_GameFile.name); savebufferOr(&buffer, g_GameFile.thumbnail, 5); savebufferOr(&buffer, g_GameFile.totaltime, 32); @@ -556,8 +554,6 @@ s32 gamefileSave(s32 device, s32 fileid, u16 deviceserial) savebufferOr(&buffer, g_GameFile.weaponsfound[i], 8); } - func0f0d54c4(&buffer); - ret = pakSaveAtGuid(device, fileid, PAKFILETYPE_GAME, buffer.bytes, &newfileid, 0); g_FilemgrLastPakError = ret; diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index a8629c8e4..69facd19f 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -3533,7 +3533,7 @@ void mpplayerfileSaveWad(s32 playernum, struct savebuffer *buffer) s32 j; u32 stack; - func0f0d55a4(buffer, g_PlayerConfigsArray[playernum].base.name); + savebufferWriteString(buffer, g_PlayerConfigsArray[playernum].base.name); if (g_PlayerConfigsArray[playernum].time > 0x0fffffff) { // over 3106 days g_PlayerConfigsArray[playernum].time = 0x0fffffff; @@ -3684,8 +3684,6 @@ s32 mpplayerfileSave(s32 playernum, s32 device, s32 fileid, u16 deviceserial) if (device >= 0) { savebufferClear(&buffer); mpplayerfileSaveWad(playernum, &buffer); - func0f0d54c4(&buffer); - var80075bd0[2] = true; ret = pakSaveAtGuid(device, fileid, PAKFILETYPE_MPPLAYER, buffer.bytes, &newfileid, 0); @@ -3718,8 +3716,6 @@ s32 mpplayerfileLoad(s32 playernum, s32 device, s32 fileid, u16 deviceserial) g_PlayerConfigsArray[playernum].fileguid.deviceserial = deviceserial; mpplayerfileLoadWad(playernum, &buffer, 1); - func0f0d54c4(&buffer); - g_PlayerConfigsArray[playernum].handicap = 0x80; return 0; } @@ -3917,7 +3913,7 @@ static u64 packWeaponSetRandomFilters() { u64 packed = 0; for (int i = 0; i < NUM_MPWEAPONS; ++i) { - packed |= g_MpWeaponSetRandomFilters[i] != 0 ? (1 << i) : 0; + packed |= g_MpWeaponSetRandomFilters[i] != 0 ? (1LL << i) : 0; } return packed; @@ -3926,11 +3922,11 @@ static u64 packWeaponSetRandomFilters() static void unpackWeaponSetRandomFilters(u64 packed) { for (int i = 0; i < NUM_MPWEAPONS; ++i) { - g_MpWeaponSetRandomFilters[i] = (packed & (1 << i)) >> i; + g_MpWeaponSetRandomFilters[i] = (packed & (1LL << i)) != 0; } } -void mpsetupfileLoadWad(struct savebuffer *buffer) +void mpsetupfileLoadWad(struct savebuffer *buffer, u8 version) { s32 i; s32 j; @@ -3993,7 +3989,7 @@ void mpsetupfileSaveWad(struct savebuffer *buffer) s32 mpbodynum; s32 i; - func0f0d55a4_ext(buffer, g_MpSetup.name, MPSETUP_MAXNAME+1); + savebufferWriteString_ext(buffer, g_MpSetup.name, MPSETUP_MAXNAME + 1); for (i = 0; i < MAX_BOTS; i++) { if (g_MpSetup.chrslots & (1 << (i + 4))) { diff --git a/src/game/savebuffer.c b/src/game/savebuffer.c index 0dc22dee5..6a9bcf581 100644 --- a/src/game/savebuffer.c +++ b/src/game/savebuffer.c @@ -374,13 +374,13 @@ Gfx *menugfxDrawPlane(Gfx *gdl, s32 x1, s32 y1, s32 x2, s32 y2, u32 colour1, u32 /** * Write the specified amount of bits to the buffer, advancing the internal pointer. * - * numbits is expected to be 32 or less. + * numbits is expected to be 64 or less. * * This function only sets bits to on and does not unset them. */ -void savebufferOr(struct savebuffer *buffer, u32 value, s32 numbits) +void savebufferOr(struct savebuffer *buffer, u64 value, s32 numbits) { - u32 bit = 1 << (numbits - 1); + u64 bit = 1LL << (numbits - 1LL); for (; bit; bit >>= 1) { if (bit & value) { @@ -399,11 +399,11 @@ void savebufferOr(struct savebuffer *buffer, u32 value, s32 numbits) /** * Write the specified amount of bits to the buffer, advancing the internal pointer. * - * numbits is expected to be 32 or less. + * numbits is expected to be 64 or less. */ -void savebufferWriteBits(struct savebuffer *buffer, u32 value, s32 numbits, u8 *dst) +void savebufferWriteBits(struct savebuffer *buffer, u64 value, s32 numbits, u8 *dst) { - u32 bit = 1 << (numbits - 1); + u64 bit = 1LL << (numbits - 1); for (; bit; bit >>= 1) { s32 bitindex = buffer->bitpos % 8; @@ -425,12 +425,12 @@ void savebufferWriteBits(struct savebuffer *buffer, u32 value, s32 numbits, u8 * * Read the specified amount of bits from the buffer and return it as an * integer, advancing the internal pointer. * - * numbits is expected to be 32 or less. + * numbits is expected to be 64 or less. */ -u32 savebufferReadBits(struct savebuffer *buffer, s32 numbits) +u64 savebufferReadBits(struct savebuffer *buffer, s32 numbits) { - u32 bit = 1 << (numbits - 1); - u32 value = 0; + u64 bit = 1LL << (numbits - 1); + u64 value = 0; for (; bit; bit >>= 1) { s32 bitindex = buffer->bitpos % 8; @@ -470,13 +470,6 @@ void savebufferWriteData(struct savebuffer *buffer, u8 *data, u8 len) } } -void func0f0d54c4(struct savebuffer *buffer) -{ - s32 tmp = buffer->bitpos; - - if (tmp / 8 && buffer->bitpos); -} - /** * Read a zero-terminated string from the buffer and move the buffer's internal * pointer past the end of the string. @@ -514,7 +507,7 @@ void savebufferReadString(struct savebuffer *buffer, char *dst, bool addlinebrea savebufferReadString_ext(buffer, dst, addlinebreak, 10); } -void func0f0d55a4_ext(struct savebuffer *buffer, char *src, u8 len) +void savebufferWriteString_ext(struct savebuffer *buffer, char *src, u8 len) { bool done = false; s32 i; @@ -537,9 +530,9 @@ void func0f0d55a4_ext(struct savebuffer *buffer, char *src, u8 len) } } -void func0f0d55a4(struct savebuffer *buffer, char *src) +void savebufferWriteString(struct savebuffer *buffer, char *src) { - func0f0d55a4_ext(buffer, src, 10); + savebufferWriteString_ext(buffer, src, 10); } void func0f0d564c_ext(u8 *data, char *dst, bool addlinebreak, u8 len) diff --git a/src/include/game/mplayer/mplayer.h b/src/include/game/mplayer/mplayer.h index b097e5a39..a5b37e34f 100644 --- a/src/include/game/mplayer/mplayer.h +++ b/src/include/game/mplayer/mplayer.h @@ -118,7 +118,7 @@ s32 mpGetNumUnlockedPresets(void); char *mpGetPresetNameBySlot(s32 slot); void mpApplyConfig(struct mpconfigfull *mpconfig); void mp0f18dec4(s32 arg0); -void mpsetupfileLoadWad(struct savebuffer *buffer); +void mpsetupfileLoadWad(struct savebuffer *buffer, u8 version); void mpsetupfileSaveWad(struct savebuffer *buffer); void mpsetupfileGetOverview(char *arg0, char *filename, u16 *numsims, u16 *stagenum, u16 *scenarionum); s32 mpsetupfileSave(s32 device, s32 filenum, u16 deviceserial); diff --git a/src/include/game/savebuffer.h b/src/include/game/savebuffer.h index 320708af2..28e4b6cb2 100644 --- a/src/include/game/savebuffer.h +++ b/src/include/game/savebuffer.h @@ -11,16 +11,15 @@ Gfx *func0f0d49c8(Gfx *gdl); Gfx *func0f0d4a3c(Gfx *gdl, s32 arg1); Gfx *func0f0d4c80(Gfx *gdl); Gfx *menugfxDrawPlane(Gfx *gdl, s32 x1, s32 y1, s32 x2, s32 y2, u32 colour1, u32 colour2, s32 type); -void savebufferOr(struct savebuffer *buffer, u32 arg1, s32 arg2); -void savebufferWriteBits(struct savebuffer *buffer, u32 value, s32 numbits, u8 *dst); -u32 savebufferReadBits(struct savebuffer *buffer, s32 offset); +void savebufferOr(struct savebuffer *buffer, u64 arg1, s32 arg2); +void savebufferWriteBits(struct savebuffer *buffer, u64 value, s32 numbits, u8 *dst); +u64 savebufferReadBits(struct savebuffer *buffer, s32 offset); void savebufferClear(struct savebuffer *buffer); void savebufferWriteData(struct savebuffer *buffer, u8 *data, u8 len); -void func0f0d54c4(struct savebuffer *buffer); void savebufferReadString_ext(struct savebuffer *buffer, char *dst, bool addlinebreak, u8 len); void savebufferReadString(struct savebuffer *buffer, char *dst, bool addlinebreak); -void func0f0d55a4_ext(struct savebuffer *buffer, char *src, u8 len); -void func0f0d55a4(struct savebuffer *buffer, char *src); +void savebufferWriteString_ext(struct savebuffer *buffer, char *src, u8 len); +void savebufferWriteString(struct savebuffer *buffer, char *src); void func0f0d564c_ext(u8 *data, char *dst, bool addlinebreak, u8 len); void func0f0d564c(u8 *data, char *dst, bool addlinebreak); void func0f0d5690(u8 *dst, char *buffer); From 8f477a36b60242436e9124b1780c17a4eb53ce15 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Mon, 31 Mar 2025 10:22:12 +0800 Subject: [PATCH 22/34] mpsetups: convert existing setups from the eeprom, removed "combat settings" items from file menu increased block size from 64 to 80 (it was insufficient) --- port/include/mpsetups.h | 3 +- port/src/mpsetups.c | 51 +++++++++++++++++--- src/game/filemgr.c | 21 -------- src/game/fmb.c | 16 ------ src/game/menutick.c | 1 - src/game/mplayer/mplayer.c | 34 ++++++++++--- src/game/mplayer/scenarios.c | 9 ++-- src/game/mplayer/scenarios/kingofthehill.inc | 5 +- src/game/mplayer/setup.c | 5 +- src/include/constants.h | 2 +- src/include/game/mplayer/scenarios.h | 2 +- 11 files changed, 87 insertions(+), 62 deletions(-) diff --git a/port/include/mpsetups.h b/port/include/mpsetups.h index 9a2b2f58a..c54aee371 100644 --- a/port/include/mpsetups.h +++ b/port/include/mpsetups.h @@ -6,6 +6,7 @@ s32 mpsetupLoadCurrentFile(); s32 mpsetupSaveCurrentFile(); void mpsetupLoadSetup(s32 slotindex); -s32 mpsetupSaveSetup(s32 slotindex); +s32 mpsetupSaveSetup(s32 slotindex, u8 savefile); +void mpsetupCopyAllFromPak(); #endif diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index a1c9d658d..dc9e0fc2e 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -1,6 +1,8 @@ #include "types.h" #include "constants.h" #include "bss.h" +#include "game/pak.h" +#include "game/filelist.h" #include "game/menu.h" #include "game/savebuffer.h" #include "game/mplayer/mplayer.h" @@ -21,6 +23,8 @@ MP Setup File Format [setup_n{64}] */ +#define MPSETUP_VERSION 1 + #define MPSETUP_EXPORTDIR "$S/exported/" #define MPSETUP_FILENAME "mpsetups" #define MPSETUP_FILENAME_EXP "mpsetups-ext" @@ -131,7 +135,7 @@ MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *ite break; case MENUOP_SET: strcpy(setup->bytes, name); - err = mpsetupSaveSetup(slotindex); + err = mpsetupSaveSetup(slotindex, true); if (!err) { menuPopDialog(); } @@ -501,13 +505,14 @@ static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct me { if (operation == MENUOP_SET) { s32 selected = g_Menus[g_MpPlayerNum].mpsetup.slotindex; + // clicked on "clear default" if (selected == g_MpSetupFile.defaultsetup - 1) { - strcpy(g_LabelSetDefault, "Set Default\n"); g_MpSetupFile.defaultsetup = -1; + strcpy(g_LabelSetDefault, "Set Default\n"); } else { - strcpy(g_LabelSetDefault, "Clear Default\n"); g_MpSetupFile.defaultsetup = selected + 1; + strcpy(g_LabelSetDefault, "Clear Default\n"); } mpsetupSaveCurrentFile(); @@ -750,6 +755,7 @@ s32 mpsetupLoadCurrentFile() s32 mpsetupSaveCurrentFile() { + g_MpSetupFile.version = MPSETUP_VERSION; return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile); } @@ -843,7 +849,7 @@ static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile) return mpsetupLoadCurrentFile(); } -s32 mpsetupSaveSetup(s32 slotindex) +s32 mpsetupSaveSetup(s32 slotindex, u8 savefile) { struct savebuffer setup; @@ -857,7 +863,7 @@ s32 mpsetupSaveSetup(s32 slotindex) memcpy(g_MpSetupFile.setups[slotindex].bytes, setup.bytes, MPSETUP_BLOCKSIZE); - return mpsetupSaveCurrentFile(); + return savefile ? mpsetupSaveCurrentFile() : 0; } void mpsetupLoadSetup(s32 index) @@ -866,6 +872,39 @@ void mpsetupLoadSetup(s32 index) savebufferClear(&buffer); struct setupblock *block = &g_MpSetupFile.setups[index]; memcpy(&buffer.bytes, block->bytes, MPSETUP_BLOCKSIZE); - mpsetupfileLoadWad(&buffer); + mpsetupfileLoadWad(&buffer, g_MpSetupFile.version); g_MpCurrentSetup = index; } + +void mpsetupCopyAllFromPak() +{ + if (fsFileSize("$S/" MPSETUP_FILENAME ".bin") > 0) { + return; + } + + filelistCreate(1, FILETYPE_MPSETUP); + filelistsTick(); + + for (int i = 0; i < g_FileLists[1]->numfiles; ++i) { + struct savebuffer buffer; + savebufferClear(&buffer); + struct filelistfile *file = &g_FileLists[1]->files[i]; + s32 device = pakFindBySerial(file->deviceserial); + s32 err = pakReadBodyAtGuid(device, file->fileid, buffer.bytes, 0); + + if (err != 0) { + sysLogPrintf(LOG_ERROR, "Unable to read pak. device %d fileid %d deviceserial %d err %d", + device, file->fileid, file->deviceserial, err); + continue; + } + + mpsetupfileLoadWad(&buffer, 0); + + // save the file when writing the last setup + u8 savefile = i == g_FileLists[1]->numfiles - 1; + mpsetupSaveSetup(g_MpSetupFile.numsetups, savefile); + } + + // to reset the mp setup + mpInit(); +} diff --git a/src/game/filemgr.c b/src/game/filemgr.c index 9c87e071d..a5dbc53e8 100644 --- a/src/game/filemgr.c +++ b/src/game/filemgr.c @@ -499,11 +499,6 @@ char *filemgrMenuTextFileType(struct menuitem *item) case FILEOP_LOAD_GAME: case FILEOP_READ_GAME: return langGet(names[0]); - case FILEOP_SAVE_MPSETUP: - case FILEOP_WRITE_MPSETUP: - case FILEOP_LOAD_MPSETUP: - case FILEOP_READ_MPSETUP: - return langGet(names[1]); case FILEOP_SAVE_MPPLAYER: case FILEOP_WRITE_MPPLAYER: case FILEOP_LOAD_MPPLAYER: @@ -3296,14 +3291,6 @@ struct menuitem g_FilemgrOperationsMenuItems[] = { 0, filemgrOpenCopyFileMenuHandler, }, - { - MENUITEMTYPE_SELECTABLE, - FILETYPE_MPSETUP, - 0, - L_OPTIONS_104, // "Combat Simulator Settings File" - 0, - filemgrOpenCopyFileMenuHandler, - }, { MENUITEMTYPE_SELECTABLE, FILETYPE_MPPLAYER, @@ -3336,14 +3323,6 @@ struct menuitem g_FilemgrOperationsMenuItems[] = { 0, filemgrOpenDeleteFileMenuHandler, }, - { - MENUITEMTYPE_SELECTABLE, - FILETYPE_MPSETUP, - 0, - L_OPTIONS_104, // "Combat Simulator Settings File" - 0, - filemgrOpenDeleteFileMenuHandler, - }, { MENUITEMTYPE_SELECTABLE, FILETYPE_MPPLAYER, diff --git a/src/game/fmb.c b/src/game/fmb.c index f6de5aadd..3cd114d0f 100644 --- a/src/game/fmb.c +++ b/src/game/fmb.c @@ -133,14 +133,6 @@ struct menuitem g_GameFiles4MbMenuItems[] = { 0, filemgrOpenCopyFileMenuHandler, }, - { - MENUITEMTYPE_SELECTABLE, - 1, - 0, - L_OPTIONS_104, // "Combat Simulator Settings File" - 0, - filemgrOpenCopyFileMenuHandler, - }, { MENUITEMTYPE_SELECTABLE, 2, @@ -173,14 +165,6 @@ struct menuitem g_GameFiles4MbMenuItems[] = { 0, filemgrOpenDeleteFileMenuHandler, }, - { - MENUITEMTYPE_SELECTABLE, - 1, - 0, - L_OPTIONS_104, // "Combat Simulator Settings File" - 0, - filemgrOpenDeleteFileMenuHandler, - }, { MENUITEMTYPE_SELECTABLE, 2, diff --git a/src/game/menutick.c b/src/game/menutick.c index 5a795da9d..fcd0df3b8 100644 --- a/src/game/menutick.c +++ b/src/game/menutick.c @@ -473,7 +473,6 @@ void menuTick(void) (g_MenuData.root == MENUROOT_MPSETUP || g_MenuData.root == MENUROOT_4MBMAINMENU)) { var80062948 = 1; filelistCreate(0, FILETYPE_MPPLAYER); - filelistCreate(1, FILETYPE_MPSETUP); } if (var80062944) { diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index 69facd19f..4b8f70ecf 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -3931,16 +3931,32 @@ void mpsetupfileLoadWad(struct savebuffer *buffer, u8 version) s32 i; s32 j; - savebufferReadString_ext(buffer, g_MpSetup.name, false, MPSETUP_MAXNAME+1); + if (version > 0) { + savebufferReadString_ext(buffer, g_MpSetup.name, false, MPSETUP_MAXNAME + 1); + } + else { + savebufferReadString(buffer, g_MpSetup.name, false); + } + savebufferReadBits(buffer, 4); g_MpSetup.stagenum = savebufferReadBits(buffer, 7); g_MpSetup.scenario = savebufferReadBits(buffer, 3); - scenarioInit(); - scenarioReadSave(buffer); + // version == 0 means we're only reading to convert, so no actions are needed + if (version > 0) { + scenarioInit(); + } + + scenarioReadSave(buffer, version); + + if (version > 0) { + g_MpSetup.options = savebufferReadBits(buffer, 32); + } + else { + g_MpSetup.options = savebufferReadBits(buffer, 21); + } - g_MpSetup.options = savebufferReadBits(buffer, 32); g_MpSetup.chrslots &= 0x000f; for (i = 0; i < MAX_BOTS; i++) { @@ -3961,14 +3977,18 @@ void mpsetupfileLoadWad(struct savebuffer *buffer, u8 version) g_BotConfigsArray[i].base.team = savebufferReadBits(buffer, 3); } - mpGenerateBotNames(); + if (version > 0) { + mpGenerateBotNames(); + } for (i = 0; i < ARRAYCOUNT(g_MpSetup.weapons); i++) { g_MpSetup.weapons[i] = savebufferReadBits(buffer, 7); } - u64 wpnRndPacked = savebufferReadBits(buffer, 64); - unpackWeaponSetRandomFilters(wpnRndPacked); + if (version > 0) { + u64 wpnRndPacked = savebufferReadBits(buffer, 64); + unpackWeaponSetRandomFilters(wpnRndPacked); + } func0f18913c(); diff --git a/src/game/mplayer/scenarios.c b/src/game/mplayer/scenarios.c index 0c4df1f51..b9ea325b3 100644 --- a/src/game/mplayer/scenarios.c +++ b/src/game/mplayer/scenarios.c @@ -70,7 +70,7 @@ struct mpscenario { bool (*isroomhighlightedfunc)(RoomNum room); void (*highlightroomfunc)(RoomNum room, s32 *arg1, s32 *arg2, s32 *arg3); void *unk3c; // never hooked into nor fired - void (*readsavefunc)(struct savebuffer *buffer); + void (*readsavefunc)(struct savebuffer *buffer, u8 version); void (*writesavefunc)(struct savebuffer *buffer); }; @@ -416,12 +416,13 @@ MenuItemHandlerResult menuhandlerMpOpenOptions(s32 operation, struct menuitem *i * * Used by KOH to read the mphilltime. */ -void scenarioReadSave(struct savebuffer *buffer) +void scenarioReadSave(struct savebuffer *buffer, u8 version) { if (g_MpScenarios[g_MpSetup.scenario].readsavefunc) { - g_MpScenarios[g_MpSetup.scenario].readsavefunc(buffer); + g_MpScenarios[g_MpSetup.scenario].readsavefunc(buffer, version); } else { - savebufferReadBits(buffer, 32); + u8 sz = version > 0 ? 32 : 8; + savebufferReadBits(buffer, sz); } } diff --git a/src/game/mplayer/scenarios/kingofthehill.inc b/src/game/mplayer/scenarios/kingofthehill.inc index 721550423..542256b9b 100644 --- a/src/game/mplayer/scenarios/kingofthehill.inc +++ b/src/game/mplayer/scenarios/kingofthehill.inc @@ -181,9 +181,10 @@ struct menudialogdef g_KohOptionsMenuDialog = { NULL, }; -void kohReadSave(struct savebuffer *buffer) +void kohReadSave(struct savebuffer *buffer, u8 version) { - g_Vars.mphilltime = savebufferReadBits(buffer, 32); + u8 sz = version > 0 ? 32 : 8; + g_Vars.mphilltime = savebufferReadBits(buffer, sz); } void kohWriteSave(struct savebuffer *buffer) diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index a70087eda..27e0b7fc3 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -470,7 +470,7 @@ MenuItemHandlerResult menuhandlerMpSetupName(s32 operation, struct menuitem *ite strcpy(g_MpSetup.name, name); break; case MENUOP_SET: - err = mpsetupSaveSetup(g_MpSetupFile.numsetups); + err = mpsetupSaveSetup(g_MpSetupFile.numsetups, true); if (!err) { menuPushDialog(&g_FilemgrFileSavedMenuDialog); } @@ -488,7 +488,7 @@ MenuItemHandlerResult menuhandlerMpSaveSetupOverwrite(s32 operation, struct menu { if (operation == MENUOP_SET) { menuPopDialog(); - mpsetupSaveSetup(g_MpCurrentSetup); + mpsetupSaveSetup(g_MpCurrentSetup, true); menuPushDialog(&g_FilemgrFileSavedMenuDialog); } @@ -5363,6 +5363,7 @@ MenuDialogHandlerResult menudialogCombatSimulator(s32 operation, struct menudial g_Vars.waitingtojoin[3] = false; // load the setup file when entering the Combat Simulator + mpsetupCopyAllFromPak(); mpsetupLoadCurrentFile(); } diff --git a/src/include/constants.h b/src/include/constants.h index e1c4b4ea3..f465b6263 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -4756,7 +4756,7 @@ enum weaponnum { #define MPSETUP_MAXSETUPS 128 #define MPSETUP_MAXNAME 18 -#define MPSETUP_BLOCKSIZE 64 +#define MPSETUP_BLOCKSIZE 80 #endif diff --git a/src/include/game/mplayer/scenarios.h b/src/include/game/mplayer/scenarios.h index a04f0d021..48c7bdcc1 100644 --- a/src/include/game/mplayer/scenarios.h +++ b/src/include/game/mplayer/scenarios.h @@ -17,7 +17,7 @@ struct mpscenariooverview { extern struct mpscenariooverview g_MpScenarioOverviews[6]; MenuItemHandlerResult menuhandlerMpOpenOptions(s32 operation, struct menuitem *item, union handlerdata *data); -void scenarioReadSave(struct savebuffer *buffer); +void scenarioReadSave(struct savebuffer *buffer, u8 version); void scenarioWriteSave(struct savebuffer *buffer); void scenarioInit(void); s32 scenarioNumProps(void); From 7a98095a0be2c23d72f0cd273a30c93d0bf93909 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Mon, 31 Mar 2025 10:25:24 +0800 Subject: [PATCH 23/34] mpsetups: bug fix - when deleting a setup that is behind the default setup in the list --- port/src/mpsetups.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index dc9e0fc2e..d347c56e2 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -663,16 +663,16 @@ static s32 deleteSetup() memcpy(dst, src, MPSETUP_BLOCKSIZE); } - if (g_MpCurrentSetup > slotindex) { + if (g_MpCurrentSetup >= slotindex) { g_MpCurrentSetup--; } - else if (g_MpCurrentSetup == slotindex) { - g_MpCurrentSetup = -1; - } - if (g_MpSetupFile.defaultsetup == slotindex + 1) { - g_MpSetupFile.defaultsetup = 0; - } + if (g_MpSetupFile.defaultsetup > slotindex + 1) { + g_MpSetupFile.defaultsetup--; + } + else if (g_MpSetupFile.defaultsetup == slotindex + 1) { + g_MpSetupFile.defaultsetup = 0; + } g_MpSetupFile.numsetups--; return mpsetupSaveCurrentFile(); From f9cfa0fa437faa1b087ef2e92919b2857c0f720b Mon Sep 17 00:00:00 2001 From: Raf <> Date: Mon, 31 Mar 2025 10:34:25 +0800 Subject: [PATCH 24/34] mpsetups: introduced "menu alt" button/key to toggle presets Currently the "menu alt" (L/R buttons, or Ctrl/Alt keys) is fixed, but we may make it bindable later --- port/include/input.h | 7 +++++ port/src/input.c | 27 +++++++++++++++++++ src/game/mplayer/mplayer.c | 4 +++ src/game/mplayer/setup.c | 53 ++++++++++++++++++++++++++++++-------- src/include/types.h | 1 + 5 files changed, 81 insertions(+), 11 deletions(-) diff --git a/port/include/input.h b/port/include/input.h index 6d5d88bfd..98f5928fc 100644 --- a/port/include/input.h +++ b/port/include/input.h @@ -40,6 +40,7 @@ enum virtkey { VK_DELETE = 76, VK_LCTRL = 224, VK_LSHIFT = 225, + VK_LALT = 226, VK_RCTRL = 228, VK_RSHIFT = 229, @@ -56,6 +57,8 @@ enum virtkey { /* same order as SDL gamecontroller buttons plus two buttons for triggers */ VK_JOY_BEGIN, VK_JOY1_BEGIN = VK_JOY_BEGIN, + VK_JOY1_LSHOULDER = VK_JOY1_BEGIN + 9, + VK_JOY1_RSHOULDER = VK_JOY1_BEGIN + 10, VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30, VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31, VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, @@ -267,4 +270,8 @@ const char *inputGetClipboard(void); // returns keymod values u32 inputGetKeyModState(void); +s32 inputMenuAlt1MenuPressed(s32 playerNum); +s32 inputMenuAlt2MenuPressed(s32 playerNum); +s32 inputMenuAltMenuPressed(s32 playerNum); + #endif diff --git a/port/src/input.c b/port/src/input.c index cfee620a5..7024fc822 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -1162,6 +1162,33 @@ s32 inputKeyJustPressed(u32 vk) return result; } +s32 inputMenuAlt1MenuPressed(s32 playerNum) +{ + s32 RSHOULDER = VK_JOY1_RSHOULDER + playerNum * INPUT_MAX_CONTROLLER_BUTTONS; + + if (playerNum == 0) { + return inputKeyJustPressed(VK_LCTRL) || inputKeyJustPressed(RSHOULDER); + } + + return inputKeyJustPressed(RSHOULDER); +} + +s32 inputMenuAlt2MenuPressed(s32 playerNum) +{ + s32 LSHOULDER = VK_JOY1_LSHOULDER + playerNum * INPUT_MAX_CONTROLLER_BUTTONS; + + if (playerNum == 0) { + return inputKeyJustPressed(VK_LALT) || inputKeyJustPressed(LSHOULDER); + } + + return inputKeyJustPressed(LSHOULDER); +} + +s32 inputMenuAltMenuPressed(s32 playerNum) +{ + return inputMenuAlt1MenuPressed(playerNum) || inputMenuAlt2MenuPressed(playerNum); +} + static inline u32 inputContToContKey(const u32 cont) { if (cont == 0) { diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index 4b8f70ecf..add19e0aa 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -600,6 +600,10 @@ void mpInit(void) } g_MpSetup.chrslots = 0; + + for (i = 0; i < ARRAYCOUNT(g_Menus); i++) { + g_Menus[i].mpsetup.showpresets = 1; + } } #if VERSION >= VERSION_PAL_BETA diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index 27e0b7fc3..a72e55759 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -20,10 +20,12 @@ #include "lib/vi.h" #include "lib/rng.h" #include "lib/str.h" +#include "lib/joy.h" #include "data.h" #include "gbiex.h" #include "types.h" #include "system.h" +#include "input.h" #include "mpsetups.h" struct menuitem g_MpCharacterMenuItems[]; @@ -2252,16 +2254,19 @@ MenuItemHandlerResult mpPlayerNameMenuHandler(s32 operation, struct menuitem *it MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem *item, union handlerdata *data) { + u8 presets = g_Menus[g_MpPlayerNum].mpsetup.showpresets; + s32 numpresets = mpGetNumUnlockedPresets()*presets; + switch (operation) { case MENUOP_GETOPTIONCOUNT: - data->list.value = mpGetNumUnlockedPresets() + g_MpSetupFile.numsetups; + data->list.value = numpresets + g_MpSetupFile.numsetups; break; case MENUOP_GETOPTIONTEXT: - if (data->list.value < mpGetNumUnlockedPresets()) { + if (presets && data->list.value < mpGetNumUnlockedPresets()) { return (uintptr_t)mpGetPresetNameBySlot(data->list.value); } if (g_MpSetupFile.numsetups > 0) { - struct setupblock *block = &g_MpSetupFile.setups[data->list.value - mpGetNumUnlockedPresets()]; + struct setupblock *block = &g_MpSetupFile.setups[data->list.value - numpresets]; func0f0d564c_ext(block->bytes, g_StringPointer, false, MPSETUP_MAXNAME+1); return (uintptr_t)g_StringPointer; } @@ -2269,12 +2274,12 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * case MENUOP_SET: mpCloseDialogsForNewSetup(); - if (data->list.value < mpGetNumUnlockedPresets()) { + if (presets && data->list.value < mpGetNumUnlockedPresets()) { mp0f18dec4(data->list.value); g_MpCurrentSetup = -1; } else { - mpsetupLoadSetup(data->list.value - mpGetNumUnlockedPresets()); + mpsetupLoadSetup(data->list.value - numpresets); } if (item->param == 1) { @@ -2289,22 +2294,22 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * data->list.value = 0xfffff; break; case MENUOP_GETOPTGROUPCOUNT: - data->list.value = 2; + data->list.value = presets ? 2 : 1; break; case MENUOP_GETOPTGROUPTEXT: - if (data->list.value == 0) { + if (presets && data->list.value == 0) { return (uintptr_t)langGet(L_MPMENU_141); // "Presets" } return (uintptr_t)"Custom"; case MENUOP_GETGROUPSTARTINDEX: - data->list.groupstartindex = data->list.value == 0 ? 0 : mpGetNumUnlockedPresets(); + data->list.groupstartindex = data->list.value == 0 ? 0 : numpresets; break; case MENUOP_LISTITEMFOCUS: - if (data->list.value < mpGetNumUnlockedPresets()) { + if (presets && data->list.value < mpGetNumUnlockedPresets()) { g_Menus[g_MpPlayerNum].mpsetup.slotindex = 0xffff; } else { - g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value - mpGetNumUnlockedPresets(); + g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value - numpresets; } break; } @@ -2632,14 +2637,40 @@ struct menuitem g_MpLoadSettingsMenuItems[] = { 0, NULL, }, + { + MENUITEMTYPE_SEPARATOR, + 0, + 0, + 0, + 0, + NULL, + }, + { + MENUITEMTYPE_LABEL, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING | MENUITEMFLAG_SMALLFONT, + (uintptr_t)"Menu Alt: Toggle Presets\n", + 0, + NULL, + }, { MENUITEMTYPE_END }, }; +MenuDialogHandlerResult loadSettingsDialogHandler(s32 operation, struct menudialogdef *dialogdef, union handlerdata *data) +{ + if (operation == MENUOP_TICK) { + if (inputMenuAltMenuPressed(g_MpPlayerNum)) { + u8 presets = g_Menus[g_MpPlayerNum].mpsetup.showpresets; + g_Menus[g_MpPlayerNum].mpsetup.showpresets = 1 - presets; + } + } +} + struct menudialogdef g_MpLoadSettingsMenuDialog = { MENUDIALOGTYPE_DEFAULT, L_MPMENU_139, // "Load Game Settings" g_MpLoadSettingsMenuItems, - NULL, + loadSettingsDialogHandler, MENUDIALOGFLAG_CLOSEONSELECT, NULL, }; diff --git a/src/include/types.h b/src/include/types.h index 61d8a96f5..cc0b2ed32 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -3774,6 +3774,7 @@ struct menudata_main { struct menudata_mpsetup { u32 slotindex; u32 slotcount; + u8 showpresets; u32 unke24; }; From 6198fbc47913b0bdcb01f9c81e21d2c408abc645 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Tue, 1 Apr 2025 17:00:59 +0800 Subject: [PATCH 25/34] mpsetups: a bunch of bug fixes - "load settings" becoming invalid when entering and exiting the challenges screen - when setting a setup as default, it would change the current setup - larger window width causing the marquee text to be rendered off-bounds - reduced the setup name's max length, as it wouldn't fit on the screen in some cases --- port/src/mpsetups.c | 20 ++++++++++++-------- src/game/mplayer/setup.c | 13 +++++++------ src/include/constants.h | 2 +- src/include/types.h | 3 ++- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index d347c56e2..7adf057db 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -154,8 +154,8 @@ struct menuitem g_RenameSetupItems[] = { { MENUITEMTYPE_LABEL, 0, - MENUITEMFLAG_LESSLEFTPADDING, - L_MPMENU_189, // "Enter a name for your game setup file:" + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING, + (uintptr_t)"Enter the setup name:\n", 0, NULL, }, @@ -663,9 +663,12 @@ static s32 deleteSetup() memcpy(dst, src, MPSETUP_BLOCKSIZE); } - if (g_MpCurrentSetup >= slotindex) { + if (g_MpCurrentSetup > slotindex) { g_MpCurrentSetup--; } + else if (g_MpCurrentSetup == slotindex) { + g_MpCurrentSetup = -1; + } if (g_MpSetupFile.defaultsetup > slotindex + 1) { g_MpSetupFile.defaultsetup--; @@ -802,8 +805,10 @@ s32 exportMpSetupFile() { struct mpsetupfile expMpSetupFile; expMpSetupFile.numsetups = 0; - - u8 maxsetups = g_MpImportExportFilter[1] == 0 ? 64 : 128; + expMpSetupFile.defaultsetup = 0; + expMpSetupFile.version = MPSETUP_VERSION; + + u8 maxsetups = MPSETUP_MAXSETUPS; maxsetups = MIN(maxsetups, g_MpSetupFile.numsetups); for (int i = 0; i < maxsetups; ++i) { u8 bank = i < 64 ? 0 : 1; @@ -840,13 +845,12 @@ static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile) if (nwritten < 1) { fsFileFree(f); sysLogPrintf(LOG_ERROR, "Unable to write the MP setup file"); + sprintf(g_StatusText, "Unable to write the setup file\n"); return -1; } fsFileFree(f); - - // reload the file to update in-memory structs - return mpsetupLoadCurrentFile(); + return 0; } s32 mpsetupSaveSetup(s32 slotindex, u8 savefile) diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index 1a91d0821..a9d920c49 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -459,6 +459,7 @@ MenuItemHandlerResult menuhandlerMpConfirmSaveChr(s32 operation, struct menuitem return 0; } +extern struct menudialogdef g_StatusErrorDialog; MenuItemHandlerResult menuhandlerMpSetupName(s32 operation, struct menuitem *item, union handlerdata *data) { char *name = data->keyboard.string; @@ -475,10 +476,10 @@ MenuItemHandlerResult menuhandlerMpSetupName(s32 operation, struct menuitem *ite err = mpsetupSaveSetup(g_MpSetupFile.numsetups, true); if (!err) { menuPushDialog(&g_FilemgrFileSavedMenuDialog); + g_MpCurrentSetup = g_MpSetupFile.numsetups - 1; } else { -// menuPushDialog(&g_FilemgrErrorMenuDialog); - // TODO + menuPushDialog(&g_StatusErrorDialog); } break; } @@ -1092,8 +1093,8 @@ struct menuitem g_MpSaveSetupNameMenuItems[] = { { MENUITEMTYPE_LABEL, 0, - MENUITEMFLAG_LESSLEFTPADDING, - L_MPMENU_189, // "Enter a name for your game setup file:" + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING, + (uintptr_t)"Enter the setup name:\n", 0, NULL, }, @@ -2322,7 +2323,7 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * char *mpMenuTextMpconfigMarquee(struct menuitem *item) { - char filename[20]; + char filename[MPSETUP_MAXNAME+1]; u16 numsims; u16 stagenum; u16 scenarionum; @@ -2628,7 +2629,7 @@ struct menuitem g_MpLoadSettingsMenuItems[] = { MENUITEMTYPE_LIST, 0, 0, - 160, + 0x00000078, 0x00000042, mpLoadSettingsMenuHandler, }, diff --git a/src/include/constants.h b/src/include/constants.h index 1b87a7952..6a77fda41 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -4757,7 +4757,7 @@ enum weaponnum { #define EXTRA_SLEEP_TIME 1000LL // 100us #define MPSETUP_MAXSETUPS 128 -#define MPSETUP_MAXNAME 18 +#define MPSETUP_MAXNAME 17 #define MPSETUP_BLOCKSIZE 80 #endif diff --git a/src/include/types.h b/src/include/types.h index cc0b2ed32..1ed8ee9d9 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -3983,13 +3983,14 @@ struct menu { union { struct menudata_endscreen endscreen; struct menudata_main main; - struct menudata_mpsetup mpsetup; struct menudata_mppause mppause; struct menudata_mpend mpend; struct menudata_filemgr fm; struct menudata_main4mb main4mb; struct menudata_training training; }; + + struct menudata_mpsetup mpsetup; }; struct gamefile { From b93015c51c4b0a2b1c49b0b3a5c56a46fc3662ed Mon Sep 17 00:00:00 2001 From: Raf <> Date: Wed, 2 Apr 2025 00:33:45 +0800 Subject: [PATCH 26/34] mpsetups: fixed reverse pitch/look ahead being reset when the mpsetups file is created for the first time --- port/src/mpsetups.c | 2 +- port/src/pdmain.c | 2 +- src/game/filemgr.c | 2 +- src/game/mplayer/mplayer.c | 20 +++++++++++--------- src/include/game/mplayer/mplayer.h | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index 7adf057db..519a8a92d 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -910,5 +910,5 @@ void mpsetupCopyAllFromPak() } // to reset the mp setup - mpInit(); + mpInit(false); } diff --git a/port/src/pdmain.c b/port/src/pdmain.c index 58d37b192..344e954fd 100644 --- a/port/src/pdmain.c +++ b/port/src/pdmain.c @@ -259,7 +259,7 @@ void mainInit(void) frametimeInit(); profileInit(); smokesInit(); - mpInit(); + mpInit(true); pheadInit(); paksInit(); pheadInit2(); diff --git a/src/game/filemgr.c b/src/game/filemgr.c index a5dbc53e8..45b85efae 100644 --- a/src/game/filemgr.c +++ b/src/game/filemgr.c @@ -2764,7 +2764,7 @@ MenuDialogHandlerResult filemgrMainMenuDialog(s32 operation, struct menudialogde g_Menus[g_MpPlayerNum].fm.filetypeplusone = 0; filelistCreate(0, FILETYPE_GAME); - mpInit(); + mpInit(true); // Set MP player names to "Player 1" through 4 if blank for (i = 0; i < MAX_PLAYERS; i++) { diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index dcb183877..40daa9935 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -518,12 +518,6 @@ void mpPlayerSetDefaults(s32 playernum, bool autonames) for (i = 0; i < ARRAYCOUNT(g_PlayerConfigsArray); i++) { g_PlayerConfigsArray[playernum].gunfuncs[i] = 0; } - -#ifndef PLATFORM_N64 - for (i = 0; i < ARRAYCOUNT(g_MpWeapons); i++) { - g_MpWeaponSetRandomFilters[i] = 1; - } -#endif } void func0f1881d4(s32 index) @@ -535,7 +529,7 @@ void func0f1881d4(s32 index) g_BotConfigsArray[index].difficulty = BOTDIFF_DISABLED; } -void mpInit(void) +void mpInit(bool resetplayers) { s32 i; s32 j; @@ -568,8 +562,10 @@ void mpInit(void) strcpy(g_MpSetup.name, ""); - for (i = 0; i < ARRAYCOUNT(g_PlayerConfigsArray); i++) { - mpPlayerSetDefaults(i, false); + if (resetplayers) { + for (i = 0; i < ARRAYCOUNT(g_PlayerConfigsArray); i++) { + mpPlayerSetDefaults(i, false); + } } for (i = 0; i < MAX_BOTS; i++) { @@ -606,6 +602,12 @@ void mpInit(void) for (i = 0; i < ARRAYCOUNT(g_Menus); i++) { g_Menus[i].mpsetup.showpresets = 1; } + +#ifndef PLATFORM_N64 + for (i = 0; i < ARRAYCOUNT(g_MpWeapons); i++) { + g_MpWeaponSetRandomFilters[i] = 1; + } +#endif } #if VERSION >= VERSION_PAL_BETA diff --git a/src/include/game/mplayer/mplayer.h b/src/include/game/mplayer/mplayer.h index a5b37e34f..7510390d5 100644 --- a/src/include/game/mplayer/mplayer.h +++ b/src/include/game/mplayer/mplayer.h @@ -13,7 +13,7 @@ void func0f187fbc(s32 playernum); void func0f187fec(void); void mpPlayerSetDefaults(s32 playernum, bool autonames); void func0f1881d4(s32 index); -void mpInit(void); +void mpInit(bool resetplayers); void mpGetTeamsWithDefaultName(u8 *mask); void mpSetTeamNamesToDefault(u8 mask); void mpSetDefaultNamesIfEmpty(void); From cb6dc1feab14dce33ed19fcc4f1460ad4726b444 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Wed, 2 Apr 2025 15:55:31 +0800 Subject: [PATCH 27/34] mpsetups: forgot to pop the dialog after import name conflict, removed debug print --- port/src/mpsetups.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index 519a8a92d..577e14cdf 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -314,6 +314,7 @@ MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct me } else { if (err == MPSETUP_IMPORT_CONFLICT) { + menuPopDialog(); menuPushDialog(&g_ImportOverrideDialog); } else { @@ -817,7 +818,6 @@ s32 exportMpSetupFile() u8 n = expMpSetupFile.numsetups; expMpSetupFile.numsetups++; char *name = g_MpSetupFile.setups[i].bytes; - sysLogPrintf(LOG_NOTE, "%s", name); memcpy(expMpSetupFile.setups[n].bytes, g_MpSetupFile.setups[i].bytes, MPSETUP_BLOCKSIZE); expMpSetupFile.numsetups = n + 1; } From d4856a193bffde6ab8a0859fd5ad3d6dd9c0edbb Mon Sep 17 00:00:00 2001 From: Raf <> Date: Wed, 2 Apr 2025 20:13:19 +0800 Subject: [PATCH 28/34] mpsetups: added weapon set num to the save file --- port/src/mpsetups.c | 4 ++-- src/game/mplayer/mplayer.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index 577e14cdf..8c4f4e1be 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -18,9 +18,9 @@ MP Setup File Format [defaultsetup{1}] [numsetups{1}] # setups - [setup_1{64}] + [setup_1{80}] ... - [setup_n{64}] + [setup_n{80}] */ #define MPSETUP_VERSION 1 diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index 40daa9935..f3a8b20cd 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -3998,7 +3998,7 @@ void mpsetupfileLoadWad(struct savebuffer *buffer, u8 version) unpackWeaponSetRandomFilters(wpnRndPacked); } - func0f18913c(); + g_MpWeaponSetNum = savebufferReadBits(buffer, 8); g_MpSetup.timelimit = savebufferReadBits(buffer, 6); g_MpSetup.scorelimit = savebufferReadBits(buffer, 7); @@ -4066,6 +4066,7 @@ void mpsetupfileSaveWad(struct savebuffer *buffer) u64 wpnRndPacked = packWeaponSetRandomFilters(); savebufferOr(buffer, wpnRndPacked, 64); + savebufferOr(buffer, g_MpWeaponSetNum, 8); savebufferOr(buffer, g_MpSetup.timelimit, 6); savebufferOr(buffer, g_MpSetup.scorelimit, 7); From 1555a4be8463e0489770aca463db74a6d7e1110a Mon Sep 17 00:00:00 2001 From: Raf <> Date: Wed, 2 Apr 2025 22:19:24 +0800 Subject: [PATCH 29/34] missing semicolon after mkdir() in non-win platforms --- port/src/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/port/src/fs.c b/port/src/fs.c index 7d4507aa7..0eb4ef4c2 100644 --- a/port/src/fs.c +++ b/port/src/fs.c @@ -288,6 +288,6 @@ s32 fsCreateDir(const char *path) { #ifdef PLATFORM_WIN32 return _mkdir(fsFullPath(path)); #else - return mkdir(fsFullPath(path), S_IRWXU | S_IRWXG) + return mkdir(fsFullPath(path), S_IRWXU | S_IRWXG); #endif } From 053f7dc8a5495cf6f671d0e37a935aa9cdb18be0 Mon Sep 17 00:00:00 2001 From: AL2009man <67606569+AL2009man@users.noreply.github.com> Date: Fri, 11 Apr 2025 00:06:02 -0400 Subject: [PATCH 30/34] Mouse Sensitivity follows Quake/id Tech mouse sens this changes mouse sensitiivity scale to mirror id Tech's Mouse Sensitivity Scale. This also makes it easier for Steam Input users (Steam Deck and Steam Controller) to use Gyro To Mouse/Flick Stick's Natural Sensitivity Scale --- port/src/input.c | 12 ++++++------ src/game/player.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/port/src/input.c b/port/src/input.c index 2bacbd646..9cf2e6134 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -88,8 +88,8 @@ static s32 mouseLockMode = MLOCK_AUTO; static u64 mouseCursorTime = 0; static s32 mouseShowCursor = 1; -static f32 mouseSensX = 1.5f; -static f32 mouseSensY = 1.5f; +static f32 mouseSensX = 2.5f; +static f32 mouseSensY = 2.5f; static s32 lastKey = 0; static char lastChar = 0; @@ -1243,8 +1243,8 @@ void inputMouseGetScaledDelta(f32 *dx, f32 *dy) { f32 mdx, mdy; if (mouseLocked) { - mdx = mouseSensX * (f32)mouseDX / 100.0f; - mdy = mouseSensY * (f32)mouseDY / 100.0f; + mdx = mouseSensX * (f32)mouseDX / 159.2f; + mdy = mouseSensY * (f32)mouseDY / 159.2f; } else { mdx = 0.f; mdy = 0.f; @@ -1257,8 +1257,8 @@ void inputMouseGetAbsScaledDelta(f32 *dx, f32 *dy) { f32 mdx, mdy; if (mouseLocked) { - mdx = fabsf(mouseSensX) * (f32)mouseDX / 100.0f; - mdy = fabsf(mouseSensY) * (f32)mouseDY / 100.0f; + mdx = fabsf(mouseSensX) * (f32)mouseDX / 159.2f; + mdy = fabsf(mouseSensY) * (f32)mouseDY / 159.2f; } else { mdx = 0.f; mdy = 0.f; diff --git a/src/game/player.c b/src/game/player.c index a0983ef36..fa17dc472 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -3674,8 +3674,8 @@ void playerTick(bool arg0) if (g_Vars.currentplayerstats && !optionsGetForwardPitch(g_Vars.currentplayerstats->mpindex)) { mdy = -mdy; } - sp178 += mdy * 0.00025f; - sp174 -= mdx * 0.00025f; + sp178 += mdy * 0.022f; + sp174 -= mdx * 0.022f; } } #endif From 9695856be6bad02fe4556f22c8c58b56d840442e Mon Sep 17 00:00:00 2001 From: AL2009man <67606569+AL2009man@users.noreply.github.com> Date: Fri, 11 Apr 2025 19:24:25 -0400 Subject: [PATCH 31/34] updated player.c to account for 0.022f scale while also changing input.c delta scale to ensure it has a divider --- port/src/input.c | 40 ++++++++++++++++++---------------------- src/game/player.c | 8 ++++---- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/port/src/input.c b/port/src/input.c index 9cf2e6134..96e37255e 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -1239,32 +1239,28 @@ void inputMouseGetRawDelta(s32 *dx, s32 *dy) if (dy) *dy = mouseDY; } -void inputMouseGetScaledDelta(f32 *dx, f32 *dy) +void inputMouseGetScaledDelta(f32* dx, f32* dy) { - f32 mdx, mdy; - if (mouseLocked) { - mdx = mouseSensX * (f32)mouseDX / 159.2f; - mdy = mouseSensY * (f32)mouseDY / 159.2f; - } else { - mdx = 0.f; - mdy = 0.f; - } - if (dx) *dx = mdx; - if (dy) *dy = mdy; + f32 mdx = 0.f, mdy = 0.f; + + if (mouseLocked) { + mdx = mouseSensX * ((f32)mouseDX / 3.5f) * 0.022f; + mdy = mouseSensY * ((f32)mouseDY / 3.5f) * 0.022f; + } + if (dx) *dx = mdx; + if (dy) *dy = mdy; } -void inputMouseGetAbsScaledDelta(f32 *dx, f32 *dy) +void inputMouseGetAbsScaledDelta(f32* dx, f32* dy) { - f32 mdx, mdy; - if (mouseLocked) { - mdx = fabsf(mouseSensX) * (f32)mouseDX / 159.2f; - mdy = fabsf(mouseSensY) * (f32)mouseDY / 159.2f; - } else { - mdx = 0.f; - mdy = 0.f; - } - if (dx) *dx = mdx; - if (dy) *dy = mdy; + f32 mdx = 0.f, mdy = 0.f; + + if (mouseLocked) { + mdx = fabsf(mouseSensX) * ((f32)mouseDX / 3.5f) * 0.022f; + mdy = fabsf(mouseSensY) * ((f32)mouseDY / 3.5f) * 0.022f; + } + if (dx) *dx = mdx; + if (dy) *dy = mdy; } void inputMouseGetSpeed(f32 *x, f32 *y) diff --git a/src/game/player.c b/src/game/player.c index fa17dc472..cd5fe4137 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -3667,15 +3667,15 @@ void playerTick(bool arg0) f32 mdx, mdy; inputMouseGetScaledDelta(&mdx, &mdy); if (mdx || mdy) { - mdx *= 48.f; - mdy *= 48.f; + mdx *= 0.022f; + mdy *= 0.022f; mdx = (mdx < -128.f) ? -128.f : (mdx > 127.f) ? 127.f : mdx; mdy = (mdy < -128.f) ? -128.f : (mdy > 127.f) ? 127.f : mdy; if (g_Vars.currentplayerstats && !optionsGetForwardPitch(g_Vars.currentplayerstats->mpindex)) { mdy = -mdy; } - sp178 += mdy * 0.022f; - sp174 -= mdx * 0.022f; + sp178 += mdy; + sp174 -= mdx; } } #endif From 30071e8f645556285c3ed277eeb2eab15f2d9d73 Mon Sep 17 00:00:00 2001 From: Catherine Reprobate Date: Sun, 13 Apr 2025 10:35:43 -0700 Subject: [PATCH 32/34] port: call `joyReset()` when changing controllers This needs to be called for controller reassignments to take effect in MP modes --- port/src/optionsmenu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index 4771fc28b..29105ab93 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -597,8 +597,10 @@ static MenuItemHandlerResult menuhandlerController(s32 operation, struct menuite if (data->dropdown.value == 0) { // unassign controller inputAssignController(g_ExtMenuPlayer, -1); + joyReset(); } else if (data->dropdown.value <= numCtrls) { inputAssignController(g_ExtMenuPlayer, ctrls[data->dropdown.value - 1]); + joyReset(); } break; case MENUOP_GETSELECTEDINDEX: From ab73fdcc308407cc3cb4e1608fcc6a35e5649863 Mon Sep 17 00:00:00 2001 From: Catherine Reprobate Date: Sun, 13 Apr 2025 10:44:26 -0700 Subject: [PATCH 33/34] fixup: include header for `joyReset` --- port/src/optionsmenu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index 29105ab93..e077acb31 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -10,6 +10,7 @@ #include "game/menu.h" #include "game/gamefile.h" #include "game/player.h" +#include "lib/joy.h" #include "video.h" #include "input.h" #include "config.h" From f96a03e60f0dffbe45e8a58e9b9a56d2e6bf73d9 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sun, 27 Apr 2025 15:34:25 +0200 Subject: [PATCH 34/34] port: clean up previous PR --- port/include/input.h | 4 - port/include/mpsetups.h | 6 +- port/src/fs.c | 5 +- port/src/input.c | 27 -- port/src/mpsetups.c | 792 +++++++++++++++++++-------------------- src/game/mplayer/setup.c | 55 ++- 6 files changed, 433 insertions(+), 456 deletions(-) diff --git a/port/include/input.h b/port/include/input.h index 98f5928fc..6171c2696 100644 --- a/port/include/input.h +++ b/port/include/input.h @@ -270,8 +270,4 @@ const char *inputGetClipboard(void); // returns keymod values u32 inputGetKeyModState(void); -s32 inputMenuAlt1MenuPressed(s32 playerNum); -s32 inputMenuAlt2MenuPressed(s32 playerNum); -s32 inputMenuAltMenuPressed(s32 playerNum); - #endif diff --git a/port/include/mpsetups.h b/port/include/mpsetups.h index c54aee371..3ef143906 100644 --- a/port/include/mpsetups.h +++ b/port/include/mpsetups.h @@ -3,10 +3,10 @@ #include "types.h" -s32 mpsetupLoadCurrentFile(); -s32 mpsetupSaveCurrentFile(); +s32 mpsetupLoadCurrentFile(void); +s32 mpsetupSaveCurrentFile(void); void mpsetupLoadSetup(s32 slotindex); s32 mpsetupSaveSetup(s32 slotindex, u8 savefile); -void mpsetupCopyAllFromPak(); +void mpsetupCopyAllFromPak(void); #endif diff --git a/port/src/fs.c b/port/src/fs.c index 0eb4ef4c2..459e72392 100644 --- a/port/src/fs.c +++ b/port/src/fs.c @@ -284,10 +284,11 @@ void fsFileFree(FILE *f) fclose(f); } -s32 fsCreateDir(const char *path) { +s32 fsCreateDir(const char *path) +{ #ifdef PLATFORM_WIN32 return _mkdir(fsFullPath(path)); #else - return mkdir(fsFullPath(path), S_IRWXU | S_IRWXG); + return mkdir(fsFullPath(path), 0777); #endif } diff --git a/port/src/input.c b/port/src/input.c index ae131dbf5..96e37255e 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -1197,33 +1197,6 @@ s32 inputKeyJustPressed(u32 vk) return result; } -s32 inputMenuAlt1MenuPressed(s32 playerNum) -{ - s32 RSHOULDER = VK_JOY1_RSHOULDER + playerNum * INPUT_MAX_CONTROLLER_BUTTONS; - - if (playerNum == 0) { - return inputKeyJustPressed(VK_LCTRL) || inputKeyJustPressed(RSHOULDER); - } - - return inputKeyJustPressed(RSHOULDER); -} - -s32 inputMenuAlt2MenuPressed(s32 playerNum) -{ - s32 LSHOULDER = VK_JOY1_LSHOULDER + playerNum * INPUT_MAX_CONTROLLER_BUTTONS; - - if (playerNum == 0) { - return inputKeyJustPressed(VK_LALT) || inputKeyJustPressed(LSHOULDER); - } - - return inputKeyJustPressed(LSHOULDER); -} - -s32 inputMenuAltMenuPressed(s32 playerNum) -{ - return inputMenuAlt1MenuPressed(playerNum) || inputMenuAlt2MenuPressed(playerNum); -} - static inline u32 inputContToContKey(const u32 cont) { if (cont == 0) { diff --git a/port/src/mpsetups.c b/port/src/mpsetups.c index 8c4f4e1be..2c308fb9c 100644 --- a/port/src/mpsetups.c +++ b/port/src/mpsetups.c @@ -40,26 +40,29 @@ MP Setup File Format extern struct menudialogdef g_MpSaveSetupNameMenuDialog; -u8 filebuffer[sizeof(struct mpsetupfile)]; - -struct mpsetupfile g_MpSetupFile; -struct mpsetupfile g_ImportMpSetupFile; s16 g_MpCurrentSetup = -1; -u64 g_MpImportExportFilter[2]; +struct mpsetupfile g_MpSetupFile; -#define BUF_READ(dst, buf, type) { dst = *(type*)((buf)); buf += sizeof(type); } -#define BUF_WRITE(src, buf, type) { *((type*)(buf)) = src; buf += sizeof(type); } -#define BUF_WRITEBLOCK(buf, src, size) { \ - memcpy(buf, src, size); \ - buf += size; } +static struct mpsetupfile g_ImportMpSetupFile; +static u64 g_MpImportExportFilter[2]; -static inline void zeroFileBuffer() -{ - memset(filebuffer, 0, sizeof(struct mpsetupfile)); -} +static char g_StatusText[128]; +static char g_TitleImportExportDialog[20]; +static char g_LabelSetDefault[20] = "Set Default\n"; -char g_StatusText[128]; -struct menuitem g_StatusOkMenuItems[] = { +/* extended mpsetup menu definitions */ + +static MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data); +static MenuItemHandlerResult menuhandlerDeleteSetup(s32 operation, struct menuitem *item, union handlerdata *data); +static MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct menuitem *item, union handlerdata *data); +static MenuItemHandlerResult menuhandlerImportAction(s32 operation, struct menuitem *item, union handlerdata *data); +static MenuItemHandlerResult menuhandlerOpenImportExportDialog(s32 operation, struct menuitem *item, union handlerdata *data); +static MenuItemHandlerResult menuhandlerSelectSetupHandler(s32 operation, struct menuitem *item, union handlerdata *data); +static MenuItemHandlerResult menuhandlerSetupRename(s32 operation, struct menuitem *item, union handlerdata *data); +static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuitem *item, union handlerdata *data); +static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct menuitem *item, union handlerdata *data); + +static struct menuitem g_StatusOkMenuItems[] = { { MENUITEMTYPE_LABEL, 0, @@ -79,7 +82,7 @@ struct menuitem g_StatusOkMenuItems[] = { { MENUITEMTYPE_END }, }; -struct menudialogdef g_StatusOkDialog = { +static struct menudialogdef g_StatusOkDialog = { MENUDIALOGTYPE_SUCCESS, L_OPTIONS_345, // "Cool!" g_StatusOkMenuItems, @@ -88,7 +91,7 @@ struct menudialogdef g_StatusOkDialog = { NULL, }; -struct menuitem g_StatusErrorMenuItems[] = { +static struct menuitem g_StatusErrorMenuItems[] = { { MENUITEMTYPE_LABEL, 0, @@ -108,6 +111,7 @@ struct menuitem g_StatusErrorMenuItems[] = { { MENUITEMTYPE_END }, }; +/* public */ struct menudialogdef g_StatusErrorDialog = { MENUDIALOGTYPE_DANGER, L_OPTIONS_277, // "Failed" @@ -117,39 +121,7 @@ struct menudialogdef g_StatusErrorDialog = { NULL, }; -// #### Rename setup dialog -MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data) -{ - char *name = data->keyboard.string; - s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex; - struct setupblock *setup = &g_MpSetupFile.setups[slotindex]; - s32 err; - - switch (operation) { - case MENUOP_GETTEXT: -// strcpy(name, g_MpSetup.name); - strcpy(name, setup->bytes); - break; - case MENUOP_SETTEXT: - strcpy(g_MpSetup.name, name); - break; - case MENUOP_SET: - strcpy(setup->bytes, name); - err = mpsetupSaveSetup(slotindex, true); - if (!err) { - menuPopDialog(); - } - else { - // TODO -// menuPushDialog(&g_FilemgrFileSavedMenuDialog); - } - break; - } - - return 0; -} - -struct menuitem g_RenameSetupItems[] = { +static struct menuitem g_RenameSetupItems[] = { #if VERSION != VERSION_JPN_FINAL { MENUITEMTYPE_LABEL, @@ -171,7 +143,7 @@ struct menuitem g_RenameSetupItems[] = { { MENUITEMTYPE_END }, }; -struct menudialogdef g_RenameSetupDialog = { +static struct menudialogdef g_RenameSetupDialog = { MENUDIALOGTYPE_DEFAULT, (uintptr_t)"Setup Name:\n", g_RenameSetupItems, @@ -180,25 +152,7 @@ struct menudialogdef g_RenameSetupDialog = { NULL, }; -// #### Delete setup dialog -static s32 deleteSetup(); -MenuItemHandlerResult menuhandlerDeleteSetup(s32 operation, struct menuitem *item, union handlerdata *data) -{ - if (operation == MENUOP_SET) { - s32 err = deleteSetup(); - if (!err) { - menuPopDialog(); - menuPopDialog(); - } - else { - // TODO - } - } - - return 0; -} - -struct menuitem g_DeleteSetupItems[] = { +static struct menuitem g_DeleteSetupItems[] = { { MENUITEMTYPE_LABEL, 0, @@ -226,7 +180,7 @@ struct menuitem g_DeleteSetupItems[] = { { MENUITEMTYPE_END }, }; -struct menudialogdef g_DeleteSetupDialog = { +static struct menudialogdef g_DeleteSetupDialog = { MENUDIALOGTYPE_DANGER, (uintptr_t)"Delete Setup\n", g_DeleteSetupItems, @@ -235,112 +189,7 @@ struct menudialogdef g_DeleteSetupDialog = { NULL, }; -// #### Import (or Export) settings dialog -s32 importMpSetupFile(u8 op, u8 skipOverlap); -s32 exportMpSetupFile(); -struct menudialogdef g_ManageSettingsDialog; -struct menudialogdef g_ImportOverrideDialog; -MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct menuitem *item, union handlerdata *data) -{ - static const char *labels[] = { - "Select All", - "Select None", - "Import", - "Export", - }; - - s32 op = g_Menus[g_MpPlayerNum].mpsetup.unke24; - - struct mpsetupfile *setupfile = op == MPSETUP_OP_IMPORT ? &g_ImportMpSetupFile : &g_MpSetupFile; - - u8 numsetups = setupfile->numsetups; - u8 numitems = numsetups + 3; - u8 bank = data->list.value < 64 ? 0 : 1; - u8 bit = data->list.value - bank * 64; - u8 hasselection = (g_MpImportExportFilter[0] | g_MpImportExportFilter[1]) != 0; - s32 err; - - switch (operation) { - case MENUOP_GETCOLOUR: { - u32 colour = data->list.unk04; - if (data->list.value == numitems - 1) { - data->list.unk04 = hasselection ? colour : (colour & 0xffffff00) | 0x66; - } - break; - } - case MENUOP_GETOPTIONCOUNT: - data->list.value = numitems; - break; - case MENUOP_GETOPTIONTEXT: - if (data->list.value < numsetups) { - return (uintptr_t) setupfile->setups[data->list.value].bytes; - } - else { - // creates an offset to select the "Export" or "Import" label for the last item - u8 ofs = (data->list.value == numitems - 1) ? op - 1 : 0; - return (intptr_t)labels[data->list.value - numsetups + ofs]; - } - case MENUOP_SET: { - if (data->list.value < setupfile->numsetups) { - g_MpImportExportFilter[bank] ^= (1 << bit); - } - else { - s32 index = data->list.value - setupfile->numsetups; - - switch (index) { - // Select All - case 0: - g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1; - break; - // Select None - case 1: - g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = 0; - break; - // Export (or Import) - case 2: - if (hasselection) { - err = op == MPSETUP_OP_IMPORT ? importMpSetupFile(0, false) : exportMpSetupFile(); - if (!err) { - menuPopDialog(); - if (op == MPSETUP_OP_IMPORT) { - // back to the 'Manage Settings' screen - menuPopDialog(); - menuPushDialog(&g_ManageSettingsDialog); - } - else { - sprintf(g_StatusText, "File %s.bin\nwritten to the folder 'exported'\n", MPSETUP_FILENAME_EXP); - menuPushDialog(&g_StatusOkDialog); - } - } - else { - if (err == MPSETUP_IMPORT_CONFLICT) { - menuPopDialog(); - menuPushDialog(&g_ImportOverrideDialog); - } - else { - menuPushDialog(&g_StatusErrorDialog); - } - } - } - break; - } - } - } - case MENUOP_GETSELECTEDINDEX: - data->list.value = 0x000fffff; - break; - case MENUOP_GETLISTITEMCHECKBOX: { - if (data->list.value < numsetups) { - data->list.unk04 = (g_MpImportExportFilter[bank] & (1 << bit)); - } - break; - } - } - - return 0; -} - -struct menuitem g_ImportExportItems[] = { +static struct menuitem g_ImportExportItems[] = { { MENUITEMTYPE_LIST, 0, @@ -352,8 +201,7 @@ struct menuitem g_ImportExportItems[] = { { MENUITEMTYPE_END }, }; -char g_TitleImportExportDialog[20]; -struct menudialogdef g_ImportExportDialog = { +static struct menudialogdef g_ImportExportDialog = { MENUDIALOGTYPE_DEFAULT, (uintptr_t) g_TitleImportExportDialog, g_ImportExportItems, @@ -362,40 +210,7 @@ struct menudialogdef g_ImportExportDialog = { NULL, }; - -// #### Manage Import/Export settings dialog -s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op); -MenuItemHandlerResult menuhandlerOpenImportExportDialog(s32 operation, struct menuitem *item, union handlerdata *data) -{ - switch (operation) { - case MENUOP_SET: - { - if (item->param == MPSETUP_OP_IMPORT) { - strcpy(g_TitleImportExportDialog, "Import Settings\n"); - if (fsFileSize("$S/" MPSETUP_FILENAME_EXP ".bin") < 0) { - sprintf(g_StatusText, - "No import file found.\n" - "Place the file %s.bin\n" - "Next to your %s.bin file\n", MPSETUP_FILENAME_EXP, MPSETUP_FILENAME); - menuPushDialog(&g_StatusErrorDialog); - return 0; - } - - mpsetupLoadFile(&g_ImportMpSetupFile, MPSETUP_OP_IMPORT); - } - else { - strcpy(g_TitleImportExportDialog, "Export Settings\n"); - } - g_Menus[g_MpPlayerNum].mpsetup.unke24 = item->param; - g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1; - menuPushDialog(&g_ImportExportDialog); - } - } - - return 0; -} - -struct menuitem g_ManageImportExportItems[] = { +static struct menuitem g_ManageImportExportItems[] = { { MENUITEMTYPE_SELECTABLE, MPSETUP_OP_IMPORT, @@ -415,7 +230,7 @@ struct menuitem g_ManageImportExportItems[] = { { MENUITEMTYPE_END }, }; -struct menudialogdef g_ManageImportExportDialog = { +static struct menudialogdef g_ManageImportExportDialog = { MENUDIALOGTYPE_DEFAULT, (uintptr_t) "Import/Export\n", g_ManageImportExportItems, @@ -424,56 +239,20 @@ struct menudialogdef g_ManageImportExportDialog = { NULL, }; -// #### Manage settings dialog -struct menudialogdef g_ManageSetupDialog; -char g_LabelSetDefault[20] = "Set Default\n"; -MenuItemHandlerResult mpSelectSetupHandler(s32 operation, struct menuitem *item, union handlerdata *data) -{ - switch (operation) { - case MENUOP_GETCOLOUR: { - u32 colour = data->list.unk04; - if (data->list.value + 1 == g_MpSetupFile.defaultsetup) { - data->list.unk04 = (colour & 0xffff0000) | 0xff; - } - break; - } - case MENUOP_GETOPTIONCOUNT: - data->list.value = g_MpSetupFile.numsetups; - break; - case MENUOP_GETOPTIONTEXT: - return (uintptr_t) g_MpSetupFile.setups[data->list.value].bytes; - case MENUOP_SET: - { - g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value; - if (data->list.value == g_MpSetupFile.defaultsetup - 1) { - strcpy(g_LabelSetDefault, "Clear Default\n"); - } - else { - strcpy(g_LabelSetDefault, "Set Default\n"); - } - menuPushDialog(&g_ManageSetupDialog); - } - case MENUOP_GETSELECTEDINDEX: - data->list.value = 0xfffff; - break; - } - - return 0; -} - -struct menuitem g_MpManageSettingsListItems[] = { +static struct menuitem g_MpManageSettingsListItems[] = { { MENUITEMTYPE_LIST, 0, MENUITEMFLAG_LABEL_CUSTOMCOLOUR, 160, 0x00000042, - mpSelectSetupHandler, + menuhandlerSelectSetupHandler, }, { MENUITEMTYPE_END }, }; +/* public */ struct menudialogdef g_ManageSettingsDialog = { MENUDIALOGTYPE_DEFAULT, (uintptr_t) "Manage Settings\n", @@ -483,46 +262,7 @@ struct menudialogdef g_ManageSettingsDialog = { &g_ManageImportExportDialog, }; -struct menudialogdef g_RenameSetupDialog; -static MenuItemHandlerResult menuhandlerSetupRename(s32 operation, struct menuitem *item, union handlerdata *data) -{ - if (operation == MENUOP_SET) { - menuPushDialog(&g_RenameSetupDialog); - } - - return 0; -} - -static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuitem *item, union handlerdata *data) -{ - if (operation == MENUOP_SET) { - menuPushDialog(&g_DeleteSetupDialog); - } - - return 0; -} - -static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct menuitem *item, union handlerdata *data) -{ - if (operation == MENUOP_SET) { - s32 selected = g_Menus[g_MpPlayerNum].mpsetup.slotindex; - // clicked on "clear default" - if (selected == g_MpSetupFile.defaultsetup - 1) { - g_MpSetupFile.defaultsetup = -1; - strcpy(g_LabelSetDefault, "Set Default\n"); - } - else { - g_MpSetupFile.defaultsetup = selected + 1; - strcpy(g_LabelSetDefault, "Clear Default\n"); - } - - mpsetupSaveCurrentFile(); - } - - return 0; -} - -struct menuitem g_ManageSetupItems[] = { +static struct menuitem g_ManageSetupItems[] = { { MENUITEMTYPE_SELECTABLE, 0, @@ -566,7 +306,7 @@ struct menuitem g_ManageSetupItems[] = { { MENUITEMTYPE_END }, }; -struct menudialogdef g_ManageSetupDialog = { +static struct menudialogdef g_ManageSetupDialog = { MENUDIALOGTYPE_DEFAULT, (uintptr_t)"Manage Setup", g_ManageSetupItems, @@ -575,28 +315,10 @@ struct menudialogdef g_ManageSetupDialog = { NULL, }; -// #### Import: overwrite dialog -MenuItemHandlerResult menuhandlerImportAction(s32 operation, struct menuitem *item, union handlerdata *data) -{ - if (operation == MENUOP_SET) { - s32 err = importMpSetupFile(item->param, true); - if (!err) { - menuPopDialog(); - menuPushDialog(&g_ManageSettingsDialog); - } - else { - menuPushDialog(&g_StatusErrorDialog); - } - } - - return 0; -} - -struct menuitem g_ImportOverrideItems[] = { +static struct menuitem g_ImportOverrideItems[] = { { MENUITEMTYPE_LABEL, 0, -// MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING | MENUITEMFLAG_SMALLFONT, MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING, (uintptr_t) "How to resolve setups\nwith the same name?\n", 0, @@ -621,7 +343,7 @@ struct menuitem g_ImportOverrideItems[] = { { MENUITEMTYPE_END }, }; -struct menudialogdef g_ImportOverrideDialog = { +static struct menudialogdef g_ImportOverrideDialog = { MENUDIALOGTYPE_DEFAULT, (uintptr_t)"Name Conflicts\n", g_ImportOverrideItems, @@ -629,60 +351,40 @@ struct menudialogdef g_ImportOverrideDialog = { MENUDIALOGFLAG_LITERAL_TEXT, NULL, }; -// -------------------------------------------------------- -static void mpsetupDeserialize(struct mpsetupfile *setupfile, u8 *buffer) + +/* common utils */ + +static s32 mpsetupDeserialize(FILE *f, struct mpsetupfile *setupfile) { - BUF_READ(setupfile->version, buffer, u8); - BUF_READ(setupfile->defaultsetup, buffer, u8); - BUF_READ(setupfile->numsetups, buffer, u8); + s32 rx = 0; + + rx += fread(&setupfile->version, sizeof(setupfile->version), 1, f); + rx += fread(&setupfile->defaultsetup, sizeof(setupfile->defaultsetup), 1, f); + rx += fread(&setupfile->numsetups, sizeof(setupfile->numsetups), 1, f); for (int i = 0; i < setupfile->numsetups; ++i) { - memcpy(setupfile->setups[i].bytes, buffer, MPSETUP_BLOCKSIZE); - buffer += MPSETUP_BLOCKSIZE; + rx += fread(setupfile->setups[i].bytes, sizeof(setupfile->setups[i].bytes), 1, f); } + + return rx; } -void mpsetupSerialize(u8 *buffer, struct mpsetupfile *setupfile) +static s32 mpsetupSerialize(FILE *f, struct mpsetupfile *setupfile) { - BUF_WRITE(setupfile->version, buffer, u8); - BUF_WRITE(setupfile->defaultsetup, buffer, u8); - BUF_WRITE(setupfile->numsetups, buffer, u8); + s32 wx = 0; + + wx += fwrite(&setupfile->version, sizeof(setupfile->version), 1, f); + wx += fwrite(&setupfile->defaultsetup, sizeof(setupfile->defaultsetup), 1, f); + wx += fwrite(&setupfile->numsetups, sizeof(setupfile->numsetups), 1, f); for (int i = 0; i < setupfile->numsetups; ++i) { - BUF_WRITEBLOCK(buffer, setupfile->setups[i].bytes, MPSETUP_BLOCKSIZE) + wx += fwrite(setupfile->setups[i].bytes, sizeof(setupfile->setups[i].bytes), 1, f); } + + return wx; } -static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile); -static s32 deleteSetup() -{ - s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex; - for (int i = slotindex; i < g_MpSetupFile.numsetups - 1; ++i) { - u8* dst = g_MpSetupFile.setups[i].bytes; - u8* src = g_MpSetupFile.setups[i+1].bytes; - - memcpy(dst, src, MPSETUP_BLOCKSIZE); - } - - if (g_MpCurrentSetup > slotindex) { - g_MpCurrentSetup--; - } - else if (g_MpCurrentSetup == slotindex) { - g_MpCurrentSetup = -1; - } - - if (g_MpSetupFile.defaultsetup > slotindex + 1) { - g_MpSetupFile.defaultsetup--; - } - else if (g_MpSetupFile.defaultsetup == slotindex + 1) { - g_MpSetupFile.defaultsetup = 0; - } - - g_MpSetupFile.numsetups--; - return mpsetupSaveCurrentFile(); -} - -static FILE *openMpSetupFile(u8 mode, u8 op) { +static FILE *mpsetupOpenFile(bool write, u8 op) { const char *filename = fsFullPath("$S/" MPSETUP_FILENAME ".bin"); if (op == MPSETUP_OP_EXPORT) { @@ -693,8 +395,7 @@ static FILE *openMpSetupFile(u8 mode, u8 op) { } } filename = fsFullPath(MPSETUP_EXPORTDIR MPSETUP_FILENAME_EXP ".bin"); - } - else if (op == MPSETUP_OP_IMPORT) { + } else if (op == MPSETUP_OP_IMPORT) { // same name as export but different folder filename = fsFullPath("$S/" MPSETUP_FILENAME_EXP ".bin"); } @@ -707,15 +408,10 @@ static FILE *openMpSetupFile(u8 mode, u8 op) { fsFileFree(f); } - if (mode == 'r') { - f = fsFileOpenRead(filename); - } - else if (mode == 'w') { + if (write) { f = fsFileOpenWrite(filename); - } - else { - sysLogPrintf(LOG_ERROR, "openMpSetupFile: invalid file mode"); - return NULL; + } else { + f = fsFileOpenRead(filename); } if (f == NULL) { @@ -726,22 +422,33 @@ static FILE *openMpSetupFile(u8 mode, u8 op) { return f; } -s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op) +static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile) { - FILE *f = openMpSetupFile('r', op); + FILE *f = mpsetupOpenFile(true, op); if (f == NULL) { return -1; } - zeroFileBuffer(); + s32 nwritten = mpsetupSerialize(f, setupfile); + if (nwritten < 1) { + fsFileFree(f); + sysLogPrintf(LOG_ERROR, "Unable to write the MP setup file"); + snprintf(g_StatusText, sizeof(g_StatusText), "Unable to write the setup file\n"); + return -1; + } - fseek(f, 0L, SEEK_END); - size_t size = ftell(f); - fseek(f, 0, SEEK_SET); + fsFileFree(f); + return 0; +} - fread(filebuffer, 1, size, f); +static s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op) +{ + FILE *f = mpsetupOpenFile(false, op); + if (f == NULL) { + return -1; + } - mpsetupDeserialize(setupfile, filebuffer); + mpsetupDeserialize(f, setupfile); if (op == MPSETUP_OP_DEFAULT && setupfile->defaultsetup > 0) { mpsetupLoadSetup(setupfile->defaultsetup - 1); @@ -752,18 +459,7 @@ s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op) return 0; } -s32 mpsetupLoadCurrentFile() -{ - return mpsetupLoadFile(&g_MpSetupFile, MPSETUP_OP_DEFAULT); -} - -s32 mpsetupSaveCurrentFile() -{ - g_MpSetupFile.version = MPSETUP_VERSION; - return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile); -} - -s32 importMpSetupFile(u8 op, u8 skipOverlap) +static s32 mpsetupImportFile(u8 op, u8 skipOverlap) { if (!skipOverlap) { // check for names overlap @@ -790,7 +486,7 @@ s32 importMpSetupFile(u8 op, u8 skipOverlap) s16 importIdx = overlapIdx; if (overlapIdx < 0 || op == MPSETUP_IMPORT_ADD) { if (g_MpSetupFile.numsetups == MPSETUP_MAXSETUPS) { - sprintf(g_StatusText, "Number of setups exceeds %d\n", MPSETUP_MAXSETUPS); + snprintf(g_StatusText, sizeof(g_StatusText), "Number of setups exceeds %d\n", MPSETUP_MAXSETUPS); return -1; } importIdx = g_MpSetupFile.numsetups++; @@ -802,7 +498,7 @@ s32 importMpSetupFile(u8 op, u8 skipOverlap) return mpsetupSaveCurrentFile(); } -s32 exportMpSetupFile() +static s32 mpsetupExportFile(void) { struct mpsetupfile expMpSetupFile; expMpSetupFile.numsetups = 0; @@ -825,34 +521,320 @@ s32 exportMpSetupFile() s32 err = mpsetupSaveFile(MPSETUP_OP_EXPORT, &expMpSetupFile); if (err) { - sprintf(g_StatusText, "Unable to write\nsetup file\n"); + snprintf(g_StatusText, sizeof(g_StatusText), "Unable to write\nsetup file\n"); } return err; } -static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile) +static s32 mpsetupDelete(void) { - zeroFileBuffer(); - mpsetupSerialize(filebuffer, setupfile); - - FILE *f = openMpSetupFile('w', op); - if (f == NULL) { - return -1; + s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex; + for (int i = slotindex; i < g_MpSetupFile.numsetups - 1; ++i) { + u8* dst = g_MpSetupFile.setups[i].bytes; + u8* src = g_MpSetupFile.setups[i+1].bytes; + memcpy(dst, src, MPSETUP_BLOCKSIZE); } - size_t nwritten = fwrite(filebuffer, sizeof(struct mpsetupfile), 1, f); - if (nwritten < 1) { - fsFileFree(f); - sysLogPrintf(LOG_ERROR, "Unable to write the MP setup file"); - sprintf(g_StatusText, "Unable to write the setup file\n"); - return -1; + if (g_MpCurrentSetup > slotindex) { + g_MpCurrentSetup--; + } + else if (g_MpCurrentSetup == slotindex) { + g_MpCurrentSetup = -1; + } + + if (g_MpSetupFile.defaultsetup > slotindex + 1) { + g_MpSetupFile.defaultsetup--; + } + else if (g_MpSetupFile.defaultsetup == slotindex + 1) { + g_MpSetupFile.defaultsetup = 0; + } + + g_MpSetupFile.numsetups--; + return mpsetupSaveCurrentFile(); +} + +/* menu handlers */ + +// Rename setup dialog +static MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data) +{ + char *name = data->keyboard.string; + s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex; + struct setupblock *setup = &g_MpSetupFile.setups[slotindex]; + s32 err; + + switch (operation) { + case MENUOP_GETTEXT: + strcpy(name, setup->bytes); + break; + case MENUOP_SETTEXT: + strcpy(g_MpSetup.name, name); + break; + case MENUOP_SET: + strcpy(setup->bytes, name); + err = mpsetupSaveSetup(slotindex, true); + if (!err) { + menuPopDialog(); + } else { + // TODO + // menuPushDialog(&g_FilemgrFileSavedMenuDialog); + } + break; } - fsFileFree(f); return 0; } +// Delete setup dialog +static MenuItemHandlerResult menuhandlerDeleteSetup(s32 operation, struct menuitem *item, union handlerdata *data) +{ + if (operation == MENUOP_SET) { + s32 err = mpsetupDelete(); + if (!err) { + menuPopDialog(); + menuPopDialog(); + } else { + // TODO + } + } + + return 0; +} + +// Import (or Export) settings dialog +static MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct menuitem *item, union handlerdata *data) +{ + static const char *labels[] = { + "Select All", + "Select None", + "Import", + "Export", + }; + + s32 op = g_Menus[g_MpPlayerNum].mpsetup.unke24; + + struct mpsetupfile *setupfile = op == MPSETUP_OP_IMPORT ? &g_ImportMpSetupFile : &g_MpSetupFile; + + u8 numsetups = setupfile->numsetups; + u8 numitems = numsetups + 3; + u8 bank = data->list.value < 64 ? 0 : 1; + u8 bit = data->list.value - bank * 64; + u8 hasselection = (g_MpImportExportFilter[0] | g_MpImportExportFilter[1]) != 0; + u8 ofs; + s32 err; + u32 colour; + s32 index; + + switch (operation) { + case MENUOP_GETCOLOUR: + colour = data->list.unk04; + if (data->list.value == numitems - 1) { + data->list.unk04 = hasselection ? colour : (colour & 0xffffff00) | 0x66; + } + break; + + case MENUOP_GETOPTIONCOUNT: + data->list.value = numitems; + break; + + case MENUOP_GETOPTIONTEXT: + if (data->list.value < numsetups) { + return (uintptr_t) setupfile->setups[data->list.value].bytes; + } else { + // creates an offset to select the "Export" or "Import" label for the last item + ofs = (data->list.value == numitems - 1) ? op - 1 : 0; + return (intptr_t)labels[data->list.value - numsetups + ofs]; + } + + case MENUOP_SET: + if (data->list.value < setupfile->numsetups) { + g_MpImportExportFilter[bank] ^= (1 << bit); + } else { + index = data->list.value - setupfile->numsetups; + + switch (index) { + // Select All + case 0: + g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1; + break; + // Select None + case 1: + g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = 0; + break; + // Export (or Import) + case 2: + if (hasselection) { + err = op == MPSETUP_OP_IMPORT ? mpsetupImportFile(0, false) : mpsetupExportFile(); + if (!err) { + menuPopDialog(); + if (op == MPSETUP_OP_IMPORT) { + // back to the 'Manage Settings' screen + menuPopDialog(); + menuPushDialog(&g_ManageSettingsDialog); + } else { + snprintf(g_StatusText, sizeof(g_StatusText), "File %s.bin\nwritten to the folder 'exported'\n", MPSETUP_FILENAME_EXP); + menuPushDialog(&g_StatusOkDialog); + } + } else { + if (err == MPSETUP_IMPORT_CONFLICT) { + menuPopDialog(); + menuPushDialog(&g_ImportOverrideDialog); + } else { + menuPushDialog(&g_StatusErrorDialog); + } + } + } + break; + } + } + break; + + case MENUOP_GETSELECTEDINDEX: + data->list.value = 0x000fffff; + break; + + case MENUOP_GETLISTITEMCHECKBOX: + if (data->list.value < numsetups) { + data->list.unk04 = (g_MpImportExportFilter[bank] & (1 << bit)); + } + break; + } + + return 0; +} + +// Import: overwrite dialog +static MenuItemHandlerResult menuhandlerImportAction(s32 operation, struct menuitem *item, union handlerdata *data) +{ + if (operation == MENUOP_SET) { + s32 err = mpsetupImportFile(item->param, true); + if (!err) { + menuPopDialog(); + menuPushDialog(&g_ManageSettingsDialog); + } else { + menuPushDialog(&g_StatusErrorDialog); + } + } + + return 0; +} + +// Manage Import/Export settings dialog +static MenuItemHandlerResult menuhandlerOpenImportExportDialog(s32 operation, struct menuitem *item, union handlerdata *data) +{ + switch (operation) { + case MENUOP_SET: + if (item->param == MPSETUP_OP_IMPORT) { + strcpy(g_TitleImportExportDialog, "Import Settings\n"); + if (fsFileSize("$S/" MPSETUP_FILENAME_EXP ".bin") < 0) { + snprintf( + g_StatusText, sizeof(g_StatusText), + "No import file found.\n" + "Place the file %s.bin\n" + "Next to your %s.bin file\n", + MPSETUP_FILENAME_EXP, MPSETUP_FILENAME + ); + menuPushDialog(&g_StatusErrorDialog); + return 0; + } + + mpsetupLoadFile(&g_ImportMpSetupFile, MPSETUP_OP_IMPORT); + } else { + strcpy(g_TitleImportExportDialog, "Export Settings\n"); + } + g_Menus[g_MpPlayerNum].mpsetup.unke24 = item->param; + g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1; + menuPushDialog(&g_ImportExportDialog); + break; + } + + return 0; +} + +// Manage settings dialog +static MenuItemHandlerResult menuhandlerSelectSetupHandler(s32 operation, struct menuitem *item, union handlerdata *data) +{ + u32 colour; + switch (operation) { + case MENUOP_GETCOLOUR: + colour = data->list.unk04; + if (data->list.value + 1 == g_MpSetupFile.defaultsetup) { + data->list.unk04 = (colour & 0xffff0000) | 0xff; + } + break; + case MENUOP_GETOPTIONCOUNT: + data->list.value = g_MpSetupFile.numsetups; + break; + case MENUOP_GETOPTIONTEXT: + return (uintptr_t) g_MpSetupFile.setups[data->list.value].bytes; + case MENUOP_SET: + g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value; + if (data->list.value == g_MpSetupFile.defaultsetup - 1) { + strcpy(g_LabelSetDefault, "Clear Default\n"); + } else { + strcpy(g_LabelSetDefault, "Set Default\n"); + } + menuPushDialog(&g_ManageSetupDialog); + break; + case MENUOP_GETSELECTEDINDEX: + data->list.value = 0xfffff; + break; + } + + return 0; +} + +static MenuItemHandlerResult menuhandlerSetupRename(s32 operation, struct menuitem *item, union handlerdata *data) +{ + if (operation == MENUOP_SET) { + menuPushDialog(&g_RenameSetupDialog); + } + + return 0; +} + +static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuitem *item, union handlerdata *data) +{ + if (operation == MENUOP_SET) { + menuPushDialog(&g_DeleteSetupDialog); + } + + return 0; +} + +static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct menuitem *item, union handlerdata *data) +{ + if (operation == MENUOP_SET) { + s32 selected = g_Menus[g_MpPlayerNum].mpsetup.slotindex; + // clicked on "clear default" + if (selected == g_MpSetupFile.defaultsetup - 1) { + g_MpSetupFile.defaultsetup = -1; + strcpy(g_LabelSetDefault, "Set Default\n"); + } else { + g_MpSetupFile.defaultsetup = selected + 1; + strcpy(g_LabelSetDefault, "Clear Default\n"); + } + + mpsetupSaveCurrentFile(); + } + + return 0; +} + +/* public functions */ + +s32 mpsetupLoadCurrentFile(void) +{ + return mpsetupLoadFile(&g_MpSetupFile, MPSETUP_OP_DEFAULT); +} + +s32 mpsetupSaveCurrentFile(void) +{ + g_MpSetupFile.version = MPSETUP_VERSION; + return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile); +} + s32 mpsetupSaveSetup(s32 slotindex, u8 savefile) { struct savebuffer setup; @@ -880,7 +862,7 @@ void mpsetupLoadSetup(s32 index) g_MpCurrentSetup = index; } -void mpsetupCopyAllFromPak() +void mpsetupCopyAllFromPak(void) { if (fsFileSize("$S/" MPSETUP_FILENAME ".bin") > 0) { return; diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index a9d920c49..d06fb8c9f 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -43,6 +43,33 @@ extern struct menudialogdef g_FilemgrErrorMenuDialog; extern s32 g_MpWeaponSetNum; #endif +static inline s32 menuAlt1Pressed(s32 playerNum) +{ + const s32 rshoulderKey = VK_JOY1_RSHOULDER + playerNum * INPUT_MAX_CONTROLLER_BUTTONS; + + if (playerNum == 0) { + return inputKeyJustPressed(VK_LCTRL) || inputKeyJustPressed(rshoulderKey); + } + + return inputKeyJustPressed(rshoulderKey); +} + +static inline s32 menuAlt2Pressed(s32 playerNum) +{ + const s32 lshoulderKey = VK_JOY1_LSHOULDER + playerNum * INPUT_MAX_CONTROLLER_BUTTONS; + + if (playerNum == 0) { + return inputKeyJustPressed(VK_LALT) || inputKeyJustPressed(lshoulderKey); + } + + return inputKeyJustPressed(lshoulderKey); +} + +static inline s32 menuAltPressed(s32 playerNum) +{ + return menuAlt1Pressed(playerNum) || menuAlt2Pressed(playerNum); +} + MenuItemHandlerResult menuhandlerMpDropOut(s32 operation, struct menuitem *item, union handlerdata *data) { if (operation == MENUOP_SET) { @@ -2281,8 +2308,7 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * if (presets && data->list.value < mpGetNumUnlockedPresets()) { mp0f18dec4(data->list.value); g_MpCurrentSetup = -1; - } - else { + } else { mpsetupLoadSetup(data->list.value - numpresets); } @@ -2311,8 +2337,7 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem * case MENUOP_LISTITEMFOCUS: if (presets && data->list.value < mpGetNumUnlockedPresets()) { g_Menus[g_MpPlayerNum].mpsetup.slotindex = 0xffff; - } - else { + } else { g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value - numpresets; } break; @@ -2566,6 +2591,16 @@ MenuDialogHandlerResult menudialogMpSimulant(s32 operation, struct menudialogdef return false; } +MenuDialogHandlerResult mpLoadSettingsDialogHandler(s32 operation, struct menudialogdef *dialogdef, union handlerdata *data) +{ + if (operation == MENUOP_TICK) { + if (menuAltPressed(g_MpPlayerNum)) { + u8 presets = g_Menus[g_MpPlayerNum].mpsetup.showpresets; + g_Menus[g_MpPlayerNum].mpsetup.showpresets = 1 - presets; + } + } +} + struct menuitem g_MpCharacterMenuItems[] = { { MENUITEMTYPE_LABEL, @@ -2660,21 +2695,11 @@ struct menuitem g_MpLoadSettingsMenuItems[] = { { MENUITEMTYPE_END }, }; -MenuDialogHandlerResult loadSettingsDialogHandler(s32 operation, struct menudialogdef *dialogdef, union handlerdata *data) -{ - if (operation == MENUOP_TICK) { - if (inputMenuAltMenuPressed(g_MpPlayerNum)) { - u8 presets = g_Menus[g_MpPlayerNum].mpsetup.showpresets; - g_Menus[g_MpPlayerNum].mpsetup.showpresets = 1 - presets; - } - } -} - struct menudialogdef g_MpLoadSettingsMenuDialog = { MENUDIALOGTYPE_DEFAULT, L_MPMENU_139, // "Load Game Settings" g_MpLoadSettingsMenuItems, - loadSettingsDialogHandler, + mpLoadSettingsDialogHandler, MENUDIALOGFLAG_CLOSEONSELECT, NULL, };