aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/blackjack.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-09-19 01:55:34 -0400
committerhistoria <[not public]>2026-09-19 01:55:34 -0400
commitcc33072eced3d5460512c09c42ec4531c807d7af (patch)
treeb1b451fa87fa389cb8343a3645372f3b43f5523e /internal/casino/blackjack.go
parent2c38386484cdb507c4687caceb37e0b963e33594 (diff)
downloadthehouseoficarus-cc33072eced3d5460512c09c42ec4531c807d7af.tar.gz
fix: casino stake preservation, world state reconciliation, casino game registration
Diffstat (limited to 'internal/casino/blackjack.go')
-rw-r--r--internal/casino/blackjack.go26
1 files changed, 15 insertions, 11 deletions
diff --git a/internal/casino/blackjack.go b/internal/casino/blackjack.go
index 3b08ba5..cb71034 100644
--- a/internal/casino/blackjack.go
+++ b/internal/casino/blackjack.go
@@ -592,14 +592,12 @@ func (t *blackjackTable) settle() []Event {
if !p.HasBet {
continue
}
- payoutFailed := false
for _, hand := range p.hands {
result, payout, settleErr := settleHand(hand, dealerTotal, dealerBlackjack, t.Rules)
// One shared settlement path for every game: pay before
// announcing, and leave the stakes pending on any failure so a
// refund can never be paid on top of a payout that was not durable.
if settleStakeOutcome(p.Wallet, payout, hand.stakes, settleErr) {
- payoutFailed = true
publicResult, _ := blackjackResultMessages(p.Name, result, payout)
settlement := t.playerAction(p.Name, publicResult, payoutFailedMessage())
colorizeBlackjackSettlement(&settlement, result)
@@ -618,7 +616,6 @@ func (t *blackjackTable) settle() []Event {
insurancePayout, insuranceErr = MulPayout(p.insurance, 1+t.Rules.InsurancePayout)
}
if settleStakeOutcome(p.Wallet, insurancePayout, []string{p.insuranceStakeID}, insuranceErr) {
- payoutFailed = true
events = append(events, t.private(p.Name, payoutFailedMessage()))
} else if insurancePayout > 0 {
events = append(events, t.private(p.Name, fmt.Sprintf("Insurance pays %d credits.", insurancePayout)))
@@ -626,11 +623,12 @@ func (t *blackjackTable) settle() []Event {
events = append(events, t.private(p.Name, "Insurance pays 0 credits."))
}
}
- if p.Wallet != nil && !payoutFailed {
- // The round resolved; the stakes are no longer pending and must
- // never be refunded.
- p.Wallet.ResolveStakes()
- }
+ // Each hand's stakes were already consumed per-handle by
+ // settleStakeOutcome (a payout removes them in PayCredits; a loss
+ // resolves them), and the insurance stake likewise. Deliberately do
+ // NOT call the player-wide ResolveStakes here: it would also consume
+ // a stake left pending by an earlier failed payout, which must stay
+ // refundable (see the Wallet contract).
}
t.resetRound()
for _, p := range t.players.ordered() {
@@ -781,9 +779,15 @@ func (t *blackjackTable) markDisconnectedLocked(name string) []Event {
}
if p := t.players.get(name); p != nil && p.HasBet && p.Wallet != nil {
if t.phase == blackjackPlaying || t.phase == blackjackInsurance {
- // A disconnected player forfeits the round in flight: consume the
- // stakes now so a later refund cannot return them.
- p.Wallet.ResolveStakes()
+ // A disconnected player forfeits the round in flight: consume
+ // ONLY this round's stakes, by handle, so a stake left pending by
+ // an earlier failed payout stays refundable.
+ var ids []string
+ for _, hand := range p.hands {
+ ids = append(ids, hand.stakes...)
+ }
+ ids = append(ids, p.insuranceStakeID)
+ resolveStakeIDs(p.Wallet, ids)
} else {
// No card has been dealt for this stake yet, so refund it: nothing
// the bettor paid for has been revealed or played.