From 5b0251b09f1123874b5af665aa44eae5e452489c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 16:17:03 +0200 Subject: [PATCH 1/5] item stacking --- apps/openmw/mwclass/armor.cpp | 8 ++++++++ apps/openmw/mwclass/armor.hpp | 3 +++ apps/openmw/mwclass/clothing.cpp | 8 ++++++++ apps/openmw/mwclass/clothing.hpp | 3 +++ apps/openmw/mwclass/weapon.cpp | 8 ++++++++ apps/openmw/mwclass/weapon.hpp | 3 +++ apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 6 +++++- apps/openmw/mwworld/containerstore.cpp | 18 +++++++++++++++++- 9 files changed, 60 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index fb34e4c88..87a5dde27 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -248,4 +248,12 @@ namespace MWClass return info; } + + std::string Armor::getEnchantment (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->enchant; + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index c757587e5..3ff101a5e 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -55,6 +55,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + ///< @return the enchantment ID if the object is enchanted, otherwise an empty string }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 620b664cc..a242874df 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -201,4 +201,12 @@ namespace MWClass return info; } + + std::string Clothing::getEnchantment (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->enchant; + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index afb184999..9b9322969 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -49,6 +49,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + ///< @return the enchantment ID if the object is enchanted, otherwise an empty string }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index fcfaebcb7..0ddf19d3c 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -339,4 +339,12 @@ namespace MWClass return info; } + + std::string Weapon::getEnchantment (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->enchant; + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 9c5f43bd3..c27a39620 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -55,6 +55,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + ///< @return the enchantment ID if the object is enchanted, otherwise an empty string }; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 78ed5ca2e..151d913be 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -181,4 +181,9 @@ namespace MWWorld { return false; } + + std::string Class::getEnchantment (const Ptr& ptr) const + { + return ""; + } } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e69b8f2ac..d7a2d2d75 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -136,7 +136,7 @@ namespace MWWorld ///< Set or unset a stance. virtual bool getStance (const Ptr& ptr, Stance stance, bool ignoreForce = false) const; - ////< Check if a stance is active or not. + ///< Check if a stance is active or not. virtual float getSpeed (const Ptr& ptr) const; ///< Return movement speed. @@ -179,6 +179,10 @@ namespace MWWorld virtual std::string getDownSoundId (const Ptr& ptr) const; ///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) + + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + /// (default implementation: return empty string) }; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 2800b6f3c..4f799f576 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -9,6 +9,7 @@ #include "manualref.hpp" #include "refdata.hpp" +#include "class.hpp" namespace { @@ -46,7 +47,22 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() void MWWorld::ContainerStore::add (const Ptr& ptr) { - /// \todo implement item stacking + // determine whether to stack or not + // item stacking depends on owner, script, enchantment and name + for (MWWorld::ContainerStoreIterator iter (begin(getType(ptr))); iter!=end(); ++iter) + { + if ( iter->mCellRef->refID == ptr.mCellRef->refID + && MWWorld::Class::get(*iter).getScript(*iter) == MWWorld::Class::get(ptr).getScript(ptr) + && MWWorld::Class::get(*iter).getEnchantment(*iter) == MWWorld::Class::get(ptr).getEnchantment(ptr) + && iter->mCellRef->owner == ptr.mCellRef->owner) + { + // stack + iter->getRefData().setCount( iter->getRefData().getCount() + ptr.getRefData().getCount() ); + + flagAsModified(); + return; + } + } switch (getType (ptr)) { From 9f2595183b039a29f3c79788a4048063041521d9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 16:30:27 +0200 Subject: [PATCH 2/5] type --- apps/openmw/mwworld/containerstore.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 4f799f576..32e2da0ae 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -47,9 +47,11 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() void MWWorld::ContainerStore::add (const Ptr& ptr) { + int type = getType(ptr); + // determine whether to stack or not // item stacking depends on owner, script, enchantment and name - for (MWWorld::ContainerStoreIterator iter (begin(getType(ptr))); iter!=end(); ++iter) + for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if ( iter->mCellRef->refID == ptr.mCellRef->refID && MWWorld::Class::get(*iter).getScript(*iter) == MWWorld::Class::get(ptr).getScript(ptr) @@ -64,7 +66,7 @@ void MWWorld::ContainerStore::add (const Ptr& ptr) } } - switch (getType (ptr)) + switch (type) { case Type_Potion: potions.list.push_back (*ptr.get()); break; case Type_Apparatus: appas.list.push_back (*ptr.get()); break; From 16522ddc59dfe697c3b4fe73f6b91beae96222bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 23:09:03 +0200 Subject: [PATCH 3/5] InventoryStore re-stacking unequipped items --- apps/openmw/mwworld/containerstore.cpp | 19 ++++++++++++++----- apps/openmw/mwworld/containerstore.hpp | 3 +++ apps/openmw/mwworld/inventorystore.cpp | 20 ++++++++++++++++++-- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 32e2da0ae..e28346de5 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -45,18 +45,27 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() return ContainerStoreIterator (this); } +bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const +{ + /// \todo add current weapon/armor health, remaining lockpick/repair uses, current enchantment charge here as soon as they are implemented + if ( ptr1.mCellRef->refID == ptr2.mCellRef->refID + && (MWWorld::Class::get(ptr1).getScript(ptr1) == "" && MWWorld::Class::get(ptr2).getScript(ptr2) == "") // item with a script never stacks + && ptr1.mCellRef->owner == ptr2.mCellRef->owner + && ptr1.mCellRef->soul == ptr2.mCellRef->soul + && ptr1.mCellRef->charge == ptr2.mCellRef->charge) + return true; + + return false; +} + void MWWorld::ContainerStore::add (const Ptr& ptr) { int type = getType(ptr); // determine whether to stack or not - // item stacking depends on owner, script, enchantment and name for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if ( iter->mCellRef->refID == ptr.mCellRef->refID - && MWWorld::Class::get(*iter).getScript(*iter) == MWWorld::Class::get(ptr).getScript(ptr) - && MWWorld::Class::get(*iter).getEnchantment(*iter) == MWWorld::Class::get(ptr).getEnchantment(ptr) - && iter->mCellRef->owner == ptr.mCellRef->owner) + if (stacks(*iter, ptr)) { // stack iter->getRefData().setCount( iter->getRefData().getCount() + ptr.getRefData().getCount() ); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index da5424fe0..2d330f6ea 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -66,6 +66,9 @@ namespace MWWorld ContainerStoreIterator end(); + bool stacks (const Ptr& ptr1, const Ptr& ptr2) const; + ///< @return true if the two specified objects can stack with each other + void add (const Ptr& ptr); ///< Add the item pointed to by \a ptr to this container. /// diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 576f2371f..f149513df 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -67,9 +67,25 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite throw std::runtime_error ("invalid slot"); } - /// \todo restack item previously in this slot (if required) + // restack item previously in this slot (if required) + if (mSlots[slot] != end()) + { + for (MWWorld::ContainerStoreIterator iter (begin()); iter!=end(); ++iter) + { + if (stacks(*iter, *mSlots[slot])) + { + iter->getRefData().setCount( iter->getRefData().getCount() + mSlots[slot]->getRefData().getCount() ); + mSlots[slot]->getRefData().setCount(0); + break; + } + } + } - /// \todo unstack item pointed to by iterator if required) + // unstack item pointed to by iterator if required + if (iterator->getRefData().getCount() > 1) + { + /// \ŧodo ??? + } mSlots[slot] = iterator; From ee7e482cba639a8c34b3b94e4433827032725a80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 11:52:17 +0200 Subject: [PATCH 4/5] implemented un-stacking --- apps/openmw/mwworld/containerstore.cpp | 8 +++++++- apps/openmw/mwworld/containerstore.hpp | 8 +++++++- apps/openmw/mwworld/inventorystore.cpp | 19 +++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index e28346de5..94df222d4 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -75,7 +75,13 @@ void MWWorld::ContainerStore::add (const Ptr& ptr) } } - switch (type) + // if we got here, this means no stacking + addImpl(ptr); +} + +void MWWorld::ContainerStore::addImpl (const Ptr& ptr) +{ + switch (getType(ptr)) { case Type_Potion: potions.list.push_back (*ptr.get()); break; case Type_Apparatus: appas.list.push_back (*ptr.get()); break; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 2d330f6ea..9b9d29c57 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -70,13 +70,19 @@ namespace MWWorld ///< @return true if the two specified objects can stack with each other void add (const Ptr& ptr); - ///< Add the item pointed to by \a ptr to this container. + ///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed) /// /// \note The item pointed to is not required to exist beyond this function call. /// /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! + protected: + void addImpl (const Ptr& ptr); + ///< Add the item to this container (no stacking) + + public: + void fill (const ESM::InventoryList& items, const ESMS::ESMStore& store); ///< Insert items into *this. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index f149513df..ea295e903 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -84,7 +84,11 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite // unstack item pointed to by iterator if required if (iterator->getRefData().getCount() > 1) { - /// \ŧodo ??? + // add the item again with a count of count-1, then set the count of the original (that will be equipped) to 1 + int count = iterator->getRefData().getCount(); + iterator->getRefData().setCount(count-1); + addImpl(*iterator); + iterator->getRefData().setCount(1); } mSlots[slot] = iterator; @@ -163,7 +167,18 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) } } - /// \todo unstack, if reqquired (itemsSlots.second) + 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) + { + // add the item again with a count of count-1, then set the count of the original (that will be equipped) to 1 + int count = iter->getRefData().getCount(); + iter->getRefData().setCount(count-1); + addImpl(*iter); + iter->getRefData().setCount(1); + } + } slots[*iter2] = iter; break; From d341d2113c8585093781f3c6975b3d7c3b1fabd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 14:58:38 +0200 Subject: [PATCH 5/5] fixed some issues --- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/containerstore.hpp | 7 ++++--- apps/openmw/mwworld/inventorystore.cpp | 22 ++++++++++++++++++++-- apps/openmw/mwworld/inventorystore.hpp | 7 +++++++ 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 94df222d4..dcddc333b 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -49,7 +49,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const { /// \todo add current weapon/armor health, remaining lockpick/repair uses, current enchantment charge here as soon as they are implemented if ( ptr1.mCellRef->refID == ptr2.mCellRef->refID - && (MWWorld::Class::get(ptr1).getScript(ptr1) == "" && MWWorld::Class::get(ptr2).getScript(ptr2) == "") // item with a script never stacks + && MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks && ptr1.mCellRef->owner == ptr2.mCellRef->owner && ptr1.mCellRef->soul == ptr2.mCellRef->soul && ptr1.mCellRef->charge == ptr2.mCellRef->charge) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 9b9d29c57..f0e9d7e4a 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -66,9 +66,6 @@ namespace MWWorld ContainerStoreIterator end(); - bool stacks (const Ptr& ptr1, const Ptr& ptr2) const; - ///< @return true if the two specified objects can stack with each other - void add (const Ptr& ptr); ///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed) /// @@ -81,6 +78,10 @@ namespace MWWorld void addImpl (const Ptr& ptr); ///< Add the item to this container (no stacking) + virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2) const; + ///< @return true if the two specified objects can stack with each other + /// @note ptr1 is the item that is already in this container + public: void fill (const ESM::InventoryList& items, const ESMS::ESMStore& store); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index ea295e903..6cf35ac64 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -59,9 +59,10 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite if (iterator.getContainerStore()!=this) throw std::runtime_error ("attempt to equip an item that is not in the inventory"); + std::pair, bool> slots; if (iterator!=end()) { - std::pair, bool> slots = Class::get (*iterator).getEquipmentSlots (*iterator); + slots = Class::get (*iterator).getEquipmentSlots (*iterator); if (std::find (slots.first.begin(), slots.first.end(), slot)==slots.first.end()) throw std::runtime_error ("invalid slot"); @@ -82,7 +83,7 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite } // unstack item pointed to by iterator if required - if (iterator->getRefData().getCount() > 1) + if (iterator!=end() && !slots.second && iterator->getRefData().getCount() > 1) // if slots.second is true, item can stay stacked when equipped { // add the item again with a count of count-1, then set the count of the original (that will be equipped) to 1 int count = iterator->getRefData().getCount(); @@ -199,3 +200,20 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) flagAsModified(); } } + +bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const +{ + bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2); + if (!canStack) + return false; + + // don't stack if the item being checked against is currently equipped. + for (TSlots::const_iterator iter (mSlots.begin()); + iter!=mSlots.end(); ++iter) + { + if (ptr1 == **iter) + return false; + } + + return true; +} diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 5eeaf570d..4162c7e2e 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -64,6 +64,13 @@ namespace MWWorld void autoEquip (const MWMechanics::NpcStats& stats); ///< Auto equip items according to stats and item value. + + protected: + + virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2) const; + ///< @return true if the two specified objects can stack with each other + /// @note ptr1 is the item that is already in this container + }; }