#pragma once #include #include #include #include #include #include #include "BeltSystem.h" #include "EntityAdmin.h" #include "entt/entity/entity.hpp" #include "SchematicDropEvent.h" #include "BuildingType.h" #include "BuildingId.h" #include "EventHandler.h" #include "FireEvent.h" #include "GameConfig.h" #include "Rotation.h" #include "Tick.h" #include "TracePrintRequestedEvent.h" class AiSystem; class BuildingSystem; class CombatSystem; class DynamicBodySystem; class MovementIntentSystem; class ShipSystem; class ScrapSystem; class WaveSystem; class Simulation: public CombinedEventHandler { public: explicit Simulation(GameConfig config, unsigned int seed = 0); ~Simulation(); const GameConfig& config() const; // Reinitializes all simulation state as if constructed fresh. void reset(unsigned int seed = 0); // Reloads config then reinitializes all simulation state. void reset(GameConfig newConfig, unsigned int seed = 0); // Advances the simulation by one tick. Tick order per architecture.md §Tick Order. void tick(); // Returns all fire events accumulated since the last drain, clearing the // internal queue. Call once per rendered frame (REQ-SHP-FIRING-BEAM). std::vector drainFireEvents(); // Returns all schematic drop events since the last drain. std::vector drainSchematicDropEvents(); Tick currentTick() const; int buildingBlocksStock() const; bool isGameOver() const; double threatLevel() const; int bossWaveCounter() const; Tick bossCountdownTicks() const; // Schematic state queries. int schematicLevel(const std::string& shipId) const; bool isSchematicUnlocked(const std::string& shipId) const; // Checks affordability, deducts building blocks, and places the building. // Returns the new entity id, or kInvalidBuildingId if blocks are insufficient. BuildingId tryPlaceBuilding(BuildingType type, QPoint anchor, Rotation rotation); // Demolishes the building with the given id and refunds building blocks. void demolish(BuildingId id); BuildingSystem& buildings(); const BuildingSystem& buildings() const; BeltSystem& belts(); const BeltSystem& belts() const; ShipSystem& ships(); const ShipSystem& ships() const; ScrapSystem& scraps(); const ScrapSystem& scraps() const; EntityAdmin& admin(); const EntityAdmin& admin() const; private: void handleEvent(std::shared_ptr event) override; BuildingId allocateBuildingId(); // Strictly increasing; never returns kInvalidBuildingId. // Populate HQ, player defence stations, and the first enemy station set. void placeInitialStructures(); // Place two enemy defence stations for the given generation level. // Stores their IDs in m_currentEnemyStationIds. void placeEnemyStationSet(int generation); // Tick step 9: remove dead ships and buildings, drop scrap, handle push. void tickDeathsAndLoot(); // Award a random schematic drop (REQ-DEF-SCHEMATIC-DROP) and emit the event. void awardSchematicDrop(); GameConfig m_config; std::mt19937 m_rng; Tick m_currentTick; Tick m_nextDepartureTick; BuildingId m_nextBuildingId; int m_buildingBlocksStock; bool m_gameOver = false; // Pre-placed structure IDs. BuildingId m_hqBuildingId; // Building id (for belt integration) entt::entity m_hqProxyEntity; // ECS entity (HP, targeting) entt::entity m_playerStation1Entity; entt::entity m_playerStation2Entity; entt::entity m_currentEnemyStationEntities[2]; // Schematic unlock state (REQ-DEF-SCHEMATIC-DROP). struct SchematicState { bool unlocked; int level; }; std::map m_schematicLevels; 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_scrapSystem; std::unique_ptr m_waveSystem; std::unique_ptr m_combatSystem; std::vector m_fireEvents; std::vector m_schematicDropEvents; };