[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