Files
skids/docs/FORMATS.md
T
andy c36572f8dc Extract the track thumbnails and the ball sprite bank
- Track files: decode the selector thumbnails (a 640x64 16-colour
  picture, four sequential bitplanes, six 123x32 tiles in a 3x2 grid) into
  tracks/<name>/thumb.png, and show them in the menu at double height
  (they are Amiga hi-res)
- gfx/ball.spr: decode the 64-frame attached-sprite bank (spinning ball
  with the Acid logo) into gfx/ball.png; its colours are not in the file
- Command-line output no longer panics when piped into e.g. head
2026-10-19 20:43:34 +00:00

229 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Super Skidmarks data formats
Notes from reverse engineering the AGA/CD32 release of *Super Skidmarks*
(Acid Software, 1995), worked out from all six disks. The one thing not
yet decoded is the executable's game logic. See [Gaps](#gaps).
All multi-byte values are big-endian unless noted.
## Disks
Each disk is a standard 880 KB double-density ADF (1760 blocks of 512
bytes). Disk 1 is FFS (`DOS\1`); disks 2–6 are OFS (`DOS\0`). The `[HD]` in
the file names refers to the hard-drive-installable release.
| Disk | Archive | Game files |
|------|---------------|------------|
| 1 | `smcd32a.lha` | Executables, `sfx/`, `gfx/`, the tune, `vehicles/*.set`, `Camaro.aga`, `caravan.aga` |
| 2 | `smcd32b.lha` | `vehicles/cow.aga`, `track/TRACK1` |
| 3 | `smcd32c.lha` | `track/TRACK2`, `vehicles/TRUCK.aga` |
| 4 | `smcd32d.lha` | `track/TRACK3`, `vehicles/PORSCHE.aga` |
| 5 | `smcd32e.lha` | `track/track4`, `vehicles/vw.aga` |
| 6 | `smcd32f.lha` | `vehicles/F1.aga`, `Midget.aga`, `mini.aga`, `Police.aga` |
Disk 1 also carries an Installer script that installs from all six disks,
and a few AmigaDOS commands.
Each archive stands on its own; the set isn't one archive split across
disks. They use level-0 headers under a top-level `super_skidmarks_cd³²\`
directory.
- **Compression:** disks 2–6 store their members (`-lh0-`), which are
themselves CrunchMania-packed. Disk 1 mostly uses `-lh5-` (LZSS with
static Huffman blocks, decoded by `src/formats/lzh.rs`).
- **Integrity:** every member is checked against its header CRC-16. One
file, `c/iconx` (an AmigaDOS utility the game doesn't use), fails its CRC
in this dump. The reference `lha` tool reports the same failure.
## CrunchMania
```
0 4 id: "CrM!" (LZ + fixed codes) or "CrM2" (LZ + Huffman)
lower-case "Crm" = delta-encoded samples (running byte sum)
4 2 unused
6 4 unpacked size
10 4 packed size (excludes this 14-byte header)
14 … packed stream
```
The stream is read **backwards** from `14 + packed - 6`, a byte at a time,
LSB first. The last six bytes seed the bit buffer: a 32-bit word shifted
right by `16 - shift` with `16 + shift` valid bits, where `shift` is the
final 16-bit word. Output is also written from the end towards the start.
`src/formats/crm.rs` implements both variants. Every packed file on the
disks decodes exactly: the output buffer fills completely and the input is
consumed to its first byte.
## Tracks (`track/TRACKn`)
```
0x00 7 × u32 end offset of sections 0..6
0x1C … section 0: thumbnails and palette for the whole file (20622 bytes, raw)
… sections 1..6: one track each, CrunchMania-packed
```
So the four files hold 24 tracks.
The last 142 bytes of section 0 hold:
| Offset | Size | Contents |
|--------|------|----------|
| 0 | 2 | File number (1–4) |
| 2 | 96 | The palette shared by the file's six tracks: 16 colours × R, G, B, each a `u16` from 0 to 15 (Amiga 12-bit colour) |
| 98 | 12 | Unknown |
| 110 | … | The name of the set of tracks, NUL-terminated |
The first 20480 bytes of section 0 are the track-selector thumbnails:
- **Picture:** one 640 × 64, 16-colour picture in the file's palette,
stored as four bitplanes one after another (80 bytes per row, 5120 bytes
per plane).
- **Layout:** the six tracks' thumbnails, 123 × 32 each, sit in a 3 × 2
grid at its top left, in track order: top row tracks 1–3, bottom row
4–6.
- **Display:** the picture is Amiga hi-res, whose pixels are half as wide
as low-res ones. So a thumbnail shows at 123 × 64 next to the low-res
track pictures, the same shape as the track.
Each track section unpacks to 281240 (`0x44A98`) bytes:
| Offset | Size | Contents |
|----------|--------|----------|
| `0x0000` | 8192 | Height map: 64 × 64 `u16`, 8.8 fixed point, row-major. Each cell covers 16 × 8 screen pixels. |
| `0x2000` | 8192 | Unused, zero on every track. |
| `0x4000` | 8 | `u16` gate count, `u16` start x, `u16` start y, `u16` flags. |
| `0x4008` | 8 × n | Gates: `x1 y1 x2 y2`, world coordinates × 32. The list repeats after the last gate. |
| … | | Unknown data, mostly a bit pattern, up to `0x4A98`. |
| `0x4A98` | 4 × 65536 | Four non-interleaved 1024 × 512 bitplanes, giving 16 colours. |
### Track geometry
Gates are line segments across the road and run in race order; gate 0 is
the start/finish line. They're defined on an isometric ground plane rotated
45° to the picture. The projection that best fits the data is:
```
screen x = wx - wy + 512
screen y = (wx + wy) × 31/64 - 252
```
With these constants, 96% of points sampled along the gates land on road
pixels across all 24 tracks (92% minimum). A plain screen-aligned 2:1 squash
gives 40–70%. Adding a height term doesn't improve the fit, so the height
map is used only for slope physics and body tilt.
The stored start point is on the road for 14 of the 24 tracks read as screen
coordinates, and 10 read as world coordinates. It isn't used; the grid forms
up behind gate 0.
### Road and scenery
Colours 8–15 are the driving surface on every track, so the fourth
bitplane is effectively a road mask. Off the road means less grip and
lower speed.
## Vehicles
### Sprite banks (`vehicles/*.aga`)
CrunchMania-packed, 409600 bytes unpacked:
25 tilt blocks × 32 headings × 512-byte frames.
A frame is a 64 × 32 AGA hardware sprite. Each line holds 8 bytes of plane
0, then 8 bytes of plane 1, giving 3 colours plus transparent:
| Index | Use |
|-------|---------------------|
| 0 | transparent |
| 1 | tyres, shadow, dark |
| 2 | trim / accent |
| 3 | bodywork |
- **Heading:** frame 12 faces screen-right, and frames advance clockwise in
11.25° steps. In world terms, frame = 12 + (angle + 45°) / 11.25°.
- **Tilt:** block = roll × 5 + pitch, each in 0..4, with 2 = level. Block
12 is the car on flat ground.
The caravan (`caravan.aga`) uses the same layout. It's a trailer with a tow
bar, not a car.
`Police.aga` reads as all zeros with one third-party ADF tool, but it's
intact when read directly from the disk image.
### Settings (`vehicles/*.set`)
- **Header:** the car's name and its driver's name, each followed by a
newline.
- **Settings:** 16 `u16` values. Eleven are used by the cars; the rest are
zero. The caravan's values differ in kind; two of them are −4.
- **Menu picture:** 512 bytes. A 64 × 32 picture in two bitplanes, plane 0
(256 bytes) then plane 1.
The settings are clearly handling values. The first is smallest for the
Cow, the second largest for the F1, and the Police car and Porsche are
nearly identical. What each one means lives in the executable and isn't
decoded yet.
## Sounds (`sfx/*.iff`, `gfx/*.iff`)
Uncompressed IFF 8SVX, 8-bit signed, mostly at Amiga rates (8363 Hz and
others). Looping sounds use the repeat part of `VHDR`. `gfx/` holds a few
extra and alternative sounds (`crash1`, `crash2`, `engine`, `motor`,
`screech`); `gfx/crash4.iff` isn't IFF.
## Pictures (`gfx/*.iff`)
IFF ILBM with ByteRun1 compression. `skidtoon.iff` is the 608 × 180,
16-colour title picture; `chat2`, `mouse` and `sign` are small odds and
ends.
`ball.spr` is a bank of 64 saved hardware sprites: a spinning ball with
the Acid logo. Each 544-byte frame is:
- **Header** (16 bytes): `u32` saved memory pointer, `u16` lines (33),
`u16` strips (4), `u16` flags (`0x8020`), `u16` bytes per strip (132),
4 unused bytes.
- **Strips:** four 16-pixel sprites, each line two bitplane words.
Flag bit 15 marks attached sprites. The strips pair up into two 16-colour
columns, so a frame is 32 × 33 pixels. The bank carries no colours.
## Music (`sfx/tune.crn`)
A CrunchMania-packed OctaMED `MMD1` module: 4 tracks, 21 plain 8-bit
sample instruments, 70 blocks played in order. The main song is positions
0–65, ending with a jump back to the start. Positions 66–69 hold separate
short pieces that end with "stop".
The song uses these commands:
- `1`, `2` (slide up, slide down)
- `3` (portamento)
- `9` (speed)
- `B` (jump)
- `C` (volume, decimal)
- `D` (volume slide)
- `F00` (break), `F1` (play twice), `F2` (delay), `FD` (set pitch),
`FE` (stop)
`src/music.rs` plays these. Its loudness tracks OpenMPT's rendering of the
module second by second through the whole song (correlation 0.996 over the
first minute), and it loops at the same point.
## Executables
- **`SKIDMARKS_CD³²`** (237 KB): a single-hunk compiled Blitz Basic 2
program. It includes IFF ILBM/8SVX/ANIM loaders and a tracker replay
routine with note-period tables.
- **`skidmarks2`** (90 KB): a three-hunk program whose code is packed.
## Gaps
- **Game logic.** The handling, AI and rules in the executable aren't
decoded; this port's versions are reconstructions. Decoding the `.set`
values would be the first step towards the original handling.
- **Unknown data:** the 12 bytes after each track file's palette, the bit
pattern after the gates in each track section, and the colours of
`ball.spr` (probably set by the executable).
The engine's own editable formats, which `skids extract` converts all of
the above into, are described in [assets/README.md](../assets/README.md).