首页 › 模组制作 › 制作变异器
第 03 章

制作变异器

叠在基础游戏或任意模组上的小型 .oamut:文件夹、清单、mutate 返回的计划、选项、沙箱,以及多个变异器叠加时的生效顺序。

本章概述 docs/mutators/authoring.md 和 docs/mutators/oamut-standard.md。

变异器是什么

变异器是一个小型 .oamut 包,叠在基础游戏或任意模组之上。它改变的是一局。资料库按清单的标识把它装进 Mutators 文件夹,安装本身并不启用它。玩家在遭遇战、战斗室或战役开始前启用它。works-with 说明它适合哪些模组,星号表示任意模组和基础游戏。

包

文件夹顶层是 oamut.yaml。入口脚本放在它旁边:默认是 mutator.lua,entry 可以另指一个,但从不放在 files/、rules/ 或 lua/ 下面。lua/ 放其他 Lua 源码,require 只读取这些文件。files/ 放文件层可以加入的字节。rules/ 放名字以 .sm 结尾的规则文件。图标是清单点名的 PNG。名字以 .md 或 .txt 结尾的说明是给人看的,游戏不加载它。这份清单以外的文件会被拒绝。比较时忽略 ASCII 字母的大小写。

my-mutator.oamut玩家拿到的文件├─ oamut.yaml必需 清单├─ mutator.lua入口脚本 mutate(ctx)├─ lua/可选;Lua 模块,require 只读取这些文件├─ files/可选;模型、脚本和其他字节├─ rules/可选;.sm 规则文件├─ icon.png可选;icon 点名的 PNG└─ README.md说明;游戏不加载它

清单

严格 YAML,规则与模组配置相同:一份文档、一个顶层映射、没有锚点、没有块标量。文件以整数 1 的 oamut 开头。标准没有列出的键会被拒绝。以大于号开头的值要加引号,星号也要加引号,否则读取器会把它当成别的东西。因此 requires.engine 要加引号。版本也要加引号:裸数字会被拒绝。

键必填作用
oamut是格式。整数 1。1.0 以及加引号的 1 都会被拒绝。
id是小写 kebab-case,1 到 64 字节。不能以连字符开头、结尾,也不能有连续连字符。安装文件夹的名字。
name是1 到 64 字节,不能有控制字符。玩家看到的名字。
version是加引号,最多 32 字节。一到三段,用点连接,每段是 0 到 65535 的数,不能有前导零。
author是一个映射。name 必填,1 到 128 字节。email 可选。
description否可选,1 到 2,000 字节。允许换行。第一行截到 200 字节,就是目录显示的摘要。
homepage否可选,1 到 256 字节。一个 http 或 https 地址。
icon否可选。包内一张正方形 PNG 的路径,以 .png 结尾。安装器会检查图片。
tags是一到四个标识,不能重复。资料库会画图标的八个列在下面。
works-with是1 到 32 个条件,标识不重复。星号表示任意模组和基础游戏,并且这时它是唯一一条。ta-3.1c 表示没有模组的基础游戏。其他标识是模组,可以带版本范围。
requires否可选。只能有 engine 和 mutators。engine 是针对本构建的加引号范围。mutators 列出必须启用的包;它们在本包之前生效,顺序就是写下来的顺序。
conflicts-with否可选。本包拒绝与之同时运行的变异器。这里的标识不能是 requires.mutators 点过名的,也不能是本包自己的标识。
layers是一到九个名字,不重复:files、units、weapons、features、sides、tables、menus、maps 和 hacks。计划只能写这里点了名的层。
clashes否可选,add 或 replace:游戏里已有同名的单位或武器时,这个变异器怎么处理。先看玩家的选择,再看这个键,最后看偏好设置 mutators.clash-default,未设置时为 replace。
options否可选,最多 16 个。玩家在对局前选择的设置。ctx.options 读取它们。
strings否可选,最多 16 个语言标记。名称、描述和选项标签的翻译。
entry否可选。入口脚本,包内以 .lua 结尾的路径,不在 files/、rules/ 或 lua/ 下。不写这个键时为 mutator.lua。
legacy否可选,1 到 16 条本包所取代的 TA: Mutation 变异器记录。每条是 name、prefix、compatibility 和 files。单独一个映射会被拒绝。

八个标签

读取器接受任意小写 kebab-case 标签,1 到 32 字节,最多四个。资料库为这八个标识画出图标和翻译后的名称,必须完全一致。其他标识按原文显示,没有自己的图标。清单没有指定图标时,如果第一个标签是这八个之一,徽章就用它的图标。

键作用
statistics统计
economy经济
commanders指挥官
new-units新单位
disable禁用
gameplay玩法
aiAI
maps地图

计划

入口定义 mutate。引擎在计划阶段调用一次 mutate(ctx),这次调用本身不改变游戏。mutate 返回一张表。空表什么也不改。引擎不认识的键会被拒绝。

files 是一张含 add 和 mask 的表。各自是一列文本,都可以不写。add 按顺序点名包里的文件夹,两个文件夹都有的路径以后面的为准。mask 隐藏路径。rules 是一列完成的块,用 where、all、named 或 on 再接 :change 做成,以及用 sm 点名的 .sm 文件路径。一种改动是 set、scale、lock、remove 或 append。scale 可以带下限和上限,这个界限只约束这一次因子。钩子是函数。它们按这个顺序运行:units、weapons、features、sides、tables,然后 menus。maps 在每一个变异器之后运行,并且只有对局选定了地图时才运行。hacks 为这一局设置注册表向变异器开放的一个参数。声明了对应的层,才允许写入。

选项与 ctx

在 mutate 期间,ctx 持有模组(标识、版本和游戏)、引擎版本、选项和 ctx.incompatible。没有模组时 ctx.mod.id 是 ta-3.1c。用一个理由调用 ctx.incompatible 会停掉这个变异器,理由就是玩家看到的文字。集合这时还没加载。钩子可以在 ctx 上读取 units、weapons、features、sides、tables 和 menus,不必声明对应的层。写入则需要声明那一层。

ctx.options 为每个选项标识放一个字段。开关是 true 或 false。数字,以及取值是数字的选择,是一个数。取值是标识符的选择是文本。玩家没动过的选项就是默认值。type 是 toggle、choice 或 number。选择列出 2 到 16 个 values,要么全是数字,要么全是标识符,词语和值不同时再列 labels。数字有 min、max、step 和 default。玩家只能选 min 到 max 之间落在步长上的值,所以脚本不必再检查范围:不落在步长上的值会在脚本运行前被拒绝。选项标识是一个 Lua 名字,Lua 关键字会被拒绝。

沙箱

脚本作为 Lua 在一个沙箱里运行。它没有文件、没有网络、没有时钟、没有环境、也没有进程。io、os、debug、package 和 coroutine 不会打开,预编译的代码块会被拒绝。每一块都是源码。两个变异器不共享状态。

每个阶段都从完整的指令额度重新开始,5,000 万条,以及完整的 10 秒实时上限。内存上限是 64 MiB,不会在下一阶段重新发给脚本。一条字符串最多 65,536 字节。脚本算出的数值用 fixed。它以 65,536 分之一计数,因此同一份脚本在每台机器上写出相同的文本。pairs 按固定顺序走键。结果不取决于机器。

叠放

玩家按一个顺序排列变异器,从上到下生效。第一个先生效。后面的每一个看到的游戏,是它上面那些留下的样子。requires.mutators 点名的变异器会和本包一起启用,并且在本包之前生效,顺序就是列表写下的顺序。超过 32 个、一个标识出现两次、上面没有任何一个满足的前提,或者两个互相冲突,都会拒绝整份列表,什么也不运行。

每个变异器的文件先按列表顺序分层,后面的变异器赢得同一条路径。然后每个变异器按同样的顺序,把自己的单位、武器和下载文件读成记录,应用规则,再运行钩子。规则一次应用一个改动,顺序固定。一个因子乘上当前的数,钳制只约束这一个因子,不约束后来的因子。赋值替换当前的值。锁定会设定值,并让之后的每个变异器都改不了那个字段。在一个 Lua 块里,改动按字段名的 ASCII 小写顺序运行,不是按表写下来的顺序。变异器之间不做平均。所有变异器都应用完之后,超出游戏所存储宽度的单位或武器数值,以及超出游戏读取范围的地物数值,会一次性停在那个范围的端点。