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,807 @@
1
+ ---
2
+ recipe: actor-activation-window
3
+ toolchain: oscar64
4
+ output_format: PRG
5
+ region: both
6
+ techniques: [actor_activation_window, object_pool]
7
+ file_formats: [PRG]
8
+ uses_registers: [DC04, DC05, DC0E, D000, D001, D010, D011, D015, D020, D021, D027]
9
+ uses_kernal: []
10
+ ---
11
+
12
+ <!-- doc-type: recipe -->
13
+
14
+ # Oscar64 actor activation window: level-placed actors that wake near the view and keep their state
15
+
16
+ ## Synopsis
17
+
18
+ Thirty-two actors are placed in a level 256 columns (2,048 pixels) wide.
19
+ Each has an entry in a level table: column, row, hit points and a flag
20
+ byte (facing, live, dead). A camera scrolls to the far end at 16 pixels a
21
+ tick and back at 8. Every tick the program examines eight table entries,
22
+ round robin, and wakes any that lie inside the view plus a margin of 8
23
+ columns into one of eight live slots. A live actor that leaves the view
24
+ plus margin plus 2 columns is written back to its entry and its slot is
25
+ freed. At camera 560 the script kills actors 9 and 11 and takes actor 10
26
+ down to 1 hit point. The program checks that the dead actors never wake
27
+ again, that actor 10 wakes on the way back where it was left and with 1
28
+ hit point, and that no living actor was ever inside the view while
29
+ dormant. It compares a checksum of the final table with a Python model,
30
+ prints PASS or FAIL, the peak live count and the cycle cost of each part
31
+ (CIA1 timer A), and draws the live actors at camera 0 as sprites. It
32
+ implements `actor_activation_window` (`techniques/logic.md`); the live
33
+ slots are an `object_pool`.
34
+
35
+ ## Source
36
+
37
+ ```c
38
+ // actor-activation-window.c
39
+ // Actors placed in the level data wake up when they come within a window
40
+ // around the view and go back to the level table when they leave it, so
41
+ // their position, hit points and direction survive. Killed actors are
42
+ // marked dead in the table and never wake again. A camera scrolls out to
43
+ // the far end of a 256-column level at 16 pixels a tick and back at 8;
44
+ // the level table is scanned 8 entries a tick, round robin. The program
45
+ // checks the result against a Python model, prints PASS or FAIL, the peak
46
+ // live count and the cycle cost of the scan, and draws the actors live at
47
+ // the end as sprites relative to the camera.
48
+ #include <c64/vic.h>
49
+ #include <c64/cia.h>
50
+
51
+ #define SCREEN ((char *)0x0400)
52
+ #define COLOUR ((char *)0xd800)
53
+ #define SPRDATA ((char *)0x0340) // sprite block 13
54
+
55
+ #define NLVL 32 // placed actors; a power of two for the wrap
56
+ #define NSLOT 8 // live slots, one hardware sprite each
57
+ #define SCAN_K 8 // level entries examined per tick
58
+ #define VIEW 40 // view width in columns
59
+ #define HYST 2 // extra columns before a live actor is dropped
60
+ #define NO_SLOT 0xff
61
+
62
+ #define LF_DIRL 0x01 // persistent: facing left
63
+ #define LF_LIVE 0x40 // in a slot now
64
+ #define LF_DEAD 0x80 // killed: never wakes again
65
+
66
+ #define EXPECT_CHK 0x1D54 // Python fold over the final level table
67
+
68
+ // ---- the level table: persistent, one byte per field per actor ----------
69
+ char lvl_x[NLVL]; // column (8-pixel block) in the level
70
+ char lvl_row[NLVL]; // character row
71
+ char lvl_hp[NLVL];
72
+ char lvl_flags[NLVL];
73
+ char lvl_home[NLVL]; // patrol centre, level data, never written
74
+
75
+ // ---- the live slots ------------------------------------------------------
76
+ char slot_lvl[NSLOT]; // level index, or NO_SLOT
77
+ unsigned slot_px[NSLOT]; // world x in pixels
78
+ char slot_hp[NSLOT];
79
+ char slot_dir[NSLOT]; // 1 = moving left
80
+
81
+ // ---- window state, set once per tick -------------------------------------
82
+ char win_lo, win_top; // wake window: win_lo <= column <= win_top
83
+ char drop_lo, drop_top; // drop window: keep while drop_lo <= column <= drop_top
84
+ char scan_pos;
85
+ char margin;
86
+ unsigned cam_px;
87
+
88
+ // ---- counters the scenario reads back ------------------------------------
89
+ char live_n, peak_n, refused;
90
+ unsigned wakes, popin;
91
+ char wake_n[NLVL];
92
+ bool hit_done;
93
+ char out_col = 0xff, out_hp; // actor 10 when it went back to the table
94
+ unsigned back_px = 0xffff; // actor 10 when it woke again
95
+ char back_hp;
96
+
97
+ __noinline void activate(char i)
98
+ {
99
+ char s = 0;
100
+ while (slot_lvl[s] != NO_SLOT)
101
+ {
102
+ if (++s == NSLOT)
103
+ {
104
+ refused++;
105
+ return;
106
+ }
107
+ }
108
+ slot_lvl[s] = i;
109
+ slot_px[s] = (unsigned)lvl_x[i] << 3;
110
+ slot_hp[s] = lvl_hp[i];
111
+ slot_dir[s] = lvl_flags[i] & LF_DIRL;
112
+ lvl_flags[i] |= LF_LIVE;
113
+ if (++live_n > peak_n)
114
+ peak_n = live_n;
115
+ wakes++;
116
+ wake_n[i]++;
117
+ if (i == 10 && out_col != 0xff && back_px == 0xffff)
118
+ {
119
+ back_px = slot_px[s];
120
+ back_hp = slot_hp[s];
121
+ }
122
+ }
123
+
124
+ // Write the live state back to the level table and free the slot.
125
+ __noinline void deactivate(char s)
126
+ {
127
+ char i = slot_lvl[s];
128
+ lvl_x[i] = (char)(slot_px[s] >> 3);
129
+ lvl_hp[i] = slot_hp[s];
130
+ lvl_flags[i] = (lvl_flags[i] & ~(LF_LIVE | LF_DIRL)) | slot_dir[s];
131
+ if (i == 10 && hit_done && out_col == 0xff)
132
+ {
133
+ out_col = lvl_x[i];
134
+ out_hp = lvl_hp[i];
135
+ }
136
+ slot_lvl[s] = NO_SLOT;
137
+ live_n--;
138
+ }
139
+
140
+ // Kill: mark the entry dead so no scan wakes it, and free the slot.
141
+ static void kill(char s)
142
+ {
143
+ char i = slot_lvl[s];
144
+ lvl_flags[i] = (lvl_flags[i] & ~LF_LIVE) | LF_DEAD;
145
+ lvl_hp[i] = 0;
146
+ slot_lvl[s] = NO_SLOT;
147
+ live_n--;
148
+ }
149
+
150
+ // Both windows as inclusive column bounds clamped to 0..255, so every
151
+ // compare in the scan and the drop pass is one byte.
152
+ __noinline void set_window(void)
153
+ {
154
+ int cc = cam_px >> 3;
155
+ int lo = cc - margin;
156
+ int hi = cc + VIEW + margin; // first column past the wake window
157
+ win_lo = lo < 0 ? 0 : lo;
158
+ win_top = hi > 256 ? 255 : hi - 1;
159
+ drop_lo = lo - HYST < 0 ? 0 : lo - HYST;
160
+ drop_top = hi + HYST > 256 ? 255 : hi + HYST - 1;
161
+ }
162
+
163
+ // Examine SCAN_K entries from where the last tick stopped.
164
+ __noinline void scan_step(void)
165
+ {
166
+ char i = scan_pos;
167
+ for (char k = 0; k < SCAN_K; k++)
168
+ {
169
+ if (!(lvl_flags[i] & (LF_LIVE | LF_DEAD)))
170
+ {
171
+ char c = lvl_x[i];
172
+ if (c >= win_lo && c <= win_top)
173
+ activate(i);
174
+ }
175
+ i = (i + 1) & (NLVL - 1);
176
+ }
177
+ scan_pos = i;
178
+ }
179
+
180
+ // The same test over the whole table, for comparison.
181
+ __noinline void scan_all(void)
182
+ {
183
+ for (char i = 0; i < NLVL; i++)
184
+ {
185
+ if (!(lvl_flags[i] & (LF_LIVE | LF_DEAD)))
186
+ {
187
+ char c = lvl_x[i];
188
+ if (c >= win_lo && c <= win_top)
189
+ activate(i);
190
+ }
191
+ }
192
+ }
193
+
194
+ // The game's own actor logic, a stand-in: patrol three columns each
195
+ // side of home, one pixel a tick.
196
+ __noinline void move_live(void)
197
+ {
198
+ for (char s = 0; s < NSLOT; s++)
199
+ {
200
+ char i = slot_lvl[s];
201
+ if (i == NO_SLOT)
202
+ continue;
203
+ unsigned p = slot_px[s];
204
+ if (slot_dir[s])
205
+ p--;
206
+ else
207
+ p++;
208
+ slot_px[s] = p;
209
+ char c = p >> 3;
210
+ if (c >= lvl_home[i] + 3)
211
+ slot_dir[s] = 1;
212
+ else if (c + 3 <= lvl_home[i])
213
+ slot_dir[s] = 0;
214
+ }
215
+ }
216
+
217
+ // Drop every live actor outside the drop window back into the table.
218
+ __noinline void drop_pass(void)
219
+ {
220
+ for (char s = 0; s < NSLOT; s++)
221
+ {
222
+ if (slot_lvl[s] == NO_SLOT)
223
+ continue;
224
+ char c = slot_px[s] >> 3;
225
+ if (c < drop_lo || c > drop_top)
226
+ deactivate(s);
227
+ }
228
+ }
229
+
230
+ // The technique's work per tick: window, scan slice, drop pass.
231
+ __noinline void window_tick(void)
232
+ {
233
+ set_window();
234
+ scan_step();
235
+ drop_pass();
236
+ }
237
+
238
+ static void tick_logic(void)
239
+ {
240
+ set_window();
241
+ scan_step();
242
+ move_live();
243
+ drop_pass();
244
+ }
245
+
246
+ // Harness only: a dormant, living entry inside the view is a pop-in.
247
+ static void check_popin(void)
248
+ {
249
+ char cc = cam_px >> 3;
250
+ for (char i = 0; i < NLVL; i++)
251
+ {
252
+ if (!(lvl_flags[i] & (LF_LIVE | LF_DEAD)))
253
+ {
254
+ char c = lvl_x[i];
255
+ if (c >= cc && c < cc + VIEW)
256
+ popin++;
257
+ }
258
+ }
259
+ }
260
+
261
+ static char slot_of(char i)
262
+ {
263
+ for (char s = 0; s < NSLOT; s++)
264
+ if (slot_lvl[s] == i)
265
+ return s;
266
+ return NO_SLOT;
267
+ }
268
+
269
+ static void level_reset(void)
270
+ {
271
+ for (char i = 0; i < NLVL; i++)
272
+ {
273
+ lvl_x[i] = lvl_home[i] = 4 + (i << 3);
274
+ lvl_row[i] = 19 + (i & 3);
275
+ lvl_hp[i] = 3;
276
+ lvl_flags[i] = i & 1;
277
+ wake_n[i] = 0;
278
+ }
279
+ for (char s = 0; s < NSLOT; s++)
280
+ slot_lvl[s] = NO_SLOT;
281
+ scan_pos = live_n = peak_n = refused = 0;
282
+ wakes = popin = 0;
283
+ hit_done = false;
284
+ out_col = 0xff;
285
+ back_px = 0xffff;
286
+ }
287
+
288
+ // Out to the far end at 16 px a tick, a scripted fight at camera 560,
289
+ // then back to 0 at 8 px a tick.
290
+ static bool kill_ok;
291
+ static char w9, w11;
292
+ static void scenario(char m)
293
+ {
294
+ level_reset();
295
+ margin = m;
296
+ kill_ok = true;
297
+ for (cam_px = 0; cam_px <= 1728; cam_px += 16)
298
+ {
299
+ tick_logic();
300
+ check_popin();
301
+ if (cam_px == 560)
302
+ {
303
+ char s = slot_of(9);
304
+ if (s == NO_SLOT) kill_ok = false; else kill(s);
305
+ s = slot_of(11);
306
+ if (s == NO_SLOT) kill_ok = false; else kill(s);
307
+ s = slot_of(10);
308
+ if (s == NO_SLOT) kill_ok = false; else slot_hp[s] = 1;
309
+ hit_done = true;
310
+ }
311
+ }
312
+ w9 = wake_n[9];
313
+ w11 = wake_n[11];
314
+ cam_px = 1728;
315
+ for (;;)
316
+ {
317
+ tick_logic();
318
+ check_popin();
319
+ if (cam_px == 0)
320
+ break;
321
+ cam_px -= 8;
322
+ }
323
+ }
324
+
325
+ // ---- timing ---------------------------------------------------------------
326
+
327
+ __noinline void nothing(void)
328
+ {
329
+ }
330
+
331
+ __noinline void wake_and_drop(void)
332
+ {
333
+ activate(0);
334
+ deactivate(0);
335
+ }
336
+
337
+ // The worst tick: every slot free and the whole slice inside the wake
338
+ // window, so all 8 entries wake, then the drop pass runs over 8 live.
339
+ // Timed with the reset, less the reset alone.
340
+ __noinline void reset_slots(void)
341
+ {
342
+ for (char s = 0; s < NSLOT; s++)
343
+ {
344
+ slot_lvl[s] = NO_SLOT;
345
+ lvl_flags[s] = 0;
346
+ }
347
+ live_n = 0;
348
+ scan_pos = 0;
349
+ }
350
+
351
+ __noinline void reset_only(void)
352
+ {
353
+ reset_slots();
354
+ }
355
+
356
+ __noinline void worst_tick(void)
357
+ {
358
+ reset_slots();
359
+ window_tick();
360
+ }
361
+
362
+ // CIA1 timer A: force-load $FFFF, count phi2 while fn runs 20 times. The
363
+ // largest subject stays under 65,535 cycles in total, so the 16-bit timer
364
+ // does not wrap; a first build with 50 calls wrapped on the actor update.
365
+ static unsigned time_loop(void (*fn)(void))
366
+ {
367
+ cia1.cra = 0x00;
368
+ cia1.ta = 0xffff;
369
+ cia1.cra = 0x11;
370
+ char i = 20;
371
+ do
372
+ {
373
+ fn();
374
+ } while (--i);
375
+ cia1.cra = 0x00;
376
+ return 0xffff - cia1.ta;
377
+ }
378
+
379
+ // ---- screen ----------------------------------------------------------------
380
+
381
+ static void put_str(char row, char col, const char *s)
382
+ {
383
+ char *p = SCREEN + 40 * row + col;
384
+ while (*s)
385
+ {
386
+ char c = *s++;
387
+ *p++ = (c >= 'a' && c <= 'z') ? c - 'a' + 1 : c;
388
+ }
389
+ }
390
+
391
+ static void put_dec(char row, char col, unsigned v, char width)
392
+ {
393
+ char *p = SCREEN + 40 * row + col + width;
394
+ do
395
+ {
396
+ *--p = '0' + v % 10;
397
+ v /= 10;
398
+ } while (--width);
399
+ }
400
+
401
+ static const char hex_glyph[16] = {
402
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 1, 2, 3, 4, 5, 6 };
403
+
404
+ static void put_hex16(char row, char col, unsigned v)
405
+ {
406
+ char *p = SCREEN + 40 * row + col;
407
+ p[0] = hex_glyph[(v >> 12) & 15];
408
+ p[1] = hex_glyph[(v >> 8) & 15];
409
+ p[2] = hex_glyph[(v >> 4) & 15];
410
+ p[3] = hex_glyph[v & 15];
411
+ }
412
+
413
+ // Net cycles per call to two decimals: (t - t0) / 20 calls.
414
+ static void put_per_call(char row, char col, unsigned t, unsigned t0)
415
+ {
416
+ unsigned long n = (unsigned long)(t - t0) * 5; // hundredths per call
417
+ put_dec(row, col, (unsigned)(n / 100), 4);
418
+ SCREEN[40 * row + col + 4] = '.';
419
+ put_dec(row, col + 5, (unsigned)(n % 100), 2);
420
+ }
421
+
422
+ static unsigned fold(unsigned cs, unsigned v)
423
+ {
424
+ return (cs ^ v) * 5 + 1;
425
+ }
426
+
427
+ int main(void)
428
+ {
429
+ for (unsigned i = 0; i < 1000; i++)
430
+ {
431
+ SCREEN[i] = 0x20;
432
+ COLOUR[i] = VCOL_WHITE;
433
+ }
434
+ vic.color_back = VCOL_BLACK;
435
+ vic.color_border = VCOL_BLACK;
436
+
437
+ // Demonstration first: a margin of 1 column is too small at 16 px a tick.
438
+ scenario(1);
439
+ unsigned popin1 = popin;
440
+
441
+ // The real run: margin 8 columns.
442
+ scenario(8);
443
+
444
+ unsigned chk = 0;
445
+ for (char i = 0; i < NLVL; i++)
446
+ {
447
+ chk = fold(chk, lvl_x[i]);
448
+ chk = fold(chk, lvl_hp[i]);
449
+ chk = fold(chk, lvl_flags[i]);
450
+ }
451
+
452
+ put_str(0, 0, "actor window 32 placed 8 slots");
453
+ put_str(1, 0, "margin 8 scan 8/tick cam 16 out 8 back");
454
+ put_str(2, 0, "kill 9 11 hit 10 at cam 560");
455
+ put_str(3, 0, "wakes 9 before after");
456
+ put_dec(3, 17, w9, 1);
457
+ put_dec(3, 26, wake_n[9], 1);
458
+ put_str(4, 0, "wakes 11 before after");
459
+ put_dec(4, 17, w11, 1);
460
+ put_dec(4, 26, wake_n[11], 1);
461
+ put_str(5, 0, "10 out col hp in px hp");
462
+ put_dec(5, 11, out_col, 3);
463
+ put_dec(5, 18, out_hp, 1);
464
+ put_dec(5, 27, back_px, 4);
465
+ put_dec(5, 35, back_hp, 1);
466
+ put_str(6, 0, "popin refused peak wakes");
467
+ put_dec(6, 6, popin, 2);
468
+ put_dec(6, 17, refused, 2);
469
+ put_dec(6, 25, peak_n, 1);
470
+ put_dec(6, 33, wakes, 3);
471
+ put_str(7, 0, "chk exp margin 1 popin");
472
+ put_hex16(7, 4, chk);
473
+ put_hex16(7, 13, EXPECT_CHK);
474
+ put_dec(7, 34, popin1, 3);
475
+
476
+ bool pass = kill_ok && w9 == 1 && w11 == 1 && wake_n[9] == 1 &&
477
+ wake_n[11] == 1 && wake_n[10] == 2 && wake_n[12] == 2 &&
478
+ out_col == 86 && out_hp == 1 && back_px == 688 && back_hp == 1 &&
479
+ popin == 0 && refused == 0 && peak_n == 8 && wakes == 56 &&
480
+ chk == EXPECT_CHK && popin1 != 0;
481
+
482
+ // Save the final table: the timing below overwrites it.
483
+ char sv_lvl[NSLOT];
484
+ unsigned sv_px[NSLOT];
485
+ for (char s = 0; s < NSLOT; s++)
486
+ {
487
+ sv_lvl[s] = slot_lvl[s];
488
+ sv_px[s] = slot_px[s];
489
+ }
490
+
491
+ // Cycle costs. Interrupts off and DEN off so nothing steals cycles.
492
+ __asm { sei }
493
+ vic.ctrl1 = 0x0b;
494
+ vic_waitFrame();
495
+ unsigned t0 = time_loop(nothing);
496
+
497
+ // Scans with every entry dormant and an empty wake window.
498
+ for (char i = 0; i < NLVL; i++)
499
+ lvl_flags[i] = 0;
500
+ win_lo = 1;
501
+ win_top = 0;
502
+ unsigned t_scan8 = time_loop(scan_step);
503
+ unsigned t_scan32 = time_loop(scan_all);
504
+
505
+ // Eight live actors (entries 0 to 7, columns 4 to 60), camera 0 and a
506
+ // margin of 22: the drop window, columns 0 to 63, holds every patrol,
507
+ // and the wake window, 0 to 61, holds no dormant entry.
508
+ for (char s = 0; s < NSLOT; s++)
509
+ {
510
+ slot_lvl[s] = s;
511
+ slot_px[s] = (unsigned)lvl_home[s] << 3;
512
+ slot_dir[s] = 0;
513
+ lvl_flags[s] = LF_LIVE;
514
+ }
515
+ cam_px = 0;
516
+ margin = 22;
517
+ set_window();
518
+ unsigned t_drop = time_loop(drop_pass);
519
+ unsigned t_tick = time_loop(window_tick); // 20 calls: 5 laps of the table
520
+ unsigned t_move = time_loop(move_live);
521
+
522
+ // One wake into the free slot 0 and one drop back.
523
+ slot_lvl[0] = NO_SLOT;
524
+ live_n = 7;
525
+ unsigned t_wd = time_loop(wake_and_drop);
526
+
527
+ // Entries 0 to 7 sit in columns 4 to 60 after the run, inside the
528
+ // wake window 0 to 61, so all 8 wake; worst_ok checks that they did.
529
+ unsigned t_ro = time_loop(reset_only);
530
+ unsigned t_worst = time_loop(worst_tick);
531
+ bool worst_ok = live_n == 8 && refused == 0;
532
+ vic.ctrl1 = 0x1b;
533
+
534
+ put_str(9, 0, "cycles x20 total per call");
535
+ put_str(10, 0, "empty call");
536
+ put_dec(10, 22, t0, 5);
537
+ put_str(11, 0, "scan 8, none wakes");
538
+ put_dec(11, 22, t_scan8, 5);
539
+ put_per_call(11, 30, t_scan8, t0);
540
+ put_str(12, 0, "scan all 32");
541
+ put_dec(12, 22, t_scan32, 5);
542
+ put_per_call(12, 30, t_scan32, t0);
543
+ put_str(13, 0, "drop pass, 8 live");
544
+ put_dec(13, 22, t_drop, 5);
545
+ put_per_call(13, 30, t_drop, t0);
546
+ put_str(14, 0, "window+scan 8+drop");
547
+ put_dec(14, 22, t_tick, 5);
548
+ put_per_call(14, 30, t_tick, t0);
549
+ put_str(15, 0, "patrol 8 (payload)");
550
+ put_dec(15, 22, t_move, 5);
551
+ put_per_call(15, 30, t_move, t0);
552
+ put_str(16, 0, "wake + drop back");
553
+ put_dec(16, 22, t_wd, 5);
554
+ put_per_call(16, 30, t_wd, t0);
555
+
556
+ put_str(17, 0, "scan 8 all wake+drop");
557
+ put_dec(17, 22, t_worst, 5);
558
+ put_per_call(17, 30, t_worst, t_ro);
559
+
560
+ pass = pass && worst_ok;
561
+ put_str(18, 0, pass ? "pass" : "fail");
562
+ vic.color_border = pass ? VCOL_GREEN : VCOL_RED;
563
+
564
+ // Draw the actors live at the end, camera 0, as sprites.
565
+ for (char k = 0; k < 63; k++)
566
+ SPRDATA[k] = 0xff;
567
+ char en = 0, msb = 0;
568
+ for (char s = 0; s < NSLOT; s++)
569
+ {
570
+ ((char *)0x07f8)[s] = 13;
571
+ vic.spr_color[s] = VCOL_YELLOW;
572
+ if (sv_lvl[s] == NO_SLOT || sv_px[s] >= VIEW * 8)
573
+ continue;
574
+ unsigned sx = sv_px[s] + 24;
575
+ vic.spr_pos[s].x = (char)sx;
576
+ vic.spr_pos[s].y = 50 + (lvl_row[sv_lvl[s]] << 3);
577
+ if (sx & 0x100)
578
+ msb |= 1 << s;
579
+ en |= 1 << s;
580
+ }
581
+ vic.spr_msbx = msb;
582
+ vic.spr_enable = en;
583
+ for (;;)
584
+ ;
585
+ return 0;
586
+ }
587
+ ```
588
+
589
+ ## Build
590
+
591
+ ```
592
+ oscar64 -tm=c64 -O2 -o=actor-activation-window.prg actor-activation-window.c
593
+ GSETTINGS_SCHEMA_DIR=/opt/homebrew/share/glib-2.0/schemas timeout 180 x64sc -default -minimized -warp +sound +autostart-delay-random -autostartprgmode 1 -limitcycles 8000000 -exitscreenshot actor-activation-window.png -autostart actor-activation-window.prg
594
+ ```
595
+
596
+ Add `-model ntsc` for the NTSC picture. 8,000,000 cycles is the pinned
597
+ run. The screen was complete at 6,000,000 on both models (measured).
598
+ A build without the worst-tick row was blank at 5,000,000 (measured,
599
+ PAL).
600
+
601
+ ## Expected output
602
+
603
+ Black screen, green border, five yellow sprites in the lower part of the
604
+ screen. Decoded from `screenshots/actor-activation-window.png` (PAL) with
605
+ the character ROM; rows 8 and 19 to 24 hold no text:
606
+
607
+ ```text
608
+ ACTOR WINDOW 32 PLACED 8 SLOTS
609
+ MARGIN 8 SCAN 8/TICK CAM 16 OUT 8 BACK
610
+ KILL 9 11 HIT 10 AT CAM 560
611
+ WAKES 9 BEFORE 1 AFTER 1
612
+ WAKES 11 BEFORE 1 AFTER 1
613
+ 10 OUT COL 086 HP 1 IN PX 0688 HP 1
614
+ POPIN 00 REFUSED 00 PEAK 8 WAKES 056
615
+ CHK 1D54 EXP 1D54 MARGIN 1 POPIN 037
616
+
617
+ CYCLES X20 TOTAL PER CALL
618
+ EMPTY CALL 00749
619
+ SCAN 8, NONE WAKES 09149 0420.00
620
+ SCAN ALL 32 23809 1153.00
621
+ DROP PASS, 8 LIVE 11329 0529.00
622
+ WINDOW+SCAN 8+DROP 22269 1076.00
623
+ PATROL 8 (PAYLOAD) 25249 1225.00
624
+ WAKE + DROP BACK 06029 0264.00
625
+ SCAN 8 ALL WAKE+DROP 60529 2809.00
626
+ PASS
627
+ ```
628
+
629
+ `screenshots/actor-activation-window-ntsc.png` (`-model ntsc`) decodes to
630
+ the same text, and the cycle counts are identical on both models (the CIA
631
+ counts phi2 cycles with the screen blanked). Each model's pinned run was
632
+ made twice and gave byte-identical PNGs (measured in VICE x64sc 3.10).
633
+
634
+ The sprites, measured with PIL on both pictures. Screenshot x is world
635
+ pixel x plus 32, because the camera is at 0 and sprite X is world x plus
636
+ 24; the top raster line is the character row's top line, one below the
637
+ sprite Y register:
638
+
639
+ | Level entry | World x (px) | Screenshot x | Raster lines | Text row, 19 + (entry AND 3) |
640
+ |---|---|---|---|---|
641
+ | 0 | 54 | 86 to 109 | 203 to 223 | 19 |
642
+ | 1 | 96 | 128 to 151 | 211 to 231 | 20 |
643
+ | 2 | 162 | 194 to 217 | 219 to 239 | 21 |
644
+ | 3 | 242 | 274 to 297 | 227 to 247 | 22 |
645
+ | 4 | 284 | 316 to 339 | 203 to 223 | 19 |
646
+
647
+ Entry 4 is at sprite X 308, past 255, so it needs its bit in `$D010`
648
+ (`sprite_x_high_bit_wrong_register`). Entry 5 is live at world x 358, in
649
+ the margin and outside the view, so it has no sprite. The world positions
650
+ are the Python model's; none of the five is at its placed position
651
+ (32 + 64 × entry) because each has patrolled since it woke.
652
+
653
+ What each row states:
654
+
655
+ - Rows 3 and 4: actors 9 and 11 each woke once on the way out; after the
656
+ kill the count is still 1, so the dead flag kept them asleep while the
657
+ camera passed them again.
658
+ - Row 5: actor 10 went back to the table at column 86 with 1 hit point
659
+ (it was placed at column 84 with 3), and woke on the way back at pixel
660
+ 688 = 86 × 8 with 1 hit point.
661
+ - Row 6: no dormant, living entry was ever inside the view; no wake was
662
+ refused for want of a slot; at most 8 slots were live at once; 56 wakes
663
+ in all.
664
+ - Row 7: the fold over the 96 bytes of `lvl_x`, `lvl_hp` and `lvl_flags`
665
+ is $1D54 on the 6510 and in Python. The same scenario run first with a
666
+ margin of 1 column had 37 pop-ins (tick-entry pairs where a living
667
+ actor was in view but dormant).
668
+ - Rows 10 to 17: CIA1 timer A over 20 calls, total and net per call.
669
+ Row 17 is the worst tick: all slots free, and all 8 entries of the
670
+ slice inside the wake window, so the tick wakes 8 and then runs the
671
+ drop pass over 8 live. It is timed with a slot reset in each call; the
672
+ net figure subtracts a call that only resets. The program checks that
673
+ all 8 woke; PASS includes that check.
674
+
675
+ The Python model of the scenario. The C code clamps the window bounds to
676
+ 0 to 255 and compares one byte; the model compares unclamped integers and
677
+ gives the same table:
678
+
679
+ ```python
680
+ NLVL, NSLOT, K, VIEW, HYST = 32, 8, 8, 40, 2
681
+ LIVE, DEAD = 0x40, 0x80
682
+ home = [4 + 8 * i for i in range(NLVL)]
683
+
684
+ def run(margin):
685
+ lx, hp, fl = list(home), [3] * NLVL, [i & 1 for i in range(NLVL)]
686
+ sl, px, shp, sd = [None] * NSLOT, [0] * NSLOT, [0] * NSLOT, [0] * NSLOT
687
+ st = dict(scan=0, live=0, peak=0, wakes=0, popin=0, hit=False, out=None, back=None)
688
+ wn = [0] * NLVL
689
+
690
+ def wake(i):
691
+ if None not in sl:
692
+ return
693
+ s = sl.index(None)
694
+ sl[s], px[s], shp[s], sd[s] = i, lx[i] * 8, hp[i], fl[i] & 1
695
+ fl[i] |= LIVE
696
+ st['live'] += 1; st['peak'] = max(st['peak'], st['live'])
697
+ st['wakes'] += 1; wn[i] += 1
698
+ if i == 10 and st['out'] and not st['back']:
699
+ st['back'] = (px[s], shp[s])
700
+
701
+ def drop(s):
702
+ i = sl[s]
703
+ lx[i], hp[i] = px[s] >> 3, shp[s]
704
+ fl[i] = (fl[i] & ~(LIVE | 1)) | sd[s]
705
+ if i == 10 and st['hit'] and not st['out']:
706
+ st['out'] = (lx[i], hp[i])
707
+ sl[s] = None; st['live'] -= 1
708
+
709
+ def kill(i):
710
+ s = sl.index(i)
711
+ fl[i] = (fl[i] & ~LIVE) | DEAD; hp[i] = 0
712
+ sl[s] = None; st['live'] -= 1
713
+
714
+ def tick(cam):
715
+ cc = cam >> 3
716
+ lo, hi = cc - margin, cc + VIEW + margin
717
+ i = st['scan']
718
+ for _ in range(K):
719
+ if not fl[i] & (LIVE | DEAD) and lo <= lx[i] < hi:
720
+ wake(i)
721
+ i = (i + 1) % NLVL
722
+ st['scan'] = i
723
+ for s in range(NSLOT):
724
+ if sl[s] is None:
725
+ continue
726
+ px[s] += -1 if sd[s] else 1
727
+ c = px[s] >> 3
728
+ if c >= home[sl[s]] + 3: sd[s] = 1
729
+ elif c + 3 <= home[sl[s]]: sd[s] = 0
730
+ for s in range(NSLOT):
731
+ if sl[s] is not None and not lo - HYST <= px[s] >> 3 < hi + HYST:
732
+ drop(s)
733
+ st['popin'] += sum(1 for i in range(NLVL)
734
+ if not fl[i] & (LIVE | DEAD) and cc <= lx[i] < cc + VIEW)
735
+
736
+ for cam in range(0, 1729, 16):
737
+ tick(cam)
738
+ if cam == 560:
739
+ kill(9); kill(11)
740
+ shp[sl.index(10)] = 1
741
+ st['hit'] = True
742
+ for cam in range(1728, -1, -8):
743
+ tick(cam)
744
+ chk = 0
745
+ for i in range(NLVL):
746
+ for v in (lx[i], hp[i], fl[i]):
747
+ chk = ((chk ^ v) * 5 + 1) & 0xFFFF
748
+ return st, wn, hex(chk), [(sl[s], px[s]) for s in range(NSLOT) if sl[s] is not None]
749
+
750
+ st, wn, chk, live = run(8)
751
+ print(wn[9], wn[11], wn[10], wn[12], st['out'], st['back'])
752
+ print(st['popin'], st['peak'], st['wakes'], chk)
753
+ print(sorted(live))
754
+ print([run(m)[0]['popin'] for m in range(1, 9)])
755
+ ```
756
+
757
+ It prints `1 1 2 2 (86, 1) (688, 1)`, `0 8 56 0x1d54`, the six live
758
+ slots with their pixel positions, and the pop-in count for margins 1 to
759
+ 8: `[37, 25, 3, 3, 0, 0, 0, 0]`.
760
+
761
+ ## Why this works
762
+
763
+ The level table is the only record of an actor while it is off screen. A
764
+ slot holds a copy while the actor is near the view, and the copy goes
765
+ back on the way out: column, hit points and facing. Sub-column position
766
+ is lost: the table stores `px >> 3`, and the actor wakes at `column × 8`.
767
+ Actor 10 was left somewhere between pixel 688 and 695 and woke at
768
+ 688; a finer table entry costs a byte per actor. A dead entry is never deleted, only flagged, so
769
+ the scan skips it for the rest of the level with one `AND` of the flag
770
+ byte.
771
+
772
+ The margin is what hides the scan's latency. Eight entries a tick means
773
+ each entry is looked at every 4 ticks, and at 16 pixels a tick the camera
774
+ moves 8 columns in 4 ticks. An entry examined one column outside the
775
+ window can be 8 columns closer when it is next examined, so a margin of 8
776
+ columns is safe for any layout (arithmetic). It is not the least. The
777
+ scan runs before the pop-in check in the same tick, so an entry is
778
+ examined again on the tick it would first be in view; that leaves 3
779
+ ticks, 6 columns, to cover, and a margin of 6 is enough. A Python model
780
+ of the scan alone over adversarial layouts (every entry on one column,
781
+ every scan phase, and random layouts) gives worst pop-in counts of 15
782
+ at margin 5 and 0 at margins 6 to 9 (rung 3, a model; not run in VICE).
783
+ The measured run: 0 pop-ins with 8, 37 with 1. The recipe's Python model
784
+ shows this layout gets by with 5, because its actors are 8 columns
785
+ apart. The
786
+ drop window is 2 columns wider than the wake window, so an actor
787
+ patrolling on the edge is not dropped and woken on alternate ticks.
788
+
789
+ The costs are Oscar64 -O2 code and are larger than hand-written assembly
790
+ would be. The scan examines an entry in about 52 cycles when it slices
791
+ eight (420 per call) and about 36 when it walks all 32 in one loop (1,153
792
+ per call): the round-robin wrap costs an `AND` and a zero-page reload per
793
+ entry. The drop pass costs 529 cycles for 8 live actors, most of it the
794
+ 16-bit shift from pixel to column. The window set-up, a scan slice and
795
+ the drop pass together cost 1,076 cycles a tick, an average over the 20
796
+ timed calls (five laps of the table) with entries 0 to 7 live, when
797
+ nothing wakes or drops. One wake and one drop add 264. The worst tick,
798
+ 8 wakes and the drop pass over 8 live, costs 2,809 cycles, 14.3% of a
799
+ 19,656-cycle PAL frame (arithmetic from the measured figure). A tick can
800
+ wake at most K entries, and wakes plus drops in one tick cannot exceed
801
+ the 8 slots, because a woken actor is inside the drop window. A variant
802
+ of this listing that drops all 8 in one tick, and wakes none, measured
803
+ 1,850 cycles, so waking is the heavier case (VICE x64sc, PAL). The patrol row is
804
+ the demonstration's own actor logic and is not part of the technique.
805
+ Timing uses 20 calls per subject: a first build with 50 calls read 176.6
806
+ cycles for the update pass, a fraction from a loop that does the same
807
+ work every call, which is the 16-bit timer wrapping at 65,536.