[Scummvm-git-logs] scummvm master -> 9628db9f8a710e6b18c24d483ba0c46e222e3f7e

elasota noreply at scummvm.org
Sun Jun 26 07:49:04 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:
738fe5311c MTROPOLIS: Don't fire events from hidden mToons
9628db9f8a MTROPOLIS: Obsidian widescreen enhancement


Commit: 738fe5311c0bb830bb1002eee624d73d3f6a5487
    https://github.com/scummvm/scummvm/commit/738fe5311c0bb830bb1002eee624d73d3f6a5487
Author: elasota (ejlasota at gmail.com)
Date: 2022-06-26T03:48:33-04:00

Commit Message:
MTROPOLIS: Don't fire events from hidden mToons

Changed paths:
    engines/mtropolis/elements.cpp


diff --git a/engines/mtropolis/elements.cpp b/engines/mtropolis/elements.cpp
index 79e10f50a0a..e7f5fb0e58f 100644
--- a/engines/mtropolis/elements.cpp
+++ b/engines/mtropolis/elements.cpp
@@ -1387,6 +1387,15 @@ void MToonElement::playMedia(Runtime *runtime, Project *project) {
 	if (_paused)
 		return;
 
+	// TODO: This is semi-accurate: mTropolis Player will advance mToon time while
+	// the element is hidden and can then fire a barrage of frame advances and events
+	// if it's revealed again.  However, we're not fully handling that here yet,
+	// and we actually miss events if frame advance overruns the last cel, which can
+	// cause problems sometimes (e.g. lag in the Spider air puzzle in Obsidian when
+	// the board is revealed)
+	if (!_visible)
+		return;
+
 	int32 minCel = _playRange.min;
 	int32 maxCel = _playRange.max;
 	int32 sanitizeMaxCel = _metadata->frames.size();
@@ -1421,6 +1430,7 @@ void MToonElement::playMedia(Runtime *runtime, Project *project) {
 		// which case the timing of "at last cel"/"at first cel" triggers based on where the timer would be
 		// in the invalid range, so mTropolis Player apparently keeps a play cel independent of the actual
 		// cel?
+
 		bool ranPastEnd = false;
 
 		size_t framesRemainingToOnePastEnd = isReversed ? (_cel - minCel + 1) : (maxCel + 1 - _cel);


Commit: 9628db9f8a710e6b18c24d483ba0c46e222e3f7e
    https://github.com/scummvm/scummvm/commit/9628db9f8a710e6b18c24d483ba0c46e222e3f7e
Author: elasota (ejlasota at gmail.com)
Date: 2022-06-26T03:48:33-04:00

Commit Message:
MTROPOLIS: Obsidian widescreen enhancement

Changed paths:
    engines/mtropolis/detection.cpp
    engines/mtropolis/hacks.cpp
    engines/mtropolis/hacks.h
    engines/mtropolis/mtropolis.cpp
    engines/mtropolis/plugin/standard.cpp
    engines/mtropolis/runtime.cpp
    engines/mtropolis/runtime.h


diff --git a/engines/mtropolis/detection.cpp b/engines/mtropolis/detection.cpp
index cc00b0040bb..632e52a39cc 100644
--- a/engines/mtropolis/detection.cpp
+++ b/engines/mtropolis/detection.cpp
@@ -66,6 +66,28 @@ public:
 const ExtraGuiOptions MTropolisMetaEngineDetection::getExtraGuiOptions(const Common::String &target) const {
 	ExtraGuiOptions options;
 
+	Common::String gameid = ConfMan.get("gameid", target);
+
+	if (gameid == "obsidian") {
+		static const ExtraGuiOption widescreenOption = {
+			_s("Widescreen"),
+			_s("Removes upper letterbox bar"),
+			"mtropolis_enh_obsidian_widescreen",
+			false,
+			0,
+			1};
+		static const ExtraGuiOption widescreenImprovedOption = {
+			_s("Enhanced Widescreen"),
+			_s("Removes the upper and lower letterbox bars and relocates inventory item graphics"),
+			"mtropolis_enh_obsidian_widescreen_improved",
+			false,
+			1,
+			0};
+
+		options.push_back(widescreenOption);
+		options.push_back(widescreenImprovedOption);
+	}
+
 	static const ExtraGuiOption launchDebugOption = {
 		_s("Start with debugger"),
 		_s("Starts with the debugger dashboard active"),
diff --git a/engines/mtropolis/hacks.cpp b/engines/mtropolis/hacks.cpp
index b0ce41c4ebc..8acf3bb5172 100644
--- a/engines/mtropolis/hacks.cpp
+++ b/engines/mtropolis/hacks.cpp
@@ -21,7 +21,9 @@
 
 #include "common/system.h"
 
+#include "mtropolis/detection.h"
 #include "mtropolis/hacks.h"
+#include "mtropolis/runtime.h"
 
 namespace MTropolis {
 
@@ -29,4 +31,114 @@ Hacks::Hacks() {
 	memset(this, 0, sizeof(*this));
 }
 
+Hacks::~Hacks() {
+	if (structuralHooks)
+		delete structuralHooks;
+	if (modifierHooks)
+		delete modifierHooks;
+}
+
+void Hacks::addStructuralHooks(uint32 guid, const Common::SharedPtr<StructuralHooks> &hooks) {
+	if (!structuralHooks)
+		structuralHooks = new Common::HashMap<uint32, Common::SharedPtr<StructuralHooks> >();
+	(*structuralHooks)[guid] = hooks;
+}
+
+void Hacks::addModifierHooks(uint32 guid, const Common::SharedPtr<ModifierHooks> &hooks) {
+	if (!modifierHooks)
+		modifierHooks = new Common::HashMap<uint32, Common::SharedPtr<ModifierHooks> >();
+	(*modifierHooks)[guid] = hooks;
+}
+
+
+namespace HackSuites {
+
+class ObsidianInventoryWindscreenHooks : public StructuralHooks {
+public:
+	void onSetPosition(Structural *structural, Common::Point &pt) override;
+};
+
+void ObsidianInventoryWindscreenHooks::onSetPosition(Structural *structural, Common::Point &pt) {
+	if (pt.y < 480) {
+		// Set direct to screen so it draws over cinematics
+		static_cast<VisualElement *>(structural)->setDirectToScreen(true);
+
+		// Move in-bounds
+		pt.y -= 60;
+	}
+}
+
+void addObsidianImprovedWidescreen(const MTropolisGameDescription &desc, Hacks &hacks) {
+	if ((desc.desc.flags & ADGF_DEMO) == 0 && desc.desc.language == Common::EN_ANY && desc.desc.platform == Common::kPlatformWindows) {
+		const uint32 inventoryItemGUIDs[] = {
+			// Bureau documents
+			// 100 area (booths)
+			0x4e2d9e,
+			0x4de654,
+
+			// 199 area (booths hint room)
+			0x4e2555,
+			0x4de654,
+
+			// 200 area (library)
+			0x4c83d2,
+			0x4c5802,
+
+			// 299 area (Cloud Ring)
+			0x178d5c,
+			0x178d5c,
+
+			// 300 area (light+phone)
+			0x4e0f86,
+			0x4e5107,
+
+			// 400 area (maze)
+			0x4e5528,
+			0x4e55cc,
+
+			// 500 area (Immediate Action)
+			0x4e2e7b,
+			0x4e0710,
+
+			// 800 area (bookshelves)
+			0x9914fb,
+			0x990f1f,
+
+			// 600 (sky face), 699 (mountain), and 700 (finale) have no document elements (player loses the documents)
+
+			// Bureau maze keycards
+			0x6035f,
+			0x62e24,
+			0x58d7f,
+			0x58212,
+
+			// Spider metal puzzle beaker
+			0x12fa7,
+
+			// Inspiration chip
+			// 100 area (Junkyard)
+			0x5f02e6,
+
+			// 200 area (Plane)
+			0x9bd5fc,
+
+			// 300 area (Piazza)
+			0x5ef979,
+			
+			// 400 area (Church)
+			0xed9a8f,
+
+			// 500 area (Statue)
+			0x5ecdee,
+		};
+
+		Common::SharedPtr<StructuralHooks> invItemHooks(new ObsidianInventoryWindscreenHooks());
+
+		for (uint32 guid : inventoryItemGUIDs)
+			hacks.addStructuralHooks(guid, invItemHooks);
+	}
+}
+
+} // End of namespace HackSuites
+
 } // End of namespace MTropolis
diff --git a/engines/mtropolis/hacks.h b/engines/mtropolis/hacks.h
index 8f67a0e68ba..ffe990a081f 100644
--- a/engines/mtropolis/hacks.h
+++ b/engines/mtropolis/hacks.h
@@ -19,10 +19,25 @@
  *
  */
 
+#ifndef MTROPOLIS_HACKS_H
+#define MTROPOLIS_HACKS_H
+
+#include "common/rect.h"
+#include "common/ptr.h"
+#include "common/hashmap.h"
+
 namespace MTropolis {
 
+class StructuralHooks;
+class ModifierHooks;
+struct MTropolisGameDescription;
+
 struct Hacks {
 	Hacks();
+	~Hacks();
+
+	void addStructuralHooks(uint32 guid, const Common::SharedPtr<StructuralHooks> &hooks);
+	void addModifierHooks(uint32 guid, const Common::SharedPtr<ModifierHooks> &hooks);
 
 	// Workaround for bug in Obsidian:
 	// When opening the journal in the intro, a script checks if cGSt.cfst.binjournal is false and if so,
@@ -34,6 +49,20 @@ struct Hacks {
 	// cJournalConst is unloaded if the player leaves the journal.  This causes a progression blocker if
 	// the player leaves the journal without clicking Continue.
 	bool ignoreMismatchedProjectNameInObjectLookups;
+
+	Common::Point reportDisplaySize;	// If X or Y is non-zero, report this as the display size
+	Common::Point mainWindowOffset;		// Coordinate offset of the main window
+
+	Common::HashMap<uint32, Common::SharedPtr<StructuralHooks> > *structuralHooks;
+	Common::HashMap<uint32, Common::SharedPtr<ModifierHooks> > *modifierHooks;
 };
 
+namespace HackSuites {
+
+void addObsidianImprovedWidescreen(const MTropolisGameDescription &desc, Hacks &hacks);
+
+} // End of namespace HackSuites
+
 } // End of namespace MTropolis
+
+#endif
diff --git a/engines/mtropolis/mtropolis.cpp b/engines/mtropolis/mtropolis.cpp
index 5c50359bf4a..abd87498113 100644
--- a/engines/mtropolis/mtropolis.cpp
+++ b/engines/mtropolis/mtropolis.cpp
@@ -105,6 +105,7 @@ void MTropolisEngine::handleEvents() {
 Common::Error MTropolisEngine::run() {
 	int preferredWidth = 1024;
 	int preferredHeight = 768;
+
 	ColorDepthMode preferredColorDepthMode = kColorDepthMode8Bit;
 	ColorDepthMode enhancedColorDepthMode = kColorDepthMode8Bit;
 
@@ -119,6 +120,21 @@ Common::Error MTropolisEngine::run() {
 		enhancedColorDepthMode = kColorDepthMode32Bit;
 
 		_runtime->getHacks().ignoreMismatchedProjectNameInObjectLookups = true;
+
+		if (ConfMan.getBool("mtropolis_enh_obsidian_widescreen")) {
+			preferredHeight = 420;
+
+			_runtime->getHacks().mainWindowOffset = Common::Point(0, -30);
+			_runtime->getHacks().reportDisplaySize = Common::Point(640, 480);
+
+			if (ConfMan.getBool("mtropolis_enh_obsidian_widescreen_improved")) {
+				preferredHeight = 360;
+
+				_runtime->getHacks().mainWindowOffset = Common::Point(0, 0);
+
+				HackSuites::addObsidianImprovedWidescreen(*_gameDescription, _runtime->getHacks());
+			}
+		}
 	}
 
 	_runtime->queueProject(projectDesc);
diff --git a/engines/mtropolis/plugin/standard.cpp b/engines/mtropolis/plugin/standard.cpp
index 0121aef592c..3c0d189e3f4 100644
--- a/engines/mtropolis/plugin/standard.cpp
+++ b/engines/mtropolis/plugin/standard.cpp
@@ -1634,7 +1634,15 @@ bool SysInfoModifier::readAttribute(MiniscriptThread *thread, DynamicValue &resu
 		return true;
 	} else if (attrib == "screensize") {
 		uint16 width, height;
+
 		thread->getRuntime()->getDisplayResolution(width, height);
+
+		Common::Point hacksSize = thread->getRuntime()->getHacks().reportDisplaySize;
+		if (hacksSize.x != 0)
+			width = hacksSize.x;
+		if (hacksSize.y != 0)
+			height = hacksSize.y;
+
 		result.setPoint(Common::Point(width, height));
 		return true;
 	}
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index 68318b55b5c..c87ab2c0278 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -2551,13 +2551,30 @@ MiniscriptInstructionOutcome SystemInterface::setVolumeName(MiniscriptThread *th
 	return kMiniscriptInstructionOutcomeContinue;
 }
 
+StructuralHooks::~StructuralHooks() {
+}
+
+void StructuralHooks::onCreate(Structural *structural) {
+}
+
+void StructuralHooks::onSetPosition(Structural *structural, Common::Point &pt) {
+}
+
+ProjectPresentationSettings::ProjectPresentationSettings() : width(640), height(480), bitsPerPixel(8) {
+}
+
 Structural::Structural() : _parent(nullptr), _paused(false), _loop(false) {
 }
 
 Structural::~Structural() {
 }
 
-ProjectPresentationSettings::ProjectPresentationSettings() : width(640), height(480), bitsPerPixel(8) {
+void Structural::setHooks(const Common::SharedPtr<StructuralHooks> &hooks) {
+	_hooks = hooks;
+}
+
+const Common::SharedPtr<StructuralHooks> &Structural::getHooks() const {
+	return _hooks;
 }
 
 bool Structural::isStructural() const {
@@ -5326,6 +5343,10 @@ void Runtime::ensureMainWindowExists() {
 
 		int32 centeredX = (static_cast<int32>(_displayWidth) - static_cast<int32>(presentationSettings.width)) / 2;
 		int32 centeredY = (static_cast<int32>(_displayHeight) - static_cast<int32>(presentationSettings.height)) / 2;
+
+		centeredX += _hacks.mainWindowOffset.x;
+		centeredY += _hacks.mainWindowOffset.y;
+
 		Common::SharedPtr<Window> mainWindow(new MainWindow(WindowParameters(this, centeredX, centeredY, presentationSettings.width, presentationSettings.height, _displayModePixelFormats[_realDisplayMode])));
 		addWindow(mainWindow);
 		_mainWindow.reset(mainWindow);
@@ -6228,6 +6249,16 @@ Common::SharedPtr<Modifier> Project::loadModifierObject(ModifierLoaderContext &l
 	if (!modifier)
 		error("Modifier object failed to load");
 
+	uint32 guid = modifier->getStaticGUID();
+	const Common::HashMap<uint32, Common::SharedPtr<ModifierHooks> > *hooksMap = _runtime->getHacks().modifierHooks;
+	if (hooksMap) {
+		Common::HashMap<uint32, Common::SharedPtr<ModifierHooks> >::const_iterator it = hooksMap->find(guid);
+		if (it != hooksMap->end()) {
+			modifier->setHooks(it->_value);
+			it->_value->onCreate(modifier.get());
+		}
+	}
+
 	return modifier;
 }
 
@@ -6449,6 +6480,16 @@ void Project::loadContextualObject(size_t streamIndex, ChildLoaderStack &stack,
 				ElementLoaderContext elementLoaderContext(_runtime, streamIndex);
 				Common::SharedPtr<Element> element = elementFactory->createElement(elementLoaderContext, dataObject);
 
+				uint32 guid = element->getStaticGUID();
+				const Common::HashMap<uint32, Common::SharedPtr<StructuralHooks> > *hooksMap = _runtime->getHacks().structuralHooks;
+				if (hooksMap) {
+					Common::HashMap<uint32, Common::SharedPtr<StructuralHooks> >::const_iterator it = hooksMap->find(guid);
+					if (it != hooksMap->end()) {
+						element->setHooks(it->_value);
+						it->_value->onCreate(element.get());
+					}
+				}
+
 				container->addChild(element);
 
 				if (structuralDef.structuralFlags & Data::StructuralFlags::kNoMoreSiblings)
@@ -6599,7 +6640,6 @@ bool Element::resolveMediaMarkerLabel(const Label& label, int32 &outResolution)
 	return false;
 }
 
-
 VisualElementRenderProperties::VisualElementRenderProperties()
 	: _inkMode(kInkModeDefault), _shape(kShapeRect), _foreColor(ColorRGB8::create(0, 0, 0)), _backColor(ColorRGB8::create(255, 255, 255)),
 	  _borderColor(ColorRGB8::create(0, 0, 0)), _shadowColor(ColorRGB8::create(0, 0, 0)), _borderSize(0), _shadowSize(0), _isDirty(true) {
@@ -6734,6 +6774,10 @@ bool VisualElement::isDirectToScreen() const {
 	return _directToScreen;
 }
 
+void VisualElement::setDirectToScreen(bool directToScreen) {
+	_directToScreen = directToScreen;
+}
+
 uint16 VisualElement::getLayer() const {
 	return _layer;
 }
@@ -6957,6 +7001,10 @@ const Common::Rect &VisualElement::getRelativeRect() const {
 	return _rect;
 }
 
+void VisualElement::setRelativeRect(const Common::Rect &rect) {
+	_rect = rect;
+}
+
 Common::Point VisualElement::getParentOrigin() const {
 	Common::Point pos = Common::Point(0, 0);
 	if (_parent && _parent->isElement()) {
@@ -7114,6 +7162,10 @@ MiniscriptInstructionOutcome VisualElement::scriptSetDirect(MiniscriptThread *th
 MiniscriptInstructionOutcome VisualElement::scriptSetPosition(MiniscriptThread *thread, const DynamicValue &value) {
 	if (value.getType() == DynamicValueTypes::kPoint) {
 		Common::Point destPoint = value.getPoint().toScummVMPoint();
+
+		if (_hooks)
+			_hooks->onSetPosition(this, destPoint);
+
 		int32 xDelta = destPoint.x - _rect.left;
 		int32 yDelta = destPoint.y - _rect.top;
 
@@ -7133,10 +7185,14 @@ MiniscriptInstructionOutcome VisualElement::scriptSetPositionX(MiniscriptThread
 	if (!dest.roundToInt(asInteger))
 		return kMiniscriptInstructionOutcomeFailed;
 
-	int32 xDelta = asInteger - _rect.left;
+	Common::Point updatedPoint = Common::Point(asInteger, _rect.top);
+	if (_hooks)
+		_hooks->onSetPosition(this, updatedPoint);
+	int32 xDelta = updatedPoint.x - _rect.left;
+	int32 yDelta = updatedPoint.y - _rect.top;
 
-	if (xDelta != 0)
-		offsetTranslate(xDelta, 0, false);
+	if (xDelta != 0 || yDelta != 0)
+		offsetTranslate(xDelta, yDelta, false);
 
 	return kMiniscriptInstructionOutcomeContinue;
 }
@@ -7146,10 +7202,15 @@ MiniscriptInstructionOutcome VisualElement::scriptSetPositionY(MiniscriptThread
 	if (!dest.roundToInt(asInteger))
 		return kMiniscriptInstructionOutcomeFailed;
 
-	int32 yDelta = asInteger - _rect.top;
+	Common::Point updatedPoint = Common::Point(_rect.left, asInteger);
+	if (_hooks)
+		_hooks->onSetPosition(this, updatedPoint);
 
-	if (yDelta != 0)
-		offsetTranslate(0, yDelta, false);
+	int32 xDelta = updatedPoint.x - _rect.left;
+	int32 yDelta = updatedPoint.y - _rect.top;
+
+	if (xDelta != 0 || yDelta != 0)
+		offsetTranslate(xDelta, yDelta, false);
 
 	return kMiniscriptInstructionOutcomeContinue;
 }
@@ -7378,6 +7439,12 @@ bool ModifierSaveLoad::load(Modifier *modifier, Common::ReadStream *stream) {
 	return loadInternal(stream);
 }
 
+ModifierHooks::~ModifierHooks() {
+}
+
+void ModifierHooks::onCreate(Modifier *modifier) {
+}
+
 Modifier::Modifier() : _parent(nullptr) {
 }
 
@@ -7537,6 +7604,14 @@ void Modifier::recursiveCollectObjectsMatchingCriteria(Common::Array<Common::Wea
 	}
 }
 
+void Modifier::setHooks(const Common::SharedPtr<ModifierHooks> &hooks) {
+	_hooks = hooks;
+}
+
+const Common::SharedPtr<ModifierHooks> &Modifier::getHooks() const {
+	return _hooks;
+}
+
 #ifdef MTROPOLIS_DEBUG_ENABLE
 
 SupportStatus Modifier::debugGetSupportStatus() const {
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index 136f7ceef01..2394f0665cd 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -1886,6 +1886,14 @@ private:
 	int _masterVolume;
 };
 
+class StructuralHooks {
+public:
+	virtual ~StructuralHooks();
+
+	virtual void onCreate(Structural *structural);
+	virtual void onSetPosition(Structural *structural, Common::Point &pt);
+};
+
 class Structural : public RuntimeObject, public IModifierContainer, public IMessageConsumer, public Debuggable {
 public:
 	Structural();
@@ -1931,6 +1939,9 @@ public:
 
 	void recursiveCollectObjectsMatchingCriteria(Common::Array<Common::WeakPtr<RuntimeObject> > &results, bool (*evalFunc)(void *userData, RuntimeObject *object), void *userData, bool onlyEnabled);
 
+	void setHooks(const Common::SharedPtr<StructuralHooks> &hooks);
+	const Common::SharedPtr<StructuralHooks> &getHooks() const;
+
 #ifdef MTROPOLIS_DEBUG_ENABLE
 	SupportStatus debugGetSupportStatus() const override;
 	const Common::String &debugGetName() const override;
@@ -1964,6 +1975,8 @@ protected:
 	// "loop" appears to have been made available on everything in 1.2.  Obsidian depends on it
 	// being available for sound indexes to be properly set up.
 	bool _loop;
+
+	Common::SharedPtr<StructuralHooks> _hooks;
 };
 
 struct ProjectPresentationSettings {
@@ -2402,6 +2415,7 @@ public:
 
 	bool isVisible() const;
 	bool isDirectToScreen() const;
+	void setDirectToScreen(bool directToScreen);
 	uint16 getLayer() const;
 
 	bool isMouseInsideDrawableArea(int32 relativeX, int32 relativeY) const;
@@ -2416,6 +2430,8 @@ public:
 	Common::Point getGlobalPosition() const;
 	const Common::Rect &getRelativeRect() const;
 
+	void setRelativeRect(const Common::Rect &rect);
+
 	// The cached absolute origin is from the last time the element was rendered.
 	// Do not rely on it mid-frame.
 	const Common::Point &getCachedAbsoluteOrigin() const;
@@ -2524,6 +2540,13 @@ protected:
 	virtual bool loadInternal(Common::ReadStream *stream) = 0;
 };
 
+class ModifierHooks {
+public:
+	virtual ~ModifierHooks();
+
+	virtual void onCreate(Modifier *modifier);
+};
+
 class Modifier : public RuntimeObject, public IMessageConsumer, public Debuggable {
 public:
 	Modifier();
@@ -2576,6 +2599,9 @@ public:
 
 	Structural *findStructuralOwner() const;
 
+	void setHooks(const Common::SharedPtr<ModifierHooks> &hooks);
+	const Common::SharedPtr<ModifierHooks> &getHooks() const;
+
 #ifdef MTROPOLIS_DEBUG_ENABLE
 	SupportStatus debugGetSupportStatus() const override;
 	const Common::String &debugGetName() const override;
@@ -2592,6 +2618,8 @@ protected:
 	Common::String _name;
 	ModifierFlags _modifierFlags;
 	Common::WeakPtr<RuntimeObject> _parent;
+
+	Common::SharedPtr<ModifierHooks> _hooks;
 };
 
 class VariableModifier : public Modifier {




More information about the Scummvm-git-logs mailing list