diff options
| author | historia <[not public]> | 2026-09-19 01:55:34 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-19 01:55:34 -0400 |
| commit | cc33072eced3d5460512c09c42ec4531c807d7af (patch) | |
| tree | b1b451fa87fa389cb8343a3645372f3b43f5523e /internal/casino/blackjack.go | |
| parent | 2c38386484cdb507c4687caceb37e0b963e33594 (diff) | |
| download | thehouseoficarus-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.go | 26 |
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. |
