- added cutscene creation code

This commit is contained in:
Christoph Oelckers 2022-06-03 00:03:57 +02:00
parent ea007f56f2
commit 99d98cf79d
6 changed files with 106 additions and 7 deletions

View File

@ -98,6 +98,7 @@ enum gameaction_t : int
ga_resumeconversation,
ga_intro,
ga_intermission,
ga_titleloop,
};
extern gameaction_t gameaction;

View File

@ -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<FString>& 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<FString>& 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)

View File

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

View File

@ -107,7 +107,8 @@ class FBaseCVar;
FBaseCVar* G_GetUserCVar(int playernum, const char* cvarname);
class DIntermissionController;
void RunIntermission(DIntermissionController* intermissionScreen, DObject* statusScreen, std::function<void(bool)> completionf);
struct level_info_t;
void RunIntermission(level_info_t* oldlevel, level_info_t* newlevel, DIntermissionController* intermissionScreen, DObject* statusScreen, std::function<void(bool)> completionf);
extern const AActor *SendItemUse, *SendItemDrop;
extern int SendItemDropAmount;

View File

@ -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<void(bool)> 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<void(bool)> 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();

View File

@ -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; });
}