Align frontend pulse contract and tasks

This commit is contained in:
2026-05-14 10:26:56 +02:00
parent 830c7aef14
commit 6decf2a9d2
13 changed files with 129 additions and 90 deletions

View File

@@ -32,7 +32,7 @@ public partial class ForecastList : PanelContainer
{
var pos = forecast.Position;
var posStr = pos != null ? $" [{pos.X},{pos.Y}]" : "";
return $"Turn +{forecast.Turns}: {forecast.Message}{posStr}";
return $"Pulse +{forecast.Turns}: {forecast.Message}{posStr}";
}
private static void ApplyForecastColor(Label label, EForecastKind kind)

View File

@@ -514,6 +514,9 @@ public partial class GridViewport : Control
EPropType.Consumer => new(0.36f, 0.48f, 0.67f),
EPropType.Junction => new(0.56f, 0.44f, 0.70f),
EPropType.AllSeeingEyeTerminal => new(0.33f, 0.59f, 0.61f),
EPropType.IsolationValve => CarrierColor(prop.Carrier),
EPropType.SprinklerControl => new(0.21f, 0.59f, 0.73f),
EPropType.SprinklerValve => new(0.15f, 0.44f, 0.59f),
EPropType.RemedySupply => new(0.30f, 0.57f, 0.34f),
EPropType.ReactorControl => new(0.69f, 0.28f, 0.29f),
_ => Colors.Gray
@@ -527,6 +530,9 @@ public partial class GridViewport : Control
EPropType.Consumer => "CON",
EPropType.Junction => $"J {prop.JunctionMode}",
EPropType.AllSeeingEyeTerminal => "EYE",
EPropType.IsolationValve => prop.IsOpen ? "V OPEN" : "V CLOSED",
EPropType.SprinklerControl => prop.IsEnabled ? "SPR ON" : "SPR OFF",
EPropType.SprinklerValve => "SPR",
EPropType.RemedySupply => RemedyShort(prop.RemedyType),
EPropType.ReactorControl => "REACT",
_ => string.Empty

View File

@@ -6,7 +6,7 @@ public sealed class GameSession
{
public event StateChangedHandler? LevelStateChanged;
public event StateChangedHandler? RobotMoved;
public event StateChangedHandler? TurnAdvanced;
public event StateChangedHandler? PulseAdvanced;
public event StateChangedHandler? LevelWon;
public event StateChangedHandler? LevelLost;
@@ -31,20 +31,13 @@ public sealed class GameSession
return true;
}
public LevelState EndTurn()
{
LevelState = m_Engine.EndTurn(LevelState);
OnTurnAdvanced();
return LevelState;
}
public bool InteractProp()
{
if (LevelState.Global.LevelState is ELevelState.Lost or ELevelState.Won)
return false;
LevelState = m_Engine.InteractProp(LevelState);
OnTurnAdvanced();
OnPulseAdvanced();
return true;
}
@@ -54,7 +47,7 @@ public sealed class GameSession
return false;
LevelState = m_Engine.InteractLeak(LevelState, carrier, useRemedy);
OnTurnAdvanced();
OnPulseAdvanced();
return true;
}
@@ -64,7 +57,7 @@ public sealed class GameSession
return false;
LevelState = m_Engine.ApplyHeatShield(LevelState);
OnTurnAdvanced();
OnPulseAdvanced();
return true;
}
@@ -89,10 +82,10 @@ public sealed class GameSession
LevelStateChanged?.Invoke(this);
}
private void OnTurnAdvanced()
private void OnPulseAdvanced()
{
CheckOutcome();
TurnAdvanced?.Invoke(this);
PulseAdvanced?.Invoke(this);
}
private void CheckOutcome()

View File

@@ -1,5 +1,5 @@
{
"Version": 3,
"Version": 4,
"Level": {
"Name": "Black Start",
"Width": 10,
@@ -3971,4 +3971,4 @@
},
"Forecasts": []
}
}
}

View File

@@ -1,5 +1,5 @@
{
"Version": 3,
"Version": 4,
"Level": {
"Name": "Coolant Restart",
"Width": 8,
@@ -2795,4 +2795,4 @@
},
"Forecasts": []
}
}
}

View File

@@ -1,5 +1,5 @@
{
"Version": 3,
"Version": 4,
"Level": {
"Name": "Fuel Bleed",
"Width": 8,
@@ -2808,4 +2808,4 @@
},
"Forecasts": []
}
}
}

View File

@@ -56,7 +56,7 @@ public partial class LevelScreen : ScreenBase
UpdateUI();
m_Session.LevelStateChanged += OnLevelStateChanged;
m_Session.RobotMoved += OnRobotMoved;
m_Session.TurnAdvanced += OnTurnAdvanced;
m_Session.PulseAdvanced += OnPulseAdvanced;
}
private GridViewport CreateGridViewport()
@@ -131,7 +131,6 @@ public partial class LevelScreen : ScreenBase
actions.AddChild(CreateButton("Move", OnMoveAction, "Move robot to adjacent floor cell"));
actions.AddChild(CreateButton("Interact", OnInteractAction, "Interact with prop at robot position"));
actions.AddChild(CreateButton("Repair", OnRepairAction, "Repair leak at robot position"));
actions.AddChild(CreateButton("End Turn", OnEndTurnAction));
actions.AddChild(CreateButton("Main Menu", () => m_App?.ShowMainMenu()));
return actions;
}
@@ -168,11 +167,6 @@ public partial class LevelScreen : ScreenBase
}
}
private void OnEndTurnAction()
{
m_Session?.EndTurn();
}
private void UpdateUI()
{
if (m_Session is null || m_Inspector is null || m_ForecastList is null || m_InventoryStrip is null)
@@ -228,7 +222,7 @@ public partial class LevelScreen : ScreenBase
UpdateUI();
}
private void OnTurnAdvanced(GameSession sender)
private void OnPulseAdvanced(GameSession sender)
{
UpdateUI();
if (sender.LevelState.Global.LevelState is ELevelState.Lost or ELevelState.Won)

View File

@@ -37,18 +37,6 @@ public sealed class SimulationEngine
return ResolveStep(level);
}
[Obsolete("Use AdvancePulseForDebug. Player-facing wait/turn advancement is not part of normal gameplay.")]
public LevelState EndTurn(LevelState level)
{
return AdvancePulseForDebug(level);
}
[Obsolete("Use AdvancePulseForDebug. Player-facing wait/turn advancement is not part of normal gameplay.")]
public LevelState AdvanceTurn(LevelState level)
{
return AdvancePulseForDebug(level);
}
public IReadOnlyList<Forecast> Forecast(LevelState level)
{
if (!level.HasActivePoweredTerminalAccess())

View File

@@ -16,7 +16,7 @@
<AppBarButton Icon="Save" Label="Save" Click="Save_Click" />
<AppBarSeparator />
<AppBarButton x:Name="PlayPauseButton" Icon="Play" Label="Play" Click="PlayPause_Click" />
<AppBarButton Icon="Forward" Label="End Turn" Click="EndTurn_Click" />
<AppBarButton Icon="Forward" Label="Debug Pulse" Click="DebugPulse_Click" />
<AppBarButton Label="Interact" Click="Interact_Click" />
<AppBarButton Label="Heat Shield" Click="HeatShield_Click" />
<AppBarButton Icon="Accept" Label="Activate" Click="Activate_Click" />
@@ -85,7 +85,7 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel>
<TextBlock Text="Turn" Foreground="#9EA7AE" />
<TextBlock Text="Pulse" Foreground="#9EA7AE" />
<TextBlock x:Name="TurnText" FontSize="22" Foreground="#F4F1E8" />
</StackPanel>
<StackPanel Grid.Column="1">

View File

@@ -217,9 +217,9 @@ public sealed partial class MainWindow
}
}
private void EndTurn_Click(object sender, RoutedEventArgs e)
private void DebugPulse_Click(object sender, RoutedEventArgs e)
{
RunSimulationStep();
RunDebugPulse();
}
private void PlayPause_Click(object sender, RoutedEventArgs e)
@@ -232,7 +232,7 @@ public sealed partial class MainWindow
private void SimulationTimer_Tick(object? sender, object e)
{
RunSimulationStep();
RunDebugPulse();
}
private void StartSimulationTimer()
@@ -254,9 +254,9 @@ public sealed partial class MainWindow
PlayPauseButton.Label = isPlaying ? "Pause" : "Play";
}
private void RunSimulationStep()
private void RunDebugPulse()
{
m_Level = m_Simulation.EndTurn(m_Level);
m_Level = m_Simulation.AdvancePulseForDebug(m_Level);
RefreshInspector();
LevelCanvas.Invalidate();
}
@@ -878,7 +878,7 @@ public sealed partial class MainWindow
private void RefreshInspector()
{
LevelNameText.Text = m_Level.Name;
TurnText.Text = m_Level.Global.Turn.ToString(CultureInfo.InvariantCulture);
TurnText.Text = m_Level.Global.Pulse.ToString(CultureInfo.InvariantCulture);
StatusText.Text = string.IsNullOrWhiteSpace(m_EditorFeedback)
? $"{m_Level.Global.LevelState}: {m_Level.Global.Status}"
: $"{m_Level.Global.LevelState}: {m_EditorFeedback}";
@@ -1152,6 +1152,9 @@ public sealed partial class MainWindow
EPropType.Junction => ColorHelper.FromArgb(255, 143, 111, 178),
EPropType.Door => ColorHelper.FromArgb(255, 187, 119, 55),
EPropType.AllSeeingEyeTerminal => ColorHelper.FromArgb(255, 85, 151, 156),
EPropType.IsolationValve => CarrierColor(prop.Carrier),
EPropType.SprinklerControl => ColorHelper.FromArgb(255, 54, 150, 186),
EPropType.SprinklerValve => ColorHelper.FromArgb(255, 38, 112, 150),
EPropType.RemedySupply => ColorHelper.FromArgb(255, 76, 145, 86),
EPropType.ReactorControl => ColorHelper.FromArgb(255, 177, 72, 73),
_ => Colors.Gray
@@ -1178,6 +1181,9 @@ public sealed partial class MainWindow
EEditorTool.Junction => EPropType.Junction,
EEditorTool.Door => EPropType.Door,
EEditorTool.AllSeeingEyeTerminal => EPropType.AllSeeingEyeTerminal,
EEditorTool.IsolationValve => EPropType.IsolationValve,
EEditorTool.SprinklerControl => EPropType.SprinklerControl,
EEditorTool.SprinklerValve => EPropType.SprinklerValve,
EEditorTool.RemedySupply => EPropType.RemedySupply,
EEditorTool.ReactorControl => EPropType.ReactorControl,
_ => EPropType.None
@@ -1192,6 +1198,9 @@ public sealed partial class MainWindow
EPropType.Junction => "prop-junction",
EPropType.Door => "prop-door",
EPropType.AllSeeingEyeTerminal => "prop-eye-terminal",
EPropType.IsolationValve => "prop-isolation-valve",
EPropType.SprinklerControl => "prop-sprinkler-control",
EPropType.SprinklerValve => "prop-sprinkler-valve",
EPropType.RemedySupply => "prop-remedy",
EPropType.ReactorControl => "prop-reactor",
_ => "prop"
@@ -1231,6 +1240,9 @@ public sealed partial class MainWindow
EPropType.Junction => $"J {prop.JunctionMode}",
EPropType.Door => "DOOR",
EPropType.AllSeeingEyeTerminal => "EYE",
EPropType.IsolationValve => prop.IsOpen ? "V OPEN" : "V CLOSED",
EPropType.SprinklerControl => prop.IsEnabled ? "SPR ON" : "SPR OFF",
EPropType.SprinklerValve => "SPR",
EPropType.RemedySupply => RemedyShort(prop.RemedyType),
EPropType.ReactorControl => "REACT",
_ => string.Empty
@@ -1300,10 +1312,15 @@ public sealed partial class MainWindow
CarrierTool(EEditorTool.Flow, ECarrierType.Fuel, "Fuel Source"),
CarrierTool(EEditorTool.Flow, ECarrierType.Water, "Water Source"),
CarrierTool(EEditorTool.Flow, ECarrierType.Electricity, "Electric Source"),
CarrierTool(EEditorTool.IsolationValve, ECarrierType.Fuel, "Fuel Valve"),
CarrierTool(EEditorTool.IsolationValve, ECarrierType.Water, "Water Valve"),
CarrierTool(EEditorTool.IsolationValve, ECarrierType.Electricity, "Electric Valve"),
Tool(EEditorTool.Consumer, "Consumer"),
Tool(EEditorTool.Junction, "Junction"),
Tool(EEditorTool.Door, "Door"),
Tool(EEditorTool.AllSeeingEyeTerminal, "Eye Terminal"),
Tool(EEditorTool.SprinklerControl, "Sprinkler Control"),
Tool(EEditorTool.SprinklerValve, "Sprinkler Valve"),
RemedyTool(ERemedyType.FuelNeutralizer, "Fuel Remedy"),
RemedyTool(ERemedyType.WaterNeutralizer, "Water Remedy"),
RemedyTool(ERemedyType.ElectricityNeutralizer, "Electric Remedy"),
@@ -1333,6 +1350,9 @@ public sealed partial class MainWindow
or EEditorTool.Junction
or EEditorTool.Door
or EEditorTool.AllSeeingEyeTerminal
or EEditorTool.IsolationValve
or EEditorTool.SprinklerControl
or EEditorTool.SprinklerValve
or EEditorTool.RemedySupply
or EEditorTool.ReactorControl
or EEditorTool.SurfaceHazard
@@ -1341,7 +1361,7 @@ public sealed partial class MainWindow
}
var activeCarrier = LayerCarrier(m_ActiveLayer);
return command.Carrier == activeCarrier && command.Tool is EEditorTool.Underground or EEditorTool.Flow or EEditorTool.Leak;
return command.Carrier == activeCarrier && command.Tool is EEditorTool.Underground or EEditorTool.Flow or EEditorTool.Leak or EEditorTool.IsolationValve;
}
private void RefreshForecasts()