[Scummvm-git-logs] scummvm master -> 96b7854d9816721c06774db598cf56a0af069853
scemino
noreply at scummvm.org
Wed Apr 17 19:35:52 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:
96b7854d98 TWP: Fix cutscene override (bug #15069)
Commit: 96b7854d9816721c06774db598cf56a0af069853
https://github.com/scummvm/scummvm/commit/96b7854d9816721c06774db598cf56a0af069853
Author: scemino (scemino74 at gmail.com)
Date: 2024-04-17T21:35:26+02:00
Commit Message:
TWP: Fix cutscene override (bug #15069)
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 b43e848362d..a5c46db3103 100644
--- a/engines/twp/debugtools.cpp
+++ b/engines/twp/debugtools.cpp
@@ -82,8 +82,7 @@ static void drawThreads() {
ImGui::TableSetupColumn("Upd. Time");
ImGui::TableHeadersRow();
- if (g_twp->_cutscene) {
- Common::SharedPtr<ThreadBase> thread(g_twp->_cutscene);
+ for (const auto &thread : threads) {
SQStackInfos infos;
ImGui::TableNextRow();
ImGui::TableNextColumn();
@@ -91,32 +90,12 @@ static void drawThreads() {
ImGui::TableNextColumn();
ImGui::Text("%-56s", thread->getName().c_str());
ImGui::TableNextColumn();
- ImGui::Text("%-6s", "cutscene");
- ImGui::TableNextColumn();
- if (SQ_SUCCEEDED(sq_stackinfos(thread->getThread(), 0, &infos))) {
- ImGui::Text("%-9s", infos.funcname);
- ImGui::TableNextColumn();
- ImGui::Text("%-9s", infos.source);
- ImGui::TableNextColumn();
- ImGui::Text("%5lld", infos.line);
+ if(thread->getId() != g_twp->_cutscene.id) {
+ ImGui::Text("%-6s", thread->isGlobal() ? "global" : "local");
} else {
- ImGui::TableNextColumn();
- ImGui::TableNextColumn();
+ ImGui::Text("%-6s", "cutscene");
}
ImGui::TableNextColumn();
- ImGui::Text("?");
- }
-
- for (const auto &thread : threads) {
- SQStackInfos infos;
- ImGui::TableNextRow();
- ImGui::TableNextColumn();
- ImGui::Text("%5d", thread->getId());
- ImGui::TableNextColumn();
- ImGui::Text("%-56s", thread->getName().c_str());
- ImGui::TableNextColumn();
- ImGui::Text("%-6s", thread->isGlobal() ? "global" : "local");
- ImGui::TableNextColumn();
if (SQ_SUCCEEDED(sq_stackinfos(thread->getThread(), 0, &infos))) {
ImGui::Text("%-9s", infos.funcname);
ImGui::TableNextColumn();
@@ -386,7 +365,12 @@ static void drawGeneral() {
ImGui::Text("%lld", size);
ImGui::TextColored(gray, "Cutscene:");
ImGui::SameLine();
- ImGui::Text("%s", g_twp->_cutscene ? g_twp->_cutscene->getName().c_str() : "no");
+ if(g_twp->_cutscene.id) {
+ Common::SharedPtr<Thread> cutscene(sqthread(g_twp->_cutscene.id));
+ ImGui::Text("%s", cutscene->getName().c_str());
+ } else {
+ ImGui::Text("no");
+ }
DialogState dialogState = g_twp->_dialog->getState();
ImGui::TextColored(gray, "In dialog:");
ImGui::SameLine();
diff --git a/engines/twp/genlib.cpp b/engines/twp/genlib.cpp
index b4090cb7354..21b5024586c 100644
--- a/engines/twp/genlib.cpp
+++ b/engines/twp/genlib.cpp
@@ -377,7 +377,7 @@ static SQInteger getPrivatePref(HSQUIRRELVM v) {
}
static SQInteger incutscene(HSQUIRRELVM v) {
- sqpush(v, g_twp->_cutscene != nullptr);
+ sqpush(v, g_twp->_cutscene.id != 0);
return 1;
}
diff --git a/engines/twp/squtil.cpp b/engines/twp/squtil.cpp
index c99d4dbd202..6bf2485cafa 100644
--- a/engines/twp/squtil.cpp
+++ b/engines/twp/squtil.cpp
@@ -361,22 +361,16 @@ void sqexec(HSQUIRRELVM v, const char *code, const char *filename) {
sq_settop(v, top);
}
-Common::SharedPtr<ThreadBase> sqthread(HSQUIRRELVM v, int i) {
+Common::SharedPtr<Thread> sqthread(HSQUIRRELVM v, int i) {
SQInteger id;
if (SQ_SUCCEEDED(sqget(v, i, id)))
return sqthread(id);
return nullptr;
}
-Common::SharedPtr<ThreadBase> sqthread(int id) {
- if (g_twp->_cutscene) {
- if (g_twp->_cutscene->getId() == id) {
- return g_twp->_cutscene;
- }
- }
-
+Common::SharedPtr<Thread> sqthread(int id) {
for (size_t i = 0; i < g_twp->_threads.size(); i++) {
- Common::SharedPtr<ThreadBase> t = g_twp->_threads[i];
+ Common::SharedPtr<Thread> t = g_twp->_threads[i];
if (t->getId() == id) {
return t;
}
@@ -406,7 +400,7 @@ Light *sqlight(HSQUIRRELVM v, int i) {
struct GetThread {
explicit GetThread(HSQUIRRELVM v) : _v(v) {}
- bool operator()(Common::SharedPtr<ThreadBase> t) {
+ bool operator()(Common::SharedPtr<Thread> t) {
return t->getThread() == _v;
}
@@ -414,13 +408,7 @@ private:
HSQUIRRELVM _v;
};
-Common::SharedPtr<ThreadBase> sqthread(HSQUIRRELVM v) {
- if (g_twp->_cutscene) {
- if (g_twp->_cutscene->getThread() == v) {
- return g_twp->_cutscene;
- }
- }
-
+Common::SharedPtr<Thread> sqthread(HSQUIRRELVM v) {
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 d41b7c1bf07..b6f9dc80e68 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<ThreadBase> sqthread(HSQUIRRELVM v);
-Common::SharedPtr<ThreadBase> sqthread(HSQUIRRELVM v, int id);
-Common::SharedPtr<ThreadBase> sqthread(int id);
+Common::SharedPtr<Thread> sqthread(HSQUIRRELVM v);
+Common::SharedPtr<Thread> sqthread(HSQUIRRELVM v, int id);
+Common::SharedPtr<Thread> 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 5d79294c10c..67d6d02068d 100644
--- a/engines/twp/syslib.cpp
+++ b/engines/twp/syslib.cpp
@@ -91,8 +91,8 @@ static SQInteger _startthread(HSQUIRRELVM v, bool global) {
return 1;
}
-static SQInteger breakfunc(HSQUIRRELVM v, void func(Common::SharedPtr<ThreadBase> t, void *data), void *data) {
- Common::SharedPtr<ThreadBase> thread(sqthread(v));
+static SQInteger breakfunc(HSQUIRRELVM v, void func(Common::SharedPtr<Thread> t, void *data), void *data) {
+ Common::SharedPtr<Thread> thread(sqthread(v));
if (!thread)
return sq_throwerror(v, "failed to get thread");
thread->suspend();
@@ -162,12 +162,12 @@ static SQInteger addFolder(HSQUIRRELVM v) {
return 0;
}
-static void threadFrames(Common::SharedPtr<ThreadBase> tb, void *data) {
+static void threadFrames(Common::SharedPtr<Thread> tb, void *data) {
int numFrames = *(int *)data;
tb->_numFrames = numFrames;
}
-static void threadTime(Common::SharedPtr<ThreadBase> tb, void *data) {
+static void threadTime(Common::SharedPtr<Thread> tb, void *data) {
float time = *(float *)data;
tb->_waitTime = time;
}
@@ -222,13 +222,13 @@ static SQInteger breakwhilecond(HSQUIRRELVM v, Predicate pred, const char *fmt,
Common::String name = Common::String::format(fmt, va);
va_end(va);
- Common::SharedPtr<ThreadBase> curThread = sqthread(v);
+ Common::SharedPtr<Thread> curThread = sqthread(v);
if (!curThread)
return sq_throwerror(v, "Current thread should be created with startthread");
debugC(kDebugSysScript, "add breakwhilecond name=%s pid=%d, %s", name.c_str(), curThread->getId(), curThread->getName().c_str());
g_twp->_tasks.push_back(Common::SharedPtr<Task>(new BreakWhileCond<Predicate>(curThread->getId(), name, Common::move(pred))));
- return -666;
+ return SQ_SUSPEND_FLAG;
}
static bool isAnimating(Common::SharedPtr<Object> obj) {
@@ -277,7 +277,7 @@ static SQInteger breakwhilecamera(HSQUIRRELVM v) {
struct CutsceneRunning {
bool operator()() {
- return g_twp->_cutscene != nullptr;
+ return g_twp->_cutscene.id != 0;
}
};
@@ -335,7 +335,7 @@ static SQInteger breakwhilerunning(HSQUIRRELVM v) {
return sq_throwerror(v, "failed to get id");
debugC(kDebugSysScript, "breakwhilerunning: %lld", id);
- Common::SharedPtr<ThreadBase> t = sqthread(id);
+ Common::SharedPtr<Thread> t = sqthread(id);
if (!t) {
if (!g_twp->_resManager->isSound(id)) {
warning("thread and sound not found: %lld", id);
@@ -464,10 +464,13 @@ static SQInteger cutscene(HSQUIRRELVM v) {
HSQUIRRELVM vm = g_twp->getVm();
SQInteger nArgs = sq_gettop(v);
+ if(g_twp->_cutscene.id && !g_twp->_cutscene.inOverride && sqthread(g_twp->_cutscene.id))
+ return sq_throwerror(v, "cutscene called while another cutscene is running");
+
HSQOBJECT envObj;
sq_resetobject(&envObj);
if (SQ_FAILED(sq_getstackobj(v, 1, &envObj)))
- return sq_throwerror(v, "Couldn't get environment from stack");
+ return sq_throwerror(v, "failed to get environment from stack");
// create thread and store it on the stack
sq_newthread(vm, 1024);
@@ -489,21 +492,35 @@ 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<ThreadBase> parentThread = sqthread(v);
+ Common::SharedPtr<Thread> parentThread = sqthread(v);
Common::String cutsceneName = Common::String::format("%s (%lld)", _stringval(_closure(closure)->_function->_sourcename), _closure(closure)->_function->_lineinfos->_line);
- Common::SharedPtr<Cutscene> cutscene(new Cutscene(cutsceneName, parentThread->getId(), threadObj, closure, closureOverride, envObj));
- g_twp->_cutscene = cutscene;
+ 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());
// call the closure in the thread
- cutscene->update(0.f);
+ if (!cutscene->call())
+ return sq_throwerror(v, "call failed");
+
return breakwhilecutscene(v);
}
static SQInteger cutsceneOverride(HSQUIRRELVM v) {
debugC(kDebugSysScript, "cutsceneOverride");
- g_twp->_cutscene->cutsceneOverride();
- return 0;
+ return g_twp->skipCutscene();
}
static SQInteger dumpvar(HSQUIRRELVM v) {
@@ -610,7 +627,7 @@ static SQInteger inputHUD(HSQUIRRELVM v) {
}
static SQInteger inputOff(HSQUIRRELVM v) {
- if (!g_twp->_cutscene || g_twp->_cutscene->isStopped()) {
+ if (!g_twp->_cutscene.id) {
g_twp->_inputState.setInputActive(false);
g_twp->_inputState.setShowCursor(false);
}
@@ -618,8 +635,7 @@ static SQInteger inputOff(HSQUIRRELVM v) {
}
static SQInteger inputOn(HSQUIRRELVM v) {
- Common::SharedPtr<Cutscene> scene(g_twp->_cutscene);
- if (!scene || scene->isStopped()) {
+ if (!g_twp->_cutscene.id) {
g_twp->_inputState.setInputActive(true);
g_twp->_inputState.setShowCursor(true);
} else {
@@ -628,8 +644,8 @@ static SQInteger inputOn(HSQUIRRELVM v) {
state &= (~UI_INPUT_OFF);
state |= UI_CURSOR_ON;
state &= (~UI_CURSOR_OFF);
- scene->setInputState((InputStateFlag)state);
- scene->setShowCursor(true);
+ g_twp->_cutscene.inputState = (InputStateFlag)state;
+ g_twp->_cutscene.showCursor = true;
}
return 0;
}
@@ -764,7 +780,7 @@ static SQInteger stopthread(HSQUIRRELVM v) {
return 1;
}
- Common::SharedPtr<ThreadBase> t = sqthread(id);
+ Common::SharedPtr<Thread> t = sqthread(id);
if (t) {
t->stop();
}
@@ -792,7 +808,7 @@ static SQInteger stopthread(HSQUIRRELVM v) {
// }
// }
static SQInteger threadid(HSQUIRRELVM v) {
- Common::SharedPtr<ThreadBase> t = sqthread(v);
+ Common::SharedPtr<Thread> t = sqthread(v);
if (t)
sqpush(v, t->getId());
else
@@ -803,7 +819,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<ThreadBase> t = sqthread(v, 2);
+ Common::SharedPtr<Thread> 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 832aedbe104..d62ed14791a 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<ThreadBase> pt = sqthread(_parentId);
+ Common::SharedPtr<Thread> 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 8636a9b0b15..f387cba58f2 100644
--- a/engines/twp/thread.cpp
+++ b/engines/twp/thread.cpp
@@ -28,28 +28,6 @@
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;
@@ -80,6 +58,40 @@ 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
@@ -121,166 +133,4 @@ 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()) {
- _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;
- }
-}
-
} // namespace Twp
diff --git a/engines/twp/thread.h b/engines/twp/thread.h
index c050529c69c..b8ea1b644d9 100644
--- a/engines/twp/thread.h
+++ b/engines/twp/thread.h
@@ -28,113 +28,45 @@
namespace Twp {
-class ThreadBase {
+class Thread {
public:
- virtual ~ThreadBase() {}
-
- void pause() {
- if (_pauseable) {
- _paused = true;
- suspend();
- }
- }
+ Thread(const Common::String &name, bool global, HSQOBJECT threadObj, HSQOBJECT envObj, HSQOBJECT closureObj, const Common::Array<HSQOBJECT> args);
+ ~Thread();
- void unpause() {
- _paused = false;
- resume();
- }
+ 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 setName(const Common::String &name) { _name = name; }
- Common::String getName() const { return _name; }
+ bool call();
+ bool update(float elapsed);
- int getId() const { return _id; }
- virtual HSQUIRRELVM getThread() = 0;
+ void pause();
+ void unpause();
+ void stop();
- virtual bool isGlobal() = 0;
- bool isSuspended();
- bool isDead();
+ bool isSuspended() const;
+ bool isDead() const;
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;
-protected:
+private:
int _id = 0;
Common::String _name;
bool _stopRequest = 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 _paused = false;
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 ab123a8392b..331bc0e7c84 100644
--- a/engines/twp/twp.cpp
+++ b/engines/twp/twp.cpp
@@ -69,6 +69,8 @@ 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());
@@ -157,7 +159,7 @@ bool TwpEngine::preWalk(Common::SharedPtr<Object> actor, VerbId verbId, Common::
sqcallfunc(result, actor->_table, "actorPreWalk", verbId.id, noun1->_table, n2Table);
}
if (!result) {
- Common::String funcName = g_twp->_resManager->isActor(noun1->getId()) ? "actorPreWalk" : "objectPreWalk";
+ Common::String funcName = _resManager->isActor(noun1->getId()) ? "actorPreWalk" : "objectPreWalk";
if (sqrawexists(noun1->_table, funcName)) {
sqcallfunc(result, noun1->_table, funcName.c_str(), verbId.id, noun1->_table, n2Table);
debugC(kDebugGame, "%s %d n1=%s(%s) n2=%s -> %s", funcName.c_str(), verbId.id, noun1->_name.c_str(), noun1->_key.c_str(), n2Name.c_str(), result ? "yes" : "no");
@@ -179,7 +181,7 @@ bool TwpEngine::execSentence(Common::SharedPtr<Object> actor, VerbId verbId, Com
Common::String noun1name = !noun1 ? "null" : noun1->_key;
Common::String noun2name = !noun2 ? "null" : noun2->_key;
debugC(kDebugGame, "exec(%s,%d,%s,%s)", name.c_str(), verbId.id, noun1name.c_str(), noun2name.c_str());
- actor = !actor ? g_twp->_actor : actor;
+ actor = !actor ? _actor : actor;
if ((verbId.id <= 0) || (verbId.id > MAX_VERBS) || (!noun1) || (!actor))
return false;
@@ -508,11 +510,11 @@ void TwpEngine::update(float elapsed) {
}
_inputState.setHotspot(_noun1 != nullptr);
- bool hudVisible = _inputState.getInputActive() && _inputState.getInputVerbsActive() && _dialog->getState() == DialogState::None && !_cutscene;
+ bool hudVisible = _inputState.getInputActive() && _inputState.getInputVerbsActive() && _dialog->getState() == DialogState::None && !_cutscene.id;
_hud->setVisible(hudVisible);
_sentence.setVisible(_hud->isVisible());
_uiInv.setVisible(hudVisible);
- _actorSwitcher.setVisible((_dialog->getState() == DialogState::None) && !_cutscene);
+ _actorSwitcher.setVisible((_dialog->getState() == DialogState::None) && !_cutscene.id);
// 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());
@@ -557,30 +559,32 @@ 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<ThreadBase> > threads(_threads);
- Common::Array<Common::SharedPtr<ThreadBase> > threadsToRemove;
+ Common::Array<Common::SharedPtr<Thread> > threads(_threads);
+ Common::Array<Common::SharedPtr<Thread> > threadsToRemove;
bool isNotInDialog = _dialog->getState() == DialogState::None;
for (auto it = threads.begin(); it != threads.end(); it++) {
- Common::SharedPtr<ThreadBase> thread(*it);
+ Common::SharedPtr<Thread> 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<ThreadBase> thread(*it);
+ Common::SharedPtr<Thread> 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);
}
}
@@ -694,7 +698,7 @@ void TwpEngine::draw(RenderTexture *outTexture) {
setShaderEffect(_room->_effect);
_lighting->update(_room->_lights);
}
- _shaderParams->randomValue[0] = g_twp->getRandom();
+ _shaderParams->randomValue[0] = getRandom();
_shaderParams->timeLapse = fmodf(_time, 1000.f);
_shaderParams->iGlobalTime = _shaderParams->timeLapse;
_shaderParams->updateShader();
@@ -886,7 +890,7 @@ Common::Error TwpEngine::run() {
case TwpAction::kSelectActor4:
case TwpAction::kSelectActor5:
case TwpAction::kSelectActor6:
- if (g_twp->_actorSwitcher._mode == asOn) {
+ if (_actorSwitcher._mode == asOn) {
int index = (TwpAction)e.customType - kSelectActor1;
ActorSlot *slot = &_hud->_actorSlots[index];
if (slot->selectable && slot->actor && (slot->actor->_room->_name != "Void")) {
@@ -895,7 +899,7 @@ Common::Error TwpEngine::run() {
}
break;
case TwpAction::kSelectPreviousActor:
- if ((g_twp->_actorSwitcher._mode == asOn) && _actor) {
+ if ((_actorSwitcher._mode == asOn) && _actor) {
Common::Array<Common::SharedPtr<Object> > actors;
for (int i = 0; i < NUMACTORS; i++) {
ActorSlot *slot = &_hud->_actorSlots[i];
@@ -910,7 +914,7 @@ Common::Error TwpEngine::run() {
}
break;
case TwpAction::kSelectNextActor:
- if ((g_twp->_actorSwitcher._mode == asOn) && _actor) {
+ if ((_actorSwitcher._mode == asOn) && _actor) {
Common::Array<Common::SharedPtr<Object> > actors;
for (int i = 0; i < NUMACTORS; i++) {
ActorSlot *slot = &_hud->_actorSlots[i];
@@ -1066,7 +1070,7 @@ Common::Error TwpEngine::loadGameStream(Common::SeekableReadStream *stream) {
}
bool TwpEngine::canSaveGameStateCurrently(Common::U32String *msg) {
- return _saveGameManager->_allowSaveGame && !_cutscene;
+ return _saveGameManager->_allowSaveGame && !_cutscene.id;
}
Common::Error TwpEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
@@ -1083,7 +1087,7 @@ Common::Error TwpEngine::saveGameState(int slot, const Common::String &desc, boo
if (result.getCode() == Common::kNoError) {
Common::OutSaveFile *thumbnail = _saveFileMan->openForSaving(Common::String::format("Savegame%d.png", slot), false);
Graphics::Surface surface;
- g_twp->capture(surface, 320, 180);
+ capture(surface, 320, 180);
Image::writePNG(*thumbnail, surface);
thumbnail->finalize();
delete thumbnail;
@@ -1277,7 +1281,7 @@ Common::SharedPtr<Room> TwpEngine::defineRoom(const Common::String &name, HSQOBJ
error("Falied to define objects");
// declare the room in the root table
- setId(result->_table, g_twp->_resManager->newRoomId());
+ setId(result->_table, _resManager->newRoomId());
sqsetf(sqrootTbl(v), name, result->_table);
return result;
@@ -1342,7 +1346,7 @@ void TwpEngine::enterRoom(Common::SharedPtr<Room> room, Common::SharedPtr<Object
_room->_scalingTriggers.push_back(ScalingTrigger(obj, scaling));
}
}
- if (g_twp->_resManager->isActor(obj->getId())) {
+ if (_resManager->isActor(obj->getId())) {
actorEnter(obj);
} else if (sqrawexists(obj->_table, "enter"))
sqcall(obj->_table, "enter");
@@ -1370,8 +1374,8 @@ void TwpEngine::enterRoom(Common::SharedPtr<Room> room, Common::SharedPtr<Object
void TwpEngine::actorEnter(Common::SharedPtr<Object> actor) {
if (!actor)
return;
- if (sqrawexists(g_twp->_room->_table, "actorEnter")) {
- sqcall(g_twp->_room->_table, "actorEnter", actor->_table);
+ if (sqrawexists(_room->_table, "actorEnter")) {
+ sqcall(_room->_table, "actorEnter", actor->_table);
} else {
sqcall("actorEnter", actor->_table);
}
@@ -1389,7 +1393,7 @@ void TwpEngine::exitRoom(Common::SharedPtr<Room> nextRoom) {
for (size_t j = 0; j < layer->_objects.size(); j++) {
Common::SharedPtr<Object> obj = layer->_objects[j];
obj->stopObjectMotors();
- if (g_twp->_resManager->isActor(obj->getId())) {
+ if (_resManager->isActor(obj->getId())) {
actorExit(obj);
}
}
@@ -1412,7 +1416,7 @@ void TwpEngine::exitRoom(Common::SharedPtr<Room> nextRoom) {
obj->_node->remove();
it = layer->_objects.erase(it);
continue;
- } else if (g_twp->_resManager->isActor(obj->getId()) && _actor != obj) {
+ } else if (_resManager->isActor(obj->getId()) && _actor != obj) {
obj->stopObjectMotors();
}
it++;
@@ -1424,7 +1428,7 @@ void TwpEngine::exitRoom(Common::SharedPtr<Room> nextRoom) {
// stop all local threads
for (size_t i = 0; i < _threads.size(); i++) {
- Common::SharedPtr<ThreadBase> thread = _threads[i];
+ Common::SharedPtr<Thread> thread = _threads[i];
if (!thread->isGlobal()) {
thread->stop();
}
@@ -1445,6 +1449,9 @@ void TwpEngine::actorExit(Common::SharedPtr<Object> actor) {
if (sqrawexists(_room->_table, "actorExit")) {
sqcall(_room->_table, "actorExit", actor->_table);
}
+ if(_followActor == actor) {
+ _followActor = _actor;
+ }
}
}
@@ -1711,7 +1718,7 @@ void TwpEngine::callTrigger(Common::SharedPtr<Object> obj, HSQOBJECT trigger) {
Common::SharedPtr<Thread> thread(new Thread("Trigger", false, threadObj, obj->_table, trigger, Common::move(args)));
debugC(kDebugGame, "create triggerthread id: %d}", thread->getId());
- g_twp->_threads.push_back(thread);
+ _threads.push_back(thread);
// call the closure in the thread
if (!thread->call()) {
@@ -1776,14 +1783,42 @@ float TwpEngine::getRandom(float min, float max) const {
return min + scale * (max - min);
}
-void TwpEngine::skipCutscene() {
- if (!_cutscene)
- return;
- if (_cutscene->hasOverride()) {
- _cutscene->cutsceneOverride();
- return;
+SQRESULT TwpEngine::skipCutscene() {
+ if(!_cutscene.id)
+ return 0;
+
+ if((_dialog->getState() != DialogState::None) || _cutscene.inOverride || (_cutscene.closureOverride._type == OT_NULL)) {
+ _noOverride->reset();
+ return 0;
}
- _noOverride->reset();
+
+ _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;
}
Scaling *TwpEngine::getScaling(const Common::String &name) {
diff --git a/engines/twp/twp.h b/engines/twp/twp.h
index 1b357a9617f..bdbefef08de 100644
--- a/engines/twp/twp.h
+++ b/engines/twp/twp.h
@@ -69,7 +69,7 @@ class Scene;
struct ShaderParams;
class Task;
class TextDb;
-class ThreadBase;
+class Thread;
struct TwpGameDescription;
struct Verb;
struct VerbId;
@@ -119,7 +119,7 @@ public:
void updateSettingVars();
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override {
- return !_cutscene;
+ return _cutscene.id == 0;
}
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
@@ -163,6 +163,8 @@ public:
int runDialog(GUI::Dialog &dialog) override;
+ SQRESULT skipCutscene();
+
private:
void update(float elapsedMs);
void draw(RenderTexture *texture = nullptr);
@@ -181,7 +183,6 @@ private:
Common::Array<ActorSwitcherSlot> actorSwitcherSlots();
ActorSwitcherSlot actorSwitcherSlot(ActorSlot *slot);
Scaling *getScaling(const Common::String &name);
- void skipCutscene();
private:
unique_ptr<Vm> _vm;
@@ -192,7 +193,7 @@ public:
unique_ptr<ResManager> _resManager;
Common::Array<Common::SharedPtr<Room> > _rooms;
Common::Array<Common::SharedPtr<Object> > _actors;
- Common::Array<Common::SharedPtr<ThreadBase> > _threads;
+ Common::Array<Common::SharedPtr<Thread> > _threads;
Common::Array<Common::SharedPtr<Task> > _tasks;
Common::Array<Common::SharedPtr<Callback> > _callbacks;
Common::SharedPtr<Object> _actor;
@@ -208,7 +209,14 @@ public:
float _nextHoldToMoveTime = 0.f;
int _frameCounter = 0;
Common::SharedPtr<Lighting> _lighting;
- Common::SharedPtr<Cutscene> _cutscene;
+ struct {
+ int id = 0;
+ InputStateFlag inputState = (InputStateFlag)0;
+ bool showCursor = false;
+ bool inOverride = false;
+ HSQOBJECT envObj;
+ HSQOBJECT closureOverride;
+ } _cutscene;
unique_ptr<Scene> _scene;
unique_ptr<Scene> _screenScene;
unique_ptr<NoOverrideNode> _noOverride;
More information about the Scummvm-git-logs
mailing list