MTROPOLIS: Add more features required by MTI

This commit is contained in:
elasota 2022-09-25 20:44:02 -04:00
parent ccfe7fae69
commit 51221b846e
8 changed files with 211 additions and 8 deletions

View File

@ -117,6 +117,7 @@ bool isModifier(DataObjectType type) {
case kCursorModifierV1:
case kGradientModifier:
case kColorTableModifier:
case kSoundFadeModifier:
case kSaveAndRestoreModifier:
case kCompoundVariableModifier:
case kBooleanVariableModifier:
@ -126,8 +127,8 @@ bool isModifier(DataObjectType type) {
case kPointVariableModifier:
case kFloatingPointVariableModifier:
case kStringVariableModifier:
case kObjectReferenceVariableModifierV1:
case kPlugInModifier:
case kSoundFadeModifier:
case kDebris:
return true;
default:
@ -1267,11 +1268,12 @@ DataReadErrorCode SetModifier::load(DataReader &reader) {
}
AliasModifier::AliasModifier()
: modifierFlags(0), sizeIncludingTag(0), aliasIndexPlusOne(0), unknown1(0), unknown2(0), lengthOfName(0), guid(0), editorLayoutPosition(Point::createDefault()) {
: modifierFlags(0), sizeIncludingTag(0), aliasIndexPlusOne(0), unknown1(0), unknown2(0)
, lengthOfName(0), guid(0), editorLayoutPosition(Point::createDefault()), haveGUID(false) {
}
DataReadErrorCode AliasModifier::load(DataReader& reader) {
if (_revision != 2)
if (_revision > 2)
return kDataReadErrorUnsupportedRevision;
if (!reader.readU32(modifierFlags)
@ -1280,9 +1282,19 @@ DataReadErrorCode AliasModifier::load(DataReader& reader) {
|| !reader.readU32(unknown1)
|| !reader.readU32(unknown2)
|| !reader.readU16(lengthOfName)
|| !editorLayoutPosition.load(reader)
|| !reader.readU32(guid)
|| !reader.readTerminatedStr(name, lengthOfName))
|| !editorLayoutPosition.load(reader))
return kDataReadErrorReadFailed;
if (_revision >= 2) {
haveGUID = true;
if (!reader.readU32(guid))
return kDataReadErrorReadFailed;
} else {
haveGUID = false;
guid = 0;
}
if (!reader.readTerminatedStr(name, lengthOfName))
return kDataReadErrorReadFailed;
return kDataReadErrorNone;
@ -1802,6 +1814,19 @@ DataReadErrorCode StringVariableModifier::load(DataReader &reader) {
return kDataReadErrorNone;
}
ObjectReferenceVariableModifierV1::ObjectReferenceVariableModifierV1() : unknown1(0) {
}
DataReadErrorCode ObjectReferenceVariableModifierV1::load(DataReader &reader) {
if (_revision != 1000)
return kDataReadErrorUnsupportedRevision;
if (!modHeader.load(reader) || !reader.readU32(unknown1) || !setToSourcesParentWhen.load(reader))
return kDataReadErrorReadFailed;
return kDataReadErrorNone;
}
PlugInModifierData::~PlugInModifierData() {
}
@ -2401,6 +2426,9 @@ DataReadErrorCode loadDataObject(const PlugInModifierRegistry &registry, DataRea
case DataObjectTypes::kStringVariableModifier:
dataObject = new StringVariableModifier();
break;
case DataObjectTypes::kObjectReferenceVariableModifierV1:
dataObject = new ObjectReferenceVariableModifierV1();
break;
case DataObjectTypes::kDebris:
dataObject = new Debris();
break;

View File

@ -137,6 +137,7 @@ enum DataObjectType {
kPointVariableModifier = 0x326,
kFloatingPointVariableModifier = 0x328,
kStringVariableModifier = 0x329,
kObjectReferenceVariableModifierV1 = 0x33e,
kDebris = 0xfffffffe, // Deleted modifier in alias list
kPlugInModifier = 0xffffffff,
@ -1058,6 +1059,8 @@ struct AliasModifier : public DataObject {
Common::String name;
bool haveGUID;
protected:
DataReadErrorCode load(DataReader &reader) override;
};
@ -1670,6 +1673,17 @@ protected:
DataReadErrorCode load(DataReader &reader) override;
};
struct ObjectReferenceVariableModifierV1 : public DataObject {
ObjectReferenceVariableModifierV1();
TypicalModifierHeader modHeader;
uint32 unknown1;
Event setToSourcesParentWhen;
protected:
DataReadErrorCode load(DataReader &reader) override;
};
struct PlugInModifierData {
virtual ~PlugInModifierData();
virtual DataReadErrorCode load(PlugIn &plugIn, const PlugInModifier &prefix, DataReader &reader) = 0;

View File

@ -134,6 +134,8 @@ SIModifierFactory *getModifierFactoryForDataObjectType(const Data::DataObjectTyp
return ModifierFactory<FloatingPointVariableModifier, Data::FloatingPointVariableModifier>::getInstance();
case Data::DataObjectTypes::kStringVariableModifier:
return ModifierFactory<StringVariableModifier, Data::StringVariableModifier>::getInstance();
case Data::DataObjectTypes::kObjectReferenceVariableModifierV1:
return ModifierFactory<ObjectReferenceVariableModifierV1, Data::ObjectReferenceVariableModifierV1>::getInstance();
default:
warning("No modifier factory for type %x", static_cast<int>(dataObjectType));

View File

@ -365,16 +365,33 @@ VThreadState SaveAndRestoreModifier::consumeMessage(Runtime *runtime, const Comm
return kVThreadError;
}
// There doesn't appear to be any flag for this, it just uses the file path field
bool isPrompt = (_filePath == "Ask User");
if (_saveWhen.respondsTo(msg->getEvent())) {
CompoundVarSaver saver(obj);
if (runtime->getSaveProvider()->promptSave(&saver, runtime->getSaveScreenshotOverride().get())) {
bool succeeded = false;
if (isPrompt)
succeeded = runtime->getSaveProvider()->promptSave(&saver, runtime->getSaveScreenshotOverride().get());
else
succeeded = runtime->getSaveProvider()->namedSave(&saver, runtime->getSaveScreenshotOverride().get(), _fileName);
if (succeeded) {
for (const Common::SharedPtr<SaveLoadHooks> &hooks : runtime->getHacks().saveLoadHooks)
hooks->onSave(runtime, this, static_cast<Modifier *>(obj));
}
return kVThreadReturn;
} else if (_restoreWhen.respondsTo(msg->getEvent())) {
CompoundVarLoader loader(obj);
if (runtime->getLoadProvider()->promptLoad(&loader)) {
bool succeeded = false;
if (isPrompt)
runtime->getLoadProvider()->promptLoad(&loader);
else
runtime->getLoadProvider()->namedLoad(&loader, _fileName);
if (succeeded) {
for (const Common::SharedPtr<SaveLoadHooks> &hooks : runtime->getHacks().saveLoadHooks)
hooks->onLoad(runtime, this, static_cast<Modifier *>(obj));
}
@ -2815,4 +2832,72 @@ bool StringVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream,
return true;
}
bool ObjectReferenceVariableModifierV1::load(ModifierLoaderContext &context, const Data::ObjectReferenceVariableModifierV1 &data) {
if (!loadTypicalHeader(data.modHeader))
return false;
if (!_setToSourcesParentWhen.load(data.setToSourcesParentWhen))
return false;
return true;
}
bool ObjectReferenceVariableModifierV1::respondsToEvent(const Event &evt) const {
return _setToSourcesParentWhen.respondsTo(evt);
}
VThreadState ObjectReferenceVariableModifierV1::consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
if (msg->getEvent().respondsTo(_setToSourcesParentWhen)) {
warning("Set to source's parent is not implemented");
}
return kVThreadError;
}
Common::SharedPtr<ModifierSaveLoad> ObjectReferenceVariableModifierV1::getSaveLoad() {
return Common::SharedPtr<ModifierSaveLoad>(new SaveLoad(this));
}
bool ObjectReferenceVariableModifierV1::varSetValue(MiniscriptThread *thread, const DynamicValue &value) {
if (value.getType() == DynamicValueTypes::kNull)
_value.reset();
else if (value.getType() == DynamicValueTypes::kObject)
_value = value.getObject().object;
else
return false;
return true;
}
void ObjectReferenceVariableModifierV1::varGetValue(MiniscriptThread *thread, DynamicValue &dest) const {
if (_value.expired())
dest.clear();
else
dest.setObject(_value);
}
Common::SharedPtr<Modifier> ObjectReferenceVariableModifierV1::shallowClone() const {
return Common::SharedPtr<Modifier>(new ObjectReferenceVariableModifierV1(*this));
}
const char *ObjectReferenceVariableModifierV1::getDefaultName() const {
return "Object Reference Variable";
}
ObjectReferenceVariableModifierV1::SaveLoad::SaveLoad(ObjectReferenceVariableModifierV1 *modifier) : _modifier(modifier) {
}
void ObjectReferenceVariableModifierV1::SaveLoad::commitLoad() const {
_modifier->_value = _value;
}
void ObjectReferenceVariableModifierV1::SaveLoad::saveInternal(Common::WriteStream *stream) const {
error("Saving version 1 object reference variables is not currently supported");
}
bool ObjectReferenceVariableModifierV1::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
return true;
}
} // End of namespace MTropolis

View File

@ -1178,6 +1178,44 @@ private:
Common::String _value;
};
class ObjectReferenceVariableModifierV1 : public VariableModifier {
public:
bool load(ModifierLoaderContext &context, const Data::ObjectReferenceVariableModifierV1 &data);
bool respondsToEvent(const Event &evt) const override;
VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
Common::SharedPtr<ModifierSaveLoad> getSaveLoad() override;
bool varSetValue(MiniscriptThread *thread, const DynamicValue &value) override;
void varGetValue(MiniscriptThread *thread, DynamicValue &dest) const override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Object Reference Variable Modifier V1"; }
SupportStatus debugGetSupportStatus() const override { return kSupportStatusNone; }
#endif
private:
class SaveLoad : public ModifierSaveLoad {
public:
explicit SaveLoad(ObjectReferenceVariableModifierV1 *modifier);
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
ObjectReferenceVariableModifierV1 *_modifier;
Common::WeakPtr<RuntimeObject> _value;
};
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
Common::WeakPtr<RuntimeObject> _value;
Event _setToSourcesParentWhen;
};
} // End of namespace MTropolis
#endif

View File

@ -59,8 +59,10 @@ public:
Common::Platform getPlatform() const;
bool promptSave(ISaveWriter *writer, const Graphics::Surface *screenshotOverride) override;
bool namedSave(ISaveWriter *writer, const Graphics::Surface *screenshotOverride, const Common::String &fileName) override;
bool autoSave(ISaveWriter *writer) override;
bool promptLoad(ISaveReader *reader) override;
bool namedLoad(ISaveReader *reader, const Common::String &fileName) override;
const Graphics::Surface *getSavegameScreenshot() const;
@ -75,6 +77,11 @@ protected:
void pauseEngineIntern(bool pause) override;
private:
bool save(ISaveWriter *writer, const Graphics::Surface *screenshotOverride, const Common::String &fileName, const Common::String &desc);
bool load(ISaveReader *reader, const Common::String &fileName);
Common::String getUnpromptedSaveFileName(const Common::String &fileName);
static const uint kCurrentSaveFileVersion = 1;
static const uint kSavegameSignature = 0x6d545356; // mTSV

View File

@ -87,6 +87,12 @@ bool MTropolisEngine::promptSave(ISaveWriter *writer, const Graphics::Surface *s
return true;
Common::String saveFileName = getSaveStateName(slot);
return save(writer, screenshotOverride, saveFileName, desc);
}
bool MTropolisEngine::save(ISaveWriter *writer, const Graphics::Surface *screenshotOverride, const Common::String &saveFileName, const Common::String &desc) {
Common::SharedPtr<Common::OutSaveFile> out(_saveFileMan->openForSaving(saveFileName, false));
ISaveWriter *oldWriter = _saveWriter;
@ -102,6 +108,10 @@ bool MTropolisEngine::promptSave(ISaveWriter *writer, const Graphics::Surface *s
return true;
}
bool MTropolisEngine::namedSave(ISaveWriter *writer, const Graphics::Surface *screenshotOverride, const Common::String &fileName) {
return save(writer, screenshotOverride, getUnpromptedSaveFileName(fileName), fileName);
}
bool MTropolisEngine::promptLoad(ISaveReader *reader) {
Common::String desc;
int slot;
@ -115,7 +125,16 @@ bool MTropolisEngine::promptLoad(ISaveReader *reader) {
return true;
Common::String saveFileName = getSaveStateName(slot);
return load(reader, saveFileName);
}
bool MTropolisEngine::load(ISaveReader *reader, const Common::String &saveFileName) {
Common::SharedPtr<Common::InSaveFile> in(_saveFileMan->openForLoading(saveFileName));
if (!in) {
warning("An error occurred while attempting to open save file '%s'", saveFileName.c_str());
return false;
}
uint32 signature = in->readUint32BE();
uint32 saveFileVersion = in->readUint32BE();
@ -154,6 +173,14 @@ bool MTropolisEngine::promptLoad(ISaveReader *reader) {
return true;
}
Common::String MTropolisEngine::getUnpromptedSaveFileName(const Common::String &fileName) {
return _targetName + "." + toCaseInsensitive(fileName);
}
bool MTropolisEngine::namedLoad(ISaveReader *reader, const Common::String &fileName) {
return load(reader, getUnpromptedSaveFileName(fileName));
}
bool MTropolisEngine::autoSave(ISaveWriter *writer) {
ISaveWriter *oldWriter = _saveWriter;
bool oldIsTriggeredAutosave = _isTriggeredAutosave;

View File

@ -53,10 +53,12 @@ struct ISaveReader : public IInterfaceBase {
struct ISaveUIProvider : public IInterfaceBase {
virtual bool promptSave(ISaveWriter *writer, const Graphics::Surface *screenshotOverride) = 0;
virtual bool namedSave(ISaveWriter *writer, const Graphics::Surface *screenshotOverride, const Common::String &fileName) = 0;
};
struct ILoadUIProvider : public IInterfaceBase {
virtual bool promptLoad(ISaveReader *reader) = 0;
virtual bool namedLoad(ISaveReader *reader, const Common::String &fileName) = 0;
};
struct IAutoSaveProvider : public IInterfaceBase {