mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-01 00:15:32 +00:00
Merge branch 'effects'
This commit is contained in:
commit
420cd53be0
18 changed files with 548 additions and 51 deletions
|
@ -48,6 +48,7 @@ add_openmw_dir (mwworld
|
||||||
refdata world physicssystem scene globals class action nullaction actionteleport
|
refdata world physicssystem scene globals class action nullaction actionteleport
|
||||||
containerstore actiontalk actiontake manualref player cellfunctors
|
containerstore actiontalk actiontake manualref player cellfunctors
|
||||||
cells localscripts customdata weather inventorystore ptr actionread
|
cells localscripts customdata weather inventorystore ptr actionread
|
||||||
|
timestamp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwclass
|
add_openmw_dir (mwclass
|
||||||
|
@ -57,6 +58,7 @@ add_openmw_dir (mwclass
|
||||||
|
|
||||||
add_openmw_dir (mwmechanics
|
add_openmw_dir (mwmechanics
|
||||||
mechanicsmanager stat creaturestats magiceffects movement actors drawstate spells
|
mechanicsmanager stat creaturestats magiceffects movement actors drawstate spells
|
||||||
|
activespells
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwbase
|
add_openmw_dir (mwbase
|
||||||
|
|
162
apps/openmw/mwmechanics/activespells.cpp
Normal file
162
apps/openmw/mwmechanics/activespells.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
58
apps/openmw/mwmechanics/activespells.hpp
Normal file
58
apps/openmw/mwmechanics/activespells.hpp
Normal file
|
@ -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
|
|
@ -8,11 +8,30 @@
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
|
#include "creaturestats.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
|
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
|
||||||
{
|
{
|
||||||
|
// magic effects
|
||||||
|
adjustMagicEffects (ptr);
|
||||||
|
|
||||||
|
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
|
||||||
|
|
||||||
|
// calculate dynamic stats
|
||||||
|
int strength = creatureStats.mAttributes[0].getBase();
|
||||||
|
int intelligence = creatureStats.mAttributes[1].getBase();
|
||||||
|
int willpower = creatureStats.mAttributes[2].getBase();
|
||||||
|
int agility = creatureStats.mAttributes[3].getBase();
|
||||||
|
int endurance = creatureStats.mAttributes[5].getBase();
|
||||||
|
|
||||||
|
double magickaFactor = creatureStats.mMagicEffects.get (EffectKey (84)).mMagnitude*0.1 + 0.5;
|
||||||
|
|
||||||
|
creatureStats.mDynamic[0].setBase (static_cast<int> (0.5 * (strength + endurance)));
|
||||||
|
creatureStats.mDynamic[1].setBase (static_cast<int> (intelligence +
|
||||||
|
magickaFactor * intelligence));
|
||||||
|
creatureStats.mDynamic[2].setBase (strength+willpower+agility+endurance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused)
|
void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused)
|
||||||
|
@ -22,6 +41,27 @@ namespace MWMechanics
|
||||||
MWWorld::Class::get (ptr).getNpcStats (ptr));
|
MWWorld::Class::get (ptr).getNpcStats (ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Actors::adjustMagicEffects (const MWWorld::Ptr& creature)
|
||||||
|
{
|
||||||
|
CreatureStats& creatureStats = MWWorld::Class::get (creature).getCreatureStats (creature);
|
||||||
|
|
||||||
|
MagicEffects now = creatureStats.mSpells.getMagicEffects();
|
||||||
|
|
||||||
|
if (creature.getTypeName()==typeid (ESM::NPC).name())
|
||||||
|
{
|
||||||
|
MWWorld::InventoryStore& store = MWWorld::Class::get (creature).getInventoryStore (creature);
|
||||||
|
now += store.getMagicEffects();
|
||||||
|
}
|
||||||
|
|
||||||
|
now += creatureStats.mActiveSpells.getMagicEffects();
|
||||||
|
|
||||||
|
MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now);
|
||||||
|
|
||||||
|
creatureStats.mMagicEffects = now;
|
||||||
|
|
||||||
|
// TODO apply diff to other stats
|
||||||
|
}
|
||||||
|
|
||||||
Actors::Actors() : mDuration (0) {}
|
Actors::Actors() : mDuration (0) {}
|
||||||
|
|
||||||
void Actors::addActor (const MWWorld::Ptr& ptr)
|
void Actors::addActor (const MWWorld::Ptr& ptr)
|
||||||
|
|
|
@ -19,10 +19,10 @@ namespace MWMechanics
|
||||||
std::set<MWWorld::Ptr> mActors;
|
std::set<MWWorld::Ptr> mActors;
|
||||||
float mDuration;
|
float mDuration;
|
||||||
|
|
||||||
void updateActor (const MWWorld::Ptr& ptr, float duration);
|
|
||||||
|
|
||||||
void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused);
|
void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused);
|
||||||
|
|
||||||
|
void adjustMagicEffects (const MWWorld::Ptr& creature);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Actors();
|
Actors();
|
||||||
|
@ -39,6 +39,11 @@ namespace MWMechanics
|
||||||
void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement,
|
void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement,
|
||||||
float duration, bool paused);
|
float duration, bool paused);
|
||||||
///< Update actor stats and store desired velocity vectors in \a movement
|
///< Update actor stats and store desired velocity vectors in \a movement
|
||||||
|
|
||||||
|
void updateActor (const MWWorld::Ptr& ptr, float duration);
|
||||||
|
///< This function is normally called automatically during the update process, but it can
|
||||||
|
/// also be called explicitly at any time to force an update.
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "stat.hpp"
|
#include "stat.hpp"
|
||||||
#include "magiceffects.hpp"
|
#include "magiceffects.hpp"
|
||||||
#include "spells.hpp"
|
#include "spells.hpp"
|
||||||
|
#include "activespells.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -16,6 +17,7 @@ namespace MWMechanics
|
||||||
DynamicStat<int> mDynamic[3]; // health, magicka, fatigue
|
DynamicStat<int> mDynamic[3]; // health, magicka, fatigue
|
||||||
int mLevel;
|
int mLevel;
|
||||||
Spells mSpells;
|
Spells mSpells;
|
||||||
|
ActiveSpells mActiveSpells;
|
||||||
MagicEffects mMagicEffects;
|
MagicEffects mMagicEffects;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
#include "magiceffects.hpp"
|
#include "magiceffects.hpp"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <components/esm/defs.hpp>
|
#include <components/esm/defs.hpp>
|
||||||
|
@ -66,6 +68,46 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MagicEffects::add (const ESM::EffectList& list)
|
||||||
|
{
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter (list.list.begin()); iter!=list.list.end();
|
||||||
|
++iter)
|
||||||
|
{
|
||||||
|
EffectParam param;
|
||||||
|
|
||||||
|
if (iter->magnMin>=iter->magnMax)
|
||||||
|
param.mMagnitude = iter->magnMin;
|
||||||
|
else
|
||||||
|
param.mMagnitude = static_cast<int> (
|
||||||
|
(iter->magnMax-iter->magnMin+1)*
|
||||||
|
(static_cast<float> (std::rand()) / RAND_MAX) + iter->magnMin);
|
||||||
|
|
||||||
|
add (*iter, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MagicEffects& MagicEffects::operator+= (const MagicEffects& effects)
|
||||||
|
{
|
||||||
|
if (this==&effects)
|
||||||
|
{
|
||||||
|
MagicEffects temp (effects);
|
||||||
|
*this += temp;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Collection::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter)
|
||||||
|
{
|
||||||
|
Collection::iterator result = mCollection.find (iter->first);
|
||||||
|
|
||||||
|
if (result!=mCollection.end())
|
||||||
|
result->second += iter->second;
|
||||||
|
else
|
||||||
|
mCollection.insert (*iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
EffectParam MagicEffects::get (const EffectKey& key) const
|
EffectParam MagicEffects::get (const EffectKey& key) const
|
||||||
{
|
{
|
||||||
Collection::const_iterator iter = mCollection.find (key);
|
Collection::const_iterator iter = mCollection.find (key);
|
||||||
|
@ -85,11 +127,11 @@ namespace MWMechanics
|
||||||
MagicEffects result;
|
MagicEffects result;
|
||||||
|
|
||||||
// adding/changing
|
// adding/changing
|
||||||
for (Collection::const_iterator iter (now.Begin()); iter!=now.End(); ++iter)
|
for (Collection::const_iterator iter (now.begin()); iter!=now.end(); ++iter)
|
||||||
{
|
{
|
||||||
Collection::const_iterator other = prev.mCollection.find (iter->first);
|
Collection::const_iterator other = prev.mCollection.find (iter->first);
|
||||||
|
|
||||||
if (other==prev.End())
|
if (other==prev.end())
|
||||||
{
|
{
|
||||||
// adding
|
// adding
|
||||||
result.add (iter->first, iter->second);
|
result.add (iter->first, iter->second);
|
||||||
|
@ -102,17 +144,16 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
// removing
|
// removing
|
||||||
for (Collection::const_iterator iter (prev.Begin()); iter!=prev.End(); ++iter)
|
for (Collection::const_iterator iter (prev.begin()); iter!=prev.end(); ++iter)
|
||||||
{
|
{
|
||||||
Collection::const_iterator other = now.mCollection.find (iter->first);
|
Collection::const_iterator other = now.mCollection.find (iter->first);
|
||||||
|
|
||||||
if (other==prev.End())
|
if (other==prev.end())
|
||||||
{
|
{
|
||||||
result.add (iter->first, EffectParam() - iter->second);
|
result.add (iter->first, EffectParam() - iter->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct ENAMstruct;
|
struct ENAMstruct;
|
||||||
|
struct EffectList;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
|
@ -60,12 +61,16 @@ namespace MWMechanics
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Collection::const_iterator Begin() const { return mCollection.begin(); }
|
Collection::const_iterator begin() const { return mCollection.begin(); }
|
||||||
|
|
||||||
Collection::const_iterator End() const { return mCollection.end(); }
|
Collection::const_iterator end() const { return mCollection.end(); }
|
||||||
|
|
||||||
void add (const EffectKey& key, const EffectParam& param);
|
void add (const EffectKey& key, const EffectParam& param);
|
||||||
|
|
||||||
|
void add (const ESM::EffectList& list);
|
||||||
|
|
||||||
|
MagicEffects& operator+= (const MagicEffects& effects);
|
||||||
|
|
||||||
EffectParam get (const EffectKey& key) const;
|
EffectParam get (const EffectKey& key) const;
|
||||||
///< This function can safely be used for keys that are not present.
|
///< This function can safely be used for keys that are not present.
|
||||||
|
|
||||||
|
|
|
@ -139,42 +139,13 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// magic effects
|
// forced update and current value adjustments
|
||||||
adjustMagicEffects (ptr);
|
mActors.updateActor (ptr, 0);
|
||||||
|
|
||||||
// calculate dynamic stats
|
|
||||||
int strength = creatureStats.mAttributes[0].getBase();
|
|
||||||
int intelligence = creatureStats.mAttributes[1].getBase();
|
|
||||||
int willpower = creatureStats.mAttributes[2].getBase();
|
|
||||||
int agility = creatureStats.mAttributes[3].getBase();
|
|
||||||
int endurance = creatureStats.mAttributes[5].getBase();
|
|
||||||
|
|
||||||
double magickaFactor = creatureStats.mMagicEffects.get (EffectKey (84)).mMagnitude*0.1 + 0.5;
|
|
||||||
|
|
||||||
creatureStats.mDynamic[0].setBase (static_cast<int> (0.5 * (strength + endurance)));
|
|
||||||
creatureStats.mDynamic[1].setBase (static_cast<int> (intelligence +
|
|
||||||
magickaFactor * intelligence));
|
|
||||||
creatureStats.mDynamic[2].setBase (strength+willpower+agility+endurance);
|
|
||||||
|
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified());
|
creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::adjustMagicEffects (MWWorld::Ptr& creature)
|
|
||||||
{
|
|
||||||
MWMechanics::CreatureStats& creatureStats =
|
|
||||||
MWWorld::Class::get (creature).getCreatureStats (creature);
|
|
||||||
|
|
||||||
MagicEffects now = creatureStats.mSpells.getMagicEffects();
|
|
||||||
|
|
||||||
/// \todo add effects from active spells and equipment
|
|
||||||
|
|
||||||
MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now);
|
|
||||||
|
|
||||||
creatureStats.mMagicEffects = now;
|
|
||||||
|
|
||||||
// TODO apply diff to other stats
|
|
||||||
}
|
|
||||||
|
|
||||||
MechanicsManager::MechanicsManager()
|
MechanicsManager::MechanicsManager()
|
||||||
: mUpdatePlayer (true), mClassSelected (false),
|
: mUpdatePlayer (true), mClassSelected (false),
|
||||||
|
|
|
@ -31,8 +31,6 @@ namespace MWMechanics
|
||||||
///< build player according to stored class/race/birthsign information. Will
|
///< build player according to stored class/race/birthsign information. Will
|
||||||
/// default to the values of the ESM::NPC object, if no explicit information is given.
|
/// default to the values of the ESM::NPC object, if no explicit information is given.
|
||||||
|
|
||||||
void adjustMagicEffects (MWWorld::Ptr& creature);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MechanicsManager ();
|
MechanicsManager ();
|
||||||
|
|
|
@ -13,13 +13,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
void Spells::addSpell (const ESM::Spell *spell, MagicEffects& effects) const
|
void Spells::addSpell (const ESM::Spell *spell, MagicEffects& effects) const
|
||||||
{
|
{
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->effects.list.begin();
|
effects.add (spell->effects);
|
||||||
iter!=spell->effects.list.end(); ++iter)
|
|
||||||
{
|
|
||||||
EffectParam param;
|
|
||||||
param.mMagnitude = iter->magnMax; /// \todo calculate magnitude
|
|
||||||
effects.add (EffectKey (*iter), param);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spells::TIterator Spells::begin() const
|
Spells::TIterator Spells::begin() const
|
||||||
|
|
|
@ -90,7 +90,7 @@ namespace MWWorld
|
||||||
void clear();
|
void clear();
|
||||||
///< Empty container.
|
///< Empty container.
|
||||||
|
|
||||||
void flagAsModified();
|
virtual void flagAsModified();
|
||||||
///< \attention This function is internal to the world model and should not be called from
|
///< \attention This function is internal to the world model and should not be called from
|
||||||
/// outside.
|
/// outside.
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <components/esm/loadench.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/world.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
|
|
||||||
#include "class.hpp"
|
#include "class.hpp"
|
||||||
|
@ -32,7 +38,7 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots)
|
||||||
slots.push_back (end());
|
slots.push_back (end());
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::InventoryStore::InventoryStore()
|
MWWorld::InventoryStore::InventoryStore() : mMagicEffectsUpToDate (false)
|
||||||
{
|
{
|
||||||
initSlots (mSlots);
|
initSlots (mSlots);
|
||||||
}
|
}
|
||||||
|
@ -40,11 +46,15 @@ MWWorld::InventoryStore::InventoryStore()
|
||||||
MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
||||||
: ContainerStore (store)
|
: ContainerStore (store)
|
||||||
{
|
{
|
||||||
|
mMagicEffects = store.mMagicEffects;
|
||||||
|
mMagicEffectsUpToDate = store.mMagicEffectsUpToDate;
|
||||||
copySlots (store);
|
copySlots (store);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStore& store)
|
MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStore& store)
|
||||||
{
|
{
|
||||||
|
mMagicEffects = store.mMagicEffects;
|
||||||
|
mMagicEffectsUpToDate = store.mMagicEffectsUpToDate;
|
||||||
ContainerStore::operator= (store);
|
ContainerStore::operator= (store);
|
||||||
mSlots.clear();
|
mSlots.clear();
|
||||||
copySlots (store);
|
copySlots (store);
|
||||||
|
@ -201,6 +211,39 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MWMechanics::MagicEffects& MWWorld::InventoryStore::getMagicEffects()
|
||||||
|
{
|
||||||
|
if (!mMagicEffectsUpToDate)
|
||||||
|
{
|
||||||
|
mMagicEffects = MWMechanics::MagicEffects();
|
||||||
|
|
||||||
|
for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter)
|
||||||
|
if (*iter!=end())
|
||||||
|
{
|
||||||
|
std::string enchantmentId = MWWorld::Class::get (**iter).getEnchantment (**iter);
|
||||||
|
|
||||||
|
if (!enchantmentId.empty())
|
||||||
|
{
|
||||||
|
const ESM::Enchantment& enchantment =
|
||||||
|
*MWBase::Environment::get().getWorld()->getStore().enchants.find (enchantmentId);
|
||||||
|
|
||||||
|
if (enchantment.data.type==ESM::Enchantment::ConstantEffect)
|
||||||
|
mMagicEffects.add (enchantment.effects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mMagicEffectsUpToDate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mMagicEffects;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWWorld::InventoryStore::flagAsModified()
|
||||||
|
{
|
||||||
|
ContainerStore::flagAsModified();
|
||||||
|
mMagicEffectsUpToDate = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
|
bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
|
||||||
{
|
{
|
||||||
bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2);
|
bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2);
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "containerstore.hpp"
|
#include "containerstore.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/magiceffects.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
struct NpcStats;
|
struct NpcStats;
|
||||||
|
@ -41,6 +43,9 @@ namespace MWWorld
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
mutable MWMechanics::MagicEffects mMagicEffects;
|
||||||
|
mutable bool mMagicEffectsUpToDate;
|
||||||
|
|
||||||
typedef std::vector<ContainerStoreIterator> TSlots;
|
typedef std::vector<ContainerStoreIterator> TSlots;
|
||||||
|
|
||||||
mutable TSlots mSlots;
|
mutable TSlots mSlots;
|
||||||
|
@ -65,6 +70,15 @@ namespace MWWorld
|
||||||
void autoEquip (const MWMechanics::NpcStats& stats);
|
void autoEquip (const MWMechanics::NpcStats& stats);
|
||||||
///< Auto equip items according to stats and item value.
|
///< Auto equip items according to stats and item value.
|
||||||
|
|
||||||
|
const MWMechanics::MagicEffects& getMagicEffects();
|
||||||
|
///< Return magic effects from worn items.
|
||||||
|
///
|
||||||
|
/// \todo make this const again, after the constness of Ptrs and iterators has been addressed.
|
||||||
|
|
||||||
|
virtual void flagAsModified();
|
||||||
|
///< \attention This function is internal to the world model and should not be called from
|
||||||
|
/// outside.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2);
|
virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2);
|
||||||
|
|
108
apps/openmw/mwworld/timestamp.cpp
Normal file
108
apps/openmw/mwworld/timestamp.cpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
|
||||||
|
#include "timestamp.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
TimeStamp::TimeStamp (float hour, int day)
|
||||||
|
: mHour (hour), mDay (day)
|
||||||
|
{
|
||||||
|
if (hour<0 || hour>=24 || day<0)
|
||||||
|
throw std::runtime_error ("invalid time stamp");
|
||||||
|
}
|
||||||
|
|
||||||
|
float TimeStamp::getHour() const
|
||||||
|
{
|
||||||
|
return mHour;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TimeStamp::getDay() const
|
||||||
|
{
|
||||||
|
return mDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeStamp& TimeStamp::operator+= (double hours)
|
||||||
|
{
|
||||||
|
if (hours<0)
|
||||||
|
throw std::runtime_error ("can't move time stamp backwards in time");
|
||||||
|
|
||||||
|
hours += mHour;
|
||||||
|
|
||||||
|
mHour = static_cast<float> (std::fmod (hours, 24));
|
||||||
|
|
||||||
|
mDay += hours / 24;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (const TimeStamp& left, const TimeStamp& right)
|
||||||
|
{
|
||||||
|
return left.getHour()==right.getHour() && left.getDay()==right.getDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!= (const TimeStamp& left, const TimeStamp& right)
|
||||||
|
{
|
||||||
|
return !(left==right);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator< (const TimeStamp& left, const TimeStamp& right)
|
||||||
|
{
|
||||||
|
if (left.getDay()<right.getDay())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (left.getDay()>right.getDay())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return left.getHour()<right.getHour();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<= (const TimeStamp& left, const TimeStamp& right)
|
||||||
|
{
|
||||||
|
return left<right || left==right;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator> (const TimeStamp& left, const TimeStamp& right)
|
||||||
|
{
|
||||||
|
return !(left<=right);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>= (const TimeStamp& left, const TimeStamp& right)
|
||||||
|
{
|
||||||
|
return !(left<right);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeStamp operator+ (const TimeStamp& stamp, double hours)
|
||||||
|
{
|
||||||
|
return TimeStamp (stamp) + hours;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeStamp operator+ (double hours, const TimeStamp& stamp)
|
||||||
|
{
|
||||||
|
return TimeStamp (stamp) + hours;
|
||||||
|
}
|
||||||
|
|
||||||
|
double operator- (const TimeStamp& left, const TimeStamp& right)
|
||||||
|
{
|
||||||
|
if (left<right)
|
||||||
|
return -(right-left);
|
||||||
|
|
||||||
|
int days = left.getDay() - right.getDay();
|
||||||
|
|
||||||
|
double hours = 0;
|
||||||
|
|
||||||
|
if (left.getHour()<right.getHour())
|
||||||
|
{
|
||||||
|
hours = 24-right.getHour()+left.getHour();
|
||||||
|
++days;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hours = left.getHour()-right.getHour();
|
||||||
|
}
|
||||||
|
|
||||||
|
return hours + 24*days;
|
||||||
|
}
|
||||||
|
}
|
44
apps/openmw/mwworld/timestamp.hpp
Normal file
44
apps/openmw/mwworld/timestamp.hpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef GAME_MWWORLD_TIMESTAMP_H
|
||||||
|
#define GAME_MWWORLD_TIMESTAMP_H
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
/// \brief In-game time stamp
|
||||||
|
///
|
||||||
|
/// This class is based on the global variables GameHour and DaysPassed.
|
||||||
|
class TimeStamp
|
||||||
|
{
|
||||||
|
float mHour;
|
||||||
|
int mDay;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit TimeStamp (float hour = 0, int day = 0);
|
||||||
|
///< \oaram hour [0, 23)
|
||||||
|
/// \param day >=0
|
||||||
|
|
||||||
|
float getHour() const;
|
||||||
|
|
||||||
|
int getDay() const;
|
||||||
|
|
||||||
|
TimeStamp& operator+= (double hours);
|
||||||
|
///< \param hours >=0
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator== (const TimeStamp& left, const TimeStamp& right);
|
||||||
|
bool operator!= (const TimeStamp& left, const TimeStamp& right);
|
||||||
|
|
||||||
|
bool operator< (const TimeStamp& left, const TimeStamp& right);
|
||||||
|
bool operator<= (const TimeStamp& left, const TimeStamp& right);
|
||||||
|
|
||||||
|
bool operator> (const TimeStamp& left, const TimeStamp& right);
|
||||||
|
bool operator>= (const TimeStamp& left, const TimeStamp& right);
|
||||||
|
|
||||||
|
TimeStamp operator+ (const TimeStamp& stamp, double hours);
|
||||||
|
TimeStamp operator+ (double hours, const TimeStamp& stamp);
|
||||||
|
|
||||||
|
double operator- (const TimeStamp& left, const TimeStamp& right);
|
||||||
|
///< Returns the difference between \a left and \a right in in-game hours.
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -471,6 +471,12 @@ namespace MWWorld
|
||||||
mRendering->skySetDate (mGlobalVariables->getInt ("day"), month);
|
mRendering->skySetDate (mGlobalVariables->getInt ("day"), month);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimeStamp World::getTimeStamp() const
|
||||||
|
{
|
||||||
|
return TimeStamp (mGlobalVariables->getFloat ("gamehour"),
|
||||||
|
mGlobalVariables->getInt ("dayspassed"));
|
||||||
|
}
|
||||||
|
|
||||||
bool World::toggleSky()
|
bool World::toggleSky()
|
||||||
{
|
{
|
||||||
if (mSky)
|
if (mSky)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "physicssystem.hpp"
|
#include "physicssystem.hpp"
|
||||||
#include "cells.hpp"
|
#include "cells.hpp"
|
||||||
#include "localscripts.hpp"
|
#include "localscripts.hpp"
|
||||||
|
#include "timestamp.hpp"
|
||||||
|
|
||||||
#include <openengine/bullet/physic.hpp>
|
#include <openengine/bullet/physic.hpp>
|
||||||
#include <openengine/ogre/fader.hpp>
|
#include <openengine/ogre/fader.hpp>
|
||||||
|
@ -185,6 +186,9 @@ namespace MWWorld
|
||||||
void setDay (int day);
|
void setDay (int day);
|
||||||
///< Set in-game time day.
|
///< Set in-game time day.
|
||||||
|
|
||||||
|
TimeStamp getTimeStamp() const;
|
||||||
|
///< Return current in-game time stamp.
|
||||||
|
|
||||||
bool toggleSky();
|
bool toggleSky();
|
||||||
///< \return Resulting mode
|
///< \return Resulting mode
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue