diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index ec0614a664..b73aafb79c 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -93,7 +93,7 @@ namespace MWGui for (int day = 0; day < mDays; ++day) { auto& prng = MWBase::Environment::get().getWorld()->getPrng(); - const ESM::Skill* skill = skillStore.find(Misc::Rng::rollDice(ESM::Skill::Length, prng)); + const ESM::Skill* skill = skillStore.searchRandom({}, prng); skills.insert(skill); MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill->mIndex); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 7b0e93edd0..e9184978fa 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -21,24 +21,6 @@ #include "tooltips.hpp" -namespace -{ - // Sorts a container descending by skill value. If skill value is equal, sorts ascending by skill ID. - // pair - bool sortSkills(const std::pair& left, const std::pair& right) - { - if (left == right) - return false; - - if (left.second > right.second) - return true; - else if (left.second < right.second) - return false; - - return left.first < right.first; - } -} - namespace MWGui { @@ -80,34 +62,37 @@ namespace MWGui mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); + const auto& store = MWBase::Environment::get().getESMStore(); + const MWWorld::Store& gmst = store->get(); + const MWWorld::Store& skillStore = store->get(); + // NPC can train you in his best 3 skills - std::vector> skills; + std::vector> skills; MWMechanics::NpcStats const& actorStats(actor.getClass().getNpcStats(actor)); - for (int i = 0; i < ESM::Skill::Length; ++i) + for (const ESM::Skill& skill : skillStore) { - float value = getSkillForTraining(actorStats, i); + float value = getSkillForTraining(actorStats, skill.mIndex); - skills.emplace_back(i, value); + skills.emplace_back(&skill, value); } - std::sort(skills.begin(), skills.end(), sortSkills); + std::sort(skills.begin(), skills.end(), [](const auto& left, const auto& right) { + return std::tie(right.second, left.first->mId) < std::tie(left.second, right.first->mId); + }); MyGUI::EnumeratorWidgetPtr widgets = mTrainingOptions->getEnumerator(); MyGUI::Gui::getInstance().destroyWidgets(widgets); MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player); - const auto& store = MWBase::Environment::get().getESMStore(); - const MWWorld::Store& gmst = store->get(); - const MWWorld::Store& skillStore = store->get(); - const int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; for (int i = 0; i < 3; ++i) { + const ESM::Skill* skill = skills[i].first; int price = static_cast( - pcStats.getSkill(skills[i].first).getBase() * gmst.find("iTrainingMod")->mValue.getInteger()); + pcStats.getSkill(skill->mIndex).getBase() * gmst.find("iTrainingMod")->mValue.getInteger()); price = std::max(1, price); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true); @@ -120,13 +105,12 @@ namespace MWGui button->setUserData(skills[i].first); button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected); - const ESM::Skill* skill = skillStore.find(skills[i].first); button->setCaptionWithReplacing( MyGUI::TextIterator::toTagsString(skill->mName) + " - " + MyGUI::utility::toString(price)); button->setSize(button->getTextSize().width + 12, button->getSize().height); - ToolTips::createSkillToolTip(button, skills[i].first); + ToolTips::createSkillToolTip(button, skill->mIndex); } center(); @@ -144,29 +128,29 @@ namespace MWGui void TrainingWindow::onTrainingSelected(MyGUI::Widget* sender) { - int skillId = *sender->getUserData(); + const ESM::Skill* skill = *sender->getUserData(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player); const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); - int price = pcStats.getSkill(skillId).getBase() + int price = pcStats.getSkill(skill->mIndex).getBase() * store.get().find("iTrainingMod")->mValue.getInteger(); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true); if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) return; - if (getSkillForTraining(mPtr.getClass().getNpcStats(mPtr), skillId) <= pcStats.getSkill(skillId).getBase()) + if (getSkillForTraining(mPtr.getClass().getNpcStats(mPtr), skill->mIndex) + <= pcStats.getSkill(skill->mIndex).getBase()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sServiceTrainingWords}"); return; } // You can not train a skill above its governing attribute - const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get().find(skillId); - if (pcStats.getSkill(skillId).getBase() >= pcStats.getAttribute(skill->mData.mAttribute).getBase()) + if (pcStats.getSkill(skill->mIndex).getBase() >= pcStats.getAttribute(skill->mData.mAttribute).getBase()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage17}"); return; @@ -176,7 +160,7 @@ namespace MWGui MWWorld::LiveCellRef* playerRef = player.get(); const ESM::Class* class_ = store.get().find(playerRef->mBase->mClass); - pcStats.increaseSkill(skillId, *class_, true); + pcStats.increaseSkill(skill->mIndex, *class_, true); // remove gold player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 487764cfbe..0fa85b9b97 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -155,16 +155,16 @@ namespace MWMechanics creatureStats.setAttribute(i, male ? attribute.mMale : attribute.mFemale); } - for (int i = 0; i < 27; ++i) + for (const ESM::Skill& skill : esmStore.get()) { int bonus = 0; auto bonusIt = std::find_if(race->mData.mBonus.begin(), race->mData.mBonus.end(), - [i](const auto& bonus) { return bonus.mSkill == i; }); + [&](const auto& bonus) { return bonus.mSkill == skill.mIndex; }); if (bonusIt != race->mData.mBonus.end()) bonus = bonusIt->mBonus; - npcStats.getSkill(i).setBase(5 + bonus); + npcStats.getSkill(skill.mIndex).setBase(5 + bonus); } for (const ESM::RefId& power : race->mPowers.mList) @@ -217,14 +217,7 @@ namespace MWMechanics for (const ESM::Skill& skill : esmStore.get()) { if (skill.mData.mSpecialization == class_->mData.mSpecialization) - { - int index = skill.mIndex; - - if (index >= 0 && index < 27) - { - npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + 5); - } - } + npcStats.getSkill(skill.mIndex).setBase(npcStats.getSkill(skill.mIndex).getBase() + 5); } } diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 5b717c81fc..5d17a86c3a 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -168,11 +168,19 @@ namespace MWWorld { if constexpr (std::is_same_v) { - std::vector results; - std::copy_if(mShared.begin(), mShared.end(), std::back_inserter(results), - [prefix](const T* item) { return item->mId.startsWith(prefix); }); - if (!results.empty()) - return results[Misc::Rng::rollDice(results.size(), prng)]; + if (prefix.empty()) + { + if (!mShared.empty()) + return mShared[Misc::Rng::rollDice(mShared.size(), prng)]; + } + else + { + std::vector results; + std::copy_if(mShared.begin(), mShared.end(), std::back_inserter(results), + [prefix](const T* item) { return item->mId.startsWith(prefix); }); + if (!results.empty()) + return results[Misc::Rng::rollDice(results.size(), prng)]; + } return nullptr; } else