romdevtools 0.16.0 → 0.22.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 +75 -16
- package/CHANGELOG.md +316 -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/hello_sprite.c +48 -4
- package/examples/atari7800/templates/music_demo.c +47 -2
- 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/c64/templates/tile_engine.c +77 -27
- package/examples/gb/templates/default.c +110 -16
- package/examples/gb/templates/hello_sprite.c +15 -6
- package/examples/gb/templates/music_demo.c +36 -0
- package/examples/gb/templates/platformer.c +28 -6
- package/examples/gb/templates/puzzle.c +35 -4
- package/examples/gb/templates/racing.c +75 -10
- package/examples/gb/templates/shmup.c +41 -3
- package/examples/gb/templates/sports.c +51 -3
- package/examples/gb/templates/tile_engine.c +3 -2
- package/examples/gba/templates/gba_hello.c +29 -11
- package/examples/gba/templates/maxmod_demo.c +36 -2
- package/examples/gba/templates/platformer.c +3 -1
- 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/gba/templates/tonc_hello_sprite.c +35 -1
- package/examples/gbc/templates/default.c +103 -26
- package/examples/gbc/templates/hello_sprite.c +12 -3
- package/examples/gbc/templates/music_demo.c +56 -12
- package/examples/gbc/templates/platformer.c +28 -6
- package/examples/gbc/templates/puzzle.c +35 -4
- package/examples/gbc/templates/racing.c +88 -21
- package/examples/gbc/templates/shmup.c +37 -3
- package/examples/gbc/templates/sports.c +48 -3
- package/examples/gbc/templates/tile_engine.c +3 -2
- package/examples/genesis/main.s +53 -1
- package/examples/genesis/templates/hello_sprite.c +25 -3
- 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/genesis/templates/shmup_2p.c +31 -0
- package/examples/genesis/templates/xgm2_demo.c +20 -0
- package/examples/gg/templates/default.c +56 -18
- package/examples/gg/templates/hello_sprite.c +25 -2
- package/examples/gg/templates/music_demo.c +24 -2
- package/examples/gg/templates/platformer.c +18 -12
- package/examples/gg/templates/puzzle.c +38 -7
- package/examples/gg/templates/racing.c +58 -9
- package/examples/gg/templates/shmup.c +47 -3
- package/examples/gg/templates/sports.c +57 -16
- package/examples/gg/templates/tile_engine.c +12 -6
- package/examples/lynx/templates/default.c +39 -8
- package/examples/lynx/templates/hello_sprite.c +15 -1
- package/examples/lynx/templates/music_demo.c +13 -1
- 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/hello_sprite.c +35 -0
- package/examples/nes/templates/music_demo.c +40 -0
- 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/catch_game/main.c +22 -3
- package/examples/pce/music_sfx/main.c +28 -1
- 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/pce/sprite_move/main.c +7 -2
- package/examples/sms/main.c +35 -6
- package/examples/sms/templates/hello_sprite.c +29 -3
- package/examples/sms/templates/music_demo.c +18 -4
- 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/shmup_2p.c +24 -1
- package/examples/sms/templates/sports.c +47 -4
- package/examples/snes/main.asm +108 -17
- package/examples/snes/templates/c-hello-data.asm +23 -0
- package/examples/snes/templates/c-hello.c +18 -1
- package/examples/snes/templates/default.c +50 -28
- package/examples/snes/templates/hello_sprite-data.asm +23 -0
- package/examples/snes/templates/hello_sprite.c +17 -1
- package/examples/snes/templates/music_demo-data.asm +23 -0
- package/examples/snes/templates/music_demo.c +22 -4
- package/examples/snes/templates/platformer-data.asm +22 -0
- package/examples/snes/templates/platformer.c +20 -2
- package/examples/snes/templates/puzzle-data.asm +22 -0
- package/examples/snes/templates/puzzle.c +21 -2
- 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/cheats/gamegenie.js +0 -1
- package/src/cli/smoke.js +1 -3
- 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 +191 -16
- package/src/host/callbacks.js +9 -1
- package/src/host/chafa-render.js +2 -0
- package/src/host/dsp-state.js +2 -2
- package/src/host/gpgx-state.js +4 -0
- package/src/host/types.js +15 -8
- package/src/http/routes.js +1 -1
- package/src/http/tool-registry.js +26 -1
- package/src/mcp/server.js +1 -1
- package/src/mcp/state.js +36 -0
- package/src/mcp/tools/address-to-symbol.js +0 -1
- package/src/mcp/tools/art-loaders.js +1 -1
- package/src/mcp/tools/cart-parts.js +75 -4
- package/src/mcp/tools/classify-region.js +1 -1
- package/src/mcp/tools/diff-roms.js +1 -1
- package/src/mcp/tools/disasm-rebuild.js +507 -0
- package/src/mcp/tools/disasm.js +97 -9
- package/src/mcp/tools/find-references.js +1 -2
- package/src/mcp/tools/font-map.js +1 -1
- package/src/mcp/tools/frame.js +168 -3
- package/src/mcp/tools/index.js +0 -49
- package/src/mcp/tools/input-layout.js +0 -1
- package/src/mcp/tools/input.js +33 -3
- package/src/mcp/tools/lifecycle.js +18 -4
- package/src/mcp/tools/lospec.js +0 -19
- package/src/mcp/tools/platform-docs.js +1 -1
- package/src/mcp/tools/platform-tools.js +4 -4
- package/src/mcp/tools/project.js +54 -11
- package/src/mcp/tools/reinject.js +0 -1
- package/src/mcp/tools/rom-id.js +2 -2
- package/src/mcp/tools/snippets.js +2 -2
- package/src/mcp/tools/sprite-pipeline.js +1 -2
- package/src/mcp/tools/state.js +201 -14
- package/src/mcp/tools/tile-inspect.js +1 -1
- package/src/mcp/tools/toolchain.js +105 -12
- package/src/mcp/tools/watch-memory.js +137 -16
- package/src/platforms/_guides/ROMHACKING_PLAYBOOK.md +34 -0
- package/src/platforms/atari2600/TROUBLESHOOTING.md +6 -0
- package/src/platforms/atari7800/TROUBLESHOOTING.md +6 -0
- package/src/platforms/c64/MENTAL_MODEL.md +45 -1
- package/src/platforms/c64/TROUBLESHOOTING.md +6 -0
- package/src/platforms/c64/d64.js +280 -0
- package/src/platforms/c64/sid.js +0 -2
- package/src/platforms/common/metasprite-adapters.js +1 -1
- package/src/platforms/common/metasprite-codegen.js +3 -3
- package/src/platforms/common/registers.js +5 -3
- package/src/platforms/gb/MENTAL_MODEL.md +10 -0
- package/src/platforms/gb/TROUBLESHOOTING.md +6 -0
- package/src/platforms/gb/lib/c/gb_runtime.c +4 -4
- package/src/platforms/gba/TROUBLESHOOTING.md +6 -0
- package/src/platforms/gbc/TROUBLESHOOTING.md +6 -0
- package/src/platforms/gbc/lib/c/gb_runtime.c +4 -4
- package/src/platforms/genesis/TROUBLESHOOTING.md +6 -0
- package/src/platforms/gg/TROUBLESHOOTING.md +6 -0
- package/src/platforms/lynx/TROUBLESHOOTING.md +6 -0
- package/src/platforms/msx/MENTAL_MODEL.md +10 -6
- package/src/platforms/msx/TROUBLESHOOTING.md +6 -0
- package/src/platforms/nes/MENTAL_MODEL.md +63 -2
- package/src/platforms/nes/TROUBLESHOOTING.md +6 -0
- package/src/platforms/nes/image-to-tilemap.js +3 -0
- package/src/platforms/nes/lib/asm/famitone2.s +5 -1
- package/src/platforms/pce/MENTAL_MODEL.md +9 -4
- package/src/platforms/pce/TROUBLESHOOTING.md +6 -0
- package/src/platforms/pce/lib/c/pce_video.c +1 -1
- package/src/platforms/sms/TROUBLESHOOTING.md +6 -0
- package/src/platforms/snes/TROUBLESHOOTING.md +6 -0
- package/src/platforms/snes/brr.js +0 -2
- package/src/playtest/playtest.js +0 -7
- package/src/rom-id/identifier.js +15 -0
- package/src/toolchains/asar/asar.js +0 -9
- package/src/toolchains/assemble-snippet.js +30 -12
- package/src/toolchains/cc65/ines.js +145 -0
- package/src/toolchains/cc65/presets/nes/chr-ram-runtime.cfg +14 -1
- 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 -3
- package/src/toolchains/common/sdk-cache.js +1 -1
- package/src/toolchains/genesis-c/genesis-c.js +5 -3
- package/src/toolchains/index.js +27 -3
- package/src/toolchains/parse-errors.js +78 -1
- package/src/toolchains/sdcc/preflight-lint.js +5 -1
- package/src/toolchains/sdcc/sdcc.js +1 -1
- package/src/toolchains/sjasm/sjasm.js +1 -1
- package/src/toolchains/snes-c/snes-c.js +2 -2
- package/src/toolchains/vasm68k/vasm68k.js +2 -4
- package/src/toolchains/wladx/wladx.js +1 -1
|
@@ -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;
|
|
@@ -11,6 +11,7 @@ extern void gg_vdp_init(void);
|
|
|
11
11
|
extern void gg_vdp_display_on(void);
|
|
12
12
|
extern void gg_load_palette(const uint8_t *palette);
|
|
13
13
|
extern void gg_load_tiles(uint16_t vram_dest, const uint8_t *src, uint16_t byte_count);
|
|
14
|
+
extern void gg_set_tilemap_cell(uint8_t row, uint8_t col, uint8_t tile_idx, uint8_t attr);
|
|
14
15
|
extern void gg_vblank_wait(void);
|
|
15
16
|
extern uint8_t gg_joypad_read(void);
|
|
16
17
|
extern void gg_sprite_init(void);
|
|
@@ -29,16 +30,19 @@ extern void gg_sat_upload(void);
|
|
|
29
30
|
#define COURT_BOT VIS_Y1
|
|
30
31
|
#define PADDLE_H 24
|
|
31
32
|
#define BALL_SIZE 8
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
/* Explicit (uint8_t) casts: these fit a byte but SDCC warns (158) on the
|
|
34
|
+
* implicit int->uint8_t narrowing when the computed macro is passed to the
|
|
35
|
+
* uint8_t x/y args of gg_sprite_set. */
|
|
36
|
+
#define PADDLE_X1 ((uint8_t)(VIS_X0 + 8)) /* near the visible left edge */
|
|
37
|
+
#define PADDLE_X2 ((uint8_t)(VIS_X1 - 16)) /* near the visible right edge */
|
|
34
38
|
|
|
35
39
|
/* GG palette = 32 entries × 2 bytes (4-4-4 BGR LE): low=(g<<4)|r, high=b.
|
|
36
40
|
* gg_load_palette reads 64 bytes; a 32-byte array leaves the sprite palette
|
|
37
41
|
* (entries 16-31) reading garbage = invisible sprites. Sprite colour 1 = entry
|
|
38
42
|
* 17 (white). */
|
|
39
43
|
static const uint8_t palette[64] = {
|
|
40
|
-
/* BG 0-15:
|
|
41
|
-
0x20,0x02,
|
|
44
|
+
/* BG 0-15: 0 = dark navy backdrop, 1 = court green, 2 = court line white */
|
|
45
|
+
0x20,0x02, 0x60,0x00, 0xFF,0x0F, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
42
46
|
0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
43
47
|
/* SPRITE 16-31: 16=transparent, 17=white */
|
|
44
48
|
0,0, 0xFF,0x0F, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
@@ -52,6 +56,42 @@ static const uint8_t tile_solid[32] = {
|
|
|
52
56
|
0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
|
53
57
|
};
|
|
54
58
|
|
|
59
|
+
/* Three BG tiles for the court, loaded into the BG tile bank at $0000:
|
|
60
|
+
* tile 0 = court green (colour 1), tile 1 = court line / border
|
|
61
|
+
* (colour 2 = white), tile 2 = dashed net (colour 2 stripe on green). */
|
|
62
|
+
static const uint8_t bg_tiles[96] = {
|
|
63
|
+
/* tile 0 = court green (colour 1 -> plane 0 set) */
|
|
64
|
+
0xFF,0x00,0x00,0x00, 0xFF,0x00,0x00,0x00,
|
|
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
|
+
/* tile 1 = court line / border (colour 2 -> plane 1 set) */
|
|
69
|
+
0x00,0xFF,0x00,0x00, 0x00,0xFF,0x00,0x00,
|
|
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
|
+
/* tile 2 = net: centre column colour 2, rest colour 1 (green) */
|
|
74
|
+
0xFF,0x18,0x00,0x00, 0xFF,0x18,0x00,0x00,
|
|
75
|
+
0xFF,0x18,0x00,0x00, 0xFF,0x18,0x00,0x00,
|
|
76
|
+
0xFF,0x18,0x00,0x00, 0xFF,0x18,0x00,0x00,
|
|
77
|
+
0xFF,0x18,0x00,0x00, 0xFF,0x18,0x00,0x00,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/* Paint the court inside the GG visible region (cols 6..25, rows 3..20):
|
|
81
|
+
* green field, white border lines around the perimeter, dashed net down
|
|
82
|
+
* the centre column. BG tile bank is $0000. */
|
|
83
|
+
static void draw_court(void) {
|
|
84
|
+
uint8_t row, col;
|
|
85
|
+
for (row = 3; row <= 20; row++) {
|
|
86
|
+
for (col = 6; col <= 25; col++) {
|
|
87
|
+
uint8_t t = 0; /* green field */
|
|
88
|
+
if (row == 3 || row == 20 || col == 6 || col == 25) t = 1; /* border */
|
|
89
|
+
else if (col == 15 && (row & 1)) t = 2; /* dashed centre net */
|
|
90
|
+
gg_set_tilemap_cell(row, col, t, 0);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
55
95
|
static int16_t p1y, p2y, bx, by;
|
|
56
96
|
static int8_t bdx, bdy;
|
|
57
97
|
static uint8_t score_p1, score_p2;
|
|
@@ -76,7 +116,13 @@ void main(void) {
|
|
|
76
116
|
uint8_t i;
|
|
77
117
|
gg_vdp_init();
|
|
78
118
|
gg_load_palette(palette);
|
|
79
|
-
gg_load_tiles(
|
|
119
|
+
gg_load_tiles(0x0000, bg_tiles, 96); /* BG court tiles -> BG bank $0000 */
|
|
120
|
+
gg_load_tiles(0x2000, tile_solid, 32); /* paddle/ball sprite tile -> $2000 */
|
|
121
|
+
{
|
|
122
|
+
uint8_t r, c;
|
|
123
|
+
for (r = 0; r < 28; r++) for (c = 0; c < 32; c++) gg_set_tilemap_cell(r, c, 0, 0);
|
|
124
|
+
}
|
|
125
|
+
draw_court();
|
|
80
126
|
gg_sprite_init();
|
|
81
127
|
sfx_init();
|
|
82
128
|
gg_vdp_display_on();
|
|
@@ -84,8 +130,9 @@ void main(void) {
|
|
|
84
130
|
reset_match();
|
|
85
131
|
|
|
86
132
|
do {
|
|
87
|
-
uint8_t p1
|
|
133
|
+
uint8_t p1;
|
|
88
134
|
uint8_t slot;
|
|
135
|
+
int16_t target;
|
|
89
136
|
gg_vblank_wait();
|
|
90
137
|
sfx_update();
|
|
91
138
|
|
|
@@ -102,20 +149,14 @@ void main(void) {
|
|
|
102
149
|
gg_sat_upload();
|
|
103
150
|
|
|
104
151
|
p1 = gg_joypad_read();
|
|
105
|
-
p2 = 0; /* GG has only one controller — always AI for the right paddle */
|
|
106
152
|
|
|
107
153
|
if ((p1 & JOY_UP) && p1y > COURT_TOP) p1y -= 2;
|
|
108
154
|
if ((p1 & JOY_DOWN) && p1y < COURT_BOT - PADDLE_H) p1y += 2;
|
|
109
155
|
|
|
110
|
-
/*
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
} else {
|
|
115
|
-
int16_t target = by - PADDLE_H / 2;
|
|
116
|
-
if (p2y < target && p2y < COURT_BOT - PADDLE_H) p2y += 1;
|
|
117
|
-
else if (p2y > target && p2y > COURT_TOP) p2y -= 1;
|
|
118
|
-
}
|
|
156
|
+
/* GG has only one controller — the right paddle is always AI. */
|
|
157
|
+
target = by - PADDLE_H / 2;
|
|
158
|
+
if (p2y < target && p2y < COURT_BOT - PADDLE_H) p2y += 1;
|
|
159
|
+
else if (p2y > target && p2y > COURT_TOP) p2y -= 1;
|
|
119
160
|
|
|
120
161
|
if (serve_timer > 0) {
|
|
121
162
|
serve_timer--;
|
|
@@ -46,8 +46,9 @@ extern void gg_sat_upload(void);
|
|
|
46
46
|
* (entries 16-31) reading garbage = invisible sprites. BG colour 1 = entry 1
|
|
47
47
|
* (dark grey wall); sprite colour 1 = entry 17 (white player). */
|
|
48
48
|
static const uint8_t palette[64] = {
|
|
49
|
-
/* BG 0-15:
|
|
50
|
-
|
|
49
|
+
/* BG 0-15: 0 = dark navy backdrop, 1 = grey wall, 2 = teal floor,
|
|
50
|
+
* 3 = blue floor (the two floor-dither tones). */
|
|
51
|
+
0x20,0x02, 0x66,0x06, 0xC8,0x08, 0x80,0x0C, 0,0, 0,0, 0,0, 0,0,
|
|
51
52
|
0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
52
53
|
/* SPRITE 16-31: 16=transparent, 17=white player */
|
|
53
54
|
0,0, 0xFF,0x0F, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
|
|
@@ -55,10 +56,15 @@ static const uint8_t palette[64] = {
|
|
|
55
56
|
};
|
|
56
57
|
|
|
57
58
|
static const uint8_t bg_tiles[32 * 2] = {
|
|
58
|
-
/* T_OPEN —
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
/* T_OPEN — dithered floor: plane1=0xFF (colour-2 bit always on), plane0
|
|
60
|
+
* alternates 0xAA/0x55 so pixels flip between colour 2 (teal) and colour 3
|
|
61
|
+
* (blue). The open floor now fills with TWO tones instead of the backdrop,
|
|
62
|
+
* so the screen never reads as a single flat colour. */
|
|
63
|
+
0xAA,0xFF,0x00,0x00, 0x55,0xFF,0x00,0x00,
|
|
64
|
+
0xAA,0xFF,0x00,0x00, 0x55,0xFF,0x00,0x00,
|
|
65
|
+
0xAA,0xFF,0x00,0x00, 0x55,0xFF,0x00,0x00,
|
|
66
|
+
0xAA,0xFF,0x00,0x00, 0x55,0xFF,0x00,0x00,
|
|
67
|
+
/* T_WALL — bordered block (colour 1, grey) */
|
|
62
68
|
0xFF,0x00,0x00,0x00, 0x81,0x00,0x00,0x00,
|
|
63
69
|
0x81,0x00,0x00,0x00, 0x81,0x00,0x00,0x00,
|
|
64
70
|
0x81,0x00,0x00,0x00, 0x81,0x00,0x00,0x00,
|
|
@@ -15,9 +15,12 @@
|
|
|
15
15
|
#include <lynx.h>
|
|
16
16
|
|
|
17
17
|
void main(void) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
/* Cycle the centre square through warm/bright shades only — NOT the
|
|
19
|
+
* blues, which would blend into the blue background and make the
|
|
20
|
+
* screen read as "almost one colour". */
|
|
21
|
+
static const unsigned char palette[6] = {
|
|
22
|
+
COLOR_RED, COLOR_YELLOW, COLOR_GREEN,
|
|
23
|
+
COLOR_WHITE, COLOR_LIGHTGREEN, COLOR_PURPLE,
|
|
21
24
|
};
|
|
22
25
|
unsigned char shade = 0;
|
|
23
26
|
unsigned int frame = 0;
|
|
@@ -26,16 +29,44 @@ void main(void) {
|
|
|
26
29
|
tgi_init();
|
|
27
30
|
|
|
28
31
|
for (;;) {
|
|
29
|
-
|
|
32
|
+
/* CANONICAL LYNX FRAME LOOP — full redraw every frame, in this order:
|
|
33
|
+
* 1. WAIT for Suzy's blitter to finish the previous frame. Drawing
|
|
34
|
+
* while it's mid-flight loses the frame → black screen. This is
|
|
35
|
+
* the #1 "Lynx stays blank" trap.
|
|
36
|
+
* 2. CLEAR with a full-screen tgi_bar in the background colour, NOT
|
|
37
|
+
* tgi_clear() — which leaves the back page stale in this
|
|
38
|
+
* toolchain+emulator path (the other genre scaffolds all do the
|
|
39
|
+
* same; see shmup.c's LYNX-1 note).
|
|
40
|
+
* 3. DRAW everything.
|
|
41
|
+
* 4. tgi_updatedisplay() to push the frame. */
|
|
42
|
+
while (tgi_busy()) { }
|
|
43
|
+
|
|
44
|
+
/* Blue field so the screen is obviously not blank. */
|
|
45
|
+
tgi_setcolor(COLOR_BLUE);
|
|
46
|
+
tgi_bar(0, 0, tgi_getmaxx(), tgi_getmaxy());
|
|
47
|
+
|
|
48
|
+
/* A fixed green frame around the centre — always a distinct colour,
|
|
49
|
+
* so the screen never collapses to a single shade even while the
|
|
50
|
+
* inner square is cycling. */
|
|
51
|
+
tgi_setcolor(COLOR_GREEN);
|
|
52
|
+
tgi_bar(50, 30, 110, 72);
|
|
53
|
+
|
|
54
|
+
/* Colour-cycling square in the centre. */
|
|
30
55
|
tgi_setcolor(palette[shade]);
|
|
31
|
-
tgi_bar(
|
|
56
|
+
tgi_bar(60, 36, 100, 66);
|
|
57
|
+
|
|
58
|
+
/* Greeting on top. The tgi font is 8 px wide; "BUILT WITH ROMDEV"
|
|
59
|
+
* is 17 chars = 136 px, so start near the left edge to stay inside
|
|
60
|
+
* the 160-px-wide screen. */
|
|
32
61
|
tgi_setcolor(COLOR_WHITE);
|
|
33
|
-
tgi_outtextxy(
|
|
62
|
+
tgi_outtextxy(40, 14, "HELLO LYNX");
|
|
63
|
+
tgi_outtextxy(12, 86, "BUILT WITH ROMDEV");
|
|
34
64
|
tgi_updatedisplay();
|
|
35
65
|
|
|
36
66
|
frame++;
|
|
37
|
-
if ((frame
|
|
38
|
-
shade
|
|
67
|
+
if ((frame % 24) == 0) { /* advance the inner square */
|
|
68
|
+
shade++;
|
|
69
|
+
if (shade >= 6) shade = 0;
|
|
39
70
|
}
|
|
40
71
|
}
|
|
41
72
|
}
|
|
@@ -22,7 +22,21 @@ void main(void) {
|
|
|
22
22
|
sfx_tone(0, 80, 12); /* boot chime */
|
|
23
23
|
|
|
24
24
|
for (;;) {
|
|
25
|
-
|
|
25
|
+
/* CANONICAL LYNX FRAME LOOP — full redraw every frame:
|
|
26
|
+
* 1. WAIT for Suzy's blitter to finish the previous frame. Drawing
|
|
27
|
+
* while it's mid-flight loses the frame → black screen. This is
|
|
28
|
+
* the #1 "Lynx stays blank" trap (tgi_clear alone leaves the back
|
|
29
|
+
* page stale on this core, so we clear with a full-screen bar). */
|
|
30
|
+
while (tgi_busy()) { }
|
|
31
|
+
|
|
32
|
+
/* Blue field so the screen is obviously not blank... */
|
|
33
|
+
tgi_setcolor(COLOR_BLUE);
|
|
34
|
+
tgi_bar(0, 0, tgi_getmaxx(), tgi_getmaxy());
|
|
35
|
+
/* ...with a green band so no single colour fills the whole screen. */
|
|
36
|
+
tgi_setcolor(COLOR_GREEN);
|
|
37
|
+
tgi_bar(0, 60, tgi_getmaxx(), 102);
|
|
38
|
+
|
|
39
|
+
/* The joystick-driven player square on top. */
|
|
26
40
|
tgi_setcolor(COLOR_YELLOW);
|
|
27
41
|
tgi_bar(x, y, x + 8, y + 8);
|
|
28
42
|
tgi_setcolor(COLOR_WHITE);
|
|
@@ -26,7 +26,19 @@ void main(void) {
|
|
|
26
26
|
lynx_snd_play(0, (unsigned char *)demo_music);
|
|
27
27
|
|
|
28
28
|
for (;;) {
|
|
29
|
-
|
|
29
|
+
/* CANONICAL LYNX FRAME LOOP — full redraw every frame: WAIT for Suzy's
|
|
30
|
+
* blitter (drawing mid-flight loses the frame → black), then clear with
|
|
31
|
+
* a full-screen bar (tgi_clear leaves the back page stale on this core)
|
|
32
|
+
* before drawing. The #1 "Lynx stays blank" trap. */
|
|
33
|
+
while (tgi_busy()) { }
|
|
34
|
+
|
|
35
|
+
/* Two colour bands so the backdrop is obviously not blank and no single
|
|
36
|
+
* colour fills the whole screen (a flat fill still reads as "blank"). */
|
|
37
|
+
tgi_setcolor(COLOR_BLUE);
|
|
38
|
+
tgi_bar(0, 0, tgi_getmaxx(), tgi_getmaxy());
|
|
39
|
+
tgi_setcolor(COLOR_PURPLE);
|
|
40
|
+
tgi_bar(0, 56, tgi_getmaxx(), 102);
|
|
41
|
+
|
|
30
42
|
tgi_setcolor(COLOR_WHITE);
|
|
31
43
|
tgi_outtextxy(20, 20, "LYNX MUSIC DEMO");
|
|
32
44
|
tgi_setcolor(COLOR_YELLOW);
|
|
@@ -98,8 +98,35 @@ void main(void) {
|
|
|
98
98
|
* — drawing while the blitter is mid-flight loses the frame → black.
|
|
99
99
|
* (Copied from the shmup scaffold, the LYNX-1 fix.) */
|
|
100
100
|
while (tgi_busy()) { }
|
|
101
|
+
|
|
102
|
+
/* ── Background scene (drawn every frame). Without it the playfield is
|
|
103
|
+
* a near-flat single colour and the render-health audit flags the
|
|
104
|
+
* screen as blank. A framed "well" in the centre with lit side panels
|
|
105
|
+
* keeps several distinct colours well under the threshold:
|
|
106
|
+
* - blue cabinet backdrop
|
|
107
|
+
* - dark-grey side panels flanking the well
|
|
108
|
+
* - black well interior so the falling blocks read clearly
|
|
109
|
+
* - light-grey well frame + a faint grid texture behind the cells. */
|
|
110
|
+
tgi_setcolor(COLOR_BLUE);
|
|
111
|
+
tgi_bar(0, 0, tgi_getmaxx(), tgi_getmaxy()); /* cabinet backdrop */
|
|
112
|
+
tgi_setcolor(COLOR_DARKGREY);
|
|
113
|
+
tgi_bar(0, 0, GRID_X - 5, 101); /* left side panel */
|
|
114
|
+
tgi_bar(GRID_X + COLS * CELL_PX + 4, 0, 159, 101); /* right side panel */
|
|
101
115
|
tgi_setcolor(COLOR_BLACK);
|
|
102
|
-
tgi_bar(
|
|
116
|
+
tgi_bar(GRID_X - 2, GRID_Y - 2,
|
|
117
|
+
GRID_X + COLS * CELL_PX + 1, GRID_Y + ROWS * CELL_PX + 1); /* well */
|
|
118
|
+
/* faint grid texture so the empty well is never one flat colour */
|
|
119
|
+
tgi_setcolor(COLOR_DARKGREY);
|
|
120
|
+
for (r = 0; r <= ROWS; r++)
|
|
121
|
+
tgi_line(GRID_X, GRID_Y + r * CELL_PX, GRID_X + COLS * CELL_PX - 1, GRID_Y + r * CELL_PX);
|
|
122
|
+
for (c = 0; c <= COLS; c++)
|
|
123
|
+
tgi_line(GRID_X + c * CELL_PX, GRID_Y, GRID_X + c * CELL_PX, GRID_Y + ROWS * CELL_PX - 1);
|
|
124
|
+
/* well frame */
|
|
125
|
+
tgi_setcolor(COLOR_LIGHTGREY);
|
|
126
|
+
tgi_line(GRID_X - 2, GRID_Y - 2, GRID_X - 2, GRID_Y + ROWS * CELL_PX + 1);
|
|
127
|
+
tgi_line(GRID_X + COLS * CELL_PX + 1, GRID_Y - 2, GRID_X + COLS * CELL_PX + 1, GRID_Y + ROWS * CELL_PX + 1);
|
|
128
|
+
tgi_line(GRID_X - 2, GRID_Y + ROWS * CELL_PX + 1, GRID_X + COLS * CELL_PX + 1, GRID_Y + ROWS * CELL_PX + 1);
|
|
129
|
+
|
|
103
130
|
/* grid */
|
|
104
131
|
for (r = 0; r < ROWS; r++) for (c = 0; c < COLS; c++) {
|
|
105
132
|
if (grid[r][c] != 0) {
|
|
@@ -23,6 +23,8 @@ void main(void) {
|
|
|
23
23
|
uint8_t game_over = 0;
|
|
24
24
|
uint8_t joy, i;
|
|
25
25
|
uint32_t rng = 1;
|
|
26
|
+
uint8_t scroll = 0; /* animates the road dashes so the track moves */
|
|
27
|
+
int16_t y;
|
|
26
28
|
|
|
27
29
|
tgi_install(&lynx_160_102_16_tgi);
|
|
28
30
|
tgi_init();
|
|
@@ -36,14 +38,37 @@ void main(void) {
|
|
|
36
38
|
* — drawing while the blitter is mid-flight loses the frame → black.
|
|
37
39
|
* (Copied from the shmup scaffold, the LYNX-1 fix.) */
|
|
38
40
|
while (tgi_busy()) { }
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
|
|
42
|
+
/* ── Background scene (drawn every frame). Without it the track is a
|
|
43
|
+
* near-flat single colour and the render-health audit flags the
|
|
44
|
+
* screen as blank. A full road with grass shoulders + animated lane
|
|
45
|
+
* dashes keeps several distinct colours well under the threshold:
|
|
46
|
+
* - green grass shoulders on both sides
|
|
47
|
+
* - mid-grey tarmac with darker-grey lane bands
|
|
48
|
+
* - white scrolling centre dashes + solid edge lines. */
|
|
49
|
+
tgi_setcolor(COLOR_GREEN);
|
|
50
|
+
tgi_bar(0, 0, tgi_getmaxx(), tgi_getmaxy()); /* grass base */
|
|
51
|
+
tgi_setcolor(COLOR_GREY);
|
|
52
|
+
tgi_bar(20, 0, 148, 101); /* tarmac */
|
|
53
|
+
/* darker lane bands so the road isn't one flat grey */
|
|
42
54
|
tgi_setcolor(COLOR_DARKGREY);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
tgi_bar(20, 0, 53, 101);
|
|
56
|
+
tgi_bar(96, 0, 128, 101);
|
|
57
|
+
/* solid road edges */
|
|
58
|
+
tgi_setcolor(COLOR_WHITE);
|
|
59
|
+
tgi_line(20, 0, 20, 101);
|
|
60
|
+
tgi_line(148, 0, 148, 101);
|
|
61
|
+
/* animated dashed lane dividers (scroll downward) */
|
|
62
|
+
for (y = (int16_t)scroll - 12; y < 102; y += 12) {
|
|
63
|
+
tgi_bar(53, (unsigned)(y < 0 ? 0 : y), 55, (unsigned)(y + 6 > 101 ? 101 : y + 6));
|
|
64
|
+
tgi_bar(96, (unsigned)(y < 0 ? 0 : y), 98, (unsigned)(y + 6 > 101 ? 101 : y + 6));
|
|
65
|
+
}
|
|
66
|
+
/* grass rumble strips for extra colour texture */
|
|
67
|
+
tgi_setcolor(COLOR_LIGHTGREEN);
|
|
68
|
+
for (y = (int16_t)scroll - 8; y < 102; y += 16) {
|
|
69
|
+
tgi_bar(0, (unsigned)(y < 0 ? 0 : y), 6, (unsigned)(y + 6 > 101 ? 101 : y + 6));
|
|
70
|
+
tgi_bar(153, (unsigned)(y < 0 ? 0 : y), 159, (unsigned)(y + 6 > 101 ? 101 : y + 6));
|
|
71
|
+
}
|
|
47
72
|
|
|
48
73
|
tgi_setcolor(COLOR_YELLOW);
|
|
49
74
|
tgi_bar((unsigned)player.x - 4, (unsigned)player.y - 4, (unsigned)player.x + 4, (unsigned)player.y + 4);
|
|
@@ -54,6 +79,8 @@ void main(void) {
|
|
|
54
79
|
tgi_updatedisplay();
|
|
55
80
|
sfx_update();
|
|
56
81
|
|
|
82
|
+
scroll += 2; if (scroll >= 12) scroll -= 12; /* advance road dashes */
|
|
83
|
+
|
|
57
84
|
if (game_over > 0) {
|
|
58
85
|
game_over--;
|
|
59
86
|
if (game_over == 0) {
|
|
@@ -50,8 +50,15 @@ static void spawn(void) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/* Scrolling starfield: a handful of stars that drift down so the dark
|
|
54
|
+
* space field is never a flat single colour (would read as "blank"). */
|
|
55
|
+
#define N_STARS 24
|
|
56
|
+
static uint8_t star_x[N_STARS];
|
|
57
|
+
static uint8_t star_y[N_STARS];
|
|
58
|
+
|
|
53
59
|
void main(void) {
|
|
54
60
|
uint8_t joy, fire_now, i, j;
|
|
61
|
+
uint32_t srng = 0x1234;
|
|
55
62
|
|
|
56
63
|
tgi_install(&lynx_160_102_16_tgi);
|
|
57
64
|
tgi_init();
|
|
@@ -61,6 +68,12 @@ void main(void) {
|
|
|
61
68
|
player.x = 76; player.y = 90; player.alive = 1;
|
|
62
69
|
for (i = 0; i < MAX_BULLETS; i++) bullets[i].alive = 0;
|
|
63
70
|
for (i = 0; i < MAX_ENEMIES; i++) enemies[i].alive = 0;
|
|
71
|
+
for (i = 0; i < N_STARS; i++) {
|
|
72
|
+
srng = srng * 1103515245u + 12345u;
|
|
73
|
+
star_x[i] = (uint8_t)((srng >> 16) % 160);
|
|
74
|
+
srng = srng * 1103515245u + 12345u;
|
|
75
|
+
star_y[i] = (uint8_t)((srng >> 16) % 102);
|
|
76
|
+
}
|
|
64
77
|
spawn_timer = 0;
|
|
65
78
|
prev_btn = 0;
|
|
66
79
|
|
|
@@ -76,10 +89,31 @@ void main(void) {
|
|
|
76
89
|
* 3. DRAW every object.
|
|
77
90
|
* 4. tgi_updatedisplay() to push the frame. */
|
|
78
91
|
while (tgi_busy()) { }
|
|
79
|
-
tgi_setcolor(COLOR_BLACK);
|
|
80
|
-
tgi_bar(0, 0, tgi_getmaxx(), tgi_getmaxy()); /* maxx/maxy = 159/101 = full screen */
|
|
81
92
|
|
|
82
|
-
/*
|
|
93
|
+
/* ── Background scene (drawn every frame; without it the dark space
|
|
94
|
+
* field is a near-flat single colour and the render-health audit
|
|
95
|
+
* flags the screen as blank). Layered bands keep any one colour well
|
|
96
|
+
* under the threshold:
|
|
97
|
+
* - deep-blue upper space
|
|
98
|
+
* - grey nebula band across the middle
|
|
99
|
+
* - green planet surface along the bottom
|
|
100
|
+
* - a drifting white/yellow starfield over the space. */
|
|
101
|
+
tgi_setcolor(COLOR_BLUE);
|
|
102
|
+
tgi_bar(0, 0, tgi_getmaxx(), tgi_getmaxy()); /* base space field */
|
|
103
|
+
tgi_setcolor(COLOR_GREY);
|
|
104
|
+
tgi_bar(0, 34, 159, 60); /* nebula band */
|
|
105
|
+
tgi_setcolor(COLOR_GREEN);
|
|
106
|
+
tgi_bar(0, 84, 159, 101); /* planet surface */
|
|
107
|
+
tgi_setcolor(COLOR_LIGHTGREEN);
|
|
108
|
+
tgi_bar(0, 78, 159, 83); /* surface horizon */
|
|
109
|
+
/* starfield (bright specks; also drifts downward each frame) */
|
|
110
|
+
tgi_setcolor(COLOR_WHITE);
|
|
111
|
+
for (i = 0; i < N_STARS; i++) {
|
|
112
|
+
tgi_setpixel(star_x[i], star_y[i]);
|
|
113
|
+
tgi_setpixel(star_x[i], (star_y[i] + 1) % 102);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Render game objects on top */
|
|
83
117
|
tgi_setcolor(COLOR_YELLOW);
|
|
84
118
|
tgi_bar(player.x, player.y, player.x + 6, player.y + 6);
|
|
85
119
|
tgi_setcolor(COLOR_WHITE);
|
|
@@ -93,6 +127,11 @@ void main(void) {
|
|
|
93
127
|
tgi_updatedisplay();
|
|
94
128
|
sfx_update();
|
|
95
129
|
|
|
130
|
+
/* drift the starfield downward */
|
|
131
|
+
for (i = 0; i < N_STARS; i++) {
|
|
132
|
+
if (star_y[i] >= 101) star_y[i] = 0; else star_y[i]++;
|
|
133
|
+
}
|
|
134
|
+
|
|
96
135
|
/* Input + state */
|
|
97
136
|
joy = joy_read(JOY_1);
|
|
98
137
|
fire_now = JOY_BTN_1(joy) ? 1 : 0;
|
|
@@ -21,6 +21,7 @@ void main(void) {
|
|
|
21
21
|
int16_t p1y = 40, p2y = 40, bx = 78, by = 48;
|
|
22
22
|
int8_t bdx = 2, bdy = 1;
|
|
23
23
|
uint8_t joy;
|
|
24
|
+
int16_t ny; /* loop var for the dashed centre net */
|
|
24
25
|
|
|
25
26
|
tgi_install(&lynx_160_102_16_tgi);
|
|
26
27
|
tgi_init();
|
|
@@ -33,8 +34,34 @@ void main(void) {
|
|
|
33
34
|
* — drawing while the blitter is mid-flight loses the frame → black.
|
|
34
35
|
* (Copied from the shmup scaffold, the LYNX-1 fix.) */
|
|
35
36
|
while (tgi_busy()) { }
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
|
|
38
|
+
/* ── Background scene (drawn every frame). Without it the court is a
|
|
39
|
+
* near-flat single colour and the render-health audit flags the
|
|
40
|
+
* screen as blank. A two-tone court with boards + net markings keeps
|
|
41
|
+
* several distinct colours well under the threshold:
|
|
42
|
+
* - green centre court
|
|
43
|
+
* - lighter-green end zones behind each paddle
|
|
44
|
+
* - dark-grey boards top and bottom
|
|
45
|
+
* - white boundary, dashed centre net + centre circle. */
|
|
46
|
+
tgi_setcolor(COLOR_GREEN);
|
|
47
|
+
tgi_bar(0, 0, tgi_getmaxx(), tgi_getmaxy()); /* court grass */
|
|
48
|
+
tgi_setcolor(COLOR_LIGHTGREEN);
|
|
49
|
+
tgi_bar(0, COURT_TOP, 52, COURT_BOT - 1); /* left end zone */
|
|
50
|
+
tgi_bar(107, COURT_TOP, 159, COURT_BOT - 1); /* right end zone */
|
|
51
|
+
tgi_setcolor(COLOR_DARKGREY);
|
|
52
|
+
tgi_bar(0, 0, 159, COURT_TOP - 1); /* top boards */
|
|
53
|
+
tgi_bar(0, COURT_BOT, 159, 101); /* bottom boards */
|
|
54
|
+
/* white court boundary + dashed centre net + centre circle */
|
|
55
|
+
tgi_setcolor(COLOR_WHITE);
|
|
56
|
+
tgi_line(0, COURT_TOP, 159, COURT_TOP);
|
|
57
|
+
tgi_line(0, COURT_BOT, 159, COURT_BOT);
|
|
58
|
+
for (ny = COURT_TOP; ny < COURT_BOT; ny += 8)
|
|
59
|
+
tgi_bar(79, (unsigned)ny, 80, (unsigned)(ny + 3 > COURT_BOT ? COURT_BOT : ny + 3));
|
|
60
|
+
tgi_line(70, 40, 90, 40);
|
|
61
|
+
tgi_line(70, 60, 90, 60);
|
|
62
|
+
tgi_line(70, 40, 70, 60);
|
|
63
|
+
tgi_line(90, 40, 90, 60);
|
|
64
|
+
|
|
38
65
|
tgi_setcolor(COLOR_WHITE);
|
|
39
66
|
tgi_bar(PADDLE_X1, (unsigned)p1y, PADDLE_X1 + PADDLE_W - 1, (unsigned)(p1y + PADDLE_H - 1));
|
|
40
67
|
tgi_bar(PADDLE_X2, (unsigned)p2y, PADDLE_X2 + PADDLE_W - 1, (unsigned)(p2y + PADDLE_H - 1));
|