Landing pads, carved rather than looked for
A random walk does not leave flat ground and a lander wants some. Four pads are cut into the moon after it is generated, each four columns levelled to whatever height its first column happened to have - so they sit in the landscape rather than on a shelf above it. The moon decides where they are; this only decides that they are flat. Searching for flat spots was the alternative and it can fail, which means a fallback that carves anyway - the carving, plus a search nobody needed. They are marked by an ATTRIBUTE and not a tile of their own, which costs no art at all: a nibble is added to every index in a tile, so one solid block is grey moon or a cyan pad depending on the byte beside it. Which columns are pads is an array, because asking has to be one lookup. Four comparisons per column per row is 12,800 of them for one screen, and the landing verdict asks the same question again. THE LANDER STARTS ABOVE ONE, because that is where a porter's day begins. Starting in the middle of nowhere meant a straight descent landed in the middle of nowhere, which is a fine thing to be able to do and a poor thing to have to. That change cost the crash test its teeth, and the way it did is worth keeping. It held nothing at all and let the lander fall - and a short drop onto the high ground of the base you started above is survivable, which is correct, and left the test saying nothing. It holds Right now: lateral speed has no limit and nothing slows it, so a slide always ends badly however the rest is tuned. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
6073086584
commit
7257ad369c
@@ -68,6 +68,7 @@ start:
|
||||
|
||||
CALL putTiles
|
||||
CALL makeMoon
|
||||
CALL carvePads
|
||||
CALL drawMoon
|
||||
CALL putLander
|
||||
CALL putGauge
|
||||
@@ -223,6 +224,73 @@ makeNext:
|
||||
BNQ makeColumn
|
||||
RET
|
||||
|
||||
; ---- Somewhere to put it down ----
|
||||
;
|
||||
; A random walk does not leave flat ground, and a lander wants some. So four pads are CARVED
|
||||
; after the moon is made rather than looked for in it: searching can fail, and a fallback that
|
||||
; carves anyway is the carving plus a search nobody needed.
|
||||
;
|
||||
; Each is four columns levelled to the height the first of them happened to have, so the pads
|
||||
; sit in the landscape rather than on a shelf above it - the moon decides where they are, and
|
||||
; this only decides that they are flat.
|
||||
;
|
||||
; The columns are marked in an array of their own. Asking "is this a pad" while drawing has to
|
||||
; be one lookup: four comparisons per column per row is 12,800 of them for a screen.
|
||||
carvePads:
|
||||
SETD.3 PadTable
|
||||
INIA 0d4
|
||||
SETD.1 PadsLeft
|
||||
STA.1
|
||||
|
||||
carveOne:
|
||||
; The height this pad is levelled to, which is whatever its first column already was.
|
||||
LDA.3
|
||||
SETD.1 Terrain
|
||||
DPUA.1
|
||||
LDA.1
|
||||
SETD.1 PadHeight
|
||||
STA.1
|
||||
|
||||
RSTA
|
||||
SETD.1 PadWide
|
||||
STA.1
|
||||
carveColumn:
|
||||
; This column of the pad: levelled, and marked as somewhere to land.
|
||||
LDA.3
|
||||
SETD.1 PadWide
|
||||
LDB.1
|
||||
CCF
|
||||
ADD
|
||||
MVQA ; The pad's first column plus how far along this is.
|
||||
PSHA
|
||||
SETD.1 Terrain
|
||||
DPUA.1
|
||||
SETD.0 PadHeight
|
||||
LDA.0
|
||||
STA.1
|
||||
POPA
|
||||
SETD.1 IsPad
|
||||
DPUA.1
|
||||
INIA 0x01
|
||||
STA.1
|
||||
|
||||
SETD.1 PadWide
|
||||
LDA.1
|
||||
INCA
|
||||
STA.1
|
||||
INIB 0d4
|
||||
CCF
|
||||
SUB
|
||||
BNQ carveColumn
|
||||
|
||||
INCD.3
|
||||
SETD.1 PadsLeft
|
||||
LDA.1
|
||||
DECA
|
||||
STA.1
|
||||
BNA carveOne
|
||||
RET
|
||||
|
||||
; The shift register. Q comes back the new value, because Q is what survives a RET.
|
||||
nextRandom:
|
||||
SETD.1 Seed
|
||||
@@ -284,11 +352,31 @@ drawCell:
|
||||
CCF
|
||||
SUB
|
||||
BRC drawSky ; Borrowed: this row is above the surface, so it is sky.
|
||||
BRQ drawSurface ; Equal: this row IS the surface, which may be somewhere to land.
|
||||
drawGround:
|
||||
INIA 0xC8
|
||||
OUTA 0xE9 ; Tile 200, the ground block.
|
||||
RSTA
|
||||
OUTA 0xE9 ; Attribute nought: grey on black, which is a fine moon.
|
||||
BRI drawNextCell
|
||||
|
||||
; ---- The top of a pad, in a colour that says so ----
|
||||
;
|
||||
; The same solid tile in a different scheme, which costs no art at all: an attribute is a
|
||||
; nibble added to every index in the tile, so one block is a grey moon and a cyan landing pad
|
||||
; depending on the byte beside it.
|
||||
drawSurface:
|
||||
SETD.1 IsPad
|
||||
SETD.0 Column
|
||||
LDA.0
|
||||
DPUA.1
|
||||
LDA.1
|
||||
BRA drawGround ; Not a pad, so it is ordinary moon.
|
||||
INIA 0xC8
|
||||
OUTA 0xE9
|
||||
INIA 0x06
|
||||
OUTA 0xE9 ; Scheme six, which is cyan against everything else out there.
|
||||
BRI drawNextCell
|
||||
drawSky:
|
||||
RSTA ; A is still this column's height, from the comparison above.
|
||||
OUTA 0xE9
|
||||
@@ -850,6 +938,8 @@ touchdown:
|
||||
INIB 0x7F
|
||||
AND ; The moon is 128 columns, so seven bits of it.
|
||||
MVQA
|
||||
SETD.1 LandColumn
|
||||
STA.1 ; Kept, because the verdict below wants it too.
|
||||
SETD.1 Terrain
|
||||
DPUA.1 ; Terrain plus the column, which is the row its surface is on.
|
||||
LDA.1
|
||||
@@ -920,6 +1010,20 @@ touchdown:
|
||||
SUB
|
||||
BNC touchdownCrash
|
||||
|
||||
; ---- Down safely, and whether it was anywhere useful ----
|
||||
;
|
||||
; A pad is where a base is, and the rest of the moon is somewhere a lander can survive
|
||||
; arriving at and do nothing about. The difference is one lookup, because the carving wrote
|
||||
; an array rather than leaving four comparisons to be done again here.
|
||||
SETD.1 IsPad
|
||||
SETD.0 LandColumn
|
||||
LDA.0
|
||||
DPUA.1
|
||||
LDA.1
|
||||
BRA touchdownNowhere
|
||||
SETD.0 AtBaseText
|
||||
BRI touchdownStop
|
||||
touchdownNowhere:
|
||||
SETD.0 LandedText
|
||||
BRI touchdownStop
|
||||
touchdownCrash:
|
||||
@@ -1059,10 +1163,15 @@ waitFrame:
|
||||
#Base 0x3000
|
||||
|
||||
; Sixteenths of a pixel, low half first, because that is the order the sums above walk in.
|
||||
; ---- Which is over a base, because that is where a day starts ----
|
||||
;
|
||||
; 0x14A0 sixteenths is 330 pixels, which is column 41 - inside the pad carved at 40. Starting
|
||||
; in the middle of nowhere meant a straight descent landed in the middle of nowhere, which is
|
||||
; a fine thing to be able to do and a poor thing to have to.
|
||||
AcrossLow:
|
||||
0x00
|
||||
0xA0
|
||||
AcrossHigh:
|
||||
0x0F ; Somewhere near the middle of the moon to start.
|
||||
0x14
|
||||
DownLow:
|
||||
0x00
|
||||
DownHigh:
|
||||
@@ -1173,8 +1282,27 @@ Flying:
|
||||
Terrain:
|
||||
#Reserve 0d128
|
||||
|
||||
; One byte a column: whether a lander touching down there is at a base. Written by the carving
|
||||
; and read while drawing and while landing, which is the whole reason it is an array rather
|
||||
; than four comparisons done again every time somebody asks.
|
||||
IsPad:
|
||||
#Reserve 0d128
|
||||
|
||||
PadTable:
|
||||
0d8 0d40 0d72 0d104 ; Four bases, evenly round a moon 128 columns about.
|
||||
PadsLeft:
|
||||
0x00
|
||||
PadWide:
|
||||
0x00
|
||||
PadHeight:
|
||||
0x00
|
||||
LandColumn:
|
||||
0x00
|
||||
|
||||
LandedText:
|
||||
"Down safely."
|
||||
"Down safely, in the middle of nowhere."
|
||||
AtBaseText:
|
||||
"Down safely at a base."
|
||||
CrashedText:
|
||||
"Crashed."
|
||||
|
||||
|
||||
@@ -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. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
|
||||
Reference in New Issue
Block a user