Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>

This commit is contained in:
Matt Bruce 2025-12-31 14:02:52 -06:00
parent c9b2a9e692
commit ed1dabfe18
10 changed files with 63 additions and 70 deletions

View File

@ -591,6 +591,22 @@ final class GameState: CasinoGameState {
return currentAmount + amount <= maxBet
}
/// The minimum bet level across all bet types that can accept more chips.
/// Used by chip selector to determine if chips should be enabled.
/// Returns the smallest bet so chips stay enabled if ANY bet type can accept more.
var minBetForChipSelector: Int {
// All bet types are always available in Baccarat
let allBetTypes: [BetType] = [
.player, .banker, .tie,
.playerPair, .bankerPair,
.dragonBonusPlayer, .dragonBonusBanker
]
// Return the minimum bet amount across all bet types
// so chips stay enabled if any bet type can accept more
return allBetTypes.map { betAmount(for: $0) }.min() ?? 0
}
// MARK: - Betting Actions
/// Places a bet of the specified amount on the given bet type.

View File

@ -353,7 +353,7 @@ struct GameTableView: View {
ChipSelectorView(
selectedChip: $selectedChip,
balance: state.balance,
currentBet: state.totalBetAmount,
currentBet: state.minBetForChipSelector,
maxBet: state.maxBet
)
.transition(.opacity.combined(with: .move(edge: .bottom)))
@ -464,7 +464,7 @@ struct GameTableView: View {
ChipSelectorView(
selectedChip: $selectedChip,
balance: state.balance,
currentBet: state.totalBetAmount,
currentBet: state.minBetForChipSelector,
maxBet: state.maxBet
)
.transition(.opacity.combined(with: .move(edge: .bottom)))

View File

@ -177,7 +177,6 @@ final class GameState: CasinoGameState {
/// Whether a specific side bet can accept more chips of the given amount.
/// Matches Baccarat's canAddToBet pattern.
func canAddToSideBet(type: SideBetType, amount: Int) -> Bool {
guard settings.sideBetsEnabled else { return false }
let currentAmount: Int
switch type {
case .perfectPairs:
@ -204,16 +203,12 @@ final class GameState: CasinoGameState {
return false
}
/// The minimum bet level across all active bet types.
/// The minimum bet level across all bet types.
/// Used by chip selector to determine if chips should be enabled.
/// Returns the smallest bet so chips stay enabled if ANY bet type can accept more.
var minBetForChipSelector: Int {
if settings.sideBetsEnabled {
// Return the minimum of all bet types so chips stay enabled if any can be increased
return min(currentBet, perfectPairsBet, twentyOnePlusThreeBet)
} else {
return currentBet
}
min(currentBet, perfectPairsBet, twentyOnePlusThreeBet)
}
/// Whether the current hand can hit.
@ -983,8 +978,6 @@ final class GameState: CasinoGameState {
/// Evaluates side bets based on the initial deal.
private func evaluateSideBets() {
guard settings.sideBetsEnabled else { return }
let playerCards = playerHands[0].cards
guard playerCards.count >= 2 else { return }

View File

@ -136,11 +136,6 @@ final class GameSettings: GameSettingsProtocol {
/// Speed of card dealing (uses CasinoDesign.DealingSpeed constants)
var dealingSpeed: Double = CasinoDesign.DealingSpeed.normal { didSet { save() } }
// MARK: - Side Bets
/// Whether side bets (Perfect Pairs, 21+3) are enabled.
var sideBetsEnabled: Bool = false { didSet { save() } }
// MARK: - Display Settings
/// Whether to show the cards remaining indicator.
@ -242,7 +237,6 @@ final class GameSettings: GameSettingsProtocol {
self.blackjackPayout = data.blackjackPayout
self.insuranceAllowed = data.insuranceAllowed
self.neverAskInsurance = data.neverAskInsurance
self.sideBetsEnabled = data.sideBetsEnabled
self.showAnimations = data.showAnimations
self.dealingSpeed = data.dealingSpeed
self.showCardsRemaining = data.showCardsRemaining
@ -269,7 +263,6 @@ final class GameSettings: GameSettingsProtocol {
blackjackPayout: blackjackPayout,
insuranceAllowed: insuranceAllowed,
neverAskInsurance: neverAskInsurance,
sideBetsEnabled: sideBetsEnabled,
showAnimations: showAnimations,
dealingSpeed: dealingSpeed,
showCardsRemaining: showCardsRemaining,
@ -297,7 +290,6 @@ final class GameSettings: GameSettingsProtocol {
blackjackPayout = 1.5
insuranceAllowed = true
neverAskInsurance = false
sideBetsEnabled = false
showAnimations = true
dealingSpeed = CasinoDesign.DealingSpeed.normal
showCardsRemaining = true

View File

@ -3250,6 +3250,7 @@
}
},
"Enable Side Bets" : {
"extractionState" : "stale",
"localizations" : {
"en" : {
"stringUnit" : {
@ -5348,6 +5349,7 @@
}
},
"Perfect Pairs (25:1) and 21+3 (100:1)" : {
"extractionState" : "stale",
"localizations" : {
"en" : {
"stringUnit" : {
@ -6329,6 +6331,7 @@
}
},
"SIDE BETS" : {
"extractionState" : "stale",
"localizations" : {
"en" : {
"stringUnit" : {

View File

@ -62,7 +62,6 @@ struct BlackjackSettingsData: PersistableGameData {
blackjackPayout: 1.5,
insuranceAllowed: true,
neverAskInsurance: false,
sideBetsEnabled: false,
showAnimations: true,
dealingSpeed: 1.0,
showCardsRemaining: true,
@ -87,7 +86,6 @@ struct BlackjackSettingsData: PersistableGameData {
var blackjackPayout: Double
var insuranceAllowed: Bool
var neverAskInsurance: Bool
var sideBetsEnabled: Bool
var showAnimations: Bool
var dealingSpeed: Double
var showCardsRemaining: Bool

View File

@ -111,16 +111,6 @@ struct SettingsView: View {
TableLimitsPicker(selection: $settings.tableLimits)
}
// 3.5. Side Bets
SheetSection(title: String(localized: "SIDE BETS"), icon: "dollarsign.arrow.trianglehead.counterclockwise.rotate.90") {
SettingsToggle(
title: String(localized: "Enable Side Bets"),
subtitle: String(localized: "Perfect Pairs (25:1) and 21+3 (100:1)"),
isOn: $settings.sideBetsEnabled,
accentColor: accent
)
}
// 4. Deck Settings
SheetSection(title: String(localized: "DECK SETTINGS"), icon: "rectangle.portrait.on.rectangle.portrait") {
DeckCountPicker(selection: $settings.deckCount)

View File

@ -55,7 +55,6 @@ struct BettingZoneView: View {
}
var body: some View {
if state.settings.sideBetsEnabled {
// Horizontal layout: PP | Main Bet | 21+3
HStack(spacing: Design.Spacing.small) {
// Perfect Pairs
@ -82,11 +81,6 @@ struct BettingZoneView: View {
.frame(width: Design.Size.sideBetZoneWidth)
}
.frame(height: zoneHeight)
} else {
// Simple layout: just main bet
mainBetZone
.frame(height: zoneHeight)
}
}
private var mainBetZone: some View {
@ -155,14 +149,12 @@ extension Design.Size {
}
}
#Preview("With Side Bets") {
#Preview("Main Bet Only") {
ZStack {
Color.Table.felt.ignoresSafeArea()
BettingZoneView(
state: {
let settings = GameSettings()
settings.sideBetsEnabled = true
let state = GameState(settings: settings)
let state = GameState(settings: GameSettings())
state.placeBet(amount: 100)
return state
}(),
@ -177,9 +169,7 @@ extension Design.Size {
Color.Table.felt.ignoresSafeArea()
BettingZoneView(
state: {
let settings = GameSettings()
settings.sideBetsEnabled = true
let state = GameState(settings: settings)
let state = GameState(settings: GameSettings())
state.placeBet(amount: 250)
state.placeSideBet(type: .perfectPairs, amount: 25)
state.placeSideBet(type: .twentyOnePlusThree, amount: 50)

View File

@ -135,7 +135,7 @@ struct BlackjackTableView: View {
)
// Side bet toasts (positioned on left/right sides to not cover cards)
if state.settings.sideBetsEnabled && state.showSideBetToasts {
if state.showSideBetToasts {
HStack {
// PP on left
if state.perfectPairsBet > 0, let ppResult = state.perfectPairsResult {

View File

@ -36,6 +36,17 @@ public protocol CasinoGameState: SessionManagedGame {
/// Aggregated statistics from all sessions.
var aggregatedStats: AggregatedSessionStats { get }
// MARK: - Chip Selection
/// The minimum bet level across all bet types.
/// Used by ChipSelectorView to determine if chips should be enabled.
/// Returns the smallest bet so chips stay enabled if ANY bet type can accept more.
///
/// Games with multiple bet types (main bet, side bets) should return the minimum
/// bet amount across all placeable bet types, ensuring the chip selector remains
/// responsive as long as at least one bet type has room for more chips.
var minBetForChipSelector: Int { get }
}
// MARK: - Default Implementations