[Scummvm-git-logs] scummvm master -> 6e4245b962e973f86dd5715444d0a73e24e03f82
elasota
noreply at scummvm.org
Tue Nov 8 04:19:36 UTC 2022
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
6e4245b962 MTROPOLIS: More accurate variable dereferencing and list behavior. Fix some Obsidian regressions.
Commit: 6e4245b962e973f86dd5715444d0a73e24e03f82
https://github.com/scummvm/scummvm/commit/6e4245b962e973f86dd5715444d0a73e24e03f82
Author: elasota (ejlasota at gmail.com)
Date: 2022-11-07T23:18:03-05:00
Commit Message:
MTROPOLIS: More accurate variable dereferencing and list behavior. Fix some Obsidian regressions.
Changed paths:
engines/mtropolis/assets.cpp
engines/mtropolis/assets.h
engines/mtropolis/elements.cpp
engines/mtropolis/miniscript.cpp
engines/mtropolis/miniscript.h
engines/mtropolis/modifiers.cpp
engines/mtropolis/mtropolis.cpp
engines/mtropolis/mtropolis.h
engines/mtropolis/plugin/obsidian.cpp
engines/mtropolis/plugin/standard.cpp
engines/mtropolis/plugin/standard.h
engines/mtropolis/runtime.cpp
engines/mtropolis/runtime.h
engines/mtropolis/saveload.cpp
diff --git a/engines/mtropolis/assets.cpp b/engines/mtropolis/assets.cpp
index 3dba8f9f0c2..af7ef3b68fe 100644
--- a/engines/mtropolis/assets.cpp
+++ b/engines/mtropolis/assets.cpp
@@ -798,6 +798,10 @@ void CachedImage::resetSurface(ColorDepthMode colorDepth, const Common::SharedPt
_surface = surface;
}
+ColorDepthMode CachedImage::getOriginalColorDepth() const {
+ return _colorDepth;
+}
+
const Common::SharedPtr<Graphics::ManagedSurface> &CachedImage::optimize(Runtime *runtime) {
ColorDepthMode renderDepth = runtime->getRealColorDepth();
const Graphics::PixelFormat &renderFmt = runtime->getRenderPixelFormat();
diff --git a/engines/mtropolis/assets.h b/engines/mtropolis/assets.h
index 4b9326e7aa4..fa2ccc16890 100644
--- a/engines/mtropolis/assets.h
+++ b/engines/mtropolis/assets.h
@@ -236,6 +236,8 @@ public:
void resetSurface(ColorDepthMode colorDepth, const Common::SharedPtr<Graphics::ManagedSurface> &surface);
+ ColorDepthMode getOriginalColorDepth() const;
+
private:
Common::SharedPtr<Graphics::ManagedSurface> _surface;
Common::SharedPtr<Graphics::ManagedSurface> _optimizedSurface;
diff --git a/engines/mtropolis/elements.cpp b/engines/mtropolis/elements.cpp
index f8f8abfd7ea..5a479fc9213 100644
--- a/engines/mtropolis/elements.cpp
+++ b/engines/mtropolis/elements.cpp
@@ -474,11 +474,11 @@ MiniscriptInstructionOutcome MovieElement::writeRefAttribute(MiniscriptThread *t
return kMiniscriptInstructionOutcomeContinue;
}
if (attrib == "volume") {
- DynamicValueWriteFuncHelper<MovieElement, &MovieElement::scriptSetVolume>::create(this, result);
+ DynamicValueWriteFuncHelper<MovieElement, &MovieElement::scriptSetVolume, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
if (attrib == "timevalue") {
- DynamicValueWriteFuncHelper<MovieElement, &MovieElement::scriptSetTimestamp>::create(this, result);
+ DynamicValueWriteFuncHelper<MovieElement, &MovieElement::scriptSetTimestamp, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -918,11 +918,11 @@ MiniscriptInstructionOutcome MovieElement::scriptSetRangeEnd(MiniscriptThread *t
MiniscriptInstructionOutcome MovieElement::scriptRangeWriteRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "start") {
- DynamicValueWriteFuncHelper<MovieElement, &MovieElement::scriptSetRangeStart>::create(this, result);
+ DynamicValueWriteFuncHelper<MovieElement, &MovieElement::scriptSetRangeStart, true>::create(this, result);
return kMiniscriptInstructionOutcomeFailed;
}
if (attrib == "end") {
- DynamicValueWriteFuncHelper<MovieElement, &MovieElement::scriptSetRangeStart>::create(this, result);
+ DynamicValueWriteFuncHelper<MovieElement, &MovieElement::scriptSetRangeStart, true>::create(this, result);
return kMiniscriptInstructionOutcomeFailed;
}
@@ -1039,7 +1039,7 @@ MiniscriptInstructionOutcome ImageElement::writeRefAttribute(MiniscriptThread *t
DynamicValueWriteStringHelper::create(&_text, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "flushpriority") {
- DynamicValueWriteFuncHelper<ImageElement, &ImageElement::scriptSetFlushPriority>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<ImageElement, &ImageElement::scriptSetFlushPriority, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -1082,12 +1082,21 @@ void ImageElement::render(Window *window) {
Common::Rect destRect(_cachedAbsoluteOrigin.x, _cachedAbsoluteOrigin.y, _cachedAbsoluteOrigin.x + _rect.width(), _cachedAbsoluteOrigin.y + _rect.height());
if (optimized->format.bytesPerPixel == 1) {
- const Palette *palette = getPalette().get();
- if (!palette)
- palette = &_runtime->getGlobalPalette();
-
// FIXME: Pass palette to blit functions instead
- optimized->setPalette(palette->getPalette(), 0, 256);
+ if (_cachedImage->getOriginalColorDepth() == kColorDepthMode1Bit) {
+ const Graphics::PixelFormat &fmt = window->getPixelFormat();
+ uint32 blackColor = fmt.RGBToColor(0, 0, 0);
+ uint32 whiteColor = fmt.RGBToColor(255, 255, 255);
+
+ const uint32 bwPalette[2] = {whiteColor, blackColor};
+ optimized->setPalette(bwPalette, 0, 2);
+ } else {
+ const Palette *palette = getPalette().get();
+ if (!palette)
+ palette = &_runtime->getGlobalPalette();
+
+ optimized->setPalette(palette->getPalette(), 0, 256);
+ }
}
uint8 alpha = _transitionProps.getAlpha();
@@ -1177,7 +1186,7 @@ bool MToonElement::readAttribute(MiniscriptThread *thread, DynamicValue &result,
MiniscriptInstructionOutcome MToonElement::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "cel") {
- DynamicValueWriteFuncHelper<MToonElement, &MToonElement::scriptSetCel>::create(this, result);
+ DynamicValueWriteFuncHelper<MToonElement, &MToonElement::scriptSetCel, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "flushpriority") {
DynamicValueWriteIntegerHelper<int32>::create(&_flushPriority, result);
@@ -1186,7 +1195,7 @@ MiniscriptInstructionOutcome MToonElement::writeRefAttribute(MiniscriptThread *t
DynamicValueWriteBoolHelper::create(&_maintainRate, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "rate") {
- DynamicValueWriteFuncHelper<MToonElement, &MToonElement::scriptSetRate>::create(this, result);
+ DynamicValueWriteFuncHelper<MToonElement, &MToonElement::scriptSetRate, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "range") {
DynamicValueWriteOrRefAttribFuncHelper<MToonElement, &MToonElement::scriptSetRange, &MToonElement::scriptRangeWriteRefAttribute>::create(this, result);
@@ -1568,10 +1577,10 @@ MiniscriptInstructionOutcome MToonElement::scriptSetRangeEnd(MiniscriptThread *t
MiniscriptInstructionOutcome MToonElement::scriptRangeWriteRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "start") {
- DynamicValueWriteFuncHelper<MToonElement, &MToonElement::scriptSetRangeStart>::create(this, result);
+ DynamicValueWriteFuncHelper<MToonElement, &MToonElement::scriptSetRangeStart, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "end") {
- DynamicValueWriteFuncHelper<MToonElement, &MToonElement::scriptSetRangeEnd>::create(this, result);
+ DynamicValueWriteFuncHelper<MToonElement, &MToonElement::scriptSetRangeEnd, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -1695,7 +1704,7 @@ bool TextLabelElement::readAttributeIndexed(MiniscriptThread *thread, DynamicVal
MiniscriptInstructionOutcome TextLabelElement::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) {
if (attrib == "text") {
- DynamicValueWriteFuncHelper<TextLabelElement, &TextLabelElement::scriptSetText>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<TextLabelElement, &TextLabelElement::scriptSetText, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -1961,7 +1970,9 @@ MiniscriptInstructionOutcome TextLabelElement::scriptSetText(MiniscriptThread *t
MiniscriptInstructionOutcome TextLabelElement::scriptSetLine(MiniscriptThread *thread, size_t lineIndex, const DynamicValue &value) {
- if (value.getType() != DynamicValueTypes::kString) {
+ DynamicValue derefValue = value.dereference();
+
+ if (derefValue.getType() != DynamicValueTypes::kString) {
thread->error("Tried to set a text label element's text to something that wasn't a string");
return kMiniscriptInstructionOutcomeFailed;
}
@@ -1969,14 +1980,14 @@ MiniscriptInstructionOutcome TextLabelElement::scriptSetLine(MiniscriptThread *t
uint32 startPos;
uint32 endPos;
if (findLineRange(lineIndex, startPos, endPos))
- _text = _text.substr(0, startPos) + value.getString() + _text.substr(endPos, _text.size() - endPos);
+ _text = _text.substr(0, startPos) + derefValue.getString() + _text.substr(endPos, _text.size() - endPos);
else {
size_t numLines = countLines();
while (numLines <= lineIndex) {
_text += '\r';
numLines++;
}
- _text += value.getString();
+ _text += derefValue.getString();
}
_needsRender = true;
@@ -2070,13 +2081,13 @@ bool SoundElement::readAttribute(MiniscriptThread *thread, DynamicValue &result,
MiniscriptInstructionOutcome SoundElement::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) {
if (attrib == "loop") {
- DynamicValueWriteFuncHelper<SoundElement, &SoundElement::scriptSetLoop>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<SoundElement, &SoundElement::scriptSetLoop, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "volume") {
- DynamicValueWriteFuncHelper<SoundElement, &SoundElement::scriptSetVolume>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<SoundElement, &SoundElement::scriptSetVolume, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "balance") {
- DynamicValueWriteFuncHelper<SoundElement, &SoundElement::scriptSetBalance>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<SoundElement, &SoundElement::scriptSetBalance, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
}
diff --git a/engines/mtropolis/miniscript.cpp b/engines/mtropolis/miniscript.cpp
index 3940b1f49b9..122f719bdf0 100644
--- a/engines/mtropolis/miniscript.cpp
+++ b/engines/mtropolis/miniscript.cpp
@@ -38,6 +38,8 @@ bool miniscriptEvaluateTruth(const DynamicValue &value) {
return (value.getInt() != 0);
case DynamicValueTypes::kFloat:
return !(value.getFloat() == 0.0);
+ case DynamicValueTypes::kObject:
+ return !value.getObject().object.expired();
default:
return false;
}
@@ -487,9 +489,7 @@ MiniscriptInstructionOutcome Set::execute(MiniscriptThread *thread) const {
}
// Convert value
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, true);
- if (outcome != kMiniscriptInstructionOutcomeContinue)
- return outcome;
+ MiniscriptInstructionOutcome outcome = kMiniscriptInstructionOutcomeContinue;
const MiniscriptStackValue &srcValue = thread->getStackValueFromTop(0);
MiniscriptStackValue &target = thread->getStackValueFromTop(1);
@@ -510,10 +510,7 @@ MiniscriptInstructionOutcome Set::execute(MiniscriptThread *thread) const {
}
if (var != nullptr) {
- if (!var->varSetValue(thread, srcValue.value)) {
- thread->error("Couldn't assign value to variable, probably wrong type");
- return kMiniscriptInstructionOutcomeFailed;
- }
+ (void)var->varSetValue(thread, srcValue.value);
} else {
thread->error("Can't assign to rvalue");
return kMiniscriptInstructionOutcomeFailed;
@@ -534,14 +531,6 @@ MiniscriptInstructionOutcome Send::execute(MiniscriptThread *thread) const {
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
- if (outcome != kMiniscriptInstructionOutcomeContinue)
- return outcome;
-
- outcome = thread->dereferenceRValue(1, true);
- if (outcome != kMiniscriptInstructionOutcomeContinue)
- return outcome;
-
DynamicValue &targetValue = thread->getStackValueFromTop(0).value;
DynamicValue &payloadValue = thread->getStackValueFromTop(1).value;
@@ -590,11 +579,11 @@ MiniscriptInstructionOutcome BinaryArithInstruction::execute(MiniscriptThread *t
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
- outcome = thread->dereferenceRValue(1, false);
+ outcome = thread->dereferenceRValue(1);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -719,11 +708,11 @@ MiniscriptInstructionOutcome UnorderedCompareInstruction::execute(MiniscriptThre
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
- outcome = thread->dereferenceRValue(1, false);
+ outcome = thread->dereferenceRValue(1);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -827,11 +816,11 @@ MiniscriptInstructionOutcome And::execute(MiniscriptThread *thread) const {
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
- outcome = thread->dereferenceRValue(1, false);
+ outcome = thread->dereferenceRValue(1);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -850,11 +839,11 @@ MiniscriptInstructionOutcome Or::execute(MiniscriptThread *thread) const {
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
- outcome = thread->dereferenceRValue(1, false);
+ outcome = thread->dereferenceRValue(1);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -873,7 +862,7 @@ MiniscriptInstructionOutcome Neg::execute(MiniscriptThread *thread) const {
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -903,7 +892,7 @@ MiniscriptInstructionOutcome Not::execute(MiniscriptThread *thread) const {
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -919,11 +908,11 @@ MiniscriptInstructionOutcome OrderedCompareInstruction::execute(MiniscriptThread
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
- outcome = thread->dereferenceRValue(1, false);
+ outcome = thread->dereferenceRValue(1);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -969,7 +958,7 @@ MiniscriptInstructionOutcome BuiltinFunc::execute(MiniscriptThread *thread) cons
}
for (size_t i = 0; i < stackArgsNeeded; i++) {
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(i, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(i);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
}
@@ -1211,11 +1200,11 @@ MiniscriptInstructionOutcome StrConcat::execute(MiniscriptThread *thread) const
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
- outcome = thread->dereferenceRValue(1, false);
+ outcome = thread->dereferenceRValue(1);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -1244,11 +1233,11 @@ MiniscriptInstructionOutcome PointCreate::execute(MiniscriptThread *thread) cons
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
- outcome = thread->dereferenceRValue(1, false);
+ outcome = thread->dereferenceRValue(1);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -1302,11 +1291,11 @@ MiniscriptInstructionOutcome RangeCreate::execute(MiniscriptThread *thread) cons
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
- outcome = thread->dereferenceRValue(1, false);
+ outcome = thread->dereferenceRValue(1);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -1376,7 +1365,7 @@ MiniscriptInstructionOutcome GetChild::execute(MiniscriptThread *thread) const {
}
// Convert index
- outcome = thread->dereferenceRValue(0, false);
+ outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -1607,26 +1596,18 @@ MiniscriptInstructionOutcome ListCreate::execute(MiniscriptThread *thread) const
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
- if (outcome != kMiniscriptInstructionOutcomeContinue)
- return outcome;
-
- outcome = thread->dereferenceRValue(1, false);
- if (outcome != kMiniscriptInstructionOutcomeContinue)
- return outcome;
-
MiniscriptStackValue &rs = thread->getStackValueFromTop(0);
MiniscriptStackValue &lsDest = thread->getStackValueFromTop(1);
Common::SharedPtr<DynamicList> list(new DynamicList());
- if (!list->setAtIndex(1, rs.value)) {
- thread->error("Failed to set value 2 of list");
- return kMiniscriptInstructionOutcomeFailed;
- }
if (!list->setAtIndex(0, lsDest.value)) {
thread->error("Failed to set value 1 of list");
return kMiniscriptInstructionOutcomeFailed;
}
+ if (!list->setAtIndex(1, rs.value)) {
+ thread->error("Failed to set value 2 of list");
+ return kMiniscriptInstructionOutcomeFailed;
+ }
lsDest.value.setList(list);
thread->popValues(1);
@@ -1640,14 +1621,6 @@ MiniscriptInstructionOutcome ListAppend::execute(MiniscriptThread *thread) const
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
- if (outcome != kMiniscriptInstructionOutcomeContinue)
- return outcome;
-
- outcome = thread->dereferenceRValue(1, false);
- if (outcome != kMiniscriptInstructionOutcomeContinue)
- return outcome;
-
MiniscriptStackValue &rs = thread->getStackValueFromTop(0);
MiniscriptStackValue &lsDest = thread->getStackValueFromTop(1);
@@ -1826,7 +1799,7 @@ MiniscriptInstructionOutcome Jump::execute(MiniscriptThread *thread) const {
return kMiniscriptInstructionOutcomeFailed;
}
- MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = thread->dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue)
return outcome;
@@ -1906,7 +1879,7 @@ MiniscriptStackValue &MiniscriptThread::getStackValueFromTop(size_t offset) {
return _stack[_stack.size() - 1 - offset];
}
-MiniscriptInstructionOutcome MiniscriptThread::dereferenceRValue(size_t offset, bool cloneLists) {
+MiniscriptInstructionOutcome MiniscriptThread::dereferenceRValue(size_t offset) {
assert(offset < _stack.size());
MiniscriptStackValue &stackValue = _stack[_stack.size() - 1 - offset];
@@ -1924,9 +1897,8 @@ MiniscriptInstructionOutcome MiniscriptThread::dereferenceRValue(size_t offset,
this->error("Attempted to dereference an lvalue proxy");
return kMiniscriptInstructionOutcomeFailed;
case DynamicValueTypes::kList:
- if (cloneLists)
- stackValue.value.setList(stackValue.value.getList()->clone());
- break;
+ stackValue.value.setList(stackValue.value.getList()->clone());
+ break;
default:
break;
}
@@ -1950,7 +1922,7 @@ bool MiniscriptThread::evaluateTruthOfResult(bool &isTrue) {
return false;
}
- MiniscriptInstructionOutcome outcome = dereferenceRValue(0, false);
+ MiniscriptInstructionOutcome outcome = dereferenceRValue(0);
if (outcome != kMiniscriptInstructionOutcomeContinue) {
this->error("Miniscript program result couldn't be dereferenced");
return false;
diff --git a/engines/mtropolis/miniscript.h b/engines/mtropolis/miniscript.h
index 9d3e0cfe2c6..7ff7c1a0193 100644
--- a/engines/mtropolis/miniscript.h
+++ b/engines/mtropolis/miniscript.h
@@ -420,8 +420,7 @@ public:
void popValues(size_t count);
size_t getStackSize() const;
MiniscriptStackValue &getStackValueFromTop(size_t offset);
-
- MiniscriptInstructionOutcome dereferenceRValue(size_t offset, bool cloneLists);
+ MiniscriptInstructionOutcome dereferenceRValue(size_t offset);
void jumpOffset(size_t offset);
diff --git a/engines/mtropolis/modifiers.cpp b/engines/mtropolis/modifiers.cpp
index 7578c7073ed..1d9a7b48ada 100644
--- a/engines/mtropolis/modifiers.cpp
+++ b/engines/mtropolis/modifiers.cpp
@@ -2395,19 +2395,11 @@ Common::SharedPtr<ModifierSaveLoad> BooleanVariableModifier::getSaveLoad() {
}
bool BooleanVariableModifier::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
- switch (value.getType()) {
- case DynamicValueTypes::kBoolean:
- _value = value.getBool();
- break;
- case DynamicValueTypes::kFloat:
- _value = (value.getFloat() != 0.0);
- break;
- case DynamicValueTypes::kInteger:
- _value = (value.getInt() != 0);
- break;
- default:
+ DynamicValue boolValue;
+ if (!value.convertToType(DynamicValueTypes::kBoolean, boolValue))
return false;
- }
+
+ _value = boolValue.getBool();
return true;
}
@@ -2470,19 +2462,12 @@ Common::SharedPtr<ModifierSaveLoad> IntegerVariableModifier::getSaveLoad() {
}
bool IntegerVariableModifier::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
- if (value.getType() == DynamicValueTypes::kFloat)
- _value = static_cast<int32>(floor(value.getFloat() + 0.5));
- else if (value.getType() == DynamicValueTypes::kInteger)
- _value = value.getInt();
- else if (value.getType() == DynamicValueTypes::kString) {
- // Should this scan %lf to a double and round it instead?
- int i;
- if (!sscanf(value.getString().c_str(), "%i", &i))
- return false;
- _value = i;
- } else
+ DynamicValue intValue;
+ if (!value.convertToType(DynamicValueTypes::kInteger, intValue))
return false;
+ _value = intValue.getInt();
+
return true;
}
@@ -2542,11 +2527,12 @@ Common::SharedPtr<ModifierSaveLoad> IntegerRangeVariableModifier::getSaveLoad()
}
bool IntegerRangeVariableModifier::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
- if (value.getType() == DynamicValueTypes::kIntegerRange)
- _range = value.getIntRange();
- else
+ DynamicValue intRangeValue;
+ if (!value.convertToType(DynamicValueTypes::kIntegerRange, intRangeValue))
return false;
+ _range = intRangeValue.getIntRange();
+
return true;
}
@@ -2632,11 +2618,12 @@ Common::SharedPtr<ModifierSaveLoad> VectorVariableModifier::getSaveLoad() {
}
bool VectorVariableModifier::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
- if (value.getType() == DynamicValueTypes::kVector)
- _vector = value.getVector();
- else
+ DynamicValue vectorValue;
+ if (!value.convertToType(DynamicValueTypes::kVector, vectorValue))
return false;
+ _vector = vectorValue.getVector();
+
return true;
}
@@ -2722,11 +2709,12 @@ Common::SharedPtr<ModifierSaveLoad> PointVariableModifier::getSaveLoad() {
}
bool PointVariableModifier::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
- if (value.getType() == DynamicValueTypes::kPoint)
- _value = value.getPoint();
- else
+ DynamicValue pointValue;
+ if (!value.convertToType(DynamicValueTypes::kPoint, pointValue))
return false;
+ _value = pointValue.getPoint();
+
return true;
}
@@ -2816,13 +2804,12 @@ Common::SharedPtr<ModifierSaveLoad> FloatingPointVariableModifier::getSaveLoad()
}
bool FloatingPointVariableModifier::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
- if (value.getType() == DynamicValueTypes::kInteger)
- _value = value.getInt();
- else if (value.getType() == DynamicValueTypes::kFloat)
- _value = value.getFloat();
- else
+ DynamicValue floatValue;
+ if (!value.convertToType(DynamicValueTypes::kFloat, floatValue))
return false;
+ _value = floatValue.getFloat();
+
return true;
}
@@ -2881,11 +2868,12 @@ Common::SharedPtr<ModifierSaveLoad> StringVariableModifier::getSaveLoad() {
}
bool StringVariableModifier::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
- if (value.getType() == DynamicValueTypes::kString)
- _value = value.getString();
- else
+ DynamicValue stringValue;
+ if (!value.convertToType(DynamicValueTypes::kString, stringValue))
return false;
+ _value = stringValue.getString();
+
return true;
}
@@ -2971,6 +2959,8 @@ Common::SharedPtr<ModifierSaveLoad> ObjectReferenceVariableModifierV1::getSaveLo
}
bool ObjectReferenceVariableModifierV1::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
+ // Somewhat tricky aspect: If this is set to another object reference variable modifier, then this will reference
+ // the other object variable modifier, it will NOT copy it.
if (value.getType() == DynamicValueTypes::kNull)
_value.reset();
else if (value.getType() == DynamicValueTypes::kObject)
@@ -2982,10 +2972,7 @@ bool ObjectReferenceVariableModifierV1::varSetValue(MiniscriptThread *thread, co
}
void ObjectReferenceVariableModifierV1::varGetValue(DynamicValue &dest) const {
- if (_value.expired())
- dest.clear();
- else
- dest.setObject(_value);
+ dest.setObject(getSelfReference());
}
Common::SharedPtr<Modifier> ObjectReferenceVariableModifierV1::shallowClone() const {
diff --git a/engines/mtropolis/mtropolis.cpp b/engines/mtropolis/mtropolis.cpp
index b2a677c9aa5..a1c9a5548a3 100644
--- a/engines/mtropolis/mtropolis.cpp
+++ b/engines/mtropolis/mtropolis.cpp
@@ -115,8 +115,6 @@ Common::Error MTropolisEngine::run() {
subRenderer.reset();
- Common::SharedPtr<ProjectDescription> projectDesc = bootProject(*_gameDescription);
-
if (_gameDescription->gameID == GID_OBSIDIAN) {
preferredWidth = 640;
preferredHeight = 480;
@@ -157,8 +155,6 @@ Common::Error MTropolisEngine::run() {
if (ConfMan.getBool("mtropolis_mod_minimum_transition_duration"))
_runtime->getHacks().minTransitionDuration = 75;
- _runtime->queueProject(projectDesc);
-
// Figure out pixel formats
Graphics::PixelFormat modePixelFormats[kColorDepthModeCount];
bool haveExactMode[kColorDepthModeCount];
@@ -255,6 +251,13 @@ Common::Error MTropolisEngine::run() {
initGraphics(preferredWidth, preferredHeight, &modePixelFormats[selectedMode]);
+
+
+ // Start the project
+ Common::SharedPtr<ProjectDescription> projectDesc = bootProject(*_gameDescription);
+ _runtime->queueProject(projectDesc);
+
+
#ifdef MTROPOLIS_DEBUG_ENABLE
if (ConfMan.getBool("mtropolis_debug_at_start")) {
_runtime->debugSetEnabled(true);
diff --git a/engines/mtropolis/mtropolis.h b/engines/mtropolis/mtropolis.h
index c43c88a8773..6dbf6c3db6f 100644
--- a/engines/mtropolis/mtropolis.h
+++ b/engines/mtropolis/mtropolis.h
@@ -82,7 +82,8 @@ private:
Common::String getUnpromptedSaveFileName(const Common::String &fileName);
- static const uint kCurrentSaveFileVersion = 1;
+ static const uint kCurrentSaveFileVersion = 2;
+ static const uint kEarliestSupportedSaveFileVersion = 2;
static const uint kSavegameSignature = 0x6d545356; // mTSV
ISaveWriter *_saveWriter;
diff --git a/engines/mtropolis/plugin/obsidian.cpp b/engines/mtropolis/plugin/obsidian.cpp
index 99a411d3358..bc4a89c1f51 100644
--- a/engines/mtropolis/plugin/obsidian.cpp
+++ b/engines/mtropolis/plugin/obsidian.cpp
@@ -399,10 +399,10 @@ MiniscriptInstructionOutcome TextWorkModifier::writeRefAttribute(MiniscriptThrea
DynamicValueWriteStringHelper::create(&_token, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "firstword") {
- DynamicValueWriteFuncHelper<TextWorkModifier, &TextWorkModifier::scriptSetFirstWord>::create(this, result);
+ DynamicValueWriteFuncHelper<TextWorkModifier, &TextWorkModifier::scriptSetFirstWord, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "lastword") {
- DynamicValueWriteFuncHelper<TextWorkModifier, &TextWorkModifier::scriptSetLastWord>::create(this, result);
+ DynamicValueWriteFuncHelper<TextWorkModifier, &TextWorkModifier::scriptSetLastWord, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -518,11 +518,11 @@ bool DictionaryModifier::readAttribute(MiniscriptThread *thread, DynamicValue &r
MiniscriptInstructionOutcome DictionaryModifier::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "index") {
- DynamicValueWriteFuncHelper<DictionaryModifier, &DictionaryModifier::scriptSetIndex>::create(this, result);
+ DynamicValueWriteFuncHelper<DictionaryModifier, &DictionaryModifier::scriptSetIndex, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
if (attrib == "string") {
- DynamicValueWriteFuncHelper<DictionaryModifier, &DictionaryModifier::scriptSetString>::create(this, result);
+ DynamicValueWriteFuncHelper<DictionaryModifier, &DictionaryModifier::scriptSetString, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -651,11 +651,11 @@ bool WordMixerModifier::readAttribute(MiniscriptThread *thread, DynamicValue &re
MiniscriptInstructionOutcome WordMixerModifier::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "input") {
- DynamicValueWriteFuncHelper<WordMixerModifier, &WordMixerModifier::scriptSetInput>::create(this, result);
+ DynamicValueWriteFuncHelper<WordMixerModifier, &WordMixerModifier::scriptSetInput, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
if (attrib == "search") {
- DynamicValueWriteFuncHelper<WordMixerModifier, &WordMixerModifier::scriptSetSearch>::create(this, result);
+ DynamicValueWriteFuncHelper<WordMixerModifier, &WordMixerModifier::scriptSetSearch, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -872,7 +872,7 @@ bool XorCheckModifier::readAttribute(MiniscriptThread *thread, DynamicValue &res
MiniscriptInstructionOutcome XorCheckModifier::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "checknow") {
- DynamicValueWriteFuncHelper<XorCheckModifier, &XorCheckModifier::scriptSetCheckNow>::create(this, result);
+ DynamicValueWriteFuncHelper<XorCheckModifier, &XorCheckModifier::scriptSetCheckNow, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
diff --git a/engines/mtropolis/plugin/standard.cpp b/engines/mtropolis/plugin/standard.cpp
index 85c88837566..235a3a99e92 100644
--- a/engines/mtropolis/plugin/standard.cpp
+++ b/engines/mtropolis/plugin/standard.cpp
@@ -1693,10 +1693,10 @@ bool STransCtModifier::readAttribute(MiniscriptThread *thread, DynamicValue &res
MiniscriptInstructionOutcome STransCtModifier::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "rate") {
- DynamicValueWriteFuncHelper<STransCtModifier, &STransCtModifier::scriptSetRate>::create(this, result);
+ DynamicValueWriteFuncHelper<STransCtModifier, &STransCtModifier::scriptSetRate, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "steps") {
- DynamicValueWriteFuncHelper<STransCtModifier, &STransCtModifier::scriptSetSteps>::create(this, result);
+ DynamicValueWriteFuncHelper<STransCtModifier, &STransCtModifier::scriptSetSteps, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -2008,7 +2008,7 @@ bool ObjectReferenceVariableModifier::readAttribute(MiniscriptThread *thread, Dy
MiniscriptInstructionOutcome ObjectReferenceVariableModifier::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "path") {
- DynamicValueWriteFuncHelper<ObjectReferenceVariableModifier, &ObjectReferenceVariableModifier::scriptSetPath>::create(this, result);
+ DynamicValueWriteFuncHelper<ObjectReferenceVariableModifier, &ObjectReferenceVariableModifier::scriptSetPath, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
if (attrib == "object") {
@@ -2022,8 +2022,6 @@ MiniscriptInstructionOutcome ObjectReferenceVariableModifier::writeRefAttribute(
}
bool ObjectReferenceVariableModifier::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
- // Somewhat strangely, setting an object reference variable to something sets the path or object,
- // but getting the variable returns the modifier
switch (value.getType()) {
case DynamicValueTypes::kNull:
case DynamicValueTypes::kObject:
@@ -2036,7 +2034,7 @@ bool ObjectReferenceVariableModifier::varSetValue(MiniscriptThread *thread, cons
}
void ObjectReferenceVariableModifier::varGetValue(DynamicValue &dest) const {
- dest.setObject(this->getSelfReference());
+ dest.setObject(getSelfReference());
}
#ifdef MTROPOLIS_DEBUG_ENABLE
@@ -2471,28 +2469,28 @@ bool MidiModifier::readAttribute(MiniscriptThread *thread, DynamicValue &result,
MiniscriptInstructionOutcome MidiModifier::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "volume") {
- DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetVolume>::create(this, result);
+ DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetVolume, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "notevelocity") {
- DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetNoteVelocity>::create(this, result);
+ DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetNoteVelocity, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "noteduration") {
- DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetNoteDuration>::create(this, result);
+ DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetNoteDuration, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "notenum") {
- DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetNoteNum>::create(this, result);
+ DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetNoteNum, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "loop") {
- DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetLoop>::create(this, result);
+ DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetLoop, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "playnote") {
- DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetPlayNote>::create(this, result);
+ DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetPlayNote, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "tempo") {
- DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetTempo>::create(this, result);
+ DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetTempo, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "mutetrack") {
- DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetMuteTrack>::create(this, result);
+ DynamicValueWriteFuncHelper<MidiModifier, &MidiModifier::scriptSetMuteTrack, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -2725,52 +2723,53 @@ ListVariableModifier::ListVariableModifier() : _list(new DynamicList()), _prefer
}
bool ListVariableModifier::load(const PlugInModifierLoaderContext &context, const Data::Standard::ListVariableModifier &data) {
- if (!data.havePersistentData || data.numValues == 0)
- return true; // If the list is empty then we don't care, the actual value type is irrelevant because it can be reassigned
-
- DynamicValueTypes::DynamicValueType expectedType = DynamicValueTypes::kInvalid;
+ _preferredContentType = DynamicValueTypes::kInvalid;
switch (data.contentsType) {
case Data::Standard::ListVariableModifier::kContentsTypeInteger:
- expectedType = DynamicValueTypes::kInteger;
+ _preferredContentType = DynamicValueTypes::kInteger;
break;
case Data::Standard::ListVariableModifier::kContentsTypePoint:
- expectedType = DynamicValueTypes::kPoint;
+ _preferredContentType = DynamicValueTypes::kPoint;
break;
case Data::Standard::ListVariableModifier::kContentsTypeRange:
- expectedType = DynamicValueTypes::kIntegerRange;
+ _preferredContentType = DynamicValueTypes::kIntegerRange;
break;
case Data::Standard::ListVariableModifier::kContentsTypeFloat:
- expectedType = DynamicValueTypes::kFloat;
+ _preferredContentType = DynamicValueTypes::kFloat;
break;
case Data::Standard::ListVariableModifier::kContentsTypeString:
- expectedType = DynamicValueTypes::kString;
+ _preferredContentType = DynamicValueTypes::kString;
break;
case Data::Standard::ListVariableModifier::kContentsTypeObject:
+ _preferredContentType = DynamicValueTypes::kObject;
if (data.persistentValuesGarbled) {
// Ignore and let the game fix it
return true;
} else {
- warning("Object reference lists are not implemented");
- return false;
+ warning("Loading object reference lists from data is not implemented");
+ return true;
}
break;
case Data::Standard::ListVariableModifier::kContentsTypeVector:
- expectedType = DynamicValueTypes::kVector;
+ _preferredContentType = DynamicValueTypes::kVector;
break;
case Data::Standard::ListVariableModifier::kContentsTypeBoolean:
- expectedType = DynamicValueTypes::kBoolean;
+ _preferredContentType = DynamicValueTypes::kBoolean;
break;
default:
warning("Unknown list data type");
return false;
}
+ if (!data.havePersistentData || data.numValues == 0)
+ return true;
+
for (size_t i = 0; i < data.numValues; i++) {
DynamicValue dynValue;
if (!dynValue.loadConstant(data.values[i]))
return false;
- if (dynValue.getType() != expectedType) {
+ if (dynValue.getType() != _preferredContentType) {
warning("List mod initialization element had the wrong type");
return false;
}
@@ -2781,8 +2780,10 @@ bool ListVariableModifier::load(const PlugInModifierLoaderContext &context, cons
}
}
- _preferredContentType = expectedType;
+ return true;
+}
+bool ListVariableModifier::isListVariable() const {
return true;
}
@@ -2791,19 +2792,71 @@ Common::SharedPtr<ModifierSaveLoad> ListVariableModifier::getSaveLoad() {
}
bool ListVariableModifier::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
- if (value.getType() == DynamicValueTypes::kList)
- _list = value.getList()->clone();
- else {
- if (!_list)
- _list.reset(new DynamicList());
- return _list->setAtIndex(0, value);
+ if (value.getType() == DynamicValueTypes::kList) {
+ // Source value is a list. In this case, it must be convertible, or an error occurs.
+ Common::SharedPtr<DynamicList> sourceList = value.getList();
+ Common::SharedPtr<DynamicList> newList(new DynamicList());
+
+ for (size_t i = 0; i < sourceList->getSize(); i++) {
+ DynamicValue sourceElement;
+ sourceList->getAtIndex(i, sourceElement);
+
+ DynamicValue convertedElement;
+
+ if (!sourceElement.convertToType(_preferredContentType, convertedElement)) {
+ thread->error("Failed to convert list when assigning to a list variable");
+ return false;
+ }
+
+ newList->setAtIndex(i, convertedElement);
+ }
+
+ _list = newList;
+ } else if (value.getType() == DynamicValueTypes::kObject) {
+ // Source value is an object. In this case, it must be another list, otherwise this fails without an error.
+ RuntimeObject *obj = value.getObject().object.lock().get();
+ if (obj && obj->isModifier() && static_cast<Modifier *>(obj)->isVariable() && static_cast<VariableModifier *>(obj)->isListVariable()) {
+ Common::SharedPtr<DynamicList> sourceList = static_cast<ListVariableModifier *>(obj)->_list;
+ Common::SharedPtr<DynamicList> newList(new DynamicList());
+
+ bool failed = false;
+ for (size_t i = 0; i < sourceList->getSize(); i++) {
+ DynamicValue sourceElement;
+ sourceList->getAtIndex(i, sourceElement);
+
+ DynamicValue convertedElement;
+
+ if (!sourceElement.convertToType(_preferredContentType, convertedElement)) {
+ warning("Failed to convert list when assigning to a list variable. (Non-fatal since it was directly assigned.)");
+ failed = true;
+ break;
+ }
+
+ newList->setAtIndex(i, convertedElement);
+ }
+
+ if (!failed)
+ _list = newList;
+ }
+ } else {
+ // Source value is a non-list. In this case, it must be exactly the correct type, except for numbers.
+
+ DynamicValue convertedValue;
+ if (value.convertToType(_preferredContentType, convertedValue)) {
+ Common::SharedPtr<DynamicList> newList(new DynamicList());
+ newList->setAtIndex(0, convertedValue);
+ _list = newList;
+ } else {
+ thread->error("Can't assign incompatible value type to a list variable");
+ return false;
+ }
}
return true;
}
void ListVariableModifier::varGetValue(DynamicValue &dest) const {
- dest.setList(_list);
+ dest.setObject(this->getSelfReference());
}
bool ListVariableModifier::readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) {
@@ -2853,7 +2906,7 @@ bool ListVariableModifier::readAttributeIndexed(MiniscriptThread *thread, Dynami
MiniscriptInstructionOutcome ListVariableModifier::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) {
if (attrib == "count") {
- DynamicValueWriteFuncHelper<ListVariableModifier, &ListVariableModifier::scriptSetCount>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<ListVariableModifier, &ListVariableModifier::scriptSetCount, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -2923,7 +2976,7 @@ void ListVariableModifier::debugInspect(IDebugInspectionReport *report) const {
}
#endif
-ListVariableModifier::ListVariableModifier(const ListVariableModifier &other) : VariableModifier(other), _preferredContentType(DynamicValueTypes::kNull) {
+ListVariableModifier::ListVariableModifier(const ListVariableModifier &other) : VariableModifier(other), _preferredContentType(other._preferredContentType) {
if (other._list)
_list = other._list->clone();
}
@@ -2967,7 +3020,10 @@ ListVariableModifier::SaveLoad::SaveLoad(ListVariableModifier *modifier) : _modi
}
void ListVariableModifier::SaveLoad::commitLoad() const {
- _modifier->_list = _list;
+ // We don't support deserializing object references (yet?), so just leave the existing values.
+ // In Obsidian at least, this doesn't matter.
+ if (_list->getType() != DynamicValueTypes::kObject)
+ _modifier->_list = _list;
}
void ListVariableModifier::SaveLoad::saveInternal(Common::WriteStream *stream) const {
@@ -3021,8 +3077,7 @@ void ListVariableModifier::SaveLoad::recursiveWriteList(DynamicList *list, Commo
case DynamicValueTypes::kBoolean:
stream->writeByte(list->getBool()[i] ? 1 : 0);
break;
- case DynamicValueTypes::kList:
- recursiveWriteList(list->getList()[i].get(), stream);
+ case DynamicValueTypes::kObject:
break;
default:
error("Can't figure out how to write a saved variable");
@@ -3090,11 +3145,8 @@ Common::SharedPtr<DynamicList> ListVariableModifier::SaveLoad::recursiveReadList
byte b = stream->readByte();
val.setBool(b != 0);
} break;
- case DynamicValueTypes::kList: {
- Common::SharedPtr<DynamicList> childList = recursiveReadList(stream);
- if (!childList)
- return nullptr;
- val.setList(childList);
+ case DynamicValueTypes::kObject: {
+ val.setObject(Common::WeakPtr<RuntimeObject>());
} break;
default:
error("Can't figure out how to write a saved variable");
diff --git a/engines/mtropolis/plugin/standard.h b/engines/mtropolis/plugin/standard.h
index c6f60dee2ef..3eb8ab9fb74 100644
--- a/engines/mtropolis/plugin/standard.h
+++ b/engines/mtropolis/plugin/standard.h
@@ -325,6 +325,8 @@ public:
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::ListVariableModifier &data);
+ bool isListVariable() const override;
+
Common::SharedPtr<ModifierSaveLoad> getSaveLoad() override;
bool varSetValue(MiniscriptThread *thread, const DynamicValue &value) override;
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index b73b4a43dd7..ab8a5acddaa 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -1018,21 +1018,20 @@ MiniscriptInstructionOutcome DynamicList::WriteProxyInterface::write(MiniscriptT
MiniscriptInstructionOutcome DynamicList::WriteProxyInterface::refAttrib(MiniscriptThread *thread, DynamicValueWriteProxy &proxy, void *objectRef, uintptr ptrOrOffset, const Common::String &attrib) {
DynamicList *list = static_cast<DynamicList *>(objectRef);
+ if (ptrOrOffset >= list->getSize()) {
+ // Only direct sets of elements may change the size of a list. Accessing attributes of elements that aren't set is an error.
+ thread->error("List attrib write dereference was out of bounds");
+ return kMiniscriptInstructionOutcomeFailed;
+ }
+
switch (list->getType()) {
case DynamicValueTypes::kPoint:
- list->expandToMinimumSize(ptrOrOffset + 1);
return pointWriteRefAttrib(list->getPoint()[ptrOrOffset], thread, proxy, attrib);
case DynamicValueTypes::kIntegerRange:
- list->expandToMinimumSize(ptrOrOffset + 1);
return list->getIntRange()[ptrOrOffset].refAttrib(thread, proxy, attrib);
case DynamicValueTypes::kVector:
- list->expandToMinimumSize(ptrOrOffset + 1);
return list->getVector()[ptrOrOffset].refAttrib(thread, proxy, attrib);
case DynamicValueTypes::kObject: {
- if (list->getSize() <= ptrOrOffset) {
- return kMiniscriptInstructionOutcomeFailed;
- }
-
Common::SharedPtr<RuntimeObject> obj = list->getObjectReference()[ptrOrOffset].object.lock();
proxy.containerList.reset();
if (!obj) {
@@ -1064,7 +1063,7 @@ MiniscriptInstructionOutcome DynamicList::WriteProxyInterface::refAttribIndexed(
subList->createWriteProxyForIndex(subIndex, proxy);
proxy.containerList = subList;
return kMiniscriptInstructionOutcomeContinue;
- }
+ } break;
case DynamicValueTypes::kObject: {
if (list->getSize() <= ptrOrOffset)
return kMiniscriptInstructionOutcomeFailed;
@@ -1075,7 +1074,7 @@ MiniscriptInstructionOutcome DynamicList::WriteProxyInterface::refAttribIndexed(
return kMiniscriptInstructionOutcomeFailed;
return kMiniscriptInstructionOutcomeContinue;
- }
+ } break;
default:
return kMiniscriptInstructionOutcomeFailed;
}
@@ -1375,22 +1374,78 @@ bool DynamicValue::roundToInt(int32 &outInt) const {
}
bool DynamicValue::convertToType(DynamicValueTypes::DynamicValueType targetType, DynamicValue &result) const {
+ if (_type == DynamicValueTypes::kObject && targetType != DynamicValueTypes::kObject) {
+ RuntimeObject *obj = this->_value.asObj.object.lock().get();
+ if (obj && obj->isModifier() && static_cast<Modifier *>(obj)->isVariable()) {
+ DynamicValue varContents;
+ static_cast<VariableModifier *>(obj)->varGetValue(varContents);
+ return varContents.convertToTypeNoDereference(targetType, result);
+ }
+ }
+
+ if (_type == DynamicValueTypes::kList && targetType != DynamicValueTypes::kList) {
+ if (_value.asList.get() && _value.asList->getSize() == 1) {
+ // Single-value lists are convertible
+ DynamicValue firstListElement;
+ (void)_value.asList->getAtIndex(0, firstListElement);
+
+ return firstListElement.convertToType(targetType, result);
+ }
+ }
+
+ return convertToTypeNoDereference(targetType, result);
+}
+
+DynamicValue DynamicValue::dereference() const {
+ if (_type == DynamicValueTypes::kObject) {
+ RuntimeObject *obj = this->_value.asObj.object.lock().get();
+ if (obj && obj->isModifier() && static_cast<Modifier *>(obj)->isVariable()) {
+ DynamicValue varContents;
+ static_cast<VariableModifier *>(obj)->varGetValue(varContents);
+ return varContents;
+ }
+ }
+
+ if (_type == DynamicValueTypes::kList) {
+ if (_value.asList.get() && _value.asList->getSize() == 1) {
+ // Single-value lists are convertible
+ DynamicValue firstListElement;
+ (void)_value.asList->getAtIndex(0, firstListElement);
+
+ return firstListElement;
+ }
+ }
+
+ return *this;
+}
+
+bool DynamicValue::convertToTypeNoDereference(DynamicValueTypes::DynamicValueType targetType, DynamicValue &result) const {
if (_type == targetType) {
result = *this;
return true;
}
switch (_type) {
+ case DynamicValueTypes::kNull:
+ if (targetType == DynamicValueTypes::kObject) {
+ result.setObject(Common::WeakPtr<RuntimeObject>());
+ return true;
+ }
+ break;
case DynamicValueTypes::kInteger:
return convertIntToType(targetType, result);
case DynamicValueTypes::kFloat:
return convertFloatToType(targetType, result);
case DynamicValueTypes::kBoolean:
return convertBoolToType(targetType, result);
+ case DynamicValueTypes::kString:
+ return convertStringToType(targetType, result);
default:
- warning("Couldn't convert dynamic value from source type");
- return false;
+ break;
}
+
+ warning("Couldn't convert dynamic value from source type");
+ return false;
}
void DynamicValue::setObject(const ObjectReference &value) {
@@ -1556,6 +1611,35 @@ bool DynamicValue::convertBoolToType(DynamicValueTypes::DynamicValueType targetT
}
}
+bool DynamicValue::convertStringToType(DynamicValueTypes::DynamicValueType targetType, DynamicValue &result) const {
+ const Common::String &value = this->getString();
+
+ // Docs say that strings are always false but they are not convertible
+ switch (targetType) {
+ case DynamicValueTypes::kInteger: {
+ // Passing float values is allowed, but they are truncated toward zero instead of rounded
+ double floatValue = 0;
+ if (sscanf(value.c_str(), "%lf", &floatValue))
+ result.setInt(static_cast<int>(floatValue));
+ else
+ result.setInt(0);
+ return true;
+ } break;
+ case DynamicValueTypes::kFloat: {
+ double floatValue = 0;
+ if (sscanf(value.c_str(), "%lf", &floatValue))
+ result.setFloat(floatValue);
+ else
+ result.setFloat(0.0);
+ return true;
+ } break;
+ default:
+ break;
+ }
+ warning("Unable to implicitly convert dynamic value");
+ return false;
+}
+
void DynamicValue::setFromOther(const DynamicValue &other) {
if (this == &other)
return;
@@ -1723,7 +1807,7 @@ DynamicValue DynamicValueSource::produceValue(const DynamicValue &incomingData)
return incomingData;
case DynamicValueSourceTypes::kVariableReference: {
Common::SharedPtr<Modifier> resolution = _valueUnion._varReference.resolution.lock();
- if (resolution->isVariable()) {
+ if (resolution && resolution->isVariable()) {
DynamicValue result;
static_cast<VariableModifier *>(resolution.get())->varGetValue(result);
return result;
@@ -1795,8 +1879,10 @@ void DynamicValueSource::initFromOther(DynamicValueSource &&other) {
}
MiniscriptInstructionOutcome DynamicValueWriteStringHelper::write(MiniscriptThread *thread, const DynamicValue &value, void *objectRef, uintptr ptrOrOffset) {
+ DynamicValue derefValue = value.dereference();
+
Common::String &dest = *static_cast<Common::String *>(objectRef);
- switch (value.getType()) {
+ switch (derefValue.getType()) {
case DynamicValueTypes::kString:
dest = value.getString();
return kMiniscriptInstructionOutcomeContinue;
@@ -1839,6 +1925,8 @@ void DynamicValueWriteDiscardHelper::create(DynamicValueWriteProxy &proxy) {
MiniscriptInstructionOutcome DynamicValueWritePointHelper::write(MiniscriptThread *thread, const DynamicValue &value, void *objectRef, uintptr ptrOrOffset) {
+ DynamicValue derefValue = value.dereference();
+
if (value.getType() != DynamicValueTypes::kPoint) {
thread->error("Can't set point to invalid type");
return kMiniscriptInstructionOutcomeFailed;
@@ -1874,10 +1962,12 @@ void DynamicValueWritePointHelper::create(Common::Point *pointValue, DynamicValu
}
MiniscriptInstructionOutcome DynamicValueWriteBoolHelper::write(MiniscriptThread *thread, const DynamicValue &value, void *objectRef, uintptr ptrOrOffset) {
+ DynamicValue derefValue = value.dereference();
+
bool &dest = *static_cast<bool *>(objectRef);
- switch (value.getType()) {
+ switch (derefValue.getType()) {
case DynamicValueTypes::kBoolean:
- dest = value.getBool();
+ dest = derefValue.getBool();
return kMiniscriptInstructionOutcomeContinue;
default:
return kMiniscriptInstructionOutcomeFailed;
@@ -2584,19 +2674,19 @@ bool WorldManagerInterface::readAttribute(MiniscriptThread *thread, DynamicValue
MiniscriptInstructionOutcome WorldManagerInterface::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "currentscene") {
- DynamicValueWriteFuncHelper<WorldManagerInterface, &WorldManagerInterface::setCurrentScene>::create(this, result);
+ DynamicValueWriteFuncHelper<WorldManagerInterface, &WorldManagerInterface::setCurrentScene, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
if (attrib == "refreshcursor") {
- DynamicValueWriteFuncHelper<WorldManagerInterface, &WorldManagerInterface::setRefreshCursor>::create(this, result);
+ DynamicValueWriteFuncHelper<WorldManagerInterface, &WorldManagerInterface::setRefreshCursor, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
if (attrib == "autoresetcursor") {
- DynamicValueWriteFuncHelper<WorldManagerInterface, &WorldManagerInterface::setAutoResetCursor>::create(this, result);
+ DynamicValueWriteFuncHelper<WorldManagerInterface, &WorldManagerInterface::setAutoResetCursor, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
if (attrib == "winsndbuffersize") {
- DynamicValueWriteFuncHelper<WorldManagerInterface, &WorldManagerInterface::setWinSndBufferSize>::create(this, result);
+ DynamicValueWriteFuncHelper<WorldManagerInterface, &WorldManagerInterface::setWinSndBufferSize, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
if (attrib == "gamemode") {
@@ -2709,19 +2799,19 @@ bool SystemInterface::readAttributeIndexed(MiniscriptThread *thread, DynamicValu
MiniscriptInstructionOutcome SystemInterface::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
if (attrib == "ejectcd") {
- DynamicValueWriteFuncHelper<SystemInterface, &SystemInterface::setEjectCD>::create(this, result);
+ DynamicValueWriteFuncHelper<SystemInterface, &SystemInterface::setEjectCD, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "gamemode") {
- DynamicValueWriteFuncHelper<SystemInterface, &SystemInterface::setGameMode>::create(this, result);
+ DynamicValueWriteFuncHelper<SystemInterface, &SystemInterface::setGameMode, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "mastervolume") {
- DynamicValueWriteFuncHelper<SystemInterface, &SystemInterface::setMasterVolume>::create(this, result);
+ DynamicValueWriteFuncHelper<SystemInterface, &SystemInterface::setMasterVolume, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "monitorbitdepth") {
- DynamicValueWriteFuncHelper<SystemInterface, &SystemInterface::setMonitorBitDepth>::create(this, result);
+ DynamicValueWriteFuncHelper<SystemInterface, &SystemInterface::setMonitorBitDepth, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "volumename") {
- DynamicValueWriteFuncHelper<SystemInterface, &SystemInterface::setVolumeName>::create(this, result);
+ DynamicValueWriteFuncHelper<SystemInterface, &SystemInterface::setVolumeName, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -2969,7 +3059,7 @@ MiniscriptInstructionOutcome Structural::writeRefAttribute(MiniscriptThread *thr
DynamicValueWriteStringHelper::create(&_name, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "paused") {
- DynamicValueWriteFuncHelper<Structural, &Structural::scriptSetPaused>::create(this, result);
+ DynamicValueWriteFuncHelper<Structural, &Structural::scriptSetPaused, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "this") {
// Yes, "this" is an attribute
@@ -3010,10 +3100,10 @@ MiniscriptInstructionOutcome Structural::writeRefAttribute(MiniscriptThread *thr
return kMiniscriptInstructionOutcomeFailed;
}
} else if (attrib == "loop") {
- DynamicValueWriteFuncHelper<Structural, &Structural::scriptSetLoop>::create(this, result);
+ DynamicValueWriteFuncHelper<Structural, &Structural::scriptSetLoop, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "debug") {
- DynamicValueWriteFuncHelper<Structural, &Structural::scriptSetDebug>::create(this, result);
+ DynamicValueWriteFuncHelper<Structural, &Structural::scriptSetDebug, true>::create(this, result);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "flushpriority") {
DynamicValueWriteIntegerHelper<int32>::create(&_flushPriority, result);
@@ -7801,10 +7891,10 @@ bool VisualElement::readAttribute(MiniscriptThread *thread, DynamicValue &result
MiniscriptInstructionOutcome VisualElement::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) {
if (attrib == "visible") {
- DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetVisibility>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetVisibility, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "direct") {
- DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetDirect>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetDirect, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "position") {
DynamicValueWriteOrRefAttribFuncHelper<VisualElement, &VisualElement::scriptSetPosition, &VisualElement::scriptWriteRefPositionAttribute>::create(this, writeProxy);
@@ -7813,13 +7903,13 @@ MiniscriptInstructionOutcome VisualElement::writeRefAttribute(MiniscriptThread *
DynamicValueWriteOrRefAttribFuncHelper<VisualElement, &VisualElement::scriptSetCenterPosition, &VisualElement::scriptWriteRefCenterPositionAttribute>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "width") {
- DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetWidth>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetWidth, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "height") {
- DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetHeight>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetHeight, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "layer") {
- DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetLayer>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetLayer, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -8152,10 +8242,10 @@ MiniscriptInstructionOutcome VisualElement::scriptSetLayer(MiniscriptThread *thr
MiniscriptInstructionOutcome VisualElement::scriptWriteRefPositionAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) {
if (attrib == "x") {
- DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetPositionX>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetPositionX, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "y") {
- DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetPositionY>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetPositionY, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -8164,10 +8254,10 @@ MiniscriptInstructionOutcome VisualElement::scriptWriteRefPositionAttribute(Mini
MiniscriptInstructionOutcome VisualElement::scriptWriteRefCenterPositionAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) {
if (attrib == "x") {
- DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetCenterPositionX>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetCenterPositionX, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
} else if (attrib == "y") {
- DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetCenterPositionY>::create(this, writeProxy);
+ DynamicValueWriteFuncHelper<VisualElement, &VisualElement::scriptSetCenterPositionY, true>::create(this, writeProxy);
return kMiniscriptInstructionOutcomeContinue;
}
@@ -8490,6 +8580,10 @@ bool VariableModifier::isVariable() const {
return true;
}
+bool VariableModifier::isListVariable() const {
+ return false;
+}
+
bool VariableModifier::readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) {
if (attrib == "value") {
varGetValue(result);
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index 37a31a5c599..d3fe79b85c7 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -856,6 +856,8 @@ struct DynamicValue {
bool convertToType(DynamicValueTypes::DynamicValueType targetType, DynamicValue &result) const;
+ DynamicValue dereference() const;
+
DynamicValue &operator=(const DynamicValue &other);
bool operator==(const DynamicValue &other) const;
@@ -903,6 +905,9 @@ private:
bool convertIntToType(DynamicValueTypes::DynamicValueType targetType, DynamicValue &result) const;
bool convertFloatToType(DynamicValueTypes::DynamicValueType targetType, DynamicValue &result) const;
bool convertBoolToType(DynamicValueTypes::DynamicValueType targetType, DynamicValue &result) const;
+ bool convertStringToType(DynamicValueTypes::DynamicValueType targetType, DynamicValue &result) const;
+
+ bool convertToTypeNoDereference(DynamicValueTypes::DynamicValueType targetType, DynamicValue &result) const;
void setFromOther(const DynamicValue &other);
@@ -951,13 +956,15 @@ private:
template<class TFloat>
struct DynamicValueWriteFloatHelper {
static MiniscriptInstructionOutcome write(MiniscriptThread *thread, const DynamicValue &value, void *objectRef, uintptr ptrOrOffset) {
+ DynamicValue derefValue = value.dereference();
+
TFloat &dest = *static_cast<TFloat *>(objectRef);
- switch (value.getType()) {
+ switch (derefValue.getType()) {
case DynamicValueTypes::kFloat:
- dest = static_cast<TFloat>(value.getFloat());
+ dest = static_cast<TFloat>(derefValue.getFloat());
return kMiniscriptInstructionOutcomeContinue;
case DynamicValueTypes::kInteger:
- dest = static_cast<TFloat>(value.getInt());
+ dest = static_cast<TFloat>(derefValue.getInt());
return kMiniscriptInstructionOutcomeContinue;
default:
return kMiniscriptInstructionOutcomeFailed;
@@ -980,13 +987,15 @@ struct DynamicValueWriteFloatHelper {
template<class TInteger>
struct DynamicValueWriteIntegerHelper {
static MiniscriptInstructionOutcome write(MiniscriptThread *thread, const DynamicValue &value, void *objectRef, uintptr ptrOrOffset) {
+ DynamicValue derefValue = value.dereference();
+
TInteger &dest = *static_cast<TInteger *>(objectRef);
- switch (value.getType()) {
+ switch (derefValue.getType()) {
case DynamicValueTypes::kFloat:
- dest = static_cast<TInteger>(floor(value.getFloat() + 0.5));
+ dest = static_cast<TInteger>(floor(derefValue.getFloat() + 0.5));
return kMiniscriptInstructionOutcomeContinue;
case DynamicValueTypes::kInteger:
- dest = static_cast<TInteger>(value.getInt());
+ dest = static_cast<TInteger>(derefValue.getInt());
return kMiniscriptInstructionOutcomeContinue;
default:
return kMiniscriptInstructionOutcomeFailed;
@@ -1041,7 +1050,9 @@ struct DynamicValueWriteDiscardHelper {
template<class TClass, MiniscriptInstructionOutcome (TClass::*TWriteMethod)(MiniscriptThread *thread, const DynamicValue &dest), MiniscriptInstructionOutcome (TClass::*TRefAttribMethod)(MiniscriptThread *thread, DynamicValueWriteProxy &proxy, const Common::String &attrib)>
struct DynamicValueWriteOrRefAttribFuncHelper {
static MiniscriptInstructionOutcome write(MiniscriptThread *thread, const DynamicValue &dest, void *objectRef, uintptr ptrOrOffset) {
- return (static_cast<TClass *>(objectRef)->*TWriteMethod)(thread, dest);
+ DynamicValue derefValue = dest.dereference();
+
+ return (static_cast<TClass *>(objectRef)->*TWriteMethod)(thread, derefValue);
}
static MiniscriptInstructionOutcome refAttrib(MiniscriptThread *thread, DynamicValueWriteProxy &proxy, void *objectRef, uintptr ptrOrOffset, const Common::String &attrib) {
return (static_cast<TClass *>(objectRef)->*TRefAttribMethod)(thread, proxy, attrib);
@@ -1057,10 +1068,13 @@ struct DynamicValueWriteOrRefAttribFuncHelper {
}
};
-template<class TClass, MiniscriptInstructionOutcome (TClass::*TWriteMethod)(MiniscriptThread *thread, const DynamicValue &dest)>
+template<class TClass, MiniscriptInstructionOutcome (TClass::*TWriteMethod)(MiniscriptThread *thread, const DynamicValue &dest), bool TDereference>
struct DynamicValueWriteFuncHelper {
static MiniscriptInstructionOutcome write(MiniscriptThread *thread, const DynamicValue &dest, void *objectRef, uintptr ptrOrOffset) {
- return (static_cast<TClass *>(objectRef)->*TWriteMethod)(thread, dest);
+ if (TDereference) {
+ return (static_cast<TClass *>(objectRef)->*TWriteMethod)(thread, dest.dereference());
+ } else
+ return (static_cast<TClass *>(objectRef)->*TWriteMethod)(thread, dest);
}
static MiniscriptInstructionOutcome refAttrib(MiniscriptThread *thread, DynamicValueWriteProxy &proxy, void *objectRef, uintptr ptrOrOffset, const Common::String &attrib) {
return kMiniscriptInstructionOutcomeFailed;
@@ -1072,7 +1086,7 @@ struct DynamicValueWriteFuncHelper {
static void create(TClass *obj, DynamicValueWriteProxy &proxy) {
proxy.pod.ptrOrOffset = 0;
proxy.pod.objectRef = obj;
- proxy.pod.ifc = DynamicValueWriteInterfaceGlue<DynamicValueWriteFuncHelper<TClass, TWriteMethod> >::getInstance();
+ proxy.pod.ifc = DynamicValueWriteInterfaceGlue<DynamicValueWriteFuncHelper<TClass, TWriteMethod, TDereference> >::getInstance();
}
};
@@ -2860,6 +2874,8 @@ protected:
class VariableModifier : public Modifier {
public:
virtual bool isVariable() const override;
+ virtual bool isListVariable() const;
+
virtual bool varSetValue(MiniscriptThread *thread, const DynamicValue &value) = 0;
virtual void varGetValue(DynamicValue &dest) const = 0;
virtual Common::SharedPtr<ModifierSaveLoad> getSaveLoad() override = 0;
diff --git a/engines/mtropolis/saveload.cpp b/engines/mtropolis/saveload.cpp
index 525b28a0acc..ebb82e8b5df 100644
--- a/engines/mtropolis/saveload.cpp
+++ b/engines/mtropolis/saveload.cpp
@@ -162,6 +162,14 @@ bool MTropolisEngine::load(ISaveReader *reader, const Common::String &saveFileNa
return false;
}
+ if (saveFileVersion < kEarliestSupportedSaveFileVersion) {
+ GUI::MessageDialog dialog(_("Saved game was created with an earlier, incompatible version of ScummVM. Unable to load."));
+ dialog.runModal();
+
+ warning("An error occurred while reading file '%s'", saveFileName.c_str());
+ return false;
+ }
+
if (!reader->readSave(in.get(), saveFileVersion)) {
GUI::MessageDialog dialog(_("Failed to load save, an error occurred when reading the save game data."));
dialog.runModal();
More information about the Scummvm-git-logs
mailing list