Files
SoundGame/web/harness/sessions/storyline.mjs
T

105 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 《声命线》新手会话剧本:像真人一样等语音播完再动、偶尔走神(触发看门狗,
* 听到轻响后 5 秒内回应——round2 修正剧本失真:round1 的「干晾 85 秒」是剧本
* 问题不是游戏问题)、在非抉择节点试一次无效的左滑(触发向导纠错)、中途演示
* 一次语速 2.2 切换(F9:设置下一句即时生效,转写状态行可见语速档)、菜单逛
* 一圈再出来、抉择点一律选左,一路打到结局。
*/
export function describe(game) {
if (game.mode === 'MENU') return '菜单里:左滑重开、右滑或单击返回剧情、上滑听帮助';
if (game.awaitingRestart) return '结局播完了。单击屏幕,可以回到故事开始的地方';
if (game.choiceArmed) return `「请选择」念完了(节点 ${game.nodeId}):左滑或右滑,做出你的决定`;
if (game.voicePlaying) return '旁白正在播。单击跳过本句,双击重听整个节点';
return `剧情等着你(节点 ${game.nodeId}):单击继续,双击重听`;
}
export async function session(ctx, mock) {
const { game } = ctx;
let invalidTried = false;
let menuDone = false;
let speedDemoDone = false;
let speedBackDone = false;
// 开场:gd_brief 先给操作口令(round2 F8),n00 全听完,再愣一会儿——看门狗 25s 才说话
await ctx.waitCond(() => !game.voicePlaying); // 只等链播完(不空烧看门狗窗口)
ctx.status('开场口令和旁白播完了,屏幕黑着,走神想剧情去了');
ctx.silence(25, '在入戏,不是迷路(round2:剧情类等待默认低频)');
await ctx.waitVirtual(25600); // 触发看门狗:nudge + gd_continue
ctx.status('听到一声轻响和「轻触屏幕,继续」,马上点一下');
await ctx.gesture('tap'); // 听到提示 ≤5s 内反应
for (let i = 0; i < 60 && !game.awaitingRestart && mock.now < 20 * 60 * 1000; i++) {
// 只等语音链播完(真人不会抢话)。不能裸 waitIdle——会把等待态看门狗的两级
// 提醒整段空烧完才动手(round1 剧本失真根源),链一停就该轮到玩家了
await ctx.waitCond(() => !game.voicePlaying);
if (game.awaitingRestart) break;
// 中途进一次菜单,逛一圈再出来
if (!menuDone && game.nodeId === 'n04') {
menuDone = true;
ctx.note('想看看还有什么可按的,下滑呼出菜单');
await ctx.gesture('down');
await ctx.waitIdle();
ctx.status('菜单里');
await ctx.gesture('up'); // 听帮助 + 进度
await ctx.waitIdle();
await ctx.gesture('doubletap'); // 重听菜单项
await ctx.waitIdle();
ctx.note('听懂了,先回去继续剧情');
await ctx.gesture('tap'); // 关菜单(回剧情并重播当前节点)
continue;
}
// F9:演示一次语速切换——2.2 档对下一句即时生效,听两段再调回 1.0
if (!speedDemoDone && game.nodeId === 'n10') {
speedDemoDone = true;
ctx.note('旁白有点慢,去设置把语速调到 2.2(下一句生效)');
ctx.settings.set({ speed: 2.2 });
if (game.choiceArmed) {
ctx.note('选了左边(循声而去)——后面几步都是 2.2 档');
await ctx.gesture('left'); // n10 抉择 → n11,2.2 倍速播
} else {
await ctx.gesture('tap');
}
await ctx.waitIdle();
ctx.status('语速 2.2 听着赶趟');
continue;
}
if (speedDemoDone && !speedBackDone && game.nodeId === 'n12') {
speedBackDone = true;
ctx.note('听了两段,把语速调回 1.0');
ctx.settings.set({ speed: 1.0 });
}
if (game.choiceArmed) {
ctx.status('抉择点,提示音念完了');
if (mock.now % 2 < 1) await ctx.waitVirtual(3000); // 偶尔犹豫一下
ctx.note('选了左边');
await ctx.gesture('left'); // 抉择点一律选左
continue;
}
// W1:叙事节点播完,静默等待
ctx.status('剧情停下来了,在等我');
if (!invalidTried) {
invalidTried = true;
ctx.note('试着左滑了一下——这里用不上,向导纠正了我');
await ctx.gesture('left');
await ctx.waitVirtual(2000); // 让纠错句播完(不空烧看门狗窗口)
} else if (i % 4 === 2) {
ctx.silence(25, '又走神想剧情去了');
await ctx.waitVirtual(25600); // 偶尔挂机,触发看门狗轻提醒(25s 才响,不轰炸)
ctx.status('又听到那声轻响,5 秒内想起该点屏幕了');
}
await ctx.gesture('tap');
}
await ctx.waitCond(() => !game.voicePlaying);
ctx.status('结局');
ctx.note('听完结局,单击重开一次看看别的走向');
await ctx.gesture('tap'); // 结算态单击重开
await ctx.waitCond(() => !game.voicePlaying);
ctx.status('回到开头,会话结束');
}