From 9f1919a230e5d6dbb0a2cf2491569169cf2bed25 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 19 May 2012 15:01:07 +0200 Subject: [PATCH] Issue #256: added active spell management (completely untested) --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwmechanics/activespells.cpp | 162 ++++++++++++++++++++++ apps/openmw/mwmechanics/activespells.hpp | 58 ++++++++ apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/creaturestats.hpp | 2 + 5 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwmechanics/activespells.cpp create mode 100644 apps/openmw/mwmechanics/activespells.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 7e5dcc1e2..ca2355346 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -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 diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp new file mode 100644 index 000000000..ced2a5c3f --- /dev/null +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -0,0 +1,162 @@ + +#include "activespells.hpp" + +#include + +#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::const_iterator iter (spell.effects.list.begin()); + iter!=spell.effects.list.end(); ++iter) + { + if (iter->duration) + { + MWWorld::TimeStamp end = start; + end += static_cast (iter->duration)* + MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); + + if (end>now) + { + EffectParam param; + param.mMagnitude = static_cast ( + (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::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 (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::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; + } +} diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp new file mode 100644 index 000000000..179321c58 --- /dev/null +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -0,0 +1,58 @@ +#ifndef GAME_MWMECHANICS_ACTIVESPELLS_H +#define GAME_MWMECHANICS_ACTIVESPELLS_H + +#include +#include +#include + +#include "../mwworld/timestamp.hpp" + +#include "magiceffects.hpp" + +namespace ESM +{ + struct Spell; +} + +namespace MWMechanics +{ + /// \brief Lasting spell effects + class ActiveSpells + { + public: + + typedef std::map > 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 diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cd2dbaddf..5a17d50e4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -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); diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index ab008da9e..cc3c409da 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -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 mDynamic[3]; // health, magicka, fatigue int mLevel; Spells mSpells; + ActiveSpells mActiveSpells; MagicEffects mMagicEffects; }; }