diff --git a/engines/mtropolis/elements.cpp b/engines/mtropolis/elements.cpp index 4c51d2741f8..a5524fd7a31 100644 --- a/engines/mtropolis/elements.cpp +++ b/engines/mtropolis/elements.cpp @@ -1566,8 +1566,10 @@ MiniscriptInstructionOutcome MToonElement::scriptSetRange(MiniscriptThread *thre } for (const MToonMetadata::FrameRangeDef &frameRange : _metadata->frameRanges) { - if (caseInsensitiveEqual(frameRange.name, *nameStrPtr)) - return scriptSetRangeTyped(thread, IntRange(frameRange.startFrame, frameRange.endFrame)); + if (caseInsensitiveEqual(frameRange.name, *nameStrPtr)) { + // Frame ranges in the metadata are 0-based, but setting the range is 1-based, so add 1 + return scriptSetRangeTyped(thread, IntRange(frameRange.startFrame + 1, frameRange.endFrame + 1)); + } } thread->error("mToon range was assigned to a label but the label doesn't exist in the mToon data"); diff --git a/engines/mtropolis/plugin/standard.cpp b/engines/mtropolis/plugin/standard.cpp index 5229fc09e5c..cef9d5aa2fd 100644 --- a/engines/mtropolis/plugin/standard.cpp +++ b/engines/mtropolis/plugin/standard.cpp @@ -2936,7 +2936,19 @@ bool ListVariableModifier::readAttributeIndexed(MiniscriptThread *thread, Dynami if (attrib == "value") { size_t realIndex = 0; return storage->_list->dynamicValueToIndex(realIndex, index) && storage->_list->getAtIndex(realIndex, result); + } else if (attrib == "delete") { + size_t realIndex = 0; + if (!storage->_list->dynamicValueToIndex(realIndex, index)) + return false; + if (!storage->_list->getAtIndex(realIndex, result)) + return false; + + storage->_list = storage->_list->clone(); + storage->_list->deleteAtIndex(realIndex); + + return true; } + return Modifier::readAttributeIndexed(thread, result, attrib, index); } diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp index 3288b51b7ed..1db8503e168 100644 --- a/engines/mtropolis/runtime.cpp +++ b/engines/mtropolis/runtime.cpp @@ -847,6 +847,21 @@ bool DynamicList::setAtIndex(size_t index, const DynamicValue &value) { } } +void DynamicList::deleteAtIndex(size_t index) { + if (_container != nullptr) { + size_t size = _container->getSize(); + if (size < _container->getSize()) { + for (size_t i = index + 1; i < size; i++) { + DynamicValue valueToMove; + _container->getAtIndex(i, valueToMove); + _container->setAtIndex(i - 1, valueToMove); + } + + _container->truncateToSize(size - 1); + } + } +} + void DynamicList::truncateToSize(size_t sz) { if (sz == 0) clear(); @@ -7955,7 +7970,7 @@ VThreadState VisualElement::consumeCommand(Runtime *runtime, const Common::Share bool VisualElement::respondsToEvent(const Event &evt) const { if (Event(EventIDs::kAuthorMessage, 13).respondsTo(evt)) { - if (getRuntime()->getHacks().mtiSceneReturnHack) + if (getRuntime()->getHacks().mtiSceneReturnHack && getParent() && getParent()->isSubsection()) return true; } @@ -7965,11 +7980,11 @@ bool VisualElement::respondsToEvent(const Event &evt) const { VThreadState VisualElement::consumeMessage(Runtime *runtime, const Common::SharedPtr &msg) { if (Event(EventIDs::kAuthorMessage, 13).respondsTo(msg->getEvent())) { if (getRuntime()->getHacks().mtiSceneReturnHack) { - assert(this->getParent()); - assert(this->getParent()->isSubsection()); - runtime->addSceneStateTransition(HighLevelSceneTransition(this->getSelfReference().lock().staticCast(), HighLevelSceneTransition::kTypeChangeToScene, false, false)); + if (getParent() && getParent()->isSubsection()) { + runtime->addSceneStateTransition(HighLevelSceneTransition(this->getSelfReference().lock().staticCast(), HighLevelSceneTransition::kTypeChangeToScene, false, false)); - return kVThreadReturn; + return kVThreadReturn; + } } } @@ -8673,10 +8688,23 @@ bool Modifier::readAttribute(MiniscriptThread *thread, DynamicValue &result, con Structural *owner = findStructuralOwner(); result.setObject(owner ? owner->getSelfReference() : Common::WeakPtr()); return true; + } else if (attrib == "previous") { + Modifier *sibling = findPrevSibling(); + if (sibling) + result.setObject(sibling->getSelfReference()); + else + result.clear(); + return true; + } else if (attrib == "next") { + Modifier *sibling = findNextSibling(); + if (sibling) + result.setObject(sibling->getSelfReference()); + else + result.clear(); + return true; } return false; - } MiniscriptInstructionOutcome Modifier::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) { @@ -8749,6 +8777,65 @@ void Modifier::setParent(const Common::WeakPtr &parent) { _parent = parent; } +Modifier *Modifier::findNextSibling() const { + RuntimeObject *parent = getParent().lock().get(); + if (parent) { + IModifierContainer *container = nullptr; + if (parent->isModifier()) + container = static_cast(parent)->getChildContainer(); + else if (parent->isStructural()) + container = static_cast(parent); + + if (container) + { + const Common::Array > &neighborhood = container->getModifiers(); + bool found = false; + size_t foundIndex = 0; + for (size_t i = 0; i < neighborhood.size(); i++) { + if (neighborhood[i].get() == this) { + foundIndex = i; + found = true; + break; + } + } + + if (found && foundIndex < neighborhood.size() - 1) + return neighborhood[foundIndex + 1].get(); + } + } + + return nullptr; +} + +Modifier *Modifier::findPrevSibling() const { + RuntimeObject *parent = getParent().lock().get(); + if (parent) { + IModifierContainer *container = nullptr; + if (parent->isModifier()) + container = static_cast(parent)->getChildContainer(); + else if (parent->isStructural()) + container = static_cast(parent); + + if (container) { + const Common::Array > &neighborhood = container->getModifiers(); + bool found = false; + size_t foundIndex = 0; + for (size_t i = 0; i < neighborhood.size(); i++) { + if (neighborhood[i].get() == this) { + foundIndex = i; + found = true; + break; + } + } + + if (found && foundIndex > 0) + return neighborhood[foundIndex - 1].get(); + } + } + + return nullptr; +} + bool Modifier::respondsToEvent(const Event &evt) const { return false; } diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h index 482d81d7d4f..f852fb60367 100644 --- a/engines/mtropolis/runtime.h +++ b/engines/mtropolis/runtime.h @@ -777,6 +777,7 @@ struct DynamicList { bool getAtIndex(size_t index, DynamicValue &value) const; bool setAtIndex(size_t index, const DynamicValue &value); + void deleteAtIndex(size_t index); void truncateToSize(size_t sz); void expandToMinimumSize(size_t sz); size_t getSize() const; @@ -2870,6 +2871,9 @@ public: const Common::WeakPtr &getParent() const; void setParent(const Common::WeakPtr &parent); + Modifier *findNextSibling() const; + Modifier *findPrevSibling() const; + bool respondsToEvent(const Event &evt) const override; VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr &msg) override;