round2: 看门狗礼仪F1(不重播/单句升级/idle-skip) + 分档归因F2 + 交接count-in/answer F3 + 教学看表现F4-F5 + 警报去叠F6 + 回绕F7 + 开场瘦身F8 + 10句新语音 + 测试全绿(6playtest零改动+guide52断言+资产终检)
This commit is contained in:
@@ -93,7 +93,11 @@ function capture(audio) {
|
||||
pending.push(`${fmtT()} ♫ BGM 切换 → ${id}${opts?.fadeMs ? `(淡入 ${opts.fadeMs}ms)` : ''}`);
|
||||
}
|
||||
} else if (isVoice && id.startsWith('voice/gd_')) {
|
||||
// 向导语音经事件钩子渲染(▶ 向导语音),此处不重复记行
|
||||
// 向导语音(round2):实际播出的在本行渲染(含全文);被 idle-skip 跳过的
|
||||
// 不产生 play 调用,由事件钩子单独标注(见 captureGuide)
|
||||
pending.push(t
|
||||
? `${fmtT()} ▶ 向导语音:「${t}」`
|
||||
: `${fmtT()} ▶ 向导语音 voice/${id.slice(6)}(无台词表文本)`);
|
||||
} else if (isVoice) {
|
||||
pending.push(t
|
||||
? `${fmtT()} ▶ 语音:「${t}」`
|
||||
@@ -105,15 +109,17 @@ function capture(audio) {
|
||||
};
|
||||
}
|
||||
|
||||
/** 向导实例接入事件流(每个 earcon/插播语音都转写成玩家可感知的一行)。 */
|
||||
/** 向导实例接入事件流(每个 earcon / 被 idle-skip 的语音都转写成玩家可感知的一行;
|
||||
* 实际播出的向导语音已由 audio.play 捕获渲染,此处不再重复记行)。 */
|
||||
function captureGuide(game) {
|
||||
if (!game.guide) return;
|
||||
game.guide.setEventHook((evt) => {
|
||||
if (evt.voiceId) {
|
||||
if (!evt.skipped) return; // 播出的由 capture() 渲染,避免重复
|
||||
const t = textOf(`voice/${evt.voiceId}`);
|
||||
pending.push(t
|
||||
? `${fmtT()} ▶ 向导语音:「${t}」`
|
||||
: `${fmtT()} ▶ 向导语音 ${evt.voiceId}(无台词表文本)`);
|
||||
? `${fmtT()} ▶ 向导语音(对白在播,本句按 idle-only 跳过未播):「${t}」`
|
||||
: `${fmtT()} ▶ 向导语音 ${evt.voiceId}(idle-only 跳过未播)`);
|
||||
} else {
|
||||
const label = GUIDE_LABEL[evt.name] || '';
|
||||
pending.push(`${fmtT()} ♪ 向导音:${evt.name}${label ? `(${label})` : ''}`);
|
||||
@@ -122,8 +128,11 @@ function captureGuide(game) {
|
||||
}
|
||||
|
||||
function drain() {
|
||||
// 震动/资产缺失按「实际触发时刻」落行(v2 起不再用 drain 时刻近似——
|
||||
// round2 审计指标要核 danger 震 ≥400ms 去抖、警报 600ms 去重,必须看真实时间)
|
||||
for (const m of mock.vibrateLog.splice(0)) {
|
||||
pending.push(`${fmtT()} 〰 震动:${hapticName(m.pattern)}`);
|
||||
const t = `t+${(m.t / 1000).toFixed(1).padStart(6)}s`;
|
||||
pending.push(`${t} 〰 震动:${hapticName(m.pattern)}`);
|
||||
}
|
||||
// 引擎按 ogg→m4a→mp3→wav、性别目录→平铺 逐个探测;只有全部路径都 404,
|
||||
// 玩家才是真的什么都没听到(角色音探测性别目录 404 后平铺成功属正常回退)
|
||||
@@ -131,7 +140,7 @@ function drain() {
|
||||
const key = m.url.replace(/^audio\//, '').replace(/\.\w+$/, '').replace(/^voice\/(male|female)\//, 'voice/');
|
||||
const everOk = mock.fetchedLog.some((f) => f.ok
|
||||
&& f.url.replace(/^audio\//, '').replace(/\.\w+$/, '').replace(/^voice\/(male|female)\//, 'voice/') === key);
|
||||
if (!everOk) pending.push(`${fmtT()} ⚠ 资产缺失 ${key} → 玩家此刻听到的是静默`);
|
||||
if (!everOk) pending.push(`t+${(m.t / 1000).toFixed(1).padStart(6)}s ⚠ 资产缺失 ${key} → 玩家此刻听到的是静默`);
|
||||
}
|
||||
pending.sort((a, b) => parseFloat(a.match(/t\+(\s*)(\d+)/)?.[2] ?? 0) - parseFloat(b.match(/t\+(\s*)(\d+)/)?.[2] ?? 0));
|
||||
lines.push(...pending);
|
||||
@@ -164,7 +173,8 @@ function makeCtx(audio, game, describe) {
|
||||
status: (tag) => {
|
||||
const d = describe ? describe(game) : '';
|
||||
const v = voiceBusy(audio) ? '语音播放中' : (audio._bgm ? `BGM=${audio._bgm?.id ?? '无'}` : '无 BGM');
|
||||
lines.push(`${fmtT()} 【状态】${tag || ''}${d ? ` ${d}` : ''}(${v})`);
|
||||
// 语速档随状态行输出(round2 F9:转写需可见语速切换生效)
|
||||
lines.push(`${fmtT()} 【状态】${tag || ''}${d ? ` ${d}` : ''}(${v},语速${settings.get().speed})`);
|
||||
},
|
||||
silence: (sec, why) => {
|
||||
lines.push(`${fmtT()} ……… 静默 ${sec}s${why ? `(${why})` : ',游戏在等待玩家输入'} ………`);
|
||||
|
||||
Reference in New Issue
Block a user