[Scummvm-git-logs] scummvm master -> 6c0a2ac38230412f813d9bdf9b6c92ce48635e75

elasota noreply at scummvm.org
Wed Jun 14 03:59:11 UTC 2023


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:
80a75d7236 MTROPOLIS: Add AVI movie support
6c0a2ac382 MTROPOLIS: Add hacks to handle several animations that are supposed to stay on-screen even though they've been removed


Commit: 80a75d723602cc6c1946d5b0605cdb34e58fa2ab
    https://github.com/scummvm/scummvm/commit/80a75d723602cc6c1946d5b0605cdb34e58fa2ab
Author: elasota (ejlasota at gmail.com)
Date: 2023-06-13T23:48:10-04:00

Commit Message:
MTROPOLIS: Add AVI movie support

Changed paths:
    engines/mtropolis/asset_factory.cpp
    engines/mtropolis/assets.cpp
    engines/mtropolis/assets.h
    engines/mtropolis/data.cpp
    engines/mtropolis/data.h
    engines/mtropolis/element_factory.cpp
    engines/mtropolis/elements.cpp
    engines/mtropolis/runtime.h


diff --git a/engines/mtropolis/asset_factory.cpp b/engines/mtropolis/asset_factory.cpp
index 7b0071bb410..ac61e23da58 100644
--- a/engines/mtropolis/asset_factory.cpp
+++ b/engines/mtropolis/asset_factory.cpp
@@ -65,6 +65,8 @@ SIAssetFactory *getAssetFactoryForDataObjectType(const Data::DataObjectTypes::Da
 		return AssetFactory<AudioAsset, Data::AudioAsset>::getInstance();
 	case Data::DataObjectTypes::kMovieAsset:
 		return AssetFactory<MovieAsset, Data::MovieAsset>::getInstance();
+	case Data::DataObjectTypes::kAVIMovieAsset:
+		return AssetFactory<AVIMovieAsset, Data::AVIMovieAsset>::getInstance();
 	case Data::DataObjectTypes::kImageAsset:
 		return AssetFactory<ImageAsset, Data::ImageAsset>::getInstance();
 	case Data::DataObjectTypes::kMToonAsset:
diff --git a/engines/mtropolis/assets.cpp b/engines/mtropolis/assets.cpp
index 896c57bd2c1..eb0e8bf3d57 100644
--- a/engines/mtropolis/assets.cpp
+++ b/engines/mtropolis/assets.cpp
@@ -802,6 +802,21 @@ void MovieAsset::addDamagedFrame(int frame) {
 	_damagedFrames.push_back(frame);
 }
 
+bool AVIMovieAsset::load(AssetLoaderContext &context, const Data::AVIMovieAsset &data) {
+	_assetID = data.assetID;
+	_extFileName = data.extFileName;
+
+	return true;
+}
+
+AssetType AVIMovieAsset::getAssetType() const {
+	return kAssetTypeAVIMovie;
+}
+
+const Common::String &AVIMovieAsset::getExtFileName() const {
+	return _extFileName;
+}
+
 const Common::Array<int> &MovieAsset::getDamagedFrames() const {
 	return _damagedFrames;
 }
diff --git a/engines/mtropolis/assets.h b/engines/mtropolis/assets.h
index a18b0f0f27d..f440199c2f2 100644
--- a/engines/mtropolis/assets.h
+++ b/engines/mtropolis/assets.h
@@ -230,6 +230,17 @@ private:
 	Common::Array<int> _damagedFrames;
 };
 
+class AVIMovieAsset : public Asset {
+public:
+	bool load(AssetLoaderContext &context, const Data::AVIMovieAsset &data);
+	AssetType getAssetType() const override;
+
+	const Common::String &getExtFileName() const;
+
+private:
+	Common::String _extFileName;
+};
+
 class CachedImage {
 public:
 	CachedImage();
diff --git a/engines/mtropolis/data.cpp b/engines/mtropolis/data.cpp
index 64bf22ccda5..72db1a11257 100644
--- a/engines/mtropolis/data.cpp
+++ b/engines/mtropolis/data.cpp
@@ -33,6 +33,7 @@ namespace DataObjectTypes {
 bool isValidSceneRootElement(DataObjectType type) {
 	switch (type) {
 	case kGraphicElement:
+	case kAVIMovieElement:
 	case kMovieElement:
 	case kMToonElement:
 	case kImageElement:
@@ -45,6 +46,7 @@ bool isValidSceneRootElement(DataObjectType type) {
 bool isVisualElement(DataObjectType type) {
 	switch (type) {
 	case kGraphicElement:
+	case kAVIMovieElement:
 	case kMovieElement:
 	case kMToonElement:
 	case kImageElement:
@@ -67,6 +69,7 @@ bool isNonVisualElement(DataObjectType type) {
 bool isElement(DataObjectType type) {
 	switch (type) {
 	case kGraphicElement:
+	case kAVIMovieElement:
 	case kMovieElement:
 	case kMToonElement:
 	case kImageElement:
@@ -140,6 +143,7 @@ bool isModifier(DataObjectType type) {
 bool isAsset(DataObjectType type) {
 	switch (type) {
 	case kMovieAsset:
+	case kAVIMovieAsset:
 	case kAudioAsset:
 	case kColorTableAsset:
 	case kImageAsset:
@@ -950,11 +954,11 @@ DataReadErrorCode SoundElement::load(DataReader& reader) {
 	return kDataReadErrorNone;
 }
 
-MovieElement::MovieElement()
+MovieElement::MovieElement(bool avi)
 	: sizeIncludingTag(0), guid(0), lengthOfName(0), elementFlags(0), layer(0),
 	  unknown3{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
 	  sectionID(0), unknown5{0, 0}, assetID(0), unknown7(0), volume(0), animationFlags(0),
-	  unknown10{0, 0, 0, 0}, unknown11{0, 0, 0, 0}, streamLocator(0), unknown13{0, 0, 0, 0} {
+	  unknown10{0, 0, 0, 0}, unknown11{0, 0, 0, 0}, streamLocator(0), unknown13{0, 0, 0, 0}, isAVI(avi) {
 }
 
 DataReadErrorCode MovieElement::load(DataReader &reader) {
@@ -2078,6 +2082,25 @@ DataReadErrorCode MovieAsset::load(DataReader &reader) {
 	return kDataReadErrorNone;
 }
 
+AVIMovieAsset::AVIMovieAsset() : unknown1{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, assetID(0), unknown2{0, 0, 0, 0},
+								 extFileNameLength(0) {
+	for (uint8 &v : unknown3)
+		v = 0;
+}
+
+DataReadErrorCode AVIMovieAsset::load(DataReader &reader) {
+	if (_revision != 0)
+		return kDataReadErrorUnsupportedRevision;
+
+	if (!reader.readBytes(unknown1) || !reader.readU32(assetID) || !reader.readBytes(unknown2) || !reader.readU16(extFileNameLength) || !reader.readBytes(unknown3))
+		return kDataReadErrorReadFailed;
+
+	if (!reader.readTerminatedStr(extFileName, extFileNameLength))
+		return kDataReadErrorReadFailed;
+
+	return kDataReadErrorNone;
+}
+
 AudioAsset::AudioAsset()
 	: persistFlags(0), assetAndDataCombinedSize(0), unknown2{0, 0, 0, 0}, assetID(0),
 	  unknown3{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, sampleRate1(0), bitsPerSample(0),
@@ -2421,7 +2444,10 @@ DataReadErrorCode loadDataObject(const PlugInModifierRegistry &registry, DataRea
 		dataObject = new GraphicElement();
 		break;
 	case DataObjectTypes::kMovieElement:
-		dataObject = new MovieElement();
+		dataObject = new MovieElement(false);
+		break;
+	case DataObjectTypes::kAVIMovieElement:
+		dataObject = new MovieElement(true);
 		break;
 	case DataObjectTypes::kMToonElement:
 		dataObject = new MToonElement();
@@ -2561,6 +2587,10 @@ DataReadErrorCode loadDataObject(const PlugInModifierRegistry &registry, DataRea
 		dataObject = new ColorTableAsset();
 		break;
 
+	case DataObjectTypes::kAVIMovieAsset:
+		dataObject = new AVIMovieAsset();
+		break;
+
 	case DataObjectTypes::kMovieAsset:
 		dataObject = new MovieAsset();
 		break;
diff --git a/engines/mtropolis/data.h b/engines/mtropolis/data.h
index 05a0431607b..a678bdb3649 100644
--- a/engines/mtropolis/data.h
+++ b/engines/mtropolis/data.h
@@ -100,6 +100,7 @@ enum DataObjectType : uint {
 	kSoundElement							= 0xa,
 	kTextLabelElement						= 0x15,
 
+	kAVIMovieElement						= 0x25,
 	kAliasModifier							= 0x27,
 	kChangeSceneModifier					= 0x136,
 	kReturnModifier							= 0x140,
@@ -148,6 +149,7 @@ enum DataObjectType : uint {
 	kImageAsset								= 0xe,
 	kMToonAsset								= 0xf,
 	kTextAsset								= 0x1f,
+	kAVIMovieAsset							= 0x24,
 
 	kAssetDataChunk							= 0xffff,
 };
@@ -752,7 +754,7 @@ protected:
 };
 
 struct MovieElement : public StructuralDef {
-	MovieElement();
+	explicit MovieElement(bool avi);
 
 	// Possible flags: NotDirectToScreen, CacheBitmap, Hidden, Loop, Loop + Alternate, Paused
 	uint32 sizeIncludingTag;
@@ -776,6 +778,8 @@ struct MovieElement : public StructuralDef {
 
 	Common::String name;
 
+	bool isAVI;
+
 protected:
 	DataReadErrorCode load(DataReader &reader) override;
 };
@@ -1851,6 +1855,21 @@ protected:
 	DataReadErrorCode load(DataReader &reader) override;
 };
 
+struct AVIMovieAsset : public DataObject {
+	AVIMovieAsset();
+
+	uint8 unknown1[12];
+	uint32 assetID;
+	uint8 unknown2[4];
+	uint16 extFileNameLength;
+	uint8 unknown3[60];
+
+	Common::String extFileName;
+
+protected:
+	DataReadErrorCode load(DataReader &reader) override;
+};
+
 struct AudioAsset : public DataObject {
 	struct MacPart {
 		uint8 unknown4[4];
diff --git a/engines/mtropolis/element_factory.cpp b/engines/mtropolis/element_factory.cpp
index 5692ca60f0e..09341b9e593 100644
--- a/engines/mtropolis/element_factory.cpp
+++ b/engines/mtropolis/element_factory.cpp
@@ -64,6 +64,7 @@ SIElementFactory *getElementFactoryForDataObjectType(const Data::DataObjectTypes
 	switch (dataObjectType) {
 	case Data::DataObjectTypes::kGraphicElement:
 		return ElementFactory<GraphicElement, Data::GraphicElement>::getInstance();
+	case Data::DataObjectTypes::kAVIMovieElement:
 	case Data::DataObjectTypes::kMovieElement:
 		return ElementFactory<MovieElement, Data::MovieElement>::getInstance();
 	case Data::DataObjectTypes::kImageElement:
diff --git a/engines/mtropolis/elements.cpp b/engines/mtropolis/elements.cpp
index 89b9f947444..5006b4f6cfe 100644
--- a/engines/mtropolis/elements.cpp
+++ b/engines/mtropolis/elements.cpp
@@ -21,7 +21,9 @@
 
 #include "video/video_decoder.h"
 #include "video/qt_decoder.h"
+#include "video/avi_decoder.h"
 
+#include "common/file.h"
 #include "common/substream.h"
 
 #include "graphics/macgui/macfontmanager.h"
@@ -618,42 +620,67 @@ void MovieElement::activate() {
 		return;
 	}
 
-	if (asset->getAssetType() != kAssetTypeMovie) {
-		warning("Movie element assigned an asset that isn't a movie");
-		return;
-	}
+	if (asset->getAssetType() == kAssetTypeMovie) {
+		MovieAsset *movieAsset = static_cast<MovieAsset *>(asset.get());
+		size_t streamIndex = movieAsset->getStreamIndex();
+		int segmentIndex = project->getSegmentForStreamIndex(streamIndex);
+		project->openSegmentStream(segmentIndex);
+		Common::SeekableReadStream *stream = project->getStreamForSegment(segmentIndex);
 
-	MovieAsset *movieAsset = static_cast<MovieAsset *>(asset.get());
-	size_t streamIndex = movieAsset->getStreamIndex();
-	int segmentIndex = project->getSegmentForStreamIndex(streamIndex);
-	project->openSegmentStream(segmentIndex);
-	Common::SeekableReadStream *stream = project->getStreamForSegment(segmentIndex);
+		if (!stream) {
+			warning("Movie element stream could not be opened");
+			return;
+		}
 
-	if (!stream) {
-		warning("Movie element stream could not be opened");
-		return;
-	}
+		Video::QuickTimeDecoder *qtDecoder = new Video::QuickTimeDecoder();
+		qtDecoder->setChunkBeginOffset(movieAsset->getMovieDataPos());
+		qtDecoder->setVolume(_volume * 255 / 100);
+
+		_videoDecoder.reset(qtDecoder);
+		_damagedFrames = movieAsset->getDamagedFrames();
+
+		Common::SafeSeekableSubReadStream *movieDataStream = new Common::SafeSeekableSubReadStream(stream, movieAsset->getMovieDataPos(), movieAsset->getMovieDataPos() + movieAsset->getMovieDataSize(), DisposeAfterUse::NO);
+
+		if (!_videoDecoder->loadStream(movieDataStream))
+			_videoDecoder.reset();
+		else {
+			if (getRuntime()->getHacks().removeQuickTimeEdits)
+				qtDecoder->flattenEditLists();
+
+			_timeScale = qtDecoder->getTimeScale();
 
-	Video::QuickTimeDecoder *qtDecoder = new Video::QuickTimeDecoder();
-	qtDecoder->setChunkBeginOffset(movieAsset->getMovieDataPos());
-	qtDecoder->setVolume(_volume * 255 / 100);
+			_maxTimestamp = qtDecoder->getDuration().convertToFramerate(qtDecoder->getTimeScale()).totalNumberOfFrames();
+		}
 
-	_videoDecoder.reset(qtDecoder);
-	_damagedFrames = movieAsset->getDamagedFrames();
+		_unloadSignaller = project->notifyOnSegmentUnload(segmentIndex, this);
+	} else if (asset->getAssetType() == kAssetTypeAVIMovie) {
+		AVIMovieAsset *aviAsset = static_cast<AVIMovieAsset *>(asset.get());
 
-	Common::SafeSeekableSubReadStream *movieDataStream = new Common::SafeSeekableSubReadStream(stream, movieAsset->getMovieDataPos(), movieAsset->getMovieDataPos() + movieAsset->getMovieDataSize(), DisposeAfterUse::NO);
+		Common::File *f = new Common::File();
+		if (!f->open(Common::Path(Common::String("VIDEO/") + aviAsset->getExtFileName()))) {
+			warning("Movie asset could not be opened");
+			delete f;
+			return;
+		}
 
-	if (!_videoDecoder->loadStream(movieDataStream))
-		_videoDecoder.reset();
+		Video::AVIDecoder *aviDec = new Video::AVIDecoder();
+		aviDec->setVolume(_volume * 255 / 100);
 
-	if (getRuntime()->getHacks().removeQuickTimeEdits)
-		qtDecoder->flattenEditLists();
-	_timeScale = qtDecoder->getTimeScale();
+		_videoDecoder.reset(aviDec);
+
+		if (!_videoDecoder->loadStream(f))
+			_videoDecoder.reset();
+		else {
+			_timeScale = 1000;
+			_maxTimestamp = aviDec->getDuration().convertToFramerate(1000).totalNumberOfFrames();
+		}
+	} else {
+		warning("Movie element referenced a non-movie asset");
+		return;
+	}
 
-	_unloadSignaller = project->notifyOnSegmentUnload(segmentIndex, this);
 	_playMediaSignaller = project->notifyOnPlayMedia(this);
 
-	_maxTimestamp = qtDecoder->getDuration().convertToFramerate(qtDecoder->getTimeScale()).totalNumberOfFrames();
 	_playRange = IntRange(0, 0);
 	_currentTimestamp = 0;
 
@@ -704,6 +731,9 @@ void MovieElement::queueAutoPlayEvents(Runtime *runtime, bool isAutoPlaying) {
 void MovieElement::render(Window *window) {
 	const IntRange realRange = computeRealRange();
 
+	if (!_videoDecoder)
+		return;
+
 	if (_needsReset) {
 		_videoDecoder->setReverse(_reversed);
 		_videoDecoder->seek(Audio::Timestamp(0, _timeScale).addFrames(_currentTimestamp));
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index f391877b957..f8fcd07d5e4 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -3040,6 +3040,7 @@ enum AssetType {
 	kAssetTypeImage,
 	kAssetTypeText,
 	kAssetTypeMToon,
+	kAssetTypeAVIMovie,
 };
 
 class AssetHooks {


Commit: 6c0a2ac38230412f813d9bdf9b6c92ce48635e75
    https://github.com/scummvm/scummvm/commit/6c0a2ac38230412f813d9bdf9b6c92ce48635e75
Author: elasota (ejlasota at gmail.com)
Date: 2023-06-13T23:48:10-04:00

Commit Message:
MTROPOLIS: Add hacks to handle several animations that are supposed to stay on-screen even though they've been removed

Changed paths:
    engines/mtropolis/elements.cpp
    engines/mtropolis/hacks.cpp
    engines/mtropolis/runtime.cpp
    engines/mtropolis/runtime.h


diff --git a/engines/mtropolis/elements.cpp b/engines/mtropolis/elements.cpp
index 5006b4f6cfe..b8e90754651 100644
--- a/engines/mtropolis/elements.cpp
+++ b/engines/mtropolis/elements.cpp
@@ -1583,6 +1583,9 @@ VThreadState MToonElement::stopPlayingTask(const StopPlayingTaskData &taskData)
 		taskData.runtime->sendMessageOnVThread(dispatch);
 	}
 
+	if (_hooks)
+		_hooks->onStopPlayingMToon(this, _visible, _isStopped);
+
 	return kVThreadReturn;
 }
 
diff --git a/engines/mtropolis/hacks.cpp b/engines/mtropolis/hacks.cpp
index e8e88e74fe4..382351f7f29 100644
--- a/engines/mtropolis/hacks.cpp
+++ b/engines/mtropolis/hacks.cpp
@@ -89,10 +89,10 @@ void ObsidianCorruptedAirTowerTransitionFix::onLoaded(Asset *asset, const Common
 
 class ObsidianInventoryWindscreenHooks : public StructuralHooks {
 public:
-	void onSetPosition(Runtime *runtime, Structural *structural, Common::Point &pt) override;
+	void onSetPosition(Runtime *runtime, Structural *structural, const Common::Point &oldPt, Common::Point &pt) override;
 };
 
-void ObsidianInventoryWindscreenHooks::onSetPosition(Runtime *runtime, Structural *structural, Common::Point &pt) {
+void ObsidianInventoryWindscreenHooks::onSetPosition(Runtime *runtime, Structural *structural, const Common::Point &oldPt, Common::Point &pt) {
 	if (pt.y < 480) {
 		// Set direct to screen so it draws over cinematics
 		static_cast<VisualElement *>(structural)->setDirectToScreen(true);
@@ -104,13 +104,13 @@ void ObsidianInventoryWindscreenHooks::onSetPosition(Runtime *runtime, Structura
 
 class ObsidianSecurityFormWidescreenHooks : public StructuralHooks {
 public:
-	void onSetPosition(Runtime *runtime, Structural *structural, Common::Point &pt) override;
+	void onSetPosition(Runtime *runtime, Structural *structural, const Common::Point &oldPt, Common::Point &pt) override;
 
 private:
 	Common::Array<uint32> _hiddenCards;
 };
 
-void ObsidianSecurityFormWidescreenHooks::onSetPosition(Runtime *runtime, Structural *structural, Common::Point &pt) {
+void ObsidianSecurityFormWidescreenHooks::onSetPosition(Runtime *runtime, Structural *structural, const Common::Point &oldPt, Common::Point &pt) {
 	bool cardVisibility = (pt.y > 480);
 
 	// Originally tried manipulating layer order but that's actually not a good solution because
@@ -1023,16 +1023,51 @@ void addObsidianSaveMechanism(const MTropolisGameDescription &desc, Hacks &hacks
 	hacks.addSaveLoadMechanismHooks(mechanism);
 }
 
+class MTIBuggyAnimationHooks : public StructuralHooks {
+public:
+	void onSetPosition(Runtime *runtime, Structural *structural, const Common::Point &oldPt, Common::Point &pt) override;
+	void onStopPlayingMToon(Structural *structural, bool &hide, bool &stopped) override;
+	void onHidden(Structural *structural, bool &visible) override;
+};
+
+void MTIBuggyAnimationHooks::onSetPosition(Runtime *runtime, Structural *structural, const Common::Point &oldPt, Common::Point &pt) {
+	// Cancel out off-screen translation
+	if (pt.x < 0)
+		pt = oldPt;
+}
+
+void MTIBuggyAnimationHooks::onStopPlayingMToon(Structural *structural, bool &visible, bool &stopped) {
+	// Un-stop
+	visible = true;
+	stopped = false;
+}
+
+void MTIBuggyAnimationHooks::onHidden(Structural *structural, bool &visible) {
+	// Un-hide
+	visible = true;
+}
+
 class MTIStructuralHooks : public StructuralHooks {
 public:
 	void onPostActivate(Structural *structural) override;
 };
 
 void MTIStructuralHooks::onPostActivate(Structural *structural) {
-	if (structural->getName() == "D15_0003.tun") {
+	const Common::String &name = structural->getName();
+
+	if (name == "D15_0003.tun") {
 		// Fix for intro not playing in Piggy's secret room.  D15_0003.tun is on layer 7 but treasure layers are on top of it.
 		if (structural->isElement() && static_cast<Element *>(structural)->isVisual())
 			static_cast<VisualElement *>(structural)->setLayer(20);
+	} else if (name == "C01c0005.tun" || name == "C01c0005a.tun" || name == "A06_Xspot.tun" || name == "A08agp01.tun") {
+		// Several animations stop (which hides) and are moved off-screen when they stop, yet for some reason are supposed to
+		// continue to draw.
+		//
+		// Known cases:
+		// - Treasure map in Benbow (A06_Xspot.tun)
+		// - Molasses when leaving Benbow (A08agp01.tun)
+		// - Long John Silver in the life boat when disembarking the Hispaniola (C01c0005.tun and C01c0005a.tun)
+		structural->setHooks(Common::SharedPtr<StructuralHooks>(new MTIBuggyAnimationHooks()));
 	}
 }
 
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index 1d4acb78890..371f612cca4 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -2979,7 +2979,13 @@ void StructuralHooks::onCreate(Structural *structural) {
 void StructuralHooks::onPostActivate(Structural *structural) {
 }
 
-void StructuralHooks::onSetPosition(Runtime *runtime, Structural *structural, Common::Point &pt) {
+void StructuralHooks::onSetPosition(Runtime *runtime, Structural *structural, const Common::Point &oldPt, Common::Point &pt) {
+}
+
+void StructuralHooks::onStopPlayingMToon(Structural *structural, bool &visible, bool &stopped) {
+}
+
+void StructuralHooks::onHidden(Structural *structural, bool &visible) {
 }
 
 ProjectPresentationSettings::ProjectPresentationSettings() : width(640), height(480), bitsPerPixel(8) {
@@ -8121,6 +8127,10 @@ VThreadState VisualElement::consumeCommand(Runtime *runtime, const Common::Share
 	if (Event(EventIDs::kElementHide, 0).respondsTo(msg->getEvent())) {
 		if (_visible) {
 			_visible = false;
+
+			if (_hooks)
+				_hooks->onHidden(this, _visible);
+
 			runtime->setSceneGraphDirty();
 		}
 
@@ -8559,7 +8569,7 @@ MiniscriptInstructionOutcome VisualElement::scriptSetPosition(MiniscriptThread *
 		Common::Point destPoint = value.getPoint();
 
 		if (_hooks)
-			_hooks->onSetPosition(thread->getRuntime(), this, destPoint);
+			_hooks->onSetPosition(thread->getRuntime(), this, Common::Point(_rect.left, _rect.top), destPoint);
 
 		int32 xDelta = destPoint.x - _rect.left;
 		int32 yDelta = destPoint.y - _rect.top;
@@ -8582,7 +8592,7 @@ MiniscriptInstructionOutcome VisualElement::scriptSetPositionX(MiniscriptThread
 
 	Common::Point updatedPoint = Common::Point(asInteger, _rect.top);
 	if (_hooks)
-		_hooks->onSetPosition(thread->getRuntime(), this, updatedPoint);
+		_hooks->onSetPosition(thread->getRuntime(), this, Common::Point(_rect.left, _rect.top), updatedPoint);
 	int32 xDelta = updatedPoint.x - _rect.left;
 	int32 yDelta = updatedPoint.y - _rect.top;
 
@@ -8599,7 +8609,7 @@ MiniscriptInstructionOutcome VisualElement::scriptSetPositionY(MiniscriptThread
 
 	Common::Point updatedPoint = Common::Point(_rect.left, asInteger);
 	if (_hooks)
-		_hooks->onSetPosition(thread->getRuntime(), this, updatedPoint);
+		_hooks->onSetPosition(thread->getRuntime(), this, Common::Point(_rect.left, _rect.top), updatedPoint);
 
 	int32 xDelta = updatedPoint.x - _rect.left;
 	int32 yDelta = updatedPoint.y - _rect.top;
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index f8fcd07d5e4..32117380a6a 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -2127,7 +2127,9 @@ public:
 
 	virtual void onCreate(Structural *structural);
 	virtual void onPostActivate(Structural *structural);
-	virtual void onSetPosition(Runtime *runtime, Structural *structural, Common::Point &pt);
+	virtual void onSetPosition(Runtime *runtime, Structural *structural, const Common::Point &oldPt, Common::Point &pt);
+	virtual void onStopPlayingMToon(Structural *structural, bool &visible, bool &stopped);
+	virtual void onHidden(Structural *structural, bool &visible);
 };
 
 class Structural : public RuntimeObject, public IModifierContainer, public IMessageConsumer, public Debuggable {




More information about the Scummvm-git-logs mailing list