romdevtools 0.16.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 +60 -12
- package/CHANGELOG.md +258 -0
- 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/tool-registry.js +26 -1
- 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/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 +76 -3
- 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/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
|
@@ -25,16 +25,19 @@ extern uint8_t sms_joypad_read(void);
|
|
|
25
25
|
#define T_R 1
|
|
26
26
|
#define T_G 2
|
|
27
27
|
#define T_B 3
|
|
28
|
+
#define T_WALL 4 /* well border */
|
|
29
|
+
#define T_FIELD 5 /* empty well interior */
|
|
28
30
|
|
|
29
31
|
static const uint8_t palette[32] = {
|
|
30
|
-
/* BG palette: backdrop
|
|
31
|
-
|
|
32
|
+
/* BG palette: 0 backdrop navy, 1 red, 2 green, 3 blue, 4 wall grey,
|
|
33
|
+
* 5 dim field blue */
|
|
34
|
+
0x10,0x03,0x0C,0x30, 0x15,0x14, 0x00,0x00,
|
|
32
35
|
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
|
33
36
|
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
|
34
37
|
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
|
35
38
|
};
|
|
36
39
|
|
|
37
|
-
static const uint8_t bg_tiles[32 *
|
|
40
|
+
static const uint8_t bg_tiles[32 * 6] = {
|
|
38
41
|
/* T_BLANK */
|
|
39
42
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
40
43
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
@@ -53,6 +56,16 @@ static const uint8_t bg_tiles[32 * 4] = {
|
|
|
53
56
|
0xFF,0xFF,0x00,0x00, 0xFF,0xFF,0x00,0x00,
|
|
54
57
|
0xFF,0xFF,0x00,0x00, 0xFF,0xFF,0x00,0x00,
|
|
55
58
|
0xFF,0xFF,0x00,0x00, 0xFF,0xFF,0x00,0x00,
|
|
59
|
+
/* T_WALL — colour 4 fill (plane 2 set) */
|
|
60
|
+
0x00,0x00,0xFF,0x00, 0x00,0x00,0xFF,0x00,
|
|
61
|
+
0x00,0x00,0xFF,0x00, 0x00,0x00,0xFF,0x00,
|
|
62
|
+
0x00,0x00,0xFF,0x00, 0x00,0x00,0xFF,0x00,
|
|
63
|
+
0x00,0x00,0xFF,0x00, 0x00,0x00,0xFF,0x00,
|
|
64
|
+
/* T_FIELD — colour 5 fill (planes 0+2 set) = dim field */
|
|
65
|
+
0xFF,0x00,0xFF,0x00, 0xFF,0x00,0xFF,0x00,
|
|
66
|
+
0xFF,0x00,0xFF,0x00, 0xFF,0x00,0xFF,0x00,
|
|
67
|
+
0xFF,0x00,0xFF,0x00, 0xFF,0x00,0xFF,0x00,
|
|
68
|
+
0xFF,0x00,0xFF,0x00, 0xFF,0x00,0xFF,0x00,
|
|
56
69
|
};
|
|
57
70
|
|
|
58
71
|
static uint8_t grid[ROWS][COLS];
|
|
@@ -76,7 +89,7 @@ static uint8_t tile_for(uint8_t c) {
|
|
|
76
89
|
if (c == 1) return T_R;
|
|
77
90
|
if (c == 2) return T_G;
|
|
78
91
|
if (c == 3) return T_B;
|
|
79
|
-
return
|
|
92
|
+
return T_FIELD; /* empty cell shows the dim well interior, not backdrop */
|
|
80
93
|
}
|
|
81
94
|
|
|
82
95
|
static void draw_cell(int8_t col, int8_t row, uint8_t cell) {
|
|
@@ -85,6 +98,21 @@ static void draw_cell(int8_t col, int8_t row, uint8_t cell) {
|
|
|
85
98
|
sms_set_tilemap_cell((uint8_t)(row + 1), (uint8_t)(col + 7), tile_for(cell), 0);
|
|
86
99
|
}
|
|
87
100
|
|
|
101
|
+
/* Draw the well: a grey border frame around the 6x12 play field with a dim
|
|
102
|
+
* field interior, so the playfield is clearly visible even when empty.
|
|
103
|
+
* The grid maps cell (col,row) -> tilemap (row+1, col+7), i.e. rows 1..12
|
|
104
|
+
* cols 7..12. Frame the perimeter at rows 0..13, cols 6..13. */
|
|
105
|
+
static void draw_well(void) {
|
|
106
|
+
uint8_t r, c;
|
|
107
|
+
for (r = 0; r <= 13; r++) {
|
|
108
|
+
for (c = 6; c <= 13; c++) {
|
|
109
|
+
uint8_t t = T_FIELD;
|
|
110
|
+
if (r == 0 || r == 13 || c == 6 || c == 13) t = T_WALL;
|
|
111
|
+
sms_set_tilemap_cell(r, c, t, 0);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
88
116
|
static void draw_grid(void) {
|
|
89
117
|
int8_t r, c;
|
|
90
118
|
for (r = 0; r < ROWS; r++) for (c = 0; c < COLS; c++) draw_cell(c, r, grid[r][c]);
|
|
@@ -151,7 +179,7 @@ void main(void) {
|
|
|
151
179
|
|
|
152
180
|
sms_vdp_init();
|
|
153
181
|
sms_load_palette(palette);
|
|
154
|
-
sms_load_tiles(0x0000, bg_tiles, 32 *
|
|
182
|
+
sms_load_tiles(0x0000, bg_tiles, 32 * 6);
|
|
155
183
|
|
|
156
184
|
for (r = 0; r < 24; r++) for (c = 0; c < 32; c++) sms_set_tilemap_cell(r, c, T_BLANK, 0);
|
|
157
185
|
for (r = 0; r < ROWS; r++) for (c = 0; c < COLS; c++) grid[r][c] = 0;
|
|
@@ -159,6 +187,7 @@ void main(void) {
|
|
|
159
187
|
score = 0;
|
|
160
188
|
fall_timer = 0;
|
|
161
189
|
new_piece();
|
|
190
|
+
draw_well();
|
|
162
191
|
draw_grid();
|
|
163
192
|
|
|
164
193
|
sfx_init();
|
|
@@ -18,6 +18,7 @@ extern void sms_vdp_init(void);
|
|
|
18
18
|
extern void sms_vdp_display_on(void);
|
|
19
19
|
extern void sms_load_palette(const uint8_t *palette);
|
|
20
20
|
extern void sms_load_tiles(uint16_t vram_dest, const uint8_t *src, uint16_t byte_count);
|
|
21
|
+
extern void sms_set_tilemap_cell(uint8_t row, uint8_t col, uint8_t tile_idx, uint8_t attr);
|
|
21
22
|
extern void sms_vblank_wait(void);
|
|
22
23
|
extern uint8_t sms_joypad_read(void);
|
|
23
24
|
extern void sms_sprite_init(void);
|
|
@@ -31,13 +32,47 @@ extern void sms_sat_upload(void);
|
|
|
31
32
|
#define MAX_OBSTACLES 4
|
|
32
33
|
|
|
33
34
|
static const uint8_t palette[32] = {
|
|
34
|
-
|
|
35
|
+
/* BG: 0 = dark navy backdrop, 1 = grass green, 2 = road grey */
|
|
36
|
+
0x10, 0x08, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
35
37
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
36
38
|
/* Sprite palette: white (1), red (2) */
|
|
37
39
|
0x00, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
38
40
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
39
41
|
};
|
|
40
42
|
|
|
43
|
+
/* Three BG tiles for the track, loaded into the BG tile bank at $0000:
|
|
44
|
+
* tile 0 = blank (backdrop), tile 1 = grass (colour 1), tile 2 = road
|
|
45
|
+
* (colour 2). The track fills the whole 32x24 SMS screen so the display
|
|
46
|
+
* is a clear road scene, not a flat backdrop. */
|
|
47
|
+
static const uint8_t bg_tiles[96] = {
|
|
48
|
+
/* BG tile 0 = blank */
|
|
49
|
+
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
50
|
+
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
51
|
+
/* BG tile 1 = grass (colour 1 -> plane 0 set) */
|
|
52
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
53
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
54
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
55
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
56
|
+
/* BG tile 2 = road (colour 2 -> plane 1 set) */
|
|
57
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
58
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
59
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
60
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/* Paint the whole 32x24 SMS screen: grey road down the centre lanes,
|
|
64
|
+
* green grass on the shoulders. BG tile bank is $0000. The road spans the
|
|
65
|
+
* three lanes (player X 72..184 -> roughly cols 8..23). */
|
|
66
|
+
static void draw_track(void) {
|
|
67
|
+
uint8_t row, col;
|
|
68
|
+
for (row = 0; row < 24; row++) {
|
|
69
|
+
for (col = 0; col < 32; col++) {
|
|
70
|
+
uint8_t road = (col >= 8 && col <= 23);
|
|
71
|
+
sms_set_tilemap_cell(row, col, road ? 2 : 1, 0);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
41
76
|
/* Two sprite tiles — player (colour 1) + enemy (colour 2). */
|
|
42
77
|
static const uint8_t tiles[64] = {
|
|
43
78
|
/* Tile 0 = player car (colour 1 → plane 0 set) */
|
|
@@ -97,7 +132,9 @@ void main(void) {
|
|
|
97
132
|
uint8_t i;
|
|
98
133
|
sms_vdp_init();
|
|
99
134
|
sms_load_palette(palette);
|
|
100
|
-
sms_load_tiles(
|
|
135
|
+
sms_load_tiles(0x0000, bg_tiles, 96); /* BG tiles -> BG bank $0000 */
|
|
136
|
+
sms_load_tiles(0x2000, tiles, 64); /* sprite tiles -> sprite bank $2000 */
|
|
137
|
+
draw_track();
|
|
101
138
|
sms_sprite_init();
|
|
102
139
|
sfx_init();
|
|
103
140
|
sms_vdp_display_on();
|
|
@@ -15,6 +15,7 @@ extern void sms_vdp_display_on(void);
|
|
|
15
15
|
extern void sms_vdp_set_addr(uint16_t addr, uint8_t prefix);
|
|
16
16
|
extern void sms_load_palette(const uint8_t *palette);
|
|
17
17
|
extern void sms_load_tiles(uint16_t vram_dest, const uint8_t *src, uint16_t byte_count);
|
|
18
|
+
extern void sms_set_tilemap_cell(uint8_t row, uint8_t col, uint8_t tile_idx, uint8_t attr);
|
|
18
19
|
extern void sms_vblank_wait(void);
|
|
19
20
|
extern uint8_t sms_joypad_read(void);
|
|
20
21
|
extern void sms_sprite_init(void);
|
|
@@ -29,13 +30,49 @@ extern void sms_sat_upload(void);
|
|
|
29
30
|
#define T_ENEMY 2
|
|
30
31
|
|
|
31
32
|
static const uint8_t palette[32] = {
|
|
32
|
-
|
|
33
|
+
/* BG: 0 = backdrop, 1 = deep space blue, 2 = lighter space blue, 3 = star white */
|
|
34
|
+
0x10,0x08,0x20,0x3F, 0x00,0x00,0x00,0x00,
|
|
33
35
|
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
|
34
36
|
/* Sprite palette: white, yellow, red */
|
|
35
37
|
0x00,0x3F,0x0F,0x03, 0x00,0x00,0x00,0x00,
|
|
36
38
|
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
|
37
39
|
};
|
|
38
40
|
|
|
41
|
+
/* Three BG tiles for the starfield, loaded into the BG tile bank at $0000:
|
|
42
|
+
* tile 0 = deep space (solid colour 1)
|
|
43
|
+
* tile 1 = lighter space band (solid colour 2)
|
|
44
|
+
* tile 2 = space with a star (mostly colour 1, one colour-3 pixel) */
|
|
45
|
+
static const uint8_t bg_tiles[96] = {
|
|
46
|
+
/* tile 0 = deep space (colour 1 -> plane 0 set) */
|
|
47
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
48
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
49
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
50
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
51
|
+
/* tile 1 = lighter band (colour 2 -> plane 1 set) */
|
|
52
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
53
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
54
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
55
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
56
|
+
/* tile 2 = deep space + a star: row 3 col 3 = colour 3 (planes 0+1) */
|
|
57
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
58
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x10,0x00,0x00,
|
|
59
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
60
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/* Paint the whole 32x24 SMS screen with a banded starfield so the screen
|
|
64
|
+
* is clearly space, not a flat backdrop. BG tile bank is $0000. */
|
|
65
|
+
static void draw_starfield(void) {
|
|
66
|
+
uint8_t row, col;
|
|
67
|
+
for (row = 0; row < 24; row++) {
|
|
68
|
+
for (col = 0; col < 32; col++) {
|
|
69
|
+
uint8_t t = (row & 2) ? 1 : 0; /* alternating depth bands */
|
|
70
|
+
if (((row * 7 + col * 5) & 7) == 0) t = 2; /* sparse stars */
|
|
71
|
+
sms_set_tilemap_cell(row, col, t, 0);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
39
76
|
static const uint8_t sprite_tiles[32 * 3] = {
|
|
40
77
|
/* T_SHIP — diamond using colour 1 (white) */
|
|
41
78
|
0x18,0x00,0x00,0x00, 0x3C,0x00,0x00,0x00,
|
|
@@ -96,7 +133,9 @@ void main(void) {
|
|
|
96
133
|
|
|
97
134
|
sms_vdp_init();
|
|
98
135
|
sms_load_palette(palette);
|
|
99
|
-
sms_load_tiles(
|
|
136
|
+
sms_load_tiles(0x0000, bg_tiles, 96); /* BG tiles -> BG bank $0000 */
|
|
137
|
+
sms_load_tiles(0x2000, sprite_tiles, 32 * 3); /* sprite tiles -> $2000 */
|
|
138
|
+
draw_starfield();
|
|
100
139
|
|
|
101
140
|
player.x = 120; player.y = 160; player.alive = 1;
|
|
102
141
|
{
|
|
@@ -20,6 +20,7 @@ extern void sms_vdp_init(void);
|
|
|
20
20
|
extern void sms_vdp_display_on(void);
|
|
21
21
|
extern void sms_load_palette(const uint8_t *palette);
|
|
22
22
|
extern void sms_load_tiles(uint16_t vram_dest, const uint8_t *src, uint16_t byte_count);
|
|
23
|
+
extern void sms_set_tilemap_cell(uint8_t row, uint8_t col, uint8_t tile_idx, uint8_t attr);
|
|
23
24
|
extern void sms_vblank_wait(void);
|
|
24
25
|
extern uint8_t sms_joypad_read(void);
|
|
25
26
|
extern uint8_t sms_joypad_read_p2(void);
|
|
@@ -35,7 +36,8 @@ extern void sms_sat_upload(void);
|
|
|
35
36
|
#define PADDLE_X2 232
|
|
36
37
|
|
|
37
38
|
static const uint8_t palette[32] = {
|
|
38
|
-
|
|
39
|
+
/* BG: 0 = backdrop, 1 = court green, 2 = court line / net white */
|
|
40
|
+
0x10, 0x08, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
39
41
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
40
42
|
/* Sprite palette: white at idx 1 */
|
|
41
43
|
0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
@@ -49,6 +51,43 @@ static const uint8_t tile_solid[32] = {
|
|
|
49
51
|
0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
|
50
52
|
};
|
|
51
53
|
|
|
54
|
+
/* Three BG tiles for the court, loaded into the BG tile bank at $0000:
|
|
55
|
+
* tile 0 = court green (solid colour 1)
|
|
56
|
+
* tile 1 = court line / border (solid colour 2 = white)
|
|
57
|
+
* tile 2 = dashed net (colour 2 vertical stripe on green) */
|
|
58
|
+
static const uint8_t bg_tiles[96] = {
|
|
59
|
+
/* tile 0 = court green (colour 1 -> plane 0 set) */
|
|
60
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
61
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
62
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
63
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
64
|
+
/* tile 1 = court line / border (colour 2 -> plane 1 set) */
|
|
65
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
66
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
67
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
68
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
69
|
+
/* tile 2 = net: centre column colour 2, rest colour 1 (green) */
|
|
70
|
+
0xFF,0x18,0x00,0x00, 0xFF,0x18,0x00,0x00,
|
|
71
|
+
0xFF,0x18,0x00,0x00, 0xFF,0x18,0x00,0x00,
|
|
72
|
+
0xFF,0x18,0x00,0x00, 0xFF,0x18,0x00,0x00,
|
|
73
|
+
0xFF,0x18,0x00,0x00, 0xFF,0x18,0x00,0x00,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/* Paint the whole 32x24 court: green field, white top/bottom border lines,
|
|
77
|
+
* and a dashed net down the centre column. BG tile bank is $0000. */
|
|
78
|
+
static void draw_court(void) {
|
|
79
|
+
uint8_t row, col;
|
|
80
|
+
for (row = 0; row < 24; row++) {
|
|
81
|
+
for (col = 0; col < 32; col++) {
|
|
82
|
+
uint8_t t = 0; /* green field */
|
|
83
|
+
if (row <= 1 || row >= 22) t = 1; /* white top/bottom lines */
|
|
84
|
+
else if (col == 1 || col == 30) t = 1; /* white sidelines */
|
|
85
|
+
else if (col == 16) t = 2; /* solid centre net */
|
|
86
|
+
sms_set_tilemap_cell(row, col, t, 0);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
52
91
|
static int16_t p1y, p2y, bx, by;
|
|
53
92
|
static int8_t bdx, bdy;
|
|
54
93
|
static uint8_t score_p1, score_p2;
|
|
@@ -72,7 +111,9 @@ void main(void) {
|
|
|
72
111
|
uint8_t i;
|
|
73
112
|
sms_vdp_init();
|
|
74
113
|
sms_load_palette(palette);
|
|
75
|
-
sms_load_tiles(
|
|
114
|
+
sms_load_tiles(0x0000, bg_tiles, 96); /* BG court tiles -> BG bank $0000 */
|
|
115
|
+
sms_load_tiles(0x2000, tile_solid, 32); /* paddle/ball sprite tile -> $2000 */
|
|
116
|
+
draw_court();
|
|
76
117
|
sms_sprite_init();
|
|
77
118
|
sfx_init();
|
|
78
119
|
sms_vdp_display_on();
|
|
@@ -1,61 +1,83 @@
|
|
|
1
1
|
/* default.c — SNES PVSnesLib starter (C).
|
|
2
2
|
*
|
|
3
|
-
* Smallest "ROM that does something visible"
|
|
4
|
-
*
|
|
5
|
-
* Pressing the d-pad moves the sprite.
|
|
3
|
+
* Smallest "ROM that does something visible": a full-screen diamond-tile
|
|
4
|
+
* background (BG0) with a movable white sprite parked in the centre.
|
|
5
|
+
* Pressing the d-pad moves the sprite. The tiled backdrop means the very
|
|
6
|
+
* first build shows recognizable content, not a flat colour — the SNES
|
|
7
|
+
* equivalent of the "is anything even rendering?" smoke test.
|
|
6
8
|
*
|
|
7
9
|
* Picked as the default SNES template because:
|
|
8
|
-
* - PVSnesLib gives a clean C API (oamSet, padsCurrent
|
|
10
|
+
* - PVSnesLib gives a clean C API (bgInitTileSet, oamSet, padsCurrent…)
|
|
9
11
|
* instead of raw 65816 / direct register pokes.
|
|
10
12
|
* - tcc-65816 builds it in <2s.
|
|
11
|
-
* - You read this file once and know how every SNES C scaffold
|
|
12
|
-
*
|
|
13
|
+
* - You read this file once and know how every SNES C scaffold is
|
|
14
|
+
* structured (hello_sprite, shmup, platformer all extend it).
|
|
15
|
+
*
|
|
16
|
+
* The one footgun this guards against: on the SNES, NOTHING renders until
|
|
17
|
+
* setScreenOn() lifts forced blank (INIDISP $80) AND at least one layer
|
|
18
|
+
* (a BG or the sprite layer) actually has tiles + a non-black palette.
|
|
19
|
+
* Disabling every BG and showing one sprite (the obvious "minimal" move)
|
|
20
|
+
* leaves a near-blank screen — so here we light up BG0 too.
|
|
13
21
|
*
|
|
14
|
-
* For raw 65816 see template:"asm" (kept for cycle-accurate work).
|
|
15
22
|
* For text-mode console output see template:"c_hello".
|
|
16
|
-
* For
|
|
23
|
+
* For raw 65816 see template:"asm" (kept for cycle-accurate work).
|
|
24
|
+
* For genre-shaped scaffolds see scaffold({op:'game', genre:"shmup", ...}).
|
|
17
25
|
*
|
|
18
|
-
* Sibling `data.asm` provides
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* platform:"snes", language:"c",
|
|
22
|
-
* sourcesPaths:{"main.c":"...","data.asm":"..."},
|
|
23
|
-
* })
|
|
26
|
+
* Sibling `data.asm` provides tilsprite (one 8×8 4bpp diamond tile) +
|
|
27
|
+
* palsprite (its 16-colour palette). We reuse that one tile for BOTH the
|
|
28
|
+
* sprite and the BG wallpaper — replace with real gfx4snes .pic/.pal art.
|
|
24
29
|
*/
|
|
25
30
|
#include <snes.h>
|
|
26
31
|
|
|
27
32
|
extern char tilsprite, palsprite;
|
|
28
33
|
|
|
34
|
+
/* A 32×32 BG tilemap (one screen), all pointing at tile 0 = the diamond.
|
|
35
|
+
* SNES map entries are 16-bit (tile# + palette/priority/flip bits); 0x0000
|
|
36
|
+
* = tile 0, palette 0, no flip. 32*32 = 1024 entries = 2048 bytes. We fill
|
|
37
|
+
* it at runtime so the source stays small. */
|
|
38
|
+
static u16 bg_map[32 * 32];
|
|
39
|
+
|
|
29
40
|
int main(void) {
|
|
30
41
|
u16 x = 120, y = 100;
|
|
42
|
+
u16 i;
|
|
31
43
|
|
|
32
|
-
/* BG_MODE1
|
|
33
|
-
*
|
|
44
|
+
/* BG_MODE1: BG0/BG1 are 16-colour, BG2 is 4-colour — standard mix.
|
|
45
|
+
* We use BG0 for the wallpaper and the sprite layer on top. */
|
|
34
46
|
setMode(BG_MODE1, 0);
|
|
35
|
-
bgSetDisable(0);
|
|
36
47
|
bgSetDisable(1);
|
|
37
48
|
bgSetDisable(2);
|
|
38
49
|
|
|
39
|
-
/*
|
|
40
|
-
*
|
|
41
|
-
|
|
50
|
+
/* Load the diamond tile + its palette as BG0's tileset. Tile gfx go to
|
|
51
|
+
* VRAM $2000, palette into BG palette 0. 32 bytes of tile (one 8×8 4bpp
|
|
52
|
+
* tile), 32 bytes of palette (16 colours × 2). */
|
|
53
|
+
bgInitTileSet(0, (u8 *)&tilsprite, (u8 *)&palsprite,
|
|
54
|
+
0, /* palette entry 0 */
|
|
55
|
+
32, /* tile data size */
|
|
56
|
+
32, /* palette size */
|
|
57
|
+
BG_16COLORS, /* colour mode */
|
|
58
|
+
0x2000); /* VRAM addr for BG0 tiles */
|
|
59
|
+
|
|
60
|
+
/* Fill the map with tile 0 and upload it to VRAM $6000. */
|
|
61
|
+
for (i = 0; i < 32 * 32; i++) bg_map[i] = 0x0000;
|
|
62
|
+
bgInitMapSet(0, (u8 *)bg_map, sizeof(bg_map), SC_32x32, 0x6000);
|
|
63
|
+
|
|
64
|
+
bgSetEnable(0);
|
|
42
65
|
|
|
43
|
-
/* Upload
|
|
44
|
-
*
|
|
45
|
-
* are 8×8, large 16×16 (we use small). */
|
|
66
|
+
/* Upload the same tile as a sprite (VRAM $0000, OBJ palette slot 0) so
|
|
67
|
+
* the movable sprite reads distinctly on top of the wallpaper. */
|
|
46
68
|
oamInitGfxSet(&tilsprite, 32, &palsprite, 32,
|
|
47
69
|
0, /* OBJ palette slot */
|
|
48
70
|
0x0000, /* VRAM address for sprite tiles */
|
|
49
71
|
OBJ_SIZE8_L16);
|
|
50
72
|
|
|
51
|
-
/* Place sprite #0 at the centre. */
|
|
73
|
+
/* Place sprite #0 at the centre, highest priority so it sits over BG0. */
|
|
52
74
|
oamSet(0, x, y,
|
|
53
|
-
3 /*
|
|
54
|
-
0 /*
|
|
75
|
+
3 /* priority */, 0 /* no flip */, 0 /* palette */,
|
|
76
|
+
0 /* tile index */, 0 /* objsize */);
|
|
55
77
|
oamSetEx(0, OBJ_SMALL, OBJ_SHOW);
|
|
56
78
|
|
|
57
|
-
/* Until setScreenOn() fires, the SNES holds forced blank
|
|
58
|
-
*
|
|
79
|
+
/* Until setScreenOn() fires, the SNES holds forced blank (INIDISP $80)
|
|
80
|
+
* and nothing renders. */
|
|
59
81
|
setScreenOn();
|
|
60
82
|
|
|
61
83
|
while (1) {
|
|
@@ -322,4 +322,26 @@ palsprite:
|
|
|
322
322
|
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
323
323
|
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
324
324
|
|
|
325
|
+
; ── Background wallpaper (one 8x8 4bpp tile, 4 solid colour quadrants) ──
|
|
326
|
+
; Tiled across BG1 it paints the whole screen in four muted colours so the
|
|
327
|
+
; playfield never reads as a flat/blank backdrop. Quadrant->colour: TL=1,
|
|
328
|
+
; TR=2, BL=3, BR=4. 4bpp plane order: bytes 0-15 = rows 0-7 plane0/plane1
|
|
329
|
+
; pairs, bytes 16-31 = rows 0-7 plane2/plane3 pairs.
|
|
330
|
+
tilbg:
|
|
331
|
+
.db $F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F ; rows 0-3: p0=left p1=right
|
|
332
|
+
.db $F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0 ; rows 4-7: p0+p1 = left
|
|
333
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00 ; rows 0-3: p2/p3 = 0
|
|
334
|
+
.db $0F, $00, $0F, $00, $0F, $00, $0F, $00 ; rows 4-7: p2 = right
|
|
335
|
+
|
|
336
|
+
palbg:
|
|
337
|
+
; 16-colour BG palette; only 1-4 used (the four wallpaper quadrant tones).
|
|
338
|
+
.db $00, $00 ; 0 unused (BG fully opaque)
|
|
339
|
+
.db $C4, $30 ; 1 dark blue
|
|
340
|
+
.db $42, $29 ; 2 dark teal
|
|
341
|
+
.db $88, $30 ; 3 dark purple
|
|
342
|
+
.db $C6, $24 ; 4 dark slate
|
|
343
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
344
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
345
|
+
.db $00, $00, $00, $00, $00, $00
|
|
346
|
+
|
|
325
347
|
.ends
|
|
@@ -23,11 +23,16 @@
|
|
|
23
23
|
|
|
24
24
|
extern char tilfont, palfont;
|
|
25
25
|
extern char tilsprite, palsprite;
|
|
26
|
+
extern char tilbg, palbg; /* wallpaper tile + palette (data.asm) */
|
|
26
27
|
|
|
27
28
|
/* consoleVblank() copies the dirty text tilemap to VRAM during VBlank.
|
|
28
29
|
* No public prototype in console.h, so declare it; call once per frame. */
|
|
29
30
|
extern void consoleVblank(void);
|
|
30
31
|
|
|
32
|
+
/* BG1 wallpaper map: a full 32x32 screen of the 4-colour tile so the
|
|
33
|
+
* playfield reads as a real backdrop, not flat blank. Filled at runtime. */
|
|
34
|
+
static u16 bg_map[32 * 32];
|
|
35
|
+
|
|
31
36
|
typedef struct { s16 x, y, w, h; } Rect;
|
|
32
37
|
|
|
33
38
|
#define WORLD_W 512
|
|
@@ -80,7 +85,17 @@ int main(void) {
|
|
|
80
85
|
* registers — point BG0 at the same font ($3000) + map ($6800). */
|
|
81
86
|
bgSetGfxPtr(0, 0x3000);
|
|
82
87
|
bgSetMapPtr(0, 0x6800, SC_32x32);
|
|
83
|
-
|
|
88
|
+
|
|
89
|
+
/* BG1 = full-screen wallpaper so the playfield never reads as blank.
|
|
90
|
+
* Tiles -> VRAM $2000, map -> VRAM $4000 (clear of sprites $0000 and
|
|
91
|
+
* the console gfx $3000 / map $6800). Map entries use palette block 1
|
|
92
|
+
* (0x0400) so the wallpaper palette doesn't disturb the console font
|
|
93
|
+
* palette in block 0 (HUD text stays legible). */
|
|
94
|
+
bgInitTileSet(1, (u8 *)&tilbg, (u8 *)&palbg, 1,
|
|
95
|
+
32, 32, BG_16COLORS, 0x2000);
|
|
96
|
+
for (i = 0; i < 32 * 32; i++) bg_map[i] = 0x0400;
|
|
97
|
+
bgInitMapSet(1, (u8 *)bg_map, sizeof(bg_map), SC_32x32, 0x4000);
|
|
98
|
+
bgSetEnable(1);
|
|
84
99
|
bgSetDisable(2);
|
|
85
100
|
|
|
86
101
|
oamInitGfxSet(&tilsprite, 32, &palsprite, 32, 0, 0x0000, OBJ_SIZE8_L16);
|
|
@@ -309,4 +309,26 @@ palfont:
|
|
|
309
309
|
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
310
310
|
.db $00, $00
|
|
311
311
|
|
|
312
|
+
; ── Background wallpaper (one 8x8 4bpp tile, 4 solid colour quadrants) ──
|
|
313
|
+
; Tiled across BG1 it paints the whole screen in four muted colours so the
|
|
314
|
+
; playfield never reads as a flat/blank backdrop. Quadrant->colour: TL=1,
|
|
315
|
+
; TR=2, BL=3, BR=4. 4bpp plane order: bytes 0-15 = rows 0-7 plane0/plane1
|
|
316
|
+
; pairs, bytes 16-31 = rows 0-7 plane2/plane3 pairs.
|
|
317
|
+
tilbg:
|
|
318
|
+
.db $F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F ; rows 0-3: p0=left p1=right
|
|
319
|
+
.db $F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0 ; rows 4-7: p0+p1 = left
|
|
320
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00 ; rows 0-3: p2/p3 = 0
|
|
321
|
+
.db $0F, $00, $0F, $00, $0F, $00, $0F, $00 ; rows 4-7: p2 = right
|
|
322
|
+
|
|
323
|
+
palbg:
|
|
324
|
+
; 16-colour BG palette; only 1-4 used (the four wallpaper quadrant tones).
|
|
325
|
+
.db $00, $00 ; 0 unused (BG fully opaque)
|
|
326
|
+
.db $C4, $30 ; 1 dark blue
|
|
327
|
+
.db $42, $29 ; 2 dark teal
|
|
328
|
+
.db $88, $30 ; 3 dark purple
|
|
329
|
+
.db $C6, $24 ; 4 dark slate
|
|
330
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
331
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
332
|
+
.db $00, $00, $00, $00, $00, $00
|
|
333
|
+
|
|
312
334
|
.ends
|
|
@@ -15,11 +15,16 @@
|
|
|
15
15
|
#include "snes_sfx.c"
|
|
16
16
|
|
|
17
17
|
extern char tilfont, palfont;
|
|
18
|
+
extern char tilbg, palbg; /* wallpaper tile + palette (data.asm) */
|
|
18
19
|
|
|
19
20
|
/* consoleVblank() copies the dirty text tilemap to VRAM during VBlank.
|
|
20
21
|
* No public prototype in console.h, so declare it; call once per frame. */
|
|
21
22
|
extern void consoleVblank(void);
|
|
22
23
|
|
|
24
|
+
/* BG1 wallpaper map: a full 32x32 screen of the 4-colour tile so the
|
|
25
|
+
* playfield reads as a real backdrop, not flat blank. Filled at runtime. */
|
|
26
|
+
static u16 bg_map[32 * 32];
|
|
27
|
+
|
|
23
28
|
#define COLS 6
|
|
24
29
|
#define ROWS 12
|
|
25
30
|
|
|
@@ -136,6 +141,7 @@ static void render_score(void) {
|
|
|
136
141
|
int main(void) {
|
|
137
142
|
s16 r, c;
|
|
138
143
|
u16 pad, prev = 0, fall_rate;
|
|
144
|
+
u16 i;
|
|
139
145
|
u8 t;
|
|
140
146
|
|
|
141
147
|
consoleSetTextMapPtr(0x6800);
|
|
@@ -147,7 +153,17 @@ int main(void) {
|
|
|
147
153
|
* registers — point BG0 at the same font ($3000) + map ($6800). */
|
|
148
154
|
bgSetGfxPtr(0, 0x3000);
|
|
149
155
|
bgSetMapPtr(0, 0x6800, SC_32x32);
|
|
150
|
-
|
|
156
|
+
|
|
157
|
+
/* BG1 = full-screen wallpaper so the playfield never reads as blank.
|
|
158
|
+
* Tiles -> VRAM $2000, map -> VRAM $4000 (clear of sprites $0000 and
|
|
159
|
+
* the console gfx $3000 / map $6800). Map entries use palette block 1
|
|
160
|
+
* (0x0400) so the wallpaper palette doesn't disturb the console font
|
|
161
|
+
* palette in block 0 (HUD/grid text stays legible). */
|
|
162
|
+
bgInitTileSet(1, (u8 *)&tilbg, (u8 *)&palbg, 1,
|
|
163
|
+
32, 32, BG_16COLORS, 0x2000);
|
|
164
|
+
for (i = 0; i < 32 * 32; i++) bg_map[i] = 0x0400;
|
|
165
|
+
bgInitMapSet(1, (u8 *)bg_map, sizeof(bg_map), SC_32x32, 0x4000);
|
|
166
|
+
bgSetEnable(1);
|
|
151
167
|
bgSetDisable(2);
|
|
152
168
|
|
|
153
169
|
for (r = 0; r < ROWS; r++)
|
|
@@ -328,4 +328,26 @@ palsprite:
|
|
|
328
328
|
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
329
329
|
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
330
330
|
|
|
331
|
+
; ── Background wallpaper (one 8x8 4bpp tile, 4 solid colour quadrants) ──
|
|
332
|
+
; Tiled across BG1 it paints the whole screen in four muted colours so the
|
|
333
|
+
; playfield never reads as a flat/blank backdrop. Quadrant->colour: TL=1,
|
|
334
|
+
; TR=2, BL=3, BR=4. 4bpp plane order: bytes 0-15 = rows 0-7 plane0/plane1
|
|
335
|
+
; pairs, bytes 16-31 = rows 0-7 plane2/plane3 pairs.
|
|
336
|
+
tilbg:
|
|
337
|
+
.db $F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F ; rows 0-3: p0=left p1=right
|
|
338
|
+
.db $F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0 ; rows 4-7: p0+p1 = left
|
|
339
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00 ; rows 0-3: p2/p3 = 0
|
|
340
|
+
.db $0F, $00, $0F, $00, $0F, $00, $0F, $00 ; rows 4-7: p2 = right
|
|
341
|
+
|
|
342
|
+
palbg:
|
|
343
|
+
; 16-colour BG palette; only 1-4 used (the four wallpaper quadrant tones).
|
|
344
|
+
.db $00, $00 ; 0 unused (BG fully opaque)
|
|
345
|
+
.db $C4, $30 ; 1 dark blue
|
|
346
|
+
.db $42, $29 ; 2 dark teal
|
|
347
|
+
.db $88, $30 ; 3 dark purple
|
|
348
|
+
.db $C6, $24 ; 4 dark slate
|
|
349
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
350
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
351
|
+
.db $00, $00, $00, $00, $00, $00
|
|
352
|
+
|
|
331
353
|
.ends
|
|
@@ -12,11 +12,16 @@
|
|
|
12
12
|
|
|
13
13
|
extern char tilfont, palfont;
|
|
14
14
|
extern char tilsprite, palsprite;
|
|
15
|
+
extern char tilbg, palbg; /* wallpaper tile + palette (data.asm) */
|
|
15
16
|
|
|
16
17
|
/* consoleVblank() copies the dirty text tilemap to VRAM during VBlank.
|
|
17
18
|
* No public prototype in console.h, so declare it; call once per frame. */
|
|
18
19
|
extern void consoleVblank(void);
|
|
19
20
|
|
|
21
|
+
/* BG1 wallpaper map: a full 32x32 screen of the 4-colour tile so the
|
|
22
|
+
* playfield reads as a real backdrop, not flat blank. Filled at runtime. */
|
|
23
|
+
static u16 bg_map[32 * 32];
|
|
24
|
+
|
|
20
25
|
#define LANE_LEFT_X 72
|
|
21
26
|
#define LANE_MID_X 124
|
|
22
27
|
#define LANE_RIGHT_X 176
|
|
@@ -103,6 +108,7 @@ static void draw_road(void) {
|
|
|
103
108
|
int main(void) {
|
|
104
109
|
u16 pad;
|
|
105
110
|
u8 i;
|
|
111
|
+
u16 bi;
|
|
106
112
|
s16 step;
|
|
107
113
|
|
|
108
114
|
consoleSetTextMapPtr(0x6800);
|
|
@@ -114,7 +120,17 @@ int main(void) {
|
|
|
114
120
|
* registers — point BG0 at the same font ($3000) + map ($6800). */
|
|
115
121
|
bgSetGfxPtr(0, 0x3000);
|
|
116
122
|
bgSetMapPtr(0, 0x6800, SC_32x32);
|
|
117
|
-
|
|
123
|
+
|
|
124
|
+
/* BG1 = full-screen wallpaper so the playfield never reads as blank.
|
|
125
|
+
* Tiles -> VRAM $2000, map -> VRAM $4000 (clear of sprites $0000 and
|
|
126
|
+
* the console gfx $3000 / map $6800). Map entries use palette block 1
|
|
127
|
+
* (0x0400) so the wallpaper palette doesn't disturb the console font
|
|
128
|
+
* palette in block 0 (HUD/road text stays legible). */
|
|
129
|
+
bgInitTileSet(1, (u8 *)&tilbg, (u8 *)&palbg, 1,
|
|
130
|
+
32, 32, BG_16COLORS, 0x2000);
|
|
131
|
+
for (bi = 0; bi < 32 * 32; bi++) bg_map[bi] = 0x0400;
|
|
132
|
+
bgInitMapSet(1, (u8 *)bg_map, sizeof(bg_map), SC_32x32, 0x4000);
|
|
133
|
+
bgSetEnable(1);
|
|
118
134
|
bgSetDisable(2);
|
|
119
135
|
|
|
120
136
|
/* 2 sprite tiles × 32 bytes = 64 bytes */
|
|
@@ -351,4 +351,26 @@ palsprite:
|
|
|
351
351
|
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
352
352
|
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
353
353
|
|
|
354
|
+
; ── Background wallpaper (one 8×8 4bpp tile, 4 solid colour quadrants) ──
|
|
355
|
+
; Tiled across BG1 it paints the whole screen in four muted colours so the
|
|
356
|
+
; playfield never reads as a flat/blank backdrop. Quadrant→colour: TL=1,
|
|
357
|
+
; TR=2, BL=3, BR=4. 4bpp plane order: bytes 0-15 = rows 0-7 plane0/plane1
|
|
358
|
+
; pairs, bytes 16-31 = rows 0-7 plane2/plane3 pairs.
|
|
359
|
+
tilbg:
|
|
360
|
+
.db $F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F ; rows 0-3: p0=left p1=right
|
|
361
|
+
.db $F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0 ; rows 4-7: p0+p1 = left
|
|
362
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00 ; rows 0-3: p2/p3 = 0
|
|
363
|
+
.db $0F, $00, $0F, $00, $0F, $00, $0F, $00 ; rows 4-7: p2 = right
|
|
364
|
+
|
|
365
|
+
palbg:
|
|
366
|
+
; 16-colour BG palette; only 1-4 used (the four wallpaper quadrant tones).
|
|
367
|
+
.db $00, $00 ; 0 unused (BG fully opaque)
|
|
368
|
+
.db $C4, $30 ; 1 dark blue
|
|
369
|
+
.db $42, $29 ; 2 dark teal
|
|
370
|
+
.db $88, $30 ; 3 dark purple
|
|
371
|
+
.db $C6, $24 ; 4 dark slate
|
|
372
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
373
|
+
.db $00, $00, $00, $00, $00, $00, $00, $00
|
|
374
|
+
.db $00, $00, $00, $00, $00, $00
|
|
375
|
+
|
|
354
376
|
.ends
|