[Scummvm-git-logs] scummvm master -> 979207a3afb81f8ccebc5ca93c25a843bffe69f8
scemino
noreply at scummvm.org
Tue Dec 10 20:56:39 UTC 2024
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
979207a3af TWP: Fix cutscene regressions
Commit: 979207a3afb81f8ccebc5ca93c25a843bffe69f8
https://github.com/scummvm/scummvm/commit/979207a3afb81f8ccebc5ca93c25a843bffe69f8
Author: scemino (scemino74 at gmail.com)
Date: 2024-12-10T21:52:42+01:00
Commit Message:
TWP: Fix cutscene regressions
Fix #15574, #15576 and #15577
Changed paths:
engines/twp/debugtools.cpp
engines/twp/genlib.cpp
engines/twp/squtil.cpp
engines/twp/squtil.h
engines/twp/syslib.cpp
engines/twp/task.h
engines/twp/thread.cpp
engines/twp/thread.h
engines/twp/twp.cpp
engines/twp/twp.h
diff --git a/engines/twp/debugtools.cpp b/engines/twp/debugtools.cpp
index ddd2c77d091..bbcfc2a2b0f 100644
--- a/engines/twp/debugtools.cpp
+++ b/engines/twp/debugtools.cpp
@@ -90,7 +90,7 @@ static void drawThreads() {
ImGui::TableNextColumn();
ImGui::Text("%-56s", thread->getName().c_str());
ImGui::TableNextColumn();
- if (thread->getId() != g_twp->_cutscene.id) {
+ if(!g_twp->_cutscene || (thread->getId() != g_twp->_cutscene->getId())) {
ImGui::Text("%-6s", thread->isGlobal() ? "global" : "local");
} else {
ImGui::Text("%-6s", "cutscene");
@@ -369,8 +369,8 @@ static void drawGeneral() {
ImGui::Text("%lld", size);
ImGui::TextColored(gray, "Cutscene:");
ImGui::SameLine();
- if (g_twp->_cutscene.id) {
- Common::SharedPtr<Thread> cutscene(sqthread(g_twp->_cutscene.id));
+ if (g_twp->_cutscene) {
+ Common::SharedPtr<ThreadBase> cutscene(sqthread(g_twp->_cutscene->getId()));
ImGui::Text("%s", cutscene->getName().c_str());
} else {
ImGui::Text("no");
diff --git a/engines/twp/genlib.cpp b/engines/twp/genlib.cpp
index 416926a4dfc..a943ea7e69c 100644
--- a/engines/twp/genlib.cpp
+++ b/engines/twp/genlib.cpp
@@ -460,7 +460,7 @@ static SQInteger getPrivatePref(HSQUIRRELVM v) {
}
static SQInteger incutscene(HSQUIRRELVM v) {
- sqpush(v, g_twp->_cutscene.id != 0);
+ sqpush(v, g_twp->_cutscene != nullptr);
return 1;
}
diff --git a/engines/twp/squtil.cpp b/engines/twp/squtil.cpp
index 6bf2485cafa..c99d4dbd202 100644
--- a/engines/twp/squtil.cpp
+++ b/engines/twp/squtil.cpp
@@ -361,16 +361,22 @@ void sqexec(HSQUIRRELVM v, const char *code, const char *filename) {
sq_settop(v, top);
}
-Common::SharedPtr<Thread> sqthread(HSQUIRRELVM v, int i) {
+Common::SharedPtr<ThreadBase> sqthread(HSQUIRRELVM v, int i) {
SQInteger id;
if (SQ_SUCCEEDED(sqget(v, i, id)))
return sqthread(id);
return nullptr;
}
-Common::SharedPtr<Thread> sqthread(int id) {
+Common::SharedPtr<ThreadBase> sqthread(int id) {
+ if (g_twp->_cutscene) {
+ if (g_twp->_cutscene->getId() == id) {
+ return g_twp->_cutscene;
+ }
+ }
+
for (size_t i = 0; i < g_twp->_threads.size(); i++) {
- Common::SharedPtr<Thread> t = g_twp->_threads[i];
+ Common::SharedPtr<ThreadBase> t = g_twp->_threads[i];
if (t->getId() == id) {
return t;
}
@@ -400,7 +406,7 @@ Light *sqlight(HSQUIRRELVM v, int i) {
struct GetThread {
explicit GetThread(HSQUIRRELVM v) : _v(v) {}
- bool operator()(Common::SharedPtr<Thread> t) {
+ bool operator()(Common::SharedPtr<ThreadBase> t) {
return t->getThread() == _v;
}
@@ -408,7 +414,13 @@ private:
HSQUIRRELVM _v;
};
-Common::SharedPtr<Thread> sqthread(HSQUIRRELVM v) {
+Common::SharedPtr<ThreadBase> sqthread(HSQUIRRELVM v) {
+ if (g_twp->_cutscene) {
+ if (g_twp->_cutscene->getThread() == v) {
+ return g_twp->_cutscene;
+ }
+ }
+
auto it = Common::find_if(g_twp->_threads.begin(), g_twp->_threads.end(), GetThread(v));
if (it != g_twp->_threads.end())
return *it;
diff --git a/engines/twp/squtil.h b/engines/twp/squtil.h
index b6f9dc80e68..d41b7c1bf07 100644
--- a/engines/twp/squtil.h
+++ b/engines/twp/squtil.h
@@ -179,9 +179,9 @@ Common::SharedPtr<Object> sqactor(HSQOBJECT table);
Common::SharedPtr<Object> sqactor(HSQUIRRELVM v, int i);
Common::SharedPtr<SoundDefinition> sqsounddef(HSQUIRRELVM v, int i);
Common::SharedPtr<SoundDefinition> sqsounddef(int id);
-Common::SharedPtr<Thread> sqthread(HSQUIRRELVM v);
-Common::SharedPtr<Thread> sqthread(HSQUIRRELVM v, int id);
-Common::SharedPtr<Thread> sqthread(int id);
+Common::SharedPtr<ThreadBase> sqthread(HSQUIRRELVM v);
+Common::SharedPtr<ThreadBase> sqthread(HSQUIRRELVM v, int id);
+Common::SharedPtr<ThreadBase> sqthread(int id);
Light *sqlight(int id);
Light *sqlight(HSQUIRRELVM v, int i);
diff --git a/engines/twp/syslib.cpp b/engines/twp/syslib.cpp
index 7f3310dd70d..fd898f7c671 100644
--- a/engines/twp/syslib.cpp
+++ b/engines/twp/syslib.cpp
@@ -93,8 +93,8 @@ static SQInteger _startthread(HSQUIRRELVM v, bool global) {
return 1;
}
-static SQInteger breakfunc(HSQUIRRELVM v, void func(Common::SharedPtr<Thread> t, void *data), void *data) {
- Common::SharedPtr<Thread> thread(sqthread(v));
+static SQInteger breakfunc(HSQUIRRELVM v, void func(Common::SharedPtr<ThreadBase> t, void *data), void *data) {
+ Common::SharedPtr<ThreadBase> thread(sqthread(v));
if (!thread)
return sq_throwerror(v, "failed to get thread");
thread->suspend();
@@ -164,12 +164,12 @@ static SQInteger addFolder(HSQUIRRELVM v) {
return 0;
}
-static void threadFrames(Common::SharedPtr<Thread> tb, void *data) {
+static void threadFrames(Common::SharedPtr<ThreadBase> tb, void *data) {
int numFrames = *(int *)data;
tb->_numFrames = numFrames;
}
-static void threadTime(Common::SharedPtr<Thread> tb, void *data) {
+static void threadTime(Common::SharedPtr<ThreadBase> tb, void *data) {
float time = *(float *)data;
tb->_waitTime = time;
}
@@ -224,7 +224,7 @@ static SQInteger breakwhilecond(HSQUIRRELVM v, Predicate pred, const char *fmt,
Common::String name = Common::String::format(fmt, va);
va_end(va);
- Common::SharedPtr<Thread> curThread = sqthread(v);
+ Common::SharedPtr<ThreadBase> curThread = sqthread(v);
if (!curThread)
return sq_throwerror(v, "Current thread should be created with startthread");
@@ -279,7 +279,7 @@ static SQInteger breakwhilecamera(HSQUIRRELVM v) {
struct CutsceneRunning {
bool operator()() {
- return g_twp->_cutscene.id != 0;
+ return g_twp->_cutscene != nullptr;
}
};
@@ -337,7 +337,7 @@ static SQInteger breakwhilerunning(HSQUIRRELVM v) {
return sq_throwerror(v, "failed to get id");
debugC(kDebugSysScript, "breakwhilerunning: %lld", id);
- Common::SharedPtr<Thread> t = sqthread(id);
+ Common::SharedPtr<ThreadBase> t = sqthread(id);
if (!t) {
if (!g_twp->_resManager->isSound(id)) {
warning("thread and sound not found: %lld", id);
@@ -471,35 +471,21 @@ static SQInteger cutscene(HSQUIRRELVM v) {
if (SQ_FAILED(sq_getstackobj(v, 3, &closureOverride)))
return sq_throwerror(v, "failed to get cutscene override closure");
}
- sq_addref(v, &closureOverride);
- Common::SharedPtr<Thread> parentThread = sqthread(v);
+ Common::SharedPtr<ThreadBase> parentThread = sqthread(v);
Common::String cutsceneName = Common::String::format("%s (%lld)", _stringval(_closure(closure)->_function->_sourcename), _closure(closure)->_function->_lineinfos->_line);
- Common::SharedPtr<Thread> cutscene(new Thread(cutsceneName, true, threadObj, envObj, closure, {}));
- g_twp->_threads.push_back(cutscene);
- if (!g_twp->_cutscene.id) {
- g_twp->_cutscene.inputState = g_twp->_inputState.getState();
- g_twp->_cutscene.showCursor = g_twp->_inputState.getShowCursor();
- g_twp->_inputState.setInputActive(false);
- g_twp->_inputState.setShowCursor(false);
- }
- g_twp->_cutscene.inOverride = false;
- g_twp->_cutscene.envObj = envObj;
- g_twp->_cutscene.closureOverride = closureOverride;
- g_twp->_cutscene.id = cutscene->getId();
-
- debugC(kDebugSysScript, "create cutscene: %s", cutsceneName.c_str());
+ Common::SharedPtr<Cutscene> cutscene(new Cutscene(cutsceneName, parentThread->getId(), threadObj, closure, closureOverride, envObj));
+ g_twp->_cutscene = cutscene;
// call the closure in the thread
- if (!cutscene->call())
- return sq_throwerror(v, "call failed");
-
+ cutscene->update(0.f);
return breakwhilecutscene(v);
}
static SQInteger cutsceneOverride(HSQUIRRELVM v) {
debugC(kDebugSysScript, "cutsceneOverride");
- return g_twp->skipCutscene();
+ g_twp->_cutscene->cutsceneOverride();
+ return 0;
}
static SQInteger dumpvar(HSQUIRRELVM v) {
@@ -606,7 +592,7 @@ static SQInteger inputHUD(HSQUIRRELVM v) {
}
static SQInteger inputOff(HSQUIRRELVM v) {
- if (!g_twp->_cutscene.id) {
+ if (!g_twp->_cutscene || g_twp->_cutscene->isStopped()) {
g_twp->_inputState.setInputActive(false);
g_twp->_inputState.setShowCursor(false);
}
@@ -614,7 +600,8 @@ static SQInteger inputOff(HSQUIRRELVM v) {
}
static SQInteger inputOn(HSQUIRRELVM v) {
- if (!g_twp->_cutscene.id) {
+ Common::SharedPtr<Cutscene> scene(g_twp->_cutscene);
+ if (!scene || scene->isStopped()) {
g_twp->_inputState.setInputActive(true);
g_twp->_inputState.setShowCursor(true);
} else {
@@ -623,8 +610,8 @@ static SQInteger inputOn(HSQUIRRELVM v) {
state &= (~UI_INPUT_OFF);
state |= UI_CURSOR_ON;
state &= (~UI_CURSOR_OFF);
- g_twp->_cutscene.inputState = (InputStateFlag)state;
- g_twp->_cutscene.showCursor = true;
+ scene->setInputState((InputStateFlag)state);
+ scene->setShowCursor(true);
}
return 0;
}
@@ -767,7 +754,7 @@ static SQInteger stopthread(HSQUIRRELVM v) {
return 1;
}
- Common::SharedPtr<Thread> t = sqthread(id);
+ Common::SharedPtr<ThreadBase> t = sqthread(id);
if (t) {
t->stop();
}
@@ -795,7 +782,7 @@ static SQInteger stopthread(HSQUIRRELVM v) {
// }
// }
static SQInteger threadid(HSQUIRRELVM v) {
- Common::SharedPtr<Thread> t = sqthread(v);
+ Common::SharedPtr<ThreadBase> t = sqthread(v);
if (t)
sqpush(v, t->getId());
else
@@ -806,7 +793,7 @@ static SQInteger threadid(HSQUIRRELVM v) {
// Specify whether a thread should be pauseable or not.
// If a thread is not pauseable, it won't be possible to pause this thread.
static SQInteger threadpauseable(HSQUIRRELVM v) {
- Common::SharedPtr<Thread> t = sqthread(v, 2);
+ Common::SharedPtr<ThreadBase> t = sqthread(v, 2);
if (!t)
return sq_throwerror(v, "failed to get thread");
SQInteger pauseable = 0;
diff --git a/engines/twp/task.h b/engines/twp/task.h
index d62ed14791a..832aedbe104 100644
--- a/engines/twp/task.h
+++ b/engines/twp/task.h
@@ -50,7 +50,7 @@ public:
virtual bool update(float elapsed) override final {
if (_cond())
return false;
- Common::SharedPtr<Thread> pt(sqthread(_parentId));
+ Common::SharedPtr<ThreadBase> pt = sqthread(_parentId);
if (pt) {
debugC(kDebugGame, "Resume task: %d, %s", _parentId, pt->getName().c_str());
pt->resume();
diff --git a/engines/twp/thread.cpp b/engines/twp/thread.cpp
index f387cba58f2..0655a514183 100644
--- a/engines/twp/thread.cpp
+++ b/engines/twp/thread.cpp
@@ -28,6 +28,28 @@
namespace Twp {
+bool ThreadBase::isDead() {
+ SQInteger state = sq_getvmstate(getThread());
+ return _stopRequest || state == SQ_VMSTATE_IDLE;
+}
+
+bool ThreadBase::isSuspended() {
+ SQInteger state = sq_getvmstate(getThread());
+ return state != SQ_VMSTATE_RUNNING;
+}
+
+void ThreadBase::suspend() {
+ if (_pauseable && !isSuspended()) {
+ sq_suspendvm(getThread());
+ }
+}
+
+void ThreadBase::resume() {
+ if (!isDead() && isSuspended()) {
+ sq_wakeupvm(getThread(), SQFalse, SQFalse, SQTrue, SQFalse);
+ }
+}
+
Thread::Thread(const Common::String &name, bool global, HSQOBJECT threadObj, HSQOBJECT envObj, HSQOBJECT closureObj, const Common::Array<HSQOBJECT> args) {
_id = g_twp->_resManager->newThreadId();
_name = name;
@@ -58,40 +80,6 @@ Thread::~Thread() {
sq_release(v, &_closureObj);
}
-void Thread::pause() {
- if (_pauseable) {
- _paused = true;
- suspend();
- }
-}
-
-void Thread::unpause() {
- _paused = false;
- resume();
-}
-
-bool Thread::isDead() const {
- SQInteger state = sq_getvmstate(getThread());
- return _stopRequest || state == SQ_VMSTATE_IDLE;
-}
-
-bool Thread::isSuspended() const {
- SQInteger state = sq_getvmstate(getThread());
- return state != SQ_VMSTATE_RUNNING;
-}
-
-void Thread::suspend() {
- if (_pauseable && !isSuspended()) {
- sq_suspendvm(getThread());
- }
-}
-
-void Thread::resume() {
- if (!isDead() && isSuspended()) {
- sq_wakeupvm(getThread(), SQFalse, SQFalse, SQTrue, SQFalse);
- }
-}
-
bool Thread::call() {
HSQUIRRELVM v = _threadObj._unVal.pThread;
// call the closure in the thread
@@ -133,4 +121,243 @@ void Thread::stop() {
suspend();
}
+Cutscene::Cutscene(const Common::String &name, int parentThreadId, HSQOBJECT threadObj, HSQOBJECT closure, HSQOBJECT closureOverride, HSQOBJECT envObj)
+ : _parentThreadId(parentThreadId),
+ _threadObj(threadObj),
+ _closure(closure),
+ _closureOverride(closureOverride),
+ _envObj(envObj) {
+
+ _name = name;
+ _id = g_twp->_resManager->newThreadId();
+ _inputState = g_twp->_inputState.getState();
+ _actor = g_twp->_followActor;
+ _showCursor = g_twp->_inputState.getShowCursor();
+ _state = csStart;
+ debugC(kDebugGame, "Create cutscene %d with input: 0x%X from parent thread: %d", _id, _inputState, _parentThreadId);
+ g_twp->_inputState.setInputActive(false);
+ g_twp->_inputState.setShowCursor(false);
+ for (auto thread : g_twp->_threads) {
+ if (thread->isGlobal())
+ thread->pause();
+ }
+ HSQUIRRELVM vm = g_twp->getVm();
+ sq_addref(vm, &_threadObj);
+ sq_addref(vm, &_closure);
+ sq_addref(vm, &_closureOverride);
+ sq_addref(vm, &_envObj);
+}
+
+Cutscene::~Cutscene() {
+ debugC(kDebugGame, "destroy cutscene %d", _id);
+ HSQUIRRELVM vm = g_twp->getVm();
+ sq_release(vm, &_threadObj);
+ sq_release(vm, &_closure);
+ sq_release(vm, &_closureOverride);
+ sq_release(vm, &_envObj);
+}
+
+void Cutscene::start() {
+ _state = csCheckEnd;
+ HSQUIRRELVM thread = getThread();
+ // call the closure in the thread
+ SQInteger top = sq_gettop(thread);
+ sq_pushobject(thread, _closure);
+ sq_pushobject(thread, _envObj);
+ if (SQ_FAILED(sq_call(thread, 1, SQFalse, SQTrue))) {
+ sq_settop(thread, top);
+ error("Couldn't call cutscene");
+ }
+}
+
+void Cutscene::stop() {
+ _state = csQuit;
+ debugC(kDebugGame, "End cutscene: %d", getId());
+ g_twp->_inputState.setState(_inputState);
+ g_twp->_inputState.setShowCursor(_showCursor);
+ if (_showCursor)
+ g_twp->_inputState.setInputActive(true);
+ debugC(kDebugGame, "Restore cutscene input: %X", _inputState);
+ g_twp->follow(g_twp->_actor);
+ Common::Array<Common::SharedPtr<ThreadBase> > threads(g_twp->_threads);
+ for (auto thread : threads) {
+ if (thread->isGlobal())
+ thread->unpause();
+ }
+ sqcall("onCutsceneEnded");
+
+ Common::SharedPtr<ThreadBase> t = sqthread(_parentThreadId);
+ if (t && t->getId())
+ t->unpause();
+ HSQUIRRELVM thread = getThread();
+ if (thread)
+ sq_suspendvm(thread);
+}
+
+HSQUIRRELVM Cutscene::getThread() {
+ if (_threadObj._type != OT_THREAD)
+ return nullptr;
+ return _threadObj._unVal.pThread;
+}
+
+void Cutscene::checkEndCutsceneOverride() {
+ if (isStopped()) {
+ _state = csEnd;
+ debugC(kDebugGame, "end checkEndCutsceneOverride");
+ }
+}
+
+bool Cutscene::update(float elapsed) {
+ if (_waitTime > 0) {
+ _waitTime -= elapsed;
+ if (_waitTime <= 0) {
+ _waitTime = 0;
+ resume();
+ }
+ } else if (_numFrames > 0) {
+ _numFrames--;
+ if (_numFrames <= 0) {
+ _numFrames = 0;
+ resume();
+ }
+ }
+
+ switch (_state) {
+ case csStart:
+ debugC(kDebugGame, "startCutscene");
+ start();
+ return false;
+ case csCheckEnd:
+ checkEndCutscene();
+ return false;
+ case csOverride:
+ debugC(kDebugGame, "doCutsceneOverride");
+ doCutsceneOverride();
+ return false;
+ case csCheckOverride:
+ debugC(kDebugGame, "checkEndCutsceneOverride");
+ checkEndCutsceneOverride();
+ return false;
+ case csEnd:
+ stop();
+ return false;
+ case csQuit:
+ return true;
+ }
+
+ return false;
+}
+
+bool Cutscene::hasOverride() const {
+ return !sq_isnull(_closureOverride);
+}
+
+void Cutscene::doCutsceneOverride() {
+ if (hasOverride()) {
+ // first quit current thread
+ HSQUIRRELVM vm = g_twp->getVm();
+ sq_release(vm, &_threadObj);
+
+ // create thread and store it on the stack
+ sq_newthread(vm, 1024);
+ sq_resetobject(&_threadObj);
+ if (SQ_FAILED(sq_getstackobj(vm, -1, &_threadObj))) {
+ error("failed to get coroutine thread from stack");
+ }
+ sq_addref(vm, &_threadObj);
+
+ _state = csCheckOverride;
+ debugC(kDebugGame, "start cutsceneOverride");
+ sq_pushobject(getThread(), _closureOverride);
+ sq_pushobject(getThread(), _envObj);
+ if (SQ_FAILED(sq_call(getThread(), 1, SQFalse, SQTrue))) {
+ error("Couldn't call cutsceneOverride");
+ }
+ return;
+ }
+ _state = csEnd;
+}
+
+void Cutscene::checkEndCutscene() {
+ if (isStopped()) {
+ _state = csEnd;
+ }
+}
+
+bool Cutscene::isStopped() {
+ if (_stopped || (_state == csQuit))
+ return true;
+ return sq_getvmstate(getThread()) == 0;
+}
+
+void Cutscene::cutsceneOverride() {
+ if (_state == csCheckEnd) {
+ _state = csOverride;
+ }
+}
+
+// CutsceneOverride::CutsceneOverride(const Common::String &name, int parentThreadId, HSQOBJECT threadObj, HSQOBJECT closureOverride, HSQOBJECT envObj)
+// : _parentThreadId(parentThreadId),
+// _threadObj(threadObj),
+// // _closure(closure),
+// _closureOverride(closureOverride),
+// _envObj(envObj) {
+
+// _name = name;
+// _id = g_twp->_resManager->newThreadId();
+// _inputState = g_twp->_inputState.getState();
+// _actor = g_twp->_followActor;
+// _showCursor = g_twp->_inputState.getShowCursor();
+// _state = csStart;
+// debugC(kDebugGame, "Create cutscene %d with input: 0x%X from parent thread: %d", _id, _inputState, _parentThreadId);
+// g_twp->_inputState.setInputActive(false);
+// g_twp->_inputState.setShowCursor(false);
+// for (auto thread : g_twp->_threads) {
+// if (thread->isGlobal())
+// thread->pause();
+// }
+// HSQUIRRELVM vm = g_twp->getVm();
+// sq_addref(vm, &_threadObj);
+// sq_addref(vm, &_closure);
+// sq_addref(vm, &_closureOverride);
+// sq_addref(vm, &_envObj);
+// }
+
+// CutsceneOverride::~CutsceneOverride() {
+// debugC(kDebugGame, "destroy cutscene override %d", _id);
+// HSQUIRRELVM vm = g_twp->getVm();
+// sq_release(vm, &_threadObj);
+// sq_release(vm, &_closure);
+// sq_release(vm, &_closureOverride);
+// sq_release(vm, &_envObj);
+// }
+
+// bool CutsceneOverride::update(float elapsed) {
+// switch (_state) {
+// case csStart:
+// debugC(kDebugGame, "start cutsceneOverride");
+// sq_pushobject(getThread(), _closureOverride);
+// sq_pushobject(getThread(), _envObj);
+// if (SQ_FAILED(sq_call(getThread(), 1, SQFalse, SQTrue)))
+// error("Couldn't call cutsceneOverride");
+// break;
+// case csCheckOverride:
+// debugC(kDebugGame, "checkEndCutsceneOverride");
+// checkEndCutsceneOverride();
+// return false;
+// case csEnd:
+// stop();
+// return false;
+// case csQuit:
+// return true;
+// }
+// }
+
+// void CutsceneOverride::checkEndCutsceneOverride() {
+// if (isStopped()) {
+// _state = csEnd;
+// debugC(kDebugGame, "end checkEndCutsceneOverride");
+// }
+// }
+
} // namespace Twp
diff --git a/engines/twp/thread.h b/engines/twp/thread.h
index b66661f9fb8..c050529c69c 100644
--- a/engines/twp/thread.h
+++ b/engines/twp/thread.h
@@ -28,45 +28,113 @@
namespace Twp {
-class Thread {
+class ThreadBase {
public:
- Thread(const Common::String &name, bool global, HSQOBJECT threadObj, HSQOBJECT envObj, HSQOBJECT closureObj, const Common::Array<HSQOBJECT> args);
- ~Thread();
+ virtual ~ThreadBase() {}
- int getId() const { return _id; }
- bool isGlobal() const { return _global; }
- HSQUIRRELVM getThread() const { return _threadObj._unVal.pThread; }
- const Common::String &getName() const { return _name; }
+ void pause() {
+ if (_pauseable) {
+ _paused = true;
+ suspend();
+ }
+ }
- bool call();
- bool update(float elapsed);
+ void unpause() {
+ _paused = false;
+ resume();
+ }
+
+ void setName(const Common::String &name) { _name = name; }
+ Common::String getName() const { return _name; }
- void pause();
- void unpause();
- void stop();
+ int getId() const { return _id; }
+ virtual HSQUIRRELVM getThread() = 0;
- bool isSuspended() const;
- bool isDead() const;
+ virtual bool isGlobal() = 0;
+ bool isSuspended();
+ bool isDead();
void suspend();
void resume();
+ virtual bool update(float elapsed) = 0;
+ virtual void stop() = 0;
+
+protected:
public:
float _waitTime = 0.f;
int _numFrames = 0;
+ bool _paused = false;
bool _pauseable = false;
uint32 _lastUpdateTime = 0;
-private:
+protected:
int _id = 0;
Common::String _name;
bool _stopRequest = false;
- bool _paused = false;
+ bool _stopped = false;
+};
+
+class Thread final : public ThreadBase {
+public:
+ Thread(const Common::String &name, bool global, HSQOBJECT threadObj, HSQOBJECT envObj, HSQOBJECT closureObj, const Common::Array<HSQOBJECT> args);
+ virtual ~Thread() override final;
+
+ virtual bool isGlobal() override final { return _global; }
+ virtual HSQUIRRELVM getThread() override final { return _threadObj._unVal.pThread; }
+
+ bool call();
+ virtual bool update(float elapsed) override final;
+ virtual void stop() override final;
+
+public:
bool _global = false;
HSQOBJECT _threadObj, _envObj, _closureObj;
Common::Array<HSQOBJECT> _args;
};
+enum CutsceneState {
+ csStart,
+ csCheckEnd,
+ csOverride,
+ csCheckOverride,
+ csEnd,
+ csQuit
+};
+
+class Object;
+class Cutscene final : public ThreadBase {
+public:
+ Cutscene(const Common::String &name, int parentThreadId, HSQOBJECT threadObj, HSQOBJECT closure, HSQOBJECT closureOverride, HSQOBJECT envObj);
+ ~Cutscene() override final;
+
+ void start();
+ bool isGlobal() override final { return false; }
+ HSQUIRRELVM getThread() override final;
+ bool update(float elapsed) override final;
+ void stop() override final;
+
+ bool hasOverride() const;
+ void cutsceneOverride();
+ bool isStopped();
+
+ void setInputState(InputStateFlag state) { _inputState = state; }
+ void setShowCursor(bool state) { _showCursor = state; }
+
+private:
+ void checkEndCutscene();
+ void checkEndCutsceneOverride();
+ void doCutsceneOverride();
+
+private:
+ int _parentThreadId = 0;
+ HSQOBJECT _threadObj, _closure, _closureOverride, _envObj;
+ CutsceneState _state;
+ bool _showCursor = false;
+ InputStateFlag _inputState = (InputStateFlag)0;
+ Common::SharedPtr<Object> _actor;
+};
+
} // namespace Twp
#endif
diff --git a/engines/twp/twp.cpp b/engines/twp/twp.cpp
index 3d6740fa760..f03d6260cc0 100644
--- a/engines/twp/twp.cpp
+++ b/engines/twp/twp.cpp
@@ -181,8 +181,6 @@ TwpEngine::TwpEngine(OSystem *syst, const TwpGameDescription *gameDesc)
_dialog.reset(new Dialog());
_dialog->_tgt.reset(new EngineDialogTarget());
sq_resetobject(&_defaultObj);
- sq_resetobject(&_cutscene.closureOverride);
- sq_resetobject(&_cutscene.envObj);
_audio.reset(new AudioSystem());
_scene.reset(new Scene());
@@ -555,11 +553,11 @@ void TwpEngine::update(float elapsed) {
}
_inputState.setHotspot(_noun1 != nullptr);
- bool hudVisible = _inputState.getInputActive() && _inputState.getInputVerbsActive() && _dialog->getState() == DialogState::None && !_cutscene.id;
+ bool hudVisible = _inputState.getInputActive() && _inputState.getInputVerbsActive() && _dialog->getState() == DialogState::None && !_cutscene;
_hud->setVisible(hudVisible);
_sentence.setVisible(_hud->isVisible());
_uiInv.setVisible(hudVisible);
- _actorSwitcher.setVisible((_dialog->getState() == DialogState::None) && !_cutscene.id);
+ _actorSwitcher.setVisible((_dialog->getState() == DialogState::None) && !_cutscene);
// Common::String cursortxt = Common::String::format("%s (%d, %d) - (%d, %d)", cursorText().c_str(), (int)roomPos.getX(), (int)roomPos.getY(), (int)scrPos.getX(), (int)scrPos.getY());
//_sentence.setText(cursortxt.c_str());
_sentence.setText(cursorText());
@@ -604,32 +602,30 @@ void TwpEngine::update(float elapsed) {
_actorSwitcher.update(actorSwitcherSlots(), elapsed);
const uint32 endMiscTime = _system->getMillis();
+ // update cutscene
+ if (_cutscene) {
+ if (_cutscene->update(elapsed)) {
+ _cutscene.reset();
+ }
+ }
const uint32 endUpdateCutsceneTime = _system->getMillis();
// update threads: make a copy of the threads because during threads update, new threads can be added
- Common::Array<Common::SharedPtr<Thread> > threads(_threads);
- Common::Array<Common::SharedPtr<Thread> > threadsToRemove;
+ Common::Array<Common::SharedPtr<ThreadBase> > threads(_threads);
+ Common::Array<Common::SharedPtr<ThreadBase> > threadsToRemove;
bool isNotInDialog = _dialog->getState() == DialogState::None;
for (auto it = threads.begin(); it != threads.end(); it++) {
- Common::SharedPtr<Thread> thread(*it);
- if ((isNotInDialog || !thread->isGlobal() || !thread->_pauseable) && thread->update(elapsed)) {
+ Common::SharedPtr<ThreadBase> thread(*it);
+ if ((isNotInDialog || !thread->isGlobal()) && thread->update(elapsed)) {
threadsToRemove.push_back(thread);
}
}
// remove threads that are terminated
for (auto it = threadsToRemove.begin(); it != threadsToRemove.end(); it++) {
- Common::SharedPtr<Thread> thread(*it);
+ Common::SharedPtr<ThreadBase> thread(*it);
size_t i = find(_threads, *it);
if (i != (size_t)-1) {
- // if cutscene reset information
- if (it->get()->getId() == _cutscene.id) {
- _cutscene.id = 0;
- g_twp->_inputState.setState(_cutscene.inputState);
- g_twp->_inputState.setShowCursor(_cutscene.showCursor);
- if (_cutscene.showCursor)
- g_twp->_inputState.setInputActive(true);
- }
_threads.remove_at(i);
}
}
@@ -1350,7 +1346,7 @@ Common::Error TwpEngine::loadGameStream(Common::SeekableReadStream *stream) {
}
bool TwpEngine::canSaveGameStateCurrently(Common::U32String *msg) {
- return _saveGameManager->_allowSaveGame && !_cutscene.id;
+ return _saveGameManager->_allowSaveGame && !_cutscene;
}
Common::Error TwpEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
@@ -1702,7 +1698,7 @@ void TwpEngine::exitRoom(Common::SharedPtr<Room> nextRoom) {
// stop all local threads
for (size_t i = 0; i < _threads.size(); i++) {
- Common::SharedPtr<Thread> thread = _threads[i];
+ Common::SharedPtr<ThreadBase> thread = _threads[i];
if (!thread->isGlobal()) {
thread->stop();
}
@@ -1723,9 +1719,6 @@ void TwpEngine::actorExit(Common::SharedPtr<Object> actor) {
if (sqrawexists(_room->_table, "actorExit")) {
sqcall(_room->_table, "actorExit", actor->_table);
}
- if (_followActor == actor) {
- _followActor = _actor;
- }
}
}
@@ -2070,42 +2063,14 @@ float TwpEngine::getRandom(float min, float max) const {
return min + scale * (max - min);
}
-SQRESULT TwpEngine::skipCutscene() {
- if (!_cutscene.id)
- return 0;
-
- if ((_dialog->getState() != DialogState::None) || _cutscene.inOverride || (_cutscene.closureOverride._type == OT_NULL)) {
- _noOverride->reset();
- return 0;
+void TwpEngine::skipCutscene() {
+ if (!_cutscene)
+ return;
+ if (_cutscene->hasOverride()) {
+ _cutscene->cutsceneOverride();
+ return;
}
-
- _cutscene.inOverride = true;
- HSQUIRRELVM vm = getVm();
- HSQUIRRELVM v = vm;
-
- // stop cutscene
- sq_addref(v, &_cutscene.envObj);
- Common::SharedPtr<Thread> thread(sqthread(_cutscene.id));
- thread->stop();
-
- // create thread and store it on the stack
- HSQOBJECT threadObj;
- sq_resetobject(&threadObj);
- sq_newthread(vm, 1024);
- if (SQ_FAILED(sq_getstackobj(vm, -1, &threadObj)))
- return sq_throwerror(v, "Couldn't get coroutine thread from stack");
-
- Common::String name(Common::String::format("cutscene override: %s", thread->getName().c_str()));
- Common::SharedPtr<Thread> t(new Thread(name, true, threadObj, _cutscene.envObj, _cutscene.closureOverride, {}));
- _threads.push_back(t);
- _cutscene.id = t->getId();
-
- debugC(kDebugSysScript, "create cutscene override");
-
- // call the closure in the thread
- if (!t->call())
- return sq_throwerror(v, "call failed");
- return 0;
+ _noOverride->reset();
}
Scaling *TwpEngine::getScaling(const Common::String &name) {
diff --git a/engines/twp/twp.h b/engines/twp/twp.h
index a98ee61ed7c..f74c852f119 100644
--- a/engines/twp/twp.h
+++ b/engines/twp/twp.h
@@ -70,7 +70,7 @@ class Scene;
struct ShaderParams;
class Task;
class TextDb;
-class Thread;
+class ThreadBase;
struct TwpGameDescription;
struct Verb;
struct VerbId;
@@ -120,7 +120,7 @@ public:
void updateSettingVars();
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override {
- return _cutscene.id == 0;
+ return !_cutscene;
}
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
@@ -167,8 +167,6 @@ public:
int runDialog(GUI::Dialog &dialog) override;
- SQRESULT skipCutscene();
-
private:
void update(float elapsedMs);
void draw(RenderTexture *texture = nullptr);
@@ -187,6 +185,7 @@ private:
Common::Array<ActorSwitcherSlot> actorSwitcherSlots();
ActorSwitcherSlot actorSwitcherSlot(ActorSlot *slot);
Scaling *getScaling(const Common::String &name);
+ void skipCutscene();
private:
unique_ptr<Vm> _vm;
@@ -196,7 +195,7 @@ public:
unique_ptr<ResManager> _resManager;
Common::Array<Common::SharedPtr<Room> > _rooms;
Common::Array<Common::SharedPtr<Object> > _actors;
- Common::Array<Common::SharedPtr<Thread> > _threads;
+ Common::Array<Common::SharedPtr<ThreadBase> > _threads;
Common::Array<Common::SharedPtr<Task> > _tasks;
Common::Array<Common::SharedPtr<Callback> > _callbacks;
Common::SharedPtr<Object> _actor;
@@ -212,14 +211,7 @@ public:
float _nextHoldToMoveTime = 0.f;
int _frameCounter = 0;
Common::SharedPtr<Lighting> _lighting;
- struct {
- int id = 0;
- InputStateFlag inputState = (InputStateFlag)0;
- bool showCursor = false;
- bool inOverride = false;
- HSQOBJECT envObj;
- HSQOBJECT closureOverride;
- } _cutscene;
+ Common::SharedPtr<Cutscene> _cutscene;
unique_ptr<Scene> _scene;
unique_ptr<Scene> _screenScene;
unique_ptr<NoOverrideNode> _noOverride;
More information about the Scummvm-git-logs
mailing list