Files
SoundGame/docs/design/23-hunt.md
T
xsl d78df35b5c fix(hunt): v2 九修 S1-S9 落地——10 人并发模拟迭代裁定(同阵容复测:去留 6/10→10/10)
研究闭环:v1 三轮 28 局四死因(失衡/社交真空/交互摩擦/观光羞辱)→ 四视角分析 →
synthesis S1-S9 裁定 → 实施 → 同 10 人配置复测两轮 20 局。依据 research/hunt-sim/
(synthesis.md / metrics-v2.md / report.md),设计登记 23-hunt.md §16。

服务端 hunt-room.js:
- S5 协作人声包:真人座位角色接线(杀熊/三连杀/旋风斩≥3 播角色句、greet 全座位);
  满编真人房呼喊 2.5s 无 bot 应答 → 邻座角色代答 help_ack;喊话预算 10s 窗 2→3
- S7 难度重构:waveCounts 4 人房 ×4/3;alignPincers 第 3-5 波齐压拍(跨座位同种类
  同秒进内圈,种子确定性保持);mobYielded bot 对人类防区怪让位 2s(只约束 bot,
  不拦真人避免挥空真话说谎);gradeForEx 双轴评级(S=耐久≥9 且 ≥2 人各 6 杀,
  单人带飞局上限 A)

客户端 game.js:
- S1 WAVE 下滑恒出击(无怪=空挥真话),菜单收窄到波间休整窗(E3 修订)——
  v1 误触菜单单人单局最多 14 次清零
- S2 冷却首拦才震 + 就绪 beat 轻叮(v1 全场 666 次乱滑连震)
- S3 0 杀不播 kill_band0(「你还没开张」下架;复测 P08 0杀→12杀)
- S4 看门狗重定义:本波出过手一级语音不触发、语音闲置每局 ≤1、一级降纯震
- S5③ help_call/help_ack 永不超时丢弃
- S6 后半平面 loop 低通 750Hz 第二线索(N/S 判读 63/69%→75/81%)
- S8 教学作答步(T1-T3)下滑不再误跳
- S9 状态链按变化播(「固若金汤」复读归零)

测试同步:hunt-sim A1/A2/A12 断言更新(真人 greet/波次缩放/预算 3)、
playtest Block 3 按 S1 新语义改写(战斗中下滑=空挥 + 波间菜单)

回归:hunt-sim 16/16 + playtest 213 + guide 132 + engine-voice 19 全绿;
balance-scan:挂机局 5/8 落 C/失守带(v1 恒满血)、optimal 单人带飞封顶 A
遗留:营地零损耗未破(18/20 局余10)——v3 头号,参数方案 report.md §5
2026-09-19 11:06:18 +08:00

48 KiB
Raw Blame History

23 · 《围猎》完整设计(hunt / Night Hunt)

给开发者的实现要点摘要

  1. 2-4 人实时联机纯音频协作守卫,项目"纯音频 MMORPG"路线的第一阶段最小验证切片(§1.3)。本作只验证三件事:实时同步(零依赖 WebSocket + 服务端权威)、音频信道拥挤控制(§8,全文重点)、空间音频协作(方位=pan+防区分工)。其余一切从简。
  2. 圆形猎场,猎人位于营地中心。野兽从 8 罗盘方位边缘逼近(8-12s),四向滑=出击(滑向映射 90° 弧,击杀弧内内圈最近一只,冷却 2.5s/人);突入中心 = 共享营地耐久 -1(巨兽 -2,初始 10);单击=呼喊支援(队友收到你防区方位的空间化喊话 + warning 震,bot 补位);双击=旋风斩(清内圈全部,冷却 8s;冷却中双击=重听威胁播报,宪法双击语义由此保留)。上滑=状态链,下滑=菜单(不暂停,联机实时豁免 E3)。
  3. 服务端权威:怪物生成/移动/命中/冷却/评级全在 web/server/ 裁决,客户端只发意图(join/act/leave)。bot 由服务器驱动,与真人同一套事件协议。房间 3-4 座,开局空位由 bot 补至 ≥3 猎人;断线 30s 宽限重连回槽,超时转 bot。
  4. 协议全文 §6(两条传输消息 + 三类服务端消息,JSON 字段表逐条给出);零依赖 WS 握手与帧解析规范 §6.1(Node 原生 http upgrade + 手写帧,不引 npm)。
  5. 拥挤控制硬规则 R1-R8(§8.1):旁白单句队列(voice 层)、bot 喊话 sfx 层同刻 ≤1、怪物移动 loop ≤3 路(最近 3 只)、非语音信息全部 <1s 短音效、听觉视野裁剪只报内圈(<4s 抵达)。
  6. 引擎改动唯一一处(后向兼容):engine/audio.js 的 sfx/voice 播放各加可选 opts.pan(-1..1,StereoPannerNode 接入对应总线),缺省行为逐字节不变(§9)。怪物移动 loop 走游戏层句柄(abyss _startLoop 先例 + 游戏层自建 panner),不占引擎改动面。
  7. 台词表 23-hunt-voice-ids.md:旁白/系统音 60 句 ×2 性别(male=Uncle_Fu / female=Serena,预算打满)+ bot 喊话 3 角色 ×8 句 = 24 条固定单音色(阿岩=Uncle_Fu / 小筝=Serena / 老周=Eric;因走 sfx 层带 pan,落盘 audio/sfx/,异例说明见台词表头注)+ 键盘变体 11 对。数字信息全分档整句,无运行时拼接。
  8. 设计裁决与对任务书核心案的修正记录(双击矛盾、出击冷却、防区模型、房码 UX 范围等 9 条)见 §15,实施前必读。断言清单住 13-playtest-criteria.md §24,本文 §13 只留摘要与指针。

1. 概述

1.1 一句话

夜幕降临,野兽从四面八方围上来——你和队友背背守住营地篝火,听声音的方向滑过去就是一刀,撑过五波,天亮就赢。

1.2 题材与纯音频相性

守夜围猎是"方位即生死"的题材:怪物唯一的接近预告就是它逼近的声像。视觉游戏里这是小地图+tower defense;纯音频里,声像本身就是小地图——题材与媒介互为 justification,与 dungeon「声音就是你的眼睛」同源,但本作是实时+协作,不是回合制探索。

1.3 定位:纯音频 MMORPG 路线 · 第一阶段最小验证切片

本项目长线方向是纯音频 MMORPG(持久世界、多玩家同图协作)。《围猎》是该路线的第一个可玩切片,刻意把范围切到最小,只验证三个技术-设计命题:

验证点 本文档落点 通过信号
实时同步:零依赖 WS、服务端权威战斗、事件流+快照兜底、断线重连 §6 协议 局域网 2-4 端同局,事件一致,断线 30s 内重连无感回槽
音频信道拥挤控制:多源并发(旁白/bot 喊话/怪物 loop/定位音效)不糊 §8 R1-R8 最坏并发 7 声流下威胁可辨、警报不丢(§8.4 验证口径)
空间音频协作:靠 pan 的方位分工与支援是否成立 §3 防区 + §7 bot 补位 玩家能用呼喊-补位闭环分担压力,无需任何视觉

明确不做(切片纪律):无持久世界、无跨房聊天、无跨玩家排行榜("排行榜"= 进度 API 的个人最佳桶 + 大厅卡片 summary,§12)、无房码音频录入 UX(协议保留,客户端 v1 只做快速匹配,§6.4)、无内购/社交。这些列 roadmap,不在本文档。

1.4 单局

5 波为一局,约 5 分钟(含 lobby ≈ 5.5 分钟;首局含教学 ≈ 6.5 分钟)。营地耐久初始 10、共享;耐久归零 = 营地失守(立即终局,突围结算,不入榜);撑过 5 波 = 胜利结算(评级 S~C + 个人击杀分档 + 排行榜写入)。

1.5 与现有 12 游戏的关系

实时方位感承接 space(呼啸来袭+同向反应),但改为协作分工;状态分档链承接 dungeon(上滑多段链);威胁裁剪承接 dungeon 脚步距离档音量规则并升级为显式"听觉视野"(§8.2);bot 喊话平铺资产承接 rpg/radio/detective NPC 先例,但首次走 sfx 层空间化(§8 R2);结算链死窗沿用 dungeon H1 先例(800ms 手势死窗);看门狗/向导层全照 00 §6。两个"第一":第一个联机游戏、第一个用到运行时 pan(引擎 opts.pan,§9)。

1.6 本作三大特有风险(均有显式对策)

  1. 多源并发糊耳(5 波峰值:旁白+喊话+3 路 loop+定位音效)→ §8 规则表 + §8.4 验证断言。
  2. 实时联机与纯音频教学的根本矛盾(不能暂停真人局教学)→ 首局教学房(§5):单人+bot、教学波、学期零惩罚,教完同场接续第 1 波。
  3. 协作流于形式(都能打所有方向=不需要队友)→ 出击冷却 2.5s 限单人吞吐 + 软防区 + bot 补位闭环(§3.3、§7)。

2. 手势映射与豁免登记

2.1 战斗态(WAVE,含教学局 TEACH 的战斗段)

手势 作用 反馈
四向滑(上/下/左/右) 出击:滑向映射 90° 弧(上→{NW,N,NE}、右→{NE,E,SE}、下→{SE,S,SW}、左→{SW,W,NW}),击杀弧内内圈(eta≤4s)最近一只;冷却 2.5s 引擎 swipe 震 + atk_whoosh;命中 kill_*+pickup 震;挥空 atk_swish+error 震
单击 呼喊支援:全队友收到你防区方位的空间化喊话 + warning 震;bot 朝你侧补位 10s(§7.3);节流 5s/人 引擎 confirm 震 + 本机播自己座位角色的 help_call(中央)
双击 旋风斩就绪 → 放出:清全场内圈(eta≤4s)全部怪物,冷却 8s;冷却中 → 重听当前威胁播报(threat_*,宪法"双击=重听"落地) 放出:success 震 + skill_spin;冷却中:引擎 confirm 震 + threat_*
上滑 状态链:营地耐久档 → 波次档 → 在场猎人数 → 自己击杀档(4 段链播 queue:true) hp_band_* → st_wave_* → team_* → kill_band_*
下滑 模态菜单(不暂停,豁免 E3,§2.4) menu earcon
长按 非玩法输入:引擎旁白快进默认行为保留 —
  • 出击冷却 2.5s 内四向滑 → 仅 error 震(无语音、不发 act;dungeon 脉冲冷却先例)。
  • 单击呼喊是非即时操作,300ms tap 延迟无碍(escape 单击=检查先例)。
  • 旋风斩就绪时刻播 skill_ready(queue:true,绝不顶句;每轮冷却完成只播一次)。
  • 事件震动总表:命中 pickup / 挥空 error / 旋风斩放出 success / 突入 hit / 收到呼喊 warning / 波次开始(ev wave)heartbeat / 耐久首次 ≤2 danger(每局 1 次,配 danger_low)。手势识别震动(swipe/confirm)由引擎内置承担,游戏层不重复(00 §2.3)。

2.2 标题/匹配/大厅等待(TITLE / MATCHING / LOBBY)

手势 TITLE MATCHING LOBBY
单击 快速匹配(首局=教学房) —(无效,error 震) 立即开局(act start)
双击 重听开场/提示 重听 重听 room_wait
上滑 个人最佳播报(有档时:best 评级+击杀档) error 震 在场猎人播报(team_*)
下滑 菜单(帮助/回大厅) 菜单(含"取消匹配") 菜单(退出房间回大厅)
左右滑 error 震 error 震 error 震

2.3 结算态(END)

单击=再来一局(重新进匹配);双击=重听结算链;上滑=重听个人最佳段;下滑=菜单(回大厅)。结算链进入时盖 800ms 手势死窗(dungeon H1 先例:吞掉致命事件前后在途的 ghost 手势,死窗后手势照常)。

2.4 模态菜单(豁免 E3:联机实时不暂停)

下滑呼出 → 单击循环 → 双击确认 → 上滑=帮助(播 help_main)→ 下滑=关闭(00 §5.2 交互骨架不变)。菜单打开期间战斗照常进行(怪物照走、突入照扣)——联机不可单方暂停,这是与 00 §5.2"菜单打开时暂停计时类玩法"的显式豁免。菜单项固定 3 项:sys_menu_resume(回到猎场)/ sys_menu_help(重新听帮助)/ sys_menu_home(退出房间回大厅 = 发 leave,槽位按 §6.6 处理)。无"重新开始"(联机房局不可单方重开)。菜单打开即播 sys_menu + 首项;菜单内另播 settings_hint(设置只读、回大厅修改,00 §1.2)。

2.5 豁免登记(显式)

# 豁免条目 理由(先例)
E1 四向滑=出击(非选择/移动) 以滑动为核心玩法(space 四向滑=闪避同款豁免);三件套(上滑/下滑/双击重听)全部保留
E2 双击优先=旋风斩,仅冷却中=重听威胁 旋风斩是即时技,必须绑零延迟双击(00 §5.4:即时判定绑滑动或双击);冷却中重听保留宪法语义
E3 菜单打开不暂停 联机实时,暂停不可能;菜单项压到 3 项、打开即播提示,把"逛菜单被咬"的代价做成可感知风险
E4 单击=呼喊(非确认/继续) 非即时操作,300ms 延迟无碍(escape 单击=检查先例)

教学(TEACH)逐条讲清 E1/E2/E4(§5);不占用长按(快进保留,无需 rateBoost 豁免);不开 immediateTap。

3. 世界模型与数值

3.1 猎场与怪物

  • 圆形猎场:猎人位于圆心营地,野兽从边缘(8 罗盘方位 N/NE/E/SE/S/SW/W/NW)沿直线匀速逼近圆心。逼近全程 8-12s(按波次表)。
  • 怪物状态由服务器持有:{ id, mkind, dir, eta }——eta = 距突入的秒数(服务端单调时钟)。客户端不推算位置,只按事件流+快照渲染(§6.7)。
  • 怪物 2 型:
型 mkind 逼近 突入扣耐久 声音
饿狼 wolf 8-10s -1 howl_wolf 生成呼啸 + loop_wolf 移动
暴熊 bear 11-12s -2 howl_bear 低吼 + loop_bear 重脚步
  • 距离分档(听觉视野,§8.2):外圈 eta>6s(仅生成呼啸一声);中圈 4-6s(移动 loop 可闻,低音量);内圈 eta≤4s(可击杀的近战窗,loop 升档,计入威胁播报)。

3.2 出击与技能(服务端裁决,§6.5)

  • 出击:act attack dir → 弧 = dir±45°(3 个罗盘向)→ 弧内活着且 eta≤4.0 的怪中取 eta 最小者击杀;无 → miss。冷却 2.5s/座(服务器计时,违规 err cooldown)。
  • 旋风斩:act skill → 清除全场 eta≤4.0 全部怪(不分方向)。冷却 8s/座(违规 err skill_cd)。
  • 呼喊:act callout → 广播 ev callout;bot 补位(§7.3)。节流 5s/座。
  • 击杀归属 = act 来源槽位(结算个人击杀账)。

3.3 防区(软分工)

  • 每座位固定主防区(连续罗盘弧)与防区中心(喊话 pan 用):
猎人数 座位 0 座位 1 座位 2 座位 3
3 [N,NE,E],中心 NE [SE,S,SW],中心 S [W,NW],中心 WNW —
4 [N,NE],中心 NNE [E,SE],中心 ESE [S,SW],中心 SSW [W,NW],中心 WNW
  • 防区不是硬限制:任何玩家可打任何方向(弧映射见 §2.1)。防区用于:① bot 目标选择偏置(§7.2);② 呼喊/喊话的 pan 方位来源;③ 刷怪剧本的方位均衡(§3.5)。
  • 座位角色(voice 身份):座 0=阿岩(yan)、座 1=小筝(zheng)、座 2=老周(zhou);座 3 仅 4 人局存在,无专属角色(呼喊=call_whistle 哨音,见 §15 裁决 6)。真人"扮演"座位角色:你的呼喊用你座位角色的预录声,断线转 bot 后声音身份无缝延续。

3.4 波次表(5 波,服务器剧本)

波 狼 熊 狼逼近 s 熊逼近 s 刷怪间隔 s 波时长约
1 4 0 10.0 — 3.0 ~21s
2 6 0 9.5 — 2.5 ~24s
3 7 1 9.0 12.0 2.2 ~29s
4 8 1 8.5 11.5 1.8 ~28s
5 10 2 8.0 11.0 1.5 ~30s
  • 波间休息 8s(wave_clear → 休整 → 号角 + 下一波播报)。波内怪物匀速逼近不止步,一波必在有限时间内出清(杀或漏),无需超时兜底。
  • 每波开始播对应整句 wave_band1…wave_band5(台词表 C 组;先号角 horn_wave 后播报)。
  • 全程怪物总数 39,耐久预算 10(熊 -2)。平衡目标:3 bot 水准下 solo 余耐久 6-9(评级 A/B),真人协作越好评级越高。
  • 局时长核算:战斗 ≈ 132s + 休息 32s + lobby ≤12s ≈ 3 分钟战斗 + 首尾 ≈ 5 分钟 ✓(任务书"约 5 分钟")。

3.5 刷怪方位与种子

  • 房间 seed 开局掷一次(joined.seed),mulberry32 派生:rng(wave) = mulberry32((seed ^ (wave * 0x9E3779B9)) >>> 0)。
  • 每波方位分配:把本波怪物按座位数轮转发牌到各座位防区内的随机方位(同一方位同刻最多 2 只在场,防叠声);同 seed → 同 spawn 剧本(服务器单测可复现断言)。
  • 服务端战斗模拟 tick = 100ms;快照 2Hz(§6.3)。

3.6 耐久与评级

结算时剩余耐久 评级
≥9 S
7-8 A
4-6 B
1-3 C
0(波内归零) 失守(立即终局,无评级,不入榜)

评级由服务器算好在 ev end.grade 下发(客户端不算分,防双源)。

终局播报链:胜利 = end_win → grade_s/a/b/c → kill_band_*(自己击杀档)→ end_rank → end_again;失守 = end_lose → kill_band_* → end_again(失守不播评级、不播 end_rank、不写 best,§12)。进 END 盖 800ms 手势死窗(§2.3)。

4. 状态机(客户端)

4.1 状态列表

TITLE / MATCHING / LOBBY / TEACH / WAVE / MENU(overlay) / END / LOST。MENU 为挂起 overlay(记录返回态,不暂停战斗);LOST = 连接不可恢复(回大厅出口)。

4.2 转移图

TITLE ──单击──> MATCHING ──joined──> LOBBY ──act start / 12s 到 / 满4人──> (ev wave 1)
                  │ 首局(tutDone=false) → join teach=true → joined.state.phase='teach' → TEACH
MATCHING ──连接失败──> LOST(net_lost→net_gone) ──单击──> TITLE
TEACH ──教学完成 / 下滑跳过──> WAVE(wave 1)
WAVE ──ev end──> END ──单击──> MATCHING(再来一局)
WAVE/LOBBY ──下滑──> MENU ──返回──> 原态(战斗不暂停)
WAVE ──WS 断开──> 本地静默重连 ≤30s(net_lost) ──joined(resume)──> WAVE(net_back)
                  └──超时/房已灭──> LOST(net_gone)

4.3 每状态手势映射总表

手势 TITLE MATCHING LOBBY TEACH WAVE MENU END
四向滑 error error error 步骤作答/出击 出击 error error
单击 快速匹配 error 立即开局 步骤作答/呼喊 呼喊 循环切项 再来一局
双击 重听 重听 重听 步骤作答/旋风斩 旋风斩/重听威胁 确认执行 重听结算链
上滑 最佳播报 error team_* 状态链(T4 起) 状态链 帮助 重听最佳段
下滑 菜单 菜单(取消匹配) 菜单 跳过教学 菜单(不暂停) 关闭 菜单
长按 快进 快进 快进 快进 快进(非玩法) — 快进

无效手势一律 error 震;full 档语音纠错 gd_invalid(onceKey 同局 1 次)。看门狗语音 idle-only。

5. 教学编排(TEACH,首局教学房)

矛盾与解法:实时联机局不能暂停教学 → 首次进入(进度 tutDone 为假)走教学房:单人 + 2 bot(教学段 bot AI 挂起)、先行一波教学波(3 狼,逼近 12s,学期零惩罚:教学波突入不扣耐久),教学完成或下滑跳过后,同一房间直接接续第 1 波(bot 激活)。教学即真联机局——这本身就是切片验证点(首局就跑了完整的 WS/事件流路径)。

步 旁白 等待动作 通过/反馈
T0 intro_1 + intro_2 + tut_rule 单击 confirm 震
T1 tut_attack(服务器放教学狼 1,方位 N) 朝声音方向滑 kill → tut_kill_ok;挥空/错向 → gd_idle 重教(≤2 次后自动放过该狼)
T2 tut_callout 单击呼喊 callout ev → bot npc_*_help_ack 响应演示(教学 bot 必答)→ tut_callout_ok(呼喊-响应闭环点明)
T3 tut_skill(服务器放教学狼 2、3,贴近 eta 5s) 双击旋风斩 cleared=2 → tut_skill_cd(讲冷却与冷却中双击=重听)
T4 tut_status 上滑(状态链) 链播完 → tut_breach → tut_done → 进 WAVE 1
任意 — 下滑 tut_skip → 进 WAVE 1(tutDone 写入进度)
  • 教学波零惩罚:教学狼突入不扣耐久(明说规则前不漏真话);T1 首输入 ≈ t+20s(<60s ✓);首个正反馈 = T1 首杀 ≈ t+40s(≤3min ✓)。
  • 看门狗:每步 8s nudge 纯震(教学句不重播),T1/T3 卡 30s 自动放过当前狼推进(space 先例),不卡流程。
  • 二周目起 TITLE 单击直达快速匹配(tutDone 存进度,§12)。

6. 多人协议(两个开发 agent 的实现契约)

6.1 传输:零依赖 WebSocket(server.js 增补)

  • 端点:GET /ws/hunt,与静态/REST 同一 HTTP 服务器、同一端口。http.createServer 的 'upgrade' 事件接管:校验 Upgrade: websocket、Sec-WebSocket-Key,回 101 + Sec-WebSocket-Accept = base64(sha1(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))(node:crypto,无 npm)。
  • 帧解析(手写,约 100 行,建议独立 web/server/ws.js 便于单测):客户端→服务器帧必须带 mask(不带 → close 1002);支持 opcode 0(continuation 拼装)/1(text)/8(close)/9(ping→回 pong)/10(pong);payload 7/16/64 位长度全支持;单条消息上限 4KB(超限 close 1009);二进制帧 close 1003。服务器→客户端帧不 mask。
  • 活性:服务器每 15s ping,45s 无 pong 判死(等同断线走 §6.6);每连接应用消息速率帽 20 条/s(超限 err rate,再犯 close)。
  • 发送背压:每连接一个待发队列;snap 可丢(新顶旧),ev/joined/err 不丢;队列 >200 → close 1013。
  • 每消息 = 1 条 text 帧 = 1 个 JSON 对象,必有 t 字段。协议版本 ver: 1(join 携带,不符 err bad_msg)。

6.2 客户端→服务器消息(3 条)

join(连接后首条,5s 内不发则 close):

字段 类型 含义
t "join" —
ver number 协议版本,恒 1
room string "quick" = 快速匹配;或 4 位房码(大写无歧义字符 23456789ABCDEFGHJKMNPQRSTUVWXYZ)
name string 显示名(1-24 字符,取自档案;服务端截断兜底)
teach bool? true = 请求教学房(首局;服务端强制单人房+教学波)
resume string? 重连凭证(joined.resume 原值);携带时按 §6.6 回槽

act(对局意图;服务器按到达序裁决):

字段 类型 含义
t "act" —
kind "attack" | "callout" | "skill" | "start" start 仅 LOBBY(立即开局)
dir "N"|"NE"|"E"|"SE"|"S"|"SW"|"W"|"NW" attack 必填(客户端四向滑只发 N/E/S/W 四基向,弧解析在服务端;bot 可发 8 向)
seq number 客户端单调递增(去重/乱序检测;乱序不拒,仅日志)
at number 客户端发出时刻 ms(仅诊断用,裁决以服务端到达序为准)

leave:{ "t": "leave" } —— 主动退出(菜单"回大厅"),槽位立即按 §6.6 处理(无 30s 宽限)。

6.3 服务器→客户端消息(joined / ev / snap / err)

joined(join 受理;resume 重连亦发):

字段 类型 含义
t "joined" —
room string 实际房码
slot number 你的座位号 0-3
resume string 重连凭证(16 hex,每槽位签发一次,连接存活期内不变)
char "yan"|"zheng"|"zhou"|null 座位角色(座 3 恒 null)
sector string[] 你的主防区方位集(§3.3)
seed number 房间种子(复现用)
state object { phase: "lobby"|"teach"|"wave"|"end", wave: number, dur: number }
roster array 全花名册:[{ slot, name, bot, char, sector }](bot=true 时 name=角色名)

ev(事件流,即时下发;ts = 房间单调时钟 ms(开局为 0)):

kind 附加字段 含义
spawn id, mkind("wolf"|"bear"), dir, eta 怪物生成(eta=逼近全程秒数)
kill id, slot, dir, mkind 出击命中击杀(归属 slot)
miss slot, dir 挥空(弧内无可打怪)
skill slot, cleared: number[] 旋风斩放出,cleared=被清怪 id 表
breach id, mkind, dir, dur 突入:耐久新值 dur(wolf -1 / bear -2 已结算)
wave wave 第 wave 波开始(1-5)
waveclear wave 第 wave 波出清
callout slot 求援呼喊(真人单击或 bot 压力呼救;接收端播该座角色 help_call + warning 震)
botline slot, line bot 喊话(line ∈ greet/help_ack/cover/kill/breach/skill/wave;客户端按 char+line 播 sfx/npc_<char>_<line>)
roster roster 花名册变更(加入/离开/断线/转 bot;形状同 joined.roster)
end win, dur, grade("S"|"A"|"B"|"C"|null), kills 终局;kills={ "0": 5, ... } 按 slot 的个人击杀

snap(2Hz 兜底快照):

字段 类型 含义
t "snap" —
ts number 房间单调时钟 ms
phase / wave / dur — 同 joined.state
mobs array 在场怪物全量 [{ id, mkind, dir, eta }](eta 为 ts 时刻值)
slots array [{ slot, alive, bot, cd, skillCd }](cd/skillCd=剩余冷却秒,重连恢复冷却 UI/判定用)

err:{ "t": "err", "code": "cooldown"|"skill_cd"|"bad_dir"|"not_ingame"|"room_full"|"room_gone"|"bad_msg"|"rate", "msg": "人话描述" }(cooldown/skill_cd 为正常违规拒绝,客户端不应惊扰玩家——客户端本地已先拦)。

6.4 房间管理与匹配

  • 快速匹配:找 phase='lobby' 且有空人类座的房 → 进;没有 → 建房(房码 4 位随机)。客户端 v1 只发 room:"quick";显式房码 join 协议完整、服务端实现并单测,客户端录入 UX 列 roadmap(§15 裁决 5)。
  • LOBBY 上限 12s:到点、任一人类 act start、或满 4 人 → 开局(播 room_start,随后 ev wave 1 + wave_band1)。开局时空位由 bot 补至 max(3, 人类数) 猎人:1 人→2 bot、2 人→1 bot、3 人→0 bot(3 座)、4 人→0 bot(4 座)。第 4 座仅 4 人局启用。
  • join 只在 lobby 受理;对局中 join → err room_full(v1 不做中途加入)。
  • 教学房:join teach:true 且本地 tutDone=false → 强制单人房(§5 剧本);教学波完直接续 WAVE 1。

6.5 服务端权威战斗(hunt-room.js,建议独立模块便于单测)

  • 房间结构:{ seed, phase, slots[≤4], mobs: Map, wave, dur, tickTimer, snapTimer };tick 100ms:eta 递减、突入结算、波剧本推进;snap 500ms。
  • 裁决规则(§3.2 数值的权威实现):弧映射、eta≤4.0 近战窗、冷却 2.5/8s、呼喊节流 5s——全部只在服务端生效;客户端可做本地预扣(冷却 UI),但以 err/ev 为准。
  • bot = 特殊 slot(bot:true,无连接):同一套裁决管线,由 §7 AI 产生 act。
  • 时钟:ts 为房间单调 ms。客户端在 joined/snap 到达时记 offset = ts - performance.now(),渲染用 nowServer = performance.now() + offset;局域网无需 RTT 补偿(逼近时长 8-12s,误差淹没在听觉分辨率内)。

6.6 断线与重连

  • 连接断开(或 45s 无 pong)→ 槽位标记断线(roster 广播 alive=false),30s 宽限:槽位静默(无 act 产出,猎人"愣在原地"——这是真实的协作代价)。
  • 宽限内带 resume 重连 → 回槽:重发 joined(同 slot/seed/char)+ 紧随 snap 全量,客户端无缝续渲染(net_back)。
  • 宽限超时:剩余人类 ≥3 → 槽位移除(roster);否则槽位转 bot(roster,bot=true,char 沿用座角色,补位 bot 播 npc_*_cover,其余客户端播 net_to_bot)。转 bot 不可逆(该局内)。
  • 最后一个人类断开:房间保留至其 30s 宽限耗尽后销毁(无人类即灭,bot 不续命)。房灭后迟到 resume → err room_gone(客户端 net_gone → LOST)。
  • 终局 end 后房间保留 30s(各端写排行榜)随后 close 1000。

6.7 客户端渲染模型(client agent 契约)

  • 本地怪表 = ev 增删 + snap 校正:每 snap 对账——本地多出的 id 删、缺的按 snap 补、eta 偏差 >0.5s 校正。事件流为主、快照兜底,二者矛盾以 snap 为准。
  • 每 500ms 重估渲染集:eta>6s 静默;≤6s 按 eta 升序取前 3 只起 loop(§8 R3);loop 音量按档(6-4s:0.30 / 4-2.5s:0.55 / <2.5s:0.80);pan 按方位角映射(§8.3)。
  • 断网期间:本地怪表按最后已知 eta 继续衰减渲染(怪物照爬——戏剧张力保留),恢复后以 snap 校正。

7. Bot 设计(服务端驱动)

7.1 角色与声音资产

座位 角色 char speaker instruct 常量 性格
0 阿岩 yan Uncle_Fu 憨厚壮实的中年男声,猎户,话少踏实 憨厚
1 小筝 zheng Serena 轻快爽利的年轻女声,猎手,干脆利落 轻快
2 老周 zhou Eric 沙哑沉稳的老年男声,老猎手,带点调侃 沙哑

每角色 8 句固定短句(事件触发,全集见台词表 N 组):greet / help_call / help_ack / cover / kill / breach / skill / wave。固定单音色平铺、不做双性别(rpg NPC 先例);因经 sfx 层带 pan 播放,资产落 audio/sfx/npc_<char>_<line>.{ogg,m4a}(§15 裁决 7)。

7.2 战斗 AI(tick 500ms,确定性)

  • 出击:冷却就绪且存在目标方向时出手。方向压力 P(d) = Σ(1/eta)(d 内活怪,仅计 eta≤4);主防区方向 ×1.5 偏置;取 max P 方向发 act attack(dir=该方向精确罗盘向)。拟人反应带:只在最优目标 eta ≤ 2.0 + rng()×1.0 时才出手,且每次出手决策带 80% 空转概率(rng 走房间 seed,复现可断言),避免" eta 一进 4 秒就秒"的机械感(数值为 §15 裁决 10 调参后口径)。
  • 旋风斩:全场 eta≤2.5 的怪 ≥3 只且技能就绪,且 60% 概率想起 → act skill(裁决 10)。
  • 呼救:主防区压力 ≥3(≥3 只 eta≤6)且 20s 节流 → act callout。
  • 难度校准:bot 不失误(挥空不存在——只打有目标的弧),但受 2.5s 冷却、反应带与空转概率上限;3 bot 局实测评级 A/B 为主(§3.4 平衡目标,多种子扫描见 §15 裁决 10),给真人留出"比 bot 强"的空间。

7.3 补位(呼喊响应)

收到 ev callout(真人或 bot 发出)后:空闲 bot(当前 500ms 无待发 act 者,多取座位号小者)播 help_ack,且其后 10s 内目标选择偏置改为呼喊者防区方向 ×2.0(覆盖主防区偏置)——即"朝你侧补位"。补位 bot 首次在新防区击杀后再无怪时播 cover。呼喊本身不改变 bot 的冷却/反应带(公平)。

7.4 喊话调度(与 §8 R2 联动的服务端纪律)

  • botline 触发源:greet(开局补位完成,逐只间隔 ≥1.5s)/ cover(转 bot 接管、补位落定)/ kill(杀熊或三连杀,15s 节流)/ breach(本防区漏怪,20s 节流)/ skill(放旋风斩)/ wave(第 2 波起,轮转一只 bot)。
  • 服务端对 botline/callout 全局节流:10s 窗口 ≤2 条,超出丢弃(喊话是氛围,不是信息主通道);help_call/help_ack 优先级最高(呼救语义不可被氛围句顶掉)。

8. 音频信道拥挤控制(本文档重点章节)

8.1 硬规则表 R1-R8

# 规则 数值
R1 旁白/系统音单句队列(引擎 voice 层既有):同刻 1 句,链播 onComplete 串行;警报类(breach/breach_heavy/danger_low)可顶掉状态/播报类(上滑链、skill_ready),教学/结算链不可顶 同刻 voice=1
R2 bot 喊话走 sfx 层(带 pan,与旁白并发):同刻在播 ≤1 条;待播队列深 ≤1(新到顶掉未播的过期句);旁白在播时延迟投递 ≤2s,超时丢弃;服务端全局 10s ≤2 条(§7.4) 同刻喊话=1
R3 怪物移动 loop ≤3 路:只渲染 eta 最小的 3 只(500ms 重估),其余静默;loop 经游戏层句柄 + 自建 StereoPannerNode(abyss _startLoop 先例,不占引擎改动面) 同刻 loop≤3
R4 定位 one-shot ≤2 并发(howl/击杀/突入/旋风斩):同类间隔 ≥0.15s;波次生成潮的呼啸队列深 ≤2,超出丢弃(怪近后 loop 已接管信息,呼啸可弃) 同刻 one-shot≤2
R5 非语音信息全部 <1s 短音效:号角 0.9s、join_chime 0.4s、call_whistle 0.6s、kill 0.5s 量级;语音通道只给人声 —
R6 听觉视野裁剪(§8.2):威胁播报只计内圈(eta≤4);状态链不报具体方位(方位由 loop pan 承载,语音永不逐只报方位——8 向 × 距离档的语音枚举被明确禁止) —
R7 电平分层:voice 层播时 BGM 自动 duck 20%(引擎既有);bot 喊话(sfx 层)不触发 duck → 游戏层统一 vol 0.55 压一档,防压旁白;loop 音量档上限 0.80 —
R8 最坏并发核算:旁白 1 + 喊话 1 + loop 3 + one-shot 2 = 7 声流;频带分离(loop 低频 100-300Hz / 人声 300Hz-3kHz / howl 中高 1-3kHz / BGM 垫底),引擎限幅器兜底。峰值场景(第 5 波 + 警报 + 呼喊)不得丢警报、不得叠爆 ≤7 声流

8.2 听觉视野裁剪规则

8 方位 × 3 距离档:

档 eta 可听内容 可被打
外圈 >6s 仅生成呼啸一声(one-shot,pan+距离音量 0.4) 否
中圈 4-6s 移动 loop(vol 0.30;受 R3 路数上限约束) 否
内圈 ≤4s loop 升档(0.55/0.80);计入 threat_* 威胁播报与 danger 评估 是(近战窗)
  • threat 口径:threat_none(内圈 0 只)/ threat_few(1-2 只)/ threat_many(≥3 只)——只报数量档,不报方位;方位信息永远由 loop/呼啸的 pan 实时承载(这本身就是切片要验证的"空间音频协作"命题)。
  • 播报裁剪:状态链/威胁播报里禁止出现逐方位枚举句;台词表不含此类 id(结构性杜绝)。

8.3 方位 → pan 映射(全作统一)

方位角 az(N=0°、E=90°、S=180°、W=270°):pan = sin(az)(N/S=0、NE/SE=±0.7、E/W=±1、NW/SW=∓0.7)。前/后歧义(StereoPanner 不能分前后):后半平面(90°<az<270°)的 loop/呼啸音量 ×0.6("身后发闷",dungeon"背后=中央减半"先例);教学 tut_rule 讲明此约定。呼喊/喊话的 pan 取座位防区中心方位(§3.3)。

8.4 验证口径(harness/测试 agent 记录点)

  • 逐事件记录:任一时刻 voice 在播句数、sfx 层人声句数、loop 路数、one-shot 并发数——断言不超 R1-R4 上限。
  • 警报可达性:第 5 波峰值剧本下,breach/danger_low/wave 播报零丢失(可被顶掉的状态类句不计)。
  • 实机听测 checklist(roadmap 真机轮):戴耳机分辨"左前狼 + 正右熊 + 旁白警报"三源。

9. 引擎改动(唯一一处,后向兼容)

web/engine/audio.js:

  1. _playSfx(id, { volume = 1, pan } = {}):typeof pan === 'number' && isFinite(pan) 且 pan !== 0 时,clamp 到 [-1,1],链路改为 source → gain → StereoPannerNode(pan) → sfxBus;pan 缺省或 0 → 原路径逐字节不变(不建 panner 节点)。ctx.createStereoPanner 不存在(老 Safari)→ 静默忽略 pan(不炸、不报错音)。
  2. _playVoice 同款:opts.pan 存在时把 panner 插在 voice gain 与 voiceBus 之间;缺省不变。(本作旁白不使用 voice pan——对称能力一次给足,后续游戏可用;见 §15 裁决 7。)
  3. 回归断言(harness 增补):全部既有游戏 play() 调用(无 pan)行为不变;pan=0 与缺省等价;pan=-1/1 时 panner 值正确。

本作使用面:bot 喊话、生成呼啸、击杀/突入/技能音全部 one-shot 带 pan;怪物 loop 走游戏层句柄(§8 R3)。

10. 音频三层资产

10.1 BGM(2 首,Mureka,-20 LUFS,ogg+m4a,90s 无缝循环)

id 状态映射 prompt 草稿(英文)
bgm/menu TITLE / MATCHING / LOBBY / END(结算 vol 0.5) "Night camp ambient pad, distant crickets and low wind, warm fireplace crackle subtle, calm anticipation, no vocals, seamless loop"
bgm/hunt TEACH / WAVE "Tense night hunt drums, low tribal percussion 100 bpm, ominous strings pulses, cold wind, no vocals, seamless loop"

切波不改 BGM(波次张力靠号角+怪密度);失守/胜利走引擎 crossfade 到 menu。语音 duck 20% 引擎自动。

10.2 SFX(13 + 24 喊话;SYN=程序合成,SA3=Stable Audio 3;双格式、真峰值 ≤-3dBFS)

id 方式 说明
atk_whoosh SYN 挥击风声 0.3s(带 pan=出击方位)
atk_swish SYN 挥空空荡风声 0.3s(归因真话:没打到)
kill_wolf / kill_bear SA3 狼哀嚎倒地 0.5s / 熊闷重倒地 0.7s(带 pan)
skill_spin SA3 旋风斩气旋 0.8s(中央,大动态)
breach_thud SA3 营地被撞闷响+木栅裂 0.6s(中央)
horn_wave SA3 波次号角 0.9s(中央)
join_chime SYN 队友加入 0.4s(双音上行)
call_whistle SYN 求援哨音 0.6s(座 3 呼喊用,带 pan)
howl_wolf / howl_bear SA3 生成呼啸 0.8s / 低吼 1.0s(带 pan,后半平面 ×0.6)
loop_wolf / loop_bear SA3 移动循环:狼碎步+低呜 / 熊重步+喘息(4s 无缝循环源,游戏层 loop,pan+距离档音量)
npc_<char>_<line> ×24 TTS bot 喊话(voice 管线生成、落盘 sfx/,峰值归一 0.89 沿用 voice 策略;游戏层 vol 0.55,§8 R7)

10.3 voice(旁白/系统音)

60 句 ×2 性别(male=Uncle_Fu / female=Serena,全表同一 instruct 常量/性别),分组与全文见 23-hunt-voice-ids.md。数字全分档整句:耐久 4 档 / 波次 3 档 + 5 整句 / 在场猎人 2 句 / 击杀 3 档 / 威胁 3 档 / 评级 4 整句。键盘变体 11 对(V 组,gesture.inputMode() 选播)。

规模核算:voice 60×2×2fmt ≈ 12MB + npc 24×2 ≈ 2MB + key 变体 11×2×2 ≈ 2MB + sfx 13×2 ≈ 1MB + bgm 2×2 ≈ 6MB ≈ 23MB < 30MB 预算 ✓。

11. 向导层接入(engine/guide.js,不新增 earcon 词表)

状态 guide.state() 时点
TITLE / MATCHING / LOBBY / MENU menu 进态即播
TEACH / WAVE battle 开局/波开始
END settle 结算进入
danger danger 耐久首次 ≤2(每局 1 次,配 danger 震 + danger_low)
  • turn cue 不使用(无回合制);看门狗:WAVE/LOBBY 无操作 [10s, 25s] → gd_idle / null(第 2 级纯 nudge);TEACH 每步 [8s] 纯 nudge(教学句不重播)。玩家任意手势复位;guide=off 全静零定时器(既定契约)。
  • 纠错:无效手势 error 震 + gd_invalid(onceKey 同局 1 次,之后仅震)。
  • 无卡关三级提示(本作无"卡住"形态:压力来自怪物而非谜题)。

12. 存档与排行榜(进度 API)

{
  "schema": 1, "game": "hunt", "updatedAt": 0,
  "summary": "最佳评级A · 击杀14 · 营地余8 · 共3局",
  "best": { "grade": "A", "kills": 14, "durLeft": 8, "at": "<ISO>" },
  "runs": 3, "totalKills": 31, "tutDone": true
}
  • 写入时机:终局结算(每局一次,胜利/失守都写 runs/totalKills;best 只被胜利局按 评级 > 营地余耐久 > 击杀 的序更新)。客户端在收到 ev end 后自行 PUT(Bearer = 档案 token;离线只写 localStorage soundgame.progress.hunt)。00 §4 约定遵守:data 自由格式 + 必带 summary(大厅卡片直接显示)。
  • summary 生成规则:最佳评级{grade} · 击杀{kills} · 营地余{durLeft} · 共{runs}局;无 best(全败)时 共{runs}局 · 还没守到天亮过。
  • 排行榜形态:本切片无跨玩家排行 API——"排行榜"= 个人最佳桶 + 大厅卡片 summary(00 §4.3 既有机制)。跨玩家榜列 roadmap。
  • 读取:TITLE 有 best 时上滑播最佳段(评级+击杀档);tutDone 控制是否进教学房(§5)。

13. playtest 断言(摘要;全表住 13 号文档 §24)

  • 关键路径:遮罩解锁 → TITLE → 快速匹配(首局教学房 T0-T4 逐步)→ LOBBY → 开局 bot 补位(roster 断言 3 猎人)→ 5 波(spawn/kill/breach/wave 事件序列与 §3.4 表逐波核对)→ 终局结算链(grade 与 dur 一致)→ PUT progress(summary 命中生成规则)→ 再来一局。
  • 边界:断线 30s 转 bot / 宽限内 resume 回槽无缝 / 旋风斩冷却与冷却中双击=重听 / 呼喊→bot 补位(10s 内 bot act 方向落入呼喊者防区)/ 听觉裁剪(eta>6 静默、loop ≤3、threat 只计内圈)/ 攻击冷却服务端拒绝 / snap 校正 / 菜单不暂停照扣耐久。
  • 失败即不通过:评级与 dur 不符(归因假话);服务器接受违规 act;ev 与 snap 矛盾不收敛;bot 喊话压过旁白(R1/R2 破);loop >3 路;教学狼扣耐久。
  • 全表与全局通用断言见 13-playtest-criteria.md §24。

14. 自检清单

# 硬约束 自检
1 FTUE 首输入 <60s / 首正反馈 ≤3min T1 首滑 ≈t+20s;首杀 ≈t+40s ✓(§5)
2 学习期零惩罚 教学波突入不扣耐久;做错重教 ≤2 次自动放过;挥空仅 error 震 ✓
3 手势宪法 上滑=状态、下滑=菜单、双击=重听(冷却中落地)保留;E1-E4 登记且教学讲清 ✓(§2.5)
4 向导层 签名 4 态不新增词表;看门狗 [10/25]s 二级纯 nudge;纠错 onceKey;guide=off 全静 ✓(§11)
5 旁白规范 60 句 ≤ 预算;整句无拼接;数字全分档;同 instruct 常量;无语速词;"重新听"规范写法 ✓(台词表头注)
6 拥挤控制 R1-R8 可断言;最坏并发 ≤7 声流;警报零丢失口径 ✓(§8)
7 方位降维 8 方位 × 3 距离档,pan 七值 + 后半平面 ×0.6;无连续角度、无逐方位语音枚举 ✓(§8.2/§8.3)
8 协议自洽 C→S 3 条、S→C 4 类字段表全;服务端权威+快照兜底;断线/重连/房灭路径闭合 ✓(§6)
9 引擎边界 引擎改动仅 opts.pan 一处且后向兼容;loop 走游戏层先例;30MB 预算内 ✓(§9/§10.3)
10 服务器约束 零依赖(手写 WS 帧);数据落盘/REST 零改动;单实例约束不恶化(房间全内存) ✓(§6.1)
11 P1 视障 双击免费重听威胁;上滑一键复述;方位由声像承载且规则教学讲明;无倒计时焦虑(波次自然出清) ✓
12 P3 通勤 单手免视;菜单不暂停但 3 项极简;局 5 分钟随玩随放 ✓
13 失败归因真话 评级=dur 服务端直发;结算击杀档=个人真账;挥空/失守有真话反馈(atk_swish/end_lose) ✓
14 seed 可复现 房间 seed + mulberry32 派生;刷怪剧本/bot 反应带全走 seed;服务器单测可复现 ✓(§3.5/§7.2)

15. 设计裁决与矛盾修正记录(实施前必读)

对任务书核心案的细化/修正,逐条登记(核心形态零改动):

  1. 双击矛盾修正:任务书"双击=旋风斩,8 秒冷却;无冷却时双击=重听威胁播报"自相矛盾(无冷却=就绪=放旋风斩)。裁定为:旋风斩就绪时双击=放出;冷却中双击=重听威胁播报——既保留技能,又让宪法"双击=重听"在全时段有定义(豁免 E2 登记)。
  2. 补出击冷却 2.5s/人:任务书未给出击冷却。无冷却则单人滑动吞吐无上限,协作失去必要性(§1.6 风险③)。2.5s 使单人峰值约 1 杀/窗,三人局才有分工意义。数值写在 §3.2,服务端裁决。
  3. 防区=软分工模型:任务书"玩家位于营地中心"与"bot 朝你侧补位"并存但无站位定义。裁定为软防区(§3.3):不设站位硬锁(任何方向都能打),防区只做 bot 偏置、喊话 pan 来源、刷怪均衡——保留"补位"语义且不引入连续几何。
  4. 四向滑 → 90° 弧映射:任务书"四向滑映射到最近罗盘方位"在 8 方位刷怪下不可玩(斜向怪永远打不到)。裁定:滑向映射 ±45° 弧,击杀弧内内圈 eta 最小者(§2.1/§3.2);协议 act.dir 仍用 8 罗盘枚举(bot 用满 8 向),客户端只发四基向。
  5. 房码 UX 范围:音频录入 4 位房码需数字语音资产(10 条)会击穿 60 句预算。裁定:协议 join.room 完整支持房码(服务端实现+单测),客户端 v1 只做快速匹配;音频录码 UX 列 roadmap(届时加数字整句资产)。
  6. 第 4 座无角色声音:bot 角色预算 3×8=24(任务书定死),而 4 人局第 4 座真人的呼喊无角色可用。裁定:座 3 呼喊=call_whistle 哨音(带 pan,<1s,R5 合规),bot 照常响应补位;哨音本身是有效求援信号,明示于 §3.3。
  7. bot 喊话落盘 sfx/(异例):任务书两处表述有张力——拥挤控制章"bot 喊话走 sfx 层空间化播放"与引擎章"voice 层同样支持 pan(bot 喊话用)"。裁定:喊话必须与旁白并发(R1/R2 的核心),voice 层单流做不到 → 走 sfx 层,引擎按 id 前缀分发故资产落 audio/sfx/npc_*(voice 管线生成不变);voice 层 opts.pan 能力同步提供但本作不使用。旁白 narrator 与 bot 同 speaker 的区分度风险(阿岩×male 旁白、小筝×female 旁白)按 abyss 先例标注"中",缓解=空间 pan + instruct 差异 + 语境(bot 只讲 1-2s 短喊话)。
  8. 巨兽 -2:任务书"突入=耐久-1"为默认口径;第 3 波起加入暴熊(-2)作为重威胁,给击杀优先级一个明确信号(重 loop/重倒地音可辨),数值与播报(breach_heavy)配套,不改核心形态。
  9. 失守与入榜:任务书"评级 S~C"隐含必完 5 波。裁定:耐久波内归零=失守终局(end_lose,无评级、不写 best,runs/totalKills 照记);胜利局才按 §3.6 评级写入 best——排行榜不被败局污染,失守有真话结算。
  10. bot 强度调参(§7.2 数值修订,协议字段不变):初版严格按 §7.2 公式(反应带 eta≤2.2+rng×1.2、无空转、旋风斩 eta≤3≥3 必放)实测零泄漏——多种子仿真 3 bot 水准局余耐久恒 10(S),甚至真人全程挂机 2 bot 独守也恒 10,§3.4"3 bot 水准余 6-9"与"协作必要性"(§1.6 风险③)落空。根因是吞吐超配:3 猎人 1.2 杀/s vs 峰值到达 0.67 杀/s,冷却 2.5s 不构成约束。裁定修订为:反应带 eta ≤ 2.0+rng×1.0;出手决策加 80% 空转概率(500ms tick 内愣神,等效出手周期 ~4.5s);旋风斩 eta≤2.5 ≥3 只且 60% 概率想起。调后 24 种子扫描(web/server/test/hunt-balance-scan.mjs):挂机局 17/24 失守或余 ≤3(6 场失守,mean 3.3,C/失守口径 ✓);3 bot 水准局 17/24 余 6-9(mean 7.5,A/B 为主 ✓);真人最优仍 23/24 满耐久 S("比 bot 强"空间保留 ✓)。bot"不失误"语义保留(只打有目标的弧),弱化的是反应速度与出手频率(拟人迟钝),不是命中率。

16. v2 修订记录(2026-09-19,10 人并发模拟迭代;依据与数据见 research/hunt-sim/)

迭代章程 research/hunt-sim/00-plan.md;v1 诊断 analysis/01-04;裁定 synthesis.md(S1-S9); 复测对比 metrics-v2.md(去留 6/10→10/10,弧错 22%→11%,N/S 可命中 63/69%→75/81%)。

  1. E3 修订(S1):WAVE 战斗态下滑恒出击(弧内无怪=空挥真话 atk_swish); 模态菜单入口收窄到波间休整窗(waveclear 后 8s)与 LOBBY/END。原「无目标下滑= 菜单」的语境折中废止——v1 实测多人战斗中误触菜单(最多单局 14 次),弹菜单+语音 播报双重打断是退游死因之一。上滑无目标=状态链维持不变。
  2. 冷却反馈(S2):冷却内被拦只在每个冷却窗首次给 error 震(连拦静默); 本窗被拦过则就绪时刻补一记 beat 轻震(无语音占用)。v1 实测全场 666 次乱滑连震。
  3. kill_band0 下架(S3):个人击杀 0 时状态链/结算链跳过「你还没开张」 (沉默优于羞辱;正向改写句列 TTS 批次)。0 杀玩家的去留反转(v2 P08:0杀→12杀) 是本项最直接证据。
  4. 看门狗重定义(S4):WAVE 内本波有出手/击杀 → 一级语音永不触发;一级降纯震; 语音闲置每局 ≤1 次;重教句只留在教学局。判定线=「耳朵在场」(等待是合法玩法)。
  5. 协作人声包(S5):①真人「扮演座位角色」(§3.3 既有设定)正式接线——杀熊/ 三连杀/旋风斩清 ≥3 时由该座角色播 kill/skill 句(服务端 creditKill/adjudicateSkill 放开 slot.bot 限制);开局 greet 覆盖全部有角色座位;②满编真人房呼喊无 bot 可应 → 2.5s 后由邻座真人角色代答 help_ack(服务端 pendingLines 兜底,v3 若加真人应答手势 则替换);③help_call/help_ack 客户端永不超时丢弃(氛围句才受 R2 ≤2s 上限); ④喊话全局预算 10s 窗 2→3 条。
  6. 后半平面第二线索(S6):身后 loop 在 ×0.6 响度之上叠加 750Hz 低通(音色 发闷 ≠ 响度发闷)。N/S 轴从单线索变双线索,模拟实测可命中 63/69%→75/81%,新手 自述「破案」。§8.3 的 pan 红线不变(方位仍由声像承载)。
  7. 难度与评级重构(S7):①波次量按座位缩放 waveCounts:4 人房 ×4/3(3 人房 原值,§3.4 表为 3 人基准);②第 3-5 波插入齐压拍 alignPincers:1-2 组跨座位 同种类怪重定时到同秒进内圈(数量与 eta 不变、种子确定性保持;齐压在 startWave 层应用,buildWaveScript 纯函数不动);③bot 让位窗:怪进内圈头 2s,bot 不与 该防区人类座位抢(mobYielded,只约束 bot——对真人不可见不拦截,避免「挥空 真话说谎」的暗墙;真人房的参与真空 v3 用分层匹配解决);④评级双轴 gradeForEx:S = 耐久 ≥9 且 ≥2 名猎人各 ≥6 个人击杀(单人带飞局上限 A)。
  8. 教学跳过保护(S8):作答步(T1/T2/T3)内下滑=答错处理,不再跳过教学; 跳过仅在 T0/T4/完成等待态(v1 实测 P04 教学局手滑跳过、记恨三局)。
  9. 状态链按变化播(S9):耐久档/波次档/猎人数/击杀档与上次播报一致的分段跳过; 全部无变化=仅 confirm 轻震(「营地固若金汤」复读投诉归零)。

v3 头号遗留(未修,如实登记):营地零损耗未破(v2 复测 18/20 局余 10)—— 4 人房 ×4/3 + 齐压拍不足以穿透专家房吞吐(单人最多 34/51 杀)。下一档参数与 分层匹配/保底猎物方案见 research/hunt-sim/report.md §5。