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 Workshop |
| 实现规模 | 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 机制资料。
从实时输入到回合决策
动作游戏和卡牌 Roguelike 的时间结构完全不同。直接把按键指令照搬成卡牌,只会得到一组需要按顺序打出的“密码牌”,保留了表面形式,却丢失了原作的决策张力。
我把原作机制拆成四个可迁移的设计单位:
| 原作中的体验 | 卡牌系统中的转译 |
|---|---|
| 咏唱需要停下动作并承担风险 | 打出咒文消耗卡牌、能量与本回合行动机会 |
| 咒文暂存在角色身上 | 法印跨卡牌、跨回合保留,等待释放 |
| 元素与修饰咒文可以叠加 | 基础、特性、强化三类法印构成组合语法 |
| 在时限内选择继续准备或立即施法 | 判断继续叠加价值,还是现在释放并清空法印 |
这里保留的是“准备—组合—释放”的节奏,而不是实时按键本身。玩家仍然需要为一次更强的法术提前投入,也仍然可能因为过度准备而失去当下的出牌机会。
法印把组合规则变成可读状态
我将原作咒文拆成三种法印:
- 基础法印决定元素或回复属性:火、冰、雷、风、治疗、再生;
- 特性法印改变生成牌的行为:追踪生成多张可选目标牌,凝聚将效果集中为一张高强度牌;
- 强化法印负责数值放大,并允许逐层积累。
同类法印会替换,不同类型可以同时存在。玩家不用记住长指令,只需要读懂当前三个槽位,就能预测下一次“法术释放”会生成什么。
这里需要区分两种反馈层级:UI 层负责告诉玩家当前法印状态与即将生成的卡牌,视觉特效层则负责把已经完成的法印组合转化为更有冲击力的施法表现。两者读取同一套组合规则,但承担的任务不同:前者帮助玩家做决策,后者提供更丰富、更酷炫的反馈,并在一定程度上还原原作的施法体验。
在 UI 层,法印指示器显示当前三个槽位中的法印图标、强化层数与组合状态,并预览下一次释放实际生成的卡牌。UI 预览和真实结算共用同一套规则,并读取智力、强化层数与古龙契约;VFX 层则在准备、维持和释放阶段持续呈现法阵,并通过元素、特性和强化组合提供更有层次的视觉反馈,在保持酷炫表现的同时部分还原原作的施法体验。
哪些机制被保留,哪些被重新设计
智力与魔法攻击
原作 Witch 的法术成长依赖 INT 与魔法相关属性。在《Slay the Spire 2》中,如果直接复用力量、虚弱和易伤,魔法构筑会很快退化成普通攻击牌的换皮。
因此我建立了独立的智力与魔法攻击规则。智力先加入生成牌的基础值,再参与凝聚和强化倍率;魔法攻击不直接受到力量、虚弱或易伤修正。这样既保留法术成长的身份,也能让预览和实际结算拥有明确顺序。
使魔与龙契约
使魔没有被降级成角色动画。它拥有独立卡牌、休息处成长和战斗状态;古龙契约则把使魔攻击、元素释放与不同减益连接起来。玩家可以围绕法印、使魔或两者的交叉收益构筑。
没有照搬的部分
实时指令、移动限制、法术暂存计时,以及 魔导书 / 魔导具 的完整武器差异都没有被逐字复制。它们在原作中服务于动作操作,但在回合制里会制造额外记忆负担。卡牌、能量、抽牌顺序和回合机会已经提供了新的时间压力,因此迁移重点放在组合结构与释放判断上。
工作流问题:AI 不缺代码能力,缺可靠上下文
《Slay the Spire 2》的 Mod 生态仍在快速变化。游戏本体、BaseLib 与 RitsuLib 的接口版本可能不同,反编译源码、运行时行为、Godot 资源和本地化文本又分散在不同位置。通用模型很容易引用旧版本 API,或写出能够编译但无法被游戏发现的实现。
我的解决方案不是写一份越来越长的提示词,而是逐步建立一套项目级工作流:
设计文档定义行为
↓
只读 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 场景,把每个效果拆成可调试、可复用的模块;我再通过离线 GIF 逐帧检查轮廓、节奏与命中反馈,并决定哪些版本进入游戏。
每个自定义场景都可以通过脚本在独立 Godot 预览环境中运行并录制循环 GIF,不需要启动游戏。确认轮廓、节奏与命中帧后,再打包进 PCK 做游戏内检查。
本地化不是翻译收尾,而是实现规范
模组维护简体中文、英语和日语三套文本。简体中文目录定义完整文件与键集合,其他语言必须保持相同结构。每次机制或术语变化都需要同时检查 DESIGN.md 术语表、卡牌描述和三语 JSON。
自动校验覆盖:
- JSON 解析、重复键和非字符串值;
- 各语言的文件集合与 key 是否一致;
- SmartFormat 动态变量与 formatter 签名是否完全匹配。
数值如果由 {Damage:diff:}、{Amount} 等变量渲染,就不重复修改翻译;新增机制文本则必须同步所有语言。校验会在 Godot PCK 导出前自动执行,使本地化成为构建条件,而不是发布前的人肉检查项。
从实现到发布的安全边界
最终交付链路被拆成几个职责单一的脚本:
- 构建 C# Release 程序集;
- 校验本地化并通过官方 Godot CLI 导出 PCK;
- 安装到独立 Mod 目录进行游戏内验证;
- 生成带版本号的 Release 归档;
- 暂存 Steam Workshop 内容;
- 只有显式提供发布参数与变更说明时才调用官方上传器。
普通构建和 Release 不会联系 Steam。源码 MCP 也不能构建、安装或发布。研究、实现、测试与公开发布分别处于不同权限层级,使 AI 可以积极参与高频开发工作,同时无法越过最后的发布边界。
结果
DMFD Witch Mod 最终交付的是两套彼此支撑的系统。
第一套是角色系统:把原作的实时咏唱、法术组合与释放压力,转译为基础 / 特性 / 强化法印、卡牌准备成本和释放时机,让 Witch 在卡牌 Roguelike 中仍然保持原有的思考方式。
第二套是开发系统:用精确版本 MCP 提供证据,用仓库 Skill 固化经验,用设计文档统一规则,再通过占位图、离线 VFX、本地化校验、运行时测试和显式发布脚本形成可重复的交付流程。
对我而言,这个项目不只是“用 AI 写了一个 Mod”,而是一次关于如何设计 AI 工程环境的实践:让模型更容易得到正确上下文,也让错误更早、更明确地暴露出来。