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 置完成。
141 lines
11 KiB
Markdown
141 lines
11 KiB
Markdown
# 26-apply · 《围猎》重构施工单(26 号文档落地)
|
||
|
||
> **设计单正文见 [23-hunt.md](23-hunt.md) 附录 C**(状态×手势矩阵、等待点表、
|
||
> 首 3 分钟逐秒脚本、失败表、台词类别)。本文不重复正文,只记录实现接线、
|
||
> 偏差、台词类别映射与测试结果。交互规则权威来源:
|
||
> [26-audio-interaction-playbook.md](26-audio-interaction-playbook.md)。
|
||
> 台词增量清单:`tools/voice_lines_26/hunt.md`;登记副本 [23-hunt-voice-ids.md](23-hunt-voice-ids.md)。
|
||
|
||
## 1. 实现接线(web/hunt/)
|
||
|
||
**引擎六模块**(`web/engine/`,未改动):`HuntGame` 构造并暴露 `receipts / floor /
|
||
confusion / invalidHints / ladder`;`invalidHints.bind(floor)`;`confusion.onConfused
|
||
→ _onConfused`:有等待点走 `wp.takeover(level)`,WAVE 对局走本作三级(见 §3)。
|
||
`audio.setRateBoostEnabled(false)`(长按=帮助,不触发旁白快进)。
|
||
|
||
**发言权**(§4.1):
|
||
|
||
| 场景 | Floor 状态 |
|
||
|---|---|
|
||
| TITLE / WAVE / TEACH 战斗 | `enterAction()`(BGM/怪 loop 即状态声) |
|
||
| 波次播报 wave_bandN | `floor.speak`(可被出击打断:打断并执行),播完回 ACTION |
|
||
| LOBBY / 波间休整 / END / LOST / 菜单 | `floor.speak(...)` 后 `yieldTurn(wp)` |
|
||
| MATCHING | BUSY(等 joined;二周目填 intro_1/2,可跳句) |
|
||
|
||
**管道**(index.html 与 playtest 同一接线):`makeInputPipeline({ floor, confusion,
|
||
receipts, invalidHints, game, ladder, opts })`,`opts = { swipeCore: true,
|
||
longpressCore: true }`。**双击窗口分档**:`game.DT_CORE = ladder.stage() >= 3` 快照
|
||
——stage < 3 时 `attachGestures(..., { doubleTapWindow: 0 })`(双击不存在,键盘回车
|
||
折算 tap);stage ≥ 3 用默认窗口 + `doubletapCore: true`(游戏内分发:阶段 3 双击
|
||
= 重听威胁档 threat_*;skillUnlocked(阶段 4)= 旋风斩,冷却中仍回威胁档)。阶段 4
|
||
解锁:首次以 stage≥3 进入大厅播 `skill_teach` 一句并落盘 `progress.skillUnlocked`
|
||
(「大厅全部解锁/专属教学」双口径中的专属教学路径;全项目大厅按钮走
|
||
novice.js 既有 unlockAll)。
|
||
|
||
**onGesture 收口**:`'ok' | 'hold' | 'invalid'`(本作不用 silent-ok:出击/呼喊的内容
|
||
音走 R4 队列可能延迟 >100ms,统一 ok 回执保「禁止静默」红线)。`stateName()`:
|
||
title/matching/lobby/teach/wave/rest/end/lost/menu。`invalidHint(state,g)` 映射见
|
||
game.js `INVALID_LINES`。
|
||
|
||
**教学波**(§4.10):joined(teach) → T0 `sys_first_tap`(critical,首句动手)→
|
||
tap → T1 `tut_hit_full`(critical「朝叫声,滑。」+ 服务器放教学狼)→ 滑砍(错向
|
||
miss → atk_swish + `miss_side`「在另一边。」)→ 首杀(`tut_kill_ok` + ladder.onGoal
|
||
= 阶段 1)→ T2 `tut_call_full` → 呼喊 → bot help_ack → `tut_callout_ok` → T3
|
||
`tut_help_full`(长按=我在哪,阶段 1 教学)→ `tut_done` → 等 ev wave 1。教学步进链
|
||
全部 critical(<3s,警报经 `_alertVoice` 排队到链尾冲刷,R1 教学不可顶)。
|
||
旧 intro_1/2/tut_rule 规则总述废除(反模式 6);无手动跳过(每步 L3 演示兜底)。
|
||
|
||
**等待点**(§4.4 三档;配置见 game.js `_introWp/_hitWp/_callWp/_helpWp/_restWp/
|
||
_endWp`):intro(tap, 6s/15s, L3 替点)、teach_hit(四向, 8s/15s, L3 替出刀)、
|
||
teach_call(tap, 8s/15s, L3 替喊)、teach_help(longpress, 8s/15s, L3 替播帮助)、
|
||
lobby(tap, 8s/12s 服务器自动开局, L3 替发 start)、rest(无 full/short——静默只给
|
||
提示音)、end(tap, 20s/45s)。**wave 等待点无 WaitPoint**:本波未出手 8s 一次 earcon
|
||
(`_startWaveIdleFeed`),出手即停(「本波已出手则永不语音催」);静默信号照喂
|
||
迷茫检测(权重 1,单独不触发接管)。
|
||
|
||
**WAVE 接管**(附录 C §7 迷茫行):L1 `gd_idle`「朝最响的滑。」→ L2 只放行最近怪
|
||
弧(`_restrictArc`,其余 invalid 回执)+ `wave_only` → L3 `_demoKillNearest` 替玩家
|
||
出刀(服务端裁决;教学狼 ≤2 挡自动放过契约保留)。
|
||
|
||
**手势语义**(附录 C §3/§4 全表落地,文件头有矩阵注释):
|
||
四向滑恒出击(90° 弧;WAVE 内下滑=出击南弧不弹菜单);单击=呼喊(5s 节流,节流内
|
||
invalid + `call_cd` 一次解释);长按=我在哪(hp 档 + 波次档 + `lp_act` ≤20 字;重复
|
||
问更短,全说过则「再说一遍:」+ lp_act);菜单仅 TITLE/LOBBY/波间休整/END(左右滑
|
||
换项、单击确认、长按重听、下滑关闭、回大厅二次确认 `sys_home_check`——原则 6);
|
||
结算尾句 end_again critical(800ms 死窗由 critical 承担:ghost tap 得 busy/跳句,
|
||
不重开)。
|
||
|
||
**断点复述**(§4.12,联机豁免口径):联机局不按单机节点存档——①断线 30s 内 resume
|
||
回槽播 `net_back`「你回来了。朝叫声滑。」;②一局内被迫退出(房灭/断线超时→LOST、
|
||
菜单回大厅、对局中 stop)→ `progress.unfinished` 标记,下次进 TITLE 播 `sys_recap`
|
||
一句复述,summary 保留(`_markUnfinished` 在改 phase 前判定)。
|
||
|
||
**手势阶梯上报**:第一次击杀 `ladder.onGoal()`(阶段 1;**不播 sys_unlock_up**——
|
||
hunt 上滑=出击北弧,「我在哪」教学由 T3 tut_help_full 承担);一局 END
|
||
`ladder.onGameDone()`(第 1 局 sys_unlock_down / 第 3 局 sys_unlock_dt 追加在结算
|
||
尾句后)。
|
||
|
||
**协议/拥挤/渲染全保留**:join/act/leave + joined/ev/snap/err、服务端权威怪表
|
||
对账、三源声像(loop pan + 后半平面低通、生成呼啸、bot 喊话防区 pan)、R2 bot
|
||
喊话调度、R4 one-shot 账目、断线 30s 回槽、评级双轴、进度 PUT——playtest Block
|
||
0/6/7 与 23 号 §10 验收口径逐条复测通过。
|
||
|
||
## 2. 偏差记录(对照 23-hunt.md 附录 C)
|
||
|
||
| # | 偏差 | 理由 |
|
||
|---|---|---|
|
||
| 1 | critical 落在 T0 `sys_first_tap` 与 T1 `tut_hit_full` 等教学指令句,而非附录 C §8 单指的开场「朝叫声,滑。」 | §8 原意「开场关键句 <3s 不可打断」;T0/T1 指令句均 <3s,critical 期间点按/滑动给 busy 回执(不打断指令),狼逼近期 ≤1.8s,代价可忽略;换来教学链不被警报/乱点打碎的确定性 |
|
||
| 2 | 结算链头(end_win→grade→kill_band→end_rank)可跳句可打断;只尾句 end_again critical | §4.6「critical 必 <3s」;800ms 手势死窗由尾句 critical 承担(ghost tap 跳句/回执,不重开) |
|
||
| 3 | 冷却内连滑「其后静默」→ 每下都给 invalid 回执(软「咚」),震动仍仅每窗首拦 | 「呼喊节流拒绝/挥空必须出声,禁止静默」红线 + §6.2 无声操作=0;v2 S2 要消灭的是连环 error 震,回执是 120ms 轻音不构成噪声 |
|
||
| 4 | 「乱滑计入迷茫但不放技能」保真;阶段 3 双击在非 WAVE = 重听当前等待点(lobby/end),WAVE = 重听威胁档 | §4.3 阶段 3「双击=重听」通用语义与附录 C §3「重听威胁档」战斗语义并存,按语境分发 |
|
||
| 5 | 死窗/吞手势一律给回执(busy/invalid),不物理静默 | 同偏差 3 红线 |
|
||
| 6 | 状态链旧 4 段(hp/波次/人数/击杀)压缩为长按 3 段(hp+波次+动作);人数移 LOBBY 长按、击杀档留结算 | 附录 C §3 阶段 1 原文「耐久档。波次。一个动作」≤20 字;人数/击杀不属「我在哪」 |
|
||
| 7 | 危险状态身份 = danger_low 语音 + danger 震(不再有 guide danger 签名 earcon) | Guide 层整体退役(floor/receipts/hints/confusion 接管);每局一次的语音句自带状态身份,避免新增资产 |
|
||
| 8 | WAVE 期一次击杀奖励句不播(kill_wolf 音效 + pickup 震即反馈);教学首杀播 tut_kill_ok | 原则 11 肯定 ≤4 字只用于教学;对局击杀高频,内容音即回报(R5 非语音信息 <1s) |
|
||
| 9 | 「冷却中双击=重听威胁」在阶段 4 之前不存在:阶段 3 双击恒重听(含就绪态),不放技能 | 附录 C §3:阶段 3「仍不放技能」;阶段 4 才有就绪/冷却分叉 |
|
||
| 10 | 菜单开着时 waveclear 只延长休整窗、不播 wave_clear | E3 菜单链不可被波间播报顶掉;wave_clear 下一波照常播 |
|
||
| 11 | `sys_turn_teach` 不使用 | 交接提示音(floor 风铃)+ 等待声已承担「轮到你了」教学;不额外占一句 |
|
||
|
||
## 3. 台词类别映射(§4.6;全表见 23-hunt-voice-ids.md 与 tools/voice_lines_26/hunt.md)
|
||
|
||
- `critical`:sys_first_tap(T0 首句)、tut_hit_full / tut_call_full / tut_help_full
|
||
(教学指令,均 <3s)、tut_kill_ok 后的步进链、tut_done、结算尾句 end_again
|
||
- `content`:intro_1/2、room_wait、room_start、wave_band1-5、wave_clear、end_win/
|
||
end_lose/grade_*/end_rank、net_*(回槽/断线复述)、sys_recap、skill_teach、
|
||
sys_unlock_down/dt、sys_home_check、sys_menu
|
||
- `hint`:tut_*_short、room_wait_short、sys_menu_short、end_again_short、lp_act/
|
||
lp_title、threat_*(重听威胁档)、st_wave_*/team_*(长按查询段)、wave_only、
|
||
gd_idle、skill_ready
|
||
- `feedback`:atk_cd、call_cd、inv_swipe、inv_rest、miss_side、gd_invalid
|
||
- 停用/删除:tut_rule、tut_attack、tut_callout、tut_skill、tut_skill_cd、
|
||
tut_status、tut_breach、tut_skip、settings_hint(详见台词清单 §3)
|
||
|
||
## 4. 测试记录
|
||
|
||
- 无头 playtest:`tools/node/bin/node web/hunt/test/playtest.mjs` —— **255 断言全绿
|
||
(退出码 0)**,覆盖:引擎 opts.pan 回归(Block 0)、教学波 §4.10(首句动手 +
|
||
首杀 ≤10s + critical 不打断 + 零规则总述)、WAVE 战斗全表(裁剪/冷却/节流/呼喊/
|
||
突入/危险/长按状态/休整窗/wave 等待点 earcon 纪律)、双击分档(阶段 3 重听威胁、
|
||
阶段 4 旋风斩 + skill_teach)、菜单 E3 + 二次确认、结算 + ladder.onGameDone 解锁
|
||
教学 + PUT summary 双轴、断线 resume/net_back/房灭/sys_recap 断点复述、snap 收敛、
|
||
R2/R4 拥挤、设置边界、座 3 哨音、资产缺失 Floor 看门狗兜底、静态 id 审计。
|
||
- **§6.2 乱点机器人**(Block 10,157 手势跑完 lobby→两波→终局→再来一局):
|
||
无声操作 **0**、被动原句重复 **0**、打断失败 **0**(口径注记:①防连点 400ms 内
|
||
吸收的快速重点(busy 回执)算一次逻辑交互,豁免;②警报类按事件计重复——每次
|
||
突入是新信息,机器人编排按真实节奏注入)。
|
||
- 节奏检查(§4.10):教学 T0 第一句即动手(critical ≤1.8s);首杀路径实测 9.6s ≤
|
||
10s;每 30s 有可听进展(呼啸/loop 档变化/波次播报/结算)。
|
||
- 真人冷启动:待测(§6.3,3-5 人)。
|
||
|
||
## 5. 已知限制 / 引擎缺口
|
||
|
||
- 引擎 `InvalidHints.explainOnce` 的 onDone 只恢复等待点:ACTION 语境(无等待点)
|
||
的解释句若被打断,floor 会漏在 BUSY。本作以**实例级包装 `floor.handleInput`**
|
||
自愈(TITLE/WAVE 无合法长驻 BUSY,输入前回 ACTION),未改引擎;若后续游戏同样
|
||
需要,建议把「反馈句播完回调用语境」收进 InvalidHints(引擎侧小改)。
|
||
- `Floor.speak` 的 id 必须带 `voice/` 层前缀(裸 id 被引擎静默丢弃,靠 Floor 看门狗
|
||
3s 后推进,表现为丢句)——本作在 `_enterEnd` 踩过一次(tail 尾句),已修;静态
|
||
审计不覆盖此类问题,值得加一条「speak 前缀 lint」进 harness。
|
||
- 联机局断点复述是「一句话 + 重进匹配」口径(23 号 §9 原文),不回填对局中段;
|
||
单机式存档恢复与联机豁免冲突,维持不改。
|