Files
ichni_Official/docs/story-variable-registry.md
SoulliesOfficial fe00ecfcc7 微调
2026-07-24 03:43:11 -04:00

232 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ichni Official 剧情变量登记表
> 状态:**长期维护文档**
> 适用范围:`ichni Official` 全部章节的正式剧情变量。
> 维护原则:每当场景卡批准新增变量时,必须按照变量在剧情中**首次写入的顺序**登记;不得等到 Yarn 或 StoryData 已大量使用后再补记。
> 当前内容只登记已经确认并实际进入正式 Yarn 的变量,不预先虚构未来章节的变量。
## 一、文档用途
本登记表是剧情作者、Yarn 编写者、StoryData 配置人员、本地化人员与程序员共同使用的变量来源。它用于回答:
- 变量的稳定 Key 是什么;
- 变量首次出现在哪个 Chapter、场景、TextBlock 与 Yarn 文件;
- 变量使用何种类型和默认值;
- 每个合法取值代表什么;
- 哪些 Yarn Node 写入或读取变量;
- 哪些 StoryData Block 使用变量作为 UnlockForbidden 条件;
- Timeline 回滚会怎样处理该变量;
- 变量当前处于计划、已使用、废弃还是迁移状态。
本登记表不替代场景卡或 StoryData。场景卡解释叙事意图StoryData 保存运行时初始值与条件;本登记表负责让所有使用者对同一个 Key 保持一致理解。
## 二、纳入与排除范围
### 必须登记
- 通过 `set_bool``set_int``set_float``set_string` 写入的章节剧情变量;
- 通过 `add_int``add_float` 累积的章节数值;
- 被 Yarn `if`、StoryData `Unlock Condition``Forbidden Condition` 或 Helper Availability 读取的剧情变量;
- 为存档迁移而保留的旧变量与替代 Key。
### 不在本表登记
- Yarn 选项记忆:由 `StoryChoiceMemory` 根据 Option Line ID 自动保存;
- Block 完成状态:由章节存档的 `completedBlockIds` 保存;
- Timeline Marker ID 与 checkpoint登记在场景卡和 StoryData
- Localization Key
- `grant_unlock`、歌曲解锁、教程解锁等全局 Unlock Key
- Settings、歌曲成绩、`isTried` 或其它非剧情变量;
- `C0_RollbackDemo_*` 等测试 Yarn 中的示例变量;
- 废弃旧稿 `C0_A0.yarn` 中的 Yarn 原生 `$variable`
## 三、命名规范
### Key 格式
- 使用小写英文、数字与下划线:`^[a-z0-9_]+$`
- 使用章节前缀Chapter 0 为 `c0_`Chapter 1 为 `c1_`,依此类推。
- Key 表达稳定的剧情语义不使用具体台词、UI 文案或临时 Node 名。
- 路线变量使用 `_route` 后缀,例如 `c0_contract_route`
- 状态变量使用能够直接读懂的过去式或状态名;只有正式批准后才可确定实际 Key、登记并使用。
- 计数或强度必须在名称中表明语义,例如未来可能出现的 `_count``_level``_trust`;不得使用 `value1``temp``flag` 等含义不明的 Key。
### 一项语义只保留一个变量
不要同时创建 `c0_contract_route``c0_contract_accepted` 来表达同一选择。能够用一个枚举式 `Int` 完整表达的互斥路线,不再增加重复 Bool。
### Key 稳定性
变量进入正式存档以后不得只为了“更好看”而重命名。确需改名时:
1. 在本表把旧 Key 标记为 `Deprecated`
2. 登记新 Key、迁移规则和首次生效版本
3. 完成 Story Save migration
4. 同步修改 Yarn、StoryData Conditions、Helper 条件和测试;
5. 确认旧存档迁移后再停止读取旧 Key。
## 四、类型、默认值与命令
| 类型 | 未配置时读取回退 | 正式写入 | 读取 | 累加 | 适用内容 |
|---|---:|---|---|---|---|
| `Bool` | `false` | `<<set_bool "key" true>>` | `get_bool("key")` | 无 | 已发生/未发生、二态状态 |
| `Int` | `0` | `<<set_int "key" 1>>` | `get_int("key")` | `<<add_int "key" 1>>` | 路线编号、整数计数、离散等级 |
| `Float` | `0f` | `<<set_float "key" 0.5>>` | `get_float("key")` | `<<add_float "key" 0.1>>` | 连续强度或比例 |
| `String` | `""` | `<<set_string "key" "value">>` | `get_string("key")` | 无 | 稳定文本 ID 或不能用数字表达的状态 |
虽然运行时在缺少定义时存在回退值,**每个正式变量仍必须在对应 Chapter 的 StoryData Initial Variables 中显式配置类型与默认值**。不得依赖隐式 `0/false/""` 掩盖漏配。
其它可用接口:
```yarn
<<remove_variable "key">>
<<if has_variable("key")>>
// 该 Key 存在已保存值,或已在 StoryData Initial Variables 中定义。
<<endif>>
```
`has_variable("key")` 会把 StoryData Initial Variable 也视为存在。由于正式变量都应显式配置初始值,它通常会从章节开始便返回 `true`,不能用于判断“玩家是否已经在剧情中写入过这个变量”。若确实需要记录事件是否发生,应创建语义明确的 Bool而不是依赖变量是否存在。
正式剧情不得使用:
```yarn
<<declare $variable = 0>>
<<set $variable = 1>>
```
这些 Yarn 原生变量不受当前章节事务、StoryData 条件和 Timeline 回滚系统统一管理。
## 五、存档与回滚规则
- 剧情变量属于当前 `StoryData.chapterIndex` 对应的章节存档;不同章节完全隔离。
- TextBlock 开始时建立章节事务。`set_*``add_*` 在对话内更新当前章节状态,但只有对话正常结束才提交存档。
- 玩家使用 Back 中途退出 TextBlock 时,本次变量变化、选项记忆与 Block 进度全部恢复到进入前状态。
- Timeline Marker checkpoint 保存进入目标列以前的章节变量快照。回滚后,目标列及右侧剧情产生的变量变化被撤销。
- Timeline 回滚不会修改歌曲成绩、Settings、全局 Unlock Key 或其它章节进度。
- 如果变量控制互斥路线,所有相关 Block 必须同时配置相反的 Unlock 与 Forbidden 条件,不能只在 Yarn 内写 `if`
## 六、按剧情顺序登记
### Chapter 0
| 顺序 | 首次写入场景 | Variable Key | 类型 | 默认值 | 合法值/范围 | 意义 | 写入位置 | 读取位置 | 回滚点 | 状态 |
|---|---|---|---|---:|---|---|---|---|---|---|
| `C0-001` | `C0-S03` 契约抉择与镜的降临 | `c0_contract_route` | `Int` | `0` | `0` 未选择;`1` 接受;`2` 拒绝 | 记录曦对神之契约的最终选择,并控制接受主线与拒绝彩蛋的互斥开放 | `C0_ContractDecision.yarn`:接受/拒绝二次确认后各写入一次 | StoryData`c0_public_disclosure``c0_refusal_ending` | `c0_contract_decision_checkpoint`;回滚后恢复为 `0` | Yarn 已使用StoryData 待配置 |
### Chapter 1 及以后
尚未开始登记。未来变量在所属场景卡批准后,按首次写入的剧情顺序添加到对应 Chapter 小节;不得提前创建占位 Key。
## 七、当前变量详细说明
### `c0_contract_route`
#### 叙事意义
该变量只表达曦是否接受神的契约,是 Chapter 0 当前唯一正式剧情变量:
| 值 | 叙事状态 | 可进入 Block | 必须 Forbidden 的 Block |
|---:|---|---|---|
| `0` | 尚未作出选择 | `c0_contract_decision` | 无;两个后续均保持 Locked |
| `1` | 接受契约 | `c0_public_disclosure` | `c0_refusal_ending` |
| `2` | 拒绝契约 | `c0_refusal_ending` | `c0_public_disclosure` |
#### StoryData Initial Variable
```text
Key: c0_contract_route
Type: Int
Default: 0
```
#### Yarn 写入
接受二次确认以后:
```yarn
<<set_int "c0_contract_route" 1>>
```
拒绝二次确认以后:
```yarn
<<set_int "c0_contract_route" 2>>
```
不得在 C0-S01、C0-S02 或玩家尚未完成二次确认时提前写入路线值。
#### StoryData 条件
`c0_public_disclosure`
```text
Unlock Condition: c0_contract_route == 1
Forbidden Condition: c0_contract_route == 2
```
`c0_refusal_ending`
```text
Unlock Condition: c0_contract_route == 2
Forbidden Condition: c0_contract_route == 1
```
#### 回滚行为
Timeline Marker `c0_contract_decision_checkpoint` 锚定 `c0_contract_decision`,保存进入抉择以前的快照。玩家从任一路线回滚后:
- `c0_contract_route` 恢复为 `0`
- 接受/拒绝选项记忆被清除;
- 该列及右侧 Block 完成状态被恢复;
- 两个互斥后续重新按未选择状态计算。
## 八、新增变量登记模板
未来新增变量时,先在所属场景卡确认叙事必要性,再复制以下模板到相应 Chapter 小节,并插入正确的剧情位置:
```markdown
| `C?-???` | `C?-S??` 场景名 | `c?_stable_key` | `Bool/Int/Float/String` | 默认值 | 合法值/范围 | 一句话语义 | 首次写入 Yarn/Node | Yarn/StoryData/Helper 读取位置 | 最近相关 Marker | Planned/Active/Deprecated |
```
同时补充详细说明:
```markdown
### `c?_stable_key`
- 叙事意义:
- 为什么不能使用现有变量或选项记忆:
- StoryData Initial Variable
- 首次写入时机:
- 所有合法值:
- Yarn 读取:
- StoryData UnlockForbidden
- Helper 条件:
- Timeline 回滚预期:
- 兼容/迁移要求:
```
## 九、变量新增检查清单
- [ ] 变量确实需要跨 Node、跨 TextBlock 或驱动 StoryDataHelper单纯控制同一 Node 内一句台词时不滥用持久变量。
- [ ] Key 使用正确章节前缀和 snake_case。
- [ ] 没有与既有变量表达重复语义。
- [ ] 类型与默认值已经在场景卡和 StoryData 中明确。
- [ ] 所有合法值均有解释,没有未定义的魔法数字。
- [ ] Yarn 只使用项目 `set_*``get_*``add_*` 接口。
- [ ] 写入发生在玩家真正确认以后,不会因预览选项提前改变路线。
- [ ] 互斥 Block 同时配置 Unlock 和 Forbidden。
- [ ] Back 中断与 Timeline 回滚行为已经说明。
- [ ] 不把 Localization Key、Unlock Key、Block ID 或 Option Memory 错记为剧情变量。
- [ ] 变量进入正式存档后,任何重命名都配套 migration。
- [ ] 本登记表中的剧情顺序与正式场景卡、Yarn 和 StoryData 一致。
## 十、维护流程
1. **前置信息讨论**:判断是否真的需要持久变量。
2. **场景卡阶段**:确定 Key、类型、默认值、合法值、首次写入点和回滚预期。
3. **场景卡批准后**:立即把变量按剧情顺序登记到本文档。
4. **Yarn 编写阶段**:严格使用登记 Key如发现语义不足返回场景卡讨论不在脚本中临时创造近义变量。
5. **StoryData 集成阶段**:配置 Initial Variable、UnlockForbiddenHelper 条件,并把登记状态更新为 `Active`
6. **回归测试阶段**:验证新档、对话 Back、已完成 TextBlock 回顾、互斥路线和 Timeline 回滚。
7. **发布后修改**:任何 Key、类型或语义变更都必须登记 migration 与版本影响。