17 · 《深海回音》(abyss) — 深海救援叙事 RPG 设计文档
给开发的实现要点摘要
- 叙事模式(声命线范式,radio 同骨架):节点链 onComplete 串行 + seqToken 打断作废 + pendingChoice 缓存;复制
web/radio/ 结构起步,状态机 6 宏状态(INTRO/DIVE/COMMS/SURFACE/ENDING + MENU 覆盖层)。
- 手势零豁免:全部走全局默认映射(单击=继续/检查(搜索等待=发声呐脉冲,宪法 §5.1「检查」义,escape 先例)/跳句、双击=重听、左右滑=抉择、上滑=状态、下滑=模态菜单、长按=引擎快进)。
- 台词依据 17-abyss-voice-ids.md(148 句:双性别 127 + 平铺 NPC 21);NPC 水声电台滤波在资产侧 ffmpeg 带通(radio 先例),引擎零改动。
- 氧气=步进资源非实时倒计时:只在潜次边界与阈值跨越时播报(分档整句、账目真实);软失败=「被迫取消第四潜/单载」而非玩家死亡,结算链完整播出(含 800ms 手势死窗)。
- 声呐双通道:回波类信息音与语音绝不重叠(游戏层 sonarGate 空闲门,R1 规则 §6.2);并发声流 ≤2。
- 章程任务 N2(research/new8/00-program.md §2):单局 15-25 分钟、9 抉择点(实走 7-9)、4 结局、分支局部化。
- 断言清单住本文档 §9(radio §20 先例);13 号文档已登记指针(§21)。
1. 概述
- 一句话:你是深潜救援员,声呐里是被困海沟的潜艇「海燕号」——氧气在倒数,每次下潜都是抉择:先救谁、花多少气、留不留、上不上去。
- 题材(声音即世界):黑暗深海里视觉归零,声呐回波=空间、电台人声=生命、氧气=代价——「用耳朵救人」与纯音频载体天然同构。声呐脉冲/回波/管路敲击/船体呻吟是叙事本体,不是装饰。
- 单局:一次完整救援(一条抉择路径)20-22 分钟;四次下潜共享主干,分歧局部化在每潜内部;9 个抉择点(单局实走 7-9 个),4 结局。
- 核心循环:下潜(声呐搜索拍:单击发脉冲→回波→调度解读)→ 通讯(船员对话+抉择)→ 带人上浮 → 水面结算(氧气扣账+档位播报)→ 下一潜。跨潜积累氧气存量与船员生死/好感,最后一潜的氧气余量决定救援形态(双载/单载/取消),收队前 p9 决定你自己的心结。
- 与 radio 的差异点(骨架同、压力源不同):radio 零压力(口碑只涨不跌);abyss 引入氧气稀缺——但全部宽限化:无实时倒计时、无中途死亡、软失败只损失「机会」不损失「已有」、最优省气路径恰好全员生还(P4 友好默认)。
2. 状态机
2.1 状态列表
| 状态 |
内容 |
BGM |
guide.state |
INTRO |
开场链:甲板口播 + 一句规矩 + 今晚目标 |
bgm/deck |
explore |
DIVE |
下潜过程:下潜链(auto)→ 搜索等待(单击=发脉冲,声呐主导)→ 回波+接通 |
bgm/dive |
explore;搜索等待由 turn cue 承担 |
COMMS |
通讯叙事:船员对白链 + 抉择点 + 结果 |
bgm/comms |
explore;抉择点=choice |
SURFACE |
上浮结算:出水确认 + 氧气扣账/档位 + 补给(D2 后),自动链 |
bgm/deck |
settle |
ENDING |
结局链 + 尾声回响(epilogue),结算态 |
bgm/ending |
settle |
MENU |
模态覆盖层(任意叙事态下滑呼出,暂停一切链) |
bgm/deck(低响度淡入) |
menu |
2.2 转移图(文本)
- INTRO/DIVE/COMMS/SURFACE/ENDING 均为节点链驱动(radio playNode 模式);下潜链与上浮结算链
auto:true,COMMS 叙事节点链末等待单击(radio 实现核对 #1 同口径)。
- SURFACE 自动链 ≤15s:扣账句(d*_surf)→ 补给句(仅 D2 后)→ 档位句(跨档才播)→ 直接进下一 DIVE;第四潜位置由氧气门分三形态(§4.3)。
- 终局取消链与结局链入口处盖
_settleGraceUntil = now+800ms 手势死窗(dungeon H1 热修同款),窗内手势一律吞掉,结算链完整播出。
- MENU 打开时
guide.disarm() + 取消一切看门狗/自动链;关闭后重播当前节点(局面复述,radio closeMenu 先例)。
2.3 每状态手势映射(6+2 全覆盖,零豁免)
| 手势 |
INTRO |
DIVE(下潜/搜索) |
COMMS |
SURFACE |
ENDING |
MENU |
| 上滑 |
帮助+状态,随后重播当前段 |
帮助+状态(潜次+氧档),留在搜索等待 |
帮助+状态,随后重播当前节点 |
帮助+状态,自动链继续 |
帮助+状态(结局名+氧档) |
帮助(sys_help) |
| 下滑 |
模态菜单 |
模态菜单 |
模态菜单 |
模态菜单 |
模态菜单 |
关闭菜单 |
| 左滑 |
无效 → error 震+gd_invalid |
无效 → gd_invalid(喂无进展轨) |
抉择=左 |
无效 → gd_invalid |
无效 → gd_invalid |
无效 → error 震 |
| 右滑 |
无效 → gd_invalid |
无效 → gd_invalid(喂无进展轨) |
抉择=右;ASK 态=新救援 |
无效 → gd_invalid |
无效 → gd_invalid |
无效 → error 震 |
| 单击 |
播放中=跳过本句;链末=开始下潜 |
播放中=跳过本句;搜索等待=发一枚声呐脉冲 |
播放中=跳过本句(p* 不可跳);链末=继续 |
跳过本句(自动链) |
再来一局(新救援) |
循环切换选项 |
| 双击 |
重听当前段 |
重听上一条回波+其解读句(尚无回波=无效,首潜前零静默) |
重听当前节点台词(含抉择提示) |
重听结算链 |
重听结局链 |
确认执行(菜单约定覆盖重听) |
| 长按 |
引擎接管:旁白临时 1.7×(12 号 §2.2,叙事类不豁免) |
同左 |
同左 |
同左 |
同左 |
同左(快进菜单语音) |
| 长按松开 |
引擎接管:恢复 settings.speed |
同左 |
同左 |
同左 |
同左 |
同左 |
- 豁免登记:无。六个基础手势全部符合全局宪法默认语义——单击在搜索等待=「检查」(宪法 §5.1 原文即含检查,escape 检查房间同款);菜单走 §5.2 R3 模态约定(单击循环+双击确认)。
- ASK(存档询问态,radio 同款):单击=继续上次 / 右滑=新救援;上滑/下滑/左滑/双击=无效(error 震+gd_invalid)。
- 抉择 prompt(voice/p1..p9)播放中单击不可跳(PROMPT_RE 门)、左右滑缓存
pendingChoice 播完即生效(radio W2 契约照抄)。
- 继承 radio G5 跳过公平契约原文:首播必完整(p 首播不可跳 / 链末关键句保护 / ASK 恢复首句锁)、复播可即掐(锁不随复播重新武装、链中段句可跳、复播滑动照常预缓存)*;p* 复播(双击重听/看门狗复述)仍不可跳、句尾生效。
- 无效手势零静默:所有「无效」格均有 error 震 + gd_invalid(onceKey 同局限次,F1.4 idle-only:语音在播时跳过语音只发震)。
- 键盘通道:三通道并行,游戏代码零改动;操作提示句按
inputMode() 选 _k 变体资产(§7.3、voice-ids 集中分组)。
3. 抉择树
3.1 全局骨架(四潜共享主干,分歧局部化)
分支纪律:每潜内部分支、上浮时收敛到结算句 → SURFACE;跨潜只传标量(oxy、saved{}、stayer、5 个 flag),不生成组合节点。最坏路径与最好路径节点数同型(剧本 A 与剧本 C 深度相同)。
3.2 分潜结构(◆=抉择点,〔〕=条件差分)
3.3 分支局部化说明
- 跨潜状态全部是标量:
oxy(int)、saved(5 个 0/1)、stayer(null/chen/zheng)、flag 5 个(knowsPipe/hasLog/valve/spareGift/gaoPeace)+ p9 派生 bell。没有任何「潜 i 分支 × 潜 j 分支」组合节点。
- 条件差分全部是节点内选播(radio w1_say/w1_say2 先例):d2_pry_ok/slow(knowsPipe)、gao_c/gao_confess(hasLog)、p7 双/单形态(氧气门)、p7_chen/p7_zheng 与留别句(stayer)、ep_* 选播。树形不变。
- 树规模:148 句台词、约 70 个节点;任一路径实走 7-9 个抉择点(D4 取消路径少 p7/p8;单载右路少 p8)。
3.4 四结局达成条件
| 结局 |
条件 |
主题 |
开环钩子 |
| e1 海燕归钟 |
saved=5 且 p9=左 |
全员生还+船钟出水,告别完整 |
「明天,想再潜一次」 |
| e2 满载的黎明 |
saved=5 且 p9=右 |
人都救回来了,钟留在沟底 |
「半夜总听见钟在响」 |
| e3 最后一潜 |
saved<5 且 p9=左 |
没能都救回,但下去敲响了钟 |
「钟声替他们响了一声」 |
| e4 按规程上浮 |
saved<5 且 p9=右 |
规程之内,难过之外 |
「安静得像三年前那天」 |
- 尾声回响(P2 回响感):epilogue 逐人点名——小舟/老白/陈医官/小郑/船长各按「好感/生死」双线播(voice-ids EP 组),沟底一句按 bell 二选一;玩家每一潜的救与错过都被点名(radio ep_* 同款)。
4. 数值设计
4.1 变量
| 变量 |
类型 |
初值 |
说明 |
oxy(氧气格) |
int |
12 |
步进资源:只在事件点扣(下潜/抉择),无实时倒计时 |
saved |
map |
zhou:0 其余 0 |
小舟/老白/陈医官/小郑/高船长 各 0/1 |
stayer |
str |
null |
p5 后留守病舱者('chen'/'zheng') |
knowsPipe/hasLog/valve/spareGift/gaoPeace/bell |
bool |
false |
p1 左/p2 左/p4 左/p6 左/p8 左/p9 左 置位 |
supply |
bool |
false |
D2 上浮后应急瓶已发(全局唯一) |
endings{} / runs |
map/int |
— |
结局收集与重玩计数(存档展示用) |
4.2 抉择计分表(左=走心·多花气 / 右=克制·省气)
| 抉择 |
左(走心) |
右(克制) |
备注 |
| p1 听暗号/直接上 |
-1 气,knowsPipe=true |
0 |
左路获 D2 情报(下潜 EFF 的唯一免气左路) |
| p2 等日志/不等 |
-1 气,hasLog=true |
0 |
hasLog 兑现 D4 船长坦白差分 |
| p3 慢撬/快切 |
knowsPipe?0:-1 气 |
0 |
右路挂危机拍#1(火花虚惊,两路都活着) |
| p4 关阀门/直接走 |
-2 气,valve=true |
0 |
左路兑现在回响(干净海) |
| p5 先带医官/先带小郑 |
0(chen 上,stayer=zheng) |
0(zheng 上,stayer=chen) |
唯一无气差的双义抉择;stayer 决定 D4 单载差分 |
| p6 留备用瓶/约定来接 |
-2 气,spareGift=true(可触发干涸链) |
0 |
左路兑现在留守者存活回响 |
| p7 慢浮/快浮(双载) |
-2 气 |
0 |
右路兑现在 e1/e2 回响(医疗舱灯) |
| p7 带船长/带留守者(单载) |
0 |
0 |
另一人随海燕号滑入沟底(措辞克制) |
| p8 说出来/不问 |
0,gaoPeace=true |
0 |
hasLog 时 gao_confess 差分前置 |
| p9 取船钟/进医疗舱 |
需 oxy≥1,bell=true |
0 |
oxy<1 时左路封锁(g9_dry,不摆假选项) |
4.3 氧气经济(单位/消耗/宽限/软失败)
| 项 |
规则 |
| 单位 |
「格」(内部 int)。初始 12(叙事=双瓶满气,够四次往返);D2 上浮后应急瓶 +3(oxy_gain 播报,全局唯一),总预算 15 |
| 固定消耗 |
每次下潜开始扣 3(往返);D4 双载额外 +1(慢浮+减压成本按 p7 计) |
| 抉择消耗 |
见 §4.2;mid-dive 扣至负数一律 floor 到 0,不中断当前救援(人已挂上吊索,照常带上) |
| 阈值播报 |
分档整句(下表),只在跨档时播(挂上浮结算链尾);上滑 status 随时可查;oxy_crit 各播报位附 warning 震(radio G2 同款) |
| 第四潜氧气门 |
SURFACE(3) 结算时:oxy≥4 → 双载(带船长+留守者);oxy=3 → 单载(p7 谁上);oxy≤2 → 终局取消链(第四潜取消,船长与留守者随海燕号滑入沟底——措辞克制、零描写) |
| 宽限设计 |
① 学习期零惩罚:D1 两个左路合计 -2,恰好被 D2 后应急瓶 +3 兜底,教学潜永不亏局;② 到点不是死:软失败只损失「机会」(少带一人/少下一潜),已救上的人永不失去;③ 无实时倒计时、无 mid-dive 打断(P4 无高压);④ p9 左路是「氧气的礼物」——省下的气兑换终局抉择 |
| 干涸链(软失败结算) |
mid-dive floor 至 0 触发:dry_a →(当前救援照常完成)→ 上浮结算内 dry_b(归因真话:指向实际花掉最后两格的那个左选择)。链入口 800ms 手势死窗 |
氧气档位表(账目真实:每格取值下句义皆为真)
| 档 |
oxy 区间 |
整句 |
真实性核验 |
| full |
≥9(floor(oxy/3)≥3) |
「气瓶还足,救得动。」 |
≥3 潜气量 ✓ |
| ok |
6-8(floor=2) |
「氧气还够两潜。」 |
恰可下 2 潜 ✓ |
| low |
3-5(floor=1) |
「氧气告急,只够最后一潜。」 |
恰可下 1 潜 ✓ |
| crit |
0-2(floor=0) |
「氧气见底,必须上浮。」 |
mid-dive=必须上浮 ✓ / 水面=一潜都下不去 ✓ |
- 档位以
floor(oxy/3)(可下潜次数)划界而非绝对半数——句子说的就是判定用的(radio rep_low 教训内化:措辞与数值对得上)。
- 低氧混音签名:tier=low/crit 期间 DIVE/COMMS 垫
breath_loop(低响度呼吸声,SA3 循环);引擎无运行时滤波,BGM 闷化降级为该呼吸层(显式降级,不阻塞管线)。
4.4 船员好感/存活矩阵
| 船员 |
好感来源(bond) |
存活条件 |
回响句 |
| 小舟(声呐兵) |
p1 左 或 p2 左 |
恒活(D1 教学潜保底救上) |
ep_zhou_ok / ep_zhou_no |
| 老白(轮机长) |
p3 左 或 p4 左 |
恒活(D2 恒可成——预算数学保证,见 §9 验算) |
ep_bai_ok / ep_bai_no |
| 陈医官 |
p5 左(当场救上);或留守时 p6 左 |
p5 左即活;p5 右留守 → D4 双载或被选则活,否则失 |
ep_chen_ok / ep_chen_lost |
| 小郑(无台词角色) |
—(吊床上的沉默存在,radio 老主播「带子里只有电流声」先例) |
p5 右即活;p5 左留守 → D4 双载或被选则活,否则失 |
ep_zheng_ok / ep_zheng_lost |
| 高船长 |
p8 左(gaoPeace) |
D4 双载 或 单载选左则活;单载右/终局取消则失 |
ep_gao_peace / ep_gao_up / ep_gao_lost |
- 好感只影响回响选播(情绪差分),不影响结局判定——结局由 savedCount × p9 决定,账目单一可验算。
- 生死分支覆盖 3 人(陈医官/小郑/高船长),措辞全部克制(「滑进了沟底」「灯还亮着」),无临场描写;失败归因走干涸链/取消链的真话句。
4.5 氧气收支验算(设计期穷举,playtest 剧本 A-D 引用)
设 lefts = 前 3 潜左路气耗之和(p7/p9 不在前 3 潜):
- SURFACE(3) 时 oxy = 15 − 9(基础)− lefts = 6 − lefts → 双载 ⟺ lefts≤2;单载 ⟺ lefts=3;取消 ⟺ lefts≥4。
- 双载收队 oxy_end = 2 − lefts(p7 右)或 0 −(lefts−2)(p7 左,floor 0)→ p9 左可用 ⟺ lefts≤1。
- 单载收队 oxy_end = 3 − lefts = 0(lefts=3)→ p9 左恒封锁 → 单载路径必 e4。
- 取消收队 oxy_end = 6 − lefts ∈ {2,1,0}(lefts=4,5,≥6)→ lefts≤5 时 p9 左可用 → e3。
- 前 3 潜恒可完成的预算证明:D1 最大支出 5(12→7);D2 最大支出 6(7→1)后应急瓶 +3(→4)≥3 ✓;D3 恒可下(最差 4→1,p6 左 floor 0 走干涸链)✓。教学潜与机舱潜永不被氧气卡死(P4)。
5. 音频三层映射
5.1 BGM(状态→曲目,Mureka instrumental,4 首 ≈ $0.12)
| 状态 |
曲目 |
切换 |
Mureka prompt 草稿(英文,seamless loop) |
| INTRO/SURFACE/MENU |
bgm/deck |
开局淡入 800ms;MENU 呼出低响度淡入 500ms |
"Night sea surface from a rescue ship deck, sparse cello and low piano over gentle waves, distant rigging creak and engine hum, melancholic but purposeful, no vocals, seamless loop, 60-90 seconds" |
| DIVE |
bgm/dive |
crossfade 800ms 进;接通 COMMS 淡至 comms 600ms |
"Deep ocean descent ambience, dark ambient drone with a slow sonar-like pulse, immense water pressure, distant whale-like tones, subtle tension, no vocals, seamless loop, 60-90 seconds" |
| COMMS |
bgm/comms |
crossfade 600ms;上浮淡回 deck |
"Underwater radio contact scene, warm muted piano over a deep water drone, faint hydrophone static, intimate and quietly hopeful, no vocals, seamless loop, 60-90 seconds" |
| ENDING |
bgm/ending |
p9 结果链播完后淡入 1500ms |
"Dawn on the sea after a deep sea rescue, warm strings and soft piano, exhausted hope and quiet triumph, no vocals, seamless loop, 60-90 seconds" |
bgm=0 时全部静默(引擎约定);menu 用 deck 同曲(省 1 首,海面场景同构);共性后缀(10 号 §8)照 radio 追加。
5.2 SFX 清单(SA3=Stable Audio 3 / SYN=程序合成;one-shot 真峰值 ≤-3dBFS;amb 循环由游戏层 buffer.loop 实现,radio phone_ring 先例)
| id |
用途 |
来源 |
prompt(英文)/ 合成参数 |
sfx/sonar_ping |
你发出的声呐脉冲(搜索单击) |
SYN |
1.4→0.9kHz 正弦 chirp 220ms,指数衰减,-6dBFS(回波家族统一音头) |
sfx/echo_metal_l / _r |
钢板回波(左/右声像;「金属回波=海燕号」承诺音) |
SA3 |
"Sonar echo returning from a steel submarine hull, resonant metallic ping with slow decay, panned slightly left(→right), underwater, 2 seconds" |
sfx/echo_debris |
碎石回波(D2 机舱外) |
SA3 |
"Sonar echo returning from an underwater rubble and debris field, diffuse granular reverberation, 2 seconds" |
sfx/echo_groan |
船体呻吟(D3 预警/D4 滑坡前奏,可变增益复用) |
SA3 |
"Stressed submarine hull groaning deep underwater, long metallic moan under immense pressure, 4 seconds" |
sfx/pipe_knock |
管路敲击暗号(老白 SOS) |
SYN |
三短三长三短固定节拍金属敲击(节拍精确可复现、断言可数) |
sfx/link_beep |
电台接通 |
SYN |
双音上行 0.3s |
sfx/static_burst |
通讯静电/断续 |
SA3 |
"Shortwave radio static burst with faint ghost of a distorted voice, 2 seconds" |
sfx/amb_deep |
深潜底噪 loop |
SA3 |
"Deep ocean ambient loop, low pressure hum, distant current wash, occasional far creak, seamless loop" |
sfx/amb_deck |
甲板底噪 loop(风+浪+缆绳) |
SA3 |
"Night ship deck ambience, wind, gentle waves against hull, distant rigging creak and engine hum, seamless loop" |
sfx/breath_loop |
低氧呼吸 loop(仅 low/crit 档垫,混音签名) |
SA3 |
"Slow scuba regulator breathing loop, calm but slightly labored, underwater, seamless loop" |
sfx/spark_flash |
D2 危机拍:切割火花+氢气虚惊 |
SA3 |
"Underwater cutting torch sparks with a brief muffled gas pop, 2 seconds" |
sfx/valve_close |
重阀关闭(p4 左) |
SA3 |
"Heavy submarine valve wheel shutting, metal rotation clunk and water seal, 2 seconds" |
sfx/landslide |
D4 危机拍:海底滑坡轰鸣(前置 2s 渐强) |
SA3 |
"Underwater landslide rumble, rolling sediment and rocks, ominous low roar building, 4 seconds" |
sfx/surf_splash |
破水出水(每潜上浮) |
SA3 |
"Diver breaking through the sea surface, splash and one gasp, 2 seconds" |
sfx/ascent_chime |
出水确认音 |
SYN |
上行三音琶音 0.4s |
sfx/bell_toll |
船钟(p9 左 payoff 音) |
SA3 |
"Old ship brass bell, single clean toll with warm resonance, 3 seconds" |
sfx/ui_confirm / ui_menu |
菜单/确认(程序合成兜底) |
SYN |
同全局先例 |
- 预警窗纪律:D2 火花与 D4 滑坡均前置 2s 起渐强(L2),danger 签名与音效同窗(radio C5 刹车先例);D4 另叠
danger 震循环(每遍间隔 ≥400ms)。
- 承诺兑现绑定:dv1_metal 教「金属回波=钢板」后,凡叙事提到船身/找到船的节点必播 echo_metal*;D2 找人必播 pipe_knock(§6.3 清单 + §9 断言)。
5.3 Voice 划分(详见 17-abyss-voice-ids.md)
| 组 |
声部 |
落位 |
数量 |
| 潜航员(你)DIVER |
双性别(female=Serena / male=Uncle_Fu + DIVER instruct 常量) |
voice/female|male/ |
30 句 |
| 调度/系统/向导 DECK |
双性别(female=Vivian / male=Dylan + DECK instruct 常量) |
voice/female|male/ |
97 句 |
| 船员 NPC ×4 |
平铺单音色(小舟=Serena / 老白=Uncle_Fu / 陈医官=Vivian / 高船长=Eric),不做双性别 |
voice/ 根(平铺回退命中)+ 电台滤波转码 |
21 句 |
- 船员 ≤4 个单音色约束满足;玩家自己的声音跟随全局
settings.voice;调度是向导人设(L4 角色化系统声,radio 导播同型)。
- 合计 148 句(≤170 GPU 预算 ✓,含
_k 键盘变体 11 对);音频文件 = 127×2 + 21 = 275 条(×2 格式 = 550 文件)。
6. 声呐双通道设计(本作核心差异层)
6.1 引擎能力边界(对照 web-engine-api.md)
| 能力 |
引擎现状 |
方案 |
| voice 运行时 EQ/滤波 |
❌(voice 链无滤波插入点) |
资产侧转码滤波(radio §6.2 先例):ffmpeg highpass+lowpass+压缩器 逐船员定档(§5.3/voice-ids) |
| sfx 循环 |
❌ 即发即弃 |
游戏层 buffer.loop=true 持句柄(amb_deep/amb_deck/breath_loop),切换档位时停(radio _ringSrc 先例) |
| 语音 duck 垫乐 |
✅ 内置(duck 20%,300ms) |
直接依赖;BGM 不再手工让路 |
| sfx vs voice 互让 |
❌ sfx 总线独立,无 duck |
游戏层 sonarGate 空闲门(§6.2 R1):信息类回波只在 !audio.isVoicePlaying() 时播出,否则挂队列表、voice onComplete/句间轮询补发 |
| sfx 声像 |
❌ 运行时无 pan API |
资产侧 pan(echo_metal_l/_r 两条,escape 先例);其余方向信息由调度语音明说(「左前方」) |
| 变速不变调 |
✅ SoundTouch |
直接依赖(长按 1.7× / 2.2× 视障档) |
6.2 通道仲裁规则(并发声流 ≤2 约束)
- 通道定义:声呐通道 = sfx 层的脉冲/回波/敲击/呻吟/环境 loop;通讯通道 = voice 层(调度+船员+你)。BGM 是第三层背景(voice 播时引擎自动 duck)。
- R1 回波不叠语音:信息类回波(echo_*、pipe_knock、groan 渐强段)与任何 voice 播放区间零重叠——sonarGate 只在 voice idle 时放行,在播则排队到句间空隙(≥600ms);玩家主动脉冲只在搜索等待(voice 恒静)受理,按构造不重叠。
- R2 声呐主导段(DIVE 搜索等待):前景=脉冲+回波余音+amb_deep,BGM=dive 曲低响度;voice 只出调度短句(解读句),且解读句固定在回波结束后接播(回波→静默一拍→解读,给耳朵留定位时间)。
- R3 常驻脉冲退位:语音在播时,环境内的周期性声呐元素(母船远程脉冲垫)降 -6dB 或暂停(游戏层 gain 控制),不消失(保持声场存在感,A2 无静默死局)。
- R4 危机拍优先:D2/D4 危机音(spark/landslide)为即发即弃 sfx,可叠在 amb 上;danger 签名同窗;当前 voice 句播完后危机链才插续(radio C5 同款;呼救类短句若必须抢时,走 sfx 层不占 voice)。
- R5 回波可重听:搜索等待双击=重听「上一条回波+其解读句」(P1 关键线索可重听);COMMS 双击=重听当前节点(radio 同款)。
- 声流账:任意时刻 ≤2 条前景流(voice 串行 1 + 声呐信息音 1),BGM/amb 为背景层——满足 ASA ≤2 注意流约束。
6.3 教学承诺清单(dungeon「铁器=楼梯」教训:每句承诺的机制必须真实存在且可感知)
| 教学句 |
承诺 |
兑现点(断言锁定) |
| dv1_metal「金属回波,钢板。听见这个,就是海燕号的船身」 |
金属回波=找到船 |
D1 找到/D4 接近指挥舱均播 echo_metal*;全剧本任何「船身」节点零漏播 |
| dv1_teach「单击,发一枚脉冲」(+gd_ping1) |
单击=脉冲 |
搜索等待单击恒出 sonar_ping(非跳句、非无效);无超时不惩罚 |
| b_goal「五个人。你的双瓶,够下四潜」 |
5 人/4 潜 |
基础消耗恰 3 格×4=12(§4.5 验算);剧本 A 恰 4 潜走完 |
| b_rule「气不够一潜,人就必须上浮」 |
氧气门 |
取消门恰在 oxy<3(§4.3/§4.5);剧本 C/D 实证 |
| d1_surf「往返,扣三格气」 |
每潜扣 3 |
每次下潜开始扣 3(账目断言) |
| d1_code「记住这个敲法」 |
敲管=老白的信号 |
D2 搜索以 pipe_knock 引导找到机舱 |
| oxy_gain「应急瓶接上了,多三格」 |
+3 |
恰一次、恰 +3、恰在 D2 上浮后 |
7. 向导层接入
7.1 状态签名 earcon / turn cue
| 时机 |
向导动作 |
说明 |
| INTRO 进入 |
guide.state('explore') |
叙事态签名 |
| 搜索等待武装(下潜链末) |
guide.turn({haptic:true})(无语音) |
turn 签名+confirm 震=「轮到你发脉冲」;首次前 dv1_teach 已口播 |
| 每个抉择点 p* 起播 |
guide.state('choice') |
选项句本身即 turn cue(W2 契约零插播) |
| SURFACE 进入 |
guide.state('settle') |
结算签名 |
| ENDING 进入 |
guide.state('settle') |
同上 |
| MENU 打开 |
guide.state('menu') |
菜单签名 |
| D2/D4 危机拍 |
guide.state('danger') |
音效前置 2s 渐强同窗(全游戏仅两处) |
| 无效手势 |
guide.error({voice:'gd_invalid', onceKey}) |
error 震 + full 档语音,idle-only(F1.4) |
- earcon 词表:只用全项目统一 8 音(menu/explore/battle/choice/settle/danger/turn/nudge),零新增;battle 不用。
7.2 看门狗双轨(radio F1 + dungeon E0-1 教训:乱按也要被抢救)
无操作轨(guide watchdog,任何手势复位;两级不同句、用尽即停、永不惩罚):
| 等待点 |
full 档 |
standard 档 |
级别内容 |
| 搜索等待无脉冲 |
[10, 25] |
[10, 25](onEscalate 游戏层补播) |
① gd_ping1 ② gd_ping2(必须不同句);两级后仅 amb+余音 |
| INTRO/COMMS/SURFACE 链末等待 |
[25, 50] |
[13, 30] |
① gd_continue ② gd_again(storyline F1.1 同款) |
| 抉择点 p* 播完无操作 |
[25, 50] |
[25, 50] |
重播当前 p* 提示句(13 号 §16 先例;空点单击=重挂计时) |
| ENDING 结算等待 |
[25, 50] |
[13, 30] |
gd_continue / gd_again |
无进展轨(游戏层计时,dungeon E0-1 ②同型;仅挂搜索等待与 COMMS 链末两个可饿死点):
| 项 |
规则 |
| 进展定义 |
节点推进 / 发出脉冲 / 抉择结算。无效手势(滑错、空点)不计进展——无操作轨被它们复位、无进展轨不被它们复位,乱按 96s 也必被抢救 |
| 阈值 |
60s → gd_prog1;120s → gd_prog2;用尽即停(每等待点一轮) |
| 有真实进展 |
全程零 prog 播出(不误伤正常玩家,dungeon 断言同款) |
| 双轨去重 |
两轨短句内容同级交叉登记;同一等待点先播过 gd_ping* 则无进展轨跳过同义级 |
- 向导插播一律
queue:true,绝不顶掉在播对白;error/watchdog 类语音 idle-only(在播则跳过且过期丢弃,F1.4)。
- 单句语音看门狗(资产缺失兜底):30s 超时且
isVoicePlaying()===false 才自动续链,长句续约不掐(radio N1 先例照抄)。
7.3 键盘变体机制(PC 键盘玩家)
- 运行时按
gesture.inputMode()(settings.input auto/touch/key)选 _k 变体资产:key → voice/<gender>/<id>_k.*,touch → 无后缀版;auto 跟随最近使用通道(keydown 后即切 key)。_k 缺失回退无后缀版(资产侧保证成对,check_all_assets 校验)。
- 变体清单(11 对,集中分组见 voice-ids §G0):gd_brief / gd_continue / gd_again / gd_ping1 / gd_ping2 / sys_help / sys_menu / sys_skip / sys_continue_ask / dv1_teach / p1。
- 抉择提示 p2..p9 措辞统一「向左滑/向右滑」;键盘玩家由 p1_k 与 sys_help_k 完成首次绑定(左=←,右=→),后续提示语义不变。
- 启动遮罩文案引擎自理(「按空格开始」/「轻触开始」),游戏零改动。
7.4 继承 radio 三轮验证机制(照抄不重设计)
| 机制 |
来源 |
落点 |
| 帮助链去重(同等待点第 2 次上滑只震+nudge) |
radio G1 |
_helpSeen 按等待点键控 |
| 状态链顺序「状态在前、帮助在后」 |
radio G6 |
prog_dN → oxy 档 → sys_help |
| 空点确认轻震(不可跳句上单击补 beat [8]) |
radio G4 |
p*/链末句/F4 锁各 tap 屏蔽分支 |
| oxy_crit 播报位附 warning 震 |
radio G2 |
全部 crit 出口(含上滑复听) |
| 菜单报名游戏侧排队零截断 |
radio 实现修复 #3 |
_menuQueue 排水 |
stop() 先 seqToken++ 作废在途链 |
radio 实现修复 #6 |
同款 |
| 新局清 choiceArmed/pendingChoice |
radio 实现修复 #7 |
newRun() |
| 长按误报无效(longpress 全状态合法) |
radio 实现修复 #2 |
仅 left/right(ASK 另含 up/down/doubletap)报无效 |
8. 存档设计
8.1 进度 data 结构(PUT /api/progress {game:'abyss'})
- 写入时机:每潜 DIVE 进入、每个抉择结算后、SURFACE 进入、ENDING 进入、菜单「保存并回大厅」。
- 断点续玩:读档 → sys_continue_ask(_k)(单击=继续上次 / 右滑=新救援);继续=恢复 phase+node+全部数值并重播当前节点链=一句话局面复述(L5);重进 ≤5s 可玩;恢复首句受 F4 跳句锁(radio G5 例外条款)。
- summary 格式:进行中
第N潜·<舱段> · 氧气K格 · 结局X/4;收队 救援收队·<结局名> · 结局X/4(大厅卡片直接显示)。
9. playtest 断言清单(登记 13 号 §21 指针;settings.set({guide:'off'}) 纯玩法验证,向导行为住 guide.test)
关键路径(剧本 A:全右+左p9 → e1,≤70 次手势):
- 遮罩点按 → INTRO 链(b_open 起,voice 层有播放记录)→ 链末单击 → DIVE(1) 下潜链 auto → 搜索等待武装(turn 事件 + amb_deep 循环起播)。
- 搜索单击 → sonar_ping → 回波静默一拍 → echo_metal_l → dv1_metal(承诺音)→ link_beep → COMMS(1):z1_a/b/knock → p1 右 → p2 右 → 上浮:surf_splash+ascent_chime → d1_surf → oxy=12-3=9 → oxy_full 播出(账目断言)。
- DIVE(2):脉冲 → echo_debris+pipe_knock → dv2_found → bai_a/b → p3 右(danger 签名前置 2s 与 spark_flash 同窗断言)→ p4 右 → d2_surf → d2_supply → oxy_gain(6→9,恰一次)。
- DIVE(3):脉冲 → echo_groan → dv3_groan → chen_a/b → p5 右 → p6 右 → d3_surf(oxy=6,ok 档)。
- 氧气门:6≥4 → DIVE(4) 双载:滑坡危机拍(landslide 前置 2s 渐强 + danger 签名 + danger 震)→ gao_a/b → p7 右 → gao_c → p8 右 → d4_surf → oxy=2(crit 档+warning 震)。
- 签收:g9_in → g9_knot → p9 左(oxy=2≥1 可用)→ d9_bell + bell_toll → ENDING(e1):e1_a/b + ep_lead + ep 链 → 结算单击 → 新救援回 INTRO。
边界断言:
- 四结局可达(含氧气逐点验算):剧本 B(同 A 但 p9 右)→ e2;剧本 C(p1左 p2左 p4左,余右):D1 后 oxy=7(ok)/D2 后 2→supply→5(gain+low 档)/D3 后 2(crit)→ 氧气门走终局取消链(dv4_none→gao_final 完整播出)→ p9 左(2≥1)→ e3(saved=3);剧本 D(p1左 p4左,余右):D1 后 8(ok)/D2 后 3→supply→6(ok)/D3 后 3(low)→ 单载形态(p7 按 stayer 选 p7_chen|p7_zheng)→ p7 左=带船长 → 留守者留别句(chen_last|d4_stay_lost)→ p8 右 → oxy_end=0 → p9 左封锁:g9_dry 播出后自动右 → e4(saved=4)。各局 oxy 逐检查点与 §4.5 公式一致。
- 氧气账目真实:每次扣减后播出的档位句与 floor(oxy/3) 桶一致;上滑 status 链顺序 prog_dN → oxy 档 → sys_help(G6);supply 全局恰一次;剧本 E(p2左 p3[无knows]左 p4左 p6左)mid-dive floor 至 0 → dry_a/dry_b 播出且当前救援者照常救上(人已挂上吊索不失去)。
- 双通道仲裁:全剧本转写断言——echo_*/pipe_knock/groan 信息音播出时刻与任一 voice 播放区间零重叠(sonarGate 排队语义:晚于在播句结束);搜索等待单击恒=脉冲(sonar_ping 计数=1,无跳句无 error);双击搜索等待=回波+解读句同序重播;语音在播时 amb_deep 持续、远程脉冲垫降 -6dB(R3)。
- 教学承诺兑现(§6.3 清单逐条):dv1_metal 后所有「船身」节点 echo_metal* 零漏播;D2 找到机舱前 pipe_knock 恒在;b_rule 与取消门一致(剧本 C 证明);b_goal 四潜=剧本 A 恰 4 潜;每潜起播扣 3 断言。
- 看门狗双轨:搜索等待快进 10s→gd_ping1、25s→gd_ping2(两级 id ≠,绝不逐字重播;两级后仅 amb);乱按 96s(每 2s 注入一个无效滑动):无操作轨零播出(被手势复位)+ 无进展轨 60s→gd_prog1、120s→gd_prog2(乱按饿不死);有真实进展(单击脉冲推进)全程零 prog 播出;COMMS 链末 25s/50s → gd_continue/gd_again;p* 播完 25s/50s 重播 p* 两次后静默;
guide=off 全程零定时器零向导事件。
- 键盘变体:settings.input='key' 会话播出 gd_brief_k/sys_help_k/gd_ping1_k/dv1_teach_k/p1_k 且对应无后缀版零播出;'touch' 反之;'auto':keydown 后下一句用 _k。
- 中断复述:杀进程重进(存档 node=bai_b)→ sys_continue_ask → 单击 → 重播该节点链(恢复首句不可跳,第二句起可跳);右滑=新救援(runs 口径同结算重开)。
- 结算链死窗(H1 内化):终局取消链/干涸链/e* 结局链开播后 800ms 内注入在途 tap(mock 补派 touchend+300ms 同款序列)→ 手势被吞、链完整有序播出、结算出口手势照常。
- pendingChoice:p* 播放中左右滑 → 播完立即生效(不丢、不重复、连滑取最后一次)。
- p 不可跳*:p* 播放中单击 → 不跳句(PROMPT_RE 门)+ beat 轻震(G4)。
- idle-only:向导 gd_* 在对白在播时跳过且不占 onceKey(F1.4);queue 句排在当前句后零截断。
- 菜单:下滑开菜单 → 上滑帮助 → 双击「回到水下」→ phase/node 不变、当前节点重播;单击循环顺序 = [回到水下, 重新开始这次救援, 保存并回大厅];确认回大厅 → sys_menu_lobby 播出且 PUT/localStorage 有最新 data。
- 资产缺失:屏蔽任意 voice 资产 → 30s 看门狗自动续链到结局不卡死;NPC 滤波资产缺失回退原声可播。
- 数字规范:prog_/oxy_/gd_* 全部整句字面量,静态审计无运行时拼接碎片。
- 低氧混音签名:tier=low/crit 期间 breath_loop 在播、升档/收队即停。
失败即不通过:任何等待 >5s 无声(静默死局);无效手势零反馈;回波与语音重叠;结局计数与 §3.4 不符;氧气档位句与 oxy 值不符。
10. 节奏曲线(每次下潜目标时长)
| 段 |
内容 |
目标时长 |
设计目标 |
| 开场+下潜链 |
甲板简报+第一潜下水+搜索 |
1-1.5 min |
首输入 <60s(开场链 ~20s 链末单击,或 ~40s 搜索首脉冲);规矩一句讲完(P4) |
| D1 找船 |
教学潜:脉冲/回波/接通/2 抉择 |
4-4.5 min |
首个正反馈 ≤3min(~2.5min 金属回波+接通小舟=「看见它了」);两抉择条条有出路;左路气耗被补给兜底=学习期零惩罚 |
| D2 机舱 |
老白:撬/切+阀门抉择 |
3.5-4 min |
首个危机拍(火花,前置 2s);补给+3 兑现宽限;暖拍(热粥,P4) |
| D3 病舱 |
生死抉择+回波预警 |
3.5-4 min |
船体呻吟埋 D4 险;留守约定=段落边界(P3 中断友好:每潜一个完整存档颗粒) |
| D4 指挥舱 |
滑坡高潮+氧气门三形态 |
4-4.5 min |
紧张峰值:danger+滑坡渐强+双人竞速;生死分支收敛 |
| 终局+结局 |
p9 心结+结局链+逐人回响 |
2.5-3 min |
氧气余量兑换终局抉择;ep 点名(P2 回响);开环钩子拉下一局 |
- 合计 ≈ 20-22 min(15-25 达标);每 30-60s 一个反馈颗粒(回波/解读短句/结果句/档位句),无沉默尴尬期(P3)。
- 难度曲线 = 道德复杂度(教学二选一 → 情报投资 → 生死取舍 → 自己的心结),操作复杂度恒定(永远二选一+单击脉冲)——P4「规则一遍听懂」由恒定操作面保证。
11. 自检清单(策划交付自验;☐ = 待开发/测试轮填)
| # |
硬约束/教训 |
落地 |
✓ |
| 1 |
FTUE 首输入 <60s |
开场链 ~20s 链末单击;~40s 搜索首脉冲(§10) |
☑ |
| 2 |
FTUE 首个正反馈 ≤3min |
~2.5min 金属回波+接通小舟(§10 D1) |
☑ |
| 3 |
学习期零惩罚 |
D1 左路 -2 被 D2 后 +3 兜底;搜索无超时惩罚;D1/D2 恒可完成(§4.5) |
☑ |
| 4 |
失败三问归因+归因真话律 |
干涸链 dry_b 指向实际左选择;gao_final/d4 留别句克制不假安慰;§4.4 无假归因句 |
☑ |
| 5 |
资源账目真实(radio rep_low 教训) |
氧档以 floor(oxy/3) 划界、每档句义逐格为真(§4.3 表);补给恰一次 +3;扣 3 恰每次下潜 |
☑ |
| 6 |
手势宪法 6 手势默认语义零豁免 |
§2.3 全覆盖;单击搜索=「检查」(宪法 §5.1+escape 先例);菜单 §5.2 模态约定 |
☑ |
| 7 |
长按显式登记 |
无豁免:长按=引擎快进(12 号叙事类不豁免),§2.3 在案 |
☑ |
| 8 |
向导:签名/turn cue/看门狗两级不同句 |
§7.1/§7.2;gd_ping1≠gd_ping2;gd_continue→gd_again |
☑ |
| 9 |
看门狗双轨(dungeon E0-1/radio F1 教训) |
无操作轨+无进展轨(§7.2);乱按 96s 必被抢救;有进展零打扰 |
☑ |
| 10 |
插播 queue 不顶对白;纠错 idle-only 过期丢弃 |
§7.2(F1.4 契约) |
☑ |
| 11 |
死亡/失败结算链完整(dungeon H1 教训) |
终局取消链/干涸链/结局链 800ms 手势死窗;已救者永不失去(§2.2/§4.3) |
☑ |
| 12 |
教学承诺兑现(dungeon「铁器=楼梯」教训) |
§6.3 承诺清单 7 条逐条绑兑现点+断言 |
☑ |
| 13 |
单次播报 ≤3 选项 |
全部抉择恒 2 选项;菜单 3 项循环 |
☑ |
| 14 |
并发声流 ≤2 + 双通道仲裁 |
voice 串行+声呐信息音互斥(R1-R5,§6.2);断言零重叠 |
☑ |
| 15 |
earcon ≤7、统一词表、语义靠语音 |
只用统一 8 音中 7 个(battle 不用),零新增 |
☑ |
| 16 |
台词一句一文件 ≤40 字、数字分档整句、无运行时拼接 |
voice-ids 全表 ≤30 字(最长 p8=30);prog/oxy 分档整句;句内数字写死 |
☑ |
| 17 |
多音字规避/同 instruct 常量/无语速词 |
voice-ids 头部+文末自查(重写→补、脏/晃/闷标注试听) |
☑ |
| 18 |
PC 键盘变体(提示句集中+标注) |
11 对 _k 变体集中分组(voice-ids §G0);inputMode() 运行时选择 |
☑ |
| 19 |
P1:可打断/重听(含回波)/status key/不当白痴 |
跳句+双击(回波可重听 R5)+上滑状态链+成功零补救教学 |
☑ |
| 20 |
P2:3 分钟见效/结局回响 |
~2.5min 首个改变世界的时刻;ep 逐人点名+bell 差分;e1 巧妙路径(p1左+p3左 省气取钟) |
☑ |
| 21 |
P3:3 分钟颗粒/中断复述/单手 |
一潜=3.5-4.5min 完整段落+边界自动存档;重进重播当前节点;全手势免视单手 |
☑ |
| 22 |
P4:一遍懂/容错/无高压倒计时/不骂人 |
一句规矩;无实时倒计时(步进资源+跨档才播);软失败零死亡;NPC 句 ≤24 字+逗号停顿 |
☑ |
| 23 |
抉择树 4 结局可走通验算 |
§4.5 公式+§9 剧本 A-D 逐 oxy 检查点(e1:lefts≤1+双载;e2:lefts≤2;e3:lefts=4-5+取消;e4:单载 lefts=3 或取消右) |
☑ |
| 24 |
单局 15-25 min |
§10 曲线 ≈20-22 min |
☑ |
| 25 |
分支不爆炸(radio 纪律) |
跨潜仅标量(oxy/saved/stayer/6 flag);~70 节点固定深度(§3.3) |
☑ |
| 26 |
台词 ≤170、船员 ≤4 单音色 |
148 句(双 127+NPC 21)/4 个船员音色(voice-ids 账目) |
☑ |
| 27 |
引擎边界诚实 |
§6.1 能力表:滤波/loop/声像/互让全写明资产侧或降级方案 |
☑ |
| 28 |
存档带 summary、断点续玩 |
§8:data+summary 格式、≥5 恢复、局面复述 |
☑ |
批 1 教训内化确认(5 条全落地)
| 教训 |
本作机制 |
断言 |
| 教学承诺必须兑现 |
§6.3 七条承诺清单(金属=钢板/单击=脉冲/四潜/氧气门/扣三格/敲管/补给) |
§9「教学承诺兑现」块 |
| 看门狗双轨 |
§7.2 无操作轨+无进展轨;无效手势不复位进展轨 |
§9「看门狗双轨」块 |
| 档位措辞真实 |
§4.3 档位=floor(oxy/3) 可下潜次数,句义逐格为真 |
§9「氧气账目真实」块 |
| 失败结算链完整不被打断 |
800ms 手势死窗盖取消链/干涸链/结局链;seqToken 作废在途链 |
§9「结算链死窗」块 |
| PC 键盘操作提示 |
11 对 _k 变体+inputMode() 选择+集中分组标注 |
§9「键盘变体」块 |