1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2026-02-11 01:08:26 +00:00

Changed IRDTstruct (alchemical ingredient magic effects) to use RefIds instead of int for effectId.

Changed various structs (ENAMstruct, EffectKey, SummonKey) to use RefId instead of strict StringRefId to account for null effects.
This commit is contained in:
Telvanni 4Life 2025-12-08 18:43:16 -05:00
parent c581ab3242
commit 3e586ed693
16 changed files with 97 additions and 50 deletions

View file

@ -646,7 +646,7 @@ namespace MWMechanics
purge([=](const ActiveSpellParams& params) { return params.mActiveSpellId == id; }, ptr);
}
void ActiveSpells::purgeEffect(const MWWorld::Ptr& ptr, const ESM::MagicEffectId& effectId, ESM::RefId effectArg)
void ActiveSpells::purgeEffect(const MWWorld::Ptr& ptr, const ESM::RefId& effectId, ESM::RefId effectArg)
{
purge(
[=](const ActiveSpellParams&, const ESM::ActiveEffect& effect) {

View file

@ -152,7 +152,7 @@ namespace MWMechanics
void removeEffectsByActiveSpellId(const MWWorld::Ptr& ptr, const ESM::RefId& id);
/// Remove all active effects with this effect id
void purgeEffect(const MWWorld::Ptr& ptr, const ESM::MagicEffectId& effectId, ESM::RefId effectArg = {});
void purgeEffect(const MWWorld::Ptr& ptr, const ESM::RefId& effectId, ESM::RefId effectArg = {});
void purge(EffectPredicate predicate, const MWWorld::Ptr& ptr);
void purge(ParamsPredicate predicate, const MWWorld::Ptr& ptr);

View file

@ -30,12 +30,12 @@ namespace
std::optional<MWMechanics::EffectKey> toKey(const ESM::Ingredient& ingredient, size_t i)
{
if (ingredient.mData.mEffectID[i] < 0)
if (ingredient.mData.mEffectID[i].empty())
return {};
ESM::RefId arg = ESM::Skill::indexToRefId(ingredient.mData.mSkills[i]);
if (arg.empty())
arg = ESM::Attribute::indexToRefId(ingredient.mData.mAttributes[i]);
return MWMechanics::EffectKey(ingredient.mData.mEffectID[i], arg);
return MWMechanics::EffectKey(*ingredient.mData.mEffectID[i].getIf<ESM::MagicEffectId>(), arg);
}
bool containsEffect(const ESM::Ingredient& ingredient, const MWMechanics::EffectKey& effect)
@ -172,11 +172,11 @@ void MWMechanics::Alchemy::updateEffects()
for (const auto& effectKey : effects)
{
const ESM::MagicEffect* magicEffect
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(effectKey.mId);
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().search(effectKey.mId);
if (magicEffect->mData.mBaseCost <= 0)
{
const std::string os = "invalid base cost for magic effect " + std::to_string(effectKey.mId);
const std::string os = "invalid base cost for magic effect " + std::string(ESM::MagicEffect::refIdToName(effectKey.mId));
throw std::runtime_error(os);
}
@ -217,7 +217,7 @@ void MWMechanics::Alchemy::updateEffects()
if (magnitude > 0 && duration > 0)
{
ESM::ENAMstruct effect;
effect.mEffectID = static_cast<int16_t>(effectKey.mId);
effect.mEffectID = effectKey.mId;
effect.mAttribute = -1;
effect.mSkill = -1;
@ -621,7 +621,7 @@ std::vector<std::string> MWMechanics::Alchemy::effectsDescription(
if (alchemySkill < fWortChanceValue * static_cast<int>(i + 1))
break;
if (effectID != -1)
if (!effectID.empty())
{
const ESM::Attribute* attribute
= store->get<ESM::Attribute>().search(ESM::Attribute::indexToRefId(data.mAttributes[i]));

View file

@ -649,7 +649,7 @@ namespace MWMechanics
return mTimeOfDeath;
}
std::multimap<ESM::MagicEffectId, ESM::RefNum>& CreatureStats::getSummonedCreatureMap()
std::multimap<ESM::RefId, ESM::RefNum>& CreatureStats::getSummonedCreatureMap()
{
return mSummonedCreatures;
}

View file

@ -82,7 +82,7 @@ namespace MWMechanics
MWWorld::TimeStamp mTimeOfDeath;
private:
std::multimap<ESM::MagicEffectId, ESM::RefNum> mSummonedCreatures; // <Effect, Actor>
std::multimap<ESM::RefId, ESM::RefNum> mSummonedCreatures; // <Effect, Actor>
float mAwarenessTimer = 0.f;
int mAwarenessRoll = -1;
@ -231,7 +231,7 @@ namespace MWMechanics
void setBlock(bool value);
bool getBlock() const;
std::multimap<ESM::MagicEffectId, ESM::RefNum>& getSummonedCreatureMap(); // <Effect, summoned creature>
std::multimap<ESM::RefId, ESM::RefNum>& getSummonedCreatureMap(); // <Effect, summoned creature>
enum Flag
{

View file

@ -23,11 +23,17 @@ namespace MWMechanics
{
struct EffectKey
{
ESM::MagicEffectId mId;
ESM::RefId mId;
ESM::RefId mArg; // skill or ability
EffectKey();
EffectKey(ESM::RefId id, ESM::RefId arg = {})
: mId(id)
, mArg(arg)
{
}
EffectKey(ESM::MagicEffectId id, ESM::RefId arg = {})
: mId(id)
, mArg(arg)

View file

@ -320,8 +320,8 @@ namespace MWMechanics
ESM::RefId school = ESM::Skill::Alteration;
if (!enchantment->mEffects.mList.empty())
{
short effectId = enchantment->mEffects.mList.front().mData.mEffectID;
const ESM::MagicEffect* magicEffect = store->get<ESM::MagicEffect>().find(effectId);
ESM::RefId effectId = enchantment->mEffects.mList.front().mData.mEffectID;
const ESM::MagicEffect* magicEffect = store->get<ESM::MagicEffect>().search(effectId);
school = magicEffect->mData.mSchool;
}
@ -509,7 +509,7 @@ namespace MWMechanics
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
if (animation)
{
animation->addEffect(castStaticModel.value(), ESM::MagicEffect::indexToName(effect->mIndex), false, {},
animation->addEffect(castStaticModel.value(), ESM::MagicEffect::refIdToName(effect->mId), false, {},
effect->mParticle);
}
else
@ -585,7 +585,7 @@ namespace MWMechanics
{
const VFS::Path::Normalized castStaticModel
= Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(castStatic->mModel));
anim->addEffect(castStaticModel.value(), ESM::MagicEffect::indexToName(magicEffect.mIndex), loop, {},
anim->addEffect(castStaticModel.value(), ESM::MagicEffect::refIdToName(magicEffect.mId), loop, {},
magicEffect.mParticle);
}
}

View file

@ -23,9 +23,41 @@
namespace MWMechanics
{
static const std::map<ESM::MagicEffectId, ESM::RefId>& getSummonMap()
bool isSummoningEffect(const ESM::RefId& effectId)
{
static std::map<ESM::MagicEffectId, ESM::RefId> summonMap;
if (effectId.empty())
return false;
static const std::array<ESM::MagicEffectId, 22> summonEffects{
ESM::MagicEffect::SummonAncestralGhost,
ESM::MagicEffect::SummonBonelord,
ESM::MagicEffect::SummonBonewalker,
ESM::MagicEffect::SummonCenturionSphere,
ESM::MagicEffect::SummonClannfear,
ESM::MagicEffect::SummonDaedroth,
ESM::MagicEffect::SummonDremora,
ESM::MagicEffect::SummonFabricant,
ESM::MagicEffect::SummonFlameAtronach,
ESM::MagicEffect::SummonFrostAtronach,
ESM::MagicEffect::SummonGoldenSaint,
ESM::MagicEffect::SummonGreaterBonewalker,
ESM::MagicEffect::SummonHunger,
ESM::MagicEffect::SummonScamp,
ESM::MagicEffect::SummonSkeletalMinion,
ESM::MagicEffect::SummonStormAtronach,
ESM::MagicEffect::SummonWingedTwilight,
ESM::MagicEffect::SummonWolf,
ESM::MagicEffect::SummonBear,
ESM::MagicEffect::SummonBonewolf,
ESM::MagicEffect::SummonCreature04,
ESM::MagicEffect::SummonCreature05,
};
return (std::find(summonEffects.begin(), summonEffects.end(), *effectId.getIf<ESM::MagicEffectId>())
!= summonEffects.end());
}
static const std::map<ESM::RefId, ESM::RefId>& getSummonMap()
{
static std::map<ESM::RefId, ESM::RefId> summonMap;
if (summonMap.size() > 0)
return summonMap;
@ -63,12 +95,7 @@ namespace MWMechanics
return summonMap;
}
bool isSummoningEffect(const ESM::MagicEffectId& effectId)
{
return getSummonMap().contains(effectId);
}
ESM::RefId getSummonedCreature(const ESM::MagicEffectId& effectId)
ESM::RefId getSummonedCreature(const ESM::RefId& effectId)
{
const auto& summonMap = getSummonMap();
auto it = summonMap.find(effectId);
@ -79,7 +106,7 @@ namespace MWMechanics
return ESM::RefId();
}
ESM::RefNum summonCreature(const ESM::MagicEffectId& effectId, const MWWorld::Ptr& summoner)
ESM::RefNum summonCreature(const ESM::RefId& effectId, const MWWorld::Ptr& summoner)
{
const ESM::RefId& creatureID = getSummonedCreature(effectId);
ESM::RefNum creature;
@ -150,7 +177,7 @@ namespace MWMechanics
}
}
void purgeSummonEffect(const MWWorld::Ptr& summoner, const std::pair<ESM::MagicEffectId, ESM::RefNum>& summon)
void purgeSummonEffect(const MWWorld::Ptr& summoner, const std::pair<ESM::RefId, ESM::RefNum>& summon)
{
auto& creatureStats = summoner.getClass().getCreatureStats(summoner);
creatureStats.getActiveSpells().purge(

View file

@ -10,8 +10,6 @@ namespace ESM
{
class RefId;
class StringRefId;
using MagicEffectId = StringRefId;
}
namespace MWWorld
{
@ -20,13 +18,13 @@ namespace MWWorld
namespace MWMechanics
{
bool isSummoningEffect(const ESM::MagicEffectId& effectId);
bool isSummoningEffect(const ESM::RefId& effectId);
ESM::RefId getSummonedCreature(const ESM::MagicEffectId& effectId);
ESM::RefId getSummonedCreature(const ESM::RefId& effectId);
void purgeSummonEffect(const MWWorld::Ptr& summoner, const std::pair<ESM::MagicEffectId, ESM::RefNum>& summon);
void purgeSummonEffect(const MWWorld::Ptr& summoner, const std::pair<ESM::RefId, ESM::RefNum>& summon);
ESM::RefNum summonCreature(const ESM::MagicEffectId& effectId, const MWWorld::Ptr& summoner);
ESM::RefNum summonCreature(const ESM::RefId& effectId, const MWWorld::Ptr& summoner);
void updateSummons(const MWWorld::Ptr& summoner, bool cleanup);
}

View file

@ -186,7 +186,7 @@ namespace
iter->mData.mAttribute = -1;
Log(Debug::Verbose) << RecordType::getRecordType() << " " << spell.mId
<< ": dropping unexpected attribute argument of "
<< iter->mData.mEffectID.getRefIdString() << " effect";
<< ESM::MagicEffect::refIdToName(iter->mData.mEffectID) << " effect";
changed = true;
}
@ -195,7 +195,7 @@ namespace
iter->mData.mSkill = -1;
Log(Debug::Verbose) << RecordType::getRecordType() << " " << spell.mId
<< ": dropping unexpected skill argument of "
<<iter->mData.mEffectID.getRefIdString() << " effect";
<< ESM::MagicEffect::refIdToName(iter->mData.mEffectID) << " effect";
changed = true;
}

View file

@ -31,7 +31,7 @@ namespace ESM
Flag_Invalid = 1 << 5
};
MagicEffectId mEffectId;
RefId mEffectId;
float mMagnitude;
float mMinMagnitude;
float mMaxMagnitude;

View file

@ -11,15 +11,13 @@ namespace ESM
class ESMReader;
class ESMWriter;
using MagicEffectId = StringRefId;
/** Defines a spell effect. Shared between SPEL (Spells), ALCH
(Potions) and ENCH (Item enchantments) records
*/
struct ENAMstruct
{
// Magical effect, serialized to int16
ESM::MagicEffectId mEffectID;
ESM::RefId mEffectID;
// Which skills/attributes are affected (for restore/drain spells
// etc.)

View file

@ -3,14 +3,26 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include <components/esm3/loadmgef.hpp>
#include <components/misc/concepts.hpp>
namespace ESM
{
template <typename T>
constexpr bool loading = !std::is_const_v<std::remove_reference_t<T>>;
template <Misc::SameAsWithoutCvref<Ingredient::IRDTstruct> T>
void decompose(T&& v, const auto& f)
{
f(v.mWeight, v.mValue, v.mEffectID, v.mSkills, v.mAttributes);
int32_t ioEffectID[4];
std::transform(
std::begin(v.mEffectID), std::end(v.mEffectID), std::begin(ioEffectID), ESM::MagicEffect::refIdToIndex);
f(v.mWeight, v.mValue, ioEffectID, v.mSkills, v.mAttributes);
if constexpr (loading<T>)
{
std::transform(
std::begin(ioEffectID), std::end(ioEffectID), std::begin(v.mEffectID), ESM::MagicEffect::indexToRefId);
}
}
void Ingredient::load(ESMReader& esm, bool& isDeleted)
@ -63,15 +75,21 @@ namespace ESM
// horrible hack to fix broken data in records
for (int i = 0; i < 4; ++i)
{
if (mData.mEffectID[i] != 85 && mData.mEffectID[i] != 22 && mData.mEffectID[i] != 17
&& mData.mEffectID[i] != 79 && mData.mEffectID[i] != 74)
if (mData.mEffectID[i] != ESM::MagicEffect::AbsorbAttribute &&
mData.mEffectID[i] != ESM::MagicEffect::DamageAttribute &&
mData.mEffectID[i] != ESM::MagicEffect::DrainAttribute &&
mData.mEffectID[i] != ESM::MagicEffect::FortifyAttribute &&
mData.mEffectID[i] != ESM::MagicEffect::RestoreAttribute)
{
mData.mAttributes[i] = -1;
}
// is this relevant in cycle from 0 to 4?
if (mData.mEffectID[i] != 89 && mData.mEffectID[i] != 26 && mData.mEffectID[i] != 21
&& mData.mEffectID[i] != 83 && mData.mEffectID[i] != 78)
if (mData.mEffectID[i] != ESM::MagicEffect::AbsorbSkill &&
mData.mEffectID[i] != ESM::MagicEffect::DamageSkill &&
mData.mEffectID[i] != ESM::MagicEffect::DrainSkill &&
mData.mEffectID[i] != ESM::MagicEffect::FortifySkill &&
mData.mEffectID[i] != ESM::MagicEffect::RestoreSkill)
{
mData.mSkills[i] = -1;
}
@ -102,7 +120,7 @@ namespace ESM
mData.mValue = 0;
for (int i = 0; i < 4; ++i)
{
mData.mEffectID[i] = 0;
mData.mEffectID[i] = ESM::MagicEffect::WaterBreathing;
mData.mSkills[i] = 0;
mData.mAttributes[i] = 0;
}

View file

@ -27,7 +27,7 @@ namespace ESM
{
float mWeight;
int32_t mValue;
int32_t mEffectID[4]; // Effect, -1 means none
RefId mEffectID[4]; // Effect, EmptyRefId means none
int32_t mSkills[4]; // SkillEnum related to effect
int32_t mAttributes[4]; // Attribute related to effect
};

View file

@ -826,6 +826,8 @@ namespace ESM
int MagicEffect::refIdToIndex(const RefId& effectId)
{
if (effectId.empty())
return -1;
for (size_t i = 0; i < sMagicEffectIds.size(); ++i)
if (sMagicEffectIds[i] == effectId)
return static_cast<int>(i);

View file

@ -12,13 +12,11 @@ namespace ESM
class ESMReader;
class ESMWriter;
using MagicEffectId = StringRefId;
// format 0, saved games only
struct MagicEffects
{
// <Effect Id, Base value, Modifier>
std::map<ESM::MagicEffectId, std::pair<int32_t, float>> mEffects;
std::map<ESM::RefId, std::pair<int32_t, float>> mEffects;
void load(ESMReader& esm);
void save(ESMWriter& esm) const;
@ -26,14 +24,14 @@ namespace ESM
struct SummonKey
{
SummonKey(const ESM::MagicEffectId& effectId, const ESM::RefId& sourceId, int32_t index)
SummonKey(const ESM::RefId& effectId, const ESM::RefId& sourceId, int32_t index)
: mEffectId(effectId)
, mSourceId(sourceId)
, mEffectIndex(index)
{
}
ESM::MagicEffectId mEffectId;
ESM::RefId mEffectId;
ESM::RefId mSourceId;
int32_t mEffectIndex;
};