DMFD Witch Mod
把动作游戏的咏唱系统迁移到卡牌 Roguelike,并建立一套可验证的 AI 辅助 Mod 开发工作流
我把《Dragon Marked for Death》中的 Witch 搬进了玩法完全不同的《Slay the Spire 2》。项目聚焦于两个核心问题:
- 如何识别一个动作游戏角色真正不可替代的部分,并把它转译成卡牌 Roguelike 的决策?
- 如何让 AI 在资料零散、接口变化快、视觉与本地化工作量都很大的 Mod 项目中稳定协作?
前一个问题决定角色是否仍然是 Witch,后一个问题决定这个角色能否被完整做出来、验证并持续发布。
| 项目维度 | 内容 |
|---|---|
| 职责 | 系统转译、游戏设计、AI 开发工作流、C# / Godot 实现、测试与发布 |
| 技术栈 | C# / .NET 9、Godot 4.5、Harmony、BaseLib、Python、PowerShell |
| 交付状态 | 已发布至 Steam 创意工坊 |
| 实现规模 | 201 个 C# 文件、约 14,340 行 C#、106 个卡牌类 |
说明: DMFD Witch Mod 是非官方同人模组,与《Slay the Spire 2》《Dragon Marked for Death》的开发商及发行商不存在隶属或合作关系。相关原作名称与角色归其权利方所有。
系统转译:从实时咏唱到回合决策
先理解原作:Witch 的核心在于咏唱决策
《Dragon Marked for Death》是一款横版动作 RPG。原作 Witch 的主要输出始于咏唱状态:玩家输入不同按键序列,将元素、强化、追踪或凝聚等咒文暂存起来,最后释放组合后的法术。
这套系统有几个关键特征:
- 施法需要准备。 咏唱期间无法自由移动,输入和释放时机本身就是风险;
- 法术可以组合。 元素决定基本类型,强化(Power-Up)提升等级,追踪(Homing)改变索敌方式,凝聚(Condense)牺牲范围换取集中与多段效果;
- 暂存会形成压力。 已完成的魔法需要在时限内释放,但继续输入新的咒文又能延长并改造它;
- 元素可以替换,修饰可以保留。 玩家可以根据敌人属性改变元素,而不用丢掉已经准备好的强化或特性;
- 使魔与龙契约参与构筑。 契约会影响特定元素、法术暂存和使魔攻击方式,使角色身份不只存在于咏唱本身。
因此,Witch 最具辨识度的是施法过程:
先准备法术,再组合属性,在风险与收益之间决定何时释放。
这也是我选择迁移的核心。原作机制参考了 Dragon Marked for Death 官方介绍 与 Witch Wiki。
将实时输入转化为回合内的决策单位
动作游戏和卡牌 Roguelike 的时间结构完全不同。直接把按键指令照搬成卡牌,只会得到一组需要按顺序打出的“密码牌”,保留了表面形式,却丢失了原作的决策张力。
我把原作机制拆成四个可迁移的设计单位:
| 原作中的体验 | 卡牌系统中的转译 |
|---|---|
| 咏唱需要停下动作并承担风险 | 打出咒文消耗卡牌、能量与本回合行动机会 |
| 咒文暂存在角色身上 | 法印跨卡牌、跨回合保留,等待释放 |
| 元素与修饰咒文可以叠加 | 基础、特性、强化三类法印构成组合语法 |
| 在时限内选择继续准备或立即施法 | 判断继续叠加价值,还是现在释放并清空法印 |
迁移后保留了“准备—组合—释放”的节奏,并将实时按键转化为回合内的决策。玩家仍然需要为一次更强的法术提前投入,也仍然可能因为过度准备而失去当下的出牌机会。
法印系统:把组合规则变成可读状态
我将原作咒文拆成三种法印:
- 基础法印决定元素或回复属性:火、冰、雷、风、治疗、再生;
- 特性法印改变生成牌的行为:追踪生成多张可选目标牌,凝聚将效果集中为一张高强度牌;
- 强化法印负责数值放大,并允许逐层积累。
同类法印会替换,不同类型可以同时存在。玩家不用记住长指令,只需要读懂当前三个槽位,就能预测下一次“法术释放”会生成什么。
同一套法印规则同时驱动两个反馈层级:UI 层负责辅助决策,视觉特效(VFX)层负责还原施法表现。
在 UI 决策层,法印指示器直接展示当前三个槽位的图标、强化层数与组合状态,并实时预览下一次释放将生成的卡牌。UI 预览与真实结算共用同一套计算管线,会实时计入智力、强化层数与古龙契约修正,确保玩家看到的预览数值就是打出去的真实效果。
在 VFX 表现层,法阵会在咏唱准备与法印维持期间持续存在于角色脚下,通过颜色表达基础法印、中心符号表达特性法印,并在释放瞬间配合攻击动画完成视觉反馈,在卡牌战斗中还原原作蓄力施法的演出感。
取舍:哪些机制被保留,哪些被重构
- 独立的智力与魔法攻击:原作 Witch 的法术成长依赖 INT 与魔法属性。在《Slay the Spire 2》中,如果直接复用力量、虚弱和易伤,魔法构筑很快会退化成普通攻击牌的换皮。因此我建立了独立的智力与魔法攻击规则——智力先加入生成牌的基础值,再参与凝聚和强化倍率;魔法攻击不受力量、虚弱或易伤修正。这样既立住了法术成长的独特身份,也让预览与结算具备清晰的先后顺序。
- 可构筑的使魔与龙契约:使魔没有被降级成纯背景动画,而是拥有独立卡牌、休息处成长和战斗状态;古龙契约则把使魔攻击、元素释放与不同减益连接起来,让玩家可以围绕法印、使魔或两者的交叉收益进行构筑。
- 主动舍弃的实时操作负担:原作中的实时按键、移动限制、暂存倒计时以及魔导书 / 魔导具的完整武器差异都没有被照搬。它们在原作中服务于动作博弈,但在回合制里只会制造额外的记忆负担——卡牌、能量、抽牌顺序和出牌机会已经提供了充足的回合制压力,迁移重点应当留在组合结构与释放判断上。
AI 工程工作流:为模型构建可靠的上下文与验证闭环
《Slay the Spire 2》的 Mod 生态仍在快速变化。游戏本体、BaseLib 与 RitsuLib 的接口版本可能不同,反编译源码、运行时行为、Godot 资源和本地化文本又分散在不同位置。通用模型很容易引用旧版本 API,或写出能够编译但无法被游戏发现的实现。
AI 并不缺写代码的能力,缺的是可靠的上下文与及时的反馈闭环。为此,我逐步建立了一套项目级工作流:
设计文档定义行为
↓
只读 MCP 查询精确版本源码
↓
仓库 Skill 提供领域规则与检查清单
↓
C# / Godot / 本地化并行实现
↓
占位图与离线 VFX 先验证完整性
↓
自动校验、游戏内测试、打包与显式发布
改造 MCP:从“万能工具箱”收敛为只读证据层
我基于社区的 STS2 Modding MCP 做了定制,将原本同时覆盖代码生成、部署、游戏控制和资源处理的工具,收敛为一个只读源码研究服务。
它只回答三类问题:
- 当前游戏版本中的类型、方法和继承关系是什么;
- BaseLib / RitsuLib 当前项目实际依赖版本提供了什么 API;
- 某个 Hook、符号或调用关系的源码证据在哪里。
服务索引反编译后的游戏 C# 源码,并为 BaseLib、RitsuLib 记录包版本、目标游戏 API、提交与缓存时间。MCP 对外只保留 11 个查询工具,构建、安装、PCK 打包、进程控制和素材生成全部移出 MCP,交回项目脚本与官方工具链。
这个改造解决了两个问题:一是防止 AI 把不同版本的 API 混在一起;二是建立清晰权限边界——源码研究可以自动进行,发布和运行时操作不能被一次查询顺带触发。
编写仓库 Skill:把踩过的坑变成可复用流程
MCP 能提供源码,但不会自动知道项目自己的约束。我把反复出现的经验整理为仓库级 Skill,让 Codex 与 OpenCode 在进入具体任务前加载对应规则:
| Skill | 解决的问题 |
|---|---|
| Modding Pitfalls | 卡牌注册、SmartFormat、预览变量、程序集命名等容易静默失败的问题 |
| DMFD Witch Localization | 三语文件、术语表、动态变量与占位符如何同步 |
| Godot Packaging | DLL、PCK、安装目录与 Workshop 发布边界 |
| STS2 VFX Style | 赛璐璐色带、轮廓、命中帧和离线预览规范 |
| KitLib Testing | 如何在明确授权的测试局中记录操作前后状态并恢复快照 |
这些 Skill 是带有入口条件、硬规则、脚本路径和验收标准的操作说明。它们采用渐进披露:先读任务所需的短规则,再按问题进入本地化、VFX、打包或运行时测试细节,减少一次性上下文负担。
同时,DESIGN.md 被设为机制与术语的权威来源。代码、测试、本地化和 Workshop 文案都必须回到同一份设计定义,避免 AI 在不同文件中逐渐创造出互相矛盾的规则。
占位图管线:先让系统完整,再逐步替换美术
卡牌系统需要在美术完成前就验证牌池、升级、预览和战斗流程。为此我编写了占位图生成脚本:每张卡使用固定缩写和按类别区分的渐变色,普通卡与 Ancient 卡输出不同尺寸,并自动生成全量 contact sheet。
脚本还维护一份受保护的正式美术清单。批量生成时,如果正式图片意外丢失,流程会直接失败,以防占位图覆盖正式资源。这让占位素材既能加速早期开发,也不会在后期污染已完成的资源。
离线 VFX 预览:把视觉迭代变成可重复测试
VFX 同样没有依赖“进游戏看看,不对再重来”的长反馈链。我把 C# 与 Godot 的职责拆开:C# 负责实例化、目标、伤害结算和时序,GDScript 与 Shader 负责形状、粒子、位移与销毁。
仓库中的 VFX Skill 固定了视觉语言:硬轮廓、窄色带、清晰白色核心和短促命中反馈,避免与游戏背景混在一起的柔软发光。伤害帧必须与白闪、形变、星爆和震屏发生在同一时刻。
在此基础上,VFX 采用 AI 辅助的程序化流程:AI 根据统一的视觉规范生成与修改 GDScript、Shader、粒子参数和 Godot 场景;每个自定义场景都可以直接通过脚本在独立的 Godot 预览环境中运行并自动录制循环 GIF,无需启动游戏。我只需通过离线 GIF 逐帧验收轮廓、节奏与命中帧,确认达标后再打包进 PCK 做游戏内检查。
本地化校验与发布安全边界
模组维护简体中文、英语和日语三套文本。简体中文目录定义完整文件与键集合,其他语言必须保持相同结构。每次机制或术语变化都需要同时检查 DESIGN.md 术语表、卡牌描述和三语 JSON。
自动校验会在 Godot PCK 导出前自动执行,把本地化变成硬性的构建条件,取代发布前的人肉检查:
- JSON 解析、重复键和非字符串值;
- 各语言的文件集合与 key 是否一致;
- SmartFormat 动态变量(如
{Damage:diff:}、{Amount})与 formatter 签名是否完全匹配。
最终交付链路也被拆成职责单一的脚本,研究、实现、测试与公开发布各自处于不同的权限层级:
- 构建 C# Release 程序集;
- 校验本地化并通过官方 Godot CLI 导出 PCK;
- 安装到独立 Mod 目录进行游戏内验证;
- 生成带版本号的 Release 归档;
- 暂存 Steam Workshop 内容;
- 只有显式提供发布参数与变更说明时,才调用官方上传器。
普通构建不会触碰 Steam,只读源码 MCP 也无法触发构建或安装。这让 AI 可以放手参与高频开发工作,同时绝无可能越过最后的公开发布边界。
结果
DMFD Witch Mod 最终交付的是两套彼此支撑的系统。
第一套是角色系统:把原作的实时咏唱、法术组合与释放压力,转译为基础 / 特性 / 强化法印、卡牌准备成本和释放时机,让 Witch 在卡牌 Roguelike 中仍然保持原有的思考方式。
第二套是开发系统:用精确版本 MCP 提供证据,用仓库 Skill 固化经验,用设计文档统一规则,再通过占位图、离线 VFX、本地化校验、运行时测试和显式发布脚本形成可重复的交付流程。
对我而言,这个项目不只是“用 AI 写了一个 Mod”,而是一次关于如何设计 AI 工程环境的实践:让模型更容易得到正确上下文,也让错误更早、更明确地暴露出来。