πŸ›‘οΈ TA Archive

Map Editors & Terrain Research

Map Editors & Terrain Height/Slope Logic (Research)

Status: First research round, 2026-09-04. All sources were retrieved and verified (web extraction). Uncertainties are explicitly marked with ⚠️.


1. TNT attribute bytes: semantics (largely solved)

The best reverse-engineering source is TAUtil (MHeasell, C#), TAUtil/Tnt/TileAttr.cs: https://raw.githubusercontent.com/MHeasell/TAUtil/master/TAUtil/Tnt/TileAttr.cs

Structure per cell (4 bytes, row-major across all attribute cells, TntReader.EnumerateAttrs):

Offset Field Meaning
0 Height (byte) Height at this cell
1–2 Feature (uint16, little-endian) Index into the map’s feature/anim list. Special values: 0xFFFF = no feature; 0xFFFC (-4) = “void” cell; 0xFFFE (-2) appears on early Cavedog maps (Lava Run, AC02) β€” meaning unknown (MHeasell asks for info).
3 Pad1 (byte) No known function (MHeasell suspects padding).

Consequence for our generator: The suspected “255/0/1/2” bytes 1+2 are not a passability or water flag β€” they are the feature index (0xFFFF = 255,255 = “no feature”). Values 0/1/2 in bytes 1+2 mean feature index 0–2, i.e. a feature (tree, rock, vent …) sits at that cell. Byte 3 is padding. β†’ When writing maps: bytes 1+2 = FF FF (no feature) unless we place features; byte 3 = 0.

Relation to the old DFR spec: The classic file-format hack document (Saruman & Bobban / DFR, v0.0.4, 1997, hosted on units.tauniverse.com) interprets the 4 bytes as “AA BBBB CC”: AA = height, BBBB = index of “special item” (0xFFFF = none), CC = unknown. That matches TAUtil (feature index + padding), confirming the same reading. DFR source: https://units.tauniverse.com/tutorials/tadesign/tadesign/ta-tnt-fmt.txt

SCT (tileset sections): version 2 = 8 bytes per attribute (extra padding longword), version 3 = 4 bytes like TNT (same reads, feature set to 0). Also from TileAttr.cs.

2. Height, water, map size (context)

3. Walkability: how slope is computed / the MaxSlope scale

TA itself is closed source β€” walkability logic is documented via the MovementClass definition in gamedata/moveinfo.tdf and the FBI/moveinfo tags MaxSlope/MaxWaterDepth:

The best-documented reference implementation β€” the Spring engine (inherits TA movement classes; SMF format derived directly from TNT):

  1. Slope computation (rts/Map/ReadMap.cpp, around CReadMap::UpdateHeightMapSynced): per cell, the 8 surrounding face normals (from the 2 triangles per height cell) are considered; avgslope = mean of the normals’ y components Γ— 0.125, maxslope = minimum of all 8 y components, then smoothing: slope = mix(maxslope, avgslope, maxslope/avgslope); stored as slopeMap = 1.0 - slope. The code comment: “smooth it a bit, so small holes don’t block huge tanks”. Sources: https://raw.githubusercontent.com/spring/spring/develop/rts/Map/ReadMap.cpp (lines ~660–697), format loader: https://raw.githubusercontent.com/spring/spring/develop/rts/Map/SMF/SMFReadMap.cpp

  2. maxSlope semantics (official Spring wiki, author kloot): Spring internally uses (1.0 - terrainNormal.y) as slope (0 = flat, 1 = vertical). The “can we walk here?” test is maxSlope > terrainSlope; the conversion is 1.0 - cos(DEG2RAD(maxSlope * 1.5)), i.e. practically: maxTerrainAngle(degrees) = maxSlope Γ— 1.5 (maxSlope 30 β†’ 45Β°, 36 β†’ 54Β°, >60 = walkable everywhere). Source: https://github-wiki-see.page/m/beyond-all-reason/springrts_engine_wiki_mirror/wiki/Movedefs.lua (mirror of the springrts.com wiki page “Movedefs.lua”). Also confirmed by the BAR movedefs.lua comment: “maxSlope is multiplied by 1.5 at load, so 60 degrees is its actual maximum” β€” https://github.com/beyond-all-reason/Beyond-All-Reason/blob/aae9279d/gamedata/movedefs.lua

Transfer to TA (⚠️ with caution): TA is closed source; the 1.5 scaling is a Spring decision. But the vanilla movement-class values (tanks 8–15, KBots 11–32) were set in 1997 to behave plausibly as degreesΓ—1.5 (β†’ roughly 12°–48Β° maximum walkable slope), and Spring adopted the TA classes unchanged. Working rule for the map generator: a cell step (16-elmo grid) that jumps more than ~30 height units over 2 cells blocks all vanilla tanks; steps ≀ ~15 per cell remain walkable for most units. The definitive TA-internal formula remains open β€” calibrate against the cliff sections of the official tilesets and run in-game tests.

Practical consequence for the generator: vanilla TA movement classes sit at MaxSlope 8–36 (tanks low ~8–15, KBots 11–32). A height jump of more than ~15–16 units per attribute cell (16 elmo) exceeds practically every vanilla tank class and is safe only for the steepest KBot classes. ⚠️ The exact formula slope = f(maxCornerDiff, minCornerDiff) per path tile is not publicly documented for TA itself β€” no community source found that nails down an empirically determined max height jump per cell. Recommendation: our own empirical tests (build defined step heights into a map, send runner units across) and calibration against the vanilla movement-class values. No broader community convention (“max height jump per tile = X”) exists per this research β€” the cliff sections of the official tilesets are the implicit reference (see below).

4. Slope/cliff tile practice from the editors

Annihilator 1.5/1.6 (Kinboat) β€” the community’s de-facto standard

TAE (official Cavedog Map & Mission Editor)

Mappy & SnappyMap (MHeasell) β€” most modern tools, directly relevant to us

Other tools

5. Ramp/slope tile placement rules (empirical, from editor docs)

Direct rule documentation is missing; what is documented:

6. Open questions / next steps

  1. Byte 3 (Pad1) and feature = 0xFFFE (Lava Run/AC02): unknown β€” MHeasell is actively looking for information.
  2. The exact TA slope formula (walkability from corner heights) β€” only achievable via CALib/binary RE or our own in-game tests; use the vanilla movement-class MaxSlopes (8–36) as calibration anchors.
  3. Wayback grabbing for: TAMEC utility descriptions (Annihilator readme, Mappy forum thread), xolon.org / totalannihilation.net format docs, tauniverse.com forum threads on “map editor height” (the old vBulletin is barely indexable β€” Google site search + Wayback).
  4. Inspect the Mappy source (GitHub) for height/slope placement checks.
  5. The local KB (/home/hermes3/ta-halle/kb/) contained only domain-setup.md before this article β€” no duplication.