diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c7935cb77..33f38c1ae 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -182,11 +182,14 @@ set(GAMECLASS_HEADER source_group(apps\\openmw\\mwclass FILES ${GAMECLASS} ${GAMECLASS_HEADER}) set(GAMEMECHANICS - mwmechanics/mechanicsmanager.cpp) + mwmechanics/mechanicsmanager.cpp + mwmechanics/magiceffects.cpp + ) set(GAMEMECHANICS_HEADER mwmechanics/mechanicsmanager.hpp mwmechanics/stat.hpp mwmechanics/creaturestats.hpp + mwmechanics/magiceffects.hpp ) source_group(apps\\openmw\\mwmechanics FILES ${GAMEMECHANICS} ${GAMEMECHANICS_HEADER}) diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 9c6481da9..d2edc031d 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -5,6 +5,7 @@ #include #include "stat.hpp" +#include "magiceffects.hpp" namespace MWMechanics { @@ -14,6 +15,7 @@ namespace MWMechanics DynamicStat mDynamic[3]; // health, magicka, fatigue int mLevel; std::set mAbilities; + MagicEffects mMagicEffects; }; } diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp new file mode 100644 index 000000000..e20d28c35 --- /dev/null +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -0,0 +1,104 @@ + +#include "magiceffects.hpp" + +#include + +#include + +namespace MWMechanics +{ + EffectKey::EffectKey() : mId (0), mArg (-1) {} + + EffectKey::EffectKey (const ESM::ENAMstruct& effect) + { + mId = effect.effectID; + mArg = -1; + + if (effect.skill!=-1) + mArg = effect.skill; + + if (effect.attribute!=-1) + { + if (mArg!=-1) + throw std::runtime_error ( + "magic effect can't have both a skill and an attribute argument"); + + mArg = effect.attribute; + } + } + + bool operator< (const EffectKey& left, const EffectKey& right) + { + if (left.mIdright.mId) + return false; + + return left.mArgsecond += param; + } + } + + MagicEffects MagicEffects::diff (const MagicEffects& prev, const MagicEffects& now) + { + MagicEffects result; + + // adding/changing + for (Collection::const_iterator iter (now.Begin()); iter!=now.End(); ++iter) + { + Collection::const_iterator other = prev.mCollection.find (iter->first); + + if (other==prev.End()) + { + // adding + result.add (iter->first, iter->second); + } + else + { + // changing + result.add (iter->first, iter->second - other->second); + } + } + + // removing + for (Collection::const_iterator iter (prev.Begin()); iter!=prev.End(); ++iter) + { + Collection::const_iterator other = now.mCollection.find (iter->first); + + if (other==prev.End()) + { + result.add (iter->first, EffectParam() - iter->second); + } + } + + return result; + + } +} diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp new file mode 100644 index 000000000..4ed3df00b --- /dev/null +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -0,0 +1,72 @@ +#ifndef GAME_MWMECHANICS_MAGICEFFECTS_H +#define GAME_MWMECHANICS_MAGICEFFECTS_H + +#include + +namespace ESM +{ + struct ENAMstruct; +} + +namespace MWMechanics +{ + struct EffectKey + { + int mId; + int mArg; // skill or ability + + EffectKey(); + + EffectKey (const ESM::ENAMstruct& effect); + }; + + bool operator< (const EffectKey& left, const EffectKey& right); + + struct EffectParam + { + int mMagnitude; + + EffectParam(); + + EffectParam& operator+= (const EffectParam& param); + + EffectParam& operator-= (const EffectParam& param); + }; + + inline EffectParam operator+ (const EffectParam& left, const EffectParam& right) + { + EffectParam param (left); + return param += right; + } + + inline EffectParam operator- (const EffectParam& left, const EffectParam& right) + { + EffectParam param (left); + return param -= right; + } + + /// \brief Effects currently affecting a NPC or creature + class MagicEffects + { + public: + + typedef std::map Collection; + + private: + + Collection mCollection; + + public: + + Collection::const_iterator Begin() const { return mCollection.begin(); } + + Collection::const_iterator End() const { return mCollection.end(); } + + void add (const EffectKey& key, const EffectParam& param); + + static MagicEffects diff (const MagicEffects& prev, const MagicEffects& now); + ///< Return changes from \a prev to \a now. + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index 34fffa13e..8d23211fa 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -23,6 +23,7 @@ namespace MWMechanics // reset creatureStats.mLevel = player->npdt52.level; creatureStats.mAbilities.clear(); + creatureStats.mMagicEffects = MagicEffects(); for (int i=0; i<27; ++i) npcStats.mSkill[i].setBase (player->npdt52.skills[i]); @@ -136,6 +137,9 @@ namespace MWMechanics } } + // magic effects + adjustMagicEffects (ptr); + // calculate dynamic stats int strength = creatureStats.mAttributes[0].getBase(); int intelligence = creatureStats.mAttributes[1].getBase(); @@ -166,7 +170,6 @@ namespace MWMechanics if (creatureStats.mAbilities.find (id)==creatureStats.mAbilities.end()) { creatureStats.mAbilities.insert (id); - // TODO apply effects } break; @@ -181,6 +184,39 @@ namespace MWMechanics } } + void MechanicsManager::adjustMagicEffects (MWWorld::Ptr& creature) + { + MWMechanics::CreatureStats& creatureStats = + MWWorld::Class::get (creature).getCreatureStats (creature); + + MagicEffects now; + + for (std::set::const_iterator iter (creatureStats.mAbilities.begin()); + iter!=creatureStats.mAbilities.end(); ++iter) + { + const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (*iter); + + for (std::vector::const_iterator iter = spell->effects.list.begin(); + iter!=spell->effects.list.end(); ++iter) + { + if (iter->range==0) // self + { + EffectParam param; + param.mMagnitude = iter->magnMax; // TODO calculate magnitude + now.add (EffectKey (*iter), param); + } + } + } + + // TODO add effects from other spell types, active spells and equipment + + MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now); + + creatureStats.mMagicEffects = now; + + // TODO apply diff to other stats + } + MechanicsManager::MechanicsManager (MWWorld::Environment& environment) : mEnvironment (environment), mUpdatePlayer (true), mClassSelected (false), mRaceSelected (false) diff --git a/apps/openmw/mwmechanics/mechanicsmanager.hpp b/apps/openmw/mwmechanics/mechanicsmanager.hpp index 2d85c2ac2..26d3621ab 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.hpp @@ -32,6 +32,8 @@ namespace MWMechanics void insertSpell (const std::string& id, MWWorld::Ptr& creature); + void adjustMagicEffects (MWWorld::Ptr& creature); + public: MechanicsManager (MWWorld::Environment& environment);