HASH eeda0bdb58ed
DATE 2025-07-27
SUBJECT nix: enrich talents and glyphs
FILES 5 CHANGED
HASH eeda0bdb58ed
DATE 2025-07-27
SUBJECT nix: enrich talents and glyphs
FILES 5 CHANGED
┌─ flake.lock ───────────────────────────────────────────────────────────────┐
│ diff --git a/flake.lock b/flake.lock │
│ index 313dcab..47a8c2c 100644 │
│ --- a/flake.lock │
│ +++ b/flake.lock │
│ @@ -85,11 +85,11 @@ │
│ ] │
│ }, │
│ "locked": { │
│ - "lastModified": 1753422684, │
│ - "narHash": "sha256-mUTXnS3d5IMH3GZ744dLylXdJYfxek9MRiWBCmtrtBQ=", │
│ + "lastModified": 1753526276, │
│ + "narHash": "sha256-XIqrgUb8ml9t2oEE6tuCMnVX6TtzSYa9aujtAe6r+jg=", │
│ "owner": "ooks-io", │
│ "repo": "mop", │
│ - "rev": "77b72ea264ed075871108b78fd9ff83f459b4780", │
│ + "rev": "49e2efe1a9b8f68e049f874142a25ce7f2e076a1", │
│ "type": "github" │
│ }, │
│ "original": { │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ flake.lock ─────────────────────────┐
│ diff --git a/flake.lock b/flake.lock │
│ index 313dcab..47a8c2c 100644 │
│ --- a/flake.lock │
│ +++ b/flake.lock │
│ @@ -85,11 +85,11 @@ │
│ ] │
│ }, │
│ "locked": { │
│ - "lastModified": 1753422684, │
│ - "narHash": "sha256-mUTXnS3d5IMH3GZ7 │
│ 44dLylXdJYfxek9MRiWBCmtrtBQ=", │
│ + "lastModified": 1753526276, │
│ + "narHash": "sha256-XIqrgUb8ml9t2oEE │
│ 6tuCMnVX6TtzSYa9aujtAe6r+jg=", │
│ "owner": "ooks-io", │
│ "repo": "mop", │
│ - "rev": "77b72ea264ed075871108b78fd9 │
│ ff83f459b4780", │
│ + "rev": "49e2efe1a9b8f68e049f874142a │
│ 25ce7f2e076a1", │
│ "type": "github" │
│ }, │
│ "original": { │
└──────────────────────────────────────────────┘
┌─ nix/apps/simulation/mkMassSim.nix ────────────────────────────────────────┐
│ diff --git a/nix/apps/simulation/mkMassSim.nix b/nix/apps/simulation/mkMassSim.nix │
│ index b1e8a1c..3b3f5aa 100644 │
│ --- a/nix/apps/simulation/mkMassSim.nix │
│ +++ b/nix/apps/simulation/mkMassSim.nix │
│ @@ -102,10 +102,11 @@ │
│ simDerivations = lib.listToAttrs (map (raceConfig: { │
│ name = "${raceConfig.className}-${raceConfig.specName}-${raceConfig.raceN │
│ ame}"; │
│ value = let │
│ - # Pre-enrich the equipment, consumables, and glyphs for this race confi │
│ g │
│ + # Pre-enrich the equipment, consumables, glyphs, and talents for this r │
│ ace config │
│ enrichedEquipment = itemDatabase.enrichEquipment raceConfig.config.equi │
│ pment; │
│ enrichedConsumables = itemDatabase.enrichConsumables raceConfig.config. │
│ consumables; │
│ - enrichedGlyphs = itemDatabase.enrichGlyphs raceConfig.config.glyphs; │
│ + enrichedGlyphs = itemDatabase.enrichGlyphs raceConfig.config.class race │
│ Config.config.glyphs; │
│ + enrichedTalents = itemDatabase.enrichTalents raceConfig.config.class ra │
│ ceConfig.config.talentsString; │
│ │
│ simInput = mkSim { │
│ inherit iterations; │
│ @@ -132,6 +133,10 @@ CONSUMABLES_EOF │
│ ${builtins.toJSON enrichedGlyphs} │
│ GLYPHS_EOF │
│ │
│ + cat > talents.json << 'TALENTS_EOF' │
│ +${builtins.toJSON enrichedTalents} │
│ +TALENTS_EOF │
│ + │
│ cat > input.json << 'INPUT_EOF' │
│ ${simInput} │
│ INPUT_EOF │
│ @@ -154,6 +159,7 @@ INPUT_EOF │
│ --slurpfile equipment enriched_equipment.json \ │
│ --slurpfile consumables consumables.json \ │
│ --arg talentsString "${raceConfig.config.talentsString}" \ │
│ + --slurpfile talents talents.json \ │
│ --slurpfile glyphs glyphs.json \ │
│ --arg race "${raceConfig.config.race}" \ │
│ --arg class "${raceConfig.config.class}" \ │
│ @@ -168,6 +174,7 @@ INPUT_EOF │
│ loadout: { │
│ consumables: $consumables[0], │
│ talentsString: $talentsString, │
│ + talents: $talents[0], │
│ glyphs: $glyphs[0], │
│ equipment: $equipment[0], │
│ race: $race, │
│ @@ -324,10 +331,11 @@ INPUT_EOF │
│ simDerivations = lib.listToAttrs (map (spec: { │
│ name = "${spec.className}-${spec.specName}"; │
│ value = let │
│ - # Pre-enrich the equipment, consumables, and glyphs for this spec │
│ + # Pre-enrich the equipment, consumables, glyphs, and talents for this s │
│ pec │
│ enrichedEquipment = itemDatabase.enrichEquipment spec.config.equipment; │
│ enrichedConsumables = itemDatabase.enrichConsumables spec.config.consum │
│ ables; │
│ - enrichedGlyphs = itemDatabase.enrichGlyphs spec.config.glyphs; │
│ + enrichedGlyphs = itemDatabase.enrichGlyphs spec.config.class spec.confi │
│ g.glyphs; │
│ + enrichedTalents = itemDatabase.enrichTalents spec.config.class spec.con │
│ fig.talentsString; │
│ │
│ simInput = mkSim { │
│ inherit iterations; │
│ @@ -354,6 +362,10 @@ CONSUMABLES_EOF │
│ ${builtins.toJSON enrichedGlyphs} │
│ GLYPHS_EOF │
│ │
│ + cat > talents.json << 'TALENTS_EOF' │
│ +${builtins.toJSON enrichedTalents} │
│ +TALENTS_EOF │
│ + │
│ cat > input.json << 'INPUT_EOF' │
│ ${simInput} │
│ INPUT_EOF │
│ @@ -377,6 +389,7 @@ INPUT_EOF │
│ --slurpfile equipment enriched_equipment.json \ │
│ --slurpfile consumables consumables.json \ │
│ --arg talentsString "${spec.config.talentsString}" \ │
│ + --slurpfile talents talents.json \ │
│ --slurpfile glyphs glyphs.json \ │
│ --arg race "${spec.config.race}" \ │
│ --arg class "${spec.config.class}" \ │
│ @@ -392,6 +405,7 @@ INPUT_EOF │
│ loadout: { │
│ consumables: $consumables[0], │
│ talentsString: $talentsString, │
│ + talents: $talents[0], │
│ glyphs: $glyphs[0], │
│ equipment: $equipment[0], │
│ race: $race, │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...apps/simulation/mkMassSim.nix ───┐
│ diff --git a/nix/apps/simulation/mkMassSim.n │
│ ix b/nix/apps/simulation/mkMassSim.nix │
│ index b1e8a1c..3b3f5aa 100644 │
│ --- a/nix/apps/simulation/mkMassSim.nix │
│ +++ b/nix/apps/simulation/mkMassSim.nix │
│ @@ -102,10 +102,11 @@ │
│ simDerivations = lib.listToAttrs (map ( │
│ raceConfig: { │
│ name = "${raceConfig.className}-${r │
│ aceConfig.specName}-${raceConfig.raceName}"; │
│ value = let │
│ - # Pre-enrich the equipment, consu │
│ mables, and glyphs for this race config │
│ + # Pre-enrich the equipment, consu │
│ mables, glyphs, and talents for this race co │
│ nfig │
│ enrichedEquipment = itemDatabase. │
│ enrichEquipment raceConfig.config.equipment; │
│ enrichedConsumables = itemDatabas │
│ e.enrichConsumables raceConfig.config.consum │
│ ables; │
│ - enrichedGlyphs = itemDatabase.enr │
│ ichGlyphs raceConfig.config.glyphs; │
│ + enrichedGlyphs = itemDatabase.enr │
│ ichGlyphs raceConfig.config.class raceConfig │
│ .config.glyphs; │
│ + enrichedTalents = itemDatabase.en │
│ richTalents raceConfig.config.class raceConf │
│ ig.config.talentsString; │
│ │
│ simInput = mkSim { │
│ inherit iterations; │
│ @@ -132,6 +133,10 @@ CONSUMABLES_EOF │
│ ${builtins.toJSON enrichedGlyphs} │
│ GLYPHS_EOF │
│ │
│ + cat > talents.json << 'TALENTS_ │
│ EOF' │
│ +${builtins.toJSON enrichedTalents} │
│ +TALENTS_EOF │
│ + │
│ cat > input.json << 'INPUT_EOF' │
│ ${simInput} │
│ INPUT_EOF │
│ @@ -154,6 +159,7 @@ INPUT_EOF │
│ --slurpfile equipment enric │
│ hed_equipment.json \ │
│ --slurpfile consumables con │
│ sumables.json \ │
│ --arg talentsString "${race │
│ Config.config.talentsString}" \ │
│ + --slurpfile talents talents │
│ .json \ │
│ --slurpfile glyphs glyphs.j │
│ son \ │
│ --arg race "${raceConfig.co │
│ nfig.race}" \ │
│ --arg class "${raceConfig.c │
│ onfig.class}" \ │
│ @@ -168,6 +174,7 @@ INPUT_EOF │
│ loadout: { │
│ consumables: $consumabl │
│ es[0], │
│ talentsString: $talents │
│ String, │
│ + talents: $talents[0], │
│ glyphs: $glyphs[0], │
│ equipment: $equipment[0 │
│ ], │
│ race: $race, │
│ @@ -324,10 +331,11 @@ INPUT_EOF │
│ simDerivations = lib.listToAttrs (map ( │
│ spec: { │
│ name = "${spec.className}-${spec.sp │
│ ecName}"; │
│ value = let │
│ - # Pre-enrich the equipment, consu │
│ mables, and glyphs for this spec │
│ + # Pre-enrich the equipment, consu │
│ mables, glyphs, and talents for this spec │
│ enrichedEquipment = itemDatabase. │
│ enrichEquipment spec.config.equipment; │
│ enrichedConsumables = itemDatabas │
│ e.enrichConsumables spec.config.consumables; │
│ - enrichedGlyphs = itemDatabase.enr │
│ ichGlyphs spec.config.glyphs; │
│ + enrichedGlyphs = itemDatabase.enr │
│ ichGlyphs spec.config.class spec.config.glyp │
│ hs; │
│ + enrichedTalents = itemDatabase.en │
│ richTalents spec.config.class spec.config.ta │
│ lentsString; │
│ │
│ simInput = mkSim { │
│ inherit iterations; │
│ @@ -354,6 +362,10 @@ CONSUMABLES_EOF │
│ ${builtins.toJSON enrichedGlyphs} │
│ GLYPHS_EOF │
│ │
│ + cat > talents.json << 'TALENTS_ │
│ EOF' │
│ +${builtins.toJSON enrichedTalents} │
│ +TALENTS_EOF │
│ + │
│ cat > input.json << 'INPUT_EOF' │
│ ${simInput} │
│ INPUT_EOF │
│ @@ -377,6 +389,7 @@ INPUT_EOF │
│ --slurpfile equipment enric │
│ hed_equipment.json \ │
│ --slurpfile consumables con │
│ sumables.json \ │
│ --arg talentsString "${spec │
│ .config.talentsString}" \ │
│ + --slurpfile talents talents │
│ .json \ │
│ --slurpfile glyphs glyphs.j │
│ son \ │
│ --arg race "${spec.config.r │
│ ace}" \ │
│ --arg class "${spec.config. │
│ class}" \ │
│ @@ -392,6 +405,7 @@ INPUT_EOF │
│ loadout: { │
│ consumables: $consumabl │
│ es[0], │
│ talentsString: $talents │
│ String, │
│ + talents: $talents[0], │
│ glyphs: $glyphs[0], │
│ equipment: $equipment[0 │
│ ], │
│ race: $race, │
└──────────────────────────────────────────────┘
┌─ nix/lib/database/glyphs.nix ──────────────────────────────────────────────┐
│ diff --git a/nix/lib/database/glyphs.nix b/nix/lib/database/glyphs.nix │
│ new file mode 100644 │
│ index 0000000..3d24853 │
│ --- /dev/null │
│ +++ b/nix/lib/database/glyphs.nix │
│ @@ -0,0 +1,91 @@ │
│ +let │
│ + mkGlyph = name: spellId: icon: { │
│ + inherit spellId icon; │
│ + name = "Glyph of ${name}"; │
│ + }; │
│ +in { │
│ + # TODO: complete glyph list, currently only supporting those that exist in the │
│ current profiles │
│ + ClassDeathKnight = { │
│ + "43533" = mkGlyph "Anti-Magic Shell" 58623 "spell_shadow_antimagicshell"; │
│ + "43537" = mkGlyph "Chains of Ice" 58620 "spell_frost_chainsofice"; │
│ + "45800" = mkGlyph "Simulacrum" 63331 "spell_holy_consumemagic"; │
│ + "104048" = mkGlyph "Regenerative Magic" 146648 "spell_shadow_antimagicshell"; │
│ + "104047" = mkGlyph "Loud Horn" 146646 "inv_misc_horn_04"; │
│ + "43548" = mkGlyph "Pestilence" 58657 "spell_shadow_plaguecloud"; │
│ + "43554" = mkGlyph "Vampiric Blood" 58657 "spell_shadow_lifedrain"; │
│ + "43550" = mkGlyph "Army of the Dead" 58669 "spell_deathknight_armyofthedead"; │
│ + "45806" = mkGlyph "Tranquil Grip" 63335 "ability_rogue_envelopingshadows"; │
│ + "43673" = mkGlyph "Death Gate" 60200 "spell_arcane_teleportundercity"; │
│ + "43539" = mkGlyph "Death's Embrace" 58677 "spell_shadow_deathcoil"; │
│ + }; │
│ + ClassDruid = { │
│ + "40914" = mkGlyph "Healing Touch" 54825 "spell_nature_healingtouch"; │
│ + "40906" = mkGlyph "Stampede" 114300 "spell_druid_stampedingroar_cat"; │
│ + "40909" = mkGlyph "Rebirth" 54733 "spell_nature_reincarnation"; │
│ + }; │
│ + ClassHunter = { │
│ + "42909" = mkGlyph "Animal Bond" 20895 "classic_ability_druid_demoralizingroar │
│ "; │
│ + "42903" = mkGlyph "Deterrence" 56850 "ability_whirlwind"; │
│ + "42911" = mkGlyph "Pathfinding" 19560 "ability_hunter_pathfinding2"; │
│ + "42914" = mkGlyph "Aimed Shot" 126095 "inv_spear_07"; │
│ + "42899" = mkGlyph "Liberation" 132106 "achievement_bg_returnxflags_def_wsg"; │
│ + }; │
│ + ClassMage = { │
│ + # major │
│ + "44955" = mkGlyph "Arcane Power" 62210 "spell_nature_lightning"; │
│ + "42748" = mkGlyph "Rapid Displacement" 146659 "spell_arcane_blink"; │
│ + "42746" = mkGlyph "Cone of Cold" 115705 "spell_frost_glacier"; │
│ + "42739" = mkGlyph "Combustion" 56368 "spell_fire_sealoffire"; │
│ + "63539" = mkGlyph "Inferno Blast" 89926 "spell_mage_infernoblast"; │
│ + "42745" = mkGlyph "Splitting Ice" 56377 "spell_frost_frostblast"; │
│ + "45736" = mkGlyph "Water Elemental" 63090 "spell_frost_summonwaterelemental_2 │
│ "; │
│ + # minor │
│ + "42743" = mkGlyph "Momentum" 56384 "spell_arcane_blink"; │
│ + "63416" = mkGlyph "Rapid Teleportation" 46989 "spell_arcane_portaldalaran"; │
│ + "42735" = mkGlyph "Loose Mana" 56363 "inv_misc_gem_sapphire_02"; │
│ + "104104" = mkGlyph "Unbound Elemental" 146976 "spell_frost_summonwaterelement │
│ al"; │
│ + "45739" = mkGlyph "Mirror Image" 45739 "spell_magic_lesserinvisibilty"; │
│ + }; │
│ + ClassMonk = { │
│ + # major │
│ + "85697" = mkGlyph "Spinning Crane Kick" 120479 "ability_monk_cranekick_new"; │
│ + "87900" = mkGlyph "Touch of Karma" 125678 "ability_monk_touchofkarma"; │
│ + "85695" = mkGlyph "Zen Meditation" 120477 "ability_monk_zenmeditation"; │
│ + # minor │
│ + "90715" = mkGlyph "Blackout Kick" 132005 "ability_monk_blackoutkick"; │
│ + }; │
│ + ClassPaladin = { │
│ + # major │
│ + "41097" = mkGlyph "Templar's Verdict" 54926 "spell_paladin_templarsverdict"; │
│ + "41092" = mkGlyph "Double Jeopardy" 54922 "spell_holy_righteousfury"; │
│ + "83107" = mkGlyph "Mass Exorcism" 122028 "spell_holy_righteousfury"; │
│ + }; │
│ + ClassPriest = {}; │
│ + ClassRogue = { │
│ + # major │
│ + "45761" = mkGlyph "Vendetta" 63249 "ability_rogue_deadliness"; │
│ + "42970" = mkGlyph "Hemorrhaging Veins" 146631 "spell_holy_sealofsacrifice"; │
│ + }; │
│ + ClassShaman = { │
│ + # major │
│ + "41539" = mkGlyph "Spiritwalker's Grace" 55446 "spell_shaman_spiritwalkersgra │
│ ce"; │
│ + "71155" = mkGlyph "Lightning Shield" 101052 "spell_nature_lightningshield"; │
│ + "41529" = mkGlyph "Fire Elemental Totem" 55455 "spell_fire_elemental_totem"; │
│ + "41530" = mkGlyph "Fire Nova" 55450 "spell_shaman_firenova"; │
│ + }; │
│ + ClassWarlock = { │
│ + # major │
│ + "42472" = mkGlyph "Unstable Affliction" 56233 "spell_shadow_unstableafflictio │
│ n_3"; │
│ + "42470" = mkGlyph "Soulstone" 56231 "inv_misc_orb_04"; │
│ + "45785" = mkGlyph "Life Tap" 63320 "spell_shadow_burningspirit"; │
│ + "42465" = mkGlyph "Imp Swarm" 104316 "ability_warlock_impoweredimp"; │
│ + # minor │
│ + "43389" = mkGlyph "Unending Breath" 58079 "spell_shadow_demonbreath"; │
│ + }; │
│ + ClassWarrior = { │
│ + # major │
│ + "67482" = mkGlyph "Bull Rush" 94372 "achievement_character_tauren_male"; │
│ + "43399" = mkGlyph "Unending Rage" 58098 "ability_warrior_intensifyrage"; │
│ + "45792" = mkGlyph "Death From Above" 63325 "ability_heroicleap"; │
│ + }; │
│ +} │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/lib/database/glyphs.nix ────────┐
│ diff --git a/nix/lib/database/glyphs.nix b/n │
│ ix/lib/database/glyphs.nix │
│ new file mode 100644 │
│ index 0000000..3d24853 │
│ --- /dev/null │
│ +++ b/nix/lib/database/glyphs.nix │
│ @@ -0,0 +1,91 @@ │
│ +let │
│ + mkGlyph = name: spellId: icon: { │
│ + inherit spellId icon; │
│ + name = "Glyph of ${name}"; │
│ + }; │
│ +in { │
│ + # TODO: complete glyph list, currently on │
│ ly supporting those that exist in the curren │
│ t profiles │
│ + ClassDeathKnight = { │
│ + "43533" = mkGlyph "Anti-Magic Shell" 58 │
│ 623 "spell_shadow_antimagicshell"; │
│ + "43537" = mkGlyph "Chains of Ice" 58620 │
│ "spell_frost_chainsofice"; │
│ + "45800" = mkGlyph "Simulacrum" 63331 "s │
│ pell_holy_consumemagic"; │
│ + "104048" = mkGlyph "Regenerative Magic" │
│ 146648 "spell_shadow_antimagicshell"; │
│ + "104047" = mkGlyph "Loud Horn" 146646 " │
│ inv_misc_horn_04"; │
│ + "43548" = mkGlyph "Pestilence" 58657 "s │
│ pell_shadow_plaguecloud"; │
│ + "43554" = mkGlyph "Vampiric Blood" 5865 │
│ 7 "spell_shadow_lifedrain"; │
│ + "43550" = mkGlyph "Army of the Dead" 58 │
│ 669 "spell_deathknight_armyofthedead"; │
│ + "45806" = mkGlyph "Tranquil Grip" 63335 │
│ "ability_rogue_envelopingshadows"; │
│ + "43673" = mkGlyph "Death Gate" 60200 "s │
│ pell_arcane_teleportundercity"; │
│ + "43539" = mkGlyph "Death's Embrace" 586 │
│ 77 "spell_shadow_deathcoil"; │
│ + }; │
│ + ClassDruid = { │
│ + "40914" = mkGlyph "Healing Touch" 54825 │
│ "spell_nature_healingtouch"; │
│ + "40906" = mkGlyph "Stampede" 114300 "sp │
│ ell_druid_stampedingroar_cat"; │
│ + "40909" = mkGlyph "Rebirth" 54733 "spel │
│ l_nature_reincarnation"; │
│ + }; │
│ + ClassHunter = { │
│ + "42909" = mkGlyph "Animal Bond" 20895 " │
│ classic_ability_druid_demoralizingroar"; │
│ + "42903" = mkGlyph "Deterrence" 56850 "a │
│ bility_whirlwind"; │
│ + "42911" = mkGlyph "Pathfinding" 19560 " │
│ ability_hunter_pathfinding2"; │
│ + "42914" = mkGlyph "Aimed Shot" 126095 " │
│ inv_spear_07"; │
│ + "42899" = mkGlyph "Liberation" 132106 " │
│ achievement_bg_returnxflags_def_wsg"; │
│ + }; │
│ + ClassMage = { │
│ + # major │
│ + "44955" = mkGlyph "Arcane Power" 62210 │
│ "spell_nature_lightning"; │
│ + "42748" = mkGlyph "Rapid Displacement" │
│ 146659 "spell_arcane_blink"; │
│ + "42746" = mkGlyph "Cone of Cold" 115705 │
│ "spell_frost_glacier"; │
│ + "42739" = mkGlyph "Combustion" 56368 "s │
│ pell_fire_sealoffire"; │
│ + "63539" = mkGlyph "Inferno Blast" 89926 │
│ "spell_mage_infernoblast"; │
│ + "42745" = mkGlyph "Splitting Ice" 56377 │
│ "spell_frost_frostblast"; │
│ + "45736" = mkGlyph "Water Elemental" 630 │
│ 90 "spell_frost_summonwaterelemental_2"; │
│ + # minor │
│ + "42743" = mkGlyph "Momentum" 56384 "spe │
│ ll_arcane_blink"; │
│ + "63416" = mkGlyph "Rapid Teleportation" │
│ 46989 "spell_arcane_portaldalaran"; │
│ + "42735" = mkGlyph "Loose Mana" 56363 "i │
│ nv_misc_gem_sapphire_02"; │
│ + "104104" = mkGlyph "Unbound Elemental" │
│ 146976 "spell_frost_summonwaterelemental"; │
│ + "45739" = mkGlyph "Mirror Image" 45739 │
│ "spell_magic_lesserinvisibilty"; │
│ + }; │
│ + ClassMonk = { │
│ + # major │
│ + "85697" = mkGlyph "Spinning Crane Kick" │
│ 120479 "ability_monk_cranekick_new"; │
│ + "87900" = mkGlyph "Touch of Karma" 1256 │
│ 78 "ability_monk_touchofkarma"; │
│ + "85695" = mkGlyph "Zen Meditation" 1204 │
│ 77 "ability_monk_zenmeditation"; │
│ + # minor │
│ + "90715" = mkGlyph "Blackout Kick" 13200 │
│ 5 "ability_monk_blackoutkick"; │
│ + }; │
│ + ClassPaladin = { │
│ + # major │
│ + "41097" = mkGlyph "Templar's Verdict" 5 │
│ 4926 "spell_paladin_templarsverdict"; │
│ + "41092" = mkGlyph "Double Jeopardy" 549 │
│ 22 "spell_holy_righteousfury"; │
│ + "83107" = mkGlyph "Mass Exorcism" 12202 │
│ 8 "spell_holy_righteousfury"; │
│ + }; │
│ + ClassPriest = {}; │
│ + ClassRogue = { │
│ + # major │
│ + "45761" = mkGlyph "Vendetta" 63249 "abi │
│ lity_rogue_deadliness"; │
│ + "42970" = mkGlyph "Hemorrhaging Veins" │
│ 146631 "spell_holy_sealofsacrifice"; │
│ + }; │
│ + ClassShaman = { │
│ + # major │
│ + "41539" = mkGlyph "Spiritwalker's Grace │
│ " 55446 "spell_shaman_spiritwalkersgrace"; │
│ + "71155" = mkGlyph "Lightning Shield" 10 │
│ 1052 "spell_nature_lightningshield"; │
│ + "41529" = mkGlyph "Fire Elemental Totem │
│ " 55455 "spell_fire_elemental_totem"; │
│ + "41530" = mkGlyph "Fire Nova" 55450 "sp │
│ ell_shaman_firenova"; │
│ + }; │
│ + ClassWarlock = { │
│ + # major │
│ + "42472" = mkGlyph "Unstable Affliction" │
│ 56233 "spell_shadow_unstableaffliction_3"; │
│ + "42470" = mkGlyph "Soulstone" 56231 "in │
│ v_misc_orb_04"; │
│ + "45785" = mkGlyph "Life Tap" 63320 "spe │
│ ll_shadow_burningspirit"; │
│ + "42465" = mkGlyph "Imp Swarm" 104316 "a │
│ bility_warlock_impoweredimp"; │
│ + # minor │
│ + "43389" = mkGlyph "Unending Breath" 580 │
│ 79 "spell_shadow_demonbreath"; │
│ + }; │
│ + ClassWarrior = { │
│ + # major │
│ + "67482" = mkGlyph "Bull Rush" 94372 "ac │
│ hievement_character_tauren_male"; │
│ + "43399" = mkGlyph "Unending Rage" 58098 │
│ "ability_warrior_intensifyrage"; │
│ + "45792" = mkGlyph "Death From Above" 63 │
│ 325 "ability_heroicleap"; │
│ + }; │
│ +} │
└──────────────────────────────────────────────┘
┌─ nix/lib/database/talents.nix ─────────────────────────────────────────────┐
│ diff --git a/nix/lib/database/talents.nix b/nix/lib/database/talents.nix │
│ new file mode 100644 │
│ index 0000000..a3caff9 │
│ --- /dev/null │
│ +++ b/nix/lib/database/talents.nix │
│ @@ -0,0 +1,371 @@ │
│ +let │
│ + mkTalent = name: spellId: icon: { │
│ + inherit name spellId icon; │
│ + }; │
│ +in { │
│ + # talent string format: "123456" where each digit represents the choice (1-3) f │
│ or each tier (1-6) │
│ + │
│ + ClassDeathKnight = { │
│ + "1" = { │
│ + "1" = mkTalent "Roiling Blood" 108170 "ability_deathknight_roilingblood"; │
│ + "2" = mkTalent "Plague Leech" 123693 "ability_creature_disease_02"; │
│ + "3" = mkTalent "Unholy Blight" 115989 "spell_shadow_contagion"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Lichborne" 49039 "spell_shadow_raisedead"; │
│ + "2" = mkTalent "Anti-Magic Zone" 51052 "spell_deathknight_antimagiczone"; │
│ + "3" = mkTalent "Purgatory" 114556 "inv_misc_shadowegg"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Death's Advance" 96268 "spell_shadow_demonicempathy"; │
│ + "2" = mkTalent "Chilblains" 50041 "spell_frost_wisp"; │
│ + "3" = mkTalent "Asphyxiate" 108194 "ability_deathknight_asphixiate"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Death Pact" 48743 "spell_shadow_deathpact"; │
│ + "2" = mkTalent "Death Siphon" 108196 "ability_deathknight_deathsiphon"; │
│ + "3" = mkTalent "Conversion" 119975 "ability_deathknight_deathsiphon2"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Blood Tap" 45529 "spell_deathknight_bloodtap"; │
│ + "2" = mkTalent "Runic Empowerment" 81229 "inv_misc_rune_10"; │
│ + "3" = mkTalent "Runic Corruption" 51462 "spell_shadow_rune"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Gorefiend's Grasp" 108199 "ability_deathknight_aoedeathgrip │
│ "; │
│ + "2" = mkTalent "Remorseless Winter" 108200 "ability_deathknight_remorseless │
│ winters2"; │
│ + "3" = mkTalent "Desecrated Ground" 108201 "ability_deathknight_desecratedgr │
│ ound"; │
│ + }; │
│ + }; │
│ + │
│ + ClassDruid = { │
│ + "1" = { │
│ + "1" = mkTalent "Feline Swiftness" 131768 "spell_druid_tirelesspursuit"; │
│ + "2" = mkTalent "Displacer Best" 102280 "spell_druid_displacement"; │
│ + "3" = mkTalent "Wild Charge" 102401 "spell_druid_wildcharge"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Ysera's Gift" 145108 "inv_misc_head_dragon_green"; │
│ + "2" = mkTalent "Renewal" 108238 "spell_nature_natureblessing"; │
│ + "3" = mkTalent "Cenarion Ward" 102351 "ability_druid_naturalperfection"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Faerie Swarm" 106707 "spell_druid_swarm"; │
│ + "2" = mkTalent "Mass Entanglement" 102359 "spell_druid_massentanglement"; │
│ + "3" = mkTalent "Typhoon" 132469 "ability_druid_typhoon"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Soul of the Forest" 114107 "ability_druid_manatree"; │
│ + "2" = mkTalent "Incarnation" 106731 "spell_druid_incarnation"; │
│ + "3" = mkTalent "Force of Nature" 106737 "ability_druid_forceofnature"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Disorienting Roar" 99 "classic_ability_druid_demoralizingro │
│ ar"; │
│ + "2" = mkTalent "Ursol's Vortex" 102793 "spell_druid_ursolsvortex"; │
│ + "3" = mkTalent "Mighty Bash" 5211 "ability_druid_bash"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Heart of the Wild" 108288 "spell_holy_blessingofagility"; │
│ + "2" = mkTalent "Dream of Cenarius" 108373 "ability_druid_dreamstate"; │
│ + "3" = mkTalent "Nature's Vigil" 124974 "achievement_zone_feralas"; │
│ + }; │
│ + }; │
│ + │
│ + ClassHunter = { │
│ + "1" = { │
│ + "1" = mkTalent "Posthaste" 109215 "ability_hunter_posthaste"; │
│ + "2" = mkTalent "Narrow Escape" 109298 "inv_misc_web_01"; │
│ + "3" = mkTalent "Crouching Tiger, Hidden Chimera" 118675 "ability_hunter_pet │
│ _chimera"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Binding Shot" 109248 "spell_shaman_bindelemental"; │
│ + "2" = mkTalent "Wyvern Sting" 19386 "inv_spear_02"; │
│ + "3" = mkTalent "Intimidation" 19577 "ability_devour"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Exhilaration" 109304 "ability_hunter_onewithnature"; │
│ + "2" = mkTalent "Aspect of the Iron Hawk" 109260 "spell_hunter_aspectoftheir │
│ onhawk"; │
│ + "3" = mkTalent "Spirit Bond" 109212 "classic_ability_druid_demoralizingroar │
│ "; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Fervor" 82726 "ability_hunter_aspectoftheviper"; │
│ + "2" = mkTalent "Dire Beast" 120679 "ability_hunter_sickem"; │
│ + "3" = mkTalent "Thrill of the Hunt" 109306 "ability_hunter_thrillofthehunt" │
│ ; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "A Murder of Crows" 131894 "ability_hunter_murderofcrows"; │
│ + "2" = mkTalent "Blink Strikes" 130392 "spell_arcane_arcane04"; │
│ + "3" = mkTalent "Lynx Rush" 120697 "ability_hunter_catlikereflexes"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Glaive Toss" 117050 "ability_glaivetoss"; │
│ + "2" = mkTalent "Powershot" 109259 "ability_hunter_resistanceisfutile"; │
│ + "3" = mkTalent "Barrage" 120360 "ability_hunter_rapidregeneration"; │
│ + }; │
│ + }; │
│ + │
│ + ClassMage = { │
│ + "1" = { │
│ + "1" = mkTalent "Presence of Mind" 12043 "spell_nature_enchantarmor"; │
│ + "2" = mkTalent "Blazing Speed" 108843 "spell_fire_burningspeed"; │
│ + "3" = mkTalent "Ice Floes" 108839 "spell_mage_iceflows"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Temporal Shield" 115610 "spell_mage_temporalshield"; │
│ + "2" = mkTalent "Flameglow" 140468 "inv_elemental_primal_fire"; │
│ + "3" = mkTalent "Ice Barrier" 11426 "spell_ice_lament"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Ring of Frost" 113724 "spell_frost_ring-of-frost"; │
│ + "2" = mkTalent "Ice Ward" 111264 "spell_frost_frostward"; │
│ + "3" = mkTalent "Frostjaw" 102051 "ability_mage_frostjaw"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Greater Invisibility" 110959 "ability_mage_greaterinvisibil │
│ ity"; │
│ + "2" = mkTalent "Cauterize" 86949 "spell_fire_rune"; │
│ + "3" = mkTalent "Cold Snap" 11958 "spell_frost_wizardmark"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Nether Tempest" 114923 "spell_mage_nethertempest"; │
│ + "2" = mkTalent "Living Bomb" 44457 "ability_mage_livingbomb"; │
│ + "3" = mkTalent "Frost Bomb" 112948 "spell_mage_frostbomb"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Invocation" 114003 "spell_arcane_arcane03"; │
│ + "2" = mkTalent "Rune of Power" 116011 "spell_mage_runeofpower"; │
│ + "3" = mkTalent "Incanter's Ward" 1463 "spell_shadow_detectlesserinvisibilit │
│ y"; │
│ + }; │
│ + }; │
│ + │
│ + ClassMonk = { │
│ + "1" = { │
│ + "1" = mkTalent "Celerity" 115173 "ability_monk_quipunch"; │
│ + "2" = mkTalent "Tiger's Lust" 116841 "ability_monk_tigerslust"; │
│ + "3" = mkTalent "Momentum" 115174 "ability_monk_standingkick"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Chi Wave" 115098 "ability_monk_chiwave"; │
│ + "2" = mkTalent "Zen Sphere" 124081 "ability_monk_forcesphere"; │
│ + "3" = mkTalent "Chi Burst" 123986 "spell_arcane_arcanetorrent"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Power Strikes" 121817 "ability_monk_powerstrikes"; │
│ + "2" = mkTalent "Ascension" 115396 "ability_monk_ascension"; │
│ + "3" = mkTalent "Chi Brew" 115399 "ability_monk_chibrew"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Ring of Peace" 116844 "spell_monk_ringofpeace"; │
│ + "2" = mkTalent "Charging Ox Wave" 119392 "ability_monk_chargingoxwave"; │
│ + "3" = mkTalent "Leg Sweep" 119381 "ability_monk_legsweep"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Healing Elixirs" 122280 "ability_monk_jasmineforcetea"; │
│ + "2" = mkTalent "Dampen Harm" 122278 "ability_monk_dampenharm"; │
│ + "3" = mkTalent "Diffuse Magic" 122783 "spell_monk_diffusemagic"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Rushing Jade Wind" 116847 "ability_monk_rushingjadewind"; │
│ + "2" = mkTalent "Invoke Xuen, the White Tiger" 123904 "ability_monk_summonti │
│ gerstatue"; │
│ + "3" = mkTalent "Chi Torpedo" 115008 "ability_monk_quitornado"; │
│ + }; │
│ + }; │
│ + │
│ + ClassPaladin = { │
│ + "1" = { │
│ + "1" = mkTalent "Speed of Light" 85499 "ability_paladin_speedoflight"; │
│ + "2" = mkTalent "Long Arm of the Law" 87172 "ability_paladin_longarmofthelaw │
│ "; │
│ + "3" = mkTalent "Pursuit of Justice" 26023 "ability_paladin_veneration"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Fist of Justice" 105593 "spell_holy_fistofjustice"; │
│ + "2" = mkTalent "Repentance" 20066 "spell_holy_prayerofhealing"; │
│ + "3" = mkTalent "Evil is a Point of View" 110301 "ability_paladin_turnevil"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Selfless Healer" 85804 "ability_paladin_gaurdedbythelight"; │
│ + "2" = mkTalent "Eternal Flame" 114163 "inv_torch_thrown"; │
│ + "3" = mkTalent "Sacred Shield" 20925 "ability_paladin_blessedmending"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Hand of Purity" 114039 "spell_holy_sealofwisdom"; │
│ + "2" = mkTalent "Unbreakable Spirit" 114154 "spell_holy_unyieldingfaith"; │
│ + "3" = mkTalent "Clemency" 105622 "ability_paladin_clemency"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Holy Avenger" 105809 "ability_paladin_holyavenger"; │
│ + "2" = mkTalent "Sanctified Wrath" 53376 "ability_paladin_sanctifiedwrath"; │
│ + "3" = mkTalent "Divine Purpose" 86172 "spell_holy_divinepurpose"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Holy Prism" 114165 "spell_paladin_holyprism"; │
│ + "2" = mkTalent "Light's Hammer" 114158 "spell_paladin_lightshammer"; │
│ + "3" = mkTalent "Execution Sentence" 114157 "spell_paladin_executionsentence │
│ "; │
│ + }; │
│ + }; │
│ + │
│ + ClassPriest = { │
│ + "1" = { │
│ + "1" = mkTalent "Void Tendrils" 108920 "spell_priest_voidtendrils"; │
│ + "2" = mkTalent "Psyfiend" 108921 "spell_priest_psyfiend"; │
│ + "3" = mkTalent "Dominate Mind" 605 "spell_shadow_shadowworddominate"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Body and Soul" 64129 "spell_holy_symbolofhope"; │
│ + "2" = mkTalent "Angelic Feather" 121536 "ability_priest_angelicfeather"; │
│ + "3" = mkTalent "Phantasm" 108942 "ability_priest_phantasm"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "From Darkness, Comes Light" 109186 "spell_holy_surgeoflight │
│ "; │
│ + "2" = mkTalent "Mindbender" 123040 "spell_shadow_soulleech_3"; │
│ + "3" = mkTalent "Solace and Insanity" 139139 "ability_priest_flashoflight"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Desperate Prayer" 19236 "spell_holy_testoffaith"; │
│ + "2" = mkTalent "Spectral Guise" 112833 "spell_priest_spectralguise"; │
│ + "3" = mkTalent "Angelic Bulwark" 108945 "ability_priest_angelicbulwark"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Twist of Fate" 109142 "spell_shadow_mindtwisting"; │
│ + "2" = mkTalent "Power Infusion" 10060 "spell_holy_powerinfusion"; │
│ + "3" = mkTalent "Divine Insight" 109175 "spell_priest_burningwill"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Cascade" 121135 "ability_priest_cascade"; │
│ + "2" = mkTalent "Divine Star" 110744 "spell_priest_divinestar"; │
│ + "3" = mkTalent "Halo" 120517 "ability_priest_halo"; │
│ + }; │
│ + }; │
│ + │
│ + ClassRogue = { │
│ + "1" = { │
│ + "1" = mkTalent "Nightstalker" 14062 "ability_stealth"; │
│ + "2" = mkTalent "Subterfuge" 108208 "rogue_subterfuge"; │
│ + "3" = mkTalent "Shadow Focus" 108209 "rogue_shadowfocus"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Deadly Throw" 26679 "inv_throwingknife_06"; │
│ + "2" = mkTalent "Nerve Strike" 108210 "rogue_nerve-_strike"; │
│ + "3" = mkTalent "Combat Readiness" 74001 "ability_rogue_combatreadiness"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Cheat Death" 31230 "ability_rogue_cheatdeath"; │
│ + "2" = mkTalent "Leeching Poison" 108211 "rogue_leeching_poison"; │
│ + "3" = mkTalent "Elusiveness" 79008 "ability_rogue_turnthetables"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Cloak and Dagger" 138106 "ability_rogue_unfairadvantage"; │
│ + "2" = mkTalent "Shadowstep" 36554 "ability_rogue_shadowstep"; │
│ + "3" = mkTalent "Burst of Speed" 108212 "rogue_burstofspeed"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Prey on the Weak" 131511 "ability_rogue_preyontheweak"; │
│ + "2" = mkTalent "Paralytic Poison" 108215 "rogue_paralytic_poison"; │
│ + "3" = mkTalent "Dirty Tricks" 108216 "ability_rogue_dirtydeeds"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Shuriken Toss" 114014 "inv_throwingknife_07"; │
│ + "2" = mkTalent "Marked for Death" 137619 "achievement_bg_killingblow_berser │
│ ker"; │
│ + "3" = mkTalent "Anticipation" 114015 "ability_rogue_slaughterfromtheshadows │
│ "; │
│ + }; │
│ + }; │
│ + │
│ + ClassShaman = { │
│ + "1" = { │
│ + "1" = mkTalent "Nature's Guardian" 30884 "spell_nature_natureguardian"; │
│ + "2" = mkTalent "Stone Bulwark Totem" 108270 "ability_shaman_stonebulwark"; │
│ + "3" = mkTalent "Astral Shift" 108271 "ability_shaman_astralshift"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Frozen Power" 63374 "spell_fire_bluecano"; │
│ + "2" = mkTalent "Earthgrab Totem" 51485 "spell_nature_stranglevines"; │
│ + "3" = mkTalent "Windwalk Totem" 108273 "ability_shaman_windwalktotem"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Call of the Elements" 108285 "ability_shaman_multitotemacti │
│ vation"; │
│ + "2" = mkTalent "Totemic Persistence" 108284 "ability_shaman_totemcooldownre │
│ fund"; │
│ + "3" = mkTalent "Totemic Projection" 108287 "ability_shaman_totemrelocation" │
│ ; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Elemental Mastery" 16166 "spell_nature_wispheal"; │
│ + "2" = mkTalent "Ancestral Swiftness" 16188 "spell_shaman_elementaloath"; │
│ + "3" = mkTalent "Echo of the Elements" 108283 "ability_shaman_echooftheeleme │
│ nts"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Rushing Streams" 147074 "inv_spear_04"; │
│ + "2" = mkTalent "Ancestral Guidance" 108281 "ability_shaman_ancestralguidanc │
│ e"; │
│ + "3" = mkTalent "Conductivity" 108282 "ability_shaman_fortifyingwaters"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Unleashed Fury" 117012 "shaman_talent_unleashedfury"; │
│ + "2" = mkTalent "Primal Elementalist" 117013 "shaman_talent_primalelementali │
│ st"; │
│ + "3" = mkTalent "Elemental Blast" 117014 "shaman_talent_elementalblast"; │
│ + }; │
│ + }; │
│ + │
│ + ClassWarlock = { │
│ + "1" = { │
│ + "1" = mkTalent "Dark Regeneration" 108359 "spell_warlock_darkregeneration"; │
│ + "2" = mkTalent "Soul Leech" 108370 "warlock_siphonlife"; │
│ + "3" = mkTalent "Harvest Life" 108371 "spell_warlock_harvestoflife"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Demonic Breath" 47897 "ability_warlock_shadowflame"; │
│ + "2" = mkTalent "Mortal Coil" 6789 "ability_warlock_mortalcoil"; │
│ + "3" = mkTalent "Shadowfury" 30283 "ability_warlock_shadowfurytga"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Soul Link" 108415 "ability_warlock_soullink"; │
│ + "2" = mkTalent "Sacrificial Pact" 108416 "warlock_sacrificial_pact"; │
│ + "3" = mkTalent "Dark Bargain" 110913 "ability_deathwing_bloodcorruption_dea │
│ th"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Blood Horror" 111397 "ability_deathwing_bloodcorruption_ear │
│ th"; │
│ + "2" = mkTalent "Burning Rush" 111400 "ability_deathwing_sealarmorbreachtga" │
│ ; │
│ + "3" = mkTalent "Unbound Will" 108482 "warlock_spelldrain"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Grimoire of Supremacy" 108499 "warlock_grimoireofcommand"; │
│ + "2" = mkTalent "Grimoire of Service" 108501 "warlock_grimoireofservice"; │
│ + "3" = mkTalent "Grimoire of Sacrifice" 108503 "warlock_grimoireofsacrifice" │
│ ; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Archimonde's Darkness" 108505 "achievement_boss_archimonde- │
│ "; │
│ + "2" = mkTalent "Kil'jaeden's Cunning" 137587 "achievement_boss_kiljaedan"; │
│ + "3" = mkTalent "Mannoroth's Fury" 108508 "achievement_boss_magtheridon"; │
│ + }; │
│ + }; │
│ + │
│ + ClassWarrior = { │
│ + "1" = { │
│ + "1" = mkTalent "Juggernaut" 103826 "ability_warrior_bullrush"; │
│ + "2" = mkTalent "Double Time" 103827 "inv_misc_horn_04"; │
│ + "3" = mkTalent "Warbringer" 103828 "ability_warrior_warbringer"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Enraged Regeneration" 55694 "ability_warrior_focusedrage"; │
│ + "2" = mkTalent "Second Wind" 29838 "ability_hunter_harass"; │
│ + "3" = mkTalent "Impending Victory" 103840 "spell_impending_victory"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Staggering Shout" 107566 "ability_bullrush"; │
│ + "2" = mkTalent "Piercing Howl" 12323 "spell_shadow_deathscream"; │
│ + "3" = mkTalent "Disrupting Shout" 102060 "warrior_disruptingshout"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Bladestorm" 46924 "ability_warrior_bladestorm"; │
│ + "2" = mkTalent "Shockwave" 46968 "ability_warrior_shockwave"; │
│ + "3" = mkTalent "Dragon Roar" 118000 "ability_warrior_dragonroar"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Mass Spell Reflection" 114028 "ability_warrior_shieldbreak" │
│ ; │
│ + "2" = mkTalent "Safeguard" 114029 "ability_warrior_safeguard"; │
│ + "3" = mkTalent "Vigilance" 114030 "ability_warrior_vigilance"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Avatar" 107574 "warrior_talent_icon_avatar"; │
│ + "2" = mkTalent "Bloodbath" 12292 "ability_warrior_bloodbath"; │
│ + "3" = mkTalent "Storm Bolt" 107570 "warrior_talent_icon_stormbolt"; │
│ + }; │
│ + }; │
│ +} │
│ + │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/lib/database/talents.nix ───────┐
│ diff --git a/nix/lib/database/talents.nix b/ │
│ nix/lib/database/talents.nix │
│ new file mode 100644 │
│ index 0000000..a3caff9 │
│ --- /dev/null │
│ +++ b/nix/lib/database/talents.nix │
│ @@ -0,0 +1,371 @@ │
│ +let │
│ + mkTalent = name: spellId: icon: { │
│ + inherit name spellId icon; │
│ + }; │
│ +in { │
│ + # talent string format: "123456" where ea │
│ ch digit represents the choice (1-3) for eac │
│ h tier (1-6) │
│ + │
│ + ClassDeathKnight = { │
│ + "1" = { │
│ + "1" = mkTalent "Roiling Blood" 108170 │
│ "ability_deathknight_roilingblood"; │
│ + "2" = mkTalent "Plague Leech" 123693 │
│ "ability_creature_disease_02"; │
│ + "3" = mkTalent "Unholy Blight" 115989 │
│ "spell_shadow_contagion"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Lichborne" 49039 "spe │
│ ll_shadow_raisedead"; │
│ + "2" = mkTalent "Anti-Magic Zone" 5105 │
│ 2 "spell_deathknight_antimagiczone"; │
│ + "3" = mkTalent "Purgatory" 114556 "in │
│ v_misc_shadowegg"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Death's Advance" 9626 │
│ 8 "spell_shadow_demonicempathy"; │
│ + "2" = mkTalent "Chilblains" 50041 "sp │
│ ell_frost_wisp"; │
│ + "3" = mkTalent "Asphyxiate" 108194 "a │
│ bility_deathknight_asphixiate"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Death Pact" 48743 "sp │
│ ell_shadow_deathpact"; │
│ + "2" = mkTalent "Death Siphon" 108196 │
│ "ability_deathknight_deathsiphon"; │
│ + "3" = mkTalent "Conversion" 119975 "a │
│ bility_deathknight_deathsiphon2"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Blood Tap" 45529 "spe │
│ ll_deathknight_bloodtap"; │
│ + "2" = mkTalent "Runic Empowerment" 81 │
│ 229 "inv_misc_rune_10"; │
│ + "3" = mkTalent "Runic Corruption" 514 │
│ 62 "spell_shadow_rune"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Gorefiend's Grasp" 10 │
│ 8199 "ability_deathknight_aoedeathgrip"; │
│ + "2" = mkTalent "Remorseless Winter" 1 │
│ 08200 "ability_deathknight_remorselesswinter │
│ s2"; │
│ + "3" = mkTalent "Desecrated Ground" 10 │
│ 8201 "ability_deathknight_desecratedground"; │
│ + }; │
│ + }; │
│ + │
│ + ClassDruid = { │
│ + "1" = { │
│ + "1" = mkTalent "Feline Swiftness" 131 │
│ 768 "spell_druid_tirelesspursuit"; │
│ + "2" = mkTalent "Displacer Best" 10228 │
│ 0 "spell_druid_displacement"; │
│ + "3" = mkTalent "Wild Charge" 102401 " │
│ spell_druid_wildcharge"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Ysera's Gift" 145108 │
│ "inv_misc_head_dragon_green"; │
│ + "2" = mkTalent "Renewal" 108238 "spel │
│ l_nature_natureblessing"; │
│ + "3" = mkTalent "Cenarion Ward" 102351 │
│ "ability_druid_naturalperfection"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Faerie Swarm" 106707 │
│ "spell_druid_swarm"; │
│ + "2" = mkTalent "Mass Entanglement" 10 │
│ 2359 "spell_druid_massentanglement"; │
│ + "3" = mkTalent "Typhoon" 132469 "abil │
│ ity_druid_typhoon"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Soul of the Forest" 1 │
│ 14107 "ability_druid_manatree"; │
│ + "2" = mkTalent "Incarnation" 106731 " │
│ spell_druid_incarnation"; │
│ + "3" = mkTalent "Force of Nature" 1067 │
│ 37 "ability_druid_forceofnature"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Disorienting Roar" 99 │
│ "classic_ability_druid_demoralizingroar"; │
│ + "2" = mkTalent "Ursol's Vortex" 10279 │
│ 3 "spell_druid_ursolsvortex"; │
│ + "3" = mkTalent "Mighty Bash" 5211 "ab │
│ ility_druid_bash"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Heart of the Wild" 10 │
│ 8288 "spell_holy_blessingofagility"; │
│ + "2" = mkTalent "Dream of Cenarius" 10 │
│ 8373 "ability_druid_dreamstate"; │
│ + "3" = mkTalent "Nature's Vigil" 12497 │
│ 4 "achievement_zone_feralas"; │
│ + }; │
│ + }; │
│ + │
│ + ClassHunter = { │
│ + "1" = { │
│ + "1" = mkTalent "Posthaste" 109215 "ab │
│ ility_hunter_posthaste"; │
│ + "2" = mkTalent "Narrow Escape" 109298 │
│ "inv_misc_web_01"; │
│ + "3" = mkTalent "Crouching Tiger, Hidd │
│ en Chimera" 118675 "ability_hunter_pet_chime │
│ ra"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Binding Shot" 109248 │
│ "spell_shaman_bindelemental"; │
│ + "2" = mkTalent "Wyvern Sting" 19386 " │
│ inv_spear_02"; │
│ + "3" = mkTalent "Intimidation" 19577 " │
│ ability_devour"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Exhilaration" 109304 │
│ "ability_hunter_onewithnature"; │
│ + "2" = mkTalent "Aspect of the Iron Ha │
│ wk" 109260 "spell_hunter_aspectoftheironhawk │
│ "; │
│ + "3" = mkTalent "Spirit Bond" 109212 " │
│ classic_ability_druid_demoralizingroar"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Fervor" 82726 "abilit │
│ y_hunter_aspectoftheviper"; │
│ + "2" = mkTalent "Dire Beast" 120679 "a │
│ bility_hunter_sickem"; │
│ + "3" = mkTalent "Thrill of the Hunt" 1 │
│ 09306 "ability_hunter_thrillofthehunt"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "A Murder of Crows" 13 │
│ 1894 "ability_hunter_murderofcrows"; │
│ + "2" = mkTalent "Blink Strikes" 130392 │
│ "spell_arcane_arcane04"; │
│ + "3" = mkTalent "Lynx Rush" 120697 "ab │
│ ility_hunter_catlikereflexes"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Glaive Toss" 117050 " │
│ ability_glaivetoss"; │
│ + "2" = mkTalent "Powershot" 109259 "ab │
│ ility_hunter_resistanceisfutile"; │
│ + "3" = mkTalent "Barrage" 120360 "abil │
│ ity_hunter_rapidregeneration"; │
│ + }; │
│ + }; │
│ + │
│ + ClassMage = { │
│ + "1" = { │
│ + "1" = mkTalent "Presence of Mind" 120 │
│ 43 "spell_nature_enchantarmor"; │
│ + "2" = mkTalent "Blazing Speed" 108843 │
│ "spell_fire_burningspeed"; │
│ + "3" = mkTalent "Ice Floes" 108839 "sp │
│ ell_mage_iceflows"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Temporal Shield" 1156 │
│ 10 "spell_mage_temporalshield"; │
│ + "2" = mkTalent "Flameglow" 140468 "in │
│ v_elemental_primal_fire"; │
│ + "3" = mkTalent "Ice Barrier" 11426 "s │
│ pell_ice_lament"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Ring of Frost" 113724 │
│ "spell_frost_ring-of-frost"; │
│ + "2" = mkTalent "Ice Ward" 111264 "spe │
│ ll_frost_frostward"; │
│ + "3" = mkTalent "Frostjaw" 102051 "abi │
│ lity_mage_frostjaw"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Greater Invisibility" │
│ 110959 "ability_mage_greaterinvisibility"; │
│ + "2" = mkTalent "Cauterize" 86949 "spe │
│ ll_fire_rune"; │
│ + "3" = mkTalent "Cold Snap" 11958 "spe │
│ ll_frost_wizardmark"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Nether Tempest" 11492 │
│ 3 "spell_mage_nethertempest"; │
│ + "2" = mkTalent "Living Bomb" 44457 "a │
│ bility_mage_livingbomb"; │
│ + "3" = mkTalent "Frost Bomb" 112948 "s │
│ pell_mage_frostbomb"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Invocation" 114003 "s │
│ pell_arcane_arcane03"; │
│ + "2" = mkTalent "Rune of Power" 116011 │
│ "spell_mage_runeofpower"; │
│ + "3" = mkTalent "Incanter's Ward" 1463 │
│ "spell_shadow_detectlesserinvisibility"; │
│ + }; │
│ + }; │
│ + │
│ + ClassMonk = { │
│ + "1" = { │
│ + "1" = mkTalent "Celerity" 115173 "abi │
│ lity_monk_quipunch"; │
│ + "2" = mkTalent "Tiger's Lust" 116841 │
│ "ability_monk_tigerslust"; │
│ + "3" = mkTalent "Momentum" 115174 "abi │
│ lity_monk_standingkick"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Chi Wave" 115098 "abi │
│ lity_monk_chiwave"; │
│ + "2" = mkTalent "Zen Sphere" 124081 "a │
│ bility_monk_forcesphere"; │
│ + "3" = mkTalent "Chi Burst" 123986 "sp │
│ ell_arcane_arcanetorrent"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Power Strikes" 121817 │
│ "ability_monk_powerstrikes"; │
│ + "2" = mkTalent "Ascension" 115396 "ab │
│ ility_monk_ascension"; │
│ + "3" = mkTalent "Chi Brew" 115399 "abi │
│ lity_monk_chibrew"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Ring of Peace" 116844 │
│ "spell_monk_ringofpeace"; │
│ + "2" = mkTalent "Charging Ox Wave" 119 │
│ 392 "ability_monk_chargingoxwave"; │
│ + "3" = mkTalent "Leg Sweep" 119381 "ab │
│ ility_monk_legsweep"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Healing Elixirs" 1222 │
│ 80 "ability_monk_jasmineforcetea"; │
│ + "2" = mkTalent "Dampen Harm" 122278 " │
│ ability_monk_dampenharm"; │
│ + "3" = mkTalent "Diffuse Magic" 122783 │
│ "spell_monk_diffusemagic"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Rushing Jade Wind" 11 │
│ 6847 "ability_monk_rushingjadewind"; │
│ + "2" = mkTalent "Invoke Xuen, the Whit │
│ e Tiger" 123904 "ability_monk_summontigersta │
│ tue"; │
│ + "3" = mkTalent "Chi Torpedo" 115008 " │
│ ability_monk_quitornado"; │
│ + }; │
│ + }; │
│ + │
│ + ClassPaladin = { │
│ + "1" = { │
│ + "1" = mkTalent "Speed of Light" 85499 │
│ "ability_paladin_speedoflight"; │
│ + "2" = mkTalent "Long Arm of the Law" │
│ 87172 "ability_paladin_longarmofthelaw"; │
│ + "3" = mkTalent "Pursuit of Justice" 2 │
│ 6023 "ability_paladin_veneration"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Fist of Justice" 1055 │
│ 93 "spell_holy_fistofjustice"; │
│ + "2" = mkTalent "Repentance" 20066 "sp │
│ ell_holy_prayerofhealing"; │
│ + "3" = mkTalent "Evil is a Point of Vi │
│ ew" 110301 "ability_paladin_turnevil"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Selfless Healer" 8580 │
│ 4 "ability_paladin_gaurdedbythelight"; │
│ + "2" = mkTalent "Eternal Flame" 114163 │
│ "inv_torch_thrown"; │
│ + "3" = mkTalent "Sacred Shield" 20925 │
│ "ability_paladin_blessedmending"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Hand of Purity" 11403 │
│ 9 "spell_holy_sealofwisdom"; │
│ + "2" = mkTalent "Unbreakable Spirit" 1 │
│ 14154 "spell_holy_unyieldingfaith"; │
│ + "3" = mkTalent "Clemency" 105622 "abi │
│ lity_paladin_clemency"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Holy Avenger" 105809 │
│ "ability_paladin_holyavenger"; │
│ + "2" = mkTalent "Sanctified Wrath" 533 │
│ 76 "ability_paladin_sanctifiedwrath"; │
│ + "3" = mkTalent "Divine Purpose" 86172 │
│ "spell_holy_divinepurpose"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Holy Prism" 114165 "s │
│ pell_paladin_holyprism"; │
│ + "2" = mkTalent "Light's Hammer" 11415 │
│ 8 "spell_paladin_lightshammer"; │
│ + "3" = mkTalent "Execution Sentence" 1 │
│ 14157 "spell_paladin_executionsentence"; │
│ + }; │
│ + }; │
│ + │
│ + ClassPriest = { │
│ + "1" = { │
│ + "1" = mkTalent "Void Tendrils" 108920 │
│ "spell_priest_voidtendrils"; │
│ + "2" = mkTalent "Psyfiend" 108921 "spe │
│ ll_priest_psyfiend"; │
│ + "3" = mkTalent "Dominate Mind" 605 "s │
│ pell_shadow_shadowworddominate"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Body and Soul" 64129 │
│ "spell_holy_symbolofhope"; │
│ + "2" = mkTalent "Angelic Feather" 1215 │
│ 36 "ability_priest_angelicfeather"; │
│ + "3" = mkTalent "Phantasm" 108942 "abi │
│ lity_priest_phantasm"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "From Darkness, Comes │
│ Light" 109186 "spell_holy_surgeoflight"; │
│ + "2" = mkTalent "Mindbender" 123040 "s │
│ pell_shadow_soulleech_3"; │
│ + "3" = mkTalent "Solace and Insanity" │
│ 139139 "ability_priest_flashoflight"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Desperate Prayer" 192 │
│ 36 "spell_holy_testoffaith"; │
│ + "2" = mkTalent "Spectral Guise" 11283 │
│ 3 "spell_priest_spectralguise"; │
│ + "3" = mkTalent "Angelic Bulwark" 1089 │
│ 45 "ability_priest_angelicbulwark"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Twist of Fate" 109142 │
│ "spell_shadow_mindtwisting"; │
│ + "2" = mkTalent "Power Infusion" 10060 │
│ "spell_holy_powerinfusion"; │
│ + "3" = mkTalent "Divine Insight" 10917 │
│ 5 "spell_priest_burningwill"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Cascade" 121135 "abil │
│ ity_priest_cascade"; │
│ + "2" = mkTalent "Divine Star" 110744 " │
│ spell_priest_divinestar"; │
│ + "3" = mkTalent "Halo" 120517 "ability │
│ _priest_halo"; │
│ + }; │
│ + }; │
│ + │
│ + ClassRogue = { │
│ + "1" = { │
│ + "1" = mkTalent "Nightstalker" 14062 " │
│ ability_stealth"; │
│ + "2" = mkTalent "Subterfuge" 108208 "r │
│ ogue_subterfuge"; │
│ + "3" = mkTalent "Shadow Focus" 108209 │
│ "rogue_shadowfocus"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Deadly Throw" 26679 " │
│ inv_throwingknife_06"; │
│ + "2" = mkTalent "Nerve Strike" 108210 │
│ "rogue_nerve-_strike"; │
│ + "3" = mkTalent "Combat Readiness" 740 │
│ 01 "ability_rogue_combatreadiness"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Cheat Death" 31230 "a │
│ bility_rogue_cheatdeath"; │
│ + "2" = mkTalent "Leeching Poison" 1082 │
│ 11 "rogue_leeching_poison"; │
│ + "3" = mkTalent "Elusiveness" 79008 "a │
│ bility_rogue_turnthetables"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Cloak and Dagger" 138 │
│ 106 "ability_rogue_unfairadvantage"; │
│ + "2" = mkTalent "Shadowstep" 36554 "ab │
│ ility_rogue_shadowstep"; │
│ + "3" = mkTalent "Burst of Speed" 10821 │
│ 2 "rogue_burstofspeed"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Prey on the Weak" 131 │
│ 511 "ability_rogue_preyontheweak"; │
│ + "2" = mkTalent "Paralytic Poison" 108 │
│ 215 "rogue_paralytic_poison"; │
│ + "3" = mkTalent "Dirty Tricks" 108216 │
│ "ability_rogue_dirtydeeds"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Shuriken Toss" 114014 │
│ "inv_throwingknife_07"; │
│ + "2" = mkTalent "Marked for Death" 137 │
│ 619 "achievement_bg_killingblow_berserker"; │
│ + "3" = mkTalent "Anticipation" 114015 │
│ "ability_rogue_slaughterfromtheshadows"; │
│ + }; │
│ + }; │
│ + │
│ + ClassShaman = { │
│ + "1" = { │
│ + "1" = mkTalent "Nature's Guardian" 30 │
│ 884 "spell_nature_natureguardian"; │
│ + "2" = mkTalent "Stone Bulwark Totem" │
│ 108270 "ability_shaman_stonebulwark"; │
│ + "3" = mkTalent "Astral Shift" 108271 │
│ "ability_shaman_astralshift"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Frozen Power" 63374 " │
│ spell_fire_bluecano"; │
│ + "2" = mkTalent "Earthgrab Totem" 5148 │
│ 5 "spell_nature_stranglevines"; │
│ + "3" = mkTalent "Windwalk Totem" 10827 │
│ 3 "ability_shaman_windwalktotem"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Call of the Elements" │
│ 108285 "ability_shaman_multitotemactivation │
│ "; │
│ + "2" = mkTalent "Totemic Persistence" │
│ 108284 "ability_shaman_totemcooldownrefund"; │
│ + "3" = mkTalent "Totemic Projection" 1 │
│ 08287 "ability_shaman_totemrelocation"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Elemental Mastery" 16 │
│ 166 "spell_nature_wispheal"; │
│ + "2" = mkTalent "Ancestral Swiftness" │
│ 16188 "spell_shaman_elementaloath"; │
│ + "3" = mkTalent "Echo of the Elements" │
│ 108283 "ability_shaman_echooftheelements"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Rushing Streams" 1470 │
│ 74 "inv_spear_04"; │
│ + "2" = mkTalent "Ancestral Guidance" 1 │
│ 08281 "ability_shaman_ancestralguidance"; │
│ + "3" = mkTalent "Conductivity" 108282 │
│ "ability_shaman_fortifyingwaters"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Unleashed Fury" 11701 │
│ 2 "shaman_talent_unleashedfury"; │
│ + "2" = mkTalent "Primal Elementalist" │
│ 117013 "shaman_talent_primalelementalist"; │
│ + "3" = mkTalent "Elemental Blast" 1170 │
│ 14 "shaman_talent_elementalblast"; │
│ + }; │
│ + }; │
│ + │
│ + ClassWarlock = { │
│ + "1" = { │
│ + "1" = mkTalent "Dark Regeneration" 10 │
│ 8359 "spell_warlock_darkregeneration"; │
│ + "2" = mkTalent "Soul Leech" 108370 "w │
│ arlock_siphonlife"; │
│ + "3" = mkTalent "Harvest Life" 108371 │
│ "spell_warlock_harvestoflife"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Demonic Breath" 47897 │
│ "ability_warlock_shadowflame"; │
│ + "2" = mkTalent "Mortal Coil" 6789 "ab │
│ ility_warlock_mortalcoil"; │
│ + "3" = mkTalent "Shadowfury" 30283 "ab │
│ ility_warlock_shadowfurytga"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Soul Link" 108415 "ab │
│ ility_warlock_soullink"; │
│ + "2" = mkTalent "Sacrificial Pact" 108 │
│ 416 "warlock_sacrificial_pact"; │
│ + "3" = mkTalent "Dark Bargain" 110913 │
│ "ability_deathwing_bloodcorruption_death"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Blood Horror" 111397 │
│ "ability_deathwing_bloodcorruption_earth"; │
│ + "2" = mkTalent "Burning Rush" 111400 │
│ "ability_deathwing_sealarmorbreachtga"; │
│ + "3" = mkTalent "Unbound Will" 108482 │
│ "warlock_spelldrain"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Grimoire of Supremacy │
│ " 108499 "warlock_grimoireofcommand"; │
│ + "2" = mkTalent "Grimoire of Service" │
│ 108501 "warlock_grimoireofservice"; │
│ + "3" = mkTalent "Grimoire of Sacrifice │
│ " 108503 "warlock_grimoireofsacrifice"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Archimonde's Darkness │
│ " 108505 "achievement_boss_archimonde-"; │
│ + "2" = mkTalent "Kil'jaeden's Cunning" │
│ 137587 "achievement_boss_kiljaedan"; │
│ + "3" = mkTalent "Mannoroth's Fury" 108 │
│ 508 "achievement_boss_magtheridon"; │
│ + }; │
│ + }; │
│ + │
│ + ClassWarrior = { │
│ + "1" = { │
│ + "1" = mkTalent "Juggernaut" 103826 "a │
│ bility_warrior_bullrush"; │
│ + "2" = mkTalent "Double Time" 103827 " │
│ inv_misc_horn_04"; │
│ + "3" = mkTalent "Warbringer" 103828 "a │
│ bility_warrior_warbringer"; │
│ + }; │
│ + "2" = { │
│ + "1" = mkTalent "Enraged Regeneration" │
│ 55694 "ability_warrior_focusedrage"; │
│ + "2" = mkTalent "Second Wind" 29838 "a │
│ bility_hunter_harass"; │
│ + "3" = mkTalent "Impending Victory" 10 │
│ 3840 "spell_impending_victory"; │
│ + }; │
│ + "3" = { │
│ + "1" = mkTalent "Staggering Shout" 107 │
│ 566 "ability_bullrush"; │
│ + "2" = mkTalent "Piercing Howl" 12323 │
│ "spell_shadow_deathscream"; │
│ + "3" = mkTalent "Disrupting Shout" 102 │
│ 060 "warrior_disruptingshout"; │
│ + }; │
│ + "4" = { │
│ + "1" = mkTalent "Bladestorm" 46924 "ab │
│ ility_warrior_bladestorm"; │
│ + "2" = mkTalent "Shockwave" 46968 "abi │
│ lity_warrior_shockwave"; │
│ + "3" = mkTalent "Dragon Roar" 118000 " │
│ ability_warrior_dragonroar"; │
│ + }; │
│ + "5" = { │
│ + "1" = mkTalent "Mass Spell Reflection │
│ " 114028 "ability_warrior_shieldbreak"; │
│ + "2" = mkTalent "Safeguard" 114029 "ab │
│ ility_warrior_safeguard"; │
│ + "3" = mkTalent "Vigilance" 114030 "ab │
│ ility_warrior_vigilance"; │
│ + }; │
│ + "6" = { │
│ + "1" = mkTalent "Avatar" 107574 "warri │
│ or_talent_icon_avatar"; │
│ + "2" = mkTalent "Bloodbath" 12292 "abi │
│ lity_warrior_bloodbath"; │
│ + "3" = mkTalent "Storm Bolt" 107570 "w │
│ arrior_talent_icon_stormbolt"; │
│ + }; │
│ + }; │
│ +} │
│ + │
└──────────────────────────────────────────────┘
┌─ nix/lib/itemDatabase.nix ─────────────────────────────────────────────────┐
│ diff --git a/nix/lib/itemDatabase.nix b/nix/lib/itemDatabase.nix │
│ index b0b9b4f..d00438e 100644 │
│ --- a/nix/lib/itemDatabase.nix │
│ +++ b/nix/lib/itemDatabase.nix │
│ @@ -4,6 +4,8 @@ │
│ ... │
│ }: let │
│ wowsimsDb = lib.importJSON "${inputs.wowsims}/assets/database/db.json"; │
│ + glyphDb = import ./database/glyphs.nix; │
│ + talentDb = import ./database/talents.nix; │
│ │
│ itemsById = lib.listToAttrs (map (item: { │
│ name = toString item.id; │
│ @@ -17,6 +19,12 @@ │
│ }) │
│ wowsimsDb.gems); │
│ │
│ + consumablesById = lib.listToAttrs (map (consumable: { │
│ + name = toString consumable.id; │
│ + value = consumable; │
│ + }) │
│ + wowsimsDb.consumables); │
│ + │
│ glyphsById = lib.listToAttrs (lib.imap0 (index: glyph: { │
│ name = toString index; │
│ value = glyph; │
│ @@ -29,50 +37,7 @@ │
│ }) │
│ wowsimsDb.enchants); │
│ │
│ - reforgeData = { │
│ - "113" = { │
│ - "i1" = 6; │
│ - "s1" = "spi"; │
│ - "i2" = 13; │
│ - "s2" = "dodgertng"; │
│ - }; │
│ - "138" = { │
│ - "i1" = 31; │
│ - "s1" = "hitrtng"; │
│ - "i2" = 36; │
│ - "s2" = "hastertng"; │
│ - }; │
│ - "158" = { │
│ - "i1" = 37; │
│ - "s1" = "exprtng"; │
│ - "i2" = 31; │
│ - "s2" = "hitrtng"; │
│ - }; │
│ - "159" = { │
│ - "i1" = 37; │
│ - "s1" = "exprtng"; │
│ - "i2" = 32; │
│ - "s2" = "critstrkrtng"; │
│ - }; │
│ - "166" = { │
│ - "i1" = 49; │
│ - "s1" = "mastrtng"; │
│ - "i2" = 32; │
│ - "s2" = "critstrkrtng"; │
│ - }; │
│ - "167" = { │
│ - "i1" = 49; │
│ - "s1" = "mastrtng"; │
│ - "i2" = 36; │
│ - "s2" = "hastertng"; │
│ - }; │
│ - "168" = { │
│ - "i1" = 49; │
│ - "s1" = "mastrtng"; │
│ - "i2" = 37; │
│ - "s2" = "exprtng"; │
│ - }; │
│ - }; │
│ + reforgeData = lib.importJSON "${inputs.wowsims}/assets/db_inputs/wowhead_reforg │
│ e_stats.json"; │
│ │
│ # stat name mappings (for reforging) │
│ statNames = { │
│ @@ -103,7 +68,7 @@ │
│ }; │
│ # Helper functions for item database operations │
│ helpers = { │
│ - # get item data by ID │
│ + # get item data by ID │
│ getItem = id: let │
│ idStr = toString id; │
│ in │
│ @@ -119,6 +84,14 @@ │
│ then gemsById.${idStr} │
│ else null; │
│ │
│ + # get consumable data by ID │
│ + getConsumable = id: let │
│ + idStr = toString id; │
│ + in │
│ + if consumablesById ? ${idStr} │
│ + then consumablesById.${idStr} │
│ + else null; │
│ + │
│ # get enchant data by effect ID │
│ getEnchant = effectId: let │
│ idStr = toString effectId; │
│ @@ -135,7 +108,7 @@ │
│ then reforgeData.${idStr} │
│ else null; │
│ │
│ - # get glyph data by ID │
│ + # get glyph data by ID (from wowsims database) │
│ getGlyph = glyphId: let │
│ idStr = toString glyphId; │
│ in │
│ @@ -143,6 +116,40 @@ │
│ then glyphsById.${idStr} │
│ else null; │
│ │
│ + # get glyph data from our custom glyph database │
│ + getGlyphData = className: glyphId: let │
│ + idStr = toString glyphId; │
│ + classGlyphs = glyphDb.${className} or {}; │
│ + in │
│ + if classGlyphs ? ${idStr} │
│ + then classGlyphs.${idStr} │
│ + else null; │
│ + │
│ + # get talent data from talent database │
│ + getTalentData = className: tier: choice: let │
│ + tierStr = toString tier; │
│ + choiceStr = toString choice; │
│ + classTalents = talentDb.${className} or {}; │
│ + tierTalents = classTalents.${tierStr} or {}; │
│ + in │
│ + if tierTalents ? ${choiceStr} │
│ + then tierTalents.${choiceStr} │
│ + else null; │
│ + │
│ + # parse talent string into individual choices │
│ + parseTalentString = talentString: let │
│ + # Convert string to list of characters, then to list of numbers │
│ + chars = lib.stringToCharacters talentString; │
│ + # Convert each character to a number (tier choice 1-3) │
│ + choices = map (char: │
│ + let num = lib.toInt char; │
│ + in if num >= 1 && num <= 3 then num else 0 │
│ + ) chars; │
│ + # Create list of {tier, choice} objects, filtering out invalid choices (0) │
│ + indexedChoices = lib.imap1 (tier: choice: {inherit tier choice;}) choices; │
│ + validChoices = lib.filter (choice: choice.choice != 0) indexedChoices; │
│ + in validChoices; │
│ + │
│ # parse gem stats into readable format │
│ parseGemStats = gem: │
│ if gem ? stats │
│ @@ -172,14 +179,19 @@ │
│ stats = helpers.parseGemStats gem; │
│ in { │
│ inherit (gem) id name; │
│ - icon = if gem ? icon then gem.icon else null; │
│ - color = if gem ? color then gem.color else null; │
│ - quality = if gem ? quality then gem.quality else null; │
│ + icon = │
│ + if gem ? icon │
│ + then gem.icon │
│ + else null; │
│ + color = │
│ + if gem ? color │
│ + then gem.color │
│ + else null; │
│ + quality = │
│ + if gem ? quality │
│ + then gem.quality │
│ + else null; │
│ stats = stats; │
│ - description = │
│ - if stats != [] │
│ - then "${gem.name} -- ${lib.concatStringsSep ", " stats}" │
│ - else gem.name; │
│ } │
│ else null │
│ else null; │
│ @@ -217,40 +229,61 @@ │
│ │
│ # enrich a single equipment item │
│ enrichItem = item: │
│ - if !(item ? id) then item │
│ + if !(item ? id) │
│ + then item │
│ else let │
│ itemData = helpers.getItem item.id; │
│ - enrichedGems = if item ? gems │
│ + enrichedGems = │
│ + if item ? gems │
│ then lib.filter (gem: gem != null) (map helpers.enrichGem item.gems) │
│ else []; │
│ - enrichedEnchant = if item ? enchant │
│ + enrichedEnchant = │
│ + if item ? enchant │
│ then helpers.enrichEnchant item.enchant │
│ else null; │
│ - enrichedReforge = if item ? reforging │
│ + enrichedReforge = │
│ + if item ? reforging │
│ then helpers.enrichReforge item.reforging │
│ else null; │
│ - │
│ + │
│ # Extract item stats from scalingOptions if available │
│ - itemStats = if itemData != null && itemData ? scalingOptions && itemData. │
│ scalingOptions ? "0" │
│ + itemStats = │
│ + if itemData != null && itemData ? scalingOptions && itemData.scalingOpt │
│ ions ? "0" │
│ then itemData.scalingOptions."0" │
│ else null; │
│ in │
│ - item // { │
│ - name = if itemData != null then itemData.name else "Item ${toString ite │
│ m.id}"; │
│ - icon = if itemData != null && itemData ? icon then itemData.icon else n │
│ ull; │
│ - quality = if itemData != null && itemData ? quality then itemData.quali │
│ ty else null; │
│ - type = if itemData != null && itemData ? type then itemData.type else n │
│ ull; │
│ - } // lib.optionalAttrs (itemStats != null) { │
│ + item │
│ + // { │
│ + name = │
│ + if itemData != null │
│ + then itemData.name │
│ + else "Item ${toString item.id}"; │
│ + icon = │
│ + if itemData != null && itemData ? icon │
│ + then itemData.icon │
│ + else null; │
│ + quality = │
│ + if itemData != null && itemData ? quality │
│ + then itemData.quality │
│ + else null; │
│ + type = │
│ + if itemData != null && itemData ? type │
│ + then itemData.type │
│ + else null; │
│ + } │
│ + // lib.optionalAttrs (itemStats != null) { │
│ stats = itemStats; │
│ - } // lib.optionalAttrs (enrichedGems != []) { │
│ + } │
│ + // lib.optionalAttrs (enrichedGems != []) { │
│ gems = enrichedGems; │
│ - } // lib.optionalAttrs (enrichedEnchant != null) { │
│ + } │
│ + // lib.optionalAttrs (enrichedEnchant != null) { │
│ enchant = enrichedEnchant; │
│ - } // lib.optionalAttrs (enrichedReforge != null) { │
│ + } │
│ + // lib.optionalAttrs (enrichedReforge != null) { │
│ reforging = enrichedReforge; │
│ }; │
│ }; │
│ - │
│ in { │
│ # get item data by ID │
│ getItem = helpers.getItem; │
│ @@ -311,9 +344,14 @@ in { │
│ # get glyph name by ID │
│ getGlyphName = glyphId: let │
│ glyph = helpers.getGlyph glyphId; │
│ - item = if glyph != null then helpers.getItem glyph.itemId else null; │
│ + item = │
│ + if glyph != null │
│ + then helpers.getItem glyph.itemId │
│ + else null; │
│ in │
│ - if item != null then item.name else "Unknown Glyph ${toString glyphId}"; │
│ + if item != null │
│ + then item.name │
│ + else "Unknown Glyph ${toString glyphId}"; │
│ │
│ # enrich equipment item with name and other data │
│ enrichEquipmentItem = helpers.enrichItem; │
│ @@ -330,116 +368,146 @@ in { │
│ │
│ # enrich consumables with item names and icons │
│ enrichConsumables = consumables: │
│ - if consumables == null then null │
│ + if consumables == null │
│ + then null │
│ else let │
│ - getItemDataSafe = id: let item = helpers.getItem id; in │
│ - if item != null then { │
│ - name = item.name; │
│ - icon = if item ? icon then item.icon else null; │
│ - quality = if item ? quality then item.quality else null; │
│ - } else { │
│ - name = "Item ${toString id}"; │
│ + getConsumableDataSafe = id: let │
│ + consumable = helpers.getConsumable id; │
│ + in │
│ + if consumable != null │
│ + then { │
│ + name = consumable.name; │
│ + icon = │
│ + if consumable ? icon │
│ + then consumable.icon │
│ + else null; │
│ + } │
│ + else { │
│ + name = "Consumable ${toString id}"; │
│ icon = null; │
│ - quality = null; │
│ }; │
│ in │
│ - consumables // lib.optionalAttrs (consumables ? flaskId && consumables.flas │
│ kId != 0) ( │
│ - let flaskData = getItemDataSafe consumables.flaskId; in { │
│ + consumables │
│ + // lib.optionalAttrs (consumables ? flaskId && consumables.flaskId != 0) ( │
│ + let │
│ + flaskData = getConsumableDataSafe consumables.flaskId; │
│ + in { │
│ flaskName = flaskData.name; │
│ flaskIcon = flaskData.icon; │
│ - flaskQuality = flaskData.quality; │
│ } │
│ - ) // lib.optionalAttrs (consumables ? foodId && consumables.foodId != 0) ( │
│ - let foodData = getItemDataSafe consumables.foodId; in { │
│ + ) │
│ + // lib.optionalAttrs (consumables ? foodId && consumables.foodId != 0) ( │
│ + let │
│ + foodData = getConsumableDataSafe consumables.foodId; │
│ + in { │
│ foodName = foodData.name; │
│ foodIcon = foodData.icon; │
│ - foodQuality = foodData.quality; │
│ } │
│ - ) // lib.optionalAttrs (consumables ? potId && consumables.potId != 0) ( │
│ - let potData = getItemDataSafe consumables.potId; in { │
│ + ) │
│ + // lib.optionalAttrs (consumables ? potId && consumables.potId != 0) ( │
│ + let │
│ + potData = getConsumableDataSafe consumables.potId; │
│ + in { │
│ potName = potData.name; │
│ potIcon = potData.icon; │
│ - potQuality = potData.quality; │
│ } │
│ - ) // lib.optionalAttrs (consumables ? prepotId && consumables.prepotId != 0 │
│ ) ( │
│ - let prepotData = getItemDataSafe consumables.prepotId; in { │
│ + ) │
│ + // lib.optionalAttrs (consumables ? prepotId && consumables.prepotId != 0) │
│ ( │
│ + let │
│ + prepotData = getConsumableDataSafe consumables.prepotId; │
│ + in { │
│ prepotName = prepotData.name; │
│ prepotIcon = prepotData.icon; │
│ - prepotQuality = prepotData.quality; │
│ } │
│ ); │
│ │
│ - # enrich glyphs with item names and icons │
│ - enrichGlyphs = glyphs: │
│ + # enrich glyphs with names and icons from glyph database │
│ + enrichGlyphs = className: glyphs: │
│ if glyphs == null then null │
│ else let │
│ getGlyphDataSafe = glyphId: let │
│ - glyph = helpers.getGlyph glyphId; │
│ - item = if glyph != null then helpers.getItem glyph.itemId else null; │
│ + glyphData = helpers.getGlyphData className glyphId; │
│ in │
│ - if item != null then { │
│ - name = item.name; │
│ - icon = if item ? icon then item.icon else null; │
│ - quality = if item ? quality then item.quality else null; │
│ - spellId = if glyph != null then glyph.spellId else null; │
│ + if glyphData != null then { │
│ + name = glyphData.name; │
│ + icon = if glyphData ? icon then glyphData.icon else null; │
│ + spellId = if glyphData ? spellId then glyphData.spellId else null; │
│ } else { │
│ name = "Glyph ${toString glyphId}"; │
│ icon = null; │
│ - quality = null; │
│ spellId = null; │
│ }; │
│ in │
│ - glyphs // lib.optionalAttrs (glyphs ? major1 && glyphs.major1 != 0) ( │
│ + glyphs │
│ + // lib.optionalAttrs (glyphs ? major1 && glyphs.major1 != 0) ( │
│ let glyphData = getGlyphDataSafe glyphs.major1; in { │
│ major1Name = glyphData.name; │
│ major1Icon = glyphData.icon; │
│ - major1Quality = glyphData.quality; │
│ major1SpellId = glyphData.spellId; │
│ } │
│ ) // lib.optionalAttrs (glyphs ? major2 && glyphs.major2 != 0) ( │
│ let glyphData = getGlyphDataSafe glyphs.major2; in { │
│ major2Name = glyphData.name; │
│ major2Icon = glyphData.icon; │
│ - major2Quality = glyphData.quality; │
│ major2SpellId = glyphData.spellId; │
│ } │
│ ) // lib.optionalAttrs (glyphs ? major3 && glyphs.major3 != 0) ( │
│ let glyphData = getGlyphDataSafe glyphs.major3; in { │
│ major3Name = glyphData.name; │
│ major3Icon = glyphData.icon; │
│ - major3Quality = glyphData.quality; │
│ major3SpellId = glyphData.spellId; │
│ } │
│ ) // lib.optionalAttrs (glyphs ? minor1 && glyphs.minor1 != 0) ( │
│ let glyphData = getGlyphDataSafe glyphs.minor1; in { │
│ minor1Name = glyphData.name; │
│ minor1Icon = glyphData.icon; │
│ - minor1Quality = glyphData.quality; │
│ minor1SpellId = glyphData.spellId; │
│ } │
│ ) // lib.optionalAttrs (glyphs ? minor2 && glyphs.minor2 != 0) ( │
│ let glyphData = getGlyphDataSafe glyphs.minor2; in { │
│ minor2Name = glyphData.name; │
│ minor2Icon = glyphData.icon; │
│ - minor2Quality = glyphData.quality; │
│ minor2SpellId = glyphData.spellId; │
│ } │
│ ) // lib.optionalAttrs (glyphs ? minor3 && glyphs.minor3 != 0) ( │
│ let glyphData = getGlyphDataSafe glyphs.minor3; in { │
│ minor3Name = glyphData.name; │
│ minor3Icon = glyphData.icon; │
│ - minor3Quality = glyphData.quality; │
│ minor3SpellId = glyphData.spellId; │
│ } │
│ ); │
│ │
│ + # enrich talents with names and icons from talent database │
│ + enrichTalents = className: talentString: │
│ + if talentString == null || talentString == "" │
│ + then null │
│ + else let │
│ + # Parse talent string into tier/choice pairs │
│ + talentChoices = helpers.parseTalentString talentString; │
│ + │
│ + # Get talent data for each choice and create enriched talent objects │
│ + enrichedTalents = map (choice: let │
│ + talentData = helpers.getTalentData className choice.tier choice.choice; │
│ + in { │
│ + tier = choice.tier; │
│ + choice = choice.choice; │
│ + name = if talentData != null then talentData.name else "Unknown Talent"; │
│ + spellId = if talentData != null then talentData.spellId else null; │
│ + icon = if talentData != null then talentData.icon else null; │
│ + }) talentChoices; │
│ + │
│ + in { │
│ + talentString = talentString; │
│ + talents = enrichedTalents; │
│ + }; │
│ + │
│ # enrich a full loadout │
│ enrichLoadout = loadout: │
│ if loadout ? equipment │
│ then │
│ loadout │
│ // { │
│ - equipment = │
│ + equipment = │
│ if loadout.equipment ? items │
│ then │
│ loadout.equipment │
│ @@ -464,15 +532,16 @@ in { │
│ then │
│ result │
│ // { │
│ - loadout = │
│ + loadout = │
│ if result.loadout ? equipment && result.loadout.equipment ? i │
│ tems │
│ then │
│ result.loadout │
│ // { │
│ - equipment = result.loadout.equipment │
│ - // { │
│ - items = map helpers.enrichItem result.loadout.equipment │
│ .items; │
│ - }; │
│ + equipment = │
│ + result.loadout.equipment │
│ + // { │
│ + items = map helpers.enrichItem result.loadout.equipme │
│ nt.items; │
│ + }; │
│ # TODO: Add consumables, gems, enchants enrichment │
│ } │
│ else result.loadout; │
│ @@ -483,4 +552,3 @@ in { │
│ } │
│ else simData; │
│ } │
│ - │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/lib/itemDatabase.nix ───────────┐
│ diff --git a/nix/lib/itemDatabase.nix b/nix/ │
│ lib/itemDatabase.nix │
│ index b0b9b4f..d00438e 100644 │
│ --- a/nix/lib/itemDatabase.nix │
│ +++ b/nix/lib/itemDatabase.nix │
│ @@ -4,6 +4,8 @@ │
│ ... │
│ }: let │
│ wowsimsDb = lib.importJSON "${inputs.wows │
│ ims}/assets/database/db.json"; │
│ + glyphDb = import ./database/glyphs.nix; │
│ + talentDb = import ./database/talents.nix; │
│ │
│ itemsById = lib.listToAttrs (map (item: { │
│ name = toString item.id; │
│ @@ -17,6 +19,12 @@ │
│ }) │
│ wowsimsDb.gems); │
│ │
│ + consumablesById = lib.listToAttrs (map (c │
│ onsumable: { │
│ + name = toString consumable.id; │
│ + value = consumable; │
│ + }) │
│ + wowsimsDb.consumables); │
│ + │
│ glyphsById = lib.listToAttrs (lib.imap0 ( │
│ index: glyph: { │
│ name = toString index; │
│ value = glyph; │
│ @@ -29,50 +37,7 @@ │
│ }) │
│ wowsimsDb.enchants); │
│ │
│ - reforgeData = { │
│ - "113" = { │
│ - "i1" = 6; │
│ - "s1" = "spi"; │
│ - "i2" = 13; │
│ - "s2" = "dodgertng"; │
│ - }; │
│ - "138" = { │
│ - "i1" = 31; │
│ - "s1" = "hitrtng"; │
│ - "i2" = 36; │
│ - "s2" = "hastertng"; │
│ - }; │
│ - "158" = { │
│ - "i1" = 37; │
│ - "s1" = "exprtng"; │
│ - "i2" = 31; │
│ - "s2" = "hitrtng"; │
│ - }; │
│ - "159" = { │
│ - "i1" = 37; │
│ - "s1" = "exprtng"; │
│ - "i2" = 32; │
│ - "s2" = "critstrkrtng"; │
│ - }; │
│ - "166" = { │
│ - "i1" = 49; │
│ - "s1" = "mastrtng"; │
│ - "i2" = 32; │
│ - "s2" = "critstrkrtng"; │
│ - }; │
│ - "167" = { │
│ - "i1" = 49; │
│ - "s1" = "mastrtng"; │
│ - "i2" = 36; │
│ - "s2" = "hastertng"; │
│ - }; │
│ - "168" = { │
│ - "i1" = 49; │
│ - "s1" = "mastrtng"; │
│ - "i2" = 37; │
│ - "s2" = "exprtng"; │
│ - }; │
│ - }; │
│ + reforgeData = lib.importJSON "${inputs.wo │
│ wsims}/assets/db_inputs/wowhead_reforge_stat │
│ s.json"; │
│ │
│ # stat name mappings (for reforging) │
│ statNames = { │
│ @@ -103,7 +68,7 @@ │
│ }; │
│ # Helper functions for item database oper │
│ ations │
│ helpers = { │
│ - # get item data by ID │
│ + # get item data by ID │
│ getItem = id: let │
│ idStr = toString id; │
│ in │
│ @@ -119,6 +84,14 @@ │
│ then gemsById.${idStr} │
│ else null; │
│ │
│ + # get consumable data by ID │
│ + getConsumable = id: let │
│ + idStr = toString id; │
│ + in │
│ + if consumablesById ? ${idStr} │
│ + then consumablesById.${idStr} │
│ + else null; │
│ + │
│ # get enchant data by effect ID │
│ getEnchant = effectId: let │
│ idStr = toString effectId; │
│ @@ -135,7 +108,7 @@ │
│ then reforgeData.${idStr} │
│ else null; │
│ │
│ - # get glyph data by ID │
│ + # get glyph data by ID (from wowsims da │
│ tabase) │
│ getGlyph = glyphId: let │
│ idStr = toString glyphId; │
│ in │
│ @@ -143,6 +116,40 @@ │
│ then glyphsById.${idStr} │
│ else null; │
│ │
│ + # get glyph data from our custom glyph │
│ database │
│ + getGlyphData = className: glyphId: let │
│ + idStr = toString glyphId; │
│ + classGlyphs = glyphDb.${className} or │
│ {}; │
│ + in │
│ + if classGlyphs ? ${idStr} │
│ + then classGlyphs.${idStr} │
│ + else null; │
│ + │
│ + # get talent data from talent database │
│ + getTalentData = className: tier: choice │
│ : let │
│ + tierStr = toString tier; │
│ + choiceStr = toString choice; │
│ + classTalents = talentDb.${className} │
│ or {}; │
│ + tierTalents = classTalents.${tierStr} │
│ or {}; │
│ + in │
│ + if tierTalents ? ${choiceStr} │
│ + then tierTalents.${choiceStr} │
│ + else null; │
│ + │
│ + # parse talent string into individual c │
│ hoices │
│ + parseTalentString = talentString: let │
│ + # Convert string to list of character │
│ s, then to list of numbers │
│ + chars = lib.stringToCharacters talent │
│ String; │
│ + # Convert each character to a number │
│ (tier choice 1-3) │
│ + choices = map (char: │
│ + let num = lib.toInt char; │
│ + in if num >= 1 && num <= 3 then num │
│ else 0 │
│ + ) chars; │
│ + # Create list of {tier, choice} objec │
│ ts, filtering out invalid choices (0) │
│ + indexedChoices = lib.imap1 (tier: cho │
│ ice: {inherit tier choice;}) choices; │
│ + validChoices = lib.filter (choice: ch │
│ oice.choice != 0) indexedChoices; │
│ + in validChoices; │
│ + │
│ # parse gem stats into readable format │
│ parseGemStats = gem: │
│ if gem ? stats │
│ @@ -172,14 +179,19 @@ │
│ stats = helpers.parseGemStats gem │
│ ; │
│ in { │
│ inherit (gem) id name; │
│ - icon = if gem ? icon then gem.ico │
│ n else null; │
│ - color = if gem ? color then gem.c │
│ olor else null; │
│ - quality = if gem ? quality then g │
│ em.quality else null; │
│ + icon = │
│ + if gem ? icon │
│ + then gem.icon │
│ + else null; │
│ + color = │
│ + if gem ? color │
│ + then gem.color │
│ + else null; │
│ + quality = │
│ + if gem ? quality │
│ + then gem.quality │
│ + else null; │
│ stats = stats; │
│ - description = │
│ - if stats != [] │
│ - then "${gem.name} -- ${lib.conc │
│ atStringsSep ", " stats}" │
│ - else gem.name; │
│ } │
│ else null │
│ else null; │
│ @@ -217,40 +229,61 @@ │
│ │
│ # enrich a single equipment item │
│ enrichItem = item: │
│ - if !(item ? id) then item │
│ + if !(item ? id) │
│ + then item │
│ else let │
│ itemData = helpers.getItem item.id; │
│ - enrichedGems = if item ? gems │
│ + enrichedGems = │
│ + if item ? gems │
│ then lib.filter (gem: gem != null │
│ ) (map helpers.enrichGem item.gems) │
│ else []; │
│ - enrichedEnchant = if item ? enchant │
│ │
│ + enrichedEnchant = │
│ + if item ? enchant │
│ then helpers.enrichEnchant item.e │
│ nchant │
│ else null; │
│ - enrichedReforge = if item ? reforgi │
│ ng │
│ + enrichedReforge = │
│ + if item ? reforging │
│ then helpers.enrichReforge item.r │
│ eforging │
│ else null; │
│ - │
│ + │
│ # Extract item stats from scalingOp │
│ tions if available │
│ - itemStats = if itemData != null && │
│ itemData ? scalingOptions && itemData.scalin │
│ gOptions ? "0" │
│ + itemStats = │
│ + if itemData != null && itemData ? │
│ scalingOptions && itemData.scalingOptions ? │
│ "0" │
│ then itemData.scalingOptions."0" │
│ else null; │
│ in │
│ - item // { │
│ - name = if itemData != null then i │
│ temData.name else "Item ${toString item.id}" │
│ ; │
│ - icon = if itemData != null && ite │
│ mData ? icon then itemData.icon else null; │
│ - quality = if itemData != null && │
│ itemData ? quality then itemData.quality els │
│ e null; │
│ - type = if itemData != null && ite │
│ mData ? type then itemData.type else null; │
│ - } // lib.optionalAttrs (itemStats ! │
│ = null) { │
│ + item │
│ + // { │
│ + name = │
│ + if itemData != null │
│ + then itemData.name │
│ + else "Item ${toString item.id}" │
│ ; │
│ + icon = │
│ + if itemData != null && itemData │
│ ? icon │
│ + then itemData.icon │
│ + else null; │
│ + quality = │
│ + if itemData != null && itemData │
│ ? quality │
│ + then itemData.quality │
│ + else null; │
│ + type = │
│ + if itemData != null && itemData │
│ ? type │
│ + then itemData.type │
│ + else null; │
│ + } │
│ + // lib.optionalAttrs (itemStats != │
│ null) { │
│ stats = itemStats; │
│ - } // lib.optionalAttrs (enrichedGem │
│ s != []) { │
│ + } │
│ + // lib.optionalAttrs (enrichedGems │
│ != []) { │
│ gems = enrichedGems; │
│ - } // lib.optionalAttrs (enrichedEnc │
│ hant != null) { │
│ + } │
│ + // lib.optionalAttrs (enrichedEncha │
│ nt != null) { │
│ enchant = enrichedEnchant; │
│ - } // lib.optionalAttrs (enrichedRef │
│ orge != null) { │
│ + } │
│ + // lib.optionalAttrs (enrichedRefor │
│ ge != null) { │
│ reforging = enrichedReforge; │
│ }; │
│ }; │
│ - │
│ in { │
│ # get item data by ID │
│ getItem = helpers.getItem; │
│ @@ -311,9 +344,14 @@ in { │
│ # get glyph name by ID │
│ getGlyphName = glyphId: let │
│ glyph = helpers.getGlyph glyphId; │
│ - item = if glyph != null then helpers.ge │
│ tItem glyph.itemId else null; │
│ + item = │
│ + if glyph != null │
│ + then helpers.getItem glyph.itemId │
│ + else null; │
│ in │
│ - if item != null then item.name else "Un │
│ known Glyph ${toString glyphId}"; │
│ + if item != null │
│ + then item.name │
│ + else "Unknown Glyph ${toString glyphId} │
│ "; │
│ │
│ # enrich equipment item with name and oth │
│ er data │
│ enrichEquipmentItem = helpers.enrichItem; │
│ @@ -330,116 +368,146 @@ in { │
│ │
│ # enrich consumables with item names and │
│ icons │
│ enrichConsumables = consumables: │
│ - if consumables == null then null │
│ + if consumables == null │
│ + then null │
│ else let │
│ - getItemDataSafe = id: let item = help │
│ ers.getItem id; in │
│ - if item != null then { │
│ - name = item.name; │
│ - icon = if item ? icon then item.i │
│ con else null; │
│ - quality = if item ? quality then │
│ item.quality else null; │
│ - } else { │
│ - name = "Item ${toString id}"; │
│ + getConsumableDataSafe = id: let │
│ + consumable = helpers.getConsumable │
│ id; │
│ + in │
│ + if consumable != null │
│ + then { │
│ + name = consumable.name; │
│ + icon = │
│ + if consumable ? icon │
│ + then consumable.icon │
│ + else null; │
│ + } │
│ + else { │
│ + name = "Consumable ${toString id} │
│ "; │
│ icon = null; │
│ - quality = null; │
│ }; │
│ in │
│ - consumables // lib.optionalAttrs (con │
│ sumables ? flaskId && consumables.flaskId != │
│ 0) ( │
│ - let flaskData = getItemDataSafe con │
│ sumables.flaskId; in { │
│ + consumables │
│ + // lib.optionalAttrs (consumables ? f │
│ laskId && consumables.flaskId != 0) ( │
│ + let │
│ + flaskData = getConsumableDataSafe │
│ consumables.flaskId; │
│ + in { │
│ flaskName = flaskData.name; │
│ flaskIcon = flaskData.icon; │
│ - flaskQuality = flaskData.quality; │
│ } │
│ - ) // lib.optionalAttrs (consumables ? │
│ foodId && consumables.foodId != 0) ( │
│ - let foodData = getItemDataSafe cons │
│ umables.foodId; in { │
│ + ) │
│ + // lib.optionalAttrs (consumables ? f │
│ oodId && consumables.foodId != 0) ( │
│ + let │
│ + foodData = getConsumableDataSafe │
│ consumables.foodId; │
│ + in { │
│ foodName = foodData.name; │
│ foodIcon = foodData.icon; │
│ - foodQuality = foodData.quality; │
│ } │
│ - ) // lib.optionalAttrs (consumables ? │
│ potId && consumables.potId != 0) ( │
│ - let potData = getItemDataSafe consu │
│ mables.potId; in { │
│ + ) │
│ + // lib.optionalAttrs (consumables ? p │
│ otId && consumables.potId != 0) ( │
│ + let │
│ + potData = getConsumableDataSafe c │
│ onsumables.potId; │
│ + in { │
│ potName = potData.name; │
│ potIcon = potData.icon; │
│ - potQuality = potData.quality; │
│ } │
│ - ) // lib.optionalAttrs (consumables ? │
│ prepotId && consumables.prepotId != 0) ( │
│ - let prepotData = getItemDataSafe co │
│ nsumables.prepotId; in { │
│ + ) │
│ + // lib.optionalAttrs (consumables ? p │
│ repotId && consumables.prepotId != 0) ( │
│ + let │
│ + prepotData = getConsumableDataSaf │
│ e consumables.prepotId; │
│ + in { │
│ prepotName = prepotData.name; │
│ prepotIcon = prepotData.icon; │
│ - prepotQuality = prepotData.qualit │
│ y; │
│ } │
│ ); │
│ │
│ - # enrich glyphs with item names and icons │
│ - enrichGlyphs = glyphs: │
│ + # enrich glyphs with names and icons from │
│ glyph database │
│ + enrichGlyphs = className: glyphs: │
│ if glyphs == null then null │
│ else let │
│ getGlyphDataSafe = glyphId: let │
│ - glyph = helpers.getGlyph glyphId; │
│ - item = if glyph != null then helper │
│ s.getItem glyph.itemId else null; │
│ + glyphData = helpers.getGlyphData cl │
│ assName glyphId; │
│ in │
│ - if item != null then { │
│ - name = item.name; │
│ - icon = if item ? icon then item.i │
│ con else null; │
│ - quality = if item ? quality then │
│ item.quality else null; │
│ - spellId = if glyph != null then g │
│ lyph.spellId else null; │
│ + if glyphData != null then { │
│ + name = glyphData.name; │
│ + icon = if glyphData ? icon then g │
│ lyphData.icon else null; │
│ + spellId = if glyphData ? spellId │
│ then glyphData.spellId else null; │
│ } else { │
│ name = "Glyph ${toString glyphId} │
│ "; │
│ icon = null; │
│ - quality = null; │
│ spellId = null; │
│ }; │
│ in │
│ - glyphs // lib.optionalAttrs (glyphs ? │
│ major1 && glyphs.major1 != 0) ( │
│ + glyphs │
│ + // lib.optionalAttrs (glyphs ? major1 │
│ && glyphs.major1 != 0) ( │
│ let glyphData = getGlyphDataSafe gl │
│ yphs.major1; in { │
│ major1Name = glyphData.name; │
│ major1Icon = glyphData.icon; │
│ - major1Quality = glyphData.quality │
│ ; │
│ major1SpellId = glyphData.spellId │
│ ; │
│ } │
│ ) // lib.optionalAttrs (glyphs ? majo │
│ r2 && glyphs.major2 != 0) ( │
│ let glyphData = getGlyphDataSafe gl │
│ yphs.major2; in { │
│ major2Name = glyphData.name; │
│ major2Icon = glyphData.icon; │
│ - major2Quality = glyphData.quality │
│ ; │
│ major2SpellId = glyphData.spellId │
│ ; │
│ } │
│ ) // lib.optionalAttrs (glyphs ? majo │
│ r3 && glyphs.major3 != 0) ( │
│ let glyphData = getGlyphDataSafe gl │
│ yphs.major3; in { │
│ major3Name = glyphData.name; │
│ major3Icon = glyphData.icon; │
│ - major3Quality = glyphData.quality │
│ ; │
│ major3SpellId = glyphData.spellId │
│ ; │
│ } │
│ ) // lib.optionalAttrs (glyphs ? mino │
│ r1 && glyphs.minor1 != 0) ( │
│ let glyphData = getGlyphDataSafe gl │
│ yphs.minor1; in { │
│ minor1Name = glyphData.name; │
│ minor1Icon = glyphData.icon; │
│ - minor1Quality = glyphData.quality │
│ ; │
│ minor1SpellId = glyphData.spellId │
│ ; │
│ } │
│ ) // lib.optionalAttrs (glyphs ? mino │
│ r2 && glyphs.minor2 != 0) ( │
│ let glyphData = getGlyphDataSafe gl │
│ yphs.minor2; in { │
│ minor2Name = glyphData.name; │
│ minor2Icon = glyphData.icon; │
│ - minor2Quality = glyphData.quality │
│ ; │
│ minor2SpellId = glyphData.spellId │
│ ; │
│ } │
│ ) // lib.optionalAttrs (glyphs ? mino │
│ r3 && glyphs.minor3 != 0) ( │
│ let glyphData = getGlyphDataSafe gl │
│ yphs.minor3; in { │
│ minor3Name = glyphData.name; │
│ minor3Icon = glyphData.icon; │
│ - minor3Quality = glyphData.quality │
│ ; │
│ minor3SpellId = glyphData.spellId │
│ ; │
│ } │
│ ); │
│ │
│ + # enrich talents with names and icons fro │
│ m talent database │
│ + enrichTalents = className: talentString: │
│ + if talentString == null || talentString │
│ == "" │
│ + then null │
│ + else let │
│ + # Parse talent string into tier/choic │
│ e pairs │
│ + talentChoices = helpers.parseTalentSt │
│ ring talentString; │
│ + │
│ + # Get talent data for each choice and │
│ create enriched talent objects │
│ + enrichedTalents = map (choice: let │
│ + talentData = helpers.getTalentData │
│ className choice.tier choice.choice; │
│ + in { │
│ + tier = choice.tier; │
│ + choice = choice.choice; │
│ + name = if talentData != null then t │
│ alentData.name else "Unknown Talent"; │
│ + spellId = if talentData != null the │
│ n talentData.spellId else null; │
│ + icon = if talentData != null then t │
│ alentData.icon else null; │
│ + }) talentChoices; │
│ + │
│ + in { │
│ + talentString = talentString; │
│ + talents = enrichedTalents; │
│ + }; │
│ + │
│ # enrich a full loadout │
│ enrichLoadout = loadout: │
│ if loadout ? equipment │
│ then │
│ loadout │
│ // { │
│ - equipment = │
│ + equipment = │
│ if loadout.equipment ? items │
│ then │
│ loadout.equipment │
│ @@ -464,15 +532,16 @@ in { │
│ then │
│ result │
│ // { │
│ - loadout = │
│ + loadout = │
│ if result.loadout ? equ │
│ ipment && result.loadout.equipment ? items │
│ then │
│ result.loadout │
│ // { │
│ - equipment = result. │
│ loadout.equipment │
│ - // { │
│ - items = map helpe │
│ rs.enrichItem result.loadout.equipment.items │
│ ; │
│ - }; │
│ + equipment = │
│ + result.loadout.eq │
│ uipment │
│ + // { │
│ + items = map hel │
│ pers.enrichItem result.loadout.equipment.ite │
│ ms; │
│ + }; │
│ # TODO: Add consuma │
│ bles, gems, enchants enrichment │
│ } │
│ else result.loadout; │
│ @@ -483,4 +552,3 @@ in { │
│ } │
│ else simData; │
│ } │
│ - │
└──────────────────────────────────────────────┘
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET