Blow a destroyed span apart in stages instead of erasing it - #4
Open
mpasternak wants to merge 1 commit into
Open
Blow a destroyed span apart in stages instead of erasing it#4mpasternak wants to merge 1 commit into
mpasternak wants to merge 1 commit into
Conversation
A destroyed bridge used to disappear between one frame and the next. It now goes in chunks: the shot punches a two-byte hole where the player aimed, wide enough to fly through, and the hole eats outward two byte columns per side every eight frames. Each stage restarts the impact explosion and its AY burst, alternating ends, so the span goes with a rhythm of separate blasts rather than a smooth fade. Both numbers are BRIDGE_CRUMBLE_CHUNK and BRIDGE_CRUMBLE_PAUSE in tools/build.py, so the rhythm can be retuned with DEFINES= alone. The span stays bridge_active for the whole sequence. That is the part which matters: nothing else repaints the wreck, so a span removed from the model freezes on the screen rows it happened to occupy while the world scrolls out from under it. Left active, the ordinary bridge machinery keeps moving the band, filling the rows entering at its bottom, restoring the rows leaving its top and repainting its colour cells; only the hole columns are excluded, and they are excluded everywhere at once. The world model reports river for them, so the plane flying through composes and restores against water instead of punching road back into the gap; the band writer steps over them; and the colour pass gives them water while the surviving stumps keep road colour. That last point also removes the green flash. Colouring the whole span as water at the moment of the hit left 0xff road bytes under water paper, and a lit pixel takes the INK, so the abandoned road glared solid green until a column happened to be redrawn. Colour now never runs ahead of the bitmap. Lethality is now separate from existence: bridge_lethal is cleared by the hit, so the wreck kills nothing and stops being a target while it crumbles. Player and projectile collision test that flag instead of bridge_active. When the hole reaches both ends the bridge hands over to the plain destroyed road, whose per-frame cost is unchanged. Verified on both builds in ZEsarUX over several natural destructions: the hole widens in two-column steps from the hit outward, bridge_y increases monotonically throughout (the wreck scrolls), the plane is never lethal to itself against it, and the handover leaves bridge_active=0 with destroyed_road_active=1. Screenshots confirm red stumps over clean river with no green. Trace profiler over 30s of autopilot play: 16.6% frame overruns against 16.1% on main, which is scene noise between two runs. Two tools needed repair to get those measurements. The profiler's cpu-history commands are refused while an emulator menu is open, which under --vo null cannot be dismissed from the keyboard; it silently fell back to a 1M-entry buffer and then failed to drain. It now closes menus over the protocol and retries every step. The screenshot tool read five state bytes as one block and was quietly shifted by the new bridge_lethal byte, so it now reads each symbol by name. AGENTS.md records these traps along with the rest. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A destroyed bridge used to disappear between one frame and the next. It now goes
in chunks: the shot punches a two-byte hole where the player aimed, wide enough
to fly through, and the hole eats outward two byte columns per side every eight
frames. Each stage restarts the impact explosion and its AY burst, alternating
ends, so the span goes with a rhythm of separate blasts rather than a fade.
Observed sequence for one span, straight from the emulator:
The two numbers are
BRIDGE_CRUMBLE_CHUNKandBRIDGE_CRUMBLE_PAUSEintools/build.py, so the rhythm can be retuned without touching the assembly:Why the span stays active
Nothing else repaints the wreck, so a span removed from the model freezes on
the screen rows it happened to occupy while the world scrolls out from under
it. The span therefore stays
bridge_activefor the whole crumble and theordinary bridge machinery keeps moving the band, filling the rows entering at
its bottom, restoring the rows leaving its top and repainting its colour cells.
Only the hole columns are excluded, and they are excluded everywhere at once:
composes and restores against water instead of stamping road back into it
That last point is also what removes the green flash. Colouring the whole span
as water at the moment of the hit left
0xffroad bytes under water paper, anda lit pixel takes the INK, so the abandoned road glared solid green until a
column happened to be redrawn. Colour now never runs ahead of the bitmap.
Lethality is separate from existence:
bridge_lethalis cleared by the hit, sothe wreck kills nothing and stops being a target while it crumbles. Player and
projectile collision test that flag instead of
bridge_active. When the holereaches both ends the bridge hands over to the plain destroyed road, whose
per-frame cost is unchanged.
Verification
Several natural destructions on both builds in ZEsarUX:
bridge_yincreases monotonically throughout, so the wreck scrolls with theworld (measured 38→166, 40→150, 48→144 across three spans)
bridge_lethalis 0 for every sample of every crumblebridge_active=0withdestroyed_road_active=1Trace profiler over 30 s of autopilot play: 16.6 % frame overruns against
16.1 % on
main. Two builds never play the same scene, so that difference isnoise rather than a regression.
Tool repairs needed to get those numbers
tools/zrcp_tail_profiler.py: everycpu-historycommand briefly enterscpu-step mode, which the emulator refuses while a menu is open — and under
--vo nullthat menu cannot be dismissed from the keyboard. The tool fellback to a 1 M-entry buffer without saying so and then died draining it. It
now closes menus over the protocol and retries each step.
tools/zrcp_bridge_screenshot.py: read five state bytes as one block and wasquietly shifted by the new
bridge_lethalbyte. Reads each symbol by name now.AGENTS.mdrecords these traps, plus two that cost real time here:write-memorysilently freezes the CPU (needsexit-cpu-step), and closingmenus cancels a tape load in progress, so only profile an already running game.
Handoff
Nothing here is blocked, but for whoever picks this up next:
are a first guess. A wide span takes about a second end to end; if that
drags,
BRIDGE_CRUMBLE_PAUSE=6is the first knob.falls through to the destroyed-road path, which queries the course model
and sees water. Making a second hit accelerate the crumble would be a
small, self-contained follow-up.
bridge_hole_right * 8, the left edge of the last blown column, so the16-pixel burst spills one column into the surviving road. It reads fine
as an explosion eating the next section, but it is not centred.
(balloon, ships, helicopter, FUEL depot) erode island edges, because the
safe X is computed from a single scanline for sprites 8–32 lines tall.
Recorded as item 1 in
docs/TODO.mdwith the wrong theory alreadydisproved; the fix belongs in placement, not in the writers. Eaten land
stays lethal while looking like water.
Test TAPs for this branch are staged at
~/attribute-raid-test/crumble-standard.tapand
crumble-timex.tap.🤖 Generated with Claude Code