package game import ( "fmt" "strings" "thehouseoficarus/internal/cardart" "thehouseoficarus/internal/casino" "thehouseoficarus/internal/color" ) var ( pokerBlue = color.NearestXterm256(0, 2, 105) pokerRed = color.NearestXterm256(254, 0, 0) pokerYellow = color.NearestXterm256(247, 231, 14) ) func pokerInk(mode, text string, active bool) string { bg := pokerBlue if active { bg = pokerRed } return color.Render(mode, color.ColorSpec{Fg: pokerYellow, Bg: bg, Bold: true}, text) } func renderPokerPayTable(s *casino.VideoPokerSnapshot, mode string) string { rows := s.Config.PayRows(s.Hands) if len(rows) == 0 { return "" } nameWidth, coinWidth := len("COINS PER HAND")+3, 6 for _, row := range rows { nameWidth = max(nameWidth, color.VisibleLen(row.Name)+3) for _, n := range row.Coins { coinWidth = max(coinWidth, len(fmt.Sprint(n))+2) } } hasNext := s.Config.Feature == casino.PokerUltimateX widths := []int{nameWidth, coinWidth, coinWidth, coinWidth, coinWidth, coinWidth} if hasNext { widths = append(widths, 8) } border := func(left, middle, right string) string { parts := make([]string, len(widths)) for i, w := range widths { parts[i] = strings.Repeat("─", w) } return pokerInk(mode, left+strings.Join(parts, middle)+right, false) } row := func(cells []string, leaders bool) string { var b strings.Builder b.WriteString(pokerInk(mode, "│", false)) for i, text := range cells { if i == 0 && leaders { text = " " + text + " " + strings.Repeat(".", widths[0]-color.VisibleLen(text)-2) } else { pad := max(0, widths[i]-color.VisibleLen(text)) text = strings.Repeat(" ", pad/2) + text + strings.Repeat(" ", pad-pad/2) } b.WriteString(pokerInk(mode, text, i > 0 && i <= 5 && s.Coins == i)) b.WriteString(pokerInk(mode, "│", false)) } return b.String() } headers := []string{"COINS PER HAND", "1", "2", "3", "4", "5"} if hasNext { headers = append(headers, "NEXT X") } lines := []string{s.Config.GameLabel() + " — " + s.Config.Payout + " pay", border("┌", "┬", "┐"), row(headers, false), border("├", "┼", "┤")} for _, pay := range rows { cells := []string{pay.Name} for _, n := range pay.Coins { cells = append(cells, fmt.Sprint(n)) } if hasNext { cells = append(cells, fmt.Sprintf("%dx", pay.NextAward)) } lines = append(lines, row(cells, true)) } lines = append(lines, border("└", "┴", "┘"), fmt.Sprintf("1 coin = %d credits | %d hand(s)", s.Denomination, s.Hands)) if s.Config.Feature != "" { lines = append(lines, fmt.Sprintf("Feature ON adds %d coin(s) per hand; requires five base coins.", s.Config.FeatureFeeCoins())) } return strings.Join(lines, "\n") } func renderPokerCards(cards []casino.CardView, held *[5]bool, mode string, unicode bool, size int, style string, store *cardart.Store) []string { if len(cards) == 0 { return nil } art := make([][]string, len(cards)) widths := make([]int, len(cards)) height := 0 for i, c := range cards { art[i] = cardsLine(mode, []casino.CardView{c}, size, unicode, style, store) height = max(height, len(art[i])) for _, line := range art[i] { widths[i] = max(widths[i], color.VisibleLen(line)) } if held != nil { widths[i] = max(widths[i], 6) } } var lines []string for r := 0; r < height; r++ { parts := make([]string, len(cards)) for i := range cards { text := "" if r < len(art[i]) { text = art[i][r] } parts[i] = rouletteCenter(text, widths[i]) } lines = append(lines, strings.Join(parts, " ")) } if held != nil { labels := make([]string, len(cards)) for i := range cards { text := fmt.Sprint(i + 1) if held[i] { text = color.Render(mode, color.ColorSpec{Fg: pokerYellow, Bg: -1, Bold: true}, text+" HELD") } labels[i] = rouletteCenter(text, widths[i]) } lines = append(lines, strings.Join(labels, " ")) } return lines } func renderVideoPoker(s *casino.VideoPokerSnapshot, mode string, unicode bool, size int, style string, store *cardart.Store) string { if s.Hands >= 100 { unicode = true } size = cardRenderSize(unicode, size) if s.Hands > 1 { size = min(size, 5) } if s.Hands >= 25 { size = 1 } var lines []string if s.ShowPayTable { lines = append(lines, renderPokerPayTable(s, mode), "") } feature := "" if s.Config.Feature != "" { feature = s.Config.FeatureLabel() + " OFF" if s.FeatureOn { feature = s.Config.FeatureLabel() + " ON" } } badge := "" if feature != "" { badge = pokerInk(mode, " ["+feature+"] ", false) } bonus := "" mult := s.Multiplier if s.Config.Feature == casino.PokerUltimateX { for _, n := range s.Current { mult = max(mult, n) } } if mult > 1 { text := fmt.Sprintf(" %dX! ", mult) if s.Config.Feature == casino.PokerUltimateX && s.Hands > 1 { text = fmt.Sprintf(" Up to %dX! ", mult) } bonus = pokerInk(mode, text, true) } if s.Dice[0] > 0 { bonus += fmt.Sprintf(" Dice [%d] + [%d]", s.Dice[0], s.Dice[1]) } decorated := badge != "" || bonus != "" if len(s.Cards) > 0 && len(s.Lines) == 0 { art := renderPokerCards(s.Cards, &s.Held, mode, unicode, size, style, store) if len(art) > 0 && decorated { art[0] += " " + badge + bonus } lines = append(lines, art...) } else if len(s.Lines) == 0 && decorated { lines = append(lines, badge+bonus) } for i, line := range s.Lines { art := renderPokerCards(line.Cards, nil, mode, unicode, size, style, store) if i == 0 && len(art) > 0 && decorated { art[0] += " " + badge + bonus } if len(s.Lines) > 1 && len(art) > 0 { art[0] = fmt.Sprintf("%3d: ", i+1) + art[0] } lines = append(lines, art...) text := "No win" fg := 15 if line.Coins > 0 { text = fmt.Sprintf("WIN: %s — %d coins", line.Category, line.Coins) fg = pokerYellow } if line.Multiplier > 1 { text += fmt.Sprintf(" (%dx)", line.Multiplier) } if len(s.Next) > i && s.Next[i] > 1 { text += fmt.Sprintf(" | earns %dx", s.Next[i]) } // Results always follow the cards, including compact hundred-play. lines = append(lines, color.Render(mode, color.ColorSpec{Fg: fg, Bg: -1, Bold: true}, text)) } if s.Result != "" { fg := pokerYellow if s.NoWin { fg = 15 } lines = append(lines, color.Render(mode, color.ColorSpec{Fg: fg, Bg: -1, Bold: true}, s.Result)) } if !s.Drawing && len(s.Lines) == 0 && s.Config.Feature == casino.PokerUltimateX && len(s.Next) > 0 { var parts []string for i, n := range s.Next { parts = append(parts, fmt.Sprintf("%d:%dx", i+1, n)) } lines = append(lines, "Multipliers on the machine: "+strings.Join(parts, " ")) } return "\n" + strings.Join(lines, "\n") + "\n" }