/** * 《剑与声》新手会话剧本(26 号重构版):critical 开场指令「点一下屏幕」→ * 序章 → 进村把选项听一圈 → 出村去小路(顺路调查一次捡钱)→ 岔路口转去溪流 * 触发教学战 → 完整打一场(四步:识招→攻击→格挡[窗口内单击]→防御,再自由 * 击杀),战后收工。26 号口径:格挡 = 前摇窗口内**再单击**(旧「双击格挡」废止); * 新手期无双击重听(上滑=状态、菜单=通关第二章解锁,此处均不使用)。 * * 种子 RNG:让教学狼首击必不掉(HP 6、伤害恒 5),保证四步教学完整走完。 */ Math.random = () => 0.4; export function describe(game) { const SCENE_NAME = { village: '雾口村', path: '林间小路', fork: '岔路口', chest: '枯树洞', stream: '溪流', hunter: '猎人小屋', deepwood: '密林深处', gate: '黑风寨门前', boss1: '聚义厅', }; const BAND = { high: '八成以上', mid: '五成上下', low: '三成以下' }; if (game.phase === 'battle' && game._battle) { const b = game._battle; if (b.state === 'PLAYER_SELECT' && b.enemy) { return `战斗中:你的血量${BAND[game._hpBand(game.player.hp, game.maxHp)]},` + `敌方血量${BAND[game._hpBand(b.enemy.hp, b.enemy.maxHp)]},等你选招式(左右滑切换,单击出手,下滑逃跑)`; } if (b.state === 'ENEMY_TELEGRAPH') return '战斗中:敌方前摇声响起了——点一下,格挡!'; return '战斗播报中,先听着'; } switch (game.phase) { case 'ask': return '检测到旅程记录:单击继续,右滑开新档'; case 'intro': return game._introTapped ? '序章旁白在播(单击可跳句)' : '开场指令在播:等风铃响起点一下'; case 'explore': return `【${SCENE_NAME[game.scene] ?? game.scene}】:左右滑切选项,单击确认,上滑查状态`; case 'shop': return '商店里:左右滑看货,单击买,下滑离开'; case 'menu': return '菜单里:左右滑切选项,单击确认,下滑关闭'; default: return '……'; } } export async function session(ctx, mock) { const { game } = ctx; // 开场:critical 指令「点一下屏幕。」播完(风铃 + 等待声)→ 第一下单击 await ctx.waitCond(() => game.floor.state === 'YOUR_TURN'); ctx.status('开场指令听完了,点一下'); ctx.note('第一句就让我动手,还给了「轮到你了」的一声风铃'); await ctx.gesture('tap'); // 序章听完 → 进村 await ctx.waitCond(() => game.phase === 'explore'); ctx.status('进村了,先听场景描述和选项'); // 村里(选项:去小路/商店/休息/听状态):把选项听一圈,回绕到首项再出发。 // 确认(tap)前等选项名念完——报名在播时单击是「跳过这句」,会慢半拍 for (let i = 0; i < 3; i++) { await ctx.gesture('right'); await ctx.waitVirtual(1800); // 听选项名 } ctx.status('选项听了一圈'); await ctx.gesture('right'); // 从末项回绕到首个选项——「回到第一个」 ctx.note('滑到头再滑就兜回来了,有人提醒「回到第一个」,不用自己数'); await ctx.waitCond(() => !ctx.voiceBusy()); await ctx.gesture('tap'); // → path // 小路(去岔路口/调查/返回):先调查一次捡钱,再左滑回「去岔路口」 await ctx.waitCond(() => game.phase === 'explore' && game.scene === 'path'); ctx.status('林间小路'); await ctx.gesture('right'); // 调查四周 await ctx.waitVirtual(1800); ctx.note('翻找了一阵,捡到一点钱'); await ctx.waitCond(() => !ctx.voiceBusy()); await ctx.gesture('left'); // 回「去岔路口」 await ctx.waitCond(() => !ctx.voiceBusy()); await ctx.gesture('tap'); // → fork // 岔路口(去枯树洞/去溪流/返回):右滑一次到「去溪流」 await ctx.waitCond(() => game.phase === 'explore' && game.scene === 'fork'); ctx.status('岔路口,水声在东边'); await ctx.gesture('right'); await ctx.waitCond(() => !ctx.voiceBusy()); await ctx.gesture('tap'); // go_stream → 溪流 → 触发教学战 // 教学战:四步(识招 → 攻击 → 格挡[窗口内单击] → 防御)+ 自由击杀 await ctx.waitCond(() => game.phase === 'battle' && game._battle?.state === 'PLAYER_SELECT'); ctx.status('遭遇教学狼,战斗开始'); const CMDS = ['attack', 'skill', 'defend', 'item']; const selectCmd = async (cmd) => { const b = game._battle; while (b && b.cmdIdx !== CMDS.indexOf(cmd)) { await ctx.gesture('right'); await ctx.waitVirtual(1300); // 听指令名 } }; // T0:左右滑各切一次(听到指令名就算过关) await ctx.gesture('right'); await ctx.waitVirtual(1300); await ctx.gesture('right'); await ctx.waitVirtual(1300); ctx.status('招式名听熟了'); // T1:选攻击,单击出剑 await ctx.waitCond(() => game._battle?.state === 'PLAYER_SELECT'); await selectCmd('attack'); ctx.note('单击出手,攻击'); await ctx.gesture('tap'); // T2:格挡(前摇窗口内再单击)——先听「它要扑了,听前摇」「就是现在,点一下挡住」 await ctx.waitCond(() => game._battle?.state === 'ENEMY_TELEGRAPH'); ctx.status('前摇声响起了'); ctx.note('前摇一响就点一下——这回干净挡下了,听到「挡得漂亮」'); await ctx.gesture('tap'); // T3:防御一次 await ctx.waitCond(() => game._battle?.state === 'PLAYER_SELECT'); await selectCmd('defend'); ctx.note('这回合先防御,减半伤害'); await ctx.gesture('tap'); // 自由阶段:攻击到狼死(中间照常听前摇、单击格挡) for (let i = 0; i < 8 && game.phase === 'battle'; i++) { await ctx.waitCond(() => game._battle?.state === 'PLAYER_SELECT' || game._battle?.state === 'ENEMY_TELEGRAPH' || game.phase !== 'battle'); if (game.phase !== 'battle') break; if (game._battle.state === 'ENEMY_TELEGRAPH') { ctx.note('前摇响了,单击格挡'); await ctx.gesture('tap'); continue; } await selectCmd('attack'); ctx.note('单击,攻击'); await ctx.gesture('tap'); } await ctx.waitCond(() => game.phase === 'explore'); ctx.status('狼打完了,胜利播报(链尾还教了一句「想知道自己在哪,就向上滑」)完回到溪流边。一场完整战斗到此收工'); }