From b1f15a35baf673ae970f606e6a46f7d4521e3f9b Mon Sep 17 00:00:00 2001 From: Zwip-Zwap Zapony Date: Tue, 28 May 2024 14:25:30 +0200 Subject: [PATCH] Use a three-option menu instead of a yes/no prompt --- src/m_menu.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++----- src/m_menu.h | 2 +- src/m_misc.c | 2 +- 3 files changed, 227 insertions(+), 26 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 86f8516b6..a459abf41 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -140,7 +140,7 @@ static char *char_notes = NULL; boolean menuactive = false; boolean fromlevelselect = false; -tic_t shieldbuttonprompt = 0; // Show a prompt about the new Shield button for old configs // TODO: 2.3: Remove +tic_t shieldprompt_timer = 0; // Show a prompt about the new Shield button for old configs // TODO: 2.3: Remove typedef enum { @@ -3162,7 +3162,7 @@ static void Command_Manual_f(void) if (modeattacking) return; M_StartControlPanel(); - if (shieldbuttonprompt) return; // TODO: 2.3: Delete this line + if (shieldprompt_timer) return; // TODO: 2.3: Delete this line currentMenu = &MISC_HelpDef; itemOn = 0; } @@ -3342,7 +3342,7 @@ boolean M_Responder(event_t *ev) if (modeattacking) return true; M_StartControlPanel(); - if (shieldbuttonprompt) return true; // TODO: 2.3: Delete this line + if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line M_Options(0); // Uncomment the below if you want the menu to reset to the top each time like before. M_SetupNextMenu will fix it automatically. //OP_SoundOptionsDef.lastOn = 0; @@ -3353,7 +3353,7 @@ boolean M_Responder(event_t *ev) if (modeattacking) return true; M_StartControlPanel(); - if (shieldbuttonprompt) return true; // TODO: 2.3: Delete this line + if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line M_Options(0); M_VideoModeMenu(0); return true; @@ -3365,7 +3365,7 @@ boolean M_Responder(event_t *ev) if (modeattacking) return true; M_StartControlPanel(); - if (shieldbuttonprompt) return true; // TODO: 2.3: Delete this line + if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line M_Options(0); M_SetupNextMenu(&OP_MainDef); return true; @@ -3636,27 +3636,230 @@ void M_Drawer(void) } } -// Handle the "Do you want to assign Shield Ability now?" pop-up for old configs // TODO: 2.3: Remove -static void M_ShieldButtonResponse(INT32 ch) +// Handle the "Do you want to assign Shield Ability now?" pop-up for old configs // TODO: 2.3: Remove this line... +static UINT8 shieldprompt_currentchoice = 0; // ...and this line... + +static void M_ShieldPromptUseDefaults(void) // ...and this function { - if (I_GetTime() <= shieldbuttonprompt) // Don't mash past the pop-up by accident! + // With a default config from v2.2.10 to v2.2.13, the B button will be set to Custom 1, + // and Controls per Key defaults to "One", so it will override the default Shield button. + // A default config from v2.2.0 to v2.2.9 has Next Weapon on B, so it suffers from this too. + + // So for "Use default Shield Ability buttons", we should update old configs to mitigate gamepad conflicts + // (even with "Several" Controls per Key!), and show a message with the default bindings + + for (setupcontrols = gamecontrol; true; setupcontrols = gamecontrolbis) // Do stuff for both P1 and P2 { - stopstopmessage = true; - return; + INT32 JOY1 = (setupcontrols == gamecontrol) ? KEY_JOY1 : KEY_2JOY1; // Is this for P1 or for P2? + + if ((setupcontrols[GC_CUSTOM1][0] == JOY1+1 || setupcontrols[GC_CUSTOM1][1] == JOY1+1) + && (setupcontrols[GC_CUSTOM2][0] == JOY1+3 || setupcontrols[GC_CUSTOM2][1] == JOY1+3) + && (setupcontrols[GC_CUSTOM3][0] == JOY1+8 || setupcontrols[GC_CUSTOM3][1] == JOY1+8)) + { + // If the player has v2.2.13's default gamepad Custom 1/2/3 buttons, + // shuffle Custom 1/2/3 around to make room for Shield Ability on B + UINT8 shield_slot = (setupcontrols[GC_SHIELD ][0] == KEY_NULL ) ? 0 : 1; + UINT8 custom1_slot = (setupcontrols[GC_CUSTOM1][0] == JOY1+1) ? 0 : 1; + UINT8 custom2_slot = (setupcontrols[GC_CUSTOM2][0] == JOY1+3) ? 0 : 1; + UINT8 custom3_slot = (setupcontrols[GC_CUSTOM3][0] == JOY1+8) ? 0 : 1; + + setupcontrols[GC_SHIELD ][shield_slot ] = JOY1+1; // Assign Shield Ability to B + setupcontrols[GC_CUSTOM1][custom1_slot] = JOY1+3; // Move Custom 1 from B to Y + setupcontrols[GC_CUSTOM2][custom2_slot] = JOY1+8; // Move Custom 2 from Y to LS + setupcontrols[GC_CUSTOM3][custom3_slot] = KEY_NULL; // Unassign Custom 3 from LS... + // (The alternative would be to check and update the ENTIRE gamepad layout. + // That'd be nice, but it would mess with people that are used to the old defaults.) + } + else if ((setupcontrols[GC_WEAPONNEXT][0] == JOY1+1 || setupcontrols[GC_WEAPONNEXT][1] == JOY1+1) + && (setupcontrols[GC_WEAPONPREV][0] == JOY1+2 || setupcontrols[GC_WEAPONPREV][1] == JOY1+2)) + { + // Or if the user has a default config from v2.2.0 to v2.2.9, + // the B button will be Next Weapon, and X will be Previous Weapon. + // It's "safe" to discard one of them, you just have to press X multiple times to select in the other direction + UINT8 shield_slot = (setupcontrols[GC_SHIELD ][0] == KEY_NULL ) ? 0 : 1; + UINT8 nweapon_slot = (setupcontrols[GC_WEAPONNEXT][0] == JOY1+1) ? 0 : 1; + UINT8 pweapon_slot = (setupcontrols[GC_WEAPONPREV][0] == JOY1+2) ? 0 : 1; + + setupcontrols[GC_SHIELD ][shield_slot ] = JOY1+1; // Assign Shield Ability to B + setupcontrols[GC_WEAPONNEXT][nweapon_slot] = JOY1+3; // Move Next Weapon from B to X + setupcontrols[GC_WEAPONPREV][pweapon_slot] = KEY_NULL; // Unassign Previous Weapon from X + } + + if (setupcontrols == gamecontrolbis) // If we've already updated both players, break out + break; } - S_StartSound(NULL, sfx_menu1); - noFurtherInput = true; - shieldbuttonprompt = 0; - if (ch == 'y' || ch == KEY_ENTER) + // Now, show a message about the default Shield Ability bindings + if ((gamecontrol[GC_SHIELD][0] == KEY_LALT && gamecontrol[GC_SHIELD][1] == KEY_JOY1+1) + || (gamecontrol[GC_SHIELD][0] == KEY_JOY1+1 && gamecontrol[GC_SHIELD][1] == KEY_LALT)) { - stopstopmessage = true; // Stop MessageDef from calling M_SetupNextMenu automatically - OP_ChangeControlsDef.lastOn = 8; // Highlight Shield Ability in the controls menu - M_Setup1PControlsMenu(ch); // Set up P1's controls menu and call M_SetupNextMenu + // Left Alt and the B button are both assigned + M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x82""Left Alt\x80"" key on keyboard,\nand the \x85""B button\x80"" on gamepads." + "\n\nYou can always reassign it\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n"), + NULL, MM_NOTHING); + MessageDef.x = 43; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 27; + } + else if (gamecontrol[GC_SHIELD][0] == KEY_LALT || gamecontrol[GC_SHIELD][1] == KEY_LALT) + { + // Left Alt is assigned, but the B button isn't. + M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x82""Left Alt\x80"" key on keyboard.\nThe \x85""B button\x80"" on gamepads was taken." + "\n\nYou can always reassign it\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n"), + NULL, MM_NOTHING); + MessageDef.x = 24; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 32; + } + else if (gamecontrol[GC_SHIELD][0] == KEY_JOY1+1 || gamecontrol[GC_SHIELD][1] == KEY_JOY1+1) + { + // The B button is assigned, but Left Alt isn't + M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x85""B button\x80"" on gamepads.\nThe \x82""Left Alt\x80"" key on keyboard was taken." + "\n\nYou can always reassign it\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n"), + NULL, MM_NOTHING); + MessageDef.x = 8; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 36; + } + else if (gamecontrol[GC_SHIELD][0] == KEY_NULL && gamecontrol[GC_SHIELD][1] == KEY_NULL) + { + // Neither Left Alt nor the B button are assigned + M_StartMessage(M_GetText("Shield Ability is unassigned!\nThe \x82""Left Alt\x80"" key on keyboard and\nthe \x85""B button\x80"" on gamepads were taken." + "\n\nYou should assign Shield Ability\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n"), + NULL, MM_NOTHING); + MessageDef.x = 19; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 33; + } + else + { + // Neither Left Alt nor the B button are assigned... but something else is??? + // (This can technically happen if you edit your config or use setcontrol in the console before opening the menu) + char keystr[16+16+2+7+1]; // Two 16-char keys + two colour codes + "' and '" + null + + if (gamecontrol[GC_SHIELD][0] != KEY_NULL && gamecontrol[GC_SHIELD][1] != KEY_NULL) + STRBUFCPY(keystr, va("%s\x80""' and '\x82""%s", + G_KeyNumToName(gamecontrol[GC_SHIELD][0]), + G_KeyNumToName(gamecontrol[GC_SHIELD][1]))); + else if (gamecontrol[GC_SHIELD][0] != KEY_NULL) + STRBUFCPY(keystr, G_KeyNumToName(gamecontrol[GC_SHIELD][0])); + else //if (gamecontrol[GC_SHIELD][1] != KEY_NULL) + STRBUFCPY(keystr, G_KeyNumToName(gamecontrol[GC_SHIELD][1])); + + M_StartMessage(va("Shield Ability is assigned to\n'\x82""%s\x80""'." + "\n\nYou can always reassign it\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n", + keystr), NULL, MM_NOTHING); + MessageDef.x = 23; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 32; } } +static void M_HandleShieldPromptMenu(INT32 choice) // TODO: 2.3: Remove +{ + switch (choice) + { + case KEY_ESCAPE: + if (I_GetTime() <= shieldprompt_timer) // Don't mash past the pop-up by accident! + break; + + S_StartSound(NULL, sfx_menu1); + noFurtherInput = true; + shieldprompt_timer = 0; + M_ShieldPromptUseDefaults(); + break; + + case KEY_ENTER: + if (I_GetTime() <= shieldprompt_timer) // Don't mash past the pop-up by accident! + break; + + S_StartSound(NULL, sfx_menu1); + noFurtherInput = true; + shieldprompt_timer = 0; + + if (shieldprompt_currentchoice == 0) + { + OP_ChangeControlsDef.lastOn = 8; // Highlight Shield Ability in the controls menu + M_Setup1PControlsMenu(0); // Set up P1's controls menu and call M_SetupNextMenu + } + else if (shieldprompt_currentchoice == 1) // Copy the Spin buttons to the Shield buttons + { + CV_SetValue(&cv_controlperkey, 2); // Make sure that Controls per Key is "Several" + + gamecontrol [GC_SHIELD][0] = gamecontrol [GC_SPIN][0]; + gamecontrol [GC_SHIELD][1] = gamecontrol [GC_SPIN][1]; + gamecontrolbis[GC_SHIELD][0] = gamecontrolbis[GC_SPIN][0]; + gamecontrolbis[GC_SHIELD][1] = gamecontrolbis[GC_SPIN][1]; + CV_SetValue(&cv_shieldaxis, cv_spinaxis.value); + CV_SetValue(&cv_shieldaxis2, cv_spinaxis2.value); + + M_StartMessage(M_GetText("Spin and Shield Ability are now\nthe same button." + "\n\nYou can always reassign them\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n"), + NULL, MM_NOTHING); + MessageDef.x = 36; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 29; + } + else + M_ShieldPromptUseDefaults(); + break; + + case KEY_UPARROW: + S_StartSound(NULL, sfx_menu1); + shieldprompt_currentchoice = (shieldprompt_currentchoice+2)%3; + break; + + case KEY_DOWNARROW: + S_StartSound(NULL, sfx_menu1); + shieldprompt_currentchoice = (shieldprompt_currentchoice+1)%3; + break; + } + + MessageDef.prevMenu = &MainDef; +} + +static void M_DrawShieldPromptMenu(void) // TODO: 2.3: Remove +{ + INT16 cursorx = (BASEVIDWIDTH/2) - 24; + + V_DrawFill(10-3, 68-3, 300+6, 40+6, 159); + // V_DrawCenteredString doesn't centre newlines, so we have to draw each line separately + V_DrawCenteredString(BASEVIDWIDTH/2, 68, V_ALLOWLOWERCASE, "Welcome back! Since you last played,"); + V_DrawCenteredString(BASEVIDWIDTH/2, 76, V_ALLOWLOWERCASE, "Spin has been split into separate"); + V_DrawCenteredString(BASEVIDWIDTH/2, 84, V_ALLOWLOWERCASE, "\"Spin\" and \"Shield Ability\" controls."); + + V_DrawCenteredString(BASEVIDWIDTH/2, 98, V_ALLOWLOWERCASE, "Do you want to assign Shield Ability now?"); + + + V_DrawCenteredString(BASEVIDWIDTH/2, 164, + (shieldprompt_currentchoice == 0) ? V_YELLOWMAP : 0, "Open Control Setup"); + V_DrawCenteredString(BASEVIDWIDTH/2, 172, + (shieldprompt_currentchoice == 1) ? V_YELLOWMAP : 0, "Keep the old behaviour"); + V_DrawCenteredString(BASEVIDWIDTH/2, 180, + (shieldprompt_currentchoice == 2) ? V_YELLOWMAP : 0, "Use default Shield Ability buttons"); + + switch (shieldprompt_currentchoice) + { + case 0: cursorx -= V_StringWidth("Open Control Setup", 0)/2; break; + case 1: cursorx -= V_StringWidth("Keep the old behaviour", 0)/2; break; + default: cursorx -= V_StringWidth("Use default Shield Ability buttons", 0)/2; break; + } + V_DrawScaledPatch(cursorx, 164 + (shieldprompt_currentchoice*8), 0, W_CachePatchName("M_CURSOR", PU_PATCH)); +} + +static menuitem_t OP_ShieldPromptMenu[] = {{IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleShieldPromptMenu, 0}}; // TODO: 2.3: Remove + +menu_t OP_ShieldPromptDef = { // TODO: 2.3: Remove + MN_SPECIAL, + NULL, + 1, + &MainDef, + OP_ShieldPromptMenu, + M_DrawShieldPromptMenu, + 0, 0, 0, NULL +}; + // // M_StartControlPanel // @@ -3689,15 +3892,13 @@ void M_StartControlPanel(void) itemOn = singleplr; M_UpdateItemOn(); - if (shieldbuttonprompt) // For old configs, show a pop-up about the new Shield button // TODO: 2.3: Remove + if (shieldprompt_timer) // For old configs, show a pop-up about the new Shield button // TODO: 2.3: Remove { - S_StartSound(NULL, sfx_menu1); - shieldbuttonprompt = I_GetTime() + TICRATE; // Don't mash past the pop-up by accident! + S_StartSound(NULL, sfx_strpst); + noFurtherInput = true; + shieldprompt_timer = I_GetTime() + TICRATE; // Don't mash past the pop-up by accident! - M_StartMessage(M_GetText("Welcome back! Since you last played,\nSpin has been split into separate\n\"Spin\" and \"Shield Ability\" controls." - "\n\nDo you want to \x82""assign Shield Ability now\x80""?" - "\n\n\nPress \x82""ENTER\x80"" or the \x83""A button\x80"" to accept\nPress \x82""ESC\x80"" or the \x85""B button\x80"" to skip\n"), - M_ShieldButtonResponse, MM_YESNO); + M_SetupNextMenu(&OP_ShieldPromptDef); } } else if (modeattacking) diff --git a/src/m_menu.h b/src/m_menu.h index ea130a607..55c0b4060 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -176,7 +176,7 @@ typedef struct extern menupres_t menupres[NUMMENUTYPES]; extern UINT32 prevMenuId; extern UINT32 activeMenuId; -extern tic_t shieldbuttonprompt; // Show a prompt about the new Shield button for old configs // TODO: 2.3: Remove +extern tic_t shieldprompt_timer; // Show a prompt about the new Shield button for old configs // TODO: 2.3: Remove void M_InitMenuPresTables(void); UINT8 M_GetYoungestChildMenu(void); diff --git a/src/m_misc.c b/src/m_misc.c index ee810a031..724717aa6 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -563,7 +563,7 @@ void M_FirstLoadConfig(void) // For configs loaded at startup only, check for pre-Shield-button configs // TODO: 2.3: Remove if (GETMAJOREXECVERSION(cv_execversion.value) < 55 // Pre-v2.2.14 configs && cv_execversion.value != 25) // Make sure that the config exists, too - shieldbuttonprompt = 1; + shieldprompt_timer = 1; // don't filter anymore vars and don't let this convsvar be changed COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, EXECVERSION));