Gamedata TDFs — Engine Configuration Tables
The files in
gamedata/are TDF text files that configure the engine itself: movement classes, weapon damage categories, side data (UI layout, build menus, starting units), sound bindings, and a handful of small lookup tables. Mods that change the rules of the game (vs. adding units) almost always live here.
This page documents the most useful gamedata files. They all use the INI-shaped TDF grammar — see TDF for parser-level details.
Tip
Try it yourself.
ls $(kbot ctx path)/gamedata/
# The web UI renders these as collapsible section trees
kbot mount $(kbot ctx path) --server
# → browse to gamedata/sidedata.tdf, then sidedata > [CANBUILD]
Files at a glance
| File | What it controls |
|---|---|
sidedata.tdf |
Per-side UI layout, starting commander, build menus. The biggest file in gamedata/. |
moveinfo.tdf |
Movement classes — what terrain each "MovementClass" can traverse. |
weapons.tdf |
Reference doc on the weapon-TDF grammar (mostly comments — not a runtime table). |
category.tdf |
Human-readable descriptions for unit categories. Cosmetic only. |
sound.tdf |
Per-unit sound categories (referenced by FBI SoundCategory=). |
allsound.tdf |
UI / game-event sounds (button clicks, score-bar pings, BGM). |
los.tdf |
Line-of-sight tuning (sight radius modifiers per terrain). |
meteor.tdf |
Asteroid-storm parameters (used by some campaign maps). |
unitview.tdf |
Layout of the in-game unit info panel. |
buildinfo.tdf |
Build-menu hot-keys and tooltip text. |
version.tdf |
Game version string the lobby reports. |
translate.tdf |
Localisation lookup table for UI strings. |
help.tdf |
In-game help-system entries. |
The big three for modding are sidedata.tdf (build menus, sides),
moveinfo.tdf (movement classes), and weapons.tdf (which is
documentation, not data — actual weapons live in weapons/*.tdf).
moveinfo.tdf — Movement Classes
A unit's FBI declares its MovementClass=KBOTSS2 (or similar);
the engine looks up that class in moveinfo.tdf to decide which
terrain it can traverse.
TA 3.1c reads only the sections [CLASS0] to [CLASS31] (the first
section of each of those names) and finds a class by its Name=,
ignoring case, lowest slot first. When the unit's class resolves, the
class's values replace the unit's own FootprintX/FootprintZ,
MaxWaterDepth, MinWaterDepth and slope keys entirely — the commander's
MaxSlope=20 gives way to TANKDS2's 32 — and a key the class leaves out
takes the game's default below, not the FBI's value. A unit with no
class, or naming one the game cannot find, reads its own FBI keys with
the same defaults. KBot Studio's unit meta, sandbox and hosted matches
resolve movement this way.
[CLASS0]
{
Name=KBOTSS2; // Class name referenced from FBIs
FootprintX=2; // Cells wide (16-px units)
FootprintZ=2; // Cells deep
MaxWaterDepth=12; // Deepest water it can enter
MaxSlope=32; // Steepest land slope it can climb
}
[CLASS3]
{
Name=TANKDH3;
FootprintX=3;
FootprintZ=3;
MaxWaterDepth=100; // Heavy tank — can ford deep water
MaxWaterSlope=30; // Slope limit *underwater* (separate from MaxSlope)
MaxSlope=15;
}
Fields
| Field | Type | Meaning |
|---|---|---|
Name |
string | Class identifier referenced from MovementClass= in unit FBIs. Case-insensitive. |
FootprintX, FootprintZ |
int | Pathing footprint, in 16-px attribute cells. Replaces the unit's FBI footprint; 0 when the class leaves it out. |
MaxWaterDepth |
int | Deepest water (in terrain-height units) the unit can enter. 0 = strictly land. Default 10000 (any depth) — hovercraft classes leave it out, so a hovercraft rides any water whatever its FBI says. |
MinWaterDepth |
int | Minimum water depth required (boats, submarines). Default -10000 (no minimum). |
MaxSlope |
int | Steepest slope the unit can climb on land (units = 2π / 256 radians). Default 255; capped by MaxWaterSlope. |
BadSlope |
int | Slope at which the unit moves at reduced speed (slower but not blocked). Defaults to half of MaxSlope; capped by MaxSlope. |
MaxWaterSlope |
int | Same as MaxSlope, applied when underwater. Default 255 (no limit, used for hovercraft). |
BadWaterSlope |
int | Underwater equivalent of BadSlope; defaults to half of MaxWaterSlope. |
Naming conventions
The class name encodes its shape in a short tag — Cavedog's convention:
| Prefix | Meaning |
|---|---|
KBOT |
Bipedal kbot |
TANK |
Tracked/wheeled vehicle |
BOAT |
Surface watercraft |
SPID |
Spider / many-legged crawler |
HOVER |
Hovercraft |
Then a suffix SS / SF / DS / DH / SH (small/deep/heavy/etc.)
and a footprint digit. The naming is convention only — the engine
treats Name= as an opaque key.
Important
Two units with the same MovementClass= share path-finding
behaviour. If you change KBOTSS2 to MaxWaterDepth=50, every
small kbot now wades through water. Add a new class instead if you
want per-unit tuning.
sidedata.tdf — Per-side configuration
This is the longest file in gamedata/ because it bundles three
distinct concerns:
- Side declarations — name, prefix, commander, fonts, colours.
- HUD layout — pixel coordinates for every status bar, label, and button in the in-game UI.
- Build menus —
[CANBUILD]section listing what each constructor can build.
Side block
[SIDE0]
{
name=ARM;
nameprefix=ARM;
commander=ARMCOM; // UnitName of the commander unit
intgaf=ARMINT; // GAF used for intro screen
font=console; // FNT for general text
fontgui=armbutt; // FNT for buttons
energycolor=208; // Palette index for energy bars
metalcolor=224; // Palette index for metal bars
// …followed by ~60 HUD coordinate sub-sections
[LOGO] { x1=132; y1=5; x2=152; y2=25; }
[ENERGYBAR] { x1=471; y1=12; x2=598; y2=14; }
[METALBAR] { x1=218; y1=12; x2=345; y2=14; }
...
}
[SIDE1] { name=CORE; ... }
| Field | Meaning |
|---|---|
name |
Side display name (also used for category matching). |
nameprefix |
String prefix added to localisation lookups. |
commander |
UnitName of the side's commander unit. |
intgaf |
GAF sequence shown during faction selection. |
font / fontgui |
FNT files for HUD text and buttons. |
energycolor / metalcolor |
Palette indices for HUD bars (palette.pal indices). |
TA 3.1c reads the sides [SIDE0], [SIDE1], … in order, stopping at the
first missing number and after five. A section with any other name
([SIDE01], a [SIDE3] after a missing [SIDE2], a sixth side) is never
read, and each side it reads needs every HUD rectangle below (kbot-io's
ta.SideRectangles), or the game loads no sides at all. The studio's
sandbox side picker offers the same sides.
HUD coordinate sub-sections
Every visible HUD element is a [NAME] block with x1/y1/x2/y2 pixel
coordinates. These are relative to the 640×480 base resolution; higher
modes scale by the engine.
[ENERGYBAR] { x1=471; y1=12; x2=598; y2=14; }
To reposition the energy bar, edit the four numbers. To re-skin it,
swap the GAF the HUD uses to draw at that position (set in unitview.tdf).
[CANBUILD] build menus
The static build-menu definition. Each constructor lists what it can build at game-start:
[CANBUILD]
{
[ARMCOM]
{
canbuild1=ARMSOLAR; // Slot 1 on the build menu
canbuild2=ARMWIN;
canbuild3=ARMESTOR;
canbuild4=ARMMSTOR;
canbuild5=ARMMEX;
...
}
[ARMLAB]
{
canbuild1=ARMCK;
canbuild2=ARMPW;
...
}
}
The slot number is the position on the build menu page. TA's build
menu is a 2-column × 3-row grid, so each page holds 6 slots:
canbuild1–canbuild6 are page 1, canbuild7–canbuild12 are
page 2, and so on.
How TA 3.1c reads the table (kbot-io's CanBuildBuilder.BuildList;
kbot document, the unit viewer and the sandbox build menu follow it):
- Only a unit whose FBI sets
Builder=1gets a list; a subsection for any other unit is ignored. - The game reads the first
[CANBUILD]section and in it the first subsection named after the builder (ignoring case). - It reads
canbuild1,canbuild2, … and stops at the first missing number:canbuild1=ARMSOLAR; canbuild3=ARMLAB;gives one entry. - A name that matches no unit is skipped, and a list keeps at most
30 units. Download entries (below) can take a builder's menu to
- (Older documentation occasionally claimed 12 slots per page; the actual in-game grid is 6.) See the TA build tree reference for the per-page layout of every constructor in the base game.
Important
For mods, do NOT edit sidedata.tdf to add units. The Cavedog-
blessed pattern for adding a unit to the build menu is to ship a
download/<UNITNAME>.tdf file alongside the rest of your mod —
the engine merges every download/*.tdf over sidedata.tdf's
static [CANBUILD] table at boot.
Editing sidedata.tdf is only appropriate if you're shipping a
total conversion that rewrites the whole HUD/build-menu layout.
Even Cavedog's own Core Contingency expansion adds its new units
via download/*.tdf, not by modifying sidedata.tdf.
See TDF: [MENUENTRY]
and the modding tutorial.
weapons.tdf — Weapon TDF reference
Despite the name, gamedata/weapons.tdf is mostly comments — it's
Cavedog's published reference for the weapon-TDF grammar, and the game
never loads it. The actual weapon definitions live in weapons/*.tdf,
one section per weapon (see TDF). kbot document does not
list the sections of gamedata/weapons.tdf as weapons.
The weapon table
TA 3.1c builds a table of 256 weapon slots from the .tdf files
directly in weapons/ (not its subdirectories), in the order it lists
them:
- A section goes into the slot its
ID=names,0–255. A section with noID, or one outside that range, is skipped. - A later section with the same
ID— in the same file or a later one — replaces the earlier one. - A unit's
Weapon1/Weapon2/Weapon3,ExplodeAsandSelfDestructAsname a section; the name (ignoring case) resolves to the lowest slot holding a section of that name. - Values read as number prefixes:
weaponacceleration=13O;is 13, and a bad value never drops the rest of the file. - Broken structure makes the game refuse the whole file, so none of its
weapons load, the sections before the fault included: a section header
with no
]or no{, text with no=or a value with no;before the end of the file, the file ending inside a section, or an empty file. Other files are not affected. (A stray}outside any section is not refused: the game stops reading there and keeps what came before.) - A missing
rangeis32767; a missingminbarrelangleis-11.25degrees;reloadtimecounts in whole ticks (30 a second,reloadtime*30truncated:0.35reloads after 10 ticks, 0.333 s);turnrateis in angle units per second (65536 = a full circle).
KBot Studio, packs and kbot host all resolve weapons through this
table. Files the game refuses and sections it skips or replaces are
reported as warnings
(kbot pack prints them; the studio serves them at
/api/studio/weapons/warnings).
rendertype=4 sprites
A rendertype=4 weapon flies a 2D sprite from anims/fx.gaf, and its
color= picks which: 0 cannonshell, 1 plasmasm, 2 plasmamd, 3
ultrashell, 4 plasmasm again; any other value (such as EARTHQUAKE's
color=255) draws no sprite. The sprite steps one frame per game tick
from the moment the shot fires, whatever durations the GAF frames carry.
The reference comments document:
- Three weapon archetypes:
ballistic,lineofsight,dropped. Every weapon TDF must set one of these to1. - Range, velocity, acceleration — in pixels and pixels/sec.
- Area-of-effect — pixel radius, with
edgeeffectivenessas drop-off fraction (e.g.0.5= half-damage at the edge). - Burst & spray —
burst,burstrate,sprayangle. - Two-phase weapons —
twophase,weapontype2,flighttimefor starburst-style projectiles. - Render type —
rendertype=Npicks 3D model, paletted bitmap, beam, etc.
The [DAMAGE] sub-section is where the per-target-category damage
modifiers live:
[FLAMETHROWER] {
...
[DAMAGE]
{
default=10; // Damage applied to anything not listed
corpyro=2; // Pyros are nearly fire-proof
}
}
Keys in [DAMAGE] are unit names: a unit listed takes that damage
instead of default=, every other unit takes default=. Values are kept
to 16 bits. Death blasts (ExplodeAs, SelfDestructAs) use the same
table — CORPYRO_BLAST deals 60 by default but 15 to a Pyro.
category.tdf — Unit category descriptions
A cosmetic flat list mapping category tokens to human-readable text. The engine displays these in the unit info panel:
[Plant] { description = Unit Creation plant; }
[KBOT] { description = Some type of units; }
[Tank] { description = Some type of units; }
[Metal] { description = Some type of units; }
The dashes-instead-of-descriptions are unintentional Cavedog boilerplate. Most mods leave this file alone; some replace the descriptions with proper flavour text. Changing it won't affect gameplay.
sound.tdf and allsound.tdf
Covered in WAV / Sound. In summary:
sound.tdf— per-unit-category sound bindings (the[ARM_COM],[ARM_KBOT]sections). Referenced by FBISoundCategory=. The game reads 23 events, each asKEYthenKEY1,KEY2, … up to the first missing number.allsound.tdf— global UI sound bindings ([BIGBUTTON],[SKIRMISH],[BGM]).
Worked example — adding a movement class
To create a "boat that can ford very shallow water" class:
Append to
gamedata/moveinfo.tdf:[CLASS20] { Name=AMPHIB3; FootprintX=3; FootprintZ=3; MaxWaterDepth=100; // Deep water OK MaxSlope=20; // Reasonable land climbing MaxWaterSlope=200; // Smooth underwater movement }In your unit's FBI:
MovementClass=AMPHIB3;The class's footprint and limits replace the FBI's own, so the unit's
FootprintX/FootprintZ/MaxWaterDepthkeys no longer matter.Pack:
kbot hpi pack ./mymod --target mymod.ufo
The unit will now traverse both land and water seamlessly.
Note
Only [CLASS0] to [CLASS31] are ever read. A class in
[CLASS32], [CLASS100] or [HOVERXL] is never found, and units naming
it fall back to their own FBI keys. Pick a free slot below 32 (retail
uses CLASS0 to CLASS14); a second section with the same slot name
is ignored.
Typical sizes
| File | Range observed in Cavedog gamedata/ |
|---|---|
sidedata.tdf |
~50 KB |
moveinfo.tdf |
~3 KB (15–20 classes) |
sound.tdf |
~20 KB (300+ categories) |
weapons.tdf |
~2 KB (mostly comments) |
category.tdf |
~1 KB |
| Other gamedata files | < 5 KB each |
Gotchas
Warning
Many gamedata files are loaded once at engine start, not per-map. To test a change you have to restart the game — reloading the lobby is not enough. This catches a lot of modders out who think their change "didn't take".
- Movement-class slots are fixed. Only
[CLASS0]to[CLASS31]are read; numbering gaps inside that range are fine. - Comments use
//, not/*…*/in most files — butweapons.tdfuses both. Test parsers tolerate both; some third-party tools don't. sidedata.tdfHUD coords are at 640×480 base and scale up by the engine for higher resolutions. Don't write coordinates in modern resolutions.[CANBUILD]numbering must not have gaps. The game stops reading a builder's list at the first missingcanbuildN, socanbuild11followed bycanbuild14loses the 14th entry and every one after it, without an error.- A
MovementClassthe game cannot find is not an error. The unit silently uses its own FBI keys, with the game's defaults for missing ones — a unit with noMaxWaterDepththen wades to depth 10000.