Improve SCUM catalog readability

This commit is contained in:
npc0-hue
2026-09-24 20:46:43 +08:00
parent 7e0780ea51
commit 2f9b4b3780
4 changed files with 70 additions and 21 deletions
@@ -13,11 +13,11 @@ const directNames: Record<string, string> = {
BP_Seagull: "海鸥",
BP_Wolf3: "狼",
WildDuck: "鹿(目录别名)",
BP_Drifter_Lvl_1: "武装 NPC 1 级",
BP_Drifter_Lvl_2: "武装 NPC 2 级",
BP_Drifter_Lvl_3: "武装 NPC 3 级",
BP_Drifter_Lvl_4: "武装 NPC 4 级",
BP_Drifter_Lvl_5: "武装 NPC 5 级",
BP_Drifter_Lvl_1: "武装非玩家角色 1 级",
BP_Drifter_Lvl_2: "武装非玩家角色 2 级",
BP_Drifter_Lvl_3: "武装非玩家角色 3 级",
BP_Drifter_Lvl_4: "武装非玩家角色 4 级",
BP_Drifter_Lvl_5: "武装非玩家角色 5 级",
BP_Guard_Lvl_1: "武装守卫 1 级",
BP_Guard_Lvl_2: "武装守卫 2 级",
BP_Guard_Lvl_3: "武装守卫 3 级",
@@ -48,21 +48,23 @@ const directNames: Record<string, string> = {
FishingRod: "鱼竿",
FishingHook: "鱼钩",
Bait_trap_for_small_animals: "小型动物诱饵陷阱",
Improvised_Backpack_Big: "大背包",
Military_Helmet_01_01: "军用头盔 深绿",
Watermelon: "西瓜"
};
const wordNames: Record<string, string> = {
absinthe: "苦艾酒", animal: "动物", animals: "动物", apple: "苹果", armor: "护甲", arrow: "箭", arrows: "箭矢", aspirin: "阿司匹林", advanced: "高级", automatic: "自动",
backpack: "背包", bait: "诱饵", ball: "球", banana: "香蕉", bandage: "绷带", baseball: "棒球", battery: "电池", bear: "熊", beer: "啤酒", beet: "甜菜", berries: "浆果", blackberry: "黑莓", blueberries: "蓝莓", bolt: "弩箭", bottle: "瓶", bow: "弓", bread: "面包", brick: "砖块", broccoli: "西兰花", buck: "雄鹿", bullet: "子弹", bulletproof: "防弹", burger: "汉堡", burn: "烧伤", cake: "蛋糕", canned: "罐装", carbon: "碳纤维", carrot: "胡萝卜", cartridge: "弹药", cash: "现金", cheese: "奶酪", chicken: "鸡", civilian: "平民", cleaver: "菜刀", cola: "可乐", coffee: "咖啡", compound: "复合", construction: "施工", cooked: "熟制", cooking: "烹饪", crow: "乌鸦", crossbow: "弩", crucian: "鲫鱼", cup: "杯", dark: "深色", deer: "鹿", detonator: "雷管", dildo: "假阳具", donkey: "驴", double: "双头", drink: "饮料", drinks: "饮料", eagle: "鹰", edible: "可食用", energy: "能量", explosive: "爆炸", female: "女性", fish: "鱼", fishing: "钓鱼", floater: "浮漂", freshwater: "淡水", fruit: "水果", gas: "燃气", gasoline: "汽油", goat: "山羊", green: "绿色", grenade: "手雷", grey: "灰色", guts: "内脏", hammer: "锤子", hands: "手部", hat: "帽子", head: "头部", helmet: "头盔", hospital: "医院", hook: "鱼钩", horse: "马", human: "人类", improvised: "简易", injection: "注射剂", iron: "铁制", juice: "果汁", katana: "武士刀", knife: "刀", large: "大型", launcher: "发射器", leather: "皮革", level: "等级", lime: "青柠", lock: "锁", lockpick: "撬锁工具", magazine: "弹匣", male: "男性", medical: "医疗", medium: "中型", metal: "金属", milk: "牛奶", mushroom: "蘑菇", muzzle: "枪口", necklace: "项链", nylon: "尼龙", orange: "橙色", pack: "包", packaged: "包装", painkiller: "止痛药", pepper: "胡椒", pill: "药片", pills: "药片", pizza: "披萨", police: "警用", potato: "土豆", red: "红色", repair: "维修", rifle: "步枪", rope: "绳子", rabbit: "兔子", rice: "米饭", revolver: "左轮手枪", salad: "沙拉", sardine: "沙丁鱼", shotgun: "霰弹枪", shovel: "铲子", small: "小型", soda: "汽水", soup: "汤", stone: "石制", suppressor: "消音器", sword: "剑", syringe: "注射器", tea: "茶", tuna: "金枪鱼", vegetables: "蔬菜", vehicle: "载具", vest: "背心", vitamins: "维生素", vodka: "伏特加", water: "水", watermelon: "西瓜", whiskey: "威士忌", white: "白色", wolf: "狼", wooden: "木制", yellow: "黄色", zombie: "丧尸"
backpack: "背包", bait: "诱饵", ball: "球", banana: "香蕉", bandage: "绷带", baseball: "棒球", battery: "电池", bear: "熊", beer: "啤酒", beet: "甜菜", berries: "浆果", blackberry: "黑莓", blueberries: "蓝莓", bolt: "弩箭", bottle: "瓶", bow: "弓", bread: "面包", brick: "砖块", broccoli: "西兰花", buck: "雄鹿", bullet: "子弹", bulletproof: "防弹", burger: "汉堡", burn: "烧伤", cake: "蛋糕", canned: "罐装", carbon: "碳纤维", carrot: "胡萝卜", cartridge: "弹药", cash: "现金", cheese: "奶酪", chicken: "鸡", civilian: "平民", cleaver: "菜刀", cola: "可乐", coffee: "咖啡", compound: "复合", construction: "施工", cooked: "熟制", cooking: "烹饪", crow: "乌鸦", crossbow: "弩", crucian: "鲫鱼", cup: "杯", dark: "深色", deer: "鹿", detonator: "雷管", dildo: "假阳具", donkey: "驴", double: "双头", drink: "饮料", drinks: "饮料", eagle: "鹰", edible: "可食用", energy: "能量", explosive: "爆炸", female: "女性", fish: "鱼", fishing: "钓鱼", floater: "浮漂", freshwater: "淡水", fruit: "水果", gas: "燃气", gasoline: "汽油", goat: "山羊", goggles: "护目镜", green: "绿色", grenade: "手雷", grey: "灰色", guts: "内脏", hammer: "锤子", hands: "手部", hat: "帽子", head: "头部", helmet: "头盔", hospital: "医院", hook: "鱼钩", horse: "马", human: "人类", improvised: "简易", injection: "注射剂", iron: "铁制", juice: "果汁", katana: "武士刀", knife: "刀", large: "大型", launcher: "发射器", leather: "皮革", level: "等级", lime: "青柠", lock: "锁", lockpick: "撬锁工具", magazine: "弹匣", male: "男性", medical: "医疗", medium: "中型", metal: "金属", milk: "牛奶", mushroom: "蘑菇", muzzle: "枪口", necklace: "项链", nylon: "尼龙", orange: "橙色", pack: "包", packaged: "包装", painkiller: "止痛药", pepper: "胡椒", pill: "药片", pills: "药片", pizza: "披萨", police: "警用", potato: "土豆", red: "红色", repair: "维修", rifle: "步枪", rope: "绳子", rabbit: "兔子", rice: "米饭", revolver: "左轮手枪", salad: "沙拉", sardine: "沙丁鱼", shotgun: "霰弹枪", shovel: "铲子", small: "小型", soda: "汽水", soup: "汤", stone: "石制", suppressor: "消音器", sword: "剑", syringe: "注射器", tea: "茶", tuna: "金枪鱼", vegetables: "蔬菜", vehicle: "载具", vest: "背心", vitamins: "维生素", vodka: "伏特加", water: "水", watermelon: "西瓜", whiskey: "威士忌", white: "白色", wolf: "狼", wooden: "木制", yellow: "黄色", zombie: "丧尸"
};
const additionalWordNames: Record<string, string> = {
activated: "活性炭", alcohol: "酒精", alcoholic: "酒精类", anti: "抗", antibiotic: "抗生素", antimalaria: "抗疟疾", antiparasitic: "抗寄生虫", antipsychotic: "抗精神病", ammunition: "弹药", attachment: "配件", back: "后部", big: "大", body: "身体", boots: "靴子", box: "盒", bucket: "桶", camp: "营地", charcoal: "木炭", clothes: "服装", component: "组件", crafted: "制作的", crafting: "制作", dirty: "脏污", door: "车门", electrodes: "电极", farming: "农业", feet: "脚部", front: "前部", gear: "装备", gloves: "手套", hiking: "徒步", hood: "引擎盖", inventory: "背包栏", item: "物品", legs: "腿部", light: "轻型", military: "军用", normal: "普通", other: "其他", parts: "零件", rear: "后部", rubber: "橡胶", security: "安全", seat: "座椅", side: "侧面", single: "单发", skin: "皮肤", spare: "备用", standing: "立式", steel: "钢制", tactical: "战术", top: "顶部", trap: "陷阱", underwear: "内衣", weapon: "武器", wheel: "车轮"
activated: "活性炭", alcohol: "酒精", alcoholic: "酒精类", anti: "抗", antibiotic: "抗生素", antimalaria: "抗疟疾", antiparasitic: "抗寄生虫", antipsychotic: "抗精神病", ammunition: "弹药", assault: "突击", attachment: "配件", back: "后部", big: "大", black: "黑色", body: "身体", boots: "靴子", box: "盒", bucket: "桶", camp: "营地", cannabis: "大麻", charcoal: "木炭", clothes: "服装", component: "组件", corn: "玉米", crafted: "制作的", crafting: "制作", cucumber: "黄瓜", dirty: "脏污", desert: "沙漠", door: "车门", electrodes: "电极", expansion: "扩展", farming: "农业", feet: "脚部", fig: "无花果", front: "前部", garlic: "大蒜", gear: "装备", gloves: "手套", grapefruit: "葡萄柚", hiking: "徒步", hood: "引擎盖", intelligence: "智力", inventory: "背包栏", item: "物品", kit: "套件", legs: "腿部", lemon: "柠檬", light: "轻型", lettuce: "生菜", marpat: "MAR-PAT", memory: "存储", military: "军用", module: "模块", normal: "普通", other: "其他", parts: "零件", quiver: "箭袋", rear: "后部", rubber: "橡胶", scorpion: "蝎子", security: "安全", seat: "座椅", side: "侧面", single: "单发", skin: "皮肤", snow: "雪地", spare: "备用", standing: "立式", steel: "钢制", tactical: "战术", tip: "尖端", top: "顶部", trap: "陷阱", urban: "城市", underwear: "内衣", weapon: "武器", wheel: "车轮", woodland: "林地"
};
const phraseNames: Array<readonly [RegExp, string]> = [
[/^Armed Guard NPC Level (\d+)$/i, "武装守卫 $1 级"],
[/^Armed NPC Level (\d+)$/i, "武装 NPC $1 级"],
[/^Armed NPC Level (\d+)$/i, "武装非玩家角色 $1 级"],
[/^Zombie (.+) Female$/i, "女性丧尸 $1"],
[/^Zombie (.+) Male$/i, "男性丧尸 $1"],
[/^Zombie (.+)$/i, "丧尸 $1"],
@@ -80,15 +82,30 @@ const phraseNames: Array<readonly [RegExp, string]> = [
[/^(.+) Level (\d+)$/i, "$1 $2 级"]
];
const catalogKindNames: Record<string, string> = { item: "物品", vehicle: "载具", animal: "动物", zombie: "丧尸", "armed-npc": "NPC", razor: "其他" };
const catalogKindNames: Record<string, string> = { item: "物品", vehicle: "载具", animal: "动物", zombie: "丧尸", "armed-npc": "非玩家角色", razor: "其他" };
const fallbackNameGroups: Array<readonly [string, string]> = [
["/backpacks/", "背包"], ["/head armor/", "头部装备"], ["/weapons/", "武器"], ["/medicals/", "医疗物品"], ["/food/", "食物"], ["/clothes/", "服装"], ["/vehicles/", "载具部件"], ["/fishing/", "钓鱼用品"], ["/farming/", "农业用品"], ["/crafting/", "制作材料"]
];
export function scumCatalogNameZh(entry: ScumCatalogEntry): string {
const direct = directNames[entry.code];
if (direct) return direct;
const code = entry.code.replace(/[_-]+/g, " ");
if (/^Military_Backpack_/i.test(entry.code)) {
const variant = translateWords(usableName(entry).replace(/^(?:Military\s+)?(?:(?:Camo\s+)?Hiking|Assault)?\s*Backpack\s*/i, "")).trim();
return compactLabel("军用背包" + (variant ? " " + variant : ""));
}
if (/^Military_Helmet_/i.test(entry.code)) {
const variant = translateWords(usableName(entry).replace(/^Military Helmet\s*/i, "")).trim();
return compactLabel("军用头盔" + (variant ? " " + variant : ""));
}
const source = usableName(entry);
for (const [pattern, replacement] of phraseNames) if (pattern.test(source)) return translateWords(source.replace(pattern, replacement));
const translated = translateWords(source);
return translated === source ? `${catalogKindNames[entry.kind] ?? "物品"} · ${source}` : translated;
const translated = compactLabel(translateWords(source));
if (!/[A-Za-z]/.test(translated)) return translated;
const translatedCode = compactLabel(translateWords(code));
if (!/[A-Za-z]/.test(translatedCode)) return translatedCode;
return catalogFallbackName(entry);
}
export function scumCatalogDisplayName(entry: ScumCatalogEntry): string { return scumCatalogNameZh(entry); }
@@ -109,6 +126,17 @@ function usableName(entry: ScumCatalogEntry): string {
}
function translateWords(value: string): string {
const spaced = value.replace(/([a-z])([A-Z])/g, "$1 $2");
const normalized = value.replace(/\bDark Green\b/gi, "深绿").replace(/\bLight Green\b/gi, "浅绿");
const spaced = normalized.replace(/([a-z])([A-Z])/g, "$1 $2");
return spaced.replace(/[A-Za-z][A-Za-z'-]*/g, (word) => additionalWordNames[word.toLowerCase()] ?? wordNames[word.toLowerCase()] ?? word);
}
function catalogFallbackName(entry: ScumCatalogEntry): string {
const icon = entry.icon.toLowerCase();
const group = fallbackNameGroups.find(([needle]) => icon.includes(needle));
const prefix = group?.[1] ?? catalogKindNames[entry.kind] ?? "物品";
const serial = entry.code.match(/\d+/g)?.join("-");
return serial ? prefix + " " + serial : prefix + "条目";
}
function compactLabel(value: string): string { return value.replace(/\s+/g, " ").trim(); }