abyss《深海回音》: - R1 补 synthesis(5/5 愿意玩 P0=0)+ 补录 R1 缺失裁决材料 - R2 十修全部现场坐实:F1 ping迟到/尾句保护首播制/链末看门狗不拆/回波静默一拍/dv4_dual扣账口播/crit水面变体/看门狗13s/震循环1.1s/震去重/状态链人数句 - 补录语音18段(flock串行,QC无离群);playtest 242→278 - 终裁:4/4 人设满分档,连续 2 轮达标 → 可交付 ✅ detective《雨夜专案》: - R1 取证轮:补跑 live 两会话(认真新手33分钟全弧线/乱按200s三级保底抢救),5/5 愿意玩 P0=0 - R2 十一修全部坐实:intro完整落声/tut不被掐/按轴取句/人名指认/结案确认闸/指路句/选句记忆位/hint轻震/st_wrong当场记账/tut_skip补动词/L2疑点齐分支 - 补录+改词33条(29新增+4重录);playtest 265→279 - 终裁:6/6 愿意玩,连续 2 轮达标 → 可交付 ✅ 公共:00-program 批次2进度账收账、13号文档 R2 断言关键词、gen_voice_dual 两游戏段、voice_text.json 验证:abyss 278/278 + detective 279/279 + guide 122/122 + check_all_assets 全项目全绿
56 KiB
18 · 《雨夜专案》完整设计(detective / Rainy Night Case)
给开发者的实现要点摘要
- 本格推理 RPG:核心动词=听证词找矛盾。案卷 7 条目(4 证人证词 + 现场勘验 + 法医报告 + 结案陈词),全部音频呈现;证词=证人 NPC 平铺单音色(声音演技核心,5 个 speaker 池满配 + 专属签名 earcon 防混淆),旁白双性别只做系统/指引/现场自勘。每句证词预打线索轴标签,指证判定=两句是否「同轴异值」——判定与归因全部从数据单源推导,机制上不可能出现「台词说对得上、逻辑上对不上」的假话。
- 手势:证词板左右滑换条目、单击听取/停止、双击=重听当前句(证词按句切分,单句 ≤8s,链播句间 0.8s——≤40s 听觉负荷以「句粒度可停可重听」兑现)、上滑状态链(已问几份/疑点几处)、下滑菜单(无豁免)、长按=进入指证(仅限无声空闲时受理,与长按快进零冲突,豁免 E1/E2 登记 §2.6)。指证/结案菜单走「左右滑预览+单击两段确认」非模态范式,双击保持全局重听语义——全游戏零手势偏离,仅 2 条已教学豁免。
- 单局 15-25 分钟;结案=三问(真凶/凶器/动机),指认错误有不在场证明复述+真话归因+无限再机会,无惩罚性失败,案子保底必结(无进展轨看门狗三级提示最终直接给出可指证的矛盾对)。评级 S-C 账目全部真实(疑点数/冗余指证分档播报,播报值=运行值)。
- 随机性全走种子 PRNG(mulberry32,
opts.seed/opts.pack可注入):选案包(pack A 周先生真凶 / pack B 小顺真凶——同模板同证词骨架、fork 句替换)、洗牌只动 filler 句位与问题选项顺序、提示轮询顺序。矩阵不变式:全案卷「同轴异值」语句对集合 ≡ 预设计矛盾表(dev 断言 + playtest 断言双保险)。- 台词表 18-detective-voice-ids.md:旁白基表 104 句 ×2 性别 + 键盘变体 V 组 14 句 ×2 性别 + NPC 平铺 53 句 = 171 句 ≤176 上限(R2 修订:158→171,新增 13 个录制单位见文末 R2 修订记录;原裁定「158 ≤160」作废,新上限 176);操作提示句带键盘变体(
_k后缀,gesture.inputMode()选播,V 组集中登记)。- 规模对标 radio:单文件 game.js 预计 900-1100 行;bgm 3 + sfx 12 + voice 264 条(×2 格式 = 528 文件)。裁决仪式链不可打断(VERDICT 态 800ms 手势死窗 + 链锁,dungeon H1 同款)。
1. 概述
- 一句话:你是专案组探长,一桩雨夜命案。翻听六份卷宗,比对证词,指出矛盾,锁定真凶。
- 题材:本格推理。核心命题「证词会撒谎,证据不会」——纯音频天然适合:证词本来就是"说"出来的信息,翻卷宗=翻语音段落,比对=重听+指证;视觉游戏需要的证词板 UI 在这里是一套规整的听觉导航(条目→句→指证对)。方法论 §4.1 无现成行(新模式探索),状态层重点自定为:信息可回读(每句可重听)+ 导航规整(同一套左右滑/单击范式贯穿)+ 归因真话(指证判定从数据推导)。
- 为什么适合纯音频:① 记忆与比对的工作记忆负载全在听觉通道——删 BGM 抢占(对白 duck 引擎自动);② 证人=声音演技(speaker+instruct 区分 + 签名 earcon),认人是听感本身;③ 本格逻辑链可完全用「谁说了什么」表述,无空间/动作信息需要降维。
- 单局:一周目(含教学)约 15-20 分钟;二周目(跳教学+变体案)约 13-15 分钟。结案必达(保底),评级 S-C 由过程质量决定。
- 与现有 8 游戏的关系:选项列表导航承接 rpg(左右滑+单击确认)、证词重听承接 simon/escape(重听=生命线)、状态档位链承接 dungeon(上滑 5 段链)、看门狗双轨承接 dungeon E0-1/E0-2(无操作轨+无进展轨);指证菜单是新交互增量(两级选择+两段确认),变体案包是内容增量。
2. 手势映射与豁免登记
2.1 证词板(BOARD,主循环)
BOARD 分空闲(无语音在播)与播放(条目链播中)两个子行为:
| 手势 | BOARD 空闲 | BOARD 播放 |
|---|---|---|
| 左滑 | 上一条目(循环):签名 earcon + 条目名 | 静默忽略(纯聆听保护,simon playback 先例) |
| 右滑 | 下一条目(循环):签名 earcon + 条目名 | 静默忽略 |
| 单击 | 播放当前条目(从首个未听句起,听过的整体重听);停在「结案陈词」时=进确认闸(fin_pre),闸内再单击才进 FINISH,滑走撤闸留板(R2 F5) | 停止播报,回空闲 |
| 双击 | 重听当前条目最后一句(闸内=重听闸句 fin_pre) | 重听当前句(≤8s,免费零消耗) |
| 上滑 | 状态链(§2.5) | 状态链(打断证词;双击可重听当前句) |
| 下滑 | 模态菜单(§2.4) | 模态菜单(打开即停播报) |
| 长按 | 进入指证(CONFRONT;仅空闲受理) | 引擎快进(旁白 1.7×,保持默认,不豁免) |
| 长按松开 | — | 恢复常速 |
条目共 7 项:老葛证词 → 小顺证词 → 周先生证词 → 温太太证词 → 现场勘验 → 法医报告 → 结案陈词。每项播报=专属签名 earcon(0.3-0.5s,§8.2)+ 条目名整句;切到「结案陈词」+单击 → 确认闸(fin_pre「证据在手,就此结案?单击,定下来;滑走,继续查。」),闸内再单击 → FINISH(R2 F5:循环列表必经站,单击直坠三问的误闯代价太大——R1 压力线实测误闯 6-7 次)。
2.2 指证(CONFRONT)与结案(FINISH)——同一导航范式
两态统一为「列表预览 + 两段确认」非模态菜单(00 §5.2 非模态约定,rpg 探索同款),双击全局语义=重听当前句,不偏离:
| 手势 | CONFRONT(选证词对) | FINISH(三问) |
|---|---|---|
| 左/右滑 | 切换:选条目阶段=6 证词条目(同 2.1 循环);选句阶段=上一句/下一句(播该句全文;R2 F7:每条目记忆上次预览/定下位置,进选句从记忆位起播,不再回回从第一句扫) | 切换选项(播选项名;R2 F4:真凶问播纯人名 item_who_w1..w4,不再念「……的证词」卷宗名) |
| 单击 | ①选条目阶段=确认条目 → 进选句;②选句阶段=进入确认(重播该句+cf_confirm);③确认态=定下这句(第一份选定后自动进第二份,流程同前;第二份定下 → 判定) |
凶器/动机问:确认选项即答题;真凶问:进入确认(fin_who_confirm 重播+确认,二次单击定下=正式指认;R2 F4:确认句中性化「就指认这位?」——原「就指认他?」对温太太为假) |
| 双击 | 重听当前预览句(宪法语义保留) | 重听当前问句/选项 |
| 上滑 | 状态链(简版:疑点数) | 同左 |
| 下滑 | 菜单(可「返回证词板」退出指证) | 菜单 |
| 长按 | 选句相位(语音在播)=引擎快进(R2 F7,宪法内加速通道;空闲=error 震);条目/确认相位=error 震(选择语境不作输入) | error 震 |
指证判定结果(§3.5)播出后自动回 BOARD 空闲。全程无倒计时、无尝试次数上限。
2.3 标题(TITLE)/ 结算(SETTLE)/ 裁决(VERDICT)
| 手势 | TITLE | VERDICT(认罪链播中) | SETTLE |
|---|---|---|---|
| 单击 | 继续(有档)/ 新案(无档) | 吞掉(手势死窗+链锁,§7.4) | 接新案(pack 翻转+新 seed) |
| 右滑 | 换一桩新案(重掷 seed/pack,meta 保留,run 清空) | 吞掉 | error |
| 双击 | 重听 continue_ask | 吞掉 | 重听结算链 |
| 上滑 | 重听案情简介(intro_1..3) | 吞掉 | 重听评级段 |
| 下滑 | 菜单 | 吞掉 | 菜单 |
| 左滑/长按 | error | 吞掉 | error |
2.4 模态菜单(遵守 00 文档 §5.2 全球约定,无豁免)
下滑呼出(同时停播报/停看门狗)→ 单击循环切换(每切播项名)→ 双击确认 → 上滑=帮助 → 下滑=关闭。选项 5 项:返回证词板 / 去指证(=长按捷径的菜单冗余入口,P4 容错)/ 保存并回大厅 / 重新听帮助 / 重新查这桩案子。本作无实时玩法,菜单=天然暂停。
2.5 每状态手势映射总表(6 手势 + 长按松开,全状态覆盖)
| 手势 | TITLE | DRILL | BOARD停 | BOARD播 | CONFRONT | FINISH | VERDICT | MENU | SETTLE |
|---|---|---|---|---|---|---|---|---|---|
| 单击 | 继续/新案 | 步骤作答 | 播放条目 | 停止 | 确认(两段) | 确认/答题 | 吞掉 | 循环切项 | 接新案 |
| 双击 | 重听 | 重听教学句 | 重听末句 | 重听当前句 | 重听预览句 | 重听问句 | 吞掉 | 确认执行 | 重听结算链 |
| 左滑 | error | 教学指定 | 上一条目 | 忽略 | 上一项/上一句 | 上一项 | 吞掉 | 上一项 | error |
| 右滑 | 换新案 | 教学指定 | 下一条目 | 忽略 | 下一项/下一句 | 下一项 | 吞掉 | 下一项 | error |
| 上滑 | 案情简介 | 状态(教过后) | 状态链 | 状态链 | 状态链(简) | 重听问句 | 吞掉 | 帮助 | 评级段 |
| 下滑 | 菜单 | 跳过教学 | 菜单 | 菜单 | 菜单 | 菜单 | 吞掉 | 关闭 | 菜单 |
| 长按 | error | 步骤作答 | 进入指证 | 快进(引擎) | error | error | 吞掉 | error | error |
| 长按松开 | — | — | — | 恢复常速 | — | — | — | — | — |
无效手势一律 error 震;full 档 gd_invalid(onceKey 同局 1 次,之后仅 error 震);idle-only(纠错/看门狗句在播时跳过,引擎 guide 已实现)。
2.6 豁免登记(必须显式)
| # | 豁免条目 | 理由(先例) |
|---|---|---|
| E1 | BOARD 单击=播放/停止(非"确认") | "检查/翻阅"类非即时操作,300ms tap 延迟无碍(escape 单击=检查、dungeon 单击=脉冲同款);停止播报是纯聆听期的标准出口 |
| E2 | BOARD 空闲长按=进入指证(核心动词快捷入口) | 绑定条件=无语音在播(!audio.isVoicePlaying()),与长按快进(仅在播时生效)在时间上互斥、零冲突,故不需 dungeon E3 式的对局期豁免;播放中长按仍走引擎快进。教学 D5 讲清(tut_confront),菜单另有「去指证」冗余入口 |
教学(DRILL)逐步讲清 E1/E2;无 immediateTap;模态菜单无豁免。
3. 核心动词:听证词找矛盾(信息设计)
3.1 信息结构总览
案卷(7 条目)── 4 证人证词(各 6 句,NPC 平铺)
├─ 现场勘验(6 句,旁白=探长自勘)
├─ 法医报告(5 句,NPC 秦法医)
└─ 结案陈词(FINISH 入口)
每句 = 1 个音频文件 + 数据侧「线索轴:值」标签(0-2 个)
矛盾 = 两句共享同一轴且值不同;全案卷该集合 ≡ 预设计矛盾表(4 条)
- 证词链播:句间 0.8s 停顿;句粒度重听(双击)+ 句粒度停止(单击)——单段连续听觉负荷 ≤35s 且随时可停可回,满足「证词单段 ≤40s、可分段」要求。
- 三套信息单源自洽(dungeon §3.2 同思路):证词=人的主张、现场/法医=物证主张、状态链=进度账目——进度账目(已问 X/疑点 n)从
heard/doubts实时读出,播报值=运行值(账目真实)。
3.2 线索轴定义(pack A《雨夜·聚宝斋》)
案情:古董商沈万川死于自家后院柴房,后脑钝器伤,当夜暴雨。
| 轴 | 含义 | 取值 |
|---|---|---|
| rain | 雨何时开始 | 21:40 |
| dep_s | 小顺离店时刻 | 21:40 |
| away_s | 小顺当晚去处 | 城南 |
| visitor | 后巷访客 | 22:15 高个微驼男性 |
| dep_z | 周先生离店时刻 | 21:50 |
| lamp | 店堂灯 | 熄 / 亮 |
| key | 库房钥匙位置 | 挂柴房铜钩 / 贴身 |
| weapon | 凶器材质 | 松木劈柴 / 铜器 |
| scale | 铜秤下落 | 已卖 / 在库房 |
| wall | 柴房后墙 | 有人翻爬 |
| door | 后门开法 | 死者亲自为熟人开(规范值 victim_opened) |
| death | 死亡时间 | 22:00-22:30 |
| motive | 账上短银 | 月底要清账 |
| struggle | 搏斗痕迹 | 无 |
(粗体 4 轴=矛盾承载轴;其余轴全部同值互证或单断言,见 3.4 验算。)
3.3 案卷正文(pack A;全部台词 ≤31 字,全文与台词表一致)
老葛(门卫):w1_1「昨儿夜里雨大,我守着街门,一步没敢挪窝。」w1_2「九点四十,雨点子刚砸下来,小顺打着伞出的街门。」w1_3「十点一刻,一位先生收着黑伞进了后巷。个儿高,微驼背。」w1_4「九点五十,周账房出的街门,跟我说了声,回家。」w1_5「后半夜,温太太还来门房借过一回热水。」w1_6「听说店里账上短了银子,沈老板撂了话,月底清账。」
小顺(学徒):w2_1「夜里,师父打发我去城南,给刘掌柜送匣子。」w2_2「雨太大,刘掌柜留我住的,今早才回店。」w2_3「库房钥匙?师父嫌沉,平日就挂在柴房墙上的铜钩。」w2_4「师父的账,向来只信周先生一个人。」w2_5「后门那闩,生人叫不开。熟人来了,师父才亲自去开。」w2_6「周先生常念叨,账房的活,越到夜里越清静。」
周先生(账房,真凶):z_1「我七点进店上夜账。九点五十对完,锁了前门回家。」z_2「临走,我顺手熄了店堂的灯。那会儿,店里就剩老板。」z_3「库房钥匙?沈老板贴身带着,从不离身。」z_4「那伤,是松木劈柴砸的。铜秤?上个月卖给收废品的了。」z_5「我到家倒头就睡,夜里的事,一概不知。」z_6「你们要是不信,去问我家婆娘。」
温太太(房东):wen_1「雨是九点四十下的。我正收晾的衣裳,记得真真的。」wen_2「十点二十,我出门倒垃圾。聚宝斋店堂的灯,亮着呢。」wen_3「刚回屋,柴房后墙咯噔一响,有人爬墙!花盆翻了一个。」wen_4「吓得我蒙头半宿没睡着,天亮才敢吱声。」wen_5「店里短银子的事,街坊都有耳闻。上礼拜他还摔了账本。」wen_6「周账房那人,见人三分笑,账算得比谁都精。」
现场勘验(旁白):sc_0「你打伞进了后院。雨水顺着瓦檐,淌成一道帘子。」sc_1「柴房门口,沈万川面朝下倒着。后脑一处伤,现场没有凶器。」sc_2「后门门闩完好,是死者自己开的门。生人叫不开这扇门。」sc_3「泥地上只有进来的脚印,没有出去的。墙根的花盆,翻了一个。」sc_4「库房铜秤立在架上,秤砣不见了。」sc_5「柴房墙上,挂钥匙的铜钩,空着。」
法医报告(秦法医):fo_1「验尸报告,念给你听。」fo_2「死亡时间,昨夜十点到十点半。」fo_3「后脑单次钝器伤,一击毙命。创口嵌有铜屑,凶器是铜器。」fo_4「死者双手干净,没有搏斗痕迹。」fo_5「鞋底是干的。当夜,死者没出过后门。」
(sc_5 铜钩空为叙事佐证,不挂 key 轴——「平日挂墙上」是习惯断言、「今晨钩空」是状态断言,二者不构成值冲突;数据侧 sc_5 clues={}。)
3.4 矛盾预设计表 + 矩阵验算(playtest 直证对象)
矛盾表(pack A,4 条):
| # | 轴 | 语句 A(真凶侧) | 值 A | 语句 B | 值 B | hit 反应 |
|---|---|---|---|---|---|---|
| M1 | lamp | z_2 周先生「顺手熄了店堂的灯」 | 熄 | wen_2 温太太「十点二十……灯,亮着呢」 | 亮 | z_react_1 |
| M2 | key | z_3 周先生「贴身带着,从不离身」 | 贴身 | w2_3 小顺「平日就挂在柴房墙上的铜钩」 | 挂墙上 | z_react_2 |
| M3 | weapon | z_4 周先生「是松木劈柴砸的」 | 木 | fo_3 法医「创口嵌有铜屑,凶器是铜器」 | 铜 | z_react_3 |
| M4 | scale | z_4 周先生「铜秤上个月卖给收废品的了」 | 已卖 | sc_4 现场「铜秤立在架上,秤砣不见了」 | 在 | z_react_4 |
注:M3/M4 共用语句 z_4(一句两断言),指证时选 z_4 两次、分别对 fo_3 与 sc_4——设计内行为。指证对无序(任一端在前都判 hit)。
矩阵验算(全轴枚举)——「同轴异值对 ≡ {M1..M4}」:
| 轴 | 断言语句(值) | 结论 |
|---|---|---|
| rain | w1_2(21:40)/ wen_1(21:40) | 同值一致(互证) |
| dep_s | w1_2(21:40) | 单断言 |
| away_s | w2_1(城南)/ w2_2(城南) | 一致 |
| visitor | w1_3 | 单断言 |
| dep_z | z_1(21:50)/ w1_4(21:50) | 一致 |
| lamp | z_2(熄)/ wen_2(亮) | M1,唯一冲突对 |
| key | z_3(贴身)/ w2_3(挂墙上) | M2,唯一冲突对 |
| weapon | z_4(木)/ fo_3(铜) | M3,唯一冲突对 |
| scale | z_4(已卖)/ sc_4(在架) | M4,唯一冲突对 |
| wall | wen_3(有人爬墙)/ sc_3(翻墙离开) | 一致 |
| door | w2_5(victim_opened)/ sc_2(victim_opened) | 一致(习惯断言与状态断言取同一规范值) |
| death | fo_2 | 单断言(wen_3 的 22:25 落在窗内,旁证) |
| motive | w1_6 / wen_5 | 一致 |
| struggle | sc_1(无)/ fo_4(无) | 一致 |
| (无轴) | w1_1、w1_5、w2_4、w2_6、z_5、z_6、wen_4、wen_6、sc_0、sc_5、fo_1、fo_5 | 叙事/filler,不参与判定 |
验算结论:除 M1-M4 外不存在任何同轴异值对;一致对 6 组(cf_same 的真话来源)、无轴句 13 句(cf_diff 的真话来源)——三条归因档全部真实可达。
3.5 指证交互与判定算法
judge(a, b):
if a.id === b.id → cf_self(同一句,比自己)
shared = axes(a) ∩ axes(b)
if shared 为空 → cf_miss(钝音)+ cf_diff「说的不是一件事」
else if 存在轴 v: a[v] ≠ b[v]:
if {a,b} ∈ 矛盾表(无序) → contra_hit + cf_hit + react_n + doubts[m]=true(疑点+1)
else → 数据错误(dev 断言禁止;playtest 失败项)
else(共享轴全同值) → cf_miss + cf_same「说得一致,不矛盾」
每次判定(无论中未中)→ cfMiss 判定计数、自动回 BOARD;无资源惩罚、无次数上限
- hit 反应句按所坐实矛盾的轴取句(R2 F3 修订;原裁定「按真凶累计被坐实次数取 z_react_1..4 递进」作废——按次数取句在换顺序坐实时答非所问,属演绎层假话,R1 人设 P1 实锤):pack A 映射 {lamp: z_react_1(灯), key: z_react_2(钥匙), weapon: z_react_w(铜器,R2 新增), scale: z_react_3(秤)};疑点 4/4 坐实的一发在轴句后追加收官句 z_react_4(逐客);pack B 用 {lamp: b_shun_react_1, 其余: b_shun_react_2}(弱绑定非轴假话),收官句同 b_shun_react_2 不重复。递进弧线由同序轴句的内容梯度 + 收官句承担,声音演技核心地位不变。
- 疑点 4/4 齐时播一次
hint_fin(引导去结案);疑点数进状态链与存档,账目同源。
3.6 归因真话律(指证/指认双处)
| 场景 | 播报 | 真话依据 |
|---|---|---|
| 指证 miss·同轴同值 | cf_same | 轴数据同值(如 w1_2 vs wen_1 都说雨 21:40 起) |
| 指证 miss·不同轴 | cf_diff | 无共享轴(绝大多数跨话题句对) |
| 指证 miss·同一句 | cf_self | 选择器同一句 |
| 指认错人 | 该证人 acc_NPC(自述不在场证明)+ fin_clear | 各无辜者的 alibi 在证词中已铺(w2_1/w2_2 小顺、w1_1/w1_5 老葛、wen_4+visitor 男性访客排除温太太)+ pack B 的 acc_zhou |
| 凶器答错 | fin_wp_wrong(「铜屑不答应」) | fo_3 物证 |
| 动机答错 | fin_mv_wrong | w1_6/wen_5 账短银 |
禁止:任何「差一点」「再想想」式无信息归因;播报值与数据值必须一致(playtest 失败项锁定)。
3.7 信息密度与记忆设计
- 单次播报 ≤3 选项:所有列表(条目/句/凶器/动机/嫌疑人)都是逐项预览(左右滑一次听一项),绝不通读清单;帮助句(sys_help)例外(dungeon help 先例)。
- 证人区分三板斧:① 5 speaker 满配 + instruct 常量(§8.3);② 每证人专属签名 earcon(条目切换/指证选择/状态复述时前置,0.3-0.5s);③ 周先生(与男旁白同 speaker)与秦法医(与女旁白同 speaker)是仅有的两处重叠,靠签名+语境+instruct 兜底——重叠从不在相邻句出现(证词链内无旁白插话)。
- P1 工作记忆:疑点无需记忆——状态链随时报数;已选第一份证词在选第二份时自动重播一次(选句确认后链上接播),不需要玩家脑内持有。
4. 状态机
4.1 状态列表
TITLE / DRILL / BOARD / CONFRONT / FINISH / VERDICT / SETTLE + MENU(挂起 overlay,记录返回态)。BOARD 含空闲/播放两子行为(非独立态)。FINISH 子相位:who → weapon → motive;CONFRONT 子相位:item1 → line1 → confirm → item2 → line2 → confirm → judged。
4.2 转移图
start ──> TITLE ──单击(有档)──> BOARD(恢复存档+局面复述)
│单击(无档) ├──────> DRILL(仅首次, meta.drillDone 控制) ──完成/下滑跳过──> BOARD
│右滑=换新案(重掷 seed/pack) ──> BOARD(新案)
v
BOARD(证词板) ⇄ 条目链播(子行为)
│ 长按(空闲) / 菜单「去指证」 │ 选中「结案陈词」条目+单击
v v
CONFRONT ──判定(hit/miss)──> BOARD FINISH(三问)
│(经菜单「返回证词板」退出) ├─指认错→ acc 链 + fin_clear → BOARD
│ └─指认对→ 凶器问→动机问→ VERDICT
VERDICT(认罪链, 手势死窗+链锁) ──> SETTLE ──单击──> TITLE(新案: pack=1-pack)
任意正交态 ──下滑──> MENU ──关闭/返回──> 原状态
4.3 语音链推进契约
- 证词链=onComplete 串行(句间 0.8s 定时器);兜底看门狗:单句 15s 无 onComplete(资产缺失)→ 告警续链(「屏蔽任意 voice 资产流程不卡死」契约)。R2 F1 修订:原 8s 兜底作废——8s 低于真实长句资产(male/intro_1 实测 8.8s、male/sys_help 9.28s,R1 live 开场白「沈万川死了」被掐尾 0.85s);兜底只防资产缺失/引擎异常,必须高于全部真实资产,不当节奏装置。
- 裁决链(VERDICT)与结算链(SETTLE)为独占链:链首停一切看门狗,链内不受理手势(§7.4)。
- 教学链
_speakGuarded串行(radio/dungeon 同款,杜绝同 tick 双调度抢占——D0-1 教训已固化引擎保险丝)。R2 F2 补充:D0 通过路径的条目报名移交 D1 链首串行补播(原_navItem450ms 报名与 tut_listen 并行互掐——R1 live 实测指令句只播 0.4s;mock 转写曾被 8s 兜底掩盖)。
5. 教学编排(DRILL,首局内嵌)
每步=一句短旁白→等待实操→反馈;做错重教同一步(新短句 ≤2 次)后自动演示通过;下滑=跳过教学(tut_skip,R2 F10 改词补核心动词:「已跳过教学。左右滑换卷宗,单击听取;按住屏幕,指证矛盾。」——原词没提指证入口,跳过教学≠已会玩),meta.drillDone 持久化,二周目不再进。教学寄生于真实案卷(D2 就听老葛真实证词,无假内容——教学承诺必须兑现)。
| 步 | 旁白 | 等待动作 | 通过条件/反馈 |
|---|---|---|---|
| D0 | intro_1→intro_2→intro_3→tut_d0 | 左滑或右滑任一 | 签名 earcon+条目名;confirm 震。首输入 ≤60s 达成点 ≈t+20s |
| D1 | tut_listen | 单击 | 老葛证词链播(真实内容) |
| D2 | tut_replay | 双击 | 当前句重播(免费) |
| D3 | tut_status | 上滑 | 状态链(st_asked_1→st_doubt_0) |
| D4 | tut_confront | 长按 | 进 CONFRONT + cf_start |
| D5 | tut_cf_try | 选条目1(滑+单击)→选句(滑)→单击确认→选条目2→选句→单击确认 | 判定被教学截获:任何选择组合都播 tut_cf_ok(练习不算数、不计 cfMiss、不动 doubts),回 BOARD。首正反馈 ≤3min 达成点(success 震) |
| D6 | tut_done | — | 进 BOARD 自由调查;此后上滑/菜单随时可用 |
- D5 教学局不真判定的原因:教学时玩家只听过 1 份证词,真判定必 miss,会把「指证=挫败」印进第一印象;练习路径承诺「真矛盾要靠耳朵找」并在 2 份证词听齐后自然兑现(预期玩家首个真 hit 在 t+5-8min)。
- FTUE 核对:遮罩→intro 三句(~13s)→D0 完成约 t+20s(<60s ✓);D5 完成 ≈t+2.5min(≤3min ✓);全程零惩罚(无资源、无倒计时)✓。
6. 案卷数据结构与随机性
6.1 JSON 草案(pack A 全量 + pack B fork;台词全文见台词表)
{
"schema": 1,
"packs": [
{
"id": 0, "name": "雨夜·聚宝斋", "culprit": "w3", "culpritName": "周先生",
"items": [
{ "id": "w1", "kind": "witness", "name": "item_w1", "sig": "sig_ge",
"intro": null, "lines": [
{ "id": "w1_1", "shuffle": false, "clues": {} },
{ "id": "w1_2", "shuffle": true, "clues": { "rain": "2140", "dep_s": "2140" } },
{ "id": "w1_3", "shuffle": false, "clues": { "visitor": "male_tall_hunched" } },
{ "id": "w1_4", "shuffle": true, "clues": { "dep_z": "2150" } },
{ "id": "w1_5", "shuffle": true, "clues": {} },
{ "id": "w1_6", "shuffle": false, "clues": { "motive": "short" } } ] },
{ "id": "w2", "kind": "witness", "name": "item_w2", "sig": "sig_shun",
"intro": null, "lines": [
{ "id": "w2_1", "shuffle": false, "clues": { "away_s": "south" } },
{ "id": "w2_2", "shuffle": true, "clues": { "away_s": "south" } },
{ "id": "w2_3", "shuffle": false, "clues": { "key": "hook" } },
{ "id": "w2_4", "shuffle": true, "clues": {} },
{ "id": "w2_5", "shuffle": false, "clues": { "door": "victim_opened" } },
{ "id": "w2_6", "shuffle": true, "clues": {} } ] },
{ "id": "w3", "kind": "witness", "name": "item_w3", "sig": "sig_zhou",
"intro": "intro_w3", "lines": [
{ "id": "z_1", "shuffle": false, "clues": { "dep_z": "2150" } },
{ "id": "z_2", "shuffle": false, "clues": { "lamp": "off" } },
{ "id": "z_3", "shuffle": false, "clues": { "key": "body" } },
{ "id": "z_4", "shuffle": false, "clues": { "weapon": "wood", "scale": "sold" } },
{ "id": "z_5", "shuffle": true, "clues": {} },
{ "id": "z_6", "shuffle": true, "clues": {} } ] },
{ "id": "w4", "kind": "witness", "name": "item_w4", "sig": "sig_wen",
"intro": null, "lines": [
{ "id": "wen_1", "shuffle": false, "clues": { "rain": "2140" } },
{ "id": "wen_2", "shuffle": false, "clues": { "lamp": "on_2220" } },
{ "id": "wen_3", "shuffle": false, "clues": { "wall": "climbed" } },
{ "id": "wen_4", "shuffle": true, "clues": {} },
{ "id": "wen_5", "shuffle": false, "clues": { "motive": "short" } },
{ "id": "wen_6", "shuffle": true, "clues": {} } ] },
{ "id": "scene", "kind": "scene", "name": "item_scene", "sig": "sig_scene",
"lines": [
{ "id": "sc_0", "shuffle": false, "clues": {} },
{ "id": "sc_1", "shuffle": false, "clues": { "struggle": "none" } },
{ "id": "sc_2", "shuffle": false, "clues": { "door": "victim_opened" } },
{ "id": "sc_3", "shuffle": false, "clues": { "wall": "climbed" } },
{ "id": "sc_4", "shuffle": false, "clues": { "scale": "present" } },
{ "id": "sc_5", "shuffle": false, "clues": {} } ] },
{ "id": "fore", "kind": "forensic", "name": "item_fore", "sig": "sig_fore",
"lines": [
{ "id": "fo_1", "shuffle": false, "clues": {} },
{ "id": "fo_2", "shuffle": false, "clues": { "death": "2200_2230" } },
{ "id": "fo_3", "shuffle": false, "clues": { "weapon": "bronze" } },
{ "id": "fo_4", "shuffle": false, "clues": { "struggle": "none" } },
{ "id": "fo_5", "shuffle": false, "clues": {} } ] }
],
"contradictions": [
{ "id": "m1", "a": "z_2", "b": "wen_2", "axis": "lamp", "hint": "hint_c1" },
{ "id": "m2", "a": "z_3", "b": "w2_3", "axis": "key", "hint": null },
{ "id": "m3", "a": "z_4", "b": "fo_3", "axis": "weapon", "hint": null },
{ "id": "m4", "a": "z_4", "b": "sc_4", "axis": "scale", "hint": "hint_c2" }
],
"verdict": { "accuseLine": "fin_right",
"break": ["z_break_1", "z_break_2", "z_break_3"] },
"wrongAccuse": { "w1": "acc_ge", "w2": "acc_shun", "w4": "acc_wen" },
"reacts": ["z_react_1", "z_react_2", "z_react_3", "z_react_4"],
"questions": {
"weapon": { "options": ["wp_1", "wp_2", "wp_3", "wp_4"], "answer": "wp_2" },
"motive": { "options": ["mv_1", "mv_2", "mv_3"], "answer": "mv_1" } }
},
{
"id": 1, "name": "雨夜·聚宝斋(变体)", "culprit": "w2", "culpritName": "小顺",
"base": 0,
"overrides": {
"w2": { "lines": [
{ "id": "w2_1", "shuffle": false, "clues": { "away_s": "south" } },
{ "id": "w2_2", "shuffle": true, "clues": { "away_s": "south" } },
{ "id": "b_shun_1", "shuffle": false, "clues": { "lamp": "off" } },
{ "id": "b_shun_2", "shuffle": false, "clues": { "key": "body" } },
{ "id": "b_shun_3", "shuffle": false, "clues": { "weapon": "wood", "scale": "sold" } },
{ "id": "b_shun_4", "shuffle": true, "clues": {} } ] },
"w3": { "lines": [
{ "id": "z_1", "shuffle": false, "clues": { "dep_z": "2150" } },
{ "id": "b_zhou_1", "shuffle": true, "clues": {} },
{ "id": "b_zhou_2", "shuffle": false, "clues": { "key": "hook" } },
{ "id": "b_zhou_3", "shuffle": true, "clues": {} },
{ "id": "z_5", "shuffle": true, "clues": {} },
{ "id": "z_6", "shuffle": true, "clues": {} } ] },
"contradictions": [
{ "id": "m1b", "a": "b_shun_1", "b": "wen_2", "axis": "lamp", "hint": "b_hint_c1" },
{ "id": "m2b", "a": "b_shun_2", "b": "b_zhou_2", "axis": "key", "hint": null },
{ "id": "m3b", "a": "b_shun_3", "b": "fo_3", "axis": "weapon", "hint": null },
{ "id": "m4b", "a": "b_shun_3", "b": "sc_4", "axis": "scale", "hint": "b_hint_c2" } ],
"verdict": { "accuseLine": "fin_right_b",
"break": ["b_shun_break_1", "b_shun_break_2", "b_shun_break_3"] },
"wrongAccuse": { "w1": "acc_ge", "w3": "acc_zhou", "w4": "acc_wen" },
"reacts": ["b_shun_react_1", "b_shun_react_2", "b_shun_react_2", "b_shun_react_2"]
}
}
]
}
6.2 seed 用法
rng = mulberry32(seed) // 与 dungeon 同族
pack = opts.pack ?? (opts.seed != null ? seed % 2 : null)
正式局:seed = Math.floor(Math.random()*1e9);pack 首局=0,结案后新案 pack = 1 - pack(强制换案)
洗牌(生成期一次性,存入 run.layout):
① 各证人内部 shuffle:true 的 filler 句在其槽位集合内置换(首句与全部矛盾承载句固定)
② 凶器问 4 选项、动机问 3 选项:Fisher-Yates by rng
③ 保底提示 hint 轮询顺序:permuted by rng
复现断言口径:同 (seed, pack) 两次构造 → game._case 深相等(布局/选项序/提示序逐项相等,不写魔法值)
6.3 变体生成规则(pack B 逻辑摘要)
- 同模板:同一桩雨夜命案、同 4 证人位、同现场/法医/温太太/老葛证词(音频全复用)、同 4 轴矛盾结构(lamp/key/weapon/scale)。
- 不同真凶:pack B 真凶=学徒小顺。fork=替换两份证词的句集:小顺换成 4 句谎(b_shun_1..4,复用其真实离店叙事作伪 alibi),周先生换成 3 句中性真话(b_zhou_1..3,其中 b_zhou_2「钥匙挂铜钩」成为 M2b 的对立端)。
- 矩阵自洽:pack B 的验算与 pack A 同构——lamp 轴唯一冲突对 (b_shun_1, wen_2);key 轴唯一冲突对 (b_shun_2, b_zhou_2);weapon/scale 由 b_shun_3(一句两断言)对 fo_3/sc_4。老葛 w1_3 的访客描述(高个微驼)由 b_shun_break_2「棉袄反穿,弓着背」解释,不产生新轴冲突。
- 动机/凶器答案跨包一致:监守自盗(小顺拿库房货换钱,b_shun_break_3 交代)与铜秤砣——问题反馈句两包共用。
- 内容成本:fork 仅 12 句 NPC + 1 句旁白(fin_right_b)+ 2 句提示(b_hint_c1/2)。
6.4 矩阵不变式(dev/playtest 双保险)
启动时与测试中断言:{(a,b,axis) : a,b 同轴且值不同} ≡ contradictions。任何台词改稿若引入新的同轴异值对,此断言立即失败——防止「文案事故变成指证归因假话」。
7. 评级系统与裁决仪式
7.1 结案三问(FINISH)
- 真凶(4 选 1:老葛/小顺/周先生/温太太;两段确认)。错→该证人 acc_NPC 自述不在场证明 + fin_clear + st_wrong「错指一回,记档。」(R2 F9:评级账目当场可闻,S/A 差距不再靠悟) → 回 BOARD;无限再机会,wrongWho 计数。
- 凶器(4 选 1:松木劈柴/铜秤砣/铁门闩/青瓷花盆;选项序由 seed 洗牌)。对=fin_wp_right,错=fin_wp_wrong(真话归因,不重答,记账)。
- 动机(3 选 1:监守自盗/寻仇泄愤/劫财入户)。同上。
7.2 评级标准(S-C)
变量:doubts(疑点 0-4)、weaponOk、motiveOk、wrongWho(指认错次数)、cfMiss(冗余指证次数)、hints(保底提示已播数)。
| 档 | 条件(自上而下首个命中) | 播报 |
|---|---|---|
| S | doubts=4 ∧ weaponOk ∧ motiveOk ∧ wrongWho=0 ∧ cfMiss≤2 ∧ hints=0 | rate_s「教科书结案。四处疑点,一击即中。」 |
| A | doubts≥3 ∧ weaponOk ∧ motiveOk ∧ wrongWho≤1 ∧ hints≤1 | rate_a「干净利落的结案。」 |
| B | doubts≥2 ∧ wrongWho≤2 | rate_b「案子结了,卷宗上有疏漏。」 |
| C | 其余(案子必然已结) | rate_c「案子是结了,卷宗上补丁不少。」 |
- 结案必达:无失败态;C 档覆盖「全靠保底提示/疑点<2/指认错 ≥3」。
- 措辞-账目对账:S 的「一击即中」=wrongWho 0;「四处疑点」=doubts 4;C 的「补丁」=hints≥2 或 cfMiss≥3 或 wrongWho≥3——每句评级文案与触发条件一一对应(E1-2 档位措辞真实教训)。
7.3 结算账目播报(真实)
SETTLE 链:settle_open → rate_X → st_doubt_n(疑点实数)→ st_miss_档(cfMiss: 0/1-2/≥3 → 三档真话)→ settle_hook(单击接新案,键盘态用 settle_hook_k)。所有分档句按运行值选播,播报值=存储值(playtest 锁定)。
7.4 裁决仪式(VERDICT,结案宣判完整弧线)
指认正确后进入,链不可打断(dungeon H1 教训:结算链不许被在途手势截杀):
fin_right(证据链闭合)→ sfx/rain_s swell 起
→ z_break_1 → z_break_2 → z_break_3(认罪,声音演技高潮;bgm/verdict)
→ sfx/gavel(法槌)→ settle_open → SETTLE(接 §7.3 链)
- 手势死窗:进 VERDICT 即盖
VERDICT_GRACE_MS=800戳(同 dungeon SETTLE_GRACE:touchstart+450ms 长按判定+300ms 双击窗 ≈750ms,800 全盖);死窗内一切手势吞掉(ghost 手势不算输入、不碰看门狗)。 - 链锁:VERDICT→SETTLE 全链播完(settle_hook 落声)前,单击/右滑/长按一律吞掉;链完成后单击=接新案(settle_hook 承诺「单击,接新案」言行一致——simon round1-live 教训)。双击=重听结算链仅在链完成后受理。
8. 音频三层
8.1 BGM(3 首,Mureka instrumental,-20 LUFS,ogg+m4a,无缝循环;雨声底烤进曲目,省第三声流)
| id | 状态映射 | Mureka prompt(英文) |
|---|---|---|
| bgm/menu | TITLE / MENU / SETTLE(结算 volume 0.5) | "Rainy night noir jazz ballad, slow brushed drums, lazy saxophone, soft rain ambience, melancholy and calm, no vocals, seamless loop" |
| bgm/board | DRILL / BOARD / CONFRONT / FINISH | "Moody jazz trio for a detective's office, muted piano walking, upright bass, soft rain on window, focused and mysterious, no vocals, seamless loop" |
| bgm/verdict | VERDICT(认罪链起播,交叉淡入) | "Tense noir jazz climax, brooding low strings under sparse piano, rain intensifying then settling, dramatic restraint, no vocals, seamless loop" |
切换全走引擎 crossfade;对白 duck 20% 引擎自动。choice/danger 不换曲(状态区分由 guide earcon 承担,氛围连续性优先)。预算:3 曲 ×2 候选 = 6 任务 $0.18(项目上限 $2.00 内)。
8.2 SFX(12 个;SA3=Stable Audio 3,SYN=程序合成;双格式、真峰值 ≤-3dBFS)
| 类别 | id | 方式 | 说明 |
|---|---|---|---|
| 卷宗 | paper_turn |
SA3 | 翻卷宗页(条目切换内容反馈,"single paper page turn on desk, dry, close") |
| 证人签名 | sig_ge |
SA3 | 搪瓷缸顿桌一下(老葛) |
sig_shun |
SYN | 布掸子拍柜台两下(小顺) | |
sig_zhou |
SA3 | 算盘珠拨两响(周先生) | |
sig_wen |
SYN | 门环叩两下(温太太) | |
sig_fore |
SYN | 纸页翻动+钢笔划线(法医报告) | |
sig_scene |
SA3 | 雨中皮鞋踩水两步+伞抖水(现场,0.5s) | |
| 指证 | contra_hit |
SYN | 不和谐金属二度相击+盖章尾(矛盾证实音,全游戏最强确认音) |
contra_miss |
SYN | 钝木鱼一下(对不上——非 error 音色,不威吓) | |
| 裁决 | gavel |
SA3 | 法槌一击("wooden gavel single strike, small room reverb") |
rain_swell |
SA3/SYN | 雨声渐强再落(认罪链垫,6s one-shot) | |
| 看门狗 | turn_tick |
SYN | 880Hz 木鱼族轻响(无进展轨 L1 复用 dungeon 配方,自存一份) |
并发纪律:签名 earcon(≤0.5s)→ 条目名语音,串行不叠;contra_hit 先响、cf_hit 语音后接。声流恒 ≤2(BGM + voice)。
8.3 voice(158 句:旁白 106 ×2 性别 + NPC 平铺 52)
- 旁白(系统/指引/教学/状态/现场自勘/裁决宣读):female=Serena / male=Uncle_Fu,instruct 常量全表统一(见台词表头);数字全分档整句(st_asked 7 档/st_doubt 5 档/st_miss 3 档),句序号一律不播(指证选句用重播该句代替报数——数字拼接禁令的交互侧落实)。
- NPC 平铺单音色(证词=证人 NPC;不做双性别;落
voice/根目录,引擎平铺回退命中):
| 角色 | speaker | instruct 常量 | 区分度风险 |
|---|---|---|---|
| 老葛(门卫 62) | Eric | 苍老沙哑的男声,守夜人,慢悠悠,带倦意 | 低:与两侧旁白均不同 speaker |
| 小顺(学徒 19) | Dylan | 年轻清亮的男声,学徒,怯生生的,慌张诚实 | 低:同上 |
| 周先生(账房,真凶 A) | Uncle_Fu | 平板谨慎的男声,账房,字斟句酌,被追问时渐慌 | 中:与 male 旁白同 speaker——靠 sig_zhou 前缀+账房腔 instruct+证词链内零旁白插话;试听确认 |
| 温太太(房东 50) | Vivian | 快嘴泼辣的中年女声,房东太太,嗓门亮,热心肠 | 低:与两侧旁白均不同 speaker |
| 秦法医 | Serena | 冷静干练的女声,验尸官,临床腔,短句平直 | 中:与 female 旁白同 speaker——靠 sig_fore 前缀+报告语境固定(只在整个案卷固定条目出现);试听确认 |
- 声音演技核心:周先生 z_react_1..4(记岔了→支吾→拒答→想走)与 z_break_1..3(认罪三段)是本作表演高潮;instruct 恒定、情绪写在句内文本(标点与省略号引导),不靠句级 instruct 变体(音色漂移禁令)。pack B 对应 b_shun_react/b_shun_break。
- 全表、触发时机、键盘变体(V 组)与多音字自查见 18-detective-voice-ids.md。
9. 向导层接入(engine/guide.js,不新增 earcon 词表)
9.1 状态签名(进入状态时播)
| 状态 | guide.state() | 时点 |
|---|---|---|
| TITLE / MENU / SETTLE | menu |
进标题、开菜单、进结算 |
| DRILL / BOARD | explore |
进教学、进证词板(含指证判定后返回) |
| CONFRONT / FINISH | choice |
进指证、进结案三问 |
| VERDICT | settle |
认罪链起 |
| danger | 不使用 | 本作无生命/倒计时压力(登记) |
9.2 turn cue 与看门狗(双轨——批次 1 教训固化)
| 等待点 | 机制 | at | say(full 档;第 2 级一律纯 nudge) |
|---|---|---|---|
| CONFROST/FINISH 各选择相位入口 | guide.turn | — | turn earcon + confirm 震 |
| BOARD 空闲 | watchdog 无操作轨 | [10s, 25s] | gd_board / null(R2 F6:六份听齐且疑点未齐时一级改播 gd_board_cf「都听过了。按住屏幕,去指证。」——「换卷宗」此情是错指令,R1 三人设同撞) |
| CONFROST 选句/确认 | watchdog 无操作轨 | [15s, 30s] | gd_cf / null |
| FINISH 三问 | watchdog 无操作轨 | [20s, 40s] | gd_fin / null |
| DRILL 每步 | watchdog 无进展轨(共享) | [30s/60s/90s] | earcon → 短句 → tut_skip 自动滚出(E0-2 先例) |
9.3 无进展轨(调查态卡关三级,证词板乱按也要被抢救)
- 进展事件=听完新条目 / 指证判定 / 结案相位推进(
_progressTrack()挂点:条目链 onComplete、judge()、FINISH 相位切换)。只由进展重置——乱按(疯狂换条目不听完、播放中狂点停起)永远攒不满进展,三级必达: - [45s] L1:turn_tick earcon(不占台词通道)→ [90s] L2:
hint_a(还有未听条目时)/hint_b(都听过但疑点未齐)/hint_fin(疑点已齐——R2 F11:此情还播「逐句比对」是指引过时,直指去结案) → [150s] L3:保底给出可指证的矛盾对(hint_c1/hint_c2 按未发现清单轮询,seed 定序);4 疑点齐 →hint_fin(去结案)。L3 后每 150s 重复(每句全局限 2 次,之后静默——不轰炸)。 - 无操作轨(手势重置)与无进展轨并行取先到;两轨短句内容同级交叉登记防重复。纠错/提示 idle-only、过期丢弃(引擎已实现)。R2 F8:提示句震动由 warning 三连震改为 confirm 轻震(递答案不是训人——R1 人设 P4:「头一下我当自己犯错了」)。
10. 存档设计
{
"schema": 1, "game": "detective", "updatedAt": 0,
"summary": "雨夜·聚宝斋 · 已问3/6 · 疑点2/4",
"meta": { "drillDone": true, "casesClosed": 1, "bestGrade": "A", "lastPack": 0 },
"run": {
"seed": 42, "pack": 0, "layout": { "w1": [...], "wpOpts": [...], "hintOrder": [...] },
"heard": ["w1", "scene", "fore"],
"doubts": [false, true, false, false],
"cfMiss": 1, "wrongWho": 0, "zHits": 1,
"hintsGiven": ["hint_c1"], "weaponAns": null, "motiveAns": null
}
}
- summary 生成规则:
{案名} · 已问{heard.length}/6 · 疑点{doubts 中 true 数}/4(结案后 run=null,summary=已结案{casesClosed}起 · 最佳{bestGrade})。 - 保存时机:条目链播完 / 指证判定后 / 菜单「保存并回大厅」/ 结案入 meta。localStorage + PUT 服务器。
- R2 补充:结案确认闸(_caseGate)与选句记忆(_cfLineMem)为瞬态 UI 态,不持久化(读档回板=闸撤、记忆空——重新调查从干净入口起)。
- 读取:有 run → TITLE 播 sys_continue_ask,单击继续 → 恢复(layout 复用存档值,不重洗)→ 局面复述链:
st_asked_n →(未听条目 ≤3 个时逐个播 item_* 名;>3 个只报计数)→ st_doubt_m → recap_go,≤10s 回到可操作;右滑=换新案(seed/pack 重掷,meta 保留)。 - 归因真话依据:评级各变量全部持久化(doubts/cfMiss/wrongWho/hintsGiven/answers),结算播报从同源读取。
11. playtest 断言清单(登记 13 号文档新增 §detective;mock 对齐 web/rpg/test/playtest.mjs;一律 guide:'off')
关键路径(seed=42, pack=0,≤200 手势):
- 启动→TITLE(无档)→单击→DRILL:D0..D6 逐步断言 voice 序与 drillStep 递进;D5 任意选择组合都播 tut_cf_ok 且 doubts/cfMiss 零变化(教学承诺兑现);下滑跳过路径 + meta.drillDone 二周目不再进。
- seed 复现:(42,0) 两次构造 →
_case深相等(条目/句序/filler 洗牌/选项序/提示序);(42,1) 与 (43,1) 布局不同。 - 矩阵不变式:对
_case全句对枚举轴交集——同轴异值对集合 ≡ contradictions(pack A 与 pack B 各验一遍)。 - 听取:6 条目链完整(句序=layout)、双击=当前句重播零消耗、单击停止、播完 st_asked 升档;播放中左右滑静默忽略(无 error 震);R2 F6:六份听齐且疑点未齐时状态链尾=recap_cf、疑点齐=hint_fin(原 recap_go 一刀切作废)。
- 指证 4 矛盾逐条走通:M1-M4 各自导航→两段确认→contra_hit+cf_hit+react_按轴(R2 F3:lamp→z_react_1 / key→z_react_2 / weapon→z_react_w / scale→z_react_3;4/4 齐追加 reactFinal z_react_4 + hint_fin)→doubts 置位;M3/M4 共用 z_4(选 z_4 两次分别对 fo_3/sc_4);指证对无序(反向选也 hit);R2 F7:同条目再进选句从记忆位起播(断言入口 lineIdx);选句相位长按在播=引擎快进不震、空闲=error 震。
- 指证 miss 三档真话:同轴同值对(w1_2 vs wen_1)→cf_same;无共享轴对(z_5 vs sc_1)→cf_diff;同句→cf_self;cfMiss 计数、无任何资源/次数惩罚。
- 指认全路径:错指小顺/老葛/温 → acc_NPC+fin_clear+st_wrong 当场记账(R2 F9)+回 BOARD(无限次);对指周先生 → 凶器问(选项序=layout)→ 动机问 → VERDICT。R2 F5:进 FINISH 先过确认闸——停「结案陈词」首击播 fin_pre 仍 BOARD,滑走撤闸,闸内再击进三问;R2 F4:真凶问选项播人名 item_who_*,确认句中性化「就指认这位?」。
- 裁决死窗:指认对瞬间同拍与 +300ms 各补一记在途 tap → 均被吞(仍 VERDICT);认罪链 4 句+gavel+settle 链完整有序;链后单击=接新案(pack 翻转、seed 重掷、meta 入账)。
- 评级账目:注入 outcomes 矩阵(doubts∈{0..4}×weapon×motive×wrongWho×cfMiss×hints 代表组合 ≥10 组)→ 断言 grade 判定与 §7.2 表一致 + 结算链播报句(rate_X/st_doubt_n/st_miss_档)与运行值一致(假话即失败)。
- 看门狗双轨:BOARD 10s/25s(gd_board→nudge;R2 F6:听齐未破时一级=gd_board_cf);无操作 96s 乱按零进展 → 无进展轨 45s earcon/90s 短句/150s hint_c(给出未发现矛盾对且该对可走通指证);R2 F11:疑点齐时 L2=hint_fin;R2 F8:提示句震动=confirm 轻震;有真实进展零提示;4 疑点齐后 150s → hint_fin。
- 中断复述:存档重进→sys_continue_ask→单击→复述链序(st_asked→未听 ≤3 时 item 名链→st_doubt→recap_go);上滑同链可重放。
- 二周目变体:seed'/pack=1 → 矛盾表指向 b_shun_*/b_zhou_2、culprit=w2、错指周先生走 acc_zhou、认罪链 b_shun_break、hint 为 b_hint_c1/2;矩阵不变式复验。
- 键盘变体:
settings.input='key'后播 sys_help_k/tut_d0_k 等 V 组(inputMode 联动);'touch' 回基础句。 - 菜单/帮助/存档:模态菜单循环-确认-关闭;「保存并回大厅」→PUT data.summary 命中生成规则;「去指证」= 长按同效。
边界断言:
- 教学期零惩罚:D5 任意乱选不产生 cfMiss/doubts 变化;全程无倒计时(全 run 无 timeout 惩罚断言)。
- 长按豁免:BOARD 播放中长按=引擎快进(不进指证);空闲长按→CONFRONT;CONFRONT/FINISH 长按=error 震。
- 状态链随时可用(含播放中,打断后双击可重听当前句);播报值=heard/doubts 实值。
- 指证第二份选择时自动重播第一份选定句(P1 记忆契约)。
- 屏蔽任意 voice 资产:链 15s 兜底推进(R2 F1:原 8s 作废),流程到结案不死锁。
- guide=off:全静、零定时器;资产齐套:voice 双性别 id 集合一致 + NPC 平铺存在 + sfx/bgm 双格式。
- VERDICT/SETTLE 链内上滑/下滑/双击全部吞掉(链锁),链完成前无任何状态逃逸。
失败即不通过:归因假话(cf_same/cf_diff/评级句与数据实值不符);矩阵外冲突对存在;同 (seed,pack) 两次构造不一致;教学练习计入账目;裁决链被手势截杀或链句缺失;保底 hint 给出的矛盾对走不通指证。
12. 节奏曲线与单局核算
| 阶段 | 时长 | 内容 | 奖励点(≤60s 一个) |
|---|---|---|---|
| 开场链 | 0:20 | intro 三句 | — |
| DRILL | 0:20-2:40 | D0-D6(老葛证词首听在 D1) | D5 完成 success 震(t+2.5min) |
| 自由调查 | 2:40-9:00 | 5 条目听取+句级重听+状态核对 | 每条目听毕 st_asked 升档 |
| 指证穿插 | 5:00-12:00 | 4 矛盾(两证词齐后即可开始,玩家自定节奏) | 每个 hit:contra_hit+真凶 react 递进 |
| 结案三问 | 12:00-14:00 | 真凶/凶器/动机 | 指认对=fin_right(高潮起) |
| 裁决+结算 | 14:00-15:30 | 认罪链+法槌+评级 | 评级播报+开环钩子 |
- 一周目 15-20 分钟(重听多的松玩家 ≤25);二周目(跳教学+已熟导航)13-15 分钟。15-30 分钟章程达标。
- 悬念曲线:听证词(信息积累)→ 首个 hit(「证词会撒谎」兑现)→ react 递进(真凶渐慌)→ 三问(主动权全在玩家)→ 认罪(演技高潮)——每 30-60s 必有可感知进展(条目数/疑点数两个可见账本)。
- 开环钩子:settle_hook「同一场雨里,还有别的案子」+ pack 强制翻转(二周目必遇变体真凶)。
13. 自检清单
| # | 硬约束/教训 | 自检 |
|---|---|---|
| 1 | FTUE 首输入 <60s | D0 完成约 t+20s ✓(§5) |
| 2 | 首个正反馈 ≤3min | D5 教学完成 success 震 ≈t+2.5min;首个真 hit 预期 t+5-8min(本作类型内最近可达)✓ |
| 3 | 学习期零惩罚 | 无资源无倒计时全域;D5 练习不算账 ✓ |
| 4 | 失败三问归因+真话律 | 指证 miss 三档从轴数据推导;指认错=不在场证明复述;凶器/动机错=物证归因;评级句与账目一一对应 ✓(§3.6/§7,playtest 失败项锁定) |
| 5 | 手势宪法三件套不豁免 | 上滑状态/下滑菜单/双击重听全状态保留;仅 E1/E2 登记且教学讲清 ✓(§2.6) |
| 6 | 向导层 | 签名 4 态(choice 用、danger 登记不用);双轨看门狗(无操作+无进展,乱按必被抢救);保底 hint 给可走通矛盾对;idle-only/queue/onceKey ✓(§9) |
| 7 | 教学承诺兑现 | tut 承诺的每个手势在正片同语义可用;settle_hook「单击接新案」言行一致(死窗+链锁后)✓ |
| 8 | 结算链完整 | VERDICT 手势死窗 800ms+链锁,认罪→法槌→评级全链不可截(H1 教训)✓(§7.4) |
| 9 | 档位措辞真实 | S-C 条件与文案一一映射;st_asked/st_doubt/st_miss 播报值=运行值 ✓(§7.2/7.3) |
| 10 | 信息密度 | 所有列表逐项预览(≤3 选项/次);证词句粒度 ≤8s、链播 ≤35s 可停可重听(≤40s 听觉负荷)✓(§3.7) |
| 11 | P4 容错 | 无惩罚性失败;错指无限再机会;保底必破案(hint_c 直接给对子);零新手势 ✓ |
| 12 | P1 视障 | 句级免费重听;导航规整(条目→句→指证同一范式);状态链随时可查;账目真实;5 speaker+签名 earcon 防混淆(2 处重叠风险已登记缓解);2.2× 语速引擎既有 ✓ |
| 13 | P3 通勤 | 中断复述(已问谁/待问谁 ≤3 名直报/疑点几处);单手免视;任意时刻菜单退出存档;3 分钟颗粒=一份证词完整听取+比对 ✓ |
| 14 | P2 大学生 | react 递进/认罪演出钩子;pack 翻转二周目变体;评级 S 追求(全疑点+零冗余)✓ |
| 15 | seed 可复现 | (seed,pack) 注入+布局洗牌全 PRNG+深相等断言;变体包数据驱动 ✓(§6.2) |
| 16 | 矛盾矩阵验算 | 全轴枚举表:同轴异值对 ≡ M1-M4;一致对 6/单断言/无轴句清单 ✓(§3.4/§6.4 不变式) |
| 17 | 指证全路径可走通 | hit(4 矛盾×双向)/miss 三档/同句/错指三人(A)/错指含周(B)/三问对错/保底 hint 对——全部有专属资产与断言 ✓(§11 路径 5-10、12) |
| 18 | 台词规范 | 全句 ≤40 字(实测 ≤31);数字全分档整句;句序号不播(重播代替报数);「重新听」写法;同角色 speaker+instruct 恒定;总句数 171 ≤176(R2 修订)✓(台词表) |
| 19 | 键盘通道 | 操作提示句 V 组 14 变体集中登记(R2 新增 fin_pre/fin_who_confirm/recap_cf/gd_board_cf 4 对),inputMode() 选播;空格/回车/方向键全手势可达(§5.5 平行通道,游戏层零改动)✓ |
| 20 | 引擎能力边界 | 无实时节点(链播 onComplete+setTimeout);长按快进与长按指证时间互斥(R2 F7 起选句相位也放行快进);资产缺失静默跳过+15s 兜底(R2 F1);30MB 预算内 ✓ |
R2 修订记录(2026-09-13;裁定追加,旧裁定原文保留于上文并就地标注「作废/修订」)
证据源:research/new8/detective/round1/{synthesis.md, live-player.md, p1..p4, transcript-*}。每条对应 R1 synthesis 的 F 编号;全部修复落于 web/detective/game.js + 台词表 + playtest 断言。
| # | 修订 | 原裁定 → 新裁定 | 证据 |
|---|---|---|---|
| F1 | 单句兜底 8s→15s | 「8s 无 onComplete 告警续链」→「15s」(兜底高于全部真实资产:male/intro_1 8.8s、male/sys_help 9.28s、key/sys_help 10.48/9.52s 登记在台词表头注) | live A t=8.16 intro_1 掐尾丢「川死了」 |
| F2 | D0→D1 串行化 | 「D0 报名与 D1 指令并行」→「D0 报名移交 D1 链首串行补播」 | live A t=33.8 tut_listen 只播 0.4s |
| F3 | react 按轴取句 | 「按累计坐实次数 z_react_1..4 递进」→「按轴映射 + 4/4 追加 reactFinal;新增 z_react_w(weapon 轴)」 | 人设 P1 建议 1(换顺序即答非所问) |
| F4 | 指认措辞真话化 | 「就指认他?」→「就指认这位?」;真凶问选项卷宗名 → item_who_w1..w4 纯人名 | 人设 P1 建议 2(温太太分支为假) |
| F5 | 结案确认闸 | 「结案陈词单击进 FINISH」→「首击 fin_pre 闸、闸内再击进、滑走撤闸」;新增 fin_pre 句 | 人设 P2 建议 1 + 压力转写误闯 6-7 次 + live B 自救实测 |
| F6 | 听齐未破指路 | 「状态链尾恒 recap_go / gd_board 恒教换卷宗」→「听齐未破:尾句 recap_cf、一级提示 gd_board_cf」;新增两句 | 人设 P1/P3/P4 同撞 + live A t=610 |
| F7 | 选句加速 | 「CONFRONT 长按一律 error」→「选句相位在播=引擎快进、空闲=error」;新增按条目选句记忆(瞬态) | 人设 P1/P3/P4 同点 + live A 选句段 25-35s/次 |
| F8 | 提示轻震 | 「hint 附 warning 三连震」→「confirm 轻震」 | 人设 P4 建议 3 + 两局 hint 落点实测 |
| F9 | 错指当场记账 | 「错指=acc+fin_clear」→「+st_wrong『错指一回,记档。』」新增句 | 人设 P2 建议 2(S/A 差距不可感知) |
| F10 | 跳教学带核心动词 | tut_skip 改词补「按住屏幕,指证矛盾。」(重录) | 人设 P2 建议 3 |
| F11 | L2 疑点齐分支 | 「L2=hint_a/hint_b 二选」→「疑点齐时 L2=hint_fin」 | live A t=1595 hint_b 指引过时实播 |
V 类观察项(本轮不动作):NPC 平铺回退 404 噪音(引擎级,abyss R1 同源);intro_w3 与 male 旁白同嗓背靠背(待人耳试听清单);FINISH 入口 tap 双震(引擎基础震+turn cue 叠加,轻)。
句数账:旁白基表 96→104(+fin_pre/recap_cf/gd_board_cf/st_wrong/item_who×4)、NPC 52→53(+z_react_w)、V 组 10→14 对(+fin_pre/fin_who_confirm/recap_cf/gd_board_cf);总 158→171 句 ≤176 新上限(原 160 上限裁定作废);音频 289 条 ×2 格式 = 578 文件。