Two zoom levels on a button, which the device already had
Forty columns and eighty are the same map, the same 8x8 cells and the same engine; only how many of them fit differs. The map is 128 by 128 either way and the moon is exactly 128 columns of it. And the front end scales whatever it is handed by the largest whole number that fits, so 320 by 200 at four times and 640 by 400 at twice fill the same glass. So the two modes ARE two zoom levels and nothing in the video device had to change to get them: forty columns shows under a third of the moon at twice the size, eighty shows nearly two thirds. Out for the orbit, in for the landing, and B says which. What did have to change is every screen coordinate in Lander, because the middle of the screen is 160 on one and 320 on the other. They now live in one block that setView copies over from whichever of two tables matches the mode, so a gauge reads a variable and never has to know which screen it is on. Several coordinates became sixteen bit on the way, since 620 will not go in a byte. follow already read HalfScreen and showLander already writes the world position straight through, so the lander itself needed nothing but its resting column. The moon is redrawn on a swap because it is filled as many rows deep as the mode shows, and a moon drawn 25 deep on a screen showing 50 floats over nothing. The swap is edge triggered. A pad is LEVEL and not an event, so a view that swapped while B was down would swap sixty times a second - which is not a zoom, it is a strobe, and it redraws the whole moon each time. The check for that holds the button for three hundred frames and requires the lander to land where a six frame tap left it; with the edge dropped it ends seventeen pixels adrift, which is the strobe costing it frames. Four checks, each seen to fail on its own break. The README's Lander entry also still described the relief orbit that the previous commit replaced, and now describes the one that is there.
This commit is contained in:
+253
-45
@@ -48,8 +48,11 @@ start:
|
||||
; floor the system gives every program does not.
|
||||
SWI osTakeScreen
|
||||
|
||||
CALL setView ; The block every gauge below reads its screen numbers out of.
|
||||
SETD.0 Wide
|
||||
LDA.0
|
||||
OUTA 0x31 ; Forty columns to start in. B swaps to eighty and back.
|
||||
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 ----
|
||||
;
|
||||
@@ -92,6 +95,7 @@ everyFrame:
|
||||
CALL waitFrame
|
||||
CALL readPad
|
||||
CALL readControls
|
||||
CALL zoomButton
|
||||
CALL fall
|
||||
CALL move
|
||||
CALL follow
|
||||
@@ -418,7 +422,8 @@ drawNextCell:
|
||||
LDA.1
|
||||
INCA
|
||||
STA.1
|
||||
INIB 0d25
|
||||
SETD.2 MoonRows
|
||||
LDB.2
|
||||
CCF
|
||||
SUB
|
||||
BNQ drawRow
|
||||
@@ -440,10 +445,12 @@ putLander:
|
||||
OUTA 0xE9 ; Tile 201.
|
||||
INIA 0x03
|
||||
OUTA 0xE9 ; Attribute three, so it is yellow against a grey moon.
|
||||
INIA 0d156
|
||||
SETD.0 ShipX
|
||||
LDA.0
|
||||
OUTA 0xE9
|
||||
RSTA
|
||||
OUTA 0xE9 ; X: the middle of a 320 pixel screen, less half a tile.
|
||||
INCD.0
|
||||
LDA.0
|
||||
OUTA 0xE9 ; X: the middle of the screen, less half a tile. Never moves.
|
||||
OUTA 0xE9
|
||||
OUTA 0xE9 ; Y, which every frame overwrites.
|
||||
INIA 0x11
|
||||
@@ -1269,20 +1276,35 @@ driftSized2:
|
||||
SETD.1 DriftSize
|
||||
STA.1
|
||||
|
||||
; Where it starts: the middle for a rightward drift, and that much back for a leftward one.
|
||||
INIA 0d160
|
||||
SETD.0 DriftLeftward
|
||||
LDB.0
|
||||
BRB driftAt ; Nought is rightward, so the bar starts at the middle.
|
||||
SETD.0 DriftLow
|
||||
LDB.0
|
||||
CCF
|
||||
SUB
|
||||
MVQA
|
||||
|
||||
driftAt:
|
||||
; ---- Where it starts, in sixteen bits ----
|
||||
;
|
||||
; The middle for a rightward drift and that much back for a leftward one, and it is a WORD
|
||||
; now because the middle of an eighty column screen is 320 and will not go in a byte.
|
||||
SETD.0 MiddleX
|
||||
LDA.0
|
||||
SETD.1 DriftAt
|
||||
STA.1
|
||||
INCD.0
|
||||
LDA.0
|
||||
INCD.1
|
||||
STA.1
|
||||
SETD.0 DriftLeftward
|
||||
LDA.0
|
||||
BRA driftAt ; Nought is rightward, so the bar starts at the middle.
|
||||
SETD.0 DriftAt
|
||||
LDA.0
|
||||
SETD.1 DriftLow
|
||||
LDB.1
|
||||
CCF
|
||||
SUB
|
||||
SETD.1 DriftAt
|
||||
STQ.1
|
||||
INCD.0
|
||||
LDA.0
|
||||
RSTB
|
||||
SUB ; And the borrow, which is the other half of the step back.
|
||||
STQ.0
|
||||
driftAt:
|
||||
|
||||
INIA 0d4
|
||||
OUTA 0xE3
|
||||
@@ -1298,11 +1320,14 @@ driftAt:
|
||||
SETD.0 DriftAt
|
||||
LDA.0
|
||||
OUTA 0xE9
|
||||
RSTA
|
||||
INCD.0
|
||||
LDA.0
|
||||
OUTA 0xE9 ; X.
|
||||
INIA 0d188
|
||||
SETD.0 BarY
|
||||
LDA.0
|
||||
OUTA 0xE9
|
||||
RSTA
|
||||
INCD.0
|
||||
LDA.0
|
||||
OUTA 0xE9 ; Y, near the bottom and clear of the ground most places.
|
||||
SETD.0 DriftSize
|
||||
LDA.0
|
||||
@@ -1585,17 +1610,24 @@ showHeightReady:
|
||||
;
|
||||
; A sprite is placed by its TOP, so a bar that grows up is one whose top moves as its height
|
||||
; changes. Both come out of the same number and the foot stays put.
|
||||
INIA 0d180
|
||||
SETD.0 HeightBar
|
||||
LDB.0
|
||||
SETD.0 HeightFoot
|
||||
LDA.0
|
||||
LDB.1
|
||||
CCF
|
||||
SUB
|
||||
SETD.1 HeightAt
|
||||
STQ.1
|
||||
INCD.0
|
||||
LDA.0
|
||||
RSTB
|
||||
SUB ; And the borrow, which is the other half of the foot.
|
||||
INCD.1
|
||||
STQ.1
|
||||
|
||||
; Nought is the off switch, and it is the SIZE that switches it: a target height of nought
|
||||
; is the natural height, which would be a tile sitting on the ground pretending to be sky.
|
||||
LDA.0 ; DP0 still names the bar, from working the top out above.
|
||||
SETD.0 HeightBar
|
||||
LDA.0
|
||||
BRA showHeightEmpty
|
||||
INIA 0x11
|
||||
BRI showHeightSized
|
||||
@@ -1631,7 +1663,8 @@ showHeightSized:
|
||||
SETD.0 HeightAt
|
||||
LDA.0
|
||||
OUTA 0xE9
|
||||
RSTA
|
||||
INCD.0
|
||||
LDA.0
|
||||
OUTA 0xE9 ; Y.
|
||||
SETD.0 HeightSize
|
||||
LDA.0
|
||||
@@ -1650,6 +1683,85 @@ showHeightSized:
|
||||
OUTA 0xE9 ; And no depth, A being nought already.
|
||||
RET
|
||||
|
||||
; ---- Two zoom levels, which the device turns out to have already had ----
|
||||
;
|
||||
; Forty columns and eighty are the same map, the same 8x8 cells and the same engine; only how
|
||||
; many of them fit on the screen differs. The map is 128 by 128 either way and the moon is
|
||||
; exactly 128 columns of it, so forty shows under a third of the moon and eighty shows nearly
|
||||
; two thirds - and the front end scales whatever it is handed up to the same window, so 320 by
|
||||
; 200 at four times and 640 by 400 at twice fill the same glass.
|
||||
;
|
||||
; THAT IS A ZOOM, and nothing in the video device had to change to get it. What has to change
|
||||
; is every screen coordinate in this program, because the middle of the screen is 160 on one
|
||||
; and 320 on the other. They all live in one block.
|
||||
setView:
|
||||
SETD.0 ViewNarrow
|
||||
SETD.1 Wide
|
||||
LDA.1
|
||||
BRA setViewFrom
|
||||
SETD.0 ViewWide
|
||||
setViewFrom:
|
||||
SETD.1 View
|
||||
INIA 0d15
|
||||
SETD.2 ViewLeft
|
||||
STA.2
|
||||
setViewByte:
|
||||
LDA.0
|
||||
STA.1
|
||||
INCD.0
|
||||
INCD.1
|
||||
SETD.2 ViewLeft
|
||||
LDA.2
|
||||
DECA
|
||||
STA.2
|
||||
BNA setViewByte
|
||||
RET
|
||||
|
||||
; ---- Out for the orbit, in for the landing ----
|
||||
;
|
||||
; The moon is redrawn because it is filled as many rows deep as the mode shows, and a moon
|
||||
; drawn 25 deep on a screen showing 50 is a moon floating over nothing. The fixed sprites go
|
||||
; again because their places moved with the middle.
|
||||
toggleView:
|
||||
SETD.0 Wide
|
||||
LDA.0
|
||||
INIB 0x01
|
||||
XOR
|
||||
STQ.0
|
||||
CALL setView
|
||||
SETD.0 Wide
|
||||
LDA.0
|
||||
OUTA 0x31
|
||||
CALL drawMoon
|
||||
CALL putLander
|
||||
CALL putGauge
|
||||
CALL putOrbital
|
||||
RET
|
||||
|
||||
; ---- One press, one swap ----
|
||||
;
|
||||
; A pad is LEVEL and not an event: it says what is held NOW, sixty times a second. A view that
|
||||
; swapped whenever B was down would swap sixty times a second, which is not a zoom, it is a
|
||||
; strobe. So the swap happens on the frame the button goes down, and the frame it comes up is
|
||||
; remembered for the comparison rather than acted on.
|
||||
zoomButton:
|
||||
SETD.0 Held
|
||||
LDA.0
|
||||
INIB 0x20 ; B.
|
||||
AND
|
||||
MVQA
|
||||
SETD.1 ZoomWas
|
||||
LDB.1
|
||||
STA.1 ; Now becomes what "last frame" means next time round.
|
||||
CCF
|
||||
SUB
|
||||
BRQ zoomDone ; The same as last frame, so nothing has been pressed or let go.
|
||||
LDA.1 ; DP1 still names it, and it now holds this frame's answer.
|
||||
BRA zoomDone ; It changed to NOT held, which is the release and not the press.
|
||||
CALL toggleView
|
||||
zoomDone:
|
||||
RET
|
||||
|
||||
; ---- Where orbital speed is, marked on the drift bar ----
|
||||
;
|
||||
; The bar says how fast sideways and the physics says 64 sixteenths is the speed at which the
|
||||
@@ -1667,28 +1779,54 @@ showHeightSized:
|
||||
;
|
||||
; Written once. They never move, and a sprite table is a memory rather than a display list.
|
||||
putOrbital:
|
||||
; The leftward mark: sixty four back from the middle, and two more for its own width, so the
|
||||
; bar's leading edge meets it rather than the bar covering it up.
|
||||
SETD.0 MiddleX
|
||||
LDA.0
|
||||
INIB 0d66
|
||||
CCF
|
||||
SUB
|
||||
SETD.1 MarkAt
|
||||
STQ.1
|
||||
INCD.0
|
||||
LDA.0
|
||||
RSTB
|
||||
SUB ; And the borrow, because the middle can be 320.
|
||||
INCD.1
|
||||
STQ.1
|
||||
INIA 0d4
|
||||
OUTA 0xE3
|
||||
INIA 0xC0
|
||||
OUTA 0xE4
|
||||
INIA 0x40
|
||||
OUTA 0xE5 ; Sprite four begins sixty four bytes in.
|
||||
INIA 0d94
|
||||
CALL putMark
|
||||
|
||||
; And the rightward one, sixty four on from it.
|
||||
SETD.0 MiddleX
|
||||
LDA.0
|
||||
INIB 0d64
|
||||
CCF
|
||||
ADD
|
||||
SETD.1 MarkAt
|
||||
STQ.1
|
||||
INCD.0
|
||||
LDA.0
|
||||
RSTB
|
||||
ADD
|
||||
INCD.1
|
||||
STQ.1
|
||||
INIA 0d4
|
||||
OUTA 0xE3
|
||||
INIA 0xC0
|
||||
OUTA 0xE4
|
||||
INIA 0x50
|
||||
OUTA 0xE5 ; And sprite five, sixteen bytes after it.
|
||||
INIA 0d224
|
||||
CALL putMark
|
||||
RET
|
||||
|
||||
; One mark, at the screen column in A, straddling the drift bar so the bar meets it end on.
|
||||
; One mark, at the column in MarkAt, straddling the drift bar so the bar meets it end on.
|
||||
putMark:
|
||||
SETD.1 MarkAt
|
||||
STA.1
|
||||
INIA 0xC8
|
||||
OUTA 0xE9 ; The solid block, which is what every bar here is made of.
|
||||
INIA 0x05
|
||||
@@ -1696,14 +1834,23 @@ putMark:
|
||||
; White was the first choice and white is what TEXT is, so the
|
||||
; ceiling check - which counts white to find its warning - started
|
||||
; counting these instead and read a warning that was never up.
|
||||
LDA.1 ; DP1 still names it, from being handed it above.
|
||||
SETD.1 MarkAt
|
||||
LDA.1
|
||||
OUTA 0xE9
|
||||
RSTA
|
||||
INCD.1
|
||||
LDA.1
|
||||
OUTA 0xE9 ; X.
|
||||
INIA 0d184
|
||||
OUTA 0xE9
|
||||
RSTA
|
||||
OUTA 0xE9 ; Y, four pixels above the bar it brackets.
|
||||
SETD.0 BarY
|
||||
LDA.0
|
||||
INIB 0d4
|
||||
CCF
|
||||
SUB
|
||||
OUTQ 0xE9
|
||||
INCD.0
|
||||
LDA.0
|
||||
RSTB
|
||||
SUB
|
||||
OUTQ 0xE9 ; Y, four pixels above the bar it brackets.
|
||||
INIA 0x11
|
||||
OUTA 0xE9 ; One tile by one, however small it ends up drawn.
|
||||
RSTA
|
||||
@@ -1786,7 +1933,8 @@ sayNext:
|
||||
LDA.1
|
||||
INCA
|
||||
STA.1
|
||||
INIB 0d40
|
||||
SETD.2 RowCells
|
||||
LDB.2
|
||||
CCF
|
||||
SUB
|
||||
BNQ sayCell
|
||||
@@ -1920,7 +2068,8 @@ fallBarSized:
|
||||
STA.1
|
||||
|
||||
; Where it starts: the middle going down, and that much back going up.
|
||||
INIA 0d100
|
||||
SETD.0 MiddleY
|
||||
LDA.0
|
||||
SETD.0 DriftLeftward
|
||||
LDB.0
|
||||
BRB fallBarAt ; Nought is downward, so it starts at the middle.
|
||||
@@ -1944,10 +2093,12 @@ fallBarAt:
|
||||
SETD.0 FallColour
|
||||
LDA.0
|
||||
OUTA 0xE9
|
||||
INIA 0x2C
|
||||
SETD.0 FallX
|
||||
LDA.0
|
||||
OUTA 0xE9
|
||||
INIA 0x01
|
||||
OUTA 0xE9 ; X is 300, which is two bytes: the screen is wider than one.
|
||||
INCD.0
|
||||
LDA.0
|
||||
OUTA 0xE9 ; X, in two bytes, because the screen is wider than one.
|
||||
SETD.0 FallAt
|
||||
LDA.0
|
||||
OUTA 0xE9
|
||||
@@ -2139,7 +2290,7 @@ DriftHigh:
|
||||
DriftLeftward:
|
||||
0x00
|
||||
DriftAt:
|
||||
0x00
|
||||
0x00 0x00
|
||||
DriftSize:
|
||||
0x00
|
||||
DriftColour:
|
||||
@@ -2175,8 +2326,65 @@ GentleDown:
|
||||
0d12
|
||||
GentleAcross:
|
||||
0d8
|
||||
; ---- The numbers that change when the screen does ----
|
||||
;
|
||||
; Copied over from whichever table below matches the mode, so a gauge reads a variable and
|
||||
; never has to know which screen it is drawing on. The order here and in both tables is the
|
||||
; same order and has to stay that way: setView copies the block straight across.
|
||||
View:
|
||||
HalfScreen:
|
||||
0xA0 0x00 ; 160 pixels, which is half of a forty column screen.
|
||||
0xA0 0x00
|
||||
ShipX:
|
||||
0x9C 0x00
|
||||
MiddleX:
|
||||
0xA0 0x00
|
||||
BarY:
|
||||
0xBC 0x00
|
||||
FallX:
|
||||
0x2C 0x01
|
||||
MiddleY:
|
||||
0d100
|
||||
HeightFoot:
|
||||
0xB4 0x00
|
||||
RowCells:
|
||||
0d40
|
||||
MoonRows:
|
||||
0d25
|
||||
ViewLeft:
|
||||
0x00 ; How much of the block is still to copy.
|
||||
|
||||
; Forty columns: 320 by 200, and the moon 25 rows deep because that is all there is to see.
|
||||
ViewNarrow:
|
||||
0xA0 0x00 ; Half a screen, which is where the lander is held.
|
||||
0x9C 0x00 ; And the lander itself, half a tile back from it.
|
||||
0xA0 0x00 ; The middle, where both bars start.
|
||||
0xBC 0x00 ; The drift bar's row, twelve pixels off the bottom.
|
||||
0x2C 0x01 ; The fall bar's column, twenty pixels in from the right.
|
||||
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.
|
||||
|
||||
; 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
|
||||
; less the same margin - a panel should sit the same distance in whichever screen it is on.
|
||||
ViewWide:
|
||||
0x40 0x01 ; 320.
|
||||
0x3C 0x01 ; 316.
|
||||
0x40 0x01 ; 320.
|
||||
0x84 0x01 ; 388, which is twelve off the bottom of four hundred.
|
||||
0x6C 0x02 ; 620, twenty in from the right of six hundred and forty.
|
||||
0d200
|
||||
0x7C 0x01 ; 380.
|
||||
0d80
|
||||
0d50
|
||||
|
||||
; Which of the two is up. Nought is forty columns, which is what the program starts in.
|
||||
Wide:
|
||||
0x00
|
||||
; What B was doing last frame, because a pad says what is held and not what was pressed.
|
||||
ZoomWas:
|
||||
0x00
|
||||
|
||||
PixelLow:
|
||||
0x00
|
||||
@@ -2252,11 +2460,11 @@ HeightHigh:
|
||||
HeightBar:
|
||||
0x00
|
||||
HeightAt:
|
||||
0x00
|
||||
0x00 0x00
|
||||
HeightSize:
|
||||
0x00
|
||||
MarkAt:
|
||||
0x00
|
||||
0x00 0x00
|
||||
Outward:
|
||||
0x00
|
||||
Lift:
|
||||
|
||||
@@ -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. And going sideways lifts the moon off you: at four pixels a frame the surface falls away as fast as the lander falls towards it, and gravity stops arriving. 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 gravity brings it back. What kills you out here is running dry a long way from the ground. |
|
||||
| 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 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. |
|
||||
| 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 4968
|
||||
Lander.sbx 5291
|
||||
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 4968
|
||||
Lander.sbx 5291
|
||||
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 4968
|
||||
Lander.sbx 5291
|
||||
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 4968
|
||||
Lander.sbx 5291
|
||||
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 4968
|
||||
Lander.sbx 5291
|
||||
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 4968
|
||||
Lander.sbx 5291
|
||||
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 4968
|
||||
Lander.sbx 5291
|
||||
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 4968
|
||||
Lander.sbx 5291
|
||||
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 4968
|
||||
Lander.sbx 5291
|
||||
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 4968
|
||||
Lander.sbx 5291
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -2032,6 +2032,71 @@ EOT
|
||||
&& result ok "orbital speed is marked on the drift bar" "64 pixels either side of the middle" \
|
||||
|| result no "orbital speed is marked on the drift bar" "marks at $MARKS"
|
||||
|
||||
# ---- Two zoom levels, on a button ----
|
||||
#
|
||||
# Forty columns and eighty are the same map, the same 8x8 cells and the same engine - and the
|
||||
# front end scales whatever it is handed up to the same window, so 320 by 200 and 640 by 400
|
||||
# fill the same glass. THE MODES ARE ALREADY A ZOOM, and nothing in the video device had to
|
||||
# change to get one. What had to change is every screen coordinate in Lander, because the
|
||||
# middle of the screen is 160 on one and 320 on the other.
|
||||
#
|
||||
# So the check is that the whole panel MOVED WITH THE MIDDLE and none of it stayed behind: the
|
||||
# lander at the centre of whichever screen it is on, and the orbital marks still 64 pixels
|
||||
# either side of that centre. A check on the picture size alone would pass with the gauges
|
||||
# still huddled in the top left corner.
|
||||
#
|
||||
# The third flight HOLDS the button for three hundred frames. A pad is level and not an event,
|
||||
# so a view that swapped on the level would swap sixty times a second - and the way that shows
|
||||
# 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)"
|
||||
for view in narrow tap hold; do
|
||||
timeout 60 "$EMU" --fast --cycles 2200000 --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 NARROW WIDE HELD NSHIP WSHIP NMARKS WMARKS TAPY HELDY <<EOT
|
||||
$(python3 -c "
|
||||
def look(path):
|
||||
d = open(path, 'rb').read()
|
||||
head = d[:40].split()
|
||||
width = int(head[1])
|
||||
px = d[d.index(b'255\n') + 4:]
|
||||
def where(colour):
|
||||
c = bytes.fromhex(colour)
|
||||
return [(i % width, i // width) for i in range(len(px) // 3)
|
||||
if px[i * 3:i * 3 + 3] == c]
|
||||
ship = where('d8c048')
|
||||
marks = sorted(set(x for x, y in where('c860c0') if x > 25))
|
||||
return (width,
|
||||
'%d-%d' % (min(x for x, y in ship), max(x for x, y in ship)) if ship else 'none',
|
||||
','.join(str(x) for x in marks) or 'none',
|
||||
min(y for x, y in ship) if ship else -1)
|
||||
n = look('$BUILD/narrow.ppm'); w = look('$BUILD/tap.ppm'); h = look('$BUILD/hold.ppm')
|
||||
print(n[0], w[0], h[0], n[1], w[1], n[2], w[2], w[3], h[3])
|
||||
" 2>/dev/null || echo "0 0 0 none none none none -1 -2")
|
||||
EOT
|
||||
[ "$NARROW" = "320" ] && [ "$WIDE" = "640" ] \
|
||||
&& result ok "B swaps forty columns for eighty" "320 across, then 640 of the same map" \
|
||||
|| result no "B swaps forty columns for eighty" "$NARROW then $WIDE"
|
||||
# Forty pixels of lander in both, so none of it is clipped, and centred in both, so the whole
|
||||
# panel moved rather than the picture merely getting bigger around it.
|
||||
[ "$NSHIP" = "156-163" ] && [ "$WSHIP" = "316-323" ] \
|
||||
&& result ok "and the lander is centred in either" "156 on the narrow one, 316 on the wide" \
|
||||
|| result no "and the lander is centred in either" "$NSHIP then $WSHIP"
|
||||
[ "$NMARKS" = "94,95,224,225" ] && [ "$WMARKS" = "254,255,384,385" ] \
|
||||
&& result ok "and orbital speed is still 64 either side" "the marks moved with the middle" \
|
||||
|| result no "and orbital speed is still 64 either side" "$NMARKS then $WMARKS"
|
||||
# One press is one swap. A level triggered one would flip every frame and redraw the moon
|
||||
# every frame with it, which costs about a frame and a half each time: the lander would be
|
||||
# somewhere else entirely by now.
|
||||
[ "$TAPY" = "$HELDY" ] && [ "$HELD" = "640" ] \
|
||||
&& 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"
|
||||
|
||||
# ---- 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