- restructured the main loop code so that the actual loop is in the common code.

This commit is contained in:
Christoph Oelckers 2020-08-23 17:47:05 +02:00
parent 85875da77a
commit adb98a47ba
12 changed files with 231 additions and 286 deletions

View file

@ -68,8 +68,6 @@ void LocalKeys(void);
void InitCheats();
bool bNoDemo = false;
bool bQuickStart = true;
char gUserMapFilename[BMAX_PATH];
@ -714,13 +712,12 @@ static const char* actions[] = {
"Toggle_Crouch",
};
static void app_init()
void GameInterface::app_init()
{
InitCheats();
buttonMap.SetButtons(actions, NUM_ACTIONS);
memcpy(&gGameOptions, &gSingleGameOptions, sizeof(GAMEOPTIONS));
gGameOptions.nMonsterSettings = !userConfig.nomonsters;
bQuickStart = userConfig.nologo;
ReadAllRFS();
HookReplaceFunctions();
@ -854,7 +851,7 @@ static void drawBackground()
netBroadcastMyLogoff(gQuitRequest == 2);
}
static void commonTicker(bool &playvideo)
static void commonTicker()
{
if (TestBitString(gotpic, 2342))
{
@ -895,85 +892,61 @@ static void commonTicker(bool &playvideo)
gQuitRequest = 0;
gRestartGame = 0;
if (gGameOptions.nGameType != 0)
{
playvideo = !bQuickStart;
}
else playvideo = false;
// Don't switch to startup if we're already outside the game.
if (gamestate == GS_LEVEL) gamestate = GS_STARTUP;
}
}
int GameInterface::app_main()
void GameInterface::RunGameFrame()
{
app_init();
gamestate = GS_STARTUP;
bool playvideo = !bQuickStart;
while (true)
if (gamestate == GS_STARTUP) gameInit();
commonTicker();
netGetPackets();
handleevents();
updatePauseStatus();
D_ProcessEvents();
ctrlGetInput();
switch (gamestate)
{
try
default:
case GS_STARTUP:
if (userConfig.CommandMap.IsNotEmpty())
{
if (gamestate == GS_STARTUP) gameInit();
commonTicker(playvideo);
netGetPackets();
handleevents();
updatePauseStatus();
D_ProcessEvents();
ctrlGetInput();
switch (gamestate)
}
else
{
if (!userConfig.nologo && gGameOptions.nGameType == 0) playlogos();
else
{
default:
case GS_STARTUP:
if (userConfig.CommandMap.IsNotEmpty())
{
}
else
{
if (playvideo) playlogos();
else
{
gamestate = GS_MENUSCREEN;
M_StartControlPanel(false);
M_SetMenu(NAME_Mainmenu);
}
}
break;
case GS_MENUSCREEN:
case GS_FULLCONSOLE:
drawBackground();
break;
case GS_INTRO:
case GS_INTERMISSION:
RunScreenJobFrame(); // This handles continuation through its completion callback.
break;
case GS_LEVEL:
gameTicker();
LocalKeys();
break;
case GS_FINALE:
gEndGameMgr.ProcessKeys();
gEndGameMgr.Draw();
break;
gamestate = GS_MENUSCREEN;
M_StartControlPanel(false);
M_SetMenu(NAME_Mainmenu);
}
}
break;
videoNextPage();
}
catch (CRecoverableError& err)
{
C_FullConsole();
Printf(TEXTCOLOR_RED "%s\n", err.what());
}
case GS_MENUSCREEN:
case GS_FULLCONSOLE:
drawBackground();
break;
case GS_INTRO:
case GS_INTERMISSION:
RunScreenJobFrame(); // This handles continuation through its completion callback.
break;
case GS_LEVEL:
gameTicker();
LocalKeys();
break;
case GS_FINALE:
gEndGameMgr.ProcessKeys();
gEndGameMgr.Draw();
break;
}
return 0;
}
bool DemoRecordStatus(void) {

View file

@ -107,7 +107,8 @@ void sndPlaySpecialMusicOrNothing(int nMusic);
struct GameInterface : ::GameInterface
{
const char* Name() override { return "Blood"; }
int app_main() override;
void app_init() override;
void RunGameFrame() override;
bool GenerateSavePic() override;
void FreeGameData() override;
FString statFPS() override;

View file

@ -117,6 +117,7 @@ void I_SetWindowTitle(const char* caption);
void S_ParseSndInfo();
void I_DetectOS(void);
void LoadScripts();
void app_loop();
bool AppActive;
@ -817,6 +818,7 @@ int RunGame()
{
playername = userConfig.CommandName;
}
GameTicRate = 30;
CheckUserMap();
GPalette.Init(MAXPALOOKUPS + 2); // one slot for each translation, plus a separate one for the base palettes and the internal one
TexMan.Init([]() {}, [](BuildInfo &) {});
@ -836,16 +838,44 @@ int RunGame()
if (enginePreInit())
{
I_FatalError("app_main: There was a problem initializing the Build engine: %s\n", engineerrstr);
I_FatalError("There was a problem initializing the Build engine: %s\n", engineerrstr);
}
auto exec = C_ParseCmdLineParams(nullptr);
if (exec) exec->ExecCommands();
gamestate = GS_LEVEL;
return gi->app_main();
gi->app_init();
app_loop();
}
//---------------------------------------------------------------------------
//
// The one and only main loop in the entire engine. Yay!
//
//---------------------------------------------------------------------------
void app_loop()
{
gamestate = GS_STARTUP;
while (true)
{
try
{
gi->RunGameFrame();
videoNextPage();
videoSetBrightness(0); // immediately reset this so that the value doesn't stick around in the backend.
}
catch (CRecoverableError& err)
{
C_FullConsole();
Printf(TEXTCOLOR_RED "%s\n", err.what());
}
}
}
//==========================================================================
//
//

View file

@ -58,7 +58,8 @@ struct GameInterface
virtual const char* Name() { return "$"; }
virtual ~GameInterface() {}
virtual bool GenerateSavePic() { return false; }
virtual int app_main() = 0;
virtual void app_init() = 0;
virtual void RunGameFrame() = 0;
virtual void clearlocalinputstate() {}
virtual void UpdateScreenSize() {}
virtual void FreeGameData() {}

View file

@ -621,7 +621,7 @@ static const char* actions[] =
void InitGame()
void GameInterface::app_init()
{
int i;
//int esi = 1;

View file

@ -134,7 +134,6 @@ void CheckKeys();
void CheckKeys2();
void GameTicker();
void InitLevel(int);
void InitGame();
void InitNewGame();
void startmainmenu();
@ -294,8 +293,9 @@ struct SavegameHelper
struct GameInterface : ::GameInterface
{
const char* Name() override { return "Exhumed"; }
int app_main() override;
bool GenerateSavePic() override;
void app_init() override;
void RunGameFrame() override;
bool GenerateSavePic() override;
void DrawNativeMenuText(int fontnum, int state, double xpos, double ypos, float fontscale, const char* text, int flags) override;
void MenuOpened() override;
void MenuSound(EMenuSounds snd) override;

View file

@ -59,7 +59,6 @@ extern ClockTicks tclocks;
void RunCinemaScene(int num);
void GameMove(void);
void InitGame();
void DrawClock();
int32_t calc_smoothratio(ClockTicks totalclk, ClockTicks ototalclk);
void DoTitle(CompletionFunc completion);
@ -262,78 +261,63 @@ void GameLoop()
fps++;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
int GameInterface::app_main()
void GameInterface::RunGameFrame()
{
InitGame();
gamestate = GS_STARTUP;
while (true)
again:
try
{
try
HandleAsync();
updatePauseStatus();
D_ProcessEvents();
CheckProgression();
switch (gamestate)
{
HandleAsync();
updatePauseStatus();
D_ProcessEvents();
CheckProgression();
switch (gamestate)
{
default:
case GS_STARTUP:
totalclock = 0;
ototalclock = 0;
GameAction = -1;
EndLevel = false;
if (userConfig.CommandMap.IsNotEmpty())
{
auto map = FindMapByName(userConfig.CommandMap);
if (map) GameAction = map->levelNumber;
userConfig.CommandMap = "";
continue;
}
else
{
DoTitle([](bool) { startmainmenu(); });
}
break;
case GS_MENUSCREEN:
case GS_FULLCONSOLE:
drawmenubackground();
break;
case GS_LEVEL:
GameLoop();
GameDisplay();
break;
case GS_INTERMISSION:
case GS_INTRO:
RunScreenJobFrame(); // This handles continuation through its completion callback.
break;
}
videoNextPage();
}
catch (CRecoverableError& err)
{
// Clear all progression sensitive variables here.
default:
case GS_STARTUP:
totalclock = 0;
ototalclock = 0;
GameAction = -1;
EndLevel = false;
C_FullConsole();
Printf(TEXTCOLOR_RED "%s\n", err.what());
if (userConfig.CommandMap.IsNotEmpty())
{
auto map = FindMapByName(userConfig.CommandMap);
if (map) GameAction = map->levelNumber;
userConfig.CommandMap = "";
goto again;
}
else
{
DoTitle([](bool) { startmainmenu(); });
}
break;
case GS_MENUSCREEN:
case GS_FULLCONSOLE:
drawmenubackground();
break;
case GS_LEVEL:
GameLoop();
GameDisplay();
break;
case GS_INTERMISSION:
case GS_INTRO:
RunScreenJobFrame(); // This handles continuation through its completion callback.
break;
}
}
catch (CRecoverableError&)
{
// Clear all progression sensitive variables here.
GameAction = -1;
EndLevel = false;
throw;
}
}
END_PS_NS

View file

@ -34,7 +34,8 @@ extern FFont* DigiFont;
struct GameInterface : public ::GameInterface
{
const char* Name() override { return "Duke"; }
int app_main() override;
void app_init() override;
void RunGameFrame() override;
void clearlocalinputstate() override;
bool GenerateSavePic() override;
void PlayHudSound() override;

View file

@ -423,14 +423,12 @@ static void Startup(void)
//
//---------------------------------------------------------------------------
void app_loop();
int GameInterface::app_main()
void GameInterface::app_init()
{
Startup();
enginePostInit();
videoInit();
app_loop();
return 0;
enginecompatibility_mode = ENGINECOMPATIBILITY_19961112;//bVanilla;
}

View file

@ -399,77 +399,60 @@ void startmainmenu()
//
//---------------------------------------------------------------------------
void app_loop()
void GameInterface::RunGameFrame()
{
gamestate = GS_STARTUP;
enginecompatibility_mode = ENGINECOMPATIBILITY_19961112;//bVanilla;
while (true)
handleevents();
updatePauseStatus();
D_ProcessEvents();
switch (gamestate)
{
try
default:
case GS_STARTUP:
totalclock = 0;
ototalclock = 0;
lockclock = 0;
ps[myconnectindex].ftq = 0;
if (userConfig.CommandMap.IsNotEmpty())
{
handleevents();
updatePauseStatus();
D_ProcessEvents();
switch (gamestate)
auto maprecord = FindMapByName(userConfig.CommandMap);
userConfig.CommandMap = "";
if (maprecord)
{
default:
case GS_STARTUP:
totalclock = 0;
ototalclock = 0;
lockclock = 0;
ud.m_respawn_monsters = ud.m_player_skill == 4;
ps[myconnectindex].ftq = 0;
if (userConfig.CommandMap.IsNotEmpty())
for (int i = 0; i != -1; i = connectpoint2[i])
{
auto maprecord = FindMapByName(userConfig.CommandMap);
userConfig.CommandMap = "";
if (maprecord)
{
ud.m_respawn_monsters = ud.m_player_skill == 4;
for (int i = 0; i != -1; i = connectpoint2[i])
{
resetweapons(i);
resetinventory(i);
}
startnewgame(maprecord, /*userConfig.skill*/2);
}
resetweapons(i);
resetinventory(i);
}
else
{
fi.ShowLogo([](bool) { startmainmenu(); });
}
break;
case GS_MENUSCREEN:
case GS_FULLCONSOLE:
drawbackground();
break;
case GS_LEVEL:
if (GameTicker()) gamestate = GS_STARTUP;
else videoSetBrightness(thunder_brightness);
break;
case GS_INTERMISSION:
case GS_INTRO:
RunScreenJobFrame(); // This handles continuation through its completion callback.
break;
startnewgame(maprecord, /*userConfig.skill*/2);
}
videoNextPage();
videoSetBrightness(0); // immediately reset this so that the value doesn't stick around in the backend.
}
catch (CRecoverableError& err)
else
{
C_FullConsole();
Printf(TEXTCOLOR_RED "%s\n", err.what());
fi.ShowLogo([](bool) { startmainmenu(); });
}
break;
case GS_MENUSCREEN:
case GS_FULLCONSOLE:
drawbackground();
break;
case GS_LEVEL:
if (GameTicker()) gamestate = GS_STARTUP;
else videoSetBrightness(thunder_brightness);
break;
case GS_INTERMISSION:
case GS_INTRO:
RunScreenJobFrame(); // This handles continuation through its completion callback.
break;
}
}
END_DUKE_NS

View file

@ -213,8 +213,9 @@ static const char* actions[] = {
};
bool InitGame()
void GameInterface::app_init()
{
GameTicRate = 40;
InitCheats();
buttonMap.SetButtons(actions, NUM_ACTIONS);
automapping = 1;
@ -284,7 +285,6 @@ bool InitGame()
enginePostInit();
videoInit();
InitFX();
return true;
}
//---------------------------------------------------------------------------
@ -804,89 +804,62 @@ void GameTicker(void)
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
int32_t GameInterface::app_main()
void GameInterface::RunGameFrame()
{
InitGame();
gamestate = GS_STARTUP;
while (true)
try
{
try
{
// if the menu initiazed a new game or loaded a savegame, switch to play mode.
if (SavegameLoaded || NextLevel) gamestate = GS_LEVEL;
// if the menu initiazed a new game or loaded a savegame, switch to play mode.
if (SavegameLoaded || NextLevel) gamestate = GS_LEVEL;
handleevents();
updatePauseStatus();
D_ProcessEvents();
DoUpdateSounds();
switch (gamestate)
{
default:
case GS_STARTUP:
totalclock = 0;
ototalclock = 0;
if (userConfig.CommandMap.IsNotEmpty())
{
}
else
{
if (!userConfig.nologo) Logo([](bool) { StartMenu(); });
else StartMenu();
}
break;
case GS_MENUSCREEN:
case GS_FULLCONSOLE:
DrawMenuLevelScreen();
break;
case GS_LEVEL:
GameTicker();
break;
case GS_INTERMISSION:
case GS_INTRO:
RunScreenJobFrame(); // This handles continuation through its completion callback.
break;
}
videoNextPage();
}
catch (CRecoverableError& err)
{
TerminateLevel();
NextLevel = nullptr;
SavegameLoaded = false;
ExitLevel = false;
FinishAnim = 0;
C_FullConsole();
Printf(TEXTCOLOR_RED "%s\n", err.what());
}
}
#if 0
while (true)
{
handleevents();
C_RunDelayedCommands();
updatePauseStatus();
D_ProcessEvents();
DoUpdateSounds();
switch (gamestate)
{
default:
case GS_STARTUP:
totalclock = 0;
ototalclock = 0;
NewLevel();
if (userConfig.CommandMap.IsNotEmpty())
{
}
else
{
if (!userConfig.nologo) Logo([](bool) { StartMenu(); });
else StartMenu();
}
break;
case GS_MENUSCREEN:
case GS_FULLCONSOLE:
DrawMenuLevelScreen();
break;
case GS_LEVEL:
GameTicker();
break;
case GS_INTERMISSION:
case GS_INTRO:
RunScreenJobFrame(); // This handles continuation through its completion callback.
break;
}
}
catch (CRecoverableError&)
{
// Make sure we do not leave the game in an unstable state
TerminateLevel();
NextLevel = nullptr;
SavegameLoaded = false;
ExitLevel = false;
FinishAnim = 0;
throw;
}
//SybexScreen();
throw CExitEvent(0);
#endif
return 0;
}
//---------------------------------------------------------------------------

View file

@ -2364,7 +2364,8 @@ extern short Bunny_Count;
struct GameInterface : ::GameInterface
{
const char* Name() override { return "ShadowWarrior"; }
int app_main() override;
void app_init() override;
void RunGameFrame() override;
void FreeGameData() override;
bool GenerateSavePic() override;
void DrawNativeMenuText(int fontnum, int state, double xpos, double ypos, float fontscale, const char* text, int flags) override;