diablo2-web/src/game/level-names-zh.ts

225 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// level-names-zh.ts — 关卡/场景的中文显示名(用于页面上的三级选择器)
//
// 出处说明(重要,避免误认为官方本地化):
// 这批译名是**社区通用译名**,由本项目手工整理;英文原名取自 `Levels.txt` 的 `LevelName`
// 列(例如 1 = "Rogue Encampment"、33 = "Cathedral"),中文对照按国内玩家习惯写法。
// 我们这份安装包里的 `data\local\LNG\CHI\string.tbl` 解出来是乱码(`.tbl` 解码器只对夹具
// 验证过,尚未对真文件校准),所以**没有**直接采用官方简中字符串表;等 `.tbl` 解码对齐后
// 可以换成官方译名,届时只需替换本表。
//
// 键是 `Levels.txt` 的 `Id`;页面从 pack 索引条目的 `slug`(形如 `33-act-1-cathedral`)里
// 取第一个数字段就能对上。查不到时回退到索引里的英文 `levelName`。
/** 五个 act 的中文名,下标即 act 号。 */
export const ACT_NAMES_ZH: Readonly<Record<number, string>> = {
1: '第一章',
2: '第二章',
3: '第三章',
4: '第四章',
5: '第五章',
}
/** `Levels.txt` 的 `Id` → 中文场景名。 */
export const LEVEL_NAMES_ZH: Readonly<Record<number, string>> = {
// Act 1
1: '罗格营地',
2: '鲜血荒地',
3: '冰冷之原',
4: '石块旷野',
5: '黑暗森林',
6: '黑色荒地',
7: '泰摩高地',
8: '邪恶洞窟',
9: '洞穴一层',
10: '地下通道一层',
11: '窟窿一层',
12: '深坑一层',
13: '洞穴二层',
14: '地下通道二层',
15: '窟窿二层',
16: '深坑二层',
17: '埋骨之地',
18: '大陵寝',
19: '灵庙',
20: '遗忘之塔',
21: '塔地窖一层',
22: '塔地窖二层',
23: '塔地窖三层',
24: '塔地窖四层',
25: '塔地窖五层',
26: '修道院大门',
27: '外回廊',
28: '军营',
29: '监牢一层',
30: '监牢二层',
31: '监牢三层',
32: '内回廊',
33: '大教堂',
34: '地下墓穴一层',
35: '地下墓穴二层',
36: '地下墓穴三层',
37: '地下墓穴四层',
38: '崔斯特瑞姆',
39: '奶牛关',
// Act 2
40: '鲁高因',
41: '碎石荒地',
42: '干燥高地',
43: '遥远绿洲',
44: '遗失的城市',
45: '群蛇峡谷',
46: '术士峡谷',
47: '下水道一层',
48: '下水道二层',
49: '下水道三层',
50: '后宫一层',
51: '后宫二层',
52: '皇宫地牢一层',
53: '皇宫地牢二层',
54: '皇宫地牢三层',
55: '石制古墓一层',
56: '死亡之殿一层',
57: '死亡之殿二层',
58: '利爪蝮蛇神殿一层',
59: '石制古墓二层',
60: '死亡之殿三层',
61: '利爪蝮蛇神殿二层',
62: '蛆虫巢穴一层',
63: '蛆虫巢穴二层',
64: '蛆虫巢穴三层',
65: '古代通道',
66: '塔·拉夏古墓 (1)',
67: '塔·拉夏古墓 (2)',
68: '塔·拉夏古墓 (3)',
69: '塔·拉夏古墓 (4)',
70: '塔·拉夏古墓 (5)',
71: '塔·拉夏古墓 (6)',
72: '塔·拉夏古墓 (7)',
73: '都瑞尔的巢穴',
74: '秘法圣所',
// Act 3
75: '库拉斯特码头',
76: '蜘蛛森林',
77: '庞大湿地',
78: '剥皮丛林',
79: '库拉斯特下层',
80: '库拉斯特商场',
81: '库拉斯特上层',
82: '库拉斯特堤道',
83: '崔凡克',
84: '蜘蛛巢穴',
85: '蜘蛛洞窟',
86: '沼泽地坑一层',
87: '沼泽地坑二层',
88: '剥皮地牢一层',
89: '剥皮地牢二层',
90: '沼泽地坑三层',
91: '剥皮地牢三层',
92: '下水道一层',
93: '下水道二层',
94: '废弃神殿',
95: '荒废神庙',
96: '遗忘圣物室',
97: '遗忘神殿',
98: '废弃神庙',
99: '荒废圣物室',
100: '憎恨囚牢一层',
101: '憎恨囚牢二层',
102: '憎恨囚牢三层',
// Act 4
103: '群魔堡垒',
104: '郊外大草原',
105: '绝望平原',
106: '神罚之城',
107: '火焰之河',
108: '混沌避难所',
// Act 5
109: '哈洛加斯',
110: '血腥丘陵',
111: '冰冻高地',
112: '亚瑞特高原',
113: '水晶通道',
114: '冰河',
115: '冰河路径',
116: '漂泊者洞穴',
117: '冰冻苔原',
118: '冰窖',
119: '痛苦之厅',
120: '岩石之巅',
121: '尼拉塞克神殿',
122: '悲痛之厅',
123: '死者呼唤之厅',
124: '沃特厅',
125: '艾巴当',
126: '阿克隆地道',
127: '炼狱地坑',
128: '世界之石要塞一层',
129: '世界之石要塞二层',
130: '世界之石要塞三层',
131: '毁灭王座',
132: '世界之石大殿',
133: '遗忘之沙',
134: '巨窟',
135: '苦痛熔炉',
136: '混沌崔斯特瑞姆',
}
/**
* DS1 变体后缀 → 方位名。
*
* 这些后缀是 D2 自己的命名习惯:城镇/回廊/鲁高因的 DS1 以 `N`/`E`/`S`/`W` 结尾
* (`TownN1`、`CourtW`、`LutN`…)。**只白名单这几个**,不做"末尾字母是方位"的猜测:
* `CryptCountess1` 末尾也是 `s`,按猜测会错成"南"。
*/
const DIRECTION_SUFFIXES: Readonly<Record<string, string>> = {
townn1: '北',
towne1: '东',
towns1: '南',
townw1: '西',
courtn: '北',
courte: '东',
courtw: '西',
lutn: '北',
lutw: '西',
}
/**
* 把一个变体后缀变成显示用的中文(拿不准就原样返回 DS1 名)。
*
* @param suffix - the part of the pack label after the level slug, e.g. `towns1` or `var1`.
* @returns the label to show in the third selector.
*/
export function variantLabelZh(suffix: string): string {
const match = /^var(\d+)$/i.exec(suffix)
if (match) return `变体 ${match[1]}`
return DIRECTION_SUFFIXES[suffix.toLowerCase()] ?? suffix
}
/**
* 从 pack 索引条目的 `slug` 里取 `Levels.txt` 的关卡 Id。
*
* @param slug - e.g. `33-act-1-cathedral`.
* @returns the id, or null when the slug does not start with one.
*/
export function levelIdOfSlug(slug: string): number | null {
const match = /^(\d+)-/.exec(slug)
return match?.[1] === undefined ? null : Number(match[1])
}
/**
* 一个场景的中文名,取不到就回退调用方给的英文名。
*
* @param slug - the scene slug from the pack index.
* @param fallback - the English name from the pack index.
* @returns the display name.
*/
export function sceneNameZh(slug: string, fallback: string): string {
const id = levelIdOfSlug(slug)
if (id === null) return fallback
return LEVEL_NAMES_ZH[id] ?? fallback
}