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,771 @@
|
|
|
1
|
+
---
|
|
2
|
+
recipe: vehicle-control
|
|
3
|
+
toolchain: oscar64
|
|
4
|
+
output_format: PRG
|
|
5
|
+
region: both
|
|
6
|
+
techniques: [vehicle_control, fixed_point_8_8, tile_grid_collision, soft_scroll_v, screen_double_buffer_d018, ecm_mode]
|
|
7
|
+
file_formats: [PRG]
|
|
8
|
+
uses_registers: [D000, D001, D010, D011, D015, D018, D020, D021, D022, D023, D024, D027, DC06, DC07, DC0F, DD04, DD05, DD0E]
|
|
9
|
+
uses_kernal: []
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!-- doc-type: recipe -->
|
|
13
|
+
|
|
14
|
+
# Oscar64 Vehicle Control: a Spy Hunter style car on a scrolling road
|
|
15
|
+
|
|
16
|
+
## Synopsis
|
|
17
|
+
|
|
18
|
+
A car sprite at a fixed screen height drives up a road that scrolls down
|
|
19
|
+
the screen. The throttle sets the forward speed in 8.8 pixels a frame,
|
|
20
|
+
and that speed is the scroll speed: up to 4 pixels a frame on the road.
|
|
21
|
+
Steering changes a lateral velocity that grip bleeds away when the stick
|
|
22
|
+
is centred. Four wheel probes read the tile map every frame: road, verge
|
|
23
|
+
(slows the car to 1.5 pixels a frame), water (boat handling, less grip)
|
|
24
|
+
and rock (a crash, a 50-frame stop, a restart on the road's centre line).
|
|
25
|
+
A 508-frame script drives it on autopilot: accelerate, onto the left
|
|
26
|
+
verge and back, a slide left and a brake into rock at the narrowing, a
|
|
27
|
+
restart, a coast, then across a water stretch.
|
|
28
|
+
Every frame folds the car's x, speed, distance and surface into a
|
|
29
|
+
checksum that the Python model below computes on the host. Rows 1 to 3
|
|
30
|
+
show the verdict and the CIA1 timer B cost of the control update and of
|
|
31
|
+
the redraw. `$02FF` = `01` and a green border when the checksum, the end
|
|
32
|
+
state, the surfaces seen and the single crash all match; `02` and red
|
|
33
|
+
otherwise. This is `vehicle_control` in `docs/techniques/logic.md`; the
|
|
34
|
+
result-byte contract is `headless-verify.md`.
|
|
35
|
+
|
|
36
|
+
## Source
|
|
37
|
+
|
|
38
|
+
```c
|
|
39
|
+
// vehicle-control.c
|
|
40
|
+
// A Spy Hunter style car on a vertically scrolling road. The throttle sets
|
|
41
|
+
// the forward speed in 8.8 pixels a frame, and that speed is the scroll
|
|
42
|
+
// speed; steering changes a lateral velocity that grip bleeds away; four
|
|
43
|
+
// wheel probes read the tile map for road, verge, water and rock. A script
|
|
44
|
+
// drives it: accelerate, onto the verge and back, a slide left and a brake
|
|
45
|
+
// into rock at the narrowing (one crash), coast, across a water stretch as
|
|
46
|
+
// a boat. Every frame folds x, speed, distance and surface into a checksum
|
|
47
|
+
// that a Python model of the same rules computed on the host. Rows 1 to 3 show the
|
|
48
|
+
// verdict and the CIA1 timer B cost of car_update and of the redraw.
|
|
49
|
+
#include <c64/vic.h>
|
|
50
|
+
#include <c64/cia.h>
|
|
51
|
+
|
|
52
|
+
#define Screen0 ((char *)0x0400)
|
|
53
|
+
#define Screen1 ((char *)0x3c00)
|
|
54
|
+
#define Color ((char *)0xd800)
|
|
55
|
+
#define SprData ((char *)0x0340) // sprite block 13
|
|
56
|
+
#define Map ((char *)0x5000) // MAP_H x 40 tile codes, 8,800 bytes
|
|
57
|
+
#define RESULT (*(volatile char *)0x02ff)
|
|
58
|
+
|
|
59
|
+
#define CODE_PASS 0x01
|
|
60
|
+
#define CODE_FAIL 0x02
|
|
61
|
+
|
|
62
|
+
#define MAP_H 220
|
|
63
|
+
#define BASE (MAP_H - 25) // top map row at distance 0
|
|
64
|
+
#define CAR_Y 150 // car top, pixels below line 48
|
|
65
|
+
#define WHEEL_L 1 // wheel columns in the 16-px body
|
|
66
|
+
#define WHEEL_R 14
|
|
67
|
+
#define WHEEL_F 3 // wheel rows below the car top
|
|
68
|
+
#define WHEEL_B 17
|
|
69
|
+
|
|
70
|
+
// Tile code bits 7-6 are the surface class and, in ECM, the background
|
|
71
|
+
// register: road $D021, verge $D022, water $D023, rock $D024.
|
|
72
|
+
#define C_ROAD 0
|
|
73
|
+
#define C_VERGE 1
|
|
74
|
+
#define C_WATER 2
|
|
75
|
+
#define C_CRASH 3
|
|
76
|
+
|
|
77
|
+
#define IN_UP 0x01
|
|
78
|
+
#define IN_DOWN 0x02
|
|
79
|
+
#define IN_LEFT 0x04
|
|
80
|
+
#define IN_RIGHT 0x08
|
|
81
|
+
|
|
82
|
+
// 8.8 constants, pixels a frame
|
|
83
|
+
#define ACCEL 0x000c
|
|
84
|
+
#define BRAKE 0x0020
|
|
85
|
+
#define COAST 0x0002
|
|
86
|
+
#define OVERDRAG 0x0010
|
|
87
|
+
#define STEER_MIN 0x0040
|
|
88
|
+
#define VXMAX 0x0180
|
|
89
|
+
#define CRASH_FRAMES 50
|
|
90
|
+
|
|
91
|
+
static const unsigned vmax[4] = {0x0400, 0x0180, 0x0300, 0};
|
|
92
|
+
static const int steer[4] = {0x0014, 0x0014, 0x0008, 0};
|
|
93
|
+
static const int grip[4] = {0x0010, 0x0010, 0x0003, 0};
|
|
94
|
+
|
|
95
|
+
// Python model (the page's "Model"): the fold after the whole script,
|
|
96
|
+
// and the state at the end.
|
|
97
|
+
#define EXPECT_CHK 0x2b51
|
|
98
|
+
#define EXPECT_X 0x91fe
|
|
99
|
+
#define EXPECT_SPEED 0x0300
|
|
100
|
+
#define EXPECT_DPIX 1210
|
|
101
|
+
#define EXPECT_SEEN 0x17 // road, verge, water, crash
|
|
102
|
+
|
|
103
|
+
// Road segments in driving order, from the bottom of the map up.
|
|
104
|
+
struct Seg { char rows, left, right, verge, water; };
|
|
105
|
+
static const struct Seg segs[] = {
|
|
106
|
+
{60, 12, 28, 3, 0}, // wide road
|
|
107
|
+
{ 6, 13, 27, 3, 0},
|
|
108
|
+
{ 6, 14, 26, 3, 0},
|
|
109
|
+
{30, 16, 24, 2, 0}, // the narrowing
|
|
110
|
+
{ 8, 13, 27, 3, 0},
|
|
111
|
+
{50, 10, 30, 0, 1}, // water between rock banks
|
|
112
|
+
{60, 12, 28, 3, 0},
|
|
113
|
+
};
|
|
114
|
+
#define NSEGS (sizeof(segs) / sizeof(segs[0]))
|
|
115
|
+
|
|
116
|
+
struct Step { char frames, input; };
|
|
117
|
+
static const struct Step script[] = {
|
|
118
|
+
{60, IN_UP}, {40, IN_UP | IN_LEFT}, {40, IN_UP}, {40, IN_UP | IN_RIGHT},
|
|
119
|
+
{30, IN_UP}, {30, IN_UP | IN_LEFT}, {60, IN_DOWN}, {60, IN_UP},
|
|
120
|
+
{20, 0}, {60, IN_UP}, {14, IN_UP | IN_LEFT}, {30, IN_UP},
|
|
121
|
+
{14, IN_UP | IN_RIGHT}, {10, IN_UP},
|
|
122
|
+
};
|
|
123
|
+
#define STEPS (sizeof(script) / sizeof(script[0]))
|
|
124
|
+
|
|
125
|
+
static unsigned rowoff[MAP_H]; // row * 40
|
|
126
|
+
static char centre[MAP_H]; // road centre column per row
|
|
127
|
+
|
|
128
|
+
// --- the car ---------------------------------------------------------------
|
|
129
|
+
unsigned x_fp; // left edge, 8.8 pixels
|
|
130
|
+
int vx; // lateral velocity, 8.8
|
|
131
|
+
unsigned speed; // forward = scroll speed, 8.8
|
|
132
|
+
char dfrac; // distance, fraction byte
|
|
133
|
+
unsigned dpix; // distance, whole pixels
|
|
134
|
+
char surface; // class under the wheels last frame
|
|
135
|
+
char crash_t; // frames left in a crash
|
|
136
|
+
char crashes;
|
|
137
|
+
|
|
138
|
+
static char tile_class(const char *row, char px)
|
|
139
|
+
{
|
|
140
|
+
return row[px >> 3] >> 6;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
void car_update(char in)
|
|
144
|
+
{
|
|
145
|
+
if (crash_t) { // crashed: no input, no motion
|
|
146
|
+
if (--crash_t == 0) {
|
|
147
|
+
unsigned w = BASE * 8 + CAR_Y + WHEEL_F - dpix;
|
|
148
|
+
x_fp = (unsigned)(centre[w >> 3] * 8 - 8) << 8;
|
|
149
|
+
surface = C_ROAD;
|
|
150
|
+
}
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 1. speed from the throttle, limited by the surface; no throttle at or
|
|
155
|
+
// over the limit, so the over-limit drag slows a car with up held
|
|
156
|
+
unsigned vm = vmax[surface];
|
|
157
|
+
if (in & IN_UP) {
|
|
158
|
+
if (speed < vm)
|
|
159
|
+
speed += ACCEL;
|
|
160
|
+
} else if (in & IN_DOWN)
|
|
161
|
+
speed = speed > BRAKE ? speed - BRAKE : 0;
|
|
162
|
+
else
|
|
163
|
+
speed = speed > COAST ? speed - COAST : 0;
|
|
164
|
+
if (speed > vm)
|
|
165
|
+
speed = speed - OVERDRAG > vm ? speed - OVERDRAG : vm;
|
|
166
|
+
|
|
167
|
+
// 2. scroll accumulator: distance += speed (16.8)
|
|
168
|
+
unsigned t = dfrac + (speed & 0xff);
|
|
169
|
+
dfrac = (char)t;
|
|
170
|
+
dpix += (speed >> 8) + (t >> 8);
|
|
171
|
+
|
|
172
|
+
// 3. lateral velocity with grip, then position
|
|
173
|
+
int g = grip[surface];
|
|
174
|
+
if (speed >= STEER_MIN && (in & IN_LEFT))
|
|
175
|
+
vx -= steer[surface];
|
|
176
|
+
else if (speed >= STEER_MIN && (in & IN_RIGHT))
|
|
177
|
+
vx += steer[surface];
|
|
178
|
+
else if (vx > 0)
|
|
179
|
+
vx = vx > g ? vx - g : 0;
|
|
180
|
+
else if (vx < 0)
|
|
181
|
+
vx = -vx > g ? vx + g : 0;
|
|
182
|
+
if (vx > VXMAX)
|
|
183
|
+
vx = VXMAX;
|
|
184
|
+
else if (vx < -VXMAX)
|
|
185
|
+
vx = -VXMAX;
|
|
186
|
+
x_fp += vx;
|
|
187
|
+
|
|
188
|
+
// 4. surface probe: four wheels, the worst class wins
|
|
189
|
+
char px = x_fp >> 8;
|
|
190
|
+
unsigned w = BASE * 8 + CAR_Y - dpix;
|
|
191
|
+
const char *rf = Map + rowoff[(w + WHEEL_F) >> 3];
|
|
192
|
+
const char *rb = Map + rowoff[(w + WHEEL_B) >> 3];
|
|
193
|
+
char c = tile_class(rf, px + WHEEL_L), k;
|
|
194
|
+
k = tile_class(rf, px + WHEEL_R); if (k > c) c = k;
|
|
195
|
+
k = tile_class(rb, px + WHEEL_L); if (k > c) c = k;
|
|
196
|
+
k = tile_class(rb, px + WHEEL_R); if (k > c) c = k;
|
|
197
|
+
|
|
198
|
+
// 5. response
|
|
199
|
+
if (c == C_CRASH) {
|
|
200
|
+
crash_t = CRASH_FRAMES;
|
|
201
|
+
speed = 0;
|
|
202
|
+
vx = 0;
|
|
203
|
+
crashes++;
|
|
204
|
+
} else
|
|
205
|
+
surface = c;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// --- the redraw (belongs to the scroll, not to the car) ---------------------
|
|
209
|
+
// Copies 250 * blocks bytes: the whole matrix is 4 blocks, half is 2.
|
|
210
|
+
static void draw(char *dst, const char *src, char blocks)
|
|
211
|
+
{
|
|
212
|
+
for (char b = 0; b < blocks; b++) {
|
|
213
|
+
for (char i = 0; i < 250; i++)
|
|
214
|
+
dst[i] = src[i];
|
|
215
|
+
dst += 250;
|
|
216
|
+
src += 250;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
static void build_map(void)
|
|
221
|
+
{
|
|
222
|
+
char r = MAP_H - 1;
|
|
223
|
+
for (char s = 0; s < NSEGS; s++) {
|
|
224
|
+
const struct Seg *g = segs + s;
|
|
225
|
+
char mid = (g->left + g->right) >> 1;
|
|
226
|
+
for (char n = 0; n < g->rows; n++) {
|
|
227
|
+
char *m = Map + (unsigned)r * 40;
|
|
228
|
+
for (char c = 0; c < 40; c++) {
|
|
229
|
+
char t;
|
|
230
|
+
if (g->water)
|
|
231
|
+
t = (c >= g->left && c < g->right) ? 0xa0 : 0xe0;
|
|
232
|
+
else if (c + g->verge < g->left || c >= g->right + g->verge)
|
|
233
|
+
t = 0xe0;
|
|
234
|
+
else if (c < g->left || c >= g->right)
|
|
235
|
+
t = 0x60;
|
|
236
|
+
else if (c == mid && (r & 3) < 2)
|
|
237
|
+
t = 0x3a; // ':' lane mark, road class
|
|
238
|
+
else
|
|
239
|
+
t = 0x20;
|
|
240
|
+
m[c] = t;
|
|
241
|
+
}
|
|
242
|
+
centre[r] = mid;
|
|
243
|
+
r--;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
for (char i = 0; i < MAP_H; i++)
|
|
247
|
+
rowoff[i] = (unsigned)i * 40;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// --- CIA1 timer B harness (as tile-grid-collision.md) -----------------------
|
|
251
|
+
static inline void timer_start(void)
|
|
252
|
+
{
|
|
253
|
+
cia1.crb = 0x00;
|
|
254
|
+
cia1.tb = 0xffff;
|
|
255
|
+
cia1.crb = 0x11;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
static inline unsigned timer_stop(void)
|
|
259
|
+
{
|
|
260
|
+
cia1.crb = 0x00;
|
|
261
|
+
return 0xffff - cia1.tb;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
static unsigned fold(unsigned chk, unsigned v)
|
|
265
|
+
{
|
|
266
|
+
chk = (chk << 1) | (chk >> 15);
|
|
267
|
+
return (chk ^ v) + 13;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
void put_str(char *p, const char *s)
|
|
271
|
+
{
|
|
272
|
+
while (*s)
|
|
273
|
+
*p++ = *s++;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
void put_dec(char *p, unsigned v, char digits)
|
|
277
|
+
{
|
|
278
|
+
for (char i = digits; i > 0; i--) {
|
|
279
|
+
p[i - 1] = 0x30 + v % 10;
|
|
280
|
+
v /= 10;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
void put_hex4(char *p, unsigned v)
|
|
285
|
+
{
|
|
286
|
+
for (char i = 4; i > 0; i--) {
|
|
287
|
+
char d = v & 15;
|
|
288
|
+
p[i - 1] = d < 10 ? 0x30 + d : d - 9;
|
|
289
|
+
v >>= 4;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
static char car_colour(void)
|
|
294
|
+
{
|
|
295
|
+
return crash_t ? VCOL_WHITE : surface == C_WATER ? VCOL_YELLOW : VCOL_RED;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
int main(void)
|
|
299
|
+
{
|
|
300
|
+
__asm { sei }
|
|
301
|
+
vic.color_border = VCOL_BLACK;
|
|
302
|
+
vic.color_back = VCOL_DARK_GREY; // road
|
|
303
|
+
vic.color_back1 = VCOL_GREEN; // verge
|
|
304
|
+
vic.color_back2 = VCOL_BLUE; // water
|
|
305
|
+
vic.color_back3 = VCOL_BROWN; // rock
|
|
306
|
+
for (unsigned i = 0; i < 1000; i++)
|
|
307
|
+
Color[i] = VCOL_WHITE;
|
|
308
|
+
build_map();
|
|
309
|
+
|
|
310
|
+
for (char i = 0; i < 63; i++)
|
|
311
|
+
SprData[i] = (i % 3 == 2) ? 0x00 : 0xff; // 16 x 21 block
|
|
312
|
+
Screen0[0x3f8] = 13;
|
|
313
|
+
Screen1[0x3f8] = 13;
|
|
314
|
+
vic.spr_enable = 0x01;
|
|
315
|
+
vic.spr_pos[0].y = 47 + CAR_Y; // drawn from line 48 + CAR_Y
|
|
316
|
+
|
|
317
|
+
x_fp = (unsigned)(centre[MAP_H - 1] * 8 - 8) << 8;
|
|
318
|
+
char top = BASE, shown = BASE, target = BASE - 1, half = 0, refused = 0;
|
|
319
|
+
draw(Screen0, Map + rowoff[BASE], 4);
|
|
320
|
+
char *back = Screen1;
|
|
321
|
+
char d018 = 0x14, d011 = 0x50; // screen $0400, chars $1000; ECM, DEN, RSEL 0
|
|
322
|
+
unsigned sx = (x_fp >> 8) + 24;
|
|
323
|
+
char scol = car_colour();
|
|
324
|
+
|
|
325
|
+
unsigned chk = 0, t_max = 0, t_at = 0, n_drive = 0, c_max = 0, f_max = 0;
|
|
326
|
+
unsigned long t_sum = 0;
|
|
327
|
+
char seen = 0;
|
|
328
|
+
unsigned frames = 0;
|
|
329
|
+
cia2.cra = 0x00;
|
|
330
|
+
|
|
331
|
+
for (char s = 0; s < STEPS; s++) {
|
|
332
|
+
for (char n = 0; n < script[s].frames; n++) {
|
|
333
|
+
vic_waitFrame(); // line 256: below the display
|
|
334
|
+
cia2.ta = 0xffff;
|
|
335
|
+
cia2.cra = 0x11; // whole-frame work timer
|
|
336
|
+
vic.memptr = d018;
|
|
337
|
+
vic.ctrl1 = d011;
|
|
338
|
+
vic.spr_pos[0].x = (char)sx;
|
|
339
|
+
vic.spr_msbx = sx >> 8;
|
|
340
|
+
vic.spr_color[0] = scol;
|
|
341
|
+
|
|
342
|
+
timer_start();
|
|
343
|
+
car_update(script[s].input);
|
|
344
|
+
unsigned t = timer_stop();
|
|
345
|
+
if (t > t_max) {
|
|
346
|
+
t_max = t;
|
|
347
|
+
t_at = frames;
|
|
348
|
+
}
|
|
349
|
+
if (!crash_t) { // typical: frames the car drives
|
|
350
|
+
t_sum += t;
|
|
351
|
+
n_drive++;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
char st = surface | (crash_t ? 0x10 : 0);
|
|
355
|
+
seen |= crash_t ? 0x10 : 1 << surface;
|
|
356
|
+
chk = fold(chk, x_fp);
|
|
357
|
+
chk = fold(chk, speed);
|
|
358
|
+
chk = fold(chk, dpix);
|
|
359
|
+
chk = fold(chk, st);
|
|
360
|
+
|
|
361
|
+
// Scroll: the top row and YSCROLL follow the distance. The
|
|
362
|
+
// hidden matrix is drawn for the next top row (one map row
|
|
363
|
+
// further ahead), half a matrix a frame, and flipped in when
|
|
364
|
+
// the top row reaches it.
|
|
365
|
+
top = BASE - (dpix >> 3);
|
|
366
|
+
if (top != shown) {
|
|
367
|
+
if (top == target && half == 2) {
|
|
368
|
+
d018 = (back == Screen1) ? 0xf4 : 0x14;
|
|
369
|
+
back = (back == Screen1) ? Screen0 : Screen1;
|
|
370
|
+
shown = top;
|
|
371
|
+
target = top - 1;
|
|
372
|
+
half = 0;
|
|
373
|
+
} else
|
|
374
|
+
refused++; // would show a wrong row
|
|
375
|
+
}
|
|
376
|
+
if (half < 2) {
|
|
377
|
+
timer_start();
|
|
378
|
+
draw(back + half * 500, Map + rowoff[target] + half * 500, 2);
|
|
379
|
+
unsigned tc = timer_stop();
|
|
380
|
+
if (tc > c_max) c_max = tc;
|
|
381
|
+
half++;
|
|
382
|
+
}
|
|
383
|
+
d011 = 0x50 | (dpix & 7);
|
|
384
|
+
sx = (x_fp >> 8) + 24;
|
|
385
|
+
scol = car_colour();
|
|
386
|
+
frames++;
|
|
387
|
+
|
|
388
|
+
cia2.cra = 0x00;
|
|
389
|
+
unsigned tf = 0xffff - cia2.ta;
|
|
390
|
+
if (tf > f_max) f_max = tf;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
vic_waitFrame(); // show the last state
|
|
395
|
+
vic.memptr = d018;
|
|
396
|
+
vic.ctrl1 = d011;
|
|
397
|
+
vic.spr_pos[0].x = (char)sx;
|
|
398
|
+
vic.spr_msbx = sx >> 8;
|
|
399
|
+
vic.spr_color[0] = scol;
|
|
400
|
+
|
|
401
|
+
bool ok = chk == EXPECT_CHK && x_fp == EXPECT_X && speed == EXPECT_SPEED &&
|
|
402
|
+
dpix == EXPECT_DPIX && seen == EXPECT_SEEN && crashes == 1 &&
|
|
403
|
+
refused == 0;
|
|
404
|
+
char *scr = (d018 == 0x14) ? Screen0 : Screen1;
|
|
405
|
+
put_str(scr + 40, ok ? s"pass chk " : s"fail chk ");
|
|
406
|
+
put_hex4(scr + 49, chk);
|
|
407
|
+
put_str(scr + 54, s"frames ");
|
|
408
|
+
put_dec(scr + 61, frames, 3);
|
|
409
|
+
put_str(scr + 80, s"ctl max avg");
|
|
410
|
+
put_dec(scr + 88, t_max, 5);
|
|
411
|
+
put_dec(scr + 98, (unsigned)(t_sum / n_drive), 5);
|
|
412
|
+
put_str(scr + 104, s"at");
|
|
413
|
+
put_dec(scr + 107, t_at, 3);
|
|
414
|
+
put_str(scr + 120, s"cpy max frm");
|
|
415
|
+
put_dec(scr + 128, c_max, 5);
|
|
416
|
+
put_dec(scr + 138, f_max, 5);
|
|
417
|
+
RESULT = ok ? CODE_PASS : CODE_FAIL;
|
|
418
|
+
vic.color_border = ok ? VCOL_GREEN : VCOL_RED;
|
|
419
|
+
for (;;)
|
|
420
|
+
;
|
|
421
|
+
return 0;
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
## Build
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
oscar64 -tm=c64 -O2 -o=vehicle-control.prg vehicle-control.c
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Produces `vehicle-control.prg`, 3,165 bytes (Oscar64 as installed on
|
|
432
|
+
2026-09-23). Then run headless in VICE (PAL):
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
GSETTINGS_SCHEMA_DIR=/opt/homebrew/share/glib-2.0/schemas x64sc -default -warp +sound \
|
|
436
|
+
+autostart-delay-random -autostartprgmode 1 -limitcycles 16000000 \
|
|
437
|
+
-exitscreenshot vehicle-control.png -autostart vehicle-control.prg
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Add `-model ntsc` for the NTSC picture. The script is 508 frames on both
|
|
441
|
+
models; at 16,000,000 cycles the run is over on both and the picture is
|
|
442
|
+
the last frame.
|
|
443
|
+
|
|
444
|
+
## Expected output
|
|
445
|
+
|
|
446
|
+
The screen is in extended colour mode (ECM), so bits 7 and 6 of each
|
|
447
|
+
tile code pick the cell's background register and are also the surface
|
|
448
|
+
class the probes read. Colour RAM is white everywhere and never changes.
|
|
449
|
+
|
|
450
|
+
| Tile code | Class | Background | Colour |
|
|
451
|
+
|---|---|---|---|
|
|
452
|
+
| `$20`, `$3A` (`:` lane mark) | road | `$D021` | dark grey, 11 |
|
|
453
|
+
| `$60` | verge | `$D022` | green, 5 |
|
|
454
|
+
| `$A0` | water | `$D023` | blue, 6 |
|
|
455
|
+
| `$E0` | rock | `$D024` | brown, 9 |
|
|
456
|
+
|
|
457
|
+
The map is 220 rows of 40 tiles, built at start from seven segments and
|
|
458
|
+
driven from the bottom up: 60 rows of road 16 tiles wide with 3-tile
|
|
459
|
+
verges, two 6-row steps in, 30 rows 8 tiles wide with 2-tile verges (the
|
|
460
|
+
narrowing), 8 rows at 14 wide, 50 rows of water 20 tiles wide between
|
|
461
|
+
rock banks, and 60 rows of road. The car is a 16 x 21 block: red on the
|
|
462
|
+
road and verge, yellow on water, white while crashed.
|
|
463
|
+
|
|
464
|
+
The script, as the model and the program both run it:
|
|
465
|
+
|
|
466
|
+
| Frames | Input | What happens |
|
|
467
|
+
|---|---|---|
|
|
468
|
+
| 0 to 59 | up | accelerates from 0 to 2.81 pixels a frame (`$02D0`), straight |
|
|
469
|
+
| 60 to 99 | up, left | reaches the road limit, 4.0 (`$0400`); slides left |
|
|
470
|
+
| 100 to 139 | up | onto the left verge at frame 108, x 94. Up adds nothing at or over the limit, so the over-limit drag takes 0.06 (`$0010`) a frame off: 4.0 at frame 108, 1.5 (`$0180`) at frame 148 |
|
|
471
|
+
| 140 to 179 | up, right | back onto the road at frame 152, x 95, and across it |
|
|
472
|
+
| 180 to 209 | up | grip takes the slide out; back to 4.0 at x 152 |
|
|
473
|
+
| 210 to 239 | up, left | slides left at 4.0; lateral speed at its cap, 1.5, from frame 229; onto the narrowing's left verge at frame 235, x 126 |
|
|
474
|
+
| 240 to 246 | down | brake: 0.13 (`$0020`) plus the over-limit drag a frame; the stick is centred, so grip slows the slide left |
|
|
475
|
+
| 247 | down | the left wheels reach rock at x 110 with the speed still over the verge limit: crash, speed 0, the one crash of the run |
|
|
476
|
+
| 248 to 297 | (ignored) | crashed; the road stands still; at frame 297 the timer ends and the car restarts at x 152, on the narrowing's centre line |
|
|
477
|
+
| 298 to 299 | down | brake at speed 0: the speed stays 0 |
|
|
478
|
+
| 300 to 359 | up | accelerates to 2.81 (`$02D0`) |
|
|
479
|
+
| 360 to 379 | none | coast: 0.008 (`$0002`) a frame off, to `$02A8` |
|
|
480
|
+
| 380 to 507 | up, then left, up, right, up | the front wheels reach water at frame 382; boat: limit 3.0 (`$0300`), steering 0.03 a frame, grip 0.01 a frame, so the drift outlasts the input |
|
|
481
|
+
|
|
482
|
+
The end state, from the model: x `$91FE` (pixel 145), speed `$0300`,
|
|
483
|
+
distance 1,210 pixels, so the top row is map row 44 and YSCROLL is 2,
|
|
484
|
+
and the checksum is `$2B51`.
|
|
485
|
+
|
|
486
|
+
Measured in VICE x64sc 3.10 at 16,000,000 cycles, decoded against the
|
|
487
|
+
char ROM: rows 1 to 3 read
|
|
488
|
+
|
|
489
|
+
```text
|
|
490
|
+
PASS CHK 2B51 FRAMES 508
|
|
491
|
+
CTL MAX 00655 AVG 00557 AT 247
|
|
492
|
+
CPY MAX 10110 FRM 11393
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
on PAL; NTSC is the same except `CPY MAX 10368 FRM 11640`. The border
|
|
496
|
+
is colour 5 on both. `CTL MAX` is the worst frame of `car_update`, 655
|
|
497
|
+
cycles, at frame 247: the crash frame, which runs the brake, the verge
|
|
498
|
+
over-limit drag, the grip step on a slide to the left, the four probes
|
|
499
|
+
and the crash response. The script puts that frame there on purpose: it
|
|
500
|
+
is the longest path through `car_update`. `AVG` is the mean over the 458
|
|
501
|
+
frames the car was not crashed, 557. Both are the same on the two
|
|
502
|
+
models because the update runs from line 256, before the first badline,
|
|
503
|
+
on both. A build whose code is laid out differently can move them by a
|
|
504
|
+
cycle (656 and 558 in a variant with a different redraw call). `CPY MAX`
|
|
505
|
+
is the worst half-matrix redraw, which runs with the display on, and
|
|
506
|
+
`FRM` the worst frame's whole work from line 256 to the end of the loop
|
|
507
|
+
body; 11,640 is 68% of an NTSC frame (17,095 cycles), so no frame
|
|
508
|
+
overran.
|
|
509
|
+
|
|
510
|
+
`screenshots/vehicle-control.png` (PAL) and
|
|
511
|
+
`screenshots/vehicle-control-ntsc.png` (NTSC) are the exit screenshots
|
|
512
|
+
at 16,000,000 cycles. Measured on the PNGs: the car's 336 yellow pixels
|
|
513
|
+
are a 16 x 21 block at PNG x 177 to 192, which is car x 145, from raster
|
|
514
|
+
line 198 (PNG row 182 on PAL, 170 on NTSC). Every other pixel of the
|
|
515
|
+
display window outside rows 1 to 3, 53,424 of them, matches the colour
|
|
516
|
+
predicted from the model's map at distance 1,210 and YSCROLL 2, with the
|
|
517
|
+
`:` glyphs taken from `chargen-901225-01.bin`: 0 mismatches on each
|
|
518
|
+
model. The picture shows the end of the water stretch: road with its
|
|
519
|
+
lane mark and verges above, the rock bank, and the boat in the water.
|
|
520
|
+
|
|
521
|
+
### Model
|
|
522
|
+
|
|
523
|
+
The Python the checksum came from. It builds the same map and runs the
|
|
524
|
+
same rules; `run()` returns the end state and the fold.
|
|
525
|
+
|
|
526
|
+
```python
|
|
527
|
+
# Model of vehicle-control.c: same map, same rules, same fold.
|
|
528
|
+
import sys
|
|
529
|
+
|
|
530
|
+
MAP_H, W = 220, 40
|
|
531
|
+
BASE = MAP_H - 25
|
|
532
|
+
CAR_Y = 150 # car top, text-area pixel row (line 48 + CAR_Y)
|
|
533
|
+
WHEEL_L, WHEEL_R = 1, 14 # wheel columns in the 16-px body
|
|
534
|
+
WHEEL_F, WHEEL_B = 3, 17 # wheel rows below the car top
|
|
535
|
+
C_ROAD, C_VERGE, C_WATER, C_CRASH = 0, 1, 2, 3
|
|
536
|
+
UP, DOWN, LEFT, RIGHT = 1, 2, 4, 8
|
|
537
|
+
|
|
538
|
+
ACCEL, BRAKE, COAST, OVERDRAG = 0x000C, 0x0020, 0x0002, 0x0010
|
|
539
|
+
STEER_MIN, VXMAX = 0x0040, 0x0180
|
|
540
|
+
VMAX = [0x0400, 0x0180, 0x0300, 0]
|
|
541
|
+
STEER = [0x0014, 0x0014, 0x0008, 0]
|
|
542
|
+
GRIP = [0x0010, 0x0010, 0x0003, 0]
|
|
543
|
+
CRASH_FRAMES = 50
|
|
544
|
+
|
|
545
|
+
# Segments in driving order from the bottom of the map:
|
|
546
|
+
# rows, road left col, road right col (exclusive), verge width, kind (0 road, 1 water)
|
|
547
|
+
SEGS = [
|
|
548
|
+
(60, 12, 28, 3, 0),
|
|
549
|
+
(6, 13, 27, 3, 0),
|
|
550
|
+
(6, 14, 26, 3, 0),
|
|
551
|
+
(30, 16, 24, 2, 0),
|
|
552
|
+
(8, 13, 27, 3, 0),
|
|
553
|
+
(50, 10, 30, 0, 1),
|
|
554
|
+
(60, 12, 28, 3, 0),
|
|
555
|
+
]
|
|
556
|
+
|
|
557
|
+
SCRIPT = [
|
|
558
|
+
(60, UP),
|
|
559
|
+
(40, UP | LEFT),
|
|
560
|
+
(40, UP),
|
|
561
|
+
(40, UP | RIGHT),
|
|
562
|
+
(30, UP),
|
|
563
|
+
(30, UP | LEFT),
|
|
564
|
+
(60, DOWN),
|
|
565
|
+
(60, UP),
|
|
566
|
+
(20, 0),
|
|
567
|
+
(60, UP),
|
|
568
|
+
(14, UP | LEFT),
|
|
569
|
+
(30, UP),
|
|
570
|
+
(14, UP | RIGHT),
|
|
571
|
+
(10, UP),
|
|
572
|
+
]
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
def build():
|
|
576
|
+
m = bytearray(MAP_H * W)
|
|
577
|
+
centre = bytearray(MAP_H)
|
|
578
|
+
r = MAP_H - 1
|
|
579
|
+
for rows, rl, rr, v, kind in SEGS:
|
|
580
|
+
for _ in range(rows):
|
|
581
|
+
for c in range(W):
|
|
582
|
+
if kind:
|
|
583
|
+
t = 0xA0 if rl <= c < rr else 0xE0
|
|
584
|
+
elif c < rl - v or c >= rr + v:
|
|
585
|
+
t = 0xE0
|
|
586
|
+
elif c < rl or c >= rr:
|
|
587
|
+
t = 0x60
|
|
588
|
+
elif c == (rl + rr) >> 1 and (r & 3) < 2:
|
|
589
|
+
t = 0x3A
|
|
590
|
+
else:
|
|
591
|
+
t = 0x20
|
|
592
|
+
m[r * W + c] = t
|
|
593
|
+
centre[r] = (rl + rr) >> 1
|
|
594
|
+
r -= 1
|
|
595
|
+
assert r == -1
|
|
596
|
+
return m, centre
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
MAP, CENTRE = build()
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
class Car:
|
|
603
|
+
def __init__(s):
|
|
604
|
+
s.x = (CENTRE[MAP_H - 1] * 8 - 8) << 8
|
|
605
|
+
s.vx = 0
|
|
606
|
+
s.speed = 0
|
|
607
|
+
s.dfrac = 0
|
|
608
|
+
s.dpix = 0
|
|
609
|
+
s.surface = C_ROAD
|
|
610
|
+
s.crash_t = 0
|
|
611
|
+
s.crashes = 0
|
|
612
|
+
|
|
613
|
+
def cls(s, px, yy):
|
|
614
|
+
w = BASE * 8 + yy - s.dpix
|
|
615
|
+
return MAP[(w >> 3) * W + (px >> 3)] >> 6
|
|
616
|
+
|
|
617
|
+
def update(s, inp):
|
|
618
|
+
if s.crash_t:
|
|
619
|
+
s.crash_t -= 1
|
|
620
|
+
if s.crash_t == 0:
|
|
621
|
+
row = (BASE * 8 + CAR_Y + WHEEL_F - s.dpix) >> 3
|
|
622
|
+
s.x = (CENTRE[row] * 8 - 8) << 8
|
|
623
|
+
s.surface = C_ROAD
|
|
624
|
+
return
|
|
625
|
+
# speed
|
|
626
|
+
vm = VMAX[s.surface]
|
|
627
|
+
if inp & UP:
|
|
628
|
+
if s.speed < vm:
|
|
629
|
+
s.speed += ACCEL
|
|
630
|
+
elif inp & DOWN:
|
|
631
|
+
s.speed = s.speed - BRAKE if s.speed > BRAKE else 0
|
|
632
|
+
else:
|
|
633
|
+
s.speed = s.speed - COAST if s.speed > COAST else 0
|
|
634
|
+
if s.speed > vm:
|
|
635
|
+
s.speed = s.speed - OVERDRAG if s.speed - OVERDRAG > vm else vm
|
|
636
|
+
# scroll accumulator
|
|
637
|
+
t = s.dfrac + (s.speed & 0xFF)
|
|
638
|
+
s.dfrac = t & 0xFF
|
|
639
|
+
s.dpix += (s.speed >> 8) + (t >> 8)
|
|
640
|
+
# lateral
|
|
641
|
+
su = s.surface
|
|
642
|
+
if s.speed >= STEER_MIN and inp & LEFT:
|
|
643
|
+
s.vx -= STEER[su]
|
|
644
|
+
elif s.speed >= STEER_MIN and inp & RIGHT:
|
|
645
|
+
s.vx += STEER[su]
|
|
646
|
+
elif s.vx > 0:
|
|
647
|
+
s.vx = s.vx - GRIP[su] if s.vx > GRIP[su] else 0
|
|
648
|
+
elif s.vx < 0:
|
|
649
|
+
s.vx = s.vx + GRIP[su] if -s.vx > GRIP[su] else 0
|
|
650
|
+
if s.vx > VXMAX:
|
|
651
|
+
s.vx = VXMAX
|
|
652
|
+
if s.vx < -VXMAX:
|
|
653
|
+
s.vx = -VXMAX
|
|
654
|
+
s.x = (s.x + s.vx) & 0xFFFF
|
|
655
|
+
# surface probe: four wheels, worst class wins
|
|
656
|
+
px = s.x >> 8
|
|
657
|
+
c = max(s.cls(px + WHEEL_L, CAR_Y + WHEEL_F), s.cls(px + WHEEL_R, CAR_Y + WHEEL_F),
|
|
658
|
+
s.cls(px + WHEEL_L, CAR_Y + WHEEL_B), s.cls(px + WHEEL_R, CAR_Y + WHEEL_B))
|
|
659
|
+
# response
|
|
660
|
+
if c == C_CRASH:
|
|
661
|
+
s.crash_t = CRASH_FRAMES
|
|
662
|
+
s.speed = 0
|
|
663
|
+
s.vx = 0
|
|
664
|
+
s.crashes += 1
|
|
665
|
+
else:
|
|
666
|
+
s.surface = c
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
def rol_fold(chk, v):
|
|
670
|
+
chk = ((chk << 1) | (chk >> 15)) & 0xFFFF
|
|
671
|
+
return ((chk ^ v) + 13) & 0xFFFF
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
def run(verbose=False):
|
|
675
|
+
car = Car()
|
|
676
|
+
chk = 0
|
|
677
|
+
f = 0
|
|
678
|
+
seen = 0
|
|
679
|
+
for n, inp in SCRIPT:
|
|
680
|
+
for _ in range(n):
|
|
681
|
+
car.update(inp)
|
|
682
|
+
st = car.surface | (0x10 if car.crash_t else 0)
|
|
683
|
+
seen |= 1 << (4 if car.crash_t else car.surface)
|
|
684
|
+
for v in (car.x, car.speed, car.dpix, st):
|
|
685
|
+
chk = rol_fold(chk, v)
|
|
686
|
+
if verbose:
|
|
687
|
+
print(f, hex(inp), 'x', car.x >> 8, hex(car.x & 255), 'sp', hex(car.speed), 'vx', car.vx,
|
|
688
|
+
'd', car.dpix, 'surf', car.surface, 'crash', car.crash_t)
|
|
689
|
+
f += 1
|
|
690
|
+
return car, chk, f, seen
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
if __name__ == '__main__':
|
|
694
|
+
car, chk, f, seen = run('-v' in sys.argv)
|
|
695
|
+
top = BASE - (car.dpix >> 3)
|
|
696
|
+
print('frames', f, 'chk %04X' % chk, 'x %04X' % car.x, 'speed %04X' % car.speed, 'dpix', car.dpix,
|
|
697
|
+
'top', top, 'yscroll', car.dpix & 7, 'crashes', car.crashes, 'seen %02X' % seen)
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
## Why this works
|
|
701
|
+
|
|
702
|
+
The distance is a 16.8 number: a whole-pixel word `dpix` and a fraction
|
|
703
|
+
byte. Each frame adds the speed, and the carry out of the fraction byte
|
|
704
|
+
moves into the pixel word, so 2.81 pixels a frame advances 2 or 3 pixels
|
|
705
|
+
and never drifts. The scroll follows from the distance and nothing else:
|
|
706
|
+
the top map row on screen is `BASE - (dpix >> 3)` and YSCROLL is
|
|
707
|
+
`dpix & 7`, so the probes and the picture cannot disagree. The screen
|
|
708
|
+
pixel `yy` lines below line 48 shows map pixel row
|
|
709
|
+
`BASE * 8 + yy - dpix`, which is what the probes index. With RSEL 0 the
|
|
710
|
+
25-row matrix covers the 24-row window at every YSCROLL.
|
|
711
|
+
|
|
712
|
+
The probes are two map rows, looked up once through a row-offset table,
|
|
713
|
+
and two columns in each, the wheel points of a 16-pixel body. The worst
|
|
714
|
+
class of the four wins (rock over water over verge over road), so one
|
|
715
|
+
wheel on the verge slows the car and one wheel on rock crashes it. The
|
|
716
|
+
class is the tile code shifted right six times; in ECM the same two bits
|
|
717
|
+
pick the background colour, so the drawing and the rule come from one
|
|
718
|
+
byte. A lateral speed of at most 1.5 pixels a frame and a forward speed
|
|
719
|
+
of at most 4 are both under a tile, so no probe steps over a tile
|
|
720
|
+
between frames.
|
|
721
|
+
|
|
722
|
+
Up adds the acceleration only below the surface's limit. Over it, the
|
|
723
|
+
over-limit drag is the only change, so a car that runs onto the verge
|
|
724
|
+
with the throttle held slows by 0.06 a frame, from 4.0 to 1.5 in 40
|
|
725
|
+
frames. If up still added its 0.05 the net fall would be 0.016 a frame,
|
|
726
|
+
160 frames to reach 1.5 (arithmetic), and the verge would barely slow a
|
|
727
|
+
car at full throttle.
|
|
728
|
+
|
|
729
|
+
The sprite's Y register is set to `47 + CAR_Y` because a sprite at Y
|
|
730
|
+
register n is drawn from raster line n + 1: the first build used
|
|
731
|
+
`48 + CAR_Y` and the PNG check found the car one line below the model's
|
|
732
|
+
probe rows, 16 mismatched pixels on each model.
|
|
733
|
+
|
|
734
|
+
The redraw is the scroll's work, not the car's. A crossing needs the
|
|
735
|
+
whole matrix rewritten one row lower. At up to 4 pixels a frame
|
|
736
|
+
crossings are at least two frames apart, so the hidden matrix is drawn
|
|
737
|
+
for the next top row half a matrix a frame, 10,110 cycles on PAL and
|
|
738
|
+
10,368 on NTSC, and `$D018` flips to it on the first frame the top row
|
|
739
|
+
equals it. A variant of this listing that copies the whole matrix in
|
|
740
|
+
one frame measured 20,330 cycles on PAL and 20,414 on NTSC, more than a
|
|
741
|
+
frame on either (19,656 and 17,095). `refused`
|
|
742
|
+
counts crossings that arrive before the hidden matrix is ready; it is 0,
|
|
743
|
+
and the verdict requires that. Colour RAM needs no move because ECM
|
|
744
|
+
takes the colour from the tile code.
|
|
745
|
+
|
|
746
|
+
The speed is per frame, so on NTSC the road passes 20% faster in real
|
|
747
|
+
time for the same script; the checksum is the same on both models
|
|
748
|
+
because the logic runs once per frame on both.
|
|
749
|
+
|
|
750
|
+
## Verification
|
|
751
|
+
|
|
752
|
+
VICE x64sc 3.10, windowless build, Oscar64 as installed on 2026-09-23.
|
|
753
|
+
|
|
754
|
+
**Every pixel against the model.** A script predicted each pixel of the
|
|
755
|
+
display window (lines 55 to 246, 320 columns) from the model's map, the
|
|
756
|
+
end distance and YSCROLL, and the char ROM for the lane-mark glyph,
|
|
757
|
+
skipping the HUD rows and the sprite's box: 53,424 pixels, 0 mismatches
|
|
758
|
+
on PAL and on NTSC. The sprite's yellow pixels were located separately
|
|
759
|
+
and give car x 145, the model's value.
|
|
760
|
+
|
|
761
|
+
**Text and border.** Rows 1 to 3 were decoded against
|
|
762
|
+
`chargen-901225-01.bin` and read as quoted above; the border pixel is
|
|
763
|
+
colour 5 on each model.
|
|
764
|
+
|
|
765
|
+
**Reproducibility.** The pinned command was run twice per model; the
|
|
766
|
+
PNG bytes were identical each time.
|
|
767
|
+
|
|
768
|
+
## Sources
|
|
769
|
+
|
|
770
|
+
None. The map, the rules, the constants and the code are original; the
|
|
771
|
+
game style is named only as the brief for the design.
|