A station in orbit, going round and not yet dockable

S1 of the station: it exists, it orbits, it wraps, it is drawn. Docking
is deliberately not here - the point of stopping at this rung is to fly
up and find out whether matching a four pixel a frame target feels good
before any rules are written about what happens when you reach it.

IT NEEDS NO PHYSICS OF ITS OWN. A body at 64 sixteenths is exactly what
a circular orbit is under the rules already here: the pull and the swing
cancel at that speed at ANY height, because gravity never falls off and
the moon is a cylinder that does not rotate. So the station is a
position, a constant, and the same fourteen bit wrap the lander uses.
That also means there is no prograde or retrograde to choose - nothing
privileges a direction, which is what makes a second station going the
other way a thing that can exist later.

Four rows above the world's origin: off the top of a forty column screen
and comfortably inside a wide one, so it is somewhere to go that the zoom
is needed to see. It starts half a moon away and a lap is 256 frames, a
little over four seconds, so it has to be found but will not stay lost.

Its column is the middle of the screen plus how far round it is from the
lander, wrapped to fourteen bits - which measures the long way round
whenever it is behind, so anything past the half way point becomes a
negative offset instead. Off the edge needs no test at all: a sprite's X
is signed and sixteen bits, so a station three hundred pixels to the left
is asked for at minus a hundred and forty and the device declines.

Blue, and that is not taste. White is counted to find the ceiling
warning, cyan to find the landing pads, magenta is the instruments and
yellow is the lander. Blue is the one ink no check measures, and picking
a measured one has broken a test twice already.

toPixelsSigned is factored out of showLander, since the station wants the
same sign-extended conversion.

Four checks, each seen to fail on its own break. Measured going round at
244 pixels in sixty frames, off the far side of the moon, and back on the
other edge.
This commit is contained in:
Anachronaut
2026-09-03 22:41:28 -04:00
parent 32559ce872
commit 800f555ffb
13 changed files with 295 additions and 23 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 5365
Lander.sbx 5751
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 5365
Lander.sbx 5751
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 5365
Lander.sbx 5751
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 5365
Lander.sbx 5751
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 5365
Lander.sbx 5751
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -108,7 +108,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 5365
Lander.sbx 5751
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 5365
Lander.sbx 5751
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 5365
Lander.sbx 5751
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 5365
Lander.sbx 5751
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 5365
Lander.sbx 5751
Pad.sbx 264
Crash.sbx 632
vars.script 50
+64
View File
@@ -2212,6 +2212,70 @@ EOT
&& result ok "and a lander at the ceiling is only on screen zoomed out" "off the top, then at row $OUTSHIP" \
|| result no "and a lander at the ceiling is only on screen zoomed out" "row $INSHIP zoomed in, row $OUTSHIP out"
# ---- The orbiting station ----
#
# A body at orbital speed, which under the rules already here is all a circular orbit IS: the
# pull and the swing cancel at 64 sixteenths at any height, because gravity never falls off
# and the moon wraps. So the station has no physics of its own - a position, a constant, and
# the same fourteen bit wrap the lander uses.
#
# Four rows above the world's origin, which puts it OFF THE TOP of a forty column screen and
# inside a wide one. That is the point of it: somewhere to go that the zoom is needed to see.
python3 -c "open('$BUILD/hovernarrow.pad','wb').write(b'\x08' * 3000 + b'\x00' * 20000)"
python3 -c "
pad = bytearray(b'\x08' * 3000)
pad[100:108] = b'\x28' * 8 # Up and B together, so the climb is not interrupted.
open('$BUILD/hoverwide.pad','wb').write(bytes(pad) + b'\x00' * 20000)"
for when in 2000000 3000000 5000000 7000000; do
timeout 60 "$EMU" --fast --cycles $when --keyboard "$BUILD/fly.keys" \
--pad "$BUILD/hoverwide.pad" --screen "$BUILD/station$when.ppm" \
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
"$BUILD/cosmos.bin" > "$BUILD/station.out" 2>&1 || true
done
timeout 60 "$EMU" --fast --cycles 3000000 --keyboard "$BUILD/fly.keys" \
--pad "$BUILD/hovernarrow.pad" --screen "$BUILD/stationnarrow.ppm" \
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
"$BUILD/cosmos.bin" > "$BUILD/stationnarrow.out" 2>&1 || true
read -r ONNARROW SEEN X2 X3 X5 X7 <<EOT
$(python3 -c "
def station(path, band):
# Blue, and ABOVE THE TERRAIN, because one of the four landing pads is blue too and it is
# always somewhere on the picture. Nothing else is up in that band.
d = open(path, 'rb').read()
width = int(d[:40].split()[1])
px = d[d.index(b'255\n') + 4:]
blue = bytes.fromhex('5880e0')
at = [(i % width, i // width) for i in range(len(px) // 3)
if px[i * 3:i * 3 + 3] == blue and i // width < band]
return len(at), (min(x for x, y in at) if at else -1)
narrow = station('$BUILD/stationnarrow.ppm', 70)
seen, x3 = station('$BUILD/station3000000.ppm', 200)
print(narrow[0], seen,
station('$BUILD/station2000000.ppm', 200)[1], x3,
station('$BUILD/station5000000.ppm', 200)[1],
station('$BUILD/station7000000.ppm', 200)[1])
" 2>/dev/null || echo "0 0 -1 -1 -1 -1")
EOT
# Forty pixels is the whole of the art, so none of it is clipped and it is the tile meant.
[ "$SEEN" = "40" ] \
&& result ok "a station is up there, zoomed out" "all forty pixels of it" \
|| result no "a station is up there, zoomed out" "$SEEN pixels of station"
[ "$ONNARROW" = "0" ] \
&& result ok "and off the top of a forty column screen" "which is what the zoom is for" \
|| result no "and off the top of a forty column screen" "$ONNARROW pixels of it in the narrow view"
# Sixty frames apart, at four pixels a frame, is about 240 - and it has to be MOVING RIGHT,
# because a station drawn from a position nothing advances would sit still and still pass a
# check that only asked whether it was there.
MOVED=$(( X3 - X2 ))
[ "$MOVED" -gt 200 ] && [ "$MOVED" -lt 280 ] \
&& result ok "and it goes round at orbital speed" "$MOVED pixels in sixty frames" \
|| result no "and it goes round at orbital speed" "$X2 then $X3, which is $MOVED"
# Off the far side of the moon and back on the other edge. The screen shows 640 of the moon's
# 1024 pixels, so there is a stretch where it is genuinely not on the picture at all.
[ "$X5" = "-1" ] && [ "$X7" -gt 0 ] \
&& result ok "and round the back of the moon and out again" "gone, then back at $X7" \
|| result no "and round the back of the moon and out again" "$X5 at five million, $X7 at seven"
# ---- Clearing puts the cursor back at the top ----
#
# A screen with nothing on it and a cursor half way down it is not a cleared screen. This