diff --git a/apps/openmw/mwgui/companionitemmodel.cpp b/apps/openmw/mwgui/companionitemmodel.cpp index 3c017a2856..6bae8aef52 100644 --- a/apps/openmw/mwgui/companionitemmodel.cpp +++ b/apps/openmw/mwgui/companionitemmodel.cpp @@ -33,6 +33,14 @@ namespace MWGui return InventoryItemModel::addItem(item, count, allowAutoEquip); } + MWWorld::Ptr CompanionItemModel::copyItem(const ItemStack& item, size_t count, bool allowAutoEquip) + { + if (hasProfit(mActor)) + modifyProfit(mActor, item.mBase.getClass().getValue(item.mBase) * count); + + return InventoryItemModel::copyItem(item, count, allowAutoEquip); + } + void CompanionItemModel::removeItem(const ItemStack& item, size_t count) { if (hasProfit(mActor)) diff --git a/apps/openmw/mwgui/companionitemmodel.hpp b/apps/openmw/mwgui/companionitemmodel.hpp index 49c84fe075..b9ee500693 100644 --- a/apps/openmw/mwgui/companionitemmodel.hpp +++ b/apps/openmw/mwgui/companionitemmodel.hpp @@ -14,6 +14,7 @@ namespace MWGui CompanionItemModel(const MWWorld::Ptr& actor); MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override; + MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override; void removeItem(const ItemStack& item, size_t count) override; bool hasProfit(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index e072f9974a..ba4f7156c9 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -104,10 +104,19 @@ namespace MWGui auto& source = mItemSources[0]; MWWorld::ContainerStore& store = source.first.getClass().getContainerStore(source.first); if (item.mBase.getContainerStore() == &store) - throw std::runtime_error("Item needs to be from a different container!"); + throw std::runtime_error("Item to add needs to be from a different container!"); return *store.add(item.mBase, count, allowAutoEquip); } + MWWorld::Ptr ContainerItemModel::copyItem(const ItemStack& item, size_t count, bool allowAutoEquip) + { + auto& source = mItemSources[0]; + MWWorld::ContainerStore& store = source.first.getClass().getContainerStore(source.first); + if (item.mBase.getContainerStore() == &store) + throw std::runtime_error("Item to copy needs to be from a different container!"); + return *store.add(item.mBase.getCellRef().getRefId(), count, allowAutoEquip); + } + void ContainerItemModel::removeItem(const ItemStack& item, size_t count) { int toRemove = count; diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index 52b1911411..8e6f5a37ef 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -33,6 +33,7 @@ namespace MWGui size_t getItemCount() override; MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override; + MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override; void removeItem(const ItemStack& item, size_t count) override; void update() override; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index b936620895..022840ea5e 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -46,20 +46,30 @@ namespace MWGui } virtual ~WorldItemModel() override {} - MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override + MWWorld::Ptr dropItemImpl(const ItemStack& item, size_t count, bool copy) { MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr dropped; if (world->canPlaceObject(mLeft, mTop)) - dropped = world->placeObject(item.mBase, mLeft, mTop, count, false); + dropped = world->placeObject(item.mBase, mLeft, mTop, count, copy); else - dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count, false); + dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count, copy); dropped.getCellRef().setOwner(ESM::RefId()); return dropped; } + MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override + { + return dropItemImpl(item, count, false); + } + + MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override + { + return dropItemImpl(item, count, true); + } + void removeItem(const ItemStack& item, size_t count) override { throw std::runtime_error("removeItem not implemented"); diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 1bd51acc1e..e87ae7b8e0 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -8,6 +8,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/manualref.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -53,6 +54,14 @@ namespace MWGui return *mActor.getClass().getContainerStore(mActor).add(item.mBase, count, allowAutoEquip); } + MWWorld::Ptr InventoryItemModel::copyItem(const ItemStack& item, size_t count, bool allowAutoEquip) + { + if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor)) + throw std::runtime_error("Item to copy needs to be from a different container!"); + return *mActor.getClass().getContainerStore(mActor).add( + item.mBase.getCellRef().getRefId(), count, allowAutoEquip); + } + void InventoryItemModel::removeItem(const ItemStack& item, size_t count) { int removed = 0; diff --git a/apps/openmw/mwgui/inventoryitemmodel.hpp b/apps/openmw/mwgui/inventoryitemmodel.hpp index 5310016d74..560d1a0fbd 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.hpp +++ b/apps/openmw/mwgui/inventoryitemmodel.hpp @@ -18,6 +18,7 @@ namespace MWGui bool onTakeItem(const MWWorld::Ptr& item, int count) override; MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override; + MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override; void removeItem(const ItemStack& item, size_t count) override; /// Move items from this model to \a otherModel. diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 23b777e91f..03bec62e7a 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -7,6 +7,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include + namespace MWGui { @@ -58,16 +60,19 @@ namespace MWGui MWWorld::Ptr ItemModel::moveItem(const ItemStack& item, size_t count, ItemModel* otherModel, bool allowAutoEquip) { - MWWorld::Ptr ret = otherModel->addItem(item, count, allowAutoEquip); - removeItem(item, count); - // Although logically the same as an unstack, to avoid unneccesarily allocating a new stack - // and then immediately removing it, we assign a new refnum here instead of calling unstack() - if (!item.mBase.getRefData().isDeleted()) + MWWorld::Ptr ret = MWWorld::Ptr(); + if (item.mBase.getRefData().getCount() <= count) + { + // We are moving the full stack + ret = otherModel->addItem(item, count, allowAutoEquip); + removeItem(item, count); + } + else { - ret.getCellRef().unsetRefNum(); - ret.getRefData().setLuaScripts(nullptr); - MWBase::Environment::get().getWorldModel()->registerPtr(ret); - MWBase::Environment::get().getWorldModel()->registerPtr(item.mBase); + // We are moving only part of the stack, so create a copy in the other model + // and then remove count from this model. + ret = otherModel->copyItem(item, count, allowAutoEquip); + removeItem(item, count); } return ret; } @@ -92,6 +97,11 @@ namespace MWGui return mSourceModel->allowedToUseItems(); } + MWWorld::Ptr ProxyItemModel::copyItem(const ItemStack& item, size_t count, bool allowAutoEquip) + { + return mSourceModel->copyItem(item, count, allowAutoEquip); + } + void ProxyItemModel::removeItem(const ItemStack& item, size_t count) { mSourceModel->removeItem(item, count); diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index 78bfd508f0..7af29878eb 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -67,6 +67,7 @@ namespace MWGui const ItemStack& item, size_t count, ItemModel* otherModel, bool allowAutoEquip = true); virtual MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) = 0; + virtual MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) = 0; virtual void removeItem(const ItemStack& item, size_t count) = 0; /// Is the player allowed to use items from this item model? (default true) @@ -97,6 +98,7 @@ namespace MWGui bool onTakeItem(const MWWorld::Ptr& item, int count) override; MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override; + MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override; void removeItem(const ItemStack& item, size_t count) override; ModelIndex getIndex(const ItemStack& item) override; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index b429bc31ed..b3ea654404 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -300,10 +300,10 @@ bool MWWorld::ContainerStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) && cls2.getItemHealth(ptr2) == cls2.getItemMaxHealth(ptr2))); } -MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const ESM::RefId& id, int count) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const ESM::RefId& id, int count, bool allowAutoEquip) { MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), id, count); - return add(ref.getPtr(), count); + return add(ref.getPtr(), count, allowAutoEquip); } MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add( diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 9d02e0b95c..253df39567 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -198,7 +198,7 @@ namespace MWWorld /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to /// the newly inserted item. - ContainerStoreIterator add(const ESM::RefId& id, int count); + ContainerStoreIterator add(const ESM::RefId& id, int count, bool allowAutoEquip = true); ///< Utility to construct a ManualRef and call add(ptr, count, actorPtr, true) int remove(const ESM::RefId& itemId, int count, bool equipReplacement = 0, bool resolve = true);