From 1d3008594d934b1ce8dd42991ead94240574d8d1 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 18 Oct 2016 13:57:35 +0200 Subject: [PATCH 1/2] Autoequip weapons (Fixes #3562) --- apps/openmw/mwworld/inventorystore.cpp | 96 +++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 25b9cbf08..6620a991e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -236,9 +236,9 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // Disable model update during auto-equip mUpdatesEnabled = false; - // Relevant are only clothing and armor items: - // - Equipping lights is handled in Actors::updateEquippedLight based on environment light. - // - Equipping weapons is handled by AiCombat. + // Autoequip clothing, armor and weapons. + // Equipping lights is handled in Actors::updateEquippedLight based on environment light. + for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter) { Ptr test = *iter; @@ -318,6 +318,96 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) } } + static const ESM::Skill::SkillEnum weaponSkills[] = + { + ESM::Skill::LongBlade, + ESM::Skill::Axe, + ESM::Skill::Spear, + ESM::Skill::ShortBlade, + ESM::Skill::Marksman, + ESM::Skill::BluntWeapon + }; + const size_t weaponSkillsLength = sizeof(weaponSkills) / sizeof(weaponSkills[0]); + + bool weaponSkillVisited[weaponSkillsLength] = { false }; + + for (int i = 0; i < static_cast(weaponSkillsLength) - 1; ++i) + { + int max = 0; + int maxWeaponSkill = -1; + + for (int j = 0; j < static_cast(weaponSkillsLength) - 1; ++j) + { + int skillValue = stats.getSkill(static_cast(weaponSkills[j])).getModified(); + + if (skillValue > max && !weaponSkillVisited[j]) + { + max = skillValue; + maxWeaponSkill = j; + } + } + + if (maxWeaponSkill == -1) + break; + + max = 0; + ContainerStoreIterator weapon(end()); + + for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter!=end(); ++iter) + { + const ESM::Weapon* esmWeapon = iter->get()->mBase; + + if (esmWeapon->mData.mType == ESM::Weapon::Arrow || esmWeapon->mData.mType == ESM::Weapon::Bolt) + continue; + + if (iter->getClass().getEquipmentSkill(*iter) == weaponSkills[maxWeaponSkill]) + { + if (esmWeapon->mData.mChop[1] >= max) + { + max = esmWeapon->mData.mChop[1]; + weapon = iter; + } + + if (esmWeapon->mData.mSlash[1] >= max) + { + max = esmWeapon->mData.mSlash[1]; + weapon = iter; + } + + if (esmWeapon->mData.mThrust[1] >= max) + { + max = esmWeapon->mData.mThrust[1]; + weapon = iter; + } + } + } + + if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, actor).first) + { + std::pair, bool> itemsSlots = + weapon->getClass().getEquipmentSlots (*weapon); + + for (std::vector::const_iterator slot (itemsSlots.first.begin()); + slot!=itemsSlots.first.end(); ++slot) + { + if (!itemsSlots.second) + { + if (weapon->getRefData().getCount() > 1) + { + unstack(*weapon, actor); + } + } + + slots_[*slot] = weapon; + break; + } + + break; + } + + weaponSkillVisited[maxWeaponSkill] = true; + } + bool changed = false; for (std::size_t i=0; i Date: Tue, 18 Oct 2016 14:03:11 +0200 Subject: [PATCH 2/2] Add a setting for merchant auto-equipping prevention --- apps/openmw/mwworld/inventorystore.cpp | 35 ++++++++++++++++++-------- apps/openmw/mwworld/inventorystore.hpp | 2 ++ files/settings-default.cfg | 3 +++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6620a991e..cf2a88c1d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -214,6 +215,26 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) return mSlots[slot]; } +bool MWWorld::InventoryStore::canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item) +{ + if (!Settings::Manager::getBool("prevent merchant equipping", "Game")) + 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; + } + + return true; +} + void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { if (!actor.getClass().isNpc()) @@ -243,17 +264,8 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { Ptr test = *iter; - // 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(test.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 - ) - { + if (!canActorAutoEquip(actor, test)) continue; - } switch(test.getClass().canBeEquipped (test, actor).first) { @@ -355,6 +367,9 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter!=end(); ++iter) { + if (!canActorAutoEquip(actor, *iter)) + continue; + const ESM::Weapon* esmWeapon = iter->get()->mBase; if (esmWeapon->mData.mType == ESM::Weapon::Arrow || esmWeapon->mData.mType == ESM::Weapon::Bolt) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9e0a8d5b6..7e6a259c4 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -115,6 +115,8 @@ 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); + public: InventoryStore(); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 3d2cd49bf..9813cb166 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -145,6 +145,9 @@ difficulty = 0 # Show duration of magic effect and lights in the spells window. show effect duration = false +# Prevents merchants from equipping items that are sold to them. +prevent merchant equipping = false + [General] # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16).