1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-16 12:12:04 +00:00
nescript/tests/emulator/goldens/platformer.audio.hash

2 lines
16 B
Text
Raw Normal View History

platformer: end-to-end side-scroller demo + three runtime bug fixes Adds `examples/platformer.ne`, a full side-scrolling game that exercises nearly every subsystem of the compiler in one program: custom CHR tileset, 32×30 background nametable with per-region attribute palettes, 2×2 metasprite hero with gravity/jump physics, wrap-around horizontal scrolling, moving enemies, coin pickups, user-declared SFX + music, and a Title → Playing state machine with autopilot so the headless jsnes harness captures real gameplay at frame 180. Tile art + nametable are generated by `scripts/gen_platformer_tiles.rs` (`cargo run --bin gen_platformer_tiles`). Building this out uncovered three independent runtime bugs that together made the example render as black-on-black smileys. All three are fixed in this commit: 1. **`gen_init` enabled sprite rendering before the linker's initial palette/background load runs.** The PPU's v-register auto-increments on every `$2007` write *during active rendering*, so the palette load (32 B) and nametable load (1024 B) were scrambled past the first ~72 bytes — every existing program with a `background Level { ... }` block was silently rendering zero-filled VRAM. Fix: leave `PPU_MASK = 0` at the end of `gen_init` and emit a new `gen_enable_rendering` call *after* all initial VRAM writes complete. 2. **Audio tick corrupted `ZP_CURRENT_STATE`.** The audio driver's period-table lookup reused `$02/$03` as a temporary indirect pointer with a comment claiming the slots were free because the tick doesn't call mul/div. But `$03` is also `ZP_CURRENT_STATE` used by the state dispatch loop, so every music note silently overwrote the state index with the high byte of `__period_table` (`0xC5` in the platformer ROM), wedging the state machine forever. Fix: `gen_nmi` now PHAs `$02/$03` on entry and PLA-restores them on exit, and the audio tick JSR moves inside that save/restore window (it used to be spliced by the linker *before* the register saves, so even A/X/Y were technically being trashed pre-save). Only `audio_demo`'s audio hash shifts (its note timings move a few cycles); every other golden is unchanged. 3. **Sub-palette mirroring footgun.** Writing a 32-byte palette blob sequentially causes the sprite sub-palettes' "index 0" slots at `$3F10/$3F14/$3F18/$3F1C` to clobber the background universal colour at `$3F00/$3F04/$3F08/$3F0C` via NES hardware mirroring. The example's palette sets all eight first bytes to `$22` (sky blue) for this reason; `docs/future-work.md` picks up a TODO to warn on inconsistent first-byte values in the analyzer. Also: - `docs/platformer.gif` — 6-second recording of the example running in jsnes, generated by the new `tests/emulator/record_gif.mjs` puppeteer helper (encodes via `gifenc`, committed as a dev-dependency under `tests/emulator/package.json`). - README / examples/README tables and the 497-test count are updated to cover the new example. https://claude.ai/code/session_01BcCcHi6FUmTh8jC7UgkA3A
2026-04-13 13:04:26 +00:00
7c8e60e4 132084