1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2026-02-11 09:38:28 +00:00

Changed skills and attributes in ENAMstruct to use RefIds instead of indices.

This commit is contained in:
Telvanni 4Life 2026-02-02 23:04:51 -05:00
parent a295acf19f
commit 12dca7ecef
19 changed files with 74 additions and 78 deletions

View file

@ -576,8 +576,8 @@ namespace ESM
EffectList record;
record.mList.emplace_back(IndexedENAMstruct{ {
.mEffectID = ESM::MagicEffect::SwiftSwim,
.mSkill = 2,
.mAttribute = 3,
.mSkill = ESM::Skill::MediumArmor,
.mAttribute = ESM::Attribute::Agility,
.mRange = 4,
.mArea = 5,
.mDuration = 6,

View file

@ -154,15 +154,16 @@ namespace
for (const ESM::IndexedENAMstruct& effect : effects.mList)
{
int effectIdx = ESM::MagicEffect::refIdToIndex(effect.mData.mEffectID);
int skillIdx = ESM::Skill::refIdToIndex(effect.mData.mSkill);
int attributeIdx = ESM::Attribute::refIdToIndex(effect.mData.mAttribute);
if (effectIdx != -1)
std::cout << " Effect[" << i << "]: " << magicEffectLabel(effectIdx) << " (" << effectIdx << ")"
<< std::endl;
if (effect.mData.mSkill != -1)
std::cout << " Skill: " << skillLabel(effect.mData.mSkill) << " (" << (int)effect.mData.mSkill << ")"
if (skillIdx != -1)
std::cout << " Skill: " << skillLabel(skillIdx) << " (" << skillIdx << ")" << std::endl;
if (attributeIdx != -1)
std::cout << " Attribute: " << attributeLabel(attributeIdx) << " (" << attributeIdx << ")"
<< std::endl;
if (effect.mData.mAttribute != -1)
std::cout << " Attribute: " << attributeLabel(effect.mData.mAttribute) << " ("
<< (int)effect.mData.mAttribute << ")" << std::endl;
std::cout << " Range: " << rangeTypeLabel(effect.mData.mRange) << " (" << effect.mData.mRange << ")"
<< std::endl;
// Area is always zero if range type is "Self"

View file

@ -27,11 +27,13 @@ namespace CSMTools
// At the time of writing this effects, attributes and skills are mostly hardcoded
int effectIndex = ESM::MagicEffect::refIdToIndex(effect.mData.mEffectID);
int skillIndex = ESM::Skill::refIdToIndex(effect.mData.mSkill);
int attributeIndex = ESM::Attribute::refIdToIndex(effect.mData.mAttribute);
if (effectIndex < -1 || effectIndex >= ESM::MagicEffect::Length)
messages.add(id, "Effect #" + number + ": invalid effect ID", "", CSMDoc::Message::Severity_Error);
if (effect.mData.mSkill < -1 || effect.mData.mSkill >= ESM::Skill::Length)
if (skillIndex < -1 || skillIndex >= ESM::Skill::Length)
messages.add(id, "Effect #" + number + ": invalid skill", "", CSMDoc::Message::Severity_Error);
if (effect.mData.mAttribute < -1 || effect.mData.mAttribute >= ESM::Attribute::Length)
if (attributeIndex < -1 || attributeIndex >= ESM::Attribute::Length)
messages.add(id, "Effect #" + number + ": invalid attribute", "", CSMDoc::Message::Severity_Error);
if (effect.mData.mRange < ESM::RT_Self || effect.mData.mRange > ESM::RT_Target)

View file

@ -9,8 +9,10 @@
#include <string>
#include <vector>
#include <components/esm/attr.hpp>
#include <components/esm3/effectlist.hpp>
#include <components/esm3/loadmgef.hpp> // for converting magic effect id to string & back
#include <components/esm3/loadskil.hpp>
#include "idcollection.hpp"
#include "nestedcolumnadapter.hpp"
@ -267,8 +269,8 @@ namespace CSMWorld
ESM::IndexedENAMstruct effect;
effect.mIndex = position;
effect.mData.mEffectID = ESM::MagicEffect::WaterBreathing;
effect.mData.mSkill = -1;
effect.mData.mAttribute = -1;
effect.mData.mSkill = ESM::RefId();
effect.mData.mAttribute = ESM::RefId();
effect.mData.mRange = 0;
effect.mData.mArea = 0;
effect.mData.mDuration = 0;
@ -339,14 +341,14 @@ namespace CSMWorld
case 1:
{
if (targetSkill)
return effect.mSkill;
return ESM::Skill::refIdToIndex(effect.mSkill);
else
return QVariant();
}
case 2:
{
if (targetAttribute)
return effect.mAttribute;
return ESM::Attribute::refIdToIndex(effect.mAttribute);
else
return QVariant();
}
@ -389,19 +391,19 @@ namespace CSMWorld
targetAttribute = mgef.mData.mFlags & ESM::MagicEffect::TargetAttribute;
}
if (!targetSkill)
effect.mSkill = -1;
effect.mSkill = ESM::RefId();
if (!targetAttribute)
effect.mAttribute = -1;
effect.mAttribute = ESM::RefId();
break;
}
case 1:
{
effect.mSkill = static_cast<signed char>(value.toInt());
effect.mSkill = ESM::Skill::indexToRefId(value.toInt());
break;
}
case 2:
{
effect.mAttribute = static_cast<signed char>(value.toInt());
effect.mAttribute = ESM::Attribute::indexToRefId(value.toInt());
break;
}
case 3:

View file

@ -48,8 +48,8 @@ namespace
effect.mMagnMax = 0;
effect.mMagnMin = 0;
effect.mRange = 0;
effect.mSkill = -1;
effect.mAttribute = -1;
effect.mSkill = ESM::RefId();
effect.mAttribute = ESM::RefId();
}
}
@ -143,8 +143,8 @@ namespace MWGui
mEffect.mMagnMax = 1;
mEffect.mDuration = 1;
mEffect.mArea = 0;
mEffect.mSkill = -1;
mEffect.mAttribute = -1;
mEffect.mSkill = ESM::RefId();
mEffect.mAttribute = ESM::RefId();
eventEffectAdded(mEffect);
onRangeButtonClicked(mRangeButton);
@ -331,13 +331,13 @@ namespace MWGui
void EditEffectDialog::setSkill(ESM::RefId skill)
{
mEffect.mSkill = static_cast<signed char>(ESM::Skill::refIdToIndex(skill));
mEffect.mSkill = skill;
eventEffectModified(mEffect);
}
void EditEffectDialog::setAttribute(ESM::RefId attribute)
{
mEffect.mAttribute = static_cast<signed char>(ESM::Attribute::refIdToIndex(attribute));
mEffect.mAttribute = attribute;
eventEffectModified(mEffect);
}
@ -961,8 +961,8 @@ namespace MWGui
{
Widgets::SpellEffectParams params;
params.mEffectID = effectInfo.mEffectID;
params.mSkill = ESM::Skill::indexToRefId(effectInfo.mSkill);
params.mAttribute = ESM::Attribute::indexToRefId(effectInfo.mAttribute);
params.mSkill = effectInfo.mSkill;
params.mAttribute = effectInfo.mAttribute;
params.mDuration = effectInfo.mDuration;
params.mMagnMin = effectInfo.mMagnMin;
params.mMagnMax = effectInfo.mMagnMax;

View file

@ -53,9 +53,8 @@ namespace MWGui
if (!effectId.empty())
{
const ESM::MagicEffect* magicEffect = store.get<ESM::MagicEffect>().find(effectId);
const ESM::Attribute* attribute
= store.get<ESM::Attribute>().search(ESM::Attribute::indexToRefId(effect.mData.mAttribute));
const ESM::Skill* skill = store.get<ESM::Skill>().search(ESM::Skill::indexToRefId(effect.mData.mSkill));
const ESM::Attribute* attribute = store.get<ESM::Attribute>().search(effect.mData.mAttribute);
const ESM::Skill* skill = store.get<ESM::Skill>().search(effect.mData.mSkill);
std::string fullEffectName = MWMechanics::getMagicEffectString(*magicEffect, attribute, skill);
std::string convert = Utf8Stream::lowerCaseUtf8(fullEffectName);

View file

@ -228,8 +228,8 @@ namespace MWGui
{
Widgets::SpellEffectParams params;
params.mEffectID = spellEffect.mData.mEffectID;
params.mSkill = ESM::Skill::indexToRefId(spellEffect.mData.mSkill);
params.mAttribute = ESM::Attribute::indexToRefId(spellEffect.mData.mAttribute);
params.mSkill = spellEffect.mData.mSkill;
params.mAttribute = spellEffect.mData.mAttribute;
params.mDuration = spellEffect.mData.mDuration;
params.mMagnMin = spellEffect.mData.mMagnMin;
params.mMagnMax = spellEffect.mData.mMagnMax;

View file

@ -216,8 +216,8 @@ namespace MWGui::Widgets
= creator->createWidget<MWSpellEffect>("MW_EffectImage", coord, MyGUI::Align::Default);
SpellEffectParams params;
params.mEffectID = effectInfo.mData.mEffectID;
params.mSkill = ESM::Skill::indexToRefId(effectInfo.mData.mSkill);
params.mAttribute = ESM::Attribute::indexToRefId(effectInfo.mData.mAttribute);
params.mSkill = effectInfo.mData.mSkill;
params.mAttribute = effectInfo.mData.mAttribute;
params.mDuration = effectInfo.mData.mDuration;
params.mMagnMin = effectInfo.mData.mMagnMin;
params.mMagnMax = effectInfo.mData.mMagnMax;
@ -333,8 +333,8 @@ namespace MWGui::Widgets
{
SpellEffectParams params;
params.mEffectID = effectInfo.mData.mEffectID;
params.mSkill = ESM::Skill::indexToRefId(effectInfo.mData.mSkill);
params.mAttribute = ESM::Attribute::indexToRefId(effectInfo.mData.mAttribute);
params.mSkill = effectInfo.mData.mSkill;
params.mAttribute = effectInfo.mData.mAttribute;
params.mDuration = effectInfo.mData.mDuration;
params.mMagnMin = effectInfo.mData.mMagnMin;
params.mMagnMax = effectInfo.mData.mMagnMax;

View file

@ -323,16 +323,14 @@ namespace MWLua
[](const ESM::IndexedENAMstruct& params) -> ESM::RefId { return params.mData.mEffectID; });
effectParamsT["affectedSkill"]
= sol::readonly_property([](const ESM::IndexedENAMstruct& params) -> sol::optional<std::string> {
ESM::RefId id = ESM::Skill::indexToRefId(params.mData.mSkill);
if (!id.empty())
return id.serializeText();
if (!params.mData.mSkill.empty())
return params.mData.mSkill.serializeText();
return sol::nullopt;
});
effectParamsT["affectedAttribute"]
= sol::readonly_property([](const ESM::IndexedENAMstruct& params) -> sol::optional<std::string> {
ESM::RefId id = ESM::Attribute::indexToRefId(params.mData.mAttribute);
if (!id.empty())
return id.serializeText();
if (!params.mData.mAttribute.empty())
return params.mData.mAttribute.serializeText();
return sol::nullopt;
});
effectParamsT["range"]

View file

@ -50,8 +50,8 @@ namespace MWLua
continue;
ESM::IndexedENAMstruct effect;
effect.mData.mEffectID = rec.mData.mEffectID[i];
effect.mData.mSkill = static_cast<signed char>(rec.mData.mSkills[i]);
effect.mData.mAttribute = static_cast<signed char>(rec.mData.mAttributes[i]);
effect.mData.mSkill = ESM::Skill::indexToRefId(rec.mData.mSkills[i]);
effect.mData.mAttribute = ESM::Attribute::indexToRefId(rec.mData.mAttributes[i]);
effect.mData.mRange = ESM::RT_Self;
effect.mData.mArea = 0;
effect.mData.mDuration = 0;

View file

@ -220,13 +220,13 @@ void MWMechanics::Alchemy::updateEffects()
ESM::ENAMstruct effect;
effect.mEffectID = effectKey.mId;
effect.mAttribute = -1;
effect.mSkill = -1;
effect.mAttribute = ESM::RefId();
effect.mSkill = ESM::RefId();
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
effect.mSkill = static_cast<signed char>(ESM::Skill::refIdToIndex(effectKey.mArg));
effect.mSkill = effectKey.mArg;
else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
effect.mAttribute = static_cast<signed char>(ESM::Attribute::refIdToIndex(effectKey.mArg));
effect.mAttribute = effectKey.mArg;
effect.mRange = 0;
effect.mArea = 0;

View file

@ -230,16 +230,14 @@ namespace MWMechanics
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill))
{
ESM::RefId skill = ESM::Skill::indexToRefId(spellEffect.mData.mSkill);
auto found = actorSkills.find(skill);
auto found = actorSkills.find(spellEffect.mData.mSkill);
if (found == actorSkills.end() || found->second.getBase() < iAutoSpellAttSkillMin)
return false;
}
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute))
{
ESM::RefId attribute = ESM::Attribute::indexToRefId(spellEffect.mData.mAttribute);
auto found = actorAttributes.find(attribute);
auto found = actorAttributes.find(spellEffect.mData.mAttribute);
if (found == actorAttributes.end() || found->second.getBase() < iAutoSpellAttSkillMin)
return false;
}

View file

@ -33,15 +33,14 @@ namespace MWMechanics
EffectKey::EffectKey(const ESM::ENAMstruct& effect)
{
mId = effect.mEffectID;
mArg = ESM::Skill::indexToRefId(effect.mSkill);
mArg = effect.mSkill;
ESM::RefId attribute = ESM::Attribute::indexToRefId(effect.mAttribute);
if (!attribute.empty())
if (!effect.mAttribute.empty())
{
if (!mArg.empty())
throw std::runtime_error("magic effect can't have both a skill and an attribute argument");
mArg = attribute;
mArg = effect.mAttribute;
}
}

View file

@ -541,14 +541,11 @@ namespace MWMechanics
|| effect.mEffectID == ESM::MagicEffect::DrainAttribute)
{
if (!enemy.isEmpty()
&& enemy.getClass()
.getCreatureStats(enemy)
.getAttribute(ESM::Attribute::indexToRefId(effect.mAttribute))
.getModified()
<= 0)
&& enemy.getClass().getCreatureStats(enemy).getAttribute(effect.mAttribute).getModified() <= 0)
return 0.f;
{
if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length)
int attributeIdx = ESM::Attribute::refIdToIndex(effect.mAttribute);
if (attributeIdx >= 0 && attributeIdx < ESM::Attribute::Length)
{
const float attributePriorities[ESM::Attribute::Length] = {
1.0f, // Strength
@ -560,7 +557,7 @@ namespace MWMechanics
0.7f, // Personality
0.3f // Luck
};
rating *= attributePriorities[effect.mAttribute];
rating *= attributePriorities[attributeIdx];
}
}
}
@ -569,7 +566,7 @@ namespace MWMechanics
{
if (enemy.isEmpty() || !enemy.getClass().isNpc())
return 0.f;
if (enemy.getClass().getSkill(enemy, ESM::Skill::indexToRefId(effect.mSkill)) <= 0)
if (enemy.getClass().getSkill(enemy, effect.mSkill) <= 0)
return 0.f;
}

View file

@ -167,8 +167,8 @@ namespace MWMechanics
ESM::ENAMstruct effect;
effect.mEffectID = ingredient->mData.mEffectID[index];
effect.mSkill = static_cast<signed char>(ingredient->mData.mSkills[index]);
effect.mAttribute = static_cast<signed char>(ingredient->mData.mAttributes[index]);
effect.mSkill = ESM::Skill::indexToRefId(ingredient->mData.mSkills[index]);
effect.mAttribute = ESM::Attribute::indexToRefId(ingredient->mData.mAttributes[index]);
effect.mRange = ESM::RT_Self;
effect.mArea = 0;

View file

@ -181,18 +181,18 @@ namespace
continue;
}
if (!(mgef->mData.mFlags & ESM::MagicEffect::TargetAttribute) && iter->mData.mAttribute != -1)
if (!(mgef->mData.mFlags & ESM::MagicEffect::TargetAttribute) && !iter->mData.mAttribute.empty())
{
iter->mData.mAttribute = -1;
iter->mData.mAttribute = ESM::RefId();
Log(Debug::Verbose) << RecordType::getRecordType() << " " << spell.mId
<< ": dropping unexpected attribute argument of " << iter->mData.mEffectID
<< " effect";
changed = true;
}
if (!(mgef->mData.mFlags & ESM::MagicEffect::TargetSkill) && iter->mData.mSkill != -1)
if (!(mgef->mData.mFlags & ESM::MagicEffect::TargetSkill) && !iter->mData.mSkill.empty())
{
iter->mData.mSkill = -1;
iter->mData.mSkill = ESM::RefId();
Log(Debug::Verbose) << RecordType::getRecordType() << " " << spell.mId
<< ": dropping unexpected skill argument of " << iter->mData.mEffectID
<< " effect";

View file

@ -48,7 +48,7 @@ namespace MWWorld
for (auto& effect : spell->mEffects.mList)
{
if (effect.mData.mEffectID == ESM::MagicEffect::DrainAttribute)
stats.mWorsenings[effect.mData.mAttribute] = oldStats.mWorsenings;
stats.mWorsenings[ESM::Attribute::refIdToIndex(effect.mData.mAttribute)] = oldStats.mWorsenings;
}
creatureStats.mCorprusSpells[id] = stats;
}

View file

@ -34,8 +34,8 @@ namespace ESM
if (index < 0 || index >= ESM::MagicEffect::Length)
throw std::runtime_error(std::format("Cannot serialize effect {}", src.mEffectID.toDebugString()));
dst.mEffectID = index;
dst.mSkill = src.mSkill;
dst.mAttribute = src.mAttribute;
dst.mSkill = static_cast<signed char>(ESM::Skill::refIdToIndex(src.mSkill));
dst.mAttribute = static_cast<signed char>(ESM::Attribute::refIdToIndex(src.mAttribute));
dst.mRange = src.mRange;
dst.mArea = src.mArea;
dst.mDuration = src.mDuration;
@ -49,8 +49,8 @@ namespace ESM
if (index < 0 || index >= ESM::MagicEffect::Length)
throw std::runtime_error(std::format("Cannot deserialize effect into ENAM with index {}.", index));
dst.mEffectID = ESM::MagicEffect::indexToRefId(index);
dst.mSkill = src.mSkill;
dst.mAttribute = src.mAttribute;
dst.mSkill = ESM::Skill::indexToRefId(src.mSkill);
dst.mAttribute = ESM::Attribute::indexToRefId(src.mAttribute);
dst.mRange = src.mRange;
dst.mArea = src.mArea;
dst.mDuration = src.mDuration;
@ -118,8 +118,8 @@ namespace ESM
esm.getSubComposite(p);
setEffectParams(p, s);
s.mEffectID = esm.getHNRefId("ENID");
s.mSkill = static_cast<signed char>(ESM::Skill::refIdToIndex(esm.getHNORefId("ENSK")));
s.mAttribute = static_cast<signed char>(ESM::Attribute::refIdToIndex(esm.getHNORefId("ENAT")));
s.mSkill = esm.getHNORefId("ENSK");
s.mAttribute = esm.getHNORefId("ENAT");
}
mList.push_back({ s, static_cast<uint32_t>(mList.size()) });
}
@ -142,8 +142,8 @@ namespace ESM
setEffectParams(enam.mData, p);
esm.writeNamedComposite("ENAM", p);
esm.writeHNRefId("ENID", enam.mData.mEffectID);
esm.writeHNORefId("ENSK", ESM::Skill::indexToRefId(enam.mData.mSkill));
esm.writeHNORefId("ENAT", ESM::Attribute::indexToRefId(enam.mData.mAttribute));
esm.writeHNORefId("ENSK", enam.mData.mSkill);
esm.writeHNORefId("ENAT", enam.mData.mAttribute);
}
}
}

View file

@ -21,7 +21,7 @@ namespace ESM
// Which skills/attributes are affected (for restore/drain spells
// etc.)
signed char mSkill, mAttribute; // -1 if N/A
ESM::RefId mSkill, mAttribute; // EmptyRefId if N/A
// Other spell parameters
int32_t mRange; // 0 - self, 1 - touch, 2 - target (RangeType enum)