diff --git a/src/Koogle.Web/Components/Game/GameInputPanel.razor b/src/Koogle.Web/Components/Game/GameInputPanel.razor
index 9483c08..6dffcc3 100644
--- a/src/Koogle.Web/Components/Game/GameInputPanel.razor
+++ b/src/Koogle.Web/Components/Game/GameInputPanel.razor
@@ -280,7 +280,15 @@
private async Task HandleGutterClick(bool isLeft)
{
// Gutter = 0 pins fallen, auto-confirm throw
- Dispatcher.Dispatch(new ResetPinsAction());
+ // In Decrease mode, preserve disabled pins (already knocked down)
+ if (GameState.Value.ThrowPanelAfter.ThrowMode == ThrowMode.Decrease)
+ {
+ Dispatcher.Dispatch(new ClearFallenPinsAction());
+ }
+ else
+ {
+ Dispatcher.Dispatch(new ResetPinsAction());
+ }
_selectedNumber = 0;
await ConfirmThrow(isGutter: true, isLeftGutter: isLeft);
diff --git a/src/Koogle.Web/Store/GameState/GameActions.cs b/src/Koogle.Web/Store/GameState/GameActions.cs
index 5b4e2dc..0e000df 100644
--- a/src/Koogle.Web/Store/GameState/GameActions.cs
+++ b/src/Koogle.Web/Store/GameState/GameActions.cs
@@ -151,6 +151,12 @@ public record SetPinStatusAction(int PinNumber, PinStatus Status);
///
public record ResetPinsAction;
+///
+/// Action to clear fallen pins (set to standing) while preserving disabled pins.
+/// Used in Decrease mode for gutter throws.
+///
+public record ClearFallenPinsAction;
+
///
/// Action to set the bell value.
///
diff --git a/src/Koogle.Web/Store/GameState/GameReducers.cs b/src/Koogle.Web/Store/GameState/GameReducers.cs
index b2a35c3..a8134ef 100644
--- a/src/Koogle.Web/Store/GameState/GameReducers.cs
+++ b/src/Koogle.Web/Store/GameState/GameReducers.cs
@@ -309,6 +309,16 @@ public static class GameReducers
ThrowPanelAfter = state.ThrowPanelAfter.ResetPins()
};
+ ///
+ /// Handles ClearFallenPinsAction - clears fallen pins while preserving disabled.
+ ///
+ [ReducerMethod(typeof(ClearFallenPinsAction))]
+ public static GameState OnClearFallenPins(GameState state)
+ => state with
+ {
+ ThrowPanelAfter = state.ThrowPanelAfter.ClearFallenPins()
+ };
+
///
/// Handles SetBellValueAction - sets bell value.
///
diff --git a/src/Koogle.Web/Store/GameState/GameState.cs b/src/Koogle.Web/Store/GameState/GameState.cs
index 67c25a4..ad2cabd 100644
--- a/src/Koogle.Web/Store/GameState/GameState.cs
+++ b/src/Koogle.Web/Store/GameState/GameState.cs
@@ -297,6 +297,23 @@ public record ThrowPanelState
Pin9 = Pin9 == PinStatus.Fallen ? PinStatus.Disabled : Pin9
};
+ ///
+ /// Clears fallen pins (sets to standing) while preserving disabled pins.
+ /// Used for gutter throws in Decrease mode.
+ ///
+ public ThrowPanelState ClearFallenPins() => this with
+ {
+ Pin1 = Pin1 == PinStatus.Fallen ? PinStatus.Standing : Pin1,
+ Pin2 = Pin2 == PinStatus.Fallen ? PinStatus.Standing : Pin2,
+ Pin3 = Pin3 == PinStatus.Fallen ? PinStatus.Standing : Pin3,
+ Pin4 = Pin4 == PinStatus.Fallen ? PinStatus.Standing : Pin4,
+ Pin5 = Pin5 == PinStatus.Fallen ? PinStatus.Standing : Pin5,
+ Pin6 = Pin6 == PinStatus.Fallen ? PinStatus.Standing : Pin6,
+ Pin7 = Pin7 == PinStatus.Fallen ? PinStatus.Standing : Pin7,
+ Pin8 = Pin8 == PinStatus.Fallen ? PinStatus.Standing : Pin8,
+ Pin9 = Pin9 == PinStatus.Fallen ? PinStatus.Standing : Pin9
+ };
+
///
/// Checks if all pins are knocked down (fallen or disabled).
///