diff --git a/src/k_menu.h b/src/k_menu.h index b6eacb6fc..d84d97414 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -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 diff --git a/src/k_menudraw.c b/src/k_menudraw.c index d07be720a..bb9205fe2 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -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; diff --git a/src/menus/transient/pause-game.c b/src/menus/transient/pause-game.c index 7991b4ab1..48c999736 100644 --- a/src/menus/transient/pause-game.c +++ b/src/menus/transient/pause-game.c @@ -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)