1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-11 06:40:34 +00:00
OpenMW/apps/openmw/mwworld/containerstore.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1529 lines
46 KiB
C++
Raw Normal View History

2012-02-20 14:14:39 +01:00
#include "containerstore.hpp"
#include <cassert>
#include <stdexcept>
2012-02-20 14:14:39 +01:00
2018-08-14 23:05:43 +04:00
#include <components/debug/debuglog.hpp>
#include <components/esm3/inventorystate.hpp>
#include <components/esm3/loadench.hpp>
#include <components/misc/strings/algorithm.hpp>
#include <components/misc/strings/lower.hpp>
Store RefData::mBaseNode as osg::ref_ptr Direct leak of 16197408 byte(s) in 56241 object(s) allocated from: #0 0x5572356d4d42 in operator new(unsigned long) (/home/elsid/dev/openmw/build/clang/asan/openmw+0xae0d42) #1 0x557236938196 in (anonymous namespace)::addObject(MWWorld::Ptr const&, MWWorld::World const&, std::__1::vector<ESM::RefNum, std::__1::allocator<ESM::RefNum> > const&, MWPhysics::PhysicsSystem&, MWRender::RenderingManager&) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:119:42 #2 0x55723692e51b in MWWorld::Scene::insertCell(MWWorld::CellStore&, Loading::Listener*)::$_7::operator()(MWWorld::Ptr const&) const /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:913:62 #3 0x55723692e51b in void (anonymous namespace)::InsertVisitor::insert<MWWorld::Scene::insertCell(MWWorld::CellStore&, Loading::Listener*)::$_7>(MWWorld::Scene::insertCell(MWWorld::CellStore&, Loading::Listener*)::$_7&&) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:230:21 #4 0x55723692e51b in MWWorld::Scene::insertCell(MWWorld::CellStore&, Loading::Listener*) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:913:23 #5 0x55723692d451 in MWWorld::Scene::loadCell(MWWorld::CellStore*, Loading::Listener*, bool, osg::Vec3f const&) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:449:9 #6 0x5572369299f5 in MWWorld::Scene::changeCellGrid(osg::Vec3f const&, int, int, bool) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:612:17 #7 0x557236928521 in MWWorld::Scene::update(float) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:315:13 #8 0x5572368d4c98 in MWWorld::World::update(float, bool) /home/elsid/dev/openmw/apps/openmw/mwworld/worldimp.cpp:1833:22 #9 0x557236ebbb72 in OMW::Engine::frame(float) /home/elsid/dev/openmw/apps/openmw/engine.cpp:418:25 #10 0x557236ed250a in OMW::Engine::go() /home/elsid/dev/openmw/apps/openmw/engine.cpp:1102:14 #11 0x557236eb621a in runApplication(int, char**) /home/elsid/dev/openmw/apps/openmw/main.cpp:228:17 #12 0x55723774d622 in wrapApplication(int (*)(int, char**), int, char**, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool) /home/elsid/dev/openmw/components/debug/debugging.cpp:328:19 #13 0x557236eb651f in main /home/elsid/dev/openmw/apps/openmw/main.cpp:240:12 #14 0x7fbf58a3f2cf (/usr/lib/libc.so.6+0x232cf) (BuildId: e637217a46491314667a7a37b2155cb07afc1a40) Direct leak of 396288 byte(s) in 1376 object(s) allocated from: #0 0x5572356d4d42 in operator new(unsigned long) (/home/elsid/dev/openmw/build/clang/asan/openmw+0xae0d42) #1 0x557236938196 in (anonymous namespace)::addObject(MWWorld::Ptr const&, MWWorld::World const&, std::__1::vector<ESM::RefNum, std::__1::allocator<ESM::RefNum> > const&, MWPhysics::PhysicsSystem&, MWRender::RenderingManager&) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:119:42 #2 0x55723692e51b in MWWorld::Scene::insertCell(MWWorld::CellStore&, Loading::Listener*)::$_7::operator()(MWWorld::Ptr const&) const /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:913:62 #3 0x55723692e51b in void (anonymous namespace)::InsertVisitor::insert<MWWorld::Scene::insertCell(MWWorld::CellStore&, Loading::Listener*)::$_7>(MWWorld::Scene::insertCell(MWWorld::CellStore&, Loading::Listener*)::$_7&&) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:230:21 #4 0x55723692e51b in MWWorld::Scene::insertCell(MWWorld::CellStore&, Loading::Listener*) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:913:23 #5 0x55723692d451 in MWWorld::Scene::loadCell(MWWorld::CellStore*, Loading::Listener*, bool, osg::Vec3f const&) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:449:9 #6 0x5572369299f5 in MWWorld::Scene::changeCellGrid(osg::Vec3f const&, int, int, bool) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:612:17 #7 0x557236936eb2 in MWWorld::Scene::changeToExteriorCell(ESM::Position const&, bool, bool) /home/elsid/dev/openmw/apps/openmw/mwworld/scene.cpp:888:9 #8 0x55723689a5ac in MWWorld::World::changeToExteriorCell(ESM::Position const&, bool, bool) /home/elsid/dev/openmw/apps/openmw/mwworld/worldimp.cpp:1003:22 #9 0x5572368c249d in MWWorld::World::changeToCell(ESM::CellId const&, ESM::Position const&, bool, bool) /home/elsid/dev/openmw/apps/openmw/mwworld/worldimp.cpp:1014:13 #10 0x557236e9bbce in MWState::StateManager::loadGame(MWState::Character const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) /home/elsid/dev/openmw/apps/openmw/mwstate/statemanagerimp.cpp:545:52 #11 0x557236e998db in MWState::StateManager::loadGame(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) /home/elsid/dev/openmw/apps/openmw/mwstate/statemanagerimp.cpp:377:17 #12 0x557236ed18fb in OMW::Engine::go() /home/elsid/dev/openmw/apps/openmw/engine.cpp:1066:24 #13 0x557236eb621a in runApplication(int, char**) /home/elsid/dev/openmw/apps/openmw/main.cpp:228:17 #14 0x55723774d622 in wrapApplication(int (*)(int, char**), int, char**, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool) /home/elsid/dev/openmw/components/debug/debugging.cpp:328:19 #15 0x557236eb651f in main /home/elsid/dev/openmw/apps/openmw/main.cpp:240:12 #16 0x7fbf58a3f2cf (/usr/lib/libc.so.6+0x232cf) (BuildId: e637217a46491314667a7a37b2155cb07afc1a40)
2022-07-08 18:58:23 +02:00
#include <components/sceneutil/positionattitudetransform.hpp>
2012-05-16 17:22:25 +02:00
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
2012-05-16 17:22:25 +02:00
2015-08-21 21:12:39 +12:00
#include "../mwmechanics/actorutil.hpp"
2013-04-07 21:01:02 +02:00
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/levelledlist.hpp"
#include "../mwmechanics/recharge.hpp"
2013-04-07 21:01:02 +02:00
2012-05-12 16:17:03 +02:00
#include "class.hpp"
#include "esmstore.hpp"
#include "localscripts.hpp"
#include "manualref.hpp"
#include "player.hpp"
#include "refdata.hpp"
namespace
{
void addScripts(MWWorld::ContainerStore& store, MWWorld::CellStore* cell)
{
auto& scripts = MWBase::Environment::get().getWorld()->getLocalScripts();
2020-12-04 18:34:51 +01:00
for (const auto&& ptr : store)
{
2022-08-11 22:51:55 +02:00
std::string_view script = ptr.getClass().getScript(ptr);
if (!script.empty())
{
MWWorld::Ptr item = ptr;
item.mCell = cell;
scripts.add(script, item);
}
}
}
template <typename T>
float getTotalWeight(const MWWorld::CellRefList<T>& cellRefList)
{
float sum = 0;
for (const MWWorld::LiveCellRef<T>& liveCellRef : cellRefList.mList)
{
if (const int count = liveCellRef.mData.getCount(); count > 0)
sum += count * liveCellRef.mBase->mData.mWeight;
}
return sum;
}
2013-08-15 18:29:09 +02:00
template <typename T>
2022-08-27 13:07:59 +02:00
MWWorld::Ptr searchId(MWWorld::CellRefList<T>& list, std::string_view id, MWWorld::ContainerStore* store)
2013-08-15 18:29:09 +02:00
{
store->resolve();
2013-08-15 18:29:09 +02:00
for (MWWorld::LiveCellRef<T>& liveCellRef : list.mList)
2013-08-15 18:29:09 +02:00
{
2022-08-27 13:07:59 +02:00
if (Misc::StringUtils::ciEqual(liveCellRef.mBase->mId, id) && liveCellRef.mData.getCount())
2013-08-15 18:29:09 +02:00
{
MWWorld::Ptr ptr(&liveCellRef, nullptr);
2013-08-15 18:29:09 +02:00
ptr.setContainerStore(store);
return ptr;
}
}
return MWWorld::Ptr();
}
}
MWWorld::ResolutionListener::~ResolutionListener()
{
try
{
mStore.unresolve();
}
catch (const std::exception& e)
{
Log(Debug::Error) << "Failed to clear temporary container contents: " << e.what();
}
}
template <typename T>
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::getState(
CellRefList<T>& collection, const ESM::ObjectState& state)
{
if (!LiveCellRef<T>::checkState(state))
return ContainerStoreIterator(this); // not valid anymore with current content files -> skip
const T* record = MWBase::Environment::get().getWorld()->getStore().get<T>().search(state.mRef.mRefID);
if (!record)
return ContainerStoreIterator(this);
LiveCellRef<T> ref(record);
ref.load(state);
collection.mList.push_back(ref);
return ContainerStoreIterator(this, --collection.mList.end());
}
void MWWorld::ContainerStore::storeEquipmentState(
const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const
{
}
void MWWorld::ContainerStore::readEquipmentState(
const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory)
{
}
template <typename T>
void MWWorld::ContainerStore::storeState(const LiveCellRef<T>& ref, ESM::ObjectState& state) const
{
ref.save(state);
}
template <typename T>
void MWWorld::ContainerStore::storeStates(
const CellRefList<T>& collection, ESM::InventoryState& inventory, int& index, bool equipable) const
{
for (const LiveCellRef<T>& liveCellRef : collection.mList)
{
if (liveCellRef.mData.getCount() == 0)
continue;
ESM::ObjectState state;
storeState(liveCellRef, state);
if (equipable)
storeEquipmentState(liveCellRef, index, inventory);
inventory.mItems.push_back(std::move(state));
++index;
}
}
2022-08-28 15:06:31 +02:00
const std::string_view MWWorld::ContainerStore::sGoldId = "gold_001";
MWWorld::ContainerStore::ContainerStore()
: mListener(nullptr)
, mRechargingItemsUpToDate(false)
, mCachedWeight(0)
, mWeightUpToDate(false)
, mModified(false)
, mResolved(false)
, mSeed()
, mPtr()
{
}
2012-03-21 12:48:05 +01:00
MWWorld::ContainerStore::~ContainerStore() {}
MWWorld::ConstContainerStoreIterator MWWorld::ContainerStore::cbegin(int mask) const
2012-02-20 14:14:39 +01:00
{
return ConstContainerStoreIterator(mask, this);
2012-02-20 14:14:39 +01:00
}
MWWorld::ConstContainerStoreIterator MWWorld::ContainerStore::cend() const
2012-02-20 14:14:39 +01:00
{
return ConstContainerStoreIterator(this);
2012-02-20 14:14:39 +01:00
}
MWWorld::ConstContainerStoreIterator MWWorld::ContainerStore::begin(int mask) const
{
return cbegin(mask);
}
MWWorld::ConstContainerStoreIterator MWWorld::ContainerStore::end() const
{
return cend();
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::begin(int mask)
{
return ContainerStoreIterator(mask, this);
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end()
{
return ContainerStoreIterator(this);
}
int MWWorld::ContainerStore::count(std::string_view id) const
{
int total = 0;
2020-12-04 18:34:51 +01:00
for (const auto&& iter : *this)
if (Misc::StringUtils::ciEqual(iter.getCellRef().getRefId(), id))
total += iter.getRefData().getCount();
return total;
}
MWWorld::ContainerStoreListener* MWWorld::ContainerStore::getContListener() const
{
return mListener;
}
void MWWorld::ContainerStore::setContListener(MWWorld::ContainerStoreListener* listener)
{
mListener = listener;
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::unstack(const Ptr& ptr, const Ptr& container, int count)
{
resolve();
if (ptr.getRefData().getCount() <= count)
return end();
MWWorld::ContainerStoreIterator it = addNewStack(ptr, subtractItems(ptr.getRefData().getCount(false), count));
2022-08-11 22:51:55 +02:00
std::string_view script = it->getClass().getScript(*it);
if (!script.empty())
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, *it);
remove(ptr, ptr.getRefData().getCount() - count, container);
return it;
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::restack(const MWWorld::Ptr& item)
{
resolve();
MWWorld::ContainerStoreIterator retval = end();
for (MWWorld::ContainerStoreIterator iter(begin()); iter != end(); ++iter)
{
if (item == *iter)
{
retval = iter;
break;
}
}
if (retval == end())
throw std::runtime_error("item is not from this container");
for (MWWorld::ContainerStoreIterator iter(begin()); iter != end(); ++iter)
{
if (stacks(*iter, item))
{
iter->getRefData().setCount(
addItems(iter->getRefData().getCount(false), item.getRefData().getCount(false)));
item.getRefData().setCount(0);
retval = iter;
break;
}
}
return retval;
}
bool MWWorld::ContainerStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) const
{
const MWWorld::Class& cls1 = ptr1.getClass();
const MWWorld::Class& cls2 = ptr2.getClass();
if (!Misc::StringUtils::ciEqual(ptr1.getCellRef().getRefId(), ptr2.getCellRef().getRefId()))
return false;
// If it has an enchantment, don't stack when some of the charge is already used
if (!ptr1.getClass().getEnchantment(ptr1).empty())
{
const ESM::Enchantment* enchantment
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
ptr1.getClass().getEnchantment(ptr1));
float maxCharge = static_cast<float>(enchantment->mData.mCharge);
float enchantCharge1
= ptr1.getCellRef().getEnchantmentCharge() == -1 ? maxCharge : ptr1.getCellRef().getEnchantmentCharge();
float enchantCharge2
= ptr2.getCellRef().getEnchantmentCharge() == -1 ? maxCharge : ptr2.getCellRef().getEnchantmentCharge();
if (enchantCharge1 != maxCharge || enchantCharge2 != maxCharge)
return false;
}
2013-11-12 23:12:56 +01:00
return ptr1 != ptr2 // an item never stacks onto itself
&& ptr1.getCellRef().getSoul() == ptr2.getCellRef().getSoul()
2013-12-16 13:31:03 +01:00
&& ptr1.getClass().getRemainingUsageTime(ptr1) == ptr2.getClass().getRemainingUsageTime(ptr2)
// Items with scripts never stack
&& cls1.getScript(ptr1).empty()
&& cls2.getScript(ptr2).empty()
// item that is already partly used up never stacks
&& (!cls1.hasItemHealth(ptr1)
|| (cls1.getItemHealth(ptr1) == cls1.getItemMaxHealth(ptr1)
&& cls2.getItemHealth(ptr2) == cls2.getItemMaxHealth(ptr2)));
}
2022-05-22 09:29:03 +02:00
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(std::string_view id, int count, const Ptr& actorPtr)
{
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count);
return add(ref.getPtr(), count, actorPtr);
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(
const Ptr& itemPtr, int count, const Ptr& actorPtr, bool /*allowAutoEquip*/, bool resolve)
{
Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::ContainerStoreIterator it = addImp(itemPtr, count, resolve);
2014-04-27 05:54:19 +02:00
// The copy of the original item we just made
MWWorld::Ptr item = *it;
// we may have copied an item from the world, so reset a few things first
2018-10-09 10:21:12 +04:00
item.getRefData().setBaseNode(
nullptr); // Especially important, otherwise scripts on the item could think that it's actually in a cell
ESM::Position pos;
pos.rot[0] = 0;
pos.rot[1] = 0;
pos.rot[2] = 0;
pos.pos[0] = 0;
pos.pos[1] = 0;
pos.pos[2] = 0;
item.getCellRef().setPosition(pos);
// We do not need to store owners for items in container stores - we do not use it anyway.
item.getCellRef().setOwner("");
item.getCellRef().resetGlobalVariable();
item.getCellRef().setFaction("");
item.getCellRef().setFactionRank(-2);
// must reset the RefNum on the copied item, so that the RefNum on the original item stays unique
// maybe we should do this in the copy constructor instead?
item.getCellRef().unsetRefNum(); // destroy link to content file
2022-08-11 22:51:55 +02:00
std::string_view script = item.getClass().getScript(item);
if (!script.empty())
{
if (actorPtr == player)
{
// Items in player's inventory have cell set to 0, so their scripts will never be removed
2020-11-13 11:39:47 +04:00
item.mCell = nullptr;
}
else
{
// 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
item.mCell = actorPtr.getCell();
}
item.mContainerStore = this;
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item);
// Set OnPCAdd special variable, if it is declared
// Make sure to do this *after* we have added the script to LocalScripts
if (actorPtr == player)
item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1);
}
// we should not fire event for InventoryStore yet - it has some custom logic
if (mListener && !actorPtr.getClass().hasInventoryStore(actorPtr))
mListener->itemAdded(item, count);
return it;
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp(const Ptr& ptr, int count, bool markModified)
{
if (markModified)
resolve();
2012-05-12 16:30:27 +02:00
int type = getType(ptr);
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
// gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001
// this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for
// detecting player gold)
if (ptr.getClass().isGold(ptr))
2012-05-16 17:22:25 +02:00
{
int realCount = count * ptr.getClass().getValue(ptr);
for (MWWorld::ContainerStoreIterator iter(begin(type)); iter != end(); ++iter)
{
if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId))
{
iter->getRefData().setCount(addItems(iter->getRefData().getCount(false), realCount));
flagAsModified();
return iter;
2012-05-16 17:22:25 +02:00
}
}
MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, realCount);
return addNewStack(ref.getPtr(), realCount);
2012-05-16 17:22:25 +02:00
}
2012-05-12 16:17:03 +02:00
// determine whether to stack or not
2012-05-12 16:30:27 +02:00
for (MWWorld::ContainerStoreIterator iter(begin(type)); iter != end(); ++iter)
2012-05-12 16:17:03 +02:00
{
if (stacks(*iter, ptr))
2012-05-12 16:17:03 +02:00
{
// stack
iter->getRefData().setCount(addItems(iter->getRefData().getCount(false), count));
2012-05-12 16:17:03 +02:00
flagAsModified();
return iter;
2012-05-12 16:17:03 +02:00
}
}
2012-05-13 11:52:17 +02:00
// if we got here, this means no stacking
return addNewStack(ptr, count);
2012-05-13 11:52:17 +02:00
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack(const ConstPtr& ptr, int count)
2012-05-13 11:52:17 +02:00
{
ContainerStoreIterator it = begin();
2012-05-13 11:52:17 +02:00
switch (getType(ptr))
{
2012-11-05 16:07:59 +04:00
case Type_Potion:
potions.mList.push_back(*ptr.get<ESM::Potion>());
it = ContainerStoreIterator(this, --potions.mList.end());
break;
case Type_Apparatus:
appas.mList.push_back(*ptr.get<ESM::Apparatus>());
it = ContainerStoreIterator(this, --appas.mList.end());
break;
case Type_Armor:
armors.mList.push_back(*ptr.get<ESM::Armor>());
it = ContainerStoreIterator(this, --armors.mList.end());
break;
case Type_Book:
books.mList.push_back(*ptr.get<ESM::Book>());
it = ContainerStoreIterator(this, --books.mList.end());
break;
case Type_Clothing:
clothes.mList.push_back(*ptr.get<ESM::Clothing>());
it = ContainerStoreIterator(this, --clothes.mList.end());
break;
case Type_Ingredient:
ingreds.mList.push_back(*ptr.get<ESM::Ingredient>());
it = ContainerStoreIterator(this, --ingreds.mList.end());
break;
case Type_Light:
lights.mList.push_back(*ptr.get<ESM::Light>());
it = ContainerStoreIterator(this, --lights.mList.end());
break;
2013-03-22 05:50:54 +01:00
case Type_Lockpick:
lockpicks.mList.push_back(*ptr.get<ESM::Lockpick>());
it = ContainerStoreIterator(this, --lockpicks.mList.end());
break;
2012-11-05 16:07:59 +04:00
case Type_Miscellaneous:
miscItems.mList.push_back(*ptr.get<ESM::Miscellaneous>());
it = ContainerStoreIterator(this, --miscItems.mList.end());
break;
case Type_Probe:
probes.mList.push_back(*ptr.get<ESM::Probe>());
it = ContainerStoreIterator(this, --probes.mList.end());
break;
case Type_Repair:
repairs.mList.push_back(*ptr.get<ESM::Repair>());
it = ContainerStoreIterator(this, --repairs.mList.end());
break;
case Type_Weapon:
weapons.mList.push_back(*ptr.get<ESM::Weapon>());
it = ContainerStoreIterator(this, --weapons.mList.end());
break;
}
2012-03-21 12:48:05 +01:00
it->getRefData().setCount(count);
2012-03-21 12:48:05 +01:00
flagAsModified();
return it;
}
void MWWorld::ContainerStore::rechargeItems(float duration)
{
if (!mRechargingItemsUpToDate)
{
updateRechargingItems();
mRechargingItemsUpToDate = true;
}
2020-12-04 18:34:51 +01:00
for (auto& it : mRechargingItems)
{
2020-12-04 18:34:51 +01:00
if (!MWMechanics::rechargeItem(*it.first, it.second, duration))
continue;
// attempt to restack when fully recharged
2020-12-04 18:34:51 +01:00
if (it.first->getCellRef().getEnchantmentCharge() == it.second)
it.first = restack(*it.first);
}
}
void MWWorld::ContainerStore::updateRechargingItems()
{
mRechargingItems.clear();
for (ContainerStoreIterator it = begin(); it != end(); ++it)
{
2022-08-22 16:55:53 +02:00
std::string_view enchantmentId = it->getClass().getEnchantment(*it);
if (!enchantmentId.empty())
{
const ESM::Enchantment* enchantment
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchantmentId);
if (!enchantment)
{
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantmentId << "' on item "
<< it->getCellRef().getRefId();
continue;
}
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
mRechargingItems.emplace_back(it, static_cast<float>(enchantment->mData.mCharge));
}
}
}
int MWWorld::ContainerStore::remove(
std::string_view itemId, int count, const Ptr& actor, bool equipReplacement, bool resolveFirst)
{
if (resolveFirst)
resolve();
int toRemove = count;
for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter)
if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId))
2020-10-26 20:13:24 +01:00
toRemove -= remove(*iter, toRemove, actor, equipReplacement, resolveFirst);
2013-11-12 23:17:03 +01:00
flagAsModified();
// number of removed items
return count - toRemove;
}
bool MWWorld::ContainerStore::hasVisibleItems() const
{
2020-12-04 18:34:51 +01:00
for (const auto&& iter : *this)
{
2020-12-04 18:34:51 +01:00
if (iter.getClass().showsInInventory(iter))
return true;
}
return false;
}
2020-10-26 20:13:24 +01:00
int MWWorld::ContainerStore::remove(
const Ptr& item, int count, const Ptr& actor, bool equipReplacement, bool resolveFirst)
{
assert(this == item.getContainerStore());
2020-10-26 20:13:24 +01:00
if (resolveFirst)
resolve();
int toRemove = count;
RefData& itemRef = item.getRefData();
if (itemRef.getCount() <= toRemove)
{
toRemove -= itemRef.getCount();
itemRef.setCount(0);
}
else
{
itemRef.setCount(subtractItems(itemRef.getCount(false), toRemove));
toRemove = 0;
}
2013-11-12 23:17:03 +01:00
flagAsModified();
// we should not fire event for InventoryStore yet - it has some custom logic
if (mListener && !actor.getClass().hasInventoryStore(actor))
mListener->itemRemoved(item, count - toRemove);
// number of removed items
return count - toRemove;
}
void MWWorld::ContainerStore::fill(
const ESM::InventoryList& items, const std::string& owner, Misc::Rng::Generator& prng)
{
for (const ESM::ContItem& iter : items.mList)
{
std::string id = Misc::StringUtils::lowerCase(iter.mItem);
addInitialItem(id, owner, iter.mCount, &prng);
}
flagAsModified();
mResolved = true;
}
void MWWorld::ContainerStore::fillNonRandom(
const ESM::InventoryList& items, const std::string& owner, unsigned int seed)
{
mSeed = seed;
for (const ESM::ContItem& iter : items.mList)
{
std::string id = Misc::StringUtils::lowerCase(iter.mItem);
addInitialItem(id, owner, iter.mCount, nullptr);
2013-04-07 21:01:02 +02:00
}
flagAsModified();
mResolved = false;
2013-04-07 21:01:02 +02:00
}
2022-08-24 20:38:52 +02:00
void MWWorld::ContainerStore::addInitialItem(
std::string_view id, const std::string& owner, int count, Misc::Rng::Generator* prng, bool topLevel)
2013-04-07 21:01:02 +02:00
{
if (count == 0)
return; // Don't restock with nothing.
try
{
ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count);
if (ref.getPtr().getClass().getScript(ref.getPtr()).empty())
{
addInitialItemImp(ref.getPtr(), owner, count, prng, topLevel);
}
else
{
// Adding just one item per time to make sure there isn't a stack of scripted items
for (int i = 0; i < std::abs(count); i++)
addInitialItemImp(ref.getPtr(), owner, count < 0 ? -1 : 1, prng, topLevel);
2013-04-07 21:01:02 +02:00
}
}
catch (const std::exception& e)
2013-04-07 21:01:02 +02:00
{
2018-08-14 23:05:43 +04:00
Log(Debug::Warning) << "Warning: MWWorld::ContainerStore::addInitialItem: " << e.what();
}
}
void MWWorld::ContainerStore::addInitialItemImp(
const MWWorld::Ptr& ptr, const std::string& owner, int count, Misc::Rng::Generator* prng, bool topLevel)
{
if (ptr.getType() == ESM::ItemLevList::sRecordId)
{
if (!prng)
return;
const ESM::ItemLevList* levItemList = ptr.get<ESM::ItemLevList>()->mBase;
if (topLevel && std::abs(count) > 1 && levItemList->mFlags & ESM::ItemLevList::Each)
{
for (int i = 0; i < std::abs(count); ++i)
addInitialItem(ptr.getCellRef().getRefId(), owner, count > 0 ? 1 : -1, prng, true);
return;
}
else
{
2022-08-24 20:38:52 +02:00
std::string_view itemId = MWMechanics::getLevelledItem(ptr.get<ESM::ItemLevList>()->mBase, false, *prng);
if (itemId.empty())
return;
addInitialItem(itemId, owner, count, prng, false);
}
}
else
{
ptr.getCellRef().setOwner(owner);
addImp(ptr, count, false);
}
}
void MWWorld::ContainerStore::clear()
{
2020-12-04 18:34:51 +01:00
for (auto&& iter : *this)
iter.getRefData().setCount(0);
2012-03-21 12:48:05 +01:00
flagAsModified();
mModified = true;
2012-03-21 12:48:05 +01:00
}
void MWWorld::ContainerStore::flagAsModified()
{
mWeightUpToDate = false;
mRechargingItemsUpToDate = false;
2012-03-21 12:48:05 +01:00
}
bool MWWorld::ContainerStore::isResolved() const
{
return mResolved;
}
void MWWorld::ContainerStore::resolve()
{
if (!mResolved && !mPtr.isEmpty())
{
2020-12-04 18:34:51 +01:00
for (const auto&& ptr : *this)
ptr.getRefData().setCount(0);
Misc::Rng::Generator prng{ mSeed };
fill(mPtr.get<ESM::Container>()->mBase->mInventory, "", prng);
addScripts(*this, mPtr.mCell);
}
mModified = true;
}
MWWorld::ResolutionHandle MWWorld::ContainerStore::resolveTemporarily()
{
if (mModified)
return {};
std::shared_ptr<ResolutionListener> listener = mResolutionListener.lock();
if (!listener)
{
listener = std::make_shared<ResolutionListener>(*this);
mResolutionListener = listener;
}
if (!mResolved && !mPtr.isEmpty())
{
2020-12-04 18:34:51 +01:00
for (const auto&& ptr : *this)
ptr.getRefData().setCount(0);
Misc::Rng::Generator prng{ mSeed };
fill(mPtr.get<ESM::Container>()->mBase->mInventory, "", prng);
addScripts(*this, mPtr.mCell);
}
return { listener };
}
void MWWorld::ContainerStore::unresolve()
{
if (mModified)
return;
if (mResolved && !mPtr.isEmpty())
{
for (const auto&& ptr : *this)
ptr.getRefData().setCount(0);
fillNonRandom(mPtr.get<ESM::Container>()->mBase->mInventory, "", mSeed);
addScripts(*this, mPtr.mCell);
mResolved = false;
}
}
float MWWorld::ContainerStore::getWeight() const
{
if (!mWeightUpToDate)
{
mCachedWeight = 0;
mCachedWeight += getTotalWeight(potions);
mCachedWeight += getTotalWeight(appas);
mCachedWeight += getTotalWeight(armors);
mCachedWeight += getTotalWeight(books);
mCachedWeight += getTotalWeight(clothes);
mCachedWeight += getTotalWeight(ingreds);
mCachedWeight += getTotalWeight(lights);
mCachedWeight += getTotalWeight(lockpicks);
mCachedWeight += getTotalWeight(miscItems);
mCachedWeight += getTotalWeight(probes);
mCachedWeight += getTotalWeight(repairs);
mCachedWeight += getTotalWeight(weapons);
mWeightUpToDate = true;
}
return mCachedWeight;
}
int MWWorld::ContainerStore::getType(const ConstPtr& ptr)
{
if (ptr.isEmpty())
throw std::runtime_error("can't put a non-existent object into a container");
if (ptr.getType() == ESM::Potion::sRecordId)
return Type_Potion;
if (ptr.getType() == ESM::Apparatus::sRecordId)
return Type_Apparatus;
if (ptr.getType() == ESM::Armor::sRecordId)
return Type_Armor;
if (ptr.getType() == ESM::Book::sRecordId)
return Type_Book;
if (ptr.getType() == ESM::Clothing::sRecordId)
return Type_Clothing;
if (ptr.getType() == ESM::Ingredient::sRecordId)
return Type_Ingredient;
if (ptr.getType() == ESM::Light::sRecordId)
return Type_Light;
if (ptr.getType() == ESM::Lockpick::sRecordId)
return Type_Lockpick;
if (ptr.getType() == ESM::Miscellaneous::sRecordId)
return Type_Miscellaneous;
if (ptr.getType() == ESM::Probe::sRecordId)
return Type_Probe;
if (ptr.getType() == ESM::Repair::sRecordId)
return Type_Repair;
if (ptr.getType() == ESM::Weapon::sRecordId)
return Type_Weapon;
throw std::runtime_error("Object '" + ptr.getCellRef().getRefId() + "' of type "
+ std::string(ptr.getTypeDescription()) + " can not be placed into a container");
}
2012-02-20 14:14:39 +01:00
MWWorld::Ptr MWWorld::ContainerStore::findReplacement(const std::string& id)
{
MWWorld::Ptr item;
int itemHealth = 1;
2020-12-04 18:34:51 +01:00
for (auto&& iter : *this)
{
2020-12-04 18:34:51 +01:00
int iterHealth = iter.getClass().hasItemHealth(iter) ? iter.getClass().getItemHealth(iter) : 1;
if (Misc::StringUtils::ciEqual(iter.getCellRef().getRefId(), id))
{
// Prefer the stack with the lowest remaining uses
// Try to get item with zero durability only if there are no other items found
if (item.isEmpty() || (iterHealth > 0 && iterHealth < itemHealth) || (itemHealth <= 0 && iterHealth > 0))
{
2020-12-04 18:34:51 +01:00
item = iter;
itemHealth = iterHealth;
}
}
}
return item;
}
2022-08-27 13:07:59 +02:00
MWWorld::Ptr MWWorld::ContainerStore::search(std::string_view id)
{
resolve();
2013-08-15 18:29:09 +02:00
{
Ptr ptr = searchId(potions, id, this);
if (!ptr.isEmpty())
return ptr;
}
2013-08-15 18:29:09 +02:00
{
Ptr ptr = searchId(appas, id, this);
if (!ptr.isEmpty())
return ptr;
}
{
Ptr ptr = searchId(armors, id, this);
if (!ptr.isEmpty())
return ptr;
}
{
2013-08-15 18:29:09 +02:00
Ptr ptr = searchId(books, id, this);
if (!ptr.isEmpty())
return ptr;
}
{
Ptr ptr = searchId(clothes, id, this);
if (!ptr.isEmpty())
return ptr;
}
2013-08-15 18:29:09 +02:00
{
Ptr ptr = searchId(ingreds, id, this);
if (!ptr.isEmpty())
return ptr;
}
{
Ptr ptr = searchId(lights, id, this);
if (!ptr.isEmpty())
return ptr;
}
{
Ptr ptr = searchId(lockpicks, id, this);
if (!ptr.isEmpty())
return ptr;
}
{
Ptr ptr = searchId(miscItems, id, this);
if (!ptr.isEmpty())
return ptr;
}
{
Ptr ptr = searchId(probes, id, this);
if (!ptr.isEmpty())
return ptr;
}
{
Ptr ptr = searchId(repairs, id, this);
if (!ptr.isEmpty())
return ptr;
}
{
Ptr ptr = searchId(weapons, id, this);
if (!ptr.isEmpty())
return ptr;
}
return Ptr();
}
int MWWorld::ContainerStore::addItems(int count1, int count2)
{
int sum = std::abs(count1) + std::abs(count2);
if (count1 < 0 || count2 < 0)
return -sum;
return sum;
}
int MWWorld::ContainerStore::subtractItems(int count1, int count2)
{
int sum = std::abs(count1) - std::abs(count2);
if (count1 < 0 || count2 < 0)
return -sum;
return sum;
}
void MWWorld::ContainerStore::writeState(ESM::InventoryState& state) const
{
state.mItems.clear();
int index = 0;
storeStates(potions, state, index);
storeStates(appas, state, index);
storeStates(armors, state, index, true);
storeStates(books, state, index, true); // not equipable as such, but for selectedEnchantItem
storeStates(clothes, state, index, true);
storeStates(ingreds, state, index);
storeStates(lockpicks, state, index, true);
storeStates(miscItems, state, index);
storeStates(probes, state, index, true);
storeStates(repairs, state, index);
storeStates(weapons, state, index, true);
storeStates(lights, state, index, true);
}
2022-09-22 21:26:05 +03:00
void MWWorld::ContainerStore::readState(const ESM::InventoryState& inventory)
{
clear();
mModified = true;
mResolved = true;
int index = 0;
2020-12-04 18:34:51 +01:00
for (const ESM::ObjectState& state : inventory.mItems)
{
int type = MWBase::Environment::get().getWorld()->getStore().find(state.mRef.mRefID);
int thisIndex = index++;
switch (type)
{
case ESM::REC_ALCH:
getState(potions, state);
break;
case ESM::REC_APPA:
getState(appas, state);
break;
case ESM::REC_ARMO:
readEquipmentState(getState(armors, state), thisIndex, inventory);
break;
case ESM::REC_BOOK:
readEquipmentState(getState(books, state), thisIndex, inventory);
break; // not equipable as such, but for selectedEnchantItem
case ESM::REC_CLOT:
readEquipmentState(getState(clothes, state), thisIndex, inventory);
break;
case ESM::REC_INGR:
getState(ingreds, state);
break;
case ESM::REC_LOCK:
readEquipmentState(getState(lockpicks, state), thisIndex, inventory);
break;
case ESM::REC_MISC:
getState(miscItems, state);
break;
case ESM::REC_PROB:
readEquipmentState(getState(probes, state), thisIndex, inventory);
break;
case ESM::REC_REPA:
getState(repairs, state);
break;
case ESM::REC_WEAP:
readEquipmentState(getState(weapons, state), thisIndex, inventory);
break;
case ESM::REC_LIGH:
readEquipmentState(getState(lights, state), thisIndex, inventory);
break;
case 0:
2018-08-14 23:05:43 +04:00
Log(Debug::Warning) << "Dropping inventory reference to '" << state.mRef.mRefID
<< "' (object no longer exists)";
break;
default:
2018-08-14 23:05:43 +04:00
Log(Debug::Warning) << "Warning: Invalid item type in inventory state, refid " << state.mRef.mRefID;
break;
}
}
}
template <class PtrType>
template <class T>
void MWWorld::ContainerStoreIteratorBase<PtrType>::copy(const ContainerStoreIteratorBase<T>& src)
2012-02-20 14:14:39 +01:00
{
mType = src.mType;
mMask = src.mMask;
mContainer = src.mContainer;
mPtr = src.mPtr;
switch (src.mType)
{
case MWWorld::ContainerStore::Type_Potion:
mPotion = src.mPotion;
break;
case MWWorld::ContainerStore::Type_Apparatus:
mApparatus = src.mApparatus;
break;
case MWWorld::ContainerStore::Type_Armor:
mArmor = src.mArmor;
break;
case MWWorld::ContainerStore::Type_Book:
mBook = src.mBook;
break;
case MWWorld::ContainerStore::Type_Clothing:
mClothing = src.mClothing;
break;
case MWWorld::ContainerStore::Type_Ingredient:
mIngredient = src.mIngredient;
break;
case MWWorld::ContainerStore::Type_Light:
mLight = src.mLight;
break;
case MWWorld::ContainerStore::Type_Lockpick:
mLockpick = src.mLockpick;
break;
case MWWorld::ContainerStore::Type_Miscellaneous:
mMiscellaneous = src.mMiscellaneous;
break;
case MWWorld::ContainerStore::Type_Probe:
mProbe = src.mProbe;
break;
case MWWorld::ContainerStore::Type_Repair:
mRepair = src.mRepair;
break;
case MWWorld::ContainerStore::Type_Weapon:
mWeapon = src.mWeapon;
break;
case -1:
2022-09-22 21:26:05 +03:00
break;
default:
assert(0);
}
}
template <class PtrType>
void MWWorld::ContainerStoreIteratorBase<PtrType>::incType()
2012-02-20 14:14:39 +01:00
{
if (mType == 0)
mType = 1;
else if (mType != -1)
{
mType <<= 1;
if (mType > ContainerStore::Type_Last)
mType = -1;
}
}
template <class PtrType>
void MWWorld::ContainerStoreIteratorBase<PtrType>::nextType()
2012-02-20 14:14:39 +01:00
{
while (mType != -1)
{
incType();
2012-05-18 22:24:19 +02:00
if ((mType & mMask) && mType > 0)
2012-02-20 14:14:39 +01:00
if (resetIterator())
break;
}
}
template <class PtrType>
bool MWWorld::ContainerStoreIteratorBase<PtrType>::resetIterator()
2012-02-20 14:14:39 +01:00
{
switch (mType)
{
case ContainerStore::Type_Potion:
2012-11-05 16:07:59 +04:00
mPotion = mContainer->potions.mList.begin();
return mPotion != mContainer->potions.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Apparatus:
2012-11-05 16:07:59 +04:00
mApparatus = mContainer->appas.mList.begin();
return mApparatus != mContainer->appas.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Armor:
2012-11-05 16:07:59 +04:00
mArmor = mContainer->armors.mList.begin();
return mArmor != mContainer->armors.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Book:
2012-11-05 16:07:59 +04:00
mBook = mContainer->books.mList.begin();
return mBook != mContainer->books.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Clothing:
2012-11-05 16:07:59 +04:00
mClothing = mContainer->clothes.mList.begin();
return mClothing != mContainer->clothes.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Ingredient:
2012-11-05 16:07:59 +04:00
mIngredient = mContainer->ingreds.mList.begin();
return mIngredient != mContainer->ingreds.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Light:
2012-11-05 16:07:59 +04:00
mLight = mContainer->lights.mList.begin();
return mLight != mContainer->lights.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Lockpick:
2012-11-05 16:07:59 +04:00
mLockpick = mContainer->lockpicks.mList.begin();
return mLockpick != mContainer->lockpicks.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Miscellaneous:
2012-11-05 16:07:59 +04:00
mMiscellaneous = mContainer->miscItems.mList.begin();
return mMiscellaneous != mContainer->miscItems.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Probe:
2012-11-05 16:07:59 +04:00
mProbe = mContainer->probes.mList.begin();
return mProbe != mContainer->probes.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Repair:
2012-11-05 16:07:59 +04:00
mRepair = mContainer->repairs.mList.begin();
return mRepair != mContainer->repairs.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Weapon:
2012-11-05 16:07:59 +04:00
mWeapon = mContainer->weapons.mList.begin();
return mWeapon != mContainer->weapons.mList.end();
2012-02-20 14:14:39 +01:00
}
return false;
}
template <class PtrType>
bool MWWorld::ContainerStoreIteratorBase<PtrType>::incIterator()
2012-02-20 14:14:39 +01:00
{
switch (mType)
{
case ContainerStore::Type_Potion:
++mPotion;
2012-11-05 16:07:59 +04:00
return mPotion == mContainer->potions.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Apparatus:
++mApparatus;
2012-11-05 16:07:59 +04:00
return mApparatus == mContainer->appas.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Armor:
++mArmor;
2012-11-05 16:07:59 +04:00
return mArmor == mContainer->armors.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Book:
++mBook;
2012-11-05 16:07:59 +04:00
return mBook == mContainer->books.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Clothing:
++mClothing;
2012-11-05 16:07:59 +04:00
return mClothing == mContainer->clothes.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Ingredient:
++mIngredient;
2012-11-05 16:07:59 +04:00
return mIngredient == mContainer->ingreds.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Light:
++mLight;
2012-11-05 16:07:59 +04:00
return mLight == mContainer->lights.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Lockpick:
++mLockpick;
2012-11-05 16:07:59 +04:00
return mLockpick == mContainer->lockpicks.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Miscellaneous:
++mMiscellaneous;
2012-11-05 16:07:59 +04:00
return mMiscellaneous == mContainer->miscItems.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Probe:
++mProbe;
2012-11-05 16:07:59 +04:00
return mProbe == mContainer->probes.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Repair:
++mRepair;
2012-11-05 16:07:59 +04:00
return mRepair == mContainer->repairs.mList.end();
2012-02-20 14:14:39 +01:00
case ContainerStore::Type_Weapon:
++mWeapon;
2012-11-05 16:07:59 +04:00
return mWeapon == mContainer->weapons.mList.end();
2012-02-20 14:14:39 +01:00
}
return true;
}
template <class PtrType>
template <class T>
bool MWWorld::ContainerStoreIteratorBase<PtrType>::isEqual(const ContainerStoreIteratorBase<T>& other) const
{
if (mContainer != other.mContainer)
return false;
if (mType != other.mType)
return false;
switch (mType)
{
case ContainerStore::Type_Potion:
return mPotion == other.mPotion;
case ContainerStore::Type_Apparatus:
return mApparatus == other.mApparatus;
case ContainerStore::Type_Armor:
return mArmor == other.mArmor;
case ContainerStore::Type_Book:
return mBook == other.mBook;
case ContainerStore::Type_Clothing:
return mClothing == other.mClothing;
case ContainerStore::Type_Ingredient:
return mIngredient == other.mIngredient;
case ContainerStore::Type_Light:
return mLight == other.mLight;
case ContainerStore::Type_Lockpick:
return mLockpick == other.mLockpick;
case ContainerStore::Type_Miscellaneous:
return mMiscellaneous == other.mMiscellaneous;
case ContainerStore::Type_Probe:
return mProbe == other.mProbe;
case ContainerStore::Type_Repair:
return mRepair == other.mRepair;
case ContainerStore::Type_Weapon:
return mWeapon == other.mWeapon;
case -1:
return true;
}
return false;
}
template <class PtrType>
PtrType* MWWorld::ContainerStoreIteratorBase<PtrType>::operator->() const
2012-02-20 14:14:39 +01:00
{
mPtr = **this;
return &mPtr;
}
template <class PtrType>
PtrType MWWorld::ContainerStoreIteratorBase<PtrType>::operator*() const
2012-02-20 14:14:39 +01:00
{
PtrType ptr;
2012-02-20 14:14:39 +01:00
switch (mType)
{
2020-11-13 11:39:47 +04:00
case ContainerStore::Type_Potion:
ptr = PtrType(&*mPotion, nullptr);
break;
case ContainerStore::Type_Apparatus:
ptr = PtrType(&*mApparatus, nullptr);
break;
case ContainerStore::Type_Armor:
ptr = PtrType(&*mArmor, nullptr);
break;
case ContainerStore::Type_Book:
ptr = PtrType(&*mBook, nullptr);
break;
case ContainerStore::Type_Clothing:
ptr = PtrType(&*mClothing, nullptr);
break;
case ContainerStore::Type_Ingredient:
ptr = PtrType(&*mIngredient, nullptr);
break;
case ContainerStore::Type_Light:
ptr = PtrType(&*mLight, nullptr);
break;
case ContainerStore::Type_Lockpick:
ptr = PtrType(&*mLockpick, nullptr);
break;
case ContainerStore::Type_Miscellaneous:
ptr = PtrType(&*mMiscellaneous, nullptr);
break;
case ContainerStore::Type_Probe:
ptr = PtrType(&*mProbe, nullptr);
break;
case ContainerStore::Type_Repair:
ptr = PtrType(&*mRepair, nullptr);
break;
case ContainerStore::Type_Weapon:
ptr = PtrType(&*mWeapon, nullptr);
break;
2012-02-20 14:14:39 +01:00
}
if (ptr.isEmpty())
throw std::runtime_error("invalid iterator");
ptr.setContainerStore(mContainer);
return ptr;
2012-02-20 14:14:39 +01:00
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>& MWWorld::ContainerStoreIteratorBase<PtrType>::operator++()
2012-02-20 14:14:39 +01:00
{
do
{
if (incIterator())
nextType();
} while (mType != -1 && !(**this).getRefData().getCount());
return *this;
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType> MWWorld::ContainerStoreIteratorBase<PtrType>::operator++(int)
2012-02-20 14:14:39 +01:00
{
ContainerStoreIteratorBase<PtrType> iter(*this);
2012-02-20 14:14:39 +01:00
++*this;
return iter;
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>& MWWorld::ContainerStoreIteratorBase<PtrType>::operator=(
const ContainerStoreIteratorBase<PtrType>& rhs)
2012-02-20 14:14:39 +01:00
{
if (this != &rhs)
2012-02-20 14:14:39 +01:00
{
copy(rhs);
2012-02-20 14:14:39 +01:00
}
return *this;
2012-02-20 14:14:39 +01:00
}
template <class PtrType>
int MWWorld::ContainerStoreIteratorBase<PtrType>::getType() const
2012-02-20 14:14:39 +01:00
{
return mType;
}
template <class PtrType>
const MWWorld::ContainerStore* MWWorld::ContainerStoreIteratorBase<PtrType>::getContainerStore() const
2012-03-13 14:04:19 +01:00
{
return mContainer;
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(ContainerStoreType container)
: mType(-1)
, mMask(0)
, mContainer(container)
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(int mask, ContainerStoreType container)
: mType(0)
, mMask(mask)
, mContainer(container)
{
nextType();
2014-01-07 14:32:14 +02:00
if (mType == -1 || (**this).getRefData().getCount())
return;
++*this;
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Potion>::type iterator)
: mType(MWWorld::ContainerStore::Type_Potion)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mPotion(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Apparatus>::type iterator)
: mType(MWWorld::ContainerStore::Type_Apparatus)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mApparatus(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Armor>::type iterator)
: mType(MWWorld::ContainerStore::Type_Armor)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mArmor(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Book>::type iterator)
: mType(MWWorld::ContainerStore::Type_Book)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mBook(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Clothing>::type iterator)
: mType(MWWorld::ContainerStore::Type_Clothing)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mClothing(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Ingredient>::type iterator)
: mType(MWWorld::ContainerStore::Type_Ingredient)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mIngredient(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Light>::type iterator)
: mType(MWWorld::ContainerStore::Type_Light)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mLight(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Lockpick>::type iterator)
: mType(MWWorld::ContainerStore::Type_Lockpick)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mLockpick(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Miscellaneous>::type iterator)
: mType(MWWorld::ContainerStore::Type_Miscellaneous)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mMiscellaneous(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Probe>::type iterator)
: mType(MWWorld::ContainerStore::Type_Probe)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mProbe(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Repair>::type iterator)
: mType(MWWorld::ContainerStore::Type_Repair)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mRepair(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class PtrType>
MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(
ContainerStoreType container, typename Iterator<ESM::Weapon>::type iterator)
: mType(MWWorld::ContainerStore::Type_Weapon)
, mMask(MWWorld::ContainerStore::Type_All)
, mContainer(container)
, mWeapon(iterator)
2022-09-22 21:26:05 +03:00
{
}
template <class T, class U>
bool MWWorld::operator==(const ContainerStoreIteratorBase<T>& left, const ContainerStoreIteratorBase<U>& right)
2012-02-20 14:14:39 +01:00
{
return left.isEqual(right);
}
template <class T, class U>
bool MWWorld::operator!=(const ContainerStoreIteratorBase<T>& left, const ContainerStoreIteratorBase<U>& right)
2012-02-20 14:14:39 +01:00
{
return !(left == right);
}
template class MWWorld::ContainerStoreIteratorBase<MWWorld::Ptr>;
template class MWWorld::ContainerStoreIteratorBase<MWWorld::ConstPtr>;
template bool MWWorld::operator==(
const ContainerStoreIteratorBase<Ptr>& left, const ContainerStoreIteratorBase<Ptr>& right);
template bool MWWorld::operator!=(
const ContainerStoreIteratorBase<Ptr>& left, const ContainerStoreIteratorBase<Ptr>& right);
template bool MWWorld::operator==(
const ContainerStoreIteratorBase<ConstPtr>& left, const ContainerStoreIteratorBase<ConstPtr>& right);
template bool MWWorld::operator!=(
const ContainerStoreIteratorBase<ConstPtr>& left, const ContainerStoreIteratorBase<ConstPtr>& right);
template bool MWWorld::operator==(
const ContainerStoreIteratorBase<ConstPtr>& left, const ContainerStoreIteratorBase<Ptr>& right);
template bool MWWorld::operator!=(
const ContainerStoreIteratorBase<ConstPtr>& left, const ContainerStoreIteratorBase<Ptr>& right);
template bool MWWorld::operator==(
const ContainerStoreIteratorBase<Ptr>& left, const ContainerStoreIteratorBase<ConstPtr>& right);
template bool MWWorld::operator!=(
const ContainerStoreIteratorBase<Ptr>& left, const ContainerStoreIteratorBase<ConstPtr>& right);
template void MWWorld::ContainerStoreIteratorBase<MWWorld::Ptr>::copy(const ContainerStoreIteratorBase<Ptr>& src);
template void MWWorld::ContainerStoreIteratorBase<MWWorld::ConstPtr>::copy(const ContainerStoreIteratorBase<Ptr>& src);
template void MWWorld::ContainerStoreIteratorBase<MWWorld::ConstPtr>::copy(
const ContainerStoreIteratorBase<ConstPtr>& src);