diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index a142bac3c5..900c28164f 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -622,18 +622,15 @@ namespace EsmTool std::cout << " Description: " << mData.mDescription << std::endl; std::cout << " Playable: " << mData.mData.mIsPlayable << std::endl; std::cout << " AI Services: " << Misc::StringUtils::format("0x%08X", mData.mData.mServices) << std::endl; - std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute[0]) << " (" << mData.mData.mAttribute[0] - << ")" << std::endl; - std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute[1]) << " (" << mData.mData.mAttribute[1] - << ")" << std::endl; + for (size_t i = 0; i < mData.mData.mAttribute.size(); ++i) + std::cout << " Attribute" << (i + 1) << ": " << attributeLabel(mData.mData.mAttribute[i]) << " (" + << mData.mData.mAttribute[i] << ")" << std::endl; std::cout << " Specialization: " << specializationLabel(mData.mData.mSpecialization) << " (" << mData.mData.mSpecialization << ")" << std::endl; - for (int i = 0; i != 5; i++) - std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][0]) << " (" << mData.mData.mSkills[i][0] - << ")" << std::endl; - for (int i = 0; i != 5; i++) - std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1]) << " (" << mData.mData.mSkills[i][1] - << ")" << std::endl; + for (const auto& skills : mData.mData.mSkills) + std::cout << " Minor Skill: " << skillLabel(skills[0]) << " (" << skills[0] << ")" << std::endl; + for (const auto& skills : mData.mData.mSkills) + std::cout << " Major Skill: " << skillLabel(skills[1]) << " (" << skills[1] << ")" << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; } diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index e608195a5f..0cbf5562fc 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -50,23 +50,32 @@ void CSMTools::ClassCheckStage::perform(int stage, CSMDoc::Messages& messages) messages.add(id, "Description of a playable class is missing", "", CSMDoc::Message::Severity_Warning); // test for invalid attributes - for (int i = 0; i < 2; ++i) - if (class_.mData.mAttribute[i] == -1) + std::map attributeCount; + for (size_t i = 0; i < class_.mData.mAttribute.size(); ++i) + { + int attribute = class_.mData.mAttribute[i]; + if (attribute == -1) + messages.add(id, "Attribute #" + std::to_string(i) + " is not set", {}, CSMDoc::Message::Severity_Error); + else { - messages.add(id, "Attribute #" + std::to_string(i) + " is not set", "", CSMDoc::Message::Severity_Error); + auto it = attributeCount.find(attribute); + if (it == attributeCount.end()) + attributeCount.emplace(attribute, 1); + else + { + if (it->second == 1) + messages.add(id, "Same attribute is listed twice", {}, CSMDoc::Message::Severity_Error); + ++it->second; + } } - - if (class_.mData.mAttribute[0] == class_.mData.mAttribute[1] && class_.mData.mAttribute[0] != -1) - { - messages.add(id, "Same attribute is listed twice", "", CSMDoc::Message::Severity_Error); } // test for non-unique skill std::map skills; // ID, number of occurrences - for (int i = 0; i < 5; ++i) - for (int i2 = 0; i2 < 2; ++i2) - ++skills[class_.mData.mSkills[i][i2]]; + for (const auto& s : class_.mData.mSkills) + for (int skill : s) + ++skills[skill]; for (auto& skill : skills) if (skill.second > 1) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 988de3c57f..2119434515 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -98,10 +98,9 @@ namespace // class bonus const ESM::Class* class_ = MWBase::Environment::get().getESMStore()->get().find(npc->mClass); - for (int i = 0; i < 2; ++i) + for (int attribute : class_->mData.mAttribute) { - int attribute = class_->mData.mAttribute[i]; - if (attribute >= 0 && attribute < 8) + if (attribute >= 0 && attribute < ESM::Attribute::Length) { creatureStats.setAttribute(attribute, creatureStats.getAttribute(attribute).getBase() + 10); } @@ -121,14 +120,11 @@ namespace // is this a minor or major skill? float add = 0.2f; - for (int k = 0; k < 5; ++k) + for (const auto& skills : class_->mData.mSkills) { - if (class_->mData.mSkills[k][0] == j) + if (skills[0] == j) add = 0.5; - } - for (int k = 0; k < 5; ++k) - { - if (class_->mData.mSkills[k][1] == j) + if (skills[1] == j) add = 1.0; } modifierSum += add; @@ -149,8 +145,8 @@ namespace else if (class_->mData.mSpecialization == ESM::Class::Stealth) multiplier += 1; - if (class_->mData.mAttribute[0] == ESM::Attribute::Endurance - || class_->mData.mAttribute[1] == ESM::Attribute::Endurance) + if (std::find(class_->mData.mAttribute.begin(), class_->mData.mAttribute.end(), ESM::Attribute::Endurance) + != class_->mData.mAttribute.end()) multiplier += 1; creatureStats.setHealth(floor(0.5f * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1)); @@ -183,9 +179,9 @@ namespace { int bonus = (i == 0) ? 10 : 25; - for (int i2 = 0; i2 < 5; ++i2) + for (const auto& skills : class_->mData.mSkills) { - int index = class_->mData.mSkills[i2][i]; + int index = skills[i]; if (index >= 0 && index < ESM::Skill::Length) { npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + bonus); @@ -206,10 +202,10 @@ namespace if (bonusIt != race->mData.mBonus.end()) raceBonus = bonusIt->mBonus; - for (int k = 0; k < 5; ++k) + for (const auto& skills : class_->mData.mSkills) { // is this a minor or major skill? - if ((class_->mData.mSkills[k][0] == skillIndex) || (class_->mData.mSkills[k][1] == skillIndex)) + if (std::find(skills.begin(), skills.end(), skillIndex) != skills.end()) { majorMultiplier = 1.0f; break; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index e0ac94db93..586e8b766d 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -473,15 +473,14 @@ namespace MWGui klass.mRecordFlags = 0; std::vector attributes = mCreateClassDialog->getFavoriteAttributes(); - assert(attributes.size() == 2); - klass.mData.mAttribute[0] = attributes[0]; - klass.mData.mAttribute[1] = attributes[1]; + assert(attributes.size() == klass.mData.mAttribute.size()); + std::copy(attributes.begin(), attributes.end(), klass.mData.mAttribute.begin()); std::vector majorSkills = mCreateClassDialog->getMajorSkills(); std::vector minorSkills = mCreateClassDialog->getMinorSkills(); - assert(majorSkills.size() >= sizeof(klass.mData.mSkills) / sizeof(klass.mData.mSkills[0])); - assert(minorSkills.size() >= sizeof(klass.mData.mSkills) / sizeof(klass.mData.mSkills[0])); - for (size_t i = 0; i < sizeof(klass.mData.mSkills) / sizeof(klass.mData.mSkills[0]); ++i) + assert(majorSkills.size() >= klass.mData.mSkills.size()); + 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]; klass.mData.mSkills[i][0] = minorSkills[i]; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 864740aac5..1e7dafe92d 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -264,7 +264,7 @@ namespace MWGui ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId()); ToolTips::createAttributeToolTip(mFavoriteAttribute[1], mFavoriteAttribute[1]->getAttributeId()); - for (int i = 0; i < 5; ++i) + for (size_t i = 0; i < klass->mData.mSkills.size(); ++i) { mMinorSkill[i]->setSkillNumber(klass->mData.mSkills[i][0]); mMajorSkill[i]->setSkillNumber(klass->mData.mSkills[i][1]); diff --git a/apps/openmw/mwgui/statswatcher.cpp b/apps/openmw/mwgui/statswatcher.cpp index b03eab6869..6ad574a5a2 100644 --- a/apps/openmw/mwgui/statswatcher.cpp +++ b/apps/openmw/mwgui/statswatcher.cpp @@ -124,10 +124,11 @@ namespace MWGui = MWBase::Environment::get().getESMStore()->get().find(watchedRecord->mClass); setValue("class", cls->mName); - MWBase::WindowManager::SkillList majorSkills(5); - MWBase::WindowManager::SkillList minorSkills(5); + size_t size = cls->mData.mSkills.size(); + MWBase::WindowManager::SkillList majorSkills(size); + MWBase::WindowManager::SkillList minorSkills(size); - for (int i = 0; i < 5; ++i) + for (size_t i = 0; i < size; ++i) { minorSkills[i] = cls->mData.mSkills[i][0]; majorSkills[i] = cls->mData.mSkills[i][1]; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 7f83f0ad8c..f5fa410725 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -191,10 +191,9 @@ namespace MWMechanics { const ESM::Class* class_ = esmStore.get().find(player->mClass); - for (int i = 0; i < 2; ++i) + for (int attribute : class_->mData.mAttribute) { - int attribute = class_->mData.mAttribute[i]; - if (attribute >= 0 && attribute < 8) + if (attribute >= 0 && attribute < ESM::Attribute::Length) { creatureStats.setAttribute(attribute, creatureStats.getAttribute(attribute).getBase() + 10); } @@ -204,11 +203,11 @@ namespace MWMechanics { int bonus = i == 0 ? 10 : 25; - for (int i2 = 0; i2 < 5; ++i2) + for (const auto& skills : class_->mData.mSkills) { - int index = class_->mData.mSkills[i2][i]; + int index = skills[i]; - if (index >= 0 && index < 27) + if (index >= 0 && index < ESM::Skill::Length) { npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + bonus); } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index dd21a85305..9f1010194c 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -162,14 +162,14 @@ float MWMechanics::NpcStats::getSkillProgressRequirement(int skillIndex, const E float typeFactor = gmst.find("fMiscSkillBonus")->mValue.getFloat(); - for (int i = 0; i < 5; ++i) + for (const auto& skills : class_.mData.mSkills) { - if (class_.mData.mSkills[i][0] == skillIndex) + if (skills[0] == skillIndex) { typeFactor = gmst.find("fMinorSkillBonus")->mValue.getFloat(); break; } - else if (class_.mData.mSkills[i][1] == skillIndex) + else if (skills[1] == skillIndex) { typeFactor = gmst.find("fMajorSkillBonus")->mValue.getFloat(); break; @@ -235,15 +235,15 @@ void MWMechanics::NpcStats::increaseSkill( // is this a minor or major skill? int increase = gmst.find("iLevelupMiscMultAttriubte")->mValue.getInteger(); // Note: GMST has a typo - for (int k = 0; k < 5; ++k) + for (const auto& skills : class_.mData.mSkills) { - if (class_.mData.mSkills[k][0] == skillIndex) + if (skills[0] == skillIndex) { mLevelProgress += gmst.find("iLevelUpMinorMult")->mValue.getInteger(); increase = gmst.find("iLevelUpMinorMultAttribute")->mValue.getInteger(); break; } - else if (class_.mData.mSkills[k][1] == skillIndex) + else if (skills[1] == skillIndex) { mLevelProgress += gmst.find("iLevelUpMajorMult")->mValue.getInteger(); increase = gmst.find("iLevelUpMajorMultAttribute")->mValue.getInteger(); diff --git a/components/esm3/loadclas.cpp b/components/esm3/loadclas.cpp index a76855eb7f..9569c1a61d 100644 --- a/components/esm3/loadclas.cpp +++ b/components/esm3/loadclas.cpp @@ -13,18 +13,12 @@ namespace ESM int& Class::CLDTstruct::getSkill(int index, bool major) { - if (index < 0 || index >= 5) - throw std::logic_error("skill index out of range"); - - return mSkills[index][major ? 1 : 0]; + return mSkills.at(index)[major ? 1 : 0]; } int Class::CLDTstruct::getSkill(int index, bool major) const { - if (index < 0 || index >= 5) - throw std::logic_error("skill index out of range"); - - return mSkills[index][major ? 1 : 0]; + return mSkills.at(index)[major ? 1 : 0]; } void Class::load(ESMReader& esm, bool& isDeleted) @@ -91,13 +85,12 @@ namespace ESM mName.clear(); mDescription.clear(); - mData.mAttribute[0] = mData.mAttribute[1] = 0; + mData.mAttribute.fill(0); mData.mSpecialization = 0; mData.mIsPlayable = 0; mData.mServices = 0; - for (int i = 0; i < 5; ++i) - for (int i2 = 0; i2 < 2; ++i2) - mData.mSkills[i][i2] = 0; + for (auto& skills : mData.mSkills) + skills.fill(0); } } diff --git a/components/esm3/loadclas.hpp b/components/esm3/loadclas.hpp index f47f0eb2b9..4f5e9a41fa 100644 --- a/components/esm3/loadclas.hpp +++ b/components/esm3/loadclas.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_ESM_CLAS_H #define OPENMW_ESM_CLAS_H +#include #include #include "components/esm/defs.hpp" @@ -33,9 +34,9 @@ namespace ESM struct CLDTstruct { - int mAttribute[2]; // Attributes that get class bonus + std::array mAttribute; // Attributes that get class bonus int mSpecialization; // 0 = Combat, 1 = Magic, 2 = Stealth - int mSkills[5][2]; // Minor and major skills. + std::array, 5> mSkills; // Minor and major skills. int mIsPlayable; // 0x0001 - Playable class int mServices;