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
|
|
|
|
// 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",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
// ── 07-10: card back ─────────────────────────────
|
|
|
|
|
|
//
|
|
|
|
|
|
// A simple 2×2 checkerboard of 2-pixel squares in black
|
|
|
|
|
|
// (palette 3) and white (palette 2). Each 8×8 tile
|
|
|
|
|
|
// carries one quadrant of a 16×16 repeating block; the
|
|
|
|
|
|
// pattern is self-similar, so every corner tile is
|
|
|
|
|
|
// actually the same art — they just get named TL/TR/BL/
|
|
|
|
|
|
// BR so draw_card_back reads naturally.
|
|
|
|
|
|
//
|
|
|
|
|
|
// draw_card_back draws a 16×24 card as:
|
|
|
|
|
|
// [TL][TR] row 0 (y=0-7)
|
|
|
|
|
|
// [BL][BR] row 1 (y=8-15)
|
|
|
|
|
|
// [TL][TR] row 2 (y=16-23) — pattern repeats
|
|
|
|
|
|
//
|
|
|
|
|
|
// The checkerboard tiles below therefore tile seamlessly
|
|
|
|
|
|
// both horizontally (TL vs TR) and vertically (row 0 vs
|
|
|
|
|
|
// row 2), which the old diamond-lattice design did not.
|
|
|
|
|
|
|
|
|
|
|
|
// ── 07: card back — TL quadrant ──────────────────
|
|
|
|
|
|
// 2-pixel square checkerboard, starting black at (0,0).
|
|
|
|
|
|
// ##..##..
|
|
|
|
|
|
// ##..##..
|
|
|
|
|
|
// ..##..##
|
|
|
|
|
|
// ..##..##
|
|
|
|
|
|
// ##..##..
|
|
|
|
|
|
// ##..##..
|
|
|
|
|
|
// ..##..##
|
|
|
|
|
|
// ..##..##
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
// ── 08: card back — TR quadrant ──────────────────
|
|
|
|
|
|
// Mirrored half-phase from TL so the horizontal join
|
|
|
|
|
|
// between TL and TR preserves the 2-pixel square grid.
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
// ── 09: card back — BL quadrant ──────────────────
|
|
|
|
|
|
// Half-phase shift in Y so the vertical join preserves
|
|
|
|
|
|
// the grid too.
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
// ── 10: card back — BR quadrant ──────────────────
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"33223322",
|
|
|
|
|
|
"22332233",
|
|
|
|
|
|
"22332233",
|
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
|
|
|
|
// ── 11: rank A (Ace) ─────────────────────────────
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
// Bold 5×7 black glyph on a fully-opaque white card body.
|
|
|
|
|
|
// Every pixel inside the tile is either 2 (white — the
|
|
|
|
|
|
// card body) or 3 (black — the glyph stroke). Nothing
|
|
|
|
|
|
// is transparent: a `.` anywhere here would let the
|
|
|
|
|
|
// felt green bleed through the card.
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"22233222",
|
|
|
|
|
|
"22233222",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"23333322",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"23222322",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 12: rank 2 ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"23333222",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"22223222",
|
|
|
|
|
|
"22232222",
|
|
|
|
|
|
"22322222",
|
|
|
|
|
|
"23333322",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 13: rank 3 ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"23333222",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"22333222",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"23333222",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 14: rank 4 ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"23222322",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"23333322",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"22222322",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 15: rank 5 ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"23333322",
|
|
|
|
|
|
"23222222",
|
|
|
|
|
|
"23333222",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"23333222",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 16: rank 6 ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"22333322",
|
|
|
|
|
|
"23222222",
|
|
|
|
|
|
"23333222",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"22333222",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 17: rank 7 ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"23333322",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"22223222",
|
|
|
|
|
|
"22232222",
|
|
|
|
|
|
"22322222",
|
|
|
|
|
|
"23222222",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 18: rank 8 ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"22333222",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"22333222",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"22333222",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 19: rank 9 ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"22333222",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"22333322",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"22333222",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 20: rank 10 (condensed "1" + "0") ─────────────
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
// "10" squeezed into an 8×8 tile: a thin "1" in cols 0-2
|
|
|
|
|
|
// and a narrow "0" in cols 4-7 with a 1-col gap.
|
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
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"22323322",
|
|
|
|
|
|
"23323322",
|
|
|
|
|
|
"22323322",
|
|
|
|
|
|
"22323322",
|
|
|
|
|
|
"22323322",
|
|
|
|
|
|
"23323322",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 21: rank J ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"22333322",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"22222322",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"22333222",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 22: rank Q ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"22333222",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"23222322",
|
|
|
|
|
|
"23223322",
|
|
|
|
|
|
"23233222",
|
|
|
|
|
|
"22332322",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 23: rank K ───────────────────────────────────
|
|
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"23222322",
|
|
|
|
|
|
"23223222",
|
|
|
|
|
|
"23322222",
|
|
|
|
|
|
"23322222",
|
|
|
|
|
|
"23223222",
|
|
|
|
|
|
"23222322",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 24: small spade ♠ ────────────────────────────
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
// 6×6 black pip centred on a fully-opaque white 8×8 tile.
|
|
|
|
|
|
// Used as the top-right corner indicator on spade cards.
|
|
|
|
|
|
// ...##...
|
|
|
|
|
|
// ..####..
|
|
|
|
|
|
// .######.
|
|
|
|
|
|
// ..####..
|
|
|
|
|
|
// ..####..
|
|
|
|
|
|
// ..#..#..
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"22233222",
|
|
|
|
|
|
"22333322",
|
|
|
|
|
|
"23333332",
|
|
|
|
|
|
"22333322",
|
|
|
|
|
|
"22233222",
|
|
|
|
|
|
"22233222",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 25: small heart ♥ ────────────────────────────
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
// Red pip on white (palette index 1 = red).
|
|
|
|
|
|
// .##..##.
|
|
|
|
|
|
// ########
|
|
|
|
|
|
// ########
|
|
|
|
|
|
// ########
|
|
|
|
|
|
// .######.
|
|
|
|
|
|
// ..####..
|
|
|
|
|
|
// ...##...
|
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
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"21122112",
|
|
|
|
|
|
"21111112",
|
|
|
|
|
|
"21111112",
|
|
|
|
|
|
"22111122",
|
|
|
|
|
|
"22211222",
|
|
|
|
|
|
"22221222",
|
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
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 26: small diamond ♦ ──────────────────────────
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
// Red pip on white (compact rhombus).
|
|
|
|
|
|
// ...##...
|
|
|
|
|
|
// ..####..
|
|
|
|
|
|
// .######.
|
|
|
|
|
|
// ########
|
|
|
|
|
|
// .######.
|
|
|
|
|
|
// ..####..
|
|
|
|
|
|
// ...##...
|
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
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"22211222",
|
|
|
|
|
|
"22111122",
|
|
|
|
|
|
"21111112",
|
|
|
|
|
|
"22111122",
|
|
|
|
|
|
"22211222",
|
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
|
|
|
|
"22221222",
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 27: small club ♣ ─────────────────────────────
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
// Black pip on white. Three rounded leaves over a short
|
|
|
|
|
|
// stem — simplified to fit an 8×8 tile.
|
|
|
|
|
|
// ...##...
|
|
|
|
|
|
// ..####..
|
|
|
|
|
|
// ...##...
|
|
|
|
|
|
// .######.
|
|
|
|
|
|
// ########
|
|
|
|
|
|
// .######.
|
|
|
|
|
|
// ...##...
|
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
|
|
|
|
"22222222",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
"22233222",
|
|
|
|
|
|
"22333322",
|
|
|
|
|
|
"22233222",
|
|
|
|
|
|
"23333332",
|
|
|
|
|
|
"23333332",
|
|
|
|
|
|
"22233222",
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 28-43: big centre pips ───────────────────────
|
|
|
|
|
|
//
|
|
|
|
|
|
// Every face-up card shows a big 16×16 pip spanning the
|
|
|
|
|
|
// bottom two rows of the card. Each suit's pip is
|
|
|
|
|
|
// authored below as four 8×8 quadrants (top-left,
|
|
|
|
|
|
// top-right, bottom-left, bottom-right) so the full
|
|
|
|
|
|
// 16×16 shape is the concatenation:
|
|
|
|
|
|
//
|
|
|
|
|
|
// [ TL ][ TR ]
|
|
|
|
|
|
// [ BL ][ BR ]
|
|
|
|
|
|
//
|
|
|
|
|
|
// The card body around the pip is solid white (palette
|
|
|
|
|
|
// 2); the pip itself is palette 1 (red — hearts and
|
|
|
|
|
|
// diamonds) or palette 3 (black — spades and clubs).
|
|
|
|
|
|
// Crucially, no tile pixel is `.` (palette 0 —
|
|
|
|
|
|
// transparent): the card must be opaque so the green
|
|
|
|
|
|
// felt does not bleed through.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Order: spade, heart, diamond, club.
|
|
|
|
|
|
// TL tiles 28-31, TR tiles 32-35, BL tiles 88-91
|
|
|
|
|
|
// (declared at the end of the Tileset), BR tiles 92-95.
|
|
|
|
|
|
|
|
|
|
|
|
// ── 28: big spade — TL quadrant ─────────────────
|
|
|
|
|
|
// Full 16×16 spade shape (TL + TR side by side,
|
|
|
|
|
|
// BL + BR underneath at tiles 88-95):
|
|
|
|
|
|
// ................
|
|
|
|
|
|
// .......##.......
|
|
|
|
|
|
// ......####......
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// ...##########...
|
|
|
|
|
|
// ..############..
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// ...##########...
|
|
|
|
|
|
// .......##.......
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// ................
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"22222223",
|
|
|
|
|
|
"22222233",
|
|
|
|
|
|
"22222333",
|
|
|
|
|
|
"22223333",
|
|
|
|
|
|
"22233333",
|
|
|
|
|
|
"22333333",
|
|
|
|
|
|
"23333333",
|
|
|
|
|
|
// ── 29: big heart — TL quadrant ──────────────────
|
|
|
|
|
|
// Full 16×16 heart shape:
|
|
|
|
|
|
// ................
|
|
|
|
|
|
// ..####....####..
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// ..############..
|
|
|
|
|
|
// ...##########...
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// .......##.......
|
|
|
|
|
|
// ................
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"22111122",
|
|
|
|
|
|
"21111111",
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
// ── 30: big diamond — TL quadrant ────────────────
|
|
|
|
|
|
// Full 16×16 diamond shape (symmetric rhombus):
|
|
|
|
|
|
// ................
|
|
|
|
|
|
// .......##.......
|
|
|
|
|
|
// ......####......
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// ...##########...
|
|
|
|
|
|
// ..############..
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// ..############..
|
|
|
|
|
|
// ...##########...
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// ......####......
|
|
|
|
|
|
// .......##.......
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"22222221",
|
|
|
|
|
|
"22222211",
|
|
|
|
|
|
"22222111",
|
|
|
|
|
|
"22221111",
|
|
|
|
|
|
"22211111",
|
|
|
|
|
|
"22111111",
|
|
|
|
|
|
"21111111",
|
|
|
|
|
|
// ── 31: big club — TL quadrant ───────────────────
|
|
|
|
|
|
// Full 16×16 club shape — three leaves in a triangle
|
|
|
|
|
|
// (one on top, two on sides) joined over a short stem
|
|
|
|
|
|
// and a wider base:
|
|
|
|
|
|
// ................
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// ..###..######...
|
|
|
|
|
|
// .#####.########.
|
|
|
|
|
|
// .###############
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// ..############..
|
|
|
|
|
|
// .......##.......
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// ................
|
|
|
|
|
|
// ................
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"22222333",
|
|
|
|
|
|
"22223333",
|
|
|
|
|
|
"22223333",
|
|
|
|
|
|
"22222333",
|
|
|
|
|
|
"22333222",
|
|
|
|
|
|
"23333322",
|
|
|
|
|
|
"23333333",
|
|
|
|
|
|
// ── 32: big spade — TR quadrant ──────────────────
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"32222222",
|
|
|
|
|
|
"33222222",
|
|
|
|
|
|
"33322222",
|
|
|
|
|
|
"33332222",
|
|
|
|
|
|
"33333222",
|
|
|
|
|
|
"33333322",
|
|
|
|
|
|
"33333332",
|
|
|
|
|
|
// ── 33: big heart — TR quadrant ──────────────────
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"22111122",
|
|
|
|
|
|
"11111112",
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
// ── 34: big diamond — TR quadrant ────────────────
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"12222222",
|
|
|
|
|
|
"11222222",
|
|
|
|
|
|
"11122222",
|
|
|
|
|
|
"11112222",
|
|
|
|
|
|
"11111222",
|
|
|
|
|
|
"11111122",
|
|
|
|
|
|
"11111112",
|
|
|
|
|
|
// ── 35: big club — TR quadrant ───────────────────
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"33322222",
|
|
|
|
|
|
"33332222",
|
|
|
|
|
|
"33332222",
|
|
|
|
|
|
"33322222",
|
|
|
|
|
|
"33333322",
|
|
|
|
|
|
"33333332",
|
|
|
|
|
|
"33333332",
|
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
|
|
|
|
// ── 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",
|
examples/war: redesign card art — opaque bodies, 16x16 pips, checkerboard back
The first-pass card tiles were riddled with palette-0 transparent
pixels that let the felt background bleed through every rank
glyph, small suit, and big pip. At arm's length the cards looked
like they had green specks eating them. This commit rewrites all
of the card art from scratch:
- **Opaque card bodies.** Every pixel inside a card tile is now
either white (palette 2), red (1), or black (3). No `.` values
anywhere on a face or back tile. The green felt only shows
outside the card rectangle, where it should.
- **Readable rank glyphs.** The 13 rank tiles (A, 2-9, 10, J, Q, K)
are now drawn as bold black strokes on a solid white body. The
"holes" of the letters (e.g. the triangle inside an "A") are
white, not transparent.
- **16x16 big pips.** The big centre pip is now a 4-tile (16x16)
shape split into TL/TR/BL/BR quadrants per suit. Previously it
was a 2-tile (16x8) half-height strip that looked cramped. The
TL/TR quadrants kept their existing tile indices (28-35) so the
shift is local; the new BL/BR quadrants are appended after the
BIG WAR letters at tiles 88-95 to avoid renumbering the entire
alphabet / digits / UI tile range.
- **Distinct suit shapes.** Spade is a smooth teardrop with a
short stem and base; heart is two symmetric lobes with a V
bottom; diamond is a clean rhombus; club is three circles
joined over a stem. Side-by-side they are unmistakable.
- **Clean checkerboard card back.** The old card back was a
diamond lattice that had the same transparent-bleed problem
and looked noisy anyway. Replaced with a crisp 2-pixel black-
and-white checkerboard that tiles seamlessly across the card
back's 16x24 footprint.
- **draw_card_face now emits 6 sprites in a rank/suit + 4-tile
big-pip layout.** The previous 6-sprite layout was
`[rank][ssuit] / [pipL][pipR] / [blankL][blankR]`; the new
one is `[rank][ssuit] / [pipTL][pipTR] / [pipBL][pipBR]` with
the bottom row carrying the bottom half of the big pip
instead of being wasted blank tiles.
Also:
- New constants TILE_PIP_TL_BASE / TR / BL / BR replace the old
TILE_PIP_L_BASE / TILE_PIP_R_BASE in constants.ne.
- Refreshed war.nes and the goldens. Every emulator harness
test still passes (31/31).
https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 18:31:15 +00:00
|
|
|
|
".2222222",
|
|
|
|
|
|
// ── 88-95: big centre pip — BL and BR quadrants ──
|
|
|
|
|
|
// Continuation of the 16×16 big-pip shapes declared at
|
|
|
|
|
|
// tiles 28-35. Placed here at the end of the Tileset so
|
|
|
|
|
|
// adding them didn't require renumbering every letter,
|
|
|
|
|
|
// digit, and UI tile in the middle of the sheet. The
|
|
|
|
|
|
// full 16×16 layout is:
|
|
|
|
|
|
//
|
|
|
|
|
|
// [TL=28..31 ][TR=32..35 ] (top half, cols 0-15)
|
|
|
|
|
|
// [BL=88..91 ][BR=92..95 ] (bottom half)
|
|
|
|
|
|
//
|
|
|
|
|
|
// Order inside each group is spade / heart / diamond /
|
|
|
|
|
|
// club — identical to TILE_PIP_*_BASE indexing so a
|
|
|
|
|
|
// single `TILE_PIP_*_BASE + suit` lookup picks the right
|
|
|
|
|
|
// tile for each suit.
|
|
|
|
|
|
|
|
|
|
|
|
// ── 88: big spade — BL quadrant ──────────────────
|
|
|
|
|
|
// Full spade bottom half: single-row peak at row 8,
|
|
|
|
|
|
// then a smooth teardrop curving down through a narrow
|
|
|
|
|
|
// stem and a short base. Matches the TL/TR triangle
|
|
|
|
|
|
// top to form a classic playing-card spade.
|
|
|
|
|
|
// ################ row 8 — widest
|
|
|
|
|
|
// .##############. row 9
|
|
|
|
|
|
// ..############.. row 10
|
|
|
|
|
|
// ...##########... row 11
|
|
|
|
|
|
// .....######..... row 12
|
|
|
|
|
|
// .......##....... row 13 — stem
|
|
|
|
|
|
// .....######..... row 14 — base
|
|
|
|
|
|
// ................ row 15
|
|
|
|
|
|
"33333333",
|
|
|
|
|
|
"23333333",
|
|
|
|
|
|
"22333333",
|
|
|
|
|
|
"22233333",
|
|
|
|
|
|
"22222333",
|
|
|
|
|
|
"22222223",
|
|
|
|
|
|
"22222333",
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 89: big heart — BL quadrant ──────────────────
|
|
|
|
|
|
// Full heart bottom half:
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// ..############..
|
|
|
|
|
|
// ...##########...
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// .......##.......
|
|
|
|
|
|
// ................
|
|
|
|
|
|
"21111111",
|
|
|
|
|
|
"21111111",
|
|
|
|
|
|
"22111111",
|
|
|
|
|
|
"22211111",
|
|
|
|
|
|
"22221111",
|
|
|
|
|
|
"22222111",
|
|
|
|
|
|
"22222221",
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 90: big diamond — BL quadrant ────────────────
|
|
|
|
|
|
// Full diamond bottom half (mirror of the top):
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// ..############..
|
|
|
|
|
|
// ...##########...
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// ......####......
|
|
|
|
|
|
// .......##.......
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
"21111111",
|
|
|
|
|
|
"22111111",
|
|
|
|
|
|
"22211111",
|
|
|
|
|
|
"22221111",
|
|
|
|
|
|
"22211111",
|
|
|
|
|
|
"22222111",
|
|
|
|
|
|
"22222221",
|
|
|
|
|
|
// ── 91: big club — BL quadrant ───────────────────
|
|
|
|
|
|
// Full club bottom half:
|
|
|
|
|
|
// ################
|
|
|
|
|
|
// .##############.
|
|
|
|
|
|
// ..############..
|
|
|
|
|
|
// .......##.......
|
|
|
|
|
|
// .....######.....
|
|
|
|
|
|
// ....########....
|
|
|
|
|
|
// ................
|
|
|
|
|
|
// ................
|
|
|
|
|
|
"33333333",
|
|
|
|
|
|
"23333333",
|
|
|
|
|
|
"22333333",
|
|
|
|
|
|
"22222223",
|
|
|
|
|
|
"22222333",
|
|
|
|
|
|
"22223333",
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 92: big spade — BR quadrant ──────────────────
|
|
|
|
|
|
"33333333",
|
|
|
|
|
|
"33333332",
|
|
|
|
|
|
"33333322",
|
|
|
|
|
|
"33333222",
|
|
|
|
|
|
"33322222",
|
|
|
|
|
|
"32222222",
|
|
|
|
|
|
"33322222",
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 93: big heart — BR quadrant ──────────────────
|
|
|
|
|
|
"11111112",
|
|
|
|
|
|
"11111112",
|
|
|
|
|
|
"11111122",
|
|
|
|
|
|
"11111222",
|
|
|
|
|
|
"11112222",
|
|
|
|
|
|
"11122222",
|
|
|
|
|
|
"12222222",
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
// ── 94: big diamond — BR quadrant ────────────────
|
|
|
|
|
|
"11111111",
|
|
|
|
|
|
"11111112",
|
|
|
|
|
|
"11111122",
|
|
|
|
|
|
"11111222",
|
|
|
|
|
|
"11112222",
|
|
|
|
|
|
"11111222",
|
|
|
|
|
|
"11112222",
|
|
|
|
|
|
"12222222",
|
|
|
|
|
|
// ── 95: big club — BR quadrant ───────────────────
|
|
|
|
|
|
"33333333",
|
|
|
|
|
|
"33333332",
|
|
|
|
|
|
"33333322",
|
|
|
|
|
|
"32222222",
|
|
|
|
|
|
"33322222",
|
|
|
|
|
|
"33332222",
|
|
|
|
|
|
"22222222",
|
|
|
|
|
|
"22222222"
|
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
|
|
|
|
]
|
|
|
|
|
|
}
|