策划轮: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
2861 lines
212 KiB
Python
2861 lines
212 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""双性别语音资产管线(R1):为 5 个 web 游戏生成 male/female 两版旁白 voice。
|
||
|
||
约定:
|
||
- 台词表从各游戏已有 gen 脚本原样提取(storyline/escape 的原始表在 app/src/<flavor>/gen/,
|
||
本脚本只做只读引用,不改 app/)。
|
||
- storyline 只生成旁白 + 系统音(NARR* 角色)的双性别版本;角色台词(林晚/猎狗/小满等)
|
||
不在本脚本范围内,沿用 web/storyline/audio/voice/ 平铺原文件。
|
||
- 输出 staging wav: tools/gen_voice_dual_wav/<game>/<gender>/<id>.wav
|
||
--convert 后落地: web/<game>/audio/voice/<gender>/<id>.{ogg,m4a}
|
||
(原有平铺 voice/*.ogg 保留不动,等引擎切换后由后续轮次清理。)
|
||
- 键盘变体(P1 路线 a,research/platform/02-input-parity.md §4.3):KEY_LINES 只登记
|
||
含操作词的句子(key 集合 ⊆ 主集合),复用主表同 id 的 instruct/speaker;
|
||
staging wav: tools/gen_voice_dual_wav/<game>/<gender>/key/<id>.wav
|
||
--convert 后落地: web/<game>/audio/voice/<gender>/key/<id>.{ogg,m4a}
|
||
(引擎 audio.js 在生效输入模式=键盘时前置该目录,触屏主资产零改动。)
|
||
生成建议:--only-variants 只跑变体(--check/--convert 对变体始终生效)。
|
||
|
||
质量控制:
|
||
- 每条 assert 时长 > 0.3s、峰值 > 0.05;统一峰值归一 0.89。
|
||
- 台词 > 40 字按句拆分生成再拼接(句间 0.12s 静音),避免长句吞字。
|
||
- 短句/数字类(文本 ≤ 2 字)同 instruct 一整批连续生成,减少 prosody 漂移。
|
||
- --check 对比同句两性时长,相差 3 倍以上判异常(删掉异常 wav 后重跑本脚本即可)。
|
||
|
||
用法(GPU 必须串行):
|
||
source env.d/tts.sh
|
||
flock /home/xsl/SoundGame/.gpu.lock .venv-tts/bin/python tools/gen_voice_dual.py --game simon --gender both
|
||
.venv-tts/bin/python tools/gen_voice_dual.py --game all --check # 无需 GPU
|
||
source env.d/android.sh && .venv-tts/bin/python tools/gen_voice_dual.py --game all --convert
|
||
"""
|
||
import argparse
|
||
import os
|
||
import re
|
||
import subprocess
|
||
import sys
|
||
|
||
os.environ.setdefault("HF_HOME", "/home/xsl/SoundGame/models/hf")
|
||
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
|
||
|
||
ROOT = "/home/xsl/SoundGame"
|
||
STAGING = os.path.join(ROOT, "tools", "gen_voice_dual_wav")
|
||
SPLIT_LIMIT = 40 # 超过 40 字拆句
|
||
GAP_SEC = 0.12 # 拼接句间静音
|
||
PEAK_NORM = 0.89
|
||
BATCH_SHORT = 16 # 数字/短句一批
|
||
BATCH_LONG = 6
|
||
|
||
# ---------------------------------------------------------------- 音色分配
|
||
# 游戏 × 性别 -> speaker。说明见 docs/audio/asset-manifest.md。
|
||
# Ryan(英语母语音色)经冒烟测试未采用:项目已有中文发音投诉,男声统一用
|
||
# 中文母语的 Uncle_Fu;测试样本在 tools/samples/ryan_zh_*.wav 供人工试听。
|
||
SPEAKERS = {
|
||
"storyline": {"male": "Uncle_Fu", "female": "Vivian"},
|
||
"escape": {"male": "Uncle_Fu", "female": "Serena"},
|
||
"simon": {"male": "Uncle_Fu", "female": "Serena"},
|
||
"rhythm": {"male": "Uncle_Fu", "female": "Vivian"},
|
||
"space": {"male": "Uncle_Fu", "female": "Serena"},
|
||
"rpg": {"male": "Uncle_Fu", "female": "Serena"},
|
||
# radio 默认 speaker 仅作兜底;双性别行按 VOICE_SPK["radio"] 逐句覆盖(HOST/PROD 双配对)
|
||
"radio": {"male": "Uncle_Fu", "female": "Serena"},
|
||
"dungeon": {"male": "Uncle_Fu", "female": "Serena"},
|
||
# abyss 默认=DECK 调度(多数行);DIVER 行按 VOICE_SPK["abyss"] 逐句覆盖(radio 同型)
|
||
"abyss": {"male": "Dylan", "female": "Vivian"},
|
||
"detective": {"male": "Uncle_Fu", "female": "Serena"},
|
||
# cipher 默认=WIND 北风/系统(多数行);OP 报务员行按 VOICE_SPK["cipher"] 逐句覆盖
|
||
"cipher": {"male": "Dylan", "female": "Vivian"},
|
||
# hunt 旁白双性别(23-hunt-voice-ids.md 头注);bot 喊话固定音色在 HUNT_NPC
|
||
"hunt": {"male": "Uncle_Fu", "female": "Serena"},
|
||
# teahouse 旁白双性别(20-teahouse-voice-ids.md 头注:male=Uncle_Fu/female=Serena)
|
||
"teahouse": {"male": "Uncle_Fu", "female": "Serena"},
|
||
# keeper 默认=SHORE 岸台/系统(多数行);KEEPER 守塔人行按 VOICE_SPK["keeper"] 逐句覆盖
|
||
"keeper": {"male": "Dylan", "female": "Vivian"},
|
||
# bridge 旁白双性别(22-bridge-voice-ids.md 头注:舰载系统音);NPC 恒定音色在 BRIDGE_NPC
|
||
"bridge": {"male": "Uncle_Fu", "female": "Serena"},
|
||
}
|
||
|
||
# instruct 对:(male, female)。None 表示两性别共用同一 instruct。
|
||
def _pair(m, f=None):
|
||
return (m, f if f is not None else m)
|
||
|
||
# ---------------------------------------------------------------- storyline
|
||
_SL_NARR = _pair("低沉醇厚的中年男声旁白,冷静、缓慢,带着末世废墟的苍凉感",
|
||
"冷静低沉的女声旁白,语速缓慢,带着末世废墟的苍凉感")
|
||
_SL_WARM = _pair("低沉醇厚的中年男声旁白,由紧张转为温暖,结尾带希望",
|
||
"女声旁白,由紧张转为温暖,结尾带希望")
|
||
_SL_COLD = _pair("低沉醇厚的中年男声旁白,冷漠、空洞,越说越轻",
|
||
"女声旁白,冷漠、空洞,越说越轻")
|
||
_SL_EPIC = _pair("低沉醇厚的中年男声旁白,悲壮,尾音下沉",
|
||
"女声旁白,悲壮,尾音下沉")
|
||
|
||
STORYLINE_LINES = [
|
||
# ---- 系统语音 ----
|
||
("help", _SL_NARR, "操作说明。单击屏幕:继续剧情。双击:重听刚才的台词。向上滑:听这段说明和当前进度。向下滑:呼出菜单,菜单里可以重新开始。当旁白说“请选择”的时候,向左滑或者向右滑,做出你的决定。选择无法撤销。"),
|
||
("status1", _SL_NARR, "当前进度:第一幕,城南地铁站附近。你的目标:活着离开这片废墟,前往北区的广播塔,寻找妹妹林晨的下落。"),
|
||
("status2", _SL_NARR, "当前进度:第二幕,酸雨笼罩的街区与断桥。你的目标:渡过江水,抵达广播塔。小心,猎狗的人,就在附近。"),
|
||
("status3", _SL_NARR, "当前进度:第三幕,广播塔下。你的目标:把警报发出去,找到林晨。这是最后一段路了。"),
|
||
("menu", _SL_NARR, "菜单。向左滑:重新开始整个故事。向右滑,或者单击:回到故事。向上滑:听操作说明。"),
|
||
# ---- 选择提示 ----
|
||
("p1", _SL_NARR, "请选择。向左滑:先检查背包里的收音机。向右滑:先摸黑寻找出口。"),
|
||
("p2", _SL_NARR, "请选择。向左滑:钻进旁边的通风管道。向右滑:躺进路边的尸体堆里装死。"),
|
||
("p3", _SL_NARR, "请选择。向左滑:循着哭声过去看看。向右滑:不去管它,直接去北区。"),
|
||
("p4", _SL_NARR, "请选择。向左滑:带上小满一起走。向右滑:留下食物,独自上路。"),
|
||
("p5", _SL_NARR, "请选择。向左滑:走桥下的污水涵洞。向右滑:爬桥上悬着的钢索。"),
|
||
("p6", _SL_NARR, "请选择。向左滑:交出坐标,保命要紧。向右滑:拒绝他,想办法周旋。"),
|
||
("p7", _SL_NARR, "请选择。向左滑:追上去,警告避难所。向右滑:自己逃命,越远越好。"),
|
||
("p8", _SL_NARR, "请选择。向左滑:用公开频道广播,让全城都听见。向右滑:用加密频段,只发给避难所。"),
|
||
# ---- 第一幕 ----
|
||
("n00_intro", _SL_NARR, "大停电后的第三十天,城市陷入彻底的黑暗。没有电,没有网络,只有收音机里偶尔闪过的沙沙声,像垂死者的呼吸。你是林晚,一名前急救员。在这个故事里,你用声音活下去。请记住:单击屏幕,继续剧情;双击,重听上一句;向上滑,听你的状态和帮助;向下滑,呼出菜单。当我说“请选择”的时候,向左滑,或者向右滑,做出你的决定。选择一旦做出,就无法回头。现在,单击屏幕,睁开眼睛。"),
|
||
("n01_wake", _SL_NARR, "后脑一阵钝痛,嘴里全是铁锈味。你在废弃的地铁站里醒来,四周黑得像沉在水底。背包还压在身下,手电筒却不知去向。远处滴水的声音,一下,一下,像某种倒计时。"),
|
||
("n04_exit", _SL_NARR, "你扶着潮湿的墙,一步一步往外摸。第五十步,脚尖踢到一个硬物——是一支手电,还剩半格电。光柱劈开黑暗的那一瞬,你看见墙上用红漆刷着一行大字:别去北区。"),
|
||
("n05_signal", _SL_NARR, "就在这时,背包侧袋里的收音机,沙沙声忽然变得清晰。一个平稳的女声,一遍又一遍地重复着:"),
|
||
("n06_whistle", _SL_NARR, "你刚走上街面,黑暗里忽然响起一声口哨。接着是第二声,第三声,从不同的方向,把你围在中间。有人的手电光,扫过你的脸。"),
|
||
("n08_vent", _SL_NARR, "你一矮身,钻进了通风管道。铁皮贴着脊背,窄得几乎无法呼吸。身后传来咒骂和铁棍敲击管道口的声音,越来越近,又渐渐远去。十分钟后,你从两条街外的井口爬出来,肺里像塞满了沙子。"),
|
||
("n09_dead", _SL_NARR, "你屏住呼吸,把自己埋进路边冰冷的尸体堆里。手电、罐头、半瓶水,被他们一样一样摸走。有人踢了你一脚,你纹丝不动。就在他们离开时,你听见一句不该听见的话——“北区那个陷阱,今晚就收网。”"),
|
||
# ---- 第二幕 ----
|
||
("n10_rain", _SL_NARR, "酸雨开始下了。街面上升起细密的嘶嘶声,像无数条小蛇在游。雨幕那头,隐约传来一阵哭声——细细的,是个孩子。"),
|
||
("n11_child", _SL_NARR, "哭声来自一间塌了一半的便利店。一个小男孩抱着膝盖坐在货架底下,身边躺着一个再也不会醒来的女人。他抬起头,脸上全是灰,小声说:“我叫小满。妈妈说,数到一千,她就会醒。我已经数到……数到好多个一千了。”"),
|
||
("n13_leave", _SL_NARR, "你把仅剩的一罐罐头放在他身边,转身走进雨里。身后,孩子重新开始数数:一……二……三……你告诉自己,别回头。千万别回头。"),
|
||
("n14_ignore", _SL_NARR, "哭声被你甩在身后,越来越远,最后混进雨声里,再也听不见了。你走得很快,快得像在逃跑。快一点,再快一点。你对自己说,只要到了北区,这一切就都值了。"),
|
||
("n15_bridge", _SL_NARR, "两个小时后,江水拦住了去路。跨江大桥断成两截,桥身斜插进黑沉沉的江面。要去广播塔,只剩两条路:桥下的污水涵洞,黑得看不见底;或者,桥上悬着的钢索,在风里荡来荡去。"),
|
||
("n16_culvert", _SL_NARR, "涵洞里,污水没到胸口,又冷又黏,带着腐烂的甜味。走到一半,水面下有什么东西,擦着你的腿滑了过去。你没有叫出声,只是走,一步,一步,直到看见洞口那点灰白的天光。"),
|
||
("n16b_culvert_c", _SL_NARR, "你让小满骑在肩上,自己蹚进没到胸口的污水里。又冷又黏,带着腐烂的甜味。走到一半,水面下有什么东西擦过你的腿,小满吓得一抖,你抬手按住他的膝盖:“数数。”他小声数起来,一,二,三……数到一百七,你们看见了洞口的天光。"),
|
||
("n17_cable", _SL_NARR, "钢索比想象中更滑。酸雨把它泡得发黏,你每挪一步,整根钢索就晃一下。江风从断桥的缺口灌进来,像有无数只手在水底下拽你的脚。你不往下看。你只知道,前面就是北岸。"),
|
||
("n17b_cable_c", _SL_NARR, "钢索比想象中更滑。小满趴在你背上,一声不吭,两条小胳膊勒得你生疼。走到一半,钢索猛地一沉,你听见身后钢丝崩断的脆响。“闭眼。”你说。然后你用尽全身力气,向前,向前,直到膝盖磕上北岸的石头。"),
|
||
# ---- 第三幕 ----
|
||
("n20_convoy", _SL_NARR, "猎狗的车队朝北区开走了,探照灯在雨幕里划出一道道口子。你蹲在原地,胃里一阵一阵地泛酸。晨晨在北区。而刚才,是你,亲手把狼,引到了她的门口。"),
|
||
("n22_fight", _SL_NARR, "你往后退了半步,忽然笑了:“坐标在我脑子里。杀了我,你什么都拿不到。”猎狗愣了半秒。就是这半秒,你抓起一把沙土扬在他脸上,转身就跑。子弹擦着肩膀打进墙里,火辣辣地疼。但你在跑,你在跑——活着的感觉,从来没有这么清楚过。"),
|
||
("n23_tower", _SL_NARR, "广播塔就立在头顶,红色的信号灯在雨里一闪一闪,像一颗还在跳动的心脏。塔底的中控台居然还能用。只要爬上去,你就能接入城市广播网,把警报发给北区的每一个人。问题是——用哪个频道。"),
|
||
# ---- 结局 ----
|
||
("e1_dawn", _SL_WARM, "加密频道那头沉默了三秒。然后,一个你等了三十天的声音响了起来:“姐?姐!是你吗?”天亮之前,避难所的救援队打开了大门。猎狗的人,在北区的高墙下溃散了。你抱着晨晨,听见广播塔里,重新响起了音乐。后来人们说,这座城市,是从一个女人的声音开始,重新活过来的。——好结局:黎明。感谢你,陪林晚走完了这条路。单击屏幕,可以回到故事开始的地方。"),
|
||
("e2_price", _SL_EPIC, "你赶在车队前面,撞进了避难所的大门。“关掉广播!关灯!猎狗来了——!”那一夜,北区守住了。探照灯熄灭的时候,晨晨从人群里扑出来抱住你,才发现你胳膊上的血,已经把半边袖子浸透了。坐标是你交出去的,命,是你抢回来的。你赢了,用一条胳膊的代价。——结局:代价。单击屏幕,重新开始。"),
|
||
("e3_alone", _SL_COLD, "你逃了。一路向南,没有回头。三天后,收音机里关于北区的广播,停了。又过了七天,你在一个废弃的加油站里,听见最后一个频段,也变成了沙沙声。你活下来了。只是从此以后的每一个夜里,你都会想起那声口哨,和你报出坐标时,自己发抖的声音。——坏结局:孤声。单击屏幕,重新开始。"),
|
||
("e4_static", _SL_EPIC, "公开频道,把所有人都引来了——幸存者,还有猎狗。塔顶的风很大,你看见山下火把连成的长龙,也看见避难所方向亮起的防御火光。猎狗的刀抵上来的时候,你对着麦克风笑了:“听见了吗,晨晨?姐姐的声音,全城都听见了。”信号中断了。但那晚之后,北区,再没有人投降。——结局:静默。单击屏幕,重新开始。"),
|
||
("skip_hint", _SL_NARR, "单击可跳过旁白。"),
|
||
# ---- 向导层(docs/design/14-guide-layer.md,schemes §1.5 定稿全文)----
|
||
("gd_continue", _SL_NARR, "轻触屏幕,继续。"),
|
||
("gd_invalid", _SL_NARR, "这个操作在这里用不上。"),
|
||
# ---- 向导层 round2(docs/design/14-guide-layer.md「round2 v1.1」,synthesis §3 定稿全文)----
|
||
("gd_brief", _SL_NARR, "单击继续剧情。请选择的时候,左右滑动。"),
|
||
("gd_again", _SL_NARR, "还在吗?单击继续。"),
|
||
|
||
]
|
||
|
||
# ---------------------------------------------------------------- escape
|
||
# R2 重设计(docs/design/01):全游戏同一 instruct 常量(00 文档 §3.2,不含语速词)。
|
||
_ESC = _pair("低沉平稳的男声,冷静、克制,带一点神秘感",
|
||
"沉稳平静的女声,冷静、克制,带一点神秘感")
|
||
|
||
ESCAPE_LINES = [
|
||
# ---- 开场引导 G0-G7 ----
|
||
("g0_intro", _ESC, "黑暗。你在废弃的地下设施里醒来,什么都想不起来。你必须找到出路。"),
|
||
("g1_move", _ESC, "先活动一下。朝任意方向滑一下,走一小步。"),
|
||
("g1_done", _ESC, "很好,你迈出了第一步。"),
|
||
("g2_wall", _ESC, "这个房间不大,四面都是墙。再滑两下,试试碰碰墙。"),
|
||
("g3_left", _ESC, "跟着我指的路走。向左滑。"),
|
||
("g4_down", _ESC, "对。再向下滑。"),
|
||
("g5_inspect", _ESC, "听到水声了吗?单击一下,仔细检查这个房间。"),
|
||
("g5_key", _ESC, "你摸到了一把钥匙!"),
|
||
("g6_doubletap", _ESC, "钥匙能开锁。双击,是把物品用出去的用法。现在,双击试试。"),
|
||
("g6_done", _ESC, "对,就是这样。接下来,靠你自己了。"),
|
||
("g7_goal", _ESC, "找到能用这把钥匙打开的东西。需要帮助时,在原地双击。"),
|
||
# ---- 引导纠错与跳过 ----
|
||
("guide_wrong_up", _ESC, "不是这个方向。向上滑。"),
|
||
("guide_wrong_down", _ESC, "不是这个方向。向下滑。"),
|
||
("guide_wrong_left", _ESC, "不是这个方向。向左滑。"),
|
||
("guide_wrong_right", _ESC, "不是这个方向。向右滑。"),
|
||
("guide_wrong_gesture", _ESC, "不是这个操作。照我说的做。"),
|
||
("guide_blunt_up", _ESC, "手指贴着屏幕,向上推一下。"),
|
||
("guide_blunt_down", _ESC, "手指贴着屏幕,向下推一下。"),
|
||
("guide_blunt_left", _ESC, "手指贴着屏幕,向左推一下。"),
|
||
("guide_blunt_right", _ESC, "手指贴着屏幕,向右推一下。"),
|
||
("guide_offpath", _ESC, "先跟我走。"),
|
||
("guide_skip", _ESC, "跳过引导,直接开始自由探索。"),
|
||
("reopen_prompt", _ESC, "上滑,重新听一遍引导。单击,直接开始。"),
|
||
# ---- 卡关三级提示 + 导航 ----
|
||
("stuck_ask", _ESC, "需要帮助吗?"),
|
||
("stuck_key_1", _ESC, "铁锈味最重的地方,值得仔细看看。"),
|
||
("stuck_key_2", _ESC, "去西南角的储物间,单击检查,找到钥匙。"),
|
||
("stuck_key_3", _ESC, "跟我说的方向走,去西南角的储物间。"),
|
||
("stuck_cabinet_1", _ESC, "钥匙就在你身上。它能打开某一把锁。"),
|
||
("stuck_cabinet_2", _ESC, "去东边的铁柜房,双击,用钥匙打开铁柜。"),
|
||
("stuck_cabinet_3", _ESC, "跟我说的方向走,去铁柜所在的房间。"),
|
||
("stuck_box_1", _ESC, "保险丝属于电箱。有电流声的地方,就有电箱。"),
|
||
("stuck_box_2", _ESC, "去西北角的电箱房,双击,把保险丝装进电箱。"),
|
||
("stuck_box_3", _ESC, "跟我说的方向走,去电箱所在的房间。"),
|
||
("stuck_gate_1", _ESC, "电已经通了。该去找那扇铁门了。"),
|
||
("stuck_gate_2", _ESC, "去东南角的大门,双击,打开它,离开这里。"),
|
||
("stuck_gate_3", _ESC, "跟我说的方向走,去大门所在的房间。"),
|
||
("nav_up", _ESC, "向上滑。"),
|
||
("nav_down", _ESC, "向下滑。"),
|
||
("nav_left", _ESC, "向左滑。"),
|
||
("nav_right", _ESC, "向右滑。"),
|
||
# ---- 房间描述 ----
|
||
("room_storage", _ESC, "一间储物间。货架上堆满杂物,角落里传来水滴声。"),
|
||
("room_cabinet", _ESC, "这个房间里,立着一个铁柜。"),
|
||
("room_power", _ESC, "这个房间的墙上,有一只电箱。"),
|
||
("room_gate", _ESC, "面前,是一扇沉重的铁门。"),
|
||
# ---- 用时播报 4 段整句 ----
|
||
("time_band1", _ESC, "你逃出来了,用时不到两分钟。了不起!"),
|
||
("time_band2", _ESC, "你逃出来了,用时不到五分钟。"),
|
||
("time_band3", _ESC, "你逃出来了,用时不到十分钟。"),
|
||
("time_band4", _ESC, "你逃出来了,用时超过十分钟。"),
|
||
# ---- 保留句(文本沿用,按新 instruct 重录) ----
|
||
("wall", _ESC, "那边是墙,换个方向。"),
|
||
("start_room", _ESC, "你站在设施中央的房间里。滑动移动,单击检查,双击使用物品。"),
|
||
("found_key", _ESC, "你蹲下身在储物架的角落里摸索,指尖碰到一个冰凉的金属物件——是一把钥匙!钥匙到手了。"),
|
||
("inspect_cabinet_locked", _ESC, "这个房间里立着一个铁柜,柜门上挂着一把锁。也许,有什么钥匙能打开它。"),
|
||
("unlock_cabinet", _ESC, "钥匙插进锁孔,缓缓转动。咔哒一声,柜门开了。柜子深处,躺着一枚保险丝。保险丝到手了。"),
|
||
("inspect_box_dead", _ESC, "墙上是一只电箱,箱盖敞开着,里面的保险丝座空空如也。没有电,这里的大门永远打不开。"),
|
||
("box_fixed", _ESC, "电箱运转正常,电流的嗡鸣声平稳而持续。"),
|
||
("fix_box", _ESC, "你把保险丝用力按进卡座。火花一闪,嗡鸣声响起——头顶的线路恢复供电了!"),
|
||
("inspect_gate", _ESC, "面前是一扇沉重的铁门。门边的电子锁一片漆黑,没有任何反应。它需要电力。"),
|
||
("inspect_gate_ready", _ESC, "电子锁的指示灯亮了,发出微弱的绿光。大门已经通电。双击,打开它,离开这里。"),
|
||
("escape", _ESC, "你扳动开关。电机轰鸣,沉重的铁门缓缓升起,刺眼的光线涌了进来。你眯起眼睛,向前迈出了第一步。自由了。你逃出来了。"),
|
||
("use_fail", _ESC, "这里没有用得上东西的地方。换个房间试试,或者先单击检查一下周围。"),
|
||
("inv_empty", _ESC, "你摸了摸身上,什么也没有。"),
|
||
("inv_key", _ESC, "你身上带着一把钥匙。"),
|
||
("inv_fuse", _ESC, "你身上带着一枚保险丝。"),
|
||
("inv_both", _ESC, "你身上带着一把钥匙和一枚保险丝。"),
|
||
("replay", _ESC, "黑暗再次合拢。你回到了中央的房间。这一次,你会更快。"),
|
||
("again", _ESC, "单击屏幕,再来一次。下滑,打开菜单。"),
|
||
("empty_1", _ESC, "房间里空空荡荡,只有你自己的回声。"),
|
||
("empty_2", _ESC, "你伸出手,摸到的只有冰冷粗糙的墙壁。"),
|
||
("empty_3", _ESC, "除了远处的水滴声,这里什么都没有。"),
|
||
# ---- 菜单与帮助 ----
|
||
("help_ops", _ESC, "滑动,在房间之间移动。单击,检查房间,或者重听房间的声音。双击,使用物品,或者查看背包。"),
|
||
("menu_open", _ESC, "菜单。"),
|
||
("menu_restart", _ESC, "重新开始。"),
|
||
("menu_home", _ESC, "回大厅。"),
|
||
("menu_back", _ESC, "返回游戏。"),
|
||
("skip_hint", _ESC, "单击可跳过旁白。"),
|
||
# ---- 向导层 round3(docs/design/14-guide-layer.md「round3 v1.2」,synthesis §3 定稿全文)----
|
||
("gd_next_fuse", _ESC, "保险丝到手。接下来,去找电箱。"),
|
||
# ---- 向导层 round4(docs/design/14-guide-layer.md「round4 v1.3」,synthesis §3 定稿全文)----
|
||
# H1:目标句后按房间图接播目标房间方位句(移动坐标系:up/down/left/right 滑动方向即方位)。
|
||
("gd_room_l", _ESC, "左面的房间。"),
|
||
("gd_room_r", _ESC, "右面的房间。"),
|
||
("gd_room_u", _ESC, "上面的房间。"),
|
||
("gd_room_d", _ESC, "下面的房间。"),
|
||
# ---- escape-state round2(docs/design/25-escape-map-flow.md §4.1 B1/B2/B3,台词与草案逐字一致)----
|
||
# B1(F1):撞墙方位句(陈述式非教学腔),wall 播完后接播,同向 10s 限频。
|
||
("wall_dir_l", _ESC, "左边是墙。"),
|
||
("wall_dir_r", _ESC, "右边是墙。"),
|
||
("wall_dir_u", _ESC, "上边是墙。"),
|
||
("wall_dir_d", _ESC, "下边是墙。"),
|
||
# B2(F2):目标名+方位一体句,替换三处 gd_room_* 接播(原句保留作异常路径兜底)。
|
||
("gd_cabinet_dir", _ESC, "铁柜,在右面的房间。"),
|
||
("gd_box_dir", _ESC, "电箱,在左面的房间。"),
|
||
("gd_gate_dir", _ESC, "大门,在右面的房间。"),
|
||
# B3(F3):无进展 150s 活跃计时器的进度重述(stage=cabinet/box/gate,key 阶段不走本通道)。
|
||
("gd_prog_1", _ESC, "钥匙已经到手。找到能用它的锁。"),
|
||
("gd_prog_2", _ESC, "铁柜已经打开。电还没有通。"),
|
||
("gd_prog_3", _ESC, "电已经通了。去找那扇大门。"),
|
||
|
||
]
|
||
|
||
# ---------------------------------------------------------------- simon
|
||
# R2 重设计(docs/design/02):全游戏同一 instruct 常量,轮次/成绩全部整句化。
|
||
_SIMON = _pair("平静、清晰,像一个耐心的游戏主持人")
|
||
_SIMON_ROUNDS = ["第一", "第二", "第三", "第四", "第五", "第六", "第七", "第八", "第九", "第十",
|
||
"第十一", "第十二", "第十三", "第十四", "第十五", "第十六", "第十七", "第十八", "第十九", "第二十"]
|
||
SIMON_LINES = [
|
||
# ---- 交互式教学 T0-T7 ----
|
||
("t0_welcome", _SIMON, "欢迎来到音序回响。先认识六种声音。"),
|
||
("t0_goal", _SIMON, "我会演奏一串声音,请你记住顺序,原样复现。"),
|
||
("t1_up", _SIMON, "向上滑,是这个声音。"),
|
||
("t2_down", _SIMON, "向下滑,是这个声音。"),
|
||
("t3_left", _SIMON, "向左滑,是这个声音。"),
|
||
("t4_right", _SIMON, "向右滑,是这个声音。"),
|
||
("t5_tap", _SIMON, "单击,是这个声音。"),
|
||
("t6_double", _SIMON, "双击,是这个声音。"),
|
||
("t_try", _SIMON, "你试试。"),
|
||
("t_ok", _SIMON, "对了。"),
|
||
("t_wrong_up", _SIMON, "不是这个,向上滑试试。"),
|
||
("t_wrong_down", _SIMON, "不是这个,向下滑试试。"),
|
||
("t_wrong_left", _SIMON, "不是这个,向左滑试试。"),
|
||
("t_wrong_right", _SIMON, "不是这个,向右滑试试。"),
|
||
("t_wrong_tap", _SIMON, "不是这个,单击试试。"),
|
||
("t_wrong_double", _SIMON, "不是这个,双击试试。"),
|
||
("t_blunt_up", _SIMON, "手指贴着屏幕,向上推一下。"),
|
||
("t_blunt_down", _SIMON, "手指贴着屏幕,向下推一下。"),
|
||
("t_blunt_left", _SIMON, "手指贴着屏幕,向左推一下。"),
|
||
("t_blunt_right", _SIMON, "手指贴着屏幕,向右推一下。"),
|
||
("t_blunt_tap", _SIMON, "用指尖,轻轻点一下屏幕。"),
|
||
("t_blunt_double", _SIMON, "用指尖,快速点两下屏幕。"),
|
||
("t7_ready", _SIMON, "六种声音都记住了。后面的序列,会越来越长。"),
|
||
("t7_retry", _SIMON, "答错可以消耗机会重听。向上滑,可以随时重听。"),
|
||
("t_skip", _SIMON, "跳过教学,直接开始。"),
|
||
# ---- 轮次播报(整句,round_01..round_20 + 兜底) ----
|
||
*[(f"round_{i + 1:02d}", _SIMON, f"{w}轮,听好了。") for i, w in enumerate(_SIMON_ROUNDS)],
|
||
("round_more", _SIMON, "新的一轮,听好了。"),
|
||
# ---- 成绩播报 6 段整句 ----
|
||
("score_band1", _SIMON, "一轮都没坚持下来。别灰心。"),
|
||
("score_band2", _SIMON, "你坚持了三轮以内。"),
|
||
("score_band3", _SIMON, "你坚持了五轮左右。"),
|
||
("score_band4", _SIMON, "你坚持了将近十轮。"),
|
||
("score_band5", _SIMON, "你坚持了十轮以上,很厉害。"),
|
||
("score_band6", _SIMON, "你坚持了十五轮以上,大师级!"),
|
||
# ---- 流程句 ----
|
||
("your_turn", _SIMON, "轮到你了。"),
|
||
("chances_out", _SIMON, "重听机会用完了,小心。"),
|
||
("retry_use", _SIMON, "错了。用一次机会,再听一遍。"),
|
||
("relisten", _SIMON, "再听一遍。"),
|
||
("replay", _SIMON, "单击屏幕,再来一局。"),
|
||
("rules_prompt", _SIMON, "上滑,重听规则。下滑,打开菜单。"),
|
||
("rules", _SIMON, "上行音,向上滑。下行音,向下滑。左边的音,向左滑。右边的音,向右滑。一声轻响,单击。两声轻响,双击。"),
|
||
("gameover", _SIMON, "游戏结束。"),
|
||
# ---- 反馈短句 ----
|
||
("correct", _SIMON, "答对了!"),
|
||
("wrong", _SIMON, "错了。"),
|
||
("chance_plus", _SIMON, "机会加一。"),
|
||
("new_record", _SIMON, "新纪录!"),
|
||
# ---- 菜单 ----
|
||
("menu_open", _SIMON, "菜单。"),
|
||
("menu_restart", _SIMON, "重新开始。"),
|
||
("menu_home", _SIMON, "回大厅。"),
|
||
("menu_back", _SIMON, "返回游戏。"),
|
||
("skip_hint", _SIMON, "单击可跳过旁白。"),
|
||
# ---- 向导层(docs/design/14-guide-layer.md,schemes §1.5 定稿全文)----
|
||
("gd_relisten", _SIMON, "需要的话,向上滑可以重新听一遍序列。"),
|
||
# ---- 向导层 round2(docs/design/14-guide-layer.md「round2 v1.1」,synthesis §3 定稿全文)----
|
||
# round3 G5 重录(14 号文档「round3 v1.2」):双击改回纯音色、重听改绑上滑,
|
||
# 机会经济句按裁定书新文案一字不改重录;教学链 t7_retry 同步手势口径。
|
||
("gd_economy", _SIMON, "记不住就向上滑,重新听一遍。免费机会有两次,用完要扣一次机会。"),
|
||
# ---- 向导层 round3(docs/design/14-guide-layer.md「round3 v1.2」,synthesis §3 定稿全文)----
|
||
("gd_clear", _SIMON, "漂亮,过了。"),
|
||
("gd_record", _SIMON, "破纪录了。"),
|
||
# ---- 向导层 round4(docs/design/14-guide-layer.md「round4 v1.3」,synthesis §3 定稿全文)----
|
||
# H2:轮次开场占用预告(序列播放后、轮到你提示前;重听键与答案音共用词表的根治形态)。
|
||
("gd_occ_up", _SIMON, "这一轮,向上滑是作答。"),
|
||
("gd_occ_dt", _SIMON, "这一轮,双击是作答。"),
|
||
("gd_occ_both", _SIMON, "这一轮,向上滑和双击都是作答。"),
|
||
# H3:使用时如实报余量(替换主动重听路径的旧「用完了」绝对句)。
|
||
("gd_chances_left1", _SIMON, "免费重听还剩一次。"),
|
||
("gd_chances_left0", _SIMON, "免费重听用完了。之后重听会花一次机会,别怕,慢慢来。"),
|
||
# ---- 状态查询(research/simon-polish round1,S1/S3/S4;input 阶段长按=问状态,
|
||
# 13 句全部整句预生成、数字分档,禁运行时拼接;不加 guide 前缀——三档 guide 全可用,
|
||
# 属玩家主动查询而非向导插播)----
|
||
("status_len_short", _SIMON, "这一轮很短。"),
|
||
("status_len_mid", _SIMON, "这一轮不长不短。"),
|
||
("status_len_long", _SIMON, "这一轮挺长。"),
|
||
("status_len_xlong", _SIMON, "这一轮很长,稳住。"),
|
||
("status_prog_start", _SIMON, "刚开头,一个还没对。"),
|
||
("status_prog_early", _SIMON, "刚答了个开头。"),
|
||
("status_prog_half", _SIMON, "答了一半左右。"),
|
||
("status_prog_late", _SIMON, "就剩最后几个了。"),
|
||
("status_free2", _SIMON, "免费重听还有两次。"),
|
||
("status_free1", _SIMON, "免费重听还有一次。"),
|
||
("status_chance2", _SIMON, "免费用完,机会还剩两次。"),
|
||
("status_chance1", _SIMON, "免费用完,机会还剩一次。"),
|
||
("status_out", _SIMON, "免费和机会都用完了,答错就结束。"),
|
||
|
||
]
|
||
|
||
# ---------------------------------------------------------------- rhythm
|
||
# 鼓手模式重构(docs/design/24-rhythm-voice-ids.md):41 句,全表同一 instruct
|
||
# 常量;向导层 9 句 gd_* 已在库沿用不重录(不在本表)。
|
||
_RHY = _pair("低沉醇厚的男声,像节奏游戏主持人,平稳有力",
|
||
"活力清晰的年轻女声,像节奏游戏主持人,情绪饱满但不夸张")
|
||
|
||
RHYTHM_LINES = [
|
||
# ---- W 组 · 开场与流程 ----
|
||
("welcome", _RHY, "欢迎来到节拍行者。今天你是乐队的鼓手,整面屏幕都是你的鼓。"),
|
||
("welcome_back", _RHY, "欢迎回来,鼓手。准备好了就开始。"),
|
||
("tut_done", _RHY, "很好,演出开始。"),
|
||
("tut_skip", _RHY, "跳过教学,直接开始。"),
|
||
("mid_song", _RHY, "过半了,保持。"),
|
||
# ---- Z 组 · 分区教学与区名 ----
|
||
("tut_map", _RHY, "先认识你的鼓。屏幕横着分三列,左边、中间、右边;竖着分两行,上面清亮,下面低沉。随便摸一摸,听到哪面鼓,我就告诉你它在哪。"),
|
||
("tut_probe", _RHY, "摸到三个不同的地方,我们就开始。"),
|
||
("tut_z_kick", _RHY, "下面正中间,是底鼓,你的家。先听四下数拍,然后跟着我敲。"),
|
||
("tut_z_sides", _RHY, "左下是军鼓,右下是低嗵。一左一右,跟着打。"),
|
||
("tut_z_patt", _RHY, "上面一排更清亮。左上踩镲,上中高嗵,右上吊镲。听这一句,三个音。"),
|
||
("tut_fill", _RHY, "最后有一段加花,跟着我连打。"),
|
||
("zone_tl", _RHY, "左上,踩镲。"),
|
||
("zone_tc", _RHY, "上中,高嗵。"),
|
||
("zone_tr", _RHY, "右上,吊镲。"),
|
||
("zone_bl", _RHY, "左下,军鼓。"),
|
||
("zone_bc", _RHY, "下中,底鼓。"),
|
||
("zone_br", _RHY, "右下,低嗵。"),
|
||
# ---- C 组 · 教学纠正 ----
|
||
("retry_early", _RHY, "早了,等鼓点再出手。"),
|
||
("retry_late", _RHY, "晚了,跟着鼓点走。"),
|
||
("retry_wrong", _RHY, "敲错鼓了,再听一遍。"),
|
||
("retry_listen", _RHY, "再听一遍,跟着来。"),
|
||
("retry_skip", _RHY, "没关系,我们先走下一句。"),
|
||
# ---- S 组 · 选曲与解锁 ----
|
||
("select_hint", _RHY, "左右滑选曲目,单击开始,下滑回大厅。"),
|
||
("song1_name", _RHY, "第一首,启程,九十拍。"),
|
||
("song2_name", _RHY, "第二首,追风,一百零五拍。"),
|
||
("song3_name", _RHY, "第三首,星爆,一百二十拍。"),
|
||
("song_locked", _RHY, "这首还没解锁。上一首拿到 B 级以上就能解锁。"),
|
||
("unlock_song2", _RHY, "新曲目解锁,追风!"),
|
||
("unlock_song3", _RHY, "新曲目解锁,星爆!"),
|
||
# ---- G 组 · 结算 ----
|
||
("grade_s", _RHY, "S 级!准确率超过九成五,完美演出。"),
|
||
("grade_a", _RHY, "A 级!准确率超过八成五,非常出色。"),
|
||
("grade_b", _RHY, "B 级,准确率超过七成。不错,还能更好。"),
|
||
("grade_c", _RHY, "C 级,准确率不到七成。别灰心,再来一遍。"),
|
||
("new_best_combo", _RHY, "新连击纪录!"),
|
||
("restart", _RHY, "单击再来一遍,右滑下一首,下滑回大厅。"),
|
||
# ---- M 组 · 菜单与规则 ----
|
||
("rules", _RHY, "规则:我敲一小节鼓,你在下一小节照着敲回来。鼓要选对,拍点也要对。"),
|
||
("settings_hint", _RHY, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("menu_main", _RHY, "菜单。单击切换选项,双击确认。"),
|
||
("menu_resume", _RHY, "继续演奏。"),
|
||
("menu_lobby", _RHY, "回大厅。"),
|
||
("skip_hint", _RHY, "单击可跳过旁白。"),
|
||
]
|
||
|
||
# ---------------------------------------------------------------- space
|
||
# R3 备产(docs/design/04-space-voice-ids.md):52 句全量替换 R1 版,全表同一 instruct 常量。
|
||
_SPC = _pair("低沉醇厚的男声,像飞船领航员,沉稳有力",
|
||
"平静清晰的女声,像飞船领航员,沉稳可信")
|
||
SPACE_LINES = [
|
||
# ---- D 组 · 交互式演练 ----
|
||
("drill_welcome", _SPC, "欢迎登上盲航。你只有一双耳朵。"),
|
||
("drill_rule", _SPC, "陨石来了,会有声音告诉你方位。"),
|
||
("drill_left", _SPC, "听,左边有陨石。向左滑,把它拨开!"),
|
||
("drill_right", _SPC, "这次在右边。向右滑!"),
|
||
("drill_up", _SPC, "上面有东西,声音又尖又高。向上滑!"),
|
||
("drill_down", _SPC, "下面是低沉的轰隆。向下滑!"),
|
||
("drill_good", _SPC, "漂亮。"),
|
||
("drill_retry_left", _SPC, "那是左边来的,向左滑。"),
|
||
("drill_retry_right", _SPC, "那是右边来的,向右滑。"),
|
||
("drill_retry_up", _SPC, "声音又高又尖,是上面,向上滑。"),
|
||
("drill_retry_down", _SPC, "轰隆声在下面,向下滑。"),
|
||
("drill_moveon", _SPC, "没关系,跟着我,我们继续。"),
|
||
("drill_done", _SPC, "四个方向你都会了。引擎点火,出发!"),
|
||
("drill_skip", _SPC, "跳过演练,直接出发。"),
|
||
# ---- P 组 · 保护期 ----
|
||
("protect_left", _SPC, "训练护盾接住了。那颗在左边,听到左边的呼啸,向左滑。"),
|
||
("protect_right", _SPC, "训练护盾接住了。那颗在右边,听到右边的呼啸,向右滑。"),
|
||
("protect_up", _SPC, "训练护盾接住了。那颗在上面,听到高高的呼啸,向上滑。"),
|
||
("protect_down", _SPC, "训练护盾接住了。那颗在下面,听到低沉的轰隆,向下滑。"),
|
||
("protect_end", _SPC, "训练护盾关闭。接下来,靠你自己了。"),
|
||
# ---- F 组 · 单击/双击分批引入 ----
|
||
("feat_boost", _SPC, "试试单击,引擎会短促加速,直接冲过空隙。"),
|
||
("feat_boost_done", _SPC, "感觉到了吗?加速的时候,陨石撞不上你。"),
|
||
("feat_shield", _SPC, "双击展开护盾,能挡下一次撞击。"),
|
||
("feat_shield_done", _SPC, "护盾展开后会自动充能,好了我会告诉你。"),
|
||
("shield_ready", _SPC, "护盾充能完毕。"),
|
||
("shield_block", _SPC, "护盾挡下了撞击。"),
|
||
# ---- H 组 · 被撞归因 ----
|
||
("hit_left", _SPC, "左边撞上的。听到左边的呼啸,向左滑。"),
|
||
("hit_right", _SPC, "右边撞上的。听到右边的呼啸,向右滑。"),
|
||
("hit_up", _SPC, "上面撞上的。听到高高的呼啸,向上滑。"),
|
||
("hit_down", _SPC, "下面撞上的。听到低沉的轰隆,向下滑。"),
|
||
("hit_last", _SPC, "船体只剩最后一次了,小心!"),
|
||
# ---- M 组 · 里程碑 ----
|
||
("ms_10", _SPC, "十颗了,稳。"),
|
||
("ms_25", _SPC, "二十五颗,老练的飞行员。"),
|
||
("ms_50", _SPC, "五十颗,传奇。"),
|
||
("ms_100", _SPC, "一百颗!天空属于你。"),
|
||
# ---- R 组 · 结算 ----
|
||
("time_1", _SPC, "不到三十秒,再试一次。"),
|
||
("time_2", _SPC, "超过三十秒,有进步。"),
|
||
("time_3", _SPC, "超过一分钟,合格的飞行员。"),
|
||
("time_4", _SPC, "超过两分钟,王牌飞行员。"),
|
||
("dodge_1", _SPC, "只拨开几颗。"),
|
||
("dodge_2", _SPC, "拨开了十来颗。"),
|
||
("dodge_3", _SPC, "拨开了几十颗。"),
|
||
("dodge_4", _SPC, "拨开了一大群,漂亮。"),
|
||
("new_record", _SPC, "新纪录!"),
|
||
("restart_hint", _SPC, "单击再飞一次,下滑回大厅。"),
|
||
# ---- Y 组 · 菜单与系统 ----
|
||
("second_run_ask", _SPC, "上滑重新听演练,单击直接出发。"),
|
||
("menu_main", _SPC, "菜单。单击切换选项,双击确认。"),
|
||
("menu_resume", _SPC, "继续飞行。"),
|
||
("menu_lobby", _SPC, "回大厅。"),
|
||
("menu_help", _SPC, "重新听教学要点。"),
|
||
("help_recap", _SPC, "左边来向左滑,右边来向右滑,上面来向上滑,下面来向下滑。单击加速,双击护盾。"),
|
||
("settings_hint", _SPC, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("paused", _SPC, "已暂停。"),
|
||
("skip_hint", _SPC, "单击可跳过旁白。"),
|
||
# ---- R5 新增(space polish round1/round2,research/space-polish/,04-space-voice-ids.md 追加节)----
|
||
("protect_soon", _SPC, "训练护盾还剩十秒。"),
|
||
("boost_not_ready", _SPC, "引擎还在冷却,稍等一下。"),
|
||
# ---- 向导层(docs/design/14-guide-layer.md,schemes §1.5 定稿全文)----
|
||
("gd_hit_hint", _SPC, "被撞了。听方位,同向滑动就能拨开。"),
|
||
# ---- 向导层 round2(docs/design/14-guide-layer.md「round2 v1.1」,synthesis §3 定稿全文)----
|
||
("gd_last_life", _SPC, "这是最后一次机会,撑住。"),
|
||
# ---- 向导层 round3(docs/design/14-guide-layer.md「round3 v1.2」,synthesis §3 定稿全文)----
|
||
# dir_* 为角色音风格超短呼喊,speaker 用本游戏旁白 pair(synthesis §3 表注)。
|
||
("dir_left", _SPC, "左!"),
|
||
("dir_right", _SPC, "右!"),
|
||
("dir_up", _SPC, "上!"),
|
||
("dir_down", _SPC, "下!"),
|
||
|
||
]
|
||
|
||
# ---------------------------------------------------------------- rpg
|
||
# R4 新游戏《剑与声》第一章(docs/design/05-rpg-ch1-voice-ids.md + 05-rpg-addendum.md §6.2)。
|
||
# 旁白全表同一 instruct 常量;NPC 单音色平铺见 RPG_NPC。
|
||
_RPG = _pair("低沉醇厚的男声,像说书人,平静有韵味",
|
||
"平静清晰的年轻女声,像在讲武侠故事")
|
||
RPG_LINES = [
|
||
# ---- A 组 · 序章 ----
|
||
("intro_1", _RPG, "你的眼睛看不见了。但你的耳朵,比谁都灵。"),
|
||
("intro_2", _RPG, "黑风寨掳走了你唯一的徒弟。追进迷雾林,把他们连根拔起。"),
|
||
("intro_3", _RPG, "先记住,怎么用耳朵走路。"),
|
||
# ---- S 组 · 系统/菜单/状态 ----
|
||
("sys_continue_ask", _RPG, "检测到你的旅程记录。单击继续,右滑开始新的旅程。"),
|
||
("sys_new_game", _RPG, "新的旅程,开始了。"),
|
||
("sys_saved", _RPG, "进度已保存。"),
|
||
("sys_rest", _RPG, "你在篝火边睡了一觉,状态全满。"),
|
||
("sys_drink", _RPG, "溪水清冽,你喝了个饱,伤势尽消。"),
|
||
("sys_menu", _RPG, "菜单。左右滑选择,单击确认。"),
|
||
("sys_menu_resume", _RPG, "继续旅程。"),
|
||
("sys_menu_save", _RPG, "保存并回大厅。"),
|
||
("sys_menu_help", _RPG, "重新听帮助。"),
|
||
("help_explore", _RPG, "左右滑切换选项,单击确认。双击重新听场景,上滑查看状态,下滑打开菜单。"),
|
||
("help_battle", _RPG, "战斗中,左右滑选招式,单击出手。听到敌人的前摇,双击格挡。"),
|
||
("settings_hint", _RPG, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("st_hp_high", _RPG, "你状态很好。"),
|
||
("st_hp_mid", _RPG, "你受了伤。"),
|
||
("st_hp_low", _RPG, "你伤势很重,命悬一线。"),
|
||
("st_gold_poor", _RPG, "口袋空空。"),
|
||
("st_gold_some", _RPG, "有些积蓄。"),
|
||
("st_gold_rich", _RPG, "腰包鼓鼓。"),
|
||
("st_lv_low", _RPG, "你初出茅庐。"),
|
||
("st_lv_mid", _RPG, "你小有名气。"),
|
||
("st_lv_high", _RPG, "你已是高手。"),
|
||
("st_weapon_none", _RPG, "你赤手空拳。"),
|
||
("st_weapon_iron", _RPG, "你手持铁剑。"),
|
||
("st_weapon_steel", _RPG, "你手持青钢剑。"),
|
||
("st_weapon_wind", _RPG, "你手持听风剑。"),
|
||
("st_armor_none", _RPG, "你身无片甲。"),
|
||
("st_armor_leather", _RPG, "你身着皮甲。"),
|
||
("st_armor_iron", _RPG, "你身着铁鳞甲。"),
|
||
# ---- D 组 · 场景描述 ----
|
||
("desc_village", _RPG, "雾口村。篝火噼啪作响,村民低声议论着林子里的土匪。"),
|
||
("desc_village_re", _RPG, "你回到了雾口村。"),
|
||
("desc_path", _RPG, "林间小路。风穿过树叶,脚下的落叶沙沙作响。"),
|
||
("desc_path_re", _RPG, "你回到林间小路。"),
|
||
("desc_fork", _RPG, "岔路口。风声在左右两边,听起来不太一样。"),
|
||
("desc_fork_re", _RPG, "你回到岔路口。"),
|
||
("desc_chest", _RPG, "一个枯树洞。洞里似乎藏着什么。"),
|
||
("desc_chest_re", _RPG, "你回到枯树洞前。"),
|
||
("desc_stream", _RPG, "溪流。水声潺潺,是个歇脚的好地方。"),
|
||
("desc_stream_re", _RPG, "你回到溪流边。"),
|
||
("desc_hunter", _RPG, "猎人小屋。柴火正旺,还有磨刀的声音。"),
|
||
("desc_hunter_re", _RPG, "你回到猎人小屋。"),
|
||
("desc_deepwood", _RPG, "密林深处。虫鸣急促,远处有狼嚎,杀气很重。"),
|
||
("desc_deepwood_re", _RPG, "你回到密林深处。"),
|
||
("desc_gate", _RPG, "黑风寨门前。火把熊熊,人声嘈杂。"),
|
||
("desc_hall", _RPG, "聚义厅。火盆熊熊,大厅空旷,回声冰冷。"),
|
||
# ---- O 组 · 选项名 ----
|
||
("opt_go_path", _RPG, "前进,去林间小路。"),
|
||
("opt_go_fork", _RPG, "前进,去岔路口。"),
|
||
("opt_go_chest", _RPG, "往左,看看树洞。"),
|
||
("opt_go_stream", _RPG, "往右,去溪流。"),
|
||
("opt_go_hunter", _RPG, "前进,去猎人小屋。"),
|
||
("opt_go_deepwood", _RPG, "前进,进密林深处。"),
|
||
("opt_go_gate", _RPG, "前进,去寨门。"),
|
||
("opt_back", _RPG, "返回。"),
|
||
("opt_shop", _RPG, "去商店。"),
|
||
("opt_rest", _RPG, "休息一晚。"),
|
||
("opt_status", _RPG, "查看状态。"),
|
||
("opt_investigate", _RPG, "调查四周。"),
|
||
("opt_open_chest", _RPG, "打开树洞。"),
|
||
("opt_drink", _RPG, "饮水休息。"),
|
||
("opt_talk_hunter", _RPG, "和老猎人谈谈。"),
|
||
("opt_assault", _RPG, "强攻寨门。"),
|
||
("opt_sneak", _RPG, "绕行潜入。"),
|
||
("opt_leave", _RPG, "离开。"),
|
||
# ---- E 组 · 事件 ----
|
||
("evt_gold15", _RPG, "你在落叶下摸到十五枚金币。"),
|
||
("evt_nothing", _RPG, "这里什么都没有了。"),
|
||
("evt_chest", _RPG, "树洞里有两瓶金疮药,你收好了。"),
|
||
("evt_hunter_gift", _RPG, "老猎人塞给你一瓶金疮药,还说商店会给你算便宜些。"),
|
||
("evt_gate_open", _RPG, "寨门缓缓打开。"),
|
||
("evt_ch1_end", _RPG, "寨主倒了,但徒弟不在这里。一张字条,指向南方的腐沼。"),
|
||
# ---- B 组 · 战斗 ----
|
||
("btl_start_wolf", _RPG, "野狼拦路!"),
|
||
("btl_start_bandit", _RPG, "山贼围上来了!"),
|
||
("btl_start_spider", _RPG, "毒蛛从树上垂了下来!"),
|
||
("btl_start_elite", _RPG, "寨丁头目挡住了去路!"),
|
||
("btl_start_boss1", _RPG, "黑风寨主,就在你面前。"),
|
||
("cmd_attack", _RPG, "攻击。"),
|
||
("cmd_skill", _RPG, "破空斩。"),
|
||
("cmd_defend", _RPG, "防御。"),
|
||
("cmd_item", _RPG, "金疮药。"),
|
||
("btl_nomp", _RPG, "内劲不足。"),
|
||
("btl_noitem", _RPG, "没有金疮药了。"),
|
||
("btl_flee", _RPG, "你抽身退出了战斗。"),
|
||
("btl_noflee", _RPG, "避无可避!"),
|
||
("btl_half_bandit", _RPG, "山贼的攻势缓了下来。"),
|
||
("btl_enemy_die", _RPG, "敌人倒下了。"),
|
||
("btl_win", _RPG, "战斗胜利。"),
|
||
("btl_loot_small", _RPG, "小有收获。"),
|
||
("btl_loot_mid", _RPG, "收获不少。"),
|
||
("btl_loot_big", _RPG, "大获全胜,收获颇丰。"),
|
||
("btl_levelup", _RPG, "你的修为精进了。"),
|
||
("btl_lose", _RPG, "你倒下了,黑暗吞没了一切。"),
|
||
("btl_lose_hint", _RPG, "记住,听清前摇,双击格挡。"),
|
||
("tut_b1", _RPG, "它要扑了,听前摇!"),
|
||
("tut_b2", _RPG, "就是现在,双击格挡!"),
|
||
("tut_b3", _RPG, "挡住了!轮到你了。左右滑选攻击,单击出剑。"),
|
||
("tut_b4", _RPG, "没挡住也没关系,再来一次。"),
|
||
("tut_b5", _RPG, "好剑法!接下来,靠你自己了。"),
|
||
# ---- SH 组 · 商店 ----
|
||
("shop_open", _RPG, "商店。左右滑看看货,单击购买。"),
|
||
("shop_price_sword", _RPG, "铁剑,一百金。"),
|
||
("shop_price_armor", _RPG, "皮甲,八十金。"),
|
||
("shop_price_potion", _RPG, "金疮药,三十金。"),
|
||
("shop_owned", _RPG, "这件你已经有了。"),
|
||
("shop_poor", _RPG, "钱不够。"),
|
||
("shop_buy", _RPG, "买下了。"),
|
||
# ---- addendum §6.2 补录:敌方血量档位(旁白) ----
|
||
("foe_hp_high", _RPG, "敌人气焰正盛。"),
|
||
("foe_hp_mid", _RPG, "敌人露出疲态。"),
|
||
("foe_hp_low", _RPG, "敌人撑不住了。"),
|
||
("skip_hint", _RPG, "单击可跳过旁白。"),
|
||
# ---- R6 补录:首次战斗教学(用户反馈:首战必须讲清交互) ----
|
||
("tut_battle_1", _RPG, "第一场战斗来了。别慌,战斗是回合制:你先出手,敌人再反击。"),
|
||
("tut_battle_2", _RPG, "左右滑切换招式,攻击、破空斩、防御、金疮药。单击,出手。"),
|
||
("tut_battle_3", _RPG, "敌人出手前有一声前摇。听到前摇,马上双击,就能格挡。"),
|
||
("tut_battle_4", _RPG, "没把握就防御,伤害减半。金疮药可以回血。"),
|
||
("tut_battle_5", _RPG, "记住:听清前摇,双击格挡。开始吧!"),
|
||
# ---- R5 补录(11 文档新增台词,资产已先行落盘;staging 无 wav,convert 跳过)----
|
||
("tut_b0", _RPG, "战斗里,左右滑选招式,单击出手。听到这个声音,就是你的回合。先滑一滑,试试。"),
|
||
("tut_b6", _RPG, "来不及格挡,就选防御。左右滑,选防御,单击。"),
|
||
("btl_flee_fail", _RPG, "没甩掉!它追上来了。"),
|
||
("boss1_warn", _RPG, "里面就是黑风寨主。你现在回去练练再来,也来得及。"),
|
||
# ---- 向导层(docs/design/14-guide-layer.md,schemes §1.5 定稿全文)----
|
||
("gd_parry_miss", _RPG, "前摇声起的时候双击,才能格挡。"),
|
||
("gd_stall", _RPG, "想好了吗?左右滑动选择,单击出手。"),
|
||
# ---- round2 新增(docs/design/14-guide-layer.md「round2 v1.1」,synthesis §3 定稿全文)----
|
||
("tut_b2b", _RPG, "挡得漂亮。"),
|
||
("gd_wrap_first", _RPG, "回到第一个。"),
|
||
("gd_wrap_last", _RPG, "最后一个了。"),
|
||
]
|
||
|
||
# NPC 单音色平铺(id, speaker, instruct, 台词)→ web/rpg/audio/voice/<id>.*
|
||
# 角色 speaker+instruct 恒定(村长与寨主同 speaker 不同 instruct,从不在同场景出现)。
|
||
RPG_NPC = [
|
||
("npc_headman_1", "Uncle_Fu", "慈祥和缓的老者", "外乡人,林子里不太平。这五十金,拿着防身。"),
|
||
("npc_headman_2", "Uncle_Fu", "慈祥和缓的老者", "商店就在村里,缺什么就去看看。"),
|
||
("npc_headman_3", "Uncle_Fu", "慈祥和缓的老者", "听说你是用耳朵走路的剑客?保重啊。"),
|
||
("npc_headman_4", "Uncle_Fu", "慈祥和缓的老者", "救救那些被掳走的孩子吧。"),
|
||
("npc_hunter_1", "Eric", "沙哑粗犷,豪爽中带着暖意", "站住。……哦,是个用耳朵的。"),
|
||
("npc_hunter_2", "Eric", "沙哑粗犷,豪爽中带着暖意", "寨子里有我旧识。带上这个,别死在路上。"),
|
||
("npc_hunter_3", "Eric", "沙哑粗犷,豪爽中带着暖意", "黑风寨主的双刀很快,听清他出刀前的动静。"),
|
||
("npc_hunter_4", "Eric", "沙哑粗犷,豪爽中带着暖意", "去吧。让我听听,你的传说。"),
|
||
("npc_elite_1", "Dylan", "凶狠粗鲁,大声喝骂", "哪儿来的瞎子,敢闯黑风寨!"),
|
||
("npc_elite_half", "Dylan", "凶狠粗鲁,大声喝骂", "你……你到底是什么人!"),
|
||
("npc_elite_die", "Dylan", "凶狠粗鲁,大声喝骂", "寨主……会替我报仇……"),
|
||
("npc_boss1_1", "Uncle_Fu", "低沉阴狠,慢条斯理", "盲剑客?正好,省得挖你的眼睛。"),
|
||
("npc_boss1_2", "Uncle_Fu", "低沉阴狠,慢条斯理", "有两下子。可惜,你听不懂死期的声音。"),
|
||
("npc_boss1_die", "Uncle_Fu", "低沉阴狠,慢条斯理", "白无瞳……会找到你……"),
|
||
]
|
||
NPCS = {"rpg": RPG_NPC}
|
||
|
||
|
||
# ---------------------------------------------------------------- radio
|
||
# 《不眠频率》批次 1(docs/design/15-radio-voice-ids.md,132 句:双性别 103 + 平铺 NPC 29)。
|
||
# 台词全文由提取脚本逐字照抄 voice-ids 文档;双性别组分 HOST(主播)/ PROD(导播/系统)
|
||
# 两个 speaker 配对(同性别双音色,VOICE_SPK 覆盖);NPC 单音色平铺(RADIO_NPC)+ 通话带通(NPC_BANDPASS)。
|
||
_RADIO_HOST = _pair("低沉温和的中年男声,深夜电台主播,沉稳亲切,有磁性",
|
||
"温暖清晰的年轻女声,深夜电台主播,沉稳亲切,不甜腻")
|
||
_RADIO_PROD = _pair("贴近耳机的低语男声,年轻电台导播,冷静克制",
|
||
"贴近耳机的低语女声,年轻电台导播,冷静克制")
|
||
RADIO_HOST_LINES = [
|
||
("b_open", _RADIO_HOST, "午夜零点,红灯亮起。欢迎回到《今夜不眠》。"),
|
||
("b_rain", _RADIO_HOST, "雨下了一整晚。热线灯,马上就要亮了。"),
|
||
("z1_song", _RADIO_HOST, "大爷别急,这首歌我也会。咱们一句一句来。"),
|
||
("z1_ask", _RADIO_HOST, "大爷,路口有什么招牌?念一个给我听听。"),
|
||
("z1_stay", _RADIO_HOST, "哪儿也不去。我陪你,这首歌还长着呢。"),
|
||
("z1_pol", _RADIO_HOST, "大爷,我把您转给派出所,他们马上就到。"),
|
||
("l1_go", _RADIO_HOST, "你妈等的不是奖杯,是你进门喊的那声妈。"),
|
||
("l1_free", _RADIO_HOST, "退不退,都是你的自由。夜还长,慢慢想。"),
|
||
("k1_lull", _RADIO_HOST, "闭上眼睛。风把云朵盖在被子上,月亮替你值夜班。"),
|
||
("k1_ask", _RADIO_HOST, "睡不着的时候,心里是不是装着事?说给我听听。"),
|
||
("k1_truth", _RADIO_HOST, "糖糖,记住,大人的事,不是小孩的错。一个字都不是。"),
|
||
("k1_lie", _RADIO_HOST, "睡吧。明天一睁眼,什么都会好起来的。"),
|
||
("w1_say", _RADIO_HOST, "四十分钟前,有个孩子问我们:爸妈摔门,是不是她的错。"),
|
||
("w1_say2", _RADIO_HOST, "今天有位小朋友,还在等爸妈回家切蛋糕。"),
|
||
("w1_air", _RADIO_HOST, "陈姐,别挂。让他接电话——全城都在听。"),
|
||
("w1_priv", _RADIO_HOST, "这里只有我们俩了。想说就说,想哭就哭。"),
|
||
("w1_home", _RADIO_HOST, "吵架隔着电话吵不赢。回家吧,蛋糕别放到坏了。"),
|
||
("h1_talk", _RADIO_HOST, "说说她。开学第一天,她跟你说的头一句话,是什么?"),
|
||
("h1_stop", _RADIO_HOST, "听我的,前面三公里有服务区。学费急,命更急。"),
|
||
("d9_face", _RADIO_HOST, "师父,三年了。这句晚安,我替您播。各位,晚安。"),
|
||
("d9_avoid", _RADIO_HOST, "各位,今晚到这里。明晚零点,今夜不眠,不见不散。"),
|
||
("e1_a", _RADIO_HOST, "天亮了,热线灯还亮着。你们的晚安,是这座城市的心跳。"),
|
||
("e1_b", _RADIO_HOST, "这把话筒,我总算接得住了。明晚零点,接着不眠。"),
|
||
("e2_a", _RADIO_HOST, "今晚的热线烧得发烫。全城的失眠者,都被接住了。"),
|
||
("e2_b", _RADIO_HOST, "只是路过留言机的时候,你还是没敢看它。红灯灭得很慢。"),
|
||
("e3_a", _RADIO_HOST, "口碑掉了一夜。可那句迟到三年的晚安,今晚说出去了。"),
|
||
("e3_b", _RADIO_HOST, "一个人的频道,也是频道。师父,收到了吗?"),
|
||
("e4_a", _RADIO_HOST, "今夜不眠,静音收播。有的夜班,谁也接不住谁。"),
|
||
("e4_b", _RADIO_HOST, "留言机还在闪。你没看它,它也没怪你。明晚再说吧。"),
|
||
]
|
||
|
||
RADIO_PROD_LINES = [
|
||
("gd_brief", _RADIO_PROD, "单击继续节目。请选择的时候,向左或向右滑。"),
|
||
("gd_continue", _RADIO_PROD, "单击屏幕,继续。"),
|
||
("gd_again", _RADIO_PROD, "还在吗?单击继续。"),
|
||
("gd_invalid", _RADIO_PROD, "这个手势,直播间里用不上。"),
|
||
("gd_ring1", _RADIO_PROD, "热线在闪。单击,接听。"),
|
||
("gd_ring2", _RADIO_PROD, "灯还亮着,听众在等。单击,接听。"),
|
||
("sys_help", _RADIO_PROD, "单击继续,双击重新听。上滑听状态,下滑开菜单。请选择时,左右滑。"),
|
||
("sys_menu", _RADIO_PROD, "菜单。单击切换选项,双击确认。"),
|
||
("sys_menu_resume", _RADIO_PROD, "回到直播。"),
|
||
("sys_menu_restart", _RADIO_PROD, "重新开始今晚。"),
|
||
("sys_menu_lobby", _RADIO_PROD, "保存并回大厅。"),
|
||
("sys_settings", _RADIO_PROD, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("sys_skip", _RADIO_PROD, "想跳过这句,单击就行。"),
|
||
("sys_continue_ask", _RADIO_PROD, "检测到你的夜班记录。单击继续上次,右滑开始新的夜晚。"),
|
||
("sys_new_night", _RADIO_PROD, "新的夜晚,开始了。"),
|
||
("sys_saved", _RADIO_PROD, "进度已保存。"),
|
||
("prog_c1", _RADIO_PROD, "现在是今晚第一通电话。"),
|
||
("prog_c2", _RADIO_PROD, "现在是今晚第二通电话。"),
|
||
("prog_c3", _RADIO_PROD, "现在是今晚第三通电话。"),
|
||
("prog_c4", _RADIO_PROD, "现在是今晚第四通电话。"),
|
||
("prog_c5", _RADIO_PROD, "现在是今晚第五通电话。"),
|
||
("rep_high", _RADIO_PROD, "今晚的口碑,在听众里立住了。"),
|
||
("rep_mid", _RADIO_PROD, "今晚的口碑,不好不坏。"),
|
||
("rep_low", _RADIO_PROD, "今晚的口碑,还没立起来。"),
|
||
("b_rule", _RADIO_PROD, "台里的规矩就一条:先接住人,再接电话。"),
|
||
("b_goal", _RADIO_PROD, "今晚五通电话。说什么话,由你决定。"),
|
||
("z1_ring_in", _RADIO_PROD, "一线来电。七十多岁,雨夜,走丢了。"),
|
||
("p1", _RADIO_PROD, "老人在发抖。向左滑,陪他哼那首老歌。向右滑,冷静问他路口的路牌。"),
|
||
("z1_sdone", _RADIO_PROD, "他稳住了。老歌,比路牌管用。"),
|
||
("z1_adone", _RADIO_PROD, "他慌了。先接住情绪,再走流程。"),
|
||
("p2", _RADIO_PROD, "雨声更密了。向左滑,留在原地陪他等巡逻队。向右滑,转接派出所。"),
|
||
("z1_staye", _RADIO_PROD, "十五分钟后,巡逻灯停在路口。全城听见老人笑了。"),
|
||
("z1_pole", _RADIO_PROD, "转接完成,地址报得清。干净利落。"),
|
||
("z1_bade", _RADIO_PROD, "地址没报清就转接,雨又大。这通砸了。先稳人,再办事。"),
|
||
("z1_ok1", _RADIO_PROD, "就这么接。记住这个手感。"),
|
||
("l1_in", _RADIO_PROD, "二线来电。姑娘,声音很轻,像怕吵到谁。"),
|
||
("p3", _RADIO_PROD, "向左滑,告诉她这趟车值得上。向右滑,把选择还给她。"),
|
||
("l1_goe", _RADIO_PROD, "二线收工。这句话,值一个头条。"),
|
||
("l1_freee", _RADIO_PROD, "她走了。没上车,也没退票。年轻人的夜,长了点。"),
|
||
("k1_in", _RADIO_PROD, "三线来电。听呼吸,是个小孩。"),
|
||
("p4", _RADIO_PROD, "向左滑,唱一段摇篮曲哄她睡。向右滑,轻轻问她怎么了。"),
|
||
("k1_lulle", _RADIO_PROD, "睡着了。可你没听见,她在怕什么。"),
|
||
("p5", _RADIO_PROD, "孩子的声音在抖。向左滑,告诉她这不是她的错。向右滑,答应她明天都会好。"),
|
||
("k1_truthe", _RADIO_PROD, "蛋糕。记下来——四线的来电,可能跟这个家有关。"),
|
||
("k1_liee", _RADIO_PROD, "你许了个兑不了的现。孩子睡了,谎留下了。"),
|
||
("w1_in", _RADIO_PROD, "四线来电。户外风声大,是位大姐。"),
|
||
("p6", _RADIO_PROD, "摔门声你听见了。向左滑,替孩子给她带句话。向右滑,劝她回家把话说开。"),
|
||
("w1_saye", _RADIO_PROD, "她攥着电话,很久没出声。风都停了。"),
|
||
("w1_say2e", _RADIO_PROD, "话递到了。就差最后一脚。"),
|
||
("p7", _RADIO_PROD, "她的呼吸平了。向左滑,留在直播里,让全城等这个门铃。向右滑,换垫乐,私下陪她说完。"),
|
||
("w1_aire", _RADIO_PROD, "电话那头,传来跑步声。今晚的高光时刻。"),
|
||
("w1_prive", _RADIO_PROD, "灯牌是你亲手关的,故事还是完整的。稳。"),
|
||
("w1_homee", _RADIO_PROD, "她往回走了。成不成,看他们自己的了。"),
|
||
("h1_in", _RADIO_PROD, "五线来电。引擎声没停过——他在开车!"),
|
||
("p8", _RADIO_PROD, "方向盘比话筒危险。向左滑,陪他聊聊闺女。向右滑,让他立刻进服务区。"),
|
||
("h1_danger", _RADIO_PROD, "车道偏了——听!"),
|
||
("h1_talke", _RADIO_PROD, "吓醒的,也算醒。这一趟,聊到家。"),
|
||
("h1_stope", _RADIO_PROD, "他下了高速。单子黄了,人齐了。"),
|
||
("h1_echo", _RADIO_PROD, "对了。头通电话那位大爷,就是这片被巡逻队找到的。这城市的夜,是接着的。"),
|
||
("g9_in", _RADIO_PROD, "五线收工。垫乐起——零点档,还剩最后一段。"),
|
||
("p9", _RADIO_PROD, "留言机红灯在闪,是老主播三年前没播完的那句晚安。向左滑,替他播出去。向右滑,照常收播。"),
|
||
("d9_facee", _RADIO_PROD, "带子里其实只有电流声。但空着的那一秒,你说满了。"),
|
||
("d9_avoide", _RADIO_PROD, "留言机的红灯,又多亮了一夜。"),
|
||
("ep_lead", _RADIO_PROD, "收播了。导播间替你记了一笔账——今晚的人都怎样了。"),
|
||
("ep_zhou_ok", _RADIO_PROD, "老周:孙子替他买了老花镜。回信说,谢谢那首歌。"),
|
||
("ep_zhou_no", _RADIO_PROD, "老周在便利店屋檐下坐到天亮。没出事,也没人听见他的歌。"),
|
||
("ep_deer_ok", _RADIO_PROD, "小鹿上车了。她妈后来打电话说,那声妈,比奖杯值钱。"),
|
||
("ep_deer_no", _RADIO_PROD, "小鹿退了票。检票口的灯,记得那趟没上成的车。"),
|
||
("ep_kid_ok", _RADIO_PROD, "糖糖家的门,这个月没再摔过。她说这是主播魔法。"),
|
||
("ep_kid_no", _RADIO_PROD, "糖糖后来又打来过一次。还是那句:楼下在吵。"),
|
||
("ep_wife_ok", _RADIO_PROD, "陈姐家切了蛋糕。那句「回来吧」,是我这晚听过最好的声音。"),
|
||
("ep_wife_no", _RADIO_PROD, "陈姐在公车站坐到了末班车。那通电话,成了没寄出的信。"),
|
||
("ep_han_ok", _RADIO_PROD, "老韩到家了。后视镜上,多了朵小红花。"),
|
||
("ep_han_no", _RADIO_PROD, "老韩在服务区睡了一觉。学费齐了,那首歌没放成。"),
|
||
]
|
||
|
||
RADIO_LINES = RADIO_HOST_LINES + RADIO_PROD_LINES
|
||
|
||
# NPC 单音色平铺(id, speaker, instruct, 台词)→ web/radio/audio/voice/<id>.*
|
||
#(转码时按 15-radio.md §6.2 逐来电者带通,见 NPC_BANDPASS;staging 保留未滤波原声)。
|
||
RADIO_NPC = [
|
||
("z1_a", "Uncle_Fu", "苍老沙哑的男声,七十五岁,疲惫害怕,带着雨夜的颤抖", "主播……我,我找不到回家的路了。"),
|
||
("z1_b", "Uncle_Fu", "苍老沙哑的男声,七十五岁,疲惫害怕,带着雨夜的颤抖", "雨太大了。我本来,只想买副老花镜。"),
|
||
("z1_songo", "Uncle_Fu", "苍老沙哑的男声,七十五岁,疲惫害怕,带着雨夜的颤抖", "对,对!路口修车铺,天天放这首!"),
|
||
("z1_asko", "Uncle_Fu", "苍老沙哑的男声,七十五岁,疲惫害怕,带着雨夜的颤抖", "招牌……雨糊住了,我眼花,看不清啊……"),
|
||
("z1_stayo", "Uncle_Fu", "苍老沙哑的男声,七十五岁,疲惫害怕,带着雨夜的颤抖", "好,好。有人说话,我就不怕了。"),
|
||
("z1_polo", "Uncle_Fu", "苍老沙哑的男声,七十五岁,疲惫害怕,带着雨夜的颤抖", "好,好。谢谢你啊,谢谢。"),
|
||
("z1_bad", "Uncle_Fu", "苍老沙哑的男声,七十五岁,疲惫害怕,带着雨夜的颤抖", "说不清……我真是,说不清了……"),
|
||
("l1_a", "Serena", "年轻女声,倔强,带着哭腔,疲惫", "主播,退票窗口十一点半就关了。我站这儿半小时了。"),
|
||
("l1_b", "Serena", "年轻女声,倔强,带着哭腔,疲惫", "票是回去看我妈的。可我试镜又黄了,两手空空……"),
|
||
("l1_goo", "Serena", "年轻女声,倔强,带着哭腔,疲惫", "呜……嗯。不退了,我现在就去检票。谢谢您。"),
|
||
("l1_freeo", "Serena", "年轻女声,倔强,带着哭腔,疲惫", "嗯……我再想想。窗口要关了,我先过去了。"),
|
||
("k1_a", "Vivian", "稚嫩童声,八岁小女孩,困倦,胆怯", "喂……有人吗?我睡不着。"),
|
||
("k1_b", "Vivian", "稚嫩童声,八岁小女孩,困倦,胆怯", "家里灯关了。可是楼下,一直有声音。"),
|
||
("k1_lullo", "Vivian", "稚嫩童声,八岁小女孩,困倦,胆怯", "月亮也睡了……那我也睡。"),
|
||
("k1_asko", "Vivian", "稚嫩童声,八岁小女孩,困倦,胆怯", "爸爸妈妈摔门了。是不是……我做错了什么呀。"),
|
||
("k1_trutho", "Vivian", "稚嫩童声,八岁小女孩,困倦,胆怯", "嗯……那我睡了。他们明天,会一起给我切蛋糕吗?"),
|
||
("k1_lieo", "Vivian", "稚嫩童声,八岁小女孩,困倦,胆怯", "真的吗?拉钩。晚安……"),
|
||
("w1_a", "Vivian", "疲惫沙哑的中年女声,四十五岁,强撑着平静", "主播,我就想找个人说说。我家那口子,今晚要出远门的活儿。"),
|
||
("w1_b", "Vivian", "疲惫沙哑的中年女声,四十五岁,强撑着平静", "明天孩子生日!蛋糕都订好了,他人要今晚走!"),
|
||
("w1_sayo", "Vivian", "疲惫沙哑的中年女声,四十五岁,强撑着平静", "什么?她还没睡?这么晚了,她还醒着?"),
|
||
("w1_say2o", "Vivian", "疲惫沙哑的中年女声,四十五岁,强撑着平静", "蛋糕……是他订的。他嘴上不说,心里都记着。"),
|
||
("w1_airo", "Vivian", "疲惫沙哑的中年女声,四十五岁,强撑着平静", "喂!回来吧!蛋糕要化了,孩子等着呢!"),
|
||
("w1_privq", "Vivian", "疲惫沙哑的中年女声,四十五岁,强撑着平静", "呜……其实他订完蛋糕就跟我道歉了。是我,把门摔得太响。"),
|
||
("w1_homeo", "Vivian", "疲惫沙哑的中年女声,四十五岁,强撑着平静", "嗯……我这就往回走。谢谢你,听我瞎嚷嚷。"),
|
||
("h1_a", "Eric", "沙哑粗犷的中年男声,货车司机,困倦强撑", "主播,别挂。陪我说话,我的眼皮,沉得很。"),
|
||
("h1_b", "Eric", "沙哑粗犷的中年男声,货车司机,困倦强撑", "跑完这趟,闺女的学费就齐了。雨刷都快刮不动了。"),
|
||
("h1_talko", "Eric", "沙哑粗犷的中年男声,货车司机,困倦强撑", "她说,爸,我在学校给你赚了朵小红花。哈哈,哈哈……"),
|
||
("h1_dango", "Eric", "沙哑粗犷的中年男声,货车司机,困倦强撑", "嘶——好险!前车急刹,我擦着护栏过去了。彻底醒了!"),
|
||
("h1_stopo", "Eric", "沙哑粗犷的中年男声,货车司机,困倦强撑", "行,听你的。进了服务区,我给你们放首歌听。"),
|
||
]
|
||
|
||
# ---------------------------------------------------------------- dungeon
|
||
# 《回声地窟》批次 1(docs/design/16-dungeon-voice-ids.md,125 句 ×2 性别,无 NPC);
|
||
# R3 起 +2(E1-2 gold_some / 打磨 tut_flee_hold)= 127 句,st_best_2 措辞重录。
|
||
_DUN = _pair("低沉醇厚的男声,像探窟向导,沉稳有力",
|
||
"平静清晰的女声,像探窟向导,沉稳可信")
|
||
DUNGEON_LINES = [
|
||
("intro_1", _DUN, "你在黑暗中醒来。这里是回声地窟。"),
|
||
("intro_2", _DUN, "伸手不见五指,声音就是你的眼睛。"),
|
||
("sys_continue_ask", _DUN, "检测到探窟记录。单击继续,右滑重新开始。"),
|
||
("sys_new_run", _DUN, "新的探窟,开始了。"),
|
||
("tut_d0", _DUN, "先学会用耳朵看。单击,发出声波脉冲。"),
|
||
("tut_echo_come", _DUN, "听,回声回来了。"),
|
||
("tut_front_rule", _DUN, "回声回来越快,墙就越近。"),
|
||
("tut_side_rule", _DUN, "两侧的回声,发闷是墙,空旷是通路。"),
|
||
("tut_walk", _DUN, "按住屏幕不放,你就往前走。"),
|
||
("tut_turn", _DUN, "左滑右滑,可以转身。"),
|
||
("tut_replay", _DUN, "双击,再发一次脉冲,不要钱。"),
|
||
("tut_status", _DUN, "上滑,随时听自己的状态。"),
|
||
("tut_menu", _DUN, "下滑,打开菜单。"),
|
||
("tut_mob", _DUN, "前面有东西!放心,它伤不到你。"),
|
||
("tut_parry", _DUN, "听到它的动静,双击格挡。"),
|
||
("tut_parry_ok", _DUN, "挡住了!"),
|
||
("tut_parry_miss", _DUN, "没挡住也别怕,它伤不到你。"),
|
||
("tut_attack", _DUN, "现在单击,挥拳打它。"),
|
||
("tut_kill", _DUN, "打中了,就是这样。"),
|
||
("tut_flee_hold", _DUN, "想逃跑,按住别松手。"), # R3 打磨:战斗短长按取消逃跑时的区分提示(每场 1 次)
|
||
("tut_stairs", _DUN, "铁器的回声,就是下潜的楼梯。"),
|
||
("tut_stairs_on", _DUN, "楼梯就在脚下。单击,下潜。"),
|
||
("tut_done", _DUN, "教学完了。地窟很深,小心走。"),
|
||
("tut_skip", _DUN, "已跳过教学。单击脉冲,先听听四周。"),
|
||
("sys_saved", _DUN, "进度已保存。"),
|
||
("sys_menu", _DUN, "菜单。单击切换,双击确认。"),
|
||
("sys_menu_resume", _DUN, "返回探索。"),
|
||
("sys_menu_save", _DUN, "保存并回大厅。"),
|
||
("sys_menu_help", _DUN, "重新听帮助。"),
|
||
("sys_menu_restart", _DUN, "重新开始本周目。"),
|
||
("help_explore", _DUN, "单击脉冲,按住前进,左右滑转身。双击再听,上滑状态,下滑菜单。"),
|
||
("help_battle", _DUN, "敌人前摇声响时双击格挡,单击挥击。打不过就按住屏幕逃跑。"),
|
||
("settings_hint", _DUN, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("st_floor_1", _DUN, "这是第一层。"),
|
||
("st_floor_2", _DUN, "这是第二层。"),
|
||
("st_floor_3", _DUN, "这是第三层。"),
|
||
("st_floor_4", _DUN, "这是第四层。"),
|
||
("st_floor_5", _DUN, "这是第五层。"),
|
||
("st_floor_6", _DUN, "这是第六层。"),
|
||
("st_floor_7", _DUN, "这是第七层。"),
|
||
("st_hp_1", _DUN, "你毫发无损。"),
|
||
("st_hp_2", _DUN, "你受了点伤。"),
|
||
("st_hp_3", _DUN, "你伤势不轻。"),
|
||
("st_hp_4", _DUN, "你命悬一线。"),
|
||
("st_gold_1", _DUN, "口袋空空。"),
|
||
("st_gold_2", _DUN, "有些积蓄。"),
|
||
("st_gold_3", _DUN, "收获可观。"),
|
||
("st_gold_4", _DUN, "腰包鼓鼓。"),
|
||
# R3 E1-2:金币档 1(0<金<50)新真话句——修「捡到金币→口袋空空/这趟没带回什么」
|
||
# 的档位谎报(P2/P4 共识);=0 仍播 st_gold_1/meta_gold_1 空手措辞。
|
||
# 上滑状态链与 SETTLE/TITLE(元进度)三处共用这一条(管线单条)。
|
||
("gold_some", _DUN, "带回来一点,不多。"),
|
||
("st_face_e", _DUN, "你面朝东。"),
|
||
("st_face_s", _DUN, "你面朝南。"),
|
||
("st_face_w", _DUN, "你面朝西。"),
|
||
("st_face_n", _DUN, "你面朝北。"),
|
||
("st_threat_none", _DUN, "附近很安静。"),
|
||
("st_threat_left", _DUN, "左边有脚步声。"),
|
||
("st_threat_right", _DUN, "右边有脚步声。"),
|
||
("st_threat_both", _DUN, "两边都有动静。"),
|
||
("st_best_1", _DUN, "你还没到过第三层。"),
|
||
("st_best_2", _DUN, "你最远到过中层。"), # R3 打磨措辞:加「最远」(live P3:防误读为"本局到过")
|
||
("st_best_3", _DUN, "你到过最深层。"),
|
||
("evt_coin_1", _DUN, "捡到几枚金币。"),
|
||
("evt_coin_2", _DUN, "捡到一小把金币。"),
|
||
("evt_coin_3", _DUN, "捡到一大袋金币。"),
|
||
("evt_potion", _DUN, "一瓶药水,收进腰带。"),
|
||
("evt_potion_full", _DUN, "腰带满了,药水留在原地。"),
|
||
("evt_weapon", _DUN, "捡到更快的短刃,出手更狠了。"),
|
||
("evt_armor", _DUN, "换上更硬的护甲,更抗打了。"),
|
||
("evt_stairs_lock", _DUN, "楼梯被大东西堵住了,先赢它。"),
|
||
("evt_descend", _DUN, "你顺着楼梯,往下潜。"),
|
||
("btl_bat", _DUN, "盲眼蝠扑了过来!"),
|
||
("btl_rat", _DUN, "窟鼠窜了出来!"),
|
||
("btl_mush", _DUN, "蘑菇怪拦住了你!"),
|
||
("btl_crab", _DUN, "窟主石甲蟹,就在你面前。"),
|
||
("btl_crawler", _DUN, "绕行者贴上来了,小心背后!"),
|
||
("btl_spider", _DUN, "洞蛛落地了!"),
|
||
("btl_leech", _DUN, "窟主腐沼蟒,挡住了楼梯。"),
|
||
("btl_guard", _DUN, "石像卫醒了!"),
|
||
("btl_king", _DUN, "窟中之王,就在深处。"),
|
||
("btl_parried", _DUN, "挡下了大半!"),
|
||
("btl_behind", _DUN, "它在你背后,转身再挡。"),
|
||
("btl_swish", _DUN, "挥空了,它不在你面前。"),
|
||
("btl_no_turn", _DUN, "它贴着你不放,不用转身。"),
|
||
("btl_kill", _DUN, "它倒下了。"),
|
||
("btl_loot_1", _DUN, "战利不多。"),
|
||
("btl_loot_2", _DUN, "小有收获。"),
|
||
("btl_loot_3", _DUN, "大有收获。"),
|
||
("btl_lvup", _DUN, "你的拳脚更利落了。"),
|
||
("btl_flee", _DUN, "你甩掉了它,被抓了一下。"),
|
||
("btl_flee_boss", _DUN, "退路塌了,跑不掉!"),
|
||
("btl_half_crab", _DUN, "石甲蟹的甲裂了!"),
|
||
("btl_half_leech", _DUN, "腐沼蟒暴怒了!"),
|
||
("btl_half_king", _DUN, "王怒了,脚步更重了!"),
|
||
("die_intro", _DUN, "你倒下了。"),
|
||
("die_cause_1", _DUN, "你被小怪拖垮了。"),
|
||
("die_cause_2", _DUN, "你没挡住那记重击。"),
|
||
("die_cause_3", _DUN, "你背后的偷袭,要了命。"),
|
||
("die_adv_1", _DUN, "下次,前摇声响时就双击。"),
|
||
("die_adv_2", _DUN, "打不过,就按住屏幕逃跑。"),
|
||
("die_adv_3", _DUN, "身后有动静,先转身。"),
|
||
("gd_pulse", _DUN, "单击脉冲,听听四周。"),
|
||
("gd_turn", _DUN, "轮到你了。单击挥击。"),
|
||
("gd_invalid", _DUN, "这个操作在这里用不上。"),
|
||
("stair_hint_a", _DUN, "找找铁器的回声,那是楼梯。"),
|
||
("stair_hint_b", _DUN, "楼梯有大东西守着,先赢它。"),
|
||
("stair_dir_e", _DUN, "楼梯在东边。"),
|
||
("stair_dir_s", _DUN, "楼梯在南边。"),
|
||
("stair_dir_w", _DUN, "楼梯在西边。"),
|
||
("stair_dir_n", _DUN, "楼梯在北边。"),
|
||
("nav_e", _DUN, "往东。"),
|
||
("nav_s", _DUN, "往南。"),
|
||
("nav_w", _DUN, "往西。"),
|
||
("nav_n", _DUN, "往北。"),
|
||
("nav_done", _DUN, "到了,就是这里。"),
|
||
("meta_gold_1", _DUN, "这趟没带回什么。"),
|
||
("meta_gold_2", _DUN, "这趟带回一些金币。"),
|
||
("meta_gold_3", _DUN, "这趟满载而归。"),
|
||
("settle_stronger", _DUN, "下个周目,你会更强。"),
|
||
("settle_win_1", _DUN, "你捧起了地窟之心,通关了!"),
|
||
("settle_win_2", _DUN, "黑暗的尽头,是光。"),
|
||
("settle_again", _DUN, "单击,再探一次。"),
|
||
("unlock_lead", _DUN, "攒够了新的遗产。"),
|
||
("unlock_potion", _DUN, "解锁行囊药,开局自带一瓶。"),
|
||
("unlock_vigor", _DUN, "解锁体魄,起始更强壮。"),
|
||
("unlock_veil", _DUN, "解锁护符,每层头一下减半。"),
|
||
("unlock_echo", _DUN, "解锁回声强化,侧向听得更远。"),
|
||
("unlock_blade", _DUN, "解锁武器,开局带着短刃。"),
|
||
("unlock_none", _DUN, "金币还不够,继续攒。"),
|
||
]
|
||
|
||
# ---------------------------------------------------------------- abyss
|
||
# 《深海回音》批次 2(docs/design/17-abyss-voice-ids.md,155 句:双性别 134 + 平铺 NPC 21;
|
||
# R2 修订 +7 句:dv4_dual / oxy_crit_deck / prog_saved1..5,sys_skip(_k) 改词)。
|
||
# 台词全文逐字照抄 voice-ids 文档;双性别组分 DIVER(潜航员=玩家)/ DECK(母船调度/系统/
|
||
# 向导 gd_*)两个 speaker 配对(同性别双音色,VOICE_SPK["abyss"] 覆盖,radio HOST/PROD 同型:
|
||
# 同场景高频对话的两者永不同 speaker);_k 键盘变体 11 对在 KEY_LINES["abyss"]。
|
||
# NPC 平铺 21 句(小舟/老白/陈医官/高船长),转码时按 17-abyss.md §5.3 水声电台带通
|
||
# (NPC_BANDPASS["abyss"]),DIVER/DECK 不滤波(母船级音质)。
|
||
_ABY_DIVER = _pair("低沉冷静的男声,深潜救援员,干练沉着,水下通讯的轻微气声",
|
||
"低沉冷静的年轻女声,深潜救援员,干练沉着,水下通讯的轻微气声")
|
||
_ABY_DECK = _pair("清晰稳定的男声,母船潜水调度员,专业干脆,隔着耳机下达指令",
|
||
"清晰稳定的女声,母船潜水调度员,专业干脆,隔着耳机下达指令")
|
||
|
||
ABYSS_DIVER_LINES = [
|
||
# ---- G1 开场 ----
|
||
("b_open", _ABY_DIVER, "风停了。我站在问海号甲板上,下面三千米,是海燕号。"),
|
||
# ---- D1 第一潜·找船·小舟 ----
|
||
("d1_listen", _ABY_DIVER, "都别出声。管子那头,敲得很稳。"),
|
||
("d1_up", _ABY_DIVER, "小舟,抓住我的肩锁。我们上。"),
|
||
("d1_nolog", _ABY_DIVER, "日志可以补,人不能等。走了。"),
|
||
# ---- D2 第二潜·机舱·老白 ----
|
||
("d2_pry", _ABY_DIVER, "老白,忍住。先泄压,再撬。"),
|
||
("d2_cut", _ABY_DIVER, "切割枪。老白,闭眼,憋气。"),
|
||
("d2_valve", _ABY_DIVER, "电池舱我陪你去。这片海不能脏。"),
|
||
("d2_leave", _ABY_DIVER, "阀门交给母船。你先上,腿要紧。"),
|
||
# ---- D3 第三潜·病舱·陈医官/小郑 ----
|
||
("d3_chen", _ABY_DIVER, "陈医官,你的手在抖。这次,听我的。"),
|
||
("d3_zheng", _ABY_DIVER, "小郑先走。陈医官,下一潜,就是你的。"),
|
||
("d3_spare", _ABY_DIVER, "备用瓶留下。灯,给我亮着。"),
|
||
("d3_promise", _ABY_DIVER, "四小时内,我下来。等我。"),
|
||
# ---- D4 第四潜·指挥舱·高船长 ----
|
||
("d4_slow", _ABY_DIVER, "逐站停,慢慢浮。规矩不能破。"),
|
||
("d4_fast", _ABY_DIVER, "来不及了。直浮!"),
|
||
("d4_pick_gao", _ABY_DIVER, "船长,抓住我。海燕号的事,上面再说。"),
|
||
("d4_pick_chen", _ABY_DIVER, "陈医官,轮到你了。抓住,上浮。"),
|
||
("d4_pick_zheng", _ABY_DIVER, "小郑,吊床连人一起。走了。"),
|
||
("d4_talk", _ABY_DIVER, "日志我听完了。海燕号为什么沉,我会带上去。走吧。"),
|
||
("d4_silent", _ABY_DIVER, "纪律就是纪律。抓住,上浮。"),
|
||
# ---- F9 签收抉择(心结) ----
|
||
("g9_knot", _ABY_DIVER, "三年前,也是这条沟。我按时上浮了,搭档没有。"),
|
||
("d9_bell", _ABY_DIVER, "最后一潜。不为救人,为个交代。"),
|
||
("d9_rest", _ABY_DIVER, "交代,留给明天的人。我去医疗舱。"),
|
||
# ---- EP 结局与尾声回响 ----
|
||
("e1_a", _ABY_DIVER, "五个人都在甲板上。船钟的第一声,是替这条沟敲的。"),
|
||
("e1_b", _ABY_DIVER, "三年了,我终于敢往下看。明天,想再潜一次。"),
|
||
("e2_a", _ABY_DIVER, "五个人都救上来了。船钟,留在了沟底。"),
|
||
("e2_b", _ABY_DIVER, "没人怪我。可半夜醒来,总听见钟在响。"),
|
||
("e3_a", _ABY_DIVER, "没能都带回来。可我到底下去了,敲响了那口钟。"),
|
||
("e3_b", _ABY_DIVER, "钟声替他们,在沟底响了一声。这样,也好。"),
|
||
("e4_a", _ABY_DIVER, "我按规矩上浮了。规矩里,没写怎么难过。"),
|
||
("e4_b", _ABY_DIVER, "沟底很安静。安静得,像三年前那天。"),
|
||
]
|
||
|
||
ABYSS_DECK_LINES = [
|
||
# ---- G0.a 操作提示句(触屏版;_k 变体在 KEY_LINES) ----
|
||
("gd_brief", _ABY_DECK, "单击继续简报。要选择时,向左或向右滑。"),
|
||
("gd_continue", _ABY_DECK, "单击屏幕,继续。"),
|
||
("gd_again", _ABY_DECK, "还在吗?单击继续。"),
|
||
("gd_ping1", _ABY_DECK, "声呐待命。单击,发脉冲。"),
|
||
("gd_ping2", _ABY_DECK, "回波不会自己来。单击。"),
|
||
("sys_help", _ABY_DECK, "单击继续,双击重新听。上滑听状态,下滑开菜单。选择时,左右滑。"),
|
||
("sys_menu", _ABY_DECK, "菜单。单击切换选项,双击确认。"),
|
||
("sys_skip", _ABY_DECK, "听过的句子再播时,单击就能跳过。"),
|
||
("sys_continue_ask", _ABY_DECK, "检测到你的下潜记录。单击继续上次,右滑开始新救援。"),
|
||
# ---- G0.b 状态/系统句 ----
|
||
("gd_invalid", _ABY_DECK, "这个手势,水里用不上。"),
|
||
("gd_prog1", _ABY_DECK, "滑动在这里用不上。想想调度刚说的话。"),
|
||
("gd_prog2", _ABY_DECK, "别乱。停一下,想想下一步。"),
|
||
("sys_menu_resume", _ABY_DECK, "回到水下。"),
|
||
("sys_menu_restart", _ABY_DECK, "重新开始这次救援。"),
|
||
("sys_menu_lobby", _ABY_DECK, "保存并回大厅。"),
|
||
("sys_settings", _ABY_DECK, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("sys_new_dive", _ABY_DECK, "新的一次下潜,开始了。"),
|
||
("prog_d1", _ABY_DECK, "现在是第一次下潜。"),
|
||
("prog_d2", _ABY_DECK, "现在是第二次下潜。"),
|
||
("prog_d3", _ABY_DECK, "现在是第三次下潜。"),
|
||
("prog_d4", _ABY_DECK, "现在是最后一次下潜。"),
|
||
# R2-F10:上滑状态链·已救人数(saved=1..5 分档整句;saved=0 不播)
|
||
("prog_saved1", _ABY_DECK, "已经救上一个人。"),
|
||
("prog_saved2", _ABY_DECK, "已经救上两个人。"),
|
||
("prog_saved3", _ABY_DECK, "已经救上三个人。"),
|
||
("prog_saved4", _ABY_DECK, "已经救上四个人。"),
|
||
("prog_saved5", _ABY_DECK, "五个人都在甲板上了。"),
|
||
("oxy_full", _ABY_DECK, "气瓶还足,救得动。"),
|
||
("oxy_ok", _ABY_DECK, "氧气还够两潜。"),
|
||
("oxy_low", _ABY_DECK, "氧气告急,只够最后一潜。"),
|
||
("oxy_crit", _ABY_DECK, "氧气见底,必须上浮。"),
|
||
# R2-F5:crit 水面变体(SURFACE/ENDING;水下保留「必须上浮」)
|
||
("oxy_crit_deck", _ABY_DECK, "氧气见底,一潜都下不去了。"),
|
||
("oxy_gain", _ABY_DECK, "应急瓶接上了,多三格。"),
|
||
("dry_a", _ABY_DECK, "气瓶用干了。立刻上浮。"),
|
||
("dry_b", _ABY_DECK, "气花在了人身上。人,都上来了。"),
|
||
# ---- G1 开场 ----
|
||
("b_rule", _ABY_DECK, "规矩就一条:气不够一潜,人就必须上浮。"),
|
||
("b_goal", _ABY_DECK, "海燕号,五个人。你的双瓶,够下四潜。"),
|
||
("b_go", _ABY_DECK, "第一潜,找船。耳朵交给声呐。"),
|
||
# ---- D1 第一潜 ----
|
||
("dv1_down", _ABY_DECK, "下潜开始。水会越来越黑,声音会越来越多。"),
|
||
("dv1_teach", _ABY_DECK, "到深度了。声呐静了。单击,发一枚脉冲。"),
|
||
("dv1_metal", _ABY_DECK, "金属回波,钢板。听见这个,就是海燕号的船身。"),
|
||
("dv1_link", _ABY_DECK, "回波后面有杂音,是电台!接通了。"),
|
||
("p1", _ABY_DECK, "管路在响。向左滑,停下来听敲管的暗号。向右滑,先带小舟上浮。"),
|
||
("d1_code", _ABY_DECK, "是老白的暗号:腿被压住,先泄压,再撬。记住这个敲法。"),
|
||
("p2", _ABY_DECK, "小舟想回去拿声呐日志。向左滑,等她。向右滑,直接上浮。"),
|
||
("d1_surf", _ABY_DECK, "小舟出水,第一潜收工。往返,扣三格气。"),
|
||
# ---- D2 第二潜 ----
|
||
("dv2_down", _ABY_DECK, "第二潜,机舱。顺着敲管的声音走。"),
|
||
("dv2_found", _ABY_DECK, "碎石回波后面,敲管声密了。机舱到了。"),
|
||
("p3", _ABY_DECK, "钢梁压着腿。向左滑,泄压后慢慢撬。向右滑,切割枪,快切。"),
|
||
("d2_pry_ok", _ABY_DECK, "暗号没白听。管子一松,钢梁抬起来了。"),
|
||
("d2_pry_slow", _ABY_DECK, "摸着找泄压阀,多费了一格气。腿,出来了。"),
|
||
("d2_flash", _ABY_DECK, "火花炸了一下,虚惊。老白咳着,腿抽出来了。"),
|
||
("p4", _ABY_DECK, "老白要去关电池舱阀门。向左滑,陪他去。向右滑,直接上浮。"),
|
||
("d2_valve_e", _ABY_DECK, "阀门关死了。两格气,换一片干净海。"),
|
||
("d2_surf", _ABY_DECK, "老白出水。他一直扒着舱门,往水里看。"),
|
||
("d2_supply", _ABY_DECK, "潜友阿凯捎来应急瓶。甲板上,粥给你温着。"),
|
||
# ---- D3 第三潜 ----
|
||
("dv3_down", _ABY_DECK, "第三潜,病舱。海燕号在倾斜,别恋战。"),
|
||
("dv3_groan", _ABY_DECK, "回波发闷。船体在呻吟,它撑不久了。"),
|
||
("p5", _ABY_DECK, "病舱一次只能走一个。向左滑,先带陈医官。向右滑,先带小郑。"),
|
||
("d3_chen_e", _ABY_DECK, "陈医官出水。小郑固定在吊床上,呼吸平稳。"),
|
||
("d3_zheng_e", _ABY_DECK, "小郑吊上去了。他一路,都没敢出声。"),
|
||
("p6", _ABY_DECK, "留守的人要空气。向左滑,留下你的备用瓶。向右滑,约定下一潜来接。"),
|
||
("d3_spare_e", _ABY_DECK, "备用瓶挂上了,能多撑十二小时。"),
|
||
("d3_surf", _ABY_DECK, "病舱的人出水。海燕号的呻吟,隔着水都听得见。"),
|
||
# ---- D4 第四潜 ----
|
||
("dv4_none", _ABY_DECK, "气不够一潜了。第四潜,取消。"),
|
||
("dv4_down", _ABY_DECK, "最后一潜,指挥舱。海燕号,撑不住了。"),
|
||
# R2-F4:双载形态下潜链追加(3+1=4 格扣账口播化,不再无声扣款)
|
||
("dv4_dual", _ABY_DECK, "两个人下同一潜。这趟往返,扣四格气。"),
|
||
("dv4_slide", _ABY_DECK, "它滑了!抓稳索缆,指挥舱里还有人!"),
|
||
("p7", _ABY_DECK, "双人上浮。向左滑,逐站减压慢慢浮。向右滑,违规直浮,搏一把。"),
|
||
("p7_chen", _ABY_DECK, "气只够带一个。向左滑,带船长。向右滑,带陈医官。"),
|
||
("p7_zheng", _ABY_DECK, "气只够带一个。向左滑,带船长。向右滑,带小郑。"),
|
||
("d4_slow_e", _ABY_DECK, "减压站一个个过。气瓶在跳,人稳着。"),
|
||
("d4_fast_e", _ABY_DECK, "违规快浮。医疗舱的灯,先给你们开好。"),
|
||
("d4_stay_lost", _ABY_DECK, "另一位,留在了倾斜的船舱。航标灯,替所有人亮着。"),
|
||
("p8", _ABY_DECK, "船长的话没说完。向左滑,把你听到的说出来。向右滑,什么都不问,拉他上浮。"),
|
||
("d4_surf", _ABY_DECK, "最后一潜收工。问海号的甲板,从没这么亮过。"),
|
||
# ---- F9 签收抉择 ----
|
||
("g9_in", _ABY_DECK, "医疗舱躺满了。你的气瓶剩多少,你比我清楚。"),
|
||
("p9", _ABY_DECK, "海燕号的船钟,还挂在沉船上。向左滑,用最后的气,下去取。向右滑,进医疗舱。"),
|
||
("g9_dry", _ABY_DECK, "一格气都不剩了。能带的,你都带回来了。"),
|
||
("d9_bello", _ABY_DECK, "船钟出水。海燕号的声音,回家了。"),
|
||
# ---- EP 尾声回响 ----
|
||
("ep_lead", _ABY_DECK, "收队了。调度台给你记一笔——他们,后来怎样了。"),
|
||
("ep_zhou_ok", _ABY_DECK, "小舟:归队报告打了三页。她说,声音都记得。"),
|
||
("ep_zhou_no", _ABY_DECK, "小舟:声呐日志没了。她凭记忆,重新描了一遍海图。"),
|
||
("ep_bai_ok", _ABY_DECK, "老白:腿保住了。阀门那夜之后,见人就夸你。"),
|
||
("ep_bai_no", _ABY_DECK, "老白:腿打了钢钉。他说,瘸着也值。"),
|
||
("ep_chen_ok", _ABY_DECK, "陈医官:回了医院。诊室里,挂着一盏海底的灯。"),
|
||
("ep_chen_lost", _ABY_DECK, "陈医官:她守着灯,到最后一小时。灯,还亮着。"),
|
||
("ep_zheng_ok", _ABY_DECK, "小郑:拆了石膏,第一件事,去看海。"),
|
||
("ep_zheng_lost", _ABY_DECK, "小郑:吊床随船,滑进了沟底。他没来得及看日出。"),
|
||
("ep_gao_peace", _ABY_DECK, "高船长:退役申请自己写的。第一行写着:数据不如人。"),
|
||
("ep_gao_up", _ABY_DECK, "高船长:上了岸,一直没说话。听说,他在学敲管语。"),
|
||
("ep_gao_lost", _ABY_DECK, "高船长:随海燕号留在沟底。航标灯,还亮着。"),
|
||
("ep_trench_bell", _ABY_DECK, "沟底:船钟挂在问海号桅杆上。风一过,就响一声。"),
|
||
("ep_trench_deep", _ABY_DECK, "沟底:很深,很静。海燕号睡在里面,像睡着了。"),
|
||
]
|
||
|
||
ABYSS_LINES = ABYSS_DIVER_LINES + ABYSS_DECK_LINES
|
||
|
||
# NPC 单音色平铺(id, speaker, instruct, 台词)→ web/abyss/audio/voice/<id>.*
|
||
#(转码时按 17-abyss.md §5.3 逐船员水声电台带通,见 NPC_BANDPASS;staging 保留未滤波原声)。
|
||
ABYSS_NPC = [
|
||
# 小舟(23 岁声呐兵,女,Serena)
|
||
("z1_a", "Serena", "年轻女声,二十三岁声呐兵,缺氧后发虚,强撑着干脆", "……有人吗?声呐兵,小舟。我们还活着,全艇五个人。"),
|
||
("z1_b", "Serena", "年轻女声,二十三岁声呐兵,缺氧后发虚,强撑着干脆", "轮机长老白困在机舱,陈医官和小郑在病舱,船长在指挥舱。"),
|
||
("z1_knock", "Serena", "年轻女声,二十三岁声呐兵,缺氧后发虚,强撑着干脆", "等等,你听。管子里,有人在敲。"),
|
||
("z1_bye", "Serena", "年轻女声,二十三岁声呐兵,缺氧后发虚,强撑着干脆", "好。上面……是不是天亮了?"),
|
||
("d1_log", "Serena", "年轻女声,二十三岁声呐兵,缺氧后发虚,强撑着干脆", "日志里有失事前,最后一段录音。给你,替我们收好。"),
|
||
# 老白(50 岁轮机长,男,Uncle_Fu)
|
||
("bai_a", "Uncle_Fu", "沙哑爽朗的中年男声,五十岁轮机长,忍着伤痛开玩笑", "哈哈,救援的?我这腿,跟冷却管缠上了。"),
|
||
("bai_b", "Uncle_Fu", "沙哑爽朗的中年男声,五十岁轮机长,忍着伤痛开玩笑", "艇上的药板烧了。病舱那两个,比我悬。"),
|
||
("bai_out", "Uncle_Fu", "沙哑爽朗的中年男声,五十岁轮机长,忍着伤痛开玩笑", "腿还在!我的腿还在!走,我给你带路。"),
|
||
("bai_thanks", "Uncle_Fu", "沙哑爽朗的中年男声,五十岁轮机长,忍着伤痛开玩笑", "这片海养着一村人。这份情,我记一辈子。"),
|
||
# 陈医官(45 岁船医,女,Vivian)
|
||
("chen_a", "Vivian", "平静沙哑的中年女声,四十五岁船医,专业镇定,语气温和", "你来了。小郑股骨断了,我给他固定好了。"),
|
||
("chen_b", "Vivian", "平静沙哑的中年女声,四十五岁船医,专业镇定,语气温和", "救援钟一次带一个。我是医生,我最后走。"),
|
||
("chen_up", "Vivian", "平静沙哑的中年女声,四十五岁船医,专业镇定,语气温和", "……好。小郑,等我,上面给你热粥。"),
|
||
("chen_stay", "Vivian", "平静沙哑的中年女声,四十五岁船医,专业镇定,语气温和", "去吧。我守着灯,灯不灭,人就不散。"),
|
||
("chen_last", "Vivian", "平静沙哑的中年女声,四十五岁船医,专业镇定,语气温和", "去吧。灯我留着,人齐了就熄。"),
|
||
# 高船长(58 岁船长,男,Eric)
|
||
("gao_final", "Eric", "低沉苍老的男声,五十八岁船长,疲惫克制,有老舵手的威严", "别下来。带他们回家,就算救完了。海燕号,通话结束。"),
|
||
("gao_a", "Eric", "低沉苍老的男声,五十八岁船长,疲惫克制,有老舵手的威严", "救援员。我船上,还剩两个活人。"),
|
||
("gao_b", "Eric", "低沉苍老的男声,五十八岁船长,疲惫克制,有老舵手的威严", "都带走,我最后上。这是船长的规矩。"),
|
||
("gao_last", "Eric", "低沉苍老的男声,五十八岁船长,疲惫克制,有老舵手的威严", "航标灯替我留着。就说,船长睡了。"),
|
||
("gao_c", "Eric", "低沉苍老的男声,五十八岁船长,疲惫克制,有老舵手的威严", "三年前……没什么。走吧,别耽误。"),
|
||
("gao_confess", "Eric", "低沉苍老的男声,五十八岁船长,疲惫克制,有老舵手的威严", "日志你拿了?里面写着。是我下令,多采了一小时。"),
|
||
("gao_peace", "Eric", "低沉苍老的男声,五十八岁船长,疲惫克制,有老舵手的威严", "……好。这一次,听救援员的。"),
|
||
]
|
||
|
||
# ---------------------------------------------------------------- detective
|
||
# 《雨夜专案》批次 2(docs/design/18-detective-voice-ids.md,171 句:旁白基表 104 双性别 + V 组 14 + 平铺 NPC 53;
|
||
# R2 修订:改词 fin_who_confirm/tut_skip;新增 fin_pre、item_who_w1..w4、st_wrong、recap_cf、gd_board_cf、
|
||
# z_react_w(NPC)、V 组 +4 对——逐条理由见 18-detective.md 文末 R2 修订记录 / new8/detective/round1 F1-F11)。
|
||
# 台词全文逐字照抄 voice-ids 文档;旁白只做系统/指引/教学/状态/现场自勘(探长自勘)/裁决宣读,
|
||
# 不念证词(证词=证人 NPC 平铺,DETECTIVE_NPC);键盘变体 V 组 10 对在 KEY_LINES["detective"]。
|
||
# NPC 不加电话滤波(区别于 radio/abyss——区分度靠 speaker+instruct+游戏侧签名 earcon 前缀)。
|
||
_DET = _pair("低沉沉稳的男声,专案组探长,冷静克制,像在雨夜读卷宗",
|
||
"沉稳清晰的女声,专案组探长,冷静克制,像在雨夜读卷宗")
|
||
DETECTIVE_LINES = [
|
||
# ---- G0 系统/菜单/帮助 ----
|
||
("sys_menu", _DET, "菜单。单击切换,双击确认。"),
|
||
("sys_menu_resume", _DET, "回到证词板。"),
|
||
("sys_menu_cf", _DET, "去指证。"),
|
||
("sys_menu_save", _DET, "保存并回大厅。"),
|
||
("sys_menu_help", _DET, "重新听帮助。"),
|
||
("sys_menu_restart", _DET, "重新查这桩案子。"),
|
||
("sys_saved", _DET, "进度已保存。"),
|
||
("settings_hint", _DET, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("sys_help", _DET, "左右滑换卷宗,单击听取,双击重新听。长按指证,上滑状态,下滑菜单。"),
|
||
("sys_continue_ask", _DET, "检测到未结的案子。单击继续,右滑换一桩新案。"),
|
||
("sys_new_case", _DET, "新案开卷。"),
|
||
# ---- G1 开场/教学 ----
|
||
("intro_1", _DET, "雨下了一整夜。清晨,聚宝斋后院,古董商沈万川死了。"),
|
||
("intro_2", _DET, "你是专案组探长。这桩案子,归你。"),
|
||
("intro_3", _DET, "卷宗六份:四位证人的证词,现场勘验,法医报告。"),
|
||
("tut_d0", _DET, "先熟悉证词板。左右滑,换卷宗。"),
|
||
("tut_listen", _DET, "单击,听取当前卷宗。"),
|
||
("tut_replay", _DET, "双击,重新听这一句。"),
|
||
("tut_status", _DET, "上滑,随时听进度:问了几份,疑点几处。"),
|
||
("tut_confront", _DET, "按住屏幕,进入指证。去找两句对不上的证词。"),
|
||
("tut_cf_try", _DET, "练习一次。选一份证词,单击确认;再选一份,任意一句。"),
|
||
("tut_cf_ok", _DET, "指证就是这样。练习不算数,真矛盾要靠耳朵找。"),
|
||
("tut_done", _DET, "教学完了。开始查案。"),
|
||
("tut_skip", _DET, "已跳过教学。左右滑换卷宗,单击听取;按住屏幕,指证矛盾。"),
|
||
# ---- G2 状态/条目 ----
|
||
("st_asked_0", _DET, "六份卷宗,一份都没听。"),
|
||
("st_asked_1", _DET, "已听一份,还有五份。"),
|
||
("st_asked_2", _DET, "已听两份,还有四份。"),
|
||
("st_asked_3", _DET, "已听三份,还有三份。"),
|
||
("st_asked_4", _DET, "已听四份,还有两份。"),
|
||
("st_asked_5", _DET, "已听五份,还有一份。"),
|
||
("st_asked_6", _DET, "六份都听完了。"),
|
||
("st_doubt_0", _DET, "疑点,还没有。"),
|
||
("st_doubt_1", _DET, "疑点,一处。"),
|
||
("st_doubt_2", _DET, "疑点,两处。"),
|
||
("st_doubt_3", _DET, "疑点,三处。"),
|
||
("st_doubt_4", _DET, "疑点,四处,齐了。"),
|
||
("item_w1", _DET, "门卫老葛的证词。"),
|
||
("item_w2", _DET, "学徒小顺的证词。"),
|
||
("item_w3", _DET, "账房周先生的证词。"),
|
||
("item_w4", _DET, "房东温太太的证词。"),
|
||
("item_scene", _DET, "现场勘验。"),
|
||
("item_fore", _DET, "法医报告。"),
|
||
("item_case", _DET, "结案陈词。"),
|
||
("intro_w3", _DET, "周先生,管了十年的账,见人三分笑。"),
|
||
# ---- G3 现场勘验(探长自勘) ----
|
||
("sc_0", _DET, "你打伞进了后院。雨水顺着瓦檐,淌成一道帘子。"),
|
||
("sc_1", _DET, "柴房门口,沈万川面朝下倒着。后脑一处伤,现场没有凶器。"),
|
||
("sc_2", _DET, "后门门闩完好,是死者自己开的门。生人叫不开这扇门。"),
|
||
("sc_3", _DET, "泥地上只有进来的脚印,没有出去的。墙根的花盆,翻了一个。"),
|
||
("sc_4", _DET, "库房铜秤立在架上,秤砣不见了。"),
|
||
("sc_5", _DET, "柴房墙上,挂钥匙的铜钩,空着。"),
|
||
# ---- G4 指证 ----
|
||
("cf_start", _DET, "指证矛盾。先选第一份证词。左右滑换,单击确认。"),
|
||
("cf_pick_line", _DET, "左右滑,一句一句听。"),
|
||
("cf_confirm", _DET, "就这句?单击,定下来。"),
|
||
("cf_second", _DET, "再选与它矛盾的那份证词。"),
|
||
("cf_self", _DET, "同一句证词,和自己比不出矛盾。"),
|
||
("cf_same", _DET, "这两句说得一致,不矛盾。"),
|
||
("cf_diff", _DET, "这两句,说的不是一件事。"),
|
||
("cf_hit", _DET, "对不上!矛盾成立,记入疑点。"),
|
||
# ---- G5 结案三问 ----
|
||
("fin_start", _DET, "结案陈词。先指认真凶:四位证人,选一个。"),
|
||
("fin_pre", _DET, "证据在手,就此结案?单击,定下来;滑走,继续查。"),
|
||
("item_who_w1", _DET, "门卫老葛。"),
|
||
("item_who_w2", _DET, "学徒小顺。"),
|
||
("item_who_w3", _DET, "账房周先生。"),
|
||
("item_who_w4", _DET, "房东温太太。"),
|
||
("fin_who_confirm", _DET, "就指认这位?单击,定下来。"),
|
||
("fin_clear", _DET, "不在场证明成立。证据放人,回到证词板。"),
|
||
("st_wrong", _DET, "错指一回,记档。"),
|
||
("fin_right", _DET, "证据链闭合。周先生,你还有什么话说?"),
|
||
("fin_right_b", _DET, "证据链闭合。小顺,你还有什么话说?"),
|
||
("fin_ask_weapon", _DET, "第二问:凶器是什么?"),
|
||
("wp_1", _DET, "松木劈柴。"),
|
||
("wp_2", _DET, "铜秤砣。"),
|
||
("wp_3", _DET, "铁门闩。"),
|
||
("wp_4", _DET, "青瓷花盆。"),
|
||
("fin_wp_right", _DET, "对。创口的铜屑,不见了的秤砣,都指向它。"),
|
||
("fin_wp_wrong", _DET, "不对。铜屑不答应。记下了。"),
|
||
("fin_ask_motive", _DET, "第三问:动机是什么?"),
|
||
("mv_1", _DET, "监守自盗。"),
|
||
("mv_2", _DET, "寻仇泄愤。"),
|
||
("mv_3", _DET, "劫财入户。"),
|
||
("fin_mv_right", _DET, "对。库里短的东西,就是引线。"),
|
||
("fin_mv_wrong", _DET, "不对。账上短的东西,才是引线。记下了。"),
|
||
# ---- G6 结算 ----
|
||
("settle_open", _DET, "案件归档。雨,停了。"),
|
||
("rate_s", _DET, "教科书结案。四处疑点,一击即中。"),
|
||
("rate_a", _DET, "干净利落的结案。"),
|
||
("rate_b", _DET, "案子结了,卷宗上有疏漏。"),
|
||
("rate_c", _DET, "案子是结了,卷宗上补丁不少。"),
|
||
("st_miss_0", _DET, "指证,一次没错。"),
|
||
("st_miss_1", _DET, "指证,错过一两回。"),
|
||
("st_miss_2", _DET, "指证,错了不少。"),
|
||
("settle_hook", _DET, "同一场雨里,还有别的案子。单击,接新案。"),
|
||
# ---- G7 看门狗/卡关/纠错 ----
|
||
("gd_board", _DET, "还在证词板。左右滑,换卷宗。"),
|
||
("gd_board_cf", _DET, "都听过了。按住屏幕,去指证。"),
|
||
("gd_cf", _DET, "还在选证词。左右滑,单击确认。"),
|
||
("gd_fin", _DET, "在想?左右滑选,单击定。"),
|
||
("gd_invalid", _DET, "这个操作,这里用不上。"),
|
||
("hint_a", _DET, "探长,还没听的卷宗,先过一遍耳朵。"),
|
||
("hint_b", _DET, "探长,证词里有对不上的地方,逐句比对。"),
|
||
("hint_c1", _DET, "试试指证:周先生说熄了灯,温太太说灯还亮着。"),
|
||
("hint_c2", _DET, "试试指证:周先生说铜秤卖了,现场铜秤还在。"),
|
||
("b_hint_c1", _DET, "试试指证:小顺说熄了灯,温太太说灯还亮着。"),
|
||
("b_hint_c2", _DET, "试试指证:小顺说铜秤卖了,现场铜秤还在。"),
|
||
("hint_fin", _DET, "疑点齐了。去结案陈词。"),
|
||
("recap_go", _DET, "接着查。"),
|
||
("recap_cf", _DET, "卷宗都在耳朵里了。挑一句你不信的,按住指证。"),
|
||
]
|
||
|
||
# NPC 单音色平铺(id, speaker, instruct, 台词)→ web/detective/audio/voice/<id>.*
|
||
# 证人 4 + 秦法医(≤5 约束);同一角色 speaker+instruct 恒定;不加滤波(18b 头注)。
|
||
DETECTIVE_NPC = [
|
||
# 老葛(62 岁门卫,Eric)
|
||
("w1_1", "Eric", "苍老沙哑的男声,守夜人,慢悠悠,带倦意", "昨儿夜里雨大,我守着街门,一步没敢挪窝。"),
|
||
("w1_2", "Eric", "苍老沙哑的男声,守夜人,慢悠悠,带倦意", "九点四十,雨点子刚砸下来,小顺打着伞出的街门。"),
|
||
("w1_3", "Eric", "苍老沙哑的男声,守夜人,慢悠悠,带倦意", "十点一刻,一位先生收着黑伞进了后巷。个儿高,微驼背。"),
|
||
("w1_4", "Eric", "苍老沙哑的男声,守夜人,慢悠悠,带倦意", "九点五十,周账房出的街门,跟我说了声,回家。"),
|
||
("w1_5", "Eric", "苍老沙哑的男声,守夜人,慢悠悠,带倦意", "后半夜,温太太还来门房借过一回热水。"),
|
||
("w1_6", "Eric", "苍老沙哑的男声,守夜人,慢悠悠,带倦意", "听说店里账上短了银子,沈老板撂了话,月底清账。"),
|
||
("acc_ge", "Eric", "苍老沙哑的男声,守夜人,慢悠悠,带倦意", "我守了一夜门!温太太来借热水,她能作证!"),
|
||
# 小顺(19 岁学徒,Dylan)
|
||
("w2_1", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "夜里,师父打发我去城南,给刘掌柜送匣子。"),
|
||
("w2_2", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "雨太大,刘掌柜留我住的,今早才回店。"),
|
||
("w2_3", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "库房钥匙?师父嫌沉,平日就挂在柴房墙上的铜钩。"),
|
||
("w2_4", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "师父的账,向来只信周先生一个人。"),
|
||
("w2_5", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "后门那闩,生人叫不开。熟人来了,师父才亲自去开。"),
|
||
("w2_6", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "周先生常念叨,账房的活,越到夜里越清静。"),
|
||
("acc_shun", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "我宿在城南刘掌柜家,他全家都能作证!"),
|
||
("b_shun_1", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "我走的时候,顺手熄了店堂的灯。"),
|
||
("b_shun_2", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "钥匙,师父贴身带着,从不离身。"),
|
||
("b_shun_3", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "那伤,八成是柴房劈柴砸的。铜秤早卖给收废品的了。"),
|
||
("b_shun_4", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "库房的货,我一件都没碰过。"),
|
||
("b_shun_react_1", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "灯?我、我走的时候明明熄了……"),
|
||
("b_shun_react_2", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "别问了……别问了……"),
|
||
("b_shun_break_1", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "匣子是我送的,可我半路折回来了……"),
|
||
("b_shun_break_2", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "我把棉袄反穿,弓着背,葛大爷没认出我。"),
|
||
("b_shun_break_3", "Dylan", "年轻清亮的男声,学徒,怯生生的,慌张诚实", "库房的货,我拿过三件换了钱。他说要对账……秤砣下去的时候,他看着我。"),
|
||
# 周先生(45 岁账房,pack A 真凶,Uncle_Fu——与 male 旁白同 speaker,靠签名+instruct 区分)
|
||
("z_1", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "我七点进店上夜账。九点五十对完,锁了前门回家。"),
|
||
("z_2", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "临走,我顺手熄了店堂的灯。那会儿,店里就剩老板。"),
|
||
("z_3", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "库房钥匙?沈老板贴身带着,从不离身。"),
|
||
("z_4", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "那伤,是松木劈柴砸的。铜秤?上个月卖给收废品的了。"),
|
||
("z_5", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "我到家倒头就睡,夜里的事,一概不知。"),
|
||
("z_6", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "你们要是不信,去问我家婆娘。"),
|
||
("z_react_1", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "灯?……许是我记岔了。人上了岁数,记性不济。"),
|
||
("z_react_2", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "钥匙的事……他、他有时候,也贴身带着的……"),
|
||
("z_react_w", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "铜器?……我那是顺口猜的。凶器的事,我怎么会知道。"),
|
||
("z_react_3", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "秤!秤的事,你们别再问了……"),
|
||
("z_react_4", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "……随你们怎么问。我要回去了。"),
|
||
("acc_zhou", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "我十点就到家了!我家婆娘能作证!"),
|
||
("z_break_1", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "别念了……我说。库房短的三件货,是我抵了赌债。"),
|
||
("z_break_2", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "他说月底清账,要报官。我求他,他不肯。"),
|
||
("z_break_3", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "我只想把钥匙放回去,把被盗做真。抡起秤砣的时候,他认出了我。"),
|
||
("b_zhou_1", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "我对完账就回家了,夜里雨大,路上没停。"),
|
||
("b_zhou_2", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "钥匙?平时就挂在柴房铜钩上,十年了。"),
|
||
("b_zhou_3", "Uncle_Fu", "平板谨慎的男声,账房,字斟句酌,被追问时渐慌", "柴房我常去,没什么不对劲的。"),
|
||
# 温太太(50 岁房东,Vivian)
|
||
("wen_1", "Vivian", "快嘴泼辣的中年女声,房东太太,嗓门亮,热心肠", "雨是九点四十下的。我正收晾的衣裳,记得真真的。"),
|
||
("wen_2", "Vivian", "快嘴泼辣的中年女声,房东太太,嗓门亮,热心肠", "十点二十,我出门倒垃圾。聚宝斋店堂的灯,亮着呢。"),
|
||
("wen_3", "Vivian", "快嘴泼辣的中年女声,房东太太,嗓门亮,热心肠", "刚回屋,柴房后墙咯噔一响,有人爬墙!花盆翻了一个。"),
|
||
("wen_4", "Vivian", "快嘴泼辣的中年女声,房东太太,嗓门亮,热心肠", "吓得我蒙头半宿没睡着,天亮才敢吱声。"),
|
||
("wen_5", "Vivian", "快嘴泼辣的中年女声,房东太太,嗓门亮,热心肠", "店里短银子的事,街坊都有耳闻。上礼拜他还摔了账本。"),
|
||
("wen_6", "Vivian", "快嘴泼辣的中年女声,房东太太,嗓门亮,热心肠", "周账房那人,见人三分笑,账算得比谁都精。"),
|
||
("acc_wen", "Vivian", "快嘴泼辣的中年女声,房东太太,嗓门亮,热心肠", "我这把年纪翻墙?先问问那墙答不答应!"),
|
||
# 秦法医(Serena——与 female 旁白同 speaker,靠签名+报告语境区分)
|
||
("fo_1", "Serena", "冷静干练的女声,验尸官,临床腔,短句平直", "验尸报告,念给你听。"),
|
||
("fo_2", "Serena", "冷静干练的女声,验尸官,临床腔,短句平直", "死亡时间,昨夜十点到十点半。"),
|
||
("fo_3", "Serena", "冷静干练的女声,验尸官,临床腔,短句平直", "后脑单次钝器伤,一击毙命。创口嵌有铜屑,凶器是铜器。"),
|
||
("fo_4", "Serena", "冷静干练的女声,验尸官,临床腔,短句平直", "死者双手干净,没有搏斗痕迹。"),
|
||
("fo_5", "Serena", "冷静干练的女声,验尸官,临床腔,短句平直", "鞋底是干的。当夜,死者没出过后门。"),
|
||
]
|
||
|
||
# ---------------------------------------------------------------- hunt
|
||
# 《围猎》批次 3(docs/design/23-hunt-voice-ids.md):旁白/系统音 60 句 ×2 性别
|
||
# (全表同一 instruct 常量/性别,禁语速词;数字全分档整句无拼接;「重听」写「重新听」)
|
||
# + bot 喊话 24 条固定单音色平铺(HUNT_NPC)+ 键盘变体 V 组 11 对(KEY_LINES["hunt"])。
|
||
# 异例(23-hunt.md §15 裁决 7):喊话走 sfx 层带 pan,convert 落盘 audio/sfx/ 而非
|
||
# audio/voice/(生成管线、峰值归一 0.89 与 voice 一致;不滤波)。
|
||
# H 组头注「×9」为文档笔误,实表 8 句(end_win/end_lose/grade_×4/end_rank/end_again),
|
||
# 旁白合计 4+11+6+12+3+3+1+8+4+6+2 = 60 ✓。
|
||
_HUNT = _pair("低沉醇厚的男声,像守夜猎人的领队,沉稳有力",
|
||
"清亮沉稳的女声,像守夜猎人的领队,冷静中带着鼓舞")
|
||
HUNT_LINES = [
|
||
# ---- A 组 · 开场/房间 ----
|
||
("intro_1", _HUNT, "夜幕降临,野兽在山林里游荡。"),
|
||
("intro_2", _HUNT, "你们是守夜的猎人,营地就在身后。"),
|
||
("room_wait", _HUNT, "房间已开好,等同伴到齐。单击,立即开局。"),
|
||
("room_start", _HUNT, "狩猎开始,先听声音的方向。"),
|
||
# ---- B 组 · 教学 TEACH ----
|
||
("tut_rule", _HUNT, "野兽会从八个方向围上来。声音在哪边,就往哪边滑。"),
|
||
("tut_attack", _HUNT, "听,有狼在靠近。朝声音的方向,滑一下。"),
|
||
("tut_kill_ok", _HUNT, "好,杀掉了。就是这样。"),
|
||
("tut_callout", _HUNT, "单击一下,呼喊支援,队友会来帮你。"),
|
||
("tut_callout_ok", _HUNT, "听到没,同伴回应你了。"),
|
||
("tut_skill", _HUNT, "双击,旋风斩,清掉身边一圈。"),
|
||
("tut_skill_cd", _HUNT, "旋风斩有八秒冷却。冷却中双击,重新听威胁。"),
|
||
("tut_status", _HUNT, "上滑,听营地状态。下滑,打开菜单。"),
|
||
("tut_breach", _HUNT, "野兽冲进营地,营地就会受损。撑过五波就赢。"),
|
||
("tut_done", _HUNT, "教学完了。真正的围猎,现在开始。"),
|
||
("tut_skip", _HUNT, "已跳过教学,开打。"),
|
||
# ---- C 组 · 波次 ----
|
||
("wave_band1", _HUNT, "第一波来了,别慌。"),
|
||
("wave_band2", _HUNT, "第二波,比刚才多。"),
|
||
("wave_band3", _HUNT, "第三波,有大家伙混在里面。"),
|
||
("wave_band4", _HUNT, "第四波,更快,更多。"),
|
||
("wave_band5", _HUNT, "最后一波,全来了!"),
|
||
("wave_clear", _HUNT, "这一波,守住了。"),
|
||
# ---- D 组 · 状态链(耐久档 → 波次档 → 猎人数 → 击杀档) ----
|
||
("hp_band1", _HUNT, "营地固若金汤。"),
|
||
("hp_band2", _HUNT, "营地受了些损伤。"),
|
||
("hp_band3", _HUNT, "营地损毁过半。"),
|
||
("hp_band4", _HUNT, "营地快守不住了。"),
|
||
("st_wave_a", _HUNT, "还在头几波。"),
|
||
("st_wave_b", _HUNT, "打到中段了。"),
|
||
("st_wave_c", _HUNT, "最后一波了。"),
|
||
("team_3", _HUNT, "三名猎人在守。"),
|
||
("team_4", _HUNT, "四名猎人全在。"),
|
||
("kill_band0", _HUNT, "你还没开张。"),
|
||
("kill_band1", _HUNT, "你小有斩获。"),
|
||
("kill_band2", _HUNT, "你战果累累。"),
|
||
# ---- E 组 · 威胁重听(只报数量档,方位由声像承载) ----
|
||
("threat_none", _HUNT, "近处暂时没有野兽。"),
|
||
("threat_few", _HUNT, "有野兽贴近了,听方向出手。"),
|
||
("threat_many", _HUNT, "四周全是动静,快出手!"),
|
||
# ---- F 组 · 警报(可顶状态/播报类) ----
|
||
("breach", _HUNT, "有野兽冲进营地了!"),
|
||
("breach_heavy", _HUNT, "巨兽撞进营地,损伤很重!"),
|
||
("danger_low", _HUNT, "营地危险了,一只都不能再漏!"),
|
||
# ---- G 组 · 技能 ----
|
||
("skill_ready", _HUNT, "旋风斩准备好了。"),
|
||
# ---- H 组 · 结算 ----
|
||
("end_win", _HUNT, "天亮了,营地还在。"),
|
||
("end_lose", _HUNT, "营地守不住了,撤退!"),
|
||
("grade_s", _HUNT, "评级,S!完美的围猎。"),
|
||
("grade_a", _HUNT, "评级,A。漂亮。"),
|
||
("grade_b", _HUNT, "评级,B。守得还行。"),
|
||
("grade_c", _HUNT, "评级,C。险胜。"),
|
||
("end_rank", _HUNT, "成绩已记入猎手榜。"),
|
||
("end_again", _HUNT, "单击,再猎一局。"),
|
||
# ---- I 组 · 断线/重连 ----
|
||
("net_lost", _HUNT, "与营地断了联系,正在重连。"),
|
||
("net_back", _HUNT, "联系恢复了,接着打。"),
|
||
("net_to_bot", _HUNT, "有猎人离队,老猎手顶上。"),
|
||
("net_gone", _HUNT, "回不去那场围猎了,回大厅。"),
|
||
# ---- J 组 · 菜单/帮助 ----
|
||
("sys_menu", _HUNT, "菜单。单击切换,双击确认。"),
|
||
("sys_menu_resume", _HUNT, "回到猎场。"),
|
||
("sys_menu_help", _HUNT, "重新听帮助。"),
|
||
("sys_menu_home", _HUNT, "退出房间,回大厅。"),
|
||
("help_main", _HUNT, "朝声音的方向滑,就是出击。单击呼喊支援,双击旋风斩。上滑状态,下滑菜单。"),
|
||
("settings_hint", _HUNT, "音色、语速、背景音乐,请回大厅修改。"),
|
||
# ---- K 组 · 向导/纠错(idle-only) ----
|
||
("gd_invalid", _HUNT, "这个操作现在用不上。"),
|
||
("gd_idle", _HUNT, "听声音的方向,滑过去。"),
|
||
]
|
||
|
||
# bot 喊话固定单音色平铺(id, speaker, instruct, 台词)→ web/hunt/audio/sfx/<id>.*
|
||
# 角色 speaker+instruct 恒定(23-hunt-voice-ids.md N 组表):阿岩=Uncle_Fu /
|
||
# 小筝=Serena / 老周=Eric;座 3 真人呼喊无角色声,用 sfx/call_whistle(裁决 6)。
|
||
HUNT_NPC = [
|
||
# 阿岩(座 0,Uncle_Fu)
|
||
("npc_yan_greet", "Uncle_Fu", "憨厚壮实的中年男声,猎户,话少踏实", "我来了,这边有我。"),
|
||
("npc_yan_help_call", "Uncle_Fu", "憨厚壮实的中年男声,猎户,话少踏实", "我这侧吃紧,来个人搭把手!"),
|
||
("npc_yan_help_ack", "Uncle_Fu", "憨厚壮实的中年男声,猎户,话少踏实", "撑住,我来了。"),
|
||
("npc_yan_cover", "Uncle_Fu", "憨厚壮实的中年男声,猎户,话少踏实", "这边交给我。"),
|
||
("npc_yan_kill", "Uncle_Fu", "憨厚壮实的中年男声,猎户,话少踏实", "拿下!"),
|
||
("npc_yan_breach", "Uncle_Fu", "憨厚壮实的中年男声,猎户,话少踏实", "漏了一个,都小心。"),
|
||
("npc_yan_skill", "Uncle_Fu", "憨厚壮实的中年男声,猎户,话少踏实", "都闪开,看我的!"),
|
||
("npc_yan_wave", "Uncle_Fu", "憨厚壮实的中年男声,猎户,话少踏实", "新一波,稳住。"),
|
||
# 小筝(座 1,Serena)
|
||
("npc_zheng_greet", "Serena", "轻快爽利的年轻女声,猎手,干脆利落", "小筝到位,开工啦。"),
|
||
("npc_zheng_help_call", "Serena", "轻快爽利的年轻女声,猎手,干脆利落", "这边太多了,谁来帮一下!"),
|
||
("npc_zheng_help_ack", "Serena", "轻快爽利的年轻女声,猎手,干脆利落", "别慌,我来了!"),
|
||
("npc_zheng_cover", "Serena", "轻快爽利的年轻女声,猎手,干脆利落", "这边我罩着。"),
|
||
("npc_zheng_kill", "Serena", "轻快爽利的年轻女声,猎手,干脆利落", "搞定!"),
|
||
("npc_zheng_breach", "Serena", "轻快爽利的年轻女声,猎手,干脆利落", "哎呀,漏了一个!"),
|
||
("npc_zheng_skill", "Serena", "轻快爽利的年轻女声,猎手,干脆利落", "看我清场!"),
|
||
("npc_zheng_wave", "Serena", "轻快爽利的年轻女声,猎手,干脆利落", "又来一波,打起精神。"),
|
||
# 老周(座 2,Eric)
|
||
("npc_zhou_greet", "Eric", "沙哑沉稳的老年男声,老猎手,带点调侃", "老周我守着,放心。"),
|
||
("npc_zhou_help_call", "Eric", "沙哑沉稳的老年男声,老猎手,带点调侃", "我这边压不住了,来人。"),
|
||
("npc_zhou_help_ack", "Eric", "沙哑沉稳的老年男声,老猎手,带点调侃", "听见了,这就到。"),
|
||
("npc_zhou_cover", "Eric", "沙哑沉稳的老年男声,老猎手,带点调侃", "这边交给我吧。"),
|
||
("npc_zhou_kill", "Eric", "沙哑沉稳的老年男声,老猎手,带点调侃", "嗯,解决了。"),
|
||
("npc_zhou_breach", "Eric", "沙哑沉稳的老年男声,老猎手,带点调侃", "啧,溜进去一只。"),
|
||
("npc_zhou_skill", "Eric", "沙哑沉稳的老年男声,老猎手,带点调侃", "让让,老骨头活动活动。"),
|
||
("npc_zhou_wave", "Eric", "沙哑沉稳的老年男声,老猎手,带点调侃", "听,又来了。"),
|
||
]
|
||
|
||
# ---------------------------------------------------------------- cipher
|
||
# 《暗码》批次 3(docs/design/19-cipher-voice-ids.md,139 句:双性别 134 = OP 报务员 20
|
||
# + WIND 北风/系统 114(含 _k 键盘变体 11 对)+ 平铺 NPC 5(处长 Eric))。
|
||
# OP/WIND 两 speaker 配对(同性别双音色,VOICE_SPK["cipher"] 逐句覆盖,radio 同型:
|
||
# female 侧你 Serena / 北风 Vivian、male 侧你 Uncle_Fu / 北风 Dylan,同场景永不同 speaker)。
|
||
# 不加滤波(19b 头注:区分度靠 speaker+instruct+语境,detective 先例);摩尔斯滴答为
|
||
# 运行时程序合成(web/cipher/morse.js),零文件资产勿排产;数字全分档整句无拼接。
|
||
_CIPHER_OP = _pair("压低而冷静的男声,报务员,值夜班,克制的紧张",
|
||
"压低而冷静的年轻女声,报务员,值夜班,克制的紧张")
|
||
_CIPHER_WIND = _pair("清晰平稳的男声,电台联络声,隔着电流,字字清楚",
|
||
"清晰平稳的女声,电台联络声,隔着电流,字字清楚")
|
||
CIPHER_OP_LINES = [
|
||
("b_open", _CIPHER_OP, "民国二十九年,江城。电讯处的夜班,从零点的电波声开始。"),
|
||
("r1a_send", _CIPHER_OP, "北风,北风。货船,丑时过江,接住。"),
|
||
("r1b_hold", _CIPHER_OP, "先压一压。这一船的事,得看清楚再说。"),
|
||
("r2a_act", _CIPHER_OP, "有的字,不能落进卷宗。"),
|
||
("r2b_act", _CIPHER_OP, "通报誊清,呈处长。"),
|
||
("r3a_go", _CIPHER_OP, "口令我背得出。今夜,我亲自去。"),
|
||
("r3b_act", _CIPHER_OP, "暗号夹进交接簿,让雨替我跑这一趟。"),
|
||
("r4a_feed", _CIPHER_OP, "戴上手键。这一封,借快手七的手法。"),
|
||
("r4b_act", _CIPHER_OP, "手,离开放键器。我只是个值机的。"),
|
||
("g9_knot", _CIPHER_OP, "三年前,我译错了一封电。那之后,我再没见过我的上线。"),
|
||
("d9_send", _CIPHER_OP, "北风,北风。处置令,今夜三时。撤。"),
|
||
("d9_sleep", _CIPHER_OP, "机关上了。雨声里,只剩挂钟。"),
|
||
("e1_a", _CIPHER_OP, "电波追不上我了。码头的灯,一盏一盏地灭。"),
|
||
("e1_b", _CIPHER_OP, "新的密码本,在城外渡口等我。黎明,比想象中安静。"),
|
||
("e2_a", _CIPHER_OP, "交了班,一切照旧。没人知道今晚频道里发生过什么。"),
|
||
("e2_b", _CIPHER_OP, "只是北风的呼叫,到天亮也没人接。下一次,我会接吗。"),
|
||
("e3_a", _CIPHER_OP, "我把警报拍了三遍。门开的时候,挂钟正好敲三点。"),
|
||
("e3_b", _CIPHER_OP, "审讯室的灯,也很亮。可码头那边,一个人都没少。"),
|
||
("e4_a", _CIPHER_OP, "两点五十九分,脚步停在门口。我把最后一页密码,塞进了炉子。"),
|
||
("e4_b", _CIPHER_OP, "耳机还挂着。里面有一封电文,永远译不完了。"),
|
||
]
|
||
CIPHER_WIND_LINES = [
|
||
# ---- G0.a 操作提示句(_k 变体见 KEY_LINES["cipher"]) ----
|
||
("gd_brief", _CIPHER_WIND, "单击继续值机。要选词时,向左或向右滑。"),
|
||
("gd_continue", _CIPHER_WIND, "单击屏幕,继续。"),
|
||
("gd_again", _CIPHER_WIND, "还在吗?单击继续。"),
|
||
("gd_tune1", _CIPHER_WIND, "电文在等。左右滑,听候选词。"),
|
||
("gd_tune2", _CIPHER_WIND, "双击,把电文再听一遍。再双击,会放慢。"),
|
||
("sys_help", _CIPHER_WIND, "单击选定,双击重新听电文。上滑听状态,下滑开菜单。选择时,左右滑。"),
|
||
("sys_menu", _CIPHER_WIND, "菜单。单击切换选项,双击确认。"),
|
||
("sys_skip", _CIPHER_WIND, "想跳过这句,单击就行。"),
|
||
("sys_continue_ask", _CIPHER_WIND, "检测到你的值机记录。单击继续上次,右滑开始新的夜班。"),
|
||
# ---- G0.b 状态/系统句 ----
|
||
("gd_invalid", _CIPHER_WIND, "这个手势,值机室里用不上。"),
|
||
("gd_prog1", _CIPHER_WIND, "光切词没有用。双击,先听电文。"),
|
||
("gd_prog2", _CIPHER_WIND, "别急。停下来,把电文听完整。"),
|
||
("sys_menu_resume", _CIPHER_WIND, "回到电波里。"),
|
||
("sys_menu_book", _CIPHER_WIND, "翻密码本,换一个字母。"),
|
||
("sys_menu_restart", _CIPHER_WIND, "重新开始今晚。"),
|
||
("sys_menu_lobby", _CIPHER_WIND, "保存并回大厅。"),
|
||
("sys_settings", _CIPHER_WIND, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("sys_new_night", _CIPHER_WIND, "新的夜班,开始了。"),
|
||
# ---- G0.c 分档状态句(整句账目,逐值为真) ----
|
||
("prog_t1", _CIPHER_WIND, "现在是今晚第一封电文。"),
|
||
("prog_t2", _CIPHER_WIND, "现在是第二封,内部通报。"),
|
||
("prog_t3", _CIPHER_WIND, "现在是第三封,交接电文。"),
|
||
("prog_t4", _CIPHER_WIND, "第四封,最后一封。"),
|
||
("book_3", _CIPHER_WIND, "密码本,还剩三页。"),
|
||
("book_2", _CIPHER_WIND, "密码本,还剩两页。"),
|
||
("book_1", _CIPHER_WIND, "密码本,只剩最后一页。"),
|
||
("book_0", _CIPHER_WIND, "密码本,一页都不剩了。"),
|
||
("exp_calm", _CIPHER_WIND, "这一晚,还没人看你第二眼。"),
|
||
("exp_low", _CIPHER_WIND, "处长端着茶,多看了你一眼。"),
|
||
("exp_mid", _CIPHER_WIND, "走廊里的脚步声,慢了下来。"),
|
||
("exp_hot", _CIPHER_WIND, "门外,好像有人换了岗。"),
|
||
# ---- G1 开场(b_rule/b_goal;b_open 在 OP 组,b_chief 在 NPC 组) ----
|
||
("b_rule", _CIPHER_WIND, "北风问候你。规矩就一条:听不清,就再听一遍。"),
|
||
("b_goal", _CIPHER_WIND, "今晚频道里有四封密电。每一个字,都要过你的耳朵。"),
|
||
# ---- M1 第一封·船期·教学 ----
|
||
("rx1_in", _CIPHER_WIND, "第一封。江上船队的调度,拍得很稳。"),
|
||
("dv1_teach", _CIPHER_WIND, "电文进来了。先双击,把它重新听一遍。"),
|
||
("dv1_teach2", _CIPHER_WIND, "左右滑,听密码本上的候选词。单击,选定一个。"),
|
||
("dv1_ask", _CIPHER_WIND, "密码本第一页。三个词,哪个是它?"),
|
||
("cand_bay", _CIPHER_WIND, "货船。"),
|
||
("cand_day", _CIPHER_WIND, "客车。"),
|
||
("cand_ray", _CIPHER_WIND, "巡逻艇。"),
|
||
("dv1_right", _CIPHER_WIND, "货船,译对了。药品,装在货船的底舱。"),
|
||
("dv1_wrong", _CIPHER_WIND, "不对。听清楚:B,一长,三短。"),
|
||
("hint_t1", _CIPHER_WIND, "我教你一页:第一个字母,是 B。一长,三短。"),
|
||
("cf_confirm", _CIPHER_WIND, "就这个词?再单击,定下来。"),
|
||
("p2", _CIPHER_WIND, "药品船,丑时过江。向左滑,把船期报给北风。向右滑,压进值机日志。"),
|
||
("r1a_e", _CIPHER_WIND, "收到。江上有人等你。第一封,做得稳。"),
|
||
("r1b_e", _CIPHER_WIND, "日志下面压着的,是三箱药。船,不会等你。"),
|
||
("n1", _CIPHER_WIND, "零点半。挂钟走了半圈,雨没有停。"),
|
||
# ---- M2 第二封·名单 ----
|
||
("rx2_in", _CIPHER_WIND, "第二封。手法很急,是内部通报。"),
|
||
("dv2_ask", _CIPHER_WIND, "密码本第二页。三个词,选一个。"),
|
||
("cand_top", _CIPHER_WIND, "黑名单。"),
|
||
("cand_tap", _CIPHER_WIND, "窃听令。"),
|
||
("cand_tip", _CIPHER_WIND, "线人费。"),
|
||
("rev_top", _CIPHER_WIND, "黑名单。头一个代号,叫码头。"),
|
||
("rev_tap", _CIPHER_WIND, "窃听令。今夜,有人要装耳朵。"),
|
||
("rev_tip", _CIPHER_WIND, "线人费。月底之前,有人要收钱。"),
|
||
("p4_known", _CIPHER_WIND, "名单上有码头。向左滑,暗号示警,让他连夜搬家。向右滑,按流程呈报处长。"),
|
||
("p4_blind", _CIPHER_WIND, "一封通报。向左滑,压进抽屉,谁的耳朵也别装。向右滑,按流程呈报处长。"),
|
||
("r2a_e", _CIPHER_WIND, "这一页,从今天起,不存在了。"),
|
||
("r2b_e", _CIPHER_WIND, "名单进了卷宗。码头,自己多保重。"),
|
||
("hint_t2", _CIPHER_WIND, "翻到这页:第二个字母,是 O。三长。"),
|
||
("n2", _CIPHER_WIND, "一点整。处长的灯,还亮着。"),
|
||
# ---- M3 第三封·交接 ----
|
||
("rx3_in", _CIPHER_WIND, "第三封。很短,手法有点抖。"),
|
||
("dv3_ask", _CIPHER_WIND, "密码本第三页。三个词,选一个。"),
|
||
("cand_hand", _CIPHER_WIND, "今夜交接。"),
|
||
("cand_sand", _CIPHER_WIND, "明晨交接。"),
|
||
("cand_land", _CIPHER_WIND, "地点变更。"),
|
||
("rev_hand", _CIPHER_WIND, "今夜交接。丑时,老码头。"),
|
||
("rev_sand", _CIPHER_WIND, "明晨交接。天亮再说。"),
|
||
("rev_land", _CIPHER_WIND, "地点变更。等下一封。"),
|
||
("p6", _CIPHER_WIND, "交接在你手里。向左滑,亲自去码头跑一趟。向右滑,留书暗号,托给下一班。"),
|
||
("r3a_e", _CIPHER_WIND, "值班室空了一刻钟。值机日志,停了一行。"),
|
||
("r3b_e_ok", _CIPHER_WIND, "交接赶上了。袋子,连夜上了船。"),
|
||
("r3b_e_no", _CIPHER_WIND, "交接的袋子,在码头放到了天亮。"),
|
||
("hint_t3", _CIPHER_WIND, "翻到这页:第一个字母,是 H。四短。"),
|
||
("n3", _CIPHER_WIND, "一点三刻。雨小了,频道里很静。"),
|
||
# ---- M4 第四封·处置令·高潮 ----
|
||
("rx4_in", _CIPHER_WIND, "第四封。最后一个手法,你听过——快手七。"),
|
||
("dv4_ask", _CIPHER_WIND, "密码本第四页。三个词,选一个。"),
|
||
("cand_spy", _CIPHER_WIND, "内线确认。"),
|
||
("cand_say", _CIPHER_WIND, "约谈。"),
|
||
("cand_sly", _CIPHER_WIND, "内部排查。"),
|
||
("rev_spy", _CIPHER_WIND, "内线确认,今夜三时收网。代号,耳机。"),
|
||
("rev_say", _CIPHER_WIND, "明早九时,约谈相关人员。"),
|
||
("rev_sly", _CIPHER_WIND, "即日起,排查站内三人。"),
|
||
("p8_known", _CIPHER_WIND, "三点之前。向左滑,拍一封假电,说北风昨夜已撤。向右滑,手离开放键器,装傻。"),
|
||
("p8_blind", _CIPHER_WIND, "收台之前。向左滑,回一封例行电文,搅一搅水。向右滑,什么都不做。"),
|
||
("r4a_e", _CIPHER_WIND, "假电出了门。对家的耳朵,听得出换人了吗。"),
|
||
("r4b_e", _CIPHER_WIND, "有时,什么都不做,就是做了。"),
|
||
("hint_t4", _CIPHER_WIND, "翻到这页:第二个字母,是 P。短,两长,短。"),
|
||
# ---- F9 签收(g9_knot/d9_send/d9_sleep 在 OP 组) ----
|
||
("g9_in", _CIPHER_WIND, "频道要收了。最后一件事,是你自己。"),
|
||
("p9_known", _CIPHER_WIND, "收网之前。向左滑,开机,发最后一电。向右滑,关机,装睡到天亮。"),
|
||
("p9_blind", _CIPHER_WIND, "北风在等答复。向左滑,开机,把今晚发出去。向右滑,例行收台。"),
|
||
("d9_send_e", _CIPHER_WIND, "收到了。你的手法,我听了一整晚。快走。"),
|
||
("d9_caught_e", _CIPHER_WIND, "信号被咬住了。别回头,走水路。快。"),
|
||
("d9_sleepe", _CIPHER_WIND, "天亮之前,还有两个钟头。守住。"),
|
||
# ---- EP 结局与尾声回响(e*_a/e*_b 在 OP 组) ----
|
||
("ep_lead", _CIPHER_WIND, "天亮了。北风给你记了最后一笔账——今晚的事,都有了去向。"),
|
||
("ep_med_ok", _CIPHER_WIND, "药品:货船丑时靠岸,三箱药,一箱不少。"),
|
||
("ep_med_no", _CIPHER_WIND, "药品:没人接住那三箱药。船,白白过了江。"),
|
||
("ep_list_ok", _CIPHER_WIND, "名单:码头连夜搬了家。卷宗里,少了一个人。"),
|
||
("ep_list_no", _CIPHER_WIND, "名单:天亮时,多了一个红圈。"),
|
||
("ep_hand_ok", _CIPHER_WIND, "交接:胶卷上了船,手很稳。"),
|
||
("ep_hand_no", _CIPHER_WIND, "交接:码头的灯,白亮了一夜。"),
|
||
("ep_spy_ok", _CIPHER_WIND, "处置令:你译对了它。北风,撤在你前头。"),
|
||
("ep_spy_no", _CIPHER_WIND, "处置令:差的那三个字母,差了一整条命。"),
|
||
# ---- EP.b 结局计数(R2 F3:数字规避分档整句;结算链尾播报,存档 endings 账同源) ----
|
||
("end_c1", _CIPHER_WIND, "这是你在电波里挣下的第一个结局。"),
|
||
("end_c2", _CIPHER_WIND, "这是你在电波里挣下的第二个结局。"),
|
||
("end_c3", _CIPHER_WIND, "这是你在电波里挣下的第三个结局。"),
|
||
("end_c4", _CIPHER_WIND, "四个结局,都收进你的密码本了。"),
|
||
]
|
||
CIPHER_LINES = CIPHER_OP_LINES + CIPHER_WIND_LINES
|
||
|
||
# 处长 NPC 单音色平铺(id, speaker, instruct, 台词)→ web/cipher/audio/voice/<id>.*
|
||
# 有台词人物 2 人(北风=WIND 双性别组、处长=平铺 Eric);不加滤波(19b 头注,detective 先例)。
|
||
CIPHER_NPC = [
|
||
("b_chief", "Eric", "威严冷淡的中年男声,电讯处长,官腔,话里有话", "四封电文,一封都不许漏。你的耳朵,是处里最值钱的东西。"),
|
||
("m2_chief", "Eric", "威严冷淡的中年男声,电讯处长,官腔,话里有话", "嗯,译得很全。去吧。"),
|
||
("m4_chief_a", "Eric", "威严冷淡的中年男声,电讯处长,官腔,话里有话", "值机员,今晚的频道,很热闹啊。"),
|
||
("m4_chief_b", "Eric", "威严冷淡的中年男声,电讯处长,官腔,话里有话", "你的耳朵最好。听见什么,记得……要报。"),
|
||
("m4_chief_c", "Eric", "威严冷淡的中年男声,电讯处长,官腔,话里有话", "行。去睡吧,明天还有明天的事。"),
|
||
]
|
||
|
||
# ---------------------------------------------------------------- bridge
|
||
# 《星环舰长》批次 4(docs/design/22-bridge-voice-ids.md,154 句:旁白 132 基表 ×2 性别
|
||
# + V 组 10 对(KEY_LINES["bridge"],base id 落 key/ 子目录)+ 平铺 NPC 12(BRIDGE_NPC)。
|
||
# 旁白=舰载系统音,全表同一 instruct 常量/性别,禁句级变体、禁语速词;数字全分档整句。
|
||
# NPC 与旁白零 speaker 重叠(大副 Dylan / 工程师 Eric / 医师 Vivian),不加滤波(22b 头注)。
|
||
_BRIDGE = _pair("低沉沉稳的男声,舰载系统音,冷静克制",
|
||
"清晰沉稳的女声,舰载系统音,冷静克制,句读干净")
|
||
BRIDGE_LINES = [
|
||
# ---- G0 组 · 系统/菜单/帮助 ----
|
||
("sys_menu", _BRIDGE, "菜单。单击切换,双击确认。"),
|
||
("sys_menu_resume", _BRIDGE, "回到舰桥。"),
|
||
("sys_menu_save", _BRIDGE, "保存并回大厅。"),
|
||
("sys_menu_help", _BRIDGE, "重新听帮助。"),
|
||
("sys_menu_restart", _BRIDGE, "放弃本次巡逻。"),
|
||
("sys_saved", _BRIDGE, "进度已保存。"),
|
||
("settings_hint", _BRIDGE, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("sys_help", _BRIDGE, "巡航中,上滑巡检全舰;危机中,左右滑听选项,单击下令。下滑菜单,双击重新听。"),
|
||
("sys_continue_ask", _BRIDGE, "检测到未完成的巡逻。单击继续,右滑进星港。"),
|
||
("sys_new_patrol", _BRIDGE, "新巡逻,星环号启航。"),
|
||
# ---- G1 组 · 开场/教学 ----
|
||
("intro_1", _BRIDGE, "你是巡逻舰星环号的舰长。在这条航线上,耳朵就是雷达。"),
|
||
("intro_2", _BRIDGE, "全舰四个系统:引擎、护盾、扫描、武器,各守一方。"),
|
||
("intro_3", _BRIDGE, "引擎在舰尾低鸣,护盾在舰首嗡响。"),
|
||
("intro_4", _BRIDGE, "扫描在左舷扫掠,武器在右舷充能。"),
|
||
("intro_5", _BRIDGE, "危机从哪边来,哪边先遭殃。"),
|
||
("tut_d0", _BRIDGE, "先试巡检。向上滑,听全舰状态。"),
|
||
("tut_all_ok", _BRIDGE, "四个音都稳,全舰正常。"),
|
||
("tut_crisis", _BRIDGE, "有情况。听签名音,辨认类型。"),
|
||
("tut_decide", _BRIDGE, "左右滑听选项,单击下令。"),
|
||
("tut_aid", _BRIDGE, "驰援靠扫描。我们的扫描,稳得很。"),
|
||
("tut_after", _BRIDGE, "就是这样:听声,辨型,下令。"),
|
||
("tut_loyal", _BRIDGE, "船员的心分三档:离心、平常、信赖。上滑巡检听得到。"),
|
||
("tut_done", _BRIDGE, "教学完了。舰长,航线交给你。"),
|
||
("tut_skip", _BRIDGE, "已跳过教学。上滑巡检,危机时左右滑听选项。"),
|
||
# ---- G2 组 · 巡检/状态 ----
|
||
("sys_engine_dmg", _BRIDGE, "引擎,受损。"),
|
||
("sys_engine_off", _BRIDGE, "引擎,离线。"),
|
||
("sys_shield_dmg", _BRIDGE, "护盾,受损。"),
|
||
("sys_shield_off", _BRIDGE, "护盾,离线。"),
|
||
("sys_scan_dmg", _BRIDGE, "扫描,受损。"),
|
||
("sys_scan_off", _BRIDGE, "扫描,离线。"),
|
||
("sys_weapon_dmg", _BRIDGE, "武器,受损。"),
|
||
("sys_weapon_off", _BRIDGE, "武器,离线。"),
|
||
("st_hull_1", _BRIDGE, "舰体,稳固。"),
|
||
("st_hull_2", _BRIDGE, "舰体,带伤。"),
|
||
("st_hull_3", _BRIDGE, "舰体,危急。"),
|
||
("st_seg_1", _BRIDGE, "第一巡航段。"),
|
||
("st_seg_2", _BRIDGE, "第二巡航段。"),
|
||
("st_seg_3", _BRIDGE, "第三巡航段。"),
|
||
("st_seg_4", _BRIDGE, "第四巡航段,末段。"),
|
||
("st_rp_1", _BRIDGE, "资源紧张。"),
|
||
("st_rp_2", _BRIDGE, "资源够用。"),
|
||
("st_rp_3", _BRIDGE, "资源充足。"),
|
||
("st_xo_1", _BRIDGE, "大副,离心。"),
|
||
("st_xo_2", _BRIDGE, "大副,平常。"),
|
||
("st_xo_3", _BRIDGE, "大副,信赖。"),
|
||
("st_eng_1", _BRIDGE, "工程师,离心。"),
|
||
("st_eng_2", _BRIDGE, "工程师,平常。"),
|
||
("st_eng_3", _BRIDGE, "工程师,信赖。"),
|
||
("st_doc_1", _BRIDGE, "医师,离心。"),
|
||
("st_doc_2", _BRIDGE, "医师,平常。"),
|
||
("st_doc_3", _BRIDGE, "医师,信赖。"),
|
||
("recap_go", _BRIDGE, "继续航行。"),
|
||
("evt_dock", _BRIDGE, "本段结束,靠港整备。"),
|
||
("evt_resume", _BRIDGE, "启航,下一段巡航。"),
|
||
# ---- G3 组 · 危机 ----
|
||
("evt_meteor", _BRIDGE, "碎石呼啸,陨石群。"),
|
||
("evt_pirate", _BRIDGE, "敌船引擎,海盗。"),
|
||
("evt_distress", _BRIDGE, "断续三短,求救信号。"),
|
||
("evt_radiation", _BRIDGE, "计数急响,辐射云。"),
|
||
("dir_port", _BRIDGE, "方位,左舷。"),
|
||
("dir_star", _BRIDGE, "方位,右舷。"),
|
||
("dir_bow", _BRIDGE, "方位,舰首。"),
|
||
("dir_stern", _BRIDGE, "方位,舰尾。"),
|
||
("cr_decide", _BRIDGE, "听选项,下令。"),
|
||
("opt_evade", _BRIDGE, "规避机动,靠引擎。"),
|
||
("opt_fight", _BRIDGE, "迎战,靠武器。"),
|
||
("opt_breach", _BRIDGE, "硬闯,靠护盾。"),
|
||
("opt_aid", _BRIDGE, "驰援,靠扫描。"),
|
||
("opt_ignore", _BRIDGE, "按兵不动,不理会。"),
|
||
("cr_timeout", _BRIDGE, "没来得及下令。"),
|
||
("res_clean", _BRIDGE, "干净利落,有惊无险。"),
|
||
("res_hurt", _BRIDGE, "舰体受创。"),
|
||
("res_bad", _BRIDGE, "损失惨重。"),
|
||
("res_mine", _BRIDGE, "轰开碎石,采到矿材,资源加一。"),
|
||
("res_plunder", _BRIDGE, "海盗击退,缴获物资,资源加二。"),
|
||
("res_reward", _BRIDGE, "救援成功,对方致谢,资源加二。"),
|
||
("res_ambush", _BRIDGE, "遭了伏击,舰体受创。"),
|
||
("res_rad", _BRIDGE, "全船受照。"),
|
||
("trap_hint", _BRIDGE, "求救码后面,有引擎声,多留心。"),
|
||
# ---- G4 组 · 忠诚/支援 ----
|
||
("loy_aid", _BRIDGE, "医师与大副,记下了这次驰援。"),
|
||
("loy_ignore", _BRIDGE, "求救没了下文,医师很失望。"),
|
||
("loy_fight_win", _BRIDGE, "大副打得尽兴,士气高涨。"),
|
||
("loy_evade_pirate", _BRIDGE, "大副觉得,这一躲有些窝囊。"),
|
||
("loy_breach", _BRIDGE, "工程师心疼过载的护盾。"),
|
||
("loy_rad", _BRIDGE, "医师在处理伤员。"),
|
||
("sup_xo", _BRIDGE, "大副坐上炮位,火力压制!"),
|
||
("sup_eng", _BRIDGE, "工程师出手,系统复航了。"),
|
||
("sup_doc", _BRIDGE, "医师带人抢修,舰体补回一点。"),
|
||
("sup_none", _BRIDGE, "这个岗位,眼下没人顶上。"),
|
||
# ---- G5 组 · 靠港整备 ----
|
||
("dock_open", _BRIDGE, "靠港整备。左右滑看项目,单击执行。"),
|
||
("rep_engine", _BRIDGE, "修理引擎,升一级,两资源。"),
|
||
("rep_shield", _BRIDGE, "修理护盾,升一级,两资源。"),
|
||
("rep_scan", _BRIDGE, "修理扫描,升一级,两资源。"),
|
||
("rep_weapon", _BRIDGE, "修理武器,升一级,两资源。"),
|
||
("rep_ok", _BRIDGE, "修理完成。"),
|
||
("rep_poor", _BRIDGE, "资源不够。"),
|
||
("dock_go", _BRIDGE, "启航,继续巡逻。"),
|
||
("dock_empty", _BRIDGE, "全舰状态良好,无需整备。"),
|
||
# ---- G6 组 · 结算/死亡 ----
|
||
("die_intro", _BRIDGE, "舰体解体在即,全员撤离。"),
|
||
("die_meteor", _BRIDGE, "陨石撕开了船身。"),
|
||
("die_pirate", _BRIDGE, "海盗的炮火击穿了舰体。"),
|
||
("die_rad", _BRIDGE, "辐射熔穿了舱壁。"),
|
||
("die_adv_to", _BRIDGE, "早下令,勤靠港,别硬扛。"),
|
||
("die_adv_sys", _BRIDGE, "系统离线时,别把宝押在它身上。"),
|
||
("rep_open", _BRIDGE, "巡逻归来,全舰记功。剩余资源已折算功勋。"),
|
||
("rate_s", _BRIDGE, "教科书巡逻,功勋卓著。"),
|
||
("rate_a", _BRIDGE, "出色完成巡逻。"),
|
||
("rate_b", _BRIDGE, "巡逻结束,有惊无险。"),
|
||
("rate_c", _BRIDGE, "巡逻结束,遍体鳞伤。"),
|
||
("rate_d", _BRIDGE, "巡逻失败,弃舰撤离。"),
|
||
("merit_1", _BRIDGE, "功勋,寥寥。"),
|
||
("merit_2", _BRIDGE, "功勋,可观。"),
|
||
("merit_3", _BRIDGE, "功勋,丰厚。"),
|
||
("settle_hook", _BRIDGE, "星港期待你的下一次巡逻。单击,返航。"),
|
||
# ---- G7 组 · 看门狗/纠错 ----
|
||
("gd_cruise", _BRIDGE, "还在巡航。上滑,巡检全舰。"),
|
||
("gd_decide", _BRIDGE, "还在等命令。左右滑,听选项。"),
|
||
("gd_dock", _BRIDGE, "还在整备。左右滑,单击执行。"),
|
||
("gd_invalid", _BRIDGE, "这个操作,这里用不上。"),
|
||
("hint_dock3", _BRIDGE, "整备完毕,就启航。"),
|
||
# ---- G8 组 · 星港 ----
|
||
("port_open", _BRIDGE, "星港整备,功勋兑换。左右滑看,单击定。"),
|
||
("upg_spare", _BRIDGE, "备用零件,出发自带一批物资。功勋二十。"),
|
||
("upg_harvest", _BRIDGE, "采集协议,每段多一份资源。功勋三十。"),
|
||
("upg_armor1", _BRIDGE, "加装装甲,舰体上限加一。功勋四十。"),
|
||
("upg_vet", _BRIDGE, "老兵船组,开局全员忠诚加一。功勋五十。"),
|
||
("upg_armor2", _BRIDGE, "重型装甲,舰体上限再加一。功勋六十。"),
|
||
("upg_aegis", _BRIDGE, "应急护盾,每段首次受创减一。功勋七十。"),
|
||
("upg_done", _BRIDGE, "这项已改装到位。"),
|
||
("upg_buy", _BRIDGE, "改装完成。"),
|
||
("port_poor", _BRIDGE, "功勋不够。"),
|
||
("port_back", _BRIDGE, "返回。"),
|
||
# ---- GR 组 · 航线选择 ----
|
||
("route_ask", _BRIDGE, "选择巡航航线。"),
|
||
("opt_route_safe", _BRIDGE, "稳妥航线,采集平平,太平。"),
|
||
("opt_route_rich", _BRIDGE, "矿富航线,采得多,磨损也多。"),
|
||
]
|
||
|
||
# 船员 NPC 单音色平铺(id, speaker, instruct, 台词)→ web/bridge/audio/voice/<id>.*
|
||
# 与旁白零 speaker 重叠(22b 头注);不加滤波;同一角色 speaker+instruct 恒定。
|
||
BRIDGE_NPC = [
|
||
# 大副(XO 34,Dylan)
|
||
("xo_fight", "Dylan", "干脆利落的年轻男声,星舰大副,令出必行,敬重舰长", "舰长,交给我,炮位就绪!"),
|
||
("xo_win", "Dylan", "干脆利落的年轻男声,星舰大副,令出必行,敬重舰长", "打得漂亮,这条航线够他们传一阵子。"),
|
||
("xo_uneasy", "Dylan", "干脆利落的年轻男声,星舰大副,令出必行,敬重舰长", "又是一路躲。舰长,弟兄们想打。"),
|
||
("xo_aid", "Dylan", "干脆利落的年轻男声,星舰大副,令出必行,敬重舰长", "驰援是应该的,星环号不是过路人。"),
|
||
# 工程师(ENG 52,Eric)
|
||
("eng_wear", "Eric", "沙哑厚重的中年男声,轮机工程师,惜船如命,慢条斯理", "老伙计累出毛病了,让我来。"),
|
||
("eng_fix", "Eric", "沙哑厚重的中年男声,轮机工程师,惜船如命,慢条斯理", "修好了,再听它稳稳地转。"),
|
||
("eng_sup", "Eric", "沙哑厚重的中年男声,轮机工程师,惜船如命,慢条斯理", "交给我,三分钟,给它救活。"),
|
||
("eng_gripe", "Eric", "沙哑厚重的中年男声,轮机工程师,惜船如命,慢条斯理", "护盾不是这么用的,舰长……"),
|
||
# 医师(DOC 38,Vivian)
|
||
("doc_aid", "Vivian", "温和坚定的女声,舰载医师,轻声但不容置疑", "幸好停了船,他们撑不了多久了。"),
|
||
("doc_ignore", "Vivian", "温和坚定的女声,舰载医师,轻声但不容置疑", "……我没有什么要说的。"),
|
||
("doc_care", "Vivian", "温和坚定的女声,舰载医师,轻声但不容置疑", "有伤员的地方,就有我。"),
|
||
("doc_trap", "Vivian", "温和坚定的女声,舰载医师,轻声但不容置疑", "有人拿求救当诱饵,小心。"),
|
||
]
|
||
|
||
# ---------------------------------------------------------------- teahouse
|
||
# 《深夜茶馆》批次 3(docs/design/20-teahouse-voice-ids.md,163 句:旁白 98 ×2 性别
|
||
# + NPC 平铺 65;键盘变体 V 组 10 对在 KEY_LINES["teahouse"])。
|
||
# 台词全文逐字照抄 voice-ids 文档;旁白只做系统/教学/状态/账目/氛围客转述(不念客人
|
||
# 台词);数字全分档整句无拼接;不加滤波(detective 先例:区分度靠 sig_* 前缀+
|
||
# speaker+instruct 三层冗余)。
|
||
_TEA = _pair("低沉温润的男声,深夜茶馆掌柜,从容安稳,像守着一炉将开的水",
|
||
"温润平和的女声,深夜茶馆掌柜,从容安稳,像守着一炉将开的水")
|
||
TEAHOUSE_LINES = [
|
||
# ---- G0 系统/菜单/帮助(10) ----
|
||
("sys_menu", _TEA, "菜单。单击切换,双击确认。"),
|
||
("sys_menu_resume", _TEA, "回到堂前。"),
|
||
("sys_menu_upg", _TEA, "打烊置办。"),
|
||
("sys_menu_save", _TEA, "保存并回大厅。"),
|
||
("sys_menu_help", _TEA, "重新听帮助。"),
|
||
("sys_saved", _TEA, "进度已保存。"),
|
||
("settings_hint", _TEA, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("sys_help", _TEA, "左右滑选茶,单击定下。听水声,双击提壶;滴答密,双击出汤。上滑状态,下滑菜单。"),
|
||
("sys_continue_ask", _TEA, "检测到没打烊的茶馆。单击继续,右滑两次重开新店。"),
|
||
("sys_reset_ask", _TEA, "重开新店?口碑和存款都从头来。再右滑一次,确认。"),
|
||
# ---- G1 开场/教学(17) ----
|
||
("intro_1", _TEA, "巷子最深处,有一盏亮到后半夜的灯。"),
|
||
("intro_2", _TEA, "你接手了这家茶馆。今晚,是它易主后的头一晚。"),
|
||
("intro_3", _TEA, "泡茶三步:选茶、候汤、出汤。手上的事,耳朵说了算。"),
|
||
("tut_d0", _TEA, "先看茶柜。左右滑,一罐一罐听。"),
|
||
("tut_tea", _TEA, "单击,选定这罐茶。"),
|
||
("tut_water", _TEA, "灶上坐水。泡泡细密是将沸,咕嘟连片是滚透——听到细密,双击提壶。"),
|
||
("tut_steep", _TEA, "注水,闷泡。滴答由稀到密,密起来就是将好——双击,出汤。"),
|
||
("tut_serve", _TEA, "茶好了。单击,端出去。"),
|
||
("tut_status", _TEA, "上滑,听今晚的局面:第几位客人,口碑如何;客人要的茶,上滑灶上随时再听。"),
|
||
("tut_done", _TEA, "都会了。往后每一晚,都这么泡。"),
|
||
("tut_skip", _TEA, "已跳过教学。左右滑选茶,单击选定,双击动手。"),
|
||
("water_early", _TEA, "急了,水还没醒透。这一步,偏了。"),
|
||
("water_ok", _TEA, "正是时候。"),
|
||
("water_late", _TEA, "水滚老了。这一步,偏了。"),
|
||
("steep_early", _TEA, "出急了,茶还睡着。这一步,偏了。"),
|
||
("steep_ok", _TEA, "出汤,正好。"),
|
||
("steep_late", _TEA, "闷过了,汤要发苦。这一步,偏了。"),
|
||
# ---- G2 状态/茶名(18) ----
|
||
("st_guest_1", _TEA, "今晚第一位客人。"),
|
||
("st_guest_2", _TEA, "今晚第二位客人。"),
|
||
("st_guest_3", _TEA, "今晚第三位客人。"),
|
||
("st_guest_4", _TEA, "今晚第四位客人。"),
|
||
("st_guest_5", _TEA, "今晚第五位客人。"),
|
||
("st_rep_1", _TEA, "口碑还没立起来,街坊不知道巷子里有这家茶馆。"),
|
||
("st_rep_2", _TEA, "有了回头客,口碑立住脚了。"),
|
||
("st_rep_3", _TEA, "巷子口都在传你的茶,小有名气。"),
|
||
("st_rep_4", _TEA, "一盏难求,茶客口耳相传。"),
|
||
("st_purse_1", _TEA, "钱箱见底,不到十文。"),
|
||
("st_purse_2", _TEA, "钱箱周转得开,不愁明日开销。"),
|
||
("st_purse_3", _TEA, "手头宽裕,二十五文往上。"),
|
||
("tea_longjing", _TEA, "龙井。绿茶性鲜:水将沸就提壶,出汤要快。"),
|
||
("tea_moli", _TEA, "茉莉花茶。香靠滚水激:水滚透再冲,出汤要快。"),
|
||
("tea_tieguanyin", _TEA, "铁观音。乌龙要滚水才醒,闷到滴答密了再出汤。"),
|
||
("tea_dianhong", _TEA, "滇红。红茶性暖,滚水冲,经得住闷,越闷越醇。"),
|
||
("tea_puer", _TEA, "普洱。老茶经泡:滚水才泡得开,多闷一会儿更醇。"),
|
||
("tea_yinzhen", _TEA, "白毫银针。嫩芽金贵:水将沸就提,闷到滴答密。"),
|
||
# ---- G3 泡茶衔接(5) ----
|
||
("brew_start", _TEA, "回到灶前。"),
|
||
("res_good", _TEA, "这一盏,泡得地道。"),
|
||
("res_plain", _TEA, "这一盏,泡得中平。"),
|
||
("res_wrong", _TEA, "这一盏,泡岔了——不是客人今晚要的那口。"),
|
||
("serve_link", _TEA, "你把茶端了过去。"),
|
||
# ---- G4 反应过场/氛围客人(9) ----
|
||
("bridge_good", _TEA, "客人把这盏茶喝得很慢,像是就着茶,把心事也喝顺了。"),
|
||
("bridge_plain", _TEA, "茶喝完了,客人点点头,起身。"),
|
||
("bridge_wrong", _TEA, "那盏茶凉在桌上,客人走的时候,没回头。"),
|
||
("amb_1", _TEA, "车铃一响,晚班的邮差探进头来。老规矩:茉莉花茶,要滚烫的。"),
|
||
("amb_2", _TEA, "门帘一挑,绣坊的阿姐收了工,想喝一盏清火的龙井。"),
|
||
("amb_3", _TEA, "巷口的醉汉扶着门框,含含糊糊,只嚷嚷要最浓的滇红。"),
|
||
("amb_react_good", _TEA, "他喝得很慢,末了多搁下两文。"),
|
||
("amb_react_plain", _TEA, "他喝完,点点头,搁下茶钱。"),
|
||
("amb_react_wrong", _TEA, "他抿了一口,搁下半盏,晃出去了。"),
|
||
# ---- G5 打烊/经济/置办(16) ----
|
||
("close_open", _TEA, "客人走尽了。收壶,打烊。"),
|
||
("close_coin_1", _TEA, "今晚进账,不到十五文。"),
|
||
("close_coin_2", _TEA, "今晚进账,十五到二十四文。"),
|
||
("close_coin_3", _TEA, "今晚进账,二十五文往上。"),
|
||
("rent_due", _TEA, "今天是房钱的日子,这一回,二十文。"),
|
||
("rent_ok", _TEA, "房钱交清,秦婶没多话。"),
|
||
("rent_short", _TEA, "房钱不够,差的那几文先记在账上。秦婶撂下一句:下回一起算。"),
|
||
("debt_clear", _TEA, "旧账清了,秦婶把那一页翻了过去。"),
|
||
("st_debt_1", _TEA, "账上,还欠着秦婶的钱。"),
|
||
("settle_night", _TEA, "熄了灯,这一晚就过去了。单击,睡下。"),
|
||
("upg_open", _TEA, "要添置点什么?左右滑看,单击买定。"),
|
||
("upg_cabinet", _TEA, "茶柜扩容,十五文。往后普洱、白毫银针,都上柜。"),
|
||
("upg_teaware", _TEA, "添一副新茶具,十二文。手上更准,火候窗更宽。"),
|
||
("upg_sign", _TEA, "立一块招牌,二十文。要口碑立得住——十二分往上才挂。"),
|
||
("upg_none", _TEA, "眼下的钱和账,还置办不起。改日再说。"),
|
||
("upg_lock", _TEA, "招牌还挂不得:口碑得十二分往上,欠账也得清。"),
|
||
# ---- G6 看门狗/纠错/复述(6) ----
|
||
("gd_serve", _TEA, "客人还在堂前。上滑,再听一遍他要的茶。"),
|
||
("gd_brew", _TEA, "还在灶上,听声动手,双击。"),
|
||
("gd_close", _TEA, "账报完了。单击,熄灯睡下。"),
|
||
("gd_invalid", _TEA, "这个操作,这里用不上。"),
|
||
("hint_water", _TEA, "水听两遍:泡泡细密是将沸,咕嘟连片是滚透。"),
|
||
("recap_go", _TEA, "接着张罗。"),
|
||
# ---- G7 晚数/章节(7) ----
|
||
("night_1", _TEA, "头一晚。灯亮了,水坐上,茶馆开门。"),
|
||
("night_2", _TEA, "第二晚。老客们,已经认得这条巷子。"),
|
||
("night_3", _TEA, "第三晚。今天,是收房钱的日子。"),
|
||
("night_4", _TEA, "第四晚。熟客进门,都不用问位子了。"),
|
||
("night_5", _TEA, "第五晚。这一章的夜,快要听全了。"),
|
||
("night_more", _TEA, "又一夜。灯还亮着,茶还热着。"),
|
||
("chapter_end", _TEA, "第一章完。这条巷子的夜,你都听过了。茶馆的故事,还长。"),
|
||
]
|
||
|
||
# NPC 单音色平铺(id, speaker, instruct, 台词)→ web/teahouse/audio/voice/<id>.*
|
||
# 5 位弧线客人(20-teahouse-voice-ids.md 头注区分度表):speaker+instruct 恒定,不滤波。
|
||
_ZHOU = ("Eric", "沙哑洪亮的男声,修车铺老师傅,大嗓门,直爽热乎")
|
||
_SU = ("Vivian", "轻柔平稳的女声,夜班护士,温和疲惫,吐字干净")
|
||
_SHI = ("Dylan", "年轻清亮的男声,高三学生,紧张,语速快,有点怯")
|
||
_BAI = ("Uncle_Fu", "苍老缓慢的男声,独居老先生,慢条斯理,带茶韵")
|
||
_HE = ("Serena", "低哑爽利的女声,夜班出租车司机,利落,带笑带倦")
|
||
TEAHOUSE_NPC = [
|
||
# 老周(13)
|
||
("zhou_enter", *_ZHOU, "小掌柜!老位置,还给我留着呢吧?"),
|
||
("zhou_o1", *_ZHOU, "修了一天车,嗓子眼里全是机油味。就你那龙井,给我去去火。"),
|
||
("zhou_r1_good", *_ZHOU, "嚯!就是这个味儿!多谢啦,小掌柜。"),
|
||
("zhou_r1_plain", *_ZHOU, "嗯……还行。今天手底下,差了点意思。"),
|
||
("zhou_r1_wrong", *_ZHOU, "这是我要的龙井吗?……算了算了,凑合喝。"),
|
||
("zhou_o2", *_ZHOU, "今天冷。来盏顶饱的、浓的,扛饿又扛冻。"),
|
||
("zhou_r2_good", *_ZHOU, "对喽,暖到脚后跟了!跟你说——我儿子今天来电话了。"),
|
||
("zhou_r2_plain", *_ZHOU, "茶是茶,水是水,差点火候。儿子的事,改天再说吧。"),
|
||
("zhou_r2_wrong", *_ZHOU, "……今晚这盏不对。儿子的事,不说也罢。"),
|
||
("zhou_o3", *_ZHOU, "今晚就想要头一回那盏。一样的,再来一份。"),
|
||
("zhou_e_a", *_ZHOU, "明天铺子歇一天,儿子回来帮我盘货。这盏茶,记你头上了!"),
|
||
("zhou_e_b", *_ZHOU, "电话里跟儿子拌了两句嘴。没事——茶还热着,日子还长。"),
|
||
("zhou_e_c", *_ZHOU, "铺子我想关了,儿子叫我过去帮工。茶馆的灯,替我多亮会儿。"),
|
||
# 苏晚(13)
|
||
("su_enter", *_SU, "请问……还营业吗?我刚下夜班。"),
|
||
("su_o1", *_SU, "胃里发凉,人空荡荡的。想要一盏暖的,别太冲,喝完好睡。"),
|
||
("su_r1_good", *_SU, "好暖……像被窝里塞了个汤婆子。谢谢你。"),
|
||
("su_r1_plain", *_SU, "嗯,是热乎的。今晚,凑合能睡。"),
|
||
("su_r1_wrong", *_SU, "这盏……有点寒。没关系,是我没说清。"),
|
||
("su_o2", *_SU, "今晚换个口味,想要香的。可我还得眯一会儿才接班。"),
|
||
("su_r2_good", *_SU, "真香啊……今夜走了位老人,家属拉着我的手道谢。这盏茶,敬他们。"),
|
||
("su_r2_plain", *_SU, "茶还行。今夜病房平静,平静得累人。"),
|
||
("su_r2_wrong", *_SU, "香气没出来……像我今晚的运气。算了。"),
|
||
("su_o3", *_SU, "最后一晚了,明天起不用值夜班。还是头一回那种,暖的。"),
|
||
("su_e_a", *_SU, "我调去白天班啦,还能常来。给你带我们科的喜糖。"),
|
||
("su_e_b", *_SU, "还在犹豫,夜班再值一季。好在这盏茶,够我撑到天亮。"),
|
||
("su_e_c", *_SU, "我递了辞呈,往后去哪还没想好。但今晚茶馆的灯,我记住了。"),
|
||
# 陈拾(13)
|
||
("shi_enter", *_SHI, "老板……还有位子吗?我背单词,背得头疼。"),
|
||
("shi_o1", *_SHI, "想喝点香的提提神,但别太浓——喝完回家还得睡,明天早读。"),
|
||
("shi_r1_good", *_SHI, "好香!脑子清醒了。这是我攒的早饭钱……值了。"),
|
||
("shi_r1_plain", *_SHI, "还行吧。单词它还是不进脑子。"),
|
||
("shi_r1_wrong", *_SHI, "有点苦……没事,我泡的方便面更苦。"),
|
||
("shi_o2", *_SHI, "模拟考砸了,心里烧得慌。想喝口最清火的。"),
|
||
("shi_r2_good", *_SHI, "凉丝丝的,火气下去一半。老板,你说我还能考上吗?……算了,当我没问。"),
|
||
("shi_r2_plain", *_SHI, "茶一般,我也一般,挺配的。"),
|
||
("shi_r2_wrong", *_SHI, "不是这个味儿……回家还得接着刷题。"),
|
||
("shi_o3", *_SHI, "考完了!今晚想喝口金贵的,犒劳自己。"),
|
||
("shi_e_a", *_SHI, "成绩出来了,比模拟考高了四十多分!这盏茶,算我请全茶馆的!"),
|
||
("shi_e_b", *_SHI, "考完了,心里反倒空荡荡的。去哪读书,听爸妈安排吧。"),
|
||
("shi_e_c", *_SHI, "考砸了,茶也不对味……但至少,这儿的灯一直亮着。"),
|
||
# 白老先生(13)
|
||
("bai_enter", *_BAI, "小掌柜,给我的紫砂壶,留个座。"),
|
||
("bai_o1", *_BAI, "晚饭积了食。要一盏刮油的、经得住泡的,我喝得慢。"),
|
||
("bai_r1_good", *_BAI, "好茶,有回甘。像我家老婆子腌的萝卜干,越嚼越有味。"),
|
||
("bai_r1_plain", *_BAI, "嗯,茶汤尚可。人老了,舌头也钝了。"),
|
||
("bai_r1_wrong", *_BAI, "这不是我要的那口。不怪你——是我话没说全。"),
|
||
("bai_o2", *_BAI, "昨儿那盏不错。今晚想喝口陈的,越陈越好。"),
|
||
("bai_r2_good", *_BAI, "陈味出来了。四十年前,我跟老婆子初见,就是一盏普洱。"),
|
||
("bai_r2_plain", *_BAI, "茶汤淡了些。故事嘛,等茶好了再说。"),
|
||
("bai_r2_wrong", *_BAI, "……不是我惦记的那口。罢了,回家睡了。"),
|
||
("bai_o3", *_BAI, "就馋那口陈味。老伙计,看你的手艺了。"),
|
||
("bai_e_a", *_BAI, "明儿我把棋盘搬来,你这儿灯亮,我天天来摆谱——就当,她还在看着。"),
|
||
("bai_e_b", *_BAI, "回去还是那间空屋子。不过睡前有盏茶垫着,梦能沉一点。"),
|
||
("bai_e_c", *_BAI, "下个月,我搬去养老院了。这把紫砂壶,留给茶馆吧。"),
|
||
# 何雨眠(13)
|
||
("he_enter", *_HE, "师傅,门口能停车不?——哦,我是说,喝茶。"),
|
||
("he_o1", *_HE, "跑了一宿,眼睛发涩,脑子发木。要一盏清口的,不要浓的。"),
|
||
("he_r1_good", *_HE, "清亮,像拿凉水洗了把脸。今晚最后一单,稳了。"),
|
||
("he_r1_plain", *_HE, "一般吧,能开就行。"),
|
||
("he_r1_wrong", *_HE, "不是这口……算了,我还得赶路。"),
|
||
("he_o2", *_HE, "今晚不打算睡了,还要跑单。要最浓的,越浓越好。"),
|
||
("he_r2_good", *_HE, "得劲儿!闺女的照片就贴在方向盘上——再跑俩月,学费就齐了。"),
|
||
("he_r2_plain", *_HE, "不够劲,今晚里程表怕是要难看。"),
|
||
("he_r2_wrong", *_HE, "淡了。算了,我赶时间。"),
|
||
("he_o3", *_HE, "最后一趟车收工。想要一盏柔的,收收心。"),
|
||
("he_e_a", *_HE, "学费攒齐了,明天去看闺女。老师说她考了年级前十——这盏,我慢慢喝。"),
|
||
("he_e_b", *_HE, "钱还差一点,再跑一个月。茶馆这盏灯,是我每晚的路标。"),
|
||
("he_e_c", *_HE, "我把夜班退了。闺女在电话里说:妈,钱够用。这盏茶,我喝得最慢。"),
|
||
]
|
||
|
||
# ---------------------------------------------------------------- keeper
|
||
# 《守塔人》批次 4(docs/design/21-keeper-voice-ids.md,148 句:双性别 121 = KEEPER 守塔人 42
|
||
# + SHORE 岸台/系统 79,含 `_k` 键盘变体 8 对 + 平铺 NPC 27 = 阿澈 19 / 父亲 3 / 祖父 5)。
|
||
# 台词全文逐字照抄 voice-ids 文档;双性别组分 KEEPER(玩家)/ SHORE(岸台值班员=向导人设)
|
||
# 两个 speaker 配对(同性别双音色,VOICE_SPK["keeper"] 逐句覆盖,radio HOST/PROD 同型:
|
||
# female 侧守塔人 Serena / 岸台 Vivian、male 侧守塔人 Uncle_Fu / 岸台 Dylan,同场景永不同 speaker);
|
||
# `_k` 变体 8 对在 KEY_LINES["keeper"](措辞「方向键/空格/回车」,abyss §G0.a 同型)。
|
||
# NPC 平铺 27 句,转码时按 21b 头注 §滤波表 带通(NPC_BANDPASS["keeper"]):
|
||
# 阿澈=电台 350-3200 / 父亲=唱片 300-2800 / 祖父=唱片 250-2600(+轻压缩,宁窄勿脏);
|
||
# 锚句(rev_g1/g4、rev_f1/f5、rev_c1/c5)是 KEEPER 双性别行、不滤波(「现在的你」在回忆里旁白)。
|
||
_KEEPER = _pair("沉静克制的男声,孤岛守塔人,低而稳,藏着心事",
|
||
"沉静克制的年轻女声,孤岛守塔人,低而稳,藏着心事")
|
||
_SHORE = _pair("清晰平稳的男声,海岸电台值班员,隔着无线电的温和干练",
|
||
"清晰平稳的女声,海岸电台值班员,隔着无线电的温和干练")
|
||
|
||
KEEPER_K_LINES = [
|
||
# ---- G1 开场(2) ----
|
||
("b_open", _KEEPER, "白角灯塔,风暴夜。我是今晚的守塔人。"),
|
||
("b_rain", _KEEPER, "浪拍到第七级台阶。雾角两长一短——塔在,我也在。"),
|
||
# ---- C1 幕一(8) ----
|
||
("c1_hold", _KEEPER, "别慌。我在白角,哪儿也不去。慢慢说。"),
|
||
("c1_ask", _KEEPER, "顺发号,报你的方位,报进水的速度。"),
|
||
("c1_open", _KEEPER, "父亲的钥匙,就在抽屉里。灯座第三级,开了。"),
|
||
("rev_teach", _KEEPER, "听到唱针落下、风声退后,是回忆。风声回来,就是现在。"),
|
||
("rev_g1", _KEEPER, "唱针落下。四十年前,也是这盏灯下。"),
|
||
("rev_g4", _KEEPER, "风声回来了。爷爷,我听见了。"),
|
||
("c1_diary", _KEEPER, "暗格里是祖父的日志。缺了最后一页。"),
|
||
("c1_focus", _KEEPER, "先守住这盏灯。旧账,天亮再算。"),
|
||
# ---- C2 幕二(9) ----
|
||
("c2_song", _KEEPER, "跟我念:浪头过,船头抬。浪头退,船头落。"),
|
||
("rev_f1", _KEEPER, "唱针又落下了。十二年前,也是这样的风。"),
|
||
("rev_f5", _KEEPER, "风声回来了。那扇门,留到今天。"),
|
||
("c2_key", _KEEPER, "父亲桌上那支手电,尾盖里卷着一页纸。"),
|
||
("c2_shore", _KEEPER, "岸台,记下他的船位。请渔政天亮前到。"),
|
||
("c4_true", _KEEPER, "我父亲也是守塔人。十二年前风暴夜,他出海救人,没有回来。"),
|
||
("c4_pass", _KEEPER, "家里人?都在大陆。这行当,习惯了。"),
|
||
("c5_patch", _KEEPER, "拿堵漏垫顶住裂缝。人守在电台边,我一直在。"),
|
||
("c5_suit", _KEEPER, "穿上救生衣,带上信号灯,站到甲板上去。"),
|
||
# ---- C3 幕三(11) ----
|
||
("c3_page", _KEEPER, "手电的尾盖旋开了。那页纸,在灯下摊平。"),
|
||
("rev_c1", _KEEPER, "唱针落下。缺的那一页,自己开了口。"),
|
||
("rev_c5", _KEEPER, "风声回来了。原来那道家规,是这么来的。"),
|
||
("c6_shut", _KEEPER, "合上。守塔人的事,守塔人自己扛。"),
|
||
("c7_go", _KEEPER, "机械上满发条,灯能自己转到天亮。等着我。"),
|
||
("c7_go2", _KEEPER, "发条……我只上了半卷。快去,快回。"),
|
||
("c7_hold", _KEEPER, "顺发号,听我的。灯照着的那条道,跟我念,一步一步来。"),
|
||
("c8_song", _KEEPER, "他爷爷传下的渔歌……在哪?再唱一遍!"),
|
||
("c8_math", _KEEPER, "坐标向东两百米。灯光扫过去,看见救生衣了!"),
|
||
("c8_old", _KEEPER, "走老航道。多绕半里,绕开所有的暗礁。"),
|
||
("c8_new", _KEEPER, "数三个浪头,借着风的角度,钻新缝!"),
|
||
# ---- D9 签收(4) ----
|
||
("g9_knot", _KEEPER, "十二年了。这一晚,我总算替父亲,站完了他的班。"),
|
||
("d9_tell_a", _KEEPER, "四十年前守塔的,是我爷爷。他离灯去救自己的儿子。灯灭那刻,回澜号……对不住。"),
|
||
("d9_tell_b", _KEEPER, "我只知道,那晚守塔的是我爷爷,灯灭过一下。剩下的,我也不敢说全。"),
|
||
("d9_keep", _KEEPER, "那晚风太大,灯出了点故障。别再问了,孩子,回家吧。"),
|
||
# ---- EP 结局主句+钩子(8) ----
|
||
("e1_a", _KEEPER, "天亮了。他在门厅睡熟,那页纸攥在手里。灯,亮到了最后一刻。"),
|
||
("e1_b", _KEEPER, "回澜号的账,翻开了第一页。这座塔,等了四十年。"),
|
||
("e2_a", _KEEPER, "他走的时候,天刚亮。我送到码头,什么也没说。"),
|
||
("e2_b", _KEEPER, "缺页放回灯底。有些东西,再压一代人。灯,还转着。"),
|
||
("e3_a", _KEEPER, "我把知道的,都说了。他望着海,半信半疑地点头。"),
|
||
("e3_b", _KEEPER, "碎片也是真话。剩下的,让海自己讲吧。"),
|
||
("e4_a", _KEEPER, "天亮,各自归位。他回他的港,我守我的灯。"),
|
||
("e4_b", _KEEPER, "隔着一道海,两座塔,谁也没再提那晚。"),
|
||
]
|
||
|
||
KEEPER_S_LINES = [
|
||
# ---- G0.a 操作提示句(7,_k 变体在 KEY_LINES) ----
|
||
("gd_brief", _SHORE, "单击,继续值守。要选择时,向左或向右滑。"),
|
||
("gd_continue", _SHORE, "单击屏幕,继续。"),
|
||
("gd_again", _SHORE, "还在吗?单击继续。"),
|
||
("sys_help", _SHORE, "单击继续,双击重新听。上滑听状态,下滑开菜单。选择时,左右滑。"),
|
||
("sys_menu", _SHORE, "菜单。单击切换选项,双击确认。"),
|
||
("sys_skip", _SHORE, "想跳过这句,单击就行。"),
|
||
("sys_continue_ask", _SHORE, "检测到你的值守记录。单击继续上次,右滑开始新的风暴夜。"),
|
||
# ---- G0.b 状态/系统句(20) ----
|
||
("gd_invalid", _SHORE, "这个手势,塔里用不上。"),
|
||
("gd_prog1", _SHORE, "滑动这里用不上。想想岸台刚说的话。"),
|
||
("gd_prog2", _SHORE, "别乱。停一停,再听一遍。"),
|
||
("sys_menu_resume", _SHORE, "回到值守。"),
|
||
("sys_menu_restart", _SHORE, "重新开始今夜。"),
|
||
("sys_menu_lobby", _SHORE, "保存并回大厅。"),
|
||
("sys_settings", _SHORE, "音色、语速、背景音乐,请回大厅修改。"),
|
||
("sys_new_night", _SHORE, "新的风暴夜,开始了。"),
|
||
("prog_m1", _SHORE, "风暴起来了。今晚第一程。"),
|
||
("prog_m2", _SHORE, "风暴到顶。第二程。"),
|
||
("prog_m3", _SHORE, "风在退。最后一程。"),
|
||
("prog_mem_g", _SHORE, "这是回忆:祖父的年代,四十年前。"),
|
||
("prog_mem_f", _SHORE, "这是回忆:父亲的最后一晚,十二年前。"),
|
||
("tr_deep", _SHORE, "他把命,交给了你的声音。"),
|
||
("tr_half", _SHORE, "他信一半,疑一半。"),
|
||
("tr_thin", _SHORE, "今晚,他只信自己的手。"),
|
||
("tru_zero", _SHORE, "旧账压在灯底,你一页没翻。"),
|
||
("tru_one", _SHORE, "灯下的旧账,你翻开了一角。"),
|
||
("tru_two", _SHORE, "祖父和父亲的事,你都翻到了。"),
|
||
("tru_full", _SHORE, "三代人的账,今夜见底了。"),
|
||
# ---- G1 开场(2) ----
|
||
("b_rule", _SHORE, "岸台的规矩就一条:风暴夜,灯不能灭。"),
|
||
("b_goal", _SHORE, "今夜两艘货轮过境。守住灯,也守住频道。"),
|
||
# ---- C1 幕一(8,含 p1) ----
|
||
("c1_tune", _SHORE, "频道里有动静。很轻,像隔着整片海。"),
|
||
("p1", _SHORE, "他的声音在抖。向左滑,先接住这个人。向右滑,先要他的船位。"),
|
||
("c1_holde", _SHORE, "他喘匀了。先接人,再办事。"),
|
||
("c1_aske", _SHORE, "他更慌了。人没接住,数字也乱。"),
|
||
("p2", _SHORE, "他提到四十年前。向左滑,去翻灯座下的暗格。向右滑,先专心守灯。"),
|
||
("c1_focuse", _SHORE, "灯转得稳。可那句「灭过一下」,留在了你耳朵里。"),
|
||
("lull_1", _SHORE, "岸台通报:风加到十级。第一程,过去了。"),
|
||
# ---- C2 幕二(7) ----
|
||
("c2_back", _SHORE, "频道又响了。顺发号的引擎,时断时续。"),
|
||
("p3", _SHORE, "他快撑不住了。向左滑,用守塔人的口诀带他稳船。向右滑,把船位报给岸台。"),
|
||
("c2_shoreo", _SHORE, "船位落在图上了。渔政的船,最快也要天亮。"),
|
||
("p4", _SHORE, "他问起你的人。向左滑,告诉他真话。向右滑,轻轻带过。"),
|
||
("c2_crack", _SHORE, "听!他那边,船板裂了!"),
|
||
("p5", _SHORE, "船在漏。向左滑,让他回舱堵漏,守住电台。向右滑,让他穿救生衣,上甲板。"),
|
||
("lull_2", _SHORE, "风眼凌晨过境。第二程,到顶了。"),
|
||
# ---- C3 幕三(12) ----
|
||
("c3_eye", _SHORE, "风眼过了。最后的浪墙,就跟在后面。"),
|
||
("m6_seal", _SHORE, "那些旧东西,你今晚没碰过。缺页的事,你一无所知。"),
|
||
("p6", _SHORE, "祖父的最后一页。向左滑,今晚就读完它。向右滑,合上,塞回灯底。"),
|
||
("c6_reade", _SHORE, "四十年,两代人,一条规矩。今晚,轮到你选了。"),
|
||
("p7", _SHORE, "浪墙压过来了。向左滑,给灯上满发条,驾接驳艇去接他。向右滑,守着灯,用声音引他过礁。"),
|
||
("c3_wall", _SHORE, "浪墙起来了!就是现在!"),
|
||
("p8_boat", _SHORE, "海上没有灯。向左滑,循着他哼的渔歌找他。向右滑,按推算的坐标,直线搜。"),
|
||
("p8_reef", _SHORE, "礁缝两道口。向左滑,走老航道,稳但绕远。向右滑,钻新缝,近但冒险。"),
|
||
("c9_return", _SHORE, "接驳艇回来了。两个人,一身水,一盏灯。"),
|
||
("c3_dark", _SHORE, "你离塔的时候,发条走到了头。灯,灭过一刻钟。过境的货轮,平安。"),
|
||
("c9_land", _SHORE, "顺发号过了礁缝,搁上背风湾的滩。人,站上了岸。"),
|
||
("c9_found", _SHORE, "他在半路改了主意。天亮时,渔队找到了他。活着,湿透了。"),
|
||
# ---- D9 签收(5) ----
|
||
("g9_in", _SHORE, "风,一层一层退下去。天边,有点灰了。"),
|
||
("p9a", _SHORE, "他问起四十年前的灯。向左滑,把缺页的事,连根说给他。向右滑,就说,那晚风太大。"),
|
||
("p9b", _SHORE, "他问起四十年前的灯。你知道的,只有碎片。向左滑,把碎片给他。向右滑,说风太大。"),
|
||
("d9_telle", _SHORE, "他听完,沉默了很久。天,亮了。"),
|
||
("d9_keepe", _SHORE, "这个话题,沉回了海里。天,亮了。"),
|
||
# ---- EP 尾声回响(11) ----
|
||
("ep_lead", _SHORE, "风停了。岸台给你记一笔——这一晚,后来怎样了。"),
|
||
("ep_amo_home", _SHORE, "阿澈:那晚之后改跑日班。他说,夜里的海,有守塔人听着。"),
|
||
("ep_amo_solo", _SHORE, "阿澈:自己把船开上了背风湾。船主骂了船,没骂人。"),
|
||
("ep_amo_dawn", _SHORE, "阿澈:抱着冷藏柜漂到天亮。打那以后,出海带两台电台。"),
|
||
("ep_lamp_full", _SHORE, "灯塔记录簿:你离塔三刻,灯自己转着。父亲的发条,说中了。"),
|
||
("ep_lamp_dark", _SHORE, "灯塔记录簿:凌晨两点,灯灭一刻钟。那一行,你写得格外用力。"),
|
||
("ep_lamp_hold", _SHORE, "灯塔记录簿:转灯整夜未停。你一步,也没离开过它。"),
|
||
("ep_log_told", _SHORE, "灯下的旧账,今夜见了光。"),
|
||
("ep_log_kept", _SHORE, "灯下的旧账,又压回了黑暗里。"),
|
||
("ep_dad", _SHORE, "值班表上,你替十二年前那个班次签了字。老陈,收工了。"),
|
||
("ep_shore", _SHORE, "岸台晨报:风暴过境,航道平安。白角灯,正常。"),
|
||
]
|
||
|
||
KEEPER_LINES = KEEPER_K_LINES + KEEPER_S_LINES
|
||
|
||
# NPC 单音色平铺(id, speaker, instruct, 台词)→ web/keeper/audio/voice/<id>.*
|
||
#(转码时按 21b 头注滤波表带通,见 NPC_BANDPASS["keeper"];staging 保留未滤波原声)。
|
||
_AMO = "年轻男声,二十二岁渔民,海风养出的嗓子,风暴里喊话,慌而不乱"
|
||
_DAD = "温和低沉的男声,四十岁守塔人,隔着老唱片,疲惫而坚定"
|
||
_GRAND = "苍老缓慢的男声,七十岁老守塔人,隔着更老的唱片,字字压秤"
|
||
KEEPER_NPC = [
|
||
# 阿澈(22 岁渔民,现在线·电台,Dylan,19 句)
|
||
("amo_a", "Dylan", _AMO, "……有人吗……顺发号……船进水了……"),
|
||
("amo_b", "Dylan", _AMO, "白角塔!是你吗?求你,回个话!"),
|
||
("c1_holdo", "Dylan", _AMO, "……好,好。你在。我听见了。"),
|
||
("c1_asko", "Dylan", _AMO, "方位……仪表进水了,我,我看不清……"),
|
||
("amo_c", "Dylan", _AMO, "我爷爷,四十年前也是在这片海没的。他说,白角的灯灭过一下。"),
|
||
("amo_d", "Dylan", _AMO, "塔……听得到吗?水,到膝盖了。"),
|
||
("c2_songo", "Dylan", _AMO, "浪头过,船头抬……真的稳了些!这口诀,谁教你的?"),
|
||
("amo_e", "Dylan", _AMO, "守塔人……塔里就你一个人?家里人不拦着你干这行?"),
|
||
("c4_trueo", "Dylan", _AMO, "……对不起。难怪今晚,你一直都在。"),
|
||
("c4_passo", "Dylan", _AMO, "哦……你也是一个人守夜。我们俩,隔着一道海。"),
|
||
("amo_f", "Dylan", _AMO, "裂了!水进得更快了。塔,告诉我怎么办!"),
|
||
("c5_patcho", "Dylan", _AMO, "顶住了!水慢下来了。我不走,守着电台。"),
|
||
("c5_suito", "Dylan", _AMO, "穿好了。要是船散了,我就抱着它漂。"),
|
||
("c8_songo", "Dylan", _AMO, "海风那个吹呀——塔!是你吗?我在这儿!"),
|
||
("c8_matho", "Dylan", _AMO, "塔!你的灯扫到我啦!我在这边!"),
|
||
("c8_oldo", "Dylan", _AMO, "老航道……我爷爷念叨过这条道!稳了!"),
|
||
("c8_newo", "Dylan", _AMO, "一个,两个,三——过去了!塔,我过来了!"),
|
||
("amo_g", "Dylan", _AMO, "……我爷爷,就在那七个人里。难怪他到死,都念着白角的灯。"),
|
||
("amo_h", "Dylan", _AMO, "风太大……嗯。那晚的风,一定很大。"),
|
||
# 父亲(回忆·十二年前,Uncle_Fu,3 句)
|
||
("rev_f2", "Uncle_Fu", _DAD, "白角塔,我是老陈。接驳艇上两个人,都活着。"),
|
||
("rev_f3", "Uncle_Fu", _DAD, "守塔人听见了求救,就不能装没听见。等我回来。"),
|
||
("rev_f4", "Uncle_Fu", _DAD, "塔上的机械上满发条,能自己转一夜。给我留着门。"),
|
||
# 祖父(回忆·四十年前,Eric,5 句)
|
||
("rev_g2", "Eric", _GRAND, "手稳住。灯罩擦到第三遍,才算干净。"),
|
||
("rev_g3", "Eric", _GRAND, "记住,灯下压着的东西,比灯重。守塔人,替它守一辈子。"),
|
||
("rev_c2", "Eric", _GRAND, "我写下这些,等一个敢看的人。那晚,我的儿子,偷了接驳艇。"),
|
||
("rev_c3", "Eric", _GRAND, "我去追他。灯,离了人。半个时辰,回澜号,七个人。"),
|
||
("rev_c4", "Eric", _GRAND, "儿子回来了。这页我撕下来,压进灯底。守塔人,不能离灯。"),
|
||
]
|
||
|
||
NPCS = {"rpg": RPG_NPC, "radio": RADIO_NPC, "abyss": ABYSS_NPC, "detective": DETECTIVE_NPC,
|
||
"hunt": HUNT_NPC, "cipher": CIPHER_NPC, "bridge": BRIDGE_NPC, "teahouse": TEAHOUSE_NPC,
|
||
"keeper": KEEPER_NPC}
|
||
|
||
# ---------------------------------------------------------------- 键盘变体(P1 路线 a)
|
||
# 「生效输入模式=键盘」的玩家听按键措辞:向左滑→按左方向键(四向同理,WASD 不进
|
||
# 台词);单击/轻触屏幕→按空格;双击→按回车;按住/长按→按住空格。只改操作词,
|
||
# 其余内容一字不动(复合短语「左右滑」→「左右方向键」等按语义等价展开;确需
|
||
# 补一两个连接字才成句处已在 docs/design/*-voice-ids.md「键盘变体」小节逐句登记)。
|
||
# 主表为叙事误用(非操作指令)的句子不做变体:storyline n16/n16b(「滑了过去」
|
||
# 「按住他的膝盖」)、n17/n17b(「更滑」)。
|
||
# 双表一致铁律:本表与 docs/design/*-voice-ids.md「键盘变体」小节必须逐字一致。
|
||
KEY_LINES = {
|
||
"storyline": [
|
||
("help", "操作说明。按空格:继续剧情。按回车:重听刚才的台词。按上方向键:听这段说明和当前进度。按下方向键:呼出菜单,菜单里可以重新开始。当旁白说“请选择”的时候,按左方向键或者按右方向键,做出你的决定。选择无法撤销。"),
|
||
("menu", "菜单。按左方向键:重新开始整个故事。按右方向键,或者按空格:回到故事。按上方向键:听操作说明。"),
|
||
("p1", "请选择。按左方向键:先检查背包里的收音机。按右方向键:先摸黑寻找出口。"),
|
||
("p2", "请选择。按左方向键:钻进旁边的通风管道。按右方向键:躺进路边的尸体堆里装死。"),
|
||
("p3", "请选择。按左方向键:循着哭声过去看看。按右方向键:不去管它,直接去北区。"),
|
||
("p4", "请选择。按左方向键:带上小满一起走。按右方向键:留下食物,独自上路。"),
|
||
("p5", "请选择。按左方向键:走桥下的污水涵洞。按右方向键:爬桥上悬着的钢索。"),
|
||
("p6", "请选择。按左方向键:交出坐标,保命要紧。按右方向键:拒绝他,想办法周旋。"),
|
||
("p7", "请选择。按左方向键:追上去,警告避难所。按右方向键:自己逃命,越远越好。"),
|
||
("p8", "请选择。按左方向键:用公开频道广播,让全城都听见。按右方向键:用加密频段,只发给避难所。"),
|
||
("n00_intro", "大停电后的第三十天,城市陷入彻底的黑暗。没有电,没有网络,只有收音机里偶尔闪过的沙沙声,像垂死者的呼吸。你是林晚,一名前急救员。在这个故事里,你用声音活下去。请记住:按空格,继续剧情;按回车,重听上一句;按上方向键,听你的状态和帮助;按下方向键,呼出菜单。当我说“请选择”的时候,按左方向键,或者按右方向键,做出你的决定。选择一旦做出,就无法回头。现在,按空格,睁开眼睛。"),
|
||
("e1_dawn", "加密频道那头沉默了三秒。然后,一个你等了三十天的声音响了起来:“姐?姐!是你吗?”天亮之前,避难所的救援队打开了大门。猎狗的人,在北区的高墙下溃散了。你抱着晨晨,听见广播塔里,重新响起了音乐。后来人们说,这座城市,是从一个女人的声音开始,重新活过来的。——好结局:黎明。感谢你,陪林晚走完了这条路。按空格,可以回到故事开始的地方。"),
|
||
("e2_price", "你赶在车队前面,撞进了避难所的大门。“关掉广播!关灯!猎狗来了——!”那一夜,北区守住了。探照灯熄灭的时候,晨晨从人群里扑出来抱住你,才发现你胳膊上的血,已经把半边袖子浸透了。坐标是你交出去的,命,是你抢回来的。你赢了,用一条胳膊的代价。——结局:代价。按空格,重新开始。"),
|
||
("e3_alone", "你逃了。一路向南,没有回头。三天后,收音机里关于北区的广播,停了。又过了七天,你在一个废弃的加油站里,听见最后一个频段,也变成了沙沙声。你活下来了。只是从此以后的每一个夜里,你都会想起那声口哨,和你报出坐标时,自己发抖的声音。——坏结局:孤声。按空格,重新开始。"),
|
||
("e4_static", "公开频道,把所有人都引来了——幸存者,还有猎狗。塔顶的风很大,你看见山下火把连成的长龙,也看见避难所方向亮起的防御火光。猎狗的刀抵上来的时候,你对着麦克风笑了:“听见了吗,晨晨?姐姐的声音,全城都听见了。”信号中断了。但那晚之后,北区,再没有人投降。——结局:静默。按空格,重新开始。"),
|
||
("skip_hint", "按空格可跳过旁白。"),
|
||
("gd_continue", "按空格,继续。"),
|
||
("gd_brief", "按空格继续剧情。请选择的时候,按左右方向键。"),
|
||
("gd_again", "还在吗?按空格继续。"),
|
||
],
|
||
"escape": [
|
||
("g1_move", "先活动一下。按任意方向键,走一小步。"),
|
||
("g2_wall", "这个房间不大,四面都是墙。再按两下方向键,试试碰碰墙。"),
|
||
("g3_left", "跟着我指的路走。按左方向键。"),
|
||
("g4_down", "对。再按下方向键。"),
|
||
("g5_inspect", "听到水声了吗?按一下空格,仔细检查这个房间。"),
|
||
("g6_doubletap", "钥匙能开锁。按回车,是把物品用出去的用法。现在,按回车试试。"),
|
||
("g7_goal", "找到能用这把钥匙打开的东西。需要帮助时,在原地按回车。"),
|
||
("guide_wrong_up", "不是这个方向。按上方向键。"),
|
||
("guide_wrong_down", "不是这个方向。按下方向键。"),
|
||
("guide_wrong_left", "不是这个方向。按左方向键。"),
|
||
("guide_wrong_right", "不是这个方向。按右方向键。"),
|
||
("guide_blunt_up", "按一下上方向键。"),
|
||
("guide_blunt_down", "按一下下方向键。"),
|
||
("guide_blunt_left", "按一下左方向键。"),
|
||
("guide_blunt_right", "按一下右方向键。"),
|
||
("reopen_prompt", "按上方向键,重新听一遍引导。按空格,直接开始。"),
|
||
("stuck_key_2", "去西南角的储物间,按空格检查,找到钥匙。"),
|
||
("stuck_cabinet_2", "去东边的铁柜房,按回车,用钥匙打开铁柜。"),
|
||
("stuck_box_2", "去西北角的电箱房,按回车,把保险丝装进电箱。"),
|
||
("stuck_gate_2", "去东南角的大门,按回车,打开它,离开这里。"),
|
||
("nav_up", "按上方向键。"),
|
||
("nav_down", "按下方向键。"),
|
||
("nav_left", "按左方向键。"),
|
||
("nav_right", "按右方向键。"),
|
||
("start_room", "你站在设施中央的房间里。方向键移动,按空格检查,按回车使用物品。"),
|
||
("inspect_gate_ready", "电子锁的指示灯亮了,发出微弱的绿光。大门已经通电。按回车,打开它,离开这里。"),
|
||
("use_fail", "这里没有用得上东西的地方。换个房间试试,或者先按空格检查一下周围。"),
|
||
("again", "按空格,再来一次。按下方向键,打开菜单。"),
|
||
("help_ops", "方向键,在房间之间移动。按空格,检查房间,或者重听房间的声音。按回车,使用物品,或者查看背包。"),
|
||
("skip_hint", "按空格可跳过旁白。"),
|
||
],
|
||
"simon": [
|
||
("t1_up", "按上方向键,是这个声音。"),
|
||
("t2_down", "按下方向键,是这个声音。"),
|
||
("t3_left", "按左方向键,是这个声音。"),
|
||
("t4_right", "按右方向键,是这个声音。"),
|
||
("t5_tap", "按空格,是这个声音。"),
|
||
("t6_double", "按回车,是这个声音。"),
|
||
("t_wrong_up", "不是这个,按上方向键试试。"),
|
||
("t_wrong_down", "不是这个,按下方向键试试。"),
|
||
("t_wrong_left", "不是这个,按左方向键试试。"),
|
||
("t_wrong_right", "不是这个,按右方向键试试。"),
|
||
("t_wrong_tap", "不是这个,按空格试试。"),
|
||
("t_wrong_double", "不是这个,按回车试试。"),
|
||
("t_blunt_up", "按一下上方向键。"),
|
||
("t_blunt_down", "按一下下方向键。"),
|
||
("t_blunt_left", "按一下左方向键。"),
|
||
("t_blunt_right", "按一下右方向键。"),
|
||
("t_blunt_tap", "轻轻按一下空格。"),
|
||
("t_blunt_double", "按一下回车。"),
|
||
("t7_retry", "答错可以消耗机会重听。按上方向键,可以随时重听。"),
|
||
("replay", "按空格,再来一局。"),
|
||
("rules_prompt", "按上方向键,重听规则。按下方向键,打开菜单。"),
|
||
("rules", "上行音,按上方向键。下行音,按下方向键。左边的音,按左方向键。右边的音,按右方向键。一声轻响,按空格。两声轻响,按回车。"),
|
||
("skip_hint", "按空格可跳过旁白。"),
|
||
("gd_relisten", "需要的话,按上方向键可以重新听一遍序列。"),
|
||
("gd_economy", "记不住就按上方向键,重新听一遍。免费机会有两次,用完要扣一次机会。"),
|
||
("gd_occ_up", "这一轮,按上方向键是作答。"),
|
||
("gd_occ_dt", "这一轮,按回车是作答。"),
|
||
("gd_occ_both", "这一轮,按上方向键和回车都是作答。"),
|
||
],
|
||
# rhythm:8 对(24-rhythm-voice-ids.md 键盘变体表,措辞含数字键/方向键/空格/回车)。
|
||
"rhythm": [
|
||
("tut_map", "先认识你的鼓。屏幕横着分三列,左边、中间、右边;竖着分两行,上面清亮,下面低沉。按数字一键到六键,听六面鼓。"),
|
||
("tut_probe", "按出三个不同的键,我们就开始。"),
|
||
("tut_z_kick", "数字五,是底鼓,你的家。先听四下数拍,然后跟着我敲。"),
|
||
("tut_z_sides", "数字四,军鼓。数字六,低嗵。一左一右,跟着打。"),
|
||
("tut_z_patt", "上面一排更清亮。数字一踩镲,数字二高嗵,数字三吊镲。听这一句,三个音。"),
|
||
("select_hint", "左右方向键选曲目,按空格开始,按下方向键回大厅。"),
|
||
("restart", "按空格再来一遍,按右方向键下一首,按下方向键回大厅。"),
|
||
("menu_main", "菜单。按空格切换选项,按回车确认。"),
|
||
],
|
||
"space": [
|
||
("drill_left", "听,左边有陨石。按左方向键,把它拨开!"),
|
||
("drill_right", "这次在右边。按右方向键!"),
|
||
("drill_up", "上面有东西,声音又尖又高。按上方向键!"),
|
||
("drill_down", "下面是低沉的轰隆。按下方向键!"),
|
||
("drill_retry_left", "那是左边来的,按左方向键。"),
|
||
("drill_retry_right", "那是右边来的,按右方向键。"),
|
||
("drill_retry_up", "声音又高又尖,是上面,按上方向键。"),
|
||
("drill_retry_down", "轰隆声在下面,按下方向键。"),
|
||
("protect_left", "训练护盾接住了。那颗在左边,听到左边的呼啸,按左方向键。"),
|
||
("protect_right", "训练护盾接住了。那颗在右边,听到右边的呼啸,按右方向键。"),
|
||
("protect_up", "训练护盾接住了。那颗在上面,听到高高的呼啸,按上方向键。"),
|
||
("protect_down", "训练护盾接住了。那颗在下面,听到低沉的轰隆,按下方向键。"),
|
||
("feat_boost", "试试按空格,引擎会短促加速,直接冲过空隙。"),
|
||
("feat_shield", "按回车展开护盾,能挡下一次撞击。"),
|
||
("hit_left", "左边撞上的。听到左边的呼啸,按左方向键。"),
|
||
("hit_right", "右边撞上的。听到右边的呼啸,按右方向键。"),
|
||
("hit_up", "上面撞上的。听到高高的呼啸,按上方向键。"),
|
||
("hit_down", "下面撞上的。听到低沉的轰隆,按下方向键。"),
|
||
("restart_hint", "按空格再飞一次,按下方向键回大厅。"),
|
||
("second_run_ask", "按上方向键重新听演练,按空格直接出发。"),
|
||
("menu_main", "菜单。按空格切换选项,按回车确认。"),
|
||
("help_recap", "左边来按左方向键,右边来按右方向键,上面来按上方向键,下面来按下方向键。按空格加速,按回车护盾。"),
|
||
("skip_hint", "按空格可跳过旁白。"),
|
||
("gd_hit_hint", "被撞了。听方位,按对应方向键就能拨开。"),
|
||
],
|
||
"rpg": [
|
||
("sys_continue_ask", "检测到你的旅程记录。按空格继续,按右方向键开始新的旅程。"),
|
||
("sys_menu", "菜单。左右方向键选择,按空格确认。"),
|
||
("help_explore", "左右方向键切换选项,按空格确认。按回车重新听场景,按上方向键查看状态,按下方向键打开菜单。"),
|
||
("help_battle", "战斗中,左右方向键选招式,按空格出手。听到敌人的前摇,按回车格挡。"),
|
||
("btl_lose_hint", "记住,听清前摇,按回车格挡。"),
|
||
("tut_b2", "就是现在,按回车格挡!"),
|
||
("tut_b3", "挡住了!轮到你了。左右方向键选攻击,按空格出剑。"),
|
||
("shop_open", "商店。左右方向键看看货,按空格购买。"),
|
||
("skip_hint", "按空格可跳过旁白。"),
|
||
("tut_battle_2", "左右方向键切换招式,攻击、破空斩、防御、金疮药。按空格,出手。"),
|
||
("tut_battle_3", "敌人出手前有一声前摇。听到前摇,马上按回车,就能格挡。"),
|
||
("tut_battle_5", "记住:听清前摇,按回车格挡。开始吧!"),
|
||
("tut_b0", "战斗里,左右方向键选招式,按空格出手。听到这个声音,就是你的回合。先按一按方向键,试试。"),
|
||
("tut_b6", "来不及格挡,就选防御。左右方向键,选防御,按空格。"),
|
||
("gd_parry_miss", "前摇声起的时候按回车,才能格挡。"),
|
||
("gd_stall", "想好了吗?左右方向键选择,按空格出手。"),
|
||
],
|
||
"radio": [
|
||
("gd_brief", "按空格继续节目。请选择的时候,按左或右方向键。"),
|
||
("gd_continue", "按空格,继续。"),
|
||
("gd_again", "还在吗?按空格继续。"),
|
||
("gd_ring1", "热线在闪。按空格,接听。"),
|
||
("gd_ring2", "灯还亮着,听众在等。按空格,接听。"),
|
||
("sys_help", "按空格继续,按回车重新听。按上方向键听状态,按下方向键开菜单。请选择时,左右方向键。"),
|
||
("sys_menu", "菜单。按空格切换选项,按回车确认。"),
|
||
("sys_skip", "想跳过这句,按空格就行。"),
|
||
("sys_continue_ask", "检测到你的夜班记录。按空格继续上次,按右方向键开始新的夜晚。"),
|
||
("p1", "老人在发抖。按左方向键,陪他哼那首老歌。按右方向键,冷静问他路口的路牌。"),
|
||
("p2", "雨声更密了。按左方向键,留在原地陪他等巡逻队。按右方向键,转接派出所。"),
|
||
("p3", "按左方向键,告诉她这趟车值得上。按右方向键,把选择还给她。"),
|
||
("p4", "按左方向键,唱一段摇篮曲哄她睡。按右方向键,轻轻问她怎么了。"),
|
||
("p5", "孩子的声音在抖。按左方向键,告诉她这不是她的错。按右方向键,答应她明天都会好。"),
|
||
("p6", "摔门声你听见了。按左方向键,替孩子给她带句话。按右方向键,劝她回家把话说开。"),
|
||
("p7", "她的呼吸平了。按左方向键,留在直播里,让全城等这个门铃。按右方向键,换垫乐,私下陪她说完。"),
|
||
("p8", "方向盘比话筒危险。按左方向键,陪他聊聊闺女。按右方向键,让他立刻进服务区。"),
|
||
("p9", "留言机红灯在闪,是老主播三年前没播完的那句晚安。按左方向键,替他播出去。按右方向键,照常收播。"),
|
||
],
|
||
"dungeon": [
|
||
("sys_continue_ask", "检测到探窟记录。按空格继续,按右方向键重新开始。"),
|
||
("tut_d0", "先学会用耳朵看。按空格,发出声波脉冲。"),
|
||
("tut_walk", "按住空格不放,你就往前走。"),
|
||
("tut_turn", "按左右方向键,可以转身。"),
|
||
("tut_replay", "按回车,再发一次脉冲,不要钱。"),
|
||
("tut_status", "按上方向键,随时听自己的状态。"),
|
||
("tut_menu", "按下方向键,打开菜单。"),
|
||
("tut_parry", "听到它的动静,按回车格挡。"),
|
||
("tut_attack", "现在按空格,挥拳打它。"),
|
||
("tut_flee_hold", "想逃跑,按住空格别松手。"),
|
||
("tut_stairs_on", "楼梯就在脚下。按空格,下潜。"),
|
||
("tut_skip", "已跳过教学。按空格发脉冲,先听听四周。"),
|
||
("sys_menu", "菜单。按空格切换,按回车确认。"),
|
||
("help_explore", "按空格发脉冲,按住空格前进,左右方向键转身。按回车再听,上方向键查状态,下方向键开菜单。"),
|
||
("help_battle", "敌人前摇声响时按回车格挡,按空格挥击。打不过就按住空格逃跑。"),
|
||
("die_adv_1", "下次,前摇声响时就按回车。"),
|
||
("die_adv_2", "打不过,就按住空格逃跑。"),
|
||
("gd_pulse", "按空格发脉冲,听听四周。"),
|
||
("gd_turn", "轮到你了。按空格挥击。"),
|
||
("settle_again", "按空格,再探一次。"),
|
||
],
|
||
# abyss:11 对(17-abyss-voice-ids.md §G0.a 9 对 + §D1 dv1_teach/p1;措辞「左箭头/右箭头」
|
||
# 「上箭头/下箭头」为文档原文,与 dungeon 的「左方向键」系两文档各自定稿措辞,不改写)。
|
||
"abyss": [
|
||
("gd_brief", "按空格继续简报。要选择时,用左右方向键。"),
|
||
("gd_continue", "按空格,继续。"),
|
||
("gd_again", "还在吗?按空格继续。"),
|
||
("gd_ping1", "声呐待命。按空格,发脉冲。"),
|
||
("gd_ping2", "回波不会自己来。按空格。"),
|
||
("sys_help", "空格继续,回车重新听。上箭头听状态,下箭头开菜单。选择时,左右箭头。"),
|
||
("sys_menu", "菜单。空格切换选项,回车确认。"),
|
||
("sys_skip", "听过的句子再播时,按空格跳过。"),
|
||
("sys_continue_ask", "检测到你的下潜记录。空格继续上次,右箭头开始新救援。"),
|
||
("dv1_teach", "到深度了。声呐静了。按空格,发一枚脉冲。"),
|
||
("p1", "管路在响。左箭头,停下来听敲管的暗号。右箭头,先带小舟上浮。"),
|
||
],
|
||
# detective:V 组 14 对(18-detective-voice-ids.md 文末;_k 逻辑 id 落 key/ 子目录;R2 +4 对)。
|
||
"detective": [
|
||
("sys_help", "方向键换卷宗,空格听取,回车重新听。按住空格指证,上键状态,下键菜单。"),
|
||
("tut_d0", "先熟悉证词板。左右方向键,换卷宗。"),
|
||
("tut_listen", "空格,听取当前卷宗。"),
|
||
("tut_replay", "回车,重新听这一句。"),
|
||
("tut_confront", "按住空格,进入指证。"),
|
||
("gd_board", "还在证词板。左右方向键,换卷宗。"),
|
||
("gd_cf", "还在选证词。左右方向键,空格确认。"),
|
||
("cf_pick_line", "左右方向键,一句一句听。"),
|
||
("cf_confirm", "就这句?空格,定下来。"),
|
||
("settle_hook", "同一场雨里,还有别的案子。按空格,接新案。"),
|
||
("fin_pre", "证据在手,就此结案?空格,定下来;方向键,继续查。"),
|
||
("fin_who_confirm", "就指认这位?空格,定下来。"),
|
||
("recap_cf", "卷宗都在耳朵里了。挑一句你不信的,按住空格指证。"),
|
||
("gd_board_cf", "都听过了。按住空格,去指证。"),
|
||
],
|
||
# hunt:V 组 11 对(23-hunt-voice-ids.md 文末;措辞「方向键/空格/回车」同 dungeon 规范)。
|
||
"hunt": [
|
||
("room_wait", "房间已开好,等同伴到齐。按空格,立即开局。"),
|
||
("tut_rule", "野兽会从八个方向围上来。声音在哪边,就按哪边方向键。"),
|
||
("tut_attack", "听,有狼在靠近。朝声音的方向,按方向键。"),
|
||
("tut_callout", "按空格,呼喊支援,队友会来帮你。"),
|
||
("tut_skill", "按回车,旋风斩,清掉身边一圈。"),
|
||
("tut_skill_cd", "旋风斩有八秒冷却。冷却中按回车,重新听威胁。"),
|
||
("tut_status", "按上方向键,听营地状态。按下方向键,打开菜单。"),
|
||
("sys_menu", "菜单。按空格切换,按回车确认。"),
|
||
("help_main", "朝声音的方向按方向键,就是出击。按空格呼喊支援,按回车旋风斩。上方向键状态,下方向键菜单。"),
|
||
("end_again", "按空格,再猎一局。"),
|
||
("gd_idle", "听声音的方向,按方向键。"),
|
||
],
|
||
# cipher:11 对(19-cipher-voice-ids.md §G0.a 9 对 + §M1 dv1_teach2/p2;措辞
|
||
# 「左右方向键/上箭头/下箭头/左箭头/右箭头」为文档原文,与 hunt「方向键」系各文档定稿措辞)。
|
||
"cipher": [
|
||
("gd_brief", "按空格继续值机。要选词时,用左右方向键。"),
|
||
("gd_continue", "按空格,继续。"),
|
||
("gd_again", "还在吗?按空格继续。"),
|
||
("gd_tune1", "电文在等。左右方向键,听候选词。"),
|
||
("gd_tune2", "按回车,把电文再听一遍。再按一次,会放慢。"),
|
||
("sys_help", "空格选定,回车重新听电文。上箭头听状态,下箭头开菜单。选择时,左右箭头。"),
|
||
("sys_menu", "菜单。空格切换选项,回车确认。"),
|
||
("sys_skip", "想跳过这句,按空格。"),
|
||
("sys_continue_ask", "检测到你的值机记录。空格继续上次,右箭头开始新的夜班。"),
|
||
("dv1_teach2", "左右方向键,听密码本上的候选词。空格,选定一个。"),
|
||
("p2", "药品船,丑时过江。左箭头,把船期报给北风。右箭头,压进值机日志。"),
|
||
],
|
||
# bridge:V 组 10 对(22-bridge-voice-ids.md §V 组;措辞「方向键/空格/回车」同 hunt 规范)。
|
||
"bridge": [
|
||
("sys_help", "巡航中,上键巡检全舰;危机中,方向键听选项,空格下令。下键菜单,回车重新听。"),
|
||
("tut_d0", "先试巡检。按上键,听全舰状态。"),
|
||
("tut_decide", "方向键听选项,空格下令。"),
|
||
("cr_decide", "听选项,空格下令。"),
|
||
("dock_open", "靠港整备。方向键看项目,空格执行。"),
|
||
("gd_cruise", "还在巡航。上键,巡检全舰。"),
|
||
("gd_decide", "还在等命令。方向键,听选项。"),
|
||
("gd_dock", "还在整备。方向键看,空格执行。"),
|
||
("sys_continue_ask", "检测到未完成的巡逻。空格继续,右方向键进星港。"),
|
||
("settle_hook", "星港期待你的下一次巡逻。按空格,返航。"),
|
||
],
|
||
# teahouse:V 组 10 对(20-teahouse-voice-ids.md §V 组;措辞「方向键/空格/回车」同 hunt 规范)。
|
||
"teahouse": [
|
||
("sys_help", "方向键选茶,空格定下。听水声,回车提壶;滴答密,回车出汤。上键状态,下键菜单。"),
|
||
("tut_d0", "先看茶柜。左右方向键,一罐一罐听。"),
|
||
("tut_tea", "空格,选定这罐茶。"),
|
||
("tut_water", "灶上坐水。泡泡细密是将沸,咕嘟连片是滚透——听到细密,回车提壶。"),
|
||
("tut_steep", "注水,闷泡。滴答由稀到密,密起来就是将好——回车,出汤。"),
|
||
("tut_serve", "茶好了。空格,端出去。"),
|
||
("gd_serve", "客人还在堂前。上键,再听一遍他要的茶。"),
|
||
("gd_brew", "还在灶上,听声动手,回车。"),
|
||
("settle_night", "熄了灯,这一晚就过去了。按空格,睡下。"),
|
||
("upg_open", "要添置点什么?左右方向键看,空格买定。"),
|
||
],
|
||
# keeper:8 对(21-keeper-voice-ids.md §G0.a 7 对 + 首个抉择 p1;措辞「方向键/空格/
|
||
# 回车/左右箭头」为 21b 文档原文,与 abyss §G0.a 同型,逐字照录不改写)。
|
||
"keeper": [
|
||
("gd_brief", "按空格,继续值守。要选择时,用左右方向键。"),
|
||
("gd_continue", "按空格,继续。"),
|
||
("gd_again", "还在吗?按空格继续。"),
|
||
("sys_help", "空格继续,回车重新听。上箭头听状态,下箭头开菜单。选择时,左右箭头。"),
|
||
("sys_menu", "菜单。空格切换选项,回车确认。"),
|
||
("sys_skip", "想跳过这句,按空格。"),
|
||
("sys_continue_ask", "检测到你的值守记录。空格继续上次,右箭头开始新的风暴夜。"),
|
||
("p1", "他的声音在抖。左箭头,先接住这个人。右箭头,先要他的船位。"),
|
||
],
|
||
}
|
||
|
||
|
||
def key_variants(game):
|
||
"""key 变体表 [(fid, instruct_pair, text), ...]。
|
||
|
||
约束(启动即校验,防两表漂移):
|
||
- key id 必须存在于该游戏主台词表(key 集合 ⊆ 主集合),复用其 instruct
|
||
与 VOICE_SPK speaker(radio HOST/PROD 配对自动生效);
|
||
- key 表内 id 不得重复。
|
||
"""
|
||
ins_by_id = {fid: ins for fid, ins, _t in GAMES[game]}
|
||
seen = set()
|
||
out = []
|
||
for fid, text in KEY_LINES[game]:
|
||
if fid not in ins_by_id:
|
||
raise SystemExit(f"key 变体 {game}/{fid} 不在主台词表中(key 集合必须 ⊆ 主集合)")
|
||
if fid in seen:
|
||
raise SystemExit(f"key 变体重复 id:{game}/{fid}")
|
||
seen.add(fid)
|
||
out.append((fid, ins_by_id[fid], text))
|
||
return out
|
||
|
||
# radio 双性别行的逐句 speaker 覆盖(HOST=主播 / PROD=导播,同性别两个音色,
|
||
# 见 15-radio-voice-ids.md 录制说明:同场景高频对话的两者永不同 speaker)。
|
||
VOICE_SPK = {"radio": {}}
|
||
VOICE_SPK["radio"].update({fid: ("Uncle_Fu", "Serena") for fid, _i, _t in RADIO_HOST_LINES})
|
||
VOICE_SPK["radio"].update({fid: ("Dylan", "Vivian") for fid, _i, _t in RADIO_PROD_LINES})
|
||
|
||
# abyss 双性别行的逐句 speaker 覆盖(DIVER=潜航员玩家 / DECK=母船调度,17b 录制说明:
|
||
# female 侧玩家 Serena/调度 Vivian、male 侧玩家 Uncle_Fu/调度 Dylan,同场景永不同 speaker)。
|
||
VOICE_SPK["abyss"] = {}
|
||
VOICE_SPK["abyss"].update({fid: ("Uncle_Fu", "Serena") for fid, _i, _t in ABYSS_DIVER_LINES})
|
||
VOICE_SPK["abyss"].update({fid: ("Dylan", "Vivian") for fid, _i, _t in ABYSS_DECK_LINES})
|
||
|
||
# cipher 双性别行的逐句 speaker 覆盖(OP=报务员玩家 / WIND=北风电台+系统音,19b 录制说明:
|
||
# female 侧你 Serena / 北风 Vivian、male 侧你 Uncle_Fu / 北风 Dylan,同场景永不同 speaker)。
|
||
VOICE_SPK["cipher"] = {}
|
||
VOICE_SPK["cipher"].update({fid: ("Uncle_Fu", "Serena") for fid, _i, _t in CIPHER_OP_LINES})
|
||
VOICE_SPK["cipher"].update({fid: ("Dylan", "Vivian") for fid, _i, _t in CIPHER_WIND_LINES})
|
||
|
||
# keeper 双性别行的逐句 speaker 覆盖(KEEPER=守塔人玩家 / SHORE=岸台值班员+系统音,
|
||
# 21b 录制说明:female 侧守塔人 Serena/岸台 Vivian、male 侧守塔人 Uncle_Fu/岸台 Dylan,
|
||
# 同场景高频对话的两者永不同 speaker,radio HOST/PROD / abyss DIVER/DECK 同型)。
|
||
VOICE_SPK["keeper"] = {}
|
||
VOICE_SPK["keeper"].update({fid: ("Uncle_Fu", "Serena") for fid, _i, _t in KEEPER_K_LINES})
|
||
VOICE_SPK["keeper"].update({fid: ("Dylan", "Vivian") for fid, _i, _t in KEEPER_S_LINES})
|
||
|
||
# radio 来电者电话滤波(15-radio.md §6.2,全部 + 轻压缩):按 NPC id 前缀分档,
|
||
# convert 转码时应用;staging wav 保留未滤波原声以便重滤/回退(宁窄勿脏)。
|
||
NPC_BANDPASS = {
|
||
"radio": [
|
||
("z1_", "highpass=f=500,lowpass=f=2800"), # 老周:老旧手机,窄而颤抖
|
||
("l1_", "highpass=f=400,lowpass=f=3400"), # 小鹿:车站手机,干净偏冷
|
||
("k1_", "highpass=f=450,lowpass=f=3000"), # 糖糖:家用座机,小而近
|
||
("w1_", "highpass=f=420,lowpass=f=3100"), # 陈姐:户外手机,风噪
|
||
("h1_", "highpass=f=300,lowpass=f=3400"), # 老韩:车载蓝牙,宽而轰
|
||
],
|
||
# abyss 船员水声电台滤波(17-abyss.md §5.3/17b 头注,全部 + 轻压缩):
|
||
# 「电台里的人」与「耳机里的人」靠音质差立住;d1_log 是小舟(z1_ 前缀外单独登记)。
|
||
"abyss": [
|
||
("z1_", "highpass=f=420,lowpass=f=3200"), # 小舟:年轻女声,窄带
|
||
("d1_log", "highpass=f=420,lowpass=f=3200"),
|
||
("bai_", "highpass=f=350,lowpass=f=3000"), # 老白:沙哑中年男,中窄带
|
||
("chen_", "highpass=f=400,lowpass=f=3100"), # 陈医官:平静女声
|
||
("gao_", "highpass=f=300,lowpass=f=2800"), # 高船长:苍老男声,最低最窄
|
||
],
|
||
# keeper NPC 滤波(21-keeper-voice-ids.md 头注 §滤波表,全部 + 轻压缩):阿澈=电台
|
||
# 350-3200;父亲=唱片 300-2800;祖父=唱片 250-2600(三代人频带逐人递减,最老者最窄最「远」)。
|
||
# 前缀只命中 NPC 平铺表内的 id(锚句 rev_f1/f5、rev_g1/g4、rev_c1/c5 是 KEEPER 双性别行不滤波)。
|
||
"keeper": [
|
||
("amo_", "highpass=f=350,lowpass=f=3200"), # 阿澈:年轻渔民电台嗓
|
||
("rev_f", "highpass=f=300,lowpass=f=2800"), # 父亲:中年男声,老唱片
|
||
("rev_g", "highpass=f=250,lowpass=f=2600"), # 祖父(插叙1):苍老男声,更老唱片
|
||
("rev_c", "highpass=f=250,lowpass=f=2600"), # 祖父(插叙3):同档
|
||
],
|
||
}
|
||
_NPC_ACOMP = "acompressor=threshold=-20dB:ratio=3:attack=10:release=150" # 轻压缩(全档)
|
||
|
||
|
||
def npc_af(game, fid):
|
||
"""NPC id -> ffmpeg -af 字符串(无滤波档返回 None)。"""
|
||
for prefix, af in NPC_BANDPASS.get(game, []):
|
||
if fid.startswith(prefix):
|
||
return af + "," + _NPC_ACOMP
|
||
return None
|
||
|
||
|
||
GAMES = {
|
||
"storyline": STORYLINE_LINES,
|
||
"escape": ESCAPE_LINES,
|
||
"simon": SIMON_LINES,
|
||
"rhythm": RHYTHM_LINES,
|
||
"space": SPACE_LINES,
|
||
"rpg": RPG_LINES,
|
||
"radio": RADIO_LINES,
|
||
"dungeon": DUNGEON_LINES,
|
||
"abyss": ABYSS_LINES,
|
||
"detective": DETECTIVE_LINES,
|
||
"hunt": HUNT_LINES,
|
||
"cipher": CIPHER_LINES,
|
||
"bridge": BRIDGE_LINES,
|
||
"teahouse": TEAHOUSE_LINES,
|
||
"keeper": KEEPER_LINES,
|
||
}
|
||
|
||
|
||
# ---------------------------------------------------------------- 工具函数
|
||
def split_text(text, limit=SPLIT_LIMIT):
|
||
"""按句末标点拆句并合并到 <=limit 字;超长单句再按逗号拆。"""
|
||
if len(text) <= limit:
|
||
return [text]
|
||
sents = [s for s in re.split(r"(?<=[。!?;…])", text) if s]
|
||
chunks, cur = [], ""
|
||
for s in sents:
|
||
if cur and len(cur) + len(s) > limit:
|
||
chunks.append(cur)
|
||
cur = s
|
||
else:
|
||
cur += s
|
||
if cur:
|
||
chunks.append(cur)
|
||
out = []
|
||
for c in chunks:
|
||
if len(c) <= limit:
|
||
out.append(c)
|
||
else: # 单句仍超限,按逗号硬拆
|
||
parts = [p for p in re.split(r"(?<=[,、:])", c) if p]
|
||
buf = ""
|
||
for p in parts:
|
||
if buf and len(buf) + len(p) > limit:
|
||
out.append(buf)
|
||
buf = p
|
||
else:
|
||
buf += p
|
||
if buf:
|
||
out.append(buf)
|
||
return [o for o in out if o.strip()]
|
||
|
||
|
||
def staging_path(game, gender, fid, variant=""):
|
||
"""staging wav 路径;variant='key' 时落 <gender>/key/ 子目录。"""
|
||
parts = [STAGING, game, gender]
|
||
if variant:
|
||
parts.append(variant)
|
||
return os.path.join(*parts, fid + ".wav")
|
||
|
||
|
||
def valid_wav(path):
|
||
import numpy as np
|
||
import soundfile as sf
|
||
if not os.path.exists(path):
|
||
return False
|
||
try:
|
||
data, sr = sf.read(path)
|
||
except Exception:
|
||
return False
|
||
if len(data) == 0:
|
||
return False
|
||
dur = len(data) / sr
|
||
peak = float(np.max(np.abs(data)))
|
||
return dur > 0.3 and peak > 0.05
|
||
|
||
|
||
# ---------------------------------------------------------------- 生成
|
||
def _generate_lines(model, game, gender, lines, variant=""):
|
||
"""一组双性别台词(主表或 key 变体)生成到 staging <game>/<gender>[/<variant>]/。"""
|
||
import numpy as np
|
||
import soundfile as sf
|
||
|
||
speaker = SPEAKERS[game][gender]
|
||
ins_idx = 0 if gender == "male" else 1
|
||
spk_map = VOICE_SPK.get(game, {})
|
||
outdir = os.path.join(STAGING, game, gender, variant) if variant else os.path.join(STAGING, game, gender)
|
||
os.makedirs(outdir, exist_ok=True)
|
||
|
||
# 展开成 (fid, chunk_idx, n_chunks, text, instruct, speaker),跳过已完成
|
||
items = []
|
||
for fid, ins_pair, text in lines:
|
||
path = staging_path(game, gender, fid, variant)
|
||
if valid_wav(path):
|
||
continue
|
||
spk = spk_map.get(fid, (speaker, speaker))[ins_idx]
|
||
chunks = split_text(text)
|
||
for ci, ctext in enumerate(chunks):
|
||
items.append((fid, ci, len(chunks), ctext, ins_pair[ins_idx], spk))
|
||
if not items:
|
||
print(f"[{game}/{gender}/{variant or '-'}] nothing to do", flush=True)
|
||
return
|
||
|
||
# 短句(数字类)优先、同 instruct 聚合成整批,减少 prosody 漂移
|
||
shorts = [it for it in items if len(it[3]) <= 2]
|
||
longs = [it for it in items if len(it[3]) > 2]
|
||
queue = ([("short", shorts[i:i + BATCH_SHORT]) for i in range(0, len(shorts), BATCH_SHORT)]
|
||
+ [("long", longs[i:i + BATCH_LONG]) for i in range(0, len(longs), BATCH_LONG)])
|
||
|
||
results = {} # fid -> {chunk_idx: wav}
|
||
for bi, (kind, batch) in enumerate(queue):
|
||
wavs, sr = model.generate_custom_voice(
|
||
text=[b[3] for b in batch],
|
||
language=["Chinese"] * len(batch),
|
||
speaker=[b[5] for b in batch],
|
||
instruct=[b[4] for b in batch],
|
||
max_new_tokens=2048,
|
||
)
|
||
for (fid, ci, _n, _t, _i, _s), wav in zip(batch, wavs):
|
||
results.setdefault(fid, {})[ci] = np.asarray(wav, dtype=np.float32)
|
||
print(f"[{game}/{gender}/{variant or '-'}] batch {bi + 1}/{len(queue)} ({kind}, n={len(batch)})", flush=True)
|
||
|
||
gap = np.zeros(int(GAP_SEC * sr), dtype=np.float32)
|
||
for fid, ins_pair, text in lines:
|
||
path = staging_path(game, gender, fid, variant)
|
||
if valid_wav(path):
|
||
continue
|
||
got = results.get(fid, {})
|
||
n_chunks = len(split_text(text))
|
||
assert len(got) == n_chunks, f"{game}/{gender}/{variant}/{fid}: 缺 chunk {len(got)}/{n_chunks}"
|
||
wav = got[0]
|
||
for ci in range(1, n_chunks):
|
||
wav = np.concatenate([wav, gap, got[ci]])
|
||
peak = float(np.max(np.abs(wav)))
|
||
assert peak > 0.05, f"{game}/{gender}/{variant}/{fid}: peak {peak:.3f}"
|
||
wav = wav / peak * PEAK_NORM
|
||
dur = len(wav) / sr
|
||
assert dur > 0.3, f"{game}/{gender}/{variant}/{fid}: dur {dur:.2f}s"
|
||
sf.write(path, wav, sr)
|
||
print(f"[ok] {game}/{gender}/{variant}/{fid} {dur:.2f}s chunks={n_chunks}", flush=True)
|
||
|
||
|
||
def generate(games, genders, only, variants_only=False):
|
||
import numpy as np
|
||
import soundfile as sf
|
||
import torch
|
||
from qwen_tts import Qwen3TTSModel
|
||
|
||
model = Qwen3TTSModel.from_pretrained(
|
||
"Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice",
|
||
device_map="cuda:0",
|
||
dtype=torch.bfloat16,
|
||
)
|
||
print("model loaded", flush=True)
|
||
|
||
for game in games:
|
||
if not variants_only:
|
||
lines = GAMES[game]
|
||
if only:
|
||
lines = [x for x in lines if x[0] in only]
|
||
for gender in genders:
|
||
_generate_lines(model, game, gender, lines)
|
||
# 键盘变体(key 集合 ⊆ 主集合,复用主表 instruct/speaker)
|
||
kvars = key_variants(game)
|
||
if only:
|
||
kvars = [x for x in kvars if x[0] in only]
|
||
for gender in genders:
|
||
_generate_lines(model, game, gender, kvars, variant="key")
|
||
|
||
# NPC 单音色平铺(staging <game>/npc/,convert 落 flat voice/)。
|
||
# --only-variants 时跳过:R5 起部分 NPC 资产已先行落盘而 staging 无 wav
|
||
# (见 RPG_LINES R5 注释),变体跑批不应顺手重录已验收 NPC 台词——
|
||
# 否则 --convert 会用新 take 覆盖 web/ 下已验收资产。
|
||
npc_lines = None if variants_only else NPCS.get(game)
|
||
if npc_lines:
|
||
outdir = os.path.join(STAGING, game, "npc")
|
||
os.makedirs(outdir, exist_ok=True)
|
||
todo = [x for x in npc_lines if not valid_wav(os.path.join(outdir, x[0] + ".wav"))]
|
||
for i in range(0, len(todo), BATCH_LONG):
|
||
batch = todo[i:i + BATCH_LONG]
|
||
wavs, sr = model.generate_custom_voice(
|
||
text=[b[3] for b in batch],
|
||
language=["Chinese"] * len(batch),
|
||
speaker=[b[1] for b in batch],
|
||
instruct=[b[2] for b in batch],
|
||
max_new_tokens=2048,
|
||
)
|
||
for (fid, _sp, _ins, _t), wav in zip(batch, wavs):
|
||
wav = np.asarray(wav, dtype=np.float32)
|
||
peak = float(np.max(np.abs(wav)))
|
||
assert peak > 0.05, f"{game}/npc/{fid}: peak {peak:.3f}"
|
||
wav = wav / peak * PEAK_NORM
|
||
dur = len(wav) / sr
|
||
assert dur > 0.3, f"{game}/npc/{fid}: dur {dur:.2f}s"
|
||
sf.write(os.path.join(outdir, fid + ".wav"), wav, sr)
|
||
print(f"[ok] {game}/npc/{fid} {dur:.2f}s", flush=True)
|
||
|
||
|
||
# ---------------------------------------------------------------- 检查
|
||
def check(games):
|
||
import numpy as np
|
||
import soundfile as sf
|
||
|
||
def check_set(game, lines, variant=""):
|
||
problems = []
|
||
prefix = f"key/" if variant else ""
|
||
for fid, _ins, _text in lines:
|
||
durs = {}
|
||
for gender in ("male", "female"):
|
||
path = staging_path(game, gender, fid, variant)
|
||
if not os.path.exists(path):
|
||
durs[gender] = None
|
||
continue
|
||
data, sr = sf.read(path)
|
||
peak = float(np.max(np.abs(data)))
|
||
durs[gender] = len(data) / sr
|
||
if durs[gender] <= 0.3 or peak <= 0.05:
|
||
problems.append(f"{game}/{gender}/{prefix}{fid}: 质量不达标 dur={durs[gender]:.2f} peak={peak:.3f}")
|
||
m, f = durs["male"], durs["female"]
|
||
if m is None or f is None:
|
||
problems.append(f"{game}/{prefix}{fid}: 缺 {'male' if m is None else 'female'}")
|
||
continue
|
||
ratio = max(m, f) / min(m, f)
|
||
flag = " <-- OUTLIER" if ratio > 3 else ""
|
||
if ratio > 3:
|
||
problems.append(f"{game}/{prefix}{fid}: 时长离群 m={m:.2f}s f={f:.2f}s ratio={ratio:.1f}")
|
||
print(f" {prefix}{fid:24s} m={m:6.2f}s f={f:6.2f}s{flag}")
|
||
return problems
|
||
|
||
problems = []
|
||
for game in games:
|
||
print(f"=== {game} ===")
|
||
problems += check_set(game, GAMES[game])
|
||
kvars = key_variants(game)
|
||
if kvars:
|
||
print(f" --- key 变体 {len(kvars)} 句 ---")
|
||
problems += check_set(game, kvars, variant="key")
|
||
print()
|
||
if problems:
|
||
print("PROBLEMS:")
|
||
for p in problems:
|
||
print(" ", p)
|
||
return 1
|
||
print("ALL OK")
|
||
return 0
|
||
|
||
|
||
# ---------------------------------------------------------------- 转码
|
||
def convert(games):
|
||
# 只按台词表转换(不扫目录),staging 里残留的旧 id wav 不会落盘
|
||
total = 0
|
||
for game in games:
|
||
for gender in ("male", "female"):
|
||
dst_dir = os.path.join(ROOT, "web", game, "audio", "voice", gender)
|
||
os.makedirs(dst_dir, exist_ok=True)
|
||
for fid, _ins, _text in GAMES[game]:
|
||
src = staging_path(game, gender, fid)
|
||
if not os.path.exists(src):
|
||
print(f"[convert] WARN missing {game}/{gender}/{fid}.wav")
|
||
continue
|
||
base = os.path.join(dst_dir, fid)
|
||
subprocess.run(["ffmpeg", "-y", "-v", "error", "-i", src,
|
||
"-ar", "44100", "-c:a", "libvorbis", "-q:a", "3", base + ".ogg"], check=True)
|
||
subprocess.run(["ffmpeg", "-y", "-v", "error", "-i", src,
|
||
"-ar", "44100", "-c:a", "aac", "-b:a", "128k", base + ".m4a"], check=True)
|
||
total += 1
|
||
# 键盘变体:落 voice/<gender>/key/ 子目录(引擎 key 模式候选链前置)
|
||
kdst = os.path.join(dst_dir, "key")
|
||
for fid, _ins, _text in key_variants(game):
|
||
src = staging_path(game, gender, fid, "key")
|
||
if not os.path.exists(src):
|
||
print(f"[convert] WARN missing {game}/{gender}/key/{fid}.wav")
|
||
continue
|
||
os.makedirs(kdst, exist_ok=True)
|
||
base = os.path.join(kdst, fid)
|
||
subprocess.run(["ffmpeg", "-y", "-v", "error", "-i", src,
|
||
"-ar", "44100", "-c:a", "libvorbis", "-q:a", "3", base + ".ogg"], check=True)
|
||
subprocess.run(["ffmpeg", "-y", "-v", "error", "-i", src,
|
||
"-ar", "44100", "-c:a", "aac", "-b:a", "128k", base + ".m4a"], check=True)
|
||
total += 1
|
||
# NPC 平铺(staging <game>/npc/ → audio/voice/<id>.*;radio 按 NPC_BANDPASS 带通)。
|
||
# 异例:hunt 喊话走 sfx 层带 pan(23-hunt.md §8 R2 / §15 裁决 7),落 audio/sfx/。
|
||
npc_layer = "sfx" if game == "hunt" else "voice"
|
||
for fid, _sp, _ins, _t in NPCS.get(game, []):
|
||
src = os.path.join(STAGING, game, "npc", fid + ".wav")
|
||
if not os.path.exists(src):
|
||
print(f"[convert] WARN missing {game}/npc/{fid}.wav")
|
||
continue
|
||
base = os.path.join(ROOT, "web", game, "audio", npc_layer, fid)
|
||
af = npc_af(game, fid)
|
||
af_args = ["-af", af] if af else []
|
||
subprocess.run(["ffmpeg", "-y", "-v", "error", "-i", src, *af_args,
|
||
"-ar", "44100", "-c:a", "libvorbis", "-q:a", "3", base + ".ogg"], check=True)
|
||
subprocess.run(["ffmpeg", "-y", "-v", "error", "-i", src, *af_args,
|
||
"-ar", "44100", "-c:a", "aac", "-b:a", "128k", base + ".m4a"], check=True)
|
||
total += 1
|
||
print(f"[convert] {game} done")
|
||
print(f"converted {total} files (ogg+m4a each)")
|
||
|
||
|
||
def main():
|
||
ap = argparse.ArgumentParser()
|
||
ap.add_argument("--game", required=True,
|
||
choices=list(GAMES.keys()) + ["all"])
|
||
ap.add_argument("--gender", default="both", choices=["male", "female", "both"])
|
||
ap.add_argument("--only", default="", help="逗号分隔的 id 列表,只生成这些")
|
||
ap.add_argument("--only-variants", action="store_true",
|
||
help="只生成键盘变体(key)台词,跳过主表(--check/--convert 对变体始终生效)")
|
||
ap.add_argument("--check", action="store_true")
|
||
ap.add_argument("--convert", action="store_true")
|
||
args = ap.parse_args()
|
||
|
||
games = list(GAMES.keys()) if args.game == "all" else [args.game]
|
||
genders = ["male", "female"] if args.gender == "both" else [args.gender]
|
||
only = set(x for x in args.only.split(",") if x)
|
||
|
||
if args.check:
|
||
sys.exit(check(games))
|
||
if args.convert:
|
||
convert(games)
|
||
return
|
||
generate(games, genders, only, variants_only=args.only_variants)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|