diff --git a/src/console.c b/src/console.c index 6571b9f2a..42b2e85b4 100644 --- a/src/console.c +++ b/src/console.c @@ -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) diff --git a/src/d_main.c b/src/d_main.c index 1d07c9298..1b562b238 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -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); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index fa366bd36..48725247e 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -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]); diff --git a/src/k_menu.h b/src/k_menu.h index 8eaf787a8..d461973b4 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -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) }; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index ecb85d279..8c99f5e31 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -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)<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)<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)< 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); } } diff --git a/src/k_menufunc.c b/src/k_menufunc.c index e467ba3b4..32c51d092 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -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; diff --git a/src/menus/extras-addons.c b/src/menus/extras-addons.c index 868ba4cd4..e3cbf192b 100644 --- a/src/menus/extras-addons.c +++ b/src/menus/extras-addons.c @@ -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 diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index 93c0f3ffe..c7d6674e1 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -21,7 +21,7 @@ menu_t MISC_ChallengesDef = { BASEVIDWIDTH/2, 30, 0, 0, 0, - "EXTRAS", + "UNLOCK", 98, 0, M_DrawChallenges, M_ChallengesTick, diff --git a/src/menus/main-profile-select.c b/src/menus/main-profile-select.c index 13b840f9a..eb0fdee53 100644 --- a/src/menus/main-profile-select.c +++ b/src/menus/main-profile-select.c @@ -16,7 +16,7 @@ menu_t MAIN_ProfilesDef = { 32, 80, SKINCOLOR_ULTRAMARINE, 0, 0, - NULL, + "FILE", 2, 5, M_DrawProfileSelect, M_OptionsTick, diff --git a/src/menus/options-profiles-1.c b/src/menus/options-profiles-1.c index 311788bb1..c43aba4fc 100644 --- a/src/menus/options-profiles-1.c +++ b/src/menus/options-profiles-1.c @@ -18,7 +18,7 @@ menu_t OPTIONS_ProfilesDef = { 32, 80, SKINCOLOR_ULTRAMARINE, 0, 0, - NULL, + "FILE", 2, 5, M_DrawProfileSelect, M_OptionsTick, diff --git a/src/menus/options-profiles-edit-1.c b/src/menus/options-profiles-edit-1.c index b1ed78f98..22375da93 100644 --- a/src/menus/options-profiles-edit-1.c +++ b/src/menus/options-profiles-edit-1.c @@ -30,7 +30,7 @@ menu_t OPTIONS_EditProfileDef = { 32, 80, SKINCOLOR_ULTRAMARINE, 0, 0, - NULL, + "FILE", 2, 5, M_DrawEditProfile, M_HandleProfileEdit, diff --git a/src/menus/options-profiles-edit-controls.c b/src/menus/options-profiles-edit-controls.c index b97b7f5b7..0140a89d4 100644 --- a/src/menus/options-profiles-edit-controls.c +++ b/src/menus/options-profiles-edit-controls.c @@ -109,7 +109,7 @@ menu_t OPTIONS_ProfileControlsDef = { 32, 80, SKINCOLOR_ULTRAMARINE, 0, 0, - NULL, + "FILE", 3, 5, M_DrawProfileControls, M_HandleProfileControls, diff --git a/src/menus/play-char-select.c b/src/menus/play-char-select.c index 35e918a65..c21990ba4 100644 --- a/src/menus/play-char-select.c +++ b/src/menus/play-char-select.c @@ -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); } diff --git a/src/menus/transient/virtual-keyboard.c b/src/menus/transient/virtual-keyboard.c index 3211538a3..d09480014 100644 --- a/src/menus/transient/virtual-keyboard.c +++ b/src/menus/transient/virtual-keyboard.c @@ -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); + } } } } diff --git a/src/y_inter.c b/src/y_inter.c index f35dc9419..70ae5e7fb 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -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;