Per-scene field map Confirmed
Every walkable scene has one file that says where the walls are, how high the floor is, which object stands on which tile and which tiles are doors. It is the first entry of the scene's block on the disc, it is exactly 0x12000 bytes, and the scene loader streams it verbatim into the field buffer - so an offset in the file and an offset at runtime are the same number.
At a glance
- Where
- Slot 0 of each scene's block in PROT.DAT (
DATA\FIELD\<scene>.MAP); 101 entries - Size
0x12000bytes (36 sectors), four regions that sum to it with nothing left over- Runtime home
- The per-scene field buffer, pointer at scratchpad
0x1F8003EC - Grid
- 128 × 128 tiles of 128 world units
- Detection
- Fixed footprint and a trigger-block header that chains; class
field_map - Parser
legaia_scene_formats::field_map- Used by
- field locomotion (collision, floor height, triggers), the environment draw resolver
Four regions
Widths to scale. Total 0x12000.
| Region | Shape | Consumer that pins the offset |
|---|---|---|
| object descriptors | 0x20-byte records, 512 slots | FUN_8003A55C: a cell's low 9 bits scaled by 0x20 |
| collision + floor grid | 1 byte per tile, 0x80-byte rows | FUN_80019278, FUN_8003A55C |
| object-index map | one u16 per tile, 0x100-byte rows | FUN_80019278 |
| trigger block | 18-byte header + four sub-tables | FUN_801D5630 |
Both grids cover the same tiles; they differ in size only because one is a byte per tile and the other a halfword. In a collision byte the high nibble is four sub-cell wall bits and the low nibble a floor-elevation tier - the field locomotion page has the per-field meaning of every region.
The whole image stays resident. Retail reads every region for as long as the scene runs, not only at load. The descriptor table is the one that is easy to assume dead after the init sweep: the sub-area window sweep indexes it again on every camera re-centre.
The trigger block
The block opens with an 18-byte header naming four sub-tables, then the four bodies laid back to back, each followed by a 2-byte gap.
A record matches when its first two bytes equal the player's tile column and row. The record strides are not in the file: they come from a separate four-byte table in the executable, and retail's are 4, 4, 4, 8.
The fallback window is a property of the read, not of the file. The loader requests 0x2000 bytes more than the map, and those trailing sectors are the next PROT entry's leading bytes - in practice the scene's own walk-on trigger sidecar. The trigger lookup searches them with the same header shape when the primary block misses, and a sidecar-only exit row is confirmed to fire in a running game.
Detecting one from bytes alone
size == 0x12000 and a trigger-block header that chains: the first body offset equals the end of the header, each following offset equals the previous body's end plus the gap, and the leading word equals the end of the last body plus two. Across the whole disc that chain holds with zero false positives.
- The footprint is necessary, not sufficient.
0x12000is a size, not a signature: 111 entries carry it and only 101 are field maps. The other ten are mesh streams, a data stream and sound streams that happen to be that long. A reader that resolves “the field map” by footprint alone picks up ten strangers; resolve by slot. - One zeroed header is real. A cutscene-only scene ships its trigger header all zeros. The detector accepts it only when the object table and collision grid are entirely zero as well - ungated, an all-zero 18-byte window matches mesh-stream entries by accident.
- Byte statistics do not identify it. The regions are sparse by construction, so a statistical classifier scatters these files across “mostly zeros” and “low entropy” - the wrong answer for the file that carries every scene's collision data.
Finding a scene's map
The map is slot 0 of the scene's block in extraction space, i.e. extraction index define - 2 under the CDNAME numbering correction. Resolving it as “the first 0x12000 entry at or after the scene's label” instead picks the next scene's map, and so the wrong collision grid.
The map alone does not draw a floor
The grid holds only a 4-bit tier per tile. The elevation it stands for lives in a 16-entry floor-height table installed at scene entry from the scene's MAN header, so the visible ground is the product of two separately resolved assets. When the second link breaks, both consumers fail quietly: there is no ground surface at all, and every placed object falls back to height zero. The result is a scene that still draws its walls and props, flattened onto the origin plane, over nothing. A floorless field scene is therefore a symptom of MAN resolution, not of this file.
See also
Source of record: docs/formats/field-map.md.