Skip to content

Writing dealer lines

The dealer corpus is hand-authored, offline, and shipping with 717 lines as of year-1. PRs that add lines are welcome — the rules below are the test-enforced contract.

Read The dealer’s voice before writing. The brief:

  • Aziraphale-Crowley register. Never campy. Never quippy.
  • He has been at this table longer than the wallpaper.
  • He calls you by name on the second night, not the first.
  • Cruelty is cheap. Fondness is the horror.
DealerLine(
id: 'win_n5_extra',
text: '"You took the third card. You shouldn\'t have. The cup tipped your way."',
event: DealerEvent.playerWin,
minNightIndex: 5,
)
FieldRequired?Notes
idyesStable, snake_case. Short but distinctive.
textyesAlways wrapped in "...". Use single-quotes inside via \'.
eventyesOne of DealerEvent.*. Don’t invent new events without engine wiring.
roomoptionalOne of 'diner', 'train', 'barbershop', 'drive_in', 'crossroads', 'final', or null (any).
minCourtesyoptionalDefault 0. Run-count gate.
minNightIndexoptionalDefault 0. Campaign-night gate.
requiresVowoptionalVow id required to be active.

Lines using {name} MUST have minNightIndex >= 2 (or rely on the picker’s name-line gate, which filters them out on Night 1). Picking a {name} line on Night 1 wouldn’t crash — the substitution falls back to “you” — but the rendered text reads awkwardly. The convention is: tag with minNightIndex: 2 and let the picker enforce.

RuleTest
No exclamation marksdealer_voice_test:tone check
No ALL CAPS (unless inside a quote attribution)dealer_voice_test:tone check
Unique idsdealer_corpus_integrity_test
Every event has ≥1 linedealer_voice_test:every event
Per-event minimum countsdealer_corpus_floor_test
Total corpus ≥700dealer_corpus_floor_test
Every {name} line is filtered on Night 1dealer_voice_campaign_test

If any of these fail, the PR doesn’t merge.

If you’ve never written for the dealer, read:

  1. The Good Omens novel. Crowley + Aziraphale dialogue.
  2. lib/sim/dealer_voice.dart line 100-300 (existing baseline greets).
  3. wiki/src/content/docs/voice/dealer.md (this site).

Don’t read modern poker / casino fiction. Don’t read Dungeons & Degenerate Gamblers’ tone (we ship the opposite of that).

MistakeWhy it doesn’t fit
Slang (“dealer’s gonna deal”)He is older than the language.
One-liners (“I’ll allow it.”)Quips break the spell.
Exclamation marksThe tone-check test fails. Also: he doesn’t shout.
References to real casinos / Vegas / brand namesThis table may not exist.
Making him cruelCruelty is cheap. Fondness is the horror.

You want to add a midHand observation for a player taking unusually long to decide.

// Don't:
DealerLine(
id: 'mid_long_decide',
text: '"Take your time! I\'ve got all night!"',
event: DealerEvent.midHand,
)
// Tone fails: exclamation marks, fake-cheery register.
// Better:
DealerLine(
id: 'mid_long_decide',
text: '"He waits. He has been doing this longer than you have been deciding."',
event: DealerEvent.midHand,
)
// Aziraphale-Crowley: dry, faintly fond, factual.

Open lib/sim/dealer_voice.dart. Find the relevant event group (the file is grouped by event with comments). Insert your DealerLine(...) in the corresponding section. Don’t reorder existing lines unless you’re explicitly cleaning up.

Run:

flutter test test/sim/dealer_voice_test.dart \
test/sim/dealer_corpus_integrity_test.dart \
test/sim/dealer_corpus_floor_test.dart

All three should pass.

If you regenerated goldens (flutter test --update-goldens), the table-screen golden snapshots will likely shift since the dealer-line RNG picks change with corpus size. Commit the golden updates with your PR.