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:
parent
518aa5c6ae
commit
55a9ab4f52
12 changed files with 85 additions and 73 deletions
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue