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,654 @@
|
|
|
1
|
+
---
|
|
2
|
+
recipe: difficulty-tables
|
|
3
|
+
toolchain: oscar64
|
|
4
|
+
output_format: PRG
|
|
5
|
+
region: both
|
|
6
|
+
techniques: [difficulty_ramp_tables, pal_ntsc_detection, object_pool, lfsr_random]
|
|
7
|
+
file_formats: [PRG]
|
|
8
|
+
uses_registers: [D011, D012, D020, D021, DC04, DC05, DC06, DC07, DC0D, DC0E, DC0F]
|
|
9
|
+
uses_kernal: []
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!-- doc-type: recipe -->
|
|
13
|
+
|
|
14
|
+
# Oscar64 difficulty tables: a level ramp read from data, region-compensated, timed on both models
|
|
15
|
+
|
|
16
|
+
## Synopsis
|
|
17
|
+
|
|
18
|
+
A six-row level table (enemy speed in 8.8 pixels per frame, spawn
|
|
19
|
+
interval in frames, active count, coin quota, a hazard flag) drives a
|
|
20
|
+
small falling-enemy game from data. Enemies come out of an eight-slot
|
|
21
|
+
object pool at the row's interval, no more than the row's count alive at
|
|
22
|
+
once; each one that lands leaves a coin, and an autopilot player collects
|
|
23
|
+
the coins. The level advances when the row's quota is collected, which is
|
|
24
|
+
something the player does, not a timer. From level 3 the flag column
|
|
25
|
+
turns on a second hazard, a spike that falls half again as fast. Past the
|
|
26
|
+
last row the last row is held.
|
|
27
|
+
|
|
28
|
+
The table is written for 50 frames a second. `COMPENSATE=1` (the
|
|
29
|
+
default) asks `pal_ntsc_detection` which chip this is and rescales the
|
|
30
|
+
interval by 6/5 and the speed by 5/6 on NTSC, so the ramp takes the same
|
|
31
|
+
real time on both machines. The program counts frames and runs CIA1
|
|
32
|
+
timers A and B as a 32-bit φ2 clock, prints the frame and the millisecond
|
|
33
|
+
at which level 3 began, and grades that millisecond against a compiled-in
|
|
34
|
+
PAL reference: `$02FF` holds `01` and the border goes green if it is
|
|
35
|
+
within `TOL_MS`, else `02` and red. Built with `-dCOMPENSATE=0` the same
|
|
36
|
+
program shows the raw table: the same frame count on both models and an
|
|
37
|
+
NTSC time about five sixths of the PAL one. It implements
|
|
38
|
+
`difficulty_ramp_tables` (`techniques/logic.md`); the pattern is
|
|
39
|
+
`difficulty_ramp` in `../../game-design/enemy-behaviour-and-difficulty.md`.
|
|
40
|
+
|
|
41
|
+
## Source
|
|
42
|
+
|
|
43
|
+
```c
|
|
44
|
+
// difficulty-tables.c
|
|
45
|
+
// A level table read from data: enemy speed (8.8 pixels per frame), spawn
|
|
46
|
+
// interval (frames), active count and a hazard flag, one row per level, the
|
|
47
|
+
// last row held. Enemies fall from an object pool; each one that reaches
|
|
48
|
+
// the ground drops a coin, and the level advances when the player has
|
|
49
|
+
// collected the row's coin quota. The table is written for PAL frames;
|
|
50
|
+
// COMPENSATE=1 rescales interval and speed on NTSC so the ramp takes the
|
|
51
|
+
// same real time on both. The frame count and CIA-timed elapsed time at
|
|
52
|
+
// which level 3 begins are printed and graded at $02FF.
|
|
53
|
+
#include <c64/vic.h>
|
|
54
|
+
#include <c64/cia.h>
|
|
55
|
+
|
|
56
|
+
#ifndef COMPENSATE
|
|
57
|
+
#define COMPENSATE 1 // 1: rescale the table on NTSC, 0: run raw
|
|
58
|
+
#endif
|
|
59
|
+
#ifndef REF_MS
|
|
60
|
+
#define REF_MS 22493 // ms to level 3 measured on PAL, compensated build
|
|
61
|
+
#endif
|
|
62
|
+
#ifndef TOL_MS
|
|
63
|
+
#define TOL_MS 500 // tolerance on REF_MS, both regions
|
|
64
|
+
#endif
|
|
65
|
+
|
|
66
|
+
#define SCREEN ((char *)0x0400)
|
|
67
|
+
#define COLOUR ((char *)0xd800)
|
|
68
|
+
#define RESULT (*(volatile char *)0x02ff)
|
|
69
|
+
|
|
70
|
+
#define CODE_PASS 0x01
|
|
71
|
+
#define CODE_FAIL 0x02
|
|
72
|
+
|
|
73
|
+
// --- The level table -----------------------------------------------------
|
|
74
|
+
// Columns: speed in 8.8 pixels per frame, spawn interval in frames, most
|
|
75
|
+
// enemies alive at once, coins to collect, flags. Written for 50 frames a
|
|
76
|
+
// second. FLAG_SPIKE turns on the second hazard type from level 3.
|
|
77
|
+
#define FLAG_SPIKE 0x01
|
|
78
|
+
|
|
79
|
+
struct LevelRow { unsigned speed; char interval; char active; char quota; char flags; };
|
|
80
|
+
|
|
81
|
+
#define LEVELS 6
|
|
82
|
+
static const struct LevelRow level_table[LEVELS] = {
|
|
83
|
+
{ 0x0080, 60, 3, 6, 0 }, // 1: 0.50 px/frame
|
|
84
|
+
{ 0x00c0, 45, 3, 6, 0 }, // 2: 0.75
|
|
85
|
+
{ 0x0100, 40, 4, 6, FLAG_SPIKE }, // 3: 1.00, spikes appear
|
|
86
|
+
{ 0x0140, 32, 4, 6, FLAG_SPIKE }, // 4: 1.25
|
|
87
|
+
{ 0x0180, 28, 5, 6, FLAG_SPIKE }, // 5: 1.50
|
|
88
|
+
{ 0x01c0, 24, 5, 6, FLAG_SPIKE }, // 6: 1.75, held for ever after
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// The row in use, copied at level start with the region scaler applied.
|
|
92
|
+
static unsigned cur_speed;
|
|
93
|
+
static char cur_interval, cur_active, cur_quota, cur_flags;
|
|
94
|
+
static char level; // 1-based
|
|
95
|
+
static char coins; // collected this level
|
|
96
|
+
|
|
97
|
+
// --- Region ----------------------------------------------------------------
|
|
98
|
+
static char is_ntsc;
|
|
99
|
+
|
|
100
|
+
// Highest $D012 value seen inside one RST8 band: $37 on a 6569, $06 or $05
|
|
101
|
+
// on a 6567. Interrupts are already off when this runs.
|
|
102
|
+
static char last_raster_line(void)
|
|
103
|
+
{
|
|
104
|
+
char top = 0;
|
|
105
|
+
while (vic.ctrl1 & 0x80) ;
|
|
106
|
+
while (!(vic.ctrl1 & 0x80)) ;
|
|
107
|
+
while (vic.ctrl1 & 0x80) {
|
|
108
|
+
char r = vic.raster;
|
|
109
|
+
if (r > top) top = r;
|
|
110
|
+
}
|
|
111
|
+
return top;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Frames written for 50 Hz become frames at 60 Hz: v * 6 / 5.
|
|
115
|
+
static char scale_frames(char v)
|
|
116
|
+
{
|
|
117
|
+
if (COMPENSATE && is_ntsc)
|
|
118
|
+
return (char)(((unsigned)v * 6 + 2) / 5);
|
|
119
|
+
return v;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Pixels per frame written for 50 Hz become pixels per frame at 60 Hz:
|
|
123
|
+
// v * 5 / 6, in 8.8 so the fraction survives.
|
|
124
|
+
static unsigned scale_speed(unsigned v)
|
|
125
|
+
{
|
|
126
|
+
if (COMPENSATE && is_ntsc)
|
|
127
|
+
return (v * 5 + 3) / 6;
|
|
128
|
+
return v;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static void level_start(char n)
|
|
132
|
+
{
|
|
133
|
+
char i = n - 1;
|
|
134
|
+
if (i >= LEVELS) i = LEVELS - 1; // hold the last row, never read past
|
|
135
|
+
level = n;
|
|
136
|
+
coins = 0;
|
|
137
|
+
cur_speed = scale_speed(level_table[i].speed);
|
|
138
|
+
cur_interval = scale_frames(level_table[i].interval);
|
|
139
|
+
cur_active = level_table[i].active;
|
|
140
|
+
cur_quota = level_table[i].quota;
|
|
141
|
+
cur_flags = level_table[i].flags;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// --- Random ----------------------------------------------------------------
|
|
145
|
+
// 16-bit Galois LFSR. The seed must not be zero or it stays zero for ever.
|
|
146
|
+
#define LFSR_SEED 0xace1
|
|
147
|
+
static unsigned lfsr = LFSR_SEED;
|
|
148
|
+
static char rnd(void)
|
|
149
|
+
{
|
|
150
|
+
char bit = lfsr & 1;
|
|
151
|
+
lfsr >>= 1;
|
|
152
|
+
if (bit) lfsr ^= 0xb400;
|
|
153
|
+
return (char)lfsr;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// --- Object pool -----------------------------------------------------------
|
|
157
|
+
#define MAX_OBJ 8
|
|
158
|
+
#define OBJ_FREE 0
|
|
159
|
+
#define OBJ_ENEMY 1
|
|
160
|
+
#define OBJ_SPIKE 2
|
|
161
|
+
#define OBJ_COIN 3
|
|
162
|
+
|
|
163
|
+
#define TOP_Y 40
|
|
164
|
+
#define GROUND_Y 176 // row 22 of the text screen
|
|
165
|
+
#define PLAYER_Y 192 // row 24, the last row
|
|
166
|
+
#define COIN_DY 0x0200 // coins fall at 2 px/frame (scaled)
|
|
167
|
+
|
|
168
|
+
static char obj_state[MAX_OBJ];
|
|
169
|
+
static char obj_x[MAX_OBJ]; // 0..159, playfield pixels
|
|
170
|
+
static unsigned obj_y[MAX_OBJ]; // 8.8
|
|
171
|
+
static unsigned obj_dy[MAX_OBJ]; // 8.8 per frame
|
|
172
|
+
|
|
173
|
+
static char pool_alloc(void)
|
|
174
|
+
{
|
|
175
|
+
for (char i = 0; i < MAX_OBJ; i++)
|
|
176
|
+
if (obj_state[i] == OBJ_FREE) return i;
|
|
177
|
+
return 0xff;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
static char count_state(char lo, char hi)
|
|
181
|
+
{
|
|
182
|
+
char n = 0;
|
|
183
|
+
for (char i = 0; i < MAX_OBJ; i++)
|
|
184
|
+
if (obj_state[i] >= lo && obj_state[i] <= hi) n++;
|
|
185
|
+
return n;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
static void spawn(char kind, char x, unsigned y, unsigned dy)
|
|
189
|
+
{
|
|
190
|
+
char s = pool_alloc();
|
|
191
|
+
if (s == 0xff) return;
|
|
192
|
+
obj_state[s] = kind;
|
|
193
|
+
obj_x[s] = x;
|
|
194
|
+
obj_y[s] = y;
|
|
195
|
+
obj_dy[s] = dy;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// --- Player and spawner ------------------------------------------------------
|
|
199
|
+
static char player_x = 80;
|
|
200
|
+
static char spawn_timer;
|
|
201
|
+
static char coins_total;
|
|
202
|
+
|
|
203
|
+
static void spawner(void)
|
|
204
|
+
{
|
|
205
|
+
if (spawn_timer) { spawn_timer--; return; }
|
|
206
|
+
if (count_state(OBJ_ENEMY, OBJ_SPIKE) >= cur_active) return;
|
|
207
|
+
spawn_timer = cur_interval;
|
|
208
|
+
char x = (rnd() & 0x7f) + 16; // 16..143 of the 160-wide field
|
|
209
|
+
// Every fourth spawn is a spike once the row's flag allows it: it
|
|
210
|
+
// falls half again as fast and is the level's new problem.
|
|
211
|
+
char kind = OBJ_ENEMY;
|
|
212
|
+
unsigned dy = cur_speed;
|
|
213
|
+
if ((cur_flags & FLAG_SPIKE) && (rnd() & 3) == 0) {
|
|
214
|
+
kind = OBJ_SPIKE;
|
|
215
|
+
dy = cur_speed + (cur_speed >> 1);
|
|
216
|
+
}
|
|
217
|
+
spawn(kind, x, (unsigned)TOP_Y << 8, dy);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// The autopilot: walk towards the lowest object at two pixels a frame,
|
|
221
|
+
// since every enemy becomes a coin where it lands, and collect the coin
|
|
222
|
+
// when it reaches the player's row within eight pixels.
|
|
223
|
+
static void player(void)
|
|
224
|
+
{
|
|
225
|
+
char best = 0xff;
|
|
226
|
+
unsigned besty = 0;
|
|
227
|
+
for (char i = 0; i < MAX_OBJ; i++)
|
|
228
|
+
if (obj_state[i] != OBJ_FREE && obj_y[i] >= besty) { besty = obj_y[i]; best = i; }
|
|
229
|
+
if (best == 0xff) return;
|
|
230
|
+
char tx = obj_x[best];
|
|
231
|
+
if (player_x + 2 <= tx) player_x += 2;
|
|
232
|
+
else if (player_x >= tx + 2) player_x -= 2;
|
|
233
|
+
else player_x = tx;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
static void tick_objects(void)
|
|
237
|
+
{
|
|
238
|
+
for (char i = 0; i < MAX_OBJ; i++) {
|
|
239
|
+
char st = obj_state[i];
|
|
240
|
+
if (st == OBJ_FREE) continue;
|
|
241
|
+
obj_y[i] += obj_dy[i];
|
|
242
|
+
char y = obj_y[i] >> 8;
|
|
243
|
+
if (st == OBJ_COIN) {
|
|
244
|
+
if (y >= PLAYER_Y) {
|
|
245
|
+
char dx = obj_x[i] > player_x ? obj_x[i] - player_x : player_x - obj_x[i];
|
|
246
|
+
if (dx <= 8) { coins++; coins_total++; }
|
|
247
|
+
obj_state[i] = OBJ_FREE;
|
|
248
|
+
}
|
|
249
|
+
} else if (y >= GROUND_Y) {
|
|
250
|
+
// The enemy lands and leaves a coin behind.
|
|
251
|
+
obj_state[i] = OBJ_COIN;
|
|
252
|
+
obj_dy[i] = scale_speed(COIN_DY);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// --- Screen ------------------------------------------------------------------
|
|
258
|
+
static const char hex_glyph[16] = {
|
|
259
|
+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
260
|
+
0x38, 0x39, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
static void put_str(char row, char col, const char *s)
|
|
264
|
+
{
|
|
265
|
+
char *p = SCREEN + row * 40 + col;
|
|
266
|
+
while (*s) { char c = *s++; *p++ = (c >= 0x40) ? c & 0x3f : c; }
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Right-aligned unsigned long in a field of width w, space padded.
|
|
270
|
+
static void put_num(char row, char col, unsigned long v, char w)
|
|
271
|
+
{
|
|
272
|
+
char *p = SCREEN + row * 40 + col + w;
|
|
273
|
+
do { *--p = 0x30 + (char)(v % 10); v /= 10; } while (v && p > SCREEN + row * 40 + col);
|
|
274
|
+
while (p > SCREEN + row * 40 + col) *--p = 0x20;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
static void draw_field(void)
|
|
278
|
+
{
|
|
279
|
+
// Playfield rows 5..24: row = y / 8, column = x / 4. Clamp y so the
|
|
280
|
+
// write can never leave the screen (past 1000 lies the program and,
|
|
281
|
+
// in colour RAM's mirror, the CIA registers).
|
|
282
|
+
for (unsigned i = 5 * 40; i < 1000; i++) SCREEN[i] = 0x20;
|
|
283
|
+
for (char i = 0; i < MAX_OBJ; i++) {
|
|
284
|
+
char st = obj_state[i];
|
|
285
|
+
if (st == OBJ_FREE) continue;
|
|
286
|
+
char y = obj_y[i] >> 8;
|
|
287
|
+
if (y > 199) y = 199;
|
|
288
|
+
unsigned pos = (unsigned)(y >> 3) * 40 + (obj_x[i] >> 2);
|
|
289
|
+
SCREEN[pos] = (st == OBJ_ENEMY) ? 0x57 : (st == OBJ_SPIKE) ? 0x5e : 0x51;
|
|
290
|
+
COLOUR[pos] = (st == OBJ_ENEMY) ? VCOL_LT_RED : (st == OBJ_SPIKE) ? VCOL_YELLOW : VCOL_LT_GREEN;
|
|
291
|
+
}
|
|
292
|
+
unsigned pp = 24 * 40 + (player_x >> 2);
|
|
293
|
+
SCREEN[pp] = 0x5a; COLOUR[pp] = VCOL_WHITE;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// --- Time --------------------------------------------------------------------
|
|
297
|
+
// CIA1 timer A counts phi2 from $FFFF; timer B counts A's underflows.
|
|
298
|
+
static void clock_start(void)
|
|
299
|
+
{
|
|
300
|
+
cia1.cra = 0x00; cia1.crb = 0x00;
|
|
301
|
+
cia1.ta = 0xffff; cia1.tb = 0xffff;
|
|
302
|
+
cia1.crb = 0x51; // count timer A underflows
|
|
303
|
+
cia1.cra = 0x11; // count phi2
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
static unsigned long clock_read(void)
|
|
307
|
+
{
|
|
308
|
+
cia1.cra = 0x00; cia1.crb = 0x00;
|
|
309
|
+
char alo = ((volatile char *)0xdc04)[0], ahi = ((volatile char *)0xdc04)[1];
|
|
310
|
+
char blo = ((volatile char *)0xdc06)[0], bhi = ((volatile char *)0xdc06)[1];
|
|
311
|
+
unsigned a = 0xffff - ((unsigned)ahi << 8 | alo);
|
|
312
|
+
unsigned b = 0xffff - ((unsigned)bhi << 8 | blo);
|
|
313
|
+
cia1.cra = 0x01; cia1.crb = 0x41; // restart with LOAD (bit 4) clear: the count continues
|
|
314
|
+
return ((unsigned long)b << 16) | a;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// phi2 cycles to milliseconds: 985,248 Hz PAL, 1,022,727 Hz NTSC.
|
|
318
|
+
static unsigned long cycles_to_ms(unsigned long c)
|
|
319
|
+
{
|
|
320
|
+
return c / (is_ntsc ? 1023 : 985);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Cost of one level-start row read with the scaler, CIA1 timer A over
|
|
324
|
+
// 100 calls, before the game clock starts. __noinline keeps the call real.
|
|
325
|
+
__noinline static void row_read_call(void) { level_start(3); }
|
|
326
|
+
__noinline static void spawner_call(void) { spawner(); }
|
|
327
|
+
// The spawner's worst frame: the interval has run out, a slot is free and
|
|
328
|
+
// the count is under the cap, so it counts the pool, rolls the LFSR,
|
|
329
|
+
// allocates and spawns. Slot 0 is freed before each call so every call
|
|
330
|
+
// is a spawning one.
|
|
331
|
+
__noinline static void spawn_frame_call(void)
|
|
332
|
+
{
|
|
333
|
+
spawn_timer = 0; obj_state[0] = OBJ_FREE; cur_active = MAX_OBJ;
|
|
334
|
+
spawner();
|
|
335
|
+
}
|
|
336
|
+
static unsigned cost_of(void (*fn)(void))
|
|
337
|
+
{
|
|
338
|
+
cia1.cra = 0x00;
|
|
339
|
+
cia1.ta = 0xffff;
|
|
340
|
+
cia1.cra = 0x11;
|
|
341
|
+
for (char i = 0; i < 100; i++) fn();
|
|
342
|
+
cia1.cra = 0x00;
|
|
343
|
+
return (0xffff - cia1.ta) / 100;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
static void wait_frame(void)
|
|
347
|
+
{
|
|
348
|
+
while (vic.raster == 250) ;
|
|
349
|
+
while (vic.raster != 250) ;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
int main(void)
|
|
353
|
+
{
|
|
354
|
+
__asm { sei }
|
|
355
|
+
cia1.icr = 0x7f; // no CIA interrupts, timer A is ours
|
|
356
|
+
is_ntsc = last_raster_line() != 0x37;
|
|
357
|
+
|
|
358
|
+
for (unsigned i = 0; i < 1000; i++) { SCREEN[i] = 0x20; COLOUR[i] = VCOL_WHITE; }
|
|
359
|
+
vic.color_back = VCOL_BLACK;
|
|
360
|
+
vic.color_border = VCOL_BLACK;
|
|
361
|
+
put_str(0, 0, is_ntsc ? "NTSC" : "PAL ");
|
|
362
|
+
put_str(0, 5, COMPENSATE ? "COMPENSATED " : "UNCOMPENSATED");
|
|
363
|
+
put_str(1, 0, "LEVEL");
|
|
364
|
+
put_str(1, 9, "COINS");
|
|
365
|
+
put_str(1, 18, "FRAMES");
|
|
366
|
+
put_str(2, 0, "L3 AT FRAME");
|
|
367
|
+
put_str(2, 18, "MS");
|
|
368
|
+
put_str(2, 28, "SPAWN");
|
|
369
|
+
|
|
370
|
+
unsigned row_cost = cost_of(row_read_call);
|
|
371
|
+
spawn_timer = 200; // the ordinary frame: count down, return
|
|
372
|
+
unsigned tick_cost = cost_of(spawner_call);
|
|
373
|
+
level_start(3); // spikes on, so the spike branch is in the figure
|
|
374
|
+
unsigned spawn_cost = cost_of(spawn_frame_call);
|
|
375
|
+
for (char i = 0; i < MAX_OBJ; i++) obj_state[i] = OBJ_FREE;
|
|
376
|
+
lfsr = LFSR_SEED; // the harness rolled it; the game starts from the seed
|
|
377
|
+
spawn_timer = 0;
|
|
378
|
+
put_str(4, 24, "ROW READ");
|
|
379
|
+
put_num(4, 33, row_cost, 4);
|
|
380
|
+
put_str(3, 27, "TICK");
|
|
381
|
+
put_num(3, 32, tick_cost, 4);
|
|
382
|
+
|
|
383
|
+
unsigned frames = 0, l3_frames = 0;
|
|
384
|
+
unsigned long l3_ms = 0, l3_cyc = 0;
|
|
385
|
+
char stop = 0; // frames left to run after level 3
|
|
386
|
+
|
|
387
|
+
level_start(1);
|
|
388
|
+
clock_start();
|
|
389
|
+
for (;;) {
|
|
390
|
+
wait_frame();
|
|
391
|
+
frames++;
|
|
392
|
+
spawner();
|
|
393
|
+
player();
|
|
394
|
+
tick_objects();
|
|
395
|
+
if (coins >= cur_quota) {
|
|
396
|
+
level_start(level + 1);
|
|
397
|
+
if (level == 3) {
|
|
398
|
+
l3_frames = frames;
|
|
399
|
+
l3_cyc = clock_read();
|
|
400
|
+
l3_ms = cycles_to_ms(l3_cyc);
|
|
401
|
+
stop = 200;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (stop && --stop == 0) break;
|
|
405
|
+
if ((frames & 3) == 0) {
|
|
406
|
+
draw_field();
|
|
407
|
+
put_num(1, 6, level, 2);
|
|
408
|
+
put_num(1, 15, coins, 2);
|
|
409
|
+
put_num(1, 25, frames, 5);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Verdict: the compensated time to level 3 must sit within TOL_MS of
|
|
414
|
+
// REF_MS on either region; uncompensated NTSC is expected 5/6 of it.
|
|
415
|
+
unsigned long want = REF_MS;
|
|
416
|
+
if (!COMPENSATE && is_ntsc) want = (unsigned long)REF_MS * 5 / 6;
|
|
417
|
+
unsigned long diff = l3_ms > want ? l3_ms - want : want - l3_ms;
|
|
418
|
+
char code = diff <= TOL_MS ? CODE_PASS : CODE_FAIL;
|
|
419
|
+
|
|
420
|
+
draw_field();
|
|
421
|
+
put_num(1, 6, level, 2);
|
|
422
|
+
put_num(1, 15, coins, 2);
|
|
423
|
+
put_num(1, 25, frames, 5);
|
|
424
|
+
put_num(2, 12, l3_frames, 5);
|
|
425
|
+
put_num(2, 20, l3_ms, 6);
|
|
426
|
+
put_num(2, 34, spawn_cost, 4);
|
|
427
|
+
put_str(4, 0, "L3 AT CYCLE");
|
|
428
|
+
put_num(4, 12, l3_cyc, 9);
|
|
429
|
+
put_str(3, 0, "WANT");
|
|
430
|
+
put_num(3, 5, want, 6);
|
|
431
|
+
put_str(3, 12, "RESULT");
|
|
432
|
+
SCREEN[3 * 40 + 19] = hex_glyph[code >> 4];
|
|
433
|
+
SCREEN[3 * 40 + 20] = hex_glyph[code & 15];
|
|
434
|
+
put_str(3, 22, code == CODE_PASS ? "PASS" : "FAIL");
|
|
435
|
+
RESULT = code;
|
|
436
|
+
vic.color_border = code == CODE_PASS ? VCOL_GREEN : VCOL_RED;
|
|
437
|
+
for (;;) ;
|
|
438
|
+
return 0;
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
## Build
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
oscar64 -tm=c64 -O2 -o=difficulty-tables.prg difficulty-tables.c
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Produces `difficulty-tables.prg`, 2,931 bytes including the BASIC stub
|
|
449
|
+
(Oscar64 build 2026-05-19). That is the invocation the pinned run used;
|
|
450
|
+
`npm run check:listings` builds the listing the same way. The other
|
|
451
|
+
build this page measures:
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
oscar64 -tm=c64 -O2 -dCOMPENSATE=0 -o=difficulty-tables-raw.prg difficulty-tables.c # 2,805 bytes
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
The pinned run, on each model:
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
x64sc -default -warp +sound +autostart-delay-random -autostartprgmode 1 -limitcycles 40000000 -exitscreenshot difficulty-tables.png -autostart difficulty-tables.prg
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
Add `-model ntsc` for the NTSC picture. The game reaches level 3 at
|
|
464
|
+
about 22 million cycles on either model and stops 200 frames later, so
|
|
465
|
+
the screen is final well inside the limit. `REF_MS` is the PAL figure
|
|
466
|
+
measured below; change the table and it must be measured again.
|
|
467
|
+
|
|
468
|
+
## Expected output
|
|
469
|
+
|
|
470
|
+
Black screen, green border. Rows 0 to 4 are text; rows 5 to 24 are the
|
|
471
|
+
playfield, enemies as red circles, spikes as yellow chevrons, coins as
|
|
472
|
+
green circles and the player as a white diamond on the bottom row.
|
|
473
|
+
Decoded from the pinned pictures with the character ROM:
|
|
474
|
+
|
|
475
|
+
PAL, `screenshots/difficulty-tables.png`:
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
PAL COMPENSATED
|
|
479
|
+
LEVEL 3 COINS 3 FRAMES 1327
|
|
480
|
+
L3 AT FRAME 1128 MS 22497 SPAWN 409
|
|
481
|
+
WANT 22493 RESULT 01 PASS TICK 51
|
|
482
|
+
L3 AT CYCLE 22159699 ROW READ 181
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
NTSC, `screenshots/difficulty-tables-ntsc.png`:
|
|
486
|
+
|
|
487
|
+
```
|
|
488
|
+
NTSC COMPENSATED
|
|
489
|
+
LEVEL 3 COINS 2 FRAMES 1551
|
|
490
|
+
L3 AT FRAME 1352 MS 22577 SPAWN 412
|
|
491
|
+
WANT 22493 RESULT 01 PASS TICK 53
|
|
492
|
+
L3 AT CYCLE 23097254 ROW READ 267
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
The `-dCOMPENSATE=0` build was run on both models and not pinned:
|
|
496
|
+
|
|
497
|
+
| Build | Model | Level 3 at frame | Level 3 at φ2 cycle | Milliseconds | WANT | Verdict |
|
|
498
|
+
|---|---|---|---|---|---|---|
|
|
499
|
+
| compensated | PAL | 1128 | 22,159,699 | 22,497 | 22,493 | 01 PASS |
|
|
500
|
+
| compensated | NTSC | 1352 | 23,097,254 | 22,577 | 22,493 | 01 PASS |
|
|
501
|
+
| uncompensated | PAL | 1128 | 22,166,254 | 22,503 | 22,493 | 01 PASS |
|
|
502
|
+
| uncompensated | NTSC | 1128 | 19,281,170 | 18,847 | 18,744 | 01 PASS |
|
|
503
|
+
|
|
504
|
+
Read across the rows. Uncompensated, the frame count is the same on both
|
|
505
|
+
models, because the simulation is deterministic and counts frames, and
|
|
506
|
+
the NTSC run reaches level 3 in 18,847 ms against 22,503 ms on PAL: a
|
|
507
|
+
ratio of 0.838. Compensated, the frame counts differ by the rescaling
|
|
508
|
+
(1352 / 1128 = 1.199) and the printed times agree within 80 ms, 0.4 %
|
|
509
|
+
of the run; with the exact clock rates applied to the cycle column
|
|
510
|
+
(see "The clock" below) the gap is 93 ms. `TOL_MS` is 500, so the
|
|
511
|
+
verdict has room for a different table row rounding and none for the
|
|
512
|
+
uncompensated 3.7 second gap. The cycle figures move by a few thousand
|
|
513
|
+
between builds of this program because the clock starts part way
|
|
514
|
+
through a frame and the first `wait_frame` absorbs the rest of it; the
|
|
515
|
+
frame counts do not move.
|
|
516
|
+
|
|
517
|
+
Three smaller figures are on the screen because the technique page
|
|
518
|
+
quotes them. `ROW READ` is the cost of one `level_start` call, the
|
|
519
|
+
table read plus the scaler: 181 cycles on PAL and 267 on NTSC in the
|
|
520
|
+
compensated build, where the NTSC path runs the multiply and divide;
|
|
521
|
+
113 and 118 uncompensated. `TICK` is the spawner's cost on an ordinary
|
|
522
|
+
frame, when the interval timer is counting and no spawn happens: 51
|
|
523
|
+
cycles on PAL, 53 on NTSC. `SPAWN` is the spawner's worst frame, when
|
|
524
|
+
the interval has run out and it counts the pool, rolls the LFSR once or
|
|
525
|
+
twice, allocates a slot and fills it: 409 cycles on PAL and 412 on
|
|
526
|
+
NTSC in the compensated build, 410 and 415 uncompensated. All three are
|
|
527
|
+
averages of one hundred calls timed by CIA1 timer A with the screen on,
|
|
528
|
+
so badline stalls are inside them and they wander by a cycle or two
|
|
529
|
+
between runs and models; the `SPAWN` average includes the spike branch
|
|
530
|
+
as often as the LFSR takes it, and about fifteen cycles of the wrapper
|
|
531
|
+
that resets the timer and frees a slot before each call.
|
|
532
|
+
|
|
533
|
+
## Why this works
|
|
534
|
+
|
|
535
|
+
**The table is the ramp.** `level_table` is the only place a speed, an
|
|
536
|
+
interval, a count or a flag is written. `level_start` copies one row
|
|
537
|
+
into `cur_*` at the start of each level, and the spawner and the movers
|
|
538
|
+
read those. Changing the game's difficulty is editing a row; adding a
|
|
539
|
+
level is adding a row and raising `LEVELS`. The index is clamped to
|
|
540
|
+
`LEVELS - 1` before the read, so level 7 and level 200 play row 6 rather
|
|
541
|
+
than the bytes after it.
|
|
542
|
+
|
|
543
|
+
**Level 3 adds a problem, not just speed.** Levels 1 and 2 differ in
|
|
544
|
+
speed and interval. Level 3 is the first row with `FLAG_SPIKE`, and the
|
|
545
|
+
spawner then makes every fourth spawn a spike at one and a half times
|
|
546
|
+
the row's speed. The autopilot cannot tell them apart; a player can, and
|
|
547
|
+
has a new thing to learn. That is the pattern page's rule of a type or
|
|
548
|
+
hazard column, not only a speed column.
|
|
549
|
+
|
|
550
|
+
**Coins, not seconds.** The level advances when `coins >= cur_quota`,
|
|
551
|
+
and a coin is only counted if the player is within eight pixels of it
|
|
552
|
+
when it reaches the bottom row. A slower player reaches level 3 later.
|
|
553
|
+
The time to level 3 that this page measures is therefore a property of
|
|
554
|
+
the table and the autopilot together, and it is repeatable because the
|
|
555
|
+
LFSR is seeded with a constant.
|
|
556
|
+
|
|
557
|
+
**Two knobs, two scalers.** Frames at 60 Hz must be more numerous to
|
|
558
|
+
last as long: `scale_frames` multiplies by 6/5, with `+2` so the divide
|
|
559
|
+
rounds to nearest. Pixels per frame at 60 Hz must be fewer to cover the
|
|
560
|
+
same distance in the same time: `scale_speed` multiplies by 5/6 in 8.8,
|
|
561
|
+
so a level-1 speed of `$0080` becomes `$006B` rather than zero. Both
|
|
562
|
+
scalers run at level start; the only other call is the coin's fall speed
|
|
563
|
+
when an enemy lands, and the frame loop never reads the table. The
|
|
564
|
+
6/5 is an approximation: a PAL frame is 19.950 ms and a 6567R8 frame is
|
|
565
|
+
16.715 ms, a ratio of 0.838, which is why the uncompensated NTSC run
|
|
566
|
+
came out at 0.838 of PAL rather than exactly 5/6, and why the
|
|
567
|
+
compensated runs differ by 80 ms rather than zero.
|
|
568
|
+
|
|
569
|
+
**The clock.** `sei` and `icr = $7F` take CIA1 away from the KERNAL,
|
|
570
|
+
whose interrupt otherwise reloads timer A sixty times a second. Timer A
|
|
571
|
+
then counts φ2 from `$FFFF` and timer B, in mode `$51`, counts timer A's
|
|
572
|
+
underflows, which makes a 32-bit cycle counter. `clock_read` stops both
|
|
573
|
+
before reading so the two halves belong to the same instant, reads the
|
|
574
|
+
four bytes low first, and restarts with `$01` and `$41`, which set START
|
|
575
|
+
and leave bit 4 clear. Bit 4 of either control register is LOAD, a
|
|
576
|
+
strobe that copies the `$FFFF` latch into the counter, so restarting
|
|
577
|
+
with the `$11` and `$51` that `clock_start` uses would zero the clock
|
|
578
|
+
on every read; a first draft of this page did exactly that and called
|
|
579
|
+
it a continuation, and it was caught by reading the clock a second time
|
|
580
|
+
200 frames later and getting 200 frames rather than the whole run.
|
|
581
|
+
Milliseconds come from dividing by the region's clock in kHz (985 or
|
|
582
|
+
1023); that is 0.025 % low on PAL and 0.027 % high on NTSC against the
|
|
583
|
+
true 985.248 and 1022.727, about six milliseconds each way at this
|
|
584
|
+
length, and because the two errors run in opposite directions they
|
|
585
|
+
close the gap between the printed times: divided exactly, the pinned
|
|
586
|
+
cycle counts are 22,491.5 ms and 22,584.0 ms, 93 ms apart, where the
|
|
587
|
+
screen says 80. Both are far inside `TOL_MS`. This is what
|
|
588
|
+
`cia_timer_phi2_difference` in `pitfalls/region-timing.md` is about: a
|
|
589
|
+
CIA count is not a time until the region's clock is applied to it.
|
|
590
|
+
|
|
591
|
+
**Why the frame count also tells the time.** Independently of the CIA,
|
|
592
|
+
1128 PAL frames of 19,656 cycles is 22,171,968 cycles, and the CIA read
|
|
593
|
+
22,159,699: the difference, 12,269 cycles, is the part of a frame
|
|
594
|
+
between the clock's start and the first `wait_frame`. The two
|
|
595
|
+
instruments agree to within one frame, under 0.07 %, on every row of
|
|
596
|
+
the table above, which is the check that the CIA path is reading the
|
|
597
|
+
right registers.
|
|
598
|
+
|
|
599
|
+
**A bug this page had.** The first build drew the coins on text rows up
|
|
600
|
+
to 28, past the 1,000 cells of the screen. The screen writes landed in
|
|
601
|
+
the program at `$0800` and the colour writes, at `$D800 + 1120` and up,
|
|
602
|
+
landed in the CIA1 register mirror at `$DC60`, where they stopped and
|
|
603
|
+
reloaded the timers. The cycle figures were nonsense and the frame
|
|
604
|
+
counts were fine, which is the symptom to remember: a colour RAM index
|
|
605
|
+
past 1,000 reaches the I/O area. The playfield now ends at row 24 and
|
|
606
|
+
the draw clamps `y` before it indexes.
|
|
607
|
+
|
|
608
|
+
## Verification
|
|
609
|
+
|
|
610
|
+
Three instruments, run against the committed PNGs (VICE x64sc 3.10,
|
|
611
|
+
windowless build, Oscar64 build 2026-05-19).
|
|
612
|
+
|
|
613
|
+
**Text and border.** A script matched every cell of rows 0 to 4 against
|
|
614
|
+
the glyphs of `chargen-901225-01.bin` and read the border pixel at
|
|
615
|
+
(2, 100). Both pictures give the five lines quoted above and the border
|
|
616
|
+
RGB VICE emits for colour 5 on each model, (98, 213, 50) on PAL and
|
|
617
|
+
(114, 189, 103) on NTSC.
|
|
618
|
+
|
|
619
|
+
**The four figures.** The frame and millisecond at level 3 were read
|
|
620
|
+
from the exit screenshots of four runs, two builds on two models, and
|
|
621
|
+
are the table above. The cycle column was checked against frames times
|
|
622
|
+
the region's frame length in cycles (19,656 PAL, 17,095 NTSC) and agreed
|
|
623
|
+
to within one frame on all four.
|
|
624
|
+
|
|
625
|
+
**Reproducibility.** The pinned command was run twice per model and the
|
|
626
|
+
PNG bytes were identical each time.
|
|
627
|
+
|
|
628
|
+
**The clock continues across a read.** A test build of this listing
|
|
629
|
+
with a second `clock_read` after the 200-frame run-out printed
|
|
630
|
+
26,070,834 cycles on PAL against 22,159,660 at level 3, a gap of
|
|
631
|
+
3,911,174, which is 200 frames of 19,656 less the fraction of a frame
|
|
632
|
+
between the read and the loop's exit. The same build with the restart
|
|
633
|
+
changed to `$11` and `$51` printed 3,911,173 for the second read: the
|
|
634
|
+
LOAD strobe had reset the clock at the first one. Neither test build is
|
|
635
|
+
pinned; the figures on the pinned pictures come from one read.
|
|
636
|
+
|
|
637
|
+
The CIA cascade was also checked in isolation before the bug above was
|
|
638
|
+
found: a 30-line program that starts the two timers, waits 100 PAL
|
|
639
|
+
frames and dumps the sixteen CIA1 registers read 29 underflows and a
|
|
640
|
+
timer A remainder of `$E4A5`, 1,959,077 cycles against the 1,965,600 of
|
|
641
|
+
100 frames; the gap is the start-up before the first `wait_frame`.
|
|
642
|
+
|
|
643
|
+
## Sources
|
|
644
|
+
|
|
645
|
+
- `../../game-design/enemy-behaviour-and-difficulty.md`, `difficulty_ramp`:
|
|
646
|
+
the table shape, the held last row and the 50/60 coupling this page
|
|
647
|
+
measures.
|
|
648
|
+
- `pal-ntsc-detect.md`: the region read, reused as one function.
|
|
649
|
+
- `object-pool.md`: the parallel-array pool and the CIA1 timer A cost
|
|
650
|
+
loop, both reused in shape.
|
|
651
|
+
- `headless-verify.md`: the `$02FF` result byte and the border verdict.
|
|
652
|
+
- `../../hardware/pal-ntsc-reference.md`: 985,248 Hz and 1,022,727 Hz,
|
|
653
|
+
312 lines of 63 cycles and 263 of 65 (read for the figures; the frame
|
|
654
|
+
lengths above are arithmetic from them).
|