From d0db7e43819f7d2062bb10ddf448eb0038b132cc Mon Sep 17 00:00:00 2001 From: SinnamonLat Date: Fri, 20 May 2022 01:15:29 +0200 Subject: [PATCH] rethink input mapping menu (again (again)) --- src/k_menu.h | 13 ++++++ src/k_menudraw.c | 77 +++++++++++++----------------------- src/k_menufunc.c | 100 ++++++++++++++++++++++++++++++++++++++++------- src/k_profiles.c | 14 +++++++ src/k_profiles.h | 5 +++ 5 files changed, 146 insertions(+), 63 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 48864c869..1362b56dd 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -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) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 9faa1be66..ebfacbdf5 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -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++; diff --git a/src/k_menufunc.c b/src/k_menufunc.c index c3fa1c22c..1305b5bcc 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -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 diff --git a/src/k_profiles.c b/src/k_profiles.c index e215cbc7f..af7801c2e 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -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; } \ No newline at end of file diff --git a/src/k_profiles.h b/src/k_profiles.h index 7996a21bd..d50d73bb2 100644 --- a/src/k_profiles.h +++ b/src/k_profiles.h @@ -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