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

@@ -2,23 +2,23 @@
internal static class PlayerActionSystem
{
public static LevelState MoveRobot(LevelState level, GridPosition destination, Func<LevelState, LevelState> spendAction)
public static LevelState MoveRobot(LevelState level, GridPosition destination)
{
if (!CanSpendAction(level) || !level.IsFloor(destination) || level.Robot.Position.ManhattanDistance(destination) != 1)
if (!CanAct(level) || !level.IsFloor(destination) || level.Robot.Position.ManhattanDistance(destination) != 1)
return Refuse(level, "MOVE BLOCKED");
return spendAction(level with {
return level with {
Robot = level.Robot with {
Position = destination,
HeatImmunitySteps = Math.Max(0, level.Robot.HeatImmunitySteps - 1)
}
});
};
}
public static LevelState InteractProp(LevelState level, Func<LevelState, LevelState> spendAction)
public static LevelState InteractProp(LevelState level, Func<LevelState, LevelState> resolveLengthyAction)
{
if (!CanSpendAction(level))
return Refuse(level, "NO ACTIONS");
if (!CanAct(level))
return Refuse(level, "NO CONTROL");
var position = level.Robot.Position;
var prop = level.GetProp(position);
@@ -28,20 +28,20 @@ internal static class PlayerActionSystem
var next = prop.Type switch {
EPropType.Flow or EPropType.Consumer => ToggleProp(level, position, prop),
EPropType.Junction => CycleJunctionMode(level, position, prop),
EPropType.Door => ToggleDoor(level, position),
EPropType.AllSeeingEyeTerminal => level with { Global = level.Global with { AllSeeingEyeUnlocked = true, Status = "ALL-SEEING-EYE ONLINE" } },
EPropType.Door => ToggleDoor(level, position, prop),
EPropType.AllSeeingEyeTerminal => level with { Global = level.Global with { Status = "ALL-SEEING-EYE AVAILABLE" } },
EPropType.RemedySupply => PickUpRemedy(level, position, prop),
EPropType.ReactorControl => ReactorSystem.Activate(level),
_ => level
};
return spendAction(next);
return prop.Type == EPropType.AllSeeingEyeTerminal || prop.Type == EPropType.ReactorControl ? next : resolveLengthyAction(next);
}
public static LevelState InteractLeak(LevelState level, ECarrierType carrier, bool useRemedy, Func<LevelState, LevelState> spendAction)
public static LevelState InteractLeak(LevelState level, ECarrierType carrier, bool useRemedy, Func<LevelState, LevelState> resolveLengthyAction)
{
if (!CanSpendAction(level))
return Refuse(level, "NO ACTIONS");
if (!CanAct(level))
return Refuse(level, "NO CONTROL");
var leakIndex = level.Leaks.ToList().FindIndex(leak => !leak.Repaired && leak.Carrier == carrier && leak.AccessPosition == level.Robot.Position);
if (leakIndex < 0)
@@ -49,15 +49,15 @@ internal static class PlayerActionSystem
var leak = level.Leaks[leakIndex];
var next = useRemedy ? ApplyElementRemedy(level, leak) : RepairLeak(level, leakIndex, leak);
return spendAction(next);
return resolveLengthyAction(next);
}
public static LevelState ApplyHeatShield(LevelState level, Func<LevelState, LevelState> spendAction)
public static LevelState ApplyHeatShield(LevelState level, Func<LevelState, LevelState> resolveLengthyAction)
{
if (!CanSpendAction(level) || level.Robot.HeatShields <= 0)
if (!CanAct(level) || level.Robot.HeatShields <= 0)
return Refuse(level, "NO HEAT SHIELD");
return spendAction(level with {
return resolveLengthyAction(level with {
Robot = level.Robot.Spend(ERemedyType.HeatShield) with { HeatImmunitySteps = Balancing.Current.HeatShieldSteps }
});
}
@@ -68,15 +68,10 @@ internal static class PlayerActionSystem
return level.SetProp(position, prop with { SwitchState = switchState });
}
private static LevelState ToggleDoor(LevelState level, GridPosition position)
private static LevelState ToggleDoor(LevelState level, GridPosition position, PropState prop)
{
var doors = level.Doors.ToArray();
var index = Array.FindIndex(doors, door => door.A == position || door.B == position);
if (index < 0)
return level;
doors[index] = doors[index] with { State = doors[index].State == EDoorState.Open ? EDoorState.Closed : EDoorState.Open };
return level with { Doors = doors };
var doorState = prop.DoorState == EDoorState.Open ? EDoorState.Closed : EDoorState.Open;
return level.SetProp(position, prop with { DoorState = doorState });
}
private static LevelState PickUpRemedy(LevelState level, GridPosition position, PropState prop)
@@ -91,7 +86,12 @@ internal static class PlayerActionSystem
{
var leaks = level.Leaks.ToArray();
leaks[leakIndex] = leak with { Repaired = true };
return level.SetUnderground(leak.UndergroundPosition, leak.Carrier, level.GetUnderground(leak.UndergroundPosition, leak.Carrier) with { State = EUndergroundState.Intact }) with { Leaks = leaks };
return level.SetUnderground(leak.UndergroundPosition, leak.Carrier, level.GetUnderground(leak.UndergroundPosition, leak.Carrier) with {
State = EUndergroundState.Intact,
StructuralIntegrity = Balancing.Current.MaxStructuralIntegrity
}) with {
Leaks = leaks
};
}
private static LevelState ApplyElementRemedy(LevelState level, LeakState leak)
@@ -121,9 +121,9 @@ internal static class PlayerActionSystem
return level.SetProp(position, prop with { JunctionMode = (prop.JunctionMode + 1) % ratios.Count });
}
private static bool CanSpendAction(LevelState level)
private static bool CanAct(LevelState level)
{
return level.Global.LevelState is not (ELevelState.Lost or ELevelState.Won) && level.Global.ActionsRemaining > 0;
return level.Global.LevelState is not (ELevelState.Lost or ELevelState.Won);
}
private static LevelState Refuse(LevelState level, string message)