Files
2026-02-02 04:50:13 +01:00

503 lines
18 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MTROPOLIS_PLUGIN_STANDARD_H
#define MTROPOLIS_PLUGIN_STANDARD_H
#include "mtropolis/modifiers.h"
#include "mtropolis/modifier_factory.h"
#include "mtropolis/runtime.h"
#include "mtropolis/plugin/standard_data.h"
namespace MTropolis {
class Runtime;
namespace Standard {
class StandardPlugIn;
class CursorModifier : public Modifier {
public:
CursorModifier();
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::CursorModifier &data);
bool respondsToEvent(const Event &evt) const override;
VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
void disable(Runtime *runtime) override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Cursor Modifier"; }
SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
#endif
private:
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
Event _applyWhen;
Event _removeWhen;
uint32 _cursorID;
};
// This appears to be basically a duplicate of scene transition modifier, except unlike that,
// its parameters are controllable via script, and the duration scaling appears to be different
// (probably 600000 max rate instead of 6000000)
class STransCtModifier : public Modifier {
public:
static const int32 kMaxDuration = 600000;
STransCtModifier();
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::STransCtModifier &data);
bool respondsToEvent(const Event &evt) const override;
VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
void disable(Runtime *runtime) override;
bool readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) override;
MiniscriptInstructionOutcome writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "STransCt Scene Transition Modifier"; }
SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
#endif
private:
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
MiniscriptInstructionOutcome scriptSetRate(MiniscriptThread *thread, const DynamicValue &value);
MiniscriptInstructionOutcome scriptSetSteps(MiniscriptThread *thread, const DynamicValue &value);
Event _enableWhen;
Event _disableWhen;
int32 _transitionType;
int32 _transitionDirection;
int32 _steps;
int32 _duration;
bool _fullScreen;
};
class MediaCueMessengerModifier : public Modifier, public IMediaCueModifier {
public:
MediaCueMessengerModifier();
~MediaCueMessengerModifier();
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::MediaCueMessengerModifier &data);
bool respondsToEvent(const Event &evt) const override;
VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
void disable(Runtime *runtime) override;
Modifier *getMediaCueModifier() override;
Common::WeakPtr<Modifier> getMediaCueTriggerSource() const override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Media Cue Modifier"; }
SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
#endif
private:
enum CueSourceType {
kCueSourceInteger,
kCueSourceIntegerRange,
kCueSourceVariableReference,
kCueSourceLabel,
kCueSourceString,
kCueSourceInvalid = -1,
};
union CueSourceUnion {
CueSourceUnion();
~CueSourceUnion();
int32 asInt;
IntRange asIntRange;
uint32 asVarRefGUID;
Label asLabel;
uint64 asUnset;
Common::String asString;
template<class T, T (CueSourceUnion::*TMember)>
void construct(const T &value);
template<class T, T(CueSourceUnion::*TMember)>
void destruct();
};
MediaCueMessengerModifier(const MediaCueMessengerModifier &other);
void destructCueSource();
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
void linkInternalReferences(ObjectLinkingScope *scope) override;
void visitInternalReferences(IStructuralReferenceVisitor *visitor) override;
CueSourceType _cueSourceType;
CueSourceUnion _cueSource;
Common::WeakPtr<Modifier> _cueSourceModifier;
Event _enableWhen;
Event _disableWhen;
MediaCueState _mediaCue;
bool _isActive;
};
class ObjectReferenceVariableModifier : public VariableModifier {
public:
ObjectReferenceVariableModifier();
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::ObjectReferenceVariableModifier &data);
bool varSetValue(MiniscriptThread *thread, const DynamicValue &value) override;
void varGetValue(DynamicValue &dest) const override;
bool readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) override;
MiniscriptInstructionOutcome writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Object Reference Variable Modifier"; }
SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
void debugInspect(IDebugInspectionReport *report) const override;
#endif
private:
struct ObjectWriteInterface {
static MiniscriptInstructionOutcome write(MiniscriptThread *thread, const DynamicValue &dest, void *objectRef, uintptr ptrOrOffset);
static MiniscriptInstructionOutcome refAttrib(MiniscriptThread *thread, DynamicValueWriteProxy &proxy, void *objectRef, uintptr ptrOrOffset, const Common::String &attrib);
static MiniscriptInstructionOutcome refAttribIndexed(MiniscriptThread *thread, DynamicValueWriteProxy &proxy, void *objectRef, uintptr ptrOrOffset, const Common::String &attrib, const DynamicValue &index);
};
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
MiniscriptInstructionOutcome scriptSetPath(MiniscriptThread *thread, const DynamicValue &value);
MiniscriptInstructionOutcome scriptSetObject(MiniscriptThread *thread, const DynamicValue &value);
MiniscriptInstructionOutcome scriptObjectRefAttrib(MiniscriptThread *thread, DynamicValueWriteProxy &proxy, const Common::String &attrib);
MiniscriptInstructionOutcome scriptObjectRefAttribIndexed(MiniscriptThread *thread, DynamicValueWriteProxy &proxy, const Common::String &attrib, const DynamicValue &index);
void resolve(Runtime *runtime);
void resolveRelativePath(Runtime *runtime, RuntimeObject *obj, const Common::String &path, size_t startPos);
void resolveAbsolutePath(Runtime *runtime);
static bool computeObjectPath(RuntimeObject *obj, Common::String &outPath);
static RuntimeObject *getObjectParent(RuntimeObject *obj);
Event _setToSourceParentWhen;
};
class ObjectReferenceVariableStorage : public VariableStorage {
public:
friend class ObjectReferenceVariableModifier;
ObjectReferenceVariableStorage();
Common::SharedPtr<ModifierSaveLoad> getSaveLoad(Runtime *runtime) override;
Common::SharedPtr<VariableStorage> clone() const override;
private:
class SaveLoad : public ModifierSaveLoad {
public:
explicit SaveLoad(ObjectReferenceVariableStorage *storage);
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
ObjectReferenceVariableStorage *_storage;
Common::String _objectPath;
};
Common::String _fullPath;
Common::String _objectPath;
mutable ObjectReference _object;
};
class ListVariableStorage : public VariableStorage {
public:
friend class ListVariableModifier;
ListVariableStorage();
Common::SharedPtr<ModifierSaveLoad> getSaveLoad(Runtime *runtime) override;
Common::SharedPtr<VariableStorage> clone() const override;
private:
class SaveLoad : public ModifierSaveLoad {
public:
explicit SaveLoad(ListVariableStorage *storage);
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
static void recursiveWriteList(DynamicList *list, Common::WriteStream *stream);
static Common::SharedPtr<DynamicList> recursiveReadList(Common::ReadStream *stream);
ListVariableStorage *_storage;
Common::SharedPtr<DynamicList> _list;
};
Common::SharedPtr<DynamicList> _list;
DynamicValueTypes::DynamicValueType _preferredContentType;
};
class ListVariableModifier : public VariableModifier {
public:
ListVariableModifier();
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::ListVariableModifier &data);
bool varSetValue(MiniscriptThread *thread, const DynamicValue &value) override;
void varGetValue(DynamicValue &dest) const override;
bool isListVariable() const override;
bool readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) override;
bool readAttributeIndexed(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib, const DynamicValue &index) override;
MiniscriptInstructionOutcome writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) override;
MiniscriptInstructionOutcome writeRefAttributeIndexed(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib, const DynamicValue &index) override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "List Variable Modifier"; }
SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
void debugInspect(IDebugInspectionReport *report) const override;
#endif
private:
MiniscriptInstructionOutcome scriptSetCount(MiniscriptThread *thread, const DynamicValue &value);
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
};
class SysInfoModifier : public Modifier {
public:
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::SysInfoModifier &data);
bool readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) override;
void disable(Runtime *runtime) override {}
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "System Info Modifier"; }
#endif
private:
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
};
struct StandardPlugInHacks {
StandardPlugInHacks();
// If list mod values are illegible, just ignore them and flag it as garbled.
// Necessary to load object 00788ab9 (olL437Check) in Obsidian, which is supposed to be a list of
// 4 lists that are 3-size each, in the persistent data, but actually contains 4 identical values
// that appear to be garbage.
bool allowGarbledListModData;
};
class PanningModifier : public Modifier {
public:
PanningModifier();
~PanningModifier();
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::PanningModifier &data);
bool respondsToEvent(const Event &evt) const override;
VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
void disable(Runtime *runtime) override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Panning Modifier"; }
void debugInspect(IDebugInspectionReport *report) const override;
#endif
private:
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
};
class FadeModifier : public Modifier {
public:
FadeModifier();
~FadeModifier();
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::FadeModifier &data);
void disable(Runtime *runtime) override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Fade Modifier"; }
#endif
private:
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
};
class PrintModifier : public Modifier {
public:
PrintModifier();
~PrintModifier();
bool respondsToEvent(const Event &evt) const override;
VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
void disable(Runtime *runtime) override;
MiniscriptInstructionOutcome writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) override;
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::PrintModifier &data);
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Print Modifier"; }
void debugInspect(IDebugInspectionReport *report) const override;
#endif
private:
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
Event _executeWhen;
Common::String _filePath;
};
class NavigateModifier : public Modifier {
public:
NavigateModifier();
~NavigateModifier();
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::NavigateModifier &data);
bool respondsToEvent(const Event &evt) const override;
VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
void disable(Runtime *runtime) override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Navigate Modifier"; }
void debugInspect(IDebugInspectionReport *report) const override;
#endif
private:
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
};
class OpenTitleModifier : public Modifier {
public:
OpenTitleModifier();
~OpenTitleModifier();
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::OpenTitleModifier &data);
bool respondsToEvent(const Event &evt) const override;
VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
void disable(Runtime *runtime) override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Open Title Modifier"; }
void debugInspect(IDebugInspectionReport *report) const override;
#endif
private:
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
Event _executeWhen;
Common::String _pathOrUrl;
bool _addToReturnList;
};
class OpenAppModifier : public Modifier {
public:
OpenAppModifier();
~OpenAppModifier();
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::OpenAppModifier &data);
bool respondsToEvent(const Event &evt) const override;
VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
void disable(Runtime *runtime) override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Open App Modifier"; }
void debugInspect(IDebugInspectionReport *report) const override;
#endif
private:
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
Event _executeWhen;
Common::String _pathOrUrl;
bool _addToReturnList;
};
class StandardPlugIn : public MTropolis::PlugIn {
public:
StandardPlugIn();
~StandardPlugIn();
void registerModifiers(IPlugInModifierRegistrar *registrar) const override;
const StandardPlugInHacks &getHacks() const;
StandardPlugInHacks &getHacks();
private:
PlugInModifierFactory<CursorModifier, Data::Standard::CursorModifier> _cursorModifierFactory;
PlugInModifierFactory<STransCtModifier, Data::Standard::STransCtModifier> _sTransCtModifierFactory;
PlugInModifierFactory<MediaCueMessengerModifier, Data::Standard::MediaCueMessengerModifier> _mediaCueModifierFactory;
PlugInModifierFactory<ObjectReferenceVariableModifier, Data::Standard::ObjectReferenceVariableModifier> _objRefVarModifierFactory;
PlugInModifierFactory<ListVariableModifier, Data::Standard::ListVariableModifier> _listVarModifierFactory;
PlugInModifierFactory<SysInfoModifier, Data::Standard::SysInfoModifier> _sysInfoModifierFactory;
PlugInModifierFactory<PanningModifier, Data::Standard::PanningModifier> _panningModifierFactory;
PlugInModifierFactory<FadeModifier, Data::Standard::FadeModifier> _fadeModifierFactory;
PlugInModifierFactory<PrintModifier, Data::Standard::PrintModifier> _printModifierFactory;
PlugInModifierFactory<NavigateModifier, Data::Standard::NavigateModifier> _navigateModifierFactory;
PlugInModifierFactory<OpenTitleModifier, Data::Standard::OpenTitleModifier> _openTitleModifierFactory;
PlugInModifierFactory<OpenAppModifier, Data::Standard::OpenAppModifier> _openAppModifierFactory;
StandardPlugInHacks _hacks;
};
} // End of namespace Standard
} // End of namespace MTropolis
#endif