From 74ebb29dd06e3cbac051f6ac79c145a3ce5563fd Mon Sep 17 00:00:00 2001 From: Telvanni 4Life Date: Sat, 20 Dec 2025 17:04:58 -0500 Subject: [PATCH] - Used addRecordFunctionBinding in magic effect binding. - Changed find to search. - Restored Hyrum's Law use of effect system by Visible Rings. --- apps/opencs/model/doc/document.cpp | 2 -- apps/openmw/mwlua/magicbindings.cpp | 40 +++++++++------------------ apps/openmw/mwmechanics/character.cpp | 6 ++++ 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7119268a27..66f847b787 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -289,9 +289,7 @@ void CSMDoc::Document::createBase() for (int i = 0; i < ESM::MagicEffect::Length; ++i) { ESM::MagicEffect record; - record.mId = *ESM::MagicEffect::indexToRefId(i).getIf(); - record.blank(); getData().getMagicEffects().add(record); diff --git a/apps/openmw/mwlua/magicbindings.cpp b/apps/openmw/mwlua/magicbindings.cpp index c31e4cdeb3..15d21034d6 100644 --- a/apps/openmw/mwlua/magicbindings.cpp +++ b/apps/openmw/mwlua/magicbindings.cpp @@ -263,23 +263,9 @@ namespace MWLua // MagicEffect store sol::table magicEffects(state, sol::create); + addRecordFunctionBinding(magicEffects, context); magicApi["effects"] = LuaUtil::makeReadOnly(magicEffects); - using MagicEffectStore = MWWorld::Store; - const MagicEffectStore* magicEffectStore - = &MWBase::Environment::get().getWorld()->getStore().get(); - auto magicEffectStoreT = state.new_usertype("ESM3_MagicEffectStore"); - magicEffectStoreT[sol::meta_function::to_string] = [](const MagicEffectStore& store) { - return "ESM3_MagicEffectStore{" + std::to_string(store.getSize()) + " effects}"; - }; - magicEffectStoreT[sol::meta_function::index] = sol::overload( - [](const MagicEffectStore& store, const ESM::RefId& id) -> const ESM::MagicEffect* { return store.search(id); }, - [](const MagicEffectStore& store, int id) -> const ESM::MagicEffect* { return store.search(ESM::MagicEffect::indexToRefId(id)); }, - [](const MagicEffectStore& store, std::string_view id) -> const ESM::MagicEffect* { - int index = ESM::MagicEffect::indexNameToIndex(id); - return store.search(ESM::MagicEffect::indexToRefId(index)); - }); - - magicEffects["records"] = magicEffectStore; + const auto* magicEffectStore = &MWBase::Environment::get().getWorld()->getStore().get(); // Spell record auto spellT = state.new_usertype("ESM3_Spell"); @@ -330,7 +316,7 @@ namespace MWLua }; effectParamsT["effect"] = sol::readonly_property( [magicEffectStore](const ESM::IndexedENAMstruct& params) -> const ESM::MagicEffect* { - return magicEffectStore->find(params.mData.mEffectID); + return magicEffectStore->search(params.mData.mEffectID); }); effectParamsT["id"] = sol::readonly_property([](const ESM::IndexedENAMstruct& params) -> std::string { auto name = ESM::MagicEffect::refIdToName(params.mData.mEffectID); @@ -447,7 +433,7 @@ namespace MWLua }); activeSpellEffectT["affectedSkill"] = sol::readonly_property([magicEffectStore](const ESM::ActiveEffect& self) -> sol::optional { - auto* rec = magicEffectStore->find(self.mEffectId); + auto* rec = magicEffectStore->search(self.mEffectId); if (rec->mData.mFlags & ESM::MagicEffect::TargetSkill) return self.getSkillOrAttribute().serializeText(); else @@ -455,7 +441,7 @@ namespace MWLua }); activeSpellEffectT["affectedAttribute"] = sol::readonly_property([magicEffectStore](const ESM::ActiveEffect& self) -> sol::optional { - auto* rec = magicEffectStore->find(self.mEffectId); + auto* rec = magicEffectStore->search(self.mEffectId); if (rec->mData.mFlags & ESM::MagicEffect::TargetAttribute) return self.getSkillOrAttribute().serializeText(); else @@ -463,21 +449,21 @@ namespace MWLua }); activeSpellEffectT["magnitudeThisFrame"] = sol::readonly_property([magicEffectStore](const ESM::ActiveEffect& self) -> sol::optional { - auto* rec = magicEffectStore->find(self.mEffectId); + auto* rec = magicEffectStore->search(self.mEffectId); if (rec->mData.mFlags & ESM::MagicEffect::Flags::NoMagnitude) return sol::nullopt; return self.mMagnitude; }); activeSpellEffectT["minMagnitude"] = sol::readonly_property([magicEffectStore](const ESM::ActiveEffect& self) -> sol::optional { - auto* rec = magicEffectStore->find(self.mEffectId); + auto* rec = magicEffectStore->search(self.mEffectId); if (rec->mData.mFlags & ESM::MagicEffect::Flags::NoMagnitude) return sol::nullopt; return self.mMinMagnitude; }); activeSpellEffectT["maxMagnitude"] = sol::readonly_property([magicEffectStore](const ESM::ActiveEffect& self) -> sol::optional { - auto* rec = magicEffectStore->find(self.mEffectId); + auto* rec = magicEffectStore->search(self.mEffectId); if (rec->mData.mFlags & ESM::MagicEffect::Flags::NoMagnitude) return sol::nullopt; return self.mMaxMagnitude; @@ -487,7 +473,7 @@ namespace MWLua // Permanent/constant effects, abilities, etc. will have a negative duration if (self.mDuration < 0) return sol::nullopt; - auto* rec = magicEffectStore->find(self.mEffectId); + auto* rec = magicEffectStore->search(self.mEffectId); if (rec->mData.mFlags & ESM::MagicEffect::Flags::NoDuration) return sol::nullopt; return self.mTimeLeft; @@ -497,7 +483,7 @@ namespace MWLua // Permanent/constant effects, abilities, etc. will have a negative duration if (self.mDuration < 0) return sol::nullopt; - auto* rec = magicEffectStore->find(self.mEffectId); + auto* rec = magicEffectStore->search(self.mEffectId); if (rec->mData.mFlags & ESM::MagicEffect::Flags::NoDuration) return sol::nullopt; return self.mDuration; @@ -580,14 +566,14 @@ namespace MWLua activeEffectT["affectedSkill"] = sol::readonly_property([magicEffectStore](const ActiveEffect& self) -> sol::optional { - auto* rec = magicEffectStore->find(self.key.mId); + auto* rec = magicEffectStore->search(self.key.mId); if (rec->mData.mFlags & ESM::MagicEffect::TargetSkill) return self.key.mArg.serializeText(); return sol::nullopt; }); activeEffectT["affectedAttribute"] = sol::readonly_property([magicEffectStore](const ActiveEffect& self) -> sol::optional { - auto* rec = magicEffectStore->find(self.key.mId); + auto* rec = magicEffectStore->search(self.key.mId); if (rec->mData.mFlags & ESM::MagicEffect::TargetAttribute) return self.key.mArg.serializeText(); return sol::nullopt; @@ -944,7 +930,7 @@ namespace MWLua for (const ESM::IndexedENAMstruct& enam : enams) { - const ESM::MagicEffect* mgef = esmStore.get().find(enam.mData.mEffectID); + const ESM::MagicEffect* mgef = esmStore.get().search(enam.mData.mEffectID); MWMechanics::ActiveSpells::ActiveEffect effect; effect.mEffectId = enam.mData.mEffectID; effect.mArg = MWMechanics::EffectKey(enam.mData).mArg; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c30c865412..90be77fc12 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2807,6 +2807,12 @@ namespace MWMechanics { auto effectId = ESM::MagicEffectId(effectStr); + // This check is to preserve backward compatibility with mods that overload the magic effect + // system (e.g. using it as a mesh attachment system). This will need to be removed when effect + // dehardcoding is implemented so custom magic effect animations are processed correctly. + if (ESM::MagicEffect::refIdToIndex(effectId) < 0) + continue; + if (mPtr.getClass().getCreatureStats(mPtr).isDeathAnimationFinished() || mPtr.getClass() .getCreatureStats(mPtr)