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:
Anachronaut
2026-09-03 11:45:30 -04:00
co-authored by Claude Opus 5
parent 6073086584
commit 7257ad369c
18 changed files with 171 additions and 22 deletions
+131 -3
View File
@@ -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."