OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
 
master @ 598 LINES
 
[ HISTORY ]  [ UP ]
 

{
  inputs,
  lib,
  ...
}: 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;
      value = item;
    })
    wowsimsDb.items);

  gemsById = lib.listToAttrs (map (gem: {
      name = toString gem.id;
      value = gem;
    })
    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;
    })
    wowsimsDb.glyphIds);

  enchantsByEffectId = lib.listToAttrs (map (enchant: {
      name = toString enchant.effectId;
      value = enchant;
    })
    wowsimsDb.enchants);

  reforgeData = lib.importJSON "${inputs.wowsims}/assets/db_inputs/wowhead_reforge
_stats.json";

  # stat name mappings (for reforging)
  statNames = {
    "spi" = "Spirit";
    "dodgertng" = "Dodge";
    "parryrtng" = "Parry";
    "hitrtng" = "Hit";
    "critstrkrtng" = "Crit";
    "hastertng" = "Haste";
    "exprtng" = "Expertise";
    "mastrtng" = "Mastery";
  };

  # stat array index mappings (for gems/items)
  statIndexNames = {
    "0" = "Strength";
    "1" = "Agility";
    "2" = "Stamina";
    "3" = "Intellect";
    "4" = "Spirit";
    "5" = "Hit";
    "6" = "Crit";
    "7" = "Haste";
    "8" = "Expertise";
    "9" = "Dodge";
    "10" = "Parry";
    "11" = "Mastery";
  };
  # Helper functions for item database operations
  helpers = {
    # get item data by ID
    getItem = id: let
      idStr = toString id;
    in
      if itemsById ? ${idStr}
      then itemsById.${idStr}
      else null;

    # get gem data by ID
    getGem = id: let
      idStr = toString id;
    in
      if gemsById ? ${idStr}
      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;
    in
      if enchantsByEffectId ? ${idStr}
      then enchantsByEffectId.${idStr}
      else null;

    # get reforge data by ID
    getReforge = reforgeId: let
      idStr = toString reforgeId;
    in
      if reforgeData ? ${idStr}
      then reforgeData.${idStr}
      else null;

    # get glyph data by ID (from wowsims database)
    getGlyph = glyphId: let
      idStr = toString glyphId;
    in
      if glyphsById ? ${idStr}
      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
      then let
        # find non-zero stats and convert to readable format
        indexedStats = lib.imap0 (index: value: {inherit index value;}) gem.stats;
        activeStats = lib.filter (stat: stat.value > 0) indexedStats;
        statDescriptions =
          map (
            stat: let
              statName = statIndexNames.${toString stat.index} or "Unknown Stat";
            in "+${toString stat.value} ${statName}"
          )
          activeStats;
      in
        statDescriptions
      else [];

    # enrich a single gem with stats
    enrichGem = gemId:
      if gemId != null && gemId != 0
      then let
        gem = helpers.getGem gemId;
      in
        if gem != null
        then let
          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;
          stats = stats;
        }
        else null
      else null;

    # enrich enchant info
    enrichEnchant = enchantId:
      if enchantId != null && enchantId != 0
      then {
        id = enchantId;
        name = let
          enchant = helpers.getEnchant enchantId;
        in
          if enchant != null
          then enchant.name
          else "Unknown Enchant ${toString enchantId}";
      }
      else null;

    # enrich reforge info
    enrichReforge = reforgeId:
      if reforgeId != null && reforgeId != 0
      then {
        id = reforgeId;
        description = let
          reforge = helpers.getReforge reforgeId;
        in
          if reforge != null
          then let
            fromStat = statNames.${reforge.s1} or reforge.s1;
            toStat = statNames.${reforge.s2} or reforge.s2;
          in "${fromStat} -> ${toStat}"
          else "Unknown Reforge ${toString reforgeId}";
      }
      else null;

    # enrich a single equipment item
    enrichItem = item:
      if !(item ? id)
      then item
      else let
        itemData = helpers.getItem item.id;
        enrichedGems =
          if item ? gems
          then lib.filter (gem: gem != null) (map helpers.enrichGem item.gems)
          else [];
        enrichedEnchant =
          if item ? enchant
          then helpers.enrichEnchant item.enchant
          else null;
        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.scalingOpti
ons ? "0"
          then itemData.scalingOptions."0"
          else null;
      in
        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 != []) {
          gems = enrichedGems;
        }
        // lib.optionalAttrs (enrichedEnchant != null) {
          enchant = enrichedEnchant;
        }
        // lib.optionalAttrs (enrichedReforge != null) {
          reforging = enrichedReforge;
        };
  };
in {
  # get item data by ID
  getItem = helpers.getItem;

  # get just the item name by ID
  getItemName = id: let
    item = helpers.getItem id;
  in
    if item != null
    then item.name
    else "Unknown Item ${toString id}";

  # get gem data by ID
  getGem = helpers.getGem;

  # get gem name by ID
  getGemName = id: let
    gem = helpers.getGem id;
  in
    if gem != null
    then gem.name
    else "Unknown Gem ${toString id}";

  # parse gem stats into readable format
  parseGemStats = helpers.parseGemStats;

  # get enriched gem data with stats (delegates to helpers)
  getEnrichedGem = helpers.enrichGem;

  # get enchant data by effect ID
  getEnchant = helpers.getEnchant;

  # get enchant name by effect ID
  getEnchantName = effectId: let
    enchant = helpers.getEnchant effectId;
  in
    if enchant != null
    then enchant.name
    else "Unknown Enchant ${toString effectId}";

  # get reforge data by ID
  getReforge = helpers.getReforge;

  # get reforge description by ID
  getReforgeDescription = reforgeId: let
    reforge = helpers.getReforge reforgeId;
  in
    if reforge != null
    then let
      fromStat = statNames.${reforge.s1} or reforge.s1;
      toStat = statNames.${reforge.s2} or reforge.s2;
    in "${fromStat} -> ${toStat}"
    else "Unknown Reforge ${toString reforgeId}";

  # get glyph data by ID
  getGlyph = helpers.getGlyph;

  # get glyph name by ID
  getGlyphName = glyphId: let
    glyph = helpers.getGlyph glyphId;
    item =
      if glyph != null
      then helpers.getItem glyph.itemId
      else null;
  in
    if item != null
    then item.name
    else "Unknown Glyph ${toString glyphId}";

  # enrich equipment item with name and other data
  enrichEquipmentItem = helpers.enrichItem;

  # enrich an entire equipment array
  enrichEquipment = equipment:
    if equipment ? items
    then
      equipment
      // {
        items = map helpers.enrichItem equipment.items;
      }
    else equipment;

  # enrich consumables with item names and icons
  enrichConsumables = consumables:
    if consumables == null
    then null
    else let
      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;
        };
    in
      consumables
      // lib.optionalAttrs (consumables ? flaskId && consumables.flaskId != 0) (
        let
          flaskData = getConsumableDataSafe consumables.flaskId;
        in {
          flaskName = flaskData.name;
          flaskIcon = flaskData.icon;
        }
      )
      // lib.optionalAttrs (consumables ? foodId && consumables.foodId != 0) (
        let
          foodData = getConsumableDataSafe consumables.foodId;
        in {
          foodName = foodData.name;
          foodIcon = foodData.icon;
        }
      )
      // lib.optionalAttrs (consumables ? potId && consumables.potId != 0) (
        let
          potData = getConsumableDataSafe consumables.potId;
        in {
          potName = potData.name;
          potIcon = potData.icon;
        }
      )
      // lib.optionalAttrs (consumables ? prepotId && consumables.prepotId != 0) (
        let
          prepotData = getConsumableDataSafe consumables.prepotId;
        in {
          prepotName = prepotData.name;
          prepotIcon = prepotData.icon;
        }
      );

  # enrich glyphs with names and icons from glyph database
  enrichGlyphs = className: glyphs:
    if glyphs == null
    then null
    else let
      getGlyphDataSafe = glyphId: let
        glyphData = helpers.getGlyphData className glyphId;
      in
        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;
          spellId = null;
        };
    in
      glyphs
      // lib.optionalAttrs (glyphs ? major1 && glyphs.major1 != 0) (
        let
          glyphData = getGlyphDataSafe glyphs.major1;
        in {
          major1Name = glyphData.name;
          major1Icon = glyphData.icon;
          major1SpellId = glyphData.spellId;
        }
      )
      // lib.optionalAttrs (glyphs ? major2 && glyphs.major2 != 0) (
        let
          glyphData = getGlyphDataSafe glyphs.major2;
        in {
          major2Name = glyphData.name;
          major2Icon = glyphData.icon;
          major2SpellId = glyphData.spellId;
        }
      )
      // lib.optionalAttrs (glyphs ? major3 && glyphs.major3 != 0) (
        let
          glyphData = getGlyphDataSafe glyphs.major3;
        in {
          major3Name = glyphData.name;
          major3Icon = glyphData.icon;
          major3SpellId = glyphData.spellId;
        }
      )
      // lib.optionalAttrs (glyphs ? minor1 && glyphs.minor1 != 0) (
        let
          glyphData = getGlyphDataSafe glyphs.minor1;
        in {
          minor1Name = glyphData.name;
          minor1Icon = glyphData.icon;
          minor1SpellId = glyphData.spellId;
        }
      )
      // lib.optionalAttrs (glyphs ? minor2 && glyphs.minor2 != 0) (
        let
          glyphData = getGlyphDataSafe glyphs.minor2;
        in {
          minor2Name = glyphData.name;
          minor2Icon = glyphData.icon;
          minor2SpellId = glyphData.spellId;
        }
      )
      // lib.optionalAttrs (glyphs ? minor3 && glyphs.minor3 != 0) (
        let
          glyphData = getGlyphDataSafe glyphs.minor3;
        in {
          minor3Name = glyphData.name;
          minor3Icon = glyphData.icon;
          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 =
          if loadout.equipment ? items
          then
            loadout.equipment
            // {
              items = map helpers.enrichItem loadout.equipment.items;
            }
          else loadout.equipment;
        # TODO: Add consumables, gems, enchants enrichment
      }
    else loadout;

  # enrich simulation results (main function)
  enrichSimulationData = simData:
    if simData ? results
    then
      simData
      // {
        results =
          lib.mapAttrs (
            _name: result:
              if result ? loadout
              then
                result
                // {
                  loadout =
                    if result.loadout ? equipment && result.loadout.equipment ? it
ems
                    then
                      result.loadout
                      // {
                        equipment =
                          result.loadout.equipment
                          // {
                            items = map helpers.enrichItem result.loadout.equipmen
t.items;
                          };
                        # TODO: Add consumables, gems, enchants enrichment
                      }
                    else result.loadout;
                }
              else result
          )
          simData.results;
      }
    else simData;
}

{
  inputs,
  lib,
  ...
}: let
  wowsimsDb = lib.importJSON "${inputs.wowsi
ms}/assets/database/db.json";
  glyphDb = import ./database/glyphs.nix;
  talentDb = import ./database/talents.nix;

  itemsById = lib.listToAttrs (map (item: {
      name = toString item.id;
      value = item;
    })
    wowsimsDb.items);

  gemsById = lib.listToAttrs (map (gem: {
      name = toString gem.id;
      value = gem;
    })
    wowsimsDb.gems);

  consumablesById = lib.listToAttrs (map (co
nsumable: {
      name = toString consumable.id;
      value = consumable;
    })
    wowsimsDb.consumables);

  glyphsById = lib.listToAttrs (lib.imap0 (i
ndex: glyph: {
      name = toString index;
      value = glyph;
    })
    wowsimsDb.glyphIds);

  enchantsByEffectId = lib.listToAttrs (map 
(enchant: {
      name = toString enchant.effectId;
      value = enchant;
    })
    wowsimsDb.enchants);

  reforgeData = lib.importJSON "${inputs.wow
sims}/assets/db_inputs/wowhead_reforge_stats
.json";

  # stat name mappings (for reforging)
  statNames = {
    "spi" = "Spirit";
    "dodgertng" = "Dodge";
    "parryrtng" = "Parry";
    "hitrtng" = "Hit";
    "critstrkrtng" = "Crit";
    "hastertng" = "Haste";
    "exprtng" = "Expertise";
    "mastrtng" = "Mastery";
  };

  # stat array index mappings (for gems/item
s)
  statIndexNames = {
    "0" = "Strength";
    "1" = "Agility";
    "2" = "Stamina";
    "3" = "Intellect";
    "4" = "Spirit";
    "5" = "Hit";
    "6" = "Crit";
    "7" = "Haste";
    "8" = "Expertise";
    "9" = "Dodge";
    "10" = "Parry";
    "11" = "Mastery";
  };
  # Helper functions for item database opera
tions
  helpers = {
    # get item data by ID
    getItem = id: let
      idStr = toString id;
    in
      if itemsById ? ${idStr}
      then itemsById.${idStr}
      else null;

    # get gem data by ID
    getGem = id: let
      idStr = toString id;
    in
      if gemsById ? ${idStr}
      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;
    in
      if enchantsByEffectId ? ${idStr}
      then enchantsByEffectId.${idStr}
      else null;

    # get reforge data by ID
    getReforge = reforgeId: let
      idStr = toString reforgeId;
    in
      if reforgeData ? ${idStr}
      then reforgeData.${idStr}
      else null;

    # get glyph data by ID (from wowsims dat
abase)
    getGlyph = glyphId: let
      idStr = toString glyphId;
    in
      if glyphsById ? ${idStr}
      then glyphsById.${idStr}
      else null;

    # get glyph data from our custom glyph d
atabase
    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} o
r {};
      tierTalents = classTalents.${tierStr} 
or {};
    in
      if tierTalents ? ${choiceStr}
      then tierTalents.${choiceStr}
      else null;

    # parse talent string into individual ch
oices
    parseTalentString = talentString: let
      # Convert string to list of characters
, then to list of numbers
      chars = lib.stringToCharacters talentS
tring;
      # 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} object
s, filtering out invalid choices (0)
      indexedChoices = lib.imap1 (tier: choi
ce: {inherit tier choice;}) choices;
      validChoices = lib.filter (choice: cho
ice.choice != 0) indexedChoices;
    in
      validChoices;

    # parse gem stats into readable format
    parseGemStats = gem:
      if gem ? stats
      then let
        # find non-zero stats and convert to
 readable format
        indexedStats = lib.imap0 (index: val
ue: {inherit index value;}) gem.stats;
        activeStats = lib.filter (stat: stat
.value > 0) indexedStats;
        statDescriptions =
          map (
            stat: let
              statName = statIndexNames.${to
String stat.index} or "Unknown Stat";
            in "+${toString stat.value} ${st
atName}"
          )
          activeStats;
      in
        statDescriptions
      else [];

    # enrich a single gem with stats
    enrichGem = gemId:
      if gemId != null && gemId != 0
      then let
        gem = helpers.getGem gemId;
      in
        if gem != null
        then let
          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;
          stats = stats;
        }
        else null
      else null;

    # enrich enchant info
    enrichEnchant = enchantId:
      if enchantId != null && enchantId != 0
      then {
        id = enchantId;
        name = let
          enchant = helpers.getEnchant encha
ntId;
        in
          if enchant != null
          then enchant.name
          else "Unknown Enchant ${toString e
nchantId}";
      }
      else null;

    # enrich reforge info
    enrichReforge = reforgeId:
      if reforgeId != null && reforgeId != 0
      then {
        id = reforgeId;
        description = let
          reforge = helpers.getReforge refor
geId;
        in
          if reforge != null
          then let
            fromStat = statNames.${reforge.s
1} or reforge.s1;
            toStat = statNames.${reforge.s2}
 or reforge.s2;
          in "${fromStat} -> ${toStat}"
          else "Unknown Reforge ${toString r
eforgeId}";
      }
      else null;

    # enrich a single equipment item
    enrichItem = item:
      if !(item ? id)
      then item
      else let
        itemData = helpers.getItem item.id;
        enrichedGems =
          if item ? gems
          then lib.filter (gem: gem != null)
 (map helpers.enrichGem item.gems)
          else [];
        enrichedEnchant =
          if item ? enchant
          then helpers.enrichEnchant item.en
chant
          else null;
        enrichedReforge =
          if item ? reforging
          then helpers.enrichReforge item.re
forging
          else null;

        # Extract item stats from scalingOpt
ions if available
        itemStats =
          if itemData != null && itemData ? 
scalingOptions && itemData.scalingOptions ? 
"0"
          then itemData.scalingOptions."0"
          else null;
      in
        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 != n
ull) {
          stats = itemStats;
        }
        // lib.optionalAttrs (enrichedGems !
= []) {
          gems = enrichedGems;
        }
        // lib.optionalAttrs (enrichedEnchan
t != null) {
          enchant = enrichedEnchant;
        }
        // lib.optionalAttrs (enrichedReforg
e != null) {
          reforging = enrichedReforge;
        };
  };
in {
  # get item data by ID
  getItem = helpers.getItem;

  # get just the item name by ID
  getItemName = id: let
    item = helpers.getItem id;
  in
    if item != null
    then item.name
    else "Unknown Item ${toString id}";

  # get gem data by ID
  getGem = helpers.getGem;

  # get gem name by ID
  getGemName = id: let
    gem = helpers.getGem id;
  in
    if gem != null
    then gem.name
    else "Unknown Gem ${toString id}";

  # parse gem stats into readable format
  parseGemStats = helpers.parseGemStats;

  # get enriched gem data with stats (delega
tes to helpers)
  getEnrichedGem = helpers.enrichGem;

  # get enchant data by effect ID
  getEnchant = helpers.getEnchant;

  # get enchant name by effect ID
  getEnchantName = effectId: let
    enchant = helpers.getEnchant effectId;
  in
    if enchant != null
    then enchant.name
    else "Unknown Enchant ${toString effectI
d}";

  # get reforge data by ID
  getReforge = helpers.getReforge;

  # get reforge description by ID
  getReforgeDescription = reforgeId: let
    reforge = helpers.getReforge reforgeId;
  in
    if reforge != null
    then let
      fromStat = statNames.${reforge.s1} or 
reforge.s1;
      toStat = statNames.${reforge.s2} or re
forge.s2;
    in "${fromStat} -> ${toStat}"
    else "Unknown Reforge ${toString reforge
Id}";

  # get glyph data by ID
  getGlyph = helpers.getGlyph;

  # get glyph name by ID
  getGlyphName = glyphId: let
    glyph = helpers.getGlyph glyphId;
    item =
      if glyph != null
      then helpers.getItem glyph.itemId
      else null;
  in
    if item != null
    then item.name
    else "Unknown Glyph ${toString glyphId}"
;

  # enrich equipment item with name and othe
r data
  enrichEquipmentItem = helpers.enrichItem;

  # enrich an entire equipment array
  enrichEquipment = equipment:
    if equipment ? items
    then
      equipment
      // {
        items = map helpers.enrichItem equip
ment.items;
      }
    else equipment;

  # enrich consumables with item names and i
cons
  enrichConsumables = consumables:
    if consumables == null
    then null
    else let
      getConsumableDataSafe = id: let
        consumable = helpers.getConsumable i
d;
      in
        if consumable != null
        then {
          name = consumable.name;
          icon =
            if consumable ? icon
            then consumable.icon
            else null;
        }
        else {
          name = "Consumable ${toString id}"
;
          icon = null;
        };
    in
      consumables
      // lib.optionalAttrs (consumables ? fl
askId && consumables.flaskId != 0) (
        let
          flaskData = getConsumableDataSafe 
consumables.flaskId;
        in {
          flaskName = flaskData.name;
          flaskIcon = flaskData.icon;
        }
      )
      // lib.optionalAttrs (consumables ? fo
odId && consumables.foodId != 0) (
        let
          foodData = getConsumableDataSafe c
onsumables.foodId;
        in {
          foodName = foodData.name;
          foodIcon = foodData.icon;
        }
      )
      // lib.optionalAttrs (consumables ? po
tId && consumables.potId != 0) (
        let
          potData = getConsumableDataSafe co
nsumables.potId;
        in {
          potName = potData.name;
          potIcon = potData.icon;
        }
      )
      // lib.optionalAttrs (consumables ? pr
epotId && consumables.prepotId != 0) (
        let
          prepotData = getConsumableDataSafe
 consumables.prepotId;
        in {
          prepotName = prepotData.name;
          prepotIcon = prepotData.icon;
        }
      );

  # enrich glyphs with names and icons from 
glyph database
  enrichGlyphs = className: glyphs:
    if glyphs == null
    then null
    else let
      getGlyphDataSafe = glyphId: let
        glyphData = helpers.getGlyphData cla
ssName glyphId;
      in
        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;
          spellId = null;
        };
    in
      glyphs
      // lib.optionalAttrs (glyphs ? major1 
&& glyphs.major1 != 0) (
        let
          glyphData = getGlyphDataSafe glyph
s.major1;
        in {
          major1Name = glyphData.name;
          major1Icon = glyphData.icon;
          major1SpellId = glyphData.spellId;
        }
      )
      // lib.optionalAttrs (glyphs ? major2 
&& glyphs.major2 != 0) (
        let
          glyphData = getGlyphDataSafe glyph
s.major2;
        in {
          major2Name = glyphData.name;
          major2Icon = glyphData.icon;
          major2SpellId = glyphData.spellId;
        }
      )
      // lib.optionalAttrs (glyphs ? major3 
&& glyphs.major3 != 0) (
        let
          glyphData = getGlyphDataSafe glyph
s.major3;
        in {
          major3Name = glyphData.name;
          major3Icon = glyphData.icon;
          major3SpellId = glyphData.spellId;
        }
      )
      // lib.optionalAttrs (glyphs ? minor1 
&& glyphs.minor1 != 0) (
        let
          glyphData = getGlyphDataSafe glyph
s.minor1;
        in {
          minor1Name = glyphData.name;
          minor1Icon = glyphData.icon;
          minor1SpellId = glyphData.spellId;
        }
      )
      // lib.optionalAttrs (glyphs ? minor2 
&& glyphs.minor2 != 0) (
        let
          glyphData = getGlyphDataSafe glyph
s.minor2;
        in {
          minor2Name = glyphData.name;
          minor2Icon = glyphData.icon;
          minor2SpellId = glyphData.spellId;
        }
      )
      // lib.optionalAttrs (glyphs ? minor3 
&& glyphs.minor3 != 0) (
        let
          glyphData = getGlyphDataSafe glyph
s.minor3;
        in {
          minor3Name = glyphData.name;
          minor3Icon = glyphData.icon;
          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.parseTalentStr
ing 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 =
          if loadout.equipment ? items
          then
            loadout.equipment
            // {
              items = map helpers.enrichItem
 loadout.equipment.items;
            }
          else loadout.equipment;
        # TODO: Add consumables, gems, encha
nts enrichment
      }
    else loadout;

  # enrich simulation results (main function
)
  enrichSimulationData = simData:
    if simData ? results
    then
      simData
      // {
        results =
          lib.mapAttrs (
            _name: result:
              if result ? loadout
              then
                result
                // {
                  loadout =
                    if result.loadout ? equi
pment && result.loadout.equipment ? items
                    then
                      result.loadout
                      // {
                        equipment =
                          result.loadout.equ
ipment
                          // {
                            items = map help
ers.enrichItem result.loadout.equipment.item
s;
                          };
                        # TODO: Add consumab
les, gems, enchants enrichment
                      }
                    else result.loadout;
                }
              else result
          )
          simData.results;
      }
    else simData;
}
 
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET