A base speaks in the window, not into the world

Two bugs with one cause. The console draws into the map, so a message
printed while flying was a message the lander then flew over - and
printing scrolls, so every one of them moved the whole world up a row. The
window is at a screen position and forty cells wide, and neither is true
of it.

So the window is two rows now: the gauge, and whatever there is to say.
The letters are ordinary tiles, because the character generator starts at
the space and glyph n is character n less thirty two. The rest of the row
is blanked after every message, or a short one would leave the tail of a
long one behind it.

Opening the throttle wipes the line, because a message that outlived the
moment would be read as describing this one.

The crash still goes to the console, deliberately: it is the last thing
the program says and it should survive the program.

A or Start continues from a message as readily as a key does. Somebody
flying on a controller should not have to reach for the keyboard to say
they have read something.

AND TWO TESTS WENT WITH IT, which is the interesting part. cosmosLanderSoft
and cosmosLanderPadOne asserted on lines in a transcript, and the lines
moved off the console - so both went on passing while checking nothing at
all. A test that asserts a side effect rather than the thing itself is
always one refactor from being decorative. What they were for is now
checked in the picture, where the message actually is.

The lander check moved earlier too. The window grew to two rows, so by 1.5
million cycles the lander had climbed behind the status bar - the window
doing exactly what it should, and leaving the check counting six pixels of
a forty pixel lander.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-09-03 12:23:12 -04:00
co-authored by Claude Opus 5
parent bfb515e23b
commit caf5e1f99d
17 changed files with 146 additions and 47 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 2429
Lander.sbx 2490
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -15,7 +15,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 2429
Lander.sbx 2490
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -32,7 +32,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 2429
Lander.sbx 2490
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 2429
Lander.sbx 2490
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 2429
Lander.sbx 2490
Pad.sbx 264
Crash.sbx 632
vars.script 50
-7
View File
@@ -1,7 +0,0 @@
CosmOS
> Lander
Loaded. Take it to the base across the moon.
Not the base this cargo is for.
Not the base this cargo is for.
Execution stopped. (cycle limit reached)
[exit 0]
-7
View File
@@ -1,7 +0,0 @@
CosmOS
> Lander
Loaded. Take it to the base across the moon.
Not the base this cargo is for.
Not the base this cargo is for.
Execution stopped. (cycle limit reached)
[exit 0]
+1 -1
View File
@@ -108,7 +108,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 2429
Lander.sbx 2490
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -27,7 +27,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 2429
Lander.sbx 2490
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -15,7 +15,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 2429
Lander.sbx 2490
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -13,7 +13,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 2429
Lander.sbx 2490
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 2429
Lander.sbx 2490
Pad.sbx 264
Crash.sbx 632
vars.script 50
-2
View File
@@ -1027,7 +1027,6 @@ padTest | testPrograms/padTest.asm | run | -
# speed has no limit and nothing slows it, so a slide always ends badly however the rest is
# tuned.
cosmosLanderCrash | CosmOS/Source/cosmos.asm | run | - | 60000000 | disks/cosmos.img | lander.keys | landerSlide.pad
cosmosLanderSoft | CosmOS/Source/cosmos.asm | run | - | 60000000 | disks/cosmos.img | lander.keys | landerSoft.pad
# ---- And the same landing, flown from the second controller ----
#
# Two pad fixtures, comma separated: the first holds nothing and the second is the recording
@@ -1037,7 +1036,6 @@ cosmosLanderSoft | CosmOS/Source/cosmos.asm | run | -
# Which is not hypothetical - it is what this did. A controller does not always arrive on
# nought; the front end hands out the numbers the host gave it, so reading only the first
# works on the machine it was written on and silently does nothing on the next one.
cosmosLanderPadOne | CosmOS/Source/cosmos.asm | run | - | 60000000 | disks/cosmos.img | lander.keys | landerIdle.pad,landerSoft.pad
# ---- A tank runs out, and gravity is patient ----
#
# The thruster is held from the first frame to the last and it still crashes. Fuel is a byte
+53 -2
View File
@@ -1608,7 +1608,10 @@ EOT
# the ACCELERATION still leaves an average velocity, so it drifts upward slowly and this is
# caught early rather than left to settle.
#
# EARLY, and that is the point of 1.5 million cycles. This program starts almost at once - the
# EARLY, and that is the point of 900 thousand cycles. Earlier again than it used to be: the
# window grew to two rows when the messages moved into it, and by 1.5 million the lander had
# climbed to row nine and was mostly BEHIND the status bar - which is the window doing exactly
# what it is meant to and left the check counting six pixels of a forty pixel lander. This program starts almost at once - the
# first guess at where to look was ten million cycles in, on the assumption that taking a
# screen was expensive, and by then the lander had flown 700 frames and left the picture. A
# capture near the start is worth far more than a tuned one: there is much less between it and
@@ -1619,7 +1622,7 @@ for i in range(400):
keys += b'\x80' + b'\x00' * 47
open('$BUILD/lander.keys','wb').write(keys + b'\x00' * 8000)
"
timeout 30 "$EMU" --fast --cycles 1500000 --keyboard "$BUILD/lander.keys" \
timeout 30 "$EMU" --fast --cycles 900000 --keyboard "$BUILD/lander.keys" \
--screen "$BUILD/lander.ppm" --disk "$ROOT/Tests/build/disks/cosmos.img" \
--ram-disk 2048 "$BUILD/cosmos.bin" > "$BUILD/lander.out" 2>&1 || true
read -r MOON SKY SHIP SHIPLEFT SHIPRIGHT <<EOT
@@ -1707,6 +1710,54 @@ EOT
&& result ok "a held thruster keeps lifting" "row $EARLY early, row $LATE later" \
|| result no "a held thruster keeps lifting" "row $EARLY early, row $LATE later"
# ---- A base speaks in the window, not into the world ----
#
# The console draws into the map, so a message printed while flying is a message the lander
# then flies over - and printing scrolls, so every one of them moved the whole world up a row.
# The window is at a screen position and forty cells wide, and neither is true of it.
#
# The lander is set down gently on the pad it starts above, which loads cargo and says so, and
# the message is white - a colour nothing else on this screen uses. Then the throttle opens
# and the line goes with it, because a message that outlived the moment would be read as
# describing this one.
python3 -c "
f = (b'\x08' * 6 + b'\x00' * 10) * 60
f += b'\x10' * 10 + b'\x00' * 20
open('$BUILD/said.pad','wb').write(f + b'\x00' * 3000)
f += b'\x08' * 120
open('$BUILD/unsaid.pad','wb').write(f + b'\x00' * 2000)
"
for which in said unsaid; do
timeout 40 "$EMU" --fast --cycles 25000000 --keyboard "$BUILD/lander.keys" \
--pad "$BUILD/$which.pad" --screen "$BUILD/$which.ppm" \
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
"$BUILD/cosmos.bin" > "$BUILD/$which.out" 2>&1 || true
done
# ---- And the same landing flown on the SECOND controller ----
#
# A pad holding nothing on nought and the flight on one, so a program that read only the first
# controller would sit there and never arrive. That check used to live in a transcript and
# stopped saying anything the moment the messages moved off the console, which is what a test
# asserting a side effect rather than the thing itself is always one refactor away from.
python3 -c "open('$BUILD/idle.pad','wb').write(b'\x00' * 4000)"
timeout 40 "$EMU" --fast --cycles 25000000 --keyboard "$BUILD/lander.keys" \
--pad "$BUILD/idle.pad" --pad "$BUILD/said.pad" --screen "$BUILD/padone.ppm" \
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
"$BUILD/cosmos.bin" > "$BUILD/padone.out" 2>&1 || true
PADONE="$(countColour "$BUILD/padone.ppm" f0f0f0)"
[ "$PADONE" -gt 100 ] \
&& result ok "and flies on the second controller too" "$PADONE pixels of message, flown on pad one" \
|| result no "and flies on the second controller too" "$PADONE pixels of message"
SAID="$(countColour "$BUILD/said.ppm" f0f0f0)"
UNSAID="$(countColour "$BUILD/unsaid.ppm" f0f0f0)"
[ "$SAID" -gt 100 ] \
&& result ok "a base says so in the window" "$SAID pixels of message, and none in the map" \
|| result no "a base says so in the window" "$SAID pixels of message"
[ "$UNSAID" = "0" ] \
&& result ok "and opening the throttle wipes it" "the line went with the moment" \
|| result no "and opening the throttle wipes it" "$UNSAID pixels of it still there"
# ---- The landing pads, carved and coloured ----
#
# A random walk does not leave flat ground and a lander wants some, so four pads are carved