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,240 @@
1
+ # action-puzzle: CAVE RUN
2
+
3
+ A Boulder Dash-style cave game for a stock C64, PAL and NTSC, in Oscar64 C.
4
+ Copy it to start a game of this kind:
5
+
6
+ ```bash
7
+ npm run new-project -- action-puzzle ~/c64/mygame # in c64-kb
8
+ ```
9
+
10
+ The player digs through earth. Boulders and gems fall and roll. Sparks keep
11
+ a wall on their left, moths a wall on their right; either explodes when the
12
+ player is next to it, and a moth crushed by a boulder bursts into gems.
13
+ Boulders can be pushed sideways into space. Collecting the cave's quota of
14
+ gems opens the exit. A time counter, a score, three lives. At game over a
15
+ new high score is entered with the joystick and the five-row table is saved
16
+ to drive 8; it is loaded again at start-up. An original two-voice tune plays
17
+ throughout, with sound effects on the third voice. Graphics, caves and tune
18
+ are original.
19
+
20
+ Joystick in port 2. Fire starts; up and down pick a letter, fire sets it.
21
+
22
+ ## Files
23
+
24
+ | File | What it holds |
25
+ |---|---|
26
+ | `src/main.c` | States (title, next cave, play, name entry, table), the frame loop, input, the autopilot and its verdict |
27
+ | `src/cave.c`, `cave.h` | The rules: the cave scan, split into row slices (technique `cave_scan_engine`) |
28
+ | `src/level.c`, `level.h` | The RLE cave decoder, timed on CIA1 timer B (`tile_map_render`, decode half) |
29
+ | `src/render.c`, `render.h` | RAM character set at `$2000`, cell drawing, the dirty list, text, glyph animation (`charset_animation`) |
30
+ | `src/sound.c`, `sound.h` | The tune on voices 1 and 2, effects on voice 3 (`sid_play_routine_pattern`, `sfx_engine_beside_music`) |
31
+ | `src/hiscore.c`, `hiscore.h` | The table, the insert, the file on drive 8 (`high_score_table_insert`, `kernal_file_read_seq`, `kernal_file_write_seq`, `error_channel_check`) |
32
+ | `tools/gen.py` | The caves, the autopilot script, a Python model of the rules, the note table. Writes `src/gen_*.h` |
33
+ | `tools/model_check.py` | Every visible cave cell of both shots against the model (`make modelcheck`) |
34
+ | `tools/disk_check.py` | Grades `make disktest` |
35
+ | `tools/drive.py` | Plays the `make joy` build headless over VICE's binary monitor |
36
+ | `expect.json`, `PLAN.md` | The screenshot checks; the plan with the c64-kb tool output it was made from |
37
+
38
+ Memory: code and data `$0880`-`$1FFF` and `$2800` up; the character set
39
+ `$2000`-`$27FF` (`$D018` = `$18`); screen `$0400`. Screen row 0 is the HUD,
40
+ rows 1 to 22 the cave (one character a cell), row 23 messages, row 24 the
41
+ cave name and, in AUTOPILOT builds, the frame meter.
42
+
43
+ ## How it runs
44
+
45
+ One cave frame is one scan of the 38 x 20 interior. It is split into four
46
+ slices of five rows, one slice a display frame, so the cave moves once every
47
+ four frames on both models (12.5 cave frames a second on PAL, 15 on NTSC).
48
+ The player's direction is latched at the first slice. Each slice redraws
49
+ only the cells it changed. After the fourth slice the exit opens if the
50
+ quota is met and the time counter ticks (once every 12 cave frames).
51
+
52
+ The dirty list holds 16 cells: 8 moves, since a move marks two cells (an
53
+ explosion marks nine). When a slice changes more, the list overflows and
54
+ the slice's rows (one above to one below) are queued instead;
55
+ `draw_pending` redraws at most two queued rows a frame, 34 cycles a cell
56
+ from the generated code, about 2,800 cycles for two rows. The first version
57
+ redrew all seven rows in the frame of the overflow, 55,305 cycles for 280
58
+ cells (measured in comparison), almost three PAL frames.
59
+
60
+ **How many objects a slice can move.** Each moving or landing object costs
61
+ about 440 cycles on top of the slice's usual work: 16 boulders falling in
62
+ one slice made a 13,643-cycle PAL frame and a 13,861-cycle NTSC one, against
63
+ a typical frame of about 6,500 to 6,800 (the meter; arithmetic for the per-object
64
+ figure). So about 20 moving objects a slice fit an NTSC frame, and about 25
65
+ fit a PAL one. A cave that moves more in one slice drops frames. The
66
+ autopilot's verdict counts dropped frames (below), so a cave designed past
67
+ that limit fails its own check. The cave-scan recipe's 380-boulder fill is
68
+ far past it; this starter's caves keep falls short and spread out.
69
+
70
+ The KERNAL IRQ is off during play; the loop polls raster line 250. Disk
71
+ calls happen on a static screen with the sound muted, and `SEI` follows
72
+ each one, because the KERNAL serial routines end in `CLI`.
73
+
74
+ ## Checks
75
+
76
+ | Command | What it proves |
77
+ |---|---|
78
+ | `make shot check` | The autopilot game on PAL and NTSC, each on a fresh D64 (`SHOT_DISK := 1`): 41 checks (verdict, HUD, the table row it inserted, the save read back, cave cells, PAL = NTSC, the meter) |
79
+ | `make modelcheck` | 516 visible cave cells per shot match the model's cave at game over |
80
+ | `make selftest` | The FORCE_FAULT build flips one byte of the save as it is read back: red border, letter V, and `READ BACK BAD` in the table |
81
+ | `make selftest-scan` | The build with `SCAN_FLAG=0` (no scanned bit, the cave-scan recipe's double-move bug) fails, and its verdict names E |
82
+ | `make disktest` | The save, a second save over it, and the load on a true-drive 1541 (below) |
83
+ | `make claims` | Every store the autopilot run makes is one the Makefile declares |
84
+
85
+ The autopilot plays a whole game of three lives. Its script is keyed to
86
+ the game's own counter of cave starts: start 1 digs right along row 2,
87
+ collects four gems, pushes a boulder twice, digs down for two more and walks
88
+ into the open exit. Starts 2, 3 and 4 are cave 2 after each lost life: out
89
+ from under a boulder, then under another, then the first again, and each
90
+ time the boulder falls on him. So the restart path (the cave decoded again,
91
+ a life taken, the score banked) runs twice. It enters the name ABE; 158
92
+ goes in row 4, and the table is saved and read back from the shot's fresh
93
+ disk. In cave 1 a boulder on the end of a brick rolls right, and a row of
94
+ 16 boulders falls and lands in one slice, which overflows the dirty list.
95
+
96
+ `tools/gen.py` plays the same script through its model and writes what the
97
+ game must end with. The verdict prints one letter for each test that
98
+ failed, after the fold on row 23:
99
+
100
+ | Letter | Test |
101
+ |---|---|
102
+ | F | the fold, chained over every cave the game left (0x75FA), against the model's |
103
+ | S, G, C, P, K | score, gems, cave, play frames, cave starts |
104
+ | T | the table row: rank, name and score |
105
+ | L | every cave decode matched its fold |
106
+ | E | the scan met the living player exactly once in every cave frame |
107
+ | M | at every cave end, after the row queue is drained, every screen cell shows its cave cell |
108
+ | D | no play frame's work ran past line 250 (the `$D019` raster latch, below) |
109
+ | V | the save read back byte for byte (`memcmp`) |
110
+
111
+ A watchdog ends the game once play runs past the model's frame count, so a
112
+ broken rule still reaches the verdict. Each gate was checked with a
113
+ mutation (2026-09-23): no right roll (F), no `dead_frames` reset on restart
114
+ (F P K D), the row queue disabled (M), the save one byte short (V), the
115
+ `memcmp` replaced by true (selftest then passes the fault build and fails),
116
+ a busy loop in one play frame (D), and the E test removed (selftest-scan
117
+ then finds no E).
118
+
119
+ **Dropped frames.** The VIC sets bit 0 of `$D019` on every raster compare
120
+ match even with the interrupt disabled. `wait_frame` acknowledges it at line
121
+ 250, so a set bit on entry means the frame's work overran. The KERNAL leaves
122
+ the compare at line 311 (bit 8 set in `$D011`), so `main` clears that bit
123
+ first: without it the latch never set (0 of 200 frames against 199 of 200,
124
+ a test program in VICE x64sc 3.10).
125
+
126
+ **The shot pin.** Both models are shot at 24,000,000 cycles. At
127
+ 18,000,000 the save is still running on both models; at 20,000,000,
128
+ 24,000,000 and 30,000,000 the picture is byte-identical, PAL and NTSC
129
+ (VICE x64sc 3.10, windowless).
130
+
131
+ **The disk test.** `make disktest` (`DISK_MODEL=ntsc` for NTSC) copies the
132
+ release D64. It runs the autopilot build against the copy with
133
+ `-drive8truedrive`, so the emulated 1541 runs its own DOS ROM. The build
134
+ finds no file (62), plays, saves (scratch, then write) and shows
135
+ `SAVED TO DISK (00)`. It then runs a second time on the same image. It
136
+ loads that file, its 158 ties row 4 and goes in row 5, and the save must
137
+ replace the file. Without the scratch the drive answers 63 (FILE EXISTS)
138
+ and nothing is written: a build with the scratch removed fails this test.
139
+ The second run's own verdict is red by design, because it did not start
140
+ from the default table. c1541 reads the 38-byte `HISCORE` file back after
141
+ each save, and the directory must hold one entry. Last, a cold VICE
142
+ autostarts the D64: the drive loads the release PRG, which reads the file
143
+ and shows the title with rows 4 and 5 `ABE 000158` and `SCORES FROM DISK
144
+ (00)`. Three pictures, two files and the directory are graded. Run on
145
+ 2026-09-23: PASS on PAL and NTSC.
146
+
147
+ ## Driving it headless
148
+
149
+ `make joy` builds the normal game (three lives, title, no autopilot) with
150
+ `-dJOY_SOURCE=0x02fe`: the port byte comes from `$02FE` instead of `$DC00`.
151
+ `tools/drive.py` plays that build over VICE's binary monitor. It writes the
152
+ byte, lets the machine run, and reads screen RAM as text:
153
+
154
+ ```bash
155
+ make joy
156
+ python3 tools/drive.py build/action-puzzle-joy.prg "until:FIRE TO START" tap:fire \
157
+ until:LIVES hold:right "until:ENTER YOUR NAME" hold:none tap:up tap:fire tap:fire \
158
+ tap:fire "until:GAME OVER" print tap:fire "until:FIRE TO START" print
159
+ ```
160
+
161
+ That run (2026-09-23) held right through three time-outs (cave 1 each
162
+ time), entered BAA, and showed `4. BAA 000120` in the table, `NOT SAVED
163
+ (74)` with no disk attached, and then the title. Two findings
164
+ behind this design:
165
+
166
+ - The windowless VICE's joyport commands do not reach `$DC00`. The binary
167
+ monitor's joyport set was accepted, but `$DC00` never changed, with or
168
+ without `-joydev2` (found in review).
169
+ - Monitor screenshots from the windowless build came back stale while the
170
+ game ran, so `drive.py` reads screen RAM. Entering the text monitor during
171
+ the start-up disk read left that read hung twice here; the binary monitor
172
+ under warp did not.
173
+
174
+ ## The measured frame
175
+
176
+ The harness meter (CIA2 timer A), over the autopilot's 240 play frames,
177
+ VICE x64sc 3.10:
178
+
179
+ | Model | Worst | Typical (median) | Frame |
180
+ |---|---|---|---|
181
+ | PAL | 13,643 | 6,518 | 19,656 |
182
+ | NTSC | 13,861 | 6,776 | 17,095 |
183
+
184
+ The worst frame is play frame 7, the slice where the 16 boulders fall and
185
+ overflow the dirty list (a debug build that kept the worst frame's index
186
+ found it). The cave decode between caves is not a play frame: 40,041 cycles
187
+ on PAL and 40,519 on NTSC for cave 2, screen on, CIA1 timer B, printed after
188
+ the verdict.
189
+
190
+ The same checks pass with the released Oscar64 v1.32.273 (make shot check,
191
+ modelcheck, selftest, selftest-scan and disktest on PAL, run 2026-09-23).
192
+ Its meter reads 13,412 / 6,392 cycles on PAL and 13,669 / 6,607 on NTSC
193
+ (measured on 3048ac1 by the other #39 session's comparator).
194
+
195
+ Against `plan-budget` (the PLAN.md output): it summed the recipe's whole
196
+ scan, 18,559 cycles, into every PAL play frame (range 19,599 to 19,807 plus
197
+ 1,075 for badlines, "undetermined") and left it out of the NTSC frame as
198
+ multi-frame (1,040 to 1,248 plus 1,075). Neither is this program's frame:
199
+ the scan here runs a quarter at a time. The scan loop takes 17 cycles a
200
+ cell of dirt (counted from the generated code). The recipe's loop measured 18.7 (14,206 cycles
201
+ for 760 cells, with badlines in). So a slice of 190 cells costs about 3,230
202
+ cycles, plus the objects in it (arithmetic). The tool's
203
+ music figure is the recipe's stub tune; this tune and its effects are
204
+ measured only inside the whole frame.
205
+
206
+ ## Extending it
207
+
208
+ 1. **Scroll a bigger cave.** Draw cells as 2 x 2 characters and scroll a
209
+ window over a cave larger than the screen: `tile_map_render` and the
210
+ recipe `oscar64/tile-map-render` (metatiles), then a scroll technique
211
+ from `technique-lookup` (`techniques-for --category scroll`).
212
+ 2. **Add amoeba, a magic wall or more enemies.** Add codes in `cave.h`
213
+ (at most 32: glyphs sit at `$40` + code), a branch in `cell()`, a glyph
214
+ and a tint in `render.c`, the same colour in `tools/model_check.py`'s
215
+ `TINT`, and the same rule in `tools/gen.py`'s `Cave.cell`. Extend the
216
+ script and run `make gen shot check modelcheck`. The rules and the
217
+ scanned bit are `cave_scan_engine` (recipe `oscar64/cave-scan`).
218
+ 3. **Faster scans.** The scan loop is C; the recipe `oscar64/level-rle-decoder`
219
+ shows a hand-written decoder a little under twice as fast as the C one,
220
+ and the same move applies to `cave_scan_rows`. Measure before and after
221
+ with the meter.
222
+
223
+ More caves: add them to `CAVES` in `tools/gen.py` and run `make gen`.
224
+
225
+ ## Left out on purpose
226
+
227
+ - Scrolling, 2 x 2 cells, multicolour graphics, sprites: one cell is one
228
+ hires character, so the whole 40 x 22 cave is on screen.
229
+ - Amoeba, magic wall, slime, collecting falling gems, the fire-to-grab move.
230
+ - A raster IRQ: the loop polls line 250. Music keeps time only while the
231
+ loop does; it stops during disk calls.
232
+ - Equal speed on both models: NTSC plays 20 % faster in real time,
233
+ tune included (pitfall `pal_ntsc_tempo_mismatch`). The note pitches are
234
+ right on both (a PAL and an NTSC table).
235
+ - Anyone listening to the sound: the tune and effects were checked by the
236
+ registers claims-watch saw written, not by ear.
237
+ - A real joystick on `$DC00`: the normal game was driven headless through
238
+ `$02FE` (above), which differs from the release build in one line of
239
+ `port_read`.
240
+ - Real hardware.
@@ -0,0 +1,25 @@
1
+ {
2
+ "checks": [
3
+ { "name": "own verdict (border)", "type": "verdict" },
4
+ { "name": "verdict line and the model's chained fold (0x75FA)", "type": "text", "row": 23, "col": 0, "text": "RESULT 01 PASS FOLD 30202" },
5
+ { "name": "HUD: cave 2's quota and time, the banked score 158, no lives left", "type": "text", "row": 0, "col": 0, "text": "GEMS 00/08 TIME 120 SCORE 000158 LIVES 0" },
6
+ { "name": "game-over box", "type": "text", "row": 7, "col": 16, "text": "GAME OVER" },
7
+ { "name": "table row 4: the scripted name and score, inserted", "type": "text", "row": 14, "col": 13, "text": "4. ABE 000158" },
8
+ { "name": "table row 5: the old row 4, shifted down", "type": "text", "row": 15, "col": 13, "text": "5. MUD 000100" },
9
+ { "name": "table row 3 kept", "type": "text", "row": 13, "col": 13, "text": "3. GEM 000200" },
10
+ { "name": "the save, read back byte for byte from the shot's fresh disk", "type": "text", "row": 17, "col": 9, "text": "SAVED TO DISK (00)" },
11
+ { "name": "steel border, cave (0, 0)", "type": "pixel", "row": 1, "col": 0, "colour": 12 },
12
+ { "name": "boulder the model leaves at cave (22, 1)", "type": "pixel", "row": 2, "col": 22, "colour": 15 },
13
+ { "name": "boulder at cave (11, 2)", "type": "pixel", "row": 3, "col": 11, "colour": 15 },
14
+ { "name": "gem at cave (14, 3)", "type": "pixel", "row": 4, "col": 14, "colour": 3 },
15
+ { "name": "spark the model moved to cave (23, 4)", "type": "pixel", "row": 5, "col": 23, "colour": 8 },
16
+ { "name": "gem that fell into the spark's corridor, cave (24, 4)", "type": "pixel", "row": 5, "col": 24, "colour": 3 },
17
+ { "name": "exit still shut (looks like steel), cave (29, 4)", "type": "pixel", "row": 5, "col": 29, "colour": 12 },
18
+ { "name": "the explosion that killed the player left space, cave (5, 3)", "type": "pixel", "row": 4, "col": 5, "colour": 0 },
19
+ { "name": "where the killing boulder fell from is space, cave (5, 1)", "type": "pixel", "row": 2, "col": 5, "colour": 0 },
20
+ { "name": "dirt beside the blast, cave (1, 3)", "type": "pixel", "row": 4, "col": 1, "colour": 9 },
21
+ { "name": "gem at cave (4, 18), below the box", "type": "pixel", "row": 19, "col": 4, "colour": 3 },
22
+ { "name": "HUD, cave, box and verdict line the same on both models", "type": "same", "cells": [0, 0, 23, 39] },
23
+ { "name": "frame meter, the script's 240 play frames over four lives", "type": "meter", "row": 24, "col": 20, "frames": 240 }
24
+ ]
25
+ }
@@ -0,0 +1,280 @@
1
+ // cave.c: the rules. Built from c64-kb's oscar64/cave-scan recipe, with
2
+ // pushing, a second enemy, explosions, gems collected for points, the exit
3
+ // and the time counter added. Every rule here is written again in Python in
4
+ // tools/gen.py (class Cave); change both together.
5
+ #include "cave.h"
6
+
7
+ char cave[CW * CH];
8
+ char cave_move;
9
+ char cave_got, cave_need, cave_time, cave_tick;
10
+ unsigned cave_points;
11
+ unsigned cave_player, cave_exit_at;
12
+ bool cave_dead, cave_exited, cave_exit_open;
13
+ char cave_events;
14
+ char cave_seen;
15
+
16
+ unsigned cave_dirty[DIRTY_MAX];
17
+ char cave_ndirty;
18
+ bool cave_overflow;
19
+
20
+ // Headings in clockwise order: left, up, right, down. Turning left is
21
+ // heading + 3, turning right heading + 1, both modulo 4.
22
+ static const signed char step[4] = { -1, -CW, 1, CW };
23
+
24
+ static void mark(char *q)
25
+ {
26
+ if (cave_ndirty < DIRTY_MAX)
27
+ cave_dirty[cave_ndirty++] = q - cave;
28
+ else
29
+ cave_overflow = true;
30
+ }
31
+
32
+ // The one place an object moves. A move to a later cell in scan order sets
33
+ // the scanned bit, so the scan skips the object when it gets there.
34
+ static void put(char *dst, char v, char *src)
35
+ {
36
+ #if SCAN_FLAG
37
+ if (dst > src)
38
+ v |= SCANNED;
39
+ #endif
40
+ *dst = v;
41
+ *src = SPACE;
42
+ if (v == PLAYER || v == (PLAYER | SCANNED))
43
+ cave_player = dst - cave;
44
+ mark(dst);
45
+ mark(src);
46
+ }
47
+
48
+ // A 3 x 3 explosion. Steel and the exit survive. Cells after `at` in scan
49
+ // order get the scanned bit, so the explosion starts on the next cave frame
50
+ // everywhere. `at` = 0xffff (from cave_end_frame) marks none.
51
+ static void explode(unsigned centre, char kind, unsigned at)
52
+ {
53
+ for (signed char dy = -CW; dy <= CW; dy += CW)
54
+ for (signed char dx = -1; dx <= 1; dx++)
55
+ {
56
+ unsigned n = centre + dy + dx;
57
+ char t = cave[n] & 0x7f;
58
+ if (t == STEEL || t == EXIT_SHUT || t == EXIT_OPEN)
59
+ continue;
60
+ if (t == PLAYER)
61
+ cave_dead = true;
62
+ cave[n] = n > at ? kind | SCANNED : kind;
63
+ mark(cave + n);
64
+ }
65
+ cave_events |= EV_BOOM;
66
+ }
67
+
68
+ static bool is_round(char t)
69
+ {
70
+ return t == BOULDER || t == GEM || t == BRICK;
71
+ }
72
+
73
+ // Roll off a round object: left first, then right. Needs the side cell and
74
+ // the cell below it empty. The object leaves falling.
75
+ static bool roll(char *p, char fall)
76
+ {
77
+ if (p[-1] == SPACE && p[CW - 1] == SPACE) { put(p - 1, fall, p); return true; }
78
+ if (p[1] == SPACE && p[CW + 1] == SPACE) { put(p + 1, fall, p); return true; }
79
+ return false;
80
+ }
81
+
82
+ static void fall_rules(char *p, char v)
83
+ {
84
+ char b = p[CW];
85
+ char bt = b & 0x7f;
86
+ if (b == SPACE)
87
+ put(p + CW, v, p); // keep falling
88
+ else if (bt == PLAYER || (bt >= SPARK && bt < MOTH))
89
+ explode(p + CW - cave, BLAST, p - cave);
90
+ else if (bt >= MOTH && bt < BLAST)
91
+ explode(p + CW - cave, BURST, p - cave); // a moth dies into gems
92
+ else if (bt == BOULDER_F || bt == GEM_F)
93
+ ; // wait for it to move
94
+ else if (!(is_round(bt) && roll(p, v)))
95
+ {
96
+ *p = v - 1; // land
97
+ mark(p);
98
+ cave_events |= EV_LAND;
99
+ }
100
+ }
101
+
102
+ static void player_rules(char *p)
103
+ {
104
+ if (cave_move >= 4)
105
+ return;
106
+ signed char s = step[cave_move];
107
+ char *t = p + s;
108
+ char tv = *t;
109
+ if (tv == SPACE || tv == DIRT)
110
+ {
111
+ if (tv == DIRT)
112
+ cave_events |= EV_DIG;
113
+ put(t, PLAYER, p);
114
+ }
115
+ else if (tv == GEM)
116
+ {
117
+ cave_got++;
118
+ cave_points += GEM_POINTS;
119
+ cave_events |= EV_GEM;
120
+ put(t, PLAYER, p);
121
+ }
122
+ else if (tv == EXIT_OPEN)
123
+ {
124
+ *p = SPACE;
125
+ mark(p);
126
+ cave_exited = true;
127
+ }
128
+ else if (tv == BOULDER && (cave_move == 0 || cave_move == 2) && t[s] == SPACE)
129
+ {
130
+ put(t + s, BOULDER, t); // push: the boulder first
131
+ put(t, PLAYER, p);
132
+ cave_events |= EV_PUSH;
133
+ }
134
+ }
135
+
136
+ // Sparks turn left when they can, moths turn right; either goes on when it
137
+ // cannot turn, and turns the other way on the spot when both are blocked.
138
+ // Either explodes when the player is next to it.
139
+ static void enemy_rules(char *p, char v)
140
+ {
141
+ char base = v < MOTH ? SPARK : MOTH;
142
+ char kind = v < MOTH ? BLAST : BURST;
143
+ for (char k = 0; k < 4; k++)
144
+ if ((p[step[k]] & 0x7f) == PLAYER)
145
+ {
146
+ explode(p - cave, kind, p - cave);
147
+ return;
148
+ }
149
+ char d = v & 3;
150
+ char first = base == SPARK ? (d + 3) & 3 : (d + 1) & 3;
151
+ char spin = base == SPARK ? (d + 1) & 3 : (d + 3) & 3;
152
+ if (p[step[first]] == SPACE)
153
+ put(p + step[first], base + first, p);
154
+ else if (p[step[d]] == SPACE)
155
+ put(p + step[d], base + d, p);
156
+ else
157
+ {
158
+ *p = base + spin;
159
+ mark(p);
160
+ }
161
+ }
162
+
163
+ // One object's turn. Called only for codes BOULDER and up. It takes the row
164
+ // and the column, not a cell pointer: with a pointer argument Oscar64 -O2
165
+ // computed row + x for every cell before the test, and the loop took 42
166
+ // cycles a cell instead of 17 (counted from the generated code). The frame meter read a typical play
167
+ // frame of 11,812 cycles before and 7,004 after, on the build whose HUD still
168
+ // rewrote every field each cave frame (6,340 with today's update_hud).
169
+ static __noinline void cell(char *row, char x)
170
+ {
171
+ char *p = row + x;
172
+ char v = *p;
173
+ if (v & SCANNED)
174
+ {
175
+ *p = v & 0x7f; // moved here this scan
176
+ return;
177
+ }
178
+ if (v == BOULDER || v == GEM)
179
+ {
180
+ char b = p[CW];
181
+ if (b == SPACE)
182
+ put(p + CW, v + 1, p); // start falling
183
+ else if (is_round(b & 0x7f))
184
+ roll(p, v + 1);
185
+ }
186
+ else if (v == BOULDER_F || v == GEM_F)
187
+ fall_rules(p, v);
188
+ else if (v == PLAYER)
189
+ {
190
+ cave_seen++; // once a cave frame, or the scanned bit failed
191
+ player_rules(p);
192
+ }
193
+ else if (v >= BLAST)
194
+ {
195
+ if (v == BLAST + 2)
196
+ *p = SPACE;
197
+ else if (v == BURST + 2)
198
+ *p = GEM;
199
+ else
200
+ *p = v + 1;
201
+ mark(p);
202
+ }
203
+ else if (v >= SPARK)
204
+ enemy_rules(p, v);
205
+ }
206
+
207
+ // Interior rows y0 .. y1 - 1. The loop only reads and compares: LDA (row),Y,
208
+ // CMP, BCC, INY, CPY, BCC: 5 + 2 + 3 + 2 + 2 + 3 = 17 cycles a cell of space,
209
+ // dirt, brick or steel (from the generated code, both branches taken, no page
210
+ // crossed). The dirty list starts
211
+ // empty for each slice.
212
+ __noinline void cave_scan_rows(char y0, char y1)
213
+ {
214
+ cave_ndirty = 0;
215
+ cave_overflow = false;
216
+ char *row = cave + CW * y0;
217
+ for (char y = y0; y < y1; y++, row += CW)
218
+ for (char x = 1; x < CW - 1; x++)
219
+ {
220
+ char v = row[x];
221
+ if (v >= BOULDER)
222
+ {
223
+ if (v & SCANNED)
224
+ row[x] = v & 0x7f; // moved here this scan: no call
225
+ else
226
+ cell(row, x);
227
+ }
228
+ }
229
+ }
230
+
231
+ void cave_start(char need, char time)
232
+ {
233
+ cave_need = need;
234
+ cave_time = time;
235
+ cave_got = 0;
236
+ cave_tick = 0;
237
+ cave_points = 0;
238
+ cave_dead = cave_exited = cave_exit_open = false;
239
+ cave_move = NO_MOVE;
240
+ for (unsigned i = 0; i < CW * CH; i++)
241
+ {
242
+ if (cave[i] == PLAYER)
243
+ cave_player = i;
244
+ else if (cave[i] == EXIT_SHUT)
245
+ cave_exit_at = i;
246
+ }
247
+ }
248
+
249
+ // After the last slice of a cave frame: open the exit when the quota is met,
250
+ // then run the clock. Time out explodes the player.
251
+ void cave_end_frame(void)
252
+ {
253
+ if (!cave_exit_open && cave_got >= cave_need)
254
+ {
255
+ cave[cave_exit_at] = EXIT_OPEN;
256
+ mark(cave + cave_exit_at);
257
+ cave_exit_open = true;
258
+ cave_events |= EV_OPEN;
259
+ }
260
+ if (cave_exited || cave_dead)
261
+ return;
262
+ if (++cave_tick == TICK_CAVE_FRAMES)
263
+ {
264
+ cave_tick = 0;
265
+ if (cave_time)
266
+ cave_time--;
267
+ if (cave_time == 0)
268
+ explode(cave_player, BLAST, 0xffff);
269
+ }
270
+ }
271
+
272
+ unsigned cave_fold(unsigned chk)
273
+ {
274
+ for (unsigned i = 0; i < CW * CH; i++)
275
+ {
276
+ unsigned t = chk ^ (cave[i] & 0x7f);
277
+ chk = (t << 2) + t + 1; // (chk ^ v) * 5 + 1
278
+ }
279
+ return chk;
280
+ }
@@ -0,0 +1,80 @@
1
+ // cave.h: the cave and its rules (c64-kb technique cave_scan_engine).
2
+ //
3
+ // A 40 x 22 cave of one-byte cells, steel border included. One cave frame is
4
+ // one top-to-bottom, left-to-right scan of the 38 x 20 interior. The game
5
+ // splits it into slices of rows, one slice a display frame
6
+ // (cave_scan_rows), then calls cave_end_frame. An object that moves down or
7
+ // right gets bit 7 (SCANNED), so the scan skips it when it reaches the cell
8
+ // it moved into. tools/gen.py holds a model of the same rules; the AUTOPILOT
9
+ // build checks the cave against it.
10
+ #ifndef CAVE_H
11
+ #define CAVE_H
12
+
13
+ #define CW 40 // cave width in cells
14
+ #define CH 22 // cave height in cells
15
+
16
+ // Element codes (tools/gen.py uses the same numbers). A code below BOULDER
17
+ // never moves, and the scan loop does nothing more than compare it.
18
+ #define SPACE 0
19
+ #define DIRT 1
20
+ #define BRICK 2 // round: things roll off it
21
+ #define STEEL 3 // not round, not destroyed by explosions
22
+ #define BOULDER 4
23
+ #define BOULDER_F 5 // falling: the resting code + 1
24
+ #define GEM 6
25
+ #define GEM_F 7
26
+ #define EXIT_SHUT 8 // drawn as steel until the quota is met
27
+ #define EXIT_OPEN 9
28
+ #define PLAYER 10
29
+ #define SPARK 12 // 12..15: heading in the low two bits; keeps a wall on its left
30
+ #define MOTH 16 // 16..19: keeps a wall on its right; dies into gems
31
+ #define BLAST 20 // 20..22: explosion stages, then space
32
+ #define BURST 23 // 23..25: explosion stages, then a gem
33
+ #define CODES 26 // at most 32: render.c draws code & 0x1f at glyph $40 + code
34
+ #define SCANNED 0x80
35
+
36
+ #define NO_MOVE 0xff // cave_move: headings 0..3 are left, up, right, down
37
+
38
+ #define GEM_POINTS 10
39
+ #define TICK_CAVE_FRAMES 12 // cave frames per unit of the time counter
40
+
41
+ // Sound events a scan raised, for the effects engine (bits of cave_events).
42
+ #define EV_DIG 0x01
43
+ #define EV_PUSH 0x02
44
+ #define EV_LAND 0x04
45
+ #define EV_GEM 0x08
46
+ #define EV_OPEN 0x10
47
+ #define EV_BOOM 0x20
48
+
49
+ extern char cave[CW * CH];
50
+ extern char cave_move; // the player's heading this cave frame, or NO_MOVE
51
+ extern char cave_got, cave_need, cave_time, cave_tick;
52
+ extern unsigned cave_points; // points scored in this cave
53
+ extern unsigned cave_player; // cell index of the player
54
+ extern unsigned cave_exit_at;
55
+ extern bool cave_dead, cave_exited, cave_exit_open;
56
+ extern char cave_events;
57
+ extern char cave_seen; // times the scan ran the player's rules; main.c resets it each cave frame
58
+
59
+ // Cells a slice changed, for the renderer. A move marks two cells, an
60
+ // explosion nine, so a slice holds up to 8 moves before the list overflows;
61
+ // then render.c queues the slice's rows and redraws them two a frame.
62
+ #define DIRTY_MAX 16
63
+ extern unsigned cave_dirty[DIRTY_MAX];
64
+ extern char cave_ndirty;
65
+ extern bool cave_overflow;
66
+
67
+ void cave_start(char need, char time); // after the decode: find the player and exit
68
+ void cave_scan_rows(char y0, char y1); // scan interior rows y0 .. y1 - 1
69
+ void cave_end_frame(void); // after the last slice: exit, clock
70
+ unsigned cave_fold(unsigned chk); // chk = (chk ^ v) * 5 + 1 over all 880 cells
71
+
72
+ // SCAN_FLAG=0 builds the rules without the scanned bit: the double-move bug
73
+ // of the cave-scan recipe, which make selftest-scan must see fail.
74
+ #ifndef SCAN_FLAG
75
+ #define SCAN_FLAG 1
76
+ #endif
77
+
78
+ #pragma compile("cave.c")
79
+
80
+ #endif
@@ -0,0 +1,20 @@
1
+ // gen_autopilot.h: written by tools/gen.py. Do not edit; edit tools/gen.py.
2
+ // The autopilot: one move per cave frame (L U R D, '-' still), per cave;
3
+ // past the end of a cave's string the player stands still.
4
+ static const char script0[] = "RRRRRRRRRRRRRRRRRRDDDR";
5
+ static const char script1[] = "RRUD";
6
+ static const char script2[] = "RRRRRRRRD";
7
+ static const char script3[] = "RRUD";
8
+ static const char * const script_for[4] = { script0, script1, script2, script3 };
9
+ static const char script_len[4] = { 22, 4, 9, 4 };
10
+ #define SCRIPT_STARTS 4
11
+ #define LIVES_AUTOPILOT 3
12
+ #define NAME_AUTOPILOT "ABE"
13
+ // What the rules model says the program must hold at game over.
14
+ #define EXPECT_FOLD 0x75fa
15
+ #define EXPECT_SCORE 158UL
16
+ #define EXPECT_GEMS 6
17
+ #define EXPECT_CAVE 1
18
+ #define EXPECT_PLAY_FRAMES 240
19
+ #define EXPECT_STARTS 4
20
+ #define EXPECT_RANK 3