从头到尾制作一个单位模组
本教程带你从原版的横扫千军安装出发,做出一个小小的模组,新增 Arm Flash 坦克的一个变体——一个速度翻倍的换皮版本。完成后,你会得到一个可以发布的
.ufo压缩包,放进游戏文件夹就能加载;同时也会对 kbot 支持的每种格式建立起清晰的整体认识。
Important
以下步骤假定使用类 UNIX 的 shell。kbot 命令行在 Windows 上完全相同;必要时把路径中的 / 换成 \。
0. 准备工作
- 位于
$TA的完整 TA 安装(GOG、Steam 或原版光盘)。 - 安装好 kbot:
go install github.com/coreprime/kbot/cmd/kbot@latest kbot ctx add "$TA" --alias ta --game totala - 留出磁盘空间,存放展开后的一份工作文件(约 120 MB)。
1. 展开安装目录
你要逐个编辑文件;先把压缩包展开一次,就能用普通工具读取它们。
kbot mount "$TA" flatten --target ./ta-flat
看看得到了什么:
ls ta-flat/ # ai/ anims/ features/ ... weapons/
ls ta-flat/units/ | head # ARMCOM.FBI, ARMFLASH.FBI, ...
文件夹布局与虚拟文件系统的结构一致——压缩包在运行时如何分层叠加,见 HPI。
2. 创建模组工作目录
为横扫千军制作模组是增量式的:把一个 .ufo 放在现有压缩包旁边,其中的文件就会覆盖基础游戏。在一个镜像目录树中构建你的模组:
mkdir -p mymod/{units,scripts,objects3d,unitpics,download}
Note
你只需要发布你改动过的文件。 不要把整个游戏复制到 mymod/ 里——那会让 .ufo 臃肿不堪,还可能遮蔽你并不想覆盖的东西。download/ 目录按惯例存放我们将在第 5 步添加的建造菜单注册文件。
3. 挑一个单位来派生
我们以现有的 Arm Flash 为基础制作 MYFLASH。复制四个文件:
cp ta-flat/units/armflash.fbi mymod/units/myflash.fbi
cp ta-flat/scripts/ARMFLASH.cob mymod/scripts/MYFLASH.cob
cp ta-flat/objects3d/armflash.3do mymod/objects3d/myflash.3do
cp ta-flat/unitpics/armflash.pcx mymod/unitpics/myflash.pcx
为什么是这四个?每个单位都需要:
| 文件 | 用途 | 页面 |
|---|---|---|
units/X.fbi |
属性和元数据 | FBI |
scripts/X.cob |
动画/行为字节码 | COB |
objects3d/X.3do |
3D 网格 | 3DO |
unitpics/X.pcx |
建造菜单用的 96×96 单位头像 | PCX |
download/X.tdf |
建造菜单注册(在第 5 步添加) | TDF |
按照惯例,文件名是 FBI 中 Objectname 的小写形式,.fbi 本身有时用大写。引擎在所有地方都不区分大小写。
4. 改写 FBI
打开 mymod/units/myflash.fbi。必须修改的两个关键字段是 UnitName(查找键)和 Objectname(文件基名引用):
[UNITINFO]
{
UnitName=MYFLASH; // ← was ARMFLASH
Objectname=myflash; // ← was armflash
Side=ARM;
Designation=ARM-MV;
Name=Super Flash; // ← display name
Description=Twice-as-fast Flash variant;
...
}
然后调高一项属性来证明改动生效——把速度翻倍:
MaxVelocity=4.0; // was 2.0
Acceleration=0.30; // was 0.15
完整的字段目录见 FBI 附录。未设置的字段都沿用引擎的默认值。
Warning
每个值末尾都要有 ;。 这是“我的改动没生效”的头号原因——漏掉的分号会悄无声息地把这个值与下一行合并。
5. 在建造菜单中注册单位
一个单位即使存在,只要没有任何建造者能造它,就无法被建造。为新单位添加建造位的正确方法,是在模组中放一个 download/<UNITNAME>.tdf 文件——Cavedog 自己的 Core Contingency 资料片就是这样发布新单位的,你能找到的每个只含一个单位的 .ufo 附加包(AFark.ufo、AFlea.ufo、CorNecro.ufo……)也都遵循同样的约定。
创建 mymod/download/MYFLASH.tdf:
[MENUENTRY1]
{
UNITMENU=ARMVP; // The builder this unit appears under
MENU=3; // Build-menu page number (1-indexed)
BUTTON=4; // Slot within that page (0–5 in a 2×3 grid;
// 4 = bottom-left)
UNITNAME=MYFLASH; // The unit being placed (matches your FBI's UnitName)
}
TA 的建造菜单每页是一个 2 列 × 3 行的网格,因此 BUTTON 取值 0–5,对应关系如下:
┌─────┬─────┐
│ 0 │ 1 │ page N, top row
├─────┼─────┤
│ 2 │ 3 │ page N, middle row
├─────┼─────┤
│ 4 │ 5 │ page N, bottom row
└─────┴─────┘
在目标建造者现有的布局中挑一个空位——基础游戏中每个建造者逐页的完整布局,见 TA 建造树参考。
引擎在启动时读取每个 download/*.tdf,解析其中的每个 [MENUENTRY<N>],并把这些条目合并到 sidedata.tdf 所声明的建造菜单中。不需要修改 sidedata.tdf。
为什么这比修改 sidedata.tdf 更好
| 做法 | 优点 | 缺点 |
|---|---|---|
修改 sidedata.tdf |
单一的权威来源 | 覆盖整个文件(约 50 KB);与任何同样改动它的模组冲突;基础游戏下次打补丁时你的添加内容就会丢失 |
download/*.tdf |
增量式,约 150 字节,不与其他模组冲突,对模组友好 | 每添加一个单位就要一个文件(而单位本来就是制作模组的自然单元) |
这是 Cavedog 官方认可的扩展钩子——它的存在正是为了让只含一个单位的附加包不必另外复制修改一份 sidedata.tdf。
由多个建造者建造
要让单位可以由多个建造者建造,只需添加更多 [MENUENTRY<N>] 节。Cavedog 自己的 download/Armfort.tdf(Arm 防御工事墙,随 ccdata.ccx 发布)正是这样做的:
[MENUENTRY1] { UNITMENU=ARMACK; MENU=3; BUTTON=4; UNITNAME=ARMFORT; }
[MENUENTRY2] { UNITMENU=ARMACV; MENU=3; BUTTON=4; UNITNAME=ARMFORT; }
[MENUENTRY3] { UNITMENU=ARMACA; MENU=3; BUTTON=4; UNITNAME=ARMFORT; }
——这样 ARMFORT 就可以由高级建造 Kbot、高级建造车和高级建造飞机建造。每个建造者一个条目。
选择 MENU 和 BUTTON 的值
原版 TA 把前两页菜单(MENU=1、MENU=2)留给基础游戏的单位。社区的惯例是把可下载的单位放在 MENU=3(或更高)上,以免与 Cavedog 发布的任何内容冲突。BUTTON 是该页内的槽位。
拿不准时,从一个向同一建造者添加单位的现有 download/*.tdf 中照抄这些值。提取 Cavedog 的 Armfort.tdf、Armmark.tdf、Cormort.tdf 等作为可用的参考:
kbot hpi extract /path/to/ccdata.ccx "*.tdf" -t /tmp/cc-downloads
ls /tmp/cc-downloads/download/
Note
两个模组使用相同的 (UNITMENU, MENU, BUTTON) 三元组时,会以无法预料的方式冲突——后加载的那个占据该槽位。如果发布的模组要与其他模组共存,请选一个较高的页码(MENU=4 或 5)。
字段参考见 TDF:[MENUENTRY]。
6. 重新编译 COB(可选)
MYFLASH.cob 是从 ARMFLASH.cob 复制来的——原样就能用。如果你想调整动画,就反编译、编辑,再重新编译:
# Decompile to readable BOS
kbot cob decompile mymod/scripts/MYFLASH.cob -t mymod/scripts/MYFLASH.bos
# Edit MYFLASH.bos in any text editor
# (See cob.md for the BOS language reference.)
# Compile back to bytecode
kbot cob compile mymod/scripts/MYFLASH.bos -t mymod/scripts/MYFLASH.cob
# Lint for common issues
kbot cob lint mymod/scripts/MYFLASH.cob
对于 Cavedog 的每一个零售版脚本,反编译→编译的往返都是逐字节一致的——kbot cob roundtrip 会对游戏中的全部脚本验证这一点。
7. (可选)重绘单位头像
unitpics/myflash.pcx 是一张 96×96 的带调色板 PCX。可以用任何支持 8 位 PCX 的图像编辑器(GIMP、Aseprite、Krita)编辑它,但要保留 TA 调色板。检查调色板是否完好:
kbot pcx describe mymod/unitpics/myflash.pcx
# Expected: BitsPerPixel: 8, embedded palette present
如果调色板被弄乱了,保存前重新导入标准的 TA 调色板(palettes/palette.pal)。关于 0x0C 标记和 BytesPerLine 填充的坑,见 PCX。
8. (可选)重做 3D 模型的外观
objects3d/myflash.3do 是一个层级网格——顶点、图元、纹理引用。尽管年代久远,Cavedog 的编辑器(3DO Builder)仍是最实用的 3DO 编辑器。kbot 不能直接编辑 .3do;网页界面只把它们渲染出来供查看:
kbot mount $(kbot ctx path) --server
# → browse to objects3d/myflash.3do for the piece tree and textures
如果你在编写工具,磁盘结构见 3DO。
9. 打包成 .ufo
kbot hpi pack ./mymod --target myflash.ufo
默认情况下,kbot 使用分块的 LZ77 压缩、标准的 Cavedog 文件头密钥,以及游戏所要求的 Cavedog 版权尾部标记——也就是说,引擎会直接接受它,不会报错。确认一下:
kbot hpi info myflash.ufo
# Should show ~5–8 files, marker 0x49504148 (HAPI), decrypt key 0xBF,
# and "TA 3.1c would mount: yes". A "no" names the reason (for example
# a missing Cavedog trailer), and the game would silently skip the file.
kbot hpi list myflash.ufo -v
# units/myflash.fbi, scripts/MYFLASH.cob, objects3d/myflash.3do, ...
10. 安装并测试
为什么用 .ufo?TA 3.1c 先挂载 rev31.gp3,然后是每个 .ccx、每个 .ufo,而 .hpi 只挂载前十个,每一组都按 ASCII 大写名称排序;每个文件都从第一个包含它的压缩包中读取(见 HPI 加载顺序)。.ufo 总会被挂载,而且排在所有 .hpi 之前;.hpi 模组则要去争夺零售版安装已经占满的那十个 *.hpi 名额。rev31.gp3 或某个 .ccx 中也有的文件(例如 units/ARMCOM.FBI 或 gamedata/sidedata.tdf)仍然会从那些压缩包中读取:这类覆盖文件要以散文件的形式放在安装根目录中发布。studio 的 Export mod… 对话框会在你下载之前列出某个工作区中的这类文件。
把 .ufo 放进 TA 安装根目录,与 totala1.hpi 放在一起:
cp myflash.ufo "$TA/"
启动 TA。开一局遭遇战,建造一座 Arm 载具工厂,你的 Super Flash 就应该出现在建造菜单中——速度是普通 Flash 的两倍。
Tip
快速迭代。 不必每次改动后都重新打包,你可以直接把 mymod/ 放进一个展开后的安装目录(那里的文件优先于压缩包中的内容)。等准备好发布时再打包。
故障排查
| 症状 | 可能的原因 |
|---|---|
| 单位没有出现在建造菜单中。 | 缺少 download/<UNITNAME>.tdf,UNITMENU= 有误(建造者名称拼错),或者 (MENU, BUTTON) 槽位已被另一个单位占用。 |
| 建造菜单显示了该单位,但点击后没有反应。 | download TDF 中的 UNITNAME= 与 FBI 的 UnitName= 不一致。或者 FBI 中该单位的 Bmcode= 为 0(表示“不可建造”)。 |
| 游戏在加载时崩溃。 | FBI 值有误(漏了 ;、[SECTION] 格式错误)。运行 kbot mount mymod --server,在网页界面的 TDF 查看器中检查该 FBI——它会高亮显示解析错误。 |
| 单位显示为一团品红色。 | FBI 中的 Objectname 指向一个不存在的 .3do 文件名。检查 objects3d/<Objectname>.3do。 |
| 单位不移动。 | MovementClass 引用了一个不在 moveinfo.tdf 中的类别。要么添加这个类别,要么使用现有的类别。 |
| 单位能移动,但网格没有动画。 | COB 脚本引用了一个 3DO 中没有的部件名。拿 `kbot cob decompile myflash.cob |
| 单位速度对了,但头像不对。 | unitpics/<Objectname>.pcx 不存在,或者引擎看到的仍是原版的 armflash.pcx(模组在基础压缩包之后才加载?)。 |
| 建造菜单显示空白图标。 | PCX 没有保存为 8 位带调色板格式。运行 kbot pcx describe 确认。 |
下一步
- 添加新武器——从
weapons/中复制一个.tdf,编辑后在 FBI 的Weapon1=中引用它。见 weapons.tdf 参考。 - 添加新的移动类别——追加到
moveinfo.tdf中。见 Gamedata。 - 制作自定义地图——用
.sct区块拼装一个.tnt(或者用kbot tnt pack直接手工制作 TNT)。见 TNT。 - 添加新音效——把 WAV 放进
sounds/,在gamedata/sound.tdf中关联起来。见音效。 - 调整 AI——在
ai/default.txt中为你的新单位添加Weight/Limit规则。见 AI。 - 研究现有模组——
kbot hpi list加上kbot hpi extract同样适用于第三方的.ufo。研究别人如何构建他们的压缩包,是掌握模组制作惯例的最快途径。