diff options
Diffstat (limited to 'internal/casino/big_six.go')
| -rw-r--r-- | internal/casino/big_six.go | 58 |
1 files changed, 49 insertions, 9 deletions
diff --git a/internal/casino/big_six.go b/internal/casino/big_six.go index 36e9c1d..0f4f764 100644 --- a/internal/casino/big_six.go +++ b/internal/casino/big_six.go @@ -99,6 +99,7 @@ type bigSixBet struct { type bigSixPlayer struct { Participant bets []bigSixBet + lastBets []rebetWager lastSpot string lastBet int } @@ -192,8 +193,8 @@ func (t *bigSixTable) commands(name string) []MenuCommand { var c []MenuCommand if p := t.players.get(name); p != nil && t.phase != phasePlaying { c = append(c, MenuCommand{Command: "bet N on BET", Desc: "Add a wager"}) - if p.lastBet > 0 { - c = append(c, MenuCommand{Command: "bet / rebet", Desc: "Repeat your last wager"}) + if len(p.lastBets) > 0 { + c = append(c, MenuCommand{Command: "bet / rebet", Desc: "Repeat all your last wagers"}) } if p.HasBet { c = append(c, MenuCommand{Command: "unbet", Desc: "Take back all wagers"}) @@ -249,31 +250,39 @@ func (t *bigSixTable) leave(name string) []Event { func (t *bigSixTable) bet(name, spot string, amount int, w Wallet) []Event { t.mu.Lock() defer t.mu.Unlock() + events, _ := t.betLocked(name, spot, amount, w) + return events +} + +// betLocked is the locked implementation of bet, shared with the multi-wager +// replay so a rebet holds the table lock across every stake. It reports false +// when no wager was placed. +func (t *bigSixTable) betLocked(name, spot string, amount int, w Wallet) ([]Event, bool) { p := t.players.get(name) if p == nil { - return []Event{t.private(name, "You aren't playing Big 6.")} + return []Event{t.private(name, "You aren't playing Big 6.")}, false } if t.phase == phasePlaying { - return []Event{t.private(name, "No more bets! The wheel is spinning.")} + return []Event{t.private(name, "No more bets! The wheel is spinning.")}, false } if spot == "" { spot = p.lastSpot } resolved, ok := bigSixResolveTarget(spot) if !ok { - return []Event{t.private(name, "Bet on 1, 2, 5, 10, 20, SWORD or SHIELD — an unambiguous prefix is fine. DOUBLE is automatic, not a bet.")} + return []Event{t.private(name, "Bet on 1, 2, 5, 10, 20, SWORD or SHIELD — an unambiguous prefix is fine. DOUBLE is automatic, not a bet.")}, false } spot = resolved if amount < t.Config.MinBet || amount > t.Config.MaxBet { - return []Event{t.private(name, "Big 6 bets must be "+betRangeText(t.Config.MinBet, t.Config.MaxBet)+".")} + return []Event{t.private(name, "Big 6 bets must be "+betRangeText(t.Config.MinBet, t.Config.MaxBet)+".")}, false } // Keep the original aggregate representable for shared menus and refunds. if amount > int(^uint(0)>>1)-p.Wager.Total { - return []Event{t.private(name, "Your total stake is too large.")} + return []Event{t.private(name, "Your total stake is too large.")}, false } wager, err := w.Wager(amount) if err != nil { - return []Event{t.private(name, walletErrorMessage(err))} + return []Event{t.private(name, walletErrorMessage(err))}, false } p.bets = append(p.bets, bigSixBet{spot, wager}) p.HasBet = true @@ -281,7 +290,34 @@ func (t *bigSixTable) bet(name, spot string, amount int, w Wallet) []Event { p.Wager.Total += amount p.lastSpot, p.lastBet, p.SittingOut = spot, amount, false events := []Event{t.playerAction(name, fmt.Sprintf("%s bets %d on %s.", name, amount, spot), fmt.Sprintf("You bet %d on %s.", amount, spot))} - return append(events, t.openRound()...) + return append(events, t.openRound()...), true +} + +// rebetAll repeats every remembered wager from the previous round in one +// command, so a bare bet/rebet restores a whole spread. +func (t *bigSixTable) rebetAll(name string, w Wallet) []Event { + t.mu.Lock() + defer t.mu.Unlock() + p := t.players.get(name) + if p == nil { + return []Event{t.private(name, "You aren't playing Big 6.")} + } + if t.phase == phasePlaying { + return []Event{t.private(name, "No more bets! The wheel is spinning.")} + } + if len(p.lastBets) == 0 { + return []Event{t.private(name, "Bet on 1, 2, 5, 10, 20, SWORD or SHIELD — an unambiguous prefix is fine. DOUBLE is automatic, not a bet.")} + } + var events []Event + for _, b := range p.lastBets { + ev, ok := t.betLocked(name, b.spot, b.amount, w) + events = append(events, ev...) + if !ok { + // A rejected stake ends the replay rather than partially betting. + break + } + } + return events } // Motion is planned backwards from an independently sampled uniform outcome. @@ -452,6 +488,10 @@ func (t *bigSixTable) reset() { t.frames = nil t.multiplier.SetInt64(1) for _, p := range t.players.ordered() { + p.lastBets = p.lastBets[:0] + for _, b := range p.bets { + p.lastBets = append(p.lastBets, rebetWager{spot: b.spot, amount: b.wager.Total}) + } p.bets = nil p.HasBet = false p.Wager = Wager{} |
