1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-28 16:39:39 +00:00

Merge pull request #2899 from akortunov/multiple_effects

Track magic effect index for summoning
This commit is contained in:
Bret Curtis 2020-09-01 14:17:49 +02:00 committed by GitHub
commit 53e581fe10
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 131 additions and 71 deletions

View file

@ -252,7 +252,7 @@ namespace MWGui
} }
// Clean up summoned creatures as well // Clean up summoned creatures as well
std::map<MWMechanics::CreatureStats::SummonKey, int>& creatureMap = creatureStats.getSummonedCreatureMap(); std::map<ESM::SummonKey, int>& creatureMap = creatureStats.getSummonedCreatureMap();
for (const auto& creature : creatureMap) for (const auto& creature : creatureMap)
MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mPtr, creature.second); MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mPtr, creature.second);
creatureMap.clear(); creatureMap.clear();

View file

@ -25,8 +25,8 @@
namespace MWGui namespace MWGui
{ {
void EffectSourceVisitor::visit (MWMechanics::EffectKey key, void EffectSourceVisitor::visit (MWMechanics::EffectKey key, int effectIndex,
const std::string& sourceName, const std::string& sourceId, int casterActorId, const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime, float totalTime) float magnitude, float remainingTime, float totalTime)
{ {
MagicEffectInfo newEffectSource; MagicEffectInfo newEffectSource;

View file

@ -46,8 +46,8 @@ namespace MWGui
virtual ~EffectSourceVisitor() {} virtual ~EffectSourceVisitor() {}
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key, int effectIndex,
const std::string& sourceName, const std::string& sourceId, int casterActorId, const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1); float magnitude, float remainingTime = -1, float totalTime = -1);
}; };

View file

@ -210,9 +210,8 @@ namespace MWMechanics
std::string name = it->second.mDisplayName; std::string name = it->second.mDisplayName;
float magnitude = effectIt->mMagnitude; float magnitude = effectIt->mMagnitude;
if (magnitude) if (magnitude)
visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, effectIt->mTimeLeft, effectIt->mDuration); visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), effectIt->mEffectIndex, name, it->first, it->second.mCasterActorId, magnitude, effectIt->mTimeLeft, effectIt->mDuration);
} }
} }
} }
@ -258,14 +257,14 @@ namespace MWMechanics
mSpellsChanged = true; mSpellsChanged = true;
} }
void ActiveSpells::purgeEffect(short effectId, const std::string& sourceId) void ActiveSpells::purgeEffect(short effectId, const std::string& sourceId, int effectIndex)
{ {
for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it) for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it)
{ {
for (std::vector<ActiveEffect>::iterator effectIt = it->second.mEffects.begin(); for (std::vector<ActiveEffect>::iterator effectIt = it->second.mEffects.begin();
effectIt != it->second.mEffects.end();) effectIt != it->second.mEffects.end();)
{ {
if (effectIt->mEffectId == effectId && it->first == sourceId) if (effectIt->mEffectId == effectId && it->first == sourceId && (effectIndex < 0 || effectIndex == effectIt->mEffectIndex))
effectIt = it->second.mEffects.erase(effectIt); effectIt = it->second.mEffects.erase(effectIt);
else else
++effectIt; ++effectIt;

View file

@ -85,7 +85,7 @@ namespace MWMechanics
void purgeEffect (short effectId); void purgeEffect (short effectId);
/// Remove all active effects with this effect id and source id /// Remove all active effects with this effect id and source id
void purgeEffect (short effectId, const std::string& sourceId); void purgeEffect (short effectId, const std::string& sourceId, int effectIndex=-1);
/// Remove all active effects, if roll succeeds (for each effect) /// Remove all active effects, if roll succeeds (for each effect)
void purgeAll(float chance, bool spellOnly = false); void purgeAll(float chance, bool spellOnly = false);

View file

@ -88,12 +88,13 @@ class CheckActorCommanded : public MWMechanics::EffectSourceVisitor
MWWorld::Ptr mActor; MWWorld::Ptr mActor;
public: public:
bool mCommanded; bool mCommanded;
CheckActorCommanded(const MWWorld::Ptr& actor) CheckActorCommanded(const MWWorld::Ptr& actor)
: mActor(actor) : mActor(actor)
, mCommanded(false){} , mCommanded(false){}
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key, int effectIndex,
const std::string& sourceName, const std::string& sourceId, int casterActorId, const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1) float magnitude, float remainingTime = -1, float totalTime = -1)
{ {
if (((key.mId == ESM::MagicEffect::CommandHumanoid && mActor.getClass().isNpc()) if (((key.mId == ESM::MagicEffect::CommandHumanoid && mActor.getClass().isNpc())
@ -156,8 +157,8 @@ namespace MWMechanics
GetStuntedMagickaDuration(const MWWorld::Ptr& actor) GetStuntedMagickaDuration(const MWWorld::Ptr& actor)
: mRemainingTime(0.f){} : mRemainingTime(0.f){}
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key, int effectIndex,
const std::string& sourceName, const std::string& sourceId, int casterActorId, const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1) float magnitude, float remainingTime = -1, float totalTime = -1)
{ {
if (mRemainingTime == -1) return; if (mRemainingTime == -1) return;
@ -186,8 +187,8 @@ namespace MWMechanics
{ {
} }
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key, int effectIndex,
const std::string& sourceName, const std::string& sourceId, int casterActorId, const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1) float magnitude, float remainingTime = -1, float totalTime = -1)
{ {
if (magnitude <= 0) if (magnitude <= 0)
@ -206,8 +207,8 @@ namespace MWMechanics
{ {
public: public:
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key, int effectIndex,
const std::string& sourceName, const std::string& sourceId, int casterActorId, const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1) float magnitude, float remainingTime = -1, float totalTime = -1)
{ {
if (key.mId != ESM::MagicEffect::Corprus) if (key.mId != ESM::MagicEffect::Corprus)
@ -231,8 +232,8 @@ namespace MWMechanics
{ {
} }
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key, int effectIndex,
const std::string& sourceName, const std::string& sourceId, int casterActorId, const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1) float magnitude, float remainingTime = -1, float totalTime = -1)
{ {
if (mTrapped) if (mTrapped)
@ -894,7 +895,7 @@ namespace MWMechanics
{ {
} }
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key, int /*effectIndex*/,
const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/, const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/,
float magnitude, float remainingTime = -1, float /*totalTime*/ = -1) float magnitude, float remainingTime = -1, float /*totalTime*/ = -1)
{ {
@ -1196,6 +1197,7 @@ namespace MWMechanics
{ {
UpdateSummonedCreatures updateSummonedCreatures(ptr); UpdateSummonedCreatures updateSummonedCreatures(ptr);
creatureStats.getActiveSpells().visitEffectSources(updateSummonedCreatures); creatureStats.getActiveSpells().visitEffectSources(updateSummonedCreatures);
creatureStats.getSpells().visitEffectSources(updateSummonedCreatures);
if (ptr.getClass().hasInventoryStore(ptr)) if (ptr.getClass().hasInventoryStore(ptr))
ptr.getClass().getInventoryStore(ptr).visitEffectSources(updateSummonedCreatures); ptr.getClass().getInventoryStore(ptr).visitEffectSources(updateSummonedCreatures);
updateSummonedCreatures.process(mTimerDisposeSummonsCorpses == 0.f); updateSummonedCreatures.process(mTimerDisposeSummonsCorpses == 0.f);
@ -2014,7 +2016,7 @@ namespace MWMechanics
// Remove the summoned creature's summoned creatures as well // Remove the summoned creature's summoned creatures as well
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
std::map<CreatureStats::SummonKey, int>& creatureMap = stats.getSummonedCreatureMap(); std::map<ESM::SummonKey, int>& creatureMap = stats.getSummonedCreatureMap();
for (const auto& creature : creatureMap) for (const auto& creature : creatureMap)
cleanupSummonedCreature(stats, creature.second); cleanupSummonedCreature(stats, creature.second);
creatureMap.clear(); creatureMap.clear();

View file

@ -683,7 +683,7 @@ namespace MWMechanics
return mTimeOfDeath; return mTimeOfDeath;
} }
std::map<CreatureStats::SummonKey, int>& CreatureStats::getSummonedCreatureMap() std::map<ESM::SummonKey, int>& CreatureStats::getSummonedCreatureMap()
{ {
return mSummonedCreatures; return mSummonedCreatures;
} }

View file

@ -13,6 +13,7 @@
#include "drawstate.hpp" #include "drawstate.hpp"
#include <components/esm/attr.hpp> #include <components/esm/attr.hpp>
#include <components/esm/magiceffects.hpp>
namespace ESM namespace ESM
{ {
@ -83,10 +84,8 @@ namespace MWMechanics
// The difference between view direction and lower body direction. // The difference between view direction and lower body direction.
float mSideMovementAngle; float mSideMovementAngle;
public:
typedef std::pair<int, std::string> SummonKey; // <ESM::MagicEffect index, spell ID>
private: private:
std::map<SummonKey, int> mSummonedCreatures; // <SummonKey, ActorId> std::map<ESM::SummonKey, int> mSummonedCreatures; // <SummonKey, ActorId>
// Contains ActorIds of summoned creatures with an expired lifetime that have not been deleted yet. // Contains ActorIds of summoned creatures with an expired lifetime that have not been deleted yet.
// This may be necessary when the creature is in an inactive cell. // This may be necessary when the creature is in an inactive cell.
@ -235,7 +234,7 @@ namespace MWMechanics
void setBlock(bool value); void setBlock(bool value);
bool getBlock() const; bool getBlock() const;
std::map<SummonKey, int>& getSummonedCreatureMap(); // <SummonKey, ActorId of summoned creature> std::map<ESM::SummonKey, int>& getSummonedCreatureMap(); // <SummonKey, ActorId of summoned creature>
std::vector<int>& getSummonedCreatureGraveyard(); // ActorIds std::vector<int>& getSummonedCreatureGraveyard(); // ActorIds
enum Flag enum Flag

View file

@ -58,6 +58,7 @@ namespace MWMechanics
std::vector<ActiveSpells::ActiveEffect> absorbEffects; std::vector<ActiveSpells::ActiveEffect> absorbEffects;
ActiveSpells::ActiveEffect absorbEffect = appliedEffect; ActiveSpells::ActiveEffect absorbEffect = appliedEffect;
absorbEffect.mMagnitude *= -1; absorbEffect.mMagnitude *= -1;
absorbEffect.mEffectIndex = appliedEffect.mEffectIndex;
absorbEffects.emplace_back(absorbEffect); absorbEffects.emplace_back(absorbEffect);
// Morrowind negates reflected Absorb spells so the original caster won't be harmed. // Morrowind negates reflected Absorb spells so the original caster won't be harmed.

View file

@ -74,8 +74,8 @@ namespace MWMechanics
{ {
virtual ~EffectSourceVisitor() { } virtual ~EffectSourceVisitor() { }
virtual void visit (MWMechanics::EffectKey key, virtual void visit (EffectKey key, int effectIndex,
const std::string& sourceName, const std::string& sourceId, int casterActorId, const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1) = 0; float magnitude, float remainingTime = -1, float totalTime = -1) = 0;
}; };

View file

@ -23,8 +23,8 @@ namespace MWMechanics
GetAbsorptionProbability() = default; GetAbsorptionProbability() = default;
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key, int /*effectIndex*/,
const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/, const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/,
float magnitude, float /*remainingTime*/, float /*totalTime*/) float magnitude, float /*remainingTime*/, float /*totalTime*/)
{ {
if (key.mId == ESM::MagicEffect::SpellAbsorption) if (key.mId == ESM::MagicEffect::SpellAbsorption)

View file

@ -121,8 +121,9 @@ namespace MWMechanics
// Try absorbing the spell. Some handling must still happen for absorbed effects. // Try absorbing the spell. Some handling must still happen for absorbed effects.
bool absorbed = absorbSpell(spell, caster, target); bool absorbed = absorbSpell(spell, caster, target);
int currentEffectIndex = 0;
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (effects.mList.begin()); for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (effects.mList.begin());
!target.isEmpty() && effectIt != effects.mList.end(); ++effectIt) !target.isEmpty() && effectIt != effects.mList.end(); ++effectIt, ++currentEffectIndex)
{ {
if (effectIt->mRange != range) if (effectIt->mRange != range)
continue; continue;
@ -189,6 +190,7 @@ namespace MWMechanics
effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
effect.mMagnitude = magnitude; effect.mMagnitude = magnitude;
effect.mTimeLeft = 0.f; effect.mTimeLeft = 0.f;
effect.mEffectIndex = currentEffectIndex;
// Avoid applying absorb effects if the caster is the target // Avoid applying absorb effects if the caster is the target
// We still need the spell to be added // We still need the spell to be added
@ -268,7 +270,8 @@ namespace MWMechanics
if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor()) if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor())
{ {
CreatureStats& targetStats = target.getClass().getCreatureStats(target); CreatureStats& targetStats = target.getClass().getCreatureStats(target);
std::map<CreatureStats::SummonKey, int>::iterator findCreature = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId)); ESM::SummonKey key(effectIt->mEffectID, mId, currentEffectIndex);
auto findCreature = targetStats.getSummonedCreatureMap().find(key);
if (findCreature != targetStats.getSummonedCreatureMap().end()) if (findCreature != targetStats.getSummonedCreatureMap().end())
{ {
MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(target, findCreature->second); MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(target, findCreature->second);

View file

@ -50,7 +50,10 @@ namespace MWMechanics
for (const auto& effect : spell->mEffects.mList) for (const auto& effect : spell->mEffects.mList)
{ {
if (iter.second.mPurgedEffects.find(i) != iter.second.mPurgedEffects.end()) if (iter.second.mPurgedEffects.find(i) != iter.second.mPurgedEffects.end())
{
++i;
continue; // effect was purged continue; // effect was purged
}
float random = 1.f; float random = 1.f;
if (iter.second.mEffectRands.find(i) != iter.second.mEffectRands.end()) if (iter.second.mEffectRands.find(i) != iter.second.mEffectRands.end())
@ -108,7 +111,7 @@ namespace MWMechanics
SpellParams params; SpellParams params;
params.mEffectRands = random; params.mEffectRands = random;
mSpells.insert (std::make_pair (spell, params)); mSpells.emplace(spell, params);
mSpellsChanged = true; mSpellsChanged = true;
} }
} }
@ -272,7 +275,8 @@ namespace MWMechanics
const ESM::Spell * spell = it.first; const ESM::Spell * spell = it.first;
for (const auto& effectIt : it.second) for (const auto& effectIt : it.second)
{ {
visitor.visit(effectIt.first, spell->mName, spell->mId, -1, effectIt.second.getMagnitude()); // FIXME: since Spells merges effects with the same ID, there is no sense to use multiple effects with same ID here
visitor.visit(effectIt.first, -1, spell->mName, spell->mId, -1, effectIt.second.getMagnitude());
} }
} }
} }
@ -308,20 +312,24 @@ namespace MWMechanics
void Spells::purgeEffect(int effectId, const std::string & sourceId) void Spells::purgeEffect(int effectId, const std::string & sourceId)
{ {
const ESM::Spell * spell = SpellList::getSpell(sourceId); // Effect source may be not a spell
const ESM::Spell * spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(sourceId);
if (spell == nullptr)
return;
auto spellIt = mSpells.find(spell); auto spellIt = mSpells.find(spell);
if (spellIt == mSpells.end()) if (spellIt == mSpells.end())
return; return;
int i = 0; int index = 0;
for (auto& effectIt : spellIt->first->mEffects.mList) for (auto& effectIt : spellIt->first->mEffects.mList)
{ {
if (effectIt.mEffectID == effectId) if (effectIt.mEffectID == effectId)
{ {
spellIt->second.mPurgedEffects.insert(i); spellIt->second.mPurgedEffects.insert(index);
mSpellsChanged = true; mSpellsChanged = true;
} }
++i; ++index;
} }
} }
@ -441,7 +449,7 @@ namespace MWMechanics
ESM::SpellState::SpellParams params; ESM::SpellState::SpellParams params;
params.mEffectRands = it.second.mEffectRands; params.mEffectRands = it.second.mEffectRands;
params.mPurgedEffects = it.second.mPurgedEffects; params.mPurgedEffects = it.second.mPurgedEffects;
state.mSpells.insert(std::make_pair(it.first->mId, params)); state.mSpells.emplace(it.first->mId, params);
} }
} }

View file

@ -65,25 +65,25 @@ namespace MWMechanics
{ {
} }
void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) void UpdateSummonedCreatures::visit(EffectKey key, int effectIndex, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime)
{ {
if (isSummoningEffect(key.mId) && magnitude > 0) if (isSummoningEffect(key.mId) && magnitude > 0)
{ {
mActiveEffects.insert(std::make_pair(key.mId, sourceId)); mActiveEffects.insert(ESM::SummonKey(key.mId, sourceId, effectIndex));
} }
} }
void UpdateSummonedCreatures::process(bool cleanup) void UpdateSummonedCreatures::process(bool cleanup)
{ {
MWMechanics::CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor); MWMechanics::CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor);
std::map<CreatureStats::SummonKey, int>& creatureMap = creatureStats.getSummonedCreatureMap(); std::map<ESM::SummonKey, int>& creatureMap = creatureStats.getSummonedCreatureMap();
for (std::set<std::pair<int, std::string> >::iterator it = mActiveEffects.begin(); it != mActiveEffects.end(); ++it) for (std::set<ESM::SummonKey>::iterator it = mActiveEffects.begin(); it != mActiveEffects.end(); ++it)
{ {
bool found = creatureMap.find(std::make_pair(it->first, it->second)) != creatureMap.end(); bool found = creatureMap.find(*it) != creatureMap.end();
if (!found) if (!found)
{ {
std::string creatureID = getSummonedCreature(it->first); std::string creatureID = getSummonedCreature(it->mEffectId);
if (!creatureID.empty()) if (!creatureID.empty())
{ {
int creatureActorId = -1; int creatureActorId = -1;
@ -115,13 +115,13 @@ namespace MWMechanics
// still insert into creatureMap so we don't try to spawn again every frame, that would spam the warning log // still insert into creatureMap so we don't try to spawn again every frame, that would spam the warning log
} }
creatureMap.insert(std::make_pair(*it, creatureActorId)); creatureMap.emplace(*it, creatureActorId);
} }
} }
} }
// Update summon effects // Update summon effects
for (std::map<CreatureStats::SummonKey, int>::iterator it = creatureMap.begin(); it != creatureMap.end(); ) for (std::map<ESM::SummonKey, int>::iterator it = creatureMap.begin(); it != creatureMap.end(); )
{ {
bool found = mActiveEffects.find(it->first) != mActiveEffects.end(); bool found = mActiveEffects.find(it->first) != mActiveEffects.end();
if (!found) if (!found)
@ -143,15 +143,17 @@ namespace MWMechanics
if (!cleanup) if (!cleanup)
return; return;
for (std::map<CreatureStats::SummonKey, int>::iterator it = creatureMap.begin(); it != creatureMap.end(); ) for (std::map<ESM::SummonKey, int>::iterator it = creatureMap.begin(); it != creatureMap.end(); )
{ {
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second);
if (ptr.isEmpty() || (ptr.getClass().getCreatureStats(ptr).isDead() && ptr.getClass().getCreatureStats(ptr).isDeathAnimationFinished())) if (ptr.isEmpty() || (ptr.getClass().getCreatureStats(ptr).isDead() && ptr.getClass().getCreatureStats(ptr).isDeathAnimationFinished()))
{ {
// Purge the magic effect so a new creature can be summoned if desired // Purge the magic effect so a new creature can be summoned if desired
creatureStats.getActiveSpells().purgeEffect(it->first.first, it->first.second); const ESM::SummonKey& key = it->first;
creatureStats.getActiveSpells().purgeEffect(key.mEffectId, key.mSourceId, key.mEffectIndex);
creatureStats.getSpells().purgeEffect(key.mEffectId, key.mSourceId);
if (mActor.getClass().hasInventoryStore(mActor)) if (mActor.getClass().hasInventoryStore(mActor))
mActor.getClass().getInventoryStore(mActor).purgeEffect(it->first.first, it->first.second); mActor.getClass().getInventoryStore(mActor).purgeEffect(key.mEffectId, key.mSourceId, false, key.mEffectIndex);
MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mActor, it->second); MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mActor, it->second);
creatureMap.erase(it++); creatureMap.erase(it++);

View file

@ -5,6 +5,8 @@
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include <components/esm/magiceffects.hpp>
#include "magiceffects.hpp" #include "magiceffects.hpp"
namespace MWMechanics namespace MWMechanics
@ -20,8 +22,8 @@ namespace MWMechanics
UpdateSummonedCreatures(const MWWorld::Ptr& actor); UpdateSummonedCreatures(const MWWorld::Ptr& actor);
virtual ~UpdateSummonedCreatures() = default; virtual ~UpdateSummonedCreatures() = default;
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key, int effectIndex,
const std::string& sourceName, const std::string& sourceId, int casterActorId, const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1); float magnitude, float remainingTime = -1, float totalTime = -1);
/// To call after all effect sources have been visited /// To call after all effect sources have been visited
@ -30,7 +32,7 @@ namespace MWMechanics
private: private:
MWWorld::Ptr mActor; MWWorld::Ptr mActor;
std::set<std::pair<int, std::string> > mActiveEffects; std::set<ESM::SummonKey> mActiveEffects;
}; };
} }

View file

@ -917,7 +917,7 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
float magnitude = effect.mMagnMin + (effect.mMagnMax - effect.mMagnMin) * params.mRandom; float magnitude = effect.mMagnMin + (effect.mMagnMax - effect.mMagnMin) * params.mRandom;
magnitude *= params.mMultiplier; magnitude *= params.mMultiplier;
if (magnitude > 0) if (magnitude > 0)
visitor.visit(MWMechanics::EffectKey(effect), (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude); visitor.visit(MWMechanics::EffectKey(effect), i-1, (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude);
} }
} }
} }
@ -931,7 +931,7 @@ void MWWorld::InventoryStore::purgeEffect(short effectId, bool wholeSpell)
} }
} }
void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sourceId, bool wholeSpell) void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sourceId, bool wholeSpell, int effectIndex)
{ {
TEffectMagnitudes::iterator effectMagnitudeIt = mPermanentMagicEffectMagnitudes.find(sourceId); TEffectMagnitudes::iterator effectMagnitudeIt = mPermanentMagicEffectMagnitudes.find(sourceId);
if (effectMagnitudeIt == mPermanentMagicEffectMagnitudes.end()) if (effectMagnitudeIt == mPermanentMagicEffectMagnitudes.end())
@ -964,6 +964,9 @@ void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sou
if (effectIt->mEffectID != effectId) if (effectIt->mEffectID != effectId)
continue; continue;
if (effectIndex >= 0 && effectIndex != i)
continue;
if (wholeSpell) if (wholeSpell)
{ {
mPermanentMagicEffectMagnitudes.erase(sourceId); mPermanentMagicEffectMagnitudes.erase(sourceId);

View file

@ -206,7 +206,7 @@ namespace MWWorld
void purgeEffect (short effectId, bool wholeSpell = false); void purgeEffect (short effectId, bool wholeSpell = false);
///< Remove a magic effect ///< Remove a magic effect
void purgeEffect (short effectId, const std::string& sourceId, bool wholeSpell = false); void purgeEffect (short effectId, const std::string& sourceId, bool wholeSpell = false, int effectIndex=-1);
///< Remove a magic effect ///< Remove a magic effect
virtual void clear(); virtual void clear();

View file

@ -3119,7 +3119,7 @@ namespace MWWorld
{ {
} }
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key, int /*effectIndex*/,
const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/, const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/,
float /*magnitude*/, float /*remainingTime*/ = -1, float /*totalTime*/ = -1) float /*magnitude*/, float /*remainingTime*/ = -1, float /*totalTime*/ = -1)
{ {

View file

@ -24,6 +24,7 @@ namespace ESM
esm.writeHNT ("ARG_", effectIt->mArg); esm.writeHNT ("ARG_", effectIt->mArg);
esm.writeHNT ("MAGN", effectIt->mMagnitude); esm.writeHNT ("MAGN", effectIt->mMagnitude);
esm.writeHNT ("DURA", effectIt->mDuration); esm.writeHNT ("DURA", effectIt->mDuration);
esm.writeHNT ("EIND", effectIt->mEffectIndex);
esm.writeHNT ("LEFT", effectIt->mTimeLeft); esm.writeHNT ("LEFT", effectIt->mTimeLeft);
} }
} }
@ -53,6 +54,8 @@ namespace ESM
esm.getHNOT(effect.mArg, "ARG_"); esm.getHNOT(effect.mArg, "ARG_");
esm.getHNT (effect.mMagnitude, "MAGN"); esm.getHNT (effect.mMagnitude, "MAGN");
esm.getHNT (effect.mDuration, "DURA"); esm.getHNT (effect.mDuration, "DURA");
effect.mEffectIndex = -1;
esm.getHNOT (effect.mEffectIndex, "EIND");
if (format < 9) if (format < 9)
effect.mTimeLeft = effect.mDuration; effect.mTimeLeft = effect.mDuration;
else else

View file

@ -22,6 +22,7 @@ namespace ESM
int mArg; // skill or attribute int mArg; // skill or attribute
float mDuration; float mDuration;
float mTimeLeft; float mTimeLeft;
int mEffectIndex;
}; };
// format 0, saved games only // format 0, saved games only

View file

@ -115,9 +115,11 @@ void ESM::CreatureStats::load (ESMReader &esm)
int magicEffect; int magicEffect;
esm.getHT(magicEffect); esm.getHT(magicEffect);
std::string source = esm.getHNOString("SOUR"); std::string source = esm.getHNOString("SOUR");
int effectIndex = -1;
esm.getHNOT (effectIndex, "EIND");
int actorId; int actorId;
esm.getHNT (actorId, "ACID"); esm.getHNT (actorId, "ACID");
mSummonedCreatureMap[std::make_pair(magicEffect, source)] = actorId; mSummonedCreatureMap[SummonKey(magicEffect, source, effectIndex)] = actorId;
} }
while (esm.isNextSub("GRAV")) while (esm.isNextSub("GRAV"))
@ -212,16 +214,19 @@ void ESM::CreatureStats::save (ESMWriter &esm) const
mAiSequence.save(esm); mAiSequence.save(esm);
mMagicEffects.save(esm); mMagicEffects.save(esm);
for (std::map<std::pair<int, std::string>, int>::const_iterator it = mSummonedCreatureMap.begin(); it != mSummonedCreatureMap.end(); ++it) for (const auto& summon : mSummonedCreatureMap)
{ {
esm.writeHNT ("SUMM", it->first.first); esm.writeHNT ("SUMM", summon.first.mEffectId);
esm.writeHNString ("SOUR", it->first.second); esm.writeHNString ("SOUR", summon.first.mSourceId);
esm.writeHNT ("ACID", it->second); int effectIndex = summon.first.mEffectIndex;
if (effectIndex != -1)
esm.writeHNT ("EIND", effectIndex);
esm.writeHNT ("ACID", summon.second);
} }
for (std::vector<int>::const_iterator it = mSummonGraveyard.begin(); it != mSummonGraveyard.end(); ++it) for (int key : mSummonGraveyard)
{ {
esm.writeHNT ("GRAV", *it); esm.writeHNT ("GRAV", key);
} }
esm.writeHNT("AISE", mHasAiSettings); esm.writeHNT("AISE", mHasAiSettings);
@ -231,11 +236,11 @@ void ESM::CreatureStats::save (ESMWriter &esm) const
mAiSettings[i].save(esm); mAiSettings[i].save(esm);
} }
for (std::map<std::string, CorprusStats>::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it) for (const auto& corprusSpell : mCorprusSpells)
{ {
esm.writeHNString("CORP", it->first); esm.writeHNString("CORP", corprusSpell.first);
const CorprusStats & stats = it->second; const CorprusStats & stats = corprusSpell.second;
esm.writeHNT("WORS", stats.mWorsenings); esm.writeHNT("WORS", stats.mWorsenings);
esm.writeHNT("TIME", stats.mNextWorsening); esm.writeHNT("TIME", stats.mNextWorsening);
} }

View file

@ -39,7 +39,7 @@ namespace ESM
bool mHasAiSettings; bool mHasAiSettings;
StatState<int> mAiSettings[4]; StatState<int> mAiSettings[4];
std::map<std::pair<int, std::string>, int> mSummonedCreatureMap; std::map<SummonKey, int> mSummonedCreatureMap;
std::vector<int> mSummonGraveyard; std::vector<int> mSummonGraveyard;
ESM::TimeStamp mTradeTime; ESM::TimeStamp mTradeTime;

View file

@ -2,6 +2,7 @@
#define COMPONENTS_ESM_MAGICEFFECTS_H #define COMPONENTS_ESM_MAGICEFFECTS_H
#include <map> #include <map>
#include <string>
namespace ESM namespace ESM
{ {
@ -18,6 +19,37 @@ namespace ESM
void save (ESMWriter &esm) const; void save (ESMWriter &esm) const;
}; };
struct SummonKey
{
SummonKey(int effectId, const std::string& sourceId, int index)
{
mEffectId = effectId;
mSourceId = sourceId;
mEffectIndex = index;
}
bool operator==(const SummonKey &other) const
{
return mEffectId == other.mEffectId &&
mSourceId == other.mSourceId &&
mEffectIndex == other.mEffectIndex;
}
bool operator<(const SummonKey &other) const
{
if (mEffectId < other.mEffectId)
return true;
if (mSourceId < other.mSourceId)
return true;
return mEffectIndex < other.mEffectIndex;
}
int mEffectId;
std::string mSourceId;
int mEffectIndex;
};
} }
#endif #endif

View file

@ -4,7 +4,7 @@
#include "esmwriter.hpp" #include "esmwriter.hpp"
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
int ESM::SavedGame::sCurrentFormat = 13; int ESM::SavedGame::sCurrentFormat = 14;
void ESM::SavedGame::load (ESMReader &esm) void ESM::SavedGame::load (ESMReader &esm)
{ {