namespace ReactorMaintenance.Simulation; public sealed class SimulationEngine { public LevelState MoveRobot(LevelState level, GridPosition destination) { return PlayerActionSystem.MoveRobot(level, destination); } public LevelState InteractProp(LevelState level) { return PlayerActionSystem.InteractProp(level, ResolvePulse); } public LevelState InteractLeak(LevelState level, ECarrierType carrier, bool useRemedy) { return PlayerActionSystem.InteractLeak(level, carrier, useRemedy, ResolvePulse); } public LevelState ApplyHeatShield(LevelState level) { return PlayerActionSystem.ApplyHeatShield(level, ResolvePulse); } public LevelState ActivateReactor(LevelState level) { return ReactorSystem.Activate(level); } public LevelState AdvancePulseForDebug(LevelState level) { return ResolvePulse(level); } public LevelState AdvanceStepForDebug(LevelState level) { return ResolveStep(level); } [Obsolete("Use AdvancePulseForDebug. Player-facing wait/turn advancement is not part of normal gameplay.")] public LevelState EndTurn(LevelState level) { return AdvancePulseForDebug(level); } [Obsolete("Use AdvancePulseForDebug. Player-facing wait/turn advancement is not part of normal gameplay.")] public LevelState AdvanceTurn(LevelState level) { return AdvancePulseForDebug(level); } public IReadOnlyList Forecast(LevelState level) { if (!level.HasActivePoweredTerminalAccess()) return Array.Empty(); return ForecastSystem.Forecast(level, simulated => ResolveStep(simulated, false)); } private LevelState ResolvePulse(LevelState level) { var next = ValidateAndPropagate(level); if (next.Global.LevelState == ELevelState.Lost) return next; for (var i = 0; i < Balancing.Current.StepsPerPulse; i++) next = ResolveStepContent(next); next = ReactorSystem.DeriveState(next); next = SurfaceInteractionSystem.AdvanceDurations(next); next = next with { Global = next.Global with { Turn = next.Global.Pulse + 1, Pulse = next.Global.Pulse + 1 } }; return next with { Forecasts = Forecast(next) }; } private LevelState ResolveStep(LevelState level, bool refreshForecasts = true) { var next = ValidateAndPropagate(level); if (next.Global.LevelState == ELevelState.Lost) return next; next = ResolveStepContent(next); next = ReactorSystem.DeriveState(next); next = SurfaceInteractionSystem.AdvanceDurations(next); return refreshForecasts ? next with { Forecasts = Forecast(next) } : next; } private LevelState ValidateAndPropagate(LevelState level) { 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 = level; next = NetworkPropagationSystem.Propagate(next); next = SprinklerSystem.ApplyPressureDebt(next); next = ConsumerSystem.Resolve(next); next = StructuralIntegritySystem.Resolve(next); return next; } private static LevelState ResolveStepContent(LevelState level) { var next = level; next = SprinklerSystem.Discharge(next); next = LeakSystem.Inject(next); next = SurfaceInteractionSystem.Resolve(next); next = next with { Global = next.Global with { Step = next.Global.Step + 1 } }; return next; } private readonly LevelValidator m_Validator = new(); }