diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 7a4369a464..c19b494845 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -241,7 +241,25 @@ namespace MWMechanics // Erase no longer active spells and effects for (auto spellIt = mSpells.begin(); spellIt != mSpells.end();) { - if (!spellIt->hasFlag(ESM::ActiveSpells::Flag_Temporary)) + if (spellIt->hasFlag(ESM::ActiveSpells::Flag_SpellStore)) + { + const ESM::Spell* spell + = MWBase::Environment::get().getESMStore()->get().search(spellIt->mSourceSpellId); + if (spell && ptr.getClass().getCreatureStats(ptr).getSpells().hasSpell(spell)) + ++spellIt; + else + { + if (spell == nullptr) + Log(Debug::Error) << "Dropping non-existent active effect: " << spellIt->mSourceSpellId; + auto params = *spellIt; + spellIt = mSpells.erase(spellIt); + for (const auto& effect : params.mEffects) + onMagicEffectRemoved(ptr, params, effect); + applyPurges(ptr, &spellIt); + } + continue; + } + else if (!spellIt->hasFlag(ESM::ActiveSpells::Flag_Temporary)) { ++spellIt; continue; @@ -416,20 +434,7 @@ namespace MWMechanics if (context.mEraseRemoved) { bool remove = false; - if (spellIt->hasFlag(ESM::ActiveSpells::Flag_SpellStore)) - { - try - { - auto& spells = ptr.getClass().getCreatureStats(ptr).getSpells(); - remove = !spells.hasSpell(spellIt->mSourceSpellId); - } - catch (const std::runtime_error& e) - { - remove = true; - Log(Debug::Error) << "Removing active effect: " << e.what(); - } - } - else if (spellIt->hasFlag(ESM::ActiveSpells::Flag_Equipment)) + if (spellIt->hasFlag(ESM::ActiveSpells::Flag_Equipment)) { // Remove effects tied to equipment that has been unequipped const auto& store = ptr.getClass().getInventoryStore(ptr); diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index efeb45dd86..f8363118bf 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -398,6 +398,23 @@ namespace { ESM::MagicEffect::BoundShield, "sMagicBoundShieldID" }, { ESM::MagicEffect::BoundSpear, "sMagicBoundSpearID" }, }; + + using SpellsPurge = void (MWMechanics::Spells::*)(); + void purgePermanent(const MWWorld::Ptr& target, SpellsPurge method, ESM::Spell::SpellType type) + { + MWMechanics::CreatureStats& stats = target.getClass().getCreatureStats(target); + (stats.getSpells().*method)(); + stats.getActiveSpells().purge( + [type](const MWMechanics::ActiveSpells::ActiveSpellParams& params) { + if (params.hasFlag(ESM::ActiveSpells::Flag_SpellStore)) + { + const ESM::Spell* spell = params.getSpell(); + return spell && spell->mData.mType == type; + } + return false; + }, + target); + } } namespace MWMechanics @@ -412,13 +429,13 @@ namespace MWMechanics switch (effect.mEffectId) { case ESM::MagicEffect::CureCommonDisease: - target.getClass().getCreatureStats(target).getSpells().purgeCommonDisease(); + purgePermanent(target, &Spells::purgeCommonDisease, ESM::Spell::ST_Disease); break; case ESM::MagicEffect::CureBlightDisease: - target.getClass().getCreatureStats(target).getSpells().purgeBlightDisease(); + purgePermanent(target, &Spells::purgeBlightDisease, ESM::Spell::ST_Blight); break; case ESM::MagicEffect::RemoveCurse: - target.getClass().getCreatureStats(target).getSpells().purgeCurses(); + purgePermanent(target, &Spells::purgeCurses, ESM::Spell::ST_Curse); break; case ESM::MagicEffect::CureCorprusDisease: target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(