[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