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,950 @@
1
+ ---
2
+ recipe: car-contact
3
+ toolchain: oscar64
4
+ output_format: PRG
5
+ region: both
6
+ techniques: [car_contact_response]
7
+ file_formats: [PRG]
8
+ uses_registers: [D000, D001, D010, D011, D012, D015, D017, D01B, D01C, D01D, D020, D021, D027, DC06, DC07, DC0F]
9
+ uses_kernal: []
10
+ ---
11
+
12
+ <!-- doc-type: recipe -->
13
+
14
+ # Oscar64 car contact: push apart on the shallow axis, trade velocity by mass, crash off the road
15
+
16
+ ## Synopsis
17
+
18
+ A top-down road strip, grass on the left and water on the right, with six
19
+ cars on scripts: the player (white), three light cars and two trucks.
20
+ Every frame each pair of cars is tested; a pair that overlaps is pushed
21
+ apart along the axis where the overlap is smaller, and its velocities on
22
+ that axis are exchanged as an elastic collision between masses 1 and 7,
23
+ using shifts, not multiplies. After a hit both cars cool for eight frames,
24
+ during which that pair is still pushed apart but gets no second kick.
25
+ Then each car's centre is looked up in a tile map; a car on grass or water
26
+ has crashed and stops. One 256-frame pass holds five scenes: the player
27
+ side-swipes a light car into the water; a light car bumps another from
28
+ behind and hands over its speed; the player hits a truck that moves
29
+ 5 pixels; a truck hits two light cars in the same frame and both go onto
30
+ the grass; and the player steers hard into the stopped truck, stays in
31
+ contact for nine frames with overlaps of 4 and 5 pixels, and shoves it
32
+ onto the grass. Every frame the cars' positions, velocities and crash
33
+ flags are folded into a checksum; the Python model on this page predicts
34
+ `$01E9` for the pass. At the end of each pass the program checks the
35
+ checksum, the hit count and the crash flags: `$02FF` = `01` and a green
36
+ border on a pass, `02` and red otherwise (`headless-verify.md`). The HUD
37
+ shows the cycles per pair, for two light cars and for a truck, and per
38
+ frame. This is the `car_contact_response` technique from
39
+ `docs/techniques/logic.md`.
40
+
41
+ ## Source
42
+
43
+ ```c
44
+ // car-contact.c
45
+ //
46
+ // Top-down road: grass left, water right, road between. Six cars on
47
+ // scripts: the player (white) and five enemies, three light and two heavy
48
+ // trucks. Each frame: scripts, move, then contact response for every pair
49
+ // (separate along the axis of least overlap, exchange velocity on that
50
+ // axis scaled by mass, no impulse while both cars are cooling), then a
51
+ // tile probe that crashes a car whose centre is off the road.
52
+ // Scenes in one 256-frame pass: the player side-swipes a light car into
53
+ // the water; a light car bumps another from behind; the player hits a
54
+ // truck that barely moves; a truck hits two light cars in one frame and
55
+ // both go onto the grass; the player holds its steering into a truck for
56
+ // nine frames of contact and shoves it onto the grass. Every frame the positions, velocities and crash
57
+ // flags are folded into a checksum that a Python model of the same rules
58
+ // predicts. At the end of a pass: $02FF = 01 and a green border on a pass,
59
+ // 02 and red on a fail.
60
+ //
61
+ #include <c64/vic.h>
62
+ #include <c64/cia.h>
63
+
64
+ #define Screen ((char *)0x0400)
65
+ #define Color ((char *)0xd800)
66
+ #define SprData ((char *)0x3000) // blocks 192, 193
67
+ #define SPR_BLK 192
68
+ #define VR ((volatile char *)0xd000)
69
+ #define PTR ((volatile char *)0x07f8)
70
+ #define RESULT (*(volatile char *)0x02ff)
71
+
72
+ // --- the road as a tile map: 0 road, 1 grass, 2 water -------------------
73
+ #define ROAD_L 9 // first road column
74
+ #define ROAD_R 26 // last road column
75
+ #define TOP_ROW 7 // rows 0-6 are the HUD
76
+ char tmap[25 * 40];
77
+ unsigned rowoff[25];
78
+
79
+ // --- cars, parallel arrays; x and y are 8.8, the centre of the body -----
80
+ #define MAXC 8
81
+ #define N_GAME 6
82
+ #define COOL 8 // frames without impulse after one
83
+ #define FR 4 // coasting drag, 1/256 px per frame
84
+
85
+ unsigned cx[MAXC], cy[MAXC];
86
+ int vx[MAXC], vy[MAXC];
87
+ char crash[MAXC], cool[MAXC], drv[MAXC];
88
+ char heavy[MAXC], hw[MAXC], hh[MAXC]; // mass class, half width, half height
89
+ char ncars;
90
+ char hits, contacts;
91
+
92
+ // --- scripts: vx, vy, frames, drive (1 holds the velocity, 0 coasts) ------
93
+ struct Step { int vx, vy; char n, drive; };
94
+
95
+ const struct Step s0[] = { {0,0,1,1}, {384,0,10,1}, {0,0,50,0}, {-383,0,16,1},
96
+ {0,0,93,0}, {-1536,0,12,1}, {0,0,0,0} };
97
+ const struct Step s1[] = { {0,0,1,1}, {0,0,0,0} };
98
+ const struct Step s3[] = { {0,0,1,1}, {0,0,0,0} };
99
+ const struct Step s4[] = { {0,0,1,1}, {0,-192,33,1}, {0,0,30,0}, {0,-128,28,1},
100
+ {0,0,1,1}, {0,0,0,0} };
101
+ const struct Step s5[] = { {0,0,120,1}, {-384,0,1,1}, {0,0,0,0} };
102
+ const struct Step *const scripts[N_GAME] = { s0, s1, s1, s3, s4, s5 };
103
+ char sstep[N_GAME], sleft[N_GAME];
104
+
105
+ const unsigned start_x[N_GAME] = { 160 << 8, 185 << 8, 140 << 8, 120 << 8, 120 << 8, 165 << 8 };
106
+ const unsigned start_y[N_GAME] = { 200 << 8, 196 << 8, 200 << 8, 150 << 8, 190 << 8, 142 << 8 };
107
+ const char kind[N_GAME] = { 0, 0, 1, 0, 0, 1 }; // 1 truck
108
+ const char col[N_GAME] = { 1, 7, 8, 3, 13, 4 };
109
+
110
+ void set_kind(char c, char k)
111
+ {
112
+ heavy[c] = k;
113
+ hw[c] = k ? 7 : 5;
114
+ hh[c] = k ? 10 : 8;
115
+ }
116
+
117
+ // --- mass: who takes how much of a push and of an impulse -----------------
118
+ // Light and heavy are masses 1 and 7. A push of pen pixels is split
119
+ // equally between equal masses; otherwise the heavy car takes pen >> 2.
120
+ // The velocity change on the contact axis is the elastic one for those
121
+ // masses: j gains g, i loses 2rv - g, with g = rv (equal), rv >> 2 (j
122
+ // heavy) or 2rv - (rv >> 2) (i heavy). No multiply.
123
+
124
+ void pair(char i, char j)
125
+ {
126
+ char yi = cy[i] >> 8, yj = cy[j] >> 8;
127
+ char ady = yj >= yi ? yj - yi : yi - yj;
128
+ char sy = hh[i] + hh[j];
129
+ if (ady >= sy)
130
+ return; // apart in Y: most pairs end here
131
+ char xi = cx[i] >> 8, xj = cx[j] >> 8;
132
+ char adx = xj >= xi ? xj - xi : xi - xj;
133
+ char sx = hw[i] + hw[j];
134
+ if (adx >= sx)
135
+ return;
136
+ contacts++;
137
+ char ox = sx - adx, oy = sy - ady;
138
+ bool xaxis = ox < oy;
139
+ char pen = xaxis ? ox : oy;
140
+ char ai, aj;
141
+ if (heavy[i] == heavy[j]) {
142
+ ai = pen >> 1; aj = pen - ai;
143
+ } else if (heavy[i]) {
144
+ ai = pen >> 2; aj = pen - ai;
145
+ } else {
146
+ aj = pen >> 2; ai = pen - aj;
147
+ }
148
+ bool jpos = xaxis ? xj >= xi : yj >= yi; // j lies on the + side of i
149
+ unsigned *p = xaxis ? cx : cy;
150
+ int *v = xaxis ? vx : vy;
151
+ if (jpos) {
152
+ p[i] -= (unsigned)ai << 8; p[j] += (unsigned)aj << 8;
153
+ } else {
154
+ p[i] += (unsigned)ai << 8; p[j] -= (unsigned)aj << 8;
155
+ }
156
+ int rv = v[i] - v[j];
157
+ bool closing = jpos ? rv > 0 : rv < 0;
158
+ if (!closing || (cool[i] && cool[j]))
159
+ return; // separating, or this pair just hit
160
+ int g;
161
+ if (heavy[i] == heavy[j])
162
+ g = rv;
163
+ else if (heavy[j])
164
+ g = rv >> 2;
165
+ else
166
+ g = 2 * rv - (rv >> 2);
167
+ v[j] += g;
168
+ v[i] -= 2 * rv - g;
169
+ cool[i] = COOL;
170
+ cool[j] = COOL;
171
+ hits++;
172
+ }
173
+
174
+ void contact_pass(void)
175
+ {
176
+ for (char i = 0; i + 1 < ncars; i++) {
177
+ if (crash[i])
178
+ continue;
179
+ for (char j = i + 1; j < ncars; j++) {
180
+ if (!crash[j])
181
+ pair(i, j);
182
+ }
183
+ }
184
+ }
185
+
186
+ // A car whose centre is on a grass or water tile has crashed.
187
+ void probe(void)
188
+ {
189
+ for (char c = 0; c < ncars; c++) {
190
+ if (crash[c])
191
+ continue;
192
+ char tc = ((char)(cx[c] >> 8) - 24) >> 3;
193
+ char tr = ((char)(cy[c] >> 8) - 50) >> 3;
194
+ char k = tmap[rowoff[tr] + tc];
195
+ if (k) {
196
+ crash[c] = k;
197
+ vx[c] = 0;
198
+ vy[c] = 0;
199
+ }
200
+ }
201
+ }
202
+
203
+ // --- scripts and movement (fixed_point_8_8), not part of the timed step ---
204
+ int drag(int v)
205
+ {
206
+ if (v > 0) {
207
+ v -= FR;
208
+ if (v < 0) v = 0;
209
+ } else if (v < 0) {
210
+ v += FR;
211
+ if (v > 0) v = 0;
212
+ }
213
+ return v;
214
+ }
215
+
216
+ void drive_and_move(void)
217
+ {
218
+ for (char c = 0; c < N_GAME; c++) {
219
+ if (cool[c]) cool[c]--;
220
+ if (crash[c])
221
+ continue;
222
+ const struct Step *s = scripts[c] + sstep[c];
223
+ if (sleft[c] == 0 && s->n)
224
+ sleft[c] = s->n;
225
+ drv[c] = 0;
226
+ if (s->n) {
227
+ if (s->drive) {
228
+ vx[c] = s->vx;
229
+ vy[c] = s->vy;
230
+ drv[c] = 1;
231
+ }
232
+ if (--sleft[c] == 0)
233
+ sstep[c]++;
234
+ }
235
+ }
236
+ for (char c = 0; c < N_GAME; c++) {
237
+ if (crash[c])
238
+ continue;
239
+ if (!drv[c]) {
240
+ vx[c] = drag(vx[c]);
241
+ vy[c] = drag(vy[c]);
242
+ }
243
+ cx[c] += vx[c];
244
+ cy[c] += vy[c];
245
+ }
246
+ }
247
+
248
+ void reset_cars(void)
249
+ {
250
+ ncars = N_GAME;
251
+ for (char c = 0; c < N_GAME; c++) {
252
+ cx[c] = start_x[c];
253
+ cy[c] = start_y[c];
254
+ vx[c] = 0; vy[c] = 0;
255
+ crash[c] = 0; cool[c] = 0; drv[c] = 0;
256
+ sstep[c] = 0; sleft[c] = 0;
257
+ set_kind(c, kind[c]);
258
+ }
259
+ hits = 0;
260
+ contacts = 0;
261
+ }
262
+
263
+ // --- checksum: the same fold as the Python model ------------------------
264
+ unsigned cs;
265
+
266
+ void fold(unsigned v)
267
+ {
268
+ cs = (cs << 1) | (cs >> 15);
269
+ cs ^= v;
270
+ cs += 13;
271
+ }
272
+
273
+ // --- CIA1 timer B -----------------------------------------------------------
274
+ static inline void timer_start(void)
275
+ {
276
+ cia1.crb = 0x00;
277
+ cia1.tb = 0xffff;
278
+ cia1.crb = 0x11;
279
+ }
280
+
281
+ static inline unsigned timer_stop(void)
282
+ {
283
+ cia1.crb = 0x00;
284
+ return 0xffff - cia1.tb;
285
+ }
286
+
287
+ char pi, pj;
288
+ __noinline void nothing(void) { }
289
+ __noinline void one_pair(void) { pair(pi, pj); }
290
+ __noinline void one_step(void) { contact_pass(); probe(); }
291
+
292
+ unsigned time1(void (*fn)(void))
293
+ {
294
+ __asm { sei }
295
+ timer_start();
296
+ fn();
297
+ unsigned t = timer_stop();
298
+ __asm { cli }
299
+ return t;
300
+ }
301
+
302
+ // Two cars in slots 6 and 7 at given centres and velocities.
303
+ void stage2(char x0, char y0, int v0, char x1, char y1, int v1, char cl, char k0, char k1)
304
+ {
305
+ ncars = MAXC;
306
+ set_kind(6, k0); set_kind(7, k1);
307
+ cx[6] = (unsigned)x0 << 8; cy[6] = (unsigned)y0 << 8; vx[6] = v0; vy[6] = 0;
308
+ cx[7] = (unsigned)x1 << 8; cy[7] = (unsigned)y1 << 8; vx[7] = v1; vy[7] = 0;
309
+ crash[6] = 0; crash[7] = 0;
310
+ cool[6] = cl; cool[7] = cl;
311
+ pi = 6; pj = 7;
312
+ }
313
+
314
+ // Eight cars in a pile-up: slot k at a column and row of a grid, every
315
+ // car closing on its neighbours. dx, dy are the grid steps.
316
+
317
+ void stage8(char dx, char dy)
318
+ {
319
+ ncars = MAXC;
320
+ for (char k = 0; k < MAXC; k++) {
321
+ set_kind(k, k == 2 || k == 5);
322
+ cx[k] = (unsigned)(150 + (k & 1) * dx) << 8;
323
+ cy[k] = (unsigned)(120 + (k >> 1) * dy) << 8;
324
+ vx[k] = (k & 1) ? -256 : 256;
325
+ vy[k] = 192 - (k >> 1) * 128;
326
+ crash[k] = 0;
327
+ cool[k] = 0;
328
+ }
329
+ hits = 0;
330
+ contacts = 0;
331
+ }
332
+
333
+ // Eight cars packed so that all 28 pairs are still in contact when their
334
+ // turn comes and 7 get an impulse, the most one pass allows (each impulse
335
+ // needs a car that is not yet cooling). Found by search on the Python model.
336
+ const unsigned pile_x[MAXC] = { 150 << 8, 150 << 8, 151 << 8, 150 << 8, 150 << 8, 151 << 8, 150 << 8, 151 << 8 };
337
+ const unsigned pile_y[MAXC] = { 120 << 8, 122 << 8, 120 << 8, 122 << 8, 122 << 8, 121 << 8, 120 << 8, 120 << 8 };
338
+ const int pile_vx[MAXC] = { 256, 256, -256, -256, 256, -256, -256, -256 };
339
+ const int pile_vy[MAXC] = { 256, -256, 256, -256, -256, 256, 256, 256 };
340
+ const char pile_k[MAXC] = { 1, 1, 0, 0, 0, 0, 0, 0 };
341
+
342
+ void stage_pile(void)
343
+ {
344
+ ncars = MAXC;
345
+ for (char k = 0; k < MAXC; k++) {
346
+ set_kind(k, pile_k[k]);
347
+ cx[k] = pile_x[k];
348
+ cy[k] = pile_y[k];
349
+ vx[k] = pile_vx[k];
350
+ vy[k] = pile_vy[k];
351
+ crash[k] = 0;
352
+ cool[k] = 0;
353
+ }
354
+ hits = 0;
355
+ contacts = 0;
356
+ }
357
+
358
+ // --- sprite images: a light car and a truck -----------------------------
359
+ void make_images(void)
360
+ {
361
+ for (char i = 0; i < 128; i++)
362
+ SprData[i] = 0;
363
+ // car: columns 7-16, rows 2-17 (10 x 16), centred on column 12, row 10
364
+ for (char r = 2; r < 18; r++) {
365
+ SprData[r * 3 + 0] = 0x01;
366
+ SprData[r * 3 + 1] = 0xff;
367
+ SprData[r * 3 + 2] = 0x80;
368
+ }
369
+ // truck: columns 5-18, rows 0-19 (14 x 20)
370
+ for (char r = 0; r < 20; r++) {
371
+ SprData[64 + r * 3 + 0] = 0x07;
372
+ SprData[64 + r * 3 + 1] = 0xff;
373
+ SprData[64 + r * 3 + 2] = 0xe0;
374
+ }
375
+ }
376
+
377
+ void draw_cars(void)
378
+ {
379
+ for (char c = 0; c < N_GAME; c++) {
380
+ VR[c * 2] = (char)(cx[c] >> 8) - 12; // every car stays below X 256
381
+ VR[c * 2 + 1] = (char)(cy[c] >> 8) - 10;
382
+ PTR[c] = SPR_BLK + heavy[c];
383
+ VR[0x27 + c] = col[c];
384
+ }
385
+ VR[0x10] = 0;
386
+ }
387
+
388
+ void draw_road(void)
389
+ {
390
+ for (char r = 0; r < 25; r++) {
391
+ rowoff[r] = r * 40;
392
+ for (char c = 0; c < 40; c++) {
393
+ char k = c < ROAD_L ? 1 : (c > ROAD_R ? 2 : 0);
394
+ tmap[rowoff[r] + c] = k;
395
+ if (r >= TOP_ROW) {
396
+ unsigned o = rowoff[r] + c;
397
+ Screen[o] = 0xa0;
398
+ Color[o] = k == 1 ? 5 : (k == 2 ? 6 : 11);
399
+ if (k == 0 && (c == 17 || c == 18) && (r & 1))
400
+ Color[o] = 15; // centre dashes
401
+ }
402
+ }
403
+ }
404
+ }
405
+
406
+ // --- text (screen codes) ------------------------------------------------------
407
+ void put_str(char *p, const char *s)
408
+ {
409
+ while (*s)
410
+ *p++ = *s++;
411
+ }
412
+
413
+ void put_dec(char *p, unsigned v, char digits)
414
+ {
415
+ for (char i = digits; i > 0; i--) {
416
+ p[i - 1] = 0x30 + v % 10;
417
+ v /= 10;
418
+ }
419
+ }
420
+
421
+ void put_hex(char *p, unsigned v)
422
+ {
423
+ for (char i = 4; i > 0; i--) {
424
+ char d = v & 15;
425
+ p[i - 1] = d < 10 ? 0x30 + d : d - 9;
426
+ v >>= 4;
427
+ }
428
+ }
429
+
430
+ // --- expected results of one pass, from the Python model --------------------
431
+ #define EXP_CS 0x01e9
432
+ #define EXP_HITS 7
433
+ const char exp_crash[N_GAME] = { 0, 2, 1, 1, 1, 0 };
434
+
435
+ int main(void)
436
+ {
437
+ vic.color_border = 0;
438
+ vic.color_back = 0;
439
+ for (unsigned i = 0; i < 1000; i++) {
440
+ Screen[i] = 0x20;
441
+ Color[i] = 1;
442
+ }
443
+ make_images();
444
+ draw_road();
445
+
446
+ put_str(Screen + 0, s"car contact response frame pass");
447
+ put_str(Screen + 1 * 40, s"result cs expect");
448
+ put_str(Screen + 2 * 40, s"hits expect 7 contacts cr");
449
+ put_str(Screen + 3 * 40, s"pair far xmiss hit cool");
450
+ put_str(Screen + 4 * 40, s"step max min mean");
451
+ put_str(Screen + 5 * 40, s"grid h c pile h c");
452
+ put_str(Screen + 6 * 40, s"truck hit i j cool i j");
453
+
454
+ // Per-pair and staged worst-frame costs, display blanked, less an
455
+ // empty call.
456
+ vic.ctrl1 &= ~VIC_CTRL1_DEN;
457
+ vic_waitFrame();
458
+ vic_waitFrame();
459
+ for (char c = 0; c < N_GAME; c++)
460
+ crash[c] = 1; // the game slots sit out
461
+ unsigned t_none = time1(nothing);
462
+ stage2(150, 100, 0, 150, 200, 0, 0, 0, 0);
463
+ unsigned t_far = time1(one_pair) - t_none;
464
+ stage2(150, 100, 0, 180, 104, 0, 0, 0, 0);
465
+ unsigned t_xmiss = time1(one_pair) - t_none;
466
+ stage2(150, 100, 256, 158, 102, -256, 0, 0, 0);
467
+ unsigned t_hit = time1(one_pair) - t_none;
468
+ stage2(150, 100, 256, 158, 102, -256, COOL, 0, 0);
469
+ unsigned t_cool = time1(one_pair) - t_none;
470
+ stage2(150, 100, 256, 158, 102, -256, 0, 1, 0);
471
+ unsigned t_hit_i = time1(one_pair) - t_none; // i is the truck
472
+ stage2(150, 100, 256, 158, 102, -256, 0, 0, 1);
473
+ unsigned t_hit_j = time1(one_pair) - t_none; // j is the truck
474
+ stage2(150, 100, 256, 158, 102, -256, COOL, 1, 0);
475
+ unsigned t_cool_i = time1(one_pair) - t_none;
476
+ stage2(150, 100, 256, 158, 102, -256, COOL, 0, 1);
477
+ unsigned t_cool_j = time1(one_pair) - t_none;
478
+ stage8(8, 14); // a 2 x 4 grid, neighbours touching
479
+ unsigned t_grid = time1(one_step) - t_none;
480
+ char grid_hits = hits, grid_contacts = contacts;
481
+ stage_pile(); // all 28 pairs in contact
482
+ unsigned t_pile = time1(one_step) - t_none;
483
+ char pile_hits = hits, pile_contacts = contacts;
484
+ vic.ctrl1 |= VIC_CTRL1_DEN;
485
+ put_dec(Screen + 3 * 40 + 9, t_far, 3);
486
+ put_dec(Screen + 3 * 40 + 19, t_xmiss, 3);
487
+ put_dec(Screen + 3 * 40 + 27, t_hit, 3);
488
+ put_dec(Screen + 3 * 40 + 36, t_cool, 3);
489
+ put_dec(Screen + 6 * 40 + 12, t_hit_i, 3);
490
+ put_dec(Screen + 6 * 40 + 18, t_hit_j, 3);
491
+ put_dec(Screen + 6 * 40 + 29, t_cool_i, 3);
492
+ put_dec(Screen + 6 * 40 + 35, t_cool_j, 3);
493
+ put_dec(Screen + 5 * 40 + 5, t_grid, 5);
494
+ put_dec(Screen + 5 * 40 + 12, grid_hits, 2);
495
+ put_dec(Screen + 5 * 40 + 16, grid_contacts, 2);
496
+ put_dec(Screen + 5 * 40 + 25, t_pile, 5);
497
+ put_dec(Screen + 5 * 40 + 32, pile_hits, 2);
498
+ put_dec(Screen + 5 * 40 + 36, pile_contacts, 2);
499
+ put_hex(Screen + 1 * 40 + 29, EXP_CS);
500
+
501
+ reset_cars();
502
+ cs = 0;
503
+ VR[0x15] = (1 << N_GAME) - 1;
504
+ VR[0x1b] = 0;
505
+ VR[0x1c] = 0;
506
+ VR[0x17] = 0;
507
+ VR[0x1d] = 0;
508
+ char frame = 0, pass = 0, fault = 0;
509
+ unsigned total = 0, s_max = 0, s_min = 0xffff, s_mean = 0;
510
+ unsigned long s_sum = 0; // over one pass, for the mean
511
+
512
+ for (;;) {
513
+ vic_waitFrame();
514
+ drive_and_move();
515
+ __asm { sei }
516
+ timer_start();
517
+ contact_pass();
518
+ probe();
519
+ unsigned ts = timer_stop();
520
+ __asm { cli }
521
+ if (ts > s_max) s_max = ts;
522
+ if (ts < s_min) s_min = ts;
523
+ s_sum += ts;
524
+ draw_cars();
525
+ for (char c = 0; c < N_GAME; c++) {
526
+ fold(cx[c]);
527
+ fold(cy[c]);
528
+ fold(vx[c]);
529
+ fold(vy[c]);
530
+ fold(crash[c]);
531
+ }
532
+ vic_waitBelow(112); // write the HUD after the beam has passed it
533
+
534
+ put_dec(Screen + 28, total, 5);
535
+ put_dec(Screen + 39, pass, 1);
536
+ put_hex(Screen + 1 * 40 + 17, cs);
537
+ put_dec(Screen + 2 * 40 + 5, hits, 2);
538
+ put_dec(Screen + 2 * 40 + 27, contacts, 2);
539
+ for (char c = 0; c < N_GAME; c++)
540
+ Screen[2 * 40 + 33 + c] = 0x30 + crash[c];
541
+ put_dec(Screen + 4 * 40 + 9, s_max, 4);
542
+ put_dec(Screen + 4 * 40 + 18, s_min, 4);
543
+ put_dec(Screen + 4 * 40 + 29, s_mean, 4);
544
+
545
+ total++;
546
+ if (++frame == 0) { // end of a 256-frame pass
547
+ if (cs != EXP_CS) fault = 1;
548
+ if (hits != EXP_HITS) fault = 2;
549
+ for (char c = 0; c < N_GAME; c++)
550
+ if (crash[c] != exp_crash[c]) fault = 3;
551
+ RESULT = fault ? 2 : 1;
552
+ vic.color_border = fault ? 2 : 5;
553
+ put_str(Screen + 40 + 7, fault ? s"fail" : s"pass");
554
+ Screen[40 + 12] = 0x30 + fault;
555
+ pass++;
556
+ s_mean = s_sum >> 8; // 256 frames
557
+ s_sum = 0;
558
+ reset_cars();
559
+ cs = 0;
560
+ }
561
+ }
562
+ return 0;
563
+ }
564
+ ```
565
+
566
+ ## Build
567
+
568
+ ```bash
569
+ oscar64 -tm=c64 -O2 -o=car-contact.prg car-contact.c
570
+ ```
571
+
572
+ Produces `car-contact.prg`, 4,442 bytes. The two sprite images are built
573
+ at run time at `$3000`, blocks 192 and 193. Then run headless in VICE
574
+ (PAL):
575
+
576
+ ```bash
577
+ GSETTINGS_SCHEMA_DIR=/opt/homebrew/share/glib-2.0/schemas x64sc -default -warp +sound \
578
+ +autostart-delay-random -autostartprgmode 1 -limitcycles 11880000 \
579
+ -exitscreenshot car-contact.png -autostart car-contact.prg
580
+ ```
581
+
582
+ Add `-model ntsc` for the NTSC picture. A pass is 256 frames; the verdict
583
+ is posted at the end of the first pass. The pinned cycle count lands in
584
+ the second pass: PAL at pass frame 181, in the middle of the shove, and
585
+ NTSC at pass frame 237, after every scene has ended.
586
+
587
+ ## Expected output
588
+
589
+ The cars, their masses and boxes, and the scenes. X and Y are the centre
590
+ of the body in sprite coordinates; a light car's body is 10 x 16 pixels,
591
+ a truck's 14 x 20. The road is tile columns 9 to 26, VIC X 96 to 239;
592
+ columns below 9 are grass, above 26 water. Velocities are 8.8 fixed point
593
+ in 1/256 pixel per frame; drag while coasting is 4 per frame on each axis.
594
+
595
+ | Car | Kind, colour | Start | Script |
596
+ |---|---|---|---|
597
+ | 0 | light, white (player) | 160, 200 | steer right at 384 for frames 1-10; coast; steer left at -383 for frames 61-76; coast; steer left at -1536 for frames 170-181; coast |
598
+ | 1 | light, yellow | 185, 196 | coast |
599
+ | 2 | truck, orange | 140, 200 | coast |
600
+ | 3 | light, cyan | 120, 150 | coast |
601
+ | 4 | light, light green | 120, 190 | drive up at -192 for frames 1-33; coast; drive up at -128 for frames 64-91; stop; coast |
602
+ | 5 | truck, purple | 165, 142 | wait; at frame 120 launched left at -384; coast |
603
+
604
+ The events of one pass, from the Python model below; the checksum makes
605
+ the C run agree with it on every frame:
606
+
607
+ | Pass frame | Event |
608
+ |---|---|
609
+ | 11 | Side-swipe. The player (vx 380) touches car 1 from the left; equal masses swap, so the player's vx is 0 and car 1's is 380, 1.48 pixels a frame. |
610
+ | 33 | Bump from behind. Car 4 (vy -192) runs into car 3; car 3 takes vy -192 and car 4 stops. |
611
+ | 61 | Car 1's centre reaches X 240, a water tile: crashed. |
612
+ | 77 | Heavy truck. The player (vx -379 after drag) hits truck 2. The truck gets -95, the player bounces to +284. The truck coasts from X 140 to 135 and stops. |
613
+ | 145 | Two contacts in one frame. Truck 5 (vx -284) reaches cars 3 and 4. Car 3 gets -497; the truck slows to -213; car 4 then gets -373 and the truck -160. |
614
+ | 158, 163 | Cars 3 and 4 reach X 95, a grass tile: crashed. |
615
+ | 177 | Shove. The player (vx -1536) reaches truck 2 with a 5-pixel overlap. The truck is pushed 1 pixel (`5 >> 2`) and the player 4; the truck gets -384 and the player +1152. |
616
+ | 178-184 | Both cars cooling. The player's steering sets vx back to -1536 each frame to 181, then it coasts. Each frame the pair overlaps by 4 or 5 pixels, the truck is pushed 1 pixel and the player the rest, and no impulse is given. |
617
+ | 185 | Cooling over. A second impulse: the truck gets -644, the player +524. |
618
+ | 193 | Truck 2 reaches X 95, a grass tile: crashed. |
619
+
620
+ At the end of the pass: 7 impulses, 14 overlapping pair-frames, crash
621
+ flags `0 2 1 1 1 0` (0 on the road, 1 grass, 2 water), checksum `$01E9`.
622
+
623
+ Measured in VICE x64sc 3.10 with the pinned command, text decoded against
624
+ the character ROM (rows 0 to 6). PAL, frame 437, pass 1 frame 181:
625
+
626
+ ```text
627
+ CAR CONTACT RESPONSE FRAME 00437 PASS 1
628
+ RESULT PASS 0 CS 455B EXPECT 01E9
629
+ HITS 06 EXPECT 7 CONTACTS 10 CR 020110
630
+ PAIR FAR 087 XMISS 147 HIT 634 COOL 505
631
+ STEP MAX 3695 MIN 0828 MEAN 2081
632
+ GRID 10949 H07 C12 PILE 17549 H07 C28
633
+ TRUCK HIT I 701 J 666 COOL I 513 J 513
634
+ ```
635
+
636
+ NTSC, frame 493, pass 1 frame 237:
637
+
638
+ ```text
639
+ CAR CONTACT RESPONSE FRAME 00493 PASS 1
640
+ RESULT PASS 0 CS B052 EXPECT 01E9
641
+ HITS 07 EXPECT 7 CONTACTS 14 CR 021110
642
+ PAIR FAR 087 XMISS 147 HIT 634 COOL 505
643
+ STEP MAX 3910 MIN 0828 MEAN 2152
644
+ GRID 10949 H07 C12 PILE 17549 H07 C28
645
+ TRUCK HIT I 701 J 666 COOL I 513 J 513
646
+ ```
647
+
648
+ `RESULT PASS 0` is the first pass's verdict. `CS` is the running checksum
649
+ of the pass so far, and both values equal the Python model's at the same
650
+ frame (`$455B` at 181, `$B052` at 237). `CR` is the six crash flags.
651
+ `MEAN` is the mean of the timed step over the 256 frames of the previous
652
+ pass. A run to 16,000,000 cycles shows pass 2 green on both models, with
653
+ `MEAN` 2,079 on PAL and 2,152 on NTSC for pass 1. Border green, `$02FF` =
654
+ `01`.
655
+
656
+ The picture, measured with PIL: every pixel of each car's colour below
657
+ the HUD, as a bounding box, with VIC X = PNG x - 8 and sprite Y = raster
658
+ line - 1 (a sprite at Y first shows on raster line Y + 1,
659
+ `hardware/vic-ii-reference.md`). All six boxes have the body size of
660
+ their kind, and every centre equals the model's.
661
+
662
+ | Car | PAL (model frame 181) | NTSC (model frame 238) |
663
+ |---|---|---|
664
+ | 0 | 136, 200, against the truck | 213, 200 |
665
+ | 1 | 240, 196, in the water | 240, 196, in the water |
666
+ | 2 | 124, 200, being shoved left | 95, 200, on the grass |
667
+ | 3 | 95, 132, on the grass | 95, 132, on the grass |
668
+ | 4 | 95, 152, on the grass | 95, 152, on the grass |
669
+ | 5 | 118, 142 | 118, 142 |
670
+
671
+ On PAL the player's left edge (136 - 5) meets the truck's right edge
672
+ (124 + 7) at X 131: the push leaves the pair just touching. The HUD is
673
+ written after the beam has passed row 6 (`vic_waitBelow(112)`), so all
674
+ seven rows come from one frame. The PAL shot shows frame 181's cars under
675
+ frame 181's HUD; the NTSC shot lands after frame 238 has written the
676
+ sprite registers and before it has written the text. The road edges
677
+ measured on the PAL picture: grass to VIC X 95, road from 96, water from
678
+ 240. The screenshots are `screenshots/car-contact.png` and
679
+ `screenshots/car-contact-ntsc.png`.
680
+
681
+ The cycle figures, CIA1 timer B, interrupts masked, Oscar64 `-O2`:
682
+
683
+ | Figure | Cycles | Conditions |
684
+ |---|---|---|
685
+ | One pair, apart in Y | 87 | screen blanked, one call through a wrapper, less an empty call |
686
+ | One pair, overlapping in Y, apart in X | 147 | as above |
687
+ | One pair of light cars in contact, pushed apart and given an impulse | 634 | as above |
688
+ | The same pair while both cool, pushed apart only | 505 | as above |
689
+ | A truck and a light car in contact with an impulse, the truck as `i` | 701 | as above; `g = 2 * rv - (rv >> 2)` |
690
+ | The same, the truck as `j` | 666 | as above; `g = rv >> 2` |
691
+ | A truck and a light car while both cool, the truck as `i` or as `j` | 513 | as above |
692
+ | Contact step, 8 cars in a 2 x 4 grid, neighbours overlapping by 2 pixels | 10,949 | screen blanked; 28 pairs tested, 12 contacts, 7 impulses; includes the tile probe |
693
+ | Contact step, 8 cars packed so that all 28 pairs are in contact | 17,549 | screen blanked; 28 contacts, 7 impulses; includes the probe |
694
+ | Contact step in the game, worst and best frame over two passes | 3,695 PAL, 3,910 NTSC, and 828 | screen on, six cars, up to 15 pairs and the probe |
695
+ | Contact step in the game, mean over one 256-frame pass | 2,081 PAL (2,079 for the second pass), 2,152 NTSC | as above |
696
+
697
+ The packed pile is the most a contact step can do with eight cars: all 28
698
+ pairs are in contact when their turn comes, and 7 impulses is the most one
699
+ pass allows, because an impulse needs a car that is not yet cooling and
700
+ the first one uses two. Its start positions and velocities were found by
701
+ a search over the Python model. It is a built frame, not a bound: its
702
+ contacts are a mix of light and truck pairs. The bound by arithmetic
703
+ (rung 3) takes the same counts with every impulse at the dearest measured
704
+ pair, 701, and every other contact at 513: 17,549 + 7 x (701 - 634) +
705
+ 21 x (513 - 505) = 18,186 cycles, on the assumption that no contact in
706
+ the pile costs less than the light-car figures. That bound was not
707
+ measured. The best game frame, 828, comes after the crashes: a crashed
708
+ car leaves the pair loop. The in-game peak differs between PAL and NTSC because different badlines and
709
+ sprite DMA land inside the timed region.
710
+
711
+ The Python side of the checksum:
712
+
713
+ ```python
714
+ # The rules of car-contact.c in Python, same integers, same order.
715
+ # Prints the checksum of one 256-frame pass: 0x1e9.
716
+
717
+ N = 6
718
+ COOL = 8
719
+ FR = 4
720
+ ROAD_L, ROAD_R = 9, 26 # road columns inclusive; <9 grass (1), >26 water (2)
721
+
722
+ def cls(col):
723
+ if col < ROAD_L: return 1
724
+ if col > ROAD_R: return 2
725
+ return 0
726
+
727
+ # light 0, heavy 1
728
+ MASS = [0, 0, 1, 0, 0, 1]
729
+ HW = [5, 5, 7, 5, 5, 7]
730
+ HH = [8, 8, 10, 8, 8, 10]
731
+ START = [(160,200),(185,196),(140,200),(120,150),(120,190),(165,142)]
732
+ # script steps: (vx, vy, n, drive); n == 0 ends: coast for ever
733
+ SCR = [
734
+ [(0,0,1,1),(384,0,10,1),(0,0,50,0),(-383,0,16,1),(0,0,93,0),(-1536,0,12,1),(0,0,0,0)],
735
+ [(0,0,1,1),(0,0,0,0)],
736
+ [(0,0,1,1),(0,0,0,0)],
737
+ [(0,0,1,1),(0,0,0,0)],
738
+ [(0,0,1,1),(0,-192,33,1),(0,0,30,0),(0,-128,28,1),(0,0,1,1),(0,0,0,0)],
739
+ [(0,0,120,1),(-384,0,1,1),(0,0,0,0)],
740
+ ]
741
+
742
+ class W: pass
743
+
744
+ def reset():
745
+ w = W()
746
+ w.x = [s[0] << 8 for s in START]
747
+ w.y = [s[1] << 8 for s in START]
748
+ w.vx = [0]*N; w.vy = [0]*N; w.crash = [0]*N; w.cool = [0]*N
749
+ w.step = [0]*N; w.left = [0]*N; w.drive = [0]*N
750
+ w.hits = 0; w.contacts = 0
751
+ return w
752
+
753
+ def drive(w):
754
+ for c in range(N):
755
+ if w.cool[c]: w.cool[c] -= 1
756
+ if w.crash[c]: continue
757
+ if w.left[c] == 0:
758
+ s = SCR[c][w.step[c]]
759
+ if s[2] == 0:
760
+ w.drive[c] = 0
761
+ else:
762
+ w.left[c] = s[2]
763
+ s = SCR[c][w.step[c]]
764
+ if s[2] and s[3]:
765
+ w.vx[c] = s[0]; w.vy[c] = s[1]; w.drive[c] = 1
766
+ else:
767
+ w.drive[c] = 0
768
+ if s[2]:
769
+ w.left[c] -= 1
770
+ if w.left[c] == 0: w.step[c] += 1
771
+
772
+ def fric(v):
773
+ if v > 0:
774
+ v -= FR
775
+ if v < 0: v = 0
776
+ elif v < 0:
777
+ v += FR
778
+ if v > 0: v = 0
779
+ return v
780
+
781
+ def move(w):
782
+ for c in range(N):
783
+ if w.crash[c]: continue
784
+ if not w.drive[c]:
785
+ w.vx[c] = fric(w.vx[c]); w.vy[c] = fric(w.vy[c])
786
+ w.x[c] = (w.x[c] + w.vx[c]) & 0xffff
787
+ w.y[c] = (w.y[c] + w.vy[c]) & 0xffff
788
+
789
+ def share(pen, mi, mj):
790
+ if mi == mj:
791
+ ai = pen >> 1; aj = pen - ai
792
+ elif mi:
793
+ ai = pen >> 2; aj = pen - ai
794
+ else:
795
+ aj = pen >> 2; ai = pen - aj
796
+ return ai, aj
797
+
798
+ def impulse(rv, mi, mj):
799
+ if mi == mj: g = rv
800
+ elif mj: g = rv >> 2
801
+ else: g = 2*rv - (rv >> 2)
802
+ return g, 2*rv - g # dv_j = +g, dv_i = -(2rv - g)
803
+
804
+ def pair(w, i, j):
805
+ dy = (w.y[j] >> 8) - (w.y[i] >> 8)
806
+ oy = HH[i] + HH[j] - abs(dy)
807
+ if oy <= 0: return
808
+ dx = (w.x[j] >> 8) - (w.x[i] >> 8)
809
+ ox = HW[i] + HW[j] - abs(dx)
810
+ if ox <= 0: return
811
+ w.contacts += 1
812
+ mi, mj = MASS[i], MASS[j]
813
+ both = w.cool[i] and w.cool[j]
814
+ if ox < oy:
815
+ ai, aj = share(ox, mi, mj)
816
+ if dx >= 0:
817
+ w.x[i] -= ai << 8; w.x[j] += aj << 8
818
+ else:
819
+ w.x[i] += ai << 8; w.x[j] -= aj << 8
820
+ rv = w.vx[i] - w.vx[j]
821
+ app = rv > 0 if dx >= 0 else rv < 0
822
+ if app and not both:
823
+ g, h = impulse(rv, mi, mj)
824
+ w.vx[j] += g; w.vx[i] -= h
825
+ w.cool[i] = w.cool[j] = COOL; w.hits += 1
826
+ else:
827
+ ai, aj = share(oy, mi, mj)
828
+ if dy >= 0:
829
+ w.y[i] -= ai << 8; w.y[j] += aj << 8
830
+ else:
831
+ w.y[i] += ai << 8; w.y[j] -= aj << 8
832
+ rv = w.vy[i] - w.vy[j]
833
+ app = rv > 0 if dy >= 0 else rv < 0
834
+ if app and not both:
835
+ g, h = impulse(rv, mi, mj)
836
+ w.vy[j] += g; w.vy[i] -= h
837
+ w.cool[i] = w.cool[j] = COOL; w.hits += 1
838
+ w.x[i] &= 0xffff; w.x[j] &= 0xffff; w.y[i] &= 0xffff; w.y[j] &= 0xffff
839
+
840
+ def contacts(w):
841
+ for i in range(N - 1):
842
+ if w.crash[i]: continue
843
+ for j in range(i + 1, N):
844
+ if w.crash[j]: continue
845
+ pair(w, i, j)
846
+
847
+ def probe(w):
848
+ for c in range(N):
849
+ if w.crash[c]: continue
850
+ col = ((w.x[c] >> 8) - 24) >> 3
851
+ k = cls(col)
852
+ if k:
853
+ w.crash[c] = k; w.vx[c] = 0; w.vy[c] = 0
854
+
855
+ def fold(cs, v):
856
+ cs = ((cs << 1) | (cs >> 15)) & 0xffff
857
+ cs ^= v & 0xffff
858
+ return (cs + 13) & 0xffff
859
+
860
+ def run(frames=256, stop=None):
861
+ w = reset(); cs = 0
862
+ for f in range(frames):
863
+ drive(w); move(w); contacts(w); probe(w)
864
+ for c in range(N):
865
+ cs = fold(cs, w.x[c]); cs = fold(cs, w.y[c])
866
+ cs = fold(cs, w.vx[c]); cs = fold(cs, w.vy[c])
867
+ cs = fold(cs, w.crash[c])
868
+ if stop is not None and f == stop:
869
+ return w, cs
870
+ return w, cs
871
+
872
+ w, cs = run()
873
+ print(hex(cs), w.hits, w.crash)
874
+ ```
875
+
876
+ ## Why this works
877
+
878
+ The pair test is ordered so most pairs cost one compare. Cars on a road
879
+ are spread along it, so the Y distance is taken first from the high bytes
880
+ of the 8.8 centres and compared with the two half heights; 87 cycles end
881
+ a pair there. Only a pair that overlaps in both axes computes the two
882
+ overlaps, and the smaller one is the axis to resolve: two cars side by
883
+ side overlap a little in X and a lot in Y, so they are pushed sideways,
884
+ and a nose-to-tail pair the other way. A tie goes to Y.
885
+
886
+ Mass is two numbers, both from shifts. The push that removes the overlap
887
+ is split in half between equal cars; a truck takes `pen >> 2` of it and
888
+ the light car the rest. That share is a chosen value that keeps a truck
889
+ nearly still, not the mass ratio (1/8). The velocity change on the
890
+ contact axis is the elastic one for masses 1 and 7 (arithmetic, rung 3):
891
+ with `rv` the closing velocity, the car on the far side gains `g` and the
892
+ near one loses `2 * rv - g`, where `g` is `rv` for equal masses, `rv >> 2`
893
+ when the far car is the truck (2/8 of `2 * rv`) and `2 * rv - (rv >> 2)`
894
+ when the near one is. Momentum is kept to the rounding of one shift.
895
+ Equal cars therefore swap their velocities on that axis, which is the
896
+ side-swipe and the bump from behind; a light car hitting a truck bounces
897
+ off and the truck moves by a quarter of the closing speed, which is why
898
+ truck 2 coasts 5 pixels.
899
+
900
+ The shift must be arithmetic: `rv >> 2` of -379 is -95, where a divide
901
+ that truncates gives -94. The player's -383 steer was chosen so that this
902
+ case occurs in the pass. Built with `rv / 4` in place of `rv >> 2`, the
903
+ program fails on the checksum alone (fault 1), everything else equal;
904
+ built with `rv >> 1`, car 4 stays on the road and the crash check fails
905
+ (fault 3). In assembly, halving a signed value is `cmp #$80 / ror` on the
906
+ high byte, then `ror` on the low byte (`asr1` in `sine_table_generation`),
907
+ not `lsr`, which would turn -2 into +127 in a byte.
908
+
909
+ An impulse needs the pair to be closing, and not both cars cooling. The
910
+ closing test compares the sign of `rv` with the side the other car is on,
911
+ a signed compare. Positions are still separated during the cooling time,
912
+ so a car held against a truck by its driver stays against it instead of
913
+ passing through, but cannot kick it again every frame: in the shove the
914
+ pair is in contact for nine frames and gets two impulses, eight frames
915
+ apart. The shove is also what the checksum uses to check both rules.
916
+ Built with no cooling test, the shove gives an impulse on every closing
917
+ frame, 10 impulses in the pass, the player follows the truck onto the grass
918
+ and the crash check fails (fault 3). Built with the truck taking
919
+ `pen >> 1` of the push, the checksum fails (fault 1). Each result was
920
+ run in VICE and matches the Python model with the same change.
921
+
922
+ The cooling counter is per car, not per pair. A car that is cooling can
923
+ still be hit by a third car that is not: the truck in the double contact
924
+ gives an impulse to car 3 and then to car 4 in the same frame, because
925
+ car 4 was not cooling. The other side of this: two cars that have each
926
+ just hit something else get no impulse on their first touch with each
927
+ other, only the push.
928
+
929
+ The tile probe runs after the pair loop, because a push can move a car
930
+ onto a verge. It reads the class of the tile under the car's centre from
931
+ a map in RAM (`tile_grid_collision`), never screen RAM, so the HUD or a
932
+ redraw cannot change what counts as road. The probe does not check its
933
+ row: a centre above sprite Y 50, or at 250 or below, gives a tile row
934
+ outside 0 to 24 and reads past `rowoff`. The cars here stay between
935
+ Y 132 and 200; a car that can leave the screen needs the row clamped.
936
+ Every car stays below X 256 on this road, so `$D010` is always 0; a
937
+ wider road needs the ninth bit.
938
+
939
+ The checksum is a second computation, not the first repeated: the Python
940
+ model on this page runs the same rules on its own integers and predicts
941
+ the pass's value, and the HUD's running value matches the model's at the
942
+ frame each screenshot shows. An earlier build stored the start positions
943
+ as bytes and shifted them left by 8 in `reset_cars`; the Oscar64 build on
944
+ this machine compiled that loop as `LDA start_x,Y / TAY / LDA start_y,Y`,
945
+ so each Y came from the wrong entry and the checksum failed. The fault
946
+ reduces to a short program: two `const char` tables read with one index,
947
+ each shifted left by 8 into an `unsigned` array, in a loop that also calls
948
+ a `__noinline` function. Run in VICE, it is wrong at `-O1`, `-O2`, `-O3`
949
+ and `-Os` and right at `-O0`; it is recorded in issue #30. The listing
950
+ stores the start positions, and the pile's, as 8.8 words.