1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 05:19:55 +00:00
openmw-tes3mp/apps/openmw/mwgui/containeritemmodel.cpp

253 lines
7.7 KiB
C++
Raw Normal View History

2013-05-11 16:38:27 +00:00
#include "containeritemmodel.hpp"
2017-06-13 09:55:22 +00:00
#include <algorithm>
2017-10-04 17:25:22 +00:00
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/actorutil.hpp"
2013-05-11 16:38:27 +00:00
#include "../mwworld/containerstore.hpp"
#include "../mwworld/class.hpp"
2013-05-27 00:18:36 +00:00
#include "../mwbase/environment.hpp"
2017-10-04 17:25:22 +00:00
#include "../mwbase/mechanicsmanager.hpp"
2017-10-04 18:37:08 +00:00
#include "../mwbase/windowmanager.hpp"
2017-10-04 17:25:22 +00:00
#include "../mwbase/world.hpp"
2013-05-27 00:18:36 +00:00
namespace
{
bool stacks (const MWWorld::Ptr& left, const MWWorld::Ptr& right)
{
if (left == right)
return true;
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
if (left.getContainerStore() && right.getContainerStore())
return left.getContainerStore()->stacks(left, right)
&& right.getContainerStore()->stacks(left, right);
if (left.getContainerStore())
return left.getContainerStore()->stacks(left, right);
if (right.getContainerStore())
return right.getContainerStore()->stacks(left, right);
MWWorld::ContainerStore store;
return store.stacks(left, right);
}
}
2013-05-11 16:38:27 +00:00
namespace MWGui
{
2013-05-27 00:18:36 +00:00
ContainerItemModel::ContainerItemModel(const std::vector<MWWorld::Ptr>& itemSources, const std::vector<MWWorld::Ptr>& worldItems)
: mWorldItems(worldItems)
, mTrading(true)
2013-05-11 16:38:27 +00:00
{
assert (!itemSources.empty());
// Tie resolution lifetimes to the ItemModel
mItemSources.reserve(itemSources.size());
for(const MWWorld::Ptr& source : itemSources)
{
MWWorld::ContainerStore& store = source.getClass().getContainerStore(source);
mItemSources.push_back(std::make_pair(source, store.resolveTemporarily()));
}
2013-05-11 16:38:27 +00:00
}
ContainerItemModel::ContainerItemModel (const MWWorld::Ptr& source) : mTrading(false)
2013-05-11 16:38:27 +00:00
{
MWWorld::ContainerStore& store = source.getClass().getContainerStore(source);
mItemSources.push_back(std::make_pair(source, store.resolveTemporarily()));
2013-05-11 16:38:27 +00:00
}
bool ContainerItemModel::allowedToUseItems() const
{
if (mItemSources.empty())
return true;
MWWorld::Ptr ptr = MWMechanics::getPlayer();
MWWorld::Ptr victim;
// Check if the player is allowed to use items from opened container
MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager();
return mm->isAllowedToUse(ptr, mItemSources[0].first, victim);
}
2013-05-11 16:38:27 +00:00
ItemStack ContainerItemModel::getItem (ModelIndex index)
{
if (index < 0)
throw std::runtime_error("Invalid index supplied");
if (mItems.size() <= static_cast<size_t>(index))
throw std::runtime_error("Item index out of range");
return mItems[index];
}
size_t ContainerItemModel::getItemCount()
{
return mItems.size();
}
ItemModel::ModelIndex ContainerItemModel::getIndex (ItemStack item)
{
size_t i = 0;
for (ItemStack& itemStack : mItems)
2013-05-11 16:38:27 +00:00
{
if (itemStack == item)
2013-05-11 16:38:27 +00:00
return i;
++i;
}
return -1;
}
MWWorld::Ptr ContainerItemModel::copyItem (const ItemStack& item, size_t count, bool allowAutoEquip)
2013-05-11 16:38:27 +00:00
{
auto& source = mItemSources[0];
MWWorld::ContainerStore& store = source.first.getClass().getContainerStore(source.first);
if (item.mBase.getContainerStore() == &store)
2013-08-25 15:40:08 +00:00
throw std::runtime_error("Item to copy needs to be from a different container!");
return *store.add(item.mBase, count, source.first, allowAutoEquip);
2013-05-11 16:38:27 +00:00
}
void ContainerItemModel::removeItem (const ItemStack& item, size_t count)
{
int toRemove = count;
for (auto& source : mItemSources)
2013-05-11 16:38:27 +00:00
{
MWWorld::ContainerStore& store = source.first.getClass().getContainerStore(source.first);
2013-05-11 16:38:27 +00:00
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
2013-05-27 00:18:36 +00:00
if (stacks(*it, item.mBase))
2013-05-11 16:38:27 +00:00
{
int quantity = it->mRef->mData.getCount(false);
// If this is a restocking quantity, just don't remove it
if(quantity < 0 && mTrading)
toRemove += quantity;
else
toRemove -= store.remove(*it, toRemove, source.first);
2013-05-11 16:38:27 +00:00
if (toRemove <= 0)
return;
}
}
}
for (MWWorld::Ptr& source : mWorldItems)
2013-05-27 00:18:36 +00:00
{
if (stacks(source, item.mBase))
2013-05-27 00:18:36 +00:00
{
int refCount = source.getRefData().getCount();
2013-05-27 00:18:36 +00:00
if (refCount - toRemove <= 0)
MWBase::Environment::get().getWorld()->deleteObject(source);
2013-05-27 00:18:36 +00:00
else
source.getRefData().setCount(std::max(0, refCount - toRemove));
2013-05-27 00:18:36 +00:00
toRemove -= refCount;
if (toRemove <= 0)
return;
}
}
2013-05-11 16:38:27 +00:00
throw std::runtime_error("Not enough items to remove could be found");
}
void ContainerItemModel::update()
{
mItems.clear();
for (auto& source : mItemSources)
2013-05-11 16:38:27 +00:00
{
MWWorld::ContainerStore& store = source.first.getClass().getContainerStore(source.first);
2013-05-11 16:38:27 +00:00
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
if (!(*it).getClass().showsInInventory(*it))
continue;
bool found = false;
for (ItemStack& itemStack : mItems)
2013-05-11 16:38:27 +00:00
{
if (stacks(*it, itemStack.mBase))
2013-05-11 16:38:27 +00:00
{
// we already have an item stack of this kind, add to it
itemStack.mCount += it->getRefData().getCount();
found = true;
2013-05-11 16:38:27 +00:00
break;
}
}
if (!found)
2013-05-11 16:38:27 +00:00
{
// no stack yet, create one
ItemStack newItem (*it, this, it->getRefData().getCount());
mItems.push_back(newItem);
}
}
}
for (MWWorld::Ptr& source : mWorldItems)
2013-05-27 00:18:36 +00:00
{
bool found = false;
for (ItemStack& itemStack : mItems)
2013-05-27 00:18:36 +00:00
{
if (stacks(source, itemStack.mBase))
2013-05-27 00:18:36 +00:00
{
// we already have an item stack of this kind, add to it
itemStack.mCount += source.getRefData().getCount();
found = true;
2013-05-27 00:18:36 +00:00
break;
}
}
if (!found)
2013-05-27 00:18:36 +00:00
{
// no stack yet, create one
ItemStack newItem (source, this, source.getRefData().getCount());
2013-05-27 00:18:36 +00:00
mItems.push_back(newItem);
}
}
2013-05-11 16:38:27 +00:00
}
2017-10-04 19:26:06 +00:00
bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count)
2017-10-04 18:37:08 +00:00
{
if (mItemSources.empty())
return false;
MWWorld::Ptr target = mItemSources[0].first;
2013-05-11 16:38:27 +00:00
2017-10-04 18:37:08 +00:00
if (target.getTypeName() != typeid(ESM::Container).name())
return true;
// check container organic flag
MWWorld::LiveCellRef<ESM::Container>* ref = target.get<ESM::Container>();
if (ref->mBase->mFlags & ESM::Container::Organic)
{
MWBase::Environment::get().getWindowManager()->
messageBox("#{sContentsMessage2}");
return false;
}
// check that we don't exceed container capacity
float weight = item.getClass().getWeight(item) * count;
if (target.getClass().getCapacity(target) < target.getClass().getEncumbrance(target) + weight)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}");
return false;
}
return true;
}
2017-10-04 19:26:06 +00:00
bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count)
2017-10-04 17:25:22 +00:00
{
if (mItemSources.empty())
return false;
MWWorld::Ptr target = mItemSources[0].first;
2017-10-04 17:25:22 +00:00
// Looting a dead corpse is considered OK
if (target.getClass().isActor() && target.getClass().getCreatureStats(target).isDead())
return true;
2017-10-04 18:37:08 +00:00
2017-10-04 17:25:22 +00:00
MWWorld::Ptr player = MWMechanics::getPlayer();
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, target, count);
return true;
}
2013-05-11 16:38:27 +00:00
}