feat(new8): 批次1收口——radio/dungeon 双双标记可交付(R3 synthesis×2 + H1 热修 + 定向live复验PASS)

- radio:R3 放行(4/4 人设满分档 5/5、愿意玩、P0=0;live 四修坐实+SA3 真声入局)
- dungeon:R1 0/4→R3 4/4 翻案达成;H1 死亡结算链截断根修(真凶=双击窗幽灵 tap 死后回调路由进 SETTLE,800ms 手势死窗;7 断言含旧代码反证)+ 定向 live 复验 PASS(两局含 R3 同款幽灵场景,结算链 7 句逐句完整)
- 章程账本更新:批次 1 验收 ☑(R4-R6 经用户裁定暂停,视上手反馈续;v2 首条=漫游迷路抢救盲区)
- 断言账面:radio 246 / dungeon 1649 / 9 套件全绿
This commit is contained in:
xsl
2026-09-03 03:01:45 +08:00
parent f7509ad5d8
commit 45124a1b9b
11 changed files with 464 additions and 3 deletions
+17 -1
View File
@@ -17,7 +17,9 @@
* 死亡归因真话律:die_cause_* / die_adv_* 按 lastHit(击杀者/背刺/未格挡)与
* run.parries 真实选择;卡关双轨(R3 E0-1):无操作轨 60/120/180s(§10.3,手势重置)
* + 无进展轨 30/60/90s(只由楼层/格位置/战斗回合/拾取重置:earcon→短句→导航接管,
* 乱按不再饿死;教学态接管=滚出教学);踩上楼梯格到达即报贴身铁器回声(R3 E1-1)。
* 乱按不再饿死;教学态接管=滚出教学);踩上楼梯格到达即报贴身铁器回声(R3 E1-1);
* 结算入口 800ms 手势死窗(H1:死亡瞬间在途的 tap 按新状态路由会把结算链掐死在
* 半句——_enterTitle/stopVoice 截杀 die_intro,R3 live A 局 2787.057 实锤)。
*
* 豁免 E1-E4:单击=脉冲、长按=前进/左右滑=转身(E2)、对局期
* setRateBoostEnabled(false)(E3,EXPLORE/BATTLE/DRILL/DESCEND,TITLE/MENU/SETTLE
@@ -50,6 +52,13 @@ const AMB_AFTER_MS = 20000; // 探索呼吸层(R2 D0-3②):静默超 2
const AMB_VOLUME = 0.35;
const FLEE_HOLD_MS = 900; // 战斗逃跑长按最短时长(R3 打磨:探索走步 450ms 不变)
const LONGPRESS_MS = 450; // 引擎 longpress 判定阈值(gesture.js cfg,只读参照)
// H1:进入结算后的手势死窗。gesture.js 非即时模式单击要等双击窗(300ms)关闭才回调——
// 致命一击落地瞬间仍在途的 tap 会在死后 ~300ms 才派发,按「当时」状态路由进 SETTLE:
// tap=离开结算 → _enterTitle 的 stopVoice() 把 die_intro 掐死在半句、整条结算链作废
// (R3 A 局 2787.057 实锤:die_intro vstart 2786.88 → vend kill 2787.057)。手势从按下
// 到回调最迟 touchstart+450ms(长按判定)+300ms(双击窗)≈ 750ms,800ms 死窗全盖住;
// 死窗后结算手势照常(tap 回标题 / 双击重听链 / 下滑菜单)。_settleWin 同栅。
const SETTLE_GRACE_MS = 800;
/** 回声编码(§3.1):正前距离 4 档 → 延迟 / 音量。 */
const ECHO_DELAY = [0, 250, 500, 800, 1100];
@@ -139,6 +148,7 @@ export class DungeonGame extends Game {
this._walk = null;
this._pulseAt = -1e9;
this._lastHit = null; // 归因真话律依据(击杀者/背刺/未格挡)
this._settleGraceUntil = 0; // H1:结算手势死窗截止时刻(performance.now() 时基)
this._lastEcho = null; // 最近一次脉冲回声(双击重发一致性断言用)
this._onStairs = false;
this._stairsSpokenFloor = 0;
@@ -570,6 +580,10 @@ export class DungeonGame extends Game {
this.guide.disarm(); // 任何手势复位向导看门狗(off 档 no-op)
if (g === 'longpressend') { this._stopWalk(); this._battleFleeCancel(); return; } // 仅停走/取消逃跑,不承载第二语义
if (this.menuOpen) { this._onMenuGesture(g); return; }
// H1:结算死窗。死亡/通关瞬间仍在途的手势(引擎双击窗 300ms 延迟派发)落进
// SETTLE 会被当成本态手势——tap=离开结算 → stopVoice 把结算链掐死在半句。
// 死窗内一律吞掉(ghost 手势不算玩家输入,_stuck 队列也不作废)。
if (this.state === 'SETTLE' && !this.menuOpen && performance.now() < this._settleGraceUntil) return;
this._stuck.pending.length = 0; // 玩家操作即作废未播的卡关提示(§10.3)
switch (this.state) {
case 'TITLE': this._onTitleGesture(g); break;
@@ -1252,6 +1266,7 @@ export class DungeonGame extends Game {
this._battle = null;
this._stopWalk();
this.state = 'SETTLE';
this._settleGraceUntil = performance.now() + SETTLE_GRACE_MS; // H1:吞掉在途手势(见常量注)
this._session++;
this._clearTimers();
this.audio.setRateBoostEnabled(true); // E3:结算恢复
@@ -1281,6 +1296,7 @@ export class DungeonGame extends Game {
this._battle = null;
this._stopWalk();
this.state = 'SETTLE';
this._settleGraceUntil = performance.now() + SETTLE_GRACE_MS; // H1:同 _die(在途 tap 会误离开结算)
this._session++;
this._clearTimers();
this.audio.setRateBoostEnabled(true);