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 置完成。
12 KiB
12 KiB
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 的实现偏差)
- 搜索等待声(17 号 §2):引擎 Bed 为全局统一音色,游戏层在 ping 等待点置
floor.bedEnabled = false——等待声由 amb_deep 常驻 + 回波余音的深海声场承担 (_yieldTurn按等待点 id 翻转)。测试侧统一压 false(mock 防周期定时器不排水)。 - critical 粒度:floor 的 critical 是整链一刀切,句级保护靠拆链实现
(
_speakNodeVoices按 critical 分段顺序播)。非 auto 叙事节点的尾句不做首播 critical——链级一刀切会把「滑动打断并执行 / 上滑我在哪」一并挡成 busy(§4.1 宪法);叙事尾句跳过的代价只是提前进等待点,由三档提示兜底复述。 - auto 过场链尾恒 critical(
_tailLocked):dv1_teach(教学句)、s_tier 档位句、 p9 结果链尾、取消链尾——「next 是 @x 过场」时链尾即过场门,不可跳。 - 搜索等待单击恒出脉冲(silent-ok):包括等待声中的抢拍单击——比「轮到你提示音 后才受理」更宽(17 号 §4:再单击=再听);四潜各恰一枚玩家脉冲由 playtest 断言。
- 打断快照为游戏层补丁:引擎 pipeline/floor 未提供「这次手势打断了一条链」的
回执,
_chainSpeaking由游戏包装 floor.speak/interrupt 维护(上游修复后可撤)。 无效滑动打断旁白 → invalid 回执 + 解释句 + 交回 continue 等待点(不重播原句, 原则 9;链末单击继续到下一节点)。 - 引擎缺口(上报,未改引擎):
engine/hints.js的use()在ledgerSay(id)之后 才floor.speak(kind hint)——静默提示到点时恰逢 SPEAKING(如上滑状态链播放中) 句子被丢弃但台账已记,之后 30s 内同句被动提示会错降档。游戏侧规避:上滑先interrupt(清 timer,状态链期间零 fire)。建议引擎改为「speak 返回 false 时不登 台账」。同类:InvalidHints.explainOnce的 ledgerSay 也在 speak 前。 - 结算重开链:
sys_new_dive → b_open → b_goal → b_go(重开不念开场教学,原则 11——sys_first_tap/sys_skip 每实例一次);开场链首句 critical 指令、b_goal 极短 目标句、b_rule/gd_brief 规矩念白废除(§4.10)。 - 状态链动作句: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.mjs243 断言全绿(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)。
- 单击确认、结局结算后下滑逛菜单——阶段 2 解锁时机、SURFACE 签收链中段链末
单击继续、COMMS 走神触发 13s 首档提示),
- 新语音资产(23 句 DECK 组 + 键盘变体)由主会话统一生成;playtest mock 与真实 资产解耦(缺失按可用处理,Floor 看门狗兜底)。
- 真人冷启动:待测(26 §6.3,3~5 人)。