Files
SoundGame/docs/design/26-apply-abyss.md
T
xsl ee5d4d2544 feat(playbook): 26 号交互手册全量落地——剩余 12 款深度重构 + 语音全量重制
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 置完成。
2026-10-02 12:33:20 +08:00

12 KiB
Raw Blame History

26-apply · 《深海回音》重构施工单(26 号文档落地)

设计单正文见 17-abyss.md 附录 C(状态×手势矩阵、等待点配置、 首 3 分钟逐秒脚本、失败表、氧气经济与四结局判定——不在本文重复)。本文件是瘦版 施工单:只写实现接线、偏差记录、台词类别映射、测试记录。台词登记见 17-abyss-voice-ids.md R3 增量节;清单见 tools/voice_lines_26/abyss.md。交互权威:26-audio-interaction-playbook.md。 范式对齐 26-apply-storyline.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(下潜链尾教学);p1p9 选项句(整句,含 p7_chen/p7_zheng);g9_in / c_none / dry_a / dry_b(结算链首句 死窗);结局链首句(e1e4_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 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 人)。