From 31e78ed41f54a93c2e1c57114cd65eb2f2e7e28d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 12 Oct 2019 14:00:36 +0400 Subject: [PATCH] Rework 'prevent merchant equipping' feature --- apps/openmw/mwmechanics/actors.cpp | 27 ++++++++++++++-- apps/openmw/mwworld/inventorystore.cpp | 44 ++++++++++++++------------ apps/openmw/mwworld/inventorystore.hpp | 3 +- 3 files changed, 51 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 49592c52e..4b6b1f4a7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -298,10 +298,31 @@ namespace MWMechanics bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual(currentItem->getCellRef().getRefId(), itemId); - store.remove(itemId, 1, actor, true); + store.remove(itemId, 1, actor); if (actor != MWMechanics::getPlayer()) + { + // Equip a replacement + if (!wasEquipped) + return; + + std::string type = currentItem->getTypeName(); + if (type != typeid(ESM::Weapon).name() && type != typeid(ESM::Armor).name() && type != typeid(ESM::Clothing).name()) + return; + + if (actor.getClass().getCreatureStats(actor).isDead()) + return; + + if (!actor.getClass().hasInventoryStore(actor) || !actor.getClass().getInventoryStore(actor).canActorAutoEquip(actor)) + return; + + if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) + return; + + actor.getClass().getInventoryStore(actor).autoEquip(actor); + return; + } MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); std::string prevItemId = player.getPreviousItem(itemId); @@ -1199,7 +1220,7 @@ namespace MWMechanics heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); // If we have a torch and can equip it, then equip it now. - if (heldIter == inventoryStore.end()) + if (heldIter == inventoryStore.end() && inventoryStore.canActorAutoEquip(ptr)) { inventoryStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, torch, ptr); } @@ -1808,6 +1829,8 @@ namespace MWMechanics // Make sure spell effects are removed purgeSpellEffects(stats.getActorId()); + calculateCreatureStatModifiers(iter->first, 0); + if( iter->first == getPlayer()) { //player's death animation is over diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index fbd7c49a4..d8c7e25bd 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -135,7 +135,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, { const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr); - // Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves + // Auto-equip items if an armor/clothing item is added, but not for the player nor werewolves if (actorPtr != MWMechanics::getPlayer() && actorPtr.getClass().isNpc() && !actorPtr.getClass().getNpcStats(actorPtr).isWerewolf()) { @@ -208,22 +208,29 @@ MWWorld::ConstContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) return findSlot (slot); } -bool MWWorld::InventoryStore::canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item) +bool MWWorld::InventoryStore::canActorAutoEquip(const MWWorld::Ptr& actor) { - if (!Settings::Manager::getBool("prevent merchant equipping", "Game")) + // Treat player as non-trader indifferently from service flags. + if (actor == MWMechanics::getPlayer()) return true; - // Only autoEquip if we are the original owner of the item. - // This stops merchants from auto equipping anything you sell to them. - // ...unless this is a companion, he should always equip items given to him. - if (!Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), actor.getCellRef().getRefId()) && - (actor.getClass().getScript(actor).empty() || - !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) - && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired - ) - { - return false; - } + static const bool prevent = Settings::Manager::getBool("prevent merchant equipping", "Game"); + if (!prevent) + return true; + + // Corpses can be dressed up by the player as desired. + if (actor.getClass().getCreatureStats(actor).isDead()) + return true; + + // Companions can autoequip items. + if (!actor.getClass().getScript(actor).empty() && + actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) + return true; + + // If the actor is trader, he can auto-equip items only during initial auto-equipping + int services = actor.getClass().getServices(actor); + if (services & ESM::NPC::AllItems) + return mFirstAutoEquip; return true; } @@ -325,9 +332,6 @@ void MWWorld::InventoryStore::autoEquipWeapon (const MWWorld::Ptr& actor, TSlots for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter!=end(); ++iter) { - if (!canActorAutoEquip(actor, *iter)) - continue; - const ESM::Weapon* esmWeapon = iter->get()->mBase; if (MWMechanics::getWeaponType(esmWeapon->mData.mType)->mWeaponClass == ESM::WeaponType::Ammo) @@ -429,9 +433,6 @@ void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots& { Ptr test = *iter; - if (!canActorAutoEquip(actor, test)) - continue; - switch(test.getClass().canBeEquipped (test, actor).first) { case 0: @@ -551,6 +552,9 @@ void MWWorld::InventoryStore::autoEquipShield(const MWWorld::Ptr& actor, TSlots& void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { + if (!canActorAutoEquip(actor)) + return; + TSlots slots_; initSlots (slots_); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 4261a49bf..faa829ef8 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -112,7 +112,6 @@ namespace MWWorld virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); - bool canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item); ContainerStoreIterator findSlot (int slot) const; public: @@ -161,6 +160,8 @@ namespace MWWorld void autoEquip (const MWWorld::Ptr& actor); ///< Auto equip items according to stats and item value. + bool canActorAutoEquip(const MWWorld::Ptr& actor); + const MWMechanics::MagicEffects& getMagicEffects() const; ///< Return magic effects from worn items.