mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'profiles-polish' into 'master'
Controls menu POLISH (and some Profiles options polish); menu deadzone tweak Closes #520 See merge request KartKrew/Kart!1940
This commit is contained in:
commit
ecefb96229
7 changed files with 554 additions and 265 deletions
|
|
@ -972,7 +972,7 @@ INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, UINT8 menuPlayers)
|
|||
|
||||
boolean G_PlayerInputDown(UINT8 p, INT32 gc, UINT8 menuPlayers)
|
||||
{
|
||||
return (G_PlayerInputAnalog(p, gc, menuPlayers) != 0);
|
||||
return (abs(G_PlayerInputAnalog(p, gc, menuPlayers)) >= JOYAXISRANGE/2);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -966,6 +966,7 @@ struct modedesc_t
|
|||
#define MAXCOLUMNMODES 12 //max modes displayed in one column
|
||||
#define MAXMODEDESCS (MAXCOLUMNMODES*3)
|
||||
#define M_OPTIONS_OFSTIME 5
|
||||
#define M_OPTIONS_BINDBEN_QUICK 106
|
||||
// Keep track of some options properties
|
||||
extern struct optionsmenu_s {
|
||||
|
||||
|
|
@ -996,8 +997,10 @@ extern struct optionsmenu_s {
|
|||
// 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)
|
||||
UINT16 bindben; // Hold right timer
|
||||
UINT8 bindben_swallow; // (bool) control is about to be cleared; (int) swallow/pose animation timer
|
||||
INT32 bindinputs[MAXINPUTMAPPING]; // Set while binding
|
||||
|
||||
INT16 trycontroller; // Starts at 3*TICRATE, holding B lowers this, when at 0, cancel controller try mode.
|
||||
|
||||
|
|
@ -1068,6 +1071,8 @@ boolean M_ProfileEditInputs(INT32 ch);
|
|||
void M_HandleProfileControls(void);
|
||||
boolean M_ProfileControlsInputs(INT32 ch);
|
||||
void M_ProfileSetControl(INT32 ch);
|
||||
void M_ProfileDefaultControls(INT32 ch);
|
||||
void M_ProfileClearControls(INT32 ch);
|
||||
|
||||
void M_MapProfileControl(event_t *ev);
|
||||
void M_ProfileTryController(INT32 choice);
|
||||
|
|
|
|||
351
src/k_menudraw.c
351
src/k_menudraw.c
|
|
@ -2382,7 +2382,7 @@ void M_DrawCharacterSelect(void)
|
|||
UINT8 priority = 0;
|
||||
INT16 quadx, quady;
|
||||
INT16 skin;
|
||||
INT32 basex = optionsmenu.profile ? (64 + M_EaseWithTransition(Easing_Linear, 5 * 32)) : 0;
|
||||
INT32 basex = optionsmenu.profile ? (64 + M_EaseWithTransition(Easing_InSine, 5 * 48)) : 0;
|
||||
boolean forceskin = M_CharacterSelectForceInAction();
|
||||
|
||||
if (setup_numplayers > 0)
|
||||
|
|
@ -4676,6 +4676,7 @@ void M_DrawEditProfile(void)
|
|||
|
||||
UINT8 *colormap = NULL;
|
||||
INT32 tflag = (currentMenu->menuitems[i].status & IT_TRANSTEXT) ? V_TRANSLUCENT : 0;
|
||||
INT32 cx = x;
|
||||
|
||||
y = currentMenu->menuitems[i].mvar2;
|
||||
|
||||
|
|
@ -4686,13 +4687,14 @@ void M_DrawEditProfile(void)
|
|||
{
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
|
||||
|
||||
V_DrawMenuString(x - 10 - (skullAnimCounter/5), y+1, highlightflags, "\x1C"); // left arrow
|
||||
cx += Easing_OutSine(M_DueFrac(optionsmenu.offset.start, 2), 0, 5);
|
||||
V_DrawMenuString(cx - 10 - (skullAnimCounter/5), y+1, highlightflags, "\x1C"); // left arrow
|
||||
}
|
||||
|
||||
// Text
|
||||
//V_DrawGamemodeString(x, y - 6, tflag, colormap, currentMenu->menuitems[i].text);
|
||||
//V_DrawGamemodeString(cx, y - 6, tflag, colormap, currentMenu->menuitems[i].text);
|
||||
V_DrawStringScaled(
|
||||
x * FRACUNIT,
|
||||
cx * FRACUNIT,
|
||||
(y - 3) * FRACUNIT,
|
||||
FRACUNIT,
|
||||
FRACUNIT,
|
||||
|
|
@ -4722,10 +4724,10 @@ 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
|
||||
{69, 142}, // gc_up
|
||||
{69, 182}, // gc_down
|
||||
{49, 162}, // gc_left
|
||||
{89, 162}, // gc_right
|
||||
{208, 200}, // gc_a
|
||||
{237, 181}, // gc_b
|
||||
{267, 166}, // gc_c
|
||||
|
|
@ -4738,22 +4740,146 @@ INT16 controlleroffsets[][2] = {
|
|||
};
|
||||
|
||||
// Controller patches for button presses.
|
||||
// {patch if not pressed, patch if pressed}
|
||||
// if NULL, draws nothing.
|
||||
// reminder that lumpnames can only be 8 chars at most. (+1 for \0)
|
||||
|
||||
char controllerpresspatch[9][2][9] = {
|
||||
{"", "BTP_A"}, // MBT_A
|
||||
{"", "BTP_B"}, // MBT_B
|
||||
{"", "BTP_C"}, // MBT_C
|
||||
{"", "BTP_X"}, // MBT_X
|
||||
{"", "BTP_Y"}, // MBT_Y
|
||||
{"", "BTP_Z"}, // MBT_Z
|
||||
{"BTNP_L", "BTP_L"},// MBT_L
|
||||
{"BTNP_R", "BTP_R"},// MBT_R
|
||||
{"", "BTP_ST"} // MBT_START
|
||||
static const char *controllerpresspatch[9][2] = {
|
||||
{"PR_BTA", "PR_BTAB"}, // MBT_A
|
||||
{"PR_BTB", "PR_BTBB"}, // MBT_B
|
||||
{"PR_BTC", "PR_BTCB"}, // MBT_C
|
||||
{"PR_BTX", "PR_BTXB"}, // MBT_X
|
||||
{"PR_BTY", "PR_BTYB"}, // MBT_Y
|
||||
{"PR_BTZ", "PR_BTZB"}, // MBT_Z
|
||||
{"PR_BTL", "PR_BTLB"}, // MBT_L
|
||||
{"PR_BTR", "PR_BTRB"}, // MBT_R
|
||||
{"PR_BTS", "PR_BTSB"}, // MBT_START
|
||||
};
|
||||
|
||||
static const char *M_GetDPadPatchName(SINT8 ud, SINT8 lr)
|
||||
{
|
||||
if (ud < 0)
|
||||
{
|
||||
if (lr < 0)
|
||||
return "PR_PADUL";
|
||||
else if (lr > 0)
|
||||
return "PR_PADUR";
|
||||
else
|
||||
return "PR_PADU";
|
||||
}
|
||||
else if (ud > 0)
|
||||
{
|
||||
if (lr < 0)
|
||||
return "PR_PADDL";
|
||||
else if (lr > 0)
|
||||
return "PR_PADDR";
|
||||
else
|
||||
return "PR_PADD";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lr < 0)
|
||||
return "PR_PADL";
|
||||
else if (lr > 0)
|
||||
return "PR_PADR";
|
||||
else
|
||||
return "PR_PADN";
|
||||
}
|
||||
}
|
||||
|
||||
static void M_DrawBindBen(INT32 x, INT32 y, INT32 scroll_remaining)
|
||||
{
|
||||
// optionsmenu.bindben_swallow
|
||||
const int pose_time = 30;
|
||||
const int swallow_time = pose_time + 14;
|
||||
|
||||
// Lid closed
|
||||
int state = 'A';
|
||||
int frame = 0;
|
||||
|
||||
if (optionsmenu.bindben_swallow > 100)
|
||||
{
|
||||
// Quick swallow (C button)
|
||||
state = 'C';
|
||||
|
||||
int t = 106 - optionsmenu.bindben_swallow;
|
||||
if (t < 3)
|
||||
frame = 0;
|
||||
else
|
||||
frame = t - 3;
|
||||
}
|
||||
else if (scroll_remaining <= 0)
|
||||
{
|
||||
// Chewing (text done scrolling)
|
||||
state = 'B';
|
||||
frame = I_GetTime() / 2 % 4;
|
||||
|
||||
// When state changes from 'lid open' to 'chewing',
|
||||
// play chomp sound.
|
||||
if (!optionsmenu.bindben_swallow)
|
||||
S_StartSound(NULL, sfx_monch);
|
||||
|
||||
// Ready to swallow when button is released.
|
||||
optionsmenu.bindben_swallow = swallow_time + 1;
|
||||
}
|
||||
else if (optionsmenu.bindben)
|
||||
{
|
||||
// Lid open (text scrolling)
|
||||
frame = 1;
|
||||
}
|
||||
else if (optionsmenu.bindben_swallow)
|
||||
{
|
||||
if (optionsmenu.bindben_swallow > pose_time)
|
||||
{
|
||||
// Swallow
|
||||
state = 'C';
|
||||
|
||||
int t = swallow_time - optionsmenu.bindben_swallow;
|
||||
if (t < 8)
|
||||
frame = 0;
|
||||
else
|
||||
frame = 1 + (t - 8) / 2 % 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pose
|
||||
state = 'D';
|
||||
|
||||
int t = pose_time - optionsmenu.bindben_swallow;
|
||||
if (t < 10)
|
||||
frame = 0;
|
||||
else
|
||||
frame = 1 + (t - 10) / 4 % 5;
|
||||
}
|
||||
}
|
||||
|
||||
V_DrawMappedPatch(x-30, y, 0, W_CachePatchName(va("PR_BIN%c%c", state, '1' + frame), PU_CACHE), aquamap);
|
||||
}
|
||||
|
||||
static void M_DrawBindMediumString(INT32 y, INT32 flags, const char *string)
|
||||
{
|
||||
fixed_t w = V_StringScaledWidth(FRACUNIT, FRACUNIT, FRACUNIT, flags, MED_FONT, string);
|
||||
fixed_t x = BASEVIDWIDTH/2 * FRACUNIT - w/2;
|
||||
V_DrawStringScaled(
|
||||
x,
|
||||
y * FRACUNIT,
|
||||
FRACUNIT,
|
||||
FRACUNIT,
|
||||
FRACUNIT,
|
||||
flags,
|
||||
NULL,
|
||||
MED_FONT,
|
||||
string
|
||||
);
|
||||
}
|
||||
|
||||
static INT32 M_DrawProfileLegend(INT32 x, INT32 y, const char *legend, const char *mediocre_key)
|
||||
{
|
||||
INT32 w = V_ThinStringWidth(legend, 0);
|
||||
V_DrawThinString(x - w, y, 0, legend);
|
||||
x -= w + 2;
|
||||
if (mediocre_key)
|
||||
M_DrawMediocreKeyboardKey(mediocre_key, &x, y, false, true);
|
||||
return x;
|
||||
}
|
||||
|
||||
// the control stuff.
|
||||
// Dear god.
|
||||
|
|
@ -4764,25 +4890,28 @@ void M_DrawProfileControls(void)
|
|||
INT32 x = 8;
|
||||
INT32 i, j, k;
|
||||
const UINT8 pid = 0;
|
||||
patch_t *hint = W_CachePatchName("MENUHINT", PU_CACHE);
|
||||
INT32 hintofs = 3;
|
||||
|
||||
V_DrawScaledPatch(BASEVIDWIDTH*2/3 - optionsmenu.contx, BASEVIDHEIGHT/2 -optionsmenu.conty, 0, W_CachePatchName("PR_CONT", PU_CACHE));
|
||||
|
||||
// Draw button presses...
|
||||
// @TODO: Dpad when we get the sprites for it.
|
||||
V_DrawScaledPatch(
|
||||
BASEVIDWIDTH*2/3 - optionsmenu.contx,
|
||||
BASEVIDHEIGHT/2 - optionsmenu.conty,
|
||||
0,
|
||||
W_CachePatchName(M_GetDPadPatchName(menucmd[pid].dpad_ud, menucmd[pid].dpad_lr), PU_CACHE)
|
||||
);
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
INT32 bt = 1<<i;
|
||||
if (M_MenuButtonHeld(pid, bt))
|
||||
{
|
||||
if (controllerpresspatch[i][1][0] != '\0')
|
||||
V_DrawScaledPatch(BASEVIDWIDTH*2/3 - optionsmenu.contx, BASEVIDHEIGHT/2 -optionsmenu.conty, 0, W_CachePatchName(controllerpresspatch[i][1], PU_CACHE));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (controllerpresspatch[i][0][0] != '\0')
|
||||
V_DrawScaledPatch(BASEVIDWIDTH*2/3 - optionsmenu.contx, BASEVIDHEIGHT/2 -optionsmenu.conty, 0, W_CachePatchName(controllerpresspatch[i][0], PU_CACHE));
|
||||
}
|
||||
V_DrawScaledPatch(
|
||||
BASEVIDWIDTH*2/3 - optionsmenu.contx,
|
||||
BASEVIDHEIGHT/2 - optionsmenu.conty,
|
||||
0,
|
||||
W_CachePatchName(controllerpresspatch[i][M_MenuButtonHeld(pid, bt) != 0], PU_CACHE)
|
||||
);
|
||||
}
|
||||
|
||||
if (optionsmenu.trycontroller)
|
||||
|
|
@ -4790,24 +4919,39 @@ void M_DrawProfileControls(void)
|
|||
optionsmenu.tcontx = BASEVIDWIDTH*2/3 - 10;
|
||||
optionsmenu.tconty = BASEVIDHEIGHT/2 +70;
|
||||
|
||||
V_DrawCenteredString(160, 180, highlightflags, va("PRESS NOTHING FOR %d SEC TO GO BACK", optionsmenu.trycontroller/TICRATE));
|
||||
V_DrawCenteredLSTitleLowString(160, 164, 0, "TRY BUTTONS");
|
||||
|
||||
const char *msg = va("Press nothing for %d sec to go back", (optionsmenu.trycontroller + (TICRATE-1)) / TICRATE);
|
||||
fixed_t w = V_StringScaledWidth(FRACUNIT, FRACUNIT, FRACUNIT, highlightflags, MED_FONT, msg);
|
||||
V_DrawStringScaled(
|
||||
160*FRACUNIT - w/2,
|
||||
186*FRACUNIT,
|
||||
FRACUNIT,
|
||||
FRACUNIT,
|
||||
FRACUNIT,
|
||||
highlightflags,
|
||||
NULL,
|
||||
MED_FONT,
|
||||
msg
|
||||
);
|
||||
return; // Don't draw the rest if we're trying the controller.
|
||||
}
|
||||
|
||||
// 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(229, 12, 0, currentMenu->menuitems[itemOn].tooltip);
|
||||
}
|
||||
|
||||
V_DrawFill(0, 0, 138, 200, 31); // Black border
|
||||
|
||||
V_SetClipRect(
|
||||
0,
|
||||
0,
|
||||
BASEVIDWIDTH * FRACUNIT,
|
||||
(BASEVIDHEIGHT - SHORT(hint->height) + hintofs) * FRACUNIT,
|
||||
0
|
||||
);
|
||||
|
||||
// Draw the menu options...
|
||||
for (i = 0; i < currentMenu->numitems; i++)
|
||||
{
|
||||
char buf[256];
|
||||
char buf2[256];
|
||||
INT32 keys[MAXINPUTMAPPING];
|
||||
|
||||
// cursor
|
||||
|
|
@ -4836,7 +4980,8 @@ void M_DrawProfileControls(void)
|
|||
|
||||
if (currentMenu->menuitems[i].patch)
|
||||
{
|
||||
V_DrawScaledPatch(x+12, y+12, 0, W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE));
|
||||
V_DrawScaledPatch(x-4, y+1, 0, W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE));
|
||||
V_DrawMenuString(x+12, y+2, (i == itemOn ? highlightflags : 0), currentMenu->menuitems[i].text);
|
||||
drawnpatch = true;
|
||||
}
|
||||
else
|
||||
|
|
@ -4862,6 +5007,9 @@ void M_DrawProfileControls(void)
|
|||
|
||||
UINT8 available = 0, set = 0;
|
||||
|
||||
if (i != itemOn)
|
||||
vflags |= V_GRAYMAP;
|
||||
|
||||
// Get userbound controls...
|
||||
for (k = 0; k < MAXINPUTMAPPING; k++)
|
||||
{
|
||||
|
|
@ -4882,6 +5030,7 @@ void M_DrawProfileControls(void)
|
|||
};
|
||||
|
||||
buf[0] = '\0';
|
||||
buf2[0] = '\0';
|
||||
|
||||
|
||||
// Cool as is this, this doesn't actually help show accurate info because of how some players would set inputs with keyboard and controller at once in a volatile way...
|
||||
|
|
@ -4928,10 +5077,15 @@ void M_DrawProfileControls(void)
|
|||
}
|
||||
}*/
|
||||
|
||||
char *p = buf;
|
||||
if (buf[0])
|
||||
;
|
||||
else if (!set)
|
||||
strcpy(buf, "\x85NOT BOUND");
|
||||
{
|
||||
vflags &= ~V_CHARCOLORMASK;
|
||||
vflags |= V_REDMAP;
|
||||
strcpy(buf, "NOT BOUND");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (k = 0; k < MAXINPUTMAPPING; k++)
|
||||
|
|
@ -4940,17 +5094,66 @@ void M_DrawProfileControls(void)
|
|||
continue;
|
||||
|
||||
if (k > 0)
|
||||
strcat(buf," / ");
|
||||
strcat(p," / ");
|
||||
|
||||
if (k == 2 && drawnpatch) // hacky...
|
||||
strcat(buf, "\n");
|
||||
if (k == 2) // hacky...
|
||||
p = buf2;
|
||||
|
||||
strcat(buf, G_KeynumToString (keys[k]));
|
||||
strcat(p, G_KeynumToString (keys[k]));
|
||||
}
|
||||
}
|
||||
|
||||
// don't shift the text if we didn't draw a patch.
|
||||
V_DrawThinString(x + (drawnpatch ? 32 : 0), y + (drawnpatch ? 2 : 12), vflags, buf);
|
||||
INT32 bindx = x;
|
||||
INT32 benx = 142;
|
||||
INT32 beny = y - 8;
|
||||
if (i == itemOn)
|
||||
{
|
||||
// Extend yellow wedge down behind
|
||||
// extra line.
|
||||
if (buf2[0])
|
||||
{
|
||||
for (j=24; j < 34; j++)
|
||||
V_DrawFill(0, (y)+j, 128+j, 1, 73);
|
||||
benx += 10;
|
||||
beny += 10;
|
||||
}
|
||||
|
||||
// Scroll text into Bind Ben.
|
||||
bindx += optionsmenu.bindben * 3;
|
||||
|
||||
if (buf2[0])
|
||||
{
|
||||
// Bind Ben: suck characters off
|
||||
// the end of the first line onto
|
||||
// the beginning of the second
|
||||
// line.
|
||||
UINT16 n = strlen(buf);
|
||||
UINT16 t = min(optionsmenu.bindben, n);
|
||||
memmove(&buf2[t], buf2, t + 1);
|
||||
memcpy(buf2, &buf[n - t], t);
|
||||
buf[n - t] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
cliprect_t clip;
|
||||
V_SaveClipRect(&clip); // preserve cliprect for tooltip
|
||||
|
||||
// Clip text as it scrolls into Bind Ben.
|
||||
V_SetClipRect(0, 0, (benx-14)*FRACUNIT, 200*FRACUNIT, 0);
|
||||
|
||||
if (i != itemOn || !optionsmenu.bindben_swallow)
|
||||
{
|
||||
// don't shift the text if we didn't draw a patch.
|
||||
V_DrawThinString(bindx + (drawnpatch ? 13 : 1), y + 12, vflags, buf);
|
||||
V_DrawThinString(bindx + (drawnpatch ? 13 : 1), y + 22, vflags, buf2);
|
||||
}
|
||||
|
||||
V_RestoreClipRect(&clip);
|
||||
}
|
||||
|
||||
if (i == itemOn)
|
||||
M_DrawBindBen(benx, beny, (benx-14) - bindx);
|
||||
|
||||
// controller dest coords:
|
||||
if (itemOn == i && gc > 0 && gc <= gc_start)
|
||||
|
|
@ -4967,8 +5170,29 @@ void M_DrawProfileControls(void)
|
|||
}
|
||||
}
|
||||
|
||||
V_ClearClipRect();
|
||||
|
||||
// Tooltip
|
||||
// Draw it at the bottom of the screen
|
||||
{
|
||||
static UINT8 blue[256];
|
||||
blue[31] = 253;
|
||||
V_DrawMappedPatch(0, BASEVIDHEIGHT + hintofs, V_VFLIP, hint, blue);
|
||||
}
|
||||
if (currentMenu->menuitems[itemOn].tooltip != NULL)
|
||||
{
|
||||
INT32 ypos = BASEVIDHEIGHT + hintofs - 9 - 12;
|
||||
V_DrawThinString(12, ypos, V_YELLOWMAP, currentMenu->menuitems[itemOn].tooltip);
|
||||
|
||||
boolean standardbuttons = gamedata->gonerlevel > GDGONER_PROFILE;
|
||||
INT32 xpos = BASEVIDWIDTH - 12;
|
||||
xpos = standardbuttons ?
|
||||
M_DrawProfileLegend(xpos, ypos, "\xB2/ \xBC Clear", NULL) :
|
||||
M_DrawProfileLegend(xpos, ypos, "Clear", "BKSP");
|
||||
}
|
||||
|
||||
// Overlay for control binding
|
||||
if (optionsmenu.bindcontrol)
|
||||
if (optionsmenu.bindtimer)
|
||||
{
|
||||
INT16 reversetimer = TICRATE*5 - optionsmenu.bindtimer;
|
||||
INT32 fade = reversetimer;
|
||||
|
|
@ -4977,14 +5201,33 @@ void M_DrawProfileControls(void)
|
|||
if (fade > 9)
|
||||
fade = 9;
|
||||
|
||||
ypos = (BASEVIDHEIGHT/2) - 4 +16*(9 - fade);
|
||||
ypos = (BASEVIDHEIGHT/2) - 20 +16*(9 - fade);
|
||||
V_DrawFadeScreen(31, fade);
|
||||
|
||||
M_DrawTextBox((BASEVIDWIDTH/2) - (120), ypos - 12, 30, 4);
|
||||
M_DrawTextBox((BASEVIDWIDTH/2) - (120), ypos - 12, 30, 8);
|
||||
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, ypos, 0, va("Press key #%d for control", optionsmenu.bindcontrol));
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, ypos +10, 0, va("\"%s\"", currentMenu->menuitems[itemOn].text));
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, ypos +20, highlightflags, va("(WAIT %d SECONDS TO SKIP)", optionsmenu.bindtimer/TICRATE));
|
||||
V_DrawCenteredMenuString(BASEVIDWIDTH/2, ypos, V_GRAYMAP, "Hold and release inputs for");
|
||||
V_DrawCenteredMenuString(BASEVIDWIDTH/2, ypos + 10, V_GRAYMAP, va("\"%s\"", currentMenu->menuitems[itemOn].text));
|
||||
|
||||
if (optionsmenu.bindtimer > 0)
|
||||
{
|
||||
M_DrawBindMediumString(
|
||||
ypos + 50,
|
||||
highlightflags,
|
||||
va("(WAIT %d SEC TO SKIP)", (optionsmenu.bindtimer + (TICRATE-1)) / TICRATE)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < MAXINPUTMAPPING && optionsmenu.bindinputs[i]; ++i)
|
||||
{
|
||||
M_DrawBindMediumString(
|
||||
ypos + (2 + i)*10,
|
||||
highlightflags | V_FORCEUPPERCASE,
|
||||
G_KeynumToString(optionsmenu.bindinputs[i])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ boolean M_Responder(event_t *ev)
|
|||
|
||||
// Profiles: Control mapping.
|
||||
// We take the WHOLE EVENT for convenience.
|
||||
if (optionsmenu.bindcontrol)
|
||||
if (optionsmenu.bindtimer)
|
||||
{
|
||||
M_MapProfileControl(ev);
|
||||
return true; // eat events.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/// \file menus/options-profiles-edit-1.c
|
||||
/// \brief Profile Editor
|
||||
|
||||
#include "../i_time.h"
|
||||
#include "../k_menu.h"
|
||||
#include "../s_sound.h"
|
||||
#include "../m_cond.h"
|
||||
|
|
@ -157,6 +158,11 @@ boolean M_ProfileEditInputs(INT32 ch)
|
|||
return true; // No.
|
||||
}
|
||||
|
||||
if (menucmd[pid].dpad_ud != 0)
|
||||
{
|
||||
optionsmenu.offset.start = I_GetTime();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -219,7 +225,6 @@ void M_ProfileDeviceSelect(INT32 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.lastkey = 0;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "../command.h"
|
||||
#include "../k_menu.h"
|
||||
#include "../m_easing.h"
|
||||
#include "../p_local.h" // cv_tilting
|
||||
|
||||
extern "C" consvar_t cv_mindelay;
|
||||
|
|
@ -16,7 +17,7 @@ namespace
|
|||
|
||||
void draw_routine()
|
||||
{
|
||||
Draw row = Draw(0, currentMenu->y).font(Draw::Font::kMenu);
|
||||
Draw row = Draw(M_EaseWithTransition(Easing_InSine, 5 * 48), currentMenu->y).font(Draw::Font::kMenu);
|
||||
|
||||
M_DrawEditProfileTooltips();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/// \file menus/options-profiles-edit-controls.c
|
||||
/// \brief Profile Controls Editor
|
||||
|
||||
#include "../g_input.h"
|
||||
#include "../k_menu.h"
|
||||
#include "../s_sound.h"
|
||||
#include "../i_joy.h" // for joystick menu controls
|
||||
|
|
@ -10,44 +11,44 @@ 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", {.routine = M_ProfileSetControl}, gc_a, 0},
|
||||
{IT_CONTROL, "Accel / Confirm", "Accelerate / Confirm",
|
||||
"TLB_A", {.routine = M_ProfileSetControl}, gc_a, 0},
|
||||
|
||||
{IT_CONTROL, "B", "Look backwards / Back",
|
||||
"PR_BTB", {.routine = M_ProfileSetControl}, gc_b, 0},
|
||||
{IT_CONTROL, "Look back", "Look backwards / Go back",
|
||||
"TLB_B", {.routine = M_ProfileSetControl}, gc_b, 0},
|
||||
|
||||
{IT_CONTROL, "C", "Spindash / Extra",
|
||||
"PR_BTC", {.routine = M_ProfileSetControl}, gc_c, 0},
|
||||
{IT_CONTROL, "Spindash", "Spindash / Extra",
|
||||
"TLB_C", {.routine = M_ProfileSetControl}, gc_c, 0},
|
||||
|
||||
{IT_CONTROL, "X", "Brake / Back",
|
||||
"PR_BTX", {.routine = M_ProfileSetControl}, gc_x, 0},
|
||||
{IT_CONTROL, "Brake / Go back", "Brake / Go back",
|
||||
"TLB_D", {.routine = M_ProfileSetControl}, gc_x, 0},
|
||||
|
||||
{IT_CONTROL, "Y", "Respawn",
|
||||
"PR_BTY", {.routine = M_ProfileSetControl}, gc_y, 0},
|
||||
{IT_CONTROL, "Respawn", "Respawn",
|
||||
"TLB_E", {.routine = M_ProfileSetControl}, gc_y, 0},
|
||||
|
||||
{IT_CONTROL, "Z", "Multiplayer quick-chat / quick-vote",
|
||||
"PR_BTZ", {.routine = M_ProfileSetControl}, gc_z, 0},
|
||||
{IT_CONTROL, "Action", "Multiplayer quick-chat / quick-vote",
|
||||
"TLB_F", {.routine = M_ProfileSetControl}, gc_z, 0},
|
||||
|
||||
{IT_CONTROL, "L", "Use item",
|
||||
"PR_BTL", {.routine = M_ProfileSetControl}, gc_l, 0},
|
||||
{IT_CONTROL, "Use Item", "Use item",
|
||||
"TLB_H", {.routine = M_ProfileSetControl}, gc_l, 0},
|
||||
|
||||
{IT_CONTROL, "R", "Drift",
|
||||
"PR_BTR", {.routine = M_ProfileSetControl}, gc_r, 0},
|
||||
{IT_CONTROL, "Drift", "Drift",
|
||||
"TLB_I", {.routine = M_ProfileSetControl}, gc_r, 0},
|
||||
|
||||
{IT_CONTROL, "Turn Left", "Turn left",
|
||||
"PR_PADL", {.routine = M_ProfileSetControl}, gc_left, 0},
|
||||
"TLB_M", {.routine = M_ProfileSetControl}, gc_left, 0},
|
||||
|
||||
{IT_CONTROL, "Turn Right", "Turn right",
|
||||
"PR_PADR", {.routine = M_ProfileSetControl}, gc_right, 0},
|
||||
"TLB_L", {.routine = M_ProfileSetControl}, gc_right, 0},
|
||||
|
||||
{IT_CONTROL, "Aim Forward", "Aim forwards",
|
||||
"PR_PADU", {.routine = M_ProfileSetControl}, gc_up, 0},
|
||||
"TLB_J", {.routine = M_ProfileSetControl}, gc_up, 0},
|
||||
|
||||
{IT_CONTROL, "Aim Backwards", "Aim backwards",
|
||||
"PR_PADD", {.routine = M_ProfileSetControl}, gc_down, 0},
|
||||
"TLB_K", {.routine = M_ProfileSetControl}, gc_down, 0},
|
||||
|
||||
{IT_CONTROL, "Start", "Open pause menu",
|
||||
"PR_BTS", {.routine = M_ProfileSetControl}, gc_start, 0},
|
||||
{IT_CONTROL, "Open pause menu", "Open pause menu",
|
||||
"TLB_G", {.routine = M_ProfileSetControl}, gc_start, 0},
|
||||
|
||||
{IT_HEADER, "OPTIONAL CONTROLS", "Take a screenshot, chat...",
|
||||
NULL, {NULL}, 0, 0},
|
||||
|
|
@ -58,21 +59,18 @@ menuitem_t OPTIONS_ProfileControls[] = {
|
|||
{IT_CONTROL, "RECORD VIDEO", "Record a video with sound.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_startmovie, 0},
|
||||
|
||||
{IT_CONTROL, "RECORD LOSSLESS", "Record a pixel perfect GIF.",
|
||||
{IT_CONTROL, "RECORD GIF", "Record a pixel perfect GIF.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_startlossless, 0},
|
||||
|
||||
{IT_CONTROL, "SHOW RANKINGS", "Display the current rankings mid-game.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_rankings, 0},
|
||||
|
||||
{IT_CONTROL, "OPEN CHAT", "Opens full keyboard chatting for online games.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_talk, 0},
|
||||
|
||||
{IT_CONTROL, "OPEN TEAM CHAT", "Opens team-only full chat for online games.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_teamtalk, 0},
|
||||
|
||||
{IT_CONTROL, "SHOW RANKINGS", "Display the current rankings mid-game.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_rankings, 0},
|
||||
|
||||
{IT_CONTROL, "OPEN CONSOLE", "Opens the developer options console.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_console, 0},
|
||||
|
||||
{IT_CONTROL, "LUA/A", "May be used by add-ons.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_luaa, 0},
|
||||
|
||||
|
|
@ -82,12 +80,21 @@ menuitem_t OPTIONS_ProfileControls[] = {
|
|||
{IT_CONTROL, "LUA/C", "May be used by add-ons.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_luac, 0},
|
||||
|
||||
{IT_HEADER, "EXTRA", "",
|
||||
{IT_CONTROL, "OPEN CONSOLE", "Opens the developer options console.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_console, 0},
|
||||
|
||||
{IT_HEADER, "TEST AND CONFIRM", "",
|
||||
NULL, {NULL}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CALL, "TRY MAPPINGS", "Test your controls.",
|
||||
NULL, {.routine = M_ProfileTryController}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CALL, "RESET TO DEFAULT", "Reset all controls back to default.",
|
||||
NULL, {.routine = M_ProfileDefaultControls}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CALL, "CLEAR ALL", "Unbind all controls.",
|
||||
NULL, {.routine = M_ProfileClearControls}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CALL, "CONFIRM", "Go back to profile setup.",
|
||||
NULL, {.routine = M_ProfileControlsConfirm}, 0, 0},
|
||||
};
|
||||
|
|
@ -129,8 +136,26 @@ static void SetDeviceOnPress(void)
|
|||
}
|
||||
*/
|
||||
|
||||
static boolean M_ClearCurrentControl(void)
|
||||
{
|
||||
// check if we're on a valid menu option...
|
||||
if (currentMenu->menuitems[itemOn].mvar1)
|
||||
{
|
||||
// clear controls for that key
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXINPUTMAPPING; i++)
|
||||
optionsmenu.tempcontrols[currentMenu->menuitems[itemOn].mvar1][i] = KEY_NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void M_HandleProfileControls(void)
|
||||
{
|
||||
const UINT8 pid = 0;
|
||||
UINT8 maxscroll = currentMenu->numitems - 5;
|
||||
M_OptionsTick();
|
||||
|
||||
|
|
@ -151,14 +176,39 @@ void M_HandleProfileControls(void)
|
|||
optionsmenu.controlscroll = 0;
|
||||
|
||||
// bindings, cancel if timer is depleted.
|
||||
if (optionsmenu.bindcontrol)
|
||||
if (optionsmenu.bindtimer)
|
||||
{
|
||||
optionsmenu.bindtimer--;
|
||||
if (!optionsmenu.bindtimer)
|
||||
if (optionsmenu.bindtimer > 0)
|
||||
optionsmenu.bindtimer--;
|
||||
}
|
||||
else if (currentMenu->menuitems[itemOn].mvar1) // check if we're on a valid menu option...
|
||||
{
|
||||
// Hold right to begin clearing the control.
|
||||
//
|
||||
// If bindben timer increases enough, bindben_swallow
|
||||
// will be set.
|
||||
// This is a commitment to clear the control.
|
||||
// You can keep holding right to postpone the clear
|
||||
// but once you let go, you are locked out of
|
||||
// pressing it again until the animation finishes.
|
||||
if (menucmd[pid].dpad_lr > 0 && (optionsmenu.bindben || !optionsmenu.bindben_swallow))
|
||||
{
|
||||
optionsmenu.bindcontrol = 0; // we've gone past the max, just stop.
|
||||
optionsmenu.bindben++;
|
||||
}
|
||||
else
|
||||
{
|
||||
optionsmenu.bindben = 0;
|
||||
|
||||
if (optionsmenu.bindben_swallow)
|
||||
{
|
||||
optionsmenu.bindben_swallow--;
|
||||
|
||||
if (optionsmenu.bindben_swallow == 100) // special countdown for the "quick" animation
|
||||
optionsmenu.bindben_swallow = 0;
|
||||
else if (!optionsmenu.bindben_swallow) // long animation, clears control when done
|
||||
M_ClearCurrentControl();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,19 +236,37 @@ static void M_ProfileControlSaveResponse(INT32 choice)
|
|||
{
|
||||
memcpy(&gamecontrol[belongsto], optionsmenu.tempcontrols, sizeof(gamecontroldefault));
|
||||
}
|
||||
|
||||
M_GoBack(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Revert changes
|
||||
memcpy(optionsmenu.tempcontrols, optionsmenu.profile->controls, sizeof(gamecontroldefault));
|
||||
}
|
||||
|
||||
M_GoBack(0);
|
||||
}
|
||||
|
||||
void M_ProfileControlsConfirm(INT32 choice)
|
||||
{
|
||||
(void)choice;
|
||||
if (!memcmp(optionsmenu.profile->controls, optionsmenu.tempcontrols, sizeof(gamecontroldefault)))
|
||||
{
|
||||
M_GoBack(0); // no change
|
||||
}
|
||||
else if (choice == 0)
|
||||
{
|
||||
M_StartMessage(
|
||||
"Profiles",
|
||||
"You have unsaved changes to your controls.\n"
|
||||
"Please confirm if you wish to save them.\n",
|
||||
&M_ProfileControlSaveResponse,
|
||||
MM_YESNO,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
else
|
||||
M_ProfileControlSaveResponse(MA_YES);
|
||||
|
||||
//M_StartMessage("Profiles", M_GetText("Exiting will save the control changes\nfor this Profile.\nIs this okay?\n"), &M_ProfileControlSaveResponse, MM_YESNO, NULL, NULL);
|
||||
// TODO: Add a graphic for controls saving, instead of obnoxious prompt.
|
||||
|
||||
M_ProfileControlSaveResponse(MA_YES);
|
||||
|
||||
// Reapply player 1's real profile.
|
||||
if (cv_currprofile.value > -1)
|
||||
|
|
@ -217,6 +285,33 @@ boolean M_ProfileControlsInputs(INT32 ch)
|
|||
{
|
||||
if (menucmd[pid].dpad_ud || menucmd[pid].dpad_lr || menucmd[pid].buttons)
|
||||
{
|
||||
if (menucmd[pid].dpad_ud != menucmd[pid].prev_dpad_ud || menucmd[pid].dpad_lr != menucmd[pid].prev_dpad_lr)
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
|
||||
UINT32 newbuttons = menucmd[pid].buttons & ~(menucmd[pid].buttonsHeld);
|
||||
|
||||
if (newbuttons & MBT_L)
|
||||
S_StartSound(NULL, sfx_kc69);
|
||||
if (newbuttons & MBT_R)
|
||||
S_StartSound(NULL, sfx_s3ka2);
|
||||
|
||||
if (newbuttons & MBT_A)
|
||||
S_StartSound(NULL, sfx_kc3c);
|
||||
if (newbuttons & MBT_B)
|
||||
S_StartSound(NULL, sfx_3db09);
|
||||
if (newbuttons & MBT_C)
|
||||
S_StartSound(NULL, sfx_s1be);
|
||||
|
||||
if (newbuttons & MBT_X)
|
||||
S_StartSound(NULL, sfx_s1a4);
|
||||
if (newbuttons & MBT_Y)
|
||||
S_StartSound(NULL, sfx_s3kcas);
|
||||
if (newbuttons & MBT_Z)
|
||||
S_StartSound(NULL, sfx_s3kc3s);
|
||||
|
||||
if (newbuttons & MBT_START)
|
||||
S_StartSound(NULL, sfx_gshdc);
|
||||
|
||||
optionsmenu.trycontroller = 5*TICRATE;
|
||||
}
|
||||
else
|
||||
|
|
@ -236,24 +331,17 @@ boolean M_ProfileControlsInputs(INT32 ch)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (optionsmenu.bindcontrol)
|
||||
if (optionsmenu.bindtimer)
|
||||
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...
|
||||
|
||||
if (M_MenuExtraPressed(pid))
|
||||
{
|
||||
// check if we're on a valid menu option...
|
||||
if (currentMenu->menuitems[itemOn].mvar1)
|
||||
{
|
||||
// clear controls for that key
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXINPUTMAPPING; i++)
|
||||
optionsmenu.tempcontrols[currentMenu->menuitems[itemOn].mvar1][i] = KEY_NULL;
|
||||
|
||||
S_StartSound(NULL, sfx_s3k66);
|
||||
}
|
||||
if (M_ClearCurrentControl())
|
||||
S_StartSound(NULL, sfx_monch);
|
||||
optionsmenu.bindben = 0;
|
||||
optionsmenu.bindben_swallow = M_OPTIONS_BINDBEN_QUICK;
|
||||
M_SetMenuDelay(pid);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -264,30 +352,73 @@ boolean M_ProfileControlsInputs(INT32 ch)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (menucmd[pid].dpad_ud)
|
||||
{
|
||||
if (optionsmenu.bindben_swallow)
|
||||
{
|
||||
// Control would be cleared, but we're
|
||||
// interrupting the animation so clear it
|
||||
// immediately.
|
||||
M_ClearCurrentControl();
|
||||
}
|
||||
optionsmenu.bindben = 0;
|
||||
optionsmenu.bindben_swallow = 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void M_ProfileSetControl(INT32 ch)
|
||||
{
|
||||
INT32 controln = currentMenu->menuitems[itemOn].mvar1;
|
||||
UINT8 i;
|
||||
(void) ch;
|
||||
|
||||
optionsmenu.bindcontrol = 1; // Default to control #1
|
||||
|
||||
for (i = 0; i < MAXINPUTMAPPING; i++)
|
||||
{
|
||||
if (optionsmenu.tempcontrols[controln][i] == KEY_NULL)
|
||||
{
|
||||
optionsmenu.bindcontrol = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we could find a null key to map into, map there.
|
||||
// Otherwise, this will stay at 1 which means we'll overwrite the first bound control.
|
||||
|
||||
optionsmenu.bindtimer = TICRATE*5;
|
||||
memset(optionsmenu.bindinputs, 0, sizeof optionsmenu.bindinputs);
|
||||
G_ResetAllDeviceGameKeyDown();
|
||||
}
|
||||
|
||||
static void M_ProfileDefaultControlsResponse(INT32 ch)
|
||||
{
|
||||
if (ch == MA_YES)
|
||||
{
|
||||
memcpy(&optionsmenu.tempcontrols, gamecontroldefault, sizeof optionsmenu.tempcontrols);
|
||||
S_StartSound(NULL, sfx_s24f);
|
||||
}
|
||||
}
|
||||
|
||||
void M_ProfileDefaultControls(INT32 ch)
|
||||
{
|
||||
(void)ch;
|
||||
M_StartMessage(
|
||||
"Profiles",
|
||||
"Reset all controls to the default mappings?",
|
||||
&M_ProfileDefaultControlsResponse,
|
||||
MM_YESNO,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
static void M_ProfileClearControlsResponse(INT32 ch)
|
||||
{
|
||||
if (ch == MA_YES)
|
||||
{
|
||||
memset(&optionsmenu.tempcontrols, 0, sizeof optionsmenu.tempcontrols);
|
||||
S_StartSound(NULL, sfx_s3k66);
|
||||
}
|
||||
}
|
||||
|
||||
void M_ProfileClearControls(INT32 ch)
|
||||
{
|
||||
(void)ch;
|
||||
M_StartMessage(
|
||||
"Profiles",
|
||||
"Clear all control bindings?",
|
||||
&M_ProfileClearControlsResponse,
|
||||
MM_YESNO,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
// Map the event to the profile.
|
||||
|
|
@ -295,157 +426,61 @@ void M_ProfileSetControl(INT32 ch)
|
|||
#define KEYHOLDFOR 1
|
||||
void M_MapProfileControl(event_t *ev)
|
||||
{
|
||||
INT32 c = 0;
|
||||
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.
|
||||
INT32 i;
|
||||
if (ev->type == ev_keydown && ev->data2) // ignore repeating keys
|
||||
return;
|
||||
|
||||
if (optionsmenu.bindtimer > TICRATE*5 - 9) // grace period after entering the bind dialog
|
||||
return;
|
||||
|
||||
INT32 *DeviceGameKeyDownArray = G_GetDeviceGameKeyDownArray(ev->device);
|
||||
|
||||
if (!DeviceGameKeyDownArray)
|
||||
return;
|
||||
|
||||
//SetDeviceOnPress(); // Update player gamepad assignments
|
||||
|
||||
// Only consider keydown and joystick events to make sure we ignore ev_mouse and other events
|
||||
// See also G_MapEventsToControls
|
||||
switch (ev->type)
|
||||
// Find every held button.
|
||||
boolean noinput = true;
|
||||
for (INT32 c = 1; c < NUMINPUTS; ++c)
|
||||
{
|
||||
case ev_keydown:
|
||||
if (ev->data1 < NUMINPUTS)
|
||||
{
|
||||
c = ev->data1;
|
||||
}
|
||||
#ifdef PARANOIA
|
||||
else
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Bad downkey input %d\n", ev->data1);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ev_gamepad_axis:
|
||||
if (ev->data1 >= JOYAXES)
|
||||
{
|
||||
#ifdef PARANOIA
|
||||
CONS_Debug(DBG_GAMELOGIC, "Bad gamepad axis event %d\n", ev->data1);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
INT32 deadzone = deadzone = (JOYAXISRANGE * cv_deadzone[0].value) / FRACUNIT; // TODO how properly account for different deadzone cvars for different devices
|
||||
boolean responsivelr = ((ev->data2 != INT32_MAX) && (abs(ev->data2) >= deadzone));
|
||||
boolean responsiveud = ((ev->data3 != INT32_MAX) && (abs(ev->data3) >= deadzone));
|
||||
if (DeviceGameKeyDownArray[c] < 3*JOYAXISRANGE/4)
|
||||
continue;
|
||||
|
||||
i = ev->data1;
|
||||
noinput = false;
|
||||
|
||||
if (i >= JOYANALOGS)
|
||||
{
|
||||
// The trigger axes are handled specially.
|
||||
i -= JOYANALOGS;
|
||||
|
||||
if (responsivelr)
|
||||
{
|
||||
c = KEY_AXIS1 + (JOYANALOGS * 4) + (i * 2);
|
||||
}
|
||||
else if (responsiveud)
|
||||
{
|
||||
c = KEY_AXIS1 + (JOYANALOGS * 4) + (i * 2) + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Actual analog sticks
|
||||
|
||||
// Only consider unambiguous assignment.
|
||||
if (responsivelr == responsiveud)
|
||||
return;
|
||||
|
||||
if (responsivelr)
|
||||
{
|
||||
if (ev->data2 < 0)
|
||||
{
|
||||
// Left
|
||||
c = KEY_AXIS1 + (i * 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Right
|
||||
c = KEY_AXIS1 + (i * 4) + 1;
|
||||
}
|
||||
}
|
||||
else //if (responsiveud)
|
||||
{
|
||||
if (ev->data3 < 0)
|
||||
{
|
||||
// Up
|
||||
c = KEY_AXIS1 + (i * 4) + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Down
|
||||
c = KEY_AXIS1 + (i * 4) + 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// safety result
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
// Set menu delay regardless of what we're doing to avoid stupid stuff.
|
||||
M_SetMenuDelay(0);
|
||||
|
||||
// Reset this input so (keyboard keys at least) are not
|
||||
// buffered and caught by menucmd.
|
||||
DeviceGameKeyDownArray[c] = 0;
|
||||
|
||||
// Check if this particular key (c) is already bound in any slot.
|
||||
// If that's the case, simply do nothing.
|
||||
for (i = 0; i < MAXINPUTMAPPING; i++)
|
||||
{
|
||||
if (optionsmenu.tempcontrols[controln][i] == c)
|
||||
for (UINT8 i = 0; i < MAXINPUTMAPPING; ++i)
|
||||
{
|
||||
optionsmenu.bindcontrol = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If this key is already bound, don't bind it again.
|
||||
if (optionsmenu.bindinputs[i] == c)
|
||||
break;
|
||||
|
||||
// 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.tempcontrols[controln][where] = c;
|
||||
optionsmenu.bindcontrol = 0; // not binding anymore
|
||||
|
||||
// If possible, reapply the profile...
|
||||
// 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;
|
||||
PR_ApplyProfile(PR_GetProfileNum(optionsmenu.profile), 0);
|
||||
CV_StealthSetValue(&cv_lastprofile[0], lastp);
|
||||
}
|
||||
else // != GS_MENU
|
||||
{
|
||||
// ONLY apply the profile if it's in use by anything currently.
|
||||
UINT8 pnum = PR_GetProfileNum(optionsmenu.profile);
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
if (cv_lastprofile[i].value == pnum)
|
||||
// Find the first available slot.
|
||||
if (!optionsmenu.bindinputs[i])
|
||||
{
|
||||
PR_ApplyProfile(pnum, i);
|
||||
optionsmenu.bindinputs[i] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (noinput)
|
||||
{
|
||||
{
|
||||
// You can hold a button before entering this
|
||||
// dialog, then buffer a keyup without pressing
|
||||
// anything else. If this happens, don't wipe the
|
||||
// binds, just ignore it.
|
||||
const UINT8 zero[sizeof optionsmenu.bindinputs] = {0};
|
||||
if (!memcmp(zero, optionsmenu.bindinputs, sizeof zero))
|
||||
return;
|
||||
}
|
||||
|
||||
INT32 controln = currentMenu->menuitems[itemOn].mvar1;
|
||||
memcpy(&optionsmenu.tempcontrols[controln], optionsmenu.bindinputs, sizeof optionsmenu.bindinputs);
|
||||
optionsmenu.bindtimer = 0;
|
||||
|
||||
// Set menu delay regardless of what we're doing to avoid stupid stuff.
|
||||
M_SetMenuDelay(0);
|
||||
}
|
||||
else
|
||||
optionsmenu.bindtimer = -1; // prevent skip countdown
|
||||
}
|
||||
#undef KEYHOLDFOR
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue