From ebc2156b7e4f7e7808ca2626ac972d8817fd04be Mon Sep 17 00:00:00 2001 From: SinnamonLat Date: Sat, 19 Feb 2022 13:26:02 +0100 Subject: [PATCH] Profiles: control setup (wip but does what it needs to for now) --- src/k_menu.h | 26 +++++++++ src/k_menudef.c | 94 ++++++++++++++++++++++++++++++- src/k_menudraw.c | 120 +++++++++++++++++++++++++++++++++++++++ src/k_menufunc.c | 142 +++++++++++++++++++++++++++++++++++++++++++++-- src/k_profiles.c | 2 +- 5 files changed, 377 insertions(+), 7 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 6bf48a642..6e7b1589e 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -20,6 +20,7 @@ #include "doomstat.h" // MAXSPLITSCREENPLAYERS #include "g_demo.h" //menudemo_t #include "k_profiles.h" // profile data & functions +#include "g_input.h" // gc_ // flags for items in the menu // menu handle (what we do when key is pressed @@ -226,6 +227,9 @@ extern menu_t OPTIONS_ProfilesDef; extern menuitem_t OPTIONS_EditProfile[]; extern menu_t OPTIONS_EditProfileDef; +extern menuitem_t OPTIONS_ProfileControls[]; +extern menu_t OPTIONS_ProfileControlsDef; + extern menuitem_t OPTIONS_Video[]; extern menu_t OPTIONS_VideoDef; @@ -626,6 +630,17 @@ 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 + 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) + + // controller coords... + // Works the same as (t)opt + INT16 contx; + INT16 conty; + INT16 tcontx; + INT16 tconty; + // for video mode testing: INT32 vidm_testingmode; INT32 vidm_previousmode; @@ -643,6 +658,8 @@ extern struct optionsmenu_s { tic_t fade; } optionsmenu; +extern INT16 controlleroffsets[][2]; + extern consvar_t cv_dummyprofilename; extern consvar_t cv_dummyprofileplayername; @@ -659,9 +676,17 @@ void M_EraseData(INT32 choice); // For data erasing void M_ProfileSelectInit(INT32 choice); void M_HandleProfileSelect(INT32 ch); +// profile edition void M_HandleProfileEdit(void); +void M_ProfileDeviceSelect(INT32 choice); boolean M_ProfileEditInputs(INT32 ch); +void M_HandleProfileControls(void); +boolean M_ProfileControlsInputs(INT32 ch); +void M_ProfileSetControl(INT32 ch); + +void M_MapProfileControl(event_t *ev); + // video modes menu (resolution) void M_VideoModeMenu(INT32 choice); void M_HandleVideoModes(INT32 ch); @@ -802,6 +827,7 @@ void M_DrawOptions(void); void M_DrawGenericOptions(void); void M_DrawProfileSelect(void); void M_DrawEditProfile(void); +void M_DrawProfileControls(void); void M_DrawVideoModes(void); void M_DrawItemToggles(void); diff --git a/src/k_menudef.c b/src/k_menudef.c index b82410734..aa68b816d 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -441,8 +441,8 @@ menuitem_t OPTIONS_EditProfile[] = { {IT_STRING | IT_CALL, "Character", "Default character and color for this Profile.", NULL, M_CharacterSelect, 0, 0}, - {IT_STRING | IT_SUBMENU, "Controls", "Select the button mappings for this Profile.", - NULL, NULL, 0, 0}, + {IT_STRING | IT_CALL, "Controls", "Select the button mappings for this Profile.", + NULL, M_ProfileDeviceSelect, 0, 0}, }; menu_t OPTIONS_EditProfileDef = { @@ -460,6 +460,96 @@ menu_t OPTIONS_EditProfileDef = { M_ProfileEditInputs, }; +menuitem_t OPTIONS_ProfileControls[] = { + + {IT_HEADER, "MAIN CONTROLS", "That's the stuff on the controller!!", + NULL, NULL, 0, 0}, + + {IT_CONTROL, "A", "Accelerate / Confirm", + "PR_BTA", M_ProfileSetControl, gc_a, 0}, + + {IT_CONTROL, "B", "Look backwards / Back", + "PR_BTB", M_ProfileSetControl, gc_b, 0}, + + {IT_CONTROL, "C", "Spindash", + "PR_BTC", M_ProfileSetControl, gc_c, 0}, + + {IT_CONTROL, "X", "Brake", + "PR_BTX", M_ProfileSetControl, gc_x, 0}, + + // @TODO What does this do??? + {IT_CONTROL, "Y", "We just don't know", + "PR_BTY", M_ProfileSetControl, gc_y, 0}, + + {IT_CONTROL, "Z", "We just don't know", + "PR_BTZ", M_ProfileSetControl, gc_z, 0}, + + {IT_CONTROL, "L", "Use item", + "PR_BTL", M_ProfileSetControl, gc_l, 0}, + + {IT_CONTROL, "R", "Drift", + "PR_BTR", M_ProfileSetControl, gc_r, 0}, + + {IT_CONTROL, "Turn Left", "Turn left", + "PR_PADL", M_ProfileSetControl, gc_left, 0}, + + {IT_CONTROL, "Turn Right", "Turn right", + "PR_PADR", M_ProfileSetControl, gc_right, 0}, + + {IT_CONTROL, "Aim Forward", "Aim forwards", + "PR_PADU", M_ProfileSetControl, gc_up, 0}, + + {IT_CONTROL, "Aim Backwards", "Aim backwards", + "PR_PADD", M_ProfileSetControl, gc_down, 0}, + + {IT_CONTROL, "Start", "Open pause menu", + "PR_BTS", M_ProfileSetControl, gc_start, 0}, + + {IT_HEADER, "OPTIONAL CONTROLS", "Take a screenshot, chat...", + NULL, NULL, 0, 0}, + + {IT_CONTROL, "SCREENSHOT", "Also usable with F8 on Keyboard.", + NULL, M_ProfileSetControl, gc_screenshot, 0}, + + {IT_CONTROL, "GIF CAPTURE", "Also usable with F9 on Keyboard.", + NULL, M_ProfileSetControl, gc_recordgif, 0}, + + {IT_CONTROL, "OPEN CHAT", "Opens chatbox in online games.", + NULL, M_ProfileSetControl, gc_talk, 0}, + + {IT_CONTROL, "OPEN TEAM CHAT", "Do we even have team gamemodes?", + NULL, M_ProfileSetControl, gc_teamtalk, 0}, + + {IT_CONTROL, "OPEN CONSOLE", "Also usable with ` on Keyboard.", + NULL, M_ProfileSetControl, gc_console, 0}, + + {IT_CONTROL, "LUA/A", "May be used by add-ons.", + NULL, M_ProfileSetControl, gc_luaa, 0}, + + {IT_CONTROL, "LUA/B", "May be used by add-ons.", + NULL, M_ProfileSetControl, gc_luab, 0}, + + {IT_CONTROL, "LUA/C", "May be used by add-ons.", + NULL, M_ProfileSetControl, gc_luac, 0}, +}; + + + +menu_t OPTIONS_ProfileControlsDef = { + sizeof (OPTIONS_ProfileControls) / sizeof (menuitem_t), + &OPTIONS_EditProfileDef, + 0, + OPTIONS_ProfileControls, + 32, 80, + SKINCOLOR_ULTRAMARINE, 0, + 3, 10, + M_DrawProfileControls, + M_HandleProfileControls, + NULL, + NULL, + M_ProfileControlsInputs, +}; + // video options menu... // options menu menuitem_t OPTIONS_Video[] = diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 9e89c8cd6..a3a989040 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2268,6 +2268,126 @@ void M_DrawEditProfile(void) } } +// Controller offsets to center on each button. +INT16 controlleroffsets[][2] = { + {0, 0}, // gc_none + {70, 112}, // gc_up + {70, 112}, // gc_down + {70, 112}, // gc_left + {70, 112}, // gc_right + {208, 200}, // gc_a + {237, 181}, // gc_b + {267, 166}, // gc_c + {191, 164}, // gc_x + {215, 149}, // gc_y + {242, 137}, // gc_z + {55, 102}, // gc_l + {253, 102}, // gc_r + {149, 187}, // gc_start +}; + +// the control stuff. +// Dear god. +void M_DrawProfileControls(void) +{ + const UINT8 spacing = 34; + INT32 y = 16 - (optionsmenu.controlscroll*spacing); + INT32 x = 8; + INT32 i, j; + + M_DrawOptionsCogs(); + + // @TODO: have it move around and shit. + V_DrawScaledPatch(BASEVIDWIDTH*2/3 - optionsmenu.contx, BASEVIDHEIGHT/2 -optionsmenu.conty, 0, W_CachePatchName("PR_CONT", PU_CACHE)); + + // 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); + if (currentMenu->menuitems[itemOn].tooltip != NULL) + { + V_DrawCenteredThinString(BASEVIDWIDTH*2/3, 12, V_ALLOWLOWERCASE|V_6WIDTHSPACE, currentMenu->menuitems[itemOn].tooltip); + } + + V_DrawFill(0, 0, 138, 200, 31); // Black border + + // Draw the menu options... + for (i = 0; i < currentMenu->numitems; i++) + { + char buf[256]; + INT32 keys[2]; + + // cursor + if (i == itemOn) + { + for (j=0; j < 24; j++) + V_DrawFill(0, (y)+j, 128+j, 1, 73); + } + + switch (currentMenu->menuitems[i].status & IT_DISPLAY) + { + case IT_HEADERTEXT: + V_DrawFill(0, y+17, 124, 1, 0); // underline + V_DrawString(x, y+8, 0, currentMenu->menuitems[i].text); + y += spacing; + break; + + case IT_STRING2: + + if (currentMenu->menuitems[i].patch) + V_DrawScaledPatch(x+12, y+12, 0, W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE)); + else + V_DrawString(x, y+1, (i == itemOn ? highlightflags : 0), currentMenu->menuitems[i].text); + + if (currentMenu->menuitems[i].status & IT_CONTROL) + { + // Draw what the controls are mapped to + keys[0] = optionsmenu.profile->controls[currentMenu->menuitems[i].mvar1][0]; + keys[1] = optionsmenu.profile->controls[currentMenu->menuitems[i].mvar1][1]; + + buf[0] = '\0'; + + if (keys[0] == KEY_NULL && keys[1] == KEY_NULL) + strcpy(buf, "\x85NOT BOUND"); + else + { + if (keys[0] != KEY_NULL) + strcat (buf, G_KeynumToString (keys[0])); + + if (keys[0] != KEY_NULL && keys[1] != KEY_NULL) + strcat(buf," / "); + + if (keys[1] != KEY_NULL) + strcat (buf, G_KeynumToString (keys[1])); + } + + V_DrawThinString(x+32, y+12, V_6WIDTHSPACE, buf); + + // controller dest coords: + if (itemOn == i && currentMenu->menuitems[i].mvar1 && currentMenu->menuitems[i].mvar1 <= gc_start) + { + optionsmenu.tcontx = controlleroffsets[currentMenu->menuitems[i].mvar1][0]; + optionsmenu.tconty = controlleroffsets[currentMenu->menuitems[i].mvar1][1]; + } + } + + y += spacing; + break; + } + } + + // Overlay for control binding + if (optionsmenu.bindcontrol) + { + V_DrawFadeScreen(31, 8); + + M_DrawTextBox((BASEVIDWIDTH/2) - (120), (BASEVIDHEIGHT/2) - (16), 30, 4); + + V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), 0, va("Press key #%d for control", optionsmenu.bindcontrol)); + V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4) +10, 0, va("\"%s\"", currentMenu->menuitems[itemOn].text)); + V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4) +20, highlightflags, va("(WAIT %d SECONDS TO SKIP)", optionsmenu.bindtimer/TICRATE)); + } +} + // Draw the video modes list, a-la-Quake void M_DrawVideoModes(void) { diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 36dd9fa89..22b16206c 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -831,6 +831,14 @@ boolean M_Responder(event_t *ev) // update keys current state G_MapEventsToControls(ev); + // Profiles: Control mapping. + // We take the WHOLE EVENT for convenience. + if (optionsmenu.bindcontrol) + { + M_MapProfileControl(ev); + return true; // eat events. + } + // Handle menu handling in-game. if (menuactive == false) { @@ -1399,13 +1407,14 @@ static void M_HandleMenuInput(void) } else { -#if 0 // this shit is crazy +//#if 0 // this shit is crazy if (routine) { - void (*otherroutine)(event_t *sev) = currentMenu->menuitems[itemOn].itemaction; - otherroutine(ev); //Alam: what a hack + //void (*otherroutine)(event_t *sev) = currentMenu->menuitems[itemOn].itemaction; + //otherroutine(menuKey); //Alam: what a hack + routine(menuKey); } -#endif +//#endif return; } @@ -3744,6 +3753,131 @@ void M_HandleVideoModes(INT32 ch) } } +static void M_ProfileDeviceSelectResponse(INT32 key) +{ + UINT8 i; + (void) key; + + for (i=0; i < MAXDEVICES; i++) + { + if (deviceResponding[i]) + { + CV_SetValue(&cv_usejoystick[0], i); // Force-set this joystick as the current joystick we're using for P1 (which is the only one controlling menus) + CONS_Printf("Using device %d for mappings\n", i); + M_SetupNextMenu(&OPTIONS_ProfileControlsDef, false); // with that set, send us to the control def + return; + } + } +} + +// Prompt a device selection window (just tap any button on the device you want) +void M_ProfileDeviceSelect(INT32 choice) +{ + (void)choice; + + // While we're here, setup the incoming controls menu to reset the scroll & bind status: + optionsmenu.controlscroll = 0; + optionsmenu.bindcontrol = 0; + optionsmenu.bindtimer = 0; + + optionsmenu.contx = optionsmenu.tcontx = controlleroffsets[gc_a][0]; + optionsmenu.conty = optionsmenu.tconty = controlleroffsets[gc_a][1]; + + M_StartMessage(M_GetText("Press any key on the device\nyou would like to use"), M_ProfileDeviceSelectResponse, MM_EVENTHANDLER); +} + +void M_HandleProfileControls(void) +{ + UINT8 maxscroll = currentMenu->numitems - 5; + M_OptionsTick(); + + optionsmenu.contx += (optionsmenu.tcontx - optionsmenu.contx)/2; + optionsmenu.conty += (optionsmenu.tconty - optionsmenu.conty)/2; + + if (abs(optionsmenu.contx - optionsmenu.tcontx) < 2 && abs(optionsmenu.conty - optionsmenu.tconty) < 2) + { + optionsmenu.contx = optionsmenu.tcontx; + optionsmenu.conty = optionsmenu.tconty; // Avoid awkward 1 px errors. + } + + optionsmenu.controlscroll = itemOn - 3; // very barebones scrolling, but it works just fine for our purpose. + if (optionsmenu.controlscroll > maxscroll) + optionsmenu.controlscroll = maxscroll; + + if (optionsmenu.controlscroll < 0) + optionsmenu.controlscroll = 0; + + // bindings, cancel if timer is depleted. + if (optionsmenu.bindcontrol) + { + optionsmenu.bindtimer--; + if (!optionsmenu.bindtimer) + { + optionsmenu.bindcontrol++; + if (optionsmenu.bindcontrol > 2) + optionsmenu.bindcontrol = 0; // we've gone past the max, just stop. + else + optionsmenu.bindtimer = TICRATE*5; // skip control + } + + } +} + +boolean M_ProfileControlsInputs(INT32 ch) +{ + (void)ch; + + // By default, accept all inputs. + if (optionsmenu.bindcontrol) + return true; // Eat all inputs there. We'll use a stupid hack in M_Responder instead. + + return false; +} + +void M_ProfileSetControl(INT32 ch) +{ + (void) ch; + + optionsmenu.bindcontrol = 1; + optionsmenu.bindtimer = TICRATE*5; +} + +// Map the event to the profile. +void M_MapProfileControl(event_t *ev) +{ + INT32 c = ev->data1; + UINT8 n = optionsmenu.bindcontrol-1; // # of input to bind + INT32 controln = currentMenu->menuitems[itemOn].mvar1; // gc_ + UINT8 where = n; // By default, we'll save the bind where we're supposed to map. + + // Only consider keydown events to make sure we ignore ev_mouse and ev_joystick as well + if (ev->type != ev_keydown) + return; + + // Check if this control is already assigned, it'd look silly to assign the same key twice on the same thing. + if (n == 0 && optionsmenu.profile->controls[controln][1] == c) + { + optionsmenu.profile->controls[controln][1] = KEY_NULL; // unbind + where = 0; // save control in slot 0 + } + else if (n == 1 && optionsmenu.profile->controls[controln][0] == c) + { + // Do nothing and exit this menu. + optionsmenu.bindcontrol = 0; + return; + } + + optionsmenu.profile->controls[controln][where] = c; + + optionsmenu.bindcontrol++; + optionsmenu.bindtimer = TICRATE*5; + if (optionsmenu.bindcontrol > 2) + { + optionsmenu.bindtimer = 0; + optionsmenu.bindcontrol = 0; + } +} + void M_HandleItemToggles(INT32 choice) { const INT32 width = 9, height = 3; diff --git a/src/k_profiles.c b/src/k_profiles.c index d87bb79da..a07c7b803 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -23,7 +23,7 @@ profile_t PR_MakeProfile(const char *prname, const char *pname, const char *snam new.version = PROFILEVER; strcpy(new.profilename, prname); - + strcpy(new.skinname, sname); strcpy(new.playername, pname); new.color = col;