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,881 @@
1
+ ---
2
+ recipe: nav-area-pathfinding
3
+ toolchain: oscar64
4
+ output_format: PRG
5
+ region: both
6
+ techniques: [nav_area_pathfinding]
7
+ file_formats: [PRG]
8
+ uses_registers: [D011, D020, D021, DC04, DC05, DC06, DC07, DC0E, DC0F]
9
+ uses_kernal: []
10
+ ---
11
+
12
+ <!-- doc-type: recipe -->
13
+
14
+ # Oscar64 Nav-Area Pathfinding: a chaser routed over platforms, ladders, drops and jumps
15
+
16
+ ## Synopsis
17
+
18
+ A chaser crosses a character-map level of twelve platform areas to reach
19
+ a player marker, which moves to the next of eight waypoints each time it
20
+ is caught. At start the program finds the areas (runs of cells an actor
21
+ can stand in), joins them with 43 links (walk, drop, jump, ladder, each
22
+ with a cost), runs one Dijkstra search per destination and keeps a
23
+ next-hop table: for every pair of areas, the link to take first. Each
24
+ move is then one table read. Odd frames spend the chaser's budget on one
25
+ step of a line-of-sight ray to the player instead. Every hop taken is
26
+ checked against a table computed in Python by a different method
27
+ (Floyd-Warshall) and compiled in, and the whole table is compared too.
28
+ The screen shows the build time, the worst search, query and ray step in
29
+ CIA1 cycles, and PASS or FAIL. `$02FF` = `01` and a green border on
30
+ pass, `02` and red on fail. This is the `nav_area_pathfinding` technique
31
+ in `docs/techniques/logic.md`; the result-byte contract is
32
+ `headless-verify.md`.
33
+
34
+ ## Source
35
+
36
+ ```c
37
+ // nav-area-pathfinding.c
38
+ //
39
+ // Platform-graph pathfinding on a character map. At start the program
40
+ // finds the walkable areas (runs of cells an actor can stand in), links
41
+ // them by walk, drop, jump and ladder moves with a cost each, runs one
42
+ // Dijkstra search per destination and keeps a next-hop table: for each
43
+ // (from, to) pair of areas, the link to take first. A chaser then follows
44
+ // a player marker that moves to the next waypoint each time it is caught.
45
+ // Even frames the chaser moves one cell and makes one table query; odd
46
+ // frames it takes one step of a line-of-sight ray to the player.
47
+ // Each hop taken is checked against a next-hop table computed in Python
48
+ // by a different method (Floyd-Warshall) and compiled in.
49
+ // Row 0: build cycles, worst single search, areas and links. Row 1:
50
+ // worst query, worst LOS step, area and link pass, next-hop pass, all
51
+ // CIA1 cycles. Row 2: steps, queries, bad hops, table mismatches, LOS
52
+ // pairs right, result. $02FF = 01 and a green border on
53
+ // pass, 02 and red on fail. The chaser leaves a cyan trail.
54
+ // Build: oscar64 -tm=c64 -O2 -o=nav-area-pathfinding.prg nav-area-pathfinding.c
55
+ #include <c64/vic.h>
56
+ #include <c64/cia.h>
57
+ #include <string.h>
58
+
59
+ #define SCREEN ((char *)0x0400)
60
+ #define COLOUR ((char *)0xd800)
61
+ #define RESULT (*(volatile char *)0x02ff)
62
+ #define CODE_PASS 0x01
63
+ #define CODE_FAIL 0x02
64
+
65
+ // Map rows 0-21 are screen rows 3-24. '#' solid, 'H' ladder, '.' air.
66
+ #define MAP_ROW0 3
67
+ #define MW 40
68
+ #define MH 22
69
+ const char map_text[MH][MW + 1] = {
70
+ "........................................", // 0
71
+ "........................................", // 1
72
+ "........................................", // 2
73
+ "..######H#####..........######H######...", // 3
74
+ "........H.....................H.........", // 4
75
+ "........H.....................H.........", // 5
76
+ "........H.....................H.........", // 6
77
+ "....#H######...##H####..####H###........", // 7
78
+ ".....H...........H..........H...........", // 8
79
+ ".....H...........H..........H...........", // 9
80
+ ".....H...........H..........H...........", // 10
81
+ "..#H#####H#.########......#########H##..", // 11
82
+ "...H.....H.........................H....", // 12
83
+ "...H.....H.........................H....", // 13
84
+ "...H.....H.........................H....", // 14
85
+ "...H..#########.....####H#####.....H....", // 15
86
+ "...H....................H.....#####H....", // 16
87
+ "...H....................H..........H....", // 17
88
+ "...H....................H..........H....", // 18
89
+ "...H....................H..........H....", // 19
90
+ "...H....................H..........H....", // 20
91
+ "########################################", // 21
92
+ };
93
+
94
+ // Next area on a shortest route, from the Python model (Floyd-Warshall,
95
+ // first hop = lowest-numbered link on a shortest route). 255 on the
96
+ // diagonal.
97
+ #define EXP_N 12
98
+ const char exp_next[EXP_N * EXP_N] = {
99
+ 255, 6, 2, 6, 6, 2, 6, 6, 2, 6, 6, 2,
100
+ 4, 255, 4, 4, 4, 4, 4, 4, 4, 9, 9, 4,
101
+ 0, 6, 255, 6, 6, 5, 6, 6, 5, 6, 6, 5,
102
+ 6, 4, 6, 255, 4, 6, 6, 4, 6, 9, 9, 9,
103
+ 3, 1, 3, 3, 255, 3, 3, 7, 3, 9, 9, 7,
104
+ 2, 6, 2, 6, 6, 255, 6, 6, 8, 6, 6, 11,
105
+ 5, 3, 5, 3, 3, 5, 255, 3, 8, 9, 9, 9,
106
+ 4, 4, 4, 4, 4, 4, 4, 255, 4, 9, 9, 11,
107
+ 5, 5, 5, 5, 5, 5, 5, 11, 255, 5, 5, 11,
108
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 255, 10, 11,
109
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 255, 9,
110
+ 5, 7, 5, 5, 7, 5, 5, 7, 5, 9, 9, 255,
111
+ };
112
+ #define EXP_STEPS 299
113
+ #define EXP_QUERIES 160
114
+
115
+ // Waypoints the player marker visits, (x, map row); each is a standing cell.
116
+ #define NWP 8
117
+ const char wp_x[NWP] = { 34, 4, 32, 10, 13, 7, 26, 38 };
118
+ const char wp_y[NWP] = { 2, 20, 15, 2, 10, 14, 6, 20 };
119
+ #define START_X 1
120
+ #define START_Y 20
121
+
122
+ // LOS test pairs: straight rows and columns, so any line algorithm gives
123
+ // the same answer. 1 clear, 2 blocked.
124
+ #define NLOS 4
125
+ const char los_x0[NLOS] = { 0, 10, 14, 0 };
126
+ const char los_y0[NLOS] = { 20, 10, 10, 7 };
127
+ const char los_x1[NLOS] = { 39, 10, 14, 20 };
128
+ const char los_y1[NLOS] = { 20, 14, 2, 7 };
129
+ const char los_exp[NLOS] = { 1, 2, 1, 2 };
130
+
131
+ // --- tiles ---------------------------------------------------------------
132
+ static inline char tile(signed char y, signed char x)
133
+ {
134
+ if (x < 0 || x >= MW || y < 0)
135
+ return '.';
136
+ if (y >= MH)
137
+ return '#';
138
+ return map_text[y][x];
139
+ }
140
+
141
+ bool standable(signed char y, signed char x)
142
+ {
143
+ if (y < 0 || y >= MH - 1 || x < 0 || x >= MW)
144
+ return false;
145
+ char c = map_text[y][x];
146
+ if (c == '#')
147
+ return false;
148
+ char b = map_text[y + 1][x];
149
+ return b == '#' || (b == 'H' && c != 'H');
150
+ }
151
+
152
+ // --- areas and links -------------------------------------------------------
153
+ #define MAXA 16 // table stride; N <= 16
154
+ #define MAXL 64
155
+ #define NONE 255
156
+ enum { L_WALK, L_DROP, L_JUMP, L_LADDER };
157
+
158
+ char n_areas, n_links;
159
+ char ay[MAXA], ax0[MAXA], ax1[MAXA];
160
+ char area_at[MH][MW]; // area per standing cell, NONE elsewhere
161
+ char lf[MAXL], lt[MAXL], lty[MAXL], lsx[MAXL], lex[MAXL], ley[MAXL], lc[MAXL];
162
+ char dist[MAXA * MAXA]; // dist[from * MAXA + to]
163
+ char nextl[MAXA * MAXA]; // link to take first, NONE if none
164
+
165
+ void add_link(char f, char t, char ty, char sx, char ex, char ey, char c)
166
+ {
167
+ char i = n_links++;
168
+ lf[i] = f; lt[i] = t; lty[i] = ty;
169
+ lsx[i] = sx; lex[i] = ex; ley[i] = ey; lc[i] = c;
170
+ }
171
+
172
+ // Step sideways into (y, x) and fall: the landing row, or NONE.
173
+ char fall_from(char y, signed char x)
174
+ {
175
+ if (x < 0 || x >= MW || map_text[y][x] != '.')
176
+ return NONE;
177
+ for (;;) {
178
+ if (standable(y, x))
179
+ return y;
180
+ y++;
181
+ if (y >= MH - 1 || map_text[y][x] != '.')
182
+ return NONE;
183
+ }
184
+ }
185
+
186
+ void build_areas(void)
187
+ {
188
+ memset(area_at, NONE, sizeof(area_at));
189
+ n_areas = 0;
190
+ for (char y = 0; y < MH; y++) {
191
+ char x = 0;
192
+ while (x < MW) {
193
+ if (standable(y, x)) {
194
+ char a = n_areas++;
195
+ ay[a] = y; ax0[a] = x;
196
+ while (x < MW && standable(y, x))
197
+ area_at[y][x++] = a;
198
+ ax1[a] = x - 1;
199
+ } else
200
+ x++;
201
+ }
202
+ }
203
+ }
204
+
205
+ void build_links(void)
206
+ {
207
+ n_links = 0;
208
+ for (char a = 0; a < n_areas; a++) {
209
+ char y = ay[a], x0 = ax0[a], x1 = ax1[a];
210
+ // Right end, then left end: a one-row step down is a walk both
211
+ // ways, a longer fall is a one-way drop.
212
+ for (char e = 0; e < 2; e++) {
213
+ char sx = e ? x0 : x1;
214
+ signed char x = e ? (signed char)x0 - 1 : x1 + 1;
215
+ char land = fall_from(y, x);
216
+ if (land != NONE && land > y) {
217
+ char b = area_at[land][x];
218
+ if (land == y + 1) {
219
+ add_link(a, b, L_WALK, sx, x, land, 1);
220
+ add_link(b, a, L_WALK, x, sx, y, 1);
221
+ } else
222
+ add_link(a, b, L_DROP, sx, x, land, land - y + 1);
223
+ }
224
+ if (e == 0) {
225
+ // Jump right over a gap of 1 or 2 cells to the same row.
226
+ for (char gap = 1; gap <= 2; gap++) {
227
+ char bx = x1 + gap + 1;
228
+ if (bx >= MW || area_at[y][bx] == NONE)
229
+ continue;
230
+ bool clear = true;
231
+ for (char xx = x1; xx <= bx; xx++)
232
+ if (tile(y - 1, xx) != '.') clear = false;
233
+ for (char xx = x1 + 1; xx < bx; xx++)
234
+ if (map_text[y][xx] != '.') clear = false;
235
+ if (clear) {
236
+ char b = area_at[y][bx];
237
+ add_link(a, b, L_JUMP, x1, bx, y, gap + 2);
238
+ add_link(b, a, L_JUMP, bx, x1, y, gap + 2);
239
+ break;
240
+ }
241
+ }
242
+ }
243
+ }
244
+ // Ladders going down from this area.
245
+ for (char x = x0; x <= x1; x++) {
246
+ if (tile(y + 1, x) != 'H')
247
+ continue;
248
+ char yb = y + 1;
249
+ while (tile(yb + 1, x) == 'H')
250
+ yb++;
251
+ char b = area_at[yb][x];
252
+ if (b != NONE) {
253
+ add_link(a, b, L_LADDER, x, x, yb, yb - y);
254
+ add_link(b, a, L_LADDER, x, x, y, yb - y);
255
+ }
256
+ }
257
+ }
258
+ }
259
+
260
+ // One search: cheapest cost from every area to area j, Dijkstra over the
261
+ // links read backwards. Writes column j of dist.
262
+ void search_to(char j)
263
+ {
264
+ char d[MAXA];
265
+ bool done[MAXA];
266
+ char n = n_areas;
267
+ for (char i = 0; i < n; i++) {
268
+ d[i] = NONE;
269
+ done[i] = false;
270
+ }
271
+ d[j] = 0;
272
+ for (char k = 0; k < n; k++) {
273
+ char best = NONE, u = NONE;
274
+ for (char i = 0; i < n; i++)
275
+ if (!done[i] && d[i] < best) {
276
+ best = d[i];
277
+ u = i;
278
+ }
279
+ if (u == NONE)
280
+ break;
281
+ done[u] = true;
282
+ for (char l = 0; l < n_links; l++)
283
+ if (lt[l] == u) {
284
+ unsigned c = best + lc[l];
285
+ char v = lf[l];
286
+ if (c < d[v])
287
+ d[v] = c;
288
+ }
289
+ }
290
+ for (char i = 0; i < n; i++)
291
+ dist[i * MAXA + j] = d[i];
292
+ }
293
+
294
+ // First link on a shortest route from i to j: the lowest-numbered link
295
+ // out of i whose cost plus the rest of the route equals the route cost.
296
+ void build_next(void)
297
+ {
298
+ for (char i = 0; i < n_areas; i++)
299
+ for (char j = 0; j < n_areas; j++) {
300
+ char r = NONE, dij = dist[i * MAXA + j];
301
+ if (i != j && dij != NONE)
302
+ for (char l = 0; l < n_links; l++) {
303
+ char dt = dist[lt[l] * MAXA + j];
304
+ if (lf[l] == i && dt != NONE && lc[l] + dt == dij) {
305
+ r = l;
306
+ break;
307
+ }
308
+ }
309
+ nextl[i * MAXA + j] = r;
310
+ }
311
+ }
312
+
313
+ // --- CIA1 timers -------------------------------------------------------------
314
+ // Timer B alone for short work; timer B counting timer A underflows for
315
+ // the build, which runs past 65,535 cycles.
316
+ static inline void timer_start(void)
317
+ {
318
+ cia1.crb = 0x00;
319
+ cia1.tb = 0xffff;
320
+ cia1.crb = 0x11;
321
+ }
322
+
323
+ static inline unsigned timer_stop(void)
324
+ {
325
+ cia1.crb = 0x00;
326
+ return 0xffff - cia1.tb;
327
+ }
328
+
329
+ void long_start(void)
330
+ {
331
+ cia1.cra = 0x00;
332
+ cia1.crb = 0x00;
333
+ cia1.ta = 0xffff;
334
+ cia1.tb = 0xffff;
335
+ cia1.crb = 0x51; // load, start, count TA underflows
336
+ cia1.cra = 0x11; // load, start, count cycles
337
+ }
338
+
339
+ unsigned long long_stop(void)
340
+ {
341
+ cia1.cra = 0x00;
342
+ cia1.crb = 0x00;
343
+ return ((unsigned long)(0xffff - cia1.tb) << 16) + (0xffff - cia1.ta);
344
+ }
345
+
346
+ // --- actors ------------------------------------------------------------------
347
+ char cx, cy, px, py; // chaser and player, (x, map row)
348
+ char tr_ty = NONE, tr_sx, tr_ex, tr_ey; // link in progress, NONE when standing
349
+
350
+ // The query: which link to take first from the chaser's area to the
351
+ // player's. Two cell lookups and one table read.
352
+ char nav_query(void)
353
+ {
354
+ char a = area_at[cy][cx];
355
+ char p = area_at[py][px];
356
+ if (a == p)
357
+ return NONE;
358
+ return nextl[a * MAXA + p];
359
+ }
360
+
361
+ void transit_step(void)
362
+ {
363
+ signed char d = tr_ex > tr_sx ? 1 : (tr_ex < tr_sx ? -1 : 0);
364
+ switch (tr_ty) {
365
+ case L_WALK:
366
+ cx = tr_ex; cy = tr_ey;
367
+ break;
368
+ case L_LADDER:
369
+ if (tr_ey > cy) cy++; else cy--;
370
+ break;
371
+ case L_DROP:
372
+ if (cx != tr_ex) cx = tr_ex; else cy++;
373
+ break;
374
+ case L_JUMP: // up and over, across, down
375
+ if (cy == tr_ey && cx == tr_sx) { cx += d; cy--; }
376
+ else if (cx != tr_ex) cx += d;
377
+ else cy++;
378
+ break;
379
+ }
380
+ if (cx == tr_ex && cy == tr_ey)
381
+ tr_ty = NONE;
382
+ }
383
+
384
+ // --- line of sight, one cell per call ------------------------------------------
385
+ signed char lx, ly, ltx, lty2, lsxs, lsys;
386
+ int ldx, ldy, lerr;
387
+ char los_state; // 0 idle, 1 running
388
+
389
+ void los_begin(char x0, char y0, char x1, char y1)
390
+ {
391
+ lx = x0; ly = y0; ltx = x1; lty2 = y1;
392
+ ldx = x1 > x0 ? x1 - x0 : x0 - x1;
393
+ ldy = -(int)(y1 > y0 ? y1 - y0 : y0 - y1);
394
+ lsxs = x0 < x1 ? 1 : -1;
395
+ lsys = y0 < y1 ? 1 : -1;
396
+ lerr = ldx + ldy;
397
+ los_state = 1;
398
+ }
399
+
400
+ // 0 still running, 1 clear, 2 blocked.
401
+ char los_step(void)
402
+ {
403
+ if (lx == ltx && ly == lty2) {
404
+ los_state = 0;
405
+ return 1;
406
+ }
407
+ int e2 = 2 * lerr;
408
+ if (e2 >= ldy) { lerr += ldy; lx += lsxs; }
409
+ if (e2 <= ldx) { lerr += ldx; ly += lsys; }
410
+ if (map_text[ly][lx] == '#') {
411
+ los_state = 0;
412
+ return 2;
413
+ }
414
+ return 0;
415
+ }
416
+
417
+ // --- drawing -------------------------------------------------------------------
418
+ #define C_FLOOR VCOL_GREEN
419
+ #define C_LADDER VCOL_ORANGE
420
+ #define C_TRAIL VCOL_CYAN
421
+ #define C_CHASER VCOL_WHITE
422
+ #define C_PLAYER VCOL_YELLOW
423
+
424
+ void draw_trail(char x, char y)
425
+ {
426
+ unsigned o = (y + MAP_ROW0) * 40 + x;
427
+ if (map_text[y][x] == '.')
428
+ SCREEN[o] = 0x2e; // '.'
429
+ COLOUR[o] = C_TRAIL;
430
+ }
431
+
432
+ void draw_at(char x, char y, char ch, char col)
433
+ {
434
+ unsigned o = (y + MAP_ROW0) * 40 + x;
435
+ SCREEN[o] = ch;
436
+ COLOUR[o] = col;
437
+ }
438
+
439
+ void put_str(char *p, const char *s)
440
+ {
441
+ while (*s)
442
+ *p++ = *s++;
443
+ }
444
+
445
+ void put_dec(char *p, unsigned long v, char digits)
446
+ {
447
+ for (char i = digits; i > 0; i--) {
448
+ p[i - 1] = 0x30 + (char)(v % 10);
449
+ v /= 10;
450
+ }
451
+ }
452
+
453
+ int main(void)
454
+ {
455
+ __asm { sei }
456
+ vic.color_border = VCOL_BLACK;
457
+ vic.color_back = VCOL_BLACK;
458
+ memset(SCREEN, 0x20, 1000);
459
+ memset(COLOUR, VCOL_LT_GREY, 1000);
460
+ for (char y = 0; y < MH; y++)
461
+ for (char x = 0; x < MW; x++) {
462
+ char c = map_text[y][x];
463
+ if (c == '#') draw_at(x, y, 0xa0, C_FLOOR);
464
+ else if (c == 'H') draw_at(x, y, 0x08, C_LADDER);
465
+ }
466
+
467
+ // Build: areas, links, one search per destination, next-hop table.
468
+ unsigned long t_search_max = 0;
469
+ long_start();
470
+ build_areas();
471
+ build_links();
472
+ unsigned long t_graph = long_stop();
473
+ for (char j = 0; j < n_areas; j++) {
474
+ long_start();
475
+ search_to(j);
476
+ unsigned long t = long_stop();
477
+ if (t > t_search_max) t_search_max = t;
478
+ }
479
+ long_start();
480
+ build_next();
481
+ unsigned long t_next = long_stop();
482
+ // Full build timed once more in one piece.
483
+ long_start();
484
+ build_areas();
485
+ build_links();
486
+ for (char j = 0; j < n_areas; j++)
487
+ search_to(j);
488
+ build_next();
489
+ unsigned long t_build = long_stop();
490
+
491
+ // Whole table against the model.
492
+ char mismatch = 0;
493
+ if (n_areas != EXP_N)
494
+ mismatch = 255;
495
+ else
496
+ for (char i = 0; i < EXP_N; i++)
497
+ for (char j = 0; j < EXP_N; j++) {
498
+ char l = nextl[i * MAXA + j];
499
+ // Not a ternary: Oscar64 1.32.271 at -O1 to -O3 drops the l == NONE
500
+ // test when lt has fewer than 256 entries and reads lt[255].
501
+ char h = NONE;
502
+ if (l != NONE)
503
+ h = lt[l];
504
+ if (h != exp_next[i * EXP_N + j]) mismatch++;
505
+ }
506
+
507
+ put_str(SCREEN, s"build");
508
+ put_dec(SCREEN + 6, t_build, 7);
509
+ put_str(SCREEN + 15, s"search");
510
+ put_dec(SCREEN + 22, t_search_max, 6);
511
+ put_str(SCREEN + 30, s"n");
512
+ put_dec(SCREEN + 32, n_areas, 2);
513
+ put_dec(SCREEN + 35, n_links, 2);
514
+ put_str(SCREEN + 40, s"qry");
515
+ put_str(SCREEN + 50, s"los");
516
+ put_str(SCREEN + 60, s"ar");
517
+ put_dec(SCREEN + 63, t_graph, 6);
518
+ put_str(SCREEN + 70, s"nx");
519
+ put_dec(SCREEN + 73, t_next, 6);
520
+ put_str(SCREEN + 80, s"st q bad mis los r");
521
+
522
+ cx = START_X; cy = START_Y;
523
+ char wp = 0;
524
+ px = wp_x[0]; py = wp_y[0];
525
+ draw_trail(cx, cy);
526
+ draw_at(px, py, 0x53, C_PLAYER);
527
+ draw_at(cx, cy, 0x51, C_CHASER);
528
+
529
+ unsigned steps = 0, queries = 0, t_q = 0, t_los = 0;
530
+ char bad = 0, frame = 0;
531
+ bool done = false;
532
+
533
+ for (;;) {
534
+ vic_waitFrame();
535
+ if (done)
536
+ continue;
537
+ frame++;
538
+ if (frame & 1) {
539
+ // Odd frame: one line-of-sight step toward the player.
540
+ timer_start();
541
+ if (los_state == 0)
542
+ los_begin(cx, cy, px, py);
543
+ else
544
+ los_step();
545
+ unsigned t = timer_stop();
546
+ if (t > t_los) t_los = t;
547
+ continue;
548
+ }
549
+
550
+ // Even frame: the chaser moves one cell.
551
+ draw_trail(cx, cy);
552
+ if (tr_ty != NONE)
553
+ transit_step();
554
+ else {
555
+ timer_start();
556
+ char l = nav_query();
557
+ unsigned t = timer_stop();
558
+ if (t > t_q) t_q = t;
559
+ if (l == NONE) {
560
+ if (px > cx) cx++;
561
+ else if (px < cx) cx--;
562
+ } else {
563
+ queries++;
564
+ char a = area_at[cy][cx], p = area_at[py][px];
565
+ if (lt[l] != exp_next[a * EXP_N + p]) bad++;
566
+ if (cx != lsx[l])
567
+ cx += cx < lsx[l] ? 1 : -1;
568
+ else {
569
+ tr_ty = lty[l]; tr_sx = lsx[l];
570
+ tr_ex = lex[l]; tr_ey = ley[l];
571
+ transit_step();
572
+ }
573
+ }
574
+ }
575
+ steps++;
576
+ if (tr_ty == NONE && cx == px && cy == py) {
577
+ wp++;
578
+ if (wp == NWP)
579
+ done = true;
580
+ else {
581
+ px = wp_x[wp]; py = wp_y[wp];
582
+ draw_at(px, py, 0x53, C_PLAYER);
583
+ }
584
+ }
585
+ draw_at(cx, cy, 0x51, C_CHASER);
586
+ put_dec(SCREEN + 44, t_q, 5);
587
+ put_dec(SCREEN + 54, t_los, 5);
588
+ put_dec(SCREEN + 80 + 3, steps, 3);
589
+ put_dec(SCREEN + 80 + 9, queries, 3);
590
+
591
+ if (done) {
592
+ char los_ok = 0;
593
+ for (char i = 0; i < NLOS; i++) {
594
+ los_begin(los_x0[i], los_y0[i], los_x1[i], los_y1[i]);
595
+ char r;
596
+ while ((r = los_step()) == 0)
597
+ ;
598
+ if (r == los_exp[i]) los_ok++;
599
+ }
600
+ char fault = 0;
601
+ if (mismatch) fault = 1;
602
+ else if (bad) fault = 2;
603
+ else if (steps != EXP_STEPS || queries != EXP_QUERIES) fault = 3;
604
+ else if (los_ok != NLOS) fault = 4;
605
+ put_dec(SCREEN + 80 + 17, bad, 3);
606
+ put_dec(SCREEN + 80 + 25, mismatch, 3);
607
+ put_dec(SCREEN + 80 + 33, los_ok, 1);
608
+ char code = fault ? CODE_FAIL : CODE_PASS;
609
+ RESULT = code;
610
+ vic.color_border = fault ? VCOL_RED : VCOL_GREEN;
611
+ SCREEN[80 + 37] = 0x30 + code;
612
+ SCREEN[80 + 38] = 0x30 + fault;
613
+ }
614
+ }
615
+ return 0;
616
+ }
617
+ ```
618
+
619
+ ## Build
620
+
621
+ ```bash
622
+ oscar64 -tm=c64 -O2 -o=nav-area-pathfinding.prg nav-area-pathfinding.c
623
+ ```
624
+
625
+ Oscar64 1.32.271 builds it with no warnings; the PRG is 5,521 bytes.
626
+
627
+ The reference table and the step and query counts come from this
628
+ script (Python 3). It reads the same map with the same link rules but
629
+ finds route costs by Floyd-Warshall, so a fault in the listing's
630
+ Dijkstra search shows as a table mismatch. It prints `12 areas, 43
631
+ links`, the twelve rows of `exp_next` and `steps 299 queries 160 end
632
+ (38, 20) trail cells 156`.
633
+
634
+ ```python
635
+ # nav_model.py: the reference for nav-area-pathfinding.c. Same map and
636
+ # link rules; route costs by Floyd-Warshall instead of Dijkstra. Prints
637
+ # the exp_next table and the step and query counts the listing compiles in.
638
+ MAP = [
639
+ "........................................",
640
+ "........................................",
641
+ "........................................",
642
+ "..######H#####..........######H######...",
643
+ "........H.....................H.........",
644
+ "........H.....................H.........",
645
+ "........H.....................H.........",
646
+ "....#H######...##H####..####H###........",
647
+ ".....H...........H..........H...........",
648
+ ".....H...........H..........H...........",
649
+ ".....H...........H..........H...........",
650
+ "..#H#####H#.########......#########H##..",
651
+ "...H.....H.........................H....",
652
+ "...H.....H.........................H....",
653
+ "...H.....H.........................H....",
654
+ "...H..#########.....####H#####.....H....",
655
+ "...H....................H.....#####H....",
656
+ "...H....................H..........H....",
657
+ "...H....................H..........H....",
658
+ "...H....................H..........H....",
659
+ "...H....................H..........H....",
660
+ "########################################",
661
+ ]
662
+ W, H = 40, len(MAP)
663
+ WALK, DROP, JUMP, LADDER = range(4)
664
+
665
+ def t(y, x):
666
+ if x < 0 or x >= W or y < 0:
667
+ return '.'
668
+ return '#' if y >= H else MAP[y][x]
669
+
670
+ def standable(y, x):
671
+ if not (0 <= y < H - 1 and 0 <= x < W) or t(y, x) == '#':
672
+ return False
673
+ return t(y + 1, x) == '#' or (t(y + 1, x) == 'H' and t(y, x) != 'H')
674
+
675
+ areas, area_at = [], {}
676
+ for y in range(H):
677
+ x = 0
678
+ while x < W:
679
+ if not standable(y, x):
680
+ x += 1
681
+ continue
682
+ x0 = x
683
+ while x < W and standable(y, x):
684
+ area_at[(y, x)] = len(areas)
685
+ x += 1
686
+ areas.append((y, x0, x - 1))
687
+
688
+ def fall_from(y, x):
689
+ if not 0 <= x < W or t(y, x) != '.':
690
+ return None
691
+ while not standable(y, x):
692
+ y += 1
693
+ if y >= H - 1 or t(y, x) != '.':
694
+ return None
695
+ return y
696
+
697
+ links = [] # (from, to, type, sx, ex, ey, cost)
698
+ for a, (y, x0, x1) in enumerate(areas):
699
+ for sx, d in ((x1, 1), (x0, -1)):
700
+ x = sx + d
701
+ land = fall_from(y, x)
702
+ if land is not None and land > y:
703
+ b = area_at[(land, x)]
704
+ if land == y + 1:
705
+ links += [(a, b, WALK, sx, x, land, 1), (b, a, WALK, x, sx, y, 1)]
706
+ else:
707
+ links.append((a, b, DROP, sx, x, land, land - y + 1))
708
+ if d == 1:
709
+ for gap in (1, 2):
710
+ bx = x1 + gap + 1
711
+ if (y, bx) in area_at and all(t(y - 1, i) == '.' for i in range(x1, bx + 1)) \
712
+ and all(t(y, i) == '.' for i in range(x1 + 1, bx)):
713
+ b = area_at[(y, bx)]
714
+ links += [(a, b, JUMP, x1, bx, y, gap + 2), (b, a, JUMP, bx, x1, y, gap + 2)]
715
+ break
716
+ for x in range(x0, x1 + 1):
717
+ if t(y + 1, x) == 'H':
718
+ yb = y + 1
719
+ while t(yb + 1, x) == 'H':
720
+ yb += 1
721
+ if (yb, x) in area_at:
722
+ b = area_at[(yb, x)]
723
+ links += [(a, b, LADDER, x, x, yb, yb - y), (b, a, LADDER, x, x, y, yb - y)]
724
+
725
+ N, INF = len(areas), 255
726
+ dist = [[0 if i == j else INF for j in range(N)] for i in range(N)]
727
+ for f, to, *_, c in links:
728
+ dist[f][to] = min(dist[f][to], c)
729
+ for k in range(N):
730
+ for i in range(N):
731
+ for j in range(N):
732
+ dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
733
+ nextlink = [[next((li for li, l in enumerate(links) if l[0] == i and dist[l[1]][j] < INF
734
+ and l[6] + dist[l[1]][j] == dist[i][j]), 255) if i != j else 255
735
+ for j in range(N)] for i in range(N)]
736
+
737
+ def step(tr, cx, cy):
738
+ ty, sx, ex, ey = tr
739
+ d = (ex > sx) - (ex < sx)
740
+ if ty == WALK:
741
+ return ex, ey
742
+ if ty == LADDER:
743
+ return cx, cy + (1 if ey > cy else -1)
744
+ if ty == DROP:
745
+ return (ex, cy) if cx != ex else (cx, cy + 1)
746
+ if cy == ey and cx == sx: # jump: up and over, across, down
747
+ return cx + d, cy - 1
748
+ return (cx + d, cy) if cx != ex else (cx, cy + 1)
749
+
750
+ def sim(start=(1, 20), wps=((34, 2), (4, 20), (32, 15), (10, 2), (13, 10), (7, 14), (26, 6), (38, 20))):
751
+ (cx, cy), wp, tr = start, 0, None
752
+ trail, steps, queries = {start}, 0, 0
753
+ while True:
754
+ px, py = wps[wp]
755
+ if tr:
756
+ cx, cy = step(tr, cx, cy)
757
+ elif area_at[(cy, cx)] == area_at[(py, px)]:
758
+ cx += (px > cx) - (px < cx)
759
+ else:
760
+ queries += 1
761
+ _, _, ty, sx, ex, ey, _ = links[nextlink[area_at[(cy, cx)]][area_at[(py, px)]]]
762
+ if cx != sx:
763
+ cx += (sx > cx) - (sx < cx)
764
+ else:
765
+ tr = (ty, sx, ex, ey)
766
+ cx, cy = step(tr, cx, cy)
767
+ if tr and (cx, cy) == tr[2:]:
768
+ tr = None
769
+ steps += 1
770
+ trail.add((cx, cy))
771
+ if not tr and (cx, cy) == (px, py):
772
+ wp += 1
773
+ if wp == len(wps):
774
+ return trail, steps, queries, (cx, cy)
775
+
776
+ if __name__ == '__main__':
777
+ print(N, 'areas,', len(links), 'links')
778
+ for i in range(N):
779
+ print(', '.join('%3d' % (links[nextlink[i][j]][1] if nextlink[i][j] != 255 else 255)
780
+ for j in range(N)) + ',')
781
+ trail, steps, queries, end = sim()
782
+ print('steps', steps, 'queries', queries, 'end', end, 'trail cells', len(trail))
783
+ ```
784
+
785
+ ## Expected output
786
+
787
+ Black background. Rows 0 to 2 are the HUD. Below them the level: green
788
+ platforms, orange ladders (`H`), a cyan trail of dots over every cell
789
+ the chaser passed through (ladder cells it climbed turn cyan), and the
790
+ chaser, a white ball, at the bottom right on column 38 of screen row 23.
791
+ The player marker (a yellow heart) is under the chaser at the end, so it
792
+ does not show.
793
+
794
+ The route uses all four link types: 138 of the 160 queries chose a
795
+ ladder, 9 a walk (the one-row step between the platform at map row 14
796
+ and the one at row 15), 7 a jump and 6 a drop (counted by the model).
797
+
798
+ HUD at 26,000,000 cycles (measured in VICE x64sc 3.10, decoded against
799
+ the character ROM):
800
+
801
+ | Row | PAL | NTSC |
802
+ |---|---|---|
803
+ | 0 | `BUILD 0703502 SEARCH 016061 N 12 43` | `BUILD 0709939 SEARCH 016134 N 12 43` |
804
+ | 1 | `QRY 00154 LOS 00369 AR 407948 NX 105602` | `QRY 00154 LOS 00369 AR 411726 NX 106063` |
805
+ | 2 | `ST 299 Q 160 BAD 000 MIS 000 LOS 4 R 10` | same |
806
+
807
+ `BUILD` is the whole start-up in cycles; `SEARCH` the worst of the
808
+ twelve single-destination searches; `AR` the area and link pass; `NX`
809
+ the next-hop pass. `QRY` and `LOS` are the worst query and the worst
810
+ ray step over the run. `ST` and `Q` are chaser steps and table queries,
811
+ equal to the model's 299 and 160. `BAD` counts hops that differed from
812
+ the compiled table, `MIS` table entries that differed, `LOS 4` the four
813
+ ray tests that gave the expected answer, `R 10` result code 1, fault 0.
814
+ The border is green: (98, 213, 50) on PAL, (114, 189, 103) on NTSC.
815
+
816
+ The build differs between models because the screen is on while it
817
+ runs. The 25 badlines of a frame steal the same cycles on both models,
818
+ a larger share of NTSC's 17,095-cycle frame than of PAL's 19,656, and
819
+ the CIA counts the stolen cycles (arithmetic, rung 3; not separated by
820
+ measurement here). The per-frame figures are identical because
821
+ they run after `vic_waitFrame()` returns, in the vertical blank. The
822
+ empty timer pair reads 5 cycles and the chained pair 17 (measured in a
823
+ separate build); the figures include them.
824
+
825
+ Screenshots at 26,000,000 cycles, both after the verdict and each
826
+ identical over two runs: `screenshots/nav-area-pathfinding.png` (PAL)
827
+ and `screenshots/nav-area-pathfinding-ntsc.png` (NTSC). Measured on both
828
+ with PIL: every map cell holding a cyan pixel, plus the one holding
829
+ white, is the set of cells the model's chaser visited, 156 cells with
830
+ none missing and none extra, and the white cell is (38, 20) in map
831
+ coordinates, the model's end position. The script:
832
+
833
+ ```python
834
+ from PIL import Image
835
+ import nav_model
836
+ def visited(png, ntsc):
837
+ cyan = (138, 230, 203) if ntsc else (126, 243, 214)
838
+ top = 23 if ntsc else 35 # PNG row of text row 0
839
+ px = Image.open(png).convert('RGB').load()
840
+ cells = set()
841
+ for y in range(22): # map row y is screen row y + 3
842
+ for x in range(40):
843
+ cols = {px[32 + 8 * x + i, top + 8 * (y + 3) + j]
844
+ for i in range(8) for j in range(8)}
845
+ if cyan in cols or (255, 255, 255) in cols:
846
+ cells.add((x, y))
847
+ return cells
848
+ assert visited('nav-area-pathfinding.png', False) == nav_model.sim()[0]
849
+ ```
850
+
851
+ ## Why this works
852
+
853
+ The area graph is small because a platform game's walkable space is
854
+ mostly runs of floor. Twelve areas replace 880 map cells, so a search
855
+ touches twelve nodes and 43 links instead of hundreds of cells, and a
856
+ table of every answer is 144 bytes (the listing pads the stride to 16,
857
+ 256 bytes, so the index is one table multiply). A standing actor then needs two
858
+ cell lookups and one table read per decision, 154 cycles here, where
859
+ one run-time search costs about 16,000. The build runs once at level
860
+ load, about 36 PAL frames here, most of it the cell-by-cell area pass.
861
+
862
+ The link rules carry the movement model. An area's end cell leads to a
863
+ fall; a one-row fall is a walk both ways, a longer one a one-way drop.
864
+ A gap of one or two cells to an area on the same row is a jump both
865
+ ways. A ladder joins the area over its top rung to the area at its
866
+ foot. The actor walks inside its area to the link's start cell and then
867
+ plays the link cell by cell, so the route chosen at the area level is
868
+ the route drawn on screen.
869
+
870
+ Link costs count cells moved during the link only; walking inside an
871
+ area is free to the search. That keeps the table exact for the graph
872
+ but lets a route cross a wide platform to save one cell of ladder. A
873
+ game that cares adds the walk from entry to exit, which needs areas
874
+ split at link points. The lowest-numbered link on a shortest route
875
+ breaks ties, the same rule in C and Python, so the two tables agree
876
+ byte for byte.
877
+
878
+ The line-of-sight ray steps one cell per call through the map and stops
879
+ at the first solid cell or the target. Spread over frames, one ray step
880
+ costs at most 369 cycles; the test pairs are straight rows and columns,
881
+ whose answer does not depend on the line algorithm.