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,781 @@
1
+ ---
2
+ recipe: mixed-fighters
3
+ toolchain: oscar64
4
+ output_format: PRG
5
+ region: both
6
+ techniques: [mixed_sprite_char_actors, mob_priority]
7
+ file_formats: [PRG]
8
+ uses_registers: [D000, D001, D002, D003, D004, D005, D006, D007, D010, D011, D015, D016, D017, D018, D01B, D01C, D01D, D020, D021, D022, D023, D025, D026, D027, D028, D029, D02A, DC06, DC07, DC0F]
9
+ uses_kernal: []
10
+ ---
11
+
12
+ <!-- doc-type: recipe -->
13
+
14
+ # Oscar64 mixed fighters: one fighter in four sprites, one in pre-shifted character cells, crossing with $D01B priority
15
+
16
+ ## Synopsis
17
+
18
+ Two fighters on a plain backdrop, drawn two different ways. Fighter A
19
+ is four multicolour hardware sprites in a 2 x 2 block, 48 x 42 pixels.
20
+ Fighter B is a 5 x 6 block of multicolour character cells whose 30
21
+ glyphs, codes 128 to 157, belong to B alone. B's picture is 16
22
+ multicolour pixels (32 screen pixels) by 48 rows, stored pre-shifted
23
+ at the four multicolour-pixel offsets inside a cell, so B moves in
24
+ 2-pixel steps while its block of codes moves in whole cells. A script
25
+ runs on autopilot: the two walk in and overlap with A in front, A
26
+ strikes, they walk through each other with B in front (A's `$D01B`
27
+ bits set), come back and hold overlapped. At 17 checkpoint ticks the
28
+ program hashes the arena's 240 screen codes, B's 240 glyph bytes and
29
+ A's sprite registers and compares them with the table the Python
30
+ model below prints. CIA1 timer B times the actor update every tick
31
+ and each part of it once with the screen blank. `$02FF` = `01` and a
32
+ green border on a pass, `02` and red otherwise (`headless-verify.md`).
33
+ This is the `mixed_sprite_char_actors` technique from
34
+ `docs/techniques/sprite.md`, with `mob_priority` deciding who is in
35
+ front.
36
+
37
+ ## Source
38
+
39
+ ```c
40
+ // mixed-fighters.c
41
+ //
42
+ // Two fighters drawn two ways. Fighter A is four multicolour hardware
43
+ // sprites, 2 x 2, 48 x 42 pixels. Fighter B is a 5 x 6 block of
44
+ // multicolour character cells whose 30 glyphs (codes 128 to 157) are
45
+ // rewritten from a pre-shifted table, so B moves in 2-pixel steps
46
+ // although its cells move in 8-pixel steps. A scripted fight runs on
47
+ // autopilot: they walk in and overlap with A in front, A strikes, they
48
+ // cross with B in front ($D01B), come back and hold overlapped.
49
+ // At checkpoint ticks the program hashes the arena's screen codes, the
50
+ // 240 glyph bytes and the sprite registers and compares them with a
51
+ // table printed by the page's Python model. CIA1 timer B times the
52
+ // actor update each tick and each part of it once with the screen blank.
53
+ // $02FF = 01 and a green border on a pass, 02 and red if not.
54
+ //
55
+ #include <c64/vic.h>
56
+ #include <c64/cia.h>
57
+
58
+ #define Screen ((char *)0x0400)
59
+ #define Color ((char *)0xd800)
60
+ #define Chars ((char *)0x3000) // $D018 = $1C
61
+ #define SprData ((char *)0x3800) // blocks 224..231
62
+ #define SPR_BLK 224
63
+ #define VR ((volatile char *)0xd000)
64
+ #define PTR ((volatile char *)0x07f8)
65
+ #define PORT (*(volatile char *)0x0001)
66
+ #define RESULT (*(volatile char *)0x02ff)
67
+
68
+ #define ROW0 13 // top row of the arena
69
+ #define ROWS 6
70
+ #define BASE 128 // B's glyph range, 30 codes
71
+ #define SPACE 32
72
+ #define FLOOR 160
73
+ #define SPR_Y 154 // A's top sprite Y register
74
+ #define A_MASK 0x0f // A owns sprites 0 to 3
75
+
76
+ // --- art: rectangles in multicolour pixels (x0, y0, x1, y1, bit pair) ----
77
+ struct Rect { char x0, y0, x1, y1, v; };
78
+
79
+ const struct Rect char_body[5] = {
80
+ {6, 0, 9, 9, 2}, {4, 10, 11, 25, 3}, {4, 26, 11, 29, 1},
81
+ {4, 30, 6, 47, 3}, {9, 30, 11, 47, 3}};
82
+ const struct Rect char_arms[2][2] = {
83
+ {{2, 12, 3, 25, 2}, {12, 12, 13, 25, 2}},
84
+ {{1, 4, 3, 11, 2}, {12, 4, 14, 11, 2}}};
85
+ const struct Rect spr_body[5] = {
86
+ {10, 0, 13, 9, 1}, {8, 10, 15, 25, 2}, {8, 26, 15, 28, 3},
87
+ {8, 29, 10, 41, 2}, {13, 29, 15, 41, 2}};
88
+ const struct Rect spr_arms[2][2] = {
89
+ {{6, 12, 7, 25, 1}, {16, 12, 17, 25, 1}},
90
+ {{5, 4, 7, 11, 1}, {16, 4, 18, 11, 1}}};
91
+
92
+ // B's canvas, 16 multicolour pixels (4 bytes) by 48 rows, one pose
93
+ char bcanvas[48 * 4];
94
+ // the pre-shifted glyphs: pose * 4 + shift, 240 bytes each in glyph order
95
+ char preshift[8][240];
96
+
97
+ void canvas_rect(char *c, char stride, const struct Rect *r)
98
+ {
99
+ for (char y = r->y0; y <= r->y1; y++)
100
+ for (char x = r->x0; x <= r->x1; x++) {
101
+ char *p = c + y * stride + (x >> 2);
102
+ char sh = 6 - 2 * (x & 3);
103
+ *p = (*p & ~(3 << sh)) | (r->v << sh);
104
+ }
105
+ }
106
+
107
+ void build_char_fighter(void)
108
+ {
109
+ for (char pose = 0; pose < 2; pose++) {
110
+ for (char i = 0; i < 192; i++)
111
+ bcanvas[i] = 0;
112
+ for (char i = 0; i < 5; i++)
113
+ canvas_rect(bcanvas, 4, char_body + i);
114
+ for (char i = 0; i < 2; i++)
115
+ canvas_rect(bcanvas, 4, char_arms[pose] + i);
116
+ for (char s = 0; s < 4; s++) {
117
+ char *g = preshift[pose * 4 + s];
118
+ for (char r = 0; r < 48; r++) {
119
+ char w[5];
120
+ w[0] = bcanvas[r * 4]; w[1] = bcanvas[r * 4 + 1];
121
+ w[2] = bcanvas[r * 4 + 2]; w[3] = bcanvas[r * 4 + 3];
122
+ w[4] = 0;
123
+ for (char k = 0; k < 2 * s; k++) { // shift right 2s bits
124
+ char c = 0;
125
+ for (char j = 0; j < 5; j++) {
126
+ char n = w[j] & 1;
127
+ w[j] = (w[j] >> 1) | (c << 7);
128
+ c = n;
129
+ }
130
+ }
131
+ for (char cx = 0; cx < 5; cx++)
132
+ g[((r >> 3) * 5 + cx) * 8 + (r & 7)] = w[cx];
133
+ }
134
+ }
135
+ }
136
+ }
137
+
138
+ // A's canvas is 24 x 42 multicolour pixels, cut into four sprites
139
+ char acanvas[42 * 6];
140
+
141
+ void build_sprite_fighter(void)
142
+ {
143
+ for (char pose = 0; pose < 2; pose++) {
144
+ for (char i = 0; i < 252; i++)
145
+ acanvas[i] = 0;
146
+ for (char i = 0; i < 5; i++)
147
+ canvas_rect(acanvas, 6, spr_body + i);
148
+ for (char i = 0; i < 2; i++)
149
+ canvas_rect(acanvas, 6, spr_arms[pose] + i);
150
+ for (char part = 0; part < 4; part++) {
151
+ char *d = SprData + (pose * 4 + part) * 64;
152
+ char y0 = (part >> 1) * 21, b0 = (part & 1) * 3;
153
+ for (char r = 0; r < 21; r++)
154
+ for (char b = 0; b < 3; b++)
155
+ d[r * 3 + b] = acanvas[(y0 + r) * 6 + b0 + b];
156
+ d[63] = 0;
157
+ }
158
+ }
159
+ }
160
+
161
+ // --- fighter state ------------------------------------------------------
162
+ int ax, bx; // screen pixels, left edges
163
+ char apose, bpose, afront;
164
+ char cur_pose = 0xff, cur_shift = 0xff, cur_col = 0xff;
165
+ char *const arow[ROWS] = {
166
+ Screen + (ROW0 + 0) * 40, Screen + (ROW0 + 1) * 40, Screen + (ROW0 + 2) * 40,
167
+ Screen + (ROW0 + 3) * 40, Screen + (ROW0 + 4) * 40, Screen + (ROW0 + 5) * 40};
168
+ const char *gsrc;
169
+ char mcol_old, mcol_new;
170
+
171
+ // --- the technique --------------------------------------------------------
172
+ // Rewrite B's 30 glyphs from the pre-shifted table: 240 bytes.
173
+ __noinline void glyph_copy(void)
174
+ {
175
+ char *d = Chars + BASE * 8;
176
+ for (char i = 0; i < 120; i++) {
177
+ d[i] = gsrc[i];
178
+ d[i + 120] = gsrc[i + 120];
179
+ }
180
+ }
181
+
182
+ // Move B's 5 x 6 block of codes when its cell column changes.
183
+ __noinline void cells_move(void)
184
+ {
185
+ for (char r = 0; r < ROWS; r++) {
186
+ char *p = arow[r];
187
+ if (mcol_old != 0xff)
188
+ for (char x = 0; x < 5; x++)
189
+ p[mcol_old + x] = SPACE;
190
+ char c = BASE + r * 5;
191
+ for (char x = 0; x < 5; x++)
192
+ p[mcol_new + x] = c + x;
193
+ }
194
+ }
195
+
196
+ // Place A's four sprites, merge the 9th X bits, set pointers and priority.
197
+ __noinline void sprite_update(void)
198
+ {
199
+ char msb = 0;
200
+ int x = ax + 24;
201
+ char f = SPR_BLK + apose * 4;
202
+ for (char i = 0; i < 4; i++) {
203
+ int xi = (i & 1) ? x + 24 : x;
204
+ VR[i * 2] = (char)xi;
205
+ VR[i * 2 + 1] = SPR_Y + (i >> 1) * 21;
206
+ if (xi & 0x100)
207
+ msb |= 1 << i;
208
+ PTR[i] = f + i;
209
+ }
210
+ VR[0x10] = (VR[0x10] & ~A_MASK) | msb;
211
+ VR[0x1b] = (VR[0x1b] & ~A_MASK) | (afront ? 0 : A_MASK);
212
+ }
213
+
214
+ void actors_update(void)
215
+ {
216
+ char col = (char)(bx >> 3), sh = ((char)bx & 7) >> 1;
217
+ if (bpose != cur_pose || sh != cur_shift) {
218
+ gsrc = preshift[bpose * 4 + sh];
219
+ glyph_copy();
220
+ cur_pose = bpose;
221
+ cur_shift = sh;
222
+ }
223
+ if (col != cur_col) {
224
+ mcol_old = cur_col;
225
+ mcol_new = col;
226
+ cells_move();
227
+ cur_col = col;
228
+ }
229
+ sprite_update();
230
+ }
231
+
232
+ // --- the script (the Python model runs the same table) ---------------------
233
+ struct Seg { char n; signed char da, db; char pa, pb, afront; };
234
+ #define NSEG 5
235
+ const struct Seg script[NSEG] = {
236
+ {50, 2, -2, 0, 0, 1}, {16, 0, 0, 1, 0, 1}, {30, 2, -2, 0, 0, 0},
237
+ {25, -2, 2, 0, 1, 0}, {8, 0, 2, 0, 1, 0}};
238
+ char seg, segleft;
239
+
240
+ void script_step(void)
241
+ {
242
+ while (seg < NSEG && segleft == 0) {
243
+ seg++;
244
+ if (seg < NSEG)
245
+ segleft = script[seg].n;
246
+ }
247
+ if (seg >= NSEG)
248
+ return; // hold the last state
249
+ const struct Seg *s = script + seg;
250
+ ax += s->da;
251
+ bx += s->db;
252
+ apose = s->pa;
253
+ bpose = s->pb;
254
+ afront = s->afront;
255
+ segleft--;
256
+ }
257
+
258
+ // --- the check: hashes against the model's table --------------------------
259
+ #define NCHK 17
260
+ const unsigned check_tick[NCHK] = {1, 2, 3, 4, 5, 25, 50, 58, 66, 67, 80, 96, 110, 121, 125, 129, 150};
261
+ const unsigned check_scr[NCHK] = {0x5fb9, 0x5fb9, 0x5fb9, 0x5fb9, 0xbf72, 0xee57, 0x95fb, 0x95fb, 0x95fb, 0x95fb, 0xafdc, 0xfdca, 0x5fb9, 0x2bf7, 0x95fb, 0xcafd, 0xcafd};
262
+ const unsigned check_gly[NCHK] = {0x7e6f, 0xf9bd, 0xe6f7, 0x9bdf, 0x7e6f, 0x7e6f, 0xf9bd, 0xf9bd, 0xf9bd, 0xe6f7, 0x9bdf, 0x9bdf, 0x9823, 0x608e, 0x608e, 0x608e, 0x608e};
263
+ const unsigned check_spr[NCHK] = {0x7062, 0x8f62, 0xda62, 0xe962, 0xbc62, 0xf862, 0x3f78, 0x3f44, 0x3f44, 0x6a88, 0x6587, 0x3582, 0xcf87, 0x868a, 0x868a, 0x868a, 0x868a};
264
+
265
+ unsigned hash;
266
+ void rx(char v)
267
+ {
268
+ hash = (hash << 1) | (hash >> 15);
269
+ hash ^= v;
270
+ }
271
+
272
+ char check(char k)
273
+ {
274
+ char bad = 0;
275
+ hash = 0;
276
+ for (char r = 0; r < ROWS; r++)
277
+ for (char x = 0; x < 40; x++)
278
+ rx(arow[r][x]);
279
+ if (hash != check_scr[k]) bad |= 1;
280
+ hash = 0;
281
+ for (char i = 0; i < 240; i++)
282
+ rx(Chars[BASE * 8 + i]);
283
+ if (hash != check_gly[k]) bad |= 2;
284
+ hash = 0;
285
+ for (char i = 0; i < 8; i++)
286
+ rx(VR[i]);
287
+ rx(VR[0x10] & A_MASK);
288
+ rx(VR[0x1b] & A_MASK);
289
+ for (char i = 0; i < 4; i++)
290
+ rx(PTR[i]);
291
+ if (hash != check_spr[k]) bad |= 4;
292
+ return bad;
293
+ }
294
+
295
+ // --- CIA1 timer B -------------------------------------------------------------
296
+ static inline void timer_start(void)
297
+ {
298
+ cia1.crb = 0x00;
299
+ cia1.tb = 0xffff;
300
+ cia1.crb = 0x11;
301
+ }
302
+
303
+ static inline unsigned timer_stop(void)
304
+ {
305
+ cia1.crb = 0x00;
306
+ return 0xffff - cia1.tb;
307
+ }
308
+
309
+ __noinline void nothing(void) { }
310
+
311
+ unsigned time1(void (*fn)(void))
312
+ {
313
+ __asm { sei }
314
+ timer_start();
315
+ fn();
316
+ unsigned t = timer_stop();
317
+ __asm { cli }
318
+ return t;
319
+ }
320
+
321
+ // --- text (screen codes) ----------------------------------------------------------
322
+ void put_str(char *p, const char *s)
323
+ {
324
+ while (*s)
325
+ *p++ = *s++;
326
+ }
327
+
328
+ void put_dec(char *p, unsigned v, char digits)
329
+ {
330
+ for (char i = digits; i > 0; i--) {
331
+ p[i - 1] = 0x30 + v % 10;
332
+ v /= 10;
333
+ }
334
+ }
335
+
336
+ #define VERDICT_TICK 160
337
+
338
+ int main(void)
339
+ {
340
+ // Copy the ROM font's first 64 glyphs (letters, digits) to $3000.
341
+ __asm { sei }
342
+ PORT = 0x33;
343
+ for (unsigned i = 0; i < 512; i++)
344
+ Chars[i] = ((volatile char *)0xd000)[i];
345
+ PORT = 0x37;
346
+ __asm { cli }
347
+ for (char i = 0; i < 8; i++) {
348
+ Chars[SPACE * 8 + i] = 0;
349
+ Chars[FLOOR * 8 + i] = (i & 1) ? 0xaa : 0xff;
350
+ }
351
+ build_char_fighter();
352
+ build_sprite_fighter();
353
+
354
+ vic.color_border = 0;
355
+ vic.color_back = 11; // 00: dark grey
356
+ vic.color_back1 = 14; // 01: light blue, B's belt
357
+ vic.color_back2 = 7; // 10: yellow, B's head and arms
358
+ vic.memptr = 0x1c;
359
+ vic.ctrl2 |= VIC_CTRL2_MCM;
360
+ for (unsigned i = 0; i < 1000; i++) {
361
+ Screen[i] = SPACE;
362
+ Color[i] = 1; // hires white text
363
+ }
364
+ for (char i = 0; i < ROWS * 40; i++)
365
+ Color[ROW0 * 40 + i] = 8 | 2; // 11: red, B's body
366
+ for (char i = 0; i < 40; i++) {
367
+ Screen[(ROW0 + ROWS) * 40 + i] = FLOOR;
368
+ Color[(ROW0 + ROWS) * 40 + i] = 4; // hires purple floor
369
+ }
370
+
371
+ vic.spr_mcolor0 = 15; // 01: light grey, A's head and arms
372
+ vic.spr_mcolor1 = 6; // 11: blue, A's belt
373
+ for (char i = 0; i < 4; i++)
374
+ VR[0x27 + i] = 5; // 10: green, A's body and legs
375
+ vic.spr_multi = A_MASK;
376
+ vic.spr_expand_x = 0;
377
+ vic.spr_expand_y = 0;
378
+
379
+ put_str(Screen + 0, s"mixed fighters tick");
380
+ put_str(Screen + 2 * 40, s"a x pose b x pose front");
381
+ put_str(Screen + 3 * 40, s"checks mismatches");
382
+ put_str(Screen + 4 * 40, s"update max min");
383
+ put_str(Screen + 5 * 40, s"glyphs cells sprites");
384
+ put_str(Screen + 6 * 40, s"overlap ticks front swaps");
385
+
386
+ // Cost of each part, screen blanked, less an empty call.
387
+ vic.ctrl1 &= ~VIC_CTRL1_DEN;
388
+ vic_waitFrame();
389
+ vic_waitFrame();
390
+ unsigned t_none = time1(nothing);
391
+ gsrc = preshift[0];
392
+ unsigned t_copy = time1(glyph_copy) - t_none;
393
+ mcol_old = 20; mcol_new = 21;
394
+ unsigned t_move = time1(cells_move) - t_none;
395
+ ax = 250; // two sprites past X 255
396
+ unsigned t_spr = time1(sprite_update) - t_none;
397
+ for (char r = 0; r < ROWS; r++)
398
+ for (char x = 0; x < 40; x++)
399
+ arow[r][x] = SPACE;
400
+ vic.ctrl1 |= VIC_CTRL1_DEN;
401
+ put_dec(Screen + 5 * 40 + 7, t_copy, 4);
402
+ put_dec(Screen + 5 * 40 + 19, t_move, 4);
403
+ put_dec(Screen + 5 * 40 + 33, t_spr, 4);
404
+
405
+ ax = 40; bx = 248;
406
+ seg = 0; segleft = script[0].n;
407
+ vic.spr_enable = A_MASK;
408
+
409
+ unsigned tick = 0, mism = 0, checks = 0, overlap = 0, swaps = 0;
410
+ unsigned u_max = 0, u_min = 0xffff;
411
+ char k = 0, fault = 0, done = 0, lastfront = 1;
412
+
413
+ for (;;) {
414
+ vic_waitFrame(); // raster line 256
415
+ script_step();
416
+ __asm { sei }
417
+ timer_start();
418
+ actors_update();
419
+ unsigned tu = timer_stop();
420
+ __asm { cli }
421
+ tick++;
422
+ if (tu > u_max) u_max = tu;
423
+ if (tu < u_min) u_min = tu;
424
+ if (afront != lastfront) swaps++;
425
+ lastfront = afront;
426
+ // The figures' pixel spans: A 48 wide, B's 32-pixel canvas.
427
+ if (ax < bx + 32 && bx < ax + 48) overlap++;
428
+
429
+ if (k < NCHK && tick == check_tick[k]) {
430
+ if (check(k)) mism++;
431
+ checks++;
432
+ k++;
433
+ }
434
+
435
+ switch (tick & 3) { // one line of text a tick
436
+ case 0:
437
+ put_dec(Screen + 22, tick, 4);
438
+ put_dec(Screen + 2 * 40 + 4, ax, 3);
439
+ Screen[2 * 40 + 13] = 0x30 + apose;
440
+ put_dec(Screen + 2 * 40 + 19, bx, 3);
441
+ Screen[2 * 40 + 29] = 0x30 + bpose;
442
+ put_str(Screen + 2 * 40 + 37, afront ? s"a" : s"b");
443
+ break;
444
+ case 1:
445
+ put_dec(Screen + 3 * 40 + 7, checks, 3);
446
+ put_dec(Screen + 3 * 40 + 23, mism, 3);
447
+ break;
448
+ case 2:
449
+ put_dec(Screen + 4 * 40 + 11, u_max, 4);
450
+ put_dec(Screen + 4 * 40 + 21, u_min, 4);
451
+ break;
452
+ case 3:
453
+ put_dec(Screen + 6 * 40 + 14, overlap, 3);
454
+ put_dec(Screen + 6 * 40 + 30, swaps, 2);
455
+ break;
456
+ }
457
+
458
+ if (!done && tick == VERDICT_TICK) {
459
+ done = 1;
460
+ if (checks != NCHK) fault = 2;
461
+ if (mism) fault = 1;
462
+ RESULT = fault ? 2 : 1;
463
+ vic.color_border = fault ? 2 : 5;
464
+ put_str(Screen + 40, fault ? s"result fail" : s"result pass");
465
+ Screen[40 + 12] = 0x30 + fault;
466
+ }
467
+ }
468
+ return 0;
469
+ }
470
+ ```
471
+
472
+ ## Build
473
+
474
+ ```bash
475
+ oscar64 -tm=c64 -O2 -o=mixed-fighters.prg mixed-fighters.c
476
+ ```
477
+
478
+ Produces `mixed-fighters.prg`, 3,743 bytes, with no warnings. The map
479
+ puts the end of BSS at `$20FC`; the font at `$3000` and the sprite
480
+ images at `$3800` (blocks 224 to 231) sit above it and are built at
481
+ run time. Code or data that grows past `$3000` would be overwritten by
482
+ the font copy, so check the map after a change.
483
+
484
+ The `check_*` tables in the listing come from this model (Python 3).
485
+ It draws both fighters from the same rectangles, runs the same script,
486
+ and hashes what the arena's codes, B's glyph range and A's registers
487
+ must hold after each checkpoint tick. It shares no code with the C.
488
+
489
+ ```python
490
+ # model.py: the mixed-fighters model. What the screen block, the glyph range and the
491
+ # sprite registers must hold after each checkpoint tick.
492
+ ROW0, ROWS, BASE, SPACE, SPR_BLK, SPR_Y = 13, 6, 128, 32, 224, 154
493
+
494
+ # rectangles (x0, y0, x1, y1, bit pair), multicolour pixels, inclusive
495
+ CHAR_BODY = [(6, 0, 9, 9, 2), (4, 10, 11, 25, 3), (4, 26, 11, 29, 1),
496
+ (4, 30, 6, 47, 3), (9, 30, 11, 47, 3)]
497
+ CHAR_ARMS = [[(2, 12, 3, 25, 2), (12, 12, 13, 25, 2)],
498
+ [(1, 4, 3, 11, 2), (12, 4, 14, 11, 2)]]
499
+ SPR_BODY = [(10, 0, 13, 9, 1), (8, 10, 15, 25, 2), (8, 26, 15, 28, 3),
500
+ (8, 29, 10, 41, 2), (13, 29, 15, 41, 2)]
501
+ SPR_ARMS = [[(6, 12, 7, 25, 1), (16, 12, 17, 25, 1)],
502
+ [(5, 4, 7, 11, 1), (16, 4, 18, 11, 1)]]
503
+
504
+ # (ticks, da, db, pose a, pose b, sprite fighter in front); the last
505
+ # segment's poses hold after the script ends
506
+ SCRIPT = [(50, 2, -2, 0, 0, 1), (16, 0, 0, 1, 0, 1), (30, 2, -2, 0, 0, 0),
507
+ (25, -2, 2, 0, 1, 0), (8, 0, 2, 0, 1, 0)]
508
+ CHECKS = [1, 2, 3, 4, 5, 25, 50, 58, 66, 67, 80, 96, 110, 121, 125, 129, 150]
509
+
510
+
511
+ def canvas(w, h, rects):
512
+ c = [[0] * w for _ in range(h)]
513
+ for x0, y0, x1, y1, v in rects:
514
+ for y in range(y0, y1 + 1):
515
+ for x in range(x0, x1 + 1):
516
+ c[y][x] = v
517
+ return c
518
+
519
+
520
+ def glyphs(pose, shift):
521
+ c = canvas(16, 48, CHAR_BODY + CHAR_ARMS[pose])
522
+ g = [0] * 240
523
+ for r in range(48):
524
+ w = 0
525
+ for x in range(16):
526
+ w = (w << 2) | c[r][x]
527
+ w = (w << 8) >> (2 * shift) # 40 bits, five cells
528
+ for cx in range(5):
529
+ g[((r >> 3) * 5 + cx) * 8 + (r & 7)] = (w >> (8 * (4 - cx))) & 255
530
+ return g
531
+
532
+
533
+ def rotxor(bs):
534
+ h = 0
535
+ for v in bs:
536
+ h = (((h << 1) | (h >> 15)) & 0xFFFF) ^ v
537
+ return h
538
+
539
+
540
+ def state_after(t):
541
+ a, b, pa, pb, fr = 40, 248, 0, 0, 1
542
+ left = t
543
+ for n, da, db, qa, qb, f in SCRIPT:
544
+ k = min(n, left)
545
+ if k:
546
+ a += da * k
547
+ b += db * k
548
+ pa, pb, fr = qa, qb, f
549
+ left -= k
550
+ return a, b, pa, pb, fr
551
+
552
+
553
+ def expect(t):
554
+ a, b, pa, pb, fr = state_after(t)
555
+ col = b >> 3
556
+ scr = []
557
+ for r in range(ROWS):
558
+ for x in range(40):
559
+ scr.append(BASE + r * 5 + (x - col) if col <= x < col + 5 else SPACE)
560
+ regs, msb = [], 0
561
+ for i in range(4):
562
+ x = a + 24 + (i & 1) * 24
563
+ regs += [x & 255, SPR_Y + (i >> 1) * 21]
564
+ if x & 256:
565
+ msb |= 1 << i
566
+ regs += [msb, 0 if fr else 15] + [SPR_BLK + pa * 4 + i for i in range(4)]
567
+ return rotxor(scr), rotxor(glyphs(pb, (b & 7) >> 1)), rotxor(regs), (a, b, pa, pb, fr)
568
+
569
+
570
+ if __name__ == "__main__":
571
+ rows = [expect(t) for t in CHECKS]
572
+ print("const unsigned check_tick[NCHK] = {%s};" % ", ".join(map(str, CHECKS)))
573
+ for k, name in enumerate(["check_scr", "check_gly", "check_spr"]):
574
+ print("const unsigned %s[NCHK] = {%s};" % (
575
+ name, ", ".join("0x%04x" % r[k] for r in rows)))
576
+ for t, r in zip(CHECKS, rows):
577
+ print("# tick %3d a %3d b %3d pose %d %d front %s" % (
578
+ t, *r[3][:4], "sprite" if r[3][4] else "char"))
579
+ ```
580
+
581
+ Then run headless in VICE (PAL):
582
+
583
+ ```bash
584
+ GSETTINGS_SCHEMA_DIR=/opt/homebrew/share/glib-2.0/schemas x64sc -default -warp +sound \
585
+ +autostart-delay-random -autostartprgmode 1 -limitcycles 8000000 \
586
+ -exitscreenshot mixed-fighters.png -autostart mixed-fighters.prg
587
+ ```
588
+
589
+ Add `-model ntsc` for the NTSC picture. The script is 129 ticks and the
590
+ verdict is posted at tick 160; at 8,000,000 cycles that has happened on
591
+ both models.
592
+
593
+ ## Expected output
594
+
595
+ The script, one tick per loop pass. Positions are the left edges in
596
+ screen pixels: A's 48-pixel block, and B's 32-pixel picture.
597
+
598
+ | Ticks | A x | B x | A pose | B pose | In front |
599
+ |---|---|---|---|---|---|
600
+ | 1-50 | 42 to 140, +2 a tick | 246 to 148, -2 a tick | stand | stand | A |
601
+ | 51-66 | 140 | 148 | strike | stand | A |
602
+ | 67-96 | 142 to 200 | 146 to 88 | stand | stand | B |
603
+ | 97-121 | 198 to 150 | 90 to 138 | stand | arms up | B |
604
+ | 122-129 | 150 | 140 to 154 | stand | arms up | B |
605
+ | 130 on | 150 | 154 | stand | arms up | B |
606
+
607
+ Colours: A is green (5) from `$D027`-`$D02A`, light grey (15) from
608
+ `$D025` for the head and arms, blue (6) from `$D026` for the belt. B is
609
+ red (2) from colour RAM for body and legs, yellow (7) from `$D023` for
610
+ head and arms, light blue (14) from `$D022` for the belt. The backdrop
611
+ is dark grey (11) and the floor purple (4).
612
+
613
+ Measured in VICE x64sc 3.10 with the pinned command, text decoded
614
+ against the character ROM (rows 0 to 6, PAL):
615
+
616
+ ```text
617
+ MIXED FIGHTERS TICK 0172
618
+ RESULT PASS 0
619
+ A X 150 POSE 0 B X 154 POSE 1 FRONT B
620
+ CHECKS 017 MISMATCHES 000
621
+ UPDATE MAX 6108 MIN 0508
622
+ GLYPHS 3323 CELLS 1899 SPRITES 0448
623
+ OVERLAP TICKS 090 FRONT SWAPS 01
624
+ ```
625
+
626
+ NTSC reads the same except `TICK 0180`, `UPDATE MAX 6366` and `OVERLAP
627
+ TICKS 098`. The tick counter and the overlap count keep running in the
628
+ hold, so both depend on the cycle count; the NTSC run fits more ticks
629
+ into the same cycles. The tick is printed every fourth tick. The border
630
+ is palette index 5, (98, 213, 50) on PAL and (114, 189, 103) on NTSC.
631
+
632
+ What the numbers say:
633
+
634
+ - `CHECKS 017 MISMATCHES 000`: at every checkpoint the arena's screen
635
+ codes, B's glyph bytes and A's X, Y, `$D010`, `$D01B` bits and
636
+ pointers hashed to the model's values. The checkpoints include ticks
637
+ 1 to 5, which step B through all four shifts, the strike, the tick the
638
+ priority swaps, and the hold.
639
+ - `UPDATE MAX 6108 MIN 0508`: the whole actor update, CIA1 timer B,
640
+ interrupts masked, started at raster line 256, worst and best tick of
641
+ the run. The worst tick is one that rewrites B's glyphs, moves B's
642
+ block of codes one cell and places A, which every walking tick on
643
+ which B crosses a cell boundary does: the three parts measured below
644
+ sum to 5,670 of the 6,108. The best is a hold tick, A's registers only. On NTSC the
645
+ worst is 6,366: the NTSC frame has 263 lines, so an update of about
646
+ 94 lines from line 256 runs into the badlines at the top of the text
647
+ area; on PAL it ends by line 41, before the first badline at 51
648
+ (arithmetic from 63 and 65 cycles a line; the stall was not traced).
649
+ - `GLYPHS 3323 CELLS 1899 SPRITES 0448`: each part once, screen
650
+ blanked, less an empty call: the 240-byte glyph copy, the 5 x 6 block
651
+ cleared and rewritten one cell over (60 stores), and A's four sprites
652
+ placed with two of them past X 255. The rest of the worst tick, 438
653
+ cycles, is `actors_update` itself, the call and the timer.
654
+ - `FRONT SWAPS 01`: the one priority change, at tick 67.
655
+
656
+ The pictures: `screenshots/mixed-fighters.png` (PAL) and
657
+ `screenshots/mixed-fighters-ntsc.png` (NTSC), the hold at A x 150,
658
+ B x 154, B in front. The script below decodes the arena, raster lines
659
+ 155 to 202 by 320 pixels, to palette indices and compares every pixel
660
+ with the model's picture of the two fighters under the `$D01B` rule.
661
+
662
+ | Shot | Pixels wrong | B over A | A through B's `$D022` belt | A only | B only |
663
+ |---|---|---|---|---|---|
664
+ | PAL, 8,000,000 cycles | 0 of 15,360 | 344 | 44 | 264 | 324 |
665
+ | NTSC, 8,000,000 cycles | 0 of 15,360 | 344 | 44 | 264 | 324 |
666
+
667
+ A's colours cover x 198 to 217 and B's x 188 to 215 in both shots,
668
+ A on rows 139 to 180 and B on 139 to 186 on PAL (127 to 168 and 127 to
669
+ 174 on NTSC; line − 16 and − 28):
670
+ B's first line is raster 155, text row 13, and so is A's with sprite
671
+ Y register 154. Where B's red, yellow body covers A, B shows; where
672
+ B's light blue belt covers A, A shows, though A is behind. In
673
+ multicolour text mode bit pair 01 counts as background for sprite
674
+ priority, like 00 (measured here; Bauer's VIC-II article, section 3.8.2,
675
+ says the same: with MCM set, 00 and 01 are background and 10 and 11
676
+ foreground, http://www.zimmers.net/cbmpics/cbm/c64/vic-ii.txt).
677
+
678
+ A probe at 5,450,000 cycles, not pinned, caught the strike (tick 60 on
679
+ PAL, 56 on NTSC; A x 140, B x 148, A in front). The same script found
680
+ 0 of 15,360 pixels wrong on both models, with 540 pixels of A over B,
681
+ belt included. Each pinned shot run twice gives byte-identical PNGs.
682
+
683
+ ```python
684
+ # measure.py: python3 measure.py shot.png pal|ntsc tick. Needs model.py
685
+ # (above) beside it and Pillow.
686
+ import sys
687
+ from PIL import Image
688
+ from model import canvas, CHAR_BODY, CHAR_ARMS, SPR_BODY, SPR_ARMS, state_after
689
+
690
+ PAL = {0: (0, 0, 0), 1: (255, 255, 255), 2: (175, 60, 88), 3: (126, 243, 214), 4: (170, 64, 245),
691
+ 5: (98, 213, 50), 6: (44, 61, 236), 7: (255, 255, 70), 8: (183, 99, 30), 9: (119, 83, 0),
692
+ 10: (238, 123, 149), 11: (98, 98, 98), 12: (148, 148, 148), 13: (183, 255, 134),
693
+ 14: (115, 133, 255), 15: (205, 205, 205)}
694
+ NTSC = {0: (0, 0, 0), 1: (255, 255, 255), 2: (169, 71, 100), 3: (138, 230, 203), 4: (154, 88, 185),
695
+ 5: (114, 189, 103), 6: (25, 73, 180), 7: (255, 248, 141), 8: (196, 98, 65), 9: (151, 64, 0),
696
+ 10: (230, 134, 163), 11: (98, 98, 98), 12: (148, 148, 148), 13: (198, 255, 186),
697
+ 14: (98, 145, 251), 15: (205, 205, 205)}
698
+ B_COL = {1: 14, 2: 7, 3: 2} # D022, D023, colour RAM
699
+ A_COL = {1: 15, 2: 5, 3: 6} # D025, D027, D026
700
+
701
+ path, model, tick = sys.argv[1], sys.argv[2], int(sys.argv[3])
702
+ pal, off = (PAL, 16) if model == 'pal' else (NTSC, 28)
703
+ inv = {v: k for k, v in pal.items()}
704
+ im = Image.open(path).convert('RGB')
705
+ a, b, pa, pb, afront = state_after(tick)
706
+ bc = canvas(16, 48, CHAR_BODY + CHAR_ARMS[pb])
707
+ ac = canvas(24, 42, SPR_BODY + SPR_ARMS[pa])
708
+ LINE0 = 51 + 13 * 8 # first raster line of the arena
709
+ stats = dict(bad=0, total=0, a_only=0, b_only=0, a_over_b=0, b_over_a=0, a_through_belt=0)
710
+ first_bad = None
711
+ for line in range(LINE0, LINE0 + 48):
712
+ for px in range(320):
713
+ r = line - LINE0
714
+ bv = bc[r][(px - b) // 2] if b <= px < b + 32 else 0
715
+ av = ac[r][(px - a) // 2] if a <= px < a + 48 and r < 42 else 0
716
+ if av and bv:
717
+ if afront or bv == 1:
718
+ want = A_COL[av]
719
+ stats['a_through_belt' if bv == 1 and not afront else 'a_over_b'] += 1
720
+ else:
721
+ want = B_COL[bv]
722
+ stats['b_over_a'] += 1
723
+ elif av:
724
+ want = A_COL[av]; stats['a_only'] += 1
725
+ elif bv:
726
+ want = B_COL[bv]; stats['b_only'] += 1
727
+ else:
728
+ want = 11
729
+ got = inv.get(im.getpixel((32 + px, line - off)), -1)
730
+ stats['total'] += 1
731
+ if got != want:
732
+ stats['bad'] += 1
733
+ if first_bad is None:
734
+ first_bad = (px, line, want, got)
735
+ print(path, model, 'tick', tick, 'a', a, 'b', b, 'poses', pa, pb, 'front', 'A' if afront else 'B')
736
+ print(stats, 'first mismatch', first_bad)
737
+ # bounding boxes of each fighter's own colours, screenshot coordinates
738
+ for name, cols in (('A', {15, 5, 6}), ('B', {14, 7, 2})):
739
+ xs, ys = [], []
740
+ for y in range(LINE0 - off, LINE0 - off + 48):
741
+ for x in range(32, 352):
742
+ if inv.get(im.getpixel((x, y)), -1) in cols:
743
+ xs.append(x); ys.append(y)
744
+ print(name, 'box x', min(xs), '-', max(xs), 'y', min(ys), '-', max(ys))
745
+ ```
746
+
747
+ ## Why this works
748
+
749
+ **B is a picture in its own glyphs.** Codes 128 to 157 are used by no
750
+ other cell, so rewriting their 240 bytes redraws B and nothing else.
751
+ The block of codes on screen is laid out once per cell position:
752
+ code `128 + row * 5 + column`. `glyph_copy` runs only when B's pose or
753
+ its shift inside the cell changes, and `cells_move` only when its cell
754
+ column changes. `cells_move` clears the old block before writing the
755
+ new one; without that the column B walked out of would keep its codes
756
+ and show a stale strip of B (`dirty_cell_skip_leaves_overlay_trail`;
757
+ from the mechanism, not run here).
758
+
759
+ **Pre-shifted by multicolour pixel.** A multicolour pixel is two screen
760
+ pixels wide, so four shifts cover every position inside a cell. Each
761
+ pose is stored four times, each copy 5 cells wide so the shifted
762
+ picture has room, 240 bytes each, 1,920 bytes for two poses (the
763
+ array's size in the map). A draw is then a straight copy at every
764
+ shift. Moving in whole cells would need no table and no copy on a
765
+ move, but B would step 8 pixels while A glides in 2.
766
+
767
+ **Priority is A's four `$D01B` bits.** With them clear A is in front of
768
+ everything B draws. With them set B's foreground pixels, bit pairs 10
769
+ and 11, cover A; pairs 00 and 01 do not. Sprite-to-sprite order does not
770
+ enter, as B is not a sprite. The script flips the bits in the same
771
+ update as the positions, before the raster reaches the fighters.
772
+
773
+ **The update runs in the vertical blank.** `vic_waitFrame` returns at
774
+ line 256. The worst update ends by line 41 on PAL and before line 91 on
775
+ NTSC (arithmetic from the measured cycles), both above B's first line,
776
+ 155, so B's glyphs never change while the VIC is drawing them.
777
+
778
+ Verified: compiled with Oscar64, run headless in VICE x64sc 3.10 with the
779
+ pinned command on PAL and NTSC, each twice with byte-identical PNGs; the
780
+ text was decoded against the character ROM and every arena pixel
781
+ compared with the model's picture with PIL, not by eye.