A crash takes the lander apart, instead of just saying so

The verdict used to be the whole of it: a line of text and a lander still
sitting there in one piece, so somebody watching a recording had to read
the words to know what had happened. That is the same problem the flames
were for.

The lander goes, and both flames with it, and six pieces of it leave in a
rough hexagon at its own colour for about a second. Then they go too,
rather than hanging over the words. The world is not running while it
plays: it is a loop of its own, so nothing else in the program has to
know how to be half destroyed.

Yellow, which is the lander's own colour, because it IS the lander - and
it is only free to use because the lander itself is hidden by then. The
check that counts exactly forty pixels of yellow looks at a flying frame.

---- Two mistakes worth keeping ----

The block went in between touchdownCrash and touchdownStop, so a crash
fell into the explosion and returned from there - no verdict, no end of
run, and the lander sitting there being crashed into the ground again
every frame. The linter caught it as a subroutine nothing called walking
into, which is exactly what it was.

And copyWord goes DP0 to DP1, so setting the pieces off from the lander's
position had the pointers the wrong way round: it copied the empty pieces
OVER ShipX. Since that is in the view block, it took the lander's own
column with it, and the one piece that could be seen drifted out of the
top left corner of the screen.

Three checks, each seen to fail on its own break. They measure the SPREAD
and not the count: two of the six leave the top of the screen on the way,
so the count drops from twenty four to sixteen, which is correct and
would make an exact count a check that breaks the day a lander crashes
somewhere else.
This commit is contained in:
Anachronaut
2026-09-04 12:06:00 -04:00
parent c408fc6cf6
commit 115efa1fa1
13 changed files with 289 additions and 11 deletions
+220
View File
@@ -1826,6 +1826,7 @@ touchdown:
touchdownCrash:
SETD.0 CrashedText
touchdownStop:
CALL explode ; Before the verdict, so there is something to watch.
; ---- The view settled before anything is said ----
;
; The console draws into the map, and the map is what is being scrolled - so a message
@@ -2321,6 +2322,201 @@ putFlame:
OUTA 0xE9 ; And no depth.
RET
; ---- Coming apart, which is the only thing on this screen that is not a number ----
;
; A crash used to be a line of text and a lander still sitting there in one piece. The verdict
; was the whole of it, and somebody watching a recording had to read the words to know what had
; happened - the same problem the flames were for.
;
; The lander goes and six pieces of it leave in a rough hexagon, at its own colour, for half a
; second. The world is not running while this happens: it is a loop of its own, so nothing has
; to know how to be half destroyed.
explode:
RSTA
CALL hideSprite ; The lander itself.
INIA 0x70
CALL hideSprite
INIA 0x80
CALL hideSprite ; And both flames, which would otherwise hang in the air.
; Every piece starts where the lander was.
RSTA
SETD.0 SparkAt
STA.0
INIA 0d6
SETD.0 SparkCount
STA.0
explodeStart:
; DP0 is what copyWord reads and DP1 what it writes, so the lander's place is DP0. Written
; the other way round first, which copied the empty sparks OVER ShipX - and since that is
; the view block, the lander's own column with it.
SETD.0 ShipX
SETD.1 Spark
SETD.2 SparkAt
LDA.2
DPUA.1
CALL copyWord
SETD.0 ShipTopLow
SETD.1 Spark
SETD.2 SparkAt
LDA.2
INCA
INCA
DPUA.1
CALL copyWord
SETD.0 SparkAt
LDA.0
INIB 0d4
CCF
ADD
STQ.0
SETD.0 SparkCount
LDA.0
DECA
STA.0
BNA explodeStart
INIA 0d48
SETD.0 SparkLeft
STA.0 ; Getting on for a second, which is long enough to watch.
explodeFrame:
CALL waitFrame
RSTA
SETD.0 SparkAt
STA.0
INIA 0x90
SETD.0 SparkSlot
STA.0
INIA 0d6
SETD.0 SparkCount
STA.0
explodeOne:
SETD.0 Spark
SETD.2 SparkAt
LDA.2
DPUA.0
SETD.1 SparkV
DPUA.1
CALL addWord ; Across, by however fast this piece is going.
SETD.0 Spark
SETD.2 SparkAt
LDA.2
INCA
INCA
DPUA.0
SETD.1 SparkV
DPUA.1
CALL addWord ; And down.
CALL putSpark
SETD.0 SparkAt
LDA.0
INIB 0d4
CCF
ADD
STQ.0
SETD.0 SparkSlot
LDA.0
INIB 0x10
CCF
ADD
STQ.0
SETD.0 SparkCount
LDA.0
DECA
STA.0
BNA explodeOne
SETD.0 SparkLeft
LDA.0
DECA
STA.0
BNA explodeFrame
; And away, or they would sit there under the verdict.
INIA 0x90
SETD.0 SparkSlot
STA.0
INIA 0d6
SETD.0 SparkCount
STA.0
explodeClear:
SETD.0 SparkSlot
LDA.0
CALL hideSprite
SETD.0 SparkSlot
LDA.0
INIB 0x10
CCF
ADD
STQ.0
SETD.0 SparkCount
LDA.0
DECA
STA.0
BNA explodeClear
RET
; One piece, where the pointers say it now is.
putSpark:
INIA 0d4
OUTA 0xE3
INIA 0xC0
OUTA 0xE4
SETD.0 SparkSlot
LDA.0
OUTA 0xE5
INIA 0xC8
OUTA 0xE9 ; The solid block, at two pixels by two.
INIA 0x03
OUTA 0xE9 ; Yellow: it is the lander that is coming apart.
SETD.0 Spark
SETD.2 SparkAt
LDA.2
DPUA.0
LDA.0
OUTA 0xE9
INCD.0
LDA.0
OUTA 0xE9
INCD.0
LDA.0
OUTA 0xE9
INCD.0
LDA.0
OUTA 0xE9 ; Across and down, four bytes in a row of them.
INIA 0x11
OUTA 0xE9
RSTA
OUTA 0xE9 ; No flags.
INIA 0d2
OUTA 0xE9
RSTA
OUTA 0xE9
INIA 0d2
OUTA 0xE9
RSTA
OUTA 0xE9 ; Two by two, which is a piece and not a lander.
OUTA 0xE9 ; And no depth.
RET
; Byte six of a sprite is its size, and nought there is the off switch.
hideSprite:
SETD.0 HideSlot
STA.0
INIA 0d4
OUTA 0xE3
INIA 0xC0
OUTA 0xE4
LDA.0
INIB 0d6
CCF
ADD
OUTQ 0xE5
RSTA
OUTA 0xE9
RET
; ---- A key, or a button ----
;
; Somebody flying on a controller should not have to reach for the keyboard to say "yes, I
@@ -3437,6 +3633,30 @@ ShipTopLow:
ShipTopHigh:
0x00
; ---- Six pieces of lander, and where each is going ----
;
; Interleaved, four bytes to a piece: where it is across, then where it is down. The speeds
; beside them are a rough hexagon, so it comes apart evenly rather than in a line.
Spark:
#Reserve 0d24
SparkV:
0x02 0x00 0x00 0x00
0x01 0x00 0x02 0x00
0xFF 0xFF 0x02 0x00
0xFE 0xFF 0x00 0x00
0xFF 0xFF 0xFE 0xFF
0x01 0x00 0xFE 0xFF
SparkAt:
0x00
SparkSlot:
0x00
SparkCount:
0x00
SparkLeft:
0x00
HideSlot:
0x00
; What a flame is being asked to be, before it is written out.
FlameSlot:
0x00