round3: G1 gd_answer提前一小节(根因=排程压窗起点) + G2教学降难DDA + G3 count-in修复(根因=未重排调度队列) + G4 escape目标链 + G5 simon双击根治(重听改上滑,重录3句) + G6轮成功/破纪录 + G7 space方向呼喊 + 22语音文件 + guide93断言全绿

This commit is contained in:
SoundGame Dev
2026-08-31 01:40:51 +08:00
parent ec89629eb4
commit 9f8096377e
537 changed files with 1046 additions and 432 deletions
+20 -8
View File
@@ -375,6 +375,13 @@ async function answerPastDoubletaps() {
}
}
/** 把前缀里连续的 up 答掉,直到期望输入非 up(round3 G5:期望恰为 up 时上滑=作答)。 */
async function answerPastUps() {
while (game.phase === 'input' && game.sequence[game.inputIdx] === 'up') {
await gesture('up'); // 期望即 up → 答题
}
}
// ---------------------------------------------------------------- 第 1-3 轮
section('第 1-3 轮(含单击跳播报、playback 忽略、看门狗)');
assert(game._interval() === 700, '第 1 轮播放间隔 700ms');
@@ -398,7 +405,8 @@ assert(game.chances === 1, '初始 1 次重听机会');
{
const prevSeq = game.sequence;
const exp = game.sequence[0];
const wrong = GESTURES.find((g) => g !== exp && g !== 'doubletap');
// round3 G5:up=重听键,注入错手势时避开(否则触发重听而非判错)
const wrong = GESTURES.find((g) => g !== exp && g !== 'doubletap' && g !== 'up');
await gesture(wrong);
assert(game.chances === 0, '答错自动消耗复活:chances 1→0');
assert(game.phase === 'roundend' && played('voice/retry_use'), '播 retry_use');
@@ -415,26 +423,29 @@ assert(game.chances === 1, '每完成 4 轮 chances +1(回到 1)');
assert(played('voice/chance_plus'), '播 chance_plus');
// ---------------------------------------------------------------- 第 5 轮:主动重听 + 边界
section('第 5 轮:主动重听 / chances=0 双击 / 双击冲突裁定');
section('第 5 轮:主动重听(上滑)/ chances=0 上滑 / 双击=作答(round3 G5,13 号文档 §8 变更记录)');
await toInputViaSkip(5);
{
// round3 G5:input 阶段双击永远=作答,主动重听改绑上滑(期望恰为 up 时上滑=作答)
await answerPastDoubletaps();
await answerPastUps(); // 先把期望恰为 up 的音答掉
const relistenCount = playCount('voice/relisten');
await gesture('doubletap'); // 期望非 doubletap → 主动重听
await gesture('up'); // 期望非 up → 主动重听
assert(game.chances === 0, '主动重听耗机会:chances 1→0');
assert(playCount('voice/relisten') === relistenCount + 1 && game.phase === 'roundend', '播 relisten 并重播');
await advanceUntil(() => game.phase === 'input', { desc: '重听重播后回输入' });
assert(game.inputIdx === 0, '重听后输入进度清零');
}
{
// chances=0 时双击非期望手势:不判错、播 chances_out
// chances=0 时上滑非期望手势:不判错、播 chances_out
await answerPastDoubletaps();
await answerPastUps();
const round = game.round;
const idx = game.inputIdx;
const coCount = playCount('voice/chances_out');
await gesture('doubletap');
assert(game.phase === 'input' && game.round === round && game.inputIdx === idx, 'chances=0 双击非期望:不判错(round/inputIdx 不变)');
assert(playCount('voice/chances_out') === coCount + 1, 'chances=0 双击播 chances_out');
await gesture('up');
assert(game.phase === 'input' && game.round === round && game.inputIdx === idx, 'chances=0 上滑非期望:不判错(round/inputIdx 不变)');
assert(playCount('voice/chances_out') === coCount + 1, 'chances=0 上滑播 chances_out');
assert(game.chances === 0, 'chances 不变(不为负)');
}
// 答完第 5 轮(途中验证双击=答题);若本轮没遇到 doubletap 则继续往下轮找
@@ -459,7 +470,8 @@ assert(game.chances === 0, '复活已耗尽');
const finalRound = game.round;
{
const exp = game.sequence[game.inputIdx];
const wrong = GESTURES.find((g) => g !== exp && g !== 'doubletap');
// round3 G5:up=重听键,注入错手势时避开
const wrong = GESTURES.find((g) => g !== exp && g !== 'doubletap' && g !== 'up');
await gesture(wrong);
}
assert(game.phase === 'gameover', 'chances=0 答错 → gameover');