romdevtools 0.15.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +61 -13
- package/CHANGELOG.md +289 -0
- package/README.md +1 -1
- package/examples/README.md +2 -0
- package/examples/atari2600/templates/platformer.asm +460 -0
- package/examples/atari2600/templates/racing.asm +463 -0
- package/examples/atari2600/templates/shmup.asm +386 -0
- package/examples/atari2600/templates/sports.asm +362 -0
- package/examples/atari7800/templates/default.c +49 -5
- package/examples/atari7800/templates/platformer.c +43 -4
- package/examples/atari7800/templates/puzzle.c +39 -4
- package/examples/atari7800/templates/racing.c +39 -4
- package/examples/atari7800/templates/shmup.c +40 -2
- package/examples/atari7800/templates/sports.c +36 -5
- package/examples/c64/templates/platformer.c +19 -5
- package/examples/c64/templates/puzzle.c +32 -2
- package/examples/c64/templates/shmup.c +28 -2
- package/examples/c64/templates/sports.c +30 -2
- package/examples/gb/templates/default.c +110 -16
- package/examples/gb/templates/platformer.c +25 -4
- package/examples/gb/templates/puzzle.c +32 -2
- package/examples/gb/templates/racing.c +72 -8
- package/examples/gb/templates/shmup.c +38 -1
- package/examples/gb/templates/sports.c +48 -1
- package/examples/gba/templates/gba_hello.c +29 -11
- package/examples/gba/templates/puzzle.c +15 -3
- package/examples/gba/templates/racing.c +65 -3
- package/examples/gba/templates/shmup.c +41 -4
- package/examples/gba/templates/sports.c +36 -2
- package/examples/gba/templates/tonc_hello.c +41 -5
- package/examples/gbc/templates/default.c +103 -26
- package/examples/gbc/templates/platformer.c +25 -4
- package/examples/gbc/templates/puzzle.c +32 -2
- package/examples/gbc/templates/racing.c +85 -19
- package/examples/gbc/templates/shmup.c +34 -1
- package/examples/gbc/templates/sports.c +45 -1
- package/examples/genesis/templates/puzzle.c +37 -3
- package/examples/genesis/templates/racing.c +44 -11
- package/examples/genesis/templates/sgdk_hello.c +34 -1
- package/examples/genesis/templates/shmup.c +31 -1
- package/examples/gg/templates/default.c +56 -18
- package/examples/gg/templates/platformer.c +18 -12
- package/examples/gg/templates/puzzle.c +38 -7
- package/examples/gg/templates/racing.c +51 -5
- package/examples/gg/templates/shmup.c +47 -3
- package/examples/gg/templates/sports.c +46 -3
- package/examples/lynx/templates/default.c +39 -8
- package/examples/lynx/templates/puzzle.c +28 -1
- package/examples/lynx/templates/racing.c +34 -7
- package/examples/lynx/templates/shmup.c +42 -3
- package/examples/lynx/templates/sports.c +29 -2
- package/examples/msx/platformer/main.c +213 -0
- package/examples/msx/puzzle/main.c +250 -0
- package/examples/msx/racing/main.c +249 -0
- package/examples/msx/shmup/main.c +288 -0
- package/examples/msx/sports/main.c +182 -0
- package/examples/nes/templates/default.c +67 -19
- package/examples/nes/templates/platformer.c +65 -6
- package/examples/nes/templates/puzzle.c +67 -6
- package/examples/nes/templates/racing.c +45 -13
- package/examples/nes/templates/shmup.c +51 -2
- package/examples/nes/templates/sports.c +51 -6
- package/examples/pce/platformer/main.c +283 -0
- package/examples/pce/puzzle/main.c +304 -0
- package/examples/pce/racing/main.c +304 -0
- package/examples/pce/shmup/main.c +346 -0
- package/examples/pce/sports/main.c +254 -0
- package/examples/sms/main.c +35 -6
- package/examples/sms/templates/puzzle.c +34 -5
- package/examples/sms/templates/racing.c +39 -2
- package/examples/sms/templates/shmup.c +41 -2
- package/examples/sms/templates/sports.c +43 -2
- package/examples/snes/templates/default.c +50 -28
- package/examples/snes/templates/platformer-data.asm +22 -0
- package/examples/snes/templates/platformer.c +16 -1
- package/examples/snes/templates/puzzle-data.asm +22 -0
- package/examples/snes/templates/puzzle.c +17 -1
- package/examples/snes/templates/racing-data.asm +22 -0
- package/examples/snes/templates/racing.c +17 -1
- package/examples/snes/templates/shmup-data.asm +22 -0
- package/examples/snes/templates/shmup.c +20 -1
- package/examples/snes/templates/sports-data.asm +22 -0
- package/examples/snes/templates/sports.c +16 -1
- package/package.json +1 -1
- package/src/cores/wasm/vice_x64_libretro.js +1 -1
- package/src/cores/wasm/vice_x64_libretro.wasm +0 -0
- package/src/host/LibretroHost.js +122 -1
- package/src/host/callbacks.js +9 -1
- package/src/host/types.js +15 -8
- package/src/http/skill-doc.js +1 -1
- package/src/http/tool-registry.js +27 -2
- package/src/mcp/tools/cart-parts.js +75 -3
- package/src/mcp/tools/disasm-rebuild.js +507 -0
- package/src/mcp/tools/disasm.js +95 -6
- package/src/mcp/tools/frame.js +168 -3
- package/src/mcp/tools/index.js +4 -4
- package/src/mcp/tools/lifecycle.js +4 -2
- package/src/mcp/tools/project.js +54 -9
- package/src/mcp/tools/state.js +201 -14
- package/src/mcp/tools/toolchain.js +89 -4
- package/src/mcp/tools/watch-memory.js +125 -14
- package/src/platforms/c64/MENTAL_MODEL.md +45 -1
- package/src/platforms/c64/d64.js +281 -0
- package/src/platforms/gb/MENTAL_MODEL.md +10 -0
- package/src/platforms/msx/MENTAL_MODEL.md +10 -6
- package/src/platforms/nes/MENTAL_MODEL.md +63 -2
- package/src/platforms/pce/MENTAL_MODEL.md +9 -4
- package/src/platforms/pce/lib/c/pce_video.c +1 -1
- package/src/rom-id/identifier.js +15 -0
- package/src/toolchains/cc65/cc65.js +8 -1
- package/src/toolchains/cc65/ines.js +145 -0
- package/src/toolchains/cc65/presets/nes/chr-rom.cfg +83 -0
- package/src/toolchains/cc65/presets/nes/chr-rom.crt0.s +153 -0
- package/src/toolchains/common/reassemble.js +10 -2
- package/src/toolchains/gba-c/gba-c.js +6 -1
- package/src/toolchains/genesis-c/genesis-c.js +10 -2
- package/src/toolchains/parse-errors.js +67 -5
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
/* ── default.c — minimal Game Boy Color (CGB) starter ─────────────
|
|
2
2
|
*
|
|
3
|
-
*
|
|
4
|
-
* +
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* A "hello, it works! IN COLOR" screen: a tiled background (two bands
|
|
4
|
+
* + a centre box) drawn with a real CGB palette, plus a sprite that
|
|
5
|
+
* bounces around. The very first GBC build shows recognizable content
|
|
6
|
+
* — not a flat colour. Use this as the starting point when you're not
|
|
7
|
+
* yet sure what you want to build; edit from here.
|
|
7
8
|
*
|
|
8
9
|
* GBC-specific notes:
|
|
9
10
|
* - CGB uses BCPS/BCPD ($FF68/$FF69) to write into 64 bytes of
|
|
10
|
-
* palette RAM (8 BG palettes × 4
|
|
11
|
-
* little-endian)
|
|
11
|
+
* palette RAM (8 BG palettes × 4 colours × 2 bytes each, BGR555
|
|
12
|
+
* little-endian) and OCPS/OCPD for the sprite palettes. The DMG-only
|
|
13
|
+
* BGP/OBP0/OBP1 ($FF47-$49) registers do nothing in CGB mode.
|
|
14
|
+
* - You MUST put tiles in VRAM and enable the BG (LCDC bit 0) or the
|
|
15
|
+
* screen stays one flat colour — the #1 GB "why is it blank" footgun.
|
|
16
|
+
* We upload tiles to $8000 and select LCDC_TILE_DATA_LO (unsigned
|
|
17
|
+
* $8000 addressing) so tile index N lives at $8000 + N*16.
|
|
12
18
|
* - patchGbHeader on a .gbc file sets $0143 = $80 (CGB-aware) by
|
|
13
|
-
* default. The corresponding `.gb` default uses BGP — don't
|
|
19
|
+
* default. The corresponding `.gb` default uses DMG BGP — don't
|
|
14
20
|
* cross-pollinate the two trees.
|
|
15
|
-
* - This template is intentionally DIFFERENT from examples/gb/
|
|
16
|
-
* templates/default.c — that one demonstrates DMG palettes.
|
|
17
21
|
*
|
|
18
22
|
* For something more game-shaped, peek at other templates in this dir:
|
|
19
23
|
* - hello_sprite — sprite + d-pad movement
|
|
@@ -25,37 +29,110 @@
|
|
|
25
29
|
#include "gb_hardware.h"
|
|
26
30
|
#include "gb_runtime.h"
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
/* Three 8×8 tiles, 2bpp (16 bytes each: row N = byte 2N low-bits, 2N+1
|
|
33
|
+
* high-bits). Colour index per tile pixel selects into the 4-colour
|
|
34
|
+
* palette below.
|
|
35
|
+
* tile 0 — blank (all colour 0 — reserved so OAM Y=0 doesn't glitch)
|
|
36
|
+
* tile 1 — solid (all colour 1 — the background fill / bands)
|
|
37
|
+
* tile 2 — sprite (a filled diamond in colour 3) */
|
|
38
|
+
static const uint8_t tiles[3 * 16] = {
|
|
39
|
+
/* tile 0: blank */
|
|
40
|
+
0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
41
|
+
/* tile 1: solid colour 1 (low plane all-on, high plane all-off) */
|
|
42
|
+
0xFF,0x00, 0xFF,0x00, 0xFF,0x00, 0xFF,0x00,
|
|
43
|
+
0xFF,0x00, 0xFF,0x00, 0xFF,0x00, 0xFF,0x00,
|
|
44
|
+
/* tile 2: diamond in colour 3 (both planes set on the diamond pixels) */
|
|
45
|
+
0x18,0x18, 0x3C,0x3C, 0x7E,0x7E, 0xFF,0xFF,
|
|
46
|
+
0xFF,0xFF, 0x7E,0x7E, 0x3C,0x3C, 0x18,0x18,
|
|
33
47
|
};
|
|
34
48
|
|
|
49
|
+
/* BG palette 0 (BGR555). Colour 0 = backdrop, colour 1 = the bands/box.
|
|
50
|
+
* We cycle colour 1 through these four shades each ~32 frames so you can
|
|
51
|
+
* SEE the CGB palette path is alive. */
|
|
52
|
+
static const uint16_t bg_fill_cycle[4] = {
|
|
53
|
+
0x03FF, /* yellow-ish */
|
|
54
|
+
0x7C00, /* blue */
|
|
55
|
+
0x03E0, /* green */
|
|
56
|
+
0x001F, /* red */
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/* Sprite palette (OBJ palette 0): 0 transparent, 3 = white diamond. */
|
|
60
|
+
static const uint16_t obj_pal[4] = {
|
|
61
|
+
0x0000, /* 0 transparent (sprite colour 0 never drawn) */
|
|
62
|
+
0x7FFF, /* 1 white */
|
|
63
|
+
0x03E0, /* 2 green */
|
|
64
|
+
0x7FFF, /* 3 white */
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
static void set_bg_color1(uint16_t bgr555) {
|
|
68
|
+
/* Write BG palette 0: colour 0 = dark backdrop, colour 1 = bgr555. */
|
|
69
|
+
BCPS = 0x80; /* palette 0, colour 0, auto-inc */
|
|
70
|
+
BCPD = 0x08; BCPD = 0x21; /* colour 0 = dark grey (0x2108) */
|
|
71
|
+
BCPD = (uint8_t)(bgr555 & 0xFF); /* colour 1 lo */
|
|
72
|
+
BCPD = (uint8_t)((bgr555 >> 8) & 0xFF); /* colour 1 hi */
|
|
73
|
+
}
|
|
74
|
+
|
|
35
75
|
void main(void) {
|
|
36
|
-
uint8_t
|
|
76
|
+
uint8_t x, y;
|
|
77
|
+
uint8_t sx = 76, sy = 64; /* sprite screen position */
|
|
78
|
+
int8_t dx = 1, dy = 1; /* sprite velocity */
|
|
37
79
|
uint8_t shade = 0;
|
|
38
80
|
uint16_t frame = 0;
|
|
81
|
+
uint8_t *bg_map = BG_MAP_0; /* $9800 */
|
|
82
|
+
uint8_t i;
|
|
39
83
|
|
|
84
|
+
/* 1. LCD off (safely — lcd_init_default checks LCDC.7 first). */
|
|
40
85
|
lcd_init_default();
|
|
86
|
+
LCDC = 0;
|
|
41
87
|
|
|
42
|
-
/*
|
|
43
|
-
|
|
88
|
+
/* 2. Tiles → VRAM at $8000 (unsigned addressing, see LCDC_TILE_DATA_LO). */
|
|
89
|
+
memcpy_vram((void *)0x8000, tiles, sizeof(tiles));
|
|
90
|
+
|
|
91
|
+
/* 3. Palettes. */
|
|
92
|
+
set_bg_color1(bg_fill_cycle[0]);
|
|
93
|
+
OCPS = 0x80;
|
|
44
94
|
for (i = 0; i < 4; i++) {
|
|
45
|
-
|
|
46
|
-
|
|
95
|
+
OCPD = (uint8_t)(obj_pal[i] & 0xFF);
|
|
96
|
+
OCPD = (uint8_t)((obj_pal[i] >> 8) & 0xFF);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* 4. Paint the BG map (32×32; we fill the visible 20×18). Background
|
|
100
|
+
* is tile 0 (blank → backdrop colour); two solid bands + a centre
|
|
101
|
+
* box are tile 1 so the screen reads as real content. */
|
|
102
|
+
for (y = 0; y < 32; y++)
|
|
103
|
+
for (x = 0; x < 32; x++)
|
|
104
|
+
bg_map[y * 32 + x] = 0;
|
|
105
|
+
for (x = 0; x < 20; x++) {
|
|
106
|
+
bg_map[2 * 32 + x] = 1; /* top band (row 2) */
|
|
107
|
+
bg_map[15 * 32 + x] = 1; /* bottom band (row 15) */
|
|
47
108
|
}
|
|
109
|
+
for (y = 6; y < 12; y++)
|
|
110
|
+
for (x = 6; x < 14; x++)
|
|
111
|
+
bg_map[y * 32 + x] = 1; /* centre box */
|
|
112
|
+
|
|
113
|
+
/* 5. Initial sprite. */
|
|
114
|
+
oam_clear();
|
|
115
|
+
oam_set(0, (uint8_t)(sy + 16), (uint8_t)(sx + 8), 2, 0);
|
|
116
|
+
|
|
117
|
+
/* 6. LCD on with BG + OBJ + $8000 tile addressing. */
|
|
118
|
+
LCDC = LCDC_LCD_ON | LCDC_BG_ON | LCDC_OBJ_ON | LCDC_TILE_DATA_LO;
|
|
48
119
|
|
|
49
120
|
for (;;) {
|
|
50
121
|
wait_vblank();
|
|
122
|
+
oam_dma_flush();
|
|
123
|
+
|
|
51
124
|
frame++;
|
|
52
|
-
if ((frame & 0x1F) == 0) {
|
|
53
|
-
shade = (shade + 1) & 0x03;
|
|
54
|
-
|
|
55
|
-
for (i = 0; i < 4; i++) {
|
|
56
|
-
BCPD = (uint8_t)(palettes[shade] & 0xFF);
|
|
57
|
-
BCPD = (uint8_t)((palettes[shade] >> 8) & 0xFF);
|
|
58
|
-
}
|
|
125
|
+
if ((frame & 0x1F) == 0) { /* every 32 frames: cycle BG colour */
|
|
126
|
+
shade = (uint8_t)((shade + 1) & 0x03);
|
|
127
|
+
set_bg_color1(bg_fill_cycle[shade]);
|
|
59
128
|
}
|
|
129
|
+
|
|
130
|
+
/* Bounce the sprite around the 160×144 visible area. */
|
|
131
|
+
sx = (uint8_t)(sx + dx);
|
|
132
|
+
sy = (uint8_t)(sy + dy);
|
|
133
|
+
if (sx < 1 || sx > 152) dx = (int8_t)-dx;
|
|
134
|
+
if (sy < 1 || sy > 136) dy = (int8_t)-dy;
|
|
135
|
+
oam_clear();
|
|
136
|
+
oam_set(0, (uint8_t)(sy + 16), (uint8_t)(sx + 8), 2, 0);
|
|
60
137
|
}
|
|
61
138
|
}
|
|
@@ -28,9 +28,26 @@ static const uint8_t tile_platform[16] = {
|
|
|
28
28
|
0xFF,0xFF, 0x80,0x80, 0x80,0x80, 0x80,0x80,
|
|
29
29
|
0x80,0x80, 0x80,0x80, 0x80,0x80, 0xFF,0xFF,
|
|
30
30
|
};
|
|
31
|
+
/* ── Backdrop tiles ───────────────────────────────────────────────────
|
|
32
|
+
* Fill the whole world so the screen is never one flat colour (the #1 GB
|
|
33
|
+
* "why is it blank" footgun). tile_sky is a sparse dot pattern over the
|
|
34
|
+
* sky; tile_ground is a textured dirt fill under the floor line. */
|
|
35
|
+
static const uint8_t tile_sky[16] = {
|
|
36
|
+
0x00,0x00, 0x00,0x00, 0x00,0x00, 0x20,0x20,
|
|
37
|
+
0x00,0x00, 0x00,0x00, 0x02,0x02, 0x00,0x00,
|
|
38
|
+
};
|
|
39
|
+
static const uint8_t tile_ground[16] = {
|
|
40
|
+
0xFF,0x00, 0xDB,0x24, 0xFF,0x00, 0x6D,0x92,
|
|
41
|
+
0xFF,0x00, 0xDB,0x24, 0xFF,0x00, 0x6D,0x92,
|
|
42
|
+
};
|
|
43
|
+
#define T_BLANK 0
|
|
44
|
+
#define T_PLATFORM 2
|
|
45
|
+
#define T_SKY 3
|
|
46
|
+
#define T_GROUND 4
|
|
31
47
|
|
|
32
48
|
static const uint16_t obj_palette[4] = { 0x7FFF, 0x001F, 0x03E0, 0x7C00 };
|
|
33
|
-
|
|
49
|
+
/* BG palette: 0 sky-blue, 1 mid, 2 dirt-dark, 3 near-black detail. */
|
|
50
|
+
static const uint16_t bg_palette[4] = { 0x7E10, 0x5294, 0x114A, 0x0000 };
|
|
34
51
|
|
|
35
52
|
typedef struct { int16_t x, y, w, h; } Rect;
|
|
36
53
|
|
|
@@ -74,8 +91,10 @@ static void paint_platforms(void) {
|
|
|
74
91
|
const Rect *p;
|
|
75
92
|
/* k MUST be uint16_t: 32*18 = 576 > 255, so a uint8_t counter would
|
|
76
93
|
* never reach the bound and this loop would spin forever (the BG map
|
|
77
|
-
* never clears, main() never starts). Classic SDCC limited-range trap.
|
|
78
|
-
|
|
94
|
+
* never clears, main() never starts). Classic SDCC limited-range trap.
|
|
95
|
+
* Fill sky above the floor line (row 16 = y 128) and textured ground
|
|
96
|
+
* at and below it, so the whole world is a real scene, not blank. */
|
|
97
|
+
for (k = 0; k < 32 * 18; k++) map[k] = (k >= 16 * 32) ? T_GROUND : T_SKY;
|
|
79
98
|
for (i = 0; i < N_PLATFORMS; i++) {
|
|
80
99
|
p = &platforms[i];
|
|
81
100
|
cx = p->x >> 3;
|
|
@@ -84,7 +103,7 @@ static void paint_platforms(void) {
|
|
|
84
103
|
ch = (p->h + 7) >> 3;
|
|
85
104
|
for (j = 0; j < cw; j++) {
|
|
86
105
|
if (cx + j < 32 && cy < 32)
|
|
87
|
-
map[cy * 32 + cx + j] =
|
|
106
|
+
map[cy * 32 + cx + j] = T_PLATFORM; /* platform top edge */
|
|
88
107
|
}
|
|
89
108
|
}
|
|
90
109
|
}
|
|
@@ -111,6 +130,8 @@ void main(void) {
|
|
|
111
130
|
upload_tile(0, tile_blank);
|
|
112
131
|
upload_tile(1, tile_player);
|
|
113
132
|
upload_tile(2, tile_platform);
|
|
133
|
+
upload_tile(T_SKY, tile_sky);
|
|
134
|
+
upload_tile(T_GROUND, tile_ground);
|
|
114
135
|
|
|
115
136
|
OCPS = 0x80;
|
|
116
137
|
for (i = 0; i < 4; i++) {
|
|
@@ -21,8 +21,22 @@
|
|
|
21
21
|
#define T_R 1
|
|
22
22
|
#define T_G 2
|
|
23
23
|
#define T_B 3
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
#define T_WALL 4
|
|
25
|
+
|
|
26
|
+
/* tile_blank is the EMPTY-cell / backdrop tile. It is NOT all-zero: a
|
|
27
|
+
* subtle dither (colour 0 + faint colour 1) so the empty playfield and the
|
|
28
|
+
* area around the well read as a textured surface, never one flat colour
|
|
29
|
+
* (the #1 GB "why is it blank" footgun). Locked blocks / the active piece
|
|
30
|
+
* overdraw it with the R/G/B shape tiles. */
|
|
31
|
+
static const uint8_t tile_blank[16] = {
|
|
32
|
+
0x00,0x00, 0x22,0x00, 0x00,0x00, 0x88,0x00,
|
|
33
|
+
0x00,0x00, 0x22,0x00, 0x00,0x00, 0x88,0x00,
|
|
34
|
+
};
|
|
35
|
+
/* Well frame: a solid colour-2 border drawn around the play area. */
|
|
36
|
+
static const uint8_t tile_wall[16] = {
|
|
37
|
+
0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF,
|
|
38
|
+
0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF,
|
|
39
|
+
};
|
|
26
40
|
/* Three distinct tile shapes (since GB BG is 2bpp, we differentiate
|
|
27
41
|
* by *shape*, not colour-on-CGB). The CGB palette path could give us
|
|
28
42
|
* real colours; for DMG-compatibility we use shape. */
|
|
@@ -131,6 +145,20 @@ static void upload_tile(uint8_t slot, const uint8_t *src) {
|
|
|
131
145
|
for (i = 0; i < 16; i++) dst[i] = src[i];
|
|
132
146
|
}
|
|
133
147
|
|
|
148
|
+
/* Draw the well frame around the 6×12 play area. Grid cells live at
|
|
149
|
+
* map[(row+1)*32 + (col+7)] (rows 1..12, cols 7..12), so the frame is the
|
|
150
|
+
* column to each side (6 and 13) and the floor row just below (row 13). */
|
|
151
|
+
static void draw_well(void) {
|
|
152
|
+
uint8_t *map = (uint8_t *)0x9800;
|
|
153
|
+
uint8_t r;
|
|
154
|
+
for (r = 1; r <= 12; r++) {
|
|
155
|
+
map[r * 32 + 6] = T_WALL; /* left wall */
|
|
156
|
+
map[r * 32 + 13] = T_WALL; /* right wall */
|
|
157
|
+
}
|
|
158
|
+
for (r = 6; r <= 13; r++)
|
|
159
|
+
map[13 * 32 + r] = T_WALL; /* floor */
|
|
160
|
+
}
|
|
161
|
+
|
|
134
162
|
void main(void) {
|
|
135
163
|
uint8_t pad, prev = 0, fall_rate, t;
|
|
136
164
|
int16_t r, c;
|
|
@@ -145,6 +173,7 @@ void main(void) {
|
|
|
145
173
|
upload_tile(T_R, tile_r);
|
|
146
174
|
upload_tile(T_G, tile_g);
|
|
147
175
|
upload_tile(T_B, tile_b);
|
|
176
|
+
upload_tile(T_WALL, tile_wall);
|
|
148
177
|
|
|
149
178
|
BCPS = 0x80;
|
|
150
179
|
for (i = 0; i < 4; i++) {
|
|
@@ -165,6 +194,7 @@ void main(void) {
|
|
|
165
194
|
score = 0;
|
|
166
195
|
fall_timer = 0;
|
|
167
196
|
new_piece();
|
|
197
|
+
draw_well();
|
|
168
198
|
draw_grid();
|
|
169
199
|
|
|
170
200
|
LCDC = LCDC_LCD_ON | LCDC_BG_ON | LCDC_TILE_DATA_LO;
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
/* ── racing.c — Game Boy top-down racing scaffold
|
|
1
|
+
/* ── racing.c — Game Boy Color top-down racing scaffold ────────────
|
|
2
2
|
*
|
|
3
|
-
* Endless 3-lane top-down dodge for the Game Boy. LEFT/RIGHT
|
|
4
|
-
* lanes (edge-detected), obstacles slide down at speed =
|
|
5
|
-
* (capped). Collision triggers a 60-frame freeze +
|
|
3
|
+
* Endless 3-lane top-down dodge for the Game Boy Color. LEFT/RIGHT
|
|
4
|
+
* switches lanes (edge-detected), obstacles slide down at speed =
|
|
5
|
+
* 2 + score/500 (capped). Collision triggers a 60-frame freeze +
|
|
6
|
+
* auto-reset.
|
|
6
7
|
*
|
|
7
|
-
* Game Boy screen is 160×144 — 3 lanes centred around x = {
|
|
8
|
+
* Game Boy screen is 160×144 — 3 lanes centred around x = {40, 76, 112}.
|
|
9
|
+
*
|
|
10
|
+
* The road is a real CGB-coloured background: green grass shoulders down
|
|
11
|
+
* each side, grey asphalt across the playfield, dashed white lane lines
|
|
12
|
+
* between the lanes (BG palette via BCPS/BCPD; LCDC bit 0 = BG ON — drop
|
|
13
|
+
* it and the screen is a flat colour, the #1 GB "why is it blank"
|
|
14
|
+
* footgun). Cars are colour sprites (OCPS/OCPD) on top.
|
|
8
15
|
*/
|
|
9
16
|
|
|
10
17
|
#include "gb_hardware.h"
|
|
@@ -16,7 +23,7 @@
|
|
|
16
23
|
#define PLAYER_Y 120
|
|
17
24
|
#define MAX_OBSTACLES 4
|
|
18
25
|
|
|
19
|
-
|
|
26
|
+
/* ── Sprite tiles (cars) ──────────────────────────────────────────── */
|
|
20
27
|
static const uint8_t tile_car_p1[16] = {
|
|
21
28
|
0x3C,0x00, 0x7E,0x00, 0x42,0x00, 0x7E,0x00,
|
|
22
29
|
0x7E,0x00, 0x42,0x00, 0x7E,0x00, 0x66,0x00,
|
|
@@ -26,8 +33,43 @@ static const uint8_t tile_car_en[16] = {
|
|
|
26
33
|
0x00,0x7E, 0x00,0x42, 0x00,0x7E, 0x00,0x66,
|
|
27
34
|
};
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
/* ── BG tiles (road) ──────────────────────────────────────────────── */
|
|
37
|
+
/* 2bpp: row N = byte 2N (low plane) + byte 2N+1 (high plane).
|
|
38
|
+
* asphalt — all colour 2 (grey)
|
|
39
|
+
* grass — all colour 1 (green)
|
|
40
|
+
* laneA/B — dashed colour-3 (white) lane line, two phases for dashes */
|
|
41
|
+
static const uint8_t tile_asphalt[16] = {
|
|
42
|
+
0x00,0xFF, 0x00,0xFF, 0x00,0xFF, 0x00,0xFF,
|
|
43
|
+
0x00,0xFF, 0x00,0xFF, 0x00,0xFF, 0x00,0xFF,
|
|
44
|
+
};
|
|
45
|
+
static const uint8_t tile_grass[16] = {
|
|
46
|
+
0xFF,0x00, 0xFF,0x00, 0xFF,0x00, 0xFF,0x00,
|
|
47
|
+
0xFF,0x00, 0xFF,0x00, 0xFF,0x00, 0xFF,0x00,
|
|
48
|
+
};
|
|
49
|
+
/* lane line = a 2px-wide colour-3 stripe down the centre of the cell;
|
|
50
|
+
* phase A draws the top half, phase B the bottom half → dashes. */
|
|
51
|
+
static const uint8_t tile_laneA[16] = {
|
|
52
|
+
0x18,0x18, 0x18,0x18, 0x18,0x18, 0x18,0x18,
|
|
53
|
+
0x00,0xFF, 0x00,0xFF, 0x00,0xFF, 0x00,0xFF,
|
|
54
|
+
};
|
|
55
|
+
static const uint8_t tile_laneB[16] = {
|
|
56
|
+
0x00,0xFF, 0x00,0xFF, 0x00,0xFF, 0x00,0xFF,
|
|
57
|
+
0x18,0x18, 0x18,0x18, 0x18,0x18, 0x18,0x18,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/* CGB palettes (BGR555).
|
|
61
|
+
* BG palette 0: 0 unused, 1 green grass, 2 grey asphalt, 3 white line. */
|
|
62
|
+
static const uint16_t bg_palette[4] = { 0x0000, 0x0320, 0x4210, 0x7FFF };
|
|
63
|
+
/* OBJ palette 0: 0 transparent, 1 white (player), 2 red (enemy), 3 green. */
|
|
64
|
+
static const uint16_t obj_palette[4] = { 0x0000, 0x7FFF, 0x001F, 0x03E0 };
|
|
65
|
+
|
|
66
|
+
/* Tile indices in VRAM. Sprites and BG share the $8000 table here. */
|
|
67
|
+
#define T_CAR_P1 1
|
|
68
|
+
#define T_CAR_EN 2
|
|
69
|
+
#define T_ASPHALT 3
|
|
70
|
+
#define T_GRASS 4
|
|
71
|
+
#define T_LANE_A 5
|
|
72
|
+
#define T_LANE_B 6
|
|
31
73
|
|
|
32
74
|
typedef struct { int16_t x, y; uint8_t alive; } Car;
|
|
33
75
|
|
|
@@ -76,6 +118,24 @@ static void upload_tile(uint8_t slot, const uint8_t *src) {
|
|
|
76
118
|
for (i = 0; i < 16; i++) dst[i] = src[i];
|
|
77
119
|
}
|
|
78
120
|
|
|
121
|
+
/* Paint the road into BG map 0 ($9800). 20×18 visible cells:
|
|
122
|
+
* col 0 = grass shoulder (left)
|
|
123
|
+
* col 19 = grass shoulder (right)
|
|
124
|
+
* cols 1..18 = asphalt, with dashed lane lines at the two lane
|
|
125
|
+
* boundaries (cols 6 and 12). Dashes alternate per row. */
|
|
126
|
+
static void draw_road(void) {
|
|
127
|
+
uint8_t *bg = BG_MAP_0;
|
|
128
|
+
uint8_t r, c, t;
|
|
129
|
+
for (r = 0; r < 18; r++) {
|
|
130
|
+
for (c = 0; c < 20; c++) {
|
|
131
|
+
if (c == 0 || c == 19) t = T_GRASS;
|
|
132
|
+
else if (c == 6 || c == 12) t = (r & 1) ? T_LANE_A : T_LANE_B;
|
|
133
|
+
else t = T_ASPHALT;
|
|
134
|
+
bg[r * 32 + c] = t;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
79
139
|
void main(void) {
|
|
80
140
|
uint8_t pad;
|
|
81
141
|
uint8_t i;
|
|
@@ -84,23 +144,29 @@ void main(void) {
|
|
|
84
144
|
lcd_init_default();
|
|
85
145
|
LCDC = 0;
|
|
86
146
|
|
|
87
|
-
upload_tile(
|
|
88
|
-
upload_tile(
|
|
89
|
-
upload_tile(
|
|
147
|
+
upload_tile(T_CAR_P1, tile_car_p1);
|
|
148
|
+
upload_tile(T_CAR_EN, tile_car_en);
|
|
149
|
+
upload_tile(T_ASPHALT, tile_asphalt);
|
|
150
|
+
upload_tile(T_GRASS, tile_grass);
|
|
151
|
+
upload_tile(T_LANE_A, tile_laneA);
|
|
152
|
+
upload_tile(T_LANE_B, tile_laneB);
|
|
90
153
|
|
|
91
|
-
|
|
92
|
-
for (i = 0; i < 4; i++) {
|
|
93
|
-
OCPD = (uint8_t)(obj_palette[i] & 0xFF);
|
|
94
|
-
OCPD = (uint8_t)((obj_palette[i] >> 8) & 0xFF);
|
|
95
|
-
}
|
|
154
|
+
/* CGB palettes. */
|
|
96
155
|
BCPS = 0x80;
|
|
97
156
|
for (i = 0; i < 4; i++) {
|
|
98
157
|
BCPD = (uint8_t)(bg_palette[i] & 0xFF);
|
|
99
158
|
BCPD = (uint8_t)((bg_palette[i] >> 8) & 0xFF);
|
|
100
159
|
}
|
|
160
|
+
OCPS = 0x80;
|
|
161
|
+
for (i = 0; i < 4; i++) {
|
|
162
|
+
OCPD = (uint8_t)(obj_palette[i] & 0xFF);
|
|
163
|
+
OCPD = (uint8_t)((obj_palette[i] >> 8) & 0xFF);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
draw_road();
|
|
101
167
|
|
|
102
168
|
oam_clear();
|
|
103
|
-
LCDC = LCDC_LCD_ON | LCDC_OBJ_ON | LCDC_TILE_DATA_LO;
|
|
169
|
+
LCDC = LCDC_LCD_ON | LCDC_BG_ON | LCDC_OBJ_ON | LCDC_TILE_DATA_LO;
|
|
104
170
|
sound_init();
|
|
105
171
|
|
|
106
172
|
reset_run();
|
|
@@ -111,13 +177,13 @@ void main(void) {
|
|
|
111
177
|
|
|
112
178
|
/* Stage OAM — player + obstacles. */
|
|
113
179
|
for (i = 0; i < 40; i++) oam_set(i, 0, 0, 0, 0);
|
|
114
|
-
oam_set(0, (uint8_t)(player.y + 16), (uint8_t)(player.x + 8),
|
|
180
|
+
oam_set(0, (uint8_t)(player.y + 16), (uint8_t)(player.x + 8), T_CAR_P1, 0);
|
|
115
181
|
for (i = 0; i < MAX_OBSTACLES; i++) {
|
|
116
182
|
if (obstacles[i].alive) {
|
|
117
183
|
oam_set((uint8_t)(1 + i),
|
|
118
184
|
(uint8_t)(obstacles[i].y + 16),
|
|
119
185
|
(uint8_t)(obstacles[i].x + 8),
|
|
120
|
-
|
|
186
|
+
T_CAR_EN, 0);
|
|
121
187
|
}
|
|
122
188
|
}
|
|
123
189
|
oam_dma_flush();
|
|
@@ -25,6 +25,24 @@ static const uint8_t tile_ship[16] = {
|
|
|
25
25
|
0x18,0x18, 0x3C,0x3C, 0x7E,0x7E, 0xFF,0xFF,
|
|
26
26
|
0xFF,0xFF, 0x7E,0x7E, 0x3C,0x3C, 0x18,0x18,
|
|
27
27
|
};
|
|
28
|
+
/* ── BG tiles (starfield) ─────────────────────────────────────────────
|
|
29
|
+
* The background is a real starfield so the screen is never one flat
|
|
30
|
+
* colour (LCDC_BG_ON below — drop it and the screen reads as blank, the
|
|
31
|
+
* #1 GB "why is it blank" footgun).
|
|
32
|
+
* tile_space — a 50/50 dither of palette colours 0 (deep space blue) +
|
|
33
|
+
* 1 (mid blue), so even an empty patch of space mixes two
|
|
34
|
+
* shades and never lets one colour dominate the frame.
|
|
35
|
+
* tile_star — a bright colour-3 (white) "+" star on the dithered field. */
|
|
36
|
+
static const uint8_t tile_space[16] = {
|
|
37
|
+
0x55,0x00, 0xAA,0x00, 0x55,0x00, 0xAA,0x00,
|
|
38
|
+
0x55,0x00, 0xAA,0x00, 0x55,0x00, 0xAA,0x00,
|
|
39
|
+
};
|
|
40
|
+
static const uint8_t tile_star[16] = {
|
|
41
|
+
0x10,0x10, 0x10,0x10, 0x54,0x54, 0x38,0x38,
|
|
42
|
+
0x54,0x54, 0x10,0x10, 0x10,0x10, 0x00,0x00,
|
|
43
|
+
};
|
|
44
|
+
#define T_SPACE 4
|
|
45
|
+
#define T_STAR 5
|
|
28
46
|
static const uint8_t tile_bullet[16] = {
|
|
29
47
|
0x00,0x00, 0x18,0x18, 0x3C,0x3C, 0x3C,0x3C,
|
|
30
48
|
0x3C,0x3C, 0x3C,0x3C, 0x18,0x18, 0x00,0x00,
|
|
@@ -94,6 +112,17 @@ static void upload_tile(uint8_t slot, const uint8_t *src) {
|
|
|
94
112
|
for (i = 0; i < 16; i++) dst[i] = src[i];
|
|
95
113
|
}
|
|
96
114
|
|
|
115
|
+
/* Paint a starfield into BG map 0 ($9800): fill the visible 20×18 with the
|
|
116
|
+
* dithered space tile, then scatter bright stars on a fixed pseudo-pattern
|
|
117
|
+
* so the field reads as deep space rather than a flat colour. */
|
|
118
|
+
static void draw_starfield(void) {
|
|
119
|
+
uint8_t *bg = BG_MAP_0;
|
|
120
|
+
uint8_t r, c;
|
|
121
|
+
for (r = 0; r < 18; r++)
|
|
122
|
+
for (c = 0; c < 20; c++)
|
|
123
|
+
bg[r * 32 + c] = ((r * 7 + c * 5) % 11 == 0) ? T_STAR : T_SPACE;
|
|
124
|
+
}
|
|
125
|
+
|
|
97
126
|
void main(void) {
|
|
98
127
|
uint8_t pad, prev = 0;
|
|
99
128
|
uint8_t i, j;
|
|
@@ -105,6 +134,8 @@ void main(void) {
|
|
|
105
134
|
upload_tile(1, tile_ship);
|
|
106
135
|
upload_tile(2, tile_bullet);
|
|
107
136
|
upload_tile(3, tile_enemy);
|
|
137
|
+
upload_tile(T_SPACE, tile_space);
|
|
138
|
+
upload_tile(T_STAR, tile_star);
|
|
108
139
|
|
|
109
140
|
/* Sprite palette 0 — uploaded to OCPS/OCPD (CGB-only registers). */
|
|
110
141
|
OCPS = 0x80;
|
|
@@ -120,6 +151,8 @@ void main(void) {
|
|
|
120
151
|
BCPD = (uint8_t)((bg_palette[i] >> 8) & 0xFF);
|
|
121
152
|
}
|
|
122
153
|
|
|
154
|
+
draw_starfield();
|
|
155
|
+
|
|
123
156
|
player.x = 76; player.y = 130; player.alive = 1;
|
|
124
157
|
for (i = 0; i < MAX_BULLETS; i++) bullets[i].alive = 0;
|
|
125
158
|
for (i = 0; i < MAX_ENEMIES; i++) enemies[i].alive = 0;
|
|
@@ -127,7 +160,7 @@ void main(void) {
|
|
|
127
160
|
spawn_timer = 0;
|
|
128
161
|
|
|
129
162
|
oam_clear();
|
|
130
|
-
LCDC = LCDC_LCD_ON | LCDC_OBJ_ON | LCDC_TILE_DATA_LO;
|
|
163
|
+
LCDC = LCDC_LCD_ON | LCDC_BG_ON | LCDC_OBJ_ON | LCDC_TILE_DATA_LO;
|
|
131
164
|
sound_init();
|
|
132
165
|
|
|
133
166
|
while (1) {
|
|
@@ -28,6 +28,31 @@ static const uint8_t tile_solid[16] = {
|
|
|
28
28
|
0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF,
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
+
/* ── BG tiles (the court) ──────────────────────────────────────────────
|
|
32
|
+
* A real playfield behind the paddles so the screen is never one flat
|
|
33
|
+
* colour (LCDC_BG_ON below — drop it and it reads as blank, the #1 GB
|
|
34
|
+
* "why is it blank" footgun).
|
|
35
|
+
* tile_court — a 50/50 dither of palette colours 0 + 1 (the green turf),
|
|
36
|
+
* so even an empty patch mixes two shades and never
|
|
37
|
+
* dominates the frame.
|
|
38
|
+
* tile_net — a dashed vertical centre-net stripe (colour 2).
|
|
39
|
+
* tile_wall — a solid colour-2 border for the top / bottom rails. */
|
|
40
|
+
static const uint8_t tile_court[16] = {
|
|
41
|
+
0x55,0x55, 0xAA,0xAA, 0x55,0x55, 0xAA,0xAA,
|
|
42
|
+
0x55,0x55, 0xAA,0xAA, 0x55,0x55, 0xAA,0xAA,
|
|
43
|
+
};
|
|
44
|
+
static const uint8_t tile_net[16] = {
|
|
45
|
+
0x18,0x18, 0x18,0x18, 0x00,0x00, 0x00,0x00,
|
|
46
|
+
0x18,0x18, 0x18,0x18, 0x00,0x00, 0x00,0x00,
|
|
47
|
+
};
|
|
48
|
+
static const uint8_t tile_wall[16] = {
|
|
49
|
+
0x00,0x00, 0xFF,0xFF, 0xFF,0xFF, 0x00,0x00,
|
|
50
|
+
0x00,0x00, 0xFF,0xFF, 0xFF,0xFF, 0x00,0x00,
|
|
51
|
+
};
|
|
52
|
+
#define T_COURT 2
|
|
53
|
+
#define T_NET 3
|
|
54
|
+
#define T_WALL 4
|
|
55
|
+
|
|
31
56
|
static const uint16_t obj_palette[4] = { 0x7FFF, 0x001F, 0x03E0, 0x7C00 };
|
|
32
57
|
static const uint16_t bg_palette[4] = { 0x2104, 0x294A, 0x4631, 0x7FFF }; /* deep court green */
|
|
33
58
|
|
|
@@ -58,6 +83,21 @@ static void upload_tile(uint8_t slot, const uint8_t *src) {
|
|
|
58
83
|
for (i = 0; i < 16; i++) dst[i] = src[i];
|
|
59
84
|
}
|
|
60
85
|
|
|
86
|
+
/* Paint the Pong court into BG map 0 ($9800): dithered turf everywhere,
|
|
87
|
+
* solid top/bottom rails, and a dashed net down the centre column. */
|
|
88
|
+
static void draw_court(void) {
|
|
89
|
+
uint8_t *bg = BG_MAP_0;
|
|
90
|
+
uint8_t r, c, t;
|
|
91
|
+
for (r = 0; r < 18; r++) {
|
|
92
|
+
for (c = 0; c < 20; c++) {
|
|
93
|
+
if (r == 0 || r == 17) t = T_WALL; /* top / bottom rail */
|
|
94
|
+
else if (c == 9 || c == 10) t = (r & 1) ? T_NET : T_COURT; /* net dashes */
|
|
95
|
+
else t = T_COURT;
|
|
96
|
+
bg[r * 32 + c] = t;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
61
101
|
void main(void) {
|
|
62
102
|
uint8_t pad;
|
|
63
103
|
uint8_t i;
|
|
@@ -68,6 +108,9 @@ void main(void) {
|
|
|
68
108
|
|
|
69
109
|
upload_tile(0, tile_blank);
|
|
70
110
|
upload_tile(1, tile_solid);
|
|
111
|
+
upload_tile(T_COURT, tile_court);
|
|
112
|
+
upload_tile(T_NET, tile_net);
|
|
113
|
+
upload_tile(T_WALL, tile_wall);
|
|
71
114
|
|
|
72
115
|
OCPS = 0x80;
|
|
73
116
|
for (i = 0; i < 4; i++) {
|
|
@@ -80,8 +123,9 @@ void main(void) {
|
|
|
80
123
|
BCPD = (uint8_t)((bg_palette[i] >> 8) & 0xFF);
|
|
81
124
|
}
|
|
82
125
|
|
|
126
|
+
draw_court();
|
|
83
127
|
oam_clear();
|
|
84
|
-
LCDC = LCDC_LCD_ON | LCDC_OBJ_ON | LCDC_TILE_DATA_LO;
|
|
128
|
+
LCDC = LCDC_LCD_ON | LCDC_BG_ON | LCDC_OBJ_ON | LCDC_TILE_DATA_LO;
|
|
85
129
|
sound_init();
|
|
86
130
|
|
|
87
131
|
reset_match();
|
|
@@ -29,8 +29,23 @@
|
|
|
29
29
|
#define T_RED (TILE_USER_INDEX + 1)
|
|
30
30
|
#define T_GREEN (TILE_USER_INDEX + 2)
|
|
31
31
|
#define T_BLUE (TILE_USER_INDEX + 3)
|
|
32
|
+
#define T_BG (TILE_USER_INDEX + 4) /* full-screen backdrop (BG_A) */
|
|
33
|
+
#define T_WELL (TILE_USER_INDEX + 5) /* play-well backdrop (BG_A) */
|
|
32
34
|
|
|
33
35
|
static const u32 tile_blank[8] = { 0,0,0,0,0,0,0,0 };
|
|
36
|
+
/* Backdrop block for the far plane: a framed cell (colour 4 border /
|
|
37
|
+
* colour 5 fill) tiled across the whole screen so the playfield no
|
|
38
|
+
* longer floats on a flat black backdrop. */
|
|
39
|
+
static const u32 tile_bg[8] = {
|
|
40
|
+
0x44444444, 0x45555554, 0x45555554, 0x45555554,
|
|
41
|
+
0x45555554, 0x45555554, 0x45555554, 0x44444444,
|
|
42
|
+
};
|
|
43
|
+
/* A darker, recessed cell drawn behind the play column so the well reads
|
|
44
|
+
* as an inset board rather than part of the surrounding wall. */
|
|
45
|
+
static const u32 tile_well[8] = {
|
|
46
|
+
0x44444444, 0x40000004, 0x40000004, 0x40000004,
|
|
47
|
+
0x40000004, 0x40000004, 0x40000004, 0x44444444,
|
|
48
|
+
};
|
|
34
49
|
static const u32 tile_red[8] = {
|
|
35
50
|
0x11111111, 0x11111111, 0x11111111, 0x11111111,
|
|
36
51
|
0x11111111, 0x11111111, 0x11111111, 0x11111111,
|
|
@@ -91,8 +106,11 @@ static void draw_cell(s16 col, s16 row) {
|
|
|
91
106
|
/* Each grid cell is CELL_PX/8 = 2 tiles square. */
|
|
92
107
|
for (u16 dy = 0; dy < 2; dy++) {
|
|
93
108
|
for (u16 dx = 0; dx < 2; dx++) {
|
|
109
|
+
/* Cells use the EMPTY-or-coloured tile. Empty cells stay
|
|
110
|
+
* transparent so the BG_A well backdrop shows through; filled
|
|
111
|
+
* cells are HIGH priority so they sit above that backdrop. */
|
|
94
112
|
VDP_setTileMapXY(BG_B,
|
|
95
|
-
TILE_ATTR_FULL(pal_for(v), 0, 0, 0, tile_for(v)),
|
|
113
|
+
TILE_ATTR_FULL(pal_for(v), v ? 1 : 0, 0, 0, tile_for(v)),
|
|
96
114
|
col * 2 + dx + 6,
|
|
97
115
|
row * 2 + dy + 1);
|
|
98
116
|
}
|
|
@@ -116,7 +134,7 @@ static void draw_piece(s16 col, s16 row, bool clear) {
|
|
|
116
134
|
for (u16 dy = 0; dy < 2; dy++)
|
|
117
135
|
for (u16 dx = 0; dx < 2; dx++)
|
|
118
136
|
VDP_setTileMapXY(BG_B,
|
|
119
|
-
TILE_ATTR_FULL(pal_for(v), 0, 0, 0, tile_for(v)),
|
|
137
|
+
TILE_ATTR_FULL(pal_for(v), v ? 1 : 0, 0, 0, tile_for(v)),
|
|
120
138
|
col * 2 + dx + 6,
|
|
121
139
|
r * 2 + dy + 1);
|
|
122
140
|
}
|
|
@@ -166,15 +184,31 @@ static void render_score(void) {
|
|
|
166
184
|
int main(bool hard) {
|
|
167
185
|
(void)hard;
|
|
168
186
|
|
|
169
|
-
/* Palette 1: tile colours for red/green/blue cells. */
|
|
187
|
+
/* Palette 1: tile colours for red/green/blue cells + the backdrop. */
|
|
170
188
|
PAL_setColor(16 + 1, 0x000E); /* red */
|
|
171
189
|
PAL_setColor(16 + 2, 0x00E0); /* green */
|
|
172
190
|
PAL_setColor(16 + 3, 0x0E00); /* blue */
|
|
191
|
+
PAL_setColor(16 + 4, 0x0420); /* backdrop wall border */
|
|
192
|
+
PAL_setColor(16 + 5, 0x0610); /* backdrop wall fill */
|
|
173
193
|
|
|
174
194
|
VDP_loadTileData(tile_blank, T_BLANK, 1, DMA);
|
|
175
195
|
VDP_loadTileData(tile_red, T_RED, 1, DMA);
|
|
176
196
|
VDP_loadTileData(tile_green, T_GREEN, 1, DMA);
|
|
177
197
|
VDP_loadTileData(tile_blue, T_BLUE, 1, DMA);
|
|
198
|
+
VDP_loadTileData(tile_bg, T_BG, 1, DMA);
|
|
199
|
+
VDP_loadTileData(tile_well, T_WELL, 1, DMA);
|
|
200
|
+
|
|
201
|
+
/* Far plane (BG_A): tile the whole 40x28 screen with the wall block,
|
|
202
|
+
* then recess the 12x24-cell play column so the grid sits in an inset
|
|
203
|
+
* well. The grid (BG_B) draws over this with HIGH priority. */
|
|
204
|
+
for (u16 cy = 0; cy < 28; cy++)
|
|
205
|
+
for (u16 cx = 0; cx < 40; cx++)
|
|
206
|
+
VDP_setTileMapXY(BG_A,
|
|
207
|
+
TILE_ATTR_FULL(PAL1, 0, 0, 0, T_BG), cx, cy);
|
|
208
|
+
for (u16 cy = 1; cy <= 24; cy++)
|
|
209
|
+
for (u16 cx = 6; cx <= 17; cx++)
|
|
210
|
+
VDP_setTileMapXY(BG_A,
|
|
211
|
+
TILE_ATTR_FULL(PAL1, 0, 0, 0, T_WELL), cx, cy);
|
|
178
212
|
|
|
179
213
|
for (s16 r = 0; r < ROWS; r++)
|
|
180
214
|
for (s16 c = 0; c < COLS; c++)
|