制作模组
用一个 JSON 文件加入新单位、建筑和升级等级:格式说明、如何在游戏里测试,以及如何发布到模组仓库。
《钢铁浪潮》支持模组。一个模组可以加入单位、建筑和升级等级——写在一个 JSON 文件里,若你画了图,精灵图放在旁边——游戏在“设置 → 模组”里列出它们,旁边就是发布所有人模组的官方仓库。模组不能改动规则、界面或游戏自带的单位:它只做加法,而它加的一切都会随它一起关闭。这正是模组能放心安装、存档能放心读取的原因。
完整参考就在本页,由游戏校验模组时用的同一份表格生成。如果你更愿意把活交给编程智能体,页面底部的说明会告诉它需要知道的一切。
模组是什么
一个文件夹:
my-mod/
mod.json 清单:模组的身份、它的定义,以及定义所用的精灵图
sprites/*.png 可选的图像
README.md 可选
mod.json 先给模组命名,再列出它的定义(每个是一个单位、一座建筑或一个升级等级),如果模组自带图像,再列出精灵图。定义可以带的每个字段都是游戏自身单位定义的字段,所以你能在这个百科页面上读到的任何数值,模组都能设定。
五分钟做出第一个模组
最简单的路径是 extends:从一个原版定义出发,只覆盖你想改的。下面就是一个完整可用的模组——后期用的重型野牛:
{
"format": "steel-tide-mod",
"v": 1,
"id": "bison-ii",
"name": [
"Bison II",
"野牛 II"
],
"version": "1.0.0",
"author": "you",
"description": [
"A heavier Bison for the late game.",
"后期用的重型野牛。"
],
"defs": [
{
"id": "bison2",
"extends": "mbt",
"name": [
"Bison II",
"野牛 II"
],
"desc": [
"Thicker plate, a bigger gun, and a bigger bill.",
"更厚的装甲、更大的炮,也更贵。"
],
"tier": 3,
"cost": 520,
"hp": 1100,
"speed": 52,
"requires": [
"radar"
],
"weapons": [
{
"id": "cannon",
"cls": "cannon",
"dmg": 90,
"reload": 2,
"range": 5,
"splash": 12,
"turret": true,
"muzzleOffset": 23
}
],
"aiWeight": 2
}
]
}- 把它保存为
mod.json,放进一个名为bison-ii的文件夹。 - 在游戏里打开“设置 → 模组”,点打开文件夹…(或者把文件夹压缩后点上传文件…)。游戏会告诉你加载了什么——或者列出哪里有问题,每一条都带着它在
mod.json里的路径。 - 开一局遭遇战。野牛 II 会从二级战车工厂开始出现在生产列表里,因为野牛就在那里生产;它用野牛的图像;而且 AI 也会造它,因为定义带了
aiWeight。
extends 会复制一切——图像、武器、造价、生产位置——你写出的每个字段都替换掉复制的值。不写 weapons 就保留基础单位的武器;写自己的列表就整个替换。
测试
- 打开文件夹…就是编辑循环。在 Chrome 和 Edge 里游戏会记住这个文件夹,改完
mod.json后在该模组那一行点重新读取即可生效。其他浏览器里重新选一次文件夹。 - **上传文件…**接受文件夹的压缩包,或者
.steel-tide-mod文件(内嵌了精灵图的清单——转换器输出的就是这种)。 - **从网址添加…**和
?mod=接受通过网络提供的模组:npx serve --cors my-mod,然后打开https://play.steelti.de/?mod=http://localhost:3000/——每次启动都会重新获取,刷新页面就能看到修改。 - “开发者工具 → 展示台”(开发者模式:连点版本号五次)会把每个单位和建筑,包括你的,摆在同一张地图上,不用建造就能看图像、看开火。
- 控制台(反引号键)里
give <id>可以给出任何定义。
模组适用于遭遇战和战役。联机对战始终不含模组——服务器的单位表是原版的。存档会记住制作时启用的模组,缺了它们就无法读取。
更进一步
一个自带图像、带防御建筑、并为发电厂线加上第四级的模组:
{
"format": "steel-tide-mod",
"v": 1,
"id": "ironworks",
"name": [
"Ironworks",
"铁工厂"
],
"version": "1.0.0",
"author": "you",
"description": [
"A hover tank, a bunker and a fusion plant.",
"一辆悬浮坦克、一座碉堡和一座聚变电站。"
],
"license": "CC-BY-4.0",
"defs": [
{
"id": "ironworks-hover",
"name": [
"Skimmer Hover Tank",
"掠行悬浮坦克"
],
"desc": [
"Fast, thin-skinned, rockets.",
"快、皮薄、打火箭。"
],
"kind": "unit",
"domain": "ground",
"tier": 2,
"cost": 260,
"hp": 320,
"armor": "light",
"speed": 110,
"turnRate": 5,
"radius": 9,
"trail": "tire",
"weapons": [
{
"id": "pods",
"cls": "rocket",
"dmg": 16,
"reload": 2.2,
"range": 4.5,
"burst": 4,
"burstDelay": 0.1,
"splash": 10,
"spread": 14
}
],
"producedBy": [
"factory2",
"factory3"
],
"aiWeight": 1
},
{
"id": "ironworks-bunker",
"name": [
"Bunker",
"碉堡"
],
"desc": [
"A gun pit that takes a beating.",
"扛打的火力点。"
],
"kind": "building",
"cost": 380,
"hp": 1600,
"fw": 2,
"fh": 2,
"power": -3,
"vision": 8,
"weapons": [
{
"id": "gun",
"cls": "autocannon",
"dmg": 22,
"reload": 0.5,
"range": 5,
"turret": false,
"targets": [
"ground",
"ship"
]
}
]
},
{
"id": "ironworks-fusion",
"name": [
"Fusion Plant",
"聚变电站"
],
"desc": [
"The plant line's fourth level.",
"发电厂线的第四级。"
],
"extends": "power3",
"upgradeOf": "power3",
"cost": 2200,
"hp": 2600,
"power": 500,
"upgradeCost": 1100,
"upgradeTime": 60,
"requires": [
"radar",
"reactor"
]
}
],
"sprites": [
{
"key": "u.ironworks-hover",
"file": "sprites/u.ironworks-hover.png",
"frames": 1,
"rotated": true,
"fw": 24,
"fh": 26
},
{
"key": "u.ironworks-bunker",
"file": "sprites/u.ironworks-bunker.png",
"frames": 1
}
]
}计量单位
一格是 32 个世界像素。speed 和弹药 speed 是世界像素/秒;range、minRange、vision、sonar、stealth、detect、repairRange 和 interceptRange 以格计;radius、splash、spread 和 muzzleOffset 以世界像素计;所有时间都是秒。作为参照,野牛主战坦克 的造价 280、生命 620、速度 60、半径 10,主炮每 1.8 秒 60 伤害、射程 4.6;侦察车 造价 60、生命 150、速度 120;战车工厂 占地 3×3、生命 1500、耗电 8。
在哪里生产
- 单位会加入
producedBy中各建筑的生产列表。不写的话,加入其移动域的生产线,从它的等级起:二级地面单位出现在二级和三级战车工厂,一级舰船出现在每座造船厂。用了extends,就在基础单位的生产处生产。 - 建筑由
builtBy中的单位建造——不写就是工程车。带produces列表的建筑就是工厂;单位在producedBy里写了一座普通建筑,也会把它变成工厂。 - 升级等级是带
upgradeOf的建筑:被指名的建筑获得一个升级按钮,花upgradeCost、用upgradeTime秒变成这个定义,而这个定义永远不能直接放置。一座建筑只有一个下一级,所以upgradeOf可以指向原版某条线末端的建筑(power3、factory3、extractor3、gatling、cannonturret2、samsite、interceptor2、radar、repairtower、reactor、nukesilo),或者本模组的另一个定义。 requires列出建造前必须存在的建筑,就像 T3 需要雷达站一样。
图像
定义用 sprite(主体)和 turretSprite(旋转部件)里的图集键来绘制。三种填法:
- **什么都不给。**没有精灵图的定义会画成阵营色的简单占位图,大小按定义——图还没画好,模组就能玩。
- 借用。
"sprite": "u.mbt", "turretSprite": "tur.mbt"用野牛的图像;extends继承基础单位的图像。 - **自己画。**每张精灵图一个
sprites条目:一张 PNG(WebP 和 JPEG 也行),frames帧动画从左到右横向排列,等距、无缝隙。主体的键是u.<id>,炮塔的键是tur.<id>,模组不能占用原版的键。
车体、炮塔以及一切会转向的东西都是一张朝上的图加 "rotated": true——游戏会烘焙 24 个朝向。fw/fh 是这张图在游戏内的世界像素尺寸(坦克车体约 24×24;按 2–4 倍画,加载器会重采样)。pivotX/pivotY 把旋转枢轴放到炮塔座圈上。
建筑是不旋转的帧序列,以略带南向倾斜的俯视角绘制:占地是帧底部 fw×32 × fh×32 像素的区域,上面多出的部分会遮住后方地形。宽、高和锚点会按定义的占地自动确定。
阵营色是品红:用 #FF66FF、#FF00FF 和 #990099 涂阵营色部件,其他地方不要用品红;游戏会按玩家重新着色。生成的图片在加载时会被清理——去背景、对齐帧、冻结静态像素——所以透明背景最好,但不是必须。
AI
AI 对手会按 aiWeight 生产模组单位,量表和原版一致(野牛是 3,侦察车 1),前提是 requires 已满足。不写就永远不造。建筑和升级等级只有你自己会用。
参考
表格之外的字段会被忽略并给出提示;超出范围的数字是错误。
mod.json
| 字段 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
| format | string | 必填 | 固定为 "steel-tide-mod" | |
| v | integer 1–1 | 必填 | 格式版本,1 | |
| id | id | 必填 | 模组 id:小写字母、数字和 `-`,也是它在仓库中的文件夹名 | |
| name | text | 必填 | 模组列表中显示的名称 | |
| version | string | 必填 | 如 `1.0.0`;仓库版本更新时游戏会提示更新 | |
| author | string | 作者 | ||
| description | text | 一两句话的介绍 | ||
| homepage | string | 主页链接 | ||
| license | string | CC-BY-4.0 | 模组许可证(SPDX 标识) | |
| minGame | string | 所需的最低游戏版本 | ||
| defs | def[] | 必填 | 单位、建筑与升级等级 | |
| sprites | sheet[] | 各定义使用的精灵图(见下) | ||
| files | { path: dataURL } | 仅单文件形式:按路径内嵌的图片(data URL) |
name、description 以及定义的 name/desc 都是文本:一个字符串(两种语言共用)、["English", "中文"],或 { "en": "…", "zh": "…" }。
定义(defs[])
| 字段 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
| id | id | 必填 | 在所有模组和原版中唯一;通用名字前加上模组 id 前缀 | |
| name | text | 必填 | HUD 中显示的名称 | |
| desc | text | "" | 提示中的描述 | |
| extends | id | 要复制的原版定义 id(或本模组中前面的定义),再逐字段覆盖;继承其图像和生产位置 | ||
| kind | unit | building | 必填 | 单位或建筑(除非 `extends` 已说明,否则必填) | |
| domain | ground | ship | air | 仅单位 | ground | 移动域;潜艇是带 `underwater` 的 `ship` |
| tier | integer 1–3 | 1 | 出现的工厂等级与徽标 | |
| cost | number 0–99999 | 必填 | 金属造价 | |
| buildTime | number 0–3600 | cost ÷ 14 | 满电力下的建造秒数 | |
| pop | integer 0–50 | 1 for a unit, 0 for a building | 占用人口 | |
| hp | number 1–1000000 | 必填 | 生命值 | |
| armor | light | medium | heavy | ship | sub | air | structure | by domain | 武器倍率所针对的装甲类型 | |
| speed | number 0–1000 | 仅单位 | 60 | 世界像素/秒(一格 32) |
| turnRate | number 0–50 | 仅单位 | 3.5 | 弧度/秒 |
| vision | number 0–64 | 8 | 视野(格) | |
| radius | number 1–200 | 9, or the footprint | 碰撞半径(世界像素) | |
| weapons | weapon[] | [] | 武器列表(见下);空列表即无武装 | |
| fw | integer 1–8 | 仅建筑 | 2 | 占地宽度(格) |
| fh | integer 1–8 | 仅建筑 | 2 | 占地高度(格) |
| producedBy | id[] | 仅单位 | the line for its domain, from its tier up | 加入哪些建筑的生产列表(原版或本模组的) |
| produces | id[] | 仅建筑 | 工厂:可生产的单位 | |
| builtBy | id[] | 仅建筑 | ["engineer"] | 可建造它的工程单位 |
| builds | id[] | 仅单位 | 工程单位:可建造的建筑 | |
| buildRate | number 0–10000 | 仅单位 | 工程单位:每秒建造量 | |
| power | number -10000–10000 | 0 | 正为发电,负为耗电 | |
| metalRate | number 0–1000 | 仅建筑 | 每秒金属(采矿场) | |
| needsDeposit | boolean | 仅建筑 | 必须建在矿点上 | |
| repairRange | number 0–64 | 仅建筑 | 维修光环范围(格) | |
| repairRate | number 0–10000 | 仅建筑 | 每目标每秒维修量 | |
| repairTargets | integer 1–50 | 仅建筑 | 同时维修的目标数 | |
| upgradeOf | id | 仅建筑 | 作为哪座建筑的下一等级;那座建筑获得升级按钮 | |
| upgradeCost | number 0–99999 | 仅建筑 | cost − the source's cost | 配合 `upgradeOf`:升级价格 |
| upgradeTime | number 0–3600 | 仅建筑 | buildTime | 配合 `upgradeOf`:升级秒数 |
| requires | id[] | 建造前必须存在的建筑 id | ||
| nukeCapacity | integer 0–10 | 发射器:可储存的弹头数 | ||
| nukeCost | number 0–99999 | 发射器:每枚弹头的金属 | ||
| nukeTime | number 0–3600 | 发射器:每枚弹头的秒数 | ||
| interceptRange | number 0–64 | 拦截:范围(格) | ||
| interceptMag | integer 1–200 | 拦截:备弹数 | ||
| interceptReload | number 0.05–600 | 拦截:每发补充秒数 | ||
| interceptMuzzleOffset | number 0–200 | 拦截:发射器长度(世界像素) | ||
| transportCap | integer 1–50 | 仅单位 | 运输载具:载重 | |
| landsForCargo | boolean | 仅单位 | 装卸时降落的运输机 | |
| cargoWeight | number 0–50 | 仅单位 | pop | 占用的载重 |
| underwater | boolean | 仅单位 | 潜艇:仅声呐可见 | |
| sonar | number 0–64 | 仅单位 | 声呐范围(格) | |
| stealth | number 0–64 | 仅单位 | 仅在敌方此距离内可见 | |
| detect | number 0–64 | 仅建筑 | 在此范围内揭示隐形 | |
| hovers | boolean | 仅单位 | 悬停而非盘旋的飞行器 | |
| altitude | number 0–64 | 仅单位 | 12 | 飞行器的绘制高度(像素) |
| fireOnMove | boolean | 仅单位 | 移动时持续开火 | |
| trail | tread | tire | wake | 仅单位 | by domain | 留下的痕迹 |
| sprite | string | this mod's u.<id> sheet, else the base's art | 主体图像键:本模组的精灵图,或借用原版的键 | |
| turretSprite | string | this mod's tur.<id> sheet, else the base's (when its art is kept) | 旋转部件的图像键(若有) | |
| aliases | string[] | 控制台 `give` 接受的别名 | ||
| aiWeight | number 0–10 | 仅单位 | 0 | AI 生产它的倾向——野牛是 3,侦察车 1;0 为从不 |
没有 extends 时的默认值:单位是 domain: "ground"、tier: 1、pop: 1、speed: 60、turnRate: 3.5、vision: 8、radius: 9,装甲按移动域(地面 medium、舰船 ship、空中 air),陆地留履带痕、海上留尾迹;建筑是 fw: 2, fh: 2、armor: "structure"、power: 0、pop: 0。buildTime 默认为造价 ÷ 14 秒。
武器(defs[].weapons[])
| 字段 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
| id | string | w1, w2… | 武器名 | |
| cls | mg | autocannon | cannon | at | he | rocket | navgun | ashm | torpedo | aa | 必填 | 设计用途——决定装甲倍率表中的行 | |
| dmg | number 0–100000 | 必填 | 每次命中伤害 | |
| reload | number 0.05–600 | 必填 | 两次射击/齐射间隔秒数 | |
| range | number 0.5–64 | 必填 | 射程(格) | |
| minRange | number 0–64 | 最小射程(格) | ||
| projectile | bullet | shell | missile | rocket | bomb | torpedo | flak | by class | 弹药样式 | |
| speed | number 1–5000 | by projectile | 弹速(世界像素/秒) | |
| targets | (ground | ship | sub | air)[] | by class | 可攻击目标:ground、ship、sub、air | |
| mult | { armour: number } | 按装甲类型覆盖倍率 | ||
| splash | number 0–500 | 溅射半径(世界像素) | ||
| burst | integer 1–32 | 每次齐射发数 | ||
| burstDelay | number 0–5 | 齐射内各发间隔秒数 | ||
| homing | boolean | 弹药追踪目标 | ||
| interceptable | boolean | 可被拦截 | ||
| arc | boolean | 抛物线弹道(火炮) | ||
| turret | boolean | true when the def has a turretSprite | 由旋转部件发射 | |
| muzzleOffset | number 0–200 | 枢轴到炮口距离(世界像素) | ||
| spread | number 0–200 | 最大射程处的散布(世界像素) | ||
| friendlyFire | boolean | 溅射也会伤及己方 | ||
| sound | mg | autocannon | cannon | missile | flak | arty | rocket | torpedo | bomb | by class | 开火音效 |
伤害 = dmg × 装甲倍率表中该武器类型对目标装甲的格子,mult 可覆盖单个格子。克制体系解释了各类型;倍率表如下:
| 武器 | 轻甲 | 中甲 | 重甲 | 建筑 | 舰船 | 潜艇 | 飞行器 |
|---|---|---|---|---|---|---|---|
| ×1.50 | ×0.80 | ×0.40 | ×0.35 | — | — | — | |
| ×1.50 | ×1 | ×0.50 | ×0.50 | ×0.70 | — | — | |
| ×0.60 | ×1.30 | ×1 | ×0.80 | ×0.90 | — | — | |
| ×0.60 | ×1.30 | ×1.10 | ×1 | ×0.90 | — | — | |
| ×0.40 | ×1.10 | ×1.80 | ×0.70 | ×1 | — | — | |
| — | — | — | — | — | — | ×1 | |
| — | — | — | — | — | — | ×1 | |
| ×1.20 | ×1 | ×0.75 | ×1.60 | ×1 | — | — | |
| ×1.20 | ×1 | ×0.75 | ×1.60 | ×1 | — | — | |
| ×1.20 | ×1 | ×0.60 | ×1.60 | ×1 | — | — | |
| ×1.50 | ×1 | ×0.50 | ×0.50 | ×0.80 | — | — | |
| — | — | — | — | ×1.60 | — | — | |
| ×1 | ×1 | ×0.75 | ×0.75 | ×1 | — | ×1 | |
| ×1 | ×1.10 | ×0.80 | ×0.80 | ×1 | ×1.90 | — | |
| — | — | — | — | ×1.30 | ×1.20 | — | |
| ×1.20 | ×1 | ×1 | ×1.60 | ×1.20 | — | — | |
| ×1.20 | ×1 | ×0.75 | ×1.60 | — | — | — | |
| — | — | — | — | — | — | ×1 | |
| ×0.60 | ×1.10 | ×1.80 | ×0.80 | ×1 | — | — | |
| ×1.40 | ×1.40 | ×0.90 | ×0.70 | ×0.90 | — | — | |
| — | — | — | — | ×1.70 | — | — | |
| ×1.20 | ×1.20 | ×1 | ×1.60 | ×1.10 | — | — | |
| ×1.20 | ×1.20 | ×1.10 | ×1 | ×1 | — | — | |
| ×1 | ×0.90 | ×0.60 | ×1.60 | ×1 | — | — | |
| — | — | — | — | ×0.90 | ×1.80 | — | |
| ×1.50 | ×0.80 | ×0.40 | ×0.30 | ×0.60 | — | ×0.70 | |
| ×1.50 | ×0.90 | ×0.50 | ×0.30 | ×0.70 | — | ×0.80 | |
| ×0.60 | ×1.30 | ×1.10 | ×0.60 | ×1 | — | — | |
| ×0.60 | ×1.30 | ×1.20 | ×0.60 | ×1.10 | — | — | |
| — | — | — | — | — | — | ×1 | |
| — | — | — | — | — | — | ×1 |
精灵图(sprites[])
| 字段 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
| key | string | 必填 | 主体用 `u.<id>`,旋转部件用 `tur.<id>`;不可与原版键重名 | |
| file | string | 必填 | 图片路径,相对 mod.json(PNG、WebP 或 JPEG) | |
| frames | integer 1–64 | 1 | 动画帧数,横向排列 | |
| fw | number 4–512 | the footprint (a building) or the image | 游戏内帧宽(世界像素) | |
| fh | number 4–512 | 游戏内帧高(世界像素) | ||
| rotated | boolean | 一张朝上的图;游戏烘焙 24 个朝向(车体、炮塔) | ||
| pivotX | number 0–1 | 0.5 | 旋转枢轴(帧宽比例) | |
| pivotY | number 0–1 | 0.5 | 旋转枢轴(帧高比例) | |
| anchorY | number 0–512 | 顶部到占地中心的像素(高建筑) | ||
| mount | [x, y] | 主体:炮塔安装位置 `[fx, fy]` | ||
| fps | number 0–60 | 动画速度 | ||
| teams | boolean | true | 按阵营重着色品红部分 | |
| ss | integer 1–4 | 超采样倍率;留空由游戏决定 | ||
| fitFootprint | boolean | 缩放内容以填满帧 | ||
| animRegion | [x0, y0, x1, y1] | 动画所在区域 `[x0, y0, x1, y1]`(比例);其余部分冻结 | ||
| stabilize | boolean | true | 对齐漂移的帧 | |
| freezeStatic | boolean | 冻结几乎不变的像素 | ||
| stripBg | boolean | 强制开启/关闭背景去除 | ||
| bgMinLuma | number 0–255 | 仍视为背景的最亮颜色 | ||
| artifactCleanup | boolean | 清理背景去除后的杂点 |
发布
模组仓库是公开的 rivertwilight/steel-tide-mods:每个模组是 mods/<id>/ 下的一个文件夹,游戏和本站列出其中的全部内容。
- Fork 仓库,把你的文件夹加为
mods/<id>/——文件夹名就是模组的id。 - 运行
node tools/check.mjs mods/<id>。它会打印游戏会报的每一个错误,并把文件夹和已发布的所有模组对照检查:id 是全局的,所以通用的词要加上模组 id 前缀(用ironworks-bunker,不用bunker)。 - 提交 Pull Request。CI 会跑同样的检查;合并后索引重建,模组就出现在游戏的仓库列表和模组页面上。
- 每次改动都提升
version。游戏会向装了该模组的人提示更新。
模组按清单里写的许可证发布(不写则为 CC-BY-4.0)。只发布你有权使用的图像。
转换 Rusted Warfare 模组
转换器接受一个 Rusted Warfare 自定义单位模组——.rwmod、压缩包或单位文件夹——输出一个钢铁浪潮模组:.ini 变成定义,图片变成精灵图,绿色阵营色变成品红。造价、生命、速度和射程会按比例缩放,使 RW 的坦克接近野牛的水平(也可以选择逐单位忠实换算)。它在浏览器里运行,不上传任何东西。转换后请检查清单:特效、动画、护盾和能量在这里没有对应物。
给编程智能体
模组仓库自带一个技能(skill)——完整格式、如何测试模组、如何发布,按 Claude Code、Cursor、Codex 等智能体读取的形式写好。用 skills 安装:
npx skills add rivertwilight/steel-tide-mods --skill steel-tide-mods-guideline
然后让你的智能体做一个模组。在仓库的克隆里工作时,智能体会读到同样内容的 AGENTS.md;能读网址的工具也可以取 steelti.de/mods/AGENTS.md 的纯文本。
