#ifndef CSM_WOLRD_REFIDADAPTERIMP_H #define CSM_WOLRD_REFIDADAPTERIMP_H #include <map> #include <QVariant> #include <components/esm/loadalch.hpp> #include <components/esm/loadappa.hpp> #include "record.hpp" #include "refiddata.hpp" #include "universalid.hpp" #include "refidadapter.hpp" namespace CSMWorld { struct BaseColumns { const RefIdColumn *mId; const RefIdColumn *mModified; const RefIdColumn *mType; }; /// \brief Base adapter for all refereceable record types template<typename RecordT> class BaseRefIdAdapter : public RefIdAdapter { UniversalId::Type mType; BaseColumns mBase; public: BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base); virtual std::string getId (const RecordBase& record) const; virtual void setId (RecordBase& record, const std::string& id); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. UniversalId::Type getType() const; }; template<typename RecordT> BaseRefIdAdapter<RecordT>::BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base) : mType (type), mBase (base) {} template<typename RecordT> void BaseRefIdAdapter<RecordT>::setId (RecordBase& record, const std::string& id) { (dynamic_cast<Record<RecordT>&> (record).get().mId) = id; } template<typename RecordT> std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const { return dynamic_cast<const Record<RecordT>&> (record).get().mId; } template<typename RecordT> QVariant BaseRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data, int index) const { const Record<RecordT>& record = static_cast<const Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, mType))); if (column==mBase.mId) return QString::fromUtf8 (record.get().mId.c_str()); if (column==mBase.mModified) { if (record.mState==Record<RecordT>::State_Erased) return static_cast<int> (Record<RecordT>::State_Deleted); return static_cast<int> (record.mState); } if (column==mBase.mType) return static_cast<int> (mType); return QVariant(); } template<typename RecordT> void BaseRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { Record<RecordT>& record = static_cast<Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, mType))); if (column==mBase.mModified) record.mState = static_cast<RecordBase::State> (value.toInt()); } template<typename RecordT> UniversalId::Type BaseRefIdAdapter<RecordT>::getType() const { return mType; } struct ModelColumns : public BaseColumns { const RefIdColumn *mModel; ModelColumns (const BaseColumns& base) : BaseColumns (base) {} }; /// \brief Adapter for IDs with models (all but levelled lists) template<typename RecordT> class ModelRefIdAdapter : public BaseRefIdAdapter<RecordT> { ModelColumns mModel; public: ModelRefIdAdapter (UniversalId::Type type, const ModelColumns& columns); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; template<typename RecordT> ModelRefIdAdapter<RecordT>::ModelRefIdAdapter (UniversalId::Type type, const ModelColumns& columns) : BaseRefIdAdapter<RecordT> (type, columns), mModel (columns) {} template<typename RecordT> QVariant ModelRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data, int index) const { const Record<RecordT>& record = static_cast<const Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mModel.mModel) return QString::fromUtf8 (record.get().mModel.c_str()); return BaseRefIdAdapter<RecordT>::getData (column, data, index); } template<typename RecordT> void ModelRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { Record<RecordT>& record = static_cast<Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mModel.mModel) record.get().mModel = value.toString().toUtf8().constData(); else BaseRefIdAdapter<RecordT>::setData (column, data, index, value); } struct NameColumns : public ModelColumns { const RefIdColumn *mName; const RefIdColumn *mScript; NameColumns (const ModelColumns& base) : ModelColumns (base) {} }; /// \brief Adapter for IDs with names (all but levelled lists and statics) template<typename RecordT> class NameRefIdAdapter : public ModelRefIdAdapter<RecordT> { NameColumns mName; public: NameRefIdAdapter (UniversalId::Type type, const NameColumns& columns); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; template<typename RecordT> NameRefIdAdapter<RecordT>::NameRefIdAdapter (UniversalId::Type type, const NameColumns& columns) : ModelRefIdAdapter<RecordT> (type, columns), mName (columns) {} template<typename RecordT> QVariant NameRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data, int index) const { const Record<RecordT>& record = static_cast<const Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mName.mName) return QString::fromUtf8 (record.get().mName.c_str()); if (column==mName.mScript) return QString::fromUtf8 (record.get().mScript.c_str()); return ModelRefIdAdapter<RecordT>::getData (column, data, index); } template<typename RecordT> void NameRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { Record<RecordT>& record = static_cast<Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mName.mName) record.get().mName = value.toString().toUtf8().constData(); else if (column==mName.mScript) record.get().mScript = value.toString().toUtf8().constData(); else ModelRefIdAdapter<RecordT>::setData (column, data, index, value); } struct InventoryColumns : public NameColumns { const RefIdColumn *mIcon; const RefIdColumn *mWeight; const RefIdColumn *mValue; InventoryColumns (const NameColumns& base) : NameColumns (base) {} }; /// \brief Adapter for IDs that can go into an inventory template<typename RecordT> class InventoryRefIdAdapter : public NameRefIdAdapter<RecordT> { InventoryColumns mInventory; public: InventoryRefIdAdapter (UniversalId::Type type, const InventoryColumns& columns); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; template<typename RecordT> InventoryRefIdAdapter<RecordT>::InventoryRefIdAdapter (UniversalId::Type type, const InventoryColumns& columns) : NameRefIdAdapter<RecordT> (type, columns), mInventory (columns) {} template<typename RecordT> QVariant InventoryRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data, int index) const { const Record<RecordT>& record = static_cast<const Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mInventory.mIcon) return QString::fromUtf8 (record.get().mIcon.c_str()); if (column==mInventory.mWeight) return record.get().mData.mWeight; if (column==mInventory.mValue) return record.get().mData.mValue; return NameRefIdAdapter<RecordT>::getData (column, data, index); } template<typename RecordT> void InventoryRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { Record<RecordT>& record = static_cast<Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mInventory.mIcon) record.get().mIcon = value.toString().toUtf8().constData(); else if (column==mInventory.mWeight) record.get().mData.mWeight = value.toFloat(); else if (column==mInventory.mValue) record.get().mData.mValue = value.toInt(); else NameRefIdAdapter<RecordT>::setData (column, data, index, value); } class PotionRefIdAdapter : public InventoryRefIdAdapter<ESM::Potion> { const RefIdColumn *mAutoCalc; public: PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; struct EnchantableColumns : public InventoryColumns { const RefIdColumn *mEnchantment; const RefIdColumn *mEnchantmentPoints; EnchantableColumns (const InventoryColumns& base) : InventoryColumns (base) {} }; /// \brief Adapter for enchantable IDs template<typename RecordT> class EnchantableRefIdAdapter : public InventoryRefIdAdapter<RecordT> { EnchantableColumns mEnchantable; public: EnchantableRefIdAdapter (UniversalId::Type type, const EnchantableColumns& columns); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; template<typename RecordT> EnchantableRefIdAdapter<RecordT>::EnchantableRefIdAdapter (UniversalId::Type type, const EnchantableColumns& columns) : InventoryRefIdAdapter<RecordT> (type, columns), mEnchantable (columns) {} template<typename RecordT> QVariant EnchantableRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data, int index) const { const Record<RecordT>& record = static_cast<const Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mEnchantable.mEnchantment) return QString::fromUtf8 (record.get().mEnchant.c_str()); if (column==mEnchantable.mEnchantmentPoints) return static_cast<int> (record.get().mData.mEnchant); return InventoryRefIdAdapter<RecordT>::getData (column, data, index); } template<typename RecordT> void EnchantableRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { Record<RecordT>& record = static_cast<Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mEnchantable.mEnchantment) record.get().mEnchant = value.toString().toUtf8().constData(); else if (column==mEnchantable.mEnchantmentPoints) record.get().mData.mEnchant = value.toInt(); else InventoryRefIdAdapter<RecordT>::setData (column, data, index, value); } struct ToolColumns : public InventoryColumns { const RefIdColumn *mQuality; const RefIdColumn *mUses; ToolColumns (const InventoryColumns& base) : InventoryColumns (base) {} }; /// \brief Adapter for tools with limited uses IDs (lockpick, repair, probes) template<typename RecordT> class ToolRefIdAdapter : public InventoryRefIdAdapter<RecordT> { ToolColumns mTools; public: ToolRefIdAdapter (UniversalId::Type type, const ToolColumns& columns); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; template<typename RecordT> ToolRefIdAdapter<RecordT>::ToolRefIdAdapter (UniversalId::Type type, const ToolColumns& columns) : InventoryRefIdAdapter<RecordT> (type, columns), mTools (columns) {} template<typename RecordT> QVariant ToolRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data, int index) const { const Record<RecordT>& record = static_cast<const Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mTools.mQuality) return record.get().mData.mQuality; if (column==mTools.mUses) return record.get().mData.mUses; return InventoryRefIdAdapter<RecordT>::getData (column, data, index); } template<typename RecordT> void ToolRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { Record<RecordT>& record = static_cast<Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mTools.mQuality) record.get().mData.mQuality = value.toFloat(); else if (column==mTools.mUses) record.get().mData.mUses = value.toInt(); else InventoryRefIdAdapter<RecordT>::setData (column, data, index, value); } struct ActorColumns : public NameColumns { const RefIdColumn *mHasAi; const RefIdColumn *mHello; const RefIdColumn *mFlee; const RefIdColumn *mFight; const RefIdColumn *mAlarm; std::map<const RefIdColumn *, unsigned int> mServices; ActorColumns (const NameColumns& base) : NameColumns (base) {} }; /// \brief Adapter for actor IDs (handles common AI functionality) template<typename RecordT> class ActorRefIdAdapter : public NameRefIdAdapter<RecordT> { ActorColumns mActors; public: ActorRefIdAdapter (UniversalId::Type type, const ActorColumns& columns); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; template<typename RecordT> ActorRefIdAdapter<RecordT>::ActorRefIdAdapter (UniversalId::Type type, const ActorColumns& columns) : NameRefIdAdapter<RecordT> (type, columns), mActors (columns) {} template<typename RecordT> QVariant ActorRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data, int index) const { const Record<RecordT>& record = static_cast<const Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mActors.mHasAi) return record.get().mHasAI!=0; if (column==mActors.mHello) return record.get().mAiData.mHello; if (column==mActors.mFlee) return record.get().mAiData.mFlee; if (column==mActors.mFight) return record.get().mAiData.mFight; if (column==mActors.mAlarm) return record.get().mAiData.mAlarm; std::map<const RefIdColumn *, unsigned int>::const_iterator iter = mActors.mServices.find (column); if (iter!=mActors.mServices.end()) return (record.get().mAiData.mServices & iter->second)!=0; return NameRefIdAdapter<RecordT>::getData (column, data, index); } template<typename RecordT> void ActorRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { Record<RecordT>& record = static_cast<Record<RecordT>&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType()))); if (column==mActors.mHasAi) record.get().mHasAI = value.toInt(); else if (column==mActors.mHello) record.get().mAiData.mHello = value.toInt(); else if (column==mActors.mFlee) record.get().mAiData.mFlee = value.toInt(); else if (column==mActors.mFight) record.get().mAiData.mFight = value.toInt(); else if (column==mActors.mAlarm) record.get().mAiData.mAlarm = value.toInt(); else { typename std::map<const RefIdColumn *, unsigned int>::const_iterator iter = mActors.mServices.find (column); if (iter!=mActors.mServices.end()) { if (value.toInt()!=0) record.get().mAiData.mServices |= iter->second; else record.get().mAiData.mServices &= ~iter->second; } else NameRefIdAdapter<RecordT>::setData (column, data, index, value); } } class ApparatusRefIdAdapter : public InventoryRefIdAdapter<ESM::Apparatus> { const RefIdColumn *mType; const RefIdColumn *mQuality; public: ApparatusRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *type, const RefIdColumn *quality); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; class ArmorRefIdAdapter : public EnchantableRefIdAdapter<ESM::Armor> { const RefIdColumn *mType; const RefIdColumn *mHealth; const RefIdColumn *mArmor; public: ArmorRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *type, const RefIdColumn *health, const RefIdColumn *armor); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; class BookRefIdAdapter : public EnchantableRefIdAdapter<ESM::Book> { const RefIdColumn *mScroll; const RefIdColumn *mSkill; public: BookRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *scroll, const RefIdColumn *skill); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; class ClothingRefIdAdapter : public EnchantableRefIdAdapter<ESM::Clothing> { const RefIdColumn *mType; public: ClothingRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *type); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; class ContainerRefIdAdapter : public NameRefIdAdapter<ESM::Container> { const RefIdColumn *mWeight; const RefIdColumn *mOrganic; const RefIdColumn *mRespawn; public: ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; struct CreatureColumns : public ActorColumns { std::map<const RefIdColumn *, unsigned int> mFlags; const RefIdColumn *mType; const RefIdColumn *mSoul; const RefIdColumn *mScale; const RefIdColumn *mOriginal; CreatureColumns (const ActorColumns& actorColumns); }; class CreatureRefIdAdapter : public ActorRefIdAdapter<ESM::Creature> { CreatureColumns mColumns; public: CreatureRefIdAdapter (const CreatureColumns& columns); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; class DoorRefIdAdapter : public NameRefIdAdapter<ESM::Door> { const RefIdColumn *mOpenSound; const RefIdColumn *mCloseSound; public: DoorRefIdAdapter (const NameColumns& columns, const RefIdColumn *openSound, const RefIdColumn *closeSound); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; struct LightColumns : public InventoryColumns { const RefIdColumn *mTime; const RefIdColumn *mRadius; const RefIdColumn *mColor; const RefIdColumn *mSound; std::map<const RefIdColumn *, unsigned int> mFlags; LightColumns (const InventoryColumns& columns); }; class LightRefIdAdapter : public InventoryRefIdAdapter<ESM::Light> { LightColumns mColumns; public: LightRefIdAdapter (const LightColumns& columns); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; class MiscRefIdAdapter : public InventoryRefIdAdapter<ESM::Miscellaneous> { const RefIdColumn *mKey; public: MiscRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *key); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; struct NpcColumns : public ActorColumns { std::map<const RefIdColumn *, unsigned int> mFlags; const RefIdColumn *mRace; const RefIdColumn *mClass; const RefIdColumn *mFaction; const RefIdColumn *mHair; const RefIdColumn *mHead; NpcColumns (const ActorColumns& actorColumns); }; class NpcRefIdAdapter : public ActorRefIdAdapter<ESM::NPC> { NpcColumns mColumns; public: NpcRefIdAdapter (const NpcColumns& columns); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; struct WeaponColumns : public EnchantableColumns { const RefIdColumn *mType; const RefIdColumn *mHealth; const RefIdColumn *mSpeed; const RefIdColumn *mReach; const RefIdColumn *mChop[2]; const RefIdColumn *mSlash[2]; const RefIdColumn *mThrust[2]; std::map<const RefIdColumn *, unsigned int> mFlags; WeaponColumns (const EnchantableColumns& columns); }; class WeaponRefIdAdapter : public EnchantableRefIdAdapter<ESM::Weapon> { WeaponColumns mColumns; public: WeaponRefIdAdapter (const WeaponColumns& columns); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; } #endif