summaryrefslogtreecommitdiffhomepage
path: root/StarsEx
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 /StarsEx
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.
Diffstat (limited to 'StarsEx')
-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();
+}