From 99d98cf79dbd9be663d5b4dfdedcee2ff78b6ec5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 3 Jun 2022 00:03:57 +0200 Subject: [PATCH] - added cutscene creation code --- src/d_event.h | 1 + src/d_main.cpp | 15 ++++- src/g_game.cpp | 5 +- src/g_game.h | 3 +- src/g_level.cpp | 87 ++++++++++++++++++++++++- src/intermission/intermission_parse.cpp | 2 +- 6 files changed, 106 insertions(+), 7 deletions(-) diff --git a/src/d_event.h b/src/d_event.h index 15b4905568..409dcb62b7 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -98,6 +98,7 @@ enum gameaction_t : int ga_resumeconversation, ga_intro, ga_intermission, + ga_titleloop, }; extern gameaction_t gameaction; diff --git a/src/d_main.cpp b/src/d_main.cpp index 9dc271e900..de5d174927 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -136,7 +136,7 @@ void DrawHUD(); void D_DoAnonStats(); void I_DetectOS(); void UpdateGenericUI(bool cvar); - +void Local_Job_Init(); // MACROS ------------------------------------------------------------------ @@ -306,6 +306,7 @@ CUSTOM_CVAR(Int, I_FriendlyWindowTitle, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_N { I_UpdateWindowTitle(); } +CVAR(Bool, cl_nointros, false, CVAR_ARCHIVE) bool hud_toggled = false; @@ -3371,6 +3372,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr twod->End(); UpdateJoystickMenu(NULL); UpdateVRModes(); + Local_Job_Init(); v = Args->CheckValue ("-loadgame"); if (v) @@ -3417,7 +3419,16 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr } else { - D_StartTitle(); // start up intro loop + if (multiplayer || cl_nointros || Args->CheckParm("-nointro")) + { + D_StartTitle(); + } + else + { + if (!StartCutscene(gameinfo.IntroScene, SJ_BLOCKUI, [=](bool) { + gameaction = ga_titleloop; + })) D_StartTitle(); + } } } else if (demorecording) diff --git a/src/g_game.cpp b/src/g_game.cpp index 0361c943f3..1a355d8661 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1198,6 +1198,9 @@ void G_Ticker () gamestate = GS_CUTSCENE; gameaction = ga_nothing; break; + case ga_titleloop: + D_StartTitle(); + break; default: @@ -3077,7 +3080,7 @@ void G_StartSlideshow(FLevelLocals *Level, FName whichone) { auto SelectedSlideshow = whichone == NAME_None ? Level->info->slideshow : whichone; auto slide = F_StartIntermission(SelectedSlideshow); - RunIntermission(slide, nullptr, [](bool) + RunIntermission(nullptr, nullptr, slide, nullptr, [](bool) { primaryLevel->SetMusic(); gamestate = GS_LEVEL; diff --git a/src/g_game.h b/src/g_game.h index f3e235acac..d0650cd86a 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -107,7 +107,8 @@ class FBaseCVar; FBaseCVar* G_GetUserCVar(int playernum, const char* cvarname); class DIntermissionController; -void RunIntermission(DIntermissionController* intermissionScreen, DObject* statusScreen, std::function completionf); +struct level_info_t; +void RunIntermission(level_info_t* oldlevel, level_info_t* newlevel, DIntermissionController* intermissionScreen, DObject* statusScreen, std::function completionf); extern const AActor *SendItemUse, *SendItemDrop; extern int SendItemDropAmount; diff --git a/src/g_level.cpp b/src/g_level.cpp index 8f0652d561..0c8384170f 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -83,9 +83,11 @@ #include "stringtable.h" #include "c_buttons.h" #include "screenjob.h" +#include "types.h" #include "gi.h" + #include "g_hub.h" #include "g_levellocals.h" #include "actorinlines.h" @@ -178,6 +180,7 @@ void *statcopy; // for statistics driver FLevelLocals level; // info about current level FLevelLocals *primaryLevel = &level; // level for which to display the user interface. FLevelLocals *currentVMLevel = &level; // level which currently ticks. Used as global input to the VM and some functions called by it. +static PType* maprecordtype; //========================================================================== @@ -938,7 +941,64 @@ DIntermissionController* FLevelLocals::CreateIntermission() return controller; } -void RunIntermission(DIntermissionController* intermissionScreen, DObject* statusScreen, std::function completionf) +//============================================================================= +// +// +// +//============================================================================= + +void Local_Job_Init() +{ + maprecordtype = NewPointer(NewStruct("MapRecord", nullptr, true)); +} + +//============================================================================= +// +// +// +//============================================================================= + +static void CallCreateMapFunction(const char* qname, DObject* runner, level_info_t* map) +{ + auto func = LookupFunction(qname); + if (func->Proto->ArgumentTypes.Size() == 1) return CallCreateFunction(qname, runner); // accept functions without map parameter as well here. + if (func->Proto->ArgumentTypes.Size() != 2) I_Error("Bad map-cutscene function %s. Must receive precisely two arguments.", qname); + if (func->Proto->ArgumentTypes[0] != runnerclasstype && func->Proto->ArgumentTypes[1] != maprecordtype) + I_Error("Bad cutscene function %s. Must receive ScreenJobRunner and LevelInfo reference.", qname); + VMValue val[2] = { runner, map }; + VMCall(func, val, 2, nullptr, 0); +} + +//============================================================================= +// +// +// +//============================================================================= + +bool CreateCutscene(CutsceneDef* cs, DObject* runner, level_info_t* map) +{ + if (cs->function.CompareNoCase("none") == 0) + return true; // play nothing but return as being validated + if (cs->function.IsNotEmpty()) + { + CallCreateMapFunction(cs->function, runner, map); + return true; + } + else if (cs->video.IsNotEmpty()) + { + AddGenericVideo(runner, cs->video, cs->GetSound(), cs->framespersec); + return true; + } + return false; +} + +//============================================================================= +// +// +// +//============================================================================= + +void RunIntermission(level_info_t* fromMap, level_info_t* toMap, DIntermissionController* intermissionScreen, DObject* statusScreen, std::function completionf) { if (!intermissionScreen && !statusScreen) { @@ -948,6 +1008,20 @@ void RunIntermission(DIntermissionController* intermissionScreen, DObject* statu runner = CreateRunner(false); GC::WriteBarrier(runner); completion = std::move(completionf); + + // retrieve cluster relations for cluster-based cutscenes. + cluster_info_t* fromcluster = nullptr, *tocluster = nullptr; + if (fromMap) fromcluster = FindClusterInfo(fromMap->cluster); + if (toMap) tocluster = FindClusterInfo(toMap->cluster); + if (fromcluster == tocluster) fromcluster = tocluster = nullptr; + + if (fromMap) + { + if (!CreateCutscene(&fromMap->outro, runner, fromMap)) + { + if (fromcluster != nullptr) CreateCutscene(&fromcluster->outro, runner, fromMap); + } + } auto func = LookupFunction("DoomCutscenes.BuildMapTransition"); if (func == nullptr) @@ -957,6 +1031,14 @@ void RunIntermission(DIntermissionController* intermissionScreen, DObject* statu VMValue val[3] = { runner, intermissionScreen, statusScreen }; VMCall(func, val, 3, nullptr, 0); + if (toMap) + { + if (!CreateCutscene(&toMap->intro, runner, toMap)) + { + if (tocluster != nullptr) CreateCutscene(&tocluster->intro, runner, toMap); + } + } + if (!ScreenJobValidate()) { DeleteScreenJob(); @@ -1012,7 +1094,8 @@ void G_DoCompleted (void) } bool endgame = strncmp(nextlevel, "enDSeQ", 6) == 0; intermissionScreen = primaryLevel->CreateIntermission(); - RunIntermission(intermissionScreen, statusScreen, [=](bool) + auto nextinfo = endgame? nullptr : FindLevelInfo(nextlevel, false); + RunIntermission(primaryLevel->info, nextinfo, intermissionScreen, statusScreen, [=](bool) { if (!endgame) primaryLevel->WorldDone(); else D_StartTitle(); diff --git a/src/intermission/intermission_parse.cpp b/src/intermission/intermission_parse.cpp index 0873978953..5b2de2c4db 100644 --- a/src/intermission/intermission_parse.cpp +++ b/src/intermission/intermission_parse.cpp @@ -955,6 +955,6 @@ CCMD(testfinale) } auto controller = F_StartFinale(gameinfo.finaleMusic, gameinfo.finaleOrder, -1, 0, gameinfo.FinaleFlat, text, false, false, true, true); - RunIntermission(controller, nullptr, [=](bool) { gameaction = ga_nothing; }); + RunIntermission(nullptr, nullptr, controller, nullptr, [=](bool) { gameaction = ga_nothing; }); }