From 47c15699616015b0dd304e4472df8d5d58b02809 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 5 Jun 2023 21:21:30 +0200 Subject: [PATCH] Use RefId key for NPC skills --- apps/openmw/mwclass/armor.cpp | 2 +- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 30 ++++---- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwdialogue/filter.cpp | 8 +- apps/openmw/mwgui/jailscreen.cpp | 4 +- apps/openmw/mwgui/review.cpp | 19 ++--- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/statswatcher.cpp | 10 +-- apps/openmw/mwgui/statswindow.cpp | 7 +- apps/openmw/mwgui/trainingwindow.cpp | 18 ++--- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwlua/stats.cpp | 51 +++++++------ apps/openmw/mwmechanics/autocalcspell.cpp | 32 +++++--- apps/openmw/mwmechanics/autocalcspell.hpp | 17 +++-- apps/openmw/mwmechanics/combat.cpp | 5 +- .../mwmechanics/mechanicsmanagerimp.cpp | 23 ++---- apps/openmw/mwmechanics/npcstats.cpp | 73 +++++++++++-------- apps/openmw/mwmechanics/npcstats.hpp | 17 +++-- apps/openmw/mwmechanics/spelleffects.cpp | 12 +-- apps/openmw/mwmechanics/spellpriority.cpp | 2 +- apps/openmw/mwmechanics/weaponpriority.cpp | 8 +- apps/openmw/mwscript/statsextensions.cpp | 37 +++++----- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 7 +- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/player.cpp | 23 +++--- apps/openmw/mwworld/player.hpp | 3 +- 29 files changed, 228 insertions(+), 196 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 416a55336a..bdaa82e873 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -298,7 +298,7 @@ namespace MWClass const MWWorld::LiveCellRef* ref = ptr.get(); int armorSkillType = getEquipmentSkill(ptr); - float armorSkill = actor.getClass().getSkill(actor, armorSkillType); + float armorSkill = actor.getClass().getSkill(actor, ESM::Skill::indexToRefId(armorSkillType)); int iBaseArmorSkill = MWBase::Environment::get() .getESMStore() diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 39de4a5b1d..1ff9c6375a 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -762,11 +762,11 @@ namespace MWClass throw std::runtime_error("Unexpected soundgen type: " + std::string(name)); } - float Creature::getSkill(const MWWorld::Ptr& ptr, int skill) const + float Creature::getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const { MWWorld::LiveCellRef* ref = ptr.get(); - const ESM::Skill* skillRecord = MWBase::Environment::get().getESMStore()->get().find(skill); + const ESM::Skill* skillRecord = MWBase::Environment::get().getESMStore()->get().find(id); switch (skillRecord->mData.mSpecialization) { diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 465c28aaaf..bd7101e93d 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -115,7 +115,7 @@ namespace MWClass bool canSwim(const MWWorld::ConstPtr& ptr) const override; bool canWalk(const MWWorld::ConstPtr& ptr) const override; - float getSkill(const MWWorld::Ptr& ptr, int skill) const override; + float getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const override; /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) int getBloodTexture(const MWWorld::ConstPtr& ptr) const override; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 9e3ca67759..ebab5bfb9c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -181,10 +181,10 @@ namespace for (const auto& skills : class_->mData.mSkills) { - int index = skills[i]; - if (index >= 0 && index < ESM::Skill::Length) + ESM::RefId id = ESM::Skill::indexToRefId(skills[i]); + if (!id.empty()) { - npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + bonus); + npcStats.getSkill(id).setBase(npcStats.getSkill(id).getBase() + bonus); } } } @@ -220,23 +220,19 @@ namespace specBonus = 5; } - npcStats.getSkill(skillIndex) - .setBase(std::min(round_ieee_754(npcStats.getSkill(skillIndex).getBase() + 5 + raceBonus + specBonus + npcStats.getSkill(skill->mId) + .setBase(std::min(round_ieee_754(npcStats.getSkill(skill->mId).getBase() + 5 + raceBonus + specBonus + (int(level) - 1) * (majorMultiplier + specMultiplier)), 100)); // Must gracefully handle level 0 } - int skills[ESM::Skill::Length]; - for (int i = 0; i < ESM::Skill::Length; ++i) - skills[i] = npcStats.getSkill(i).getBase(); - int attributes[ESM::Attribute::Length]; for (int i = 0; i < ESM::Attribute::Length; ++i) attributes[i] = npcStats.getAttribute(i).getBase(); if (!spellsInitialised) { - std::vector spells = MWMechanics::autoCalcNpcSpells(skills, attributes, race); + std::vector spells = MWMechanics::autoCalcNpcSpells(npcStats.getSkills(), attributes, race); npcStats.getSpells().addAllToInstance(spells); } } @@ -315,7 +311,7 @@ namespace MWClass gold = ref->mBase->mNpdt.mGold; for (size_t i = 0; i < ref->mBase->mNpdt.mSkills.size(); ++i) - data->mNpcStats.getSkill(i).setBase(ref->mBase->mNpdt.mSkills[i]); + data->mNpcStats.getSkill(ESM::Skill::indexToRefId(i)).setBase(ref->mBase->mNpdt.mSkills[i]); data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt.mStrength); data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt.mIntelligence); @@ -593,7 +589,7 @@ namespace MWClass if (!weapon.isEmpty()) weapskill = weapon.getClass().getEquipmentSkill(weapon); - float hitchance = MWMechanics::getHitChance(ptr, victim, getSkill(ptr, weapskill)); + float hitchance = MWMechanics::getHitChance(ptr, victim, getSkill(ptr, ESM::Skill::indexToRefId(weapskill))); return Misc::Rng::roll0to99(world->getPrng()) < hitchance; } @@ -1052,7 +1048,7 @@ namespace MWClass const float encumbranceTerm = gmst.fJumpEncumbranceBase->mValue.getFloat() + gmst.fJumpEncumbranceMultiplier->mValue.getFloat() * (1.0f - Npc::getNormalizedEncumbrance(ptr)); - float a = getSkill(ptr, ESM::Skill::Acrobatics); + float a = Class::getSkill(ptr, ESM::Skill::Acrobatics); float b = 0.0f; if (a > 50.0f) { @@ -1185,7 +1181,7 @@ namespace MWClass float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); - float unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored); + float unarmoredSkill = Class::getSkill(ptr, ESM::Skill::Unarmored); float ratings[MWWorld::InventoryStore::Slots]; for (int i = 0; i < MWWorld::InventoryStore::Slots; i++) @@ -1355,9 +1351,9 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - float Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const + float Npc::getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const { - return getNpcStats(ptr).getSkill(skill).getModified(); + return getNpcStats(ptr).getSkill(id).getModified(); } int Npc::getBloodTexture(const MWWorld::ConstPtr& ptr) const @@ -1550,7 +1546,7 @@ namespace MWClass { const GMST& gmst = getGmst(); return getWalkSpeed(ptr) - * (0.01f * getSkill(ptr, ESM::Skill::Athletics) * gmst.fAthleticsRunBonus->mValue.getFloat() + * (0.01f * Class::getSkill(ptr, ESM::Skill::Athletics) * gmst.fAthleticsRunBonus->mValue.getFloat() + gmst.fBaseRunMultiplier->mValue.getFloat()); } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 9b8e229890..242548ab20 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -134,7 +134,7 @@ namespace MWClass std::string getModel(const MWWorld::ConstPtr& ptr) const override; - float getSkill(const MWWorld::Ptr& ptr, int skill) const override; + float getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const override; /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) int getBloodTexture(const MWWorld::ConstPtr& ptr) const override; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 31a76e949c..6858c76cfe 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/environment.hpp" @@ -385,9 +386,10 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons return player.getClass().getCreatureStats(player).getAttribute(select.getArgument()).getModified(); case SelectWrapper::Function_PcSkill: - - return static_cast(player.getClass().getNpcStats(player).getSkill(select.getArgument()).getModified()); - + { + ESM::RefId skill = ESM::Skill::indexToRefId(select.getArgument()); + return static_cast(player.getClass().getNpcStats(player).getSkill(skill).getModified()); + } case SelectWrapper::Function_FriendlyHit: { int hits = mActor.getClass().getCreatureStats(mActor).getFriendlyHits(); diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index b73aafb79c..484e9370cc 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -96,7 +96,7 @@ namespace MWGui const ESM::Skill* skill = skillStore.searchRandom({}, prng); skills.insert(skill); - MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill->mIndex); + MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill->mId); if (skill->mIndex == ESM::Skill::Security || skill->mIndex == ESM::Skill::Sneak) value.setBase(std::min(100.f, value.getBase() + 1)); else @@ -116,7 +116,7 @@ namespace MWGui for (const ESM::Skill* skill : skills) { - int skillValue = player.getClass().getNpcStats(player).getSkill(skill->mIndex).getBase(); + int skillValue = player.getClass().getNpcStats(player).getSkill(skill->mId).getBase(); std::string skillMsg = gmst.find("sNotifyMessage44")->mValue.getString(); if (skill->mIndex == ESM::Skill::Sneak || skill->mIndex == ESM::Skill::Security) skillMsg = gmst.find("sNotifyMessage39")->mValue.getString(); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 2a04cca6c8..02555a4cfe 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -90,10 +90,10 @@ namespace MWGui getWidget(mSkillView, "SkillView"); mSkillView->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - for (int i = 0; i < ESM::Skill::Length; ++i) + for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get()) { - mSkillValues.insert(std::make_pair(i, MWMechanics::SkillValue())); - mSkillWidgetMap.insert(std::make_pair(i, static_cast(nullptr))); + mSkillValues.emplace(skill.mId, MWMechanics::SkillValue()); + mSkillWidgetMap.emplace(skill.mIndex, static_cast(nullptr)); } MyGUI::Button* backButton; @@ -206,11 +206,12 @@ namespace MWGui void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value) { - mSkillValues[skillId] = value; + mSkillValues[ESM::Skill::indexToRefId(skillId)] = value; MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; if (widget) { - float modified = static_cast(value.getModified()), base = static_cast(value.getBase()); + float modified = value.getModified(); + float base = value.getBase(); std::string text = MyGUI::utility::toString(std::floor(modified)); std::string state = "normal"; if (modified > base) @@ -345,7 +346,7 @@ namespace MWGui ESM::Skill::indexToRefId(skillIndex)); if (!skill) // Skip unknown skills continue; - const MWMechanics::SkillValue& stat = mSkillValues.find(skill->mIndex)->second; + const MWMechanics::SkillValue& stat = mSkillValues.find(skill->mId)->second; int base = stat.getBase(); int modified = stat.getModified(); @@ -394,15 +395,11 @@ namespace MWGui if (!mRaceId.empty()) race = MWBase::Environment::get().getESMStore()->get().find(mRaceId); - int skills[ESM::Skill::Length]; - for (int i = 0; i < ESM::Skill::Length; ++i) - skills[i] = mSkillValues.find(i)->second.getBase(); - int attributes[ESM::Attribute::Length]; for (int i = 0; i < ESM::Attribute::Length; ++i) attributes[i] = mAttributeWidgets[i]->getAttributeValue().getBase(); - std::vector selectedSpells = MWMechanics::autoCalcPlayerSpells(skills, attributes, race); + std::vector selectedSpells = MWMechanics::autoCalcPlayerSpells(mSkillValues, attributes, race); for (ESM::RefId& spellId : selectedSpells) { if (std::find(spells.begin(), spells.end(), spellId) == spells.end()) diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 54044a762a..f0eefb35a7 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -94,7 +94,7 @@ namespace MWGui std::map mAttributeWidgets; SkillList mMajorSkills, mMinorSkills, mMiscSkills; - std::map mSkillValues; + std::map mSkillValues; std::map mSkillWidgetMap; ESM::RefId mRaceId, mBirthSignId; std::string mName; diff --git a/apps/openmw/mwgui/statswatcher.cpp b/apps/openmw/mwgui/statswatcher.cpp index 6ad574a5a2..cd630043d3 100644 --- a/apps/openmw/mwgui/statswatcher.cpp +++ b/apps/openmw/mwgui/statswatcher.cpp @@ -83,13 +83,13 @@ namespace MWGui } } - // Loop over ESM::Skill::SkillEnum - for (int i = 0; i < ESM::Skill::Length; ++i) + for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get()) { - if (stats.getSkill(i) != mWatchedSkills[i] || mWatchedStatsEmpty) + const auto& value = stats.getSkill(skill.mId); + if (value != mWatchedSkills[skill.mIndex] || mWatchedStatsEmpty) { - mWatchedSkills[i] = stats.getSkill(i); - setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i)); + mWatchedSkills[skill.mIndex] = value; + setValue(ESM::Skill::SkillEnum(skill.mIndex), value); } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index ec6fd49f15..00e330c54c 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -237,7 +237,7 @@ namespace MWGui } } - void setSkillProgress(MyGUI::Widget* w, float progress, int skillId) + void setSkillProgress(MyGUI::Widget* w, float progress, ESM::RefId skillId) { MWWorld::Ptr player = MWMechanics::getPlayer(); const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore(); @@ -296,8 +296,9 @@ namespace MWGui valueWidget->setUserString("Visible_SkillProgressVBox", "true"); valueWidget->setUserString("UserData^Hidden_SkillProgressVBox", "false"); - setSkillProgress(nameWidget, value.getProgress(), parSkill); - setSkillProgress(valueWidget, value.getProgress(), parSkill); + ESM::RefId id = ESM::Skill::indexToRefId(parSkill); + setSkillProgress(nameWidget, value.getProgress(), id); + setSkillProgress(valueWidget, value.getProgress(), id); } else { diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index e9184978fa..daa8303a69 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -72,7 +72,7 @@ namespace MWGui MWMechanics::NpcStats const& actorStats(actor.getClass().getNpcStats(actor)); for (const ESM::Skill& skill : skillStore) { - float value = getSkillForTraining(actorStats, skill.mIndex); + float value = getSkillForTraining(actorStats, skill.mId); skills.emplace_back(&skill, value); } @@ -92,7 +92,7 @@ namespace MWGui { const ESM::Skill* skill = skills[i].first; int price = static_cast( - pcStats.getSkill(skill->mIndex).getBase() * gmst.find("iTrainingMod")->mValue.getInteger()); + pcStats.getSkill(skill->mId).getBase() * gmst.find("iTrainingMod")->mValue.getInteger()); price = std::max(1, price); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true); @@ -135,22 +135,22 @@ namespace MWGui const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); - int price = pcStats.getSkill(skill->mIndex).getBase() + int price = pcStats.getSkill(skill->mId).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), skill->mIndex) - <= pcStats.getSkill(skill->mIndex).getBase()) + if (getSkillForTraining(mPtr.getClass().getNpcStats(mPtr), skill->mId) + <= pcStats.getSkill(skill->mId).getBase()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sServiceTrainingWords}"); return; } // You can not train a skill above its governing attribute - if (pcStats.getSkill(skill->mIndex).getBase() >= pcStats.getAttribute(skill->mData.mAttribute).getBase()) + if (pcStats.getSkill(skill->mId).getBase() >= pcStats.getAttribute(skill->mData.mAttribute).getBase()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage17}"); return; @@ -196,11 +196,11 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } - float TrainingWindow::getSkillForTraining(const MWMechanics::NpcStats& stats, int skillId) const + float TrainingWindow::getSkillForTraining(const MWMechanics::NpcStats& stats, ESM::RefId id) const { if (mTrainingSkillBasedOnBaseSkill) - return stats.getSkill(skillId).getBase(); - return stats.getSkill(skillId).getModified(); + return stats.getSkill(id).getBase(); + return stats.getSkill(id).getModified(); } void TrainingWindow::onFrame(float dt) diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 145c326150..c169022b25 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -42,7 +42,7 @@ namespace MWGui // Retrieve the base skill value if the setting 'training skills based on base skill' is set; // otherwise returns the modified skill - float getSkillForTraining(const MWMechanics::NpcStats& stats, int skillId) const; + float getSkillForTraining(const MWMechanics::NpcStats& stats, ESM::RefId id) const; MyGUI::Widget* mTrainingOptions; MyGUI::Button* mCancelButton; diff --git a/apps/openmw/mwlua/stats.cpp b/apps/openmw/mwlua/stats.cpp index eddd366fd0..817703728e 100644 --- a/apps/openmw/mwlua/stats.cpp +++ b/apps/openmw/mwlua/stats.cpp @@ -25,8 +25,8 @@ namespace using SelfObject = MWLua::SelfObject; using ObjectVariant = MWLua::ObjectVariant; - template - auto addIndexedAccessor(int index) + template + auto addIndexedAccessor(I index) { return [index](const sol::object& o) { return T::create(ObjectVariant(o), index); }; } @@ -228,37 +228,36 @@ namespace MWLua class SkillStat { ObjectVariant mObject; - int mIndex; + ESM::RefId mId; - SkillStat(ObjectVariant object, int index) + SkillStat(ObjectVariant object, ESM::RefId id) : mObject(std::move(object)) - , mIndex(index) + , mId(id) { } - static float getProgress(const MWWorld::Ptr& ptr, int index, const MWMechanics::SkillValue& stat) + static float getProgress(const MWWorld::Ptr& ptr, ESM::RefId id, const MWMechanics::SkillValue& stat) { float progress = stat.getProgress(); if (progress != 0.f) - progress /= getMaxProgress(ptr, index, stat); + progress /= getMaxProgress(ptr, id, stat); return progress; } - static float getMaxProgress(const MWWorld::Ptr& ptr, int index, const MWMechanics::SkillValue& stat) + static float getMaxProgress(const MWWorld::Ptr& ptr, ESM::RefId id, const MWMechanics::SkillValue& stat) { const auto& store = *MWBase::Environment::get().getESMStore(); const auto cl = store.get().find(ptr.get()->mBase->mClass); - return ptr.getClass().getNpcStats(ptr).getSkillProgressRequirement(index, *cl); + return ptr.getClass().getNpcStats(ptr).getSkillProgressRequirement(id, *cl); } public: template sol::object get(const Context& context, std::string_view prop, G getter) const { - return getValue( - context, mObject, &SkillStat::setValue, mIndex, prop, [this, getter](const MWWorld::Ptr& ptr) { - return (ptr.getClass().getNpcStats(ptr).getSkill(mIndex).*getter)(); - }); + return getValue(context, mObject, &SkillStat::setValue, mId.getIf()->getValue(), prop, + [this, getter]( + const MWWorld::Ptr& ptr) { return (ptr.getClass().getNpcStats(ptr).getSkill(mId).*getter)(); }); } float getModified(const Context& context) const @@ -271,30 +270,33 @@ namespace MWLua sol::object getProgress(const Context& context) const { - return getValue( - context, mObject, &SkillStat::setValue, mIndex, "progress", [this](const MWWorld::Ptr& ptr) { - return getProgress(ptr, mIndex, ptr.getClass().getNpcStats(ptr).getSkill(mIndex)); + return getValue(context, mObject, &SkillStat::setValue, mId.getIf()->getValue(), + "progress", [this](const MWWorld::Ptr& ptr) { + return getProgress(ptr, mId, ptr.getClass().getNpcStats(ptr).getSkill(mId)); }); } - static std::optional create(ObjectVariant object, int index) + static std::optional create(ObjectVariant object, ESM::RefId id) { if (!object.ptr().getClass().isNpc()) return {}; - return SkillStat{ std::move(object), index }; + return SkillStat{ std::move(object), id }; } void cache(const Context& context, std::string_view prop, const sol::object& value) const { SelfObject* obj = mObject.asSelfObject(); addStatUpdateAction(context.mLuaManager, *obj); - obj->mStatsCache[SelfObject::CachedStat{ &SkillStat::setValue, mIndex, prop }] = value; + obj->mStatsCache[SelfObject::CachedStat{ + &SkillStat::setValue, int(mId.getIf()->getValue()), prop }] + = value; } static void setValue(int index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value) { + ESM::RefId id = ESM::Skill::indexToRefId(index); auto& stats = ptr.getClass().getNpcStats(ptr); - auto stat = stats.getSkill(index); + auto stat = stats.getSkill(id); float floatValue = LuaUtil::cast(value); if (prop == "base") stat.setBase(floatValue); @@ -306,8 +308,8 @@ namespace MWLua else if (prop == "modifier") stat.setModifier(floatValue); else if (prop == "progress") - stat.setProgress(floatValue * getMaxProgress(ptr, index, stat)); - stats.setSkill(index, stat); + stat.setProgress(floatValue * getMaxProgress(ptr, id, stat)); + stats.setSkill(id, stat); } }; } @@ -385,7 +387,8 @@ namespace MWLua [context](const SkillStat& stat, const sol::object& value) { stat.cache(context, "progress", value); }); sol::table skills(context.mLua->sol(), sol::create); npcStats["skills"] = LuaUtil::makeReadOnly(skills); - for (int id = ESM::Skill::Block; id < ESM::Skill::Length; ++id) - skills[Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[id])] = addIndexedAccessor(id); + for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get()) + skills[Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[skill.mIndex])] + = addIndexedAccessor(skill.mId); } } diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index e2ad06854d..c0be97c9a9 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -27,7 +27,8 @@ namespace MWMechanics ESM::RefId mWeakestSpell; }; - std::vector autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race) + std::vector autoCalcNpcSpells( + const std::map& actorSkills, const int* actorAttributes, const ESM::Race* race) { const MWWorld::Store& gmst = MWBase::Environment::get().getESMStore()->get(); @@ -148,7 +149,7 @@ namespace MWMechanics } std::vector autoCalcPlayerSpells( - const int* actorSkills, const int* actorAttributes, const ESM::Race* race) + const std::map& actorSkills, const int* actorAttributes, const ESM::Race* race) { const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore(); @@ -226,7 +227,8 @@ namespace MWMechanics return selectedSpells; } - bool attrSkillCheck(const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes) + bool attrSkillCheck( + const ESM::Spell* spell, const std::map& actorSkills, const int* actorAttributes) { for (const auto& spellEffect : spell->mEffects.mList) { @@ -240,8 +242,9 @@ namespace MWMechanics if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)) { - assert(spellEffect.mSkill >= 0 && spellEffect.mSkill < ESM::Skill::Length); - if (actorSkills[spellEffect.mSkill] < iAutoSpellAttSkillMin) + ESM::RefId skill = ESM::Skill::indexToRefId(spellEffect.mSkill); + auto found = actorSkills.find(skill); + if (found == actorSkills.end() || found->second.getBase() < iAutoSpellAttSkillMin) return false; } @@ -256,7 +259,8 @@ namespace MWMechanics return true; } - void calcWeakestSchool(const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm) + void calcWeakestSchool(const ESM::Spell* spell, const std::map& actorSkills, + int& effectiveSchool, float& skillTerm) { // Morrowind for some reason uses a formula slightly different from magicka cost calculation float minChance = std::numeric_limits::max(); @@ -294,7 +298,11 @@ namespace MWMechanics if (effect.mRange == ESM::RT_Target) x *= 1.5f; - float s = 2.f * actorSkills[spellSchoolToSkill(magicEffect->mData.mSchool)]; + float s = 0.f; + ESM::RefId skill = ESM::Skill::indexToRefId(spellSchoolToSkill(magicEffect->mData.mSchool)); + auto found = actorSkills.find(skill); + if (found != actorSkills.end()) + s = 2.f * found->second.getBase(); if (s - x < minChance) { minChance = s - x; @@ -304,8 +312,8 @@ namespace MWMechanics } } - float calcAutoCastChance( - const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes, int effectiveSchool) + float calcAutoCastChance(const ESM::Spell* spell, const std::map& actorSkills, + const int* actorAttributes, int effectiveSchool) { if (spell->mData.mType != ESM::Spell::ST_Spell) return 100.f; @@ -314,8 +322,10 @@ namespace MWMechanics return 100.f; float skillTerm = 0; - if (effectiveSchool != -1) - skillTerm = 2.f * actorSkills[spellSchoolToSkill(effectiveSchool)]; + ESM::RefId skill = ESM::Skill::indexToRefId(spellSchoolToSkill(effectiveSchool)); + auto found = actorSkills.find(skill); + if (found != actorSkills.end()) + skillTerm = 2.f * found->second.getBase(); else calcWeakestSchool( spell, actorSkills, effectiveSchool, skillTerm); // Note effectiveSchool is unused after this diff --git a/apps/openmw/mwmechanics/autocalcspell.hpp b/apps/openmw/mwmechanics/autocalcspell.hpp index c445321623..4c445b01ab 100644 --- a/apps/openmw/mwmechanics/autocalcspell.hpp +++ b/apps/openmw/mwmechanics/autocalcspell.hpp @@ -1,9 +1,12 @@ #ifndef OPENMW_AUTOCALCSPELL_H #define OPENMW_AUTOCALCSPELL_H +#include "creaturestats.hpp" #include +#include #include #include + namespace ESM { struct Spell; @@ -17,19 +20,21 @@ namespace MWMechanics /// @note We might want to move this code to a component later, so the editor can use it for preview purposes std::vector autoCalcNpcSpells( - const int* actorSkills, const int* actorAttributes, const ESM::Race* race); + const std::map& actorSkills, const int* actorAttributes, const ESM::Race* race); std::vector autoCalcPlayerSpells( - const int* actorSkills, const int* actorAttributes, const ESM::Race* race); + const std::map& actorSkills, const int* actorAttributes, const ESM::Race* race); // Helpers - bool attrSkillCheck(const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes); + bool attrSkillCheck( + const ESM::Spell* spell, const std::map& actorSkills, const int* actorAttributes); - void calcWeakestSchool(const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm); + void calcWeakestSchool(const ESM::Spell* spell, const std::map& actorSkills, + int& effectiveSchool, float& skillTerm); - float calcAutoCastChance( - const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes, int effectiveSchool); + float calcAutoCastChance(const ESM::Spell* spell, const std::map& actorSkills, + const int* actorAttributes, int effectiveSchool); } diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 917d06bea6..06c3cb603b 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -122,7 +122,8 @@ namespace MWMechanics if (weapon.isEmpty()) attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand); else - attackerSkill = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); + attackerSkill = attacker.getClass().getSkill( + attacker, ESM::Skill::indexToRefId(weapon.getClass().getEquipmentSkill(weapon))); float attackerTerm = attackerSkill + 0.2f * attackerStats.getAttribute(ESM::Attribute::Agility).getModified() + 0.1f * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); attackerTerm *= attackerStats.getFatigueTerm(); @@ -227,7 +228,7 @@ namespace MWMechanics if (attacker == getPlayer()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); - int skillValue = attacker.getClass().getSkill(attacker, weaponSkill); + int skillValue = attacker.getClass().getSkill(attacker, ESM::Skill::indexToRefId(weaponSkill)); if (Misc::Rng::roll0to99(world->getPrng()) >= getHitChance(attacker, victim, skillValue)) { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0fa85b9b97..4e2fe047f6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -129,7 +129,7 @@ namespace MWMechanics creatureStats.getActiveSpells().clear(ptr); for (size_t i = 0; i < player->mNpdt.mSkills.size(); ++i) - npcStats.getSkill(i).setBase(player->mNpdt.mSkills[i]); + npcStats.getSkill(ESM::Skill::indexToRefId(i)).setBase(player->mNpdt.mSkills[i]); creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt.mStrength); creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt.mIntelligence); @@ -164,7 +164,7 @@ namespace MWMechanics if (bonusIt != race->mData.mBonus.end()) bonus = bonusIt->mBonus; - npcStats.getSkill(skill.mIndex).setBase(5 + bonus); + npcStats.getSkill(skill.mId).setBase(5 + bonus); } for (const ESM::RefId& power : race->mPowers.mList) @@ -205,19 +205,16 @@ namespace MWMechanics for (const auto& skills : class_->mData.mSkills) { - int index = skills[i]; - - if (index >= 0 && index < ESM::Skill::Length) - { - npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + bonus); - } + ESM::RefId id = ESM::Skill::indexToRefId(skills[i]); + if (!id.empty()) + npcStats.getSkill(id).setBase(npcStats.getSkill(id).getBase() + bonus); } } for (const ESM::Skill& skill : esmStore.get()) { if (skill.mData.mSpecialization == class_->mData.mSpecialization) - npcStats.getSkill(skill.mIndex).setBase(npcStats.getSkill(skill.mIndex).getBase() + 5); + npcStats.getSkill(skill.mId).setBase(npcStats.getSkill(skill.mId).getBase() + 5); } } @@ -226,16 +223,12 @@ namespace MWMechanics if (mRaceSelected) race = esmStore.get().find(player->mRace); - int skills[ESM::Skill::Length]; - for (int i = 0; i < ESM::Skill::Length; ++i) - skills[i] = npcStats.getSkill(i).getBase(); - int attributes[ESM::Attribute::Length]; for (int i = 0; i < ESM::Attribute::Length; ++i) attributes[i] = npcStats.getAttribute(i).getBase(); npcStats.updateHealth(); - std::vector selectedSpells = autoCalcPlayerSpells(skills, attributes, race); + std::vector selectedSpells = autoCalcPlayerSpells(npcStats.getSkills(), attributes, race); for (const ESM::RefId& spell : selectedSpells) creatureStats.getSpells().add(spell); @@ -1914,7 +1907,7 @@ namespace MWMechanics const ESM::Skill* acrobatics = MWBase::Environment::get().getESMStore()->get().find(ESM::Skill::Acrobatics); MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor); - auto& skill = stats.getSkill(acrobatics->mIndex); + auto& skill = stats.getSkill(acrobatics->mId); skill.setModifier(acrobatics->mWerewolfValue - skill.getModified()); } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index e9812e7931..e52f8232c3 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -30,6 +30,8 @@ MWMechanics::NpcStats::NpcStats() { mSkillIncreases.resize(ESM::Attribute::Length, 0); mSpecIncreases.resize(3, 0); + for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get()) + mSkills.emplace(skill.mId, SkillValue{}); } int MWMechanics::NpcStats::getBaseDisposition() const @@ -42,28 +44,28 @@ void MWMechanics::NpcStats::setBaseDisposition(int disposition) mDisposition = disposition; } -const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(int index) const +const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(ESM::RefId id) const { - if (index < 0 || index >= ESM::Skill::Length) - throw std::runtime_error("skill index out of range"); - - return mSkill[index]; + auto it = mSkills.find(id); + if (it == mSkills.end()) + throw std::runtime_error("skill not found"); + return it->second; } -MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(int index) +MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(ESM::RefId id) { - if (index < 0 || index >= ESM::Skill::Length) - throw std::runtime_error("skill index out of range"); - - return mSkill[index]; + auto it = mSkills.find(id); + if (it == mSkills.end()) + throw std::runtime_error("skill not found"); + return it->second; } -void MWMechanics::NpcStats::setSkill(int index, const MWMechanics::SkillValue& value) +void MWMechanics::NpcStats::setSkill(ESM::RefId id, const MWMechanics::SkillValue& value) { - if (index < 0 || index >= ESM::Skill::Length) - throw std::runtime_error("skill index out of range"); - - mSkill[index] = value; + auto it = mSkills.find(id); + if (it == mSkills.end()) + throw std::runtime_error("skill not found"); + it->second = value; } const std::map& MWMechanics::NpcStats::getFactionRanks() const @@ -154,22 +156,23 @@ void MWMechanics::NpcStats::setFactionReputation(const ESM::RefId& faction, int mFactionReputation[faction] = value; } -float MWMechanics::NpcStats::getSkillProgressRequirement(int skillIndex, const ESM::Class& class_) const +float MWMechanics::NpcStats::getSkillProgressRequirement(ESM::RefId id, const ESM::Class& class_) const { - float progressRequirement = static_cast(1 + getSkill(skillIndex).getBase()); + float progressRequirement = 1.f + getSkill(id).getBase(); const MWWorld::Store& gmst = MWBase::Environment::get().getESMStore()->get(); + const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get().find(id); float typeFactor = gmst.find("fMiscSkillBonus")->mValue.getFloat(); for (const auto& skills : class_.mData.mSkills) { - if (skills[0] == skillIndex) + if (skills[0] == skill->mIndex) { typeFactor = gmst.find("fMinorSkillBonus")->mValue.getFloat(); break; } - else if (skills[1] == skillIndex) + else if (skills[1] == skill->mIndex) { typeFactor = gmst.find("fMajorSkillBonus")->mValue.getFloat(); break; @@ -183,7 +186,6 @@ float MWMechanics::NpcStats::getSkillProgressRequirement(int skillIndex, const E float specialisationFactor = 1; - const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get().find(skillIndex); if (skill->mData.mSpecialization == class_.mData.mSpecialization) { specialisationFactor = gmst.find("fSpecialSkillBonus")->mValue.getFloat(); @@ -210,11 +212,11 @@ void MWMechanics::NpcStats::useSkill(int skillIndex, const ESM::Class& class_, i } skillGain *= extraFactor; - MWMechanics::SkillValue& value = getSkill(skillIndex); + MWMechanics::SkillValue& value = getSkill(skill->mId); value.setProgress(value.getProgress() + skillGain); - if (int(value.getProgress()) >= int(getSkillProgressRequirement(skillIndex, class_))) + if (int(value.getProgress()) >= int(getSkillProgressRequirement(skill->mId, class_))) { // skill levelled up increaseSkill(skillIndex, class_, false); @@ -224,7 +226,8 @@ void MWMechanics::NpcStats::useSkill(int skillIndex, const ESM::Class& class_, i void MWMechanics::NpcStats::increaseSkill( int skillIndex, const ESM::Class& class_, bool preserveProgress, bool readBook) { - float base = getSkill(skillIndex).getBase(); + const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get().find(skillIndex); + float base = getSkill(skill->mId).getBase(); if (base >= 100.f) return; @@ -251,7 +254,6 @@ void MWMechanics::NpcStats::increaseSkill( } } - const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get().find(skillIndex); mSkillIncreases[skill->mData.mAttribute] += increase; mSpecIncreases[skill->mData.mSpecialization] += gmst.find("iLevelupSpecialization")->mValue.getInteger(); @@ -275,9 +277,9 @@ void MWMechanics::NpcStats::increaseSkill( MWBase::Environment::get().getWindowManager()->messageBox("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never); } - getSkill(skillIndex).setBase(base); + getSkill(skill->mId).setBase(base); if (!preserveProgress) - getSkill(skillIndex).setProgress(0); + getSkill(skill->mId).setProgress(0); } int MWMechanics::NpcStats::getLevelProgress() const @@ -388,9 +390,10 @@ bool MWMechanics::NpcStats::hasSkillsForRank(const ESM::RefId& factionId, int ra std::vector skills; - for (int id : faction.mData.mSkills) + for (int index : faction.mData.mSkills) { - if (id != -1) + ESM::RefId id = ESM::Skill::indexToRefId(index); + if (!id.empty()) skills.push_back(static_cast(getSkill(id).getBase())); } @@ -470,8 +473,12 @@ void MWMechanics::NpcStats::writeState(ESM::NpcStats& state) const state.mDisposition = mDisposition; - for (size_t i = 0; i < state.mSkills.size(); ++i) - mSkill[i].writeState(state.mSkills[i]); + for (const auto& [id, value] : mSkills) + { + // TODO extend format + auto index = id.getIf()->getValue(); + value.writeState(state.mSkills[index]); + } state.mIsWerewolf = mIsWerewolf; @@ -524,7 +531,11 @@ void MWMechanics::NpcStats::readState(const ESM::NpcStats& state) mDisposition = state.mDisposition; for (size_t i = 0; i < state.mSkills.size(); ++i) - mSkill[i].readState(state.mSkills[i]); + { + // TODO extend format + ESM::RefId id = ESM::Skill::indexToRefId(i); + mSkills[id].readState(state.mSkills[i]); + } mIsWerewolf = state.mIsWerewolf; diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 57f4bbd1e4..ddf677c665 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -3,6 +3,7 @@ #include "creaturestats.hpp" #include +#include #include #include #include @@ -21,7 +22,7 @@ namespace MWMechanics class NpcStats : public CreatureStats { int mDisposition; - SkillValue mSkill[ESM::Skill::Length]; // SkillValue.mProgress used by the player only + std::map mSkills; // SkillValue.mProgress used by the player only int mReputation; int mCrimeId; @@ -58,9 +59,13 @@ namespace MWMechanics int getCrimeId() const; void setCrimeId(int id); - const SkillValue& getSkill(int index) const; - SkillValue& getSkill(int index); - void setSkill(int index, const SkillValue& value); + const SkillValue& getSkill(ESM::RefId id) const; + const SkillValue& getSkill(ESM::Skill::SkillEnum index) const + { + return getSkill(ESM::Skill::indexToRefId(index)); + } + SkillValue& getSkill(ESM::RefId id); + void setSkill(ESM::RefId id, const SkillValue& value); int getFactionRank(const ESM::RefId& faction) const; const std::map& getFactionRanks() const; @@ -79,7 +84,7 @@ namespace MWMechanics bool isInFaction(const ESM::RefId& faction) const; - float getSkillProgressRequirement(int skillIndex, const ESM::Class& class_) const; + float getSkillProgressRequirement(ESM::RefId id, const ESM::Class& class_) const; void useSkill(int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor = 1.f); ///< Increase skill by usage. @@ -133,6 +138,8 @@ namespace MWMechanics void readState(const ESM::CreatureStats& state); void readState(const ESM::NpcStats& state); + + const std::map& getSkills() const { return mSkills; } }; } diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index 3afe220a24..fe1e073aac 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -105,7 +105,7 @@ namespace void damageSkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude) { auto& npcStats = target.getClass().getNpcStats(target); - auto& skill = npcStats.getSkill(effect.mArg); + auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg)); if (effect.mEffectId == ESM::MagicEffect::DamageSkill) magnitude = std::min(skill.getModified(), magnitude); skill.damage(magnitude); @@ -114,14 +114,14 @@ namespace void restoreSkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude) { auto& npcStats = target.getClass().getNpcStats(target); - auto& skill = npcStats.getSkill(effect.mArg); + auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg)); skill.restore(magnitude); } void fortifySkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude) { auto& npcStats = target.getClass().getNpcStats(target); - auto& skill = npcStats.getSkill(effect.mArg); + auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg)); skill.setModifier(skill.getModifier() + magnitude); } @@ -668,7 +668,7 @@ namespace MWMechanics if (spellParams.getType() == ESM::ActiveSpells::Type_Ability) { auto& npcStats = target.getClass().getNpcStats(target); - SkillValue& skill = npcStats.getSkill(effect.mArg); + SkillValue& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg)); // Damage Skill abilities reduce base skill :todd: skill.setBase(std::max(skill.getBase() - effect.mMagnitude, 0.f)); } @@ -760,7 +760,7 @@ namespace MWMechanics { // Abilities affect base stats, but not for drain auto& npcStats = target.getClass().getNpcStats(target); - auto& skill = npcStats.getSkill(effect.mArg); + auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg)); skill.setBase(skill.getBase() + effect.mMagnitude); } else @@ -1218,7 +1218,7 @@ namespace MWMechanics if (spellParams.getType() == ESM::ActiveSpells::Type_Ability) { auto& npcStats = target.getClass().getNpcStats(target); - auto& skill = npcStats.getSkill(effect.mArg); + auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg)); skill.setBase(skill.getBase() - effect.mMagnitude); } else diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index 4e813ec37c..79f8d315ab 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -565,7 +565,7 @@ namespace MWMechanics case ESM::MagicEffect::DrainSkill: if (enemy.isEmpty() || !enemy.getClass().isNpc()) return 0.f; - if (enemy.getClass().getSkill(enemy, effect.mSkill) <= 0) + if (enemy.getClass().getSkill(enemy, ESM::Skill::indexToRefId(effect.mSkill)) <= 0) return 0.f; break; diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 14ee1d7c02..3fa4d454fa 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -120,8 +120,8 @@ namespace MWMechanics int value = 50.f; if (actor.getClass().isNpc()) { - int skill = item.getClass().getEquipmentSkill(item); - if (skill != -1) + ESM::RefId skill = ESM::Skill::indexToRefId(item.getClass().getEquipmentSkill(item)); + if (!skill.empty()) value = actor.getClass().getSkill(actor, skill); } else @@ -179,7 +179,9 @@ namespace MWMechanics if (weapon.isEmpty()) return 0.f; - float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f; + float skillMult + = actor.getClass().getSkill(actor, ESM::Skill::indexToRefId(weapon.getClass().getEquipmentSkill(weapon))) + * 0.01f; float chopMult = fAIMeleeWeaponMult; float bonusDamage = 0.f; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 877fa79099..a3d2d89220 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -345,11 +345,11 @@ namespace MWScript template class OpGetSkill : public Interpreter::Opcode0 { - int mIndex; + ESM::RefId mId; public: - OpGetSkill(int index) - : mIndex(index) + OpGetSkill(ESM::RefId id) + : mId(id) { } @@ -357,7 +357,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mIndex); + Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mId); runtime.push(value); } @@ -366,11 +366,11 @@ namespace MWScript template class OpSetSkill : public Interpreter::Opcode0 { - int mIndex; + ESM::RefId mId; public: - OpSetSkill(int index) - : mIndex(index) + OpSetSkill(ESM::RefId id) + : mId(id) { } @@ -383,18 +383,18 @@ namespace MWScript MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr); - stats.getSkill(mIndex).setBase(value, true); + stats.getSkill(mId).setBase(value, true); } }; template class OpModSkill : public Interpreter::Opcode0 { - int mIndex; + ESM::RefId mId; public: - OpModSkill(int index) - : mIndex(index) + OpModSkill(ESM::RefId id) + : mId(id) { } @@ -405,7 +405,7 @@ namespace MWScript Interpreter::Type_Float value = runtime[0].mFloat; runtime.pop(); - MWMechanics::SkillValue& skill = ptr.getClass().getNpcStats(ptr).getSkill(mIndex); + MWMechanics::SkillValue& skill = ptr.getClass().getNpcStats(ptr).getSkill(mId); modStat(skill, value); } }; @@ -1364,14 +1364,15 @@ namespace MWScript for (int i = 0; i < Compiler::Stats::numberOfSkills; ++i) { - interpreter.installSegment5>(Compiler::Stats::opcodeGetSkill + i, i); - interpreter.installSegment5>(Compiler::Stats::opcodeGetSkillExplicit + i, i); + ESM::RefId id = ESM::Skill::indexToRefId(i); + interpreter.installSegment5>(Compiler::Stats::opcodeGetSkill + i, id); + interpreter.installSegment5>(Compiler::Stats::opcodeGetSkillExplicit + i, id); - interpreter.installSegment5>(Compiler::Stats::opcodeSetSkill + i, i); - interpreter.installSegment5>(Compiler::Stats::opcodeSetSkillExplicit + i, i); + interpreter.installSegment5>(Compiler::Stats::opcodeSetSkill + i, id); + interpreter.installSegment5>(Compiler::Stats::opcodeSetSkillExplicit + i, id); - interpreter.installSegment5>(Compiler::Stats::opcodeModSkill + i, i); - interpreter.installSegment5>(Compiler::Stats::opcodeModSkillExplicit + i, i); + interpreter.installSegment5>(Compiler::Stats::opcodeModSkill + i, id); + interpreter.installSegment5>(Compiler::Stats::opcodeModSkillExplicit + i, id); } interpreter.installSegment5(Compiler::Stats::opcodeGetPCCrimeLevel); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 28777656c8..bb91e66b86 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -438,7 +438,7 @@ namespace MWWorld return canSwim(ptr) || canWalk(ptr) || canFly(ptr); } - float Class::getSkill(const MWWorld::Ptr& ptr, int skill) const + float Class::getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const { throw std::runtime_error("class does not support skills"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 59f228a4d4..eaaf19d135 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -14,6 +14,7 @@ #include "../mwmechanics/aisetting.hpp" #include +#include namespace ESM { @@ -340,7 +341,11 @@ namespace MWWorld bool isPureLandCreature(const MWWorld::Ptr& ptr) const; bool isMobile(const MWWorld::Ptr& ptr) const; - virtual float getSkill(const MWWorld::Ptr& ptr, int skill) const; + virtual float getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const; + float getSkill(const MWWorld::Ptr& ptr, ESM::Skill::SkillEnum index) const + { + return getSkill(ptr, ESM::Skill::indexToRefId(index)); + }; virtual void readAdditionalState(const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 34a298ae0d..5ec18557ac 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -285,7 +285,7 @@ void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_) for (int j = 0; j < static_cast(weaponSkillsLength); ++j) { - float skillValue = mActor.getClass().getSkill(mActor, static_cast(weaponSkills[j])); + float skillValue = mActor.getClass().getSkill(mActor, weaponSkills[j]); if (skillValue > max && !weaponSkillVisited[j]) { max = skillValue; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 2d7617adfa..ea1ada7689 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -59,23 +59,23 @@ namespace MWWorld { MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer()); - for (int i = 0; i < ESM::Skill::Length; ++i) - mSaveSkills[i] = stats.getSkill(i).getModified(); + for (size_t i = 0; i < mSaveSkills.size(); ++i) + mSaveSkills[i] = stats.getSkill(ESM::Skill::indexToRefId(i)).getModified(); for (int i = 0; i < ESM::Attribute::Length; ++i) mSaveAttributes[i] = stats.getAttribute(i).getModified(); } void Player::restoreStats() { - const MWWorld::Store& gmst - = MWBase::Environment::get().getESMStore()->get(); + const auto& store = MWBase::Environment::get().getESMStore(); + const MWWorld::Store& gmst = store->get(); MWMechanics::CreatureStats& creatureStats = getPlayer().getClass().getCreatureStats(getPlayer()); MWMechanics::NpcStats& npcStats = getPlayer().getClass().getNpcStats(getPlayer()); MWMechanics::DynamicStat health = creatureStats.getDynamic(0); creatureStats.setHealth(health.getBase() / gmst.find("fWereWolfHealth")->mValue.getFloat()); - for (int i = 0; i < ESM::Skill::Length; ++i) + for (size_t i = 0; i < mSaveSkills.size(); ++i) { - auto& skill = npcStats.getSkill(i); + auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(i)); skill.restore(skill.getDamage()); skill.setModifier(mSaveSkills[i] - skill.getBase()); } @@ -109,7 +109,7 @@ namespace MWWorld if (skill.mIndex == ESM::Skill::Acrobatics) continue; - MWMechanics::SkillValue& value = npcStats.getSkill(skill.mIndex); + MWMechanics::SkillValue& value = npcStats.getSkill(skill.mId); value.setModifier(skill.mWerewolfValue - value.getModified()); } } @@ -251,10 +251,7 @@ namespace MWWorld mPreviousItems.clear(); mLastKnownExteriorPosition = osg::Vec3f(0, 0, 0); - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mSaveSkills[i] = 0.f; - } + mSaveSkills.fill(0.f); for (int i = 0; i < ESM::Attribute::Length; ++i) { @@ -296,7 +293,7 @@ namespace MWWorld for (int i = 0; i < ESM::Attribute::Length; ++i) player.mSaveAttributes[i] = mSaveAttributes[i]; - for (int i = 0; i < ESM::Skill::Length; ++i) + for (size_t i = 0; i < mSaveSkills.size(); ++i) player.mSaveSkills[i] = mSaveSkills[i]; player.mPreviousItems = mPreviousItems; @@ -334,7 +331,7 @@ namespace MWWorld for (int i = 0; i < ESM::Attribute::Length; ++i) mSaveAttributes[i] = player.mSaveAttributes[i]; - for (int i = 0; i < ESM::Skill::Length; ++i) + for (size_t i = 0; i < mSaveSkills.size(); ++i) mSaveSkills[i] = player.mSaveSkills[i]; if (player.mObject.mNpcStats.mIsWerewolf) diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 913ff00b02..12eadab10f 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -1,6 +1,7 @@ #ifndef GAME_MWWORLD_PLAYER_H #define GAME_MWWORLD_PLAYER_H +#include #include #include "../mwworld/livecellref.hpp" @@ -50,7 +51,7 @@ namespace MWWorld PreviousItems mPreviousItems; // Saved stats prior to becoming a werewolf - float mSaveSkills[ESM::Skill::Length]; + std::array mSaveSkills; float mSaveAttributes[ESM::Attribute::Length]; bool mJumping;