Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
8d222317a0
commit
100eb83422
@ -48,9 +48,12 @@ enum Design {
|
||||
static let mainBetRowHeight: CGFloat = 50
|
||||
static let bonusZoneWidth: CGFloat = 80
|
||||
|
||||
// Labels
|
||||
// Labels (matches Blackjack for consistency)
|
||||
static let labelFontSize: CGFloat = 14
|
||||
static let labelRowHeight: CGFloat = 30
|
||||
static let handLabelFontSize: CGFloat = 14
|
||||
static let handNumberFontSize: CGFloat = 12
|
||||
static let handIconSize: CGFloat = 18
|
||||
|
||||
// Buttons
|
||||
static let bettingButtonsContainerHeight: CGFloat = 70
|
||||
|
||||
@ -62,13 +62,13 @@ struct CardsDisplayArea: View {
|
||||
|
||||
private var showDebugBorders: Bool { Design.showDebugBorders }
|
||||
|
||||
private var labelFontSize: CGFloat {
|
||||
isLargeScreen ? 18 : Design.Size.labelFontSize
|
||||
}
|
||||
// MARK: - Scaled Metrics (Dynamic Type)
|
||||
// These match Blackjack's HandLabelView for consistency
|
||||
|
||||
private var labelRowMinHeight: CGFloat {
|
||||
isLargeScreen ? 40 : Design.Size.labelRowHeight
|
||||
}
|
||||
@ScaledMetric(relativeTo: .headline) private var labelFontSize: CGFloat = Design.Size.handLabelFontSize
|
||||
@ScaledMetric(relativeTo: .headline) private var badgeHeight: CGFloat = CasinoDesign.Size.valueBadge
|
||||
@ScaledMetric(relativeTo: .caption) private var betFontSize: CGFloat = Design.Size.handNumberFontSize
|
||||
@ScaledMetric(relativeTo: .body) private var iconSize: CGFloat = Design.Size.handIconSize
|
||||
|
||||
/// Whether Player hand should be on bottom in vertical mode.
|
||||
private var playerOnBottom: Bool {
|
||||
@ -225,15 +225,16 @@ struct CardsDisplayArea: View {
|
||||
// MARK: - Private Views
|
||||
|
||||
/// Bet amount display shown below the bottom hand during dealing.
|
||||
/// Matches Blackjack's PlayerHandView bet display styling.
|
||||
@ViewBuilder
|
||||
private var betAmountDisplay: some View {
|
||||
if totalBetAmount > 0 {
|
||||
HStack(spacing: Design.Spacing.xSmall) {
|
||||
Image(systemName: "dollarsign.circle.fill")
|
||||
.font(.system(size: Design.BaseFontSize.xLarge))
|
||||
.font(.system(size: iconSize))
|
||||
.foregroundStyle(.yellow)
|
||||
Text("\(totalBetAmount)")
|
||||
.font(.system(size: Design.BaseFontSize.medium, weight: .bold, design: .rounded))
|
||||
.font(.system(size: betFontSize, weight: .bold, design: .rounded))
|
||||
.foregroundStyle(.yellow)
|
||||
}
|
||||
.padding(.top, Design.Spacing.medium)
|
||||
@ -265,7 +266,8 @@ struct CardsDisplayArea: View {
|
||||
.animation(nil, value: visibleValue) // No animation when value changes
|
||||
}
|
||||
}
|
||||
.frame(minHeight: labelRowMinHeight)
|
||||
.fixedSize() // Prevent the label from being constrained/truncated
|
||||
.frame(minHeight: badgeHeight)
|
||||
|
||||
CompactHandView(
|
||||
cards: playerCards,
|
||||
@ -316,7 +318,8 @@ struct CardsDisplayArea: View {
|
||||
.animation(nil, value: visibleValue) // No animation when value changes
|
||||
}
|
||||
}
|
||||
.frame(minHeight: labelRowMinHeight)
|
||||
.fixedSize() // Prevent the label from being constrained/truncated
|
||||
.frame(minHeight: badgeHeight)
|
||||
|
||||
CompactHandView(
|
||||
cards: bankerCards,
|
||||
|
||||
@ -86,6 +86,18 @@ struct CompactHandView: View {
|
||||
cards.isEmpty ? placeholderSpacing : cardSpacing
|
||||
}
|
||||
|
||||
/// The actual width of the cards content (for winner border sizing)
|
||||
private var cardsContentWidth: CGFloat {
|
||||
if cards.isEmpty {
|
||||
// 2 placeholders with spacing
|
||||
return (2 * placeholderWidth) + placeholderSpacing
|
||||
} else {
|
||||
// N cards with (N-1) spacings
|
||||
let cardCount = CGFloat(cards.count)
|
||||
return (cardCount * cardWidth) + ((cardCount - 1) * cardSpacing)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Body
|
||||
|
||||
var body: some View {
|
||||
@ -94,15 +106,13 @@ struct CompactHandView: View {
|
||||
|
||||
if isLargeScreen || !isDealing {
|
||||
// iPad or betting phase: Simple centered layout - no scrolling needed
|
||||
cardsContent
|
||||
.padding(.horizontal, Design.Spacing.medium)
|
||||
cardsContentWithBorder
|
||||
.frame(width: availableWidth, alignment: .center)
|
||||
} else {
|
||||
// iPhone dealing phase: Use ScrollView for 3rd card
|
||||
ScrollViewReader { proxy in
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
cardsContent
|
||||
.padding(.horizontal, Design.Spacing.medium)
|
||||
cardsContentWithBorder
|
||||
.frame(minWidth: availableWidth, alignment: .center)
|
||||
.id("cards_container")
|
||||
}
|
||||
@ -131,17 +141,23 @@ struct CompactHandView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(height: cardHeight)
|
||||
.frame(height: cardHeight + (isWinner ? Design.Spacing.small * 2 : 0))
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, isWinner ? Design.Spacing.small : 0)
|
||||
.background(winnerBorder)
|
||||
.overlay(alignment: .bottom) {
|
||||
winBadge
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private Views
|
||||
|
||||
/// Cards content wrapped with the winner border sized to fit the actual cards
|
||||
private var cardsContentWithBorder: some View {
|
||||
cardsContent
|
||||
.padding(.horizontal, Design.Spacing.medium)
|
||||
.padding(.vertical, isWinner ? Design.Spacing.small : 0)
|
||||
.background(winnerBorder)
|
||||
.overlay(alignment: .bottom) {
|
||||
winBadge
|
||||
}
|
||||
}
|
||||
|
||||
private var cardsContent: some View {
|
||||
HStack(spacing: effectiveSpacing) {
|
||||
if cards.isEmpty {
|
||||
|
||||
@ -2,40 +2,25 @@
|
||||
// HandValueBadge.swift
|
||||
// Baccarat
|
||||
//
|
||||
// A circular badge displaying the hand value.
|
||||
// A capsule badge displaying the hand value.
|
||||
// Matches CasinoKit's ValueBadge styling for consistency with Blackjack.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import CasinoKit
|
||||
|
||||
/// A small circular badge showing the hand value.
|
||||
/// A capsule badge showing the hand value.
|
||||
/// Uses the same styling as CasinoKit's ValueBadge for consistency across games.
|
||||
struct HandValueBadge: View {
|
||||
let value: Int
|
||||
let color: Color
|
||||
|
||||
// MARK: - Environment
|
||||
// MARK: - Scaled Metrics (Dynamic Type)
|
||||
// These match CasinoKit's ValueBadge exactly
|
||||
|
||||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||
|
||||
// MARK: - Computed Properties
|
||||
|
||||
/// Whether we're on a large screen (iPad)
|
||||
private var isLargeScreen: Bool {
|
||||
horizontalSizeClass == .regular
|
||||
}
|
||||
|
||||
@ScaledMetric(relativeTo: .headline) private var baseValueFontSize: CGFloat = 15
|
||||
@ScaledMetric(relativeTo: .headline) private var baseBadgeSize: CGFloat = 26
|
||||
|
||||
/// Font size - larger on iPad
|
||||
private var valueFontSize: CGFloat {
|
||||
isLargeScreen ? baseValueFontSize * 1.5 : baseValueFontSize
|
||||
}
|
||||
|
||||
/// Badge size - larger on iPad
|
||||
private var badgeSize: CGFloat {
|
||||
isLargeScreen ? baseBadgeSize * 1.5 : baseBadgeSize
|
||||
}
|
||||
@ScaledMetric(relativeTo: .headline) private var valueFontSize: CGFloat = 15
|
||||
@ScaledMetric(relativeTo: .headline) private var badgeHeight: CGFloat = CasinoDesign.Size.valueBadge
|
||||
@ScaledMetric(relativeTo: .headline) private var badgePadding: CGFloat = 8
|
||||
|
||||
// MARK: - Body
|
||||
|
||||
@ -43,9 +28,12 @@ struct HandValueBadge: View {
|
||||
Text("\(value)")
|
||||
.font(.system(size: valueFontSize, weight: .black, design: .rounded))
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: badgeSize, height: badgeSize)
|
||||
.lineLimit(1)
|
||||
.fixedSize(horizontal: true, vertical: false)
|
||||
.padding(.horizontal, badgePadding)
|
||||
.frame(minWidth: badgeHeight, minHeight: badgeHeight)
|
||||
.background(
|
||||
Circle()
|
||||
Capsule()
|
||||
.fill(color)
|
||||
)
|
||||
}
|
||||
|
||||
@ -29,9 +29,6 @@ struct InteractiveCardView: View {
|
||||
isWaiting && !isFaceUp && isBottomHand && revealStyle != .auto && !isInteracting
|
||||
}
|
||||
|
||||
/// Animation state for the pulsing glow
|
||||
@State private var glowPulse = false
|
||||
|
||||
/// Tracks if we just completed a squeeze reveal (to skip flip animation)
|
||||
@State private var squeezeJustCompleted = false
|
||||
|
||||
@ -44,21 +41,18 @@ struct InteractiveCardView: View {
|
||||
// Glow layer - completely separate from the card, sits underneath
|
||||
GlowBackgroundView(
|
||||
isActive: showGlow,
|
||||
glowPulse: glowPulse,
|
||||
shouldPulse: showGlow,
|
||||
cardWidth: cardWidth
|
||||
)
|
||||
// Force recreation on size change to avoid stale dimensions during rotation
|
||||
.id("glow-\(Int(cardWidth))")
|
||||
|
||||
// Card layer - completely independent, no glow modifiers
|
||||
cardContent
|
||||
}
|
||||
.onAppear {
|
||||
if showGlow {
|
||||
glowPulse = true
|
||||
}
|
||||
}
|
||||
.onChange(of: showGlow) { _, newValue in
|
||||
glowPulse = newValue
|
||||
}
|
||||
// Explicit frame ensures card and glow stay synced during size changes
|
||||
.frame(width: cardWidth, height: cardHeight)
|
||||
.animation(.easeOut(duration: 0.3), value: cardWidth)
|
||||
.onChange(of: isWaiting) { _, newValue in
|
||||
// Reset interaction state when this card is no longer waiting
|
||||
if !newValue {
|
||||
@ -154,9 +148,12 @@ private struct VerticalFlipCardView: View {
|
||||
/// Completely separate from the card view to avoid any state changes affecting the card.
|
||||
private struct GlowBackgroundView: View {
|
||||
let isActive: Bool
|
||||
let glowPulse: Bool
|
||||
let shouldPulse: Bool
|
||||
let cardWidth: CGFloat
|
||||
|
||||
/// Internal animation state - starts false so animation triggers on appear
|
||||
@State private var animatingPulse = false
|
||||
|
||||
/// Corner radius matching CasinoKit's CardView
|
||||
private var cornerRadius: CGFloat {
|
||||
cardWidth * 0.08
|
||||
@ -170,15 +167,15 @@ private struct GlowBackgroundView: View {
|
||||
ZStack {
|
||||
// Outer glow strokes (largest to smallest for layered glow)
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(Color.orange.opacity(glowPulse ? 0.6 : 0.2), lineWidth: glowPulse ? 20 : 10)
|
||||
.stroke(Color.orange.opacity(animatingPulse ? 0.6 : 0.2), lineWidth: animatingPulse ? 20 : 10)
|
||||
.blur(radius: 10)
|
||||
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(Color.yellow.opacity(glowPulse ? 0.8 : 0.3), lineWidth: glowPulse ? 12 : 6)
|
||||
.stroke(Color.yellow.opacity(animatingPulse ? 0.8 : 0.3), lineWidth: animatingPulse ? 12 : 6)
|
||||
.blur(radius: 6)
|
||||
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(Color.yellow.opacity(glowPulse ? 1.0 : 0.5), lineWidth: glowPulse ? 6 : 3)
|
||||
.stroke(Color.yellow.opacity(animatingPulse ? 1.0 : 0.5), lineWidth: animatingPulse ? 6 : 3)
|
||||
.blur(radius: 3)
|
||||
|
||||
// Bright animated border (sharp, on top)
|
||||
@ -189,16 +186,25 @@ private struct GlowBackgroundView: View {
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
),
|
||||
lineWidth: glowPulse ? 4 : 3
|
||||
lineWidth: animatingPulse ? 4 : 3
|
||||
)
|
||||
}
|
||||
.frame(width: cardWidth, height: cardHeight)
|
||||
.scaleEffect(isActive && glowPulse ? 1.02 : 1.0)
|
||||
.scaleEffect(isActive && animatingPulse ? 1.02 : 1.0)
|
||||
.opacity(isActive ? 1.0 : 0.0)
|
||||
.animation(.easeOut(duration: 0.15), value: isActive)
|
||||
.animation(
|
||||
isActive ? .easeInOut(duration: 0.7).repeatForever(autoreverses: true) : .easeOut(duration: 0.15),
|
||||
value: glowPulse
|
||||
value: animatingPulse
|
||||
)
|
||||
.onAppear {
|
||||
// Start animation after view appears - this ensures the repeating animation triggers
|
||||
if shouldPulse {
|
||||
animatingPulse = true
|
||||
}
|
||||
}
|
||||
.onChange(of: shouldPulse) { _, newValue in
|
||||
animatingPulse = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,8 @@ struct PageCurlView: View {
|
||||
var body: some View {
|
||||
PageCurlRepresentable(
|
||||
currentIndex: $currentIndex,
|
||||
width: width,
|
||||
height: height,
|
||||
onReveal: onReveal,
|
||||
onInteractionStarted: onInteractionStarted,
|
||||
pages: [
|
||||
@ -48,12 +50,15 @@ struct PageCurlView: View {
|
||||
)
|
||||
])
|
||||
.frame(width: width, height: height)
|
||||
.id("page-curl-\(card.id)")
|
||||
// Use both card ID and size to force recreation on rotation
|
||||
.id("page-curl-\(card.id)-\(Int(width))")
|
||||
}
|
||||
}
|
||||
|
||||
private struct PageCurlRepresentable: UIViewControllerRepresentable {
|
||||
@Binding var currentIndex: Int
|
||||
let width: CGFloat
|
||||
let height: CGFloat
|
||||
let onReveal: () -> Void
|
||||
let onInteractionStarted: (() -> Void)?
|
||||
let pages: [AnyView]
|
||||
@ -84,7 +89,10 @@ private struct PageCurlRepresentable: UIViewControllerRepresentable {
|
||||
return pageVC
|
||||
}
|
||||
|
||||
func updateUIViewController(_ pageVC: UIPageViewController, context: Context) { }
|
||||
func updateUIViewController(_ pageVC: UIPageViewController, context: Context) {
|
||||
// Update the page view controller's preferred content size when dimensions change
|
||||
pageVC.preferredContentSize = CGSize(width: width, height: height)
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(self)
|
||||
|
||||
@ -435,7 +435,7 @@ final class GameState: CasinoGameState {
|
||||
|
||||
currentBet += amount
|
||||
balance -= amount
|
||||
sound.play(.chipPlace)
|
||||
sound.playChipPlace()
|
||||
}
|
||||
|
||||
/// Places a side bet (Perfect Pairs or 21+3).
|
||||
@ -452,7 +452,7 @@ final class GameState: CasinoGameState {
|
||||
twentyOnePlusThreeBet += amount
|
||||
}
|
||||
balance -= amount
|
||||
sound.play(.chipPlace)
|
||||
sound.playChipPlace()
|
||||
}
|
||||
|
||||
/// Clears all bets (main and side bets).
|
||||
@ -461,7 +461,7 @@ final class GameState: CasinoGameState {
|
||||
currentBet = 0
|
||||
perfectPairsBet = 0
|
||||
twentyOnePlusThreeBet = 0
|
||||
sound.play(.chipPlace)
|
||||
sound.playClearBets()
|
||||
}
|
||||
|
||||
/// Total amount bet (main + side bets).
|
||||
@ -538,7 +538,7 @@ final class GameState: CasinoGameState {
|
||||
} else {
|
||||
dealerHand.cards.append(card)
|
||||
}
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
|
||||
// Wait for card to appear on screen
|
||||
if cardAppearDelay > 0 {
|
||||
@ -593,7 +593,7 @@ final class GameState: CasinoGameState {
|
||||
|
||||
if playerBJ || dealerBJ {
|
||||
// Reveal dealer card
|
||||
sound.play(.cardFlip)
|
||||
sound.playCardFlip()
|
||||
|
||||
if playerBJ && dealerBJ {
|
||||
// Push
|
||||
@ -625,11 +625,11 @@ final class GameState: CasinoGameState {
|
||||
|
||||
insuranceBet = insuranceAmount
|
||||
balance -= insuranceAmount
|
||||
sound.play(.chipPlace)
|
||||
sound.playChipPlace()
|
||||
|
||||
// Check dealer blackjack
|
||||
if dealerHand.isBlackjack {
|
||||
sound.play(.cardFlip)
|
||||
sound.playCardFlip()
|
||||
// Insurance wins
|
||||
let payout = insuranceBet * 3
|
||||
balance += payout
|
||||
@ -672,7 +672,7 @@ final class GameState: CasinoGameState {
|
||||
guard let card = engine.dealCard() else { return }
|
||||
|
||||
playerHands[activeHandIndex].cards.append(card)
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
|
||||
// Animation timing
|
||||
let animationDuration = Design.Animation.springDuration * settings.dealingSpeed
|
||||
@ -733,12 +733,12 @@ final class GameState: CasinoGameState {
|
||||
let additionalBet = playerHands[activeHandIndex].bet
|
||||
balance -= additionalBet
|
||||
playerHands[activeHandIndex].isDoubledDown = true
|
||||
sound.play(.chipPlace)
|
||||
sound.playChipPlace()
|
||||
|
||||
// Deal one card and stand
|
||||
if let card = engine.dealCard() {
|
||||
playerHands[activeHandIndex].cards.append(card)
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
|
||||
// Animation timing
|
||||
let animationDuration = Design.Animation.springDuration * settings.dealingSpeed
|
||||
@ -792,7 +792,7 @@ final class GameState: CasinoGameState {
|
||||
|
||||
// Deduct bet for second hand
|
||||
balance -= originalHand.bet
|
||||
sound.play(.chipPlace)
|
||||
sound.playChipPlace()
|
||||
|
||||
// Replace original with split hands first (so visible counts are tracked correctly)
|
||||
playerHands.remove(at: activeHandIndex)
|
||||
@ -818,7 +818,7 @@ final class GameState: CasinoGameState {
|
||||
// Deal one card to each hand (with full animation timing for each)
|
||||
if let card1 = engine.dealCard() {
|
||||
playerHands[activeHandIndex].cards.append(card1)
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
|
||||
if cardAppearDelay > 0 {
|
||||
try? await Task.sleep(for: .seconds(cardAppearDelay))
|
||||
@ -831,7 +831,7 @@ final class GameState: CasinoGameState {
|
||||
|
||||
if let card2 = engine.dealCard() {
|
||||
playerHands[activeHandIndex + 1].cards.append(card2)
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
|
||||
if cardAppearDelay > 0 {
|
||||
try? await Task.sleep(for: .seconds(cardAppearDelay))
|
||||
@ -911,7 +911,7 @@ final class GameState: CasinoGameState {
|
||||
dealerHand.cards.append(card)
|
||||
// Mark card as visible immediately - face is visible as soon as card appears
|
||||
dealerVisibleCardCount += 1
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
|
||||
// Wait for animation to complete before checking blackjack
|
||||
if delay > 0 {
|
||||
@ -938,7 +938,7 @@ final class GameState: CasinoGameState {
|
||||
} else {
|
||||
// American style: reveal hole card (card is already in hand)
|
||||
// The flip animation shows the card face at the midpoint (90° rotation)
|
||||
sound.play(.cardFlip)
|
||||
sound.playCardFlip()
|
||||
|
||||
// Wait until card face becomes visible (halfway through flip)
|
||||
if flipMidpointDelay > 0 {
|
||||
@ -962,7 +962,7 @@ final class GameState: CasinoGameState {
|
||||
dealerHand.cards.append(card)
|
||||
// Mark card as visible immediately - face is visible as soon as card appears
|
||||
dealerVisibleCardCount += 1
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
|
||||
// Wait for animation to complete before drawing next card
|
||||
if delay > 0 {
|
||||
@ -1006,7 +1006,7 @@ final class GameState: CasinoGameState {
|
||||
let ppWon = perfectPairsResult?.isWin ?? false
|
||||
let topWon = twentyOnePlusThreeResult?.isWin ?? false
|
||||
if ppWon || topWon {
|
||||
sound.play(.win)
|
||||
sound.playWin()
|
||||
}
|
||||
|
||||
// Auto-hide toasts after delay
|
||||
@ -1186,13 +1186,13 @@ final class GameState: CasinoGameState {
|
||||
// Save game data to iCloud
|
||||
saveGameData()
|
||||
|
||||
// Play appropriate sound
|
||||
// Play appropriate sound with haptic feedback
|
||||
if roundWinnings > 0 {
|
||||
sound.play(.win)
|
||||
sound.playWin()
|
||||
} else if roundWinnings < 0 {
|
||||
sound.play(.lose)
|
||||
sound.playLose()
|
||||
} else {
|
||||
sound.play(.push)
|
||||
sound.playPush()
|
||||
}
|
||||
|
||||
// Reset bet for next round
|
||||
@ -1249,7 +1249,7 @@ final class GameState: CasinoGameState {
|
||||
lastRoundResult = nil
|
||||
currentPhase = .betting
|
||||
|
||||
sound.play(.newRound)
|
||||
sound.playNewRound()
|
||||
}
|
||||
|
||||
// MARK: - SessionManagedGame Implementation
|
||||
@ -1366,28 +1366,28 @@ final class GameState: CasinoGameState {
|
||||
|
||||
// Deal player card 1
|
||||
playerHands[0].cards.append(card1)
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
if cardAppearDelay > 0 { try? await Task.sleep(for: .seconds(cardAppearDelay)) }
|
||||
playerHandsVisibleCardCount[0] += 1
|
||||
if remainingDelay > 0 { try? await Task.sleep(for: .seconds(remainingDelay)) }
|
||||
|
||||
// Deal dealer card 1 (face up)
|
||||
dealerHand.cards.append(dealerCard1)
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
if cardAppearDelay > 0 { try? await Task.sleep(for: .seconds(cardAppearDelay)) }
|
||||
dealerVisibleCardCount += 1
|
||||
if remainingDelay > 0 { try? await Task.sleep(for: .seconds(remainingDelay)) }
|
||||
|
||||
// Deal player card 2 (matching rank for split)
|
||||
playerHands[0].cards.append(card2)
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
if cardAppearDelay > 0 { try? await Task.sleep(for: .seconds(cardAppearDelay)) }
|
||||
playerHandsVisibleCardCount[0] += 1
|
||||
if remainingDelay > 0 { try? await Task.sleep(for: .seconds(remainingDelay)) }
|
||||
|
||||
// Deal dealer hole card (face down)
|
||||
dealerHand.cards.append(dealerCard2)
|
||||
sound.play(.cardDeal)
|
||||
sound.playCardDeal()
|
||||
if cardAppearDelay > 0 { try? await Task.sleep(for: .seconds(cardAppearDelay)) }
|
||||
dealerVisibleCardCount += 1
|
||||
if remainingDelay > 0 { try? await Task.sleep(for: .seconds(remainingDelay)) }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user