Merge branch 'menu-pokes' into 'master'

Menu Pokes

See merge request KartKrew/Kart!1248
This commit is contained in:
Oni 2023-05-26 05:53:16 +00:00
commit 9b8306c91b
15 changed files with 692 additions and 237 deletions

View file

@ -648,11 +648,31 @@ INT32 CON_ShiftChar(INT32 ch)
{
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
{
// Standard Latin-script uppercase translation
if (shiftdown ^ capslock)
ch = shiftxform[ch];
}
else // if we're holding shift we should still shift non letter symbols
else if (ch >= KEY_KEYPAD7 && ch <= KEY_KPADDEL)
{
// Numpad keycodes mapped to printable equivalent
const char keypad_translation[] =
{
'7','8','9','-',
'4','5','6','+',
'1','2','3',
'0','.'
};
ch = keypad_translation[ch - KEY_KEYPAD7];
}
else if (ch == KEY_KPADSLASH)
{
// Ditto, but non-contiguous keycode
ch = '/';
}
else
{
// QWERTY keycode translation
if (shiftdown)
ch = shiftxform[ch];
}
@ -1296,30 +1316,7 @@ boolean CON_Responder(event_t *ev)
return true;
}
// allow people to use keypad in console (good for typing IP addresses) - Calum
if (key >= KEY_KEYPAD7 && key <= KEY_KPADDEL)
{
char keypad_translation[] = {'7','8','9','-',
'4','5','6','+',
'1','2','3',
'0','.'};
key = keypad_translation[key - KEY_KEYPAD7];
}
else if (key == KEY_KPADSLASH)
key = '/';
// same capslock code as hu_stuff.c's HU_responder. Check there for details.
if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z'))
{
if (shiftdown ^ capslock)
key = shiftxform[key];
}
else
{
if (shiftdown)
key = shiftxform[key];
}
key = CON_ShiftChar(key);
// enter a char into the command prompt
if (key < 32 || key > 127)

View file

@ -659,25 +659,6 @@ static void D_Display(void)
if (forcerefresh && G_GamestateUsesLevel() == false)
V_SetPalette(0);
// draw pause pic
if (paused && cv_showhud.value && !demo.playback)
{
#if 0
INT32 py;
patch_t *patch;
if (automapactive)
py = 4;
else
py = viewwindowy + 4;
patch = W_CachePatchName("M_PAUSE", PU_PATCH);
V_DrawScaledPatch(viewwindowx + (BASEVIDWIDTH - patch->width)/2, py, 0, patch);
#else
INT32 y = ((automapactive) ? (32) : (BASEVIDHEIGHT/2));
M_DrawTextBox((BASEVIDWIDTH/2) - (60), y - (16), 13, 2);
V_DrawCenteredString(BASEVIDWIDTH/2, y - (4), V_YELLOWMAP, "Game Paused");
#endif
}
if (demo.rewinding)
V_DrawFadeScreen(TC_RAINBOW, (leveltime & 0x20) ? SKINCOLOR_PASTEL : SKINCOLOR_MOONSET);

View file

@ -2586,13 +2586,16 @@ static void HU_DrawRankings(void)
#define strtime standings.strval[standings.numplayers]
standings.val[standings.numplayers] = 0;
strtime[0] = '\0';
if (players[i].pflags & PF_NOCONTEST)
{
standings.val[standings.numplayers] = (UINT32_MAX-1);
STRBUFCPY(strtime, "RETIRED.");
}
else if ((gametyperules & GTR_CIRCUIT))
{
{
standings.val[standings.numplayers] = players[i].laps;
if (players[i].exiting)
@ -2600,12 +2603,12 @@ static void HU_DrawRankings(void)
snprintf(strtime, sizeof strtime, "%i'%02i\"%02i", G_TicsToMinutes(players[i].realtime, true),
G_TicsToSeconds(players[i].realtime), G_TicsToCentiseconds(players[i].realtime));
}
else
else if (numlaps > 1)
{
snprintf(strtime, sizeof strtime, "Lap %d", standings.val[standings.numplayers]);
snprintf(strtime, sizeof strtime, "Lap %d", players[i].laps);
}
}
else
else if ((gametyperules & GTR_POINTLIMIT))
{
standings.val[standings.numplayers] = players[i].roundscore;
snprintf(strtime, sizeof strtime, "%d", standings.val[standings.numplayers]);

View file

@ -487,8 +487,9 @@ extern INT16 skullAnimCounter; // skull animation counter
extern INT32 menuKey; // keyboard key pressed for menu
extern INT16 virtualKeyboard[5][13];
extern INT16 shift_virtualKeyboard[5][13];
#define NUMVIRTUALKEYSINROW (10+2) // 1-9, 0, and a right-side gutter of two keys' width
extern INT16 virtualKeyboard[5][NUMVIRTUALKEYSINROW];
extern INT16 shift_virtualKeyboard[5][NUMVIRTUALKEYSINROW];
extern struct menutyping_s
{
@ -551,10 +552,16 @@ typedef enum
struct menucmd_t
{
// Current frame's data
SINT8 dpad_ud; // up / down dpad
SINT8 dpad_lr; // left / right
UINT32 buttons; // buttons
UINT32 buttonsHeld; // prev frame's buttons
// Previous frame's data
SINT8 prev_dpad_ud;
SINT8 prev_dpad_lr;
UINT32 buttonsHeld;
UINT16 delay; // menu wait
UINT32 delayCount; // num times ya did menu wait (to make the wait shorter each time)
};

View file

@ -357,79 +357,233 @@ void M_DrawMenuForeground(void)
}
}
//
// M_DrawMenuTooltips
//
// Draw a banner across the top of the screen, with a description of the current option displayed
//
static void M_DrawMenuTooltips(void)
{
if (currentMenu->menuitems[itemOn].tooltip != NULL)
{
V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("MENUHINT", PU_CACHE), NULL);
V_DrawCenteredThinString(BASEVIDWIDTH/2, 12, V_ALLOWLOWERCASE|V_6WIDTHSPACE, currentMenu->menuitems[itemOn].tooltip);
}
}
// Draws the typing submenu
static void M_DrawMenuTyping(void)
{
const UINT8 pid = 0;
INT32 i, j;
INT32 x = 60;
INT32 y = 100 + (9-menutyping.menutypingfade)*8;
INT32 tflag = (9 - menutyping.menutypingfade)<<V_ALPHASHIFT;
INT32 x, y;
consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar;
char buf[8]; // We write there to use drawstring for convenience.
V_DrawFadeScreen(31, menutyping.menutypingfade);
V_DrawFadeScreen(31, (menutyping.menutypingfade+1)/2);
// Draw the string we're editing at the top.
V_DrawString(x, y-48 + 12, V_ALLOWLOWERCASE|tflag, cv->string);
const INT32 boxwidth = (8*(MAXSTRINGLENGTH + 1)) + 7;
x = (BASEVIDWIDTH - boxwidth)/2;
y = 80;
if (menutyping.menutypingfade < 9)
y += (9-menutyping.menutypingfade)*10;
else
y += (9-menutyping.menutypingfade);
if (currentMenu->menuitems[itemOn].text)
{
V_DrawThinString(x + 5, y - 2, highlightflags|V_ALLOWLOWERCASE, currentMenu->menuitems[itemOn].text);
}
M_DrawMenuTooltips();
//M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1);
V_DrawFill(x + 5, y + 4 + 5, boxwidth - 8, 8+6, 159);
V_DrawFill(x + 4, y + 4 + 4, boxwidth - 6, 1, 121);
V_DrawFill(x + 4, y + 4 + 5 + 8 + 6, boxwidth - 6, 1, 121);
V_DrawFill(x + 4, y + 4 + 5, 1, 8+6, 121);
V_DrawFill(x + 5 + boxwidth - 8, y + 4 + 5, 1, 8+6, 121);
V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, cv->string);
if (skullAnimCounter < 4)
V_DrawCharacter(x + V_StringWidth(cv->string, 0), y - 35, '_' | 0x80, false);
V_DrawCharacter(x + 8 + V_StringWidth(cv->string, 0), y + 12 + 1, '_' | 0x80, false);
const INT32 buttonwidth = ((boxwidth + 1)/NUMVIRTUALKEYSINROW);
#define BUTTONHEIGHT (11)
// Now the keyboard itself
x += 5;
INT32 returnx = x;
if (menutyping.menutypingfade > 9)
{
y += 36 + 80 + (9-menutyping.menutypingfade)*10; // double yoffs for animation
INT32 tempkeyboardx = menutyping.keyboardx;
while (virtualKeyboard[menutyping.keyboardy][tempkeyboardx] == 1
&& tempkeyboardx > 0)
tempkeyboardx--;
for (i = 0; i < 5; i++)
{
j = 0;
while (j < NUMVIRTUALKEYSINROW)
{
INT32 mflag = V_ALLOWLOWERCASE|V_6WIDTHSPACE;
INT16 c = virtualKeyboard[i][j];
INT32 buttonspacing = 1;
UINT8 col = 27;
INT32 arrowoffset = 0;
while (j + buttonspacing < NUMVIRTUALKEYSINROW
&& virtualKeyboard[i][j + buttonspacing] == 1)
{
buttonspacing++;
}
if (menutyping.keyboardshift ^ menutyping.keyboardcapslock)
c = shift_virtualKeyboard[i][j];
if (i < 4 && j < NUMVIRTUALKEYSINROW-2)
{
col = 25;
}
boolean canmodifycol = (menutyping.menutypingfade == 18);
if (c == KEY_BACKSPACE)
{
arrowoffset = 1;
buf[0] = '\x1C'; // left arrow
buf[1] = '\0';
if (canmodifycol && M_MenuBackHeld(pid))
{
col -= 4;
canmodifycol = false;
}
}
else if (c == KEY_RSHIFT)
{
arrowoffset = 2;
buf[0] = '\x1A'; // up arrow
buf[1] = '\0';
if (menutyping.keyboardcapslock || menutyping.keyboardshift)
{
col = 22;
}
if (canmodifycol && M_MenuExtraHeld(pid))
{
col -= 4;
canmodifycol = false;
}
}
else if (c == KEY_ENTER)
{
strcpy(buf, "OK");
if (menutyping.menutypingclose)
{
col -= 4;
canmodifycol = false;
}
}
else if (c == KEY_SPACE)
{
strcpy(buf, "Space");
}
else
{
buf[0] = c;
buf[1] = '\0';
}
INT32 width = (buttonwidth * buttonspacing) - 1;
// highlight:
/*if (menutyping.keyboardtyping)
{
mflag |= V_TRANSLUCENT; // grey it out if we can't use it.
}
else*/
{
if (tempkeyboardx == j && menutyping.keyboardy == i)
{
if (canmodifycol && M_MenuConfirmHeld(pid))
{
col -= 4;
canmodifycol = false;
}
V_DrawFill(x + 1, y + 1, width - 2, BUTTONHEIGHT - 2, col - 3);
V_DrawFill(x, y, width, 1, 121);
V_DrawFill(x, y + BUTTONHEIGHT - 1, width, 1, 121);
V_DrawFill(x, y + 1, 1, BUTTONHEIGHT - 2, 121);
V_DrawFill(x + width - 1, y + 1, 1, BUTTONHEIGHT - 2, 121);
mflag |= highlightflags;
}
else
{
V_DrawFill(x, y, width, BUTTONHEIGHT, col);
}
}
if (arrowoffset != 0)
{
if (c == KEY_RSHIFT)
{
V_DrawFill(x + width - 5, y + 1, 4, 4, 31);
if (menutyping.keyboardcapslock)
{
V_DrawFill(x + width - 4, y + 2, 2, 2, 121);
}
}
V_DrawCenteredString(x + (width/2), y + 1 + arrowoffset, mflag, buf);
}
else
{
V_DrawCenteredThinString(x + (width/2), y + 1, mflag, buf);
}
x += width + 1;
j += buttonspacing;
}
x = returnx;
y += BUTTONHEIGHT + 1;
}
}
#undef BUTTONHEIGHT
// Some contextual stuff
if (menutyping.keyboardtyping)
V_DrawThinString(10, 175, V_ALLOWLOWERCASE|tflag|V_GRAYMAP, "Type using your keyboard. Press Enter to confirm & exit.\nUse your controller or any directional input to use the Virtual Keyboard.\n");
else
V_DrawThinString(10, 175, V_ALLOWLOWERCASE|tflag|V_GRAYMAP, "Type using the Virtual Keyboard. Use the \'OK\' button to confirm & exit.\nPress any keyboard key not bound to a control to use it.");
// Now the keyboard itself
for (i=0; i < 5; i++)
{
for (j=0; j < 13; j++)
{
INT32 mflag = 0;
INT16 c = virtualKeyboard[i][j];
if (menutyping.keyboardshift ^ menutyping.keyboardcapslock)
c = shift_virtualKeyboard[i][j];
if (c == KEY_BACKSPACE)
strcpy(buf, "DEL");
else if (c == KEY_RSHIFT)
strcpy(buf, "SHIFT");
else if (c == KEY_CAPSLOCK)
strcpy(buf, "CAPS");
else if (c == KEY_ENTER)
strcpy(buf, "OK");
else if (c == KEY_SPACE)
strcpy(buf, "SPACE");
else
{
buf[0] = c;
buf[1] = '\0';
}
// highlight:
if (menutyping.keyboardx == j && menutyping.keyboardy == i && !menutyping.keyboardtyping)
mflag |= highlightflags;
else if (menutyping.keyboardtyping)
mflag |= V_TRANSLUCENT; // grey it out if we can't use it.
V_DrawString(x, y, V_ALLOWLOWERCASE|tflag|mflag, buf);
x += V_StringWidth(buf, 0)+8;
}
x = 60;
y += 12;
V_DrawThinString(returnx, 175, V_ALLOWLOWERCASE|V_6WIDTHSPACE|V_GRAYMAP, "Type using your keyboard. Press Enter to confirm & exit.\nUse your controller or any directional input to use the Virtual Keyboard.\n");
}
else
{
V_DrawThinString(x, 175, V_ALLOWLOWERCASE|V_6WIDTHSPACE|V_GRAYMAP, "Type using the Virtual Keyboard. Use the \'OK\' button to confirm & exit.\nPress any keyboard key not bound to a control to use it.");
}
}
// Draw the message popup submenu
@ -497,6 +651,16 @@ void M_DrawMenuMessage(void)
}
}
// PAUSE
static void M_DrawPausedText(INT32 x)
{
patch_t *pausebg = W_CachePatchName("M_STRIPU", PU_CACHE);
patch_t *pausetext = W_CachePatchName("M_PAUSET", PU_CACHE);
V_DrawFixedPatch(x, 0, FRACUNIT, V_SNAPTOLEFT|V_SNAPTOTOP|V_ADD, pausebg, NULL);
V_DrawFixedPatch(x, 0, FRACUNIT, V_SNAPTOLEFT|V_SNAPTOTOP, pausetext, NULL);
}
//
// M_Drawer
// Called after the view has been rendered,
@ -556,14 +720,17 @@ void M_Drawer(void)
menuwipe = false;
}
// draw pause pic
if (paused && !demo.playback && (menuactive || cv_showhud.value))
{
M_DrawPausedText(0);
}
// focus lost notification goes on top of everything, even the former everything
if (window_notinfocus && cv_showfocuslost.value)
{
M_DrawTextBox((BASEVIDWIDTH/2) - (60), (BASEVIDHEIGHT/2) - (16), 13, 2);
if (gamestate == GS_LEVEL && (P_AutoPause() || paused))
V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), highlightflags, "Game Paused");
else
V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), highlightflags, "Focus Lost");
V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), highlightflags, "Focus Lost");
}
}
@ -571,20 +738,6 @@ void M_Drawer(void)
// GENERIC MENUS
// ==========================================================================
//
// M_DrawMenuTooltips
//
// Draw a banner across the top of the screen, with a description of the current option displayed
//
static void M_DrawMenuTooltips(void)
{
if (currentMenu->menuitems[itemOn].tooltip != NULL)
{
V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("MENUHINT", PU_CACHE), NULL);
V_DrawCenteredThinString(BASEVIDWIDTH/2, 12, V_ALLOWLOWERCASE|V_6WIDTHSPACE, currentMenu->menuitems[itemOn].tooltip);
}
}
// Converts a string into question marks.
// Used for the secrets menu, to hide yet-to-be-unlocked stuff.
static const char *M_CreateSecretMenuOption(const char *str)
@ -680,12 +833,20 @@ void M_DrawGenericMenu(void)
break;
#endif
case IT_CV_STRING:
M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1);
V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, cv->string);
if (skullAnimCounter < 4 && i == itemOn)
V_DrawCharacter(x + 8 + V_StringWidth(cv->string, 0), y + 12,
'_' | 0x80, false);
y += 16;
{
M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1);
INT32 xoffs = 0;
if (itemOn == i)
{
xoffs += 8;
V_DrawString(x + (skullAnimCounter/5) + 6, y + 12, highlightflags, "\x1D");
}
V_DrawString(x + xoffs + 8, y + 12, V_ALLOWLOWERCASE, cv->string);
y += 16;
}
break;
default:
w = V_StringWidth(cv->string, 0);
@ -2727,9 +2888,16 @@ void M_DrawMPHost(void)
switch (currentMenu->menuitems[i].status & IT_CVARTYPE)
{
case IT_CV_STRING:
V_DrawThinString(xp + 96, yp, V_ALLOWLOWERCASE|V_6WIDTHSPACE, cv->string);
if (skullAnimCounter < 4 && i == itemOn)
V_DrawString(xp + 96 + V_ThinStringWidth(cv->string, V_ALLOWLOWERCASE|V_6WIDTHSPACE), yp+1, 0, "_");
{
INT32 xoffs = 0;
if (itemOn == i)
{
xoffs += 8;
V_DrawString(xp + (skullAnimCounter/5) + 94, yp+1, highlightflags, "\x1D");
}
V_DrawThinString(xp + xoffs + 96, yp, V_ALLOWLOWERCASE|V_6WIDTHSPACE, cv->string);
}
break;
@ -2837,9 +3005,17 @@ void M_DrawMPJoinIP(void)
colormapc = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
V_DrawFixedPatch((xp + 12)<<FRACBITS, (yp-2)<<FRACBITS, FRACUNIT, 0, typebar, colormapc); // Always consider that this is selected otherwise it clashes.
V_DrawThinString(xp + 18, yp, V_ALLOWLOWERCASE|V_6WIDTHSPACE, cv->string);
if (skullAnimCounter < 4 && i == itemOn)
V_DrawString(xp + 18 + V_ThinStringWidth(cv->string, V_ALLOWLOWERCASE|V_6WIDTHSPACE), yp+1, 0, "_");
{
INT32 xoffs = 0;
if (itemOn == i)
{
xoffs += 8;
V_DrawString(xp + (skullAnimCounter/5) + 17, yp+1, highlightflags, "\x1D");
}
V_DrawThinString(xp + xoffs + 18, yp, V_ALLOWLOWERCASE|V_6WIDTHSPACE, cv->string);
}
/*// On this specific menu the only time we'll ever see this is for the connect by IP typefield.
// Draw the small GO button here (and the text which is a separate graphic)
@ -3167,12 +3343,20 @@ void M_DrawGenericOptions(void)
case IT_CV_INVISSLIDER: // monitor toggles use this
break;
case IT_CV_STRING:
M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1);
V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, cv->string);
if (skullAnimCounter < 4 && i == itemOn)
V_DrawCharacter(x + 8 + V_StringWidth(cv->string, 0), y + 12,
'_' | 0x80, false);
y += 16;
{
M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1);
INT32 xoffs = 0;
if (itemOn == i)
{
xoffs += 8;
V_DrawString(x + (skullAnimCounter/5) + 6, y + 12, highlightflags, "\x1D");
}
V_DrawString(x + xoffs + 8, y + 12, V_ALLOWLOWERCASE, cv->string);
y += 16;
}
break;
default:
w = V_StringWidth(cv->string, 0);
@ -3912,8 +4096,6 @@ void M_DrawExtras(void)
// INGAME / PAUSE MENUS
//
// PAUSE
// PAUSE MAIN MENU
void M_DrawPause(void)
{
@ -3934,18 +4116,17 @@ void M_DrawPause(void)
INT16 word2len = 0;
boolean sok = false;
patch_t *pausebg = W_CachePatchName("M_STRIPU", PU_CACHE);
patch_t *vertbg = W_CachePatchName("M_STRIPV", PU_CACHE);
patch_t *pausetext = W_CachePatchName("M_PAUSET", PU_CACHE);
patch_t *arrstart = W_CachePatchName("M_PTIP", PU_CACHE);
patch_t *arrfill = W_CachePatchName("M_PFILL", PU_CACHE);
//V_DrawFadeScreen(0xFF00, 16);
// "PAUSED"
V_DrawFixedPatch(-offset*FRACUNIT, 0, FRACUNIT, V_ADD, pausebg, NULL);
V_DrawFixedPatch(-offset*FRACUNIT, 0, FRACUNIT, 0, pausetext, NULL);
if (!paused && !demo.playback && !modeattacking && !netgame) // as close to possible as P_AutoPause, but not dependent on menuactive
{
M_DrawPausedText(-offset*FRACUNIT);
}
// Vertical Strip:
V_DrawFixedPatch((230 + offset)<<FRACBITS, 0, FRACUNIT, V_ADD, vertbg, NULL);
@ -4081,7 +4262,7 @@ void M_DrawPause(void)
V_DrawCenteredLSTitleLowString(220 + offset*2, 103, 0, word2);
}
if (gamestate != GS_INTERMISSION)
if (gamestate != GS_INTERMISSION && roundqueue.size > 0)
{
y_data_t standings;
memset(&standings, 0, sizeof (standings));
@ -4105,7 +4286,57 @@ void M_DrawPause(void)
standings.showrank = true;
}
// Returns early if there's no roundqueue entries to draw
patch_t *smallroundpatch = NULL;
if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE)
{
const char *append = NULL;
switch (grandprixinfo.eventmode)
{
case GPEVENT_SPECIAL:
{
append = "SS";
break;
}
case GPEVENT_BONUS:
{
append = "B";
break;
}
default:
break;
}
if (append)
{
smallroundpatch =
W_CachePatchName(
va("TT_RNS%s", append),
PU_PATCH
);
}
}
else if (roundqueue.roundnum > 0 && roundqueue.roundnum <= 10)
{
smallroundpatch =
W_CachePatchName(
va("TT_RNS%d", roundqueue.roundnum),
PU_PATCH
);
}
if (smallroundpatch != NULL)
{
V_DrawMappedPatch(
24, 152,
0,
smallroundpatch,
NULL);
}
Y_RoundQueueDrawer(&standings, false, false);
}
}

View file

@ -223,7 +223,7 @@ static boolean M_GamestateCanOpenMenu(void)
//
boolean M_Responder(event_t *ev)
{
menuKey = -1;
boolean menuKeyJustChanged = false;
if (dedicated
|| (demo.playback && demo.title)
@ -255,10 +255,11 @@ boolean M_Responder(event_t *ev)
D_StartTitle();
}
if (ev->type == ev_keydown && ev->data1 < NUMKEYS)
if (ev->type == ev_keydown && ev->data1 > 0 && ev->data1 < NUMKEYS)
{
// Record keyboard presses
menuKey = ev->data1;
menuKeyJustChanged = true;
}
// Profiles: Control mapping.
@ -354,7 +355,7 @@ boolean M_Responder(event_t *ev)
}
// Typing for CV_IT_STRING
if (menutyping.active && !menutyping.menutypingclose && menutyping.keyboardtyping)
if (menuKeyJustChanged && menutyping.active && !menutyping.menutypingclose && menutyping.keyboardtyping)
{
M_ChangeStringCvar(menuKey);
}
@ -564,6 +565,9 @@ void M_StartControlPanel(void)
currentMenu->lastOn = 0;
CV_StealthSetValue(&cv_currprofile, -1); // Make sure to reset that as it is set by PR_ApplyProfile which we kind of hack together to force it.
// Ambient ocean sounds
S_ChangeMusicInternal("_OCEAN", true);
}
else
{
@ -571,9 +575,9 @@ void M_StartControlPanel(void)
restoreMenu = &MainDef;
currentMenu = M_SpecificMenuRestore(M_InterruptMenuWithChallenges(restoreMenu));
restoreMenu = NULL;
}
M_PlayMenuJam();
M_PlayMenuJam();
}
}
else
{
@ -737,6 +741,9 @@ void M_UpdateMenuCMD(UINT8 i)
{
UINT8 mp = max(1, setup_numplayers);
menucmd[i].prev_dpad_ud = menucmd[i].dpad_ud;
menucmd[i].prev_dpad_lr = menucmd[i].dpad_lr;
menucmd[i].dpad_ud = 0;
menucmd[i].dpad_lr = 0;
@ -830,6 +837,9 @@ static void M_HandleMenuInput(void)
void (*routine)(INT32 choice); // for some casting problem
UINT8 pid = 0; // todo: Add ability for any splitscreen player to bring up the menu.
SINT8 lr = 0, ud = 0;
INT32 thisMenuKey = menuKey;
menuKey = -1;
if (menuactive == false)
{
@ -846,7 +856,7 @@ static void M_HandleMenuInput(void)
// Typing for CV_IT_STRING
if (menutyping.active)
{
M_MenuTypingInput(menuKey);
M_MenuTypingInput(thisMenuKey);
return;
}
@ -858,7 +868,7 @@ static void M_HandleMenuInput(void)
// Handle menu-specific input handling. If this returns true, we skip regular input handling.
if (currentMenu->inputroutine)
{
if (currentMenu->inputroutine(menuKey))
if (currentMenu->inputroutine(thisMenuKey))
{
return;
}
@ -884,7 +894,7 @@ static void M_HandleMenuInput(void)
// If we're hovering over a IT_CV_STRING option, pressing A/X opens the typing submenu
if (M_MenuConfirmPressed(pid))
{
menutyping.keyboardtyping = menuKey != 0 ? true : false; // If we entered this menu by pressing a menu Key, default to keyboard typing, otherwise use controller.
menutyping.keyboardtyping = thisMenuKey != -1 ? true : false; // If we entered this menu by pressing a menu Key, default to keyboard typing, otherwise use controller.
menutyping.active = true;
menutyping.menutypingclose = false;
return;

View file

@ -10,7 +10,7 @@
menuitem_t MISC_AddonsMenu[] =
{
{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, NULL,
{IT_STRING | IT_CVAR | IT_CV_STRING, "Search for add-ons", "Provide a full or partial name to filter available files by.",
NULL, {.cvar = &cv_dummyaddonsearch}, 0, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, NULL,
NULL, {.routine = M_HandleAddons}, 0, 0}, // dummy menuitem for the control func

View file

@ -21,7 +21,7 @@ menu_t MISC_ChallengesDef = {
BASEVIDWIDTH/2, 30,
0, 0,
0,
"EXTRAS",
"UNLOCK",
98, 0,
M_DrawChallenges,
M_ChallengesTick,

View file

@ -16,7 +16,7 @@ menu_t MAIN_ProfilesDef = {
32, 80,
SKINCOLOR_ULTRAMARINE, 0,
0,
NULL,
"FILE",
2, 5,
M_DrawProfileSelect,
M_OptionsTick,

View file

@ -18,7 +18,7 @@ menu_t OPTIONS_ProfilesDef = {
32, 80,
SKINCOLOR_ULTRAMARINE, 0,
0,
NULL,
"FILE",
2, 5,
M_DrawProfileSelect,
M_OptionsTick,

View file

@ -30,7 +30,7 @@ menu_t OPTIONS_EditProfileDef = {
32, 80,
SKINCOLOR_ULTRAMARINE, 0,
0,
NULL,
"FILE",
2, 5,
M_DrawEditProfile,
M_HandleProfileEdit,

View file

@ -109,7 +109,7 @@ menu_t OPTIONS_ProfileControlsDef = {
32, 80,
SKINCOLOR_ULTRAMARINE, 0,
0,
NULL,
"FILE",
3, 5,
M_DrawProfileControls,
M_HandleProfileControls,

View file

@ -497,6 +497,7 @@ void M_CharacterSelectInit(void)
void M_CharacterSelect(INT32 choice)
{
(void)choice;
PLAY_CharSelectDef.music = currentMenu->music;
PLAY_CharSelectDef.prevMenu = currentMenu;
M_SetupNextMenu(&PLAY_CharSelectDef, false);
}

View file

@ -3,56 +3,151 @@
#include "../../k_menu.h"
#include "../../s_sound.h"
#include "../../hu_stuff.h" // shiftxform
#include "../../console.h" // CON_ShiftChar
#include "../../i_system.h" // I_Clipboard funcs
// Typing "sub"-menu
struct menutyping_s menutyping;
// keyboard layouts
INT16 virtualKeyboard[5][13] = {
INT16 virtualKeyboard[5][NUMVIRTUALKEYSINROW] = {
{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0},
{'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0},
{'a', 's', 'd', 'f', 'g', 'h', 'i', 'j', 'k', 'l', ';', '\'', '\\'},
{'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0},
{KEY_SPACE, KEY_RSHIFT, KEY_BACKSPACE, KEY_CAPSLOCK, KEY_ENTER, 0, 0, 0, 0, 0, 0, 0, 0}
{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', KEY_BACKSPACE, 1},
{'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', '='},
{'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '/', '[', ']'},
{'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '\\', ';', '\''},
{KEY_RSHIFT, 1, 1, KEY_SPACE, 1, 1, 1, 1, KEY_ENTER, 1, 1, 1}
};
INT16 shift_virtualKeyboard[5][13] = {
INT16 shift_virtualKeyboard[5][NUMVIRTUALKEYSINROW] = {
{'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0},
{'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0},
{'A', 'S', 'D', 'F', 'G', 'H', 'I', 'J', 'K', 'L', ':', '\"', '|'},
{'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 0, 0},
{KEY_SPACE, KEY_RSHIFT, KEY_BACKSPACE, KEY_CAPSLOCK, KEY_ENTER, 0, 0, 0, 0, 0, 0, 0, 0}
{'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', KEY_BACKSPACE, 1},
{'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '_', '+'},
{'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', '?', '{', '}'},
{'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '|', ':', '\"'},
{KEY_RSHIFT, 1, 1, KEY_SPACE, 1, 1, 1, 1, KEY_ENTER, 1, 1, 1}
};
typedef enum
{
CVCPM_NONE,
CVCPM_COPY,
CVCPM_CUT,
CVCPM_PASTE
} cvarcopypastemode_t;
boolean M_ChangeStringCvar(INT32 choice)
{
consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar;
char buf[MAXSTRINGLENGTH];
size_t len;
cvarcopypastemode_t copypastemode = CVCPM_NONE;
if (shiftdown && choice >= 32 && choice <= 127)
choice = shiftxform[choice];
if (menutyping.keyboardtyping == true)
{
// We can only use global modifiers in key mode.
if (ctrldown)
{
if (choice == 'c' || choice == 'C' || choice == KEY_INS)
{
// ctrl+c, ctrl+insert, copying
copypastemode = CVCPM_COPY;
}
else if (choice == 'x' || choice == 'X')
{
// ctrl+x, cutting
copypastemode = CVCPM_CUT;
}
else if (choice == 'v' || choice == 'V')
{
// ctrl+v, pasting
copypastemode = CVCPM_PASTE;
}
else
{
// not a known ctrl code
return false;
}
}
else if (shiftdown)
{
if (choice == KEY_INS)
{
// shift+insert, pasting
copypastemode = CVCPM_PASTE;
}
else if (choice == KEY_DEL)
{
// shift+delete, cutting
copypastemode = CVCPM_CUT;
}
}
if (copypastemode != CVCPM_NONE)
{
len = strlen(cv->string);
if (copypastemode == CVCPM_PASTE)
{
const char *paste = I_ClipboardPaste();
if (paste == NULL || paste[0] == '\0')
;
else if (len < MAXSTRINGLENGTH - 1)
{
M_Memcpy(buf, cv->string, len);
buf[len] = 0;
strncat(buf, paste, (MAXSTRINGLENGTH - 1) - len);
CV_Set(cv, buf);
S_StartSound(NULL, sfx_s3k5b); // Tails
}
}
else if (len > 0 /*&& (copypastemode == CVCPM_COPY
|| copypastemode == CVCPM_CUT)*/
)
{
I_ClipboardCopy(cv->string, len);
if (copypastemode == CVCPM_CUT)
{
// A cut should wipe.
CV_Set(cv, "");
}
S_StartSound(NULL, sfx_s3k5b); // Tails
}
return true;
}
// Okay, now we can auto-modify the character.
choice = CON_ShiftChar(choice);
}
switch (choice)
{
case KEY_BACKSPACE:
len = strlen(cv->string);
if (len > 0)
if (cv->string[0])
{
S_StartSound(NULL, sfx_s3k5b); // Tails
len = strlen(cv->string);
M_Memcpy(buf, cv->string, len);
buf[len-1] = 0;
CV_Set(cv, buf);
S_StartSound(NULL, sfx_s3k5b); // Tails
}
return true;
case KEY_DEL:
if (cv->string[0])
{
S_StartSound(NULL, sfx_s3k5b); // Tails
CV_Set(cv, "");
S_StartSound(NULL, sfx_s3k5b); // Tails
}
return true;
default:
@ -61,11 +156,14 @@ boolean M_ChangeStringCvar(INT32 choice)
len = strlen(cv->string);
if (len < MAXSTRINGLENGTH - 1)
{
S_StartSound(NULL, sfx_s3k5b); // Tails
M_Memcpy(buf, cv->string, len);
buf[len++] = (char)choice;
buf[len] = 0;
CV_Set(cv, buf);
S_StartSound(NULL, sfx_s3k5b); // Tails
}
return true;
}
@ -75,42 +173,64 @@ boolean M_ChangeStringCvar(INT32 choice)
return false;
}
// Updates the x coordinate of the keybord so prevent it from going in weird places
static void M_UpdateKeyboardX(void)
static void M_ToggleVirtualShift(void)
{
// 0s are only at the rightmost edges of the keyboard table, so just go backwards until we get something.
while (!virtualKeyboard[menutyping.keyboardy][menutyping.keyboardx])
menutyping.keyboardx--;
if (menutyping.keyboardcapslock == true)
{
menutyping.keyboardcapslock = false;
}
else
{
menutyping.keyboardshift ^= true;
if (menutyping.keyboardshift == false)
{
menutyping.keyboardcapslock = true;
}
}
}
static boolean M_IsTypingKey(INT32 key)
{
return key == KEY_BACKSPACE || key == KEY_ENTER ||
key == KEY_ESCAPE || key == KEY_DEL || isprint(key);
return key == KEY_BACKSPACE || key == KEY_ENTER
|| key == KEY_ESCAPE || key == KEY_DEL
|| key == KEY_LCTRL || key == KEY_RCTRL
|| isprint(key);
}
void M_MenuTypingInput(INT32 key)
{
const UINT8 pid = 0;
// Fade-in
if (menutyping.menutypingclose) // closing
if (menutyping.menutypingclose)
{
// Closing
menutyping.menutypingfade--;
if (!menutyping.menutypingfade)
menutyping.active = false;
return; // prevent inputs while closing the menu.
}
else // opening
else
{
menutyping.menutypingfade++;
if (menutyping.menutypingfade > 9) // Don't fade all the way, but have it VERY strong to be readable
menutyping.menutypingfade = 9;
else if (menutyping.menutypingfade < 9)
return; // Don't allow typing until it's fully opened.
// Opening
const UINT8 destination = (menutyping.keyboardtyping ? 9 : 18);
if (menutyping.menutypingfade > destination)
{
menutyping.menutypingfade--;
}
else if (menutyping.menutypingfade < destination)
{
menutyping.menutypingfade++;
}
if (menutyping.menutypingfade != destination)
{
// Don't allow typing until it's fully opened.
return;
}
}
// Determine when to check for keyboard inputs or controller inputs using menuKey, which is the key passed here as argument.
@ -123,7 +243,8 @@ void M_MenuTypingInput(INT32 key)
&& !(menucmd[pid].buttons & MBT_C)
&& !(menucmd[pid].buttons & MBT_X)
&& !(menucmd[pid].buttons & MBT_Y)
&& !(menucmd[pid].buttons & MBT_Z))
&& !(menucmd[pid].buttons & MBT_Z)
&& !(menucmd[pid].buttons & MBT_START))
{
menutyping.keyboardtyping = true;
}
@ -138,10 +259,26 @@ void M_MenuTypingInput(INT32 key)
|| M_MenuButtonPressed(pid, MBT_X)
|| M_MenuButtonPressed(pid, MBT_Y)
|| M_MenuButtonPressed(pid, MBT_Z)
|| menucmd[pid].dpad_lr != 0
|| menucmd[pid].dpad_ud != 0
|| M_MenuButtonPressed(pid, MBT_START)
|| (menucmd[pid].dpad_lr != 0 && menucmd[pid].prev_dpad_lr == 0)
|| (menucmd[pid].dpad_ud != 0 && menucmd[pid].prev_dpad_ud != 0)
))
{
/*CONS_Printf("key is %d, \
%c%c%c-%c%c%c-%c-%c%c%c%c\n",
key,
M_MenuButtonPressed(pid, MBT_A) ? 'A' : ' ',
M_MenuButtonPressed(pid, MBT_B) ? 'B' : ' ',
M_MenuButtonPressed(pid, MBT_C) ? 'C' : ' ',
M_MenuButtonPressed(pid, MBT_X) ? 'X' : ' ',
M_MenuButtonPressed(pid, MBT_Y) ? 'Y' : ' ',
M_MenuButtonPressed(pid, MBT_Z) ? 'Z' : ' ',
M_MenuButtonPressed(pid, MBT_START) ? '+' : ' ',
menucmd[pid].dpad_lr < 0 ? '<' : ' ',
menucmd[pid].dpad_ud > 0 ? '^' : ' ',
menucmd[pid].dpad_ud < 0 ? 'v' : ' ',
menucmd[pid].dpad_lr > 0 ? '>' : ' '
);*/
menutyping.keyboardtyping = false;
return;
}
@ -150,9 +287,12 @@ void M_MenuTypingInput(INT32 key)
if (key == KEY_ENTER || key == KEY_ESCAPE)
{
menutyping.menutypingclose = true; // close menu.
M_SetMenuDelay(pid);
S_StartSound(NULL, sfx_s3k5b);
return;
}
}
if (menucmd[pid].delay == 0 && !menutyping.keyboardtyping) // We must check for this here because we bypass the normal delay check to allow for normal keyboard inputs
@ -163,7 +303,6 @@ void M_MenuTypingInput(INT32 key)
if (menutyping.keyboardy > 4)
menutyping.keyboardy = 0;
M_UpdateKeyboardX();
M_SetMenuDelay(pid);
S_StartSound(NULL, sfx_s3k5b);
}
@ -173,54 +312,101 @@ void M_MenuTypingInput(INT32 key)
if (menutyping.keyboardy < 0)
menutyping.keyboardy = 4;
M_UpdateKeyboardX();
M_SetMenuDelay(pid);
S_StartSound(NULL, sfx_s3k5b);
}
else if (menucmd[pid].dpad_lr > 0) // right
{
menutyping.keyboardx++;
if (!virtualKeyboard[menutyping.keyboardy][menutyping.keyboardx])
menutyping.keyboardx = 0;
do
{
menutyping.keyboardx++;
if (menutyping.keyboardx > NUMVIRTUALKEYSINROW-1)
{
menutyping.keyboardx = 0;
break;
}
}
while (virtualKeyboard[menutyping.keyboardy][menutyping.keyboardx] == 1);
M_SetMenuDelay(pid);
S_StartSound(NULL, sfx_s3k5b);
}
else if (menucmd[pid].dpad_lr < 0) // left
{
while (virtualKeyboard[menutyping.keyboardy][menutyping.keyboardx] == 1)
{
menutyping.keyboardx--;
if (menutyping.keyboardx < 0)
{
menutyping.keyboardx = NUMVIRTUALKEYSINROW-1;
break;
}
}
menutyping.keyboardx--;
if (menutyping.keyboardx < 0)
{
menutyping.keyboardx = 12;
M_UpdateKeyboardX();
menutyping.keyboardx = NUMVIRTUALKEYSINROW-1;
}
M_SetMenuDelay(pid);
S_StartSound(NULL, sfx_s3k5b);
}
else if (M_MenuButtonPressed(pid, MBT_START))
{
// Shortcut for close menu.
menutyping.menutypingclose = true;
M_SetMenuDelay(pid);
S_StartSound(NULL, sfx_s3k5b);
}
else if (M_MenuBackPressed(pid))
{
// Shortcut for backspace.
M_ChangeStringCvar(KEY_BACKSPACE);
M_SetMenuDelay(pid);
S_StartSound(NULL, sfx_s3k5b);
}
else if (M_MenuExtraPressed(pid))
{
// Shortcut for shift/caps lock.
M_ToggleVirtualShift();
M_SetMenuDelay(pid);
S_StartSound(NULL, sfx_s3k5b);
}
else if (M_MenuConfirmPressed(pid))
{
// Add the character. First though, check what we're pressing....
INT16 c = virtualKeyboard[menutyping.keyboardy][menutyping.keyboardx];
if (menutyping.keyboardshift ^ menutyping.keyboardcapslock)
c = shift_virtualKeyboard[menutyping.keyboardy][menutyping.keyboardx];
INT32 tempkeyboardx = menutyping.keyboardx;
INT16 c = 0;
while ((c = virtualKeyboard[menutyping.keyboardy][tempkeyboardx]) == 1
&& tempkeyboardx > 0)
tempkeyboardx--;
if (c == KEY_RSHIFT)
menutyping.keyboardshift = !menutyping.keyboardshift;
else if (c == KEY_CAPSLOCK)
menutyping.keyboardcapslock = !menutyping.keyboardcapslock;
else if (c == KEY_ENTER)
if (c > 1)
{
menutyping.menutypingclose = true; // close menu.
return;
}
else
{
M_ChangeStringCvar((INT32)c); // Write!
menutyping.keyboardshift = false; // undo shift if it had been pressed
}
if (menutyping.keyboardshift ^ menutyping.keyboardcapslock)
c = shift_virtualKeyboard[menutyping.keyboardy][tempkeyboardx];
M_SetMenuDelay(pid);
S_StartSound(NULL, sfx_s3k5b);
if (c == KEY_RSHIFT)
{
M_ToggleVirtualShift();
}
else if (c == KEY_ENTER)
{
menutyping.menutypingclose = true; // close menu.
}
else
{
M_ChangeStringCvar((INT32)c); // Write!
menutyping.keyboardshift = false; // undo shift if it had been pressed
}
M_SetMenuDelay(pid);
S_StartSound(NULL, sfx_s3k5b);
}
}
}
}

View file

@ -436,7 +436,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
INT32 heightcount = (standings->numplayers - 1);
INT32 x, y;
INT32 x2, returny;
INT32 x2, returny, inwardshim = 0;
boolean verticalresults = (standings->numplayers < 4);
boolean datarightofcolumn = false;
@ -446,23 +446,29 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
patch_t *resbar = W_CachePatchName("R_RESBAR", PU_PATCH); // Results bars for players
if (drawping || data.rankingsmode != 0)
{
inwardshim = 8;
}
if (verticalresults)
{
x = (BASEVIDWIDTH/2) - 61;
if (drawping)
{
x += 9;
}
}
else
{
x = 29;
inwardshim /= 2;
heightcount /= 2;
}
x += xoffset;
x2 = x - 9;
x += xoffset + inwardshim;
x2 = x;
if (drawping)
{
x2 -= 9;
}
if (standings->numplayers > 10)
{
@ -595,6 +601,39 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
);
}
}
else if (data.rankingsmode != 0)
{
char *increasenum = NULL;
if (data.increase[pnum] != INT16_MIN)
{
increasenum = va(
"(%d)",
data.increase[pnum]
);
}
if (increasenum)
{
if (datarightofcolumn)
{
V_DrawThinString(
x2, y-2,
V_ALLOWLOWERCASE|V_6WIDTHSPACE,
increasenum
);
}
else
{
V_DrawRightAlignedThinString(
x2, y-2,
V_ALLOWLOWERCASE|V_6WIDTHSPACE,
increasenum
);
}
}
}
// Reverse the jitter offset
if (standings->jitter[pnum] > 0)
@ -605,7 +644,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
if (verticalresults == false && i == (standings->numplayers-1)/2)
{
x = 169 + xoffset;
x = 169 + xoffset - inwardshim;
y = returny;
datarightofcolumn = true;