diff options
Diffstat (limited to 'internal/game/look_casino.go')
| -rw-r--r-- | internal/game/look_casino.go | 128 |
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() +} |
