diff --git a/assets/database/db.bin b/assets/database/db.bin index cd67a607d6..8612dbed5a 100644 Binary files a/assets/database/db.bin and b/assets/database/db.bin differ diff --git a/assets/database/db.json b/assets/database/db.json index eab802e11c..ffd6eeaaf7 100644 --- a/assets/database/db.json +++ b/assets/database/db.json @@ -9226,6 +9226,64 @@ {"id":38113,"name":"Marwyn","zoneId":4820}, {"id":38433,"name":"Toravon the Ice Watcher","zoneId":4603} ], +"reforgeStats":[ +{"id":113,"fromStat":[4],"toStat":[25],"multiplier":0.4}, +{"id":114,"fromStat":[4],"toStat":[26],"multiplier":0.4}, +{"id":115,"fromStat":[4],"toStat":[12,7],"multiplier":0.4}, +{"id":116,"fromStat":[4],"toStat":[13,8],"multiplier":0.4}, +{"id":117,"fromStat":[4],"toStat":[14,9],"multiplier":0.4}, +{"id":118,"fromStat":[4],"toStat":[16],"multiplier":0.4}, +{"id":119,"fromStat":[4],"multiplier":0.4}, +{"id":120,"fromStat":[25],"toStat":[4],"multiplier":0.4}, +{"id":121,"fromStat":[25],"toStat":[26],"multiplier":0.4}, +{"id":122,"fromStat":[25],"toStat":[12,7],"multiplier":0.4}, +{"id":123,"fromStat":[25],"toStat":[13,8],"multiplier":0.4}, +{"id":124,"fromStat":[25],"toStat":[14,9],"multiplier":0.4}, +{"id":125,"fromStat":[25],"toStat":[16],"multiplier":0.4}, +{"id":126,"fromStat":[25],"multiplier":0.4}, +{"id":127,"fromStat":[26],"toStat":[4],"multiplier":0.4}, +{"id":128,"fromStat":[26],"toStat":[25],"multiplier":0.4}, +{"id":129,"fromStat":[26],"toStat":[12,7],"multiplier":0.4}, +{"id":130,"fromStat":[26],"toStat":[13,8],"multiplier":0.4}, +{"id":131,"fromStat":[26],"toStat":[14,9],"multiplier":0.4}, +{"id":132,"fromStat":[26],"toStat":[16],"multiplier":0.4}, +{"id":133,"fromStat":[26],"multiplier":0.4}, +{"id":134,"fromStat":[12,7],"toStat":[4],"multiplier":0.4}, +{"id":135,"fromStat":[12,7],"toStat":[25],"multiplier":0.4}, +{"id":136,"fromStat":[12,7],"toStat":[26],"multiplier":0.4}, +{"id":137,"fromStat":[12,7],"toStat":[13,8],"multiplier":0.4}, +{"id":138,"fromStat":[12,7],"toStat":[14,9],"multiplier":0.4}, +{"id":139,"fromStat":[12,7],"toStat":[16],"multiplier":0.4}, +{"id":140,"fromStat":[12,7],"multiplier":0.4}, +{"id":141,"fromStat":[13,8],"toStat":[4],"multiplier":0.4}, +{"id":142,"fromStat":[13,8],"toStat":[25],"multiplier":0.4}, +{"id":143,"fromStat":[13,8],"toStat":[26],"multiplier":0.4}, +{"id":144,"fromStat":[13,8],"toStat":[12,7],"multiplier":0.4}, +{"id":145,"fromStat":[13,8],"toStat":[14,9],"multiplier":0.4}, +{"id":146,"fromStat":[13,8],"toStat":[16],"multiplier":0.4}, +{"id":147,"fromStat":[13,8],"multiplier":0.4}, +{"id":148,"fromStat":[14,9],"toStat":[4],"multiplier":0.4}, +{"id":149,"fromStat":[14,9],"toStat":[25],"multiplier":0.4}, +{"id":150,"fromStat":[14,9],"toStat":[26],"multiplier":0.4}, +{"id":151,"fromStat":[14,9],"toStat":[12,7],"multiplier":0.4}, +{"id":152,"fromStat":[14,9],"toStat":[13,8],"multiplier":0.4}, +{"id":153,"fromStat":[14,9],"toStat":[16],"multiplier":0.4}, +{"id":154,"fromStat":[14,9],"multiplier":0.4}, +{"id":155,"fromStat":[16],"toStat":[4],"multiplier":0.4}, +{"id":156,"fromStat":[16],"toStat":[25],"multiplier":0.4}, +{"id":157,"fromStat":[16],"toStat":[26],"multiplier":0.4}, +{"id":158,"fromStat":[16],"toStat":[12,7],"multiplier":0.4}, +{"id":159,"fromStat":[16],"toStat":[13,8],"multiplier":0.4}, +{"id":160,"fromStat":[16],"toStat":[14,9],"multiplier":0.4}, +{"id":161,"fromStat":[16],"multiplier":0.4}, +{"id":162,"toStat":[4],"multiplier":0.4}, +{"id":163,"toStat":[25],"multiplier":0.4}, +{"id":164,"toStat":[26],"multiplier":0.4}, +{"id":165,"toStat":[12,7],"multiplier":0.4}, +{"id":166,"toStat":[13,8],"multiplier":0.4}, +{"id":167,"toStat":[14,9],"multiplier":0.4}, +{"id":168,"toStat":[16],"multiplier":0.4} +], "itemIcons":[ {"id":7676,"name":"Thistle Tea","icon":"inv_drink_milk_05"}, {"id":9088,"name":"Gift of Arthas","icon":"inv_potion_28"}, @@ -11008,6 +11066,7 @@ {"id":34296,"name":"Pyromaniac","icon":"spell_fire_burnout"}, {"id":34297,"name":"Improved Leader of the Pack","icon":"spell_nature_unyeildingstamina"}, {"id":34300,"name":"Improved Leader of the Pack","icon":"spell_nature_unyeildingstamina"}, +{"id":34433,"name":"Shadowfiend","icon":"spell_shadow_shadowfiend"}, {"id":34453,"name":"Animal Handler","icon":"ability_hunter_animalhandler"}, {"id":34454,"name":"Animal Handler","icon":"ability_hunter_animalhandler"}, {"id":34455,"name":"Ferocious Inspiration","icon":"ability_hunter_ferociousinspiration"}, @@ -11845,6 +11904,7 @@ {"id":52803,"name":"Twin Disciplines","icon":"spell_holy_sealofvengeance"}, {"id":52858,"name":"Culling the Herd","icon":"inv_misc_monsterhorn_06"}, {"id":53007,"name":"Penance","icon":"spell_holy_penance"}, +{"id":53022,"name":"Mind Sear","icon":"spell_shadow_mindshear"}, {"id":53023,"name":"Mind Sear","icon":"spell_shadow_mindshear"}, {"id":53137,"name":"Abomination's Might","icon":"ability_warrior_intensifyrage"}, {"id":53138,"name":"Abomination's Might","icon":"ability_warrior_intensifyrage"}, @@ -12254,6 +12314,7 @@ {"id":57699,"name":"Fur Lining - Nature Resist","icon":"trade_leatherworking"}, {"id":57701,"name":"Fur Lining - Arcane Resist","icon":"trade_leatherworking"}, {"id":57722,"name":"Totem of Wrath","icon":"spell_fire_totemofwrath"}, +{"id":57724,"name":"Sated","icon":"spell_nature_sleep"}, {"id":57755,"name":"Heroic Throw","icon":"inv_axe_66"}, {"id":57810,"name":"Genesis","icon":"spell_arcane_arcane03"}, {"id":57811,"name":"Genesis","icon":"spell_arcane_arcane03"}, @@ -12374,10 +12435,12 @@ {"id":60185,"name":"Elemental Fury","icon":"spell_fire_volcano"}, {"id":60187,"name":"Elemental Fury","icon":"spell_fire_volcano"}, {"id":60188,"name":"Elemental Fury","icon":"spell_fire_volcano"}, +{"id":60229,"name":"Greatness","icon":"inv_inscription_tarotgreatness"}, {"id":60396,"name":"Mercurial Alchemist Stone","icon":"spell_holy_aspiration"}, {"id":60403,"name":"Indestructible Alchemist Stone","icon":"spell_holy_aspiration"}, {"id":60405,"name":"Mighty Alchemist Stone","icon":"spell_holy_aspiration"}, {"id":60432,"name":"Earth and Moon","icon":"ability_druid_earthandsky"}, +{"id":60494,"name":"Dying Curse","icon":"spell_holy_mindvision"}, {"id":60581,"name":"Frosthide Leg Armor","icon":"trade_leatherworking"}, {"id":60582,"name":"Icescale Leg Armor","icon":"trade_leatherworking"}, {"id":60583,"name":"Jormungar Leg Reinforcements","icon":"trade_leatherworking"}, diff --git a/assets/database/leftover_db.bin b/assets/database/leftover_db.bin index d5404a73a0..82627c2837 100644 Binary files a/assets/database/leftover_db.bin and b/assets/database/leftover_db.bin differ diff --git a/assets/database/leftover_db.json b/assets/database/leftover_db.json index 17d3ebfe50..49a3738d28 100644 --- a/assets/database/leftover_db.json +++ b/assets/database/leftover_db.json @@ -12896,6 +12896,64 @@ ], "npcs":[ ], +"reforgeStats":[ +{"id":113,"fromStat":[4],"toStat":[25],"multiplier":0.4}, +{"id":114,"fromStat":[4],"toStat":[26],"multiplier":0.4}, +{"id":115,"fromStat":[4],"toStat":[12,7],"multiplier":0.4}, +{"id":116,"fromStat":[4],"toStat":[13,8],"multiplier":0.4}, +{"id":117,"fromStat":[4],"toStat":[14,9],"multiplier":0.4}, +{"id":118,"fromStat":[4],"toStat":[16],"multiplier":0.4}, +{"id":119,"fromStat":[4],"multiplier":0.4}, +{"id":120,"fromStat":[25],"toStat":[4],"multiplier":0.4}, +{"id":121,"fromStat":[25],"toStat":[26],"multiplier":0.4}, +{"id":122,"fromStat":[25],"toStat":[12,7],"multiplier":0.4}, +{"id":123,"fromStat":[25],"toStat":[13,8],"multiplier":0.4}, +{"id":124,"fromStat":[25],"toStat":[14,9],"multiplier":0.4}, +{"id":125,"fromStat":[25],"toStat":[16],"multiplier":0.4}, +{"id":126,"fromStat":[25],"multiplier":0.4}, +{"id":127,"fromStat":[26],"toStat":[4],"multiplier":0.4}, +{"id":128,"fromStat":[26],"toStat":[25],"multiplier":0.4}, +{"id":129,"fromStat":[26],"toStat":[12,7],"multiplier":0.4}, +{"id":130,"fromStat":[26],"toStat":[13,8],"multiplier":0.4}, +{"id":131,"fromStat":[26],"toStat":[14,9],"multiplier":0.4}, +{"id":132,"fromStat":[26],"toStat":[16],"multiplier":0.4}, +{"id":133,"fromStat":[26],"multiplier":0.4}, +{"id":134,"fromStat":[12,7],"toStat":[4],"multiplier":0.4}, +{"id":135,"fromStat":[12,7],"toStat":[25],"multiplier":0.4}, +{"id":136,"fromStat":[12,7],"toStat":[26],"multiplier":0.4}, +{"id":137,"fromStat":[12,7],"toStat":[13,8],"multiplier":0.4}, +{"id":138,"fromStat":[12,7],"toStat":[14,9],"multiplier":0.4}, +{"id":139,"fromStat":[12,7],"toStat":[16],"multiplier":0.4}, +{"id":140,"fromStat":[12,7],"multiplier":0.4}, +{"id":141,"fromStat":[13,8],"toStat":[4],"multiplier":0.4}, +{"id":142,"fromStat":[13,8],"toStat":[25],"multiplier":0.4}, +{"id":143,"fromStat":[13,8],"toStat":[26],"multiplier":0.4}, +{"id":144,"fromStat":[13,8],"toStat":[12,7],"multiplier":0.4}, +{"id":145,"fromStat":[13,8],"toStat":[14,9],"multiplier":0.4}, +{"id":146,"fromStat":[13,8],"toStat":[16],"multiplier":0.4}, +{"id":147,"fromStat":[13,8],"multiplier":0.4}, +{"id":148,"fromStat":[14,9],"toStat":[4],"multiplier":0.4}, +{"id":149,"fromStat":[14,9],"toStat":[25],"multiplier":0.4}, +{"id":150,"fromStat":[14,9],"toStat":[26],"multiplier":0.4}, +{"id":151,"fromStat":[14,9],"toStat":[12,7],"multiplier":0.4}, +{"id":152,"fromStat":[14,9],"toStat":[13,8],"multiplier":0.4}, +{"id":153,"fromStat":[14,9],"toStat":[16],"multiplier":0.4}, +{"id":154,"fromStat":[14,9],"multiplier":0.4}, +{"id":155,"fromStat":[16],"toStat":[4],"multiplier":0.4}, +{"id":156,"fromStat":[16],"toStat":[25],"multiplier":0.4}, +{"id":157,"fromStat":[16],"toStat":[26],"multiplier":0.4}, +{"id":158,"fromStat":[16],"toStat":[12,7],"multiplier":0.4}, +{"id":159,"fromStat":[16],"toStat":[13,8],"multiplier":0.4}, +{"id":160,"fromStat":[16],"toStat":[14,9],"multiplier":0.4}, +{"id":161,"fromStat":[16],"multiplier":0.4}, +{"id":162,"toStat":[4],"multiplier":0.4}, +{"id":163,"toStat":[25],"multiplier":0.4}, +{"id":164,"toStat":[26],"multiplier":0.4}, +{"id":165,"toStat":[12,7],"multiplier":0.4}, +{"id":166,"toStat":[13,8],"multiplier":0.4}, +{"id":167,"toStat":[14,9],"multiplier":0.4}, +{"id":168,"toStat":[16],"multiplier":0.4} +], "itemIcons":[ ], "spellIcons":[ diff --git a/assets/db_inputs/wowhead_reforge_stats.json b/assets/db_inputs/wowhead_reforge_stats.json new file mode 100644 index 0000000000..6ba17577bd --- /dev/null +++ b/assets/db_inputs/wowhead_reforge_stats.json @@ -0,0 +1,450 @@ +{ + "113": { + "id": 113, + "i1": 6, + "s1": "spi", + "i2": 13, + "s2": "dodgertng", + "v": 0.4 + }, + "114": { + "id": 114, + "i1": 6, + "s1": "spi", + "i2": 14, + "s2": "parryrtng", + "v": 0.4 + }, + "115": { + "id": 115, + "i1": 6, + "s1": "spi", + "i2": 31, + "s2": "hitrtng", + "v": 0.4 + }, + "116": { + "id": 116, + "i1": 6, + "s1": "spi", + "i2": 32, + "s2": "critstrkrtng", + "v": 0.4 + }, + "117": { + "id": 117, + "i1": 6, + "s1": "spi", + "i2": 36, + "s2": "hastertng", + "v": 0.4 + }, + "118": { + "id": 118, + "i1": 6, + "s1": "spi", + "i2": 37, + "s2": "exprtng", + "v": 0.4 + }, + "119": { + "id": 119, + "i1": 6, + "s1": "spi", + "i2": 49, + "s2": "mastrtng", + "v": 0.4 + }, + "120": { + "id": 120, + "i1": 13, + "s1": "dodgertng", + "i2": 6, + "s2": "spi", + "v": 0.4 + }, + "121": { + "id": 121, + "i1": 13, + "s1": "dodgertng", + "i2": 14, + "s2": "parryrtng", + "v": 0.4 + }, + "122": { + "id": 122, + "i1": 13, + "s1": "dodgertng", + "i2": 31, + "s2": "hitrtng", + "v": 0.4 + }, + "123": { + "id": 123, + "i1": 13, + "s1": "dodgertng", + "i2": 32, + "s2": "critstrkrtng", + "v": 0.4 + }, + "124": { + "id": 124, + "i1": 13, + "s1": "dodgertng", + "i2": 36, + "s2": "hastertng", + "v": 0.4 + }, + "125": { + "id": 125, + "i1": 13, + "s1": "dodgertng", + "i2": 37, + "s2": "exprtng", + "v": 0.4 + }, + "126": { + "id": 126, + "i1": 13, + "s1": "dodgertng", + "i2": 49, + "s2": "mastrtng", + "v": 0.4 + }, + "127": { + "id": 127, + "i1": 14, + "s1": "parryrtng", + "i2": 6, + "s2": "spi", + "v": 0.4 + }, + "128": { + "id": 128, + "i1": 14, + "s1": "parryrtng", + "i2": 13, + "s2": "dodgertng", + "v": 0.4 + }, + "129": { + "id": 129, + "i1": 14, + "s1": "parryrtng", + "i2": 31, + "s2": "hitrtng", + "v": 0.4 + }, + "130": { + "id": 130, + "i1": 14, + "s1": "parryrtng", + "i2": 32, + "s2": "critstrkrtng", + "v": 0.4 + }, + "131": { + "id": 131, + "i1": 14, + "s1": "parryrtng", + "i2": 36, + "s2": "hastertng", + "v": 0.4 + }, + "132": { + "id": 132, + "i1": 14, + "s1": "parryrtng", + "i2": 37, + "s2": "exprtng", + "v": 0.4 + }, + "133": { + "id": 133, + "i1": 14, + "s1": "parryrtng", + "i2": 49, + "s2": "mastrtng", + "v": 0.4 + }, + "134": { + "id": 134, + "i1": 31, + "s1": "hitrtng", + "i2": 6, + "s2": "spi", + "v": 0.4 + }, + "135": { + "id": 135, + "i1": 31, + "s1": "hitrtng", + "i2": 13, + "s2": "dodgertng", + "v": 0.4 + }, + "136": { + "id": 136, + "i1": 31, + "s1": "hitrtng", + "i2": 14, + "s2": "parryrtng", + "v": 0.4 + }, + "137": { + "id": 137, + "i1": 31, + "s1": "hitrtng", + "i2": 32, + "s2": "critstrkrtng", + "v": 0.4 + }, + "138": { + "id": 138, + "i1": 31, + "s1": "hitrtng", + "i2": 36, + "s2": "hastertng", + "v": 0.4 + }, + "139": { + "id": 139, + "i1": 31, + "s1": "hitrtng", + "i2": 37, + "s2": "exprtng", + "v": 0.4 + }, + "140": { + "id": 140, + "i1": 31, + "s1": "hitrtng", + "i2": 49, + "s2": "mastrtng", + "v": 0.4 + }, + "141": { + "id": 141, + "i1": 32, + "s1": "critstrkrtng", + "i2": 6, + "s2": "spi", + "v": 0.4 + }, + "142": { + "id": 142, + "i1": 32, + "s1": "critstrkrtng", + "i2": 13, + "s2": "dodgertng", + "v": 0.4 + }, + "143": { + "id": 143, + "i1": 32, + "s1": "critstrkrtng", + "i2": 14, + "s2": "parryrtng", + "v": 0.4 + }, + "144": { + "id": 144, + "i1": 32, + "s1": "critstrkrtng", + "i2": 31, + "s2": "hitrtng", + "v": 0.4 + }, + "145": { + "id": 145, + "i1": 32, + "s1": "critstrkrtng", + "i2": 36, + "s2": "hastertng", + "v": 0.4 + }, + "146": { + "id": 146, + "i1": 32, + "s1": "critstrkrtng", + "i2": 37, + "s2": "exprtng", + "v": 0.4 + }, + "147": { + "id": 147, + "i1": 32, + "s1": "critstrkrtng", + "i2": 49, + "s2": "mastrtng", + "v": 0.4 + }, + "148": { + "id": 148, + "i1": 36, + "s1": "hastertng", + "i2": 6, + "s2": "spi", + "v": 0.4 + }, + "149": { + "id": 149, + "i1": 36, + "s1": "hastertng", + "i2": 13, + "s2": "dodgertng", + "v": 0.4 + }, + "150": { + "id": 150, + "i1": 36, + "s1": "hastertng", + "i2": 14, + "s2": "parryrtng", + "v": 0.4 + }, + "151": { + "id": 151, + "i1": 36, + "s1": "hastertng", + "i2": 31, + "s2": "hitrtng", + "v": 0.4 + }, + "152": { + "id": 152, + "i1": 36, + "s1": "hastertng", + "i2": 32, + "s2": "critstrkrtng", + "v": 0.4 + }, + "153": { + "id": 153, + "i1": 36, + "s1": "hastertng", + "i2": 37, + "s2": "exprtng", + "v": 0.4 + }, + "154": { + "id": 154, + "i1": 36, + "s1": "hastertng", + "i2": 49, + "s2": "mastrtng", + "v": 0.4 + }, + "155": { + "id": 155, + "i1": 37, + "s1": "exprtng", + "i2": 6, + "s2": "spi", + "v": 0.4 + }, + "156": { + "id": 156, + "i1": 37, + "s1": "exprtng", + "i2": 13, + "s2": "dodgertng", + "v": 0.4 + }, + "157": { + "id": 157, + "i1": 37, + "s1": "exprtng", + "i2": 14, + "s2": "parryrtng", + "v": 0.4 + }, + "158": { + "id": 158, + "i1": 37, + "s1": "exprtng", + "i2": 31, + "s2": "hitrtng", + "v": 0.4 + }, + "159": { + "id": 159, + "i1": 37, + "s1": "exprtng", + "i2": 32, + "s2": "critstrkrtng", + "v": 0.4 + }, + "160": { + "id": 160, + "i1": 37, + "s1": "exprtng", + "i2": 36, + "s2": "hastertng", + "v": 0.4 + }, + "161": { + "id": 161, + "i1": 37, + "s1": "exprtng", + "i2": 49, + "s2": "mastrtng", + "v": 0.4 + }, + "162": { + "id": 162, + "i1": 49, + "s1": "mastrtng", + "i2": 6, + "s2": "spi", + "v": 0.4 + }, + "163": { + "id": 163, + "i1": 49, + "s1": "mastrtng", + "i2": 13, + "s2": "dodgertng", + "v": 0.4 + }, + "164": { + "id": 164, + "i1": 49, + "s1": "mastrtng", + "i2": 14, + "s2": "parryrtng", + "v": 0.4 + }, + "165": { + "id": 165, + "i1": 49, + "s1": "mastrtng", + "i2": 31, + "s2": "hitrtng", + "v": 0.4 + }, + "166": { + "id": 166, + "i1": 49, + "s1": "mastrtng", + "i2": 32, + "s2": "critstrkrtng", + "v": 0.4 + }, + "167": { + "id": 167, + "i1": 49, + "s1": "mastrtng", + "i2": 36, + "s2": "hastertng", + "v": 0.4 + }, + "168": { + "id": 168, + "i1": 49, + "s1": "mastrtng", + "i2": 37, + "s2": "exprtng", + "v": 0.4 + } +} \ No newline at end of file diff --git a/proto/common.proto b/proto/common.proto index a41176b01e..942fa6ba2d 100644 --- a/proto/common.proto +++ b/proto/common.proto @@ -140,6 +140,13 @@ message UnitStats { repeated double pseudo_stats = 2; } +message ReforgeStat { + int32 id = 1; + repeated Stat fromStat = 2; + repeated Stat toStat = 3; + double multiplier = 4; +} + enum ItemType { ItemTypeUnknown = 0; ItemTypeHead = 1; @@ -704,6 +711,7 @@ message ItemSpec { int32 id = 2; int32 enchant = 3; repeated int32 gems = 4; + int32 reforging = 5; //reforging id } message EquipmentSpec { @@ -714,6 +722,7 @@ message SimDatabase { repeated SimItem items = 1; repeated SimEnchant enchants = 2; repeated SimGem gems = 3; + repeated ReforgeStat reforge_stats = 6; } // Contains only the Item info needed by the sim. @@ -736,6 +745,7 @@ message SimItem { double weapon_speed = 13; string set_name = 14; + } // Extra enum for describing which items are eligible for an enchant, when diff --git a/proto/ui.proto b/proto/ui.proto index 343ba90593..e4cdc9d116 100644 --- a/proto/ui.proto +++ b/proto/ui.proto @@ -23,6 +23,7 @@ message UIDatabase { repeated IconData spell_icons = 5; repeated GlyphID glyph_ids = 7; + repeated ReforgeStat reforge_stats = 12; } message UIZone { diff --git a/sim/core/apl.go b/sim/core/apl.go index 15cc3c8084..7382372437 100644 --- a/sim/core/apl.go +++ b/sim/core/apl.go @@ -171,9 +171,18 @@ func (rot *APLRotation) getStats() *proto.APLStats { } } -// Returns all action objects as an unstructured list. Used for easily finding specific actions. func (rot *APLRotation) allAPLActions() []*APLAction { - return Flatten(MapSlice(rot.priorityList, func(action *APLAction) []*APLAction { return action.GetAllActions() })) + if rot == nil || rot.priorityList == nil { + return []*APLAction{} + } + + return Flatten(MapSlice(rot.priorityList, func(action *APLAction) []*APLAction { + // Check if action is nil before calling GetAllActions + if action == nil { + return []*APLAction{} + } + return action.GetAllActions() + })) } // Returns all action objects from the prepull as an unstructured list. Used for easily finding specific actions. diff --git a/sim/core/database.go b/sim/core/database.go index 02deb8e248..1d63b48524 100644 --- a/sim/core/database.go +++ b/sim/core/database.go @@ -2,6 +2,8 @@ package core import ( "fmt" + "math" + "github.com/wowsims/wotlk/sim/core/proto" "github.com/wowsims/wotlk/sim/core/stats" "google.golang.org/protobuf/encoding/protojson" @@ -12,6 +14,7 @@ var WITH_DB = false var ItemsByID = map[int32]Item{} var GemsByID = map[int32]Gem{} var EnchantsByEffectID = map[int32]Enchant{} +var ReforgeStatsByID = map[int32]ReforgeStat{} func addToDatabase(newDB *proto.SimDatabase) { for _, v := range newDB.Items { @@ -31,6 +34,39 @@ func addToDatabase(newDB *proto.SimDatabase) { GemsByID[v.Id] = GemFromProto(v) } } + + for _, v := range newDB.ReforgeStats { + if _, ok := ReforgeStatsByID[v.Id]; !ok { + ReforgeStatsByID[v.Id] = ReforgeStatFromProto(v) + } + } +} + +type ReforgeStat struct { + ID int32 + FromStat []proto.Stat // Assuming Stat is an enum or int32 type you've defined elsewhere + ToStat []proto.Stat + Multiplier float64 +} + +// ReforgeStatFromProto converts a protobuf ReforgeStat to a Go ReforgeStat +func ReforgeStatFromProto(protoStat *proto.ReforgeStat) ReforgeStat { + return ReforgeStat{ + ID: protoStat.GetId(), + FromStat: protoStat.GetFromStat(), + ToStat: protoStat.GetToStat(), + Multiplier: protoStat.GetMultiplier(), + } +} + +// ReforgeStatToProto converts a Go ReforgeStat to a protobuf ReforgeStat +func ReforgeStatToProto(stat ReforgeStat) *proto.ReforgeStat { + return &proto.ReforgeStat{ + Id: stat.ID, + FromStat: stat.FromStat, + ToStat: stat.ToStat, + Multiplier: stat.Multiplier, + } } type Item struct { @@ -54,8 +90,9 @@ type Item struct { SocketBonus stats.Stats // Modified for each instance of the item. - Gems []Gem - Enchant Enchant + Gems []Gem + Enchant Enchant + Reforging *ReforgeStat //Internal use TempEnchant int32 @@ -81,11 +118,21 @@ func ItemFromProto(pData *proto.SimItem) Item { } func (item *Item) ToItemSpecProto() *proto.ItemSpec { - return &proto.ItemSpec{ + itemSpec := &proto.ItemSpec{ Id: item.ID, Enchant: item.Enchant.EffectID, Gems: MapSlice(item.Gems, func(gem Gem) int32 { return gem.ID }), } + + // Check if Reforging is not nil before accessing ID + // The idea here is to convert a reforging ID to sim stats + if item.Reforging != nil { + itemSpec.Reforging = item.Reforging.ID + } else { + itemSpec.Reforging = 0 + } + + return itemSpec } type Enchant struct { @@ -117,9 +164,10 @@ func GemFromProto(pData *proto.SimGem) Gem { } type ItemSpec struct { - ID int32 - Enchant int32 - Gems []int32 + ID int32 + Enchant int32 + Gems []int32 + Reforging int32 } type Equipment [proto.ItemSlot_ItemSlotRanged + 1]Item @@ -211,9 +259,10 @@ func ProtoToEquipmentSpec(es *proto.EquipmentSpec) EquipmentSpec { var coreEquip EquipmentSpec for i, item := range es.Items { coreEquip[i] = ItemSpec{ - ID: item.Id, - Enchant: item.Enchant, - Gems: item.Gems, + ID: item.Id, + Enchant: item.Enchant, + Gems: item.Gems, + Reforging: item.Reforging, } } return coreEquip @@ -236,6 +285,15 @@ func NewItem(itemSpec ItemSpec) Item { // } } + if itemSpec.Reforging > 112 { // There is no id below 113 + reforge := ReforgeStatsByID[itemSpec.Reforging] + if validateReforging(&item, reforge) { + item.Reforging = &reforge + } else { + panic(fmt.Sprintf("When validating reforging for item %d, the reforging could not be validated. %d", itemSpec.ID, itemSpec.Reforging)) + } + } + if len(itemSpec.Gems) > 0 { // Need to do this to account for possible extra gem sockets. numGems := len(item.GemSockets) @@ -257,6 +315,31 @@ func NewItem(itemSpec ItemSpec) Item { return item } +func validateReforging(item *Item, reforging ReforgeStat) bool { + // Validate that the item can reforge these to stats + fromStatValid := false + for _, fromStat := range reforging.FromStat { + if item.Stats[fromStat] > 0 { + println("hello") + fromStatValid = true + break + } + } + if !fromStatValid { + return false + } + + toStatValid := false + for _, toStat := range reforging.ToStat { + if item.Stats[toStat] == 0 { + println("hello2") + toStatValid = true + break + } + } + + return toStatValid +} func NewEquipmentSet(equipSpec EquipmentSpec) Equipment { equipment := Equipment{} for _, itemSpec := range equipSpec { @@ -290,14 +373,34 @@ func EquipmentSpecFromJsonString(jsonString string) *proto.EquipmentSpec { func (equipment *Equipment) Stats() stats.Stats { equipStats := stats.Stats{} + for _, item := range equipment { + equipStats = equipStats.Add(item.Stats) + + // Apply reforging + if item.Reforging != nil { + reforgingChanges := stats.Stats{} + for _, fromStat := range item.Reforging.FromStat { + if equipStats[fromStat] > 0 { + reduction := math.Floor(equipStats[fromStat] * item.Reforging.Multiplier) + reforgingChanges[fromStat] = -reduction + } + } + for _, toStat := range item.Reforging.FromStat { + if equipStats[toStat] > 0 { + increase := math.Floor(equipStats[toStat] * item.Reforging.Multiplier) + reforgingChanges[toStat] = +increase + } + } + equipStats = equipStats.Add(reforgingChanges) + } + equipStats = equipStats.Add(item.Enchant.Stats) for _, gem := range item.Gems { equipStats = equipStats.Add(gem.Stats) } - // Check socket bonus if len(item.GemSockets) > 0 && len(item.Gems) >= len(item.GemSockets) { allMatch := true @@ -312,6 +415,7 @@ func (equipment *Equipment) Stats() stats.Stats { equipStats = equipStats.Add(item.SocketBonus) } } + } return equipStats } diff --git a/sim/core/database_load.go b/sim/core/database_load.go index 3c2816768a..637c4a2210 100644 --- a/sim/core/database_load.go +++ b/sim/core/database_load.go @@ -14,9 +14,10 @@ func init() { WITH_DB = true simDB := &proto.SimDatabase{ - Items: make([]*proto.SimItem, len(db.Items)), - Enchants: make([]*proto.SimEnchant, len(db.Enchants)), - Gems: make([]*proto.SimGem, len(db.Gems)), + Items: make([]*proto.SimItem, len(db.Items)), + Enchants: make([]*proto.SimEnchant, len(db.Enchants)), + Gems: make([]*proto.SimGem, len(db.Gems)), + ReforgeStats: make([]*proto.ReforgeStat, len(db.ReforgeStats)), } for i, item := range db.Items { @@ -54,5 +55,14 @@ func init() { } } + for i, reforgeStat := range db.ReforgeStats { + simDB.ReforgeStats[i] = &proto.ReforgeStat{ + Id: reforgeStat.Id, + FromStat: reforgeStat.FromStat, + ToStat: reforgeStat.ToStat, + Multiplier: reforgeStat.Multiplier, + } + } + addToDatabase(simDB) } diff --git a/tools/database/database.go b/tools/database/database.go index 7a18ffd83d..b22fff23ac 100644 --- a/tools/database/database.go +++ b/tools/database/database.go @@ -36,8 +36,9 @@ type WowDatabase struct { Zones map[int32]*proto.UIZone Npcs map[int32]*proto.UINPC - ItemIcons map[int32]*proto.IconData - SpellIcons map[int32]*proto.IconData + ItemIcons map[int32]*proto.IconData + SpellIcons map[int32]*proto.IconData + ReforgeStats map[int32]*proto.ReforgeStat Encounters []*proto.PresetEncounter GlyphIDs []*proto.GlyphID @@ -51,20 +52,22 @@ func NewWowDatabase() *WowDatabase { Zones: make(map[int32]*proto.UIZone), Npcs: make(map[int32]*proto.UINPC), - ItemIcons: make(map[int32]*proto.IconData), - SpellIcons: make(map[int32]*proto.IconData), + ItemIcons: make(map[int32]*proto.IconData), + SpellIcons: make(map[int32]*proto.IconData), + ReforgeStats: make(map[int32]*proto.ReforgeStat), } } func (db *WowDatabase) Clone() *WowDatabase { return &WowDatabase{ - Items: maps.Clone(db.Items), - Enchants: maps.Clone(db.Enchants), - Gems: maps.Clone(db.Gems), - Zones: maps.Clone(db.Zones), - Npcs: maps.Clone(db.Npcs), - ItemIcons: maps.Clone(db.ItemIcons), - SpellIcons: maps.Clone(db.SpellIcons), + Items: maps.Clone(db.Items), + Enchants: maps.Clone(db.Enchants), + Gems: maps.Clone(db.Gems), + Zones: maps.Clone(db.Zones), + Npcs: maps.Clone(db.Npcs), + ItemIcons: maps.Clone(db.ItemIcons), + SpellIcons: maps.Clone(db.SpellIcons), + ReforgeStats: maps.Clone(db.ReforgeStats), } } @@ -203,15 +206,16 @@ func (db *WowDatabase) ToUIProto() *proto.UIDatabase { }) return &proto.UIDatabase{ - Items: mapToSlice(db.Items), - Enchants: enchants, - Gems: mapToSlice(db.Gems), - Encounters: db.Encounters, - Zones: mapToSlice(db.Zones), - Npcs: mapToSlice(db.Npcs), - ItemIcons: mapToSlice(db.ItemIcons), - SpellIcons: mapToSlice(db.SpellIcons), - GlyphIds: db.GlyphIDs, + Items: mapToSlice(db.Items), + Enchants: enchants, + Gems: mapToSlice(db.Gems), + Encounters: db.Encounters, + Zones: mapToSlice(db.Zones), + Npcs: mapToSlice(db.Npcs), + ItemIcons: mapToSlice(db.ItemIcons), + SpellIcons: mapToSlice(db.SpellIcons), + GlyphIds: db.GlyphIDs, + ReforgeStats: mapToSlice(db.ReforgeStats), } } @@ -235,13 +239,14 @@ func ReadDatabaseFromJson(jsonStr string) *WowDatabase { } return &WowDatabase{ - Items: sliceToMap(dbProto.Items), - Enchants: enchants, - Gems: sliceToMap(dbProto.Gems), - Zones: sliceToMap(dbProto.Zones), - Npcs: sliceToMap(dbProto.Npcs), - ItemIcons: sliceToMap(dbProto.ItemIcons), - SpellIcons: sliceToMap(dbProto.SpellIcons), + Items: sliceToMap(dbProto.Items), + Enchants: enchants, + Gems: sliceToMap(dbProto.Gems), + Zones: sliceToMap(dbProto.Zones), + Npcs: sliceToMap(dbProto.Npcs), + ItemIcons: sliceToMap(dbProto.ItemIcons), + SpellIcons: sliceToMap(dbProto.SpellIcons), + ReforgeStats: sliceToMap(dbProto.ReforgeStats), } } @@ -280,6 +285,8 @@ func (db *WowDatabase) WriteJson(jsonFilePath string) { buffer.WriteString(",\n") tools.WriteProtoArrayToBuffer(uidb.Npcs, buffer, "npcs") buffer.WriteString(",\n") + tools.WriteProtoArrayToBuffer(uidb.ReforgeStats, buffer, "reforgeStats") + buffer.WriteString(",\n") tools.WriteProtoArrayToBuffer(uidb.ItemIcons, buffer, "itemIcons") buffer.WriteString(",\n") tools.WriteProtoArrayToBuffer(uidb.SpellIcons, buffer, "spellIcons") diff --git a/tools/database/gen_db/main.go b/tools/database/gen_db/main.go index b8931d749f..ae000029de 100644 --- a/tools/database/gen_db/main.go +++ b/tools/database/gen_db/main.go @@ -60,19 +60,26 @@ func main() { } else if *genAsset == "wago-db2-items" { tools.WriteFile(fmt.Sprintf("%s/wago_db2_items.csv", inputsDir), tools.ReadWebRequired("https://wago.tools/db2/ItemSparse/csv?build=3.4.2.49311")) return + } else if *genAsset == "reforge-stats" { + //Todo: fill this when we have information from wowhead @ Neteyes - Gehennas + // For now, the version we have was taken from https://web.archive.org/web/20120201045249js_/http://www.wowhead.com/data=item-scaling + return } else if *genAsset != "db" { panic("Invalid gen value") } - itemTooltips := database.NewWowheadItemTooltipManager(fmt.Sprintf("%s/wowhead_item_tooltips.csv", inputsDir)).Read() spellTooltips := database.NewWowheadSpellTooltipManager(fmt.Sprintf("%s/wowhead_spell_tooltips.csv", inputsDir)).Read() wowheadDB := database.ParseWowheadDB(tools.ReadFile(fmt.Sprintf("%s/wowhead_gearplannerdb.txt", inputsDir))) atlaslootDB := database.ReadDatabaseFromJson(tools.ReadFile(fmt.Sprintf("%s/atlasloot_db.json", inputsDir))) factionRestrictions := database.ParseItemFactionRestrictionsFromWagoDB(tools.ReadFile(fmt.Sprintf("%s/wago_db2_items.csv", inputsDir))) + // Todo: https://web.archive.org/web/20120201045249js_/http://www.wowhead.com/data=item-scaling + reforgeStats := database.ParseWowheadReforgeStats(tools.ReadFile(fmt.Sprintf("%s/wowhead_reforge_stats.json", inputsDir))) + db := database.NewWowDatabase() db.Encounters = core.PresetEncounters db.GlyphIDs = getGlyphIDsFromJson(fmt.Sprintf("%s/glyph_id_map.json", inputsDir)) + db.ReforgeStats = reforgeStats.ToProto() for _, response := range itemTooltips { if response.IsEquippable() { @@ -458,98 +465,98 @@ func GetAllRotationSpellIds() map[string][]int32 { Class: proto.Class_ClassDruid, Equipment: &proto.EquipmentSpec{}, TalentsString: "5102233115331303213305311031--205003002", - }, &proto.Player_BalanceDruid{BalanceDruid: &proto.BalanceDruid{Options: &proto.BalanceDruid_Options{}, Rotation: &proto.BalanceDruid_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_BalanceDruid{BalanceDruid: &proto.BalanceDruid{Options: &proto.BalanceDruid_Options{}}}), nil, nil, nil)}, {Name: "guardian", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassDruid, Equipment: &proto.EquipmentSpec{}, TalentsString: "-503232132322010353120300313511-20350001", - }, &proto.Player_FeralTankDruid{FeralTankDruid: &proto.FeralTankDruid{Options: &proto.FeralTankDruid_Options{}, Rotation: &proto.FeralTankDruid_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_FeralTankDruid{FeralTankDruid: &proto.FeralTankDruid{Options: &proto.FeralTankDruid_Options{}}}), nil, nil, nil)}, {Name: "restodruid", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassDruid, Equipment: &proto.EquipmentSpec{}, TalentsString: "05320031103--230023312131502331050313051", - }, &proto.Player_RestorationDruid{RestorationDruid: &proto.RestorationDruid{Options: &proto.RestorationDruid_Options{}, Rotation: &proto.RestorationDruid_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_RestorationDruid{RestorationDruid: &proto.RestorationDruid{Options: &proto.RestorationDruid_Options{}}}), nil, nil, nil)}, {Name: "elemental", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassShaman, Race: proto.Race_RaceTroll, Equipment: &proto.EquipmentSpec{}, TalentsString: "0532001523212351322301351-005052031", - }, &proto.Player_ElementalShaman{ElementalShaman: &proto.ElementalShaman{Options: &proto.ElementalShaman_Options{}, Rotation: &proto.ElementalShaman_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_ElementalShaman{ElementalShaman: &proto.ElementalShaman{Options: &proto.ElementalShaman_Options{}}}), nil, nil, nil)}, {Name: "enhance", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassShaman, Race: proto.Race_RaceTroll, Equipment: &proto.EquipmentSpec{}, TalentsString: "053030152-30405003105021333031131031051", - }, &proto.Player_EnhancementShaman{EnhancementShaman: &proto.EnhancementShaman{Options: &proto.EnhancementShaman_Options{}, Rotation: &proto.EnhancementShaman_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_EnhancementShaman{EnhancementShaman: &proto.EnhancementShaman{Options: &proto.EnhancementShaman_Options{}}}), nil, nil, nil)}, {Name: "restosham", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassShaman, Race: proto.Race_RaceTroll, Equipment: &proto.EquipmentSpec{}, TalentsString: "-3020503-50005331335310501122331251", - }, &proto.Player_RestorationShaman{RestorationShaman: &proto.RestorationShaman{Options: &proto.RestorationShaman_Options{}, Rotation: &proto.RestorationShaman_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_RestorationShaman{RestorationShaman: &proto.RestorationShaman{Options: &proto.RestorationShaman_Options{}}}), nil, nil, nil)}, {Name: "hunter", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassHunter, Race: proto.Race_RaceTroll, Equipment: &proto.EquipmentSpec{}, TalentsString: "-015305101-5000032500033330532135301311", - }, &proto.Player_Hunter{Hunter: &proto.Hunter{Options: &proto.Hunter_Options{}, Rotation: &proto.Hunter_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_Hunter{Hunter: &proto.Hunter{Options: &proto.Hunter_Options{}}}), nil, nil, nil)}, {Name: "mage", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassMage, Race: proto.Race_RaceTroll, Equipment: &proto.EquipmentSpec{}, TalentsString: "23000513310033015032310250532-03-023303001", - }, &proto.Player_Mage{Mage: &proto.Mage{Options: &proto.Mage_Options{}, Rotation: &proto.Mage_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_Mage{Mage: &proto.Mage{Options: &proto.Mage_Options{}}}), nil, nil, nil)}, {Name: "healingpriest", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassPriest, Equipment: &proto.EquipmentSpec{}, TalentsString: "0503203130300512301313231251-2351010303", - }, &proto.Player_HealingPriest{HealingPriest: &proto.HealingPriest{Options: &proto.HealingPriest_Options{}, Rotation: &proto.HealingPriest_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_HealingPriest{HealingPriest: &proto.HealingPriest{Options: &proto.HealingPriest_Options{}}}), nil, nil, nil)}, {Name: "shadow", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassPriest, Equipment: &proto.EquipmentSpec{}, TalentsString: "05032031--325023051223010323151301351", - }, &proto.Player_ShadowPriest{ShadowPriest: &proto.ShadowPriest{Options: &proto.ShadowPriest_Options{}, Rotation: &proto.ShadowPriest_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_ShadowPriest{ShadowPriest: &proto.ShadowPriest{Options: &proto.ShadowPriest_Options{}}}), nil, nil, nil)}, {Name: "rogue", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassRogue, Equipment: &proto.EquipmentSpec{}, TalentsString: "00532000523-0252051050035010223100501251", - }, &proto.Player_Rogue{Rogue: &proto.Rogue{Options: &proto.Rogue_Options{}, Rotation: &proto.Rogue_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_Rogue{Rogue: &proto.Rogue{Options: &proto.Rogue_Options{}}}), nil, nil, nil)}, {Name: "warrior", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassWarrior, Equipment: &proto.EquipmentSpec{}, TalentsString: "302023102331-305053000520310053120500351", - }, &proto.Player_Warrior{Warrior: &proto.Warrior{Options: &proto.Warrior_Options{}, Rotation: &proto.Warrior_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_Warrior{Warrior: &proto.Warrior{Options: &proto.Warrior_Options{}}}), nil, nil, nil)}, {Name: "protwarrior", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassWarrior, Equipment: &proto.EquipmentSpec{}, TalentsString: "2500030023-302-053351225000012521030113321", - }, &proto.Player_ProtectionWarrior{ProtectionWarrior: &proto.ProtectionWarrior{Options: &proto.ProtectionWarrior_Options{}, Rotation: &proto.ProtectionWarrior_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_ProtectionWarrior{ProtectionWarrior: &proto.ProtectionWarrior{Options: &proto.ProtectionWarrior_Options{}}}), nil, nil, nil)}, {Name: "holypally", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassPaladin, Equipment: &proto.EquipmentSpec{}, TalentsString: "50350151020013053100515221-50023131203", - }, &proto.Player_HolyPaladin{HolyPaladin: &proto.HolyPaladin{Options: &proto.HolyPaladin_Options{}, Rotation: &proto.HolyPaladin_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_HolyPaladin{HolyPaladin: &proto.HolyPaladin{Options: &proto.HolyPaladin_Options{}}}), nil, nil, nil)}, {Name: "protpally", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassPaladin, Equipment: &proto.EquipmentSpec{}, TalentsString: "-05005135200132311333312321-511302012003", - }, &proto.Player_ProtectionPaladin{ProtectionPaladin: &proto.ProtectionPaladin{Options: &proto.ProtectionPaladin_Options{}, Rotation: &proto.ProtectionPaladin_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_ProtectionPaladin{ProtectionPaladin: &proto.ProtectionPaladin{Options: &proto.ProtectionPaladin_Options{}}}), nil, nil, nil)}, {Name: "ret", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassPaladin, Race: proto.Race_RaceBloodElf, Equipment: &proto.EquipmentSpec{}, TalentsString: "050501-05-05232051203331302133231331", - }, &proto.Player_RetributionPaladin{RetributionPaladin: &proto.RetributionPaladin{Options: &proto.RetributionPaladin_Options{}, Rotation: &proto.RetributionPaladin_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_RetributionPaladin{RetributionPaladin: &proto.RetributionPaladin{Options: &proto.RetributionPaladin_Options{}}}), nil, nil, nil)}, {Name: "warlock", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassWarlock, Equipment: &proto.EquipmentSpec{}, TalentsString: "2350002030023510253500331151--550000051", - }, &proto.Player_Warlock{Warlock: &proto.Warlock{Options: &proto.Warlock_Options{}, Rotation: &proto.Warlock_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_Warlock{Warlock: &proto.Warlock{Options: &proto.Warlock_Options{}}}), nil, nil, nil)}, {Name: "dk", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassDeathknight, Equipment: &proto.EquipmentSpec{}, TalentsString: "-320043500002-2300303050032152000150013133051", - }, &proto.Player_Deathknight{Deathknight: &proto.Deathknight{Options: &proto.Deathknight_Options{}, Rotation: &proto.Deathknight_Rotation{}}}), nil, nil, nil)}, + }, &proto.Player_Deathknight{Deathknight: &proto.Deathknight{Options: &proto.Deathknight_Options{}}}), nil, nil, nil)}, {Name: "tankdk", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ Class: proto.Class_ClassDeathknight, Equipment: &proto.EquipmentSpec{}, diff --git a/tools/database/wowhead_reforge_db.go b/tools/database/wowhead_reforge_db.go new file mode 100644 index 0000000000..92aa51a226 --- /dev/null +++ b/tools/database/wowhead_reforge_db.go @@ -0,0 +1,67 @@ +package database + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/tailscale/hujson" + "github.com/wowsims/wotlk/sim/core/proto" +) + +func ParseWowheadReforgeStats(contents string) WowheadReforgeStats { + var stats WowheadReforgeStats + standardized, err := hujson.Standardize([]byte(contents)) // Removes invalid JSON, such as trailing commas + if err != nil { + log.Fatalf("Failed to standardize json %s\n\n%s\n\n%s", err, contents[0:30], contents[len(contents)-30:]) + } + + err = json.Unmarshal(standardized, &stats) + if err != nil { + log.Fatalf("failed to parse wowhead item db to json %s\n\n%s", err, contents[0:30]) + } + fmt.Printf("\n--\nWowhead reforges loaded\n--\n") + return stats +} + +// statStringToEnum maps wowhead stat strings to their corresponding proto.Stat enum values +var statStringToEnum = map[string][]proto.Stat{ + "spi": {proto.Stat_StatSpirit}, + "dodgertng": {proto.Stat_StatDodge}, + "parryrtng": {proto.Stat_StatParry}, + "hitrtng": {proto.Stat_StatMeleeHit, proto.Stat_StatSpellHit}, + "critstrkrtng": {proto.Stat_StatMeleeCrit, proto.Stat_StatSpellCrit}, + "hastertng": {proto.Stat_StatMeleeHaste, proto.Stat_StatSpellHaste}, + "exprtng": {proto.Stat_StatExpertise}, + // "mastrtng" mapping needs to be defined when the appropriate proto.Stat value for mastery is available. + // "mastrtng": {proto.Stat_StatMastery}, +} + +func mapStringToStat(statString string) []proto.Stat { + return statStringToEnum[statString] // Directly return the slice from the map. +} + +func (reforgeStats WowheadReforgeStats) ToProto() map[int32]*proto.ReforgeStat { + protoStatsMap := make(map[int32]*proto.ReforgeStat) + for _, stat := range reforgeStats { + protoStat := &proto.ReforgeStat{ + Id: int32(stat.ReforgeID), + FromStat: mapStringToStat(stat.FromStat), // Assuming you have S1 and S2 fields in your struct + ToStat: mapStringToStat(stat.ToStat), + Multiplier: stat.ReforgeMultiplier, + } + protoStatsMap[protoStat.Id] = protoStat + } + return protoStatsMap +} + +type WowheadReforgeStat struct { + ReforgeID int `json:"id"` // Reforge ID used by game + FromID int `json:"i1"` // WH Stat ID to reforge from + FromStat string `json:"s1"` // WH Stat string to reforge from + ToID int `json:"i2"` // WH Stat ID to reforge to + ToStat string `json:"s2"` // WH Stat string to reforge to + ReforgeMultiplier float64 `json:"v"` // Multiplier for reforge, always 0.4 +} + +type WowheadReforgeStats map[string]WowheadReforgeStat diff --git a/ui/protection_warrior/gear_sets/p1_balanced.gear.json b/ui/protection_warrior/gear_sets/p1_balanced.gear.json index a7e2f624e1..f43885e59f 100644 --- a/ui/protection_warrior/gear_sets/p1_balanced.gear.json +++ b/ui/protection_warrior/gear_sets/p1_balanced.gear.json @@ -16,4 +16,4 @@ {"id":40402,"enchant":3788}, {"id":40400,"enchant":3849}, {"id":41168,"gems":[36767]} -]} \ No newline at end of file +]}