2012-03-10 12:43:48 +01:00
|
|
|
#include "inventorystore.hpp"
|
2012-03-13 13:31:11 +01:00
|
|
|
|
2012-03-13 14:04:19 +01:00
|
|
|
#include <algorithm>
|
2012-03-13 13:31:11 +01:00
|
|
|
#include <iterator>
|
2012-03-13 14:04:19 +01:00
|
|
|
|
2022-01-22 15:58:41 +01:00
|
|
|
#include <components/esm3/inventorystate.hpp>
|
2012-05-18 15:48:55 +02:00
|
|
|
|
|
|
|
#include "../mwbase/environment.hpp"
|
2012-07-03 12:30:50 +02:00
|
|
|
#include "../mwbase/world.hpp"
|
2012-05-18 15:48:55 +02:00
|
|
|
|
2015-08-21 21:12:39 +12:00
|
|
|
#include "../mwmechanics/actorutil.hpp"
|
2012-04-08 12:26:21 +02:00
|
|
|
#include "../mwmechanics/npcstats.hpp"
|
2018-12-26 13:45:28 +04:00
|
|
|
#include "../mwmechanics/weapontype.hpp"
|
2012-04-08 12:26:21 +02:00
|
|
|
|
2012-03-13 14:04:19 +01:00
|
|
|
#include "class.hpp"
|
2012-10-01 19:17:04 +04:00
|
|
|
#include "esmstore.hpp"
|
2012-03-13 13:31:11 +01:00
|
|
|
|
|
|
|
void MWWorld::InventoryStore::copySlots(const InventoryStore& store)
|
|
|
|
{
|
|
|
|
// some const-trickery, required because of a flaw in the handling of MW-references and the
|
|
|
|
// resulting workarounds
|
|
|
|
for (std::vector<ContainerStoreIterator>::const_iterator iter(const_cast<InventoryStore&>(store).mSlots.begin());
|
|
|
|
iter != const_cast<InventoryStore&>(store).mSlots.end(); ++iter)
|
|
|
|
{
|
|
|
|
std::size_t distance = std::distance(const_cast<InventoryStore&>(store).begin(), *iter);
|
|
|
|
|
|
|
|
ContainerStoreIterator slot = begin();
|
|
|
|
|
|
|
|
std::advance(slot, distance);
|
|
|
|
|
|
|
|
mSlots.push_back(slot);
|
|
|
|
}
|
2014-01-26 20:15:22 +01:00
|
|
|
|
|
|
|
// some const-trickery, required because of a flaw in the handling of MW-references and the
|
|
|
|
// resulting workarounds
|
|
|
|
std::size_t distance = std::distance(
|
|
|
|
const_cast<InventoryStore&>(store).begin(), const_cast<InventoryStore&>(store).mSelectedEnchantItem);
|
|
|
|
ContainerStoreIterator slot = begin();
|
|
|
|
std::advance(slot, distance);
|
|
|
|
mSelectedEnchantItem = slot;
|
2012-03-13 13:31:11 +01:00
|
|
|
}
|
|
|
|
|
2013-11-12 23:23:19 +01:00
|
|
|
void MWWorld::InventoryStore::initSlots(TSlots& slots_)
|
2012-03-13 13:31:11 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < Slots; ++i)
|
2013-11-12 23:23:19 +01:00
|
|
|
slots_.push_back(end());
|
2012-03-31 17:26:15 +02:00
|
|
|
}
|
|
|
|
|
2015-01-23 16:45:47 +01:00
|
|
|
void MWWorld::InventoryStore::storeEquipmentState(
|
|
|
|
const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const
|
2014-02-01 17:07:08 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < static_cast<int>(mSlots.size()); ++i)
|
2015-01-23 02:32:43 +01:00
|
|
|
if (mSlots[i].getType() != -1 && mSlots[i]->getBase() == &ref)
|
2015-01-23 16:45:47 +01:00
|
|
|
{
|
|
|
|
inventory.mEquipmentSlots[index] = i;
|
|
|
|
}
|
2014-02-01 17:07:08 +01:00
|
|
|
|
2015-01-23 16:45:47 +01:00
|
|
|
if (mSelectedEnchantItem.getType() != -1 && mSelectedEnchantItem->getBase() == &ref)
|
|
|
|
inventory.mSelectedEnchantItem = index;
|
2014-02-01 17:07:08 +01:00
|
|
|
}
|
|
|
|
|
2015-01-23 16:45:47 +01:00
|
|
|
void MWWorld::InventoryStore::readEquipmentState(
|
|
|
|
const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory)
|
2014-02-01 17:07:08 +01:00
|
|
|
{
|
2015-01-23 16:45:47 +01:00
|
|
|
if (index == inventory.mSelectedEnchantItem)
|
|
|
|
mSelectedEnchantItem = iter;
|
2015-01-23 15:31:44 +01:00
|
|
|
|
2015-01-23 16:45:47 +01:00
|
|
|
std::map<int, int>::const_iterator found = inventory.mEquipmentSlots.find(index);
|
|
|
|
if (found != inventory.mEquipmentSlots.end())
|
2015-01-23 15:31:44 +01:00
|
|
|
{
|
2015-01-23 16:45:47 +01:00
|
|
|
if (found->second < 0 || found->second >= MWWorld::InventoryStore::Slots)
|
|
|
|
throw std::runtime_error("Invalid slot index in inventory state");
|
|
|
|
|
|
|
|
// make sure the item can actually be equipped in this slot
|
|
|
|
int slot = found->second;
|
|
|
|
std::pair<std::vector<int>, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter);
|
|
|
|
if (!allowedSlots.first.size())
|
|
|
|
return;
|
|
|
|
if (std::find(allowedSlots.first.begin(), allowedSlots.first.end(), slot) == allowedSlots.first.end())
|
|
|
|
slot = allowedSlots.first.front();
|
|
|
|
|
|
|
|
// unstack if required
|
|
|
|
if (!allowedSlots.second && iter->getRefData().getCount() > 1)
|
|
|
|
{
|
2020-10-13 17:46:32 +02:00
|
|
|
int count = iter->getRefData().getCount(false);
|
|
|
|
MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, count > 0 ? 1 : -1);
|
|
|
|
iter->getRefData().setCount(subtractItems(count, 1));
|
2015-01-23 16:45:47 +01:00
|
|
|
mSlots[slot] = newIter;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
mSlots[slot] = iter;
|
2015-01-23 15:31:44 +01:00
|
|
|
}
|
2014-02-01 17:07:08 +01:00
|
|
|
}
|
|
|
|
|
2013-11-13 18:51:28 +01:00
|
|
|
MWWorld::InventoryStore::InventoryStore()
|
2018-03-03 14:16:21 +04:00
|
|
|
: ContainerStore()
|
|
|
|
, mInventoryListener(nullptr)
|
2013-11-13 18:51:28 +01:00
|
|
|
, mUpdatesEnabled(true)
|
2013-11-14 14:41:10 +01:00
|
|
|
, mFirstAutoEquip(true)
|
2015-04-30 19:24:27 -05:00
|
|
|
, mSelectedEnchantItem(end())
|
2012-03-31 17:26:15 +02:00
|
|
|
{
|
|
|
|
initSlots(mSlots);
|
2012-03-13 13:31:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
MWWorld::InventoryStore::InventoryStore(const InventoryStore& store)
|
2014-09-26 17:12:48 +02:00
|
|
|
: ContainerStore(store)
|
2018-03-03 14:16:21 +04:00
|
|
|
, mInventoryListener(store.mInventoryListener)
|
2014-09-26 17:12:48 +02:00
|
|
|
, mUpdatesEnabled(store.mUpdatesEnabled)
|
2015-04-30 19:24:27 -05:00
|
|
|
, mFirstAutoEquip(store.mFirstAutoEquip)
|
|
|
|
, mSelectedEnchantItem(end())
|
2012-03-13 13:31:11 +01:00
|
|
|
{
|
|
|
|
copySlots(store);
|
|
|
|
}
|
|
|
|
|
|
|
|
MWWorld::InventoryStore& MWWorld::InventoryStore::operator=(const InventoryStore& store)
|
|
|
|
{
|
2021-01-09 18:28:26 +04:00
|
|
|
if (this == &store)
|
|
|
|
return *this;
|
|
|
|
|
2014-01-26 20:15:22 +01:00
|
|
|
mListener = store.mListener;
|
2018-03-03 14:16:21 +04:00
|
|
|
mInventoryListener = store.mInventoryListener;
|
2013-11-14 14:41:10 +01:00
|
|
|
mFirstAutoEquip = store.mFirstAutoEquip;
|
2014-10-05 18:27:26 +02:00
|
|
|
mRechargingItemsUpToDate = false;
|
2012-03-13 13:31:11 +01:00
|
|
|
ContainerStore::operator=(store);
|
|
|
|
mSlots.clear();
|
|
|
|
copySlots(store);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-10-20 09:22:43 +00:00
|
|
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(
|
2023-01-16 23:51:04 +01:00
|
|
|
const Ptr& itemPtr, int count, bool allowAutoEquip, bool resolve)
|
2013-08-07 14:45:23 +02:00
|
|
|
{
|
2020-10-20 09:22:43 +00:00
|
|
|
const MWWorld::ContainerStoreIterator& retVal
|
2023-01-16 23:51:04 +01:00
|
|
|
= MWWorld::ContainerStore::add(itemPtr, count, allowAutoEquip, resolve);
|
2013-08-07 14:45:23 +02:00
|
|
|
|
2019-10-12 14:00:36 +04:00
|
|
|
// Auto-equip items if an armor/clothing item is added, but not for the player nor werewolves
|
2023-01-16 23:51:04 +01:00
|
|
|
if (allowAutoEquip && mActor != MWMechanics::getPlayer() && mActor.getClass().isNpc()
|
|
|
|
&& !mActor.getClass().getNpcStats(mActor).isWerewolf())
|
2013-08-07 14:45:23 +02:00
|
|
|
{
|
2021-10-11 11:46:21 +00:00
|
|
|
auto type = itemPtr.getType();
|
|
|
|
if (type == ESM::Armor::sRecordId || type == ESM::Clothing::sRecordId)
|
2023-01-16 23:51:04 +01:00
|
|
|
autoEquip();
|
2013-08-07 14:45:23 +02:00
|
|
|
}
|
|
|
|
|
2018-03-03 14:16:21 +04:00
|
|
|
if (mListener)
|
2018-12-04 16:47:47 +03:00
|
|
|
mListener->itemAdded(*retVal, count);
|
2018-03-03 14:16:21 +04:00
|
|
|
|
2013-08-07 14:45:23 +02:00
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
void MWWorld::InventoryStore::equip(int slot, const ContainerStoreIterator& iterator)
|
2012-03-13 13:31:11 +01:00
|
|
|
{
|
2013-11-17 13:38:54 +01:00
|
|
|
if (iterator == end())
|
|
|
|
throw std::runtime_error("can't equip end() iterator, use unequip function instead");
|
|
|
|
|
2012-03-13 13:31:11 +01:00
|
|
|
if (slot < 0 || slot >= static_cast<int>(mSlots.size()))
|
|
|
|
throw std::runtime_error("slot number out of range");
|
|
|
|
|
2012-03-13 14:04:19 +01:00
|
|
|
if (iterator.getContainerStore() != this)
|
|
|
|
throw std::runtime_error("attempt to equip an item that is not in the inventory");
|
|
|
|
|
2013-11-12 23:23:19 +01:00
|
|
|
std::pair<std::vector<int>, bool> slots_;
|
2012-03-13 14:04:19 +01:00
|
|
|
|
2014-05-22 20:37:22 +02:00
|
|
|
slots_ = iterator->getClass().getEquipmentSlots(*iterator);
|
2013-11-17 13:38:54 +01:00
|
|
|
|
|
|
|
if (std::find(slots_.first.begin(), slots_.first.end(), slot) == slots_.first.end())
|
|
|
|
throw std::runtime_error("invalid slot");
|
2012-03-13 14:04:19 +01:00
|
|
|
|
2012-05-12 23:09:03 +02:00
|
|
|
if (mSlots[slot] != end())
|
2023-01-16 23:51:04 +01:00
|
|
|
unequipSlot(slot);
|
2012-03-13 14:04:19 +01:00
|
|
|
|
2012-05-12 23:09:03 +02:00
|
|
|
// unstack item pointed to by iterator if required
|
2013-11-12 23:23:19 +01:00
|
|
|
if (iterator != end() && !slots_.second
|
|
|
|
&& iterator->getRefData().getCount() > 1) // if slots.second is true, item can stay stacked when equipped
|
2012-05-12 23:09:03 +02:00
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
unstack(*iterator);
|
2012-05-12 23:09:03 +02:00
|
|
|
}
|
2012-04-23 15:27:03 +02:00
|
|
|
|
2012-03-13 13:31:11 +01:00
|
|
|
mSlots[slot] = iterator;
|
2012-03-21 12:48:05 +01:00
|
|
|
|
|
|
|
flagAsModified();
|
2013-10-25 22:16:52 +02:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
fireEquipmentChangedEvent();
|
2012-03-13 13:31:11 +01:00
|
|
|
}
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
void MWWorld::InventoryStore::unequipAll()
|
2013-08-06 11:20:51 +02:00
|
|
|
{
|
2014-01-04 20:43:57 +01:00
|
|
|
mUpdatesEnabled = false;
|
2013-08-06 11:20:51 +02:00
|
|
|
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
2023-01-16 23:51:04 +01:00
|
|
|
unequipSlot(slot);
|
2014-10-04 22:27:23 +02:00
|
|
|
|
2014-01-04 20:43:57 +01:00
|
|
|
mUpdatesEnabled = true;
|
2014-10-11 21:05:12 +02:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
fireEquipmentChangedEvent();
|
2013-08-06 11:20:51 +02:00
|
|
|
}
|
|
|
|
|
2012-03-13 13:31:11 +01:00
|
|
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot(int slot)
|
|
|
|
{
|
2017-02-28 14:43:20 +00:00
|
|
|
return findSlot(slot);
|
2012-03-13 13:31:11 +01:00
|
|
|
}
|
|
|
|
|
2017-02-26 21:24:51 +00:00
|
|
|
MWWorld::ConstContainerStoreIterator MWWorld::InventoryStore::getSlot(int slot) const
|
|
|
|
{
|
2017-02-28 14:43:20 +00:00
|
|
|
return findSlot(slot);
|
2012-03-13 13:31:11 +01:00
|
|
|
}
|
2012-03-31 17:26:15 +02:00
|
|
|
|
2017-02-28 14:43:20 +00:00
|
|
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::findSlot(int slot) const
|
|
|
|
{
|
|
|
|
if (slot < 0 || slot >= static_cast<int>(mSlots.size()))
|
|
|
|
throw std::runtime_error("slot number out of range");
|
|
|
|
|
|
|
|
if (mSlots[slot] == end())
|
|
|
|
return mSlots[slot];
|
|
|
|
|
|
|
|
if (mSlots[slot]->getRefData().getCount() < 1)
|
|
|
|
{
|
|
|
|
// Object has been deleted
|
|
|
|
// This should no longer happen, since the new remove function will unequip first
|
|
|
|
throw std::runtime_error(
|
|
|
|
"Invalid slot, make sure you are not calling RefData::setCount for a container object");
|
|
|
|
}
|
|
|
|
|
|
|
|
return mSlots[slot];
|
|
|
|
}
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_)
|
2018-03-03 14:16:21 +04:00
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
if (!mActor.getClass().isNpc())
|
2018-03-03 14:16:21 +04:00
|
|
|
{
|
|
|
|
// 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.
|
|
|
|
// So just disable weapon autoequipping for creatures which sells weapon.
|
2023-01-16 23:51:04 +01:00
|
|
|
int services = mActor.getClass().getServices(mActor);
|
2018-03-03 14:16:21 +04:00
|
|
|
bool sellsWeapon = services & (ESM::NPC::Weapon | ESM::NPC::MagicItems);
|
|
|
|
if (sellsWeapon)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const ESM::Skill::SkillEnum weaponSkills[] = {
|
|
|
|
ESM::Skill::LongBlade,
|
|
|
|
ESM::Skill::Axe,
|
|
|
|
ESM::Skill::Spear,
|
|
|
|
ESM::Skill::ShortBlade,
|
|
|
|
ESM::Skill::Marksman,
|
2022-09-14 00:08:19 +02:00
|
|
|
ESM::Skill::BluntWeapon,
|
2018-03-03 14:16:21 +04:00
|
|
|
};
|
|
|
|
const size_t weaponSkillsLength = sizeof(weaponSkills) / sizeof(weaponSkills[0]);
|
|
|
|
|
|
|
|
bool weaponSkillVisited[weaponSkillsLength] = { false };
|
|
|
|
|
|
|
|
// give arrows/bolt with max damage by default
|
|
|
|
int arrowMax = 0;
|
|
|
|
int boltMax = 0;
|
|
|
|
ContainerStoreIterator arrow(end());
|
|
|
|
ContainerStoreIterator bolt(end());
|
|
|
|
|
|
|
|
// rate ammo
|
|
|
|
for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter != end(); ++iter)
|
|
|
|
{
|
|
|
|
const ESM::Weapon* esmWeapon = iter->get<ESM::Weapon>()->mBase;
|
|
|
|
|
|
|
|
if (esmWeapon->mData.mType == ESM::Weapon::Arrow)
|
|
|
|
{
|
|
|
|
if (esmWeapon->mData.mChop[1] >= arrowMax)
|
|
|
|
{
|
|
|
|
arrowMax = esmWeapon->mData.mChop[1];
|
|
|
|
arrow = iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (esmWeapon->mData.mType == ESM::Weapon::Bolt)
|
|
|
|
{
|
|
|
|
if (esmWeapon->mData.mChop[1] >= boltMax)
|
|
|
|
{
|
|
|
|
boltMax = esmWeapon->mData.mChop[1];
|
|
|
|
bolt = iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// rate weapon
|
|
|
|
for (int i = 0; i < static_cast<int>(weaponSkillsLength); ++i)
|
|
|
|
{
|
2018-12-23 15:18:33 +04:00
|
|
|
float max = 0;
|
2018-03-03 14:16:21 +04:00
|
|
|
int maxWeaponSkill = -1;
|
|
|
|
|
|
|
|
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
|
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
float skillValue = mActor.getClass().getSkill(mActor, static_cast<int>(weaponSkills[j]));
|
2018-03-03 14:16:21 +04:00
|
|
|
if (skillValue > max && !weaponSkillVisited[j])
|
|
|
|
{
|
|
|
|
max = skillValue;
|
|
|
|
maxWeaponSkill = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maxWeaponSkill == -1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
max = 0;
|
|
|
|
ContainerStoreIterator weapon(end());
|
|
|
|
|
|
|
|
for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter != end(); ++iter)
|
|
|
|
{
|
|
|
|
const ESM::Weapon* esmWeapon = iter->get<ESM::Weapon>()->mBase;
|
|
|
|
|
2018-12-26 13:45:28 +04:00
|
|
|
if (MWMechanics::getWeaponType(esmWeapon->mData.mType)->mWeaponClass == ESM::WeaponType::Ammo)
|
2018-03-03 14:16:21 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (iter->getClass().getEquipmentSkill(*iter) == weaponSkills[maxWeaponSkill])
|
|
|
|
{
|
|
|
|
if (esmWeapon->mData.mChop[1] >= max)
|
|
|
|
{
|
|
|
|
max = esmWeapon->mData.mChop[1];
|
|
|
|
weapon = iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (esmWeapon->mData.mSlash[1] >= max)
|
|
|
|
{
|
|
|
|
max = esmWeapon->mData.mSlash[1];
|
|
|
|
weapon = iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (esmWeapon->mData.mThrust[1] >= max)
|
|
|
|
{
|
|
|
|
max = esmWeapon->mData.mThrust[1];
|
|
|
|
weapon = iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, mActor).first)
|
2018-03-03 14:16:21 +04:00
|
|
|
{
|
|
|
|
// Do not equip ranged weapons, if there is no suitable ammo
|
|
|
|
bool hasAmmo = true;
|
2018-12-26 13:45:28 +04:00
|
|
|
const MWWorld::LiveCellRef<ESM::Weapon>* ref = weapon->get<ESM::Weapon>();
|
|
|
|
int type = ref->mBase->mData.mType;
|
|
|
|
int ammotype = MWMechanics::getWeaponType(type)->mAmmoType;
|
|
|
|
if (ammotype == ESM::Weapon::Arrow)
|
2018-03-03 14:16:21 +04:00
|
|
|
{
|
|
|
|
if (arrow == end())
|
|
|
|
hasAmmo = false;
|
|
|
|
else
|
|
|
|
slots_[Slot_Ammunition] = arrow;
|
|
|
|
}
|
2018-12-26 13:45:28 +04:00
|
|
|
else if (ammotype == ESM::Weapon::Bolt)
|
2018-03-03 14:16:21 +04:00
|
|
|
{
|
|
|
|
if (bolt == end())
|
|
|
|
hasAmmo = false;
|
|
|
|
else
|
|
|
|
slots_[Slot_Ammunition] = bolt;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasAmmo)
|
|
|
|
{
|
|
|
|
std::pair<std::vector<int>, bool> itemsSlots = weapon->getClass().getEquipmentSlots(*weapon);
|
|
|
|
|
|
|
|
if (!itemsSlots.first.empty())
|
|
|
|
{
|
|
|
|
if (!itemsSlots.second)
|
|
|
|
{
|
|
|
|
if (weapon->getRefData().getCount() > 1)
|
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
unstack(*weapon);
|
2018-03-03 14:16:21 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int slot = itemsSlots.first.front();
|
|
|
|
slots_[slot] = weapon;
|
|
|
|
|
2018-12-26 13:45:28 +04:00
|
|
|
if (ammotype == ESM::Weapon::None)
|
2018-03-03 14:16:21 +04:00
|
|
|
slots_[Slot_Ammunition] = end();
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
weaponSkillVisited[maxWeaponSkill] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
void MWWorld::InventoryStore::autoEquipArmor(TSlots& slots_)
|
2012-03-31 17:26:15 +02:00
|
|
|
{
|
2018-03-03 14:16:21 +04:00
|
|
|
// Only NPCs can wear armor for now.
|
|
|
|
// For creatures we equip only shields.
|
2023-01-16 23:51:04 +01:00
|
|
|
if (!mActor.getClass().isNpc())
|
2018-03-03 14:16:21 +04:00
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
autoEquipShield(slots_);
|
2018-03-03 14:16:21 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-04-20 21:07:53 +02:00
|
|
|
const MWWorld::Store<ESM::GameSetting>& store = MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
2016-10-16 17:27:17 +02:00
|
|
|
|
2018-08-29 18:38:12 +03:00
|
|
|
static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
|
|
|
|
static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
|
2016-10-16 17:27:17 +02:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
float unarmoredSkill = mActor.getClass().getSkill(mActor, ESM::Skill::Unarmored);
|
2017-02-17 03:11:37 +01:00
|
|
|
float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
|
2016-10-16 17:27:17 +02:00
|
|
|
|
|
|
|
for (ContainerStoreIterator iter(begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter != end();
|
|
|
|
++iter)
|
2012-03-31 17:26:15 +02:00
|
|
|
{
|
2012-04-07 20:09:09 +02:00
|
|
|
Ptr test = *iter;
|
2013-12-20 22:38:23 +01:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
switch (test.getClass().canBeEquipped(test, mActor).first)
|
2016-10-16 17:27:17 +02:00
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iter.getType() == ContainerStore::Type_Armor
|
2023-01-16 23:51:04 +01:00
|
|
|
&& test.getClass().getEffectiveArmorRating(test, mActor) <= std::max(unarmoredRating, 0.f))
|
2016-10-16 17:27:17 +02:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2012-04-07 20:09:09 +02:00
|
|
|
|
2012-03-31 17:26:15 +02:00
|
|
|
std::pair<std::vector<int>, bool> itemsSlots = iter->getClass().getEquipmentSlots(*iter);
|
|
|
|
|
2018-03-03 14:16:21 +04:00
|
|
|
// checking if current item pointed by iter can be equipped
|
2019-03-07 12:38:55 +04:00
|
|
|
for (int slot : itemsSlots.first)
|
2012-03-31 17:26:15 +02:00
|
|
|
{
|
2017-10-13 14:47:26 +02:00
|
|
|
// if true then it means slot is equipped already
|
2018-03-03 14:16:21 +04:00
|
|
|
// check if slot may require swapping if current item is more valuable
|
2019-03-07 12:38:55 +04:00
|
|
|
if (slots_.at(slot) != end())
|
2012-03-31 17:26:15 +02:00
|
|
|
{
|
2019-03-07 12:38:55 +04:00
|
|
|
Ptr old = *slots_.at(slot);
|
2012-04-07 20:09:09 +02:00
|
|
|
|
2016-10-16 17:27:17 +02:00
|
|
|
if (iter.getType() == ContainerStore::Type_Armor)
|
2012-04-08 12:26:21 +02:00
|
|
|
{
|
2021-10-11 11:46:21 +00:00
|
|
|
if (old.getType() == ESM::Armor::sRecordId)
|
2016-10-16 17:27:17 +02:00
|
|
|
{
|
2017-02-16 22:41:19 +09:00
|
|
|
if (old.get<ESM::Armor>()->mBase->mData.mType < test.get<ESM::Armor>()->mBase->mData.mType)
|
2016-10-16 17:27:17 +02:00
|
|
|
continue;
|
2017-02-16 22:41:19 +09:00
|
|
|
|
|
|
|
if (old.get<ESM::Armor>()->mBase->mData.mType == test.get<ESM::Armor>()->mBase->mData.mType)
|
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
if (old.getClass().getEffectiveArmorRating(old, mActor)
|
|
|
|
>= test.getClass().getEffectiveArmorRating(test, mActor))
|
2017-02-16 22:41:19 +09:00
|
|
|
// old armor had better armor rating
|
|
|
|
continue;
|
|
|
|
}
|
2016-10-16 17:27:17 +02:00
|
|
|
}
|
|
|
|
// suitable armor should replace already equipped clothing
|
2012-04-08 12:26:21 +02:00
|
|
|
}
|
2016-10-16 17:27:17 +02:00
|
|
|
else if (iter.getType() == ContainerStore::Type_Clothing)
|
2012-04-07 20:09:09 +02:00
|
|
|
{
|
2017-10-13 14:47:26 +02:00
|
|
|
// if left ring is equipped
|
2019-03-07 12:38:55 +04:00
|
|
|
if (slot == Slot_LeftRing)
|
2017-10-13 14:39:44 +02:00
|
|
|
{
|
2017-10-13 20:32:52 +02:00
|
|
|
// if there is a place for right ring dont swap it
|
2017-10-13 15:16:07 +02:00
|
|
|
if (slots_.at(Slot_RightRing) == end())
|
2017-10-13 14:39:44 +02:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2017-10-13 15:16:07 +02:00
|
|
|
else // if right ring is equipped too
|
|
|
|
{
|
|
|
|
Ptr rightRing = *slots_.at(Slot_RightRing);
|
|
|
|
|
|
|
|
// we want to swap cheaper ring only if both are equipped
|
2017-10-20 23:05:12 +04:00
|
|
|
if (old.getClass().getValue(old) >= rightRing.getClass().getValue(rightRing))
|
2017-10-13 15:16:07 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-10-13 14:39:44 +02:00
|
|
|
}
|
|
|
|
|
2021-10-11 11:46:21 +00:00
|
|
|
if (old.getType() == ESM::Clothing::sRecordId)
|
2012-04-08 12:26:21 +02:00
|
|
|
{
|
2016-10-16 17:27:17 +02:00
|
|
|
// check value
|
2017-10-19 22:46:08 +10:30
|
|
|
if (old.getClass().getValue(old) >= test.getClass().getValue(test))
|
2016-10-16 17:27:17 +02:00
|
|
|
// old clothing was more valuable
|
|
|
|
continue;
|
2012-04-08 12:26:21 +02:00
|
|
|
}
|
2016-10-16 17:27:17 +02:00
|
|
|
else
|
|
|
|
// suitable clothing should NOT replace already equipped armor
|
|
|
|
continue;
|
2012-04-07 20:09:09 +02:00
|
|
|
}
|
2012-03-31 17:26:15 +02:00
|
|
|
}
|
2012-04-07 20:09:09 +02:00
|
|
|
|
2012-05-13 11:52:17 +02:00
|
|
|
if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped
|
|
|
|
{
|
|
|
|
// unstack item pointed to by iterator if required
|
|
|
|
if (iter->getRefData().getCount() > 1)
|
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
unstack(*iter);
|
2012-05-13 11:52:17 +02:00
|
|
|
}
|
|
|
|
}
|
2012-04-07 20:09:09 +02:00
|
|
|
|
2017-10-13 14:47:26 +02:00
|
|
|
// if we are here it means item can be equipped or swapped
|
2019-03-07 12:38:55 +04:00
|
|
|
slots_[slot] = iter;
|
2012-04-07 20:09:09 +02:00
|
|
|
break;
|
2012-03-31 17:26:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-13 14:58:38 +02:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
void MWWorld::InventoryStore::autoEquipShield(TSlots& slots_)
|
2017-01-08 20:52:04 +01:00
|
|
|
{
|
|
|
|
for (ContainerStoreIterator iter(begin(ContainerStore::Type_Armor)); iter != end(); ++iter)
|
|
|
|
{
|
|
|
|
if (iter->get<ESM::Armor>()->mBase->mData.mType != ESM::Armor::Shield)
|
|
|
|
continue;
|
2023-01-16 23:51:04 +01:00
|
|
|
if (iter->getClass().canBeEquipped(*iter, mActor).first != 1)
|
2017-01-08 20:52:04 +01:00
|
|
|
continue;
|
|
|
|
std::pair<std::vector<int>, bool> shieldSlots = iter->getClass().getEquipmentSlots(*iter);
|
|
|
|
int slot = shieldSlots.first[0];
|
2020-01-05 23:30:22 +03:00
|
|
|
const ContainerStoreIterator& shield = slots_[slot];
|
2017-01-08 20:52:04 +01:00
|
|
|
if (shield != end() && shield.getType() == Type_Armor
|
|
|
|
&& shield->get<ESM::Armor>()->mBase->mData.mType == ESM::Armor::Shield)
|
|
|
|
{
|
|
|
|
if (shield->getClass().getItemHealth(*shield) >= iter->getClass().getItemHealth(*iter))
|
|
|
|
continue;
|
|
|
|
}
|
2018-03-03 14:16:21 +04:00
|
|
|
slots_[slot] = iter;
|
|
|
|
}
|
|
|
|
}
|
2017-01-08 20:52:04 +01:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
void MWWorld::InventoryStore::autoEquip()
|
2018-03-03 14:16:21 +04:00
|
|
|
{
|
|
|
|
TSlots slots_;
|
|
|
|
initSlots(slots_);
|
|
|
|
|
|
|
|
// Disable model update during auto-equip
|
|
|
|
mUpdatesEnabled = false;
|
|
|
|
|
|
|
|
// Autoequip clothing, armor and weapons.
|
|
|
|
// Equipping lights is handled in Actors::updateEquippedLight based on environment light.
|
2019-05-11 19:20:23 +03:00
|
|
|
// Note: creatures ignore equipment armor rating and only equip shields
|
|
|
|
// Use custom logic for them - select shield based on its health instead of armor rating
|
2023-01-16 23:51:04 +01:00
|
|
|
autoEquipWeapon(slots_);
|
|
|
|
autoEquipArmor(slots_);
|
2018-03-03 14:16:21 +04:00
|
|
|
|
|
|
|
bool changed = false;
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < slots_.size(); ++i)
|
|
|
|
{
|
|
|
|
if (slots_[i] != mSlots[i])
|
|
|
|
{
|
|
|
|
changed = true;
|
|
|
|
break;
|
|
|
|
}
|
2017-01-08 20:52:04 +01:00
|
|
|
}
|
|
|
|
mUpdatesEnabled = true;
|
|
|
|
|
2018-03-03 14:16:21 +04:00
|
|
|
if (changed)
|
2017-01-08 20:52:04 +01:00
|
|
|
{
|
2018-03-03 14:16:21 +04:00
|
|
|
mSlots.swap(slots_);
|
2023-01-16 23:51:04 +01:00
|
|
|
fireEquipmentChangedEvent();
|
2018-03-03 14:16:21 +04:00
|
|
|
flagAsModified();
|
2017-01-08 20:52:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getPreferredShield()
|
2020-12-29 01:40:30 +00:00
|
|
|
{
|
|
|
|
TSlots slots;
|
|
|
|
initSlots(slots);
|
2023-01-16 23:51:04 +01:00
|
|
|
autoEquipArmor(slots);
|
2020-12-29 01:40:30 +00:00
|
|
|
return slots[Slot_CarriedLeft];
|
|
|
|
}
|
|
|
|
|
2017-03-08 01:28:56 +01:00
|
|
|
bool MWWorld::InventoryStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) const
|
2012-05-13 14:58:38 +02:00
|
|
|
{
|
2013-11-12 23:12:56 +01:00
|
|
|
bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2);
|
2012-05-13 14:58:38 +02:00
|
|
|
if (!canStack)
|
|
|
|
return false;
|
|
|
|
|
2013-11-15 02:08:36 +01:00
|
|
|
// don't stack if either item is currently equipped
|
2012-05-13 14:58:38 +02:00
|
|
|
for (TSlots::const_iterator iter(mSlots.begin()); iter != mSlots.end(); ++iter)
|
|
|
|
{
|
2013-11-12 23:12:56 +01:00
|
|
|
if (*iter != end() && (ptr1 == **iter || ptr2 == **iter))
|
2013-10-23 14:36:55 +02:00
|
|
|
{
|
2014-05-22 20:37:22 +02:00
|
|
|
bool stackWhenEquipped = (*iter)->getClass().getEquipmentSlots(**iter).second;
|
2013-10-23 14:36:55 +02:00
|
|
|
if (!stackWhenEquipped)
|
|
|
|
return false;
|
|
|
|
}
|
2012-05-13 14:58:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2012-05-29 12:35:03 +02:00
|
|
|
|
|
|
|
void MWWorld::InventoryStore::setSelectedEnchantItem(const ContainerStoreIterator& iterator)
|
|
|
|
{
|
|
|
|
mSelectedEnchantItem = iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem()
|
|
|
|
{
|
|
|
|
return mSelectedEnchantItem;
|
|
|
|
}
|
2013-08-13 01:19:33 +02:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
int MWWorld::InventoryStore::remove(const Ptr& item, int count, bool equipReplacement, bool resolve)
|
2017-10-06 10:54:25 +04:00
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
int retCount = ContainerStore::remove(item, count, equipReplacement, resolve);
|
2013-11-01 00:54:54 +01:00
|
|
|
|
2015-07-23 02:28:38 +02:00
|
|
|
bool wasEquipped = false;
|
2014-02-04 04:11:46 +01:00
|
|
|
if (!item.getRefData().getCount())
|
|
|
|
{
|
|
|
|
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
2013-11-01 00:54:54 +01:00
|
|
|
{
|
2014-02-04 04:11:46 +01:00
|
|
|
if (mSlots[slot] == end())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (*mSlots[slot] == item)
|
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
unequipSlot(slot);
|
2015-07-23 02:28:38 +02:00
|
|
|
wasEquipped = true;
|
2014-02-04 04:11:46 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-11-01 00:54:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-24 02:14:05 +02:00
|
|
|
// If an armor/clothing item is removed, try to find a replacement,
|
2017-04-13 22:18:03 +09:00
|
|
|
// but not for the player nor werewolves, and not if the RemoveItem script command
|
|
|
|
// was used (equipReplacement is false)
|
2023-01-16 23:51:04 +01:00
|
|
|
if (equipReplacement && wasEquipped && (mActor != MWMechanics::getPlayer()) && mActor.getClass().isNpc()
|
|
|
|
&& !mActor.getClass().getNpcStats(mActor).isWerewolf())
|
2013-10-24 02:14:05 +02:00
|
|
|
{
|
2021-10-11 11:46:21 +00:00
|
|
|
auto type = item.getType();
|
|
|
|
if (type == ESM::Armor::sRecordId || type == ESM::Clothing::sRecordId)
|
2023-01-16 23:51:04 +01:00
|
|
|
autoEquip();
|
2013-10-24 02:14:05 +02:00
|
|
|
}
|
|
|
|
|
2013-11-17 23:15:57 +01:00
|
|
|
if (item.getRefData().getCount() == 0 && mSelectedEnchantItem != end() && *mSelectedEnchantItem == item)
|
|
|
|
{
|
|
|
|
mSelectedEnchantItem = end();
|
|
|
|
}
|
|
|
|
|
2018-03-03 14:16:21 +04:00
|
|
|
if (mListener)
|
|
|
|
mListener->itemRemoved(item, retCount);
|
|
|
|
|
2013-10-24 02:14:05 +02:00
|
|
|
return retCount;
|
2013-08-13 01:19:33 +02:00
|
|
|
}
|
2013-11-01 00:54:54 +01:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, bool applyUpdates)
|
2013-11-01 00:54:54 +01:00
|
|
|
{
|
2016-01-11 07:24:52 -06:00
|
|
|
if (slot < 0 || slot >= static_cast<int>(mSlots.size()))
|
|
|
|
throw std::runtime_error("slot number out of range");
|
|
|
|
|
2014-02-04 04:11:46 +01:00
|
|
|
ContainerStoreIterator it = mSlots[slot];
|
2013-11-01 01:01:55 +01:00
|
|
|
|
2013-11-01 00:54:54 +01:00
|
|
|
if (it != end())
|
|
|
|
{
|
2013-11-01 01:01:55 +01:00
|
|
|
ContainerStoreIterator retval = it;
|
2013-11-09 02:47:11 +01:00
|
|
|
|
2013-11-14 19:54:00 +01:00
|
|
|
// empty this slot
|
|
|
|
mSlots[slot] = end();
|
|
|
|
|
2014-07-16 15:30:06 +02:00
|
|
|
if (it->getRefData().getCount())
|
2014-02-04 04:11:46 +01:00
|
|
|
{
|
2014-07-16 15:30:06 +02:00
|
|
|
retval = restack(*it);
|
2013-11-01 00:55:24 +01:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
if (mActor == MWMechanics::getPlayer())
|
2013-11-01 00:55:24 +01:00
|
|
|
{
|
2014-07-16 15:30:06 +02:00
|
|
|
// Unset OnPCEquip Variable on item's script, if it has a script with that variable declared
|
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID
Slowly going through all the changes to make, still hundreds of errors
a lot of functions/structures use std::string or stringview to designate an ID. So it takes time
Continues slowly replacing ids. There are technically more and more compilation errors
I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type
Continue moving forward, changes to the stores
slowly moving along
Starting to see the fruit of those changes.
still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.
More replacements. Things are starting to get easier
I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.
Still moving forward, and for the first time error count is going down!
Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably
Cells are back to using string for the name, haven't fixed everything yet. Many other changes
Under the bar of 400 compilation errors.
more good progress <100 compile errors!
More progress
Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string
some more progress on other fronts
Mostly game settings clean
one error opened a lot of other errors. Down to 18, but more will prbably appear
only link errors left??
Fixed link errors
OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
|
|
|
const ESM::RefId& script = it->getClass().getScript(*it);
|
2022-08-11 22:51:55 +02:00
|
|
|
if (!script.empty())
|
2014-07-16 15:30:06 +02:00
|
|
|
(*it).getRefData().getLocals().setVarByInt(script, "onpcequip", 0);
|
2014-08-28 16:31:06 +02:00
|
|
|
}
|
2014-07-16 15:30:06 +02:00
|
|
|
|
2014-08-28 16:31:06 +02:00
|
|
|
if ((mSelectedEnchantItem != end()) && (mSelectedEnchantItem == it))
|
|
|
|
{
|
|
|
|
mSelectedEnchantItem = end();
|
2013-11-01 00:55:24 +01:00
|
|
|
}
|
|
|
|
}
|
2013-11-01 00:54:54 +01:00
|
|
|
|
2021-01-10 08:04:06 +00:00
|
|
|
if (applyUpdates)
|
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
fireEquipmentChangedEvent();
|
2021-01-10 08:04:06 +00:00
|
|
|
}
|
2013-11-01 01:01:55 +01:00
|
|
|
|
|
|
|
return retval;
|
2013-11-01 00:54:54 +01:00
|
|
|
}
|
2013-11-01 01:01:55 +01:00
|
|
|
|
|
|
|
return it;
|
2013-11-01 00:54:54 +01:00
|
|
|
}
|
2013-11-01 00:21:15 +01:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItem(const MWWorld::Ptr& item)
|
2013-11-01 00:21:15 +01:00
|
|
|
{
|
|
|
|
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
|
|
|
{
|
|
|
|
MWWorld::ContainerStoreIterator equipped = getSlot(slot);
|
|
|
|
if (equipped != end() && *equipped == item)
|
2023-01-16 23:51:04 +01:00
|
|
|
return unequipSlot(slot);
|
2013-11-01 00:21:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
throw std::runtime_error("attempt to unequip an item that is not currently equipped");
|
|
|
|
}
|
2013-10-25 22:16:52 +02:00
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItemQuantity(const Ptr& item, int count)
|
2016-01-18 19:56:35 -06:00
|
|
|
{
|
|
|
|
if (!isEquipped(item))
|
|
|
|
throw std::runtime_error("attempt to unequip an item that is not currently equipped");
|
|
|
|
if (count <= 0)
|
|
|
|
throw std::runtime_error("attempt to unequip nothing (count <= 0)");
|
|
|
|
if (count > item.getRefData().getCount())
|
|
|
|
throw std::runtime_error("attempt to unequip more items than equipped");
|
|
|
|
|
|
|
|
if (count == item.getRefData().getCount())
|
2023-01-16 23:51:04 +01:00
|
|
|
return unequipItem(item);
|
2016-01-18 19:56:35 -06:00
|
|
|
|
|
|
|
// Move items to an existing stack if possible, otherwise split count items out into a new stack.
|
|
|
|
// Moving counts manually here, since ContainerStore's restack can't target unequipped stacks.
|
|
|
|
for (MWWorld::ContainerStoreIterator iter(begin()); iter != end(); ++iter)
|
|
|
|
{
|
|
|
|
if (stacks(*iter, item) && !isEquipped(*iter))
|
|
|
|
{
|
2020-10-13 17:46:32 +02:00
|
|
|
iter->getRefData().setCount(addItems(iter->getRefData().getCount(false), count));
|
|
|
|
item.getRefData().setCount(subtractItems(item.getRefData().getCount(false), count));
|
2016-01-18 19:56:35 -06:00
|
|
|
return iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
return unstack(item, item.getRefData().getCount() - count);
|
2016-01-18 19:56:35 -06:00
|
|
|
}
|
|
|
|
|
2021-08-27 20:07:50 +02:00
|
|
|
MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getInvListener() const
|
2015-06-07 16:50:34 +02:00
|
|
|
{
|
2018-03-03 14:16:21 +04:00
|
|
|
return mInventoryListener;
|
2015-06-07 16:50:34 +02:00
|
|
|
}
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
void MWWorld::InventoryStore::setInvListener(InventoryStoreListener* listener)
|
2013-10-25 22:16:52 +02:00
|
|
|
{
|
2018-03-03 14:16:21 +04:00
|
|
|
mInventoryListener = listener;
|
2013-11-15 02:08:36 +01:00
|
|
|
}
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
void MWWorld::InventoryStore::fireEquipmentChangedEvent()
|
2013-11-15 02:08:36 +01:00
|
|
|
{
|
|
|
|
if (!mUpdatesEnabled)
|
|
|
|
return;
|
2018-03-03 14:16:21 +04:00
|
|
|
if (mInventoryListener)
|
|
|
|
mInventoryListener->equipmentChanged();
|
2015-04-06 15:13:09 +12:00
|
|
|
|
|
|
|
// if player, update inventory window
|
2015-04-19 02:39:10 +02:00
|
|
|
/*
|
2023-01-16 23:51:04 +01:00
|
|
|
if (mActor == MWMechanics::getPlayer())
|
2015-04-06 15:13:09 +12:00
|
|
|
{
|
|
|
|
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
|
|
|
|
}
|
2015-04-19 02:39:10 +02:00
|
|
|
*/
|
2013-10-25 22:16:52 +02:00
|
|
|
}
|
2013-11-15 20:29:47 +01:00
|
|
|
|
2014-02-01 17:07:08 +01:00
|
|
|
void MWWorld::InventoryStore::clear()
|
|
|
|
{
|
|
|
|
mSlots.clear();
|
|
|
|
initSlots(mSlots);
|
|
|
|
ContainerStore::clear();
|
|
|
|
}
|
2014-12-15 13:47:34 +01:00
|
|
|
|
2015-12-18 17:06:58 +01:00
|
|
|
bool MWWorld::InventoryStore::isEquipped(const MWWorld::ConstPtr& item)
|
2014-12-15 13:47:34 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < MWWorld::InventoryStore::Slots; ++i)
|
|
|
|
{
|
|
|
|
if (getSlot(i) != end() && *getSlot(i) == item)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2014-12-30 01:36:31 +01:00
|
|
|
|
2021-08-27 20:07:50 +02:00
|
|
|
bool MWWorld::InventoryStore::isFirstEquip()
|
2014-12-30 01:36:31 +01:00
|
|
|
{
|
2021-08-27 20:07:50 +02:00
|
|
|
bool first = mFirstAutoEquip;
|
|
|
|
mFirstAutoEquip = false;
|
|
|
|
return first;
|
2014-12-30 01:36:31 +01:00
|
|
|
}
|