Skip to content

Commit 8c752f8

Browse files
authored
City files (#2)
* Start * update
1 parent 24661e2 commit 8c752f8

8 files changed

Lines changed: 171 additions & 0 deletions

File tree

src/SUMMARY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,12 @@
8989
- [Navigation Vector](./file-formats/navigation-vector.md)
9090
- [Navpoint Matrix](./file-formats/navpoint-matrix.md)
9191
- [Fixed Paths](./file-formats/fixed-paths.md)
92+
- [Town Map (.town)](./file-formats/town.md)
93+
- [Build Mask (.locked)](./file-formats/locked.md)
94+
- [City Nodes (.nodes)](./file-formats/nodes.md)
95+
- [Spawn Points (.spawn)](./file-formats/spawn.md)
96+
- [Isometric Tiles (.let)](./file-formats/let.md)
97+
- [Tile Groups (.lgr)](./file-formats/lgr.md)
98+
- [AIM Images (.aim)](./file-formats/aim.md)
9299
- [Community Tools](./community-tools.md)
93100
- [Appendix](./ch80-00-appendix.md)

src/file-formats/aim.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# AIM Images (.aim)
2+
The engine's image format, handled by `AIM.dll` and selected as
3+
`ShaderFormat=aim` in `iso.ini`. It is used both for tile bitmaps in
4+
`./images/module_stadtkarte/` and for baked town overview images in
5+
`./iso/towns/<id>.aim`.
6+
7+
The file starts with the magic `AIM\0`, followed by an embedded name string and
8+
a sequence of chunks of the form `{ Type, Size, Data }`:
9+
```
10+
0000 41 49 4d 00 ... "AIM\0"
11+
0009 6c 61 6c 61 00 embedded name string
12+
... chunks { Type, Size, Data }
13+
```
14+
15+
| Chunk Type | Encoding | Example |
16+
|-|-|-|
17+
| `22` | RGB / BGR, uncompressed | town overview `0.aim` (`272 x 155`) |
18+
| `34` | compressed indexed BGRA | tile bitmaps |
19+
20+
Tile bitmaps are sheets of `34 x 21` diamonds keyed on magenta (`FF 00 FF`); a
21+
single file may hold several variants. The overview `iso/towns/<id>.aim` decodes
22+
to a `272 x 155` painted image (the same size as the matching `.tga`), not a tile
23+
render.
24+
25+
`.aim` files can be converted to and from PNG with the community `aim_converter`
26+
tool (`to-png` / `to-aim`).
27+
28+
[To be completed]

src/file-formats/let.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Isometric Tiles (.let)
2+
Individual isometric tiles are stored in `./iso/let/<name>.let`
3+
(`TileFormat=let` in `iso.ini`). A `.let` file is a small (~104 byte) descriptor
4+
that binds a tile to its bitmap; it does not contain pixel data itself.
5+
6+
The descriptor is defined as:
7+
8+
| Offset | Type | Field |
9+
|-|-|-|
10+
| `0x08` | `u8[4]` | colour key, magenta `FF 00 FF` |
11+
| `0x10` | `uint32` | tile width (`34`) |
12+
| `0x14` | `uint32` | tile height (`21`) |
13+
| `0x30` | `uint32` | source width |
14+
| `0x34` | `uint32` | source height |
15+
| `0x38` | `uint32` | path length |
16+
| `0x3c` | ASCII | NUL-terminated path to the [`.aim`](./aim.md) bitmap |
17+
18+
For example, `1_1.let`:
19+
```
20+
0000 00 52 1b 01 0e 00 00 00 ff 00 ff ff 00 00 00 00
21+
0010 00 00 00 00 22 00 00 00 15 00 00 00 01 00 00 00
22+
0020 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
23+
0030 22 00 00 00 15 00 00 00 28 00 00 00 69 6d 61 67 "imag
24+
0040 65 73 5c 6d 6f 64 75 6c 65 5f 73 74 61 64 74 6b es\module_stadtk
25+
0050 61 72 74 65 2f 77 61 73 73 65 72 5f 6e 65 75 2e arte/wasser_neu.
26+
0060 61 69 6d 00 00 00 00 00 aim
27+
```
28+
points at `images\module_stadtkarte/wasser_neu.aim` (water).
29+
30+
The tile size (`34 x 21`) matches `TileSize` in `iso.ini`. Tiles named
31+
`1_1`..`9_9` are ground tilesets; the remaining named files are objects.
32+
Variants are bundled by [tile groups](./lgr.md).

src/file-formats/lgr.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Tile Groups (.lgr)
2+
Groups of interchangeable tiles are stored in `./iso/let/<name>.lgr`
3+
(`GroupFormat=lgr` in `iso.ini`). Unlike most of the engine's formats, a `.lgr`
4+
file is plain INI text. The engine treats the members as variants of one tile.
5+
```ini
6+
[GROUP]
7+
Type=2
8+
FileCnt=72
9+
File0=0 0 1_6.let
10+
File1=0 0 1_2.let
11+
File2=0 0 1_3.let
12+
...
13+
```
14+
Each `File<n>` entry is `offsetX offsetY <name>.let`, and `FileCnt` is the number
15+
of member [tiles](./let.md). For example, `Wasser_NEU.lgr` groups 72 water tile
16+
variants.

src/file-formats/locked.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Build Mask (.locked)
2+
The build mask of a town is stored in `./iso/towns/<id>.locked`
3+
(`LockFormat=locked` in `iso.ini`).
4+
5+
It is a flat array of one byte per tile covering the town area only
6+
(`128 x 226 = 28928` bytes, no header).
7+
8+
| Value | Meaning |
9+
|-|-|
10+
| `0x00` | buildable |
11+
| `0x01` | locked |
12+
13+
The entry for column `x` and row `y` (`0..225`) is the byte at `y * 128 + x`.
14+
The covered area matches rows `0..225` of the [town map](./town.md).

src/file-formats/nodes.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# City Nodes (.nodes)
2+
The polyline data of a town is stored in `./iso/towns/<id>.nodes`
3+
(`NodesFormat=nodes` in `iso.ini`).
4+
5+
It is a list of sections, each holding a number of nodes (polylines), each
6+
holding a number of points. All values are `uint32`. The file format is defined
7+
as:
8+
```
9+
File := Section[]
10+
Section := { SectionID, NodeCount, Node[NodeCount] }
11+
Node := { PointCount, Point[PointCount] }
12+
Point := { X, Y }
13+
```
14+
A sample file holds 5 sections (60 nodes, 303 points):
15+
16+
| Section | Nodes | Description |
17+
|-|-|-|
18+
| 0 | 24 | ships town docking path (polylines starting near `y = 10`) |
19+
| 1, 2 | 3 + 3 | citizen route paths (those boundaries have to be 22pixel apart) |
20+
| 3 | 1 | small 4 point region |
21+
| 4 | 29 | detail features |
22+
23+
The coordinates use a pixel/unit space (observed `X` `17..4352`, `Y`
24+
`10..2353`), not the tile grid.

src/file-formats/spawn.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Spawn Points (.spawn)
2+
Spawn data of a town is stored in `./iso/towns/<id>.spawn`
3+
(`SpawnFormat=spawn` in `iso.ini`).
4+
5+
The file is an array of `uint32` values that decode as pairs and appear to be
6+
grouped into sections, similar to the [nodes](./nodes.md) file:
7+
```
8+
| 00 01 02 03 04 05 06 07 |
9+
00000000 | A | B | A | B |
10+
```
11+
The first value of each pair (`A`) lies in the tile-column range (`0..127`),
12+
while the paired value (`B`) increases monotonically within a run. The exact
13+
field semantics and section boundaries have not been identified.

src/file-formats/town.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Town Map (.town)
2+
The isometric tile map of a town is stored in `./iso/towns/<id>.town`.
3+
A sibling file `<id>.editor` uses the same layout.
4+
5+
A map is a grid of `128 x 452` tiles. The file is a 26 byte header followed by
6+
the tile array of `128 * 452 = 57856` tiles, 4 bytes each (`57856 * 4 = 231424`
7+
bytes), so the tile data begins at offset `0x1a`.
8+
9+
Each tile is defined as:
10+
```
11+
| 00 01 02 03 |
12+
00000000 | Tile ID | Terrain |
13+
```
14+
`Tile ID` is a `uint16` selecting the ground or object tile (observed range
15+
`0..904`). `Terrain` is a `uint16` that packs the elevation level and a slope
16+
code as `Terrain = (Level << 8) | Slope`:
17+
18+
| Slope | Meaning |
19+
|-|-|
20+
| `0x00` | flat |
21+
| `0x01`..`0x06` | slope direction |
22+
| `0xff` | scarp / cliff edge |
23+
24+
The tile at column `x` (`0..127`) and row `y` (`0..451`) is located at
25+
`0x1a + (y * 128 + x) * 4`.
26+
27+
The grid is split at row `226`: rows `0..225` cover the town itself (the same
28+
area as the [build mask](./locked.md)), while rows `226..451` describe the
29+
surrounding world and sea.
30+
31+
The `Tile ID` does not map directly to a [tile](./let.md) filename. The lookup
32+
from `Tile ID` to a concrete tile is resolved internally by the engine and is
33+
not stored in the game's text files.
34+
35+
## Header
36+
The purpose of most of the 26 byte header is not yet identified. The `uint16` at
37+
offset `0x02` holds the map width (`128`).

0 commit comments

Comments
 (0)