- 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
This commit is contained in:
Christoph Oelckers 2020-07-29 23:18:08 +02:00
parent 0958bccade
commit 347ed51036
19 changed files with 444 additions and 549 deletions

View file

@ -34,7 +34,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "blood.h" #include "blood.h"
#include "choke.h" #include "choke.h"
#include "controls.h" #include "controls.h"
#include "credits.h"
#include "dude.h" #include "dude.h"
#include "endgame.h" #include "endgame.h"
#include "eventq.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 "raze_sound.h"
#include "nnexts.h" #include "nnexts.h"
#include "secrets.h" #include "secrets.h"
#include "gamestate.h"
#include "screenjob.h"
BEGIN_BLD_NS BEGIN_BLD_NS
INPUT_MODE gInputMode;
#ifdef USE_QHEAP
unsigned int nMaxAlloc = 0x4000000;
#endif
char bAddUserMap = false; char bAddUserMap = false;
bool bNoDemo = false; bool bNoDemo = false;
bool bQuickStart = true; bool bQuickStart = true;
@ -80,8 +75,6 @@ short BloodVersion = 0x115;
int gNetPlayers; int gNetPlayers;
char *pUserTiles = NULL;
int gChokeCounter = 0; int gChokeCounter = 0;
double g_gameUpdateTime, g_gameUpdateAndDrawTime; double g_gameUpdateTime, g_gameUpdateAndDrawTime;
@ -131,21 +124,9 @@ enum gametokens
int blood_globalflags; int blood_globalflags;
void ShutDown(void)
{
if (!in3dmode())
return;
netDeinitialize();
//sndTerm();
sfxTerm();
// PORT_TODO: Check argument
DO_FREE_AND_NULL(pUserTiles);
}
void QuitGame(void) void QuitGame(void)
{ {
ShutDown(); throw CExitEvent(0);
Bexit(0);
} }
void PrecacheDude(spritetype *pSprite) void PrecacheDude(spritetype *pSprite)
@ -412,8 +393,6 @@ void StartLevel(GAMEOPTIONS *gameOptions)
if (gEpisodeInfo[gGameOptions.nEpisode].cutALevel == gGameOptions.nLevel if (gEpisodeInfo[gGameOptions.nEpisode].cutALevel == gGameOptions.nLevel
&& gEpisodeInfo[gGameOptions.nEpisode].at8f08) && gEpisodeInfo[gGameOptions.nEpisode].at8f08)
gGameOptions.uGameFlags |= 4; gGameOptions.uGameFlags |= 4;
if ((gGameOptions.uGameFlags&4))
levelPlayIntroScene(gGameOptions.nEpisode);
/////// ///////
gGameOptions.weaponsV10x = gWeaponsV10x; gGameOptions.weaponsV10x = gWeaponsV10x;
@ -455,11 +434,10 @@ void StartLevel(GAMEOPTIONS *gameOptions)
enginecompatibility_mode = ENGINECOMPATIBILITY_19960925;//bVanilla; enginecompatibility_mode = ENGINECOMPATIBILITY_19960925;//bVanilla;
memset(xsprite,0,sizeof(xsprite)); memset(xsprite,0,sizeof(xsprite));
memset(sprite,0,kMaxSprites*sizeof(spritetype)); 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)) if (dbLoadMap(gameOptions->zLevelName,(int*)&startpos.x,(int*)&startpos.y,(int*)&startpos.z,&startang,&startsectnum,(unsigned int*)&gameOptions->uMapCRC))
{ {
gQuitGame = true; I_Error("Unable to load map");
return;
} }
currentLevel = &mapList[gGameOptions.nEpisode * kMaxLevels + gGameOptions.nLevel]; currentLevel = &mapList[gGameOptions.nEpisode * kMaxLevels + gGameOptions.nLevel];
SECRET_SetMapName(currentLevel->DisplayName(), currentLevel->name); SECRET_SetMapName(currentLevel->DisplayName(), currentLevel->name);
@ -571,7 +549,6 @@ void StartLevel(GAMEOPTIONS *gameOptions)
gFrame = 0; gFrame = 0;
gChokeCounter = 0; gChokeCounter = 0;
M_ClearMenus(); M_ClearMenus();
levelTryPlayMusicOrNothing(gGameOptions.nEpisode, gGameOptions.nLevel);
// viewSetMessage(""); // viewSetMessage("");
viewSetErrorMessage(""); viewSetErrorMessage("");
viewResizeView(gViewSize); viewResizeView(gViewSize);
@ -580,40 +557,9 @@ void StartLevel(GAMEOPTIONS *gameOptions)
netWaitForEveryone(0); netWaitForEveryone(0);
totalclock = 0; totalclock = 0;
paused = 0; paused = 0;
gGameStarted = 1;
ready2send = 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) void LocalKeys(void)
{ {
@ -778,22 +724,33 @@ void ProcessFrame(void)
netMasterUpdate(); netMasterUpdate();
} }
} }
Mus_Fade(4000);
seqKillAll(); seqKillAll();
if (gGameOptions.uGameFlags&2) if (gGameOptions.uGameFlags&2)
{ {
STAT_Update(true); STAT_Update(true);
if (gGameOptions.nGameType == 0) 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) if (gGameOptions.uGameFlags&8)
levelPlayEndScene(gGameOptions.nEpisode); {
levelPlayEndScene(gGameOptions.nEpisode, completion);
M_StartControlPanel(false); }
M_SetMenu(NAME_CreditsMenu); else completion(false);
} }
gGameOptions.uGameFlags &= ~3; else
gRestartGame = 1; {
gQuitGame = 1; gGameOptions.uGameFlags &= ~3;
gRestartGame = 1;
gQuitGame = 1;
}
} }
else else
{ {
@ -876,13 +833,12 @@ static const char* actions[] = {
"Jetpack" "Jetpack"
}; };
int GameInterface::app_main() static void app_init()
{ {
buttonMap.SetButtons(actions, NUM_ACTIONS); buttonMap.SetButtons(actions, NUM_ACTIONS);
memcpy(&gGameOptions, &gSingleGameOptions, sizeof(GAMEOPTIONS)); memcpy(&gGameOptions, &gSingleGameOptions, sizeof(GAMEOPTIONS));
gGameOptions.nMonsterSettings = !userConfig.nomonsters; gGameOptions.nMonsterSettings = !userConfig.nomonsters;
bQuickStart = userConfig.nologo; bQuickStart = userConfig.nologo;
ReadAllRFS(); ReadAllRFS();
HookReplaceFunctions(); HookReplaceFunctions();
@ -891,29 +847,20 @@ int GameInterface::app_main()
engineInit(); engineInit();
Printf("Loading tiles\n"); Printf("Loading tiles\n");
if (pUserTiles) if (!tileInit(0, NULL))
{ I_FatalError("TILES###.ART files not found");
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");
}
levelLoadDefaults(); levelLoadDefaults();
loaddefinitionsfile(BLOODWIDESCREENDEF); loaddefinitionsfile(BLOODWIDESCREENDEF);
loaddefinitions_game(BLOODWIDESCREENDEF, FALSE); loaddefinitions_game(BLOODWIDESCREENDEF, FALSE);
const char *defsfile = G_DefFile(); const char* defsfile = G_DefFile();
uint32_t stime = timerGetTicks(); uint32_t stime = timerGetTicks();
if (!loaddefinitionsfile(defsfile)) if (!loaddefinitionsfile(defsfile))
{ {
uint32_t etime = timerGetTicks(); 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); loaddefinitions_game(defsfile, FALSE);
powerupInit(); powerupInit();
@ -931,11 +878,10 @@ int GameInterface::app_main()
ctrlInit(); ctrlInit();
timerInit(120); timerInit(120);
timerSetCallback(ClockStrobe); timerSetCallback(ClockStrobe);
// PORT-TODO: CD audio init
Printf("Initializing network users\n"); Printf("Initializing network users\n");
netInitialize(true); netInitialize(true);
videoInit(); videoInit();
hud_size.Callback(); hud_size.Callback();
Printf("Initializing sound system\n"); Printf("Initializing sound system\n");
sndInit(); sndInit();
@ -948,18 +894,17 @@ int GameInterface::app_main()
gStartNewGame = 1; gStartNewGame = 1;
} }
videoSetViewableArea(0, 0, xdim - 1, ydim - 1); videoSetViewableArea(0, 0, xdim - 1, ydim - 1);
bool playvideo = !bQuickStart;
if (playvideo)
credLogosDos();
UpdateDacs(0, true); UpdateDacs(0, true);
}
RESTART: static void gameInit()
{
//RESTART:
sub_79760(); sub_79760();
gViewIndex = myconnectindex; gViewIndex = myconnectindex;
gMe = gView = &gPlayer[myconnectindex]; gMe = gView = &gPlayer[myconnectindex];
netBroadcastPlayerInfo(myconnectindex); netBroadcastPlayerInfo(myconnectindex);
#if 0
Printf("Waiting for network players!\n"); Printf("Waiting for network players!\n");
netWaitForEveryone(0); netWaitForEveryone(0);
if (gRestartGame) if (gRestartGame)
@ -971,134 +916,94 @@ RESTART:
netResetToSinglePlayer(); netResetToSinglePlayer();
goto RESTART; goto RESTART;
} }
UpdateNetworkMenus(); #endif
UpdateNetworkMenus();
gQuitGame = 0; gQuitGame = 0;
gRestartGame = 0; gRestartGame = 0;
if (gGameOptions.nGameType > 0) if (gGameOptions.nGameType > 0)
{ {
inputState.ClearAllInput(); inputState.ClearAllInput();
} }
if (!bAddUserMap && !gGameStarted)
{ }
M_StartControlPanel(false);
M_SetMenu(NAME_Mainmenu); static void gameTicker()
} {
ready2send = 1; bool gameUpdate = false;
while (!gQuitGame) double const gameUpdateStartTime = timerGetHiTicks();
while (gPredictTail < gNetFifoHead[myconnectindex] && !paused)
{ {
bool bDraw; viewUpdatePrediction(&gFifoInput[gPredictTail & 255][myconnectindex]);
D_ProcessEvents(); }
if (gGameStarted) // gGameStarted: gameState == GS_LEVEL if (numplayers == 1)
{ gBufferJitter = 0;
char gameUpdate = false; while (totalclock >= gNetFifoClock && ready2send)
double const gameUpdateStartTime = timerGetHiTicks(); {
while (gPredictTail < gNetFifoHead[myconnectindex] && !paused) gNetInput = gInput;
{ gInput = {};
viewUpdatePrediction(&gFifoInput[gPredictTail&255][myconnectindex]); netGetInput();
} gNetFifoClock += 4;
if (numplayers == 1) while (gNetFifoHead[myconnectindex] - gNetFifoTail > gBufferJitter && !gStartNewGame && !gQuitGame)
gBufferJitter = 0; {
while (totalclock >= gNetFifoClock && ready2send) int i;
{ for (i = connecthead; i >= 0; i = connectpoint2[i])
gNetInput = gInput; if (gNetFifoHead[i] == gNetFifoTail)
gInput = {}; break;
netGetInput(); if (i >= 0)
gNetFifoClock += 4; break;
while (gNetFifoHead[myconnectindex]-gNetFifoTail > gBufferJitter && !gStartNewGame && !gQuitGame) //faketimerhandler();
{ ProcessFrame();
int i; gameUpdate = true;
for (i = connecthead; i >= 0; i = connectpoint2[i]) }
if (gNetFifoHead[i] == gNetFifoTail) }
break; if (gameUpdate)
if (i >= 0) {
break; g_gameUpdateTime = timerGetHiTicks() - gameUpdateStartTime;
//faketimerhandler(); if (g_gameUpdateAvgTime < 0.f)
ProcessFrame(); g_gameUpdateAvgTime = g_gameUpdateTime;
gameUpdate = true; g_gameUpdateAvgTime = ((GAMEUPDATEAVGTIMENUMSAMPLES - 1.f) * g_gameUpdateAvgTime + g_gameUpdateTime) / ((float)GAMEUPDATEAVGTIMENUMSAMPLES);
} }
} if (gQuitRequest && gQuitGame)
if (gameUpdate) videoClearScreen(0);
{ else
g_gameUpdateTime = timerGetHiTicks() - gameUpdateStartTime; {
if (g_gameUpdateAvgTime < 0.f) netCheckSync();
g_gameUpdateAvgTime = g_gameUpdateTime; viewDrawScreen();
g_gameUpdateAvgTime = ((GAMEUPDATEAVGTIMENUMSAMPLES-1.f)*g_gameUpdateAvgTime+g_gameUpdateTime)/((float) GAMEUPDATEAVGTIMENUMSAMPLES); g_gameUpdateAndDrawTime = g_beforeSwapTime/* timerGetHiTicks()*/ - gameUpdateStartTime;
} }
bDraw = G_FPSLimit() != 0; }
if (gQuitRequest && gQuitGame)
videoClearScreen(0); static void drawBackground()
else {
{ twod->ClearScreen();
netCheckSync(); rotatesprite(160 << 16, 100 << 16, 65536, 0, 2518, 0, 0, 0x4a, 0, 0, xdim - 1, ydim - 1);
if (bDraw) if (gQuitRequest && !gQuitGame)
{ netBroadcastMyLogoff(gQuitRequest == 2);
viewDrawScreen(); }
g_gameUpdateAndDrawTime = g_beforeSwapTime/* timerGetHiTicks()*/ - gameUpdateStartTime;
} static void commonTicker(bool &playvideo)
} {
} if (TestBitString(gotpic, 2342))
else // gameState == GS_DEMOSCREEN {
{ FireProcess();
// Menu background ClearBitString(gotpic, 2342);
bDraw = G_FPSLimit() != 0; }
if (bDraw) if (gStartNewGame)
{ {
twod->ClearScreen(); StartLevel(&gGameOptions);
rotatesprite(160<<16,100<<16,65536,0,2518,0,0,0x4a,0,0,xdim-1,ydim-1);
} auto completion = [](bool = false)
if (gQuitRequest && !gQuitGame) {
netBroadcastMyLogoff(gQuitRequest == 2); levelTryPlayMusicOrNothing(gGameOptions.nEpisode, gGameOptions.nLevel);
} gamestate = GS_LEVEL;
if (bDraw) };
{
gameHandleEvents(); if ((gGameOptions.uGameFlags & 4))
inputState.SetBindsEnabled(gInputMode == kInputGame); levelPlayIntroScene(gGameOptions.nEpisode, completion);
switch (gInputMode) else
{ completion(false);
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);
}
} }
ready2send = 0;
if (gRestartGame) if (gRestartGame)
{ {
Mus_Stop(); Mus_Stop();
@ -1106,21 +1011,70 @@ RESTART:
gQuitGame = 0; gQuitGame = 0;
gQuitRequest = 0; gQuitRequest = 0;
gRestartGame = 0; gRestartGame = 0;
gGameStarted = 0; levelSetupOptions(0, 0);
levelSetupOptions(0,0);
if (gGameOptions.nGameType != 0) if (gGameOptions.nGameType != 0)
{ {
videoSetViewableArea(0,0,xdim-1,ydim-1); playvideo = !bQuickStart;
playvideo = !bQuickStart;
} }
else playvideo = false; else playvideo = false;
gamestate = GS_STARTUP;
goto RESTART;
} }
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; return 0;
} }
@ -1449,7 +1403,7 @@ extern IniFile* BloodINI;
void GameInterface::FreeGameData() void GameInterface::FreeGameData()
{ {
if (BloodINI) delete BloodINI; if (BloodINI) delete BloodINI;
ShutDown(); netDeinitialize();
} }
void GameInterface::UpdateScreenSize() void GameInterface::UpdateScreenSize()

View file

@ -106,13 +106,6 @@ struct INICHAIN {
extern INICHAIN *pINIChain; extern INICHAIN *pINIChain;
enum INPUT_MODE {
kInputGame = 0,
kInputMessage,
kInputEndGame,
};
extern INPUT_MODE gInputMode;
extern short BloodVersion; extern short BloodVersion;
extern int gNetPlayers; extern int gNetPlayers;
extern bool gRestartGame; extern bool gRestartGame;

View file

@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "map2d.h" #include "map2d.h"
#include "view.h" #include "view.h"
#include "d_event.h" #include "d_event.h"
#include "gamestate.h"
BEGIN_BLD_NS BEGIN_BLD_NS
@ -83,7 +84,7 @@ void ctrlGetInput(void)
auto scaleAdjustmentToInterval = [=](double x) { return x * kTicsPerSec / (1000.0 / elapsedInputTicks); }; auto scaleAdjustmentToInterval = [=](double x) { return x * kTicsPerSec / (1000.0 / elapsedInputTicks); };
if (!gGameStarted || gInputMode != kInputGame) if (gamestate != GS_LEVEL || System_WantGuiCapture())
{ {
gInput = {}; gInput = {};
CONTROL_GetInput(&info); 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 END_BLD_NS

View file

@ -37,212 +37,113 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "../glbackend/glbackend.h" #include "../glbackend/glbackend.h"
#include "raze_sound.h" #include "raze_sound.h"
#include "v_2ddrawer.h" #include "v_2ddrawer.h"
#include "screenjob.h"
#include "gamestate.h"
#include "seq.h"
#include "menu.h"
BEGIN_BLD_NS BEGIN_BLD_NS
char exitCredits = 0;
char Wait(int nTicks) //---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void playlogos()
{ {
totalclock = 0; JobDesc jobs[6];
while (totalclock < nTicks) int job = 0;
{ static AnimSound logosound[] =
gameHandleEvents(); {
auto key = inputState.keyGetScan(); { 1, -1 },
if (key) { -1, -1 },
{ { 1, -1 },
if (key == sc_Escape) // sc_Escape { -1,-1 }
exitCredits = 1; };
return 0;
} if (logosound[0].soundnum == -1)
} {
return 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<DBlackScreen>(1), []() { sndStartSample("THUNDER2", 128, -1); }};
jobs[job++] = { Create<DImageScreen>(2050) };
}
if (fileSystem.FindFile("gti.smk"))
{
jobs[job++] = { PlayVideo("gti.smk", &logosound[2], 0) };
}
else
{
jobs[job++] = { Create<DBlackScreen>(1), []() { sndStartSample("THUNDER2", 128, -1); }};
jobs[job++] = { Create<DImageScreen>(2052) };
}
jobs[job++] = { Create<DBlackScreen>(1), []() { sndPlaySpecialMusicOrNothing(MUS_INTRO); sndStartSample("THUNDER2", 128, -1); }};
jobs[job++] = { Create<DImageScreen>(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 levelPlayEndScene(int nEpisode, CompletionFunc completion)
void credLogosDos(void)
{ {
char bShift = inputState.ShiftPressed(); gGameOptions.uGameFlags &= ~8;
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<uint8_t> 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);
Mus_Stop(); Mus_Stop();
sndKillAllSounds();
int nScale; sfxKillAllSounds();
int nStat; ambKillAll();
seqKillAll();
if (nWidth <= 320 && nHeight <= 200) EPISODEINFO *pEpisode = &gEpisodeInfo[nEpisode];
{ playSmk(pEpisode->at8f98, pEpisode->at90c0, pEpisode->at902c, completion);
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();
} }
END_BLD_NS END_BLD_NS

View file

@ -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

View file

@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "c_bind.h" #include "c_bind.h"
#include "menu.h" #include "menu.h"
#include "sound.h" #include "sound.h"
#include "gamestate.h"
bool ShowOptionMenu(); bool ShowOptionMenu();
@ -247,7 +248,7 @@ void GameInterface::MenuClosed()
bool GameInterface::CanSave() bool GameInterface::CanSave()
{ {
return (gGameStarted && gPlayer[myconnectindex].pXSprite->health != 0); return (gamestate == GS_LEVEL && gPlayer[myconnectindex].pXSprite->health != 0);
} }
void GameInterface::StartGame(FNewGameStartup& gs) void GameInterface::StartGame(FNewGameStartup& gs)

View file

@ -39,6 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "messages.h" #include "messages.h"
#include "statistics.h" #include "statistics.h"
#include "gstrings.h" #include "gstrings.h"
#include "gamestate.h"
#include "raze_sound.h" #include "raze_sound.h"
BEGIN_BLD_NS BEGIN_BLD_NS
@ -86,8 +87,7 @@ void CEndGameMgr::ProcessKeys(void)
//} //}
//else //else
{ {
char ch = inputState.keyGetScan(); if (!inputState.CheckAllInput())
if (!ch)
return; return;
if (gGameOptions.nGameType > 0 || numplayers > 1) if (gGameOptions.nGameType > 0 || numplayers > 1)
netWaitForEveryone(0); netWaitForEveryone(0);
@ -99,8 +99,7 @@ extern void EndLevel(void);
void CEndGameMgr::Setup(void) void CEndGameMgr::Setup(void)
{ {
at1 = gInputMode; gamestate = GS_FINALE;
gInputMode = kInputEndGame;
at0 = 1; at0 = 1;
STAT_Update(false); STAT_Update(false);
EndLevel(); EndLevel();
@ -119,7 +118,6 @@ void CEndGameMgr::Finish(void)
gInitialNetPlayers = numplayers; gInitialNetPlayers = numplayers;
soundEngine->StopAllChannels(); soundEngine->StopAllChannels();
gStartNewGame = 1; gStartNewGame = 1;
gInputMode = (INPUT_MODE)at1;
at0 = 0; at0 = 0;
} }

View file

@ -29,7 +29,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "blood.h" #include "blood.h"
#include "globals.h" #include "globals.h"
#include "credits.h"
#include "endgame.h" #include "endgame.h"
#include "inifile.h" #include "inifile.h"
#include "levels.h" #include "levels.h"
@ -56,7 +55,6 @@ EPISODEINFO gEpisodeInfo[kMaxEpisodes+1];
int gSkill = 2; int gSkill = 2;
int gEpisodeCount; int gEpisodeCount;
int gNextLevel; int gNextLevel;
bool gGameStarted;
int gLevelTime; int gLevelTime;
@ -83,35 +81,6 @@ void levelOverrideINI(const char *pzIni)
strcpy(BloodIniFile, 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) void levelClearSecrets(void)
{ {
gSecretMgr.Clear(); gSecretMgr.Clear();
@ -412,14 +381,12 @@ void LevelsLoadSave::Load(void)
{ {
Read(&gNextLevel, sizeof(gNextLevel)); Read(&gNextLevel, sizeof(gNextLevel));
Read(&gGameOptions, sizeof(gGameOptions)); Read(&gGameOptions, sizeof(gGameOptions));
Read(&gGameStarted, sizeof(gGameStarted));
} }
void LevelsLoadSave::Save(void) void LevelsLoadSave::Save(void)
{ {
Write(&gNextLevel, sizeof(gNextLevel)); Write(&gNextLevel, sizeof(gNextLevel));
Write(&gGameOptions, sizeof(gGameOptions)); Write(&gGameOptions, sizeof(gGameOptions));
Write(&gGameStarted, sizeof(gGameStarted));
} }
void LevelsLoadSaveConstruct(void) void LevelsLoadSaveConstruct(void)

View file

@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
#pragma once #pragma once
#include "screenjob.h"
#include "common_game.h" #include "common_game.h"
#include "inifile.h" #include "inifile.h"
#include "mapinfo.h" #include "mapinfo.h"
@ -98,8 +99,8 @@ extern int gLevelTime;
void levelInitINI(const char *pzIni); void levelInitINI(const char *pzIni);
void levelOverrideINI(const char *pzIni); void levelOverrideINI(const char *pzIni);
void levelPlayIntroScene(int nEpisode); void levelPlayIntroScene(int nEpisode, CompletionFunc completion);
void levelPlayEndScene(int nEpisode); void levelPlayEndScene(int nEpisode, CompletionFunc completion);
void levelSetupSecret(int nCount); void levelSetupSecret(int nCount);
void levelTriggerSecret(int nSecret); void levelTriggerSecret(int nSecret);
void CheckSectionAbend(const char *pzSection); void CheckSectionAbend(const char *pzSection);

View file

@ -44,6 +44,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "savegamehelp.h" #include "savegamehelp.h"
#include "raze_music.h" #include "raze_music.h"
#include "mapinfo.h" #include "mapinfo.h"
#include "gamestate.h"
#include "aistate.h" #include "aistate.h"
#include "aiunicult.h" #include "aiunicult.h"
@ -480,7 +481,7 @@ bool GameInterface::LoadGame(FSaveGameNode* node)
sfxKillAllSounds(); sfxKillAllSounds();
ambKillAll(); ambKillAll();
seqKillAll(); seqKillAll();
if (!gGameStarted) if (gamestate != GS_LEVEL)
{ {
memset(xsprite, 0, sizeof(xsprite)); memset(xsprite, 0, sizeof(xsprite));
} }
@ -524,7 +525,7 @@ bool GameInterface::LoadGame(FSaveGameNode* node)
else else
gGameMessageMgr.Clear(); gGameMessageMgr.Clear();
viewSetErrorMessage(""); viewSetErrorMessage("");
if (!gGameStarted) if (gamestate != GS_LEVEL)
{ {
netWaitForEveryone(0); netWaitForEveryone(0);
memset(gPlayerReady, 0, sizeof(gPlayerReady)); memset(gPlayerReady, 0, sizeof(gPlayerReady));
@ -534,7 +535,7 @@ bool GameInterface::LoadGame(FSaveGameNode* node)
gFrameRate = 0; gFrameRate = 0;
totalclock = 0; totalclock = 0;
paused = 0; paused = 0;
gGameStarted = 1; gamestate = GS_LEVEL;
bVanilla = false; bVanilla = false;

View file

@ -337,7 +337,7 @@ void CGameMessageMgr::Display(void)
{ {
if (VanillaMode()) if (VanillaMode())
{ {
if (numberOfDisplayedMessages && this->state && gInputMode != kInputMessage) if (numberOfDisplayedMessages && this->state)
{ {
int initialNrOfDisplayedMsgs = numberOfDisplayedMessages; int initialNrOfDisplayedMsgs = numberOfDisplayedMessages;
int initialMessagesIndex = messagesIndex; int initialMessagesIndex = messagesIndex;
@ -368,7 +368,7 @@ void CGameMessageMgr::Display(void)
} }
else else
{ {
if (this->state && gInputMode != kInputMessage) if (this->state)
{ {
messageStruct* currentMessages[kMessageLogSize]; messageStruct* currentMessages[kMessageLogSize];
int currentMessagesCount = 0; int currentMessagesCount = 0;
@ -500,7 +500,6 @@ void CPlayerMsg::Clear(void)
void CPlayerMsg::Term(void) void CPlayerMsg::Term(void)
{ {
Clear(); Clear();
gInputMode = kInputGame;
} }
void CPlayerMsg::Draw(void) void CPlayerMsg::Draw(void)

View file

@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
BEGIN_BLD_NS BEGIN_BLD_NS
void playlogos();
void *ResReadLine(char *buffer, unsigned int nBytes, void **pRes); void *ResReadLine(char *buffer, unsigned int nBytes, void **pRes);
unsigned int qrand(void); unsigned int qrand(void);
int wrand(void); int wrand(void);

View file

@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "sound.h" #include "sound.h"
#include "view.h" #include "view.h"
#include "menu.h" #include "menu.h"
#include "gamestate.h"
extern bool gHaveNetworking; extern bool gHaveNetworking;
@ -1326,7 +1327,7 @@ void netPlayerQuit(int nPlayer)
char buffer[128]; char buffer[128];
sprintf(buffer, "%s left the game with %d frags.", gProfile[nPlayer].name, gPlayer[nPlayer].fragCount); sprintf(buffer, "%s left the game with %d frags.", gProfile[nPlayer].name, gPlayer[nPlayer].fragCount);
viewSetMessage(buffer); viewSetMessage(buffer);
if (gGameStarted) if (gamestate == GS_LEVEL)
{ {
seqKill(3, gPlayer[nPlayer].pSprite->extra); seqKill(3, gPlayer[nPlayer].pSprite->extra);
actPostSprite(gPlayer[nPlayer].nSprite, kStatFree); actPostSprite(gPlayer[nPlayer].nSprite, kStatFree);

View file

@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "sound.h" #include "sound.h"
#include "view.h" #include "view.h"
#include "mapinfo.h" #include "mapinfo.h"
#include "gamestate.h"
BEGIN_BLD_NS BEGIN_BLD_NS
@ -89,7 +90,7 @@ static int osdcmd_map(CCmdFuncPtr parm)
static int osdcmd_give(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"); Printf("give: Cannot give while dead or not in a single-player game.\n");
return CCMD_OK; return CCMD_OK;
@ -149,7 +150,7 @@ static int osdcmd_give(CCmdFuncPtr parm)
static int osdcmd_god(CCmdFuncPtr UNUSED(parm)) static int osdcmd_god(CCmdFuncPtr UNUSED(parm))
{ {
UNREFERENCED_CONST_PARAMETER(parm); UNREFERENCED_CONST_PARAMETER(parm);
if (numplayers == 1 && gGameStarted) if (numplayers == 1 && gamestate == GS_LEVEL)
{ {
SetGodMode(!gMe->godMode); SetGodMode(!gMe->godMode);
gCheatMgr.m_bPlayerCheated = true; gCheatMgr.m_bPlayerCheated = true;
@ -164,7 +165,7 @@ static int osdcmd_noclip(CCmdFuncPtr UNUSED(parm))
{ {
UNREFERENCED_CONST_PARAMETER(parm); UNREFERENCED_CONST_PARAMETER(parm);
if (numplayers == 1 && gGameStarted) if (numplayers == 1 && gamestate == GS_LEVEL)
{ {
SetClipMode(!gNoClip); SetClipMode(!gNoClip);
gCheatMgr.m_bPlayerCheated = true; gCheatMgr.m_bPlayerCheated = true;

View file

@ -225,12 +225,6 @@ void Mus_Stop()
S_StopMusic(true); 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) void Mus_SetPaused(bool on)
{ {
if (on) S_PauseMusic(); if (on) S_PauseMusic();

View file

@ -13,7 +13,6 @@ void Mus_UpdateMusic();
int Mus_Play(const char *mapname, const char *fn, bool loop); int Mus_Play(const char *mapname, const char *fn, bool loop);
void Mus_Stop(); void Mus_Stop();
bool Mus_IsPlaying(); bool Mus_IsPlaying();
void Mus_Fade(double seconds);
void Mus_SetPaused(bool on); void Mus_SetPaused(bool on);
void Mus_ResumeSaved(); void Mus_ResumeSaved();
FString G_SetupFilenameBasedMusic(const char* fileName, const char *defaultfn); FString G_SetupFilenameBasedMusic(const char* fileName, const char *defaultfn);

View file

@ -45,6 +45,7 @@
#include "gamestate.h" #include "gamestate.h"
#include "menu.h" #include "menu.h"
#include "raze_sound.h" #include "raze_sound.h"
#include "SmackerDecoder.h"
#include "movie/playmve.h" #include "movie/playmve.h"
#include "gamecontrol.h" #include "gamecontrol.h"
@ -52,6 +53,14 @@
IMPLEMENT_CLASS(DScreenJob, true, false) IMPLEMENT_CLASS(DScreenJob, true, false)
IMPLEMENT_CLASS(DImageScreen, 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(); twod->ClearScreen();
DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, 3, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, 3, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE);
// Only end after having faded out. // 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<uint8_t> 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); auto fr = fileSystem.OpenFileReader(filename);
if (!fr.isOpen()) 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); Printf("%s: Unable to open video\n", filename);
return nothing(); return nothing();
} }
@ -243,13 +356,21 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
{ {
Printf("%s: invalid ANM file.\n", filename); Printf("%s: invalid ANM file.\n", filename);
anm->Destroy(); anm->Destroy();
return nothing(); return nothing();
} }
return anm; return anm;
} }
else if (!memcmp(id, "SMK2", 4)) else if (!memcmp(id, "SMK2", 4))
{ {
// todo fr.Close();
auto anm = Create<DSmkPlayer>(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)) else if (!memcmp(id, "Interplay MVE File", 18))
{ {
@ -317,7 +438,6 @@ public:
{ {
for (auto& job : jobs) for (auto& job : jobs)
{ {
job.job->Destroy();
job.job->ObjectFlags |= OF_YesReallyDelete; job.job->ObjectFlags |= OF_YesReallyDelete;
delete job.job; delete job.job;
} }
@ -326,9 +446,17 @@ public:
void AdvanceJob(bool skip) 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++; 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; actionState = clearbefore ? State_Clear : State_Run;
if (index < jobs.Size()) screenfade = jobs[index].job->fadestyle & DScreenJob::fadein ? 0.f : 1.f; if (index < jobs.Size()) screenfade = jobs[index].job->fadestyle & DScreenJob::fadein ? 0.f : 1.f;
startTime = -1; startTime = -1;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include "dobject.h" #include "dobject.h"
#include "v_2ddrawer.h"
using CompletionFunc = std::function<void(bool)>; using CompletionFunc = std::function<void(bool)>;
struct JobDesc; 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 class DImageScreen : public DScreenJob
{ {
DECLARE_CLASS(DImageScreen, DScreenJob) DECLARE_CLASS(DImageScreen, DScreenJob)
int tilenum = -1; int tilenum = -1;
int waittime; // in ms.
FGameTexture* tex = nullptr; FGameTexture* tex = nullptr;
public: 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; 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; tilenum = tile;
} }

View file

@ -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 class DEpisode3End : public DImageScreen
{ {
int sound = 0; int sound = 0;