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

AI——电脑对手配置文件

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

ai/*.txt 中的文件是纯文本的电脑对手配置文件。每个配置文件按难度声明建造优先级和单位上限;为一张地图设置 AI 玩家时,引擎会读取它们。OTA 的 aiprofile= 键决定一张地图开局时使用哪个配置文件,但用户可以在大厅中覆盖它。

Tip

自己试试。

# Plain-text — just read them
ls $(kbot ctx path)/ai/
head -40 $(kbot ctx path)/ai/default.txt

在 kbot 中。 studio 的资源浏览器在 AI Profile 标签页中显示配置文件,kbot mount 则用 describe ai/<name>.txt 打印它(见 kbot 显示什么)。

在 Go 中调用。 使用 kbot-io 的 formats/ai:

import "github.com/coreprime/kbot-io/formats/ai"

raw, _ := os.ReadFile("ai/default.txt")
profile, _ := ai.Parse(raw)
// profile.Preamble: lines before the first plan; profile.Plans: plan.Name,
// plan.Weights, plan.Limits; profile.Diagnostics: lines read unusually.
settings := ai.NewResolver(units).Apply(profile, ai.Easy) // per-unit result

概览

一个配置文件是一串 plan,每个难度级别一个。每个 plan 包含 Weight 和 Limit 指令,其目标是单个单位名(ARMCOM)、一个类别词(PLANT、LEVEL3、SPECIAL)或 ALL。

plan easy

Weight ARM      0.2
Weight CORE     0.2
Weight PLANT    2
Weight CONSTR   3
Weight ARMACK   2
Weight CORACK   2

Limit  ARMSILO  1
Limit  CORSILO  1


plan medium

Weight ARM      1.0
Weight CORE     1.0
...

指令

指令 语法 含义
plan <word>… plan easy 开始一个新的 plan 块。其后的 Weight/Limit 行只在该 plan 与游戏难度匹配时生效,直到下一个 plan 为止。
Weight <target> <value> Weight ARMCK 0.5 用这个值乘以目标的建造优先级(见权重如何组合)。
Limit <target> <value> Limit ARMSILO 1 限制电脑玩家拥有该目标的数量:-1 表示不限,0 或其他任何负值表示禁止。

TA 3.1c 如何读取这些文本(kbot-io 的 formats/ai 遵循同样的规则):

  • 一行按任意空白字符分割成词——空格、制表符、CR、VT、FF——而且 # 无论出现在哪里都会结束该行,即使在一个词的中间。
  • 第一个词是指令,比较时不区分大小写。第一个词是其他任何内容的行都会被忽略;零售版中的 // comment 行就是这样被跳过的。值后面的词也会被忽略,所以结尾的 // note 无害。
  • 值是第三个词的数字前缀。 权重是一个十进制数(0.5、.5、2、1e1);上限是一个回绕到 32 位的整数。不是数字的值词读作 0,而指令照样生效:零售版 krogoth.txt 中的 Limit CORFORT O(字母 O)禁止了 CORFORT,而 Limit ARM DECOM 4 把整个 ARM 类别的上限设成了 0。
  • 第一行 plan 之前的行在游戏开始时会被忽略,因为此时还没有任何 plan 匹配。如果在游戏过程中重新加载配置文件,它们可能会生效。零售版 krogoth.txt 开头就有两行这样的内容(weight cormakr 0.2、weight armmakr 0.2)。《横扫千军:王国》的 AI 文件根本不使用 plan——见下文横扫千军:王国——没有 plan 的配置文件。

难度级别

原版配置文件带有三个 plan,分别名为 easy、medium 和 hard。当 plan 的某个词(不区分大小写)指明某个难度时——plan medium hard 同时涵盖两者——或者它的第一个词是 any 时,该 plan 就在那个难度下生效。词中没有指明任何难度的 plan(plan brutal、单独一个 plan)不匹配任何难度:其下的行会被忽略,直到下一个 plan 行为止。


单位名与类别词

Weight 和 Limit 都可以以下列内容为目标:

  • 单位的 UnitName——例如 ARMCOM、CORRAID(比较时不区分大小写)。该指令只作用于这一个单位,并将其锁定:之后的 Weight 行(对权重而言)或 Limit 行(对上限而言)不再改变它。
  • 类别词——ARM、CORE、PLANT、CONSTR、LEVEL3、SPECIAL……——与每个单位 Category= 字段中的词进行匹配。它作用于每个匹配且未被锁定的单位。
  • ALL——每个未被锁定的单位。

每个单位起始时优先级为 100 %,且没有上限。权重会乘以当前的百分比,截断为整数,并限制在 0–100 % 之间,所以大于 1 的权重可以恢复先前被降低的单位,但永远不会让它超过 100 %。上限则直接替换当前值。在 default.txt 的 easy plan 中,Weight ARM 0.2 让每个 Arm 单位都变成 20 %;随后的 Weight ARMRAD 0.25 把 Arm 雷达塔降到 5 % 并锁定它;Weight PLANT 2 则把每座 Arm 工厂从 20 % 拉回到 40 %。

Important

类别别名是与单位的 Category= 词表匹配,而不是与任何分类文件匹配。 只有至少一个单位声明了某个类别别名,它才“存在”。把它拼错成 LEVL3,这条指令就会悄无声息地什么也不做(kbot 的查看器会把它标为 matches no unit,即不匹配任何单位)。


实例解析——default.txt 的片段

// DEFAULT PROFILE

//--------------------------- EASY

plan easy

Weight ARM 0.2          // Every Arm unit to 20%
Weight CORE 0.2

Weight ARMRAD 0.25      // Radar towers to 5%, locked
Weight CORRAD 0.25

Weight ARMMAKR .1       // …metal makers to 2%, locked
Weight CORMAKR .1

Weight PLANT 2          // Factories back up to 40%
Weight CONSTR 3         // Constructors to 60%

// encourages advanced units
Weight ARMACK 2         // Advanced Construction Kbots
Weight CORACK 2
Weight ARMACV 2
Weight CORACV 2
Weight ARMACA 2
Weight CORACA 2
Weight SPECIAL 2
Weight LEVEL3 2

解读:在 easy 难度下,每个 Arm 和 Core 单位的优先级都降到 20 %;雷达塔降到 5 %,金属转换器降到 2 %(两者随后都被锁定);工厂(PLANT)和建造者(CONSTR)回升到 40 % 和 60 %,而高级建造者各自的那几行把它们的 60 % 翻倍,达到 100 % 的上限并将其锁定。


地图专用的配置文件

Cavedog 发布了几个针对地图调校的配置文件:

配置文件 使用者
default.txt 大多数普通地图
metal.txt 金属丰富的地图(Metal Heck 之类)
airbattle.txt 以空战为主的地图
seabattle.txt 以海战为主的地图
hover.txt 气垫船为主的地图
acid.txt 酸性世界的地图
urban.txt 城市地图
waterwrld.txt 水世界地图
krogoth.txt Krogoth 头目任务
missions.txt 战役任务

地图的 .ota 通过 aiprofile= 选择其中之一,例如 aiprofile=metal。


横扫千军:王国——没有 plan 的配置文件

Note

本节只讲 TA:K 的差异。 TAK 使用相同的 ai/*.txt 文件名约定和相同的 weight/limit 指令语法,但把 plan 指令视为可选。

横扫千军:王国的每个零售版 AI 配置文件(ai/default.txt,以及战役用的 ai/mission*.txt 一组)列出的 weight/limit 指令根本没有任何 plan 行——每个文件只有一个隐式的难度。其结构是一长串权重块,后面跟着一长串上限块,按单位名前缀以阵营分组。

实例解析——ai/default.txt 的前 30 行

// Kingdoms Default AI Profile 3-28-99


weight araarch 5
weight araat 1
weight arabow 8
weight arabroad 5
weight arabuild 10
weight aracan 4
weight aracastl 10
weight araclay 5
weight aradrag 25      // Dragons: top priority
weight arafast 1
weight arakeep 10
weight araknigh 5
weight aralode 10
weight aramana 5
weight arangate 0      // 0 = never build
weight arapal 8
weight arapries 10
weight arapult 1
weight arasmith 8
weight araspy 4
weight arassh 1
weight arasword 5
weight aratre 1
weight arawall 0
weight arawar 1

扫一遍 default.txt 中的权重偏向,就能看出 Cavedog 的优先次序:

  • aradrag 25——Aramon 的龙被有意加大了权重;AI 会比建造其他任何东西都更积极地建造龙。
  • arabuild 10、aracastl 10、arakeep 10、arapries 10——每一种经济/建造者类型的权重都是 10。
  • arawall 0、arangate 0——明确设为零,从不建造。
  • araat 1、arafast 1、arassh 1——AI 降低了优先级、转而偏好更高级替代品的基础单位。

同样的模式在文件后面针对 tar*、ver* 和 zon* 单位重复出现。

上限块

权重块之下是一个与之平行的上限块:

limit araarch 16
limit araat 8
limit arabow 16
limit arabroad 16
limit arabuild 10
limit aracan 3
limit aracastl 2       // Only 2 castles per game
limit araclay 3
limit aradrag 1        // ONE dragon, even though weight=25
limit arafast 4
limit arakeep 2
limit araknigh 16
…

注意这种不对称:aradrag 的权重是 25(高优先级),上限却是 1(永远不超过一个)。TA:K 的 AI 就是这样朝英雄单位发展的——高权重让它早早被建造出来,低上限则让军队构成保持合理。

配置文件统计

default.txt 和战役任务文件都遵循同样的结构:

配置文件 Weight 行数 Limit 行数 plan 数
ai/default.txt 104 104 0
ai/mission06.txt 104 104 0
ai/mission08.txt(Iron Plague 任务) 161 162 0

Iron Plague 的任务文件有更丰富的权重/上限表,因为它们涵盖了基础游戏的 default.txt 所没有的 Creon(CRE 前缀)单位。

kbot 如何处理没有 plan 的文件

kbot-io 的 ai.Parse 把第一行 plan 之前的每一行都放进 AIFile.Preamble,这正是 TA 对待它们的方式(见上文);对于横扫千军:王国的配置文件,ai.ParseWith(data, ai.ParseOptions{DefaultPlan: true}) 会把它们读进一个匹配所有难度的隐式 plan。kbot 的查看器在单独的 Before first plan 标签页中显示它们,并同时说明两件事:TA 在游戏开始时忽略它们,而没有 plan 行的横扫千军:王国配置文件则在每个难度下都应用它们。kbot 没有模拟横扫千军:王国如何应用大于 1 的权重。

ai.IsAIFile() 查看每一行的第一个词:只要某一行以按常规方式书写的指令开头(一行指明 easy、medium、hard 或 any 的 plan,或者值以数字开头的 weight/limit 行),这个文件就是配置文件。这样既能识别没有 plan 的 TAK 配置文件,也能识别用制表符分隔的配置文件,而只是在正文中提到 “weight” 或 “limit” 的 .txt 则不会被误认为配置文件。


坑点

Warning

游戏什么也不报告。 拼错的单位名会被当作一个不匹配任何单位的类别读取,什么也不做;不是数字的值读作 0(于是上限会禁止该目标);第一行 plan 之前的行在游戏开始时会被忽略。配置文件损坏的第一个迹象通常是“AI 行为古怪”。kbot 的查看器会逐一标出这些情况(见下文)。

  • Limit 0,或除 -1 以外的任何负数上限,都会禁止 AI 建造该目标。-1 解除上限。
  • # 在任何位置都会结束一行,即使在一个词的中间;没有块注释。// 之所以能用,只是因为第一个词不是指令的行会被忽略,而值后面多出的词也会被忽略。
  • 大于 1 的权重永远不会让单位超过 100 %。 它只能恢复先前被某个类别权重降低的单位。
  • 第一个指明某单位的行会锁定它。 把针对单个单位的行放在它们要细化的类别行之后。
  • 词与词之间的空白只起分隔作用——制表符、空格、多个空格效果都一样。
  • 不支持嵌套或共享的节。 每个 plan 块都必须重新声明它关心的每一条权重/上限。

kbot 显示什么

studio 的资源浏览器(AI Profile 标签页)和 kbot mount 的 describe 都按游戏的方式读取配置文件:

  • Before first plan——前导部分的行,并注明它们在游戏开始时会被忽略。
  • 每个 plan 一个标签页,每个目标都依据安装目录中的 units/*.fbi(名称和 Category=)标为 unit(单位)、category(类别)或 all units(所有单位)。没有任何单位拥有的类别——拼错的单位名就会被读成这样——会被标为 matches no unit(不匹配任何单位)。权重显示为乘数,并附一个条形,表示一个从 100 % 出发的单位最终剩下的百分比;上限显示为 ∞ Unlimited(不限)、Disabled(禁用,即 0 或除 -1 以外的任何负值)或 Max: N(最多 N 个)。
  • 游戏读法不同的行——kbot-io 的诊断信息,例如不是数字的值词(O 读作 0),或值后面的词。若值词不是游戏所读出的那个数,就会在旁边显示出来(written "O");同一个数的另一种写法,例如 .1 或 0.10,则不会。
  • 游戏开始时(studio;kbot mount 打印计数)——针对 easy、medium 和 hard,列出配置文件改动了其权重或上限的每个单位,被单位行锁定的值带有 🔒。

典型大小

指标 在 Cavedog 配置文件中观察到的范围
文件大小 1–4 KB
每个文件的 plan 数 3(easy/medium/hard)
每个 plan 的 Weight 指令数 20–80
每个 plan 的 Limit 指令数 0–10

另见

  • TDF——选择 AI 配置文件的 .ota 地图元数据。
  • 术语表——阵营(side)、类别(category)。