diff --git a/src/Koogle.Application/Games/GameProgress.cs b/src/Koogle.Application/Games/GameProgress.cs index 53dae84..04c61b5 100644 --- a/src/Koogle.Application/Games/GameProgress.cs +++ b/src/Koogle.Application/Games/GameProgress.cs @@ -22,6 +22,7 @@ public record BeforeThrowState( /// Whether all 9 pins were knocked down. /// Whether the throw was a gutter (Rinne). /// Whether all remaining pins are hit (Abgeräumt). +/// Whether bell was active in this throw. public record AfterThrowState( ThrowPanelSnapshot ThrowPanel, Guid CurrentPlayerId, @@ -29,7 +30,8 @@ public record AfterThrowState( bool IsCircle, bool IsStrike, bool IsGutter, - bool IsCleared + bool IsCleared, + bool IsBell ); /// @@ -162,11 +164,13 @@ public static class GameProgressExtensions /// Snapshot before the throw. /// Current player ID. /// Whether the throw went into the gutter (from user input). + /// Whether the throw activated the bell (from user input). public static AfterThrowState CreateAfterThrowState( this ThrowPanelSnapshot afterThrow, ThrowPanelSnapshot beforeThrow, Guid playerId, - bool isGutter = false) + bool isGutter = false, + bool isBell = false) { var pinsKnockedBefore = beforeThrow.PinCount(); var pinsKnockedAfter = afterThrow.PinCount(); @@ -179,7 +183,8 @@ public static class GameProgressExtensions IsCircle: afterThrow.IsCircle(), IsStrike: afterThrow.IsStrike(), IsGutter: isGutter, - IsCleared: afterThrow.IsCleared() + IsCleared: afterThrow.IsCleared(), + IsBell: isBell ); } } diff --git a/src/Koogle.Application/Games/Training/TrainingGameLogicService.cs b/src/Koogle.Application/Games/Training/TrainingGameLogicService.cs index d4df1c9..42ababa 100644 --- a/src/Koogle.Application/Games/Training/TrainingGameLogicService.cs +++ b/src/Koogle.Application/Games/Training/TrainingGameLogicService.cs @@ -63,7 +63,7 @@ public class TrainingGameLogicService : IGameLogicService stats.ClearedCount++; } - if (afterThrow.ThrowPanel.BellValue) + if (afterThrow.IsBell) { stats.BellCount++; } diff --git a/src/Koogle.Web/Components/Shared/PlayerStatisticsChart.razor b/src/Koogle.Web/Components/Shared/PlayerStatisticsChart.razor index e38f585..ccdd229 100644 --- a/src/Koogle.Web/Components/Shared/PlayerStatisticsChart.razor +++ b/src/Koogle.Web/Components/Shared/PlayerStatisticsChart.razor @@ -70,6 +70,13 @@ else if (_stats != null) SeriesType="SeriesType.Bar" XValue="e => e.Name" YValue="e => e.TotalCleared" /> + + } } @@ -88,6 +95,7 @@ else if (_stats != null) public int TotalStrikes { get; set; } public int TotalCircles { get; set; } public int TotalCleared { get; set; } + public int TotalBells { get; set; } } @@ -111,7 +119,8 @@ else if (_stats != null) TotalThrows = s.TotalThrows, TotalStrikes = s.TotalStrikes, TotalCircles = s.TotalCircles, - TotalCleared = s.TotalCleared + TotalCleared = s.TotalCleared, + TotalBells = s.TotalBells }) ); } diff --git a/src/Koogle.Web/Store/GameState/GameEffects.cs b/src/Koogle.Web/Store/GameState/GameEffects.cs index 6b5479d..7895054 100644 --- a/src/Koogle.Web/Store/GameState/GameEffects.cs +++ b/src/Koogle.Web/Store/GameState/GameEffects.cs @@ -363,7 +363,8 @@ 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, action.IsGutter); + var afterThrowState = afterSnapshot.CreateAfterThrowState(beforeSnapshot, + currentPlayerId.Value, action.IsGutter, action.AfterThrowState.BellValue); // Default values bool shouldRotatePlayer = false; @@ -440,7 +441,7 @@ public class GameEffects // Fire expense triggers for special throw events // Note: Use action.AfterThrowState.BellValue since afterThrowState has BellValue reset to false - await FireThrowTriggersAsync(state, currentPlayerId.Value, action, afterThrowState, action.AfterThrowState.BellValue, dispatcher); + await FireThrowTriggersAsync(state, currentPlayerId.Value, action, afterThrowState, dispatcher); // Record player statistics (game-type independent) await RecordPlayerStatisticsAsync(state, currentPlayerId.Value, afterThrowState); @@ -893,7 +894,6 @@ public class GameEffects Guid currentPlayerId, RecordThrowAction action, AfterThrowState afterThrowState, - bool bellValue, IDispatcher dispatcher) { // Skip if no day or game context @@ -991,7 +991,7 @@ public class GameEffects } // Check for Bell hit - if (bellValue) + if (afterThrowState.IsBell) { var expenses = await _gameEventService.RegisterBellAsync( currentPlayerId, @@ -1016,7 +1016,7 @@ public class GameEffects } // Trigger GIF playback for special events - await TriggerGifForEventsAsync(state, gameId, action, afterThrowState, bellValue, dispatcher); + await TriggerGifForEventsAsync(state, gameId, action, afterThrowState, dispatcher); } catch (Exception ex) { @@ -1034,7 +1034,6 @@ public class GameEffects Guid gameId, RecordThrowAction action, AfterThrowState afterThrowState, - bool bellValue, IDispatcher dispatcher) { var clubId = _clubContext.ClubId; @@ -1049,7 +1048,7 @@ public class GameEffects { triggeredEvent = ThrowEventType.Circle; } - else if (bellValue) + else if (afterThrowState.IsBell) { triggeredEvent = ThrowEventType.Bell; } @@ -1188,7 +1187,7 @@ public class GameEffects afterThrowState.IsGutter, afterThrowState.IsCircle, afterThrowState.IsStrike, - afterThrowState.ThrowPanel.BellValue); + afterThrowState.IsBell); } catch (Exception ex) {