diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index d7c229cf9..ca2355346 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -48,6 +48,7 @@ add_openmw_dir (mwworld refdata world physicssystem scene globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors cells localscripts customdata weather inventorystore ptr actionread + timestamp ) add_openmw_dir (mwclass @@ -57,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 849ab8ea4..5a17d50e4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -8,11 +8,30 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" +#include "creaturestats.hpp" + namespace MWMechanics { 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 (0.5 * (strength + endurance))); + creatureStats.mDynamic[1].setBase (static_cast (intelligence + + magickaFactor * intelligence)); + creatureStats.mDynamic[2].setBase (strength+willpower+agility+endurance); } void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) @@ -22,6 +41,27 @@ namespace MWMechanics 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) {} void Actors::addActor (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index ae93fb52e..30e73ccf7 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -19,10 +19,10 @@ namespace MWMechanics std::set mActors; float mDuration; - void updateActor (const MWWorld::Ptr& ptr, float duration); - void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); + void adjustMagicEffects (const MWWorld::Ptr& creature); + public: Actors(); @@ -39,6 +39,11 @@ namespace MWMechanics void update (std::vector >& movement, float duration, bool paused); ///< 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. + }; } 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; }; } diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 1c73bf1b1..a77e19966 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -1,6 +1,8 @@ #include "magiceffects.hpp" +#include + #include #include @@ -66,6 +68,46 @@ namespace MWMechanics } } + void MagicEffects::add (const ESM::EffectList& list) + { + for (std::vector::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 ( + (iter->magnMax-iter->magnMin+1)* + (static_cast (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 { Collection::const_iterator iter = mCollection.find (key); @@ -85,11 +127,11 @@ namespace MWMechanics MagicEffects result; // 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); - if (other==prev.End()) + if (other==prev.end()) { // adding result.add (iter->first, iter->second); @@ -102,17 +144,16 @@ namespace MWMechanics } // 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); - if (other==prev.End()) + 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 index 3d36ea813..2f61d7eeb 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -6,6 +6,7 @@ namespace ESM { struct ENAMstruct; + struct EffectList; } namespace MWMechanics @@ -60,12 +61,16 @@ namespace MWMechanics 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 ESM::EffectList& list); + + MagicEffects& operator+= (const MagicEffects& effects); + EffectParam get (const EffectKey& key) const; ///< This function can safely be used for keys that are not present. diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index 8bc408be6..0c48d8894 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -139,42 +139,13 @@ namespace MWMechanics } } - // magic effects - adjustMagicEffects (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 (0.5 * (strength + endurance))); - creatureStats.mDynamic[1].setBase (static_cast (intelligence + - magickaFactor * intelligence)); - creatureStats.mDynamic[2].setBase (strength+willpower+agility+endurance); + // forced update and current value adjustments + mActors.updateActor (ptr, 0); for (int i=0; i<3; ++i) 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() : mUpdatePlayer (true), mClassSelected (false), diff --git a/apps/openmw/mwmechanics/mechanicsmanager.hpp b/apps/openmw/mwmechanics/mechanicsmanager.hpp index a26fb98cd..62bb4cf7e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.hpp @@ -31,8 +31,6 @@ namespace MWMechanics ///< 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. - void adjustMagicEffects (MWWorld::Ptr& creature); - public: MechanicsManager (); diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index a53c75dc2..af43cdfb5 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -13,13 +13,7 @@ namespace MWMechanics { void Spells::addSpell (const ESM::Spell *spell, MagicEffects& effects) const { - for (std::vector::const_iterator iter = spell->effects.list.begin(); - iter!=spell->effects.list.end(); ++iter) - { - EffectParam param; - param.mMagnitude = iter->magnMax; /// \todo calculate magnitude - effects.add (EffectKey (*iter), param); - } + effects.add (spell->effects); } Spells::TIterator Spells::begin() const diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 3cb3f3bdc..f677e0dcb 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -90,7 +90,7 @@ namespace MWWorld void clear(); ///< Empty container. - void flagAsModified(); + virtual void flagAsModified(); ///< \attention This function is internal to the world model and should not be called from /// outside. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 3e535793c..98ab1665b 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -4,6 +4,12 @@ #include #include +#include + +#include "../mwbase/environment.hpp" + +#include "../mwworld/world.hpp" + #include "../mwmechanics/npcstats.hpp" #include "class.hpp" @@ -32,7 +38,7 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots) slots.push_back (end()); } -MWWorld::InventoryStore::InventoryStore() +MWWorld::InventoryStore::InventoryStore() : mMagicEffectsUpToDate (false) { initSlots (mSlots); } @@ -40,11 +46,15 @@ MWWorld::InventoryStore::InventoryStore() MWWorld::InventoryStore::InventoryStore (const InventoryStore& store) : ContainerStore (store) { + mMagicEffects = store.mMagicEffects; + mMagicEffectsUpToDate = store.mMagicEffectsUpToDate; copySlots (store); } MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStore& store) { + mMagicEffects = store.mMagicEffects; + mMagicEffectsUpToDate = store.mMagicEffectsUpToDate; ContainerStore::operator= (store); mSlots.clear(); 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 canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 05fc651ee..dcfb21f30 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -3,6 +3,8 @@ #include "containerstore.hpp" +#include "../mwmechanics/magiceffects.hpp" + namespace MWMechanics { struct NpcStats; @@ -41,6 +43,9 @@ namespace MWWorld private: + mutable MWMechanics::MagicEffects mMagicEffects; + mutable bool mMagicEffectsUpToDate; + typedef std::vector TSlots; mutable TSlots mSlots; @@ -65,6 +70,15 @@ namespace MWWorld void autoEquip (const MWMechanics::NpcStats& stats); ///< 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: virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); diff --git a/apps/openmw/mwworld/timestamp.cpp b/apps/openmw/mwworld/timestamp.cpp new file mode 100644 index 000000000..e2f3d6c63 --- /dev/null +++ b/apps/openmw/mwworld/timestamp.cpp @@ -0,0 +1,108 @@ + +#include "timestamp.hpp" + +#include + +#include + +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 (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 false; + + return left.getHour() (const TimeStamp& left, const TimeStamp& right) + { + return !(left<=right); + } + + bool operator>= (const TimeStamp& left, const TimeStamp& right) + { + return !(left=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 diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 4adaf7918..eeda92277 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -471,6 +471,12 @@ namespace MWWorld mRendering->skySetDate (mGlobalVariables->getInt ("day"), month); } + TimeStamp World::getTimeStamp() const + { + return TimeStamp (mGlobalVariables->getFloat ("gamehour"), + mGlobalVariables->getInt ("dayspassed")); + } + bool World::toggleSky() { if (mSky) diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 7359f8b90..49a3cf029 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -18,6 +18,7 @@ #include "physicssystem.hpp" #include "cells.hpp" #include "localscripts.hpp" +#include "timestamp.hpp" #include #include @@ -185,6 +186,9 @@ namespace MWWorld void setDay (int day); ///< Set in-game time day. + TimeStamp getTimeStamp() const; + ///< Return current in-game time stamp. + bool toggleSky(); ///< \return Resulting mode