Merge pull request #596 from rafccq/port-enh-mpsetupfile

Enhanced multiplayer game setup save files
This commit is contained in:
fgsfds authored and GitHub committed 2025-04-27 14:26:39 +02:00
commit 9d2db1a346
27 files changed
+1245 -247

No files matched your search

+1
View File
@@ -25,3 +25,4 @@ tools/mkrom/mkrom
/.vs /.vs
CppProperties.json CppProperties.json
.idea .idea
cmake-build-debug
+1
View File
@@ -22,5 +22,6 @@ FILE *fsFileOpenRead(const char *name);
void fsFileFree(FILE *f); void fsFileFree(FILE *f);
const char *fsGetModDir(void); const char *fsGetModDir(void);
s32 fsCreateDir(const char *path);
#endif #endif
+7
View File
@@ -40,6 +40,7 @@ enum virtkey {
VK_DELETE = 76, VK_DELETE = 76,
VK_LCTRL = 224, VK_LCTRL = 224,
VK_LSHIFT = 225, VK_LSHIFT = 225,
VK_LALT = 226,
VK_RCTRL = 228, VK_RCTRL = 228,
VK_RSHIFT = 229, VK_RSHIFT = 229,
@@ -56,6 +57,8 @@ enum virtkey {
/* same order as SDL gamecontroller buttons plus two buttons for triggers */ /* same order as SDL gamecontroller buttons plus two buttons for triggers */
VK_JOY_BEGIN, VK_JOY_BEGIN,
VK_JOY1_BEGIN = 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_LTRIG = VK_JOY1_BEGIN + 30,
VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31, VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31,
VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
@@ -267,4 +270,8 @@ const char *inputGetClipboard(void);
// returns keymod values // returns keymod values
u32 inputGetKeyModState(void); u32 inputGetKeyModState(void);
s32 inputMenuAlt1MenuPressed(s32 playerNum);
s32 inputMenuAlt2MenuPressed(s32 playerNum);
s32 inputMenuAltMenuPressed(s32 playerNum);
#endif #endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef _IN_MPSETUPS_H
#define _IN_MPSETUPS_H
#include "types.h"
s32 mpsetupLoadCurrentFile();
s32 mpsetupSaveCurrentFile();
void mpsetupLoadSetup(s32 slotindex);
s32 mpsetupSaveSetup(s32 slotindex, u8 savefile);
void mpsetupCopyAllFromPak();
#endif
+11
View File
@@ -11,6 +11,9 @@
#include "platform.h" #include "platform.h"
#include "utils.h" #include "utils.h"
#include "fs.h" #include "fs.h"
#ifdef PLATFORM_WIN32
#include <direct.h>
#endif
#define DEFAULT_BASEDIR_NAME "data" #define DEFAULT_BASEDIR_NAME "data"
@@ -280,3 +283,11 @@ void fsFileFree(FILE *f)
{ {
fclose(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
}
+27
View File
@@ -1197,6 +1197,33 @@ s32 inputKeyJustPressed(u32 vk)
return result; 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) static inline u32 inputContToContKey(const u32 cont)
{ {
if (cont == 0) { if (cont == 0) {
+914
View File
@@ -0,0 +1,914 @@
#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"
#include <string.h>
#include "fs.h"
#include "system.h"
#include "mpsetups.h"
/*
MP Setup File Format
# header
[version{1}]
[defaultsetup{1}]
[numsetups{1}]
# setups
[setup_1{80}]
...
[setup_n{80}]
*/
#define MPSETUP_VERSION 1
#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;
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); }
#define BUF_WRITEBLOCK(buf, src, size) { \
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)
{
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[] = {
#if VERSION != VERSION_JPN_FINAL
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
(uintptr_t)"Enter the setup name:\n",
0,
NULL,
},
#endif
{
MENUITEMTYPE_KEYBOARD,
18,
0,
0,
1,
menuhandlerRenameSetup,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_RenameSetupDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Setup Name:\n",
g_RenameSetupItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
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[] = {
{
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,
};
// #### 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[] = {
{
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;
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[] = {
{
MENUITEMTYPE_LIST,
0,
MENUITEMFLAG_LABEL_CUSTOMCOLOUR,
160,
0x00000042,
mpSelectSetupHandler,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_ManageSettingsDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t) "Manage Settings\n",
g_MpManageSettingsListItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
&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[] = {
{
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_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)g_LabelSetDefault,
0,
menuhandlerSetupSetDefault,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_213, // "Back"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_ManageSetupDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Manage Setup",
g_ManageSetupItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
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[] = {
{
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);
BUF_READ(setupfile->defaultsetup, buffer, u8);
BUF_READ(setupfile->numsetups, buffer, u8);
for (int i = 0; i < setupfile->numsetups; ++i) {
memcpy(setupfile->setups[i].bytes, buffer, MPSETUP_BLOCKSIZE);
buffer += MPSETUP_BLOCKSIZE;
}
}
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);
for (int i = 0; i < setupfile->numsetups; ++i) {
BUF_WRITEBLOCK(buffer, setupfile->setups[i].bytes, MPSETUP_BLOCKSIZE)
}
}
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) {
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(filename) < 0) {
// setup file doesn't exist: create one
f = fsFileOpenWrite(filename);
fsFileFree(f);
}
if (mode == 'r') {
f = fsFileOpenRead(filename);
}
else if (mode == 'w') {
f = fsFileOpenWrite(filename);
}
else {
sysLogPrintf(LOG_ERROR, "openMpSetupFile: invalid file mode");
return NULL;
}
if (f == NULL) {
sysLogPrintf(LOG_ERROR, "Unable to open mp setup file");
return NULL;
}
return f;
}
s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op)
{
FILE *f = openMpSetupFile('r', op);
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);
mpsetupDeserialize(setupfile, filebuffer);
if (op == MPSETUP_OP_DEFAULT && setupfile->defaultsetup > 0) {
mpsetupLoadSetup(setupfile->defaultsetup - 1);
}
fsFileFree(f);
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)
{
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 mpsetupSaveCurrentFile();
}
s32 exportMpSetupFile()
{
struct mpsetupfile expMpSetupFile;
expMpSetupFile.numsetups = 0;
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;
u8 bit = i - bank * 64;
if (g_MpImportExportFilter[bank] & (1 << bit)) {
u8 n = expMpSetupFile.numsetups;
expMpSetupFile.numsetups++;
char *name = g_MpSetupFile.setups[i].bytes;
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, setupfile);
FILE *f = openMpSetupFile('w', op);
if (f == NULL) {
return -1;
}
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;
}
fsFileFree(f);
return 0;
}
s32 mpsetupSaveSetup(s32 slotindex, u8 savefile)
{
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 savefile ? mpsetupSaveCurrentFile() : 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_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(false);
}
+1 -1
View File
@@ -259,7 +259,7 @@ void mainInit(void)
frametimeInit(); frametimeInit();
profileInit(); profileInit();
smokesInit(); smokesInit();
mpInit(); mpInit(true);
pheadInit(); pheadInit();
paksInit(); paksInit();
pheadInit2(); pheadInit2();
+1 -5
View File
@@ -138,8 +138,6 @@ void bossfileLoad(void)
g_BossFile.usingmultipletunes = savebufferReadBits(&buffer, 1); g_BossFile.usingmultipletunes = savebufferReadBits(&buffer, 1);
g_AltTitleUnlocked = savebufferReadBits(&buffer, 1); g_AltTitleUnlocked = savebufferReadBits(&buffer, 1);
g_AltTitleEnabled = savebufferReadBits(&buffer, 1); g_AltTitleEnabled = savebufferReadBits(&buffer, 1);
func0f0d54c4(&buffer);
} }
if (failed) { if (failed) {
@@ -168,7 +166,7 @@ void bossfileSave(void)
savebufferOr(&buffer, g_Vars.language, 4); savebufferOr(&buffer, g_Vars.language, 4);
for (i = 0; i < ARRAYCOUNT(g_BossFile.teamnames); i++) { 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) { if (g_BossFile.tracknum == -1) {
@@ -185,8 +183,6 @@ void bossfileSave(void)
savebufferOr(&buffer, g_AltTitleUnlocked, 1); savebufferOr(&buffer, g_AltTitleUnlocked, 1);
savebufferOr(&buffer, g_AltTitleEnabled, 1); savebufferOr(&buffer, g_AltTitleEnabled, 1);
func0f0d54c4(&buffer);
fileid = bossfileFindFileId(); fileid = bossfileFindFileId();
if (fileid == 0) { if (fileid == 0) {
+3
View File
@@ -400,6 +400,8 @@ struct mpconfigfull *challengeLoadConfig(s32 confignum, u8 *buffer, s32 len)
extern struct mpstrings EXT_SEG _mpstringsSSegmentRomEnd; extern struct mpstrings EXT_SEG _mpstringsSSegmentRomEnd;
extern struct mpstrings EXT_SEG _mpstringsISegmentRomEnd; extern struct mpstrings EXT_SEG _mpstringsISegmentRomEnd;
extern struct mpconfig g_MpConfigs[];
BTYPE banks[][2] = { BTYPE banks[][2] = {
{ (BTYPE)REF_SEG _mpstringsESegmentRomStart, (BTYPE)REF_SEG _mpstringsESegmentRomEnd }, { (BTYPE)REF_SEG _mpstringsESegmentRomStart, (BTYPE)REF_SEG _mpstringsESegmentRomEnd },
{ (BTYPE)REF_SEG _mpstringsJSegmentRomStart, (BTYPE)REF_SEG _mpstringsJSegmentRomEnd }, { (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]; bank = banks[language_id][0];
loadedstrings = dmaExecWithAutoAlign(buffer2, bank + confignum * sizeof(struct mpstrings), sizeof(struct mpstrings)); loadedstrings = dmaExecWithAutoAlign(buffer2, bank + confignum * sizeof(struct mpstrings), sizeof(struct mpstrings));
mpconfig->config = g_MpConfigs[confignum];
mpconfig->strings = *loadedstrings; mpconfig->strings = *loadedstrings;
return mpconfig; return mpconfig;
+1 -33
View File
@@ -499,11 +499,6 @@ char *filemgrMenuTextFileType(struct menuitem *item)
case FILEOP_LOAD_GAME: case FILEOP_LOAD_GAME:
case FILEOP_READ_GAME: case FILEOP_READ_GAME:
return langGet(names[0]); 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_SAVE_MPPLAYER:
case FILEOP_WRITE_MPPLAYER: case FILEOP_WRITE_MPPLAYER:
case FILEOP_LOAD_MPPLAYER: case FILEOP_LOAD_MPPLAYER:
@@ -816,12 +811,6 @@ bool filemgrAttemptOperation(s32 device, bool closeonsuccess)
g_Menus[g_MpPlayerNum].fm.fileid, g_Menus[g_MpPlayerNum].fm.fileid,
g_Menus[g_MpPlayerNum].fm.deviceserial); g_Menus[g_MpPlayerNum].fm.deviceserial);
break; 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_GAME:
case FILEOP_WRITE_MPSETUP: case FILEOP_WRITE_MPSETUP:
case FILEOP_WRITE_MPPLAYER: case FILEOP_WRITE_MPPLAYER:
@@ -845,11 +834,6 @@ bool filemgrAttemptOperation(s32 device, bool closeonsuccess)
g_Menus[g_MpPlayerNum].fm.fileid, g_Menus[g_MpPlayerNum].fm.fileid,
g_Menus[g_MpPlayerNum].fm.deviceserial); g_Menus[g_MpPlayerNum].fm.deviceserial);
break; 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_GAME:
case FILEOP_READ_MPSETUP: case FILEOP_READ_MPSETUP:
case FILEOP_READ_MPPLAYER: case FILEOP_READ_MPPLAYER:
@@ -2780,7 +2764,7 @@ MenuDialogHandlerResult filemgrMainMenuDialog(s32 operation, struct menudialogde
g_Menus[g_MpPlayerNum].fm.filetypeplusone = 0; g_Menus[g_MpPlayerNum].fm.filetypeplusone = 0;
filelistCreate(0, FILETYPE_GAME); filelistCreate(0, FILETYPE_GAME);
mpInit(); mpInit(true);
// Set MP player names to "Player 1" through 4 if blank // Set MP player names to "Player 1" through 4 if blank
for (i = 0; i < MAX_PLAYERS; i++) { for (i = 0; i < MAX_PLAYERS; i++) {
@@ -3307,14 +3291,6 @@ struct menuitem g_FilemgrOperationsMenuItems[] = {
0, 0,
filemgrOpenCopyFileMenuHandler, filemgrOpenCopyFileMenuHandler,
}, },
{
MENUITEMTYPE_SELECTABLE,
FILETYPE_MPSETUP,
0,
L_OPTIONS_104, // "Combat Simulator Settings File"
0,
filemgrOpenCopyFileMenuHandler,
},
{ {
MENUITEMTYPE_SELECTABLE, MENUITEMTYPE_SELECTABLE,
FILETYPE_MPPLAYER, FILETYPE_MPPLAYER,
@@ -3347,14 +3323,6 @@ struct menuitem g_FilemgrOperationsMenuItems[] = {
0, 0,
filemgrOpenDeleteFileMenuHandler, filemgrOpenDeleteFileMenuHandler,
}, },
{
MENUITEMTYPE_SELECTABLE,
FILETYPE_MPSETUP,
0,
L_OPTIONS_104, // "Combat Simulator Settings File"
0,
filemgrOpenDeleteFileMenuHandler,
},
{ {
MENUITEMTYPE_SELECTABLE, MENUITEMTYPE_SELECTABLE,
FILETYPE_MPPLAYER, FILETYPE_MPPLAYER,
-16
View File
@@ -133,14 +133,6 @@ struct menuitem g_GameFiles4MbMenuItems[] = {
0, 0,
filemgrOpenCopyFileMenuHandler, filemgrOpenCopyFileMenuHandler,
}, },
{
MENUITEMTYPE_SELECTABLE,
1,
0,
L_OPTIONS_104, // "Combat Simulator Settings File"
0,
filemgrOpenCopyFileMenuHandler,
},
{ {
MENUITEMTYPE_SELECTABLE, MENUITEMTYPE_SELECTABLE,
2, 2,
@@ -173,14 +165,6 @@ struct menuitem g_GameFiles4MbMenuItems[] = {
0, 0,
filemgrOpenDeleteFileMenuHandler, filemgrOpenDeleteFileMenuHandler,
}, },
{
MENUITEMTYPE_SELECTABLE,
1,
0,
L_OPTIONS_104, // "Combat Simulator Settings File"
0,
filemgrOpenDeleteFileMenuHandler,
},
{ {
MENUITEMTYPE_SELECTABLE, MENUITEMTYPE_SELECTABLE,
2, 2,
+1 -5
View File
@@ -395,8 +395,6 @@ s32 gamefileLoad(s32 device)
frSetWeaponFound(WEAPON_REMOTEMINE); frSetWeaponFound(WEAPON_REMOTEMINE);
} }
#endif #endif
func0f0d54c4(&buffer);
gamefileApplyOptions(&g_GameFile); gamefileApplyOptions(&g_GameFile);
return 0; return 0;
@@ -499,7 +497,7 @@ s32 gamefileSave(s32 device, s32 fileid, u16 deviceserial)
if (device >= 0) { if (device >= 0) {
savebufferClear(&buffer); savebufferClear(&buffer);
func0f0d55a4(&buffer, g_GameFile.name); savebufferWriteString(&buffer, g_GameFile.name);
savebufferOr(&buffer, g_GameFile.thumbnail, 5); savebufferOr(&buffer, g_GameFile.thumbnail, 5);
savebufferOr(&buffer, g_GameFile.totaltime, 32); 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); savebufferOr(&buffer, g_GameFile.weaponsfound[i], 8);
} }
func0f0d54c4(&buffer);
ret = pakSaveAtGuid(device, fileid, PAKFILETYPE_GAME, buffer.bytes, &newfileid, 0); ret = pakSaveAtGuid(device, fileid, PAKFILETYPE_GAME, buffer.bytes, &newfileid, 0);
g_FilemgrLastPakError = ret; g_FilemgrLastPakError = ret;
+13 -3
View File
@@ -614,6 +614,15 @@ Gfx *menuitemListRender(Gfx *gdl, struct menurendercontext *context)
height = 0; 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); gdl = textRenderProjected(gdl, &x, &y, text2, chars, font, colour, context->width - left + context->x, height, sp128, 0);
// Consider a checkbox // Consider a checkbox
@@ -1520,6 +1529,7 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32
inputs->start = false; inputs->start = false;
} }
u8 maxlen = item->param == 0 ? 10 : item->param;
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
if (g_MenuKeyboardPlayer == g_MpPlayerNum) { if (g_MenuKeyboardPlayer == g_MpPlayerNum) {
// match caps state to keyboard shift/caps if typing with keyboard // match caps state to keyboard shift/caps if typing with keyboard
@@ -1531,7 +1541,7 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32
// handle text input // handle text input
s32 prevpos = strlen(kb->string); s32 prevpos = strlen(kb->string);
s32 pos = prevpos; 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) { if (result == -1) {
// cancel // cancel
kb->row = 5; kb->row = 5;
@@ -1608,7 +1618,7 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32
s32 textwidth; s32 textwidth;
s32 textheight; s32 textheight;
if (kb->string[9] == '\0') { if (kb->string[maxlen-1] == '\0') {
// String is not full // String is not full
i = 0; i = 0;
@@ -1644,7 +1654,7 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32
// Handle deleting // Handle deleting
if (delete && kb->string[0] != '\0') { if (delete && kb->string[0] != '\0') {
s32 deleted = false; s32 deleted = false;
s32 i = 10; s32 i = maxlen;
menuPlaySound(MENUSOUND_FOCUS); menuPlaySound(MENUSOUND_FOCUS);
-1
View File
@@ -473,7 +473,6 @@ void menuTick(void)
(g_MenuData.root == MENUROOT_MPSETUP || g_MenuData.root == MENUROOT_4MBMAINMENU)) { (g_MenuData.root == MENUROOT_MPSETUP || g_MenuData.root == MENUROOT_4MBMAINMENU)) {
var80062948 = 1; var80062948 = 1;
filelistCreate(0, FILETYPE_MPPLAYER); filelistCreate(0, FILETYPE_MPPLAYER);
filelistCreate(1, FILETYPE_MPSETUP);
} }
if (var80062944) { if (var80062944) {
File renamed without changes.
+74 -79
View File
@@ -28,6 +28,9 @@
#include "lib/lib_317f0.h" #include "lib/lib_317f0.h"
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
#include "fs.h"
#include "system.h"
#include "mpsetups.h"
// bss // bss
struct chrdata *g_MpAllChrPtrs[MAX_MPCHRS]; struct chrdata *g_MpAllChrPtrs[MAX_MPCHRS];
@@ -515,12 +518,6 @@ void mpPlayerSetDefaults(s32 playernum, bool autonames)
for (i = 0; i < ARRAYCOUNT(g_PlayerConfigsArray); i++) { for (i = 0; i < ARRAYCOUNT(g_PlayerConfigsArray); i++) {
g_PlayerConfigsArray[playernum].gunfuncs[i] = 0; 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) void func0f1881d4(s32 index)
@@ -532,7 +529,7 @@ void func0f1881d4(s32 index)
g_BotConfigsArray[index].difficulty = BOTDIFF_DISABLED; g_BotConfigsArray[index].difficulty = BOTDIFF_DISABLED;
} }
void mpInit(void) void mpInit(bool resetplayers)
{ {
s32 i; s32 i;
s32 j; s32 j;
@@ -565,8 +562,10 @@ void mpInit(void)
strcpy(g_MpSetup.name, ""); strcpy(g_MpSetup.name, "");
for (i = 0; i < ARRAYCOUNT(g_PlayerConfigsArray); i++) { if (resetplayers) {
mpPlayerSetDefaults(i, false); for (i = 0; i < ARRAYCOUNT(g_PlayerConfigsArray); i++) {
mpPlayerSetDefaults(i, false);
}
} }
for (i = 0; i < MAX_BOTS; i++) { for (i = 0; i < MAX_BOTS; i++) {
@@ -599,6 +598,16 @@ void mpInit(void)
} }
g_MpSetup.chrslots = 0; g_MpSetup.chrslots = 0;
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 #if VERSION >= VERSION_PAL_BETA
@@ -3532,7 +3541,7 @@ void mpplayerfileSaveWad(s32 playernum, struct savebuffer *buffer)
s32 j; s32 j;
u32 stack; 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 if (g_PlayerConfigsArray[playernum].time > 0x0fffffff) { // over 3106 days
g_PlayerConfigsArray[playernum].time = 0x0fffffff; g_PlayerConfigsArray[playernum].time = 0x0fffffff;
@@ -3683,8 +3692,6 @@ s32 mpplayerfileSave(s32 playernum, s32 device, s32 fileid, u16 deviceserial)
if (device >= 0) { if (device >= 0) {
savebufferClear(&buffer); savebufferClear(&buffer);
mpplayerfileSaveWad(playernum, &buffer); mpplayerfileSaveWad(playernum, &buffer);
func0f0d54c4(&buffer);
var80075bd0[2] = true; var80075bd0[2] = true;
ret = pakSaveAtGuid(device, fileid, PAKFILETYPE_MPPLAYER, buffer.bytes, &newfileid, 0); ret = pakSaveAtGuid(device, fileid, PAKFILETYPE_MPPLAYER, buffer.bytes, &newfileid, 0);
@@ -3717,8 +3724,6 @@ s32 mpplayerfileLoad(s32 playernum, s32 device, s32 fileid, u16 deviceserial)
g_PlayerConfigsArray[playernum].fileguid.deviceserial = deviceserial; g_PlayerConfigsArray[playernum].fileguid.deviceserial = deviceserial;
mpplayerfileLoadWad(playernum, &buffer, 1); mpplayerfileLoadWad(playernum, &buffer, 1);
func0f0d54c4(&buffer);
g_PlayerConfigsArray[playernum].handicap = 0x80; g_PlayerConfigsArray[playernum].handicap = 0x80;
return 0; return 0;
} }
@@ -3912,21 +3917,54 @@ void mp0f18dec4(s32 slot)
#endif #endif
} }
void mpsetupfileLoadWad(struct savebuffer *buffer) static u64 packWeaponSetRandomFilters()
{
u64 packed = 0;
for (int i = 0; i < NUM_MPWEAPONS; ++i) {
packed |= g_MpWeaponSetRandomFilters[i] != 0 ? (1LL << i) : 0;
}
return packed;
}
static void unpackWeaponSetRandomFilters(u64 packed)
{
for (int i = 0; i < NUM_MPWEAPONS; ++i) {
g_MpWeaponSetRandomFilters[i] = (packed & (1LL << i)) != 0;
}
}
void mpsetupfileLoadWad(struct savebuffer *buffer, u8 version)
{ {
s32 i; s32 i;
s32 j; s32 j;
savebufferReadString(buffer, g_MpSetup.name, false); if (version > 0) {
savebufferReadString_ext(buffer, g_MpSetup.name, false, MPSETUP_MAXNAME + 1);
}
else {
savebufferReadString(buffer, g_MpSetup.name, false);
}
savebufferReadBits(buffer, 4); savebufferReadBits(buffer, 4);
g_MpSetup.stagenum = savebufferReadBits(buffer, 7); g_MpSetup.stagenum = savebufferReadBits(buffer, 7);
g_MpSetup.scenario = savebufferReadBits(buffer, 3); g_MpSetup.scenario = savebufferReadBits(buffer, 3);
scenarioInit(); // version == 0 means we're only reading to convert, so no actions are needed
scenarioReadSave(buffer); 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, 21);
g_MpSetup.chrslots &= 0x000f; g_MpSetup.chrslots &= 0x000f;
for (i = 0; i < MAX_BOTS; i++) { for (i = 0; i < MAX_BOTS; i++) {
@@ -3947,13 +3985,20 @@ void mpsetupfileLoadWad(struct savebuffer *buffer)
g_BotConfigsArray[i].base.team = savebufferReadBits(buffer, 3); g_BotConfigsArray[i].base.team = savebufferReadBits(buffer, 3);
} }
mpGenerateBotNames(); if (version > 0) {
mpGenerateBotNames();
}
for (i = 0; i < ARRAYCOUNT(g_MpSetup.weapons); i++) { for (i = 0; i < ARRAYCOUNT(g_MpSetup.weapons); i++) {
g_MpSetup.weapons[i] = savebufferReadBits(buffer, 7); g_MpSetup.weapons[i] = savebufferReadBits(buffer, 7);
} }
func0f18913c(); if (version > 0) {
u64 wpnRndPacked = savebufferReadBits(buffer, 64);
unpackWeaponSetRandomFilters(wpnRndPacked);
}
g_MpWeaponSetNum = savebufferReadBits(buffer, 8);
g_MpSetup.timelimit = savebufferReadBits(buffer, 6); g_MpSetup.timelimit = savebufferReadBits(buffer, 6);
g_MpSetup.scorelimit = savebufferReadBits(buffer, 7); g_MpSetup.scorelimit = savebufferReadBits(buffer, 7);
@@ -3972,7 +4017,7 @@ void mpsetupfileSaveWad(struct savebuffer *buffer)
s32 mpbodynum; s32 mpbodynum;
s32 i; s32 i;
func0f0d55a4(buffer, g_MpSetup.name); savebufferWriteString_ext(buffer, g_MpSetup.name, MPSETUP_MAXNAME + 1);
for (i = 0; i < MAX_BOTS; i++) { for (i = 0; i < MAX_BOTS; i++) {
if (g_MpSetup.chrslots & (1 << (i + 4))) { if (g_MpSetup.chrslots & (1 << (i + 4))) {
@@ -3986,7 +4031,7 @@ void mpsetupfileSaveWad(struct savebuffer *buffer)
scenarioWriteSave(buffer); scenarioWriteSave(buffer);
savebufferOr(buffer, g_MpSetup.options, 21); savebufferOr(buffer, g_MpSetup.options, 32);
for (i = 0; i < MAX_BOTS; i++) { for (i = 0; i < MAX_BOTS; i++) {
savebufferOr(buffer, g_BotConfigsArray[i].type, 5); savebufferOr(buffer, g_BotConfigsArray[i].type, 5);
@@ -4019,6 +4064,10 @@ void mpsetupfileSaveWad(struct savebuffer *buffer)
savebufferOr(buffer, g_MpSetup.weapons[i], 7); savebufferOr(buffer, g_MpSetup.weapons[i], 7);
} }
u64 wpnRndPacked = packWeaponSetRandomFilters();
savebufferOr(buffer, wpnRndPacked, 64);
savebufferOr(buffer, g_MpWeaponSetNum, 8);
savebufferOr(buffer, g_MpSetup.timelimit, 6); savebufferOr(buffer, g_MpSetup.timelimit, 6);
savebufferOr(buffer, g_MpSetup.scorelimit, 7); savebufferOr(buffer, g_MpSetup.scorelimit, 7);
savebufferOr(buffer, g_MpSetup.teamscorelimit, 9); savebufferOr(buffer, g_MpSetup.teamscorelimit, 9);
@@ -4032,69 +4081,15 @@ void mpsetupfileGetOverview(char *arg0, char *filename, u16 *numsims, u16 *stage
{ {
struct savebuffer buffer; 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); *numsims = savebufferReadBits(&buffer, 4);
*stagenum = savebufferReadBits(&buffer, 7); *stagenum = savebufferReadBits(&buffer, 7);
*scenarionum = savebufferReadBits(&buffer, 3); *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) void func0f18e558(void)
{ {
s32 i; s32 i;
+6 -5
View File
@@ -70,7 +70,7 @@ struct mpscenario {
bool (*isroomhighlightedfunc)(RoomNum room); bool (*isroomhighlightedfunc)(RoomNum room);
void (*highlightroomfunc)(RoomNum room, s32 *arg1, s32 *arg2, s32 *arg3); void (*highlightroomfunc)(RoomNum room, s32 *arg1, s32 *arg2, s32 *arg3);
void *unk3c; // never hooked into nor fired void *unk3c; // never hooked into nor fired
void (*readsavefunc)(struct savebuffer *buffer); void (*readsavefunc)(struct savebuffer *buffer, u8 version);
void (*writesavefunc)(struct savebuffer *buffer); void (*writesavefunc)(struct savebuffer *buffer);
}; };
@@ -416,12 +416,13 @@ MenuItemHandlerResult menuhandlerMpOpenOptions(s32 operation, struct menuitem *i
* *
* Used by KOH to read the mphilltime. * 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) { if (g_MpScenarios[g_MpSetup.scenario].readsavefunc) {
g_MpScenarios[g_MpSetup.scenario].readsavefunc(buffer); g_MpScenarios[g_MpSetup.scenario].readsavefunc(buffer, version);
} else { } else {
savebufferReadBits(buffer, 8); u8 sz = version > 0 ? 32 : 8;
savebufferReadBits(buffer, sz);
} }
} }
@@ -438,7 +439,7 @@ void scenarioWriteSave(struct savebuffer *buffer)
if (g_MpScenarios[g_MpSetup.scenario].writesavefunc) { if (g_MpScenarios[g_MpSetup.scenario].writesavefunc) {
g_MpScenarios[g_MpSetup.scenario].writesavefunc(buffer); g_MpScenarios[g_MpSetup.scenario].writesavefunc(buffer);
} else { } else {
savebufferOr(buffer, 0, 8); savebufferOr(buffer, 0, 32);
} }
} }
+4 -3
View File
@@ -181,14 +181,15 @@ struct menudialogdef g_KohOptionsMenuDialog = {
NULL, NULL,
}; };
void kohReadSave(struct savebuffer *buffer) void kohReadSave(struct savebuffer *buffer, u8 version)
{ {
g_Vars.mphilltime = savebufferReadBits(buffer, 8); u8 sz = version > 0 ? 32 : 8;
g_Vars.mphilltime = savebufferReadBits(buffer, sz);
} }
void kohWriteSave(struct savebuffer *buffer) void kohWriteSave(struct savebuffer *buffer)
{ {
savebufferOr(buffer, g_Vars.mphilltime, 8); savebufferOr(buffer, g_Vars.mphilltime, 32);
} }
void kohInit(void) void kohInit(void)
+103 -60
View File
@@ -20,9 +20,13 @@
#include "lib/vi.h" #include "lib/vi.h"
#include "lib/rng.h" #include "lib/rng.h"
#include "lib/str.h" #include "lib/str.h"
#include "lib/joy.h"
#include "data.h" #include "data.h"
#include "gbiex.h" #include "gbiex.h"
#include "types.h" #include "types.h"
#include "system.h"
#include "input.h"
#include "mpsetups.h"
struct menuitem g_MpCharacterMenuItems[]; struct menuitem g_MpCharacterMenuItems[];
struct menudialogdef g_MpAddSimulantMenuDialog; struct menudialogdef g_MpAddSimulantMenuDialog;
@@ -31,6 +35,10 @@ struct menudialogdef g_MpChangeTeamNameMenuDialog;
struct menudialogdef g_MpEditSimulantMenuDialog; struct menudialogdef g_MpEditSimulantMenuDialog;
struct menudialogdef g_MpSaveSetupNameMenuDialog; struct menudialogdef g_MpSaveSetupNameMenuDialog;
extern struct menudialogdef g_ManageSettingsDialog;
extern struct menudialogdef g_FilemgrFileSavedMenuDialog;
extern struct menudialogdef g_FilemgrErrorMenuDialog;
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
extern s32 g_MpWeaponSetNum; extern s32 g_MpWeaponSetNum;
#endif #endif
@@ -451,9 +459,11 @@ MenuItemHandlerResult menuhandlerMpConfirmSaveChr(s32 operation, struct menuitem
return 0; return 0;
} }
extern struct menudialogdef g_StatusErrorDialog;
MenuItemHandlerResult menuhandlerMpSetupName(s32 operation, struct menuitem *item, union handlerdata *data) MenuItemHandlerResult menuhandlerMpSetupName(s32 operation, struct menuitem *item, union handlerdata *data)
{ {
char *name = data->keyboard.string; char *name = data->keyboard.string;
s32 err;
switch (operation) { switch (operation) {
case MENUOP_GETTEXT: case MENUOP_GETTEXT:
@@ -463,7 +473,14 @@ MenuItemHandlerResult menuhandlerMpSetupName(s32 operation, struct menuitem *ite
strcpy(g_MpSetup.name, name); strcpy(g_MpSetup.name, name);
break; break;
case MENUOP_SET: case MENUOP_SET:
filemgrPushSelectLocationDialog(7, FILETYPE_MPSETUP); err = mpsetupSaveSetup(g_MpSetupFile.numsetups, true);
if (!err) {
menuPushDialog(&g_FilemgrFileSavedMenuDialog);
g_MpCurrentSetup = g_MpSetupFile.numsetups - 1;
}
else {
menuPushDialog(&g_StatusErrorDialog);
}
break; break;
} }
@@ -474,7 +491,8 @@ MenuItemHandlerResult menuhandlerMpSaveSetupOverwrite(s32 operation, struct menu
{ {
if (operation == MENUOP_SET) { if (operation == MENUOP_SET) {
menuPopDialog(); menuPopDialog();
filemgrSaveOrLoad(&g_MpSetup.fileguid, FILEOP_SAVE_MPSETUP, 0); mpsetupSaveSetup(g_MpCurrentSetup, true);
menuPushDialog(&g_FilemgrFileSavedMenuDialog);
} }
return 0; return 0;
@@ -1075,18 +1093,18 @@ struct menuitem g_MpSaveSetupNameMenuItems[] = {
{ {
MENUITEMTYPE_LABEL, MENUITEMTYPE_LABEL,
0, 0,
MENUITEMFLAG_LESSLEFTPADDING, MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
L_MPMENU_189, // "Enter a name for your game setup file:" (uintptr_t)"Enter the setup name:\n",
0, 0,
NULL, NULL,
}, },
#endif #endif
{ {
MENUITEMTYPE_KEYBOARD, MENUITEMTYPE_KEYBOARD,
MPSETUP_MAXNAME,
0, 0,
0, 0,
0, 1,
0,
menuhandlerMpSetupName, menuhandlerMpSetupName,
}, },
{ MENUITEMTYPE_END }, { MENUITEMTYPE_END },
@@ -1112,10 +1130,10 @@ struct menuitem g_MpSaveSetupExistsMenuItems[] = {
NULL, NULL,
}, },
{ {
MENUITEMTYPE_LABEL, MENUITEMTYPE_SEPARATOR,
0,
0,
0, 0,
MENUITEMFLAG_LESSLEFTPADDING | MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_SMALLFONT,
(uintptr_t)&filemgrMenuTextDeviceName,
0, 0,
NULL, NULL,
}, },
@@ -1123,8 +1141,16 @@ struct menuitem g_MpSaveSetupExistsMenuItems[] = {
{ {
MENUITEMTYPE_LABEL, MENUITEMTYPE_LABEL,
0, 0,
MENUITEMFLAG_LESSLEFTPADDING, MENUITEMFLAG_LESSLEFTPADDING | MENUITEMFLAG_LITERAL_TEXT,
L_MPMENU_184, // "Do you want to save over your original game file?" (uintptr_t)"Save over your\noriginal setup?\n",
0,
NULL,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0, 0,
NULL, NULL,
}, },
@@ -2232,36 +2258,32 @@ MenuItemHandlerResult mpPlayerNameMenuHandler(s32 operation, struct menuitem *it
MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem *item, union handlerdata *data) MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem *item, union handlerdata *data)
{ {
u8 presets = g_Menus[g_MpPlayerNum].mpsetup.showpresets;
s32 numpresets = mpGetNumUnlockedPresets()*presets;
switch (operation) { switch (operation) {
case MENUOP_GETOPTIONCOUNT: case MENUOP_GETOPTIONCOUNT:
data->list.value = mpGetNumUnlockedPresets(); data->list.value = numpresets + g_MpSetupFile.numsetups;
if (g_FileLists[1] != NULL) {
data->list.value += g_FileLists[1]->numfiles;
}
break; break;
case MENUOP_GETOPTIONTEXT: case MENUOP_GETOPTIONTEXT:
if (data->list.value < mpGetNumUnlockedPresets()) { if (presets && data->list.value < mpGetNumUnlockedPresets()) {
return (uintptr_t)mpGetPresetNameBySlot(data->list.value); return (uintptr_t)mpGetPresetNameBySlot(data->list.value);
} }
if (g_FileLists[1] != NULL) { if (g_MpSetupFile.numsetups > 0) {
func0f0d564c(g_FileLists[1]->files[data->list.value - mpGetNumUnlockedPresets()].name, g_StringPointer, false); 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; return (uintptr_t)g_StringPointer;
} }
break; break;
case MENUOP_SET: case MENUOP_SET:
mpCloseDialogsForNewSetup(); mpCloseDialogsForNewSetup();
if (data->list.value < mpGetNumUnlockedPresets()) { if (presets && data->list.value < mpGetNumUnlockedPresets()) {
mp0f18dec4(data->list.value); mp0f18dec4(data->list.value);
} else if (g_FileLists[1] != NULL) { g_MpCurrentSetup = -1;
struct filelistfile *file = &g_FileLists[1]->files[data->list.value - mpGetNumUnlockedPresets()]; }
struct fileguid guid; else {
mpsetupLoadSetup(data->list.value - numpresets);
guid.fileid = file->fileid;
guid.deviceserial = file->deviceserial;
filemgrSaveOrLoad(&guid, FILEOP_LOAD_MPSETUP, 0);
} }
if (item->param == 1) { if (item->param == 1) {
@@ -2276,36 +2298,22 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem *
data->list.value = 0xfffff; data->list.value = 0xfffff;
break; break;
case MENUOP_GETOPTGROUPCOUNT: case MENUOP_GETOPTGROUPCOUNT:
data->list.value = 1; data->list.value = presets ? 2 : 1;
if (g_FileLists[1] != NULL) {
data->list.value += g_FileLists[1]->numdevices;
}
break; break;
case MENUOP_GETOPTGROUPTEXT: 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)langGet(L_MPMENU_141); // "Presets"
} }
if (g_FileLists[1] != NULL) { return (uintptr_t)"Custom";
return (uintptr_t)filemgrGetDeviceNameOrStartIndex(1, operation, data->list.value - 1);
}
break;
case MENUOP_GETGROUPSTARTINDEX: case MENUOP_GETGROUPSTARTINDEX:
if (data->list.value == 0) { data->list.groupstartindex = data->list.value == 0 ? 0 : numpresets;
data->list.groupstartindex = 0;
} else {
data->list.groupstartindex = mpGetNumUnlockedPresets();
if (g_FileLists[1] != NULL) {
data->list.groupstartindex += filemgrGetDeviceNameOrStartIndex(1, operation, data->list.value - 1);
}
}
break; break;
case MENUOP_LISTITEMFOCUS: case MENUOP_LISTITEMFOCUS:
if (data->list.value < mpGetNumUnlockedPresets()) { if (presets && data->list.value < mpGetNumUnlockedPresets()) {
g_Menus[g_MpPlayerNum].mpsetup.slotindex = 0xffff; g_Menus[g_MpPlayerNum].mpsetup.slotindex = 0xffff;
} else { }
g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value - mpGetNumUnlockedPresets(); else {
g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value - numpresets;
} }
break; break;
} }
@@ -2315,21 +2323,21 @@ MenuItemHandlerResult mpLoadSettingsMenuHandler(s32 operation, struct menuitem *
char *mpMenuTextMpconfigMarquee(struct menuitem *item) char *mpMenuTextMpconfigMarquee(struct menuitem *item)
{ {
char filename[20]; char filename[MPSETUP_MAXNAME+1];
u16 numsims; u16 numsims;
u16 stagenum; u16 stagenum;
u16 scenarionum; u16 scenarionum;
s32 arenanum; s32 arenanum;
s32 i; 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 #if VERSION >= VERSION_NTSC_1_0
arenanum = -1; arenanum = -1;
#else #else
arenanum = 0; arenanum = 0;
#endif #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); filename, &numsims, &stagenum, &scenarionum);
for (i = 0; i < ARRAYCOUNT(g_MpArenas); i++) { for (i = 0; i < ARRAYCOUNT(g_MpArenas); i++) {
@@ -2633,14 +2641,40 @@ struct menuitem g_MpLoadSettingsMenuItems[] = {
0, 0,
NULL, 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 }, { 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 = { struct menudialogdef g_MpLoadSettingsMenuDialog = {
MENUDIALOGTYPE_DEFAULT, MENUDIALOGTYPE_DEFAULT,
L_MPMENU_139, // "Load Game Settings" L_MPMENU_139, // "Load Game Settings"
g_MpLoadSettingsMenuItems, g_MpLoadSettingsMenuItems,
NULL, loadSettingsDialogHandler,
MENUDIALOGFLAG_CLOSEONSELECT, MENUDIALOGFLAG_CLOSEONSELECT,
NULL, NULL,
}; };
@@ -5016,13 +5050,10 @@ MenuItemHandlerResult menuhandler0017ef30(s32 operation, struct menuitem *item,
MenuItemHandlerResult menuhandlerMpSaveSettings(s32 operation, struct menuitem *item, union handlerdata *data) MenuItemHandlerResult menuhandlerMpSaveSettings(s32 operation, struct menuitem *item, union handlerdata *data)
{ {
if (operation == MENUOP_SET) { if (operation == MENUOP_SET) {
if (g_MpSetup.fileguid.fileid == 0) { if (g_MpCurrentSetup < 0) {
menuPushDialog(&g_MpSaveSetupNameMenuDialog); menuPushDialog(&g_MpSaveSetupNameMenuDialog);
} else { }
#if VERSION >= VERSION_NTSC_1_0 else {
filemgrSetDevice1BySerial(g_MpSetup.fileguid.deviceserial);
#endif
menuPushDialog(&g_MpSaveSetupExistsMenuDialog); menuPushDialog(&g_MpSaveSetupExistsMenuDialog);
} }
} }
@@ -5365,6 +5396,10 @@ MenuDialogHandlerResult menudialogCombatSimulator(s32 operation, struct menudial
g_Vars.waitingtojoin[1] = false; g_Vars.waitingtojoin[1] = false;
g_Vars.waitingtojoin[2] = false; g_Vars.waitingtojoin[2] = false;
g_Vars.waitingtojoin[3] = false; g_Vars.waitingtojoin[3] = false;
// load the setup file when entering the Combat Simulator
mpsetupCopyAllFromPak();
mpsetupLoadCurrentFile();
} }
if (g_Menus[g_MpPlayerNum].curdialog if (g_Menus[g_MpPlayerNum].curdialog
@@ -5757,6 +5792,14 @@ struct menuitem g_MpAdvancedSetupMenuItems[] = {
0, 0,
NULL, NULL,
}, },
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_OPENSDIALOG | MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LOCKABLEMAJOR,
(uintptr_t)"Manage Settings\n",
0,
(void *)&g_ManageSettingsDialog,
},
{ {
MENUITEMTYPE_SELECTABLE, MENUITEMTYPE_SELECTABLE,
0, 0,
+32 -24
View File
@@ -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. * 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. * 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) { for (; bit; bit >>= 1) {
if (bit & value) { 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. * 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) { for (; bit; bit >>= 1) {
s32 bitindex = buffer->bitpos % 8; 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 * Read the specified amount of bits from the buffer and return it as an
* integer, advancing the internal pointer. * 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); u64 bit = 1LL << (numbits - 1);
u32 value = 0; u64 value = 0;
for (; bit; bit >>= 1) { for (; bit; bit >>= 1) {
s32 bitindex = buffer->bitpos % 8; s32 bitindex = buffer->bitpos % 8;
@@ -470,24 +470,17 @@ 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 * Read a zero-terminated string from the buffer and move the buffer's internal
* pointer past the end of the string. * 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; bool foundnull = false;
s32 index = 0; s32 index = 0;
s32 i; s32 i;
for (i = 0; i < 10; i++) { for (i = 0; i < len; i++) {
s32 byte = savebufferReadBits(buffer, 8); s32 byte = savebufferReadBits(buffer, 8);
if (!foundnull) { if (!foundnull) {
@@ -509,12 +502,17 @@ void savebufferReadString(struct savebuffer *buffer, char *dst, bool addlinebrea
dst[index] = '\0'; 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 savebufferWriteString_ext(struct savebuffer *buffer, char *src, u8 len)
{ {
bool done = false; bool done = false;
s32 i; s32 i;
for (i = 0; i < 10; i++) { for (i = 0; i < len; i++) {
if (!done) { if (!done) {
if (src[i] == '\0') { if (src[i] == '\0') {
done = true; done = true;
@@ -532,12 +530,22 @@ void func0f0d55a4(struct savebuffer *buffer, char *src)
} }
} }
void func0f0d564c(u8 *data, char *dst, bool addlinebreak) void savebufferWriteString(struct savebuffer *buffer, char *src)
{
savebufferWriteString_ext(buffer, src, 10);
}
void func0f0d564c_ext(u8 *data, char *dst, bool addlinebreak, u8 len)
{ {
struct savebuffer buffer; struct savebuffer buffer;
savebufferWriteData(&buffer, data, 10); savebufferWriteData(&buffer, data, len);
savebufferReadString(&buffer, dst, addlinebreak); 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 #if VERSION >= VERSION_NTSC_1_0
+4
View File
@@ -4756,6 +4756,10 @@ enum weaponnum {
#define EXTRA_SLEEP_TIME 1000LL // 100us #define EXTRA_SLEEP_TIME 1000LL // 100us
#define MPSETUP_MAXSETUPS 128
#define MPSETUP_MAXNAME 17
#define MPSETUP_BLOCKSIZE 80
#endif #endif
#endif #endif
+3
View File
@@ -562,6 +562,9 @@ extern s32 g_FileAutoSelect;
extern u8 g_MpWeaponSetRandomFilters[NUM_MPWEAPONS]; extern u8 g_MpWeaponSetRandomFilters[NUM_MPWEAPONS];
extern s32 g_MpWeaponRandomFilterNum; extern s32 g_MpWeaponRandomFilterNum;
extern struct mpsetupfile g_MpSetupFile;
extern s16 g_MpCurrentSetup;
#define PLAYER_EXTCFG() g_PlayerExtCfg[g_Vars.currentplayerstats->mpindex & 3] #define PLAYER_EXTCFG() g_PlayerExtCfg[g_Vars.currentplayerstats->mpindex & 3]
#define PLAYER_DEFAULT_FOV (PLAYER_EXTCFG().fovy) #define PLAYER_DEFAULT_FOV (PLAYER_EXTCFG().fovy)
+2 -3
View File
@@ -13,7 +13,7 @@ void func0f187fbc(s32 playernum);
void func0f187fec(void); void func0f187fec(void);
void mpPlayerSetDefaults(s32 playernum, bool autonames); void mpPlayerSetDefaults(s32 playernum, bool autonames);
void func0f1881d4(s32 index); void func0f1881d4(s32 index);
void mpInit(void); void mpInit(bool resetplayers);
void mpGetTeamsWithDefaultName(u8 *mask); void mpGetTeamsWithDefaultName(u8 *mask);
void mpSetTeamNamesToDefault(u8 mask); void mpSetTeamNamesToDefault(u8 mask);
void mpSetDefaultNamesIfEmpty(void); void mpSetDefaultNamesIfEmpty(void);
@@ -118,11 +118,10 @@ s32 mpGetNumUnlockedPresets(void);
char *mpGetPresetNameBySlot(s32 slot); char *mpGetPresetNameBySlot(s32 slot);
void mpApplyConfig(struct mpconfigfull *mpconfig); void mpApplyConfig(struct mpconfigfull *mpconfig);
void mp0f18dec4(s32 arg0); void mp0f18dec4(s32 arg0);
void mpsetupfileLoadWad(struct savebuffer *buffer); void mpsetupfileLoadWad(struct savebuffer *buffer, u8 version);
void mpsetupfileSaveWad(struct savebuffer *buffer); void mpsetupfileSaveWad(struct savebuffer *buffer);
void mpsetupfileGetOverview(char *arg0, char *filename, u16 *numsims, u16 *stagenum, u16 *scenarionum); void mpsetupfileGetOverview(char *arg0, char *filename, u16 *numsims, u16 *stagenum, u16 *scenarionum);
s32 mpsetupfileSave(s32 device, s32 filenum, u16 deviceserial); s32 mpsetupfileSave(s32 device, s32 filenum, u16 deviceserial);
s32 mpsetupfileLoad(s32 device, s32 filenum, u16 deviceserial);
void func0f18e558(void); void func0f18e558(void);
struct modeldef *func0f18e57c(s32 index, s32 *headnum); struct modeldef *func0f18e57c(s32 index, s32 *headnum);
+1 -1
View File
@@ -17,7 +17,7 @@ struct mpscenariooverview {
extern struct mpscenariooverview g_MpScenarioOverviews[6]; extern struct mpscenariooverview g_MpScenarioOverviews[6];
MenuItemHandlerResult menuhandlerMpOpenOptions(s32 operation, struct menuitem *item, union handlerdata *data); 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 scenarioWriteSave(struct savebuffer *buffer);
void scenarioInit(void); void scenarioInit(void);
s32 scenarioNumProps(void); s32 scenarioNumProps(void);
+7 -5
View File
@@ -11,14 +11,16 @@ Gfx *func0f0d49c8(Gfx *gdl);
Gfx *func0f0d4a3c(Gfx *gdl, s32 arg1); Gfx *func0f0d4a3c(Gfx *gdl, s32 arg1);
Gfx *func0f0d4c80(Gfx *gdl); Gfx *func0f0d4c80(Gfx *gdl);
Gfx *menugfxDrawPlane(Gfx *gdl, s32 x1, s32 y1, s32 x2, s32 y2, u32 colour1, u32 colour2, s32 type); 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 savebufferOr(struct savebuffer *buffer, u64 arg1, s32 arg2);
void savebufferWriteBits(struct savebuffer *buffer, u32 value, s32 numbits, u8 *dst); void savebufferWriteBits(struct savebuffer *buffer, u64 value, s32 numbits, u8 *dst);
u32 savebufferReadBits(struct savebuffer *buffer, s32 offset); u64 savebufferReadBits(struct savebuffer *buffer, s32 offset);
void savebufferClear(struct savebuffer *buffer); void savebufferClear(struct savebuffer *buffer);
void savebufferWriteData(struct savebuffer *buffer, u8 *data, u8 len); 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 savebufferReadString(struct savebuffer *buffer, char *dst, bool addlinebreak);
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 func0f0d564c(u8 *data, char *dst, bool addlinebreak);
void func0f0d5690(u8 *dst, char *buffer); void func0f0d5690(u8 *dst, char *buffer);
void savebufferWriteGuid(struct savebuffer *buffer, struct fileguid *guid); void savebufferWriteGuid(struct savebuffer *buffer, struct fileguid *guid);
+16 -3
View File
@@ -3295,7 +3295,7 @@ struct menuitemdata_dropdown {
}; };
struct menuitemdata_keyboard { struct menuitemdata_keyboard {
char string[11]; char string[MPSETUP_MAXNAME+1];
s8 col; s8 col;
s8 row; s8 row;
u8 capslock : 1; // Pressed A on caps button u8 capslock : 1; // Pressed A on caps button
@@ -3774,6 +3774,7 @@ struct menudata_main {
struct menudata_mpsetup { struct menudata_mpsetup {
u32 slotindex; u32 slotindex;
u32 slotcount; u32 slotcount;
u8 showpresets;
u32 unke24; u32 unke24;
}; };
@@ -3982,13 +3983,14 @@ struct menu {
union { union {
struct menudata_endscreen endscreen; struct menudata_endscreen endscreen;
struct menudata_main main; struct menudata_main main;
struct menudata_mpsetup mpsetup;
struct menudata_mppause mppause; struct menudata_mppause mppause;
struct menudata_mpend mpend; struct menudata_mpend mpend;
struct menudata_filemgr fm; struct menudata_filemgr fm;
struct menudata_main4mb main4mb; struct menudata_main4mb main4mb;
struct menudata_training training; struct menudata_training training;
}; };
struct menudata_mpsetup mpsetup;
}; };
struct gamefile { struct gamefile {
@@ -4080,7 +4082,7 @@ struct missionconfig {
}; };
struct mpsetup { struct mpsetup {
/*0x800acb88*/ char name[12]; /*0x800acb88*/ char name[MPSETUP_MAXNAME+1];
/*0x800acb94*/ u32 options; /*0x800acb94*/ u32 options;
/*0x800acb98*/ u8 scenario; /*0x800acb98*/ u8 scenario;
/*0x800acb99*/ u8 stagenum; /*0x800acb99*/ u8 stagenum;
@@ -6156,6 +6158,17 @@ struct extplayerconfig {
s32 usereloads; s32 usereloads;
}; };
struct setupblock {
u8 bytes[MPSETUP_BLOCKSIZE];
};
struct mpsetupfile {
u8 version;
u8 defaultsetup;
u8 numsetups;
struct setupblock setups[MPSETUP_MAXSETUPS];
};
#endif #endif
#endif #endif