From 61c968d5507670f9e3fce874e8abd48f0c819a85 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Jun 2018 12:56:58 +0400 Subject: [PATCH] Ignore broken items when search for replacement (bug #4453) --- apps/openmw/mwgui/quickkeysmenu.cpp | 88 ++++++++++++++++---------- apps/openmw/mwgui/quickkeysmenu.hpp | 1 + apps/openmw/mwmechanics/actors.cpp | 18 +----- apps/openmw/mwworld/containerstore.cpp | 24 +++++++ apps/openmw/mwworld/containerstore.hpp | 3 + 5 files changed, 85 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 2ce9d04e5..08192625f 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -81,6 +81,47 @@ namespace MWGui delete mMagicSelectionDialog; } + void QuickKeysMenu::onOpen() + { + WindowBase::onOpen(); + + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + + // Check if quick keys are still valid + for (int i=0; i<10; ++i) + { + ItemWidget* button = mQuickKeyButtons[i]; + int type = mAssigned[i]; + + switch (type) + { + case Type_Unassigned: + case Type_HandToHand: + case Type_Magic: + break; + case Type_Item: + case Type_MagicItem: + { + MWWorld::Ptr item = *button->getUserData(); + // Make sure the item is available and is not broken + if (item.getRefData().getCount() < 1 || + (item.getClass().hasItemHealth(item) && + item.getClass().getItemHealth(item) <= 0)) + { + // Try searching for a compatible replacement + std::string id = item.getCellRef().getRefId(); + + item = store.findReplacement(id); + button->setUserData(MWWorld::Ptr(item)); + break; + } + } + } + } + + } + void QuickKeysMenu::unassign(ItemWidget* key, int index) { key->clearUserStrings(); @@ -122,12 +163,10 @@ namespace MWGui assert(index != -1); mSelectedIndex = index; - { - // open assign dialog - if (!mAssignDialog) - mAssignDialog = new QuickKeysMenuAssign(this); - mAssignDialog->setVisible (true); - } + // open assign dialog + if (!mAssignDialog) + mAssignDialog = new QuickKeysMenuAssign(this); + mAssignDialog->setVisible (true); } void QuickKeysMenu::onOkButtonClicked (MyGUI::Widget *sender) @@ -296,21 +335,16 @@ namespace MWGui if (type == Type_Item || type == Type_MagicItem) { MWWorld::Ptr item = *button->getUserData(); - // make sure the item is available - if (item.getRefData ().getCount() < 1) + // Make sure the item is available and is not broken + if (item.getRefData().getCount() < 1 || + (item.getClass().hasItemHealth(item) && + item.getClass().getItemHealth(item) <= 0)) { // Try searching for a compatible replacement std::string id = item.getCellRef().getRefId(); - for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) - { - if (Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), id)) - { - item = *it; - button->setUserData(MWWorld::Ptr(item)); - break; - } - } + item = store.findReplacement(id); + button->setUserData(MWWorld::Ptr(item)); if (item.getRefData().getCount() < 1) { @@ -498,6 +532,9 @@ namespace MWGui ESM::QuickKeys keys; keys.load(reader); + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + int i=0; for (std::vector::const_iterator it = keys.mKeys.begin(); it != keys.mKeys.end(); ++it) { @@ -519,22 +556,7 @@ namespace MWGui case Type_MagicItem: { // Find the item by id - MWWorld::Ptr player = MWMechanics::getPlayer(); - MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); - MWWorld::Ptr item; - for (MWWorld::ContainerStoreIterator iter = store.begin(); iter != store.end(); ++iter) - { - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) - { - if (item.isEmpty() || - // Prefer the stack with the lowest remaining uses - !item.getClass().hasItemHealth(*iter) || - iter->getClass().getItemHealth(*iter) < item.getClass().getItemHealth(item)) - { - item = *iter; - } - } - } + MWWorld::Ptr item = store.findReplacement(id); if (item.isEmpty()) unassign(button, i); diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 0070aa55b..b5bc60b19 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -34,6 +34,7 @@ namespace MWGui void onAssignMagicItem (MWWorld::Ptr item); void onAssignMagic (const std::string& spellId); void onAssignMagicCancel (); + void onOpen(); void activateQuickKey(int index); void updateActivatedQuickKey(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index de394c446..f1bc6907c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -288,23 +288,9 @@ namespace MWMechanics if (prevItemId.empty()) return; - // Find the item by id - MWWorld::Ptr item; - for (MWWorld::ContainerStoreIterator iter = store.begin(); iter != store.end(); ++iter) - { - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), prevItemId)) - { - if (item.isEmpty() || - // Prefer the stack with the lowest remaining uses - !item.getClass().hasItemHealth(*iter) || - iter->getClass().getItemHealth(*iter) < item.getClass().getItemHealth(item)) - { - item = *iter; - } - } - } - + // Find previous item (or its replacement) by id. // we should equip previous item only if expired bound item was equipped. + MWWorld::Ptr item = store.findReplacement(prevItemId); if (item.isEmpty() || !wasEquipped) return; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index dd5d7a853..c92d51701 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -675,6 +675,30 @@ int MWWorld::ContainerStore::getType (const ConstPtr& ptr) "Object '" + ptr.getCellRef().getRefId() + "' of type " + ptr.getTypeName() + " can not be placed into a container"); } +MWWorld::Ptr MWWorld::ContainerStore::findReplacement(const std::string& id) +{ + MWWorld::Ptr item; + int itemHealth = 1; + for (MWWorld::ContainerStoreIterator iter = begin(); iter != end(); ++iter) + { + 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)) + { + item = *iter; + itemHealth = iterHealth; + } + } + } + + return item; +} + MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) { { diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index dbb82cbda..b67eb6552 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -198,6 +198,9 @@ namespace MWWorld ///< This function throws an exception, if ptr does not point to an object, that can be /// put into a container. + Ptr findReplacement(const std::string& id); + ///< Returns replacement for object with given id. Prefer used items (with low durability left). + Ptr search (const std::string& id); virtual void writeState (ESM::InventoryState& state) const;