diff --git a/src/Koogle.Application/Games/GameProgress.cs b/src/Koogle.Application/Games/GameProgress.cs
index 14335f6..fbb556b 100644
--- a/src/Koogle.Application/Games/GameProgress.cs
+++ b/src/Koogle.Application/Games/GameProgress.cs
@@ -147,10 +147,15 @@ public static class GameProgressExtensions
///
/// Creates after-throw state from before and after snapshots.
///
+ /// Snapshot after the throw.
+ /// Snapshot before the throw.
+ /// Current player ID.
+ /// Whether the throw went into the gutter (from user input).
public static AfterThrowState CreateAfterThrowState(
this ThrowPanelSnapshot afterThrow,
ThrowPanelSnapshot beforeThrow,
- Guid playerId)
+ Guid playerId,
+ bool isGutter = false)
{
var pinsKnockedBefore = beforeThrow.PinCount();
var pinsKnockedAfter = afterThrow.PinCount();
@@ -162,7 +167,7 @@ public static class GameProgressExtensions
PinsKnocked: pinsKnocked,
IsCircle: afterThrow.IsCircle(),
IsStrike: afterThrow.IsStrike(),
- IsGutter: pinsKnocked == 0
+ IsGutter: isGutter
);
}
}
diff --git a/src/Koogle.Web/Components/Game/GameInputPanel.razor b/src/Koogle.Web/Components/Game/GameInputPanel.razor
index 423a49f..2386fda 100644
--- a/src/Koogle.Web/Components/Game/GameInputPanel.razor
+++ b/src/Koogle.Web/Components/Game/GameInputPanel.razor
@@ -276,7 +276,7 @@
var beforeState = _beforeThrowState ?? currentThrowPanel;
// Dispatch record throw action - game logic will handle pin reset and player rotation
- Dispatcher.Dispatch(new RecordThrowAction(beforeState, currentThrowPanel));
+ Dispatcher.Dispatch(new RecordThrowAction(beforeState, currentThrowPanel, isGutter, isLeftGutter));
// Reset local state
_selectedNumber = null;
diff --git a/src/Koogle.Web/Store/GameState/GameActions.cs b/src/Koogle.Web/Store/GameState/GameActions.cs
index 4f12952..9ce6f63 100644
--- a/src/Koogle.Web/Store/GameState/GameActions.cs
+++ b/src/Koogle.Web/Store/GameState/GameActions.cs
@@ -106,7 +106,9 @@ public record LoadCompletedGamesFailureAction(string Error);
///
/// State before the throw was made.
/// State after the throw was made.
-public record RecordThrowAction(ThrowPanelState BeforeThrowState, ThrowPanelState AfterThrowState);
+/// Whether the throw went into the gutter.
+/// Whether it was the left gutter.
+public record RecordThrowAction(ThrowPanelState BeforeThrowState, ThrowPanelState AfterThrowState, bool IsGutter = false, bool IsLeftGutter = false);
///
/// Action dispatched after ProcessThrow completes with game logic result.
diff --git a/src/Koogle.Web/Store/GameState/GameEffects.cs b/src/Koogle.Web/Store/GameState/GameEffects.cs
index 2c3d299..8f61bef 100644
--- a/src/Koogle.Web/Store/GameState/GameEffects.cs
+++ b/src/Koogle.Web/Store/GameState/GameEffects.cs
@@ -310,7 +310,7 @@ public class GameEffects
// Create AfterThrowState for game logic with updated counters
var beforeSnapshot = CreateThrowPanelSnapshot(action.BeforeThrowState);
var afterSnapshot = CreateThrowPanelSnapshot(newThrowPanel);
- var afterThrowState = afterSnapshot.CreateAfterThrowState(beforeSnapshot, currentPlayerId.Value);
+ var afterThrowState = afterSnapshot.CreateAfterThrowState(beforeSnapshot, currentPlayerId.Value, action.IsGutter);
// Default values
bool shouldRotatePlayer = false;