82 lines
3.2 KiB
C#
82 lines
3.2 KiB
C#
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.Water => level with { Water = 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;
|
|
}
|
|
} |