From 0375bedab229358b8fe04c29cd16d382623f4370 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 19:57:36 +0400 Subject: [PATCH 1/8] Equip previous item after a bound item expires (bug #2326) --- apps/openmw/mwmechanics/actors.cpp | 106 +++++++++++++++++++++++------ apps/openmw/mwmechanics/actors.hpp | 4 ++ 2 files changed, 91 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7990373a7..10e9b7afc 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -50,27 +50,36 @@ bool isConscious(const MWWorld::Ptr& ptr) return !stats.isDead() && !stats.getKnockedDown(); } -void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& actor) +int getBoundItemSlot (const std::string& itemId) { - if (bound) + static std::map boundItemsMap; + if (boundItemsMap.empty()) { - if (actor.getClass().getContainerStore(actor).count(item) == 0) - { - MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); - MWWorld::Ptr newPtr = *store.MWWorld::ContainerStore::add(item, 1, actor); - MWWorld::ActionEquip action(newPtr); - action.execute(actor); - MWWorld::ConstContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - // change draw state only if the item is in player's right hand - if (actor == MWMechanics::getPlayer() - && rightHand != store.end() && newPtr == *rightHand) - { - MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); - } - } + std::string boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundBootsID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Boots; + + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundCuirassID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Cuirass; + + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundLeftGauntletID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_LeftGauntlet; + + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundRightGauntletID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_RightGauntlet; + + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundHelmID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Helmet; + + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundShieldID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_CarriedLeft; } - else - actor.getClass().getInventoryStore(actor).remove(item, 1, actor, true); + + int slot = MWWorld::InventoryStore::Slot_CarriedRight; + std::map::iterator it = boundItemsMap.find(itemId); + if (it != boundItemsMap.end()) + slot = it->second; + + return slot; } class CheckActorCommanded : public MWMechanics::EffectSourceVisitor @@ -139,7 +148,6 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float namespace MWMechanics { - const float aiProcessingDistance = 7168; const float sqrAiProcessingDistance = aiProcessingDistance*aiProcessingDistance; @@ -227,6 +235,65 @@ namespace MWMechanics } }; + void Actors::adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor) + { + MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + + if (bound) + { + if (actor.getClass().getContainerStore(actor).count(itemId) != 0) + return; + + int slot = getBoundItemSlot(itemId); + + MWWorld::Ptr prevItem = *store.getSlot(slot); + + MWWorld::Ptr boundPtr = *store.MWWorld::ContainerStore::add(itemId, 1, actor); + MWWorld::ActionEquip action(boundPtr); + action.execute(actor); + + if (actor != MWMechanics::getPlayer()) + return; + + MWWorld::Ptr newItem = *store.getSlot(slot); + + if (newItem.isEmpty() || boundPtr != newItem) + return; + + // change draw state only if the item is in player's right hand + if (slot == MWWorld::InventoryStore::Slot_CarriedRight) + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + + mPreviousItems[slot] = std::make_pair(itemId, prevItem.isEmpty() ? "" : prevItem.getCellRef().getRefId()); + } + else + { + store.remove(itemId, 1, actor, true); + + if (actor != MWMechanics::getPlayer()) + return; + + int slot = getBoundItemSlot(itemId); + + std::pair prevItem = mPreviousItems[slot]; + + if (prevItem.first != itemId) + return; + + MWWorld::Ptr ptr = MWWorld::Ptr(); + if (prevItem.second != "") + ptr = store.search (prevItem.second); + + mPreviousItems.erase(slot); + + if (ptr.isEmpty()) + return; + + MWWorld::ActionEquip action(ptr); + action.execute(actor); + } + } + void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) { // magic effects @@ -1875,6 +1942,7 @@ namespace MWMechanics } mActors.clear(); mDeathCount.clear(); + mPreviousItems.clear(); } void Actors::updateMagicEffects(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 15f2d3dc8..f0e157db1 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,6 +25,10 @@ namespace MWMechanics class Actors { std::map mDeathCount; + typedef std::map> PreviousItems; + PreviousItems mPreviousItems; + + void adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor); void updateNpc(const MWWorld::Ptr &ptr, float duration); From 9b72a6ac69ddd4b282ff3c9ed46ca4d8b7cde44c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 27 Nov 2017 13:00:14 +0400 Subject: [PATCH 2/8] Use the MWWorld::Ptr() instead of string ID --- apps/openmw/mwmechanics/actors.cpp | 23 +++++++++++++++-------- apps/openmw/mwmechanics/actors.hpp | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 10e9b7afc..76c5744b3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -264,7 +264,7 @@ namespace MWMechanics if (slot == MWWorld::InventoryStore::Slot_CarriedRight) MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); - mPreviousItems[slot] = std::make_pair(itemId, prevItem.isEmpty() ? "" : prevItem.getCellRef().getRefId()); + mPreviousItems[slot] = std::make_pair(itemId, prevItem); } else { @@ -275,21 +275,28 @@ namespace MWMechanics int slot = getBoundItemSlot(itemId); - std::pair prevItem = mPreviousItems[slot]; + std::pair prevItem = mPreviousItems[slot]; if (prevItem.first != itemId) return; - MWWorld::Ptr ptr = MWWorld::Ptr(); - if (prevItem.second != "") - ptr = store.search (prevItem.second); - mPreviousItems.erase(slot); - if (ptr.isEmpty()) + if (prevItem.second.isEmpty()) + return; + + // check if the item is still in the player's inventory + MWWorld::ContainerStoreIterator it = store.begin(); + for (; it != store.end(); ++it) + { + if (*it == prevItem.second) + break; + } + + if (it == store.end()) return; - MWWorld::ActionEquip action(ptr); + MWWorld::ActionEquip action(prevItem.second); action.execute(actor); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index f0e157db1..40e9e1d21 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,7 +25,7 @@ namespace MWMechanics class Actors { std::map mDeathCount; - typedef std::map> PreviousItems; + typedef std::map> PreviousItems; PreviousItems mPreviousItems; void adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor); From d1b1cb748d94cda070c5383973329613620097d0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 24 Dec 2017 16:26:43 +0400 Subject: [PATCH 3/8] Reequip previous item only if the expired bound item was equipped --- apps/openmw/mwmechanics/actors.cpp | 41 +++++++++++++++--------------- apps/openmw/mwmechanics/actors.hpp | 2 +- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 76c5744b3..4019067e3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -238,15 +238,14 @@ namespace MWMechanics void Actors::adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor) { MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + int slot = getBoundItemSlot(itemId); if (bound) { if (actor.getClass().getContainerStore(actor).count(itemId) != 0) return; - int slot = getBoundItemSlot(itemId); - - MWWorld::Ptr prevItem = *store.getSlot(slot); + MWWorld::ContainerStoreIterator prevItem = store.getSlot(slot); MWWorld::Ptr boundPtr = *store.MWWorld::ContainerStore::add(itemId, 1, actor); MWWorld::ActionEquip action(boundPtr); @@ -264,39 +263,40 @@ namespace MWMechanics if (slot == MWWorld::InventoryStore::Slot_CarriedRight) MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); - mPreviousItems[slot] = std::make_pair(itemId, prevItem); + if (prevItem != store.end()) + mPreviousItems[itemId] = *prevItem; } else { + MWWorld::ContainerStoreIterator currentItem = store.getSlot(slot); + + bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual((*currentItem).getCellRef().getRefId(), itemId); + store.remove(itemId, 1, actor, true); if (actor != MWMechanics::getPlayer()) return; - int slot = getBoundItemSlot(itemId); + MWWorld::Ptr prevItem = mPreviousItems[itemId]; - std::pair prevItem = mPreviousItems[slot]; + mPreviousItems.erase(itemId); - if (prevItem.first != itemId) - return; - - mPreviousItems.erase(slot); - - if (prevItem.second.isEmpty()) + if (prevItem.isEmpty()) return; // check if the item is still in the player's inventory MWWorld::ContainerStoreIterator it = store.begin(); for (; it != store.end(); ++it) { - if (*it == prevItem.second) + if (*it == prevItem) break; } - if (it == store.end()) + // we should equip previous item only if expired bound item was equipped. + if (it == store.end() || !wasEquipped) return; - MWWorld::ActionEquip action(prevItem.second); + MWWorld::ActionEquip action(prevItem); action.execute(actor); } } @@ -830,9 +830,15 @@ namespace MWMechanics float magnitude = effects.get(it->first).getMagnitude(); if (found != (magnitude > 0)) { + if (magnitude > 0) + creatureStats.mBoundItems.insert(it->first); + else + creatureStats.mBoundItems.erase(it->first); + std::string itemGmst = it->second; std::string item = MWBase::Environment::get().getWorld()->getStore().get().find( itemGmst)->getString(); + if (it->first == ESM::MagicEffect::BoundGloves) { item = MWBase::Environment::get().getWorld()->getStore().get().find( @@ -844,11 +850,6 @@ namespace MWMechanics } else adjustBoundItem(item, magnitude > 0, ptr); - - if (magnitude > 0) - creatureStats.mBoundItems.insert(it->first); - else - creatureStats.mBoundItems.erase(it->first); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 40e9e1d21..e696abf01 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,7 +25,7 @@ namespace MWMechanics class Actors { std::map mDeathCount; - typedef std::map> PreviousItems; + typedef std::map PreviousItems; PreviousItems mPreviousItems; void adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor); From 4de9d9fa778402eff3de8c9e8d56b44132aaca80 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 24 Dec 2017 17:18:16 +0400 Subject: [PATCH 4/8] Split adjustBoundItem() --- apps/openmw/mwmechanics/actors.cpp | 96 +++++++++++++++--------------- apps/openmw/mwmechanics/actors.hpp | 3 +- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4019067e3..d1e74e576 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -235,70 +235,71 @@ namespace MWMechanics } }; - void Actors::adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor) + void Actors::addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor) { MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); int slot = getBoundItemSlot(itemId); - if (bound) - { - if (actor.getClass().getContainerStore(actor).count(itemId) != 0) - return; + if (actor.getClass().getContainerStore(actor).count(itemId) != 0) + return; - MWWorld::ContainerStoreIterator prevItem = store.getSlot(slot); + MWWorld::ContainerStoreIterator prevItem = store.getSlot(slot); - MWWorld::Ptr boundPtr = *store.MWWorld::ContainerStore::add(itemId, 1, actor); - MWWorld::ActionEquip action(boundPtr); - action.execute(actor); + MWWorld::Ptr boundPtr = *store.MWWorld::ContainerStore::add(itemId, 1, actor); + MWWorld::ActionEquip action(boundPtr); + action.execute(actor); - if (actor != MWMechanics::getPlayer()) - return; + if (actor != MWMechanics::getPlayer()) + return; - MWWorld::Ptr newItem = *store.getSlot(slot); + MWWorld::Ptr newItem = *store.getSlot(slot); - if (newItem.isEmpty() || boundPtr != newItem) - return; + if (newItem.isEmpty() || boundPtr != newItem) + return; - // change draw state only if the item is in player's right hand - if (slot == MWWorld::InventoryStore::Slot_CarriedRight) - MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + // change draw state only if the item is in player's right hand + if (slot == MWWorld::InventoryStore::Slot_CarriedRight) + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); - if (prevItem != store.end()) - mPreviousItems[itemId] = *prevItem; - } - else - { - MWWorld::ContainerStoreIterator currentItem = store.getSlot(slot); + if (prevItem != store.end()) + mPreviousItems[itemId] = *prevItem; + } - bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual((*currentItem).getCellRef().getRefId(), itemId); + void Actors::removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor) + { + MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + int slot = getBoundItemSlot(itemId); - store.remove(itemId, 1, actor, true); + MWWorld::ContainerStoreIterator currentItem = store.getSlot(slot); - if (actor != MWMechanics::getPlayer()) - return; + bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual((*currentItem).getCellRef().getRefId(), itemId); - MWWorld::Ptr prevItem = mPreviousItems[itemId]; + store.remove(itemId, 1, actor, true); - mPreviousItems.erase(itemId); + if (actor != MWMechanics::getPlayer()) + return; - if (prevItem.isEmpty()) - return; + MWWorld::Ptr prevItem = mPreviousItems[itemId]; - // check if the item is still in the player's inventory - MWWorld::ContainerStoreIterator it = store.begin(); - for (; it != store.end(); ++it) - { - if (*it == prevItem) - break; - } + mPreviousItems.erase(itemId); - // we should equip previous item only if expired bound item was equipped. - if (it == store.end() || !wasEquipped) - return; + if (prevItem.isEmpty()) + return; - MWWorld::ActionEquip action(prevItem); - action.execute(actor); + // check if the item is still in the player's inventory + MWWorld::ContainerStoreIterator it = store.begin(); + for (; it != store.end(); ++it) + { + if (*it == prevItem) + break; } + + // we should equip previous item only if expired bound item was equipped. + if (it == store.end() || !wasEquipped) + return; + + MWWorld::ActionEquip action(prevItem); + action.execute(actor); } void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) @@ -839,17 +840,14 @@ namespace MWMechanics std::string item = MWBase::Environment::get().getWorld()->getStore().get().find( itemGmst)->getString(); + magnitude > 0 ? addBoundItem(item, ptr) : removeBoundItem(item, ptr); + if (it->first == ESM::MagicEffect::BoundGloves) { - item = MWBase::Environment::get().getWorld()->getStore().get().find( - "sMagicBoundLeftGauntletID")->getString(); - adjustBoundItem(item, magnitude > 0, ptr); item = MWBase::Environment::get().getWorld()->getStore().get().find( "sMagicBoundRightGauntletID")->getString(); - adjustBoundItem(item, magnitude > 0, ptr); + magnitude > 0 ? addBoundItem(item, ptr) : removeBoundItem(item, ptr); } - else - adjustBoundItem(item, magnitude > 0, ptr); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index e696abf01..b3e1f95db 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -28,7 +28,8 @@ namespace MWMechanics typedef std::map PreviousItems; PreviousItems mPreviousItems; - void adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor); + void addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); + void removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); void updateNpc(const MWWorld::Ptr &ptr, float duration); From f977c6876ff391cc4624483647bf3197791482c5 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 23 Feb 2018 14:48:40 +0400 Subject: [PATCH 5/8] Bound items: store item ID instead of pointer --- apps/openmw/mwmechanics/actors.cpp | 28 ++++++++++++++++++---------- apps/openmw/mwmechanics/actors.hpp | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d1e74e576..8a13b492f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -262,7 +262,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); if (prevItem != store.end()) - mPreviousItems[itemId] = *prevItem; + mPreviousItems[itemId] = (*prevItem).getCellRef().getRefId(); } void Actors::removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor) @@ -279,26 +279,34 @@ namespace MWMechanics if (actor != MWMechanics::getPlayer()) return; - MWWorld::Ptr prevItem = mPreviousItems[itemId]; + std::string prevItemId = mPreviousItems[itemId]; mPreviousItems.erase(itemId); - if (prevItem.isEmpty()) + if (prevItemId.empty()) return; - // check if the item is still in the player's inventory - MWWorld::ContainerStoreIterator it = store.begin(); - for (; it != store.end(); ++it) + // Find the item by id + MWWorld::Ptr item; + for (MWWorld::ContainerStoreIterator iter = store.begin(); iter != store.end(); ++iter) { - if (*it == prevItem) - break; + 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; + } + } } // we should equip previous item only if expired bound item was equipped. - if (it == store.end() || !wasEquipped) + if (item.isEmpty() || !wasEquipped) return; - MWWorld::ActionEquip action(prevItem); + MWWorld::ActionEquip action(item); action.execute(actor); } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index b3e1f95db..90b646f0e 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,7 +25,7 @@ namespace MWMechanics class Actors { std::map mDeathCount; - typedef std::map PreviousItems; + typedef std::map PreviousItems; PreviousItems mPreviousItems; void addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); From 9fd2d57b8663dee2df8ca739f15d7b39b769b3a6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 9 Mar 2018 08:56:04 +0400 Subject: [PATCH 6/8] Move previous items to player --- apps/openmw/mwmechanics/actors.cpp | 14 ++++++++------ apps/openmw/mwmechanics/actors.hpp | 3 --- apps/openmw/mwworld/player.cpp | 16 ++++++++++++++++ apps/openmw/mwworld/player.hpp | 9 +++++++++ 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 8a13b492f..6549c169b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -262,7 +262,10 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); if (prevItem != store.end()) - mPreviousItems[itemId] = (*prevItem).getCellRef().getRefId(); + { + MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); + player->setPreviousItem(itemId, prevItem->getCellRef().getRefId()); + } } void Actors::removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor) @@ -272,16 +275,16 @@ namespace MWMechanics MWWorld::ContainerStoreIterator currentItem = store.getSlot(slot); - bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual((*currentItem).getCellRef().getRefId(), itemId); + bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual(currentItem->getCellRef().getRefId(), itemId); store.remove(itemId, 1, actor, true); if (actor != MWMechanics::getPlayer()) return; - std::string prevItemId = mPreviousItems[itemId]; - - mPreviousItems.erase(itemId); + MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); + std::string prevItemId = player->getPreviousItem(itemId); + player->erasePreviousItem(itemId); if (prevItemId.empty()) return; @@ -1956,7 +1959,6 @@ namespace MWMechanics } mActors.clear(); mDeathCount.clear(); - mPreviousItems.clear(); } void Actors::updateMagicEffects(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 90b646f0e..0de1f4d6c 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "../mwbase/world.hpp" @@ -25,8 +24,6 @@ namespace MWMechanics class Actors { std::map mDeathCount; - typedef std::map PreviousItems; - PreviousItems mPreviousItems; void addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); void removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 34c5f713d..193663098 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -287,6 +287,7 @@ namespace MWWorld mAttackingOrSpell = false; mCurrentCrimeId = -1; mPaidCrimeId = -1; + mPreviousItems.clear(); mLastKnownExteriorPosition = osg::Vec3f(0,0,0); for (int i=0; i + #include "../mwworld/refdata.hpp" #include "../mwworld/livecellref.hpp" @@ -46,6 +48,9 @@ namespace MWWorld int mCurrentCrimeId; // the id assigned witnesses int mPaidCrimeId; // the last id paid off (0 bounty) + typedef std::map PreviousItems; // previous equipped items, needed for bound spells + PreviousItems mPreviousItems; + // Saved stats prior to becoming a werewolf MWMechanics::SkillValue mSaveSkills[ESM::Skill::Length]; MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length]; @@ -120,6 +125,10 @@ namespace MWWorld int getNewCrimeId(); // get new id for witnesses void recordCrimeId(); // record the paid crime id when bounty is 0 int getCrimeId() const; // get the last paid crime id + + void setPreviousItem(const std::string& boundItemId, const std::string& previousItemId); + std::string getPreviousItem(const std::string& boundItemId); + void erasePreviousItem(const std::string& boundItemId); }; } #endif From acd3cba5fae441602389bd2dbef4579e8e70a842 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 9 Mar 2018 10:20:17 +0400 Subject: [PATCH 7/8] Store previous items in the savegame --- CHANGELOG.md | 1 + apps/openmw/mwworld/player.cpp | 4 ++++ components/esm/player.cpp | 18 ++++++++++++++++++ components/esm/player.hpp | 3 +++ components/esm/savedgame.cpp | 2 +- 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3101056e..a19b012c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 0.45.0 ------ + Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped Bug #2835: Player able to slowly move when overencumbered Bug #3374: Touch spells not hitting kwama foragers Bug #3591: Angled hit distance too low diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 193663098..5439447fd 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -342,6 +342,8 @@ namespace MWWorld for (int i=0; ifirst); + esm.writeHNString ("PREV", it->second); + } + for (int i=0; i mSaveAttributes[ESM::Attribute::Length]; StatState mSaveSkills[ESM::Skill::Length]; + typedef std::map PreviousItems; // previous equipped items, needed for bound spells + PreviousItems mPreviousItems; + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index c96261c64..ea9fef4fb 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -5,7 +5,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; -int ESM::SavedGame::sCurrentFormat = 4; +int ESM::SavedGame::sCurrentFormat = 5; void ESM::SavedGame::load (ESMReader &esm) { From 9c45cc7e48897171fc27c219bd1e7d9533b81ff9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 12 Jun 2018 22:05:00 +0400 Subject: [PATCH 8/8] Use player reference instead of pointer --- apps/openmw/mwmechanics/actors.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 6549c169b..de394c446 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -257,15 +257,14 @@ namespace MWMechanics if (newItem.isEmpty() || boundPtr != newItem) return; + MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); + // change draw state only if the item is in player's right hand if (slot == MWWorld::InventoryStore::Slot_CarriedRight) - MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + player.setDrawState(MWMechanics::DrawState_Weapon); if (prevItem != store.end()) - { - MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); - player->setPreviousItem(itemId, prevItem->getCellRef().getRefId()); - } + player.setPreviousItem(itemId, prevItem->getCellRef().getRefId()); } void Actors::removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor) @@ -282,9 +281,9 @@ namespace MWMechanics if (actor != MWMechanics::getPlayer()) return; - MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); - std::string prevItemId = player->getPreviousItem(itemId); - player->erasePreviousItem(itemId); + MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); + std::string prevItemId = player.getPreviousItem(itemId); + player.erasePreviousItem(itemId); if (prevItemId.empty()) return;