Merge branch 'splitscreen-spectate-switch' into 'master'

Splitscreen Spectate Switch (resolves #981)

Closes #981

See merge request KartKrew/Kart!1964
This commit is contained in:
Oni 2024-02-29 00:53:02 +00:00
commit 762a029dd9
5 changed files with 222 additions and 67 deletions

View file

@ -3708,11 +3708,15 @@ static void Got_Teamchange(const UINT8 **cp, INT32 playernum)
//Now that we've done our error checking and killed the player
//if necessary, put the player on the correct team/status.
// This serves us in both teamchange contexts.
if (NetPacket.packet.newteam != 0)
{
// This serves us in both teamchange contexts.
players[playernum].pflags |= PF_WANTSTOJOIN;
}
else
{
players[playernum].pflags &= ~PF_WANTSTOJOIN;
}
if (G_GametypeHasTeams())
{

View file

@ -497,10 +497,7 @@ typedef enum
mpause_tryagain,
mpause_continue,
mpause_spectate,
mpause_entergame,
mpause_canceljoin,
mpause_spectatemenu,
mpause_spectatetoggle,
mpause_psetup,
mpause_cheats,
mpause_options,
@ -1151,6 +1148,8 @@ extern struct pausemenu_s {
menu_anim_t openoffset; // Used when you open / close the menu to slide everything in.
boolean closing; // When this is set, the open offset goes backwards to close the menu smoothly.
UINT8 splitscreenfocusid; // This is not exclusively visual, but thog dont care. For selecting splitscreen players to individually change their spectator state.
} pausemenu;
void M_OpenPauseMenu(void);
@ -1174,9 +1173,7 @@ extern consvar_t cv_dummyspectator;
void M_RestartMap(INT32 choice); // Restart level (MP)
void M_TryAgain(INT32 choice); // Try again (SP)
void M_GiveUp(INT32 choice); // Give up (SP)
void M_ConfirmSpectate(INT32 choice); // Spectate confirm when you're alone
void M_ConfirmEnterGame(INT32 choice); // Enter game confirm when you're alone
void M_ConfirmSpectateChange(INT32 choice); // Splitscreen spectate/play menu func
void M_HandleSpectateToggle(INT32 choice); // Spectate confirm
void M_EndGame(INT32 choice); // Quitting to title
// Replay Playback

View file

@ -5528,6 +5528,24 @@ void M_DrawPause(void)
fixed_t t = M_DueFrac(pausemenu.offset.start, 3);
UINT8 splitspectatestate = 0;
if (G_GametypeHasSpectators() && pausemenu.splitscreenfocusid <= splitscreen)
{
// Identify relevant spectator state of pausemenu.splitscreenfocusid.
// See also M_HandleSpectatorToggle.
const UINT8 splitspecid =
g_localplayers[pausemenu.splitscreenfocusid];
if (players[splitspecid].spectator)
{
splitspectatestate =
(players[splitspecid].pflags & PF_WANTSTOJOIN)
? UINT8_MAX
: 1;
}
}
//V_DrawFadeScreen(0xFF00, 16);
{
@ -5630,7 +5648,6 @@ void M_DrawPause(void)
while (itemsdrawn < 7)
{
switch (currentMenu->menuitems[i].status & IT_DISPLAY)
{
case IT_STRING:
@ -5644,6 +5661,17 @@ void M_DrawPause(void)
va("M_ICOR2%c", ('A'+(pausemenu.ticker & 1))),
PU_CACHE);
}
else if (i == mpause_spectatetoggle)
{
pp = W_CachePatchName(
((splitspectatestate == 1)
? "M_ICOENT"
: "M_ICOSPC"
), PU_CACHE
);
if (i == itemOn)
colormap = yellowmap;
}
else
{
pp = W_CachePatchName(currentMenu->menuitems[i].tooltip, PU_CACHE);
@ -5668,29 +5696,30 @@ void M_DrawPause(void)
}
}
i++; // Regardless of whether we drew or not, go to the next item in the menu.
if (i >= currentMenu->numitems)
{
i = 0;
while (!(currentMenu->menuitems[i].status & IT_DISPLAY))
i++;
}
}
// Draw the string!
const char *maintext = NULL;
const char *selectableheadertext = NULL;
const char *selectabletext = NULL;
INT32 mainflags = V_YELLOWMAP, selectableflags = 0;
INT32 mainflags = 0, selectableflags = 0;
if (itemOn == mpause_changegametype)
{
selectableheadertext = currentMenu->menuitems[itemOn].text;
selectabletext = gametypes[menugametype]->name;
}
else if (itemOn == mpause_callvote)
{
selectableheadertext = currentMenu->menuitems[itemOn].text;
selectabletext = K_GetMidVoteLabel(menucallvote);
if (K_MinimalCheckNewMidVote(menucallvote) == false)
@ -5714,22 +5743,57 @@ void M_DrawPause(void)
}
if (maintext != NULL)
{
mainflags |= V_YELLOWMAP;
selectableflags |= V_MODULATE;
}
}
}
else if (itemOn == mpause_spectatetoggle)
{
const char *spectatetext = NULL;
INT32 spectateflags = 0;
if (splitspectatestate == 0)
spectatetext = "SPECTATE";
else if (splitspectatestate == 1)
{
spectatetext = "ENTER GAME";
if (!cv_allowteamchange.value)
{
spectateflags |= V_MODULATE;
}
}
else
spectatetext = "CANCEL JOIN";
if (splitscreen)
{
selectableheadertext = spectatetext;
selectabletext = va("PLAYER %c", 'A' + pausemenu.splitscreenfocusid);
selectableflags |= spectateflags;
}
else
{
maintext = spectatetext;
mainflags |= spectateflags;
}
}
else
{
maintext = currentMenu->menuitems[itemOn].text;
mainflags = 0;
}
if (selectableheadertext != NULL)
{
// For selections, show the full menu text on top.
V_DrawCenteredLSTitleHighString(220 + offset*2, 75, selectableflags, selectableheadertext);
}
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);
// The selectable text is shown below.
selectableflags |= V_YELLOWMAP;
INT32 w = V_LSTitleLowStringWidth(selectabletext, selectableflags)/2;

View file

@ -385,19 +385,63 @@ boolean M_Responder(event_t *ev)
}
#endif
// Attack modes quick-restart
if (CON_Ready() == false && modeattacking && G_PlayerInputDown(0, gc_y, splitscreen + 1) == true)
if (CON_Ready() == false)
{
M_TryAgain(0);
return true;
}
boolean allowmpause = true;
if (CON_Ready() == false && G_PlayerInputDown(0, gc_start, splitscreen + 1) == true)
{
if (!chat_on)
// Special mid-game input behaviours
if (Playing() && !demo.playback)
{
M_StartControlPanel();
return true;
// Quick Retry (Y in modeattacking)
if (modeattacking && G_PlayerInputDown(0, gc_y, splitscreen + 1) == true)
{
M_TryAgain(0);
return true;
}
// Quick Spectate (L+R+A+Start online)
if (G_GametypeHasSpectators())
{
UINT8 workingpid = 0;
for (workingpid = 0; workingpid <= splitscreen; workingpid++)
{
if (players[g_localplayers[workingpid]].spectator == true)
continue;
if (G_PlayerInputDown(workingpid, gc_l, 0) == false)
continue;
if (G_PlayerInputDown(workingpid, gc_r, 0) == false)
continue;
if (G_PlayerInputDown(workingpid, gc_a, 0) == false)
continue;
if (G_PlayerInputDown(workingpid, gc_start, 0) == false)
continue;
if (workingpid == 0)
{
allowmpause = false;
COM_ImmedExecute("changeteam spectator");
continue;
}
COM_ImmedExecute(
va(
"changeteam%u spectator",
workingpid + 1
)
);
}
}
}
// Bog-standard Pause
if (allowmpause && G_PlayerInputDown(0, gc_start, splitscreen + 1) == true)
{
if (!chat_on)
{
M_StartControlPanel();
return true;
}
}
}

View file

@ -54,17 +54,8 @@ menuitem_t PAUSE_Main[] =
{IT_STRING | IT_CALL, "RESUME GAME", "M_ICOUNP",
NULL, {.routine = M_QuitPauseMenu}, 0, 0},
{IT_STRING | IT_CALL, "SPECTATE", "M_ICOSPC",
NULL, {.routine = M_ConfirmSpectate}, 0, 0},
{IT_STRING | IT_CALL, "ENTER GAME", "M_ICOENT",
NULL, {.routine = M_ConfirmEnterGame}, 0, 0},
{IT_STRING | IT_CALL, "CANCEL JOIN", "M_ICOSPC",
NULL, {.routine = M_ConfirmSpectate}, 0, 0},
{IT_STRING | IT_SUBMENU, "JOIN OR SPECTATE", "M_ICOENT",
NULL, {NULL}, 0, 0},
{IT_STRING | IT_ARROWS, "SPECTATE", "M_ICOSPC",
NULL, {.routine = M_HandleSpectateToggle}, 0, 0},
{IT_STRING | IT_CALL, "PLAYER SETUP", "M_ICOCHR",
NULL, {.routine = M_CharacterSelect}, 0, 0},
@ -142,10 +133,7 @@ void M_OpenPauseMenu(void)
PAUSE_Main[mpause_restartmap].status = IT_DISABLED;
PAUSE_Main[mpause_tryagain].status = IT_DISABLED;
PAUSE_Main[mpause_spectate].status = IT_DISABLED;
PAUSE_Main[mpause_entergame].status = IT_DISABLED;
PAUSE_Main[mpause_canceljoin].status = IT_DISABLED;
PAUSE_Main[mpause_spectatemenu].status = IT_DISABLED;
PAUSE_Main[mpause_spectatetoggle].status = IT_DISABLED;
PAUSE_Main[mpause_psetup].status = IT_DISABLED;
PAUSE_Main[mpause_cheats].status = IT_DISABLED;
@ -236,17 +224,13 @@ void M_OpenPauseMenu(void)
if (G_GametypeHasSpectators())
{
if (splitscreen)
PAUSE_Main[mpause_spectatemenu].status = IT_STRING|IT_SUBMENU;
else
if (pausemenu.splitscreenfocusid > splitscreen)
{
if (!players[consoleplayer].spectator)
PAUSE_Main[mpause_spectate].status = IT_STRING | IT_CALL;
else if (players[consoleplayer].pflags & PF_WANTSTOJOIN)
PAUSE_Main[mpause_canceljoin].status = IT_STRING | IT_CALL;
else
PAUSE_Main[mpause_entergame].status = IT_STRING | IT_CALL;
// Only futz if necessary.
pausemenu.splitscreenfocusid = 0;
}
PAUSE_Main[mpause_spectatetoggle].status = IT_STRING | IT_ARROWS;
}
if (CV_CheatsEnabled())
@ -462,24 +446,86 @@ void M_GiveUp(INT32 choice)
}
// Pause spectate / join functions
void M_ConfirmSpectate(INT32 choice)
{
(void)choice;
// We allow switching to spectator even if team changing is not allowed
M_QuitPauseMenu(-1);
COM_ImmedExecute("changeteam spectator");
}
void M_ConfirmEnterGame(INT32 choice)
{
(void)choice;
if (!cv_allowteamchange.value)
void M_HandleSpectateToggle(INT32 choice)
{
if (choice == 2)
{
M_StartMessage("Team Change", M_GetText("The server is not allowing\nteam changes at this time.\n"), NULL, MM_NOTHING, NULL, NULL);
if (!(G_GametypeHasSpectators() && pausemenu.splitscreenfocusid <= splitscreen))
{
M_StartMessage("Team Change", va("You can't change spectator status right now. (Player %c)", ('A' + pausemenu.splitscreenfocusid)), NULL, MM_NOTHING, NULL, NULL);
return;
}
boolean tospectator = false;
{
// Identify relevant spectator state of pausemenu.splitscreenfocusid.
// See also M_DrawPause.
const UINT8 splitspecid =
g_localplayers[pausemenu.splitscreenfocusid];
tospectator = (
players[splitspecid].spectator == false
|| (players[splitspecid].pflags & PF_WANTSTOJOIN)
);
}
if (!tospectator && !cv_allowteamchange.value)
{
M_StartMessage("Team Change", M_GetText("The server is not allowing\nteam changes at this time.\n"), NULL, MM_NOTHING, NULL, NULL);
return;
}
M_QuitPauseMenu(-1);
const char *destinationstate = tospectator ? "spectator" : "playing";
// These console command names...
if (pausemenu.splitscreenfocusid == 0)
{
COM_ImmedExecute(
va(
"changeteam %s",
destinationstate
)
);
}
else
{
COM_ImmedExecute(
va(
"changeteam%u %s",
pausemenu.splitscreenfocusid + 1,
destinationstate
)
);
}
return;
}
M_QuitPauseMenu(-1);
COM_ImmedExecute("changeteam playing");
if (splitscreen == 0)
return;
if (choice == 0) // left
{
if (pausemenu.splitscreenfocusid)
pausemenu.splitscreenfocusid--;
else
pausemenu.splitscreenfocusid = splitscreen;
}
else if (choice == 1) // right
{
if (pausemenu.splitscreenfocusid < splitscreen)
pausemenu.splitscreenfocusid++;
else
pausemenu.splitscreenfocusid = 0;
}
else // reset
{
pausemenu.splitscreenfocusid = 0;
}
S_StartSound(NULL, sfx_s3k5b);
}
static void M_ExitGameResponse(INT32 ch)