Issue #256: added active spell management (completely untested)

actorid
Marc Zinnschlag 13 years ago
parent 635a89c35c
commit 9f1919a230

@ -58,6 +58,7 @@ add_openmw_dir (mwclass
add_openmw_dir (mwmechanics
mechanicsmanager stat creaturestats magiceffects movement actors drawstate spells
activespells
)
add_openmw_dir (mwbase

@ -0,0 +1,162 @@
#include "activespells.hpp"
#include <cstdlib>
#include "../mwbase/environment.hpp"
#include "../mwworld/world.hpp"
namespace MWMechanics
{
void ActiveSpells::update() const
{
bool rebuild = false;
MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp();
if (mLastUpdate!=now)
{
TContainer::iterator iter (mSpells.begin());
while (iter!=mSpells.end())
if (!timeToExpire (iter))
{
mSpells.erase (iter++);
rebuild = true;
}
else
++iter;
mLastUpdate = now;
}
if (mSpellsChanged)
{
mSpellsChanged = false;
rebuild = true;
}
if (rebuild)
{
mEffects = MagicEffects();
for (TIterator iter (begin()); iter!=end(); ++iter)
{
const ESM::Spell& spell =
*MWBase::Environment::get().getWorld()->getStore().spells.find (iter->first);
const MWWorld::TimeStamp& start = iter->second.first;
float magnitude = iter->second.second;
for (std::vector<ESM::ENAMstruct>::const_iterator iter (spell.effects.list.begin());
iter!=spell.effects.list.end(); ++iter)
{
if (iter->duration)
{
MWWorld::TimeStamp end = start;
end += static_cast<double> (iter->duration)*
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
if (end>now)
{
EffectParam param;
param.mMagnitude = static_cast<int> (
(iter->magnMax-iter->magnMin+1)*magnitude + iter->magnMin);
mEffects.add (*iter, param);
}
}
}
}
}
}
ActiveSpells::ActiveSpells()
: mSpellsChanged (false), mLastUpdate (MWBase::Environment::get().getWorld()->getTimeStamp())
{}
void ActiveSpells::addSpell (const std::string& id)
{
const ESM::Spell& spell = *MWBase::Environment::get().getWorld()->getStore().spells.find (id);
bool found = false;
for (std::vector<ESM::ENAMstruct>::const_iterator iter (spell.effects.list.begin());
iter!=spell.effects.list.end(); ++iter)
{
if (iter->duration)
{
found = true;
break;
}
}
if (!found)
return;
TContainer::iterator iter = mSpells.find (id);
float random = static_cast<float> (std::rand()) / RAND_MAX;
if (iter==mSpells.end())
mSpells.insert (std::make_pair (id,
std::make_pair (MWBase::Environment::get().getWorld()->getTimeStamp(), random)));
else
iter->second = std::make_pair (MWBase::Environment::get().getWorld()->getTimeStamp(), random);
mSpellsChanged = true;
}
void ActiveSpells::removeSpell (const std::string& id)
{
TContainer::iterator iter = mSpells.find (id);
if (iter!=mSpells.end())
{
mSpells.erase (iter);
mSpellsChanged = true;
}
}
const MagicEffects& ActiveSpells::getMagicEffects() const
{
update();
return mEffects;
}
ActiveSpells::TIterator ActiveSpells::begin() const
{
update();
return mSpells.begin();
}
ActiveSpells::TIterator ActiveSpells::end() const
{
update();
return mSpells.end();
}
double ActiveSpells::timeToExpire (const TIterator& iterator) const
{
const ESM::Spell& spell =
*MWBase::Environment::get().getWorld()->getStore().spells.find (iterator->first);
int duration = 0;
for (std::vector<ESM::ENAMstruct>::const_iterator iter (spell.effects.list.begin());
iter!=spell.effects.list.end(); ++iter)
{
if (iter->duration>duration)
duration = iter->duration;
}
double scaledDuration = duration *
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
double usedUp = MWBase::Environment::get().getWorld()->getTimeStamp()-iterator->second.first;
if (usedUp>=scaledDuration)
return 0;
return scaledDuration-usedUp;
}
}

@ -0,0 +1,58 @@
#ifndef GAME_MWMECHANICS_ACTIVESPELLS_H
#define GAME_MWMECHANICS_ACTIVESPELLS_H
#include <map>
#include <vector>
#include <string>
#include "../mwworld/timestamp.hpp"
#include "magiceffects.hpp"
namespace ESM
{
struct Spell;
}
namespace MWMechanics
{
/// \brief Lasting spell effects
class ActiveSpells
{
public:
typedef std::map<std::string, std::pair<MWWorld::TimeStamp, float> > TContainer;
typedef TContainer::const_iterator TIterator;
private:
mutable TContainer mSpells; // spellId, (time of casting, relative magnitude)
mutable MagicEffects mEffects;
mutable bool mSpellsChanged;
mutable MWWorld::TimeStamp mLastUpdate;
void update() const;
public:
ActiveSpells();
void addSpell (const std::string& id);
///< Overwrites an existing spell with the same ID. If the spell does not have any
/// non-instant effects, it is ignored.
void removeSpell (const std::string& id);
const MagicEffects& getMagicEffects() const;
TIterator begin() const;
TIterator end() const;
double timeToExpire (const TIterator& iterator) const;
///< Returns time (in in-game hours) until the spell pointed to by \a iterator
/// expires.
};
}
#endif

@ -53,7 +53,7 @@ namespace MWMechanics
now += store.getMagicEffects();
}
/// \todo add effects from active spells
now += creatureStats.mActiveSpells.getMagicEffects();
MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now);

@ -7,6 +7,7 @@
#include "stat.hpp"
#include "magiceffects.hpp"
#include "spells.hpp"
#include "activespells.hpp"
namespace MWMechanics
{
@ -16,6 +17,7 @@ namespace MWMechanics
DynamicStat<int> mDynamic[3]; // health, magicka, fatigue
int mLevel;
Spells mSpells;
ActiveSpells mActiveSpells;
MagicEffects mMagicEffects;
};
}

Loading…
Cancel
Save