From 3be3bfaa17773550a696ed2b756136debfe79ae2 Mon Sep 17 00:00:00 2001 From: Aki Date: Mon, 1 Apr 2024 05:16:14 +0200 Subject: 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. --- StarsEx/CMakeLists.txt | 38 ++++++------ StarsEx/Campaign.cpp | 114 +++++++++++++++-------------------- StarsEx/Campaign.h | 13 +--- StarsEx/CampaignSaveGame.cpp | 34 +++++------ StarsEx/Clock.cpp | 5 +- StarsEx/Clock.h | 2 +- StarsEx/CmdIntelDlg.cpp | 15 ++--- StarsEx/CmdIntelDlg.h | 1 - StarsEx/CmpSelectDlg.cpp | 10 +--- StarsEx/Mission.cpp | 2 + StarsEx/Mission.h | 4 +- StarsEx/MsnSelectDlg.cpp | 42 ++++++++----- StarsEx/NetUnitDlg.cpp | 29 +++++---- StarsEx/Player.cpp | 12 ++-- StarsEx/Player.h | 4 +- StarsEx/Sim.cpp | 17 +++--- StarsEx/StarSystem.cpp | 75 +++++------------------ StarsEx/StarSystem.h | 5 -- StarsEx/Stardate.cpp | 137 +++++++++++++++++++++++++++++++++++++++++++ StarsEx/Stardate.h | 43 ++++++++++++++ StarsEx/Starshatter.cpp | 39 ++++++------ StarsEx/Weather.cpp | 6 +- StarsEx/test/Stardate.cpp | 60 +++++++++++++++++++ 23 files changed, 441 insertions(+), 266 deletions(-) create mode 100644 StarsEx/Stardate.cpp create mode 100644 StarsEx/Stardate.h create mode 100644 StarsEx/test/Stardate.cpp (limited to 'StarsEx') 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 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 target {seconds}; + m_game_elapsed = std::chrono::duration_cast(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("") + campaign->Name() + Text("\n\n") + @@ -165,7 +161,7 @@ CmpSelectDlg::ExecFrame() Text("\n\n") + ContentBundle::GetInstance()->GetText("CmpSelectDlg.campaign-time") + Text("\n\t") + - time_buf + + load_time + Text("\n\n") + ContentBundle::GetInstance()->GetText("CmpSelectDlg.assignment") + Text("\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() / 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 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 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 + +#include + +#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() / 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 + + +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() / 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 + +#include +#include + +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(); +} -- cgit v1.1