From a074a831f0230b0e98978106e46d752cdcf0a757 Mon Sep 17 00:00:00 2001 From: Anachronaut Date: Wed, 2 Sep 2026 23:51:48 -0400 Subject: [PATCH] The shell scrolls, and the moon was drawn where nobody was looking Lunar Porter never put the row origin back. The map is a ring 128 rows tall that the screen shows 25 of, and the shell leaves that origin wherever its last command finished - so a moon drawn into rows nought to 24 while the screen is reading from row forty is a moon nobody can see. It came out as terrain missing, or half there, depending on how far down the prompt had got. Running Pad first was enough; so was holding Return. Nothing here is tidiness. It is the difference between the rows a program WRITES and the rows the screen READS, and only one of those is under the program's control. Grid has always known this; Lander did not. The check for it needed writing twice. Forty returns caught nothing, because the shell runs an eighty column screen which is FIFTY rows tall - forty returns fill it and never scroll it, so the origin was still nought and the test passed against a build with the fix taken out. The screenful that matters is the one the shell is using, not the one the program is about to ask for. At eighty it is 28,608 pixels of moon with the fix and none at all without it. break.sh is what said so. The first version of this check looked exactly like a passing test. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW --- Programs/CosmOS/Apps/Lander.asm | 15 +++++++++++++++ Tests/expected/cosmosCrossDisk.out | 2 +- Tests/expected/cosmosDrives.out | 2 +- Tests/expected/cosmosFault.out | 2 +- Tests/expected/cosmosFlip.out | 2 +- Tests/expected/cosmosGrid.out | 2 +- Tests/expected/cosmosMonitor.out | 2 +- Tests/expected/cosmosMonitorRun.out | 2 +- Tests/expected/cosmosRun.out | 2 +- Tests/expected/cosmosSlowDisk.out | 2 +- Tests/expected/cosmosSprite.out | 2 +- Tests/video.sh | 30 +++++++++++++++++++++++++++++ 12 files changed, 55 insertions(+), 10 deletions(-) diff --git a/Programs/CosmOS/Apps/Lander.asm b/Programs/CosmOS/Apps/Lander.asm index 5bfbeca..4c804e2 100644 --- a/Programs/CosmOS/Apps/Lander.asm +++ b/Programs/CosmOS/Apps/Lander.asm @@ -51,6 +51,21 @@ start: RSTA OUTA 0x31 ; Forty columns. A moon 320 pixels across reads better than 640. + ; ---- And the view put back to the top of the map ---- + ; + ; THE SHELL SCROLLS. Its row origin is wherever the last command left it, and the map is a + ; ring 128 rows tall that the screen shows 25 of - so a moon drawn into rows nought to 24 + ; while the screen is looking at row forty is a moon nobody can see. It came out as terrain + ; that was missing, or half there, depending on how far down the prompt had got. + ; + ; Nothing here is being tidy: this is the difference between the rows this program WRITES + ; and the rows the screen READS, and only one of them is under its control. + ; + ; The column origin and the fine offsets are set every frame by follow, so they need no + ; help. The row origin is set once, here, because nothing scrolls vertically after this. + OUTA 0x34 + OUTA 0x38 ; No fraction of a cell downwards either. + CALL putTiles CALL makeMoon CALL drawMoon diff --git a/Tests/expected/cosmosCrossDisk.out b/Tests/expected/cosmosCrossDisk.out index 2779100..f424a97 100644 --- a/Tests/expected/cosmosCrossDisk.out +++ b/Tests/expected/cosmosCrossDisk.out @@ -25,7 +25,7 @@ Mode.sbx 48 Flip.sbx 173 Sprite.sbx 442 Depth.sbx 672 -Lander.sbx 1571 +Lander.sbx 1575 Pad.sbx 264 Crash.sbx 632 vars.script 50 diff --git a/Tests/expected/cosmosDrives.out b/Tests/expected/cosmosDrives.out index 23c1db4..06e5162 100644 --- a/Tests/expected/cosmosDrives.out +++ b/Tests/expected/cosmosDrives.out @@ -15,7 +15,7 @@ Mode.sbx 48 Flip.sbx 173 Sprite.sbx 442 Depth.sbx 672 -Lander.sbx 1571 +Lander.sbx 1575 Pad.sbx 264 Crash.sbx 632 vars.script 50 diff --git a/Tests/expected/cosmosFault.out b/Tests/expected/cosmosFault.out index 3e8753e..f341fd9 100644 --- a/Tests/expected/cosmosFault.out +++ b/Tests/expected/cosmosFault.out @@ -32,7 +32,7 @@ Mode.sbx 48 Flip.sbx 173 Sprite.sbx 442 Depth.sbx 672 -Lander.sbx 1571 +Lander.sbx 1575 Pad.sbx 264 Crash.sbx 632 vars.script 50 diff --git a/Tests/expected/cosmosFlip.out b/Tests/expected/cosmosFlip.out index 21227b9..8c3fec0 100644 --- a/Tests/expected/cosmosFlip.out +++ b/Tests/expected/cosmosFlip.out @@ -22,7 +22,7 @@ Mode.sbx 48 Flip.sbx 173 Sprite.sbx 442 Depth.sbx 672 -Lander.sbx 1571 +Lander.sbx 1575 Pad.sbx 264 Crash.sbx 632 vars.script 50 diff --git a/Tests/expected/cosmosGrid.out b/Tests/expected/cosmosGrid.out index 6806e0a..be3d52e 100644 --- a/Tests/expected/cosmosGrid.out +++ b/Tests/expected/cosmosGrid.out @@ -22,7 +22,7 @@ Mode.sbx 48 Flip.sbx 173 Sprite.sbx 442 Depth.sbx 672 -Lander.sbx 1571 +Lander.sbx 1575 Pad.sbx 264 Crash.sbx 632 vars.script 50 diff --git a/Tests/expected/cosmosMonitor.out b/Tests/expected/cosmosMonitor.out index f1fe9f9..2aa74ce 100644 --- a/Tests/expected/cosmosMonitor.out +++ b/Tests/expected/cosmosMonitor.out @@ -108,7 +108,7 @@ Mode.sbx 48 Flip.sbx 173 Sprite.sbx 442 Depth.sbx 672 -Lander.sbx 1571 +Lander.sbx 1575 Pad.sbx 264 Crash.sbx 632 vars.script 50 diff --git a/Tests/expected/cosmosMonitorRun.out b/Tests/expected/cosmosMonitorRun.out index 155251e..54cb4ff 100644 --- a/Tests/expected/cosmosMonitorRun.out +++ b/Tests/expected/cosmosMonitorRun.out @@ -27,7 +27,7 @@ Mode.sbx 48 Flip.sbx 173 Sprite.sbx 442 Depth.sbx 672 -Lander.sbx 1571 +Lander.sbx 1575 Pad.sbx 264 Crash.sbx 632 vars.script 50 diff --git a/Tests/expected/cosmosRun.out b/Tests/expected/cosmosRun.out index 5fb6079..c9e15bd 100644 --- a/Tests/expected/cosmosRun.out +++ b/Tests/expected/cosmosRun.out @@ -15,7 +15,7 @@ Mode.sbx 48 Flip.sbx 173 Sprite.sbx 442 Depth.sbx 672 -Lander.sbx 1571 +Lander.sbx 1575 Pad.sbx 264 Crash.sbx 632 vars.script 50 diff --git a/Tests/expected/cosmosSlowDisk.out b/Tests/expected/cosmosSlowDisk.out index 29d96a6..463352e 100644 --- a/Tests/expected/cosmosSlowDisk.out +++ b/Tests/expected/cosmosSlowDisk.out @@ -13,7 +13,7 @@ Mode.sbx 48 Flip.sbx 173 Sprite.sbx 442 Depth.sbx 672 -Lander.sbx 1571 +Lander.sbx 1575 Pad.sbx 264 Crash.sbx 632 vars.script 50 diff --git a/Tests/expected/cosmosSprite.out b/Tests/expected/cosmosSprite.out index f00579b..2c5fc56 100644 --- a/Tests/expected/cosmosSprite.out +++ b/Tests/expected/cosmosSprite.out @@ -22,7 +22,7 @@ Mode.sbx 48 Flip.sbx 173 Sprite.sbx 442 Depth.sbx 672 -Lander.sbx 1571 +Lander.sbx 1575 Pad.sbx 264 Crash.sbx 632 vars.script 50 diff --git a/Tests/video.sh b/Tests/video.sh index 139fcc4..4afe85a 100755 --- a/Tests/video.sh +++ b/Tests/video.sh @@ -1568,6 +1568,36 @@ EOT && result ok "and a lander in the middle of it" "all forty pixels, at the screen's centre" \ || result no "and a lander in the middle of it" "$SHIP pixels, x $SHIPLEFT to $SHIPRIGHT" +# ---- The same lander, after the shell has scrolled ---- +# +# THE SHELL SCROLLS, and its row origin is wherever the last command left it. The map is a +# ring 128 rows tall that the screen shows 25 of, so a moon drawn into rows nought to 24 while +# the screen is looking at row forty is a moon nobody can see - which came out as terrain that +# was missing, or half there, depending on how far down the prompt had got. +# +# EIGHTY returns before the program is started. Forty was the first try and it caught nothing, +# because the shell runs an eighty column screen which is FIFTY ROWS TALL - forty returns fill +# it and never scroll it, so the origin was still nought and the check passed against a +# version with the fix taken out. The screenful that matters is the one the shell is using, +# not the one the program is about to ask for. The moon has to come out exactly as it does from a fresh +# prompt: the rows a program WRITES and the rows the screen READS are two different things, +# and only one of them is under the program's control. +python3 -c "open('$BUILD/scrolled.keys','wb').write(b'\n' * 80 + b'Lander\n' + b'\x00' * 3000)" +python3 -c "open('$BUILD/scrolled.pad','wb').write(b'\\x00' * 40 + b'\\x08' * 400)" +timeout 30 "$EMU" --fast --cycles 1500000 --keyboard "$BUILD/scrolled.keys" \ + --pad "$BUILD/scrolled.pad" --screen "$BUILD/scrolled.ppm" \ + --disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \ + "$BUILD/cosmos.bin" > "$BUILD/scrolled.out" 2>&1 || true +SCROLLEDMOON="$(python3 -c " +d = open('$BUILD/scrolled.ppm', 'rb').read() +px = d[d.index(b'255\n') + 4:] +moon = bytes.fromhex('d8d8d8') +print(sum(1 for o in range(0, len(px), 3) if px[o:o + 3] == moon)) +" 2>/dev/null || echo 0)" +[ "$SCROLLEDMOON" -gt 10000 ] \ + && result ok "a scrolled shell does not hide the moon" "$SCROLLEDMOON pixels of it, drawn where the screen looks" \ + || result no "a scrolled shell does not hide the moon" "$SCROLLEDMOON pixels of ground" + # ---- And the same lander, on a controller ---- # # A pad reports what is HELD, so the thruster can be leaned on rather than pumped - which is