diff --git a/examples/war.nes b/examples/war.nes index 954fc65..daeda7e 100644 Binary files a/examples/war.nes and b/examples/war.nes differ diff --git a/examples/war/assets.ne b/examples/war/assets.ne index b0c2cb0..dfb54ea 100644 --- a/examples/war/assets.ne +++ b/examples/war/assets.ne @@ -84,284 +84,431 @@ sprite Tileset { "22222223", "22222223", "22222223", - // ── 07: card back top-left ─────────────────────── - // The back is a black-and-white diamond lattice, - // painted as a 2×2 repeating block. Every card back - // uses all four corners tiled into a 16×16 / 16×24 - // block. - "..333333", - ".3333333", - ".3322333", - "333.2.33", - "33.222.3", - "33.2.233", - "3322.333", - "3333.333", - // ── 08: card back top-right ────────────────────── - "333333..", - "3333333.", - "33322.33", - "33.2.333", - "3.222.33", - "33.2.333", - "333.2233", - "3333.333", - // ── 09: card back bottom-left ──────────────────── - "3333.333", - "3322.333", - "33.2.233", - "33.222.3", - "333.2.33", - ".3322333", - ".3333333", - "..333333", - // ── 10: card back bottom-right ─────────────────── - "3333.333", - "333.2233", - "33.2.333", - "3.222.33", - "33.2.333", - "33322.33", - "3333333.", - "333333..", + // ── 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", // ── 11: rank A (Ace) ───────────────────────────── - // Bold black glyph on a white card body. The rank is - // drawn 6×6 px and centred horizontally in the 8×8 tile. - // The card body fills index 2 (white) so the glyph reads - // as black-on-white when the card frame's outline tiles - // wrap it. + // 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", - "22.33.22", - "2.3333.2", - "2.3..3.2", - "2.3333.2", - "2.3..3.2", - "2.3..3.2", + "22233222", + "22233222", + "23222322", + "23333322", + "23222322", + "23222322", "22222222", // ── 12: rank 2 ─────────────────────────────────── "22222222", - "2.3333.2", - "2....3.2", - "22.33.22", - "2.3...22", - "2.3...22", - "2.3333.2", + "23333222", + "22222322", + "22223222", + "22232222", + "22322222", + "23333322", "22222222", // ── 13: rank 3 ─────────────────────────────────── "22222222", - "2.3333.2", - "22...3.2", - "22.33.22", - "22...3.2", - "2....3.2", - "2.3333.2", + "23333222", + "22222322", + "22333222", + "22222322", + "22222322", + "23333222", "22222222", // ── 14: rank 4 ─────────────────────────────────── "22222222", - "2.3..3.2", - "2.3..3.2", - "2.3..3.2", - "2.3333.2", - "22...3.2", - "22...3.2", + "23222322", + "23222322", + "23222322", + "23333322", + "22222322", + "22222322", "22222222", // ── 15: rank 5 ─────────────────────────────────── "22222222", - "2.3333.2", - "2.3...22", - "2.3333.2", - "22...3.2", - "22...3.2", - "2.3333.2", + "23333322", + "23222222", + "23333222", + "22222322", + "22222322", + "23333222", "22222222", // ── 16: rank 6 ─────────────────────────────────── "22222222", - "2.3333.2", - "2.3...22", - "2.3333.2", - "2.3..3.2", - "2.3..3.2", - "2.3333.2", + "22333322", + "23222222", + "23333222", + "23222322", + "23222322", + "22333222", "22222222", // ── 17: rank 7 ─────────────────────────────────── "22222222", - "2.3333.2", - "22...3.2", - "22..3.22", - "22.3..22", - "22.3..22", - "22.3..22", + "23333322", + "22222322", + "22223222", + "22232222", + "22322222", + "23222222", "22222222", // ── 18: rank 8 ─────────────────────────────────── "22222222", - "2.3333.2", - "2.3..3.2", - "2.3333.2", - "2.3..3.2", - "2.3..3.2", - "2.3333.2", + "22333222", + "23222322", + "22333222", + "23222322", + "23222322", + "22333222", "22222222", // ── 19: rank 9 ─────────────────────────────────── "22222222", - "2.3333.2", - "2.3..3.2", - "2.3..3.2", - "2.3333.2", - "22...3.2", - "2.3333.2", + "22333222", + "23222322", + "23222322", + "22333322", + "22222322", + "22333222", "22222222", // ── 20: rank 10 (condensed "1" + "0") ───────────── - // "10" squeezed into an 8x8 tile. The "1" takes columns - // 0-1, a gap, the "0" takes columns 4-7. + // "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. "22222222", - "2.3.33.2", - "233.3..3", - "2.3.3..3", - "2.3.3..3", - "2.3.3..3", - "2.3.33.2", + "22323322", + "23323322", + "22323322", + "22323322", + "22323322", + "23323322", "22222222", // ── 21: rank J ─────────────────────────────────── "22222222", - "222.33.2", - "222..3.2", - "222..3.2", - "222..3.2", - "22.3.3.2", - "22.333.2", + "22333322", + "22222322", + "22222322", + "22222322", + "23222322", + "22333222", "22222222", // ── 22: rank Q ─────────────────────────────────── "22222222", - "2.3333.2", - "2.3..3.2", - "2.3..3.2", - "2.3.33.2", - "2.3333.2", - "22.33.32", + "22333222", + "23222322", + "23222322", + "23223322", + "23233222", + "22332322", "22222222", // ── 23: rank K ─────────────────────────────────── "22222222", - "2.3..3.2", - "2.3.3.22", - "2.33..22", - "2.3.3.22", - "2.3..3.2", - "2.3..3.2", + "23222322", + "23223222", + "23322222", + "23322222", + "23223222", + "23222322", "22222222", // ── 24: small spade ♠ ──────────────────────────── - // 6x6 centred pip on a white 8x8 tile. + // 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", "22222222", - "2222.222", - "222.3.22", - "22.333.2", - "2.33333.", - "2.33333.", - "222.3.22", - "222333.2", // ── 25: small heart ♥ ──────────────────────────── - // Red pip on white. + // Red pip on white (palette index 1 = red). + // .##..##. + // ######## + // ######## + // ######## + // .######. + // ..####.. + // ...##... "22222222", - "22.11.22", - "2.1111.2", - "2.1111.2", - "2.1111.2", - "22.11.22", - "222.1.22", + "21122112", + "21111112", + "21111112", + "22111122", + "22211222", + "22221222", "22222222", // ── 26: small diamond ♦ ────────────────────────── + // Red pip on white (compact rhombus). + // ...##... + // ..####.. + // .######. + // ######## + // .######. + // ..####.. + // ...##... "22222222", - "22221222", - "2221.122", - "221...12", - "221...12", - "2221.122", + "22211222", + "22111122", + "21111112", + "22111122", + "22211222", "22221222", "22222222", // ── 27: small club ♣ ───────────────────────────── + // Black pip on white. Three rounded leaves over a short + // stem — simplified to fit an 8×8 tile. + // ...##... + // ..####.. + // ...##... + // .######. + // ######## + // .######. + // ...##... "22222222", - "2222.222", - "2223332.", - "2223332.", - "22.333.2", - "2.33333.", - "22.3.3.2", - "222333.2", - // ── 28: big spade — left half ──────────────────── - // The big centre-pip is drawn 16×8: two tiles side by - // side. Each suit's (left half, right half) pair is - // authored explicitly so the centre art can be bolder - // and more symmetric than the corner pips. - "2222222.", - "222222.3", - "22222.33", - "2222.333", - "222.3333", - "22.33333", - "2.333333", - ".3333333", - // ── 29: big heart — left half ──────────────────── - "2222.111", - "222.1111", - "22.11111", - "22.11111", - "22.11111", - "222.1111", - "2222.111", - "22222.11", - // ── 30: big diamond — left half ────────────────── + "22233222", + "22333322", + "22233222", + "23333332", + "23333332", + "22233222", "22222222", - "22222.12", - "2222.112", - "222.1112", - "22.11112", - "2.111112", - "22.11112", - "222.1112", - // ── 31: big club — left half ───────────────────── - "2222.333", - "2222.333", - "222.3333", - "22.33333", - "2.333333", - "2.333333", - "22.333.3", - "2223.333", - // ── 32: big spade — right half ─────────────────── - ".3333333", - "2.333333", - "22.33333", - "222.3333", - "2222.333", - "22222.33", - "222222.3", - "2222222.", - // ── 33: big heart — right half ─────────────────── - "111.2222", - "1111.222", - "11111.22", - "11111.22", - "11111.22", - "1111.222", - "111.2222", - "11.22222", - // ── 34: big diamond — right half ───────────────── + // ── 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", - "21.22222", - "211.2222", - "2111.222", - "21111.22", - "211111.2", - "21111.22", - "2111.222", - // ── 35: big club — right half ──────────────────── - "333.2222", - "333.2222", - "3333.222", - "33333.22", - "333333.2", - "333333.2", - "3.333.22", - "333.3222", + "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", // ── 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 @@ -851,6 +998,132 @@ sprite Tileset { "222222..", "2222222.", "22222222", - ".2222222" + ".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" ] } diff --git a/examples/war/constants.ne b/examples/war/constants.ne index 722d096..1a3411e 100644 --- a/examples/war/constants.ne +++ b/examples/war/constants.ne @@ -59,9 +59,16 @@ const TILE_RANK_BASE: u8 = 11 // 13 tiles: A, 2..10, J, Q, K // Small suit glyphs for the card corner, one per suit. const TILE_SUIT_SMALL_BASE: u8 = 24 // 4 tiles: ♠ ♥ ♦ ♣ -// Big centre-pip, authored as a 16×8 pair per suit (left half + right half). -const TILE_PIP_L_BASE: u8 = 28 // 4 tiles -const TILE_PIP_R_BASE: u8 = 32 // 4 tiles +// Big centre-pip, authored as a 16×16 shape split into four 8×8 +// quadrants per suit. Each `_BASE + suit` picks the tile for that +// suit's quadrant. The TL/TR quadrants are contiguous at 28-35; +// the BL/BR quadrants live at 88-95 because they were added +// after the alphabet / digit / BIG WAR tiles and putting them in +// the middle would have shifted every later tile's index. +const TILE_PIP_TL_BASE: u8 = 28 // spade/heart/diamond/club TL +const TILE_PIP_TR_BASE: u8 = 32 // spade/heart/diamond/club TR +const TILE_PIP_BL_BASE: u8 = 88 // spade/heart/diamond/club BL +const TILE_PIP_BR_BASE: u8 = 92 // spade/heart/diamond/club BR // Alphanumerics (8×8) used for all on-screen text that lives on the // sprite layer. Letters A-Z then digits 0-9, contiguous. diff --git a/examples/war/render.ne b/examples/war/render.ne index aeb44fb..26c3633 100644 --- a/examples/war/render.ne +++ b/examples/war/render.ne @@ -13,16 +13,19 @@ // ── Card face ────────────────────────────────────────────── // -// Draws the 6-sprite card face at (x, y) for the packed card -// byte. Layout (each cell is 8×8): +// Draws the 6-sprite face of a 16×24 card at (x, y) for the +// packed `rank<<4 | suit` byte. Layout (each cell is 8×8): // -// [rank ][small_suit] row 0 -// [pipL ][pipR ] row 1 -// [blankL][blankR ] row 2 +// [ rank ][ssuit] row 0: rank letter + small suit pip +// [pipTL ][pipTR] row 1: top half of the big 16×16 pip +// [pipBL ][pipBR] row 2: bottom half of the big pip // -// Rank is the condensed glyph at TILE_RANK_BASE + (rank - 1); -// small suit + big-pip halves are indexed directly off their -// base constants. +// Every tile in the card has a fully-opaque white background +// (palette index 2) so the felt green behind the card does not +// bleed through — see `assets.ne` for the art itself. The big +// centre pip is a single 16×16 shape split across the bottom +// two rows (4 tiles total); `rank` sits in the top-left corner +// and `small_suit` in the top-right. fun draw_card_face(dcf_in_x: u8, dcf_in_y: u8, dcf_in_card: u8) { // Snapshot every parameter into a fresh local *before* any // nested function call. NEScript v0.1 passes parameters via @@ -38,20 +41,22 @@ fun draw_card_face(dcf_in_x: u8, dcf_in_y: u8, dcf_in_card: u8) { var dcf_suit: u8 = card_suit(dcf_card) var dcf_rank_tile: u8 = TILE_RANK_BASE + dcf_rank - 1 var dcf_small_tile: u8 = TILE_SUIT_SMALL_BASE + dcf_suit - var dcf_pipl_tile: u8 = TILE_PIP_L_BASE + dcf_suit - var dcf_pipr_tile: u8 = TILE_PIP_R_BASE + dcf_suit + var dcf_pip_tl: u8 = TILE_PIP_TL_BASE + dcf_suit + var dcf_pip_tr: u8 = TILE_PIP_TR_BASE + dcf_suit + var dcf_pip_bl: u8 = TILE_PIP_BL_BASE + dcf_suit + var dcf_pip_br: u8 = TILE_PIP_BR_BASE + dcf_suit var dcf_x1: u8 = dcf_x + 8 var dcf_y1: u8 = dcf_y + 8 var dcf_y2: u8 = dcf_y + 16 // Row 0 — rank corner + small suit draw Tileset at: (dcf_x, dcf_y) frame: dcf_rank_tile draw Tileset at: (dcf_x1, dcf_y) frame: dcf_small_tile - // Row 1 — big centre pip (left + right halves) - draw Tileset at: (dcf_x, dcf_y1) frame: dcf_pipl_tile - draw Tileset at: (dcf_x1, dcf_y1) frame: dcf_pipr_tile - // Row 2 — blank bottom so the card body is symmetric - draw Tileset at: (dcf_x, dcf_y2) frame: TILE_FRAME_BLANK_L - draw Tileset at: (dcf_x1, dcf_y2) frame: TILE_FRAME_BLANK_R + // Row 1 — top half of the 16×16 big pip + draw Tileset at: (dcf_x, dcf_y1) frame: dcf_pip_tl + draw Tileset at: (dcf_x1, dcf_y1) frame: dcf_pip_tr + // Row 2 — bottom half of the 16×16 big pip + draw Tileset at: (dcf_x, dcf_y2) frame: dcf_pip_bl + draw Tileset at: (dcf_x1, dcf_y2) frame: dcf_pip_br } // Draw the card-back lattice at (x, y). 6 sprites again. Rows diff --git a/tests/emulator/goldens/war.audio.hash b/tests/emulator/goldens/war.audio.hash index 040c3bc..e8f8ea6 100644 --- a/tests/emulator/goldens/war.audio.hash +++ b/tests/emulator/goldens/war.audio.hash @@ -1 +1 @@ -4747e070 132084 +21f4a315 132084 diff --git a/tests/emulator/goldens/war.png b/tests/emulator/goldens/war.png index 0784e9d..398430e 100644 Binary files a/tests/emulator/goldens/war.png and b/tests/emulator/goldens/war.png differ