Restore menu state after playsim

- restoreMenu, M_SpecificMenuRestore
    - From any Cup Select, Level Select, or Time Attack context (including non-net replay playback), return to the relevant "core menu"
    - From any server OR server connection failure, return to the Online EGGA CHANNEL top-level menu
    - From netreplay, head to replay hut without incorrect gamestate/fade cope
    - Interruption for Challenges unlock sequence now happens on all menu returns, not just post-titlescreen
- M_StartControlPanel
    - Integrate with above
    - Handle menu re-initialisation properly under more contexts
- D_ClearState
    - Split out from D_StartTitle
    - Can be used alongside M_StartControlPanel to restore menu state from any play session in a way just as reliable as D_StartTitle was
This commit is contained in:
toaster 2023-01-29 23:53:21 +00:00
parent 154d9c5f18
commit 20e9b2f5e8
16 changed files with 220 additions and 104 deletions

View file

@ -1533,7 +1533,8 @@ static boolean CL_FinishedFileList(void)
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
M_StartMessage(M_GetText(
"You have too many WAD files loaded\n"
"to add ones the server is using.\n"
@ -1546,7 +1547,8 @@ static boolean CL_FinishedFileList(void)
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
M_StartMessage(M_GetText(
"You have the wrong addons loaded.\n\n"
"To play on this server, restart\n"
@ -1713,7 +1715,8 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
M_StartMessage(va(
"Your EXE differs from the server.\n"
@ -1864,7 +1867,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
M_StartMessage(M_GetText(
"The direct download encountered an error.\n"
"See the logfile for more info.\n"
@ -1893,7 +1897,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
M_StartMessage(M_GetText(
"5 minute wait time exceeded.\n"
"You may retry connection.\n"
@ -1982,7 +1987,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
return false;
}
@ -2507,6 +2513,7 @@ static void Command_connect(void)
SplitScreen_OnChange();
}
restoreMenu = &PLAY_MP_OptSelectDef;
CL_ConnectToServer();
}
@ -3142,7 +3149,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
if (msg == KICK_MSG_CON_FAIL)
M_StartMessage(M_GetText("Server closed connection\n(Synch failure)\nPress (B)\n"), NULL, MM_NOTHING);
@ -4169,7 +4177,8 @@ static void HandleShutdown(SINT8 node)
LUA_HookBool(false, HOOK(GameQuit));
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
M_StartMessage(M_GetText("Server has shutdown\n\nPress (B)\n"), NULL, MM_NOTHING);
}
@ -4184,7 +4193,8 @@ static void HandleTimeout(SINT8 node)
LUA_HookBool(false, HOOK(GameQuit));
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
M_StartMessage(M_GetText("Server Timeout\n\nPress (B)\n"), NULL, MM_NOTHING);
}
@ -4370,7 +4380,8 @@ static void HandlePacketFromAwayNode(SINT8 node)
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
if (reason[1] == '|')
{

View file

@ -915,9 +915,9 @@ void D_SRB2Loop(void)
// =========================================================================
//
// D_StartTitle
// D_ClearState
//
void D_StartTitle(void)
void D_ClearState(void)
{
INT32 i;
@ -932,7 +932,7 @@ void D_StartTitle(void)
i = G_GetFirstMapOfGametype(gametype)+1;
if (i > nummapheaders)
I_Error("D_StartTitle: No valid map ID found!?");
I_Error("D_ClearState: No valid map ID found!?");
COM_BufAddText(va("map %s\n", G_BuildMapName(i)));
}
@ -979,15 +979,27 @@ void D_StartTitle(void)
memset(gamekeydown, 0, sizeof (gamekeydown));
memset(deviceResponding, false, sizeof (deviceResponding));
F_StartTitleScreen();
M_ClearMenus(false);
// Reset the palette
if (rendermode != render_none)
V_SetPaletteLump("PLAYPAL");
// The title screen is obviously not a tutorial! (Unless I'm mistaken)
tutorialmode = false;
G_SetGamestate(GS_NULL);
}
//
// D_StartTitle
//
void D_StartTitle(void)
{
D_ClearState();
if (netgame)
return;
F_StartTitleScreen();
M_ClearMenus(false);
}
//

View file

@ -57,6 +57,7 @@ const char *D_Home(void);
//
// BASE LEVEL
//
void D_ClearState(void);
void D_StartTitle(void);
#ifdef __cplusplus

View file

@ -2971,6 +2971,7 @@ static void Command_Map_f(void)
if (!Playing())
{
multiplayer = true;
restoreMenu = NULL;
}
}
@ -5782,7 +5783,10 @@ void Command_ExitGame_f(void)
closefilemenu(true);
if (!modeattacking)
D_StartTitle();
{
D_ClearState();
M_StartControlPanel();
}
}
void Command_Retry_f(void)

View file

@ -2990,7 +2990,8 @@ void G_ExitLevel(void)
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
D_ClearState();
M_StartControlPanel();
}
}
else
@ -4003,15 +4004,7 @@ void G_AfterIntermission(void)
if (demo.playback)
{
G_StopDemo();
#if 0
if (demo.inreplayhut)
M_ReplayHut(0);
else
#endif
D_StartTitle();
M_PlaybackQuit(0);
return;
}
else if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING))
@ -4170,8 +4163,8 @@ void G_EndGame(void)
{
if (nextmap == NEXTMAP_CEREMONY) // end game with ceremony
{
D_StartTitle(); //F_StartEnding(); -- temporary
return;
/*F_StartEnding(); -- temporary
return;*/
}
if (nextmap == NEXTMAP_CREDITS) // end game with credits
{
@ -4186,7 +4179,8 @@ void G_EndGame(void)
}
// direct or competitive multiplayer, so go back to title screen.
D_StartTitle();
D_ClearState();
M_StartControlPanel();
}
//

View file

@ -466,6 +466,8 @@ typedef enum
void Moviemode_option_Onchange(void);
extern menu_t *currentMenu;
extern menu_t *restoreMenu;
extern char dummystaffname[22];
extern consvar_t cv_dummystaff;
@ -583,6 +585,7 @@ boolean M_MenuExtraPressed(UINT8 pid);
boolean M_MenuExtraHeld(UINT8 pid);
void M_StartControlPanel(void);
menu_t *M_SpecificMenuRestore(menu_t *torestore);
void M_ClearMenus(boolean callexitmenufunc);
void M_SelectableClearMenus(INT32 choice);
void M_SetupNextMenu(menu_t *menudef, boolean nofade);

View file

@ -237,7 +237,7 @@ static void M_DrawMenuParty(void)
UINT16 color;
UINT8 *colormap;
if (setup_numplayers == 0 || currentMenu == &PLAY_CharSelectDef)
if (setup_numplayers == 0 || currentMenu == &PLAY_CharSelectDef || currentMenu == &MISC_ChallengesDef)
{
return;
}

View file

@ -35,6 +35,7 @@ boolean fromlevelselect = false;
// current menudef
menu_t *currentMenu = &MAIN_ProfilesDef;
menu_t *restoreMenu = NULL;
char dummystaffname[22];
@ -355,6 +356,51 @@ boolean M_Responder(event_t *ev)
return true;
}
//
// M_SpecificMenuRestore
//
menu_t *M_SpecificMenuRestore(menu_t *torestore)
{
// I'd advise the following not be a switch case because they're pointers...
if (torestore == &PLAY_CupSelectDef
|| torestore == &PLAY_LevelSelectDef
|| torestore == &PLAY_TimeAttackDef)
{
// Handle unlock restrictions
M_SetupGametypeMenu(-1);
M_SetupRaceMenu(-1);
if (!M_LevelListFromGametype(-1))
{
if (PLAY_LevelSelectDef.prevMenu == &PLAY_CupSelectDef)
{
torestore = PLAY_CupSelectDef.prevMenu;
}
else
{
torestore = PLAY_LevelSelectDef.prevMenu;
}
}
else if (torestore == &PLAY_TimeAttackDef)
{
M_PrepareTimeAttack(0);
}
}
else if (torestore == &EXTRAS_ReplayHutDef)
{
// Handle modifications to the folder while playing
M_ReplayHut(0);
}
if (setup_numplayers == 0)
{
setup_numplayers = 1;
}
return torestore;
}
//
// M_StartControlPanel
//
@ -370,32 +416,18 @@ void M_StartControlPanel(void)
}
// intro might call this repeatedly
if (menuactive)
if (menuactive && gamestate != GS_NULL)
{
CON_ToggleOff(); // move away console
return;
}
if (gamestate == GS_TITLESCREEN) // Set up menu state
if (gamestate == GS_TITLESCREEN && restoreMenu == NULL) // Set up menu state
{
// No instantly skipping the titlescreen.
// (We can change this timer later when extra animation is added.)
if (finalecount < 1)
return;
G_SetGamestate(GS_MENU);
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
if (cv_menujam_update.value)
{
CV_AddValue(&cv_menujam, 1);
CV_SetValue(&cv_menujam_update, 0);
}
S_ChangeMusicInternal(cv_menujam.string, true);
}
menuactive = true;
@ -408,6 +440,28 @@ void M_StartControlPanel(void)
{
M_StopMessage(0); // Doesn't work with MM_YESNO or MM_EVENTHANDLER... but good enough to get the game as it is currently functional again
if (gamestate != GS_MENU)
{
G_SetGamestate(GS_MENU);
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
modeattacking = ATTACKING_NONE;
if (cv_menujam_update.value)
{
CV_AddValue(&cv_menujam, 1);
CV_SetValue(&cv_menujam_update, 0);
}
S_ChangeMusicInternal(cv_menujam.string, true);
if (!restoreMenu)
restoreMenu = &MainDef;
}
if (cv_currprofile.value == -1) // Only ask once per session.
{
// Make sure the profile data is ready now since we need to select a profile.
@ -431,8 +485,10 @@ void M_StartControlPanel(void)
}
else
{
currentMenu = M_InterruptMenuWithChallenges(&MainDef);
currentMenu = M_SpecificMenuRestore(M_InterruptMenuWithChallenges(restoreMenu));
}
restoreMenu = NULL;
}
else
{

View file

@ -416,6 +416,8 @@ boolean M_ChallengesInputs(INT32 ch)
{
if (M_MenuBackPressed(pid) || start)
{
currentMenu->prevMenu = M_SpecificMenuRestore(currentMenu->prevMenu);
M_GoBack(0);
M_SetMenuDelay(pid);

View file

@ -26,11 +26,11 @@ menu_t EXTRAS_ReplayHutDef =
EXTRAS_ReplayHut,
30, 80,
0, 0,
0, 0,
41, 1,
M_DrawReplayHut,
NULL,
NULL,
M_QuitReplayHut,
NULL,
NULL
};
@ -58,7 +58,7 @@ menu_t EXTRAS_ReplayStartDef =
EXTRAS_ReplayStart,
27, 80,
0, 0,
0, 0,
41, 1,
M_DrawReplayStartMenu,
NULL,
NULL,
@ -102,37 +102,43 @@ void M_ReplayHut(INT32 choice)
{
(void)choice;
extrasmenu.replayScrollTitle = 0;
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = 1;
if (!demo.inreplayhut)
if (demo.inreplayhut)
{
demo.rewinding = false;
CL_ClearRewinds();
}
else
{
snprintf(menupath, 1024, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home);
menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath);
}
if (!preparefilemenu(false, true))
{
M_StartMessage("No replays found.\n\nPress (B)\n", NULL, MM_NOTHING);
if (restoreMenu == &EXTRAS_ReplayHutDef)
{
restoreMenu = &EXTRAS_MainDef;
}
return;
}
else if (!demo.inreplayhut)
{
dir_on[menudepthleft] = 0;
demo.inreplayhut = true;
}
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
extrasmenu.replayScrollTitle = 0;
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = 1;
M_PrepReplayList();
menuactive = true;
M_SetupNextMenu(&EXTRAS_ReplayHutDef, false);
//G_SetGamestate(GS_TIMEATTACK);
//titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
if (!demo.inreplayhut)
M_SetupNextMenu(&EXTRAS_ReplayHutDef, false);
demo.rewinding = false;
CL_ClearRewinds();
//S_ChangeMusicInternal("replst", true);
demo.inreplayhut = true;
}
// key handler
@ -223,11 +229,11 @@ void M_HandleReplayHutList(INT32 choice)
M_PrepReplayList();
break;
default:
// We can't just use M_SetupNextMenu because that'll run ReplayDef's quitroutine and boot us back to the title screen!
currentMenu->lastOn = itemOn;
currentMenu = &EXTRAS_ReplayStartDef;
M_SetupNextMenu(&EXTRAS_ReplayStartDef, false);
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
extrasmenu.replayScrollTitle = 0;
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = 1;
switch (extrasmenu.demolist[dir_on[menudepthleft]].addonstatus)
{
@ -267,16 +273,13 @@ void M_HandleReplayHutList(INT32 choice)
boolean M_QuitReplayHut(void)
{
// D_StartTitle does its own wipe, since GS_TIMEATTACK is now a complete gamestate.
menuactive = false;
D_StartTitle();
if (extrasmenu.demolist)
Z_Free(extrasmenu.demolist);
extrasmenu.demolist = NULL;
demo.inreplayhut = false;
M_GoBack(0);
return true;
}
@ -284,6 +287,8 @@ void M_HutStartReplay(INT32 choice)
{
(void)choice;
restoreMenu = &EXTRAS_ReplayHutDef;
M_ClearMenus(false);
demo.loadfiles = (itemOn == 0);
demo.ignorefiles = (itemOn != 0);

View file

@ -25,9 +25,8 @@ menu_t PLAY_GamemodesDef = KARTGAMEMODEMENU(PLAY_GamemodesMenu, &PLAY_MainDef);
void M_SetupGametypeMenu(INT32 choice)
{
(void)choice;
PLAY_GamemodesDef.prevMenu = currentMenu;
if (choice != -1)
PLAY_GamemodesDef.prevMenu = currentMenu;
// Battle and Capsules (and Special) disabled
PLAY_GamemodesMenu[1].status = IT_DISABLED;
@ -65,5 +64,6 @@ void M_SetupGametypeMenu(INT32 choice)
}
}
M_SetupNextMenu(&PLAY_GamemodesDef, false);
if (choice != -1)
M_SetupNextMenu(&PLAY_GamemodesDef, false);
}

View file

@ -22,9 +22,8 @@ menu_t PLAY_RaceGamemodesDef = KARTGAMEMODEMENU(PLAY_RaceGamemodesMenu, &PLAY_Ga
void M_SetupRaceMenu(INT32 choice)
{
(void)choice;
PLAY_RaceGamemodesDef.prevMenu = currentMenu;
if (choice != -1)
PLAY_RaceGamemodesDef.prevMenu = currentMenu;
// Time Attack disabled
PLAY_RaceGamemodesMenu[2].status = IT_DISABLED;
@ -36,5 +35,6 @@ void M_SetupRaceMenu(INT32 choice)
PLAY_RaceGamemodesMenu[2].status = IT_STRING | IT_CALL;
}
M_SetupNextMenu(&PLAY_RaceGamemodesDef, false);
if (choice != -1)
M_SetupNextMenu(&PLAY_RaceGamemodesDef, false);
}

View file

@ -290,8 +290,12 @@ void M_HandleStaffReplay(INT32 choice)
void M_ReplayTimeAttack(INT32 choice)
{
const char *which;
restoreMenu = &PLAY_TimeAttackDef;
M_ClearMenus(true);
demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed
demo.loadfiles = false;
demo.ignorefiles = true; // Just assume that record attack replays have the files needed
switch (choice)
{
@ -445,6 +449,8 @@ void M_StartTimeAttack(INT32 choice)
else
G_RecordDemo(nameofdemo);
restoreMenu = &PLAY_TimeAttackDef;
M_ClearMenus(true);
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_dummygpencore.value == 1), 1, 1, false, false);
}

View file

@ -157,6 +157,8 @@ void M_CupSelectHandler(INT32 choice)
);
M_ClearMenus(true);
restoreMenu = &PLAY_CupSelectDef;
}
else if (count == 1)
{

View file

@ -195,13 +195,14 @@ void M_LevelSelectScrollDest(void)
levellist.dest = (6*m)-3;
}
// Builds the level list we'll be using from the gametype we're choosing and send us to the apropriate menu.
// Builds the level list we'll be using from the gametype we're choosing and send us to the apropriate menu.
// A gt of -1 means the menu is being restored.
boolean M_LevelListFromGametype(INT16 gt)
{
static boolean first = true;
UINT8 temp = 0;
if (first || gt != levellist.newgametype || levellist.guessgt != MAXGAMETYPES)
if (gt != -1 && (first || gt != levellist.newgametype || levellist.guessgt != MAXGAMETYPES))
{
if (first)
{
@ -224,7 +225,6 @@ boolean M_LevelListFromGametype(INT16 gt)
}
levellist.levelsearch.cupmode = (!(gametypes[gt]->rules & GTR_NOCUPSELECT));
levellist.levelsearch.cup = NULL;
first = false;
}
@ -237,7 +237,7 @@ boolean M_LevelListFromGametype(INT16 gt)
levelsearch_t templevelsearch = levellist.levelsearch; // full copy
size_t currentid = 0, highestunlockedid = 0;
const size_t pagelen = sizeof(cupheader_t*) * (CUPMENU_COLUMNS * CUPMENU_ROWS);
boolean foundany = false;
boolean foundany = false, currentvalid = false;
templevelsearch.cup = kartcupheaders;
@ -297,11 +297,15 @@ boolean M_LevelListFromGametype(INT16 gt)
if (M_GetFirstLevelInList(&temp, &templevelsearch) != NEXTMAP_INVALID)
{
highestunlockedid = currentid;
if (Playing() && mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == templevelsearch.cup)
if (Playing()
? (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == templevelsearch.cup)
: (gt == -1 && levellist.levelsearch.cup == templevelsearch.cup))
{
cupgrid.x = currentid % CUPMENU_COLUMNS;
cupgrid.y = (currentid / CUPMENU_COLUMNS) % CUPMENU_ROWS;
cupgrid.pageno = currentid / (CUPMENU_COLUMNS * CUPMENU_ROWS);
currentvalid = true;
}
}
@ -314,15 +318,27 @@ boolean M_LevelListFromGametype(INT16 gt)
return false;
}
if (currentvalid == false)
{
levellist.levelsearch.cup = NULL;
if (gt == -1 && restoreMenu != &PLAY_CupSelectDef)
{
restoreMenu = &PLAY_CupSelectDef;
}
}
cupgrid.numpages = (highestunlockedid / (CUPMENU_COLUMNS * CUPMENU_ROWS)) + 1;
if (cupgrid.pageno >= cupgrid.numpages)
{
cupgrid.pageno = 0;
}
PLAY_CupSelectDef.prevMenu = currentMenu;
PLAY_LevelSelectDef.prevMenu = &PLAY_CupSelectDef;
M_SetupNextMenu(&PLAY_CupSelectDef, false);
if (gt != -1)
{
PLAY_CupSelectDef.prevMenu = currentMenu;
PLAY_LevelSelectDef.prevMenu = &PLAY_CupSelectDef;
M_SetupNextMenu(&PLAY_CupSelectDef, false);
}
return true;
}
@ -344,8 +360,11 @@ boolean M_LevelListFromGametype(INT16 gt)
M_LevelSelectScrollDest();
levellist.y = levellist.dest;
PLAY_LevelSelectDef.prevMenu = currentMenu;
M_SetupNextMenu(&PLAY_LevelSelectDef, false);
if (gt != -1)
{
PLAY_LevelSelectDef.prevMenu = currentMenu;
M_SetupNextMenu(&PLAY_LevelSelectDef, false);
}
return true;
}
@ -478,6 +497,15 @@ void M_LevelSelected(INT16 add)
CV_StealthSet(&cv_kartspeed, (cv_dummykartspeed.value == KARTSPEED_NORMAL) ? "Auto" : cv_dummykartspeed.string);
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
if (levellist.netgame == true)
{
restoreMenu = &PLAY_MP_OptSelectDef;
}
else
{
restoreMenu = &PLAY_LevelSelectDef;
}
}
else
{

View file

@ -54,17 +54,9 @@ void M_EndModeAttackRun(void)
if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION)
Command_ExitGame_f();
M_StartControlPanel();
M_PrepareTimeAttack(0);
currentMenu = &PLAY_TimeAttackDef;
itemOn = currentMenu->lastOn;
G_SetGamestate(GS_MENU);
S_ChangeMusicInternal("menu", true);
modeattacking = ATTACKING_NONE;
M_StartControlPanel();
}
// Replay Playback Menu
@ -250,7 +242,7 @@ void M_PlaybackQuit(INT32 choice)
G_StopDemo();
if (demo.inreplayhut)
M_ReplayHut(choice);
M_StartControlPanel();
else if (modeattacking)
M_EndModeAttackRun();
else