Allow separate summoned creature instances for each spell ID (Fixes #2194)

openmw-35
scrawl 10 years ago
parent 464f8abb3f
commit f267497c03

@ -76,7 +76,7 @@ add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
)
add_openmw_dir (mwstate

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

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

@ -195,7 +195,7 @@ namespace MWMechanics
float magnitude = effectIt->mMagnitude;
if (magnitude)
visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration);
visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration);
}
}
}
@ -229,6 +229,22 @@ namespace MWMechanics
mSpellsChanged = true;
}
void ActiveSpells::purgeEffect(short effectId, const std::string& sourceId)
{
for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it)
{
for (std::vector<ActiveEffect>::iterator effectIt = it->second.mEffects.begin();
effectIt != it->second.mEffects.end();)
{
if (effectIt->mEffectId == effectId && it->first == sourceId)
effectIt = it->second.mEffects.erase(effectIt);
else
++effectIt;
}
}
mSpellsChanged = true;
}
void ActiveSpells::purge(int casterActorId)
{
for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it)

@ -82,6 +82,9 @@ namespace MWMechanics
/// Remove all active effects with this effect id
void purgeEffect (short effectId);
/// Remove all active effects with this effect id and source id
void purgeEffect (short effectId, const std::string& sourceId);
/// Remove all active effects, if roll succeeds (for each effect)
void purgeAll (float chance);

@ -36,6 +36,7 @@
#include "aipursue.hpp"
#include "actor.hpp"
#include "summoning.hpp"
namespace
{
@ -105,7 +106,7 @@ public:
, mCommanded(false){}
virtual void visit (MWMechanics::EffectKey key,
const std::string& sourceName, int casterActorId,
const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
@ -165,30 +166,6 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
}
}
void cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId)
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(creatureActorId);
if (!ptr.isEmpty())
{
// TODO: Show death animation before deleting? We shouldn't allow looting the corpse while the animation
// plays though, which is a rather lame exploit in vanilla.
MWBase::Environment::get().getWorld()->deleteObject(ptr);
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_End");
if (fx)
MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel,
"", Ogre::Vector3(ptr.getRefData().getPosition().pos));
}
else
{
// We didn't find the creature. It's probably in an inactive cell.
// Add to graveyard so we can delete it when the cell becomes active.
std::vector<int>& graveyard = casterStats.getSummonedCreatureGraveyard();
graveyard.push_back(creatureActorId);
}
}
}
namespace MWMechanics
@ -203,7 +180,7 @@ namespace MWMechanics
: mCreature(trappedCreature) {}
virtual void visit (MWMechanics::EffectKey key,
const std::string& sourceName, int casterActorId,
const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1)
{
if (key.mId != ESM::MagicEffect::Soultrap)
@ -782,131 +759,11 @@ namespace MWMechanics
}
}
// Update summon effects
static std::map<int, std::string> summonMap;
if (summonMap.empty())
{
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID";
summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID";
summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID";
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID";
summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID";
summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID";
summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID";
summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID";
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID";
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID";
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID";
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID";
summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID";
summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID";
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID";
summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID";
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID";
summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID";
summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID";
summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID";
summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID";
summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID";
}
std::map<int, int>& creatureMap = creatureStats.getSummonedCreatureMap();
for (std::map<int, std::string>::iterator it = summonMap.begin(); it != summonMap.end(); ++it)
{
bool found = creatureMap.find(it->first) != creatureMap.end();
int magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude();
if (found != (magnitude > 0))
{
if (magnitude > 0)
{
ESM::Position ipos = ptr.getRefData().getPosition();
Ogre::Vector3 pos(ipos.pos);
Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z);
const float distance = 50;
pos = pos + distance*rot.yAxis();
ipos.pos[0] = pos.x;
ipos.pos[1] = pos.y;
ipos.pos[2] = pos.z;
ipos.rot[0] = 0;
ipos.rot[1] = 0;
ipos.rot[2] = 0;
std::string creatureID =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->getString();
if (!creatureID.empty())
{
MWWorld::CellStore* store = ptr.getCell();
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1);
ref.getPtr().getCellRef().setPosition(ipos);
MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr());
// Make the summoned creature follow its master and help in fights
AiFollow package(ptr.getCellRef().getRefId());
summonedCreatureStats.getAiSequence().stack(package, ref.getPtr());
int creatureActorId = summonedCreatureStats.getActorId();
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos);
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed);
if (anim)
{
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_Start");
if (fx)
anim->addEffect("meshes\\" + fx->mModel, -1, false);
}
creatureMap.insert(std::make_pair(it->first, creatureActorId));
}
}
else
{
// Effect has ended
std::map<int, int>::iterator foundCreature = creatureMap.find(it->first);
cleanupSummonedCreature(creatureStats, foundCreature->second);
creatureMap.erase(foundCreature);
}
}
}
for (std::map<int, int>::iterator it = creatureMap.begin(); it != creatureMap.end(); )
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second);
if (!ptr.isEmpty() && ptr.getClass().getCreatureStats(ptr).isDead())
{
// Purge the magic effect so a new creature can be summoned if desired
creatureStats.getActiveSpells().purgeEffect(it->first);
if (ptr.getClass().hasInventoryStore(ptr))
ptr.getClass().getInventoryStore(ptr).purgeEffect(it->first);
cleanupSummonedCreature(creatureStats, it->second);
creatureMap.erase(it++);
}
else
++it;
}
std::vector<int>& graveyard = creatureStats.getSummonedCreatureGraveyard();
for (std::vector<int>::iterator it = graveyard.begin(); it != graveyard.end(); )
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(*it);
if (!ptr.isEmpty())
{
it = graveyard.erase(it);
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_End");
if (fx)
MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel,
"", Ogre::Vector3(ptr.getRefData().getPosition().pos));
MWBase::Environment::get().getWorld()->deleteObject(ptr);
}
else
++it;
}
UpdateSummonedCreatures updateSummonedCreatures(ptr);
creatureStats.getActiveSpells().visitEffectSources(updateSummonedCreatures);
if (ptr.getClass().hasInventoryStore(ptr))
ptr.getClass().getInventoryStore(ptr).visitEffectSources(updateSummonedCreatures);
updateSummonedCreatures.finish();
}
void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr, float duration)

@ -638,7 +638,7 @@ namespace MWMechanics
mDeathAnimation = index;
}
std::map<int, int>& CreatureStats::getSummonedCreatureMap()
std::map<CreatureStats::SummonKey, int>& CreatureStats::getSummonedCreatureMap()
{
return mSummonedCreatures;
}

@ -67,8 +67,11 @@ namespace MWMechanics
// The index of the death animation that was played
unsigned char mDeathAnimation;
// <ESM::MagicEffect index, ActorId>
std::map<int, int> mSummonedCreatures;
public:
typedef std::pair<int, std::string> SummonKey; // <ESM::MagicEffect index, spell ID>
private:
std::map<SummonKey, int> mSummonedCreatures; // <SummonKey, ActorId>
// 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.
std::vector<int> mSummonGraveyard;
@ -216,8 +219,8 @@ namespace MWMechanics
void setBlock(bool value);
bool getBlock() const;
std::map<int, int>& getSummonedCreatureMap();
std::vector<int>& getSummonedCreatureGraveyard();
std::map<SummonKey, int>& getSummonedCreatureMap(); // <SummonKey, ActorId of summoned creature>
std::vector<int>& getSummonedCreatureGraveyard(); // ActorIds
enum Flag
{

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

@ -21,6 +21,7 @@
#include "magiceffects.hpp"
#include "npcstats.hpp"
#include "summoning.hpp"
namespace
{

@ -249,7 +249,7 @@ namespace MWMechanics
random = it->second.at(i);
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, -1, magnitude);
visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, spell->mId, -1, magnitude);
}
}
}

@ -0,0 +1,195 @@
#include "summoning.hpp"
#include <OgreVector3.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/manualref.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwrender/animation.hpp"
#include "creaturestats.hpp"
#include "aifollow.hpp"
namespace MWMechanics
{
void cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId)
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(creatureActorId);
if (!ptr.isEmpty())
{
// TODO: Show death animation before deleting? We shouldn't allow looting the corpse while the animation
// plays though, which is a rather lame exploit in vanilla.
MWBase::Environment::get().getWorld()->deleteObject(ptr);
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_End");
if (fx)
MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel,
"", Ogre::Vector3(ptr.getRefData().getPosition().pos));
}
else
{
// We didn't find the creature. It's probably in an inactive cell.
// Add to graveyard so we can delete it when the cell becomes active.
std::vector<int>& graveyard = casterStats.getSummonedCreatureGraveyard();
graveyard.push_back(creatureActorId);
}
}
UpdateSummonedCreatures::UpdateSummonedCreatures(const MWWorld::Ptr &actor)
: mActor(actor)
{
}
void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime)
{
if (key.mId >= ESM::MagicEffect::SummonScamp
&& key.mId <= ESM::MagicEffect::SummonStormAtronach && magnitude > 0)
{
mActiveEffects.insert(std::make_pair(key.mId, sourceId));
}
}
void UpdateSummonedCreatures::finish()
{
static std::map<int, std::string> summonMap;
if (summonMap.empty())
{
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID";
summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID";
summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID";
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID";
summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID";
summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID";
summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID";
summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID";
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID";
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID";
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID";
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID";
summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID";
summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID";
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID";
summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID";
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID";
summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID";
summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID";
summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID";
summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID";
summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID";
}
MWMechanics::CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor);
// Update summon effects
std::map<CreatureStats::SummonKey, int>& creatureMap = creatureStats.getSummonedCreatureMap();
for (std::map<CreatureStats::SummonKey, int>::iterator it = creatureMap.begin(); it != creatureMap.end(); )
{
bool found = mActiveEffects.find(it->first) != mActiveEffects.end();
if (!found)
{
// Effect has ended
cleanupSummonedCreature(creatureStats, it->second);
creatureMap.erase(it++);
continue;
}
++it;
}
for (std::set<std::pair<int, std::string> >::iterator it = mActiveEffects.begin(); it != mActiveEffects.end(); ++it)
{
bool found = creatureMap.find(std::make_pair(it->first, it->second)) != creatureMap.end();
if (!found)
{
ESM::Position ipos = mActor.getRefData().getPosition();
Ogre::Vector3 pos(ipos.pos);
Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z);
const float distance = 50;
pos = pos + distance*rot.yAxis();
ipos.pos[0] = pos.x;
ipos.pos[1] = pos.y;
ipos.pos[2] = pos.z;
ipos.rot[0] = 0;
ipos.rot[1] = 0;
ipos.rot[2] = 0;
const std::string& creatureGmst = summonMap[it->first];
std::string creatureID =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(creatureGmst)->getString();
if (!creatureID.empty())
{
MWWorld::CellStore* store = mActor.getCell();
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1);
ref.getPtr().getCellRef().setPosition(ipos);
MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr());
// Make the summoned creature follow its master and help in fights
AiFollow package(mActor.getCellRef().getRefId());
summonedCreatureStats.getAiSequence().stack(package, ref.getPtr());
int creatureActorId = summonedCreatureStats.getActorId();
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos);
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed);
if (anim)
{
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_Start");
if (fx)
anim->addEffect("meshes\\" + fx->mModel, -1, false);
}
creatureMap.insert(std::make_pair(*it, creatureActorId));
}
}
}
for (std::map<CreatureStats::SummonKey, int>::iterator it = creatureMap.begin(); it != creatureMap.end(); )
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second);
if (!ptr.isEmpty() && ptr.getClass().getCreatureStats(ptr).isDead())
{
// Purge the magic effect so a new creature can be summoned if desired
creatureStats.getActiveSpells().purgeEffect(it->first.first, it->first.second);
if (mActor.getClass().hasInventoryStore(ptr))
mActor.getClass().getInventoryStore(mActor).purgeEffect(it->first.first, it->first.second);
cleanupSummonedCreature(creatureStats, it->second);
creatureMap.erase(it++);
}
else
++it;
}
std::vector<int>& graveyard = creatureStats.getSummonedCreatureGraveyard();
for (std::vector<int>::iterator it = graveyard.begin(); it != graveyard.end(); )
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(*it);
if (!ptr.isEmpty())
{
it = graveyard.erase(it);
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_End");
if (fx)
MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel,
"", Ogre::Vector3(ptr.getRefData().getPosition().pos));
MWBase::Environment::get().getWorld()->deleteObject(ptr);
}
else
++it;
}
}
}

@ -0,0 +1,35 @@
#ifndef OPENMW_MECHANICS_SUMMONING_H
#define OPENMW_MECHANICS_SUMMONING_H
#include <set>
#include "magiceffects.hpp"
#include "../mwworld/ptr.hpp"
namespace MWMechanics
{
class CreatureStats;
struct UpdateSummonedCreatures : public EffectSourceVisitor
{
UpdateSummonedCreatures(const MWWorld::Ptr& actor);
virtual void visit (MWMechanics::EffectKey key,
const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1);
/// To call after all effect sources have been visited
void finish();
private:
MWWorld::Ptr mActor;
std::set<std::pair<int, std::string> > mActiveEffects;
};
void cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId);
}
#endif

@ -583,7 +583,8 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i];
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
magnitude *= params.mMultiplier;
visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), -1, magnitude);
if (magnitude > 0)
visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude);
++i;
}
@ -639,6 +640,52 @@ void MWWorld::InventoryStore::purgeEffect(short effectId)
mMagicEffects.remove(MWMechanics::EffectKey(effectId));
}
void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sourceId)
{
TEffectMagnitudes::iterator effectMagnitudeIt = mPermanentMagicEffectMagnitudes.find(sourceId);
if (effectMagnitudeIt == mPermanentMagicEffectMagnitudes.end())
return;
for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter)
{
if (*iter==end())
continue;
if ((*iter)->getClass().getId(**iter) != sourceId)
continue;
std::string enchantmentId = (*iter)->getClass().getEnchantment (**iter);
if (!enchantmentId.empty())
{
const ESM::Enchantment& enchantment =
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find (enchantmentId);
if (enchantment.mData.mType != ESM::Enchantment::ConstantEffect)
continue;
std::vector<EffectParams>& params = effectMagnitudeIt->second;
int i=0;
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
effectIt!=enchantment.mEffects.mList.end(); ++effectIt, ++i)
{
if (effectIt->mEffectID != effectId)
continue;
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom;
magnitude *= params[i].mMultiplier;
if (magnitude)
mMagicEffects.add (*effectIt, -magnitude);
params[i].mMultiplier = 0;
break;
}
}
}
}
void MWWorld::InventoryStore::clear()
{
mSlots.clear();

@ -203,6 +203,9 @@ namespace MWWorld
void purgeEffect (short effectId);
///< Remove a magic effect
void purgeEffect (short effectId, const std::string& sourceId);
///< Remove a magic effect
virtual void clear();
///< Empty container.

@ -94,9 +94,10 @@ void ESM::CreatureStats::load (ESMReader &esm)
{
int magicEffect;
esm.getHT(magicEffect);
std::string source = esm.getHNOString("SOUR");
int actorId;
esm.getHNT (actorId, "ACID");
mSummonedCreatureMap[magicEffect] = actorId;
mSummonedCreatureMap[std::make_pair(magicEffect, source)] = actorId;
}
while (esm.isNextSub("GRAV"))
@ -204,9 +205,10 @@ void ESM::CreatureStats::save (ESMWriter &esm) const
mAiSequence.save(esm);
mMagicEffects.save(esm);
for (std::map<int, int>::const_iterator it = mSummonedCreatureMap.begin(); it != mSummonedCreatureMap.end(); ++it)
for (std::map<std::pair<int, std::string>, int>::const_iterator it = mSummonedCreatureMap.begin(); it != mSummonedCreatureMap.end(); ++it)
{
esm.writeHNT ("SUMM", it->first);
esm.writeHNT ("SUMM", it->first.first);
esm.writeHNString ("SOUR", it->first.second);
esm.writeHNT ("ACID", it->second);
}

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

Loading…
Cancel
Save