Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
98d72d0db8
commit
45ad602d9a
@ -74,6 +74,9 @@ final class GameState {
|
|||||||
/// Index of the hand currently being played.
|
/// Index of the hand currently being played.
|
||||||
private(set) var activeHandIndex: Int = 0
|
private(set) var activeHandIndex: Int = 0
|
||||||
|
|
||||||
|
/// Whether an action is currently being processed (prevents double-tap issues).
|
||||||
|
private(set) var isProcessingAction: Bool = false
|
||||||
|
|
||||||
/// The active player hand.
|
/// The active player hand.
|
||||||
var activeHand: BlackjackHand? {
|
var activeHand: BlackjackHand? {
|
||||||
guard activeHandIndex < playerHands.count else { return nil }
|
guard activeHandIndex < playerHands.count else { return nil }
|
||||||
@ -184,18 +187,21 @@ final class GameState {
|
|||||||
|
|
||||||
/// Whether the current hand can hit.
|
/// Whether the current hand can hit.
|
||||||
var canHit: Bool {
|
var canHit: Bool {
|
||||||
|
guard !isProcessingAction else { return false }
|
||||||
guard case .playerTurn = currentPhase else { return false }
|
guard case .playerTurn = currentPhase else { return false }
|
||||||
return activeHand?.canHit ?? false
|
return activeHand?.canHit ?? false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the current hand can stand.
|
/// Whether the current hand can stand.
|
||||||
var canStand: Bool {
|
var canStand: Bool {
|
||||||
|
guard !isProcessingAction else { return false }
|
||||||
guard case .playerTurn = currentPhase else { return false }
|
guard case .playerTurn = currentPhase else { return false }
|
||||||
return !(activeHand?.isBusted ?? true)
|
return !(activeHand?.isBusted ?? true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the current hand can double.
|
/// Whether the current hand can double.
|
||||||
var canDouble: Bool {
|
var canDouble: Bool {
|
||||||
|
guard !isProcessingAction else { return false }
|
||||||
guard case .playerTurn = currentPhase else { return false }
|
guard case .playerTurn = currentPhase else { return false }
|
||||||
guard let hand = activeHand else { return false }
|
guard let hand = activeHand else { return false }
|
||||||
return engine.canDoubleDown(hand: hand, balance: balance)
|
return engine.canDoubleDown(hand: hand, balance: balance)
|
||||||
@ -203,6 +209,7 @@ final class GameState {
|
|||||||
|
|
||||||
/// Whether the current hand can split.
|
/// Whether the current hand can split.
|
||||||
var canSplit: Bool {
|
var canSplit: Bool {
|
||||||
|
guard !isProcessingAction else { return false }
|
||||||
guard case .playerTurn = currentPhase else { return false }
|
guard case .playerTurn = currentPhase else { return false }
|
||||||
guard let hand = activeHand else { return false }
|
guard let hand = activeHand else { return false }
|
||||||
let splitCount = playerHands.count - 1
|
let splitCount = playerHands.count - 1
|
||||||
@ -211,6 +218,7 @@ final class GameState {
|
|||||||
|
|
||||||
/// Whether the player can surrender.
|
/// Whether the player can surrender.
|
||||||
var canSurrender: Bool {
|
var canSurrender: Bool {
|
||||||
|
guard !isProcessingAction else { return false }
|
||||||
guard case .playerTurn = currentPhase else { return false }
|
guard case .playerTurn = currentPhase else { return false }
|
||||||
guard let hand = activeHand else { return false }
|
guard let hand = activeHand else { return false }
|
||||||
return engine.canSurrender(hand: hand)
|
return engine.canSurrender(hand: hand)
|
||||||
@ -445,11 +453,18 @@ final class GameState {
|
|||||||
// Ensure enough cards for a full hand - reshuffle if needed
|
// Ensure enough cards for a full hand - reshuffle if needed
|
||||||
if !engine.canDealNewHand {
|
if !engine.canDealNewHand {
|
||||||
engine.reshuffle()
|
engine.reshuffle()
|
||||||
showReshuffleNotification = true
|
|
||||||
|
|
||||||
|
// Show notification with animation
|
||||||
|
withAnimation(.spring(duration: Design.Animation.springDuration)) {
|
||||||
|
showReshuffleNotification = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-dismiss after 2 seconds
|
||||||
Task {
|
Task {
|
||||||
try? await Task.sleep(for: .seconds(2))
|
try? await Task.sleep(for: .seconds(2))
|
||||||
showReshuffleNotification = false
|
withAnimation(.spring(duration: Design.Animation.springDuration)) {
|
||||||
|
showReshuffleNotification = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,6 +597,9 @@ final class GameState {
|
|||||||
/// Player hits (takes another card).
|
/// Player hits (takes another card).
|
||||||
func hit() async {
|
func hit() async {
|
||||||
guard canHit else { return }
|
guard canHit else { return }
|
||||||
|
isProcessingAction = true
|
||||||
|
defer { isProcessingAction = false }
|
||||||
|
|
||||||
guard let card = engine.dealCard() else { return }
|
guard let card = engine.dealCard() else { return }
|
||||||
|
|
||||||
playerHands[activeHandIndex].cards.append(card)
|
playerHands[activeHandIndex].cards.append(card)
|
||||||
@ -600,6 +618,8 @@ final class GameState {
|
|||||||
/// Player stands.
|
/// Player stands.
|
||||||
func stand() async {
|
func stand() async {
|
||||||
guard canStand else { return }
|
guard canStand else { return }
|
||||||
|
isProcessingAction = true
|
||||||
|
defer { isProcessingAction = false }
|
||||||
|
|
||||||
playerHands[activeHandIndex].isStanding = true
|
playerHands[activeHandIndex].isStanding = true
|
||||||
await moveToNextHand()
|
await moveToNextHand()
|
||||||
@ -608,6 +628,8 @@ final class GameState {
|
|||||||
/// Player doubles down.
|
/// Player doubles down.
|
||||||
func doubleDown() async {
|
func doubleDown() async {
|
||||||
guard canDouble else { return }
|
guard canDouble else { return }
|
||||||
|
isProcessingAction = true
|
||||||
|
defer { isProcessingAction = false }
|
||||||
|
|
||||||
let additionalBet = playerHands[activeHandIndex].bet
|
let additionalBet = playerHands[activeHandIndex].bet
|
||||||
balance -= additionalBet
|
balance -= additionalBet
|
||||||
@ -632,6 +654,8 @@ final class GameState {
|
|||||||
/// Player splits the hand.
|
/// Player splits the hand.
|
||||||
func split() async {
|
func split() async {
|
||||||
guard canSplit else { return }
|
guard canSplit else { return }
|
||||||
|
isProcessingAction = true
|
||||||
|
defer { isProcessingAction = false }
|
||||||
|
|
||||||
let originalHand = playerHands[activeHandIndex]
|
let originalHand = playerHands[activeHandIndex]
|
||||||
let splitCard = originalHand.cards[1]
|
let splitCard = originalHand.cards[1]
|
||||||
@ -676,6 +700,8 @@ final class GameState {
|
|||||||
/// Player surrenders.
|
/// Player surrenders.
|
||||||
func surrender() async {
|
func surrender() async {
|
||||||
guard canSurrender else { return }
|
guard canSurrender else { return }
|
||||||
|
isProcessingAction = true
|
||||||
|
defer { isProcessingAction = false }
|
||||||
|
|
||||||
playerHands[activeHandIndex].result = .surrender
|
playerHands[activeHandIndex].result = .surrender
|
||||||
await completeRound()
|
await completeRound()
|
||||||
@ -964,12 +990,19 @@ final class GameState {
|
|||||||
// Check if shoe needs reshuffling
|
// Check if shoe needs reshuffling
|
||||||
if engine.needsReshuffle {
|
if engine.needsReshuffle {
|
||||||
engine.reshuffle()
|
engine.reshuffle()
|
||||||
showReshuffleNotification = true
|
|
||||||
|
|
||||||
// Auto-dismiss after a delay
|
// Show notification after delay so it appears after result banner is dismissed
|
||||||
Task {
|
Task {
|
||||||
try? await Task.sleep(for: .seconds(2))
|
try? await Task.sleep(for: .seconds(2))
|
||||||
showReshuffleNotification = false
|
withAnimation(.spring(duration: Design.Animation.springDuration)) {
|
||||||
|
showReshuffleNotification = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-dismiss after showing for 2 seconds
|
||||||
|
try? await Task.sleep(for: .seconds(2))
|
||||||
|
withAnimation(.spring(duration: Design.Animation.springDuration)) {
|
||||||
|
showReshuffleNotification = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -136,13 +136,6 @@ struct GameTableView: View {
|
|||||||
.frame(maxWidth: maxContentWidth)
|
.frame(maxWidth: maxContentWidth)
|
||||||
.debugBorder(showDebugBorders, color: .cyan, label: "TopBar")
|
.debugBorder(showDebugBorders, color: .cyan, label: "TopBar")
|
||||||
|
|
||||||
// Reshuffle notification
|
|
||||||
if state.showReshuffleNotification {
|
|
||||||
ReshuffleNotificationView(showCardCount: settings.showCardCount)
|
|
||||||
.frame(maxWidth: maxContentWidth)
|
|
||||||
.transition(.move(edge: .top).combined(with: .opacity))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Table layout
|
// Table layout
|
||||||
BlackjackTableView(
|
BlackjackTableView(
|
||||||
state: state,
|
state: state,
|
||||||
@ -178,6 +171,13 @@ struct GameTableView: View {
|
|||||||
Design.debugLog("🔄 Phase changed: \(oldPhase) → \(newPhase)")
|
Design.debugLog("🔄 Phase changed: \(oldPhase) → \(newPhase)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reshuffle notification overlay (centered, floating)
|
||||||
|
if state.showReshuffleNotification {
|
||||||
|
ReshuffleNotificationView(showCardCount: settings.showCardCount)
|
||||||
|
.transition(.scale.combined(with: .opacity))
|
||||||
|
.zIndex(50)
|
||||||
|
}
|
||||||
|
|
||||||
// Insurance popup overlay (covers entire screen)
|
// Insurance popup overlay (covers entire screen)
|
||||||
if state.currentPhase == .insurance {
|
if state.currentPhase == .insurance {
|
||||||
Color.clear
|
Color.clear
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user