#pragma once #include #include #include #include #include #include #include #include "BalancingConfig.h" #include "BeltSystem.h" #include "EntityAdmin.h" #include "BuildingId.h" #include "entt/entity/entity.hpp" #include "BeamFiredEvent.h" #include "GameConfig.h" #include "Tick.h" class AiSystem; class BuildingSystem; class CombatSystem; class DynamicBodySystem; class MovementIntentSystem; class RepairSystem; class SalvagerSystem; class ShipSystem; class DebrisSystem; struct ArenaStatus { struct Entry { std::string displayName; // Level suffix shown in the widget/inspect display. Set for the HQ and // defence stations; empty for ships, which no longer have a level. std::optional level; int total; int surviving; }; struct TeamStatus { std::string name; double threatLevel = 0.0; // accumulated threat of the team's configured ships // Remaining durability of the team's ships and defence stations (HQ // excluded). currentEhp is summed live; maxEhp is the fixed full-HP // baseline. See getEhpPercentText() for the displayed value. double currentEhp = 0.0; double maxEhp = 0.0; std::vector entries; // HQ first, then ships, then stations // Remaining EHP as a whole-number percentage ("NN%"), or "n/a" when the // team has no ships or stations (maxEhp == 0). std::string getEhpPercentText() const; }; TeamStatus teams[2]; bool finished = false; std::optional winnerTeam; // 0 or 1 when finished; nullopt while running // Game time the fight has lasted (simulated ticks * fixed tick duration). // Meaningful once finished; the battle duration shown for completed runs. double durationSeconds = 0.0; }; class ArenaSimulation { public: ArenaSimulation(const GameConfig& gameConfig, ArenaConfig arenaConfig, unsigned int seed = 0); ~ArenaSimulation(); void run(); void requestStop(); void tickOnce(); std::vector drainBeamFiredEvents(); ArenaStatus getStatus() const; bool isFinished() const; std::optional getWinnerTeam() const; Tick getCurrentTick() const; const ArenaConfig& getArenaConfig() const; const BuildingSystem& getBuildings() const; const ShipSystem& getShips() const; const DebrisSystem& getDebrisSystem() const; EntityAdmin& getAdmin(); const EntityAdmin& getAdmin() const; private: BuildingId allocateBuildingId(); void placeStructures(); void spawnShips(); void computeTeamMaxEhp(); void tick(); void tickDeaths(); void updateStatus(); const GameConfig& m_gameConfig; ArenaConfig m_arenaConfig; std::mt19937 m_rng; Tick m_currentTick; BuildingId m_nextBuildingId; EntityAdmin m_admin; BeltSystem m_beltSystem; std::unique_ptr m_buildingSystem; std::unique_ptr m_shipSystem; std::unique_ptr m_aiSystem; std::unique_ptr m_movementIntentSystem; std::unique_ptr m_dynamicBodySystem; std::unique_ptr m_combatSystem; std::unique_ptr m_debrisSystem; std::unique_ptr m_salvagerSystem; std::unique_ptr m_repairSystem; entt::entity m_team1HqEntity; entt::entity m_team2HqEntity; bool m_finished; std::optional m_winnerTeam; std::atomic m_stopRequested; // Static accumulated threat per team, computed once from the configured roster. double m_teamThreat[2] = {0.0, 0.0}; // Full-HP baseline per team (ships + defence stations, HQ excluded), computed // once after spawning; the EHP-percentage denominator. double m_teamMaxEhp[2] = {0.0, 0.0}; std::vector m_beamFiredEvents; mutable std::mutex m_statusMutex; ArenaStatus m_status; };