summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAki <please@ignore.pl>2024-04-01 05:16:14 +0200
committerAki <please@ignore.pl>2024-04-01 05:21:16 +0200
commit3be3bfaa17773550a696ed2b756136debfe79ae2 (patch)
treedb55a420e43ddaa4a72140d2795892757c1672d3
parent0a3451f251f360267e2927d8320787d59148eadd (diff)
downloadstarshatter-3be3bfaa17773550a696ed2b756136debfe79ae2.zip
starshatter-3be3bfaa17773550a696ed2b756136debfe79ae2.tar.gz
starshatter-3be3bfaa17773550a696ed2b756136debfe79ae2.tar.bz2
Fixed date and time consistency across Campaigns and Missions
This fixes campaign mission generation mostly, but a full playthrough will be needed. Missions now serialize and accept stardate setting a bit better. Thanks to this, date is propagated over multiplayer, too. This seems to break points system? Code-wise, this does not workaround the problems from before namely over-reliance on side-effects. Stardate class is at least one small step into good direction. Now, it'd be nice to attach clocks to simulation and campaign and whatever else that needs them.
-rw-r--r--StarsEx/CMakeLists.txt38
-rw-r--r--StarsEx/Campaign.cpp114
-rw-r--r--StarsEx/Campaign.h13
-rw-r--r--StarsEx/CampaignSaveGame.cpp34
-rw-r--r--StarsEx/Clock.cpp5
-rw-r--r--StarsEx/Clock.h2
-rw-r--r--StarsEx/CmdIntelDlg.cpp15
-rw-r--r--StarsEx/CmdIntelDlg.h1
-rw-r--r--StarsEx/CmpSelectDlg.cpp10
-rw-r--r--StarsEx/Mission.cpp2
-rw-r--r--StarsEx/Mission.h4
-rw-r--r--StarsEx/MsnSelectDlg.cpp42
-rw-r--r--StarsEx/NetUnitDlg.cpp29
-rw-r--r--StarsEx/Player.cpp12
-rw-r--r--StarsEx/Player.h4
-rw-r--r--StarsEx/Sim.cpp17
-rw-r--r--StarsEx/StarSystem.cpp75
-rw-r--r--StarsEx/StarSystem.h5
-rw-r--r--StarsEx/Stardate.cpp137
-rw-r--r--StarsEx/Stardate.h43
-rw-r--r--StarsEx/Starshatter.cpp39
-rw-r--r--StarsEx/Weather.cpp6
-rw-r--r--StarsEx/test/Stardate.cpp60
23 files changed, 441 insertions, 266 deletions
diff --git a/StarsEx/CMakeLists.txt b/StarsEx/CMakeLists.txt
index 4541191..6a6b4d6 100644
--- a/StarsEx/CMakeLists.txt
+++ b/StarsEx/CMakeLists.txt
@@ -39,18 +39,18 @@ add_library(
CmpCompleteDlg.cpp
CmpFileDlg.cpp
CmpLoadDlg.cpp
+ CmpnScreen.cpp
CmpSceneDlg.cpp
CmpSelectDlg.cpp
- CmpnScreen.cpp
Color.cpp
CombatAction.cpp
+ Combatant.cpp
CombatAssignment.cpp
CombatEvent.cpp
CombatGroup.cpp
CombatRoster.cpp
CombatUnit.cpp
CombatZone.cpp
- Combatant.cpp
ComboBox.cpp
ComboList.cpp
Component.cpp
@@ -74,7 +74,6 @@ add_library(
Element.cpp
Encrypt.cpp
EngDlg.cpp
- UIEventDispatch.cpp
ExceptionHandler.cpp
ExitDlg.cpp
Explosion.cpp
@@ -89,9 +88,9 @@ add_library(
FltDlg.cpp
Font.cpp
FontMgr.cpp
+ FormatUtil.cpp
FormDef.cpp
FormWindow.cpp
- FormatUtil.cpp
Galaxy.cpp
Game.cpp
GameScreen.cpp
@@ -100,20 +99,20 @@ add_library(
Graphic.cpp
Grid.cpp
GroundAI.cpp
- HUDSounds.cpp
- HUDView.cpp
Hangar.cpp
HardPoint.cpp
Hoop.cpp
+ HUDSounds.cpp
+ HUDView.cpp
ImageBox.cpp
ImgView.cpp
Instruction.cpp
Intel.cpp
JoyDlg.cpp
Joystick.cpp
+ Keyboard.cpp
KeyDlg.cpp
KeyMap.cpp
- Keyboard.cpp
LandingGear.cpp
Layout.cpp
Light.cpp
@@ -121,8 +120,8 @@ add_library(
LoadDlg.cpp
LoadScreen.cpp
Locale_ss.cpp
- MCIWave.cpp
MapView.cpp
+ MCIWave.cpp
Menu.cpp
MenuDlg.cpp
MenuScreen.cpp
@@ -135,8 +134,8 @@ add_library(
ModDlg.cpp
ModInfo.cpp
ModInfoDlg.cpp
- Mouse.cpp
MouseController.cpp
+ Mouse.cpp
MsnDlg.cpp
MsnEditDlg.cpp
MsnEditNavDlg.cpp
@@ -150,7 +149,6 @@ add_library(
MultiController.cpp
MusicDirector.cpp
MusicTrack.cpp
- NPClientWraps.cpp
NavAI.cpp
NavDlg.cpp
NavLight.cpp
@@ -162,11 +160,11 @@ add_library(
NetClientConfig.cpp
NetClientDlg.cpp
NetData.cpp
- NetGame.cpp
NetGameClient.cpp
+ NetGame.cpp
NetGameServer.cpp
- NetLobby.cpp
NetLobbyClient.cpp
+ NetLobby.cpp
NetLobbyDlg.cpp
NetLobbyServer.cpp
NetPacket.cpp
@@ -177,11 +175,12 @@ add_library(
NetUnitDlg.cpp
NetUser.cpp
NetUtil.cpp
+ NPClientWraps.cpp
OptDlg.cpp
- Pcx.cpp
Panic.cpp
ParseUtil.cpp
Particles.cpp
+ Pcx.cpp
Physical.cpp
PlanScreen.cpp
Player.cpp
@@ -194,7 +193,6 @@ add_library(
QuantumFlash.cpp
QuantumView.cpp
QuitView.cpp
- RLoc.cpp
RadioHandler.cpp
RadioMessage.cpp
RadioTraffic.cpp
@@ -203,6 +201,7 @@ add_library(
Random.cpp
Res.cpp
RichTextBox.cpp
+ RLoc.cpp
Scene.cpp
Screen.cpp
ScrollWindow.cpp
@@ -211,8 +210,8 @@ add_library(
Shadow.cpp
Shield.cpp
ShieldRep.cpp
- Ship.cpp
ShipAI.cpp
+ Ship.cpp
ShipCtrl.cpp
ShipDesign.cpp
ShipKiller.cpp
@@ -225,23 +224,24 @@ add_library(
Sky.cpp
Slider.cpp
Solid.cpp
- Sound.cpp
SoundCard.cpp
+ Sound.cpp
SoundD3D.cpp
Sprite.cpp
- StarSystem.cpp
+ Stardate.cpp
Starshatter.cpp
StarshipAI.cpp
StarshipTacticalAI.cpp
+ StarSystem.cpp
SteerAI.cpp
System.cpp
SystemDesign.cpp
TacRefDlg.cpp
TacticalAI.cpp
TacticalView.cpp
- Terrain.cpp
TerrainApron.cpp
TerrainClouds.cpp
+ Terrain.cpp
TerrainHaze.cpp
TerrainPatch.cpp
TerrainRegion.cpp
@@ -250,6 +250,7 @@ add_library(
Thruster.cpp
TrackIR.cpp
Trail.cpp
+ UIEventDispatch.cpp
VidDlg.cpp
Video.cpp
VideoDX9.cpp
@@ -331,6 +332,7 @@ endif()
add_executable(
${PROJECT_NAME}_test
test/AudioConfig.cpp
+ test/Stardate.cpp
)
generate_emulator(${PROJECT_NAME}_test LIBS Opcode ArchiveEx)
target_link_libraries(${PROJECT_NAME}_test PRIVATE ${PROJECT_NAME} GTest::gtest_main)
diff --git a/StarsEx/Campaign.cpp b/StarsEx/Campaign.cpp
index 70846f0..b139787 100644
--- a/StarsEx/Campaign.cpp
+++ b/StarsEx/Campaign.cpp
@@ -12,33 +12,34 @@
*/
#include "Campaign.h"
-#include "CampaignPlanStrategic.h"
+
+#include "Bitmap.h"
#include "CampaignPlanAssignment.h"
#include "CampaignPlanEvent.h"
#include "CampaignPlanMission.h"
#include "CampaignPlanMovement.h"
-#include "CampaignSituationReport.h"
+#include "CampaignPlanStrategic.h"
#include "CampaignSaveGame.h"
-#include "Combatant.h"
+#include "CampaignSituationReport.h"
+#include "Clock.h"
#include "CombatAction.h"
+#include "Combatant.h"
#include "CombatEvent.h"
#include "CombatGroup.h"
#include "CombatRoster.h"
#include "CombatUnit.h"
#include "CombatZone.h"
-#include "Galaxy.h"
-#include "Mission.h"
-#include "StarSystem.h"
-#include "Starshatter.h"
-#include "Player.h"
-
#include "ContentBundle.h"
-#include "Bitmap.h"
-#include "Clock.h"
#include "DataLoader.h"
+#include "FormatUtil.h"
+#include "Galaxy.h"
+#include "Mission.h"
#include "ParseUtil.h"
+#include "Player.h"
#include "Random.h"
-#include "FormatUtil.h"
+#include "Stardate.h"
+#include "Starshatter.h"
+#include "StarSystem.h"
const int TIME_NEVER = (int) 1e9;
@@ -108,7 +109,7 @@ static Campaign* current_campaign = 0;
Campaign::Campaign(int id, const char* n)
: campaign_id(id), name(n), mission_id(-1), mission(0), net_mission(0),
- scripted(false), sequential(false), time(0), startTime(0), loadTime(0),
+ scripted(false), sequential(false), time(0), load_time(0),
player_group(0), player_unit(0), status(CAMPAIGN_INIT), lockout(0),
loaded_from_savegame(false)
{
@@ -118,7 +119,7 @@ Campaign::Campaign(int id, const char* n)
Campaign::Campaign(int id, const char* n, const char* p)
: campaign_id(id), name(n), mission_id(-1), mission(0), net_mission(0),
- scripted(false), sequential(false), time(0), startTime(0), loadTime(0),
+ scripted(false), sequential(false), time(0), load_time(0),
player_group(0), player_unit(0), status(CAMPAIGN_INIT), lockout(0),
loaded_from_savegame(false)
{
@@ -316,8 +317,6 @@ Campaign::Clear()
player_group = 0;
player_unit = 0;
-
- updateTime = time;
}
// +--------------------------------------------------------------------+
@@ -408,11 +407,10 @@ Campaign::Unload()
{
SetStatus(CAMPAIGN_INIT);
+ starshatter::engine::SetOperationStart();
+ starshatter::engine::SetMissionStart();
Clock::GetInstance()->ResetGameTime();
- StarSystem::SetBaseTime(0);
- startTime = Stardate();
- loadTime = startTime;
lockout = 0;
for (int i = 0; i < NUM_IMAGES; i++)
@@ -1849,7 +1847,7 @@ Campaign::SetMissionId(int id)
long double
Campaign::Stardate()
{
- return StarSystem::Stardate();
+ return starshatter::engine::OperationTime();
}
// +--------------------------------------------------------------------+
@@ -1882,7 +1880,9 @@ Campaign::Prep()
LoadCampaign(loader, true);
}
- StarSystem::SetBaseTime(loadTime);
+ starshatter::engine::SetOperationStart();
+ starshatter::engine::SetMissionStart();
+ Clock::GetInstance()->ResetGameTime(load_time);
// load scripted missions:
if (IsScripted() && actions.isEmpty()) {
@@ -1917,7 +1917,7 @@ Campaign::ExecFrame()
if (InCutscene())
return;
- time = Stardate() - startTime;
+ time = Stardate();
if (status < CAMPAIGN_ACTIVE)
return;
@@ -1936,12 +1936,10 @@ Campaign::ExecFrame()
::Print("Campaign::ExecFrame() destroying mission list after completion...\n");
missions.destroy();
- if (!player_group || player_group->IsFighterGroup())
- time += 10 * 3600;
- else
- time += 20 * 3600;
-
- StarSystem::SetBaseTime(startTime + time - Clock::GetInstance()->GameTime()/1000.0);
+ const auto factor = (!player_group || player_group->IsFighterGroup()) ? 10.0 : 20.0;
+ Clock::GetInstance()->ResetGameTime(starshatter::engine::OperationTime() + 3600.0 * factor);
+ starshatter::engine::SetMissionStart();
+ time = Stardate();
}
else {
m.reset();
@@ -2043,20 +2041,10 @@ Campaign::StartMission()
::Print("\n\nCampaign Start Mission - %d. '%s'\n", m->Identity(), m->Name());
if (!scripted) {
- long double gtime = (long double) Clock::GetInstance()->GameTime() / 1000.0;
- long double base = startTime + m->Start() - 15 - gtime;
-
- StarSystem::SetBaseTime(base);
-
- long double current_time = Stardate() - startTime;
-
- char buffer[32];
- FormatDayTime(buffer, current_time);
- ::Print(" current time: %s\n", buffer);
-
- FormatDayTime(buffer, m->Start());
- ::Print(" mission start: %s\n", buffer);
- ::Print("\n");
+ const auto now = starshatter::engine::OperationTime().Format();
+ const auto mission_start = starshatter::engine::Stardate{m->Start()}.Format();
+ ::Print(" current time: %s\n", now.data());
+ ::Print(" mission start: %s\n", mission_start.data());
}
}
}
@@ -2070,14 +2058,10 @@ Campaign::RollbackMission()
if (m) {
if (!scripted) {
- long double gtime = (long double) Clock::GetInstance()->GameTime() / 1000.0;
- long double base = startTime + m->Start() - 60 - gtime;
-
- StarSystem::SetBaseTime(base);
-
- long double current_time = Stardate() - startTime;
- ::Print(" mission start: %d\n", m->Start());
- ::Print(" current time: %d\n", (int) current_time);
+ const auto now = starshatter::engine::OperationTime().Format();
+ const auto mission_start = starshatter::engine::Stardate{m->Start()}.Format();
+ ::Print(" current time: %s\n", now.data());
+ ::Print(" mission start: %s\n", mission_start.data());
}
m->SetActive(false);
@@ -2085,6 +2069,20 @@ Campaign::RollbackMission()
}
}
+
+long double
+Campaign::LoadTime() const
+{
+ return load_time;
+}
+
+
+void
+Campaign::SetLoadTime(long double value)
+{
+ load_time = value;
+}
+
// +--------------------------------------------------------------------+
bool
@@ -2229,22 +2227,6 @@ Campaign::FindStrikeTarget(int iff, CombatGroup* strike_group)
// +--------------------------------------------------------------------+
-void
-Campaign::CommitExpiredActions()
-{
- ListIter<CombatAction> iter = actions;
- while (++iter) {
- CombatAction* a = iter.value();
-
- if (a->IsAvailable())
- a->SetStatus(CombatAction::COMPLETE);
- }
-
- updateTime = time;
-}
-
-// +--------------------------------------------------------------------+
-
int
Campaign::GetPlayerTeamScore()
{
diff --git a/StarsEx/Campaign.h b/StarsEx/Campaign.h
index c9bc534..8b38c51 100644
--- a/StarsEx/Campaign.h
+++ b/StarsEx/Campaign.h
@@ -130,7 +130,6 @@ public:
virtual void Unload();
virtual void Clear();
- virtual void CommitExpiredActions();
virtual void LockoutEvents(int seconds);
virtual void CheckPlayerGroup();
void CreatePlanners();
@@ -190,12 +189,8 @@ public:
int GetMissionId() const { return mission_id; }
Bitmap* GetImage(int n) { return &image[n]; }
long double GetTime() const { return time; }
- long double GetStartTime() const { return startTime; }
- void SetStartTime(long double t) { startTime = t; }
- long double GetLoadTime() const { return loadTime; }
- void SetLoadTime(long double t) { loadTime = t; }
- long double GetUpdateTime() const { return updateTime; }
- void SetUpdateTime(long double t) { updateTime = t; }
+ long double LoadTime() const;
+ void SetLoadTime(long double value);
bool InCutscene() const;
bool IsDynamic() const;
@@ -272,9 +267,7 @@ protected:
Mission* net_mission;
long double time;
- long double loadTime;
- long double startTime;
- long double updateTime;
+ long double load_time;
int lockout;
};
diff --git a/StarsEx/CampaignSaveGame.cpp b/StarsEx/CampaignSaveGame.cpp
index b959f01..62f8438 100644
--- a/StarsEx/CampaignSaveGame.cpp
+++ b/StarsEx/CampaignSaveGame.cpp
@@ -13,22 +13,24 @@
*/
#include "CampaignSaveGame.h"
+
#include "Campaign.h"
-#include "Combatant.h"
+#include "Clock.h"
#include "CombatAction.h"
+#include "Combatant.h"
#include "CombatEvent.h"
#include "CombatGroup.h"
#include "CombatUnit.h"
#include "CombatZone.h"
+#include "DataLoader.h"
+#include "FormatUtil.h"
#include "Galaxy.h"
-#include "Mission.h"
-#include "StarSystem.h"
-#include "Player.h"
-
#include "Game.h"
-#include "DataLoader.h"
+#include "Mission.h"
#include "ParseUtil.h"
-#include "FormatUtil.h"
+#include "Player.h"
+#include "Stardate.h"
+#include "StarSystem.h"
static const char* SAVE_DIR = "SaveGame";
@@ -190,8 +192,8 @@ CampaignSaveGame::Load(const char* filename)
int grp_type = 0;
int grp_id = 0;
int status = 0;
- double baseTime = 0;
- double time = 0;
+ long double baseTime = 0;
+ long double time = 0;
Text unit;
Text sitrep;
Text orders;
@@ -470,8 +472,7 @@ CampaignSaveGame::Load(const char* filename)
campaign->SetStatus(status);
if (sitrep.length()) campaign->SetSituation(sitrep);
if (orders.length()) campaign->SetOrders(orders);
- campaign->SetStartTime(baseTime);
- campaign->SetLoadTime(baseTime + time);
+ campaign->SetLoadTime(time);
campaign->LockoutEvents(3600);
campaign->Start();
@@ -567,9 +568,6 @@ CampaignSaveGame::Save(const char* name)
fopen_s(&f, s, "wb");
if (f) {
- char timestr[32];
- FormatDayTime(timestr, campaign->GetTime());
-
CombatGroup* player_group = campaign->GetPlayerGroup();
CombatUnit* player_unit = campaign->GetPlayerUnit();
@@ -582,10 +580,10 @@ CampaignSaveGame::Save(const char* name)
fprintf(f, "unit: \"%s\"\n", player_unit->Name().data());
fprintf(f, "status: %d\n", (int) campaign->GetStatus());
- fprintf(f, "basetime: %Lf\n", campaign->GetStartTime());
- fprintf(f, "time: %Lf // %s\n\n",
- campaign->GetTime(),
- timestr);
+ fprintf(f, "basetime: %.1Lf\n", starshatter::engine::OperationStart());
+ const auto operation_time = starshatter::engine::OperationTime();
+ const auto formatted_time = operation_time.Format();
+ fprintf(f, "time: %.1Lf // %s\n\n", operation_time.value, formatted_time.data());
fprintf(f, "sitrep: \"%s\"\n", campaign->Situation());
fprintf(f, "orders: \"%s\"\n\n", campaign->Orders());
diff --git a/StarsEx/Clock.cpp b/StarsEx/Clock.cpp
index 60e6f67..252cc69 100644
--- a/StarsEx/Clock.cpp
+++ b/StarsEx/Clock.cpp
@@ -80,9 +80,10 @@ Clock::Step()
void
-Clock::ResetGameTime()
+Clock::ResetGameTime(double seconds)
{
- m_game_elapsed = inner_clock::duration::zero();
+ const std::chrono::duration<double> target {seconds};
+ m_game_elapsed = std::chrono::duration_cast<inner_clock::duration>(target);
}
diff --git a/StarsEx/Clock.h b/StarsEx/Clock.h
index 40b5262..08e5005 100644
--- a/StarsEx/Clock.h
+++ b/StarsEx/Clock.h
@@ -22,7 +22,7 @@ public:
void Set();
double Step();
- void ResetGameTime();
+ void ResetGameTime(double seconds={});
void SkipGameTime(double seconds);
double Delta() const;
diff --git a/StarsEx/CmdIntelDlg.cpp b/StarsEx/CmdIntelDlg.cpp
index fb0c83b..f7ed247 100644
--- a/StarsEx/CmdIntelDlg.cpp
+++ b/StarsEx/CmdIntelDlg.cpp
@@ -49,15 +49,11 @@ DEF_MAP_CLIENT(CmdIntelDlg, OnPlay);
CmdIntelDlg::CmdIntelDlg(Screen* s, FormDef& def, CmpnScreen* mgr)
: FormWindow(s, 0, 0, s->Width(), s->Height()), CmdDlg(mgr), manager(mgr),
- stars(0), campaign(0), update_time(0), start_scene(0),
+ stars(0), campaign(0), start_scene(0),
cam_view(0), dsp_view(0)
{
stars = Starshatter::GetInstance();
campaign = Campaign::GetCampaign();
-
- if (campaign)
- update_time = campaign->GetUpdateTime();
-
Init(def);
}
@@ -140,15 +136,12 @@ CmdIntelDlg::ExecFrame()
{
CmdDlg::ExecFrame();
- if (campaign != Campaign::GetCampaign() || campaign->GetUpdateTime() != update_time) {
- campaign = Campaign::GetCampaign();
- update_time = campaign->GetUpdateTime();
-
+ if (campaign != Campaign::GetCampaign()) {
+ campaign = Campaign::GetCampaign();
lst_news->ClearItems();
txt_news->SetText("");
-
if (img_news)
- img_news->SetPicture(bmp_default);
+ img_news->SetPicture(bmp_default);
}
if (campaign) {
diff --git a/StarsEx/CmdIntelDlg.h b/StarsEx/CmdIntelDlg.h
index 8ff5fe7..98bae4f 100644
--- a/StarsEx/CmdIntelDlg.h
+++ b/StarsEx/CmdIntelDlg.h
@@ -66,7 +66,6 @@ protected:
Starshatter* stars;
Campaign* campaign;
- double update_time;
int start_scene;
Text event_scene;
};
diff --git a/StarsEx/CmpSelectDlg.cpp b/StarsEx/CmpSelectDlg.cpp
index 941c53a..028dc17 100644
--- a/StarsEx/CmpSelectDlg.cpp
+++ b/StarsEx/CmpSelectDlg.cpp
@@ -23,6 +23,7 @@
#include "CombatGroup.h"
#include "ShipDesign.h"
#include "Player.h"
+#include "Stardate.h"
#include "Clock.h"
#include "ContentBundle.h"
@@ -147,14 +148,9 @@ CmpSelectDlg::ExecFrame()
campaign->Description());
}
else {
- char time_buf[32];
char score_buf[32];
-
- double t = campaign->GetLoadTime() - campaign->GetStartTime();
- FormatDayTime(time_buf, t);
-
+ const auto load_time = starshatter::engine::Stardate{campaign->LoadTime()}.Format();
sprintf_s(score_buf, "%d", campaign->GetPlayerTeamScore());
-
Text desc = Text("<font Limerick12><color ffffff>") +
campaign->Name() +
Text("<font Verdana>\n\n") +
@@ -165,7 +161,7 @@ CmpSelectDlg::ExecFrame()
Text("\n\n<color ffff80>") +
ContentBundle::GetInstance()->GetText("CmpSelectDlg.campaign-time") +
Text("<color ffffff>\n\t") +
- time_buf +
+ load_time +
Text("\n\n<color ffff80>") +
ContentBundle::GetInstance()->GetText("CmpSelectDlg.assignment") +
Text("<color ffffff>\n\t");
diff --git a/StarsEx/Mission.cpp b/StarsEx/Mission.cpp
index 2350a8d..f794335 100644
--- a/StarsEx/Mission.cpp
+++ b/StarsEx/Mission.cpp
@@ -1409,6 +1409,8 @@ Mission::Serialize(const char* player_elem, int player_index)
s += "\"\n\n";
}
+ s += Text::format("stardate: %.1Lf\n", Stardate());
+
char buffer[256];
FormatTime(buffer, Start());
diff --git a/StarsEx/Mission.h b/StarsEx/Mission.h
index 5bcffa7..0b8c0a6 100644
--- a/StarsEx/Mission.h
+++ b/StarsEx/Mission.h
@@ -104,7 +104,7 @@ public:
const char* Objective() const { return objective; }
const char* Subtitles() const;
int Start() const { return start; }
- double Stardate() const { return stardate; }
+ long double Stardate() const { return stardate; }
int Type() const { return type; }
const char* TypeName() const { return RoleName(type); }
int Team() const { return team; }
@@ -174,7 +174,7 @@ protected:
int type;
int team;
int start;
- double stardate;
+ long double stardate;
bool ok;
bool active;
bool complete;
diff --git a/StarsEx/MsnSelectDlg.cpp b/StarsEx/MsnSelectDlg.cpp
index 8c720c8..1f61d9a 100644
--- a/StarsEx/MsnSelectDlg.cpp
+++ b/StarsEx/MsnSelectDlg.cpp
@@ -12,25 +12,27 @@
*/
#include "MsnSelectDlg.h"
-#include "MsnEditDlg.h"
-#include "MsnEditNavDlg.h"
-#include "ConfirmDlg.h"
-#include "MenuScreen.h"
-#include "Starshatter.h"
-#include "Campaign.h"
-#include "Mission.h"
-#include "Game.h"
-#include "ContentBundle.h"
#include "Button.h"
+#include "Campaign.h"
+#include "Clock.h"
#include "ComboBox.h"
-#include "ListBox.h"
-#include "Slider.h"
-#include "Video.h"
+#include "ConfirmDlg.h"
+#include "ContentBundle.h"
+#include "FormatUtil.h"
+#include "Game.h"
#include "Keyboard.h"
+#include "ListBox.h"
+#include "MenuScreen.h"
+#include "Mission.h"
#include "Mouse.h"
+#include "MsnEditDlg.h"
+#include "MsnEditNavDlg.h"
#include "ParseUtil.h"
-#include "FormatUtil.h"
+#include "Slider.h"
+#include "Stardate.h"
+#include "Starshatter.h"
+#include "Video.h"
// +--------------------------------------------------------------------+
// DECLARE MAPPING FUNCTIONS:
@@ -393,6 +395,9 @@ MsnSelectDlg::OnNew(AWEvent* event)
navdlg->SetMission(info->mission);
navdlg->SetMissionInfo(info);
}
+ starshatter::engine::SetOperationStart(info->mission->Stardate());
+ starshatter::engine::SetMissionStart(info->mission->Start());
+ Clock::GetInstance()->ResetGameTime();
}
void
@@ -418,6 +423,9 @@ MsnSelectDlg::OnEdit(AWEvent* event)
editor->SetMissionInfo(c->GetMissionInfo(mission_id));
editor->SetMission(m);
+ starshatter::engine::SetOperationStart(m->Stardate());
+ starshatter::engine::SetMissionStart(m->Start());
+ Clock::GetInstance()->ResetGameTime();
manager->ShowMsnEditDlg();
}
}
@@ -479,11 +487,13 @@ MsnSelectDlg::OnAccept(AWEvent* event)
{
if (selected_mission >= 0) {
Mouse::Show(false);
-
- int id = campaign->GetMissionList()[selected_mission]->id;
+ const auto id = campaign->GetMissionList()[selected_mission]->id;
campaign->SetMissionId(id);
campaign->ReloadMission(id);
-
+ const auto* mission = campaign->GetMission();
+ starshatter::engine::SetOperationStart(mission->Stardate());
+ starshatter::engine::SetMissionStart(mission->Start());
+ Clock::GetInstance()->ResetGameTime();
stars->SetGameMode(Game::PREP_MODE);
}
}
diff --git a/StarsEx/NetUnitDlg.cpp b/StarsEx/NetUnitDlg.cpp
index 26b2af7..d9d7144 100644
--- a/StarsEx/NetUnitDlg.cpp
+++ b/StarsEx/NetUnitDlg.cpp
@@ -12,27 +12,27 @@
*/
#include "NetUnitDlg.h"
-#include "NetClientConfig.h"
+
+#include "Campaign.h"
+#include "Campaign.h"
+#include "Clock.h"
#include "ConfirmDlg.h"
+#include "ContentBundle.h"
+#include "Keyboard.h"
#include "MenuScreen.h"
-#include "Starshatter.h"
-#include "Campaign.h"
#include "Mission.h"
-#include "Ship.h"
-#include "Player.h"
-#include "Campaign.h"
-#include "ShipDesign.h"
-
#include "NetAddr.h"
+#include "NetChat.h"
+#include "NetClientConfig.h"
#include "NetLobbyClient.h"
#include "NetLobbyServer.h"
#include "NetUser.h"
-#include "NetChat.h"
-
-#include "ContentBundle.h"
+#include "Player.h"
+#include "ShipDesign.h"
+#include "Ship.h"
+#include "Stardate.h"
+#include "Starshatter.h"
#include "Video.h"
-#include "Keyboard.h"
-#include "Clock.h"
// +--------------------------------------------------------------------+
// DECLARE MAPPING FUNCTIONS:
@@ -619,6 +619,9 @@ NetUnitDlg::OnApply(AWEvent* event)
Mission* mission = net_lobby->GetSelectedMission();
if (mission) {
+ starshatter::engine::SetOperationStart(mission->Stardate());
+ starshatter::engine::SetMissionStart(mission->Start());
+ Clock::GetInstance()->ResetGameTime();
net_lobby->GameStart();
ok = true;
}
diff --git a/StarsEx/Player.cpp b/StarsEx/Player.cpp
index fffa9a6..091c808 100644
--- a/StarsEx/Player.cpp
+++ b/StarsEx/Player.cpp
@@ -635,19 +635,17 @@ Player::CommandRankRequired(int ship_class)
// +-------------------------------------------------------------------+
int
-Player::GetMissionPoints(ShipStats* s, std::uint32_t start_time)
+Player::GetMissionPoints(ShipStats* s, std::int_fast32_t flight_time_)
{
int result = 0;
if (s) {
result = s->GetPoints();
- int flight_time = (Clock::GetInstance()->GameTime() - start_time) / 1000;
-
// if player survived mission, award one experience point
// for each minute of action, in ten point blocks:
if (!s->GetDeaths() && !s->GetColls()) {
- int minutes = flight_time / 60;
+ int minutes = flight_time_ / 60;
minutes /= 10;
minutes *= 10;
result += minutes;
@@ -669,12 +667,12 @@ Player::GetMissionPoints(ShipStats* s, std::uint32_t start_time)
// +-------------------------------------------------------------------+
void
-Player::ProcessStats(ShipStats* s, std::uint32_t start_time)
+Player::ProcessStats(ShipStats* s, std::int_fast32_t flight_time_)
{
if (!s) return;
int old_rank = Rank();
- int pts = GetMissionPoints(s, start_time);
+ int pts = GetMissionPoints(s, flight_time_);
AddPoints(pts);
AddPoints(s->GetCommandPoints());
@@ -683,7 +681,7 @@ Player::ProcessStats(ShipStats* s, std::uint32_t start_time)
AddLosses(s->GetDeaths());
AddLosses(s->GetColls());
AddMissions(1);
- AddFlightTime((Clock::GetInstance()->GameTime() - start_time) / 1000);
+ AddFlightTime(flight_time_);
int rank = Rank();
diff --git a/StarsEx/Player.h b/StarsEx/Player.h
index c0a9b6c..62e8700 100644
--- a/StarsEx/Player.h
+++ b/StarsEx/Player.h
@@ -116,8 +116,8 @@ public:
Text EncodeStats();
void DecodeStats(const char* stats);
- int GetMissionPoints(ShipStats* stats, std::uint32_t start_time);
- void ProcessStats(ShipStats* stats, std::uint32_t start_time);
+ int GetMissionPoints(ShipStats* stats, std::int_fast32_t flight_time_);
+ void ProcessStats(ShipStats* stats, std::int_fast32_t flight_time_);
bool EarnedAward(AwardInfo* a, ShipStats* s);
static const char* RankName(int rank);
diff --git a/StarsEx/Sim.cpp b/StarsEx/Sim.cpp
index bdf843b..f938b7a 100644
--- a/StarsEx/Sim.cpp
+++ b/StarsEx/Sim.cpp
@@ -71,6 +71,7 @@
#include "Solid.h"
#include "Sound.h"
#include "Sprite.h"
+#include "Stardate.h"
#include "Starshatter.h"
#include "StarSystem.h"
#include "Terrain.h"
@@ -122,8 +123,7 @@ Sim* Sim::sim = 0;
Sim::Sim(MotionController* c)
: ctrl(c), test_mode(false), grid_shown(false), dust(0),
- star_system(0), active_region(0), mission(0), netgame(0),
- start_time(0)
+ star_system(0), active_region(0), mission(0), netgame(0)
{
Drive::Initialize();
Explosion::Initialize();
@@ -206,7 +206,7 @@ Sim::CommitMission()
if (s->IsPlayer()) {
Player* p = Player::GetCurrentPlayer();
- p->ProcessStats(s, start_time);
+ p->ProcessStats(s, starshatter::engine::MissionTime());
if (mission && mission->Type() == Mission::TRAINING &&
s->GetDeaths() == 0 && s->GetColls() == 0)
@@ -368,8 +368,10 @@ Sim::ExecMission()
if (cam_dir)
cam_dir->Reset();
- if (mission->Stardate() > 0)
- StarSystem::SetBaseTime(mission->Stardate(), true);
+ if (mission->Stardate() > 0.0l)
+ starshatter::engine::SetOperationStart(mission->Stardate());
+ starshatter::engine::SetMissionStart(mission->Start());
+ Clock::GetInstance()->ResetGameTime();
star_system = mission->GetStarSystem();
star_system->Activate(scene);
@@ -395,7 +397,6 @@ Sim::ExecMission()
}
first_frame = true;
- start_time = Clock::GetInstance()->GameTime();
AudioConfig::SetTraining(mission->Type() == Mission::TRAINING);
}
@@ -1896,7 +1897,7 @@ Sim::ProcessEventTrigger(int type, int event_id, const char* ship, int param)
double
Sim::MissionClock() const
{
- return (Clock::GetInstance()->GameTime() - start_time) / 1000.0;
+ return starshatter::engine::MissionTime();
}
// +--------------------------------------------------------------------+
@@ -1931,7 +1932,7 @@ Sim::SkipCutscene()
}
}
- double skip_time = end_time - MissionClock();
+ const auto skip_time = end_time - MissionClock();
if (skip_time > 0) {
Clock::GetInstance()->SkipGameTime(skip_time);
}
diff --git a/StarsEx/StarSystem.cpp b/StarsEx/StarSystem.cpp
index b8340f6..6641b63 100644
--- a/StarsEx/StarSystem.cpp
+++ b/StarsEx/StarSystem.cpp
@@ -12,71 +12,31 @@
*/
#include "StarSystem.h"
-#include "Galaxy.h"
-#include "Sky.h"
-#include "Starshatter.h"
-#include "TerrainRegion.h"
-#include "TerrainHaze.h"
-#include "Weather.h"
+#include "Bitmap.h"
+#include "Clock.h"
+#include "DataLoader.h"
+#include "Galaxy.h"
#include "Game.h"
#include "GameWinDX9.h"
-#include "Clock.h"
-#include "Sound.h"
-#include "Solid.h"
#include "Light.h"
-#include "Bitmap.h"
-#include "DataLoader.h"
-#include "Scene.h"
#include "ParseUtil.h"
+#include "Scene.h"
+#include "Sky.h"
+#include "Solid.h"
+#include "Sound.h"
+#include "Stardate.h"
+#include "Starshatter.h"
+#include "TerrainHaze.h"
+#include "TerrainRegion.h"
#include "Video.h"
-
-const long double epoch = 0.5e9;
-long double StarSystem::stardate = 0;
+#include "Weather.h"
// +====================================================================+
-static long double base_time = 0;
static WORD oldcw = 0;
static WORD fpcw = 0;
-void StarSystem::SetBaseTime(long double t, bool absolute)
-{
- if (absolute) {
- base_time = t;
- CalcStardate();
- }
-
- else if (t > 0) {
- if (t > epoch) t -= epoch;
- base_time = t;
- CalcStardate();
- }
-}
-
-long double StarSystem::GetBaseTime()
-{
- return base_time;
-}
-
-void StarSystem::CalcStardate()
-{
- if (base_time < 1) {
- time_t clock_seconds;
- time(&clock_seconds);
-
- base_time = clock_seconds;
-
- while (base_time < 0)
- base_time += epoch;
- }
-
- long double gtime = Clock::GetInstance()->GameTime<long double>() / 1000.0;
- long double sdate = gtime + base_time + epoch;
-
- stardate = sdate;
-}
-
static const double GRAV = 6.673e-11;
static const int NAMELEN = 64;
@@ -119,7 +79,6 @@ static OrbitalBody* primary_moon = 0;
void
StarSystem::Load()
{
- CalcStardate();
active_region = 0;
BYTE* block = 0;
@@ -1386,8 +1345,6 @@ static BYTE min3(BYTE a, BYTE b, BYTE c)
void
StarSystem::ExecFrame()
{
- CalcStardate();
-
ListIter<OrbitalBody> star = bodies;
while (++star)
star->Update();
@@ -1843,7 +1800,7 @@ Orbital::Update()
double grade = (retro) ? -1 : 1;
// orbits are counter clockwise:
- phase = -2 * PI * grade * StarSystem::Stardate() / period;
+ phase = PI * -2.0 * grade * starshatter::engine::CurrentTime() / period;
loc = primary->Location() + Point((double) (orbit * cos(phase)),
(double) (orbit * sin(phase)),
@@ -1871,7 +1828,7 @@ Orbital::PredictLocation(double delta_t)
double grade = (retro) ? -1 : 1;
// orbits are(?) counter clockwise:
- double predicted_phase = (double) (-2 * PI * grade * (StarSystem::Stardate()+delta_t) / period);
+ const auto predicted_phase = PI * -2.0 * grade * (starshatter::engine::CurrentTime() + delta_t) / period;
predicted_loc += Point((double) (orbit * cos(predicted_phase)),
(double) (orbit * sin(predicted_phase)),
@@ -1917,7 +1874,7 @@ OrbitalBody::Update()
theta = 0;
if (rotation > 0)
- theta = -2 * PI * StarSystem::Stardate() / rotation;
+ theta = PI * -2.0 * starshatter::engine::CurrentTime() / rotation;
ListIter<OrbitalBody> body = satellites;
while (++body)
diff --git a/StarsEx/StarSystem.h b/StarsEx/StarSystem.h
index bdd37ec..6770f4a 100644
--- a/StarsEx/StarSystem.h
+++ b/StarsEx/StarSystem.h
@@ -78,10 +78,6 @@ public:
void SetActiveRegion(OrbitalRegion* rgn);
- static void SetBaseTime(long double t, bool absolute=false);
- static long double GetBaseTime();
- static long double Stardate() { return stardate; }
- static void CalcStardate();
double Radius() const { return radius; }
void SetSunlight(Color color, double brightness=1);
@@ -109,7 +105,6 @@ protected:
int affiliation;
int seq;
Point loc;
- static long double stardate;
double radius;
bool instantiated;
diff --git a/StarsEx/Stardate.cpp b/StarsEx/Stardate.cpp
new file mode 100644
index 0000000..f57205a
--- /dev/null
+++ b/StarsEx/Stardate.cpp
@@ -0,0 +1,137 @@
+/* Starshatter: The Open Source Project
+ Copyright (c) 2021-2024, Starshatter: The Open Source Project Contributors
+ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
+ Copyright (c) 1997-2006, Destroyer Studios LLC.
+*/
+
+#include "Stardate.h"
+
+#include <cstdint>
+
+#include <Text.h>
+
+#include "Clock.h"
+
+
+namespace starshatter
+{
+namespace engine
+{
+
+
+static constexpr long double EPOCH {0.5e9l};
+static constexpr long double MINUTE {60};
+static constexpr long double HOUR {60 * MINUTE};
+static constexpr long double DAY {24 * HOUR};
+static long double operation_start {};
+static long double mission_start {};
+
+
+Stardate::Stardate() :
+ value {0}
+{
+}
+
+
+Stardate::Stardate(long double value_) :
+ value {value_}
+{
+}
+
+
+Stardate::operator long double() const
+{
+ return value;
+}
+
+
+Text
+Stardate::Format(bool short_format) const
+{
+ auto time = value;
+ std::int_fast32_t day = 1, hours = 0, minutes = 0, seconds = 0;
+ while (time >= DAY) {
+ time -= DAY;
+ ++day;
+ }
+ while (time >= HOUR) {
+ time -= HOUR;
+ ++hours;
+ }
+ while (time >= MINUTE) {
+ time -= MINUTE;
+ ++minutes;
+ }
+ seconds = time;
+ return Text::format(
+ short_format ? "%02d/%02d:%02d:%02d" : "Day %d, %02d:%02d:%02d",
+ day, hours, minutes, seconds);
+}
+
+
+Stardate
+CurrentTime()
+{
+ return Epoch() + OperationStart() + OperationTime();
+}
+
+
+Stardate
+OperationTime()
+{
+ return MissionStart() + MissionTime();
+}
+
+
+Stardate
+MissionTime()
+{
+ if (const auto* clock = Clock::GetInstance())
+ return clock->GameTime<long double>() / 1000.0l;
+ throw "game clock not initialized";
+}
+
+
+long double
+Epoch()
+{
+ return EPOCH;
+}
+
+
+long double
+OperationStart()
+{
+ return operation_start;
+}
+
+
+long double
+MissionStart()
+{
+ return mission_start;
+}
+
+
+void
+SetOperationStart(long double value, bool relative)
+{
+ if (relative)
+ operation_start += value;
+ else
+ operation_start = value;
+}
+
+
+void
+SetMissionStart(long double value, bool relative)
+{
+ if (relative)
+ mission_start += value;
+ else
+ mission_start = value;
+}
+
+
+} // namespace engine
+} // namespace starshatter
diff --git a/StarsEx/Stardate.h b/StarsEx/Stardate.h
new file mode 100644
index 0000000..cc696c8
--- /dev/null
+++ b/StarsEx/Stardate.h
@@ -0,0 +1,43 @@
+/* Starshatter: The Open Source Project
+ Copyright (c) 2021-2024, Starshatter: The Open Source Project Contributors
+ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
+ Copyright (c) 1997-2006, Destroyer Studios LLC.
+*/
+
+#pragma once
+
+#include <Text.h>
+
+
+namespace starshatter
+{
+namespace engine
+{
+
+
+struct Stardate
+{
+ long double value = {};
+
+ Stardate();
+ Stardate(long double value_);
+
+ operator long double() const;
+
+ Text Format(bool short_format=false) const;
+};
+
+
+Stardate CurrentTime();
+Stardate OperationTime();
+Stardate MissionTime();
+
+long double Epoch();
+long double OperationStart();
+long double MissionStart();
+void SetOperationStart(long double value={}, bool relative=false);
+void SetMissionStart(long double value={}, bool relative=false);
+
+
+} // namespace engine
+} // namespace starshatter
diff --git a/StarsEx/Starshatter.cpp b/StarsEx/Starshatter.cpp
index 7663148..1a373cc 100644
--- a/StarsEx/Starshatter.cpp
+++ b/StarsEx/Starshatter.cpp
@@ -7,7 +7,6 @@
*/
-
#include "Starshatter.h"
#include "MenuScreen.h"
@@ -108,6 +107,7 @@
#include "Universe.h"
#include "Video.h"
#include "VideoSettings.h"
+#include "Stardate.h"
// +--------------------------------------------------------------------+
@@ -121,7 +121,9 @@ Starshatter* Starshatter::instance {nullptr};
static Mission* current_mission = 0;
static Mission* cutscene_mission = 0;
-static double cutscene_basetime = 0;
+static long double cutscene_operation_start = 0;
+static long double cutscene_mission_start = 0;
+static double cutscene_game_time = 0;
static int cut_efx_volume = 100;
static int cut_wrn_volume = 100;
static double time_til_change = 0;
@@ -592,7 +594,7 @@ Starshatter::SetGameMode(int m)
Clock::GetInstance()->SetTimeCompression(1.0);
Pause(false);
- Print(" Stardate: %.1Lf\n", StarSystem::GetBaseTime());
+ Print(" Stardate: %.1Lf\n", starshatter::engine::CurrentTime().value);
}
else if (m == PLAN_MODE) {
@@ -603,7 +605,7 @@ Starshatter::SetGameMode(int m)
StopNetGame();
Pause(true);
- Print(" Stardate: %.1Lf\n", StarSystem::GetBaseTime());
+ Print(" Stardate: %.1Lf\n", starshatter::engine::CurrentTime().value);
}
}
@@ -630,7 +632,7 @@ Starshatter::SetGameMode(int m)
StopNetGame();
}
- Print(" Stardate: %.1Lf\n", StarSystem::GetBaseTime());
+ Print(" Stardate: %.1Lf\n", starshatter::engine::CurrentTime().value);
Print(" Bitmap Cache Footprint: %d KB\n", Bitmap::CacheMemoryFootprint() / 1024);
paused = true;
@@ -1600,11 +1602,11 @@ Starshatter::DoGameKeys()
/*** For Debug Convenience Only: ***/
else if (KeyDown(KEY_INC_STARDATE)) {
- StarSystem::SetBaseTime(StarSystem::GetBaseTime() + 600, true);
+ starshatter::engine::SetOperationStart(300.0, true);
}
else if (KeyDown(KEY_DEC_STARDATE)) {
- StarSystem::SetBaseTime(StarSystem::GetBaseTime() - 600, true);
+ starshatter::engine::SetOperationStart(-300.0, true);
}
/***/
}
@@ -2556,7 +2558,9 @@ Starshatter::ExecCutscene(const char* msn_file, const char* path)
CreateWorld();
cutscene_mission = new Mission(0);
- cutscene_basetime = StarSystem::GetBaseTime();
+ cutscene_operation_start = starshatter::engine::OperationStart();
+ cutscene_mission_start = starshatter::engine::MissionStart();
+ cutscene_game_time = Clock::GetInstance()->GameTime<double>() / 1000.0;
if (cutscene_mission->Load(msn_file, path)) {
Sim* sim = (Sim*) world;
@@ -2582,7 +2586,9 @@ Starshatter::ExecCutscene(const char* msn_file, const char* path)
else {
delete cutscene_mission;
cutscene_mission = 0;
- cutscene_basetime = 0;
+ cutscene_operation_start = 0;
+ cutscene_mission_start = 0;
+ cutscene_game_time = 0;
}
}
@@ -2659,15 +2665,14 @@ Starshatter::EndMission()
if (sim && sim->GetMission() == cutscene_mission) {
ShipStats::Initialize();
sim->UnloadMission();
-
- // restore world clock (true => absolute time reference)
- if (cutscene_basetime != 0)
- StarSystem::SetBaseTime(cutscene_basetime, true);
-
+ starshatter::engine::SetOperationStart(cutscene_operation_start);
+ starshatter::engine::SetMissionStart(cutscene_mission_start);
+ Clock::GetInstance()->ResetGameTime(cutscene_game_time);
delete cutscene_mission;
- cutscene_mission = 0;
- cutscene_basetime = 0;
-
+ cutscene_mission = nullptr;
+ cutscene_operation_start = 0;
+ cutscene_mission_start = 0;
+ cutscene_game_time = 0;
return;
}
}
diff --git a/StarsEx/Weather.cpp b/StarsEx/Weather.cpp
index 8d3ded6..ffbdaff 100644
--- a/StarsEx/Weather.cpp
+++ b/StarsEx/Weather.cpp
@@ -12,9 +12,9 @@
*/
#include "Weather.h"
-#include "StarSystem.h"
-#include "Game.h"
+
#include "ContentBundle.h"
+#include "Stardate.h"
// +--------------------------------------------------------------------+
@@ -94,7 +94,7 @@ Weather::Update()
{
NormalizeChances();
- double weather = (sin(StarSystem::Stardate() * 2 * PI / period)+1)/2;
+ const auto weather = (sin(starshatter::engine::CurrentTime() * 2.0 * PI / period) + 1.0) / 2.0;
state = active_states[0];
diff --git a/StarsEx/test/Stardate.cpp b/StarsEx/test/Stardate.cpp
new file mode 100644
index 0000000..fb95562
--- /dev/null
+++ b/StarsEx/test/Stardate.cpp
@@ -0,0 +1,60 @@
+#include <gtest/gtest.h>
+
+#include <Clock.h>
+#include <Stardate.h>
+
+namespace ng = starshatter::engine;
+
+
+TEST(StarsEx, MissionTimeIsGameTime)
+{
+ ASSERT_TRUE(Clock::Init());
+ auto* clock = Clock::GetInstance();
+ EXPECT_NEAR(0.0l, ng::MissionTime(), 0.001l);
+ clock->SkipGameTime(0.05);
+ EXPECT_NEAR(0.05l, ng::MissionTime(), 0.001l);
+ clock->SkipGameTime(0.05);
+ EXPECT_NEAR(0.10l, ng::MissionTime(), 0.001l);
+ Clock::Close();
+}
+
+
+TEST(StarsEx, OperationTimeIsMissionOffset)
+{
+ ASSERT_TRUE(Clock::Init());
+ auto* clock = Clock::GetInstance();
+ EXPECT_NEAR(0.0l, ng::OperationTime(), 0.001l);
+ ng::SetMissionStart(1000.0l);
+ EXPECT_NEAR(1000.0l, ng::OperationTime(), 0.001l);
+ clock->SkipGameTime(0.05);
+ EXPECT_NEAR(1000.05l, ng::OperationTime(), 0.001l);
+ ng::SetMissionStart(1000.0l, true);
+ EXPECT_NEAR(2000.05l, ng::OperationTime(), 0.001l);
+ Clock::Close();
+}
+
+
+TEST(StarsEx, CurrentTimeIsOperationAndEpoch)
+{
+ ASSERT_TRUE(Clock::Init());
+ auto* clock = Clock::GetInstance();
+ EXPECT_NEAR(ng::Epoch(), ng::CurrentTime(), 0.001l);
+ ng::SetOperationStart(1000.0l);
+ EXPECT_NEAR(ng::Epoch() + 1000.0l, ng::CurrentTime(), 0.001l);
+ ng::SetMissionStart(500.0l);
+ EXPECT_NEAR(ng::Epoch() + 1500.0l, ng::CurrentTime(), 0.001l);
+ clock->SkipGameTime(0.05);
+ EXPECT_NEAR(ng::Epoch() + 1500.05l, ng::CurrentTime(), 0.001l);
+ ng::SetOperationStart(1000.0l, true);
+ EXPECT_NEAR(ng::Epoch() + 2500.05l, ng::CurrentTime(), 0.001l);
+ Clock::Close();
+}
+
+
+TEST(StarsEx, FormatOperationTime)
+{
+ ASSERT_TRUE(Clock::Init());
+ auto* clock = Clock::GetInstance();
+ EXPECT_EQ("Day 1, 00:00:00", ng::OperationTime().Format());
+ Clock::Close();
+}