c64-kb 0.17.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 (970) hide show
  1. package/CHANGELOG.md +2082 -0
  2. package/LICENSE +29 -0
  3. package/README.md +559 -0
  4. package/VERSION +25 -0
  5. package/dist/cli/setup.js +66 -0
  6. package/dist/cli/setup.js.map +1 -0
  7. package/dist/cli-memorize-audit.js +97 -0
  8. package/dist/cli-memorize-audit.js.map +1 -0
  9. package/dist/cli.js +335 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config.js +83 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/context.js +53 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/domain/budget-notes.js +104 -0
  16. package/dist/domain/budget-notes.js.map +1 -0
  17. package/dist/domain/budget.js +417 -0
  18. package/dist/domain/budget.js.map +1 -0
  19. package/dist/domain/game-design.js +77 -0
  20. package/dist/domain/game-design.js.map +1 -0
  21. package/dist/domain/timing.js +39 -0
  22. package/dist/domain/timing.js.map +1 -0
  23. package/dist/graph/apply.js +132 -0
  24. package/dist/graph/apply.js.map +1 -0
  25. package/dist/graph/claims.js +231 -0
  26. package/dist/graph/claims.js.map +1 -0
  27. package/dist/graph/extract/archetype.js +118 -0
  28. package/dist/graph/extract/archetype.js.map +1 -0
  29. package/dist/graph/extract/common.js +69 -0
  30. package/dist/graph/extract/common.js.map +1 -0
  31. package/dist/graph/extract/failure.js +37 -0
  32. package/dist/graph/extract/failure.js.map +1 -0
  33. package/dist/graph/extract/game-design.js +189 -0
  34. package/dist/graph/extract/game-design.js.map +1 -0
  35. package/dist/graph/extract/hardware.js +124 -0
  36. package/dist/graph/extract/hardware.js.map +1 -0
  37. package/dist/graph/extract/pitfall.js +62 -0
  38. package/dist/graph/extract/pitfall.js.map +1 -0
  39. package/dist/graph/extract/raster-band.js +56 -0
  40. package/dist/graph/extract/raster-band.js.map +1 -0
  41. package/dist/graph/extract/recipe.js +71 -0
  42. package/dist/graph/extract/recipe.js.map +1 -0
  43. package/dist/graph/extract/technique-entities.js +180 -0
  44. package/dist/graph/extract/technique-entities.js.map +1 -0
  45. package/dist/graph/extract/technique.js +179 -0
  46. package/dist/graph/extract/technique.js.map +1 -0
  47. package/dist/graph/extract/toolchain.js +67 -0
  48. package/dist/graph/extract/toolchain.js.map +1 -0
  49. package/dist/graph/extract/types.js +3 -0
  50. package/dist/graph/extract/types.js.map +1 -0
  51. package/dist/graph/extract/vocabulary.js +65 -0
  52. package/dist/graph/extract/vocabulary.js.map +1 -0
  53. package/dist/graph/extract.js +43 -0
  54. package/dist/graph/extract.js.map +1 -0
  55. package/dist/graph/kernal-clobbers.js +64 -0
  56. package/dist/graph/kernal-clobbers.js.map +1 -0
  57. package/dist/graph/machine-variants.js +208 -0
  58. package/dist/graph/machine-variants.js.map +1 -0
  59. package/dist/ingest/files.js +99 -0
  60. package/dist/ingest/files.js.map +1 -0
  61. package/dist/ingest/passes.js +104 -0
  62. package/dist/ingest/passes.js.map +1 -0
  63. package/dist/ingest/points.js +50 -0
  64. package/dist/ingest/points.js.map +1 -0
  65. package/dist/ingest/report.js +140 -0
  66. package/dist/ingest/report.js.map +1 -0
  67. package/dist/ingest/tally.js +81 -0
  68. package/dist/ingest/tally.js.map +1 -0
  69. package/dist/ingest/verified-on.js +43 -0
  70. package/dist/ingest/verified-on.js.map +1 -0
  71. package/dist/ingest.js +135 -0
  72. package/dist/ingest.js.map +1 -0
  73. package/dist/schemas/cost-basis.js +5 -0
  74. package/dist/schemas/cost-basis.js.map +1 -0
  75. package/dist/schemas/machine-variant.js +25 -0
  76. package/dist/schemas/machine-variant.js.map +1 -0
  77. package/dist/schemas/plan-budget.js +121 -0
  78. package/dist/schemas/plan-budget.js.map +1 -0
  79. package/dist/schemas/tool-outputs.js +526 -0
  80. package/dist/schemas/tool-outputs.js.map +1 -0
  81. package/dist/server/define-tool.js +52 -0
  82. package/dist/server/define-tool.js.map +1 -0
  83. package/dist/server/defined-only.js +9 -0
  84. package/dist/server/defined-only.js.map +1 -0
  85. package/dist/server/tools-briefings.js +70 -0
  86. package/dist/server/tools-briefings.js.map +1 -0
  87. package/dist/server/tools-lookup.js +180 -0
  88. package/dist/server/tools-lookup.js.map +1 -0
  89. package/dist/server/tools-maintenance.js +116 -0
  90. package/dist/server/tools-maintenance.js.map +1 -0
  91. package/dist/server/tools-pitfalls.js +89 -0
  92. package/dist/server/tools-pitfalls.js.map +1 -0
  93. package/dist/server/tools-recipes.js +296 -0
  94. package/dist/server/tools-recipes.js.map +1 -0
  95. package/dist/server/tools-runtime.js +48 -0
  96. package/dist/server/tools-runtime.js.map +1 -0
  97. package/dist/server/tools.js +43 -0
  98. package/dist/server/tools.js.map +1 -0
  99. package/dist/server.js +95 -0
  100. package/dist/server.js.map +1 -0
  101. package/dist/services/analytics/schema.js +78 -0
  102. package/dist/services/analytics/schema.js.map +1 -0
  103. package/dist/services/analytics/statements.js +99 -0
  104. package/dist/services/analytics/statements.js.map +1 -0
  105. package/dist/services/analytics.js +195 -0
  106. package/dist/services/analytics.js.map +1 -0
  107. package/dist/services/bm25.js +158 -0
  108. package/dist/services/bm25.js.map +1 -0
  109. package/dist/services/chunker.js +81 -0
  110. package/dist/services/chunker.js.map +1 -0
  111. package/dist/services/embeddings.js +58 -0
  112. package/dist/services/embeddings.js.map +1 -0
  113. package/dist/services/falkor/base.js +85 -0
  114. package/dist/services/falkor/base.js.map +1 -0
  115. package/dist/services/falkor/links.js +361 -0
  116. package/dist/services/falkor/links.js.map +1 -0
  117. package/dist/services/falkor/nodes.js +183 -0
  118. package/dist/services/falkor/nodes.js.map +1 -0
  119. package/dist/services/falkor/params.js +45 -0
  120. package/dist/services/falkor/params.js.map +1 -0
  121. package/dist/services/falkor/schema.js +77 -0
  122. package/dist/services/falkor/schema.js.map +1 -0
  123. package/dist/services/falkor.js +100 -0
  124. package/dist/services/falkor.js.map +1 -0
  125. package/dist/services/qdrant.js +238 -0
  126. package/dist/services/qdrant.js.map +1 -0
  127. package/dist/services/versions.js +73 -0
  128. package/dist/services/versions.js.map +1 -0
  129. package/dist/services/vice-bin.js +51 -0
  130. package/dist/services/vice-bin.js.map +1 -0
  131. package/dist/tools/briefings/archetype.js +174 -0
  132. package/dist/tools/briefings/archetype.js.map +1 -0
  133. package/dist/tools/briefings/budget.js +177 -0
  134. package/dist/tools/briefings/budget.js.map +1 -0
  135. package/dist/tools/briefings/build-order.js +135 -0
  136. package/dist/tools/briefings/build-order.js.map +1 -0
  137. package/dist/tools/briefings/build.js +185 -0
  138. package/dist/tools/briefings/build.js.map +1 -0
  139. package/dist/tools/briefings/discovery.js +290 -0
  140. package/dist/tools/briefings/discovery.js.map +1 -0
  141. package/dist/tools/briefings/plan-pitfalls.js +69 -0
  142. package/dist/tools/briefings/plan-pitfalls.js.map +1 -0
  143. package/dist/tools/briefings/render.js +151 -0
  144. package/dist/tools/briefings/render.js.map +1 -0
  145. package/dist/tools/briefings/rows.js +41 -0
  146. package/dist/tools/briefings/rows.js.map +1 -0
  147. package/dist/tools/briefings/toolchain.js +63 -0
  148. package/dist/tools/briefings/toolchain.js.map +1 -0
  149. package/dist/tools/briefings/why-proposed.js +69 -0
  150. package/dist/tools/briefings/why-proposed.js.map +1 -0
  151. package/dist/tools/briefings.js +44 -0
  152. package/dist/tools/briefings.js.map +1 -0
  153. package/dist/tools/feedback.js +97 -0
  154. package/dist/tools/feedback.js.map +1 -0
  155. package/dist/tools/hydrate.js +75 -0
  156. package/dist/tools/hydrate.js.map +1 -0
  157. package/dist/tools/intelligence.js +67 -0
  158. package/dist/tools/intelligence.js.map +1 -0
  159. package/dist/tools/lint/asm-decimal.js +86 -0
  160. package/dist/tools/lint/asm-decimal.js.map +1 -0
  161. package/dist/tools/lint/asm-rules.js +221 -0
  162. package/dist/tools/lint/asm-rules.js.map +1 -0
  163. package/dist/tools/lint/asm-shared.js +3 -0
  164. package/dist/tools/lint/asm-shared.js.map +1 -0
  165. package/dist/tools/lint/c-rules.js +215 -0
  166. package/dist/tools/lint/c-rules.js.map +1 -0
  167. package/dist/tools/lint/text.js +122 -0
  168. package/dist/tools/lint/text.js.map +1 -0
  169. package/dist/tools/lint/types.js +40 -0
  170. package/dist/tools/lint/types.js.map +1 -0
  171. package/dist/tools/lint.js +76 -0
  172. package/dist/tools/lint.js.map +1 -0
  173. package/dist/tools/memorization-mcp.js +111 -0
  174. package/dist/tools/memorization-mcp.js.map +1 -0
  175. package/dist/tools/pitfalls/bm25.js +53 -0
  176. package/dist/tools/pitfalls/bm25.js.map +1 -0
  177. package/dist/tools/pitfalls/format.js +58 -0
  178. package/dist/tools/pitfalls/format.js.map +1 -0
  179. package/dist/tools/pitfalls/graph.js +124 -0
  180. package/dist/tools/pitfalls/graph.js.map +1 -0
  181. package/dist/tools/pitfalls.js +134 -0
  182. package/dist/tools/pitfalls.js.map +1 -0
  183. package/dist/tools/prompts.js +81 -0
  184. package/dist/tools/prompts.js.map +1 -0
  185. package/dist/tools/query/compatibility/closure.js +62 -0
  186. package/dist/tools/query/compatibility/closure.js.map +1 -0
  187. package/dist/tools/query/compatibility/facts.js +28 -0
  188. package/dist/tools/query/compatibility/facts.js.map +1 -0
  189. package/dist/tools/query/compatibility/fetch.js +164 -0
  190. package/dist/tools/query/compatibility/fetch.js.map +1 -0
  191. package/dist/tools/query/compatibility/hard-rules.js +159 -0
  192. package/dist/tools/query/compatibility/hard-rules.js.map +1 -0
  193. package/dist/tools/query/compatibility/index.js +27 -0
  194. package/dist/tools/query/compatibility/index.js.map +1 -0
  195. package/dist/tools/query/compatibility/kernal-zp-rule.js +90 -0
  196. package/dist/tools/query/compatibility/kernal-zp-rule.js.map +1 -0
  197. package/dist/tools/query/compatibility/render.js +106 -0
  198. package/dist/tools/query/compatibility/render.js.map +1 -0
  199. package/dist/tools/query/compatibility/rules.js +337 -0
  200. package/dist/tools/query/compatibility/rules.js.map +1 -0
  201. package/dist/tools/query/compatibility/unit-rules.js +253 -0
  202. package/dist/tools/query/compatibility/unit-rules.js.map +1 -0
  203. package/dist/tools/query/game-design.js +83 -0
  204. package/dist/tools/query/game-design.js.map +1 -0
  205. package/dist/tools/query/lookups.js +220 -0
  206. package/dist/tools/query/lookups.js.map +1 -0
  207. package/dist/tools/query/plan-budget.js +266 -0
  208. package/dist/tools/query/plan-budget.js.map +1 -0
  209. package/dist/tools/query/recipes.js +214 -0
  210. package/dist/tools/query/recipes.js.map +1 -0
  211. package/dist/tools/query/retrieval.js +128 -0
  212. package/dist/tools/query/retrieval.js.map +1 -0
  213. package/dist/tools/query/shared.js +121 -0
  214. package/dist/tools/query/shared.js.map +1 -0
  215. package/dist/tools/query/techniques.js +331 -0
  216. package/dist/tools/query/techniques.js.map +1 -0
  217. package/dist/tools/query/timing.js +106 -0
  218. package/dist/tools/query/timing.js.map +1 -0
  219. package/dist/tools/query/types.js +11 -0
  220. package/dist/tools/query/types.js.map +1 -0
  221. package/dist/tools/query.js +21 -0
  222. package/dist/tools/query.js.map +1 -0
  223. package/dist/tools/resources.js +186 -0
  224. package/dist/tools/resources.js.map +1 -0
  225. package/dist/tools/run-game.js +249 -0
  226. package/dist/tools/run-game.js.map +1 -0
  227. package/dist/tools/selfimprovement.js +367 -0
  228. package/dist/tools/selfimprovement.js.map +1 -0
  229. package/docker-compose.yml +35 -0
  230. package/docs/ARCHITECTURE.md +164 -0
  231. package/docs/CONVENTIONS-archetypes.md +158 -0
  232. package/docs/CONVENTIONS-failures.md +46 -0
  233. package/docs/CONVENTIONS-game-designs.md +75 -0
  234. package/docs/CONVENTIONS-hardware-reference.md +184 -0
  235. package/docs/CONVENTIONS-pitfalls.md +91 -0
  236. package/docs/CONVENTIONS-recipes.md +106 -0
  237. package/docs/CONVENTIONS-techniques.md +309 -0
  238. package/docs/CONVENTIONS-toolchain-reference.md +89 -0
  239. package/docs/ONTOLOGY.md +655 -0
  240. package/docs/art/art-production-reference.md +157 -0
  241. package/docs/art/asset-pipelines.md +586 -0
  242. package/docs/c64-failure-patterns.md +693 -0
  243. package/docs/demo-design/demo-composition.md +349 -0
  244. package/docs/demo-design/demo-design-philosophy.md +320 -0
  245. package/docs/demo-design/intro-cracktro-patterns.md +435 -0
  246. package/docs/figures/ctm-spd-embed-probe.png +0 -0
  247. package/docs/figures/dot-flag-mid-5000000.png +0 -0
  248. package/docs/figures/dot-flag-no-erase-12000000.png +0 -0
  249. package/docs/figures/edges.json +1 -0
  250. package/docs/figures/fig6-architecture.png +0 -0
  251. package/docs/figures/fig7-ontology.png +0 -0
  252. package/docs/figures/screen-dissolve-mid-frame25.png +0 -0
  253. package/docs/figures/screen-dissolve-wipe-frame25.png +0 -0
  254. package/docs/figures/spindle-two-parts-part1.png +0 -0
  255. package/docs/figures/spindle-two-parts-part2.png +0 -0
  256. package/docs/figures/starters/action-puzzle.png +0 -0
  257. package/docs/figures/starters/adventure.png +0 -0
  258. package/docs/figures/starters/beat-em-up.png +0 -0
  259. package/docs/figures/starters/demo.png +0 -0
  260. package/docs/figures/starters/platformer.png +0 -0
  261. package/docs/figures/starters/shmup-vertical.png +0 -0
  262. package/docs/figures/tape-kernal-master-ntsc.png +0 -0
  263. package/docs/figures/tape-kernal-master-pal.png +0 -0
  264. package/docs/figures/tape-turbo-loader-ntsc.png +0 -0
  265. package/docs/figures/tape-turbo-loader-pal.png +0 -0
  266. package/docs/figures/tape-turbo-master-ntsc.png +0 -0
  267. package/docs/figures/tape-turbo-master-pal.png +0 -0
  268. package/docs/figures/tech-tech-pad2-12000000.png +0 -0
  269. package/docs/figures/tech-tech-pad4-12000000.png +0 -0
  270. package/docs/figures/tech-tech-seven-12000000.png +0 -0
  271. package/docs/figures/twister-mid-5000000.png +0 -0
  272. package/docs/figures/twister-straight-12000000.png +0 -0
  273. package/docs/figures/vector-balls-nosort-ntsc.png +0 -0
  274. package/docs/figures/vector-balls-nosort.png +0 -0
  275. package/docs/formats/c64-file-formats.md +1212 -0
  276. package/docs/formats/iec-disk-reference.md +754 -0
  277. package/docs/game-design/c64-game-archetypes.md +273 -0
  278. package/docs/game-design/designs/falling-blocks.md +54 -0
  279. package/docs/game-design/designs/platformer-scaffold.md +48 -0
  280. package/docs/game-design/designs/simple-shmup.md +27 -0
  281. package/docs/game-design/enemy-behaviour-and-difficulty.md +349 -0
  282. package/docs/game-design/game-design-patterns.md +1189 -0
  283. package/docs/game-design/game-structure.md +354 -0
  284. package/docs/game-design/production-planning.md +349 -0
  285. package/docs/game-design/reference-game-sources.md +90 -0
  286. package/docs/hardware/6502-illegal-opcodes.md +1353 -0
  287. package/docs/hardware/6510-cpu-reference.md +2112 -0
  288. package/docs/hardware/c64-memory-map.md +3184 -0
  289. package/docs/hardware/c64-registers-reference.md +996 -0
  290. package/docs/hardware/cia-reference.md +1281 -0
  291. package/docs/hardware/kernal-routines-reference.md +1836 -0
  292. package/docs/hardware/pal-ntsc-reference.md +813 -0
  293. package/docs/hardware/sid-reference.md +1137 -0
  294. package/docs/hardware/vic-ii-reference.md +1714 -0
  295. package/docs/music/music-production-reference.md +403 -0
  296. package/docs/pitfalls/banking.md +1067 -0
  297. package/docs/pitfalls/cia.md +1147 -0
  298. package/docs/pitfalls/cpu.md +874 -0
  299. package/docs/pitfalls/input.md +282 -0
  300. package/docs/pitfalls/kernal-and-io.md +1615 -0
  301. package/docs/pitfalls/loader.md +1191 -0
  302. package/docs/pitfalls/logic.md +94 -0
  303. package/docs/pitfalls/maths.md +187 -0
  304. package/docs/pitfalls/raster-and-badline.md +721 -0
  305. package/docs/pitfalls/region-timing.md +660 -0
  306. package/docs/pitfalls/scroll.md +207 -0
  307. package/docs/pitfalls/sid.md +738 -0
  308. package/docs/pitfalls/sprite.md +979 -0
  309. package/docs/pitfalls/text-mode-render.md +1172 -0
  310. package/docs/recipes/cc65/cartridge-8k.md +398 -0
  311. package/docs/recipes/cc65/hello-world-conio.md +76 -0
  312. package/docs/recipes/cc65/memory-layout.md +312 -0
  313. package/docs/recipes/cc65/screenshots/README.md +14 -0
  314. package/docs/recipes/cc65/screenshots/cartridge-8k-ntsc.png +0 -0
  315. package/docs/recipes/cc65/screenshots/cartridge-8k.png +0 -0
  316. package/docs/recipes/cc65/screenshots/hello-world-conio.png +0 -0
  317. package/docs/recipes/cc65/screenshots/memory-layout-ntsc.png +0 -0
  318. package/docs/recipes/cc65/screenshots/memory-layout.png +0 -0
  319. package/docs/recipes/kickassembler/basic-float-calls.md +578 -0
  320. package/docs/recipes/kickassembler/basic-wedge.md +398 -0
  321. package/docs/recipes/kickassembler/big-font-scroller.md +620 -0
  322. package/docs/recipes/kickassembler/charset-copy-rom-to-ram.md +623 -0
  323. package/docs/recipes/kickassembler/cia-revision-detect.md +366 -0
  324. package/docs/recipes/kickassembler/colour-cycling.md +343 -0
  325. package/docs/recipes/kickassembler/colour-fade.md +303 -0
  326. package/docs/recipes/kickassembler/compare-16bit-signed.md +1007 -0
  327. package/docs/recipes/kickassembler/cracktro-template.md +526 -0
  328. package/docs/recipes/kickassembler/crt-banked.md +276 -0
  329. package/docs/recipes/kickassembler/dos-error-codes.md +466 -0
  330. package/docs/recipes/kickassembler/dot-flag.md +576 -0
  331. package/docs/recipes/kickassembler/drive-job-queue.md +667 -0
  332. package/docs/recipes/kickassembler/drive-via-probe.md +690 -0
  333. package/docs/recipes/kickassembler/dycp-scroller.md +568 -0
  334. package/docs/recipes/kickassembler/dypp-sprite-scroller.md +681 -0
  335. package/docs/recipes/kickassembler/dysp.md +670 -0
  336. package/docs/recipes/kickassembler/easyflash-save.md +800 -0
  337. package/docs/recipes/kickassembler/eight-way-scroll.md +1484 -0
  338. package/docs/recipes/kickassembler/file-io-roundtrip.md +546 -0
  339. package/docs/recipes/kickassembler/fire-effect.md +420 -0
  340. package/docs/recipes/kickassembler/fld.md +414 -0
  341. package/docs/recipes/kickassembler/fli-image.md +336 -0
  342. package/docs/recipes/kickassembler/four-player-read.md +672 -0
  343. package/docs/recipes/kickassembler/headless-verify.md +228 -0
  344. package/docs/recipes/kickassembler/hello-world.md +98 -0
  345. package/docs/recipes/kickassembler/high-score-insert.md +660 -0
  346. package/docs/recipes/kickassembler/hires-plot-line.md +723 -0
  347. package/docs/recipes/kickassembler/irq-chain.md +316 -0
  348. package/docs/recipes/kickassembler/irq-owns-port.md +668 -0
  349. package/docs/recipes/kickassembler/isometric-room.md +1145 -0
  350. package/docs/recipes/kickassembler/light-pen-read.md +926 -0
  351. package/docs/recipes/kickassembler/logic-rate-decoupling.md +670 -0
  352. package/docs/recipes/kickassembler/mci-interlace.md +543 -0
  353. package/docs/recipes/kickassembler/memory-layout.md +277 -0
  354. package/docs/recipes/kickassembler/mouse-1351-read.md +801 -0
  355. package/docs/recipes/kickassembler/nmi-timer-tick.md +562 -0
  356. package/docs/recipes/kickassembler/own-keyscan.md +881 -0
  357. package/docs/recipes/kickassembler/paddle-read.md +751 -0
  358. package/docs/recipes/kickassembler/palette-cells.md +219 -0
  359. package/docs/recipes/kickassembler/pseudo-3d-road.md +930 -0
  360. package/docs/recipes/kickassembler/pwm-digi.md +463 -0
  361. package/docs/recipes/kickassembler/raster-bars.md +264 -0
  362. package/docs/recipes/kickassembler/reu-dma.md +1019 -0
  363. package/docs/recipes/kickassembler/runtime-relocation.md +743 -0
  364. package/docs/recipes/kickassembler/screen-dissolve.md +545 -0
  365. package/docs/recipes/kickassembler/screen-wipe.md +408 -0
  366. package/docs/recipes/kickassembler/screenshots/README.md +72 -0
  367. package/docs/recipes/kickassembler/screenshots/basic-float-calls-ntsc.png +0 -0
  368. package/docs/recipes/kickassembler/screenshots/basic-float-calls.png +0 -0
  369. package/docs/recipes/kickassembler/screenshots/basic-wedge-ntsc.png +0 -0
  370. package/docs/recipes/kickassembler/screenshots/basic-wedge.png +0 -0
  371. package/docs/recipes/kickassembler/screenshots/big-font-scroller-ntsc.png +0 -0
  372. package/docs/recipes/kickassembler/screenshots/big-font-scroller.png +0 -0
  373. package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram-ntsc.png +0 -0
  374. package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram.png +0 -0
  375. package/docs/recipes/kickassembler/screenshots/cia-revision-detect-ntsc.png +0 -0
  376. package/docs/recipes/kickassembler/screenshots/cia-revision-detect.png +0 -0
  377. package/docs/recipes/kickassembler/screenshots/colour-cycling-ntsc.png +0 -0
  378. package/docs/recipes/kickassembler/screenshots/colour-cycling.png +0 -0
  379. package/docs/recipes/kickassembler/screenshots/colour-fade-ntsc.png +0 -0
  380. package/docs/recipes/kickassembler/screenshots/colour-fade.png +0 -0
  381. package/docs/recipes/kickassembler/screenshots/compare-16bit-signed-ntsc.png +0 -0
  382. package/docs/recipes/kickassembler/screenshots/compare-16bit-signed.png +0 -0
  383. package/docs/recipes/kickassembler/screenshots/cracktro-template.png +0 -0
  384. package/docs/recipes/kickassembler/screenshots/crt-banked-ntsc.png +0 -0
  385. package/docs/recipes/kickassembler/screenshots/crt-banked.png +0 -0
  386. package/docs/recipes/kickassembler/screenshots/dos-error-codes-ntsc.png +0 -0
  387. package/docs/recipes/kickassembler/screenshots/dos-error-codes.png +0 -0
  388. package/docs/recipes/kickassembler/screenshots/dot-flag-ntsc.png +0 -0
  389. package/docs/recipes/kickassembler/screenshots/dot-flag.png +0 -0
  390. package/docs/recipes/kickassembler/screenshots/drive-job-queue-ntsc.png +0 -0
  391. package/docs/recipes/kickassembler/screenshots/drive-job-queue.png +0 -0
  392. package/docs/recipes/kickassembler/screenshots/drive-via-probe-ntsc.png +0 -0
  393. package/docs/recipes/kickassembler/screenshots/drive-via-probe.png +0 -0
  394. package/docs/recipes/kickassembler/screenshots/dycp-scroller-ntsc.png +0 -0
  395. package/docs/recipes/kickassembler/screenshots/dycp-scroller.png +0 -0
  396. package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller-ntsc.png +0 -0
  397. package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller.png +0 -0
  398. package/docs/recipes/kickassembler/screenshots/dysp-ntsc.png +0 -0
  399. package/docs/recipes/kickassembler/screenshots/dysp.png +0 -0
  400. package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc-run2.png +0 -0
  401. package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc.png +0 -0
  402. package/docs/recipes/kickassembler/screenshots/easyflash-save-run2.png +0 -0
  403. package/docs/recipes/kickassembler/screenshots/easyflash-save.png +0 -0
  404. package/docs/recipes/kickassembler/screenshots/eight-way-scroll-ntsc.png +0 -0
  405. package/docs/recipes/kickassembler/screenshots/eight-way-scroll.png +0 -0
  406. package/docs/recipes/kickassembler/screenshots/file-io-roundtrip-ntsc.png +0 -0
  407. package/docs/recipes/kickassembler/screenshots/file-io-roundtrip.png +0 -0
  408. package/docs/recipes/kickassembler/screenshots/fire-effect-ntsc.png +0 -0
  409. package/docs/recipes/kickassembler/screenshots/fire-effect.png +0 -0
  410. package/docs/recipes/kickassembler/screenshots/fld-ntsc.png +0 -0
  411. package/docs/recipes/kickassembler/screenshots/fld.png +0 -0
  412. package/docs/recipes/kickassembler/screenshots/fli-image.png +0 -0
  413. package/docs/recipes/kickassembler/screenshots/four-player-read-ntsc.png +0 -0
  414. package/docs/recipes/kickassembler/screenshots/four-player-read.png +0 -0
  415. package/docs/recipes/kickassembler/screenshots/headless-verify-ntsc.png +0 -0
  416. package/docs/recipes/kickassembler/screenshots/headless-verify.png +0 -0
  417. package/docs/recipes/kickassembler/screenshots/hello-world.png +0 -0
  418. package/docs/recipes/kickassembler/screenshots/high-score-insert-ntsc.png +0 -0
  419. package/docs/recipes/kickassembler/screenshots/high-score-insert.png +0 -0
  420. package/docs/recipes/kickassembler/screenshots/hires-plot-line-ntsc.png +0 -0
  421. package/docs/recipes/kickassembler/screenshots/hires-plot-line.png +0 -0
  422. package/docs/recipes/kickassembler/screenshots/irq-chain-ntsc.png +0 -0
  423. package/docs/recipes/kickassembler/screenshots/irq-chain.png +0 -0
  424. package/docs/recipes/kickassembler/screenshots/irq-owns-port-ntsc.png +0 -0
  425. package/docs/recipes/kickassembler/screenshots/irq-owns-port.png +0 -0
  426. package/docs/recipes/kickassembler/screenshots/isometric-room-ntsc.png +0 -0
  427. package/docs/recipes/kickassembler/screenshots/isometric-room.png +0 -0
  428. package/docs/recipes/kickassembler/screenshots/light-pen-read-ntsc.png +0 -0
  429. package/docs/recipes/kickassembler/screenshots/light-pen-read.png +0 -0
  430. package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling-ntsc.png +0 -0
  431. package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling.png +0 -0
  432. package/docs/recipes/kickassembler/screenshots/mci-interlace-average.png +0 -0
  433. package/docs/recipes/kickassembler/screenshots/mci-interlace-frame-b.png +0 -0
  434. package/docs/recipes/kickassembler/screenshots/mci-interlace-ntsc.png +0 -0
  435. package/docs/recipes/kickassembler/screenshots/mci-interlace.png +0 -0
  436. package/docs/recipes/kickassembler/screenshots/memory-layout-ntsc.png +0 -0
  437. package/docs/recipes/kickassembler/screenshots/memory-layout.png +0 -0
  438. package/docs/recipes/kickassembler/screenshots/mouse-1351-read-ntsc.png +0 -0
  439. package/docs/recipes/kickassembler/screenshots/mouse-1351-read.png +0 -0
  440. package/docs/recipes/kickassembler/screenshots/nmi-timer-tick-ntsc.png +0 -0
  441. package/docs/recipes/kickassembler/screenshots/nmi-timer-tick.png +0 -0
  442. package/docs/recipes/kickassembler/screenshots/own-keyscan-ntsc.png +0 -0
  443. package/docs/recipes/kickassembler/screenshots/own-keyscan.png +0 -0
  444. package/docs/recipes/kickassembler/screenshots/paddle-read-ntsc.png +0 -0
  445. package/docs/recipes/kickassembler/screenshots/paddle-read.png +0 -0
  446. package/docs/recipes/kickassembler/screenshots/palette-cells-ntsc.png +0 -0
  447. package/docs/recipes/kickassembler/screenshots/palette-cells.png +0 -0
  448. package/docs/recipes/kickassembler/screenshots/pseudo-3d-road-ntsc.png +0 -0
  449. package/docs/recipes/kickassembler/screenshots/pseudo-3d-road.png +0 -0
  450. package/docs/recipes/kickassembler/screenshots/pwm-digi-ntsc.png +0 -0
  451. package/docs/recipes/kickassembler/screenshots/pwm-digi.png +0 -0
  452. package/docs/recipes/kickassembler/screenshots/raster-bars.png +0 -0
  453. package/docs/recipes/kickassembler/screenshots/reu-dma-ntsc.png +0 -0
  454. package/docs/recipes/kickassembler/screenshots/reu-dma.png +0 -0
  455. package/docs/recipes/kickassembler/screenshots/runtime-relocation-ntsc.png +0 -0
  456. package/docs/recipes/kickassembler/screenshots/runtime-relocation.png +0 -0
  457. package/docs/recipes/kickassembler/screenshots/screen-dissolve-ntsc.png +0 -0
  458. package/docs/recipes/kickassembler/screenshots/screen-dissolve.png +0 -0
  459. package/docs/recipes/kickassembler/screenshots/screen-wipe-ntsc.png +0 -0
  460. package/docs/recipes/kickassembler/screenshots/screen-wipe.png +0 -0
  461. package/docs/recipes/kickassembler/screenshots/scroll-panel-split-ntsc.png +0 -0
  462. package/docs/recipes/kickassembler/screenshots/scroll-panel-split.png +0 -0
  463. package/docs/recipes/kickassembler/screenshots/sfx-in-player-ntsc.png +0 -0
  464. package/docs/recipes/kickassembler/screenshots/sfx-in-player.png +0 -0
  465. package/docs/recipes/kickassembler/screenshots/shadebobs-ntsc.png +0 -0
  466. package/docs/recipes/kickassembler/screenshots/shadebobs.png +0 -0
  467. package/docs/recipes/kickassembler/screenshots/sideborder-open.png +0 -0
  468. package/docs/recipes/kickassembler/screenshots/sine-scroller.png +0 -0
  469. package/docs/recipes/kickassembler/screenshots/sine-table-runtime-ntsc.png +0 -0
  470. package/docs/recipes/kickassembler/screenshots/sine-table-runtime.png +0 -0
  471. package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted-ntsc.png +0 -0
  472. package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted.png +0 -0
  473. package/docs/recipes/kickassembler/screenshots/speedcode-generator-ntsc.png +0 -0
  474. package/docs/recipes/kickassembler/screenshots/speedcode-generator.png +0 -0
  475. package/docs/recipes/kickassembler/screenshots/sprite-border-scroller-ntsc.png +0 -0
  476. package/docs/recipes/kickassembler/screenshots/sprite-border-scroller.png +0 -0
  477. package/docs/recipes/kickassembler/screenshots/sprite-cache-flip-ntsc.png +0 -0
  478. package/docs/recipes/kickassembler/screenshots/sprite-cache-flip.png +0 -0
  479. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-24.png +0 -0
  480. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game-ntsc.png +0 -0
  481. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game.png +0 -0
  482. package/docs/recipes/kickassembler/screenshots/sprite-priority-classes-ntsc.png +0 -0
  483. package/docs/recipes/kickassembler/screenshots/sprite-priority-classes.png +0 -0
  484. package/docs/recipes/kickassembler/screenshots/sprite-sine-chain-ntsc.png +0 -0
  485. package/docs/recipes/kickassembler/screenshots/sprite-sine-chain.png +0 -0
  486. package/docs/recipes/kickassembler/screenshots/sprite-stretcher-ntsc.png +0 -0
  487. package/docs/recipes/kickassembler/screenshots/sprite-stretcher.png +0 -0
  488. package/docs/recipes/kickassembler/screenshots/sprites-only-screen-ntsc.png +0 -0
  489. package/docs/recipes/kickassembler/screenshots/sprites-only-screen.png +0 -0
  490. package/docs/recipes/kickassembler/screenshots/sqrt-atan2-ntsc.png +0 -0
  491. package/docs/recipes/kickassembler/screenshots/sqrt-atan2.png +0 -0
  492. package/docs/recipes/kickassembler/screenshots/stable-raster-irq-control.png +0 -0
  493. package/docs/recipes/kickassembler/screenshots/stable-raster-irq.png +0 -0
  494. package/docs/recipes/kickassembler/screenshots/tech-tech-ntsc.png +0 -0
  495. package/docs/recipes/kickassembler/screenshots/tech-tech.png +0 -0
  496. package/docs/recipes/kickassembler/screenshots/tod-alarm-ntsc.png +0 -0
  497. package/docs/recipes/kickassembler/screenshots/tod-alarm.png +0 -0
  498. package/docs/recipes/kickassembler/screenshots/topbottom-border-open.png +0 -0
  499. package/docs/recipes/kickassembler/screenshots/twister-ntsc.png +0 -0
  500. package/docs/recipes/kickassembler/screenshots/twister.png +0 -0
  501. package/docs/recipes/kickassembler/screenshots/unit-test-driver-ntsc.png +0 -0
  502. package/docs/recipes/kickassembler/screenshots/unit-test-driver.png +0 -0
  503. package/docs/recipes/kickassembler/screenshots/vector-balls-ntsc.png +0 -0
  504. package/docs/recipes/kickassembler/screenshots/vector-balls.png +0 -0
  505. package/docs/recipes/kickassembler/screenshots/wireframe-ships-ntsc.png +0 -0
  506. package/docs/recipes/kickassembler/screenshots/wireframe-ships.png +0 -0
  507. package/docs/recipes/kickassembler/scroll-panel-split.md +381 -0
  508. package/docs/recipes/kickassembler/sfx-in-player.md +907 -0
  509. package/docs/recipes/kickassembler/shadebobs.md +522 -0
  510. package/docs/recipes/kickassembler/sideborder-open.md +338 -0
  511. package/docs/recipes/kickassembler/sine-scroller.md +321 -0
  512. package/docs/recipes/kickassembler/sine-table-runtime.md +815 -0
  513. package/docs/recipes/kickassembler/software-sprite-preshifted.md +725 -0
  514. package/docs/recipes/kickassembler/speedcode-generator.md +606 -0
  515. package/docs/recipes/kickassembler/sprite-border-scroller.md +696 -0
  516. package/docs/recipes/kickassembler/sprite-cache-flip.md +1071 -0
  517. package/docs/recipes/kickassembler/sprite-multiplex-24.md +326 -0
  518. package/docs/recipes/kickassembler/sprite-multiplex-game.md +986 -0
  519. package/docs/recipes/kickassembler/sprite-priority-classes.md +463 -0
  520. package/docs/recipes/kickassembler/sprite-sine-chain.md +338 -0
  521. package/docs/recipes/kickassembler/sprite-stretcher.md +501 -0
  522. package/docs/recipes/kickassembler/sprites-only-screen.md +550 -0
  523. package/docs/recipes/kickassembler/sqrt-atan2.md +1014 -0
  524. package/docs/recipes/kickassembler/stable-raster-irq.md +360 -0
  525. package/docs/recipes/kickassembler/tape-turbo-loader.md +875 -0
  526. package/docs/recipes/kickassembler/tech-tech.md +679 -0
  527. package/docs/recipes/kickassembler/tod-alarm.md +754 -0
  528. package/docs/recipes/kickassembler/topbottom-border-open.md +407 -0
  529. package/docs/recipes/kickassembler/twister.md +518 -0
  530. package/docs/recipes/kickassembler/unit-test-driver.md +314 -0
  531. package/docs/recipes/kickassembler/vector-balls.md +545 -0
  532. package/docs/recipes/kickassembler/wireframe-ships.md +2324 -0
  533. package/docs/recipes/oscar64/actor-activation-window.md +807 -0
  534. package/docs/recipes/oscar64/adventure-engine.md +1094 -0
  535. package/docs/recipes/oscar64/attract-replay.md +465 -0
  536. package/docs/recipes/oscar64/beat-em-up-lanes.md +563 -0
  537. package/docs/recipes/oscar64/bfs-distance-map.md +723 -0
  538. package/docs/recipes/oscar64/bitmap-koala-viewer.md +355 -0
  539. package/docs/recipes/oscar64/car-contact.md +950 -0
  540. package/docs/recipes/oscar64/cave-scan.md +609 -0
  541. package/docs/recipes/oscar64/char-bullets.md +477 -0
  542. package/docs/recipes/oscar64/charset-animation.md +383 -0
  543. package/docs/recipes/oscar64/charset-parallax.md +401 -0
  544. package/docs/recipes/oscar64/destructible-terrain.md +1099 -0
  545. package/docs/recipes/oscar64/difficulty-tables.md +654 -0
  546. package/docs/recipes/oscar64/dig-and-guards.md +975 -0
  547. package/docs/recipes/oscar64/directory-reader.md +535 -0
  548. package/docs/recipes/oscar64/divide-check.md +581 -0
  549. package/docs/recipes/oscar64/double-buffer-nomirror.md +205 -0
  550. package/docs/recipes/oscar64/double-buffer.md +255 -0
  551. package/docs/recipes/oscar64/falling-blocks.md +874 -0
  552. package/docs/recipes/oscar64/fixed-point-jump-velocity.md +289 -0
  553. package/docs/recipes/oscar64/fixed-point-jump.md +210 -0
  554. package/docs/recipes/oscar64/flip-screen-rooms.md +793 -0
  555. package/docs/recipes/oscar64/frame-sync-loop-overrun.md +214 -0
  556. package/docs/recipes/oscar64/frame-sync-loop.md +254 -0
  557. package/docs/recipes/oscar64/game-tree-search.md +743 -0
  558. package/docs/recipes/oscar64/ghost-targeting.md +867 -0
  559. package/docs/recipes/oscar64/headless-verify.md +345 -0
  560. package/docs/recipes/oscar64/hello-world.md +83 -0
  561. package/docs/recipes/oscar64/high-score-persist.md +772 -0
  562. package/docs/recipes/oscar64/iffl-kernal-skip.md +421 -0
  563. package/docs/recipes/oscar64/joystick-input.md +358 -0
  564. package/docs/recipes/oscar64/lane-pursuit.md +1028 -0
  565. package/docs/recipes/oscar64/level-rle-decoder.md +620 -0
  566. package/docs/recipes/oscar64/lfsr-random-seed2.md +338 -0
  567. package/docs/recipes/oscar64/lfsr-random.md +403 -0
  568. package/docs/recipes/oscar64/load-asset-runtime.md +492 -0
  569. package/docs/recipes/oscar64/memory-layout.md +232 -0
  570. package/docs/recipes/oscar64/mixed-fighters.md +781 -0
  571. package/docs/recipes/oscar64/multi-sprite-object.md +533 -0
  572. package/docs/recipes/oscar64/nav-area-pathfinding.md +881 -0
  573. package/docs/recipes/oscar64/object-pool.md +572 -0
  574. package/docs/recipes/oscar64/pal-ntsc-detect.md +257 -0
  575. package/docs/recipes/oscar64/password-state.md +532 -0
  576. package/docs/recipes/oscar64/per-frame-hitbox.md +651 -0
  577. package/docs/recipes/oscar64/petscii-screen-codes.md +428 -0
  578. package/docs/recipes/oscar64/platformer-scaffold.md +1467 -0
  579. package/docs/recipes/oscar64/print-number.md +367 -0
  580. package/docs/recipes/oscar64/raster-bars.md +239 -0
  581. package/docs/recipes/oscar64/raster-profile-bars.md +404 -0
  582. package/docs/recipes/oscar64/rel-side-sectors.md +391 -0
  583. package/docs/recipes/oscar64/relative-file-records.md +378 -0
  584. package/docs/recipes/oscar64/save-load-seq-file.md +365 -0
  585. package/docs/recipes/oscar64/screenshots/README.md +99 -0
  586. package/docs/recipes/oscar64/screenshots/actor-activation-window-ntsc.png +0 -0
  587. package/docs/recipes/oscar64/screenshots/actor-activation-window.png +0 -0
  588. package/docs/recipes/oscar64/screenshots/adventure-engine-ntsc.png +0 -0
  589. package/docs/recipes/oscar64/screenshots/adventure-engine.png +0 -0
  590. package/docs/recipes/oscar64/screenshots/attract-replay-ntsc.png +0 -0
  591. package/docs/recipes/oscar64/screenshots/attract-replay.png +0 -0
  592. package/docs/recipes/oscar64/screenshots/beat-em-up-lanes-ntsc.png +0 -0
  593. package/docs/recipes/oscar64/screenshots/beat-em-up-lanes.png +0 -0
  594. package/docs/recipes/oscar64/screenshots/bfs-distance-map-ntsc.png +0 -0
  595. package/docs/recipes/oscar64/screenshots/bfs-distance-map.png +0 -0
  596. package/docs/recipes/oscar64/screenshots/bitmap-koala-viewer.png +0 -0
  597. package/docs/recipes/oscar64/screenshots/car-contact-ntsc.png +0 -0
  598. package/docs/recipes/oscar64/screenshots/car-contact.png +0 -0
  599. package/docs/recipes/oscar64/screenshots/cave-scan-ntsc.png +0 -0
  600. package/docs/recipes/oscar64/screenshots/cave-scan.png +0 -0
  601. package/docs/recipes/oscar64/screenshots/char-bullets-ntsc.png +0 -0
  602. package/docs/recipes/oscar64/screenshots/char-bullets.png +0 -0
  603. package/docs/recipes/oscar64/screenshots/charset-animation-ntsc.png +0 -0
  604. package/docs/recipes/oscar64/screenshots/charset-animation.png +0 -0
  605. package/docs/recipes/oscar64/screenshots/charset-parallax-ntsc.png +0 -0
  606. package/docs/recipes/oscar64/screenshots/charset-parallax.png +0 -0
  607. package/docs/recipes/oscar64/screenshots/destructible-terrain-ntsc.png +0 -0
  608. package/docs/recipes/oscar64/screenshots/destructible-terrain.png +0 -0
  609. package/docs/recipes/oscar64/screenshots/difficulty-tables-ntsc.png +0 -0
  610. package/docs/recipes/oscar64/screenshots/difficulty-tables.png +0 -0
  611. package/docs/recipes/oscar64/screenshots/dig-and-guards-ntsc.png +0 -0
  612. package/docs/recipes/oscar64/screenshots/dig-and-guards.png +0 -0
  613. package/docs/recipes/oscar64/screenshots/directory-reader-ntsc.png +0 -0
  614. package/docs/recipes/oscar64/screenshots/directory-reader.png +0 -0
  615. package/docs/recipes/oscar64/screenshots/divide-check-ntsc.png +0 -0
  616. package/docs/recipes/oscar64/screenshots/divide-check.png +0 -0
  617. package/docs/recipes/oscar64/screenshots/double-buffer-nomirror.png +0 -0
  618. package/docs/recipes/oscar64/screenshots/double-buffer-ntsc.png +0 -0
  619. package/docs/recipes/oscar64/screenshots/double-buffer.png +0 -0
  620. package/docs/recipes/oscar64/screenshots/falling-blocks-ntsc.png +0 -0
  621. package/docs/recipes/oscar64/screenshots/falling-blocks.png +0 -0
  622. package/docs/recipes/oscar64/screenshots/fixed-point-jump-ntsc.png +0 -0
  623. package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity-ntsc.png +0 -0
  624. package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity.png +0 -0
  625. package/docs/recipes/oscar64/screenshots/fixed-point-jump.png +0 -0
  626. package/docs/recipes/oscar64/screenshots/flip-screen-rooms-ntsc.png +0 -0
  627. package/docs/recipes/oscar64/screenshots/flip-screen-rooms.png +0 -0
  628. package/docs/recipes/oscar64/screenshots/frame-sync-loop-ntsc.png +0 -0
  629. package/docs/recipes/oscar64/screenshots/frame-sync-loop-overrun.png +0 -0
  630. package/docs/recipes/oscar64/screenshots/frame-sync-loop.png +0 -0
  631. package/docs/recipes/oscar64/screenshots/game-tree-search-ntsc.png +0 -0
  632. package/docs/recipes/oscar64/screenshots/game-tree-search.png +0 -0
  633. package/docs/recipes/oscar64/screenshots/ghost-targeting-ntsc.png +0 -0
  634. package/docs/recipes/oscar64/screenshots/ghost-targeting.png +0 -0
  635. package/docs/recipes/oscar64/screenshots/headless-verify-ntsc.png +0 -0
  636. package/docs/recipes/oscar64/screenshots/headless-verify.png +0 -0
  637. package/docs/recipes/oscar64/screenshots/hello-world.png +0 -0
  638. package/docs/recipes/oscar64/screenshots/high-score-persist-ntsc.png +0 -0
  639. package/docs/recipes/oscar64/screenshots/high-score-persist.png +0 -0
  640. package/docs/recipes/oscar64/screenshots/iffl-kernal-skip-ntsc.png +0 -0
  641. package/docs/recipes/oscar64/screenshots/iffl-kernal-skip.png +0 -0
  642. package/docs/recipes/oscar64/screenshots/joystick-input-ntsc.png +0 -0
  643. package/docs/recipes/oscar64/screenshots/joystick-input.png +0 -0
  644. package/docs/recipes/oscar64/screenshots/lane-pursuit-ntsc.png +0 -0
  645. package/docs/recipes/oscar64/screenshots/lane-pursuit.png +0 -0
  646. package/docs/recipes/oscar64/screenshots/level-rle-decoder-ntsc.png +0 -0
  647. package/docs/recipes/oscar64/screenshots/level-rle-decoder.png +0 -0
  648. package/docs/recipes/oscar64/screenshots/lfsr-random-ntsc.png +0 -0
  649. package/docs/recipes/oscar64/screenshots/lfsr-random-seed2.png +0 -0
  650. package/docs/recipes/oscar64/screenshots/lfsr-random.png +0 -0
  651. package/docs/recipes/oscar64/screenshots/load-asset-runtime-ntsc.png +0 -0
  652. package/docs/recipes/oscar64/screenshots/load-asset-runtime.png +0 -0
  653. package/docs/recipes/oscar64/screenshots/memory-layout-ntsc.png +0 -0
  654. package/docs/recipes/oscar64/screenshots/memory-layout.png +0 -0
  655. package/docs/recipes/oscar64/screenshots/mixed-fighters-ntsc.png +0 -0
  656. package/docs/recipes/oscar64/screenshots/mixed-fighters.png +0 -0
  657. package/docs/recipes/oscar64/screenshots/multi-sprite-object-ntsc.png +0 -0
  658. package/docs/recipes/oscar64/screenshots/multi-sprite-object.png +0 -0
  659. package/docs/recipes/oscar64/screenshots/nav-area-pathfinding-ntsc.png +0 -0
  660. package/docs/recipes/oscar64/screenshots/nav-area-pathfinding.png +0 -0
  661. package/docs/recipes/oscar64/screenshots/object-pool-ntsc.png +0 -0
  662. package/docs/recipes/oscar64/screenshots/object-pool.png +0 -0
  663. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-ntsc.png +0 -0
  664. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-oldntsc.png +0 -0
  665. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-pal.png +0 -0
  666. package/docs/recipes/oscar64/screenshots/password-state-ntsc.png +0 -0
  667. package/docs/recipes/oscar64/screenshots/password-state.png +0 -0
  668. package/docs/recipes/oscar64/screenshots/per-frame-hitbox-ntsc.png +0 -0
  669. package/docs/recipes/oscar64/screenshots/per-frame-hitbox.png +0 -0
  670. package/docs/recipes/oscar64/screenshots/petscii-screen-codes-ntsc.png +0 -0
  671. package/docs/recipes/oscar64/screenshots/petscii-screen-codes.png +0 -0
  672. package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64-ntsc.png +0 -0
  673. package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64.png +0 -0
  674. package/docs/recipes/oscar64/screenshots/platformer-scaffold-ntsc.png +0 -0
  675. package/docs/recipes/oscar64/screenshots/platformer-scaffold.png +0 -0
  676. package/docs/recipes/oscar64/screenshots/print-number-ntsc.png +0 -0
  677. package/docs/recipes/oscar64/screenshots/print-number.png +0 -0
  678. package/docs/recipes/oscar64/screenshots/raster-bars.png +0 -0
  679. package/docs/recipes/oscar64/screenshots/raster-profile-bars-ntsc.png +0 -0
  680. package/docs/recipes/oscar64/screenshots/raster-profile-bars.png +0 -0
  681. package/docs/recipes/oscar64/screenshots/rel-side-sectors-ntsc.png +0 -0
  682. package/docs/recipes/oscar64/screenshots/rel-side-sectors.png +0 -0
  683. package/docs/recipes/oscar64/screenshots/relative-file-records-ntsc.png +0 -0
  684. package/docs/recipes/oscar64/screenshots/relative-file-records.png +0 -0
  685. package/docs/recipes/oscar64/screenshots/save-load-seq-file-ntsc.png +0 -0
  686. package/docs/recipes/oscar64/screenshots/save-load-seq-file.png +0 -0
  687. package/docs/recipes/oscar64/screenshots/seeded-level-fill-ntsc.png +0 -0
  688. package/docs/recipes/oscar64/screenshots/seeded-level-fill.png +0 -0
  689. package/docs/recipes/oscar64/screenshots/sfx-engine-ntsc.png +0 -0
  690. package/docs/recipes/oscar64/screenshots/sfx-engine.png +0 -0
  691. package/docs/recipes/oscar64/screenshots/sid-music-player.png +0 -0
  692. package/docs/recipes/oscar64/screenshots/simple-shmup.png +0 -0
  693. package/docs/recipes/oscar64/screenshots/slope-collision-ntsc.png +0 -0
  694. package/docs/recipes/oscar64/screenshots/slope-collision.png +0 -0
  695. package/docs/recipes/oscar64/screenshots/soft-scroll-h.png +0 -0
  696. package/docs/recipes/oscar64/screenshots/sprite-animation-table-ntsc.png +0 -0
  697. package/docs/recipes/oscar64/screenshots/sprite-animation-table.png +0 -0
  698. package/docs/recipes/oscar64/screenshots/sprite-multiplex-8.png +0 -0
  699. package/docs/recipes/oscar64/screenshots/stable-raster-irq.png +0 -0
  700. package/docs/recipes/oscar64/screenshots/text-input-ntsc.png +0 -0
  701. package/docs/recipes/oscar64/screenshots/text-input.png +0 -0
  702. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-gameover.png +0 -0
  703. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-notrail-control.png +0 -0
  704. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ntsc.png +0 -0
  705. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ungated-control.png +0 -0
  706. package/docs/recipes/oscar64/screenshots/text-overlay-playfield.png +0 -0
  707. package/docs/recipes/oscar64/screenshots/text-window-menu-ntsc.png +0 -0
  708. package/docs/recipes/oscar64/screenshots/text-window-menu.png +0 -0
  709. package/docs/recipes/oscar64/screenshots/tile-grid-collision-ntsc.png +0 -0
  710. package/docs/recipes/oscar64/screenshots/tile-grid-collision.png +0 -0
  711. package/docs/recipes/oscar64/screenshots/tile-map-render-ntsc.png +0 -0
  712. package/docs/recipes/oscar64/screenshots/tile-map-render.png +0 -0
  713. package/docs/recipes/oscar64/screenshots/two-player-ntsc.png +0 -0
  714. package/docs/recipes/oscar64/screenshots/two-player.png +0 -0
  715. package/docs/recipes/oscar64/screenshots/two-word-parser-ntsc.png +0 -0
  716. package/docs/recipes/oscar64/screenshots/two-word-parser.png +0 -0
  717. package/docs/recipes/oscar64/screenshots/vehicle-control-ntsc.png +0 -0
  718. package/docs/recipes/oscar64/screenshots/vehicle-control.png +0 -0
  719. package/docs/recipes/oscar64/screenshots/wave-director-ntsc.png +0 -0
  720. package/docs/recipes/oscar64/screenshots/wave-director.png +0 -0
  721. package/docs/recipes/oscar64/seeded-level-fill.md +364 -0
  722. package/docs/recipes/oscar64/sfx-engine.md +514 -0
  723. package/docs/recipes/oscar64/sid-music-player.md +441 -0
  724. package/docs/recipes/oscar64/simple-shmup.md +1000 -0
  725. package/docs/recipes/oscar64/slope-collision.md +610 -0
  726. package/docs/recipes/oscar64/soft-scroll-h.md +261 -0
  727. package/docs/recipes/oscar64/sprite-animation-table.md +671 -0
  728. package/docs/recipes/oscar64/sprite-multiplex-8.md +314 -0
  729. package/docs/recipes/oscar64/stable-raster-irq.md +236 -0
  730. package/docs/recipes/oscar64/text-input.md +274 -0
  731. package/docs/recipes/oscar64/text-overlay-playfield.md +617 -0
  732. package/docs/recipes/oscar64/text-window-menu.md +551 -0
  733. package/docs/recipes/oscar64/tile-grid-collision.md +563 -0
  734. package/docs/recipes/oscar64/tile-map-render.md +395 -0
  735. package/docs/recipes/oscar64/two-player.md +528 -0
  736. package/docs/recipes/oscar64/two-word-parser.md +510 -0
  737. package/docs/recipes/oscar64/vehicle-control.md +771 -0
  738. package/docs/recipes/oscar64/wave-director.md +787 -0
  739. package/docs/recipes/runs.json +1606 -0
  740. package/docs/runtime/sim6502-reference.md +466 -0
  741. package/docs/runtime/vice-mcp-reference.md +351 -0
  742. package/docs/runtime/vice-reference.md +1393 -0
  743. package/docs/techniques/bitmap-modes.md +685 -0
  744. package/docs/techniques/cpu-cycle-tricks.md +1570 -0
  745. package/docs/techniques/effects-vector-3d.md +1431 -0
  746. package/docs/techniques/file-io.md +1427 -0
  747. package/docs/techniques/input.md +1072 -0
  748. package/docs/techniques/loaders-packers.md +768 -0
  749. package/docs/techniques/logic.md +3091 -0
  750. package/docs/techniques/maths.md +1524 -0
  751. package/docs/techniques/memory-banking.md +1686 -0
  752. package/docs/techniques/music-sid.md +1144 -0
  753. package/docs/techniques/raster.md +1543 -0
  754. package/docs/techniques/scroll.md +1292 -0
  755. package/docs/techniques/sprite.md +2566 -0
  756. package/docs/techniques/text-mode-render.md +717 -0
  757. package/docs/techniques/text.md +1095 -0
  758. package/docs/techniques/transitions.md +405 -0
  759. package/docs/toolchains/cartconv-reference.md +262 -0
  760. package/docs/toolchains/cc1541-reference.md +316 -0
  761. package/docs/toolchains/cc65-reference.md +667 -0
  762. package/docs/toolchains/error-sources/cc65/README.md +1 -0
  763. package/docs/toolchains/error-sources/cc65/missing-setcpu.s +4 -0
  764. package/docs/toolchains/error-sources/cc65/range-error.s +4 -0
  765. package/docs/toolchains/error-sources/cc65/segment-overflow.c +6 -0
  766. package/docs/toolchains/error-sources/cc65/unresolved-external.c +6 -0
  767. package/docs/toolchains/error-sources/kickassembler/README.md +1 -0
  768. package/docs/toolchains/error-sources/kickassembler/branch-out-of-range.asm +4 -0
  769. package/docs/toolchains/error-sources/kickassembler/failed-assert.asm +3 -0
  770. package/docs/toolchains/error-sources/kickassembler/flat-lib.asm +4 -0
  771. package/docs/toolchains/error-sources/kickassembler/import-source-no-namespace.asm +5 -0
  772. package/docs/toolchains/error-sources/kickassembler/macro-without-parentheses.asm +6 -0
  773. package/docs/toolchains/error-sources/kickassembler/memory-block-overlap.asm +4 -0
  774. package/docs/toolchains/error-sources/kickassembler/symbol-clash-lib.asm +5 -0
  775. package/docs/toolchains/error-sources/kickassembler/symbol-clash-main.asm +6 -0
  776. package/docs/toolchains/error-sources/kickassembler/unknown-symbol.asm +4 -0
  777. package/docs/toolchains/error-sources/oscar64/README.md +1 -0
  778. package/docs/toolchains/error-sources/oscar64/asm-addressing-mode.c +7 -0
  779. package/docs/toolchains/error-sources/oscar64/region-overflow.c +6 -0
  780. package/docs/toolchains/error-sources/oscar64/undefined-extern-var.c +5 -0
  781. package/docs/toolchains/error-sources/oscar64/undefined-extern.c +6 -0
  782. package/docs/toolchains/error-sources/oscar64/unknown-vic-field.c +6 -0
  783. package/docs/toolchains/error-sources/oscar64/void-main.c +3 -0
  784. package/docs/toolchains/kickassembler-reference.md +1020 -0
  785. package/docs/toolchains/memory-layout-planning.md +362 -0
  786. package/docs/toolchains/oscar64-headers-reference.md +583 -0
  787. package/docs/toolchains/oscar64-reference.md +892 -0
  788. package/docs/toolchains/petcat-reference.md +290 -0
  789. package/docs/toolchains/png2prg.md +188 -0
  790. package/docs/toolchains/release-disk.md +314 -0
  791. package/docs/toolchains/sidreloc.md +236 -0
  792. package/docs/toolchains/spindle-reference.md +487 -0
  793. package/docs/toolchains/tape-mastering.md +592 -0
  794. package/docs/toolchains/unit-testing-6502.md +281 -0
  795. package/docs/workflow/agent-harness.md +478 -0
  796. package/package.json +105 -0
  797. package/templates/_harness/CLAUDE.md.template +91 -0
  798. package/templates/_harness/PLAN.md.template +72 -0
  799. package/templates/_harness/check.py +442 -0
  800. package/templates/_harness/claude/settings.json +17 -0
  801. package/templates/_harness/gen-asm-header.py +96 -0
  802. package/templates/_harness/harness.mk +273 -0
  803. package/templates/_harness/hooks/plan-gate.py +185 -0
  804. package/templates/_harness/meter/frame_meter.asm +311 -0
  805. package/templates/_harness/meter/frame_meter.c +155 -0
  806. package/templates/_harness/meter/frame_meter.h +80 -0
  807. package/templates/_harness/zp-used.py +104 -0
  808. package/templates/action-puzzle/.claude/settings.json +17 -0
  809. package/templates/action-puzzle/.mcp.json +10 -0
  810. package/templates/action-puzzle/CLAUDE.md +120 -0
  811. package/templates/action-puzzle/Makefile +125 -0
  812. package/templates/action-puzzle/PLAN.md +388 -0
  813. package/templates/action-puzzle/README.md +240 -0
  814. package/templates/action-puzzle/expect.json +25 -0
  815. package/templates/action-puzzle/src/cave.c +280 -0
  816. package/templates/action-puzzle/src/cave.h +80 -0
  817. package/templates/action-puzzle/src/gen_autopilot.h +20 -0
  818. package/templates/action-puzzle/src/gen_caves.h +59 -0
  819. package/templates/action-puzzle/src/gen_notes.h +16 -0
  820. package/templates/action-puzzle/src/hiscore.c +152 -0
  821. package/templates/action-puzzle/src/hiscore.h +41 -0
  822. package/templates/action-puzzle/src/level.c +64 -0
  823. package/templates/action-puzzle/src/level.h +24 -0
  824. package/templates/action-puzzle/src/main.c +599 -0
  825. package/templates/action-puzzle/src/render.c +239 -0
  826. package/templates/action-puzzle/src/render.h +31 -0
  827. package/templates/action-puzzle/src/sound.c +158 -0
  828. package/templates/action-puzzle/src/sound.h +22 -0
  829. package/templates/action-puzzle/tools/disk_check.py +77 -0
  830. package/templates/action-puzzle/tools/drive.py +106 -0
  831. package/templates/action-puzzle/tools/gen.py +454 -0
  832. package/templates/action-puzzle/tools/model_check.py +49 -0
  833. package/templates/action-puzzle/tools/verdict_codes.py +24 -0
  834. package/templates/adventure/.claude/settings.json +17 -0
  835. package/templates/adventure/.mcp.json +10 -0
  836. package/templates/adventure/CLAUDE.md +118 -0
  837. package/templates/adventure/Makefile +113 -0
  838. package/templates/adventure/PLAN.md +396 -0
  839. package/templates/adventure/README.md +277 -0
  840. package/templates/adventure/expect.json +25 -0
  841. package/templates/adventure/src/engine.c +543 -0
  842. package/templates/adventure/src/engine.h +48 -0
  843. package/templates/adventure/src/gen_script.h +141 -0
  844. package/templates/adventure/src/gen_world.h +511 -0
  845. package/templates/adventure/src/main.c +439 -0
  846. package/templates/adventure/src/picture.c +83 -0
  847. package/templates/adventure/src/picture.h +16 -0
  848. package/templates/adventure/src/save.c +159 -0
  849. package/templates/adventure/src/save.h +25 -0
  850. package/templates/adventure/src/sound.c +71 -0
  851. package/templates/adventure/src/sound.h +16 -0
  852. package/templates/adventure/src/text.c +349 -0
  853. package/templates/adventure/src/text.h +40 -0
  854. package/templates/adventure/tools/disk_check.py +128 -0
  855. package/templates/adventure/tools/drive.py +119 -0
  856. package/templates/adventure/tools/gen.py +1033 -0
  857. package/templates/adventure/tools/world.py +356 -0
  858. package/templates/beat-em-up/.claude/settings.json +17 -0
  859. package/templates/beat-em-up/.mcp.json +10 -0
  860. package/templates/beat-em-up/CLAUDE.md +136 -0
  861. package/templates/beat-em-up/Makefile +96 -0
  862. package/templates/beat-em-up/PLAN.md +502 -0
  863. package/templates/beat-em-up/README.md +315 -0
  864. package/templates/beat-em-up/expect-gameover.json +8 -0
  865. package/templates/beat-em-up/expect.json +29 -0
  866. package/templates/beat-em-up/src/anim.c +70 -0
  867. package/templates/beat-em-up/src/art.c +344 -0
  868. package/templates/beat-em-up/src/autopilot.h +154 -0
  869. package/templates/beat-em-up/src/brute.c +273 -0
  870. package/templates/beat-em-up/src/enemy.c +281 -0
  871. package/templates/beat-em-up/src/engine.asm +512 -0
  872. package/templates/beat-em-up/src/fighter.c +384 -0
  873. package/templates/beat-em-up/src/game.h +269 -0
  874. package/templates/beat-em-up/src/hud.c +135 -0
  875. package/templates/beat-em-up/src/main.c +341 -0
  876. package/templates/beat-em-up/src/sound.c +44 -0
  877. package/templates/beat-em-up/src/street.c +93 -0
  878. package/templates/beat-em-up/src/verdict.h +523 -0
  879. package/templates/beat-em-up/src/view.c +362 -0
  880. package/templates/beat-em-up/tools/drive.py +105 -0
  881. package/templates/beat-em-up/tools/flickercheck.py +273 -0
  882. package/templates/demo/.claude/settings.json +17 -0
  883. package/templates/demo/.mcp.json +10 -0
  884. package/templates/demo/CLAUDE.md +129 -0
  885. package/templates/demo/Makefile +66 -0
  886. package/templates/demo/PLAN.md +401 -0
  887. package/templates/demo/README.md +322 -0
  888. package/templates/demo/expect.json +945 -0
  889. package/templates/demo/src/config.asm +80 -0
  890. package/templates/demo/src/framework.asm +390 -0
  891. package/templates/demo/src/main.asm +139 -0
  892. package/templates/demo/src/music.asm +197 -0
  893. package/templates/demo/src/part_main.asm +279 -0
  894. package/templates/demo/src/part_title.asm +79 -0
  895. package/templates/demo/src/parts.asm +43 -0
  896. package/templates/demo/src/tables.asm +73 -0
  897. package/templates/demo/src/verdict.asm +179 -0
  898. package/templates/demo/tools/audio.py +80 -0
  899. package/templates/demo/tools/gen_expect.py +167 -0
  900. package/templates/demo/tools/probe.py +95 -0
  901. package/templates/hello/.claude/settings.json +17 -0
  902. package/templates/hello/.mcp.json +10 -0
  903. package/templates/hello/CLAUDE.md +100 -0
  904. package/templates/hello/Makefile +38 -0
  905. package/templates/hello/PLAN.md +200 -0
  906. package/templates/hello/expect.json +20 -0
  907. package/templates/hello/src/main.c +161 -0
  908. package/templates/hello/src/sprite.asm +27 -0
  909. package/templates/hello-kick/.claude/settings.json +17 -0
  910. package/templates/hello-kick/.mcp.json +10 -0
  911. package/templates/hello-kick/CLAUDE.md +100 -0
  912. package/templates/hello-kick/Makefile +17 -0
  913. package/templates/hello-kick/PLAN.md +199 -0
  914. package/templates/hello-kick/expect.json +20 -0
  915. package/templates/hello-kick/src/main.asm +233 -0
  916. package/templates/platformer/.claude/settings.json +17 -0
  917. package/templates/platformer/.mcp.json +10 -0
  918. package/templates/platformer/CLAUDE.md +125 -0
  919. package/templates/platformer/Makefile +86 -0
  920. package/templates/platformer/PLAN.md +360 -0
  921. package/templates/platformer/README.md +277 -0
  922. package/templates/platformer/expect.json +32 -0
  923. package/templates/platformer/src/actors.c +289 -0
  924. package/templates/platformer/src/anim.c +51 -0
  925. package/templates/platformer/src/art.c +212 -0
  926. package/templates/platformer/src/autopilot.h +30 -0
  927. package/templates/platformer/src/engine.asm +253 -0
  928. package/templates/platformer/src/game.h +248 -0
  929. package/templates/platformer/src/hud.c +90 -0
  930. package/templates/platformer/src/level.c +184 -0
  931. package/templates/platformer/src/main.c +306 -0
  932. package/templates/platformer/src/player.c +268 -0
  933. package/templates/platformer/src/sound.c +42 -0
  934. package/templates/platformer/src/verdict.h +206 -0
  935. package/templates/platformer/src/view.c +331 -0
  936. package/templates/platformer/stage-expect.json +6 -0
  937. package/templates/platformer/tools/drive.py +112 -0
  938. package/templates/platformer/tools/tearcheck.py +229 -0
  939. package/templates/shmup-vertical/.claude/settings.json +17 -0
  940. package/templates/shmup-vertical/.mcp.json +10 -0
  941. package/templates/shmup-vertical/CLAUDE.md +137 -0
  942. package/templates/shmup-vertical/Makefile +131 -0
  943. package/templates/shmup-vertical/PLAN.md +569 -0
  944. package/templates/shmup-vertical/README.md +189 -0
  945. package/templates/shmup-vertical/expect.json +38 -0
  946. package/templates/shmup-vertical/src/bullets.c +158 -0
  947. package/templates/shmup-vertical/src/bullets.h +35 -0
  948. package/templates/shmup-vertical/src/display.c +239 -0
  949. package/templates/shmup-vertical/src/display.h +40 -0
  950. package/templates/shmup-vertical/src/game.h +85 -0
  951. package/templates/shmup-vertical/src/glyph.asm +358 -0
  952. package/templates/shmup-vertical/src/hiscore.c +141 -0
  953. package/templates/shmup-vertical/src/hiscore.h +16 -0
  954. package/templates/shmup-vertical/src/hit.asm +180 -0
  955. package/templates/shmup-vertical/src/hitbox.c +59 -0
  956. package/templates/shmup-vertical/src/hitbox.h +25 -0
  957. package/templates/shmup-vertical/src/kernel.asm +330 -0
  958. package/templates/shmup-vertical/src/level.c +174 -0
  959. package/templates/shmup-vertical/src/level.h +27 -0
  960. package/templates/shmup-vertical/src/main.c +824 -0
  961. package/templates/shmup-vertical/src/mux.asm +321 -0
  962. package/templates/shmup-vertical/src/sound.asm +255 -0
  963. package/templates/shmup-vertical/src/step.asm +169 -0
  964. package/templates/shmup-vertical/src/waves.c +195 -0
  965. package/templates/shmup-vertical/src/waves.h +33 -0
  966. package/templates/shmup-vertical/stage-expect.json +6 -0
  967. package/templates/shmup-vertical/tools/drive.py +152 -0
  968. package/templates/shmup-vertical/tools/joytest.py +159 -0
  969. package/templates/shmup-vertical/tools/meter.py +15 -0
  970. package/templates/shmup-vertical/tools/phases.py +73 -0
@@ -0,0 +1,454 @@
1
+ #!/usr/bin/env python3
2
+ """gen.py: the caves, the autopilot script, the rules model and the note table.
3
+
4
+ python3 tools/gen.py # writes src/gen_caves.h, gen_autopilot.h, gen_notes.h
5
+ python3 tools/gen.py --show # also prints the model's cave at game over
6
+
7
+ Edit CAVES (or SCRIPT) below, run this, rebuild. It
8
+ 1. packs every cave into the RLE row stream of c64-kb's level-rle-decoder
9
+ recipe (control byte 0x80+n: the next byte n times; 1..127: that many
10
+ literal bytes follow; 0: end of row), one stream per row of 40 cells;
11
+ 2. runs a model of the same rules as src/cave.c over the autopilot script
12
+ and writes what the program must find at game over (the cave's fold,
13
+ score, gems, play frames), which the AUTOPILOT build grades itself on;
14
+ 3. writes the SID frequency tables for PAL and NTSC.
15
+ The model is the specification of the rules: change a rule in cave.c and
16
+ here together, or the autopilot verdict turns red.
17
+ """
18
+ import os
19
+ import sys
20
+
21
+ W, H = 40, 22
22
+
23
+ # Element codes, the same numbers as src/cave.h. Bit 7 is the scanned bit.
24
+ SPACE, DIRT, BRICK, STEEL, BOULDER, BOULDER_F, GEM, GEM_F = range(8)
25
+ EXIT_SHUT, EXIT_OPEN, PLAYER = 8, 9, 10
26
+ SPARK, MOTH, BLAST, BURST = 12, 16, 20, 23 # SPARK/MOTH + heading 0..3; BLAST/BURST + stage 0..2
27
+ SCANNED = 0x80
28
+ STEP = [-1, -W, 1, W] # headings: left, up, right, down
29
+
30
+ LEGEND = {'.': DIRT, ' ': SPACE, '#': BRICK, 'S': STEEL, 'o': BOULDER, '*': GEM,
31
+ 'X': EXIT_SHUT, 'P': PLAYER, 'f': SPARK + 0, 'm': MOTH + 0}
32
+
33
+ GEM_POINTS = 10
34
+ TICK_CAVE_FRAMES = 12 # cave frames per unit of the time counter
35
+ DEATH_FRAMES = 6 # cave frames between a death and the next life
36
+ SLICE_FRAMES = 4 # display frames per cave frame (the scan's four slices)
37
+
38
+ # Each cave: name (at most 16 characters), gems needed, time, 20 interior
39
+ # rows of 38 cells (shorter rows are padded with dirt). The steel border is
40
+ # added here. One player, one exit per cave. Original layouts.
41
+ CAVES = [
42
+ ("FIRST DIG", 6, 99, [
43
+ "...........o..*.........o............",
44
+ ".P...*..*..*...*..o ...........oo...",
45
+ "...................*.....o...........",
46
+ "...................*....oo...........",
47
+ "....................XS........o .....", # the boulder on the brick end rolls right
48
+ "..........................##### .....",
49
+ ".....o...............................",
50
+ "..............####.......####........",
51
+ "....*.........# #.......# #...*....",
52
+ "..............# f#.......#m #........",
53
+ "..............# #.......# #........",
54
+ "..............####.......####........",
55
+ "." * 11 + "o" * 16 + "." * 11, # boulder rain: 16 fall and land in one
56
+ "." + " " * 36 + ".", # slice and overflow the dirty list, so
57
+ "", # the gated run meets render.c's row queue
58
+ "",
59
+ "..............*..........#####.......",
60
+ "......o..............................",
61
+ "......*........o..............*......",
62
+ "",
63
+ ]),
64
+ ("BOULDER HALL", 8, 120, [
65
+ "....o................o...............",
66
+ "..........o.......................o..",
67
+ "..P..........*.........*.............",
68
+ "...............o.....f .X........",
69
+ "...........#####.....................",
70
+ "......*..............*.......*.......",
71
+ "...........o...........o.............",
72
+ "........ ...........................",
73
+ "......#####...........#####..........",
74
+ "...........*....*.........*..........",
75
+ "",
76
+ "........m .......................",
77
+ "....o.......o.......o........o.......",
78
+ "....*.......*.......*........*.......",
79
+ "",
80
+ "..........####.............####......",
81
+ "",
82
+ "...*..................*.........*....",
83
+ "",
84
+ "",
85
+ ]),
86
+ ]
87
+
88
+ # The autopilot's moves, one per cave frame: L U R D, '-' stands still.
89
+ # One string per cave start (a new cave, or the same cave after a lost
90
+ # life), keyed by the game's count of starts; past the end of a string the
91
+ # player stands still.
92
+ SCRIPT = [
93
+ "RRRRRRRRRRRRRRRRRRDDDR", # cave 1: gems, two pushes, the exit
94
+ "RRUD", # cave 2: out from under a boulder; it falls on him
95
+ "RRRRRRRRD", # cave 2 again: under another boulder, the same end
96
+ "RRUD", # cave 2, last life: game over
97
+ ]
98
+ LIVES_AUTOPILOT = 3
99
+ DEFAULT_SCORES = [400, 300, 200, 100, 50] # hiscore.c's default table
100
+ NAME_AUTOPILOT = "ABE"
101
+
102
+
103
+ def build(cave):
104
+ name, need, time, rows = cave
105
+ c = [STEEL] * (W * H)
106
+ for y in range(1, H - 1):
107
+ r = rows[y - 1] if y - 1 < len(rows) else ""
108
+ if len(r) > W - 2:
109
+ sys.exit(f"cave {name}: row {y} is {len(r)} cells, more than {W - 2}")
110
+ for x, ch in enumerate(r.ljust(W - 2, '.'), 1):
111
+ if ch not in LEGEND:
112
+ sys.exit(f"cave {name}: row {y} has '{ch}', not in the legend")
113
+ c[y * W + x] = LEGEND[ch]
114
+ for code in (PLAYER, EXIT_SHUT):
115
+ if c.count(code) != 1:
116
+ sys.exit(f"cave {name}: {c.count(code)} cells of code {code}, want 1")
117
+ return c
118
+
119
+
120
+ def rle_row(cells):
121
+ """The level-rle-decoder stream for one row: runs of 3 or more, else literals."""
122
+ out, i, lit = [], 0, []
123
+ while i < len(cells):
124
+ j = i
125
+ while j < len(cells) and cells[j] == cells[i] and j - i < 127:
126
+ j += 1
127
+ if j - i >= 3:
128
+ if lit:
129
+ out += [len(lit)] + lit
130
+ lit = []
131
+ out += [0x80 | (j - i), cells[i]]
132
+ i = j
133
+ else:
134
+ lit.append(cells[i])
135
+ i += 1
136
+ if len(lit) == 127:
137
+ out += [len(lit)] + lit
138
+ lit = []
139
+ if lit:
140
+ out += [len(lit)] + lit
141
+ return out + [0]
142
+
143
+
144
+ def rle_decode(data):
145
+ out, i = [], 0
146
+ for _ in range(H):
147
+ while True:
148
+ c = data[i]; i += 1
149
+ if c == 0:
150
+ break
151
+ if c & 0x80:
152
+ out += [data[i]] * (c & 0x7f); i += 1
153
+ else:
154
+ out += data[i:i + c]; i += c
155
+ return out
156
+
157
+
158
+ def fold(cells, chk=0):
159
+ for v in cells:
160
+ chk = ((chk ^ (v & 0x7f)) * 5 + 1) & 0xffff
161
+ return chk
162
+
163
+
164
+ class Cave:
165
+ """One cave's state and the rules. Mirrors src/cave.c line for line."""
166
+
167
+ def __init__(self, cells, need, time):
168
+ self.c = list(cells)
169
+ self.need, self.time = need, time
170
+ self.got = self.points = 0
171
+ self.dead = self.exited = self.exit_open = False
172
+ self.player = self.c.index(PLAYER)
173
+ self.exit_at = self.c.index(EXIT_SHUT)
174
+ self.tick = 0
175
+ self.move = -1
176
+ self.seen = 0
177
+
178
+ def put(self, d, v, s):
179
+ if d > s:
180
+ v |= SCANNED
181
+ self.c[d] = v
182
+ self.c[s] = SPACE
183
+ if v & 0x7f == PLAYER:
184
+ self.player = d
185
+
186
+ def explode(self, centre, kind, at):
187
+ for dy in (-W, 0, W):
188
+ for dx in (-1, 0, 1):
189
+ n = centre + dy + dx
190
+ t = self.c[n] & 0x7f
191
+ if t in (STEEL, EXIT_SHUT, EXIT_OPEN):
192
+ continue
193
+ if t == PLAYER:
194
+ self.dead = True
195
+ self.c[n] = kind | (SCANNED if n > at else 0)
196
+
197
+ def roll(self, i, fall):
198
+ for o in (-1, 1):
199
+ if self.c[i + o] == SPACE and self.c[i + W + o] == SPACE:
200
+ self.put(i + o, fall, i)
201
+ return True
202
+ return False
203
+
204
+ @staticmethod
205
+ def round_(t):
206
+ return t in (BOULDER, GEM, BRICK)
207
+
208
+ def cell(self, i):
209
+ c, v = self.c, self.c[i]
210
+ if v & SCANNED:
211
+ c[i] = v & 0x7f
212
+ return
213
+ if v in (BOULDER, GEM):
214
+ b = c[i + W]
215
+ if b == SPACE:
216
+ self.put(i + W, v + 1, i)
217
+ elif self.round_(b & 0x7f):
218
+ self.roll(i, v + 1)
219
+ elif v in (BOULDER_F, GEM_F):
220
+ b = c[i + W]; bt = b & 0x7f
221
+ if b == SPACE:
222
+ self.put(i + W, v, i)
223
+ elif bt == PLAYER:
224
+ self.explode(i + W, BLAST, i)
225
+ elif SPARK <= bt < MOTH:
226
+ self.explode(i + W, BLAST, i)
227
+ elif MOTH <= bt < BLAST:
228
+ self.explode(i + W, BURST, i)
229
+ elif bt in (BOULDER_F, GEM_F):
230
+ pass
231
+ elif not (self.round_(bt) and self.roll(i, v)):
232
+ c[i] = v - 1
233
+ elif v == PLAYER:
234
+ self.seen += 1
235
+ if 0 <= self.move < 4:
236
+ t = i + STEP[self.move]
237
+ tv = c[t]
238
+ if tv in (SPACE, DIRT):
239
+ self.put(t, PLAYER, i)
240
+ elif tv == GEM:
241
+ self.got += 1
242
+ self.points += GEM_POINTS
243
+ self.put(t, PLAYER, i)
244
+ elif tv == EXIT_OPEN:
245
+ c[i] = SPACE
246
+ self.exited = True
247
+ elif tv == BOULDER and self.move in (0, 2) and c[t + STEP[self.move]] == SPACE:
248
+ self.put(t + STEP[self.move], BOULDER, t)
249
+ self.put(t, PLAYER, i)
250
+ elif v >= BLAST:
251
+ if v in (BLAST + 2,):
252
+ c[i] = SPACE
253
+ elif v == BURST + 2:
254
+ c[i] = GEM
255
+ else:
256
+ c[i] = v + 1
257
+ elif v >= SPARK:
258
+ base = SPARK if v < MOTH else MOTH
259
+ kind = BLAST if v < MOTH else BURST
260
+ d = v & 3
261
+ for o in STEP:
262
+ if c[i + o] & 0x7f == PLAYER:
263
+ self.explode(i, kind, i)
264
+ return
265
+ first = (d + 3) & 3 if base == SPARK else (d + 1) & 3
266
+ spin = (d + 1) & 3 if base == SPARK else (d + 3) & 3
267
+ if c[i + STEP[first]] == SPACE:
268
+ self.put(i + STEP[first], base + first, i)
269
+ elif c[i + STEP[d]] == SPACE:
270
+ self.put(i + STEP[d], base + d, i)
271
+ else:
272
+ c[i] = base + spin
273
+
274
+ def scan(self):
275
+ for y in range(1, H - 1):
276
+ for x in range(1, W - 1):
277
+ i = y * W + x
278
+ if self.c[i] >= BOULDER:
279
+ self.cell(i)
280
+ assert not any(v & SCANNED for v in self.c), "a scanned bit survived the scan"
281
+
282
+ def end_of_frame(self):
283
+ """What the game does after the last slice of a cave frame."""
284
+ if not self.exit_open and self.got >= self.need:
285
+ self.c[self.exit_at] = EXIT_OPEN
286
+ self.exit_open = True
287
+ if self.exited or self.dead:
288
+ return
289
+ self.tick += 1
290
+ if self.tick == TICK_CAVE_FRAMES:
291
+ self.tick = 0
292
+ if self.time:
293
+ self.time -= 1
294
+ if self.time == 0:
295
+ self.explode(self.player, BLAST, 0xffff)
296
+
297
+
298
+ def play():
299
+ """The autopilot game, as the program plays it. Returns what it must show.
300
+
301
+ The script is keyed by the game's own counter of cave starts: SCRIPT[n]
302
+ plays the n-th start (a new cave or a restart after a lost life). The
303
+ fold is chained over every cave the game leaves, so a rule that fires in
304
+ any cave, not only the last, moves the verdict."""
305
+ score, gems, frames, lives = 0, 0, 0, LIVES_AUTOPILOT
306
+ ci, starts, chk = 0, 0, 0
307
+ while True:
308
+ name, need, time, _ = CAVES[ci]
309
+ cv = Cave(build(CAVES[ci]), need, time)
310
+ script = SCRIPT[starts] if starts < len(SCRIPT) else ""
311
+ starts += 1
312
+ f, dead_frames = 0, 0
313
+ while True:
314
+ m = script[f] if f < len(script) else '-'
315
+ cv.move = "LURD".find(m)
316
+ cv.seen = 0
317
+ cv.scan()
318
+ cv.end_of_frame()
319
+ # the scan meets the living player exactly once a cave frame
320
+ assert cv.seen <= 1 if cv.dead else cv.seen == 1, (starts, f, cv.seen)
321
+ f += 1
322
+ frames += SLICE_FRAMES
323
+ if cv.exited:
324
+ break
325
+ if cv.dead:
326
+ dead_frames += 1
327
+ if dead_frames == DEATH_FRAMES:
328
+ break
329
+ if f > 5000:
330
+ sys.exit("autopilot: the script never ends a cave")
331
+ score += cv.points
332
+ gems += cv.got
333
+ chk = fold(cv.c, chk)
334
+ if cv.exited:
335
+ score += cv.time
336
+ ci = (ci + 1) % len(CAVES)
337
+ continue
338
+ lives -= 1
339
+ if lives == 0:
340
+ rank = next((r for r, v in enumerate(DEFAULT_SCORES) if v < score), len(DEFAULT_SCORES))
341
+ return dict(fold=chk, score=score, gems=gems, cave=ci, frames=frames, starts=starts,
342
+ rank=rank, cells=[v & 0x7f for v in cv.c])
343
+
344
+
345
+ def c_array(name, data):
346
+ lines = [f"static const char {name}[{len(data)}] = {{"]
347
+ for k in range(0, len(data), 16):
348
+ lines.append(" " + ", ".join(f"0x{b:02x}" for b in data[k:k + 16]) + ",")
349
+ lines.append("};")
350
+ return "\n".join(lines)
351
+
352
+
353
+ def screen_codes(s):
354
+ return [ord(ch) - 64 if 'A' <= ch <= 'Z' else ord(ch) for ch in s]
355
+
356
+
357
+ def write_caves(path):
358
+ out = ["// gen_caves.h: written by tools/gen.py. Do not edit; edit tools/gen.py.",
359
+ f"#define CAVE_COUNT {len(CAVES)}", ""]
360
+ total = 0
361
+ for k, cave in enumerate(CAVES):
362
+ cells = build(cave)
363
+ packed = []
364
+ for y in range(H):
365
+ packed += rle_row(cells[y * W:(y + 1) * W])
366
+ assert rle_decode(packed) == cells
367
+ total += len(packed)
368
+ out.append(f"// {cave[0]}: 880 cells -> {len(packed)} bytes, fold 0x{fold(cells):04x}")
369
+ out.append(c_array(f"cave{k}_rle", packed))
370
+ out.append(c_array(f"cave{k}_name", screen_codes(cave[0].ljust(16)[:16])))
371
+ out.append("")
372
+ out.append("static const CaveInfo cave_info[CAVE_COUNT] = {")
373
+ for k, (name, need, time, _) in enumerate(CAVES):
374
+ fold0 = fold(build(CAVES[k]))
375
+ out.append(f" {{ cave{k}_rle, cave{k}_name, {need}, {time}, 0x{fold0:04x} }},")
376
+ out.append("};")
377
+ open(path, "w").write("\n".join(out) + "\n")
378
+ return total
379
+
380
+
381
+ def write_autopilot(path, result):
382
+ out = ["// gen_autopilot.h: written by tools/gen.py. Do not edit; edit tools/gen.py.",
383
+ "// The autopilot: one move per cave frame (L U R D, '-' still), per cave;",
384
+ "// past the end of a cave's string the player stands still."]
385
+ for k, s in enumerate(SCRIPT):
386
+ out.append(f'static const char script{k}[] = "{s}";')
387
+ out.append(f"static const char * const script_for[{len(SCRIPT)}] = {{ " +
388
+ ", ".join(f"script{k}" for k in range(len(SCRIPT))) + " };")
389
+ out.append(f"static const char script_len[{len(SCRIPT)}] = {{ " +
390
+ ", ".join(str(len(x)) for x in SCRIPT) + " };")
391
+ out.append(f"#define SCRIPT_STARTS {len(SCRIPT)}")
392
+ out.append(f"#define LIVES_AUTOPILOT {LIVES_AUTOPILOT}")
393
+ out.append(f'#define NAME_AUTOPILOT "{NAME_AUTOPILOT}"')
394
+ out.append("// What the rules model says the program must hold at game over.")
395
+ out.append(f"#define EXPECT_FOLD 0x{result['fold']:04x}")
396
+ out.append(f"#define EXPECT_SCORE {result['score']}UL")
397
+ out.append(f"#define EXPECT_GEMS {result['gems']}")
398
+ out.append(f"#define EXPECT_CAVE {result['cave']}")
399
+ out.append(f"#define EXPECT_PLAY_FRAMES {result['frames']}")
400
+ out.append(f"#define EXPECT_STARTS {result['starts']}")
401
+ out.append(f"#define EXPECT_RANK {result['rank']}")
402
+ open(path, "w").write("\n".join(out) + "\n")
403
+
404
+
405
+ def write_notes(path):
406
+ """SID frequency words for notes 0..59 (C1 up), A4 = 440 Hz, PAL and NTSC clocks."""
407
+ clocks = {"pal": 985248, "ntsc": 1022727}
408
+ out = ["// gen_notes.h: written by tools/gen.py. Note n is C1 + n semitones; A4 = 440 Hz.",
409
+ "// Frequency word = Hz * 16777216 / clock (PAL 985,248 Hz; NTSC 1,022,727 Hz)."]
410
+ for model, clk in clocks.items():
411
+ words = []
412
+ for n in range(60):
413
+ hz = 440.0 * 2 ** ((n - 45) / 12) # n = 45 is A4 (C1 + 45 semitones)
414
+ words.append(min(0xffff, round(hz * 16777216 / clk)))
415
+ out.append(f"static const unsigned note_{model}[60] = {{")
416
+ for k in range(0, 60, 12):
417
+ out.append(" " + ", ".join(f"0x{w:04x}" for w in words[k:k + 12]) + ",")
418
+ out.append("};")
419
+ open(path, "w").write("\n".join(out) + "\n")
420
+
421
+
422
+ def show(cells):
423
+ rev = {v: k for k, v in LEGEND.items()}
424
+ for y in range(H):
425
+ row = ""
426
+ for x in range(W):
427
+ v = cells[y * W + x] & 0x7f
428
+ if SPARK <= v < MOTH:
429
+ row += 'f'
430
+ elif MOTH <= v < BLAST:
431
+ row += 'm'
432
+ elif v >= BLAST:
433
+ row += '%'
434
+ elif v == EXIT_OPEN:
435
+ row += 'x'
436
+ else:
437
+ row += rev.get(v, '?')
438
+ print(row)
439
+
440
+
441
+ if __name__ == "__main__":
442
+ here = os.path.dirname(os.path.abspath(__file__))
443
+ src = os.path.join(here, "..", "src")
444
+ r = play()
445
+ if "--show" in sys.argv:
446
+ show(r["cells"])
447
+ total = write_caves(os.path.join(src, "gen_caves.h"))
448
+ write_autopilot(os.path.join(src, "gen_autopilot.h"), r)
449
+ write_notes(os.path.join(src, "gen_notes.h"))
450
+ print(f"gen: {len(CAVES)} caves, {total} bytes packed; autopilot: score {r['score']}, gems {r['gems']}, "
451
+ f"game over in cave {r['cave'] + 1} after {r['starts']} starts, {r['frames']} play frames, "
452
+ f"chained fold 0x{r['fold']:04x}, table row {r['rank'] + 1}")
453
+ if r["frames"] > 255:
454
+ print("gen: more than 255 play frames: the meter records the first 255 only")
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env python3
2
+ """model_check.py HARNESS_DIR PAL.png NTSC.png: every visible cave cell against the model.
3
+
4
+ The autopilot shot shows cave 2 as it stood at game over, under the table
5
+ box. For each cave cell outside the box this reads the colour at the cell's
6
+ centre (every element glyph is inked there, see render.c) and compares it
7
+ with the colour of the element tools/gen.py's model holds at game over.
8
+ Exit 0 when all match on both pictures. `make modelcheck` runs it.
9
+ """
10
+ import os
11
+ import sys
12
+
13
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
14
+ import gen # noqa: E402
15
+
16
+ TINT = [0, 9, 2, 12, 15, 15, 3, 3, 12, 13, 7, 0, # render.c tint[], element 0..25
17
+ 8, 8, 8, 8, 4, 4, 4, 4, 1, 1, 1, 14, 14, 14]
18
+ BOX = (6, 7, 19, 32) # main.c draw_box: rows 6-19, columns 7-32
19
+
20
+
21
+ def main():
22
+ harness, pal, ntsc = sys.argv[1:4]
23
+ sys.path.insert(0, harness)
24
+ import check # the harness's geometry and palette
25
+
26
+ cells = gen.play()["cells"]
27
+ bad = 0
28
+ for path, model in ((pal, "pal"), (ntsc, "ntsc")):
29
+ shot = check.Shot(path, model)
30
+ seen = 0
31
+ for y in range(gen.H):
32
+ for x in range(gen.W):
33
+ row, col = y + 1, x
34
+ if BOX[0] <= row <= BOX[2] and BOX[1] <= col <= BOX[3]:
35
+ continue
36
+ px, py = check.point_xy({"row": row, "col": col}, model)
37
+ got, want = shot.index(px, py), TINT[cells[y * gen.W + x]]
38
+ seen += 1
39
+ if got != want:
40
+ bad += 1
41
+ print(f"FAIL {model.upper()} cave ({x}, {y}): colour {got}, the model's element "
42
+ f"{cells[y * gen.W + x]} is colour {want}")
43
+ print(f"model_check: {model.upper()} {seen} cave cells compared with the model")
44
+ print("model_check: PASS" if bad == 0 else f"model_check: {bad} cells differ")
45
+ sys.exit(1 if bad else 0)
46
+
47
+
48
+ if __name__ == "__main__":
49
+ main()
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env python3
2
+ """verdict_codes.py HARNESS_DIR PNG MODEL LETTERS: the verdict's failure letters.
3
+
4
+ The AUTOPILOT verdict prints one letter per failed test on row 23 from
5
+ column 27 (main.c, verdict). Exit 0 when every letter in LETTERS is there.
6
+ `make selftest-scan` uses it to see that the SCAN_FLAG=0 build fails on E,
7
+ the test that the scan meets the living player exactly once a cave frame.
8
+ """
9
+ import sys
10
+
11
+
12
+ def main():
13
+ harness, png, model, want = sys.argv[1:5]
14
+ sys.path.insert(0, harness)
15
+ import check
16
+ got = check.read_text(check.Shot(png, model), check.load_glyphs(), 23, 27, 12).strip()
17
+ missing = [c for c in want if c not in got]
18
+ print(f"verdict_codes: {model.upper()} failure letters '{got}'" +
19
+ (f", missing {''.join(missing)}" if missing else ""))
20
+ sys.exit(1 if missing else 0)
21
+
22
+
23
+ if __name__ == "__main__":
24
+ main()
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
+ "hooks": {
4
+ "PreToolUse": [
5
+ {
6
+ "matcher": "Edit|MultiEdit|Write|NotebookEdit",
7
+ "hooks": [
8
+ {
9
+ "type": "command",
10
+ "command": "h=\"$CLAUDE_PROJECT_DIR/harness/hooks/plan-gate.py\"; [ -f \"$h\" ] || h=\"$CLAUDE_PROJECT_DIR/../_harness/hooks/plan-gate.py\"; exec python3 \"$h\"",
11
+ "timeout": 10
12
+ }
13
+ ]
14
+ }
15
+ ]
16
+ }
17
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "mcpServers": {
3
+ "c64-kb": {
4
+ "type": "stdio",
5
+ "command": "node",
6
+ "args": ["../../dist/cli.js", "serve"],
7
+ "env": {}
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,118 @@
1
+ # Rules for an agent working on this C64 program
2
+
3
+ This program runs on a stock Commodore 64, PAL and NTSC. It is built on the
4
+ c64-kb harness (`./harness`, vendored from c64-kb's `templates/_harness`).
5
+ c64-kb is the reference: its pages give the registers, timings, techniques,
6
+ pitfalls and recipes this program is built from. A wrong number becomes a torn
7
+ screen or a crash, so every claim here is measured or says it is not.
8
+
9
+ A new program starts in c64-kb with `npm run new-project -- <starter> <dir>`.
10
+ That copies the starter and the harness, points `.mcp.json` and `local.mk`
11
+ at the c64-kb checkout, proves the copy with `make shot check`, and leaves a
12
+ blank `PLAN.md`.
13
+
14
+ ## This starter: adventure
15
+
16
+ STARWATCH, a two-word text adventure in Oscar64 C: twelve rooms, containers,
17
+ three puzzles, a scored ending, SAVE and LOAD to drive 8, packed text and a
18
+ multicolour picture strip. README.md has the file map and the measured
19
+ frame. Start a program from it with `npm run new-project -- adventure <dir>`
20
+ in c64-kb. `PLAN.md` here is a plan filled from real tool output;
21
+ new-project keeps it as `PLAN-adventure-example.md` and gives the new
22
+ program a blank one.
23
+
24
+ Rules this starter adds:
25
+
26
+ - The world lives in `tools/world.py`. Edit it, run `make gen`, then
27
+ `make shot check`. Never edit the generated `src/gen_*.h`.
28
+ - The engine and the printer live twice: `src/engine.c` and `src/text.c`,
29
+ and the model in `tools/gen.py`. Change both. The verdict compares the
30
+ game with the model (state, a fold of every printed line, the frame
31
+ count); a change on one side only turns it red.
32
+ - A frame does one bounded job: the picture, one window line, or the typed
33
+ keys and a turn. Keep it that way; the meter's worst is the check. The
34
+ script must show every picture (gen.py refuses it otherwise) and stay
35
+ within the meter's 255 frames (gen.py warns).
36
+ - After changing the script or the text, `expect.json`'s texts, the fold
37
+ on row 24 and the meter's `frames` change: `make gen` prints the new
38
+ frame count and fold.
39
+ - Disk calls run on a frame outside the meter, muted, followed by `SEI`.
40
+ Run `make disktest` after any change to `save.c` or the save record.
41
+
42
+ ## Before any code
43
+
44
+ 1. Brief: `npx tsx src/cli.ts game-briefing "<concept>" --archetype <name>`
45
+ (or `demo-briefing`), in the c64-kb checkout. Read what it proposes.
46
+ 2. For each technique you keep: `technique-lookup <name>` and
47
+ `pitfalls-for <name>`. Start from the recipe it names (`recipe-lookup`).
48
+ 3. Fill `PLAN.md`: paste the whole output of `check-compatibility` and of
49
+ `plan-budget` (same techniques) into their sections, list every technique
50
+ in its table, and replace every `FILL:` line.
51
+
52
+ Until `PLAN.md` passes, a hook blocks Edit and Write under `src/`, and every
53
+ make target that builds stops (`make plan-gate` says what is missing). With
54
+ C64KB set, `make` re-runs `check-compatibility` and wants the pasted Verdict.
55
+ The gate cannot see writes made through a shell command, or outputs edited
56
+ into shape by hand: do neither. `make PLAN_GATE=off` overrides it; say why in
57
+ `PLAN.md` if you do.
58
+
59
+ ## The loop
60
+
61
+ ```bash
62
+ make # build build/<name>.prg
63
+ make shot check # autopilot build, headless PAL and NTSC, graded by expect.json
64
+ make selftest # the FORCE_FAULT build must fail the same checks
65
+ make disk # build/<name>.d64
66
+ make claims # every store the program makes, against what it declares
67
+ make run # windowed VICE, for a human
68
+ ```
69
+
70
+ ## Rules
71
+
72
+ - Build before claiming. Code that has not built is not done.
73
+ - Measure screenshots with `check.py` through `expect.json`, never by eye.
74
+ Every visible claim gets a check. Add one before you trust a change.
75
+ - PAL and NTSC: both shots pass, or it is not done.
76
+ - Name the rung for every number: measured here (`make shot`, the meter, the
77
+ VICE monitor), taken from a c64-kb page (say which), arithmetic, or not
78
+ measured. Never call something verified that was not run.
79
+ - Frame cost comes from the meter: CIA2 timer A, printed as
80
+ `F<frames> W<worst> T<typical>` at row 24, columns 20 to 39, in AUTOPILOT
81
+ builds. It records the first `hold` frames: make that the autopilot
82
+ script's play frames. Typical is the median of those frames, the KB's
83
+ `cycles_per_frame_typical`. Keep grading, logging and printing outside the
84
+ bracket; work split between the main loop and IRQs is summed with
85
+ `METER_PAUSE` / `METER_START`.
86
+ - Do not invent a register, routine or address. Look it up:
87
+ `lookup-register`, `lookup-kernal`, `memory-map`.
88
+ - Lint every source you change: `npx tsx src/cli.ts lint <file>`.
89
+ - Commit named paths only. Never `git add -A` or `git add .`. `build/`,
90
+ `shots/` and `local.mk` are never committed.
91
+
92
+ ## Harness facts you will need
93
+
94
+ - `AUTOPILOT=1` builds read a scripted joystick byte instead of `$DC00` and
95
+ grade themselves: `$02FF` = `$01` and a green border on pass, `$02` and red
96
+ on fail. `FORCE_FAULT=1` must turn the verdict red and move something a
97
+ screenshot check can see.
98
+ - Screenshot geometry (c64-kb `docs/runtime/vice-reference.md`): PAL 384 x 272,
99
+ row = raster line - 16; NTSC 384 x 247, row = line - 28; x = VIC X + 8. A
100
+ sprite at Y register y is drawn from line y + 1.
101
+ - `check.py` reads text in the ROM character set unless a check names a
102
+ `charset` file; the meter's cells need 0-9, F, W and T in the set on screen.
103
+ - A KickAssembler part called from C is a raw blob at its own `* =` address,
104
+ `$0880` or above; `build/asm.h` gives C its labels as `ASM_<LABEL>`
105
+ (`ASM_<SCOPE>_<LABEL>` inside a scope). Pass arguments through bytes in the
106
+ blob, not Oscar64's zero page (`$02` to `$52`).
107
+ - The meter takes CIA2 timer A. Do not open RS-232 (device 2) while it runs.
108
+ - The KERNAL serial routines end in `CLI` (ROM bytes `58 60` / `58 18` at
109
+ `$EDAB`, `$EDB5`, `$EDDB`, `$EE82`). After any disk call, `SEI` again if
110
+ the program runs with the KERNAL IRQ off: otherwise that IRQ lands inside
111
+ the meter's brackets and rewrites `$DC00`.
112
+
113
+ ## Calling c64-kb
114
+
115
+ - CLI, from the c64-kb checkout (`C64KB` in `local.mk`):
116
+ `npx tsx src/cli.ts <command>`; `npx tsx src/cli.ts --help` lists them.
117
+ - MCP: `.mcp.json` starts `node <c64-kb>/dist/cli.js serve` (run
118
+ `npm run build` in c64-kb first).