From ac9378fa0803ea5b724af7798c35957cb941744e Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 15 Jun 2023 20:49:14 +0200 Subject: [PATCH 1/5] Replace Skill::mIndex with Skill::refIdToIndex --- apps/esmtool/record.cpp | 3 ++- apps/opencs/model/doc/document.cpp | 5 ++--- apps/openmw/mwclass/npc.cpp | 10 ++++++---- apps/openmw/mwgui/charactercreation.cpp | 4 ++-- apps/openmw/mwgui/spellcreationdialog.cpp | 2 +- apps/openmw/mwlua/stats.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 4 ++-- apps/openmw/mwmechanics/npcstats.cpp | 13 +++++++------ apps/openmw/mwworld/store.cpp | 12 +++++++----- apps/openmw_test_suite/mwworld/test_store.cpp | 4 +++- components/esm3/loadskil.cpp | 19 +++++++++++++++---- components/esm3/loadskil.hpp | 6 +----- 12 files changed, 49 insertions(+), 35 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 8227fcfcf0..d20bb4619c 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1264,7 +1264,8 @@ namespace EsmTool template <> void Record::print() { - std::cout << " ID: " << skillLabel(mData.mIndex) << " (" << mData.mIndex << ")" << std::endl; + int index = ESM::Skill::refIdToIndex(mData.mId); + std::cout << " ID: " << skillLabel(index) << " (" << index << ")" << std::endl; std::cout << " Description: " << mData.mDescription << std::endl; std::cout << " Governing Attribute: " << attributeLabel(mData.mData.mAttribute) << " (" << mData.mData.mAttribute << ")" << std::endl; diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 9ee2a8bc48..84adfb2b87 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -201,11 +201,10 @@ void CSMDoc::Document::createBase() addGmsts(); - for (int i = 0; i < 27; ++i) + for (int i = 0; i < ESM::Skill::Length; ++i) { ESM::Skill record; - record.mIndex = i; - record.mId = ESM::Skill::indexToRefId(record.mIndex); + record.mId = ESM::Skill::indexToRefId(i); record.blank(); getData().getSkills().add(record); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 59aefc715f..bdba113038 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -121,11 +121,12 @@ namespace // is this a minor or major skill? float add = 0.2f; + int index = ESM::Skill::refIdToIndex(skill.mId); for (const auto& skills : class_->mData.mSkills) { - if (skills[0] == skill.mIndex) + if (skills[0] == index) add = 0.5; - if (skills[1] == skill.mIndex) + if (skills[1] == index) add = 1.0; } modifierSum += add; @@ -199,15 +200,16 @@ namespace int raceBonus = 0; int specBonus = 0; + int index = ESM::Skill::refIdToIndex(skill.mId); auto bonusIt = std::find_if(race->mData.mBonus.begin(), race->mData.mBonus.end(), - [&](const auto& bonus) { return bonus.mSkill == skill.mIndex; }); + [&](const auto& bonus) { return bonus.mSkill == index; }); if (bonusIt != race->mData.mBonus.end()) raceBonus = bonusIt->mBonus; for (const auto& skills : class_->mData.mSkills) { // is this a minor or major skill? - if (std::find(skills.begin(), skills.end(), skill.mIndex) != skills.end()) + if (std::find(skills.begin(), skills.end(), index) != skills.end()) { majorMultiplier = 1.0f; break; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 114238482d..3987264fc6 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -471,8 +471,8 @@ namespace MWGui assert(minorSkills.size() >= klass.mData.mSkills.size()); for (size_t i = 0; i < klass.mData.mSkills.size(); ++i) { - klass.mData.mSkills[i][1] = majorSkills[i].getIf()->getValue(); - klass.mData.mSkills[i][0] = minorSkills[i].getIf()->getValue(); + klass.mData.mSkills[i][1] = ESM::Skill::refIdToIndex(majorSkills[i]); + klass.mData.mSkills[i][0] = ESM::Skill::refIdToIndex(minorSkills[i]); } MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 0c326049e8..7105112cca 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -287,7 +287,7 @@ namespace MWGui void EditEffectDialog::setSkill(ESM::RefId skill) { - mEffect.mSkill = skill.getIf()->getValue(); + mEffect.mSkill = ESM::Skill::refIdToIndex(skill); eventEffectModified(mEffect); } diff --git a/apps/openmw/mwlua/stats.cpp b/apps/openmw/mwlua/stats.cpp index da4d2a4614..552129c3fd 100644 --- a/apps/openmw/mwlua/stats.cpp +++ b/apps/openmw/mwlua/stats.cpp @@ -392,7 +392,7 @@ namespace MWLua sol::table skills(context.mLua->sol(), sol::create); npcStats["skills"] = LuaUtil::makeReadOnly(skills); for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get()) - skills[Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[skill.mIndex])] + skills[Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[ESM::Skill::refIdToIndex(skill.mId)])] = addIndexedAccessor(skill.mId); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 135c8e4660..8d89e81f12 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -158,9 +158,9 @@ namespace MWMechanics for (const ESM::Skill& skill : esmStore.get()) { int bonus = 0; - + int index = ESM::Skill::refIdToIndex(skill.mId); auto bonusIt = std::find_if(race->mData.mBonus.begin(), race->mData.mBonus.end(), - [&](const auto& bonus) { return bonus.mSkill == skill.mIndex; }); + [&](const auto& bonus) { return bonus.mSkill == index; }); if (bonusIt != race->mData.mBonus.end()) bonus = bonusIt->mBonus; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index ce779418af..f182a09944 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -155,15 +155,15 @@ float MWMechanics::NpcStats::getSkillProgressRequirement(ESM::RefId id, const ES const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get().find(id); float typeFactor = gmst.find("fMiscSkillBonus")->mValue.getFloat(); - + int index = ESM::Skill::refIdToIndex(skill->mId); for (const auto& skills : class_.mData.mSkills) { - if (skills[0] == skill->mIndex) + if (skills[0] == index) { typeFactor = gmst.find("fMinorSkillBonus")->mValue.getFloat(); break; } - else if (skills[1] == skill->mIndex) + else if (skills[1] == index) { typeFactor = gmst.find("fMajorSkillBonus")->mValue.getFloat(); break; @@ -228,15 +228,16 @@ void MWMechanics::NpcStats::increaseSkill(ESM::RefId id, const ESM::Class& class // is this a minor or major skill? int increase = gmst.find("iLevelupMiscMultAttriubte")->mValue.getInteger(); // Note: GMST has a typo + int index = ESM::Skill::refIdToIndex(skill->mId); for (const auto& skills : class_.mData.mSkills) { - if (skills[0] == skill->mIndex) + if (skills[0] == index) { mLevelProgress += gmst.find("iLevelUpMinorMult")->mValue.getInteger(); increase = gmst.find("iLevelUpMinorMultAttribute")->mValue.getInteger(); break; } - else if (skills[1] == skill->mIndex) + else if (skills[1] == index) { mLevelProgress += gmst.find("iLevelUpMajorMult")->mValue.getInteger(); increase = gmst.find("iLevelUpMajorMultAttribute")->mValue.getInteger(); @@ -463,7 +464,7 @@ void MWMechanics::NpcStats::writeState(ESM::NpcStats& state) const for (const auto& [id, value] : mSkills) { // TODO extend format - auto index = id.getIf()->getValue(); + auto index = ESM::Skill::refIdToIndex(id); value.writeState(state.mSkills[index]); } diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 2b69ec82c4..a2114648a0 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -962,12 +962,14 @@ namespace MWWorld }; for (ESM::Skill* skill : mShared) { - if (skill->mIndex >= 0) + int index = ESM::Skill::refIdToIndex(skill->mId); + if (index >= 0) { - skill->mName = getGMSTString(settings, skillValues[skill->mIndex][0]); - skill->mIcon = skillValues[skill->mIndex][1]; - skill->mWerewolfValue = getGMSTFloat(settings, skillValues[skill->mIndex][2]); - const auto& school = skillValues[skill->mIndex][3]; + const auto& values = skillValues[index]; + skill->mName = getGMSTString(settings, values[0]); + skill->mIcon = values[1]; + skill->mWerewolfValue = getGMSTFloat(settings, values[2]); + const auto& school = values[3]; if (!school.empty()) { if (!skill->mSchool) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 2b5e460627..e325dcd08e 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -462,6 +462,8 @@ namespace { refId = ESM::RefId::esm3ExteriorCell(0, 0); } + else if constexpr (std::is_same_v) + refId = ESM::Skill::Block; else refId = ESM::StringRefId(stringId); @@ -496,7 +498,7 @@ namespace const RecordType* result = nullptr; if constexpr (std::is_same_v) result = esmStore.get().search(index, 0); - else if constexpr (ESM::hasIndex && !std::is_same_v) + else if constexpr (ESM::hasIndex) result = esmStore.get().search(index); else result = esmStore.get().search(refId); diff --git a/components/esm3/loadskil.cpp b/components/esm3/loadskil.cpp index d435501e05..73fb7f34e3 100644 --- a/components/esm3/loadskil.cpp +++ b/components/esm3/loadskil.cpp @@ -53,13 +53,14 @@ namespace ESM bool hasIndex = false; bool hasData = false; + int index = -1; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().toInt()) { case fourCC("INDX"): - esm.getHT(mIndex); + esm.getHT(index); hasIndex = true; break; case fourCC("SKDT"): @@ -75,19 +76,19 @@ namespace ESM } if (!hasIndex) esm.fail("Missing INDX"); - else if (mIndex < 0 || mIndex >= Length) + else if (index < 0 || index >= Length) esm.fail("Invalid INDX"); if (!hasData) esm.fail("Missing SKDT"); // create an ID from the index and the name (only used in the editor and likely to change in the // future) - mId = indexToRefId(mIndex); + mId = indexToRefId(index); } void Skill::save(ESMWriter& esm, bool /*isDeleted*/) const { - esm.writeHNT("INDX", mIndex); + esm.writeHNT("INDX", refIdToIndex(mId)); esm.writeHNT("SKDT", mData, 24); esm.writeHNOString("DESC", mDescription); } @@ -108,6 +109,16 @@ namespace ESM return RefId::index(sRecordId, static_cast(index)); } + int Skill::refIdToIndex(RefId id) + { + if (const IndexRefId* index = id.getIf()) + { + if (index->getRecordType() == sRecordId) + return index->getValue(); + } + return -1; + } + const std::array sMagicSchools = { Skill::Alteration, Skill::Conjuration, diff --git a/components/esm3/loadskil.hpp b/components/esm3/loadskil.hpp index 637c44d0f8..f8e3390fa1 100644 --- a/components/esm3/loadskil.hpp +++ b/components/esm3/loadskil.hpp @@ -55,11 +55,6 @@ namespace ESM }; // Total size: 24 bytes SKDTstruct mData; - // Skill index. Skils don't have an id ("NAME") like most records, - // they only have a numerical index that matches one of the - // hard-coded skills in the game. - int mIndex{ -1 }; - std::string mDescription; std::string mName; std::string mIcon; @@ -105,6 +100,7 @@ namespace ESM ///< Set record to default state (does not touch the ID/index). static RefId indexToRefId(int index); + static int refIdToIndex(RefId id); }; } #endif From 967b5d205bce782df43e526aba1d338dc1d78c9f Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 15 Jun 2023 21:38:46 +0200 Subject: [PATCH 2/5] Use StringRefId for skills --- apps/opencs/model/world/columnimp.cpp | 8 +- apps/opencs/model/world/columnimp.hpp | 3 +- apps/openmw/mwlua/luabindings.cpp | 11 +- apps/openmw/mwlua/magicbindings.cpp | 24 +- apps/openmw/mwlua/stats.cpp | 3 +- apps/openmw/mwlua/types/book.cpp | 22 +- apps/openmw/mwmechanics/weapontype.cpp | 434 ++++++++++++++----------- components/esm3/loadskil.cpp | 103 +++--- components/esm3/loadskil.hpp | 57 ++-- 9 files changed, 379 insertions(+), 286 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 7d43d1e4f3..b514550479 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -26,8 +26,6 @@ namespace CSMWorld { switch (value.getRecordType()) { - case ESM::REC_SKIL: - return ESM::Skill::sSkillNames[value.getValue()]; case ESM::REC_MGEF: return std::string(ESM::MagicEffect::sIndexNames[value.getValue()]); default: @@ -335,10 +333,10 @@ namespace CSMWorld std::optional getSkillIndex(std::string_view value) { - const auto it = std::find(std::begin(ESM::Skill::sSkillNames), std::end(ESM::Skill::sSkillNames), value); - if (it == std::end(ESM::Skill::sSkillNames)) + int index = ESM::Skill::refIdToIndex(ESM::RefId::stringRefId(value)); + if (index < 0) return std::nullopt; - return static_cast(it - std::begin(ESM::Skill::sSkillNames)); + return static_cast(index); } std::string getStringId(ESM::RefId value) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 3f137fadb7..5e5ff83fcf 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -409,7 +409,8 @@ namespace CSMWorld QVariant get(const Record& record) const override { - return QString::fromStdString(ESM::Skill::sSkillNames[record.get().mData.getSkill(mIndex, mMajor)]); + return QString::fromStdString( + ESM::Skill::indexToRefId(record.get().mData.getSkill(mIndex, mMajor)).getRefIdString()); } void set(Record& record, const QVariant& data) override diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index 1804ea4004..a204287b88 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -156,10 +156,17 @@ namespace MWLua return sol::nil; }; + // TODO: deprecate this and provide access to the store instead sol::table skill(context.mLua->sol(), sol::create); api["SKILL"] = LuaUtil::makeStrictReadOnly(skill); - for (int id = 0; id < ESM::Skill::Length; ++id) - skill[ESM::Skill::sSkillNames[id]] = Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[id]); + for (int i = 0; i < ESM::Skill::Length; ++i) + { + std::string id = ESM::Skill::indexToRefId(i).serializeText(); + std::string key = id; + // force first character to uppercase for backwards compatability + key[0] += 'A' - 'a'; + skill[key] = id; + } sol::table attribute(context.mLua->sol(), sol::create); api["ATTRIBUTE"] = LuaUtil::makeStrictReadOnly(attribute); diff --git a/apps/openmw/mwlua/magicbindings.cpp b/apps/openmw/mwlua/magicbindings.cpp index 51d43b8523..6247fc6216 100644 --- a/apps/openmw/mwlua/magicbindings.cpp +++ b/apps/openmw/mwlua/magicbindings.cpp @@ -309,10 +309,10 @@ namespace MWLua }); effectParamsT["affectedSkill"] = sol::readonly_property([](const ESM::ENAMstruct& params) -> sol::optional { - if (params.mSkill >= 0 && params.mSkill < ESM::Skill::Length) - return Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[params.mSkill]); - else - return sol::nullopt; + ESM::RefId id = ESM::Skill::indexToRefId(params.mSkill); + if (!id.empty()) + return id.serializeText(); + return sol::nullopt; }); effectParamsT["affectedAttribute"] = sol::readonly_property([](const ESM::ENAMstruct& params) -> sol::optional { @@ -383,11 +383,12 @@ namespace MWLua activeEffectT["affectedSkill"] = sol::readonly_property([magicEffectStore](const ActiveEffect& effect) -> sol::optional { auto* rec = magicEffectStore->find(effect.key.mId); - if ((rec->mData.mFlags & ESM::MagicEffect::TargetSkill) && effect.key.mArg >= 0 - && effect.key.mArg < ESM::Skill::Length) - return Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[effect.key.mArg]); - else - return sol::nullopt; + if (rec->mData.mFlags & ESM::MagicEffect::TargetSkill) + { + ESM::RefId id = ESM::Skill::indexToRefId(effect.key.mArg); + return id.serializeText(); + } + return sol::nullopt; }); activeEffectT["affectedAttribute"] = sol::readonly_property([magicEffectStore](const ActiveEffect& effect) -> sol::optional { @@ -620,7 +621,10 @@ namespace MWLua key = MWMechanics::EffectKey(id, ESM::Attribute::stringToAttributeId(argStr.value())); if (rec->mData.mFlags & ESM::MagicEffect::TargetSkill) - key = MWMechanics::EffectKey(id, ESM::Skill::stringToSkillId(argStr.value())); + { + ESM::RefId skill = ESM::RefId::stringRefId(argStr.value()); + key = MWMechanics::EffectKey(id, ESM::Skill::refIdToIndex(skill)); + } } return key; diff --git a/apps/openmw/mwlua/stats.cpp b/apps/openmw/mwlua/stats.cpp index 552129c3fd..f8dde1e68d 100644 --- a/apps/openmw/mwlua/stats.cpp +++ b/apps/openmw/mwlua/stats.cpp @@ -392,7 +392,6 @@ namespace MWLua sol::table skills(context.mLua->sol(), sol::create); npcStats["skills"] = LuaUtil::makeReadOnly(skills); for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get()) - skills[Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[ESM::Skill::refIdToIndex(skill.mId)])] - = addIndexedAccessor(skill.mId); + skills[skill.mId.serializeText()] = addIndexedAccessor(skill.mId); } } diff --git a/apps/openmw/mwlua/types/book.cpp b/apps/openmw/mwlua/types/book.cpp index f7120e529a..97e51059d0 100644 --- a/apps/openmw/mwlua/types/book.cpp +++ b/apps/openmw/mwlua/types/book.cpp @@ -41,18 +41,14 @@ namespace book.mData.mValue = rec["value"]; book.mData.mIsScroll = rec["isScroll"]; - std::string_view skill = rec["skill"].get(); + ESM::RefId skill = ESM::RefId::stringRefId(rec["skill"].get()); book.mData.mSkillId = -1; - if (skill.length() > 0) + if (!skill.empty()) { - for (std::size_t i = 0; i < std::size(ESM::Skill::sSkillNames); ++i) - { - if (Misc::StringUtils::ciEqual(ESM::Skill::sSkillNames[i], skill)) - book.mData.mSkillId = i; - } + book.mData.mSkillId = ESM::Skill::refIdToIndex(skill); if (book.mData.mSkillId == -1) - throw std::runtime_error("Incorrect skill: " + std::string(skill)); + throw std::runtime_error("Incorrect skill: " + skill.toDebugString()); } return book; } @@ -69,7 +65,7 @@ namespace MWLua book["createRecordDraft"] = tableToBook; for (int id = 0; id < ESM::Skill::Length; ++id) { - std::string skillName = Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[id]); + std::string skillName = ESM::Skill::indexToRefId(id).serializeText(); skill[skillName] = skillName; } @@ -100,10 +96,10 @@ namespace MWLua record["enchantCapacity"] = sol::readonly_property([](const ESM::Book& rec) -> float { return rec.mData.mEnchant * 0.1f; }); record["skill"] = sol::readonly_property([](const ESM::Book& rec) -> sol::optional { - if (rec.mData.mSkillId >= 0) - return Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[rec.mData.mSkillId]); - else - return sol::nullopt; + ESM::RefId skill = ESM::Skill::indexToRefId(rec.mData.mSkillId); + if (!skill.empty()) + return skill.serializeText(); + return sol::nullopt; }); } } diff --git a/apps/openmw/mwmechanics/weapontype.cpp b/apps/openmw/mwmechanics/weapontype.cpp index 0612ca1a2e..9dd5842f58 100644 --- a/apps/openmw/mwmechanics/weapontype.cpp +++ b/apps/openmw/mwmechanics/weapontype.cpp @@ -18,253 +18,325 @@ namespace MWMechanics template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "", - /* long group */ "", - /* sound ID */ "", - /* attach bone */ "", - /* sheath bone */ "", - /* usage skill */ ESM::Skill::HandToHand, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ 0 }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "", + /* long group */ "", + /* sound ID */ "", + /* attach bone */ "", + /* sheath bone */ "", + /* usage skill */ ESM::Skill::HandToHand, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ 0 }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "1h", - /* long group */ "pickprobe", - /* sound ID */ "", - /* attach bone */ "", - /* sheath bone */ "", - /* usage skill */ ESM::Skill::Security, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ 0 }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "1h", + /* long group */ "pickprobe", + /* sound ID */ "", + /* attach bone */ "", + /* sheath bone */ "", + /* usage skill */ ESM::Skill::Security, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ 0 }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "spell", - /* long group */ "spellcast", - /* sound ID */ "", - /* attach bone */ "", - /* sheath bone */ "", - /* usage skill */ ESM::Skill::HandToHand, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::TwoHanded }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "spell", + /* long group */ "spellcast", + /* sound ID */ "", + /* attach bone */ "", + /* sheath bone */ "", + /* usage skill */ ESM::Skill::HandToHand, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::TwoHanded }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "hh", - /* long group */ "handtohand", - /* sound ID */ "", - /* attach bone */ "", - /* sheath bone */ "", - /* usage skill */ ESM::Skill::HandToHand, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::TwoHanded }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "hh", + /* long group */ "handtohand", + /* sound ID */ "", + /* attach bone */ "", + /* sheath bone */ "", + /* usage skill */ ESM::Skill::HandToHand, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::TwoHanded }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "1s", - /* long group */ "shortbladeonehand", - /* sound ID */ "Item Weapon Shortblade", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 ShortBladeOneHand", - /* usage skill */ ESM::Skill::ShortBlade, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::HasHealth }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "1s", + /* long group */ "shortbladeonehand", + /* sound ID */ "Item Weapon Shortblade", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 ShortBladeOneHand", + /* usage skill */ ESM::Skill::ShortBlade, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::HasHealth }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "1h", - /* long group */ "weapononehand", - /* sound ID */ "Item Weapon Longblade", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 LongBladeOneHand", - /* usage skill */ ESM::Skill::LongBlade, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::HasHealth }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "1h", + /* long group */ "weapononehand", + /* sound ID */ "Item Weapon Longblade", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 LongBladeOneHand", + /* usage skill */ ESM::Skill::LongBlade, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::HasHealth }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "1b", - /* long group */ "bluntonehand", - /* sound ID */ "Item Weapon Blunt", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 BluntOneHand", - /* usage skill */ ESM::Skill::BluntWeapon, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::HasHealth }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "1b", + /* long group */ "bluntonehand", + /* sound ID */ "Item Weapon Blunt", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 BluntOneHand", + /* usage skill */ ESM::Skill::BluntWeapon, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::HasHealth }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "1b", - /* long group */ "bluntonehand", - /* sound ID */ "Item Weapon Blunt", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 LongBladeOneHand", - /* usage skill */ ESM::Skill::Axe, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::HasHealth }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "1b", + /* long group */ "bluntonehand", + /* sound ID */ "Item Weapon Blunt", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 LongBladeOneHand", + /* usage skill */ ESM::Skill::Axe, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::HasHealth }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "2c", - /* long group */ "weapontwohand", - /* sound ID */ "Item Weapon Longblade", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 LongBladeTwoClose", - /* usage skill */ ESM::Skill::LongBlade, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "2c", + /* long group */ "weapontwohand", + /* sound ID */ "Item Weapon Longblade", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 LongBladeTwoClose", + /* usage skill */ ESM::Skill::LongBlade, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "2b", - /* long group */ "blunttwohand", - /* sound ID */ "Item Weapon Blunt", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 AxeTwoClose", - /* usage skill */ ESM::Skill::Axe, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "2b", + /* long group */ "blunttwohand", + /* sound ID */ "Item Weapon Blunt", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 AxeTwoClose", + /* usage skill */ ESM::Skill::Axe, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "2b", - /* long group */ "blunttwohand", - /* sound ID */ "Item Weapon Blunt", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 BluntTwoClose", - /* usage skill */ ESM::Skill::BluntWeapon, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "2b", + /* long group */ "blunttwohand", + /* sound ID */ "Item Weapon Blunt", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 BluntTwoClose", + /* usage skill */ ESM::Skill::BluntWeapon, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "2w", - /* long group */ "weapontwowide", - /* sound ID */ "Item Weapon Blunt", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 BluntTwoWide", - /* usage skill */ ESM::Skill::BluntWeapon, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "2w", + /* long group */ "weapontwowide", + /* sound ID */ "Item Weapon Blunt", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 BluntTwoWide", + /* usage skill */ ESM::Skill::BluntWeapon, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "2w", - /* long group */ "weapontwowide", - /* sound ID */ "Item Weapon Spear", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 SpearTwoWide", - /* usage skill */ ESM::Skill::Spear, - /* weapon class*/ ESM::WeaponType::Melee, - /* ammo type */ ESM::Weapon::None, - /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "2w", + /* long group */ "weapontwowide", + /* sound ID */ "Item Weapon Spear", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 SpearTwoWide", + /* usage skill */ ESM::Skill::Spear, + /* weapon class*/ ESM::WeaponType::Melee, + /* ammo type */ ESM::Weapon::None, + /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "bow", - /* long group */ "bowandarrow", - /* sound ID */ "Item Weapon Bow", - /* attach bone */ "Weapon Bone Left", - /* sheath bone */ "Bip01 MarksmanBow", - /* usage skill */ ESM::Skill::Marksman, - /* weapon class*/ ESM::WeaponType::Ranged, - /* ammo type */ ESM::Weapon::Arrow, - /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "bow", + /* long group */ "bowandarrow", + /* sound ID */ "Item Weapon Bow", + /* attach bone */ "Weapon Bone Left", + /* sheath bone */ "Bip01 MarksmanBow", + /* usage skill */ ESM::Skill::Marksman, + /* weapon class*/ ESM::WeaponType::Ranged, + /* ammo type */ ESM::Weapon::Arrow, + /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "crossbow", - /* long group */ "crossbow", - /* sound ID */ "Item Weapon Crossbow", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 MarksmanCrossbow", - /* usage skill */ ESM::Skill::Marksman, - /* weapon class*/ ESM::WeaponType::Ranged, - /* ammo type */ ESM::Weapon::Bolt, - /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "crossbow", + /* long group */ "crossbow", + /* sound ID */ "Item Weapon Crossbow", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 MarksmanCrossbow", + /* usage skill */ ESM::Skill::Marksman, + /* weapon class*/ ESM::WeaponType::Ranged, + /* ammo type */ ESM::Weapon::Bolt, + /* flags */ ESM::WeaponType::HasHealth | ESM::WeaponType::TwoHanded }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "1t", - /* long group */ "throwweapon", - /* sound ID */ "Item Weapon Blunt", - /* attach bone */ "Weapon Bone", - /* sheath bone */ "Bip01 MarksmanThrown", - /* usage skill */ ESM::Skill::Marksman, - /* weapon class*/ ESM::WeaponType::Thrown, - /* ammo type */ ESM::Weapon::None, - /* flags */ 0 }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "1t", + /* long group */ "throwweapon", + /* sound ID */ "Item Weapon Blunt", + /* attach bone */ "Weapon Bone", + /* sheath bone */ "Bip01 MarksmanThrown", + /* usage skill */ ESM::Skill::Marksman, + /* weapon class*/ ESM::WeaponType::Thrown, + /* ammo type */ ESM::Weapon::None, + /* flags */ 0 }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "", - /* long group */ "", - /* sound ID */ "Item Ammo", - /* attach bone */ "Bip01 Arrow", - /* sheath bone */ "", - /* usage skill */ ESM::Skill::Marksman, - /* weapon class*/ ESM::WeaponType::Ammo, - /* ammo type */ ESM::Weapon::None, - /* flags */ 0 }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "", + /* long group */ "", + /* sound ID */ "Item Ammo", + /* attach bone */ "Bip01 Arrow", + /* sheath bone */ "", + /* usage skill */ ESM::Skill::Marksman, + /* weapon class*/ ESM::WeaponType::Ammo, + /* ammo type */ ESM::Weapon::None, + /* flags */ 0 }; + return value; + } }; template <> struct Weapon { - inline static const ESM::WeaponType sValue{ /* short group */ "", - /* long group */ "", - /* sound ID */ "Item Ammo", - /* attach bone */ "ArrowBone", - /* sheath bone */ "", - /* usage skill */ ESM::Skill::Marksman, - /* weapon class*/ ESM::WeaponType::Ammo, - /* ammo type */ ESM::Weapon::None, - /* flags */ 0 }; + inline static const ESM::WeaponType& getValue() + { + static const ESM::WeaponType value{ /* short group */ "", + /* long group */ "", + /* sound ID */ "Item Ammo", + /* attach bone */ "ArrowBone", + /* sheath bone */ "", + /* usage skill */ ESM::Skill::Marksman, + /* weapon class*/ ESM::WeaponType::Ammo, + /* ammo type */ ESM::Weapon::None, + /* flags */ 0 }; + return value; + } }; MWWorld::ContainerStoreIterator getActiveWeapon(const MWWorld::Ptr& actor, int* weaptype) @@ -305,43 +377,43 @@ namespace MWMechanics switch (static_cast(weaponType)) { case ESM::Weapon::PickProbe: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::HandToHand: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::Spell: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::None: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::ShortBladeOneHand: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::LongBladeOneHand: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::LongBladeTwoHand: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::BluntOneHand: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::BluntTwoClose: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::BluntTwoWide: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::SpearTwoWide: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::AxeOneHand: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::AxeTwoHand: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::MarksmanBow: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::MarksmanCrossbow: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::MarksmanThrown: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::Arrow: - return &Weapon::sValue; + return &Weapon::getValue(); case ESM::Weapon::Bolt: - return &Weapon::sValue; + return &Weapon::getValue(); } - return &Weapon::sValue; + return &Weapon::getValue(); } } diff --git a/components/esm3/loadskil.cpp b/components/esm3/loadskil.cpp index 73fb7f34e3..21549df05b 100644 --- a/components/esm3/loadskil.cpp +++ b/components/esm3/loadskil.cpp @@ -7,44 +7,33 @@ namespace ESM { - const std::string Skill::sSkillNames[Length] = { - "Block", - "Armorer", - "Mediumarmor", - "Heavyarmor", - "Bluntweapon", - "Longblade", - "Axe", - "Spear", - "Athletics", - "Enchant", - "Destruction", - "Alteration", - "Illusion", - "Conjuration", - "Mysticism", - "Restoration", - "Alchemy", - "Unarmored", - "Security", - "Sneak", - "Acrobatics", - "Lightarmor", - "Shortblade", - "Marksman", - "Mercantile", - "Speechcraft", - "Handtohand", - }; - - int Skill::stringToSkillId(std::string_view skill) - { - for (int id = 0; id < Skill::Length; ++id) - if (Misc::StringUtils::ciEqual(sSkillNames[id], skill)) - return id; - - throw std::logic_error("No such skill: " + std::string(skill)); - } + const RefId Skill::Block = RefId::stringRefId("Block"); + const RefId Skill::Armorer = RefId::stringRefId("Armorer"); + const RefId Skill::MediumArmor = RefId::stringRefId("MediumArmor"); + const RefId Skill::HeavyArmor = RefId::stringRefId("HeavyArmor"); + const RefId Skill::BluntWeapon = RefId::stringRefId("BluntWeapon"); + const RefId Skill::LongBlade = RefId::stringRefId("LongBlade"); + const RefId Skill::Axe = RefId::stringRefId("Axe"); + const RefId Skill::Spear = RefId::stringRefId("Spear"); + const RefId Skill::Athletics = RefId::stringRefId("Athletics"); + const RefId Skill::Enchant = RefId::stringRefId("Enchant"); + const RefId Skill::Destruction = RefId::stringRefId("Destruction"); + const RefId Skill::Alteration = RefId::stringRefId("Alteration"); + const RefId Skill::Illusion = RefId::stringRefId("Illusion"); + const RefId Skill::Conjuration = RefId::stringRefId("Conjuration"); + const RefId Skill::Mysticism = RefId::stringRefId("Mysticism"); + const RefId Skill::Restoration = RefId::stringRefId("Restoration"); + const RefId Skill::Alchemy = RefId::stringRefId("Alchemy"); + const RefId Skill::Unarmored = RefId::stringRefId("Unarmored"); + const RefId Skill::Security = RefId::stringRefId("Security"); + const RefId Skill::Sneak = RefId::stringRefId("Sneak"); + const RefId Skill::Acrobatics = RefId::stringRefId("Acrobatics"); + const RefId Skill::LightArmor = RefId::stringRefId("LightArmor"); + const RefId Skill::ShortBlade = RefId::stringRefId("ShortBlade"); + const RefId Skill::Marksman = RefId::stringRefId("Marksman"); + const RefId Skill::Mercantile = RefId::stringRefId("Mercantile"); + const RefId Skill::Speechcraft = RefId::stringRefId("Speechcraft"); + const RefId Skill::HandToHand = RefId::stringRefId("HandToHand"); void Skill::load(ESMReader& esm, bool& isDeleted) { @@ -102,19 +91,49 @@ namespace ESM mDescription.clear(); } + static const RefId sSkills[] = { + Skill::Block, + Skill::Armorer, + Skill::MediumArmor, + Skill::HeavyArmor, + Skill::BluntWeapon, + Skill::LongBlade, + Skill::Axe, + Skill::Spear, + Skill::Athletics, + Skill::Enchant, + Skill::Destruction, + Skill::Alteration, + Skill::Illusion, + Skill::Conjuration, + Skill::Mysticism, + Skill::Restoration, + Skill::Alchemy, + Skill::Unarmored, + Skill::Security, + Skill::Sneak, + Skill::Acrobatics, + Skill::LightArmor, + Skill::ShortBlade, + Skill::Marksman, + Skill::Mercantile, + Skill::Speechcraft, + Skill::HandToHand, + }; + RefId Skill::indexToRefId(int index) { if (index < 0 || index >= Length) return RefId(); - return RefId::index(sRecordId, static_cast(index)); + return sSkills[index]; } int Skill::refIdToIndex(RefId id) { - if (const IndexRefId* index = id.getIf()) + for (int i = 0; i < Length; ++i) { - if (index->getRecordType() == sRecordId) - return index->getValue(); + if (sSkills[i] == id) + return i; } return -1; } diff --git a/components/esm3/loadskil.hpp b/components/esm3/loadskil.hpp index f8e3390fa1..57680e56eb 100644 --- a/components/esm3/loadskil.hpp +++ b/components/esm3/loadskil.hpp @@ -61,37 +61,34 @@ namespace ESM float mWerewolfValue{}; std::optional mSchool; - static constexpr IndexRefId Block{ sRecordId, 0 }; - static constexpr IndexRefId Armorer{ sRecordId, 1 }; - static constexpr IndexRefId MediumArmor{ sRecordId, 2 }; - static constexpr IndexRefId HeavyArmor{ sRecordId, 3 }; - static constexpr IndexRefId BluntWeapon{ sRecordId, 4 }; - static constexpr IndexRefId LongBlade{ sRecordId, 5 }; - static constexpr IndexRefId Axe{ sRecordId, 6 }; - static constexpr IndexRefId Spear{ sRecordId, 7 }; - static constexpr IndexRefId Athletics{ sRecordId, 8 }; - static constexpr IndexRefId Enchant{ sRecordId, 9 }; - static constexpr IndexRefId Destruction{ sRecordId, 10 }; - static constexpr IndexRefId Alteration{ sRecordId, 11 }; - static constexpr IndexRefId Illusion{ sRecordId, 12 }; - static constexpr IndexRefId Conjuration{ sRecordId, 13 }; - static constexpr IndexRefId Mysticism{ sRecordId, 14 }; - static constexpr IndexRefId Restoration{ sRecordId, 15 }; - static constexpr IndexRefId Alchemy{ sRecordId, 16 }; - static constexpr IndexRefId Unarmored{ sRecordId, 17 }; - static constexpr IndexRefId Security{ sRecordId, 18 }; - static constexpr IndexRefId Sneak{ sRecordId, 19 }; - static constexpr IndexRefId Acrobatics{ sRecordId, 20 }; - static constexpr IndexRefId LightArmor{ sRecordId, 21 }; - static constexpr IndexRefId ShortBlade{ sRecordId, 22 }; - static constexpr IndexRefId Marksman{ sRecordId, 23 }; - static constexpr IndexRefId Mercantile{ sRecordId, 24 }; - static constexpr IndexRefId Speechcraft{ sRecordId, 25 }; - static constexpr IndexRefId HandToHand{ sRecordId, 26 }; + static const RefId Block; + static const RefId Armorer; + static const RefId MediumArmor; + static const RefId HeavyArmor; + static const RefId BluntWeapon; + static const RefId LongBlade; + static const RefId Axe; + static const RefId Spear; + static const RefId Athletics; + static const RefId Enchant; + static const RefId Destruction; + static const RefId Alteration; + static const RefId Illusion; + static const RefId Conjuration; + static const RefId Mysticism; + static const RefId Restoration; + static const RefId Alchemy; + static const RefId Unarmored; + static const RefId Security; + static const RefId Sneak; + static const RefId Acrobatics; + static const RefId LightArmor; + static const RefId ShortBlade; + static const RefId Marksman; + static const RefId Mercantile; + static const RefId Speechcraft; + static const RefId HandToHand; static constexpr int Length = 27; - static const std::string sSkillNames[Length]; - - static int stringToSkillId(std::string_view skill); void load(ESMReader& esm, bool& isDeleted); void save(ESMWriter& esm, bool isDeleted = false) const; From f7be94aa21aff3a8a9e712a785e86bb80fe7194a Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 18 Jun 2023 09:37:41 +0200 Subject: [PATCH 3/5] Address feedback --- apps/openmw/mwlua/luabindings.cpp | 12 +++++++----- apps/openmw/mwlua/magicbindings.cpp | 2 +- apps/openmw/mwlua/types/book.cpp | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index a204287b88..5918095707 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/statemanager.hpp" @@ -157,15 +158,16 @@ namespace MWLua }; // TODO: deprecate this and provide access to the store instead - sol::table skill(context.mLua->sol(), sol::create); - api["SKILL"] = LuaUtil::makeStrictReadOnly(skill); + sol::table skills(context.mLua->sol(), sol::create); + api["SKILL"] = LuaUtil::makeStrictReadOnly(skills); for (int i = 0; i < ESM::Skill::Length; ++i) { - std::string id = ESM::Skill::indexToRefId(i).serializeText(); - std::string key = id; + ESM::RefId skill = ESM::Skill::indexToRefId(i); + std::string id = skill.serializeText(); + std::string key = Misc::StringUtils::lowerCase(skill.getRefIdString()); // force first character to uppercase for backwards compatability key[0] += 'A' - 'a'; - skill[key] = id; + skills[key] = id; } sol::table attribute(context.mLua->sol(), sol::create); diff --git a/apps/openmw/mwlua/magicbindings.cpp b/apps/openmw/mwlua/magicbindings.cpp index 6247fc6216..586c50be6d 100644 --- a/apps/openmw/mwlua/magicbindings.cpp +++ b/apps/openmw/mwlua/magicbindings.cpp @@ -622,7 +622,7 @@ namespace MWLua if (rec->mData.mFlags & ESM::MagicEffect::TargetSkill) { - ESM::RefId skill = ESM::RefId::stringRefId(argStr.value()); + ESM::RefId skill = ESM::RefId::deserializeText(argStr.value()); key = MWMechanics::EffectKey(id, ESM::Skill::refIdToIndex(skill)); } } diff --git a/apps/openmw/mwlua/types/book.cpp b/apps/openmw/mwlua/types/book.cpp index 97e51059d0..4b40837604 100644 --- a/apps/openmw/mwlua/types/book.cpp +++ b/apps/openmw/mwlua/types/book.cpp @@ -41,7 +41,7 @@ namespace book.mData.mValue = rec["value"]; book.mData.mIsScroll = rec["isScroll"]; - ESM::RefId skill = ESM::RefId::stringRefId(rec["skill"].get()); + ESM::RefId skill = ESM::RefId::deserializeText(rec["skill"].get()); book.mData.mSkillId = -1; if (!skill.empty()) From cd8f2355c0f92c12f226978d2363ada7b8a355ef Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Fri, 14 Jul 2023 17:33:32 +0200 Subject: [PATCH 4/5] Only allow StringRefId for Skill ids --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/collection.hpp | 8 ++++ apps/openmw/mwlua/stats.cpp | 2 +- components/esm3/loadskil.cpp | 58 +++++++++++++------------- components/esm3/loadskil.hpp | 58 +++++++++++++------------- 5 files changed, 68 insertions(+), 60 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 84adfb2b87..f604608c7b 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -204,7 +204,7 @@ void CSMDoc::Document::createBase() for (int i = 0; i < ESM::Skill::Length; ++i) { ESM::Skill record; - record.mId = ESM::Skill::indexToRefId(i); + record.mId = *ESM::Skill::indexToRefId(i).getIf(); record.blank(); getData().getSkills().add(record); diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 17207ae154..9db6b3b042 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -15,6 +15,7 @@ #include #include +#include #include #include "collectionbase.hpp" @@ -86,6 +87,13 @@ namespace CSMWorld return ESM::RefId::stringRefId(LandTexture::createUniqueRecordId(record.mPluginIndex, record.mIndex)); } + inline void setRecordId(const ESM::RefId& id, ESM::Skill& record) + { + if (const auto* skillId = id.getIf()) + record.mId = *skillId; + throw std::runtime_error("Invalid skill id: " + id.toDebugString()); + } + /// \brief Single-type record collection template class Collection : public CollectionBase diff --git a/apps/openmw/mwlua/stats.cpp b/apps/openmw/mwlua/stats.cpp index f8dde1e68d..1eb96ebad0 100644 --- a/apps/openmw/mwlua/stats.cpp +++ b/apps/openmw/mwlua/stats.cpp @@ -392,6 +392,6 @@ namespace MWLua sol::table skills(context.mLua->sol(), sol::create); npcStats["skills"] = LuaUtil::makeReadOnly(skills); for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get()) - skills[skill.mId.serializeText()] = addIndexedAccessor(skill.mId); + skills[ESM::RefId(skill.mId).serializeText()] = addIndexedAccessor(skill.mId); } } diff --git a/components/esm3/loadskil.cpp b/components/esm3/loadskil.cpp index 21549df05b..06e5371ac7 100644 --- a/components/esm3/loadskil.cpp +++ b/components/esm3/loadskil.cpp @@ -7,33 +7,33 @@ namespace ESM { - const RefId Skill::Block = RefId::stringRefId("Block"); - const RefId Skill::Armorer = RefId::stringRefId("Armorer"); - const RefId Skill::MediumArmor = RefId::stringRefId("MediumArmor"); - const RefId Skill::HeavyArmor = RefId::stringRefId("HeavyArmor"); - const RefId Skill::BluntWeapon = RefId::stringRefId("BluntWeapon"); - const RefId Skill::LongBlade = RefId::stringRefId("LongBlade"); - const RefId Skill::Axe = RefId::stringRefId("Axe"); - const RefId Skill::Spear = RefId::stringRefId("Spear"); - const RefId Skill::Athletics = RefId::stringRefId("Athletics"); - const RefId Skill::Enchant = RefId::stringRefId("Enchant"); - const RefId Skill::Destruction = RefId::stringRefId("Destruction"); - const RefId Skill::Alteration = RefId::stringRefId("Alteration"); - const RefId Skill::Illusion = RefId::stringRefId("Illusion"); - const RefId Skill::Conjuration = RefId::stringRefId("Conjuration"); - const RefId Skill::Mysticism = RefId::stringRefId("Mysticism"); - const RefId Skill::Restoration = RefId::stringRefId("Restoration"); - const RefId Skill::Alchemy = RefId::stringRefId("Alchemy"); - const RefId Skill::Unarmored = RefId::stringRefId("Unarmored"); - const RefId Skill::Security = RefId::stringRefId("Security"); - const RefId Skill::Sneak = RefId::stringRefId("Sneak"); - const RefId Skill::Acrobatics = RefId::stringRefId("Acrobatics"); - const RefId Skill::LightArmor = RefId::stringRefId("LightArmor"); - const RefId Skill::ShortBlade = RefId::stringRefId("ShortBlade"); - const RefId Skill::Marksman = RefId::stringRefId("Marksman"); - const RefId Skill::Mercantile = RefId::stringRefId("Mercantile"); - const RefId Skill::Speechcraft = RefId::stringRefId("Speechcraft"); - const RefId Skill::HandToHand = RefId::stringRefId("HandToHand"); + const SkillId Skill::Block("Block"); + const SkillId Skill::Armorer("Armorer"); + const SkillId Skill::MediumArmor("MediumArmor"); + const SkillId Skill::HeavyArmor("HeavyArmor"); + const SkillId Skill::BluntWeapon("BluntWeapon"); + const SkillId Skill::LongBlade("LongBlade"); + const SkillId Skill::Axe("Axe"); + const SkillId Skill::Spear("Spear"); + const SkillId Skill::Athletics("Athletics"); + const SkillId Skill::Enchant("Enchant"); + const SkillId Skill::Destruction("Destruction"); + const SkillId Skill::Alteration("Alteration"); + const SkillId Skill::Illusion("Illusion"); + const SkillId Skill::Conjuration("Conjuration"); + const SkillId Skill::Mysticism("Mysticism"); + const SkillId Skill::Restoration("Restoration"); + const SkillId Skill::Alchemy("Alchemy"); + const SkillId Skill::Unarmored("Unarmored"); + const SkillId Skill::Security("Security"); + const SkillId Skill::Sneak("Sneak"); + const SkillId Skill::Acrobatics("Acrobatics"); + const SkillId Skill::LightArmor("LightArmor"); + const SkillId Skill::ShortBlade("ShortBlade"); + const SkillId Skill::Marksman("Marksman"); + const SkillId Skill::Mercantile("Mercantile"); + const SkillId Skill::Speechcraft("Speechcraft"); + const SkillId Skill::HandToHand("HandToHand"); void Skill::load(ESMReader& esm, bool& isDeleted) { @@ -70,9 +70,7 @@ namespace ESM if (!hasData) esm.fail("Missing SKDT"); - // create an ID from the index and the name (only used in the editor and likely to change in the - // future) - mId = indexToRefId(index); + mId = *indexToRefId(index).getIf(); } void Skill::save(ESMWriter& esm, bool /*isDeleted*/) const diff --git a/components/esm3/loadskil.hpp b/components/esm3/loadskil.hpp index 57680e56eb..dac7745d3f 100644 --- a/components/esm3/loadskil.hpp +++ b/components/esm3/loadskil.hpp @@ -14,6 +14,8 @@ namespace ESM class ESMReader; class ESMWriter; + using SkillId = StringRefId; + struct MagicSchool { ESM::RefId mAreaSound; @@ -43,7 +45,7 @@ namespace ESM static std::string_view getRecordType() { return "Skill"; } unsigned int mRecordFlags; - RefId mId; + SkillId mId; struct SKDTstruct { @@ -61,33 +63,33 @@ namespace ESM float mWerewolfValue{}; std::optional mSchool; - static const RefId Block; - static const RefId Armorer; - static const RefId MediumArmor; - static const RefId HeavyArmor; - static const RefId BluntWeapon; - static const RefId LongBlade; - static const RefId Axe; - static const RefId Spear; - static const RefId Athletics; - static const RefId Enchant; - static const RefId Destruction; - static const RefId Alteration; - static const RefId Illusion; - static const RefId Conjuration; - static const RefId Mysticism; - static const RefId Restoration; - static const RefId Alchemy; - static const RefId Unarmored; - static const RefId Security; - static const RefId Sneak; - static const RefId Acrobatics; - static const RefId LightArmor; - static const RefId ShortBlade; - static const RefId Marksman; - static const RefId Mercantile; - static const RefId Speechcraft; - static const RefId HandToHand; + static const SkillId Block; + static const SkillId Armorer; + static const SkillId MediumArmor; + static const SkillId HeavyArmor; + static const SkillId BluntWeapon; + static const SkillId LongBlade; + static const SkillId Axe; + static const SkillId Spear; + static const SkillId Athletics; + static const SkillId Enchant; + static const SkillId Destruction; + static const SkillId Alteration; + static const SkillId Illusion; + static const SkillId Conjuration; + static const SkillId Mysticism; + static const SkillId Restoration; + static const SkillId Alchemy; + static const SkillId Unarmored; + static const SkillId Security; + static const SkillId Sneak; + static const SkillId Acrobatics; + static const SkillId LightArmor; + static const SkillId ShortBlade; + static const SkillId Marksman; + static const SkillId Mercantile; + static const SkillId Speechcraft; + static const SkillId HandToHand; static constexpr int Length = 27; void load(ESMReader& esm, bool& isDeleted); From 2a1d520c9ee860a3c378b30a125411880152761b Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 17 Jul 2023 19:37:28 +0200 Subject: [PATCH 5/5] Address feedback --- components/esm3/loadskil.cpp | 6 ++++-- components/esm3/npcstats.cpp | 2 +- components/esm3/player.cpp | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/components/esm3/loadskil.cpp b/components/esm3/loadskil.cpp index 06e5371ac7..8661230e8c 100644 --- a/components/esm3/loadskil.cpp +++ b/components/esm3/loadskil.cpp @@ -5,6 +5,8 @@ #include +#include + namespace ESM { const SkillId Skill::Block("Block"); @@ -42,7 +44,7 @@ namespace ESM bool hasIndex = false; bool hasData = false; - int index = -1; + int32_t index = -1; while (esm.hasMoreSubs()) { esm.getSubName(); @@ -89,7 +91,7 @@ namespace ESM mDescription.clear(); } - static const RefId sSkills[] = { + static const RefId sSkills[Skill::Length] = { Skill::Block, Skill::Armorer, Skill::MediumArmor, diff --git a/components/esm3/npcstats.cpp b/components/esm3/npcstats.cpp index e2ee4f50d4..c34205f6c2 100644 --- a/components/esm3/npcstats.cpp +++ b/components/esm3/npcstats.cpp @@ -49,7 +49,7 @@ namespace ESM mWerewolfDeprecatedData = true; std::vector> skills(mSkills.begin(), mSkills.end()); - for (int i = 0; i < ESM::Skill::Length; ++i) + for (size_t i = 0; i < std::size(mSkills); ++i) { StatState skill; skill.load(esm, intFallback); diff --git a/components/esm3/player.cpp b/components/esm3/player.cpp index 9c2cad86d1..3b52f8d779 100644 --- a/components/esm3/player.cpp +++ b/components/esm3/player.cpp @@ -54,7 +54,7 @@ namespace ESM = esm.getFormatVersion() <= MaxClearModifiersFormatVersion && !mObject.mNpcStats.mIsWerewolf; if (esm.hasMoreSubs()) { - for (int i = 0; i < Attribute::Length; ++i) + for (size_t i = 0; i < std::size(mSaveAttributes); ++i) { StatState attribute; attribute.load(esm, intFallback); @@ -64,7 +64,7 @@ namespace ESM if (mObject.mNpcStats.mIsWerewolf) mObject.mCreatureStats.mAttributes[i] = attribute; } - for (int i = 0; i < Skill::Length; ++i) + for (size_t i = 0; i < std::size(mSaveSkills); ++i) { StatState skill; skill.load(esm, intFallback);