diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp index caa1de1f0..c9d12af74 100644 --- a/source/blood/src/blood.cpp +++ b/source/blood/src/blood.cpp @@ -70,15 +70,12 @@ void InitCheats(); bool bNoDemo = false; int gNetPlayers; -int gQuitRequest; int gChokeCounter = 0; -bool gQuitGame; int blood_globalflags; PLAYER gPlayerTemp[kMaxPlayers]; int gHealthTemp[kMaxPlayers]; vec3_t startpos; int16_t startang, startsectnum; -MapRecord* gStartNewGame = nullptr; void QuitGame(void) @@ -104,7 +101,6 @@ void StartLevel(MapRecord* level) STAT_Update(0); EndLevel(); gInput = {}; - gStartNewGame = nullptr; currentLevel = level; if (gGameOptions.nGameType == 0) @@ -114,14 +110,14 @@ void StartLevel(MapRecord* level) /////// } #if 0 - else if (gGameOptions.nGameType > 0 && !(gGameOptions.uGameFlags & 1)) + else if (gGameOptions.nGameType > 0 && !(gGameOptions.uGameFlags & GF_AdvanceLevel)) { // todo gBlueFlagDropped = false; gRedFlagDropped = false; } #endif - if (gGameOptions.uGameFlags & 1) + if (gGameOptions.uGameFlags & GF_AdvanceLevel) { for (int i = connecthead; i >= 0; i = connectpoint2[i]) { @@ -204,7 +200,7 @@ void StartLevel(MapRecord* level) evInit(); for (int i = connecthead; i >= 0; i = connectpoint2[i]) { - if (!(gGameOptions.uGameFlags & 1)) + if (!(gGameOptions.uGameFlags & GF_AdvanceLevel)) { if (numplayers == 1) { @@ -214,7 +210,7 @@ void StartLevel(MapRecord* level) } playerStart(i, 1); } - if (gGameOptions.uGameFlags & 1) + if (gGameOptions.uGameFlags & GF_AdvanceLevel) { for (int i = connecthead; i >= 0; i = connectpoint2[i]) { @@ -231,7 +227,7 @@ void StartLevel(MapRecord* level) pPlayer->nextWeapon = gPlayerTemp[i].nextWeapon; } } - gGameOptions.uGameFlags &= ~3; + gGameOptions.uGameFlags &= ~(GF_AdvanceLevel|GF_EndGame); PreloadCache(); InitMirrors(); trInit(); @@ -249,60 +245,44 @@ void StartLevel(MapRecord* level) } -bool gRestartGame = false; - -static void commonTicker() +void NewLevel(MapRecord *sng, int skill) { - if (TestBitString(gotpic, 2342)) + auto completion = [=](bool = false) { - FireProcess(); - ClearBitString(gotpic, 2342); - } - if (gStartNewGame) + gGameOptions.nDifficulty = skill; + gSkill = skill; + cheatReset(); + StartLevel(sng); + gamestate = GS_LEVEL; + }; + + bool startedCutscene = false; + if (!(sng->flags & MI_USERMAP)) { - auto sng = gStartNewGame; - gStartNewGame = nullptr; - gQuitGame = false; - auto completion = [=](bool = false) + int episode = volfromlevelnum(sng->levelNumber); + int level = mapfromlevelnum(sng->levelNumber); + if (gEpisodeInfo[episode].cutALevel == level && gEpisodeInfo[episode].cutsceneAName[0]) { - StartLevel(sng); - - gamestate = GS_LEVEL; - }; - - bool startedCutscene = false; - if (!(sng->flags & MI_USERMAP)) - { - int episode = volfromlevelnum(sng->levelNumber); - int level = mapfromlevelnum(sng->levelNumber); - if (gEpisodeInfo[episode].cutALevel == level && gEpisodeInfo[episode].cutsceneAName[0]) - { - levelPlayIntroScene(episode, completion); - startedCutscene = true; - } - + levelPlayIntroScene(episode, completion); + startedCutscene = true; } - if (!startedCutscene) completion(false); - } - else if (gRestartGame) - { - Mus_Stop(); - soundEngine->StopAllChannels(); - gQuitGame = 0; - gQuitRequest = 0; - gRestartGame = 0; - // Don't switch to startup if we're already outside the game. - if (gamestate == GS_LEVEL) - { - gamestate = GS_MENUSCREEN; - M_StartControlPanel(false); - M_SetMenu(NAME_Mainmenu); - } } + if (!startedCutscene) completion(false); + } +void GameInterface::NewGame(MapRecord *sng, int skill) +{ + gGameOptions.uGameFlags = 0; + NewLevel(sng, skill); +} +void GameInterface::NextLevel(MapRecord *map, int skill) +{ + gGameOptions.uGameFlags = GF_AdvanceLevel; + NewLevel(map, skill); +} void GameInterface::Ticker() { @@ -369,25 +349,20 @@ void GameInterface::Ticker() dword_21EFD0[i] = 0; } - if ((gGameOptions.uGameFlags & 1) != 0 && !gStartNewGame) + if ((gGameOptions.uGameFlags & GF_AdvanceLevel) != 0) { seqKillAll(); - if (gGameOptions.uGameFlags & 2) + if (gGameOptions.uGameFlags & GF_EndGame) { STAT_Update(true); if (gGameOptions.nGameType == 0) { auto completion = [](bool) { - gamestate = GS_MENUSCREEN; - M_StartControlPanel(false); - M_SetMenu(NAME_Mainmenu); - M_SetMenu(NAME_CreditsMenu); - gGameOptions.uGameFlags &= ~3; - gQuitGame = 1; - gRestartGame = true; + gGameOptions.uGameFlags &= ~(GF_AdvanceLevel|GF_EndGame); + gameaction = ga_creditsmenu; }; - if (gGameOptions.uGameFlags & 8) + if (gGameOptions.uGameFlags & GF_PlayCutscene) { levelPlayEndScene(volfromlevelnum(currentLevel->levelNumber), completion); } @@ -395,27 +370,29 @@ void GameInterface::Ticker() } else { - gGameOptions.uGameFlags &= ~3; - gRestartGame = 1; - gQuitGame = 1; + gGameOptions.uGameFlags &= ~(GF_AdvanceLevel|GF_EndGame); } } else { - ShowSummaryScreen(); + STAT_Update(false); + EndLevel(); + Mus_Stop(); + // Fixme: Link maps, not episode/level pairs. + int ep = volfromlevelnum(currentLevel->levelNumber); + auto map = FindMapByLevelNum(levelnum(ep, gNextLevel)); + CompleteLevel(map); } } r_NoInterpolate = false; } else r_NoInterpolate = true; - commonTicker(); } void GameInterface::DrawBackground() { twod->ClearScreen(); DrawTexture(twod, tileGetTexture(2518, true), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); - commonTicker(); } @@ -488,8 +465,6 @@ static void gameInit() pProfile->skill = gSkill; UpdateNetworkMenus(); - gQuitGame = 0; - gRestartGame = 0; if (gGameOptions.nGameType > 0) { inputState.ClearAllInput(); diff --git a/source/blood/src/blood.h b/source/blood/src/blood.h index 06bcc7649..5b89de332 100644 --- a/source/blood/src/blood.h +++ b/source/blood/src/blood.h @@ -46,16 +46,9 @@ struct INICHAIN { extern INICHAIN *pINIChain; -extern MapRecord* gStartNewGame; - extern int gNetPlayers; -extern bool gRestartGame; extern int blood_globalflags; -extern bool gSavingGame; -extern bool gQuitGame; -extern int gQuitRequest; - void QuitGame(void); void PreloadCache(void); void StartLevel(MapRecord *gameOptions); @@ -101,6 +94,10 @@ struct GameInterface : ::GameInterface void Startup() override; void Render() override; const char* GenericCheat(int player, int cheat) override; + void NewGame(MapRecord *sng, int skill) override; + void NextLevel(MapRecord* map, int skill) override; + void LevelCompleted(MapRecord* map, int skill) override; + GameStats getStats() override; }; diff --git a/source/blood/src/credits.cpp b/source/blood/src/credits.cpp index 6a67d92d8..6b8b48a45 100644 --- a/source/blood/src/credits.cpp +++ b/source/blood/src/credits.cpp @@ -129,7 +129,6 @@ void playSmk(const char *smk, const char *wav, int wavid, CompletionFunc func) void levelPlayIntroScene(int nEpisode, CompletionFunc completion) { - gGameOptions.uGameFlags &= ~4; Mus_Stop(); sndKillAllSounds(); sfxKillAllSounds(); @@ -141,7 +140,7 @@ void levelPlayIntroScene(int nEpisode, CompletionFunc completion) void levelPlayEndScene(int nEpisode, CompletionFunc completion) { - gGameOptions.uGameFlags &= ~8; + gGameOptions.uGameFlags &= ~GF_PlayCutscene; Mus_Stop(); sndKillAllSounds(); sfxKillAllSounds(); diff --git a/source/blood/src/d_menu.cpp b/source/blood/src/d_menu.cpp index 6a6182dc3..e56a7c866 100644 --- a/source/blood/src/d_menu.cpp +++ b/source/blood/src/d_menu.cpp @@ -242,10 +242,8 @@ bool GameInterface::CanSave() void GameInterface::StartGame(FNewGameStartup& gs) { sfxKillAllSounds(); - gGameOptions.nDifficulty = gs.Skill; - gSkill = gs.Skill; - gStartNewGame = FindMapByLevelNum(levelnum(gs.Episode, gs.Level)); - cheatReset(); + auto map = FindMapByLevelNum(levelnum(gs.Episode, gs.Level)); + DeferedStartGame(map, gs.Skill); } FSavegameInfo GameInterface::GetSaveSig() @@ -290,12 +288,7 @@ void GameInterface::DrawCenteredTextScreen(const DVector2& origin, const char* t void GameInterface::QuitToTitle() { - if (gGameOptions.nGameType == 0 || numplayers == 1) - { - gQuitGame = true; - gRestartGame = true; - } - //else gQuitRequest = 2; + gameaction = ga_mainmenu; } END_BLD_NS diff --git a/source/blood/src/endgame.cpp b/source/blood/src/endgame.cpp index f89e24b1c..ef2d3193e 100644 --- a/source/blood/src/endgame.cpp +++ b/source/blood/src/endgame.cpp @@ -164,24 +164,17 @@ class DBloodSummaryScreen : public DScreenJob } }; - -void ShowSummaryScreen() +void GameInterface::LevelCompleted(MapRecord *map, int skill) { JobDesc job = { Create() }; - - STAT_Update(false); - EndLevel(); - Mus_Stop(); sndStartSample(268, 128, -1, false); - RunScreenJob(&job, 1, [](bool) + RunScreenJob(&job, 1, [=](bool) { - int ep = volfromlevelnum(currentLevel->levelNumber); - gStartNewGame = FindMapByLevelNum(levelnum(ep, gNextLevel)); - gamestate = GS_LEVEL; soundEngine->StopAllChannels(); + gameaction = ga_nextlevel; }); -} +} CKillMgr::CKillMgr() diff --git a/source/blood/src/endgame.h b/source/blood/src/endgame.h index afbea6ce3..ffafa7de1 100644 --- a/source/blood/src/endgame.h +++ b/source/blood/src/endgame.h @@ -49,6 +49,5 @@ public: extern CSecretMgr gSecretMgr; extern CKillMgr gKillMgr; -void ShowSummaryScreen(); END_BLD_NS diff --git a/source/blood/src/levels.cpp b/source/blood/src/levels.cpp index 2a19ce3ec..852ce5db0 100644 --- a/source/blood/src/levels.cpp +++ b/source/blood/src/levels.cpp @@ -199,7 +199,7 @@ void levelEndLevel(int arg) int nEndingA, nEndingB; auto episode = volfromlevelnum(currentLevel->levelNumber); EPISODEINFO *pEpisodeInfo = &gEpisodeInfo[episode]; - gGameOptions.uGameFlags |= 1; + gGameOptions.uGameFlags |= GF_AdvanceLevel; levelGetNextLevels(&nEndingA, &nEndingB); switch (arg) { @@ -207,8 +207,8 @@ void levelEndLevel(int arg) if (nEndingA == -1) { if (pEpisodeInfo->cutsceneBName[0]) - gGameOptions.uGameFlags |= 8; - gGameOptions.uGameFlags |= 2; + gGameOptions.uGameFlags |= GF_PlayCutscene; + gGameOptions.uGameFlags |= GF_EndGame; } else gNextLevel = nEndingA; @@ -219,12 +219,12 @@ void levelEndLevel(int arg) if (episode + 1 < gEpisodeCount) { if (pEpisodeInfo->cutsceneBName[0]) - gGameOptions.uGameFlags |= 8; - gGameOptions.uGameFlags |= 2; + gGameOptions.uGameFlags |= GF_PlayCutscene; + gGameOptions.uGameFlags |= GF_EndGame; } else { - gGameOptions.uGameFlags |= 1; + gGameOptions.uGameFlags |= GF_AdvanceLevel; } } else diff --git a/source/blood/src/levels.h b/source/blood/src/levels.h index 6c5c7ad63..03c242b79 100644 --- a/source/blood/src/levels.h +++ b/source/blood/src/levels.h @@ -35,6 +35,14 @@ BEGIN_BLD_NS #pragma pack(push, 1) +enum EGameFlag +{ + GF_AdvanceLevel = 1, + GF_EndGame = 2, + // 4 was for playing intro cutscenes but is no longer used. + GF_PlayCutscene = 8, +}; + struct GAMEOPTIONS { unsigned char nGameType; unsigned char nDifficulty; diff --git a/source/blood/src/messages.cpp b/source/blood/src/messages.cpp index 5208453a4..660daac91 100644 --- a/source/blood/src/messages.cpp +++ b/source/blood/src/messages.cpp @@ -267,12 +267,6 @@ void ToggleDelirium(void) } } -void LevelWarp(int nEpisode, int nLevel) -{ - auto map = FindMapByLevelNum(levelnum(nEpisode, nLevel)); - if (map) StartLevel(map); -} - bool bPlayerCheated = false; static int parseArgs(char *pzArgs, int *nArg1, int *nArg2) @@ -434,7 +428,10 @@ static bool cheatMario(cheatseq_t* c) { int nEpisode, nLevel; if (parseArgs((char*)c->Args, &nEpisode, &nLevel) == 2) - LevelWarp(nEpisode, nLevel); + { + auto map = FindMapByLevelNum(levelnum(nEpisode, nLevel)); + if (map) DeferedStartGame(map, -1); + } return true; } diff --git a/source/blood/src/nnexts.cpp b/source/blood/src/nnexts.cpp index cd3021563..9b2f62c1e 100644 --- a/source/blood/src/nnexts.cpp +++ b/source/blood/src/nnexts.cpp @@ -5169,10 +5169,10 @@ void seqSpawnerOffSameTx(XSPRITE* pXSource) { // it allows to set custom next level instead of taking it from INI file. void levelEndLevelCustom(int nLevel) { - gGameOptions.uGameFlags |= 1; + gGameOptions.uGameFlags |= GF_AdvanceLevel; if (nLevel >= 16 || nLevel < 0) { - gGameOptions.uGameFlags |= 2; + gGameOptions.uGameFlags |= GF_EndGame; return; } diff --git a/source/blood/src/osdcmd.cpp b/source/blood/src/osdcmd.cpp index 2afd61da2..f1b1d75ae 100644 --- a/source/blood/src/osdcmd.cpp +++ b/source/blood/src/osdcmd.cpp @@ -38,53 +38,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS -void LevelWarp(int nEpisode, int nLevel); - -static int osdcmd_map(CCmdFuncPtr parm) -{ - if (parm->numparms != 1) - return CCMD_SHOWHELP; - - FString mapname = parm->parms[0]; - FString mapfilename = mapname; - DefaultExtension(mapfilename, ".map"); - - if (!fileSystem.FileExists(mapfilename)) - { - Printf(TEXTCOLOR_RED "map: file \"%s\" not found.\n", mapfilename.GetChars()); - return CCMD_OK; - } - - auto maprec = FindMapByName(mapname); - if (maprec) - { - StartLevel(maprec); - } - else - { - // Map has not been defined. Treat as user map. - StartLevel(SetupUserMap(mapfilename)); - } - - return CCMD_OK; -} - - -static int osdcmd_levelwarp(CCmdFuncPtr parm) -{ - if (parm->numparms != 2) - return CCMD_SHOWHELP; - int e = atoi(parm->parms[0]); - int m = atoi(parm->parms[1]); - if (e == 0 || m == 0) - { - Printf(TEXTCOLOR_RED "Invalid level!: E%sM%s\n", parm->parms[0], parm->parms[1]); - return CCMD_OK; - } - LevelWarp(e - 1, m - 1); - return CCMD_OK; -} - static int osdcmd_warptocoords(CCmdFuncPtr parm) { if (parm->numparms < 3 || parm->numparms > 5) @@ -160,8 +113,6 @@ static int osdcmd_show_weapon(CCmdFuncPtr parm) int32_t registerosdcommands(void) { - C_RegisterFunction("map","map : loads the given map", osdcmd_map); - C_RegisterFunction("levelwarp","levelwarp : warp to episode 'e' and map 'm'", osdcmd_levelwarp); C_RegisterFunction("warptocoords","warptocoords [x] [y] [z] [ang] (optional) [horiz] (optional): warps the player to the specified coordinates",osdcmd_warptocoords); C_RegisterFunction("third_person_view", "Switch to third person view", osdcmd_third_person_view); C_RegisterFunction("coop_view", "Switch player to view from in coop", osdcmd_coop_view); diff --git a/source/blood/src/player.cpp b/source/blood/src/player.cpp index 016cf1097..bb3c02bf5 100644 --- a/source/blood/src/player.cpp +++ b/source/blood/src/player.cpp @@ -1369,7 +1369,7 @@ void ProcessInput(PLAYER *pPlayer) playerReset(pPlayer); if (gGameOptions.nGameType == 0 && numplayers == 1) { - gStartNewGame = currentLevel; + DeferedStartGame(currentLevel, -1); } else playerStart(pPlayer->nPlayer); diff --git a/source/blood/src/view.cpp b/source/blood/src/view.cpp index 377cb5d09..d250867c1 100644 --- a/source/blood/src/view.cpp +++ b/source/blood/src/view.cpp @@ -601,6 +601,13 @@ void viewDrawScreen(bool sceneonly) { int nPalette = 0; int defaultHoriz = r_horizcenter ? 100 : 90; + + if (TestBitString(gotpic, 2342)) + { + FireProcess(); + ClearBitString(gotpic, 2342); + } + #ifdef USE_OPENGL polymostcenterhoriz = defaultHoriz; diff --git a/source/core/gamestate.h b/source/core/gamestate.h index ad6d742e0..a09c986c6 100644 --- a/source/core/gamestate.h +++ b/source/core/gamestate.h @@ -26,6 +26,7 @@ enum gameaction_t : int ga_nothing, ga_startup, // go back to intro after uninitializing the game state ga_mainmenu, // go back to main menu after uninitializing the game state + 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) ga_loadgame, // load a savegame and resume play. diff --git a/source/core/mainloop.cpp b/source/core/mainloop.cpp index e40bd95da..a9c792abe 100644 --- a/source/core/mainloop.cpp +++ b/source/core/mainloop.cpp @@ -182,6 +182,12 @@ static void GameTicker() startmainmenu(); break; + case ga_creditsmenu: + gi->FreeLevelData(); + startmainmenu(); + M_SetMenu(NAME_CreditsMenu); + break; + case ga_savegame: // We only need this for multiplayer saves that need to go through the network. // gi->SaveGame(); diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 0aaf49785..afd88b36a 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -589,11 +589,17 @@ void DeleteScreenJob() void RunScreenJobFrame() { // we cannot recover from this because we have no completion callback to call. - if (!runner) I_Error("Trying to run a non-existent screen job"); + if (!runner) + { + // We can get here before a gameaction has been processed. In that case just draw a black screen and wait. + if (gameaction == ga_nothing) I_Error("Trying to run a non-existent screen job"); + twod->ClearScreen(); + return; + } auto res = runner->RunFrame(); if (!res) { - assert(gamestate != GS_INTERMISSION && gamestate != GS_INTRO); + assert((gamestate != GS_INTERMISSION && gamestate != GS_INTRO) || gameaction != ga_nothing); DeleteScreenJob(); } } diff --git a/source/games/duke/src/d_menu.cpp b/source/games/duke/src/d_menu.cpp index 870c37a55..598054433 100644 --- a/source/games/duke/src/d_menu.cpp +++ b/source/games/duke/src/d_menu.cpp @@ -337,7 +337,7 @@ void GameInterface::DrawPlayerSprite(const DVector2& origin, bool onteam) void GameInterface::QuitToTitle() { - gamestate = GS_STARTUP; + gameaction = ga_startup; } END_DUKE_NS