Organize simulation systems and balancing profiles

This commit is contained in:
2026-05-08 21:45:43 +02:00
parent 8018ebbabb
commit c46b6664ed
25 changed files with 406 additions and 269 deletions

View File

@@ -1,4 +1,7 @@
namespace ReactorMaintenance.Simulation;
using ReactorMaintenance.Simulation.Effects;
using ReactorMaintenance.Simulation.Hazards;
namespace ReactorMaintenance.Simulation;
public sealed class SimulationEngine(IEnumerable<ISimulationEffect> effects, IEnumerable<IAreaSimulationEffect> areaEffects, IEnumerable<Hazard> hazards)
{
@@ -23,14 +26,14 @@ public sealed class SimulationEngine(IEnumerable<ISimulationEffect> effects, IEn
var seen = new HashSet<ForecastKey>();
var forecastLevel = level with { Cells = level.Cells.ToArray(), Forecasts = Array.Empty<Forecast>() };
if (forecastLevel.Global.Lost)
AddHazardForecasts(forecasts, seen, forecastLevel, Balancing.CurrentForecastTurn);
AddHazardForecasts(forecasts, seen, forecastLevel, Balancing.Current.CurrentForecastTurn);
AddReactorReadyForecast(forecasts, seen, forecastLevel, Balancing.CurrentForecastTurn);
AddReactorReadyForecast(forecasts, seen, forecastLevel, Balancing.Current.CurrentForecastTurn);
if (IsReactorReady(forecastLevel) || forecastLevel.Global.Lost || forecastLevel.Global.ReactorActivated)
return forecasts.OrderBy(f => f.Turns).ThenBy(f => f.Message).ToArray();
for (var step = Balancing.TurnIncrement; step <= Balancing.MaxForecastStepCount; step++)
for (var step = Balancing.Current.TurnIncrement; step <= Balancing.Current.MaxForecastStepCount; step++)
{
forecastLevel = AdvanceTurn(forecastLevel, false);
AddHazardForecasts(forecasts, seen, forecastLevel, step);
@@ -60,9 +63,9 @@ public sealed class SimulationEngine(IEnumerable<ISimulationEffect> effects, IEn
{
var cells = level.Cells.ToArray();
for (var y = Balancing.FirstGridCoordinate; y < level.Height; y++)
for (var y = Balancing.Current.FirstGridCoordinate; y < level.Height; y++)
{
for (var x = Balancing.FirstGridCoordinate; x < level.Width; x++)
for (var x = Balancing.Current.FirstGridCoordinate; x < level.Width; x++)
{
var position = new GridPosition(x, y);
var index = level.Index(position);
@@ -84,7 +87,7 @@ public sealed class SimulationEngine(IEnumerable<ISimulationEffect> effects, IEn
var global = UpdateGlobal(level, cells);
var next = level with {
Cells = cells,
Global = global with { Turn = level.Global.Turn + Balancing.TurnIncrement }
Global = global with { Turn = level.Global.Turn + Balancing.Current.TurnIncrement }
};
return updateForecasts ? next with { Forecasts = Forecast(next) } : next;
@@ -116,14 +119,14 @@ public sealed class SimulationEngine(IEnumerable<ISimulationEffect> effects, IEn
var reactorHeat = cells.Where(c => c.Kind == ECellKind.Reactor).Select(c => c.Hazards.Heat).DefaultIfEmpty(level.Global.CoreHeat).Max();
var poweredGenerators = cells.Count(c => c is { Kind: ECellKind.Generator, Powered: true, Hazards.Fire: false });
var poweredPumps = cells.Count(c => c is { Kind: ECellKind.CoolingPump, Powered: true, Hazards.Fire: false });
var damagedCriticalCells = cells.Count(c => c.Kind is ECellKind.Reactor or ECellKind.Generator or ECellKind.CoolingPump && c.Hazards.Stability <= Balancing.CriticalCellStabilityThreshold);
var damagedCriticalCells = cells.Count(c => c.Kind is ECellKind.Reactor or ECellKind.Generator or ECellKind.CoolingPump && c.Hazards.Stability <= Balancing.Current.CriticalCellStabilityThreshold);
var stability = Rules.Clamp(level.Global.FacilityStability - damagedCriticalCells);
var lost = reactorHeat >= Balancing.MeltdownCoreHeatThreshold || stability <= Balancing.StabilityCollapseThreshold;
var status = lost ? reactorHeat >= Balancing.MeltdownCoreHeatThreshold ? "CORE MELTDOWN" : "FACILITY STABILITY COLLAPSE" : "STABILIZE SYSTEMS";
var lost = reactorHeat >= Balancing.Current.MeltdownCoreHeatThreshold || stability <= Balancing.Current.StabilityCollapseThreshold;
var status = lost ? reactorHeat >= Balancing.Current.MeltdownCoreHeatThreshold ? "CORE MELTDOWN" : "FACILITY STABILITY COLLAPSE" : "STABILIZE SYSTEMS";
var global = level.Global with {
CoreHeat = Rules.Clamp(reactorHeat - poweredPumps),
Power = Rules.Clamp(poweredGenerators * Balancing.GeneratorPowerOutput),
Cooling = Rules.Clamp(poweredPumps * Balancing.CoolingPumpOutput),
Power = Rules.Clamp(poweredGenerators * Balancing.Current.GeneratorPowerOutput),
Cooling = Rules.Clamp(poweredPumps * Balancing.Current.CoolingPumpOutput),
FacilityStability = stability,
Lost = lost,
Status = status
@@ -135,9 +138,9 @@ public sealed class SimulationEngine(IEnumerable<ISimulationEffect> effects, IEn
private static bool IsReactorReady(LevelState level)
{
var hasReactor = level.Cells.Any(c => c.Kind == ECellKind.Reactor);
var hasStablePower = level.Global.Power >= Balancing.ReactorReadyPowerThreshold || level.Cells.Any(c => c is { Kind: ECellKind.Generator, Powered: true, Hazards.Fire: false });
var hasCooling = level.Global.Cooling >= Balancing.ReactorReadyCoolingThreshold || level.Cells.Any(c => c is { Kind: ECellKind.CoolingPump, Powered: true, Hazards.Fire: false });
var reactorStable = level.Global.CoreHeat < Balancing.ReactorReadyCoreHeatThreshold;
var hasStablePower = level.Global.Power >= Balancing.Current.ReactorReadyPowerThreshold || level.Cells.Any(c => c is { Kind: ECellKind.Generator, Powered: true, Hazards.Fire: false });
var hasCooling = level.Global.Cooling >= Balancing.Current.ReactorReadyCoolingThreshold || level.Cells.Any(c => c is { Kind: ECellKind.CoolingPump, Powered: true, Hazards.Fire: false });
var reactorStable = level.Global.CoreHeat < Balancing.Current.ReactorReadyCoreHeatThreshold;
return hasReactor && hasStablePower && hasCooling && reactorStable && !level.Global.Lost;
}