MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) { int type = getType(ptr); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) if (MWWorld::Class::get(ptr).getName(ptr) == esmStore.get<ESM::GameSetting>().find("sGold")->getString()) { MWWorld::LiveCellRef<ESM::Miscellaneous> *gold = ptr.get<ESM::Miscellaneous>(); if (compare_string_ci(gold->mRef.mRefID, "gold_001") || compare_string_ci(gold->mRef.mRefID, "gold_005") || compare_string_ci(gold->mRef.mRefID, "gold_010") || compare_string_ci(gold->mRef.mRefID, "gold_025") || compare_string_ci(gold->mRef.mRefID, "gold_100")) { MWWorld::ManualRef ref(esmStore, "Gold_001"); int count = (ptr.getRefData().getCount() == 1) ? gold->mBase->mData.mValue : ptr.getRefData().getCount(); ref.getPtr().getRefData().setCount(count); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (compare_string_ci((*iter).get<ESM::Miscellaneous>()->mRef.mRefID, "gold_001")) { (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); flagAsModified(); return iter; } } return addImpl(ref.getPtr()); } } // determine whether to stack or not for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (stacks(*iter, ptr)) { // stack iter->getRefData().setCount( iter->getRefData().getCount() + ptr.getRefData().getCount() ); flagAsModified(); return iter; } } // if we got here, this means no stacking return addImpl(ptr); }
void MWWorld::ContainerStore::clear() { for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) iter->getRefData().setCount (0); flagAsModified(); }
void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& iterator, const Ptr& actor) { if (iterator == end()) throw std::runtime_error ("can't equip end() iterator, use unequip function instead"); if (slot<0 || slot>=static_cast<int> (mSlots.size())) throw std::runtime_error ("slot number out of range"); if (iterator.getContainerStore()!=this) throw std::runtime_error ("attempt to equip an item that is not in the inventory"); std::pair<std::vector<int>, bool> slots_; slots_ = iterator->getClass().getEquipmentSlots (*iterator); if (std::find (slots_.first.begin(), slots_.first.end(), slot)==slots_.first.end()) throw std::runtime_error ("invalid slot"); if (mSlots[slot] != end()) unequipSlot(slot, actor); // unstack item pointed to by iterator if required if (iterator!=end() && !slots_.second && iterator->getRefData().getCount() > 1) // if slots.second is true, item can stay stacked when equipped { unstack(*iterator, actor); } mSlots[slot] = iterator; flagAsModified(); fireEquipmentChangedEvent(actor); updateMagicEffects(actor); }
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const ConstPtr& ptr, int count) { ContainerStoreIterator it = begin(); switch (getType(ptr)) { case Type_Potion: potions.mList.push_back (*ptr.get<ESM::Potion>()); it = ContainerStoreIterator(this, --potions.mList.end()); break; case Type_Apparatus: appas.mList.push_back (*ptr.get<ESM::Apparatus>()); it = ContainerStoreIterator(this, --appas.mList.end()); break; case Type_Armor: armors.mList.push_back (*ptr.get<ESM::Armor>()); it = ContainerStoreIterator(this, --armors.mList.end()); break; case Type_Book: books.mList.push_back (*ptr.get<ESM::Book>()); it = ContainerStoreIterator(this, --books.mList.end()); break; case Type_Clothing: clothes.mList.push_back (*ptr.get<ESM::Clothing>()); it = ContainerStoreIterator(this, --clothes.mList.end()); break; case Type_Ingredient: ingreds.mList.push_back (*ptr.get<ESM::Ingredient>()); it = ContainerStoreIterator(this, --ingreds.mList.end()); break; case Type_Light: lights.mList.push_back (*ptr.get<ESM::Light>()); it = ContainerStoreIterator(this, --lights.mList.end()); break; case Type_Lockpick: lockpicks.mList.push_back (*ptr.get<ESM::Lockpick>()); it = ContainerStoreIterator(this, --lockpicks.mList.end()); break; case Type_Miscellaneous: miscItems.mList.push_back (*ptr.get<ESM::Miscellaneous>()); it = ContainerStoreIterator(this, --miscItems.mList.end()); break; case Type_Probe: probes.mList.push_back (*ptr.get<ESM::Probe>()); it = ContainerStoreIterator(this, --probes.mList.end()); break; case Type_Repair: repairs.mList.push_back (*ptr.get<ESM::Repair>()); it = ContainerStoreIterator(this, --repairs.mList.end()); break; case Type_Weapon: weapons.mList.push_back (*ptr.get<ESM::Weapon>()); it = ContainerStoreIterator(this, --weapons.mList.end()); break; } it->getRefData().setCount(count); flagAsModified(); return it; }
int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor) { assert(this == item.getContainerStore()); int toRemove = count; RefData& itemRef = item.getRefData(); if (itemRef.getCount() <= toRemove) { toRemove -= itemRef.getCount(); itemRef.setCount(0); } else { itemRef.setCount(itemRef.getCount() - toRemove); toRemove = 0; } flagAsModified(); if (mListener) mListener->itemRemoved(item, count - toRemove); // number of removed items return count - toRemove; }
void CSVRender::PreviewWidget::ReferenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { if (mReferenceId.empty()) return; CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); int columnIndex = references.findColumnIndex (CSMWorld::Columns::ColumnId_ReferenceableId); QModelIndex index = references.getModelIndex (mReferenceId, columnIndex); if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) { /// \todo possible optimisation; check columns and only update if relevant columns have /// changed adjust(); if (index.column()>=topLeft.column() && index.column()<=bottomRight.row()) { mReferenceableId = references.data (index).toString().toUtf8().constData(); emit referenceableIdChanged (mReferenceableId); setModel(); } flagAsModified(); } }
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { 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. // Note: creatures do not use the armor mitigation and can equip only shields // Use a custom logic for them - select shield based on its health instead of armor rating (since it useless for creatures) autoEquipWeapon(actor, slots_); autoEquipArmor(actor, slots_); 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 CSVRender::UnpagedWorldspaceWidget::referenceAdded (const QModelIndex& parent, int start, int end) { if (mCell.get()) if (mCell.get()->referenceAdded (parent, start, end)) flagAsModified(); }
void CSVRender::PreviewWidget::ReferenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end) { if (mReferenceableId.empty()) return; CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> ( *mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables)); QModelIndex index = referenceables.getModelIndex (mReferenceableId, 0); if (index.row()>=start && index.row()<=end) { if (mReferenceId.empty()) { // this is a preview for a referenceble emit closeRequest(); } else { // this is a preview for a reference mObject.setNull(); flagAsModified(); } } }
void CSVRender::UnpagedWorldspaceWidget::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { if (mCell.get()) if (mCell.get()->referenceDataChanged (topLeft, bottomRight)) flagAsModified(); }
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, int count) { int type = getType(ptr); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) if(ptr.getClass().isGold(ptr)) { int realCount = count * ptr.getClass().getValue(ptr); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (Misc::StringUtils::ciEqual((*iter).getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) { iter->getRefData().setCount(iter->getRefData().getCount() + realCount); flagAsModified(); return iter; } } MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, realCount); return addNewStack(ref.getPtr(), realCount); } // determine whether to stack or not for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (stacks(*iter, ptr)) { // stack iter->getRefData().setCount( iter->getRefData().getCount() + count ); flagAsModified(); return iter; } } // if we got here, this means no stacking return addNewStack(ptr, count); }
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const MWWorld::ESMStore& store) { for (std::vector<ESM::ContItem>::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { std::string id = iter->mItem.toString(); addInitialItem(id, owner, iter->mCount); } flagAsModified(); }
void CSVRender::UnpagedWorldspaceWidget::update() { const CSMWorld::Record<CSMWorld::Cell>& record = dynamic_cast<const CSMWorld::Record<CSMWorld::Cell>&> (mCellsModel->getRecord (mCellId)); osg::Vec4f colour = SceneUtil::colourFromRGB(record.get().mAmbi.mAmbient); setDefaultAmbient (colour); /// \todo deal with mSunlight and mFog/mForDensity flagAsModified(); }
void CSVRender::UnpagedWorldspaceWidget::referenceableAdded (const QModelIndex& parent, int start, int end) { if (mCell.get()) { QModelIndex topLeft = mReferenceablesModel->index (start, 0); QModelIndex bottomRight = mReferenceablesModel->index (end, mReferenceablesModel->columnCount()); if (mCell.get()->referenceableDataChanged (topLeft, bottomRight)) flagAsModified(); } }
int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor) { int toRemove = count; for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) toRemove -= remove(*iter, toRemove, actor); flagAsModified(); // number of removed items return count - toRemove; }
void SceneWidget::setLighting(Lighting *lighting) { if (mLighting) mLighting->deactivate(); mLighting = lighting; mLighting->activate (mRootNode); osg::Vec4f ambient = mLighting->getAmbientColour(mHasDefaultAmbient ? &mDefaultAmbient : 0); setAmbient(ambient); flagAsModified(); }
void CSVRender::PreviewWidget::ReferenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { if (mReferenceableId.empty()) return; CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> ( *mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables)); QModelIndex index = referenceables.getModelIndex (mReferenceableId, 0); if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) { /// \todo possible optimisation; check columns and only update if relevant columns have /// changed setModel(); flagAsModified(); } }
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS::ESMStore& store) { for (std::vector<ESM::ContItem>::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { ManualRef ref (store, iter->mItem.toString()); if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { /// \todo implement leveled item lists continue; } ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count) add (ref.getPtr()); } flagAsModified(); }
void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& iterator) { if (slot<0 || slot>=static_cast<int> (mSlots.size())) throw std::runtime_error ("slot number out of range"); if (iterator.getContainerStore()!=this) throw std::runtime_error ("attempt to equip an item that is not in the inventory"); if (iterator!=end()) { std::pair<std::vector<int>, bool> slots = Class::get (*iterator).getEquipmentSlots (*iterator); if (std::find (slots.first.begin(), slots.first.end(), slot)==slots.first.end()) throw std::runtime_error ("invalid slot"); } /// \todo restack item previously in this slot (if required) /// \todo unstack item pointed to by iterator if required) mSlots[slot] = iterator; flagAsModified(); }
void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) { TSlots slots; initSlots (slots); for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) { Ptr test = *iter; int testSkill = MWWorld::Class::get (test).getEquipmentSkill (test); std::pair<std::vector<int>, bool> itemsSlots = MWWorld::Class::get (*iter).getEquipmentSlots (*iter); for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { bool use = false; if (slots.at (*iter2)==end()) use = true; // slot was empty before -> skill all further checks else { Ptr old = *slots.at (*iter2); if (!use) { // check skill int oldSkill = MWWorld::Class::get (old).getEquipmentSkill (old); if (testSkill!=-1 || oldSkill!=-1 || testSkill!=oldSkill) { if (stats.mSkill[oldSkill].getModified()>stats.mSkill[testSkill].getModified()) continue; // rejected, because old item better matched the NPC's skills. if (stats.mSkill[oldSkill].getModified()<stats.mSkill[testSkill].getModified()) use = true; } } if (!use) { // check value if (MWWorld::Class::get (old).getValue (old)>= MWWorld::Class::get (test).getValue (test)) { continue; } use = true; } } /// \todo unstack, if reqquired (itemsSlots.second) slots[*iter2] = iter; break; } } bool changed = false; for (std::size_t i=0; i<slots.size(); ++i) if (slots[i]!=mSlots[i]) { changed = true; } if (changed) { mSlots.swap (slots); flagAsModified(); } }
void CSVRender::UnpagedWorldspaceWidget::clearSelection (int elementMask) { mCell->setSelection (elementMask, Cell::Selection_Clear); flagAsModified(); }
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 CSVRender::WorldspaceWidget::elementSelectionChanged() { setVisibilityMask (getVisibilityMask()); flagAsModified(); updateOverlay(); }
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; } // Don't auto-equip probes or lockpicks. NPCs can't use them (yet). And AiCombat would attempt to "attack" with them. // NOTE: In the future AiCombat should handle equipping appropriate weapons if (test.getTypeName() == typeid(ESM::Lockpick).name() || test.getTypeName() == typeid(ESM::Probe).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"))) 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) { bool use = false; if (slots_.at (*iter2)==end()) use = true; // slot was empty before -> skip all further checks else { Ptr old = *slots_.at (*iter2); if (!use) { // check skill int oldSkill = old.getClass().getEquipmentSkill (old); 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; } use = true; } } switch(test.getClass().canBeEquipped (test, actor).first) { case 0: continue; case 2: slots_[MWWorld::InventoryStore::Slot_CarriedLeft] = end(); break; case 3: // Prefer keeping twohanded weapon 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; } mUpdatesEnabled = true; if (changed) { mSlots.swap (slots_); fireEquipmentChangedEvent(); updateMagicEffects(actor); flagAsModified(); } }
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) { //allowedForReplace - Holds information about how many items from the list were not sold; // Hence, tells us how many items we don't need to restock. //allowedForReplace[list] <- How many items we should generate(how many of these were sold) std::map<std::string, int> allowedForReplace; //Check which lists need restocking: for (std::map<std::pair<std::string, std::string>, int>::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end();) { int spawnedCount = it->second; //How many items should be in shop originally int itemCount = restockCount(it->first.first); //How many items are there in shop now //If something was not sold if(itemCount >= spawnedCount) { const std::string& parent = it->first.second; // Security check for old saves: //If item is imported from old save(doesn't have an parent) and wasn't sold if(parent == "") { //Remove it, from shop, remove(it->first.first, itemCount, ptr);//ptr is the NPC //And remove it from map, so that when we restock, the new item will have proper parent. mLevelledItemMap.erase(it++); continue; } //Create the entry if it does not exist yet std::map<std::string, int>::iterator listInMap = allowedForReplace.insert( std::make_pair(it->first.second, 0)).first; //And signal that we don't need to restock item from this list listInMap->second += std::abs(itemCount); } //If every of the item was sold else if (itemCount == 0) { mLevelledItemMap.erase(it++); continue; } //If some was sold, but some remain else { //Create entry if it does not exist yet std::map<std::string, int>::iterator listInMap = allowedForReplace.insert( std::make_pair(it->first.second, 0)).first; //And signal that we don't need to restock all items from this list listInMap->second += std::abs(itemCount); //And update itemCount so we don't mistake it next time. it->second = itemCount; } ++it; } //Restock: //For every item that NPC could have for (std::vector<ESM::ContItem>::const_iterator it = items.mList.begin(); it != items.mList.end(); ++it) { //If he shouldn't have it restocked, don't restock it. if (it->mCount >= 0) continue; std::string itemOrList = Misc::StringUtils::lowerCase(it->mItem.toString()); //If it's levelled list, restock if there's need to do so. if (MWBase::Environment::get().getWorld()->getStore().get<ESM::ItemLevList>().search(it->mItem.toString())) { std::map<std::string, int>::iterator listInMap = allowedForReplace.find(itemOrList); int restockNum = std::abs(it->mCount); //If we know we must restock less, take it into account if(listInMap != allowedForReplace.end()) restockNum -= std::min(restockNum, listInMap->second); //restock addInitialItem(itemOrList, owner, -restockNum, true); } else { //Restocking static item - just restock to the max count int currentCount = restockCount(itemOrList); if (currentCount < std::abs(it->mCount)) addInitialItem(itemOrList, owner, -(std::abs(it->mCount) - currentCount), true); } } 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(); } }