From 07fa5fff01462eaad915442928d14d47136189a3 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 27 Jun 2023 13:28:12 +0100 Subject: [PATCH 01/13] M_DrawPause: Make the visual case for user-selectable options more flexible/less specific to the gametype changer it was implemented for. A surprise tool that will help us later --- src/k_menudraw.c | 85 +++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index d01bd593d..6df9183da 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -4262,11 +4262,6 @@ void M_DrawPause(void) INT16 arrxpos = 150 + 2*offset; // To draw the background arrow. INT16 j = 0; - char word1[MAXSTRINGLENGTH]; - INT16 word1len = 0; - char word2[MAXSTRINGLENGTH]; - INT16 word2len = 0; - boolean sok = false; patch_t *vertbg = W_CachePatchName("M_STRIPV", PU_CACHE); patch_t *arrstart = W_CachePatchName("M_PTIP", PU_CACHE); @@ -4364,48 +4359,64 @@ void M_DrawPause(void) } // Draw the string! - // ...but first get what we need to get. - while (currentMenu->menuitems[itemOn].text[j] && j < MAXSTRINGLENGTH) - { - char c = currentMenu->menuitems[itemOn].text[j]; - - if (c == ' ' && !sok) - { - sok = true; - j++; - continue; // We don't care about this :moyai: - } - - if (sok) - { - word2[word2len] = c; - word2len++; - } - else - { - word1[word1len] = c; - word1len++; - } - - j++; - } - - word1[word1len] = '\0'; - word2[word2len] = '\0'; + const char *selectabletext = NULL; if (itemOn == mpause_changegametype) { - INT32 w = V_LSTitleLowStringWidth(gametypes[menugametype]->name, 0)/2; + selectabletext = gametypes[menugametype]->name; + } - if (word1len) - V_DrawCenteredLSTitleHighString(220 + offset*2, 75, 0, word1); + if (selectabletext != NULL) + { + // We have a selection. Let's show the full menu text on top, and the choice below. - V_DrawLSTitleLowString(220-w + offset*2, 103, V_YELLOWMAP, gametypes[menugametype]->name); + INT32 w = V_LSTitleLowStringWidth(selectabletext, 0)/2; + + if (currentMenu->menuitems[itemOn].text) + V_DrawCenteredLSTitleHighString(220 + offset*2, 75, 0, currentMenu->menuitems[itemOn].text); + + V_DrawLSTitleLowString(220-w + offset*2, 103, V_YELLOWMAP, selectabletext); V_DrawCharacter(220-w + offset*2 - 8 - (skullAnimCounter/5), 103+6, '\x1C' | V_YELLOWMAP, false); // left arrow V_DrawCharacter(220+w + offset*2 + 4 + (skullAnimCounter/5), 103+6, '\x1D' | V_YELLOWMAP, false); // right arrow } else { + // This is a regular menu option. Try to break it onto two lines. + + char word1[MAXSTRINGLENGTH]; + INT16 word1len = 0; + char word2[MAXSTRINGLENGTH]; + INT16 word2len = 0; + boolean sok = false; + + while (currentMenu->menuitems[itemOn].text[j] && j < MAXSTRINGLENGTH) + { + const char c = currentMenu->menuitems[itemOn].text[j]; + + if (c == ' ' && !sok) + { + sok = true; + j++; + continue; // We don't care about this :moyai: + } + + if (sok) + { + word2[word2len] = c; + word2len++; + } + else + { + word1[word1len] = c; + word1len++; + } + + j++; + } + + word1[word1len] = '\0'; + word2[word2len] = '\0'; + // If there's no 2nd word, take this opportunity to center this line of text. if (word1len) V_DrawCenteredLSTitleHighString(220 + offset*2, 75 + (!word2len ? 10 : 0), 0, word1); From ec8a6247c22c8dff4178a252865bc891bce83826 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 27 Jun 2023 14:16:48 +0100 Subject: [PATCH 02/13] Z-vote is now server-authoriative - Only calls callback if you're the server (and not demo.playback, forward thinking for stored xcmd netreplays) - G_GamestateUsesExitLevel() for homogenising the conditions that permit XD_EXITLEVEL to be dispatched and recieved --- src/d_netcmd.c | 21 ++++++++++++++++++++- src/d_netcmd.h | 1 + src/k_zvote.c | 19 +++++++++++++------ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index f391e83c1..63781835d 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5646,6 +5646,22 @@ static void Command_Mapmd5_f(void) CONS_Printf(M_GetText("You must be in a level to use this.\n")); } +boolean G_GamestateUsesExitLevel(void) +{ + if (demo.playback) + return false; + + switch (gamestate) + { + case GS_LEVEL: + case GS_CREDITS: + return true; + + default: + return false; + } +} + static void Command_ExitLevel_f(void) { if (!(server || (IsPlayerAdmin(consoleplayer)))) @@ -5656,7 +5672,7 @@ static void Command_ExitLevel_f(void) { CONS_Printf(M_GetText("This cannot be used without cheats enabled.\n")); } - else if (( gamestate != GS_LEVEL && gamestate != GS_CREDITS ) || demo.playback) + else if (G_GamestateUsesExitLevel() == false) { CONS_Printf(M_GetText("You must be in a level to use this.\n")); } @@ -5682,6 +5698,9 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) return; } + if (G_GamestateUsesExitLevel() == false) + return; + G_ExitLevel(); } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index c9938b4e5..621179d86 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -241,6 +241,7 @@ void WeaponPref_Parse(UINT8 **cp, INT32 playernum); void D_SendPlayerConfig(UINT8 n); void Command_ExitGame_f(void); void Command_Retry_f(void); +boolean G_GamestateUsesExitLevel(void); void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore void D_MapChange(UINT16 pmapnum, INT32 pgametype, boolean pencoremode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pforcespecialstage); void D_SetupVote(void); diff --git a/src/k_zvote.c b/src/k_zvote.c index 9958e58b7..9c933d734 100644 --- a/src/k_zvote.c +++ b/src/k_zvote.c @@ -57,10 +57,7 @@ static void K_MidVoteKick(void) return; } - if (server) - { - SendKick(g_midVote.victim - players, KICK_MSG_VOTE_KICK); - } + SendKick(g_midVote.victim - players, KICK_MSG_VOTE_KICK); } /*-------------------------------------------------- @@ -70,7 +67,13 @@ static void K_MidVoteKick(void) --------------------------------------------------*/ static void K_MidVoteRockTheVote(void) { - G_ExitLevel(); + if (G_GamestateUsesExitLevel() == false) + { + return; + } + + SendNetXCmd(XD_EXITLEVEL, NULL, 0); +} } static midVoteTypeDef_t g_midVoteTypeDefs[MVT__MAX] = @@ -630,7 +633,11 @@ void K_MidVoteFinalize(fixed_t delayMul) --------------------------------------------------*/ void K_MidVoteSuccess(void) { - if (g_midVoteTypeDefs[ g_midVote.type ].callback != NULL) + if ( + server == true + && demo.playback == false + && g_midVoteTypeDefs[ g_midVote.type ].callback != NULL + ) { g_midVoteTypeDefs[ g_midVote.type ].callback(); } From ddce2e9a2da7ccb8e9136d7e38b2012c55d27856 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 27 Jun 2023 14:24:45 +0100 Subject: [PATCH 03/13] zvote_call runitback - "Redo Level?" - Functionally `restartlevel` but votable --- src/k_zvote.c | 23 +++++++++++++++++++++++ src/k_zvote.h | 1 + 2 files changed, 24 insertions(+) diff --git a/src/k_zvote.c b/src/k_zvote.c index 9c933d734..b0d1991b6 100644 --- a/src/k_zvote.c +++ b/src/k_zvote.c @@ -74,6 +74,22 @@ static void K_MidVoteRockTheVote(void) SendNetXCmd(XD_EXITLEVEL, NULL, 0); } + +/*-------------------------------------------------- + static void K_MidVoteRunItBack(void) + + MVT_RUNITBACK's success function. +--------------------------------------------------*/ +static void K_MidVoteRunItBack(void) +{ + boolean newencore = false; + + if (cv_kartencore.value != 0) + { + newencore = (cv_kartencore.value == 1) || encoremode; + } + + D_MapChange(gamemap, gametype, newencore, false, 0, false, false); } static midVoteTypeDef_t g_midVoteTypeDefs[MVT__MAX] = @@ -91,6 +107,13 @@ static midVoteTypeDef_t g_midVoteTypeDefs[MVT__MAX] = CVAR_INIT ("zvote_rtv_allowed", "No", CV_SAVE|CV_NETVAR, CV_YesNo, NULL), K_MidVoteRockTheVote }, + + { // MVT_RUNITBACK + "RUNITBACK", + "Redo Level?", + CVAR_INIT ("zvote_runitback_allowed", "No", CV_SAVE|CV_NETVAR, CV_YesNo, NULL), + K_MidVoteRunItBack + }, }; /*-------------------------------------------------- diff --git a/src/k_zvote.h b/src/k_zvote.h index 7296770aa..f1d57a546 100644 --- a/src/k_zvote.h +++ b/src/k_zvote.h @@ -28,6 +28,7 @@ typedef enum { MVT_KICK, // Kick another player in the server MVT_RTV, // Exit level early + MVT_RUNITBACK, // Restart level fresh MVT__MAX, // Total number of vote types } midVoteType_e; From 34563ebecd4d4e4a0bc7f0d38b2e24e52299950b Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 27 Jun 2023 17:30:43 +0100 Subject: [PATCH 04/13] Got_KickCmd: Only PROMOTE any regular kick to votekick if that player's the victim, don't downgrade a ban --- src/d_clisrv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 2849589ba..e5dde4921 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3255,7 +3255,11 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) { // Running the callback here would mean a very dumb infinite loop. // We'll manually handle this here by changing the msg type. - msg = KICK_MSG_VOTE_KICK; + if (msg != KICK_MSG_BANNED && msg != KICK_MSG_CUSTOM_BAN) + { + // of course, don't take the teeth out of a ban + msg = KICK_MSG_VOTE_KICK; + } K_MidVoteFinalize(FRACUNIT); // Vote succeeded, so the delay is normal. } else From 15ff670a48046651c40896b4939fdd5b468fe885 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 27 Jun 2023 17:32:03 +0100 Subject: [PATCH 05/13] Reduce space width of Level Select high/low fonts - fancy fonts shouldn't be monospace --- src/v_video.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index d25778061..ae65de142 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -2286,7 +2286,7 @@ void V_DrawStringScaled( break; case LSHI_FONT: case LSLOW_FONT: - spacew = 16; + spacew = 10; break; case OPPRF_FONT: spacew = 5; @@ -2579,7 +2579,7 @@ fixed_t V_StringScaledWidth( break; case LSHI_FONT: case LSLOW_FONT: - spacew = 16; + spacew = 10; break; case OPPRF_FONT: spacew = 5; From 8a4cca8518de90a97c170ad9f4198ed7cf6d1b4c Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 27 Jun 2023 17:33:01 +0100 Subject: [PATCH 06/13] Seperate out K_SendCallMidVote from Command_CallVote --- src/k_zvote.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/k_zvote.c b/src/k_zvote.c index b0d1991b6..94fffb720 100644 --- a/src/k_zvote.c +++ b/src/k_zvote.c @@ -151,9 +151,6 @@ static boolean K_MidVoteTypeUsesVictim(midVoteType_e voteType) --------------------------------------------------*/ static void Command_CallVote(void) { - UINT8 buf[MAXTEXTCMD]; - UINT8 *buf_p = buf; - size_t numArgs = 0; const char *voteTypeStr = NULL; @@ -162,8 +159,6 @@ static void Command_CallVote(void) const char *voteVariableStr = NULL; INT32 voteVariable = 0; - player_t *victim = NULL; - INT32 i = INT32_MAX; if (netgame == false) @@ -210,11 +205,26 @@ static void Command_CallVote(void) break; } } + } + } - if (voteVariable >= 0 && voteVariable < MAXPLAYERS) - { - victim = &players[voteVariable]; - } + K_SendCallMidVote(voteType, voteVariable); +} + +/*-------------------------------------------------- + void K_SendCallMidVote(midVoteType_e voteType, INT32 voteVariable) + + See header file for description. +--------------------------------------------------*/ +void K_SendCallMidVote(midVoteType_e voteType, INT32 voteVariable) +{ + player_t *victim = NULL; + + if (K_MidVoteTypeUsesVictim(voteType) == true) + { + if (voteVariable >= 0 && voteVariable < MAXPLAYERS) + { + victim = &players[voteVariable]; } } @@ -224,6 +234,9 @@ static void Command_CallVote(void) return; } + UINT8 buf[MAXTEXTCMD]; + UINT8 *buf_p = buf; + WRITEUINT8(buf_p, voteType); WRITEINT32(buf_p, voteVariable); From 721d5d9da99e0cc544849270d1da97bd3d25cfd8 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 27 Jun 2023 17:45:27 +0100 Subject: [PATCH 07/13] Improve M_HandlePauseMenuGametype and M_HandleHostMenuGametype Simplify massively by using IT_ARROWS --- src/k_menudraw.c | 2 +- src/menus/play-online-1.c | 2 +- src/menus/play-online-host.c | 38 ++++++++------------------------ src/menus/transient/pause-game.c | 34 ++++++++++++++-------------- 4 files changed, 27 insertions(+), 49 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 6df9183da..bd2ae614a 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -3065,7 +3065,7 @@ void M_DrawMPHost(void) } break; } - case IT_KEYHANDLER: + case IT_ARROWS: { if (currentMenu->menuitems[i].itemaction.routine != M_HandleHostMenuGametype) break; diff --git a/src/menus/play-online-1.c b/src/menus/play-online-1.c index 8a9b74234..7f9a9c294 100644 --- a/src/menus/play-online-1.c +++ b/src/menus/play-online-1.c @@ -80,8 +80,8 @@ void M_MPOptSelectInit(INT32 choice) memcpy(&mpmenu.modewinextend, &arrcpy, sizeof(mpmenu.modewinextend)); // Guarantee menugametype is good - M_NextMenuGametype(forbidden); M_PrevMenuGametype(forbidden); + M_NextMenuGametype(forbidden); if (choice != -1) { diff --git a/src/menus/play-online-host.c b/src/menus/play-online-host.c index 7ab684c5c..a7061a32a 100644 --- a/src/menus/play-online-host.c +++ b/src/menus/play-online-host.c @@ -18,7 +18,7 @@ menuitem_t PLAY_MP_Host[] = {IT_STRING | IT_CVAR, "Max. Players", "Set how many players can play at once. Others will spectate.", NULL, {.cvar = &cv_maxplayers}, 0, 0}, - {IT_STRING | IT_KEYHANDLER, "Gamemode", "Choose the type of play on your server.", + {IT_STRING | IT_ARROWS, "Gamemode", "Choose the type of play on your server.", NULL, {.routine = M_HandleHostMenuGametype}, 0, 0}, {IT_STRING | IT_CALL, "GO", "Select a map with the currently selected gamemode", @@ -54,41 +54,21 @@ void M_MPHostInit(INT32 choice) void M_HandleHostMenuGametype(INT32 choice) { - const UINT8 pid = 0; const UINT32 forbidden = GTR_FORBIDMP; - (void)choice; - - if (M_MenuBackPressed(pid)) - { - M_GoBack(0); - M_SetMenuDelay(pid); - return; - } - else if (menucmd[pid].dpad_lr > 0 || M_MenuConfirmPressed(pid)) + if (choice > 0) { M_NextMenuGametype(forbidden); - S_StartSound(NULL, sfx_s3k5b); - M_SetMenuDelay(pid); } - else if (menucmd[pid].dpad_lr < 0) + else if (choice == -1) + { + menugametype = GT_RACE; + M_PrevMenuGametype(forbidden); + M_NextMenuGametype(forbidden); + } + else { M_PrevMenuGametype(forbidden); - S_StartSound(NULL, sfx_s3k5b); - M_SetMenuDelay(pid); - } - - if (menucmd[pid].dpad_ud > 0) - { - M_NextOpt(); - S_StartSound(NULL, sfx_s3k5b); - M_SetMenuDelay(pid); - } - else if (menucmd[pid].dpad_ud < 0) - { - M_PrevOpt(); - S_StartSound(NULL, sfx_s3k5b); - M_SetMenuDelay(pid); } } diff --git a/src/menus/transient/pause-game.c b/src/menus/transient/pause-game.c index c3b640ea8..e43f05d5d 100644 --- a/src/menus/transient/pause-game.c +++ b/src/menus/transient/pause-game.c @@ -22,7 +22,7 @@ menuitem_t PAUSE_Main[] = {IT_STRING | IT_CALL, "STEREO MODE", "M_ICOSTM", NULL, {.routine = M_SoundTest}, 0, 0}, - {IT_STRING | IT_KEYHANDLER, "GAMETYPE", "M_ICOGAM", + {IT_STRING | IT_ARROWS, "GAMETYPE", "M_ICOGAM", NULL, {.routine = M_HandlePauseMenuGametype}, 0, 0}, {IT_STRING | IT_CALL, "CHANGE MAP", "M_ICOMAP", @@ -71,7 +71,7 @@ menu_t PAUSE_MainDef = { PAUSE_Main, 0, 0, 0, 0, - 0, + MBF_SOUNDLESS, NULL, 1, 10, // For transition with some menus! M_DrawPause, @@ -146,7 +146,7 @@ void M_OpenPauseMenu(void) if (server || IsPlayerAdmin(consoleplayer)) { - PAUSE_Main[mpause_changegametype].status = IT_STRING | IT_KEYHANDLER; + PAUSE_Main[mpause_changegametype].status = IT_STRING | IT_ARROWS; menugametype = gametype; PAUSE_Main[mpause_switchmap].status = IT_STRING | IT_CALL; @@ -267,12 +267,9 @@ boolean M_PauseInputs(INT32 ch) // Change gametype void M_HandlePauseMenuGametype(INT32 choice) { - const UINT8 pid = 0; const UINT32 forbidden = GTR_FORBIDMP; - (void)choice; - - if (M_MenuConfirmPressed(pid)) + if (choice == 2) { if (menugametype != gametype) { @@ -281,26 +278,27 @@ void M_HandlePauseMenuGametype(INT32 choice) return; } - M_SetMenuDelay(pid); S_StartSound(NULL, sfx_s3k7b); + + return; } - else if (M_MenuExtraPressed(pid)) + + if (choice == -1) { menugametype = gametype; - M_SetMenuDelay(pid); S_StartSound(NULL, sfx_s3k7b); + return; } - else if (menucmd[pid].dpad_lr > 0) - { - M_NextMenuGametype(forbidden); - S_StartSound(NULL, sfx_s3k5b); - M_SetMenuDelay(pid); - } - else if (menucmd[pid].dpad_lr < 0) + + if (choice == 0) { M_PrevMenuGametype(forbidden); S_StartSound(NULL, sfx_s3k5b); - M_SetMenuDelay(pid); + } + else + { + M_NextMenuGametype(forbidden); + S_StartSound(NULL, sfx_s3k5b); } } From d8ea8c0fe1fd461ede5c8f597e7f090c30e4c655 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 27 Jun 2023 17:53:59 +0100 Subject: [PATCH 08/13] Implement "CALL VOTE" for victimless commands on the pause menu Currently just plays the squishy "nope" sound for "KICK PLAYER?", all others are functional Shows whether vote is active or the cooldown is too recent (via numerical timer) as reasons for why you can't select it --- src/k_menu.h | 4 ++ src/k_menudraw.c | 64 +++++++++++++---- src/k_zvote.c | 118 +++++++++++++++++++++++++++---- src/k_zvote.h | 74 +++++++++++++++++++ src/menus/transient/pause-game.c | 49 +++++++++++++ 5 files changed, 281 insertions(+), 28 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 7eefd06ea..b4ce7c6bd 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -126,6 +126,9 @@ void M_PrevMenuGametype(UINT32 forbidden); void M_HandleHostMenuGametype(INT32 choice); void M_HandlePauseMenuGametype(INT32 choice); +extern UINT32 menucallvote; // not midVoteType_e to prevent #include k_zvote +void M_HandlePauseMenuCallVote(INT32 choice); + // // MENU TYPEDEFS // @@ -447,6 +450,7 @@ typedef enum #ifdef HAVE_DISCORDRPC mpause_discordrequests, #endif + mpause_callvote, mpause_continue, mpause_spectate, diff --git a/src/k_menudraw.c b/src/k_menudraw.c index bd2ae614a..f89eb0db8 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -52,6 +52,7 @@ #include "doomstat.h" // MAXSPLITSCREENPLAYERS #include "k_grandprix.h" // K_CanChangeRules #include "k_rank.h" // K_GetGradeColor +#include "k_zvote.h" // K_GetMidVoteLabel #include "y_inter.h" // Y_RoundQueueDrawer @@ -4360,26 +4361,61 @@ void M_DrawPause(void) // Draw the string! + const char *maintext = NULL; const char *selectabletext = NULL; + INT32 mainflags = V_YELLOWMAP, selectableflags = 0; + if (itemOn == mpause_changegametype) { selectabletext = gametypes[menugametype]->name; } + else if (itemOn == mpause_callvote) + { + selectabletext = K_GetMidVoteLabel(menucallvote); + + if (K_MinimalCheckNewMidVote(menucallvote) == false) + { + if (g_midVote.active == true) + { + maintext = "ACTIVE..."; + } + else if (g_midVote.delay > 0) + { + if (g_midVote.delay != 1) + maintext = va("%u", ((g_midVote.delay - 1) / TICRATE) + 1); + } + else + { + maintext = "INVALID!?"; + } + + if (maintext != NULL) + selectableflags |= V_MODULATE; + } + } + else + { + maintext = currentMenu->menuitems[itemOn].text; + mainflags = 0; + } if (selectabletext != NULL) { // We have a selection. Let's show the full menu text on top, and the choice below. - INT32 w = V_LSTitleLowStringWidth(selectabletext, 0)/2; - if (currentMenu->menuitems[itemOn].text) - V_DrawCenteredLSTitleHighString(220 + offset*2, 75, 0, currentMenu->menuitems[itemOn].text); + V_DrawCenteredLSTitleHighString(220 + offset*2, 75, selectableflags, currentMenu->menuitems[itemOn].text); - V_DrawLSTitleLowString(220-w + offset*2, 103, V_YELLOWMAP, selectabletext); - V_DrawCharacter(220-w + offset*2 - 8 - (skullAnimCounter/5), 103+6, '\x1C' | V_YELLOWMAP, false); // left arrow - V_DrawCharacter(220+w + offset*2 + 4 + (skullAnimCounter/5), 103+6, '\x1D' | V_YELLOWMAP, false); // right arrow + selectableflags |= V_YELLOWMAP; + + INT32 w = V_LSTitleLowStringWidth(selectabletext, selectableflags)/2; + V_DrawLSTitleLowString(220-w + offset*2, 103, selectableflags, selectabletext); + + V_DrawCharacter(220-w + offset*2 - 8 - (skullAnimCounter/5), 103+6, '\x1C' | selectableflags, false); // left arrow + V_DrawCharacter(220+w + offset*2 + (skullAnimCounter/5), 103+6, '\x1D' | selectableflags, false); // right arrow } - else + + if (maintext != NULL) { // This is a regular menu option. Try to break it onto two lines. @@ -4389,11 +4425,9 @@ void M_DrawPause(void) INT16 word2len = 0; boolean sok = false; - while (currentMenu->menuitems[itemOn].text[j] && j < MAXSTRINGLENGTH) + while (maintext[j] && j < MAXSTRINGLENGTH) { - const char c = currentMenu->menuitems[itemOn].text[j]; - - if (c == ' ' && !sok) + if (maintext[j] == ' ' && !sok) { sok = true; j++; @@ -4402,12 +4436,12 @@ void M_DrawPause(void) if (sok) { - word2[word2len] = c; + word2[word2len] = maintext[j]; word2len++; } else { - word1[word1len] = c; + word1[word1len] = maintext[j]; word1len++; } @@ -4419,10 +4453,10 @@ void M_DrawPause(void) // If there's no 2nd word, take this opportunity to center this line of text. if (word1len) - V_DrawCenteredLSTitleHighString(220 + offset*2, 75 + (!word2len ? 10 : 0), 0, word1); + V_DrawCenteredLSTitleHighString(220 + offset*2, 75 + (!word2len ? 10 : 0), mainflags, word1); if (word2len) - V_DrawCenteredLSTitleLowString(220 + offset*2, 103, 0, word2); + V_DrawCenteredLSTitleLowString(220 + offset*2, 103, mainflags, word2); } if (gamestate != GS_INTERMISSION && roundqueue.size > 0) diff --git a/src/k_zvote.c b/src/k_zvote.c index 94fffb720..8f6ba9e95 100644 --- a/src/k_zvote.c +++ b/src/k_zvote.c @@ -117,19 +117,11 @@ static midVoteTypeDef_t g_midVoteTypeDefs[MVT__MAX] = }; /*-------------------------------------------------- - static boolean K_MidVoteTypeUsesVictim(midVoteType_e voteType) + boolean K_MidVoteTypeUsesVictim(midVoteType_e voteType) - Specifies whenever or not a vote type is intended - to specify a "victim", or a player that would be - negatively affected by the vote. - - Input Arguments:- - voteType - The vote type to check. - - Return:- - true if it uses a victim, otherwise false. + See header file for description. --------------------------------------------------*/ -static boolean K_MidVoteTypeUsesVictim(midVoteType_e voteType) +boolean K_MidVoteTypeUsesVictim(midVoteType_e voteType) { switch (voteType) { @@ -380,6 +372,51 @@ boolean K_AnyMidVotesAllowed(void) return false; } +/*-------------------------------------------------- + midVoteType_e K_GetNextCallableMidVote(INT32 seed, boolean backwards) + + See header file for description. +--------------------------------------------------*/ + +midVoteType_e K_GetNextAllowedMidVote(midVoteType_e seed, boolean backwards) +{ + if (seed >= MVT__MAX) + seed = 0; + + midVoteType_e i = seed; + + if (backwards) + { + do + { + if (i <= 0) + i = MVT__MAX; + i--; + + if (g_midVoteTypeDefs[i].cv_allowed.value != 0) + return i; + + } + while (i != seed); + } + else + { + do + { + i++; + if (i >= MVT__MAX) + i = 0; + + if (g_midVoteTypeDefs[i].cv_allowed.value != 0) + return i; + + } + while (i != seed); + } + + return MVT__MAX; +} + /*-------------------------------------------------- boolean K_PlayerIDAllowedInMidVote(const UINT8 id) @@ -507,6 +544,40 @@ UINT8 K_CountMidVotes(void) return voteCount; } +/*-------------------------------------------------- + boolean K_MinimalCheckNewMidVote(midVoteType_e type) + + See header file for description. +--------------------------------------------------*/ +boolean K_MinimalCheckNewMidVote(midVoteType_e type) +{ + if (g_midVote.active == true) + { + // Don't allow another vote if one is already running. + return false; + } + + if (g_midVote.delay > 0) + { + // Don't allow another vote if one has recently just ran. + return false; + } + + if (type < 0 || type >= MVT__MAX) + { + // Invalid range. + return false; + } + + if (g_midVoteTypeDefs[type].cv_allowed.value == 0) + { + // These types of votes aren't allowed on this server. + return false; + } + + return true; +} + /*-------------------------------------------------- boolean K_AllowNewMidVote(player_t *caller, midVoteType_e type, INT32 variable, player_t *victim) @@ -866,6 +937,25 @@ void K_UpdateMidVotePatches(void) HU_UpdatePatch(&g_zBarEnds[1][1][1], "TLBXB0"); } +/*-------------------------------------------------- + const char *K_GetMidVoteLabel(midVoteType_e i) + + See header file for description. +--------------------------------------------------*/ + +const char *K_GetMidVoteLabel(midVoteType_e i) +{ + if ( + i < 0 + || i >= MVT__MAX + || g_midVoteTypeDefs[i].label == NULL) + { + return "N/A"; + } + + return g_midVoteTypeDefs[i].label; +} + /*-------------------------------------------------- static void K_DrawMidVoteBar(fixed_t x, fixed_t y, INT32 flags, fixed_t fill, skincolornum_t color, boolean flipped) @@ -1049,11 +1139,13 @@ void K_DrawMidVote(void) (id & 1) ); + const char *label = K_GetMidVoteLabel(g_midVote.type); + // Vote main label strWidth = V__OneScaleStringWidth( FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN, - KART_FONT, g_midVoteTypeDefs[g_midVote.type].label + KART_FONT, label ); V__DrawOneScaleString( @@ -1061,7 +1153,7 @@ void K_DrawMidVote(void) y - (18 * FRACUNIT), FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN, NULL, - KART_FONT, g_midVoteTypeDefs[g_midVote.type].label + KART_FONT, label ); // Vote extra text diff --git a/src/k_zvote.h b/src/k_zvote.h index f1d57a546..61ee8c630 100644 --- a/src/k_zvote.h +++ b/src/k_zvote.h @@ -64,6 +64,39 @@ struct midVote_t extern midVote_t g_midVote; +/*-------------------------------------------------- + boolean K_MidVoteTypeUsesVictim(midVoteType_e voteType) + + Specifies whenever or not a vote type is intended + to specify a "victim", or a player that would be + negatively affected by the vote. + + Input Arguments:- + voteType - The vote type to check. + + Return:- + true if it uses a victim, otherwise false. +--------------------------------------------------*/ + +boolean K_MidVoteTypeUsesVictim(midVoteType_e voteType); + + +/*-------------------------------------------------- + void K_SendCallMidVote(midVoteType_e voteType, INT32 voteVariable) + + Prepares and sends net packet for calling a midvote. + + Input Arguments:- + voteType - The type of vote a local player is trying to call. + variable - Extra arguments for the vote type. + + Return:- + N/A +--------------------------------------------------*/ + +void K_SendCallMidVote(midVoteType_e voteType, INT32 voteVariable); + + /*-------------------------------------------------- void K_RegisterMidVoteCVars(void); @@ -100,6 +133,22 @@ void K_ResetMidVote(void); boolean K_AnyMidVotesAllowed(void); +/*-------------------------------------------------- + midVoteType_e K_GetNextCallableMidVote(midVoteType_e seed, boolean backwards) + + Gets the next enabled Z-vote type in the list. + + Input Arguments:- + seed - position in the list to start with + backwards - if true, traverses list in reverse order + + Return:- + next Z-vote id if any vote types are enabled, otherwise MVT__MAX. +--------------------------------------------------*/ + +midVoteType_e K_GetNextAllowedMidVote(midVoteType_e seed, boolean backwards); + + /*-------------------------------------------------- boolean K_PlayerIDAllowedInMidVote(const UINT8 id); @@ -171,6 +220,18 @@ boolean K_PlayerIDMidVoted(const UINT8 id); UINT8 K_CountMidVotes(void); +/*-------------------------------------------------- + boolean K_MinimalCheckNewMidVote(midVoteType_e type) + + Returns if the variables given are a valid state for + pause menu Z-vote flow. + + Input Arguments:- + type - The type of vote they're trying to call. +--------------------------------------------------*/ + +boolean K_MinimalCheckNewMidVote(midVoteType_e type); + /*-------------------------------------------------- boolean K_AllowNewMidVote(player_t *caller, midVoteType_e type, INT32 variable, player_t *victim); @@ -264,6 +325,19 @@ void K_TickMidVote(void); void K_UpdateMidVotePatches(void); +/*-------------------------------------------------- + const char *K_GetMidVoteLabel(midVoteType_e i) + + Input Arguments:- + i - id in the list to retrieve label for + + Return:- + label associated with that id, or a sensible default (not NULL) +--------------------------------------------------*/ + +const char *K_GetMidVoteLabel(midVoteType_e i); + + /*-------------------------------------------------- void K_DrawMidVote(void); diff --git a/src/menus/transient/pause-game.c b/src/menus/transient/pause-game.c index e43f05d5d..cac1c1280 100644 --- a/src/menus/transient/pause-game.c +++ b/src/menus/transient/pause-game.c @@ -5,6 +5,7 @@ #include "../../k_grandprix.h" // K_CanChangeRules #include "../../m_cond.h" #include "../../s_sound.h" +#include "../../k_zvote.h" #ifdef HAVE_DISCORDRPC #include "../../discord.h" @@ -39,6 +40,9 @@ menuitem_t PAUSE_Main[] = NULL, {.routine = M_DiscordRequests}, 0, 0}, #endif + {IT_STRING | IT_ARROWS, "CALL VOTE", "M_ICOVOT", + NULL, {.routine = M_HandlePauseMenuCallVote}, 0, 0}, + {IT_STRING | IT_CALL, "RESUME GAME", "M_ICOUNP", NULL, {.routine = M_QuitPauseMenu}, 0, 0}, @@ -123,6 +127,7 @@ void M_OpenPauseMenu(void) PAUSE_Main[mpause_switchmap].status = IT_DISABLED; PAUSE_Main[mpause_restartmap].status = IT_DISABLED; PAUSE_Main[mpause_tryagain].status = IT_DISABLED; + PAUSE_Main[mpause_callvote].status = IT_DISABLED; #ifdef HAVE_DISCORDRPC PAUSE_Main[mpause_discordrequests].status = IT_DISABLED; #endif @@ -178,6 +183,18 @@ void M_OpenPauseMenu(void) } } + if (netgame) + { + menucallvote = K_GetNextAllowedMidVote(menucallvote, true); + + if (menucallvote != MVT__MAX) + { + menucallvote = K_GetNextAllowedMidVote(menucallvote, false); + + PAUSE_Main[mpause_callvote].status = IT_STRING | IT_ARROWS; + } + } + if (G_GametypeHasSpectators()) { if (splitscreen) @@ -302,6 +319,38 @@ void M_HandlePauseMenuGametype(INT32 choice) } } +// Call vote +UINT32 menucallvote = MVT__MAX; + +void M_HandlePauseMenuCallVote(INT32 choice) +{ + if (choice == 2) + { + if (K_MinimalCheckNewMidVote(menucallvote) == false) + { + // Invalid. + S_StartSound(NULL, sfx_s3k7b); + } + else if (K_MidVoteTypeUsesVictim(menucallvote) == true) + { + // Not yet implemented. + S_StartSound(NULL, sfx_s3k7b); + } + else + { + // Bog standard and victimless, let's send it on its way! + M_ClearMenus(true); + K_SendCallMidVote(menucallvote, 0); + return; + } + + return; + } + + menucallvote = K_GetNextAllowedMidVote(menucallvote, (choice == 0)); + S_StartSound(NULL, sfx_s3k5b); +} + // Restart map void M_RestartMap(INT32 choice) { From b59346f63773fc88c673c1bec741c9da35610a7b Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 27 Jun 2023 23:59:01 +0100 Subject: [PATCH 09/13] Votekick menu Not super polished, literally just implemented this way to make freeze --- src/k_menu.h | 11 +++ src/k_menudraw.c | 98 +++++++++++++++++++++++++ src/menus/transient/CMakeLists.txt | 1 + src/menus/transient/pause-game.c | 4 +- src/menus/transient/pause-kick.c | 112 +++++++++++++++++++++++++++++ 5 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 src/menus/transient/pause-kick.c diff --git a/src/k_menu.h b/src/k_menu.h index b4ce7c6bd..6d21212d0 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -418,6 +418,8 @@ extern menu_t EXTRAS_EggTVDef; extern menuitem_t PAUSE_Main[]; extern menu_t PAUSE_MainDef; +extern menu_t PAUSE_KickHandlerDef; + // EXTRAS extern menuitem_t MISC_Manual[]; extern menu_t MISC_ManualDef; @@ -1082,6 +1084,14 @@ void M_QuitPauseMenu(INT32 choice); boolean M_PauseInputs(INT32 ch); void M_PauseTick(void); +extern struct playerkickmenu_s { + tic_t ticker; + UINT8 player; + UINT8 poke; +} playerkickmenu; + +void M_KickHandler(INT32 choice); + extern consvar_t cv_dummymenuplayer; extern consvar_t cv_dummyspectator; @@ -1154,6 +1164,7 @@ void M_DrawMPServerBrowser(void); // Pause menu: void M_DrawPause(void); +void M_DrawKickHandler(void); // Replay Playback void M_DrawPlaybackMenu(void); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index f89eb0db8..c10ef7762 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -4538,6 +4538,104 @@ void M_DrawPause(void) } } +void M_DrawKickHandler(void) +{ + // fake round queue drawer simply to make release + INT32 x = 29 + 4, y = 70, returny = y; + INT32 pokeamount = (playerkickmenu.poke & 1) ? -playerkickmenu.poke/2 : playerkickmenu.poke/2; + INT32 x2 = x + pokeamount - 9 - 8; + + boolean datarightofcolumn = false; + + patch_t *resbar = W_CachePatchName("R_RESBAR", PU_CACHE); // Results bars for players + + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + V_DrawMappedPatch( + x, y, + (playeringame[i] == true) + ? ((players[i].spectator == true) ? V_TRANSLUCENT : 0) + : V_MODULATE, + resbar, NULL + ); + + V_DrawRightAlignedThinString( + x+13, y-2, + ((i == playerkickmenu.player) + ? highlightflags + : 0 + ), + va("%u", i) + ); + + if (playeringame[i] == true) + { + if (players[i].skincolor != SKINCOLOR_NONE) + { + UINT8 *charcolormap; + if ((players[i].pflags & PF_NOCONTEST) && players[i].bot) + { + // RETIRED !! + charcolormap = R_GetTranslationColormap(TC_DEFAULT, players[i].skincolor, GTC_CACHE); + V_DrawMappedPatch(x+14, y-5, 0, W_CachePatchName("MINIDEAD", PU_CACHE), charcolormap); + } + else + { + charcolormap = R_GetTranslationColormap(players[i].skin, players[i].skincolor, GTC_CACHE); + V_DrawMappedPatch(x+14, y-5, 0, faceprefix[players[i].skin][FACE_MINIMAP], charcolormap); + } + } + + V_DrawThinString( + x+27, y-2, + ( + P_IsMachineLocalPlayer(&players[i]) + ? highlightflags + : 0 + )|V_ALLOWLOWERCASE|V_6WIDTHSPACE, + player_names[i] + ); + + V_DrawRightAlignedThinString( + x+118, y-2, + V_ALLOWLOWERCASE|V_6WIDTHSPACE, + (players[i].spectator) ? "SPECTATOR" : "PLAYING" + ); + } + + if (i == playerkickmenu.player) + { + V_DrawScaledPatch( + x2, y-1, + (datarightofcolumn ? V_FLIP : 0), + W_CachePatchName("M_CURSOR", PU_CACHE) + ); + } + + y += 13; + + if (i == (MAXPLAYERS-1)/2) + { + x = 169 - 4; + y = returny; + + datarightofcolumn = true; + x2 = x + 118 + 9 + 8 + 4 - pokeamount; + } + } + + //V_DrawFill(32 + (playerkickmenu.player & 8), 32 + (playerkickmenu.player & 7)*8, 8, 8, playeringame[playerkickmenu.player] ? 0 : 16); + + V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("MENUHINT", PU_CACHE), NULL); + V_DrawCenteredThinString( + BASEVIDWIDTH/2, 12, + V_ALLOWLOWERCASE|V_6WIDTHSPACE, + K_GetMidVoteLabel(menucallvote) + ); +} + void M_DrawPlaybackMenu(void) { INT16 i; diff --git a/src/menus/transient/CMakeLists.txt b/src/menus/transient/CMakeLists.txt index 1b9309749..aa1397595 100644 --- a/src/menus/transient/CMakeLists.txt +++ b/src/menus/transient/CMakeLists.txt @@ -8,6 +8,7 @@ target_sources(SRB2SDL2 PRIVATE discord-requests.c message-box.c pause-game.c + pause-kick.c pause-replay.c virtual-keyboard.c ) diff --git a/src/menus/transient/pause-game.c b/src/menus/transient/pause-game.c index cac1c1280..29ae32177 100644 --- a/src/menus/transient/pause-game.c +++ b/src/menus/transient/pause-game.c @@ -333,8 +333,8 @@ void M_HandlePauseMenuCallVote(INT32 choice) } else if (K_MidVoteTypeUsesVictim(menucallvote) == true) { - // Not yet implemented. - S_StartSound(NULL, sfx_s3k7b); + S_StartSound(NULL, sfx_s3k5b); + M_KickHandler(-1); } else { diff --git a/src/menus/transient/pause-kick.c b/src/menus/transient/pause-kick.c new file mode 100644 index 000000000..2340406ee --- /dev/null +++ b/src/menus/transient/pause-kick.c @@ -0,0 +1,112 @@ +/// \file menus/transient/pause-kick.c +/// \brief Player Kick menu + +#include "../../k_menu.h" +#include "../../s_sound.h" +#include "../../p_local.h" +#include "../../k_zvote.h" + +struct playerkickmenu_s playerkickmenu; + +static void M_PlayerKickHandler(INT32 choice) +{ + const UINT8 pid = 0; + + (void)choice; + + if (menucmd[pid].dpad_lr != 0) // symmetrical in this case + { + S_StartSound(NULL, sfx_s3k5b); + + playerkickmenu.player = ((playerkickmenu.player + 8) % MAXPLAYERS); + + M_SetMenuDelay(pid); + } + + else if (menucmd[pid].dpad_ud > 0) + { + S_StartSound(NULL, sfx_s3k5b); + + playerkickmenu.player = ((playerkickmenu.player + 1) & 7) + (playerkickmenu.player & 8); + + M_SetMenuDelay(pid); + } + + else if (menucmd[pid].dpad_ud < 0) + { + S_StartSound(NULL, sfx_s3k5b); + + playerkickmenu.player = ((playerkickmenu.player + 7) & 7) + (playerkickmenu.player & 8); + + M_SetMenuDelay(pid); + } + + else if (M_MenuBackPressed(pid)) + { + M_GoBack(0); + M_SetMenuDelay(pid); + } + + else if (M_MenuConfirmPressed(pid)) + { + M_SetMenuDelay(pid); + + if ( + playeringame[playerkickmenu.player] + && P_IsMachineLocalPlayer(&players[playerkickmenu.player]) == false + && playerkickmenu.player != serverplayer + ) + { + if ( + K_MinimalCheckNewMidVote(menucallvote) == true +#ifndef DEVELOP + && IsPlayerAdmin(playerkickmenu.player) == false +#endif + ) + { + M_ClearMenus(true); + K_SendCallMidVote(menucallvote, playerkickmenu.player); + return; + } + } + + playerkickmenu.poke = 8; + S_StartSound(NULL, sfx_s3k7b); + } +} + +static menuitem_t PAUSE_KickHandler[] = +{ + {IT_NOTHING | IT_KEYHANDLER, NULL, NULL, NULL, {.routine = M_PlayerKickHandler}, 0, 0}, +}; + +static void M_KickHandlerTick(void) +{ + playerkickmenu.ticker++; + + if (playerkickmenu.poke) + playerkickmenu.poke--; +} + +menu_t PAUSE_KickHandlerDef = { + sizeof(PAUSE_KickHandler) / sizeof(menuitem_t), + &PAUSE_MainDef, + 0, + PAUSE_KickHandler, + 0, 0, + 0, 0, + 0, + NULL, + 0, 0, + M_DrawKickHandler, + M_KickHandlerTick, + NULL, + NULL, + NULL, +}; + +void M_KickHandler(INT32 choice) +{ + PAUSE_KickHandlerDef.prevMenu = currentMenu; + M_SetupNextMenu(&PAUSE_KickHandlerDef, true); +} From 685e1b019f97eb9e4a0ace2d5a6eaa8199170c46 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 27 Jun 2023 23:59:46 +0100 Subject: [PATCH 10/13] Actually pay attention to K_PlayerIDAllowedInMidVote for access to calling votes --- src/k_menudraw.c | 4 ++++ src/k_zvote.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index c10ef7762..4d3f138e4 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -4384,6 +4384,10 @@ void M_DrawPause(void) if (g_midVote.delay != 1) maintext = va("%u", ((g_midVote.delay - 1) / TICRATE) + 1); } + else if (K_PlayerIDAllowedInMidVote(consoleplayer) == false) + { + maintext = "SPECTATING"; + } else { maintext = "INVALID!?"; diff --git a/src/k_zvote.c b/src/k_zvote.c index 8f6ba9e95..8ce9fde7e 100644 --- a/src/k_zvote.c +++ b/src/k_zvote.c @@ -575,6 +575,12 @@ boolean K_MinimalCheckNewMidVote(midVoteType_e type) return false; } + if (K_PlayerIDAllowedInMidVote(consoleplayer) == false) + { + // Invalid calling player. + return false; + } + return true; } From dee753d979e78d2efd3b47209761886274b322c5 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 28 Jun 2023 00:02:09 +0100 Subject: [PATCH 11/13] Admin Tools menu Just a superpowered version of the Call Votekick menu, also just to make release cleanly --- src/k_menu.h | 2 ++ src/k_menudraw.c | 4 +++- src/menus/transient/pause-game.c | 11 ++++++++++- src/menus/transient/pause-kick.c | 25 ++++++++++++++++++++++++- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 6d21212d0..888ecb181 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -453,6 +453,7 @@ typedef enum mpause_discordrequests, #endif mpause_callvote, + mpause_admin, mpause_continue, mpause_spectate, @@ -1088,6 +1089,7 @@ extern struct playerkickmenu_s { tic_t ticker; UINT8 player; UINT8 poke; + boolean adminpowered; } playerkickmenu; void M_KickHandler(INT32 choice); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 4d3f138e4..40f96c9c7 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -4636,7 +4636,9 @@ void M_DrawKickHandler(void) V_DrawCenteredThinString( BASEVIDWIDTH/2, 12, V_ALLOWLOWERCASE|V_6WIDTHSPACE, - K_GetMidVoteLabel(menucallvote) + (playerkickmenu.adminpowered) + ? "You are using ""\x85""Admin Tools""\x80"", ""\x83""(A)""\x80"" to kick and ""\x84""(C)""\x80"" to ban" + : K_GetMidVoteLabel(menucallvote) ); } diff --git a/src/menus/transient/pause-game.c b/src/menus/transient/pause-game.c index 29ae32177..2e73fe040 100644 --- a/src/menus/transient/pause-game.c +++ b/src/menus/transient/pause-game.c @@ -43,6 +43,9 @@ menuitem_t PAUSE_Main[] = {IT_STRING | IT_ARROWS, "CALL VOTE", "M_ICOVOT", NULL, {.routine = M_HandlePauseMenuCallVote}, 0, 0}, + {IT_STRING | IT_ARROWS, "ADMIN TOOLS", "M_ICOADM", + NULL, {.routine = M_KickHandler}, 0, 0}, + {IT_STRING | IT_CALL, "RESUME GAME", "M_ICOUNP", NULL, {.routine = M_QuitPauseMenu}, 0, 0}, @@ -128,6 +131,7 @@ void M_OpenPauseMenu(void) PAUSE_Main[mpause_restartmap].status = IT_DISABLED; PAUSE_Main[mpause_tryagain].status = IT_DISABLED; PAUSE_Main[mpause_callvote].status = IT_DISABLED; + PAUSE_Main[mpause_admin].status = IT_DISABLED; #ifdef HAVE_DISCORDRPC PAUSE_Main[mpause_discordrequests].status = IT_DISABLED; #endif @@ -161,6 +165,11 @@ void M_OpenPauseMenu(void) { PAUSE_Main[mpause_addons].status = IT_STRING | IT_CALL; } + + if (netgame) + { + PAUSE_Main[mpause_admin].status = IT_STRING | IT_CALL; + } } } else if (!netgame && !demo.playback) @@ -183,7 +192,7 @@ void M_OpenPauseMenu(void) } } - if (netgame) + if (netgame && (PAUSE_Main[mpause_admin].status == IT_DISABLED)) { menucallvote = K_GetNextAllowedMidVote(menucallvote, true); diff --git a/src/menus/transient/pause-kick.c b/src/menus/transient/pause-kick.c index 2340406ee..2f4a83ab5 100644 --- a/src/menus/transient/pause-kick.c +++ b/src/menus/transient/pause-kick.c @@ -12,6 +12,8 @@ static void M_PlayerKickHandler(INT32 choice) { const UINT8 pid = 0; + UINT8 kicktype = UINT8_MAX; + (void)choice; if (menucmd[pid].dpad_lr != 0) // symmetrical in this case @@ -47,7 +49,17 @@ static void M_PlayerKickHandler(INT32 choice) M_SetMenuDelay(pid); } + else if (M_MenuExtraPressed(pid) && playerkickmenu.adminpowered) + { + kicktype = KICK_MSG_BANNED; + } + else if (M_MenuConfirmPressed(pid)) + { + kicktype = KICK_MSG_KICKED; + } + + if (kicktype != UINT8_MAX) { M_SetMenuDelay(pid); @@ -57,7 +69,16 @@ static void M_PlayerKickHandler(INT32 choice) && playerkickmenu.player != serverplayer ) { - if ( + if (playerkickmenu.adminpowered) + { + if (consoleplayer == serverplayer || IsPlayerAdmin(consoleplayer)) + { + playerkickmenu.poke = (kicktype == KICK_MSG_BANNED) ? 16 : 12; + SendKick(playerkickmenu.player, kicktype); + return; + } + } + else if ( K_MinimalCheckNewMidVote(menucallvote) == true #ifndef DEVELOP && IsPlayerAdmin(playerkickmenu.player) == false @@ -107,6 +128,8 @@ menu_t PAUSE_KickHandlerDef = { void M_KickHandler(INT32 choice) { + playerkickmenu.adminpowered = (choice >= 0); + PAUSE_KickHandlerDef.prevMenu = currentMenu; M_SetupNextMenu(&PAUSE_KickHandlerDef, true); } From 97dd516568a1b2cc89a13683b9251b8786f2995e Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 28 Jun 2023 00:07:39 +0100 Subject: [PATCH 12/13] Unrelated Pause Menu bugfix: Only permit GP "TRY AGAIN" option in GS_LEVEL, given it's buggy right now (we can change it back when it's fixed) --- src/menus/transient/pause-game.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/menus/transient/pause-game.c b/src/menus/transient/pause-game.c index 2e73fe040..a26e1df14 100644 --- a/src/menus/transient/pause-game.c +++ b/src/menus/transient/pause-game.c @@ -175,7 +175,11 @@ void M_OpenPauseMenu(void) else if (!netgame && !demo.playback) { boolean retryallowed = (modeattacking != ATTACKING_NONE); - if (G_GametypeUsesLives()) + if ( + retryallowed == false + && gamestate == GS_LEVEL + && G_GametypeUsesLives() + ) { for (i = 0; i <= splitscreen; i++) { From cc73279756b0af3f8a88218ce97281506589d38d Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 28 Jun 2023 00:37:30 +0100 Subject: [PATCH 13/13] Allow both CALL VOTE and ADMIN TOOLS in pause menu Also slight re-ordering --- src/k_menu.h | 2 +- src/menus/transient/pause-game.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 888ecb181..921e0ecea 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -452,8 +452,8 @@ typedef enum #ifdef HAVE_DISCORDRPC mpause_discordrequests, #endif - mpause_callvote, mpause_admin, + mpause_callvote, mpause_continue, mpause_spectate, diff --git a/src/menus/transient/pause-game.c b/src/menus/transient/pause-game.c index a26e1df14..9a24e77ca 100644 --- a/src/menus/transient/pause-game.c +++ b/src/menus/transient/pause-game.c @@ -40,12 +40,12 @@ menuitem_t PAUSE_Main[] = NULL, {.routine = M_DiscordRequests}, 0, 0}, #endif - {IT_STRING | IT_ARROWS, "CALL VOTE", "M_ICOVOT", - NULL, {.routine = M_HandlePauseMenuCallVote}, 0, 0}, - {IT_STRING | IT_ARROWS, "ADMIN TOOLS", "M_ICOADM", NULL, {.routine = M_KickHandler}, 0, 0}, + {IT_STRING | IT_ARROWS, "CALL VOTE", "M_ICOVOT", + NULL, {.routine = M_HandlePauseMenuCallVote}, 0, 0}, + {IT_STRING | IT_CALL, "RESUME GAME", "M_ICOUNP", NULL, {.routine = M_QuitPauseMenu}, 0, 0}, @@ -196,7 +196,7 @@ void M_OpenPauseMenu(void) } } - if (netgame && (PAUSE_Main[mpause_admin].status == IT_DISABLED)) + if (netgame) // && (PAUSE_Main[mpause_admin].status == IT_DISABLED)) { menucallvote = K_GetNextAllowedMidVote(menucallvote, true);