mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 20:21:26 +00:00
- block wipes when streaming movies are playing.
For synchronization purposes they cannot be interrupted by the wipe loop. This also groups the cutscene state in a struct for readability purposes.
This commit is contained in:
parent
c62e14d2c1
commit
71ce8aa79a
4 changed files with 80 additions and 50 deletions
|
@ -54,10 +54,7 @@
|
|||
|
||||
CVAR(Bool, inter_subtitles, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
|
||||
DObject* runner;
|
||||
PClass* runnerclass;
|
||||
PType* runnerclasstype;
|
||||
CompletionFunc completion;
|
||||
CutsceneState cutscene;
|
||||
static int ticks;
|
||||
|
||||
//=============================================================================
|
||||
|
@ -72,11 +69,11 @@ void Job_Init()
|
|||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
GC::AddMarkerFunc([] { GC::Mark(runner); });
|
||||
GC::AddMarkerFunc([] { GC::Mark(cutscene.runner); });
|
||||
}
|
||||
runnerclass = PClass::FindClass("ScreenJobRunner");
|
||||
if (!runnerclass) I_FatalError("ScreenJobRunner not defined");
|
||||
runnerclasstype = NewPointer(runnerclass);
|
||||
cutscene.runnerclass = PClass::FindClass("ScreenJobRunner");
|
||||
if (!cutscene.runnerclass) I_FatalError("ScreenJobRunner not defined");
|
||||
cutscene.runnerclasstype = NewPointer(cutscene.runnerclass);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
@ -115,7 +112,7 @@ void CallCreateFunction(const char* qname, DObject* runner)
|
|||
{
|
||||
auto func = LookupFunction(qname);
|
||||
if (func->Proto->ArgumentTypes.Size() != 1) I_Error("Bad cutscene function %s. Must receive precisely one argument.", qname);
|
||||
if (func->Proto->ArgumentTypes[0] != runnerclasstype) I_Error("Bad cutscene function %s. Must receive ScreenJobRunner reference.", qname);
|
||||
if (func->Proto->ArgumentTypes[0] != cutscene.runnerclasstype) I_Error("Bad cutscene function %s. Must receive ScreenJobRunner reference.", qname);
|
||||
VMValue val = runner;
|
||||
VMCall(func, &val, 1, nullptr, 0);
|
||||
}
|
||||
|
@ -128,7 +125,7 @@ void CallCreateFunction(const char* qname, DObject* runner)
|
|||
|
||||
DObject* CreateRunner(bool clearbefore)
|
||||
{
|
||||
auto obj = runnerclass->CreateNew();
|
||||
auto obj = cutscene.runnerclass->CreateNew();
|
||||
auto func = LookupFunction("ScreenJobRunner.Init", false);
|
||||
VMValue val[3] = { obj, clearbefore, false };
|
||||
VMCall(func, val, 3, nullptr, 0);
|
||||
|
@ -182,15 +179,15 @@ void CutsceneDef::Create(DObject* runner)
|
|||
|
||||
void DeleteScreenJob()
|
||||
{
|
||||
if (runner) runner->Destroy();
|
||||
runner = nullptr;
|
||||
if (cutscene.runner) cutscene.runner->Destroy();
|
||||
cutscene.runner = nullptr;
|
||||
}
|
||||
|
||||
void EndScreenJob()
|
||||
{
|
||||
DeleteScreenJob();
|
||||
if (completion) completion(false);
|
||||
completion = nullptr;
|
||||
if (cutscene.completion) cutscene.completion(false);
|
||||
cutscene.completion = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -213,12 +210,12 @@ bool ScreenJobResponder(event_t* ev)
|
|||
}
|
||||
}
|
||||
FInputEvent evt = ev;
|
||||
if (runner)
|
||||
if (cutscene.runner)
|
||||
{
|
||||
IFVIRTUALPTRNAME(runner, NAME_ScreenJobRunner, OnEvent)
|
||||
IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, OnEvent)
|
||||
{
|
||||
int result = 0;
|
||||
VMValue parm[] = { runner, &evt };
|
||||
VMValue parm[] = { cutscene.runner, &evt };
|
||||
VMReturn ret(&result);
|
||||
VMCall(func, parm, 2, &ret, 1);
|
||||
return result;
|
||||
|
@ -236,12 +233,12 @@ bool ScreenJobResponder(event_t* ev)
|
|||
bool ScreenJobTick()
|
||||
{
|
||||
ticks++;
|
||||
if (runner)
|
||||
if (cutscene.runner)
|
||||
{
|
||||
IFVIRTUALPTRNAME(runner, NAME_ScreenJobRunner, OnTick)
|
||||
IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, OnTick)
|
||||
{
|
||||
int result = 0;
|
||||
VMValue parm[] = { runner };
|
||||
VMValue parm[] = { cutscene.runner };
|
||||
VMReturn ret(&result);
|
||||
VMCall(func, parm, 1, &ret, 1);
|
||||
return result;
|
||||
|
@ -260,12 +257,12 @@ void ScreenJobDraw()
|
|||
{
|
||||
double smoothratio = I_GetTimeFrac();
|
||||
|
||||
if (runner)
|
||||
if (cutscene.runner)
|
||||
{
|
||||
twod->ClearScreen();
|
||||
IFVIRTUALPTRNAME(runner, NAME_ScreenJobRunner, RunFrame)
|
||||
IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, RunFrame)
|
||||
{
|
||||
VMValue parm[] = { runner, smoothratio };
|
||||
VMValue parm[] = { cutscene.runner, smoothratio };
|
||||
VMCall(func, parm, 2, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
@ -279,12 +276,12 @@ void ScreenJobDraw()
|
|||
|
||||
bool ScreenJobValidate()
|
||||
{
|
||||
if (runner)
|
||||
if (cutscene.runner)
|
||||
{
|
||||
IFVIRTUALPTRNAME(runner, NAME_ScreenJobRunner, Validate)
|
||||
IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, Validate)
|
||||
{
|
||||
int res;
|
||||
VMValue parm[] = { runner };
|
||||
VMValue parm[] = { cutscene.runner };
|
||||
VMReturn ret(&res);
|
||||
VMCall(func, parm, 1, &ret, 1);
|
||||
I_ResetFrameTime();
|
||||
|
@ -304,12 +301,12 @@ bool StartCutscene(CutsceneDef& cs, int flags, const CompletionFunc& completion_
|
|||
{
|
||||
if ((cs.function.IsNotEmpty() || cs.video.IsNotEmpty()) && cs.function.CompareNoCase("none") != 0)
|
||||
{
|
||||
completion = completion_;
|
||||
runner = CreateRunner();
|
||||
GC::WriteBarrier(runner);
|
||||
cutscene.completion = completion_;
|
||||
cutscene.runner = CreateRunner();
|
||||
GC::WriteBarrier(cutscene.runner);
|
||||
try
|
||||
{
|
||||
cs.Create(runner);
|
||||
cs.Create(cutscene.runner);
|
||||
if (!ScreenJobValidate())
|
||||
{
|
||||
DeleteScreenJob();
|
||||
|
@ -349,6 +346,26 @@ DEFINE_ACTION_FUNCTION(DScreenJobRunner, setTransition)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// to block wipes on cutscenes that cannot handle it
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool CanWipe()
|
||||
{
|
||||
if (cutscene.runner == nullptr) return true;
|
||||
IFVM(ScreenJobRunner, CanWipe)
|
||||
{
|
||||
int can;
|
||||
VMReturn ret(&can);
|
||||
VMValue param = cutscene.runner;
|
||||
VMCall(func, ¶m, 1, &ret, 1);
|
||||
return can;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
@ -43,14 +43,19 @@ bool ScreenJobValidate();
|
|||
struct CutsceneDef;
|
||||
bool StartCutscene(const char* s, int flags, const CompletionFunc& completion);
|
||||
bool StartCutscene(CutsceneDef& cs, int flags, const CompletionFunc& completion_);
|
||||
bool CanWipe();
|
||||
|
||||
VMFunction* LookupFunction(const char* qname, bool validate = true);
|
||||
void CallCreateFunction(const char* qname, DObject* runner);
|
||||
DObject* CreateRunner(bool clearbefore = true);
|
||||
void AddGenericVideo(DObject* runner, const FString& fn, int soundid, int fps);
|
||||
|
||||
struct CutsceneState
|
||||
{
|
||||
DObject* runner;
|
||||
PClass* runnerclass;
|
||||
PType* runnerclasstype;
|
||||
CompletionFunc completion;
|
||||
};
|
||||
|
||||
extern DObject* runner;
|
||||
extern PClass* runnerclass;
|
||||
extern PType* runnerclasstype;
|
||||
extern CompletionFunc completion;
|
||||
extern CutsceneState cutscene;
|
||||
|
|
|
@ -205,7 +205,7 @@ static void CallCreateMapFunction(const char* qname, DObject* runner, level_info
|
|||
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)
|
||||
if (func->Proto->ArgumentTypes[0] != cutscene.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);
|
||||
|
@ -264,19 +264,19 @@ void G_DeferedInitNew (FNewGameStartup *gs)
|
|||
|
||||
if (AllEpisodes[gs->Episode].mIntro.isdefined())
|
||||
{
|
||||
runner = CreateRunner(false);
|
||||
GC::WriteBarrier(runner);
|
||||
cutscene.runner = CreateRunner(false);
|
||||
GC::WriteBarrier(cutscene.runner);
|
||||
|
||||
if (!CreateCutscene(&AllEpisodes[gs->Episode].mIntro, runner, nullptr))
|
||||
if (!CreateCutscene(&AllEpisodes[gs->Episode].mIntro, cutscene.runner, nullptr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
completion = [](bool) { gameaction = ga_newgame2; };
|
||||
cutscene.completion = [](bool) { gameaction = ga_newgame2; };
|
||||
if (!ScreenJobValidate())
|
||||
{
|
||||
DeleteScreenJob();
|
||||
completion = nullptr;
|
||||
cutscene.completion = nullptr;
|
||||
return;
|
||||
}
|
||||
gameaction = ga_intermission;
|
||||
|
@ -1025,9 +1025,9 @@ void RunIntermission(level_info_t* fromMap, level_info_t* toMap, DIntermissionCo
|
|||
completionf(false);
|
||||
return;
|
||||
}
|
||||
runner = CreateRunner(false);
|
||||
GC::WriteBarrier(runner);
|
||||
completion = std::move(completionf);
|
||||
cutscene.runner = CreateRunner(false);
|
||||
GC::WriteBarrier(cutscene.runner);
|
||||
cutscene.completion = std::move(completionf);
|
||||
|
||||
// retrieve cluster relations for cluster-based cutscenes.
|
||||
cluster_info_t* fromcluster = nullptr, *tocluster = nullptr;
|
||||
|
@ -1037,9 +1037,9 @@ void RunIntermission(level_info_t* fromMap, level_info_t* toMap, DIntermissionCo
|
|||
|
||||
if (fromMap)
|
||||
{
|
||||
if (!CreateCutscene(&fromMap->outro, runner, fromMap))
|
||||
if (!CreateCutscene(&fromMap->outro, cutscene.runner, fromMap))
|
||||
{
|
||||
if (fromcluster != nullptr) CreateCutscene(&fromcluster->outro, runner, fromMap);
|
||||
if (fromcluster != nullptr) CreateCutscene(&fromcluster->outro, cutscene.runner, fromMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1048,22 +1048,22 @@ void RunIntermission(level_info_t* fromMap, level_info_t* toMap, DIntermissionCo
|
|||
{
|
||||
I_Error("Script function 'DoomCutscenes.BuildMapTransition' not found");
|
||||
}
|
||||
VMValue val[3] = { runner, intermissionScreen, statusScreen };
|
||||
VMValue val[3] = { cutscene.runner, intermissionScreen, statusScreen };
|
||||
VMCall(func, val, 3, nullptr, 0);
|
||||
|
||||
if (toMap)
|
||||
{
|
||||
if (!CreateCutscene(&toMap->intro, runner, toMap))
|
||||
if (!CreateCutscene(&toMap->intro, cutscene.runner, toMap))
|
||||
{
|
||||
if (tocluster != nullptr) CreateCutscene(&tocluster->intro, runner, toMap);
|
||||
if (tocluster != nullptr) CreateCutscene(&tocluster->intro, cutscene.runner, toMap);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ScreenJobValidate())
|
||||
{
|
||||
DeleteScreenJob();
|
||||
if (completion) completion(false);
|
||||
completion = nullptr;
|
||||
if (cutscene.completion) cutscene.completion(false);
|
||||
cutscene.completion = nullptr;
|
||||
return;
|
||||
}
|
||||
gameaction = ga_intermission;
|
||||
|
|
|
@ -9,6 +9,7 @@ class ScreenJob : Object UI
|
|||
int jobstate;
|
||||
|
||||
bool skipover;
|
||||
bool nowipe;
|
||||
|
||||
enum EJobState
|
||||
{
|
||||
|
@ -229,6 +230,7 @@ class MoviePlayerJob : SkippableScreenJob
|
|||
Super.Init();
|
||||
flag = flags;
|
||||
player = mp;
|
||||
nowipe = true; // due to synchronization issues wipes must be disabled on any movie.
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -360,6 +362,12 @@ class ScreenJobRunner : Object UI
|
|||
return jobs.Size() > 0;
|
||||
}
|
||||
|
||||
bool CanWipe()
|
||||
{
|
||||
if (index < jobs.Size()) return !jobs[index].nowipe;
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue