From f5d851f7c2d6a491b866f75e087a88d93e6f53c8 Mon Sep 17 00:00:00 2001 From: Raf <> Date: Mon, 24 Mar 2025 03:33:34 +0800 Subject: [PATCH] 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