joeylib2/examples/spacetaxi/assets/levels/format.md

5 KiB

Space Taxi level .dat format (STL2)

A small custom binary format that stLevelLoad() reads at scene boot. Output files land in examples/spacetaxi/generated/levels/ (from romToLevel.py for the 24 canonical C64 levels, or from mkstlevel for hand-authored levels in assets/levels/*.txt). The build copies them under DATA/levels/levelNN.dat in the runtime asset bundle. All multi-byte fields are little-endian. No compression; ~2 KB per level.

Offset Type Field
0 4 bytes magic S T L 2
4 u8 nameLen (0..23)
5 char[N] name (no NUL; max 23 chars)
5+N u8 tileBankId
... u8 musicId (UNUSED -- C64 gameplay is silent; see VERIFIED.md)
... u8 bgColor (palette slot)
... u8 borderColor (palette slot, also HUD-band fill)
... u8 taxiSpawnTileX
... u8 taxiSpawnTileY
... u8 xAccel (horizontal thrust magnitude / frame)
... u8 yAccel (vertical thrust magnitude / frame)
... i8 xGrav (constant horizontal accel; side-wind on levels P, U)
... i8 yGrav (constant vertical accel; anti-gravity on level K = -7)
... u8 bgColor1 ($D022, VIC multicolor -- UNUSED)
... u8 bgColor2 ($D023, VIC multicolor -- UNUSED)
... u8 bgColor3 ($D024, VIC multicolor -- UNUSED)
... u8 spriteMc0 ($D025, sprite multicolor -- UNUSED)
... u8 spriteMc1 ($D026, sprite multicolor -- UNUSED)
... u8 sprite0Color ($D027, cab fallback color)
... u8 sprite1Color ($D028, flame fallback color)
... u8 padCount (0..10)
... pad[] padCount * 4 bytes: letter, tileX, tileY, tileW
... u8 fareCount (0..16)
... fare[] fareCount * 2 bytes: spawnPad, destPad
... u8[40*25] tilemap (row-major, full 25 rows)
... u8[40*25] colormap (row-major, palette slot per cell)

Notes:

  • xAccel/yAccel/xGrav/yGrav mirror the C64 per-level templates at $7D8F-$7D96. Side-wind levels P (xGrav = +4) and U (+2); the anti-gravity level K (yGrav = -7) makes the cab drift upward without input. See VERIFIED.md for the emulator-traced extracts.
  • musicId is preserved for format symmetry only; the C64 original has no gameplay music (only title/score-screen jingles).
  • The five VIC multicolor fields are preserved so the .dat is a faithful byte-for-byte capture of the C64 $7D00-$7D08 block. The port renders in single-color mode and ignores them at runtime.
  • Pads are 4 bytes (letter + 3 tile coords); there is no patience byte on fares -- Space Taxi proper has no patience timeout, and the emulator trace at $71CE/$7213 confirmed the only gating is the player-selectable fare target at the title screen.

Tile-index conventions (in the tilemap byte)

Indexes 0..255 reference the level's active tile bank. Reserved ranges:

Range Meaning
0 empty (sky / interior space; non-solid)
1..63 solid (walls, ceilings, support structures)
64..127 landing-pad surfaces (also solid; pad collisions live here)
128..255 decorative non-solid (lights, signs, animation frames)

The engine's isSolidAt() uses this convention. If you redesign a tile bank, keep the indexing consistent so the physics keeps working without changes.

Authoring pipeline

  1. Author a 256-tile (or smaller) tile sheet as an indexed PNG. Each tile is 8x8 px. Arrange in a grid; the bank loader assumes row- major, tile-index = ty * tilesPerRow + tx. Drop the PNG at examples/spacetaxi/assets/tiles/tbank<N>.png.
  2. The Makefile bakes per-target via tools/assetbake/assetbake.py --type tile --target <port> tbank<N>.png tbank<N>.tbk. Output lands in examples/spacetaxi/generated/<port>/tiles/ and is staged into the runtime tree at build/<port>/.../DATA/tiles/.
  3. Author each level layout in a text editor or grid tool, save as a .dat per this spec. The helper examples/spacetaxi/mkstlevel converts from a human-readable text grid to .dat. The 24 canonical C64 levels are emitted by stuff/spacetaxi/romToLevel.py directly from a raw VICE dump of the original .prg.

Naming

Use the original game's level names as the name field (uppercase ASCII, max 23 chars). The HUD displays this at the bottom-right of the screen.