1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-27 04:40:26 +00:00

Add obj.parentContainer in Lua. Refactor ContainerStore::mPtr, ContainerStore::mActor.

This commit is contained in:
Petr Mikheev 2023-08-27 09:21:36 +02:00
parent 518aa5c6ae
commit 55a9ab4f52
12 changed files with 85 additions and 73 deletions

View file

@ -21,6 +21,7 @@
#include "../mwworld/failedaction.hpp" #include "../mwworld/failedaction.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwworld/worldmodel.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
#include "../mwgui/ustring.hpp" #include "../mwgui/ustring.hpp"
@ -68,10 +69,12 @@ namespace MWClass
{ {
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
{ {
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
MWWorld::LiveCellRef<ESM::Container>* ref = ptr.get<ESM::Container>(); MWWorld::LiveCellRef<ESM::Container>* ref = ptr.get<ESM::Container>();
// store // store
ptr.getRefData().setCustomData(std::make_unique<ContainerCustomData>(*ref->mBase, ptr.getCell())); ptr.getRefData().setCustomData(std::make_unique<ContainerCustomData>(*ref->mBase, ptr.getCell()));
getContainerStore(ptr).setPtr(ptr);
MWBase::Environment::get().getWorld()->addContainerScripts(ptr, ptr.getCell()); MWBase::Environment::get().getWorld()->addContainerScripts(ptr, ptr.getCell());
} }
@ -223,9 +226,7 @@ namespace MWClass
MWWorld::ContainerStore& Container::getContainerStore(const MWWorld::Ptr& ptr) const MWWorld::ContainerStore& Container::getContainerStore(const MWWorld::Ptr& ptr) const
{ {
ensureCustomData(ptr); ensureCustomData(ptr);
auto& data = ptr.getRefData().getCustomData()->asContainerCustomData(); return ptr.getRefData().getCustomData()->asContainerCustomData().mStore;
data.mStore.mPtr = ptr;
return data.mStore;
} }
ESM::RefId Container::getScript(const MWWorld::ConstPtr& ptr) const ESM::RefId Container::getScript(const MWWorld::ConstPtr& ptr) const
@ -312,6 +313,9 @@ namespace MWClass
const ESM::ContainerState& containerState = state.asContainerState(); const ESM::ContainerState& containerState = state.asContainerState();
ptr.getRefData().setCustomData(std::make_unique<ContainerCustomData>(containerState.mInventory)); ptr.getRefData().setCustomData(std::make_unique<ContainerCustomData>(containerState.mInventory));
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
getContainerStore(ptr).setPtr(ptr);
} }
void Container::writeAdditionalState(const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const void Container::writeAdditionalState(const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const

View file

@ -39,6 +39,7 @@
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/localscripts.hpp" #include "../mwworld/localscripts.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwworld/worldmodel.hpp"
#include "../mwrender/objects.hpp" #include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
@ -117,6 +118,7 @@ namespace MWClass
{ {
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
{ {
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
auto tempData = std::make_unique<CreatureCustomData>(); auto tempData = std::make_unique<CreatureCustomData>();
CreatureCustomData* data = tempData.get(); CreatureCustomData* data = tempData.get();
MWMechanics::CreatureCustomDataResetter resetter{ ptr }; MWMechanics::CreatureCustomDataResetter resetter{ ptr };
@ -161,6 +163,7 @@ namespace MWClass
data->mContainerStore = std::make_unique<MWWorld::InventoryStore>(); data->mContainerStore = std::make_unique<MWWorld::InventoryStore>();
else else
data->mContainerStore = std::make_unique<MWWorld::ContainerStore>(); data->mContainerStore = std::make_unique<MWWorld::ContainerStore>();
data->mContainerStore->setPtr(ptr);
data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold); data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold);
@ -505,10 +508,7 @@ namespace MWClass
MWWorld::ContainerStore& Creature::getContainerStore(const MWWorld::Ptr& ptr) const MWWorld::ContainerStore& Creature::getContainerStore(const MWWorld::Ptr& ptr) const
{ {
ensureCustomData(ptr); ensureCustomData(ptr);
auto& store = *ptr.getRefData().getCustomData()->asCreatureCustomData().mContainerStore; return *ptr.getRefData().getCustomData()->asCreatureCustomData().mContainerStore;
if (hasInventoryStore(ptr))
static_cast<MWWorld::InventoryStore&>(store).setActor(ptr);
return store;
} }
MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr& ptr) const MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr& ptr) const
@ -807,6 +807,9 @@ namespace MWClass
else else
data->mContainerStore = std::make_unique<MWWorld::ContainerStore>(); data->mContainerStore = std::make_unique<MWWorld::ContainerStore>();
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
data->mContainerStore->setPtr(ptr);
ptr.getRefData().setCustomData(std::move(data)); ptr.getRefData().setCustomData(std::move(data));
} }
} }

View file

@ -297,6 +297,7 @@ namespace MWClass
{ {
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
{ {
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
bool recalculate = false; bool recalculate = false;
auto tempData = std::make_unique<NpcCustomData>(); auto tempData = std::make_unique<NpcCustomData>();
NpcCustomData* data = tempData.get(); NpcCustomData* data = tempData.get();
@ -397,9 +398,10 @@ namespace MWClass
// inventory // inventory
// setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items // setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items
auto& prng = MWBase::Environment::get().getWorld()->getPrng(); auto& prng = MWBase::Environment::get().getWorld()->getPrng();
getInventoryStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId(), prng); MWWorld::InventoryStore& inventory = getInventoryStore(ptr);
inventory.setPtr(ptr);
getInventoryStore(ptr).autoEquip(); inventory.fill(ref->mBase->mInventory, ptr.getCellRef().getRefId(), prng);
inventory.autoEquip();
} }
} }
@ -956,18 +958,13 @@ namespace MWClass
MWWorld::ContainerStore& Npc::getContainerStore(const MWWorld::Ptr& ptr) const MWWorld::ContainerStore& Npc::getContainerStore(const MWWorld::Ptr& ptr) const
{ {
ensureCustomData(ptr); return getInventoryStore(ptr);
auto& store = ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore;
store.setActor(ptr);
return store;
} }
MWWorld::InventoryStore& Npc::getInventoryStore(const MWWorld::Ptr& ptr) const MWWorld::InventoryStore& Npc::getInventoryStore(const MWWorld::Ptr& ptr) const
{ {
ensureCustomData(ptr); ensureCustomData(ptr);
auto& store = ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore; return ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore;
store.setActor(ptr);
return store;
} }
ESM::RefId Npc::getScript(const MWWorld::ConstPtr& ptr) const ESM::RefId Npc::getScript(const MWWorld::ConstPtr& ptr) const
@ -1362,8 +1359,13 @@ namespace MWClass
if (npcState.mCreatureStats.mMissingACDT) if (npcState.mCreatureStats.mMissingACDT)
ensureCustomData(ptr); ensureCustomData(ptr);
else else
{
// Create a CustomData, but don't fill it from ESM records (not needed) // Create a CustomData, but don't fill it from ESM records (not needed)
ptr.getRefData().setCustomData(std::make_unique<NpcCustomData>()); auto data = std::make_unique<NpcCustomData>();
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
data->mInventoryStore.setPtr(ptr);
ptr.getRefData().setCustomData(std::move(data));
}
} }
} }
else else

View file

@ -190,6 +190,13 @@ namespace MWLua
else else
return sol::nullopt; return sol::nullopt;
}); });
objectT["parentContainer"] = sol::readonly_property([](const ObjectT& o) -> sol::optional<ObjectT> {
const MWWorld::Ptr& ptr = o.ptr();
if (ptr.getContainerStore())
return ObjectT(ptr.getContainerStore()->getPtr());
else
return sol::nullopt;
});
objectT["position"] = sol::readonly_property( objectT["position"] = sol::readonly_property(
[](const ObjectT& o) -> osg::Vec3f { return o.ptr().getRefData().getPosition().asVec3(); }); [](const ObjectT& o) -> osg::Vec3f { return o.ptr().getRefData().getPosition().asVec3(); });
objectT["scale"] objectT["scale"]

View file

@ -495,11 +495,7 @@ namespace MWWorld
mMovedToAnotherCell.insert(std::make_pair(object.getBase(), cellToMoveTo)); mMovedToAnotherCell.insert(std::make_pair(object.getBase(), cellToMoveTo));
requestMergedRefsUpdate(); requestMergedRefsUpdate();
MWWorld::Ptr ptr(object.getBase(), cellToMoveTo); return MWWorld::Ptr(object.getBase(), cellToMoveTo);
const Class& cls = ptr.getClass();
if (cls.hasInventoryStore(ptr))
cls.getInventoryStore(ptr).setActor(ptr);
return ptr;
} }
struct MergeVisitor struct MergeVisitor

View file

@ -376,8 +376,6 @@ namespace MWWorld
newPtr.getRefData().setCount(count); newPtr.getRefData().setCount(count);
newPtr.getRefData().setLuaScripts(nullptr); newPtr.getRefData().setLuaScripts(nullptr);
MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); MWBase::Environment::get().getWorldModel()->registerPtr(newPtr);
if (hasInventoryStore(newPtr))
getInventoryStore(newPtr).setActor(newPtr);
return newPtr; return newPtr;
} }
@ -386,8 +384,6 @@ namespace MWWorld
Ptr newPtr = copyToCellImpl(ptr, cell); Ptr newPtr = copyToCellImpl(ptr, cell);
ptr.getRefData().setLuaScripts(nullptr); ptr.getRefData().setLuaScripts(nullptr);
MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); MWBase::Environment::get().getWorldModel()->registerPtr(newPtr);
if (hasInventoryStore(newPtr))
getInventoryStore(newPtr).setActor(newPtr);
return newPtr; return newPtr;
} }

View file

@ -350,7 +350,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(
const ESM::RefId& script = item.getClass().getScript(item); const ESM::RefId& script = item.getClass().getScript(item);
if (!script.empty()) if (!script.empty())
{ {
if (mActor == player) const Ptr& contPtr = getPtr();
if (contPtr == player)
{ {
// Items in player's inventory have cell set to 0, so their scripts will never be removed // Items in player's inventory have cell set to 0, so their scripts will never be removed
item.mCell = nullptr; item.mCell = nullptr;
@ -359,10 +360,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(
{ {
// Set mCell to the cell of the container/actor, so that the scripts are removed properly when // Set mCell to the cell of the container/actor, so that the scripts are removed properly when
// the cell of the container/actor goes inactive // the cell of the container/actor goes inactive
if (!mPtr.isEmpty()) if (!contPtr.isEmpty())
item.mCell = mPtr.getCell(); item.mCell = contPtr.getCell();
else if (!mActor.isEmpty())
item.mCell = mActor.getCell();
} }
item.mContainerStore = this; item.mContainerStore = this;
@ -371,12 +370,12 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(
// Set OnPCAdd special variable, if it is declared // Set OnPCAdd special variable, if it is declared
// Make sure to do this *after* we have added the script to LocalScripts // Make sure to do this *after* we have added the script to LocalScripts
if (mActor == player) if (contPtr == player)
item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1); item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1);
} }
// we should not fire event for InventoryStore yet - it has some custom logic // we should not fire event for InventoryStore yet - it has some custom logic
if (mListener && !(!mActor.isEmpty() && mActor.getClass().hasInventoryStore(mActor))) if (mListener && typeid(*this) == typeid(ContainerStore))
mListener->itemAdded(item, count); mListener->itemAdded(item, count);
return it; return it;
@ -415,8 +414,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp(const Ptr& ptr,
for (MWWorld::ContainerStoreIterator iter(begin(type)); iter != end(); ++iter) for (MWWorld::ContainerStoreIterator iter(begin(type)); iter != end(); ++iter)
{ {
// Don't stack with equipped items // Don't stack with equipped items
if (!mActor.isEmpty() && mActor.getClass().hasInventoryStore(mActor)) if (auto* inventoryStore = dynamic_cast<InventoryStore*>(this))
if (mActor.getClass().getInventoryStore(mActor).isEquipped(*iter)) if (inventoryStore->isEquipped(*iter))
continue; continue;
if (stacks(*iter, ptr)) if (stacks(*iter, ptr))
@ -586,7 +585,7 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, bool equipReplac
flagAsModified(); flagAsModified();
// we should not fire event for InventoryStore yet - it has some custom logic // we should not fire event for InventoryStore yet - it has some custom logic
if (mListener && !(!mActor.isEmpty() && mActor.getClass().hasInventoryStore(mActor))) if (mListener && typeid(*this) == typeid(ContainerStore))
mListener->itemRemoved(item, count - toRemove); mListener->itemRemoved(item, count - toRemove);
// number of removed items // number of removed items
@ -694,13 +693,14 @@ bool MWWorld::ContainerStore::isResolved() const
void MWWorld::ContainerStore::resolve() void MWWorld::ContainerStore::resolve()
{ {
if (!mResolved && !mPtr.isEmpty()) const Ptr& container = getPtr();
if (!mResolved && !container.isEmpty() && container.getType() == ESM::REC_CONT)
{ {
for (const auto&& ptr : *this) for (const auto&& ptr : *this)
ptr.getRefData().setCount(0); ptr.getRefData().setCount(0);
Misc::Rng::Generator prng{ mSeed }; Misc::Rng::Generator prng{ mSeed };
fill(mPtr.get<ESM::Container>()->mBase->mInventory, ESM::RefId(), prng); fill(container.get<ESM::Container>()->mBase->mInventory, ESM::RefId(), prng);
addScripts(*this, mPtr.mCell); addScripts(*this, container.mCell);
} }
mModified = true; mModified = true;
} }
@ -715,13 +715,14 @@ MWWorld::ResolutionHandle MWWorld::ContainerStore::resolveTemporarily()
listener = std::make_shared<ResolutionListener>(*this); listener = std::make_shared<ResolutionListener>(*this);
mResolutionListener = listener; mResolutionListener = listener;
} }
if (!mResolved && !mPtr.isEmpty()) const Ptr& container = getPtr();
if (!mResolved && !container.isEmpty() && container.getType() == ESM::REC_CONT)
{ {
for (const auto&& ptr : *this) for (const auto&& ptr : *this)
ptr.getRefData().setCount(0); ptr.getRefData().setCount(0);
Misc::Rng::Generator prng{ mSeed }; Misc::Rng::Generator prng{ mSeed };
fill(mPtr.get<ESM::Container>()->mBase->mInventory, ESM::RefId(), prng); fill(container.get<ESM::Container>()->mBase->mInventory, ESM::RefId(), prng);
addScripts(*this, mPtr.mCell); addScripts(*this, container.mCell);
} }
return { listener }; return { listener };
} }
@ -731,12 +732,13 @@ void MWWorld::ContainerStore::unresolve()
if (mModified) if (mModified)
return; return;
if (mResolved && !mPtr.isEmpty()) const Ptr& container = getPtr();
if (mResolved && !container.isEmpty() && container.getType() == ESM::REC_CONT)
{ {
for (const auto&& ptr : *this) for (const auto&& ptr : *this)
ptr.getRefData().setCount(0); ptr.getRefData().setCount(0);
fillNonRandom(mPtr.get<ESM::Container>()->mBase->mInventory, ESM::RefId(), mSeed); fillNonRandom(container.get<ESM::Container>()->mBase->mInventory, ESM::RefId(), mSeed);
addScripts(*this, mPtr.mCell); addScripts(*this, container.mCell);
mResolved = false; mResolved = false;
} }
} }

View file

@ -125,11 +125,6 @@ namespace MWWorld
bool mRechargingItemsUpToDate; bool mRechargingItemsUpToDate;
// Non-empty only if is InventoryStore.
// The actor whose inventory it is.
// TODO: Consider merging mActor and mPtr.
MWWorld::Ptr mActor;
private: private:
MWWorld::CellRefList<ESM::Potion> potions; MWWorld::CellRefList<ESM::Potion> potions;
MWWorld::CellRefList<ESM::Apparatus> appas; MWWorld::CellRefList<ESM::Apparatus> appas;
@ -150,7 +145,7 @@ namespace MWWorld
bool mModified; bool mModified;
bool mResolved; bool mResolved;
unsigned int mSeed; unsigned int mSeed;
MWWorld::Ptr mPtr; // Container that contains this store. Set in MWClass::Container::getContainerStore MWWorld::SafePtr mPtr; // Container or actor that holds this store.
std::weak_ptr<ResolutionListener> mResolutionListener; std::weak_ptr<ResolutionListener> mResolutionListener;
ContainerStoreIterator addImp(const Ptr& ptr, int count, bool markModified = true); ContainerStoreIterator addImp(const Ptr& ptr, int count, bool markModified = true);
@ -189,6 +184,10 @@ namespace MWWorld
return res; return res;
} }
// Container or actor that holds this store.
const Ptr& getPtr() const { return mPtr.ptrOrEmpty(); }
void setPtr(const Ptr& ptr) { mPtr = SafePtr(ptr); }
ConstContainerStoreIterator cbegin(int mask = Type_All) const; ConstContainerStoreIterator cbegin(int mask = Type_All) const;
ConstContainerStoreIterator cend() const; ConstContainerStoreIterator cend() const;
ConstContainerStoreIterator begin(int mask = Type_All) const; ConstContainerStoreIterator begin(int mask = Type_All) const;

View file

@ -133,8 +133,9 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(
= MWWorld::ContainerStore::add(itemPtr, count, allowAutoEquip, resolve); = MWWorld::ContainerStore::add(itemPtr, count, allowAutoEquip, resolve);
// Auto-equip items if an armor/clothing item is added, but not for the player nor werewolves // Auto-equip items if an armor/clothing item is added, but not for the player nor werewolves
if (allowAutoEquip && mActor != MWMechanics::getPlayer() && mActor.getClass().isNpc() const Ptr& actor = getPtr();
&& !mActor.getClass().getNpcStats(mActor).isWerewolf()) if (allowAutoEquip && actor != MWMechanics::getPlayer() && actor.getClass().isNpc()
&& !actor.getClass().getNpcStats(actor).isWerewolf())
{ {
auto type = itemPtr.getType(); auto type = itemPtr.getType();
if (type == ESM::Armor::sRecordId || type == ESM::Clothing::sRecordId) if (type == ESM::Armor::sRecordId || type == ESM::Clothing::sRecordId)
@ -220,12 +221,13 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::findSlot(int slot) cons
void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_) void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_)
{ {
if (!mActor.getClass().isNpc()) const Ptr& actor = getPtr();
if (!actor.getClass().isNpc())
{ {
// In original game creatures do not autoequip weapon, but we need it for weapon sheathing. // In original game creatures do not autoequip weapon, but we need it for weapon sheathing.
// The only case when the difference is noticable - when this creature sells weapon. // The only case when the difference is noticable - when this creature sells weapon.
// So just disable weapon autoequipping for creatures which sells weapon. // So just disable weapon autoequipping for creatures which sells weapon.
int services = mActor.getClass().getServices(mActor); int services = actor.getClass().getServices(actor);
bool sellsWeapon = services & (ESM::NPC::Weapon | ESM::NPC::MagicItems); bool sellsWeapon = services & (ESM::NPC::Weapon | ESM::NPC::MagicItems);
if (sellsWeapon) if (sellsWeapon)
return; return;
@ -280,7 +282,7 @@ void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_)
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j) for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
{ {
float skillValue = mActor.getClass().getSkill(mActor, weaponSkills[j]); float skillValue = actor.getClass().getSkill(actor, weaponSkills[j]);
if (skillValue > max && !weaponSkillVisited[j]) if (skillValue > max && !weaponSkillVisited[j])
{ {
max = skillValue; max = skillValue;
@ -323,7 +325,7 @@ void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_)
} }
} }
if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, mActor).first) if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, actor).first)
{ {
// Do not equip ranged weapons, if there is no suitable ammo // Do not equip ranged weapons, if there is no suitable ammo
bool hasAmmo = true; bool hasAmmo = true;
@ -378,7 +380,8 @@ void MWWorld::InventoryStore::autoEquipArmor(TSlots& slots_)
{ {
// Only NPCs can wear armor for now. // Only NPCs can wear armor for now.
// For creatures we equip only shields. // For creatures we equip only shields.
if (!mActor.getClass().isNpc()) const Ptr& actor = getPtr();
if (!actor.getClass().isNpc())
{ {
autoEquipShield(slots_); autoEquipShield(slots_);
return; return;
@ -389,7 +392,7 @@ void MWWorld::InventoryStore::autoEquipArmor(TSlots& slots_)
static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
float unarmoredSkill = mActor.getClass().getSkill(mActor, ESM::Skill::Unarmored); float unarmoredSkill = actor.getClass().getSkill(actor, ESM::Skill::Unarmored);
float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
for (ContainerStoreIterator iter(begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter != end(); for (ContainerStoreIterator iter(begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter != end();
@ -397,7 +400,7 @@ void MWWorld::InventoryStore::autoEquipArmor(TSlots& slots_)
{ {
Ptr test = *iter; Ptr test = *iter;
switch (test.getClass().canBeEquipped(test, mActor).first) switch (test.getClass().canBeEquipped(test, actor).first)
{ {
case 0: case 0:
continue; continue;
@ -406,7 +409,7 @@ void MWWorld::InventoryStore::autoEquipArmor(TSlots& slots_)
} }
if (iter.getType() == ContainerStore::Type_Armor if (iter.getType() == ContainerStore::Type_Armor
&& test.getClass().getEffectiveArmorRating(test, mActor) <= std::max(unarmoredRating, 0.f)) && test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f))
{ {
continue; continue;
} }
@ -431,8 +434,8 @@ void MWWorld::InventoryStore::autoEquipArmor(TSlots& slots_)
if (old.get<ESM::Armor>()->mBase->mData.mType == test.get<ESM::Armor>()->mBase->mData.mType) if (old.get<ESM::Armor>()->mBase->mData.mType == test.get<ESM::Armor>()->mBase->mData.mType)
{ {
if (old.getClass().getEffectiveArmorRating(old, mActor) if (old.getClass().getEffectiveArmorRating(old, actor)
>= test.getClass().getEffectiveArmorRating(test, mActor)) >= test.getClass().getEffectiveArmorRating(test, actor))
// old armor had better armor rating // old armor had better armor rating
continue; continue;
} }
@ -494,7 +497,7 @@ void MWWorld::InventoryStore::autoEquipShield(TSlots& slots_)
{ {
if (iter->get<ESM::Armor>()->mBase->mData.mType != ESM::Armor::Shield) if (iter->get<ESM::Armor>()->mBase->mData.mType != ESM::Armor::Shield)
continue; continue;
if (iter->getClass().canBeEquipped(*iter, mActor).first != 1) if (iter->getClass().canBeEquipped(*iter, getPtr()).first != 1)
continue; continue;
std::pair<std::vector<int>, bool> shieldSlots = iter->getClass().getEquipmentSlots(*iter); std::pair<std::vector<int>, bool> shieldSlots = iter->getClass().getEquipmentSlots(*iter);
int slot = shieldSlots.first[0]; int slot = shieldSlots.first[0];
@ -606,8 +609,9 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, bool equipReplac
// If an armor/clothing item is removed, try to find a replacement, // If an armor/clothing item is removed, try to find a replacement,
// but not for the player nor werewolves, and not if the RemoveItem script command // but not for the player nor werewolves, and not if the RemoveItem script command
// was used (equipReplacement is false) // was used (equipReplacement is false)
if (equipReplacement && wasEquipped && (mActor != MWMechanics::getPlayer()) && mActor.getClass().isNpc() const Ptr& actor = getPtr();
&& !mActor.getClass().getNpcStats(mActor).isWerewolf()) if (equipReplacement && wasEquipped && (actor != MWMechanics::getPlayer()) && actor.getClass().isNpc()
&& !actor.getClass().getNpcStats(actor).isWerewolf())
{ {
auto type = item.getType(); auto type = item.getType();
if (type == ESM::Armor::sRecordId || type == ESM::Clothing::sRecordId) if (type == ESM::Armor::sRecordId || type == ESM::Clothing::sRecordId)
@ -643,7 +647,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, b
{ {
retval = restack(*it); retval = restack(*it);
if (mActor == MWMechanics::getPlayer()) if (getPtr() == MWMechanics::getPlayer())
{ {
// Unset OnPCEquip Variable on item's script, if it has a script with that variable declared // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared
const ESM::RefId& script = it->getClass().getScript(*it); const ESM::RefId& script = it->getClass().getScript(*it);

View file

@ -94,9 +94,6 @@ namespace MWWorld
InventoryStore& operator=(const InventoryStore& store); InventoryStore& operator=(const InventoryStore& store);
const MWWorld::Ptr& getActor() const { return mActor; }
void setActor(const MWWorld::Ptr& actor) { mActor = actor; }
std::unique_ptr<ContainerStore> clone() override std::unique_ptr<ContainerStore> clone() override
{ {
auto res = std::make_unique<InventoryStore>(*this); auto res = std::make_unique<InventoryStore>(*this);

View file

@ -153,8 +153,9 @@ namespace MWWorld
class SafePtr class SafePtr
{ {
public: public:
using Id = ESM::RefNum; using Id = ESM::FormId;
SafePtr() = default;
explicit SafePtr(Id id) explicit SafePtr(Id id)
: mId(id) : mId(id)
{ {
@ -172,7 +173,7 @@ namespace MWWorld
} }
private: private:
const Id mId; Id mId;
mutable Ptr mPtr; mutable Ptr mPtr;
mutable size_t mLastUpdate = 0; mutable size_t mLastUpdate = 0;

View file

@ -159,6 +159,7 @@
-- @field #string ownerFactionId Faction who owns the object (nil if missing). Global and self scripts can set the value. -- @field #string ownerFactionId Faction who owns the object (nil if missing). Global and self scripts can set the value.
-- @field #number ownerFactionRank Rank required to be allowed to pick up the object. Global and self scripts can set the value. -- @field #number ownerFactionRank Rank required to be allowed to pick up the object. Global and self scripts can set the value.
-- @field #Cell cell The cell where the object currently is. During loading a game and for objects in an inventory or a container `cell` is nil. -- @field #Cell cell The cell where the object currently is. During loading a game and for objects in an inventory or a container `cell` is nil.
-- @field #GameObject parentContainer Container or actor that contains (or has in inventory) this object. It is nil if the object is in a cell.
-- @field #any type Type of the object (one of the tables from the package @{openmw.types#types}). -- @field #any type Type of the object (one of the tables from the package @{openmw.types#types}).
-- @field #number count Count (>1 means a stack of objects). -- @field #number count Count (>1 means a stack of objects).
-- @field #string recordId Returns record ID of the object in lowercase. -- @field #string recordId Returns record ID of the object in lowercase.