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,787 @@
|
|
|
1
|
+
---
|
|
2
|
+
recipe: wave-director
|
|
3
|
+
toolchain: oscar64
|
|
4
|
+
output_format: PRG
|
|
5
|
+
region: both
|
|
6
|
+
techniques: [wave_director, object_pool]
|
|
7
|
+
file_formats: [PRG]
|
|
8
|
+
uses_registers: [DC04, DC05, DC0E, D000, D001, D010, D011, D012, D015, D020, D021, D027]
|
|
9
|
+
uses_kernal: []
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!-- doc-type: recipe -->
|
|
13
|
+
|
|
14
|
+
# Oscar64 wave director: attack waves keyed to scroll position, with path bytecode
|
|
15
|
+
|
|
16
|
+
## Synopsis
|
|
17
|
+
|
|
18
|
+
A scrolling shooter's attack waves, driven by the level's scroll position
|
|
19
|
+
and not by a frame count. A scroll counter advances one position a frame on
|
|
20
|
+
autopilot, and holds still for 50 frames part-way to show that the waves
|
|
21
|
+
wait for it. A list of six wave records, sorted by trigger position, is read
|
|
22
|
+
through a cursor. Each record names a path, a count, a spawn spacing in
|
|
23
|
+
frames and a formation (start x and x step). Enemies are hardware sprites
|
|
24
|
+
in an eight-slot pool. Each runs one of three paths (dive, weave, swoop)
|
|
25
|
+
written as a small bytecode: MOVE n steps at (dx, dy), FIRE, LOOP, END. An
|
|
26
|
+
enemy leaves when its path ends or it crosses a screen edge; an autopilot
|
|
27
|
+
gun column kills what flies through it, and a wave whose enemies were all
|
|
28
|
+
killed scores a bonus. After the list the level loops, the cursor resets and
|
|
29
|
+
the spawn spacing halves. After 710 frames the program checks every trigger
|
|
30
|
+
against the table and against frames computed in Python, folds the slot
|
|
31
|
+
table into a checksum that the Python model also computes, prints PASS or
|
|
32
|
+
FAIL, and prints the interpreter's cost and a worst frame's, measured with
|
|
33
|
+
CIA1 timer A. It
|
|
34
|
+
implements `wave_director` (`techniques/logic.md`) on top of `object_pool`.
|
|
35
|
+
|
|
36
|
+
## Source
|
|
37
|
+
|
|
38
|
+
```c
|
|
39
|
+
// wave-director.c
|
|
40
|
+
// Attack waves keyed to scroll position. A level scroll counter advances
|
|
41
|
+
// one step a frame on autopilot and stops for 50 frames part-way. A wave
|
|
42
|
+
// list sorted by scroll position is read through a cursor; each record
|
|
43
|
+
// names a path, a count, a spawn spacing in frames and a formation. Each
|
|
44
|
+
// enemy is a hardware sprite that runs a small path bytecode: MOVE n
|
|
45
|
+
// steps at (dx, dy), FIRE, LOOP, END. An enemy leaves when its path ends
|
|
46
|
+
// or it crosses a screen edge; an autopilot gun column kills what flies
|
|
47
|
+
// through it, and a wave whose enemies were all killed earns a bonus.
|
|
48
|
+
// After the list the level loops and the spacing halves. The program logs
|
|
49
|
+
// each trigger, checks it against the table and a Python model, and times
|
|
50
|
+
// the path interpreter with CIA1 timer A.
|
|
51
|
+
#include <c64/vic.h>
|
|
52
|
+
#include <c64/cia.h>
|
|
53
|
+
|
|
54
|
+
#define SCREEN ((char *)0x0400)
|
|
55
|
+
#define COLOUR ((char *)0xd800)
|
|
56
|
+
#define SPRDATA ((char *)0x0340) // sprite block 13
|
|
57
|
+
#define SPRPTR ((char *)0x07f8)
|
|
58
|
+
|
|
59
|
+
#define NS 8 // enemy slots, one hardware sprite each
|
|
60
|
+
#define NWAVES 6
|
|
61
|
+
#define LEVEL_LEN 600 // scroll positions per loop of the level
|
|
62
|
+
#define STOP0 250 // the scroll holds still for frames
|
|
63
|
+
#define STOP1 300 // STOP0 to STOP1 - 1
|
|
64
|
+
#define T_END 710 // frames the game runs before the check
|
|
65
|
+
#define Y_ENTRY 30 // spawn line, above the visible screen
|
|
66
|
+
#define GUN_X0 140 // autopilot gun column: sprite X 140-163,
|
|
67
|
+
#define GUN_X1 164 // at sprite Y 150 and below
|
|
68
|
+
#define GUN_Y 150
|
|
69
|
+
#define EXPECT_CHK 0xEB12 // Python fold over the final slot table
|
|
70
|
+
|
|
71
|
+
// Path bytecode. A byte below $80 is MOVE: that many steps, then signed
|
|
72
|
+
// dx and dy per step. The others take no frame.
|
|
73
|
+
#define P_END 0x80 // leave: free the slot
|
|
74
|
+
#define P_LOOP 0x81 // count, target: jump back count-1 times
|
|
75
|
+
#define P_FIRE 0x82 // fire one shot (counted here)
|
|
76
|
+
|
|
77
|
+
static const char path_dive[] = {
|
|
78
|
+
127, 0, 3,
|
|
79
|
+
P_END };
|
|
80
|
+
static const char path_weave[] = {
|
|
81
|
+
6, 2, 2, 12, 0xfe, 2, 6, 2, 2, // offset 0: one sway, 24 steps
|
|
82
|
+
P_FIRE, // offset 9
|
|
83
|
+
P_LOOP, 3, 0, // offset 10: three sways
|
|
84
|
+
127, 0, 3, // then dive out of the bottom
|
|
85
|
+
P_END };
|
|
86
|
+
static const char path_swoop[] = {
|
|
87
|
+
16, 0, 3, 8, 1, 3, 8, 2, 2, // dive, then bend right
|
|
88
|
+
P_FIRE,
|
|
89
|
+
8, 3, 1, 8, 3, 0, 127, 3, 0xfe, // level out, climb off the side
|
|
90
|
+
P_END };
|
|
91
|
+
static const char * const paths[3] = { path_dive, path_weave, path_swoop };
|
|
92
|
+
static const char path_colour[3] = { VCOL_YELLOW, VCOL_CYAN, VCOL_LT_RED };
|
|
93
|
+
|
|
94
|
+
// The wave list, sorted by trigger position. Enemy k of a wave spawns at
|
|
95
|
+
// x0 + k * xstep on line Y_ENTRY, one every `spacing` frames.
|
|
96
|
+
static const unsigned wave_pos[NWAVES] = { 40, 130, 220, 310, 400, 490 };
|
|
97
|
+
static const char wave_path[NWAVES] = { 0, 1, 2, 0, 1, 2 };
|
|
98
|
+
static const char wave_count[NWAVES] = { 5, 6, 6, 4, 6, 6 };
|
|
99
|
+
static const char wave_spacing[NWAVES] = { 6, 10, 8, 10, 10, 8 };
|
|
100
|
+
static const char wave_x0[NWAVES] = { 60, 40, 30, 150, 120, 100 };
|
|
101
|
+
static const char wave_xstep[NWAVES] = { 30, 0, 12, 0, 0, 12 };
|
|
102
|
+
|
|
103
|
+
// Expected trigger frames from the Python model: the scroll stop delays
|
|
104
|
+
// waves 3 to 5 by 50 frames, and loop 1 starts again at frame 650.
|
|
105
|
+
static const unsigned expect_tick[7] = { 39, 129, 219, 359, 449, 539, 689 };
|
|
106
|
+
|
|
107
|
+
// Enemy slots, parallel arrays indexed by slot = sprite number.
|
|
108
|
+
char e_live[NS], e_x[NS], e_y[NS], e_path[NS], e_pc[NS];
|
|
109
|
+
char e_n[NS], e_dx[NS], e_dy[NS], e_lc[NS], e_wave[NS];
|
|
110
|
+
|
|
111
|
+
// Director state.
|
|
112
|
+
unsigned scroll, tick;
|
|
113
|
+
char loop, cursor;
|
|
114
|
+
char sp_wave, sp_left, sp_timer; // the one active spawner
|
|
115
|
+
char w_alive[NWAVES], w_kill[NWAVES], w_spawned[NWAVES];
|
|
116
|
+
char refused, bonus, escaped, kills, peak;
|
|
117
|
+
unsigned shots;
|
|
118
|
+
|
|
119
|
+
// Trigger log.
|
|
120
|
+
char log_n;
|
|
121
|
+
char log_wave[8], log_loop[8], log_spawn[8];
|
|
122
|
+
unsigned log_scroll[8], log_tick[8];
|
|
123
|
+
|
|
124
|
+
// ---- the path interpreter ------------------------------------------------
|
|
125
|
+
|
|
126
|
+
// One step of slot s. Returns 0 when the path has ended.
|
|
127
|
+
__noinline char path_step(char s)
|
|
128
|
+
{
|
|
129
|
+
const char *p = paths[e_path[s]];
|
|
130
|
+
while (e_n[s] == 0)
|
|
131
|
+
{
|
|
132
|
+
char pc = e_pc[s];
|
|
133
|
+
char op = p[pc];
|
|
134
|
+
if (op == P_END)
|
|
135
|
+
return 0;
|
|
136
|
+
if (op == P_FIRE)
|
|
137
|
+
{
|
|
138
|
+
shots++;
|
|
139
|
+
e_pc[s] = pc + 1;
|
|
140
|
+
}
|
|
141
|
+
else if (op == P_LOOP)
|
|
142
|
+
{
|
|
143
|
+
if (e_lc[s] == 0)
|
|
144
|
+
e_lc[s] = p[pc + 1];
|
|
145
|
+
if (--e_lc[s] != 0)
|
|
146
|
+
e_pc[s] = p[pc + 2];
|
|
147
|
+
else
|
|
148
|
+
e_pc[s] = pc + 3;
|
|
149
|
+
}
|
|
150
|
+
else
|
|
151
|
+
{
|
|
152
|
+
e_n[s] = op;
|
|
153
|
+
e_dx[s] = p[pc + 1];
|
|
154
|
+
e_dy[s] = p[pc + 2];
|
|
155
|
+
e_pc[s] = pc + 3;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
e_x[s] += e_dx[s];
|
|
159
|
+
e_y[s] += e_dy[s];
|
|
160
|
+
e_n[s]--;
|
|
161
|
+
return 1;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ---- the director --------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
static void spawn(char w, char k)
|
|
167
|
+
{
|
|
168
|
+
for (char s = 0; s < NS; s++)
|
|
169
|
+
{
|
|
170
|
+
if (!e_live[s])
|
|
171
|
+
{
|
|
172
|
+
e_live[s] = 1;
|
|
173
|
+
e_x[s] = wave_x0[w] + k * wave_xstep[w];
|
|
174
|
+
e_y[s] = Y_ENTRY;
|
|
175
|
+
e_path[s] = wave_path[w];
|
|
176
|
+
e_pc[s] = 0;
|
|
177
|
+
e_n[s] = 0;
|
|
178
|
+
e_lc[s] = 0;
|
|
179
|
+
e_wave[s] = w;
|
|
180
|
+
w_alive[w]++;
|
|
181
|
+
w_spawned[w]++;
|
|
182
|
+
log_spawn[log_n - 1]++;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
refused++;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
static void gone(char s, char killed)
|
|
190
|
+
{
|
|
191
|
+
char w = e_wave[s];
|
|
192
|
+
e_live[s] = 0;
|
|
193
|
+
w_alive[w]--;
|
|
194
|
+
if (killed)
|
|
195
|
+
{
|
|
196
|
+
w_kill[w]++;
|
|
197
|
+
kills++;
|
|
198
|
+
}
|
|
199
|
+
// The wave is over when none is alive and the spawner has finished it.
|
|
200
|
+
if (w_alive[w] == 0 && w_spawned[w] == wave_count[w] &&
|
|
201
|
+
!(sp_left != 0 && sp_wave == w))
|
|
202
|
+
{
|
|
203
|
+
if (w_kill[w] == wave_count[w])
|
|
204
|
+
bonus++;
|
|
205
|
+
else
|
|
206
|
+
escaped++;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Start every wave whose position the scroll has reached. >= and not ==,
|
|
211
|
+
// so a scroll that moves more than one position a frame cannot skip one.
|
|
212
|
+
__noinline void director(void)
|
|
213
|
+
{
|
|
214
|
+
while (cursor < NWAVES && scroll >= wave_pos[cursor])
|
|
215
|
+
{
|
|
216
|
+
char w = cursor;
|
|
217
|
+
log_wave[log_n] = w;
|
|
218
|
+
log_loop[log_n] = loop;
|
|
219
|
+
log_scroll[log_n] = scroll;
|
|
220
|
+
log_tick[log_n] = tick;
|
|
221
|
+
log_spawn[log_n] = 0;
|
|
222
|
+
log_n++;
|
|
223
|
+
sp_wave = w;
|
|
224
|
+
sp_left = wave_count[w];
|
|
225
|
+
sp_timer = 0;
|
|
226
|
+
w_alive[w] = 0;
|
|
227
|
+
w_kill[w] = 0;
|
|
228
|
+
w_spawned[w] = 0;
|
|
229
|
+
cursor++;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
static void spawner(void)
|
|
234
|
+
{
|
|
235
|
+
if (sp_left == 0)
|
|
236
|
+
return;
|
|
237
|
+
if (sp_timer == 0)
|
|
238
|
+
{
|
|
239
|
+
char w = sp_wave;
|
|
240
|
+
spawn(w, wave_count[w] - sp_left);
|
|
241
|
+
sp_left--;
|
|
242
|
+
char gap = wave_spacing[w] >> loop; // difficulty: loop 1 halves it
|
|
243
|
+
if (gap == 0)
|
|
244
|
+
gap = 1;
|
|
245
|
+
sp_timer = gap - 1;
|
|
246
|
+
}
|
|
247
|
+
else
|
|
248
|
+
sp_timer--;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Every live enemy: one path step, the edge test, the gun column.
|
|
252
|
+
__noinline void update_enemies(void)
|
|
253
|
+
{
|
|
254
|
+
for (char s = 0; s < NS; s++)
|
|
255
|
+
{
|
|
256
|
+
if (!e_live[s])
|
|
257
|
+
continue;
|
|
258
|
+
if (!path_step(s))
|
|
259
|
+
gone(s, 0);
|
|
260
|
+
else if (e_x[s] >= 250 || e_y[s] >= 250) // off any edge: a byte
|
|
261
|
+
gone(s, 0); // that wrapped reads >= 250
|
|
262
|
+
else if (e_x[s] >= GUN_X0 && e_x[s] < GUN_X1 && e_y[s] >= GUN_Y)
|
|
263
|
+
gone(s, 1);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
static void game_tick(void)
|
|
268
|
+
{
|
|
269
|
+
if (tick < STOP0 || tick >= STOP1)
|
|
270
|
+
{
|
|
271
|
+
scroll++;
|
|
272
|
+
if (scroll == LEVEL_LEN)
|
|
273
|
+
{
|
|
274
|
+
scroll = 0;
|
|
275
|
+
loop++;
|
|
276
|
+
cursor = 0;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
director();
|
|
280
|
+
spawner();
|
|
281
|
+
update_enemies();
|
|
282
|
+
char n = 0;
|
|
283
|
+
for (char s = 0; s < NS; s++)
|
|
284
|
+
n += e_live[s];
|
|
285
|
+
if (n > peak)
|
|
286
|
+
peak = n;
|
|
287
|
+
tick++;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Sprite X is the 8-bit enemy x, so the playfield is sprite X 0-249 and
|
|
291
|
+
// $D010 stays 0.
|
|
292
|
+
static void draw_sprites(void)
|
|
293
|
+
{
|
|
294
|
+
char en = 0;
|
|
295
|
+
for (char s = 0; s < NS; s++)
|
|
296
|
+
{
|
|
297
|
+
if (e_live[s])
|
|
298
|
+
{
|
|
299
|
+
vic.spr_pos[s].x = e_x[s];
|
|
300
|
+
vic.spr_pos[s].y = e_y[s];
|
|
301
|
+
vic.spr_color[s] = path_colour[e_path[s]];
|
|
302
|
+
en |= 1 << s;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
vic.spr_enable = en;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ---- timing subjects -----------------------------------------------------
|
|
309
|
+
|
|
310
|
+
// Each subject resets slot 0 and runs one step; `reset_only` is the
|
|
311
|
+
// baseline that does the reset without the step.
|
|
312
|
+
__noinline void reset_only(void)
|
|
313
|
+
{
|
|
314
|
+
e_path[0] = 1; e_pc[0] = 9; e_n[0] = 100; e_lc[0] = 2;
|
|
315
|
+
}
|
|
316
|
+
__noinline void step_move(void) // steps left: no fetch
|
|
317
|
+
{
|
|
318
|
+
e_path[0] = 1; e_pc[0] = 9; e_n[0] = 100; e_lc[0] = 2;
|
|
319
|
+
path_step(0);
|
|
320
|
+
}
|
|
321
|
+
__noinline void step_fetch(void) // fetch one MOVE, then step
|
|
322
|
+
{
|
|
323
|
+
e_path[0] = 1; e_pc[0] = 0; e_n[0] = 0; e_lc[0] = 2;
|
|
324
|
+
path_step(0);
|
|
325
|
+
}
|
|
326
|
+
__noinline void step_fire_loop(void) // FIRE, LOOP back, MOVE, step
|
|
327
|
+
{
|
|
328
|
+
e_path[0] = 1; e_pc[0] = 9; e_n[0] = 0; e_lc[0] = 2;
|
|
329
|
+
path_step(0);
|
|
330
|
+
}
|
|
331
|
+
__noinline void nothing(void)
|
|
332
|
+
{
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// A frame's director work, spawner and path steps (no scroll, no drawing).
|
|
336
|
+
// Positions are reset each call, so nothing leaves or is shot.
|
|
337
|
+
// 8 moving: all eight slots mid-MOVE on the dive path, nothing due.
|
|
338
|
+
__noinline void reset8_only(void)
|
|
339
|
+
{
|
|
340
|
+
for (char s = 0; s < NS; s++)
|
|
341
|
+
{
|
|
342
|
+
e_live[s] = 1; e_path[s] = 0; e_pc[s] = 0; e_n[s] = 0;
|
|
343
|
+
e_x[s] = 100; e_y[s] = 100;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
static void frame_work(void)
|
|
347
|
+
{
|
|
348
|
+
director();
|
|
349
|
+
spawner();
|
|
350
|
+
update_enemies();
|
|
351
|
+
}
|
|
352
|
+
__noinline void frame8_move(void)
|
|
353
|
+
{
|
|
354
|
+
for (char s = 0; s < NS; s++)
|
|
355
|
+
{
|
|
356
|
+
e_live[s] = 1; e_path[s] = 0; e_pc[s] = 0; e_n[s] = 100;
|
|
357
|
+
e_x[s] = 100; e_y[s] = 100;
|
|
358
|
+
}
|
|
359
|
+
frame_work();
|
|
360
|
+
}
|
|
361
|
+
// Worst frame: seven live enemies each on the weave path's FIRE, LOOP
|
|
362
|
+
// back and MOVE fetch, wave 0 due at scroll 40, and its first enemy
|
|
363
|
+
// spawned into the free slot 7, which then fetches its first MOVE.
|
|
364
|
+
__noinline void reset_worst(void)
|
|
365
|
+
{
|
|
366
|
+
for (char s = 0; s < NS; s++)
|
|
367
|
+
{
|
|
368
|
+
e_live[s] = 1; e_path[s] = 1; e_pc[s] = 9; e_n[s] = 0; e_lc[s] = 2;
|
|
369
|
+
e_x[s] = 100; e_y[s] = 100;
|
|
370
|
+
}
|
|
371
|
+
e_live[7] = 0;
|
|
372
|
+
cursor = 0; scroll = 40; loop = 0; log_n = 0;
|
|
373
|
+
}
|
|
374
|
+
__noinline void frame_worst(void)
|
|
375
|
+
{
|
|
376
|
+
for (char s = 0; s < NS; s++)
|
|
377
|
+
{
|
|
378
|
+
e_live[s] = 1; e_path[s] = 1; e_pc[s] = 9; e_n[s] = 0; e_lc[s] = 2;
|
|
379
|
+
e_x[s] = 100; e_y[s] = 100;
|
|
380
|
+
}
|
|
381
|
+
e_live[7] = 0;
|
|
382
|
+
cursor = 0; scroll = 40; loop = 0; log_n = 0;
|
|
383
|
+
frame_work();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// CIA1 timer A: force-load $FFFF, count phi2 while fn runs `calls`
|
|
387
|
+
// times, read. The frame subjects run 20 or 10 times so the 16-bit
|
|
388
|
+
// count cannot wrap.
|
|
389
|
+
static unsigned time_loop(void (*fn)(void), char calls)
|
|
390
|
+
{
|
|
391
|
+
cia1.cra = 0x00;
|
|
392
|
+
cia1.ta = 0xffff;
|
|
393
|
+
cia1.cra = 0x11;
|
|
394
|
+
char i = calls;
|
|
395
|
+
do
|
|
396
|
+
{
|
|
397
|
+
fn();
|
|
398
|
+
} while (--i);
|
|
399
|
+
cia1.cra = 0x00;
|
|
400
|
+
return 0xffff - cia1.ta;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// ---- screen --------------------------------------------------------------
|
|
404
|
+
|
|
405
|
+
static void put_str(char row, char col, const char *s)
|
|
406
|
+
{
|
|
407
|
+
char *p = SCREEN + 40 * row + col;
|
|
408
|
+
while (*s)
|
|
409
|
+
{
|
|
410
|
+
char c = *s++;
|
|
411
|
+
*p++ = (c >= 'a' && c <= 'z') ? c - 'a' + 1 : c;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
static void put_dec(char row, char col, unsigned v, char width)
|
|
416
|
+
{
|
|
417
|
+
char *p = SCREEN + 40 * row + col + width;
|
|
418
|
+
do
|
|
419
|
+
{
|
|
420
|
+
*--p = '0' + v % 10;
|
|
421
|
+
v /= 10;
|
|
422
|
+
} while (--width);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
static const char hex_glyph[16] = {
|
|
426
|
+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 1, 2, 3, 4, 5, 6 };
|
|
427
|
+
|
|
428
|
+
static void put_hex16(char row, char col, unsigned v)
|
|
429
|
+
{
|
|
430
|
+
char *p = SCREEN + 40 * row + col;
|
|
431
|
+
p[0] = hex_glyph[(v >> 12) & 15];
|
|
432
|
+
p[1] = hex_glyph[(v >> 8) & 15];
|
|
433
|
+
p[2] = hex_glyph[(v >> 4) & 15];
|
|
434
|
+
p[3] = hex_glyph[v & 15];
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Net cycles per call to two decimals: (t - t0) / calls.
|
|
438
|
+
static void put_per_call(char row, char col, unsigned t, unsigned t0, char calls)
|
|
439
|
+
{
|
|
440
|
+
unsigned n = t - t0;
|
|
441
|
+
put_dec(row, col, n / calls, 4);
|
|
442
|
+
SCREEN[40 * row + col + 4] = '.';
|
|
443
|
+
put_dec(row, col + 5, (n % calls) * 100 / calls, 2);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
static unsigned fold(unsigned cs, unsigned v)
|
|
447
|
+
{
|
|
448
|
+
return (cs ^ v) * 5 + 1;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
int main(void)
|
|
452
|
+
{
|
|
453
|
+
for (unsigned i = 0; i < 1000; i++)
|
|
454
|
+
{
|
|
455
|
+
SCREEN[i] = 0x20;
|
|
456
|
+
COLOUR[i] = VCOL_WHITE;
|
|
457
|
+
}
|
|
458
|
+
vic.color_back = VCOL_BLACK;
|
|
459
|
+
vic.color_border = VCOL_BLACK;
|
|
460
|
+
for (char k = 0; k < 64; k++) // an 8 by 8 square
|
|
461
|
+
SPRDATA[k] = (k < 24 && k % 3 == 0) ? 0xff : 0x00;
|
|
462
|
+
for (char s = 0; s < NS; s++)
|
|
463
|
+
SPRPTR[s] = 13;
|
|
464
|
+
vic.spr_msbx = 0;
|
|
465
|
+
|
|
466
|
+
put_str(7, 0, "wave director 6 waves 3 paths");
|
|
467
|
+
put_str(8, 0, "w lp pos tick spawn");
|
|
468
|
+
|
|
469
|
+
// The game: one tick a frame, sprites written after the tick.
|
|
470
|
+
char shown = 0;
|
|
471
|
+
while (tick < T_END)
|
|
472
|
+
{
|
|
473
|
+
vic_waitFrame();
|
|
474
|
+
draw_sprites();
|
|
475
|
+
game_tick();
|
|
476
|
+
while (shown < log_n)
|
|
477
|
+
{
|
|
478
|
+
char r = 9 + shown;
|
|
479
|
+
put_dec(r, 0, log_wave[shown], 1);
|
|
480
|
+
put_dec(r, 2, log_loop[shown], 1);
|
|
481
|
+
put_dec(r, 5, log_scroll[shown], 3);
|
|
482
|
+
put_dec(r, 9, log_tick[shown], 4);
|
|
483
|
+
shown++;
|
|
484
|
+
}
|
|
485
|
+
put_str(8, 26, "scroll");
|
|
486
|
+
put_dec(8, 33, scroll, 3);
|
|
487
|
+
}
|
|
488
|
+
draw_sprites();
|
|
489
|
+
|
|
490
|
+
// Checks: every trigger at its table position, on the model's frame,
|
|
491
|
+
// with the table's count spawned.
|
|
492
|
+
bool pass = log_n == 7 && refused == 0;
|
|
493
|
+
for (char i = 0; i < log_n; i++)
|
|
494
|
+
{
|
|
495
|
+
char w = log_wave[i];
|
|
496
|
+
put_dec(9 + i, 16, log_spawn[i], 1);
|
|
497
|
+
if (w != i % NWAVES || log_scroll[i] != wave_pos[w] ||
|
|
498
|
+
log_tick[i] != expect_tick[i] || log_spawn[i] != wave_count[w])
|
|
499
|
+
pass = false;
|
|
500
|
+
}
|
|
501
|
+
put_str(16, 0, "refused peak bonus kills");
|
|
502
|
+
put_dec(16, 8, refused, 1);
|
|
503
|
+
put_dec(16, 15, peak, 1);
|
|
504
|
+
put_dec(16, 23, bonus, 1);
|
|
505
|
+
put_dec(16, 31, kills, 1);
|
|
506
|
+
put_str(17, 20, "shots");
|
|
507
|
+
put_dec(17, 26, shots, 2);
|
|
508
|
+
|
|
509
|
+
unsigned chk = 0;
|
|
510
|
+
for (char s = 0; s < NS; s++)
|
|
511
|
+
{
|
|
512
|
+
chk = fold(chk, e_live[s]);
|
|
513
|
+
chk = fold(chk, e_x[s]);
|
|
514
|
+
chk = fold(chk, e_y[s]);
|
|
515
|
+
chk = fold(chk, e_pc[s]);
|
|
516
|
+
chk = fold(chk, e_n[s]);
|
|
517
|
+
chk = fold(chk, e_lc[s]);
|
|
518
|
+
}
|
|
519
|
+
put_str(17, 0, "chk exp");
|
|
520
|
+
put_hex16(17, 4, chk);
|
|
521
|
+
put_hex16(17, 13, EXPECT_CHK);
|
|
522
|
+
pass = pass && chk == EXPECT_CHK;
|
|
523
|
+
|
|
524
|
+
// Timing. The picture and the checks are done, so the subjects may
|
|
525
|
+
// overwrite the slots. Sprites off, interrupts off, screen blanked, so
|
|
526
|
+
// no DMA or IRQ lands in a count.
|
|
527
|
+
char en = vic.spr_enable;
|
|
528
|
+
__asm { sei }
|
|
529
|
+
vic.spr_enable = 0;
|
|
530
|
+
vic.ctrl1 = 0x0b;
|
|
531
|
+
vic_waitFrame();
|
|
532
|
+
unsigned t0 = time_loop(nothing, 100);
|
|
533
|
+
unsigned tb = time_loop(reset_only, 100);
|
|
534
|
+
unsigned t_mv = time_loop(step_move, 100);
|
|
535
|
+
unsigned t_fe = time_loop(step_fetch, 100);
|
|
536
|
+
unsigned t_fl = time_loop(step_fire_loop, 100);
|
|
537
|
+
unsigned t_di = time_loop(director, 100); // cursor at 1: no trigger
|
|
538
|
+
unsigned tb8 = time_loop(reset8_only, 20);
|
|
539
|
+
unsigned t_f8m = time_loop(frame8_move, 20);
|
|
540
|
+
unsigned tbw = time_loop(reset_worst, 10);
|
|
541
|
+
unsigned t_w = time_loop(frame_worst, 10);
|
|
542
|
+
vic.ctrl1 = 0x1b;
|
|
543
|
+
vic.spr_enable = en;
|
|
544
|
+
|
|
545
|
+
put_str(18, 0, "cycles n total per call");
|
|
546
|
+
put_str(19, 0, "step, move");
|
|
547
|
+
put_dec(19, 16, 100, 3);
|
|
548
|
+
put_dec(19, 21, t_mv, 5);
|
|
549
|
+
put_per_call(19, 28, t_mv, tb, 100);
|
|
550
|
+
put_str(20, 0, "step, fetch");
|
|
551
|
+
put_dec(20, 16, 100, 3);
|
|
552
|
+
put_dec(20, 21, t_fe, 5);
|
|
553
|
+
put_per_call(20, 28, t_fe, tb, 100);
|
|
554
|
+
put_str(21, 0, "fire+loop+move");
|
|
555
|
+
put_dec(21, 16, 100, 3);
|
|
556
|
+
put_dec(21, 21, t_fl, 5);
|
|
557
|
+
put_per_call(21, 28, t_fl, tb, 100);
|
|
558
|
+
put_str(22, 0, "director idle");
|
|
559
|
+
put_dec(22, 16, 100, 3);
|
|
560
|
+
put_dec(22, 21, t_di, 5);
|
|
561
|
+
put_per_call(22, 28, t_di, t0, 100);
|
|
562
|
+
put_str(23, 0, "8 moving");
|
|
563
|
+
put_dec(23, 16, 20, 3);
|
|
564
|
+
put_dec(23, 21, t_f8m, 5);
|
|
565
|
+
put_per_call(23, 28, t_f8m, tb8, 20);
|
|
566
|
+
put_str(24, 0, "worst frame");
|
|
567
|
+
put_dec(24, 16, 10, 3);
|
|
568
|
+
put_dec(24, 21, t_w, 5);
|
|
569
|
+
put_per_call(24, 28, t_w, tbw, 10);
|
|
570
|
+
|
|
571
|
+
put_str(7, 36, pass ? "pass" : "fail");
|
|
572
|
+
vic.color_border = pass ? VCOL_GREEN : VCOL_RED;
|
|
573
|
+
for (;;)
|
|
574
|
+
;
|
|
575
|
+
return 0;
|
|
576
|
+
}
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
## Build
|
|
580
|
+
|
|
581
|
+
```
|
|
582
|
+
oscar64 -tm=c64 -O2 -o=wave-director.prg wave-director.c
|
|
583
|
+
GSETTINGS_SCHEMA_DIR=/opt/homebrew/share/glib-2.0/schemas timeout 180 x64sc -default -minimized -warp +sound +autostart-delay-random -autostartprgmode 1 -limitcycles 20000000 -exitscreenshot wave-director.png -autostart wave-director.prg
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
Add `-model ntsc` for the NTSC picture. 20,000,000 cycles is the pinned
|
|
587
|
+
run. The game runs 710 frames, about 14,000,000 cycles on PAL and
|
|
588
|
+
12,140,000 on NTSC (arithmetic: 19,656 and 17,095 cycles a frame). The PAL
|
|
589
|
+
screen was not yet complete at 16,000,000 and complete at 18,000,000; NTSC
|
|
590
|
+
was complete at 16,000,000 (measured in VICE x64sc 3.10). The PRG is 3,777
|
|
591
|
+
bytes.
|
|
592
|
+
|
|
593
|
+
## Expected output
|
|
594
|
+
|
|
595
|
+
Black screen, green border, five yellow 8 by 8 squares in a diagonal above
|
|
596
|
+
the text. Decoded from `screenshots/wave-director.png` (PAL) with the
|
|
597
|
+
character ROM; rows 0 to 6 hold no text:
|
|
598
|
+
|
|
599
|
+
```text
|
|
600
|
+
WAVE DIRECTOR 6 WAVES 3 PATHS PASS
|
|
601
|
+
W LP POS TICK SPAWN SCROLL 060
|
|
602
|
+
0 0 040 0039 5
|
|
603
|
+
1 0 130 0129 6
|
|
604
|
+
2 0 220 0219 6
|
|
605
|
+
3 0 310 0359 4
|
|
606
|
+
4 0 400 0449 6
|
|
607
|
+
5 0 490 0539 6
|
|
608
|
+
0 1 040 0689 5
|
|
609
|
+
REFUSED 0 PEAK 8 BONUS 1 KILLS 5
|
|
610
|
+
CHK EB12 EXP EB12 SHOTS 48
|
|
611
|
+
CYCLES N TOTAL PER CALL
|
|
612
|
+
STEP, MOVE 100 14104 0080.00
|
|
613
|
+
STEP, FETCH 100 21904 0158.00
|
|
614
|
+
FIRE+LOOP+MOVE 100 35004 0289.00
|
|
615
|
+
DIRECTOR IDLE 100 08204 0045.00
|
|
616
|
+
8 MOVING 020 31044 1170.00
|
|
617
|
+
WORST FRAME 010 36704 3188.00
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
`screenshots/wave-director-ntsc.png` (`-model ntsc`) decodes to the same
|
|
621
|
+
text, and the cycle counts are identical on both models (the CIA counts phi2
|
|
622
|
+
cycles with the screen blanked). Each model's pinned run was made twice and
|
|
623
|
+
gave byte-identical PNGs (measured in VICE x64sc 3.10).
|
|
624
|
+
|
|
625
|
+
What each row states:
|
|
626
|
+
|
|
627
|
+
- Rows 9 to 15, the trigger log: wave, loop, scroll position at the
|
|
628
|
+
trigger, frame of the trigger, enemies spawned. Every scroll position
|
|
629
|
+
equals the table's, and every spawn count equals the table's count.
|
|
630
|
+
Waves 0 to 2 trigger on frames 39, 129 and 219: frame 0 already moves
|
|
631
|
+
the scroll to 1, and the director looks after the move. The scroll
|
|
632
|
+
holds for frames 250 to 299, so waves 3 to 5 trigger 50 frames later
|
|
633
|
+
than their position (359, 449, 539) and still at their position. The
|
|
634
|
+
level loops at frame 650 and wave 0 starts again at frame 689.
|
|
635
|
+
- Row 16: no spawn found the pool full; at most 8 enemies were live at
|
|
636
|
+
once; one wave (wave 3, four dives down the gun column at x 150) was
|
|
637
|
+
killed whole and scored the bonus; 5 kills in all (wave 3's four and
|
|
638
|
+
wave 0's enemy at x 150).
|
|
639
|
+
- Row 17: the fold over the 48 bytes of `e_live`, `e_x`, `e_y`, `e_pc`,
|
|
640
|
+
`e_n` and `e_lc` is $EB12 on the 6510 and in Python; 48 FIRE opcodes ran.
|
|
641
|
+
- Rows 19 to 24: CIA1 timer A over N calls, total and net per call. The
|
|
642
|
+
single-step rows subtract a subject that does the same slot reset without
|
|
643
|
+
the step; the director row subtracts an empty call; each frame row
|
|
644
|
+
subtracts a subject that does its slot reset without the frame's work.
|
|
645
|
+
A frame row times the director, the spawner and every live enemy's
|
|
646
|
+
step with its edge and gun tests. 8 moving: eight enemies mid-MOVE,
|
|
647
|
+
nothing due. Worst frame: seven enemies on the weave path's FIRE, LOOP
|
|
648
|
+
back and MOVE fetch in one step, a wave due, and its first enemy
|
|
649
|
+
spawned into the last free slot, which fetches its first MOVE.
|
|
650
|
+
|
|
651
|
+
The sprites, measured with PIL on both pictures. They are loop 1's wave 0,
|
|
652
|
+
five dives spawned every 3 frames instead of 6, so they are 9 lines apart
|
|
653
|
+
where loop 0's were 18. Screenshot x is sprite X plus 8; the top raster
|
|
654
|
+
line is the sprite Y register plus 1:
|
|
655
|
+
|
|
656
|
+
| Sprite X, Y (Python model) | Screenshot x | PAL rows | NTSC rows | Raster lines |
|
|
657
|
+
|---|---|---|---|---|
|
|
658
|
+
| 60, 93 | 68 to 75 | 78 to 85 | 66 to 73 | 94 to 101 |
|
|
659
|
+
| 90, 84 | 98 to 105 | 69 to 76 | 57 to 64 | 85 to 92 |
|
|
660
|
+
| 120, 75 | 128 to 135 | 60 to 67 | 48 to 55 | 76 to 83 |
|
|
661
|
+
| 150, 66 | 158 to 165 | 51 to 58 | 39 to 46 | 67 to 74 |
|
|
662
|
+
| 180, 57 | 188 to 195 | 42 to 49 | 30 to 37 | 58 to 65 |
|
|
663
|
+
|
|
664
|
+
Every square is where the model puts it, to the pixel, on both models. The
|
|
665
|
+
model of the whole run:
|
|
666
|
+
|
|
667
|
+
```python
|
|
668
|
+
END, LOOP, FIRE = 0x80, 0x81, 0x82
|
|
669
|
+
PATHS = [[127, 0, 3, END],
|
|
670
|
+
[6, 2, 2, 12, 0xfe, 2, 6, 2, 2, FIRE, LOOP, 3, 0, 127, 0, 3, END],
|
|
671
|
+
[16, 0, 3, 8, 1, 3, 8, 2, 2, FIRE, 8, 3, 1, 8, 3, 0, 127, 3, 0xfe, END]]
|
|
672
|
+
WAVES = [(40, 0, 5, 6, 60, 30), (130, 1, 6, 10, 40, 0), (220, 2, 6, 8, 30, 12),
|
|
673
|
+
(310, 0, 4, 10, 150, 0), (400, 1, 6, 10, 120, 0), (490, 2, 6, 8, 100, 12)]
|
|
674
|
+
NS = 8
|
|
675
|
+
live, x, y, pa, pc, n, dx, dy, lc, wv = ([0] * NS for _ in range(10))
|
|
676
|
+
g = dict(scroll=0, loop=0, cur=0, left=0, timer=0, sw=0, refused=0,
|
|
677
|
+
bonus=0, kills=0, shots=0, peak=0)
|
|
678
|
+
alive, killed, spawned = [0] * 6, [0] * 6, [0] * 6
|
|
679
|
+
log = []
|
|
680
|
+
|
|
681
|
+
def step(s):
|
|
682
|
+
p = PATHS[pa[s]]
|
|
683
|
+
while n[s] == 0:
|
|
684
|
+
op = p[pc[s]]
|
|
685
|
+
if op == END:
|
|
686
|
+
return False
|
|
687
|
+
if op == FIRE:
|
|
688
|
+
g['shots'] += 1; pc[s] += 1
|
|
689
|
+
elif op == LOOP:
|
|
690
|
+
if lc[s] == 0: lc[s] = p[pc[s] + 1]
|
|
691
|
+
lc[s] -= 1
|
|
692
|
+
pc[s] = p[pc[s] + 2] if lc[s] else pc[s] + 3
|
|
693
|
+
else:
|
|
694
|
+
n[s], dx[s], dy[s] = op, p[pc[s] + 1], p[pc[s] + 2]; pc[s] += 3
|
|
695
|
+
x[s] = (x[s] + dx[s]) & 255; y[s] = (y[s] + dy[s]) & 255; n[s] -= 1
|
|
696
|
+
return True
|
|
697
|
+
|
|
698
|
+
def gone(s, hit):
|
|
699
|
+
w = wv[s]; live[s] = 0; alive[w] -= 1
|
|
700
|
+
if hit: killed[w] += 1; g['kills'] += 1
|
|
701
|
+
if alive[w] == 0 and spawned[w] == WAVES[w][2] and not (g['left'] and g['sw'] == w):
|
|
702
|
+
g['bonus'] += killed[w] == WAVES[w][2]
|
|
703
|
+
|
|
704
|
+
for t in range(710):
|
|
705
|
+
if not 250 <= t < 300:
|
|
706
|
+
g['scroll'] += 1
|
|
707
|
+
if g['scroll'] == 600:
|
|
708
|
+
g['scroll'], g['cur'] = 0, 0; g['loop'] += 1
|
|
709
|
+
while g['cur'] < 6 and g['scroll'] >= WAVES[g['cur']][0]:
|
|
710
|
+
w = g['cur']; log.append([w, g['loop'], g['scroll'], t, 0])
|
|
711
|
+
g['sw'], g['left'], g['timer'] = w, WAVES[w][2], 0
|
|
712
|
+
alive[w] = killed[w] = spawned[w] = 0; g['cur'] += 1
|
|
713
|
+
if g['left']:
|
|
714
|
+
if g['timer'] == 0:
|
|
715
|
+
w = g['sw']; pos, path, cnt, spc, x0, xs = WAVES[w]
|
|
716
|
+
free = [s for s in range(NS) if not live[s]]
|
|
717
|
+
if free:
|
|
718
|
+
s = free[0]
|
|
719
|
+
live[s], x[s], y[s], pa[s], pc[s], n[s], lc[s], wv[s] = \
|
|
720
|
+
1, (x0 + (cnt - g['left']) * xs) & 255, 30, path, 0, 0, 0, w
|
|
721
|
+
alive[w] += 1; spawned[w] += 1; log[-1][4] += 1
|
|
722
|
+
else:
|
|
723
|
+
g['refused'] += 1
|
|
724
|
+
g['left'] -= 1
|
|
725
|
+
g['timer'] = max(1, spc >> g['loop']) - 1
|
|
726
|
+
else:
|
|
727
|
+
g['timer'] -= 1
|
|
728
|
+
for s in range(NS):
|
|
729
|
+
if not live[s]: continue
|
|
730
|
+
if not step(s): gone(s, False)
|
|
731
|
+
elif x[s] >= 250 or y[s] >= 250: gone(s, False)
|
|
732
|
+
elif 140 <= x[s] < 164 and y[s] >= 150: gone(s, True)
|
|
733
|
+
g['peak'] = max(g['peak'], sum(live))
|
|
734
|
+
|
|
735
|
+
chk = 0
|
|
736
|
+
for s in range(NS):
|
|
737
|
+
for v in (live[s], x[s], y[s], pc[s], n[s], lc[s]):
|
|
738
|
+
chk = ((chk ^ v) * 5 + 1) & 0xFFFF
|
|
739
|
+
print(log)
|
|
740
|
+
print(g['refused'], g['peak'], g['bonus'], g['kills'], g['shots'], hex(chk))
|
|
741
|
+
print([(x[s], y[s]) for s in range(NS) if live[s]])
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
It prints the seven log rows above as lists, `0 8 1 5 48 0xeb12`, and the five
|
|
745
|
+
positions in the table.
|
|
746
|
+
|
|
747
|
+
## Why this works
|
|
748
|
+
|
|
749
|
+
The trigger compares the scroll position, not the frame. The 50-frame hold
|
|
750
|
+
proves it: waves 3 to 5 start 50 frames late and at their exact positions,
|
|
751
|
+
so the enemies meet the same scenery they were placed against. A frame-keyed
|
|
752
|
+
table would have started them on frames 309, 399 and 489, while the scroll
|
|
753
|
+
stood still. The compare is `>=`, and the director loops while the next
|
|
754
|
+
record is due, so a scroll that jumps several positions in a frame starts
|
|
755
|
+
every wave it passed, in order, and never skips one. Because the list is
|
|
756
|
+
sorted, one compare against the record under the cursor is the whole idle
|
|
757
|
+
cost: 45 cycles a frame in C.
|
|
758
|
+
|
|
759
|
+
A path is data, so one interpreter moves every enemy. A MOVE costs a fetch
|
|
760
|
+
once and then a plain add per frame: 80 cycles a step with steps left, 158
|
|
761
|
+
on a step that fetches the next MOVE, 289 on one that also runs FIRE and a
|
|
762
|
+
LOOP back (all Oscar64 -O2, measured). The control opcodes take no frame,
|
|
763
|
+
so a path can fire and loop between two moves without a stall. Each enemy
|
|
764
|
+
carries only a path id, a program counter, a step count, a velocity and a
|
|
765
|
+
loop counter; the path bytes are shared by every enemy on that path.
|
|
766
|
+
|
|
767
|
+
The edge test is one compare per axis. x and y are bytes, and any byte at
|
|
768
|
+
250 or more is off screen: moving right past 249 or up or left past 0 both
|
|
769
|
+
land there, because a byte that goes below 0 wraps to 255. The price is a
|
|
770
|
+
playfield of sprite X 0 to 249, so `$D010` stays 0 and cannot be forgotten
|
|
771
|
+
(`sprite_x_high_bit_wrong_register`). A full-width game keeps a ninth x bit
|
|
772
|
+
per enemy and writes `$D010` from it.
|
|
773
|
+
|
|
774
|
+
The frame's director work with all eight slots live and mid-MOVE is 1,170
|
|
775
|
+
cycles, about 146 per enemy with the edge and gun tests. The worst frame
|
|
776
|
+
measured is 3,188: seven enemies each run FIRE, a LOOP back and a MOVE
|
|
777
|
+
fetch in one step (the longest step these paths have), a wave triggers,
|
|
778
|
+
and its first enemy is spawned into the last free slot. A frame budget has
|
|
779
|
+
to hold that figure. It leaves out the scroll advance, the live count and
|
|
780
|
+
the sprite writes, and `gone()` with its end-of-wave test, which runs only
|
|
781
|
+
when an enemy leaves. The step and frame figures move by a few cycles
|
|
782
|
+
with code layout. These are
|
|
783
|
+
C figures; hand-written assembly would be well under them.
|
|
784
|
+
|
|
785
|
+
The difficulty rule is one shift: the spacing is `spacing >> loop`, never
|
|
786
|
+
less than 1. Loop 1's wave 0 therefore spawns every 3 frames, and the
|
|
787
|
+
picture shows the five dives 9 lines apart where loop 0 had them 18 apart.
|