Merge branch 'zvote-menu' into 'master'

Call Vote + Admin Tools Menus

See merge request KartKrew/Kart!1303
This commit is contained in:
Oni 2023-06-28 00:24:32 +00:00
commit 1217934693
13 changed files with 704 additions and 122 deletions

View file

@ -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

View file

@ -5648,6 +5648,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))))
@ -5658,7 +5674,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"));
}
@ -5684,6 +5700,9 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
return;
}
if (G_GamestateUsesExitLevel() == false)
return;
G_ExitLevel();
}

View file

@ -242,6 +242,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);

View file

@ -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
//
@ -415,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;
@ -447,6 +452,8 @@ typedef enum
#ifdef HAVE_DISCORDRPC
mpause_discordrequests,
#endif
mpause_admin,
mpause_callvote,
mpause_continue,
mpause_spectate,
@ -1078,6 +1085,15 @@ 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;
boolean adminpowered;
} playerkickmenu;
void M_KickHandler(INT32 choice);
extern consvar_t cv_dummymenuplayer;
extern consvar_t cv_dummyspectator;
@ -1150,6 +1166,7 @@ void M_DrawMPServerBrowser(void);
// Pause menu:
void M_DrawPause(void);
void M_DrawKickHandler(void);
// Replay Playback
void M_DrawPlaybackMenu(void);

View file

@ -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
@ -3065,7 +3066,7 @@ void M_DrawMPHost(void)
}
break;
}
case IT_KEYHANDLER:
case IT_ARROWS:
{
if (currentMenu->menuitems[i].itemaction.routine != M_HandleHostMenuGametype)
break;
@ -4262,11 +4263,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,54 +4360,107 @@ 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 *maintext = NULL;
const char *selectabletext = NULL;
INT32 mainflags = V_YELLOWMAP, selectableflags = 0;
if (itemOn == mpause_changegametype)
{
INT32 w = V_LSTitleLowStringWidth(gametypes[menugametype]->name, 0)/2;
selectabletext = gametypes[menugametype]->name;
}
else if (itemOn == mpause_callvote)
{
selectabletext = K_GetMidVoteLabel(menucallvote);
if (word1len)
V_DrawCenteredLSTitleHighString(220 + offset*2, 75, 0, word1);
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 if (K_PlayerIDAllowedInMidVote(consoleplayer) == false)
{
maintext = "SPECTATING";
}
else
{
maintext = "INVALID!?";
}
V_DrawLSTitleLowString(220-w + offset*2, 103, V_YELLOWMAP, gametypes[menugametype]->name);
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
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.
if (currentMenu->menuitems[itemOn].text)
V_DrawCenteredLSTitleHighString(220 + offset*2, 75, selectableflags, currentMenu->menuitems[itemOn].text);
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
}
if (maintext != NULL)
{
// 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 (maintext[j] && j < MAXSTRINGLENGTH)
{
if (maintext[j] == ' ' && !sok)
{
sok = true;
j++;
continue; // We don't care about this :moyai:
}
if (sok)
{
word2[word2len] = maintext[j];
word2len++;
}
else
{
word1[word1len] = maintext[j];
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);
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)
@ -4493,6 +4542,106 @@ 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,
(playerkickmenu.adminpowered)
? "You are using ""\x85""Admin Tools""\x80"", ""\x83""(A)""\x80"" to kick and ""\x84""(C)""\x80"" to ban"
: K_GetMidVoteLabel(menucallvote)
);
}
void M_DrawPlaybackMenu(void)
{
INT16 i;

View file

@ -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,29 @@ static void K_MidVoteKick(void)
--------------------------------------------------*/
static void K_MidVoteRockTheVote(void)
{
G_ExitLevel();
if (G_GamestateUsesExitLevel() == false)
{
return;
}
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] =
@ -88,22 +107,21 @@ 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
},
};
/*--------------------------------------------------
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)
{
@ -125,9 +143,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;
@ -136,8 +151,6 @@ static void Command_CallVote(void)
const char *voteVariableStr = NULL;
INT32 voteVariable = 0;
player_t *victim = NULL;
INT32 i = INT32_MAX;
if (netgame == false)
@ -184,11 +197,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];
}
}
@ -198,6 +226,9 @@ static void Command_CallVote(void)
return;
}
UINT8 buf[MAXTEXTCMD];
UINT8 *buf_p = buf;
WRITEUINT8(buf_p, voteType);
WRITEINT32(buf_p, voteVariable);
@ -341,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)
@ -468,6 +544,46 @@ 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;
}
if (K_PlayerIDAllowedInMidVote(consoleplayer) == false)
{
// Invalid calling player.
return false;
}
return true;
}
/*--------------------------------------------------
boolean K_AllowNewMidVote(player_t *caller, midVoteType_e type, INT32 variable, player_t *victim)
@ -630,7 +746,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();
}
@ -823,6 +943,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)
@ -1006,11 +1145,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(
@ -1018,7 +1159,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

View file

@ -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;
@ -63,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);
@ -99,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);
@ -170,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);
@ -263,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);

View file

@ -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)
{

View file

@ -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);
}
}

View file

@ -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
)

View file

@ -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"
@ -22,7 +23,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",
@ -39,6 +40,12 @@ menuitem_t PAUSE_Main[] =
NULL, {.routine = M_DiscordRequests}, 0, 0},
#endif
{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},
@ -71,7 +78,7 @@ menu_t PAUSE_MainDef = {
PAUSE_Main,
0, 0,
0, 0,
0,
MBF_SOUNDLESS,
NULL,
1, 10, // For transition with some menus!
M_DrawPause,
@ -123,6 +130,8 @@ 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;
PAUSE_Main[mpause_admin].status = IT_DISABLED;
#ifdef HAVE_DISCORDRPC
PAUSE_Main[mpause_discordrequests].status = IT_DISABLED;
#endif
@ -146,7 +155,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;
@ -156,12 +165,21 @@ 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)
{
boolean retryallowed = (modeattacking != ATTACKING_NONE);
if (G_GametypeUsesLives())
if (
retryallowed == false
&& gamestate == GS_LEVEL
&& G_GametypeUsesLives()
)
{
for (i = 0; i <= splitscreen; i++)
{
@ -178,6 +196,18 @@ void M_OpenPauseMenu(void)
}
}
if (netgame) // && (PAUSE_Main[mpause_admin].status == IT_DISABLED))
{
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)
@ -267,12 +297,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,27 +308,60 @@ 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);
}
}
// 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)
{
S_StartSound(NULL, sfx_s3k5b);
M_KickHandler(-1);
}
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

View file

@ -0,0 +1,135 @@
/// \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;
UINT8 kicktype = UINT8_MAX;
(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_MenuExtraPressed(pid) && playerkickmenu.adminpowered)
{
kicktype = KICK_MSG_BANNED;
}
else if (M_MenuConfirmPressed(pid))
{
kicktype = KICK_MSG_KICKED;
}
if (kicktype != UINT8_MAX)
{
M_SetMenuDelay(pid);
if (
playeringame[playerkickmenu.player]
&& P_IsMachineLocalPlayer(&players[playerkickmenu.player]) == false
&& playerkickmenu.player != serverplayer
)
{
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
#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)
{
playerkickmenu.adminpowered = (choice >= 0);
PAUSE_KickHandlerDef.prevMenu = currentMenu;
M_SetupNextMenu(&PAUSE_KickHandlerDef, true);
}

View file

@ -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;