From 6232d41e5639f9c38e47b2bb65266e343ca26e8f Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Sat, 3 Oct 2026 02:16:00 -0400 Subject: feat: add casino_hints option and standardize casino command syntax --- internal/game/casino.go | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) (limited to 'internal/game/casino.go') diff --git a/internal/game/casino.go b/internal/game/casino.go index 0b16114..8f18614 100644 --- a/internal/game/casino.go +++ b/internal/game/casino.go @@ -342,7 +342,7 @@ func (g *Game) executePlay(sess *net.Session, args []string, rawInput string) { if len(args) > 1 { amount, err := strconv.Atoi(args[1]) if !choice.table || len(args) > 3 || (args[1] != "min" && args[1] != "max" && (err != nil || amount <= 0)) { - sess.WriteLine("Use play [amount|min|max] [target]. No wager was placed.") + sess.WriteLine("Use play GAME [N|min|max] [on BET]. No wager was placed.") return } } @@ -406,7 +406,7 @@ func (g *Game) executeBet(sess *net.Session, args []string, rawInput string) { return } } - sess.WriteLine("Use bet, bet , or bet max.") + sess.WriteLine("Use bet, bet N, or bet max.") return } table, playing := g.Casino.Participation(p.Name) @@ -424,7 +424,7 @@ func (g *Game) executeBet(sess *net.Session, args []string, rawInput string) { g.emitCasinoEvents(g.Casino.RebetAll(table.RoomID, table.Config.ID, p.Name, casinoWallet{g: g, p: p})) return } - // Table bet syntax: bet | bet [on] | bet min|max [on] . + // Table bet syntax: bet | bet N [on BET] | bet min|max [on BET]. // BEFORE an "on" keyword, a token that parses as an amount (or min/max) // sets the wager and any other token is the bet target; AFTER "on", the // next token is always the target. That makes numeric targets reachable @@ -438,26 +438,21 @@ func (g *Game) executeBet(sess *net.Session, args []string, rawInput string) { for i, arg := range args { if strings.EqualFold(arg, "on") { if sawOn || spot != "" || i == len(args)-1 { - sess.WriteLine("Use bet on . No wager was placed.") + sess.WriteLine("Use bet N on BET. No wager was placed.") return } sawOn = true continue } - if !sawOn && !(joinTarget && hasAmount && spot != "") { + // Once an amount is set, every remaining token belongs to the target + // ("bet 2 2" and "bet 2 on 2" are identical). Before that, a numeric + // token sets the amount and anything else starts the target. + if !sawOn && !hasAmount { if strings.EqualFold(arg, "min") { - if hasAmount { - sess.WriteLine("Use bet, bet [on ], bet min, or bet max.") - return - } amount, hasAmount = table.Config.MinBet, true continue } if strings.EqualFold(arg, "max") { - if hasAmount { - sess.WriteLine("Use bet, bet [on ], bet min, or bet max.") - return - } amount = min(table.Config.MaxBet, casinoAffordable(p)) if amount < 1 { sess.WriteLine("You don't have any chips or credits to bet.") @@ -467,10 +462,6 @@ func (g *Game) executeBet(sess *net.Session, args []string, rawInput string) { continue } if value, err := strconv.Atoi(arg); err == nil && value > 0 { - if hasAmount { - sess.WriteLine("Use bet, bet [on ], bet min, or bet max.") - return - } amount, hasAmount = value, true continue } @@ -483,7 +474,7 @@ func (g *Game) executeBet(sess *net.Session, args []string, rawInput string) { spot += " " + strings.ToLower(arg) continue } - sess.WriteLine("Use bet, bet [on ], bet min, or bet max.") + sess.WriteLine("Use bet, bet N [on BET], bet min, or bet max.") return } if table.Config.Game == casino.GameBaccarat { @@ -657,6 +648,9 @@ func (g *Game) casinoMenuParts(sess *net.Session, menu *casino.MenuView, message heading = message } commands = append([]casino.MenuCommand(nil), menu.Commands...) + if !g.casinoHintsVisible(sess, menu) { + commands = nil + } for i := range commands { if commands[i].Cost > casinoAffordable(sess.Player) { commands[i].Desc += " [unavailable: insufficient funds]" @@ -665,6 +659,24 @@ func (g *Game) casinoMenuParts(sess *net.Session, menu *casino.MenuView, message return balance, heading, commands } +// casinoHintsVisible decides whether a menu's command list prints. "on" +// always shows hints (the historical behavior); "off" never does; the default +// "once" shows them only on the menu a player gets when sitting down. Players +// can always ask for the live list with "what" or "verbs". +func (g *Game) casinoHintsVisible(sess *net.Session, menu *casino.MenuView) bool { + if sess == nil || sess.Player == nil || menu == nil { + return true + } + switch sess.Player.OptionString("casino_hints") { + case "off": + return false + case "once": + return menu.ShowHints + default: + return true + } +} + // casinoBoardReminder splits a persistent-board menu (craps, roulette, video // poker, Pai Gow) so its instructions print under the board they describe. // Every other game, and compact displays, keep their menu in one block. -- cgit v1.2.3