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,454 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""gen.py: the caves, the autopilot script, the rules model and the note table.
|
|
3
|
+
|
|
4
|
+
python3 tools/gen.py # writes src/gen_caves.h, gen_autopilot.h, gen_notes.h
|
|
5
|
+
python3 tools/gen.py --show # also prints the model's cave at game over
|
|
6
|
+
|
|
7
|
+
Edit CAVES (or SCRIPT) below, run this, rebuild. It
|
|
8
|
+
1. packs every cave into the RLE row stream of c64-kb's level-rle-decoder
|
|
9
|
+
recipe (control byte 0x80+n: the next byte n times; 1..127: that many
|
|
10
|
+
literal bytes follow; 0: end of row), one stream per row of 40 cells;
|
|
11
|
+
2. runs a model of the same rules as src/cave.c over the autopilot script
|
|
12
|
+
and writes what the program must find at game over (the cave's fold,
|
|
13
|
+
score, gems, play frames), which the AUTOPILOT build grades itself on;
|
|
14
|
+
3. writes the SID frequency tables for PAL and NTSC.
|
|
15
|
+
The model is the specification of the rules: change a rule in cave.c and
|
|
16
|
+
here together, or the autopilot verdict turns red.
|
|
17
|
+
"""
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
W, H = 40, 22
|
|
22
|
+
|
|
23
|
+
# Element codes, the same numbers as src/cave.h. Bit 7 is the scanned bit.
|
|
24
|
+
SPACE, DIRT, BRICK, STEEL, BOULDER, BOULDER_F, GEM, GEM_F = range(8)
|
|
25
|
+
EXIT_SHUT, EXIT_OPEN, PLAYER = 8, 9, 10
|
|
26
|
+
SPARK, MOTH, BLAST, BURST = 12, 16, 20, 23 # SPARK/MOTH + heading 0..3; BLAST/BURST + stage 0..2
|
|
27
|
+
SCANNED = 0x80
|
|
28
|
+
STEP = [-1, -W, 1, W] # headings: left, up, right, down
|
|
29
|
+
|
|
30
|
+
LEGEND = {'.': DIRT, ' ': SPACE, '#': BRICK, 'S': STEEL, 'o': BOULDER, '*': GEM,
|
|
31
|
+
'X': EXIT_SHUT, 'P': PLAYER, 'f': SPARK + 0, 'm': MOTH + 0}
|
|
32
|
+
|
|
33
|
+
GEM_POINTS = 10
|
|
34
|
+
TICK_CAVE_FRAMES = 12 # cave frames per unit of the time counter
|
|
35
|
+
DEATH_FRAMES = 6 # cave frames between a death and the next life
|
|
36
|
+
SLICE_FRAMES = 4 # display frames per cave frame (the scan's four slices)
|
|
37
|
+
|
|
38
|
+
# Each cave: name (at most 16 characters), gems needed, time, 20 interior
|
|
39
|
+
# rows of 38 cells (shorter rows are padded with dirt). The steel border is
|
|
40
|
+
# added here. One player, one exit per cave. Original layouts.
|
|
41
|
+
CAVES = [
|
|
42
|
+
("FIRST DIG", 6, 99, [
|
|
43
|
+
"...........o..*.........o............",
|
|
44
|
+
".P...*..*..*...*..o ...........oo...",
|
|
45
|
+
"...................*.....o...........",
|
|
46
|
+
"...................*....oo...........",
|
|
47
|
+
"....................XS........o .....", # the boulder on the brick end rolls right
|
|
48
|
+
"..........................##### .....",
|
|
49
|
+
".....o...............................",
|
|
50
|
+
"..............####.......####........",
|
|
51
|
+
"....*.........# #.......# #...*....",
|
|
52
|
+
"..............# f#.......#m #........",
|
|
53
|
+
"..............# #.......# #........",
|
|
54
|
+
"..............####.......####........",
|
|
55
|
+
"." * 11 + "o" * 16 + "." * 11, # boulder rain: 16 fall and land in one
|
|
56
|
+
"." + " " * 36 + ".", # slice and overflow the dirty list, so
|
|
57
|
+
"", # the gated run meets render.c's row queue
|
|
58
|
+
"",
|
|
59
|
+
"..............*..........#####.......",
|
|
60
|
+
"......o..............................",
|
|
61
|
+
"......*........o..............*......",
|
|
62
|
+
"",
|
|
63
|
+
]),
|
|
64
|
+
("BOULDER HALL", 8, 120, [
|
|
65
|
+
"....o................o...............",
|
|
66
|
+
"..........o.......................o..",
|
|
67
|
+
"..P..........*.........*.............",
|
|
68
|
+
"...............o.....f .X........",
|
|
69
|
+
"...........#####.....................",
|
|
70
|
+
"......*..............*.......*.......",
|
|
71
|
+
"...........o...........o.............",
|
|
72
|
+
"........ ...........................",
|
|
73
|
+
"......#####...........#####..........",
|
|
74
|
+
"...........*....*.........*..........",
|
|
75
|
+
"",
|
|
76
|
+
"........m .......................",
|
|
77
|
+
"....o.......o.......o........o.......",
|
|
78
|
+
"....*.......*.......*........*.......",
|
|
79
|
+
"",
|
|
80
|
+
"..........####.............####......",
|
|
81
|
+
"",
|
|
82
|
+
"...*..................*.........*....",
|
|
83
|
+
"",
|
|
84
|
+
"",
|
|
85
|
+
]),
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
# The autopilot's moves, one per cave frame: L U R D, '-' stands still.
|
|
89
|
+
# One string per cave start (a new cave, or the same cave after a lost
|
|
90
|
+
# life), keyed by the game's count of starts; past the end of a string the
|
|
91
|
+
# player stands still.
|
|
92
|
+
SCRIPT = [
|
|
93
|
+
"RRRRRRRRRRRRRRRRRRDDDR", # cave 1: gems, two pushes, the exit
|
|
94
|
+
"RRUD", # cave 2: out from under a boulder; it falls on him
|
|
95
|
+
"RRRRRRRRD", # cave 2 again: under another boulder, the same end
|
|
96
|
+
"RRUD", # cave 2, last life: game over
|
|
97
|
+
]
|
|
98
|
+
LIVES_AUTOPILOT = 3
|
|
99
|
+
DEFAULT_SCORES = [400, 300, 200, 100, 50] # hiscore.c's default table
|
|
100
|
+
NAME_AUTOPILOT = "ABE"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def build(cave):
|
|
104
|
+
name, need, time, rows = cave
|
|
105
|
+
c = [STEEL] * (W * H)
|
|
106
|
+
for y in range(1, H - 1):
|
|
107
|
+
r = rows[y - 1] if y - 1 < len(rows) else ""
|
|
108
|
+
if len(r) > W - 2:
|
|
109
|
+
sys.exit(f"cave {name}: row {y} is {len(r)} cells, more than {W - 2}")
|
|
110
|
+
for x, ch in enumerate(r.ljust(W - 2, '.'), 1):
|
|
111
|
+
if ch not in LEGEND:
|
|
112
|
+
sys.exit(f"cave {name}: row {y} has '{ch}', not in the legend")
|
|
113
|
+
c[y * W + x] = LEGEND[ch]
|
|
114
|
+
for code in (PLAYER, EXIT_SHUT):
|
|
115
|
+
if c.count(code) != 1:
|
|
116
|
+
sys.exit(f"cave {name}: {c.count(code)} cells of code {code}, want 1")
|
|
117
|
+
return c
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def rle_row(cells):
|
|
121
|
+
"""The level-rle-decoder stream for one row: runs of 3 or more, else literals."""
|
|
122
|
+
out, i, lit = [], 0, []
|
|
123
|
+
while i < len(cells):
|
|
124
|
+
j = i
|
|
125
|
+
while j < len(cells) and cells[j] == cells[i] and j - i < 127:
|
|
126
|
+
j += 1
|
|
127
|
+
if j - i >= 3:
|
|
128
|
+
if lit:
|
|
129
|
+
out += [len(lit)] + lit
|
|
130
|
+
lit = []
|
|
131
|
+
out += [0x80 | (j - i), cells[i]]
|
|
132
|
+
i = j
|
|
133
|
+
else:
|
|
134
|
+
lit.append(cells[i])
|
|
135
|
+
i += 1
|
|
136
|
+
if len(lit) == 127:
|
|
137
|
+
out += [len(lit)] + lit
|
|
138
|
+
lit = []
|
|
139
|
+
if lit:
|
|
140
|
+
out += [len(lit)] + lit
|
|
141
|
+
return out + [0]
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def rle_decode(data):
|
|
145
|
+
out, i = [], 0
|
|
146
|
+
for _ in range(H):
|
|
147
|
+
while True:
|
|
148
|
+
c = data[i]; i += 1
|
|
149
|
+
if c == 0:
|
|
150
|
+
break
|
|
151
|
+
if c & 0x80:
|
|
152
|
+
out += [data[i]] * (c & 0x7f); i += 1
|
|
153
|
+
else:
|
|
154
|
+
out += data[i:i + c]; i += c
|
|
155
|
+
return out
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def fold(cells, chk=0):
|
|
159
|
+
for v in cells:
|
|
160
|
+
chk = ((chk ^ (v & 0x7f)) * 5 + 1) & 0xffff
|
|
161
|
+
return chk
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class Cave:
|
|
165
|
+
"""One cave's state and the rules. Mirrors src/cave.c line for line."""
|
|
166
|
+
|
|
167
|
+
def __init__(self, cells, need, time):
|
|
168
|
+
self.c = list(cells)
|
|
169
|
+
self.need, self.time = need, time
|
|
170
|
+
self.got = self.points = 0
|
|
171
|
+
self.dead = self.exited = self.exit_open = False
|
|
172
|
+
self.player = self.c.index(PLAYER)
|
|
173
|
+
self.exit_at = self.c.index(EXIT_SHUT)
|
|
174
|
+
self.tick = 0
|
|
175
|
+
self.move = -1
|
|
176
|
+
self.seen = 0
|
|
177
|
+
|
|
178
|
+
def put(self, d, v, s):
|
|
179
|
+
if d > s:
|
|
180
|
+
v |= SCANNED
|
|
181
|
+
self.c[d] = v
|
|
182
|
+
self.c[s] = SPACE
|
|
183
|
+
if v & 0x7f == PLAYER:
|
|
184
|
+
self.player = d
|
|
185
|
+
|
|
186
|
+
def explode(self, centre, kind, at):
|
|
187
|
+
for dy in (-W, 0, W):
|
|
188
|
+
for dx in (-1, 0, 1):
|
|
189
|
+
n = centre + dy + dx
|
|
190
|
+
t = self.c[n] & 0x7f
|
|
191
|
+
if t in (STEEL, EXIT_SHUT, EXIT_OPEN):
|
|
192
|
+
continue
|
|
193
|
+
if t == PLAYER:
|
|
194
|
+
self.dead = True
|
|
195
|
+
self.c[n] = kind | (SCANNED if n > at else 0)
|
|
196
|
+
|
|
197
|
+
def roll(self, i, fall):
|
|
198
|
+
for o in (-1, 1):
|
|
199
|
+
if self.c[i + o] == SPACE and self.c[i + W + o] == SPACE:
|
|
200
|
+
self.put(i + o, fall, i)
|
|
201
|
+
return True
|
|
202
|
+
return False
|
|
203
|
+
|
|
204
|
+
@staticmethod
|
|
205
|
+
def round_(t):
|
|
206
|
+
return t in (BOULDER, GEM, BRICK)
|
|
207
|
+
|
|
208
|
+
def cell(self, i):
|
|
209
|
+
c, v = self.c, self.c[i]
|
|
210
|
+
if v & SCANNED:
|
|
211
|
+
c[i] = v & 0x7f
|
|
212
|
+
return
|
|
213
|
+
if v in (BOULDER, GEM):
|
|
214
|
+
b = c[i + W]
|
|
215
|
+
if b == SPACE:
|
|
216
|
+
self.put(i + W, v + 1, i)
|
|
217
|
+
elif self.round_(b & 0x7f):
|
|
218
|
+
self.roll(i, v + 1)
|
|
219
|
+
elif v in (BOULDER_F, GEM_F):
|
|
220
|
+
b = c[i + W]; bt = b & 0x7f
|
|
221
|
+
if b == SPACE:
|
|
222
|
+
self.put(i + W, v, i)
|
|
223
|
+
elif bt == PLAYER:
|
|
224
|
+
self.explode(i + W, BLAST, i)
|
|
225
|
+
elif SPARK <= bt < MOTH:
|
|
226
|
+
self.explode(i + W, BLAST, i)
|
|
227
|
+
elif MOTH <= bt < BLAST:
|
|
228
|
+
self.explode(i + W, BURST, i)
|
|
229
|
+
elif bt in (BOULDER_F, GEM_F):
|
|
230
|
+
pass
|
|
231
|
+
elif not (self.round_(bt) and self.roll(i, v)):
|
|
232
|
+
c[i] = v - 1
|
|
233
|
+
elif v == PLAYER:
|
|
234
|
+
self.seen += 1
|
|
235
|
+
if 0 <= self.move < 4:
|
|
236
|
+
t = i + STEP[self.move]
|
|
237
|
+
tv = c[t]
|
|
238
|
+
if tv in (SPACE, DIRT):
|
|
239
|
+
self.put(t, PLAYER, i)
|
|
240
|
+
elif tv == GEM:
|
|
241
|
+
self.got += 1
|
|
242
|
+
self.points += GEM_POINTS
|
|
243
|
+
self.put(t, PLAYER, i)
|
|
244
|
+
elif tv == EXIT_OPEN:
|
|
245
|
+
c[i] = SPACE
|
|
246
|
+
self.exited = True
|
|
247
|
+
elif tv == BOULDER and self.move in (0, 2) and c[t + STEP[self.move]] == SPACE:
|
|
248
|
+
self.put(t + STEP[self.move], BOULDER, t)
|
|
249
|
+
self.put(t, PLAYER, i)
|
|
250
|
+
elif v >= BLAST:
|
|
251
|
+
if v in (BLAST + 2,):
|
|
252
|
+
c[i] = SPACE
|
|
253
|
+
elif v == BURST + 2:
|
|
254
|
+
c[i] = GEM
|
|
255
|
+
else:
|
|
256
|
+
c[i] = v + 1
|
|
257
|
+
elif v >= SPARK:
|
|
258
|
+
base = SPARK if v < MOTH else MOTH
|
|
259
|
+
kind = BLAST if v < MOTH else BURST
|
|
260
|
+
d = v & 3
|
|
261
|
+
for o in STEP:
|
|
262
|
+
if c[i + o] & 0x7f == PLAYER:
|
|
263
|
+
self.explode(i, kind, i)
|
|
264
|
+
return
|
|
265
|
+
first = (d + 3) & 3 if base == SPARK else (d + 1) & 3
|
|
266
|
+
spin = (d + 1) & 3 if base == SPARK else (d + 3) & 3
|
|
267
|
+
if c[i + STEP[first]] == SPACE:
|
|
268
|
+
self.put(i + STEP[first], base + first, i)
|
|
269
|
+
elif c[i + STEP[d]] == SPACE:
|
|
270
|
+
self.put(i + STEP[d], base + d, i)
|
|
271
|
+
else:
|
|
272
|
+
c[i] = base + spin
|
|
273
|
+
|
|
274
|
+
def scan(self):
|
|
275
|
+
for y in range(1, H - 1):
|
|
276
|
+
for x in range(1, W - 1):
|
|
277
|
+
i = y * W + x
|
|
278
|
+
if self.c[i] >= BOULDER:
|
|
279
|
+
self.cell(i)
|
|
280
|
+
assert not any(v & SCANNED for v in self.c), "a scanned bit survived the scan"
|
|
281
|
+
|
|
282
|
+
def end_of_frame(self):
|
|
283
|
+
"""What the game does after the last slice of a cave frame."""
|
|
284
|
+
if not self.exit_open and self.got >= self.need:
|
|
285
|
+
self.c[self.exit_at] = EXIT_OPEN
|
|
286
|
+
self.exit_open = True
|
|
287
|
+
if self.exited or self.dead:
|
|
288
|
+
return
|
|
289
|
+
self.tick += 1
|
|
290
|
+
if self.tick == TICK_CAVE_FRAMES:
|
|
291
|
+
self.tick = 0
|
|
292
|
+
if self.time:
|
|
293
|
+
self.time -= 1
|
|
294
|
+
if self.time == 0:
|
|
295
|
+
self.explode(self.player, BLAST, 0xffff)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def play():
|
|
299
|
+
"""The autopilot game, as the program plays it. Returns what it must show.
|
|
300
|
+
|
|
301
|
+
The script is keyed by the game's own counter of cave starts: SCRIPT[n]
|
|
302
|
+
plays the n-th start (a new cave or a restart after a lost life). The
|
|
303
|
+
fold is chained over every cave the game leaves, so a rule that fires in
|
|
304
|
+
any cave, not only the last, moves the verdict."""
|
|
305
|
+
score, gems, frames, lives = 0, 0, 0, LIVES_AUTOPILOT
|
|
306
|
+
ci, starts, chk = 0, 0, 0
|
|
307
|
+
while True:
|
|
308
|
+
name, need, time, _ = CAVES[ci]
|
|
309
|
+
cv = Cave(build(CAVES[ci]), need, time)
|
|
310
|
+
script = SCRIPT[starts] if starts < len(SCRIPT) else ""
|
|
311
|
+
starts += 1
|
|
312
|
+
f, dead_frames = 0, 0
|
|
313
|
+
while True:
|
|
314
|
+
m = script[f] if f < len(script) else '-'
|
|
315
|
+
cv.move = "LURD".find(m)
|
|
316
|
+
cv.seen = 0
|
|
317
|
+
cv.scan()
|
|
318
|
+
cv.end_of_frame()
|
|
319
|
+
# the scan meets the living player exactly once a cave frame
|
|
320
|
+
assert cv.seen <= 1 if cv.dead else cv.seen == 1, (starts, f, cv.seen)
|
|
321
|
+
f += 1
|
|
322
|
+
frames += SLICE_FRAMES
|
|
323
|
+
if cv.exited:
|
|
324
|
+
break
|
|
325
|
+
if cv.dead:
|
|
326
|
+
dead_frames += 1
|
|
327
|
+
if dead_frames == DEATH_FRAMES:
|
|
328
|
+
break
|
|
329
|
+
if f > 5000:
|
|
330
|
+
sys.exit("autopilot: the script never ends a cave")
|
|
331
|
+
score += cv.points
|
|
332
|
+
gems += cv.got
|
|
333
|
+
chk = fold(cv.c, chk)
|
|
334
|
+
if cv.exited:
|
|
335
|
+
score += cv.time
|
|
336
|
+
ci = (ci + 1) % len(CAVES)
|
|
337
|
+
continue
|
|
338
|
+
lives -= 1
|
|
339
|
+
if lives == 0:
|
|
340
|
+
rank = next((r for r, v in enumerate(DEFAULT_SCORES) if v < score), len(DEFAULT_SCORES))
|
|
341
|
+
return dict(fold=chk, score=score, gems=gems, cave=ci, frames=frames, starts=starts,
|
|
342
|
+
rank=rank, cells=[v & 0x7f for v in cv.c])
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def c_array(name, data):
|
|
346
|
+
lines = [f"static const char {name}[{len(data)}] = {{"]
|
|
347
|
+
for k in range(0, len(data), 16):
|
|
348
|
+
lines.append(" " + ", ".join(f"0x{b:02x}" for b in data[k:k + 16]) + ",")
|
|
349
|
+
lines.append("};")
|
|
350
|
+
return "\n".join(lines)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def screen_codes(s):
|
|
354
|
+
return [ord(ch) - 64 if 'A' <= ch <= 'Z' else ord(ch) for ch in s]
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def write_caves(path):
|
|
358
|
+
out = ["// gen_caves.h: written by tools/gen.py. Do not edit; edit tools/gen.py.",
|
|
359
|
+
f"#define CAVE_COUNT {len(CAVES)}", ""]
|
|
360
|
+
total = 0
|
|
361
|
+
for k, cave in enumerate(CAVES):
|
|
362
|
+
cells = build(cave)
|
|
363
|
+
packed = []
|
|
364
|
+
for y in range(H):
|
|
365
|
+
packed += rle_row(cells[y * W:(y + 1) * W])
|
|
366
|
+
assert rle_decode(packed) == cells
|
|
367
|
+
total += len(packed)
|
|
368
|
+
out.append(f"// {cave[0]}: 880 cells -> {len(packed)} bytes, fold 0x{fold(cells):04x}")
|
|
369
|
+
out.append(c_array(f"cave{k}_rle", packed))
|
|
370
|
+
out.append(c_array(f"cave{k}_name", screen_codes(cave[0].ljust(16)[:16])))
|
|
371
|
+
out.append("")
|
|
372
|
+
out.append("static const CaveInfo cave_info[CAVE_COUNT] = {")
|
|
373
|
+
for k, (name, need, time, _) in enumerate(CAVES):
|
|
374
|
+
fold0 = fold(build(CAVES[k]))
|
|
375
|
+
out.append(f" {{ cave{k}_rle, cave{k}_name, {need}, {time}, 0x{fold0:04x} }},")
|
|
376
|
+
out.append("};")
|
|
377
|
+
open(path, "w").write("\n".join(out) + "\n")
|
|
378
|
+
return total
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def write_autopilot(path, result):
|
|
382
|
+
out = ["// gen_autopilot.h: written by tools/gen.py. Do not edit; edit tools/gen.py.",
|
|
383
|
+
"// The autopilot: one move per cave frame (L U R D, '-' still), per cave;",
|
|
384
|
+
"// past the end of a cave's string the player stands still."]
|
|
385
|
+
for k, s in enumerate(SCRIPT):
|
|
386
|
+
out.append(f'static const char script{k}[] = "{s}";')
|
|
387
|
+
out.append(f"static const char * const script_for[{len(SCRIPT)}] = {{ " +
|
|
388
|
+
", ".join(f"script{k}" for k in range(len(SCRIPT))) + " };")
|
|
389
|
+
out.append(f"static const char script_len[{len(SCRIPT)}] = {{ " +
|
|
390
|
+
", ".join(str(len(x)) for x in SCRIPT) + " };")
|
|
391
|
+
out.append(f"#define SCRIPT_STARTS {len(SCRIPT)}")
|
|
392
|
+
out.append(f"#define LIVES_AUTOPILOT {LIVES_AUTOPILOT}")
|
|
393
|
+
out.append(f'#define NAME_AUTOPILOT "{NAME_AUTOPILOT}"')
|
|
394
|
+
out.append("// What the rules model says the program must hold at game over.")
|
|
395
|
+
out.append(f"#define EXPECT_FOLD 0x{result['fold']:04x}")
|
|
396
|
+
out.append(f"#define EXPECT_SCORE {result['score']}UL")
|
|
397
|
+
out.append(f"#define EXPECT_GEMS {result['gems']}")
|
|
398
|
+
out.append(f"#define EXPECT_CAVE {result['cave']}")
|
|
399
|
+
out.append(f"#define EXPECT_PLAY_FRAMES {result['frames']}")
|
|
400
|
+
out.append(f"#define EXPECT_STARTS {result['starts']}")
|
|
401
|
+
out.append(f"#define EXPECT_RANK {result['rank']}")
|
|
402
|
+
open(path, "w").write("\n".join(out) + "\n")
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
def write_notes(path):
|
|
406
|
+
"""SID frequency words for notes 0..59 (C1 up), A4 = 440 Hz, PAL and NTSC clocks."""
|
|
407
|
+
clocks = {"pal": 985248, "ntsc": 1022727}
|
|
408
|
+
out = ["// gen_notes.h: written by tools/gen.py. Note n is C1 + n semitones; A4 = 440 Hz.",
|
|
409
|
+
"// Frequency word = Hz * 16777216 / clock (PAL 985,248 Hz; NTSC 1,022,727 Hz)."]
|
|
410
|
+
for model, clk in clocks.items():
|
|
411
|
+
words = []
|
|
412
|
+
for n in range(60):
|
|
413
|
+
hz = 440.0 * 2 ** ((n - 45) / 12) # n = 45 is A4 (C1 + 45 semitones)
|
|
414
|
+
words.append(min(0xffff, round(hz * 16777216 / clk)))
|
|
415
|
+
out.append(f"static const unsigned note_{model}[60] = {{")
|
|
416
|
+
for k in range(0, 60, 12):
|
|
417
|
+
out.append(" " + ", ".join(f"0x{w:04x}" for w in words[k:k + 12]) + ",")
|
|
418
|
+
out.append("};")
|
|
419
|
+
open(path, "w").write("\n".join(out) + "\n")
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def show(cells):
|
|
423
|
+
rev = {v: k for k, v in LEGEND.items()}
|
|
424
|
+
for y in range(H):
|
|
425
|
+
row = ""
|
|
426
|
+
for x in range(W):
|
|
427
|
+
v = cells[y * W + x] & 0x7f
|
|
428
|
+
if SPARK <= v < MOTH:
|
|
429
|
+
row += 'f'
|
|
430
|
+
elif MOTH <= v < BLAST:
|
|
431
|
+
row += 'm'
|
|
432
|
+
elif v >= BLAST:
|
|
433
|
+
row += '%'
|
|
434
|
+
elif v == EXIT_OPEN:
|
|
435
|
+
row += 'x'
|
|
436
|
+
else:
|
|
437
|
+
row += rev.get(v, '?')
|
|
438
|
+
print(row)
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
if __name__ == "__main__":
|
|
442
|
+
here = os.path.dirname(os.path.abspath(__file__))
|
|
443
|
+
src = os.path.join(here, "..", "src")
|
|
444
|
+
r = play()
|
|
445
|
+
if "--show" in sys.argv:
|
|
446
|
+
show(r["cells"])
|
|
447
|
+
total = write_caves(os.path.join(src, "gen_caves.h"))
|
|
448
|
+
write_autopilot(os.path.join(src, "gen_autopilot.h"), r)
|
|
449
|
+
write_notes(os.path.join(src, "gen_notes.h"))
|
|
450
|
+
print(f"gen: {len(CAVES)} caves, {total} bytes packed; autopilot: score {r['score']}, gems {r['gems']}, "
|
|
451
|
+
f"game over in cave {r['cave'] + 1} after {r['starts']} starts, {r['frames']} play frames, "
|
|
452
|
+
f"chained fold 0x{r['fold']:04x}, table row {r['rank'] + 1}")
|
|
453
|
+
if r["frames"] > 255:
|
|
454
|
+
print("gen: more than 255 play frames: the meter records the first 255 only")
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""model_check.py HARNESS_DIR PAL.png NTSC.png: every visible cave cell against the model.
|
|
3
|
+
|
|
4
|
+
The autopilot shot shows cave 2 as it stood at game over, under the table
|
|
5
|
+
box. For each cave cell outside the box this reads the colour at the cell's
|
|
6
|
+
centre (every element glyph is inked there, see render.c) and compares it
|
|
7
|
+
with the colour of the element tools/gen.py's model holds at game over.
|
|
8
|
+
Exit 0 when all match on both pictures. `make modelcheck` runs it.
|
|
9
|
+
"""
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
14
|
+
import gen # noqa: E402
|
|
15
|
+
|
|
16
|
+
TINT = [0, 9, 2, 12, 15, 15, 3, 3, 12, 13, 7, 0, # render.c tint[], element 0..25
|
|
17
|
+
8, 8, 8, 8, 4, 4, 4, 4, 1, 1, 1, 14, 14, 14]
|
|
18
|
+
BOX = (6, 7, 19, 32) # main.c draw_box: rows 6-19, columns 7-32
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main():
|
|
22
|
+
harness, pal, ntsc = sys.argv[1:4]
|
|
23
|
+
sys.path.insert(0, harness)
|
|
24
|
+
import check # the harness's geometry and palette
|
|
25
|
+
|
|
26
|
+
cells = gen.play()["cells"]
|
|
27
|
+
bad = 0
|
|
28
|
+
for path, model in ((pal, "pal"), (ntsc, "ntsc")):
|
|
29
|
+
shot = check.Shot(path, model)
|
|
30
|
+
seen = 0
|
|
31
|
+
for y in range(gen.H):
|
|
32
|
+
for x in range(gen.W):
|
|
33
|
+
row, col = y + 1, x
|
|
34
|
+
if BOX[0] <= row <= BOX[2] and BOX[1] <= col <= BOX[3]:
|
|
35
|
+
continue
|
|
36
|
+
px, py = check.point_xy({"row": row, "col": col}, model)
|
|
37
|
+
got, want = shot.index(px, py), TINT[cells[y * gen.W + x]]
|
|
38
|
+
seen += 1
|
|
39
|
+
if got != want:
|
|
40
|
+
bad += 1
|
|
41
|
+
print(f"FAIL {model.upper()} cave ({x}, {y}): colour {got}, the model's element "
|
|
42
|
+
f"{cells[y * gen.W + x]} is colour {want}")
|
|
43
|
+
print(f"model_check: {model.upper()} {seen} cave cells compared with the model")
|
|
44
|
+
print("model_check: PASS" if bad == 0 else f"model_check: {bad} cells differ")
|
|
45
|
+
sys.exit(1 if bad else 0)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
main()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""verdict_codes.py HARNESS_DIR PNG MODEL LETTERS: the verdict's failure letters.
|
|
3
|
+
|
|
4
|
+
The AUTOPILOT verdict prints one letter per failed test on row 23 from
|
|
5
|
+
column 27 (main.c, verdict). Exit 0 when every letter in LETTERS is there.
|
|
6
|
+
`make selftest-scan` uses it to see that the SCAN_FLAG=0 build fails on E,
|
|
7
|
+
the test that the scan meets the living player exactly once a cave frame.
|
|
8
|
+
"""
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main():
|
|
13
|
+
harness, png, model, want = sys.argv[1:5]
|
|
14
|
+
sys.path.insert(0, harness)
|
|
15
|
+
import check
|
|
16
|
+
got = check.read_text(check.Shot(png, model), check.load_glyphs(), 23, 27, 12).strip()
|
|
17
|
+
missing = [c for c in want if c not in got]
|
|
18
|
+
print(f"verdict_codes: {model.upper()} failure letters '{got}'" +
|
|
19
|
+
(f", missing {''.join(missing)}" if missing else ""))
|
|
20
|
+
sys.exit(1 if missing else 0)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
main()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PreToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "Edit|MultiEdit|Write|NotebookEdit",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "h=\"$CLAUDE_PROJECT_DIR/harness/hooks/plan-gate.py\"; [ -f \"$h\" ] || h=\"$CLAUDE_PROJECT_DIR/../_harness/hooks/plan-gate.py\"; exec python3 \"$h\"",
|
|
11
|
+
"timeout": 10
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Rules for an agent working on this C64 program
|
|
2
|
+
|
|
3
|
+
This program runs on a stock Commodore 64, PAL and NTSC. It is built on the
|
|
4
|
+
c64-kb harness (`./harness`, vendored from c64-kb's `templates/_harness`).
|
|
5
|
+
c64-kb is the reference: its pages give the registers, timings, techniques,
|
|
6
|
+
pitfalls and recipes this program is built from. A wrong number becomes a torn
|
|
7
|
+
screen or a crash, so every claim here is measured or says it is not.
|
|
8
|
+
|
|
9
|
+
A new program starts in c64-kb with `npm run new-project -- <starter> <dir>`.
|
|
10
|
+
That copies the starter and the harness, points `.mcp.json` and `local.mk`
|
|
11
|
+
at the c64-kb checkout, proves the copy with `make shot check`, and leaves a
|
|
12
|
+
blank `PLAN.md`.
|
|
13
|
+
|
|
14
|
+
## This starter: adventure
|
|
15
|
+
|
|
16
|
+
STARWATCH, a two-word text adventure in Oscar64 C: twelve rooms, containers,
|
|
17
|
+
three puzzles, a scored ending, SAVE and LOAD to drive 8, packed text and a
|
|
18
|
+
multicolour picture strip. README.md has the file map and the measured
|
|
19
|
+
frame. Start a program from it with `npm run new-project -- adventure <dir>`
|
|
20
|
+
in c64-kb. `PLAN.md` here is a plan filled from real tool output;
|
|
21
|
+
new-project keeps it as `PLAN-adventure-example.md` and gives the new
|
|
22
|
+
program a blank one.
|
|
23
|
+
|
|
24
|
+
Rules this starter adds:
|
|
25
|
+
|
|
26
|
+
- The world lives in `tools/world.py`. Edit it, run `make gen`, then
|
|
27
|
+
`make shot check`. Never edit the generated `src/gen_*.h`.
|
|
28
|
+
- The engine and the printer live twice: `src/engine.c` and `src/text.c`,
|
|
29
|
+
and the model in `tools/gen.py`. Change both. The verdict compares the
|
|
30
|
+
game with the model (state, a fold of every printed line, the frame
|
|
31
|
+
count); a change on one side only turns it red.
|
|
32
|
+
- A frame does one bounded job: the picture, one window line, or the typed
|
|
33
|
+
keys and a turn. Keep it that way; the meter's worst is the check. The
|
|
34
|
+
script must show every picture (gen.py refuses it otherwise) and stay
|
|
35
|
+
within the meter's 255 frames (gen.py warns).
|
|
36
|
+
- After changing the script or the text, `expect.json`'s texts, the fold
|
|
37
|
+
on row 24 and the meter's `frames` change: `make gen` prints the new
|
|
38
|
+
frame count and fold.
|
|
39
|
+
- Disk calls run on a frame outside the meter, muted, followed by `SEI`.
|
|
40
|
+
Run `make disktest` after any change to `save.c` or the save record.
|
|
41
|
+
|
|
42
|
+
## Before any code
|
|
43
|
+
|
|
44
|
+
1. Brief: `npx tsx src/cli.ts game-briefing "<concept>" --archetype <name>`
|
|
45
|
+
(or `demo-briefing`), in the c64-kb checkout. Read what it proposes.
|
|
46
|
+
2. For each technique you keep: `technique-lookup <name>` and
|
|
47
|
+
`pitfalls-for <name>`. Start from the recipe it names (`recipe-lookup`).
|
|
48
|
+
3. Fill `PLAN.md`: paste the whole output of `check-compatibility` and of
|
|
49
|
+
`plan-budget` (same techniques) into their sections, list every technique
|
|
50
|
+
in its table, and replace every `FILL:` line.
|
|
51
|
+
|
|
52
|
+
Until `PLAN.md` passes, a hook blocks Edit and Write under `src/`, and every
|
|
53
|
+
make target that builds stops (`make plan-gate` says what is missing). With
|
|
54
|
+
C64KB set, `make` re-runs `check-compatibility` and wants the pasted Verdict.
|
|
55
|
+
The gate cannot see writes made through a shell command, or outputs edited
|
|
56
|
+
into shape by hand: do neither. `make PLAN_GATE=off` overrides it; say why in
|
|
57
|
+
`PLAN.md` if you do.
|
|
58
|
+
|
|
59
|
+
## The loop
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
make # build build/<name>.prg
|
|
63
|
+
make shot check # autopilot build, headless PAL and NTSC, graded by expect.json
|
|
64
|
+
make selftest # the FORCE_FAULT build must fail the same checks
|
|
65
|
+
make disk # build/<name>.d64
|
|
66
|
+
make claims # every store the program makes, against what it declares
|
|
67
|
+
make run # windowed VICE, for a human
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Rules
|
|
71
|
+
|
|
72
|
+
- Build before claiming. Code that has not built is not done.
|
|
73
|
+
- Measure screenshots with `check.py` through `expect.json`, never by eye.
|
|
74
|
+
Every visible claim gets a check. Add one before you trust a change.
|
|
75
|
+
- PAL and NTSC: both shots pass, or it is not done.
|
|
76
|
+
- Name the rung for every number: measured here (`make shot`, the meter, the
|
|
77
|
+
VICE monitor), taken from a c64-kb page (say which), arithmetic, or not
|
|
78
|
+
measured. Never call something verified that was not run.
|
|
79
|
+
- Frame cost comes from the meter: CIA2 timer A, printed as
|
|
80
|
+
`F<frames> W<worst> T<typical>` at row 24, columns 20 to 39, in AUTOPILOT
|
|
81
|
+
builds. It records the first `hold` frames: make that the autopilot
|
|
82
|
+
script's play frames. Typical is the median of those frames, the KB's
|
|
83
|
+
`cycles_per_frame_typical`. Keep grading, logging and printing outside the
|
|
84
|
+
bracket; work split between the main loop and IRQs is summed with
|
|
85
|
+
`METER_PAUSE` / `METER_START`.
|
|
86
|
+
- Do not invent a register, routine or address. Look it up:
|
|
87
|
+
`lookup-register`, `lookup-kernal`, `memory-map`.
|
|
88
|
+
- Lint every source you change: `npx tsx src/cli.ts lint <file>`.
|
|
89
|
+
- Commit named paths only. Never `git add -A` or `git add .`. `build/`,
|
|
90
|
+
`shots/` and `local.mk` are never committed.
|
|
91
|
+
|
|
92
|
+
## Harness facts you will need
|
|
93
|
+
|
|
94
|
+
- `AUTOPILOT=1` builds read a scripted joystick byte instead of `$DC00` and
|
|
95
|
+
grade themselves: `$02FF` = `$01` and a green border on pass, `$02` and red
|
|
96
|
+
on fail. `FORCE_FAULT=1` must turn the verdict red and move something a
|
|
97
|
+
screenshot check can see.
|
|
98
|
+
- Screenshot geometry (c64-kb `docs/runtime/vice-reference.md`): PAL 384 x 272,
|
|
99
|
+
row = raster line - 16; NTSC 384 x 247, row = line - 28; x = VIC X + 8. A
|
|
100
|
+
sprite at Y register y is drawn from line y + 1.
|
|
101
|
+
- `check.py` reads text in the ROM character set unless a check names a
|
|
102
|
+
`charset` file; the meter's cells need 0-9, F, W and T in the set on screen.
|
|
103
|
+
- A KickAssembler part called from C is a raw blob at its own `* =` address,
|
|
104
|
+
`$0880` or above; `build/asm.h` gives C its labels as `ASM_<LABEL>`
|
|
105
|
+
(`ASM_<SCOPE>_<LABEL>` inside a scope). Pass arguments through bytes in the
|
|
106
|
+
blob, not Oscar64's zero page (`$02` to `$52`).
|
|
107
|
+
- The meter takes CIA2 timer A. Do not open RS-232 (device 2) while it runs.
|
|
108
|
+
- The KERNAL serial routines end in `CLI` (ROM bytes `58 60` / `58 18` at
|
|
109
|
+
`$EDAB`, `$EDB5`, `$EDDB`, `$EE82`). After any disk call, `SEI` again if
|
|
110
|
+
the program runs with the KERNAL IRQ off: otherwise that IRQ lands inside
|
|
111
|
+
the meter's brackets and rewrites `$DC00`.
|
|
112
|
+
|
|
113
|
+
## Calling c64-kb
|
|
114
|
+
|
|
115
|
+
- CLI, from the c64-kb checkout (`C64KB` in `local.mk`):
|
|
116
|
+
`npx tsx src/cli.ts <command>`; `npx tsx src/cli.ts --help` lists them.
|
|
117
|
+
- MCP: `.mcp.json` starts `node <c64-kb>/dist/cli.js serve` (run
|
|
118
|
+
`npm run build` in c64-kb first).
|