[Scummvm-git-logs] scummvm master -> 6a966b2d1796ec2429b82936bb4e2cda197e5f07
elasota
noreply at scummvm.org
Sat Jul 16 01:49:57 UTC 2022
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
7180505432 MTROPOLIS: Change enable short transitions default to on
6a966b2d17 MTROPOLIS: Add boundary detection modifier, fix real-time vector motion var sourcing
Commit: 7180505432d31a06fee7713382bc33cd7317737f
https://github.com/scummvm/scummvm/commit/7180505432d31a06fee7713382bc33cd7317737f
Author: elasota (ejlasota at gmail.com)
Date: 2022-07-15T21:49:23-04:00
Commit Message:
MTROPOLIS: Change enable short transitions default to on
Changed paths:
engines/mtropolis/detection.cpp
diff --git a/engines/mtropolis/detection.cpp b/engines/mtropolis/detection.cpp
index 3e3a808b83d..1957103811d 100644
--- a/engines/mtropolis/detection.cpp
+++ b/engines/mtropolis/detection.cpp
@@ -76,7 +76,7 @@ static const ADExtraGuiOptionsMap optionsList[] = {
_s("Enable short transitions"),
_s("Enables transitions that are set to maximum rate instead of skipping them"),
"mtropolis_mod_minimum_transition_duration",
- false,
+ true,
0,
0
}
Commit: 6a966b2d1796ec2429b82936bb4e2cda197e5f07
https://github.com/scummvm/scummvm/commit/6a966b2d1796ec2429b82936bb4e2cda197e5f07
Author: elasota (ejlasota at gmail.com)
Date: 2022-07-15T21:49:23-04:00
Commit Message:
MTROPOLIS: Add boundary detection modifier, fix real-time vector motion var sourcing
Changed paths:
engines/mtropolis/modifiers.cpp
engines/mtropolis/modifiers.h
engines/mtropolis/runtime.cpp
engines/mtropolis/runtime.h
diff --git a/engines/mtropolis/modifiers.cpp b/engines/mtropolis/modifiers.cpp
index c4391c1f554..6f93f8b12a1 100644
--- a/engines/mtropolis/modifiers.cpp
+++ b/engines/mtropolis/modifiers.cpp
@@ -769,6 +769,19 @@ void VectorMotionModifier::trigger(Runtime *runtime) {
uint64 currentTime = runtime->getPlayTime();
_scheduledEvent = runtime->getScheduler().scheduleMethod<VectorMotionModifier, &VectorMotionModifier::trigger>(currentTime + 1, this);
+ Modifier *vecSrcModifier = _vecVar.lock().get();
+
+ // Variable-sourced motion is continuously updated and doesn't need to be re-triggered.
+ // The Pong minigame in Obsidian's Bureau chapter depends on this.
+ if (vecSrcModifier && vecSrcModifier->isVariable()) {
+ DynamicValue vec;
+ VariableModifier *varModifier = static_cast<VariableModifier *>(vecSrcModifier);
+ varModifier->varGetValue(nullptr, vec);
+
+ if (vec.getType() == DynamicValueTypes::kVector)
+ _resolvedVector = vec.getVector();
+ }
+
double radians = _resolvedVector.angleDegrees * (M_PI / 180.0);
// Distance is per-tick, which is 1/60 of a sec, so the multiplier is 60.0/1000.0 or 0.06
@@ -1171,6 +1184,18 @@ void TimerMessengerModifier::trigger(Runtime *runtime) {
_sendSpec.sendFromMessenger(runtime, this, _incomingData, nullptr);
}
+BoundaryDetectionMessengerModifier::BoundaryDetectionMessengerModifier()
+ : _enableWhen(Event::create()), _disableWhen(Event::create()), _exitTriggerMode(kExitTriggerExiting),
+ _detectTopEdge(false), _detectBottomEdge(false), _detectLeftEdge(false), _detectRightEdge(false),
+ _detectionMode(kContinuous), _runtime(nullptr), _isActive(false) {
+}
+
+BoundaryDetectionMessengerModifier::~BoundaryDetectionMessengerModifier() {
+ if (_isActive)
+ _runtime->removeBoundaryDetector(this);
+}
+
+
bool BoundaryDetectionMessengerModifier::load(ModifierLoaderContext &context, const Data::BoundaryDetectionMessengerModifier &data) {
if (!loadTypicalHeader(data.modHeader))
return false;
@@ -1192,6 +1217,59 @@ bool BoundaryDetectionMessengerModifier::load(ModifierLoaderContext &context, co
return true;
}
+bool BoundaryDetectionMessengerModifier::respondsToEvent(const Event &evt) const {
+ return _enableWhen.respondsTo(evt) || _disableWhen.respondsTo(evt);
+}
+
+VThreadState BoundaryDetectionMessengerModifier::consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
+ if (_enableWhen.respondsTo(msg->getEvent()) && !_isActive) {
+ _runtime = runtime;
+ _runtime->addBoundaryDetector(this);
+ _isActive = true;
+
+ _incomingData = msg->getValue();
+ if (_incomingData.getType() == DynamicValueTypes::kList)
+ _incomingData.setList(_incomingData.getList()->clone());
+ }
+ if (_disableWhen.respondsTo(msg->getEvent()) && _isActive) {
+ _runtime->removeBoundaryDetector(this);
+ _isActive = false;
+ _runtime = nullptr;
+ }
+
+ return kVThreadReturn;
+}
+
+void BoundaryDetectionMessengerModifier::linkInternalReferences(ObjectLinkingScope *outerScope) {
+ _send.linkInternalReferences(outerScope);
+}
+
+void BoundaryDetectionMessengerModifier::visitInternalReferences(IStructuralReferenceVisitor *visitor) {
+ _send.visitInternalReferences(visitor);
+}
+
+void BoundaryDetectionMessengerModifier::getCollisionProperties(Modifier *&modifier, uint &edgeFlags, bool &mustBeCompletelyOutside, bool &continuous) const {
+ modifier = const_cast<BoundaryDetectionMessengerModifier *>(this);
+
+ uint flags = 0;
+ if (_detectBottomEdge)
+ flags |= kEdgeBottom;
+ if (_detectTopEdge)
+ flags |= kEdgeTop;
+ if (_detectRightEdge)
+ flags |= kEdgeRight;
+ if (_detectLeftEdge)
+ flags |= kEdgeLeft;
+
+ edgeFlags = flags;
+ mustBeCompletelyOutside = (_exitTriggerMode == kExitTriggerOnceExited);
+ continuous = (_detectionMode == kContinuous);
+}
+
+void BoundaryDetectionMessengerModifier::triggerCollision(Runtime *runtime) {
+ _send.sendFromMessenger(runtime, this, _incomingData, nullptr);
+}
+
Common::SharedPtr<Modifier> BoundaryDetectionMessengerModifier::shallowClone() const {
return Common::SharedPtr<Modifier>(new BoundaryDetectionMessengerModifier(*this));
}
diff --git a/engines/mtropolis/modifiers.h b/engines/mtropolis/modifiers.h
index aebbd1ea091..72be5f140c1 100644
--- a/engines/mtropolis/modifiers.h
+++ b/engines/mtropolis/modifiers.h
@@ -477,10 +477,22 @@ private:
Common::SharedPtr<ScheduledEvent> _scheduledEvent;
};
-class BoundaryDetectionMessengerModifier : public Modifier {
+class BoundaryDetectionMessengerModifier : public Modifier, public IBoundaryDetector {
public:
+ BoundaryDetectionMessengerModifier();
+ ~BoundaryDetectionMessengerModifier();
+
bool load(ModifierLoaderContext &context, const Data::BoundaryDetectionMessengerModifier &data);
+ bool respondsToEvent(const Event &evt) const override;
+ VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
+
+ void linkInternalReferences(ObjectLinkingScope *outerScope) override;
+ void visitInternalReferences(IStructuralReferenceVisitor *visitor) override;
+
+ void getCollisionProperties(Modifier *&modifier, uint &edgeFlags, bool &mustBeCompletelyOutside, bool &continuous) const override;
+ void triggerCollision(Runtime *runtime) override;
+
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Boundary Detection Modifier"; }
#endif
@@ -508,6 +520,10 @@ private:
bool _detectLeftEdge;
bool _detectRightEdge;
MessengerSendSpec _send;
+
+ Runtime *_runtime;
+ bool _isActive;
+ DynamicValue _incomingData;
};
class CollisionDetectionMessengerModifier : public Modifier, public ICollider {
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index 32c11152edd..257f3152868 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -4036,6 +4036,7 @@ bool Runtime::runFrame() {
if (_collisionCheckTime < _playTime) {
_collisionCheckTime = _playTime;
+ checkBoundaries();
checkCollisions();
}
@@ -5498,6 +5499,109 @@ void Runtime::checkCollisions() {
}
}
+void Runtime::addBoundaryDetector(IBoundaryDetector *boundaryDetector) {
+ BoundaryCheckState state;
+ state.currentContacts = 0;
+ state.detector = boundaryDetector;
+ state.position = Common::Point(0, 0);
+ state.positionResolved = false;
+
+ Modifier *modifier;
+ uint edgeFlags;
+ bool mustBeCompletelyOutside;
+ bool continuous;
+ boundaryDetector->getCollisionProperties(modifier, edgeFlags, mustBeCompletelyOutside, continuous);
+
+ _boundaryChecks.push_back(state);
+}
+
+void Runtime::removeBoundaryDetector(IBoundaryDetector *boundaryDetector) {
+ size_t numColliders = _boundaryChecks.size();
+ for (size_t i = 0; i < numColliders; i++) {
+ if (_boundaryChecks[i].detector == boundaryDetector) {
+ _boundaryChecks.remove_at(i);
+ return;
+ }
+ }
+}
+
+void Runtime::checkBoundaries() {
+ // Boundary Detection Messenger behavior is very quirky in mTropolis 1.1. Basically, if an object moves in the direction of
+ // the boundary, then it may trigger collision checks with the boundary. If it moves but does not move in the direction of
+ // the boundary, then it is considered no longer in contact with the boundary - period - which means it can trigger again
+ // once it moves in the boundary direction.
+ for (BoundaryCheckState &checkState : _boundaryChecks) {
+ Modifier *modifier;
+ uint edgeFlags;
+ bool mustBeCompletelyOutside;
+ bool continuous;
+ checkState.detector->getCollisionProperties(modifier, edgeFlags, mustBeCompletelyOutside, continuous);
+
+ Structural *structural = modifier->findStructuralOwner();
+ if (structural == nullptr || !structural->isElement() || !static_cast<Element *>(structural)->isVisual())
+ continue;
+
+ VisualElement *visual = static_cast<VisualElement *>(structural);
+
+ Common::Rect thisRect = visual->getRelativeRect();
+ Common::Point point(thisRect.left, thisRect.top);
+
+ if (!checkState.positionResolved) {
+ checkState.positionResolved = true;
+ checkState.position = point;
+ continue;
+ }
+
+ if (point == checkState.position)
+ continue;
+
+ Structural *parentStructural = visual->getParent();
+ if (parentStructural == nullptr || !parentStructural->isElement() || !static_cast<Element *>(parentStructural)->isVisual())
+ continue;
+
+ VisualElement *parentVisual = static_cast<VisualElement *>(parentStructural);
+
+ Common::Point delta = point - checkState.position;
+
+ int16 parentWidth = parentVisual->getRelativeRect().width();
+ int16 parentHeight = parentVisual->getRelativeRect().height();
+
+ uint contacts = 0;
+ if (delta.x < 0) {
+ int16 edge = mustBeCompletelyOutside ? thisRect.right : thisRect.left;
+ if (edge < 0)
+ contacts |= IBoundaryDetector::kEdgeLeft;
+ }
+ if (delta.y < 0) {
+ int16 edge = mustBeCompletelyOutside ? thisRect.bottom : thisRect.top;
+ if (edge < 0)
+ contacts |= IBoundaryDetector::kEdgeTop;
+ }
+ if (delta.x > 0) {
+ int16 edge = mustBeCompletelyOutside ? thisRect.left : thisRect.right;
+ if (edge >= parentWidth)
+ contacts |= IBoundaryDetector::kEdgeRight;
+ }
+ if (delta.y > 0) {
+ int16 edge = mustBeCompletelyOutside ? thisRect.top : thisRect.bottom;
+ if (edge >= parentHeight)
+ contacts |= IBoundaryDetector::kEdgeBottom;
+ }
+
+ uint activatedContacts = contacts;
+
+ // If non-continuous, then only activate new contacts
+ if (!continuous)
+ activatedContacts &= ~checkState.currentContacts;
+
+ checkState.position = point;
+ checkState.currentContacts = contacts;
+
+ if (activatedContacts & edgeFlags)
+ checkState.detector->triggerCollision(this);
+ }
+}
+
void Runtime::recursiveFindColliders(Structural *structural, size_t sceneStackDepth, Common::Array<ColliderInfo> &colliders, int32 parentOriginX, int32 parentOriginY, bool isRoot) {
int32 childOffsetX = parentOriginX;
int32 childOffsetY = parentOriginY;
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index 1c97601a944..84fe30dccea 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -91,6 +91,7 @@ class Window;
class WorldManagerInterface;
struct DynamicValue;
struct DynamicValueWriteProxy;
+struct IBoundaryDetector;
struct ICollider;
struct ILoadUIProvider;
struct IMessageConsumer;
@@ -1583,6 +1584,10 @@ public:
void removeCollider(ICollider *collider);
void checkCollisions();
+ void addBoundaryDetector(IBoundaryDetector *boundaryDetector);
+ void removeBoundaryDetector(IBoundaryDetector *boundaryDetector);
+ void checkBoundaries();
+
const Common::String *resolveAttributeIDName(uint32 attribID) const;
#ifdef MTROPOLIS_DEBUG_ENABLE
@@ -1648,6 +1653,13 @@ private:
ICollider *collider;
};
+ struct BoundaryCheckState {
+ IBoundaryDetector *detector;
+ uint currentContacts;
+ Common::Point position;
+ bool positionResolved;
+ };
+
struct ColliderInfo {
size_t sceneStackDepth;
uint16 layer;
@@ -1789,6 +1801,7 @@ private:
bool _isQuitting;
Common::Array<Common::SharedPtr<CollisionCheckState> > _colliders;
+ Common::Array<BoundaryCheckState> _boundaryChecks;
uint32 _collisionCheckTime;
Hacks _hacks;
@@ -2131,6 +2144,18 @@ struct ICollider : public IInterfaceBase {
virtual void triggerCollision(Runtime *runtime, Structural *collidingElement, bool wasInContact, bool isInContact, bool &outShouldStop) = 0;
};
+struct IBoundaryDetector : public IInterfaceBase {
+ enum EdgeFlags {
+ kEdgeTop = 0x1,
+ kEdgeBottom = 0x2,
+ kEdgeLeft = 0x4,
+ kEdgeRight = 0x8,
+ };
+
+ virtual void getCollisionProperties(Modifier *&modifier, uint &edgeFlags, bool &mustBeCompletelyOutside, bool &continuous) const = 0;
+ virtual void triggerCollision(Runtime *runtime) = 0;
+};
+
struct MediaCueState {
enum TriggerTiming {
kTriggerTimingStart = 0,
More information about the Scummvm-git-logs
mailing list