Introduce a separate class to control world date and time

pull/578/head
Andrei Kortunov 5 years ago
parent 2eb9d4ad4e
commit 81805b7263

@ -71,7 +71,7 @@ add_openmw_dir (mwworld
actionequip timestamp actionalchemy cellstore actionapply actioneat
store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager
cellpreloader
cellpreloader datetimemanager
)
add_openmw_dir (mwphysics

@ -48,6 +48,7 @@ namespace ESM
struct EffectList;
struct CreatureLevList;
struct ItemLevList;
struct TimeStamp;
}
namespace MWRender
@ -204,24 +205,14 @@ namespace MWBase
virtual void advanceTime (double hours, bool incremental = false) = 0;
///< Advance in-game time.
virtual void setHour (double hour) = 0;
///< Set in-game time hour.
virtual void setMonth (int month) = 0;
///< Set in-game time month.
virtual void setDay (int day) = 0;
///< Set in-game time day.
virtual int getDay() const = 0;
virtual int getMonth() const = 0;
virtual int getYear() const = 0;
virtual std::string getMonthName (int month = -1) const = 0;
///< Return name of month (-1: current month)
virtual MWWorld::TimeStamp getTimeStamp() const = 0;
///< Return current in-game time stamp.
///< Return current in-game time and number of day since new game start.
virtual ESM::EpochTimeStamp getEpochTimeStamp() const = 0;
///< Return current in-game date and time.
virtual bool toggleSky() = 0;
///< \return Resulting mode

@ -150,11 +150,10 @@ namespace MWGui
if (hour >= 13) hour -= 12;
if (hour == 0) hour = 12;
std::string dateTimeText =
MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getDay ()) + " "
+ month + " (#{sDay} " + MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay())
+ ") " + MyGUI::utility::toString(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
ESM::EpochTimeStamp currentDate = MWBase::Environment::get().getWorld()->getEpochTimeStamp();
int daysPassed = MWBase::Environment::get().getWorld()->getTimeStamp().getDay();
std::string formattedHour = pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}";
std::string dateTimeText = Misc::StringUtils::format("%i %s (#{sDay} %i) %i %s", currentDate.mDay, month, daysPassed, hour, formattedHour);
mDateTimeText->setCaptionWithReplacing (dateTimeText);
}

@ -213,11 +213,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
profile.mPlayerClassId = classId;
profile.mPlayerCell = world.getCellName();
profile.mInGameTime.mGameHour = world.getTimeStamp().getHour();
profile.mInGameTime.mDay = world.getDay();
profile.mInGameTime.mMonth = world.getMonth();
profile.mInGameTime.mYear = world.getYear();
profile.mInGameTime = world.getEpochTimeStamp();
profile.mTimePlayed = mTimePlayed;
profile.mDescription = description;

@ -0,0 +1,227 @@
#include "datetimemanager.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "esmstore.hpp"
#include "globals.hpp"
#include "timestamp.hpp"
namespace
{
static int getDaysPerMonth(int month)
{
switch (month)
{
case 0: return 31;
case 1: return 28;
case 2: return 31;
case 3: return 30;
case 4: return 31;
case 5: return 30;
case 6: return 31;
case 7: return 31;
case 8: return 30;
case 9: return 31;
case 10: return 30;
case 11: return 31;
}
throw std::runtime_error ("month out of range");
}
}
namespace MWWorld
{
void DateTimeManager::setup(Globals& globalVariables)
{
mGameHour = globalVariables["gamehour"].getFloat();
mDaysPassed = globalVariables["dayspassed"].getInteger();
mDay = globalVariables["day"].getInteger();
mMonth = globalVariables["month"].getInteger();
mYear = globalVariables["year"].getInteger();
mTimeScale = globalVariables["timescale"].getFloat();
}
void DateTimeManager::setHour(double hour)
{
if (hour < 0)
hour = 0;
int days = static_cast<int>(hour / 24);
hour = std::fmod(hour, 24);
mGameHour = static_cast<float>(hour);
if (days > 0)
setDay(days + mDay);
}
void DateTimeManager::setDay(int day)
{
if (day < 1)
day = 1;
int month = mMonth;
while (true)
{
int days = getDaysPerMonth(month);
if (day <= days)
break;
if (month < 11)
{
++month;
}
else
{
month = 0;
mYear++;
}
day -= days;
}
mDay = day;
mMonth = month;
}
TimeStamp DateTimeManager::getTimeStamp() const
{
return TimeStamp(mGameHour, mDaysPassed);
}
float DateTimeManager::getTimeScaleFactor() const
{
return mTimeScale;
}
ESM::EpochTimeStamp DateTimeManager::getEpochTimeStamp() const
{
ESM::EpochTimeStamp timeStamp;
timeStamp.mGameHour = mGameHour;
timeStamp.mDay = mDay;
timeStamp.mMonth = mMonth;
timeStamp.mYear = mYear;
return timeStamp;
}
void DateTimeManager::setMonth(int month)
{
if (month < 0)
month = 0;
int years = month / 12;
month = month % 12;
int days = getDaysPerMonth(month);
if (mDay > days)
mDay = days;
mMonth = month;
if (years > 0)
mYear += years;
}
void DateTimeManager::advanceTime(double hours, Globals& globalVariables)
{
hours += mGameHour;
setHour(hours);
int days = static_cast<int>(hours / 24);
if (days > 0)
mDaysPassed += days;
globalVariables["gamehour"].setFloat(mGameHour);
globalVariables["dayspassed"].setInteger(mDaysPassed);
globalVariables["day"].setInteger(mDay);
globalVariables["month"].setInteger(mMonth);
globalVariables["year"].setInteger(mYear);
}
std::string DateTimeManager::getMonthName(int month) const
{
if (month == -1)
month = mMonth;
const int months = 12;
if (month < 0 || month >= months)
return std::string();
static const char *monthNames[months] =
{
"sMonthMorningstar", "sMonthSunsdawn", "sMonthFirstseed", "sMonthRainshand",
"sMonthSecondseed", "sMonthMidyear", "sMonthSunsheight", "sMonthLastseed",
"sMonthHeartfire", "sMonthFrostfall", "sMonthSunsdusk", "sMonthEveningstar"
};
const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(monthNames[month]);
return setting->mValue.getString();
}
bool DateTimeManager::updateGlobalFloat(const std::string& name, float value)
{
if (name=="gamehour")
{
setHour(value);
return true;
}
else if (name=="day")
{
setDay(static_cast<int>(value));
return true;
}
else if (name=="month")
{
setMonth(static_cast<int>(value));
return true;
}
else if (name=="year")
{
mYear = static_cast<int>(value);
}
else if (name=="timescale")
{
mTimeScale = value;
}
else if (name=="dayspassed")
{
mDaysPassed = static_cast<int>(value);
}
return false;
}
bool DateTimeManager::updateGlobalInt(const std::string& name, int value)
{
if (name=="gamehour")
{
setHour(static_cast<float>(value));
return true;
}
else if (name=="day")
{
setDay(value);
return true;
}
else if (name=="month")
{
setMonth(value);
return true;
}
else if (name=="year")
{
mYear = value;
}
else if (name=="timescale")
{
mTimeScale = static_cast<float>(value);
}
else if (name=="dayspassed")
{
mDaysPassed = value;
}
return false;
}
}

@ -0,0 +1,43 @@
#ifndef GAME_MWWORLD_DATETIMEMANAGER_H
#define GAME_MWWORLD_DATETIMEMANAGER_H
#include <string>
namespace ESM
{
struct EpochTimeStamp;
}
namespace MWWorld
{
class Globals;
class TimeStamp;
class DateTimeManager
{
int mDaysPassed = 0;
int mDay = 0;
int mMonth = 0;
int mYear = 0;
float mGameHour = 0.f;
float mTimeScale = 0.f;
void setHour(double hour);
void setDay(int day);
void setMonth(int month);
public:
std::string getMonthName(int month) const;
TimeStamp getTimeStamp() const;
ESM::EpochTimeStamp getEpochTimeStamp() const;
float getTimeScaleFactor() const;
void advanceTime(double hours, Globals& globalVariables);
void setup(Globals& globalVariables);
bool updateGlobalInt(const std::string& name, int value);
bool updateGlobalFloat(const std::string& name, float value);
};
}
#endif

@ -2,10 +2,9 @@
#include <stdexcept>
#include <components/misc/stringops.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/esmreader.hpp>
#include <components/misc/stringops.hpp>
#include "esmstore.hpp"

@ -60,6 +60,7 @@
#include "../mwphysics/object.hpp"
#include "../mwphysics/constants.hpp"
#include "datetimemanager.hpp"
#include "player.hpp"
#include "manualref.hpp"
#include "cellstore.hpp"
@ -121,33 +122,11 @@ namespace MWWorld
LoadersContainer mLoaders;
};
int World::getDaysPerMonth (int month) const
{
switch (month)
{
case 0: return 31;
case 1: return 28;
case 2: return 31;
case 3: return 30;
case 4: return 31;
case 5: return 30;
case 6: return 31;
case 7: return 31;
case 8: return 30;
case 9: return 31;
case 10: return 30;
case 11: return 31;
}
throw std::runtime_error ("month out of range");
}
void World::adjustSky()
{
if (mSky && (isCellExterior() || isCellQuasiExterior()))
{
mRendering->skySetDate (mDay->getInteger(), mMonth->getInteger());
updateSkyDate();
mRendering->setSkyEnabled(true);
}
else
@ -193,6 +172,8 @@ namespace MWWorld
if (mEsm[0].getFormat() == 0)
ensureNeededRecords();
mCurrentDate.reset(new DateTimeManager());
fillGlobalVariables();
mStore.setUp(true);
@ -227,13 +208,7 @@ namespace MWWorld
void World::fillGlobalVariables()
{
mGlobalVariables.fill (mStore);
mGameHour = &mGlobalVariables["gamehour"];
mDaysPassed = &mGlobalVariables["dayspassed"];
mDay = &mGlobalVariables["day"];
mMonth = &mGlobalVariables["month"];
mYear = &mGlobalVariables["year"];
mTimeScale = &mGlobalVariables["timescale"];
mCurrentDate->setup(mGlobalVariables);
}
void World::startNewGame (bool bypass)
@ -310,6 +285,7 @@ namespace MWWorld
mPhysics->toggleCollisionMode();
MWBase::Environment::get().getWindowManager()->updatePlayer();
mCurrentDate->setup(mGlobalVariables);
}
void World::clear()
@ -639,26 +615,20 @@ namespace MWWorld
void World::setGlobalInt (const std::string& name, int value)
{
if (name=="gamehour")
setHour (value);
else if (name=="day")
setDay (value);
else if (name=="month")
setMonth (value);
else
mGlobalVariables[name].setInteger (value);
bool dateUpdated = mCurrentDate->updateGlobalInt(name, value);
if (dateUpdated)
updateSkyDate();
mGlobalVariables[name].setInteger (value);
}
void World::setGlobalFloat (const std::string& name, float value)
{
if (name=="gamehour")
setHour (value);
else if (name=="day")
setDay(static_cast<int>(value));
else if (name=="month")
setMonth(static_cast<int>(value));
else
mGlobalVariables[name].setFloat (value);
bool dateUpdated = mCurrentDate->updateGlobalFloat(name, value);
if (dateUpdated)
updateSkyDate();
mGlobalVariables[name].setFloat(value);
}
int World::getGlobalInt (const std::string& name) const
@ -676,6 +646,11 @@ namespace MWWorld
return mGlobalVariables.getType (name);
}
std::string World::getMonthName (int month) const
{
return mCurrentDate->getMonthName(month);
}
std::string World::getCellName (const MWWorld::CellStore *cell) const
{
if (!cell)
@ -894,130 +869,29 @@ namespace MWWorld
}
mWeatherManager->advanceTime (hours, incremental);
mCurrentDate->advanceTime(hours, mGlobalVariables);
updateSkyDate();
if (!incremental)
{
mRendering->notifyWorldSpaceChanged();
mProjectileManager->clear();
}
hours += mGameHour->getFloat();
setHour (hours);
int days = static_cast<int>(hours / 24);
if (days>0)
mDaysPassed->setInteger (
days + mDaysPassed->getInteger());
}
void World::setHour (double hour)
{
if (hour<0)
hour = 0;
int days = static_cast<int>(hour / 24);
hour = std::fmod (hour, 24);
mGameHour->setFloat(static_cast<float>(hour));
if (days>0)
setDay (days + mDay->getInteger());
}
void World::setDay (int day)
{
if (day<1)
day = 1;
int month = mMonth->getInteger();
while (true)
{
int days = getDaysPerMonth (month);
if (day<=days)
break;
if (month<11)
{
++month;
}
else
{
month = 0;
mYear->setInteger(mYear->getInteger()+1);
}
day -= days;
}
mDay->setInteger(day);
mMonth->setInteger(month);
mRendering->skySetDate(day, month);
}
void World::setMonth (int month)
{
if (month<0)
month = 0;
int years = month / 12;
month = month % 12;
int days = getDaysPerMonth (month);
if (mDay->getInteger()>days)
mDay->setInteger (days);
mMonth->setInteger (month);
if (years>0)
mYear->setInteger (years+mYear->getInteger());
mRendering->skySetDate (mDay->getInteger(), month);
}
int World::getDay() const
{
return mDay->getInteger();
}
int World::getMonth() const
{
return mMonth->getInteger();
}
int World::getYear() const
float World::getTimeScaleFactor() const
{
return mYear->getInteger();
return mCurrentDate->getTimeScaleFactor();
}
std::string World::getMonthName (int month) const
TimeStamp World::getTimeStamp() const
{
if (month==-1)
month = getMonth();
const int months = 12;
if (month<0 || month>=months)
return "";
static const char *monthNames[months] =
{
"sMonthMorningstar", "sMonthSunsdawn", "sMonthFirstseed", "sMonthRainshand",
"sMonthSecondseed", "sMonthMidyear", "sMonthSunsheight", "sMonthLastseed",
"sMonthHeartfire", "sMonthFrostfall", "sMonthSunsdusk", "sMonthEveningstar"
};
return mStore.get<ESM::GameSetting>().find (monthNames[month])->mValue.getString();
return mCurrentDate->getTimeStamp();
}
TimeStamp World::getTimeStamp() const
ESM::EpochTimeStamp World::getEpochTimeStamp() const
{
return TimeStamp (mGameHour->getFloat(), mDaysPassed->getInteger());
return mCurrentDate->getEpochTimeStamp();
}
bool World::toggleSky()
@ -1042,11 +916,6 @@ namespace MWWorld
mRendering->skySetMoonColour (red);
}
float World::getTimeScaleFactor() const
{
return mTimeScale->getFloat();
}
void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
{
mPhysics->clearQueuedMovement();
@ -1089,6 +958,8 @@ namespace MWWorld
changeToExteriorCell (position, adjustPlayerPos, changeEvent);
else
changeToInteriorCell (cellId.mWorldspace, position, adjustPlayerPos, changeEvent);
mCurrentDate->setup(mGlobalVariables);
}
void World::markCellAsUnchanged()
@ -3968,4 +3839,10 @@ namespace MWWorld
mNavigator->reportStats(frameNumber, stats);
mPhysics->reportStats(frameNumber, stats);
}
void World::updateSkyDate()
{
ESM::EpochTimeStamp currentDate = mCurrentDate->getEpochTimeStamp();
mRendering->skySetDate(currentDate.mDay, currentDate.mMonth);
}
}

@ -69,6 +69,7 @@ namespace MWPhysics
namespace MWWorld
{
class DateTimeManager;
class WeatherManager;
class Player;
class ProjectileManager;
@ -85,13 +86,6 @@ namespace MWWorld
LocalScripts mLocalScripts;
MWWorld::Globals mGlobalVariables;
ESM::Variant* mGameHour;
ESM::Variant* mDaysPassed;
ESM::Variant* mDay;
ESM::Variant* mMonth;
ESM::Variant* mYear;
ESM::Variant* mTimeScale;
Cells mCells;
std::string mCurrentWorldSpace;
@ -102,6 +96,7 @@ namespace MWWorld
std::unique_ptr<MWRender::RenderingManager> mRendering;
std::unique_ptr<MWWorld::Scene> mWorldScene;
std::unique_ptr<MWWorld::WeatherManager> mWeatherManager;
std::unique_ptr<MWWorld::DateTimeManager> mCurrentDate;
std::shared_ptr<ProjectileManager> mProjectileManager;
bool mSky;
@ -139,7 +134,6 @@ namespace MWWorld
World& operator= (const World&);
void updateWeather(float duration, bool paused = false);
int getDaysPerMonth (int month) const;
void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags);
@ -173,6 +167,8 @@ namespace MWWorld
void fillGlobalVariables();
void updateSkyDate();
/**
* @brief loadContentFiles - Loads content files (esm,esp,omwgame,omwaddon)
* @param fileCollections- Container which holds content file names and their paths
@ -318,24 +314,14 @@ namespace MWWorld
void advanceTime (double hours, bool incremental = false) override;
///< Advance in-game time.
void setHour (double hour) override;
///< Set in-game time hour.
void setMonth (int month) override;
///< Set in-game time month.
void setDay (int day) override;
///< Set in-game time day.
int getDay() const override;
int getMonth() const override;
int getYear() const override;
std::string getMonthName (int month = -1) const override;
///< Return name of month (-1: current month)
TimeStamp getTimeStamp() const override;
///< Return current in-game time stamp.
///< Return current in-game time and number of day since new game start.
ESM::EpochTimeStamp getEpochTimeStamp() const override;
///< Return current in-game date and time.
bool toggleSky() override;
///< \return Resulting mode

@ -14,6 +14,14 @@ struct TimeStamp
int mDay;
};
struct EpochTimeStamp
{
float mGameHour;
int mDay;
int mMonth;
int mYear;
};
// Pixel color value. Standard four-byte rr,gg,bb,aa format.
typedef uint32_t Color;

@ -2,7 +2,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
int ESM::SavedGame::sCurrentFormat = 10;

@ -4,6 +4,8 @@
#include <vector>
#include <string>
#include "defs.hpp"
namespace ESM
{
class ESMReader;
@ -17,14 +19,6 @@ namespace ESM
static int sCurrentFormat;
struct TimeStamp
{
float mGameHour;
int mDay;
int mMonth;
int mYear;
};
std::vector<std::string> mContentFiles;
std::string mPlayerName;
int mPlayerLevel;
@ -36,7 +30,7 @@ namespace ESM
std::string mPlayerClassName;
std::string mPlayerCell;
TimeStamp mInGameTime;
EpochTimeStamp mInGameTime;
double mTimePlayed;
std::string mDescription;
std::vector<char> mScreenshot; // raw jpg-encoded data

Loading…
Cancel
Save