[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