From 347ed51036db5bf6b7ee108bd5be9bad77990420 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 29 Jul 2020 23:18:08 +0200 Subject: [PATCH] - refactored Blood's main loop. * moved Smacker video playing code into the backend, so now all games can play all supported video formats * logos and level intro/exit videos use ScreenJob --- source/blood/src/blood.cpp | 398 +++++++++++++++------------------ source/blood/src/blood.h | 7 - source/blood/src/controls.cpp | 14 +- source/blood/src/credits.cpp | 283 ++++++++--------------- source/blood/src/credits.h | 31 --- source/blood/src/d_menu.cpp | 3 +- source/blood/src/endgame.cpp | 8 +- source/blood/src/levels.cpp | 33 --- source/blood/src/levels.h | 5 +- source/blood/src/loadsave.cpp | 7 +- source/blood/src/messages.cpp | 5 +- source/blood/src/misc.h | 1 + source/blood/src/network.cpp | 3 +- source/blood/src/osdcmd.cpp | 7 +- source/core/raze_music.cpp | 6 - source/core/raze_music.h | 1 - source/core/screenjob.cpp | 140 +++++++++++- source/core/screenjob.h | 21 +- source/games/duke/src/2d_d.cpp | 20 -- 19 files changed, 444 insertions(+), 549 deletions(-) delete mode 100644 source/blood/src/credits.h diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp index 40ffadaed..3d0800185 100644 --- a/source/blood/src/blood.cpp +++ b/source/blood/src/blood.cpp @@ -34,7 +34,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "blood.h" #include "choke.h" #include "controls.h" -#include "credits.h" #include "dude.h" #include "endgame.h" #include "eventq.h" @@ -59,16 +58,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "raze_sound.h" #include "nnexts.h" #include "secrets.h" +#include "gamestate.h" +#include "screenjob.h" BEGIN_BLD_NS -INPUT_MODE gInputMode; - -#ifdef USE_QHEAP -unsigned int nMaxAlloc = 0x4000000; -#endif - char bAddUserMap = false; bool bNoDemo = false; bool bQuickStart = true; @@ -80,8 +75,6 @@ short BloodVersion = 0x115; int gNetPlayers; -char *pUserTiles = NULL; - int gChokeCounter = 0; double g_gameUpdateTime, g_gameUpdateAndDrawTime; @@ -131,21 +124,9 @@ enum gametokens int blood_globalflags; -void ShutDown(void) -{ - if (!in3dmode()) - return; - netDeinitialize(); - //sndTerm(); - sfxTerm(); - // PORT_TODO: Check argument - DO_FREE_AND_NULL(pUserTiles); -} - void QuitGame(void) { - ShutDown(); - Bexit(0); + throw CExitEvent(0); } void PrecacheDude(spritetype *pSprite) @@ -412,8 +393,6 @@ void StartLevel(GAMEOPTIONS *gameOptions) if (gEpisodeInfo[gGameOptions.nEpisode].cutALevel == gGameOptions.nLevel && gEpisodeInfo[gGameOptions.nEpisode].at8f08) gGameOptions.uGameFlags |= 4; - if ((gGameOptions.uGameFlags&4)) - levelPlayIntroScene(gGameOptions.nEpisode); /////// gGameOptions.weaponsV10x = gWeaponsV10x; @@ -455,11 +434,10 @@ void StartLevel(GAMEOPTIONS *gameOptions) enginecompatibility_mode = ENGINECOMPATIBILITY_19960925;//bVanilla; memset(xsprite,0,sizeof(xsprite)); memset(sprite,0,kMaxSprites*sizeof(spritetype)); - drawLoadingScreen(); + //drawLoadingScreen(); if (dbLoadMap(gameOptions->zLevelName,(int*)&startpos.x,(int*)&startpos.y,(int*)&startpos.z,&startang,&startsectnum,(unsigned int*)&gameOptions->uMapCRC)) { - gQuitGame = true; - return; + I_Error("Unable to load map"); } currentLevel = &mapList[gGameOptions.nEpisode * kMaxLevels + gGameOptions.nLevel]; SECRET_SetMapName(currentLevel->DisplayName(), currentLevel->name); @@ -571,7 +549,6 @@ void StartLevel(GAMEOPTIONS *gameOptions) gFrame = 0; gChokeCounter = 0; M_ClearMenus(); - levelTryPlayMusicOrNothing(gGameOptions.nEpisode, gGameOptions.nLevel); // viewSetMessage(""); viewSetErrorMessage(""); viewResizeView(gViewSize); @@ -580,40 +557,9 @@ void StartLevel(GAMEOPTIONS *gameOptions) netWaitForEveryone(0); totalclock = 0; paused = 0; - gGameStarted = 1; ready2send = 1; } -void StartNetworkLevel(void) -{ - if (!(gGameOptions.uGameFlags&1)) - { - gGameOptions.nEpisode = gPacketStartGame.episodeId; - gGameOptions.nLevel = gPacketStartGame.levelId; - gGameOptions.nGameType = gPacketStartGame.gameType; - gGameOptions.nDifficulty = gPacketStartGame.difficulty; - gGameOptions.nMonsterSettings = gPacketStartGame.monsterSettings; - gGameOptions.nWeaponSettings = gPacketStartGame.weaponSettings; - gGameOptions.nItemSettings = gPacketStartGame.itemSettings; - gGameOptions.nRespawnSettings = gPacketStartGame.respawnSettings; - gGameOptions.bFriendlyFire = gPacketStartGame.bFriendlyFire; - gGameOptions.bKeepKeysOnRespawn = gPacketStartGame.bKeepKeysOnRespawn; - - /////// - gGameOptions.weaponsV10x = gPacketStartGame.weaponsV10x; - /////// - - gBlueFlagDropped = false; - gRedFlagDropped = false; - - if (gPacketStartGame.userMap) - levelAddUserMap(gPacketStartGame.userMapName); - else - levelSetupOptions(gGameOptions.nEpisode, gGameOptions.nLevel); - } - StartLevel(&gGameOptions); -} - void LocalKeys(void) { @@ -778,22 +724,33 @@ void ProcessFrame(void) netMasterUpdate(); } } - Mus_Fade(4000); seqKillAll(); if (gGameOptions.uGameFlags&2) { STAT_Update(true); if (gGameOptions.nGameType == 0) { + auto completion = [] (bool) { + gamestate = GS_DEMOSCREEN; + M_StartControlPanel(false); + M_SetMenu(NAME_CreditsMenu); + gGameOptions.uGameFlags &= ~3; + gRestartGame = 1; + gQuitGame = 1; + }; + if (gGameOptions.uGameFlags&8) - levelPlayEndScene(gGameOptions.nEpisode); - - M_StartControlPanel(false); - M_SetMenu(NAME_CreditsMenu); + { + levelPlayEndScene(gGameOptions.nEpisode, completion); + } + else completion(false); } - gGameOptions.uGameFlags &= ~3; - gRestartGame = 1; - gQuitGame = 1; + else + { + gGameOptions.uGameFlags &= ~3; + gRestartGame = 1; + gQuitGame = 1; + } } else { @@ -876,13 +833,12 @@ static const char* actions[] = { "Jetpack" }; -int GameInterface::app_main() +static void app_init() { - buttonMap.SetButtons(actions, NUM_ACTIONS); memcpy(&gGameOptions, &gSingleGameOptions, sizeof(GAMEOPTIONS)); - gGameOptions.nMonsterSettings = !userConfig.nomonsters; - bQuickStart = userConfig.nologo; + gGameOptions.nMonsterSettings = !userConfig.nomonsters; + bQuickStart = userConfig.nologo; ReadAllRFS(); HookReplaceFunctions(); @@ -891,29 +847,20 @@ int GameInterface::app_main() engineInit(); Printf("Loading tiles\n"); - if (pUserTiles) - { - FStringf buffer("%s%%03i.ART", pUserTiles); - if (!tileInit(0,buffer)) - ThrowError("User specified ART files not found"); - } - else - { - if (!tileInit(0,NULL)) - ThrowError("TILES###.ART files not found"); - } + if (!tileInit(0, NULL)) + I_FatalError("TILES###.ART files not found"); levelLoadDefaults(); loaddefinitionsfile(BLOODWIDESCREENDEF); loaddefinitions_game(BLOODWIDESCREENDEF, FALSE); - const char *defsfile = G_DefFile(); + const char* defsfile = G_DefFile(); uint32_t stime = timerGetTicks(); if (!loaddefinitionsfile(defsfile)) { uint32_t etime = timerGetTicks(); - Printf("Definitions file \"%s\" loaded in %d ms.\n", defsfile, etime-stime); + Printf("Definitions file \"%s\" loaded in %d ms.\n", defsfile, etime - stime); } loaddefinitions_game(defsfile, FALSE); powerupInit(); @@ -931,11 +878,10 @@ int GameInterface::app_main() ctrlInit(); timerInit(120); timerSetCallback(ClockStrobe); - // PORT-TODO: CD audio init Printf("Initializing network users\n"); netInitialize(true); - videoInit(); + videoInit(); hud_size.Callback(); Printf("Initializing sound system\n"); sndInit(); @@ -948,18 +894,17 @@ int GameInterface::app_main() gStartNewGame = 1; } videoSetViewableArea(0, 0, xdim - 1, ydim - 1); - bool playvideo = !bQuickStart; - - if (playvideo) - credLogosDos(); - UpdateDacs(0, true); +} -RESTART: +static void gameInit() +{ +//RESTART: sub_79760(); gViewIndex = myconnectindex; gMe = gView = &gPlayer[myconnectindex]; netBroadcastPlayerInfo(myconnectindex); +#if 0 Printf("Waiting for network players!\n"); netWaitForEveryone(0); if (gRestartGame) @@ -971,134 +916,94 @@ RESTART: netResetToSinglePlayer(); goto RESTART; } - UpdateNetworkMenus(); +#endif + UpdateNetworkMenus(); gQuitGame = 0; gRestartGame = 0; if (gGameOptions.nGameType > 0) { inputState.ClearAllInput(); } - if (!bAddUserMap && !gGameStarted) - { - M_StartControlPanel(false); - M_SetMenu(NAME_Mainmenu); - } - ready2send = 1; - while (!gQuitGame) + +} + +static void gameTicker() +{ + bool gameUpdate = false; + double const gameUpdateStartTime = timerGetHiTicks(); + while (gPredictTail < gNetFifoHead[myconnectindex] && !paused) { - bool bDraw; - D_ProcessEvents(); - if (gGameStarted) // gGameStarted: gameState == GS_LEVEL - { - char gameUpdate = false; - double const gameUpdateStartTime = timerGetHiTicks(); - while (gPredictTail < gNetFifoHead[myconnectindex] && !paused) - { - viewUpdatePrediction(&gFifoInput[gPredictTail&255][myconnectindex]); - } - if (numplayers == 1) - gBufferJitter = 0; - while (totalclock >= gNetFifoClock && ready2send) - { - gNetInput = gInput; - gInput = {}; - netGetInput(); - gNetFifoClock += 4; - while (gNetFifoHead[myconnectindex]-gNetFifoTail > gBufferJitter && !gStartNewGame && !gQuitGame) - { - int i; - for (i = connecthead; i >= 0; i = connectpoint2[i]) - if (gNetFifoHead[i] == gNetFifoTail) - break; - if (i >= 0) - break; - //faketimerhandler(); - ProcessFrame(); - gameUpdate = true; - } - } - if (gameUpdate) - { - g_gameUpdateTime = timerGetHiTicks() - gameUpdateStartTime; - if (g_gameUpdateAvgTime < 0.f) - g_gameUpdateAvgTime = g_gameUpdateTime; - g_gameUpdateAvgTime = ((GAMEUPDATEAVGTIMENUMSAMPLES-1.f)*g_gameUpdateAvgTime+g_gameUpdateTime)/((float) GAMEUPDATEAVGTIMENUMSAMPLES); - } - bDraw = G_FPSLimit() != 0; - if (gQuitRequest && gQuitGame) - videoClearScreen(0); - else - { - netCheckSync(); - if (bDraw) - { - viewDrawScreen(); - g_gameUpdateAndDrawTime = g_beforeSwapTime/* timerGetHiTicks()*/ - gameUpdateStartTime; - } - } - } - else // gameState == GS_DEMOSCREEN - { - // Menu background - bDraw = G_FPSLimit() != 0; - if (bDraw) - { - twod->ClearScreen(); - rotatesprite(160<<16,100<<16,65536,0,2518,0,0,0x4a,0,0,xdim-1,ydim-1); - } - if (gQuitRequest && !gQuitGame) - netBroadcastMyLogoff(gQuitRequest == 2); - } - if (bDraw) - { - gameHandleEvents(); - inputState.SetBindsEnabled(gInputMode == kInputGame); - switch (gInputMode) - { - case kInputGame: - LocalKeys(); - break; - default: - break; - } - if (gQuitGame) - continue; - - C_RunDelayedCommands(); - - ctrlGetInput(); - - switch (gInputMode) - { - case kInputMessage: - gPlayerMsg.ProcessKeys(); - gPlayerMsg.Draw(); - break; - case kInputEndGame: - gEndGameMgr.ProcessKeys(); - gEndGameMgr.Draw(); - break; - default: - break; - } - videoNextPage(); - } - if (TestBitString(gotpic, 2342)) - { - FireProcess(); - ClearBitString(gotpic, 2342); - } - //if (byte_148e29 && gStartNewGame) - //{ - // gStartNewGame = 0; - // gQuitGame = 1; - //} - if (gStartNewGame) - { - StartLevel(&gGameOptions); - } + viewUpdatePrediction(&gFifoInput[gPredictTail & 255][myconnectindex]); + } + if (numplayers == 1) + gBufferJitter = 0; + while (totalclock >= gNetFifoClock && ready2send) + { + gNetInput = gInput; + gInput = {}; + netGetInput(); + gNetFifoClock += 4; + while (gNetFifoHead[myconnectindex] - gNetFifoTail > gBufferJitter && !gStartNewGame && !gQuitGame) + { + int i; + for (i = connecthead; i >= 0; i = connectpoint2[i]) + if (gNetFifoHead[i] == gNetFifoTail) + break; + if (i >= 0) + break; + //faketimerhandler(); + ProcessFrame(); + gameUpdate = true; + } + } + if (gameUpdate) + { + g_gameUpdateTime = timerGetHiTicks() - gameUpdateStartTime; + if (g_gameUpdateAvgTime < 0.f) + g_gameUpdateAvgTime = g_gameUpdateTime; + g_gameUpdateAvgTime = ((GAMEUPDATEAVGTIMENUMSAMPLES - 1.f) * g_gameUpdateAvgTime + g_gameUpdateTime) / ((float)GAMEUPDATEAVGTIMENUMSAMPLES); + } + if (gQuitRequest && gQuitGame) + videoClearScreen(0); + else + { + netCheckSync(); + viewDrawScreen(); + g_gameUpdateAndDrawTime = g_beforeSwapTime/* timerGetHiTicks()*/ - gameUpdateStartTime; + } +} + +static void drawBackground() +{ + twod->ClearScreen(); + rotatesprite(160 << 16, 100 << 16, 65536, 0, 2518, 0, 0, 0x4a, 0, 0, xdim - 1, ydim - 1); + if (gQuitRequest && !gQuitGame) + netBroadcastMyLogoff(gQuitRequest == 2); +} + +static void commonTicker(bool &playvideo) +{ + if (TestBitString(gotpic, 2342)) + { + FireProcess(); + ClearBitString(gotpic, 2342); + } + if (gStartNewGame) + { + StartLevel(&gGameOptions); + + auto completion = [](bool = false) + { + levelTryPlayMusicOrNothing(gGameOptions.nEpisode, gGameOptions.nLevel); + gamestate = GS_LEVEL; + }; + + if ((gGameOptions.uGameFlags & 4)) + levelPlayIntroScene(gGameOptions.nEpisode, completion); + else + completion(false); + } - ready2send = 0; if (gRestartGame) { Mus_Stop(); @@ -1106,21 +1011,70 @@ RESTART: gQuitGame = 0; gQuitRequest = 0; gRestartGame = 0; - gGameStarted = 0; - levelSetupOptions(0,0); + levelSetupOptions(0, 0); + - if (gGameOptions.nGameType != 0) { - videoSetViewableArea(0,0,xdim-1,ydim-1); - playvideo = !bQuickStart; + playvideo = !bQuickStart; } - else playvideo = false; - - goto RESTART; + else playvideo = false; + gamestate = GS_STARTUP; } - ShutDown(); +} +int GameInterface::app_main() +{ + + app_init(); + gamestate = GS_STARTUP; + bool playvideo = !bQuickStart; + while (true) + { + if (gamestate == GS_STARTUP) gameInit(); + + commonTicker(playvideo); + gameHandleEvents(); + D_ProcessEvents(); + ctrlGetInput(); + + switch (gamestate) + { + default: + case GS_STARTUP: + if (playvideo) playlogos(); + else + { + gamestate = GS_DEMOSCREEN; + M_StartControlPanel(false); + M_SetMenu(NAME_Mainmenu); + } + break; + + case GS_DEMOSCREEN: + 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; + } + + videoNextPage(); + + + } return 0; } @@ -1449,7 +1403,7 @@ extern IniFile* BloodINI; void GameInterface::FreeGameData() { if (BloodINI) delete BloodINI; - ShutDown(); + netDeinitialize(); } void GameInterface::UpdateScreenSize() diff --git a/source/blood/src/blood.h b/source/blood/src/blood.h index c1383a9a2..cb4bc5c6b 100644 --- a/source/blood/src/blood.h +++ b/source/blood/src/blood.h @@ -106,13 +106,6 @@ struct INICHAIN { extern INICHAIN *pINIChain; -enum INPUT_MODE { - kInputGame = 0, - kInputMessage, - kInputEndGame, -}; - -extern INPUT_MODE gInputMode; extern short BloodVersion; extern int gNetPlayers; extern bool gRestartGame; diff --git a/source/blood/src/controls.cpp b/source/blood/src/controls.cpp index a50a35ae0..cfe5a12d1 100644 --- a/source/blood/src/controls.cpp +++ b/source/blood/src/controls.cpp @@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "map2d.h" #include "view.h" #include "d_event.h" +#include "gamestate.h" BEGIN_BLD_NS @@ -83,7 +84,7 @@ void ctrlGetInput(void) auto scaleAdjustmentToInterval = [=](double x) { return x * kTicsPerSec / (1000.0 / elapsedInputTicks); }; - if (!gGameStarted || gInputMode != kInputGame) + if (gamestate != GS_LEVEL || System_WantGuiCapture()) { gInput = {}; CONTROL_GetInput(&info); @@ -414,15 +415,4 @@ void ctrlGetInput(void) } } -#if 0 -if (gGameStarted && gInputMode != kInputMessage - && buttonMap.ButtonDown(gamefunc_SendMessage)) -{ - buttonMap.ClearButton(gamefunc_SendMessage); - inputState.keyFlushScans(); - gInputMode = kInputMessage; -} - -#endif - END_BLD_NS diff --git a/source/blood/src/credits.cpp b/source/blood/src/credits.cpp index 374b9f45b..f629fdd82 100644 --- a/source/blood/src/credits.cpp +++ b/source/blood/src/credits.cpp @@ -37,212 +37,113 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "../glbackend/glbackend.h" #include "raze_sound.h" #include "v_2ddrawer.h" +#include "screenjob.h" +#include "gamestate.h" +#include "seq.h" +#include "menu.h" BEGIN_BLD_NS -char exitCredits = 0; -char Wait(int nTicks) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void playlogos() { - totalclock = 0; - while (totalclock < nTicks) - { - gameHandleEvents(); - auto key = inputState.keyGetScan(); - if (key) - { - if (key == sc_Escape) // sc_Escape - exitCredits = 1; - return 0; - } - } - return 1; + JobDesc jobs[6]; + int job = 0; + static AnimSound logosound[] = + { + { 1, -1 }, + { -1, -1 }, + { 1, -1 }, + { -1,-1 } + }; + + if (logosound[0].soundnum == -1) + { + logosound[0].soundnum = S_FindSound("logo.wav"); + logosound[2].soundnum = S_FindSound("gt.wav"); + } + + + if (fileSystem.FindFile("logo.smk")) + { + jobs[job++] = { PlayVideo("logo.smk", &logosound[0], 0) }; + } + else + { + jobs[job++] = { Create(1), []() { sndStartSample("THUNDER2", 128, -1); }}; + jobs[job++] = { Create(2050) }; + } + if (fileSystem.FindFile("gti.smk")) + { + jobs[job++] = { PlayVideo("gti.smk", &logosound[2], 0) }; + } + else + { + jobs[job++] = { Create(1), []() { sndStartSample("THUNDER2", 128, -1); }}; + jobs[job++] = { Create(2052) }; + } + jobs[job++] = { Create(1), []() { sndPlaySpecialMusicOrNothing(MUS_INTRO); sndStartSample("THUNDER2", 128, -1); }}; + jobs[job++] = { Create(2518, DScreenJob::fadein) }; + + RunScreenJob(jobs, job, [](bool) { + gamestate = GS_DEMOSCREEN; + M_StartControlPanel(false); + M_SetMenu(NAME_Mainmenu); + }, true, true); } -char DoFade(char r, char g, char b, int nTicks) +void playSmk(const char *smk, const char *wav, int wavid, CompletionFunc func) { - return 1; + JobDesc jobs{}; + static AnimSound smksound[] = + { + { 1, -1 }, + { -1, -1 }, + }; + int id = S_FindSoundByResID(wavid); + if (id <= 0) + { + FString wavv = wav; + FixPathSeperator(wavv); + id = S_FindSound(wavv); + } + FString smkk = smk; + FixPathSeperator(smkk); + smksound[0].soundnum = id; + jobs.job = PlayVideo(smkk, smksound, nullptr); + RunScreenJob(&jobs, 1, func); } -char DoUnFade(int nTicks) +void levelPlayIntroScene(int nEpisode, CompletionFunc completion) { - return 1; + gGameOptions.uGameFlags &= ~4; + Mus_Stop(); + sndKillAllSounds(); + sfxKillAllSounds(); + ambKillAll(); + seqKillAll(); + EPISODEINFO *pEpisode = &gEpisodeInfo[nEpisode]; + playSmk(pEpisode->at8f08, pEpisode->at9030, pEpisode->at9028, completion); } -void credPlaySmk(const char* _pzSMK, const char* _pzWAV, int nWav); - -void credLogosDos(void) +void levelPlayEndScene(int nEpisode, CompletionFunc completion) { - char bShift = inputState.ShiftPressed(); - videoSetViewableArea(0, 0, xdim-1, ydim-1); - DoUnFade(1); - if (bShift) - return; - { - if (fileSystem.FindFile("logo.smk")) - { - credPlaySmk("logo.smk", "logo.wav", -1); - } - else - { - twod->ClearScreen(); - rotatesprite(160<<16, 100<<16, 65536, 0, 2050, 0, 0, 0x4a, 0, 0, xdim-1, ydim-1); - sndStartSample("THUNDER2", 128, -1); - videoNextPage(); - if (!Wait(360)) - return; - if (!DoFade(0, 0, 0, 60)) - return; - } - if (fileSystem.FindFile("gti.smk")) - { - credPlaySmk("gti.smk", "gt.wav", -1); - } - else - { - twod->ClearScreen(); - rotatesprite(160<<16, 100<<16, 65536, 0, 2052, 0, 0, 0x0a, 0, 0, xdim-1, ydim-1); - videoNextPage(); - DoUnFade(1); - sndStartSample("THUNDER2", 128, -1); - if (!Wait(360)) - return; - } - } - sndPlaySpecialMusicOrNothing(MUS_INTRO); - sndStartSample("THUNDER2", 128, -1); - if (!DoFade(0, 0, 0, 60)) - return; - twod->ClearScreen(); - videoNextPage(); - if (!DoUnFade(1)) - return; - twod->ClearScreen(); - rotatesprite(160<<16, 100<<16, 65536, 0, 2518, 0, 0, 0x4a, 0, 0, xdim-1, ydim-1); - videoNextPage(); - Wait(360); - //Mus_Fade(4000); -} - -void credReset(void) -{ - twod->ClearScreen(); - videoNextPage(); - DoFade(0,0,0,1); - DoUnFade(1); -} - -bool credKOpen4Load(FString &pzFile) -{ - int nLen = strlen(pzFile); - FixPathSeperator(pzFile); - auto nHandle = fileSystem.FindFile(pzFile); - if (nHandle < 0) - { - // Strip the drive letter and retry. - if (nLen >= 3 && isalpha(pzFile[0]) && pzFile[1] == ':' && pzFile[2] == '/') - { - pzFile = pzFile.Mid(3); - nHandle = fileSystem.FindFile(pzFile); - } - } - return nHandle; -} - -void credPlaySmk(const char *_pzSMK, const char *_pzWAV, int nWav) -{ - if (!_pzSMK || !*_pzSMK) - return; - FString pzSMK = _pzSMK; - FString pzWAV = _pzWAV; - auto nHandleSMK = credKOpen4Load(pzSMK); - if (!nHandleSMK) - { - return; - } - SmackerHandle hSMK = Smacker_Open(pzSMK); - if (!hSMK.isValid) - { - return; - } - uint32_t nWidth, nHeight; - Smacker_GetFrameSize(hSMK, nWidth, nHeight); - uint8_t palette[768]; - AnimTextures animtex; - TArray pFrame(nWidth * nHeight + std::max(nWidth, nHeight), true); - animtex.SetSize(AnimTexture::Paletted, nWidth, nHeight); - int nFrameRate = Smacker_GetFrameRate(hSMK); - int nFrames = Smacker_GetNumFrames(hSMK); - - Smacker_GetPalette(hSMK, palette); + gGameOptions.uGameFlags &= ~8; Mus_Stop(); - - int nScale; - int nStat; - - if (nWidth <= 320 && nHeight <= 200) - { - if ((nWidth / (nHeight * 1.2f)) > (1.f * xdim / ydim)) - nScale = divscale16(320 * xdim * 3, nWidth * ydim * 4); - else - nScale = divscale16(200, nHeight); - nStat = 2 | 8 | 64; - } - else - { - // DOS Blood v1.11: 320x240, 320x320, 640x400, and 640x480 SMKs all display 1:1 and centered in a 640x480 viewport - int num = scale(65536, ydim << 2, xdim * 3); - int div = (max(nHeight, 240 + 1u) + 239) / 240; - nScale = num / div; - nStat = 2 | 8 | 64 | 1024; - renderSetAspect(viewingrange, 65536); - } - - - if (nWav > 0) - sndStartWavID(nWav, 255); - else - { - auto nHandleWAV = credKOpen4Load(pzWAV); - if (nHandleWAV) - { - sndStartWavDisk(pzWAV, 255); - } - } - - - gameHandleEvents(); - ClockTicks nStartTime = totalclock; - - inputState.ClearAllInput(); - - int nFrame = 0; - hw_int_useindexedcolortextures = false; - do - { - gameHandleEvents(); - if (scale((int)(totalclock-nStartTime), nFrameRate, kTicRate) < nFrame) - continue; - - if (inputState.CheckAllInput()) - break; - - twod->ClearScreen(); - Smacker_GetPalette(hSMK, palette); - Smacker_GetFrame(hSMK, pFrame.Data()); - animtex.SetFrame(palette, pFrame.Data()); - rotatesprite_fs(160<<16, 100<<16, nScale, 0, -1, 0, 0, nStat, animtex.GetFrame()); - - videoNextPage(); - - nFrame++; - Smacker_GetNextFrame(hSMK); - } while(nFrame < nFrames); - hw_int_useindexedcolortextures = hw_useindexedcolortextures; - - Smacker_Close(hSMK); - inputState.ClearAllInput(); - soundEngine->StopAllChannels(); + sndKillAllSounds(); + sfxKillAllSounds(); + ambKillAll(); + seqKillAll(); + EPISODEINFO *pEpisode = &gEpisodeInfo[nEpisode]; + playSmk(pEpisode->at8f98, pEpisode->at90c0, pEpisode->at902c, completion); } + + END_BLD_NS diff --git a/source/blood/src/credits.h b/source/blood/src/credits.h deleted file mode 100644 index 03cbb05ae..000000000 --- a/source/blood/src/credits.h +++ /dev/null @@ -1,31 +0,0 @@ -//------------------------------------------------------------------------- -/* -Copyright (C) 2010-2019 EDuke32 developers and contributors -Copyright (C) 2019 Nuke.YKT - -This file is part of NBlood. - -NBlood is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -//------------------------------------------------------------------------- -#pragma once - -BEGIN_BLD_NS - -void credLogosDos(void); -void credReset(void); -void credPlaySmk(const char *pzSMK, const char *pzWAV, int nWAV); - -END_BLD_NS diff --git a/source/blood/src/d_menu.cpp b/source/blood/src/d_menu.cpp index 6f508d7c1..45103f7e8 100644 --- a/source/blood/src/d_menu.cpp +++ b/source/blood/src/d_menu.cpp @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c_bind.h" #include "menu.h" #include "sound.h" +#include "gamestate.h" bool ShowOptionMenu(); @@ -247,7 +248,7 @@ void GameInterface::MenuClosed() bool GameInterface::CanSave() { - return (gGameStarted && gPlayer[myconnectindex].pXSprite->health != 0); + return (gamestate == GS_LEVEL && gPlayer[myconnectindex].pXSprite->health != 0); } void GameInterface::StartGame(FNewGameStartup& gs) diff --git a/source/blood/src/endgame.cpp b/source/blood/src/endgame.cpp index 0d68f68f5..f4e4905b5 100644 --- a/source/blood/src/endgame.cpp +++ b/source/blood/src/endgame.cpp @@ -39,6 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "messages.h" #include "statistics.h" #include "gstrings.h" +#include "gamestate.h" #include "raze_sound.h" BEGIN_BLD_NS @@ -86,8 +87,7 @@ void CEndGameMgr::ProcessKeys(void) //} //else { - char ch = inputState.keyGetScan(); - if (!ch) + if (!inputState.CheckAllInput()) return; if (gGameOptions.nGameType > 0 || numplayers > 1) netWaitForEveryone(0); @@ -99,8 +99,7 @@ extern void EndLevel(void); void CEndGameMgr::Setup(void) { - at1 = gInputMode; - gInputMode = kInputEndGame; + gamestate = GS_FINALE; at0 = 1; STAT_Update(false); EndLevel(); @@ -119,7 +118,6 @@ void CEndGameMgr::Finish(void) gInitialNetPlayers = numplayers; soundEngine->StopAllChannels(); gStartNewGame = 1; - gInputMode = (INPUT_MODE)at1; at0 = 0; } diff --git a/source/blood/src/levels.cpp b/source/blood/src/levels.cpp index 00b3518dc..7921a876c 100644 --- a/source/blood/src/levels.cpp +++ b/source/blood/src/levels.cpp @@ -29,7 +29,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "blood.h" #include "globals.h" -#include "credits.h" #include "endgame.h" #include "inifile.h" #include "levels.h" @@ -56,7 +55,6 @@ EPISODEINFO gEpisodeInfo[kMaxEpisodes+1]; int gSkill = 2; int gEpisodeCount; int gNextLevel; -bool gGameStarted; int gLevelTime; @@ -83,35 +81,6 @@ void levelOverrideINI(const char *pzIni) strcpy(BloodIniFile, pzIni); } -void levelPlayIntroScene(int nEpisode) -{ - gGameOptions.uGameFlags &= ~4; - Mus_SetPaused(true); - sndKillAllSounds(); - sfxKillAllSounds(); - ambKillAll(); - seqKillAll(); - EPISODEINFO *pEpisode = &gEpisodeInfo[nEpisode]; - credPlaySmk(pEpisode->at8f08, pEpisode->at9030, pEpisode->at9028); - viewResizeView(gViewSize); - credReset(); - Mus_SetPaused(false); -} - -void levelPlayEndScene(int nEpisode) -{ - gGameOptions.uGameFlags &= ~8; - Mus_Stop(); - sndKillAllSounds(); - sfxKillAllSounds(); - ambKillAll(); - seqKillAll(); - EPISODEINFO *pEpisode = &gEpisodeInfo[nEpisode]; - credPlaySmk(pEpisode->at8f98, pEpisode->at90c0, pEpisode->at902c); - viewResizeView(gViewSize); - credReset(); -} - void levelClearSecrets(void) { gSecretMgr.Clear(); @@ -412,14 +381,12 @@ void LevelsLoadSave::Load(void) { Read(&gNextLevel, sizeof(gNextLevel)); Read(&gGameOptions, sizeof(gGameOptions)); - Read(&gGameStarted, sizeof(gGameStarted)); } void LevelsLoadSave::Save(void) { Write(&gNextLevel, sizeof(gNextLevel)); Write(&gGameOptions, sizeof(gGameOptions)); - Write(&gGameStarted, sizeof(gGameStarted)); } void LevelsLoadSaveConstruct(void) diff --git a/source/blood/src/levels.h b/source/blood/src/levels.h index 70d54bc41..e1b00d85e 100644 --- a/source/blood/src/levels.h +++ b/source/blood/src/levels.h @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //------------------------------------------------------------------------- #pragma once +#include "screenjob.h" #include "common_game.h" #include "inifile.h" #include "mapinfo.h" @@ -98,8 +99,8 @@ extern int gLevelTime; void levelInitINI(const char *pzIni); void levelOverrideINI(const char *pzIni); -void levelPlayIntroScene(int nEpisode); -void levelPlayEndScene(int nEpisode); +void levelPlayIntroScene(int nEpisode, CompletionFunc completion); +void levelPlayEndScene(int nEpisode, CompletionFunc completion); void levelSetupSecret(int nCount); void levelTriggerSecret(int nSecret); void CheckSectionAbend(const char *pzSection); diff --git a/source/blood/src/loadsave.cpp b/source/blood/src/loadsave.cpp index bc5346578..96108ea5d 100644 --- a/source/blood/src/loadsave.cpp +++ b/source/blood/src/loadsave.cpp @@ -44,6 +44,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "savegamehelp.h" #include "raze_music.h" #include "mapinfo.h" +#include "gamestate.h" #include "aistate.h" #include "aiunicult.h" @@ -480,7 +481,7 @@ bool GameInterface::LoadGame(FSaveGameNode* node) sfxKillAllSounds(); ambKillAll(); seqKillAll(); - if (!gGameStarted) + if (gamestate != GS_LEVEL) { memset(xsprite, 0, sizeof(xsprite)); } @@ -524,7 +525,7 @@ bool GameInterface::LoadGame(FSaveGameNode* node) else gGameMessageMgr.Clear(); viewSetErrorMessage(""); - if (!gGameStarted) + if (gamestate != GS_LEVEL) { netWaitForEveryone(0); memset(gPlayerReady, 0, sizeof(gPlayerReady)); @@ -534,7 +535,7 @@ bool GameInterface::LoadGame(FSaveGameNode* node) gFrameRate = 0; totalclock = 0; paused = 0; - gGameStarted = 1; + gamestate = GS_LEVEL; bVanilla = false; diff --git a/source/blood/src/messages.cpp b/source/blood/src/messages.cpp index 0fb6f234e..ecd7f885f 100644 --- a/source/blood/src/messages.cpp +++ b/source/blood/src/messages.cpp @@ -337,7 +337,7 @@ void CGameMessageMgr::Display(void) { if (VanillaMode()) { - if (numberOfDisplayedMessages && this->state && gInputMode != kInputMessage) + if (numberOfDisplayedMessages && this->state) { int initialNrOfDisplayedMsgs = numberOfDisplayedMessages; int initialMessagesIndex = messagesIndex; @@ -368,7 +368,7 @@ void CGameMessageMgr::Display(void) } else { - if (this->state && gInputMode != kInputMessage) + if (this->state) { messageStruct* currentMessages[kMessageLogSize]; int currentMessagesCount = 0; @@ -500,7 +500,6 @@ void CPlayerMsg::Clear(void) void CPlayerMsg::Term(void) { Clear(); - gInputMode = kInputGame; } void CPlayerMsg::Draw(void) diff --git a/source/blood/src/misc.h b/source/blood/src/misc.h index a1fc41399..5c869dcf7 100644 --- a/source/blood/src/misc.h +++ b/source/blood/src/misc.h @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS +void playlogos(); void *ResReadLine(char *buffer, unsigned int nBytes, void **pRes); unsigned int qrand(void); int wrand(void); diff --git a/source/blood/src/network.cpp b/source/blood/src/network.cpp index 6f9320e83..9e46c3d49 100644 --- a/source/blood/src/network.cpp +++ b/source/blood/src/network.cpp @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "sound.h" #include "view.h" #include "menu.h" +#include "gamestate.h" extern bool gHaveNetworking; @@ -1326,7 +1327,7 @@ void netPlayerQuit(int nPlayer) char buffer[128]; sprintf(buffer, "%s left the game with %d frags.", gProfile[nPlayer].name, gPlayer[nPlayer].fragCount); viewSetMessage(buffer); - if (gGameStarted) + if (gamestate == GS_LEVEL) { seqKill(3, gPlayer[nPlayer].pSprite->extra); actPostSprite(gPlayer[nPlayer].nSprite, kStatFree); diff --git a/source/blood/src/osdcmd.cpp b/source/blood/src/osdcmd.cpp index 3cc4ba52d..ee8fd109f 100644 --- a/source/blood/src/osdcmd.cpp +++ b/source/blood/src/osdcmd.cpp @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "sound.h" #include "view.h" #include "mapinfo.h" +#include "gamestate.h" BEGIN_BLD_NS @@ -89,7 +90,7 @@ static int osdcmd_map(CCmdFuncPtr parm) static int osdcmd_give(CCmdFuncPtr parm) { - if (numplayers != 1 || !gGameStarted || gMe->pXSprite->health == 0) + if (numplayers != 1 || gamestate != GS_LEVEL|| gMe->pXSprite->health == 0) { Printf("give: Cannot give while dead or not in a single-player game.\n"); return CCMD_OK; @@ -149,7 +150,7 @@ static int osdcmd_give(CCmdFuncPtr parm) static int osdcmd_god(CCmdFuncPtr UNUSED(parm)) { UNREFERENCED_CONST_PARAMETER(parm); - if (numplayers == 1 && gGameStarted) + if (numplayers == 1 && gamestate == GS_LEVEL) { SetGodMode(!gMe->godMode); gCheatMgr.m_bPlayerCheated = true; @@ -164,7 +165,7 @@ static int osdcmd_noclip(CCmdFuncPtr UNUSED(parm)) { UNREFERENCED_CONST_PARAMETER(parm); - if (numplayers == 1 && gGameStarted) + if (numplayers == 1 && gamestate == GS_LEVEL) { SetClipMode(!gNoClip); gCheatMgr.m_bPlayerCheated = true; diff --git a/source/core/raze_music.cpp b/source/core/raze_music.cpp index 03340ae89..02373c1f2 100644 --- a/source/core/raze_music.cpp +++ b/source/core/raze_music.cpp @@ -225,12 +225,6 @@ void Mus_Stop() S_StopMusic(true); } -void Mus_Fade(double seconds) -{ - // Todo: Blood uses this, but the streamer cannot currently fade the volume. - Mus_Stop(); -} - void Mus_SetPaused(bool on) { if (on) S_PauseMusic(); diff --git a/source/core/raze_music.h b/source/core/raze_music.h index 57e492c67..fd968aefd 100644 --- a/source/core/raze_music.h +++ b/source/core/raze_music.h @@ -13,7 +13,6 @@ void Mus_UpdateMusic(); int Mus_Play(const char *mapname, const char *fn, bool loop); void Mus_Stop(); bool Mus_IsPlaying(); -void Mus_Fade(double seconds); void Mus_SetPaused(bool on); void Mus_ResumeSaved(); FString G_SetupFilenameBasedMusic(const char* fileName, const char *defaultfn); diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 6f54da6a8..bf8277344 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -45,6 +45,7 @@ #include "gamestate.h" #include "menu.h" #include "raze_sound.h" +#include "SmackerDecoder.h" #include "movie/playmve.h" #include "gamecontrol.h" @@ -52,6 +53,14 @@ IMPLEMENT_CLASS(DScreenJob, true, false) IMPLEMENT_CLASS(DImageScreen, true, false) + +int DBlackScreen::Frame(uint64_t clock, bool skiprequest) +{ + int span = int(clock / 1'000'000); + twod->ClearScreen(); + return span < wait ? 1 : -1; +} + //--------------------------------------------------------------------------- // // @@ -69,7 +78,7 @@ int DImageScreen::Frame(uint64_t clock, bool skiprequest) twod->ClearScreen(); DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, 3, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); // Only end after having faded out. - return skiprequest ? -1 : 1; + return skiprequest ? -1 : span > waittime? 0 : 1; } //--------------------------------------------------------------------------- @@ -212,6 +221,103 @@ public: } }; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class DSmkPlayer : public DScreenJob +{ + SmackerHandle hSMK{}; + uint32_t nWidth, nHeight; + uint8_t palette[768]; + AnimTextures animtex; + TArray pFrame; + int nFrameRate; + int nFrames; + bool fullscreenScale; + uint64_t nFrameNs; + int nFrame = 0; + const AnimSound* animSnd; + FString filename; + +public: + bool isvalid() { return hSMK.isValid; } + + DSmkPlayer(const char *fn, const AnimSound* ans, bool fixedviewport) + { + hSMK = Smacker_Open(fn); + if (!hSMK.isValid) + { + return; + } + Smacker_GetFrameSize(hSMK, nWidth, nHeight); + pFrame.Resize(nWidth * nHeight + std::max(nWidth, nHeight)); + nFrameRate = Smacker_GetFrameRate(hSMK); + nFrameNs = 1'000'000'000 / nFrameRate; + nFrames = Smacker_GetNumFrames(hSMK); + Smacker_GetPalette(hSMK, palette); + fullscreenScale = (!fixedviewport || (nWidth <= 320 && nHeight <= 200) || nWidth >= 640 || nHeight >= 480); + animSnd = ans; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + int Frame(uint64_t clock, bool skiprequest) override + { + int frame = clock / nFrameNs; + + if (clock == 0) + { + animtex.SetSize(AnimTexture::Paletted, nWidth, nHeight); + } + twod->ClearScreen(); + if (frame > nFrame) + { + Smacker_GetPalette(hSMK, palette); + Smacker_GetFrame(hSMK, pFrame.Data()); + animtex.SetFrame(palette, pFrame.Data()); + } + if (fullscreenScale) + { + DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, 3, TAG_DONE); + } + else + { + DrawTexture(twod, animtex.GetFrame(), 320, 240, DTA_VirtualWidth, 640, DTA_VirtualHeight, 480, DTA_CenterOffset, true, TAG_DONE); + } + if (frame > nFrame) + { + nFrame++; + Smacker_GetNextFrame(hSMK); + for (int i = 0; animSnd[i].framenum >= 0; i++) + { + if (animSnd[i].framenum == nFrame) + { + int sound = animSnd[i].soundnum; + if (sound == -1) + soundEngine->StopAllChannels(); + else + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); + } + } + } + + return skiprequest ? -1 : nFrame < nFrames ? 1 : 0; + } + + void OnDestroy() override + { + Smacker_Close(hSMK); + soundEngine->StopAllChannels(); + } +}; + //--------------------------------------------------------------------------- // // @@ -228,6 +334,13 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra auto fr = fileSystem.OpenFileReader(filename); if (!fr.isOpen()) { + int nLen = strlen(filename); + // Strip the drive letter and retry. + if (nLen >= 3 && isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/') + { + filename += 3; + fr = fileSystem.OpenFileReader(filename); + } Printf("%s: Unable to open video\n", filename); return nothing(); } @@ -243,13 +356,21 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra { Printf("%s: invalid ANM file.\n", filename); anm->Destroy(); - return nothing(); + return nothing(); } return anm; } else if (!memcmp(id, "SMK2", 4)) { - // todo + fr.Close(); + auto anm = Create(filename, ans, true); // Fixme: Handle Blood's video scaling behavior more intelligently. + if (!anm->isvalid()) + { + Printf("%s: invalid SMK file.\n", filename); + anm->Destroy(); + return nothing(); + } + return anm; } else if (!memcmp(id, "Interplay MVE File", 18)) { @@ -317,7 +438,6 @@ public: { for (auto& job : jobs) { - job.job->Destroy(); job.job->ObjectFlags |= OF_YesReallyDelete; delete job.job; } @@ -326,9 +446,17 @@ public: void AdvanceJob(bool skip) { - if (index >= 0 && jobs[index].postAction) jobs[index].postAction(); + if (index >= 0) + { + if (jobs[index].postAction) jobs[index].postAction(); + jobs[index].job->Destroy(); + } index++; - while (index < jobs.Size() && (jobs[index].job == nullptr || (skip && jobs[index].ignoreifskipped))) index++; + while (index < jobs.Size() && (jobs[index].job == nullptr || (skip && jobs[index].ignoreifskipped))) + { + if (jobs[index].job != nullptr) jobs[index].job->Destroy(); + index++; + } actionState = clearbefore ? State_Clear : State_Run; if (index < jobs.Size()) screenfade = jobs[index].job->fadestyle & DScreenJob::fadein ? 0.f : 1.f; startTime = -1; diff --git a/source/core/screenjob.h b/source/core/screenjob.h index 4093e9a57..661d0a10a 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -1,6 +1,7 @@ #pragma once #include #include "dobject.h" +#include "v_2ddrawer.h" using CompletionFunc = std::function; struct JobDesc; @@ -47,20 +48,36 @@ public: // //--------------------------------------------------------------------------- +class DBlackScreen : public DScreenJob +{ + int wait; + +public: + DBlackScreen(int w) : wait(w) {} + int Frame(uint64_t clock, bool skiprequest) override; +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + class DImageScreen : public DScreenJob { DECLARE_CLASS(DImageScreen, DScreenJob) int tilenum = -1; + int waittime; // in ms. FGameTexture* tex = nullptr; public: - DImageScreen(FGameTexture* tile, int fade = DScreenJob::fadein | DScreenJob::fadeout) : DScreenJob(fade) + DImageScreen(FGameTexture* tile, int fade = DScreenJob::fadein | DScreenJob::fadeout, int wait = 3000) : DScreenJob(fade), waittime(wait) { tex = tile; } - DImageScreen(int tile, int fade = DScreenJob::fadein | DScreenJob::fadeout) : DScreenJob(fade) + DImageScreen(int tile, int fade = DScreenJob::fadein | DScreenJob::fadeout, int wait = 3000) : DScreenJob(fade), waittime(wait) { tilenum = tile; } diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index df3500d65..5306f118e 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -373,26 +373,6 @@ public: // //--------------------------------------------------------------------------- -class DBlackScreen : public DScreenJob -{ - int wait; - -public: - DBlackScreen(int w) : wait(w) {} - int Frame(uint64_t clock, bool skiprequest) - { - int span = int(clock / 1'000'000); - twod->ClearScreen(); - return span < wait ? 1 : -1; - } -}; - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - class DEpisode3End : public DImageScreen { int sound = 0;