TDF / FBI / OTA——文本配置文件
TDF(“Text Data File”)、FBI(“Feature/Building/Item”)和 OTA(“Online Total Annihilation”)文件都采用同一种类 INI 的文本格式。Cavedog 用它们以规范的方式声明一切非二进制的内容——单位属性、武器参数、地图物件定义、任务元数据、音效类别、AI 提示。
| 扩展名 | 所在位置 | 示例 |
|---|---|---|
.fbi |
units/ |
ARMCOM.FBI、CORRAID.FBI——单位定义 |
.tdf |
features/、weapons/、sounds/、gamedata/ 等 |
armflak_weapon.tdf、treeb.tdf |
.ota |
maps/ |
metal heck.ota——地图元数据、起始位置、AI 简报 |
这些文件都是纯 ASCII 文本,可以用任何文本编辑器打开。
Tip
自己试试。
# The web UI renders FBI/TDF/OTA as collapsible section trees
kbot mount ~/games/totala --server
# → browse to units/ARMCOM.FBI
终端浏览器用法和展开(flatten)选项见 CLI 的 kbot mount 参考。
在 Go 中调用。 使用 formats/tdf:
import "github.com/coreprime/kbot/formats/tdf"
doc, _ := tdf.ParseFile("units/ARMCOM.FBI")
info := doc.Section("UNITINFO")
fmt.Println(info.String("UnitName"), info.Int("MaxDamage"))
语法
TDF 文件是一棵由节(section)组成的树。每个节先是方括号中的名称,然后是一个 { ... } 主体,其中包含 key=value 键值对和/或嵌套的节。
[UNITINFO]
{
UnitName=ARMCOM;
Designation=Commander;
Description=Commander, Arm;
Side=ARM;
Objectname=armcom;
BuildCostEnergy=2500;
BuildCostMetal=2500;
MaxDamage=3000;
[SOUNDS]
{
canselect=cmdsel1;
select1=cmdok1;
}
}
规则:
- 节名写在方括号中;其后直到匹配的
}为止的所有内容都属于该节。一个节可以写在一行里([special0] { specialwhat=StartPos1; XPos=464; ZPos=216; })。 - 值从
=一直延续到下一个;,可以跨越换行:除此之外没有任何东西能结束它,所以值中的花括号、方括号和=都只是普通文本,而值永远不能包含;。键或值两端的空格、制表符和换行都会被去掉。同一个键赋值两次时,保留最后一个值。 - 键不区分大小写。
UnitName、unitname和UNITNAME都指同一个字段;工具通常在读取时统一转成小写。节名的比较同样忽略大小写。 - 值默认是字符串。数字按 C 语言的方式读取,只取开头的数字部分:在游戏需要整数的地方,
12abc读作 12,56.8读作 56(killmul和tidalstrength之类的字段按小数读取)。列表以空格分隔(例如Category=NOTSUB COMMANDER NOTAIR ...)。 - 注释在读取任何内容之前就会被清除:
//到行尾,以及可以跨行的/* ... */块。因此missiondescription=See http://tauniverse.com;会丢掉从//开始的所有内容,包括其中的;,于是这个值会一直延续到下一行。kbot 拒绝写出包含;、//或/*的值。 - 空白和空行会被忽略。
嵌套的节(比如上面 [UNITINFO] 中的 [SOUNDS])在 FBI/OTA 中很常见。TDF 规范没有规定最大深度;实际上不会超过 3 层。
FBI——单位定义
FBI 是引擎眼中一个单位的完整面貌。它把单位的 3D 模型、脚本、武器列表、音效库、建造成本和战斗行为集中到一处。下面是一个删减过的 Arm 指挥官示例:
[UNITINFO]
{
// === Identification ===
UnitName=ARMCOM; // Internal lookup key
Objectname=armcom; // → objects3d/armcom.3do, scripts/armcom.cob
Side=ARM; // ARM or CORE
Designation=Commander; // Mouseover label
Description=Commander, Arm;
// === Economy & build ===
BuildCostMetal=2500;
BuildCostEnergy=2500;
BuildTime=89400; // Build-power × seconds (engine units)
WorkerTime=300; // How fast it builds other things
// === Combat ===
MaxDamage=3000; // Hit points
Weapon1=COMMANDER_WEAPON; // → weapons/commander_weapon.tdf [COMMANDER_WEAPON]
Weapon2=disintegrator; // The dreaded D-gun
candgun=1; // Allowed to fire weapon2 on demand
// === Movement ===
MaxVelocity=1.15;
Acceleration=0.075;
BrakeRate=0.0825;
TurnRate=510;
MovementClass=COMMANDER_TANK3; // → gamedata/movinfo.tdf
// === Senses ===
SightDistance=520;
RadarDistance=585;
// === Tags & categories ===
Category=COMMANDER SURFACE MOBILE WEAPON ...;
NoChaseCategory=AIR;
[SOUNDS] {
canselect=cmdsel1;
select1=cmdok1;
...
}
}
1998 年的社区 FBI 指南(保存在本仓库的源资料中)记录了一百多个字段。大多数一看就懂;不那么直观的通常是这些:
| 字段 | 它实际控制什么 |
|---|---|
Bmcode |
建造菜单页代码——普通单位保持为 1。 |
Category |
以空格分隔的标签列表,供武器的 BadTargetCategory、NoChaseCategory、AI 和建造菜单使用。 |
MovementClass |
引用 gamedata/movinfo.tdf 中的一个类别,该类别规定可通行的地形坡度、水深等。 |
YardMap |
一幅 ASCII 图(例如 oooo\noooo\n),声明单位的占地范围,以及每个格子的水域/陆地限制。 |
Corpse |
用作残骸掉落物的 [FEATURE](见下文)名称。 |
SoundCategory |
选择 gamedata/sound.tdf 中的音效库。 |
TEDClass |
给 Cavedog 编辑器的提示;运行时忽略。 |
Important
UnitName 是其他所有地方使用的查找键——OTA 引用它,AI 引用它,建造菜单也引用它。如果你给一个 FBI 改名,就必须在整个模组中 grep 所有引用。
TDF——地图物件、武器、音效定义
features/**/*.tdf 文件包含 [FEATURE] 节,每节对应一个静态地图摆设。TNT 格式(TNT)按节名引用它们:
[ArmTree01]
{
description=Arm Tree;
category=trees;
object=arm_tree01; // → objects3d/arm_tree01.3do
footprintx=1;
footprintz=1;
height=20;
blocking=1; // Pathing obstacle
flamable=1;
burnmin=10;
burnmax=20;
burntime=30;
feature_reclamate=ArmTree01_Heap; // Recursive: what's left when reclaimed
damage=15;
reclaimable=1;
energy=0;
metal=2;
seqname=arm_tree01; // GAF sequence to draw (for animated features)
}
weapons/*.tdf 遵循同样的模式,使用 [WEAPON_NAME] 节。FBI 中的 Weapon1=COMMANDER_WEAPON 字段,会经由游戏以 ID 为索引的武器表,解析到 weapons/ 中某个 TDF 里的 [COMMANDER_WEAPON] 节:每个节都需要一个取值在 0–255 之间的 ID=,ID 相同时后出现的节取代先出现的节,而一个名称解析到持有它的最低槽位(见 Gamedata:武器表)。社区的武器指南记录了大约 60 个不同的字段;最要紧的是 ballistic/lineofsight/dropped(武器原型)、weapontimer、weaponvelocity、areaofeffect、edgeeffectiveness、burst/burstrate,以及 [DAMAGE] 子节(按类别的伤害修正)。
[FLAMETHROWER] {
ID=1;
name=Flame Thrower;
rendertype=5;
ballistic=1;
turret=1;
range=160;
reloadtime=1.2;
weapontimer=1;
weaponvelocity=188;
areaofeffect=32;
burst=17;
burstrate=.04;
[DAMAGE] {
default=10;
corpyro=2; // Pyros are nearly fireproof
}
}
[MENUENTRY]——建造菜单扩展
download/*.tdf 中的文件可以把一个单位注册到一个或多个建造者的建造菜单中,而无需修改 sidedata.tdf。Cavedog 的 Core Contingency 资料片就是用这种机制加入其单位的,每个只含一个单位的 .ufo 附加包也都遵循这一约定。
[MENUENTRY1]
{
UNITMENU=ARMVP; // Builder's UnitName
MENU=3; // Menu page (row)
BUTTON=4; // Slot within the page
UNITNAME=MYFLASH; // Unit being placed
}
[MENUENTRY2] // Additional builders for the same unit
{
UNITMENU=ARMACV;
MENU=3;
BUTTON=4;
UNITNAME=MYFLASH;
}
| 字段 | 类型 | 含义 |
|---|---|---|
UNITMENU |
str | 要添加到其菜单中的建造者的 UnitName。 |
MENU |
int | 建造菜单页码。1–2 被 Cavedog 保留给原版单位;社区约定从 3 开始。 |
BUTTON |
int | 页内的槽位(0–5,排成 2 列 × 3 行的网格:0=左上,1=右上,2=左中,3=右中,4=左下,5=右下)。 |
UNITNAME |
str | 被添加的单位——必须与你的单位 FBI 中的 UnitName= 一致。 |
文件命名约定。 按惯例,文件名为 download/<UNITNAME>.tdf(与第一个条目的 UNITNAME= 一致),但引擎会读取 download/ 中的每个 *.tdf,所以文件名纯粹是给模组作者的提示。通常一个文件只放一个单位。
多个条目。 一个文件可以包含多个条目——Cavedog 的 download/Armfort.tdf 用了三个条目,让 Arm 防御工事墙(Fortification Wall)可以由 ACK、ACV 和 ACA 建造。TA 3.1c 读取每个文件的前五个节,不论它们叫什么名字([MENUENTRY1] 是惯例,[ENTRY0] 也同样可用);第六个节永远不会被读取。如果某个条目的 UNITMENU 不指向任何单位,或者指向的单位没有 Builder=1,该条目会被忽略;UNITNAME 不指向任何单位的条目同样会被忽略。MENU 和 BUTTON 只保留 8 位,而一个建造者的菜单——它的 [CANBUILD] 列表加上 download 中添加的条目——最多容纳 31 个单位。
Important
download/*.tdf 只会向建造菜单添加内容,不会替换任何东西。 如果你选的槽位与已有条目冲突,引擎的行为是不可预测的——通常是后加载的条目胜出,但 .ufo 的加载顺序在不同平台上不一定相同。对于打算与其他模组共存的模组,请选择较高的 MENU 页(4 或 5)。
有了这个增量式的模组钩子,你只需发布一个 .ufo,而不必另外复制一份 50 KB 的 sidedata.tdf 来修改。端到端的用法见模组制作教程。
OTA——地图元数据
每个 .tnt 都附带一个 .ota,其中包含引擎游玩这张地图所需的一切(而不是渲染其地形所需的内容):
[GlobalHeader]
{
missionname=Metal Heck;
missiondescription=A small, brutal metal map.;
planet=metal;
tidalstrength=0;
solarstrength=20;
lavaworld=0;
killmul=50;
waterdoesdamage=0;
minwindspeed=100;
maxwindspeed=2500;
gravity=112;
numplayers=2,4,6,8,10;
[Schema 0] {
Type=Network 1;
aiprofile=DEFAULT;
SurfaceMetal=10;
MohoMetal=125;
HumanMetal=1000;
ComputerMetal=1000;
HumanEnergy=1000;
ComputerEnergy=1000;
[specials] {
[special0] { specialwhat=StartPos1; XPos=464; ZPos=216; }
[special1] { specialwhat=StartPos2; XPos=3408; ZPos=216; }
...
}
}
}
kbot tnt preview 会读取对应的 .ota,并在所选方案(schema)的每个起始位置绘制带编号的标记。
游戏读取方案和起始位置的方式如下(kbot 的每一个视图——studio 地图编辑器、沙盒、资源浏览器、kbot tnt preview、kbot tnt lint 以及 Quality Checker——都通过 kbot-io 的 OTA 游戏视图,以同样的方式读取它们):
- 方案按名称查找:
Schema 0、Schema 1……直到第一个缺失的编号为止。 名称比较时忽略大小写([schema 1]也算),但编号必须直接写出:[Schema0]或[Schema 01]永远找不到,而编号断档之后的方案(Schema 0、Schema 1、Schema 3)永远不会被读取。SCHEMACOUNT会被忽略。 - 遭遇战和多人游戏按
Type和起始位置数量挑选方案,而不是按位置先后。 只有Type为Network 1到Network 4(比较时忽略大小写)、且至少有一个起始位置的方案才符合条件。对于 N 名玩家,游戏优先选择最后一个恰好有 N 个起始位置的合格方案,否则选择起始位置最多的那个。战役任务则按难度(Easy、Medium、Hard)挑选。numplayers只是显示在大厅中的文本(2, 4、2-8和Any都能加载)。 - 起始位置是
[specials]中specialwhat以StartPos开头的条目(忽略大小写)。StartPosN是玩家槽位 N-1,StartPos0也是槽位 0,StartPos后面不带数字的条目则自行取下一个编号(第一个为 1)。XPos和ZPos以地图像素为单位,保留 16 位。 - 缺失的键有默认值,而不是零: 缺少
missiondescription时显示“No description available”,缺少maxunits(仅用于战役)时取 200,而没有XPos或ZPos的预置地图物件([features])会被跳过,因此位于第 0 列或第 0 行的地图物件需要显式写出0。
Note
studio 地图编辑器会就地编辑地图的 .ota。 保存时只改动你编辑过的值(并添加或删除你添加或删除的方案和起始位置);其余一切——胜利条件和触发器键、useonlyunits、[units]、[features]、其他 [specials]、killmul=0.5 之类的小数、注释——都按原样写回。删除一个方案或起始位置时,文件会按 kbot-io 的布局重写(内容相同,注释丢弃),并对其后的方案重新编号,使游戏仍能找到它们。kbot 无法读取的 .ota 会连同其错误一起显示,保存时保持不变;包含 ;、// 或 /* 的对话框文本会被拒绝。如果一次保存会让游戏读到某个目前被跳过的方案,同样会被拒绝:添加方案时取最小的空闲编号,因此在一个包含 [Schema 0] 和 [Schema 2] 的文件中,新的 [Schema 1] 会让 [Schema 2] 生效;错误信息会指出需要改名或删除的节。大到无法表示的小数(killmul=1e999,游戏将其读作无穷大)显示为可表示的最大数,除非你修改它,否则按原样保留。游戏从 .tnt 文件头中取得海平面高度;编辑器会让已有的 sealevel= 键保持同步,但绝不会新增这个键。
实例解析——最小单位
一个完整可用的“假”FBI,描述一座固定炮塔:
[UNITINFO]
{
UnitName=MYTURRET;
Objectname=myturret;
Side=ARM;
Designation=Test Turret;
Description=Bare-minimum turret for format testing.
BuildCostMetal=200;
BuildCostEnergy=400;
BuildTime=2400;
MaxDamage=600;
Category=NOTSUB SURFACE WEAPON NOTAIR;
TEDClass=LASER;
Builder=0;
canattack=1;
onoffable=0;
ActivateWhenBuilt=1;
Weapon1=LIGHTLASER;
FootprintX=2;
FootprintZ=2;
YardMap=cccc;
MaxSlope=15;
MaxWaterDepth=0;
SightDistance=300;
Corpse=MyTurret_Dead;
[SOUNDS] {
select1=corselect1;
ok1=corok1;
}
}
要把它做成一个完整的单位附加包,你需要发布:
mymod/
├── units/myturret.fbi
├── objects3d/myturret.3do
├── scripts/MYTURRET.cob
├── features/corpses/myturret.tdf # contains [MyTurret_Dead]
└── unitpics/MYTURRET.PCX
……然后把这个目录打包成 HPI:
kbot hpi pack ./mymod --target myturret.ufo
坑点
Warning
每个值都必须以 ; 结尾。 缺少分号并不会报错——解析器会悄悄地把这个值与下一行合并,产生令人费解的属性(MaxDamage=3000 后面跟一个没有结尾的 Description=...,会产生一个拥有 30,000 生命值且没有提示文字的单位)。
- 键不区分大小写,值区分。
Side=arm能匹配针对 ARM 的单位分类逻辑,但那些用if (Side == "ARM")这类字符串相等比较来动态切换阵营的模组就会出问题。 - 列表值以空格分隔(
Category=COMMANDER MOBILE WEAPON)——而不是逗号。引擎按任意空白字符拆分。 - 不过,有些 OTA 字段使用逗号:
numplayers=2,4,6,8,10。并没有统一的列表分隔符约定,而且游戏根本不解析numplayers——只是显示这段文本。 - 嵌套的节没有正式的深度限制,但 Cavedog 发布的内容从未超过 3 层。假定只有 2 层的编辑器,会在少数带有
[WEAPON][DAMAGE][category]式嵌套的武器 TDF 上出错。 - 布尔字段是整数(
canmove=1、canstop=0),而不是true/false。引擎只接受1/0。 .ota文件的任务描述中经常出现 UTF-8 乱码(来自 Word 的智能引号等)。引擎用 Windows-1252 代码页渲染它们,超出该代码页的字符都会显示成方块。
典型大小
| 项目 | 在 Cavedog 内容中观察到的范围 |
|---|---|
| 单位 FBI | 1–4 KB(指挥官:约 3 KB;轻型坦克:约 1.5 KB) |
| 单个地图物件的 TDF | 200 B – 1 KB |
| 武器 TDF | 每个 [WEAPON] 节 0.5–3 KB |
| OTA 文件 | 1–8 KB |
gamedata/sidedata.tdf |
约 50 KB(主要是 HUD 布局) |
gamedata/sound.tdf |
约 20 KB |
| TA + CC 中的 FBI 总数 | 约 250 个文件 |
附录 A——FBI 字段词典
units/*.fbi 中常见的每个字段,按用途分组。类型列的含义:str = 标识符/字符串;int = 整数;float = 浮点数;bool = 0/1;list = 以空白分隔的记号;enum = 含义有文档说明的小整数。
这里没有列出的字段,要么是编辑器的临时数据(UnitNumber、Copyright),要么尚无文档记载。引擎会悄悄忽略未知的键。
身份与显示
| 字段 | 类型 | 说明 |
|---|---|---|
UnitName |
str | 主查找键。 被其他配置、AI、OTA 和建造菜单引用。 |
Side |
str | ARM 或 CORE(TA),Aramon/Taros/Veruna/Zhon(TA:K)。对应 gamedata/sidedata.tdf 中的一个 [SIDE<N>]。 |
Objectname |
str | 单位的 .3do 网格、.cob 脚本和 unitpics/*.pcx 头像共用的基本名称。 |
Designation |
str | 单位信息面板中显示的“型号代码”(例如 Arm 指挥官的 ARM-WM)。 |
Name |
str | 显示在单位上方的简短名称。 |
Description |
str | 显示在建造按钮和单位信息面板上的提示文字。 |
GermanName / FrenchName / SpanishName / ItalianName / JapaneseName / PigLatinName |
str | 本地化名称。按发行的语言版本使用。 |
GermanDescription / FrenchDescription / SpanishDescription / ItalianDescription / JapaneseDescription / PigLatinDescription |
str | 本地化提示文字。 |
Version |
int | 编辑器记录的格式版本。零售版内容中总是 1 或 2。 |
UnitNumber |
int | 仅供编辑器使用的 ID。运行时忽略。 |
Copyright |
str | 自由格式的版权字符串。被忽略。 |
TEDClass |
str | TAE 编辑器的分类(KBOT、TANK、COMMANDER……)。纯属标注,不影响游戏。 |
经济与建造
| 字段 | 类型 | 说明 |
|---|---|---|
BuildCostMetal |
int | 建造该单位所需的金属。 |
BuildCostEnergy |
int | 建造该单位所需的能量。 |
BuildTime |
int | 建造力 × 秒。引擎用它除以建造者的 WorkerTime,得到实际建造时间。 |
WorkerTime |
int | 本单位作为建造者时输出的建造力。 |
EnergyUse |
int | 激活时每 tick 消耗的能量。 |
EnergyMake |
int | 激活时每 tick 产出的能量。 |
MetalUse |
int | 每 tick 消耗的金属。 |
MetalMake |
int | 每 tick 产出的金属。 |
EnergyStorage |
int | 存储容量。非存储类单位留空。 |
MetalStorage |
int | 存储容量。非存储类单位留空。 |
MakesMetal |
int | 金属转换器在开启且能量得到满足时,每秒转换出的金属;按整数读取(1.9 即 1)。与始终生效的 MetalMake 相互独立。 |
ExtractsMetal |
float | 金属提取器在开启且有电力供应时,其占地范围内每单位地图金属的产出量。 |
TidalGenerator |
bool | 该单位的能量产出随地图的 tidalstrength 缩放。 |
WindGenerator |
bool | 产出随地图的风速范围缩放。 |
Builder |
bool | 能够建造其他单位。 |
Builddistance |
int | 纳米车床的最大作用距离,以 16 像素格为单位。 |
CanReclamate |
bool | 能够回收残骸/地图物件。 |
CanCapture |
bool | 能够俘获敌方单位(仅限指挥官)。 |
ActivateWhenBuilt |
bool | 建造完成时,“激活”开关默认为开。 |
onoffable |
bool | 有一个玩家可以切换的开/关开关。 |
战斗与生存
| 字段 | 类型 | 说明 |
|---|---|---|
MaxDamage |
int | 生命值。 |
Weapon1 / Weapon2 / Weapon3 |
str | weapons/*.tdf 中武器节的名称。最多 3 种武器。 |
wpri_badTargetCategory |
list | 主武器效果不佳的类别(降低优先级)。 |
wsec_badTargetCategory |
list | 副武器的同类设置。 |
BadTargetCategory |
list | 整个单位都会避开的目标。 |
NoChaseCategory |
list | 单位不会追击的目标(仅在射程内时开火)。 |
canattack |
bool | 能否开火。 |
candgun |
bool | 能否手动发射第 3 种武器(指挥官的 D-gun)。 |
commandfire |
bool | 强制每一次射击都由玩家发起。 |
ExplodeAs |
str | 死亡时爆炸所用的武器名称(在 weapons/*.tdf 中)。 |
SelfDestructAs |
str | 自毁爆炸所用的武器名称。 |
Corpse |
str | 残骸掉落物在 features/**/*.tdf 中的 [FEATURE] 节名。 |
HealTime |
int | 在维修平台上完全修复所需的秒数。 |
DamageModifier |
float | 施加于所受伤害的倍数。<1 = 有抗性。 |
ImmuneToParalyzer |
bool | 不受定身(stasis)武器影响。 |
HideDamage |
bool | 对敌方隐藏伤害条。 |
kamikaze |
bool | 接触时自爆,而不是开火。 |
firestandorders |
bool | 有常备射击命令开关。 |
StandingFireOrder |
enum | 默认射击姿态:0 = 停火,1 = 还击,2 = 自由开火。缺少该键时为 2;显式给出的值保留其低两位,所以 0 确实就是停火(Hold Fire)。 |
mobilestandorders |
bool | 有常备移动命令开关。 |
StandingMoveOrder |
enum | 默认移动姿态:0 = 原地待命,1 = 机动,2 = 自由行动。缺少该键时为 2;显式给出的值保留其低两位(指挥官的 0 即原地待命,Hold Position)。 |
ShootMe |
bool | 给 AI/电脑对手的提示:优先攻击这个单位。 |
Commander |
bool | 把它标记为指挥官单位(被消灭时输掉游戏)。 |
移动
| 字段 | 类型 | 说明 |
|---|---|---|
MaxVelocity |
float | 最高速度,单位为每 tick 的世界单位。 |
Acceleration |
float | 每 tick 增加的速度。 |
BrakeRate |
float | 停下时每 tick 减少的速度。 |
TurnRate |
int | 旋转速度,单位为每 tick 2π/65536。 |
MaxSlope |
int | 单位能攀爬的最陡陆地坡度。默认为 255。 |
MaxWaterDepth |
int | 单位能进入的最深水域。0 = 只能在陆地上;默认为 10000。 |
MinWaterDepth |
int | 最小水深(仅限船只)。默认为 -10000。 |
MovementClass |
str | gamedata/moveinfo.tdf 中的类别名([CLASS0]–[CLASS31])。能解析到时,该类别的占地、水深和坡度会取代 FBI 自身的键(见 Gamedata)。 |
SteeringMode |
enum | 0/1/2——先转向再移动 / 弧线 / 瞬时转向。 |
Upright |
bool | 让单位以直立方式(kbot)或平贴方式(车辆)渲染。 |
BankScale |
float | 单位转弯时侧倾的剧烈程度(飞机)。默认为 1;显式的 0 表示从不侧倾。 |
PitchScale |
float | 单位加速时俯仰的剧烈程度。 |
Scale |
float | 视觉缩放倍数(1.0 = 正常)。 |
CanFly |
bool | 飞机标志。 |
crusisealt |
int | 飞行单位的巡航高度。 |
attackrunlength |
int | VTOL/轰炸机扫射航程的距离。 |
HoverAttack |
bool | 飞机攻击时悬停(武装直升机)。 |
floater |
bool | 漂浮在水面上。 |
canmove |
bool | 单位能否移动。 |
canpatrol |
bool | 启用巡逻命令。 |
canstop |
bool | 启用停止命令。 |
canguard |
bool | 启用护卫命令。 |
canload |
bool | 能装载被运输的单位。 |
transportsize |
int | 用于运输装载检查的尺寸等级。 |
transportmaxunits / TransMaxUnits |
int | 运输单位的容量。 |
manuverleashlength(也写作 maneuverleashlength) |
int | 单位在机动时离开其驻守位置的最远距离。 |
BadSlope |
int | 移动会减慢但不会被阻挡的坡度。 |
BuildAngle |
int | 可以建造该单位的最大坡度。 |
侦测
| 字段 | 类型 | 说明 |
|---|---|---|
SightDistance |
int | 视野半径,以 16 像素格为单位。 |
RadarDistance |
int | 雷达覆盖半径。0 = 没有雷达。 |
SonarDistance |
int | 声呐覆盖半径。 |
RadarDistanceJam |
int | 单位干扰敌方雷达的半径。 |
Stealth |
bool | 单位不出现在敌方雷达上。 |
CloakCost |
int | 静止时保持隐形每 tick 消耗的能量。 |
CloakCostMoving |
int | 移动时保持隐形每 tick 消耗的能量。 |
mincloakdistance |
int | 有敌人进入这么多格以内时,隐形失效。 |
建造菜单与占地
| 字段 | 类型 | 说明 |
|---|---|---|
Bmcode |
int | 建造菜单代码。可由单位建造的保持为 1;不出现在菜单中的建筑为 0。 |
FootprintX / FootprintZ |
int | 占地范围,以 16 像素格为单位。必须与 MovementClass 的占地一致。 |
YardMap |
str | 多行 ASCII 网格(o=开放,c=封闭,w=水域,g=地热),规定每个格子的限制。 |
ThreeD |
bool | 以 3D 模型渲染。零售版单位总是 1。 |
ZBuffer |
bool | 使用 Z 缓冲。总是 1。 |
NoShadow |
bool | 跳过阴影渲染。 |
NoAutoFire |
bool | 禁用自动开火。 |
norestrict |
bool | 不执行禁区限制。 |
IsAirBase |
bool | 飞机可以在此降落/维修。 |
IsFeature |
bool | 当作静态地图物件而不是单位处理。 |
Category |
list | 至关重要。 以空白分隔的标签列表,用于武器瞄准、AI 权重和建造菜单。标准记号:MOBILE、WEAPON、SURFACE、UNDERWATER、VTOL、KBOT、TANK、SHIP、LEVEL1/LEVEL2/LEVEL3、NOTSUB、NOTAIR、COMMANDER,以及阵营名称。 |
WaterLine |
int | 漂浮单位稳定下来时的吃水深度。 |
altfromsealevel |
int | 飞机高度从海平面而不是地形算起。 |
音频
| 字段 | 类型 | 说明 |
|---|---|---|
SoundCategory |
str | gamedata/sound.tdf 中一个节的名称,提供该单位的语音样本。 |
[SOUNDS](嵌套的节) |
子节 | 针对特定事件的内联覆盖(canselect=…、select1=… 等)。 |
杂项 / 尚未弄清的字段
| 字段 | 类型 | 说明 |
|---|---|---|
DefaultMissionType |
str | 初始任务状态(Standby、Move 等)。 |
sortbias |
int | 在建造菜单中的排序权重。 |
teleporter |
bool | 标记为传送平台(Galactic Gate)。 |
IsAirBase |
bool | 见“建造菜单与占地”——为完整起见在此重复列出。 |
Ovradjust |
bool | 触发一个没有文档的引擎覆盖行为;只有指挥官使用它。 |
ShowPlayerName |
bool | 在单位上方显示玩家名称(仅限指挥官)。 |
MoveRate1 / MoveRate2 |
int | 编辑器的临时数据。运行时不使用。 |
antiweapons |
bool | 由反武器平台使用(Fortitude、反核)。 |
参考目录中的实际示例
字段的用法最好从真实的 FBI 中学习。参考仓库收录了每一个发行的单位:
- TA——全部 FBI:“丰富”的好例子有
ARMCOM(指挥官,带Commander=1、CloakCost、MaxDamage=3000)、ARMSAM(炮塔,Weapon1/2/3都已填写)、ARMBRAWL(飞机,带CanFly、crusisealt、BankScale)、ARMMEX(金属提取器,带ExtractsMetal)。 - TA——全部武器 TDF:
[FLAMETHROWER]展示burst/burstrate/firestarter,[NUCLEAR_MISSILE]展示两阶段制导导弹,[LIGHTNING]展示光束武器。 - TA——地图物件与武器建造树——游戏文件中的每一条
[MENUENTRY]注册。 - 横扫千军:王国单位——不同的字段集(单一资源的
buildcost=、damagecategory=、内联的[WEAPONn])。ARAKING(Aramon 的君主 Elsin)和ARAARCH(Archer)是不错的切入点。