From cdb2b44aa6d1f3b8985d2c4dd012570af22a8391 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 10 Dec 2023 16:10:45 +0000 Subject: [PATCH] ACS-Dialogue interface: New threads with dialogue auto-skip previous threads with dialogue If some dialogue needs to be never-missable, that's the mapper's responsibility - but now they won't get randomly interleaved if multiple are activated just by regular free driving, which was the worst kind of default --- src/acs/call-funcs.cpp | 44 ++++++++++++++++++++++++++++++----------- src/acs/environment.cpp | 5 +++-- src/acs/thread.hpp | 11 ++++++++--- src/k_dialogue.cpp | 11 +++++++++++ src/k_dialogue.hpp | 5 +++++ 5 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index f7354723d..5da29fcbb 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -667,6 +667,27 @@ bool CallFunc_CameraWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:: return true; // Execution interrupted } +/*-------------------------------------------------- + bool Dialogue_ValidCheck(ACSVM::Thread *thread) + + Helper to check if the thread's dialogue + context is valid, initialising if not set. +--------------------------------------------------*/ +static bool Dialogue_ValidCheck(ACSVM::Thread *thread) +{ + // TODO when we move away from g_dialogue + if (netgame) + { + return false; + } + + auto info = &static_cast(thread)->info; + if (!info->dialogue_era) + info->dialogue_era = g_dialogue.GetNewEra(); + + return g_dialogue.EraIsValid(info->dialogue_era); +} + /*-------------------------------------------------- bool CallFunc_DialogueWaitDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) @@ -678,17 +699,18 @@ bool CallFunc_DialogueWaitDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV (void)argV; (void)argC; - // TODO when we move away from g_dialogue - if (netgame) + if (Dialogue_ValidCheck(thread) == false) { return false; } g_dialogue.SetDismissable(true); + auto info = &static_cast(thread)->info; + thread->state = { ACSVM::ThreadState::WaitTag, - 0, + info->dialogue_era, ACS_TAGTYPE_DIALOGUE }; @@ -706,17 +728,18 @@ bool CallFunc_DialogueWaitText(ACSVM::Thread *thread, const ACSVM::Word *argV, A (void)argV; (void)argC; - // TODO when we move away from g_dialogue - if (netgame) + if (Dialogue_ValidCheck(thread) == false) { return false; } g_dialogue.SetDismissable(false); + auto info = &static_cast(thread)->info; + thread->state = { ACSVM::ThreadState::WaitTag, - 1, + info->dialogue_era, ACS_TAGTYPE_DIALOGUE }; @@ -2025,8 +2048,7 @@ bool CallFunc_DialogueSetSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, (void)argC; - // TODO when we move away from g_dialogue - if (netgame) + if (Dialogue_ValidCheck(thread) == false) { return false; } @@ -2069,8 +2091,7 @@ bool CallFunc_DialogueSetCustomSpeaker(ACSVM::Thread *thread, const ACSVM::Word (void)argC; - // TODO when we move away from g_dialogue - if (netgame) + if (Dialogue_ValidCheck(thread) == false) { return false; } @@ -2161,8 +2182,7 @@ bool CallFunc_DialogueNewText(ACSVM::Thread *thread, const ACSVM::Word *argV, AC (void)argC; - // TODO when we move away from g_dialogue - if (netgame) + if (Dialogue_ValidCheck(thread) == false) { return false; } diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index e6f9554cb..6979a3cd0 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -312,12 +312,13 @@ bool Environment::checkTag(ACSVM::Word type, ACSVM::Word tag) case ACS_TAGTYPE_DIALOGUE: { // TODO when we move away from g_dialogue - if (netgame) + // See also call-funcs.cpp Dialogue_ValidCheck + if (netgame || !g_dialogue.EraIsValid(tag)) // cheeky reuse { return true; } - if (tag == 0) // cheeky reuse + if (g_dialogue.Dismissable()) { // wait for dismissal return (!g_dialogue.Active()); diff --git a/src/acs/thread.hpp b/src/acs/thread.hpp index f72aac34f..faa345c15 100644 --- a/src/acs/thread.hpp +++ b/src/acs/thread.hpp @@ -66,6 +66,7 @@ public: sector_t *sector; // Sector that activated this thread. polyobj_t *po; // Polyobject that activated this thread. bool fromLineSpecial; // Called from P_ProcessLineSpecial. + UINT32 dialogue_era; // Prevents overlapping dialogue scripts. ThreadInfo() : thread_era { thinker_era }, @@ -74,7 +75,8 @@ public: side{ 0 }, sector{ nullptr }, po{ nullptr }, - fromLineSpecial{ false } + fromLineSpecial{ false }, + dialogue_era { 0 } { } @@ -85,7 +87,8 @@ public: side{ info.side }, sector{ info.sector }, po{ info.po }, - fromLineSpecial{ info.fromLineSpecial } + fromLineSpecial{ info.fromLineSpecial }, + dialogue_era { info.dialogue_era } { P_SetTarget(&mo, info.mo); } @@ -97,7 +100,8 @@ public: side{ activator->side }, sector{ activator->sector }, po{ activator->po }, - fromLineSpecial{ static_cast(activator->fromLineSpecial) } + fromLineSpecial{ static_cast(activator->fromLineSpecial) }, + dialogue_era { 0 } { P_SetTarget(&mo, activator->mo); } @@ -118,6 +122,7 @@ public: side = info.side; sector = info.sector; po = info.po; + dialogue_era = info.dialogue_era; return *this; } diff --git a/src/k_dialogue.cpp b/src/k_dialogue.cpp index c95dc8d23..d3fbe82dd 100644 --- a/src/k_dialogue.cpp +++ b/src/k_dialogue.cpp @@ -478,11 +478,22 @@ void Dialogue::Dismiss(void) typewriter.ClearText(); } +UINT32 Dialogue::GetNewEra(void) +{ + return (++current_era); +} + +bool Dialogue::EraIsValid(INT32 comparison) +{ + return (current_era == comparison); +} + void Dialogue::Unset(void) { Dismiss(); SetSpeaker(); slide = 0; + current_era = 0; } /* diff --git a/src/k_dialogue.hpp b/src/k_dialogue.hpp index adce8fa84..bdea25626 100644 --- a/src/k_dialogue.hpp +++ b/src/k_dialogue.hpp @@ -49,6 +49,9 @@ public: void Dismiss(void); void Unset(void); + UINT32 GetNewEra(void); + bool EraIsValid(INT32 comparison); + class Typewriter { public: @@ -76,6 +79,8 @@ public: private: Typewriter typewriter; + INT32 current_era; + patch_t *bgPatch; patch_t *confirmPatch;