Rework simulation rules

This commit is contained in:
2026-05-11 22:18:43 +02:00
parent 3d406179bf
commit e1ac56d201
30 changed files with 554 additions and 848 deletions

View File

@@ -0,0 +1,82 @@
namespace ReactorMaintenance.Simulation;
internal static class StructuralIntegritySystem
{
public static LevelState Resolve(LevelState level)
{
foreach (var carrier in Enum.GetValues<ECarrierType>())
level = ResolveCarrier(level, carrier);
return level;
}
private static LevelState ResolveCarrier(LevelState level, ECarrierType carrier)
{
var layer = level.Layer(carrier).ToArray();
var leaks = level.Leaks.ToList();
foreach (var position in LevelTraversal.AllPositions(level))
{
var index = level.Index(position);
var cell = layer[index];
if (!cell.IsPresent)
continue;
var integrity = DegradeIntegrity(cell, carrier);
var state = cell.State;
if (state != EUndergroundState.Leaking && integrity <= Balancing.Current.StructuralIntegrityLeakThreshold && cell.Intensity > 0)
{
state = EUndergroundState.Leaking;
leaks = UpsertLeak(leaks, level, position, carrier);
}
layer[index] = cell with { State = state, StructuralIntegrity = integrity };
}
var next = carrier switch {
ECarrierType.Fuel => level with { Fuel = layer },
ECarrierType.Coolant => level with { Coolant = layer },
ECarrierType.Electricity => level with { Electricity = layer },
_ => throw new ArgumentOutOfRangeException(nameof(carrier), carrier, "Unsupported carrier.")
};
return next with { Leaks = leaks.ToArray() };
}
private static int DegradeIntegrity(UndergroundCell cell, ECarrierType carrier)
{
if (cell.StructuralIntegrity >= Balancing.Current.MaxStructuralIntegrity && cell.Intensity <= Balancing.Current.StructuralPressureThreshold(carrier))
return Balancing.Current.MaxStructuralIntegrity;
var overPressure = Math.Max(0, cell.Intensity - Balancing.Current.StructuralPressureThreshold(carrier));
if (overPressure <= 0 || cell.StructuralIntegrity >= Balancing.Current.MaxStructuralIntegrity)
return Math.Clamp(cell.StructuralIntegrity, 0, Balancing.Current.MaxStructuralIntegrity);
var damage = Math.Max(1, (int)Math.Ceiling(overPressure * Balancing.Current.StructuralIntegrityDamageScale));
return Math.Clamp(cell.StructuralIntegrity - damage, 0, Balancing.Current.MaxStructuralIntegrity);
}
private static List<LeakState> UpsertLeak(List<LeakState> leaks, LevelState level, GridPosition position, ECarrierType carrier)
{
var accessPosition = carrier == ECarrierType.Electricity
? position.Neighbors().FirstOrDefault(level.IsFloor)
: position;
if (accessPosition is null || !level.IsFloor(accessPosition))
return leaks;
var index = leaks.FindIndex(leak => leak.UndergroundPosition == position && leak.Carrier == carrier);
var leakState = new LeakState {
Carrier = carrier,
UndergroundPosition = position,
AccessPosition = accessPosition,
Repaired = false
};
if (index >= 0)
leaks[index] = leakState;
else
leaks.Add(leakState);
return leaks;
}
}