romdevtools 0.13.0 → 0.15.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.
Files changed (124) hide show
  1. package/AGENTS.md +21 -14
  2. package/CHANGELOG.md +125 -1
  3. package/README.md +13 -8
  4. package/examples/atari2600/main.asm +1 -1
  5. package/examples/atari2600/templates/default.asm +1 -1
  6. package/examples/atari2600/templates/paddle.asm +59 -47
  7. package/examples/atari7800/main.c +1 -1
  8. package/examples/atari7800/templates/default.c +1 -1
  9. package/examples/atari7800/templates/music_demo.c +1 -1
  10. package/examples/c64/main.c +1 -1
  11. package/examples/c64/templates/platformer.c +2 -2
  12. package/examples/c64/templates/puzzle.c +1 -1
  13. package/examples/c64/templates/racing.c +3 -3
  14. package/examples/c64/templates/shmup.c +6 -5
  15. package/examples/c64/templates/sports.c +4 -4
  16. package/examples/gb/main.asm +1 -1
  17. package/examples/gb/main.c +1 -1
  18. package/examples/gb/templates/puzzle.c +1 -1
  19. package/examples/gb/templates/racing.c +1 -1
  20. package/examples/gb/templates/shmup.c +1 -1
  21. package/examples/gba/templates/gba_hello.c +1 -1
  22. package/examples/gba/templates/maxmod_demo.c +1 -1
  23. package/examples/gba/templates/puzzle.c +17 -3
  24. package/examples/gba/templates/racing.c +16 -2
  25. package/examples/gba/templates/shmup.c +23 -4
  26. package/examples/gba/templates/tonc_hello.c +6 -4
  27. package/examples/gbc/main.asm +1 -1
  28. package/examples/gbc/templates/puzzle.c +1 -1
  29. package/examples/gbc/templates/racing.c +1 -1
  30. package/examples/gbc/templates/shmup.c +1 -1
  31. package/examples/genesis/main.s +1 -1
  32. package/examples/genesis/templates/puzzle.c +1 -1
  33. package/examples/genesis/templates/racing.c +45 -1
  34. package/examples/genesis/templates/shmup.c +12 -3
  35. package/examples/genesis/templates/shmup_2p.c +2 -2
  36. package/examples/genesis/templates/sports.c +39 -0
  37. package/examples/gg/templates/hello_sprite.c +38 -23
  38. package/examples/gg/templates/music_demo.c +11 -8
  39. package/examples/gg/templates/platformer.c +37 -15
  40. package/examples/gg/templates/racing.c +25 -12
  41. package/examples/gg/templates/shmup.c +12 -6
  42. package/examples/gg/templates/sports.c +30 -16
  43. package/examples/gg/templates/tile_engine.c +24 -10
  44. package/examples/lynx/templates/platformer.c +7 -1
  45. package/examples/lynx/templates/puzzle.c +8 -2
  46. package/examples/lynx/templates/racing.c +7 -1
  47. package/examples/lynx/templates/sports.c +7 -1
  48. package/examples/nes/main.c +2 -2
  49. package/examples/nes/space-shooter/nes_runtime.h +1 -1
  50. package/examples/nes/templates/default.c +4 -1
  51. package/examples/nes/templates/racing.c +50 -1
  52. package/examples/pce/main.c +1 -1
  53. package/examples/sms/templates/hello_sprite.c +1 -1
  54. package/examples/sms/templates/music_demo.c +1 -1
  55. package/examples/sms/templates/puzzle.c +1 -1
  56. package/examples/sms/templates/racing.c +1 -1
  57. package/examples/sms/templates/shmup.c +1 -1
  58. package/examples/sms/templates/shmup_2p.c +2 -2
  59. package/examples/snes/main.asm +1 -1
  60. package/examples/snes/templates/c-hello-data.asm +309 -14
  61. package/examples/snes/templates/c-hello.c +13 -2
  62. package/examples/snes/templates/default.c +1 -1
  63. package/examples/snes/templates/hello_sprite-data.asm +300 -2
  64. package/examples/snes/templates/hello_sprite.c +10 -1
  65. package/examples/snes/templates/music_demo-data.asm +300 -2
  66. package/examples/snes/templates/music_demo.c +10 -1
  67. package/examples/snes/templates/platformer-data.asm +300 -2
  68. package/examples/snes/templates/platformer.c +10 -1
  69. package/examples/snes/templates/puzzle-data.asm +300 -2
  70. package/examples/snes/templates/puzzle.c +11 -1
  71. package/examples/snes/templates/racing-data.asm +300 -2
  72. package/examples/snes/templates/racing.c +40 -4
  73. package/examples/snes/templates/shmup-data.asm +299 -6
  74. package/examples/snes/templates/shmup.c +11 -7
  75. package/examples/snes/templates/sports-data.asm +300 -2
  76. package/examples/snes/templates/sports.c +40 -5
  77. package/package.json +1 -1
  78. package/src/cheats/lookup.js +39 -18
  79. package/src/http/routes.js +58 -33
  80. package/src/http/skill-doc.js +10 -9
  81. package/src/http/swagger.js +1 -1
  82. package/src/http/tool-registry.js +72 -5
  83. package/src/mcp/server.js +6 -5
  84. package/src/mcp/state.js +8 -6
  85. package/src/mcp/tool-manifest.js +7 -7
  86. package/src/mcp/tools/cheats.js +4 -3
  87. package/src/mcp/tools/index.js +18 -2
  88. package/src/mcp/tools/playtest.js +48 -35
  89. package/src/mcp/tools/project.js +39 -73
  90. package/src/mcp/tools/rom-id.js +49 -4
  91. package/src/mcp/tools/tile-inspect.js +1 -1
  92. package/src/mcp/tools/toolchain.js +183 -19
  93. package/src/mcp/tools/trace-vram-source.js +3 -3
  94. package/src/mcp/tools/watch-memory.js +27 -46
  95. package/src/observer/livestream.html +41 -5
  96. package/src/platforms/_guides/ROMHACKING_PLAYBOOK.md +5 -5
  97. package/src/platforms/gb/MENTAL_MODEL.md +3 -3
  98. package/src/platforms/gb/TROUBLESHOOTING.md +1 -1
  99. package/src/platforms/gb/UPSTREAM_SOURCES.md +1 -1
  100. package/src/platforms/gb/lib/c/README.md +2 -2
  101. package/src/platforms/gb/lib/c/SDCC_GOTCHAS.md +1 -1
  102. package/src/platforms/gbc/MENTAL_MODEL.md +3 -3
  103. package/src/platforms/gbc/TROUBLESHOOTING.md +5 -5
  104. package/src/platforms/gbc/UPSTREAM_SOURCES.md +2 -2
  105. package/src/platforms/gbc/lib/c/README.md +2 -2
  106. package/src/platforms/gbc/lib/c/SDCC_GOTCHAS.md +1 -1
  107. package/src/platforms/gg/MENTAL_MODEL.md +14 -13
  108. package/src/platforms/gg/lib/c/vdp_init.c +10 -8
  109. package/src/platforms/msx/MENTAL_MODEL.md +1 -1
  110. package/src/platforms/nes/TROUBLESHOOTING.md +1 -1
  111. package/src/platforms/nes/lib/c/nes_runtime.c +28 -6
  112. package/src/platforms/pce/MENTAL_MODEL.md +1 -1
  113. package/src/platforms/pce/lib/c/pce_hw.h +1 -0
  114. package/src/platforms/pce/lib/c/pce_video.c +26 -0
  115. package/src/platforms/sms/MENTAL_MODEL.md +12 -12
  116. package/src/platforms/sms/lib/c/vdp_init.c +10 -8
  117. package/src/platforms/sms/lib/vdp_init.s +1 -1
  118. package/src/playtest/playtest.js +25 -0
  119. package/src/toolchains/cc65/presets/nes/chr-ram-runtime.cfg +1 -1
  120. package/src/toolchains/cc65/presets/nes/chr-ram.cfg +1 -1
  121. package/src/toolchains/cc65/presets/nes/chr-ram.crt0.s +1 -1
  122. package/src/toolchains/genesis-c/README.md +1 -1
  123. package/src/toolchains/sdcc/preflight-lint.js +47 -7
  124. package/src/toolchains/snes-c/snes-c.js +3 -7
@@ -5,10 +5,308 @@
5
5
  .section ".rodata1" superfree
6
6
 
7
7
  tilfont:
8
- .db 0, 0, 0, 0, 0, 0, 0, 0
8
+ ; 8x8 4bpp console font, 96 glyphs (ASCII 0x20-0x7F). consoleInitText
9
+ ; DMAs exactly 3072 bytes (96 tiles x 32 bytes, 4bpp) from here into
10
+ ; VRAM. Glyph index = (char - 0x20); only bitplane 0 carries pixels so
11
+ ; every set pixel uses palette colour 1. Public-domain font8x8 basic.
12
+ ; 0x20 '(space)'
13
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
14
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
15
+ ; 0x21 '!'
16
+ .db $18, $00, $3C, $00, $3C, $00, $18, $00, $18, $00, $00, $00, $18, $00, $00, $00
17
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
18
+ ; 0x22 '"'
19
+ .db $6C, $00, $6C, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
20
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
21
+ ; 0x23 '#'
22
+ .db $6C, $00, $6C, $00, $FE, $00, $6C, $00, $FE, $00, $6C, $00, $6C, $00, $00, $00
23
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
24
+ ; 0x24 '$'
25
+ .db $30, $00, $7C, $00, $C0, $00, $78, $00, $0C, $00, $F8, $00, $30, $00, $00, $00
26
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
27
+ ; 0x25 '%'
28
+ .db $00, $00, $C6, $00, $CC, $00, $18, $00, $30, $00, $66, $00, $C6, $00, $00, $00
29
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
30
+ ; 0x26 '&'
31
+ .db $38, $00, $6C, $00, $38, $00, $76, $00, $DC, $00, $CC, $00, $76, $00, $00, $00
32
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
33
+ ; 0x27 '''
34
+ .db $60, $00, $60, $00, $C0, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
35
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
36
+ ; 0x28 '('
37
+ .db $18, $00, $30, $00, $60, $00, $60, $00, $60, $00, $30, $00, $18, $00, $00, $00
38
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
39
+ ; 0x29 ')'
40
+ .db $60, $00, $30, $00, $18, $00, $18, $00, $18, $00, $30, $00, $60, $00, $00, $00
41
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
42
+ ; 0x2A '*'
43
+ .db $00, $00, $66, $00, $3C, $00, $FF, $00, $3C, $00, $66, $00, $00, $00, $00, $00
44
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
45
+ ; 0x2B '+'
46
+ .db $00, $00, $30, $00, $30, $00, $FC, $00, $30, $00, $30, $00, $00, $00, $00, $00
47
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
48
+ ; 0x2C ','
49
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $30, $00, $30, $00, $60, $00
50
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
51
+ ; 0x2D '-'
52
+ .db $00, $00, $00, $00, $00, $00, $FC, $00, $00, $00, $00, $00, $00, $00, $00, $00
53
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
54
+ ; 0x2E '.'
55
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $30, $00, $30, $00, $00, $00
56
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
57
+ ; 0x2F '/'
58
+ .db $06, $00, $0C, $00, $18, $00, $30, $00, $60, $00, $C0, $00, $80, $00, $00, $00
59
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
60
+ ; 0x30 '0'
61
+ .db $7C, $00, $C6, $00, $CE, $00, $DE, $00, $F6, $00, $E6, $00, $7C, $00, $00, $00
62
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
63
+ ; 0x31 '1'
64
+ .db $30, $00, $70, $00, $30, $00, $30, $00, $30, $00, $30, $00, $FC, $00, $00, $00
65
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
66
+ ; 0x32 '2'
67
+ .db $78, $00, $CC, $00, $0C, $00, $38, $00, $60, $00, $CC, $00, $FC, $00, $00, $00
68
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
69
+ ; 0x33 '3'
70
+ .db $78, $00, $CC, $00, $0C, $00, $38, $00, $0C, $00, $CC, $00, $78, $00, $00, $00
71
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
72
+ ; 0x34 '4'
73
+ .db $1C, $00, $3C, $00, $6C, $00, $CC, $00, $FE, $00, $0C, $00, $1E, $00, $00, $00
74
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
75
+ ; 0x35 '5'
76
+ .db $FC, $00, $C0, $00, $F8, $00, $0C, $00, $0C, $00, $CC, $00, $78, $00, $00, $00
77
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
78
+ ; 0x36 '6'
79
+ .db $38, $00, $60, $00, $C0, $00, $F8, $00, $CC, $00, $CC, $00, $78, $00, $00, $00
80
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
81
+ ; 0x37 '7'
82
+ .db $FC, $00, $CC, $00, $0C, $00, $18, $00, $30, $00, $30, $00, $30, $00, $00, $00
83
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
84
+ ; 0x38 '8'
85
+ .db $78, $00, $CC, $00, $CC, $00, $78, $00, $CC, $00, $CC, $00, $78, $00, $00, $00
86
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
87
+ ; 0x39 '9'
88
+ .db $78, $00, $CC, $00, $CC, $00, $7C, $00, $0C, $00, $18, $00, $70, $00, $00, $00
89
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
90
+ ; 0x3A ':'
91
+ .db $00, $00, $30, $00, $30, $00, $00, $00, $00, $00, $30, $00, $30, $00, $00, $00
92
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
93
+ ; 0x3B ';'
94
+ .db $00, $00, $30, $00, $30, $00, $00, $00, $00, $00, $30, $00, $30, $00, $60, $00
95
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
96
+ ; 0x3C '<'
97
+ .db $18, $00, $30, $00, $60, $00, $C0, $00, $60, $00, $30, $00, $18, $00, $00, $00
98
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
99
+ ; 0x3D '='
100
+ .db $00, $00, $00, $00, $FC, $00, $00, $00, $00, $00, $FC, $00, $00, $00, $00, $00
101
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
102
+ ; 0x3E '>'
103
+ .db $60, $00, $30, $00, $18, $00, $0C, $00, $18, $00, $30, $00, $60, $00, $00, $00
104
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
105
+ ; 0x3F '?'
106
+ .db $78, $00, $CC, $00, $0C, $00, $18, $00, $30, $00, $00, $00, $30, $00, $00, $00
107
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
108
+ ; 0x40 '@'
109
+ .db $7C, $00, $C6, $00, $DE, $00, $DE, $00, $DE, $00, $C0, $00, $78, $00, $00, $00
110
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
111
+ ; 0x41 'A'
112
+ .db $30, $00, $78, $00, $CC, $00, $CC, $00, $FC, $00, $CC, $00, $CC, $00, $00, $00
113
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
114
+ ; 0x42 'B'
115
+ .db $FC, $00, $66, $00, $66, $00, $7C, $00, $66, $00, $66, $00, $FC, $00, $00, $00
116
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
117
+ ; 0x43 'C'
118
+ .db $3C, $00, $66, $00, $C0, $00, $C0, $00, $C0, $00, $66, $00, $3C, $00, $00, $00
119
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
120
+ ; 0x44 'D'
121
+ .db $F8, $00, $6C, $00, $66, $00, $66, $00, $66, $00, $6C, $00, $F8, $00, $00, $00
122
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
123
+ ; 0x45 'E'
124
+ .db $FE, $00, $62, $00, $68, $00, $78, $00, $68, $00, $62, $00, $FE, $00, $00, $00
125
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
126
+ ; 0x46 'F'
127
+ .db $FE, $00, $62, $00, $68, $00, $78, $00, $68, $00, $60, $00, $F0, $00, $00, $00
128
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
129
+ ; 0x47 'G'
130
+ .db $3C, $00, $66, $00, $C0, $00, $C0, $00, $CE, $00, $66, $00, $3E, $00, $00, $00
131
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
132
+ ; 0x48 'H'
133
+ .db $CC, $00, $CC, $00, $CC, $00, $FC, $00, $CC, $00, $CC, $00, $CC, $00, $00, $00
134
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
135
+ ; 0x49 'I'
136
+ .db $78, $00, $30, $00, $30, $00, $30, $00, $30, $00, $30, $00, $78, $00, $00, $00
137
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
138
+ ; 0x4A 'J'
139
+ .db $1E, $00, $0C, $00, $0C, $00, $0C, $00, $CC, $00, $CC, $00, $78, $00, $00, $00
140
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
141
+ ; 0x4B 'K'
142
+ .db $E6, $00, $66, $00, $6C, $00, $78, $00, $6C, $00, $66, $00, $E6, $00, $00, $00
143
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
144
+ ; 0x4C 'L'
145
+ .db $F0, $00, $60, $00, $60, $00, $60, $00, $62, $00, $66, $00, $FE, $00, $00, $00
146
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
147
+ ; 0x4D 'M'
148
+ .db $C6, $00, $EE, $00, $FE, $00, $FE, $00, $D6, $00, $C6, $00, $C6, $00, $00, $00
149
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
150
+ ; 0x4E 'N'
151
+ .db $C6, $00, $E6, $00, $F6, $00, $DE, $00, $CE, $00, $C6, $00, $C6, $00, $00, $00
152
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
153
+ ; 0x4F 'O'
154
+ .db $38, $00, $6C, $00, $C6, $00, $C6, $00, $C6, $00, $6C, $00, $38, $00, $00, $00
155
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
156
+ ; 0x50 'P'
157
+ .db $FC, $00, $66, $00, $66, $00, $7C, $00, $60, $00, $60, $00, $F0, $00, $00, $00
158
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
159
+ ; 0x51 'Q'
160
+ .db $78, $00, $CC, $00, $CC, $00, $CC, $00, $DC, $00, $78, $00, $1C, $00, $00, $00
161
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
162
+ ; 0x52 'R'
163
+ .db $FC, $00, $66, $00, $66, $00, $7C, $00, $6C, $00, $66, $00, $E6, $00, $00, $00
164
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
165
+ ; 0x53 'S'
166
+ .db $78, $00, $CC, $00, $E0, $00, $70, $00, $1C, $00, $CC, $00, $78, $00, $00, $00
167
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
168
+ ; 0x54 'T'
169
+ .db $FC, $00, $B4, $00, $30, $00, $30, $00, $30, $00, $30, $00, $78, $00, $00, $00
170
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
171
+ ; 0x55 'U'
172
+ .db $CC, $00, $CC, $00, $CC, $00, $CC, $00, $CC, $00, $CC, $00, $FC, $00, $00, $00
173
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
174
+ ; 0x56 'V'
175
+ .db $CC, $00, $CC, $00, $CC, $00, $CC, $00, $CC, $00, $78, $00, $30, $00, $00, $00
176
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
177
+ ; 0x57 'W'
178
+ .db $C6, $00, $C6, $00, $C6, $00, $D6, $00, $FE, $00, $EE, $00, $C6, $00, $00, $00
179
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
180
+ ; 0x58 'X'
181
+ .db $C6, $00, $C6, $00, $6C, $00, $38, $00, $38, $00, $6C, $00, $C6, $00, $00, $00
182
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
183
+ ; 0x59 'Y'
184
+ .db $CC, $00, $CC, $00, $CC, $00, $78, $00, $30, $00, $30, $00, $78, $00, $00, $00
185
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
186
+ ; 0x5A 'Z'
187
+ .db $FE, $00, $C6, $00, $8C, $00, $18, $00, $32, $00, $66, $00, $FE, $00, $00, $00
188
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
189
+ ; 0x5B '['
190
+ .db $78, $00, $60, $00, $60, $00, $60, $00, $60, $00, $60, $00, $78, $00, $00, $00
191
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
192
+ ; 0x5C 'backslash'
193
+ .db $C0, $00, $60, $00, $30, $00, $18, $00, $0C, $00, $06, $00, $02, $00, $00, $00
194
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
195
+ ; 0x5D ']'
196
+ .db $78, $00, $18, $00, $18, $00, $18, $00, $18, $00, $18, $00, $78, $00, $00, $00
197
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
198
+ ; 0x5E '^'
199
+ .db $10, $00, $38, $00, $6C, $00, $C6, $00, $00, $00, $00, $00, $00, $00, $00, $00
200
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
201
+ ; 0x5F '_'
202
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $FF, $00
203
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
204
+ ; 0x60 '`'
205
+ .db $30, $00, $30, $00, $18, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
206
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
207
+ ; 0x61 'a'
208
+ .db $00, $00, $00, $00, $78, $00, $0C, $00, $7C, $00, $CC, $00, $76, $00, $00, $00
209
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
210
+ ; 0x62 'b'
211
+ .db $E0, $00, $60, $00, $60, $00, $7C, $00, $66, $00, $66, $00, $DC, $00, $00, $00
212
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
213
+ ; 0x63 'c'
214
+ .db $00, $00, $00, $00, $78, $00, $CC, $00, $C0, $00, $CC, $00, $78, $00, $00, $00
215
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
216
+ ; 0x64 'd'
217
+ .db $1C, $00, $0C, $00, $0C, $00, $7C, $00, $CC, $00, $CC, $00, $76, $00, $00, $00
218
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
219
+ ; 0x65 'e'
220
+ .db $00, $00, $00, $00, $78, $00, $CC, $00, $FC, $00, $C0, $00, $78, $00, $00, $00
221
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
222
+ ; 0x66 'f'
223
+ .db $38, $00, $6C, $00, $60, $00, $F0, $00, $60, $00, $60, $00, $F0, $00, $00, $00
224
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
225
+ ; 0x67 'g'
226
+ .db $00, $00, $00, $00, $76, $00, $CC, $00, $CC, $00, $7C, $00, $0C, $00, $F8, $00
227
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
228
+ ; 0x68 'h'
229
+ .db $E0, $00, $60, $00, $6C, $00, $76, $00, $66, $00, $66, $00, $E6, $00, $00, $00
230
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
231
+ ; 0x69 'i'
232
+ .db $30, $00, $00, $00, $70, $00, $30, $00, $30, $00, $30, $00, $78, $00, $00, $00
233
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
234
+ ; 0x6A 'j'
235
+ .db $0C, $00, $00, $00, $0C, $00, $0C, $00, $0C, $00, $CC, $00, $CC, $00, $78, $00
236
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
237
+ ; 0x6B 'k'
238
+ .db $E0, $00, $60, $00, $66, $00, $6C, $00, $78, $00, $6C, $00, $E6, $00, $00, $00
239
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
240
+ ; 0x6C 'l'
241
+ .db $70, $00, $30, $00, $30, $00, $30, $00, $30, $00, $30, $00, $78, $00, $00, $00
242
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
243
+ ; 0x6D 'm'
244
+ .db $00, $00, $00, $00, $CC, $00, $FE, $00, $FE, $00, $D6, $00, $C6, $00, $00, $00
245
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
246
+ ; 0x6E 'n'
247
+ .db $00, $00, $00, $00, $F8, $00, $CC, $00, $CC, $00, $CC, $00, $CC, $00, $00, $00
248
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
249
+ ; 0x6F 'o'
250
+ .db $00, $00, $00, $00, $78, $00, $CC, $00, $CC, $00, $CC, $00, $78, $00, $00, $00
251
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
252
+ ; 0x70 'p'
253
+ .db $00, $00, $00, $00, $DC, $00, $66, $00, $66, $00, $7C, $00, $60, $00, $F0, $00
254
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
255
+ ; 0x71 'q'
256
+ .db $00, $00, $00, $00, $76, $00, $CC, $00, $CC, $00, $7C, $00, $0C, $00, $1E, $00
257
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
258
+ ; 0x72 'r'
259
+ .db $00, $00, $00, $00, $DC, $00, $76, $00, $66, $00, $60, $00, $F0, $00, $00, $00
260
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
261
+ ; 0x73 's'
262
+ .db $00, $00, $00, $00, $7C, $00, $C0, $00, $78, $00, $0C, $00, $F8, $00, $00, $00
263
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
264
+ ; 0x74 't'
265
+ .db $10, $00, $30, $00, $7C, $00, $30, $00, $30, $00, $34, $00, $18, $00, $00, $00
266
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
267
+ ; 0x75 'u'
268
+ .db $00, $00, $00, $00, $CC, $00, $CC, $00, $CC, $00, $CC, $00, $76, $00, $00, $00
269
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
270
+ ; 0x76 'v'
271
+ .db $00, $00, $00, $00, $CC, $00, $CC, $00, $CC, $00, $78, $00, $30, $00, $00, $00
272
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
273
+ ; 0x77 'w'
274
+ .db $00, $00, $00, $00, $C6, $00, $D6, $00, $FE, $00, $FE, $00, $6C, $00, $00, $00
275
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
276
+ ; 0x78 'x'
277
+ .db $00, $00, $00, $00, $C6, $00, $6C, $00, $38, $00, $6C, $00, $C6, $00, $00, $00
278
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
279
+ ; 0x79 'y'
280
+ .db $00, $00, $00, $00, $CC, $00, $CC, $00, $CC, $00, $7C, $00, $0C, $00, $F8, $00
281
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
282
+ ; 0x7A 'z'
283
+ .db $00, $00, $00, $00, $FC, $00, $98, $00, $30, $00, $64, $00, $FC, $00, $00, $00
284
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
285
+ ; 0x7B '{'
286
+ .db $1C, $00, $30, $00, $30, $00, $E0, $00, $30, $00, $30, $00, $1C, $00, $00, $00
287
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
288
+ ; 0x7C '|'
289
+ .db $18, $00, $18, $00, $18, $00, $00, $00, $18, $00, $18, $00, $18, $00, $00, $00
290
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
291
+ ; 0x7D '}'
292
+ .db $E0, $00, $30, $00, $30, $00, $1C, $00, $30, $00, $30, $00, $E0, $00, $00, $00
293
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
294
+ ; 0x7E '~'
295
+ .db $76, $00, $DC, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
296
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
297
+ ; 0x7F 'del'
298
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
299
+ .db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
9
300
 
10
301
  palfont:
11
- .db 0, 0, 0, 0, 0, 0, 0, 0
302
+ ; 16-colour text palette (32 bytes, BGR555): colour 0 transparent
303
+ ; (backdrop shows through), colour 1 white (the text colour).
304
+ .db $00, $00 ; 0 transparent
305
+ .db $FF, $7F ; 1 white
306
+ .db $00, $00, $00, $00, $00, $00, $00, $00
307
+ .db $00, $00, $00, $00, $00, $00, $00, $00
308
+ .db $00, $00, $00, $00, $00, $00, $00, $00
309
+ .db $00, $00
12
310
 
13
311
  tilsprite:
14
312
  ; Tile 0 — solid 8×8 block, colour 1
@@ -16,6 +16,10 @@
16
16
  extern char tilfont, palfont;
17
17
  extern char tilsprite, palsprite;
18
18
 
19
+ /* consoleVblank() copies the dirty text tilemap to VRAM during VBlank.
20
+ * No public prototype in console.h, so declare it; call once per frame. */
21
+ extern void consoleVblank(void);
22
+
19
23
  #define COURT_TOP 16
20
24
  #define COURT_BOT 208
21
25
  #define PADDLE_H 24
@@ -23,6 +27,12 @@ extern char tilsprite, palsprite;
23
27
  #define PADDLE_X1 16
24
28
  #define PADDLE_X2 232
25
29
 
30
+ /* oamSet's FIRST arg is a BYTE OFFSET into OAM, not a slot number: slot N lives
31
+ * at byte offset N*4. Passing the raw slot writes every sprite into OAM bytes
32
+ * 0-9, corrupting each other → black/garbled screen. (The shmup scaffold gets
33
+ * this right; sports/racing did not — SNES-1.) */
34
+ #define SPR(slot) ((slot) << 2)
35
+
26
36
  static s16 p1y, p2y, bx, by;
27
37
  static s8 bdx, bdy;
28
38
  static u16 score_p1, score_p2;
@@ -53,6 +63,25 @@ static void render_scores(void) {
53
63
  consoleDrawText(24, 2, buf);
54
64
  }
55
65
 
66
+ /* Draw a Pong court out of font glyphs on the text BG (no extra tile
67
+ * data needed): a dashed rail across the top and bottom of the playfield
68
+ * plus a dashed centre net. The text grid is 32x28 cells (8px each). */
69
+ #define COURT_NET_COL 16
70
+ #define COURT_ROW_TOP 4
71
+ #define COURT_ROW_BOT 23
72
+ static void draw_court(void) {
73
+ char rail[29];
74
+ u16 i;
75
+ for (i = 0; i < 28; i++) rail[i] = '-';
76
+ rail[28] = 0;
77
+ consoleDrawText(2, COURT_ROW_TOP, rail);
78
+ consoleDrawText(2, COURT_ROW_BOT, rail);
79
+ /* Dashed centre net: a ':' every other row between the rails. */
80
+ for (i = COURT_ROW_TOP + 1; i < COURT_ROW_BOT; i += 2) {
81
+ consoleDrawText(COURT_NET_COL, i, ":");
82
+ }
83
+ }
84
+
56
85
  int main(void) {
57
86
  u16 p1, p2;
58
87
  u16 i, slot;
@@ -60,9 +89,13 @@ int main(void) {
60
89
 
61
90
  consoleSetTextMapPtr(0x6800);
62
91
  consoleSetTextGfxPtr(0x3000);
63
- consoleSetTextOffset(0x0100);
92
+ consoleSetTextOffset(0x0000); /* tile index = (char-0x20); font is at the BG char base */
64
93
  consoleInitText(0, 16 * 2, &tilfont, &palfont);
65
94
  setMode(BG_MODE1, 0);
95
+ /* consoleInitText DMAs the font but does NOT set the PPU BG base
96
+ * registers — point BG0 at the same font ($3000) + map ($6800). */
97
+ bgSetGfxPtr(0, 0x3000);
98
+ bgSetMapPtr(0, 0x6800, SC_32x32);
66
99
  bgSetDisable(1);
67
100
  bgSetDisable(2);
68
101
 
@@ -71,9 +104,10 @@ int main(void) {
71
104
  consoleDrawText(2, 1, "P1");
72
105
  consoleDrawText(28, 1, "P2");
73
106
  consoleDrawText(6, 26, "UP/DOWN MOVES YOUR PADDLE");
107
+ draw_court(); /* dashed rails + centre net (font glyphs, no extra tiles) */
74
108
 
75
109
  /* Hide all OAM slots initially. */
76
- for (i = 0; i < 7; i++) oamSet(i, 0, 240, 3, 0, 0, 0, 0);
110
+ for (i = 0; i < 7; i++) oamSet(SPR(i), 0, 240, 3, 0, 0, 0, 0);
77
111
 
78
112
  setScreenOn();
79
113
  sfx_init();
@@ -83,15 +117,16 @@ int main(void) {
83
117
  slot = 0;
84
118
  /* Left paddle = 3 stacked 8×8 sprites */
85
119
  for (i = 0; i < PADDLE_H / 8; i++) {
86
- oamSet(slot++, PADDLE_X1, (u16)(p1y + i * 8), 3, 0, 0, 0, 0);
120
+ oamSet(SPR(slot++), PADDLE_X1, (u16)(p1y + i * 8), 3, 0, 0, 0, 0);
87
121
  }
88
122
  for (i = 0; i < PADDLE_H / 8; i++) {
89
- oamSet(slot++, PADDLE_X2, (u16)(p2y + i * 8), 3, 0, 0, 0, 0);
123
+ oamSet(SPR(slot++), PADDLE_X2, (u16)(p2y + i * 8), 3, 0, 0, 0, 0);
90
124
  }
91
- oamSet(slot++, bx, by, 3, 0, 0, 0, 0);
125
+ oamSet(SPR(slot++), bx, by, 3, 0, 0, 0, 0);
92
126
  oamUpdate();
93
127
  render_scores();
94
128
  WaitForVBlank();
129
+ consoleVblank();
95
130
 
96
131
  p1 = padsCurrent(0);
97
132
  p2 = padsCurrent(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "romdevtools",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "Tool server giving coding agents full control of homebrew ROM development AND reverse-engineering/romhacking across 14 retro platforms (NES, SNES, GB, Genesis, Atari, C64, PC Engine, MSX, ...) via WASM toolchains + emulator cores. Use over plain HTTP, as an Agent Skill, or as an MCP server.",
5
5
  "type": "module",
6
6
  "main": "src/mcp/server.js",
@@ -121,37 +121,58 @@ function baseName(name) {
121
121
  .trim();
122
122
  }
123
123
 
124
+ // The platforms that ship a bundled cheat index — the set searchCheatGames sweeps
125
+ // when no `platform` is given. (Kept in step with cheats.js SUPPORTED; C64 has no
126
+ // source cheats so it has no index.)
127
+ const INDEXED_PLATFORMS = [
128
+ "nes", "gb", "gbc", "snes", "genesis", "sms", "gg",
129
+ "atari2600", "atari7800", "lynx", "gba", "pce", "msx",
130
+ ];
131
+
124
132
  /**
125
- * Fuzzy-search a platform's cheat index by game name. Returns the best-matching
126
- * game names + cheat counts WITHOUT dumping the whole DB so an agent can find
127
- * "NBA Jam Tournament" the real entry without a huge context load.
133
+ * Fuzzy-search the cheat DB by game NAME. Each match carries the `platform` it
134
+ * was found on, so the caller never has to know the console up front. By default
135
+ * this searches EVERY indexed platform (the natural ask: "find a game's cheats"
136
+ * — you shouldn't have to name the device); pass `platform` only to scope the
137
+ * search to one console. Returns best-matching game names + cheat counts WITHOUT
138
+ * dumping the whole DB.
128
139
  * @param {object} a
129
- * @param {string} a.platform
130
140
  * @param {string} a.query
141
+ * @param {string} [a.platform] optional — restrict to one platform; omit to search all
131
142
  * @param {number} [a.limit]
132
143
  * @param {number} [a.minScore]
133
- * @returns {Promise<{platform:string, query:string, matches:Array<{game:string, score:number, cheats:number}>, gameCount:number, note:string}>}
144
+ * @returns {Promise<{platform:string|null, query:string, matches:Array<{game:string, platform:string, score:number, cheats:number}>, gameCount:number, note:string}>}
134
145
  */
135
146
  export async function searchCheatGames({ platform, query, limit = 12, minScore = 0.25 }) {
136
- const idx = await loadIndex(platform);
137
- if (!idx || !idx.games) {
147
+ const platforms = platform ? [platform] : INDEXED_PLATFORMS;
148
+ let scored = [];
149
+ let gameCount = 0;
150
+ let missing = [];
151
+ for (const plat of platforms) {
152
+ const idx = await loadIndex(plat);
153
+ if (!idx || !idx.games) { missing.push(plat); continue; }
154
+ gameCount += idx.gameCount ?? Object.keys(idx.games).length;
155
+ const fuse = await getFuse(plat);
156
+ if (!fuse) continue;
157
+ for (const r of fuse.search(baseName(query))) {
158
+ const score = simFromFuse(r.score);
159
+ if (score >= minScore) scored.push({ game: r.item.game, platform: plat, score, cheats: r.item.cheats });
160
+ }
161
+ }
162
+ // When scoped to one platform and that platform has no index at all, say so.
163
+ if (platform && missing.length) {
138
164
  return { platform, query, matches: [], gameCount: 0, note: `No bundled cheat index for platform '${platform}'.` };
139
165
  }
140
- const names = Object.keys(idx.games);
141
- const fuse = await getFuse(platform);
142
- // Search the tag-stripped query against the tag-stripped baseName index.
143
- const results = fuse.search(baseName(query));
144
- const matches = results
145
- .map((r) => ({ game: r.item.game, score: simFromFuse(r.score), cheats: r.item.cheats }))
146
- .filter((m) => m.score >= minScore)
166
+ const matches = scored
147
167
  .sort((a, b) => b.score - a.score || a.game.length - b.game.length)
148
168
  .slice(0, limit);
169
+ const scope = platform ? `the ${platform} cheat DB` : `the cheat DB (all ${platforms.length - missing.length} platforms)`;
149
170
  return {
150
- platform, query, matches,
151
- gameCount: idx.gameCount ?? names.length,
171
+ platform: platform ?? null,
172
+ query, matches, gameCount,
152
173
  note: matches.length === 0
153
- ? `No game in the ${platform} cheat DB (${names.length} games) is close to "${query}". Try fewer/looser words.`
154
- : `${matches.length} candidate(s) by fuzzy name match (region/revision tags ignored, typo-tolerant). Pass an exact \`game\` to cheats({op:'lookup'}) (it also fuzzy-matches). Score is name similarity, not a content guarantee — verify a label before patching.`,
174
+ ? `No game in ${scope} (${gameCount} games) is close to "${query}". Try fewer/looser words.`
175
+ : `${matches.length} candidate(s) by fuzzy name match across ${platform ? "1 platform" : "all platforms"} (each match shows its \`platform\`; region/revision tags ignored, typo-tolerant). To read a game's cheats, call cheats({op:'lookup', platform, game}) with the match's own platform. Score is name similarity, not a content guarantee — verify a label before patching.`,
155
176
  };
156
177
  }
157
178