Profiles: control setup (wip but does what it needs to for now)

This commit is contained in:
SinnamonLat 2022-02-19 13:26:02 +01:00
parent 5601fa4c22
commit ebc2156b7e
5 changed files with 377 additions and 7 deletions

View file

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

View file

@ -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[] =

View file

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

View file

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

View file

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