From 73c238770805dc6c7ba9f78f301e4ebdb390f9ca Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 26 Jun 2023 20:42:52 +0200 Subject: [PATCH] Merge schools into skills --- apps/esmtool/record.cpp | 4 +- apps/opencs/model/world/columnimp.hpp | 7 ++- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/tooltips.cpp | 18 +++--- apps/openmw/mwlua/magicbindings.cpp | 4 +- apps/openmw/mwmechanics/autocalcspell.cpp | 32 +++++----- apps/openmw/mwmechanics/autocalcspell.hpp | 4 +- apps/openmw/mwmechanics/magicschool.cpp | 39 ------------- apps/openmw/mwmechanics/magicschool.hpp | 26 --------- apps/openmw/mwmechanics/spellcasting.cpp | 36 +++++++----- apps/openmw/mwmechanics/spellutil.cpp | 29 +++------ apps/openmw/mwmechanics/spellutil.hpp | 18 +++--- apps/openmw/mwworld/projectilemanager.cpp | 7 ++- apps/openmw/mwworld/store.cpp | 71 ++++++++++++++--------- components/esm3/loadmgef.cpp | 30 +++++++++- components/esm3/loadmgef.hpp | 2 +- components/esm3/loadskil.cpp | 26 +++++++++ components/esm3/loadskil.hpp | 18 ++++++ 18 files changed, 194 insertions(+), 179 deletions(-) delete mode 100644 apps/openmw/mwmechanics/magicschool.cpp delete mode 100644 apps/openmw/mwmechanics/magicschool.hpp 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/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 90cb59ec3a..997eea667b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -99,7 +99,7 @@ add_openmw_dir (mwmechanics aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellcasting spellresistance disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction summoning character actors objects aistate trading weaponpriority spellpriority weapontype spellutil - spelleffects magicschool + spelleffects ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 4c32ef83cf..fdf945f2dc 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -20,7 +20,6 @@ #include "../mwbase/world.hpp" #include "../mwmechanics/actorutil.hpp" -#include "../mwmechanics/magicschool.hpp" #include "../mwmechanics/spellutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -225,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) @@ -248,8 +248,9 @@ namespace MWGui spell)) // display school of spells that contribute to skill progress { MWWorld::Ptr player = MWMechanics::getPlayer(); - const auto& school = MWMechanics::getMagicSchool(MWMechanics::getSpellSchool(spell, player)); - info.text = "#{sSchool}: " + MyGUI::TextIterator::toTagsString(school.mName).asUTF8(); + 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") @@ -942,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 +958,9 @@ namespace MWGui widget->setUserString("Caption_MagicEffectDescription", effect->mDescription); widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " - + MyGUI::TextIterator::toTagsString(MWMechanics::getMagicSchool(effect->mData.mSchool).mName).asUTF8()); + + MyGUI::TextIterator::toTagsString( + store->get().find(effect->mData.mSchool)->mSchool->mName) + .asUTF8()); widget->setUserString("ImageTexture_MagicEffectImage", icon); } 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 0117e3f563..08c76e900f 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -13,7 +13,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "magicschool.hpp" #include "spellutil.hpp" namespace MWMechanics @@ -36,17 +35,18 @@ namespace MWMechanics static const float fNPCbaseMagickaMult = gmst.find("fNPCbaseMagickaMult")->mValue.getFloat(); float baseMagicka = fNPCbaseMagickaMult * actorAttributes.at(ESM::Attribute::Intelligence).getBase(); - std::map schoolCaps; - for (int i = 0; i < MagicSchool::Length; ++i) + std::map schoolCaps; + for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get()) { - const MagicSchool& school = getMagicSchool(i); + if (!skill.mSchool) + continue; SchoolCaps caps; caps.mCount = 0; - caps.mLimit = school.mAutoCalcMax; - caps.mReachedLimit = school.mAutoCalcMax <= 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; @@ -72,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) @@ -171,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)) @@ -248,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(); @@ -287,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) @@ -301,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; @@ -310,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/magicschool.cpp b/apps/openmw/mwmechanics/magicschool.cpp deleted file mode 100644 index b98355faeb..0000000000 --- a/apps/openmw/mwmechanics/magicschool.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "magicschool.hpp" - -#include - -#include "../mwworld/esmstore.hpp" - -#include "../mwbase/environment.hpp" - -namespace -{ - std::array initSchools() - { - const MWWorld::Store& gmst - = MWBase::Environment::get().getESMStore()->get(); - std::array out; - const std::string schools[] - = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" }; - for (size_t i = 0; i < out.size(); ++i) - { - out[i].mAreaSound = ESM::RefId::stringRefId(schools[i] + " area"); - out[i].mBoltSound = ESM::RefId::stringRefId(schools[i] + " bolt"); - out[i].mCastSound = ESM::RefId::stringRefId(schools[i] + " cast"); - out[i].mFailureSound = ESM::RefId::stringRefId("Spell Failure " + schools[i]); - out[i].mHitSound = ESM::RefId::stringRefId(schools[i] + " hit"); - out[i].mName = gmst.find("sSchool" + schools[i])->mValue.getString(); - out[i].mAutoCalcMax = gmst.find("iAutoSpell" + schools[i] + "Max")->mValue.getInteger(); - } - return out; - } -} - -namespace MWMechanics -{ - const MagicSchool& getMagicSchool(int index) - { - static const std::array sSchools = initSchools(); - return sSchools[index]; - } -} diff --git a/apps/openmw/mwmechanics/magicschool.hpp b/apps/openmw/mwmechanics/magicschool.hpp deleted file mode 100644 index fbfbca0efd..0000000000 --- a/apps/openmw/mwmechanics/magicschool.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef GAME_MWMECHANICS_MAGICSCHOOL_H -#define GAME_MWMECHANICS_MAGICSCHOOL_H - -#include - -#include - -namespace MWMechanics -{ - 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; - }; - - const MagicSchool& getMagicSchool(int index); -} - -#endif diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 909784e15b..d7aa0d6b71 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -22,7 +22,6 @@ #include "actorutil.hpp" #include "creaturestats.hpp" -#include "magicschool.hpp" #include "spelleffects.hpp" #include "spellutil.hpp" #include "weapontype.hpp" @@ -89,7 +88,9 @@ namespace MWMechanics if (!effect->mAreaSound.empty()) sndMgr->playSound3D(mHitPosition, effect->mAreaSound, 1.0f, 1.0f); else - sndMgr->playSound3D(mHitPosition, getMagicSchool(effect->mData.mSchool).mAreaSound, 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; @@ -298,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; @@ -330,17 +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; } MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mCaster, getMagicSchool(school).mFailureSound, 1.0f, 1.0f); + sndMgr->playSound3D( + mCaster, store->get().find(school)->mSchool->mFailureSound, 1.0f, 1.0f); } return false; } @@ -396,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(); @@ -424,7 +425,8 @@ namespace MWMechanics { // Failure sound MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mCaster, getMagicSchool(school).mFailureSound, 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; } } @@ -435,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()) @@ -592,28 +594,30 @@ namespace MWMechanics if (!effect->mCastSound.empty()) sndMgr->playSound3D(mCaster, effect->mCastSound, 1.0f, 1.0f); else - sndMgr->playSound3D(mCaster, getMagicSchool(effect->mData.mSchool).mCastSound, 1.0f, 1.0f); + sndMgr->playSound3D( + 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) { MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); if (!magicEffect.mHitSound.empty()) sndMgr->playSound3D(target, magicEffect.mHitSound, 1.0f, 1.0f); else - sndMgr->playSound3D(target, getMagicSchool(magicEffect.mData.mSchool).mHitSound, 1.0f, 1.0f); + sndMgr->playSound3D( + 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); - - int getSpellSchool(const ESM::RefId& spellId, const MWWorld::Ptr& actor); - int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor); + 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); + + 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 3aa19d1473..28f1904508 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -42,7 +42,6 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/combat.hpp" #include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/magicschool.hpp" #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/weapontype.hpp" @@ -102,7 +101,11 @@ namespace if (!magicEffect->mBoltSound.empty()) sounds.emplace(magicEffect->mBoltSound); else - sounds.emplace(MWMechanics::getMagicSchool(magicEffect->mData.mSchool).mBoltSound); + 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 };