diff options
Diffstat (limited to 'internal/casino')
| -rw-r--r-- | internal/casino/baccarat.go | 4 | ||||
| -rw-r--r-- | internal/casino/baccarat_test.go | 24 | ||||
| -rw-r--r-- | internal/casino/blackjack.go | 36 | ||||
| -rw-r--r-- | internal/casino/blackjack_test.go | 8 | ||||
| -rw-r--r-- | internal/casino/table_ux_test.go | 32 |
5 files changed, 83 insertions, 21 deletions
diff --git a/internal/casino/baccarat.go b/internal/casino/baccarat.go index e34518f..ad56da4 100644 --- a/internal/casino/baccarat.go +++ b/internal/casino/baccarat.go @@ -192,7 +192,9 @@ func (t *baccaratTable) deal() []Event { publicResult = p.Name + "’s settlement is pending recovery." } settlement := t.playerAction(p.Name, publicResult, privateResult) - settlement.ShowBalance = !payoutFailed + // Returning players get their balance in the next bet menu; only + // departures/sit-outs need it attached to the settlement. + settlement.ShowBalance = !payoutFailed && (p.LeaveAfter || p.SitOutAfter || !p.Connected) if result == "win" { if p.lastSpot == baccaratSpotTie { settlement.Color = "casino_jackpot_win" diff --git a/internal/casino/baccarat_test.go b/internal/casino/baccarat_test.go index 12dc07c..f947f5b 100644 --- a/internal/casino/baccarat_test.go +++ b/internal/casino/baccarat_test.go @@ -162,6 +162,30 @@ func TestBaccaratSoloBetDealsImmediately(t *testing.T) { } } +func TestBaccaratSettlementShowsBalanceOnlyWithoutNextMenu(t *testing.T) { + for _, leaving := range []bool{false, true} { + table := newBaccaratTestTable(TableConfig{ID: "baccarat", Game: GameBaccarat}) + table.join("alice") + forceShoe(table, card{rank: "5"}, card{rank: "4"}, card{rank: "2"}, card{rank: "3"}) + if leaving { + table.players.get("alice").LeaveAfter = true + } + events := table.bet("alice", baccaratSpotPlayer, 10, &testWallet{credits: 100}) + found := false + for _, e := range events { + if e.PrivateTo == "alice" && strings.Contains(e.PrivateMessage, "WIN | Net") { + found = true + if e.ShowBalance != leaving { + t.Fatalf("leaving=%v settlement ShowBalance=%v: %+v", leaving, e.ShowBalance, e) + } + } + } + if !found { + t.Fatalf("leaving=%v missing settlement: %+v", leaving, events) + } + } +} + func TestBaccaratWaitsForAllPlayersToBet(t *testing.T) { table := newBaccaratTestTable(TableConfig{ID: "baccarat", Game: GameBaccarat, MaxPlayers: 2}) table.join("alice") diff --git a/internal/casino/blackjack.go b/internal/casino/blackjack.go index 2e7d7e9..0a5c0d1 100644 --- a/internal/casino/blackjack.go +++ b/internal/casino/blackjack.go @@ -5,7 +5,6 @@ package casino import ( "fmt" "math/rand" - "strings" ) // Blackjack uses the shared table phases; these aliases keep the rule @@ -550,24 +549,22 @@ func (t *blackjackTable) prompt() []Event { func (t *blackjackTable) turnMenuLocked(name string) Event { p := t.players.get(name) - h := p.hands[t.activeHand] - ranks := make([]string, len(h.cards)) - for i, card := range h.cards { - ranks[i] = card.rank - } - actions := t.availableActions(p, h) - e := t.private(name, fmt.Sprintf("Your turn (%s).\nActions: %s", strings.Join(ranks, ","), strings.Join(actions, ", "))) + hand := p.hands[t.activeHand] + actions := t.availableActions(p, hand) + // The table snapshot already shows the active hand's cards, score, wager, + // and "Your turn" status; the menu only needs the deadline and actions. + e := t.private(name, "Your turn.") e.Color = "casino_menu" deadline := t.timer.remaining() if p.Connected && t.bettorCount() <= 1 { deadline = t.ceiling.remaining() } - e.Menu = &MenuView{Heading: fmt.Sprintf("Your turn (%s) | Hand %d/%d | %s | Wager %d | %d ticks remaining", strings.Join(ranks, ","), t.activeHand+1, len(p.hands), handScore(h), h.bet, deadline), Commands: blackjackActionCommands(actions)} + e.Menu = &MenuView{Heading: fmt.Sprintf("Your turn | %d ticks remaining", deadline), Commands: blackjackActionCommands(actions)} for i := range e.Menu.Commands { c := &e.Menu.Commands[i] if c.Command == "double" || c.Command == "split" { - c.Cost = h.bet - c.Desc += fmt.Sprintf(" (+%d credits)", h.bet) + c.Cost = hand.bet + c.Desc += fmt.Sprintf(" (+%d credits)", hand.bet) } } return e @@ -709,12 +706,19 @@ func (t *blackjackTable) settle() []Event { } } if !roundFailed { - e := t.private(p.Name, fmt.Sprintf("Round complete | Net %+d credits (insurance included)", roundNet)) - e.ShowBalance = true - if roundNet > 0 { - e.Color = "casino_big_win" + // A single settled hand with no insurance already reported its net + // in the per-hand result line, so a summary is only noise. Keep it + // for split hands and insurance, and whenever the player will not + // receive the next-round menu that carries their balance. + needsBalance := p.LeaveAfter || p.SitOutAfter || !p.Connected + if len(p.hands) > 1 || p.insurance > 0 || needsBalance { + e := t.private(p.Name, fmt.Sprintf("Round complete | Net %+d credits (insurance included)", roundNet)) + e.ShowBalance = needsBalance + if roundNet > 0 { + e.Color = "casino_big_win" + } + events = append(events, e) } - events = append(events, e) } // Each hand's stakes were already consumed per-handle by // settleStakeOutcome (a payout removes them in PayCredits; a loss diff --git a/internal/casino/blackjack_test.go b/internal/casino/blackjack_test.go index dd3d83a..08069ef 100644 --- a/internal/casino/blackjack_test.go +++ b/internal/casino/blackjack_test.go @@ -127,10 +127,10 @@ func TestBlackjackPromptNamesActiveHandAndOnlyOffersAvailableActions(t *testing. table.activeHand = 0 table.dealer.cards = []card{{rank: "10"}, {rank: "7"}} event := table.prompt()[0] - if event.Message != "Your turn (K,6).\nActions: hit, stand, double" { + if event.Message != "Your turn." { t.Fatalf("prompt=%q", event.Message) } - if event.Menu == nil || !strings.Contains(event.Menu.Heading, "Hand 1/1 | 16 | Wager 10") || event.Menu.ShowBalance || + if event.Menu == nil || !strings.Contains(event.Menu.Heading, "Your turn |") || event.Menu.ShowBalance || len(event.Menu.Commands) != 3 || event.Menu.Commands[0].Command != "hit" || event.Menu.Commands[1].Command != "stand" || event.Menu.Commands[2].Command != "double" { t.Fatalf("prompt menu=%+v", event.Menu) } @@ -199,7 +199,7 @@ func TestBlackjackInsuranceDeclineContinuesRound(t *testing.T) { if table.phase != blackjackPlaying { t.Fatalf("phase=%s, want playing after insurance declined", table.phase) } - if !hasMessage(events, "Your turn (10,8).") { + if !hasMessage(events, "Your turn.") { t.Fatalf("round did not continue after insurance: %+v", events) } } @@ -280,7 +280,7 @@ func TestBlackjackDisconnectActivePassesPlay(t *testing.T) { t.Fatalf("alice's forfeited wager was paid: %d", wa.paid) } // Bob is now prompted for his turn (10,6 against dealer 10-up). - if !hasMessage(disEvt, "Your turn (10,6)") { + if !hasMessage(disEvt, "Your turn.") { t.Fatalf("play did not pass to bob after alice left: %+v", disEvt) } // Bob stands; round settles. diff --git a/internal/casino/table_ux_test.go b/internal/casino/table_ux_test.go index 7f93951..812bed0 100644 --- a/internal/casino/table_ux_test.go +++ b/internal/casino/table_ux_test.go @@ -161,6 +161,38 @@ func TestSplitAndInsuranceRoundNetIncludesEveryStake(t *testing.T) { } } +func TestSingleHandSettlementKeepsSummaryQuiet(t *testing.T) { + // A connected player with one hand and no insurance already saw the net in + // the per-hand result; the next bet menu carries the balance. + table := uxBlackjack() + table.dealer.cards = []card{{rank: "10", suit: "spades"}, {rank: "7", suit: "hearts"}} + events := table.settle() + if hasMessage(events, "Round complete") { + t.Fatalf("single-hand settlement repeated the net: %+v", events) + } + for _, e := range events { + if e.ShowBalance { + t.Fatalf("balance attached to a settlement whose next menu carries it: %+v", e) + } + } +} + +func TestDepartingSettlementCarriesBalanceSummary(t *testing.T) { + table := uxBlackjack() + table.dealer.cards = []card{{rank: "10", suit: "spades"}, {rank: "7", suit: "hearts"}} + table.players.get("alice").LeaveAfter = true + events := table.settle() + found := false + for _, e := range events { + if strings.Contains(e.Message, "Round complete") && e.ShowBalance { + found = true + } + } + if !found { + t.Fatalf("departing player lost the balance summary: %+v", events) + } +} + func TestRebetMenusAndMidRoundJoin(t *testing.T) { table := uxBlackjack() events := table.join("bob") |
