diff --git a/assets/database/db.bin b/assets/database/db.bin index 2937a8f89..6feb6195f 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 89c7f15e8..d4f921329 100644 --- a/assets/database/db.json +++ b/assets/database/db.json @@ -5605,7 +5605,7 @@ {"id":21184,"name":"Deeprock Bracers","icon":"inv_bracer_07","type":6,"armorType":4,"requiresLevel":60,"stats":[19,10,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,309,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":1,"quality":4,"sources":[{"quest":{"id":8574,"name":"Stalwart's Battlegear"}},{"rep":{"repFactionId":609,"repLevel":7}}]}, {"id":21185,"name":"Earthcalm Orb","icon":"inv_misc_gem_pearl_06","type":13,"weaponType":5,"handType":3,"requiresLevel":60,"stats":[0,0,0,10,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":1,"quality":4,"sources":[{"quest":{"id":8574,"name":"Stalwart's Battlegear"}},{"rep":{"repFactionId":609,"repLevel":7}}]}, {"id":21186,"name":"Rockfury Bracers","icon":"inv_bracer_12","type":6,"armorType":1,"requiresLevel":60,"stats":[0,0,7,0,0,27,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":1,"quality":4,"sources":[{"quest":{"id":8574,"name":"Stalwart's Battlegear"}},{"rep":{"repFactionId":609,"repLevel":7}}]}, -{"id":21189,"name":"Might of Cenarius","icon":"inv_jewelry_ring_41","type":11,"requiresLevel":60,"stats":[0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":1,"quality":4,"unique":true,"sources":[{"quest":{"id":8574,"name":"Stalwart's Battlegear"}},{"rep":{"repFactionId":609,"repLevel":7}}]}, +{"id":21189,"name":"Might of Cenarius","icon":"inv_jewelry_ring_41","type":11,"requiresLevel":60,"stats":[0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":4,"ilvl":62,"phase":1,"quality":4,"unique":true,"sources":[{"quest":{"id":8574,"name":"Stalwart's Battlegear"}},{"rep":{"repFactionId":609,"repLevel":7}}]}, {"id":21198,"name":"Signet Ring of the Bronze Dragonflight","icon":"inv_jewelry_ring_40","type":11,"requiresLevel":60,"stats":[12,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":70,"phase":1,"quality":4,"unique":true,"sources":[{"quest":{"id":8749,"name":"The Path of the Protector"}},{"rep":{"repFactionId":910,"repLevel":6}}]}, {"id":21199,"name":"Signet Ring of the Bronze Dragonflight","icon":"inv_jewelry_ring_40","type":11,"requiresLevel":60,"stats":[12,0,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":1,"quality":4,"unique":true,"sources":[{"quest":{"id":8750,"name":"The Path of the Protector"}},{"rep":{"repFactionId":910,"repLevel":7}}]}, {"id":21200,"name":"Signet Ring of the Bronze Dragonflight","icon":"inv_jewelry_ring_40","type":11,"requiresLevel":60,"stats":[13,0,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":80,"phase":1,"quality":4,"unique":true,"sources":[{"rep":{"repFactionId":910,"repLevel":8}}]}, @@ -6089,7 +6089,7 @@ {"id":215114,"name":"Glowing Hyperconductive Scale Coif","icon":"inv_helmet_43","type":1,"armorType":3,"requiresLevel":40,"stats":[0,0,14,15,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,242,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":45,"phase":2,"quality":4,"requiredProfession":8,"sources":[{"crafted":{"profession":8}}]}, {"id":215115,"name":"Hyperconductive Goldwrap","icon":"inv_belt_32","type":8,"armorType":1,"requiresLevel":40,"stats":[0,0,9,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":45,"phase":2,"quality":4,"requiredProfession":4,"sources":[{"crafted":{"profession":4}}]}, {"id":215161,"name":"Tempered Interference-Negating Helmet","icon":"inv_helmet_49","type":1,"armorType":4,"requiresLevel":40,"stats":[20,0,14,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,426,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":45,"phase":2,"quality":4,"requiredProfession":2,"sources":[{"crafted":{"profession":2}},{"crafted":{"profession":2}}]}, -{"id":215166,"name":"Glowing Gneuro-Linked Cowl","icon":"inv_helmet_15","type":1,"armorType":2,"requiresLevel":40,"stats":[0,14,14,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,118,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":45,"phase":2,"quality":4,"requiredProfession":8,"sources":[{"crafted":{"profession":8}}]}, +{"id":215166,"name":"Glowing Gneuro-Linked Cowl","icon":"inv_helmet_15","type":1,"armorType":2,"requiresLevel":40,"stats":[0,14,14,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,118,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":3,"ilvl":45,"phase":2,"quality":4,"requiredProfession":8,"sources":[{"crafted":{"profession":8}}]}, {"id":215167,"name":"Reflective Truesilver Braincage","icon":"inv_helmet_49","type":1,"armorType":4,"requiresLevel":40,"stats":[0,0,14,15,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,426,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":45,"phase":2,"quality":4,"requiredProfession":2,"sources":[{"crafted":{"profession":2}}]}, {"id":215365,"name":"Invoker's Mantle","icon":"inv_shoulder_02","type":3,"armorType":1,"requiresLevel":25,"stats":[0,0,0,5,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":30,"phase":1,"quality":2}, {"id":215366,"name":"Invoker's Cord","icon":"inv_belt_03","type":8,"armorType":1,"requiresLevel":25,"stats":[0,0,0,5,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":30,"phase":1,"quality":2}, @@ -7384,7 +7384,7 @@ {"id":227806,"name":"Wisdom of the Timbermaw","icon":"inv_belt_09","type":8,"armorType":1,"requiresLevel":53,"stats":[0,0,0,21,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,46,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":58,"phase":4,"quality":3}, {"id":227807,"name":"Dense Timbermaw Belt","icon":"inv_belt_16","type":8,"armorType":3,"requiresLevel":60,"stats":[0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,234,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":65,"phase":4,"quality":4,"requiredProfession":2,"sources":[{"crafted":{"profession":2}},{"soldBy":{"npcId":11557,"npcName":"Meilosh","zoneId":361}},{"rep":{"repFactionId":576,"repLevel":6}}]}, {"id":227808,"name":"Rugged Mantle of the Timbermaw","icon":"inv_shoulder_19","type":3,"armorType":1,"requiresLevel":60,"stats":[0,0,0,15,0,27,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":65,"phase":4,"quality":4,"requiredProfession":11,"sources":[{"crafted":{"profession":11}},{"soldBy":{"npcId":11557,"npcName":"Meilosh","zoneId":361}},{"rep":{"repFactionId":576,"repLevel":7}}]}, -{"id":227809,"name":"Studded Timbermaw Brawlers","icon":"inv_gauntlets_26","type":7,"armorType":2,"requiresLevel":60,"stats":[20,10,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":65,"phase":4,"quality":4,"requiredProfession":8,"sources":[{"crafted":{"profession":8}},{"soldBy":{"npcId":11557,"npcName":"Meilosh","zoneId":361}},{"rep":{"repFactionId":576,"repLevel":7}}]}, +{"id":227809,"name":"Studded Timbermaw Brawlers","icon":"inv_gauntlets_26","type":7,"armorType":2,"requiresLevel":60,"stats":[20,10,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":3,"ilvl":65,"phase":4,"quality":4,"requiredProfession":8,"sources":[{"crafted":{"profession":8}},{"soldBy":{"npcId":11557,"npcName":"Meilosh","zoneId":361}},{"rep":{"repFactionId":576,"repLevel":7}}]}, {"id":227810,"name":"Dense Timbermaw Boots","icon":"inv_boots_chain_10","type":10,"armorType":3,"requiresLevel":60,"stats":[0,0,23,14,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,286,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":65,"phase":4,"quality":4,"requiredProfession":2,"sources":[{"crafted":{"profession":2}},{"soldBy":{"npcId":11557,"npcName":"Meilosh","zoneId":361}},{"rep":{"repFactionId":576,"repLevel":7}}]}, {"id":227811,"name":"Defender of the Timbermaw","icon":"inv_misc_horn_01","type":12,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":4,"quality":4,"unique":true}, {"id":227812,"name":"Furbolg Medicine Pouch","icon":"inv_misc_bag_11","type":13,"weaponType":5,"handType":3,"stats":[0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":52,"phase":4,"quality":2}, @@ -7585,7 +7585,7 @@ {"id":228086,"name":"Repurposed Shredderblade","icon":"inv_sword_142","type":13,"weaponType":9,"handType":4,"requiresLevel":57,"stats":[12,0,11,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponDamageMin":152,"weaponDamageMax":229,"weaponSpeed":3.6,"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":4,"quality":3,"sources":[{"drop":{"npcId":226922,"zoneId":15475}},{"drop":{"difficulty":1,"zoneId":15475,"otherName":"Zilbagob"}}]}, {"id":228087,"name":"Supercharged Silver Moebius","icon":"inv_jewelry_ring_15","type":11,"requiresLevel":57,"stats":[0,0,0,8,8,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":4,"quality":3,"unique":true,"sources":[{"drop":{"npcId":226922,"zoneId":15475}},{"drop":{"difficulty":1,"zoneId":15475,"otherName":"Zilbagob"}}]}, {"id":228088,"name":"Shredder Operator's Dogtags","icon":"inv_jewelry_necklace_39","type":2,"requiresLevel":57,"stats":[0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":4,"quality":3,"sources":[{"drop":{"npcId":226922,"zoneId":15475}},{"drop":{"difficulty":1,"zoneId":15475,"otherName":"Zilbagob"}}]}, -{"id":228089,"name":"Woodcarved Moonstalker","icon":"inv_jewelcrafting_blackpearlpanther","type":12,"requiresLevel":57,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":4,"quality":3,"sources":[{"drop":{"npcId":227140,"zoneId":15475}},{"drop":{"difficulty":1,"zoneId":15475,"otherName":"Pyranis"}}]}, +{"id":228089,"name":"Woodcarved Moonstalker","icon":"inv_jewelcrafting_blackpearlpanther","type":12,"requiresLevel":57,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":4,"ilvl":62,"phase":4,"quality":3,"sources":[{"drop":{"npcId":227140,"zoneId":15475}},{"drop":{"difficulty":1,"zoneId":15475,"otherName":"Pyranis"}}]}, {"id":228090,"name":"Cenarion Ritual Dagger","icon":"inv_weapon_shortblade_25","type":13,"weaponType":2,"handType":1,"requiresLevel":57,"stats":[0,0,6,5,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponDamageMin":45,"weaponDamageMax":85,"weaponSpeed":1.6,"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":4,"quality":3,"sources":[{"drop":{"npcId":227140,"zoneId":15475}},{"drop":{"difficulty":1,"zoneId":15475,"otherName":"Pyranis"}}]}, {"id":228091,"name":"Thorned Boots","icon":"inv_boots_cloth_04","type":10,"armorType":2,"requiresLevel":57,"stats":[0,14,9,0,0,0,0,0,0,0,0,0,0,1,0,0,0,28,1,0,0,0,0,0,0,0,120,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":4,"quality":3,"sources":[{"drop":{"npcId":227140,"zoneId":15475}},{"drop":{"difficulty":1,"zoneId":15475,"otherName":"Pyranis"}}]}, {"id":228092,"name":"Druidic Mantle","icon":"inv_shoulder_18","type":3,"armorType":2,"requiresLevel":57,"stats":[0,0,9,10,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":62,"phase":4,"quality":3,"sources":[{"drop":{"npcId":227140,"zoneId":15475}},{"drop":{"difficulty":1,"zoneId":15475,"otherName":"Pyranis"}}]}, @@ -8781,11 +8781,11 @@ {"id":233404,"name":"Enigma Circlet","icon":"inv_helmet_06","type":1,"armorType":1,"requiresLevel":60,"stats":[0,0,14,15,0,44,0,0,0,0,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":81,"phase":6,"quality":4,"classAllowlist":[3],"setName":"Enigma Insight"}, {"id":233405,"name":"Enigma Boots","icon":"inv_boots_cloth_03","type":10,"armorType":1,"requiresLevel":60,"stats":[0,0,10,10,0,34,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":78,"phase":6,"quality":4,"classAllowlist":[3],"setName":"Enigma Insight"}, {"id":233406,"name":"Enigma Leggings","icon":"inv_pants_cloth_08","type":9,"armorType":1,"requiresLevel":60,"stats":[0,0,11,12,0,44,0,0,0,0,0,0,0,1,2,0,0,0,1,2,0,0,0,0,0,0,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":81,"phase":6,"quality":4,"classAllowlist":[3],"setName":"Enigma Insight"}, -{"id":233407,"name":"Striker's Footguards","icon":"inv_boots_chain_08","type":10,"armorType":3,"requiresLevel":60,"stats":[0,30,13,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,340,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":78,"phase":6,"quality":4,"classAllowlist":[2],"setName":"Striker's Pursuit"}, -{"id":233408,"name":"Striker's Leggings","icon":"inv_pants_mail_11","type":9,"armorType":3,"requiresLevel":60,"stats":[0,40,12,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,448,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":81,"phase":6,"quality":4,"classAllowlist":[2],"setName":"Striker's Pursuit"}, -{"id":233409,"name":"Striker's Pauldrons","icon":"inv_shoulder_36","type":3,"armorType":3,"requiresLevel":60,"stats":[0,30,10,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,384,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":81,"phase":6,"quality":4,"classAllowlist":[2],"setName":"Striker's Pursuit"}, -{"id":233410,"name":"Striker's Diadem","icon":"inv_helmet_73","type":1,"armorType":3,"requiresLevel":60,"stats":[0,38,14,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,416,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":81,"phase":6,"quality":4,"classAllowlist":[2],"setName":"Striker's Pursuit"}, -{"id":233411,"name":"Striker's Hauberk","icon":"inv_chest_chain_04","type":5,"armorType":3,"requiresLevel":60,"stats":[0,40,15,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,1,2,0,0,0,0,0,0,553,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":88,"phase":6,"quality":4,"classAllowlist":[2],"setName":"Striker's Pursuit"}, +{"id":233407,"name":"Striker's Footguards","icon":"inv_boots_chain_08","type":10,"armorType":3,"requiresLevel":60,"stats":[0,30,13,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,340,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":2,"ilvl":78,"phase":6,"quality":4,"classAllowlist":[2],"setName":"Striker's Pursuit"}, +{"id":233408,"name":"Striker's Leggings","icon":"inv_pants_mail_11","type":9,"armorType":3,"requiresLevel":60,"stats":[0,40,12,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,448,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":2,"ilvl":81,"phase":6,"quality":4,"classAllowlist":[2],"setName":"Striker's Pursuit"}, +{"id":233409,"name":"Striker's Pauldrons","icon":"inv_shoulder_36","type":3,"armorType":3,"requiresLevel":60,"stats":[0,30,10,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,384,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":3,"ilvl":81,"phase":6,"quality":4,"classAllowlist":[2],"setName":"Striker's Pursuit"}, +{"id":233410,"name":"Striker's Diadem","icon":"inv_helmet_73","type":1,"armorType":3,"requiresLevel":60,"stats":[0,38,14,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,416,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":3,"ilvl":81,"phase":6,"quality":4,"classAllowlist":[2],"setName":"Striker's Pursuit"}, +{"id":233411,"name":"Striker's Hauberk","icon":"inv_chest_chain_04","type":5,"armorType":3,"requiresLevel":60,"stats":[0,40,15,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,1,2,0,0,0,0,0,0,553,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":4,"ilvl":88,"phase":6,"quality":4,"classAllowlist":[2],"setName":"Striker's Pursuit"}, {"id":233412,"name":"Genesis Helm","icon":"inv_helmet_06","type":1,"armorType":2,"requiresLevel":60,"stats":[12,16,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,192,0,18,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":81,"phase":6,"quality":4,"classAllowlist":[1],"setName":"Genesis Fury"}, {"id":233413,"name":"Genesis Shoulderpads","icon":"inv_shoulder_03","type":3,"armorType":2,"requiresLevel":60,"stats":[8,8,27,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,172,0,9,0,0,0,0,0,0,0,0,0,0,0,50,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":78,"phase":6,"quality":4,"classAllowlist":[1],"setName":"Genesis Fury"}, {"id":233414,"name":"Genesis Boots","icon":"inv_boots_cloth_07","type":10,"armorType":2,"requiresLevel":60,"stats":[10,10,27,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,158,0,13,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":78,"phase":6,"quality":4,"classAllowlist":[1],"setName":"Genesis Fury"}, @@ -8919,7 +8919,7 @@ {"id":233635,"name":"Belt of Never-ending Agony","icon":"inv_belt_26","type":8,"armorType":2,"requiresLevel":60,"stats":[0,0,20,0,0,0,0,0,0,0,0,0,0,1,1,0,0,60,1,1,0,0,1,0,0,0,142,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":88,"phase":6,"quality":4,"timeworn":true}, {"id":233636,"name":"Scepter of the False Prophet","icon":"inv_mace22","type":13,"weaponType":4,"handType":1,"requiresLevel":60,"stats":[0,0,11,20,0,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponDamageMin":38,"weaponDamageMax":111,"weaponSpeed":1.8,"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":84,"phase":6,"quality":4}, {"id":233637,"name":"Gauntlets of Annihilation","icon":"inv_gauntlets_31","type":7,"armorType":4,"requiresLevel":60,"stats":[34,0,10,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,1,0,0,0,615,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":88,"phase":6,"quality":4,"timeworn":true}, -{"id":233638,"name":"Ring of the Godslayer","icon":"inv_jewelry_ring_ahnqiraj_06","type":11,"requiresLevel":60,"stats":[0,26,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":88,"phase":6,"quality":4,"unique":true}, +{"id":233638,"name":"Ring of the Godslayer","icon":"inv_jewelry_ring_ahnqiraj_06","type":11,"requiresLevel":60,"stats":[0,26,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":3,"ilvl":88,"phase":6,"quality":4,"unique":true}, {"id":233639,"name":"Vanquished Tentacle of C'Thun","icon":"inv_misc_ahnqirajtrinket_05","type":12,"requiresLevel":60,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":88,"phase":6,"quality":4,"unique":true}, {"id":233640,"name":"Dark Edge of Insanity","icon":"inv_axe_24","type":13,"weaponType":1,"handType":4,"requiresLevel":60,"stats":[35,19,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponDamageMin":256,"weaponDamageMax":385,"weaponSpeed":3.7,"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":84,"phase":6,"quality":4,"unique":true}, {"id":233641,"name":"Cloak of Clarity","icon":"inv_misc_cape_02","type":4,"requiresLevel":60,"stats":[0,0,7,12,8,19,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":88,"phase":6,"quality":4}, @@ -9116,7 +9116,7 @@ {"id":234062,"name":"Vestments of the Shifting Sands","icon":"inv_chest_cloth_17","type":5,"armorType":1,"requiresLevel":60,"stats":[0,0,20,14,14,40,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, {"id":234063,"name":"Belt of the Sand Reaver","icon":"inv_belt_13","type":8,"armorType":4,"requiresLevel":60,"stats":[20,0,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,476,0,7,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, {"id":234064,"name":"Belt of the Inquisition","icon":"inv_belt_05","type":8,"armorType":1,"requiresLevel":60,"stats":[0,0,16,17,0,19,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, -{"id":234065,"name":"Sand Reaver Wristguards","icon":"inv_bracer_19","type":6,"armorType":3,"requiresLevel":60,"stats":[0,22,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, +{"id":234065,"name":"Sand Reaver Wristguards","icon":"inv_bracer_19","type":6,"armorType":3,"requiresLevel":60,"stats":[0,22,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":2,"ilvl":75,"phase":6,"quality":4,"timeworn":true}, {"id":234066,"name":"Toughened Silithid Hide Gloves","icon":"inv_gauntlets_24","type":7,"armorType":2,"requiresLevel":60,"stats":[11,15,24,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,139,0,7,0,0,0,0,0,0,0,0,0,0,0,60,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, {"id":234067,"name":"Manslayer of the Qiraji","icon":"inv_sword_56","type":13,"weaponType":9,"handType":4,"requiresLevel":60,"stats":[36,23,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponDamageMin":223,"weaponDamageMax":335,"weaponSpeed":3.8,"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4}, {"id":234068,"name":"Boots of the Vanguard","icon":"inv_boots_08","type":10,"armorType":2,"requiresLevel":60,"stats":[21,26,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, @@ -9134,7 +9134,7 @@ {"id":234081,"name":"Gauntlets of Southwind","icon":"inv_gauntlets_05","type":7,"armorType":2,"requiresLevel":60,"stats":[0,0,11,13,0,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,139,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, {"id":234082,"name":"Mantle of Maz'Nadir","icon":"inv_shoulder_25","type":3,"armorType":1,"requiresLevel":60,"stats":[0,0,11,15,7,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, {"id":234083,"name":"Ring of Fury","icon":"inv_jewelry_ring_ahnqiraj_04","type":11,"requiresLevel":60,"stats":[0,0,9,0,0,0,0,0,0,0,0,0,0,1,0,0,0,48,1,0,0,0,0,0,0,0,0,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"unique":true}, -{"id":234084,"name":"Southwind Helm","icon":"inv_helmet_01","type":1,"armorType":2,"requiresLevel":60,"stats":[26,30,15,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, +{"id":234084,"name":"Southwind Helm","icon":"inv_helmet_01","type":1,"armorType":2,"requiresLevel":60,"stats":[26,30,15,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":3,"ilvl":75,"phase":6,"quality":4,"timeworn":true}, {"id":234086,"name":"Black Grasp of the Destroyer","icon":"inv_gauntlets_31","type":7,"armorType":3,"requiresLevel":60,"stats":[0,0,15,0,0,0,0,0,0,0,0,0,0,0,1,0,0,50,0,1,0,0,0,0,0,0,298,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4}, {"id":234087,"name":"Obsidian Scaled Leggings","icon":"inv_pants_mail_15","type":9,"armorType":3,"requiresLevel":60,"stats":[0,0,30,18,0,18,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,417,0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, {"id":234088,"name":"Legplates of the Destroyer","icon":"inv_pants_plate_01","type":9,"armorType":4,"requiresLevel":60,"stats":[19,0,30,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,740,0,15,0,24,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"timeworn":true}, @@ -9185,7 +9185,7 @@ {"id":234139,"name":"Ravencrest's Legacy","icon":"inv_sword_49","type":13,"weaponType":9,"handType":2,"requiresLevel":60,"stats":[14,9,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponDamageMin":119,"weaponDamageMax":221,"weaponSpeed":2.8,"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":79,"phase":5,"quality":4,"unique":true}, {"id":234141,"name":"Runesword of the Red","icon":"inv_sword_51","type":13,"weaponType":9,"handType":1,"requiresLevel":60,"stats":[0,0,17,10,9,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponDamageMin":51,"weaponDamageMax":132,"weaponSpeed":2.2,"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":79,"phase":5,"quality":4,"unique":true}, {"id":234146,"name":"Acid Inscribed Greaves","icon":"inv_boots_plate_04","type":10,"armorType":4,"requiresLevel":60,"stats":[8,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,581,0,11,0,0,0,0,0,0,0,0,0,25,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4}, -{"id":234147,"name":"Ancient Corroded Leggings","icon":"inv_pants_mail_08","type":9,"armorType":3,"requiresLevel":60,"stats":[0,33,21,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,417,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4}, +{"id":234147,"name":"Ancient Corroded Leggings","icon":"inv_pants_mail_08","type":9,"armorType":3,"requiresLevel":60,"stats":[0,33,21,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,417,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":4,"ilvl":75,"phase":6,"quality":4}, {"id":234148,"name":"Dragonbone Wristguards","icon":"inv_bracer_14","type":6,"armorType":4,"requiresLevel":60,"stats":[10,0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,370,0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4}, {"id":234149,"name":"Dragonspur Wraps","icon":"inv_bracer_15","type":6,"armorType":2,"requiresLevel":60,"stats":[0,0,10,0,0,0,0,0,0,0,0,0,0,1,0,0,0,28,1,0,0,0,0,0,0,0,97,28,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4}, {"id":234150,"name":"Gloves of Delusional Power","icon":"inv_gauntlets_17","type":7,"armorType":1,"requiresLevel":60,"stats":[0,0,14,16,0,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4}, @@ -9315,7 +9315,7 @@ {"id":234748,"name":"Deeprock Bracers","icon":"inv_bracer_07","type":6,"armorType":4,"stats":[19,13,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,370,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4}, {"id":234749,"name":"Earthcalm Orb","icon":"inv_misc_gem_pearl_06","type":13,"weaponType":5,"handType":3,"stats":[0,0,0,12,0,15,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4}, {"id":234760,"name":"Rockfury Bracers","icon":"inv_bracer_12","type":6,"armorType":1,"stats":[0,0,7,0,0,28,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4}, -{"id":234761,"name":"Might of Cenarius","icon":"inv_jewelry_ring_41","type":11,"stats":[0,0,10,0,0,0,0,0,0,0,0,0,0,1,0,0,0,20,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":75,"phase":6,"quality":4,"unique":true}, +{"id":234761,"name":"Might of Cenarius","icon":"inv_jewelry_ring_41","type":11,"stats":[0,0,10,0,0,0,0,0,0,0,0,0,0,1,0,0,0,20,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bonusPhysicalDamage":4,"ilvl":75,"phase":6,"quality":4,"unique":true}, {"id":234779,"name":"Grace of Earth","icon":"inv_misc_herb_02","type":12,"stats":[0,0,0,0,0,19,0,0,0,0,0,0,5,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":70,"phase":6,"quality":4,"unique":true}, {"id":234780,"name":"Band of Earthen Might","icon":"inv_jewelry_ring_19","type":11,"stats":[10,0,14,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":70,"phase":6,"quality":4,"unique":true}, {"id":234782,"name":"Earthpower Vest","icon":"inv_chest_cloth_06","type":5,"armorType":1,"stats":[0,0,0,34,0,30,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"weaponSkills":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ilvl":70,"phase":6,"quality":4}, diff --git a/assets/database/leftover_db.bin b/assets/database/leftover_db.bin index 434257cf0..9d4727ed8 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 a30b08d94..48301cb41 100644 --- a/assets/database/leftover_db.json +++ b/assets/database/leftover_db.json @@ -1482,8 +1482,8 @@ {"effectId":63,"spellId":13538,"name":"Enchant Chest - Lesser Absorption","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":66,"spellId":7457,"name":"Enchant Bracer - Minor Stamina","type":6,"stats":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":66,"spellId":7863,"name":"Enchant Boots - Minor Stamina","type":10,"stats":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, -{"effectId":241,"spellId":7745,"name":"Enchant 2H Weapon - Minor Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":241,"spellId":13503,"name":"Enchant Weapon - Lesser Striking","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, +{"effectId":241,"spellId":7745,"name":"Enchant 2H Weapon - Minor Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":242,"spellId":7748,"name":"Enchant Chest - Lesser Health","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":243,"spellId":7766,"name":"Enchant Bracer - Minor Spirit","type":6,"stats":[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":246,"spellId":7776,"name":"Enchant Chest - Lesser Mana","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, @@ -1585,8 +1585,8 @@ {"effectId":1893,"spellId":20028,"name":"Enchant Chest - Major Mana","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":1894,"spellId":20029,"name":"Enchant Weapon - Icy Chill","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":1896,"spellId":20030,"name":"Enchant 2H Weapon - Superior Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, -{"effectId":1897,"spellId":20031,"name":"Enchant Weapon - Superior Striking","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":1897,"spellId":13695,"name":"Enchant 2H Weapon - Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, +{"effectId":1897,"spellId":20031,"name":"Enchant Weapon - Superior Striking","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":1898,"spellId":20032,"name":"Enchant Weapon - Lifestealing","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":3}, {"effectId":1899,"spellId":20033,"name":"Enchant Weapon - Unholy Weapon","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":1900,"spellId":20034,"name":"Enchant Weapon - Crusader","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, diff --git a/proto/common.proto b/proto/common.proto index 5fcf86c49..f32c20e03 100644 --- a/proto/common.proto +++ b/proto/common.proto @@ -127,7 +127,7 @@ enum Stat { // between the UI and backend. // // It's also OK to include things here which aren't in the PseudoStats struct. -// NextIndex: 31 +// NextIndex: 32 enum PseudoStat { PseudoStatMainHandDps = 0; PseudoStatOffHandDps = 1; @@ -135,6 +135,7 @@ enum PseudoStat { PseudoStatBlockValueMultiplier = 3; PseudoStatDodge = 4; PseudoStatParry = 5; + BonusPhysicalDamage = 31; // Melee Weapon Skill PseudoStatUnarmedSkill = 6; @@ -933,7 +934,7 @@ message SimDatabase { } // Contains only the Item info needed by the sim. -// NextIndex: 20 +// NextIndex: 21 message SimItem { int32 id = 1; int32 requires_level = 16; @@ -951,6 +952,7 @@ message SimItem { double weapon_damage_min = 11; double weapon_damage_max = 12; double weapon_speed = 13; + double bonus_physical_damage = 20; string set_name = 14; int32 set_id = 18; diff --git a/proto/ui.proto b/proto/ui.proto index 87ae7cec7..f029b6bfd 100644 --- a/proto/ui.proto +++ b/proto/ui.proto @@ -44,7 +44,7 @@ message UIFaction { // Contains all information about an Item needed by the UI. // Generally this will include everything needed by the sim, plus some // additional data for displaying / filtering. -// NextIndex: 31 +// NextIndex: 32 message UIItem { int32 id = 1; string name = 2; @@ -65,6 +65,7 @@ message UIItem { double weapon_damage_max = 14; double weapon_speed = 15; repeated double weapon_skills = 28; + double bonus_physical_damage = 31; int32 ilvl = 16; int32 phase = 17; diff --git a/sim/common/sod/crafted/phase_2.go b/sim/common/sod/crafted/phase_2.go index 0697c5f40..af93c9b27 100644 --- a/sim/common/sod/crafted/phase_2.go +++ b/sim/common/sod/crafted/phase_2.go @@ -114,8 +114,6 @@ func init() { core.NewItemEffect(215166, func(agent core.Agent) { character := agent.GetCharacter() - character.PseudoStats.BonusDamage += 3 - actionId := core.ActionID{SpellID: 437349} buffAura := character.GetOrRegisterAura(core.Aura{ diff --git a/sim/common/sod/item_effects/phase_3.go b/sim/common/sod/item_effects/phase_3.go index 825025357..b5c98b2ef 100644 --- a/sim/common/sod/item_effects/phase_3.go +++ b/sim/common/sod/item_effects/phase_3.go @@ -91,7 +91,7 @@ func init() { aura.SetStacks(sim, aura.MaxStacks) }, OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) { - character.PseudoStats.BonusDamage += float64(newStacks - oldStacks) + character.PseudoStats.BonusPhysicalDamage += float64(newStacks - oldStacks) }, OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { if result.Landed() && spell.ProcMask.Matches(core.ProcMaskMeleeOrRanged) { diff --git a/sim/common/sod/item_effects/phase_4.go b/sim/common/sod/item_effects/phase_4.go index 15f5b980d..176d1919f 100644 --- a/sim/common/sod/item_effects/phase_4.go +++ b/sim/common/sod/item_effects/phase_4.go @@ -23,7 +23,6 @@ const ( BroodmothersBrooch = 228163 TreantsBane = 228486 FistOfTheFireswornMolten = 229374 - StuddedTimbermawBrawlers = 227809 ) func init() { @@ -83,8 +82,6 @@ func init() { core.NewItemEffect(WoodcarvedMoonstalker, func(agent core.Agent) { character := agent.GetCharacter() - character.PseudoStats.BonusDamage += 4 - // Woodcarved Moonstalker isn't unique, but presumably the on-use has a shared CD if character.HasAura("Woodcarved Moonstalker") { return @@ -184,12 +181,5 @@ func init() { } }) - // https://www.wowhead.com/classic/item=227809/studded-timbermaw-brawlers - // Equip: +3 Weapon Damage. - core.NewItemEffect(StuddedTimbermawBrawlers, func(agent core.Agent) { - character := agent.GetCharacter() - character.PseudoStats.BonusDamage += 3 - }) - core.AddEffectsToTest = true } diff --git a/sim/common/vanilla/item_effects.go b/sim/common/vanilla/item_effects.go index 6d0cf6f65..caa5ef6f9 100644 --- a/sim/common/vanilla/item_effects.go +++ b/sim/common/vanilla/item_effects.go @@ -2904,7 +2904,7 @@ func init() { aura.SetStacks(sim, aura.MaxStacks) }, OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) { - character.PseudoStats.BonusDamage += 2 * float64(newStacks-oldStacks) + character.PseudoStats.BonusPhysicalDamage += 2 * float64(newStacks-oldStacks) }, OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { if result.Landed() && spell.ProcMask.Matches(core.ProcMaskMeleeOrRanged) { @@ -3049,11 +3049,11 @@ func EnrageAura446327(character *core.Character) *core.Aura { Label: "Enrage (446327)", Duration: time.Second * 15, OnGain: func(aura *core.Aura, sim *core.Simulation) { - character.PseudoStats.BonusDamage += 20 + character.PseudoStats.BonusPhysicalDamage += 20 character.MultiplyAttackSpeed(sim, 1.05) }, OnExpire: func(aura *core.Aura, sim *core.Simulation) { - character.PseudoStats.BonusDamage -= 20 + character.PseudoStats.BonusPhysicalDamage -= 20 character.MultiplyAttackSpeed(sim, 1/1.05) }, }) diff --git a/sim/core/character.go b/sim/core/character.go index 45ea7a552..786d45349 100644 --- a/sim/core/character.go +++ b/sim/core/character.go @@ -189,7 +189,8 @@ func NewCharacter(party *Party, partyIndex int, player *proto.Player) Character character.PseudoStats.BowsSkill += ps[proto.PseudoStat_PseudoStatBowsSkill] character.PseudoStats.CrossbowsSkill += ps[proto.PseudoStat_PseudoStatCrossbowsSkill] character.PseudoStats.GunsSkill += ps[proto.PseudoStat_PseudoStatGunsSkill] - + character.PseudoStats.BonusPhysicalDamage += ps[proto.PseudoStat_BonusPhysicalDamage] + character.PseudoStats.TimewornBonus += int32(ps[proto.PseudoStat_TimewornBonus]) } } @@ -267,7 +268,10 @@ func (character *Character) applyEquipment() { if item.Timeworn { character.PseudoStats.TimewornBonus += 1 } + + character.PseudoStats.BonusPhysicalDamage += item.BonusPhysicalDamage } + } func (character *Character) addUniversalStatDependencies() { @@ -636,6 +640,9 @@ func (character *Character) GetPseudoStatsProto() []float64 { proto.PseudoStat_PseudoStatMeleeSpeedMultiplier: float64(character.PseudoStats.MeleeSpeedMultiplier), proto.PseudoStat_PseudoStatRangedSpeedMultiplier: float64(character.PseudoStats.RangedSpeedMultiplier), proto.PseudoStat_PseudoStatBlockValuePerStrength: float64(character.PseudoStats.BlockValuePerStrength), + + proto.PseudoStat_TimewornBonus: float64(character.PseudoStats.TimewornBonus), + proto.PseudoStat_BonusPhysicalDamage: float64(character.PseudoStats.BonusPhysicalDamage), } } diff --git a/sim/core/consumes.go b/sim/core/consumes.go index 4b383ca3a..15a3f98bc 100644 --- a/sim/core/consumes.go +++ b/sim/core/consumes.go @@ -463,8 +463,8 @@ func applyDefensiveBuffConsumes(character *Character, consumes *proto.Consumes) switch consumes.ArmorElixir { case proto.ArmorElixir_ElixirOfTheIronside: character.AddStats(stats.Stats{ - stats.BonusArmor: 350, - stats.Defense: 5, + stats.BonusArmor: 350, + stats.Defense: 5, stats.NatureResistance: 15, }) case proto.ArmorElixir_ElixirOfSuperiorDefense: @@ -525,8 +525,8 @@ func applyPhysicalBuffConsumes(character *Character, consumes *proto.Consumes) { switch consumes.AgilityElixir { case proto.AgilityElixir_ElixirOfTheHoneyBadger: character.AddStats(stats.Stats{ - stats.Agility: 30, - stats.MeleeCrit: 2 * CritRatingPerCritChance, + stats.Agility: 30, + stats.MeleeCrit: 2 * CritRatingPerCritChance, stats.NatureResistance: 15, }) case proto.AgilityElixir_ElixirOfTheMongoose: @@ -592,7 +592,7 @@ func applySpellBuffConsumes(character *Character, consumes *proto.Consumes) { }) case proto.SpellPowerBuff_ElixirOfTheMageLord: character.AddStats(stats.Stats{ - stats.SpellDamage: 40, + stats.SpellDamage: 40, stats.NatureResistance: 15, }) } @@ -777,7 +777,7 @@ func applyMiscConsumes(character *Character, miscConsumes *proto.MiscConsumes) { } if miscConsumes.BoglingRoot { - character.PseudoStats.BonusDamage += 1 + character.PseudoStats.BonusPhysicalDamage += 1 } if miscConsumes.ElixirOfCoalescedRegret { @@ -908,7 +908,7 @@ func applyEnchantingConsumes(character *Character, consumes *proto.Consumes) { stats.SpellPower: 40, }) } - } + } } /////////////////////////////////////////////////////////////////////////// @@ -1044,6 +1044,7 @@ func (character *Character) newBasicExplosiveSpellConfig(sharedTimer *Timer, act func (character *Character) newSapperSpell(sharedTimer *Timer) *Spell { return character.GetOrRegisterSpell(character.newBasicExplosiveSpellConfig(sharedTimer, SapperActionID, SpellSchoolFire, 450, 750, Cooldown{Timer: character.NewTimer(), Duration: time.Minute * 5}, 375, 625)) } + // Needs testing for Silithid interaction if in raid func (character *Character) newFumigatorSpell(sharedTimer *Timer) *Spell { return character.GetOrRegisterSpell(character.newBasicExplosiveSpellConfig(sharedTimer, FumigatorActionID, SpellSchoolFire, 650, 950, Cooldown{Timer: character.NewTimer(), Duration: time.Minute * 5}, 475, 725)) @@ -1296,7 +1297,7 @@ func makeArmorConsumableMCD(itemId int32, character *Character, cdTimer *Timer) cdDuration := time.Minute * 2 lesserStoneshieldAura := character.NewTemporaryStatsAura("Lesser Stoneshield Potion", actionID, stats.Stats{stats.BonusArmor: 1000}, time.Second*90) greaterStoneshieldAura := character.NewTemporaryStatsAura("Greater Stoneshield Potion", actionID, stats.Stats{stats.BonusArmor: 2000}, time.Second*120) - + return MajorCooldown{ Type: CooldownTypeSurvival, Spell: character.GetOrRegisterSpell(SpellConfig{ @@ -1316,7 +1317,7 @@ func makeArmorConsumableMCD(itemId int32, character *Character, cdTimer *Timer) case 4623: lesserStoneshieldAura.Activate(sim) case 13455: - + greaterStoneshieldAura.Activate(sim) } }, diff --git a/sim/core/database.go b/sim/core/database.go index fd0967798..5c20b4156 100644 --- a/sim/core/database.go +++ b/sim/core/database.go @@ -58,12 +58,13 @@ type Item struct { WeaponDamageMax float64 SwingSpeed float64 - Name string - Stats stats.Stats // Stats applied to wearer - Quality proto.ItemQuality - SetName string // Empty string if not part of a set. - SetID int32 // 0 if not part of a set. - WeaponSkills stats.WeaponSkills + Name string + Stats stats.Stats // Stats applied to wearer + BonusPhysicalDamage float64 + Quality proto.ItemQuality + SetName string // Empty string if not part of a set. + SetID int32 // 0 if not part of a set. + WeaponSkills stats.WeaponSkills Timeworn bool @@ -78,23 +79,24 @@ type Item struct { func ItemFromProto(pData *proto.SimItem) Item { return Item{ - ID: pData.Id, - RequiresLevel: pData.RequiresLevel, - ClassAllowlist: pData.ClassAllowlist, - Name: pData.Name, - Type: pData.Type, - ArmorType: pData.ArmorType, - WeaponType: pData.WeaponType, - HandType: pData.HandType, - RangedWeaponType: pData.RangedWeaponType, - WeaponDamageMin: pData.WeaponDamageMin, - WeaponDamageMax: pData.WeaponDamageMax, - SwingSpeed: pData.WeaponSpeed, - Stats: stats.FromFloatArray(pData.Stats), - SetName: pData.SetName, - SetID: pData.SetId, - WeaponSkills: stats.WeaponSkillsFloatArray(pData.WeaponSkills), - Timeworn: pData.Timeworn, + ID: pData.Id, + RequiresLevel: pData.RequiresLevel, + ClassAllowlist: pData.ClassAllowlist, + Name: pData.Name, + Type: pData.Type, + ArmorType: pData.ArmorType, + WeaponType: pData.WeaponType, + HandType: pData.HandType, + RangedWeaponType: pData.RangedWeaponType, + WeaponDamageMin: pData.WeaponDamageMin, + WeaponDamageMax: pData.WeaponDamageMax, + SwingSpeed: pData.WeaponSpeed, + Stats: stats.FromFloatArray(pData.Stats), + BonusPhysicalDamage: pData.BonusPhysicalDamage, + SetName: pData.SetName, + SetID: pData.SetId, + WeaponSkills: stats.WeaponSkillsFloatArray(pData.WeaponSkills), + Timeworn: pData.Timeworn, } } diff --git a/sim/core/database_load.go b/sim/core/database_load.go index bc7057f87..65db27217 100644 --- a/sim/core/database_load.go +++ b/sim/core/database_load.go @@ -21,23 +21,24 @@ func init() { for i, item := range db.Items { simDB.Items[i] = &proto.SimItem{ - Id: item.Id, - RequiresLevel: item.RequiresLevel, - ClassAllowlist: item.ClassAllowlist, - Name: item.Name, - Type: item.Type, - ArmorType: item.ArmorType, - WeaponType: item.WeaponType, - HandType: item.HandType, - RangedWeaponType: item.RangedWeaponType, - Stats: item.Stats, - WeaponDamageMin: item.WeaponDamageMin, - WeaponDamageMax: item.WeaponDamageMax, - WeaponSpeed: item.WeaponSpeed, - SetName: item.SetName, - SetId: item.SetId, - WeaponSkills: item.WeaponSkills, - Timeworn: item.Timeworn, + Id: item.Id, + RequiresLevel: item.RequiresLevel, + ClassAllowlist: item.ClassAllowlist, + Name: item.Name, + Type: item.Type, + ArmorType: item.ArmorType, + WeaponType: item.WeaponType, + HandType: item.HandType, + RangedWeaponType: item.RangedWeaponType, + Stats: item.Stats, + BonusPhysicalDamage: item.BonusPhysicalDamage, + WeaponDamageMin: item.WeaponDamageMin, + WeaponDamageMax: item.WeaponDamageMax, + WeaponSpeed: item.WeaponSpeed, + SetName: item.SetName, + SetId: item.SetId, + WeaponSkills: item.WeaponSkills, + Timeworn: item.Timeworn, } } diff --git a/sim/core/debuffs.go b/sim/core/debuffs.go index f5f8134f2..d396eac4f 100644 --- a/sim/core/debuffs.go +++ b/sim/core/debuffs.go @@ -1177,10 +1177,10 @@ func CurseOfWeaknessAura(target *Unit, points int32, playerLevel int32) *Aura { ActionID: ActionID{SpellID: spellID}, Duration: time.Minute * 2, OnGain: func(aura *Aura, sim *Simulation) { - aura.Unit.PseudoStats.BonusDamage += modDmgReduction + aura.Unit.PseudoStats.BonusPhysicalDamage += modDmgReduction }, OnExpire: func(aura *Aura, sim *Simulation) { - aura.Unit.PseudoStats.BonusDamage -= modDmgReduction + aura.Unit.PseudoStats.BonusPhysicalDamage -= modDmgReduction }, }) return aura diff --git a/sim/core/spell_result.go b/sim/core/spell_result.go index 85ef0c45c..53dab1f1e 100644 --- a/sim/core/spell_result.go +++ b/sim/core/spell_result.go @@ -139,7 +139,7 @@ func (spell *Spell) GetBonusDamage() float64 { // PseudoStats.BonusDamage is physical "spell power", just return that here. // TODO: Do "MobTypeSpellPower" effects for physical exist? E.g. something like "Do x extra weapon damage against y type"? // If yes then it needs to be handled here and for the multi school case below. - return spell.Unit.PseudoStats.BonusDamage + return spell.Unit.PseudoStats.BonusPhysicalDamage case stats.SchoolIndexArcane: schoolBonusDamage = spell.Unit.GetStat(stats.ArcanePower) case stats.SchoolIndexFire: @@ -163,7 +163,7 @@ func (spell *Spell) GetBonusDamage() float64 { // non-physical schools and would need to be considered against physical here and obviously not applied // if physical is chosen. if baseSchoolIndex == stats.SchoolIndexPhysical { - power = spell.Unit.PseudoStats.BonusDamage + power = spell.Unit.PseudoStats.BonusPhysicalDamage } else { // School and stat indices are ordered the same way. power = spell.Unit.GetStat(stats.ArcanePower + stats.Stat(baseSchoolIndex) - 2) diff --git a/sim/core/spell_school_test.go b/sim/core/spell_school_test.go index 1a5eb925a..3b93557c1 100644 --- a/sim/core/spell_school_test.go +++ b/sim/core/spell_school_test.go @@ -318,7 +318,7 @@ func Test_MultiSchoolSpellPower(t *testing.T) { for i := indexLen - 1; i >= 0; i-- { powerStat := stats.ArcanePower + stats.Stat(baseIndices[i]) - 2 if powerStat == stats.SpellPower { - caster.PseudoStats.BonusDamage = highestValue - 25.0*float64(indexLen-1-i) + caster.PseudoStats.BonusPhysicalDamage = highestValue - 25.0*float64(indexLen-1-i) } else { caster.stats[powerStat] = highestValue - 25.0*float64(indexLen-1-i) } @@ -328,7 +328,7 @@ func Test_MultiSchoolSpellPower(t *testing.T) { for i, baseIndex := range baseIndices { powerStat := stats.ArcanePower + stats.Stat(baseIndex) - 2 if powerStat == stats.SpellPower { - caster.PseudoStats.BonusDamage = highestValue - 25.0*float64(i) + caster.PseudoStats.BonusPhysicalDamage = highestValue - 25.0*float64(i) } else { caster.stats[powerStat] = highestValue - 25.0*float64(i) } @@ -341,8 +341,8 @@ func Test_MultiSchoolSpellPower(t *testing.T) { for _, baseIndex := range baseIndices { powerStat := stats.ArcanePower + stats.Stat(baseIndex) - 2 if powerStat == stats.SpellPower { - if caster.PseudoStats.BonusDamage > highestValFound { - highestValFound = caster.PseudoStats.BonusDamage + if caster.PseudoStats.BonusPhysicalDamage > highestValFound { + highestValFound = caster.PseudoStats.BonusPhysicalDamage highestFound = powerStat } } else { diff --git a/sim/core/stats/stats.go b/sim/core/stats/stats.go index bcf70bc39..2fa33f0bc 100644 --- a/sim/core/stats/stats.go +++ b/sim/core/stats/stats.go @@ -416,7 +416,7 @@ type PseudoStats struct { // "Apply Aura: Mod Damage Done (Physical)", applies to abilities with EffectSpellCoefficient > 0. // This includes almost all "(Normalized) Weapon Damage", but also some "School Damage (Physical)" abilities. - BonusDamage float64 // Comes from '+X Weapon Damage' effects + BonusPhysicalDamage float64 // Comes from '+X Weapon Damage' effects BonusMHDps float64 BonusOHDps float64 diff --git a/sim/druid/tigers_fury.go b/sim/druid/tigers_fury.go index 6a9336360..8f624c3da 100644 --- a/sim/druid/tigers_fury.go +++ b/sim/druid/tigers_fury.go @@ -32,10 +32,10 @@ func (druid *Druid) registerTigersFurySpell() { ActionID: actionID, Duration: 6 * time.Second, OnGain: func(aura *core.Aura, sim *core.Simulation) { - druid.PseudoStats.BonusDamage += dmgBonus + druid.PseudoStats.BonusPhysicalDamage += dmgBonus }, OnExpire: func(aura *core.Aura, sim *core.Simulation) { - druid.PseudoStats.BonusDamage -= dmgBonus + druid.PseudoStats.BonusPhysicalDamage -= dmgBonus }, }) diff --git a/sim/paladin/items.go b/sim/paladin/items.go index a5cd9ccb5..a908da961 100644 --- a/sim/paladin/items.go +++ b/sim/paladin/items.go @@ -269,7 +269,7 @@ func crusadersZealAura465414(character *core.Character) *core.Aura { Label: "Crusader's Zeal", Duration: time.Second * 8, OnGain: func(aura *core.Aura, sim *core.Simulation) { - character.PseudoStats.BonusDamage += 15 + character.PseudoStats.BonusPhysicalDamage += 15 character.MultiplyAttackSpeed(sim, 1.30) // Crusader's zeal proc overwrites scrolls regardless of time left @@ -279,7 +279,7 @@ func crusadersZealAura465414(character *core.Character) *core.Aura { } }, OnExpire: func(aura *core.Aura, sim *core.Simulation) { - character.PseudoStats.BonusDamage -= 15 + character.PseudoStats.BonusPhysicalDamage -= 15 character.MultiplyAttackSpeed(sim, 1/1.30) }, }) diff --git a/sim/rogue/dps_rogue/TestAssassination.results b/sim/rogue/dps_rogue/TestAssassination.results index 78229a398..7cf89b2be 100644 --- a/sim/rogue/dps_rogue/TestAssassination.results +++ b/sim/rogue/dps_rogue/TestAssassination.results @@ -149,7 +149,7 @@ stat_weights_results: { key: "TestAssassination-Phase2-Lvl40-StatWeights-Default" value: { weights: 0.37633 - weights: 0.63147 + weights: 0.63635 weights: 0 weights: 0 weights: 0 @@ -166,8 +166,8 @@ stat_weights_results: { weights: 0 weights: 0 weights: 0.34212 - weights: 5.14343 - weights: 4.25831 + weights: 5.22022 + weights: 4.34088 weights: 0 weights: 0 weights: 0 @@ -309,98 +309,98 @@ dps_results: { dps_results: { key: "TestAssassination-Phase2-Lvl40-Average-Default" value: { - dps: 568.12431 - tps: 403.36826 + dps: 575.99965 + tps: 408.95975 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-LongMultiTarget" value: { - dps: 277.14262 - tps: 196.77126 + dps: 279.78754 + tps: 198.64915 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-LongSingleTarget" value: { - dps: 277.14262 - tps: 196.77126 + dps: 279.78754 + tps: 198.64915 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-ShortSingleTarget" value: { - dps: 297.48201 - tps: 211.21223 + dps: 300.39224 + tps: 213.27849 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-LongMultiTarget" value: { - dps: 154.47345 - tps: 109.67615 + dps: 156.2515 + tps: 110.93856 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-LongSingleTarget" value: { - dps: 154.47345 - tps: 109.67615 + dps: 156.2515 + tps: 110.93856 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-ShortSingleTarget" value: { - dps: 165.19973 - tps: 117.29181 + dps: 167.14676 + tps: 118.6742 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-LongMultiTarget" value: { - dps: 270.26545 - tps: 191.88847 + dps: 272.90152 + tps: 193.76008 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-LongSingleTarget" value: { - dps: 270.26545 - tps: 191.88847 + dps: 272.90152 + tps: 193.76008 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-ShortSingleTarget" value: { - dps: 289.45148 - tps: 205.51055 + dps: 292.30493 + tps: 207.5365 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-LongMultiTarget" value: { - dps: 155.29613 - tps: 110.26025 + dps: 157.06939 + tps: 111.51927 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-LongSingleTarget" value: { - dps: 155.29613 - tps: 110.26025 + dps: 157.06939 + tps: 111.51927 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-ShortSingleTarget" value: { - dps: 165.38053 - tps: 117.42018 + dps: 167.28493 + tps: 118.7723 } } dps_results: { key: "TestAssassination-Phase2-Lvl40-SwitchInFrontOfTarget-Default" value: { - dps: 548.13568 - tps: 389.17633 + dps: 555.66525 + tps: 394.52233 } } diff --git a/sim/rogue/dps_rogue/TestCombat.results b/sim/rogue/dps_rogue/TestCombat.results index a294b6034..864384bc5 100644 --- a/sim/rogue/dps_rogue/TestCombat.results +++ b/sim/rogue/dps_rogue/TestCombat.results @@ -149,7 +149,7 @@ stat_weights_results: { key: "TestCombat-Phase2-Lvl40-StatWeights-Default" value: { weights: 0.36156 - weights: 0.58814 + weights: 0.59368 weights: 0 weights: 0 weights: 0 @@ -166,8 +166,8 @@ stat_weights_results: { weights: 0 weights: 0 weights: 0.32869 - weights: 3.8469 - weights: 3.65987 + weights: 3.92986 + weights: 3.74848 weights: 0 weights: 0 weights: 0 @@ -309,98 +309,98 @@ dps_results: { dps_results: { key: "TestCombat-Phase2-Lvl40-Average-Default" value: { - dps: 521.54556 - tps: 370.29735 + dps: 531.71169 + tps: 377.5153 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-LongMultiTarget" value: { - dps: 204.74949 - tps: 145.37214 + dps: 208.03987 + tps: 147.70831 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-LongSingleTarget" value: { - dps: 177.4997 - tps: 126.02479 + dps: 180.26207 + tps: 127.98607 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-ShortSingleTarget" value: { - dps: 234.00579 - tps: 166.14411 + dps: 237.45502 + tps: 168.59307 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-LongMultiTarget" value: { - dps: 113.13914 - tps: 80.32879 + dps: 115.41787 + tps: 81.94669 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-LongSingleTarget" value: { - dps: 98.50083 - tps: 69.93559 + dps: 100.40169 + tps: 71.2852 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Human-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-ShortSingleTarget" value: { - dps: 130.39198 - tps: 92.57831 + dps: 132.7893 + tps: 94.2804 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-LongMultiTarget" value: { - dps: 204.43303 - tps: 145.14745 + dps: 207.74219 + tps: 147.49695 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-LongSingleTarget" value: { - dps: 175.77764 - tps: 124.80213 + dps: 178.5406 + tps: 126.76382 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-FullBuffs-P2-Consumes-ShortSingleTarget" value: { - dps: 230.09488 - tps: 163.36737 + dps: 233.52889 + tps: 165.80551 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-LongMultiTarget" value: { - dps: 116.48548 - tps: 82.70469 + dps: 118.77544 + tps: 84.33057 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-LongSingleTarget" value: { - dps: 100.54143 - tps: 71.38441 + dps: 102.44067 + tps: 72.73288 } } dps_results: { key: "TestCombat-Phase2-Lvl40-Settings-Orc-p2_daggers-No Poisons-mutilate-NoBuffs-P2-Consumes-ShortSingleTarget" value: { - dps: 131.29614 - tps: 93.22026 + dps: 133.65744 + tps: 94.89678 } } dps_results: { key: "TestCombat-Phase2-Lvl40-SwitchInFrontOfTarget-Default" value: { - dps: 497.77303 - tps: 353.41885 + dps: 507.43522 + tps: 360.27901 } } diff --git a/tools/database/wowhead_tooltips.go b/tools/database/wowhead_tooltips.go index 35573b9be..fc1c51212 100644 --- a/tools/database/wowhead_tooltips.go +++ b/tools/database/wowhead_tooltips.go @@ -209,6 +209,7 @@ var weaponDamageRegex = regexp.MustCompile(`([0-9]+) - ([0-9]+)`) var weaponDamageRegex2 = regexp.MustCompile(`([0-9]+) Damage`) var weaponDamageBonusSchoolRegex = regexp.MustCompile(`\+ ([0-9]+) - ([0-9]+) [a-zA-Z]+ Damage`) var weaponSpeedRegex = regexp.MustCompile(`(([0-9]+).([0-9]+))`) +var physicalBonusDamageRegex = regexp.MustCompile(`\+([0-9]+) Weapon Damage.`) var axesSkill = regexp.MustCompile(`Increased Axes \+([0-9]+)\.`) var swordsSkill = regexp.MustCompile(`Increased Swords \+([0-9]+)\.`) @@ -660,6 +661,17 @@ func (item WowheadItemResponse) GetWeaponSpeed() float64 { return 0 } +func (item WowheadItemResponse) GetPhysicalBonusDamage() float64 { + if matches := physicalBonusDamageRegex.FindStringSubmatch(item.Tooltip); len(matches) > 0 { + bonus, err := strconv.ParseFloat(matches[1], 64) + if err != nil { + log.Fatalf("Failed to parse weapon bonus damage: %s", err) + } + return bonus + } + return 0 +} + func (item WowheadItemResponse) ToItemProto() *proto.UIItem { weaponDamageMin, weaponDamageMax := item.GetWeaponDamage() @@ -678,6 +690,8 @@ func (item WowheadItemResponse) ToItemProto() *proto.UIItem { WeaponSkills: weaponSkillsToSlice(item.GetWeaponSkills()), + BonusPhysicalDamage: item.GetPhysicalBonusDamage(), + WeaponDamageMin: weaponDamageMin, WeaponDamageMax: weaponDamageMax, WeaponSpeed: item.GetWeaponSpeed(), diff --git a/ui/balance_druid/sim.ts b/ui/balance_druid/sim.ts index 44eacb2ce..0348f4555 100644 --- a/ui/balance_druid/sim.ts +++ b/ui/balance_druid/sim.ts @@ -50,7 +50,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecBalanceDruid, { Stat.StatSpellHaste, Stat.StatMP5, ], - + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/core/components/character_stats.tsx b/ui/core/components/character_stats.tsx index d64aa48fe..8c15d5218 100644 --- a/ui/core/components/character_stats.tsx +++ b/ui/core/components/character_stats.tsx @@ -4,102 +4,106 @@ import { ref } from 'tsx-vanilla'; import * as Mechanics from '../constants/mechanics.js'; import { Player } from '../player.js'; import { PseudoStat, Spec, Stat } from '../proto/common.js'; -import { getClassStatName, statOrder } from '../proto_utils/names.js'; -import { Stats } from '../proto_utils/stats.js'; +import { Stats, UnitStat } from '../proto_utils/stats.js'; import { EventID, TypedEvent } from '../typed_event.js'; import { Component } from './component.js'; import { NumberPicker } from './number_picker'; export type StatMods = { talents?: Stats; buffs?: Stats }; -const statGroups = new Map>([ +const statGroups = new Map>([ [ 'Primary', [ - Stat.StatHealth, - Stat.StatMana, + UnitStat.fromStat(Stat.StatHealth), + UnitStat.fromStat(Stat.StatMana), ], ], [ 'Attributes', [ - Stat.StatStrength, - Stat.StatAgility, - Stat.StatStamina, - Stat.StatIntellect, - Stat.StatSpirit, + UnitStat.fromStat(Stat.StatStrength), + UnitStat.fromStat(Stat.StatAgility), + UnitStat.fromStat(Stat.StatStamina), + UnitStat.fromStat(Stat.StatIntellect), + UnitStat.fromStat(Stat.StatSpirit), ] ], [ 'Physical', [ - Stat.StatAttackPower, - Stat.StatFeralAttackPower, - Stat.StatRangedAttackPower, - Stat.StatMeleeHit, - Stat.StatExpertise, - Stat.StatMeleeCrit, - Stat.StatMeleeHaste, + UnitStat.fromStat(Stat.StatAttackPower), + UnitStat.fromStat(Stat.StatFeralAttackPower), + UnitStat.fromStat(Stat.StatRangedAttackPower), + UnitStat.fromStat(Stat.StatMeleeHit), + UnitStat.fromStat(Stat.StatExpertise), + UnitStat.fromStat(Stat.StatMeleeCrit), + UnitStat.fromStat(Stat.StatMeleeHaste), + UnitStat.fromPseudoStat(PseudoStat.BonusPhysicalDamage), ] ], [ 'Spell', [ - Stat.StatSpellPower, - Stat.StatSpellDamage, - Stat.StatArcanePower, - Stat.StatFirePower, - Stat.StatFrostPower, - Stat.StatHolyPower, - Stat.StatNaturePower, - Stat.StatShadowPower, - Stat.StatSpellHit, - Stat.StatSpellCrit, - Stat.StatSpellHaste, - Stat.StatSpellPenetration, - Stat.StatMP5, + UnitStat.fromStat(Stat.StatSpellPower), + UnitStat.fromStat(Stat.StatSpellDamage), + UnitStat.fromStat(Stat.StatArcanePower), + UnitStat.fromStat(Stat.StatFirePower), + UnitStat.fromStat(Stat.StatFrostPower), + UnitStat.fromStat(Stat.StatHolyPower), + UnitStat.fromStat(Stat.StatNaturePower), + UnitStat.fromStat(Stat.StatShadowPower), + UnitStat.fromStat(Stat.StatSpellHit), + UnitStat.fromStat(Stat.StatSpellCrit), + UnitStat.fromStat(Stat.StatSpellHaste), + UnitStat.fromStat(Stat.StatSpellPenetration), + UnitStat.fromStat(Stat.StatMP5), ] ], [ 'Defense', [ - Stat.StatArmor, - Stat.StatBonusArmor, - Stat.StatDefense, - Stat.StatDodge, - Stat.StatParry, - Stat.StatBlock, - Stat.StatBlockValue, + UnitStat.fromStat(Stat.StatArmor), + UnitStat.fromStat(Stat.StatBonusArmor), + UnitStat.fromStat(Stat.StatDefense), + UnitStat.fromStat(Stat.StatDodge), + UnitStat.fromStat(Stat.StatParry), + UnitStat.fromStat(Stat.StatBlock), + UnitStat.fromStat(Stat.StatBlockValue), ] ], [ 'Resistance', [ - Stat.StatArcaneResistance, - Stat.StatFireResistance, - Stat.StatFrostResistance, - Stat.StatNatureResistance, - Stat.StatShadowResistance, + UnitStat.fromStat(Stat.StatArcaneResistance), + UnitStat.fromStat(Stat.StatFireResistance), + UnitStat.fromStat(Stat.StatFrostResistance), + UnitStat.fromStat(Stat.StatNatureResistance), + UnitStat.fromStat(Stat.StatShadowResistance), + ] + ], + [ + 'Misc', + [ + UnitStat.fromPseudoStat(PseudoStat.TimewornBonus), ] ], ]) export class CharacterStats extends Component { - readonly stats: Array; + readonly stats: Array; readonly valueElems: Array; readonly meleeCritCapValueElem: HTMLTableCellElement | undefined; private readonly player: Player; private readonly modifyDisplayStats?: (player: Player) => StatMods; - constructor(parent: HTMLElement, player: Player, stats: Array, modifyDisplayStats?: (player: Player) => StatMods) { + constructor(parent: HTMLElement, player: Player, displayStats: Array, modifyDisplayStats?: (player: Player) => StatMods) { super(parent, 'character-stats-root'); - this.stats = [] + this.stats = []; this.player = player; this.modifyDisplayStats = modifyDisplayStats; - const statsSet = new Set(stats); - const playerLevelRef = ref(); this.player.levelChangeEmitter.on(() => (playerLevelRef.value!.textContent = `Level ${player.getLevel()}`)); @@ -117,14 +121,15 @@ export class CharacterStats extends Component { this.valueElems = []; statGroups.forEach((groupedStats, _) => { - const filteredStats = groupedStats.filter(stat => statsSet.has(stat)) - if (!filteredStats.length) return + const filteredStats = groupedStats.filter(stat => displayStats.find(displayStat => displayStat.equals(stat))); + + if (!filteredStats.length) return; - const body = + const body = ; filteredStats.forEach(stat => { - this.stats.push(stat) + this.stats.push(stat); - const statName = getClassStatName(stat, player.getClass()); + const statName = stat.getName(player.getClass()); const row = ( @@ -133,13 +138,13 @@ export class CharacterStats extends Component { ); body.appendChild(row); - + const valueElem = row.getElementsByClassName('character-stats-table-value')[0] as HTMLTableCellElement; this.valueElems.push(valueElem); - }) + }); - table.appendChild(body) - }) + table.appendChild(body); + }); if (this.shouldShowMeleeCritCap(player)) { const row = ( @@ -183,7 +188,7 @@ export class CharacterStats extends Component { const finalStats = Stats.fromProto(playerStats.finalStats).add(statMods.talents).add(statMods.buffs).add(debuffStats); this.stats.forEach((stat, idx) => { - const bonusStatValue = bonusStats.getStat(stat); + const bonusStatValue = bonusStats.getUnitStat(stat); let contextualClass: string; if (bonusStatValue === 0) { contextualClass = 'text-white'; @@ -231,7 +236,7 @@ export class CharacterStats extends Component { Consumes: {this.statDisplayString(player, consumesStats, consumesDelta, stat)} - {debuffStats.getStat(stat) != 0 && ( + {stat.isStat() && debuffStats.getStat(stat.getStat()) != 0 && (
Debuffs: {this.statDisplayString(player, debuffStats, debuffStats, stat)} @@ -251,7 +256,7 @@ export class CharacterStats extends Component {
); - if (stat === Stat.StatMeleeHit) { + if (stat.isStat() && stat.getStat() === Stat.StatMeleeHit) { tooltipContent.appendChild(
@@ -299,7 +304,7 @@ export class CharacterStats extends Component {
, ); - } else if (stat === Stat.StatSpellHit) { + } else if (stat.isStat() && stat.getStat() === Stat.StatSpellHit) { tooltipContent.appendChild(
@@ -402,58 +407,62 @@ export class CharacterStats extends Component { } } - private statDisplayString(player: Player, stats: Stats, deltaStats: Stats, stat: Stat): string { - let rawValue = deltaStats.getStat(stat); + private statDisplayString(player: Player, stats: Stats, deltaStats: Stats, unitStat: UnitStat): string { + const rawValue = deltaStats.getUnitStat(unitStat); + let displayStr: string | undefined; - if (stat === Stat.StatBlockValue) { - rawValue *= stats.getPseudoStat(PseudoStat.PseudoStatBlockValueMultiplier) || 1; - rawValue += Math.max(0, stats.getPseudoStat(PseudoStat.PseudoStatBlockValuePerStrength) * deltaStats.getStat(Stat.StatStrength) - 1); - } + if (unitStat.isStat()) { + const stat = unitStat.getStat(); - let displayStr = String(Math.round(rawValue)); - - if (stat === Stat.StatMeleeHit) { - displayStr = `${(rawValue / Mechanics.MELEE_HIT_RATING_PER_HIT_CHANCE).toFixed(2)}%`; - } else if (stat === Stat.StatSpellHit) { - displayStr = `${(rawValue / Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE).toFixed(2)}%`; - } else if (stat === Stat.StatSpellDamage) { - const spDmg = Math.round(rawValue); - const baseSp = Math.round(deltaStats.getStat(Stat.StatSpellPower)); - displayStr = baseSp + spDmg + ` (+${spDmg})`; - } else if ( - stat === Stat.StatArcanePower || - stat === Stat.StatFirePower || - stat === Stat.StatFrostPower || - stat === Stat.StatHolyPower || - stat === Stat.StatNaturePower || - stat === Stat.StatShadowPower - ) { - const spDmg = Math.round(rawValue); - const baseSp = Math.round(deltaStats.getStat(Stat.StatSpellPower) + deltaStats.getStat(Stat.StatSpellDamage)); - displayStr = baseSp + spDmg + ` (+${spDmg})`; - } else if (stat === Stat.StatMeleeCrit || stat === Stat.StatSpellCrit) { - displayStr = `${(rawValue / Mechanics.SPELL_CRIT_RATING_PER_CRIT_CHANCE).toFixed(2)}%`; - } else if (stat === Stat.StatMeleeHaste) { - // Melee Haste doesn't actually exist in vanilla so use the melee speed pseudostat - displayStr = `${(deltaStats.getPseudoStat(PseudoStat.PseudoStatMeleeSpeedMultiplier) * 100).toFixed(2)}%`; - } else if (stat === Stat.StatSpellHaste) { - displayStr = `${(rawValue / Mechanics.HASTE_RATING_PER_HASTE_PERCENT).toFixed(2)}%`; - } else if (stat === Stat.StatArmorPenetration) { - displayStr += ` (${(rawValue / Mechanics.ARMOR_PEN_PER_PERCENT_ARMOR).toFixed(2)}%)`; - } else if (stat === Stat.StatExpertise) { - // It's just like crit and hit in SoD. - displayStr += `%`; - } else if (stat === Stat.StatDefense) { - displayStr = `${(player.getLevel() * 5 + Math.floor(rawValue / Mechanics.DEFENSE_RATING_PER_DEFENSE)).toFixed(0)}`; - } else if (stat === Stat.StatBlock) { - displayStr = `${(rawValue / Mechanics.BLOCK_RATING_PER_BLOCK_CHANCE).toFixed(2)}%`; - } else if (stat === Stat.StatDodge) { - displayStr = `${(rawValue / Mechanics.DODGE_RATING_PER_DODGE_CHANCE).toFixed(2)}%`; - } else if (stat === Stat.StatParry) { - displayStr = `${(rawValue / Mechanics.PARRY_RATING_PER_PARRY_CHANCE).toFixed(2)}%`; - } else if (stat === Stat.StatResilience) { - displayStr += ` (${(rawValue / Mechanics.RESILIENCE_RATING_PER_CRIT_REDUCTION_CHANCE).toFixed(2)}%)`; + if (stat === Stat.StatBlockValue) { + const mult = stats.getPseudoStat(PseudoStat.PseudoStatBlockValueMultiplier) || 1; + const perStr = Math.max(0, stats.getPseudoStat(PseudoStat.PseudoStatBlockValuePerStrength) * deltaStats.getStat(Stat.StatStrength) - 1); + displayStr = String(Math.round((rawValue * mult) + perStr)); + } else if (stat === Stat.StatMeleeHit) { + displayStr = `${(rawValue / Mechanics.MELEE_HIT_RATING_PER_HIT_CHANCE).toFixed(2)}%`; + } else if (stat === Stat.StatSpellHit) { + displayStr = `${(rawValue / Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE).toFixed(2)}%`; + } else if (stat === Stat.StatSpellDamage) { + const spDmg = Math.round(rawValue); + const baseSp = Math.round(deltaStats.getStat(Stat.StatSpellPower)); + displayStr = baseSp + spDmg + ` (+${spDmg})`; + } else if ( + stat === Stat.StatArcanePower || + stat === Stat.StatFirePower || + stat === Stat.StatFrostPower || + stat === Stat.StatHolyPower || + stat === Stat.StatNaturePower || + stat === Stat.StatShadowPower + ) { + const spDmg = Math.round(rawValue); + const baseSp = Math.round(deltaStats.getStat(Stat.StatSpellPower) + deltaStats.getStat(Stat.StatSpellDamage)); + displayStr = baseSp + spDmg + ` (+${spDmg})`; + } else if (stat === Stat.StatMeleeCrit || stat === Stat.StatSpellCrit) { + displayStr = `${(rawValue / Mechanics.SPELL_CRIT_RATING_PER_CRIT_CHANCE).toFixed(2)}%`; + } else if (stat === Stat.StatMeleeHaste) { + // Melee Haste doesn't actually exist in vanilla so use the melee speed pseudostat + displayStr = `${(deltaStats.getPseudoStat(PseudoStat.PseudoStatMeleeSpeedMultiplier) * 100).toFixed(2)}%`; + } else if (stat === Stat.StatSpellHaste) { + displayStr = `${(rawValue / Mechanics.HASTE_RATING_PER_HASTE_PERCENT).toFixed(2)}%`; + } else if (stat === Stat.StatArmorPenetration) { + displayStr = `${rawValue} (${(rawValue / Mechanics.ARMOR_PEN_PER_PERCENT_ARMOR).toFixed(2)}%)`; + } else if (stat === Stat.StatExpertise) { + // It's just like crit and hit in SoD. + displayStr = `${rawValue}%`; + } else if (stat === Stat.StatDefense) { + displayStr = `${(player.getLevel() * 5 + Math.floor(rawValue / Mechanics.DEFENSE_RATING_PER_DEFENSE)).toFixed(0)}`; + } else if (stat === Stat.StatBlock) { + displayStr = `${(rawValue / Mechanics.BLOCK_RATING_PER_BLOCK_CHANCE).toFixed(2)}%`; + } else if (stat === Stat.StatDodge) { + displayStr = `${(rawValue / Mechanics.DODGE_RATING_PER_DODGE_CHANCE).toFixed(2)}%`; + } else if (stat === Stat.StatParry) { + displayStr = `${(rawValue / Mechanics.PARRY_RATING_PER_PARRY_CHANCE).toFixed(2)}%`; + } else if (stat === Stat.StatResilience) { + displayStr = `${rawValue} (${(rawValue / Mechanics.RESILIENCE_RATING_PER_CRIT_REDUCTION_CHANCE).toFixed(2)}%)`; + } } + + if (!displayStr) displayStr = String(Math.round(rawValue)); return displayStr; } @@ -478,8 +487,8 @@ export class CharacterStats extends Component { return debuffStats; } - private bonusStatsLink(stat: Stat): HTMLElement { - const statName = getClassStatName(stat, this.player.getClass()); + private bonusStatsLink(stat: UnitStat): HTMLElement { + const statName = stat.getName(this.player.getClass()); const linkRef = ref(); const iconRef = ref(); @@ -502,13 +511,13 @@ export class CharacterStats extends Component { placement: 'right', onShow: instance => { const picker = new NumberPicker(null, this.player, { - id: `character-bonus-stat-${stat}`, + id: `character-bonus-${stat.isStat() ? 'stat-' + stat.getStat() : 'pseudostat-' + stat.getPseudoStat()}`, label: `Bonus ${statName}`, extraCssClasses: ['mb-0'], changedEvent: (player: Player) => player.bonusStatsChangeEmitter, - getValue: (player: Player) => player.getBonusStats().getStat(stat), + getValue: (player: Player) => player.getBonusStats().getUnitStat(stat), setValue: (eventID: EventID, player: Player, newValue: number) => { - const bonusStats = player.getBonusStats().withStat(stat, newValue); + const bonusStats = player.getBonusStats().withUnitStat(stat, newValue); player.setBonusStats(eventID, bonusStats); instance?.hide(); }, diff --git a/ui/core/components/stat_weights_action.ts b/ui/core/components/stat_weights_action.ts index 61f1e182e..41d916264 100644 --- a/ui/core/components/stat_weights_action.ts +++ b/ui/core/components/stat_weights_action.ts @@ -749,7 +749,12 @@ class EpWeightsMenu extends BaseModal { if (stat.isStat()) { return true; } else { - return [PseudoStat.PseudoStatMainHandDps, PseudoStat.PseudoStatOffHandDps, PseudoStat.PseudoStatRangedDps].includes(stat.getPseudoStat()); + return [ + PseudoStat.PseudoStatMainHandDps, + PseudoStat.PseudoStatOffHandDps, + PseudoStat.PseudoStatRangedDps, + PseudoStat.BonusPhysicalDamage + ].includes(stat.getPseudoStat()); } }); } diff --git a/ui/core/constants/other.ts b/ui/core/constants/other.ts index 6cd30a371..bc748ef48 100644 --- a/ui/core/constants/other.ts +++ b/ui/core/constants/other.ts @@ -35,6 +35,10 @@ export const GLOBAL_DISPLAY_STATS = [ Stat.StatNatureResistance, ]; +export const GLOBAL_DISPLAY_PSEUDO_STATS = [ + PseudoStat.TimewornBonus, +]; + export const GLOBAL_EP_STATS = [ Stat.StatFireResistance, Stat.StatFrostResistance, diff --git a/ui/core/individual_sim_ui.ts b/ui/core/individual_sim_ui.ts index 654716ef5..a03d650f6 100644 --- a/ui/core/individual_sim_ui.ts +++ b/ui/core/individual_sim_ui.ts @@ -15,7 +15,7 @@ import * as InputHelpers from './components/input_helpers'; import { addRaidSimAction, RaidSimResultsManager } from './components/raid_sim_action'; import { SavedDataConfig } from './components/saved_data_manager'; import { addStatWeightsAction } from './components/stat_weights_action'; -import { GLOBAL_DISPLAY_STATS, GLOBAL_EP_STATS, LEVEL_THRESHOLDS } from './constants/other'; +import { GLOBAL_DISPLAY_PSEUDO_STATS, GLOBAL_DISPLAY_STATS, GLOBAL_EP_STATS, LEVEL_THRESHOLDS } from './constants/other'; import * as Tooltips from './constants/tooltips'; import { simLaunchStatuses } from './launched_sims'; import { Player, PlayerConfig, registerSpecConfig as registerPlayerConfig } from './player'; @@ -42,7 +42,7 @@ import { import { IndividualSimSettings, SavedTalents } from './proto/ui'; import { ItemSwapGear } from './proto_utils/gear'; import { professionNames } from './proto_utils/names'; -import { Stats } from './proto_utils/stats'; +import { Stats, UnitStat } from './proto_utils/stats'; import { getTalentPoints, isHealingSpec, isTankSpec, SpecOptions, SpecRotation, specToEligibleRaces, specToLocalStorageKey } from './proto_utils/utils'; import { SimSettingCategories } from './sim'; import { SimUI, SimWarning } from './sim_ui'; @@ -98,6 +98,7 @@ export interface IndividualSimUIConfig extends PlayerConf epPseudoStats?: Array; epReferenceStat: Stat; displayStats: Array; + displayPseudoStats: Array; modifyDisplayStats?: (player: Player) => StatMods; defaults: { @@ -328,10 +329,18 @@ export abstract class IndividualSimUI extends SimUI { this.raidSimResultsManager = addRaidSimAction(this); addStatWeightsAction(this, this.individualConfig.epStats.concat(GLOBAL_EP_STATS), this.individualConfig.epPseudoStats, this.individualConfig.epReferenceStat); + const displayStats: UnitStat[] = []; + + this.individualConfig.displayStats.forEach(s => displayStats.push(UnitStat.fromStat(s))); + GLOBAL_DISPLAY_STATS.forEach(s => displayStats.push(UnitStat.fromStat(s))); + + this.individualConfig.displayPseudoStats.forEach(ps => displayStats.push(UnitStat.fromPseudoStat(ps))); + GLOBAL_DISPLAY_PSEUDO_STATS.forEach(ps => displayStats.push(UnitStat.fromPseudoStat(ps))); + new CharacterStats( this.rootElem.getElementsByClassName('sim-sidebar-stats')[0] as HTMLElement, this.player, - this.individualConfig.displayStats.concat(GLOBAL_DISPLAY_STATS), + displayStats, this.individualConfig.modifyDisplayStats, ); } diff --git a/ui/core/player.ts b/ui/core/player.ts index 1721ace8a..b0da94a9f 100644 --- a/ui/core/player.ts +++ b/ui/core/player.ts @@ -1076,6 +1076,9 @@ export class Player { } } + // Add pseudo stats that should be included in item EP. + itemStats = itemStats.addPseudoStat(PseudoStat.BonusPhysicalDamage, item.bonusPhysicalDamage); + // For random suffix items, use the suffix option with the highest EP for the purposes of ranking items in the picker. let maxSuffixEP = 0; diff --git a/ui/core/proto_utils/names.ts b/ui/core/proto_utils/names.ts index e4e053f6e..1f5e5fd31 100644 --- a/ui/core/proto_utils/names.ts +++ b/ui/core/proto_utils/names.ts @@ -208,6 +208,7 @@ export const pseudoStatNames: Map = new Map([ [PseudoStat.PseudoStatRangedDps, 'Ranged DPS'], [PseudoStat.PseudoStatBlockValueMultiplier, 'Block Value Multiplier'], [PseudoStat.TimewornBonus, 'Timeworn Pieces'], + [PseudoStat.BonusPhysicalDamage, 'Bonus Weapon Damage'], ]); export function getClassStatName(stat: Stat, playerClass: Class): string { diff --git a/ui/elemental_shaman/sim.ts b/ui/elemental_shaman/sim.ts index 237c710b6..c992f375a 100644 --- a/ui/elemental_shaman/sim.ts +++ b/ui/elemental_shaman/sim.ts @@ -52,6 +52,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecElementalShaman, { Stat.StatSpellHaste, Stat.StatMP5, ], + displayPseudoStats: [], defaults: { race: Race.RaceTroll, diff --git a/ui/enhancement_shaman/sim.ts b/ui/enhancement_shaman/sim.ts index 511092393..9307deb85 100644 --- a/ui/enhancement_shaman/sim.ts +++ b/ui/enhancement_shaman/sim.ts @@ -66,7 +66,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecEnhancementShaman, { Stat.StatSpellHaste, Stat.StatMP5, ], - + displayPseudoStats: [], + defaults: { race: Race.RaceTroll, // Default equipped gear. diff --git a/ui/feral_druid/sim.ts b/ui/feral_druid/sim.ts index db6a3974f..1323f299d 100644 --- a/ui/feral_druid/sim.ts +++ b/ui/feral_druid/sim.ts @@ -4,7 +4,7 @@ import { Phase } from '../core/constants/other.js'; import { IndividualSimUI, registerSpecConfig } from '../core/individual_sim_ui.js'; import { Player } from '../core/player.js'; import { APLRotation_Type as APLRotationType } from '../core/proto/apl.js'; -import { Class, Faction, ItemSlot, PartyBuffs, Race, Spec, Stat, WeaponImbue } from '../core/proto/common.js'; +import { Class, Faction, ItemSlot, PartyBuffs, PseudoStat, Race, Spec, Stat, WeaponImbue } from '../core/proto/common.js'; import { Gear } from '../core/proto_utils/gear.js'; import { Stats } from '../core/proto_utils/stats.js'; import { getSpecIcon, specNames } from '../core/proto_utils/utils.js'; @@ -38,7 +38,9 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecFeralDruid, { // Spell Stat.StatMP5, ], - epPseudoStats: [], + epPseudoStats: [ + PseudoStat.BonusPhysicalDamage, + ], // Reference stat against which to calculate EP. I think all classes use either spell power or attack power. epReferenceStat: Stat.StatAttackPower, // Which stats to display in the Character Stats section, at the bottom of the left-hand sidebar. @@ -59,6 +61,9 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecFeralDruid, { // Spell Stat.StatMP5, ], + displayPseudoStats: [ + PseudoStat.BonusPhysicalDamage, + ], defaults: { // Default equipped gear. diff --git a/ui/feral_tank_druid/sim.ts b/ui/feral_tank_druid/sim.ts index 951e1635b..0450c93c1 100644 --- a/ui/feral_tank_druid/sim.ts +++ b/ui/feral_tank_druid/sim.ts @@ -53,7 +53,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecFeralTankDruid, { Stat.StatSpellCrit, Stat.StatShadowResistance, ], - + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/healing_priest/sim.ts b/ui/healing_priest/sim.ts index 044167685..0cf3ec279 100644 --- a/ui/healing_priest/sim.ts +++ b/ui/healing_priest/sim.ts @@ -47,6 +47,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecHealingPriest, { Stat.StatSpellHaste, Stat.StatMP5, ], + displayPseudoStats: [], defaults: { // Default equipped gear. diff --git a/ui/holy_paladin/sim.ts b/ui/holy_paladin/sim.ts index 5942d6e8b..63f0b9e09 100644 --- a/ui/holy_paladin/sim.ts +++ b/ui/holy_paladin/sim.ts @@ -29,6 +29,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecHolyPaladin, { Stat.StatSpellHaste, Stat.StatMP5, ], + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/hunter/sim.ts b/ui/hunter/sim.ts index a8f4c3dd6..b0fbe3d9a 100644 --- a/ui/hunter/sim.ts +++ b/ui/hunter/sim.ts @@ -70,7 +70,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecHunter, { Stat.StatSpellCrit, Stat.StatMP5, ], - + displayPseudoStats: [], + defaults: { race: Presets.OtherDefaults.race, // Default equipped gear. diff --git a/ui/mage/sim.ts b/ui/mage/sim.ts index ead51b43e..897b73b23 100644 --- a/ui/mage/sim.ts +++ b/ui/mage/sim.ts @@ -51,6 +51,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecMage, { Stat.StatSpellHaste, Stat.StatMP5, ], + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/protection_paladin/sim.ts b/ui/protection_paladin/sim.ts index 73773c500..14fe21eb8 100644 --- a/ui/protection_paladin/sim.ts +++ b/ui/protection_paladin/sim.ts @@ -103,7 +103,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecProtectionPaladin, { Stat.StatShadowResistance, Stat.StatArcaneResistance, ], - + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/restoration_druid/sim.ts b/ui/restoration_druid/sim.ts index 1ef8d10ae..5ecaf9598 100644 --- a/ui/restoration_druid/sim.ts +++ b/ui/restoration_druid/sim.ts @@ -45,7 +45,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecRestorationDruid, { Stat.StatSpellHaste, Stat.StatMP5, ], - + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/restoration_shaman/sim.ts b/ui/restoration_shaman/sim.ts index 58f032eb7..b8f1bb433 100644 --- a/ui/restoration_shaman/sim.ts +++ b/ui/restoration_shaman/sim.ts @@ -31,7 +31,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecRestorationShaman, { Stat.StatSpellHaste, Stat.StatMP5, ], - + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/retribution_paladin/sim.ts b/ui/retribution_paladin/sim.ts index b5c13a796..589b1ada4 100644 --- a/ui/retribution_paladin/sim.ts +++ b/ui/retribution_paladin/sim.ts @@ -82,7 +82,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecRetributionPaladin, { Stat.StatSpellHit, Stat.StatMP5, ], - + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/rogue/sim.ts b/ui/rogue/sim.ts index 9d777bb0a..72c84488e 100644 --- a/ui/rogue/sim.ts +++ b/ui/rogue/sim.ts @@ -88,6 +88,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecRogue, { Stat.StatSpellHit, Stat.StatSpellCrit, ], + displayPseudoStats: [], defaults: { // Default equipped gear. diff --git a/ui/shadow_priest/sim.ts b/ui/shadow_priest/sim.ts index 86688b9ef..88f86ffbc 100644 --- a/ui/shadow_priest/sim.ts +++ b/ui/shadow_priest/sim.ts @@ -49,6 +49,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecShadowPriest, { Stat.StatSpellCrit, Stat.StatMP5, ], + displayPseudoStats: [], + modifyDisplayStats: (player: Player) => { let stats = new Stats(); stats = stats.addPseudoStat(PseudoStat.PseudoStatSchoolHitShadow, player.getTalents().shadowFocus * 2 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); diff --git a/ui/tank_rogue/sim.ts b/ui/tank_rogue/sim.ts index 392f6ac6a..88ba70dd6 100644 --- a/ui/tank_rogue/sim.ts +++ b/ui/tank_rogue/sim.ts @@ -63,7 +63,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecTankRogue, { // Resistances Stat.StatShadowResistance, ], - + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/tank_warlock/sim.ts b/ui/tank_warlock/sim.ts index 949a40b5e..d4b9f5700 100644 --- a/ui/tank_warlock/sim.ts +++ b/ui/tank_warlock/sim.ts @@ -80,7 +80,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecTankWarlock, { // Resistances Stat.StatShadowResistance, ], - + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/tank_warrior/sim.ts b/ui/tank_warrior/sim.ts index 6cd626214..a17b5be9b 100644 --- a/ui/tank_warrior/sim.ts +++ b/ui/tank_warrior/sim.ts @@ -64,7 +64,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecTankWarrior, { // Resistances Stat.StatShadowResistance, ], - + displayPseudoStats: [], + defaults: { // Default equipped gear. gear: Presets.DefaultGear.gear, diff --git a/ui/warden_shaman/sim.ts b/ui/warden_shaman/sim.ts index 730204562..8328459f0 100644 --- a/ui/warden_shaman/sim.ts +++ b/ui/warden_shaman/sim.ts @@ -83,7 +83,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecWardenShaman, { // Resistances Stat.StatShadowResistance, ], - + displayPseudoStats: [], + defaults: { race: Race.RaceTroll, // Default equipped gear. diff --git a/ui/warlock/sim.ts b/ui/warlock/sim.ts index df1f024a9..c2db7d3a3 100644 --- a/ui/warlock/sim.ts +++ b/ui/warlock/sim.ts @@ -70,6 +70,8 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecWarlock, { Stat.StatSpellHaste, Stat.StatMP5, ], + displayPseudoStats: [], + // TODO: Figure out a way to get the stat but right now this comes out wrong // due to pet scaling and player getting some dynamic buffs which we cant get here // modifyDisplayStats: (player: Player) => { diff --git a/ui/warrior/sim.ts b/ui/warrior/sim.ts index 22a2e4fdf..2985d4d89 100644 --- a/ui/warrior/sim.ts +++ b/ui/warrior/sim.ts @@ -46,6 +46,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecWarrior, { Stat.StatMeleeHaste, Stat.StatExpertise, ], + displayPseudoStats: [], defaults: { race: Presets.OtherDefaults.race,