# ichni Official 剧情变量登记表 > 状态:**长期维护文档** > 适用范围:`ichni Official` 全部章节的正式剧情变量。 > 维护原则:每当场景卡批准新增变量时,必须按照变量在剧情中**首次写入的顺序**登记;不得等到 Yarn 或 StoryData 已大量使用后再补记。 > 当前内容只登记已经确认并实际进入正式 Yarn 的变量,不预先虚构未来章节的变量。 ## 一、文档用途 本登记表是剧情作者、Yarn 编写者、StoryData 配置人员、本地化人员与程序员共同使用的变量来源。它用于回答: - 变量的稳定 Key 是什么; - 变量首次出现在哪个 Chapter、场景、TextBlock 与 Yarn 文件; - 变量使用何种类型和默认值; - 每个合法取值代表什么; - 哪些 Yarn Node 写入或读取变量; - 哪些 StoryData Block 使用变量作为 Unlock/Forbidden 条件; - 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` | `<>` | `get_bool("key")` | 无 | 已发生/未发生、二态状态 | | `Int` | `0` | `<>` | `get_int("key")` | `<>` | 路线编号、整数计数、离散等级 | | `Float` | `0f` | `<>` | `get_float("key")` | `<>` | 连续强度或比例 | | `String` | `""` | `<>` | `get_string("key")` | 无 | 稳定文本 ID 或不能用数字表达的状态 | 虽然运行时在缺少定义时存在回退值,**每个正式变量仍必须在对应 Chapter 的 StoryData Initial Variables 中显式配置类型与默认值**。不得依赖隐式 `0/false/""` 掩盖漏配。 其它可用接口: ```yarn <> <> // 该 Key 存在已保存值,或已在 StoryData Initial Variables 中定义。 <> ``` `has_variable("key")` 会把 StoryData Initial Variable 也视为存在。由于正式变量都应显式配置初始值,它通常会从章节开始便返回 `true`,不能用于判断“玩家是否已经在剧情中写入过这个变量”。若确实需要记录事件是否发生,应创建语义明确的 Bool,而不是依赖变量是否存在。 正式剧情不得使用: ```yarn <> <> ``` 这些 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 <> ``` 拒绝二次确认以后: ```yarn <> ``` 不得在 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 Unlock/Forbidden: - Helper 条件: - Timeline 回滚预期: - 兼容/迁移要求: ``` ## 九、变量新增检查清单 - [ ] 变量确实需要跨 Node、跨 TextBlock 或驱动 StoryData/Helper;单纯控制同一 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、Unlock/Forbidden/Helper 条件,并把登记状态更新为 `Active`。 6. **回归测试阶段**:验证新档、对话 Back、已完成 TextBlock 回顾、互斥路线和 Timeline 回滚。 7. **发布后修改**:任何 Key、类型或语义变更都必须登记 migration 与版本影响。