diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 6e15449e1..eec4f2bd3 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -152,12 +152,7 @@ namespace MWMechanics void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector effects, const std::string &displayName, int casterActorId) { - bool exists = false; - for (TContainer::const_iterator it = begin(); it != end(); ++it) - { - if (id == it->first) - exists = true; - } + TContainer::iterator it(mSpells.find(id)); ActiveSpellParams params; params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp(); @@ -165,14 +160,44 @@ namespace MWMechanics params.mDisplayName = displayName; params.mCasterActorId = casterActorId; - if (!exists || stack) - mSpells.insert (std::make_pair(id, params)); + if (it == end() || stack) + { + mSpells.insert(std::make_pair(id, params)); + } else - mSpells.find(id)->second = params; + { + // addSpell() is called with effects for a range. + // but a spell may have effects with different ranges (e.g. Touch & Target) + // so, if we see new effects for same spell assume additional + // spell effects and add to existing effects of spell + mergeEffects(params.mEffects, it->second.mEffects); + it->second = params; + } mSpellsChanged = true; } + void ActiveSpells::mergeEffects(std::vector& addTo, const std::vector& from) + { + for (std::vector::const_iterator effect(from.begin()); effect != from.end(); ++effect) + { + // if effect is not in addTo, add it + bool missing = true; + for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) + { + if (effect->mEffectId == iter->mEffectId) + { + missing = false; + break; + } + } + if (missing) + { + addTo.push_back(*effect); + } + } + } + void ActiveSpells::removeEffects(const std::string &id) { mSpells.erase(Misc::StringUtils::lowerCase(id)); diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 4f9d15d8c..2a4d75d40 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -55,6 +55,9 @@ namespace MWMechanics void rebuildEffects() const; + /// Add any effects that are in "from" and not in "addTo" to "addTo" + void mergeEffects(std::vector& addTo, const std::vector& from); + double timeToExpire (const TIterator& iterator) const; ///< Returns time (in in-game hours) until the spell pointed to by \a iterator /// expires. diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f8068e800..aa2cc8615 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -515,8 +515,8 @@ namespace MWMechanics for(int i = 0;i < ESM::Attribute::Length;++i) { AttributeValue stat = creatureStats.getAttribute(i); - stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - + stat.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude(), + effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); @@ -782,8 +782,8 @@ namespace MWMechanics for(int i = 0;i < ESM::Skill::Length;++i) { SkillValue& skill = npcStats.getSkill(i); - skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - + skill.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude(), + effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 61b6d60ad..554f619a5 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -15,6 +15,11 @@ void MWMechanics::AttributeValue::readState (const ESM::StatState& state) mDamage = state.mDamage; } +void MWMechanics::AttributeValue::setModifiers(int fortify, int drain, int absorb) +{ + mFortified = fortify; + mModifier = (fortify - drain) - absorb; +} void MWMechanics::SkillValue::writeState (ESM::StatState& state) const { diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 1c33db0fd..294dbcb6c 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -235,26 +235,29 @@ namespace MWMechanics class AttributeValue { int mBase; - int mModifier; + int mFortified; + int mModifier; // net effect of Fortified, Drain & Absorb float mDamage; // needs to be float to allow continuous damage public: - AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} + AttributeValue() : mBase(0), mFortified(0), mModifier(0), mDamage(0) {} int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } int getBase() const { return mBase; } int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } - void setModifier(int mod) { mModifier = mod; } + void setModifiers(int fortify, int drain, int absorb); - void damage(float damage) { mDamage += damage; } + void damage(float damage) { mDamage = std::min(mDamage + damage, (float)(mBase + mFortified)); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } int getDamage() const { return mDamage; } void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); + + friend bool operator== (const AttributeValue& left, const AttributeValue& right); }; class SkillValue : public AttributeValue @@ -268,13 +271,16 @@ namespace MWMechanics void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); + + friend bool operator== (const SkillValue& left, const SkillValue& right); }; inline bool operator== (const AttributeValue& left, const AttributeValue& right) { return left.getBase() == right.getBase() + && left.mFortified == right.mFortified && left.getModifier() == right.getModifier() - && left.getDamage() == right.getDamage(); + && left.mDamage == right.mDamage; } inline bool operator!= (const AttributeValue& left, const AttributeValue& right) { @@ -283,9 +289,8 @@ namespace MWMechanics inline bool operator== (const SkillValue& left, const SkillValue& right) { - return left.getBase() == right.getBase() - && left.getModifier() == right.getModifier() - && left.getDamage() == right.getDamage() + // delegate to base class for most of the work + return (static_cast(left) == right) && left.getProgress() == right.getProgress(); } inline bool operator!= (const SkillValue& left, const SkillValue& right)