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.
- package/CHANGELOG.md +2082 -0
- package/LICENSE +29 -0
- package/README.md +559 -0
- package/VERSION +25 -0
- package/dist/cli/setup.js +66 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli-memorize-audit.js +97 -0
- package/dist/cli-memorize-audit.js.map +1 -0
- package/dist/cli.js +335 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +83 -0
- package/dist/config.js.map +1 -0
- package/dist/context.js +53 -0
- package/dist/context.js.map +1 -0
- package/dist/domain/budget-notes.js +104 -0
- package/dist/domain/budget-notes.js.map +1 -0
- package/dist/domain/budget.js +417 -0
- package/dist/domain/budget.js.map +1 -0
- package/dist/domain/game-design.js +77 -0
- package/dist/domain/game-design.js.map +1 -0
- package/dist/domain/timing.js +39 -0
- package/dist/domain/timing.js.map +1 -0
- package/dist/graph/apply.js +132 -0
- package/dist/graph/apply.js.map +1 -0
- package/dist/graph/claims.js +231 -0
- package/dist/graph/claims.js.map +1 -0
- package/dist/graph/extract/archetype.js +118 -0
- package/dist/graph/extract/archetype.js.map +1 -0
- package/dist/graph/extract/common.js +69 -0
- package/dist/graph/extract/common.js.map +1 -0
- package/dist/graph/extract/failure.js +37 -0
- package/dist/graph/extract/failure.js.map +1 -0
- package/dist/graph/extract/game-design.js +189 -0
- package/dist/graph/extract/game-design.js.map +1 -0
- package/dist/graph/extract/hardware.js +124 -0
- package/dist/graph/extract/hardware.js.map +1 -0
- package/dist/graph/extract/pitfall.js +62 -0
- package/dist/graph/extract/pitfall.js.map +1 -0
- package/dist/graph/extract/raster-band.js +56 -0
- package/dist/graph/extract/raster-band.js.map +1 -0
- package/dist/graph/extract/recipe.js +71 -0
- package/dist/graph/extract/recipe.js.map +1 -0
- package/dist/graph/extract/technique-entities.js +180 -0
- package/dist/graph/extract/technique-entities.js.map +1 -0
- package/dist/graph/extract/technique.js +179 -0
- package/dist/graph/extract/technique.js.map +1 -0
- package/dist/graph/extract/toolchain.js +67 -0
- package/dist/graph/extract/toolchain.js.map +1 -0
- package/dist/graph/extract/types.js +3 -0
- package/dist/graph/extract/types.js.map +1 -0
- package/dist/graph/extract/vocabulary.js +65 -0
- package/dist/graph/extract/vocabulary.js.map +1 -0
- package/dist/graph/extract.js +43 -0
- package/dist/graph/extract.js.map +1 -0
- package/dist/graph/kernal-clobbers.js +64 -0
- package/dist/graph/kernal-clobbers.js.map +1 -0
- package/dist/graph/machine-variants.js +208 -0
- package/dist/graph/machine-variants.js.map +1 -0
- package/dist/ingest/files.js +99 -0
- package/dist/ingest/files.js.map +1 -0
- package/dist/ingest/passes.js +104 -0
- package/dist/ingest/passes.js.map +1 -0
- package/dist/ingest/points.js +50 -0
- package/dist/ingest/points.js.map +1 -0
- package/dist/ingest/report.js +140 -0
- package/dist/ingest/report.js.map +1 -0
- package/dist/ingest/tally.js +81 -0
- package/dist/ingest/tally.js.map +1 -0
- package/dist/ingest/verified-on.js +43 -0
- package/dist/ingest/verified-on.js.map +1 -0
- package/dist/ingest.js +135 -0
- package/dist/ingest.js.map +1 -0
- package/dist/schemas/cost-basis.js +5 -0
- package/dist/schemas/cost-basis.js.map +1 -0
- package/dist/schemas/machine-variant.js +25 -0
- package/dist/schemas/machine-variant.js.map +1 -0
- package/dist/schemas/plan-budget.js +121 -0
- package/dist/schemas/plan-budget.js.map +1 -0
- package/dist/schemas/tool-outputs.js +526 -0
- package/dist/schemas/tool-outputs.js.map +1 -0
- package/dist/server/define-tool.js +52 -0
- package/dist/server/define-tool.js.map +1 -0
- package/dist/server/defined-only.js +9 -0
- package/dist/server/defined-only.js.map +1 -0
- package/dist/server/tools-briefings.js +70 -0
- package/dist/server/tools-briefings.js.map +1 -0
- package/dist/server/tools-lookup.js +180 -0
- package/dist/server/tools-lookup.js.map +1 -0
- package/dist/server/tools-maintenance.js +116 -0
- package/dist/server/tools-maintenance.js.map +1 -0
- package/dist/server/tools-pitfalls.js +89 -0
- package/dist/server/tools-pitfalls.js.map +1 -0
- package/dist/server/tools-recipes.js +296 -0
- package/dist/server/tools-recipes.js.map +1 -0
- package/dist/server/tools-runtime.js +48 -0
- package/dist/server/tools-runtime.js.map +1 -0
- package/dist/server/tools.js +43 -0
- package/dist/server/tools.js.map +1 -0
- package/dist/server.js +95 -0
- package/dist/server.js.map +1 -0
- package/dist/services/analytics/schema.js +78 -0
- package/dist/services/analytics/schema.js.map +1 -0
- package/dist/services/analytics/statements.js +99 -0
- package/dist/services/analytics/statements.js.map +1 -0
- package/dist/services/analytics.js +195 -0
- package/dist/services/analytics.js.map +1 -0
- package/dist/services/bm25.js +158 -0
- package/dist/services/bm25.js.map +1 -0
- package/dist/services/chunker.js +81 -0
- package/dist/services/chunker.js.map +1 -0
- package/dist/services/embeddings.js +58 -0
- package/dist/services/embeddings.js.map +1 -0
- package/dist/services/falkor/base.js +85 -0
- package/dist/services/falkor/base.js.map +1 -0
- package/dist/services/falkor/links.js +361 -0
- package/dist/services/falkor/links.js.map +1 -0
- package/dist/services/falkor/nodes.js +183 -0
- package/dist/services/falkor/nodes.js.map +1 -0
- package/dist/services/falkor/params.js +45 -0
- package/dist/services/falkor/params.js.map +1 -0
- package/dist/services/falkor/schema.js +77 -0
- package/dist/services/falkor/schema.js.map +1 -0
- package/dist/services/falkor.js +100 -0
- package/dist/services/falkor.js.map +1 -0
- package/dist/services/qdrant.js +238 -0
- package/dist/services/qdrant.js.map +1 -0
- package/dist/services/versions.js +73 -0
- package/dist/services/versions.js.map +1 -0
- package/dist/services/vice-bin.js +51 -0
- package/dist/services/vice-bin.js.map +1 -0
- package/dist/tools/briefings/archetype.js +174 -0
- package/dist/tools/briefings/archetype.js.map +1 -0
- package/dist/tools/briefings/budget.js +177 -0
- package/dist/tools/briefings/budget.js.map +1 -0
- package/dist/tools/briefings/build-order.js +135 -0
- package/dist/tools/briefings/build-order.js.map +1 -0
- package/dist/tools/briefings/build.js +185 -0
- package/dist/tools/briefings/build.js.map +1 -0
- package/dist/tools/briefings/discovery.js +290 -0
- package/dist/tools/briefings/discovery.js.map +1 -0
- package/dist/tools/briefings/plan-pitfalls.js +69 -0
- package/dist/tools/briefings/plan-pitfalls.js.map +1 -0
- package/dist/tools/briefings/render.js +151 -0
- package/dist/tools/briefings/render.js.map +1 -0
- package/dist/tools/briefings/rows.js +41 -0
- package/dist/tools/briefings/rows.js.map +1 -0
- package/dist/tools/briefings/toolchain.js +63 -0
- package/dist/tools/briefings/toolchain.js.map +1 -0
- package/dist/tools/briefings/why-proposed.js +69 -0
- package/dist/tools/briefings/why-proposed.js.map +1 -0
- package/dist/tools/briefings.js +44 -0
- package/dist/tools/briefings.js.map +1 -0
- package/dist/tools/feedback.js +97 -0
- package/dist/tools/feedback.js.map +1 -0
- package/dist/tools/hydrate.js +75 -0
- package/dist/tools/hydrate.js.map +1 -0
- package/dist/tools/intelligence.js +67 -0
- package/dist/tools/intelligence.js.map +1 -0
- package/dist/tools/lint/asm-decimal.js +86 -0
- package/dist/tools/lint/asm-decimal.js.map +1 -0
- package/dist/tools/lint/asm-rules.js +221 -0
- package/dist/tools/lint/asm-rules.js.map +1 -0
- package/dist/tools/lint/asm-shared.js +3 -0
- package/dist/tools/lint/asm-shared.js.map +1 -0
- package/dist/tools/lint/c-rules.js +215 -0
- package/dist/tools/lint/c-rules.js.map +1 -0
- package/dist/tools/lint/text.js +122 -0
- package/dist/tools/lint/text.js.map +1 -0
- package/dist/tools/lint/types.js +40 -0
- package/dist/tools/lint/types.js.map +1 -0
- package/dist/tools/lint.js +76 -0
- package/dist/tools/lint.js.map +1 -0
- package/dist/tools/memorization-mcp.js +111 -0
- package/dist/tools/memorization-mcp.js.map +1 -0
- package/dist/tools/pitfalls/bm25.js +53 -0
- package/dist/tools/pitfalls/bm25.js.map +1 -0
- package/dist/tools/pitfalls/format.js +58 -0
- package/dist/tools/pitfalls/format.js.map +1 -0
- package/dist/tools/pitfalls/graph.js +124 -0
- package/dist/tools/pitfalls/graph.js.map +1 -0
- package/dist/tools/pitfalls.js +134 -0
- package/dist/tools/pitfalls.js.map +1 -0
- package/dist/tools/prompts.js +81 -0
- package/dist/tools/prompts.js.map +1 -0
- package/dist/tools/query/compatibility/closure.js +62 -0
- package/dist/tools/query/compatibility/closure.js.map +1 -0
- package/dist/tools/query/compatibility/facts.js +28 -0
- package/dist/tools/query/compatibility/facts.js.map +1 -0
- package/dist/tools/query/compatibility/fetch.js +164 -0
- package/dist/tools/query/compatibility/fetch.js.map +1 -0
- package/dist/tools/query/compatibility/hard-rules.js +159 -0
- package/dist/tools/query/compatibility/hard-rules.js.map +1 -0
- package/dist/tools/query/compatibility/index.js +27 -0
- package/dist/tools/query/compatibility/index.js.map +1 -0
- package/dist/tools/query/compatibility/kernal-zp-rule.js +90 -0
- package/dist/tools/query/compatibility/kernal-zp-rule.js.map +1 -0
- package/dist/tools/query/compatibility/render.js +106 -0
- package/dist/tools/query/compatibility/render.js.map +1 -0
- package/dist/tools/query/compatibility/rules.js +337 -0
- package/dist/tools/query/compatibility/rules.js.map +1 -0
- package/dist/tools/query/compatibility/unit-rules.js +253 -0
- package/dist/tools/query/compatibility/unit-rules.js.map +1 -0
- package/dist/tools/query/game-design.js +83 -0
- package/dist/tools/query/game-design.js.map +1 -0
- package/dist/tools/query/lookups.js +220 -0
- package/dist/tools/query/lookups.js.map +1 -0
- package/dist/tools/query/plan-budget.js +266 -0
- package/dist/tools/query/plan-budget.js.map +1 -0
- package/dist/tools/query/recipes.js +214 -0
- package/dist/tools/query/recipes.js.map +1 -0
- package/dist/tools/query/retrieval.js +128 -0
- package/dist/tools/query/retrieval.js.map +1 -0
- package/dist/tools/query/shared.js +121 -0
- package/dist/tools/query/shared.js.map +1 -0
- package/dist/tools/query/techniques.js +331 -0
- package/dist/tools/query/techniques.js.map +1 -0
- package/dist/tools/query/timing.js +106 -0
- package/dist/tools/query/timing.js.map +1 -0
- package/dist/tools/query/types.js +11 -0
- package/dist/tools/query/types.js.map +1 -0
- package/dist/tools/query.js +21 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/tools/resources.js +186 -0
- package/dist/tools/resources.js.map +1 -0
- package/dist/tools/run-game.js +249 -0
- package/dist/tools/run-game.js.map +1 -0
- package/dist/tools/selfimprovement.js +367 -0
- package/dist/tools/selfimprovement.js.map +1 -0
- package/docker-compose.yml +35 -0
- package/docs/ARCHITECTURE.md +164 -0
- package/docs/CONVENTIONS-archetypes.md +158 -0
- package/docs/CONVENTIONS-failures.md +46 -0
- package/docs/CONVENTIONS-game-designs.md +75 -0
- package/docs/CONVENTIONS-hardware-reference.md +184 -0
- package/docs/CONVENTIONS-pitfalls.md +91 -0
- package/docs/CONVENTIONS-recipes.md +106 -0
- package/docs/CONVENTIONS-techniques.md +309 -0
- package/docs/CONVENTIONS-toolchain-reference.md +89 -0
- package/docs/ONTOLOGY.md +655 -0
- package/docs/art/art-production-reference.md +157 -0
- package/docs/art/asset-pipelines.md +586 -0
- package/docs/c64-failure-patterns.md +693 -0
- package/docs/demo-design/demo-composition.md +349 -0
- package/docs/demo-design/demo-design-philosophy.md +320 -0
- package/docs/demo-design/intro-cracktro-patterns.md +435 -0
- package/docs/figures/ctm-spd-embed-probe.png +0 -0
- package/docs/figures/dot-flag-mid-5000000.png +0 -0
- package/docs/figures/dot-flag-no-erase-12000000.png +0 -0
- package/docs/figures/edges.json +1 -0
- package/docs/figures/fig6-architecture.png +0 -0
- package/docs/figures/fig7-ontology.png +0 -0
- package/docs/figures/screen-dissolve-mid-frame25.png +0 -0
- package/docs/figures/screen-dissolve-wipe-frame25.png +0 -0
- package/docs/figures/spindle-two-parts-part1.png +0 -0
- package/docs/figures/spindle-two-parts-part2.png +0 -0
- package/docs/figures/starters/action-puzzle.png +0 -0
- package/docs/figures/starters/adventure.png +0 -0
- package/docs/figures/starters/beat-em-up.png +0 -0
- package/docs/figures/starters/demo.png +0 -0
- package/docs/figures/starters/platformer.png +0 -0
- package/docs/figures/starters/shmup-vertical.png +0 -0
- package/docs/figures/tape-kernal-master-ntsc.png +0 -0
- package/docs/figures/tape-kernal-master-pal.png +0 -0
- package/docs/figures/tape-turbo-loader-ntsc.png +0 -0
- package/docs/figures/tape-turbo-loader-pal.png +0 -0
- package/docs/figures/tape-turbo-master-ntsc.png +0 -0
- package/docs/figures/tape-turbo-master-pal.png +0 -0
- package/docs/figures/tech-tech-pad2-12000000.png +0 -0
- package/docs/figures/tech-tech-pad4-12000000.png +0 -0
- package/docs/figures/tech-tech-seven-12000000.png +0 -0
- package/docs/figures/twister-mid-5000000.png +0 -0
- package/docs/figures/twister-straight-12000000.png +0 -0
- package/docs/figures/vector-balls-nosort-ntsc.png +0 -0
- package/docs/figures/vector-balls-nosort.png +0 -0
- package/docs/formats/c64-file-formats.md +1212 -0
- package/docs/formats/iec-disk-reference.md +754 -0
- package/docs/game-design/c64-game-archetypes.md +273 -0
- package/docs/game-design/designs/falling-blocks.md +54 -0
- package/docs/game-design/designs/platformer-scaffold.md +48 -0
- package/docs/game-design/designs/simple-shmup.md +27 -0
- package/docs/game-design/enemy-behaviour-and-difficulty.md +349 -0
- package/docs/game-design/game-design-patterns.md +1189 -0
- package/docs/game-design/game-structure.md +354 -0
- package/docs/game-design/production-planning.md +349 -0
- package/docs/game-design/reference-game-sources.md +90 -0
- package/docs/hardware/6502-illegal-opcodes.md +1353 -0
- package/docs/hardware/6510-cpu-reference.md +2112 -0
- package/docs/hardware/c64-memory-map.md +3184 -0
- package/docs/hardware/c64-registers-reference.md +996 -0
- package/docs/hardware/cia-reference.md +1281 -0
- package/docs/hardware/kernal-routines-reference.md +1836 -0
- package/docs/hardware/pal-ntsc-reference.md +813 -0
- package/docs/hardware/sid-reference.md +1137 -0
- package/docs/hardware/vic-ii-reference.md +1714 -0
- package/docs/music/music-production-reference.md +403 -0
- package/docs/pitfalls/banking.md +1067 -0
- package/docs/pitfalls/cia.md +1147 -0
- package/docs/pitfalls/cpu.md +874 -0
- package/docs/pitfalls/input.md +282 -0
- package/docs/pitfalls/kernal-and-io.md +1615 -0
- package/docs/pitfalls/loader.md +1191 -0
- package/docs/pitfalls/logic.md +94 -0
- package/docs/pitfalls/maths.md +187 -0
- package/docs/pitfalls/raster-and-badline.md +721 -0
- package/docs/pitfalls/region-timing.md +660 -0
- package/docs/pitfalls/scroll.md +207 -0
- package/docs/pitfalls/sid.md +738 -0
- package/docs/pitfalls/sprite.md +979 -0
- package/docs/pitfalls/text-mode-render.md +1172 -0
- package/docs/recipes/cc65/cartridge-8k.md +398 -0
- package/docs/recipes/cc65/hello-world-conio.md +76 -0
- package/docs/recipes/cc65/memory-layout.md +312 -0
- package/docs/recipes/cc65/screenshots/README.md +14 -0
- package/docs/recipes/cc65/screenshots/cartridge-8k-ntsc.png +0 -0
- package/docs/recipes/cc65/screenshots/cartridge-8k.png +0 -0
- package/docs/recipes/cc65/screenshots/hello-world-conio.png +0 -0
- package/docs/recipes/cc65/screenshots/memory-layout-ntsc.png +0 -0
- package/docs/recipes/cc65/screenshots/memory-layout.png +0 -0
- package/docs/recipes/kickassembler/basic-float-calls.md +578 -0
- package/docs/recipes/kickassembler/basic-wedge.md +398 -0
- package/docs/recipes/kickassembler/big-font-scroller.md +620 -0
- package/docs/recipes/kickassembler/charset-copy-rom-to-ram.md +623 -0
- package/docs/recipes/kickassembler/cia-revision-detect.md +366 -0
- package/docs/recipes/kickassembler/colour-cycling.md +343 -0
- package/docs/recipes/kickassembler/colour-fade.md +303 -0
- package/docs/recipes/kickassembler/compare-16bit-signed.md +1007 -0
- package/docs/recipes/kickassembler/cracktro-template.md +526 -0
- package/docs/recipes/kickassembler/crt-banked.md +276 -0
- package/docs/recipes/kickassembler/dos-error-codes.md +466 -0
- package/docs/recipes/kickassembler/dot-flag.md +576 -0
- package/docs/recipes/kickassembler/drive-job-queue.md +667 -0
- package/docs/recipes/kickassembler/drive-via-probe.md +690 -0
- package/docs/recipes/kickassembler/dycp-scroller.md +568 -0
- package/docs/recipes/kickassembler/dypp-sprite-scroller.md +681 -0
- package/docs/recipes/kickassembler/dysp.md +670 -0
- package/docs/recipes/kickassembler/easyflash-save.md +800 -0
- package/docs/recipes/kickassembler/eight-way-scroll.md +1484 -0
- package/docs/recipes/kickassembler/file-io-roundtrip.md +546 -0
- package/docs/recipes/kickassembler/fire-effect.md +420 -0
- package/docs/recipes/kickassembler/fld.md +414 -0
- package/docs/recipes/kickassembler/fli-image.md +336 -0
- package/docs/recipes/kickassembler/four-player-read.md +672 -0
- package/docs/recipes/kickassembler/headless-verify.md +228 -0
- package/docs/recipes/kickassembler/hello-world.md +98 -0
- package/docs/recipes/kickassembler/high-score-insert.md +660 -0
- package/docs/recipes/kickassembler/hires-plot-line.md +723 -0
- package/docs/recipes/kickassembler/irq-chain.md +316 -0
- package/docs/recipes/kickassembler/irq-owns-port.md +668 -0
- package/docs/recipes/kickassembler/isometric-room.md +1145 -0
- package/docs/recipes/kickassembler/light-pen-read.md +926 -0
- package/docs/recipes/kickassembler/logic-rate-decoupling.md +670 -0
- package/docs/recipes/kickassembler/mci-interlace.md +543 -0
- package/docs/recipes/kickassembler/memory-layout.md +277 -0
- package/docs/recipes/kickassembler/mouse-1351-read.md +801 -0
- package/docs/recipes/kickassembler/nmi-timer-tick.md +562 -0
- package/docs/recipes/kickassembler/own-keyscan.md +881 -0
- package/docs/recipes/kickassembler/paddle-read.md +751 -0
- package/docs/recipes/kickassembler/palette-cells.md +219 -0
- package/docs/recipes/kickassembler/pseudo-3d-road.md +930 -0
- package/docs/recipes/kickassembler/pwm-digi.md +463 -0
- package/docs/recipes/kickassembler/raster-bars.md +264 -0
- package/docs/recipes/kickassembler/reu-dma.md +1019 -0
- package/docs/recipes/kickassembler/runtime-relocation.md +743 -0
- package/docs/recipes/kickassembler/screen-dissolve.md +545 -0
- package/docs/recipes/kickassembler/screen-wipe.md +408 -0
- package/docs/recipes/kickassembler/screenshots/README.md +72 -0
- package/docs/recipes/kickassembler/screenshots/basic-float-calls-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/basic-float-calls.png +0 -0
- package/docs/recipes/kickassembler/screenshots/basic-wedge-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/basic-wedge.png +0 -0
- package/docs/recipes/kickassembler/screenshots/big-font-scroller-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/big-font-scroller.png +0 -0
- package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram.png +0 -0
- package/docs/recipes/kickassembler/screenshots/cia-revision-detect-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/cia-revision-detect.png +0 -0
- package/docs/recipes/kickassembler/screenshots/colour-cycling-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/colour-cycling.png +0 -0
- package/docs/recipes/kickassembler/screenshots/colour-fade-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/colour-fade.png +0 -0
- package/docs/recipes/kickassembler/screenshots/compare-16bit-signed-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/compare-16bit-signed.png +0 -0
- package/docs/recipes/kickassembler/screenshots/cracktro-template.png +0 -0
- package/docs/recipes/kickassembler/screenshots/crt-banked-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/crt-banked.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dos-error-codes-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dos-error-codes.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dot-flag-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dot-flag.png +0 -0
- package/docs/recipes/kickassembler/screenshots/drive-job-queue-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/drive-job-queue.png +0 -0
- package/docs/recipes/kickassembler/screenshots/drive-via-probe-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/drive-via-probe.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dycp-scroller-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dycp-scroller.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dysp-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dysp.png +0 -0
- package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc-run2.png +0 -0
- package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/easyflash-save-run2.png +0 -0
- package/docs/recipes/kickassembler/screenshots/easyflash-save.png +0 -0
- package/docs/recipes/kickassembler/screenshots/eight-way-scroll-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/eight-way-scroll.png +0 -0
- package/docs/recipes/kickassembler/screenshots/file-io-roundtrip-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/file-io-roundtrip.png +0 -0
- package/docs/recipes/kickassembler/screenshots/fire-effect-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/fire-effect.png +0 -0
- package/docs/recipes/kickassembler/screenshots/fld-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/fld.png +0 -0
- package/docs/recipes/kickassembler/screenshots/fli-image.png +0 -0
- package/docs/recipes/kickassembler/screenshots/four-player-read-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/four-player-read.png +0 -0
- package/docs/recipes/kickassembler/screenshots/headless-verify-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/headless-verify.png +0 -0
- package/docs/recipes/kickassembler/screenshots/hello-world.png +0 -0
- package/docs/recipes/kickassembler/screenshots/high-score-insert-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/high-score-insert.png +0 -0
- package/docs/recipes/kickassembler/screenshots/hires-plot-line-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/hires-plot-line.png +0 -0
- package/docs/recipes/kickassembler/screenshots/irq-chain-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/irq-chain.png +0 -0
- package/docs/recipes/kickassembler/screenshots/irq-owns-port-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/irq-owns-port.png +0 -0
- package/docs/recipes/kickassembler/screenshots/isometric-room-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/isometric-room.png +0 -0
- package/docs/recipes/kickassembler/screenshots/light-pen-read-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/light-pen-read.png +0 -0
- package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mci-interlace-average.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mci-interlace-frame-b.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mci-interlace-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mci-interlace.png +0 -0
- package/docs/recipes/kickassembler/screenshots/memory-layout-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/memory-layout.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mouse-1351-read-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mouse-1351-read.png +0 -0
- package/docs/recipes/kickassembler/screenshots/nmi-timer-tick-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/nmi-timer-tick.png +0 -0
- package/docs/recipes/kickassembler/screenshots/own-keyscan-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/own-keyscan.png +0 -0
- package/docs/recipes/kickassembler/screenshots/paddle-read-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/paddle-read.png +0 -0
- package/docs/recipes/kickassembler/screenshots/palette-cells-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/palette-cells.png +0 -0
- package/docs/recipes/kickassembler/screenshots/pseudo-3d-road-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/pseudo-3d-road.png +0 -0
- package/docs/recipes/kickassembler/screenshots/pwm-digi-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/pwm-digi.png +0 -0
- package/docs/recipes/kickassembler/screenshots/raster-bars.png +0 -0
- package/docs/recipes/kickassembler/screenshots/reu-dma-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/reu-dma.png +0 -0
- package/docs/recipes/kickassembler/screenshots/runtime-relocation-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/runtime-relocation.png +0 -0
- package/docs/recipes/kickassembler/screenshots/screen-dissolve-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/screen-dissolve.png +0 -0
- package/docs/recipes/kickassembler/screenshots/screen-wipe-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/screen-wipe.png +0 -0
- package/docs/recipes/kickassembler/screenshots/scroll-panel-split-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/scroll-panel-split.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sfx-in-player-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sfx-in-player.png +0 -0
- package/docs/recipes/kickassembler/screenshots/shadebobs-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/shadebobs.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sideborder-open.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sine-scroller.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sine-table-runtime-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sine-table-runtime.png +0 -0
- package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted.png +0 -0
- package/docs/recipes/kickassembler/screenshots/speedcode-generator-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/speedcode-generator.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-border-scroller-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-border-scroller.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-cache-flip-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-cache-flip.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-multiplex-24.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-priority-classes-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-priority-classes.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-sine-chain-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-sine-chain.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-stretcher-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-stretcher.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprites-only-screen-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprites-only-screen.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sqrt-atan2-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sqrt-atan2.png +0 -0
- package/docs/recipes/kickassembler/screenshots/stable-raster-irq-control.png +0 -0
- package/docs/recipes/kickassembler/screenshots/stable-raster-irq.png +0 -0
- package/docs/recipes/kickassembler/screenshots/tech-tech-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/tech-tech.png +0 -0
- package/docs/recipes/kickassembler/screenshots/tod-alarm-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/tod-alarm.png +0 -0
- package/docs/recipes/kickassembler/screenshots/topbottom-border-open.png +0 -0
- package/docs/recipes/kickassembler/screenshots/twister-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/twister.png +0 -0
- package/docs/recipes/kickassembler/screenshots/unit-test-driver-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/unit-test-driver.png +0 -0
- package/docs/recipes/kickassembler/screenshots/vector-balls-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/vector-balls.png +0 -0
- package/docs/recipes/kickassembler/screenshots/wireframe-ships-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/wireframe-ships.png +0 -0
- package/docs/recipes/kickassembler/scroll-panel-split.md +381 -0
- package/docs/recipes/kickassembler/sfx-in-player.md +907 -0
- package/docs/recipes/kickassembler/shadebobs.md +522 -0
- package/docs/recipes/kickassembler/sideborder-open.md +338 -0
- package/docs/recipes/kickassembler/sine-scroller.md +321 -0
- package/docs/recipes/kickassembler/sine-table-runtime.md +815 -0
- package/docs/recipes/kickassembler/software-sprite-preshifted.md +725 -0
- package/docs/recipes/kickassembler/speedcode-generator.md +606 -0
- package/docs/recipes/kickassembler/sprite-border-scroller.md +696 -0
- package/docs/recipes/kickassembler/sprite-cache-flip.md +1071 -0
- package/docs/recipes/kickassembler/sprite-multiplex-24.md +326 -0
- package/docs/recipes/kickassembler/sprite-multiplex-game.md +986 -0
- package/docs/recipes/kickassembler/sprite-priority-classes.md +463 -0
- package/docs/recipes/kickassembler/sprite-sine-chain.md +338 -0
- package/docs/recipes/kickassembler/sprite-stretcher.md +501 -0
- package/docs/recipes/kickassembler/sprites-only-screen.md +550 -0
- package/docs/recipes/kickassembler/sqrt-atan2.md +1014 -0
- package/docs/recipes/kickassembler/stable-raster-irq.md +360 -0
- package/docs/recipes/kickassembler/tape-turbo-loader.md +875 -0
- package/docs/recipes/kickassembler/tech-tech.md +679 -0
- package/docs/recipes/kickassembler/tod-alarm.md +754 -0
- package/docs/recipes/kickassembler/topbottom-border-open.md +407 -0
- package/docs/recipes/kickassembler/twister.md +518 -0
- package/docs/recipes/kickassembler/unit-test-driver.md +314 -0
- package/docs/recipes/kickassembler/vector-balls.md +545 -0
- package/docs/recipes/kickassembler/wireframe-ships.md +2324 -0
- package/docs/recipes/oscar64/actor-activation-window.md +807 -0
- package/docs/recipes/oscar64/adventure-engine.md +1094 -0
- package/docs/recipes/oscar64/attract-replay.md +465 -0
- package/docs/recipes/oscar64/beat-em-up-lanes.md +563 -0
- package/docs/recipes/oscar64/bfs-distance-map.md +723 -0
- package/docs/recipes/oscar64/bitmap-koala-viewer.md +355 -0
- package/docs/recipes/oscar64/car-contact.md +950 -0
- package/docs/recipes/oscar64/cave-scan.md +609 -0
- package/docs/recipes/oscar64/char-bullets.md +477 -0
- package/docs/recipes/oscar64/charset-animation.md +383 -0
- package/docs/recipes/oscar64/charset-parallax.md +401 -0
- package/docs/recipes/oscar64/destructible-terrain.md +1099 -0
- package/docs/recipes/oscar64/difficulty-tables.md +654 -0
- package/docs/recipes/oscar64/dig-and-guards.md +975 -0
- package/docs/recipes/oscar64/directory-reader.md +535 -0
- package/docs/recipes/oscar64/divide-check.md +581 -0
- package/docs/recipes/oscar64/double-buffer-nomirror.md +205 -0
- package/docs/recipes/oscar64/double-buffer.md +255 -0
- package/docs/recipes/oscar64/falling-blocks.md +874 -0
- package/docs/recipes/oscar64/fixed-point-jump-velocity.md +289 -0
- package/docs/recipes/oscar64/fixed-point-jump.md +210 -0
- package/docs/recipes/oscar64/flip-screen-rooms.md +793 -0
- package/docs/recipes/oscar64/frame-sync-loop-overrun.md +214 -0
- package/docs/recipes/oscar64/frame-sync-loop.md +254 -0
- package/docs/recipes/oscar64/game-tree-search.md +743 -0
- package/docs/recipes/oscar64/ghost-targeting.md +867 -0
- package/docs/recipes/oscar64/headless-verify.md +345 -0
- package/docs/recipes/oscar64/hello-world.md +83 -0
- package/docs/recipes/oscar64/high-score-persist.md +772 -0
- package/docs/recipes/oscar64/iffl-kernal-skip.md +421 -0
- package/docs/recipes/oscar64/joystick-input.md +358 -0
- package/docs/recipes/oscar64/lane-pursuit.md +1028 -0
- package/docs/recipes/oscar64/level-rle-decoder.md +620 -0
- package/docs/recipes/oscar64/lfsr-random-seed2.md +338 -0
- package/docs/recipes/oscar64/lfsr-random.md +403 -0
- package/docs/recipes/oscar64/load-asset-runtime.md +492 -0
- package/docs/recipes/oscar64/memory-layout.md +232 -0
- package/docs/recipes/oscar64/mixed-fighters.md +781 -0
- package/docs/recipes/oscar64/multi-sprite-object.md +533 -0
- package/docs/recipes/oscar64/nav-area-pathfinding.md +881 -0
- package/docs/recipes/oscar64/object-pool.md +572 -0
- package/docs/recipes/oscar64/pal-ntsc-detect.md +257 -0
- package/docs/recipes/oscar64/password-state.md +532 -0
- package/docs/recipes/oscar64/per-frame-hitbox.md +651 -0
- package/docs/recipes/oscar64/petscii-screen-codes.md +428 -0
- package/docs/recipes/oscar64/platformer-scaffold.md +1467 -0
- package/docs/recipes/oscar64/print-number.md +367 -0
- package/docs/recipes/oscar64/raster-bars.md +239 -0
- package/docs/recipes/oscar64/raster-profile-bars.md +404 -0
- package/docs/recipes/oscar64/rel-side-sectors.md +391 -0
- package/docs/recipes/oscar64/relative-file-records.md +378 -0
- package/docs/recipes/oscar64/save-load-seq-file.md +365 -0
- package/docs/recipes/oscar64/screenshots/README.md +99 -0
- package/docs/recipes/oscar64/screenshots/actor-activation-window-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/actor-activation-window.png +0 -0
- package/docs/recipes/oscar64/screenshots/adventure-engine-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/adventure-engine.png +0 -0
- package/docs/recipes/oscar64/screenshots/attract-replay-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/attract-replay.png +0 -0
- package/docs/recipes/oscar64/screenshots/beat-em-up-lanes-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/beat-em-up-lanes.png +0 -0
- package/docs/recipes/oscar64/screenshots/bfs-distance-map-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/bfs-distance-map.png +0 -0
- package/docs/recipes/oscar64/screenshots/bitmap-koala-viewer.png +0 -0
- package/docs/recipes/oscar64/screenshots/car-contact-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/car-contact.png +0 -0
- package/docs/recipes/oscar64/screenshots/cave-scan-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/cave-scan.png +0 -0
- package/docs/recipes/oscar64/screenshots/char-bullets-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/char-bullets.png +0 -0
- package/docs/recipes/oscar64/screenshots/charset-animation-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/charset-animation.png +0 -0
- package/docs/recipes/oscar64/screenshots/charset-parallax-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/charset-parallax.png +0 -0
- package/docs/recipes/oscar64/screenshots/destructible-terrain-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/destructible-terrain.png +0 -0
- package/docs/recipes/oscar64/screenshots/difficulty-tables-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/difficulty-tables.png +0 -0
- package/docs/recipes/oscar64/screenshots/dig-and-guards-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/dig-and-guards.png +0 -0
- package/docs/recipes/oscar64/screenshots/directory-reader-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/directory-reader.png +0 -0
- package/docs/recipes/oscar64/screenshots/divide-check-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/divide-check.png +0 -0
- package/docs/recipes/oscar64/screenshots/double-buffer-nomirror.png +0 -0
- package/docs/recipes/oscar64/screenshots/double-buffer-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/double-buffer.png +0 -0
- package/docs/recipes/oscar64/screenshots/falling-blocks-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/falling-blocks.png +0 -0
- package/docs/recipes/oscar64/screenshots/fixed-point-jump-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity.png +0 -0
- package/docs/recipes/oscar64/screenshots/fixed-point-jump.png +0 -0
- package/docs/recipes/oscar64/screenshots/flip-screen-rooms-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/flip-screen-rooms.png +0 -0
- package/docs/recipes/oscar64/screenshots/frame-sync-loop-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/frame-sync-loop-overrun.png +0 -0
- package/docs/recipes/oscar64/screenshots/frame-sync-loop.png +0 -0
- package/docs/recipes/oscar64/screenshots/game-tree-search-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/game-tree-search.png +0 -0
- package/docs/recipes/oscar64/screenshots/ghost-targeting-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/ghost-targeting.png +0 -0
- package/docs/recipes/oscar64/screenshots/headless-verify-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/headless-verify.png +0 -0
- package/docs/recipes/oscar64/screenshots/hello-world.png +0 -0
- package/docs/recipes/oscar64/screenshots/high-score-persist-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/high-score-persist.png +0 -0
- package/docs/recipes/oscar64/screenshots/iffl-kernal-skip-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/iffl-kernal-skip.png +0 -0
- package/docs/recipes/oscar64/screenshots/joystick-input-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/joystick-input.png +0 -0
- package/docs/recipes/oscar64/screenshots/lane-pursuit-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/lane-pursuit.png +0 -0
- package/docs/recipes/oscar64/screenshots/level-rle-decoder-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/level-rle-decoder.png +0 -0
- package/docs/recipes/oscar64/screenshots/lfsr-random-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/lfsr-random-seed2.png +0 -0
- package/docs/recipes/oscar64/screenshots/lfsr-random.png +0 -0
- package/docs/recipes/oscar64/screenshots/load-asset-runtime-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/load-asset-runtime.png +0 -0
- package/docs/recipes/oscar64/screenshots/memory-layout-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/memory-layout.png +0 -0
- package/docs/recipes/oscar64/screenshots/mixed-fighters-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/mixed-fighters.png +0 -0
- package/docs/recipes/oscar64/screenshots/multi-sprite-object-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/multi-sprite-object.png +0 -0
- package/docs/recipes/oscar64/screenshots/nav-area-pathfinding-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/nav-area-pathfinding.png +0 -0
- package/docs/recipes/oscar64/screenshots/object-pool-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/object-pool.png +0 -0
- package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-oldntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-pal.png +0 -0
- package/docs/recipes/oscar64/screenshots/password-state-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/password-state.png +0 -0
- package/docs/recipes/oscar64/screenshots/per-frame-hitbox-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/per-frame-hitbox.png +0 -0
- package/docs/recipes/oscar64/screenshots/petscii-screen-codes-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/petscii-screen-codes.png +0 -0
- package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64.png +0 -0
- package/docs/recipes/oscar64/screenshots/platformer-scaffold-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/platformer-scaffold.png +0 -0
- package/docs/recipes/oscar64/screenshots/print-number-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/print-number.png +0 -0
- package/docs/recipes/oscar64/screenshots/raster-bars.png +0 -0
- package/docs/recipes/oscar64/screenshots/raster-profile-bars-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/raster-profile-bars.png +0 -0
- package/docs/recipes/oscar64/screenshots/rel-side-sectors-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/rel-side-sectors.png +0 -0
- package/docs/recipes/oscar64/screenshots/relative-file-records-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/relative-file-records.png +0 -0
- package/docs/recipes/oscar64/screenshots/save-load-seq-file-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/save-load-seq-file.png +0 -0
- package/docs/recipes/oscar64/screenshots/seeded-level-fill-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/seeded-level-fill.png +0 -0
- package/docs/recipes/oscar64/screenshots/sfx-engine-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/sfx-engine.png +0 -0
- package/docs/recipes/oscar64/screenshots/sid-music-player.png +0 -0
- package/docs/recipes/oscar64/screenshots/simple-shmup.png +0 -0
- package/docs/recipes/oscar64/screenshots/slope-collision-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/slope-collision.png +0 -0
- package/docs/recipes/oscar64/screenshots/soft-scroll-h.png +0 -0
- package/docs/recipes/oscar64/screenshots/sprite-animation-table-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/sprite-animation-table.png +0 -0
- package/docs/recipes/oscar64/screenshots/sprite-multiplex-8.png +0 -0
- package/docs/recipes/oscar64/screenshots/stable-raster-irq.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-input-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-input.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-overlay-playfield-gameover.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-overlay-playfield-notrail-control.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ungated-control.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-overlay-playfield.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-window-menu-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-window-menu.png +0 -0
- package/docs/recipes/oscar64/screenshots/tile-grid-collision-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/tile-grid-collision.png +0 -0
- package/docs/recipes/oscar64/screenshots/tile-map-render-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/tile-map-render.png +0 -0
- package/docs/recipes/oscar64/screenshots/two-player-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/two-player.png +0 -0
- package/docs/recipes/oscar64/screenshots/two-word-parser-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/two-word-parser.png +0 -0
- package/docs/recipes/oscar64/screenshots/vehicle-control-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/vehicle-control.png +0 -0
- package/docs/recipes/oscar64/screenshots/wave-director-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/wave-director.png +0 -0
- package/docs/recipes/oscar64/seeded-level-fill.md +364 -0
- package/docs/recipes/oscar64/sfx-engine.md +514 -0
- package/docs/recipes/oscar64/sid-music-player.md +441 -0
- package/docs/recipes/oscar64/simple-shmup.md +1000 -0
- package/docs/recipes/oscar64/slope-collision.md +610 -0
- package/docs/recipes/oscar64/soft-scroll-h.md +261 -0
- package/docs/recipes/oscar64/sprite-animation-table.md +671 -0
- package/docs/recipes/oscar64/sprite-multiplex-8.md +314 -0
- package/docs/recipes/oscar64/stable-raster-irq.md +236 -0
- package/docs/recipes/oscar64/text-input.md +274 -0
- package/docs/recipes/oscar64/text-overlay-playfield.md +617 -0
- package/docs/recipes/oscar64/text-window-menu.md +551 -0
- package/docs/recipes/oscar64/tile-grid-collision.md +563 -0
- package/docs/recipes/oscar64/tile-map-render.md +395 -0
- package/docs/recipes/oscar64/two-player.md +528 -0
- package/docs/recipes/oscar64/two-word-parser.md +510 -0
- package/docs/recipes/oscar64/vehicle-control.md +771 -0
- package/docs/recipes/oscar64/wave-director.md +787 -0
- package/docs/recipes/runs.json +1606 -0
- package/docs/runtime/sim6502-reference.md +466 -0
- package/docs/runtime/vice-mcp-reference.md +351 -0
- package/docs/runtime/vice-reference.md +1393 -0
- package/docs/techniques/bitmap-modes.md +685 -0
- package/docs/techniques/cpu-cycle-tricks.md +1570 -0
- package/docs/techniques/effects-vector-3d.md +1431 -0
- package/docs/techniques/file-io.md +1427 -0
- package/docs/techniques/input.md +1072 -0
- package/docs/techniques/loaders-packers.md +768 -0
- package/docs/techniques/logic.md +3091 -0
- package/docs/techniques/maths.md +1524 -0
- package/docs/techniques/memory-banking.md +1686 -0
- package/docs/techniques/music-sid.md +1144 -0
- package/docs/techniques/raster.md +1543 -0
- package/docs/techniques/scroll.md +1292 -0
- package/docs/techniques/sprite.md +2566 -0
- package/docs/techniques/text-mode-render.md +717 -0
- package/docs/techniques/text.md +1095 -0
- package/docs/techniques/transitions.md +405 -0
- package/docs/toolchains/cartconv-reference.md +262 -0
- package/docs/toolchains/cc1541-reference.md +316 -0
- package/docs/toolchains/cc65-reference.md +667 -0
- package/docs/toolchains/error-sources/cc65/README.md +1 -0
- package/docs/toolchains/error-sources/cc65/missing-setcpu.s +4 -0
- package/docs/toolchains/error-sources/cc65/range-error.s +4 -0
- package/docs/toolchains/error-sources/cc65/segment-overflow.c +6 -0
- package/docs/toolchains/error-sources/cc65/unresolved-external.c +6 -0
- package/docs/toolchains/error-sources/kickassembler/README.md +1 -0
- package/docs/toolchains/error-sources/kickassembler/branch-out-of-range.asm +4 -0
- package/docs/toolchains/error-sources/kickassembler/failed-assert.asm +3 -0
- package/docs/toolchains/error-sources/kickassembler/flat-lib.asm +4 -0
- package/docs/toolchains/error-sources/kickassembler/import-source-no-namespace.asm +5 -0
- package/docs/toolchains/error-sources/kickassembler/macro-without-parentheses.asm +6 -0
- package/docs/toolchains/error-sources/kickassembler/memory-block-overlap.asm +4 -0
- package/docs/toolchains/error-sources/kickassembler/symbol-clash-lib.asm +5 -0
- package/docs/toolchains/error-sources/kickassembler/symbol-clash-main.asm +6 -0
- package/docs/toolchains/error-sources/kickassembler/unknown-symbol.asm +4 -0
- package/docs/toolchains/error-sources/oscar64/README.md +1 -0
- package/docs/toolchains/error-sources/oscar64/asm-addressing-mode.c +7 -0
- package/docs/toolchains/error-sources/oscar64/region-overflow.c +6 -0
- package/docs/toolchains/error-sources/oscar64/undefined-extern-var.c +5 -0
- package/docs/toolchains/error-sources/oscar64/undefined-extern.c +6 -0
- package/docs/toolchains/error-sources/oscar64/unknown-vic-field.c +6 -0
- package/docs/toolchains/error-sources/oscar64/void-main.c +3 -0
- package/docs/toolchains/kickassembler-reference.md +1020 -0
- package/docs/toolchains/memory-layout-planning.md +362 -0
- package/docs/toolchains/oscar64-headers-reference.md +583 -0
- package/docs/toolchains/oscar64-reference.md +892 -0
- package/docs/toolchains/petcat-reference.md +290 -0
- package/docs/toolchains/png2prg.md +188 -0
- package/docs/toolchains/release-disk.md +314 -0
- package/docs/toolchains/sidreloc.md +236 -0
- package/docs/toolchains/spindle-reference.md +487 -0
- package/docs/toolchains/tape-mastering.md +592 -0
- package/docs/toolchains/unit-testing-6502.md +281 -0
- package/docs/workflow/agent-harness.md +478 -0
- package/package.json +105 -0
- package/templates/_harness/CLAUDE.md.template +91 -0
- package/templates/_harness/PLAN.md.template +72 -0
- package/templates/_harness/check.py +442 -0
- package/templates/_harness/claude/settings.json +17 -0
- package/templates/_harness/gen-asm-header.py +96 -0
- package/templates/_harness/harness.mk +273 -0
- package/templates/_harness/hooks/plan-gate.py +185 -0
- package/templates/_harness/meter/frame_meter.asm +311 -0
- package/templates/_harness/meter/frame_meter.c +155 -0
- package/templates/_harness/meter/frame_meter.h +80 -0
- package/templates/_harness/zp-used.py +104 -0
- package/templates/action-puzzle/.claude/settings.json +17 -0
- package/templates/action-puzzle/.mcp.json +10 -0
- package/templates/action-puzzle/CLAUDE.md +120 -0
- package/templates/action-puzzle/Makefile +125 -0
- package/templates/action-puzzle/PLAN.md +388 -0
- package/templates/action-puzzle/README.md +240 -0
- package/templates/action-puzzle/expect.json +25 -0
- package/templates/action-puzzle/src/cave.c +280 -0
- package/templates/action-puzzle/src/cave.h +80 -0
- package/templates/action-puzzle/src/gen_autopilot.h +20 -0
- package/templates/action-puzzle/src/gen_caves.h +59 -0
- package/templates/action-puzzle/src/gen_notes.h +16 -0
- package/templates/action-puzzle/src/hiscore.c +152 -0
- package/templates/action-puzzle/src/hiscore.h +41 -0
- package/templates/action-puzzle/src/level.c +64 -0
- package/templates/action-puzzle/src/level.h +24 -0
- package/templates/action-puzzle/src/main.c +599 -0
- package/templates/action-puzzle/src/render.c +239 -0
- package/templates/action-puzzle/src/render.h +31 -0
- package/templates/action-puzzle/src/sound.c +158 -0
- package/templates/action-puzzle/src/sound.h +22 -0
- package/templates/action-puzzle/tools/disk_check.py +77 -0
- package/templates/action-puzzle/tools/drive.py +106 -0
- package/templates/action-puzzle/tools/gen.py +454 -0
- package/templates/action-puzzle/tools/model_check.py +49 -0
- package/templates/action-puzzle/tools/verdict_codes.py +24 -0
- package/templates/adventure/.claude/settings.json +17 -0
- package/templates/adventure/.mcp.json +10 -0
- package/templates/adventure/CLAUDE.md +118 -0
- package/templates/adventure/Makefile +113 -0
- package/templates/adventure/PLAN.md +396 -0
- package/templates/adventure/README.md +277 -0
- package/templates/adventure/expect.json +25 -0
- package/templates/adventure/src/engine.c +543 -0
- package/templates/adventure/src/engine.h +48 -0
- package/templates/adventure/src/gen_script.h +141 -0
- package/templates/adventure/src/gen_world.h +511 -0
- package/templates/adventure/src/main.c +439 -0
- package/templates/adventure/src/picture.c +83 -0
- package/templates/adventure/src/picture.h +16 -0
- package/templates/adventure/src/save.c +159 -0
- package/templates/adventure/src/save.h +25 -0
- package/templates/adventure/src/sound.c +71 -0
- package/templates/adventure/src/sound.h +16 -0
- package/templates/adventure/src/text.c +349 -0
- package/templates/adventure/src/text.h +40 -0
- package/templates/adventure/tools/disk_check.py +128 -0
- package/templates/adventure/tools/drive.py +119 -0
- package/templates/adventure/tools/gen.py +1033 -0
- package/templates/adventure/tools/world.py +356 -0
- package/templates/beat-em-up/.claude/settings.json +17 -0
- package/templates/beat-em-up/.mcp.json +10 -0
- package/templates/beat-em-up/CLAUDE.md +136 -0
- package/templates/beat-em-up/Makefile +96 -0
- package/templates/beat-em-up/PLAN.md +502 -0
- package/templates/beat-em-up/README.md +315 -0
- package/templates/beat-em-up/expect-gameover.json +8 -0
- package/templates/beat-em-up/expect.json +29 -0
- package/templates/beat-em-up/src/anim.c +70 -0
- package/templates/beat-em-up/src/art.c +344 -0
- package/templates/beat-em-up/src/autopilot.h +154 -0
- package/templates/beat-em-up/src/brute.c +273 -0
- package/templates/beat-em-up/src/enemy.c +281 -0
- package/templates/beat-em-up/src/engine.asm +512 -0
- package/templates/beat-em-up/src/fighter.c +384 -0
- package/templates/beat-em-up/src/game.h +269 -0
- package/templates/beat-em-up/src/hud.c +135 -0
- package/templates/beat-em-up/src/main.c +341 -0
- package/templates/beat-em-up/src/sound.c +44 -0
- package/templates/beat-em-up/src/street.c +93 -0
- package/templates/beat-em-up/src/verdict.h +523 -0
- package/templates/beat-em-up/src/view.c +362 -0
- package/templates/beat-em-up/tools/drive.py +105 -0
- package/templates/beat-em-up/tools/flickercheck.py +273 -0
- package/templates/demo/.claude/settings.json +17 -0
- package/templates/demo/.mcp.json +10 -0
- package/templates/demo/CLAUDE.md +129 -0
- package/templates/demo/Makefile +66 -0
- package/templates/demo/PLAN.md +401 -0
- package/templates/demo/README.md +322 -0
- package/templates/demo/expect.json +945 -0
- package/templates/demo/src/config.asm +80 -0
- package/templates/demo/src/framework.asm +390 -0
- package/templates/demo/src/main.asm +139 -0
- package/templates/demo/src/music.asm +197 -0
- package/templates/demo/src/part_main.asm +279 -0
- package/templates/demo/src/part_title.asm +79 -0
- package/templates/demo/src/parts.asm +43 -0
- package/templates/demo/src/tables.asm +73 -0
- package/templates/demo/src/verdict.asm +179 -0
- package/templates/demo/tools/audio.py +80 -0
- package/templates/demo/tools/gen_expect.py +167 -0
- package/templates/demo/tools/probe.py +95 -0
- package/templates/hello/.claude/settings.json +17 -0
- package/templates/hello/.mcp.json +10 -0
- package/templates/hello/CLAUDE.md +100 -0
- package/templates/hello/Makefile +38 -0
- package/templates/hello/PLAN.md +200 -0
- package/templates/hello/expect.json +20 -0
- package/templates/hello/src/main.c +161 -0
- package/templates/hello/src/sprite.asm +27 -0
- package/templates/hello-kick/.claude/settings.json +17 -0
- package/templates/hello-kick/.mcp.json +10 -0
- package/templates/hello-kick/CLAUDE.md +100 -0
- package/templates/hello-kick/Makefile +17 -0
- package/templates/hello-kick/PLAN.md +199 -0
- package/templates/hello-kick/expect.json +20 -0
- package/templates/hello-kick/src/main.asm +233 -0
- package/templates/platformer/.claude/settings.json +17 -0
- package/templates/platformer/.mcp.json +10 -0
- package/templates/platformer/CLAUDE.md +125 -0
- package/templates/platformer/Makefile +86 -0
- package/templates/platformer/PLAN.md +360 -0
- package/templates/platformer/README.md +277 -0
- package/templates/platformer/expect.json +32 -0
- package/templates/platformer/src/actors.c +289 -0
- package/templates/platformer/src/anim.c +51 -0
- package/templates/platformer/src/art.c +212 -0
- package/templates/platformer/src/autopilot.h +30 -0
- package/templates/platformer/src/engine.asm +253 -0
- package/templates/platformer/src/game.h +248 -0
- package/templates/platformer/src/hud.c +90 -0
- package/templates/platformer/src/level.c +184 -0
- package/templates/platformer/src/main.c +306 -0
- package/templates/platformer/src/player.c +268 -0
- package/templates/platformer/src/sound.c +42 -0
- package/templates/platformer/src/verdict.h +206 -0
- package/templates/platformer/src/view.c +331 -0
- package/templates/platformer/stage-expect.json +6 -0
- package/templates/platformer/tools/drive.py +112 -0
- package/templates/platformer/tools/tearcheck.py +229 -0
- package/templates/shmup-vertical/.claude/settings.json +17 -0
- package/templates/shmup-vertical/.mcp.json +10 -0
- package/templates/shmup-vertical/CLAUDE.md +137 -0
- package/templates/shmup-vertical/Makefile +131 -0
- package/templates/shmup-vertical/PLAN.md +569 -0
- package/templates/shmup-vertical/README.md +189 -0
- package/templates/shmup-vertical/expect.json +38 -0
- package/templates/shmup-vertical/src/bullets.c +158 -0
- package/templates/shmup-vertical/src/bullets.h +35 -0
- package/templates/shmup-vertical/src/display.c +239 -0
- package/templates/shmup-vertical/src/display.h +40 -0
- package/templates/shmup-vertical/src/game.h +85 -0
- package/templates/shmup-vertical/src/glyph.asm +358 -0
- package/templates/shmup-vertical/src/hiscore.c +141 -0
- package/templates/shmup-vertical/src/hiscore.h +16 -0
- package/templates/shmup-vertical/src/hit.asm +180 -0
- package/templates/shmup-vertical/src/hitbox.c +59 -0
- package/templates/shmup-vertical/src/hitbox.h +25 -0
- package/templates/shmup-vertical/src/kernel.asm +330 -0
- package/templates/shmup-vertical/src/level.c +174 -0
- package/templates/shmup-vertical/src/level.h +27 -0
- package/templates/shmup-vertical/src/main.c +824 -0
- package/templates/shmup-vertical/src/mux.asm +321 -0
- package/templates/shmup-vertical/src/sound.asm +255 -0
- package/templates/shmup-vertical/src/step.asm +169 -0
- package/templates/shmup-vertical/src/waves.c +195 -0
- package/templates/shmup-vertical/src/waves.h +33 -0
- package/templates/shmup-vertical/stage-expect.json +6 -0
- package/templates/shmup-vertical/tools/drive.py +152 -0
- package/templates/shmup-vertical/tools/joytest.py +159 -0
- package/templates/shmup-vertical/tools/meter.py +15 -0
- package/templates/shmup-vertical/tools/phases.py +73 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# action-puzzle: CAVE RUN
|
|
2
|
+
|
|
3
|
+
A Boulder Dash-style cave game for a stock C64, PAL and NTSC, in Oscar64 C.
|
|
4
|
+
Copy it to start a game of this kind:
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm run new-project -- action-puzzle ~/c64/mygame # in c64-kb
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
The player digs through earth. Boulders and gems fall and roll. Sparks keep
|
|
11
|
+
a wall on their left, moths a wall on their right; either explodes when the
|
|
12
|
+
player is next to it, and a moth crushed by a boulder bursts into gems.
|
|
13
|
+
Boulders can be pushed sideways into space. Collecting the cave's quota of
|
|
14
|
+
gems opens the exit. A time counter, a score, three lives. At game over a
|
|
15
|
+
new high score is entered with the joystick and the five-row table is saved
|
|
16
|
+
to drive 8; it is loaded again at start-up. An original two-voice tune plays
|
|
17
|
+
throughout, with sound effects on the third voice. Graphics, caves and tune
|
|
18
|
+
are original.
|
|
19
|
+
|
|
20
|
+
Joystick in port 2. Fire starts; up and down pick a letter, fire sets it.
|
|
21
|
+
|
|
22
|
+
## Files
|
|
23
|
+
|
|
24
|
+
| File | What it holds |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `src/main.c` | States (title, next cave, play, name entry, table), the frame loop, input, the autopilot and its verdict |
|
|
27
|
+
| `src/cave.c`, `cave.h` | The rules: the cave scan, split into row slices (technique `cave_scan_engine`) |
|
|
28
|
+
| `src/level.c`, `level.h` | The RLE cave decoder, timed on CIA1 timer B (`tile_map_render`, decode half) |
|
|
29
|
+
| `src/render.c`, `render.h` | RAM character set at `$2000`, cell drawing, the dirty list, text, glyph animation (`charset_animation`) |
|
|
30
|
+
| `src/sound.c`, `sound.h` | The tune on voices 1 and 2, effects on voice 3 (`sid_play_routine_pattern`, `sfx_engine_beside_music`) |
|
|
31
|
+
| `src/hiscore.c`, `hiscore.h` | The table, the insert, the file on drive 8 (`high_score_table_insert`, `kernal_file_read_seq`, `kernal_file_write_seq`, `error_channel_check`) |
|
|
32
|
+
| `tools/gen.py` | The caves, the autopilot script, a Python model of the rules, the note table. Writes `src/gen_*.h` |
|
|
33
|
+
| `tools/model_check.py` | Every visible cave cell of both shots against the model (`make modelcheck`) |
|
|
34
|
+
| `tools/disk_check.py` | Grades `make disktest` |
|
|
35
|
+
| `tools/drive.py` | Plays the `make joy` build headless over VICE's binary monitor |
|
|
36
|
+
| `expect.json`, `PLAN.md` | The screenshot checks; the plan with the c64-kb tool output it was made from |
|
|
37
|
+
|
|
38
|
+
Memory: code and data `$0880`-`$1FFF` and `$2800` up; the character set
|
|
39
|
+
`$2000`-`$27FF` (`$D018` = `$18`); screen `$0400`. Screen row 0 is the HUD,
|
|
40
|
+
rows 1 to 22 the cave (one character a cell), row 23 messages, row 24 the
|
|
41
|
+
cave name and, in AUTOPILOT builds, the frame meter.
|
|
42
|
+
|
|
43
|
+
## How it runs
|
|
44
|
+
|
|
45
|
+
One cave frame is one scan of the 38 x 20 interior. It is split into four
|
|
46
|
+
slices of five rows, one slice a display frame, so the cave moves once every
|
|
47
|
+
four frames on both models (12.5 cave frames a second on PAL, 15 on NTSC).
|
|
48
|
+
The player's direction is latched at the first slice. Each slice redraws
|
|
49
|
+
only the cells it changed. After the fourth slice the exit opens if the
|
|
50
|
+
quota is met and the time counter ticks (once every 12 cave frames).
|
|
51
|
+
|
|
52
|
+
The dirty list holds 16 cells: 8 moves, since a move marks two cells (an
|
|
53
|
+
explosion marks nine). When a slice changes more, the list overflows and
|
|
54
|
+
the slice's rows (one above to one below) are queued instead;
|
|
55
|
+
`draw_pending` redraws at most two queued rows a frame, 34 cycles a cell
|
|
56
|
+
from the generated code, about 2,800 cycles for two rows. The first version
|
|
57
|
+
redrew all seven rows in the frame of the overflow, 55,305 cycles for 280
|
|
58
|
+
cells (measured in comparison), almost three PAL frames.
|
|
59
|
+
|
|
60
|
+
**How many objects a slice can move.** Each moving or landing object costs
|
|
61
|
+
about 440 cycles on top of the slice's usual work: 16 boulders falling in
|
|
62
|
+
one slice made a 13,643-cycle PAL frame and a 13,861-cycle NTSC one, against
|
|
63
|
+
a typical frame of about 6,500 to 6,800 (the meter; arithmetic for the per-object
|
|
64
|
+
figure). So about 20 moving objects a slice fit an NTSC frame, and about 25
|
|
65
|
+
fit a PAL one. A cave that moves more in one slice drops frames. The
|
|
66
|
+
autopilot's verdict counts dropped frames (below), so a cave designed past
|
|
67
|
+
that limit fails its own check. The cave-scan recipe's 380-boulder fill is
|
|
68
|
+
far past it; this starter's caves keep falls short and spread out.
|
|
69
|
+
|
|
70
|
+
The KERNAL IRQ is off during play; the loop polls raster line 250. Disk
|
|
71
|
+
calls happen on a static screen with the sound muted, and `SEI` follows
|
|
72
|
+
each one, because the KERNAL serial routines end in `CLI`.
|
|
73
|
+
|
|
74
|
+
## Checks
|
|
75
|
+
|
|
76
|
+
| Command | What it proves |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `make shot check` | The autopilot game on PAL and NTSC, each on a fresh D64 (`SHOT_DISK := 1`): 41 checks (verdict, HUD, the table row it inserted, the save read back, cave cells, PAL = NTSC, the meter) |
|
|
79
|
+
| `make modelcheck` | 516 visible cave cells per shot match the model's cave at game over |
|
|
80
|
+
| `make selftest` | The FORCE_FAULT build flips one byte of the save as it is read back: red border, letter V, and `READ BACK BAD` in the table |
|
|
81
|
+
| `make selftest-scan` | The build with `SCAN_FLAG=0` (no scanned bit, the cave-scan recipe's double-move bug) fails, and its verdict names E |
|
|
82
|
+
| `make disktest` | The save, a second save over it, and the load on a true-drive 1541 (below) |
|
|
83
|
+
| `make claims` | Every store the autopilot run makes is one the Makefile declares |
|
|
84
|
+
|
|
85
|
+
The autopilot plays a whole game of three lives. Its script is keyed to
|
|
86
|
+
the game's own counter of cave starts: start 1 digs right along row 2,
|
|
87
|
+
collects four gems, pushes a boulder twice, digs down for two more and walks
|
|
88
|
+
into the open exit. Starts 2, 3 and 4 are cave 2 after each lost life: out
|
|
89
|
+
from under a boulder, then under another, then the first again, and each
|
|
90
|
+
time the boulder falls on him. So the restart path (the cave decoded again,
|
|
91
|
+
a life taken, the score banked) runs twice. It enters the name ABE; 158
|
|
92
|
+
goes in row 4, and the table is saved and read back from the shot's fresh
|
|
93
|
+
disk. In cave 1 a boulder on the end of a brick rolls right, and a row of
|
|
94
|
+
16 boulders falls and lands in one slice, which overflows the dirty list.
|
|
95
|
+
|
|
96
|
+
`tools/gen.py` plays the same script through its model and writes what the
|
|
97
|
+
game must end with. The verdict prints one letter for each test that
|
|
98
|
+
failed, after the fold on row 23:
|
|
99
|
+
|
|
100
|
+
| Letter | Test |
|
|
101
|
+
|---|---|
|
|
102
|
+
| F | the fold, chained over every cave the game left (0x75FA), against the model's |
|
|
103
|
+
| S, G, C, P, K | score, gems, cave, play frames, cave starts |
|
|
104
|
+
| T | the table row: rank, name and score |
|
|
105
|
+
| L | every cave decode matched its fold |
|
|
106
|
+
| E | the scan met the living player exactly once in every cave frame |
|
|
107
|
+
| M | at every cave end, after the row queue is drained, every screen cell shows its cave cell |
|
|
108
|
+
| D | no play frame's work ran past line 250 (the `$D019` raster latch, below) |
|
|
109
|
+
| V | the save read back byte for byte (`memcmp`) |
|
|
110
|
+
|
|
111
|
+
A watchdog ends the game once play runs past the model's frame count, so a
|
|
112
|
+
broken rule still reaches the verdict. Each gate was checked with a
|
|
113
|
+
mutation (2026-09-23): no right roll (F), no `dead_frames` reset on restart
|
|
114
|
+
(F P K D), the row queue disabled (M), the save one byte short (V), the
|
|
115
|
+
`memcmp` replaced by true (selftest then passes the fault build and fails),
|
|
116
|
+
a busy loop in one play frame (D), and the E test removed (selftest-scan
|
|
117
|
+
then finds no E).
|
|
118
|
+
|
|
119
|
+
**Dropped frames.** The VIC sets bit 0 of `$D019` on every raster compare
|
|
120
|
+
match even with the interrupt disabled. `wait_frame` acknowledges it at line
|
|
121
|
+
250, so a set bit on entry means the frame's work overran. The KERNAL leaves
|
|
122
|
+
the compare at line 311 (bit 8 set in `$D011`), so `main` clears that bit
|
|
123
|
+
first: without it the latch never set (0 of 200 frames against 199 of 200,
|
|
124
|
+
a test program in VICE x64sc 3.10).
|
|
125
|
+
|
|
126
|
+
**The shot pin.** Both models are shot at 24,000,000 cycles. At
|
|
127
|
+
18,000,000 the save is still running on both models; at 20,000,000,
|
|
128
|
+
24,000,000 and 30,000,000 the picture is byte-identical, PAL and NTSC
|
|
129
|
+
(VICE x64sc 3.10, windowless).
|
|
130
|
+
|
|
131
|
+
**The disk test.** `make disktest` (`DISK_MODEL=ntsc` for NTSC) copies the
|
|
132
|
+
release D64. It runs the autopilot build against the copy with
|
|
133
|
+
`-drive8truedrive`, so the emulated 1541 runs its own DOS ROM. The build
|
|
134
|
+
finds no file (62), plays, saves (scratch, then write) and shows
|
|
135
|
+
`SAVED TO DISK (00)`. It then runs a second time on the same image. It
|
|
136
|
+
loads that file, its 158 ties row 4 and goes in row 5, and the save must
|
|
137
|
+
replace the file. Without the scratch the drive answers 63 (FILE EXISTS)
|
|
138
|
+
and nothing is written: a build with the scratch removed fails this test.
|
|
139
|
+
The second run's own verdict is red by design, because it did not start
|
|
140
|
+
from the default table. c1541 reads the 38-byte `HISCORE` file back after
|
|
141
|
+
each save, and the directory must hold one entry. Last, a cold VICE
|
|
142
|
+
autostarts the D64: the drive loads the release PRG, which reads the file
|
|
143
|
+
and shows the title with rows 4 and 5 `ABE 000158` and `SCORES FROM DISK
|
|
144
|
+
(00)`. Three pictures, two files and the directory are graded. Run on
|
|
145
|
+
2026-09-23: PASS on PAL and NTSC.
|
|
146
|
+
|
|
147
|
+
## Driving it headless
|
|
148
|
+
|
|
149
|
+
`make joy` builds the normal game (three lives, title, no autopilot) with
|
|
150
|
+
`-dJOY_SOURCE=0x02fe`: the port byte comes from `$02FE` instead of `$DC00`.
|
|
151
|
+
`tools/drive.py` plays that build over VICE's binary monitor. It writes the
|
|
152
|
+
byte, lets the machine run, and reads screen RAM as text:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
make joy
|
|
156
|
+
python3 tools/drive.py build/action-puzzle-joy.prg "until:FIRE TO START" tap:fire \
|
|
157
|
+
until:LIVES hold:right "until:ENTER YOUR NAME" hold:none tap:up tap:fire tap:fire \
|
|
158
|
+
tap:fire "until:GAME OVER" print tap:fire "until:FIRE TO START" print
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
That run (2026-09-23) held right through three time-outs (cave 1 each
|
|
162
|
+
time), entered BAA, and showed `4. BAA 000120` in the table, `NOT SAVED
|
|
163
|
+
(74)` with no disk attached, and then the title. Two findings
|
|
164
|
+
behind this design:
|
|
165
|
+
|
|
166
|
+
- The windowless VICE's joyport commands do not reach `$DC00`. The binary
|
|
167
|
+
monitor's joyport set was accepted, but `$DC00` never changed, with or
|
|
168
|
+
without `-joydev2` (found in review).
|
|
169
|
+
- Monitor screenshots from the windowless build came back stale while the
|
|
170
|
+
game ran, so `drive.py` reads screen RAM. Entering the text monitor during
|
|
171
|
+
the start-up disk read left that read hung twice here; the binary monitor
|
|
172
|
+
under warp did not.
|
|
173
|
+
|
|
174
|
+
## The measured frame
|
|
175
|
+
|
|
176
|
+
The harness meter (CIA2 timer A), over the autopilot's 240 play frames,
|
|
177
|
+
VICE x64sc 3.10:
|
|
178
|
+
|
|
179
|
+
| Model | Worst | Typical (median) | Frame |
|
|
180
|
+
|---|---|---|---|
|
|
181
|
+
| PAL | 13,643 | 6,518 | 19,656 |
|
|
182
|
+
| NTSC | 13,861 | 6,776 | 17,095 |
|
|
183
|
+
|
|
184
|
+
The worst frame is play frame 7, the slice where the 16 boulders fall and
|
|
185
|
+
overflow the dirty list (a debug build that kept the worst frame's index
|
|
186
|
+
found it). The cave decode between caves is not a play frame: 40,041 cycles
|
|
187
|
+
on PAL and 40,519 on NTSC for cave 2, screen on, CIA1 timer B, printed after
|
|
188
|
+
the verdict.
|
|
189
|
+
|
|
190
|
+
The same checks pass with the released Oscar64 v1.32.273 (make shot check,
|
|
191
|
+
modelcheck, selftest, selftest-scan and disktest on PAL, run 2026-09-23).
|
|
192
|
+
Its meter reads 13,412 / 6,392 cycles on PAL and 13,669 / 6,607 on NTSC
|
|
193
|
+
(measured on 3048ac1 by the other #39 session's comparator).
|
|
194
|
+
|
|
195
|
+
Against `plan-budget` (the PLAN.md output): it summed the recipe's whole
|
|
196
|
+
scan, 18,559 cycles, into every PAL play frame (range 19,599 to 19,807 plus
|
|
197
|
+
1,075 for badlines, "undetermined") and left it out of the NTSC frame as
|
|
198
|
+
multi-frame (1,040 to 1,248 plus 1,075). Neither is this program's frame:
|
|
199
|
+
the scan here runs a quarter at a time. The scan loop takes 17 cycles a
|
|
200
|
+
cell of dirt (counted from the generated code). The recipe's loop measured 18.7 (14,206 cycles
|
|
201
|
+
for 760 cells, with badlines in). So a slice of 190 cells costs about 3,230
|
|
202
|
+
cycles, plus the objects in it (arithmetic). The tool's
|
|
203
|
+
music figure is the recipe's stub tune; this tune and its effects are
|
|
204
|
+
measured only inside the whole frame.
|
|
205
|
+
|
|
206
|
+
## Extending it
|
|
207
|
+
|
|
208
|
+
1. **Scroll a bigger cave.** Draw cells as 2 x 2 characters and scroll a
|
|
209
|
+
window over a cave larger than the screen: `tile_map_render` and the
|
|
210
|
+
recipe `oscar64/tile-map-render` (metatiles), then a scroll technique
|
|
211
|
+
from `technique-lookup` (`techniques-for --category scroll`).
|
|
212
|
+
2. **Add amoeba, a magic wall or more enemies.** Add codes in `cave.h`
|
|
213
|
+
(at most 32: glyphs sit at `$40` + code), a branch in `cell()`, a glyph
|
|
214
|
+
and a tint in `render.c`, the same colour in `tools/model_check.py`'s
|
|
215
|
+
`TINT`, and the same rule in `tools/gen.py`'s `Cave.cell`. Extend the
|
|
216
|
+
script and run `make gen shot check modelcheck`. The rules and the
|
|
217
|
+
scanned bit are `cave_scan_engine` (recipe `oscar64/cave-scan`).
|
|
218
|
+
3. **Faster scans.** The scan loop is C; the recipe `oscar64/level-rle-decoder`
|
|
219
|
+
shows a hand-written decoder a little under twice as fast as the C one,
|
|
220
|
+
and the same move applies to `cave_scan_rows`. Measure before and after
|
|
221
|
+
with the meter.
|
|
222
|
+
|
|
223
|
+
More caves: add them to `CAVES` in `tools/gen.py` and run `make gen`.
|
|
224
|
+
|
|
225
|
+
## Left out on purpose
|
|
226
|
+
|
|
227
|
+
- Scrolling, 2 x 2 cells, multicolour graphics, sprites: one cell is one
|
|
228
|
+
hires character, so the whole 40 x 22 cave is on screen.
|
|
229
|
+
- Amoeba, magic wall, slime, collecting falling gems, the fire-to-grab move.
|
|
230
|
+
- A raster IRQ: the loop polls line 250. Music keeps time only while the
|
|
231
|
+
loop does; it stops during disk calls.
|
|
232
|
+
- Equal speed on both models: NTSC plays 20 % faster in real time,
|
|
233
|
+
tune included (pitfall `pal_ntsc_tempo_mismatch`). The note pitches are
|
|
234
|
+
right on both (a PAL and an NTSC table).
|
|
235
|
+
- Anyone listening to the sound: the tune and effects were checked by the
|
|
236
|
+
registers claims-watch saw written, not by ear.
|
|
237
|
+
- A real joystick on `$DC00`: the normal game was driven headless through
|
|
238
|
+
`$02FE` (above), which differs from the release build in one line of
|
|
239
|
+
`port_read`.
|
|
240
|
+
- Real hardware.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"checks": [
|
|
3
|
+
{ "name": "own verdict (border)", "type": "verdict" },
|
|
4
|
+
{ "name": "verdict line and the model's chained fold (0x75FA)", "type": "text", "row": 23, "col": 0, "text": "RESULT 01 PASS FOLD 30202" },
|
|
5
|
+
{ "name": "HUD: cave 2's quota and time, the banked score 158, no lives left", "type": "text", "row": 0, "col": 0, "text": "GEMS 00/08 TIME 120 SCORE 000158 LIVES 0" },
|
|
6
|
+
{ "name": "game-over box", "type": "text", "row": 7, "col": 16, "text": "GAME OVER" },
|
|
7
|
+
{ "name": "table row 4: the scripted name and score, inserted", "type": "text", "row": 14, "col": 13, "text": "4. ABE 000158" },
|
|
8
|
+
{ "name": "table row 5: the old row 4, shifted down", "type": "text", "row": 15, "col": 13, "text": "5. MUD 000100" },
|
|
9
|
+
{ "name": "table row 3 kept", "type": "text", "row": 13, "col": 13, "text": "3. GEM 000200" },
|
|
10
|
+
{ "name": "the save, read back byte for byte from the shot's fresh disk", "type": "text", "row": 17, "col": 9, "text": "SAVED TO DISK (00)" },
|
|
11
|
+
{ "name": "steel border, cave (0, 0)", "type": "pixel", "row": 1, "col": 0, "colour": 12 },
|
|
12
|
+
{ "name": "boulder the model leaves at cave (22, 1)", "type": "pixel", "row": 2, "col": 22, "colour": 15 },
|
|
13
|
+
{ "name": "boulder at cave (11, 2)", "type": "pixel", "row": 3, "col": 11, "colour": 15 },
|
|
14
|
+
{ "name": "gem at cave (14, 3)", "type": "pixel", "row": 4, "col": 14, "colour": 3 },
|
|
15
|
+
{ "name": "spark the model moved to cave (23, 4)", "type": "pixel", "row": 5, "col": 23, "colour": 8 },
|
|
16
|
+
{ "name": "gem that fell into the spark's corridor, cave (24, 4)", "type": "pixel", "row": 5, "col": 24, "colour": 3 },
|
|
17
|
+
{ "name": "exit still shut (looks like steel), cave (29, 4)", "type": "pixel", "row": 5, "col": 29, "colour": 12 },
|
|
18
|
+
{ "name": "the explosion that killed the player left space, cave (5, 3)", "type": "pixel", "row": 4, "col": 5, "colour": 0 },
|
|
19
|
+
{ "name": "where the killing boulder fell from is space, cave (5, 1)", "type": "pixel", "row": 2, "col": 5, "colour": 0 },
|
|
20
|
+
{ "name": "dirt beside the blast, cave (1, 3)", "type": "pixel", "row": 4, "col": 1, "colour": 9 },
|
|
21
|
+
{ "name": "gem at cave (4, 18), below the box", "type": "pixel", "row": 19, "col": 4, "colour": 3 },
|
|
22
|
+
{ "name": "HUD, cave, box and verdict line the same on both models", "type": "same", "cells": [0, 0, 23, 39] },
|
|
23
|
+
{ "name": "frame meter, the script's 240 play frames over four lives", "type": "meter", "row": 24, "col": 20, "frames": 240 }
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
// cave.c: the rules. Built from c64-kb's oscar64/cave-scan recipe, with
|
|
2
|
+
// pushing, a second enemy, explosions, gems collected for points, the exit
|
|
3
|
+
// and the time counter added. Every rule here is written again in Python in
|
|
4
|
+
// tools/gen.py (class Cave); change both together.
|
|
5
|
+
#include "cave.h"
|
|
6
|
+
|
|
7
|
+
char cave[CW * CH];
|
|
8
|
+
char cave_move;
|
|
9
|
+
char cave_got, cave_need, cave_time, cave_tick;
|
|
10
|
+
unsigned cave_points;
|
|
11
|
+
unsigned cave_player, cave_exit_at;
|
|
12
|
+
bool cave_dead, cave_exited, cave_exit_open;
|
|
13
|
+
char cave_events;
|
|
14
|
+
char cave_seen;
|
|
15
|
+
|
|
16
|
+
unsigned cave_dirty[DIRTY_MAX];
|
|
17
|
+
char cave_ndirty;
|
|
18
|
+
bool cave_overflow;
|
|
19
|
+
|
|
20
|
+
// Headings in clockwise order: left, up, right, down. Turning left is
|
|
21
|
+
// heading + 3, turning right heading + 1, both modulo 4.
|
|
22
|
+
static const signed char step[4] = { -1, -CW, 1, CW };
|
|
23
|
+
|
|
24
|
+
static void mark(char *q)
|
|
25
|
+
{
|
|
26
|
+
if (cave_ndirty < DIRTY_MAX)
|
|
27
|
+
cave_dirty[cave_ndirty++] = q - cave;
|
|
28
|
+
else
|
|
29
|
+
cave_overflow = true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// The one place an object moves. A move to a later cell in scan order sets
|
|
33
|
+
// the scanned bit, so the scan skips the object when it gets there.
|
|
34
|
+
static void put(char *dst, char v, char *src)
|
|
35
|
+
{
|
|
36
|
+
#if SCAN_FLAG
|
|
37
|
+
if (dst > src)
|
|
38
|
+
v |= SCANNED;
|
|
39
|
+
#endif
|
|
40
|
+
*dst = v;
|
|
41
|
+
*src = SPACE;
|
|
42
|
+
if (v == PLAYER || v == (PLAYER | SCANNED))
|
|
43
|
+
cave_player = dst - cave;
|
|
44
|
+
mark(dst);
|
|
45
|
+
mark(src);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// A 3 x 3 explosion. Steel and the exit survive. Cells after `at` in scan
|
|
49
|
+
// order get the scanned bit, so the explosion starts on the next cave frame
|
|
50
|
+
// everywhere. `at` = 0xffff (from cave_end_frame) marks none.
|
|
51
|
+
static void explode(unsigned centre, char kind, unsigned at)
|
|
52
|
+
{
|
|
53
|
+
for (signed char dy = -CW; dy <= CW; dy += CW)
|
|
54
|
+
for (signed char dx = -1; dx <= 1; dx++)
|
|
55
|
+
{
|
|
56
|
+
unsigned n = centre + dy + dx;
|
|
57
|
+
char t = cave[n] & 0x7f;
|
|
58
|
+
if (t == STEEL || t == EXIT_SHUT || t == EXIT_OPEN)
|
|
59
|
+
continue;
|
|
60
|
+
if (t == PLAYER)
|
|
61
|
+
cave_dead = true;
|
|
62
|
+
cave[n] = n > at ? kind | SCANNED : kind;
|
|
63
|
+
mark(cave + n);
|
|
64
|
+
}
|
|
65
|
+
cave_events |= EV_BOOM;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static bool is_round(char t)
|
|
69
|
+
{
|
|
70
|
+
return t == BOULDER || t == GEM || t == BRICK;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Roll off a round object: left first, then right. Needs the side cell and
|
|
74
|
+
// the cell below it empty. The object leaves falling.
|
|
75
|
+
static bool roll(char *p, char fall)
|
|
76
|
+
{
|
|
77
|
+
if (p[-1] == SPACE && p[CW - 1] == SPACE) { put(p - 1, fall, p); return true; }
|
|
78
|
+
if (p[1] == SPACE && p[CW + 1] == SPACE) { put(p + 1, fall, p); return true; }
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static void fall_rules(char *p, char v)
|
|
83
|
+
{
|
|
84
|
+
char b = p[CW];
|
|
85
|
+
char bt = b & 0x7f;
|
|
86
|
+
if (b == SPACE)
|
|
87
|
+
put(p + CW, v, p); // keep falling
|
|
88
|
+
else if (bt == PLAYER || (bt >= SPARK && bt < MOTH))
|
|
89
|
+
explode(p + CW - cave, BLAST, p - cave);
|
|
90
|
+
else if (bt >= MOTH && bt < BLAST)
|
|
91
|
+
explode(p + CW - cave, BURST, p - cave); // a moth dies into gems
|
|
92
|
+
else if (bt == BOULDER_F || bt == GEM_F)
|
|
93
|
+
; // wait for it to move
|
|
94
|
+
else if (!(is_round(bt) && roll(p, v)))
|
|
95
|
+
{
|
|
96
|
+
*p = v - 1; // land
|
|
97
|
+
mark(p);
|
|
98
|
+
cave_events |= EV_LAND;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static void player_rules(char *p)
|
|
103
|
+
{
|
|
104
|
+
if (cave_move >= 4)
|
|
105
|
+
return;
|
|
106
|
+
signed char s = step[cave_move];
|
|
107
|
+
char *t = p + s;
|
|
108
|
+
char tv = *t;
|
|
109
|
+
if (tv == SPACE || tv == DIRT)
|
|
110
|
+
{
|
|
111
|
+
if (tv == DIRT)
|
|
112
|
+
cave_events |= EV_DIG;
|
|
113
|
+
put(t, PLAYER, p);
|
|
114
|
+
}
|
|
115
|
+
else if (tv == GEM)
|
|
116
|
+
{
|
|
117
|
+
cave_got++;
|
|
118
|
+
cave_points += GEM_POINTS;
|
|
119
|
+
cave_events |= EV_GEM;
|
|
120
|
+
put(t, PLAYER, p);
|
|
121
|
+
}
|
|
122
|
+
else if (tv == EXIT_OPEN)
|
|
123
|
+
{
|
|
124
|
+
*p = SPACE;
|
|
125
|
+
mark(p);
|
|
126
|
+
cave_exited = true;
|
|
127
|
+
}
|
|
128
|
+
else if (tv == BOULDER && (cave_move == 0 || cave_move == 2) && t[s] == SPACE)
|
|
129
|
+
{
|
|
130
|
+
put(t + s, BOULDER, t); // push: the boulder first
|
|
131
|
+
put(t, PLAYER, p);
|
|
132
|
+
cave_events |= EV_PUSH;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Sparks turn left when they can, moths turn right; either goes on when it
|
|
137
|
+
// cannot turn, and turns the other way on the spot when both are blocked.
|
|
138
|
+
// Either explodes when the player is next to it.
|
|
139
|
+
static void enemy_rules(char *p, char v)
|
|
140
|
+
{
|
|
141
|
+
char base = v < MOTH ? SPARK : MOTH;
|
|
142
|
+
char kind = v < MOTH ? BLAST : BURST;
|
|
143
|
+
for (char k = 0; k < 4; k++)
|
|
144
|
+
if ((p[step[k]] & 0x7f) == PLAYER)
|
|
145
|
+
{
|
|
146
|
+
explode(p - cave, kind, p - cave);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
char d = v & 3;
|
|
150
|
+
char first = base == SPARK ? (d + 3) & 3 : (d + 1) & 3;
|
|
151
|
+
char spin = base == SPARK ? (d + 1) & 3 : (d + 3) & 3;
|
|
152
|
+
if (p[step[first]] == SPACE)
|
|
153
|
+
put(p + step[first], base + first, p);
|
|
154
|
+
else if (p[step[d]] == SPACE)
|
|
155
|
+
put(p + step[d], base + d, p);
|
|
156
|
+
else
|
|
157
|
+
{
|
|
158
|
+
*p = base + spin;
|
|
159
|
+
mark(p);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// One object's turn. Called only for codes BOULDER and up. It takes the row
|
|
164
|
+
// and the column, not a cell pointer: with a pointer argument Oscar64 -O2
|
|
165
|
+
// computed row + x for every cell before the test, and the loop took 42
|
|
166
|
+
// cycles a cell instead of 17 (counted from the generated code). The frame meter read a typical play
|
|
167
|
+
// frame of 11,812 cycles before and 7,004 after, on the build whose HUD still
|
|
168
|
+
// rewrote every field each cave frame (6,340 with today's update_hud).
|
|
169
|
+
static __noinline void cell(char *row, char x)
|
|
170
|
+
{
|
|
171
|
+
char *p = row + x;
|
|
172
|
+
char v = *p;
|
|
173
|
+
if (v & SCANNED)
|
|
174
|
+
{
|
|
175
|
+
*p = v & 0x7f; // moved here this scan
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (v == BOULDER || v == GEM)
|
|
179
|
+
{
|
|
180
|
+
char b = p[CW];
|
|
181
|
+
if (b == SPACE)
|
|
182
|
+
put(p + CW, v + 1, p); // start falling
|
|
183
|
+
else if (is_round(b & 0x7f))
|
|
184
|
+
roll(p, v + 1);
|
|
185
|
+
}
|
|
186
|
+
else if (v == BOULDER_F || v == GEM_F)
|
|
187
|
+
fall_rules(p, v);
|
|
188
|
+
else if (v == PLAYER)
|
|
189
|
+
{
|
|
190
|
+
cave_seen++; // once a cave frame, or the scanned bit failed
|
|
191
|
+
player_rules(p);
|
|
192
|
+
}
|
|
193
|
+
else if (v >= BLAST)
|
|
194
|
+
{
|
|
195
|
+
if (v == BLAST + 2)
|
|
196
|
+
*p = SPACE;
|
|
197
|
+
else if (v == BURST + 2)
|
|
198
|
+
*p = GEM;
|
|
199
|
+
else
|
|
200
|
+
*p = v + 1;
|
|
201
|
+
mark(p);
|
|
202
|
+
}
|
|
203
|
+
else if (v >= SPARK)
|
|
204
|
+
enemy_rules(p, v);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Interior rows y0 .. y1 - 1. The loop only reads and compares: LDA (row),Y,
|
|
208
|
+
// CMP, BCC, INY, CPY, BCC: 5 + 2 + 3 + 2 + 2 + 3 = 17 cycles a cell of space,
|
|
209
|
+
// dirt, brick or steel (from the generated code, both branches taken, no page
|
|
210
|
+
// crossed). The dirty list starts
|
|
211
|
+
// empty for each slice.
|
|
212
|
+
__noinline void cave_scan_rows(char y0, char y1)
|
|
213
|
+
{
|
|
214
|
+
cave_ndirty = 0;
|
|
215
|
+
cave_overflow = false;
|
|
216
|
+
char *row = cave + CW * y0;
|
|
217
|
+
for (char y = y0; y < y1; y++, row += CW)
|
|
218
|
+
for (char x = 1; x < CW - 1; x++)
|
|
219
|
+
{
|
|
220
|
+
char v = row[x];
|
|
221
|
+
if (v >= BOULDER)
|
|
222
|
+
{
|
|
223
|
+
if (v & SCANNED)
|
|
224
|
+
row[x] = v & 0x7f; // moved here this scan: no call
|
|
225
|
+
else
|
|
226
|
+
cell(row, x);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
void cave_start(char need, char time)
|
|
232
|
+
{
|
|
233
|
+
cave_need = need;
|
|
234
|
+
cave_time = time;
|
|
235
|
+
cave_got = 0;
|
|
236
|
+
cave_tick = 0;
|
|
237
|
+
cave_points = 0;
|
|
238
|
+
cave_dead = cave_exited = cave_exit_open = false;
|
|
239
|
+
cave_move = NO_MOVE;
|
|
240
|
+
for (unsigned i = 0; i < CW * CH; i++)
|
|
241
|
+
{
|
|
242
|
+
if (cave[i] == PLAYER)
|
|
243
|
+
cave_player = i;
|
|
244
|
+
else if (cave[i] == EXIT_SHUT)
|
|
245
|
+
cave_exit_at = i;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// After the last slice of a cave frame: open the exit when the quota is met,
|
|
250
|
+
// then run the clock. Time out explodes the player.
|
|
251
|
+
void cave_end_frame(void)
|
|
252
|
+
{
|
|
253
|
+
if (!cave_exit_open && cave_got >= cave_need)
|
|
254
|
+
{
|
|
255
|
+
cave[cave_exit_at] = EXIT_OPEN;
|
|
256
|
+
mark(cave + cave_exit_at);
|
|
257
|
+
cave_exit_open = true;
|
|
258
|
+
cave_events |= EV_OPEN;
|
|
259
|
+
}
|
|
260
|
+
if (cave_exited || cave_dead)
|
|
261
|
+
return;
|
|
262
|
+
if (++cave_tick == TICK_CAVE_FRAMES)
|
|
263
|
+
{
|
|
264
|
+
cave_tick = 0;
|
|
265
|
+
if (cave_time)
|
|
266
|
+
cave_time--;
|
|
267
|
+
if (cave_time == 0)
|
|
268
|
+
explode(cave_player, BLAST, 0xffff);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
unsigned cave_fold(unsigned chk)
|
|
273
|
+
{
|
|
274
|
+
for (unsigned i = 0; i < CW * CH; i++)
|
|
275
|
+
{
|
|
276
|
+
unsigned t = chk ^ (cave[i] & 0x7f);
|
|
277
|
+
chk = (t << 2) + t + 1; // (chk ^ v) * 5 + 1
|
|
278
|
+
}
|
|
279
|
+
return chk;
|
|
280
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// cave.h: the cave and its rules (c64-kb technique cave_scan_engine).
|
|
2
|
+
//
|
|
3
|
+
// A 40 x 22 cave of one-byte cells, steel border included. One cave frame is
|
|
4
|
+
// one top-to-bottom, left-to-right scan of the 38 x 20 interior. The game
|
|
5
|
+
// splits it into slices of rows, one slice a display frame
|
|
6
|
+
// (cave_scan_rows), then calls cave_end_frame. An object that moves down or
|
|
7
|
+
// right gets bit 7 (SCANNED), so the scan skips it when it reaches the cell
|
|
8
|
+
// it moved into. tools/gen.py holds a model of the same rules; the AUTOPILOT
|
|
9
|
+
// build checks the cave against it.
|
|
10
|
+
#ifndef CAVE_H
|
|
11
|
+
#define CAVE_H
|
|
12
|
+
|
|
13
|
+
#define CW 40 // cave width in cells
|
|
14
|
+
#define CH 22 // cave height in cells
|
|
15
|
+
|
|
16
|
+
// Element codes (tools/gen.py uses the same numbers). A code below BOULDER
|
|
17
|
+
// never moves, and the scan loop does nothing more than compare it.
|
|
18
|
+
#define SPACE 0
|
|
19
|
+
#define DIRT 1
|
|
20
|
+
#define BRICK 2 // round: things roll off it
|
|
21
|
+
#define STEEL 3 // not round, not destroyed by explosions
|
|
22
|
+
#define BOULDER 4
|
|
23
|
+
#define BOULDER_F 5 // falling: the resting code + 1
|
|
24
|
+
#define GEM 6
|
|
25
|
+
#define GEM_F 7
|
|
26
|
+
#define EXIT_SHUT 8 // drawn as steel until the quota is met
|
|
27
|
+
#define EXIT_OPEN 9
|
|
28
|
+
#define PLAYER 10
|
|
29
|
+
#define SPARK 12 // 12..15: heading in the low two bits; keeps a wall on its left
|
|
30
|
+
#define MOTH 16 // 16..19: keeps a wall on its right; dies into gems
|
|
31
|
+
#define BLAST 20 // 20..22: explosion stages, then space
|
|
32
|
+
#define BURST 23 // 23..25: explosion stages, then a gem
|
|
33
|
+
#define CODES 26 // at most 32: render.c draws code & 0x1f at glyph $40 + code
|
|
34
|
+
#define SCANNED 0x80
|
|
35
|
+
|
|
36
|
+
#define NO_MOVE 0xff // cave_move: headings 0..3 are left, up, right, down
|
|
37
|
+
|
|
38
|
+
#define GEM_POINTS 10
|
|
39
|
+
#define TICK_CAVE_FRAMES 12 // cave frames per unit of the time counter
|
|
40
|
+
|
|
41
|
+
// Sound events a scan raised, for the effects engine (bits of cave_events).
|
|
42
|
+
#define EV_DIG 0x01
|
|
43
|
+
#define EV_PUSH 0x02
|
|
44
|
+
#define EV_LAND 0x04
|
|
45
|
+
#define EV_GEM 0x08
|
|
46
|
+
#define EV_OPEN 0x10
|
|
47
|
+
#define EV_BOOM 0x20
|
|
48
|
+
|
|
49
|
+
extern char cave[CW * CH];
|
|
50
|
+
extern char cave_move; // the player's heading this cave frame, or NO_MOVE
|
|
51
|
+
extern char cave_got, cave_need, cave_time, cave_tick;
|
|
52
|
+
extern unsigned cave_points; // points scored in this cave
|
|
53
|
+
extern unsigned cave_player; // cell index of the player
|
|
54
|
+
extern unsigned cave_exit_at;
|
|
55
|
+
extern bool cave_dead, cave_exited, cave_exit_open;
|
|
56
|
+
extern char cave_events;
|
|
57
|
+
extern char cave_seen; // times the scan ran the player's rules; main.c resets it each cave frame
|
|
58
|
+
|
|
59
|
+
// Cells a slice changed, for the renderer. A move marks two cells, an
|
|
60
|
+
// explosion nine, so a slice holds up to 8 moves before the list overflows;
|
|
61
|
+
// then render.c queues the slice's rows and redraws them two a frame.
|
|
62
|
+
#define DIRTY_MAX 16
|
|
63
|
+
extern unsigned cave_dirty[DIRTY_MAX];
|
|
64
|
+
extern char cave_ndirty;
|
|
65
|
+
extern bool cave_overflow;
|
|
66
|
+
|
|
67
|
+
void cave_start(char need, char time); // after the decode: find the player and exit
|
|
68
|
+
void cave_scan_rows(char y0, char y1); // scan interior rows y0 .. y1 - 1
|
|
69
|
+
void cave_end_frame(void); // after the last slice: exit, clock
|
|
70
|
+
unsigned cave_fold(unsigned chk); // chk = (chk ^ v) * 5 + 1 over all 880 cells
|
|
71
|
+
|
|
72
|
+
// SCAN_FLAG=0 builds the rules without the scanned bit: the double-move bug
|
|
73
|
+
// of the cave-scan recipe, which make selftest-scan must see fail.
|
|
74
|
+
#ifndef SCAN_FLAG
|
|
75
|
+
#define SCAN_FLAG 1
|
|
76
|
+
#endif
|
|
77
|
+
|
|
78
|
+
#pragma compile("cave.c")
|
|
79
|
+
|
|
80
|
+
#endif
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// gen_autopilot.h: written by tools/gen.py. Do not edit; edit tools/gen.py.
|
|
2
|
+
// The autopilot: one move per cave frame (L U R D, '-' still), per cave;
|
|
3
|
+
// past the end of a cave's string the player stands still.
|
|
4
|
+
static const char script0[] = "RRRRRRRRRRRRRRRRRRDDDR";
|
|
5
|
+
static const char script1[] = "RRUD";
|
|
6
|
+
static const char script2[] = "RRRRRRRRD";
|
|
7
|
+
static const char script3[] = "RRUD";
|
|
8
|
+
static const char * const script_for[4] = { script0, script1, script2, script3 };
|
|
9
|
+
static const char script_len[4] = { 22, 4, 9, 4 };
|
|
10
|
+
#define SCRIPT_STARTS 4
|
|
11
|
+
#define LIVES_AUTOPILOT 3
|
|
12
|
+
#define NAME_AUTOPILOT "ABE"
|
|
13
|
+
// What the rules model says the program must hold at game over.
|
|
14
|
+
#define EXPECT_FOLD 0x75fa
|
|
15
|
+
#define EXPECT_SCORE 158UL
|
|
16
|
+
#define EXPECT_GEMS 6
|
|
17
|
+
#define EXPECT_CAVE 1
|
|
18
|
+
#define EXPECT_PLAY_FRAMES 240
|
|
19
|
+
#define EXPECT_STARTS 4
|
|
20
|
+
#define EXPECT_RANK 3
|