Merge schools into skills

revert-6246b479
Evil Eye 2 years ago
parent 9947a41c37
commit 73c2387708

@ -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;

@ -2040,13 +2040,16 @@ namespace CSMWorld
{
}
QVariant get(const Record<ESXRecordT>& record) const override { return record.get().mData.mSchool; }
QVariant get(const Record<ESXRecordT>& record) const override
{
return ESM::MagicSchool::skillRefIdToIndex(record.get().mData.mSchool);
}
void set(Record<ESXRecordT>& 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);
}

@ -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

@ -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<ESM::Spell>().find(
ESM::RefId::deserialize(focus->getUserString("Spell")));
const auto& store = MWBase::Environment::get().getESMStore();
const ESM::Spell* spell
= store->get<ESM::Spell>().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<ESM::Skill>().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<ESM::MagicEffect>().find(id);
const auto& store = MWBase::Environment::get().getESMStore();
const ESM::MagicEffect* effect = store->get<ESM::MagicEffect>().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<ESM::Skill>().find(effect->mData.mSchool)->mSchool->mName)
.asUTF8());
widget->setUserString("ImageTexture_MagicEffectImage", icon);
}

@ -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 {

@ -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<int, SchoolCaps> schoolCaps;
for (int i = 0; i < MagicSchool::Length; ++i)
std::map<ESM::RefId, SchoolCaps> schoolCaps;
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
{
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<int>::max();
caps.mWeakestSpell = ESM::RefId();
schoolCaps[i] = caps;
schoolCaps[skill.mId] = caps;
}
std::vector<ESM::RefId> 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<ESM::GameSetting>().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<ESM::RefId, SkillValue>& 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<float>::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<ESM::RefId, SkillValue>& actorSkills,
const std::map<ESM::Attribute::AttributeID, AttributeValue>& actorAttributes, int effectiveSchool)
const std::map<ESM::Attribute::AttributeID, AttributeValue>& 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();
}

@ -31,10 +31,10 @@ namespace MWMechanics
const std::map<ESM::Attribute::AttributeID, AttributeValue>& actorAttributes);
void calcWeakestSchool(const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills,
int& effectiveSchool, float& skillTerm);
ESM::RefId& effectiveSchool, float& skillTerm);
float calcAutoCastChance(const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills,
const std::map<ESM::Attribute::AttributeID, AttributeValue>& actorAttributes, int effectiveSchool);
const std::map<ESM::Attribute::AttributeID, AttributeValue>& actorAttributes, ESM::RefId effectiveSchool);
}

@ -1,39 +0,0 @@
#include "magicschool.hpp"
#include <components/esm3/loadgmst.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp"
namespace
{
std::array<MWMechanics::MagicSchool, MWMechanics::MagicSchool::Length> initSchools()
{
const MWWorld::Store<ESM::GameSetting>& gmst
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
std::array<MWMechanics::MagicSchool, MWMechanics::MagicSchool::Length> 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<MagicSchool, MagicSchool::Length> sSchools = initSchools();
return sSchools[index];
}
}

@ -1,26 +0,0 @@
#ifndef GAME_MWMECHANICS_MAGICSCHOOL_H
#define GAME_MWMECHANICS_MAGICSCHOOL_H
#include <components/esm/refid.hpp>
#include <array>
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

@ -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<ESM::Skill>().find(effect->mData.mSchool)->mSchool->mAreaSound, 1.0f,
1.0f);
}
// Get the actors in range of the effect
std::vector<MWWorld::Ptr> 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<ESM::Enchantment>().find(enchantmentName);
const auto& store = MWBase::Environment::get().getESMStore();
const ESM::Enchantment* enchantment = store->get<ESM::Enchantment>().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<ESM::MagicEffect>().find(effectId);
const ESM::MagicEffect* magicEffect = store->get<ESM::MagicEffect>().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<ESM::Skill>().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<ESM::Skill>().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<ESM::Skill>().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<ESM::Skill>().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<ESM::Static>().find(magicEffect.mHit);
castStatic = store->get<ESM::Static>().find(magicEffect.mHit);
else
castStatic = MWBase::Environment::get().getESMStore()->get<ESM::Static>().find(
ESM::RefId::stringRefId("VFX_DefaultHit"));
castStatic = store->get<ESM::Static>().find(ESM::RefId::stringRefId("VFX_DefaultHit"));
bool loop = (magicEffect.mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0;
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target);

@ -37,19 +37,6 @@ namespace MWMechanics
}
}
ESM::RefId spellSchoolToSkill(int school)
{
static const std::array<ESM::RefId, 6> 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<float>::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<ESM::Spell>().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;
}

@ -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);

@ -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<ESM::Skill>()
.find(magicEffect->mData.mSchool)
->mSchool->mBoltSound);
projectileEffects.mList.push_back(*iter);
}

@ -932,35 +932,35 @@ namespace MWWorld
void Store<ESM::Skill>::setUp(const MWWorld::Store<ESM::GameSetting>& 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"));
}
}
}
}

@ -2,6 +2,7 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "loadskil.hpp"
#include <components/misc/strings/algorithm.hpp>
@ -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;

@ -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

@ -107,4 +107,30 @@ namespace ESM
return RefId();
return RefId::index(sRecordId, static_cast<std::uint32_t>(index));
}
const std::array<RefId, MagicSchool::Length> 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<int>(i);
}
return -1;
}
}

@ -2,6 +2,7 @@
#define OPENMW_ESM_SKIL_H
#include <array>
#include <optional>
#include <string>
#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<MagicSchool> mSchool;
static constexpr IndexRefId Block{ sRecordId, 0 };
static constexpr IndexRefId Armorer{ sRecordId, 1 };

Loading…
Cancel
Save