Dust on landing, gas on letting go, and a lander that stays let go
One particle system, three uses now: a lander coming apart, dust kicked up by a landing, and gas out of a docking port on release. Where they start, how fast they go, what colour they are and how long they last are arguments; everything else is shared. Dust goes sideways and UP off the lander's feet, because that is where kicked dust goes and there is ground in the way of the rest of it. Gas goes evenly in every direction, because nothing is in the way of a docking port. Neither happens on docking - a dock is a catch and not a touchdown, and there is nothing under it to kick. ---- Ticked from the frame loop, not run in place ---- The explosion can afford to stop the world; there is nothing left to fly. The undocking puff cannot, because it goes off on the frame a thruster is pressed, and freezing a quarter of a second exactly then is felt as the controls sticking. So a burst advances one frame at a time from the main loop, and the two that can afford to wait just pump that same tick until the air is clear. ---- And letting go did not let go ---- Which the puff is what found. A docked lander sits EXACTLY one tile under the station, so releasing upwards moved it towards the station and it docked again on the very next frame: took the fuel again, said so again, and waited to be told the message had been read - which reads as the controls locking up the instant they are used. It has to get clear now before it can take hold again, and the two distances have to differ: docking wants one tile, re-arming wants two. A single distance re-armed on the frame it let go, because a tile is exactly where it was sitting. Three checks, each seen to fail on its own break. The last of them measures HOW FAR the lander has got and not merely that it moved: a sixteen frame pause on release still leaves it climbing, four rows short of a free run, so "it moved" would pass for a stall that has been slept through.
This commit is contained in:
@@ -25,7 +25,7 @@ Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Lander.sbx 7913
|
||||
Lander.sbx 8243
|
||||
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 7913
|
||||
Lander.sbx 8243
|
||||
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 7913
|
||||
Lander.sbx 8243
|
||||
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 7913
|
||||
Lander.sbx 8243
|
||||
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 7913
|
||||
Lander.sbx 8243
|
||||
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 7913
|
||||
Lander.sbx 8243
|
||||
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 7913
|
||||
Lander.sbx 8243
|
||||
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 7913
|
||||
Lander.sbx 8243
|
||||
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 7913
|
||||
Lander.sbx 8243
|
||||
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 7913
|
||||
Lander.sbx 8243
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
|
||||
@@ -2661,6 +2661,83 @@ EOT
|
||||
&& result ok "and are gone before the verdict" "nothing left over the words" \
|
||||
|| result no "and are gone before the verdict" "$AFTERBITS pixels still there"
|
||||
|
||||
# ---- Dust on landing, and gas on letting go ----
|
||||
#
|
||||
# The same six pieces as the explosion, thrown differently: dust goes sideways and UP off the
|
||||
# lander's feet, because that is where kicked dust goes and there is ground in the way of the
|
||||
# rest of it; gas goes evenly in every direction, because nothing is in the way of a docking
|
||||
# port. Neither happens on DOCKING - a dock is a catch, not a touchdown, and there is nothing
|
||||
# under it to kick.
|
||||
#
|
||||
# ---- The gas is the one that must not stop the world ----
|
||||
#
|
||||
# It goes off on the frame a thruster is pressed. The explosion can afford to hold everything
|
||||
# still, because there is nothing left to fly; freezing a quarter of a second exactly as the
|
||||
# controls are used would be felt as them sticking. So the check watches the LANDER MOVE while
|
||||
# the gas has gone, and how FAR it has got by then.
|
||||
python3 -c "
|
||||
import struct
|
||||
open('$BUILD/undock.state','wb').write(struct.pack('<hhhhhhBBBB',
|
||||
0x34A0 - 64, -1536 + 64, 64, 0, 0x34A0, -1536, 100, 1, 0, 0))
|
||||
"
|
||||
cp "$ROOT/Tests/build/disks/cosmos.img" "$BUILD/undock.img"
|
||||
"$ROOT/SplitDisk" put "$BUILD/undock.img" "$BUILD/undock.state" /lander.state > /dev/null
|
||||
# Acknowledge the dock at frame 400, then hold up from 600 to let go of it.
|
||||
python3 -c "open('$BUILD/undock.pad','wb').write(b'\x00' * 400 + b'\x10' * 8 + b'\x00' * 192 + b'\x08' * 4000 + b'\x00' * 20000)"
|
||||
for when in 9900000 10150000 10800000; do
|
||||
timeout 60 "$EMU" --fast --cycles $when --keyboard "$BUILD/fly.keys" \
|
||||
--pad "$BUILD/undock.pad" --screen "$BUILD/gas$when.ppm" \
|
||||
--disk "$BUILD/undock.img" --ram-disk 2048 \
|
||||
"$BUILD/cosmos.bin" > "$BUILD/gas.out" 2>&1 || true
|
||||
done
|
||||
# And a plain fall onto the pad it starts over, which lands rather than crashes.
|
||||
for when in 2700000 2820000 3100000; do
|
||||
timeout 60 "$EMU" --fast --cycles $when --keyboard "$BUILD/fly.keys" \
|
||||
--pad "$BUILD/none.pad" --screen "$BUILD/dust$when.ppm" \
|
||||
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
|
||||
"$BUILD/cosmos.bin" > "$BUILD/dust.out" 2>&1 || true
|
||||
done
|
||||
read -r DUSTBEFORE DUSTDURING DUSTAFTER GASBEFORE GASDURING GASAFTER SHIPHELD SHIPFREE <<EOT
|
||||
$(python3 -c "
|
||||
def look(path):
|
||||
d = open(path, 'rb').read()
|
||||
width = int(d[:40].split()[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]
|
||||
# White BELOW THE WINDOW. The window's own text is white and sits in the top two rows.
|
||||
puff = len([1 for x, y in where('f0f0f0') if y > 20])
|
||||
ship = where('d8c048')
|
||||
return puff, (min(y for x, y in ship) if ship else -1)
|
||||
print(look('$BUILD/dust2700000.ppm')[0], look('$BUILD/dust2820000.ppm')[0],
|
||||
look('$BUILD/dust3100000.ppm')[0],
|
||||
look('$BUILD/gas9900000.ppm')[0], look('$BUILD/gas10150000.ppm')[0],
|
||||
look('$BUILD/gas10800000.ppm')[0],
|
||||
look('$BUILD/gas10150000.ppm')[1], look('$BUILD/gas10800000.ppm')[1])
|
||||
" 2>/dev/null || echo "-1 -1 -1 -1 -1 -1 -1 -1")
|
||||
EOT
|
||||
[ "$DUSTBEFORE" = "0" ] && [ "$DUSTDURING" -gt 0 ] && [ "$DUSTAFTER" = "0" ] \
|
||||
&& result ok "a landing kicks up dust" "none, then $DUSTDURING pixels of it, then none" \
|
||||
|| result no "a landing kicks up dust" "$DUSTBEFORE before, $DUSTDURING during, $DUSTAFTER after"
|
||||
[ "$GASBEFORE" = "0" ] && [ "$GASDURING" -gt 0 ] && [ "$GASAFTER" = "0" ] \
|
||||
&& result ok "and letting go of the station vents gas" "none, then $GASDURING pixels, then none" \
|
||||
|| result no "and letting go of the station vents gas" "$GASBEFORE before, $GASDURING during, $GASAFTER after"
|
||||
# ---- Which is the half that matters ----
|
||||
#
|
||||
# The lander has to be somewhere ELSE by the time the gas has gone. If letting go froze the
|
||||
# world it would still be at the row it undocked from - and so would it if the lander re-docked
|
||||
# on the next frame, which is what happened before a lander had to get clear of the station
|
||||
# before it could take hold of it again: it took the fuel again, said so again, and sat waiting
|
||||
# to be told the message had been read.
|
||||
# HOW FAR it has got, not merely that it moved. Twelve rows is what a free run manages by
|
||||
# then; a sixteen frame pause on letting go still leaves it climbing, just four rows short - so
|
||||
# "it moved" passes for a stall that has been slept through and this does not.
|
||||
[ "$SHIPFREE" -gt 0 ] && [ "$(( SHIPHELD - SHIPFREE ))" -ge 8 ] \
|
||||
&& result ok "and the lander is well away, not merely moving" "row $SHIPHELD became row $SHIPFREE" \
|
||||
|| result no "and the lander is well away, not merely moving" "row $SHIPHELD, then row $SHIPFREE"
|
||||
|
||||
# ---- 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