Rework simulation rules
This commit is contained in:
@@ -280,7 +280,6 @@ public sealed partial class MainWindow
|
||||
ClearPendingEditorOperation();
|
||||
m_Level = m_Level.SetProp(position, new()).SetSurface(position, new()) with {
|
||||
Leaks = m_Level.Leaks.Where(leak => leak.AccessPosition != position && leak.UndergroundPosition != position).ToArray(),
|
||||
Doors = m_Level.Doors.Where(door => door.A != position && door.B != position).ToArray(),
|
||||
Reactors = m_Level.Reactors.Where(reactor => reactor.ControlPosition != position).ToArray()
|
||||
};
|
||||
m_Level = m_Level with { Forecasts = m_Simulation.Forecast(m_Level) };
|
||||
@@ -384,6 +383,11 @@ public sealed partial class MainWindow
|
||||
return m_Level.InBounds(position) ? m_Level.GetTerrain(position) : ECellTerrain.Wall;
|
||||
}
|
||||
|
||||
private bool IsWall(GridPosition position)
|
||||
{
|
||||
return m_Level.InBounds(position) && m_Level.GetTerrain(position) == ECellTerrain.Wall;
|
||||
}
|
||||
|
||||
private void DrawUnderground(CanvasDrawingSession drawing, CanvasLayout layout)
|
||||
{
|
||||
foreach (var position in AllPositions())
|
||||
@@ -431,11 +435,19 @@ public sealed partial class MainWindow
|
||||
|
||||
private void DrawDoors(CanvasDrawingSession drawing, CanvasLayout layout)
|
||||
{
|
||||
foreach (var door in m_Level.Doors)
|
||||
foreach (var position in AllPositions())
|
||||
{
|
||||
var centerA = Center(layout.CellRect(door.A));
|
||||
var centerB = Center(layout.CellRect(door.B));
|
||||
drawing.DrawLine((float)centerA.X, (float)centerA.Y, (float)centerB.X, (float)centerB.Y, door.State == EDoorState.Open ? Colors.LightGreen : Colors.OrangeRed, 5);
|
||||
var prop = m_Level.GetProp(position);
|
||||
if (prop.Type != EPropType.Door)
|
||||
continue;
|
||||
|
||||
var rect = layout.CellRect(position);
|
||||
var center = Center(rect);
|
||||
var color = prop.DoorState == EDoorState.Open ? Colors.LightGreen : Colors.OrangeRed;
|
||||
if (IsWall(new(position.X, position.Y - 1)) && IsWall(new(position.X, position.Y + 1)))
|
||||
drawing.DrawLine((float)rect.Left, (float)center.Y, (float)rect.Right, (float)center.Y, color, 5);
|
||||
else
|
||||
drawing.DrawLine((float)center.X, (float)rect.Top, (float)center.X, (float)rect.Bottom, color, 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,11 +566,11 @@ public sealed partial class MainWindow
|
||||
LevelNameText.Text = m_Level.Name;
|
||||
TurnText.Text = m_Level.Global.Turn.ToString(CultureInfo.InvariantCulture);
|
||||
StatusText.Text = $"{m_Level.Global.LevelState}: {m_Level.Global.Status}";
|
||||
GlobalText.Text = $"Actions: {m_Level.Global.ActionsRemaining}/{Balancing.Current.ActionsPerTurn}\n"
|
||||
+ $"All-seeing-eye: {(m_Level.Global.AllSeeingEyeUnlocked ? "unlocked" : "locked")}\n"
|
||||
+ $"Inventory: F {m_Level.Robot.FuelNeutralizers}, C {m_Level.Robot.CoolantNeutralizers}, E {m_Level.Robot.ElectricityNeutralizers}, H {m_Level.Robot.HeatShields}\n"
|
||||
var doorCount = m_Level.Props.Count(prop => prop.Type == EPropType.Door);
|
||||
GlobalText.Text = $"Inventory: F {m_Level.Robot.FuelNeutralizers}, C {m_Level.Robot.CoolantNeutralizers}, E {m_Level.Robot.ElectricityNeutralizers}, H {m_Level.Robot.HeatShields}\n"
|
||||
+ $"Heat immunity steps: {m_Level.Robot.HeatImmunitySteps}\n"
|
||||
+ $"Reactors: {m_Level.Reactors.Count}, Leaks: {m_Level.Leaks.Count}, Doors: {m_Level.Doors.Count}";
|
||||
+ $"Required consumers F/C/E: {m_Level.RequiredFuelConsumers}/{m_Level.RequiredCoolantConsumers}/{m_Level.RequiredElectricityConsumers}\n"
|
||||
+ $"Reactors: {m_Level.Reactors.Count}, Leaks: {m_Level.Leaks.Count}, Doors: {doorCount}";
|
||||
|
||||
CellText.Text = m_SelectedCell is { } position && m_Level.InBounds(position) ? CellInspectionText(position) : "No cell selected.";
|
||||
ForecastList.ItemsSource = m_Level.Forecasts.Select(forecast => new ForecastViewModel($"{forecast.Turns}: {forecast.Message}")).ToArray();
|
||||
@@ -588,19 +600,8 @@ public sealed partial class MainWindow
|
||||
|
||||
private void ApplyDoorTool(GridPosition position)
|
||||
{
|
||||
if (!m_Level.IsFloor(position))
|
||||
return;
|
||||
|
||||
if (m_PendingDoorCell is not { } pending)
|
||||
{
|
||||
m_PendingDoorCell = position;
|
||||
m_Level = LevelEditor.Apply(m_Level, position, m_SelectedTool);
|
||||
RefreshForecasts();
|
||||
return;
|
||||
}
|
||||
|
||||
m_Level = LevelEditor.SetDoorEdge(m_Level, pending, position);
|
||||
m_PendingDoorCell = null;
|
||||
ClearPendingEditorOperation();
|
||||
m_Level = LevelEditor.Apply(m_Level, position, m_SelectedTool);
|
||||
RefreshForecasts();
|
||||
}
|
||||
|
||||
@@ -641,42 +642,17 @@ public sealed partial class MainWindow
|
||||
|
||||
private void AddWarningRule_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var turn = m_Level.Global.Turn + 1;
|
||||
m_Level = LevelEditor.AddRuleEvent(m_Level, new() {
|
||||
Phase = ERuleEventPhase.EndOfTurn,
|
||||
ForecastText = $"Warning on turn {turn}",
|
||||
Predicates = [new() { Kind = ERulePredicateKind.TurnAtLeast, Turn = turn }],
|
||||
Effects = [new() { Kind = ERuleEffectKind.EmitWarning, Message = $"Authored warning on turn {turn}" }]
|
||||
});
|
||||
RefreshForecasts();
|
||||
RefreshInspector();
|
||||
StatusText.Text = "Rule events were removed from level authoring.";
|
||||
}
|
||||
|
||||
private void AddLeakRule_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (m_SelectedCell is not { } position || !TryGetAuthoredLeakCarrier(position, out var carrier))
|
||||
return;
|
||||
|
||||
var turn = m_Level.Global.Turn + 1;
|
||||
m_Level = LevelEditor.AddRuleEvent(m_Level, new() {
|
||||
Phase = ERuleEventPhase.EndOfTurn,
|
||||
ForecastText = $"{carrier} leak starts on turn {turn}",
|
||||
Predicates = [new() { Kind = ERulePredicateKind.TurnAtLeast, Turn = turn }],
|
||||
Effects = [new() { Kind = ERuleEffectKind.StartLeak, Position = position, AccessPosition = position, Carrier = carrier }]
|
||||
});
|
||||
RefreshForecasts();
|
||||
RefreshInspector();
|
||||
StatusText.Text = "Rule events were removed from level authoring.";
|
||||
}
|
||||
|
||||
private void RemoveLastRule_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var ruleEvent = m_Level.RuleEvents.LastOrDefault();
|
||||
if (ruleEvent is null)
|
||||
return;
|
||||
|
||||
m_Level = LevelEditor.RemoveRuleEvent(m_Level, ruleEvent.Id);
|
||||
RefreshForecasts();
|
||||
RefreshInspector();
|
||||
StatusText.Text = "Rule events were removed from level authoring.";
|
||||
}
|
||||
|
||||
private void BindSelectedConsumer(ECarrierType carrier)
|
||||
@@ -684,9 +660,7 @@ public sealed partial class MainWindow
|
||||
if (m_SelectedCell is not { } position || m_SelectedReactorId is not { } reactorId)
|
||||
return;
|
||||
|
||||
m_Level = LevelEditor.BindReactorConsumer(m_Level, reactorId, carrier, position);
|
||||
RefreshForecasts();
|
||||
RefreshInspector();
|
||||
StatusText.Text = "Reactors now use required consumer counts instead of bindings.";
|
||||
}
|
||||
|
||||
private string CellInspectionText(GridPosition position)
|
||||
@@ -698,7 +672,7 @@ public sealed partial class MainWindow
|
||||
var electricity = m_Level.GetUnderground(position, ECarrierType.Electricity);
|
||||
return $"Position: {position.X},{position.Y}\n"
|
||||
+ $"Terrain: {m_Level.GetTerrain(position)}\n"
|
||||
+ $"Prop: {prop.Type} {prop.Carrier} {prop.SwitchState} {prop.ServiceState}\n"
|
||||
+ $"Prop: {prop.Type} {prop.SwitchState} {prop.ServiceState}\n"
|
||||
+ $"Fuel: {UndergroundText(fuel)}\n"
|
||||
+ $"Coolant: {UndergroundText(coolant)}\n"
|
||||
+ $"Electricity: {UndergroundText(electricity)}\n"
|
||||
@@ -708,9 +682,6 @@ public sealed partial class MainWindow
|
||||
|
||||
private string WorkflowInspectionText()
|
||||
{
|
||||
if (m_PendingDoorCell is { } door)
|
||||
return $"Door edge: select an adjacent floor for {door.X},{door.Y}.";
|
||||
|
||||
if (m_PendingElectricityLeakCell is { } leak)
|
||||
return $"Electricity leak face: select adjacent floor access for {leak.X},{leak.Y}.";
|
||||
|
||||
@@ -724,18 +695,14 @@ public sealed partial class MainWindow
|
||||
return "Select or place a reactor control.";
|
||||
|
||||
return $"Reactor {reactor.ReactorId}\n"
|
||||
+ $"Fuel: {PositionText(reactor.FuelConsumerPosition)}\n"
|
||||
+ $"Coolant: {PositionText(reactor.CoolantConsumerPosition)}\n"
|
||||
+ $"Electric: {PositionText(reactor.ElectricityConsumerPosition)}";
|
||||
+ $"Control: {PositionText(reactor.ControlPosition)}\n"
|
||||
+ $"Ready: {reactor.Ready}\n"
|
||||
+ $"Required F/C/E: {m_Level.RequiredFuelConsumers}/{m_Level.RequiredCoolantConsumers}/{m_Level.RequiredElectricityConsumers}";
|
||||
}
|
||||
|
||||
private string RuleEventInspectionText()
|
||||
{
|
||||
if (m_Level.RuleEvents.Count == 0)
|
||||
return "No authored rule events.";
|
||||
|
||||
var last = m_Level.RuleEvents[^1];
|
||||
return $"{m_Level.RuleEvents.Count} authored. Last: {last.Id} ({last.Phase}).";
|
||||
return "Rule events were removed from level authoring.";
|
||||
}
|
||||
|
||||
private static string PositionText(GridPosition position)
|
||||
@@ -745,7 +712,7 @@ public sealed partial class MainWindow
|
||||
|
||||
private static string UndergroundText(UndergroundCell cell)
|
||||
{
|
||||
return $"{cell.State} amount {Format(cell.Amount)} intensity {Format(cell.Intensity)}";
|
||||
return $"{cell.State} amount {Format(cell.Amount)} intensity {Format(cell.Intensity)} integrity {cell.StructuralIntegrity}";
|
||||
}
|
||||
|
||||
private static string Format(float value)
|
||||
@@ -762,26 +729,25 @@ public sealed partial class MainWindow
|
||||
level = level.SetProp(new(2, 3), new() { Type = EPropType.Flow, Carrier = ECarrierType.Fuel });
|
||||
level = level.SetProp(new(2, 5), new() { Type = EPropType.Flow, Carrier = ECarrierType.Coolant });
|
||||
level = level.SetProp(new(2, 7), new() { Type = EPropType.Flow, Carrier = ECarrierType.Electricity });
|
||||
level = level.SetProp(new(5, 3), new() { Type = EPropType.Consumer, Carrier = ECarrierType.Fuel });
|
||||
level = level.SetProp(new(5, 5), new() { Type = EPropType.Consumer, Carrier = ECarrierType.Coolant });
|
||||
level = level.SetProp(new(5, 7), new() { Type = EPropType.Consumer, Carrier = ECarrierType.Electricity });
|
||||
level = level.SetProp(new(5, 3), new() { Type = EPropType.Consumer });
|
||||
level = level.SetProp(new(5, 5), new() { Type = EPropType.Consumer });
|
||||
level = level.SetProp(new(5, 7), new() { Type = EPropType.Consumer });
|
||||
level = level.SetProp(new(10, 5), new() { Type = EPropType.ReactorControl, ReactorId = 1 });
|
||||
level = level.SetProp(new(11, 4), new() { Type = EPropType.AllSeeingEyeTerminal });
|
||||
level = level.SetProp(new(11, 6), new() { Type = EPropType.RemedySupply, RemedyType = ERemedyType.HeatShield });
|
||||
level = level.SetUnderground(new(4, 5), ECarrierType.Coolant, new() { State = EUndergroundState.Leaking }) with {
|
||||
Leaks = [new() { Carrier = ECarrierType.Coolant, UndergroundPosition = new(4, 5), AccessPosition = new(4, 5) }],
|
||||
Doors = [new() { A = new(8, 5), B = new(9, 5), State = EDoorState.Closed }],
|
||||
Robot = new() { Position = new(10, 5) },
|
||||
Reactors = [
|
||||
new() {
|
||||
ReactorId = 1,
|
||||
ControlPosition = new(10, 5),
|
||||
FuelConsumerPosition = new(5, 3),
|
||||
CoolantConsumerPosition = new(5, 5),
|
||||
ElectricityConsumerPosition = new(5, 7)
|
||||
ControlPosition = new(10, 5)
|
||||
}
|
||||
]
|
||||
};
|
||||
level = level.SetTerrain(new(8, 4), ECellTerrain.Wall);
|
||||
level = level.SetTerrain(new(8, 6), ECellTerrain.Wall);
|
||||
level = level.SetProp(new(8, 5), new() { Type = EPropType.Door });
|
||||
|
||||
return level with { Forecasts = new SimulationEngine().Forecast(level) };
|
||||
}
|
||||
@@ -860,7 +826,7 @@ public sealed partial class MainWindow
|
||||
{
|
||||
return prop.Type switch {
|
||||
EPropType.Flow => $"{CarrierShort(prop.Carrier)} SRC",
|
||||
EPropType.Consumer => $"{CarrierShort(prop.Carrier)} CON",
|
||||
EPropType.Consumer => "CON",
|
||||
EPropType.Junction => $"J {prop.JunctionMode}",
|
||||
EPropType.Door => "DOOR",
|
||||
EPropType.AllSeeingEyeTerminal => "EYE",
|
||||
@@ -975,7 +941,6 @@ public sealed partial class MainWindow
|
||||
|
||||
private void ClearPendingEditorOperation()
|
||||
{
|
||||
m_PendingDoorCell = null;
|
||||
m_PendingElectricityLeakCell = null;
|
||||
}
|
||||
|
||||
@@ -1005,7 +970,6 @@ public sealed partial class MainWindow
|
||||
private LevelState m_Level;
|
||||
private double m_PanX;
|
||||
private double m_PanY;
|
||||
private GridPosition? m_PendingDoorCell;
|
||||
private GridPosition? m_PendingElectricityLeakCell;
|
||||
private CanvasBitmap? m_RobotSprite;
|
||||
private GridPosition? m_SelectedCell;
|
||||
|
||||
Reference in New Issue
Block a user