diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index aae756350d..81f1a9ae1d 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -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) { diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 0824405f9a..6a82643e66 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -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); diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 3c08279463..a6534d9c93 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -30,12 +30,12 @@ namespace std::optional 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(), 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().find(effectKey.mId); + = MWBase::Environment::get().getESMStore()->get().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(effectKey.mId); + effect.mEffectID = effectKey.mId; effect.mAttribute = -1; effect.mSkill = -1; @@ -621,7 +621,7 @@ std::vector MWMechanics::Alchemy::effectsDescription( if (alchemySkill < fWortChanceValue * static_cast(i + 1)) break; - if (effectID != -1) + if (!effectID.empty()) { const ESM::Attribute* attribute = store->get().search(ESM::Attribute::indexToRefId(data.mAttributes[i])); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 83fd5a1f4d..3531b7fde1 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -649,7 +649,7 @@ namespace MWMechanics return mTimeOfDeath; } - std::multimap& CreatureStats::getSummonedCreatureMap() + std::multimap& CreatureStats::getSummonedCreatureMap() { return mSummonedCreatures; } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 29c2c73e94..4cf4c2e421 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -82,7 +82,7 @@ namespace MWMechanics MWWorld::TimeStamp mTimeOfDeath; private: - std::multimap mSummonedCreatures; // + std::multimap mSummonedCreatures; // float mAwarenessTimer = 0.f; int mAwarenessRoll = -1; @@ -231,7 +231,7 @@ namespace MWMechanics void setBlock(bool value); bool getBlock() const; - std::multimap& getSummonedCreatureMap(); // + std::multimap& getSummonedCreatureMap(); // enum Flag { diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index 45de2c7beb..491f011807 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -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) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index d17bd97744..398ad09d2b 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -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().find(effectId); + ESM::RefId effectId = enchantment->mEffects.mList.front().mData.mEffectID; + const ESM::MagicEffect* magicEffect = store->get().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); } } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index bf2da8206f..e6c9a85ff2 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -23,9 +23,41 @@ namespace MWMechanics { - static const std::map& getSummonMap() + bool isSummoningEffect(const ESM::RefId& effectId) { - static std::map summonMap; + if (effectId.empty()) + return false; + static const std::array 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()) + != summonEffects.end()); + } + + static const std::map& getSummonMap() + { + static std::map 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& summon) + void purgeSummonEffect(const MWWorld::Ptr& summoner, const std::pair& summon) { auto& creatureStats = summoner.getClass().getCreatureStats(summoner); creatureStats.getActiveSpells().purge( diff --git a/apps/openmw/mwmechanics/summoning.hpp b/apps/openmw/mwmechanics/summoning.hpp index 34fc68dffc..09dac36d39 100644 --- a/apps/openmw/mwmechanics/summoning.hpp +++ b/apps/openmw/mwmechanics/summoning.hpp @@ -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& summon); + void purgeSummonEffect(const MWWorld::Ptr& summoner, const std::pair& 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); } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index ec55de0b91..ff3bf9fd5b 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -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 " - <mData.mEffectID.getRefIdString() << " effect"; + << ESM::MagicEffect::refIdToName(iter->mData.mEffectID) << " effect"; changed = true; } diff --git a/components/esm3/activespells.hpp b/components/esm3/activespells.hpp index b53e77a6e6..3cd96e9a16 100644 --- a/components/esm3/activespells.hpp +++ b/components/esm3/activespells.hpp @@ -31,7 +31,7 @@ namespace ESM Flag_Invalid = 1 << 5 }; - MagicEffectId mEffectId; + RefId mEffectId; float mMagnitude; float mMinMagnitude; float mMaxMagnitude; diff --git a/components/esm3/effectlist.hpp b/components/esm3/effectlist.hpp index b02f14dfc8..f7350f40fc 100644 --- a/components/esm3/effectlist.hpp +++ b/components/esm3/effectlist.hpp @@ -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.) diff --git a/components/esm3/loadingr.cpp b/components/esm3/loadingr.cpp index 6a4753d8e4..b0b5065434 100644 --- a/components/esm3/loadingr.cpp +++ b/components/esm3/loadingr.cpp @@ -3,14 +3,26 @@ #include "esmreader.hpp" #include "esmwriter.hpp" +#include #include namespace ESM { + template + constexpr bool loading = !std::is_const_v>; + template 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) + { + 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; } diff --git a/components/esm3/loadingr.hpp b/components/esm3/loadingr.hpp index 2a8748e067..289cf839a4 100644 --- a/components/esm3/loadingr.hpp +++ b/components/esm3/loadingr.hpp @@ -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 }; diff --git a/components/esm3/loadmgef.cpp b/components/esm3/loadmgef.cpp index aac4981dc8..b90d985088 100644 --- a/components/esm3/loadmgef.cpp +++ b/components/esm3/loadmgef.cpp @@ -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(i); diff --git a/components/esm3/magiceffects.hpp b/components/esm3/magiceffects.hpp index 82194d0039..ab93288d92 100644 --- a/components/esm3/magiceffects.hpp +++ b/components/esm3/magiceffects.hpp @@ -12,13 +12,11 @@ namespace ESM class ESMReader; class ESMWriter; - using MagicEffectId = StringRefId; - // format 0, saved games only struct MagicEffects { // - std::map> mEffects; + std::map> 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; };