Tyrian game data formats
Mods never edit the original data files: they describe changes in JSON. This page is a map of those files for the curious and
for tool writers. The byte-level specification is docs/formats-spec.md in the repository.
Conventions
- Multi-byte values are little-endian, with two exceptions: the tile tables of the level maps and the delays of the demo files are big-endian.
- Several files are containers: a 16-bit count, then a table of absolute 32-bit offsets, then the entries.
- Texts (episode scripts, data cubes, credits) are stored as Pascal strings (a length byte, then the bytes) lightly encrypted with a 10-byte key, each byte also chained to the previous one.
The files
| File | Content |
|---|---|
tyrian1.lvl … tyrian5.lvl | The levels of each episode. Each level is a pair of entries: a header with the random-enemy list and the event list (11 bytes per event), then the three map layers. For episodes 4 and 5 the last entry also holds the item and enemy tables those episodes use. |
levels1.dat … levels5.dat | Episode scripts: sections that chain shops, levels, story screens, navigation choices and jumps. |
tyrian.hdt | Item and enemy tables for episodes 1 to 3: weapons, weapon ports (the guns sold in the shop), specials, generators, ships, sidekicks, shields and 1,701 enemy records. |
shapesW/X/Y/Z/).dat | Background tiles, 24×28 pixels, 600 per file. |
newsh?.shp | Enemy sprite sheets: 12×14 cells, run-length compressed; big enemies use 2×2 cells. |
tyrian.shp | Fonts, planets, faces, option and weapon icons, player shots, player ships, power-ups and coins. |
palette.dat | 24 palettes of 256 VGA colours (6 bits per channel). |
tyrian.pic, tshp2.pcx | Full-screen 320×200 pictures. |
music.mus | 41 songs in the Loudness (LDS) AdLib format. |
tyrian.snd, voices.snd | Sound effects and voices, 8-bit PCM at 11,025 Hz. |
cubetxt1.dat … cubetxt5.dat | Data cube texts. The game now shows translated texts from data/locales/. |
demo.1 … demo.5 | The title-screen demos: the starting equipment, then recorded inputs. |
Item and enemy tables
The tables have fixed sizes. Weapon records describe one firing pattern (fire delay, shots per volley, and for each projectile its damage, lifetime, speed, offset and sprite). A weapon port is what the shop sells: a name, a price, a power use, and for each of its one or two firing modes the weapon record used at each of the 11 power levels. Enemy records hold movement, armor, size, up to 20 animation frames, the sprite bank, three turrets with their fire rates, launched and dropped enemies, and the score value.
Some values have a special meaning:
- enemy armor 255: cannot be destroyed by shots; armor 0: a pickup rather than an enemy;
- projectile damage 99: freeze; 100 to 249: chain reaction; 250 and above: piercing;
- an enemy value above 10,000 marks a special pickup, such as the hidden items that open secret levels.
Episodes 4 and 5 replace the whole table with their own copy, in which the same slot often holds a different enemy. That is why mods cite enemies by name rather than by slot.
Tools in the repository
rewrite/crates/tyrian-formats: readers and writers for these formats, in Rust.rewrite/crates/tyrian-mods: the mod loader and thetyrian-modscommand (check,run,catalog).utils/: Python scripts that export the tables to JSON and extract sprites.site-tools/wiki-gen: the generator of this wiki, which reads the tables, levels and episode scripts to produce its pages.