package game import ( "fmt" "strings" "thehouseoficarus/internal/casino" "thehouseoficarus/internal/color" ) func bigSixInk(mode, label, text string, dim bool) string { fg := 2 switch label { case "2": fg = 6 case "5": fg = 4 case "10": fg = 5 case "20": fg = 3 case "SWORD": fg = 15 case "SHIELD": fg = 6 case "DOUBLE": fg = 11 } return color.Render(mode, color.ColorSpec{Fg: fg, Bg: -1, Bold: !dim, Dim: dim}, text) } func bigSixLabel(s string) string { if s == "SWORD" || s == "SHIELD" || s == "DOUBLE" { return s } return "$" + s } func bigSixPanel(spot casino.BigSixSpot, width int, mode string, unicode bool) []string { b := rouletteBorders(unicode) label := bigSixLabel(spot.Label) art := []string{"$ $", ".--------.", "|" + rouletteCenter(label, 8) + "|", "'--------'", "$ $"} if unicode { art = []string{"$ $", "╭────────╮", "│" + rouletteCenter(label, 8) + "│", "╰────────╯", "$ $"} } switch spot.Label { case "SWORD": // Two full blade rows below the tip; the guard sits just above the grip. art = []string{"/\\", "||", "||", "===++===", "()"} if unicode { art = []string{"▲", "║", "║", "╘══╬══╛", "╩"} } case "SHIELD": art = []string{".--------.", "| /\\ |", "| \\/ |", "\\ /", "'------'"} if unicode { // Keep a fixed-width canvas: centering each tapered row separately // would shift the corners apart and break the shield's outline. art = []string{"╭───────╮", "│ ◇ │", "╰╮ ╭╯", " ╰╮ ╭╯ ", " ╰───╯ "} } } lines := []string{b.tl + strings.Repeat(b.h, width) + b.tr, b.v + rouletteCenter(label, width) + b.v} for _, a := range art { lines = append(lines, b.v+rouletteCenter(a, width)+b.v) } lines = append(lines, b.bl+strings.Repeat(b.h, width)+b.br) // The payout text is dim, but its box walls keep the same bold weight as // the rest of the panel; otherwise the row's verticals look thin. wall := bigSixInk(mode, spot.Label, b.v, false) oddsLine := wall + bigSixInk(mode, spot.Label, rouletteCenter(fmt.Sprintf("pays %d:1", spot.Pays), width), true) + wall lines = append(lines[:len(lines)-1], oddsLine, lines[len(lines)-1]) for i := range lines { if i == len(lines)-2 { continue // oddsLine is already colored: bold walls, dim payout } lines[i] = bigSixInk(mode, spot.Label, lines[i], false) } return lines } // Self-contained scrollback art, always within 80 columns. The last two // betting panels expand into the space formerly occupied by DOUBLE; DOUBLE // is an automatic feature, advertised in a shallow full-width banner instead. func renderBigSixSnapshot(s *casino.BigSixSnapshot, mode string, unicode bool) string { if len(s.Pockets) > 0 { return renderBigSixStrip(s, mode, unicode) } if s.Phase == "playing" { return "Big 6 wheel spinning | live stakes " + s.Multiplier + "x" } var out strings.Builder spots := casino.BigSixSpots() for _, row := range [][]casino.BigSixSpot{spots[:4], spots[4:7]} { var panels [][]string for _, spot := range row { width := 15 if spot.Label == "SWORD" || spot.Label == "SHIELD" { width = 24 } panels = append(panels, bigSixPanel(spot, width, mode, unicode)) } for line := range panels[0] { out.WriteString(" ") for col, panel := range panels { if col > 0 { out.WriteByte(' ') } out.WriteString(panel[line]) } out.WriteByte('\n') } } b := rouletteBorders(unicode) const bannerWidth = 69 // 71 columns including borders, like both betting rows. banner := []string{ b.tl + strings.Repeat(b.h, bannerWidth) + b.tr, b.v + rouletteCenter("DOUBLE", bannerWidth) + b.v, b.v + rouletteCenter("Every live bet doubles and the wheel spins again", bannerWidth) + b.v, b.v + rouletteCenter("Double again. And again. No cap.", bannerWidth) + b.v, b.bl + strings.Repeat(b.h, bannerWidth) + b.br, } for _, line := range banner { out.WriteString(" " + bigSixInk(mode, "DOUBLE", line, false) + "\n") } fmt.Fprintf(&out, " Bets: %s", betLimitsText(s.MinBet, s.MaxBet)) return out.String() } func renderBigSixStrip(s *casino.BigSixSnapshot, mode string, unicode bool) string { result := s.Phase == "result" width := 6 if result { width = 7 } n := len(s.Pockets) center := n / 2 pointer := 1 + center*(width+1) + width/2 b := rouletteBorders(unicode) wall := "|" if unicode { wall = "│" } // Every rail and separator on the wheel uses the same dim-yellow border // ink; the per-pocket colors paint only the interiors. borderInk := func(text string) string { return bigSixInk(mode, "20", text, true) } var out strings.Builder tip := "\\/" if unicode { tip = "▼" } // No leading/trailing newline: WriteLine supplies the sole frame separator. out.WriteString(strings.Repeat(" ", pointer) + bigSixInk(mode, "DOUBLE", tip, false) + "\n") top := b.tl + strings.Repeat(strings.Repeat(b.h, width)+b.teeTop, n-1) + strings.Repeat(b.h, width) + b.tr bottom := b.bl + strings.Repeat(strings.Repeat(b.h, width)+b.teeBottom, n-1) + strings.Repeat(b.h, width) + b.br out.WriteString(borderInk(top) + "\n") rows := 3 if result { rows = 4 } for row := 0; row < rows; row++ { out.WriteString(borderInk(b.v)) for i, pocket := range s.Pockets { label := bigSixLabel(pocket) var art []string if result { // The bill's side walls continue through the number row so the // outline stays complete once the wheel stops. art = []string{".-----.", "| $ |", wall + rouletteCenter(label, 5) + wall, "'-----'"} if unicode { art = []string{"╭─────╮", "│ $ │", wall + rouletteCenter(label, 5) + wall, "╰─────╯"} } switch pocket { case "SWORD": art = []string{"/\\", "||", "--+--", label} if unicode { art = []string{"▲", "╘═╬═╛", "╩", label} } case "SHIELD": art = []string{"/---\\", "| + |", "\\___/", label} if unicode { art = []string{"╭─────╮", "╰╮ ◇ ╭╯", " ╰───╯ ", label} } case "DOUBLE": art = []string{"", "x 2", label, "RESPIN"} if unicode { art[1] = "× 2" } } } else { // Only the dollar symbols are drawn as banknotes; the logo and // DOUBLE spaces show their name without the bill walls. art = []string{".----.", wall + rouletteCenter(label, 4) + wall, "'----'"} if unicode { art = []string{"╭────╮", wall + rouletteCenter(label, 4) + wall, "╰────╯"} } switch pocket { case "SWORD", "SHIELD", "DOUBLE": art = []string{"", label, ""} } } out.WriteString(bigSixInk(mode, pocket, rouletteCenter(art[row], width), result && i != center)) out.WriteString(borderInk(b.v)) } out.WriteByte('\n') } out.WriteString(borderInk(bottom)) if result { out.WriteString("\n" + strings.Repeat(" ", pointer-3) + bigSixInk(mode, s.Pockets[center], "WINNER", false)) } return out.String() }