[Scummvm-git-logs] scummvm master -> 84f564db2393901999a22782adfc6347799b5b03

elasota noreply at scummvm.org
Tue Dec 27 19:17:52 UTC 2022


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:
84f564db23 MTROPOLIS: Implement cursor element tracking and fire collision modifiers immediately if the same message disables and e


Commit: 84f564db2393901999a22782adfc6347799b5b03
    https://github.com/scummvm/scummvm/commit/84f564db2393901999a22782adfc6347799b5b03
Author: elasota (ejlasota at gmail.com)
Date: 2022-12-27T14:17:29-05:00

Commit Message:
MTROPOLIS: Implement cursor element tracking and fire collision modifiers immediately if the same message disables and enables the collision modifier.  This should fix the MTI save menu.

Changed paths:
    engines/mtropolis/modifiers.cpp
    engines/mtropolis/modifiers.h
    engines/mtropolis/render.cpp
    engines/mtropolis/render.h
    engines/mtropolis/runtime.cpp
    engines/mtropolis/runtime.h


diff --git a/engines/mtropolis/modifiers.cpp b/engines/mtropolis/modifiers.cpp
index 0e348b809e2..b63d7c7aeef 100644
--- a/engines/mtropolis/modifiers.cpp
+++ b/engines/mtropolis/modifiers.cpp
@@ -1734,22 +1734,37 @@ bool CollisionDetectionMessengerModifier::respondsToEvent(const Event &evt) cons
 }
 
 VThreadState CollisionDetectionMessengerModifier::consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
+	// If we get a message that enables AND disables this at the same time, then we need to detect collisions and fire them,
+	// then disable this element.
+	// MTI depends on this behavior for the save game menu.
+
+	if (_disableWhen.respondsTo(msg->getEvent())) {
+		runtime->getVThread().pushTask("CollisionDetectionModifier::disableTask", this, &CollisionDetectionMessengerModifier::disableTask);
+	}
 	if (_enableWhen.respondsTo(msg->getEvent())) {
-		if (!_isActive) {
-			_isActive = true;
-			_runtime = runtime;
+		runtime->getVThread().pushTask("CollisionDetectionModifier::enableTask", this, &CollisionDetectionMessengerModifier::enableTask);
 
-			runtime->addCollider(this);
-		}
 		_incomingData = msg->getValue();
 		if (_incomingData.getType() == DynamicValueTypes::kList)
 			_incomingData.setList(_incomingData.getList()->clone());
 		_triggerSource = msg->getSource();
+		_runtime = runtime;
 	}
-	if (_disableWhen.respondsTo(msg->getEvent())) {
-		disable(runtime);
+
+	return kVThreadReturn;
+}
+
+VThreadState CollisionDetectionMessengerModifier::enableTask(const EnableTaskData &taskData) {
+	if (!_isActive) {
+		_isActive = true;
+		_runtime->addCollider(this);
+		_runtime->checkCollisions(this);
 	}
+	return kVThreadReturn;
+}
 
+VThreadState CollisionDetectionMessengerModifier::disableTask(const DisableTaskData &taskData) {
+	disable(_runtime);
 	return kVThreadReturn;
 }
 
diff --git a/engines/mtropolis/modifiers.h b/engines/mtropolis/modifiers.h
index f04b84e6d66..fa3c0153d72 100644
--- a/engines/mtropolis/modifiers.h
+++ b/engines/mtropolis/modifiers.h
@@ -704,6 +704,15 @@ private:
 	Common::SharedPtr<Modifier> shallowClone() const override;
 	const char *getDefaultName() const override;
 
+	struct EnableTaskData {
+	};
+
+	struct DisableTaskData {
+	};
+
+	VThreadState enableTask(const EnableTaskData &taskData);
+	VThreadState disableTask(const DisableTaskData &taskData);
+
 	void getCollisionProperties(Modifier *&modifier, bool &collideInFront, bool &collideBehind, bool &excludeParents) const override;
 	void triggerCollision(Runtime *runtime, Structural *collidingElement, bool wasInContact, bool isInContact, bool &outShouldStop) override;
 
diff --git a/engines/mtropolis/render.cpp b/engines/mtropolis/render.cpp
index c0b23fbc16c..61b1bb31a60 100644
--- a/engines/mtropolis/render.cpp
+++ b/engines/mtropolis/render.cpp
@@ -107,7 +107,7 @@ WindowParameters::WindowParameters(Runtime *wp_runtime, int32 wp_x, int32 wp_y,
 }
 
 Window::Window(const WindowParameters &windowParams)
-	: _runtime(windowParams.runtime), _x(windowParams.x), _y(windowParams.y), _strata(0), _isMouseTransparent(false) {
+	: _runtime(windowParams.runtime), _x(windowParams.x), _y(windowParams.y), _strata(0), _isMouseTransparent(false), _isMouseVisible(true) {
 	_surface.reset(new Graphics::ManagedSurface(windowParams.width, windowParams.height, windowParams.format));
 }
 
@@ -157,6 +157,14 @@ void Window::setCursorGraphic(const Common::SharedPtr<CursorGraphic>& cursor) {
 	_cursor = cursor;
 }
 
+bool Window::getMouseVisible() const {
+	return _isMouseVisible;
+}
+
+void Window::setMouseVisible(bool visible) {
+	_isMouseVisible = visible;
+}
+
 void Window::setStrata(int strata) {
 	_strata = strata;
 }
diff --git a/engines/mtropolis/render.h b/engines/mtropolis/render.h
index 5249cf84e1e..97ea606bf90 100644
--- a/engines/mtropolis/render.h
+++ b/engines/mtropolis/render.h
@@ -108,6 +108,9 @@ public:
 	const Common::SharedPtr<CursorGraphic> &getCursorGraphic() const;
 	void setCursorGraphic(const Common::SharedPtr<CursorGraphic> &cursor);
 
+	bool getMouseVisible() const;
+	void setMouseVisible(bool visible);
+
 	void setStrata(int strata);
 	int getStrata() const;
 
@@ -130,6 +133,7 @@ protected:
 	Runtime *_runtime;
 	int _strata;
 	bool _isMouseTransparent;
+	bool _isMouseVisible;
 
 	Common::SharedPtr<Graphics::ManagedSurface> _surface;
 	Common::SharedPtr<CursorGraphic> _cursor;
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index 5630ee7706c..454e5f62fe0 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -2716,9 +2716,15 @@ MiniscriptInstructionOutcome WorldManagerInterface::writeRefAttribute(Miniscript
 		DynamicValueWriteIntegerHelper<int32>::create(&_opInt, result);
 		return kMiniscriptInstructionOutcomeContinue;
 	} else if (attrib == "scenefades") {
-		// TODO
+#ifdef MTROPOLIS_DEBUG_ENABLE
+		if (Debugger *debugger = thread->getRuntime()->debugGetDebugger())
+			debugger->notify(kDebugSeverityWarning, "'scenefades' attribute was set on WorldManager, which is implemented yet");
+#endif
 		DynamicValueWriteDiscardHelper::create(result);
 		return kMiniscriptInstructionOutcomeContinue;
+	} else if (attrib == "cursor") {
+		DynamicValueWriteFuncHelper<WorldManagerInterface, &WorldManagerInterface::setCursor, true>::create(this, result);
+		return kMiniscriptInstructionOutcomeContinue;
 	}
 	return RuntimeObject::writeRefAttribute(thread, result, attrib);
 }
@@ -2774,6 +2780,28 @@ MiniscriptInstructionOutcome WorldManagerInterface::setWinSndBufferSize(Miniscri
 	return kMiniscriptInstructionOutcomeContinue;
 }
 
+MiniscriptInstructionOutcome WorldManagerInterface::setCursor(MiniscriptThread *thread, const DynamicValue &value) {
+	switch (value.getType())
+	{
+	case DynamicValueTypes::kNull:
+		thread->getRuntime()->setCursorElement(Common::WeakPtr<VisualElement>());
+		return kMiniscriptInstructionOutcomeContinue;
+	case DynamicValueTypes::kObject: {
+			Common::SharedPtr<RuntimeObject> obj = value.getObject().object.lock();
+			if (obj && obj->isElement() && static_cast<Element *>(obj.get())->isVisual()) {
+				thread->getRuntime()->setCursorElement(obj.staticCast<VisualElement>());
+				return kMiniscriptInstructionOutcomeContinue;
+			} else {
+				thread->error("Object assigned as cursor wasn't a visual element");
+				return kMiniscriptInstructionOutcomeFailed;
+			}
+		} break;
+	default:
+		thread->error("Value assigned as cursor wasn't an object");
+		return kMiniscriptInstructionOutcomeFailed;
+	}
+}
+
 SystemInterface::SystemInterface() : _masterVolume(kFullVolume) {
 }
 
@@ -4180,10 +4208,10 @@ Runtime::Runtime(OSystem *system, Audio::Mixer *mixer, ISaveUIProvider *saveProv
 	: _system(system), _mixer(mixer), _saveProvider(saveProvider), _loadProvider(loadProvider),
 	  _nextRuntimeGUID(1), _realDisplayMode(kColorDepthModeInvalid), _fakeDisplayMode(kColorDepthModeInvalid),
 	  _displayWidth(1024), _displayHeight(768), _realTime(0), _realTimeBase(0), _playTime(0), _playTimeBase(0), _sceneTransitionState(kSceneTransitionStateNotTransitioning),
-	  _lastFrameCursor(nullptr), _defaultCursor(new DefaultCursorGraphic()), _platform(kProjectPlatformUnknown),
+	  _lastFrameCursor(nullptr), _lastFrameMouseVisible(false), _defaultCursor(new DefaultCursorGraphic()), _platform(kProjectPlatformUnknown),
 	  _cachedMousePosition(Common::Point(0, 0)), _realMousePosition(Common::Point(0, 0)), _trackedMouseOutside(false),
-	  _forceCursorRefreshOnce(true), _autoResetCursor(false), _haveModifierOverrideCursor(false), _sceneGraphChanged(false), _isQuitting(false),
-	  _collisionCheckTime(0), _defaultVolumeState(true), _activeSceneTransitionEffect(nullptr), _sceneTransitionStartTime(0), _sceneTransitionEndTime(0),
+	  _forceCursorRefreshOnce(true), _autoResetCursor(false), _haveModifierOverrideCursor(false), _haveCursorElement(false), _sceneGraphChanged(false), _isQuitting(false),
+	  _collisionCheckTime(0), _elementCursorUpdateTime(0), _defaultVolumeState(true), _activeSceneTransitionEffect(nullptr), _sceneTransitionStartTime(0), _sceneTransitionEndTime(0),
 	  _sharedSceneWasSetExplicitly(false), _modifierOverrideCursorID(0), _subtitleRenderer(subRenderer), _multiClickStartTime(0), _multiClickInterval(500), _multiClickCount(0)
 {
 	_random.reset(new Common::RandomSource("mtropolis"));
@@ -4509,9 +4537,14 @@ bool Runtime::runFrame() {
 			_collisionCheckTime = _playTime;
 
 			checkBoundaries();
-			checkCollisions();
+			checkCollisions(nullptr);
+			continue;
 		}
 
+		// Reset cursor if the cursor element is gone
+		if (_haveCursorElement && _elementTrackedToCursor.expired())
+			updateMainWindowCursor();
+
 		if (_isQuitting)
 			return false;
 
@@ -4642,23 +4675,30 @@ void Runtime::drawFrame() {
 	_system->updateScreen();
 
 	Common::SharedPtr<CursorGraphic> cursor;
+	bool mouseVisible = true;
 
 	Common::SharedPtr<Window> focusWindow = _mouseFocusWindow.lock();
 
 	if (!focusWindow)
 		focusWindow = findTopWindow(_realMousePosition.x, _realMousePosition.y);
 
-	if (focusWindow)
+	if (focusWindow) {
 		cursor = focusWindow->getCursorGraphic();
+		mouseVisible = focusWindow->getMouseVisible();
+	}
 
 	if (!cursor)
 		cursor = _defaultCursor;
 
-	if (cursor != _lastFrameCursor) {
+	if ((cursor != _lastFrameCursor || !_lastFrameMouseVisible) && mouseVisible) {
 		CursorMan.showMouse(true);
 		CursorMan.replaceCursor(cursor->getCursor());
 
 		_lastFrameCursor = cursor;
+		_lastFrameMouseVisible = true;
+	} else if (_lastFrameMouseVisible && !mouseVisible) {
+		CursorMan.showMouse(false);
+		_lastFrameMouseVisible = false;
 	}
 
 	if (_project)
@@ -5656,9 +5696,15 @@ VThreadState Runtime::updateMousePositionTask(const UpdateMousePositionTaskData
 		sendMessageOnVThread(dispatch);
 	}
 
+	// Cursor element positions are only updated on mouse movement, not when initially set
+	bool needUpdateElementPosition = (_cachedMousePosition.x != data.x || _cachedMousePosition.y != data.y);
+
 	_cachedMousePosition.x = data.x;
 	_cachedMousePosition.y = data.y;
 
+	if (needUpdateElementPosition)
+		updateCursorElementPosition();
+
 	return kVThreadReturn;
 }
 
@@ -5667,6 +5713,17 @@ void Runtime::updateMainWindowCursor() {
 	const uint32 kArrowID = 10011;
 
 	if (!_mainWindow.expired()) {
+		if (_haveCursorElement) {
+			Common::SharedPtr<Window> mainWindow = _mainWindow.lock();
+			if (_elementTrackedToCursor.expired()) {
+				mainWindow->setMouseVisible(true);
+				_elementTrackedToCursor.reset();
+			} else {
+				mainWindow->setMouseVisible(false);
+				return;
+			}
+		}
+
 		uint32 selectedCursor = kArrowID;
 		if (!_mouseOverObject.expired())
 			selectedCursor = kHandPointUpID;
@@ -5681,6 +5738,7 @@ void Runtime::updateMainWindowCursor() {
 				if (graphic) {
 					Common::SharedPtr<Window> mainWindow = _mainWindow.lock();
 					mainWindow->setCursorGraphic(graphic);
+					mainWindow->setMouseVisible(true);
 				}
 			}
 		}
@@ -5931,7 +5989,7 @@ void Runtime::removeCollider(ICollider *collider) {
 	}
 }
 
-void Runtime::checkCollisions() {
+void Runtime::checkCollisions(ICollider *optRestrictToCollider) {
 	if (!_colliders.size())
 		return;
 
@@ -5944,6 +6002,9 @@ void Runtime::checkCollisions() {
 	for (const Common::SharedPtr<CollisionCheckState> &collisionCheckPtr : _colliders) {
 		CollisionCheckState &colCheck = *collisionCheckPtr.get();
 
+		if (optRestrictToCollider && colCheck.collider != optRestrictToCollider)
+			continue;
+
 		Modifier *modifier = nullptr;
 		bool collideInFront;
 		bool collideBehind;
@@ -6062,6 +6123,26 @@ void Runtime::checkCollisions() {
 	}
 }
 
+void Runtime::setCursorElement(const Common::WeakPtr<VisualElement> &element) {
+	_elementTrackedToCursor = element;
+	_haveCursorElement = !element.expired();
+
+	updateMainWindowCursor();
+}
+
+void Runtime::updateCursorElementPosition() {
+	Common::SharedPtr<VisualElement> element = _elementTrackedToCursor.lock();
+	if (!element)
+		return;
+
+	Common::Point elementPos = element->getGlobalPosition();
+	if (elementPos != _cachedMousePosition) {
+		VisualElement::OffsetTranslateTaskData *taskData = _vthread->pushTask("VisualElement::offsetTranslateTask", element.get(), &VisualElement::offsetTranslateTask);
+		taskData->dx = _cachedMousePosition.x - elementPos.x;
+		taskData->dy = _cachedMousePosition.y - elementPos.y;
+	}
+}
+
 void Runtime::addBoundaryDetector(IBoundaryDetector *boundaryDetector) {
 	BoundaryCheckState state;
 	state.currentContacts = 0;
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index 1e35aecbfa6..4bd33306828 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -1671,7 +1671,10 @@ public:
 
 	void addCollider(ICollider *collider);
 	void removeCollider(ICollider *collider);
-	void checkCollisions();
+	void checkCollisions(ICollider *optRestrictToCollider);
+
+	void setCursorElement(const Common::WeakPtr<VisualElement> &element);
+	void updateCursorElementPosition();
 
 	void addBoundaryDetector(IBoundaryDetector *boundaryDetector);
 	void removeBoundaryDetector(IBoundaryDetector *boundaryDetector);
@@ -1891,6 +1894,7 @@ private:
 
 	Common::SharedPtr<CursorGraphic> _lastFrameCursor;
 	Common::SharedPtr<CursorGraphic> _defaultCursor;
+	bool _lastFrameMouseVisible;
 
 	Common::WeakPtr<Window> _mouseFocusWindow;
 	bool _mouseFocusFlags[Actions::kMouseButtonCount];
@@ -1925,6 +1929,7 @@ private:
 
 	uint32 _modifierOverrideCursorID;
 	bool _haveModifierOverrideCursor;
+	bool _haveCursorElement;
 
 	uint32 _multiClickStartTime;
 	uint32 _multiClickInterval;
@@ -1941,6 +1946,9 @@ private:
 	Common::Array<BoundaryCheckState> _boundaryChecks;
 	uint32 _collisionCheckTime;
 
+	Common::WeakPtr<VisualElement> _elementTrackedToCursor;
+	uint32 _elementCursorUpdateTime;
+
 	Common::Array<IPostEffect *> _postEffects;
 
 	Palette _globalPalette;
@@ -2048,6 +2056,7 @@ private:
 	MiniscriptInstructionOutcome setRefreshCursor(MiniscriptThread *thread, const DynamicValue &value);
 	MiniscriptInstructionOutcome setAutoResetCursor(MiniscriptThread *thread, const DynamicValue &value);
 	MiniscriptInstructionOutcome setWinSndBufferSize(MiniscriptThread *thread, const DynamicValue &value);
+	MiniscriptInstructionOutcome setCursor(MiniscriptThread *thread, const DynamicValue &value);
 
 	int32 _opInt;
 	bool _gameMode;




More information about the Scummvm-git-logs mailing list