This folder holds The Broken Seal's maps as editable tables: the layered maps of towns, dungeons and interiors, the world map's ground blocks, the default map, and the Colosso rivals' recorded paths.
There is no code here. The field engine loads the maps (Map_LoadLayeredScene, ../field/field/map_layers.c); the scene table says which scene uses which map.
See also: Field, which loads and draws the maps; Field objects, which places the markers; and Scenes.
| Path | What it holds |
|---|---|
| map_NNN/ | one layered map, 180 of them: map.s and the tables it places |
| gondowan_passage/, venus_entrance/ | two layered maps named for their place, built like the others |
| world/blocks.tsv | the world map's ground blocks (Field_PerspectiveDataA) |
| default/ | the default cells, tile animation and block attributes (Field_DefaultMapCells and its kin) |
| colosso/ | the rivals' recorded paths in the Colosso finals, and the Colosso lettering placed after them |
| map.s | places world/ and default/ |
| map.inc | the map_header, map_layer and map_block macros every map.s uses |
The folder has 1,527 tracked files: 1,342 tables (.tsv), 184 assembly files (.s) and map.inc. A built tree has about 780 more, the encoded form of each table, written beside it and ignored by git (2,308 in all).
A layered map's directory holds:
| File | What it is | Built as |
|---|---|---|
| map.s | the header, the three layers and six offsets, then the blocks; and the tile sheets and palette of its tile set after them | assembled |
| metatiles.tsv | the blocks: four tile entries each, top left, top right, bottom left, bottom right | metatiles.delta0.lz, .delta1.lz or .delta2.lz |
| shapes.tsv | the ground shapes: a kind and three height samples each | shapes.table.lz |
| grid.tsv | the cell grid's three planes, in order | grid.parts.lz |
| grid_collision.tsv, grid_shape.tsv, grid_metatile.tsv | the planes: each cell's collision code, shape and block | parts of the grid |
| animation.tsv | the tile animation channels | animation.script.lz |
| blend.tsv | the blend script | blend.script.lz |
| markers.tsv | the cells where chests and Psynergy stones stand | markers.table |
| *_ja.tsv, *_de.tsv, *_es.tsv and so on | an edition's own version of a table | chosen in map.s |
| *_patch.tsv | the bytes Camelot changed after packing | read by the packer |
A map's header (map_header and three map_layer lines, struct LayeredSceneHeader in the loader) holds the camera's bounds in 8-pixel tiles, each layer's priority and tile block, and for each layer its origin, its parallax (sixteenths of the view's motion), its drift (sixteenths of a pixel a frame) and its wrap. Six offsets follow, from the header to its blocks: the blocks, the shapes, the cell grid, the tile animation, the blend script and the markers. An offset of 0 means the map has none.
Map_LoadLayeredScene decodes each into a fixed buffer: the blocks into gMapBlocks, the shapes into gMapCollision, the grid into Ram_MapCellBuffer, and the two scripts into the space after the shapes. The grid is stored as three planes one after another (collision codes, then shapes, then blocks: 16 KB, 16 KB and 32 KB), which keeps each plane's long runs of one value together for the packer (XXX: an inference; the bytes show only the layout). Tile_ConvertMap then interleaves them into cell words, 128 by 128 of them, 64 KB from 0x02010000. That is more than gMapCellBuffer's 32 KB: the cells run on through gActorSpriteSlots and gDecodeBuffer, which the field therefore cannot use for anything else while a map is loaded. A battle reuses that memory, and the scene's map is loaded again when the party returns.
The three layers share that one grid. Each layer's origin picks the cell its window starts at, so a map lays its layers out side by side or one above another in the grid: map 000's three layers start at tiles 0, 60 and 120 across, Venus Lighthouse's entrance at (0, 0), (64, 0) and (0, 68). Layer 0 shows on BG3, layer 1 on BG2 and layer 2 on BG1, and BG0 stays the windows'. A layer's priority byte is also its switch: a layer with priority 0 is not shown. Most maps use 3, 2 and 1; nine give 0 to their second and third layers and show only the first.
Collision and height are per layer too. Code that asks about the ground passes a layer (an object's terrainId), reads the cell at that point in that layer's window, and looks its shape up in gMapCollision; with no map work, it reads the buffer from its start. So each layer has its own walls and heights, and an object belongs to one layer at a time.
A cell whose block is 0xfff is a placeholder. As the map is converted, each placeholder is given a block number of its own, counting up from 0 in map order. XXX: what fills those blocks is not known.
Every table is encoded by tools/ags-graphics, which reads the form and the codec from the name of the file it is asked to write (NAME.FORM[.CODEC] from NAME.tsv, the Makefile's asset rules). The forms a map uses:
The codec lz then packs the result as Camelot's packer did, and the bytes must come out identical. Two kinds of record keep them so. Where the original stream is followed by a few stray bytes, which the packer left from its buffer, map.s places them as literal bytes with a PACKER: comment that says what wrote them. Where Camelot changed a stream after packing it, a _patch.tsv beside the table lists each changed byte: its position, the byte the packer saw, the byte that shipped, and the proof. The table holds what shipped, and the patch gives the packer the byte it packed, so the packer makes the same choices and the stream decodes to the edited map.
An edition's own version of a table (grid_es.tsv, markers_ja.tsv) is chosen in map.s with .ifdef TBS_EDITION_*; editions that agree share one file, and a map that uses another map's table names that map's file (many map.s place map_000/markers.table, which is empty).
The names metatiles, shapes, grid and markers come from what the loader and the code that reads each block do with it: the blocks become BG map entries, the shapes feed the height functions, the markers place chests and Psynergy stones (Field_PlaceMapMarkers). The sixth offset is the marker list: the loader stores a pointer to it, undecoded, in the map work (LayeredSceneHeader.markers), and the only code that reads that pointer is Field_PlaceMapMarkers, which reads (column, row, id) triples from it; MapScrollWork (include/map_scroll.h) still calls the field script. The map numbers are the directory's.
Still unknown: