aboutsummaryrefslogtreecommitdiff
path: root/internal/game/look_casino.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/look_casino.go')
-rw-r--r--internal/game/look_casino.go128
1 files changed, 128 insertions, 0 deletions
diff --git a/internal/game/look_casino.go b/internal/game/look_casino.go
new file mode 100644
index 0000000..6fa2959
--- /dev/null
+++ b/internal/game/look_casino.go
@@ -0,0 +1,128 @@
+package game
+
+import (
+ "fmt"
+ "strings"
+
+ "thehouseoficarus/internal/casino"
+ "thehouseoficarus/internal/net"
+)
+
+// lookCasinoTable renders a table fixture's details for a look target: the
+// wager limits, the live state and seated players, and this table's rule
+// variants. The invariant roulette and craps graphics and the generic rule
+// dumps are deliberately omitted; blackjack, baccarat and Pai Gow keep their
+// felt because it carries per-table rules and pay tables. It reports whether
+// the target named this room's game.
+func (g *Game) lookCasinoTable(sess *net.Session, target string, game casino.GameName) bool {
+ table, ok := g.resolveRoomTable(sess, target, game)
+ if !ok {
+ return false
+ }
+ // Use the live table's normalized config: the room fixture may omit
+ // defaults (seat count, bet limits) that EnsureTable fills in.
+ sess.WriteLine(g.renderCasinoTableDetails(sess, table.Config, table))
+ return true
+}
+
+// resolveRoomTable matches a look target against the room's table for game
+// using the same names and prefix rules as the play command, plus the fixture
+// id, an optional " table" suffix, and the bare "table" target when the room
+// holds exactly one table.
+func (g *Game) resolveRoomTable(sess *net.Session, target string, game casino.GameName) (*casino.Table, bool) {
+ if g.Casino == nil || sess.Player == nil {
+ return nil, false
+ }
+ room, err := g.World.LoadRoom(sess.Player.RoomID)
+ if err != nil {
+ return nil, false
+ }
+ target = strings.TrimSpace(strings.ToLower(target))
+ target = strings.TrimSuffix(target, " table")
+ address := string(game)
+ if target == "table" {
+ if len(room.CasinoTables) != 1 || room.CasinoTables[0].Game != game {
+ return nil, false
+ }
+ } else {
+ var choices []casinoChoice
+ for _, cfg := range room.CasinoTables {
+ if cfg.Game != game {
+ continue
+ }
+ choices = append(choices, casinoChoice{address: string(cfg.Game), names: append(casinoTableAliases(cfg), cfg.ID), table: true})
+ }
+ choice, ok := resolveCasinoChoice(choices, target)
+ if !ok {
+ return nil, false
+ }
+ address = choice.address
+ }
+ table, ok := g.casinoTable(room.ID, address)
+ if !ok {
+ return nil, false
+ }
+ return table, true
+}
+
+// renderCasinoTableDetails formats the details block and, for the felt games,
+// the per-table rule card. It never prints the craps or roulette board.
+func (g *Game) renderCasinoTableDetails(sess *net.Session, cfg casino.TableConfig, table *casino.Table) string {
+ seats := table.Seats()
+ seated := "no one"
+ if len(seats) > 0 {
+ seated = strings.Join(seats, ", ")
+ }
+ lines := []string{
+ g.colorize(sess, "casino_action", cfg.Label()),
+ fmt.Sprintf(" Limits %s", betLimitsText(cfg.MinBet, cfg.MaxBet)),
+ fmt.Sprintf(" Seats %d/%d", len(seats), cfg.MaxPlayers),
+ fmt.Sprintf(" State %s", table.State()),
+ fmt.Sprintf(" Rules %s", casinoTableSummary(cfg)),
+ fmt.Sprintf(" Seated %s", seated),
+ }
+ switch cfg.Game {
+ case casino.GameBlackjack:
+ lines = append(lines, "", g.renderCasinoSnapshot(sess, &casino.BlackjackRulesView{Config: cfg}))
+ case casino.GameBaccarat:
+ lines = append(lines, "", g.renderCasinoSnapshot(sess, &casino.BaccaratRulesView{Config: cfg}))
+ case casino.GamePaiGow:
+ lines = append(lines, "", renderPaiGowFelt(cfg, g.colorMode(sess), sess.Player.OptionBool("unicode")))
+ }
+ return strings.Join(lines, "\n")
+}
+
+// casinoTableSummary is the compact per-table rule description used by the
+// look details block. The full wording stays in RulesText.
+func casinoTableSummary(cfg casino.TableConfig) string {
+ switch cfg.Game {
+ case casino.GameBlackjack:
+ b := cfg.Blackjack.Normalize()
+ dealer := "dealer stands on soft 17"
+ if b.DealerHitsSoft17() {
+ dealer = "dealer hits soft 17"
+ }
+ return fmt.Sprintf("%d decks; %s; blackjack pays %s", b.Decks, dealer, ratioText(b.BlackjackPayout))
+ case casino.GameBaccarat:
+ return fmt.Sprintf("%d decks", cfg.Baccarat.Normalize().Decks)
+ case casino.GameRoulette:
+ summary := "single-zero wheel"
+ if cfg.Roulette.DoubleZero {
+ summary = "double-zero wheel"
+ }
+ if cfg.Roulette.Racetrack {
+ summary += "; racetrack call bets"
+ }
+ return summary
+ case casino.GameCraps:
+ return cfg.Craps.Normalize().Title()
+ case casino.GamePaiGow:
+ p := cfg.PaiGow.Normalize()
+ envy := "Envy off"
+ if p.Envy {
+ envy = "Envy on"
+ }
+ return p.Label() + "; " + envy
+ }
+ return cfg.Label()
+}