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
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
#define T_CAR_EN (TILE_USER_INDEX + 1)
|
|
30
30
|
#define T_LANE (TILE_USER_INDEX + 2) /* dashed lane divider (BG_B) */
|
|
31
31
|
#define T_EDGE (TILE_USER_INDEX + 3) /* solid road edge (BG_B) */
|
|
32
|
+
#define T_GRASS (TILE_USER_INDEX + 4) /* roadside backdrop (BG_A) */
|
|
33
|
+
#define T_ASPHALT (TILE_USER_INDEX + 5) /* road surface backdrop(BG_A) */
|
|
32
34
|
|
|
33
35
|
static const u32 tile_car_p1[8] = {
|
|
34
36
|
0x01111110, 0x11111111, 0x12222221, 0x11111111,
|
|
@@ -51,6 +53,18 @@ static const u32 tile_edge[8] = {
|
|
|
51
53
|
0x00000022, 0x00000022, 0x00000022, 0x00000022,
|
|
52
54
|
0x00000022, 0x00000022, 0x00000022, 0x00000022,
|
|
53
55
|
};
|
|
56
|
+
/* Roadside grass (colour 5) with a couple of darker tufts (colour 6) so
|
|
57
|
+
* it isn't a flat fill — tiled down both shoulders on BG_A. */
|
|
58
|
+
static const u32 tile_grass[8] = {
|
|
59
|
+
0x55555555, 0x55556555, 0x55555555, 0x65555555,
|
|
60
|
+
0x55555555, 0x55555565, 0x55555555, 0x55655555,
|
|
61
|
+
};
|
|
62
|
+
/* Road asphalt (colour 6) with faint speckle (colour 5) — tiled across
|
|
63
|
+
* the driving surface on BG_A, behind the BG_B lane markings + cars. */
|
|
64
|
+
static const u32 tile_asphalt[8] = {
|
|
65
|
+
0x66666666, 0x66666566, 0x66666666, 0x56666666,
|
|
66
|
+
0x66666666, 0x66666656, 0x66666666, 0x66566666,
|
|
67
|
+
};
|
|
54
68
|
|
|
55
69
|
/* The road lives on BG_B (8×8 cells). Two dashed dividers sit between the
|
|
56
70
|
* three lanes; solid edges frame the outermost lanes. */
|
|
@@ -61,15 +75,28 @@ static const u32 tile_edge[8] = {
|
|
|
61
75
|
#define ROAD_EDGE_L ((LANE_LEFT_X - 12) / 8)
|
|
62
76
|
#define ROAD_EDGE_R ((LANE_RIGHT_X + 12) / 8)
|
|
63
77
|
|
|
78
|
+
/* Far plane (BG_A): grass shoulders + asphalt driving surface, tiled
|
|
79
|
+
* across the whole 40x28 screen so the road no longer floats on black.
|
|
80
|
+
* Drawn at low priority; the BG_B markings + sprite cars sit on top. */
|
|
81
|
+
static void draw_backdrop(void) {
|
|
82
|
+
s16 r, c;
|
|
83
|
+
for (r = 0; r < 28; r++)
|
|
84
|
+
for (c = 0; c < 40; c++) {
|
|
85
|
+
u16 t = (c >= ROAD_EDGE_L && c <= ROAD_EDGE_R) ? T_ASPHALT : T_GRASS;
|
|
86
|
+
VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL0, 0, 0, 0, t), c, r);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
64
90
|
static void draw_road(void) {
|
|
65
91
|
s16 r;
|
|
66
92
|
for (r = ROAD_TOP_ROW; r <= ROAD_BOT_ROW; r++) {
|
|
67
|
-
/* Left edge (stripe on its right), right edge (hflipped).
|
|
68
|
-
|
|
69
|
-
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0,
|
|
93
|
+
/* Left edge (stripe on its right), right edge (hflipped). HIGH
|
|
94
|
+
* priority so the markings sit above the BG_A asphalt backdrop. */
|
|
95
|
+
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, 1, 0, 0, T_EDGE), ROAD_EDGE_L, r);
|
|
96
|
+
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, 1, 0, 1, T_EDGE), ROAD_EDGE_R, r);
|
|
70
97
|
/* Two dashed lane dividers. */
|
|
71
|
-
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0,
|
|
72
|
-
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0,
|
|
98
|
+
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, 1, 0, 0, T_LANE), LANE_DIV1_COL, r);
|
|
99
|
+
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, 1, 0, 0, T_LANE), LANE_DIV2_COL, r);
|
|
73
100
|
}
|
|
74
101
|
}
|
|
75
102
|
|
|
@@ -125,18 +152,24 @@ static void render_score(void) {
|
|
|
125
152
|
int main(bool hard) {
|
|
126
153
|
(void)hard;
|
|
127
154
|
|
|
128
|
-
/* PAL0 = player (white + blue trim). PAL1 = enemy
|
|
155
|
+
/* PAL0 = player (white + blue trim) + road backdrop. PAL1 = enemy. */
|
|
129
156
|
PAL_setColor(0 + 1, 0x0EEE); /* white body */
|
|
130
157
|
PAL_setColor(0 + 2, 0x0AAA); /* roof grey */
|
|
158
|
+
PAL_setColor(0 + 5, 0x0260); /* roadside grass */
|
|
159
|
+
PAL_setColor(0 + 6, 0x0222); /* asphalt grey */
|
|
131
160
|
PAL_setColor(16 + 3, 0x000E); /* enemy red */
|
|
132
161
|
PAL_setColor(16 + 4, 0x0666); /* enemy roof */
|
|
133
162
|
|
|
134
|
-
VDP_loadTileData(tile_car_p1, T_CAR_P1,
|
|
135
|
-
VDP_loadTileData(tile_car_enemy, T_CAR_EN,
|
|
136
|
-
VDP_loadTileData(tile_lane, T_LANE,
|
|
137
|
-
VDP_loadTileData(tile_edge, T_EDGE,
|
|
163
|
+
VDP_loadTileData(tile_car_p1, T_CAR_P1, 1, DMA);
|
|
164
|
+
VDP_loadTileData(tile_car_enemy, T_CAR_EN, 1, DMA);
|
|
165
|
+
VDP_loadTileData(tile_lane, T_LANE, 1, DMA);
|
|
166
|
+
VDP_loadTileData(tile_edge, T_EDGE, 1, DMA);
|
|
167
|
+
VDP_loadTileData(tile_grass, T_GRASS, 1, DMA);
|
|
168
|
+
VDP_loadTileData(tile_asphalt, T_ASPHALT, 1, DMA);
|
|
138
169
|
|
|
139
|
-
/* Draw the
|
|
170
|
+
/* Draw the grass+asphalt backdrop (BG_A) then the road markings on
|
|
171
|
+
* BG_B over it. */
|
|
172
|
+
draw_backdrop();
|
|
140
173
|
draw_road();
|
|
141
174
|
|
|
142
175
|
VDP_drawText("SCORE", 28, 2);
|
|
@@ -21,6 +21,23 @@
|
|
|
21
21
|
|
|
22
22
|
#include <genesis.h>
|
|
23
23
|
|
|
24
|
+
/* Two simple 8x8 background tiles for the far plane (BG_B). Tiling them
|
|
25
|
+
* in a checkerboard fills the whole screen so it doesn't read as a blank
|
|
26
|
+
* black backdrop. T_BG_A is a framed block (colour 1 border, colour 2
|
|
27
|
+
* fill); T_BG_B is the same block in colour 3 — alternating them gives a
|
|
28
|
+
* two-tone grid with a clear majority of non-backdrop pixels. */
|
|
29
|
+
#define T_BG_A (TILE_USER_INDEX + 0)
|
|
30
|
+
#define T_BG_B (TILE_USER_INDEX + 1)
|
|
31
|
+
|
|
32
|
+
static const u32 tile_bg_a[8] = {
|
|
33
|
+
0x11111111, 0x12222221, 0x12222221, 0x12222221,
|
|
34
|
+
0x12222221, 0x12222221, 0x12222221, 0x11111111,
|
|
35
|
+
};
|
|
36
|
+
static const u32 tile_bg_b[8] = {
|
|
37
|
+
0x11111111, 0x13333331, 0x13333331, 0x13333331,
|
|
38
|
+
0x13333331, 0x13333331, 0x13333331, 0x11111111,
|
|
39
|
+
};
|
|
40
|
+
|
|
24
41
|
int main(bool hard) {
|
|
25
42
|
/* Boot info: hard == TRUE on power-on, FALSE on soft reset (we
|
|
26
43
|
* could re-init differently in each case; this minimum starter
|
|
@@ -28,7 +45,23 @@ int main(bool hard) {
|
|
|
28
45
|
(void)hard;
|
|
29
46
|
|
|
30
47
|
/* SGDK initialized the VDP + default palette in sega.s + libmd
|
|
31
|
-
* before main() ran.
|
|
48
|
+
* before main() ran. We add a tiled background so the screen isn't a
|
|
49
|
+
* flat black backdrop, then draw the text on top. */
|
|
50
|
+
PAL_setColor(16 + 1, 0x0444); /* dark grey grid border */
|
|
51
|
+
PAL_setColor(16 + 2, 0x0A22); /* deep blue fill */
|
|
52
|
+
PAL_setColor(16 + 3, 0x022A); /* deep red fill (2nd block) */
|
|
53
|
+
|
|
54
|
+
VDP_loadTileData(tile_bg_a, T_BG_A, 1, DMA);
|
|
55
|
+
VDP_loadTileData(tile_bg_b, T_BG_B, 1, DMA);
|
|
56
|
+
|
|
57
|
+
/* Fill the far plane (BG_B) with a checkerboard of the two blocks so
|
|
58
|
+
* a clear majority of the visible 40x28 cells are non-backdrop. */
|
|
59
|
+
for (u16 cy = 0; cy < 28; cy++)
|
|
60
|
+
for (u16 cx = 0; cx < 40; cx++)
|
|
61
|
+
VDP_setTileMapXY(BG_B,
|
|
62
|
+
TILE_ATTR_FULL(PAL1, 0, 0, 0, ((cx ^ cy) & 1) ? T_BG_A : T_BG_B),
|
|
63
|
+
cx, cy);
|
|
64
|
+
|
|
32
65
|
VDP_drawText("HELLO SEGA GENESIS", 10, 12);
|
|
33
66
|
VDP_drawText("BUILT WITH ROM-DEV-MCP", 8, 14);
|
|
34
67
|
|
|
@@ -30,8 +30,22 @@
|
|
|
30
30
|
#define T_SHIP (TILE_USER_INDEX + 1)
|
|
31
31
|
#define T_BULLET (TILE_USER_INDEX + 2)
|
|
32
32
|
#define T_ENEMY (TILE_USER_INDEX + 3)
|
|
33
|
+
#define T_SPACE (TILE_USER_INDEX + 4) /* nebula backdrop A (BG_B) */
|
|
34
|
+
#define T_STARS (TILE_USER_INDEX + 5) /* nebula backdrop B (BG_B) */
|
|
33
35
|
|
|
34
36
|
static const u32 tile_blank[8] = { 0,0,0,0,0,0,0,0 };
|
|
37
|
+
/* Deep-space backdrop tiled across BG_B so the playfield isn't a flat
|
|
38
|
+
* black void. Two distinct nebula blocks are checkerboarded so no single
|
|
39
|
+
* colour dominates the screen: T_SPACE is colour-4 nebula with colour-5
|
|
40
|
+
* star dots; T_STARS swaps the roles (colour-5 field, colour-4 dots). */
|
|
41
|
+
static const u32 tile_space[8] = {
|
|
42
|
+
0x44444444, 0x44455444, 0x44444444, 0x54444445,
|
|
43
|
+
0x44444444, 0x44455444, 0x44444444, 0x54444445,
|
|
44
|
+
};
|
|
45
|
+
static const u32 tile_stars[8] = {
|
|
46
|
+
0x55555555, 0x55544555, 0x55555555, 0x45555554,
|
|
47
|
+
0x55555555, 0x55544555, 0x55555555, 0x45555554,
|
|
48
|
+
};
|
|
35
49
|
static const u32 tile_ship[8] = {
|
|
36
50
|
0x00011000, 0x00011000, 0x00111100, 0x00111100,
|
|
37
51
|
0x01111110, 0x01111110, 0x11111111, 0x11000011,
|
|
@@ -102,8 +116,10 @@ int main(bool hard) {
|
|
|
102
116
|
|
|
103
117
|
/* PAL0 — used by player + font */
|
|
104
118
|
PAL_setColor(0 + 1, 0x0EEE); /* ship white */
|
|
105
|
-
/* PAL1 — bullet */
|
|
119
|
+
/* PAL1 — bullet + space backdrop */
|
|
106
120
|
PAL_setColor(16 + 2, 0x00EE); /* bullet yellow */
|
|
121
|
+
PAL_setColor(16 + 4, 0x0600); /* nebula deep blue */
|
|
122
|
+
PAL_setColor(16 + 5, 0x0402); /* nebula violet */
|
|
107
123
|
/* PAL2 — enemy */
|
|
108
124
|
PAL_setColor(32 + 3, 0x000E); /* enemy red */
|
|
109
125
|
|
|
@@ -113,6 +129,20 @@ int main(bool hard) {
|
|
|
113
129
|
VDP_loadTileData(tile_ship, T_SHIP, 1, DMA);
|
|
114
130
|
VDP_loadTileData(tile_bullet, T_BULLET, 1, DMA);
|
|
115
131
|
VDP_loadTileData(tile_enemy, T_ENEMY, 1, DMA);
|
|
132
|
+
VDP_loadTileData(tile_space, T_SPACE, 1, DMA);
|
|
133
|
+
VDP_loadTileData(tile_stars, T_STARS, 1, DMA);
|
|
134
|
+
|
|
135
|
+
/* Fill the far plane (BG_B) with the space backdrop so the screen
|
|
136
|
+
* isn't an empty black void; sprinkle denser star clusters for
|
|
137
|
+
* variety. Sprites (ship/bullets/enemies) always draw above the
|
|
138
|
+
* planes, so the gameplay reads on top of this with no priority
|
|
139
|
+
* juggling. */
|
|
140
|
+
for (u16 cy = 0; cy < 28; cy++)
|
|
141
|
+
for (u16 cx = 0; cx < 40; cx++)
|
|
142
|
+
VDP_setTileMapXY(BG_B,
|
|
143
|
+
TILE_ATTR_FULL(PAL1, 0, 0, 0,
|
|
144
|
+
((cx ^ cy) & 1) ? T_STARS : T_SPACE),
|
|
145
|
+
cx, cy);
|
|
116
146
|
|
|
117
147
|
player.x = 152; player.y = 180; player.alive = TRUE;
|
|
118
148
|
for (u16 i = 0; i < MAX_BULLETS; i++) bullets[i].alive = FALSE;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
/* Game Gear hello-world.
|
|
2
|
-
*
|
|
3
|
-
* P1-B1 scrolls the BG by one pixel per frame.
|
|
1
|
+
/* Game Gear hello-world. Paints the whole 160×144 visible viewport with
|
|
2
|
+
* a blue BG panel, drops a yellow 'H' tile in its centre, enables
|
|
3
|
+
* display. Pressing P1-B1 scrolls the BG by one pixel per frame.
|
|
4
4
|
*
|
|
5
|
-
* Self-contained — inlines the VDP helpers so this single file
|
|
5
|
+
* Self-contained — inlines the VDP helpers so this single file plus the
|
|
6
6
|
* bundled gg_crt0.s are all you need to compile and run. For a more
|
|
7
|
-
* modular multi-file project that pulls in
|
|
7
|
+
* modular multi-file project that pulls in the bundled GG runtime,
|
|
8
8
|
* see `hello_sprite` and `tile_engine`.
|
|
9
9
|
*
|
|
10
10
|
* GG specifics this file demonstrates (read MENTAL_MODEL.md for details):
|
|
11
11
|
* - Visible viewport is 160×144 centered in the 256×192 framebuffer.
|
|
12
12
|
* OAM/name-table coords are in 256×192 space; the visible region
|
|
13
|
-
* starts at hw coord (48, 24). The 'H' goes at name-table row
|
|
14
|
-
* col
|
|
13
|
+
* starts at hw coord (48, 24). The 'H' goes at name-table row 11
|
|
14
|
+
* col 15 = visible center.
|
|
15
15
|
* - CRAM entries are 12-bit BGR (2 bytes each, little-endian), 16 BG
|
|
16
16
|
* colors at $0000-$1F and 16 sprite colors at $0020-$3F.
|
|
17
17
|
* - VDP R6 default is 0xFB → sprite tiles read from $0000 (NOT $2000
|
|
@@ -86,13 +86,17 @@ static void vdp_init(void) {
|
|
|
86
86
|
static const uint8_t palette[32] = {
|
|
87
87
|
0x00, 0x00, /* 0 backdrop (black) */
|
|
88
88
|
0xFF, 0x00, /* 1 yellow */
|
|
89
|
-
0x00,
|
|
89
|
+
0x00, 0x0F, /* 2 blue (panel fill A) */
|
|
90
|
+
0x0F, 0x00, /* 3 red (panel fill B) */
|
|
91
|
+
0x00, 0x00, 0x00, 0x00,
|
|
90
92
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
91
93
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
92
94
|
};
|
|
93
95
|
|
|
94
|
-
/*
|
|
95
|
-
*
|
|
96
|
+
/* Tile 1 = an 'H' glyph. Tile 2 = a solid colour-2 fill used to paint
|
|
97
|
+
* the whole visible viewport so the screen is obviously not blank.
|
|
98
|
+
* Mode 4 stores 4 bytes per scanline (one per bitplane). Plane 0 set →
|
|
99
|
+
* colour index 1; plane 1 set → colour index 2. */
|
|
96
100
|
static const uint8_t tile_h[32] = {
|
|
97
101
|
0x66, 0x00, 0x00, 0x00,
|
|
98
102
|
0x66, 0x00, 0x00, 0x00,
|
|
@@ -103,6 +107,21 @@ static const uint8_t tile_h[32] = {
|
|
|
103
107
|
0x66, 0x00, 0x00, 0x00,
|
|
104
108
|
0x00, 0x00, 0x00, 0x00,
|
|
105
109
|
};
|
|
110
|
+
/* Tile 2 = solid colour 2 (blue). Tile 3 = solid colour 3 (red). The
|
|
111
|
+
* viewport is painted as a blue/red checkerboard so no single colour
|
|
112
|
+
* dominates the screen — a clear "it works" panel, not a flat fill. */
|
|
113
|
+
static const uint8_t tile_fill2[32] = {
|
|
114
|
+
0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
|
115
|
+
0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
|
116
|
+
0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
|
117
|
+
0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
|
118
|
+
};
|
|
119
|
+
static const uint8_t tile_fill3[32] = {
|
|
120
|
+
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
|
121
|
+
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
|
122
|
+
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
|
123
|
+
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
|
124
|
+
};
|
|
106
125
|
|
|
107
126
|
static void load_palette(void) {
|
|
108
127
|
uint8_t i;
|
|
@@ -110,23 +129,42 @@ static void load_palette(void) {
|
|
|
110
129
|
for (i = 0; i < 32; i++) PORT_VDP_DATA = palette[i];
|
|
111
130
|
}
|
|
112
131
|
|
|
113
|
-
static void
|
|
132
|
+
static void load_tiles(void) {
|
|
114
133
|
uint8_t i;
|
|
115
134
|
vdp_set_addr(32, VDP_VRAM_WRITE); /* tile slot 1 = VRAM offset 32 */
|
|
116
135
|
for (i = 0; i < 32; i++) PORT_VDP_DATA = tile_h[i];
|
|
136
|
+
vdp_set_addr(64, VDP_VRAM_WRITE); /* tile slot 2 = VRAM offset 64 */
|
|
137
|
+
for (i = 0; i < 32; i++) PORT_VDP_DATA = tile_fill2[i];
|
|
138
|
+
vdp_set_addr(96, VDP_VRAM_WRITE); /* tile slot 3 = VRAM offset 96 */
|
|
139
|
+
for (i = 0; i < 32; i++) PORT_VDP_DATA = tile_fill3[i];
|
|
117
140
|
}
|
|
118
141
|
|
|
119
|
-
|
|
142
|
+
/* Clear the whole 32×28 name table, then paint the visible 160×144
|
|
143
|
+
* viewport (cols 6..25, rows 3..20) as a solid blue panel inside a red
|
|
144
|
+
* border frame — a clean "it works" screen that is obviously neither
|
|
145
|
+
* blank nor a single flat colour. */
|
|
146
|
+
static void draw_background(void) {
|
|
147
|
+
uint8_t row, col, fill;
|
|
120
148
|
uint16_t i;
|
|
121
149
|
vdp_set_addr(0x3800, VDP_VRAM_WRITE);
|
|
122
150
|
for (i = 0; i < 1792; i++) PORT_VDP_DATA = 0;
|
|
151
|
+
for (row = GG_VIS_ROW_MIN; row <= GG_VIS_ROW_MAX; row++) {
|
|
152
|
+
vdp_set_addr(0x3800 + (row * 32 + GG_VIS_COL_MIN) * 2, VDP_VRAM_WRITE);
|
|
153
|
+
for (col = GG_VIS_COL_MIN; col <= GG_VIS_COL_MAX; col++) {
|
|
154
|
+
if (row == GG_VIS_ROW_MIN || row == GG_VIS_ROW_MAX ||
|
|
155
|
+
col == GG_VIS_COL_MIN || col == GG_VIS_COL_MAX)
|
|
156
|
+
fill = 3; /* red border */
|
|
157
|
+
else
|
|
158
|
+
fill = 2; /* blue interior */
|
|
159
|
+
PORT_VDP_DATA = fill;
|
|
160
|
+
PORT_VDP_DATA = 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
123
163
|
}
|
|
124
164
|
|
|
125
|
-
/* Drop the 'H' at name-table (row
|
|
126
|
-
* sits at name-table cols 6..25 / rows 3..20 — so (12,16) is roughly
|
|
127
|
-
* the visible center. */
|
|
165
|
+
/* Drop the 'H' at name-table (row 11, col 15) — the visible centre. */
|
|
128
166
|
static void place_h(void) {
|
|
129
|
-
vdp_set_addr(0x3800 + (
|
|
167
|
+
vdp_set_addr(0x3800 + (11 * 32 + 15) * 2, VDP_VRAM_WRITE);
|
|
130
168
|
PORT_VDP_DATA = 1;
|
|
131
169
|
PORT_VDP_DATA = 0;
|
|
132
170
|
}
|
|
@@ -140,8 +178,8 @@ void main(void) {
|
|
|
140
178
|
|
|
141
179
|
vdp_init();
|
|
142
180
|
load_palette();
|
|
143
|
-
|
|
144
|
-
|
|
181
|
+
load_tiles();
|
|
182
|
+
draw_background();
|
|
145
183
|
place_h();
|
|
146
184
|
|
|
147
185
|
vdp_write_reg(1, 0xE0); /* display ON, vblank IRQ on, 192-line */
|
|
@@ -52,11 +52,12 @@ extern void gg_sat_upload(void);
|
|
|
52
52
|
|
|
53
53
|
/* GG palette = 32 entries × 2 bytes (4-4-4 BGR LE): low=(g<<4)|r, high=b.
|
|
54
54
|
* gg_load_palette reads 64 bytes; a 32-byte array leaves the sprite palette
|
|
55
|
-
* (entries 16-31) reading garbage = invisible sprites. BG colour 1 =
|
|
56
|
-
*
|
|
55
|
+
* (entries 16-31) reading garbage = invisible sprites. BG colour 1 = light
|
|
56
|
+
* sky blue, 2 = darker sky blue (the sky dither), 3 = mid-grey wall; sprite
|
|
57
|
+
* colour 1 = entry 17 (white player). */
|
|
57
58
|
static const uint8_t palette[64] = {
|
|
58
|
-
/* BG 0-15:
|
|
59
|
-
0x20,0x02,
|
|
59
|
+
/* BG 0-15: 0 = dark navy backdrop, 1 = light sky, 2 = dark sky, 3 = wall grey */
|
|
60
|
+
0x20,0x02, 0xFB,0x0F, 0xC8,0x0C, 0x88,0x08, 0,0, 0,0, 0,0, 0,0,
|
|
60
61
|
0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
61
62
|
/* SPRITE 16-31: 16=transparent, 17=white player */
|
|
62
63
|
0,0, 0xFF,0x0F, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
@@ -64,14 +65,19 @@ static const uint8_t palette[64] = {
|
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
static const uint8_t bg_tiles[32 * 2] = {
|
|
67
|
-
/* T_OPEN —
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
/* T_OPEN — dithered sky: pixels alternate colour 1 (light) / colour 2
|
|
69
|
+
* (dark) so the sky fills the screen but no single colour dominates.
|
|
70
|
+
* plane0 = 0xAA (cols 0,2,4,6 -> colour 1), plane1 = 0x55 (cols 1,3,5,7
|
|
71
|
+
* -> colour 2). */
|
|
72
|
+
0xAA,0x55,0x00,0x00, 0x55,0xAA,0x00,0x00,
|
|
73
|
+
0xAA,0x55,0x00,0x00, 0x55,0xAA,0x00,0x00,
|
|
74
|
+
0xAA,0x55,0x00,0x00, 0x55,0xAA,0x00,0x00,
|
|
75
|
+
0xAA,0x55,0x00,0x00, 0x55,0xAA,0x00,0x00,
|
|
76
|
+
/* T_WALL — solid block in colour 3 (planes 0+1 set) */
|
|
77
|
+
0xFF,0xFF,0x00,0x00, 0xFF,0xFF,0x00,0x00,
|
|
78
|
+
0xFF,0xFF,0x00,0x00, 0xFF,0xFF,0x00,0x00,
|
|
79
|
+
0xFF,0xFF,0x00,0x00, 0xFF,0xFF,0x00,0x00,
|
|
80
|
+
0xFF,0xFF,0x00,0x00, 0xFF,0xFF,0x00,0x00,
|
|
75
81
|
};
|
|
76
82
|
|
|
77
83
|
static const uint8_t player_tile[32] = {
|
|
@@ -25,16 +25,19 @@ extern uint8_t gg_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,13 +89,30 @@ 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
|
|
|
95
|
+
/* GG shows only the centered cols 6..25 / rows 3..20. Place the 6×12 grid
|
|
96
|
+
* at tilemap cols 7..12, rows 4..15 so the whole well sits inside that
|
|
97
|
+
* visible band. */
|
|
82
98
|
static void draw_cell(int8_t col, int8_t row, uint8_t cell) {
|
|
83
99
|
if (row < 0 || row >= ROWS) return;
|
|
84
|
-
|
|
85
|
-
|
|
100
|
+
gg_set_tilemap_cell((uint8_t)(row + 4), (uint8_t)(col + 7), tile_for(cell), 0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* Draw the well: a grey border frame around the 6×12 play field with a dim
|
|
104
|
+
* field interior, so the playfield is clearly visible even when empty. The
|
|
105
|
+
* grid maps cell (col,row) -> tilemap (row+4, col+7) = rows 4..15 cols 7..12.
|
|
106
|
+
* Frame the perimeter at rows 3..16, cols 6..13 — inside the GG viewport. */
|
|
107
|
+
static void draw_well(void) {
|
|
108
|
+
uint8_t r, c;
|
|
109
|
+
for (r = 3; r <= 16; r++) {
|
|
110
|
+
for (c = 6; c <= 13; c++) {
|
|
111
|
+
uint8_t t = T_FIELD;
|
|
112
|
+
if (r == 3 || r == 16 || c == 6 || c == 13) t = T_WALL;
|
|
113
|
+
gg_set_tilemap_cell(r, c, t, 0);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
86
116
|
}
|
|
87
117
|
|
|
88
118
|
static void draw_grid(void) {
|
|
@@ -151,7 +181,7 @@ void main(void) {
|
|
|
151
181
|
|
|
152
182
|
gg_vdp_init();
|
|
153
183
|
gg_load_palette(palette);
|
|
154
|
-
gg_load_tiles(0x0000, bg_tiles, 32 *
|
|
184
|
+
gg_load_tiles(0x0000, bg_tiles, 32 * 6);
|
|
155
185
|
|
|
156
186
|
for (r = 0; r < 24; r++) for (c = 0; c < 32; c++) gg_set_tilemap_cell(r, c, T_BLANK, 0);
|
|
157
187
|
for (r = 0; r < ROWS; r++) for (c = 0; c < COLS; c++) grid[r][c] = 0;
|
|
@@ -159,6 +189,7 @@ void main(void) {
|
|
|
159
189
|
score = 0;
|
|
160
190
|
fall_timer = 0;
|
|
161
191
|
new_piece();
|
|
192
|
+
draw_well();
|
|
162
193
|
draw_grid();
|
|
163
194
|
|
|
164
195
|
sfx_init();
|
|
@@ -18,6 +18,7 @@ extern void gg_vdp_init(void);
|
|
|
18
18
|
extern void gg_vdp_display_on(void);
|
|
19
19
|
extern void gg_load_palette(const uint8_t *palette);
|
|
20
20
|
extern void gg_load_tiles(uint16_t vram_dest, const uint8_t *src, uint16_t byte_count);
|
|
21
|
+
extern void gg_set_tilemap_cell(uint8_t row, uint8_t col, uint8_t tile_idx, uint8_t attr);
|
|
21
22
|
extern void gg_vblank_wait(void);
|
|
22
23
|
extern uint8_t gg_joypad_read(void);
|
|
23
24
|
extern void gg_sprite_init(void);
|
|
@@ -40,17 +41,38 @@ extern void gg_sat_upload(void);
|
|
|
40
41
|
|
|
41
42
|
/* GG palette = 32 entries × 2 bytes (4-4-4 BGR LE): low=(g<<4)|r, high=b.
|
|
42
43
|
* gg_load_palette reads 64 bytes; a 32-byte array leaves the sprite palette
|
|
43
|
-
* (entries 16-31) reading garbage = invisible sprites.
|
|
44
|
-
*
|
|
44
|
+
* (entries 16-31) reading garbage = invisible sprites. BG colour 1 = grass
|
|
45
|
+
* green, BG colour 2 = road grey. Sprite colour 1 = entry 17 (white),
|
|
46
|
+
* colour 2 = entry 18 (red). */
|
|
45
47
|
static const uint8_t palette[64] = {
|
|
46
|
-
/* BG 0-15:
|
|
47
|
-
0x20,0x02,
|
|
48
|
+
/* BG 0-15: 0 = dark navy backdrop, 1 = grass green, 2 = road grey */
|
|
49
|
+
0x20,0x02, 0x60,0x00, 0x66,0x06, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
48
50
|
0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
49
51
|
/* SPRITE 16-31: 16=transparent, 17=white, 18=red */
|
|
50
52
|
0,0, 0xFF,0x0F, 0x0F,0x00, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
51
53
|
0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
52
54
|
};
|
|
53
55
|
|
|
56
|
+
/* Three BG tiles for the track, loaded into the BG tile bank at $0000:
|
|
57
|
+
* tile 0 = blank (all zeros → shows the backdrop colour)
|
|
58
|
+
* tile 1 = solid grass (colour 1)
|
|
59
|
+
* tile 2 = solid road (colour 2) */
|
|
60
|
+
static const uint8_t bg_tiles[96] = {
|
|
61
|
+
/* BG tile 0 = blank */
|
|
62
|
+
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
63
|
+
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
64
|
+
/* BG tile 1 = grass (colour 1 → plane 0 set) */
|
|
65
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
66
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
67
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
68
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
69
|
+
/* BG tile 2 = road (colour 2 → plane 1 set) */
|
|
70
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
71
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
72
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
73
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
74
|
+
};
|
|
75
|
+
|
|
54
76
|
/* Two sprite tiles — player (colour 1) + enemy (colour 2). */
|
|
55
77
|
static const uint8_t tiles[64] = {
|
|
56
78
|
/* Tile 0 = player car (colour 1 → plane 0 set) */
|
|
@@ -65,6 +87,28 @@ static const uint8_t tiles[64] = {
|
|
|
65
87
|
0x00,0x7E,0x00,0x00, 0x00,0x66,0x00,0x00,
|
|
66
88
|
};
|
|
67
89
|
|
|
90
|
+
/* Paint the visible viewport: grey road down the centre lanes, green
|
|
91
|
+
* grass on the shoulders. Visible name-table region is cols 6..25,
|
|
92
|
+
* rows 3..20 (the centered 160×144). BG tile bank is $0000. */
|
|
93
|
+
#define VIS_COL_MIN 6
|
|
94
|
+
#define VIS_COL_MAX 25
|
|
95
|
+
#define VIS_ROW_MIN 3
|
|
96
|
+
#define VIS_ROW_MAX 20
|
|
97
|
+
static void draw_track(void) {
|
|
98
|
+
uint8_t row, col;
|
|
99
|
+
/* Blank the whole 32×28 name table to backdrop (tile 0). */
|
|
100
|
+
for (row = 0; row < 28; row++)
|
|
101
|
+
for (col = 0; col < 32; col++) gg_set_tilemap_cell(row, col, 0, 0);
|
|
102
|
+
/* Paint the visible viewport: road (tile 2) down the central lanes,
|
|
103
|
+
* grass (tile 1) on the shoulders. */
|
|
104
|
+
for (row = VIS_ROW_MIN; row <= VIS_ROW_MAX; row++) {
|
|
105
|
+
for (col = VIS_COL_MIN; col <= VIS_COL_MAX; col++) {
|
|
106
|
+
uint8_t road = (col >= VIS_COL_MIN + 4 && col <= VIS_COL_MAX - 4);
|
|
107
|
+
gg_set_tilemap_cell(row, col, road ? 2 : 1, 0);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
68
112
|
typedef struct { uint8_t x, y, alive; } Car;
|
|
69
113
|
|
|
70
114
|
static Car player;
|
|
@@ -110,7 +154,9 @@ void main(void) {
|
|
|
110
154
|
uint8_t i;
|
|
111
155
|
gg_vdp_init();
|
|
112
156
|
gg_load_palette(palette);
|
|
113
|
-
gg_load_tiles(
|
|
157
|
+
gg_load_tiles(0x0000, bg_tiles, 96); /* BG tiles → BG bank $0000 */
|
|
158
|
+
gg_load_tiles(0x2000, tiles, 64); /* sprite tiles → sprite bank $2000 */
|
|
159
|
+
draw_track();
|
|
114
160
|
gg_sprite_init();
|
|
115
161
|
sfx_init();
|
|
116
162
|
gg_vdp_display_on();
|
|
@@ -15,6 +15,7 @@ extern void gg_vdp_display_on(void);
|
|
|
15
15
|
extern void gg_vdp_set_addr(uint16_t addr, uint8_t prefix);
|
|
16
16
|
extern void gg_load_palette(const uint8_t *palette);
|
|
17
17
|
extern void gg_load_tiles(uint16_t vram_dest, const uint8_t *src, uint16_t byte_count);
|
|
18
|
+
extern void gg_set_tilemap_cell(uint8_t row, uint8_t col, uint8_t tile_idx, uint8_t attr);
|
|
18
19
|
extern void gg_vblank_wait(void);
|
|
19
20
|
extern uint8_t gg_joypad_read(void);
|
|
20
21
|
extern void gg_sprite_init(void);
|
|
@@ -52,14 +53,55 @@ extern void gg_sat_upload(void);
|
|
|
52
53
|
* array left the sprite palette (entries 16-31) reading past the array = garbage
|
|
53
54
|
* = invisible sprites.) */
|
|
54
55
|
static const uint8_t palette[64] = {
|
|
55
|
-
/* BG 0-15:
|
|
56
|
-
|
|
56
|
+
/* BG 0-15: 0 = backdrop, 1 = deep space blue, 2 = lighter space blue,
|
|
57
|
+
* 3 = star white. */
|
|
58
|
+
0x20,0x02, 0x30,0x04, 0x80,0x08, 0xFF,0x0F, 0,0, 0,0, 0,0, 0,0,
|
|
57
59
|
0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
58
60
|
/* SPRITE 16-31: 16=transparent, 17=white, 18=yellow, 19=red */
|
|
59
61
|
0,0, 0xFF,0x0F, 0xFF,0x00, 0x0F,0x00, 0,0, 0,0, 0,0, 0,0,
|
|
60
62
|
0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
61
63
|
};
|
|
62
64
|
|
|
65
|
+
/* Three BG tiles for the starfield, loaded into the BG tile bank at
|
|
66
|
+
* $0000:
|
|
67
|
+
* tile 0 = deep space (solid colour 1)
|
|
68
|
+
* tile 1 = lighter space band (solid colour 2)
|
|
69
|
+
* tile 2 = space with a star (mostly colour 1, one colour-3 pixel) */
|
|
70
|
+
static const uint8_t bg_tiles[96] = {
|
|
71
|
+
/* tile 0 = deep space (colour 1 → plane 0 set) */
|
|
72
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
73
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
74
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
75
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
76
|
+
/* tile 1 = lighter band (colour 2 → plane 1 set) */
|
|
77
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
78
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
79
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
80
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
81
|
+
/* tile 2 = deep space + a star: row 3 col 3 = colour 3 (planes 0+1),
|
|
82
|
+
* everything else colour 1 (plane 0). */
|
|
83
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
84
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x10,0x00,0x00,
|
|
85
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
86
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/* Paint the visible viewport with a banded starfield so the screen is
|
|
90
|
+
* clearly space, not a flat backdrop. Visible name-table region is cols
|
|
91
|
+
* 6..25, rows 3..20. BG tile bank is $0000. */
|
|
92
|
+
static void draw_starfield(void) {
|
|
93
|
+
uint8_t row, col;
|
|
94
|
+
for (row = 0; row < 28; row++)
|
|
95
|
+
for (col = 0; col < 32; col++) gg_set_tilemap_cell(row, col, 0, 0);
|
|
96
|
+
for (row = 3; row <= 20; row++) {
|
|
97
|
+
for (col = 6; col <= 25; col++) {
|
|
98
|
+
uint8_t t = (row & 2) ? 1 : 0; /* alternating depth bands */
|
|
99
|
+
if (((row * 7 + col * 5) & 7) == 0) t = 2; /* sparse stars */
|
|
100
|
+
gg_set_tilemap_cell(row, col, t, 0);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
63
105
|
static const uint8_t sprite_tiles[32 * 3] = {
|
|
64
106
|
/* T_SHIP — diamond using colour 1 (white) */
|
|
65
107
|
0x18,0x00,0x00,0x00, 0x3C,0x00,0x00,0x00,
|
|
@@ -121,7 +163,9 @@ void main(void) {
|
|
|
121
163
|
|
|
122
164
|
gg_vdp_init();
|
|
123
165
|
gg_load_palette(palette);
|
|
124
|
-
gg_load_tiles(
|
|
166
|
+
gg_load_tiles(0x0000, bg_tiles, 96); /* BG tiles → BG bank $0000 */
|
|
167
|
+
gg_load_tiles(0x2000, sprite_tiles, 32 * 3); /* sprite tiles → $2000 */
|
|
168
|
+
draw_starfield();
|
|
125
169
|
|
|
126
170
|
/* Start the ship centered, near the bottom of the VISIBLE region. */
|
|
127
171
|
player.x = (uint8_t)(VIS_X0 + VIS_W / 2 - 4); player.y = (uint8_t)(VIS_Y1 - 16); player.alive = 1;
|