- made episode intro cutscenes a game independent feature.

So far only defined for Duke E4 but all the logic is outside the game code now and can be universally handled.
This commit is contained in:
Christoph Oelckers 2021-04-27 20:04:11 +02:00
parent 3c27ec8cbd
commit 0dc6980e5c
15 changed files with 61 additions and 171 deletions

View file

@ -133,6 +133,23 @@ void G_BuildTiccmd(ticcmd_t* cmd)
//==========================================================================
bool newGameStarted;
void NewGame(MapRecord* map, int skill, bool ns = false)
{
newGameStarted = true;
int volume = map->cluster - 1;
if (volume >= 0 && volume < MAXVOLUMES)
{
if (StartCutscene(volumeList[volume].intro, 0, [=](bool) { gi->NewGame(map, skill, ns); })) return;
}
gi->NewGame(map, skill, ns);
}
//==========================================================================
//
//
//
//==========================================================================
static void GameTicker()
{
int i;
@ -159,7 +176,7 @@ static void GameTicker()
FX_SetReverb(0);
gi->FreeLevelData();
gameaction = ga_level;
gi->NewGame(g_nextmap, -1);
NewGame(g_nextmap, -1);
BackupSaveGame = "";
}
break;
@ -191,13 +208,12 @@ static void GameTicker()
FX_StopAllSounds();
case ga_newgamenostopsound:
DeleteScreenJob();
newGameStarted = true;
FX_SetReverb(0);
gi->FreeLevelData();
C_FlushDisplay();
gameaction = ga_level;
BackupSaveGame = "";
gi->NewGame(g_nextmap, g_nextskill, ga == ga_newgamenostopsound);
NewGame(g_nextmap, g_nextskill, ga == ga_newgamenostopsound);
break;
case ga_startup:
@ -637,6 +653,16 @@ void MainLoop ()
// Clamp the timer to TICRATE until the playloop has been entered.
r_NoInterpolate = true;
if (userConfig.CommandMap.IsNotEmpty())
{
auto maprecord = FindMapByName(userConfig.CommandMap);
userConfig.CommandMap = "";
if (maprecord)
{
NewGame(maprecord, /*userConfig.skill*/2); // todo: fix the skill.
}
}
for (;;)
{
try

View file

@ -93,6 +93,7 @@ struct MapRecord
int cdSongId = -1;
int flags = 0;
int levelNumber = -1;
int cluster = -1;
// The rest is only used by Blood
int nextLevel = -1;

View file

@ -96,7 +96,7 @@ void parseDefineCutscene(FScanner& sc, FScriptPosition& pos)
{
parseCutscene(sc, globalCutscenes.DefaultMapOutro);
}
else if (sc.Compare("episode"))
else if (sc.Compare({ "episode", "volume", "cluster" }))
{
FScanner::SavedPos eblockend;
sc.MustGetNumber();

View file

@ -523,14 +523,8 @@ static void gameInit()
void GameInterface::Startup()
{
gameInit();
if (userConfig.CommandMap.IsNotEmpty())
{
}
else
{
PlayLogos(ga_mainmenu, ga_mainmenu, true);
}
}

View file

@ -185,6 +185,7 @@ void levelLoadDefaults(void)
const char *pMap = BloodINI->GetKeyString(buffer, buffer2, NULL);
CheckSectionAbend(pMap);
pLevelInfo->levelNumber = levelnum(i, j);
pLevelInfo->cluster = i + 1;
pLevelInfo->labelName = pMap;
pLevelInfo->fileName.Format("%s.map", pMap);
levelLoadMapInfo(BloodINI, pLevelInfo, pMap, i, j);

View file

@ -181,63 +181,6 @@ void dobonus_d(int bonusonly, const CompletionFunc& completion)
#endif
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void e4intro(const CompletionFunc& completion)
{
#if 0
TArray<DScreenJob*> jobs;
static const AnimSound vol42a[] =
{
{ 1, INTRO4_B + 1 },
{ 12, SHORT_CIRCUIT + 1 },
{ 18, INTRO4_5 + 1 },
{ 34, SHORT_CIRCUIT + 1 },
{ -1,-1 }
};
static const AnimSound vol41a[] =
{
{ 1, INTRO4_1 + 1 },
{ 7, INTRO4_3 + 1 },
{ 12, INTRO4_2 + 1 },
{ 26, INTRO4_4 + 1 },
{ -1,-1 }
};
static const AnimSound vol43a[] =
{
{ 10, INTRO4_6 + 1 },
{ -1,-1 }
};
static const int framespeed_10[] = { 10, 10, 10 };
static const int framespeed_14[] = { 14, 14, 14 };
S_PlaySpecialMusic(MUS_BRIEFING);
jobs.Push(PlayVideo("vol41a.anm", vol41a, framespeed_10));
jobs.Push(PlayVideo("vol42a.anm", vol42a, framespeed_14));
jobs.Push(PlayVideo("vol43a.anm", vol43a, framespeed_10));
RunScreenJob(jobs, completion, SJ_SKIPALL);
#endif
}
#if 0
void loadscreen_d(MapRecord *rec, CompletionFunc func)
{
TArray<DScreenJob*> jobs(1, true);
jobs[0] = Create<DDukeLoadScreen>(rec);
RunScreenJob(jobs, func);
}
#endif
void PrintPaused_d()
{
BigText(160, 100, GStrings("Game Paused"));

View file

@ -224,7 +224,6 @@ void e4intro(const CompletionFunc& completion);
void exitlevel(MapRecord *next);
void enterlevel(MapRecord* mi, int gm);
void donewgame(MapRecord* map, int sk);
void startnewgame(MapRecord* map, int skill);
int playercolor2lookup(int color);
void PlayerColorChanged(void);
bool movementBlocked(player_struct *p);

View file

@ -1714,6 +1714,7 @@ int ConCompiler::parsecommand()
(((*(textptr + 3) - '0') * 10 + (*(textptr + 4) - '0')) * 26);
map->levelNumber = levnum;
map->cluster = j + 1;
textptr += 5;
while (*textptr == ' ' || *textptr == '\t') textptr++;
@ -3251,6 +3252,7 @@ void FixMapinfo()
maprec->SetFileName("endgame.map");
maprec->SetName("$TXT_CLOSEENCOUNTERS");
maprec->levelNumber = levelnum(1, 7);
maprec->cluster = 2;
}
}
}

View file

@ -114,28 +114,8 @@ void GameInterface::Ticker()
void GameInterface::Startup()
{
ps[myconnectindex].ftq = 0;
if (userConfig.CommandMap.IsNotEmpty())
{
auto maprecord = FindMapByName(userConfig.CommandMap);
userConfig.CommandMap = "";
if (maprecord)
{
ud.m_respawn_monsters = ud.player_skill == 4;
for (int i = 0; i != -1; i = connectpoint2[i])
{
resetweapons(i);
resetinventory(i);
}
startnewgame(maprecord, /*userConfig.skill*/2);
}
}
else
{
PlayLogos(ga_mainmenunostopsound, ga_mainmenunostopsound, false);
}
}
//---------------------------------------------------------------------------
//
@ -159,15 +139,12 @@ void GameInterface::Render()
//
//
//---------------------------------------------------------------------------
void loadscreen_d(MapRecord* rec, CompletionFunc func);
void loadscreen_r(MapRecord* rec, CompletionFunc func);
void GameInterface::NextLevel(MapRecord* map, int skill)
{
#if 0
// Loading is so fast on modern system so that this only serves as an irritant, not an asset.
auto loadscreen = isRR() ? loadscreen_r : loadscreen_d;
loadscreen_d(map, [=](bool)
// Loading is so fast on modern systems that this only serves as an irritant, not an asset.
loadscreen(map, [=](bool)
{
enterlevel(map, 0);
gameaction = ga_level;
@ -182,23 +159,6 @@ void GameInterface::NextLevel(MapRecord* map, int skill)
//
//---------------------------------------------------------------------------
void GameInterface::NewGame(MapRecord* map, int skill, bool)
{
// Hmm... What about the other players?
ps[0].last_extra = gs.max_player_health;
resetweapons(0);
resetinventory(0);
if (skill != -1) skill = skill + 1;
startnewgame(map, skill);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void GameInterface::LevelCompleted(MapRecord* map, int skill)
{
exitlevel(map);

View file

@ -812,33 +812,6 @@ void donewgame(MapRecord* map, int sk)
}
}
template<class func>
void newgame(MapRecord* map, int sk, func completion)
{
auto completion1 = [=](bool res)
{
if (!isRR() && map->levelNumber == levelnum(3, 0) && (ud.multimode < 2))
{
e4intro([=](bool) { donewgame(map, sk); completion(res); });
}
else
{
donewgame(map, sk);
completion(res);
}
};
if (ud.m_recstat != 2 && ud.last_level >= 0 && ud.multimode > 1 && ud.coop != 1)
dobonus(1, completion1);
#if 0 // this is one lousy hack job that's hopefully not needed anymore.
else if (isRR() && !isRRRA() && map->levelNumber == levelnum(0, 6))
dobonus(0, completion1);
#endif
else completion1(false);
}
//---------------------------------------------------------------------------
//
//
@ -983,9 +956,19 @@ void enterlevel(MapRecord *mi, int gamemode)
//
//---------------------------------------------------------------------------
void startnewgame(MapRecord* map, int skill)
void GameInterface::NewGame(MapRecord* map, int skill, bool)
{
for (int i = 0; i != -1; i = connectpoint2[i])
{
resetweapons(i);
resetinventory(i);
}
ps[0].last_extra = gs.max_player_health;
if (skill == -1) skill = ud.player_skill;
else skill++;
ud.player_skill = skill;
ud.m_respawn_monsters = (skill == 4);
ud.m_monsters_off = ud.monsters_off = 0;
@ -993,13 +976,11 @@ void startnewgame(MapRecord* map, int skill)
ud.m_respawn_inventory = 0;
ud.multimode = 1;
newgame(map, skill, [=](bool)
{
donewgame(map, skill);
enterlevel(map, 0);
PlayerColorChanged();
inputState.ClearAllInput();
gameaction = ga_level;
});
}
//---------------------------------------------------------------------------

View file

@ -494,6 +494,7 @@ void GameInterface::app_init()
mi->labelName.Format("LEV%d", i);
mi->name.Format("$TXT_EX_MAP%02d", i);
mi->levelNumber = i;
mi->cluster = i? 1 : 2; // training is cluster 2
int nTrack = i;
if (nTrack != 0) nTrack--;

View file

@ -155,23 +155,9 @@ void GameInterface::Startup()
{
resettiming();
EndLevel = 0;
if (userConfig.CommandMap.IsNotEmpty())
{
/*
auto map = FindMapByName(userConfig.CommandMap);
if (map) DeferedStartMap(map, 0);
userConfig.CommandMap = "";
goto again;
*/
}
else
{
PlayLogos(ga_mainmenu, ga_mainmenu, false);
}
}
void GameInterface::ErrorCleanup()
{
// Clear all progression sensitive variables here.

View file

@ -644,15 +644,9 @@ void GameInterface::Render()
void GameInterface::Startup()
{
if (userConfig.CommandMap.IsNotEmpty())
{
}
else
{
PlayLogos(ga_mainmenunostopsound, ga_mainmenu, false);
}
}
void GameInterface::ErrorCleanup()

View file

@ -447,6 +447,7 @@ void LoadCustomInfoFromScript(const char *filename)
{
curMap = AllocateMap();
curMap->levelNumber = mapno;
curMap->cluster = mapno < 5 ? 1 : 2;
}
if (sc.CheckString("{"))

View file

@ -5,7 +5,8 @@ definecutscene intro
function RRCutscenes.BuildIntro
}
definecutscene map e1l7 // episode 1
// The 'E1End' cutscene is tied to the level as it is not an end-of-game event.
definecutscene map e1l7
{
outro
{