{"id":49606210,"url":"https://github.com/lewster32/chaos-disassembly","last_synced_at":"2026-05-04T13:05:50.793Z","repository":{"id":355109846,"uuid":"1208893103","full_name":"lewster32/chaos-disassembly","owner":"lewster32","description":"Annotated dissasembly of Chaos: The Battle of Wizards (1985)","archived":false,"fork":false,"pushed_at":"2026-05-01T21:47:37.000Z","size":3427,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-01T23:27:05.448Z","etag":null,"topics":["gamedev","sinclair-zx-spectrum","z80-assembly"],"latest_commit_sha":null,"homepage":"https://www.archaos.co.uk/chaos-disassembly/","language":"Assembly","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lewster32.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-12T21:58:34.000Z","updated_at":"2026-05-01T21:47:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lewster32/chaos-disassembly","commit_stats":null,"previous_names":["lewster32/chaos-disassembly"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/lewster32/chaos-disassembly","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewster32%2Fchaos-disassembly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewster32%2Fchaos-disassembly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewster32%2Fchaos-disassembly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewster32%2Fchaos-disassembly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lewster32","download_url":"https://codeload.github.com/lewster32/chaos-disassembly/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewster32%2Fchaos-disassembly/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32608335,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-04T10:08:07.713Z","status":"ssl_error","status_checked_at":"2026-05-04T10:08:02.005Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gamedev","sinclair-zx-spectrum","z80-assembly"],"created_at":"2026-05-04T13:05:49.004Z","updated_at":"2026-05-04T13:05:50.776Z","avatar_url":"https://github.com/lewster32.png","language":"Assembly","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Chaos Disassembly\n\nAn annotated disassembly of [Chaos: The Battle of Wizards](https://en.wikipedia.org/wiki/Chaos_(1985_video_game)) (Julian Gollop, 1985) for the ZX Spectrum 48K, produced with [SkoolKit 10.0](https://skoolkit.ca/).\n\n**Browse the rendered site:** [archaos.co.uk/chaos-disassembly](https://www.archaos.co.uk/chaos-disassembly/)\n\nThe output is a browsable HTML site with labelled routines, annotated data tables, creature sprites, sound-effect previews, and cross-referenced spell and creature stats. Custom memory-map pages group the engine into thematic chunks (Spell selection and casting, Movement and combat, Computer AI).\n\n## AI disclaimer\n\n_The following paragraph has been written by a real person; everything else is probably AI-generated._\n\nWhile this project has been supervised by a knowledgeable human (me, [Lewis Lane](https://www.rotates.org)) the immense amount of heavy lifting has been performed tirelessly by [Claude Code](https://claude.ai/). Its accuracy can therefore not be guaranteed; I don't know Z80 assembly, nor have I spoken to Julian Gollop at any length about the original game's development. Everything presented here is a mixture of research and reference materials from others who have almost certainly done things the old fashioned way, my own knowledge of the game, and a lot of LLM magic.\n\n## Layout\n\n```\nsources/      everything the build consumes\n  chaos.ctl     primary annotation file (this is what you edit)\n  chaos.ref     SkoolKit config (paths, custom pages, page index)\n  pages.ref     [Page:*] definitions for the custom HTML pages\n  bugs.ref      [Bug:*] entries\n  glossary.ref  [Glossary:*] entries\n  chaos.py      ChaosHtmlWriter subclass that renders the live tables\n  chaos.css     site stylesheet (overlays skoolkit.css + dark theme)\n  chaos.js      sortable tables and the custom audio player\n  chaos.woff/.woff2  Chaos web font\n  chaos.z80     game snapshot (input to sna2skool)\n  chaos.rzx     game recording (input to the trace harnesses)\n  chaossounds.json  beeper-effect parameter table\n\ntools/        build, generation and research scripts\n  gen_sounds.py     beeper WAV synthesiser, run by update.sh\n  trace_beams.py    capture beam-flight sounds via the trace harness\n  encode_sounds.py  WAV -\u003e Opus/OGG converter (needs ffmpeg, falls back to WAV)\n  gen_beams.py      beam GIFs, run by update.sh\n  gen_favicon.py    favicon.ico from the Blob sprite, run by update.sh\n  trace_magic_wood.py  Magic Wood placement trace (research)\n  serve.py          local dev server with browser auto-reload\n  *.py              archived one-shot research / patch scripts\n\nreference/    read-only reference material\n  chaos-manual.md, chaos-rules.md, creatures.md\n  chaos-mapped-utf8.ctl, chaos-guesser.ctl, chaos-guesser.skool\n  zxs48rom.asm, ZXS48.ROM\n  alignment.ts        TS reference for the spell-alignment math\n\nchaos/        generated HTML site (gitignored)\n```\n\n## Prerequisites\n\n- Python 3.x\n- [Pillow](https://pillow.readthedocs.io/) (for the favicon and beam GIFs)\n- SkoolKit 10.0 - either checked out into `skoolkit-src/` or installed via pip:\n\n```\npip install -r requirements.txt\n```\n\n- [ffmpeg](https://ffmpeg.org/) - used by `tools/encode_sounds.py` to compress the synthesised beeper WAVs into Opus/OGG (~95% smaller). The build falls back to shipping uncompressed `.wav` if ffmpeg isn't on `PATH`, so this is technically optional, but the rendered site is much lighter with it. Windows install:\n\n```\nwinget install --id=Gyan.FFmpeg -e\n```\n\n(or `choco install ffmpeg` / `scoop install ffmpeg`). On macOS use `brew install ffmpeg`; on Debian/Ubuntu `sudo apt install ffmpeg`.\n\n## Building\n\n```\nbash update.sh\n```\n\nThe script runs from the project root:\n\n1. `sna2skool` reads `sources/chaos.z80` + `sources/chaos.ctl` and writes `sources/chaos.skool`.\n2. `tools/gen_sounds.py` synthesises beeper WAVs into `chaos/audio/sounds/`.\n3. `tools/trace_beams.py` captures the beam-flight sounds that need the trace harness.\n4. `tools/encode_sounds.py` compresses the WAVs to Opus/OGG via ffmpeg (skipped with a notice if ffmpeg is missing).\n5. `tools/gen_beams.py` renders beam-animation GIFs into `chaos/images/beams/`.\n6. `skool2html` renders `sources/chaos.skool` + the ref files into `chaos/`. SkoolKit's `[Game] AudioFormats` default makes it auto-prefer the `.ogg` siblings of any `#AUDIO0(...wav)` macro, so no source edits are needed when the encode step runs.\n7. `tools/gen_favicon.py` writes `chaos/favicon.ico` from the Blob sprite.\n\nOpen `chaos/index.html` to browse the result, or use the dev server:\n\n```\npython tools/serve.py        # http://localhost:8080\npython tools/serve.py 9000   # custom port\n```\n\nThe dev server auto-reloads any open browser tabs after each `update.sh` run.\n\n## What's annotated\n\n- **Spells** - all 65 records at `$7D60` with casting chance, range, alignment bias, sort key, and dispatch routine.\n- **Creature stats** - 38-byte records for every creature and structure, with sprite UDGs and live casting-chance lookup from the spell table.\n- **Sound effects** - 10-byte beeper records with embedded WAV preview and a custom audio player.\n- **Beams** - the six beam types rendered by the Bresenham line routine at `$B626`, each with a per-beam GIF preview.\n- **Sprites** - creature, wizard, font, and effects/UI blocks rendered as UDG arrays.\n- **Custom memory maps** - `Spell selection and casting` (`$9168-$97CD`), `Movement and combat` (`$AC36-$B60A`), `Computer AI` (`$C63D-$CDD2` + `$D3F0`).\n\n## Editing tips\n\n- Edit `sources/chaos.ctl` only. `sources/chaos.skool` is generated and overwritten on every build.\n- All addresses in `chaos.ctl` use `$XXXX` hex (uppercase).\n- Stick to ASCII in `sources/*.ctl` and `sources/*.ref` - SkoolKit decodes them as ASCII. Use HTML entities (`\u0026times;`, `\u0026#10003;`, etc) for symbols.\n- See `CLAUDE.md` for the full annotation conventions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flewster32%2Fchaos-disassembly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flewster32%2Fchaos-disassembly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flewster32%2Fchaos-disassembly/lists"}