diff --git a/src/ReactorMaintenance.Win2D/MainWindow.xaml b/src/ReactorMaintenance.Win2D/MainWindow.xaml
index 20c4533..ca2a8a4 100644
--- a/src/ReactorMaintenance.Win2D/MainWindow.xaml
+++ b/src/ReactorMaintenance.Win2D/MainWindow.xaml
@@ -136,8 +136,10 @@
-
-
+
+
@@ -148,7 +150,8 @@
-
+
@@ -167,13 +170,14 @@
-
+
-
+
@@ -188,13 +192,14 @@
-
+
-
+
@@ -204,8 +209,10 @@
-
-
+
+
@@ -225,7 +232,8 @@
-
+
diff --git a/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs b/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs
index 0295d4e..86704d0 100644
--- a/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs
+++ b/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs
@@ -266,7 +266,7 @@ public sealed partial class MainWindow
m_EditorFeedback = string.Empty;
m_LastPaintedCell = null;
if (!m_IsPanning && m_SelectedTool.Tool == EEditorTool.Cursor && TryGetGridPosition(point.Position, out var position))
- StartCursorDrag(position);
+ m_CursorDragStartCell = position;
else if (!m_IsPanning && IsDragPaintTool(m_SelectedTool.Tool) && TryGetGridPosition(point.Position, out position))
{
m_LastPaintedCell = position;
@@ -306,7 +306,7 @@ public sealed partial class MainWindow
}
else if (m_CursorDragStartCell is not null && m_DragExceededClickThreshold && TryGetGridPosition(point.Position, out var destination))
{
- m_DragPreviewDestination = destination;
+ UpdateCursorDragPreview(destination);
LevelCanvas.Invalidate();
}
@@ -322,7 +322,7 @@ public sealed partial class MainWindow
{
LevelCanvas.Invalidate();
}
- else if (m_CursorDragStartCell is { } source && m_DragExceededClickThreshold && TryGetGridPosition(point.Position, out var destination))
+ else if (m_CursorDragStartCell is { } source && m_DragExceededClickThreshold && !m_CursorDragStartRejected && TryGetGridPosition(point.Position, out var destination))
{
var result = LevelEditor.TryMoveOccupant(m_Level, source, destination);
m_Level = result.Level;
@@ -343,6 +343,7 @@ public sealed partial class MainWindow
}
}
+ var clearRejectedDragFeedback = m_CursorDragStartRejected;
m_LeftPointerDown = false;
m_IsPanning = false;
m_CursorDragStartCell = null;
@@ -350,6 +351,13 @@ public sealed partial class MainWindow
m_DragPreviewDestination = null;
m_LastPaintedCell = null;
m_DragExceededClickThreshold = false;
+ if (clearRejectedDragFeedback)
+ {
+ ClearDragFeedback();
+ RefreshInspector();
+ LevelCanvas.Invalidate();
+ }
+
LevelCanvas.ReleasePointerCapture(e.Pointer);
e.Handled = true;
}
@@ -363,6 +371,9 @@ public sealed partial class MainWindow
m_DragPreviewDestination = null;
m_LastPaintedCell = null;
m_DragExceededClickThreshold = false;
+ ClearDragFeedback();
+ RefreshInspector();
+ LevelCanvas.Invalidate();
}
private void LevelCanvas_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
@@ -415,22 +426,34 @@ public sealed partial class MainWindow
return tool is EEditorTool.Floor or EEditorTool.Wall or EEditorTool.Underground;
}
- private void StartCursorDrag(GridPosition position)
+ private void UpdateCursorDragPreview(GridPosition destination)
{
- m_SelectedCell = position;
- if (HasMovableAt(position))
+ if (m_CursorDragStartCell is not { } source)
+ return;
+
+ if (m_CursorDragStartRejected)
+ return;
+
+ if (!HasMovableAt(source))
{
- m_CursorDragStartCell = position;
+ m_CursorDragStartRejected = true;
+ m_DragPreviewDestination = null;
+ m_InvalidDragCell = source;
+ m_EditorFeedback = "No movable robot, prop, source, or leak starts here.";
RefreshInspector();
- LevelCanvas.Invalidate();
return;
}
- m_CursorDragStartRejected = true;
- m_InvalidDragCell = position;
- m_EditorFeedback = "No movable robot, prop, source, or leak starts here.";
+ m_DragPreviewDestination = destination;
+ m_InvalidDragCell = null;
+ m_EditorFeedback = string.Empty;
RefreshInspector();
- LevelCanvas.Invalidate();
+ }
+
+ private void ClearDragFeedback()
+ {
+ m_InvalidDragCell = null;
+ m_EditorFeedback = string.Empty;
}
private void ClearAt(Point point)
@@ -613,23 +636,39 @@ public sealed partial class MainWindow
{
var surface = m_Level.GetSurface(position);
var rect = layout.CellRect(position);
- FillHazard(drawing, rect, surface.Fuel, c_FuelColor, 0.08, opacity);
- FillHazard(drawing, rect, surface.Coolant, c_CoolantColor, 0.18, opacity);
- FillHazard(drawing, rect, surface.Electricity, c_ElectricityColor, 0.28, opacity);
- if (surface.Heat > 0)
- DrawImage(drawing, m_HeatSprite, Inset(rect, 0.18), Math.Clamp(surface.Heat / Balancing.Current.MaxValue, 0.25f, 0.9f) * opacity);
+ FillHazard(drawing, rect, surface.Fuel, c_FuelColor, 0.08, opacity, Balancing.Current.FuelCaution, Balancing.Current.FuelCritical);
+ FillHazard(drawing, rect, surface.Coolant, c_CoolantColor, 0.18, opacity, Balancing.Current.CoolantCaution, Balancing.Current.CoolantCritical);
+ FillHazard(drawing, rect, surface.Electricity, c_ElectricityColor, 0.28, opacity, Balancing.Current.ElectricityCaution, Balancing.Current.ElectricityCritical);
+
+ var heatOpacity = SurfaceOverlayOpacity(surface.Heat, Balancing.Current.HeatCaution, Balancing.Current.HeatCritical);
+ if (heatOpacity > 0)
+ DrawImage(drawing, m_HeatSprite, Inset(rect, 0.18), heatOpacity * opacity);
}
}
- private static void FillHazard(CanvasDrawingSession drawing, Rect rect, float amount, Color color, double inset, float opacity)
+ private static void FillHazard(CanvasDrawingSession drawing, Rect rect, float amount, Color color, double inset, float opacity, float caution, float critical)
{
- if (amount <= 0)
+ var overlayOpacity = SurfaceOverlayOpacity(amount, caution, critical);
+ if (overlayOpacity <= 0)
return;
- var alpha = (byte)Math.Clamp((40 + (amount / Balancing.Current.MaxValue * 130)) * opacity, 0, 170);
+ var alpha = (byte)Math.Clamp(170 * overlayOpacity * opacity, 0, 170);
drawing.FillRectangle(Inset(rect, inset), ColorHelper.FromArgb(alpha, color.R, color.G, color.B));
}
+ private static float SurfaceOverlayOpacity(float amount, float caution, float critical)
+ {
+ if (amount < caution)
+ return 0;
+
+ if (amount >= critical)
+ return 0.9f;
+
+ var cautionRange = Math.Max(0.001f, critical - caution);
+ var t = (amount - caution) / cautionRange;
+ return 0.3f + (t * 0.35f);
+ }
+
private void DrawDoors(CanvasDrawingSession drawing, CanvasLayout layout, float opacity)
{
foreach (var position in AllPositions())
@@ -805,7 +844,7 @@ public sealed partial class MainWindow
new InspectorItemViewModel("Fuel", $"{m_Level.Robot.FuelNeutralizers}"),
new InspectorItemViewModel("Coolant", $"{m_Level.Robot.CoolantNeutralizers}"),
new InspectorItemViewModel("Electricity", $"{m_Level.Robot.ElectricityNeutralizers}"),
- new InspectorItemViewModel("Heat", $"{m_Level.Robot.HeatShields} ({m_Level.Robot.HeatImmunitySteps.ToString(CultureInfo.InvariantCulture)} steps)"),
+ new InspectorItemViewModel("Heat", $"{m_Level.Robot.HeatShields} ({m_Level.Robot.HeatImmunitySteps.ToString(CultureInfo.InvariantCulture)} steps)")
};
RequiredGrid.ItemsSource = new[] {
new InspectorItemViewModel("Fuel", m_Level.RequiredFuelConsumers.ToString(CultureInfo.InvariantCulture)),
@@ -822,13 +861,13 @@ public sealed partial class MainWindow
ServicesGrid.ItemsSource = new[] {
new InspectorItemViewModel("Fuel", prop.FuelServiceState.ToString()),
new InspectorItemViewModel("Coolant", prop.CoolantServiceState.ToString()),
- new InspectorItemViewModel("Electricity", prop.ElectricityServiceState.ToString()),
+ new InspectorItemViewModel("Electricity", prop.ElectricityServiceState.ToString())
};
var surface = m_Level.GetSurface(position);
ConsumersGrid.ItemsSource = new[] {
new InspectorItemViewModel("Fuel", surface.FuelBlockTurns.ToString()),
new InspectorItemViewModel("Coolant", surface.CoolantBlockTurns.ToString()),
- new InspectorItemViewModel("Electricity", surface.ElectricityBlockTurns.ToString()),
+ new InspectorItemViewModel("Electricity", surface.ElectricityBlockTurns.ToString())
};
LeaksGrid.ItemsSource = m_Level.Leaks.Select(leak => new InspectorItemViewModel(leak.Carrier.ToString(), $"{leak.UndergroundPosition.X}, {leak.UndergroundPosition.Y}"));
SurfaceGrid.ItemsSource = SurfaceInspectionItems(position);
@@ -1267,7 +1306,7 @@ public sealed partial class MainWindow
{
m_Level = m_Level with { Forecasts = m_Simulation.Forecast(m_Level) };
}
-
+
public GridPosition? HoverCell { get; private set; }
private const double c_MinZoom = 0.5;