From ca55cd29d875bb8c83df9d253309959bcdae9418 Mon Sep 17 00:00:00 2001 From: troytt <47798984@qq.com> Date: Sat, 19 Sep 2026 12:35:08 +0000 Subject: [PATCH] =?UTF-8?q?feat(i18n):=20=E8=A1=A5=E5=85=A8=E6=9A=97?= =?UTF-8?q?=E9=BB=912=E5=85=A8=E9=87=8F=E8=AF=8D=E7=BC=80=E6=B1=89?= =?UTF-8?q?=E5=8C=96=E3=80=81=E4=BF=AE=E5=A4=8D=E8=AF=AD=E5=BA=8F=E5=80=92?= =?UTF-8?q?=E8=A3=85=E3=80=81=E5=85=85=E8=83=BD=E6=8A=80=E8=83=BD=E8=B4=9F?= =?UTF-8?q?=E6=95=B0=E4=B8=8E=E5=B1=9E=E6=80=A7=E8=AF=8D=E6=9D=A1=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=20(Issue=20#122)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/audit-boss-kill-10-zh.js | 183 ++++ scripts/generate-affix-dictionaries.ts | 607 +++++++++++ src/game/item-tooltip.ts | 315 +----- src/game/skills-data.ts | 304 ++++++ src/game/tooltip-i18n.ts | 1320 ++++++++++++++++++------ tests/item-tooltip-i18n-122.test.ts | 33 +- 6 files changed, 2117 insertions(+), 645 deletions(-) create mode 100644 scripts/audit-boss-kill-10-zh.js create mode 100644 scripts/generate-affix-dictionaries.ts create mode 100644 src/game/skills-data.ts diff --git a/scripts/audit-boss-kill-10-zh.js b/scripts/audit-boss-kill-10-zh.js new file mode 100644 index 0000000..21e305a --- /dev/null +++ b/scripts/audit-boss-kill-10-zh.js @@ -0,0 +1,183 @@ +import { spawn } from 'child_process' + +async function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +async function runBrowserAudit() { + console.log('1. Starting Google Chrome headless...') + const chromeProc = spawn('/usr/bin/google-chrome', [ + '--headless=new', + '--remote-debugging-port=9222', + '--no-sandbox', + '--disable-gpu', + '--disable-extensions', + 'http://localhost:8080/boss.html', + ]) + + // Wait for Chrome to be ready + let wsUrl = null + for (let i = 0; i < 30; i++) { + await sleep(300) + try { + const res = await fetch('http://127.0.0.1:9222/json/list') + const pages = await res.json() + const page = pages.find(p => p.type === 'page' && p.url.includes('boss.html')) + if (page && page.webSocketDebuggerUrl) { + wsUrl = page.webSocketDebuggerUrl + break + } + } catch (e) { + // keep trying + } + } + + if (!wsUrl) { + chromeProc.kill() + throw new Error('Failed to connect to Chrome headless CDP within 10s') + } + + console.log('2. Connected to Chrome CDP on page:', wsUrl) + + const ws = new WebSocket(wsUrl) + await new Promise(resolve => ws.onopen = resolve) + + let idCounter = 1 + function sendCommand(method, params = {}) { + return new Promise((resolve, reject) => { + const id = idCounter++ + const handler = event => { + const msg = JSON.parse(event.data) + if (msg.id === id) { + ws.removeEventListener('message', handler) + if (msg.error) reject(msg.error) + else resolve(msg.result) + } + } + ws.addEventListener('message', handler) + ws.send(JSON.stringify({ id, method, params })) + }) + } + + // Enable Runtime + await sendCommand('Runtime.enable') + + // Wait 1.5s for initial drop tables to load + await sleep(1500) + + console.log('3. Triggering Chinese language switch and 10x Boss Kill in browser DOM...') + + const evalResult = await sendCommand('Runtime.evaluate', { + expression: `(async () => { + // 1. Click Chinese language pill + const zhPill = document.querySelector('.lang-pill[data-lang="zh"]'); + if (zhPill) zhPill.click(); + + // 2. Click 10x kill button + const kill10Btn = document.getElementById('btn-kill-10'); + if (kill10Btn) kill10Btn.click(); + + // Wait a short moment for DOM rendering + await new Promise(r => setTimeout(r, 800)); + + // 3. Extract items + const cards = Array.from(document.querySelectorAll('#loot-items-grid .d2-item-card')); + return cards.map(c => { + const title = c.querySelector('.item-title')?.textContent?.trim() || ''; + const subTitle = c.querySelector('.item-subtitle')?.textContent?.trim() || ''; + const quality = c.querySelector('.item-quality-pill')?.textContent?.trim() || ''; + const ilvl = c.querySelector('.item-ilvl-pill')?.textContent?.trim() || ''; + const stats = Array.from(c.querySelectorAll('.item-base-stats .base-stat-item')).map(s => s.textContent.trim()); + const affixes = Array.from(c.querySelectorAll('.item-affix-lines .tooltip-stat-line')).map(a => a.textContent.trim()); + return { + title, + subTitle, + quality, + ilvl, + stats, + affixes + }; + }); + })()`, + awaitPromise: true, + returnByValue: true, + }) + + console.log('4. Evaluation completed. Closing Chrome...') + ws.close() + chromeProc.kill() + + const items = evalResult.result.value + console.log(`\nSuccessfully captured ${items.length} items from http://localhost:8080/boss.html!\n`) + return items +} + +runBrowserAudit() + .then(items => { + console.log('================================================================'); + console.log(`=== AUDITING ALL ${items.length} ITEMS GENERATED FROM 10x BOSS KILL ===`); + console.log('================================================================\n'); + + let errorsFound = 0; + const traditionalChars = ['屬', '無', '紅', '綠', '變', '爛', '誕', '誠', '雲', '犧', '嚇', '層', '靜', '換', '亂', '節', '甦']; + + items.forEach((item, index) => { + console.log(`[#${index + 1}] [${item.quality}] ${item.title} (底材: ${item.subTitle || '无'}, ${item.ilvl})`); + if (item.stats.length > 0) { + console.log(` 基础属性: ${item.stats.join(' | ')}`); + } + if (item.affixes.length > 0) { + console.log(` 词条属性:`); + item.affixes.forEach(aff => console.log(` * ${aff}`)); + } + + // Check 1: Negative numbers in charged spells + item.affixes.forEach(aff => { + if (aff.includes('次充能') && (aff.includes('等级 -') || aff.includes('(-'))) { + console.error(` ❌ ERROR: Negative value in charged spell: "${aff}"`); + errorsFound++; + } + }); + + // Check 2: Missing English affix translations (e.g. English letters followed by 之 or preceded by 之) + const englishAffixMatch = item.title.match(/[a-zA-Z]+之|之[a-zA-Z]+/); + if (englishAffixMatch) { + console.error(` ❌ ERROR: Untranslated English affix in title: "${item.title}"`); + errorsFound++; + } + + // Check 3: Word order anomaly: base name followed by '之' at the end of title + if (item.subTitle && item.title.endsWith(item.subTitle + '之')) { + console.error(` ❌ ERROR: Word order inversion (base followed by suffix particle): "${item.title}"`); + errorsFound++; + } + + // Check 4: Traditional Chinese characters + const allText = item.title + ' ' + item.subTitle + ' ' + item.affixes.join(' '); + traditionalChars.forEach(ch => { + if (allText.includes(ch)) { + console.error(` ❌ ERROR: Traditional Chinese character '${ch}' found in: "${allText}"`); + errorsFound++; + } + }); + + console.log(''); + }); + + console.log('================================================================'); + if (errorsFound === 0) { + console.log(`🎉 AUDIT PASSED! All ${items.length} items checked with ZERO errors!`); + console.log(`✅ All names in correct Chinese grammar word order`); + console.log(`✅ 100% Affix translations matched without fallback artifacts`); + console.log(`✅ Charged spell positive charges and positive skill levels verified`); + console.log(`✅ Normalized Simplified Chinese characters verified`); + } else { + console.error(`⚠️ AUDIT FOUND ${errorsFound} ERRORS!`); + process.exit(1); + } + console.log('================================================================\n'); + }) + .catch(err => { + console.error('Audit execution failed:', err); + process.exit(1); + }); diff --git a/scripts/generate-affix-dictionaries.ts b/scripts/generate-affix-dictionaries.ts new file mode 100644 index 0000000..49d3265 --- /dev/null +++ b/scripts/generate-affix-dictionaries.ts @@ -0,0 +1,607 @@ +import { getEmbeddedDropTables } from '../src/game/embedded-drop-tables.ts' +import { SKILL_NAMES_ZH } from '../src/game/tooltip-i18n.ts' + +const dt = getEmbeddedDropTables() +const prefixes = Array.from(new Set(dt.magicAffixes.prefixes.all.map(p => p.name))).sort() +const suffixes = Array.from(new Set(dt.magicAffixes.suffixes.all.map(s => s.name))).sort() + +// Complete 252 prefixes +const prefixMap: Record = { + "Accursed": "诅咒之", + "Acrobat's": "杂技之", + "Amber": "琥珀之", + "Ambergris": "龙涎香之", + "Amethyst": "紫水晶之", + "Angel's": "天使之", + "Antimagic": "防魔之", + "Arcadian": "阿卡迪亚之", + "Arch-Angel's": "大天使之", + "Archer's": "弓箭手之", + "Arcing": "电弧之", + "Argent": "白银之", + "Artificer's": "工匠之", + "Assamic": "阿萨姆之", + "Astral": "星界之", + "Athlete": "运动之", + "Athlete's": "运动之", + "Aureolin": "钴黄之", + "Azure": "天青之", + "Bahamut's": "巴哈姆特之", + "Beryl": "绿柱石之", + "Berserker's": "狂战士之", + "Bishop's": "主教之", + "Blanched": "漂白之", + "Blank": "虚无之", + "Blazing": "炽热之", + "Blessed": "祝福之", + "Blighting": "枯萎之", + "Bloody": "血腥之", + "Bone": "白骨之", + "Boreal": "极北之", + "Bowyer's": "弓箭手之", + "Bright": "光明之", + "Bronze": "青铜之", + "Brown": "棕褐之", + "Brutal": "残忍之", + "Burgundy": "红棕之", + "Burly": "魁梧之", + "Burning": "燃烧之", + "Buzzing": "嗡鸣之", + "Calling": "呼唤之", + "Camphor": "樟脑之", + "Captain's": "领袖之", + "Carbuncle": "痈肿之", + "Caretaker's": "看顾者之", + "Carmine": "洋红之", + "Celestial": "天界之", + "Charged": "充能之", + "Chestnut": "栗色之", + "Chilling": "严寒之", + "Chromatic": "炫彩之", + "Cinnabar": "朱砂之", + "Cobalt": "钴蓝之", + "Commander's": "指挥官之", + "Communal": "公社之", + "Compact": "紧密之", + "Consecrated": "奉献之", + "Coral": "珊瑚之", + "Corosive": "腐蚀之", + "Crimson": "枣红之", + "Cruel": "残忍之", + "Cunning": "狡黠之", + "Deadly": "致命之", + "Dense": "致密之", + "Devious": "迂回之", + "Diamond": "钻石之", + "Divine": "神圣之", + "Dragon's": "龙之", + "Drake's": "德尔克之", + "Dun": "黑褐之", + "Eagleeye": "雕眼之", + "Earth": "大地之", + "Eburin": "象牙之", + "Echoing": "回音之", + "Elysian": "极乐之", + "Ember": "余烬之", + "Emerald": "绿宝石之", + "Entrapping": "陷阱之", + "Envenomed": "腐烂之", + "Eocene": "始新世之", + "Expert's": "专家之", + "Falconeye": "猎鹰之眼", + "Fanatic": "狂热之", + "Felicitous": "吉庆之", + "Feral": "野性之", + "Ferocious": "凶猛之", + "Fine": "精良之", + "Flaming": "烈焰之", + "Fletcher's": "制箭者之", + "Fool's": "愚人之", + "Forked": "分叉之", + "Fortified": "防御强化之", + "Fortuitous": "偶然之", + "Freezing": "冰冻之", + "Fungal": "真菌之", + "Furious": "狂怒之", + "Gaea's": "大地之", + "Gaia": "大地之", + "Garnet": "石榴石之", + "Glacial": "极冰之", + "Glimmering": "微光之", + "Glorious": "光荣之", + "Glowing": "发光之", + "Godly": "神圣之", + "Gold": "金之", + "Golemlord": "魔像领主之", + "Golemlord's": "魔像领主之", + "Grandmaster's": "宗师之", + "Graverobber's": "盗墓者之", + "Great Wyrm's": "大巨龙之", + "Gritty": "坚韧之", + "Guardian's": "护卫者之", + "Gymnastic": "体操之", + "Gymnast's": "体操之", + "Hallowed": "神圣之", + "Harpoonist's": "标枪之", + "Hawk Branded": "鹰之烙印之", + "Hawkeye": "鹰眼之", + "Hexing": "诅咒之", + "Hibernal": "极寒之", + "Hierophant's": "教皇之", + "Holy": "神圣之", + "Howling": "咆哮之", + "Iron": "铁之", + "Ivory": "象牙之", + "Jacinth": "风信子石之", + "Jack's": "随从之", + "Jade": "翡翠之", + "Jagged": "锯齿之", + "Jester's": "弄臣之", + "Jeweler's": "珠宝匠之", + "Joker's": "小丑之", + "Kenshi's": "剑士之", + "Keeper's": "守护者之", + "King's": "国王之", + "Knave's": "盗贼之", + "Knight's": "骑士之", + "Lancer's": "长矛手之", + "Lapis": "青金石之", + "Lapis Lazuli": "青金石之", + "Lion Branded": "狮子烙印之", + "Lizard's": "蜥蜴之", + "Lord's": "领主之", + "Loud": "响亮之", + "Lucky": "幸运之", + "Magekiller's": "法师杀手之", + "Maiden's": "处女之", + "Maroon": "褐红之", + "Marshal": "元帅之", + "Marshal's": "元帅之", + "Massive": "稳重之", + "Master's": "大师之", + "Mechanist's": "机械师之", + "Mentalist": "通灵之", + "Mentalist's": "通灵之", + "Merciless": "绝情之", + "Meteoric": "陨铁之", + "Miocene": "中新世之", + "Mnemonic": "记忆之", + "Monk's": "僧人之", + "Nature": "自然之", + "Nature's": "自然之", + "Necromancer": "死灵法师之", + "Necromancer's": "死灵法师之", + "Nickel": "白镍之", + "Noxious": "有害之", + "Null": "无效之", + "Ocher": "赭黄之", + "Oligocene": "渐新世之", + "Paleocene": "忠诚信使之", + "Paradox": "悖论之", + "Patriarch's": "先知之", + "Pearl": "珍珠之", + "Pestilent": "瘟疫之", + "Platinum": "白金之", + "Powered": "能量之", + "Preserver": "保护者之", + "Preserver's": "保护者之", + "Priest's": "祭司之", + "Prismatic": "彩虹之", + "Psychic": "心灵之", + "Pure": "纯净之", + "Raging": "暴怒之", + "Rainbow": "彩虹之", + "Realgar": "雄黄之", + "Red": "红之", + "Resonant": "共鸣之", + "Robineye": "知更鸟眼之", + "Rose Branded": "玫瑰烙印之", + "Ruby": "红宝石之", + "Rugged": "凹凸之", + "Russet": "铁锈之", + "Rusty": "生锈之", + "Sacred": "圣洁之", + "Saintly": "崇高之", + "Sanguinary": "鲜血之", + "Sapphire": "蓝宝石之", + "Savage": "野蛮之", + "Scarlet": "猩红之", + "Scintillating": "闪烁之", + "Scorching": "灼烧之", + "Screaming": "尖叫之", + "Sensei's": "老师之", + "Septic": "腐臭之", + "Serpent's": "海蛇之", + "Serrated": "锯齿之", + "Shadow": "阴影之", + "Shaman's": "萨满之", + "Sharp": "尖锐之", + "Shimmering": "微光之", + "Shivering": "寒颤之", + "Shocking": "雷霆之", + "Shogukusha's": "刺客之", + "Shouting": "咆哮之", + "Silver": "银之", + "Slayer's": "屠杀者之", + "Smoldering": "焖燃之", + "Smoking": "烟雾之", + "Snake's": "蛇之", + "Snowflake": "雪花之", + "Soldier's": "士兵之", + "Sounding": "鸣响之", + "Sparking": "火花之", + "Sparroweye": "麻雀眼之", + "Spearmaiden's": "标枪女郎之", + "Spiritual": "精神之", + "Stalwart": "健壮之", + "Static": "静电之", + "Steel": "钢之", + "Stout": "坚固之", + "Strange": "怪异之", + "Strong": "强壮之", + "Sturdy": "结实之", + "Summoner's": "召唤者之", + "Tangerine": "橙黄之", + "Terra's": "大地之", + "Thin": "轻薄之", + "Tin": "白铁之", + "Tireless": "不倦之", + "Topaz": "黄宝石之", + "Toxic": "剧毒之", + "Trainer's": "驯兽师之", + "Trickster's": "戏法师之", + "Triumphant": "得胜之", + "Trump": "胜者之", + "Turquoise": "绿松石之", + "Unearthly": "超凡之", + "Valkyrie's": "女武神之", + "Venomous": "剧毒之", + "Vermillion": "朱砂之", + "Veteran's": "老兵之", + "Vicious": "恶毒之", + "Victorious": "胜利之", + "Vigorous": "强健之", + "Viridian": "铭绿之", + "Visionary": "梦幻之", + "Vodoun": "伏都之", + "Volcanic": "火山之", + "Vulpine": "奸诈之", + "Wailing": "哀嚎之", + "Warden": "看守者之", + "Warder's": "监视者之", + "Warrior's": "战士之", + "Weird": "怪异之", + "Witch-hunter's": "猎巫者之", + "Wyrm's": "维特之", + "Yelling": "呐喊之", + "Zircon": "锆石之" +} + +// Complete 288 suffixes +const suffixBaseMap: Record = { + "Health": "健康之", + "Acceleration": "加速之", + "Anima": "生灵之", + "Balance": "平衡之", + "Equilibrium": "均势之", + "Stability": "安定之", + "Chance": "几率之", + "Greed": "贪欲之", + "Wealth": "财富之", + "Light": "光明之", + "Radiance": "光辉之", + "the Sun": "太阳之", + "Nirvana": "涅槃之", + "Vileness": "卑劣之", + "the Colosuss": "巨神之", + "the Jackal": "胡狼之", + "Protection": "守护之", + "Absorption": "吸收之", + "Life": "生命之", + "Warding": "防避之", + "the Sentinel": "步哨之", + "Guarding": "守卫之", + "Negation": "否定之", + "Piercing": "刺穿之", + "Bashing": "重击之", + "Puncturing": "爆破之", + "Thorns": "荆棘之", + "Spikes": "尖刺之", + "Readiness": "准备之", + "Alacrity": "迅捷之", + "Swiftness": "疾速之", + "Quickness": "快速之", + "Blocking": "格挡之", + "Deflecting": "偏向之", + "the Apprentice": "学徒之", + "the Magus": "法师之", + "Frost": "冰霜之", + "the Glacier": "冰川之", + "Flame": "火焰之", + "Fire": "烈火之", + "Burning": "燃烧之", + "Lightning": "闪电之", + "Thunder": "雷霆之", + "Shock": "电击之", + "Spark": "火花之", + "Static": "静电之", + "Craftsmanship": "工匠之", + "Quality": "品质之", + "Maiming": "残废之", + "Slaying": "杀戮之", + "Gore": "鲜血之", + "Carnage": "大屠杀之", + "Slaughter": "屠杀之", + "Butchery": "屠戮之", + "Evisceration": "剖腹之", + "Destruction": "毁灭之", + "Worth": "价值之", + "Measure": "度量之", + "Excellence": "卓越之", + "Performance": "精良之", + "Joyfulness": "欢欣之", + "Bliss": "至福之", + "Blight": "枯萎之", + "Venom": "毒素之", + "Pestilence": "瘟疫之", + "Anthrax": "炭疽之", + "Frostbite": "冻疮之", + "the Leech": "水蛭之", + "the Bat": "蝙蝠之", + "the Vampire": "吸血鬼之", + "the Lamprey": "八目鳗之", + "the Wraith": "幽灵之", + "the Ghoul": "食尸鬼之", + "the Locust": "蝗虫之", + "Daring": "果敢之", + "Truth": "真理之", + "Honor": "荣耀之", + "Avarice": "贪婪之", + "Luck": "幸运之", + "Good Luck": "好运之", + "Prosperity": "繁荣之", + "Fortune": "财富之", + "Perfection": "完美之", + "Enlightenment": "启迪之", + "Knowledge": "知识之", + "Substinence": "生计之", + "Vita": "活力之", + "Spirit": "精神之", + "Hope": "希望之", + "Freedom": "自由之", + "Atlus": "阿特拉斯之", + "Virility": "刚毅之", + "Traveling": "旅行之", + "Inertia": "抗性之", + "Self-Repair": "自我修复之", + "Fast Repair": "快速修复之", + "Ages": "万古之", + "Replenishing": "充盈之", + "Propogation": "繁衍之", + "the Kraken": "海妖之", + "Memory": "记忆之", + "the Elephant": "大象之", + "Power": "力量之", + "Grace": "优雅之", + "Grace and Power": "优雅与力量之", + "the Yeti": "雪人之", + "the Phoenix": "凤凰之", + "the Efreeti": "火灵之", + "the Cobra": "眼镜蛇之", + "the Elements": "元素之", + "the Icicle": "冰柱之", + "Winter": "严冬之", + "Frigidity": "寒冷之", + "Incineration": "焚化之", + "Passion": "激情之", + "Storms": "风暴之", + "Ennui": "厌倦之", + "Ire": "愤怒之", + "Wrath": "盛怒之", + "Transcendence": "卓越之", + "Envy": "嫉妒之", + "Fervor": "狂热之", + "Speed": "速度之", + "Haste": "急速之", + "Dexterity": "敏捷之", + "Skill": "技巧之", + "Accuracy": "准确之", + "Precision": "精确之", + "Sniping": "狙击之", + "the Bear": "巨熊之", + "Strength": "力量之", + "Might": "强力之", + "the Ox": "公牛之", + "the Giant": "巨人之", + "the Titan": "泰坦之", + "the Fox": "狐狸之", + "the Wolf": "苍狼之", + "the Tiger": "猛虎之", + "the Mammoth": "猛犸之", + "the Colossus": "巨神之", + "the Squid": "乌贼之", + "the Whale": "巨鲸之", + "Defiance": "蔑视之", + "Fumigation": "熏蒸之", + "Ease": "轻便之", + "Simplicity": "简朴之", + "Dawn": "黎明之", + "Sunlight": "阳光之", + "Energy": "能量之", + "Mind": "心灵之", + "Brilliance": "辉煌之", + "Sorcery": "巫术之", + "Wizardry": "法术之", + "Warmth": "温暖之", + "Remedy": "救治之", + "Amelioration": "改善之", + "Regeneration": "再生之", + "Regrowth": "新生之", + "Revivification": "复苏之", + "Spikers": "尖刺之", + "Passing": "消逝之", + "Stamina": "耐力之", + "Pacing": "步行之", + "Striding": "跨步之", + "Health Everlasting": "永恒健康之", + "Life Everlasting": "永恒生命之", + "Amianthus": "石棉之", + "Fire Quenching": "灭火之", + "Incombustibility": "不燃之", + "Coolness": "清凉之", + "Faith": "信仰之", + "Resistance": "抗性之", + "Insulation": "绝缘之", + "Grounding": "接地之", + "the Dynamo": "发电机之", + "Stoicism": "坚忍之", + "Warming": "保温之", + "Thawing": "解冻之", + "the Dunes": "沙丘之", + "the Sirocco": "热风之", + "Desire": "渴望之", + "Razors": "剃刀之", + "Swords": "剑刃之", + "Malice": "恶意之", + "the Mind": "心灵之", + "Telekinesis": "心灵传动之", + "Teleportation": "传送之", + "Teleport Shield": "传送护盾之", + "Inner Sight": "内视之", + "Slow Missiles": "慢速箭之", + "Damage Amplification": "伤害加深之", + "Amplify Damage": "伤害加深之", + "Weaken": "削弱之", + "Dim Vision": "微暗灵视之", + "Iron Maiden": "攻击反噬之", + "Terror": "恐惧之", + "Confusion": "迷乱之", + "Life Tap": "偷取生命之", + "Attraction": "吸引之", + "Decrepification": "衰老之", + "Lower Resistance": "降低抗性之", + "Taunting": "嘲弄之", + "Howling": "狂嚎之", + "Shouting": "大叫之", + "Battle Cry": "刺耳尖叫之", + "Battle Orders": "战斗体制之", + "Battle Command": "战斗指挥之", + "War Cry": "战鸣之", + "Stunning": "击晕之", + "Concentration": "专注之", + "Grim Ward": "残骸清理之", + "Item Finding": "寻找物品之", + "Potion Finding": "寻找药剂之", + "Holy Bolts": "圣光弹之", + "Blessed Hammers": "祝福之槌之", + "Conversion": "转化之", + "Sacrifice": "牺牲之", + "Zeal": "热诚之", + "Vengeance": "复仇之", + "Fist of the Heavens": "天堂之拳之", + "Static Field": "静电场之", + "Nova": "新星之", + "Novas": "新星之", + "Nova Shield": "新星护盾之", + "Frost Novas": "冰霜新星之", + "Frost Shield": "冰霜护盾之", + "Ice Blast": "冰风暴之", + "Ice Blasts": "冰风暴之", + "Icebolt": "冰弹之", + "Ice Bolts": "冰弹之", + "Glacial Spike": "冰尖柱之", + "Glacial Spikes": "冰尖柱之", + "Blizzard": "暴风雪之", + "Blizzards": "暴风雪之", + "Frozen Orb": "冰封球之", + "Frozen Orbs": "冰封球之", + "Frozen Armor": "冰封甲之", + "Shiver Armor": "碎冰甲之", + "Chilling Armor": "寒冰甲之", + "Charged Bolts": "充能弹之", + "Charged Shield": "充能护盾之", + "Charged Strike": "充能一击之", + "Lightning Strike": "雷电一击之", + "Lightning Javelin": "闪电标枪之", + "Lightning Fury": "闪电之怒之", + "Chain Lightning": "连锁闪电之", + "Thunder Storm": "雷暴之", + "Energy Shield": "能量护盾之", + "Hydras": "九头海蛇之", + "Hydra Shield": "九头蛇护盾之", + "Firebolt": "火弹之", + "Firebolts": "火弹之", + "Fire Bolts": "火弹之", + "Fire Ball": "火球之", + "Fire Balls": "火球之", + "Fire Wall": "火墙之", + "Fire Walls": "火墙之", + "Enchant": "强化之", + "Enchantment": "强化之", + "Meteor": "陨石之", + "Meteors": "陨石之", + "Blaze": "炽烈之径之", + "Blazing": "炽烈之径之", + "Firestorms": "火风暴之", + "Molten Boulders": "熔岩巨石之", + "Eruption": "火山喷发之", + "Cyclone Armor": "飓风装甲之", + "Twister": "龙卷风之", + "Volcano": "火山之", + "Tornado": "暴风之", + "Armageddon": "末日风暴之", + "Hurricane": "飓风之", + "Teeth": "牙之", + "Bone Armor": "白骨装甲之", + "Poison Dagger": "毒匕首之", + "Corpse Explosions": "尸体爆炸之", + "Bone Walls": "骨墙之", + "Poison Explosion": "毒爆之", + "Bone Spears": "骨矛之", + "Bone Imprisonment": "骨牢之", + "Poison Novas": "剧毒新星之", + "Bone Spirits": "白骨之魂之", + "Clay Golem Summoning": "黏土魔像之", + "Blood Golem Summoning": "鲜血魔像之", + "Iron Golem Creation": "钢铁魔像之", + "Fire Golem Summoning": "火焰魔像之", + "Raise Skeletons": "复生骷髅之", + "Raise Skeletal Mages": "骷髅法师之", + "Magic Arrows": "魔法箭之", + "Fire Arrows": "火箭之", + "Cold Arrows": "冰箭之", + "Multiple Shot": "多重箭之", + "Exploding Arrows": "爆裂箭之", + "Ice Arrows": "冻结箭之", + "Guided Arrows": "追踪箭之", + "Immolating Arrows": "牺牲之箭之", + "Freezing Arrows": "急冻箭之", + "Power Strike": "威力一击之", + "Poison Jab": "毒枪之", + "Jabbing": "戳刺之", + "Impaling Strike": "刺爆之", + "Fending": "击退之", + "Plague Jab": "瘟疫标枪之" +} + +// Build full suffix map +const suffixMap: Record = {} +for (const [k, v] of Object.entries(suffixBaseMap)) { + suffixMap['of ' + k] = v + suffixMap[k] = v +} + +// Validation +const missingPre = prefixes.filter(p => !prefixMap[p]) +const missingSuf = suffixes.filter(s => !suffixMap[s] && !suffixMap['of ' + s]) + +console.log('Validating coverage...') +console.log('Prefix coverage: ' + (prefixes.length - missingPre.length) + ' / ' + prefixes.length) +if (missingPre.length > 0) console.log('Missing prefixes:', missingPre) + +console.log('Suffix coverage: ' + (suffixes.length - missingSuf.length) + ' / ' + suffixes.length) +if (missingSuf.length > 0) console.log('Missing suffixes:', missingSuf) + +if (missingPre.length === 0 && missingSuf.length === 0) { + console.log('SUCCESS! 100% Affix Coverage achieved for all 252 prefixes and 288 suffixes.') +} diff --git a/src/game/item-tooltip.ts b/src/game/item-tooltip.ts index 88168c1..13256b0 100644 --- a/src/game/item-tooltip.ts +++ b/src/game/item-tooltip.ts @@ -144,305 +144,18 @@ const RUNE_INFO: Record = { - ama: '(Amazon Only)', - sor: '(Sorceress Only)', - nec: '(Necromancer Only)', - pal: '(Paladin Only)', - bar: '(Barbarian Only)', - dru: '(Druid Only)', - ass: '(Assassin Only)', -} - -const SKILL_LOOKUP_BY_ID = new Map() -const SKILL_LOOKUP_BY_NAME = new Map() - -for (const [id, rawName, displayName, cls] of CANONICAL_SKILLS) { - const classOnly = cls ? CLASS_ONLY_LABELS[cls] : undefined - const info = classOnly ? { name: displayName, classOnly } : { name: displayName } - SKILL_LOOKUP_BY_ID.set(id, info) - SKILL_LOOKUP_BY_NAME.set(rawName.toLowerCase(), info) - SKILL_LOOKUP_BY_NAME.set(displayName.toLowerCase(), info) -} - -/** - * Resolves a skill parameter (numeric ID or internal name from Skills.txt) - * into its 1.13c canonical English display name and optional class restriction. - */ -export function resolveSkillInfo(par: string | number | undefined): { name: string; classOnly?: string } { - if (par === undefined || par === '') return { name: 'Skill' } - const str = String(par).trim() - const num = Number(str) - if (!Number.isNaN(num) && SKILL_LOOKUP_BY_ID.has(num)) { - return SKILL_LOOKUP_BY_ID.get(num)! - } - const byName = SKILL_LOOKUP_BY_NAME.get(str.toLowerCase()) - if (byName) return byName - return { name: str } -} - -/** - * Canonical 1.13c skilltab mapping (par 0..20 from CharStats.txt StrSkillTab1..3 + StrClassOnly). - */ -const CANONICAL_SKILL_TABS: Record = { - 0: 'Bow and Crossbow Skills (Amazon Only)', - 1: 'Passive and Magic Skills (Amazon Only)', - 2: 'Javelin and Spear Skills (Amazon Only)', - 3: 'Fire Skills (Sorceress Only)', - 4: 'Lightning Skills (Sorceress Only)', - 5: 'Cold Skills (Sorceress Only)', - 6: 'Curses (Necromancer Only)', - 7: 'Poison and Bone Skills (Necromancer Only)', - 8: 'Summoning Skills (Necromancer Only)', - 9: 'Combat Skills (Paladin Only)', - 10: 'Offensive Auras (Paladin Only)', - 11: 'Defensive Auras (Paladin Only)', - 12: 'Combat Skills (Barbarian Only)', - 13: 'Masteries (Barbarian Only)', - 14: 'Warcries (Barbarian Only)', - 15: 'Summoning Skills (Druid Only)', - 16: 'Shape Shifting Skills (Druid Only)', - 17: 'Elemental Skills (Druid Only)', - 18: 'Traps (Assassin Only)', - 19: 'Shadow Disciplines (Assassin Only)', - 20: 'Martial Arts (Assassin Only)', -} - -/** - * Canonical 1.13c MonStats.txt hcIdx -> NameStr for reanimate property. - */ -const CANONICAL_REANIMATE_MONSTERS: Record = { - 0: 'Skeleton', - 1: 'Returned', - 2: 'Bone Warrior', - 3: 'Burning Dead', - 4: 'Horror', - 5: 'Zombie', +export { + resolveSkillInfo, + CANONICAL_SKILLS, + CANONICAL_SKILL_TABS, + CANONICAL_REANIMATE_MONSTERS, } function formatPerLevelVal(rawEighths: number): string { @@ -502,7 +215,7 @@ export function formatPropertyCode( const plusVal = effectiveVal >= 0 ? `+${effectiveVal}` : `${effectiveVal}` - switch (code.trim().toLowerCase()) { + switch (code.trim().toLowerCase().replace(/^\*/, '')) { // --- Skills & Class Skills (descFunc 1, 13, 14, 16, 27, 28) --- case 'allskills': return `${plusVal} to All Skills` @@ -590,8 +303,8 @@ export function formatPropertyCode( } case 'charged': { const sk = resolveSkillInfo(par) - const charges = min || effectiveVal || 10 - const slvl = max || 1 + const charges = Math.abs(min || effectiveVal || 10) + const slvl = Math.abs(max || 1) return `Level ${slvl} ${sk.name} (${charges}/${charges} Charges)` } diff --git a/src/game/skills-data.ts b/src/game/skills-data.ts new file mode 100644 index 0000000..8a850ec --- /dev/null +++ b/src/game/skills-data.ts @@ -0,0 +1,304 @@ +/** + * Canonical 1.13c Skills Data & ID Lookup Table (Skills.txt). + */ +export const CANONICAL_SKILLS: readonly [number, string, string, string][] = [ + [0, "Attack", "Attack", ""], + [1, "Kick", "Kick", ""], + [2, "Throw", "Throw", ""], + [3, "Unsummon", "Unsummon", ""], + [4, "Left Hand Throw", "Left Hand Throw", ""], + [5, "Left Hand Swing", "Left Hand Swing", ""], + [6, "Magic Arrow", "Magic Arrow", "ama"], + [7, "Fire Arrow", "Fire Arrow", "ama"], + [8, "Inner Sight", "Inner Sight", "ama"], + [9, "Critical Strike", "Critical Strike", "ama"], + [10, "Jab", "Jab", "ama"], + [11, "Cold Arrow", "Cold Arrow", "ama"], + [12, "Multiple Shot", "Multiple Shot", "ama"], + [13, "Dodge", "Dodge", "ama"], + [14, "Power Strike", "Power Strike", "ama"], + [15, "Poison Javelin", "Poison Javelin", "ama"], + [16, "Exploding Arrow", "Exploding Arrow", "ama"], + [17, "Slow Missiles", "Slow Missiles", "ama"], + [18, "Avoid", "Avoid", "ama"], + [19, "Impale", "Impale", "ama"], + [20, "Lightning Bolt", "Lightning Bolt", "ama"], + [21, "Ice Arrow", "Ice Arrow", "ama"], + [22, "Guided Arrow", "Guided Arrow", "ama"], + [23, "Penetrate", "Penetrate", "ama"], + [24, "Charged Strike", "Charged Strike", "ama"], + [25, "Plague Javelin", "Plague Javelin", "ama"], + [26, "Strafe", "Strafe", "ama"], + [27, "Immolation Arrow", "Immolation Arrow", "ama"], + [28, "Dopplezon", "Decoy", "ama"], + [29, "Evade", "Evade", "ama"], + [30, "Fend", "Fend", "ama"], + [31, "Freezing Arrow", "Freezing Arrow", "ama"], + [32, "Valkyrie", "Valkyrie", "ama"], + [33, "Pierce", "Pierce", "ama"], + [34, "Lightning Strike", "Lightning Strike", "ama"], + [35, "Lightning Fury", "Lightning Fury", "ama"], + [36, "Fire Bolt", "Fire Bolt", "sor"], + [37, "Warmth", "Warmth", "sor"], + [38, "Charged Bolt", "Charged Bolt", "sor"], + [39, "Ice Bolt", "Ice Bolt", "sor"], + [40, "Frozen Armor", "Frozen Armor", "sor"], + [41, "Inferno", "Inferno", "sor"], + [42, "Static Field", "Static Field", "sor"], + [43, "Telekinesis", "Telekinesis", "sor"], + [44, "Frost Nova", "Frost Nova", "sor"], + [45, "Ice Blast", "Ice Blast", "sor"], + [46, "Blaze", "Blaze", "sor"], + [47, "Fire Ball", "Fire Ball", "sor"], + [48, "Nova", "Nova", "sor"], + [49, "Lightning", "Lightning", "sor"], + [50, "Shiver Armor", "Shiver Armor", "sor"], + [51, "Fire Wall", "Fire Wall", "sor"], + [52, "Enchant", "Enchant", "sor"], + [53, "Chain Lightning", "Chain Lightning", "sor"], + [54, "Teleport", "Teleport", "sor"], + [55, "Glacial Spike", "Glacial Spike", "sor"], + [56, "Meteor", "Meteor", "sor"], + [57, "Thunder Storm", "Thunder Storm", "sor"], + [58, "Energy Shield", "Energy Shield", "sor"], + [59, "Blizzard", "Blizzard", "sor"], + [60, "Chilling Armor", "Chilling Armor", "sor"], + [61, "Fire Mastery", "Fire Mastery", "sor"], + [62, "Hydra", "Hydra", "sor"], + [63, "Lightning Mastery", "Lightning Mastery", "sor"], + [64, "Frozen Orb", "Frozen Orb", "sor"], + [65, "Cold Mastery", "Cold Mastery", "sor"], + [66, "Amplify Damage", "Amplify Damage", "nec"], + [67, "Teeth", "Teeth", "nec"], + [68, "Bone Armor", "Bone Armor", "nec"], + [69, "Skeleton Mastery", "Skeleton Mastery", "nec"], + [70, "Raise Skeleton", "Raise Skeleton", "nec"], + [71, "Dim Vision", "Dim Vision", "nec"], + [72, "Weaken", "Weaken", "nec"], + [73, "Poison Dagger", "Poison Dagger", "nec"], + [74, "Corpse Explosion", "Corpse Explosion", "nec"], + [75, "Clay Golem", "Clay Golem", "nec"], + [76, "Iron Maiden", "Iron Maiden", "nec"], + [77, "Terror", "Terror", "nec"], + [78, "Bone Wall", "Bone Wall", "nec"], + [79, "Golem Mastery", "Golem Mastery", "nec"], + [80, "Raise Skeletal Mage", "Raise Skeletal Mage", "nec"], + [81, "Confuse", "Confuse", "nec"], + [82, "Life Tap", "Life Tap", "nec"], + [83, "Poison Explosion", "Poison Explosion", "nec"], + [84, "Bone Spear", "Bone Spear", "nec"], + [85, "BloodGolem", "Blood Golem", "nec"], + [86, "Attract", "Attract", "nec"], + [87, "Decrepify", "Decrepify", "nec"], + [88, "Bone Prison", "Bone Prison", "nec"], + [89, "Summon Resist", "Summon Resist", "nec"], + [90, "IronGolem", "Iron Golem", "nec"], + [91, "Lower Resist", "Lower Resist", "nec"], + [92, "Poison Nova", "Poison Nova", "nec"], + [93, "Bone Spirit", "Bone Spirit", "nec"], + [94, "FireGolem", "Fire Golem", "nec"], + [95, "Revive", "Revive", "nec"], + [96, "Sacrifice", "Sacrifice", "pal"], + [97, "Smite", "Smite", "pal"], + [98, "Might", "Might", "pal"], + [99, "Prayer", "Prayer", "pal"], + [100, "Resist Fire", "Resist Fire", "pal"], + [101, "Holy Bolt", "Holy Bolt", "pal"], + [102, "Holy Fire", "Holy Fire", "pal"], + [103, "Thorns", "Thorns", "pal"], + [104, "Defiance", "Defiance", "pal"], + [105, "Resist Cold", "Resist Cold", "pal"], + [106, "Zeal", "Zeal", "pal"], + [107, "Charge", "Charge", "pal"], + [108, "Blessed Aim", "Blessed Aim", "pal"], + [109, "Cleansing", "Cleansing", "pal"], + [110, "Resist Lightning", "Resist Lightning", "pal"], + [111, "Vengeance", "Vengeance", "pal"], + [112, "Blessed Hammer", "Blessed Hammer", "pal"], + [113, "Concentration", "Concentration", "pal"], + [114, "Holy Freeze", "Holy Freeze", "pal"], + [115, "Vigor", "Vigor", "pal"], + [116, "Conversion", "Conversion", "pal"], + [117, "Holy Shield", "Holy Shield", "pal"], + [118, "Holy Shock", "Holy Shock", "pal"], + [119, "Sanctuary", "Sanctuary", "pal"], + [120, "Meditation", "Meditation", "pal"], + [121, "Fist of the Heavens", "Fist of the Heavens", "pal"], + [122, "Fanaticism", "Fanaticism", "pal"], + [123, "Conviction", "Conviction", "pal"], + [124, "Redemption", "Redemption", "pal"], + [125, "Salvation", "Salvation", "pal"], + [126, "Bash", "Bash", "bar"], + [127, "Sword Mastery", "Sword Mastery", "bar"], + [128, "Axe Mastery", "Axe Mastery", "bar"], + [129, "Mace Mastery", "Mace Mastery", "bar"], + [130, "Howl", "Howl", "bar"], + [131, "Find Potion", "Find Potion", "bar"], + [132, "Leap", "Leap", "bar"], + [133, "Double Swing", "Double Swing", "bar"], + [134, "Pole Arm Mastery", "Pole Arm Mastery", "bar"], + [135, "Throwing Mastery", "Throwing Mastery", "bar"], + [136, "Spear Mastery", "Spear Mastery", "bar"], + [137, "Taunt", "Taunt", "bar"], + [138, "Shout", "Shout", "bar"], + [139, "Stun", "Stun", "bar"], + [140, "Double Throw", "Double Throw", "bar"], + [141, "Increased Stamina", "Increased Stamina", "bar"], + [142, "Find Item", "Find Item", "bar"], + [143, "Leap Attack", "Leap Attack", "bar"], + [144, "Concentrate", "Concentrate", "bar"], + [145, "Iron Skin", "Iron Skin", "bar"], + [146, "Battle Cry", "Battle Cry", "bar"], + [147, "Frenzy", "Frenzy", "bar"], + [148, "Increased Speed", "Increased Speed", "bar"], + [149, "Battle Orders", "Battle Orders", "bar"], + [150, "Grim Ward", "Grim Ward", "bar"], + [151, "Whirlwind", "Whirlwind", "bar"], + [152, "Berserk", "Berserk", "bar"], + [153, "Natural Resistance", "Natural Resistance", "bar"], + [154, "War Cry", "War Cry", "bar"], + [155, "Battle Command", "Battle Command", "bar"], + [197, "DiabWall", "Firestorm", ""], + [217, "Scroll of Identify", "Scroll of Identify", ""], + [218, "Book of Identify", "Tome of Identify", ""], + [219, "Scroll of Townportal", "Scroll of Townportal", ""], + [220, "Book of Townportal", "Tome of Townportal", ""], + [221, "Raven", "Raven", "dru"], + [222, "Plague Poppy", "Poison Creeper", "dru"], + [223, "Wearwolf", "Werewolf", "dru"], + [224, "Shape Shifting", "Lycanthropy", "dru"], + [225, "Firestorm", "Firestorm", "dru"], + [226, "Oak Sage", "Oak Sage", "dru"], + [227, "Summon Spirit Wolf", "Summon Spirit Wolf", "dru"], + [228, "Wearbear", "Werebear", "dru"], + [229, "Molten Boulder", "Molten Boulder", "dru"], + [230, "Arctic Blast", "Arctic Blast", "dru"], + [231, "Cycle of Life", "Carrion Vine", "dru"], + [232, "Feral Rage", "Feral Rage", "dru"], + [233, "Maul", "Maul", "dru"], + [234, "Eruption", "Fissure", "dru"], + [235, "Cyclone Armor", "Cyclone Armor", "dru"], + [236, "Heart of Wolverine", "Heart of Wolverine", "dru"], + [237, "Summon Fenris", "Summon Dire Wolf", "dru"], + [238, "Rabies", "Rabies", "dru"], + [239, "Fire Claws", "Fire Claws", "dru"], + [240, "Twister", "Twister", "dru"], + [241, "Vines", "Solar Creeper", "dru"], + [242, "Hunger", "Hunger", "dru"], + [243, "Shock Wave", "Shock Wave", "dru"], + [244, "Volcano", "Volcano", "dru"], + [245, "Tornado", "Tornado", "dru"], + [246, "Spirit of Barbs", "Spirit of Barbs", "dru"], + [247, "Summon Grizzly", "Summon Grizzly", "dru"], + [248, "Fury", "Fury", "dru"], + [249, "Armageddon", "Armageddon", "dru"], + [250, "Hurricane", "Hurricane", "dru"], + [251, "Fire Trauma", "Fire Blast", "ass"], + [252, "Claw Mastery", "Claw Mastery", "ass"], + [253, "Psychic Hammer", "Psychic Hammer", "ass"], + [254, "Tiger Strike", "Tiger Strike", "ass"], + [255, "Dragon Talon", "Dragon Talon", "ass"], + [256, "Shock Field", "Shock Web", "ass"], + [257, "Blade Sentinel", "Blade Sentinel", "ass"], + [258, "Quickness", "Burst of Speed", "ass"], + [259, "Fists of Fire", "Fists of Fire", "ass"], + [260, "Dragon Claw", "Dragon Claw", "ass"], + [261, "Charged Bolt Sentry", "Charged Bolt Sentry", "ass"], + [262, "Wake of Fire Sentry", "Wake of Fire", "ass"], + [263, "Weapon Block", "Weapon Block", "ass"], + [264, "Cloak of Shadows", "Cloak of Shadows", "ass"], + [265, "Cobra Strike", "Cobra Strike", "ass"], + [266, "Blade Fury", "Blade Fury", "ass"], + [267, "Fade", "Fade", "ass"], + [268, "Shadow Warrior", "Shadow Warrior", "ass"], + [269, "Claws of Thunder", "Claws of Thunder", "ass"], + [270, "Dragon Tail", "Dragon Tail", "ass"], + [271, "Lightning Sentry", "Lightning Sentry", "ass"], + [272, "Inferno Sentry", "Wake of Inferno", "ass"], + [273, "Mind Blast", "Mind Blast", "ass"], + [274, "Blades of Ice", "Blades of Ice", "ass"], + [275, "Dragon Flight", "Dragon Flight", "ass"], + [276, "Death Sentry", "Death Sentry", "ass"], + [277, "Blade Shield", "Blade Shield", "ass"], + [278, "Venom", "Venom", "ass"], + [279, "Shadow Master", "Shadow Master", "ass"], + [280, "Royal Strike", "Phoenix Strike", "ass"], + [350, "Delerium Change", "Delirium", ""], +] + +const CLASS_ONLY_LABELS: Record = { + ama: '(Amazon Only)', + sor: '(Sorceress Only)', + nec: '(Necromancer Only)', + pal: '(Paladin Only)', + bar: '(Barbarian Only)', + dru: '(Druid Only)', + ass: '(Assassin Only)', +} + +const SKILL_LOOKUP_BY_ID = new Map() +const SKILL_LOOKUP_BY_NAME = new Map() + +for (const [id, rawName, displayName, cls] of CANONICAL_SKILLS) { + const classOnly = cls ? CLASS_ONLY_LABELS[cls] : undefined + const info = classOnly ? { name: displayName, classOnly } : { name: displayName } + SKILL_LOOKUP_BY_ID.set(id, info) + SKILL_LOOKUP_BY_NAME.set(rawName.toLowerCase(), info) + SKILL_LOOKUP_BY_NAME.set(displayName.toLowerCase(), info) +} + +/** + * Resolves a skill parameter (numeric ID or internal name from Skills.txt) + * into its 1.13c canonical English display name and optional class restriction. + */ +export function resolveSkillInfo(par: string | number | undefined): { name: string; classOnly?: string } { + if (par === undefined || par === '') return { name: 'Skill' } + const str = String(par).trim() + const num = Number(str) + if (!Number.isNaN(num) && SKILL_LOOKUP_BY_ID.has(num)) { + return SKILL_LOOKUP_BY_ID.get(num)! + } + const byName = SKILL_LOOKUP_BY_NAME.get(str.toLowerCase()) + if (byName) return byName + return { name: str } +} + +/** + * Canonical 1.13c skilltab mapping (par 0..20 from CharStats.txt StrSkillTab1..3 + StrClassOnly). + */ +export const CANONICAL_SKILL_TABS: Record = { + 0: 'Bow and Crossbow Skills (Amazon Only)', + 1: 'Passive and Magic Skills (Amazon Only)', + 2: 'Javelin and Spear Skills (Amazon Only)', + 3: 'Fire Skills (Sorceress Only)', + 4: 'Lightning Skills (Sorceress Only)', + 5: 'Cold Skills (Sorceress Only)', + 6: 'Curses (Necromancer Only)', + 7: 'Poison and Bone Skills (Necromancer Only)', + 8: 'Summoning Skills (Necromancer Only)', + 9: 'Combat Skills (Paladin Only)', + 10: 'Offensive Auras (Paladin Only)', + 11: 'Defensive Auras (Paladin Only)', + 12: 'Combat Skills (Barbarian Only)', + 13: 'Masteries (Barbarian Only)', + 14: 'Warcries (Barbarian Only)', + 15: 'Summoning Skills (Druid Only)', + 16: 'Shape Shifting Skills (Druid Only)', + 17: 'Elemental Skills (Druid Only)', + 18: 'Traps (Assassin Only)', + 19: 'Shadow Disciplines (Assassin Only)', + 20: 'Martial Arts (Assassin Only)', +} + +/** + * Canonical 1.13c MonStats.txt hcIdx -> NameStr for reanimate property. + */ +export const CANONICAL_REANIMATE_MONSTERS: Record = { + 0: 'Skeleton', + 1: 'Returned', + 2: 'Bone Warrior', + 3: 'Burning Dead', + 4: 'Horror', + 5: 'Zombie', +} + diff --git a/src/game/tooltip-i18n.ts b/src/game/tooltip-i18n.ts index 1d1181b..cc747c1 100644 --- a/src/game/tooltip-i18n.ts +++ b/src/game/tooltip-i18n.ts @@ -7,6 +7,8 @@ * - 'bilingual': Bilingual title (English + Chinese) with Chinese property lines */ +import { resolveSkillInfo } from './skills-data.ts' + export type TooltipLocale = 'en' | 'zh' | 'bilingual' let currentTooltipLocale: TooltipLocale = 'en' @@ -64,7 +66,7 @@ export const ITEM_NAMES_ZH: Record = { "Leather Boots": "皮靴", "Heavy Boots": "重靴", "Chain Boots": "锁链靴", - "Light Plated Boots": "轻型金屬靴", + "Light Plated Boots": "轻型金属靴", "Light Plate Boots": "轻型金属靴", "Greaves": "护胫", "Plate Boots": "护胫", @@ -75,7 +77,7 @@ export const ITEM_NAMES_ZH: Record = { "Belt(M)": "扣带", "Heavy Belt": "重扣带", "Plated Belt": "金属扣带", - "Girdle(H)": "金屬扣带", + "Girdle(H)": "金属扣带", "Bone Helm": "白骨头盔", "Bone Shield": "白骨盾牌", "Spiked Shield": "尖刺盾牌", @@ -196,7 +198,7 @@ export const ITEM_NAMES_ZH: Record = { "War Scythe": "巨战镰刀", "Short Staff": "短棍", "Long Staff": "长棍", - "Gnarled Staff": "多節棍", + "Gnarled Staff": "多节棍", "Battle Staff": "战斗法杖", "War Staff": "巨战法杖", "Short Bow": "短弓", @@ -245,7 +247,7 @@ export const ITEM_NAMES_ZH: Record = { "Cudgel": "棍棒", "Rune Scepter": "符文权杖", "Holy Water Sprinkler": "圣水喷杖", - "Divine Scepter": "神屬权杖", + "Divine Scepter": "神圣权杖", "Barbed Club": "倒钩锤", "Flanged Mace": "凸缘钉头锤", "Jagged Star": "锯齿流星锤", @@ -328,7 +330,7 @@ export const ITEM_NAMES_ZH: Record = { "Thawing Potion": "融解药剂", "Tome of Town Portal": "城镇传送之书", "Town Portal Book": "城镇传送之书", - "Tome of Identify": "辨视之书", + "Tome of Identify": "辨识之书", "Identify Book": "辨视之书", "Amulet": "项链", "amulet": "项链", @@ -347,7 +349,7 @@ export const ITEM_NAMES_ZH: Record = { "Bolts": "十字弓弹", "Scroll of Town Portal": "城镇传送卷轴", "Town Portal Scroll": "城镇传送卷轴", - "Scroll of Identify": "辨视卷轴", + "Scroll of Identify": "辨识卷轴", "Identify Scroll": "辨视卷轴", "Heart": "一股邪恶力量", "Not used": "一股邪恶力量", @@ -392,12 +394,12 @@ export const ITEM_NAMES_ZH: Record = { "Chipped Amethyst": "碎裂的紫宝石", "Flawed Amethyst": "裂开的紫宝石", "Amethyst": "紫宝石", - "Flawless Amethyst": "無暇疵的紫宝石", + "Flawless Amethyst": "无瑕疵的紫宝石", "Perfect Amethyst": "完美的紫宝石", "Chipped Topaz": "碎裂的黄宝石", "Flawed Topaz": "裂开的黄宝石", "Topaz": "黄宝石", - "Flawless Topaz": "無暇疵的黄宝石", + "Flawless Topaz": "无瑕疵的黄宝石", "Perfect Topaz": "完美的黄宝石", "Chipped Sapphire": "碎裂的蓝宝石", "Chipped Saphire": "碎裂的蓝宝石", @@ -405,24 +407,24 @@ export const ITEM_NAMES_ZH: Record = { "Flawed Saphire": "裂开的蓝宝石", "Sapphire": "蓝宝石", "Saphire": "蓝宝石", - "Flawless Sapphire": "無暇疵的蓝宝石", - "Flawless Saphire": "無暇疵的蓝宝石", + "Flawless Sapphire": "无瑕疵的蓝宝石", + "Flawless Saphire": "无瑕疵的蓝宝石", "Perfect Sapphire": "完美的蓝宝石", "Perfect Saphire": "完美的蓝宝石", - "Chipped Emerald": "碎裂的綠宝石", - "Flawed Emerald": "裂开的綠宝石", - "Emerald": "綠宝石", - "Flawless Emerald": "無暇疵的綠宝石", - "Perfect Emerald": "完美的綠宝石", - "Chipped Ruby": "碎裂的紅宝石", - "Flawed Ruby": "裂开的紅宝石", - "Ruby": "紅宝石", - "Flawless Ruby": "無暇疵的紅宝石", - "Perfect Ruby": "完美的紅宝石", + "Chipped Emerald": "碎裂的绿宝石", + "Flawed Emerald": "裂开的绿宝石", + "Emerald": "绿宝石", + "Flawless Emerald": "无瑕疵的绿宝石", + "Perfect Emerald": "完美的绿宝石", + "Chipped Ruby": "碎裂的红宝石", + "Flawed Ruby": "裂开的红宝石", + "Ruby": "红宝石", + "Flawless Ruby": "无瑕疵的红宝石", + "Perfect Ruby": "完美的红宝石", "Chipped Diamond": "碎裂的钻石", "Flawed Diamond": "裂开的钻石", "Diamond": "钻石", - "Flawless Diamond": "無暇疵的钻石", + "Flawless Diamond": "无瑕疵的钻石", "Perfect Diamond": "完美的钻石", "Minor Healing Potion": "轻微治疗药剂", "Lesser Healing Potion": "轻微治疗药剂", @@ -441,7 +443,7 @@ export const ITEM_NAMES_ZH: Record = { "Chipped Skull": "碎裂的骷髅", "Flawed Skull": "裂开的骷髅", "Skull": "骷髅", - "Flawless Skull": "無暇疵的骷髅", + "Flawless Skull": "无瑕疵的骷髅", "Perfect Skull": "完美的骷髅", "Herb": "药草", "herb": "药草", @@ -478,8 +480,8 @@ export const ITEM_NAMES_ZH: Record = { "The Chieftan": "族长", "The Chieftain": "族长", "Brainhew": "脑袋", - "The Humongous": "巨大無比", - "Humongous": "巨大無比", + "The Humongous": "巨大无比", + "Humongous": "巨大无比", "Iros Torch": "衣洛的火炬", "Torch of Iro": "衣洛的火炬", "Maelstromwrath": "漩涡", @@ -502,7 +504,7 @@ export const ITEM_NAMES_ZH: Record = { "Steeldriver": "铁制大锤", "Rixots Keen": "瑞克撒特的挽歌", "Rixot's Keen": "瑞克撒特的挽歌", - "Blood Crescent": "血紅新月", + "Blood Crescent": "血红新月", "Krintizs Skewer": "格林提斯的肉叉", "Skewer of Krintiz": "格林提斯的肉叉", "Gleamscythe": "闪耀的镰刀", @@ -588,9 +590,9 @@ export const ITEM_NAMES_ZH: Record = { "Pelta Lunata": "新月小盾", "Umbral Disk": "阴影圆盘", "Stormguild": "暴风公会", - "Wall of the Eyeless": "無眼之墙", + "Wall of the Eyeless": "无眼之墙", "Swordback Hold": "剑背之架", - "Steelclash": "作响的金屬", + "Steelclash": "作响的金属", "Bverrit Keep": "贝弗提的纪念", "The Ward": "囚房", "The Hand of Broc": "柏克之手", @@ -655,7 +657,7 @@ export const ITEM_NAMES_ZH: Record = { "Tancred's Crowbill": "坦克雷的鸦嘴钳", "Tancred's Spine": "坦克雷的脊柱", "Tancred's Hobnails": "坦克雷的平头钉", - "Tancred's Weird": "坦克雷的怪誕", + "Tancred's Weird": "坦克雷的怪诞", "Tancred's Skull": "坦克雷之骷髅", "Sigon's Gage": "西刚的挑战", "Sigon's Visor": "西刚之面甲", @@ -1372,285 +1374,889 @@ export const ITEM_NAMES_ZH: Record = { } /** - * Magic Prefixes (MPQ + LoD Expansion). + * Magic Prefixes (100% 1.13c MPQ Complete, 252 entries). */ export const MAGIC_PREFIX_ZH: Record = { - "Sturdy": "结实之", - "Strong": "强壮之", - "Glorious": "光荣之", - "Blessed": "祝福之", - "Saintly": "崇高之", - "Holy": "神圣之", - "Devious": "迂回之", - "Fortified": "防御强化之", - "Jagged": "锯齿之", - "Deadly": "致命之", - "Vicious": "恶毒之", - "Brutal": "残忍之", - "Massive": "稳重之", - "Savage": "野蛮之", - "Merciless": "绝情之", - "Vulpine": "奸诈之", - "Tireless": "不倦之", - "Rugged": "凹凸之", - "Bronze": "青铜之", - "Iron": "铁之", - "Steel": "钢之", - "Silver": "银之", - "Gold": "金之", - "Platinum": "白金之", - "Meteoric": "陨铁之", - "Sharp": "尖锐之", - "Fine": "精良之", - "Warrior's": "战士之", - "Soldier's": "士兵之", - "Knight's": "骑士之", - "Lord's": "领主之", - "King's": "国王之", - "Howling": "咆哮之", - "Fortuitous": "偶然之", - "Glimmering": "微光之", - "Glowing": "发光之", - "Lizard's": "蜥蜴之", - "Snake's": "蛇之", - "Serpent's": "海蛇之", - "Drake's": "德尔克之", - "Dragon's": "龙之", - "Wyrm's": "维特之", - "Prismatic": "彩虹之", - "Azure": "天青之", - "Lapis": "青金石之", - "Cobalt": "钴蓝之", - "Sapphire": "蓝宝石之", - "Crimson": "枣紅之", - "Burgundy": "紅棕之", - "Garnet": "石榴石之", - "Ruby": "红宝石之", - "Ocher": "赭黄之", - "Tangerine": "橙黄之", - "Coral": "珊瑚之", + "Accursed": "诅咒之", + "Acrobat's": "杂技之", "Amber": "琥珀之", - "Beryl": "绿柱石之", - "Jade": "翡翠之", - "Viridian": "铭綠之", - "Emerald": "绿宝石之", - "Fletcher's": "制箭者之", - "Archer's": "弓箭手之", - "Monk's": "僧人之", - "Priest's": "祭司之", - "Summoner's": "召唤者之", - "Necromancer's": "死灵法师之", - "Angel's": "天使之", - "Arch-Angel's": "大天使之", - "Slayer's": "屠杀者之", - "Berserker's": "狂战士之", - "Triumphant": "得胜之", - "Bone": "白骨之", - "Blank": "虚無之", - "Red": "紅之", - "Forked": "分叉之", - "Vermillion": "朱砂之", - "Cruel": "残忍之", - "Weird": "怪异", - "Bright": "光明之", - "Russet": "铁锈之", - "Shadow": "阴影之", - "Paleocene": "忠誠信使", - "Shouting": "咆哮之", - "Envenomed": "腐爛之", - "Maiden's": "处女之", - "Valkyrie's": "女武神之", - "Stout": "坚固之", - "Burly": "魁梧之", - "Stalwart": "健壮之", - "Blanched": "漂白之", - "Eburin": "象牙之", - "Ivory": "象牙之", - "Godly": "神圣之", - "Null": "无效之", - "Antimagic": "防魔之", - "Sanguinary": "鲜血之", - "Bloody": "血腥之", - "Scarlet": "猩红之", - "Serrated": "锯齿之", - "Carbuncle": "痈肿之", - "Carmine": "洋红之", - "Ferocious": "凶猛之", - "Cinnabar": "朱砂之", - "Rusty": "生锈之", - "Realgar": "雄黄之", - "Dun": "黑褐之", - "Topaz": "黄宝石之", - "Diamond": "钻石之", + "Ambergris": "龙涎香之", "Amethyst": "紫水晶之", - "Rainbow": "彩虹之", - "Chromatic": "炫彩之", - "Scintillating": "闪烁之", - "Shimmering": "微光之", - "Turquoise": "绿松石之", - "Grandmaster's": "宗师之", - "Master's": "大师之", - "Captain's": "领袖之", - "Veteran's": "老兵之", - "Fool's": "愚人之", - "Bishop's": "主教之", - "Patriarch's": "先知之", - "Hierophant's": "教皇之", - "Shaman's": "萨满之", - "Magekiller's": "法师杀手之", - "Victorious": "胜利之", - "Acrobatic": "杂技之", - "Gymnastic": "体操之", + "Angel's": "天使之", + "Antimagic": "防魔之", + "Arcadian": "阿卡迪亚之", + "Arch-Angel's": "大天使之", + "Archer's": "弓箭手之", + "Arcing": "电弧之", + "Argent": "白银之", + "Artificer's": "工匠之", + "Assamic": "阿萨姆之", + "Astral": "星界之", "Athlete": "运动之", - "Entrapping": "陷阱之", - "Mentalist": "通灵之", - "Sparking": "火花之", - "Static": "静电之", - "Glacial": "极冰之", - "Volcanic": "火山之", - "Golemlord": "魔像领主之", - "Necromancer": "死灵法师之", - "Preserver": "保护者之", - "Warden": "看守者之", - "Marshal": "元帅之", - "Sounding": "鸣响之", - "Resonant": "共鸣之", - "Echoing": "回音之", - "Trainer's": "驯兽师之", + "Athlete's": "运动之", + "Aureolin": "钴黄之", + "Azure": "天青之", + "Bahamut's": "巴哈姆特之", + "Beryl": "绿柱石之", + "Berserker's": "狂战士之", + "Bishop's": "主教之", + "Blanched": "漂白之", + "Blank": "虚无之", + "Blazing": "炽热之", + "Blessed": "祝福之", + "Blighting": "枯萎之", + "Bloody": "血腥之", + "Bone": "白骨之", + "Boreal": "极北之", + "Bowyer's": "弓箭手之", + "Bright": "光明之", + "Bronze": "青铜之", + "Brown": "棕褐之", + "Brutal": "残忍之", + "Burgundy": "红棕之", + "Burly": "魁梧之", + "Burning": "燃烧之", + "Buzzing": "嗡鸣之", + "Calling": "呼唤之", + "Camphor": "樟脑之", + "Captain's": "领袖之", + "Carbuncle": "痈肿之", "Caretaker's": "看顾者之", - "Keeper's": "守护者之", - "Nature": "自然之", - "Gaia": "大地之", + "Carmine": "洋红之", + "Celestial": "天界之", + "Charged": "充能之", + "Chestnut": "栗色之", + "Chilling": "严寒之", + "Chromatic": "炫彩之", + "Cinnabar": "朱砂之", + "Cobalt": "钴蓝之", + "Commander's": "指挥官之", + "Communal": "公社之", + "Compact": "紧密之", + "Consecrated": "奉献之", + "Coral": "珊瑚之", + "Corosive": "腐蚀之", + "Crimson": "枣红之", + "Cruel": "残忍之", + "Cunning": "狡黠之", + "Deadly": "致命之", + "Dense": "致密之", + "Devious": "迂回之", + "Diamond": "钻石之", + "Divine": "神圣之", + "Dragon's": "龙之", + "Drake's": "德尔克之", + "Dun": "黑褐之", + "Eagleeye": "雕眼之", "Earth": "大地之", + "Eburin": "象牙之", + "Echoing": "回音之", + "Elysian": "极乐之", + "Ember": "余烬之", + "Emerald": "绿宝石之", + "Entrapping": "陷阱之", + "Envenomed": "腐烂之", + "Eocene": "始新世之", + "Expert's": "专家之", + "Falconeye": "猎鹰之眼", + "Fanatic": "狂热之", + "Felicitous": "吉庆之", "Feral": "野性之", - "Communal": "公社之" + "Ferocious": "凶猛之", + "Fine": "精良之", + "Flaming": "烈焰之", + "Fletcher's": "制箭者之", + "Fool's": "愚人之", + "Forked": "分叉之", + "Fortified": "防御强化之", + "Fortuitous": "偶然之", + "Freezing": "冰冻之", + "Fungal": "真菌之", + "Furious": "狂怒之", + "Gaea's": "大地之", + "Gaia": "大地之", + "Garnet": "石榴石之", + "Glacial": "极冰之", + "Glimmering": "微光之", + "Glorious": "光荣之", + "Glowing": "发光之", + "Godly": "神圣之", + "Gold": "金之", + "Golemlord": "魔像领主之", + "Golemlord's": "魔像领主之", + "Grandmaster's": "宗师之", + "Graverobber's": "盗墓者之", + "Great Wyrm's": "大巨龙之", + "Gritty": "坚韧之", + "Guardian's": "护卫者之", + "Gymnastic": "体操之", + "Gymnast's": "体操之", + "Hallowed": "神圣之", + "Harpoonist's": "标枪之", + "Hawk Branded": "鹰之烙印之", + "Hawkeye": "鹰眼之", + "Hexing": "诅咒之", + "Hibernal": "极寒之", + "Hierophant's": "教皇之", + "Holy": "神圣之", + "Howling": "咆哮之", + "Iron": "铁之", + "Ivory": "象牙之", + "Jacinth": "风信子石之", + "Jack's": "随从之", + "Jade": "翡翠之", + "Jagged": "锯齿之", + "Jester's": "弄臣之", + "Jeweler's": "珠宝匠之", + "Joker's": "小丑之", + "Kenshi's": "剑士之", + "Keeper's": "守护者之", + "King's": "国王之", + "Knave's": "盗贼之", + "Knight's": "骑士之", + "Lancer's": "长矛手之", + "Lapis": "青金石之", + "Lapis Lazuli": "青金石之", + "Lion Branded": "狮子烙印之", + "Lizard's": "蜥蜴之", + "Lord's": "领主之", + "Loud": "响亮之", + "Lucky": "幸运之", + "Magekiller's": "法师杀手之", + "Maiden's": "处女之", + "Maroon": "褐红之", + "Marshal": "元帅之", + "Marshal's": "元帅之", + "Massive": "稳重之", + "Master's": "大师之", + "Mechanist's": "机械师之", + "Mentalist": "通灵之", + "Mentalist's": "通灵之", + "Merciless": "绝情之", + "Meteoric": "陨铁之", + "Miocene": "中新世之", + "Mnemonic": "记忆之", + "Monk's": "僧人之", + "Nature": "自然之", + "Nature's": "自然之", + "Necromancer": "死灵法师之", + "Necromancer's": "死灵法师之", + "Nickel": "白镍之", + "Noxious": "有害之", + "Null": "无效之", + "Ocher": "赭黄之", + "Oligocene": "渐新世之", + "Paleocene": "忠诚信使之", + "Paradox": "悖论之", + "Patriarch's": "先知之", + "Pearl": "珍珠之", + "Pestilent": "瘟疫之", + "Platinum": "白金之", + "Powered": "能量之", + "Preserver": "保护者之", + "Preserver's": "保护者之", + "Priest's": "祭司之", + "Prismatic": "彩虹之", + "Psychic": "心灵之", + "Pure": "纯净之", + "Raging": "暴怒之", + "Rainbow": "彩虹之", + "Realgar": "雄黄之", + "Red": "红之", + "Resonant": "共鸣之", + "Robineye": "知更鸟眼之", + "Rose Branded": "玫瑰烙印之", + "Ruby": "红宝石之", + "Rugged": "凹凸之", + "Russet": "铁锈之", + "Rusty": "生锈之", + "Sacred": "圣洁之", + "Saintly": "崇高之", + "Sanguinary": "鲜血之", + "Sapphire": "蓝宝石之", + "Savage": "野蛮之", + "Scarlet": "猩红之", + "Scintillating": "闪烁之", + "Scorching": "灼烧之", + "Screaming": "尖叫之", + "Sensei's": "老师之", + "Septic": "腐臭之", + "Serpent's": "海蛇之", + "Serrated": "锯齿之", + "Shadow": "阴影之", + "Shaman's": "萨满之", + "Sharp": "尖锐之", + "Shimmering": "微光之", + "Shivering": "寒颤之", + "Shocking": "雷霆之", + "Shogukusha's": "刺客之", + "Shouting": "咆哮之", + "Silver": "银之", + "Slayer's": "屠杀者之", + "Smoldering": "焖燃之", + "Smoking": "烟雾之", + "Snake's": "蛇之", + "Snowflake": "雪花之", + "Soldier's": "士兵之", + "Sounding": "鸣响之", + "Sparking": "火花之", + "Sparroweye": "麻雀眼之", + "Spearmaiden's": "标枪女郎之", + "Spiritual": "精神之", + "Stalwart": "健壮之", + "Static": "静电之", + "Steel": "钢之", + "Stout": "坚固之", + "Strange": "怪异之", + "Strong": "强壮之", + "Sturdy": "结实之", + "Summoner's": "召唤者之", + "Tangerine": "橙黄之", + "Terra's": "大地之", + "Thin": "轻薄之", + "Tin": "白铁之", + "Tireless": "不倦之", + "Topaz": "黄宝石之", + "Toxic": "剧毒之", + "Trainer's": "驯兽师之", + "Trickster's": "戏法师之", + "Triumphant": "得胜之", + "Trump": "胜者之", + "Turquoise": "绿松石之", + "Unearthly": "超凡之", + "Valkyrie's": "女武神之", + "Venomous": "剧毒之", + "Vermillion": "朱砂之", + "Veteran's": "老兵之", + "Vicious": "恶毒之", + "Victorious": "胜利之", + "Vigorous": "强健之", + "Viridian": "铭绿之", + "Visionary": "梦幻之", + "Vodoun": "伏都之", + "Volcanic": "火山之", + "Vulpine": "奸诈之", + "Wailing": "哀嚎之", + "Warden": "看守者之", + "Warder's": "监视者之", + "Warrior's": "战士之", + "Weird": "怪异之", + "Witch-hunter's": "猎巫者之", + "Wyrm's": "维特之", + "Yelling": "呐喊之", + "Zircon": "锆石之" } /** - * Magic Suffixes (MPQ + LoD Expansion). + * Magic Suffixes (100% 1.13c MPQ Complete, 288 entries). */ export const MAGIC_SUFFIX_ZH: Record = { - "of Health": "健康之", - "of Protection": "守护之", "of Absorption": "吸收之", - "of Life": "生命之", - "of Warding": "防避的", - "of the Sentinel": "步哨的", - "of Guarding": "守卫的", - "of Negation": "否定的", - "of Piercing": "刺穿的", - "of Bashing": "重击的", - "of Puncturing": "爆破的", - "of Thorns": "荆棘之", - "of Spikes": "尖刺之", - "of Readiness": "准备之", - "of Alacrity": "迅捷之", - "of Swiftness": "疾速之", - "of Quickness": "快速之", - "of Blocking": "格挡的", - "of Deflecting": "偏向的", - "of the Apprentice": "学徒之", - "of the Magus": "贤者之", - "of Frost": "霜的", - "of the Glacier": "冰川之", - "of Warmth": "融解的", - "of Flame": "火焰的", - "of Fire": "火的", - "of Burning": "燃烧的", - "of Shock": "冲击的", - "of Lightning": "闪电的", - "of Thunder": "雷电的", - "of Craftsmanship": "工匠的", - "of Quality": "品质的", - "of Maiming": "残废的", - "of Slaying": "屠杀的", - "of Gore": "凝血的", - "of Carnage": "屠杀的", - "of Slaughter": "残杀的", - "of Worth": "价值的", - "of Measure": "测量的", - "of Excellence": "精灵的", - "of Performance": "表现的", - "of Blight": "光明的", - "of Venom": "毒素的", - "of Pestilence": "瘟疫的", - "of Dexterity": "敏捷之", - "of Skill": "技巧之", - "of Accuracy": "准确之", - "of Precision": "精密之", - "of Perfection": "完美之", - "of Balance": "平衡之", - "of Stability": "安定之", - "of Regeneration": "再生之", - "of Regrowth": "新生之", - "of Vileness": "下流的", - "of Greed": "贪婪之", - "of Wealth": "财富之", - "of Chance": "运气之", - "of Fortune": "财富之", - "of Energy": "精力之", - "of the Mind": "心灵之", - "of Brilliance": "光辉之", - "of Sorcery": "巫术之", - "of Wizardry": "法师之", - "of the Bear": "熊的", - "of Light": "光明的", - "of Radiance": "光彩的", - "of the Sun": "太阳之", - "of the Jackal": "豺狼之", - "of the Fox": "狡狐之", - "of the Wolf": "恶狼之", - "of the Tiger": "猛虎之", - "of the Mammoth": "猛犸之", - "of the Colosuss": "太阳神的", - "of the Leech": "水蛭之", - "of the Locust": "蝗虫之", - "of the Bat": "蝙蝠之", - "of the Vampire": "吸血鬼之", - "of Defiance": "蔑视之", - "of Amelioration": "演进的", - "of Remedy": "医治的", - "of Simplicity": "朴素之", - "of Ease": "轻松之", - "of Strength": "力量之", - "of Might": "强权之", - "of the Ox": "公牛之", - "of the Giant": "巨人之", - "of the Titan": "泰坦之", - "of Pacing": "步伐的", - "of Haste": "憎恨的", - "of Speed": "极速之", - "of Equilibrium": "平衡之", - "of the Wraith": "死灵", - "of Life Everlasting": "长生之", - "of Anima": "灵魂之", - "of Coolness": "凉爽之", - "of Incombustibility": "不燃之", - "of Amianthus": "石棉之", - "of Fire Quenching": "灭火之", - "of Faith": "信念之", - "of Resistance": "抗性之", - "of Insulation": "绝缘之", - "of Grounding": "接地之", - "of the Dynamo": "发电机之", - "of Stoicism": "坚忍之", - "of Warming": "温暖之", - "of Thawing": "融化之", - "of the Dunes": "沙丘之", - "of the Sirocco": "热风之", - "of Desire": "欲望之", - "of Razors": "剃刀之", - "of Swords": "剑刃之", - "of Malice": "怨恨之", - "of the Whale": "巨鲸之", - "of the Squid": "乌贼之", - "of the Colossus": "巨人之", - "of Atlas": "阿特拉斯之", - "of Nirvana": "涅槃之", + "Absorption": "吸收之", "of Acceleration": "加速之", - "of Restoration": "恢复之", - "of Revivification": "复活之", - "of Immortality": "不朽之" + "Acceleration": "加速之", + "of Accuracy": "准确之", + "Accuracy": "准确之", + "of Ages": "万古之", + "Ages": "万古之", + "of Alacrity": "迅捷之", + "Alacrity": "迅捷之", + "of Amelioration": "改善之", + "Amelioration": "改善之", + "of Amianthus": "石棉之", + "Amianthus": "石棉之", + "of Amplify Damage": "伤害加深之", + "Amplify Damage": "伤害加深之", + "of Anima": "生灵之", + "Anima": "生灵之", + "of Anthrax": "炭疽之", + "Anthrax": "炭疽之", + "of Armageddon": "末日风暴之", + "Armageddon": "末日风暴之", + "of Atlus": "阿特拉斯之", + "Atlus": "阿特拉斯之", + "of Attraction": "吸引之", + "Attraction": "吸引之", + "of Avarice": "贪婪之", + "Avarice": "贪婪之", + "of Balance": "平衡之", + "Balance": "平衡之", + "of Bashing": "重击之", + "Bashing": "重击之", + "of Battle Command": "战斗指挥之", + "Battle Command": "战斗指挥之", + "of Battle Cry": "刺耳尖叫之", + "Battle Cry": "刺耳尖叫之", + "of Battle Orders": "战斗体制之", + "Battle Orders": "战斗体制之", + "of Blaze": "炽烈之径之", + "Blaze": "炽烈之径之", + "of Blazing": "炽烈之径之", + "Blazing": "炽烈之径之", + "of Blessed Hammers": "祝福之槌之", + "Blessed Hammers": "祝福之槌之", + "of Blight": "枯萎之", + "Blight": "枯萎之", + "of Bliss": "至福之", + "Bliss": "至福之", + "of Blizzard": "暴风雪之", + "Blizzard": "暴风雪之", + "of Blizzards": "暴风雪之", + "Blizzards": "暴风雪之", + "of Blocking": "格挡之", + "Blocking": "格挡之", + "of Blood Golem Summoning": "鲜血魔像之", + "Blood Golem Summoning": "鲜血魔像之", + "of Bone Armor": "白骨装甲之", + "Bone Armor": "白骨装甲之", + "of Bone Imprisonment": "骨牢之", + "Bone Imprisonment": "骨牢之", + "of Bone Spears": "骨矛之", + "Bone Spears": "骨矛之", + "of Bone Spirits": "白骨之魂之", + "Bone Spirits": "白骨之魂之", + "of Bone Walls": "骨墙之", + "Bone Walls": "骨墙之", + "of Brilliance": "辉煌之", + "Brilliance": "辉煌之", + "of Burning": "燃烧之", + "Burning": "燃烧之", + "of Butchery": "屠戮之", + "Butchery": "屠戮之", + "of Carnage": "大屠杀之", + "Carnage": "大屠杀之", + "of Chain Lightning": "连锁闪电之", + "Chain Lightning": "连锁闪电之", + "of Chance": "几率之", + "Chance": "几率之", + "of Charged Bolts": "充能弹之", + "Charged Bolts": "充能弹之", + "of Charged Shield": "充能护盾之", + "Charged Shield": "充能护盾之", + "of Charged Strike": "充能一击之", + "Charged Strike": "充能一击之", + "of Chilling Armor": "寒冰甲之", + "Chilling Armor": "寒冰甲之", + "of Clay Golem Summoning": "黏土魔像之", + "Clay Golem Summoning": "黏土魔像之", + "of Cold Arrows": "冰箭之", + "Cold Arrows": "冰箭之", + "of Concentration": "专注之", + "Concentration": "专注之", + "of Confusion": "迷乱之", + "Confusion": "迷乱之", + "of Conversion": "转化之", + "Conversion": "转化之", + "of Coolness": "清凉之", + "Coolness": "清凉之", + "of Corpse Explosions": "尸体爆炸之", + "Corpse Explosions": "尸体爆炸之", + "of Craftsmanship": "工匠之", + "Craftsmanship": "工匠之", + "of Cyclone Armor": "飓风装甲之", + "Cyclone Armor": "飓风装甲之", + "of Damage Amplification": "伤害加深之", + "Damage Amplification": "伤害加深之", + "of Daring": "果敢之", + "Daring": "果敢之", + "of Dawn": "黎明之", + "Dawn": "黎明之", + "of Decrepification": "衰老之", + "Decrepification": "衰老之", + "of Defiance": "蔑视之", + "Defiance": "蔑视之", + "of Deflecting": "偏向之", + "Deflecting": "偏向之", + "of Desire": "渴望之", + "Desire": "渴望之", + "of Destruction": "毁灭之", + "Destruction": "毁灭之", + "of Dexterity": "敏捷之", + "Dexterity": "敏捷之", + "of Dim Vision": "微暗灵视之", + "Dim Vision": "微暗灵视之", + "of Ease": "轻便之", + "Ease": "轻便之", + "of Enchant": "强化之", + "Enchant": "强化之", + "of Enchantment": "强化之", + "Enchantment": "强化之", + "of Energy": "能量之", + "Energy": "能量之", + "of Energy Shield": "能量护盾之", + "Energy Shield": "能量护盾之", + "of Enlightenment": "启迪之", + "Enlightenment": "启迪之", + "of Ennui": "厌倦之", + "Ennui": "厌倦之", + "of Envy": "嫉妒之", + "Envy": "嫉妒之", + "of Equilibrium": "均势之", + "Equilibrium": "均势之", + "of Eruption": "火山喷发之", + "Eruption": "火山喷发之", + "of Evisceration": "剖腹之", + "Evisceration": "剖腹之", + "of Excellence": "卓越之", + "Excellence": "卓越之", + "of Exploding Arrows": "爆裂箭之", + "Exploding Arrows": "爆裂箭之", + "of Faith": "信仰之", + "Faith": "信仰之", + "of Fast Repair": "快速修复之", + "Fast Repair": "快速修复之", + "of Fending": "击退之", + "Fending": "击退之", + "of Fervor": "狂热之", + "Fervor": "狂热之", + "of Fire": "烈火之", + "Fire": "烈火之", + "of Fire Arrows": "火箭之", + "Fire Arrows": "火箭之", + "of Fire Ball": "火球之", + "Fire Ball": "火球之", + "of Fire Balls": "火球之", + "Fire Balls": "火球之", + "of Fire Bolts": "火弹之", + "Fire Bolts": "火弹之", + "of Fire Golem Summoning": "火焰魔像之", + "Fire Golem Summoning": "火焰魔像之", + "of Fire Quenching": "灭火之", + "Fire Quenching": "灭火之", + "of Fire Wall": "火墙之", + "Fire Wall": "火墙之", + "of Fire Walls": "火墙之", + "Fire Walls": "火墙之", + "of Firebolt": "火弹之", + "Firebolt": "火弹之", + "of Firebolts": "火弹之", + "Firebolts": "火弹之", + "of Firestorms": "火风暴之", + "Firestorms": "火风暴之", + "of Fist of the Heavens": "天堂之拳之", + "Fist of the Heavens": "天堂之拳之", + "of Flame": "火焰之", + "Flame": "火焰之", + "of Fortune": "财富之", + "Fortune": "财富之", + "of Freedom": "自由之", + "Freedom": "自由之", + "of Freezing Arrows": "急冻箭之", + "Freezing Arrows": "急冻箭之", + "of Frigidity": "寒冷之", + "Frigidity": "寒冷之", + "of Frost": "冰霜之", + "Frost": "冰霜之", + "of Frost Novas": "冰霜新星之", + "Frost Novas": "冰霜新星之", + "of Frost Shield": "冰霜护盾之", + "Frost Shield": "冰霜护盾之", + "of Frostbite": "冻疮之", + "Frostbite": "冻疮之", + "of Frozen Armor": "冰封甲之", + "Frozen Armor": "冰封甲之", + "of Frozen Orb": "冰封球之", + "Frozen Orb": "冰封球之", + "of Frozen Orbs": "冰封球之", + "Frozen Orbs": "冰封球之", + "of Fumigation": "熏蒸之", + "Fumigation": "熏蒸之", + "of Glacial Spike": "冰尖柱之", + "Glacial Spike": "冰尖柱之", + "of Glacial Spikes": "冰尖柱之", + "Glacial Spikes": "冰尖柱之", + "of Good Luck": "好运之", + "Good Luck": "好运之", + "of Gore": "鲜血之", + "Gore": "鲜血之", + "of Grace": "优雅之", + "Grace": "优雅之", + "of Grace and Power": "优雅与力量之", + "Grace and Power": "优雅与力量之", + "of Greed": "贪欲之", + "Greed": "贪欲之", + "of Grim Ward": "残骸清理之", + "Grim Ward": "残骸清理之", + "of Grounding": "接地之", + "Grounding": "接地之", + "of Guarding": "守卫之", + "Guarding": "守卫之", + "of Guided Arrows": "追踪箭之", + "Guided Arrows": "追踪箭之", + "of Haste": "急速之", + "Haste": "急速之", + "of Health": "健康之", + "Health": "健康之", + "of Health Everlasting": "永恒健康之", + "Health Everlasting": "永恒健康之", + "of Holy Bolts": "圣光弹之", + "Holy Bolts": "圣光弹之", + "of Honor": "荣耀之", + "Honor": "荣耀之", + "of Hope": "希望之", + "Hope": "希望之", + "of Howling": "狂嚎之", + "Howling": "狂嚎之", + "of Hurricane": "飓风之", + "Hurricane": "飓风之", + "of Hydra Shield": "九头蛇护盾之", + "Hydra Shield": "九头蛇护盾之", + "of Hydras": "九头海蛇之", + "Hydras": "九头海蛇之", + "of Ice Arrows": "冻结箭之", + "Ice Arrows": "冻结箭之", + "of Ice Blast": "冰风暴之", + "Ice Blast": "冰风暴之", + "of Ice Blasts": "冰风暴之", + "Ice Blasts": "冰风暴之", + "of Ice Bolts": "冰弹之", + "Ice Bolts": "冰弹之", + "of Icebolt": "冰弹之", + "Icebolt": "冰弹之", + "of Immolating Arrows": "牺牲之箭之", + "Immolating Arrows": "牺牲之箭之", + "of Impaling Strike": "刺爆之", + "Impaling Strike": "刺爆之", + "of Incineration": "焚化之", + "Incineration": "焚化之", + "of Incombustibility": "不燃之", + "Incombustibility": "不燃之", + "of Inertia": "抗性之", + "Inertia": "抗性之", + "of Inner Sight": "内视之", + "Inner Sight": "内视之", + "of Insulation": "绝缘之", + "Insulation": "绝缘之", + "of Ire": "愤怒之", + "Ire": "愤怒之", + "of Iron Golem Creation": "钢铁魔像之", + "Iron Golem Creation": "钢铁魔像之", + "of Iron Maiden": "攻击反噬之", + "Iron Maiden": "攻击反噬之", + "of Item Finding": "寻找物品之", + "Item Finding": "寻找物品之", + "of Jabbing": "戳刺之", + "Jabbing": "戳刺之", + "of Joyfulness": "欢欣之", + "Joyfulness": "欢欣之", + "of Knowledge": "知识之", + "Knowledge": "知识之", + "of Life": "生命之", + "Life": "生命之", + "of Life Everlasting": "永恒生命之", + "Life Everlasting": "永恒生命之", + "of Life Tap": "偷取生命之", + "Life Tap": "偷取生命之", + "of Light": "光明之", + "Light": "光明之", + "of Lightning": "闪电之", + "Lightning": "闪电之", + "of Lightning Fury": "闪电之怒之", + "Lightning Fury": "闪电之怒之", + "of Lightning Javelin": "闪电标枪之", + "Lightning Javelin": "闪电标枪之", + "of Lightning Strike": "雷电一击之", + "Lightning Strike": "雷电一击之", + "of Lower Resistance": "降低抗性之", + "Lower Resistance": "降低抗性之", + "of Luck": "幸运之", + "Luck": "幸运之", + "of Magic Arrows": "魔法箭之", + "Magic Arrows": "魔法箭之", + "of Maiming": "残废之", + "Maiming": "残废之", + "of Malice": "恶意之", + "Malice": "恶意之", + "of Measure": "度量之", + "Measure": "度量之", + "of Memory": "记忆之", + "Memory": "记忆之", + "of Meteor": "陨石之", + "Meteor": "陨石之", + "of Meteors": "陨石之", + "Meteors": "陨石之", + "of Might": "强力之", + "Might": "强力之", + "of Mind": "心灵之", + "Mind": "心灵之", + "of Molten Boulders": "熔岩巨石之", + "Molten Boulders": "熔岩巨石之", + "of Multiple Shot": "多重箭之", + "Multiple Shot": "多重箭之", + "of Negation": "否定之", + "Negation": "否定之", + "of Nirvana": "涅槃之", + "Nirvana": "涅槃之", + "of Nova": "新星之", + "Nova": "新星之", + "of Nova Shield": "新星护盾之", + "Nova Shield": "新星护盾之", + "of Novas": "新星之", + "Novas": "新星之", + "of Pacing": "步行之", + "Pacing": "步行之", + "of Passing": "消逝之", + "Passing": "消逝之", + "of Passion": "激情之", + "Passion": "激情之", + "of Perfection": "完美之", + "Perfection": "完美之", + "of Performance": "精良之", + "Performance": "精良之", + "of Pestilence": "瘟疫之", + "Pestilence": "瘟疫之", + "of Piercing": "刺穿之", + "Piercing": "刺穿之", + "of Plague Jab": "瘟疫标枪之", + "Plague Jab": "瘟疫标枪之", + "of Poison Dagger": "毒匕首之", + "Poison Dagger": "毒匕首之", + "of Poison Explosion": "毒爆之", + "Poison Explosion": "毒爆之", + "of Poison Jab": "毒枪之", + "Poison Jab": "毒枪之", + "of Poison Novas": "剧毒新星之", + "Poison Novas": "剧毒新星之", + "of Potion Finding": "寻找药剂之", + "Potion Finding": "寻找药剂之", + "of Power": "力量之", + "Power": "力量之", + "of Power Strike": "威力一击之", + "Power Strike": "威力一击之", + "of Precision": "精确之", + "Precision": "精确之", + "of Propogation": "繁衍之", + "Propogation": "繁衍之", + "of Prosperity": "繁荣之", + "Prosperity": "繁荣之", + "of Protection": "守护之", + "Protection": "守护之", + "of Puncturing": "爆破之", + "Puncturing": "爆破之", + "of Quality": "品质之", + "Quality": "品质之", + "of Quickness": "快速之", + "Quickness": "快速之", + "of Radiance": "光辉之", + "Radiance": "光辉之", + "of Raise Skeletal Mages": "骷髅法师之", + "Raise Skeletal Mages": "骷髅法师之", + "of Raise Skeletons": "复生骷髅之", + "Raise Skeletons": "复生骷髅之", + "of Razors": "剃刀之", + "Razors": "剃刀之", + "of Readiness": "准备之", + "Readiness": "准备之", + "of Regeneration": "再生之", + "Regeneration": "再生之", + "of Regrowth": "新生之", + "Regrowth": "新生之", + "of Remedy": "救治之", + "Remedy": "救治之", + "of Replenishing": "充盈之", + "Replenishing": "充盈之", + "of Resistance": "抗性之", + "Resistance": "抗性之", + "of Revivification": "复苏之", + "Revivification": "复苏之", + "of Sacrifice": "牺牲之", + "Sacrifice": "牺牲之", + "of Self-Repair": "自我修复之", + "Self-Repair": "自我修复之", + "of Shiver Armor": "碎冰甲之", + "Shiver Armor": "碎冰甲之", + "of Shock": "电击之", + "Shock": "电击之", + "of Shouting": "大叫之", + "Shouting": "大叫之", + "of Simplicity": "简朴之", + "Simplicity": "简朴之", + "of Skill": "技巧之", + "Skill": "技巧之", + "of Slaughter": "屠杀之", + "Slaughter": "屠杀之", + "of Slaying": "杀戮之", + "Slaying": "杀戮之", + "of Slow Missiles": "慢速箭之", + "Slow Missiles": "慢速箭之", + "of Sniping": "狙击之", + "Sniping": "狙击之", + "of Sorcery": "巫术之", + "Sorcery": "巫术之", + "of Spark": "火花之", + "Spark": "火花之", + "of Speed": "速度之", + "Speed": "速度之", + "of Spikers": "尖刺之", + "Spikers": "尖刺之", + "of Spikes": "尖刺之", + "Spikes": "尖刺之", + "of Spirit": "精神之", + "Spirit": "精神之", + "of Stability": "安定之", + "Stability": "安定之", + "of Stamina": "耐力之", + "Stamina": "耐力之", + "of Static": "静电之", + "Static": "静电之", + "of Static Field": "静电场之", + "Static Field": "静电场之", + "of Stoicism": "坚忍之", + "Stoicism": "坚忍之", + "of Storms": "风暴之", + "Storms": "风暴之", + "of Strength": "力量之", + "Strength": "力量之", + "of Striding": "跨步之", + "Striding": "跨步之", + "of Stunning": "击晕之", + "Stunning": "击晕之", + "of Substinence": "生计之", + "Substinence": "生计之", + "of Sunlight": "阳光之", + "Sunlight": "阳光之", + "of Swiftness": "疾速之", + "Swiftness": "疾速之", + "of Swords": "剑刃之", + "Swords": "剑刃之", + "of Taunting": "嘲弄之", + "Taunting": "嘲弄之", + "of Teeth": "牙之", + "Teeth": "牙之", + "of Telekinesis": "心灵传动之", + "Telekinesis": "心灵传动之", + "of Teleport Shield": "传送护盾之", + "Teleport Shield": "传送护盾之", + "of Teleportation": "传送之", + "Teleportation": "传送之", + "of Terror": "恐惧之", + "Terror": "恐惧之", + "of Thawing": "解冻之", + "Thawing": "解冻之", + "of Thorns": "荆棘之", + "Thorns": "荆棘之", + "of Thunder": "雷霆之", + "Thunder": "雷霆之", + "of Thunder Storm": "雷暴之", + "Thunder Storm": "雷暴之", + "of Tornado": "暴风之", + "Tornado": "暴风之", + "of Transcendence": "卓越之", + "Transcendence": "卓越之", + "of Traveling": "旅行之", + "Traveling": "旅行之", + "of Truth": "真理之", + "Truth": "真理之", + "of Twister": "龙卷风之", + "Twister": "龙卷风之", + "of Vengeance": "复仇之", + "Vengeance": "复仇之", + "of Venom": "毒素之", + "Venom": "毒素之", + "of Vileness": "卑劣之", + "Vileness": "卑劣之", + "of Virility": "刚毅之", + "Virility": "刚毅之", + "of Vita": "活力之", + "Vita": "活力之", + "of Volcano": "火山之", + "Volcano": "火山之", + "of War Cry": "战鸣之", + "War Cry": "战鸣之", + "of Warding": "防避之", + "Warding": "防避之", + "of Warming": "保温之", + "Warming": "保温之", + "of Warmth": "温暖之", + "Warmth": "温暖之", + "of Weaken": "削弱之", + "Weaken": "削弱之", + "of Wealth": "财富之", + "Wealth": "财富之", + "of Winter": "严冬之", + "Winter": "严冬之", + "of Wizardry": "法术之", + "Wizardry": "法术之", + "of Worth": "价值之", + "Worth": "价值之", + "of Wrath": "盛怒之", + "Wrath": "盛怒之", + "of Zeal": "热诚之", + "Zeal": "热诚之", + "of the Apprentice": "学徒之", + "the Apprentice": "学徒之", + "of the Bat": "蝙蝠之", + "the Bat": "蝙蝠之", + "of the Bear": "巨熊之", + "the Bear": "巨熊之", + "of the Cobra": "眼镜蛇之", + "the Cobra": "眼镜蛇之", + "of the Colossus": "巨神之", + "the Colossus": "巨神之", + "of the Colosuss": "巨神之", + "the Colosuss": "巨神之", + "of the Dunes": "沙丘之", + "the Dunes": "沙丘之", + "of the Dynamo": "发电机之", + "the Dynamo": "发电机之", + "of the Efreeti": "火灵之", + "the Efreeti": "火灵之", + "of the Elements": "元素之", + "the Elements": "元素之", + "of the Elephant": "大象之", + "the Elephant": "大象之", + "of the Fox": "狐狸之", + "the Fox": "狐狸之", + "of the Ghoul": "食尸鬼之", + "the Ghoul": "食尸鬼之", + "of the Giant": "巨人之", + "the Giant": "巨人之", + "of the Glacier": "冰川之", + "the Glacier": "冰川之", + "of the Icicle": "冰柱之", + "the Icicle": "冰柱之", + "of the Jackal": "胡狼之", + "the Jackal": "胡狼之", + "of the Kraken": "海妖之", + "the Kraken": "海妖之", + "of the Lamprey": "八目鳗之", + "the Lamprey": "八目鳗之", + "of the Leech": "水蛭之", + "the Leech": "水蛭之", + "of the Locust": "蝗虫之", + "the Locust": "蝗虫之", + "of the Magus": "法师之", + "the Magus": "法师之", + "of the Mammoth": "猛犸之", + "the Mammoth": "猛犸之", + "of the Mind": "心灵之", + "the Mind": "心灵之", + "of the Ox": "公牛之", + "the Ox": "公牛之", + "of the Phoenix": "凤凰之", + "the Phoenix": "凤凰之", + "of the Sentinel": "步哨之", + "the Sentinel": "步哨之", + "of the Sirocco": "热风之", + "the Sirocco": "热风之", + "of the Squid": "乌贼之", + "the Squid": "乌贼之", + "of the Sun": "太阳之", + "the Sun": "太阳之", + "of the Tiger": "猛虎之", + "the Tiger": "猛虎之", + "of the Titan": "泰坦之", + "the Titan": "泰坦之", + "of the Vampire": "吸血鬼之", + "the Vampire": "吸血鬼之", + "of the Whale": "巨鲸之", + "the Whale": "巨鲸之", + "of the Wolf": "苍狼之", + "the Wolf": "苍狼之", + "of the Wraith": "幽灵之", + "the Wraith": "幽灵之", + "of the Yeti": "雪人之", + "the Yeti": "雪人之", } /** @@ -1723,7 +2329,7 @@ export const RARE_SUFFIX_ZH: Record = { "sever": "断裂者", "sunder": "撕碎者", "rend": "分裂", - "mangler": "亂砍者", + "mangler": "乱砍者", "slayer": "屠杀者", "reaver": "强夺者", "spawn": "重生的", @@ -1766,7 +2372,7 @@ export const RARE_SUFFIX_ZH: Record = { "spell": "法术", "chant": "曲", "weaver": "编织者", - "gnarl": "節", + "gnarl": "节", "visage": "脸", "crest": "顶饰", "circlet": "饰环", @@ -1806,7 +2412,7 @@ export const RARE_SUFFIX_ZH: Record = { "hold": "握", "touch": "触碰", "finger": "手指", - "knuckle": "指節", + "knuckle": "指节", "shank": "小腿", "spur": "踢马刺", "tread": "踏步", @@ -1837,7 +2443,7 @@ export const RARE_SUFFIX_ZH: Record = { "coil": "盘绕", "gyre": "旋回", "band": "箍", - "whorl": "螺層", + "whorl": "螺层", "talisman": "护符", "heart": "心", "noose": "套索", @@ -1895,10 +2501,10 @@ export const SKILL_NAMES_ZH: Record = { "Penetrate": "刺入", "Charged Strike": "充能一击", "Plague Javelin": "瘟疫标枪", - "Strafe": "砲轟", - "Immolation Arrow": "犧牲之箭", - "Decoy": "诱弭", - "Dopplezon": "诱弭", + "Strafe": "炮轰", + "Immolation Arrow": "牺牲之箭", + "Decoy": "诱饵", + "Dopplezon": "诱饵", "Evade": "回避", "Fend": "击退", "Freezing Arrow": "冻结之箭", @@ -1912,11 +2518,11 @@ export const SKILL_NAMES_ZH: Record = { "Ice Bolt": "冰弹", "Frozen Armor": "冰封装甲", "Inferno": "地狱之火", - "Static Field": "靜態力场", + "Static Field": "静态力场", "Telekinesis": "心灵传动", "Frost Nova": "霜之新星", "Ice Blast": "冰风暴", - "Blaze": "炽烈之徑", + "Blaze": "炽烈之径", "Fire Ball": "火球", "Nova": "新星", "Lightning": "闪电", @@ -1927,7 +2533,7 @@ export const SKILL_NAMES_ZH: Record = { "Teleport": "传送", "Glacial Spike": "冰尖柱", "Meteor": "陨石", - "Thunder Storm": "雷雲风暴", + "Thunder Storm": "雷云风暴", "Energy Shield": "能量护盾", "Blizzard": "暴风雪", "Chilling Armor": "寒冰装甲", @@ -1940,7 +2546,7 @@ export const SKILL_NAMES_ZH: Record = { "Teeth": "牙", "Bone Armor": "白骨装甲", "Skeleton Mastery": "支配骷髅", - "Raise Skeleton": "骷髅复甦", + "Raise Skeleton": "骷髅复苏", "Dim Vision": "微暗灵视", "Weaken": "削弱", "Poison Dagger": "淬毒匕首", @@ -1950,8 +2556,8 @@ export const SKILL_NAMES_ZH: Record = { "Terror": "恐惧", "Bone Wall": "骨墙", "Golem Mastery": "支配石魔", - "Raise Skeletal Mage": "复甦骷髅法师", - "Confuse": "迷亂", + "Raise Skeletal Mage": "复苏骷髅法师", + "Confuse": "迷乱", "Life Tap": "偷取生命", "Poison Explosion": "毒爆", "Bone Spear": "骨矛", @@ -1964,12 +2570,12 @@ export const SKILL_NAMES_ZH: Record = { "Iron Golem": "铁石魔", "IronGolem": "铁石魔", "Lower Resist": "降低抵抗", - "Poison Nova": "劇毒新星", + "Poison Nova": "剧毒新星", "Bone Spirit": "白骨之魂", "Fire Golem": "火石魔", "FireGolem": "火石魔", "Revive": "重生", - "Sacrifice": "犧牲", + "Sacrifice": "牺牲", "Smite": "重击", "Might": "力量", "Prayer": "祈祷", @@ -1989,7 +2595,7 @@ export const SKILL_NAMES_ZH: Record = { "Concentration": "专注", "Holy Freeze": "神圣冰冻", "Vigor": "精力", - "Conversion": "转換", + "Conversion": "转换", "Holy Shield": "神圣之盾", "Holy Shock": "神圣冲击", "Sanctuary": "庇护所", @@ -2020,10 +2626,10 @@ export const SKILL_NAMES_ZH: Record = { "Concentrate": "专心", "Iron Skin": "铁布杉", "Battle Cry": "战嗥", - "Frenzy": "狂亂", + "Frenzy": "狂乱", "Increased Speed": "加速", "Battle Orders": "战斗体制", - "Grim Ward": "残酷嚇阻", + "Grim Ward": "残酷吓阻", "Whirlwind": "旋风", "Berserk": "狂战士", "Natural Resistance": "自然抵抗", @@ -2031,16 +2637,16 @@ export const SKILL_NAMES_ZH: Record = { "Battle Command": "战斗指挥", "Scroll of Identify": "辨视卷轴", "Tome of Identify": "辨视之书", - "Book of Identify": "辨视之书", + "Book of Identify": "辨识之书", "Scroll of Townportal": "城镇传送卷轴", "Tome of Townportal": "城镇传送之书", "Book of Townportal": "城镇传送之书", "Raven": "渡鸟之", - "Werewolf": "狼人變化", - "Wearwolf": "狼人變化", + "Werewolf": "狼人变化", + "Wearwolf": "狼人变化", "Maul": "大木槌的", - "Fissure": "裂縫", - "Eruption": "裂縫", + "Fissure": "裂缝", + "Eruption": "裂缝", "Armageddon": "世界末日之", "Venom": "毒液的", "Delirium": "迪勒瑞姆", @@ -2072,7 +2678,7 @@ export const SKILL_NAMES_ZH: Record = { "Hurricane": "飓风", "Fire Blast": "火焰爆震", "Claw Mastery": "支配利爪", - "Psychic Hammer": "心灵战槌", + "Psychic Hammer": "心灵战锤", "Tiger Strike": "虎击", "Dragon Talon": "龙爪", "Shock Web": "电能网", @@ -2337,18 +2943,19 @@ export function translateMagicName(magicName: string, baseName?: string): string } } - const preZh = pre ? (MAGIC_PREFIX_ZH[pre] ?? pre + '之') : '' - const sufZh = suf ? (MAGIC_SUFFIX_ZH[suf] ?? suf) : '' + const preZh = pre ? (MAGIC_PREFIX_ZH[pre] ?? (pre.endsWith('之') ? pre : pre + '之')) : '' + const sufKey = suf.startsWith('of ') ? suf : 'of ' + suf + const sufZh = suf ? (MAGIC_SUFFIX_ZH[suf] ?? MAGIC_SUFFIX_ZH[sufKey] ?? MAGIC_SUFFIX_ZH[suf.replace(/^of\s+/, '')] ?? (suf.endsWith('之') ? suf : suf + '之')) : '' const baseZh = translateItemName(base) if (preZh && sufZh) { - return `${preZh}${baseZh}${sufZh}` + return `${preZh}${sufZh}${baseZh}` } if (preZh) { return `${preZh}${baseZh}` } if (sufZh) { - return `${baseZh}${sufZh}` + return `${sufZh}${baseZh}` } return translateItemName(magicName) } @@ -2423,15 +3030,20 @@ function resolveSkillInfoZh(par: string | number | undefined): { name: string; c if (par === undefined || par === '') { return { name: '未知技能' } } - const str = String(par).trim() - const num = Number(str) - if (!Number.isNaN(num)) { - // Look up ID in skills map or fallback - const enName = Object.keys(SKILL_NAMES_ZH)[num] ?? str - return { name: SKILL_NAMES_ZH[enName] ?? enName } + const info = resolveSkillInfo(par) + const nameZh = translateSkillName(info.name) + let classOnlyZh: string | undefined + if (info.classOnly) { + if (info.classOnly.includes('Amazon')) classOnlyZh = '(限亚马逊使用)' + else if (info.classOnly.includes('Sorceress')) classOnlyZh = '(限法师使用)' + else if (info.classOnly.includes('Necromancer')) classOnlyZh = '(限死灵法师使用)' + else if (info.classOnly.includes('Paladin')) classOnlyZh = '(限圣骑士使用)' + else if (info.classOnly.includes('Barbarian')) classOnlyZh = '(限野蛮人使用)' + else if (info.classOnly.includes('Druid')) classOnlyZh = '(限德鲁伊使用)' + else if (info.classOnly.includes('Assassin')) classOnlyZh = '(限刺客使用)' + else classOnlyZh = info.classOnly } - const nameZh = SKILL_NAMES_ZH[str] ?? SKILL_NAMES_ZH[str.toLowerCase()] ?? str - return { name: nameZh } + return classOnlyZh ? { name: nameZh, classOnly: classOnlyZh } : { name: nameZh } } function formatPropertyCodeZh( @@ -2443,7 +3055,7 @@ function formatPropertyCodeZh( effectiveVal: number, plusVal: string, ): string { - switch (code.trim().toLowerCase()) { + switch (code.trim().toLowerCase().replace(/^\*/, '')) { // --- Skills & Class Skills --- case 'allskills': return `${plusVal} 所有技能` @@ -2534,8 +3146,8 @@ function formatPropertyCodeZh( } case 'charged': { const sk = resolveSkillInfoZh(par) - const charges = min || effectiveVal || 10 - const slvl = max || 1 + const charges = Math.abs(min || effectiveVal || 10) + const slvl = Math.abs(max || 1) return `等级 ${slvl} ${sk.name} (${charges}/${charges} 次充能)` } @@ -2925,7 +3537,7 @@ function formatPropertyCodeEn( effectiveVal: number, plusVal: string, ): string { - switch (code.trim().toLowerCase()) { + switch (code.trim().toLowerCase().replace(/^\*/, '')) { case 'allskills': return `${plusVal} to All Skills` case 'ama': return `${plusVal} to Amazon Skill Levels` case 'sor': return `${plusVal} to Sorceress Skill Levels` @@ -2941,14 +3553,40 @@ function formatPropertyCodeEn( case 'skill': return `${plusVal} to ${par ?? 'Skill'}` case 'skill-rand': return `+${par || 3} to Skill` case 'oskill': return `${plusVal} to ${par ?? 'Skill'}` - case 'aura': return `Level ${effectiveVal} ${par} Aura When Equipped` - case 'hit-skill': return `${min || effectiveVal || 5}% Chance to cast level ${max || 1} ${par} on striking` - case 'att-skill': return `${min || effectiveVal || 5}% Chance to cast level ${max || 1} ${par} on attack` - case 'gethit-skill': return `${min || effectiveVal || 5}% Chance to cast level ${max || 1} ${par} when struck` - case 'kill-skill': return `${min || effectiveVal || 5}% Chance to cast level ${max || 1} ${par} when you Kill an Enemy` - case 'death-skill': return `${min || effectiveVal || 100}% Chance to cast level ${max || 1} ${par} when you Die` - case 'levelup-skill': return `${min || effectiveVal || 100}% Chance to cast level ${max || 1} ${par} when you Level-Up` - case 'charged': return `Level ${max || 1} ${par} (${min || effectiveVal || 10}/${min || effectiveVal || 10} Charges)` + case 'aura': { + const sk = resolveSkillInfo(par) + return `Level ${effectiveVal} ${sk.name} Aura When Equipped` + } + case 'hit-skill': { + const sk = resolveSkillInfo(par) + return `${min || effectiveVal || 5}% Chance to cast level ${max || 1} ${sk.name} on striking` + } + case 'att-skill': { + const sk = resolveSkillInfo(par) + return `${min || effectiveVal || 5}% Chance to cast level ${max || 1} ${sk.name} on attack` + } + case 'gethit-skill': { + const sk = resolveSkillInfo(par) + return `${min || effectiveVal || 5}% Chance to cast level ${max || 1} ${sk.name} when struck` + } + case 'kill-skill': { + const sk = resolveSkillInfo(par) + return `${min || effectiveVal || 5}% Chance to cast level ${max || 1} ${sk.name} when you Kill an Enemy` + } + case 'death-skill': { + const sk = resolveSkillInfo(par) + return `${min || effectiveVal || 100}% Chance to cast level ${max || 1} ${sk.name} when you Die` + } + case 'levelup-skill': { + const sk = resolveSkillInfo(par) + return `${min || effectiveVal || 100}% Chance to cast level ${max || 1} ${sk.name} when you Level-Up` + } + case 'charged': { + const sk = resolveSkillInfo(par) + const c = Math.abs(min || effectiveVal || 10) + const l = Math.abs(max || 1) + return `Level ${l} ${sk.name} (${c}/${c} Charges)` + } case 'str': return `${plusVal} to Strength` case 'dex': return `${plusVal} to Dexterity` case 'vit': return `${plusVal} to Vitality` diff --git a/tests/item-tooltip-i18n-122.test.ts b/tests/item-tooltip-i18n-122.test.ts index a6adcf5..2c0795f 100644 --- a/tests/item-tooltip-i18n-122.test.ts +++ b/tests/item-tooltip-i18n-122.test.ts @@ -82,10 +82,26 @@ describe('Issue #122: Equipment & Affix Chinese Localization (EN / ZH / Bilingua expect(translateSkillName('Poison Creeper')).toBe('剧毒蔓藤') }) - it('translates rare and magic names correctly', () => { + it('translates rare and magic names correctly with proper Chinese word order', () => { expect(translateRareName('Beast Edge')).toBe('野兽之刃') expect(translateRareName('Shadow Brow')).toBe('阴影之额头') + // Prefix only expect(translateMagicName('Sturdy Leather Armor', 'Leather Armor')).toBe('结实之皮甲') + // Suffix only: modifier before noun + expect(translateMagicName('War Spear of Swiftness', 'War Spear')).toBe('疾速之巨战长矛') + // Both prefix & suffix: modifiers before noun + expect(translateMagicName('Savage Short Sword of the Giant', 'Short Sword')).toBe('野蛮之巨人之短剑') + // 100% Affix Coverage test for previously missing items + expect(translateMagicName("Harpoonist's Ceremonial Javelin", 'Ceremonial Javelin')).toBe('标枪之祭典标枪') + expect(translateMagicName('Trump Edge Bow', 'Edge Bow')).toBe('胜者之锋锐之弓') + expect(translateMagicName('Gritty Broad Axe', 'Broad Axe')).toBe('坚韧之阔斧') + }) + + it('translates item names to normalized Simplified Chinese', () => { + expect(translateItemName('Flawless Ruby')).toBe('无瑕疵的红宝石') + expect(translateItemName('Flawless Emerald')).toBe('无瑕疵的绿宝石') + expect(translateItemName('The Humongous')).toBe('巨大无比') + expect(translateItemName('Steelclash')).toBe('作响的金属') }) }) @@ -93,8 +109,8 @@ describe('Issue #122: Equipment & Affix Chinese Localization (EN / ZH / Bilingua it('formats skills in Chinese', () => { expect(formatPropertyCodeI18n('allskills', 2, undefined, undefined, undefined, 'zh')).toBe('+2 所有技能') expect(formatPropertyCodeI18n('ama', 1, undefined, undefined, undefined, 'zh')).toBe('+1 亚马逊技能等级') - expect(formatPropertyCodeI18n('skilltab', 2, undefined, undefined, 3, 'zh')).toBe('+2 火焰技能 (限法师使用)') - expect(formatPropertyCodeI18n('skill', 3, undefined, undefined, 'Teleport', 'zh')).toBe('+3 传送') + expect(formatPropertyCodeI18n('skill', 3, undefined, undefined, 'Teleport', 'zh')).toBe('+3 传送 (限法师使用)') + expect(formatPropertyCodeI18n('oskill', 1, undefined, undefined, 'Teleport', 'zh')).toBe('+1 传送') }) it('formats attributes & life/mana in Chinese', () => { @@ -117,6 +133,17 @@ describe('Issue #122: Equipment & Affix Chinese Localization (EN / ZH / Bilingua expect(formatPropertyCodeI18n('hp/lvl', 12, undefined, undefined, undefined, 'zh')).toBe('+1.5 生命 (依角色等级提升)') expect(formatPropertyCodeI18n('rep-dur', 0, 0, undefined, 33, 'zh')).toBe('每 3 秒恢复 1 点耐久度') }) + + it('handles charged spell properties with MPQ negative encoding', () => { + // In 1.13c MPQ, charges and level are stored as negative numbers e.g. min: -20, max: -3 + expect(formatPropertyCodeI18n('charged', -20, -20, -3, 'Enchant', 'zh')).toBe('等级 3 强化 (20/20 次充能)') + expect(formatPropertyCodeI18n('charged', -20, -20, -3, 'Enchant', 'en')).toBe('Level 3 Enchant (20/20 Charges)') + }) + + it('handles asterisk-prefixed properties like *hp from UniqueItems.txt', () => { + expect(formatPropertyCodeI18n('*hp', -10, -10, -10, undefined, 'zh')).toBe('-10 生命') + expect(formatPropertyCodeI18n('*hp', -10, -10, -10, undefined, 'en')).toBe('-10 to Life') + }) }) describe('4. formatItemTooltip: EN, ZH, and Bilingual Modes', () => {