# 26-apply · 《回声地窟》重构施工单(26 号文档落地) > **设计单正文见 [16-dungeon.md](16-dungeon.md) 附录 C**(一句话核心动作 / 状态 / > 手势表 / 等待点 / 首 3 分钟脚本 / 失败表 / 台词账目 / 断点复述),本施工单不重复, > 只写:实现接线(§11)、偏差记录(§12)、台词类别映射(§8)、测试记录(§10)。 > 交互规则权威来源:[26-audio-interaction-playbook.md](26-audio-interaction-playbook.md)、 > [00-global-ux.md](00-global-ux.md) §5.3。台词登记 [16-dungeon-voice-ids.md](16-dungeon-voice-ids.md)。 > 本次只动交互层:地窟生成、回声编码、战斗数值、遗产经济一概不动。 ## 1. 一句话核心动作 **朝四个方向滑动在洞窟里走,单击发出声波脉冲听地形,按住屏幕问路。** ## 2. 玩家可感知的状态(3 个)与声音身份 | 状态 | 听感 | 来源 | |---|---|---| | 探索(轮到你) | 洞穴环境垫 amb_cave(静默 20s 补一层)+ 脚步/回声/怪物脚步就是状态声 | §4.1 ACTION | | 听讲(游戏在说) | 教学/遭遇/结算语音,BGM 整链压低(floor.holdDuck) | §4.1 SPEAKING | | 危险(战斗) | battle/boss BGM;敌方前摇音 tel_* + beat 震;血 ≤25% warning 震 | ACTION + 战斗曲即状态 | 撞墙 = 闷响 bump + invalid 回执,不算第四态(一次性教,见 §7)。 ## 3. 新手手势表(四向滑动是玩法 → §4.3 裁定:帮助换到长按) | 手势 | 含义 | 说明 | |---|---|---| | 四向滑动 | **面朝相对移动**:上=前进一格;左=向左一格并转向;右=向右一格并转向;下=后退一格(面朝不变) | swipeCore,阶段 0 即核心,不按阶梯锁 | | 单击 | 脉冲(探索);楼梯格=下潜确认;战斗我的回合=挥击;敌方前摇窗内=格挡 | 核心动词;旧「双击=免冷却重发」「双击=格挡」废除 | | 长按 | 我在哪(层[+血 if 伤]+面朝+目标方位,≤20 字) | longpressCore;旧「按住前进」废除;对局期关闭旁白快进 | | 双击 | 新手期按单击处理;阶段 3 = 重听(结算/标题重听等待点句;探索 = 冷却外再脉冲) | 禁绑「立刻免冷却重播」 | | 下滑 | 探索/战斗=后退/逃跑(玩法占用);菜单仅阶段 2 且 TITLE/SETTLE | 00 §5.3 | 管道:`makeInputPipeline({ ..., opts: { swipeCore: true, longpressCore: true } })` + `attachGestures(root, pipe, { doubleTapWindow: 0 })`。 ## 4. 状态 × 手势矩阵(新手期) | 状态 \ 手势 | 单击 | 四向滑动 | 长按 | 双击(未解锁) | 连点/乱滑 | |---|---|---|---|---|---| | TITLE | 开始/继续 + ok | 右=新周目;上=元进度链;左/下(未解锁)=invalid+解释 | 重听询问句 | 按单击 | 计入迷茫 | | 教学作答 | 按步骤(脉冲/确认) | 按步骤走/转向;步骤外 invalid+inv_drill | 帮助(D5 即教学内容) | 按单击 | 计入迷茫 | | 探索(ACTION) | 楼梯格=下潜;否则脉冲+回声组(silent-ok);冷却中 invalid+inv_pulse | 移动=脚步(silent-ok);撞墙=bump+invalid+归因+方位真话 | 帮助(层/血/面朝/方位) | 按单击(=再脉冲) | 乱滑计入迷茫;冷却连点 invalid | | 描述在播 | 跳过这句 + ok | 打断并移动 | 打断,帮助 | 按单击 | 第一下有效 | | 战斗·我的回合 | 挥击(面前才中) | 左/右=转身(缠斗怪 btl_no_turn 每场一次);下=逃跑(Boss 拒绝);上=战斗状态 | 帮助(血+敌方位) | 按单击 | 计入迷茫 | | 战斗·敌前摇 | **格挡**(面对 ×0.2 / 未面对 ×1.0) | 左/右=转身(来得及则面对) | invalid+inv_tel | 按单击=格挡 | 只处理第一下 | | DESCEND 演出 | 跳句 + ok | 打断演出(兜底定时器续流程) | 同左 | 按单击 | busy/ok | | 结算(critical 链) | busy 回执(死亡/通关归因链不打断) | busy 回执 | busy 回执 | busy | busy | | 结算(等待) | 再探一次 + ok | 上=元进度链;左=invalid+inv_settle;下(阶段2)=菜单 | 重听结算句 | (阶段3)重听结算句 | 只处理第一下 | | 菜单 | 确认当前项 + ok | 右=下一项 / 左=上一项(hold);上=帮助 | 重听菜单说明 | 按单击=确认 | busy | | 迷茫 L2 期间 | 照常 | 只放行接管方向,其余 invalid(不移动) | 照常 | 照常 | 照常 | 验收:无空格、无「没有声音」的格子;连点/乱滑无破坏性效果(重开走菜单二次确认)。 ## 5. 等待点配置表(教学期)与探索期接管 教学等待点(6s/15s 两档;wrong 手势 = invalid 回执 + explainOnce,三级接管后 75s 兜底自动过步): | 步 | 期待 | 指令句(full) | short | |---|---|---|---| | D0 | 单击 | d0_new「黑暗。点一下,听回声。」(critical) | sys_first_tap_short「点一下。」 | | D1 | 再单击(巩固) | tut_praise + tut_front_rule(回声规则) | 「点一下。」 | | D2 | 上滑(前进) | sys_turn_teach → tut_move「朝前,滑一下。」 | hint_swipe「滑一下。」 | | D3 | 左/右滑(侧移转向) | tut_side_move「向左滑,转身走。」 | hint_swipe | | D4 | 走到金币格(四向) | tut_coin「房里有金币,走过去捡。」→ 拾取即 ladder.onGoal() | hint_swipe | | D5 | 长按 | tut_help_hold「迷路了,按住屏幕。」→ 帮助链即答案 | 「按住屏幕。」 | | D6 | 教学战:前摇单击格挡→单击挥击 | tut_mob → tut_parry_tap → tut_attack | btl_turn_short「点一下,打。」 | | D7 | 自行走到楼梯→单击下潜 | tut_stairs「铁器的回声,就是下潜的楼梯。」 | hint_swipe | 其他等待点: | id | 期待 | full | short | 静默 | L3 演示 | |---|---|---|---|---|---| | title | tap/right | sys_first_tap / sys_continue_ask | 「点一下。」 | 12s/30s | 提示音 | | battle | tap/left/right | gd_turn「轮到你了。单击挥击。」 | btl_turn_short「点一下,打。」 | 8s/15s | 游戏替你挥一拳 | | settle | tap | settle_again「单击,再探一次。」 | 「点一下。」 | 20s/45s | 提示音 | | menu | tap/left/right | menu_help | menu_help | 20s/45s | 提示音 | 探索期(无固定等待点,静默 40s 起每 20s 喂迷茫信号)三级接管: | 级 | 做什么 | 台词 | |---|---|---| | 1 | 说目标(铁器暗示/窟主守梯,30s 台账去重) | stair_hint_a「找找铁器的回声,那是楼梯。」/ stair_hint_b | | 2 | 只放行最短路首步方向(面朝相对换算) | sys_only_*「现在,只要向左滑。」 | | 3 | 听我做一次:游戏自己朝楼梯走一步 | sys_demo + 脚步声 + sys_now_you | 进展事件(拾取/击杀/踏上楼梯/下潜/下潜层)清零重来。 ## 6. 首 3 分钟逐秒脚本 | 时间 | 游戏说 / 播 | 期待玩家做 | 没做 | 做错 | |---|---|---|---|---| | 0~3s | amb_cave →「黑暗。点一下,听回声。」(critical) | 单击脉冲 | 6s:「点一下。」15s:提示音 | 滑动:invalid + inv_drill | | 3~8s | pulse + echo + 材质 →「对。」「回声回来越快,墙就越近。」 | 再点一次(巩固) | 「点一下。」 | 冷却内连点:invalid + inv_pulse | | 8~10s | 第二组回声 + 奖励音(levelup 低音量)= 第一次成功 | — | | | | 10~25s | 「听到这个声音,就是轮到你了。」→ 交话轮 →「朝前,滑一下。」 | 上滑前进 | 「滑一下。」 | 撞墙:bump + wall + wall_dir_front | | 25~40s | 「向左滑,转身走。」→ 转身声+脚步 | 左/右滑侧移 | 「滑一下。」 | 其他方向也走(D3 接受左右) | | 40~60s | 「房里有金币,走过去捡。」→ 拾金币 + onGoal | 四向滑动 | 三档提示 | 撞墙归因 | | 60~75s | 「迷路了,按住屏幕。」→ 帮助链(层/面朝/楼梯方位) | 长按 | 「按住屏幕。」 | 其他:inv_drill | | 75~90s | 「前面有东西!放心,它伤不到你。」→ 教学蝠逼近 | 听脚步 | 接管 | 乱动:战斗内纠错 | | 90~180s | 「听到动静,单击格挡。」→ 前摇单击格挡 →「现在单击,挥拳打它」至击杀 →「铁器的回声,就是下潜的楼梯」→ 自行走到楼梯 →「楼梯就在脚下。单击,下潜。」 | 单击 | 三档/接管 | 挥空:btl_swish 每场一次 | 节奏检查 ✓:3s 内脉冲;~8s 第一次成功(听懂回声);每 30s 有可听进展(金币/击杀/下潜);开场零规则念白(intro_1/intro_2 砍掉)。 ## 7. 失败表 | 失败类型 | 判定 | 归因句 | 回到哪里 | 新手期代价 | |---|---|---|---|---| | 撞墙 | 目标格越界 | 首次 wall「那边是墙。」;每方向整局一次 wall_dir_{front,left,right,back},之后只 bump+invalid | 原地 | 无伤 | | 脉冲冷却 | 1.2s 内再点 | inv_pulse「回声还没回来,稍等。」(状态×手势一次) | 原地 | 无 | | 挥空 | 怪不在面前 | btl_swish 每场一次(之后只挥空声) | 本回合 | 无 | | 格挡失败 | 前摇内未点/未面对 | 「慢了。听到就点。」= tut_parry_miss(教学期);背后 = btl_behind 每场一次 | 下回合 | L1–2 怪打不死你 | | 转身无效 | 缠斗怪时左右滑 | btl_no_turn 每场一次,之后仅 invalid | 本回合 | 无 | | 死亡 | HP≤0 | die_cause_* 按 lastHit;die_adv_* 按真实格挡/逃跑账(critical 链,不许打断) | SETTLE→新周目,金币入 meta | 学期不可能死 | | 迷路 | 迷茫信号 | 接管 L1→L2→L3 | 原地 | 无 | ## 8. 台词表(类别标注;清单见 tools/voice_lines_26/dungeon.md) - `critical`:d0_new(开场指令 <3s);死亡链 die_intro→…→settle_again 整链(结局,§4.6);通关链同 - `content`:intro 砍掉后的教学链(tut_praise/tut_move/tut_side_move/tut_coin/tut_help_hold/tut_stairs/tut_mob/tut_attack…)、st_*(层/血/金/面朝/威胁)、evt_*、btl_*(遭遇/半血/击杀/战利)、unlock_*、settle_win_*、tut_stairs_on - `hint`:长按帮助链(st_floor/st_face/stair_dir_*)、gd_turn、btl_turn_short、hint_swipe、sys_first_tap(_short)、sys_continue_ask、stair_hint_a/b、menu_help - `feedback`:wall、wall_dir_*、inv_*(pulse/title/settle/drill/tel/menu_locked)、btl_swish、btl_behind、btl_no_turn、tut_parry_miss、die_cause_*、die_adv_*、sys_only_*、sys_demo、sys_now_you、menu_restart_confirm - 通用系统句与 storyline 逐字一致:sys_first_tap / sys_turn_teach / sys_say_again / sys_unlock_down / sys_unlock_dt(00 号 §5.2 阶梯表)。 - 数字全分档整句不变(层 7 / 血 4 / 面朝 4 / 威胁 4 / 战利 3 / 死因 3 / 建议 3 / 元进度 3; 金位 = meta_gold 3 档 + gold_some 真话句——旧上滑状态链的 st_gold_1..4 随链下线)。 - 净变化:新增 35、修改 4、删除 25(明细见 `tools/voice_lines_26/dungeon.md`);127 → 137 句 ×2 性别。 ## 9. 断点复述句 - 保存:拾取/战斗胜负/下潜/死亡/菜单保存/stop() 自动存(schema 1,summary 字段不变:`第{floor}层 · {血量档} · 金币{meta.gold} · 遗产{n}/5`)。 - 回来:TITLE 播 sys_continue_ask → 交出话轮;单击 = 恢复 + 复述链 `[st_floor_N, st_hp_X, st_face_X, 楼梯方位句]`(窟主未清换 stair_hint_b)→ 回 ACTION;右滑 = 新周目(meta 保留,开局 sys_new_run + 同款复述链)。 ## 10. 测试记录 - 无头 playtest:`tools/node/bin/node web/dungeon/test/playtest.mjs`,**11 场景 + 资产审计, 断言 1551 条全绿、退出码 0**(2026-10-02,seed 42/2026 等种子复现)。覆盖: 1. seed 复现与七层网格不变式(两次构造逐格相等 / 连通 / 楼梯=最远房 / 安全区 / 密度 / L1 教学硬约束); 2. 新教学链 D0~D7 全走通 + 回声调度全扫描(全地板格 ×4 面向 ===grid 真值,含延迟/音量/侧向时序)+ 下潜复现; 3. 四向相对移动矩阵 / 撞墙归因(wall + wall_dir_* 每方向一次)/ 脉冲冷却 invalid / 双击(阶段 3)冷却外再脉冲 / 长按帮助 / 呼吸层; 4. 战斗数学(单击格挡 ×0.2 / 缠斗纠错 / 下滑逃跑 / Boss 拒绝 / 绕位背刺 / 半血 ATK+1 / 自动喝药); 5. 死亡归因真话 + 遗产自动购置 + 结算 critical 链(在途手势全 busy)+ 菜单(左右滑换项 / 单击确认 / 重开二次确认); 6. 断点复述(stop 自动存档 / continue_ask / 复述链 / 右滑新周目 meta 保留); 7. 迷茫接管三级(静默 40s 起 L1 目标句 → 乱撞 L2 sys_only_* 只放行 → 连续无效 L3 演示+交回;进展事件清零重来); 8. 屏蔽 voice 资产流程不卡死(_sayFlow/_drillChain 兜底); 9. L1..L7 全网格回声一致性 + 贴身即接战; 10. 管道契约(stateName / invalidHint / PIPELINE_OPTS = { swipeCore, longpressCore }); 11. §6.2 乱点机器人(150 步):无声操作 0 / 打断失败 0(防连点 busy 回执不计——§4.2 刻意抑制且已有可听反馈)/ 被动原句重复 0 / 首次操作 ≤10s / 首次成功 ≤20s。 - 资产审计:静态引用 192 id 全量双格式(ogg+m4a)齐全;新句以 PENDING_VOICE 35 条虚拟资产 模拟(照常播放可断言),主会话生成落地后清空清单即自动转实物断言(台词数断言 127 → 137, 口径见 `tools/voice_lines_26/dungeon.md`「生成与验收」)。 - 真人冷启动:待测。 ## 11. 实现接线(引擎六模块,对齐 escape 参考) - **装配**(game.js 构造器 + index.html):`this.receipts / this.floor / this.confusion / this.invalidHints(= new InvalidHints().bind(floor)) / this.ladder` 全部暴露; `audio.setRateBoostEnabled(false)`(长按=帮助是核心手势,不触发旁白快进)。 `get PIPELINE_OPTS() = { swipeCore: true, longpressCore: true }`;index.html 照 escape: `makeInputPipeline({ floor, confusion, receipts, invalidHints, game, ladder, opts })` + `attachGestures(root, pipe, { doubleTapWindow: 0 })`。 - **onGesture 收口**:返回 `'ok' | 'hold' | 'invalid' | 'silent-ok'`(移动=脚步声 silent-ok;撞墙/冷却/步骤外=invalid;转身(玩家回合)=hold 不消耗回合)。 `stateName()` → title/drill/explore/battle/tel/settle/menu/descend;`invalidHint(state, g)` → inv_pulse / inv_title / inv_settle / inv_drill / inv_tel / menu_help / locked=null (四向+长按均核心,无锁态)。 - **floor 状态流**:探索/教学自由步 `floor.enterAction()`(玩法声即状态);描述/归因/ 帮助链走 `floor.speak`(`_sayContent`,播完回 ACTION 或等待点);流程链 `_sayFlow` (自然播完或超时先到先推进,资产缺失不卡死);教学链 `_drillChain`(arm 有界兜底)。 等待点 `WaitPoint`:drill0..7 / title / battle / settle / menu,全配 full/short/ silenceMs/expected/onDemo(§5 表)。 - **confusion**:record 由管道喂(新手门之前,锁定手势也喂信号);探索态静默喂信号 40s 首次、每 8s 再喂(窗口内两记静默可累计权重 2);`onConfused → 等待点 takeover (wp.takeover)`,探索态/教学态走游戏侧 `_takeover / _drillTakeover`(三级,台账去重)。 - **novice 阶梯**:D4 拾金币 = `ladder.onGoal()`(阶段 1;返回的 up 教学对四向玩法 无意义,与 escape 同样忽略);死亡/通关 = `ladder.onGameDone()`(阶段 2/3),返回的 teachLine(**已带 voice/ 前缀,2026-10 novice.js 修复后不要再加前缀**)接在结算链尾。 - **存档**:schema 1、summary `第{floor}层 · {血量档} · 金币{meta.gold} · 遗产{n}/5` 字段不动;拾取/战斗/下潜/死亡/菜单/stop() 自动存。 ## 12. 偏差记录(与 26 号/16 号的落地差异及理由) 1. **D1 巩固步等待点不即时挂**:设计单口径「巩固等待立即挂上」,实现改为回声组落地 (+1.3s)后播规则链、链播完才 yieldTurn——管道契约是「onGesture 返回时 floor 在 YOUR_TURN 即视为完成当前等待点」,手势内同步 yieldTurn 的新等待点会被当已完成摘掉, 随后 invalid 解释链播完无人恢复话轮(floor 停 BUSY 吞手势,D1 卡死根因)。0~1.3s 窗口由回声组内容音覆盖;窗口内抢先单击照常成立(case 1 直答)。 2. **孤儿 BUSY 看门狗**(`_healOrphanBusy`,800ms 周期,仅 stop() 停):引擎 InvalidHints 解释链的 onDone 只在「挂着等待点」时恢复话轮,探索/教学自由步没有 等待点,链播完 floor 停 BUSY——管道在 floor.handleInput 就拦下 busy,游戏层永远 收不到手势。看门狗按当前态拉回规范态(探索=ACTION / 答题步=重挂等待点 / 前摇= ACTION / TITLE·SETTLE=重交话轮)。**引擎缺口**:InvalidHints/feedback 链结束后 的状态恢复依赖调用方,建议引擎侧统一兜底(escape 用无条件 resumeTurn 达成同效)。 3. **教学态接管不走 wp.takeover**:其 L2(restrictLine/short 兜底)无 30s 台账检查, 会把刚说过的指令句原样重播,违反「被动原句重复 = 0」红线;改走游戏侧 `_drillTakeover`(L1 短句 → L2 重教指令句 → L3 `_drillDemo`,全过台账)。 **引擎缺口**:WaitPoint.takeover(2) 建议补台账去重。 4. **战斗玩家回合转身返回 hold**:转身不消耗回合,hold 让管道 settleWaitPoint(false) 保住战斗等待点(血量/敌方位长按链播完要回它;silent-ok 会把等待点当已完成摘掉)。 5. **D4 推进走 1.6s 有界定时**:evt_coin 链被乱手势打断也不丢 onGoal/进 D5(对齐 _sayFlow 兜底语义,步骤号先守恒)。 6. **tut_praise 不进 D4 链**:原则 9 逐字重复禁令(D2/D3 已各一次「对。」),D4 直接 布置任务 tut_coin。 7. **遭遇自动面对落在 _encounter**:走进怪格/相邻扑来先把玩家面朝转到怪的方向 (报名「就在你面前」即真话),保证 D6 单击格挡教学确定性(16 号 §5「遭遇自动面对」)。 8. **btl_no_turn 补 onDone**:链播完回战斗等待点(无 onDone 会孤儿 BUSY,见偏差 2)。 9. **教学不存步骤**:断点回来教学未完从头再练(16 号 §10 口径),DRILL 步骤不进存档。