diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index ef5d93827d..ffc98ef208 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -7,10 +7,54 @@ namespace MWWorld { + CellRef::CellRef(const ESM::CellRef& ref) + : mCellRef(ESM::ReferenceVariant(ref)) + { + mChanged = false; + mSoul = ref.mSoul; + mTrap = ref.mTrap; + mKey = ref.mKey; + mFaction = ref.mFaction; + mOwner = ref.mOwner; + mReferenceType = ref.mRefID; + mPos = ref.mPos; + mDoorDest = ref.mDoorDest; + mRefNum = ref.mRefNum; + mGlobalVariable = ref.mGlobalVariable; + mDestCell = ref.mDestCell; + + mLockLevel = ref.mLockLevel; + mGoldValue = ref.mGoldValue; + mFactionRank = ref.mFactionRank; + mEnchantmentCharge = ref.mEnchantmentCharge; + + mScale = ref.mScale; + } + + CellRef::CellRef(const ESM4::Reference& ref) + : mCellRef(ESM::ReferenceVariant(ref)) + { + + mChanged = false; + + mReferenceType = ref.mBaseObj; + mPos = { { ref.mPlacement.pos.x, ref.mPlacement.pos.y, ref.mPlacement.pos.z }, + { ref.mPlacement.rot.x, ref.mPlacement.rot.y, ref.mPlacement.rot.z } }; + + mRefNum = {}; + mDoorDest = {}; + + mLockLevel = ref.mLockLevel; + mFactionRank = ref.mFactionRank; + mGoldValue = 0; + mEnchantmentCharge = 0; + + mScale = ref.mScale; + } const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum) { - if (!mCellRef.mRefNum.isSet()) + if (!mRefNum.isSet()) { // Generated RefNums have negative mContentFile assert(lastAssignedRefNum.mContentFile < 0); @@ -22,30 +66,38 @@ namespace MWWorld else Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum"; } - mCellRef.mRefNum = lastAssignedRefNum; + mRefNum = lastAssignedRefNum; mChanged = true; } - return mCellRef.mRefNum; + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mRefNum = mRefNum; + return mRefNum; } void CellRef::unsetRefNum() { - mCellRef.mRefNum = ESM::RefNum{}; + mRefNum = ESM::RefNum{}; + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mRefNum = mRefNum; } void CellRef::setScale(float scale) { - if (scale != mCellRef.mScale) + if (scale != mScale) { mChanged = true; - mCellRef.mScale = scale; + mScale = scale; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mScale = Scale; } void CellRef::setPosition(const ESM::Position& position) { mChanged = true; - mCellRef.mPos = position; + mPos = position; + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mPos = position; } float CellRef::getNormalizedEnchantmentCharge(int maxCharge) const @@ -54,113 +106,140 @@ namespace MWWorld { return 0; } - else if (mCellRef.mEnchantmentCharge == -1) + else if (mEnchantmentCharge == -1) { return 1; } else { - return mCellRef.mEnchantmentCharge / static_cast(maxCharge); + return mEnchantmentCharge / static_cast(maxCharge); } } void CellRef::setEnchantmentCharge(float charge) { - if (charge != mCellRef.mEnchantmentCharge) + if (charge != mEnchantmentCharge) { mChanged = true; - mCellRef.mEnchantmentCharge = charge; + mEnchantmentCharge = charge; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mEnchantmentCharge = mEnchantmentCharge; } void CellRef::setCharge(int charge) { - if (charge != mCellRef.mChargeInt) + if (mCellRef.isESM4()) + return; + + auto& cellRef3 = mCellRef.getEsm3(); + if (charge != cellRef3.mChargeInt) { mChanged = true; - mCellRef.mChargeInt = charge; + cellRef3.mChargeInt = charge; } } void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder) { - mCellRef.mChargeIntRemainder += std::abs(chargeRemainder); - if (mCellRef.mChargeIntRemainder > 1.0f) + if (mCellRef.isESM4()) + return; + + auto& cellRef3 = mCellRef.getEsm3(); + cellRef3.mChargeIntRemainder += std::abs(chargeRemainder); + if (cellRef3.mChargeIntRemainder > 1.0f) { - float newChargeRemainder = (mCellRef.mChargeIntRemainder - std::floor(mCellRef.mChargeIntRemainder)); - if (mCellRef.mChargeInt <= static_cast(mCellRef.mChargeIntRemainder)) + float newChargeRemainder = (cellRef3.mChargeIntRemainder - std::floor(cellRef3.mChargeIntRemainder)); + if (cellRef3.mChargeInt <= static_cast(cellRef3.mChargeIntRemainder)) { - mCellRef.mChargeInt = 0; + cellRef3.mChargeInt = 0; } else { - mCellRef.mChargeInt -= static_cast(mCellRef.mChargeIntRemainder); + cellRef3.mChargeInt -= static_cast(cellRef3.mChargeIntRemainder); } - mCellRef.mChargeIntRemainder = newChargeRemainder; + cellRef3.mChargeIntRemainder = newChargeRemainder; } } void CellRef::setChargeFloat(float charge) { - if (charge != mCellRef.mChargeFloat) + if (mCellRef.isESM4()) + return; + + auto& cellRef3 = mCellRef.getEsm3(); + if (charge != cellRef3.mChargeFloat) { mChanged = true; - mCellRef.mChargeFloat = charge; + cellRef3.mChargeFloat = charge; } } void CellRef::resetGlobalVariable() { - if (!mCellRef.mGlobalVariable.empty()) + if (!mGlobalVariable.empty()) { mChanged = true; - mCellRef.mGlobalVariable.erase(); + mGlobalVariable.erase(); } + + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mGlobalVariable = mGlobalVariable; } void CellRef::setFactionRank(int factionRank) { - if (factionRank != mCellRef.mFactionRank) + if (factionRank != mFactionRank) { mChanged = true; - mCellRef.mFactionRank = factionRank; + mFactionRank = factionRank; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mFactionRank = mFactionRank; } void CellRef::setOwner(const ESM::RefId& owner) { - if (owner != mCellRef.mOwner) + if (owner != mOwner) { mChanged = true; - mCellRef.mOwner = owner; + mOwner = owner; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mOwner = mOwner; } void CellRef::setSoul(const ESM::RefId& soul) { - if (soul != mCellRef.mSoul) + if (soul != mSoul) { mChanged = true; - mCellRef.mSoul = soul; + mSoul = soul; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mSoul = mSoul; } void CellRef::setFaction(const ESM::RefId& faction) { - if (faction != mCellRef.mFaction) + if (faction != mFaction) { mChanged = true; - mCellRef.mFaction = faction; + mFaction = faction; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mFaction = mFaction; } void CellRef::setLockLevel(int lockLevel) { - if (lockLevel != mCellRef.mLockLevel) + if (lockLevel != mLockLevel) { mChanged = true; - mCellRef.mLockLevel = lockLevel; + mLockLevel = lockLevel; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mLockLevel = mLockLevel; } void CellRef::lock(int lockLevel) @@ -173,30 +252,38 @@ namespace MWWorld void CellRef::unlock() { - setLockLevel(-abs(mCellRef.mLockLevel)); // Makes lockLevel negative + setLockLevel(-abs(mLockLevel)); // Makes lockLevel negative } void CellRef::setTrap(const ESM::RefId& trap) { - if (trap != mCellRef.mTrap) + if (trap != mTrap) { mChanged = true; - mCellRef.mTrap = trap; + mTrap = trap; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mTrap = mTrap; } void CellRef::setGoldValue(int value) { - if (value != mCellRef.mGoldValue) + if (value != mGoldValue) { mChanged = true; - mCellRef.mGoldValue = value; + mGoldValue = value; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mGoldValue = mGoldValue; } void CellRef::writeState(ESM::ObjectState& state) const { - state.mRef = mCellRef; + if (!mCellRef.isESM4()) + { + auto& cellRef3 = mCellRef.getEsm3(); + state.mRef = cellRef3; + } } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 822961e645..b3f3e84125 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -19,24 +19,12 @@ namespace MWWorld class CellRef { public: - CellRef(const ESM::CellRef& ref) - : mCellRef(ref) - { - mIsEsm4 = false; - mChanged = false; - } + CellRef(const ESM::CellRef& ref); - CellRef(const ESM4::Reference& ref) - : mCellRef4(ref) - { - mRefrPos = { { mCellRef4.mPlacement.pos.x, mCellRef4.mPlacement.pos.y, mCellRef4.mPlacement.pos.z }, - { mCellRef4.mPlacement.rot.x, mCellRef4.mPlacement.rot.y, mCellRef4.mPlacement.rot.z } }; - mChanged = false; - mIsEsm4 = true; - } + CellRef(const ESM4::Reference& ref); // Note: Currently unused for items in containers - const ESM::RefNum& getRefNum() const { return mCellRef.mRefNum; } + const ESM::RefNum& getRefNum() const { return mRefNum; } // Returns RefNum. // If RefNum is not set, assigns a generated one and changes the "lastAssignedRefNum" counter. @@ -46,44 +34,32 @@ namespace MWWorld void unsetRefNum(); /// Does the RefNum have a content file? - bool hasContentFile() const { return mCellRef.mRefNum.hasContentFile(); } + bool hasContentFile() const { return mRefNum.hasContentFile(); } // Id of object being referenced - const ESM::RefId& getRefId() const { return mCellRef.mRefID; } + const ESM::RefId& getRefId() const { return mReferenceType; } // For doors - true if this door teleports to somewhere else, false // if it should open through animation. - bool getTeleport() const { return mCellRef.mTeleport; } + bool getTeleport() const { return mCellRef.isESM4() ? false : mCellRef.getEsm3().mTeleport; } // Teleport location for the door, if this is a teleporting door. - const ESM::Position& getDoorDest() const { return mCellRef.mDoorDest; } + const ESM::Position& getDoorDest() const { return mDoorDest; } // Destination cell for doors (optional) - const std::string& getDestCell() const { return mCellRef.mDestCell; } + const std::string& getDestCell() const { return mDestCell; } // Scale applied to mesh - float getScale() const - { - if (mIsEsm4) - return mCellRef4.mScale; - else - return mCellRef.mScale; - } + float getScale() const { return mScale; } void setScale(float scale); // The *original* position and rotation as it was given in the Construction Set. // Current position and rotation of the object is stored in RefData. - const ESM::Position& getPosition() const - { - if (mIsEsm4) - return mRefrPos; - else - return mCellRef.mPos; - } + const ESM::Position& getPosition() const { return mPos; } void setPosition(const ESM::Position& position); // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). - float getEnchantmentCharge() const { return mCellRef.mEnchantmentCharge; } + float getEnchantmentCharge() const { return mEnchantmentCharge; } // Remaining enchantment charge rescaled to the supplied maximum charge (such as one of the enchantment). float getNormalizedEnchantmentCharge(int maxCharge) const; @@ -93,50 +69,53 @@ namespace MWWorld // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. // If this returns int(-1) it means full health. - int getCharge() const { return mCellRef.mChargeInt; } - float getChargeFloat() const { return mCellRef.mChargeFloat; } // Implemented as union with int charge + int getCharge() const { return mCellRef.isESM4() ? 0 : mCellRef.getEsm3().mChargeInt; } + float getChargeFloat() const + { + return mCellRef.isESM4() ? 0.f : mCellRef.getEsm3().mChargeFloat; + } // Implemented as union with int charge void setCharge(int charge); void setChargeFloat(float charge); void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1 // The NPC that owns this object (and will get angry if you steal it) - const ESM::RefId& getOwner() const { return mCellRef.mOwner; } + const ESM::RefId& getOwner() const { return mOwner; } void setOwner(const ESM::RefId& owner); // Name of a global variable. If the global variable is set to '1', using the object is temporarily allowed // even if it has an Owner field. // Used by bed rent scripts to allow the player to use the bed for the duration of the rent. - const std::string& getGlobalVariable() const { return mCellRef.mGlobalVariable; } + const std::string& getGlobalVariable() const { return mGlobalVariable; } void resetGlobalVariable(); // ID of creature trapped in this soul gem - const ESM::RefId& getSoul() const { return mCellRef.mSoul; } + const ESM::RefId& getSoul() const { return mSoul; } void setSoul(const ESM::RefId& soul); // The faction that owns this object (and will get angry if // you take it and are not a faction member) - const ESM::RefId& getFaction() const { return mCellRef.mFaction; } + const ESM::RefId& getFaction() const { return mFaction; } void setFaction(const ESM::RefId& faction); // PC faction rank required to use the item. Sometimes is -1, which means "any rank". void setFactionRank(int factionRank); - int getFactionRank() const { return mCellRef.mFactionRank; } + int getFactionRank() const { return mFactionRank; } // Lock level for doors and containers // Positive for a locked door. 0 for a door that was never locked. // For an unlocked door, it is set to -(previous locklevel) - int getLockLevel() const { return mCellRef.mLockLevel; } + int getLockLevel() const { return mLockLevel; } void setLockLevel(int lockLevel); void lock(int lockLevel); void unlock(); // Key and trap ID names, if any - const ESM::RefId& getKey() const { return mCellRef.mKey; } - const ESM::RefId& getTrap() const { return mCellRef.mTrap; } + const ESM::RefId& getKey() const { return mKey; } + const ESM::RefId& getTrap() const { return mTrap; } void setTrap(const ESM::RefId& trap); // This is 5 for Gold_005 references, 100 for Gold_100 and so on. - int getGoldValue() const { return mCellRef.mGoldValue; } + int getGoldValue() const { return mGoldValue; } void setGoldValue(int value); // Write the content of this CellRef into the given ObjectState @@ -147,10 +126,15 @@ namespace MWWorld private: bool mChanged; - ESM::CellRef mCellRef; - ESM4::Reference mCellRef4; - ESM::Position mRefrPos; - bool mIsEsm4; + ESM::ReferenceVariant mCellRef; + + ESM::RefId mSoul, mFaction, mKey, mTrap, mOwner, mReferenceType; + float Scale; + ESM::Position mPos, mDoorDest; + ESM::RefNum mRefNum; + std::string mGlobalVariable, mDestCell; + int mLockLevel, mGoldValue, mFactionRank, mEnchantmentCharge; + float mScale; }; } diff --git a/components/esm/esmbridge.hpp b/components/esm/esmbridge.hpp index b63a89315a..753f0690e0 100644 --- a/components/esm/esmbridge.hpp +++ b/components/esm/esmbridge.hpp @@ -4,7 +4,8 @@ #include #include -#include +#include +#include namespace ESM4 { @@ -39,6 +40,31 @@ namespace ESM const ESM::Cell& getEsm3() const; }; + + struct ReferenceVariant + { + protected: + std::variant mVariant; + + public: + explicit ReferenceVariant(const ESM4::Reference& ref) + : mVariant(ref) + { + } + + explicit ReferenceVariant(const ESM::CellRef& ref) + : mVariant(ref) + { + } + + bool isESM4() const { return std::holds_alternative(mVariant); } + + const ESM::CellRef& getEsm3() const { return std::get(mVariant); } + const ESM4::Reference& getEsm4() const { return std::get(mVariant); } + + ESM::CellRef& getEsm3() { return std::get(mVariant); } + ESM4::Reference& getEsm4() { return std::get(mVariant); } + }; } #endif