void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots& slots_) { // Only NPCs can wear armor for now. // For creatures we equip only shields. if (!actor.getClass().isNpc()) { autoEquipShield(actor, slots_); return; } const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>(); static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); int unarmoredSkill = actor.getClass().getSkill(actor, ESM::Skill::Unarmored); float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter) { Ptr test = *iter; if (!canActorAutoEquip(actor, test)) continue; switch(test.getClass().canBeEquipped (test, actor).first) { case 0: continue; default: break; } if (iter.getType() == ContainerStore::Type_Armor && test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f)) { continue; } std::pair<std::vector<int>, bool> itemsSlots = iter->getClass().getEquipmentSlots (*iter); // checking if current item pointed by iter can be equipped for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { // if true then it means slot is equipped already // check if slot may require swapping if current item is more valuable if (slots_.at (*iter2)!=end()) { Ptr old = *slots_.at (*iter2); if (iter.getType() == ContainerStore::Type_Armor) { if (old.getTypeName() == typeid(ESM::Armor).name()) { if (old.get<ESM::Armor>()->mBase->mData.mType < test.get<ESM::Armor>()->mBase->mData.mType) continue; if (old.get<ESM::Armor>()->mBase->mData.mType == test.get<ESM::Armor>()->mBase->mData.mType) { if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor)) // old armor had better armor rating continue; } } // suitable armor should replace already equipped clothing } else if (iter.getType() == ContainerStore::Type_Clothing) { // if left ring is equipped if (*iter2 == Slot_LeftRing) { // if there is a place for right ring dont swap it if (slots_.at(Slot_RightRing) == end()) { continue; } else // if right ring is equipped too { Ptr rightRing = *slots_.at(Slot_RightRing); // we want to swap cheaper ring only if both are equipped if (old.getClass().getValue (old) >= rightRing.getClass().getValue (rightRing)) continue; } } if (old.getTypeName() == typeid(ESM::Clothing).name()) { // check value if (old.getClass().getValue (old) >= test.getClass().getValue (test)) // old clothing was more valuable continue; } else // suitable clothing should NOT replace already equipped armor continue; } } 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) { unstack(*iter, actor); } } // if we are here it means item can be equipped or swapped slots_[*iter2] = iter; break; } } }
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { TSlots slots_; initSlots (slots_); // Disable model update during auto-equip mUpdatesEnabled = false; for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) { Ptr test = *iter; // Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light. if (test.getTypeName() == typeid(ESM::Light).name()) { continue; } // 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 ) { continue; } int testSkill = test.getClass().getEquipmentSkill (test); std::pair<std::vector<int>, bool> itemsSlots = iter->getClass().getEquipmentSlots (*iter); for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { if (*iter2 == Slot_CarriedRight) // Items in right hand are situational use, so don't equip them. // Equipping weapons is handled by AiCombat. Anything else (lockpicks, probes) can't be used by NPCs anyway (yet) continue; if (iter.getType() == MWWorld::ContainerStore::Type_Weapon) continue; if (slots_.at (*iter2)!=end()) { Ptr old = *slots_.at (*iter2); // check skill int oldSkill = old.getClass().getEquipmentSkill (old); bool use = false; if (testSkill!=-1 && oldSkill==-1) use = true; else if (testSkill!=-1 && oldSkill!=-1 && testSkill!=oldSkill) { if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill)) continue; // rejected, because old item better matched the NPC's skills. if (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill)) use = true; } if (!use) { // check value if (old.getClass().getValue (old)>= test.getClass().getValue (test)) { continue; } } } switch(test.getClass().canBeEquipped (test, actor).first) { case 0: continue; default: break; } 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) { unstack(*iter, actor); } } slots_[*iter2] = iter; break; } } bool changed = false; for (std::size_t i=0; i<slots_.size(); ++i) { if (slots_[i] != mSlots[i]) { changed = true; break; } } mUpdatesEnabled = true; if (changed) { mSlots.swap (slots_); fireEquipmentChangedEvent(actor); updateMagicEffects(actor); flagAsModified(); } }
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>(); MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor); static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); TSlots slots_; initSlots (slots_); // Disable model update during auto-equip mUpdatesEnabled = false; // 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; if (!canActorAutoEquip(actor, test)) continue; switch(test.getClass().canBeEquipped (test, actor).first) { case 0: continue; default: break; } if (iter.getType() == ContainerStore::Type_Armor && test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f)) { continue; } std::pair<std::vector<int>, bool> itemsSlots = iter->getClass().getEquipmentSlots (*iter); // checking if current item poited by iter can be equipped for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { // if true then it means slot is equipped already // check if slot may require swapping if current item is more valueable if (slots_.at (*iter2)!=end()) { Ptr old = *slots_.at (*iter2); if (iter.getType() == ContainerStore::Type_Armor) { if (old.getTypeName() == typeid(ESM::Armor).name()) { if (old.get<ESM::Armor>()->mBase->mData.mType < test.get<ESM::Armor>()->mBase->mData.mType) continue; if (old.get<ESM::Armor>()->mBase->mData.mType == test.get<ESM::Armor>()->mBase->mData.mType) { if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor)) // old armor had better armor rating continue; } } // suitable armor should replace already equipped clothing } else if (iter.getType() == ContainerStore::Type_Clothing) { // if left ring is equipped if (*iter2 == Slot_LeftRing) { // if there is a place for right ring dont swap it if (slots_.at(Slot_RightRing) == end()) { continue; } else // if right ring is equipped too { Ptr rightRing = *slots_.at(Slot_RightRing); // we want to swap cheaper ring only if both are equipped if (old.getClass().getValue (old) >= rightRing.getClass().getValue (rightRing)) continue; } } if (old.getTypeName() == typeid(ESM::Clothing).name()) { // check value if (old.getClass().getValue (old) >= test.getClass().getValue (test)) // old clothing was more valuable continue; } else // suitable clothing should NOT replace already equipped armor continue; } } 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) { unstack(*iter, actor); } } // if we are here it means item can be equipped or swapped slots_[*iter2] = iter; break; } } 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<int>(weaponSkillsLength); ++i) { int max = 0; int maxWeaponSkill = -1; for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j) { int skillValue = stats.getSkill(static_cast<int>(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) { if (!canActorAutoEquip(actor, *iter)) continue; const ESM::Weapon* esmWeapon = iter->get<ESM::Weapon>()->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<std::vector<int>, bool> itemsSlots = weapon->getClass().getEquipmentSlots (*weapon); if (!itemsSlots.first.empty()) { if (!itemsSlots.second) { if (weapon->getRefData().getCount() > 1) { unstack(*weapon, actor); } } int slot = itemsSlots.first.front(); slots_[slot] = weapon; } break; } weaponSkillVisited[maxWeaponSkill] = true; } bool changed = false; for (std::size_t i=0; i<slots_.size(); ++i) { if (slots_[i] != mSlots[i]) { changed = true; break; } } mUpdatesEnabled = true; if (changed) { mSlots.swap (slots_); fireEquipmentChangedEvent(actor); updateMagicEffects(actor); flagAsModified(); } }