策划轮:25-escape-map-flow.md as-built地图/玩家流程/信息账本+盲区清单(S1-S7)+方案B1-B8 实施(玩法零改动,只加状态引导层): - F1 撞墙方位句「左边是墙」(wall_dir_*×4,同向10s限频) - F2 目标句并入方位「铁柜,在右面的房间」(gd_*_dir×3) - F3 无进展150s活跃计时器+gd_prog_1..3进度重述(只重述不泄题,专治活跃迷路玩家——修卡关计时从「无进展」退化为「无操作」的既定偏差) - F4 双击兜底直通L2降级L1(不再白送答案) - F5 空房首访描述(4空房可区分) - F7 busy窗口手势缓存补判(原静默吞手势) - F8 结算链单击守卫(time_band/again完整到达) - F9 跳过引导补播目标句 - F6 空房方位特征句按25号裁定留档后续轮 新增语音10句×2性别(flock串行QC无离群,ASR逐字正确) 验证:escape playtest 235/235(+85新断言)+ guide 132/132 + 终检全绿 + 14游戏回归零回退 live复跑10.4分钟通关:零截断,S1-S7盲区逐条核销 档案 research/escape-state/round1-2;01号文档追加修订记录R1
97 lines
5.8 KiB
JavaScript
97 lines
5.8 KiB
JavaScript
/**
|
||
* 《暗室》新手会话剧本:老玩家二周目不算——这里清空过进度走首局引导(G0-G7),
|
||
* 每步听清再做;进 PLAY 后先连撞两次墙(round2 B1:wall 后跟陈述式方位句
|
||
* 「上边是墙。」,同向 10s 限频),经空房首访描述(B5a)找到铁柜房开柜拿保险丝、
|
||
* 照 round2 B2 的"目标名+方位"一体句跨四个房间修电箱、再摸到大门收工。
|
||
*/
|
||
export function describe(game) {
|
||
switch (game.phase) {
|
||
case 'REOPEN': return '有人问我回不回来看过引导:单击直接开始,上滑重听引导';
|
||
case 'GUIDE': return game._guideBusy ? '引导在说话,照它说的做就行' : `引导第 ${game.guideStep + 1}/8 步,等我做手势`;
|
||
case 'PLAY': return `探索中,我在 (${game.x},${game.y})。四向滑挪步,单击摸一遍房间,双击用物品`;
|
||
case 'ENDING': return '逃脱了,结算播报中。播完单击再来,下滑开菜单';
|
||
case 'MENU': return '菜单里:单击切选项,双击确认,下滑关闭';
|
||
default: return '……';
|
||
}
|
||
}
|
||
|
||
export async function session(ctx, mock) {
|
||
const { game } = ctx;
|
||
|
||
// 首局:交互式引导 G0-G7(n = 引导步号 guideStep)。
|
||
// 注意:卡关轮询 interval 常驻,虚拟时钟永不"空闲"——等待一律用有界/带条件等待。
|
||
ctx.status('黑屏,只有引子的声音,先听完');
|
||
await ctx.waitCond(() => game.phase === 'GUIDE' && !game._guideBusy); // g0_intro 播完
|
||
const steps = [
|
||
{ n: 0, do: async () => { ctx.note('照引导单击了一下'); await ctx.gesture('tap'); } },
|
||
{ n: 1, do: async () => { ctx.note('随便滑了一步,有脚步声'); await ctx.gesture('up'); } },
|
||
{
|
||
n: 2,
|
||
do: async () => {
|
||
await ctx.gesture('left');
|
||
await ctx.waitVirtual(1600);
|
||
ctx.note('又滑一步,又撞墙了——墙的方位听出来了');
|
||
await ctx.gesture('right');
|
||
},
|
||
},
|
||
{ n: 3, do: async () => { ctx.note('这回往左,走通了一步'); await ctx.gesture('left'); } },
|
||
{ n: 4, do: async () => { ctx.note('往下滑,进了储物间'); await ctx.gesture('down'); } },
|
||
{ n: 5, do: async () => { ctx.note('单击摸一遍房间,摸到钥匙了'); await ctx.gesture('tap'); } },
|
||
{ n: 6, do: async () => { ctx.note('双击看了看背包'); await ctx.gesture('doubletap'); } },
|
||
];
|
||
for (const s of steps) {
|
||
await ctx.waitCond(() => game.phase === 'GUIDE' && game.guideStep === s.n && !game._guideBusy);
|
||
ctx.status(`引导第 ${s.n + 1}/8 步`);
|
||
await s.do();
|
||
await ctx.waitVirtual(800); // 缓一缓再继续(推进链由语音 onComplete 驱动)
|
||
}
|
||
|
||
// PLAY:自由探索。引导结束时我站在储物间 (0,2),手里已有钥匙
|
||
await ctx.waitCond(() => game.phase === 'PLAY');
|
||
ctx.status('引导完毕,正式开始。我在储物间');
|
||
const move = async (g, why) => {
|
||
await ctx.gesture(g);
|
||
await ctx.waitVirtual(1600); // 听脚步/环境音/描述
|
||
if (why) ctx.note(why);
|
||
};
|
||
|
||
// 先往北乱撞探探边界:两步走到 (0,0)——(0,1) 首访会播 empty_2(B5a 空房听觉锚),
|
||
// 再连撞两次北墙——wall 后各跟一句陈述式方位「上边是墙。」(B1,同向 10s 限频)
|
||
ctx.silence(3, '辨了辨方向');
|
||
await move('up', '路过一间空房,它自己开口了:摸到的只有冰冷粗糙的墙壁');
|
||
await move('up', '电流声——电箱房到了');
|
||
await move('up', '北边是墙,撞了一下——「那边是墙」后面跟了句「上边是墙。」,这面不通记住了');
|
||
await move('up', '又撞了一下——同方向 10 秒内不重复报方位,游戏不啰嗦');
|
||
await ctx.waitVirtual(5200); // 缓一缓(卡关轮询 5s tick 空转,活跃操作不触发提示)
|
||
|
||
// 去铁柜房:(0,0) → 右×2 = (2,0) → 下 = (2,1),双击用钥匙
|
||
// ((1,0)/(2,0) 首访各播 empty_1/empty_3——B5a:四间空房从此声学可区分)
|
||
await move('right', '往东走,一间空房自报家门:空空荡荡只有回声');
|
||
await move('right', '又一间空房:除了远处的水滴声什么都没有');
|
||
await move('down', '到了铁柜房,柜子锁着');
|
||
// 用钥匙 → unlock_cabinet + gd_next_fuse + gd_box_dir(round2 B2:目标名+方位
|
||
// 一体句,从铁柜房 (2,1) 看电箱房 (0,0) 在西 = 「电箱,在左面的房间。」)
|
||
await ctx.gesture('doubletap');
|
||
await ctx.waitVirtual(5600);
|
||
ctx.status('柜子开了。「保险丝到手。接下来,去找电箱。」后面跟的是「电箱,在左面的房间。」——目标名和方位一句话说全了');
|
||
// round4 H1 剧本:照方位句跨房间去电箱房——(2,1) → 左×2 = (0,1) → 上 = (0,0)
|
||
await move('left', '照方位句往左(西)摸');
|
||
await move('left');
|
||
await move('up', '电流声越来越清晰——电箱房到了');
|
||
// 修电箱 → fix_box + gd_gate_dir(round2 B2:从 (0,0) 看大门 (2,2) 在东 =
|
||
// 「大门,在右面的房间。」)
|
||
await ctx.gesture('doubletap');
|
||
await ctx.waitVirtual(5600);
|
||
ctx.status('电箱修好了。目标句后面照样是目标名+方位——「大门,在右面的房间。」');
|
||
// 照方位句多跨两个房间摸向大门:(0,0) → 右×2 = (2,0) → 下×2 = (2,2)
|
||
await move('right', '照方位句往右(东)摸');
|
||
await move('right');
|
||
await move('down');
|
||
await move('down', '脚步声停下来——面前这间就是大门');
|
||
// 完整弧线收尾:在大门双击用钥匙开门 → ENDING 结算链(逃脱播报+结算 BGM)
|
||
// (round4 终版修订:此前剧本在大门"收工",两位终评人设把"没演完"读成了"游戏哑结尾")
|
||
await ctx.gesture('doubletap');
|
||
await ctx.waitVirtual(6000);
|
||
ctx.status('钥匙插进锁孔,门开了——结算播报来了,这局是完整的赢');
|
||
}
|