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,717 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: render
|
|
3
|
+
chip: VIC-II
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- doc-type: technique-reference -->
|
|
7
|
+
|
|
8
|
+
# Text-Mode Render Techniques
|
|
9
|
+
|
|
10
|
+
Text-mode rendering on the C64 is cheap per byte and not free per frame.
|
|
11
|
+
Writing screen RAM is one STA absolute (4 cycles) per byte, but a redraw
|
|
12
|
+
from a field array needs a load and a store for the screen code and
|
|
13
|
+
again for the colour byte: 16 cycles per cell fully unrolled (a 12 KB
|
|
14
|
+
code footprint for 1000 cells), about 24 cycles per cell in a compact
|
|
15
|
+
indexed loop (both measured in VICE x64sc, CIA timer, DEN off). A 40×25
|
|
16
|
+
redraw with colour is therefore 16,000–24,000 cycles against a PAL frame
|
|
17
|
+
of 19,656 cycles, of which the CPU keeps roughly 18,600 once the 25
|
|
18
|
+
badlines have taken their 40-odd cycles each — most of a frame at best,
|
|
19
|
+
more than a frame in the looped form, and far more from a compiled loop
|
|
20
|
+
(see "Cycle budget"). An earlier version of this page said "a 4-cycle
|
|
21
|
+
operation per cell" and "~4000 cycles — about 1/5 of a PAL frame"; 4
|
|
22
|
+
cycles is one STA of a constant (a screen clear), not a redraw, and
|
|
23
|
+
that figure was below the page's own 1000-cell budget further down.
|
|
24
|
+
Redrawing unconditionally does avoid a class of bugs
|
|
25
|
+
(`dirty_cell_skip_leaves_overlay_trail`) that dirty-cell tracking opens,
|
|
26
|
+
but whether the budget allows it depends on the field size and the
|
|
27
|
+
toolchain — read "The frame-budget trap" before choosing.
|
|
28
|
+
|
|
29
|
+
Most C64 games that look like Tetris, Boulder Dash, Sokoban, or any
|
|
30
|
+
top-down puzzle/board game ship a single tight render loop that walks
|
|
31
|
+
the playfield array each frame (in hand-written assembly, at the costs
|
|
32
|
+
below), then layers the active piece(s) on top as a second pass. The active piece(s) never live in the playfield
|
|
33
|
+
array — they're an overlay drawn last, and the next frame's
|
|
34
|
+
field-redraw is what erases them.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## text_mode_overlay_render — Playfield + moving-piece overlay in text mode
|
|
39
|
+
|
|
40
|
+
**Complexity:** low
|
|
41
|
+
**Region:** both
|
|
42
|
+
**Uses registers:** (none)
|
|
43
|
+
**Uses kernal:** (none)
|
|
44
|
+
|
|
45
|
+
### Why
|
|
46
|
+
|
|
47
|
+
Tetris-likes, Sokoban-likes, Boulder Dash variants, and most C64
|
|
48
|
+
puzzle / board games need to draw a mostly-static playfield with one
|
|
49
|
+
or more *moving* pieces on top of it. The pieces aren't part of the
|
|
50
|
+
playfield's persistent state — they move every gravity tick — so the
|
|
51
|
+
question is how the rendering layer keeps the field cells correct
|
|
52
|
+
while also drawing the piece on top of them. The technique touches no
|
|
53
|
+
VIC or CIA register: it is direct screen and colour RAM writes only.
|
|
54
|
+
|
|
55
|
+
The answer that "feels professional" is to track dirty cells and
|
|
56
|
+
repaint only what changed; the simplest answer that works on a stock
|
|
57
|
+
C64 in text mode is to repaint the whole field every frame and draw the
|
|
58
|
+
piece overlay last — where the budget allows it. In hand assembly a
|
|
59
|
+
400-screen-cell field is 4,800–9,500 cycles a frame (see "Cycle
|
|
60
|
+
budget"), which fits; from an Oscar64 -O2 loop the same field is
|
|
61
|
+
17,100–19,400 cycles (recipe, measured in VICE x64sc), which does not
|
|
62
|
+
fit the blank window and tears — see "The frame-budget trap". An
|
|
63
|
+
earlier version of this section said "the frame budget is more than
|
|
64
|
+
ample" without that qualification, while the trap section below said
|
|
65
|
+
the opposite. The dirty-cell approach has a subtle invariant that's
|
|
66
|
+
easy to miss (see `dirty_cell_skip_leaves_overlay_trail` in
|
|
67
|
+
`pitfalls/text-mode-render.md`); the erase-prev/draw-current overlay
|
|
68
|
+
described under the trap avoids both problems.
|
|
69
|
+
|
|
70
|
+
### How
|
|
71
|
+
|
|
72
|
+
Two passes per frame. The piece overlay never writes back to the
|
|
73
|
+
playfield array — it's pure pixels on top of the field's render:
|
|
74
|
+
|
|
75
|
+
1. **render_field()** — walk every cell of `field[FIELD_H][FIELD_W]`,
|
|
76
|
+
write its screen code + color to screen / color RAM. Empty cells
|
|
77
|
+
get `$20` (space). Filled cells get `$A0` (reverse-space) in the
|
|
78
|
+
piece's designated color.
|
|
79
|
+
2. **render_piece()** — walk the 4 cells of the active piece (read
|
|
80
|
+
from a pieces-table indexed by `current_type`, `current_rot`),
|
|
81
|
+
write `$A0` + piece color to screen / color RAM at the piece's
|
|
82
|
+
absolute screen offset.
|
|
83
|
+
|
|
84
|
+
`render_piece` runs second, so its writes win for the cells the piece
|
|
85
|
+
currently occupies. Next frame, `render_field` re-paints every cell
|
|
86
|
+
based on the persistent playfield — which still has those cells as
|
|
87
|
+
empty, so they go back to spaces — and then `render_piece` redraws
|
|
88
|
+
the piece at its new (gravity-advanced) position. The "trail" from
|
|
89
|
+
the previous frame is implicitly cleared by render_field's
|
|
90
|
+
unconditional rewrite.
|
|
91
|
+
|
|
92
|
+
The piece only enters `field[][]` when it locks. From that point the
|
|
93
|
+
field redraw alone keeps it on screen and `render_piece` switches to
|
|
94
|
+
drawing the *next* piece.
|
|
95
|
+
|
|
96
|
+
### Why it works
|
|
97
|
+
|
|
98
|
+
`render_piece` writes second so its 4 piece cells overwrite the
|
|
99
|
+
empties `render_field` just laid down. Next frame, `render_field`
|
|
100
|
+
re-clears everything from `field[][]` (which doesn't contain the
|
|
101
|
+
moving piece), and `render_piece` re-overlays at the new position.
|
|
102
|
+
The old position is implicitly erased — no per-overlay book-keeping.
|
|
103
|
+
|
|
104
|
+
### The frame-budget trap
|
|
105
|
+
|
|
106
|
+
The naive "unconditional full redraw every frame" pattern WILL exceed
|
|
107
|
+
the PAL vblank window if you do it on a typical Oscar64 build. Empirical
|
|
108
|
+
numbers from puzzle-tetris-c64-kb (DEMO-DOG-T, 2026-05-18):
|
|
109
|
+
|
|
110
|
+
- 10×20 playfield rendered 2-chars wide = 200 cells × ~92 cycles
|
|
111
|
+
(Oscar64 -O2: indexed-loop overhead, two screen writes, two color
|
|
112
|
+
writes per cell) = **~18,400 cycles**. Measured since at 272 raster
|
|
113
|
+
lines, 17,100–17,450 cycles, about 86 a cell (recipe, CIA-timed in
|
|
114
|
+
VICE x64sc); a naive build reads up to ~19,400. Same order either way.
|
|
115
|
+
- After `vic_waitBottom` returns at raster 256 there are 107 raster
|
|
116
|
+
lines = **~6,700 cycles** (56 lines of lower border and blanking to
|
|
117
|
+
the wrap, then 51 of upper border) before the 25-row display window
|
|
118
|
+
resumes at raster 51. The 56 lines to the wrap alone are ~3,500
|
|
119
|
+
cycles, which is what an earlier version of this page called "the
|
|
120
|
+
vblank window"; the race-free budget is nearly twice that.
|
|
121
|
+
- CPU writes continue while the VIC raster has already started drawing
|
|
122
|
+
the next frame top-down. Upper rows show stale content (the old
|
|
123
|
+
frame's piece position OR an "in-between" state from `render_field`).
|
|
124
|
+
Lower rows show the new piece (CPU caught up before the raster).
|
|
125
|
+
|
|
126
|
+
The visible symptom is "pieces only appear in the last 4-5 rows of
|
|
127
|
+
the playfield, even though the in-memory state has them moving from
|
|
128
|
+
the top." See pitfall `full_field_redraw_exceeds_vblank`.
|
|
129
|
+
|
|
130
|
+
The fix is to NOT call `render_field` every frame. Use the
|
|
131
|
+
"erase-prev + draw-current" overlay pattern instead:
|
|
132
|
+
|
|
133
|
+
1. Track `prev_x, prev_y, prev_type, prev_rot` (the piece's last-frame
|
|
134
|
+
state).
|
|
135
|
+
2. Each frame, erase the prev-position cells by repainting them from
|
|
136
|
+
`field[][]` (which now has the locked piece at those cells if the
|
|
137
|
+
piece just locked, so this "erase" pass correctly redraws a
|
|
138
|
+
just-locked piece).
|
|
139
|
+
3. Draw the current-position cells with `$A0` + piece color.
|
|
140
|
+
4. Eight cell writes per frame: about **2,000 cycles** as the Oscar64
|
|
141
|
+
recipe measures it (~33 raster lines; `render_piece` 1,998 cycles on
|
|
142
|
+
CIA 2 timer A — see `recipes/oscar64/text-overlay-playfield.md`), or
|
|
143
|
+
roughly 150–200 cycles in hand assembly with precomputed addresses.
|
|
144
|
+
Either way well inside the 107-line window between raster 256 and
|
|
145
|
+
the display window resuming at line 51. An earlier version said
|
|
146
|
+
"~120 cycles", which is 15 a cell against the ~92 this section had
|
|
147
|
+
just priced an Oscar64 cell write at.
|
|
148
|
+
|
|
149
|
+
`render_field` is reserved for events that change persistent state:
|
|
150
|
+
line-clear shift (rare), game-over restart (rare), initial paint. The
|
|
151
|
+
brief tearing on those one-frame events is acceptable.
|
|
152
|
+
|
|
153
|
+
### Variations
|
|
154
|
+
|
|
155
|
+
- **Two-byte-wide cells.** A 40-column screen with a 10-wide playfield
|
|
156
|
+
often renders each playfield cell as 2 screen columns wide to give
|
|
157
|
+
square-ish character cells. Same loop, but each cell now needs a
|
|
158
|
+
second screen-code store and a second colour store. That is not
|
|
159
|
+
cheap: one extra STA abs,X is 5 cycles on a ~24-cycle indexed cell
|
|
160
|
+
(measured in VICE x64sc: 9,490 → 11,490 cycles over 400 cells,
|
|
161
|
+
+21 %), and with the matching colour store it is 13,490 cycles,
|
|
162
|
+
+42 % indexed; +50 % fully unrolled (16 → 24 cycles per cell).
|
|
163
|
+
Budget for roughly one and a half times the single-width cost, not
|
|
164
|
+
a rounding error. (An earlier version said "under 3 %".) The one
|
|
165
|
+
form that stays cheap is sharing the load: read the field byte once
|
|
166
|
+
and store it to both columns — see "Cycle budget".
|
|
167
|
+
- **Color-only flash for line-clear.** During an animation (e.g.
|
|
168
|
+
Tetris line clear), don't rewrite screen codes — just toggle the color
|
|
169
|
+
RAM byte per cell on/off per N frames. Skip the screen-RAM write
|
|
170
|
+
pass entirely.
|
|
171
|
+
- **Skip render during state transitions.** When the game flips to a
|
|
172
|
+
non-playing state mid-frame (game-over banner drawn, line-flash
|
|
173
|
+
starting), gate the render_field+render_piece pair on the state so the
|
|
174
|
+
banner / flash isn't immediately clobbered.
|
|
175
|
+
|
|
176
|
+
### Cycle budget
|
|
177
|
+
|
|
178
|
+
All hand-assembly figures below were measured in VICE x64sc (PAL, CIA 1
|
|
179
|
+
timer A, DEN off so no badline steals the count); frame lengths are
|
|
180
|
+
from `hardware/pal-ntsc-reference.md` (PAL 19,656; NTSC 6567R8 17,095;
|
|
181
|
+
6567R56A 16,768).
|
|
182
|
+
|
|
183
|
+
For a 10×20 playfield rendered as 2-char-wide cells (= 20×20 screen
|
|
184
|
+
cells), per frame, hand assembly:
|
|
185
|
+
|
|
186
|
+
- render_field, fully unrolled and sharing one LDA between the two
|
|
187
|
+
columns of each field cell (LDA field / STA scr / STA scr+1 / LDA
|
|
188
|
+
colr / STA col / STA col+1): 200 field cells × 24 cyc = 4,800 cycles
|
|
189
|
+
(24 % of a PAL frame, 28 % NTSC). That is the only form in which
|
|
190
|
+
"~12 cycles per screen cell" is true; a cell whose code and colour
|
|
191
|
+
are read individually costs at least 16 (LDA abs / STA abs for the
|
|
192
|
+
code and again for the colour) — 400 × 16 = 6,400 (33 % PAL, 37 %
|
|
193
|
+
NTSC).
|
|
194
|
+
- The compact indexed loop (LDA field,x / STA screen,x / LDA colr,x /
|
|
195
|
+
STA colour,x / INX / BNE): 23.7 cycles per cell, 9,490 for 400 cells
|
|
196
|
+
(48 % PAL, 56 % NTSC).
|
|
197
|
+
- Oscar64 -O2 in C: about 86–97 cycles per two-wide field cell,
|
|
198
|
+
17,100–19,400 for 200 cells (recipe; measured in VICE x64sc) — see
|
|
199
|
+
"The frame-budget trap" above.
|
|
200
|
+
- render_piece: 8 screen cells × 16 cyc = ~128 cycles unrolled, ~190
|
|
201
|
+
looped, ~2,000 in Oscar64 (negligible against the field either way).
|
|
202
|
+
- Total, hand assembly: ~4,900 cycles shared-unrolled (25 % PAL, 29 %
|
|
203
|
+
NTSC R8), ~6,500 unrolled (33 % / 38 %), ~9,700 looped (49 % / 57 %).
|
|
204
|
+
An earlier version said "< 27 % of an NTSC frame" for 4,896 cycles;
|
|
205
|
+
4,896 / 17,095 is 28.6 %.
|
|
206
|
+
|
|
207
|
+
For a full-screen 40×25 redraw (Boulder Dash-style map, every cell
|
|
208
|
+
distinct, so no shared load):
|
|
209
|
+
|
|
210
|
+
- 1000 cells × 16 cyc = 16,000 cycles fully unrolled (81 % of a PAL
|
|
211
|
+
frame, 94 % of an NTSC R8 frame, and ~12 KB of code); the indexed
|
|
212
|
+
loop is ~23,700 cycles — more than a PAL frame (19,656).
|
|
213
|
+
|
|
214
|
+
That's the point at which dirty-cell tracking or a partial redraw pays
|
|
215
|
+
off: a looped 1000-cell screen+colour redraw does not fit in one frame.
|
|
216
|
+
An earlier version of this section said ~12 cycles per cell, 12,000
|
|
217
|
+
cycles for 1000 cells, and that "even a 1000-cell redraw fits inside a
|
|
218
|
+
single frame"; 12 is below the 16-cycle unrolled floor for a cell whose
|
|
219
|
+
code and colour are read individually, and holds only for the
|
|
220
|
+
two-column-shared unrolled form (4,800 for 200 field cells, measured as
|
|
221
|
+
above). Fitting inside a frame is not the criterion in any case: unless
|
|
222
|
+
screen RAM is double-buffered via `$D018`, the redraw races the beam,
|
|
223
|
+
so the budget is the blank window — 107 lines from raster 256 through
|
|
224
|
+
the wrap to raster 51, about 6,700 cycles — not the whole frame.
|
|
225
|
+
|
|
226
|
+
### Recipes
|
|
227
|
+
|
|
228
|
+
- `recipes/oscar64/text-overlay-playfield.md`
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## charset_animation — Animating tiles by changing the glyph, not the cells
|
|
233
|
+
|
|
234
|
+
**Complexity:** low
|
|
235
|
+
**Region:** both
|
|
236
|
+
**Uses registers:** D018
|
|
237
|
+
**Uses kernal:** (none)
|
|
238
|
+
**Cost:** cycles_per_frame=196
|
|
239
|
+
**Cost basis:** measured-vice
|
|
240
|
+
**Cost measured on:** oscar64-charset-animation (one glyph a frame, in the vertical blank)
|
|
241
|
+
|
|
242
|
+
### Why
|
|
243
|
+
|
|
244
|
+
Water, fire, lava, conveyor belts and blinking lights are the same tile
|
|
245
|
+
repeated across a field. Redrawing every cell that shows the tile each
|
|
246
|
+
frame costs cycles in proportion to the field: 12 cycles a cell from an
|
|
247
|
+
Oscar64 `-O2` store loop, 2,429 for 200 cells (recipe, CIA-timed in VICE
|
|
248
|
+
x64sc), so 240 water cells would be about 2,880 and a full screen of
|
|
249
|
+
them more than a blank window. The VIC has no copy of a glyph. It fetches
|
|
250
|
+
the 8 bytes for each cell's code from the character base on every raster
|
|
251
|
+
line it draws, so changing those 8 bytes changes every cell that shows
|
|
252
|
+
the code at once, whatever the field holds. That is the whole technique,
|
|
253
|
+
in two forms.
|
|
254
|
+
|
|
255
|
+
### How
|
|
256
|
+
|
|
257
|
+
**(a) Rewrite the glyph in place.** Keep an animation table of N phases,
|
|
258
|
+
8 bytes each, and once per frame copy phase `frame mod N` over the
|
|
259
|
+
glyph's 8 bytes in the charset the VIC is showing. Every cell with that
|
|
260
|
+
code animates. The cost is one 8-byte copy per animated glyph per frame,
|
|
261
|
+
independent of how many cells show it: 196 cycles in Oscar64 with the
|
|
262
|
+
call and pointer set-up inside the timed window, of which the eight
|
|
263
|
+
`LDA (zp),Y / STA (zp),Y` pairs with their index loads are 120
|
|
264
|
+
(recipe); 64 cycles in hand assembly as eight `LDA abs,Y / STA abs`
|
|
265
|
+
pairs (arithmetic, not measured here). An eight-phase table is 64 bytes.
|
|
266
|
+
|
|
267
|
+
**(b) Flip whole charsets.** Prepare two or more 2 KB charsets in the VIC
|
|
268
|
+
bank that differ in the animated glyphs, and once per frame write the
|
|
269
|
+
one to show into `$D018` bits 1 to 3. One 4-cycle store (the recipe's
|
|
270
|
+
harness reads 14 with its index load and its own stop store) moves the
|
|
271
|
+
glyph source for the whole screen. The cost is the same whether one cell
|
|
272
|
+
or a thousand shows the animated code, and the same however many glyphs
|
|
273
|
+
differ between the sets: a fire glyph, a water glyph and a belt glyph
|
|
274
|
+
can all step at once for the same store. The price is memory, 2 KB a
|
|
275
|
+
phase, and the bank: all the sets, the screen and any sprites must sit
|
|
276
|
+
in the one 16 KB VIC bank, and a compiler will not stop code growing
|
|
277
|
+
into a hardcoded set address (`charset_blit_overruns_grown_code`).
|
|
278
|
+
|
|
279
|
+
### Why it works
|
|
280
|
+
|
|
281
|
+
`$D018` bits 1 to 3 give the character base in 2 KB steps inside the VIC
|
|
282
|
+
bank, and the character generator reads glyph row `line & 7` of each
|
|
283
|
+
code at `base + code * 8` as it draws. Both forms change what that read
|
|
284
|
+
returns. (a) changes the bytes at the address; (b) changes the address.
|
|
285
|
+
The difference is atomicity. A `$D018` store is one write and the VIC
|
|
286
|
+
reads the register at each fetch, so there is no half state: rows above
|
|
287
|
+
the store show the old set, rows below it the new one, and if the store
|
|
288
|
+
is made below the display nobody sees the seam. An 8-byte rewrite is
|
|
289
|
+
eight writes. If a fetch of that glyph falls between them, the rows
|
|
290
|
+
above show the old glyph, the rows below the new one, and the text row
|
|
291
|
+
the beam is in can show old and new pixel rows of the same glyph. Do the
|
|
292
|
+
rewrite after the last display line and before the first badline: from
|
|
293
|
+
line 256 that is 107 lines on PAL and 58 on the 6567R8 (arithmetic from
|
|
294
|
+
the settled frame lengths). The recipe rewrites first thing after
|
|
295
|
+
`vic_waitFrame()`, 196 cycles, inside four raster lines of line 256
|
|
296
|
+
(arithmetic at 63 cycles a line).
|
|
297
|
+
|
|
298
|
+
Reading `$D018` back gives bit 0 as 1 whatever was written; mask it
|
|
299
|
+
before comparing (measured: the monitor shows `1D` for a stored `1C`).
|
|
300
|
+
|
|
301
|
+
### Variations
|
|
302
|
+
|
|
303
|
+
- **Animate a subset of rows.** The glyph is global, so cells that must
|
|
304
|
+
not animate need a different code with a static copy of the glyph. A
|
|
305
|
+
raster split that writes `$D018` mid-frame gives the rows below it a
|
|
306
|
+
different set; it needs a stable raster IRQ and the store must land in
|
|
307
|
+
the horizontal blank or the seam line shows both sets.
|
|
308
|
+
- **Double-buffered charsets.** Combine the two forms: rewrite glyphs
|
|
309
|
+
into the set that is not being shown, anywhere in the frame, and flip
|
|
310
|
+
`$D018` to it in the blank. The rewrite can then be spread across the
|
|
311
|
+
frame and the flip is atomic. The recipe's in-place band does the
|
|
312
|
+
single-buffered version, writing only the set about to be shown.
|
|
313
|
+
- **Colour RAM alongside.** The glyph carries shape, colour RAM carries
|
|
314
|
+
the cell's colour; cycling colour RAM under an animated glyph gives a
|
|
315
|
+
second axis (a fire glyph stepping through yellow, orange, red) at one
|
|
316
|
+
store per cell, which is the redraw cost again. Use it on few cells.
|
|
317
|
+
- **More phases in (a) than (b).** An eight-phase table costs 64 bytes;
|
|
318
|
+
eight charsets cost 16 KB, the whole bank. Long animations go in (a),
|
|
319
|
+
many simultaneous glyphs in (b).
|
|
320
|
+
|
|
321
|
+
### Cycle budget
|
|
322
|
+
|
|
323
|
+
Per frame, in the blank: 196 cycles for one in-place glyph and 14 for a
|
|
324
|
+
flip as the recipe's harness reads them, 3,368 for the recipe's whole
|
|
325
|
+
loop including its 200-cell redraw comparison and the self-check, all
|
|
326
|
+
measured in VICE x64sc on both models with identical figures because
|
|
327
|
+
nothing runs across a badline. Against the 107-line PAL blank (about
|
|
328
|
+
6,700 cycles) an in-place glyph is 3 %; the 58-line NTSC blank (about
|
|
329
|
+
3,770) holds nineteen of them. The Cost line above is the in-place
|
|
330
|
+
form, 196 cycles; its 64-byte table is stated here and not on the line,
|
|
331
|
+
so that the line keeps the basis of its measured figure. The flip form's
|
|
332
|
+
per-frame cost is under 20 cycles and its data cost is 2,048 bytes a
|
|
333
|
+
set, which the line does not carry because the set count is the
|
|
334
|
+
design's.
|
|
335
|
+
|
|
336
|
+
### Recipes
|
|
337
|
+
|
|
338
|
+
- `recipes/oscar64/charset-animation.md`
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## char_bullets — Bullets drawn as characters, merged into reserved glyphs
|
|
343
|
+
|
|
344
|
+
**Complexity:** medium
|
|
345
|
+
**Region:** both
|
|
346
|
+
**Uses registers:** D018
|
|
347
|
+
**Uses kernal:** (none)
|
|
348
|
+
**Cost:** cycles_per_frame=3995
|
|
349
|
+
**Cost basis:** measured-vice
|
|
350
|
+
**Cost measured on:** oscar64-char-bullets (eight bullets, worst frame)
|
|
351
|
+
|
|
352
|
+
### Why
|
|
353
|
+
|
|
354
|
+
A shoot-'em-up or run-and-gun runs out of sprites for bullets first.
|
|
355
|
+
Eight hardware sprites go to the player and the enemies, and a
|
|
356
|
+
multiplexer is a poor fit for dozens of objects a few pixels across
|
|
357
|
+
that share raster lines. A bullet drawn into the character screen costs
|
|
358
|
+
no sprite at all. The naive form, writing a bullet glyph into the cell,
|
|
359
|
+
wipes out the background under it. The form here keeps the background
|
|
360
|
+
visible and puts the bullet at pixel precision inside the cell.
|
|
361
|
+
|
|
362
|
+
### How
|
|
363
|
+
|
|
364
|
+
Reserve a few screen codes in a RAM charset, one per bullet: eight
|
|
365
|
+
codes, $F8 to $FF, in the recipe. Keep a table per bullet of its pixel
|
|
366
|
+
position, the screen code and colour it saved, and the cell it was
|
|
367
|
+
drawn in. Each frame:
|
|
368
|
+
|
|
369
|
+
1. **Restore, in reverse draw order.** Write each bullet's saved code
|
|
370
|
+
and colour back to its cell, last-drawn bullet first.
|
|
371
|
+
2. **Move** the bullets.
|
|
372
|
+
3. **Draw, in forward order.** For each bullet, find its cell from the
|
|
373
|
+
position (`x >> 3`, `y >> 3` through a row-address table). Save the
|
|
374
|
+
code and colour there. Copy the saved code's 8 glyph bytes into the
|
|
375
|
+
bullet's reserved glyph, then OR the bullet's pixels into it at row
|
|
376
|
+
`y & 7`, shifted by `x & 7`. Write the reserved code into the cell,
|
|
377
|
+
and a colour if the bullet has one.
|
|
378
|
+
|
|
379
|
+
**Shared cells.** When bullet B lands in bullet A's cell, it saves A's
|
|
380
|
+
reserved code and builds its glyph from A's merged glyph, so both show.
|
|
381
|
+
Restoring B before A puts A's code back and then the background. That is
|
|
382
|
+
why restore runs in reverse. Forward order leaves A's reserved code on
|
|
383
|
+
screen for good (measured in the recipe: the compare fails).
|
|
384
|
+
|
|
385
|
+
**Pixel positioning.** The bullet's bits are shifted within the glyph by
|
|
386
|
+
`x & 7` and placed on row `y & 7`. A bullet that stays inside one cell
|
|
387
|
+
needs one reserved glyph. The recipe keeps both coordinates even and the
|
|
388
|
+
bullet 2 by 2, so it never crosses an edge. A bullet that can straddle a
|
|
389
|
+
cell edge needs two cells (four at a corner) and as many reserved glyphs.
|
|
390
|
+
|
|
391
|
+
**Collision with the background.** The saved code says what the bullet
|
|
392
|
+
is over. Look its class up in a 256-byte table (solid, destructible,
|
|
393
|
+
empty). If the saved code is itself a reserved code, the bullet is over
|
|
394
|
+
another bullet: follow that bullet's saved code until it is below the
|
|
395
|
+
reserved range. Bullets drawn earlier in the same frame have current
|
|
396
|
+
saved codes, so the walk ends. A reserved code left on screen by a
|
|
397
|
+
wrong restore can make a bullet save its own code, and the walk then
|
|
398
|
+
never ends (measured: the recipe's forward-order variant hung).
|
|
399
|
+
|
|
400
|
+
**Colour RAM.** A hires cell has one foreground colour, so a bullet
|
|
401
|
+
coloured differently from its cell also recolours the background pixels
|
|
402
|
+
in that cell. Either leave colour RAM alone (the bullet takes the
|
|
403
|
+
cell's colour, cost 0) or save and restore it with the code, as the
|
|
404
|
+
recipe does. Colour RAM is 4 bits wide and its upper nibble reads back
|
|
405
|
+
as bus noise; mask it with `$0F` before comparing a saved value.
|
|
406
|
+
|
|
407
|
+
**What the reserved count limits.** Each bullet on screen needs its own
|
|
408
|
+
reserved glyph, so the reserved count is the bullet limit, and every
|
|
409
|
+
reserved code is lost to the background art. The codebase64 merge page reserves
|
|
410
|
+
eight, $F8 to $FF (not measured here). A bullet that straddles cells needs more than one.
|
|
411
|
+
|
|
412
|
+
### Why it works
|
|
413
|
+
|
|
414
|
+
The VIC reads each cell's glyph from the charset on every raster line
|
|
415
|
+
it draws. A reserved glyph that is a copy of the background glyph plus
|
|
416
|
+
bullet bits therefore shows the background cell with the bullet on it.
|
|
417
|
+
The background glyph itself is never written, so every other cell with
|
|
418
|
+
the same code is untouched. Restoring is one code store and one colour
|
|
419
|
+
store per bullet.
|
|
420
|
+
|
|
421
|
+
The reserved glyphs are rewritten while their codes are off screen: the
|
|
422
|
+
restore runs first, and each glyph is built before its code goes into a
|
|
423
|
+
cell. So a glyph cannot tear the way an in-place glyph rewrite can
|
|
424
|
+
(compare `charset_animation`). What can still show is the gap between
|
|
425
|
+
restore and draw. If the beam passes a bullet's row in that gap, the
|
|
426
|
+
bullet is missing for that frame. Run restore and draw in the lower
|
|
427
|
+
border, or at least before the beam reaches the first row bullets can
|
|
428
|
+
occupy (`full_field_redraw_exceeds_vblank`). In the recipe the draw ends
|
|
429
|
+
on line 108 (PAL) or 156 (NTSC), and the arena starts on line 171.
|
|
430
|
+
|
|
431
|
+
### Variations
|
|
432
|
+
|
|
433
|
+
- **Masked bullets.** AND the glyph with an inverted mask before the OR,
|
|
434
|
+
so a bullet with a dark outline shows on a busy background. That is
|
|
435
|
+
the form the codebase64 "merge char bullets" page describes. It costs
|
|
436
|
+
one more operation per glyph row touched.
|
|
437
|
+
- **Whole-cell bullets.** Save the code under the bullet, write one fixed
|
|
438
|
+
bullet code, restore on move: no glyph build, no pixel positioning,
|
|
439
|
+
and the background in that cell disappears. Escape From New York uses
|
|
440
|
+
this form, with 16 bullets moving 8 pixels a frame (Cadaver's source
|
|
441
|
+
dissection, not measured here).
|
|
442
|
+
- **Hand assembly.** The recipe is Oscar64 C. Hand-written 6502 with an
|
|
443
|
+
unrolled glyph copy should draw a bullet in fewer cycles than the
|
|
444
|
+
recipe's 407; not measured here.
|
|
445
|
+
|
|
446
|
+
### Cycle budget
|
|
447
|
+
|
|
448
|
+
Measured in VICE x64sc on both models with the recipe's CIA timers
|
|
449
|
+
(Oscar64 `-O2`): 641 cycles to restore eight bullets, 80 a bullet;
|
|
450
|
+
3,258 to 3,354 to draw eight, 407 to 419 a bullet. The Cost line is the
|
|
451
|
+
worst frame seen over about 240 frames on each model, 3,354 + 641 =
|
|
452
|
+
3,995 cycles, about a fifth of a PAL frame. The draw varies with shared
|
|
453
|
+
cells (one more chain step) and wall hits. The recipe's full-arena
|
|
454
|
+
compare, 5,873 cycles on PAL and 6,131 on NTSC, is its self-check and
|
|
455
|
+
not part of the technique.
|
|
456
|
+
|
|
457
|
+
### Recipes
|
|
458
|
+
|
|
459
|
+
- `recipes/oscar64/char-bullets.md`
|
|
460
|
+
|
|
461
|
+
### Sources
|
|
462
|
+
|
|
463
|
+
- codebase64, "Character bullets": https://codebase.c64.org/doku.php?id=base:character_bullets
|
|
464
|
+
- codebase64, "Merge char bullets": https://codebase.c64.org/doku.php?id=base:merge_char_bullets
|
|
465
|
+
- Cadaver, Escape From New York source dissection: https://cadaver.github.io/rants/dissect.html
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## destructible_char_terrain — Destructible terrain in characters: private glyphs from a pool, pixel edits and pixel probes
|
|
470
|
+
|
|
471
|
+
**Complexity:** high
|
|
472
|
+
**Region:** both
|
|
473
|
+
**Uses registers:** D018
|
|
474
|
+
**Uses kernal:** (none)
|
|
475
|
+
**Cost:** cycles_per_frame=1450
|
|
476
|
+
**Cost basis:** measured-vice
|
|
477
|
+
**Cost measured on:** oscar64-destructible-terrain (one dig step, three pixel edits)
|
|
478
|
+
|
|
479
|
+
### Why
|
|
480
|
+
|
|
481
|
+
A game where creatures dig tunnels and build bridges through the
|
|
482
|
+
landscape needs terrain that changes one pixel at a time. A bitmap does
|
|
483
|
+
that directly but costs 8 KB. Characters cost
|
|
484
|
+
1 KB of screen and 2 KB of charset, and most of a landscape is a few
|
|
485
|
+
repeated textures. The catch is that a glyph is shared: editing the
|
|
486
|
+
earth glyph to dig one hole digs it in every earth cell on screen. The
|
|
487
|
+
form here gives each edited cell its own copy.
|
|
488
|
+
|
|
489
|
+
### How
|
|
490
|
+
|
|
491
|
+
Draw the level with a few **shared glyphs** (the recipe has three:
|
|
492
|
+
empty, earth, and a 2-pixel step) and set aside a block of codes as a
|
|
493
|
+
**pool of private glyphs** ($80 to $FF, 128 codes, in the recipe), kept
|
|
494
|
+
as a stack of free codes.
|
|
495
|
+
|
|
496
|
+
**Editing a pixel.** Find the cell (`x >> 2`, `y >> 3` in multicolour;
|
|
497
|
+
`x >> 3` in hires) and its screen code.
|
|
498
|
+
|
|
499
|
+
1. If the pixel already has the wanted value, stop. This keeps a dig
|
|
500
|
+
through empty air from allocating anything.
|
|
501
|
+
2. If the code is shared, pop a free code, copy the shared glyph's 8
|
|
502
|
+
bytes into it and write the new code into the cell. If the pool is
|
|
503
|
+
empty, refuse the edit and count it.
|
|
504
|
+
3. Change the pixel in the private glyph: clear its pair to dig, set it
|
|
505
|
+
to build.
|
|
506
|
+
4. Compare the private glyph with each shared glyph. On a match, write
|
|
507
|
+
the shared code back into the cell and push the private code on the
|
|
508
|
+
free stack.
|
|
509
|
+
|
|
510
|
+
One cell owns each private glyph, so step 4 needs no reference count: a
|
|
511
|
+
cell dug out completely becomes the empty glyph again and its code goes
|
|
512
|
+
back (the recipe's two side-by-side diggers free two cells this way).
|
|
513
|
+
|
|
514
|
+
**Probing a pixel.** Cell from the coordinates, screen code from the
|
|
515
|
+
cell, glyph byte at row `y & 7`, then a mask for the pixel (`x & 3` in
|
|
516
|
+
multicolour, `x & 7` in hires). A non-zero result is terrain. The probe
|
|
517
|
+
reads what the VIC shows, so collision and picture cannot disagree.
|
|
518
|
+
Anything drawn into the glyphs that is not terrain, such as creatures
|
|
519
|
+
merged in the `char_bullets` way, must be restored before probes run.
|
|
520
|
+
|
|
521
|
+
**Pool exhaustion.** Choose a policy and state it. The recipe refuses:
|
|
522
|
+
the pixel stays as it was and a counter goes up. Its digger still steps
|
|
523
|
+
down, into earth it could not remove; a game should end the dig
|
|
524
|
+
instead. The other policy merges: before taking a new
|
|
525
|
+
code, look for a private glyph with the same 8 bytes and share it, which
|
|
526
|
+
needs a reference count per code and a search or hash (not built here).
|
|
527
|
+
Refusing is simpler and cannot corrupt anything; merging helps where
|
|
528
|
+
many edits make identical cells, such as a flat bridge.
|
|
529
|
+
|
|
530
|
+
**The code budget.** A charset has 256 codes. The recipe spends 64 on
|
|
531
|
+
HUD letters and digits, 3 on shared terrain, 48 on creatures (two per
|
|
532
|
+
creature for 24) and 128 on the pool; 13 are unused. So a level with
|
|
533
|
+
this HUD, these creatures and three shared glyphs can afford at most
|
|
534
|
+
141 private glyphs at once (arithmetic). A private glyph is needed for
|
|
535
|
+
each cell whose pixels match no shared glyph. In the recipe a shaft
|
|
536
|
+
through a 16-pixel platform, dug by two creatures side by side, and a
|
|
537
|
+
twelve-brick staircase used at most 7 at once;
|
|
538
|
+
24 simultaneous dig steps on untouched floor took 36. More shared
|
|
539
|
+
textures cost codes but do not change this: every edited cell that is
|
|
540
|
+
not back to a shared glyph costs one code.
|
|
541
|
+
|
|
542
|
+
### Why it works
|
|
543
|
+
|
|
544
|
+
The VIC-II reads each cell's glyph from the charset on every raster
|
|
545
|
+
line it draws, so a changed byte in a private glyph shows the next time
|
|
546
|
+
the beam draws that row of the cell. Shared glyphs are never written, so the cells
|
|
547
|
+
that still use them are untouched. A cell's screen code is the only
|
|
548
|
+
link between the cell and its private glyph, which is why freeing only
|
|
549
|
+
needs the cell's code rewritten.
|
|
550
|
+
|
|
551
|
+
An edit changes a glyph that is on screen. If the beam is inside that
|
|
552
|
+
cell's rows at that moment, one frame shows the old and new byte on
|
|
553
|
+
different lines. A dig or brick step changes one row of one or two
|
|
554
|
+
cells, so at most that row of a cell is late by a frame. The in-place
|
|
555
|
+
rewrite in `charset_animation` has the same effect over whole glyphs.
|
|
556
|
+
|
|
557
|
+
### Variations
|
|
558
|
+
|
|
559
|
+
- **Hires.** 8 pixels a byte, one colour a cell from colour RAM. The
|
|
560
|
+
probe mask comes from `x & 7`. Pixels are twice as fine and the cells
|
|
561
|
+
hold one colour, so terrain texture has to come from the pattern.
|
|
562
|
+
- **Different textures.** Every shared texture is one more code and one
|
|
563
|
+
more comparison in step 4. A private glyph only returns to the pool
|
|
564
|
+
when it equals one of them exactly.
|
|
565
|
+
- **Two charsets.** A raster interrupt that changes `$D018` part way
|
|
566
|
+
down the screen gives the lower part its own 256 codes. Not built
|
|
567
|
+
here.
|
|
568
|
+
|
|
569
|
+
### Cycle budget
|
|
570
|
+
|
|
571
|
+
Measured in VICE x64sc 3.10 with the recipe's CIA timers (Oscar64
|
|
572
|
+
`-O2`). A probe costs 52 cycles: 160 probes along one pixel row take
|
|
573
|
+
10,912 cycles and the same loop without the probe 2,580, with the
|
|
574
|
+
display off. The Cost line is one dig step's terrain work, the
|
|
575
|
+
technique called once: 3 pixel edits on untouched floor. The dearest
|
|
576
|
+
of 24 such steps took 1,450 cycles on both models, timer calls
|
|
577
|
+
included; half the steps span two cells and allocate twice.
|
|
578
|
+
|
|
579
|
+
A frame's terrain cost is edits times about 452. The 72 edits of 24 dig
|
|
580
|
+
steps at once, 36 of which allocate, took 32,037 cycles on PAL and
|
|
581
|
+
32,555 on NTSC, about 452 an edit and 1,356 a dig step. That is more
|
|
582
|
+
than a PAL frame (19,656 cycles) and nearly two NTSC frames (17,095).
|
|
583
|
+
A typical frame of the recipe edits nothing or one or two cells.
|
|
584
|
+
Hand-written assembly with a table of glyph addresses would be cheaper;
|
|
585
|
+
not measured here.
|
|
586
|
+
|
|
587
|
+
### Recipes
|
|
588
|
+
|
|
589
|
+
- `recipes/oscar64/destructible-terrain.md` — a 40 by 16 cell multicolour level; 24 creatures dig, build and block; terrain glyph bytes and creature states checked against a Python model after 360 ticks; worst frames timed on both models
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## isometric_tile_engine — Diamond-grid projection, draw order and sprite depth for isometric rooms
|
|
594
|
+
|
|
595
|
+
**Complexity:** high
|
|
596
|
+
**Region:** both
|
|
597
|
+
**Uses registers:** D018, D01B, D015, D000, D001, D010, DC04, DC05, DC0E
|
|
598
|
+
**Uses kernal:** (none)
|
|
599
|
+
**Cost:** cycles_per_frame=42034
|
|
600
|
+
**Cost basis:** measured-vice
|
|
601
|
+
**Cost measured on:** kickassembler-isometric-room (the frame that redraws the whole 8 by 8 room, which is the worst frame; a frame that only moves the player is far cheaper, and one block draw is 527 cycles, see Cycle budget)
|
|
602
|
+
**Requires:** tile_map_render
|
|
603
|
+
|
|
604
|
+
### Why
|
|
605
|
+
|
|
606
|
+
A top-down puzzle or action game that wants depth cues without a bitmap mode
|
|
607
|
+
uses an isometric projection: tiles are drawn as 2:1 diamonds, blocks as cubes,
|
|
608
|
+
and the painter's diagonal sort hides the z-buffer. The VIC-II hardware sprite
|
|
609
|
+
depth register (`$D01B`) gives the player figure a single behind-or-in-front
|
|
610
|
+
state relative to the entire playfield, which is enough for most rooms.
|
|
611
|
+
|
|
612
|
+
### How
|
|
613
|
+
|
|
614
|
+
**Layout.** One VIC bank holds the screen at `$0400`, a 2 KB custom charset at
|
|
615
|
+
`$3000`, and the sprite data. `$D018 = $1C` selects them. The map is a flat
|
|
616
|
+
byte array: 0 = floor, 1 = block (one tile tall), 2 = tall block (two tiles).
|
|
617
|
+
|
|
618
|
+
**Tiles.** Three shapes, all 4 character columns wide:
|
|
619
|
+
|
|
620
|
+
- Floor diamond: 2 rows tall. Eight chars (top-face row 0, top-face row 1).
|
|
621
|
+
- Block: 4 rows tall. Top face (2 rows, same chars as floor) above two rows of
|
|
622
|
+
solid side-face chars.
|
|
623
|
+
- Tall block: 6 rows tall. Top face (2 rows) above four rows of side-face chars.
|
|
624
|
+
|
|
625
|
+
The custom charset holds 13 glyphs: one blank, four for the top-face top row,
|
|
626
|
+
four for the top-face bottom row, and four for the side face. Colour RAM sets
|
|
627
|
+
the foreground colour of each tile type.
|
|
628
|
+
|
|
629
|
+
**Projection.** For map cell (x, y):
|
|
630
|
+
|
|
631
|
+
```
|
|
632
|
+
char_col = ORIG_COL + 2 * (x - y)
|
|
633
|
+
char_row = ORIG_ROW + (x + y)
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
With `ORIG_COL = 18` and `ORIG_ROW = 4` an 8-by-8 map lands in screen columns
|
|
637
|
+
4 to 35 and rows 4 to 19, fitting the 40-by-25 display without overflow
|
|
638
|
+
(arithmetic from the extreme cells (0,7) and (7,0)).
|
|
639
|
+
|
|
640
|
+
**Painter's order.** Iterate diagonal `s = x + y` from 0 to 14. For each
|
|
641
|
+
diagonal, iterate x from `max(0, s-7)` to `min(7, s)` with `y = s - x`. Draw
|
|
642
|
+
that cell last-wins: a cell at a higher diagonal (closer to the viewer) is
|
|
643
|
+
drawn after any cell at a lower diagonal whose character region overlaps it.
|
|
644
|
+
Clear the screen rows to space before drawing so removed tiles do not leave
|
|
645
|
+
stale characters.
|
|
646
|
+
|
|
647
|
+
**Sprite depth scan.** After each player move, scan all 64 cells. For each cell
|
|
648
|
+
with `bx + by > px + py` (in front of the player), check whether its character
|
|
649
|
+
box overlaps the sprite's character box:
|
|
650
|
+
|
|
651
|
+
- Sprite box: cols `[player_col+2, player_col+4]`, rows `[player_row-1, player_row+1]`.
|
|
652
|
+
Formula: `sprite_x = 24 + 8*(player_col + 2)`, `sprite_y = 45 + 8*player_row`.
|
|
653
|
+
- Block box: cols `[block_col, block_col+3]`, rows `[block_row-2, block_row+1]`.
|
|
654
|
+
- Tall block box: cols `[block_col, block_col+3]`, rows `[block_row-4, block_row+1]`.
|
|
655
|
+
|
|
656
|
+
If any in-front cell is a block and its box overlaps the sprite box, set
|
|
657
|
+
`$D01B` bit 0 (sprite behind the playfield); otherwise clear bit 0.
|
|
658
|
+
|
|
659
|
+
**Timing.** Wrap a draw with CIA 1 timer A in one-shot mode from `$FFFF`
|
|
660
|
+
(`$DC0E = $19`). Stop with `$08`. Elapsed = `$FFFF` minus the timer value,
|
|
661
|
+
computed as `$FF - low_byte` and `$FF - high_byte`.
|
|
662
|
+
|
|
663
|
+
### Why it works
|
|
664
|
+
|
|
665
|
+
The VIC-II reads character codes from screen RAM and fetches glyph bytes from
|
|
666
|
+
the charset on every raster line it draws. Writing a code to a screen cell
|
|
667
|
+
instantly changes what that cell shows on the next raster fetch. Painter's
|
|
668
|
+
order means the last write wins without a z-buffer. `$D01B` bit 0 swaps sprite
|
|
669
|
+
priority for sprite 0 between two modes without any extra CPU cycle cost per
|
|
670
|
+
frame: one OR or AND to one register.
|
|
671
|
+
|
|
672
|
+
### Cycle budget
|
|
673
|
+
|
|
674
|
+
Measured in VICE x64sc 3.10 (PAL, CIA 1 timer A, one-shot from `$FFFF`):
|
|
675
|
+
|
|
676
|
+
- Full 8-by-8 room redraw (64 cells, mix of floors and blocks): 42,034 cycles --
|
|
677
|
+
about 2.1 PAL frames (19,656 cycles each). A full-screen 40-by-25 hires
|
|
678
|
+
redraw (1,000 cells) is comparably large; see the cycle budget under
|
|
679
|
+
`text_mode_overlay_render`.
|
|
680
|
+
- One block draw (four rows of four chars, 16 screen writes + 16 colour writes
|
|
681
|
+
via four `setup_row` calls): 527 cycles, under 3 % of a PAL frame.
|
|
682
|
+
|
|
683
|
+
The 42,034-cycle redraw budget is for a room redrawn on state changes only
|
|
684
|
+
(start and after the final player move). A per-frame redraw would need either
|
|
685
|
+
a smaller map or a dirty-cell approach -- see `full_field_redraw_exceeds_vblank`.
|
|
686
|
+
|
|
687
|
+
### Variations
|
|
688
|
+
|
|
689
|
+
**Depth bit limitation.** `$D01B` has one bit per sprite. Setting it places the
|
|
690
|
+
sprite behind every playfield character, not just the block in front of it. A
|
|
691
|
+
player standing between a nearer block and a farther block will appear behind
|
|
692
|
+
the farther block too, which is incorrect. The fix is either a software sprite
|
|
693
|
+
(redraw the figure into the charset each move, eliminating `$D01B` entirely) or
|
|
694
|
+
a per-raster split that sets `$D01B` only for the rows the front block occupies.
|
|
695
|
+
|
|
696
|
+
**Scrolling camera.** Replace the fixed origin with a scrollable viewport and
|
|
697
|
+
double-buffer the screen with `$D018` to avoid mid-draw tearing. The `tile_map_render`
|
|
698
|
+
technique documents the double-buffer flip; the painter loop becomes a partial
|
|
699
|
+
redraw of the visible window.
|
|
700
|
+
|
|
701
|
+
**More tile shapes.** The three shapes here share the same 13 glyphs. An
|
|
702
|
+
animated water tile needs one more code per animation phase; a sloped ramp
|
|
703
|
+
tile needs its own top-face glyph set. Each distinct shape adds at most eight
|
|
704
|
+
bytes to the charset.
|
|
705
|
+
|
|
706
|
+
### Pitfalls
|
|
707
|
+
|
|
708
|
+
- `dirty_cell_skip_leaves_overlay_trail` -- the room clear-and-redraw avoids
|
|
709
|
+
this, but a dirty-cell optimisation would reintroduce it.
|
|
710
|
+
- `full_field_redraw_exceeds_vblank` -- a 64-cell isometric room costs 42,034
|
|
711
|
+
cycles per redraw, well over the ~6,700-cycle PAL blank window. Redraw on
|
|
712
|
+
state changes only.
|
|
713
|
+
|
|
714
|
+
### Sources
|
|
715
|
+
|
|
716
|
+
- `recipes/kickassembler/isometric-room.md` -- 8-by-8 room, scripted player,
|
|
717
|
+
two timed redraws, verdict byte, depth scan; measured in VICE x64sc 3.10
|