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
+220 -12
View File
@@ -100,9 +100,11 @@ everyFrame:
CALL zoomButton CALL zoomButton
CALL fall CALL fall
CALL move CALL move
CALL moveStation
CALL follow CALL follow
CALL touchdown CALL touchdown
CALL showLander CALL showLander
CALL showStation
CALL showDrift CALL showDrift
CALL showFall CALL showFall
CALL showFuel CALL showFuel
@@ -158,6 +160,28 @@ putTiles:
OUTA 0xE7 OUTA 0xE7
INIA 0x01 INIA 0x01
OUTA 0xE8 ; Blit. OUTA 0xE8 ; Blit.
OUTA 0xE0 ; Bank one again, A still holding the one the blit above wanted.
SETD.1 StationArtAt
SETD.0 StationArt
STD.0.1
LDA.1
OUTA 0xE1
INCD.1
LDA.1
OUTA 0xE2
INIA 0d4
OUTA 0xE3
INIA 0x32
OUTA 0xE4
INIA 0x80
OUTA 0xE5 ; Tile 202, one tile on again.
RSTA
OUTA 0xE6
INIA 0x40
OUTA 0xE7
INIA 0x01
OUTA 0xE8 ; Blit.
RET RET
; ---- A moon, one column at a time ---- ; ---- A moon, one column at a time ----
@@ -1183,27 +1207,164 @@ follow:
RET RET
; ---- The lander, put where it now is ---- ; ---- The lander, put where it now is ----
showLander: ; ---- Round it goes, one orbital speed a frame ----
SETD.0 DownLow moveStation:
CALL toPixels SETD.0 StationLow
SETD.1 StationSpeed
CALL addWord
SETD.0 StationHigh
LDA.0
INIB 0x3F
AND
STQ.0 ; The same wrap the lander has: 2^14 sixteenths round.
RET
; ---- Signed, which it did not have to be while the view never moved ---- ; ---- Where that puts it on the screen ----
; ;
; toPixels shifts a sixteen bit position down four and masks what is left to twelve bits, so ; The lander is always at the middle, so the station's column is the middle plus HOW FAR ROUND
; a lander above the world's origin comes back as a large POSITIVE number rather than a small ; IT IS FROM THE LANDER. That difference is taken in the moon's own arithmetic and wrapped to
; negative one. That was harmless while the top of the screen was the origin: such a lander ; fourteen bits, which measures it the long way round whenever the station is behind: over
; was off the picture either way. Now that the wide view starts twenty four rows higher it is ; half a moon ahead IS under half a moon behind, so anything past the half way point is turned
; on the picture, and it has to be on the right part of it. ; into a negative offset instead.
;
; Off the edge needs no test. 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
; to draw it, which is a comparison this does not have to make.
showStation:
SETD.0 StationLow
LDA.0
SETD.1 AcrossLow
LDB.1
CCF
SUB
SETD.1 GapLow
STQ.1
SETD.0 StationHigh
LDA.0
SETD.1 AcrossHigh
LDB.1
SUB ; And the borrow the half below left.
MVQA
INIB 0x3F
AND
SETD.1 GapHigh
STQ.1
SETD.0 GapLow
CALL toPixels ; Nought to 1023 pixels, which is the whole moon.
SETD.0 PixelHigh
LDA.0
INIB 0x02
AND
BRQ stationAhead ; Under 512, so it is ahead and the offset stands.
LDA.0
INIB 0d4
CCF
SUB
STQ.0 ; Less a whole moon, which makes it a distance backwards.
stationAhead:
SETD.0 PixelLow
LDA.0
SETD.1 HalfScreen
LDB.1
CCF
ADD
SETD.1 StationAt
STQ.1
SETD.0 PixelHigh
LDA.0
SETD.1 HalfScreen
INCD.1
LDB.1
ADD
SETD.1 StationAt
INCD.1
STQ.1
; And its row, which moves with the view exactly as the lander's does.
SETD.0 StationDownLow
CALL toPixelsSigned
SETD.0 PixelLow
LDA.0
SETD.1 ShipYAdd
LDB.1
CCF
ADD
SETD.1 StationTop
STQ.1
SETD.0 PixelHigh
LDA.0
SETD.1 ShipYAdd
INCD.1
LDB.1
ADD
SETD.1 StationTop
INCD.1
STQ.1
INIA 0d4
OUTA 0xE3
INIA 0xC0
OUTA 0xE4
INIA 0x60
OUTA 0xE5 ; Sprite six begins ninety six bytes in.
INIA 0xCA
OUTA 0xE9 ; Tile 202.
INIA 0x04
OUTA 0xE9 ; ---- Attribute four, blue ----
;
; Not taste. White is what the ceiling warning is counted in, cyan
; is what a landing pad is counted in, 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.
SETD.0 StationAt
LDA.0
OUTA 0xE9
INCD.0
LDA.0
OUTA 0xE9 ; X.
SETD.0 StationTop
LDA.0
OUTA 0xE9
INCD.0
LDA.0
OUTA 0xE9 ; Y.
INIA 0x11
OUTA 0xE9 ; One tile by one.
RSTA
OUTA 0xE9 ; No flags.
OUTA 0xE9
OUTA 0xE9
OUTA 0xE9
OUTA 0xE9 ; No target size, which HERE means its natural one.
OUTA 0xE9 ; And no depth.
RET
; ---- A world position in pixels, with its sign kept ----
;
; toPixels shifts a sixteen bit position down four and masks what is left to twelve bits, so a
; position above the world's origin comes back as a large POSITIVE number rather than a small
; negative one. That was harmless while the top of the screen WAS the origin: anything up
; there was off the picture either way. Now that the wide view starts twenty four rows higher
; it is on the picture, and it has to be on the right part of it.
toPixelsSigned:
CALL toPixels
SETD.0 PixelHigh SETD.0 PixelHigh
LDA.0 LDA.0
INIB 0x08 INIB 0x08
AND AND
BRQ showLanderDown BRQ toPixelsSignedDone
LDA.0 LDA.0
INIB 0xF0 INIB 0xF0
OR OR
STQ.0 ; The twelfth bit was the sign, so the top nibble is too. STQ.0 ; The twelfth bit was the sign, so the top nibble is too.
showLanderDown: toPixelsSignedDone:
RET
showLander:
SETD.0 DownLow
CALL toPixelsSigned
INIA 0d4 INIA 0d4
OUTA 0xE3 OUTA 0xE3
INIA 0xC0 INIA 0xC0
@@ -2592,6 +2753,53 @@ EmptyText:
CrashedText: CrashedText:
"Crashed." "Crashed."
; ---- The station, which is a body and not a special case ----
;
; A circular orbit is exactly what a thing at orbital speed DOES under the rules already here:
; the pull and the swing cancel at 64 sixteenths, at any height, because gravity never falls
; off and the moon wraps. So the station needs no physics of its own - a position, a constant,
; and the same wrap the lander uses.
;
; Four rows above the world's origin, which is off the top of a forty column screen and
; comfortably inside a wide one. That is deliberate: it makes the station a reason to use the
; zoom rather than something that can be flown to without it.
;
; It starts half a moon away, so it has to be found. At four pixels a frame a lap is 256
; frames, a little over four seconds, so it will not stay lost for long.
StationLow:
0xA0
StationHigh:
0x34
StationDownLow:
0x00
StationDownHigh:
0xFE ; Minus 512 sixteenths, which is four rows up.
StationSpeed:
0x40 0x00 ; Orbital speed, and the whole of its behaviour.
; How far round the moon the station is from the lander, and where that puts it on the screen.
GapLow:
0x00
GapHigh:
0x00
StationAt:
0x00 0x00
StationTop:
0x00 0x00
StationArt:
0x00 0x00 0x01 0x01 0x01 0x01 0x00 0x00
0x00 0x00 0x00 0x01 0x01 0x00 0x00 0x00
0x01 0x01 0x00 0x01 0x01 0x00 0x01 0x01
0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01
0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01
0x01 0x01 0x00 0x01 0x01 0x00 0x01 0x01
0x00 0x00 0x00 0x01 0x01 0x00 0x00 0x00
0x00 0x00 0x01 0x01 0x01 0x01 0x00 0x00
StationArtAt:
#Reserve 0d2
LanderArt: LanderArt:
0x00 0x00 0x01 0x01 0x01 0x01 0x00 0x00 0x00 0x00 0x01 0x01 0x01 0x01 0x00 0x00
0x00 0x01 0x01 0x01 0x01 0x01 0x01 0x00 0x00 0x01 0x01 0x01 0x01 0x01 0x01 0x00
+1 -1
View File
@@ -727,7 +727,7 @@ from every assembly file in it. Several are old programs written for the bare ma
| Grid | The first program to use the screen as a screen. Redefines a tile above the font, fills all 128 map rows, and scrolls it diagonally a pixel at a time. | | Grid | The first program to use the screen as a screen. Redefines a tile above the font, fills all 128 map rows, and scrolls it diagonally a pixel at a time. |
| Sprite | Moves a ball across the shell's own text, writing not one byte of the map to do it. It leaves the sprite in the table on the way out, because clearing them is the system's job - see below. | | Sprite | Moves a ball across the shell's own text, writing not one byte of the map to do it. It leaves the sprite in the table on the way out, because clearing them is the system's job - see below. |
| Pad | Says what the controllers are doing, printing a line whenever one changes. It tells apart the three things that look identical from inside a game that is not responding: a pad nobody noticed, a pad mapped to nothing, and a mapping that is wrong. | | Pad | Says what the controllers are doing, printing a line whenever one changes. It tells apart the three things that look identical from inside a game that is not responding: a pad nobody noticed, a pad mapped to nothing, and a mapping that is wrong. |
| Lander | Lunar Porter, rung one: a lander over a moon that wraps. Flown with a controller if there is one - a held thruster burns every tick it is held for - and with the arrow keys if there is not, where one press is one burn and that is the most the console can say. A bar at the bottom is the sideways drift, drawn as a sprite stretched to the speed - a moon has no air, so a drift never stops by itself and stopping one means cancelling it exactly, which is hard to do blind. It lands or crashes on arrival, and what decides is the speed at the moment it touches: gentler than three quarters of a pixel a frame downwards and half of one sideways, or it is a lander on its side. A fuel gauge sits in the window layer, where the moon turning underneath cannot scroll it away, and every thruster costs a unit of fuel every tick it fires. An empty tank is not an ending: it is a lander still flying that can no longer do anything about where. Four landing pads are carved into the moon after it is generated, levelled to whatever height their first column happened to have, and marked in cyan by an attribute rather than a tile of their own. The lander starts above one, because that is where a porter's day begins. Each pad is a base, told apart by the colour it is drawn in, and landing at one either loads cargo for the base across the moon or delivers what is aboard and pays eighty units of fuel. A landing is not an ending: the lander rests where it is until the throttle opens again, and A or Start says "read it" as readily as a key does. What a base says goes in the window rather than out of the console: the console draws into the map, so a message printed while flying is one the lander then flies over, and printing scrolls the whole world up a row. Opening the throttle wipes the line. Two bars read the speeds and are green while a landing would survive and red while it would not, so "can I put down" is a glance rather than a sum. A third runs up the left edge and is how much sky is under the lander, half a pixel of bar to a pixel of it; it reads nought the moment the lander is down, and it exists because the orbit takes the lander off the top of the screen and a panel that only works while the ground is in sight is no use above it. And gravity here is the pull MINUS the swing outwards, which is what makes an orbit rather than a one way trip: under four pixels a frame sideways the pull wins and the lander falls, over it the swing wins and the lander climbs, and at it they cancel and it circles. Falling buys sideways speed and climbing spends it - at a rate set by the product of the two, so the trade stops by itself as the sideways speed runs out - and that is the cycle: a fall carries the lander past orbital speed and becomes a climb, the climb pays it back and becomes a fall, periapse and apoapse, round and round. Orbital speed is marked on the drift bar, sixty four pixels either side of the middle, because a number nothing points at is folklore. Gravity never falls off and the moon wraps, so a circular orbit is the same length at any height and one orbital speed serves everywhere. There is a ceiling sixty four pixels above the screen, which pins rather than ends: leaving upward is recoverable, so the lander is held there and told so, and one sideways is spent every tick it tries to climb - without that the pin wiped the climb, the trade saw neither fall nor climb, and the speed pushing it up never changed. What kills you out here is running dry a long way from the ground. B, or z on the keyboard, swaps the screen between forty columns and eighty, which is the same map, the same cells and the same engine at half the size: nearly two thirds of the moon at once for the orbit, and twice as big for the landing. The twenty extra rows that buys go to the SKY and not to the moon - the wide view starts twenty four rows above the world's origin rather than at it, so the ground sits near the bottom and the whole flyable band is on the screen. Drawn down from the origin instead it was 71 per cent rock, which is a zoom that shows you more of the thing you cannot fly through. A lander at the ceiling is off the top of a forty column screen, which is where the orbit lives and why the altitude bar had to exist; zoomed out it is in the picture. | | Lander | Lunar Porter, rung one: a lander over a moon that wraps. Flown with a controller if there is one - a held thruster burns every tick it is held for - and with the arrow keys if there is not, where one press is one burn and that is the most the console can say. A bar at the bottom is the sideways drift, drawn as a sprite stretched to the speed - a moon has no air, so a drift never stops by itself and stopping one means cancelling it exactly, which is hard to do blind. It lands or crashes on arrival, and what decides is the speed at the moment it touches: gentler than three quarters of a pixel a frame downwards and half of one sideways, or it is a lander on its side. A fuel gauge sits in the window layer, where the moon turning underneath cannot scroll it away, and every thruster costs a unit of fuel every tick it fires. An empty tank is not an ending: it is a lander still flying that can no longer do anything about where. Four landing pads are carved into the moon after it is generated, levelled to whatever height their first column happened to have, and marked in cyan by an attribute rather than a tile of their own. The lander starts above one, because that is where a porter's day begins. Each pad is a base, told apart by the colour it is drawn in, and landing at one either loads cargo for the base across the moon or delivers what is aboard and pays eighty units of fuel. A landing is not an ending: the lander rests where it is until the throttle opens again, and A or Start says "read it" as readily as a key does. What a base says goes in the window rather than out of the console: the console draws into the map, so a message printed while flying is one the lander then flies over, and printing scrolls the whole world up a row. Opening the throttle wipes the line. Two bars read the speeds and are green while a landing would survive and red while it would not, so "can I put down" is a glance rather than a sum. A third runs up the left edge and is how much sky is under the lander, half a pixel of bar to a pixel of it; it reads nought the moment the lander is down, and it exists because the orbit takes the lander off the top of the screen and a panel that only works while the ground is in sight is no use above it. And gravity here is the pull MINUS the swing outwards, which is what makes an orbit rather than a one way trip: under four pixels a frame sideways the pull wins and the lander falls, over it the swing wins and the lander climbs, and at it they cancel and it circles. Falling buys sideways speed and climbing spends it - at a rate set by the product of the two, so the trade stops by itself as the sideways speed runs out - and that is the cycle: a fall carries the lander past orbital speed and becomes a climb, the climb pays it back and becomes a fall, periapse and apoapse, round and round. Orbital speed is marked on the drift bar, sixty four pixels either side of the middle, because a number nothing points at is folklore. Gravity never falls off and the moon wraps, so a circular orbit is the same length at any height and one orbital speed serves everywhere. There is a ceiling sixty four pixels above the screen, which pins rather than ends: leaving upward is recoverable, so the lander is held there and told so, and one sideways is spent every tick it tries to climb - without that the pin wiped the climb, the trade saw neither fall nor climb, and the speed pushing it up never changed. What kills you out here is running dry a long way from the ground. B, or z on the keyboard, swaps the screen between forty columns and eighty, which is the same map, the same cells and the same engine at half the size: nearly two thirds of the moon at once for the orbit, and twice as big for the landing. The twenty extra rows that buys go to the SKY and not to the moon - the wide view starts twenty four rows above the world's origin rather than at it, so the ground sits near the bottom and the whole flyable band is on the screen. Drawn down from the origin instead it was 71 per cent rock, which is a zoom that shows you more of the thing you cannot fly through. A lander at the ceiling is off the top of a forty column screen, which is where the orbit lives and why the altitude bar had to exist; zoomed out it is in the picture. And there is a station up there, four rows above the world's origin, going round at orbital speed - which needs no physics of its own, because a body at 64 sixteenths is exactly what a circular orbit IS under these rules, at any height, since gravity never falls off and the moon wraps. It is off the top of a forty column screen too, so it is somewhere to go that the zoom is needed to see. It cannot be docked with yet: it goes round, and that is all. |
| Depth | Four pillars at four distances and a ball walking past them, behind the near ones and in front of the far ones. The ball is sprite nought and every pillar is numbered after it, so table order puts it in front of all four - what actually decides is the depth buffer, asked a column at a time. | | Depth | Four pillars at four distances and a ball walking past them, behind the near ones and in front of the far ones. The ball is sprite nought and every pillar is numbered after it, so table order puts it in front of all four - what actually decides is the depth buffer, asked a column at a time. |
| Flip | Draws a whole screen into the bank that is not being shown, waits, and then shows it in one byte out of one port. It writes nothing else at all - not a tile, not a colour - so it does not ask for the screen to be saved, and the line it printed is still there when it comes back. It deliberately does not put the displayed screen back either, because that is the system's to restore: a program that faulted while flipped could not have. | | Flip | Draws a whole screen into the bank that is not being shown, waits, and then shows it in one byte out of one port. It writes nothing else at all - not a tile, not a colour - so it does not ask for the screen to be saved, and the line it printed is still there when it comes back. It deliberately does not put the displayed screen back either, because that is the system's to restore: a program that faulted while flipped could not have. |
| Edit | A line editor. | | Edit | A line editor. |
+1 -1
View File
@@ -25,7 +25,7 @@ Mode.sbx 48
Flip.sbx 173 Flip.sbx 173
Sprite.sbx 442 Sprite.sbx 442
Depth.sbx 672 Depth.sbx 672
Lander.sbx 5365 Lander.sbx 5751
Pad.sbx 264 Pad.sbx 264
Crash.sbx 632 Crash.sbx 632
vars.script 50 vars.script 50
+1 -1
View File
@@ -15,7 +15,7 @@ Mode.sbx 48
Flip.sbx 173 Flip.sbx 173
Sprite.sbx 442 Sprite.sbx 442
Depth.sbx 672 Depth.sbx 672
Lander.sbx 5365 Lander.sbx 5751
Pad.sbx 264 Pad.sbx 264
Crash.sbx 632 Crash.sbx 632
vars.script 50 vars.script 50
+1 -1
View File
@@ -32,7 +32,7 @@ Mode.sbx 48
Flip.sbx 173 Flip.sbx 173
Sprite.sbx 442 Sprite.sbx 442
Depth.sbx 672 Depth.sbx 672
Lander.sbx 5365 Lander.sbx 5751
Pad.sbx 264 Pad.sbx 264
Crash.sbx 632 Crash.sbx 632
vars.script 50 vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173 Flip.sbx 173
Sprite.sbx 442 Sprite.sbx 442
Depth.sbx 672 Depth.sbx 672
Lander.sbx 5365 Lander.sbx 5751
Pad.sbx 264 Pad.sbx 264
Crash.sbx 632 Crash.sbx 632
vars.script 50 vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173 Flip.sbx 173
Sprite.sbx 442 Sprite.sbx 442
Depth.sbx 672 Depth.sbx 672
Lander.sbx 5365 Lander.sbx 5751
Pad.sbx 264 Pad.sbx 264
Crash.sbx 632 Crash.sbx 632
vars.script 50 vars.script 50
+1 -1
View File
@@ -108,7 +108,7 @@ Mode.sbx 48
Flip.sbx 173 Flip.sbx 173
Sprite.sbx 442 Sprite.sbx 442
Depth.sbx 672 Depth.sbx 672
Lander.sbx 5365 Lander.sbx 5751
Pad.sbx 264 Pad.sbx 264
Crash.sbx 632 Crash.sbx 632
vars.script 50 vars.script 50
+1 -1
View File
@@ -27,7 +27,7 @@ Mode.sbx 48
Flip.sbx 173 Flip.sbx 173
Sprite.sbx 442 Sprite.sbx 442
Depth.sbx 672 Depth.sbx 672
Lander.sbx 5365 Lander.sbx 5751
Pad.sbx 264 Pad.sbx 264
Crash.sbx 632 Crash.sbx 632
vars.script 50 vars.script 50
+1 -1
View File
@@ -15,7 +15,7 @@ Mode.sbx 48
Flip.sbx 173 Flip.sbx 173
Sprite.sbx 442 Sprite.sbx 442
Depth.sbx 672 Depth.sbx 672
Lander.sbx 5365 Lander.sbx 5751
Pad.sbx 264 Pad.sbx 264
Crash.sbx 632 Crash.sbx 632
vars.script 50 vars.script 50
+1 -1
View File
@@ -13,7 +13,7 @@ Mode.sbx 48
Flip.sbx 173 Flip.sbx 173
Sprite.sbx 442 Sprite.sbx 442
Depth.sbx 672 Depth.sbx 672
Lander.sbx 5365 Lander.sbx 5751
Pad.sbx 264 Pad.sbx 264
Crash.sbx 632 Crash.sbx 632
vars.script 50 vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173 Flip.sbx 173
Sprite.sbx 442 Sprite.sbx 442
Depth.sbx 672 Depth.sbx 672
Lander.sbx 5365 Lander.sbx 5751
Pad.sbx 264 Pad.sbx 264
Crash.sbx 632 Crash.sbx 632
vars.script 50 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 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" || 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 ---- # ---- 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 # A screen with nothing on it and a cursor half way down it is not a cleared screen. This