From f270ac5579c6e3ba4cb441c82dd8db47219f872e Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 19:41:42 -0800 Subject: [PATCH 1/9] Virtual Keyboard: use callback function to get/set cvar string --- src/k_menu.h | 4 +++- src/k_menufunc.c | 11 ++++++++++- src/menus/transient/virtual-keyboard.c | 7 ++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 049559ce4..dc5b5d095 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -542,6 +542,7 @@ extern INT32 menuKey; // keyboard key pressed for menu extern INT16 virtualKeyboard[5][NUMVIRTUALKEYSINROW]; extern INT16 shift_virtualKeyboard[5][NUMVIRTUALKEYSINROW]; +typedef const char *(*vkb_query_fn_t)(const char *replace); extern struct menutyping_s { boolean active; // Active @@ -554,6 +555,7 @@ extern struct menutyping_s boolean keyboardcapslock; boolean keyboardshift; + vkb_query_fn_t queryfn; // callback on open and close char cache[MAXSTRINGLENGTH]; // cached string } menutyping; @@ -682,7 +684,7 @@ void M_PlayMenuJam(void); boolean M_ConsiderSealedSwapAlert(void); -void M_OpenVirtualKeyboard(boolean gamepad); +void M_OpenVirtualKeyboard(boolean gamepad, vkb_query_fn_t queryfn); void M_MenuTypingInput(INT32 key); void M_QuitResponse(INT32 ch); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 7833da1e3..aa3c3b674 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -188,6 +188,14 @@ static void M_ChangeCvar(INT32 choice) M_ChangeCvarDirect(choice, currentMenu->menuitems[itemOn].itemaction.cvar); } +static const char *M_QueryCvarAction(const char *replace) +{ + consvar_t *cvar = currentMenu->menuitems[itemOn].itemaction.cvar; + if (replace) + CV_Set(cvar, replace); + return cvar->string; +} + boolean M_NextOpt(void) { INT16 oldItemOn = itemOn; // prevent infinite loop @@ -1124,7 +1132,8 @@ 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)) { - M_OpenVirtualKeyboard(thisMenuKey == -1); // If we entered this menu by pressing a menu Key, default to keyboard typing, otherwise use controller. + // If we entered this menu by pressing a menu Key, default to keyboard typing, otherwise use controller. + M_OpenVirtualKeyboard(thisMenuKey == -1, M_QueryCvarAction); return; } else if (M_MenuExtraPressed(pid)) diff --git a/src/menus/transient/virtual-keyboard.c b/src/menus/transient/virtual-keyboard.c index 81afaed8e..6722e48ca 100644 --- a/src/menus/transient/virtual-keyboard.c +++ b/src/menus/transient/virtual-keyboard.c @@ -180,7 +180,7 @@ static void M_ToggleVirtualShift(void) static void M_CloseVirtualKeyboard(void) { menutyping.menutypingclose = true; // close menu. - CV_Set(currentMenu->menuitems[itemOn].itemaction.cvar, menutyping.cache); + menutyping.queryfn(menutyping.cache); } static boolean M_IsTypingKey(INT32 key) @@ -405,11 +405,12 @@ void M_MenuTypingInput(INT32 key) } } -void M_OpenVirtualKeyboard(boolean gamepad) +void M_OpenVirtualKeyboard(boolean gamepad, vkb_query_fn_t queryfn) { menutyping.keyboardtyping = !gamepad; menutyping.active = true; menutyping.menutypingclose = false; - strlcpy(menutyping.cache, currentMenu->menuitems[itemOn].itemaction.cvar->string, MAXSTRINGLENGTH); + menutyping.queryfn = queryfn; + strlcpy(menutyping.cache, queryfn(NULL), MAXSTRINGLENGTH); } From 7d01c3046b1e81d224ae319e6d71f9eaec54b80a Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 21:22:56 -0800 Subject: [PATCH 2/9] M_OpenVirtualKeyboard: add optional dummymenu argument - Virtual Keyboard can switch to a temporary menu while typing - It will switch back to the previous menu after it's closed - This functionality can be used even if the menu isn't already open - It will close the menu and return to gameplay when the Virtual Keyboard is closed --- src/k_menu.h | 4 +++- src/k_menufunc.c | 4 ++-- src/menus/transient/virtual-keyboard.c | 28 ++++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index dc5b5d095..fdc7c2c88 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -556,6 +556,7 @@ extern struct menutyping_s boolean keyboardshift; vkb_query_fn_t queryfn; // callback on open and close + menu_t *dummymenu; char cache[MAXSTRINGLENGTH]; // cached string } menutyping; @@ -684,7 +685,8 @@ void M_PlayMenuJam(void); boolean M_ConsiderSealedSwapAlert(void); -void M_OpenVirtualKeyboard(boolean gamepad, vkb_query_fn_t queryfn); +void M_OpenVirtualKeyboard(boolean gamepad, vkb_query_fn_t queryfn, menu_t *dummymenu); +void M_AbortVirtualKeyboard(void); void M_MenuTypingInput(INT32 key); void M_QuitResponse(INT32 ch); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index aa3c3b674..e7507aec3 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -839,7 +839,7 @@ void M_ClearMenus(boolean callexitmenufunc) D_StartTitle(); } - menutyping.active = false; + M_AbortVirtualKeyboard(); menumessage.active = false; menuactive = false; @@ -1133,7 +1133,7 @@ static void M_HandleMenuInput(void) if (M_MenuConfirmPressed(pid)) { // If we entered this menu by pressing a menu Key, default to keyboard typing, otherwise use controller. - M_OpenVirtualKeyboard(thisMenuKey == -1, M_QueryCvarAction); + M_OpenVirtualKeyboard(thisMenuKey == -1, M_QueryCvarAction, NULL); return; } else if (M_MenuExtraPressed(pid)) diff --git a/src/menus/transient/virtual-keyboard.c b/src/menus/transient/virtual-keyboard.c index 6722e48ca..15e0e9485 100644 --- a/src/menus/transient/virtual-keyboard.c +++ b/src/menus/transient/virtual-keyboard.c @@ -183,6 +183,16 @@ static void M_CloseVirtualKeyboard(void) menutyping.queryfn(menutyping.cache); } +void M_AbortVirtualKeyboard(void) +{ + if (!menutyping.active) + return; + + menutyping.active = false; + if (currentMenu == menutyping.dummymenu) + M_GoBack(0); +} + static boolean M_IsTypingKey(INT32 key) { return key == KEY_BACKSPACE || key == KEY_ENTER @@ -202,7 +212,7 @@ void M_MenuTypingInput(INT32 key) // Closing menutyping.menutypingfade--; if (!menutyping.menutypingfade) - menutyping.active = false; + M_AbortVirtualKeyboard(); return; // prevent inputs while closing the menu. } @@ -405,12 +415,26 @@ void M_MenuTypingInput(INT32 key) } } -void M_OpenVirtualKeyboard(boolean gamepad, vkb_query_fn_t queryfn) +void M_OpenVirtualKeyboard(boolean gamepad, vkb_query_fn_t queryfn, menu_t *dummymenu) { menutyping.keyboardtyping = !gamepad; menutyping.active = true; menutyping.menutypingclose = false; menutyping.queryfn = queryfn; + menutyping.dummymenu = dummymenu; strlcpy(menutyping.cache, queryfn(NULL), MAXSTRINGLENGTH); + + if (dummymenu) + { + if (!menuactive) + { + M_StartControlPanel(); + dummymenu->prevMenu = NULL; + } + else + dummymenu->prevMenu = currentMenu; + + M_SetupNextMenu(dummymenu, true); + } } From 8fa01ee558a05f9e35f8e68abbb679f6e11d84fb Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 21:30:32 -0800 Subject: [PATCH 3/9] Replays: use Virtual Keyboard for title entry - This shortens the maximum title length from 64 to 31 characters --- src/d_main.cpp | 6 ---- src/g_demo.cpp | 88 +++++++++++++++++++++---------------------------- src/g_demo.h | 3 -- src/st_stuff.c | 34 ------------------- src/st_stuff.h | 3 -- src/y_inter.cpp | 4 --- 6 files changed, 38 insertions(+), 100 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 793c14013..19fd9c1db 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -278,12 +278,6 @@ void D_ProcessEvents(void) HandleGamepadDeviceEvents(ev); - if (demo.savemode == demovars_s::DSM_TITLEENTRY) - { - if (G_DemoTitleResponder(ev)) - continue; - } - // console input #ifdef HAVE_THREADS I_lock_mutex(&con_mutex); diff --git a/src/g_demo.cpp b/src/g_demo.cpp index eac0b1989..71cef6e81 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -65,6 +65,30 @@ #include "k_credits.h" #include "k_grandprix.h" +static menuitem_t TitleEntry[] = +{ + {IT_NOTHING | IT_SPACE, "Save Replay", NULL, + NULL, {NULL}, 0, 0}, +}; + +static menu_t TitleEntryDef = { + sizeof (TitleEntry) / sizeof (menuitem_t), + NULL, + 0, + TitleEntry, + 0, 0, + 0, 0, + MBF_SOUNDLESS, + NULL, + 0, 0, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + boolean nodrawers; // for comparative timing purposes boolean noblit; // for comparative timing purposes tic_t demostarttime; // for comparative timing purposes @@ -3992,6 +4016,9 @@ void G_SaveDemo(void) UINT8 i; #endif + if (currentMenu == &TitleEntryDef) + M_ClearMenus(true); + // Ensure extrainfo pointer is always available, even if no info is present. if (demoinfo_p && *(UINT32 *)demoinfo_p == 0) { @@ -4076,55 +4103,6 @@ void G_SaveDemo(void) } } -boolean G_DemoTitleResponder(event_t *ev) -{ - size_t len; - INT32 ch; - - if (ev->type != ev_keydown) - return false; - - ch = (INT32)ev->data1; - - // Only ESC and non-keyboard keys abort connection - if (ch == KEY_ESCAPE) - { - demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? demovars_s::DSM_WILLAUTOSAVE : demovars_s::DSM_NOTSAVING; - return true; - } - - if (ch == KEY_ENTER || ch >= NUMKEYS) - { - demo.savemode = demovars_s::DSM_WILLSAVE; - return true; - } - - if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && fontv[HU_FONT].font[ch-HU_FONTSTART]) - || ch == ' ') // Allow spaces, of course - { - len = strlen(demo.titlename); - if (len < 64) - { - demo.titlename[len+1] = 0; - demo.titlename[len] = CON_ShiftChar(ch); - } - } - else if (ch == KEY_BACKSPACE) - { - if (shiftdown) - memset(demo.titlename, 0, sizeof(demo.titlename)); - else - { - len = strlen(demo.titlename); - - if (len > 0) - demo.titlename[len-1] = 0; - } - } - - return true; -} - boolean G_CheckDemoTitleEntry(void) { if (menuactive || chat_on) @@ -4133,7 +4111,17 @@ boolean G_CheckDemoTitleEntry(void) if (!G_PlayerInputDown(0, gc_b, 0) && !G_PlayerInputDown(0, gc_x, 0)) return false; - demo.savemode = demovars_s::DSM_TITLEENTRY; + demo.savemode = demovars_s::DSM_WILLSAVE; + M_OpenVirtualKeyboard( + false, + [](const char* replace) -> const char* + { + if (replace) + strlcpy(demo.titlename, replace, sizeof demo.titlename); + return demo.titlename; + }, + &TitleEntryDef + ); return true; } diff --git a/src/g_demo.h b/src/g_demo.h index 4e89b24ef..85b4d65f7 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -93,7 +93,6 @@ struct demovars_s { enum { DSM_NOTSAVING, DSM_WILLAUTOSAVE, - DSM_TITLEENTRY, DSM_WILLSAVE, DSM_SAVED } savemode; @@ -232,8 +231,6 @@ void G_DeferedPlayDemo(const char *demo); void G_SaveDemo(void); -boolean G_DemoTitleResponder(event_t *ev); - boolean G_CheckDemoTitleEntry(void); typedef enum diff --git a/src/st_stuff.c b/src/st_stuff.c index d65d19ea1..df86acbb8 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1303,36 +1303,6 @@ static void ST_overlayDrawer(void) K_DrawMidVote(); } -void ST_DrawDemoTitleEntry(void) -{ - static UINT8 anim = 0; - char *nametodraw; - - anim++; - anim %= 8; - - nametodraw = demo.titlename; - while (V_StringWidth(nametodraw, 0) > MAXSTRINGLENGTH*8 - 8) - nametodraw++; - -#define x (BASEVIDWIDTH/2 - 139) -#define y (BASEVIDHEIGHT/2) - M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1); - V_DrawString(x + 8, y + 12, 0, nametodraw); - if (anim < 4) - V_DrawCharacter(x + 8 + V_StringWidth(nametodraw, 0), y + 12, - '_' | 0x80, false); - - M_DrawTextBox(x + 30, y - 24, 26, 1); - V_DrawString(x + 38, y - 16, 0, "Enter the name of the replay."); - - M_DrawTextBox(x + 50, y + 20, 20, 1); - V_DrawThinString(x + 58, y + 28, 0, "Escape - Cancel"); - V_DrawRightAlignedThinString(x + 220, y + 28, 0, "Enter - Confirm"); -#undef x -#undef y -} - // MayonakaStatic: draw Midnight Channel's TV-like borders static void ST_MayonakaStatic(void) { @@ -1640,10 +1610,6 @@ void ST_Drawer(void) V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, flags|V_YELLOWMAP, "Replay will be saved."); break; - case DSM_TITLEENTRY: - ST_DrawDemoTitleEntry(); - break; - default: // Don't render anything break; } diff --git a/src/st_stuff.h b/src/st_stuff.h index a48eaf213..72289d652 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -33,9 +33,6 @@ extern "C" { // Called by main loop. void ST_Ticker(boolean run); -// Called when naming a replay. -void ST_DrawDemoTitleEntry(void); - #ifdef HAVE_DISCORDRPC // Called when you have Discord asks void ST_AskToJoinEnvelope(void); diff --git a/src/y_inter.cpp b/src/y_inter.cpp index 1822debde..545627e9f 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -1710,10 +1710,6 @@ finalcounter: V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, highlightflags, "Replay saved!"); break; - case demovars_s::DSM_TITLEENTRY: - ST_DrawDemoTitleEntry(); - break; - default: // Don't render any text here break; } From e05daf0f1163699d15eb8aa5bdb2b8627de26ffe Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 21:31:30 -0800 Subject: [PATCH 4/9] M_GoBack: do not play sound effect on MBF_SOUNDLESS menus --- src/k_menufunc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index e7507aec3..b5335a87c 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -926,6 +926,8 @@ void M_SetupNextMenu(menu_t *menudef, boolean notransition) void M_GoBack(INT32 choice) { + const INT16 behaviourflags = currentMenu->behaviourflags; + (void)choice; noFurtherInput = true; @@ -948,7 +950,8 @@ void M_GoBack(INT32 choice) else // No returning to the title screen. M_QuitSRB2(-1); - S_StartSound(NULL, sfx_s3k5b); + if (!(behaviourflags & MBF_SOUNDLESS)) + S_StartSound(NULL, sfx_s3k5b); } // From 153ffa471799366c0a272d42216a70aaae775a9d Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 21:33:08 -0800 Subject: [PATCH 5/9] Replays: do not save file at intermission start - Postpone saving until intermission ends --- src/y_inter.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/y_inter.cpp b/src/y_inter.cpp index 545627e9f..fe380119b 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -1756,9 +1756,6 @@ void Y_Ticker(void) replayprompttic++; G_CheckDemoTitleEntry(); } - - if (demo.savemode == demovars_s::DSM_WILLSAVE || demo.savemode == demovars_s::DSM_WILLAUTOSAVE) - G_SaveDemo(); } // Check for pause or menu up in single player From 983fb4c53c6b43f02254293d63771404cf591d83 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 21:38:55 -0800 Subject: [PATCH 6/9] Replays: merge HUD and intermission drawing functions for "Save replay" prompt --- src/st_stuff.c | 42 +++++++++++++++++++++++++----------------- src/st_stuff.h | 1 + src/y_inter.cpp | 21 +-------------------- 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index df86acbb8..b2a2bbc41 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1457,6 +1457,30 @@ void ST_DrawServerSplash(boolean timelimited) } } +void ST_DrawSaveReplayHint(INT32 flags) +{ + const char *text = ""; + switch (demo.savemode) + { + case DSM_NOTSAVING: + text = "\xAB" "or " "\xAE" "Save replay"; + break; + + case DSM_WILLAUTOSAVE: + text = "Replay will be saved. \xAB" "Change title"; + break; + + case DSM_WILLSAVE: + text = "Replay will be saved."; + break; + + case DSM_SAVED: + text = "Replay saved!"; + break; + } + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, flags|V_YELLOWMAP, text); +} + static fixed_t ST_CalculateFadeIn(player_t *player) { const tic_t length = TICRATE/4; @@ -1596,22 +1620,6 @@ void ST_Drawer(void) INT32 flags = V_SNAPTOTOP | V_SNAPTORIGHT | (Easing_Linear(min(t, fadeLength) * FRACUNIT / fadeLength, 9, 0) << V_ALPHASHIFT); - switch (demo.savemode) - { - case DSM_NOTSAVING: - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, flags|V_YELLOWMAP, "\xAB" "or " "\xAE" "Save replay"); - break; - - case DSM_WILLAUTOSAVE: - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, flags|V_YELLOWMAP, "Replay will be saved. \xAB" "Change title"); - break; - - case DSM_WILLSAVE: - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, flags|V_YELLOWMAP, "Replay will be saved."); - break; - - default: // Don't render anything - break; - } + ST_DrawSaveReplayHint(flags); } } diff --git a/src/st_stuff.h b/src/st_stuff.h index 72289d652..23eecb034 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -76,6 +76,7 @@ extern tic_t lt_exitticker, lt_endtime; extern tic_t lt_fade; void ST_DrawServerSplash(boolean timelimited); +void ST_DrawSaveReplayHint(INT32 flags); // return if player a is in the same team as player b boolean ST_SameTeam(player_t *a, player_t *b); diff --git a/src/y_inter.cpp b/src/y_inter.cpp index fe380119b..13a5e6ba1 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -1693,26 +1693,7 @@ finalcounter: { if ((modeattacking == ATTACKING_NONE) && (demo.recording || demo.savemode == demovars_s::DSM_SAVED) && !demo.playback) { - switch (demo.savemode) - { - case demovars_s::DSM_NOTSAVING: - { - INT32 buttonx = BASEVIDWIDTH; - INT32 buttony = 2; - - K_drawButtonAnim(buttonx - 76, buttony, 0, kp_button_b[1], replayprompttic); - V_DrawRightAlignedThinString(buttonx - 55, buttony, highlightflags, "or"); - K_drawButtonAnim(buttonx - 55, buttony, 0, kp_button_x[1], replayprompttic); - V_DrawRightAlignedThinString(buttonx - 2, buttony, highlightflags, "Save replay"); - break; - } - case demovars_s::DSM_SAVED: - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, highlightflags, "Replay saved!"); - break; - - default: // Don't render any text here - break; - } + ST_DrawSaveReplayHint(0); } } From 38e1ae1c53cdfff9009a9c66b16ea01374e653b2 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 21:40:22 -0800 Subject: [PATCH 7/9] Replays: let name be changed any time until the file is saved --- src/d_netcmd.c | 2 +- src/g_demo.cpp | 9 ++++----- src/g_demo.h | 7 +------ src/g_game.c | 2 +- src/p_tick.c | 5 ++--- src/st_stuff.c | 25 +++++-------------------- src/y_inter.cpp | 17 +++-------------- 7 files changed, 17 insertions(+), 50 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index cc16907fa..fdda510dd 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2878,7 +2878,7 @@ static void Got_Mapcmd(const UINT8 **cp, INT32 playernum) if (demo.playback && !demo.timing) precache = false; - demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING; + demo.willsave = (cv_recordmultiplayerdemos.value == 2); demo.savebutton = 0; G_InitNew(pencoremode, mapnumber, presetplayer, skipprecutscene); diff --git a/src/g_demo.cpp b/src/g_demo.cpp index 71cef6e81..28e92b027 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -3992,7 +3992,7 @@ boolean G_CheckDemoStatus(void) if (!demo.recording) return false; - if (modeattacking || demo.savemode != demovars_s::DSM_NOTSAVING) + if (modeattacking || demo.willsave) { if (demobuf.p) { @@ -4081,14 +4081,13 @@ void G_SaveDemo(void) md5_buffer((char *)p+16, (demobuf.buffer + length) - (p+16), p); #endif - if (FIL_WriteFile(demoname, demobuf.buffer, demobuf.p - demobuf.buffer)) // finally output the file. - demo.savemode = demovars_s::DSM_SAVED; + bool saved = FIL_WriteFile(demoname, demobuf.buffer, demobuf.p - demobuf.buffer); // finally output the file. Z_Free(demobuf.buffer); demo.recording = false; if (!modeattacking) { - if (demo.savemode == demovars_s::DSM_SAVED) + if (saved) { CONS_Printf(M_GetText("Demo %s recorded\n"), demoname); if (gamedata->eversavedreplay == false) @@ -4111,7 +4110,7 @@ boolean G_CheckDemoTitleEntry(void) if (!G_PlayerInputDown(0, gc_b, 0) && !G_PlayerInputDown(0, gc_x, 0)) return false; - demo.savemode = demovars_s::DSM_WILLSAVE; + demo.willsave = true; M_OpenVirtualKeyboard( false, [](const char* replace) -> const char* diff --git a/src/g_demo.h b/src/g_demo.h index 85b4d65f7..91b2c7ee7 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -90,12 +90,7 @@ struct demovars_s { boolean netgame; // multiplayer netgame tic_t savebutton; // Used to determine when the local player can choose to save the replay while the race is still going - enum { - DSM_NOTSAVING, - DSM_WILLAUTOSAVE, - DSM_WILLSAVE, - DSM_SAVED - } savemode; + boolean willsave; boolean freecam; diff --git a/src/g_game.c b/src/g_game.c index 79e5bd91e..3ca13d642 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4549,7 +4549,7 @@ void G_AfterIntermission(void) M_PlaybackQuit(0); return; } - else if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING)) + else if (demo.recording && (modeattacking || demo.willsave)) G_SaveDemo(); if (modeattacking) // End the run. diff --git a/src/p_tick.c b/src/p_tick.c index 1d273e328..3e1e2bb1c 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -1178,9 +1178,8 @@ void P_Ticker(boolean run) { G_WriteAllGhostTics(); - if (cv_recordmultiplayerdemos.value && (demo.savemode == DSM_NOTSAVING || demo.savemode == DSM_WILLAUTOSAVE)) - if (demo.savebutton && demo.savebutton + 3*TICRATE < leveltime) - G_CheckDemoTitleEntry(); + if (cv_recordmultiplayerdemos.value && demo.savebutton && demo.savebutton + 3*TICRATE < leveltime) + G_CheckDemoTitleEntry(); } else if (demo.playback) // Use Ghost data for consistency checks. { diff --git a/src/st_stuff.c b/src/st_stuff.c index b2a2bbc41..65f048b7c 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1459,26 +1459,11 @@ void ST_DrawServerSplash(boolean timelimited) void ST_DrawSaveReplayHint(INT32 flags) { - const char *text = ""; - switch (demo.savemode) - { - case DSM_NOTSAVING: - text = "\xAB" "or " "\xAE" "Save replay"; - break; - - case DSM_WILLAUTOSAVE: - text = "Replay will be saved. \xAB" "Change title"; - break; - - case DSM_WILLSAVE: - text = "Replay will be saved."; - break; - - case DSM_SAVED: - text = "Replay saved!"; - break; - } - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, flags|V_YELLOWMAP, text); + V_DrawRightAlignedThinString( + BASEVIDWIDTH - 2, 2, + flags|V_YELLOWMAP, + demo.willsave ? "Replay will be saved. \xAB" "Change title" : "\xAB" "or " "\xAE" "Save replay" + ); } static fixed_t ST_CalculateFadeIn(player_t *player) diff --git a/src/y_inter.cpp b/src/y_inter.cpp index 13a5e6ba1..688afbd8c 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -80,7 +80,6 @@ static INT32 powertype = PWRLV_DISABLED; static INT32 intertic; static INT32 endtic = -1; static INT32 sorttic = -1; -static INT32 replayprompttic; static fixed_t mqscroll = 0; static fixed_t chkscroll = 0; @@ -1690,12 +1689,8 @@ skiptallydrawer: } finalcounter: - { - if ((modeattacking == ATTACKING_NONE) && (demo.recording || demo.savemode == demovars_s::DSM_SAVED) && !demo.playback) - { - ST_DrawSaveReplayHint(0); - } - } + if ((modeattacking == ATTACKING_NONE) && demo.recording) + ST_DrawSaveReplayHint(0); if (Y_CanSkipIntermission()) { @@ -1731,13 +1726,7 @@ void Y_Ticker(void) return; if (demo.recording) - { - if (demo.savemode == demovars_s::DSM_NOTSAVING) - { - replayprompttic++; - G_CheckDemoTitleEntry(); - } - } + G_CheckDemoTitleEntry(); // Check for pause or menu up in single player if (paused || P_AutoPause()) From 8c76dee523eba5691346eb8b071f76c73400b4e6 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 22:51:22 -0800 Subject: [PATCH 8/9] Virtual Keyboard: dynamically allocate cache; allow full size of replay title buffer --- src/g_demo.cpp | 1 + src/k_menu.h | 5 +++-- src/k_menudraw.c | 17 ++++++++++++++++- src/k_menufunc.c | 2 +- src/menus/transient/virtual-keyboard.c | 15 ++++++++++----- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/g_demo.cpp b/src/g_demo.cpp index 28e92b027..c84b650bc 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -4113,6 +4113,7 @@ boolean G_CheckDemoTitleEntry(void) demo.willsave = true; M_OpenVirtualKeyboard( false, + sizeof demo.titlename, [](const char* replace) -> const char* { if (replace) diff --git a/src/k_menu.h b/src/k_menu.h index fdc7c2c88..ae093bf1c 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -557,7 +557,8 @@ extern struct menutyping_s vkb_query_fn_t queryfn; // callback on open and close menu_t *dummymenu; - char cache[MAXSTRINGLENGTH]; // cached string + size_t cachelen; + char *cache; // cached string } menutyping; // While typing, we'll have a fade strongly darken the screen to overlay the typing menu instead @@ -685,7 +686,7 @@ void M_PlayMenuJam(void); boolean M_ConsiderSealedSwapAlert(void); -void M_OpenVirtualKeyboard(boolean gamepad, vkb_query_fn_t queryfn, menu_t *dummymenu); +void M_OpenVirtualKeyboard(boolean gamepad, size_t cachelen, vkb_query_fn_t queryfn, menu_t *dummymenu); void M_AbortVirtualKeyboard(void); void M_MenuTypingInput(INT32 key); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 0929e714e..b0a125478 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -495,6 +495,21 @@ static void M_DrawMenuTooltips(void) } } +static const char *M_MenuTypingCroppedString(void) +{ + static char buf[36]; + const char *p = menutyping.cache; + size_t n = strlen(p); + if (n > sizeof buf) + { + p += n - sizeof buf; + n = sizeof buf; + } + memcpy(buf, p, n); + buf[n] = '\0'; + return buf; +} + // Draws the typing submenu static void M_DrawMenuTyping(void) { @@ -534,7 +549,7 @@ static void M_DrawMenuTyping(void) V_DrawFill(x + 4, y + 4 + 5, 1, 8+6, 121); V_DrawFill(x + 5 + boxwidth - 8, y + 4 + 5, 1, 8+6, 121); - INT32 textwidth = M_DrawCaretString(x + 8, y + 12, menutyping.cache, true); + INT32 textwidth = M_DrawCaretString(x + 8, y + 12, M_MenuTypingCroppedString(), true); if (skullAnimCounter < 4 && menutyping.menutypingclose == false && menutyping.menutypingfade == (menutyping.keyboardtyping ? 9 : 18)) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index b5335a87c..dc86b141c 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -1136,7 +1136,7 @@ static void M_HandleMenuInput(void) if (M_MenuConfirmPressed(pid)) { // If we entered this menu by pressing a menu Key, default to keyboard typing, otherwise use controller. - M_OpenVirtualKeyboard(thisMenuKey == -1, M_QueryCvarAction, NULL); + M_OpenVirtualKeyboard(thisMenuKey == -1, MAXSTRINGLENGTH, M_QueryCvarAction, NULL); return; } else if (M_MenuExtraPressed(pid)) diff --git a/src/menus/transient/virtual-keyboard.c b/src/menus/transient/virtual-keyboard.c index 15e0e9485..4204dce09 100644 --- a/src/menus/transient/virtual-keyboard.c +++ b/src/menus/transient/virtual-keyboard.c @@ -5,6 +5,7 @@ #include "../../s_sound.h" #include "../../console.h" // CON_ShiftChar #include "../../i_system.h" // I_Clipboard funcs +#include "../../z_zone.h" // Typing "sub"-menu struct menutyping_s menutyping; @@ -91,9 +92,9 @@ boolean M_ChangeStringCvar(INT32 choice) const char *paste = I_ClipboardPaste(); if (paste == NULL || paste[0] == '\0') ; - else if (len < MAXSTRINGLENGTH - 1) + else if (len < menutyping.cachelen) { - strlcat(menutyping.cache, paste, MAXSTRINGLENGTH); + strlcat(menutyping.cache, paste, menutyping.cachelen + 1); S_StartSound(NULL, sfx_tmxbdn); // Tails } @@ -146,7 +147,7 @@ boolean M_ChangeStringCvar(INT32 choice) if (choice >= 32 && choice <= 127) { len = strlen(menutyping.cache); - if (len < MAXSTRINGLENGTH - 1) + if (len < menutyping.cachelen) { menutyping.cache[len++] = (char)choice; menutyping.cache[len] = 0; @@ -189,6 +190,8 @@ void M_AbortVirtualKeyboard(void) return; menutyping.active = false; + Z_Free(menutyping.cache); + if (currentMenu == menutyping.dummymenu) M_GoBack(0); } @@ -415,7 +418,7 @@ void M_MenuTypingInput(INT32 key) } } -void M_OpenVirtualKeyboard(boolean gamepad, vkb_query_fn_t queryfn, menu_t *dummymenu) +void M_OpenVirtualKeyboard(boolean gamepad, size_t cachelen, vkb_query_fn_t queryfn, menu_t *dummymenu) { menutyping.keyboardtyping = !gamepad; menutyping.active = true; @@ -423,7 +426,9 @@ void M_OpenVirtualKeyboard(boolean gamepad, vkb_query_fn_t queryfn, menu_t *dumm menutyping.queryfn = queryfn; menutyping.dummymenu = dummymenu; - strlcpy(menutyping.cache, queryfn(NULL), MAXSTRINGLENGTH); + menutyping.cachelen = cachelen; + Z_Malloc(cachelen + 1, PU_STATIC, &menutyping.cache); + strlcpy(menutyping.cache, queryfn(NULL), cachelen + 1); if (dummymenu) { From e563f6271fc3fb86e41424d717b1acc566c8938f Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 23:06:44 -0800 Subject: [PATCH 9/9] Replays: auto-save when new recording starts - Saves if the map changes --- src/g_demo.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/g_demo.cpp b/src/g_demo.cpp index c84b650bc..e727eacba 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -1776,6 +1776,9 @@ void G_ConfirmRewind(tic_t rewindtime) // void G_RecordDemo(const char *name) { + if (demo.recording) + G_CheckDemoStatus(); + extern consvar_t cv_netdemosize; INT32 maxsize;