aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/big_six.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/casino/big_six.go')
-rw-r--r--internal/casino/big_six.go58
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{}