From 54f52f7bae08e870713eb5dcb7c5e09be911f583 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 1 Jul 2016 18:50:28 +0200 Subject: [PATCH] Implement effect removal for abilities (Fixes #3455) --- apps/essimporter/converter.hpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/spells.cpp | 62 +++++++++++++++++++++++++----- apps/openmw/mwmechanics/spells.hpp | 10 ++++- apps/openmw/mwworld/worldimp.cpp | 1 + components/esm/spellstate.cpp | 18 +++++++-- components/esm/spellstate.hpp | 7 +++- 7 files changed, 85 insertions(+), 16 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 81b2bec14..11f966446 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -121,7 +121,7 @@ public: { mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; mContext->mPlayerBase = npc; - std::map empty; + ESM::SpellState::SpellParams empty; // FIXME: player start spells and birthsign spells aren't listed here, // need to fix openmw to account for this for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f27bb312a..9426bda4b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -513,6 +513,7 @@ namespace MWMechanics CastSpell cast(ptr, ptr); if (cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude())) { + creatureStats.getSpells().purgeEffect(it->first.mId); creatureStats.getActiveSpells().purgeEffect(it->first.mId); if (ptr.getClass().hasInventoryStore(ptr)) ptr.getClass().getInventoryStore(ptr).purgeEffect(it->first.mId); diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 2f87d0446..b4bf7ca6f 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -66,7 +66,9 @@ namespace MWMechanics mCorprusSpells[spell] = corprus; } - mSpells.insert (std::make_pair (spell, random)); + SpellParams params; + params.mEffectRands = random; + mSpells.insert (std::make_pair (spell, params)); } } @@ -124,9 +126,12 @@ namespace MWMechanics int i=0; for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != spell->mEffects.mList.end(); ++it) { + if (iter->second.mPurgedEffects.find(i) != iter->second.mPurgedEffects.end()) + continue; // effect was purged + float random = 1.f; - if (iter->second.find(i) != iter->second.end()) - random = iter->second.at(i); + if (iter->second.mEffectRands.find(i) != iter->second.mEffectRands.end()) + random = iter->second.mEffectRands.at(i); effects.add (*it, it->mMagnMin + (it->mMagnMax - it->mMagnMin) * random); ++i; @@ -259,9 +264,12 @@ namespace MWMechanics for (std::vector::const_iterator effectIt = list.mList.begin(); effectIt != list.mList.end(); ++effectIt, ++i) { + if (it->second.mPurgedEffects.find(i) != it->second.mPurgedEffects.end()) + continue; // effect was purged + float random = 1.f; - if (it->second.find(i) != it->second.end()) - random = it->second.at(i); + if (it->second.mEffectRands.find(i) != it->second.mEffectRands.end()) + random = it->second.mEffectRands.at(i); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, spell->mId, -1, magnitude); @@ -283,8 +291,8 @@ namespace MWMechanics if ((effectIt->mEffectID != ESM::MagicEffect::Corprus) && (magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) // APPLIED_ONCE { float random = 1.f; - if (mSpells[spell].find(i) != mSpells[spell].end()) - random = mSpells[spell].at(i); + if (mSpells[spell].mEffectRands.find(i) != mSpells[spell].mEffectRands.end()) + random = mSpells[spell].mEffectRands.at(i); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= std::max(1, mCorprusSpells[spell].mWorsenings); @@ -310,6 +318,36 @@ namespace MWMechanics return mCorprusSpells; } + void Spells::purgeEffect(int effectId) + { + for (TContainer::iterator spellIt = mSpells.begin(); spellIt != mSpells.end(); ++spellIt) + { + int i = 0; + for (std::vector::const_iterator effectIt = spellIt->first->mEffects.mList.begin(); effectIt != spellIt->first->mEffects.mList.end(); ++effectIt) + { + if (effectIt->mEffectID == effectId) + spellIt->second.mPurgedEffects.insert(i); + ++i; + } + } + } + + void Spells::purgeEffect(int effectId, const std::string & sourceId) + { + const ESM::Spell * spell = MWBase::Environment::get().getWorld()->getStore().get().find(sourceId); + TContainer::iterator spellIt = mSpells.find(spell); + if (spellIt == mSpells.end()) + return; + + int i = 0; + for (std::vector::const_iterator effectIt = spellIt->first->mEffects.mList.begin(); effectIt != spellIt->first->mEffects.mList.end(); ++effectIt) + { + if (effectIt->mEffectID == effectId) + spellIt->second.mPurgedEffects.insert(i); + ++i; + } + } + bool Spells::canUsePower(const ESM::Spell* spell) const { std::map::const_iterator it = mUsedPowers.find(spell); @@ -332,7 +370,8 @@ namespace MWMechanics const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); if (spell) { - mSpells[spell] = it->second; + mSpells[spell].mEffectRands = it->second.mEffectRands; + mSpells[spell].mPurgedEffects = it->second.mPurgedEffects; if (it->first == state.mSelectedSpell) mSelectedSpell = it->first; @@ -375,7 +414,12 @@ namespace MWMechanics void Spells::writeState(ESM::SpellState &state) const { for (TContainer::const_iterator it = mSpells.begin(); it != mSpells.end(); ++it) - state.mSpells.insert(std::make_pair(it->first->mId, it->second)); + { + ESM::SpellState::SpellParams params; + params.mEffectRands = it->second.mEffectRands; + params.mPurgedEffects = it->second.mPurgedEffects; + state.mSpells.insert(std::make_pair(it->first->mId, params)); + } state.mSelectedSpell = mSelectedSpell; diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index a46988c4c..0e72cd131 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -32,8 +33,12 @@ namespace MWMechanics public: typedef const ESM::Spell* SpellKey; + struct SpellParams { + std::map mEffectRands; // + std::set mPurgedEffects; // indices of purged effects + }; - typedef std::map > TContainer; // ID, + typedef std::map TContainer; typedef TContainer::const_iterator TIterator; struct CorprusStats @@ -67,6 +72,9 @@ namespace MWMechanics static bool hasCorprusEffect(const ESM::Spell *spell); const std::map & getCorprusSpells() const; + void purgeEffect(int effectId); + void purgeEffect(int effectId, const std::string & sourceId); + bool canUsePower (const ESM::Spell* spell) const; void usePower (const ESM::Spell* spell); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 313fe73b1..cb31d6e0d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2687,6 +2687,7 @@ namespace MWWorld void World::breakInvisibility(const Ptr &actor) { + actor.getClass().getCreatureStats(actor).getSpells().purgeEffect(ESM::MagicEffect::Invisibility); actor.getClass().getCreatureStats(actor).getActiveSpells().purgeEffect(ESM::MagicEffect::Invisibility); if (actor.getClass().hasInventoryStore(actor)) actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Invisibility); diff --git a/components/esm/spellstate.cpp b/components/esm/spellstate.cpp index 8845842e9..a21078e10 100644 --- a/components/esm/spellstate.cpp +++ b/components/esm/spellstate.cpp @@ -12,7 +12,7 @@ namespace ESM { std::string id = esm.getHString(); - std::map random; + SpellParams state; while (esm.isNextSub("INDX")) { int index; @@ -21,10 +21,16 @@ namespace ESM float magnitude; esm.getHNT(magnitude, "RAND"); - random[index] = magnitude; + state.mEffectRands[index] = magnitude; } - mSpells[id] = random; + while (esm.isNextSub("PURG")) { + int index; + esm.getHT(index); + state.mPurgedEffects.insert(index); + } + + mSpells[id] = state; } while (esm.isNextSub("PERM")) @@ -73,12 +79,16 @@ namespace ESM { esm.writeHNString("SPEL", it->first); - const std::map& random = it->second; + const std::map& random = it->second.mEffectRands; for (std::map::const_iterator rIt = random.begin(); rIt != random.end(); ++rIt) { esm.writeHNT("INDX", rIt->first); esm.writeHNT("RAND", rIt->second); } + + const std::set& purges = it->second.mPurgedEffects; + for (std::set::const_iterator pIt = purges.begin(); pIt != purges.end(); ++pIt) + esm.writeHNT("PURG", *pIt); } for (std::map >::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) diff --git a/components/esm/spellstate.hpp b/components/esm/spellstate.hpp index 503c3aea9..ec613afab 100644 --- a/components/esm/spellstate.hpp +++ b/components/esm/spellstate.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "defs.hpp" @@ -28,7 +29,11 @@ namespace ESM float mMagnitude; }; - typedef std::map > TContainer; + struct SpellParams { + std::map mEffectRands; + std::set mPurgedEffects; + }; + typedef std::map TContainer; TContainer mSpells; std::map > mPermanentSpellEffects;