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,950 @@
|
|
|
1
|
+
---
|
|
2
|
+
recipe: car-contact
|
|
3
|
+
toolchain: oscar64
|
|
4
|
+
output_format: PRG
|
|
5
|
+
region: both
|
|
6
|
+
techniques: [car_contact_response]
|
|
7
|
+
file_formats: [PRG]
|
|
8
|
+
uses_registers: [D000, D001, D010, D011, D012, D015, D017, D01B, D01C, D01D, D020, D021, D027, DC06, DC07, DC0F]
|
|
9
|
+
uses_kernal: []
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!-- doc-type: recipe -->
|
|
13
|
+
|
|
14
|
+
# Oscar64 car contact: push apart on the shallow axis, trade velocity by mass, crash off the road
|
|
15
|
+
|
|
16
|
+
## Synopsis
|
|
17
|
+
|
|
18
|
+
A top-down road strip, grass on the left and water on the right, with six
|
|
19
|
+
cars on scripts: the player (white), three light cars and two trucks.
|
|
20
|
+
Every frame each pair of cars is tested; a pair that overlaps is pushed
|
|
21
|
+
apart along the axis where the overlap is smaller, and its velocities on
|
|
22
|
+
that axis are exchanged as an elastic collision between masses 1 and 7,
|
|
23
|
+
using shifts, not multiplies. After a hit both cars cool for eight frames,
|
|
24
|
+
during which that pair is still pushed apart but gets no second kick.
|
|
25
|
+
Then each car's centre is looked up in a tile map; a car on grass or water
|
|
26
|
+
has crashed and stops. One 256-frame pass holds five scenes: the player
|
|
27
|
+
side-swipes a light car into the water; a light car bumps another from
|
|
28
|
+
behind and hands over its speed; the player hits a truck that moves
|
|
29
|
+
5 pixels; a truck hits two light cars in the same frame and both go onto
|
|
30
|
+
the grass; and the player steers hard into the stopped truck, stays in
|
|
31
|
+
contact for nine frames with overlaps of 4 and 5 pixels, and shoves it
|
|
32
|
+
onto the grass. Every frame the cars' positions, velocities and crash
|
|
33
|
+
flags are folded into a checksum; the Python model on this page predicts
|
|
34
|
+
`$01E9` for the pass. At the end of each pass the program checks the
|
|
35
|
+
checksum, the hit count and the crash flags: `$02FF` = `01` and a green
|
|
36
|
+
border on a pass, `02` and red otherwise (`headless-verify.md`). The HUD
|
|
37
|
+
shows the cycles per pair, for two light cars and for a truck, and per
|
|
38
|
+
frame. This is the `car_contact_response` technique from
|
|
39
|
+
`docs/techniques/logic.md`.
|
|
40
|
+
|
|
41
|
+
## Source
|
|
42
|
+
|
|
43
|
+
```c
|
|
44
|
+
// car-contact.c
|
|
45
|
+
//
|
|
46
|
+
// Top-down road: grass left, water right, road between. Six cars on
|
|
47
|
+
// scripts: the player (white) and five enemies, three light and two heavy
|
|
48
|
+
// trucks. Each frame: scripts, move, then contact response for every pair
|
|
49
|
+
// (separate along the axis of least overlap, exchange velocity on that
|
|
50
|
+
// axis scaled by mass, no impulse while both cars are cooling), then a
|
|
51
|
+
// tile probe that crashes a car whose centre is off the road.
|
|
52
|
+
// Scenes in one 256-frame pass: the player side-swipes a light car into
|
|
53
|
+
// the water; a light car bumps another from behind; the player hits a
|
|
54
|
+
// truck that barely moves; a truck hits two light cars in one frame and
|
|
55
|
+
// both go onto the grass; the player holds its steering into a truck for
|
|
56
|
+
// nine frames of contact and shoves it onto the grass. Every frame the positions, velocities and crash
|
|
57
|
+
// flags are folded into a checksum that a Python model of the same rules
|
|
58
|
+
// predicts. At the end of a pass: $02FF = 01 and a green border on a pass,
|
|
59
|
+
// 02 and red on a fail.
|
|
60
|
+
//
|
|
61
|
+
#include <c64/vic.h>
|
|
62
|
+
#include <c64/cia.h>
|
|
63
|
+
|
|
64
|
+
#define Screen ((char *)0x0400)
|
|
65
|
+
#define Color ((char *)0xd800)
|
|
66
|
+
#define SprData ((char *)0x3000) // blocks 192, 193
|
|
67
|
+
#define SPR_BLK 192
|
|
68
|
+
#define VR ((volatile char *)0xd000)
|
|
69
|
+
#define PTR ((volatile char *)0x07f8)
|
|
70
|
+
#define RESULT (*(volatile char *)0x02ff)
|
|
71
|
+
|
|
72
|
+
// --- the road as a tile map: 0 road, 1 grass, 2 water -------------------
|
|
73
|
+
#define ROAD_L 9 // first road column
|
|
74
|
+
#define ROAD_R 26 // last road column
|
|
75
|
+
#define TOP_ROW 7 // rows 0-6 are the HUD
|
|
76
|
+
char tmap[25 * 40];
|
|
77
|
+
unsigned rowoff[25];
|
|
78
|
+
|
|
79
|
+
// --- cars, parallel arrays; x and y are 8.8, the centre of the body -----
|
|
80
|
+
#define MAXC 8
|
|
81
|
+
#define N_GAME 6
|
|
82
|
+
#define COOL 8 // frames without impulse after one
|
|
83
|
+
#define FR 4 // coasting drag, 1/256 px per frame
|
|
84
|
+
|
|
85
|
+
unsigned cx[MAXC], cy[MAXC];
|
|
86
|
+
int vx[MAXC], vy[MAXC];
|
|
87
|
+
char crash[MAXC], cool[MAXC], drv[MAXC];
|
|
88
|
+
char heavy[MAXC], hw[MAXC], hh[MAXC]; // mass class, half width, half height
|
|
89
|
+
char ncars;
|
|
90
|
+
char hits, contacts;
|
|
91
|
+
|
|
92
|
+
// --- scripts: vx, vy, frames, drive (1 holds the velocity, 0 coasts) ------
|
|
93
|
+
struct Step { int vx, vy; char n, drive; };
|
|
94
|
+
|
|
95
|
+
const struct Step s0[] = { {0,0,1,1}, {384,0,10,1}, {0,0,50,0}, {-383,0,16,1},
|
|
96
|
+
{0,0,93,0}, {-1536,0,12,1}, {0,0,0,0} };
|
|
97
|
+
const struct Step s1[] = { {0,0,1,1}, {0,0,0,0} };
|
|
98
|
+
const struct Step s3[] = { {0,0,1,1}, {0,0,0,0} };
|
|
99
|
+
const struct Step s4[] = { {0,0,1,1}, {0,-192,33,1}, {0,0,30,0}, {0,-128,28,1},
|
|
100
|
+
{0,0,1,1}, {0,0,0,0} };
|
|
101
|
+
const struct Step s5[] = { {0,0,120,1}, {-384,0,1,1}, {0,0,0,0} };
|
|
102
|
+
const struct Step *const scripts[N_GAME] = { s0, s1, s1, s3, s4, s5 };
|
|
103
|
+
char sstep[N_GAME], sleft[N_GAME];
|
|
104
|
+
|
|
105
|
+
const unsigned start_x[N_GAME] = { 160 << 8, 185 << 8, 140 << 8, 120 << 8, 120 << 8, 165 << 8 };
|
|
106
|
+
const unsigned start_y[N_GAME] = { 200 << 8, 196 << 8, 200 << 8, 150 << 8, 190 << 8, 142 << 8 };
|
|
107
|
+
const char kind[N_GAME] = { 0, 0, 1, 0, 0, 1 }; // 1 truck
|
|
108
|
+
const char col[N_GAME] = { 1, 7, 8, 3, 13, 4 };
|
|
109
|
+
|
|
110
|
+
void set_kind(char c, char k)
|
|
111
|
+
{
|
|
112
|
+
heavy[c] = k;
|
|
113
|
+
hw[c] = k ? 7 : 5;
|
|
114
|
+
hh[c] = k ? 10 : 8;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// --- mass: who takes how much of a push and of an impulse -----------------
|
|
118
|
+
// Light and heavy are masses 1 and 7. A push of pen pixels is split
|
|
119
|
+
// equally between equal masses; otherwise the heavy car takes pen >> 2.
|
|
120
|
+
// The velocity change on the contact axis is the elastic one for those
|
|
121
|
+
// masses: j gains g, i loses 2rv - g, with g = rv (equal), rv >> 2 (j
|
|
122
|
+
// heavy) or 2rv - (rv >> 2) (i heavy). No multiply.
|
|
123
|
+
|
|
124
|
+
void pair(char i, char j)
|
|
125
|
+
{
|
|
126
|
+
char yi = cy[i] >> 8, yj = cy[j] >> 8;
|
|
127
|
+
char ady = yj >= yi ? yj - yi : yi - yj;
|
|
128
|
+
char sy = hh[i] + hh[j];
|
|
129
|
+
if (ady >= sy)
|
|
130
|
+
return; // apart in Y: most pairs end here
|
|
131
|
+
char xi = cx[i] >> 8, xj = cx[j] >> 8;
|
|
132
|
+
char adx = xj >= xi ? xj - xi : xi - xj;
|
|
133
|
+
char sx = hw[i] + hw[j];
|
|
134
|
+
if (adx >= sx)
|
|
135
|
+
return;
|
|
136
|
+
contacts++;
|
|
137
|
+
char ox = sx - adx, oy = sy - ady;
|
|
138
|
+
bool xaxis = ox < oy;
|
|
139
|
+
char pen = xaxis ? ox : oy;
|
|
140
|
+
char ai, aj;
|
|
141
|
+
if (heavy[i] == heavy[j]) {
|
|
142
|
+
ai = pen >> 1; aj = pen - ai;
|
|
143
|
+
} else if (heavy[i]) {
|
|
144
|
+
ai = pen >> 2; aj = pen - ai;
|
|
145
|
+
} else {
|
|
146
|
+
aj = pen >> 2; ai = pen - aj;
|
|
147
|
+
}
|
|
148
|
+
bool jpos = xaxis ? xj >= xi : yj >= yi; // j lies on the + side of i
|
|
149
|
+
unsigned *p = xaxis ? cx : cy;
|
|
150
|
+
int *v = xaxis ? vx : vy;
|
|
151
|
+
if (jpos) {
|
|
152
|
+
p[i] -= (unsigned)ai << 8; p[j] += (unsigned)aj << 8;
|
|
153
|
+
} else {
|
|
154
|
+
p[i] += (unsigned)ai << 8; p[j] -= (unsigned)aj << 8;
|
|
155
|
+
}
|
|
156
|
+
int rv = v[i] - v[j];
|
|
157
|
+
bool closing = jpos ? rv > 0 : rv < 0;
|
|
158
|
+
if (!closing || (cool[i] && cool[j]))
|
|
159
|
+
return; // separating, or this pair just hit
|
|
160
|
+
int g;
|
|
161
|
+
if (heavy[i] == heavy[j])
|
|
162
|
+
g = rv;
|
|
163
|
+
else if (heavy[j])
|
|
164
|
+
g = rv >> 2;
|
|
165
|
+
else
|
|
166
|
+
g = 2 * rv - (rv >> 2);
|
|
167
|
+
v[j] += g;
|
|
168
|
+
v[i] -= 2 * rv - g;
|
|
169
|
+
cool[i] = COOL;
|
|
170
|
+
cool[j] = COOL;
|
|
171
|
+
hits++;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
void contact_pass(void)
|
|
175
|
+
{
|
|
176
|
+
for (char i = 0; i + 1 < ncars; i++) {
|
|
177
|
+
if (crash[i])
|
|
178
|
+
continue;
|
|
179
|
+
for (char j = i + 1; j < ncars; j++) {
|
|
180
|
+
if (!crash[j])
|
|
181
|
+
pair(i, j);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// A car whose centre is on a grass or water tile has crashed.
|
|
187
|
+
void probe(void)
|
|
188
|
+
{
|
|
189
|
+
for (char c = 0; c < ncars; c++) {
|
|
190
|
+
if (crash[c])
|
|
191
|
+
continue;
|
|
192
|
+
char tc = ((char)(cx[c] >> 8) - 24) >> 3;
|
|
193
|
+
char tr = ((char)(cy[c] >> 8) - 50) >> 3;
|
|
194
|
+
char k = tmap[rowoff[tr] + tc];
|
|
195
|
+
if (k) {
|
|
196
|
+
crash[c] = k;
|
|
197
|
+
vx[c] = 0;
|
|
198
|
+
vy[c] = 0;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// --- scripts and movement (fixed_point_8_8), not part of the timed step ---
|
|
204
|
+
int drag(int v)
|
|
205
|
+
{
|
|
206
|
+
if (v > 0) {
|
|
207
|
+
v -= FR;
|
|
208
|
+
if (v < 0) v = 0;
|
|
209
|
+
} else if (v < 0) {
|
|
210
|
+
v += FR;
|
|
211
|
+
if (v > 0) v = 0;
|
|
212
|
+
}
|
|
213
|
+
return v;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
void drive_and_move(void)
|
|
217
|
+
{
|
|
218
|
+
for (char c = 0; c < N_GAME; c++) {
|
|
219
|
+
if (cool[c]) cool[c]--;
|
|
220
|
+
if (crash[c])
|
|
221
|
+
continue;
|
|
222
|
+
const struct Step *s = scripts[c] + sstep[c];
|
|
223
|
+
if (sleft[c] == 0 && s->n)
|
|
224
|
+
sleft[c] = s->n;
|
|
225
|
+
drv[c] = 0;
|
|
226
|
+
if (s->n) {
|
|
227
|
+
if (s->drive) {
|
|
228
|
+
vx[c] = s->vx;
|
|
229
|
+
vy[c] = s->vy;
|
|
230
|
+
drv[c] = 1;
|
|
231
|
+
}
|
|
232
|
+
if (--sleft[c] == 0)
|
|
233
|
+
sstep[c]++;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
for (char c = 0; c < N_GAME; c++) {
|
|
237
|
+
if (crash[c])
|
|
238
|
+
continue;
|
|
239
|
+
if (!drv[c]) {
|
|
240
|
+
vx[c] = drag(vx[c]);
|
|
241
|
+
vy[c] = drag(vy[c]);
|
|
242
|
+
}
|
|
243
|
+
cx[c] += vx[c];
|
|
244
|
+
cy[c] += vy[c];
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
void reset_cars(void)
|
|
249
|
+
{
|
|
250
|
+
ncars = N_GAME;
|
|
251
|
+
for (char c = 0; c < N_GAME; c++) {
|
|
252
|
+
cx[c] = start_x[c];
|
|
253
|
+
cy[c] = start_y[c];
|
|
254
|
+
vx[c] = 0; vy[c] = 0;
|
|
255
|
+
crash[c] = 0; cool[c] = 0; drv[c] = 0;
|
|
256
|
+
sstep[c] = 0; sleft[c] = 0;
|
|
257
|
+
set_kind(c, kind[c]);
|
|
258
|
+
}
|
|
259
|
+
hits = 0;
|
|
260
|
+
contacts = 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// --- checksum: the same fold as the Python model ------------------------
|
|
264
|
+
unsigned cs;
|
|
265
|
+
|
|
266
|
+
void fold(unsigned v)
|
|
267
|
+
{
|
|
268
|
+
cs = (cs << 1) | (cs >> 15);
|
|
269
|
+
cs ^= v;
|
|
270
|
+
cs += 13;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// --- CIA1 timer B -----------------------------------------------------------
|
|
274
|
+
static inline void timer_start(void)
|
|
275
|
+
{
|
|
276
|
+
cia1.crb = 0x00;
|
|
277
|
+
cia1.tb = 0xffff;
|
|
278
|
+
cia1.crb = 0x11;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
static inline unsigned timer_stop(void)
|
|
282
|
+
{
|
|
283
|
+
cia1.crb = 0x00;
|
|
284
|
+
return 0xffff - cia1.tb;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
char pi, pj;
|
|
288
|
+
__noinline void nothing(void) { }
|
|
289
|
+
__noinline void one_pair(void) { pair(pi, pj); }
|
|
290
|
+
__noinline void one_step(void) { contact_pass(); probe(); }
|
|
291
|
+
|
|
292
|
+
unsigned time1(void (*fn)(void))
|
|
293
|
+
{
|
|
294
|
+
__asm { sei }
|
|
295
|
+
timer_start();
|
|
296
|
+
fn();
|
|
297
|
+
unsigned t = timer_stop();
|
|
298
|
+
__asm { cli }
|
|
299
|
+
return t;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Two cars in slots 6 and 7 at given centres and velocities.
|
|
303
|
+
void stage2(char x0, char y0, int v0, char x1, char y1, int v1, char cl, char k0, char k1)
|
|
304
|
+
{
|
|
305
|
+
ncars = MAXC;
|
|
306
|
+
set_kind(6, k0); set_kind(7, k1);
|
|
307
|
+
cx[6] = (unsigned)x0 << 8; cy[6] = (unsigned)y0 << 8; vx[6] = v0; vy[6] = 0;
|
|
308
|
+
cx[7] = (unsigned)x1 << 8; cy[7] = (unsigned)y1 << 8; vx[7] = v1; vy[7] = 0;
|
|
309
|
+
crash[6] = 0; crash[7] = 0;
|
|
310
|
+
cool[6] = cl; cool[7] = cl;
|
|
311
|
+
pi = 6; pj = 7;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Eight cars in a pile-up: slot k at a column and row of a grid, every
|
|
315
|
+
// car closing on its neighbours. dx, dy are the grid steps.
|
|
316
|
+
|
|
317
|
+
void stage8(char dx, char dy)
|
|
318
|
+
{
|
|
319
|
+
ncars = MAXC;
|
|
320
|
+
for (char k = 0; k < MAXC; k++) {
|
|
321
|
+
set_kind(k, k == 2 || k == 5);
|
|
322
|
+
cx[k] = (unsigned)(150 + (k & 1) * dx) << 8;
|
|
323
|
+
cy[k] = (unsigned)(120 + (k >> 1) * dy) << 8;
|
|
324
|
+
vx[k] = (k & 1) ? -256 : 256;
|
|
325
|
+
vy[k] = 192 - (k >> 1) * 128;
|
|
326
|
+
crash[k] = 0;
|
|
327
|
+
cool[k] = 0;
|
|
328
|
+
}
|
|
329
|
+
hits = 0;
|
|
330
|
+
contacts = 0;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Eight cars packed so that all 28 pairs are still in contact when their
|
|
334
|
+
// turn comes and 7 get an impulse, the most one pass allows (each impulse
|
|
335
|
+
// needs a car that is not yet cooling). Found by search on the Python model.
|
|
336
|
+
const unsigned pile_x[MAXC] = { 150 << 8, 150 << 8, 151 << 8, 150 << 8, 150 << 8, 151 << 8, 150 << 8, 151 << 8 };
|
|
337
|
+
const unsigned pile_y[MAXC] = { 120 << 8, 122 << 8, 120 << 8, 122 << 8, 122 << 8, 121 << 8, 120 << 8, 120 << 8 };
|
|
338
|
+
const int pile_vx[MAXC] = { 256, 256, -256, -256, 256, -256, -256, -256 };
|
|
339
|
+
const int pile_vy[MAXC] = { 256, -256, 256, -256, -256, 256, 256, 256 };
|
|
340
|
+
const char pile_k[MAXC] = { 1, 1, 0, 0, 0, 0, 0, 0 };
|
|
341
|
+
|
|
342
|
+
void stage_pile(void)
|
|
343
|
+
{
|
|
344
|
+
ncars = MAXC;
|
|
345
|
+
for (char k = 0; k < MAXC; k++) {
|
|
346
|
+
set_kind(k, pile_k[k]);
|
|
347
|
+
cx[k] = pile_x[k];
|
|
348
|
+
cy[k] = pile_y[k];
|
|
349
|
+
vx[k] = pile_vx[k];
|
|
350
|
+
vy[k] = pile_vy[k];
|
|
351
|
+
crash[k] = 0;
|
|
352
|
+
cool[k] = 0;
|
|
353
|
+
}
|
|
354
|
+
hits = 0;
|
|
355
|
+
contacts = 0;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// --- sprite images: a light car and a truck -----------------------------
|
|
359
|
+
void make_images(void)
|
|
360
|
+
{
|
|
361
|
+
for (char i = 0; i < 128; i++)
|
|
362
|
+
SprData[i] = 0;
|
|
363
|
+
// car: columns 7-16, rows 2-17 (10 x 16), centred on column 12, row 10
|
|
364
|
+
for (char r = 2; r < 18; r++) {
|
|
365
|
+
SprData[r * 3 + 0] = 0x01;
|
|
366
|
+
SprData[r * 3 + 1] = 0xff;
|
|
367
|
+
SprData[r * 3 + 2] = 0x80;
|
|
368
|
+
}
|
|
369
|
+
// truck: columns 5-18, rows 0-19 (14 x 20)
|
|
370
|
+
for (char r = 0; r < 20; r++) {
|
|
371
|
+
SprData[64 + r * 3 + 0] = 0x07;
|
|
372
|
+
SprData[64 + r * 3 + 1] = 0xff;
|
|
373
|
+
SprData[64 + r * 3 + 2] = 0xe0;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
void draw_cars(void)
|
|
378
|
+
{
|
|
379
|
+
for (char c = 0; c < N_GAME; c++) {
|
|
380
|
+
VR[c * 2] = (char)(cx[c] >> 8) - 12; // every car stays below X 256
|
|
381
|
+
VR[c * 2 + 1] = (char)(cy[c] >> 8) - 10;
|
|
382
|
+
PTR[c] = SPR_BLK + heavy[c];
|
|
383
|
+
VR[0x27 + c] = col[c];
|
|
384
|
+
}
|
|
385
|
+
VR[0x10] = 0;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
void draw_road(void)
|
|
389
|
+
{
|
|
390
|
+
for (char r = 0; r < 25; r++) {
|
|
391
|
+
rowoff[r] = r * 40;
|
|
392
|
+
for (char c = 0; c < 40; c++) {
|
|
393
|
+
char k = c < ROAD_L ? 1 : (c > ROAD_R ? 2 : 0);
|
|
394
|
+
tmap[rowoff[r] + c] = k;
|
|
395
|
+
if (r >= TOP_ROW) {
|
|
396
|
+
unsigned o = rowoff[r] + c;
|
|
397
|
+
Screen[o] = 0xa0;
|
|
398
|
+
Color[o] = k == 1 ? 5 : (k == 2 ? 6 : 11);
|
|
399
|
+
if (k == 0 && (c == 17 || c == 18) && (r & 1))
|
|
400
|
+
Color[o] = 15; // centre dashes
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// --- text (screen codes) ------------------------------------------------------
|
|
407
|
+
void put_str(char *p, const char *s)
|
|
408
|
+
{
|
|
409
|
+
while (*s)
|
|
410
|
+
*p++ = *s++;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
void put_dec(char *p, unsigned v, char digits)
|
|
414
|
+
{
|
|
415
|
+
for (char i = digits; i > 0; i--) {
|
|
416
|
+
p[i - 1] = 0x30 + v % 10;
|
|
417
|
+
v /= 10;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
void put_hex(char *p, unsigned v)
|
|
422
|
+
{
|
|
423
|
+
for (char i = 4; i > 0; i--) {
|
|
424
|
+
char d = v & 15;
|
|
425
|
+
p[i - 1] = d < 10 ? 0x30 + d : d - 9;
|
|
426
|
+
v >>= 4;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// --- expected results of one pass, from the Python model --------------------
|
|
431
|
+
#define EXP_CS 0x01e9
|
|
432
|
+
#define EXP_HITS 7
|
|
433
|
+
const char exp_crash[N_GAME] = { 0, 2, 1, 1, 1, 0 };
|
|
434
|
+
|
|
435
|
+
int main(void)
|
|
436
|
+
{
|
|
437
|
+
vic.color_border = 0;
|
|
438
|
+
vic.color_back = 0;
|
|
439
|
+
for (unsigned i = 0; i < 1000; i++) {
|
|
440
|
+
Screen[i] = 0x20;
|
|
441
|
+
Color[i] = 1;
|
|
442
|
+
}
|
|
443
|
+
make_images();
|
|
444
|
+
draw_road();
|
|
445
|
+
|
|
446
|
+
put_str(Screen + 0, s"car contact response frame pass");
|
|
447
|
+
put_str(Screen + 1 * 40, s"result cs expect");
|
|
448
|
+
put_str(Screen + 2 * 40, s"hits expect 7 contacts cr");
|
|
449
|
+
put_str(Screen + 3 * 40, s"pair far xmiss hit cool");
|
|
450
|
+
put_str(Screen + 4 * 40, s"step max min mean");
|
|
451
|
+
put_str(Screen + 5 * 40, s"grid h c pile h c");
|
|
452
|
+
put_str(Screen + 6 * 40, s"truck hit i j cool i j");
|
|
453
|
+
|
|
454
|
+
// Per-pair and staged worst-frame costs, display blanked, less an
|
|
455
|
+
// empty call.
|
|
456
|
+
vic.ctrl1 &= ~VIC_CTRL1_DEN;
|
|
457
|
+
vic_waitFrame();
|
|
458
|
+
vic_waitFrame();
|
|
459
|
+
for (char c = 0; c < N_GAME; c++)
|
|
460
|
+
crash[c] = 1; // the game slots sit out
|
|
461
|
+
unsigned t_none = time1(nothing);
|
|
462
|
+
stage2(150, 100, 0, 150, 200, 0, 0, 0, 0);
|
|
463
|
+
unsigned t_far = time1(one_pair) - t_none;
|
|
464
|
+
stage2(150, 100, 0, 180, 104, 0, 0, 0, 0);
|
|
465
|
+
unsigned t_xmiss = time1(one_pair) - t_none;
|
|
466
|
+
stage2(150, 100, 256, 158, 102, -256, 0, 0, 0);
|
|
467
|
+
unsigned t_hit = time1(one_pair) - t_none;
|
|
468
|
+
stage2(150, 100, 256, 158, 102, -256, COOL, 0, 0);
|
|
469
|
+
unsigned t_cool = time1(one_pair) - t_none;
|
|
470
|
+
stage2(150, 100, 256, 158, 102, -256, 0, 1, 0);
|
|
471
|
+
unsigned t_hit_i = time1(one_pair) - t_none; // i is the truck
|
|
472
|
+
stage2(150, 100, 256, 158, 102, -256, 0, 0, 1);
|
|
473
|
+
unsigned t_hit_j = time1(one_pair) - t_none; // j is the truck
|
|
474
|
+
stage2(150, 100, 256, 158, 102, -256, COOL, 1, 0);
|
|
475
|
+
unsigned t_cool_i = time1(one_pair) - t_none;
|
|
476
|
+
stage2(150, 100, 256, 158, 102, -256, COOL, 0, 1);
|
|
477
|
+
unsigned t_cool_j = time1(one_pair) - t_none;
|
|
478
|
+
stage8(8, 14); // a 2 x 4 grid, neighbours touching
|
|
479
|
+
unsigned t_grid = time1(one_step) - t_none;
|
|
480
|
+
char grid_hits = hits, grid_contacts = contacts;
|
|
481
|
+
stage_pile(); // all 28 pairs in contact
|
|
482
|
+
unsigned t_pile = time1(one_step) - t_none;
|
|
483
|
+
char pile_hits = hits, pile_contacts = contacts;
|
|
484
|
+
vic.ctrl1 |= VIC_CTRL1_DEN;
|
|
485
|
+
put_dec(Screen + 3 * 40 + 9, t_far, 3);
|
|
486
|
+
put_dec(Screen + 3 * 40 + 19, t_xmiss, 3);
|
|
487
|
+
put_dec(Screen + 3 * 40 + 27, t_hit, 3);
|
|
488
|
+
put_dec(Screen + 3 * 40 + 36, t_cool, 3);
|
|
489
|
+
put_dec(Screen + 6 * 40 + 12, t_hit_i, 3);
|
|
490
|
+
put_dec(Screen + 6 * 40 + 18, t_hit_j, 3);
|
|
491
|
+
put_dec(Screen + 6 * 40 + 29, t_cool_i, 3);
|
|
492
|
+
put_dec(Screen + 6 * 40 + 35, t_cool_j, 3);
|
|
493
|
+
put_dec(Screen + 5 * 40 + 5, t_grid, 5);
|
|
494
|
+
put_dec(Screen + 5 * 40 + 12, grid_hits, 2);
|
|
495
|
+
put_dec(Screen + 5 * 40 + 16, grid_contacts, 2);
|
|
496
|
+
put_dec(Screen + 5 * 40 + 25, t_pile, 5);
|
|
497
|
+
put_dec(Screen + 5 * 40 + 32, pile_hits, 2);
|
|
498
|
+
put_dec(Screen + 5 * 40 + 36, pile_contacts, 2);
|
|
499
|
+
put_hex(Screen + 1 * 40 + 29, EXP_CS);
|
|
500
|
+
|
|
501
|
+
reset_cars();
|
|
502
|
+
cs = 0;
|
|
503
|
+
VR[0x15] = (1 << N_GAME) - 1;
|
|
504
|
+
VR[0x1b] = 0;
|
|
505
|
+
VR[0x1c] = 0;
|
|
506
|
+
VR[0x17] = 0;
|
|
507
|
+
VR[0x1d] = 0;
|
|
508
|
+
char frame = 0, pass = 0, fault = 0;
|
|
509
|
+
unsigned total = 0, s_max = 0, s_min = 0xffff, s_mean = 0;
|
|
510
|
+
unsigned long s_sum = 0; // over one pass, for the mean
|
|
511
|
+
|
|
512
|
+
for (;;) {
|
|
513
|
+
vic_waitFrame();
|
|
514
|
+
drive_and_move();
|
|
515
|
+
__asm { sei }
|
|
516
|
+
timer_start();
|
|
517
|
+
contact_pass();
|
|
518
|
+
probe();
|
|
519
|
+
unsigned ts = timer_stop();
|
|
520
|
+
__asm { cli }
|
|
521
|
+
if (ts > s_max) s_max = ts;
|
|
522
|
+
if (ts < s_min) s_min = ts;
|
|
523
|
+
s_sum += ts;
|
|
524
|
+
draw_cars();
|
|
525
|
+
for (char c = 0; c < N_GAME; c++) {
|
|
526
|
+
fold(cx[c]);
|
|
527
|
+
fold(cy[c]);
|
|
528
|
+
fold(vx[c]);
|
|
529
|
+
fold(vy[c]);
|
|
530
|
+
fold(crash[c]);
|
|
531
|
+
}
|
|
532
|
+
vic_waitBelow(112); // write the HUD after the beam has passed it
|
|
533
|
+
|
|
534
|
+
put_dec(Screen + 28, total, 5);
|
|
535
|
+
put_dec(Screen + 39, pass, 1);
|
|
536
|
+
put_hex(Screen + 1 * 40 + 17, cs);
|
|
537
|
+
put_dec(Screen + 2 * 40 + 5, hits, 2);
|
|
538
|
+
put_dec(Screen + 2 * 40 + 27, contacts, 2);
|
|
539
|
+
for (char c = 0; c < N_GAME; c++)
|
|
540
|
+
Screen[2 * 40 + 33 + c] = 0x30 + crash[c];
|
|
541
|
+
put_dec(Screen + 4 * 40 + 9, s_max, 4);
|
|
542
|
+
put_dec(Screen + 4 * 40 + 18, s_min, 4);
|
|
543
|
+
put_dec(Screen + 4 * 40 + 29, s_mean, 4);
|
|
544
|
+
|
|
545
|
+
total++;
|
|
546
|
+
if (++frame == 0) { // end of a 256-frame pass
|
|
547
|
+
if (cs != EXP_CS) fault = 1;
|
|
548
|
+
if (hits != EXP_HITS) fault = 2;
|
|
549
|
+
for (char c = 0; c < N_GAME; c++)
|
|
550
|
+
if (crash[c] != exp_crash[c]) fault = 3;
|
|
551
|
+
RESULT = fault ? 2 : 1;
|
|
552
|
+
vic.color_border = fault ? 2 : 5;
|
|
553
|
+
put_str(Screen + 40 + 7, fault ? s"fail" : s"pass");
|
|
554
|
+
Screen[40 + 12] = 0x30 + fault;
|
|
555
|
+
pass++;
|
|
556
|
+
s_mean = s_sum >> 8; // 256 frames
|
|
557
|
+
s_sum = 0;
|
|
558
|
+
reset_cars();
|
|
559
|
+
cs = 0;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return 0;
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
## Build
|
|
567
|
+
|
|
568
|
+
```bash
|
|
569
|
+
oscar64 -tm=c64 -O2 -o=car-contact.prg car-contact.c
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
Produces `car-contact.prg`, 4,442 bytes. The two sprite images are built
|
|
573
|
+
at run time at `$3000`, blocks 192 and 193. Then run headless in VICE
|
|
574
|
+
(PAL):
|
|
575
|
+
|
|
576
|
+
```bash
|
|
577
|
+
GSETTINGS_SCHEMA_DIR=/opt/homebrew/share/glib-2.0/schemas x64sc -default -warp +sound \
|
|
578
|
+
+autostart-delay-random -autostartprgmode 1 -limitcycles 11880000 \
|
|
579
|
+
-exitscreenshot car-contact.png -autostart car-contact.prg
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
Add `-model ntsc` for the NTSC picture. A pass is 256 frames; the verdict
|
|
583
|
+
is posted at the end of the first pass. The pinned cycle count lands in
|
|
584
|
+
the second pass: PAL at pass frame 181, in the middle of the shove, and
|
|
585
|
+
NTSC at pass frame 237, after every scene has ended.
|
|
586
|
+
|
|
587
|
+
## Expected output
|
|
588
|
+
|
|
589
|
+
The cars, their masses and boxes, and the scenes. X and Y are the centre
|
|
590
|
+
of the body in sprite coordinates; a light car's body is 10 x 16 pixels,
|
|
591
|
+
a truck's 14 x 20. The road is tile columns 9 to 26, VIC X 96 to 239;
|
|
592
|
+
columns below 9 are grass, above 26 water. Velocities are 8.8 fixed point
|
|
593
|
+
in 1/256 pixel per frame; drag while coasting is 4 per frame on each axis.
|
|
594
|
+
|
|
595
|
+
| Car | Kind, colour | Start | Script |
|
|
596
|
+
|---|---|---|---|
|
|
597
|
+
| 0 | light, white (player) | 160, 200 | steer right at 384 for frames 1-10; coast; steer left at -383 for frames 61-76; coast; steer left at -1536 for frames 170-181; coast |
|
|
598
|
+
| 1 | light, yellow | 185, 196 | coast |
|
|
599
|
+
| 2 | truck, orange | 140, 200 | coast |
|
|
600
|
+
| 3 | light, cyan | 120, 150 | coast |
|
|
601
|
+
| 4 | light, light green | 120, 190 | drive up at -192 for frames 1-33; coast; drive up at -128 for frames 64-91; stop; coast |
|
|
602
|
+
| 5 | truck, purple | 165, 142 | wait; at frame 120 launched left at -384; coast |
|
|
603
|
+
|
|
604
|
+
The events of one pass, from the Python model below; the checksum makes
|
|
605
|
+
the C run agree with it on every frame:
|
|
606
|
+
|
|
607
|
+
| Pass frame | Event |
|
|
608
|
+
|---|---|
|
|
609
|
+
| 11 | Side-swipe. The player (vx 380) touches car 1 from the left; equal masses swap, so the player's vx is 0 and car 1's is 380, 1.48 pixels a frame. |
|
|
610
|
+
| 33 | Bump from behind. Car 4 (vy -192) runs into car 3; car 3 takes vy -192 and car 4 stops. |
|
|
611
|
+
| 61 | Car 1's centre reaches X 240, a water tile: crashed. |
|
|
612
|
+
| 77 | Heavy truck. The player (vx -379 after drag) hits truck 2. The truck gets -95, the player bounces to +284. The truck coasts from X 140 to 135 and stops. |
|
|
613
|
+
| 145 | Two contacts in one frame. Truck 5 (vx -284) reaches cars 3 and 4. Car 3 gets -497; the truck slows to -213; car 4 then gets -373 and the truck -160. |
|
|
614
|
+
| 158, 163 | Cars 3 and 4 reach X 95, a grass tile: crashed. |
|
|
615
|
+
| 177 | Shove. The player (vx -1536) reaches truck 2 with a 5-pixel overlap. The truck is pushed 1 pixel (`5 >> 2`) and the player 4; the truck gets -384 and the player +1152. |
|
|
616
|
+
| 178-184 | Both cars cooling. The player's steering sets vx back to -1536 each frame to 181, then it coasts. Each frame the pair overlaps by 4 or 5 pixels, the truck is pushed 1 pixel and the player the rest, and no impulse is given. |
|
|
617
|
+
| 185 | Cooling over. A second impulse: the truck gets -644, the player +524. |
|
|
618
|
+
| 193 | Truck 2 reaches X 95, a grass tile: crashed. |
|
|
619
|
+
|
|
620
|
+
At the end of the pass: 7 impulses, 14 overlapping pair-frames, crash
|
|
621
|
+
flags `0 2 1 1 1 0` (0 on the road, 1 grass, 2 water), checksum `$01E9`.
|
|
622
|
+
|
|
623
|
+
Measured in VICE x64sc 3.10 with the pinned command, text decoded against
|
|
624
|
+
the character ROM (rows 0 to 6). PAL, frame 437, pass 1 frame 181:
|
|
625
|
+
|
|
626
|
+
```text
|
|
627
|
+
CAR CONTACT RESPONSE FRAME 00437 PASS 1
|
|
628
|
+
RESULT PASS 0 CS 455B EXPECT 01E9
|
|
629
|
+
HITS 06 EXPECT 7 CONTACTS 10 CR 020110
|
|
630
|
+
PAIR FAR 087 XMISS 147 HIT 634 COOL 505
|
|
631
|
+
STEP MAX 3695 MIN 0828 MEAN 2081
|
|
632
|
+
GRID 10949 H07 C12 PILE 17549 H07 C28
|
|
633
|
+
TRUCK HIT I 701 J 666 COOL I 513 J 513
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
NTSC, frame 493, pass 1 frame 237:
|
|
637
|
+
|
|
638
|
+
```text
|
|
639
|
+
CAR CONTACT RESPONSE FRAME 00493 PASS 1
|
|
640
|
+
RESULT PASS 0 CS B052 EXPECT 01E9
|
|
641
|
+
HITS 07 EXPECT 7 CONTACTS 14 CR 021110
|
|
642
|
+
PAIR FAR 087 XMISS 147 HIT 634 COOL 505
|
|
643
|
+
STEP MAX 3910 MIN 0828 MEAN 2152
|
|
644
|
+
GRID 10949 H07 C12 PILE 17549 H07 C28
|
|
645
|
+
TRUCK HIT I 701 J 666 COOL I 513 J 513
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
`RESULT PASS 0` is the first pass's verdict. `CS` is the running checksum
|
|
649
|
+
of the pass so far, and both values equal the Python model's at the same
|
|
650
|
+
frame (`$455B` at 181, `$B052` at 237). `CR` is the six crash flags.
|
|
651
|
+
`MEAN` is the mean of the timed step over the 256 frames of the previous
|
|
652
|
+
pass. A run to 16,000,000 cycles shows pass 2 green on both models, with
|
|
653
|
+
`MEAN` 2,079 on PAL and 2,152 on NTSC for pass 1. Border green, `$02FF` =
|
|
654
|
+
`01`.
|
|
655
|
+
|
|
656
|
+
The picture, measured with PIL: every pixel of each car's colour below
|
|
657
|
+
the HUD, as a bounding box, with VIC X = PNG x - 8 and sprite Y = raster
|
|
658
|
+
line - 1 (a sprite at Y first shows on raster line Y + 1,
|
|
659
|
+
`hardware/vic-ii-reference.md`). All six boxes have the body size of
|
|
660
|
+
their kind, and every centre equals the model's.
|
|
661
|
+
|
|
662
|
+
| Car | PAL (model frame 181) | NTSC (model frame 238) |
|
|
663
|
+
|---|---|---|
|
|
664
|
+
| 0 | 136, 200, against the truck | 213, 200 |
|
|
665
|
+
| 1 | 240, 196, in the water | 240, 196, in the water |
|
|
666
|
+
| 2 | 124, 200, being shoved left | 95, 200, on the grass |
|
|
667
|
+
| 3 | 95, 132, on the grass | 95, 132, on the grass |
|
|
668
|
+
| 4 | 95, 152, on the grass | 95, 152, on the grass |
|
|
669
|
+
| 5 | 118, 142 | 118, 142 |
|
|
670
|
+
|
|
671
|
+
On PAL the player's left edge (136 - 5) meets the truck's right edge
|
|
672
|
+
(124 + 7) at X 131: the push leaves the pair just touching. The HUD is
|
|
673
|
+
written after the beam has passed row 6 (`vic_waitBelow(112)`), so all
|
|
674
|
+
seven rows come from one frame. The PAL shot shows frame 181's cars under
|
|
675
|
+
frame 181's HUD; the NTSC shot lands after frame 238 has written the
|
|
676
|
+
sprite registers and before it has written the text. The road edges
|
|
677
|
+
measured on the PAL picture: grass to VIC X 95, road from 96, water from
|
|
678
|
+
240. The screenshots are `screenshots/car-contact.png` and
|
|
679
|
+
`screenshots/car-contact-ntsc.png`.
|
|
680
|
+
|
|
681
|
+
The cycle figures, CIA1 timer B, interrupts masked, Oscar64 `-O2`:
|
|
682
|
+
|
|
683
|
+
| Figure | Cycles | Conditions |
|
|
684
|
+
|---|---|---|
|
|
685
|
+
| One pair, apart in Y | 87 | screen blanked, one call through a wrapper, less an empty call |
|
|
686
|
+
| One pair, overlapping in Y, apart in X | 147 | as above |
|
|
687
|
+
| One pair of light cars in contact, pushed apart and given an impulse | 634 | as above |
|
|
688
|
+
| The same pair while both cool, pushed apart only | 505 | as above |
|
|
689
|
+
| A truck and a light car in contact with an impulse, the truck as `i` | 701 | as above; `g = 2 * rv - (rv >> 2)` |
|
|
690
|
+
| The same, the truck as `j` | 666 | as above; `g = rv >> 2` |
|
|
691
|
+
| A truck and a light car while both cool, the truck as `i` or as `j` | 513 | as above |
|
|
692
|
+
| Contact step, 8 cars in a 2 x 4 grid, neighbours overlapping by 2 pixels | 10,949 | screen blanked; 28 pairs tested, 12 contacts, 7 impulses; includes the tile probe |
|
|
693
|
+
| Contact step, 8 cars packed so that all 28 pairs are in contact | 17,549 | screen blanked; 28 contacts, 7 impulses; includes the probe |
|
|
694
|
+
| Contact step in the game, worst and best frame over two passes | 3,695 PAL, 3,910 NTSC, and 828 | screen on, six cars, up to 15 pairs and the probe |
|
|
695
|
+
| Contact step in the game, mean over one 256-frame pass | 2,081 PAL (2,079 for the second pass), 2,152 NTSC | as above |
|
|
696
|
+
|
|
697
|
+
The packed pile is the most a contact step can do with eight cars: all 28
|
|
698
|
+
pairs are in contact when their turn comes, and 7 impulses is the most one
|
|
699
|
+
pass allows, because an impulse needs a car that is not yet cooling and
|
|
700
|
+
the first one uses two. Its start positions and velocities were found by
|
|
701
|
+
a search over the Python model. It is a built frame, not a bound: its
|
|
702
|
+
contacts are a mix of light and truck pairs. The bound by arithmetic
|
|
703
|
+
(rung 3) takes the same counts with every impulse at the dearest measured
|
|
704
|
+
pair, 701, and every other contact at 513: 17,549 + 7 x (701 - 634) +
|
|
705
|
+
21 x (513 - 505) = 18,186 cycles, on the assumption that no contact in
|
|
706
|
+
the pile costs less than the light-car figures. That bound was not
|
|
707
|
+
measured. The best game frame, 828, comes after the crashes: a crashed
|
|
708
|
+
car leaves the pair loop. The in-game peak differs between PAL and NTSC because different badlines and
|
|
709
|
+
sprite DMA land inside the timed region.
|
|
710
|
+
|
|
711
|
+
The Python side of the checksum:
|
|
712
|
+
|
|
713
|
+
```python
|
|
714
|
+
# The rules of car-contact.c in Python, same integers, same order.
|
|
715
|
+
# Prints the checksum of one 256-frame pass: 0x1e9.
|
|
716
|
+
|
|
717
|
+
N = 6
|
|
718
|
+
COOL = 8
|
|
719
|
+
FR = 4
|
|
720
|
+
ROAD_L, ROAD_R = 9, 26 # road columns inclusive; <9 grass (1), >26 water (2)
|
|
721
|
+
|
|
722
|
+
def cls(col):
|
|
723
|
+
if col < ROAD_L: return 1
|
|
724
|
+
if col > ROAD_R: return 2
|
|
725
|
+
return 0
|
|
726
|
+
|
|
727
|
+
# light 0, heavy 1
|
|
728
|
+
MASS = [0, 0, 1, 0, 0, 1]
|
|
729
|
+
HW = [5, 5, 7, 5, 5, 7]
|
|
730
|
+
HH = [8, 8, 10, 8, 8, 10]
|
|
731
|
+
START = [(160,200),(185,196),(140,200),(120,150),(120,190),(165,142)]
|
|
732
|
+
# script steps: (vx, vy, n, drive); n == 0 ends: coast for ever
|
|
733
|
+
SCR = [
|
|
734
|
+
[(0,0,1,1),(384,0,10,1),(0,0,50,0),(-383,0,16,1),(0,0,93,0),(-1536,0,12,1),(0,0,0,0)],
|
|
735
|
+
[(0,0,1,1),(0,0,0,0)],
|
|
736
|
+
[(0,0,1,1),(0,0,0,0)],
|
|
737
|
+
[(0,0,1,1),(0,0,0,0)],
|
|
738
|
+
[(0,0,1,1),(0,-192,33,1),(0,0,30,0),(0,-128,28,1),(0,0,1,1),(0,0,0,0)],
|
|
739
|
+
[(0,0,120,1),(-384,0,1,1),(0,0,0,0)],
|
|
740
|
+
]
|
|
741
|
+
|
|
742
|
+
class W: pass
|
|
743
|
+
|
|
744
|
+
def reset():
|
|
745
|
+
w = W()
|
|
746
|
+
w.x = [s[0] << 8 for s in START]
|
|
747
|
+
w.y = [s[1] << 8 for s in START]
|
|
748
|
+
w.vx = [0]*N; w.vy = [0]*N; w.crash = [0]*N; w.cool = [0]*N
|
|
749
|
+
w.step = [0]*N; w.left = [0]*N; w.drive = [0]*N
|
|
750
|
+
w.hits = 0; w.contacts = 0
|
|
751
|
+
return w
|
|
752
|
+
|
|
753
|
+
def drive(w):
|
|
754
|
+
for c in range(N):
|
|
755
|
+
if w.cool[c]: w.cool[c] -= 1
|
|
756
|
+
if w.crash[c]: continue
|
|
757
|
+
if w.left[c] == 0:
|
|
758
|
+
s = SCR[c][w.step[c]]
|
|
759
|
+
if s[2] == 0:
|
|
760
|
+
w.drive[c] = 0
|
|
761
|
+
else:
|
|
762
|
+
w.left[c] = s[2]
|
|
763
|
+
s = SCR[c][w.step[c]]
|
|
764
|
+
if s[2] and s[3]:
|
|
765
|
+
w.vx[c] = s[0]; w.vy[c] = s[1]; w.drive[c] = 1
|
|
766
|
+
else:
|
|
767
|
+
w.drive[c] = 0
|
|
768
|
+
if s[2]:
|
|
769
|
+
w.left[c] -= 1
|
|
770
|
+
if w.left[c] == 0: w.step[c] += 1
|
|
771
|
+
|
|
772
|
+
def fric(v):
|
|
773
|
+
if v > 0:
|
|
774
|
+
v -= FR
|
|
775
|
+
if v < 0: v = 0
|
|
776
|
+
elif v < 0:
|
|
777
|
+
v += FR
|
|
778
|
+
if v > 0: v = 0
|
|
779
|
+
return v
|
|
780
|
+
|
|
781
|
+
def move(w):
|
|
782
|
+
for c in range(N):
|
|
783
|
+
if w.crash[c]: continue
|
|
784
|
+
if not w.drive[c]:
|
|
785
|
+
w.vx[c] = fric(w.vx[c]); w.vy[c] = fric(w.vy[c])
|
|
786
|
+
w.x[c] = (w.x[c] + w.vx[c]) & 0xffff
|
|
787
|
+
w.y[c] = (w.y[c] + w.vy[c]) & 0xffff
|
|
788
|
+
|
|
789
|
+
def share(pen, mi, mj):
|
|
790
|
+
if mi == mj:
|
|
791
|
+
ai = pen >> 1; aj = pen - ai
|
|
792
|
+
elif mi:
|
|
793
|
+
ai = pen >> 2; aj = pen - ai
|
|
794
|
+
else:
|
|
795
|
+
aj = pen >> 2; ai = pen - aj
|
|
796
|
+
return ai, aj
|
|
797
|
+
|
|
798
|
+
def impulse(rv, mi, mj):
|
|
799
|
+
if mi == mj: g = rv
|
|
800
|
+
elif mj: g = rv >> 2
|
|
801
|
+
else: g = 2*rv - (rv >> 2)
|
|
802
|
+
return g, 2*rv - g # dv_j = +g, dv_i = -(2rv - g)
|
|
803
|
+
|
|
804
|
+
def pair(w, i, j):
|
|
805
|
+
dy = (w.y[j] >> 8) - (w.y[i] >> 8)
|
|
806
|
+
oy = HH[i] + HH[j] - abs(dy)
|
|
807
|
+
if oy <= 0: return
|
|
808
|
+
dx = (w.x[j] >> 8) - (w.x[i] >> 8)
|
|
809
|
+
ox = HW[i] + HW[j] - abs(dx)
|
|
810
|
+
if ox <= 0: return
|
|
811
|
+
w.contacts += 1
|
|
812
|
+
mi, mj = MASS[i], MASS[j]
|
|
813
|
+
both = w.cool[i] and w.cool[j]
|
|
814
|
+
if ox < oy:
|
|
815
|
+
ai, aj = share(ox, mi, mj)
|
|
816
|
+
if dx >= 0:
|
|
817
|
+
w.x[i] -= ai << 8; w.x[j] += aj << 8
|
|
818
|
+
else:
|
|
819
|
+
w.x[i] += ai << 8; w.x[j] -= aj << 8
|
|
820
|
+
rv = w.vx[i] - w.vx[j]
|
|
821
|
+
app = rv > 0 if dx >= 0 else rv < 0
|
|
822
|
+
if app and not both:
|
|
823
|
+
g, h = impulse(rv, mi, mj)
|
|
824
|
+
w.vx[j] += g; w.vx[i] -= h
|
|
825
|
+
w.cool[i] = w.cool[j] = COOL; w.hits += 1
|
|
826
|
+
else:
|
|
827
|
+
ai, aj = share(oy, mi, mj)
|
|
828
|
+
if dy >= 0:
|
|
829
|
+
w.y[i] -= ai << 8; w.y[j] += aj << 8
|
|
830
|
+
else:
|
|
831
|
+
w.y[i] += ai << 8; w.y[j] -= aj << 8
|
|
832
|
+
rv = w.vy[i] - w.vy[j]
|
|
833
|
+
app = rv > 0 if dy >= 0 else rv < 0
|
|
834
|
+
if app and not both:
|
|
835
|
+
g, h = impulse(rv, mi, mj)
|
|
836
|
+
w.vy[j] += g; w.vy[i] -= h
|
|
837
|
+
w.cool[i] = w.cool[j] = COOL; w.hits += 1
|
|
838
|
+
w.x[i] &= 0xffff; w.x[j] &= 0xffff; w.y[i] &= 0xffff; w.y[j] &= 0xffff
|
|
839
|
+
|
|
840
|
+
def contacts(w):
|
|
841
|
+
for i in range(N - 1):
|
|
842
|
+
if w.crash[i]: continue
|
|
843
|
+
for j in range(i + 1, N):
|
|
844
|
+
if w.crash[j]: continue
|
|
845
|
+
pair(w, i, j)
|
|
846
|
+
|
|
847
|
+
def probe(w):
|
|
848
|
+
for c in range(N):
|
|
849
|
+
if w.crash[c]: continue
|
|
850
|
+
col = ((w.x[c] >> 8) - 24) >> 3
|
|
851
|
+
k = cls(col)
|
|
852
|
+
if k:
|
|
853
|
+
w.crash[c] = k; w.vx[c] = 0; w.vy[c] = 0
|
|
854
|
+
|
|
855
|
+
def fold(cs, v):
|
|
856
|
+
cs = ((cs << 1) | (cs >> 15)) & 0xffff
|
|
857
|
+
cs ^= v & 0xffff
|
|
858
|
+
return (cs + 13) & 0xffff
|
|
859
|
+
|
|
860
|
+
def run(frames=256, stop=None):
|
|
861
|
+
w = reset(); cs = 0
|
|
862
|
+
for f in range(frames):
|
|
863
|
+
drive(w); move(w); contacts(w); probe(w)
|
|
864
|
+
for c in range(N):
|
|
865
|
+
cs = fold(cs, w.x[c]); cs = fold(cs, w.y[c])
|
|
866
|
+
cs = fold(cs, w.vx[c]); cs = fold(cs, w.vy[c])
|
|
867
|
+
cs = fold(cs, w.crash[c])
|
|
868
|
+
if stop is not None and f == stop:
|
|
869
|
+
return w, cs
|
|
870
|
+
return w, cs
|
|
871
|
+
|
|
872
|
+
w, cs = run()
|
|
873
|
+
print(hex(cs), w.hits, w.crash)
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
## Why this works
|
|
877
|
+
|
|
878
|
+
The pair test is ordered so most pairs cost one compare. Cars on a road
|
|
879
|
+
are spread along it, so the Y distance is taken first from the high bytes
|
|
880
|
+
of the 8.8 centres and compared with the two half heights; 87 cycles end
|
|
881
|
+
a pair there. Only a pair that overlaps in both axes computes the two
|
|
882
|
+
overlaps, and the smaller one is the axis to resolve: two cars side by
|
|
883
|
+
side overlap a little in X and a lot in Y, so they are pushed sideways,
|
|
884
|
+
and a nose-to-tail pair the other way. A tie goes to Y.
|
|
885
|
+
|
|
886
|
+
Mass is two numbers, both from shifts. The push that removes the overlap
|
|
887
|
+
is split in half between equal cars; a truck takes `pen >> 2` of it and
|
|
888
|
+
the light car the rest. That share is a chosen value that keeps a truck
|
|
889
|
+
nearly still, not the mass ratio (1/8). The velocity change on the
|
|
890
|
+
contact axis is the elastic one for masses 1 and 7 (arithmetic, rung 3):
|
|
891
|
+
with `rv` the closing velocity, the car on the far side gains `g` and the
|
|
892
|
+
near one loses `2 * rv - g`, where `g` is `rv` for equal masses, `rv >> 2`
|
|
893
|
+
when the far car is the truck (2/8 of `2 * rv`) and `2 * rv - (rv >> 2)`
|
|
894
|
+
when the near one is. Momentum is kept to the rounding of one shift.
|
|
895
|
+
Equal cars therefore swap their velocities on that axis, which is the
|
|
896
|
+
side-swipe and the bump from behind; a light car hitting a truck bounces
|
|
897
|
+
off and the truck moves by a quarter of the closing speed, which is why
|
|
898
|
+
truck 2 coasts 5 pixels.
|
|
899
|
+
|
|
900
|
+
The shift must be arithmetic: `rv >> 2` of -379 is -95, where a divide
|
|
901
|
+
that truncates gives -94. The player's -383 steer was chosen so that this
|
|
902
|
+
case occurs in the pass. Built with `rv / 4` in place of `rv >> 2`, the
|
|
903
|
+
program fails on the checksum alone (fault 1), everything else equal;
|
|
904
|
+
built with `rv >> 1`, car 4 stays on the road and the crash check fails
|
|
905
|
+
(fault 3). In assembly, halving a signed value is `cmp #$80 / ror` on the
|
|
906
|
+
high byte, then `ror` on the low byte (`asr1` in `sine_table_generation`),
|
|
907
|
+
not `lsr`, which would turn -2 into +127 in a byte.
|
|
908
|
+
|
|
909
|
+
An impulse needs the pair to be closing, and not both cars cooling. The
|
|
910
|
+
closing test compares the sign of `rv` with the side the other car is on,
|
|
911
|
+
a signed compare. Positions are still separated during the cooling time,
|
|
912
|
+
so a car held against a truck by its driver stays against it instead of
|
|
913
|
+
passing through, but cannot kick it again every frame: in the shove the
|
|
914
|
+
pair is in contact for nine frames and gets two impulses, eight frames
|
|
915
|
+
apart. The shove is also what the checksum uses to check both rules.
|
|
916
|
+
Built with no cooling test, the shove gives an impulse on every closing
|
|
917
|
+
frame, 10 impulses in the pass, the player follows the truck onto the grass
|
|
918
|
+
and the crash check fails (fault 3). Built with the truck taking
|
|
919
|
+
`pen >> 1` of the push, the checksum fails (fault 1). Each result was
|
|
920
|
+
run in VICE and matches the Python model with the same change.
|
|
921
|
+
|
|
922
|
+
The cooling counter is per car, not per pair. A car that is cooling can
|
|
923
|
+
still be hit by a third car that is not: the truck in the double contact
|
|
924
|
+
gives an impulse to car 3 and then to car 4 in the same frame, because
|
|
925
|
+
car 4 was not cooling. The other side of this: two cars that have each
|
|
926
|
+
just hit something else get no impulse on their first touch with each
|
|
927
|
+
other, only the push.
|
|
928
|
+
|
|
929
|
+
The tile probe runs after the pair loop, because a push can move a car
|
|
930
|
+
onto a verge. It reads the class of the tile under the car's centre from
|
|
931
|
+
a map in RAM (`tile_grid_collision`), never screen RAM, so the HUD or a
|
|
932
|
+
redraw cannot change what counts as road. The probe does not check its
|
|
933
|
+
row: a centre above sprite Y 50, or at 250 or below, gives a tile row
|
|
934
|
+
outside 0 to 24 and reads past `rowoff`. The cars here stay between
|
|
935
|
+
Y 132 and 200; a car that can leave the screen needs the row clamped.
|
|
936
|
+
Every car stays below X 256 on this road, so `$D010` is always 0; a
|
|
937
|
+
wider road needs the ninth bit.
|
|
938
|
+
|
|
939
|
+
The checksum is a second computation, not the first repeated: the Python
|
|
940
|
+
model on this page runs the same rules on its own integers and predicts
|
|
941
|
+
the pass's value, and the HUD's running value matches the model's at the
|
|
942
|
+
frame each screenshot shows. An earlier build stored the start positions
|
|
943
|
+
as bytes and shifted them left by 8 in `reset_cars`; the Oscar64 build on
|
|
944
|
+
this machine compiled that loop as `LDA start_x,Y / TAY / LDA start_y,Y`,
|
|
945
|
+
so each Y came from the wrong entry and the checksum failed. The fault
|
|
946
|
+
reduces to a short program: two `const char` tables read with one index,
|
|
947
|
+
each shifted left by 8 into an `unsigned` array, in a loop that also calls
|
|
948
|
+
a `__noinline` function. Run in VICE, it is wrong at `-O1`, `-O2`, `-O3`
|
|
949
|
+
and `-Os` and right at `-O0`; it is recorded in issue #30. The listing
|
|
950
|
+
stores the start positions, and the pile's, as 8.8 words.
|