The room a zoom buys goes to the sky, not to the moon
Zooming out drew fifty rows DOWN from the world's origin, which put exactly the same sky on the screen as before with twice as much moon under it. Measured: 47 per cent rock zoomed in and 71 per cent zoomed out. A zoom that shows you more of the thing you cannot fly through is not worth a button. The eighty column screen is fifty rows and the flyable band is thirty - the ceiling is eight rows above the origin and the deepest valley is twenty two below it - so the twenty rows a zoom buys have to go somewhere. They go above. The wide view starts twenty four rows over the origin, the ground sits near the bottom, and the whole band is on the screen: 23 per cent rock instead of 71. Which needed three things. The moon is drawn from row minus twenty four rather than from nought, because rows above the origin are sky by definition and because whatever the shell left in them is otherwise still there. The row origin comes out of the view block like every other screen number. And the lander's own Y moves with the view, which meant making toPixels' answer SIGNED at last: it masks to twelve bits, so a lander above the origin came back as a large positive number rather than a small negative one - harmless while such a lander was off the picture either way, and wrong the moment the view moved up to include it. That is the point of the button. 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 at row 149 and you can watch the whole orbit. Four checks, and the proportion is deliberately not on its own: measured alone it passes for a moon floating over a void, because pointing the view back at the origin leaves the rows under the terrain simply never drawn, and black counts as sky. Both breaks that matter went straight through it. What catches them is that the ground has to reach the bottom of the screen and the sky has to be empty - the latter only on a shell scrolled a hundred and eighteen lines deep, since that is what it takes to get anything into the rows the wide view moves into. The tap fixture also moved to frame 100. Fifty rows of moon take longer to draw than twenty five, and a six frame tap at frame thirty now lands before the program is reading a controller at all, which reads exactly like a button that has stopped working.
This commit is contained in:
@@ -52,7 +52,6 @@ start:
|
||||
SETD.0 Wide
|
||||
LDA.0
|
||||
OUTA 0x31 ; Forty columns to start in. B swaps to eighty and back.
|
||||
RSTA
|
||||
|
||||
; ---- And the view put back to the top of the map ----
|
||||
;
|
||||
@@ -66,7 +65,10 @@ start:
|
||||
;
|
||||
; 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.
|
||||
SETD.0 ScrollRow
|
||||
LDA.0
|
||||
OUTA 0x34
|
||||
RSTA
|
||||
OUTA 0x38 ; No fraction of a cell downwards either.
|
||||
|
||||
CALL mulReady ; The quarter square table, once. The orbit below needs a product.
|
||||
@@ -344,8 +346,22 @@ randomTap:
|
||||
; are next to each other, so the address is named once and the controller's Data port steps
|
||||
; through 128 of them. Cells down a COLUMN are a page apart, and doing it that way would mean
|
||||
; naming an address for every one of the 3,200 cells.
|
||||
; ---- Drawn from twenty four rows above the world, not from the world's top ----
|
||||
;
|
||||
; The eighty column screen is fifty rows and the flyable band is thirty: the ceiling is eight
|
||||
; rows above the origin and the deepest valley is twenty two below it. So the extra twenty
|
||||
; rows a zoom buys have to go SOMEWHERE, and the first version gave them all to rock - it
|
||||
; drew fifty rows down from the origin, which put the same sky on the screen as before with
|
||||
; twice as much moon under it. Measured: 47 per cent moon zoomed in and 71 per cent zoomed
|
||||
; out, which is a zoom that shows you less of what you are flying in.
|
||||
;
|
||||
; They go above instead. The rows run from minus twenty four to twenty five, which is the
|
||||
; whole band with the ground near the bottom of it, and negative rows are sky by definition
|
||||
; because nothing has a surface up there. In forty columns the ones above the origin are not
|
||||
; on the screen at all, and drawing them anyway costs a startup and clears whatever the shell
|
||||
; left in them.
|
||||
drawMoon:
|
||||
RSTA
|
||||
INIA 0xE8 ; Minus twenty four.
|
||||
SETD.1 Row
|
||||
STA.1
|
||||
drawRow:
|
||||
@@ -353,6 +369,9 @@ drawRow:
|
||||
OUTA 0xE3
|
||||
SETD.1 Row
|
||||
LDA.1
|
||||
INIB 0x7F
|
||||
AND
|
||||
MVQA ; Round the ring of 128, so minus twenty four is row 104.
|
||||
INIB 0x40
|
||||
CCF
|
||||
ADD
|
||||
@@ -364,12 +383,18 @@ drawRow:
|
||||
SETD.1 Column
|
||||
STA.1 ; A is still the nought that went to DestLow.
|
||||
drawCell:
|
||||
; Above the world's origin, where no column has a surface, so there is nothing to compare.
|
||||
SETD.1 Row
|
||||
LDA.1
|
||||
INIB 0x80
|
||||
AND
|
||||
BNQ drawSky
|
||||
|
||||
; ---- Ground at the surface row and everything under it ----
|
||||
;
|
||||
; ROW MINUS HEIGHT and not the other way round, which matters at the surface itself: the
|
||||
; two are equal there, equal does not borrow, and the row a column's surface is on has to
|
||||
; be ground rather than the last of the sky.
|
||||
SETD.1 Row
|
||||
LDA.1
|
||||
LDB.2
|
||||
CCF
|
||||
@@ -422,11 +447,10 @@ drawNextCell:
|
||||
LDA.1
|
||||
INCA
|
||||
STA.1
|
||||
SETD.2 MoonRows
|
||||
LDB.2
|
||||
INIB 0d26
|
||||
CCF
|
||||
SUB
|
||||
BNQ drawRow
|
||||
BNQ drawRow ; Fifty rows, from minus twenty four up to and including 25.
|
||||
RET
|
||||
|
||||
; ---- The lander, as a sprite ----
|
||||
@@ -1162,6 +1186,24 @@ follow:
|
||||
showLander:
|
||||
SETD.0 DownLow
|
||||
CALL toPixels
|
||||
|
||||
; ---- Signed, which it did not have to be while the view never moved ----
|
||||
;
|
||||
; toPixels shifts a sixteen bit position down four and masks what is left to twelve bits, so
|
||||
; a lander 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: such a lander
|
||||
; 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.
|
||||
SETD.0 PixelHigh
|
||||
LDA.0
|
||||
INIB 0x08
|
||||
AND
|
||||
BRQ showLanderDown
|
||||
LDA.0
|
||||
INIB 0xF0
|
||||
OR
|
||||
STQ.0 ; The twelfth bit was the sign, so the top nibble is too.
|
||||
showLanderDown:
|
||||
INIA 0d4
|
||||
OUTA 0xE3
|
||||
INIA 0xC0
|
||||
@@ -1170,10 +1212,17 @@ showLander:
|
||||
OUTA 0xE5 ; Y is bytes four and five of the entry.
|
||||
SETD.0 PixelLow
|
||||
LDA.0
|
||||
OUTA 0xE9
|
||||
SETD.1 ShipYAdd
|
||||
LDB.1
|
||||
CCF
|
||||
ADD
|
||||
OUTQ 0xE9
|
||||
SETD.0 PixelHigh
|
||||
LDA.0
|
||||
OUTA 0xE9
|
||||
INCD.1
|
||||
LDB.1
|
||||
ADD ; And the carry, which is the other half of the shift.
|
||||
OUTQ 0xE9
|
||||
RET
|
||||
|
||||
; ---- Green if it would survive, red if it would not ----
|
||||
@@ -1722,7 +1771,7 @@ setView:
|
||||
SETD.0 ViewWide
|
||||
setViewFrom:
|
||||
SETD.1 View
|
||||
INIA 0d15
|
||||
INIA 0d17
|
||||
SETD.2 ViewLeft
|
||||
STA.2
|
||||
setViewByte:
|
||||
@@ -1752,6 +1801,9 @@ toggleView:
|
||||
SETD.0 Wide
|
||||
LDA.0
|
||||
OUTA 0x31
|
||||
SETD.0 ScrollRow
|
||||
LDA.0
|
||||
OUTA 0x34 ; The wide view starts higher up, which is where the sky is.
|
||||
CALL drawMoon
|
||||
CALL putLander
|
||||
CALL putGauge
|
||||
@@ -2368,8 +2420,10 @@ HeightFoot:
|
||||
0xB4 0x00
|
||||
RowCells:
|
||||
0d40
|
||||
MoonRows:
|
||||
0d25
|
||||
ScrollRow:
|
||||
0d0
|
||||
ShipYAdd:
|
||||
0x00 0x00
|
||||
ViewLeft:
|
||||
0x00 ; How much of the block is still to copy.
|
||||
|
||||
@@ -2383,7 +2437,8 @@ ViewNarrow:
|
||||
0d100 ; Half the height, which is where the fall bar starts.
|
||||
0xB4 0x00 ; The height bar's foot.
|
||||
0d40 ; Cells to a window row.
|
||||
0d25 ; Rows of moon to draw.
|
||||
0d0 ; The map row the top of the screen is, and
|
||||
0x00 0x00 ; how far the lander's own Y has to move with it.
|
||||
|
||||
; Eighty columns: 640 by 400, the same cells at half the size, so twice as much moon either
|
||||
; way. Every screen number doubles except the ones measured from an edge, which are the edge
|
||||
@@ -2397,7 +2452,8 @@ ViewWide:
|
||||
0d200
|
||||
0x7C 0x01 ; 380.
|
||||
0d80
|
||||
0d50
|
||||
0d104 ; Twenty four rows ABOVE the world's origin, which is the point.
|
||||
0xC0 0x00 ; So the lander's Y moves 192 pixels down to match.
|
||||
|
||||
; Which of the two is up. Nought is forty columns, which is what the program starts in.
|
||||
Wide:
|
||||
|
||||
@@ -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. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| Edit | A line editor. |
|
||||
|
||||
@@ -25,7 +25,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 5304
|
||||
Lander.sbx 5365
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -15,7 +15,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 5304
|
||||
Lander.sbx 5365
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -32,7 +32,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 5304
|
||||
Lander.sbx 5365
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -22,7 +22,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 5304
|
||||
Lander.sbx 5365
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -22,7 +22,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 5304
|
||||
Lander.sbx 5365
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -108,7 +108,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 5304
|
||||
Lander.sbx 5365
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -27,7 +27,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 5304
|
||||
Lander.sbx 5365
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -15,7 +15,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 5304
|
||||
Lander.sbx 5365
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -13,7 +13,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 5304
|
||||
Lander.sbx 5365
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -22,7 +22,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 5304
|
||||
Lander.sbx 5365
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
+98
-3
@@ -2050,10 +2050,14 @@ EOT
|
||||
# is not only the mode it lands on but the TIME it costs, because each swap redraws the whole
|
||||
# moon. Holding is checked to land in the same place as tapping, which a strobe cannot do.
|
||||
python3 -c "open('$BUILD/narrow.pad','wb').write(b'\x00' * 8000)"
|
||||
python3 -c "open('$BUILD/tap.pad','wb').write(b'\x00' * 30 + b'\x20' * 6 + b'\x00' * 8000)"
|
||||
python3 -c "open('$BUILD/hold.pad','wb').write(b'\x00' * 30 + b'\x20' * 300 + b'\x00' * 8000)"
|
||||
# A hundred frames before the button, because the program spends the first sixty or so
|
||||
# drawing fifty rows of moon and is not reading a controller yet. A six frame tap at frame
|
||||
# thirty used to work and stopped the day the moon got deeper, which reads exactly like a
|
||||
# button that no longer does anything.
|
||||
python3 -c "open('$BUILD/tap.pad','wb').write(b'\x00' * 100 + b'\x20' * 8 + b'\x00' * 8000)"
|
||||
python3 -c "open('$BUILD/hold.pad','wb').write(b'\x00' * 100 + b'\x20' * 300 + b'\x00' * 8000)"
|
||||
for view in narrow tap hold; do
|
||||
timeout 60 "$EMU" --fast --cycles 2200000 --keyboard "$BUILD/fly.keys" \
|
||||
timeout 60 "$EMU" --fast --cycles 3500000 --keyboard "$BUILD/fly.keys" \
|
||||
--pad "$BUILD/$view.pad" --screen "$BUILD/$view.ppm" \
|
||||
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
|
||||
"$BUILD/cosmos.bin" > "$BUILD/$view.out" 2>&1 || true
|
||||
@@ -2117,6 +2121,97 @@ print(int(d[:40].split()[1]))
|
||||
&& result ok "and holding it swaps once, not sixty times a second" "held lands where tapped did" \
|
||||
|| result no "and holding it swaps once, not sixty times a second" "tapped $TAPY, held $HELDY at $HELD across"
|
||||
|
||||
# ---- And the room the zoom buys goes to the sky, not to the rock ----
|
||||
#
|
||||
# The first version of this drew fifty rows DOWN from the world's origin, which put exactly
|
||||
# the same sky on the screen as before with twice as much moon under it: 47 per cent moon
|
||||
# zoomed in and 71 per cent zoomed out. A zoom that shows you more of the thing you cannot fly
|
||||
# through is not worth a button. The rows go above instead, so the wide view starts twenty
|
||||
# four rows over the origin and the ground sits near the bottom of it.
|
||||
#
|
||||
# THREE CHECKS, and the proportion alone is not one of them. Measured on its own it passes for
|
||||
# a moon floating over a void: point the view at the world's origin again and the rows below
|
||||
# the terrain are simply never drawn, which is black, which counts as sky. Both breaks that
|
||||
# matter went straight through a proportion check and are caught by the two beside it - the
|
||||
# ground has to REACH THE BOTTOM of the screen, and the sky above the world has to be empty
|
||||
# rather than holding whatever the shell left in those rows.
|
||||
#
|
||||
# THE SHELL HAS TO BE SCROLLED DEEP for the second of those to mean anything, and that took
|
||||
# finding out. The map is a ring of 128 rows and the wide view moves into rows 104 to 127; a
|
||||
# shell that has only printed a few lines has never written up there, so leaving those rows
|
||||
# alone looks exactly like clearing them. A hundred and eighteen returns first, which puts the
|
||||
# prompt in that band, and then the difference appears: 136 pixels of somebody else's text
|
||||
# hanging in the sky.
|
||||
python3 -c "open('$BUILD/deep.keys','wb').write(b'\n' * 118 + b'Lander\n' + b'\x00' * 8000)"
|
||||
timeout 60 "$EMU" --fast --cycles 8000000 --keyboard "$BUILD/deep.keys" \
|
||||
--pad "$BUILD/tap.pad" --screen "$BUILD/deep.ppm" \
|
||||
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
|
||||
"$BUILD/cosmos.bin" > "$BUILD/deep.out" 2>&1 || true
|
||||
read -r NARROWMOON WIDEMOON NARROWFLOOR WIDEFLOOR WIDESKY <<EOT
|
||||
$(python3 -c "
|
||||
def look(path):
|
||||
d = open(path, 'rb').read()
|
||||
head = d[:40].split()
|
||||
width, height = int(head[1]), int(head[2])
|
||||
px = d[d.index(b'255\n') + 4:]
|
||||
moon = bytes.fromhex('d8d8d8')
|
||||
at = [(i % width, i // width) for i in range(len(px) // 3)
|
||||
if px[i * 3:i * 3 + 3] == moon]
|
||||
rock = 100 * len(at) // (width * height)
|
||||
floor = sum(1 for x, y in at if y == height - 1)
|
||||
# Below the two row window and above the highest ground a terrain row can reach.
|
||||
sky = sum(1 for x, y in at if 16 <= y < 260)
|
||||
return rock, floor, sky, width
|
||||
n = look('$BUILD/narrow.ppm'); w = look('$BUILD/hold.ppm')
|
||||
print(n[0], w[0], '%d/%d' % (n[1], n[3]), '%d/%d' % (w[1], w[3]),
|
||||
look('$BUILD/deep.ppm')[2])
|
||||
" 2>/dev/null || echo "0 100 0/1 0/1 999")
|
||||
EOT
|
||||
[ "$WIDEMOON" -lt "$NARROWMOON" ] && [ "$WIDEMOON" -lt 35 ] \
|
||||
&& result ok "and zooming out buys sky, not moon" "$NARROWMOON per cent rock became $WIDEMOON" \
|
||||
|| result no "and zooming out buys sky, not moon" "$NARROWMOON per cent rock became $WIDEMOON"
|
||||
# A whole scanline of moon along the bottom in both. Without it the terrain is a band with
|
||||
# nothing underneath, which is what pointing the wide view at the origin actually produces.
|
||||
[ "$NARROWFLOOR" = "320/320" ] && [ "$WIDEFLOOR" = "640/640" ] \
|
||||
&& result ok "and the ground still reaches the bottom" "a full scanline of moon in both" \
|
||||
|| result no "and the ground still reaches the bottom" "$NARROWFLOOR then $WIDEFLOOR"
|
||||
# The rows above the world's origin are drawn as sky rather than left alone, so nothing the
|
||||
# shell wrote up there is still sitting in the part of the map the wide view has moved into.
|
||||
# Read off the deeply scrolled run, which is the only one that has anything up there to leave.
|
||||
[ "$WIDESKY" = "0" ] \
|
||||
&& result ok "and the sky over the world is empty" "nothing left in the rows the view moved into" \
|
||||
|| result no "and the sky over the world is empty" "$WIDESKY pixels of moon up in the sky"
|
||||
|
||||
# ---- Which is the whole reason for the button ----
|
||||
#
|
||||
# A lander at the ceiling is OFF THE TOP of a forty column screen - that is where the orbit
|
||||
# lives, and it is why the altitude bar had to exist at all. Zoomed out it is on the picture,
|
||||
# because the wide view starts above the ceiling rather than at the world's origin. Same
|
||||
# flight, same nine hundred frames of thruster; the only difference is the button.
|
||||
python3 -c "open('$BUILD/ceilingin.pad','wb').write(b'\x00' * 20 + b'\x08' * 900 + b'\x00' * 8000)"
|
||||
python3 -c "open('$BUILD/ceilingout.pad','wb').write(b'\x00' * 20 + b'\x08' * 900 + b'\x20' * 8 + b'\x00' * 8000)"
|
||||
for view in ceilingin ceilingout; do
|
||||
timeout 60 "$EMU" --fast --cycles 17000000 --keyboard "$BUILD/fly.keys" \
|
||||
--pad "$BUILD/$view.pad" --screen "$BUILD/$view.ppm" \
|
||||
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
|
||||
"$BUILD/cosmos.bin" > "$BUILD/$view.out" 2>&1 || true
|
||||
done
|
||||
read -r INSHIP OUTSHIP <<EOT
|
||||
$(python3 -c "
|
||||
def shipRow(path):
|
||||
d = open(path, 'rb').read()
|
||||
width = int(d[:40].split()[1])
|
||||
px = d[d.index(b'255\n') + 4:]
|
||||
ship = bytes.fromhex('d8c048')
|
||||
rows = [i // width for i in range(len(px) // 3) if px[i * 3:i * 3 + 3] == ship]
|
||||
return min(rows) if rows else -1
|
||||
print(shipRow('$BUILD/ceilingin.ppm'), shipRow('$BUILD/ceilingout.ppm'))
|
||||
" 2>/dev/null || echo "-1 -1")
|
||||
EOT
|
||||
[ "$INSHIP" = "-1" ] && [ "$OUTSHIP" -gt 0 ] \
|
||||
&& 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"
|
||||
|
||||
# ---- 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
|
||||
|
||||
Reference in New Issue
Block a user