规则集的层、翻译与迁移

本页介绍如何提供玩家为单局游戏开启的变体、如何翻译规则集的文本,以及人物卡变更时如何把已保存的值移到新 ID。本页面向规则集作者。开始之前,先读编写 Game Mode 规则集。

层:规则集自身的变体

层是规则集的具名变体,由玩家创建游戏时开启,例如 Low magic、Hard winter,或更残酷的难度。层位于规则集文件的可选 layers 数组中,因此随文件一起流转,不会从使用过它的游戏中丢失。向导在规则集下将其显示为开关,选择与规则集本身一样,在游戏整个生命周期中固定。

"layers": [
  {
    "id": "hard_winter",
    "label": "Hard winter",
    "summary": "Cold, hunger and short days. Everything is harder.",
    "conflicts": ["mud_season"],
    "gm": {
      "guidance": "Hard winter is on. Let a failed check cost warmth, food or daylight as well as progress.",
      "worldGuidance": "Hard winter is on. Build a world of closed roads, thin stores and rationed settlements."
    },
    "fields": [{ "id": "calling", "removeValues": ["Sailor"], "default": "Hauler" }],
    "difficultyLadder": [{ "label": "Easy", "dc": 7 }],
    "catalogs": [{ "id": "knacks", "hide": { "filter": "grit", "above": 0 } }]
  },
  {
    "id": "mud_season",
    "label": "Mud season",
    "summary": "Thaw, flooded roads and slow going."
  }
]

层能做什么。 列表是封闭的,每个效果要么缩小范围,要么添加文本:

"items": {
  "market": { "removeSellers": ["magic_dealer", "scribe"], "unsold": [{ "tag": "magical" }] },
  "lootTables": [{ "id": "treasure_low", "label": "Pocket treasure", "entries": [{ "coins": "sp", "weight": 1, "count": "4d6" }] }]
}

层不能做什么。 不能添加枚举值、字段、技能、池或休息,不能添加卖家或战利品表,不能改变结算类型、触及实时状态或战斗数值,也不能增加模型调用。层所_添加_的值,对人物卡的其他读取者都会是未知值,因此只能移除值。超出这份列表的内容,应当修改规则集本身,或成为第二个规则集。

冲突。 conflicts 指定不能同时开启的层。只在成对关系的一侧声明就够了。向导会禁用另一个开关;如果保存的选择不知为何包含两者,就丢弃声明较晚的那个,因此相同的两个选择总会得到相同规则。

已经持有被移除值的人物卡会保留它。 不会重写角色。编辑器停止提供该值,而已经拥有它的角色仍按原值显示。在新游戏中关闭该层后,该值又能选择。隐藏的目录条目也一样:只从选择器中排除,玩家已经选择的行仍留在人物卡上。层所移除、但已有人携带的钱币,仍留在其背包里。

限制。 每个规则集最多 12 个层,每层两段指引字符串合计最多 4000 字符。声明 layers 或基础 gm.worldGuidance 的打包规则集需要 Capability API 1.25,层会移除钱币的规则集需要 1.64,层会更改其 items 的规则集需要 1.813。导入的规则集由读取它的 Engine 验证,因此不需要这项声明。

其他人编写的层(例如为不是自己编写的规则集提供独立文件的 Low Magic 层)会在以后添加。目前层随其所属规则集一起提供。

翻译

译文(Capability API 1.811)。规则集以其他语言显示的字符串,每种语言对应一份译文,像 Engine 自身的语言包一样,以语言代码命名(ru、pt-BR、zh-Hans)。在官方智能体目录中,每份译文都是一个语言包,与规则集文件并列(见下文)。分享的规则集包文件也可以改为把译文放在内部,每种语言一个文件,与 ruleset.json 并列:locales/<language>.json,像其他文件一样列入清单。无论采用哪种方式,每份译文都是带有 ruleset 部分的包本地化目录:每个键都是规则集或其目录中的一个显示字符串,必须与英文逐字一致,值则是该字符串在文件所用语言中的译文。

{
  "_meta": { "locale": "ru", "direction": "ltr" },
  "package": { "name": "5e (SRD 5.1)" },
  "ruleset": { "Prone": "Лежащий", "Fire Bolt": "Огненный снаряд", "Goblin": "Гоблин" }
}

_meta.locale 必须是文件名指定的语言,文件只包含 $schema、_meta、package 和 ruleset,不能有其他内容,所有值都是文本。字符串留空表示尚未翻译,会显示英文;没有 ruleset 部分的文件(包自身的英文介绍,locales/en.json)不会翻译任何内容。译文只用于显示:规则、人物卡命令以及告知游戏主持人(GM)的所有内容仍读取英文。战斗界面(名称、状态、行动、法术、日志和行动顺序)中的每个字符串,如果规则集译文中有对应翻译,就以玩家的语言显示,先查找该语言自身的文件,再查找其基础语言的文件(pt-BR 的基础语言是 pt),否则显示英文;“Goblin 2”使用“Goblin”的译文并附上其数字。带有译文的包文件需要 Capability API 1.811。导入时只保留 Engine 当前设置的语言(或其基础语言)的译文,其余丢弃;要以另一种语言阅读规则集,先切换 Engine 的语言,再次导入文件,新译文会替换原先保留的译文。译文不属于版本的一部分,因此用修正后的译文再次导入相同版本,也会替换原译文;导入不带译文的同版本文件则保留已有译文。

目录中的规则集绝不能在其文件内部携带 locales/<language>.json(携带此文件的规则集会在下载前被拒绝)。其译文以语言包形式提供(Capability API 1.811):每种语言一个 JSON 文件,命名为 <id>-<version>.<language>.json,与 <id>-<version>.ruleset.json 并列发布,内容与 locales/<language>.json 完全相同(_meta.locale 为文件名指定的语言,并带有 ruleset 部分)。目录条目将这些语言包与其 artifact 并列列出:

"locales": {
  "ru": {
    "url": "https://raw.githubusercontent.com/Pasta-Devs/Marinara-Agents/main/artifacts/ember-roads-1.0.0.ru.json",
    "sha256": "<64 hex>",
    "bytes": 812345,
    "name": "Угольные дороги",
    "description": "<the store card's description in Russian>"
  }
}

每个语言包都是一个与产物 URL 格式相同的 https URL,以其版本和语言命名,并带有其 sha256 和大小(最多 8 MB);一个规则集最多列出 40 个语言包,绝不能列出 en(规则集本身就是英文),其清单须声明 Capability API 1.811。name 和 description 是该语言的商店卡片名称和描述,因此无需获取语言包,卡片就能以 Engine 的语言显示。安装时先获取规则集文件,再只获取 Engine 当前设置的语言(或其基础语言)的语言包,检查其大小、校验和及语言,并将其与已安装版本一起保留。Engine 的语言改变时(以及每次在 Engine 中打开页面时),每个已安装且在目录中列有新语言对应语言包的规则集都会获取该语言包,并移除旧语言的语言包。无法获取语言包时(离线、未列出语言包,或获取的文件不是目录所列文件),规则集显示英文;下次安装或切换语言时会重试。更新时会保留上一版本以供回滚,但不保留其语言包:回滚后,下次切换语言时,如果目录仍列有该版本的语言包,就会再次获取。

把值移到新 ID:sheet.migrations

添加内容不需要任何额外操作。当新布局把某个值移到别处时(重命名的字段、变为每个职业一个等级的单一等级、变为每种骰子一个池的单一生命骰池),请在 sheet.migrations(Capability API 1.77) 中说明如何移动,让每个按旧布局创建的角色都保留其数值:在角色库中、在游戏中、在旧存档、分支和检查点中,以及在导入的角色卡中。

"migrations": [
  {
    "from": 3,
    "steps": [
      { "rename": "field", "from": "xp", "to": "experience" },
      {
        "route": "level",
        "by": "class",
        "cases": [
          { "words": ["fighter"], "to": "level_fighter" },
          { "words": ["wizard"], "to": "level_wizard" }
        ],
        "else": "level_other",
        "default": 1
      },
      {
        "routeLive": "pool",
        "from": "hit_dice",
        "cases": ["hit_dice_d6", "hit_dice_d8", "hit_dice_d10", "hit_dice_d12"],
        "else": "hit_dice_d8"
      }
    ]
  }
]