rethink input mapping menu (again (again))

This commit is contained in:
SinnamonLat 2022-05-20 01:15:29 +02:00
parent 0ee02ce1e1
commit d0db7e4381
5 changed files with 146 additions and 63 deletions

View file

@ -228,6 +228,15 @@ extern menu_t OPTIONS_ProfilesDef;
extern menuitem_t MAIN_Profiles[];
extern menu_t MAIN_ProfilesDef;
typedef enum
{
popt_profilename = 0,
popt_profilepname,
popt_char,
popt_controls,
popt_confirm,
} popt_e;
extern menuitem_t OPTIONS_EditProfile[];
extern menu_t OPTIONS_EditProfileDef;
@ -679,6 +688,10 @@ extern struct optionsmenu_s {
boolean resetprofile; // After going back from the edit menu, this tells the profile select menu to kill the profile data after the transition.
profile_t *profile; // Pointer to the profile we're editing
INT32 tempcontrols[num_gamecontrols][MAXINPUTMAPPING];
// Temporary buffer where we're gonna store game controls.
// This is only applied to the profile when you exit out of the controls menu.
INT16 controlscroll; // scrolling for the control menu....
UINT8 bindcontrol; // 0: not binding, 1: binding control #1, 2: binding control #2
INT16 bindtimer; // Timer until binding is cancelled (5s)

View file

@ -2634,44 +2634,37 @@ void M_DrawEditProfile(void)
// Draw the menu options...
for (i = 0; i < currentMenu->numitems; i++)
{
switch (currentMenu->menuitems[i].status & IT_DISPLAY)
UINT8 *colormap = NULL;
INT32 tflag = (currentMenu->menuitems[i].status & IT_TRANSTEXT) ? V_TRANSLUCENT : 0;
if (i == itemOn)
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
// Background
V_DrawFill(0, y, 400 - (menutransition.tics*64), 24, itemOn == i ? 169 : 30); // 169 is the plague colourization
// Text
V_DrawGamemodeString(x + (menutransition.tics*32), y - 6, V_ALLOWLOWERCASE|tflag, colormap, currentMenu->menuitems[i].text);
// Cvar specific handling
/*switch (currentMenu->menuitems[i].status & IT_TYPE)
{
case IT_STRING: {
UINT8 *colormap = NULL;
if (i == itemOn)
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
// Background
V_DrawFill(0, y, 400 - (menutransition.tics*64), 24, itemOn == i ? 169 : 30); // 169 is the plague colourization
// Text
V_DrawGamemodeString(x + (menutransition.tics*32), y - 6, V_ALLOWLOWERCASE, colormap, currentMenu->menuitems[i].text);
// Cvar specific handling
/*switch (currentMenu->menuitems[i].status & IT_TYPE)
case IT_CVAR:
{
consvar_t *cv = currentMenu->menuitems[i].itemaction.cvar;
switch (currentMenu->menuitems[i].status & IT_CVARTYPE)
{
case IT_CVAR:
{
consvar_t *cv = currentMenu->menuitems[i].itemaction.cvar;
switch (currentMenu->menuitems[i].status & IT_CVARTYPE)
{
case IT_CV_STRING:
V_DrawFill(0, y+24, 400 - (menutransition.tics*64), 16, itemOn == i ? 169 : 30); // 169 is the plague colourization
V_DrawString(x + 8, y + 29, V_ALLOWLOWERCASE, cv->string);
if (skullAnimCounter < 4 && i == itemOn)
V_DrawCharacter(x + 8 + V_StringWidth(cv->string, 0), y + 29,
'_' | 0x80, false);
y += 16;
break;
}
case IT_CV_STRING:
V_DrawFill(0, y+24, 400 - (menutransition.tics*64), 16, itemOn == i ? 169 : 30); // 169 is the plague colourization
V_DrawString(x + 8, y + 29, V_ALLOWLOWERCASE, cv->string);
if (skullAnimCounter < 4 && i == itemOn)
V_DrawCharacter(x + 8 + V_StringWidth(cv->string, 0), y + 29, '_' | 0x80, false);
y += 16;
}
}*/
}
}*/
y += 34;
break;
}
}
y += 34;
}
// Finally, draw the card ontop
@ -2758,20 +2751,6 @@ void M_DrawProfileControls(void)
return; // Don't draw the rest if we're trying the controller.
}
// If we're past here, draw some text warnings.
if (gamestate == GS_MENU || PR_GetProfileNum(optionsmenu.profile) == cv_lastprofile[pid].value)
{
if (gamestate != GS_MENU) // If we're in a menu we'll always use the current profile to map controls from regardless.
V_DrawCenteredThinString(229, 180, highlightflags|V_ALLOWLOWERCASE|V_6WIDTHSPACE, "This is your last used profile,");
V_DrawCenteredThinString(229, 190, highlightflags|V_ALLOWLOWERCASE|V_6WIDTHSPACE, "Control changes will happen in real time");
}
else
{
V_DrawCenteredThinString(229, 180, highlightflags|V_ALLOWLOWERCASE|V_6WIDTHSPACE, "This isn't your last used profile,");
V_DrawCenteredThinString(229, 180, highlightflags|V_ALLOWLOWERCASE|V_6WIDTHSPACE, "Changes will apply on next profile selection.");
}
// Tooltip
// The text is slightly shifted hence why we don't just use M_DrawMenuTooltips()
V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("MENUHINT", PU_CACHE), NULL);
@ -2841,7 +2820,7 @@ void M_DrawProfileControls(void)
// Get userbound controls...
for (k = 0; k < MAXINPUTMAPPING; k++)
{
keys[k] = optionsmenu.profile->controls[gc][k];
keys[k] = optionsmenu.tempcontrols[gc][k];
if (keys[k] == KEY_NULL)
continue;
set++;

View file

@ -3718,10 +3718,6 @@ void M_InitOptions(INT32 choice)
OPTIONS_MainDef.menuitems[mopt_server].status = IT_STRING | IT_TRANSTEXT;
}
// disable profiles outside of gs_menu altogether.
if (gamestate != GS_MENU)
OPTIONS_MainDef.menuitems[mopt_profiles].status = IT_STRING | IT_TRANSTEXT;
M_ResetOptions();
// So that pause doesn't go to the main menu...
@ -3977,6 +3973,9 @@ static void M_StartEditProfile(INT32 c)
PR_InitNewProfile(); // initialize the new profile.
optionsmenu.profile = PR_GetProfile(optionsmenu.profilen);
// copy this profile's controls into optionsmenu so that we can edit controls without changing them directly.
// we do this so that we don't edit a profile's controls in real-time and end up doing really weird shit.
memcpy(&optionsmenu.tempcontrols, optionsmenu.profile->controls, sizeof(gamecontroldefault));
// This is now used to move the card we've selected.
optionsmenu.optx = 160;
@ -3998,6 +3997,18 @@ static void M_StartEditProfile(INT32 c)
CV_StealthSetValue(&cv_dummyprofilekickstart, 0); // off
}
// Setup greyout and stuff.
OPTIONS_EditProfile[popt_profilename].status = IT_STRING | IT_CVAR | IT_CV_STRING;
OPTIONS_EditProfile[popt_profilepname].status = IT_STRING | IT_CVAR | IT_CV_STRING;
OPTIONS_EditProfile[popt_char].status = IT_STRING | IT_CALL;
if (gamestate != GS_MENU) // If we're modifying things mid game, transtext some of those!
{
OPTIONS_EditProfile[popt_profilename].status |= IT_TRANSTEXT;
OPTIONS_EditProfile[popt_profilepname].status |= IT_TRANSTEXT;
OPTIONS_EditProfile[popt_char].status |= IT_TRANSTEXT;
}
M_SetupNextMenu(&OPTIONS_EditProfileDef, false);
return;
}
@ -4157,6 +4168,11 @@ boolean M_ProfileEditInputs(INT32 ch)
}
return true;
}
else if (M_MenuConfirmPressed(pid))
{
if (currentMenu->menuitems[itemOn].status & IT_TRANSTEXT)
return true; // No.
}
return false;
}
@ -4369,18 +4385,54 @@ void M_HandleProfileControls(void)
}
}
static void M_ProfileTryControllerResponse(INT32 choice)
{
if (choice == MA_YES)
{
optionsmenu.trycontroller = TICRATE*3;
// Apply these controls right now on P1's end.
memcpy(&gamecontrol[0], optionsmenu.tempcontrols, sizeof(gamecontroldefault));
}
}
void M_ProfileTryController(INT32 choice)
{
(void) choice;
// I managed to softlock myself during testing lol.
if (!optionsmenu.profile->controls[gc_x][0])
if (!optionsmenu.tempcontrols[gc_x][0])
{
M_StartMessage(M_GetText("You need to bind a key to [X]\nto use this feature.\n"), NULL, MM_NOTHING);
return;
}
else
{
M_StartMessage(M_GetText("Your inputs will temporarily be\nremapped to match this Profile's settings.\nThe controller graphic will animate\nto show you what buttons are being pressed.\nIs this okay?\n\n(Press A to continue)"),
FUNCPTRCAST(M_ProfileTryControllerResponse), MM_YESNO);
return;
}
}
optionsmenu.trycontroller = TICRATE*3;
static void M_ProfileControlSaveResponse(INT32 choice)
{
if (choice == MA_YES)
{
SINT8 belongsto = PR_ProfileUsedBy(optionsmenu.profile);
// Save the profile
optionsmenu.profile->kickstartaccel = cv_dummyprofilekickstart.value;
memcpy(&optionsmenu.profile->controls, optionsmenu.tempcontrols, sizeof(gamecontroldefault));
// If this profile is in-use by anyone, apply the changes immediately upon exiting.
// Don't apply the profile itself as that would lead to issues mid-game.
if (belongsto > -1 && belongsto < MAXSPLITSCREENPLAYERS)
{
memcpy(&gamecontrol[belongsto], optionsmenu.tempcontrols, sizeof(gamecontroldefault));
CV_StealthSetValue(&cv_kickstartaccel[belongsto], cv_dummyprofilekickstart.value);
}
M_GoBack(0);
}
}
boolean M_ProfileControlsInputs(INT32 ch)
@ -4396,13 +4448,21 @@ boolean M_ProfileControlsInputs(INT32 ch)
else
optionsmenu.trycontroller = TICRATE*3;
if (!optionsmenu.trycontroller)
{
// Reset controls to that of the current profile.
profile_t *cpr = PR_GetProfile(cv_currprofile.value);
memcpy(&gamecontrol[0], cpr->controls, sizeof(gamecontroldefault));
M_StartMessage(M_GetText("Your controls have been\nreverted to their previous state.\n\n(Press any key)"), NULL, MM_NOTHING);
}
return true;
}
if (optionsmenu.bindcontrol)
return true; // Eat all inputs there. We'll use a stupid hack in M_Responder instead.
SetDeviceOnPress(); // Update device constantly so that we don't stay stuck with otpions saying a device is unavailable just because we're mapping multiple devices...
//SetDeviceOnPress(); // Update device constantly so that we don't stay stuck with otpions saying a device is unavailable just because we're mapping multiple devices...
if (M_MenuExtraPressed(pid))
{
@ -4413,7 +4473,7 @@ boolean M_ProfileControlsInputs(INT32 ch)
INT32 i;
for (i = 0; i < MAXINPUTMAPPING; i++)
optionsmenu.profile->controls[currentMenu->menuitems[itemOn].mvar1][i] = KEY_NULL;
optionsmenu.tempcontrols[currentMenu->menuitems[itemOn].mvar1][i] = KEY_NULL;
S_StartSound(NULL, sfx_s3k66);
}
@ -4422,10 +4482,20 @@ boolean M_ProfileControlsInputs(INT32 ch)
}
else if (M_MenuBackPressed(pid))
{
SINT8 usedby = PR_ProfileUsedBy(optionsmenu.profile);
if (usedby > -1)
M_StartMessage(M_GetText(va("As this is Player %d's active Profile,\ncontrol changes will be applied \nimmediately upon exiting this menu.\nIs this okay?\n\n(Press A to confirm)", usedby+1)), FUNCPTRCAST(M_ProfileControlSaveResponse), MM_YESNO);
else
M_StartMessage(M_GetText("Exiting will save the control changes\nfor this Profile.\nIs this okay?\n\n(Press A to confirm)"), FUNCPTRCAST(M_ProfileControlSaveResponse), MM_YESNO);
optionsmenu.profile->kickstartaccel = cv_dummyprofilekickstart.value; // Make sure to save kickstart accel.
// Reapply player 1's real profile.
PR_ApplyProfile(cv_lastprofile[0].value, 0);
return true;
}
return false;
@ -4441,7 +4511,7 @@ void M_ProfileSetControl(INT32 ch)
for (i = 0; i < MAXINPUTMAPPING; i++)
{
if (optionsmenu.profile->controls[controln][i] == KEY_NULL)
if (optionsmenu.tempcontrols[controln][i] == KEY_NULL)
{
optionsmenu.bindcontrol = i+1;
break;
@ -4465,7 +4535,7 @@ void M_MapProfileControl(event_t *ev)
UINT8 where = n; // By default, we'll save the bind where we're supposed to map.
INT32 i;
SetDeviceOnPress(); // Update cv_usejoystick
//SetDeviceOnPress(); // Update cv_usejoystick
// Only consider keydown and joystick events to make sure we ignore ev_mouse and other events
// See also G_MapEventsToControls
@ -4572,7 +4642,7 @@ void M_MapProfileControl(event_t *ev)
// If that's the case, simply do nothing.
for (i = 0; i < MAXINPUTMAPPING; i++)
{
if (optionsmenu.profile->controls[controln][i] == c)
if (optionsmenu.tempcontrols[controln][i] == c)
{
optionsmenu.bindcontrol = 0;
return;
@ -4582,11 +4652,13 @@ void M_MapProfileControl(event_t *ev)
// With the way we do things, there cannot be instances of 'gaps' within the controls, so we don't need to pretend like we need to handle that.
// Unless of course you tamper with the cfg file, but then it's *your* fault, not mine.
optionsmenu.profile->controls[controln][where] = c;
optionsmenu.tempcontrols[controln][where] = c;
optionsmenu.bindcontrol = 0; // not binding anymore
// If possible, reapply the profile...
if (gamestate == GS_MENU) // In menu? Apply this to P1, no questions asked.
// 19/05/22: Actually, no, don't do that, it just fucks everything up in too many cases.
/*if (gamestate == GS_MENU) // In menu? Apply this to P1, no questions asked.
{
// Apply the profile's properties to player 1 but keep the last profile cv to p1's ACTUAL profile to revert once we exit.
UINT8 lastp = cv_lastprofile[0].value;
@ -4605,7 +4677,7 @@ void M_MapProfileControl(event_t *ev)
break;
}
}
}
}*/
}
#undef KEYHOLDFOR

View file

@ -198,4 +198,18 @@ UINT8 PR_GetProfileNum(profile_t *p)
return i;
}
return 0;
}
SINT8 PR_ProfileUsedBy(profile_t *p)
{
UINT8 i;
UINT8 prn = PR_GetProfileNum(p);
for (i=0; i < MAXSPLITSCREENPLAYERS; i++)
{
if (prn == cv_lastprofile[i].value)
return i;
}
return -1;
}

View file

@ -117,4 +117,9 @@ void PR_ApplyProfile(UINT8 profilenum, UINT8 playernum);
// Gets the profile's index # in profilesList
UINT8 PR_GetProfileNum(profile_t *p);
// PR_ProfileUsedBy(profile_t *p)
// Returns the player # this profile is used by (if any)
// If the profile belongs to no player, then this returns -1
SINT8 PR_ProfileUsedBy(profile_t *p);
#endif