namespace ReactorMaintenance.Simulation; public sealed class SimulationEngine { public LevelState MoveRobot(LevelState level, GridPosition destination) { return PlayerActionSystem.MoveRobot(level, destination, SpendAction); } public LevelState InteractProp(LevelState level) { return PlayerActionSystem.InteractProp(level, SpendAction); } public LevelState InteractLeak(LevelState level, ECarrierType carrier, bool useRemedy) { return PlayerActionSystem.InteractLeak(level, carrier, useRemedy, SpendAction); } public LevelState ApplyHeatShield(LevelState level) { return PlayerActionSystem.ApplyHeatShield(level, SpendAction); } public LevelState ActivateReactor(LevelState level) { return ReactorSystem.Activate(level); } public LevelState EndTurn(LevelState level) { return ResolveTurn(level with { Global = level.Global with { ActionsRemaining = 0 } }); } public LevelState AdvanceTurn(LevelState level) { return ResolveTurn(level); } public IReadOnlyList Forecast(LevelState level) { return ForecastSystem.Forecast(level, simulated => ResolveTurn(simulated, false)); } private LevelState SpendAction(LevelState level) { var actions = Math.Max(0, level.Global.ActionsRemaining - 1); var next = level with { Global = level.Global with { ActionsRemaining = actions } }; return actions == 0 ? ResolveTurn(next) : next; } private LevelState ResolveTurn(LevelState level, bool refreshForecasts = true) { var report = m_Validator.Validate(level); if (!report.IsValid) return level with { Global = level.Global with { LevelState = ELevelState.Lost, Status = report.Errors[0].Message } }; var next = RuleEventSystem.Apply(level, ERuleEventPhase.StartOfSimulation); next = NetworkPropagationSystem.Propagate(next); next = ConsumerSystem.Resolve(next); next = LeakSystem.Inject(next); next = SurfaceInteractionSystem.Resolve(next); next = RobotSafetySystem.Resolve(next); next = ReactorSystem.DeriveState(next); next = RuleEventSystem.Apply(next, ERuleEventPhase.EndOfTurn); next = SurfaceInteractionSystem.AdvanceDurations(next); next = next with { Global = next.Global with { Turn = next.Global.Turn + 1, ActionsRemaining = Balancing.Current.ActionsPerTurn } }; return refreshForecasts ? next with { Forecasts = Forecast(next) } : next; } private readonly LevelValidator m_Validator = new(); }