aboutsummaryrefslogtreecommitdiff
path: root/internal/game
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-10-03 00:51:41 -0400
committerhistoria <[not public]>2026-10-03 00:51:41 -0400
commit82e571d227feeafd0af4011e701ce26b99c5e3d9 (patch)
treeab4d56ddf94c3bf3b42fff5dfc2ff9a339f09113 /internal/game
parentcac16d1725c46c82a2e62b84c93f7090b2ce0746 (diff)
downloadthehouseoficarus-82e571d227feeafd0af4011e701ce26b99c5e3d9.tar.gz
fix: craps felt and wager description cleanup
Diffstat (limited to 'internal/game')
-rw-r--r--internal/game/casino.go2
-rw-r--r--internal/game/casino_edge_list_test.go20
-rw-r--r--internal/game/casino_house_edge.go6
-rw-r--r--internal/game/casino_ux.go2
-rw-r--r--internal/game/craps_test.go4
-rw-r--r--internal/game/game.go2
-rw-r--r--internal/game/render_casino_settlement.go6
-rw-r--r--internal/game/render_casino_settlement_test.go11
-rw-r--r--internal/game/render_craps.go113
-rw-r--r--internal/game/render_craps_test.go45
-rw-r--r--internal/game/render_roulette_test.go2
11 files changed, 162 insertions, 51 deletions
diff --git a/internal/game/casino.go b/internal/game/casino.go
index dc9f8f0..5e09d48 100644
--- a/internal/game/casino.go
+++ b/internal/game/casino.go
@@ -438,7 +438,7 @@ 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 <amount> on <target>. No wager was placed.")
+ sess.WriteLine("Use bet <n> on <bet>. No wager was placed.")
return
}
sawOn = true
diff --git a/internal/game/casino_edge_list_test.go b/internal/game/casino_edge_list_test.go
index ff0b965..902d178 100644
--- a/internal/game/casino_edge_list_test.go
+++ b/internal/game/casino_edge_list_test.go
@@ -34,6 +34,26 @@ func TestEdgeListAllTableGames(t *testing.T) {
}
}
+// TestCrapsListEveryBetHasRTP: once a reference item is carried, every
+// craps wager the list can name must resolve to a real percentage. An
+// unknown target would render the dash, which is the bug this guards.
+func TestCrapsListEveryBetHasRTP(t *testing.T) {
+ for _, variant := range []string{"bank", "crapless", "new_york"} {
+ t.Run(variant, func(t *testing.T) {
+ room := "name: CR\ncasino_tables:\n - id: cr\n game: craps\n craps:\n variant: " + variant + "\n"
+ g, sess, conn := houseEdgeGame(t, room)
+ writeHouseEdgeManual(t, g, sess, 2)
+ g.executePlay(sess, []string{"craps"}, "play craps")
+ g.executeBet(sess, []string{"10", "pass"}, "bet 10 pass")
+ conn.data = nil
+ g.executeList(sess, nil, "list")
+ if text := stripANSI(string(conn.data)); strings.Contains(text, "—") {
+ t.Fatalf("%s come-out list left a bet without RTP:\n%s", variant, text)
+ }
+ })
+ }
+}
+
func TestEdgeListBlackjackActionsOmitRTP(t *testing.T) {
g, sess, conn := houseEdgeGame(t, "name: BJ\ncasino_tables:\n - id: bj\n game: blackjack\n")
writeHouseEdgeManual(t, g, sess, 2)
diff --git a/internal/game/casino_house_edge.go b/internal/game/casino_house_edge.go
index 19d8cc2..1abbcac 100644
--- a/internal/game/casino_house_edge.go
+++ b/internal/game/casino_house_edge.go
@@ -78,8 +78,10 @@ func (g *Game) casinoListRows(sess *net.Session, t *casino.Table, wagers []casin
entry := row
if strings.Contains(wager.Bet, "<n>") {
entry.bet = strings.ReplaceAll(wager.Bet, "<n>", part.Label)
- } else {
- entry.win = part.Label + "; " + entry.win
+ } else if part.Label != "" {
+ // The label refines the shared win text (hop's doubles), so append
+ // it: the base phrase stays "Next roll is a/b (doubles)".
+ entry.win = entry.win + " " + part.Label
}
entry.edge = casino.HouseEdge{Parts: []casino.EdgePart{part}}
rows = append(rows, entry)
diff --git a/internal/game/casino_ux.go b/internal/game/casino_ux.go
index 2650d47..4c9accb 100644
--- a/internal/game/casino_ux.go
+++ b/internal/game/casino_ux.go
@@ -410,7 +410,7 @@ func (g *Game) showCasinoWagerList(sess *net.Session, t *casino.Table) {
g.showCasinoListTable(sess, "Bet", list)
return
}
- g.showCasinoListTable(sess, "bet <amount> on", g.casinoListRows(sess, t, rows))
+ g.showCasinoListTable(sess, "bet <n> on", g.casinoListRows(sess, t, rows))
}
// showCasinoGameLook appends the live game state and hint menu for the
diff --git a/internal/game/craps_test.go b/internal/game/craps_test.go
index 6712455..1e9ff6b 100644
--- a/internal/game/craps_test.go
+++ b/internal/game/craps_test.go
@@ -18,7 +18,7 @@ func TestCrapsCommandsAndRendering(t *testing.T) {
conn := &casinoTestConn{}
sess := &net.Session{Player: player.New("alice"), Conn: conn}
g.loggedInChars = map[string]*net.Session{"alice": sess}
- for _, args := range [][]string{{"12", "on", "place", "6"}, {"10", "on", "hop", "2", "3"}, {"10", "buy", "4"}, {"10", "on", "fire"}} {
+ for _, args := range [][]string{{"12", "on", "place", "6"}, {"10", "on", "hop", "2", "3"}, {"20", "buy", "4"}, {"10", "on", "fire"}} {
conn.data = nil
g.executeBet(sess, args, "bet "+strings.Join(args, " "))
if !strings.Contains(string(conn.data), "You don't have enough chips and credits") {
@@ -43,7 +43,7 @@ func TestCrapsCommandsAndRendering(t *testing.T) {
for _, unicode := range []bool{false, true} {
art := renderCrapsSnapshot(snap, mode, unicode)
plain := plainRoulette(art)
- for _, word := range []string{"PASS LINE", "DON'T COME", "FIELD", "FIRE", "SMALL", "Total: 7", "POINT 6"} {
+ for _, word := range []string{"PASS LINE", "DON'T COME", "F I E L D", "FIRE", "SMALL", "Total: 7", "POINT 6"} {
if !strings.Contains(plain, word) {
t.Fatal("missing", word)
}
diff --git a/internal/game/game.go b/internal/game/game.go
index f1855dc..3357077 100644
--- a/internal/game/game.go
+++ b/internal/game/game.go
@@ -750,7 +750,7 @@ func (g *Game) ProcessQueuedCommands() {
ss, _ := g.safespot.Get(p.Name)
isHiding := ss.Active
isBusy := p.Action != nil || len(p.WalkSequence) > 0 || g.Combat.Get(p.Name) != nil || p.MoveTicks > 0 || isHiding
- isCasinoSpin := g.Casino != nil && g.Casino.MachineBusy(p.Name)
+ isCasinoSpin := g.Casino != nil && (g.Casino.MachineBusy(p.Name) || g.Casino.TableBusy(p.Name))
_, isResting := g.restTimers[p.Name]
if !isResting && !isBusy && !isCasinoSpin && qc.Session.State() == net.StateGame {
g.writePrompt(qc.Session)
diff --git a/internal/game/render_casino_settlement.go b/internal/game/render_casino_settlement.go
index bfe101c..2b5acc9 100644
--- a/internal/game/render_casino_settlement.go
+++ b/internal/game/render_casino_settlement.go
@@ -149,6 +149,12 @@ func renderCasinoSettlement(lines []casino.SettlementLine, unicode bool, paint f
}
}
}
+ if settled == 0 {
+ // Nothing settled yet: the whole totals footer is noise, so end the
+ // receipt at the wager rows with the flat bottom border.
+ out = append(out, paint("dim", bl+strings.Repeat(h, inner)+br))
+ return strings.Join(out, "\n")
+ }
out = append(out, border(lj, bj, rj))
footer := func(text, tag string) {
out = append(out, paint("dim", v)+" "+paint(tag, pad(text, inner-2, false))+" "+paint("dim", v))
diff --git a/internal/game/render_casino_settlement_test.go b/internal/game/render_casino_settlement_test.go
index f26a174..15441ac 100644
--- a/internal/game/render_casino_settlement_test.go
+++ b/internal/game/render_casino_settlement_test.go
@@ -129,10 +129,15 @@ func TestCasinoReceiptIsPrivateEvenOnPublicResult(t *testing.T) {
}
}
-func TestCasinoReceiptUnresolvedIsNotPush(t *testing.T) {
+// TestCasinoReceiptUnresolvedOmitsTotals: while every wager is still live,
+// the receipt shows only the rows; the settled/active totals and NET PENDING
+// footer are omitted entirely.
+func TestCasinoReceiptUnresolvedOmitsTotals(t *testing.T) {
got := renderCasinoSettlement([]casino.SettlementLine{{Label: "Pass line", Stake: 100, Unresolved: true}}, false, plainReceipt)
- if !strings.Contains(got, "NET PENDING") || strings.Contains(got, "NET EVEN") || strings.Contains(got, "PUSH") {
- t.Fatal(got)
+ for _, gone := range []string{"NET PENDING", "NET EVEN", "PUSH", "Settled:", "Active:", "Staked:"} {
+ if strings.Contains(got, gone) {
+ t.Fatalf("unresolved receipt still shows %q:\n%s", gone, got)
+ }
}
}
diff --git a/internal/game/render_craps.go b/internal/game/render_craps.go
index ce9825f..e4e6618 100644
--- a/internal/game/render_craps.go
+++ b/internal/game/render_craps.go
@@ -21,17 +21,23 @@ const (
crapsPuckOn
crapsPuckOff
crapsBonus
+ crapsGoldInk
+ crapsBonusInk
+ crapsBonusDim
)
var crapsPaint = []color.ColorSpec{
{Fg: 15, Bg: crapsFelt},
{Fg: 229, Bg: crapsFelt, Bold: true},
- {Fg: 217, Bg: crapsFelt, Bold: true},
+ {Fg: 160, Bg: crapsFelt, Bold: true}, // deep red for come/pass/props
{Fg: 108, Bg: crapsFelt},
{Fg: 0, Bg: 220, Bold: true},
{Fg: 0, Bg: 15, Bold: true},
{Fg: 15, Bg: 0, Bold: true},
{Fg: 229, Bg: 24, Bold: true}, // Fire/ATS tracker: yellow on blue
+ {Fg: 229, Bg: crapsFelt}, // regular-weight gold, used for field notes
+ {Fg: 229, Bg: 24}, // regular-weight tracker text and brackets
+ {Fg: 108, Bg: 24}, // dim tracker odds, matching the place/lay payouts
}
type crapsCell struct {
@@ -93,6 +99,26 @@ func (c *crapsCanvas) center(x1, x2, y int, s string, ink int) {
c.text(x1+(x2-x1+1-color.VisibleLen(s))/2, y, s, ink)
}
+// crapsSpan is one color run inside a centered line. centerSpans lays the runs
+// end to end and centers their combined width, so a label can stay regular
+// weight while its payout is dim, or a heading can pair two inks on one row.
+type crapsSpan struct {
+ text string
+ ink int
+}
+
+func (c *crapsCanvas) centerSpans(x1, x2, y int, spans ...crapsSpan) {
+ total := 0
+ for _, s := range spans {
+ total += color.VisibleLen(s.text)
+ }
+ x := x1 + (x2-x1+1-total)/2
+ for _, s := range spans {
+ c.text(x, y, s.text, s.ink)
+ x += color.VisibleLen(s.text)
+ }
+}
+
// crapsJoints maps a union of box edges (N=1, E=2, S=4, W=8) to its glyph.
var crapsJoints = map[uint8]rune{3: '└', 6: '┌', 9: '┘', 12: '┐', 7: '├', 11: '┴', 13: '┤', 14: '┬', 15: '┼'}
@@ -191,17 +217,15 @@ func renderCrapsTrackers(s *casino.CrapsSnapshot, mode string, unicode bool) str
c.box(38, 4, 76, 6)
c.text(3, 1, "FIRE", crapsBonus)
for i, n := range []int{4, 5, 6, 8, 9, 10} {
- ink := crapsBonus
- if crapsHas(s.Made, n) {
- ink = crapsMarked
- }
- c.text(15+i*9, 1, fmt.Sprintf("[%2d]", n), ink)
+ crapsTrackerPoint(c, 15+i*9, 1, n, crapsHas(s.Made, n))
}
bounds := []int{0, 25, 50, 76}
for i, payout := range []string{"24:1", "249:1", "999:1"} {
lo, hi := bounds[i], bounds[i+1]
c.box(lo, 2, hi, 4)
- c.center(lo+1, hi-1, 3, fmt.Sprintf("%d POINTS %s", i+4, payout), crapsBonus)
+ c.centerSpans(lo+1, hi-1, 3,
+ crapsSpan{fmt.Sprintf("%d POINTS", i+4), crapsBonusInk},
+ crapsSpan{" " + payout, crapsBonusDim})
}
c.text(2, 5, "SMALL", crapsBonus)
c.text(40, 5, "TALL", crapsBonus)
@@ -210,16 +234,27 @@ func renderCrapsTrackers(s *casino.CrapsSnapshot, mode string, unicode bool) str
if i >= 5 {
x = 48 + (i-5)*5
}
- ink := crapsBonus
- if crapsHas(s.Seen, n) {
- ink = crapsMarked
- }
- c.text(x, 5, fmt.Sprintf("[%2d]", n), ink)
+ crapsTrackerPoint(c, x, 5, n, crapsHas(s.Seen, n))
}
return c.render(mode, unicode)
}
+
+// crapsTrackerPoint draws one bracketed total for the Fire/ATS tracker. The
+// brackets stay regular weight while the number itself is bold; a made or
+// seen point keeps its solid highlight across the whole token.
+func crapsTrackerPoint(c *crapsCanvas, x, y, n int, marked bool) {
+ if marked {
+ c.text(x, y, fmt.Sprintf("[%2d]", n), crapsMarked)
+ return
+ }
+ c.text(x, y, "[", crapsBonusInk)
+ c.text(x+1, y, fmt.Sprintf("%2d", n), crapsBonus)
+ c.text(x+3, y, "]", crapsBonusInk)
+}
func renderCrapsFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string {
- c := newCrapsCanvas(26)
+ // Compact half-table: every rail keeps its label and value on adjacent
+ // rows, so the felt is five rows shorter than the spaced-out layout.
+ c := newCrapsCanvas(21)
c.box(0, 0, 14, 6)
c.center(1, 13, 4, "DON'T COME", crapsInk)
c.center(1, 13, 5, "BAR 12", crapsMuted)
@@ -241,9 +276,9 @@ func renderCrapsFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string
c.box(0, 6, 50, 10)
c.center(1, 49, 7, "PLACE / BUY / LAY ON THE NUMBERS ABOVE", crapsMuted)
c.center(1, 49, 9, "C O M E", crapsRed)
- c.box(0, 10, 50, 16)
- c.center(1, 49, 11, "FIELD", crapsGold)
- c.center(1, 49, 13, "( 2 ) 3 4 9 10 11 ( 12 )", crapsInk)
+ c.box(0, 10, 50, 14)
+ c.center(1, 49, 11, "F I E L D", crapsGold)
+ c.center(1, 49, 12, "( 2 ) 3 4 9 10 11 ( 12 )", crapsInk)
twelve := s.Field12
if twelve == 0 {
twelve = 2
@@ -252,13 +287,17 @@ func renderCrapsFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string
if twelve == 3 {
twelvePay = "TRIPLE"
}
- c.center(1, 49, 15, fmt.Sprintf("2 PAYS DOUBLE 12 PAYS %s", twelvePay), crapsGold)
- c.box(0, 16, 50, 19)
- c.center(1, 49, 18, "DON'T PASS / BAR 12", crapsInk)
- c.box(0, 19, 50, 22)
- c.center(1, 49, 21, "PASS LINE", crapsGold)
- c.box(0, 22, 50, 25)
- c.center(1, 49, 24, "FREE ODDS / BEHIND THE LINE", crapsInk)
+ c.center(1, 49, 13, fmt.Sprintf("2 PAYS DOUBLE 12 PAYS %s", twelvePay), crapsGoldInk)
+ c.box(0, 14, 50, 16)
+ c.centerSpans(1, 49, 15, crapsSpan{"DON'T PASS", crapsInk}, crapsSpan{" BAR 12", crapsMuted})
+ c.box(0, 16, 50, 18)
+ c.center(1, 49, 17, "PASS LINE", crapsRed)
+ c.box(0, 18, 50, 20)
+ odds := s.Odds
+ if odds == "" {
+ odds = "3x-4x-5x"
+ }
+ c.centerSpans(1, 49, 19, crapsSpan{"FREE ODDS", crapsInk}, crapsSpan{" (" + odds + ")", crapsMuted})
// Centre action: four bonus spots, four hardways, six propositions, horn/hop.
// The Fire and ATS spots share one blue field.
bonus := []struct{ label, pays string }{{"FIRE", "24x"}, {"SMALL", "34:1"}, {"ALL", "175:1"}, {"TALL", "34:1"}}
@@ -269,11 +308,11 @@ func renderCrapsFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string
c.fill(50, 0, 76, 5, crapsBonus)
for i, spot := range bonus {
c.center(xs[i]+1, xs[i+1]-1, 2, spot.label, crapsBonus)
- c.center(xs[i]+1, xs[i+1]-1, 4, spot.pays, crapsBonus)
+ c.center(xs[i]+1, xs[i+1]-1, 4, spot.pays, crapsBonusDim)
}
for i, n := range []int{4, 6, 8, 10} {
- x, y := 50+(i%2)*13, 5+(i/2)*4
- c.box(x, y, x+13, y+4)
+ x, y := 50+(i%2)*13, 5+(i/2)*3
+ c.box(x, y, x+13, y+3)
c.center(x+1, x+12, y+1, fmt.Sprintf("HARD %d", n), crapsInk)
pay := 7
if n == 6 || n == 8 {
@@ -283,29 +322,29 @@ func renderCrapsFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string
if unicode {
pair = crapsDie(n/2) + "+" + crapsDie(n/2)
}
- c.center(x+1, x+12, y+3, fmt.Sprintf("%s %d:1", pair, pay), crapsGold)
+ c.centerSpans(x+1, x+12, y+2, crapsSpan{pair + " ", crapsGold}, crapsSpan{fmt.Sprintf("%d:1", pay), crapsMuted})
}
props := []string{"SEVEN", "CRAPS", "ELEVEN", "ACES", "ACE 3", "BOXCARS"}
- odds := []string{"4:1", "7:1", "15:1", "30:1", "15:1", "30:1"}
+ oddsRows := []string{"4:1", "7:1", "15:1", "30:1", "15:1", "30:1"}
px := []int{50, 59, 67, 76}
for i, label := range props {
- col, y := i%3, 13+(i/3)*4
+ col, y := i%3, 11+(i/3)*3
x, x2 := px[col], px[col+1]
- c.box(x, y, x2, y+4)
+ c.box(x, y, x2, y+3)
c.center(x+1, x2-1, y+1, label, crapsRed)
- c.center(x+1, x2-1, y+3, odds[i], crapsInk)
+ c.center(x+1, x2-1, y+2, oddsRows[i], crapsMuted)
}
- c.box(50, 21, 63, 25)
- c.center(51, 62, 22, "HORN", crapsGold)
+ c.box(50, 17, 63, 20)
+ c.center(51, 62, 18, "HORN", crapsGold)
horn := "2 3 11 12"
if unicode {
// Horn combinations as painted dice pairs: 2, 3, 11, 12.
horn = strings.Join([]string{crapsDie(1) + crapsDie(1), crapsDie(1) + crapsDie(2), crapsDie(5) + crapsDie(6), crapsDie(6) + crapsDie(6)}, " ")
}
- c.center(51, 62, 24, horn, crapsMuted)
- c.box(63, 21, 76, 25)
- c.center(64, 75, 22, "HOP", crapsGold)
- c.center(64, 75, 24, "15:1 / 30:1", crapsMuted)
+ c.center(51, 62, 19, horn, crapsMuted)
+ c.box(63, 17, 76, 20)
+ c.center(64, 75, 18, "HOP", crapsGold)
+ c.center(64, 75, 19, "15:1 / 30:1", crapsMuted)
return c.render(mode, unicode)
}
diff --git a/internal/game/render_craps_test.go b/internal/game/render_craps_test.go
index 49bda4a..b6a70be 100644
--- a/internal/game/render_craps_test.go
+++ b/internal/game/render_craps_test.go
@@ -18,7 +18,7 @@ func TestCrapsHalfTableGeometryAndPuck(t *testing.T) {
s := &casino.CrapsSnapshot{Point: point, Field12: 3}
art := renderCrapsFelt(s, "none", unicode)
rows := strings.Split(strings.TrimSuffix(art, "\n"), "\n")
- if len(rows) != 26 {
+ if len(rows) != 21 {
t.Fatal(len(rows))
}
for _, row := range rows {
@@ -48,7 +48,7 @@ func TestCrapsHalfTableGeometryAndPuck(t *testing.T) {
if !strings.Contains(art, "12 PAYS TRIPLE") {
t.Fatal("field variant invisible")
}
- for _, bet := range []string{"DON'T COME", "C O M E", "FIELD", "DON'T PASS", "PASS LINE", "HARD 4", "HARD 6", "HARD 8", "HARD 10", "SEVEN", "CRAPS", "ELEVEN", "ACES", "ACE 3", "BOXCARS", "HORN", "HOP"} {
+ for _, bet := range []string{"DON'T COME", "C O M E", "F I E L D", "DON'T PASS", "PASS LINE", "HARD 4", "HARD 6", "HARD 8", "HARD 10", "SEVEN", "CRAPS", "ELEVEN", "ACES", "ACE 3", "BOXCARS", "HORN", "HOP"} {
if strings.Count(art, bet) != 1 {
t.Fatalf("missing or duplicate %q", bet)
}
@@ -58,6 +58,45 @@ func TestCrapsHalfTableGeometryAndPuck(t *testing.T) {
t.Log("\n" + renderCrapsSnapshot(&casino.CrapsSnapshot{Point: 6, Field12: 3, Dice: [2]int{3, 3}, Queue: []string{"Alice", "Bob"}, Made: []int{4, 5}, Seen: []int{2, 4, 5, 6, 9}, Phase: "betting", ShootIn: 10, DealerIn: 70}, "none", true))
}
+// TestCrapsFeltOddsLabelAndCompaction pins the compacted felt copy: the
+// free-odds cap is printed in parentheses, the old behind-the-line suffix is
+// gone, and FIELD is letter-spaced.
+func TestCrapsFeltOddsLabelAndCompaction(t *testing.T) {
+ base := &casino.CrapsSnapshot{Point: 6, Field12: 3}
+ art := plainRoulette(renderCrapsFelt(base, "none", true))
+ for _, want := range []string{"F I E L D", "FREE ODDS (3x-4x-5x)", "DON'T PASS", "BAR 12"} {
+ if !strings.Contains(art, want) {
+ t.Fatalf("felt missing %q", want)
+ }
+ }
+ if strings.Count(art, "BAR 12") != 2 {
+ t.Fatalf("expected BAR 12 on both don't rails: %q", art)
+ }
+ for _, gone := range []string{"BEHIND THE LINE", "DON'T PASS /", "FREE ODDS /"} {
+ if strings.Contains(art, gone) {
+ t.Fatalf("felt still shows %q", gone)
+ }
+ }
+ custom := &casino.CrapsSnapshot{Point: 6, Field12: 3, Odds: "100x"}
+ if !strings.Contains(plainRoulette(renderCrapsFelt(custom, "none", true)), "FREE ODDS (100x)") {
+ t.Fatal("custom odds cap not shown")
+ }
+}
+
+// TestCrapsTrackerBracketsRegularNumbersBold pins the mixed tracker weights:
+// the bracket glyphs are regular while the total itself stays bold.
+func TestCrapsTrackerBracketsRegularNumbersBold(t *testing.T) {
+ art := renderCrapsTrackers(&casino.CrapsSnapshot{}, "xterm256", true)
+ regular := color.Render("xterm256", color.ColorSpec{Fg: 229, Bg: 24}, "[")
+ bold := color.Render("xterm256", color.ColorSpec{Fg: 229, Bg: 24, Bold: true}, " 4")
+ if !strings.Contains(art, regular) {
+ t.Fatal("tracker brackets are not regular weight")
+ }
+ if !strings.Contains(art, bold) {
+ t.Fatal("tracker numbers are not bold")
+ }
+}
+
// TestCrapsFireTrackerHighlightsMadePoints pins the Fire half of the tracker:
// made points highlight, un-made points do not, and no asterisk is involved.
func TestCrapsFireTrackerHighlightsMadePoints(t *testing.T) {
@@ -168,7 +207,7 @@ func TestCrapsRemindersFollowArt(t *testing.T) {
conn.data = nil
g.emitCasinoEvents(g.Casino.Table(1, "c").Status("alice"))
text := plainRoulette(string(conn.data))
- felt, commands := strings.Index(text, "PASS LINE"), strings.Index(text, "bet <amount> on <target>")
+ felt, commands := strings.Index(text, "PASS LINE"), strings.Index(text, "bet <n> on <bet>")
if felt < 0 || commands < felt {
t.Fatal("reminder above graphic", text)
}
diff --git a/internal/game/render_roulette_test.go b/internal/game/render_roulette_test.go
index 72da225..90cee0c 100644
--- a/internal/game/render_roulette_test.go
+++ b/internal/game/render_roulette_test.go
@@ -606,7 +606,7 @@ func TestRouletteMenuPutsReminderAfterBoard(t *testing.T) {
out := strings.ReplaceAll(string(conn.data), "\r\n", "\n")
tracker := strings.Index(out, "History: last 0 spins")
board := strings.Index(out, "R = red, B = black, G = green")
- reminder := strings.Index(out, "bet <amount> on <target>")
+ reminder := strings.Index(out, "bet <n> on <bet>")
if tracker < 0 || board < 0 || reminder < 0 {
t.Fatalf("missing tracker, board, or reminder:\n%s", out)
}