1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 17:06:04 +00:00
nescript/examples/war/assets.ne
Claude 8ababdcec4
examples/war: working end-to-end War card game
A complete, playable port of the card game War: title screen with
0/1/2 player menu, animated deal, sliding cards, deck-count HUD, a
"WAR!" tie-break with buried cards, and a victory screen with a
fanfare. Source split across examples/war/*.ne (constants, assets,
audio, deck/queue logic, RNG, render helpers, and one state file
per game state) and pulled in via examples/war.ne.

Drives nearly every NEScript subsystem at once: custom 88-tile
sprite sheet (card frames, ranks, suits, font, BIG WAR letters);
felt background nametable; pulse-1 / pulse-2 / noise sfx; looping
march on pulse 2; an 8-bit Galois LFSR PRNG; queue-based decks
that conserve cards across rounds; a phase machine inside the
Playing state that handles draw/reveal/win/war/check; and an
autopilot that boots straight into 0-PLAYERS mode so the headless
jsnes harness captures real gameplay at frame 180.

While building this I uncovered five compiler bugs / limitations
in the v0.1 implementation; each is documented with a minimal
reproduction, root cause, current workaround, and proposed fix in
examples/war/COMPILER_BUGS.md. The most painful was the
parameter-VarId aliasing one (#1b) — two functions sharing a
parameter NAME end up sharing a single zero-page slot mapping
across the whole program. Once those compiler bugs are fixed, the
workarounds in war/*.ne should be reverted in the same PR.

https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 15:22:20 +00:00

856 lines
22 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// war/assets.ne — the one big Tileset sprite block.
//
// Every custom 8×8 CHR tile in the game is stacked vertically inside
// a single `sprite Tileset { pixels: [...] }` declaration. Stacking
// them 1-tile-wide × N-tiles-tall means the parser splits each tile
// into consecutive tile indices in reading order, so tile index N in
// a `draw Tileset frame: N` call picks the N'th 8×8 block.
//
// Every constant in constants.ne points at a position in this list.
// If you add or remove a tile, update BOTH this file AND the matching
// constant range.
//
// The colour vocabulary (per the palette declaration in war.ne):
//
// . transparent
// 1 red (palette index 1 — hearts, diamonds, accents)
// 2 white (palette index 2 — card body, letters)
// 3 black (palette index 3 — outlines, spades, clubs, text)
//
// All tiles below use this 4-colour alphabet. Red is only used for
// red suits; black is used for text, outlines, and black suits.
sprite Tileset {
pixels: [
// ── 01: card frame top-left corner ───────────────
// Rounded top-left corner of a card body. Black outline
// two pixels thick on the exterior, white interior so
// rank glyphs drawn with black pixels read cleanly on
// top. The interior corner is pure white so the rank
// tile (drawn next to it) overpaints naturally.
"..333333",
".3222222",
".3222222",
"3222....",
"3222....",
"3222....",
"3222....",
"3222....",
// ── 02: card frame top-right corner ──────────────
"333333..",
"2222223.",
"2222223.",
"....2223",
"....2223",
"....2223",
"....2223",
"....2223",
// ── 03: card frame bottom-left corner ────────────
"3222....",
"3222....",
"3222....",
"3222....",
"3222....",
".3222222",
".3222222",
"..333333",
// ── 04: card frame bottom-right corner ───────────
"....2223",
"....2223",
"....2223",
"....2223",
"....2223",
"2222223.",
"2222223.",
"333333..",
// ── 05: card frame blank cell — left half ────────
// Pure white interior with a left black edge (for the
// card's left border). Used for the blank middle /
// bottom of any card face that doesn't carry art.
"32222222",
"32222222",
"32222222",
"32222222",
"32222222",
"32222222",
"32222222",
"32222222",
// ── 06: card frame blank cell — right half ───────
"22222223",
"22222223",
"22222223",
"22222223",
"22222223",
"22222223",
"22222223",
"22222223",
// ── 07: card back top-left ───────────────────────
// The back is a black-and-white diamond lattice,
// painted as a 2×2 repeating block. Every card back
// uses all four corners tiled into a 16×16 / 16×24
// block.
"..333333",
".3333333",
".3322333",
"333.2.33",
"33.222.3",
"33.2.233",
"3322.333",
"3333.333",
// ── 08: card back top-right ──────────────────────
"333333..",
"3333333.",
"33322.33",
"33.2.333",
"3.222.33",
"33.2.333",
"333.2233",
"3333.333",
// ── 09: card back bottom-left ────────────────────
"3333.333",
"3322.333",
"33.2.233",
"33.222.3",
"333.2.33",
".3322333",
".3333333",
"..333333",
// ── 10: card back bottom-right ───────────────────
"3333.333",
"333.2233",
"33.2.333",
"3.222.33",
"33.2.333",
"33322.33",
"3333333.",
"333333..",
// ── 11: rank A (Ace) ─────────────────────────────
// Bold black glyph on a white card body. The rank is
// drawn 6×6 px and centred horizontally in the 8×8 tile.
// The card body fills index 2 (white) so the glyph reads
// as black-on-white when the card frame's outline tiles
// wrap it.
"22222222",
"22.33.22",
"2.3333.2",
"2.3..3.2",
"2.3333.2",
"2.3..3.2",
"2.3..3.2",
"22222222",
// ── 12: rank 2 ───────────────────────────────────
"22222222",
"2.3333.2",
"2....3.2",
"22.33.22",
"2.3...22",
"2.3...22",
"2.3333.2",
"22222222",
// ── 13: rank 3 ───────────────────────────────────
"22222222",
"2.3333.2",
"22...3.2",
"22.33.22",
"22...3.2",
"2....3.2",
"2.3333.2",
"22222222",
// ── 14: rank 4 ───────────────────────────────────
"22222222",
"2.3..3.2",
"2.3..3.2",
"2.3..3.2",
"2.3333.2",
"22...3.2",
"22...3.2",
"22222222",
// ── 15: rank 5 ───────────────────────────────────
"22222222",
"2.3333.2",
"2.3...22",
"2.3333.2",
"22...3.2",
"22...3.2",
"2.3333.2",
"22222222",
// ── 16: rank 6 ───────────────────────────────────
"22222222",
"2.3333.2",
"2.3...22",
"2.3333.2",
"2.3..3.2",
"2.3..3.2",
"2.3333.2",
"22222222",
// ── 17: rank 7 ───────────────────────────────────
"22222222",
"2.3333.2",
"22...3.2",
"22..3.22",
"22.3..22",
"22.3..22",
"22.3..22",
"22222222",
// ── 18: rank 8 ───────────────────────────────────
"22222222",
"2.3333.2",
"2.3..3.2",
"2.3333.2",
"2.3..3.2",
"2.3..3.2",
"2.3333.2",
"22222222",
// ── 19: rank 9 ───────────────────────────────────
"22222222",
"2.3333.2",
"2.3..3.2",
"2.3..3.2",
"2.3333.2",
"22...3.2",
"2.3333.2",
"22222222",
// ── 20: rank 10 (condensed "1" + "0") ─────────────
// "10" squeezed into an 8x8 tile. The "1" takes columns
// 0-1, a gap, the "0" takes columns 4-7.
"22222222",
"2.3.33.2",
"233.3..3",
"2.3.3..3",
"2.3.3..3",
"2.3.3..3",
"2.3.33.2",
"22222222",
// ── 21: rank J ───────────────────────────────────
"22222222",
"222.33.2",
"222..3.2",
"222..3.2",
"222..3.2",
"22.3.3.2",
"22.333.2",
"22222222",
// ── 22: rank Q ───────────────────────────────────
"22222222",
"2.3333.2",
"2.3..3.2",
"2.3..3.2",
"2.3.33.2",
"2.3333.2",
"22.33.32",
"22222222",
// ── 23: rank K ───────────────────────────────────
"22222222",
"2.3..3.2",
"2.3.3.22",
"2.33..22",
"2.3.3.22",
"2.3..3.2",
"2.3..3.2",
"22222222",
// ── 24: small spade ♠ ────────────────────────────
// 6x6 centred pip on a white 8x8 tile.
"22222222",
"2222.222",
"222.3.22",
"22.333.2",
"2.33333.",
"2.33333.",
"222.3.22",
"222333.2",
// ── 25: small heart ♥ ────────────────────────────
// Red pip on white.
"22222222",
"22.11.22",
"2.1111.2",
"2.1111.2",
"2.1111.2",
"22.11.22",
"222.1.22",
"22222222",
// ── 26: small diamond ♦ ──────────────────────────
"22222222",
"22221222",
"2221.122",
"221...12",
"221...12",
"2221.122",
"22221222",
"22222222",
// ── 27: small club ♣ ─────────────────────────────
"22222222",
"2222.222",
"2223332.",
"2223332.",
"22.333.2",
"2.33333.",
"22.3.3.2",
"222333.2",
// ── 28: big spade — left half ────────────────────
// The big centre-pip is drawn 16×8: two tiles side by
// side. Each suit's (left half, right half) pair is
// authored explicitly so the centre art can be bolder
// and more symmetric than the corner pips.
"2222222.",
"222222.3",
"22222.33",
"2222.333",
"222.3333",
"22.33333",
"2.333333",
".3333333",
// ── 29: big heart — left half ────────────────────
"2222.111",
"222.1111",
"22.11111",
"22.11111",
"22.11111",
"222.1111",
"2222.111",
"22222.11",
// ── 30: big diamond — left half ──────────────────
"22222222",
"22222.12",
"2222.112",
"222.1112",
"22.11112",
"2.111112",
"22.11112",
"222.1112",
// ── 31: big club — left half ─────────────────────
"2222.333",
"2222.333",
"222.3333",
"22.33333",
"2.333333",
"2.333333",
"22.333.3",
"2223.333",
// ── 32: big spade — right half ───────────────────
".3333333",
"2.333333",
"22.33333",
"222.3333",
"2222.333",
"22222.33",
"222222.3",
"2222222.",
// ── 33: big heart — right half ───────────────────
"111.2222",
"1111.222",
"11111.22",
"11111.22",
"11111.22",
"1111.222",
"111.2222",
"11.22222",
// ── 34: big diamond — right half ─────────────────
"22222222",
"21.22222",
"211.2222",
"2111.222",
"21111.22",
"211111.2",
"21111.22",
"2111.222",
// ── 35: big club — right half ────────────────────
"333.2222",
"333.2222",
"3333.222",
"33333.22",
"333333.2",
"333333.2",
"3.333.22",
"333.3222",
// ── 36-61: alphabet A..Z (8x8, white on transparent) ─
// Bold sans-serif letters drawn with 2-pixel strokes so
// they still read over the felt at NES resolution. Every
// letter uses palette index 2 (white) on a transparent
// background. Letters are 6 wide, centred horizontally
// in the 8-wide tile with a 1-pixel top/bottom margin.
// A
"........",
"..2222..",
".22..22.",
".22..22.",
".222222.",
".22..22.",
".22..22.",
"........",
// B
"........",
".22222..",
".22..22.",
".22222..",
".22..22.",
".22..22.",
".22222..",
"........",
// C
"........",
"..22222.",
".22..22.",
".22.....",
".22.....",
".22..22.",
"..22222.",
"........",
// D
"........",
".2222...",
".22.22..",
".22..22.",
".22..22.",
".22.22..",
".2222...",
"........",
// E
"........",
".222222.",
".22.....",
".22222..",
".22.....",
".22.....",
".222222.",
"........",
// F
"........",
".222222.",
".22.....",
".22222..",
".22.....",
".22.....",
".22.....",
"........",
// G
"........",
"..22222.",
".22.....",
".22.222.",
".22..22.",
".22..22.",
"..2222..",
"........",
// H
"........",
".22..22.",
".22..22.",
".222222.",
".22..22.",
".22..22.",
".22..22.",
"........",
// I
"........",
"..2222..",
"...22...",
"...22...",
"...22...",
"...22...",
"..2222..",
"........",
// J
"........",
"....222.",
".....22.",
".....22.",
".....22.",
".22..22.",
"..2222..",
"........",
// K
"........",
".22..22.",
".22.22..",
".2222...",
".22.22..",
".22..22.",
".22..22.",
"........",
// L
"........",
".22.....",
".22.....",
".22.....",
".22.....",
".22.....",
".222222.",
"........",
// M
"........",
".22..22.",
".222222.",
".222222.",
".22..22.",
".22..22.",
".22..22.",
"........",
// N
"........",
".22..22.",
".222.22.",
".222222.",
".22.222.",
".22..22.",
".22..22.",
"........",
// O
"........",
"..2222..",
".22..22.",
".22..22.",
".22..22.",
".22..22.",
"..2222..",
"........",
// P
"........",
".22222..",
".22..22.",
".22..22.",
".22222..",
".22.....",
".22.....",
"........",
// Q
"........",
"..2222..",
".22..22.",
".22..22.",
".22.222.",
".22.22..",
"..222.2.",
"........",
// R
"........",
".22222..",
".22..22.",
".22..22.",
".22222..",
".22.22..",
".22..22.",
"........",
// S
"........",
"..22222.",
".22.....",
"..2222..",
".....22.",
".....22.",
".22222..",
"........",
// T
"........",
".222222.",
"...22...",
"...22...",
"...22...",
"...22...",
"...22...",
"........",
// U
"........",
".22..22.",
".22..22.",
".22..22.",
".22..22.",
".22..22.",
"..2222..",
"........",
// V
"........",
".22..22.",
".22..22.",
".22..22.",
".22..22.",
"..2222..",
"...22...",
"........",
// W
"........",
".22..22.",
".22..22.",
".22..22.",
".222222.",
".222222.",
".22..22.",
"........",
// X
"........",
".22..22.",
"..2222..",
"...22...",
"...22...",
"..2222..",
".22..22.",
"........",
// Y
"........",
".22..22.",
".22..22.",
"..2222..",
"...22...",
"...22...",
"...22...",
"........",
// Z
"........",
".222222.",
".....22.",
"....22..",
"...22...",
"..22....",
".222222.",
"........",
// ── 62-71: digits 0..9 (bold) ──────────────────
// 0
"........",
"..2222..",
".22..22.",
".22..22.",
".22..22.",
".22..22.",
"..2222..",
"........",
// 1
"........",
"...22...",
"..222...",
".2.22...",
"...22...",
"...22...",
"..2222..",
"........",
// 2
"........",
"..2222..",
".22..22.",
".....22.",
"....22..",
"..22....",
".222222.",
"........",
// 3
"........",
"..2222..",
".22..22.",
"....22..",
".....22.",
".22..22.",
"..2222..",
"........",
// 4
"........",
"....22..",
"...222..",
"..2.22..",
".22.22..",
".222222.",
"....22..",
"........",
// 5
"........",
".222222.",
".22.....",
".22222..",
".....22.",
".22..22.",
"..2222..",
"........",
// 6
"........",
"..2222..",
".22.....",
".22222..",
".22..22.",
".22..22.",
"..2222..",
"........",
// 7
"........",
".222222.",
".....22.",
"....22..",
"...22...",
"..22....",
"..22....",
"........",
// 8
"........",
"..2222..",
".22..22.",
"..2222..",
".22..22.",
".22..22.",
"..2222..",
"........",
// 9
"........",
"..2222..",
".22..22.",
".22..22.",
"..22222.",
".....22.",
"..2222..",
"........",
// ── 72: cursor (▶) ────────────────────────────
"........",
"..2.....",
"..22....",
"..222...",
"..222...",
"..22....",
"..2.....",
"........",
// ── 73: tiny heart (victory marker) ───────────
"........",
".11..11.",
"11111111",
"11111111",
".111111.",
"..1111..",
"...11...",
"........",
// ── 74: single dot (stack marker / spacer) ────
"........",
"...22...",
"..2222..",
"..2222..",
"..2222..",
"..2222..",
"...22...",
"........",
// ── 75: felt background fill ─────────────────
// Subtle cross-hatch on the felt. When the background
// layer renders this tile through bg sub-palette 0
// (universal dk_green + forest/green/mint), index 0
// becomes dk_green and index 3 becomes mint — so the
// tile shows as dk_green felt with sparse mint flecks.
// The same CHR rendered as a sprite would show as
// transparent + black, which we never do.
"........",
"....3...",
"........",
"..3.....",
"........",
"......3.",
"........",
"...3....",
// ── 76-87: BIG WAR title letters ─────────────
// Each letter is 16×16 = a 2x2 block of tiles. The
// letters are designed bold and chunky so the title
// reads from across the room. Each tile draws a
// quadrant of the letter using palette index 2 (white
// when rendered via sp0, white when rendered via the
// bg cream sub-palette).
//
// 76: BIG W top-left
"22....22",
"22....22",
"22....22",
"22....22",
"22....22",
"22....22",
"22....22",
"22....22",
// 77: BIG W top-right
"22....22",
"22....22",
"22....22",
"22....22",
"22....22",
"22....22",
"22....22",
"22....22",
// 78: BIG W bottom-left
"22....22",
"22....22",
"22.22.22",
"22.22.22",
"22.22.22",
"2222.222",
"2222.222",
".22..22.",
// 79: BIG W bottom-right
"22....22",
"22....22",
"22.22.22",
"22.22.22",
"22.22.22",
"222.2222",
"222.2222",
".22..22.",
// 80: BIG A top-left
"....2222",
"...22222",
"..222222",
".2222.22",
"2222..22",
"2222..22",
"222....2",
"222....2",
// 81: BIG A top-right
"2222....",
"22222...",
"222222..",
"22.2222.",
"22..2222",
"22..2222",
"2....222",
"2....222",
// 82: BIG A bottom-left
"22222222",
"22222222",
"22222222",
"222....2",
"222....2",
"222....2",
"222....2",
"222....2",
// 83: BIG A bottom-right
"22222222",
"22222222",
"22222222",
"2....222",
"2....222",
"2....222",
"2....222",
"2....222",
// 84: BIG R top-left
"22222222",
"22222222",
"222....2",
"222....2",
"222....2",
"222....2",
"22222222",
"22222222",
// 85: BIG R top-right
"2222....",
"22222...",
"..222...",
"..222...",
"..222...",
"..2222..",
".22222..",
"22222...",
// 86: BIG R bottom-left
"22222222",
"22222222",
"222.2222",
"222..222",
"222...22",
"222...22",
"222....2",
"222....2",
// 87: BIG R bottom-right
"22......",
"222.....",
"2222....",
"22222...",
"222222..",
"2222222.",
"22222222",
".2222222"
]
}