/* 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 . * */ #include "common/debug.h" #include "common/file.h" #include "common/hash-ptr.h" #include "common/macresman.h" #include "common/random.h" #include "common/substream.h" #include "common/system.h" #include "graphics/cursorman.h" #include "graphics/managed_surface.h" #include "graphics/paletteman.h" #include "graphics/surface.h" #include "graphics/wincursor.h" #include "graphics/maccursor.h" #include "graphics/macgui/macfontmanager.h" #include "audio/mixer.h" #include "mtropolis/runtime.h" #include "mtropolis/coroutine_manager.h" #include "mtropolis/coroutines.h" #include "mtropolis/data.h" #include "mtropolis/vthread.h" #include "mtropolis/asset_factory.h" #include "mtropolis/element_factory.h" #include "mtropolis/miniscript.h" #include "mtropolis/modifier_factory.h" #include "mtropolis/modifiers.h" #include "mtropolis/render.h" namespace MTropolis { int32 displayModeToBitDepth(ColorDepthMode displayMode) { switch (displayMode) { case kColorDepthMode1Bit: return 1; case kColorDepthMode2Bit: return 2; case kColorDepthMode4Bit: return 4; case kColorDepthMode8Bit: return 8; case kColorDepthMode16Bit: return 16; case kColorDepthMode32Bit: return 32; default: return 0; } } ColorDepthMode bitDepthToDisplayMode(int32 bits) { switch (bits) { case 1: return kColorDepthMode1Bit; case 2: return kColorDepthMode2Bit; case 4: return kColorDepthMode4Bit; case 8: return kColorDepthMode8Bit; case 16: return kColorDepthMode16Bit; case 32: return kColorDepthMode32Bit; default: return kColorDepthModeInvalid; } } class MainWindow : public Window { public: MainWindow(const WindowParameters &windowParams); void onMouseDown(int32 x, int32 y, int mouseButton) override; void onMouseMove(int32 x, int32 y) override; void onMouseUp(int32 x, int32 y, int mouseButton) override; void onKeyboardEvent(const Common::EventType evtType, bool repeat, const Common::KeyState &keyEvt) override; void onAction(MTropolis::Actions::Action action) override; private: bool _mouseButtonStates[Actions::kMouseButtonCount]; }; MainWindow::MainWindow(const WindowParameters &windowParams) : Window(windowParams) { for (int i = 0; i < Actions::kMouseButtonCount; i++) _mouseButtonStates[i] = false; } void MainWindow::onMouseDown(int32 x, int32 y, int mouseButton) { if (!_mouseButtonStates[mouseButton]) { _mouseButtonStates[mouseButton] = true; if (mouseButton == Actions::kMouseButtonLeft) { _runtime->queueOSEvent(Common::SharedPtr(new MouseInputEvent(kOSEventTypeMouseDown, x, y, static_cast(mouseButton)))); } } } void MainWindow::onMouseMove(int32 x, int32 y) { _runtime->queueOSEvent(Common::SharedPtr(new MouseInputEvent(kOSEventTypeMouseMove, x, y, Actions::kMouseButtonLeft))); } void MainWindow::onMouseUp(int32 x, int32 y, int mouseButton) { if (_mouseButtonStates[mouseButton]) { _mouseButtonStates[mouseButton] = false; if (mouseButton == Actions::kMouseButtonLeft) { _runtime->queueOSEvent(Common::SharedPtr(new MouseInputEvent(kOSEventTypeMouseUp, x, y, static_cast(mouseButton)))); } } } void MainWindow::onKeyboardEvent(const Common::EventType evtType, bool repeat, const Common::KeyState &keyEvt) { _runtime->queueOSEvent(Common::SharedPtr(new KeyboardInputEvent(kOSEventTypeKeyboard, evtType, repeat, keyEvt))); } void MainWindow::onAction(MTropolis::Actions::Action action) { _runtime->queueOSEvent(Common::SharedPtr(new ActionEvent(kOSEventTypeAction, action))); } class ModifierInnerScopeBuilder : public IStructuralReferenceVisitor { public: ModifierInnerScopeBuilder(Runtime *runtime, Modifier *modifier, ObjectLinkingScope *scope); void visitChildStructuralRef(Common::SharedPtr &structural) override; void visitChildModifierRef(Common::SharedPtr &modifier) override; void visitWeakStructuralRef(Common::WeakPtr &structural) override; void visitWeakModifierRef(Common::WeakPtr &modifier) override; private: ObjectLinkingScope *_scope; Modifier *_modifier; Runtime *_runtime; }; ModifierInnerScopeBuilder::ModifierInnerScopeBuilder(Runtime *runtime, Modifier *modifier, ObjectLinkingScope *scope) : _scope(scope), _modifier(modifier), _runtime(runtime) { } void ModifierInnerScopeBuilder::visitChildStructuralRef(Common::SharedPtr &structural) { assert(false); } void ModifierInnerScopeBuilder::visitChildModifierRef(Common::SharedPtr &modifier) { uint32 oldStaticGUID = modifier->getStaticGUID(); _runtime->instantiateIfAlias(modifier, _modifier->getSelfReference()); _scope->addObject(oldStaticGUID, modifier->getName(), modifier); } void ModifierInnerScopeBuilder::visitWeakStructuralRef(Common::WeakPtr &structural) { } void ModifierInnerScopeBuilder::visitWeakModifierRef(Common::WeakPtr &modifier) { // Do nothing } class ModifierChildMaterializer : public IStructuralReferenceVisitor { public: ModifierChildMaterializer(Runtime *runtime, ObjectLinkingScope *outerScope); void visitChildStructuralRef(Common::SharedPtr &structural) override; void visitChildModifierRef(Common::SharedPtr &modifier) override; void visitWeakStructuralRef(Common::WeakPtr &structural) override; void visitWeakModifierRef(Common::WeakPtr &modifier) override; private: Runtime *_runtime; ObjectLinkingScope *_outerScope; }; ModifierChildMaterializer::ModifierChildMaterializer(Runtime *runtime, ObjectLinkingScope *outerScope) : _runtime(runtime), _outerScope(outerScope) { } void ModifierChildMaterializer::visitChildStructuralRef(Common::SharedPtr &structural) { assert(false); } void ModifierChildMaterializer::visitChildModifierRef(Common::SharedPtr &modifier) { modifier->materialize(_runtime, _outerScope); } void ModifierChildMaterializer::visitWeakStructuralRef(Common::WeakPtr &structural) { // Do nothing } void ModifierChildMaterializer::visitWeakModifierRef(Common::WeakPtr &modifier) { // Do nothing } class ModifierChildCloner : public IStructuralReferenceVisitor { public: ModifierChildCloner(Runtime *runtime, const Common::WeakPtr &relinkParent); void visitChildStructuralRef(Common::SharedPtr &structural) override; void visitChildModifierRef(Common::SharedPtr &modifier) override; void visitWeakStructuralRef(Common::WeakPtr &structural) override; void visitWeakModifierRef(Common::WeakPtr &modifier) override; private: Runtime *_runtime; Common::WeakPtr _relinkParent; }; ModifierChildCloner::ModifierChildCloner(Runtime *runtime, const Common::WeakPtr &relinkParent) : _runtime(runtime), _relinkParent(relinkParent) { } void ModifierChildCloner::visitChildStructuralRef(Common::SharedPtr &structural) { assert(false); } void ModifierChildCloner::visitChildModifierRef(Common::SharedPtr &modifier) { uint32 oldGUID = modifier->getStaticGUID(); modifier = modifier->shallowClone(); assert(modifier->getStaticGUID() == oldGUID); (void)oldGUID; modifier->setSelfReference(modifier); modifier->setParent(_relinkParent); ModifierChildCloner recursiveCloner(_runtime, modifier); modifier->visitInternalReferences(&recursiveCloner); } void ModifierChildCloner::visitWeakStructuralRef(Common::WeakPtr &structural) { // Do nothing } void ModifierChildCloner::visitWeakModifierRef(Common::WeakPtr &modifier) { // Do nothing } class ObjectCloner : public IStructuralReferenceVisitor { public: ObjectCloner(Runtime *runtime, const Common::WeakPtr &relinkParent, Common::HashMap *objectRemaps); void visitChildStructuralRef(Common::SharedPtr &structural) override; void visitChildModifierRef(Common::SharedPtr &modifier) override; void visitWeakStructuralRef(Common::WeakPtr &structural) override; void visitWeakModifierRef(Common::WeakPtr &modifier) override; private: Runtime *_runtime; Common::WeakPtr _relinkParent; Common::HashMap *_objectRemaps; }; ObjectCloner::ObjectCloner(Runtime *runtime, const Common::WeakPtr &relinkParent, Common::HashMap *objectRemaps) : _runtime(runtime), _relinkParent(relinkParent), _objectRemaps(objectRemaps) { } void ObjectCloner::visitChildStructuralRef(Common::SharedPtr &structuralRef) { uint32 oldGUID = structuralRef->getStaticGUID(); Common::SharedPtr cloned = structuralRef->shallowClone(); assert(cloned->getStaticGUID() == oldGUID); (void)oldGUID; if (_objectRemaps) (*_objectRemaps)[structuralRef.get()] = cloned.get(); assert(!_relinkParent.expired() && _relinkParent.lock()->isStructural()); cloned->setSelfReference(cloned); cloned->setRuntimeGUID(_runtime->allocateRuntimeGUID()); cloned->setParent(static_cast(_relinkParent.lock().get())); ObjectCloner recursiveCloner(_runtime, cloned, _objectRemaps); cloned->visitInternalReferences(&recursiveCloner); structuralRef = cloned; } void ObjectCloner::visitChildModifierRef(Common::SharedPtr &modifierRef) { uint32 oldGUID = modifierRef->getStaticGUID(); Common::SharedPtr cloned = modifierRef->shallowClone(); assert(cloned->getStaticGUID() == oldGUID); (void)oldGUID; if (_objectRemaps) (*_objectRemaps)[modifierRef.get()] = cloned.get(); cloned->setSelfReference(cloned); cloned->setRuntimeGUID(_runtime->allocateRuntimeGUID()); cloned->setParent(_relinkParent); ObjectCloner recursiveCloner(_runtime, cloned, _objectRemaps); cloned->visitInternalReferences(&recursiveCloner); modifierRef = cloned; } void ObjectCloner::visitWeakStructuralRef(Common::WeakPtr &structural) { // Do nothing } void ObjectCloner::visitWeakModifierRef(Common::WeakPtr &modifier) { // Do nothing } class ObjectRefRemapper : public IStructuralReferenceVisitor { public: explicit ObjectRefRemapper(const Common::HashMap &objectRemaps); void visitChildStructuralRef(Common::SharedPtr &structural) override; void visitChildModifierRef(Common::SharedPtr &modifier) override; void visitWeakStructuralRef(Common::WeakPtr &structural) override; void visitWeakModifierRef(Common::WeakPtr &modifier) override; private: const Common::HashMap &_objectRemaps; }; ObjectRefRemapper::ObjectRefRemapper(const Common::HashMap &objectRemaps) : _objectRemaps(objectRemaps) { } void ObjectRefRemapper::visitChildStructuralRef(Common::SharedPtr &structural) { RuntimeObject *obj = structural.get(); if (obj) { Common::HashMap ::const_iterator it = _objectRemaps.find(obj); if (it != _objectRemaps.end()) structural = it->_value->getSelfReference().lock().staticCast(); } } void ObjectRefRemapper::visitChildModifierRef(Common::SharedPtr &modifier) { RuntimeObject *obj = modifier.get(); if (obj) { Common::HashMap::const_iterator it = _objectRemaps.find(obj); if (it != _objectRemaps.end()) modifier = it->_value->getSelfReference().lock().staticCast(); } } void ObjectRefRemapper::visitWeakStructuralRef(Common::WeakPtr &structural) { RuntimeObject *obj = structural.lock().get(); if (obj) { Common::HashMap::const_iterator it = _objectRemaps.find(obj); if (it != _objectRemaps.end()) structural = it->_value->getSelfReference().staticCast(); } } void ObjectRefRemapper::visitWeakModifierRef(Common::WeakPtr &modifier) { RuntimeObject *obj = modifier.lock().get(); if (obj) { Common::HashMap::const_iterator it = _objectRemaps.find(obj); if (it != _objectRemaps.end()) modifier = it->_value->getSelfReference().staticCast(); } } char invariantToLower(char c) { if (c >= 'A' && c <= 'Z') return static_cast(c - 'A' + 'a'); return c; } Common::String toCaseInsensitive(const Common::String &str) { uint strLen = str.size(); if (strLen == 0) return str; // TODO: Figure out how this is supposed to behave with respect to non-ASCII characters Common::Array lowered; lowered.resize(strLen); for (uint i = 0; i < strLen; i++) lowered[i] = invariantToLower(str[i]); return Common::String(&lowered[0], strLen); } bool caseInsensitiveEqual(const Common::String& str1, const Common::String& str2) { size_t length1 = str1.size(); size_t length2 = str2.size(); if (length1 != length2) return false; for (size_t i = 0; i < length1; i++) { if (invariantToLower(str1[i]) != invariantToLower(str2[i])) return false; } return true; } size_t caseInsensitiveFind(const Common::String &strToSearch, const Common::String &stringToFind) { if (stringToFind.size() > strToSearch.size()) return Common::String::npos; size_t lastValidStart = strToSearch.size() - stringToFind.size(); size_t searchLength = stringToFind.size(); for (size_t startIndex = 0; startIndex <= lastValidStart; startIndex++) { bool matches = true; for (size_t i = 0; i < searchLength; i++) { char ca = strToSearch[i + startIndex]; char cb = stringToFind[i]; if (ca != cb && invariantToLower(ca) != invariantToLower(cb)) { matches = false; break; } } if (matches) return startIndex; } return Common::String::npos; } bool SceneTransitionTypes::loadFromData(SceneTransitionType &transType, int32 data) { switch (data) { case Data::SceneTransitionTypes::kNone: transType = kNone; break; case Data::SceneTransitionTypes::kPatternDissolve: transType = kPatternDissolve; break; case Data::SceneTransitionTypes::kRandomDissolve: transType = kRandomDissolve; break; case Data::SceneTransitionTypes::kFade: transType = kFade; break; case Data::SceneTransitionTypes::kSlide: transType = kSlide; break; case Data::SceneTransitionTypes::kPush: transType = kPush; break; case Data::SceneTransitionTypes::kZoom: transType = kZoom; break; case Data::SceneTransitionTypes::kWipe: transType = kWipe; break; default: return false; } return true; } bool SceneTransitionDirections::loadFromData(SceneTransitionDirection &transDir, int32 data) { switch (data) { case Data::SceneTransitionDirections::kUp: transDir = kUp; break; case Data::SceneTransitionDirections::kDown: transDir = kDown; break; case Data::SceneTransitionDirections::kLeft: transDir = kLeft; break; case Data::SceneTransitionDirections::kRight: transDir = kRight; break; default: return false; } return true; } bool EventIDs::isCommand(EventID eventID) { switch (eventID) { case kElementShow: case kElementHide: case kElementSelect: case kElementDeselect: case kElementToggleSelect: case kElementEnableEdit: case kElementDisableEdit: case kElementUpdatedCalculated: case kElementScrollUp: case kElementScrollDown: case kElementScrollLeft: case kElementScrollRight: case kPreloadMedia: case kFlushMedia: case kPrerollMedia: case kClone: case kKill: case kPlay: case kStop: case kPause: case kUnpause: case kTogglePause: case kCloseProject: case kFlushAllMedia: case kAttribGet: case kAttribSet: return true; default: return false; } } MiniscriptInstructionOutcome pointWriteRefAttrib(Common::Point &point, MiniscriptThread *thread, DynamicValueWriteProxy &proxy, const Common::String &attrib) { if (attrib == "x") { DynamicValueWriteIntegerHelper::create(&point.x, proxy); return kMiniscriptInstructionOutcomeContinue; } if (attrib == "y") { DynamicValueWriteIntegerHelper::create(&point.y, proxy); return kMiniscriptInstructionOutcomeContinue; } return kMiniscriptInstructionOutcomeFailed; } Common::String pointToString(const Common::Point &point) { return Common::String::format("(%i,%i)", point.x, point.y); } IntRange::IntRange() : min(0), max(0) { } IntRange::IntRange(int32 pmin, int32 pmax) : min(pmin), max(pmax) { } bool IntRange::load(const Data::IntRange &range) { max = range.max; min = range.min; return true; } MiniscriptInstructionOutcome IntRange::refAttrib(MiniscriptThread *thread, DynamicValueWriteProxy &proxy, const Common::String &attrib) { if (attrib == "start") { DynamicValueWriteIntegerHelper::create(&min, proxy); return kMiniscriptInstructionOutcomeContinue; } if (attrib == "end") { DynamicValueWriteIntegerHelper::create(&max, proxy); return kMiniscriptInstructionOutcomeContinue; } thread->error("Couldn't reference int range attribute '" + attrib + "'"); return kMiniscriptInstructionOutcomeFailed; } Common::String IntRange::toString() const { return Common::String::format("(%i thru %i)", min, max); } Label::Label() : superGroupID(0), id(0) { } Label::Label(int32 psuperGroupID, int32 pid) : superGroupID(psuperGroupID), id(pid) { } bool Label::load(const Data::Label &label) { id = label.labelID; superGroupID = label.superGroupID; return true; } bool ColorRGB8::load(const Data::ColorRGB16 &color) { this->r = (color.red * 0xff * 2 + 1) / (0xffff * 2); this->g = (color.green * 0xff * 2 + 1) / (0xffff * 2); this->b = (color.blue * 0xff * 2 + 1) / (0xffff * 2); return true; } ColorRGB8::ColorRGB8() : r(0), g(0), b(0) { } ColorRGB8::ColorRGB8(uint8 pr, uint8 pg, uint8 pb) : r(pr), g(pg), b(pb) { } MessageFlags::MessageFlags() : relay(true), cascade(true), immediate(true) { } DynamicValueWriteProxyPOD DynamicValueWriteProxyPOD::createDefault() { DynamicValueWriteProxyPOD proxy; proxy.ifc = nullptr; proxy.objectRef = nullptr; proxy.ptrOrOffset = 0; return proxy; } DynamicValueWriteProxy::DynamicValueWriteProxy() : pod(DynamicValueWriteProxyPOD::createDefault()) { } Common::Point Point16POD::toScummVMPoint() const { return Common::Point(x, y); } DynamicListContainerBase::~DynamicListContainerBase() { } void DynamicListDefaultSetter::defaultSet(int32 &value) { value = 0; } void DynamicListDefaultSetter::defaultSet(double &value) { value = 0.0; } void DynamicListDefaultSetter::defaultSet(Common::Point &value) { value.x = 0; value.y = 0; } void DynamicListDefaultSetter::defaultSet(IntRange &value) { value.min = 0; value.max = 0; } void DynamicListDefaultSetter::defaultSet(bool &value) { value = false; } void DynamicListDefaultSetter::defaultSet(AngleMagVector &value) { value.angleDegrees = 0.0; value.magnitude = 0.0; } void DynamicListDefaultSetter::defaultSet(Label &value) { value.id = 0; value.superGroupID = 0; } void DynamicListDefaultSetter::defaultSet(Event &value) { value.eventType = EventIDs::EventID::kNothing; value.eventInfo = 0; } void DynamicListDefaultSetter::defaultSet(Common::String &value) { } void DynamicListDefaultSetter::defaultSet(Common::SharedPtr &value) { } void DynamicListDefaultSetter::defaultSet(ObjectReference &value) { } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const int32 *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kInteger) return false; outPtr = &dynValue.getInt(); return true; } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const double *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kFloat) return false; outPtr = &dynValue.getFloat(); return true; } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const Common::Point *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kPoint) return false; outPtr = &dynValue.getPoint(); return true; } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const IntRange *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kIntegerRange) return false; outPtr = &dynValue.getIntRange(); return true; } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const bool *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kBoolean) return false; outPtr = &dynValue.getBool(); return true; } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const AngleMagVector *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kVector) return false; outPtr = &dynValue.getVector(); return true; } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const Label *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kLabel) return false; outPtr = &dynValue.getLabel(); return true; } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const Event *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kEvent) return false; outPtr = &dynValue.getEvent(); return true; } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const Common::String *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kString) return false; outPtr = &dynValue.getString(); return true; } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const Common::SharedPtr *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kList) return false; outPtr = &dynValue.getList(); return true; } bool DynamicListValueImporter::importValue(const DynamicValue &dynValue, const ObjectReference *&outPtr) { if (dynValue.getType() != DynamicValueTypes::kObject) return false; outPtr = &dynValue.getObject(); return true; } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const int32 &value) { dynValue.setInt(value); } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const double &value) { dynValue.setFloat(value); } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const Common::Point &value) { dynValue.setPoint(value); } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const IntRange &value) { dynValue.setIntRange(value); } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const bool &value) { dynValue.setBool(value); } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const AngleMagVector &value) { dynValue.setVector(value); } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const Label &value) { dynValue.setLabel(value); } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const Event &value) { dynValue.setEvent(value); } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const Common::String &value) { dynValue.setString(value); } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const Common::SharedPtr &value) { dynValue.setList(value); } void DynamicListValueExporter::exportValue(DynamicValue &dynValue, const ObjectReference &value) { dynValue.setObject(value); } DynamicListContainer::DynamicListContainer() : _size(0) { } bool DynamicListContainer::setAtIndex(size_t index, const DynamicValue &dynValue) { return true; } void DynamicListContainer::truncateToSize(size_t sz) { } bool DynamicListContainer::expandToMinimumSize(size_t sz) { return false; } bool DynamicListContainer::getAtIndex(size_t index, DynamicValue &dynValue) const { dynValue.clear(); return true; } void DynamicListContainer::setFrom(const DynamicListContainerBase &other) { _size = other.getSize(); // ... the only thing we have anyway... } const void *DynamicListContainer::getConstArrayPtr() const { return nullptr; } void *DynamicListContainer::getArrayPtr() { return nullptr; } size_t DynamicListContainer::getSize() const { return _size; } bool DynamicListContainer::compareEqual(const DynamicListContainerBase &other) const { return true; } DynamicListContainerBase *DynamicListContainer::clone() const { return new DynamicListContainer(*this); } DynamicList::DynamicList() : _type(DynamicValueTypes::kUnspecified), _container(nullptr) { } DynamicList::DynamicList(const DynamicList &other) : _type(DynamicValueTypes::kUnspecified), _container(nullptr) { initFromOther(other); } DynamicList::~DynamicList() { destroyContainer(); } DynamicValueTypes::DynamicValueType DynamicList::getType() const { return _type; } const Common::Array &DynamicList::getInt() const { assert(_type == DynamicValueTypes::kInteger); return *static_cast *>(_container->getConstArrayPtr()); } const Common::Array &DynamicList::getFloat() const { assert(_type == DynamicValueTypes::kFloat); return *static_cast *>(_container->getConstArrayPtr()); } const Common::Array &DynamicList::getPoint() const { assert(_type == DynamicValueTypes::kPoint); return *static_cast *>(_container->getConstArrayPtr()); } const Common::Array &DynamicList::getIntRange() const { assert(_type == DynamicValueTypes::kIntegerRange); return *static_cast *>(_container->getConstArrayPtr()); } const Common::Array &DynamicList::getVector() const { assert(_type == DynamicValueTypes::kVector); return *static_cast *>(_container->getConstArrayPtr()); } const Common::Array