- route all game state changes through game actions.

This is to avoid problems with the main loop not calling Ticker and Render in sync.
This commit is contained in:
Christoph Oelckers 2020-09-05 15:43:34 +02:00
parent 7a5dca7d5d
commit c1786001b2
17 changed files with 57 additions and 94 deletions

View file

@ -254,7 +254,7 @@ void NewLevel(MapRecord *sng, int skill)
gSkill = skill;
cheatReset();
StartLevel(sng);
gamestate = GS_LEVEL;
gameaction = ga_level;
};
bool startedCutscene = false;
@ -485,7 +485,7 @@ void GameInterface::Startup()
if (!userConfig.nologo && gGameOptions.nGameType == 0) playlogos();
else
{
startmainmenu();
gameaction = ga_mainmenu;
}
}
}

View file

@ -94,10 +94,8 @@ void playlogos()
jobs[job++] = { Create<DImageScreen>(2518, DScreenJob::fadein) };
RunScreenJob(jobs, job, [](bool) {
gamestate = GS_MENUSCREEN;
M_StartControlPanel(false);
M_SetMenu(NAME_Mainmenu);
}, true, true);
gameaction = ga_mainmenu;
}, true, true);
}
void playSmk(const char *smk, const char *wav, int wavid, CompletionFunc func)

View file

@ -506,7 +506,6 @@ bool GameInterface::LoadGame(FSaveGameNode* node)
viewSetErrorMessage("");
Net_ClearFifo();
paused = 0;
gamestate = GS_LEVEL;
bVanilla = false;

View file

@ -1179,15 +1179,6 @@ CCMD(taunt)
//
//---------------------------------------------------------------------------
void startmainmenu()
{
gamestate = GS_MENUSCREEN;
M_StartControlPanel(false);
M_SetMenu(NAME_Mainmenu);
FX_StopAllSounds();
}
void GameInterface::FreeLevelData()
{
// Make sure that there is no more level to toy around with.

View file

@ -55,7 +55,6 @@ extern FStringCVar* const CombatMacros[];
void CONFIG_ReadCombatMacros();
int GameMain();
void startmainmenu();
int GetAutomapZoom(int gZoom);
void DrawCrosshair(int deftile, int health, double xdelta, double scale, PalEntry color = 0xffffffff);
void updatePauseStatus();

View file

@ -24,8 +24,13 @@ enum gamestate_t : int
enum gameaction_t : int
{
ga_nothing,
ga_level, // Switch to play mode without any initialization
ga_intro,
ga_intermission,
ga_startup, // go back to intro after uninitializing the game state
ga_mainmenu, // go back to main menu after uninitializing the game state
ga_mainmenunostopsound, // Same but doesn't stop playing sounds.
ga_creditsmenu, // go to the credits menu after uninitializing the game state
ga_newgame, // start a new game
ga_recordgame, // start a new demo recording (later)

View file

@ -140,6 +140,7 @@ static void GameTicker()
FX_SetReverb(0);
gi->FreeLevelData();
C_ClearMessages();
gameaction = ga_level;
gi->NewGame(g_nextmap, -1);
break;
@ -150,16 +151,19 @@ static void GameTicker()
{
// if the same level is restarted, skip any progression stuff like summary screens or cutscenes.
gi->FreeLevelData();
gamestate = GS_LEVEL;
gameaction = ga_level;
gi->NextLevel(g_nextmap, g_nextskill);
}
else
{
gi->LevelCompleted(g_nextmap, g_nextskill);
assert(gameaction != ga_nothing);
}
break;
case ga_nextlevel:
gi->FreeLevelData();
gamestate = GS_LEVEL;
gameaction = ga_level;
gi->NextLevel(g_nextmap, g_nextskill);
break;
@ -168,23 +172,32 @@ static void GameTicker()
FX_SetReverb(0);
gi->FreeLevelData();
C_ClearMessages();
gamestate = GS_LEVEL;
gameaction = ga_level;
gi->NewGame(g_nextmap, g_nextskill);
break;
case ga_startup:
Mus_Stop();
FX_StopAllSounds();
gi->FreeLevelData();
gamestate = GS_STARTUP;
break;
case ga_mainmenu:
FX_StopAllSounds();
case ga_mainmenunostopsound:
gi->FreeLevelData();
startmainmenu();
gamestate = GS_MENUSCREEN;
M_StartControlPanel(false);
M_SetMenu(NAME_Mainmenu);
break;
case ga_creditsmenu:
FX_StopAllSounds();
gi->FreeLevelData();
startmainmenu();
gamestate = GS_MENUSCREEN;
M_StartControlPanel(false);
M_SetMenu(NAME_Mainmenu);
M_SetMenu(NAME_CreditsMenu);
break;
@ -194,7 +207,19 @@ static void GameTicker()
break;
case ga_autosave:
M_Autosave();
if (gamestate == GS_LEVEL) M_Autosave();
break;
case ga_level:
gamestate = GS_LEVEL;
break;
case ga_intro:
gamestate = GS_INTRO;
break;
case ga_intermission:
gamestate = GS_INTERMISSION;
break;
// for later

View file

@ -66,7 +66,7 @@ void FSavegameManager::LoadGame(FSaveGameNode* node)
{
if (gi->LoadGame(node))
{
gamestate = GS_LEVEL;
gameaction = ga_level;
}
else
{

View file

@ -729,7 +729,11 @@ void RunScreenJob(JobDesc* jobs, int count, CompletionFunc completion, bool clea
if (count)
{
runner = new ScreenJobRunner(jobs, count, completion, clearbefore);
gamestate = blockingui? GS_INTRO : GS_INTERMISSION;
gameaction = blockingui? ga_intro : ga_intermission;
}
else
{
completion(false);
}
}

View file

@ -1283,7 +1283,7 @@ void DoGameOverScene(bool finallevel)
PlayGameOverSound();
job = { Create<DImageScreen>(tileGetTexture(kTile3591), DScreenJob::fadein | DScreenJob::fadeout, 0x7fffffff) };
}
RunScreenJob(&job, 1, [](bool) { gamestate = GS_STARTUP; });
RunScreenJob(&job, 1, [](bool) { gameaction = ga_startup; });
}

View file

@ -221,7 +221,7 @@ void GameInterface::NewGame(MapRecord *map, int skill)
void GameInterface::LevelCompleted(MapRecord *map, int skill)
{
if (currentLevel->levelNumber == 0) startmainmenu();
if (currentLevel->levelNumber == 0) gameaction = ga_mainmenu;
else Intermission(currentLevel, map);
}
@ -247,8 +247,8 @@ void GameInterface::Startup()
}
else
{
if (!userConfig.nologo) DoTitle([](bool) { startmainmenu(); });
else startmainmenu();
if (!userConfig.nologo) DoTitle([](bool) { gameaction = ga_mainmenu; });
else gameaction = ga_mainmenu;
}
}

View file

@ -640,56 +640,5 @@ void PrintLevelName_r(double alpha)
BigText(160, 114, currentLevel->DisplayName(), 0, alpha);
}
// Utility for testing the above screens
CCMD(testrscreen)
{
JobDesc jobs[10];
int job = 0;
C_HideConsole();
FX_StopAllSounds();
Mus_Stop();
auto gs = gamestate;
auto completion = [=](bool)
{
if (gs == GS_LEVEL || gs == GS_MENUSCREEN) gamestate = gs;
else gamestate = GS_STARTUP;
};
if (argv.argc() > 1)
{
int screen = strtol(argv[1], nullptr, 0);
switch (screen)
{
case 0:
case 1:
if (!isRRRA())
{
bonussequence_r(screen, jobs, job);
RunScreenJob(jobs, job, completion);
}
break;
case 2:
jobs[job++] = { Create<DRRMultiplayerBonusScreen>(6) };
RunScreenJob(jobs, job, completion);
break;
case 3:
jobs[job++] = { Create<DRRLevelSummaryScreen>() };
RunScreenJob(jobs, job, completion);
break;
case 4:
jobs[job++] = { Create<DRRRAEndOfGame>() };
RunScreenJob(jobs, job, completion);
break;
default:
break;
}
}
}
END_DUKE_NS

View file

@ -133,8 +133,8 @@ void GameInterface::Startup()
}
else
{
if (!userConfig.nologo) fi.ShowLogo([](bool) { startmainmenu(); });
else startmainmenu();
if (!userConfig.nologo) fi.ShowLogo([](bool) { gameaction = ga_mainmenu; });
else gameaction = ga_mainmenu;
}
}

View file

@ -1017,7 +1017,7 @@ void startnewgame(MapRecord* map, int skill)
{
if (enterlevel(map, 0))
{
startmainmenu();
gameaction = ga_mainmenu;
}
else
{
@ -1025,7 +1025,7 @@ void startnewgame(MapRecord* map, int skill)
setlocalplayerinput(&ps[myconnectindex]);
PlayerColorChanged();
inputState.ClearAllInput();
gamestate = GS_LEVEL;
gameaction = ga_level;
}
});
}
@ -1087,7 +1087,7 @@ void exitlevel(MapRecord *nextlevel)
// Clear potentially loaded per-map ART only after the bonus screens.
artClearMapArt();
gamestate = GS_LEVEL;
gameaction = ga_level;
if (endofgame)
{
if (ud.multimode < 2)

View file

@ -486,7 +486,6 @@ void GameInterface::SerializeGameState(FSerializer& arc)
if (arc.isReading())
{
screenpeek = myconnectindex;
gamestate = GS_LEVEL;
ud.recstat = 0;
ud.m_player_skill = ud.player_skill;

View file

@ -149,11 +149,7 @@ void GameInterface::DrawNativeMenuText(int fontnum, int state, double xpos, doub
void GameInterface::QuitToTitle()
{
Mus_Stop();
TerminateLevel();
currentLevel = nullptr;
M_StartControlPanel(false);
M_SetMenu(NAME_Mainmenu);
gamestate = GS_MENUSCREEN;
gameaction = ga_mainmenu;
}

View file

@ -678,9 +678,7 @@ void GameInterface::Startup()
{
if (!userConfig.nologo) Logo([](bool)
{
gamestate = GS_MENUSCREEN;
M_StartControlPanel(false);
M_SetMenu(NAME_Mainmenu);
gameaction = ga_mainmenunostopsound;
});
else gameaction = ga_mainmenu;
}