真言符文 - 强力对话补丁工具

真言符文 - 强力对话补丁工具

运行时对话规则引擎 — 有条件、轮换、有状态的非玩家角色(NPC)台词,无需使用 Content Patcher

模组工具

真言符文:对话导演

条件性。循环性。状态化。对话规则引擎。

场地

每个NPC放置一个JSON文件,即可完全控制他们的对话内容。规则可响应邮件标记、好感度、季节、星期几、节日、NPC所在位置,甚至玩家在一小时前选择的$q选项——对话还能产生反馈:提出分支问题、给予礼物、设置标记。引擎会在每一次交互时重新解析规则——无需等待天数切换,也无需存档重载。

游戏内设置 (GMCM)

游戏内设置截图

所有设置均可通过游戏内操作切换,无需编辑config.json文件。

与内容补丁模组兼容运行

真符文:对话导演是一个 额外 引擎。你现有的 Content Patcher 对话模组仍可正常运行——你 无需 迁移任何内容。请参阅下方“与 Content Patcher 协同工作”部分查看测试示例。

TRD在内容补丁的编辑数据对话/基础上新增的内容

  • 实时评估。 设置一个标记 → 下次点击时,新行被触发。
  • 内置优先级和循环功能。 将三个问候语设置为相同优先级,它们会自动洗牌并循环。
  • 最大使用次数限额。 “每个存档显示一次”是一个整数字段——会为你持久化到存档文件中。
  • 跨NPC好感度门槛。海莉的台词会随艾米莉的好感度变化。CP不支持此功能。
  • 答案历史门。 后续对话只有在玩家之前选择了分支A时才会触发。
  • 节日对话。 可选的节日台词——寻蛋活动的闲聊、花舞节舞伴台词、冬日星庆典的祝酒词——而不干扰预设的仪式脚本。CP无法像TRD那样替换节日自由漫游时的闲谈。
  • 互动问题、礼物及副作用。 通过纯JSON键(question、gift、set_flags、actions)编写分支$q问题,给予玩家物品、设置标志或增加金钱——这些键会自动编译成星露谷物语的确切标记符。
  • 他们在哪儿的大门。 发射一条线,因为某个NPC此刻正站在海滩——或者因为他们的日程安排今天早些时候就已经带他们去了那里。
  • 开发者友好的JSON格式。 字段名称描述其功能。无令牌、无When子句、无补丁指令。
  • AI友好。 完整编写指南已包含在压缩包内——将其与你的概要一起粘贴到Claude/ChatGPT中,即可得到可运行的JSON文件。

混凝土对比 — CP与TRD中的同三条线

将以下三句Haley的雨日台词来自一个真实的Content Patcher模组(Canon-Friendly Dialogue Expansion):

"CFE_Haley_rainy_1": "我花了一整个早上弄头发……现在这场雨可能全毁了。$s#$e#*叹气*……人生有时候真难啊。"
"CFE_Haley_rainy_2": "哎呀。不是故意冒犯,但你全身都湿透了。"
"CFE_Haley_rainy_3": "*叹气* 想想看...此刻地球另一端的人们正在阳光明媚的海滩上呢。$s"

…在content.json中与以下内容连线:

{
"LogName": "CFE_Haley_Include"
"动作": "包含",
"FromFile": "Data/NPCs/Haley.json",
"当":
{
"查询:'{{CFE_Haley}}' = 'true' 或 ('{{CFE_Haley}}' = 'random' 且 '{{Random: true, false}}' = 'true')" : true
}
}

这部分难以说明的是:

  • 玩家今天实际上会看到哪条线?(随机性存在于其他地方的一个{{Random}}标记中——你需要追踪标记才能知道。)
  • 单个行能否限制为“每个存档最多显示一次”?(非原生支持 — 你需要自定义存档数据标记或其它模组。)
  • 第二行能否设定为“仅当确实下雨且是星期二且玩家拥有4颗以上心”时触发?(可以,但你需堆叠更多当子句和标记。)
  • 这三行能否[轮换](每行在重复前各发射一次),而不是纯随机且可能重复?(除非有外部记录,否则不行。)

与TRD包相同的三行规则:

{
"npc": "海莉",
"replacements": {
"rainy": [
{
"id": "haley_rainy_hair"
"priority": 10,
"min_heart": 2,
"weather": "rain",
"text": "我花了一整个早上整理头发……现在下雨可能会把它弄乱。$s#$e#*叹气* ……生活有时真不容易。"
},
{
"id": "haley_rainy_soaked",
"priority": 10,
"weather": "rain",
"最大使用次数": 3,
"text": "哎呀。无意冒犯,但你全身都湿透了。"
},
{
"id": "haley_rainy_beaches"
"priority": 10,
"weather": "rain",
"date": { "days_of_week": ["星期二"] },
"text": "*叹气* 想想看...现在世界其他地方的阳光沙滩上还有人呢。$s"
}
]
}
}

无需编写任何额外逻辑就能获得的内容:

  • 每种状况都存在于它所限制的那一行中。 无需跨文件追踪令牌——只需阅读一条规则,便能确切知晓其触发时机。
  • 旋转是自动的。 三者均处于优先级10,因此它们进入一个旋转池:洗牌一次,然后循环——没有立即重复。
  • 每行使用次数上限。 max_uses: 3 位于“soaked”行上,表示在整个存档中最多触发3次,之后永久失效。该设置已保存到存档文件中。
  • 自由混合门控条件。 心数最低值、天气、星期、邮件标记以及跨NPC心数条件,都可以通过纯字段名称叠加在同一规则中。
  • 对话窗口节流。 默认情况下,每个NPC在每个游戏时间窗口内最多显示3条触发回复对话(TRD)行,之后将回退至原版模式——可通过config.json中的MaxLinesPerConversationWindow进行配置,单个规则也可使用force_show选择退出。

这是头条胜利:你可以阅读一条规则并立即知道它有什么作用,而游戏引擎会为你处理旋转和配额记账。

与 Content Patcher 模组配合使用

如果TRD为当前上下文找到匹配的规则,该行会生效。如果TRD中没有任何内容匹配,游戏会回退到内容补丁(或原版星露谷物语)本应显示的内容。你可以保留所有已有的CP对话模组——TRD只是在它们之上叠加一层。

工作测试 — 雨天星期二,与海莉交谈

设置:

  • 佳能友好对话扩展 (一个内容补丁模组)已安装,新增了三条可能的雨天对话:
"CFE_Haley_rainy_1": "我花了一整个早上打理头发……现在这雨可能会把它弄乱。$s#$e#*叹气* ……生活有时真难啊。"
"CFE_Haley_rainy_2": "哎呀。无意冒犯,但你全身湿透了。"
"CFE_Haley_rainy_3": "*叹息* 想想看……此刻世界上其他地方正有人躺在阳光明媚的海滩上呢。$s"
  • 一个TRD内容包,包含一条规则:
{
"npc": "海莉",
"title": "覆盖每个对话指导功能的实例。"
"替换项": {
"_smoke_test": [
{
"id": "smoke_test_always_on"
"priority": 1,
"max_uses": 1,
"text": "$h[示例包] 你好@!如果你看到这一行,说明真符文:对话导演正在工作。"
}
]
}
}

结果1 — TRD规则匹配,TRD获胜:

TRD规则匹配

“[样本包] 你好 @!...” — TRD 找到了匹配的规则,因此它覆盖了 CP 和原版内容。

结果2 — TRD无匹配(最大使用次数耗尽),回退至内容修补器(Content Patcher):

回退至CP

最大使用次数已用完,TRD没有符合条件的项目——因此显示CFE内容补丁行。

结果3 — 既没有匹配到TRD,也没有匹配到任何CP模组,回退至原版星露谷物语对话:

回退至原版

最终备选方案:原始游戏台词,未经修改。

简明概要 — 如果TRD规则匹配,则执行该规则。否则,游戏会按照未安装TRD时的原样进行,包括任何内容补丁的修改。

一个注意事项——你无法在同一个内容包文件夹内混合使用TRD和CP规则。 一个SMAPI清单只能声明一个ContentPackFor目标。内容补丁包需要:

"ContentPackFor": { "UniqueID": "Pathoschild.ContentPatcher" }

……以及TRD包需要:

"ContentPackFor": { "UniqueID": "Riou.TrueRune.Dialogue", "MinimumVersion": "1.0.0" }

如果你想同时安装这两个,只需将两个文件夹并排放在同一个 zip 文件中——玩家把这两个文件夹都放入 Mods/ 目录,它们会正常共存。

节日对话 — 不破坏节日

节日对话通常是大多数对话模组无能为力的地方。星露谷通过不同的代码路径处理节日对话,因此普通的编辑根本无法生效。TRD也勾住了那条路径——但处理得十分谨慎:

  • 按规则选择参与。 一个规则只有在标记为"festivals": true(任何节日)或列出特定的"festival_ids": ["spring24"]时,才会在节日中发言。你的日常台词永远不混入节日,节日的台词也永远不会泄露到普通日子。
  • 仪式保持神圣。 只有自由交流的社交环节有所调整。舞蹈、品汤、寻蛋倒计时——完全保持游戏原样。
  • 问题仍可正常运作。 花舞节“…邀请我做你的舞伴吗?”提示 — 以及所有节日中$q问题 — 始终会原样显示,因此玩家仍可回答。TRD仅替换了其周围的闲聊内容,从不改动问题本身。
  • 被选中的时刻台词。 is_dance_partner: true 仅在玩家选择该NPC作为花舞节舞伴后触发——因此你可以写一句特别的“你和我,舞池中央”的回复,这是普通节日台词永远不会出现的场景。
  • 全局开关。 EnableDuringFestivals(GMCM,默认开启)一键关闭所有内容。
{
"id": "haley_flowerdance_partner"
"festival_ids": ["spring24"]
"is_dance_partner": true,
"priority": 10,
"text": "$l 你和我,在舞池中央。可别踩到我的脚,@!"
}

支持的节日ID: spring13 (复活节), spring24 (花舞节), summer11 (夏威夷宴会), summer28 (月光水母起舞), fall16 (丰收节), fall27 (亡灵节), winter8 (冰雪节), winter25 (冬日星盛宴)。

互动问答、礼物与副作用

一行不必只是一行。TRD让规则执行操作——向玩家提出分支问题、交给物品、设置故事标记、掉落金币——所有这些都来自可读的JSON键,编译后为你生成精确的星露谷物语代币。无需手写密集的$q/$r/$action字符串。

{
"id": "haley_beach_invite",
"priority": 80,
"force_show": true,
"text": "……好吧。随便问个问题,别搞得太奇怪。$7"
"question": {
"prompt": "自由的春日下午——海滩,还是被困在室内?"
"answers": [
{ "id": "98010", "text": "和你一起的海滩。", "friendship": 20, "reply": "...回答得不错。$l" }
{ "id": "98011", "text": "在里面,跟上进度。", "friendship": -10, "reply": "...无药可救。$u", "reask": true }
]
}
"gift": "392"
"set_flags": ["MyMod_asked_to_beach"]
"actions": ["增加金币 500"]
}
  • 问题 — 一个完整的分支提示,包含每个答案的友谊变化和行内回复。引擎会生成$q ID列表,填充回复内容,并自动抑制重复询问。在“拒绝”答案中标记"reask": true以持续提示。
  • 礼物 — 在行结束时给予一个物品。纯ID → 一个物体;像(BC)13这样的限定ID则会通过。
  • set_flags — 设置邮件标记,以便后续规则(您或其他规则包的)能立即触发。
  • 行动 — 其他所有情况的退路:增加金钱、增加任务、增加特殊订单、增加对话话题等等。

在星期一回答一个问题,然后一个基于answered_question_ids的后续规则可以在几天后对该选择做出反应。这就是有状态的、分支式对话——用非程序员也能读懂的JSON格式。

安装后即可立即生效

框架示例

该框架附带了一个适用于Robin的小规则,以便在安装任何内容包之前确认引擎是否正常运行。

作者快速入门指南

你的内容包只是一个包含清单文件和 TrueRune/dialogue/ 子文件夹的文件夹:

MyDialoguePack/
├── manifest.json   (内容包用于: "Riou.TrueRune.Dialogue")
└── TrueRune/
└── dialogue/
└── Haley.json

TrueRune/伞状结构将所有True Rune Toolkit子系统整合在一个文件夹下。如果你的资源包还包含了TrueRune/events/,事件框架会通过交叉发现机制自动识别这些内容——你只需声明一次ContentPackFor。

一个最小可行性的Haley.json:

{
"npc": "海莉",
"替换内容": [
{
"id": "spring_morning"
"priority": 5,
"min_heart": 4,
"date": { "seasons": ["春天"] }
"text": "$h 春天的早晨最棒了,@!"
}
]
}

将文件放入 星露谷物语/模组/ → 启动 → 与海莉对话。整个过程就是这样循环的。

示例对话

你的游戏内对白,依据好感度等级和季节触发——无需额外前提。

模式参考

  • id — 用于日志记录、旋转和最大使用次数跟踪的标识符
  • 优先级 — 数值高者胜出。平局则进入轮流顺序。
  • 文本 — 带有头像代码的对话($h $u $l $7 $12…)
  • 问题 — 分支 $q/$r 提示,每个答案都有好感度 + 内联回复
  • gift / set_flags / actions — 当该行结束时,给予物品、设置标记或运行$action副作用
  • required_AND_flags / required_OR_flags / forbidden_flags — 通过玩家邮件标记进行门控
  • 已答题ID / 禁答题ID — 根据过往 $q/$r 选择进行筛选
  • min_heart / max_heart — 与该NPC的好感度等级
  • npc_heart_conditions — 与其他NPC的好感度
  • npc_current_location_conditions — 当前NPC正站在某个位置
  • npc_current_schedule_conditions — 一名NPC按照日程今天前往某地点(可选时间窗口)
  • date — 季节 + 星期 + 日 + 年 窗口
  • 性别 — 将某一行限制为玩家的性别(男性 / 女性)。省略则无限制。
  • 节日 / 节日ID / 是否是舞伴 — 将规则应用于节日(任意或特定节日)及花舞节舞伴场景
  • max_uses — 使用寿命次数上限(存档永久生效)
  • force_show — 跳过每个NPC对话窗口的限制

完整的示例涵盖了仓库中 samples/Sample-EmilyDialoguePack/ 内的所有功能。完整的架构文档位于压缩包内的 docs/DIALOGUE_AUTHORING.md 中。

安装

  1. 安装 SMAPI 4.0+
  2. 推荐: 通用模组配置菜单 用于游戏内设置页面
  3. 将解压后的文件夹放入 Stardew Valley/Mods/
  4. 安装任何需要此框架的内容包

控制台命令(前缀 rune_dlg_)

· rune_dlg_reload · 符文对话列表 [NPC] · rune_dlg_try <NPC> · rune_dlg_clearusage · 标志/答案解锁:使用原版 debug seenMail / debug question

在 SMAPI 控制台中输入 help rune_dlg_<name> 以了解使用方法。

C# 应用程序编程接口

var api = Helper.ModRegistry.GetApi<IDialogueDirectorApi>("Riou.TrueRune.Dialogue");
api.RegisterRules("Haley", myRules, ownerUniqueId: ModManifest.UniqueID);

兼容性与权限

SMAPI 4.0+ / Stardew Valley 1.6+. 可与 Content Patcher 和自定义NPC框架(SVE、Ridgeside、East Scarp)一起使用。MIT许可 — 无需询问即可作为依赖使用,可自由分支,欢迎翻译。

真符文工具包的一部分

  • 真符文:事件 — 具有分支、子事件、片段的JSON核心事件
  • 真·符文:模组工具包 — 头像查看器 + NPC枚举 + 标记操控
  • 真·刻印:日程导演(即将推出)——条件性NPC日程