OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      3492ffad1950
DATE      2025-07-27
SUBJECT   nix: itemDatabase lib init
FILES     4 CHANGED
HASH      3492ffad1950
DATE      2025-07-27
SUBJECT   nix: itemDatabase lib init
FILES     4 CHANGED
 

diff --git a/nix/apps/default.nix b/nix/apps/default.nix
index 65bf09e..5aa4045 100644
--- a/nix/apps/default.nix
+++ b/nix/apps/default.nix
@@ -8,8 +8,30 @@
   ...
 }: {
   perSystem = {pkgs, ...}: let
+    inherit (pkgs) callPackage writeShellApplication;
     simulation = import ./simulation {inherit lib classes encounter buffs debuffs
 inputs pkgs;};
+    getDB = callPackage ./getDB.nix { inherit inputs; };
+    testItemLookup = callPackage ./testItemLookup.nix { inherit inputs lib; };
+    testEnrichmentOutput = callPackage ./testEnrichmentOutput.nix { inherit input
s lib; };
+    testEquipmentEnrichment = callPackage ./testEquipmentEnrichment.nix { inherit
 inputs lib; };
   in {
-    apps = simulation;
+    apps = simulation // {
+      getDB = {
+        type = "app";
+        program = "${getDB}/bin/getDB";
+      };
+      testItemLookup = {
+        type = "app";
+        program = "${testItemLookup}/bin/testItemLookup";
+      };
+      testEnrichmentOutput = {
+        type = "app";
+        program = "${testEnrichmentOutput}/bin/testEnrichmentOutput";
+      };
+      testEquipmentEnrichment = {
+        type = "app";
+        program = "${testEquipmentEnrichment}/bin/testEquipmentEnrichment";
+      };
+    };
   };
 }

diff --git a/nix/apps/default.nix b/nix/apps
/default.nix
index 65bf09e..5aa4045 100644
--- a/nix/apps/default.nix
+++ b/nix/apps/default.nix
@@ -8,8 +8,30 @@
   ...
 }: {
   perSystem = {pkgs, ...}: let
+    inherit (pkgs) callPackage writeShellAp
plication;
     simulation = import ./simulation {inher
it lib classes encounter buffs debuffs input
s pkgs;};
+    getDB = callPackage ./getDB.nix { inher
it inputs; };
+    testItemLookup = callPackage ./testItem
Lookup.nix { inherit inputs lib; };
+    testEnrichmentOutput = callPackage ./te
stEnrichmentOutput.nix { inherit inputs lib;
 };
+    testEquipmentEnrichment = callPackage .
/testEquipmentEnrichment.nix { inherit input
s lib; };
   in {
-    apps = simulation;
+    apps = simulation // {
+      getDB = {
+        type = "app";
+        program = "${getDB}/bin/getDB";
+      };
+      testItemLookup = {
+        type = "app";
+        program = "${testItemLookup}/bin/te
stItemLookup";
+      };
+      testEnrichmentOutput = {
+        type = "app";
+        program = "${testEnrichmentOutput}/
bin/testEnrichmentOutput";
+      };
+      testEquipmentEnrichment = {
+        type = "app";
+        program = "${testEquipmentEnrichmen
t}/bin/testEquipmentEnrichment";
+      };
+    };
   };
 }
 

diff --git a/nix/apps/simulation/mkMassSim.nix b/nix/apps/simulation/mkMassSim.nix
index 9eb3905..b1e8a1c 100644
--- a/nix/apps/simulation/mkMassSim.nix
+++ b/nix/apps/simulation/mkMassSim.nix
@@ -10,6 +10,7 @@
 }: let
   # TODO: this is cursed, consolidate the functions.
   inherit (lib.sim.simulation) mkSim;
+  inherit (lib.sim) itemDatabase;
 
   # extract playable races from class definitions
   getPlayableRaces = className:
@@ -101,6 +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
+          enrichedEquipment = itemDatabase.enrichEquipment raceConfig.config.equi
pment;
+          enrichedConsumables = itemDatabase.enrichConsumables raceConfig.config.
consumables;
+          enrichedGlyphs = itemDatabase.enrichGlyphs raceConfig.config.glyphs;
+
           simInput = mkSim {
             inherit iterations;
             player = raceConfig.config;
@@ -113,9 +119,22 @@
             buildInputs = [pkgs.jq];
             nativeBuildInputs = [inputs.wowsims.packages.${pkgs.system}.wowsimcli
];
           } ''
-            cat > input.json << 'EOF'
-            ${simInput}
-            EOF
+            # Write enriched JSON data to files using cat with EOF to handle any 
quotes safely
+            cat > enriched_equipment.json << 'EQUIPMENT_EOF'
+${builtins.toJSON enrichedEquipment}
+EQUIPMENT_EOF
+            
+            cat > consumables.json << 'CONSUMABLES_EOF'
+${builtins.toJSON enrichedConsumables}
+CONSUMABLES_EOF
+            
+            cat > glyphs.json << 'GLYPHS_EOF'
+${builtins.toJSON enrichedGlyphs}
+GLYPHS_EOF
+            
+            cat > input.json << 'INPUT_EOF'
+${simInput}
+INPUT_EOF
 
             echo "Running ${raceConfig.className}/${raceConfig.specName}/${raceCo
nfig.raceName} simulation..."
             if wowsimcli sim --infile input.json --outfile output.json; then
@@ -125,33 +144,37 @@
               minDps=$(jq -r '.raidMetrics.dps.min // 0' output.json)
               stdevDps=$(jq -r '.raidMetrics.dps.stdev // 0' output.json)
 
-              # construct loadout info
-              loadout=$(echo '${builtins.toJSON raceConfig.config}' | jq '{
-                consumables,
-                talentsString,
-                glyphs,
-                equipment,
-                race,
-                class,
-                profession1,
-                profession2
-              }')
-
-              # create final result
+              # create final result with enriched data
               jq -n \
                 --arg raceName "${raceConfig.raceName}" \
                 --arg avgDps "$avgDps" \
                 --arg maxDps "$maxDps" \
                 --arg minDps "$minDps" \
                 --arg stdevDps "$stdevDps" \
-                --argjson loadout "$loadout" \
+                --slurpfile equipment enriched_equipment.json \
+                --slurpfile consumables consumables.json \
+                --arg talentsString "${raceConfig.config.talentsString}" \
+                --slurpfile glyphs glyphs.json \
+                --arg race "${raceConfig.config.race}" \
+                --arg class "${raceConfig.config.class}" \
+                --arg profession1 "${raceConfig.config.profession1}" \
+                --arg profession2 "${raceConfig.config.profession2}" \
                 '{
                   race: $raceName,
                   dps: ($avgDps | tonumber),
                   max: ($maxDps | tonumber),
                   min: ($minDps | tonumber),
                   stdev: ($stdevDps | tonumber),
-                  loadout: $loadout
+                  loadout: {
+                    consumables: $consumables[0],
+                    talentsString: $talentsString,
+                    glyphs: $glyphs[0],
+                    equipment: $equipment[0],
+                    race: $race,
+                    class: $class,
+                    profession1: $profession1,
+                    profession2: $profession2
+                  }
                 }' > $out
             else
               echo "Simulation failed for ${raceConfig.className}/${raceConfig.sp
ecName}/${raceConfig.raceName}"
@@ -301,6 +324,11 @@
     simDerivations = lib.listToAttrs (map (spec: {
         name = "${spec.className}-${spec.specName}";
         value = let
+          # Pre-enrich the equipment, consumables, and glyphs for this spec
+          enrichedEquipment = itemDatabase.enrichEquipment spec.config.equipment;
+          enrichedConsumables = itemDatabase.enrichConsumables spec.config.consum
ables;
+          enrichedGlyphs = itemDatabase.enrichGlyphs spec.config.glyphs;
+          
           simInput = mkSim {
             inherit iterations;
             player = spec.config;
@@ -313,10 +341,22 @@
             buildInputs = [pkgs.jq];
             nativeBuildInputs = [inputs.wowsims.packages.${pkgs.system}.wowsimcli
];
           } ''
-            # Generate input JSON file using HERE document approach (same as test
-composition)
-            cat > input.json << 'EOF'
-            ${simInput}
-            EOF
+            # Write enriched JSON data to files using cat with EOF to handle any 
quotes safely
+            cat > enriched_equipment.json << 'EQUIPMENT_EOF'
+${builtins.toJSON enrichedEquipment}
+EQUIPMENT_EOF
+            
+            cat > consumables.json << 'CONSUMABLES_EOF'
+${builtins.toJSON enrichedConsumables}
+CONSUMABLES_EOF
+            
+            cat > glyphs.json << 'GLYPHS_EOF'
+${builtins.toJSON enrichedGlyphs}
+GLYPHS_EOF
+            
+            cat > input.json << 'INPUT_EOF'
+${simInput}
+INPUT_EOF
 
             echo "Running ${spec.className}/${spec.specName} simulation..."
             if wowsimcli sim --infile input.json --outfile output.json; then
@@ -326,20 +366,7 @@
               minDps=$(jq -r '.raidMetrics.dps.min // 0' output.json)
               stdevDps=$(jq -r '.raidMetrics.dps.stdev // 0' output.json)
 
-              # create loadout without rotation (only keep consumables, talents, 
glyphs, gear)
-              # TODO: should we output the apl?
-              loadout=$(echo '${builtins.toJSON spec.config}' | jq '{
-                consumables,
-                talentsString,
-                glyphs,
-                equipment,
-                race,
-                class,
-                profession1,
-                profession2
-              }')
-
-              # create final result with all DPS statistics
+              # create final result with all DPS statistics and enriched data
               jq -n \
                 --arg className "${spec.className}" \
                 --arg specName "${spec.specName}" \
@@ -347,7 +374,14 @@
                 --arg maxDps "$maxDps" \
                 --arg minDps "$minDps" \
                 --arg stdevDps "$stdevDps" \
-                --argjson loadout "$loadout" \
+                --slurpfile equipment enriched_equipment.json \
+                --slurpfile consumables consumables.json \
+                --arg talentsString "${spec.config.talentsString}" \
+                --slurpfile glyphs glyphs.json \
+                --arg race "${spec.config.race}" \
+                --arg class "${spec.config.class}" \
+                --arg profession1 "${spec.config.profession1}" \
+                --arg profession2 "${spec.config.profession2}" \
                 '{
                   className: $className,
                   specName: $specName,
@@ -355,7 +389,16 @@
                   max: ($maxDps | tonumber),
                   min: ($minDps | tonumber),
                   stdev: ($stdevDps | tonumber),
-                  loadout: $loadout
+                  loadout: {
+                    consumables: $consumables[0],
+                    talentsString: $talentsString,
+                    glyphs: $glyphs[0],
+                    equipment: $equipment[0],
+                    race: $race,
+                    class: $class,
+                    profession1: $profession1,
+                    profession2: $profession2
+                  }
                 }' > $out
             else
               echo "Simulation failed for ${spec.className}/${spec.specName}"

diff --git a/nix/apps/simulation/mkMassSim.n
ix b/nix/apps/simulation/mkMassSim.nix
index 9eb3905..b1e8a1c 100644
--- a/nix/apps/simulation/mkMassSim.nix
+++ b/nix/apps/simulation/mkMassSim.nix
@@ -10,6 +10,7 @@
 }: let
   # TODO: this is cursed, consolidate the f
unctions.
   inherit (lib.sim.simulation) mkSim;
+  inherit (lib.sim) itemDatabase;
 
   # extract playable races from class defin
itions
   getPlayableRaces = className:
@@ -101,6 +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
+          enrichedEquipment = itemDatabase.
enrichEquipment raceConfig.config.equipment;
+          enrichedConsumables = itemDatabas
e.enrichConsumables raceConfig.config.consum
ables;
+          enrichedGlyphs = itemDatabase.enr
ichGlyphs raceConfig.config.glyphs;
+
           simInput = mkSim {
             inherit iterations;
             player = raceConfig.config;
@@ -113,9 +119,22 @@
             buildInputs = [pkgs.jq];
             nativeBuildInputs = [inputs.wow
sims.packages.${pkgs.system}.wowsimcli];
           } ''
-            cat > input.json << 'EOF'
-            ${simInput}
-            EOF
+            # Write enriched JSON data to f
iles using cat with EOF to handle any quotes
 safely
+            cat > enriched_equipment.json <
< 'EQUIPMENT_EOF'
+${builtins.toJSON enrichedEquipment}
+EQUIPMENT_EOF
+            
+            cat > consumables.json << 'CONS
UMABLES_EOF'
+${builtins.toJSON enrichedConsumables}
+CONSUMABLES_EOF
+            
+            cat > glyphs.json << 'GLYPHS_EO
F'
+${builtins.toJSON enrichedGlyphs}
+GLYPHS_EOF
+            
+            cat > input.json << 'INPUT_EOF'
+${simInput}
+INPUT_EOF
 
             echo "Running ${raceConfig.clas
sName}/${raceConfig.specName}/${raceConfig.r
aceName} simulation..."
             if wowsimcli sim --infile input
.json --outfile output.json; then
@@ -125,33 +144,37 @@
               minDps=$(jq -r '.raidMetrics.
dps.min // 0' output.json)
               stdevDps=$(jq -r '.raidMetric
s.dps.stdev // 0' output.json)
 
-              # construct loadout info
-              loadout=$(echo '${builtins.to
JSON raceConfig.config}' | jq '{
-                consumables,
-                talentsString,
-                glyphs,
-                equipment,
-                race,
-                class,
-                profession1,
-                profession2
-              }')
-
-              # create final result
+              # create final result with en
riched data
               jq -n \
                 --arg raceName "${raceConfi
g.raceName}" \
                 --arg avgDps "$avgDps" \
                 --arg maxDps "$maxDps" \
                 --arg minDps "$minDps" \
                 --arg stdevDps "$stdevDps" 
\
-                --argjson loadout "$loadout
" \
+                --slurpfile equipment enric
hed_equipment.json \
+                --slurpfile consumables con
sumables.json \
+                --arg talentsString "${race
Config.config.talentsString}" \
+                --slurpfile glyphs glyphs.j
son \
+                --arg race "${raceConfig.co
nfig.race}" \
+                --arg class "${raceConfig.c
onfig.class}" \
+                --arg profession1 "${raceCo
nfig.config.profession1}" \
+                --arg profession2 "${raceCo
nfig.config.profession2}" \
                 '{
                   race: $raceName,
                   dps: ($avgDps | tonumber)
,
                   max: ($maxDps | tonumber)
,
                   min: ($minDps | tonumber)
,
                   stdev: ($stdevDps | tonum
ber),
-                  loadout: $loadout
+                  loadout: {
+                    consumables: $consumabl
es[0],
+                    talentsString: $talents
String,
+                    glyphs: $glyphs[0],
+                    equipment: $equipment[0
],
+                    race: $race,
+                    class: $class,
+                    profession1: $professio
n1,
+                    profession2: $professio
n2
+                  }
                 }' > $out
             else
               echo "Simulation failed for $
{raceConfig.className}/${raceConfig.specName
}/${raceConfig.raceName}"
@@ -301,6 +324,11 @@
     simDerivations = lib.listToAttrs (map (
spec: {
         name = "${spec.className}-${spec.sp
ecName}";
         value = let
+          # Pre-enrich the equipment, consu
mables, and glyphs for this spec
+          enrichedEquipment = itemDatabase.
enrichEquipment spec.config.equipment;
+          enrichedConsumables = itemDatabas
e.enrichConsumables spec.config.consumables;
+          enrichedGlyphs = itemDatabase.enr
ichGlyphs spec.config.glyphs;
+          
           simInput = mkSim {
             inherit iterations;
             player = spec.config;
@@ -313,10 +341,22 @@
             buildInputs = [pkgs.jq];
             nativeBuildInputs = [inputs.wow
sims.packages.${pkgs.system}.wowsimcli];
           } ''
-            # Generate input JSON file usin
g HERE document approach (same as test-compo
sition)
-            cat > input.json << 'EOF'
-            ${simInput}
-            EOF
+            # Write enriched JSON data to f
iles using cat with EOF to handle any quotes
 safely
+            cat > enriched_equipment.json <
< 'EQUIPMENT_EOF'
+${builtins.toJSON enrichedEquipment}
+EQUIPMENT_EOF
+            
+            cat > consumables.json << 'CONS
UMABLES_EOF'
+${builtins.toJSON enrichedConsumables}
+CONSUMABLES_EOF
+            
+            cat > glyphs.json << 'GLYPHS_EO
F'
+${builtins.toJSON enrichedGlyphs}
+GLYPHS_EOF
+            
+            cat > input.json << 'INPUT_EOF'
+${simInput}
+INPUT_EOF
 
             echo "Running ${spec.className}
/${spec.specName} simulation..."
             if wowsimcli sim --infile input
.json --outfile output.json; then
@@ -326,20 +366,7 @@
               minDps=$(jq -r '.raidMetrics.
dps.min // 0' output.json)
               stdevDps=$(jq -r '.raidMetric
s.dps.stdev // 0' output.json)
 
-              # create loadout without rota
tion (only keep consumables, talents, glyphs
, gear)
-              # TODO: should we output the 
apl?
-              loadout=$(echo '${builtins.to
JSON spec.config}' | jq '{
-                consumables,
-                talentsString,
-                glyphs,
-                equipment,
-                race,
-                class,
-                profession1,
-                profession2
-              }')
-
-              # create final result with al
l DPS statistics
+              # create final result with al
l DPS statistics and enriched data
               jq -n \
                 --arg className "${spec.cla
ssName}" \
                 --arg specName "${spec.spec
Name}" \
@@ -347,7 +374,14 @@
                 --arg maxDps "$maxDps" \
                 --arg minDps "$minDps" \
                 --arg stdevDps "$stdevDps" 
\
-                --argjson loadout "$loadout
" \
+                --slurpfile equipment enric
hed_equipment.json \
+                --slurpfile consumables con
sumables.json \
+                --arg talentsString "${spec
.config.talentsString}" \
+                --slurpfile glyphs glyphs.j
son \
+                --arg race "${spec.config.r
ace}" \
+                --arg class "${spec.config.
class}" \
+                --arg profession1 "${spec.c
onfig.profession1}" \
+                --arg profession2 "${spec.c
onfig.profession2}" \
                 '{
                   className: $className,
                   specName: $specName,
@@ -355,7 +389,16 @@
                   max: ($maxDps | tonumber)
,
                   min: ($minDps | tonumber)
,
                   stdev: ($stdevDps | tonum
ber),
-                  loadout: $loadout
+                  loadout: {
+                    consumables: $consumabl
es[0],
+                    talentsString: $talents
String,
+                    glyphs: $glyphs[0],
+                    equipment: $equipment[0
],
+                    race: $race,
+                    class: $class,
+                    profession1: $professio
n1,
+                    profession2: $professio
n2
+                  }
                 }' > $out
             else
               echo "Simulation failed for $
{spec.className}/${spec.specName}"
 

diff --git a/nix/lib/default.nix b/nix/lib/default.nix
index 2305572..0cb55f4 100644
--- a/nix/lib/default.nix
+++ b/nix/lib/default.nix
@@ -11,4 +11,5 @@
   simulation = import ./simulation.nix {inherit lib;};
   party = import ./party.nix {inherit lib;};
   classes = import ./classes.nix {inherit lib;};
+  itemDatabase = import ./itemDatabase.nix {inherit inputs lib;};
 }

diff --git a/nix/lib/default.nix b/nix/lib/d
efault.nix
index 2305572..0cb55f4 100644
--- a/nix/lib/default.nix
+++ b/nix/lib/default.nix
@@ -11,4 +11,5 @@
   simulation = import ./simulation.nix {inh
erit lib;};
   party = import ./party.nix {inherit lib;}
;
   classes = import ./classes.nix {inherit l
ib;};
+  itemDatabase = import ./itemDatabase.nix 
{inherit inputs lib;};
 }
 

diff --git a/nix/lib/itemDatabase.nix b/nix/lib/itemDatabase.nix
new file mode 100644
index 0000000..b0b9b4f
--- /dev/null
+++ b/nix/lib/itemDatabase.nix
@@ -0,0 +1,486 @@
+{
+  inputs,
+  lib,
+  ...
+}: let
+  wowsimsDb = lib.importJSON "${inputs.wowsims}/assets/database/db.json";
+
+  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);
+
+  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 = {
+    "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";
+    };
+  };
+
+  # 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 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
+    getGlyph = glyphId: let
+      idStr = toString glyphId;
+    in
+      if glyphsById ? ${idStr}
+      then glyphsById.${idStr}
+      else null;
+
+    # 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;
+          description =
+            if stats != []
+            then "${gem.name} -- ${lib.concatStringsSep ", " stats}"
+            else gem.name;
+        }
+        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.
scalingOptions ? "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) {
+          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
+      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}";
+          icon = null;
+          quality = null;
+        };
+    in
+      consumables // lib.optionalAttrs (consumables ? flaskId && consumables.flas
kId != 0) (
+        let flaskData = getItemDataSafe 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 {
+          foodName = foodData.name;
+          foodIcon = foodData.icon;
+          foodQuality = foodData.quality;
+        }
+      ) // lib.optionalAttrs (consumables ? potId && consumables.potId != 0) (
+        let potData = getItemDataSafe 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 {
+          prepotName = prepotData.name;
+          prepotIcon = prepotData.icon;
+          prepotQuality = prepotData.quality;
+        }
+      );
+
+  # enrich glyphs with item names and icons
+  enrichGlyphs = 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;
+      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;
+        } else {
+          name = "Glyph ${toString glyphId}";
+          icon = null;
+          quality = null;
+          spellId = null;
+        };
+    in
+      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 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 ? i
tems
+                    then
+                      result.loadout
+                      // {
+                        equipment = result.loadout.equipment
+                        // {
+                          items = map helpers.enrichItem result.loadout.equipment
.items;
+                        };
+                        # TODO: Add consumables, gems, enchants enrichment
+                      }
+                    else result.loadout;
+                }
+              else result
+          )
+          simData.results;
+      }
+    else simData;
+}
+

diff --git a/nix/lib/itemDatabase.nix b/nix/
lib/itemDatabase.nix
new file mode 100644
index 0000000..b0b9b4f
--- /dev/null
+++ b/nix/lib/itemDatabase.nix
@@ -0,0 +1,486 @@
+{
+  inputs,
+  lib,
+  ...
+}: let
+  wowsimsDb = lib.importJSON "${inputs.wows
ims}/assets/database/db.json";
+
+  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);
+
+  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 = {
+    "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";
+    };
+  };
+
+  # 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/ite
ms)
+  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 oper
ations
+  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 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
+    getGlyph = glyphId: let
+      idStr = toString glyphId;
+    in
+      if glyphsById ? ${idStr}
+      then glyphsById.${idStr}
+      else null;
+
+    # parse gem stats into readable format
+    parseGemStats = gem:
+      if gem ? stats
+      then let
+        # find non-zero stats and convert t
o readable format
+        indexedStats = lib.imap0 (index: va
lue: {inherit index value;}) gem.stats;
+        activeStats = lib.filter (stat: sta
t.value > 0) indexedStats;
+        statDescriptions =
+          map (
+            stat: let
+              statName = statIndexNames.${t
oString stat.index} or "Unknown Stat";
+            in "+${toString stat.value} ${s
tatName}"
+          )
+          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.ico
n else null;
+          color = if gem ? color then gem.c
olor else null;
+          quality = if gem ? quality then g
em.quality else null;
+          stats = stats;
+          description =
+            if stats != []
+            then "${gem.name} -- ${lib.conc
atStringsSep ", " stats}"
+            else gem.name;
+        }
+        else null
+      else null;
+
+    # enrich enchant info
+    enrichEnchant = enchantId:
+      if enchantId != null && enchantId != 
0
+      then {
+        id = enchantId;
+        name = let
+          enchant = helpers.getEnchant ench
antId;
+        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 refo
rgeId;
+        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.e
nchant
+          else null;
+        enrichedReforge = if item ? reforgi
ng 
+          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"
+          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) {
+          stats = itemStats;
+        } // lib.optionalAttrs (enrichedGem
s != []) {
+          gems = enrichedGems;
+        } // lib.optionalAttrs (enrichedEnc
hant != null) {
+          enchant = enrichedEnchant;
+        } // lib.optionalAttrs (enrichedRef
orge != 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 (deleg
ates 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 effect
Id}";
+
+  # 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 r
eforge.s2;
+    in "${fromStat} -> ${toStat}"
+    else "Unknown Reforge ${toString reforg
eId}";
+
+  # 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.ge
tItem glyph.itemId else null;
+  in
+    if item != null then item.name else "Un
known Glyph ${toString glyphId}";
+
+  # enrich equipment item with name and oth
er data
+  enrichEquipmentItem = helpers.enrichItem;
+
+  # enrich an entire equipment array
+  enrichEquipment = equipment:
+    if equipment ? items
+    then
+      equipment
+      // {
+        items = map helpers.enrichItem equi
pment.items;
+      }
+    else equipment;
+
+  # enrich consumables with item names and 
icons
+  enrichConsumables = consumables:
+    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}";
+          icon = null;
+          quality = null;
+        };
+    in
+      consumables // lib.optionalAttrs (con
sumables ? flaskId && consumables.flaskId !=
 0) (
+        let flaskData = getItemDataSafe con
sumables.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 {
+          foodName = foodData.name;
+          foodIcon = foodData.icon;
+          foodQuality = foodData.quality;
+        }
+      ) // lib.optionalAttrs (consumables ?
 potId && consumables.potId != 0) (
+        let potData = getItemDataSafe consu
mables.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 {
+          prepotName = prepotData.name;
+          prepotIcon = prepotData.icon;
+          prepotQuality = prepotData.qualit
y;
+        }
+      );
+
+  # enrich glyphs with item names and icons
+  enrichGlyphs = 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;
+      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;
+        } else {
+          name = "Glyph ${toString glyphId}
";
+          icon = null;
+          quality = null;
+          spellId = null;
+        };
+    in
+      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 a full loadout
+  enrichLoadout = loadout:
+    if loadout ? equipment
+    then
+      loadout
+      // {
+        equipment = 
+          if loadout.equipment ? items
+          then
+            loadout.equipment
+            // {
+              items = map helpers.enrichIte
m loadout.equipment.items;
+            }
+          else loadout.equipment;
+        # TODO: Add consumables, gems, ench
ants enrichment
+      }
+    else loadout;
+
+  # enrich simulation results (main functio
n)
+  enrichSimulationData = simData:
+    if simData ? results
+    then
+      simData
+      // {
+        results =
+          lib.mapAttrs (
+            name: result:
+              if result ? loadout
+              then
+                result
+                // {
+                  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
;
+                        };
+                        # TODO: Add consuma
bles, gems, enchants enrichment
+                      }
+                    else result.loadout;
+                }
+              else result
+          )
+          simData.results;
+      }
+    else simData;
+}
+
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET