storyline/escape/simon 首批之后的推广收官:15 款全部按 26 号模式运行 (发言权/回执/三档提示/迷茫接管/手势阶梯/断点复述),旧「双击重听/格挡/ 菜单确认」等反模式口径全线废除,开场零规则念白(首句即动手)。 游戏层(12 款):rpg(格挡=前摇窗口内再单击)/ rhythm / space / radio / dungeon / abyss / detective / cipher / teahouse / keeper / bridge / hunt(联机切片): - 每款 game.js 接引擎六模块 + makeInputPipeline(doubleTapWindow:0); 四向玩法类 swipeCore + 长按帮助;双击是玩法的(space 护盾 / hunt 旋风斩)按手势阶梯阶段 3 分档恢复双击窗口(doubletapCore) - 每款 playtest 重写:玩法断言 + §6.2 乱点机器人(无声操作 / 被动 原句重复 / 打断失败 = 0);15 款 3900+ 断言全绿 - 12 份 docs/design/26-apply-*.md 施工单 + tools/voice_lines_26/ 台词清单 + voice-ids 文档同步 + 转写会话剧本按新口径重写 引擎层(web/engine/,6 处修复):pipeline 增 doubletapCore;novice teachLine 带 voice/ 前缀(此前教学句被静默丢弃);confusion.record 前置到新手门(锁定手势的乱点也计信号);InvalidHints 播完恢复解释前 状态(根治孤儿 BUSY);WaitPoint takeover(2) 台账去重;台账只在 speak 真正播出时登记。遗留引擎债登记 roadmap §3.1。 语音资产:台词表合并(新增 ~250 系统句 / 改 ~50 旧口径 / 删 ~110 废止句;合并器 tools/merge_voice_lines_26.py + 引用校验器 tools/validate_voice_refs.py),GPU 重录 1536 wav → 4204 ogg/m4a 落地,check_all_assets + validate_voice_refs 双绿;键盘变体同步扩表。 大厅/文档:15 款统一新交互口径(「新交互」徽标退役);README / HANDOVER / rpg README 旧口径修正;roadmap P0-P3 置完成。
143 lines
12 KiB
Markdown
143 lines
12 KiB
Markdown
# 26-apply · 《深海回音》重构施工单(26 号文档落地)
|
||
|
||
> **设计单正文见 [17-abyss.md](17-abyss.md) 附录 C**(状态×手势矩阵、等待点配置、
|
||
> 首 3 分钟逐秒脚本、失败表、氧气经济与四结局判定——不在本文重复)。本文件是瘦版
|
||
> 施工单:只写实现接线、偏差记录、台词类别映射、测试记录。台词登记见
|
||
> [17-abyss-voice-ids.md](17-abyss-voice-ids.md) R3 增量节;清单见
|
||
> `tools/voice_lines_26/abyss.md`。交互权威:[26-audio-interaction-playbook.md](26-audio-interaction-playbook.md)。
|
||
> 范式对齐 [26-apply-storyline.md](26-apply-storyline.md)(叙事型主参考)与
|
||
> [26-apply-radio.md](26-apply-radio.md)(双音色组同型 + HOST/PROD 系统句归类先例)。
|
||
|
||
## 1. 一句话核心动作
|
||
|
||
**听一段深海救援:单击继续或发声呐脉冲;听到选项时左右滑做决定。**
|
||
|
||
## 2. 实现接线(web/abyss/game.js + index.html)
|
||
|
||
六模块(§4.1/§4.2/§4.3/§4.4/§4.5/§4.12)全部接通,玩法核心(节点链 + seqToken +
|
||
pendingChoice 骨架、氧气步进经济、9 抉择、4 结局 + 尾声回响、DIVER/DECK 双音色 +
|
||
NPC 平铺、存档 summary)不动:
|
||
|
||
- **接线**:`this.receipts = new Receipts(audio)`、`this.floor = new Floor(audio)`、
|
||
`this.confusion = new Confusion({ onConfused: (lvl) => waitPoint?.takeover(lvl) })`、
|
||
`this.invalidHints = new InvalidHints().bind(this.floor)`、`this.ladder = new GestureLadder()`
|
||
(构造时按 `ladder.stage() >= 3` 开旁白加速)。`index.html` 照 storyline 同构:
|
||
`makeInputPipeline({ floor, confusion, receipts, invalidHints, game, ladder,
|
||
opts: game.PIPELINE_OPTS })` + `attachGestures(root, pipe, { doubleTapWindow: 0 })`,
|
||
启动遮罩保留。
|
||
- **PIPELINE_OPTS = `{ longpressCore: true }`**:长按由游戏层裁定——新手期 invalid
|
||
(回执 + gd_invalid 首次解释),阶段 3 起 = 引擎旁白加速(`hold`,等待点保留)。
|
||
doubleTapWindow: 0 → 未解锁双击由管道折算成 tap(搜索等待=再发一枚脉冲)。
|
||
- **`onGesture` 返回值收口**(§4.2):`'ok'`(继续/抉择/菜单/状态)|`'hold'`
|
||
(重听、菜单换项——等待点保留)|`'silent-ok'`(**搜索等待单击=发脉冲**:声呐脉冲
|
||
即内容音,省 ok 回执)|`'invalid'`(pipeline 给回执 + explainOnce + 迷茫信号)。
|
||
- **打断快照 `_chainSpeaking`**(本轮新增,见偏差 5):pipeline 的
|
||
`floor.handleInput(滑动/长按)` 按 §4.1「打断并执行」先杀链把 floor 置 BUSY,游戏侧
|
||
`floor.speaking` 已为 false——`_chainSpeaking` 在 speak 置位、onDone/interrupt/
|
||
`_yieldTurn` 清零,让被掐断的旁白链按矩阵落「旁白中」分支(滑动命中抉择点 →
|
||
缓存 pendingChoice + 跳选项句;未命中/长按 → `_recoverInterrupted()` 交回 continue
|
||
等待点,零无声死锁)。
|
||
- **pendingChoice(V1 播完才生效)**:旁白链中滑动只缓存方向并跳去 p* 选项句
|
||
(`_swipePromptTarget`:本节点是抉择节点或 next 直入抉择节点);p* 整句 critical
|
||
(tap=busy 不可跳),`_armChoice` 在选项句播完的当刻让缓存生效:ui_confirm 结算音 →
|
||
结果句,零插播(W2 契约 + 盲玩公平)。
|
||
- **critical 清单**(§8 台词类别 / 结算死窗等价实现):sys_first_tap(开场第一句)、
|
||
dv1_teach(下潜链尾教学句)、p1~p9 选项句(整句)、lockFirst 节点首句(g9_in /
|
||
c_none / dry_a / dry_b——结算链首句死窗)、结局链首句、恢复链首句(F4:
|
||
`_resumeGuard` 播完即清)。**替代旧 800ms 手势死窗**:覆盖整句而非定时窗。
|
||
- **sonarGate(§5 声呐与语音互斥)保留**:信息类声呐音(echo_*/pipe_knock)只在
|
||
voice idle 时播出,否则挂队、链歇补发(`_sonar`/`_drainSonar`);玩家脉冲只在
|
||
搜索等待(voice 恒静)受理,按构造不重叠。
|
||
- **声呐步 = BUSY(`_runSteps` + `_seqBusy`)**:pre/post 信息音、危机前置(spark_flash/
|
||
landslide 前置 2s + danger 震循环 ≥1000ms 间隔)期间手势统一 busy 回执——旧
|
||
「tap 快进回波余音」废除。
|
||
- **存档(§4.12/§7)**:DIVE 进入、SURFACE 进入、每个抉择结算后、ENDING 进入、
|
||
stop() 退出、菜单「保存并回大厅」前(leaving 标记);MENU 态落盘记回原状态;ASK
|
||
态不落盘(stash 原存档才是真进度)。runs 口径 = `newRun()` 时 +1(冷启动 0 起;
|
||
ASK 右滑与结算单击同口径)。
|
||
- **手势阶梯教学句挂链尾**:第一次脉冲成功(`_firePing` → `ladder.onGoal()`)→
|
||
`sys_unlock_up` 挂本条回波链尾;一局结局(`enterEnding` → `onGameDone()`)→
|
||
`sys_unlock_down` 挂结局链尾。`teachLine()` 已带 `voice/` 前缀(novice.js 修复后
|
||
语义),游戏侧**直接引用不再拼前缀**(双前缀是曾出现过的坑,静态审计拦截
|
||
`` `voice/${` `` 模板拼接)。
|
||
- **上滑「我在哪」**(§3/§9 顺序:潜次 → 已救人数 → 氧档 → 一个动作):`interrupt` 摘
|
||
等待点(状态链期间静默 timer 清零,见偏差 6)→ 状态句全量 `markHintSaid` → 播完
|
||
**按原等待点类型重建**(搜索重挂/抉择重挂/结算/continue——radio 口径不重播节点)。
|
||
crit 档附 warning 震按档进入去重;`oxy_crit_deck` 水面变体(R2-F5)保留。
|
||
|
||
## 3. 偏差记录(与 26 号手册 / 17 号附录 C 的实现偏差)
|
||
|
||
1. **搜索等待声(17 号 §2)**:引擎 Bed 为全局统一音色,游戏层在 ping 等待点置
|
||
`floor.bedEnabled = false`——等待声由 amb_deep 常驻 + 回波余音的深海声场承担
|
||
(`_yieldTurn` 按等待点 id 翻转)。测试侧统一压 false(mock 防周期定时器不排水)。
|
||
2. **critical 粒度**:floor 的 critical 是整链一刀切,句级保护靠**拆链**实现
|
||
(`_speakNodeVoices` 按 critical 分段顺序播)。非 auto 叙事节点的尾句**不做**首播
|
||
critical——链级一刀切会把「滑动打断并执行 / 上滑我在哪」一并挡成 busy(§4.1
|
||
宪法);叙事尾句跳过的代价只是提前进等待点,由三档提示兜底复述。
|
||
3. **auto 过场链尾恒 critical**(`_tailLocked`):dv1_teach(教学句)、s_tier 档位句、
|
||
p9 结果链尾、取消链尾——「next 是 @x 过场」时链尾即过场门,不可跳。
|
||
4. **搜索等待单击恒出脉冲(silent-ok)**:包括等待声中的抢拍单击——比「轮到你提示音
|
||
后才受理」更宽(17 号 §4:再单击=再听);四潜各恰一枚玩家脉冲由 playtest 断言。
|
||
5. **打断快照为游戏层补丁**:引擎 pipeline/floor 未提供「这次手势打断了一条链」的
|
||
回执,`_chainSpeaking` 由游戏包装 floor.speak/interrupt 维护(上游修复后可撤)。
|
||
无效滑动打断旁白 → invalid 回执 + 解释句 + **交回 continue 等待点**(不重播原句,
|
||
原则 9;链末单击继续到下一节点)。
|
||
6. **引擎缺口(上报,未改引擎)**:`engine/hints.js` 的 `use()` 在 `ledgerSay(id)` 之后
|
||
才 `floor.speak`(kind hint)——静默提示到点时恰逢 SPEAKING(如上滑状态链播放中)
|
||
句子被丢弃**但台账已记**,之后 30s 内同句被动提示会错降档。游戏侧规避:上滑先
|
||
`interrupt`(清 timer,状态链期间零 fire)。建议引擎改为「speak 返回 false 时不登
|
||
台账」。同类:`InvalidHints.explainOnce` 的 ledgerSay 也在 speak 前。
|
||
7. **结算重开链**:`sys_new_dive → b_open → b_goal → b_go`(重开不念开场教学,原则
|
||
11——sys_first_tap/sys_skip 每实例一次);开场链首句 critical 指令、b_goal 极短
|
||
目标句、b_rule/gd_brief 规矩念白废除(§4.10)。
|
||
8. **状态链动作句**:search=「点一下,发脉冲。」(sys_act_ping 兼首次解释句);
|
||
choice=「正在抉择。左右滑。」(status_choice);settle=「单击,开始新救援。」
|
||
(sys_hint_settle_full);continue=「单击,继续。」——全部 DECK 组、进台账。
|
||
|
||
## 4. 台词类别映射(类别标注;增量清单见 `tools/voice_lines_26/abyss.md`)
|
||
|
||
- `critical`:sys_first_tap(开场 ≤3s 唯一指令);dv1_teach(下潜链尾教学);p1~p9
|
||
选项句(整句,含 p7_chen/p7_zheng);g9_in / c_none / dry_a / dry_b(结算链首句
|
||
死窗);结局链首句(e1~e4_a);恢复链首句(F4)。
|
||
- `content`:b_*、各潜对白(dv*/sv*/z1/bai/chen/gao/d*_e 组)、结局与尾声
|
||
(e*_b、ep_*)、prog_d1..4、prog_saved1..5、oxy_full/ok/low/crit/crit_deck/gain、
|
||
sys_turn_teach、sys_unlock_*、sys_menu、menu_help、sys_menu_*、sys_new_dive、
|
||
sys_continue_ask、sys_skip。
|
||
- `hint`:sys_hint_ping_full/short、sys_hint_continue_full/short、
|
||
sys_hint_choice_short、sys_hint_settle_full、sys_only_choice、sys_demo_continue、
|
||
sys_demo_choice、status_choice、sys_say_again(「再说一遍:」前缀,engine/hints.js
|
||
播出)。
|
||
- `feedback`:sys_act_ping(搜索等待无效滑动首次解释)、inv_nosel、inv_up_locked、
|
||
inv_down_locked、gd_invalid(通用格,保留旧句)、sys_menu_restart_confirm(重开
|
||
二次确认)。
|
||
- 音色组:系统/交互层全部 `_ABY_DECK`(母船调度=系统音,与 radio PROD 同型);
|
||
剧情潜水员 `_ABY_DIVER`、幸存者 ABYSS_NPC 平铺(不动)。通用系统句与
|
||
STORYLINE_LINES 的 sys_* 段逐字一致;键盘变体照 KEY_LINES["storyline"]。
|
||
- 完整登记(新增 23 / 修改 1 / 删除 10)见 `tools/voice_lines_26/abyss.md` 与
|
||
[17-abyss-voice-ids.md](17-abyss-voice-ids.md) R3 增量节。
|
||
|
||
## 5. 测试记录
|
||
|
||
- 无头 playtest:`web/abyss/test/playtest.mjs` **243 断言全绿**(`tools/node/bin/node
|
||
web/abyss/test/playtest.mjs` 退出码 0;`node --check web/abyss/game.js` 通过)。
|
||
覆盖:§4.10 首 3 分钟(3s 内动手、critical 指令句、规则念白零播出);剧本 A~F
|
||
六路径四结局 + 氧气逐检查点验算 + 氧气门三形态 + 干涸链 + 尾声回响差分;
|
||
pendingChoice V1 时序(缓存 → 选项句播完 → ui_confirm → 结果句);sonarGate
|
||
零重叠 + 四潜各一脉冲;结算死窗(取消链/结局链首句 critical,幽灵手势不截链);
|
||
等待点三档(ping 8/18、continue 13/30、choice 25 台账降档);迷茫接管三级
|
||
(L1 短句 → L2 缩小 → L3 替发脉冲);手势阶梯(阶段 1/2 教学句挂链尾);
|
||
§4.12 断点复述(ASK 左/右、F4 恢复首句锁、上滑状态链);菜单(左右滑换项 +
|
||
单击确认 + 二次确认重开 + 回大厅);资产缺失续链;键盘变体路由;**§6.2 乱点
|
||
机器人**:无声操作 0(0/309)、被动原句重复 0、打断失败 0、第一次操作 ≤10s
|
||
(2120ms)、第一次成功 ≤20s(2120ms)、乱按不锁死(零死锁收在合法等待态)、
|
||
关键路径手势预算 9 ≤70;静态审计(无运行时 id 拼接、11 句废止台词零引用、
|
||
19 条游戏引用新台词待生成豁免 + 引擎侧 4 条入清单)。
|
||
- 玩家感知转写:`web/harness/sessions/abyss.mjs` 已同步 26 号口径(菜单左右滑换项
|
||
+ 单击确认、结局结算后下滑逛菜单——阶段 2 解锁时机、SURFACE 签收链中段链末
|
||
单击继续、COMMS 走神触发 13s 首档提示),`tools/node/bin/node
|
||
web/harness/transcribe.mjs abyss`(含 `--session sessionStress`)两剧本零死锁
|
||
跑通(主线虚拟 279s 到 E1 海燕归钟;乱按剧本同达 E1)。
|
||
- 新语音资产(23 句 DECK 组 + 键盘变体)由主会话统一生成;playtest mock 与真实
|
||
资产解耦(缺失按可用处理,Floor 看门狗兜底)。
|
||
- 真人冷启动:待测(26 §6.3,3~5 人)。
|