aboutsummaryrefslogtreecommitdiff
path: root/building_guide/roulette.md
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-10-01 14:38:08 -0400
committerhistoria <[not public]>2026-10-01 14:38:08 -0400
commit1082f3336085c15992ca83d5553c0ba52208d70a (patch)
tree4fcedaa90bc01c41456258a9d57f492f31754948 /building_guide/roulette.md
parentd4eae333a8d8a96452bbf3617aa85b50466c11a7 (diff)
downloadthehouseoficarus-1082f3336085c15992ca83d5553c0ba52208d70a.tar.gz
feat: pai gow poker added to the casino
Diffstat (limited to 'building_guide/roulette.md')
-rw-r--r--building_guide/roulette.md164
1 files changed, 0 insertions, 164 deletions
diff --git a/building_guide/roulette.md b/building_guide/roulette.md
deleted file mode 100644
index e3794e2..0000000
--- a/building_guide/roulette.md
+++ /dev/null
@@ -1,164 +0,0 @@
-# Roulette and casino extension readiness
-
-The casino has a usable extension seam: `tableGame`, generic `tableCore`,
-registered constructors/config validation in `registry.go`, structured snapshots,
-shared participation/control routing, and durable per-stake wallet handles.
-Roulette uses those seams rather than adding another command dispatcher.
-
-Example table (one game of each type per room remains the manager's rule):
-
-```yaml
-casino_tables:
- - id: roulette_single
- game: roulette
- min_bet: 1
- max_bet: 10000
- betting_ticks: 15
- roulette:
- double_zero: false
- spin_ticks: 4
-```
-
-`double_zero: true` selects the American 38-pocket wheel; otherwise the
-European 37-pocket wheel is used. Spin ticks default to 3; betting ticks use
-the shared default. Ticks follow the server's configured tick length.
-The wheel order is authentic and the outcome is selected uniformly only when
-spinning finishes.
-
-## Presentation
-
-Art is rendered per recipient in `internal/game/render_roulette.go`, so color
-mode and Unicode preference stay per player (the engine snapshot never embeds
-ANSI). The views and betting tracker share one snapshot renderer:
-
-- **Tracker**: a five-line, 74-column strip above the betting board, rendered
- by `render_roulette_tracker.go`. The betting snapshot leads with a blank line
- so the tracker is separated from the prose or menu that precedes it. It shows
- the latest eight hits (newest first), three hot/cold pockets with hit counts,
- and red/black/zero percentages.
- All stats use a table-local rolling window of 50 completed spins. Zeros are
- included in the denominator; ties use numeric order (0, 00, 1, ...).
- History is copied into snapshots, never sampled before settlement, and
- survives round resets but not table replacement or server restart.
- History is copied into snapshots, never sampled before settlement, and
- survives round resets but not table replacement or server restart.
-- **Snapshot cadence**: the board and tracker are drawn once per round by the
- betting menu (on join and after settlement) and by an
- explicit `table`/`table rules`. Placing a wager only confirms the wager; it
- does not re-send the board snapshot.
-- **Betting board**: numbered grid with zeros in the left lane, red/black
- pockets, and outside bets. The whole five-row zero lane (three numbered rows
- plus the two separators between them) carries the green background, and its
- outer corners are rounded in Unicode mode. A racetrack table draws
- `renderRouletteRacetrack` above the board: a numbered oval in physical
- clockwise wheel order, with 26 at the right tip. Interior dividers meet
- each call bet's pockets, left to right: Tiers du Cylindre, Orphelins,
- Voisins du Zero, Zero. Labels are centered on the middle row; a label too
- wide to leave a blank cell against its dividers wraps onto the rows above
- and below it (e.g. "Tiers du" / "Cylindre"), and only the glyphs are
- written so the centering padding never paints over the dividers. Connected
- box-drawing steps separate Tiers from Orphelins; Zero has a curved boundary
- within Voisins. Neighbors is not drawn on the board, but remains in the
- payout reference and help.
-- **Menu ordering**: the roulette betting menu prints its balance and
- heading, then the tracker and board, and only then the wager reminder
- (`bet <amount> on <target>`, `bet / rebet`, `table / sitout / stop`) so the
- instructions follow the table they describe. Other games keep their menu
- above the snapshot.
-- **Spinning**: a stylised 17x9 wheel (wider than tall so it reads as a circle
- in a terminal cell grid). Only the rim is colored: solid red pockets alternate
- with a very dark blue that stands in for black (`rouletteWheelBlack`), because
- pure black vanishes on dark terminals. Pockets are two cells wide except the
- top and bottom centres, which stay one cell. One pocket is green (plus its
- diametrically opposite pocket on American wheels). A simple plus marks the
- croupier's spindle. No pocket numbers are drawn; with color off the pockets
- fall back to R/B/G so the wheel still reads.
-- **Result**: the winning pocket plus two physical wheel neighbours on each
- side (five cards) at playing-card size. The pocket number sits on the top row,
- a rule separates it from the ball (one row above centre), and the color name
- is spelled out on the bottom row only when color is off. There is no
- surrounding prose. The smallest (five-row) cards drop the rule so the ball
- can sit directly under the number. The wheel and result graphics each get a
- blank line before and after so they do not crowd the prose.
-
-The colored payout tables in `internal/game/render_casino_help.go` use the
-shared ANSI-aware `ui.Table` renderer, respecting ASCII/Unicode and wrap width.
-They show wheel-specific win chances and net profit odds, including call-bet
-exceptions. They appear only with `table` and `table rules`, not ambient art.
-`table help` opens the current game's guide; `help casino` indexes the brief
-casino guides in `data/help/`. `help racetrack` explains chip placements and
-rounding, including `zero`/`jeu zero` versus the straight-number target `0`.
-Each table's one-line
-overview is kept short (`Label | Limits 1-10000 | n/m seated | state`) so it
-fits beside a look minimap; `writeLookSideBySide` also wraps any content line
-that would otherwise run into the map column.
-
-Initial scope is **one wager per player per spin**. A wager covers straight-up
-numbers, outside bets (colors, parity, high/low, 1to12/13to24/25to36, rows),
-and the combination bets: splits, streets, corners, six-lines, trios, and the
-basket. Combination targets are a compact number list (`split 1 2`,
-`street 1-2-3`, `corner 1 2 4 5`, `line 1 2 3 4 5 6`, `trio 0 00 2`,
-`basket`) joined from the tokens after `on`; the leading name is optional
-because the geometry of the covered set identifies the bet. Non-adjacent or
-wrong-shaped sets are rejected rather than silently accepted. Multiple
-simultaneous wagers remain future work: `Participant.Wager` still holds a
-single stake.
-
-Single-zero tables may set `roulette.racetrack: true`. That adds the four
-French call bets (Voisins du Zéro, Tiers du Cylindre, Orphelins, Jeu Zero)
-and the Neighbors bet (a chosen number plus four on each side in wheel order).
-The racetrack is a single-zero layout only: the validator rejects
-`racetrack: true` together with `double_zero: true`. A call bet is **one
-wager** whose amount is the total stake spread evenly over the bet's chips
-(Voisins 9, Tiers 6, Orphelins 5, Jeu Zero 4, Neighbors 9). Because the
-components are ordinary inside bets, each returns `36/covered` when its
-number hits, so a winning pocket can pay a different multiple of the stake
-than another (for example 0 on Voisins pays 24/9, while 4 pays 18/9). The
-engine therefore resolves a wager to exact per-pocket `num/den` shares
-(`roulette_racetrack.go`) instead of a single multiplier; `bet` validates
-every possible return before committing and `settle` floors
-`stake*num/den`. The rack panel is drawn by `renderRouletteRacetrack` above
-the board and lists each bet's wheel-order series.
-
-All returns are checked before debiting a wager. Both winning and losing stakes
-settle through `PayCredits(return, stakeID)`, including a zero return for losses.
-Failures leave the stake pending and do not claim that payment succeeded.
-Shutdown and eviction refund outstanding stakes and reset the round.
-Disconnect refunds are safe because no partial outcome is sampled or exposed.
-
-Settlements are rendered by `settlementText` in `internal/casino/table_ux.go`:
-a colored win/loss/push headline gives the round's net once (the old
-"Net ... | ... returned (stake included)" split is gone), then each named bet
-— a blackjack hand, insurance, or the table's spot — is listed with its own
-net. Wins are green, losses red, pushes white, and a natural keeps the jackpot
-gradient. The engine emits inline color tags (`{casino_result_win}WIN{/}`),
-which `Game.casinoProse` expands per recipient against the session palette, so
-the engine still never embeds ANSI. Casino prose defaults to white
-(`casino_action`), leaving color for emphasized outcomes.
-
-## Assessment and boundaries
-
-This is a sound foundation for more testing-stage table games, not a blanket
-production-readiness certification. New games must test payout math, overflow,
-phase boundaries, disconnects, queued departure, refunds, persistence failure,
-and spectator output. Shared card-game loss settlement still uses the void
-`ResolveStakesByIDs` API: it preserves failed stakes for recovery but cannot
-report that failure to its caller. Roulette avoids that limitation with the
-existing error-returning payment API. Uniform per-stake error-returning
-settlement would be a worthwhile follow-up for older games.
-
-Multiple concurrent wagers need their own explicit ledger/limit model instead
-of reusing the single `Participant.Wager`. Multiple same-game tables in one room
-would also require changing current addressing/validation assumptions.
-
-## Testing shortcut
-
-`data/objects/casino_test_portal.yaml` is placed in starting room 1001.
-`use casino` gives 1000 chips and teleports to vestibule 6100. It is intentionally
-repeatable and uses ordinary trigger/drop/teleport machinery. Keep an inventory
-slot free (ordinary trigger drops fall to the ground when inventory is full).
-Remove the room's `casino_test_portal` reference before production: this grants
-unlimited test funds and bypasses travel/progression. No account roles are needed.
-
-Single-zero room 6182 and double-zero room 6183 are north of ground-floor
-landing 6102. `help roulette` describes player syntax and supported bets.