gamedata TDF 文件——引擎配置表
gamedata/中的文件是配置引擎本身的 TDF 文本文件:移动类别、武器伤害类别、阵营数据(界面布局、建造菜单、初始单位)、声音绑定,以及少量小型查找表。改变游戏规则(而不是添加单位)的模组,几乎总是在这里做文章。
本页记述最有用的几个 gamedata 文件。它们都使用 INI 形态的 TDF 语法——解析器层面的细节见 TDF。
Tip
自己试试。
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]
文件一览
| 文件 | 它控制什么 |
|---|---|
sidedata.tdf |
各阵营的界面布局、初始指挥官、建造菜单。gamedata/ 中最大的文件。 |
moveinfo.tdf |
移动类别——每个“MovementClass”能通过哪些地形。 |
weapons.tdf |
武器 TDF 语法的参考文档(大部分是注释——不是运行时用的表)。 |
category.tdf |
单位类别的人类可读描述。仅用于显示。 |
sound.tdf |
按单位区分的音效类别(由 FBI 的 SoundCategory= 引用)。 |
allsound.tdf |
界面/游戏事件音效(按钮点击、比分条提示音、背景音乐)。 |
los.tdf |
视野调校(按地形区分的视野半径修正)。 |
meteor.tdf |
陨石雨参数(部分战役地图使用)。 |
unitview.tdf |
游戏内单位信息面板的布局。 |
buildinfo.tdf |
建造菜单的快捷键和提示文字。 |
version.tdf |
大厅报告的游戏版本字符串。 |
translate.tdf |
界面字符串的本地化查找表。 |
help.tdf |
游戏内帮助系统的条目。 |
对模组制作来说,最重要的三个是 sidedata.tdf(建造菜单、阵营)、moveinfo.tdf(移动类别)和 weapons.tdf(它是文档而不是数据——实际的武器在 weapons/*.tdf 中)。
moveinfo.tdf——移动类别
单位的 FBI 声明它的 MovementClass=KBOTSS2(或类似的值);引擎在 moveinfo.tdf 中查找这个类别,以决定该单位能通过哪些地形。
TA 3.1c 只读取 [CLASS0] 到 [CLASS31] 这些节(每个名称只读第一个节),并按 Name= 查找类别,忽略大小写,从最低槽位开始。当单位的类别能解析到时,该类别的值会完全取代单位自身的 FootprintX/FootprintZ、MaxWaterDepth、MinWaterDepth 和坡度键——指挥官的 MaxSlope=20 让位于 TANKDS2 的 32——而类别中省略的键取下面列出的游戏默认值,而不是 FBI 中的值。没有类别、或者指定了游戏找不到的类别的单位,读取它自己 FBI 中的键,并采用同样的默认值。KBot Studio 的单位元数据、沙盒和托管对局都以这种方式解析移动属性。
[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;
}
字段
| 字段 | 类型 | 含义 |
|---|---|---|
Name |
string | 单位 FBI 中 MovementClass= 引用的类别标识符。不区分大小写。 |
FootprintX、FootprintZ |
int | 寻路占地,以 16 像素的属性格为单位。取代单位 FBI 中的占地;类别省略时为 0。 |
MaxWaterDepth |
int | 单位能进入的最深水域(以地形高度单位计)。0 = 只能在陆地上。默认为 10000(任意深度)——气垫船类别省略了它,所以无论 FBI 怎么写,气垫船都能在任何水域行驶。 |
MinWaterDepth |
int | 所需的最小水深(船只、潜艇)。默认为 -10000(没有下限)。 |
MaxSlope |
int | 单位在陆地上能攀爬的最陡坡度(单位 = 2π / 256 弧度)。默认为 255;上限为 MaxWaterSlope。 |
BadSlope |
int | 单位以较低速度移动的坡度(变慢但不会被阻挡)。默认为 MaxSlope 的一半;上限为 MaxSlope。 |
MaxWaterSlope |
int | 与 MaxSlope 相同,在水下时适用。默认为 255(没有限制,用于气垫船)。 |
BadWaterSlope |
int | BadSlope 的水下对应项;默认为 MaxWaterSlope 的一半。 |
命名约定
类别名用一个简短的标签编码其形态——这是 Cavedog 的约定:
| 前缀 | 含义 |
|---|---|
KBOT |
双足 kbot |
TANK |
履带/轮式车辆 |
BOAT |
水面舰船 |
SPID |
蜘蛛型 / 多足爬行单位 |
HOVER |
气垫船 |
然后是一个后缀 SS / SF / DS / DH / SH(小型/深水/重型等)和一个表示占地的数字。这种命名只是约定——引擎把 Name= 当作一个不透明的键。
Important
MovementClass= 相同的两个单位共享寻路行为。 如果你把 KBOTSS2 改成 MaxWaterDepth=50,每个小型 kbot 现在都会蹚水前进。如果你想针对单个单位调校,请改为新增一个类别。
sidedata.tdf——各阵营的配置
这是 gamedata/ 中最长的文件,因为它把三类不同的内容打包在一起:
- 阵营声明——名称、前缀、指挥官、字体、颜色。
- HUD 布局——游戏内界面中每个状态条、标签和按钮的像素坐标。
- 建造菜单——
[CANBUILD]节,列出每个建造者能建造什么。
阵营块
[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; ... }
| 字段 | 含义 |
|---|---|
name |
阵营的显示名称(也用于类别匹配)。 |
nameprefix |
添加到本地化查找中的字符串前缀。 |
commander |
该阵营指挥官单位的 UnitName。 |
intgaf |
选择阵营时显示的 GAF 序列。 |
font / fontgui |
用于 HUD 文本和按钮的 FNT 文件。 |
energycolor / metalcolor |
HUD 条的调色板索引(palette.pal 中的索引)。 |
TA 3.1c 按顺序读取 [SIDE0]、[SIDE1]……这些阵营,在第一个缺失的编号处停止,最多读取五个。名称不符合的节([SIDE01]、缺少 [SIDE2] 时的 [SIDE3]、第六个阵营)永远不会被读取;而它读取的每个阵营都需要下面的全部 HUD 矩形(kbot-io 的 ta.SideRectangles),否则游戏一个阵营都不会加载。studio 沙盒的阵营选择器提供的也是同样的这些阵营。
HUD 坐标子节
每个可见的 HUD 元素都是一个带 x1/y1/x2/y2 像素坐标的 [NAME] 块。这些坐标相对于 640×480 的基准分辨率;更高的分辨率由引擎缩放。
[ENERGYBAR] { x1=471; y1=12; x2=598; y2=14; }
要移动能量条的位置,就编辑这四个数字。要更换它的外观,就替换 HUD 在该位置绘制所用的 GAF(在 unitview.tdf 中设置)。
[CANBUILD] 建造菜单
静态的建造菜单定义。每个建造者列出它在游戏开始时能建造什么:
[CANBUILD]
{
[ARMCOM]
{
canbuild1=ARMSOLAR; // Slot 1 on the build menu
canbuild2=ARMWIN;
canbuild3=ARMESTOR;
canbuild4=ARMMSTOR;
canbuild5=ARMMEX;
...
}
[ARMLAB]
{
canbuild1=ARMCK;
canbuild2=ARMPW;
...
}
}
槽位编号就是在建造菜单页上的位置。TA 的建造菜单是一个 2 列 × 3 行的网格,所以每页有 6 个槽位:canbuild1–canbuild6 是第 1 页,canbuild7–canbuild12 是第 2 页,依此类推。
TA 3.1c 读取这张表的方式(kbot-io 的 CanBuildBuilder.BuildList;kbot document、单位查看器和沙盒建造菜单都遵循它):
- 只有 FBI 中设置了
Builder=1的单位才会得到列表;任何其他单位的子节都会被忽略。 - 游戏读取第一个
[CANBUILD]节,并读取其中第一个以该建造者命名的子节(忽略大小写)。 - 它依次读取
canbuild1、canbuild2……并在第一个缺失的编号处停止:canbuild1=ARMSOLAR; canbuild3=ARMLAB;只得到一个条目。 - 不匹配任何单位的名称会被跳过,一个列表最多保留 30 个单位。download 条目(见下文)可以让一个建造者的菜单达到 31 个。(旧文档偶尔声称每页 12 个槽位;游戏中实际的网格是 6 个。)基础游戏中每个建造者的分页布局,见 TA 建造树参考。
Important
对于模组,不要通过编辑 sidedata.tdf 来添加单位。 Cavedog 认可的、把单位添加到建造菜单的做法,是在模组的其他文件旁附带一个 download/<UNITNAME>.tdf 文件——引擎在启动时会把每个 download/*.tdf 合并到 sidedata.tdf 的静态 [CANBUILD] 表之上。
只有当你发布的是重写整个 HUD/建造菜单布局的全面改版模组(total conversion)时,编辑 sidedata.tdf 才是合适的。就连 Cavedog 自己的 Core Contingency 资料片,也是通过 download/*.tdf 而不是修改 sidedata.tdf 来加入新单位的。
weapons.tdf——武器 TDF 参考
尽管名字如此,gamedata/weapons.tdf 大部分是注释——它是 Cavedog 发布的武器 TDF 语法参考,游戏从不加载它。实际的武器定义在 weapons/*.tdf 中,每种武器一个节(见 TDF)。kbot document 不会把 gamedata/weapons.tdf 中的节当作武器列出。
武器表
TA 3.1c 用直接位于 weapons/ 中(不含其子目录)的 .tdf 文件,按它列出文件的顺序,构建一张有 256 个武器槽位的表:
- 一个节放入其
ID=指定的槽位,取值0–255。没有ID、或ID超出该范围的节会被跳过。 ID相同的后出现的节——无论在同一个文件还是后面的文件中——会取代先出现的节。- 单位的
Weapon1/Weapon2/Weapon3、ExplodeAs和SelfDestructAs指定一个节;该名称(忽略大小写)解析到持有同名节的最低槽位。 - 值按数字前缀读取:
weaponacceleration=13O;读作 13,而且一个错误的值绝不会导致文件的其余部分被丢弃。 - 结构损坏会让游戏拒绝整个文件,因此其中的武器一个都不会加载,包括出错位置之前的节:节头缺少
]或{、在文件末尾之前出现没有=的文本或没有;的值、文件在某个节内部结束,或者文件为空。其他文件不受影响。(任何节之外多出的一个}不会导致文件被拒绝:游戏在那里停止读取,并保留之前读到的内容。) - 缺少
range时为32767;缺少minbarrelangle时为-11.25度;reloadtime以整数个 tick 计(每秒 30 个,reloadtime*30截断取整:0.35在 10 个 tick,即 0.333 秒后完成装填);turnrate以每秒的角度单位计(65536 = 一整圈)。
KBot Studio、包和 kbot host 都通过这张表解析武器。游戏拒绝的文件,以及它跳过或取代的节,都会作为警告报告(kbot pack 会打印它们;studio 在 /api/studio/weapons/warnings 提供它们)。
rendertype=4 精灵图
rendertype=4 的武器发射一个来自 anims/fx.gaf 的 2D 精灵图,由其 color= 选择具体是哪一个:0 cannonshell,1 plasmasm,2 plasmamd,3 ultrashell,4 又是 plasmasm;其他任何值(例如 EARTHQUAKE 的 color=255)都不绘制精灵图。从开火那一刻起,精灵图每个游戏 tick 前进一帧,与 GAF 帧所带的时长无关。
参考注释记录了以下内容:
- 三种武器原型:
ballistic、lineofsight、dropped。每个武器 TDF 都必须把其中之一设为1。 - 射程、速度、加速度——以像素和像素/秒为单位。
- 作用范围——像素半径,
edgeeffectiveness为衰减比例(例如0.5= 边缘处伤害减半)。 - 连发与散布——
burst、burstrate、sprayangle。 - 两阶段武器——
twophase、weapontype2、flighttime,用于星爆式弹丸。 - 渲染类型——
rendertype=N选择 3D 模型、带调色板的位图、光束等。
[DAMAGE] 子节是存放按目标类别区分的伤害修正的地方:
[FLAMETHROWER] {
...
[DAMAGE]
{
default=10; // Damage applied to anything not listed
corpyro=2; // Pyros are nearly fire-proof
}
}
[DAMAGE] 中的键是单位名称:列出的单位受到该伤害,而不是 default= 的伤害;其他所有单位受到 default= 的伤害。值只保留 16 位。死亡爆炸(ExplodeAs、SelfDestructAs)使用同一张表——CORPYRO_BLAST 默认造成 60 点伤害,但对 Pyro 只造成 15 点。
category.tdf——单位类别描述
一个仅用于显示的扁平列表,把类别记号映射到人类可读的文本。引擎在单位信息面板中显示这些文本:
[Plant] { description = Unit Creation plant; }
[KBOT] { description = Some type of units; }
[Tank] { description = Some type of units; }
[Metal] { description = Some type of units; }
用短横线代替描述,是 Cavedog 无意中留下的样板文字。大多数模组不碰这个文件;有些模组会把描述换成像样的背景描述文字。修改它不会影响游戏玩法。
sound.tdf 和 allsound.tdf
详见 WAV / 音效。概括来说:
sound.tdf——按单位类别区分的声音绑定([ARM_COM]、[ARM_KBOT]等节)。由 FBI 的SoundCategory=引用。游戏读取 23 种事件,每种都按KEY、然后KEY1、KEY2……的顺序读取,直到第一个缺失的编号。allsound.tdf——全局界面声音绑定([BIGBUTTON]、[SKIRMISH]、[BGM])。
实例解析——添加一个移动类别
要创建一个“能涉过很浅水域的船”类别:
追加到
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 }在你的单位 FBI 中:
MovementClass=AMPHIB3;该类别的占地和各项限制会取代 FBI 自己的值,所以单位的
FootprintX/FootprintZ/MaxWaterDepth键不再起作用。打包:
kbot hpi pack ./mymod --target mymod.ufo
现在这个单位就能在陆地和水域之间无缝通行了。
Note
只有 [CLASS0] 到 [CLASS31] 会被读取。 位于 [CLASS32]、[CLASS100] 或 [HOVERXL] 中的类别永远找不到,指定它的单位会退回到自己 FBI 中的键。请选一个低于 32 的空闲槽位(零售版使用 CLASS0 到 CLASS14);槽位名重复的第二个节会被忽略。
典型大小
| 文件 | 在 Cavedog gamedata/ 中观察到的范围 |
|---|---|
sidedata.tdf |
约 50 KB |
moveinfo.tdf |
约 3 KB(15–20 个类别) |
sound.tdf |
约 20 KB(300 多个类别) |
weapons.tdf |
约 2 KB(大部分是注释) |
category.tdf |
约 1 KB |
| 其他 gamedata 文件 | 每个 < 5 KB |
坑点
Warning
许多 gamedata 文件只在引擎启动时加载一次,而不是每张地图加载一次。要测试改动,你必须重启游戏——重新载入大厅是不够的。很多模组作者以为自己的改动“没生效”,就是栽在这里。
- 移动类别的槽位是固定的。 只有
[CLASS0]到[CLASS31]会被读取;该范围内编号有空缺没有关系。 - 在大多数文件中,注释使用
//,而不是/*…*/——但weapons.tdf两者都用。测试用的解析器两者都能容忍;有些第三方工具则不行。 sidedata.tdf的 HUD 坐标以 640×480 为基准,在更高分辨率下由引擎放大。不要按现代分辨率写坐标。[CANBUILD]的编号不能有空缺。 游戏在第一个缺失的canbuildN处停止读取建造者的列表,所以canbuild11后面跟着canbuild14时,第 14 个条目及其后的所有条目都会丢失,而且不会报错。- 游戏找不到
MovementClass并不算错误。 单位会悄悄地使用它自己 FBI 中的键,缺失的键取游戏默认值——于是一个没有MaxWaterDepth的单位能蹚到 10000 的深度。