Use a three-option menu instead of a yes/no prompt

This commit is contained in:
Zwip-Zwap Zapony 2024-05-28 14:25:30 +02:00
parent c53da609b1
commit b1f15a35ba
3 changed files with 227 additions and 26 deletions

View file

@ -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,26 +3636,229 @@ 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;
}
// 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))
{
// 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;
shieldbuttonprompt = 0;
shieldprompt_timer = 0;
M_ShieldPromptUseDefaults();
break;
if (ch == 'y' || ch == KEY_ENTER)
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)
{
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
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)

View file

@ -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);

View file

@ -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));