1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-06 15:15:34 +00:00

gives MWWorld::CellRef the MWWorld::Cell treatment

MWWorld::CellRef now has a variant, and datas that are part of the intersection of both ESM4::Reference and ESM::CellRef are part of MWWorld::CellRef

For ESM4 most data isn't filled in, so it returns default values.
This commit is contained in:
florent.teppe 2023-01-27 19:40:45 +01:00
parent 23614ae2ae
commit e6e27413d9
3 changed files with 188 additions and 91 deletions

View file

@ -7,10 +7,54 @@
namespace MWWorld 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) const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum)
{ {
if (!mCellRef.mRefNum.isSet()) if (!mRefNum.isSet())
{ {
// Generated RefNums have negative mContentFile // Generated RefNums have negative mContentFile
assert(lastAssignedRefNum.mContentFile < 0); assert(lastAssignedRefNum.mContentFile < 0);
@ -22,30 +66,38 @@ namespace MWWorld
else else
Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum"; Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum";
} }
mCellRef.mRefNum = lastAssignedRefNum; mRefNum = lastAssignedRefNum;
mChanged = true; mChanged = true;
} }
return mCellRef.mRefNum; if (!mCellRef.isESM4())
mCellRef.getEsm3().mRefNum = mRefNum;
return mRefNum;
} }
void CellRef::unsetRefNum() void CellRef::unsetRefNum()
{ {
mCellRef.mRefNum = ESM::RefNum{}; mRefNum = ESM::RefNum{};
if (!mCellRef.isESM4())
mCellRef.getEsm3().mRefNum = mRefNum;
} }
void CellRef::setScale(float scale) void CellRef::setScale(float scale)
{ {
if (scale != mCellRef.mScale) if (scale != mScale)
{ {
mChanged = true; mChanged = true;
mCellRef.mScale = scale; mScale = scale;
} }
if (!mCellRef.isESM4())
mCellRef.getEsm3().mScale = Scale;
} }
void CellRef::setPosition(const ESM::Position& position) void CellRef::setPosition(const ESM::Position& position)
{ {
mChanged = true; mChanged = true;
mCellRef.mPos = position; mPos = position;
if (!mCellRef.isESM4())
mCellRef.getEsm3().mPos = position;
} }
float CellRef::getNormalizedEnchantmentCharge(int maxCharge) const float CellRef::getNormalizedEnchantmentCharge(int maxCharge) const
@ -54,113 +106,140 @@ namespace MWWorld
{ {
return 0; return 0;
} }
else if (mCellRef.mEnchantmentCharge == -1) else if (mEnchantmentCharge == -1)
{ {
return 1; return 1;
} }
else else
{ {
return mCellRef.mEnchantmentCharge / static_cast<float>(maxCharge); return mEnchantmentCharge / static_cast<float>(maxCharge);
} }
} }
void CellRef::setEnchantmentCharge(float charge) void CellRef::setEnchantmentCharge(float charge)
{ {
if (charge != mCellRef.mEnchantmentCharge) if (charge != mEnchantmentCharge)
{ {
mChanged = true; mChanged = true;
mCellRef.mEnchantmentCharge = charge; mEnchantmentCharge = charge;
} }
if (!mCellRef.isESM4())
mCellRef.getEsm3().mEnchantmentCharge = mEnchantmentCharge;
} }
void CellRef::setCharge(int charge) void CellRef::setCharge(int charge)
{ {
if (charge != mCellRef.mChargeInt) if (mCellRef.isESM4())
return;
auto& cellRef3 = mCellRef.getEsm3();
if (charge != cellRef3.mChargeInt)
{ {
mChanged = true; mChanged = true;
mCellRef.mChargeInt = charge; cellRef3.mChargeInt = charge;
} }
} }
void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder) void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder)
{ {
mCellRef.mChargeIntRemainder += std::abs(chargeRemainder); if (mCellRef.isESM4())
if (mCellRef.mChargeIntRemainder > 1.0f) return;
auto& cellRef3 = mCellRef.getEsm3();
cellRef3.mChargeIntRemainder += std::abs(chargeRemainder);
if (cellRef3.mChargeIntRemainder > 1.0f)
{ {
float newChargeRemainder = (mCellRef.mChargeIntRemainder - std::floor(mCellRef.mChargeIntRemainder)); float newChargeRemainder = (cellRef3.mChargeIntRemainder - std::floor(cellRef3.mChargeIntRemainder));
if (mCellRef.mChargeInt <= static_cast<int>(mCellRef.mChargeIntRemainder)) if (cellRef3.mChargeInt <= static_cast<int>(cellRef3.mChargeIntRemainder))
{ {
mCellRef.mChargeInt = 0; cellRef3.mChargeInt = 0;
} }
else else
{ {
mCellRef.mChargeInt -= static_cast<int>(mCellRef.mChargeIntRemainder); cellRef3.mChargeInt -= static_cast<int>(cellRef3.mChargeIntRemainder);
} }
mCellRef.mChargeIntRemainder = newChargeRemainder; cellRef3.mChargeIntRemainder = newChargeRemainder;
} }
} }
void CellRef::setChargeFloat(float charge) void CellRef::setChargeFloat(float charge)
{ {
if (charge != mCellRef.mChargeFloat) if (mCellRef.isESM4())
return;
auto& cellRef3 = mCellRef.getEsm3();
if (charge != cellRef3.mChargeFloat)
{ {
mChanged = true; mChanged = true;
mCellRef.mChargeFloat = charge; cellRef3.mChargeFloat = charge;
} }
} }
void CellRef::resetGlobalVariable() void CellRef::resetGlobalVariable()
{ {
if (!mCellRef.mGlobalVariable.empty()) if (!mGlobalVariable.empty())
{ {
mChanged = true; mChanged = true;
mCellRef.mGlobalVariable.erase(); mGlobalVariable.erase();
} }
if (!mCellRef.isESM4())
mCellRef.getEsm3().mGlobalVariable = mGlobalVariable;
} }
void CellRef::setFactionRank(int factionRank) void CellRef::setFactionRank(int factionRank)
{ {
if (factionRank != mCellRef.mFactionRank) if (factionRank != mFactionRank)
{ {
mChanged = true; mChanged = true;
mCellRef.mFactionRank = factionRank; mFactionRank = factionRank;
} }
if (!mCellRef.isESM4())
mCellRef.getEsm3().mFactionRank = mFactionRank;
} }
void CellRef::setOwner(const ESM::RefId& owner) void CellRef::setOwner(const ESM::RefId& owner)
{ {
if (owner != mCellRef.mOwner) if (owner != mOwner)
{ {
mChanged = true; mChanged = true;
mCellRef.mOwner = owner; mOwner = owner;
} }
if (!mCellRef.isESM4())
mCellRef.getEsm3().mOwner = mOwner;
} }
void CellRef::setSoul(const ESM::RefId& soul) void CellRef::setSoul(const ESM::RefId& soul)
{ {
if (soul != mCellRef.mSoul) if (soul != mSoul)
{ {
mChanged = true; mChanged = true;
mCellRef.mSoul = soul; mSoul = soul;
} }
if (!mCellRef.isESM4())
mCellRef.getEsm3().mSoul = mSoul;
} }
void CellRef::setFaction(const ESM::RefId& faction) void CellRef::setFaction(const ESM::RefId& faction)
{ {
if (faction != mCellRef.mFaction) if (faction != mFaction)
{ {
mChanged = true; mChanged = true;
mCellRef.mFaction = faction; mFaction = faction;
} }
if (!mCellRef.isESM4())
mCellRef.getEsm3().mFaction = mFaction;
} }
void CellRef::setLockLevel(int lockLevel) void CellRef::setLockLevel(int lockLevel)
{ {
if (lockLevel != mCellRef.mLockLevel) if (lockLevel != mLockLevel)
{ {
mChanged = true; mChanged = true;
mCellRef.mLockLevel = lockLevel; mLockLevel = lockLevel;
} }
if (!mCellRef.isESM4())
mCellRef.getEsm3().mLockLevel = mLockLevel;
} }
void CellRef::lock(int lockLevel) void CellRef::lock(int lockLevel)
@ -173,30 +252,38 @@ namespace MWWorld
void CellRef::unlock() void CellRef::unlock()
{ {
setLockLevel(-abs(mCellRef.mLockLevel)); // Makes lockLevel negative setLockLevel(-abs(mLockLevel)); // Makes lockLevel negative
} }
void CellRef::setTrap(const ESM::RefId& trap) void CellRef::setTrap(const ESM::RefId& trap)
{ {
if (trap != mCellRef.mTrap) if (trap != mTrap)
{ {
mChanged = true; mChanged = true;
mCellRef.mTrap = trap; mTrap = trap;
} }
if (!mCellRef.isESM4())
mCellRef.getEsm3().mTrap = mTrap;
} }
void CellRef::setGoldValue(int value) void CellRef::setGoldValue(int value)
{ {
if (value != mCellRef.mGoldValue) if (value != mGoldValue)
{ {
mChanged = true; mChanged = true;
mCellRef.mGoldValue = value; mGoldValue = value;
} }
if (!mCellRef.isESM4())
mCellRef.getEsm3().mGoldValue = mGoldValue;
} }
void CellRef::writeState(ESM::ObjectState& state) const void CellRef::writeState(ESM::ObjectState& state) const
{ {
state.mRef = mCellRef; if (!mCellRef.isESM4())
{
auto& cellRef3 = mCellRef.getEsm3();
state.mRef = cellRef3;
}
} }
} }

View file

@ -19,24 +19,12 @@ namespace MWWorld
class CellRef class CellRef
{ {
public: public:
CellRef(const ESM::CellRef& ref) CellRef(const ESM::CellRef& ref);
: mCellRef(ref)
{
mIsEsm4 = false;
mChanged = false;
}
CellRef(const ESM4::Reference& 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;
}
// Note: Currently unused for items in containers // Note: Currently unused for items in containers
const ESM::RefNum& getRefNum() const { return mCellRef.mRefNum; } const ESM::RefNum& getRefNum() const { return mRefNum; }
// Returns RefNum. // Returns RefNum.
// If RefNum is not set, assigns a generated one and changes the "lastAssignedRefNum" counter. // If RefNum is not set, assigns a generated one and changes the "lastAssignedRefNum" counter.
@ -46,44 +34,32 @@ namespace MWWorld
void unsetRefNum(); void unsetRefNum();
/// Does the RefNum have a content file? /// 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 // 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 // For doors - true if this door teleports to somewhere else, false
// if it should open through animation. // 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. // 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) // Destination cell for doors (optional)
const std::string& getDestCell() const { return mCellRef.mDestCell; } const std::string& getDestCell() const { return mDestCell; }
// Scale applied to mesh // Scale applied to mesh
float getScale() const float getScale() const { return mScale; }
{
if (mIsEsm4)
return mCellRef4.mScale;
else
return mCellRef.mScale;
}
void setScale(float scale); void setScale(float scale);
// The *original* position and rotation as it was given in the Construction Set. // The *original* position and rotation as it was given in the Construction Set.
// Current position and rotation of the object is stored in RefData. // Current position and rotation of the object is stored in RefData.
const ESM::Position& getPosition() const const ESM::Position& getPosition() const { return mPos; }
{
if (mIsEsm4)
return mRefrPos;
else
return mCellRef.mPos;
}
void setPosition(const ESM::Position& position); void setPosition(const ESM::Position& position);
// Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). // 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). // Remaining enchantment charge rescaled to the supplied maximum charge (such as one of the enchantment).
float getNormalizedEnchantmentCharge(int maxCharge) const; float getNormalizedEnchantmentCharge(int maxCharge) const;
@ -93,50 +69,53 @@ namespace MWWorld
// For weapon or armor, this is the remaining item health. // For weapon or armor, this is the remaining item health.
// For tools (lockpicks, probes, repair hammer) it is the remaining uses. // For tools (lockpicks, probes, repair hammer) it is the remaining uses.
// If this returns int(-1) it means full health. // If this returns int(-1) it means full health.
int getCharge() const { return mCellRef.mChargeInt; } int getCharge() const { return mCellRef.isESM4() ? 0 : mCellRef.getEsm3().mChargeInt; }
float getChargeFloat() const { return mCellRef.mChargeFloat; } // Implemented as union with int charge float getChargeFloat() const
{
return mCellRef.isESM4() ? 0.f : mCellRef.getEsm3().mChargeFloat;
} // Implemented as union with int charge
void setCharge(int charge); void setCharge(int charge);
void setChargeFloat(float charge); void setChargeFloat(float charge);
void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1 void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1
// The NPC that owns this object (and will get angry if you steal it) // 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); 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 // 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. // 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. // 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(); void resetGlobalVariable();
// ID of creature trapped in this soul gem // 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); void setSoul(const ESM::RefId& soul);
// The faction that owns this object (and will get angry if // The faction that owns this object (and will get angry if
// you take it and are not a faction member) // 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); void setFaction(const ESM::RefId& faction);
// PC faction rank required to use the item. Sometimes is -1, which means "any rank". // PC faction rank required to use the item. Sometimes is -1, which means "any rank".
void setFactionRank(int factionRank); void setFactionRank(int factionRank);
int getFactionRank() const { return mCellRef.mFactionRank; } int getFactionRank() const { return mFactionRank; }
// Lock level for doors and containers // Lock level for doors and containers
// Positive for a locked door. 0 for a door that was never locked. // Positive for a locked door. 0 for a door that was never locked.
// For an unlocked door, it is set to -(previous locklevel) // 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 setLockLevel(int lockLevel);
void lock(int lockLevel); void lock(int lockLevel);
void unlock(); void unlock();
// Key and trap ID names, if any // Key and trap ID names, if any
const ESM::RefId& getKey() const { return mCellRef.mKey; } const ESM::RefId& getKey() const { return mKey; }
const ESM::RefId& getTrap() const { return mCellRef.mTrap; } const ESM::RefId& getTrap() const { return mTrap; }
void setTrap(const ESM::RefId& trap); void setTrap(const ESM::RefId& trap);
// This is 5 for Gold_005 references, 100 for Gold_100 and so on. // 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); void setGoldValue(int value);
// Write the content of this CellRef into the given ObjectState // Write the content of this CellRef into the given ObjectState
@ -147,10 +126,15 @@ namespace MWWorld
private: private:
bool mChanged; bool mChanged;
ESM::CellRef mCellRef; ESM::ReferenceVariant mCellRef;
ESM4::Reference mCellRef4;
ESM::Position mRefrPos; ESM::RefId mSoul, mFaction, mKey, mTrap, mOwner, mReferenceType;
bool mIsEsm4; float Scale;
ESM::Position mPos, mDoorDest;
ESM::RefNum mRefNum;
std::string mGlobalVariable, mDestCell;
int mLockLevel, mGoldValue, mFactionRank, mEnchantmentCharge;
float mScale;
}; };
} }

View file

@ -4,7 +4,8 @@
#include <string_view> #include <string_view>
#include <variant> #include <variant>
#include <components/misc/notnullptr.hpp> #include <components/esm3/cellref.hpp>
#include <components/esm4/loadrefr.hpp>
namespace ESM4 namespace ESM4
{ {
@ -39,6 +40,31 @@ namespace ESM
const ESM::Cell& getEsm3() const; const ESM::Cell& getEsm3() const;
}; };
struct ReferenceVariant
{
protected:
std::variant<ESM::CellRef, ESM4::Reference> 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<ESM4::Reference>(mVariant); }
const ESM::CellRef& getEsm3() const { return std::get<ESM::CellRef>(mVariant); }
const ESM4::Reference& getEsm4() const { return std::get<ESM4::Reference>(mVariant); }
ESM::CellRef& getEsm3() { return std::get<ESM::CellRef>(mVariant); }
ESM4::Reference& getEsm4() { return std::get<ESM4::Reference>(mVariant); }
};
} }
#endif #endif