Skip to content

Park signs (*.sgn)

A .sgn holds everything a park’s name board needs: the artwork painted on the board, and the fonts its name is lettered in. The name itself is not in here — it comes from the park’s script (see Where the name comes from).

Five ship with the game:

FilePark
lobby.wadterrain\Jun_isle.sgnJungle (“Lost Kingdom”)
lobby.wadterrain\Hal_isle.sgnHallow (“Halloween”)
lobby.wadterrain\Fan_gate.sgnFantasy
lobby.wadterrain\Spa_gate.sgnSpace
levels\<park>\features\sign1.wadsign1.sgnthe placeable in-park sign

Note the inconsistent naming. A .sgn is named after the model that carries the sign1 and sign2 materials, which is the island model for jungle and hallow but the gate model for fantasy and space — so a lookup has to try both rather than assume either.

File format

The header is a fixed size: the image body starts at 0x43DD in all five files.

Rows marked (engine-confirmed) were checked against the original game’s own reader and sign compositor rather than inferred from the shipped files alone — the reader loads the header field by field in file order, which is what fixes the sizes and the boundaries below.

OffsetSizeDescription
0x00004 bytesVersion — the engine requires > 99; all five files are 101 (engine-confirmed)
0x00044 bytesUnknown — 0 in all five
0x00081 byteUnknown — 1 in all five
0x00094 bytesLine 0 mode — see Line modes below (engine-confirmed)
0x000D4 bytesLine 1 mode (engine-confirmed)
0x0011436 bytesFont record 0
0x01C5436 bytesFont record 1
0x037920 bytesLine 0 ink — see Line ink below (engine-confirmed)
0x038D20 bytesLine 1 ink (engine-confirmed)
0x03A136 bytesUnknown — three ints (16, 128, 4) then six 4-byte entries
0x03C516384 bytes32-bit pixel data — see below
0x43C54 x floatY, Cb, Cr and A quantisation scales (6, 10, 2, 6 in all five files)
0x43D54 bytesColour chunk size
0x43D94 bytesAlpha chunk size
0x43DDColour chunk, then alpha chunk

Font record

OffsetSizeDescription
+0x00064 bytesDisplay name, NUL-padded ASCII (e.g. Young Itch AOE)
+0x040260 bytesTrueType file name (e.g. YOUNIA__.TTF) — the file itself is in fonts.wad
+0x1444 bytesUnknown
+0x1484 bytesUnknown
+0x14C60 bytesA Windows LOGFONTA (engine-confirmed)
+0x18844 bytesRead by a separate helper; contents not established

There is one record per line of the sign. Jungle letters its two lines in different fonts (Young Itch AOE then Clunker AOE); Space names the same font twice.

The original letters its signs with GDI, so it stores a LOGFONT rather than a size and weight of its own. That structure is why the display name appears to occur a second time part-way through the record: LOGFONTA.lfFaceName sits at +28 within it, which is +0x168 from the record start. Its lfHeight is the usual negative character height (-144 for jungle’s first line).

The floats in the tail are not a colour. Reading the record as two 64-byte name fields instead gives eight tidy floats at +0x18C, three of which always land in 0..1 and look convincingly like a text colour — jungle’s are 0.40, 0.87, 0.31, a green. They are not. That offset falls past the end of the LOGFONT, inside the 44-byte tail above, and the values belong to whatever the helper reads there.

The trap is worth spelling out because the wrong reading survives a casual check: three of the four parks have dark boards, so lettering them in some wrong colour still shows up. Only Fantasy gives it away — its board is painted pale mint and those floats are very nearly the same mint, so its name comes out invisible. The real ink is below.

Line ink

Each line’s colour is a four-byte block sitting after both font records, followed by four more 4-byte fields that are not yet identified — 20 bytes per line. A line whose mode is 0 is absent and contributes no block at all, though no shipped sign does that.

OffsetSizeDescription
+0x001 byteRed
+0x011 byteGreen
+0x021 byteBlue
+0x031 byteOpacity
+0x044 x 4 bytesUnknown — an int, a float, then two more ints

Three steps in the engine fix that ordering, and none of it has to be guessed. The loader reads the four bytes singly into consecutive bytes of its sign object. The renderer hands them to the compositor with the fourth byte first and the other three after it. The compositor walks the glyph’s coverage mask and moves each board pixel that fraction of the way toward the three channels, writing them into bytes 1, 2 and 3 of a pixel whose byte 0 is the coverage — and that same function later packs the buffer as ARGB4444, which is what makes byte 1 red rather than blue.

The opacity is a genuine blend and not a threshold, so a line set below full strength tints the board and lets the artwork show through the lettering.

What the four lobby signs ask for:

FileModeLine 0Line 1
Fan_gate.sgn (Fantasy)1#808000 olive, 67%#808000 olive, 66%
Hal_isle.sgn (Hallow)1#00FF00 green, 79%#00FF00 green, 84%
Jun_isle.sgn (Jungle)2#000000 black, 60%(never read)
Spa_gate.sgn (Space)2#FF80FF pink, 100%(never read)

Line modes

The two 4-byte fields at 0x0009 and 0x000D say how each line is laid down. 1 inks the line on its own; 2 means the two lines are drawn as one.

That distinction matters for colour. At mode 2 the engine maxes both glyph masks into a single surface and then runs one colour over the result, so the second line’s own four bytes are never reached and both words come out in the first line’s ink. Jun_isle.sgn and Spa_gate.sgn are both mode 2; Fan_gate.sgn and Hal_isle.sgn are mode 1 and ink each line separately. A file whose two modes disagree takes a third path that nothing in the shipped data exercises.

Mode 2 is also the likelier home of the six 4-byte entries at 0x03A1. They are a constant FF DB FF 30 repeated in three of the four signs, but in Jun_isle.sgn they are six distinct values that climb steadily (00 2F 5C 80, 00 31 58 78, … 00 3F 58 75) — which reads like a small gradient or palette, and would explain why Lost Kingdom’s flat black is not the whole story of how its board looks. This is not established.

The pixel data at 0x03C5

16384 bytes, which is 64x64 at 32 bits per pixel. It decodes to a small tiling pattern rather than to anything resembling the sign, so while it is clearly image data, its dimensions and purpose are not established. It is not the sign artwork — that is the image body below.

The image body

Everything from 0x43C5 is a .wct version 4 image with its header fields rearranged: four quantisation scales, two chunk sizes, then the colour and alpha chunks, each wrapped in the same BILZ zlib container a .wct uses. A decoder can be handed these directly.

The image is 256x128, decoded at an aligned size of 256 and with the half-scale path (the FullScale flag clear). That gives the expected chunk sizes:

  • colour inflates to 98304 = 256*256 (Y) + 128*128 (Cb) + 128*128 (Cr)
  • alpha inflates to 65536 = 256*256

The alpha channel is uniform and opaque in all four lobby signs — it compresses to 190 bytes in every one — so the board is a solid picture, not a cut-out.

The artwork is a blank board. Jungle’s is cracked bark, fantasy’s a mint wall, hallow’s a framed maroon panel, space’s a starfield. No lettering is baked in; the park name is composited on top at runtime using the fonts named above. The clearest evidence is that the colour chunk’s compressed size tracks the length of the park name — 5,607 bytes for “Space” (5 characters), 7,126 for “Halloween” (9), 11,760 for “Lost Kingdom” (12) and 14,606 for “Fantasy Island” (14) — even though every file inflates to the same 98304 bytes.

How the board maps onto the model

The model draws the board as two 128x128 panels side by side, using materials sign1 and sign2, each taking a full 0..1 UV range. sign1 is the left half of the sheet and sign2 the right. Each material appears twice, once per face, mirrored, so the sign reads correctly from either side.

Laying a two-line name out across the whole 256x128 sheet and then cutting it down the middle is what puts “Lost” above “Kingdom” on the assembled board.

Where the name comes from

Each park has a script at the root of lobby.wad, named after the park, holding a single ISLAND() line whose fourth quoted field is the sign text:

ISLAND(0,"data\lobby\terrain","jun_isle","jun_gate","Lost Kingdom",90.0,12.5)

The others read "Fantasy", "Halloween" and "Space". The same line also names the terrain directory and the two models, and ends with two numbers that look like a heading and a size.