diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index c203af8a48..8227fcfcf0 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1032,8 +1032,8 @@ namespace EsmTool std::cout << " Area Static: " << mData.mArea << std::endl; if (!mData.mAreaSound.empty()) std::cout << " Area Sound: " << mData.mAreaSound << std::endl; - std::cout << " School: " << schoolLabel(mData.mData.mSchool) << " (" << mData.mData.mSchool << ")" - << std::endl; + std::cout << " School: " << schoolLabel(ESM::MagicSchool::skillRefIdToIndex(mData.mData.mSchool)) << " (" + << mData.mData.mSchool << ")" << std::endl; std::cout << " Base Cost: " << mData.mData.mBaseCost << std::endl; std::cout << " Unknown 1: " << mData.mData.mUnknown1 << std::endl; std::cout << " Speed: " << mData.mData.mSpeed << std::endl; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 6ce7b96815..3f137fadb7 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2040,13 +2040,16 @@ namespace CSMWorld { } - QVariant get(const Record& record) const override { return record.get().mData.mSchool; } + QVariant get(const Record& record) const override + { + return ESM::MagicSchool::skillRefIdToIndex(record.get().mData.mSchool); + } void set(Record& record, const QVariant& data) override { ESXRecordT record2 = record.get(); - record2.mData.mSchool = data.toInt(); + record2.mData.mSchool = ESM::MagicSchool::indexToSkillRefId(data.toInt()); record.setModified(record2); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7fa58589df..fdf945f2dc 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -31,9 +31,6 @@ namespace MWGui { - std::string ToolTips::sSchoolNames[] = { "#{sSchoolAlteration}", "#{sSchoolConjuration}", "#{sSchoolDestruction}", - "#{sSchoolIllusion}", "#{sSchoolMysticism}", "#{sSchoolRestoration}" }; - ToolTips::ToolTips() : Layout("openmw_tooltips.layout") , mFocusToolTipX(0.0) @@ -227,8 +224,9 @@ namespace MWGui { ToolTipInfo info; - const ESM::Spell* spell = MWBase::Environment::get().getESMStore()->get().find( - ESM::RefId::deserialize(focus->getUserString("Spell"))); + const auto& store = MWBase::Environment::get().getESMStore(); + const ESM::Spell* spell + = store->get().find(ESM::RefId::deserialize(focus->getUserString("Spell"))); info.caption = spell->mName; Widgets::SpellEffectList effects; for (const ESM::ENAMstruct& spellEffect : spell->mEffects.mList) @@ -250,8 +248,9 @@ namespace MWGui spell)) // display school of spells that contribute to skill progress { MWWorld::Ptr player = MWMechanics::getPlayer(); - int school = MWMechanics::getSpellSchool(spell, player); - info.text = "#{sSchool}: " + sSchoolNames[school]; + const auto& school + = store->get().find(MWMechanics::getSpellSchool(spell, player))->mSchool; + info.text = "#{sSchool}: " + MyGUI::TextIterator::toTagsString(school->mName).asUTF8(); } const std::string& cost = focus->getUserString("SpellCost"); if (!cost.empty() && cost != "0") @@ -944,7 +943,8 @@ namespace MWGui void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, short id) { - const ESM::MagicEffect* effect = MWBase::Environment::get().getESMStore()->get().find(id); + const auto& store = MWBase::Environment::get().getESMStore(); + const ESM::MagicEffect* effect = store->get().find(id); const std::string& name = ESM::MagicEffect::indexToGmstString(id); std::string icon = effect->mIcon; @@ -956,7 +956,11 @@ namespace MWGui widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); widget->setUserString("Caption_MagicEffectName", "#{" + name + "}"); widget->setUserString("Caption_MagicEffectDescription", effect->mDescription); - widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + sSchoolNames[effect->mData.mSchool]); + widget->setUserString("Caption_MagicEffectSchool", + "#{sSchool}: " + + MyGUI::TextIterator::toTagsString( + store->get().find(effect->mData.mSchool)->mSchool->mName) + .asUTF8()); widget->setUserString("ImageTexture_MagicEffectImage", icon); } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 4fa0803eaa..500c3bea44 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -122,8 +122,6 @@ namespace MWGui /// Adjust position for a tooltip so that it doesn't leave the screen and does not obscure the mouse cursor void position(MyGUI::IntPoint& position, MyGUI::IntSize size, MyGUI::IntSize viewportSize); - static std::string sSchoolNames[6]; - int mHorizontalScrollIndex; float mDelay; diff --git a/apps/openmw/mwlua/magicbindings.cpp b/apps/openmw/mwlua/magicbindings.cpp index 941ab2b4eb..4e01f4c79d 100644 --- a/apps/openmw/mwlua/magicbindings.cpp +++ b/apps/openmw/mwlua/magicbindings.cpp @@ -358,8 +358,8 @@ namespace MWLua .find(ESM::MagicEffect::indexToGmstString(rec.mIndex)) ->mValue.getString(); }); - magicEffectT["school"] - = sol::readonly_property([](const ESM::MagicEffect& rec) -> int { return rec.mData.mSchool; }); + magicEffectT["school"] = sol::readonly_property( + [](const ESM::MagicEffect& rec) -> int { return ESM::MagicSchool::skillRefIdToIndex(rec.mData.mSchool); }); magicEffectT["baseCost"] = sol::readonly_property([](const ESM::MagicEffect& rec) -> float { return rec.mData.mBaseCost; }); magicEffectT["color"] = sol::readonly_property([](const ESM::MagicEffect& rec) -> Misc::Color { diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 64cc4e8597..08c76e900f 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -35,30 +35,18 @@ namespace MWMechanics static const float fNPCbaseMagickaMult = gmst.find("fNPCbaseMagickaMult")->mValue.getFloat(); float baseMagicka = fNPCbaseMagickaMult * actorAttributes.at(ESM::Attribute::Intelligence).getBase(); - static const std::string schools[] - = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" }; - static int iAutoSpellSchoolMax[6]; - static bool init = false; - if (!init) - { - for (int i = 0; i < 6; ++i) - { - const std::string& gmstName = "iAutoSpell" + schools[i] + "Max"; - iAutoSpellSchoolMax[i] = gmst.find(gmstName)->mValue.getInteger(); - } - init = true; - } - - std::map schoolCaps; - for (int i = 0; i < 6; ++i) + std::map schoolCaps; + for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get()) { + if (!skill.mSchool) + continue; SchoolCaps caps; caps.mCount = 0; - caps.mLimit = iAutoSpellSchoolMax[i]; - caps.mReachedLimit = iAutoSpellSchoolMax[i] <= 0; + caps.mLimit = skill.mSchool->mAutoCalcMax; + caps.mReachedLimit = skill.mSchool->mAutoCalcMax <= 0; caps.mMinCost = std::numeric_limits::max(); caps.mWeakestSpell = ESM::RefId(); - schoolCaps[i] = caps; + schoolCaps[skill.mId] = caps; } std::vector selectedSpells; @@ -84,10 +72,10 @@ namespace MWMechanics if (!attrSkillCheck(&spell, actorSkills, actorAttributes)) continue; - int school; + ESM::RefId school; float skillTerm; calcWeakestSchool(&spell, actorSkills, school, skillTerm); - assert(school >= 0 && school < 6); + assert(!school.empty()); SchoolCaps& cap = schoolCaps[school]; if (cap.mReachedLimit && spellCost <= cap.mMinCost) @@ -183,7 +171,7 @@ namespace MWMechanics static const float fAutoPCSpellChance = esmStore.get().find("fAutoPCSpellChance")->mValue.getFloat(); - if (calcAutoCastChance(&spell, actorSkills, actorAttributes, -1) < fAutoPCSpellChance) + if (calcAutoCastChance(&spell, actorSkills, actorAttributes, {}) < fAutoPCSpellChance) continue; if (!attrSkillCheck(&spell, actorSkills, actorAttributes)) @@ -260,7 +248,7 @@ namespace MWMechanics } void calcWeakestSchool(const ESM::Spell* spell, const std::map& actorSkills, - int& effectiveSchool, float& skillTerm) + ESM::RefId& effectiveSchool, float& skillTerm) { // Morrowind for some reason uses a formula slightly different from magicka cost calculation float minChance = std::numeric_limits::max(); @@ -299,8 +287,7 @@ namespace MWMechanics x *= 1.5f; float s = 0.f; - ESM::RefId skill = spellSchoolToSkill(magicEffect->mData.mSchool); - auto found = actorSkills.find(skill); + auto found = actorSkills.find(magicEffect->mData.mSchool); if (found != actorSkills.end()) s = 2.f * found->second.getBase(); if (s - x < minChance) @@ -313,7 +300,7 @@ namespace MWMechanics } float calcAutoCastChance(const ESM::Spell* spell, const std::map& actorSkills, - const std::map& actorAttributes, int effectiveSchool) + const std::map& actorAttributes, ESM::RefId effectiveSchool) { if (spell->mData.mType != ESM::Spell::ST_Spell) return 100.f; @@ -322,10 +309,9 @@ namespace MWMechanics return 100.f; float skillTerm = 0; - if (effectiveSchool != -1) + if (!effectiveSchool.empty()) { - ESM::RefId skill = spellSchoolToSkill(effectiveSchool); - auto found = actorSkills.find(skill); + auto found = actorSkills.find(effectiveSchool); if (found != actorSkills.end()) skillTerm = 2.f * found->second.getBase(); } diff --git a/apps/openmw/mwmechanics/autocalcspell.hpp b/apps/openmw/mwmechanics/autocalcspell.hpp index 09efb34bdb..7edfd8b75e 100644 --- a/apps/openmw/mwmechanics/autocalcspell.hpp +++ b/apps/openmw/mwmechanics/autocalcspell.hpp @@ -31,10 +31,10 @@ namespace MWMechanics const std::map& actorAttributes); void calcWeakestSchool(const ESM::Spell* spell, const std::map& actorSkills, - int& effectiveSchool, float& skillTerm); + ESM::RefId& effectiveSchool, float& skillTerm); float calcAutoCastChance(const ESM::Spell* spell, const std::map& actorSkills, - const std::map& actorAttributes, int effectiveSchool); + const std::map& actorAttributes, ESM::RefId effectiveSchool); } diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 59c2a1686d..d7aa0d6b71 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -83,15 +83,14 @@ namespace MWMechanics mHitPosition, static_cast(effectInfo.mArea * 2)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) - static const std::string schools[] - = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" }; { MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); if (!effect->mAreaSound.empty()) sndMgr->playSound3D(mHitPosition, effect->mAreaSound, 1.0f, 1.0f); else - sndMgr->playSound3D( - mHitPosition, ESM::RefId::stringRefId(schools[effect->mData.mSchool] + " area"), 1.0f, 1.0f); + sndMgr->playSound3D(mHitPosition, + world->getStore().get().find(effect->mData.mSchool)->mSchool->mAreaSound, 1.0f, + 1.0f); } // Get the actors in range of the effect std::vector objects; @@ -300,8 +299,8 @@ namespace MWMechanics mSourceName = item.getClass().getName(item); mId = item.getCellRef().getRefId(); - const ESM::Enchantment* enchantment - = MWBase::Environment::get().getESMStore()->get().find(enchantmentName); + const auto& store = MWBase::Environment::get().getESMStore(); + const ESM::Enchantment* enchantment = store->get().find(enchantmentName); mSlot = slot; @@ -332,20 +331,17 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}"); // Failure sound - int school = 0; + ESM::RefId school = ESM::Skill::Alteration; if (!enchantment->mEffects.mList.empty()) { short effectId = enchantment->mEffects.mList.front().mEffectID; - const ESM::MagicEffect* magicEffect - = MWBase::Environment::get().getESMStore()->get().find(effectId); + const ESM::MagicEffect* magicEffect = store->get().find(effectId); school = magicEffect->mData.mSchool; } - static const std::string schools[] - = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" }; MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); sndMgr->playSound3D( - mCaster, ESM::RefId::stringRefId("Spell Failure " + schools[school]), 1.0f, 1.0f); + mCaster, store->get().find(school)->mSchool->mFailureSound, 1.0f, 1.0f); } return false; } @@ -401,7 +397,7 @@ namespace MWMechanics mSourceName = spell->mName; mId = spell->mId; - int school = 0; + ESM::RefId school = ESM::Skill::Alteration; bool godmode = mCaster == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); @@ -428,12 +424,9 @@ namespace MWMechanics if (fail) { // Failure sound - static const std::string schools[] - = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" }; - MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D( - mCaster, ESM::RefId::stringRefId("Spell Failure " + schools[school]), 1.0f, 1.0f); + const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get().find(school); + sndMgr->playSound3D(mCaster, skill->mSchool->mFailureSound, 1.0f, 1.0f); return false; } } @@ -444,7 +437,7 @@ namespace MWMechanics } if (!mManualSpell && mCaster == getPlayer() && spellIncreasesSkill(spell)) - mCaster.getClass().skillUsageSucceeded(mCaster, spellSchoolToSkill(school), 0); + mCaster.getClass().skillUsageSucceeded(mCaster, school, 0); // A non-actor doesn't play its spell cast effects from a character controller, so play them here if (!mCaster.getClass().isActor()) @@ -595,9 +588,6 @@ namespace MWMechanics if (animation && !mCaster.getClass().isActor()) animation->addSpellCastGlow(effect); - static const std::string schools[] - = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" }; - addedEffects.push_back(Misc::ResourceHelpers::correctMeshPath(castStatic->mModel, vfs)); MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); @@ -605,32 +595,29 @@ namespace MWMechanics sndMgr->playSound3D(mCaster, effect->mCastSound, 1.0f, 1.0f); else sndMgr->playSound3D( - mCaster, ESM::RefId::stringRefId(schools[effect->mData.mSchool] + " cast"), 1.0f, 1.0f); + mCaster, store.get().find(effect->mData.mSchool)->mSchool->mCastSound, 1.0f, 1.0f); } } void playEffects(const MWWorld::Ptr& target, const ESM::MagicEffect& magicEffect, bool playNonLooping) { + const auto& store = MWBase::Environment::get().getESMStore(); if (playNonLooping) { - static const std::string schools[] - = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" }; - MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); if (!magicEffect.mHitSound.empty()) sndMgr->playSound3D(target, magicEffect.mHitSound, 1.0f, 1.0f); else sndMgr->playSound3D( - target, ESM::RefId::stringRefId(schools[magicEffect.mData.mSchool] + " hit"), 1.0f, 1.0f); + target, store->get().find(magicEffect.mData.mSchool)->mSchool->mHitSound, 1.0f, 1.0f); } // Add VFX const ESM::Static* castStatic; if (!magicEffect.mHit.empty()) - castStatic = MWBase::Environment::get().getESMStore()->get().find(magicEffect.mHit); + castStatic = store->get().find(magicEffect.mHit); else - castStatic = MWBase::Environment::get().getESMStore()->get().find( - ESM::RefId::stringRefId("VFX_DefaultHit")); + castStatic = store->get().find(ESM::RefId::stringRefId("VFX_DefaultHit")); bool loop = (magicEffect.mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); diff --git a/apps/openmw/mwmechanics/spellutil.cpp b/apps/openmw/mwmechanics/spellutil.cpp index 7f032bd181..2a63a3a444 100644 --- a/apps/openmw/mwmechanics/spellutil.cpp +++ b/apps/openmw/mwmechanics/spellutil.cpp @@ -37,19 +37,6 @@ namespace MWMechanics } } - ESM::RefId spellSchoolToSkill(int school) - { - static const std::array schoolSkillArray{ - ESM::Skill::Alteration, - ESM::Skill::Conjuration, - ESM::Skill::Destruction, - ESM::Skill::Illusion, - ESM::Skill::Mysticism, - ESM::Skill::Restoration, - }; - return schoolSkillArray.at(school); - } - float calcEffectCost( const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect, const EffectCostMethod method) { @@ -153,7 +140,7 @@ namespace MWMechanics return enchantment.mData.mCharge; } - float calcSpellBaseSuccessChance(const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool) + float calcSpellBaseSuccessChance(const ESM::Spell* spell, const MWWorld::Ptr& actor, ESM::RefId* effectiveSchool) { // Morrowind for some reason uses a formula slightly different from magicka cost calculation float y = std::numeric_limits::max(); @@ -180,7 +167,7 @@ namespace MWMechanics ->mValue.getFloat(); x *= fEffectCostMult; - float s = 2.0f * actor.getClass().getSkill(actor, spellSchoolToSkill(magicEffect->mData.mSchool)); + float s = 2.0f * actor.getClass().getSkill(actor, magicEffect->mData.mSchool); if (s - x < y) { y = s - x; @@ -201,7 +188,7 @@ namespace MWMechanics } float getSpellSuccessChance( - const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap, bool checkMagicka) + const ESM::Spell* spell, const MWWorld::Ptr& actor, ESM::RefId* effectiveSchool, bool cap, bool checkMagicka) { // NB: Base chance is calculated here because the effective school pointer must be filled float baseChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool); @@ -239,23 +226,23 @@ namespace MWMechanics } float getSpellSuccessChance( - const ESM::RefId& spellId, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap, bool checkMagicka) + const ESM::RefId& spellId, const MWWorld::Ptr& actor, ESM::RefId* effectiveSchool, bool cap, bool checkMagicka) { if (const auto spell = MWBase::Environment::get().getESMStore()->get().search(spellId)) return getSpellSuccessChance(spell, actor, effectiveSchool, cap, checkMagicka); return 0.f; } - int getSpellSchool(const ESM::RefId& spellId, const MWWorld::Ptr& actor) + ESM::RefId getSpellSchool(const ESM::RefId& spellId, const MWWorld::Ptr& actor) { - int school = 0; + ESM::RefId school; getSpellSuccessChance(spellId, actor, &school); return school; } - int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor) + ESM::RefId getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor) { - int school = 0; + ESM::RefId school; getSpellSuccessChance(spell, actor, &school); return school; } diff --git a/apps/openmw/mwmechanics/spellutil.hpp b/apps/openmw/mwmechanics/spellutil.hpp index 6b346b5c34..a332a231e6 100644 --- a/apps/openmw/mwmechanics/spellutil.hpp +++ b/apps/openmw/mwmechanics/spellutil.hpp @@ -18,8 +18,6 @@ namespace MWWorld namespace MWMechanics { - ESM::RefId spellSchoolToSkill(int school); - enum class EffectCostMethod { GameSpell, @@ -44,14 +42,14 @@ namespace MWMechanics * @note actor can be an NPC or a creature * @return success chance from 0 to 100 (in percent), if cap=false then chance above 100 may be returned. */ - float calcSpellBaseSuccessChance(const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool); - float getSpellSuccessChance(const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = nullptr, - bool cap = true, bool checkMagicka = true); - float getSpellSuccessChance(const ESM::RefId& spellId, const MWWorld::Ptr& actor, int* effectiveSchool = nullptr, - bool cap = true, bool checkMagicka = true); + float calcSpellBaseSuccessChance(const ESM::Spell* spell, const MWWorld::Ptr& actor, ESM::RefId* effectiveSchool); + float getSpellSuccessChance(const ESM::Spell* spell, const MWWorld::Ptr& actor, + ESM::RefId* effectiveSchool = nullptr, bool cap = true, bool checkMagicka = true); + float getSpellSuccessChance(const ESM::RefId& spellId, const MWWorld::Ptr& actor, + ESM::RefId* effectiveSchool = nullptr, bool cap = true, bool checkMagicka = true); - int getSpellSchool(const ESM::RefId& spellId, const MWWorld::Ptr& actor); - int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor); + ESM::RefId getSpellSchool(const ESM::RefId& spellId, const MWWorld::Ptr& actor); + ESM::RefId getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor); /// Get whether or not the given spell contributes to skill progress. bool spellIncreasesSkill(const ESM::Spell* spell); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 0785241927..28f1904508 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -98,12 +98,14 @@ namespace else projectileIDs.push_back(magicEffect->mBolt); - static const std::string schools[] - = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" }; if (!magicEffect->mBoltSound.empty()) sounds.emplace(magicEffect->mBoltSound); else - sounds.emplace(ESM::RefId::stringRefId(schools[magicEffect->mData.mSchool] + " bolt")); + sounds.emplace(MWBase::Environment::get() + .getESMStore() + ->get() + .find(magicEffect->mData.mSchool) + ->mSchool->mBoltSound); projectileEffects.mList.push_back(*iter); } diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 49b28d7f14..5afa92e53a 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -932,35 +932,35 @@ namespace MWWorld void Store::setUp(const MWWorld::Store& settings) { - constexpr std::string_view skillValues[ESM::Skill::Length][3] = { - { "sSkillBlock", "icons\\k\\combat_block.dds", "fWerewolfBlock" }, - { "sSkillArmorer", "icons\\k\\combat_armor.dds", "fWerewolfArmorer" }, - { "sSkillMediumarmor", "icons\\k\\combat_mediumarmor.dds", "fWerewolfMediumarmor" }, - { "sSkillHeavyarmor", "icons\\k\\combat_heavyarmor.dds", "fWerewolfHeavyarmor" }, - { "sSkillBluntweapon", "icons\\k\\combat_blunt.dds", "fWerewolfBluntweapon" }, - { "sSkillLongblade", "icons\\k\\combat_longblade.dds", "fWerewolfLongblade" }, - { "sSkillAxe", "icons\\k\\combat_axe.dds", "fWerewolfAxe" }, - { "sSkillSpear", "icons\\k\\combat_spear.dds", "fWerewolfSpear" }, - { "sSkillAthletics", "icons\\k\\combat_athletics.dds", "fWerewolfAthletics" }, - { "sSkillEnchant", "icons\\k\\magic_enchant.dds", "fWerewolfEnchant" }, - { "sSkillDestruction", "icons\\k\\magic_destruction.dds", "fWerewolfDestruction" }, - { "sSkillAlteration", "icons\\k\\magic_alteration.dds", "fWerewolfAlteration" }, - { "sSkillIllusion", "icons\\k\\magic_illusion.dds", "fWerewolfIllusion" }, - { "sSkillConjuration", "icons\\k\\magic_conjuration.dds", "fWerewolfConjuration" }, - { "sSkillMysticism", "icons\\k\\magic_mysticism.dds", "fWerewolfMysticism" }, - { "sSkillRestoration", "icons\\k\\magic_restoration.dds", "fWerewolfRestoration" }, - { "sSkillAlchemy", "icons\\k\\magic_alchemy.dds", "fWerewolfAlchemy" }, - { "sSkillUnarmored", "icons\\k\\magic_unarmored.dds", "fWerewolfUnarmored" }, - { "sSkillSecurity", "icons\\k\\stealth_security.dds", "fWerewolfSecurity" }, - { "sSkillSneak", "icons\\k\\stealth_sneak.dds", "fWerewolfSneak" }, - { "sSkillAcrobatics", "icons\\k\\stealth_acrobatics.dds", "fWerewolfAcrobatics" }, - { "sSkillLightarmor", "icons\\k\\stealth_lightarmor.dds", "fWerewolfLightarmor" }, - { "sSkillShortblade", "icons\\k\\stealth_shortblade.dds", "fWerewolfShortblade" }, - { "sSkillMarksman", "icons\\k\\stealth_marksman.dds", "fWerewolfMarksman" }, + constexpr std::string_view skillValues[ESM::Skill::Length][4] = { + { "sSkillBlock", "icons\\k\\combat_block.dds", "fWerewolfBlock", {} }, + { "sSkillArmorer", "icons\\k\\combat_armor.dds", "fWerewolfArmorer", {} }, + { "sSkillMediumarmor", "icons\\k\\combat_mediumarmor.dds", "fWerewolfMediumarmor", {} }, + { "sSkillHeavyarmor", "icons\\k\\combat_heavyarmor.dds", "fWerewolfHeavyarmor", {} }, + { "sSkillBluntweapon", "icons\\k\\combat_blunt.dds", "fWerewolfBluntweapon", {} }, + { "sSkillLongblade", "icons\\k\\combat_longblade.dds", "fWerewolfLongblade", {} }, + { "sSkillAxe", "icons\\k\\combat_axe.dds", "fWerewolfAxe", {} }, + { "sSkillSpear", "icons\\k\\combat_spear.dds", "fWerewolfSpear", {} }, + { "sSkillAthletics", "icons\\k\\combat_athletics.dds", "fWerewolfAthletics", {} }, + { "sSkillEnchant", "icons\\k\\magic_enchant.dds", "fWerewolfEnchant", {} }, + { "sSkillDestruction", "icons\\k\\magic_destruction.dds", "fWerewolfDestruction", "destruction" }, + { "sSkillAlteration", "icons\\k\\magic_alteration.dds", "fWerewolfAlteration", "alteration" }, + { "sSkillIllusion", "icons\\k\\magic_illusion.dds", "fWerewolfIllusion", "illusion" }, + { "sSkillConjuration", "icons\\k\\magic_conjuration.dds", "fWerewolfConjuration", "conjuration" }, + { "sSkillMysticism", "icons\\k\\magic_mysticism.dds", "fWerewolfMysticism", "mysticism" }, + { "sSkillRestoration", "icons\\k\\magic_restoration.dds", "fWerewolfRestoration", "restoration" }, + { "sSkillAlchemy", "icons\\k\\magic_alchemy.dds", "fWerewolfAlchemy", {} }, + { "sSkillUnarmored", "icons\\k\\magic_unarmored.dds", "fWerewolfUnarmored", {} }, + { "sSkillSecurity", "icons\\k\\stealth_security.dds", "fWerewolfSecurity", {} }, + { "sSkillSneak", "icons\\k\\stealth_sneak.dds", "fWerewolfSneak", {} }, + { "sSkillAcrobatics", "icons\\k\\stealth_acrobatics.dds", "fWerewolfAcrobatics", {} }, + { "sSkillLightarmor", "icons\\k\\stealth_lightarmor.dds", "fWerewolfLightarmor", {} }, + { "sSkillShortblade", "icons\\k\\stealth_shortblade.dds", "fWerewolfShortblade", {} }, + { "sSkillMarksman", "icons\\k\\stealth_marksman.dds", "fWerewolfMarksman", {} }, // "Mercantile"! >_< - { "sSkillMercantile", "icons\\k\\stealth_mercantile.dds", "fWerewolfMerchantile" }, - { "sSkillSpeechcraft", "icons\\k\\stealth_speechcraft.dds", "fWerewolfSpeechcraft" }, - { "sSkillHandtohand", "icons\\k\\stealth_handtohand.dds", "fWerewolfHandtohand" }, + { "sSkillMercantile", "icons\\k\\stealth_mercantile.dds", "fWerewolfMerchantile", {} }, + { "sSkillSpeechcraft", "icons\\k\\stealth_speechcraft.dds", "fWerewolfSpeechcraft", {} }, + { "sSkillHandtohand", "icons\\k\\stealth_handtohand.dds", "fWerewolfHandtohand", {} }, }; for (ESM::Skill* skill : mShared) { @@ -969,6 +969,21 @@ namespace MWWorld 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]; + if (!school.empty()) + { + if (!skill->mSchool) + skill->mSchool = ESM::MagicSchool{}; + const std::string id{ school }; + skill->mSchool->mAreaSound = ESM::RefId::stringRefId(id + " area"); + skill->mSchool->mBoltSound = ESM::RefId::stringRefId(id + " bolt"); + skill->mSchool->mCastSound = ESM::RefId::stringRefId(id + " cast"); + skill->mSchool->mFailureSound = ESM::RefId::stringRefId("Spell Failure " + id); + skill->mSchool->mHitSound = ESM::RefId::stringRefId(id + " hit"); + const std::string name = "sSchool" + id; + skill->mSchool->mName = getGMSTString(settings, name); + skill->mSchool->mAutoCalcMax = int(getGMSTFloat(settings, "iAutoSpell" + id + "Max")); + } } } } diff --git a/components/esm3/loadmgef.cpp b/components/esm3/loadmgef.cpp index ee5b48038f..68225d44ef 100644 --- a/components/esm3/loadmgef.cpp +++ b/components/esm3/loadmgef.cpp @@ -2,6 +2,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" +#include "loadskil.hpp" #include @@ -33,7 +34,20 @@ namespace ESM mId = indexToRefId(mIndex); - esm.getHNTSized<36>(mData, "MEDT"); + esm.getSubNameIs("MEDT"); + esm.getSubHeader(); + int school; + esm.getT(school); + mData.mSchool = MagicSchool::indexToSkillRefId(school); + esm.getT(mData.mBaseCost); + esm.getT(mData.mFlags); + esm.getT(mData.mRed); + esm.getT(mData.mGreen); + esm.getT(mData.mBlue); + esm.getT(mData.mUnknown1); + esm.getT(mData.mSpeed); + esm.getT(mData.mUnknown2); + if (esm.getFormatVersion() == DefaultFormatVersion) { // don't allow mods to change fixed flags in the legacy format @@ -91,7 +105,17 @@ namespace ESM { esm.writeHNT("INDX", mIndex); - esm.writeHNT("MEDT", mData, 36); + esm.startSubRecord("MEDT"); + esm.writeT(MagicSchool::skillRefIdToIndex(mData.mSchool)); + esm.writeT(mData.mBaseCost); + esm.writeT(mData.mFlags); + esm.writeT(mData.mRed); + esm.writeT(mData.mGreen); + esm.writeT(mData.mBlue); + esm.writeT(mData.mUnknown1); + esm.writeT(mData.mSpeed); + esm.writeT(mData.mUnknown2); + esm.endRecord("MEDT"); esm.writeHNOCString("ITEX", mIcon); esm.writeHNOCString("PTEX", mParticle); @@ -558,7 +582,7 @@ namespace ESM void MagicEffect::blank() { mRecordFlags = 0; - mData.mSchool = 0; + mData.mSchool = ESM::Skill::Alteration; mData.mBaseCost = 0; mData.mFlags = 0; mData.mRed = 0; diff --git a/components/esm3/loadmgef.hpp b/components/esm3/loadmgef.hpp index 1de3fb8a0a..1b4089e74a 100644 --- a/components/esm3/loadmgef.hpp +++ b/components/esm3/loadmgef.hpp @@ -70,7 +70,7 @@ namespace ESM struct MEDTstruct { - int mSchool; // SpellSchool, see defs.hpp + RefId mSchool; // Skill id float mBaseCost; int mFlags; // Glow color for enchanted items with this effect diff --git a/components/esm3/loadskil.cpp b/components/esm3/loadskil.cpp index 983ef8a152..d435501e05 100644 --- a/components/esm3/loadskil.cpp +++ b/components/esm3/loadskil.cpp @@ -107,4 +107,30 @@ namespace ESM return RefId(); return RefId::index(sRecordId, static_cast(index)); } + + const std::array sMagicSchools = { + Skill::Alteration, + Skill::Conjuration, + Skill::Destruction, + Skill::Illusion, + Skill::Mysticism, + Skill::Restoration, + }; + + RefId MagicSchool::indexToSkillRefId(int index) + { + if (index < 0 || index >= Length) + return {}; + return sMagicSchools[index]; + } + + int MagicSchool::skillRefIdToIndex(RefId id) + { + for (size_t i = 0; i < sMagicSchools.size(); ++i) + { + if (id == sMagicSchools[i]) + return static_cast(i); + } + return -1; + } } diff --git a/components/esm3/loadskil.hpp b/components/esm3/loadskil.hpp index ea3dd6954b..637c44d0f8 100644 --- a/components/esm3/loadskil.hpp +++ b/components/esm3/loadskil.hpp @@ -2,6 +2,7 @@ #define OPENMW_ESM_SKIL_H #include +#include #include #include "components/esm/defs.hpp" @@ -13,6 +14,22 @@ namespace ESM class ESMReader; class ESMWriter; + struct MagicSchool + { + ESM::RefId mAreaSound; + ESM::RefId mBoltSound; + ESM::RefId mCastSound; + ESM::RefId mFailureSound; + ESM::RefId mHitSound; + std::string mName; + int mAutoCalcMax; + + static constexpr int Length = 6; + + static RefId indexToSkillRefId(int index); + static int skillRefIdToIndex(RefId id); + }; + /* * Skill information * @@ -47,6 +64,7 @@ namespace ESM std::string mName; std::string mIcon; float mWerewolfValue{}; + std::optional mSchool; static constexpr IndexRefId Block{ sRecordId, 0 }; static constexpr IndexRefId Armorer{ sRecordId, 1 };