所有格式页面 ↓
单位、脚本与配置

gamedata TDF 文件——引擎配置表

来自 coreprime/kbot @ 0ab97bf · 在 GitHub 上编辑

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/ 中最长的文件,因为它把三类不同的内容打包在一起:

  1. 阵营声明——名称、前缀、指挥官、字体、颜色。
  2. HUD 布局——游戏内界面中每个状态条、标签和按钮的像素坐标。
  3. 建造菜单——[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 来加入新单位的。

见 TDF:[MENUENTRY] 和模组制作教程。


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])。

实例解析——添加一个移动类别

要创建一个“能涉过很浅水域的船”类别:

  1. 追加到 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
    }
  2. 在你的单位 FBI 中:

    MovementClass=AMPHIB3;

    该类别的占地和各项限制会取代 FBI 自己的值,所以单位的 FootprintX/FootprintZ/MaxWaterDepth 键不再起作用。

  3. 打包:

    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 的深度。

另见

  • TDF——与 FBI/OTA 共用的解析器层面语法。
  • 音效——sound.tdf 和 allsound.tdf 的接线方式。
  • FBI——单位引用 MovementClass、SoundCategory 和武器 TDF 名称。
  • 术语表——movement class、footprint、side。