From 6d9908b29c8187196d23b126b1165c7e0bd0fc76 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Thu, 1 Oct 2026 19:30:38 -0400 Subject: fix: casino pai gow sorting, universal unbet, table/rules split, remove solo timers --- internal/casino/table_ux.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'internal/casino/table_ux.go') diff --git a/internal/casino/table_ux.go b/internal/casino/table_ux.go index e255825..4251e4f 100644 --- a/internal/casino/table_ux.go +++ b/internal/casino/table_ux.go @@ -115,10 +115,46 @@ func (c *tableCore[P]) committedMenu(name string) Event { {Command: "sitout", Desc: "Sit out after this round"}, {Command: "stop", Desc: "Leave after this round"}, } + // Until the round is dealt or spun, the committed wager can still be + // taken back with the same universal unbet command every game uses. + if c.phase == phaseBetting { + commands = append([]MenuCommand{{Command: "unbet", Desc: "Take back all your wagers before the round"}}, commands...) + } e.Menu = &MenuView{Heading: e.Message, Commands: withTableHints(commands, nil)} return e } +// unbetLocked refunds a seated player's pre-round wager in the shared betting +// phase. Every table game routes the single unbet command through it; a stake +// already in play (cards dealt, wheel spinning) is refused. Games that keep +// their own stake metadata clear it after this returns. +func (c *tableCore[P]) unbetLocked(name string) ([]Event, bool) { + for _, p := range c.players.participants() { + if p.Name != name { + continue + } + if c.phase != phaseWaiting && c.phase != phaseBetting { + return []Event{c.private(name, "You can only take back bets before the round starts.")}, true + } + if !p.HasBet || p.Wager.Total == 0 { + return []Event{c.private(name, "Nothing to take back.")}, true + } + total := p.Wager.Total + var ids []string + if p.Wager.ID != "" { + ids = append(ids, p.Wager.ID) + } + if p.Wallet != nil { + if err := p.Wallet.PayCredits(total, ids...); err != nil { + return []Event{c.private(name, payoutFailedMessage())}, true + } + } + p.HasBet, p.Wager = false, Wager{} + return []Event{c.private(name, fmt.Sprintf("You take back %d credits.", total))}, true + } + return []Event{c.private(name, "You aren't seated at this table.")}, true +} + // controlLocked queues departures without changing committed hands or stakes. func (c *tableCore[P]) controlLocked(name, action string) ([]Event, bool) { if action != "leave_after" && action != "sitout" { -- cgit v1.2.3