From 01ac94681d278e782b9e895866b1cf3341f80239 Mon Sep 17 00:00:00 2001 From: Kevin Ferm Date: Tue, 12 Mar 2024 13:27:17 +0100 Subject: [PATCH 1/2] Add Cataclysm Talents and Glyphs --- assets/db_inputs/glyph_id_map.json | 697 ++++--- proto/common.proto | 15 +- proto/death_knight.proto | 189 +- proto/druid.proto | 196 +- proto/hunter.proto | 252 ++- proto/mage.proto | 195 +- proto/paladin.proto | 187 +- proto/priest.proto | 182 +- proto/rogue.proto | 167 +- proto/shaman.proto | 179 +- proto/warlock.proto | 177 +- proto/warrior.proto | 192 +- sim/core/character.go | 7 +- tools/database/wowhead_reforge_db.go | 3 +- tools/scrape_glyphs.py | 71 +- tools/scrape_pet_talents.py | 64 + tools/scrape_pet_talents_config.py | 150 ++ tools/scrape_proto.sh | 11 + tools/scrape_talents_config.py | 76 +- tools/scrape_talents_proto.py | 17 +- ui/core/components/exporters.tsx | 15 +- ui/core/player.ts | 10 +- ui/core/talents/death_knight.ts | 213 +- ui/core/talents/druid.ts | 247 +-- ui/core/talents/factory.ts | 8 +- ui/core/talents/glyphs_picker.tsx | 31 +- ui/core/talents/hunter.ts | 182 +- ui/core/talents/hunter_pet.ts | 12 +- ui/core/talents/mage.ts | 220 +-- ui/core/talents/paladin.ts | 245 +-- ui/core/talents/priest.ts | 201 +- ui/core/talents/rogue.ts | 168 +- ui/core/talents/shaman.ts | 218 ++- ui/core/talents/talents_picker.tsx | 6 +- ui/core/talents/trees/death_knight.json | 1979 ++++++++----------- ui/core/talents/trees/druid.json | 2054 +++++++++----------- ui/core/talents/trees/hunter.json | 1922 ++++++++---------- ui/core/talents/trees/hunter_cunning.json | 540 ++--- ui/core/talents/trees/hunter_ferocity.json | 505 ++--- ui/core/talents/trees/hunter_tenacity.json | 536 ++--- ui/core/talents/trees/mage.json | 2009 ++++++++----------- ui/core/talents/trees/paladin.json | 1772 ++++++++--------- ui/core/talents/trees/priest.json | 1981 +++++++++---------- ui/core/talents/trees/rogue.json | 1900 ++++++++---------- ui/core/talents/trees/shaman.json | 1822 ++++++++--------- ui/core/talents/trees/warlock.json | 1889 ++++++++---------- ui/core/talents/trees/warrior.json | 1961 ++++++++----------- ui/core/talents/warlock.ts | 193 +- ui/core/talents/warrior.ts | 204 +- 49 files changed, 11795 insertions(+), 14275 deletions(-) create mode 100644 tools/scrape_pet_talents.py create mode 100644 tools/scrape_pet_talents_config.py create mode 100644 tools/scrape_proto.sh diff --git a/assets/db_inputs/glyph_id_map.json b/assets/db_inputs/glyph_id_map.json index 70dd3f727c..20101bdd34 100644 --- a/assets/db_inputs/glyph_id_map.json +++ b/assets/db_inputs/glyph_id_map.json @@ -1,350 +1,349 @@ [ - {"itemId": 43361,"spellId":52648}, - {"itemId": 40909,"spellId":54733}, - {"itemId": 40912,"spellId":54743}, - {"itemId": 40913,"spellId":54754}, - {"itemId": 40922,"spellId":54756}, - {"itemId": 40924,"spellId":54760}, - {"itemId": 40896,"spellId":54810}, - {"itemId": 40897,"spellId":54811}, - {"itemId": 40899,"spellId":54812}, - {"itemId": 40900,"spellId":54813}, - {"itemId": 40901,"spellId":54815}, - {"itemId": 40902,"spellId":54818}, - {"itemId": 40903,"spellId":54821}, - {"itemId": 40906,"spellId":54824}, - {"itemId": 40914,"spellId":54825}, - {"itemId": 40915,"spellId":54826}, - {"itemId": 40921,"spellId":54828}, - {"itemId": 40923,"spellId":54829}, - {"itemId": 40919,"spellId":54830}, - {"itemId": 40920,"spellId":54831}, - {"itemId": 40908,"spellId":54832}, - {"itemId": 40916,"spellId":54845}, - {"itemId": 41092,"spellId":54922}, - {"itemId": 41095,"spellId":54923}, - {"itemId": 41096,"spellId":54924}, - {"itemId": 41094,"spellId":54925}, - {"itemId": 41097,"spellId":54926}, - {"itemId": 41098,"spellId":54927}, - {"itemId": 41099,"spellId":54928}, - {"itemId": 41100,"spellId":54929}, - {"itemId": 41101,"spellId":54930}, - {"itemId": 41102,"spellId":54931}, - {"itemId": 41103,"spellId":54934}, - {"itemId": 41104,"spellId":54935}, - {"itemId": 41105,"spellId":54936}, - {"itemId": 41106,"spellId":54937}, - {"itemId": 41107,"spellId":54938}, - {"itemId": 41108,"spellId":54939}, - {"itemId": 41109,"spellId":54940}, - {"itemId": 41110,"spellId":54943}, - {"itemId": 41541,"spellId":55436}, - {"itemId": 41517,"spellId":55437}, - {"itemId": 41535,"spellId":55438}, - {"itemId": 41527,"spellId":55439}, - {"itemId": 41534,"spellId":55440}, - {"itemId": 41538,"spellId":55441}, - {"itemId": 41526,"spellId":55442}, - {"itemId": 41547,"spellId":55443}, - {"itemId": 41540,"spellId":55444}, - {"itemId": 41542,"spellId":55445}, - {"itemId": 41539,"spellId":55446}, - {"itemId": 41531,"spellId":55447}, - {"itemId": 41537,"spellId":55448}, - {"itemId": 41518,"spellId":55449}, - {"itemId": 41530,"spellId":55450}, - {"itemId": 41532,"spellId":55451}, - {"itemId": 41552,"spellId":55452}, - {"itemId": 41536,"spellId":55453}, - {"itemId": 41524,"spellId":55454}, - {"itemId": 41529,"spellId":55455}, - {"itemId": 41533,"spellId":55456}, - {"itemId": 42408,"spellId":55672}, - {"itemId": 42403,"spellId":55673}, - {"itemId": 42411,"spellId":55674}, - {"itemId": 42396,"spellId":55675}, - {"itemId": 42410,"spellId":55676}, - {"itemId": 42397,"spellId":55677}, - {"itemId": 42399,"spellId":55678}, - {"itemId": 42400,"spellId":55679}, - {"itemId": 42409,"spellId":55680}, - {"itemId": 42406,"spellId":55681}, - {"itemId": 42414,"spellId":55682}, - {"itemId": 42401,"spellId":55683}, - {"itemId": 42398,"spellId":55684}, - {"itemId": 42417,"spellId":55685}, - {"itemId": 42402,"spellId":55686}, - {"itemId": 42415,"spellId":55687}, - {"itemId": 42405,"spellId":55688}, - {"itemId": 42407,"spellId":55689}, - {"itemId": 42412,"spellId":55690}, - {"itemId": 42404,"spellId":55691}, - {"itemId": 42416,"spellId":55692}, - {"itemId": 42469,"spellId":56216}, - {"itemId": 42463,"spellId":56217}, - {"itemId": 42455,"spellId":56218}, - {"itemId": 42462,"spellId":56224}, - {"itemId": 42466,"spellId":56226}, - {"itemId": 42464,"spellId":56228}, - {"itemId": 42468,"spellId":56229}, - {"itemId": 42470,"spellId":56231}, - {"itemId": 42457,"spellId":56232}, - {"itemId": 42472,"spellId":56233}, - {"itemId": 42454,"spellId":56235}, - {"itemId": 42461,"spellId":56238}, - {"itemId": 42467,"spellId":56240}, - {"itemId": 42456,"spellId":56241}, - {"itemId": 42453,"spellId":56242}, - {"itemId": 42458,"spellId":56244}, - {"itemId": 42459,"spellId":56246}, - {"itemId": 42473,"spellId":56247}, - {"itemId": 42465,"spellId":56248}, - {"itemId": 42460,"spellId":56249}, - {"itemId": 42471,"spellId":56250}, - {"itemId": 42734,"spellId":56360}, - {"itemId": 42735,"spellId":56363}, - {"itemId": 42753,"spellId":56364}, - {"itemId": 42737,"spellId":56365}, - {"itemId": 42748,"spellId":56366}, - {"itemId": 42750,"spellId":56367}, - {"itemId": 42739,"spellId":56368}, - {"itemId": 42740,"spellId":56369}, - {"itemId": 42742,"spellId":56370}, - {"itemId": 42747,"spellId":56371}, - {"itemId": 42744,"spellId":56372}, - {"itemId": 42754,"spellId":56373}, - {"itemId": 42746,"spellId":56374}, - {"itemId": 42752,"spellId":56375}, - {"itemId": 42741,"spellId":56376}, - {"itemId": 42745,"spellId":56377}, - {"itemId": 42738,"spellId":56380}, - {"itemId": 42736,"spellId":56381}, - {"itemId": 42751,"spellId":56382}, - {"itemId": 42749,"spellId":56383}, - {"itemId": 42743,"spellId":56384}, - {"itemId": 43868,"spellId":56414}, - {"itemId": 43869,"spellId":56416}, - {"itemId": 43867,"spellId":56420}, - {"itemId": 42970,"spellId":56798}, - {"itemId": 42960,"spellId":56799}, - {"itemId": 42956,"spellId":56800}, - {"itemId": 42969,"spellId":56801}, - {"itemId": 42961,"spellId":56802}, - {"itemId": 42962,"spellId":56803}, - {"itemId": 42963,"spellId":56804}, - {"itemId": 42971,"spellId":56805}, - {"itemId": 42959,"spellId":56806}, - {"itemId": 42967,"spellId":56807}, - {"itemId": 42954,"spellId":56808}, - {"itemId": 42966,"spellId":56809}, - {"itemId": 42973,"spellId":56810}, - {"itemId": 42974,"spellId":56811}, - {"itemId": 42964,"spellId":56812}, - {"itemId": 42955,"spellId":56813}, - {"itemId": 42965,"spellId":56814}, - {"itemId": 42957,"spellId":56818}, - {"itemId": 42968,"spellId":56819}, - {"itemId": 42958,"spellId":56820}, - {"itemId": 42972,"spellId":56821}, - {"itemId": 42897,"spellId":56824}, - {"itemId": 42914,"spellId":56826}, - {"itemId": 42911,"spellId":56828}, - {"itemId": 42907,"spellId":56829}, - {"itemId": 42902,"spellId":56830}, - {"itemId": 42912,"spellId":56832}, - {"itemId": 42900,"spellId":56833}, - {"itemId": 42910,"spellId":56836}, - {"itemId": 42916,"spellId":56838}, - {"itemId": 42898,"spellId":56841}, - {"itemId": 42915,"spellId":56842}, - {"itemId": 42904,"spellId":56844}, - {"itemId": 42905,"spellId":56845}, - {"itemId": 42908,"spellId":56846}, - {"itemId": 42906,"spellId":56847}, - {"itemId": 42917,"spellId":56848}, - {"itemId": 42913,"spellId":56849}, - {"itemId": 42903,"spellId":56850}, - {"itemId": 42901,"spellId":56851}, - {"itemId": 42909,"spellId":56856}, - {"itemId": 42899,"spellId":56857}, - {"itemId": 43335,"spellId":57855}, - {"itemId": 43316,"spellId":57856}, - {"itemId": 43331,"spellId":57857}, - {"itemId": 43334,"spellId":57858}, - {"itemId": 43332,"spellId":57862}, - {"itemId": 43338,"spellId":57866}, - {"itemId": 43350,"spellId":57870}, - {"itemId": 43354,"spellId":57900}, - {"itemId": 43356,"spellId":57902}, - {"itemId": 43351,"spellId":57903}, - {"itemId": 43355,"spellId":57904}, - {"itemId": 43339,"spellId":57924}, - {"itemId": 43364,"spellId":57925}, - {"itemId": 43357,"spellId":57926}, - {"itemId": 43360,"spellId":57927}, - {"itemId": 43359,"spellId":57928}, - {"itemId": 43365,"spellId":57937}, - {"itemId": 43368,"spellId":57947}, - {"itemId": 43369,"spellId":57954}, - {"itemId": 43367,"spellId":57955}, - {"itemId": 43340,"spellId":57958}, - {"itemId": 43366,"spellId":57979}, - {"itemId": 43342,"spellId":57985}, - {"itemId": 43373,"spellId":57986}, - {"itemId": 43370,"spellId":57987}, - {"itemId": 43371,"spellId":58009}, - {"itemId": 43372,"spellId":58015}, - {"itemId": 43343,"spellId":58017}, - {"itemId": 43377,"spellId":58027}, - {"itemId": 43376,"spellId":58032}, - {"itemId": 43378,"spellId":58033}, - {"itemId": 43380,"spellId":58038}, - {"itemId": 43379,"spellId":58039}, - {"itemId": 43344,"spellId":58055}, - {"itemId": 43388,"spellId":58057}, - {"itemId": 43381,"spellId":58058}, - {"itemId": 43385,"spellId":58059}, - {"itemId": 43386,"spellId":58063}, - {"itemId": 43390,"spellId":58070}, - {"itemId": 43389,"spellId":58079}, - {"itemId": 43392,"spellId":58080}, - {"itemId": 43391,"spellId":58081}, - {"itemId": 43394,"spellId":58094}, - {"itemId": 43395,"spellId":58095}, - {"itemId": 43396,"spellId":58096}, - {"itemId": 43397,"spellId":58097}, - {"itemId": 43399,"spellId":58098}, - {"itemId": 43398,"spellId":58099}, - {"itemId": 43400,"spellId":58104}, - {"itemId": 43393,"spellId":58107}, - {"itemId": 43374,"spellId":58228}, - {"itemId": 43429,"spellId":58353}, - {"itemId": 43413,"spellId":58355}, - {"itemId": 43430,"spellId":58356}, - {"itemId": 43418,"spellId":58357}, - {"itemId": 43424,"spellId":58364}, - {"itemId": 43420,"spellId":58365}, - {"itemId": 43414,"spellId":58366}, - {"itemId": 43416,"spellId":58367}, - {"itemId": 43421,"spellId":58368}, - {"itemId": 43412,"spellId":58369}, - {"itemId": 43432,"spellId":58370}, - {"itemId": 43417,"spellId":58372}, - {"itemId": 43425,"spellId":58375}, - {"itemId": 43426,"spellId":58376}, - {"itemId": 43419,"spellId":58377}, - {"itemId": 43431,"spellId":58382}, - {"itemId": 43428,"spellId":58384}, - {"itemId": 43423,"spellId":58385}, - {"itemId": 43422,"spellId":58386}, - {"itemId": 43427,"spellId":58387}, - {"itemId": 43415,"spellId":58388}, - {"itemId": 43538,"spellId":58613}, - {"itemId": 43534,"spellId":58616}, - {"itemId": 43552,"spellId":58618}, - {"itemId": 43537,"spellId":58620}, - {"itemId": 43533,"spellId":58623}, - {"itemId": 43545,"spellId":58625}, - {"itemId": 43542,"spellId":58629}, - {"itemId": 43546,"spellId":58631}, - {"itemId": 43553,"spellId":58635}, - {"itemId": 43535,"spellId":58640}, - {"itemId": 43551,"spellId":58642}, - {"itemId": 43543,"spellId":58647}, - {"itemId": 43548,"spellId":58657}, - {"itemId": 43550,"spellId":58669}, - {"itemId": 43547,"spellId":58671}, - {"itemId": 43536,"spellId":58673}, - {"itemId": 43554,"spellId":58676}, - {"itemId": 43539,"spellId":58677}, - {"itemId": 43544,"spellId":58680}, - {"itemId": 43549,"spellId":58686}, - {"itemId": 43674,"spellId":59219}, - {"itemId": 43725,"spellId":59289}, - {"itemId": 43671,"spellId":59307}, - {"itemId": 43672,"spellId":59309}, - {"itemId": 43825,"spellId":59327}, - {"itemId": 43826,"spellId":59332}, - {"itemId": 43827,"spellId":59336}, - {"itemId": 43673,"spellId":60200}, - {"itemId": 44684,"spellId":61205}, - {"itemId": 44928,"spellId":62080}, - {"itemId": 44920,"spellId":62126}, - {"itemId": 44923,"spellId":62132}, - {"itemId": 44922,"spellId":62135}, - {"itemId": 44955,"spellId":62210}, - {"itemId": 43541,"spellId":62259}, - {"itemId": 45601,"spellId":62969}, - {"itemId": 45602,"spellId":62970}, - {"itemId": 45603,"spellId":62971}, - {"itemId": 45604,"spellId":63055}, - {"itemId": 45622,"spellId":63056}, - {"itemId": 45623,"spellId":63057}, - {"itemId": 45625,"spellId":63065}, - {"itemId": 45731,"spellId":63066}, - {"itemId": 45732,"spellId":63067}, - {"itemId": 45733,"spellId":63068}, - {"itemId": 45734,"spellId":63069}, - {"itemId": 45735,"spellId":63086}, - {"itemId": 45736,"spellId":63090}, - {"itemId": 45737,"spellId":63091}, - {"itemId": 45738,"spellId":63092}, - {"itemId": 45739,"spellId":63093}, - {"itemId": 45740,"spellId":63095}, - {"itemId": 45741,"spellId":63218}, - {"itemId": 45742,"spellId":63219}, - {"itemId": 45743,"spellId":63220}, - {"itemId": 45744,"spellId":63222}, - {"itemId": 45745,"spellId":63223}, - {"itemId": 45746,"spellId":63224}, - {"itemId": 45747,"spellId":63225}, - {"itemId": 45753,"spellId":63229}, - {"itemId": 45755,"spellId":63231}, - {"itemId": 45756,"spellId":63235}, - {"itemId": 45757,"spellId":63237}, - {"itemId": 45758,"spellId":63246}, - {"itemId": 45760,"spellId":63248}, - {"itemId": 45761,"spellId":63249}, - {"itemId": 45762,"spellId":63252}, - {"itemId": 45764,"spellId":63253}, - {"itemId": 45766,"spellId":63254}, - {"itemId": 45767,"spellId":63256}, - {"itemId": 45768,"spellId":63268}, - {"itemId": 45769,"spellId":63269}, - {"itemId": 45770,"spellId":63270}, - {"itemId": 45771,"spellId":63271}, - {"itemId": 45772,"spellId":63273}, - {"itemId": 45775,"spellId":63279}, - {"itemId": 45776,"spellId":63280}, - {"itemId": 45777,"spellId":63291}, - {"itemId": 45778,"spellId":63298}, - {"itemId": 45779,"spellId":63302}, - {"itemId": 45780,"spellId":63303}, - {"itemId": 45781,"spellId":63304}, - {"itemId": 45782,"spellId":63309}, - {"itemId": 45783,"spellId":63310}, - {"itemId": 45789,"spellId":63312}, - {"itemId": 45785,"spellId":63320}, - {"itemId": 45790,"spellId":63324}, - {"itemId": 45792,"spellId":63325}, - {"itemId": 45793,"spellId":63326}, - {"itemId": 45794,"spellId":63327}, - {"itemId": 45795,"spellId":63328}, - {"itemId": 45797,"spellId":63329}, - {"itemId": 45799,"spellId":63330}, - {"itemId": 45800,"spellId":63331}, - {"itemId": 45803,"spellId":63332}, - {"itemId": 45804,"spellId":63333}, - {"itemId": 45805,"spellId":63334}, - {"itemId": 45806,"spellId":63335}, - {"itemId": 46372,"spellId":65243}, - {"itemId": 48720,"spellId":67598}, - {"itemId": 49084,"spellId":68164}, - {"itemId": 50045,"spellId":70937}, - {"itemId": 50077,"spellId":70947}, - {"itemId": 50125,"spellId":71013}, - {"itemId": 204385,"spellId":405004}, - {"itemId": 206580,"spellId":413895}, - {"itemId": 206953,"spellId":414812} - ] \ No newline at end of file + {"itemId": 40919, "spellId": 54830}, + {"itemId": 40900, "spellId": 54813}, + {"itemId": 40912, "spellId": 54743}, + {"itemId": 40913, "spellId": 54754}, + {"itemId": 40922, "spellId": 54756}, + {"itemId": 40901, "spellId": 54815}, + {"itemId": 40902, "spellId": 54818}, + {"itemId": 40906, "spellId": 54824}, + {"itemId": 40915, "spellId": 54826}, + {"itemId": 40923, "spellId": 54829}, + {"itemId": 40916, "spellId": 54845}, + {"itemId": 45601, "spellId": 62969}, + {"itemId": 45603, "spellId": 62971}, + {"itemId": 45604, "spellId": 63055}, + {"itemId": 67484, "spellId": 94382}, + {"itemId": 67487, "spellId": 94390}, + {"itemId": 40896, "spellId": 54810}, + {"itemId": 45623, "spellId": 63057}, + {"itemId": 206580, "spellId": 413895}, + {"itemId": 40909, "spellId": 54733}, + {"itemId": 40924, "spellId": 54760}, + {"itemId": 40897, "spellId": 54811}, + {"itemId": 40899, "spellId": 54812}, + {"itemId": 40903, "spellId": 54821}, + {"itemId": 40914, "spellId": 54825}, + {"itemId": 40921, "spellId": 54828}, + {"itemId": 40920, "spellId": 54831}, + {"itemId": 40908, "spellId": 54832}, + {"itemId": 43332, "spellId": 57862}, + {"itemId": 44928, "spellId": 62080}, + {"itemId": 45602, "spellId": 62970}, + {"itemId": 45622, "spellId": 63056}, + {"itemId": 48720, "spellId": 67598}, + {"itemId": 67485, "spellId": 94386}, + {"itemId": 67486, "spellId": 94388}, + {"itemId": 43335, "spellId": 57855}, + {"itemId": 43316, "spellId": 57856}, + {"itemId": 43331, "spellId": 57857}, + {"itemId": 43334, "spellId": 57858}, + {"itemId": 43674, "spellId": 59219}, + {"itemId": 44922, "spellId": 62135}, + {"itemId": 68039, "spellId": 95212}, + {"itemId": 42897, "spellId": 56824}, + {"itemId": 42914, "spellId": 56826}, + {"itemId": 42911, "spellId": 56828}, + {"itemId": 42912, "spellId": 56832}, + {"itemId": 42898, "spellId": 56841}, + {"itemId": 42915, "spellId": 56842}, + {"itemId": 42909, "spellId": 56856}, + {"itemId": 45625, "spellId": 63065}, + {"itemId": 45731, "spellId": 63066}, + {"itemId": 45732, "spellId": 63067}, + {"itemId": 42907, "spellId": 56829}, + {"itemId": 42904, "spellId": 56844}, + {"itemId": 42902, "spellId": 56830}, + {"itemId": 42900, "spellId": 56833}, + {"itemId": 42910, "spellId": 56836}, + {"itemId": 42905, "spellId": 56845}, + {"itemId": 42908, "spellId": 56846}, + {"itemId": 42906, "spellId": 56847}, + {"itemId": 42917, "spellId": 56848}, + {"itemId": 42913, "spellId": 56849}, + {"itemId": 42903, "spellId": 56850}, + {"itemId": 42901, "spellId": 56851}, + {"itemId": 42899, "spellId": 56857}, + {"itemId": 45733, "spellId": 63068}, + {"itemId": 45734, "spellId": 63069}, + {"itemId": 45735, "spellId": 63086}, + {"itemId": 43356, "spellId": 57902}, + {"itemId": 43338, "spellId": 57866}, + {"itemId": 43350, "spellId": 57870}, + {"itemId": 43351, "spellId": 57903}, + {"itemId": 43355, "spellId": 57904}, + {"itemId": 42735, "spellId": 56363}, + {"itemId": 42753, "spellId": 56364}, + {"itemId": 42739, "spellId": 56368}, + {"itemId": 42742, "spellId": 56370}, + {"itemId": 42745, "spellId": 56377}, + {"itemId": 42751, "spellId": 56382}, + {"itemId": 42749, "spellId": 56383}, + {"itemId": 42743, "spellId": 56384}, + {"itemId": 44684, "spellId": 61205}, + {"itemId": 44955, "spellId": 62210}, + {"itemId": 45736, "spellId": 63090}, + {"itemId": 45738, "spellId": 63092}, + {"itemId": 63539, "spellId": 89926}, + {"itemId": 42737, "spellId": 56365}, + {"itemId": 42748, "spellId": 56366}, + {"itemId": 42744, "spellId": 56372}, + {"itemId": 42754, "spellId": 56373}, + {"itemId": 42746, "spellId": 56374}, + {"itemId": 42752, "spellId": 56375}, + {"itemId": 42741, "spellId": 56376}, + {"itemId": 42738, "spellId": 56380}, + {"itemId": 42736, "spellId": 56381}, + {"itemId": 44920, "spellId": 62126}, + {"itemId": 45737, "spellId": 63091}, + {"itemId": 45740, "spellId": 63095}, + {"itemId": 50045, "spellId": 70937}, + {"itemId": 69773, "spellId": 98397}, + {"itemId": 43339, "spellId": 57924}, + {"itemId": 43364, "spellId": 57925}, + {"itemId": 43360, "spellId": 57927}, + {"itemId": 43359, "spellId": 57928}, + {"itemId": 45739, "spellId": 63093}, + {"itemId": 63416, "spellId": 89749}, + {"itemId": 41092, "spellId": 54922}, + {"itemId": 41098, "spellId": 54927}, + {"itemId": 41105, "spellId": 54936}, + {"itemId": 45743, "spellId": 63220}, + {"itemId": 41103, "spellId": 54934}, + {"itemId": 41106, "spellId": 54937}, + {"itemId": 41110, "spellId": 54943}, + {"itemId": 43869, "spellId": 56416}, + {"itemId": 45742, "spellId": 63219}, + {"itemId": 45744, "spellId": 63222}, + {"itemId": 45746, "spellId": 63224}, + {"itemId": 41097, "spellId": 54926}, + {"itemId": 41104, "spellId": 54935}, + {"itemId": 41107, "spellId": 54938}, + {"itemId": 41109, "spellId": 54940}, + {"itemId": 43868, "spellId": 56414}, + {"itemId": 43867, "spellId": 56420}, + {"itemId": 43367, "spellId": 57955}, + {"itemId": 66918, "spellId": 93466}, + {"itemId": 41095, "spellId": 54923}, + {"itemId": 41096, "spellId": 54924}, + {"itemId": 41094, "spellId": 54925}, + {"itemId": 41099, "spellId": 54928}, + {"itemId": 41101, "spellId": 54930}, + {"itemId": 41102, "spellId": 54931}, + {"itemId": 41108, "spellId": 54939}, + {"itemId": 45741, "spellId": 63218}, + {"itemId": 45745, "spellId": 63223}, + {"itemId": 45747, "spellId": 63225}, + {"itemId": 204385, "spellId": 405004}, + {"itemId": 43365, "spellId": 57937}, + {"itemId": 43340, "spellId": 57958}, + {"itemId": 43368, "spellId": 57947}, + {"itemId": 43369, "spellId": 57954}, + {"itemId": 43366, "spellId": 57979}, + {"itemId": 41100, "spellId": 89401}, + {"itemId": 45753, "spellId": 63229}, + {"itemId": 42408, "spellId": 55672}, + {"itemId": 42403, "spellId": 55673}, + {"itemId": 42411, "spellId": 55674}, + {"itemId": 42400, "spellId": 55679}, + {"itemId": 42409, "spellId": 55680}, + {"itemId": 42406, "spellId": 55681}, + {"itemId": 42414, "spellId": 55682}, + {"itemId": 42415, "spellId": 55687}, + {"itemId": 42407, "spellId": 55689}, + {"itemId": 45755, "spellId": 63231}, + {"itemId": 45756, "spellId": 63235}, + {"itemId": 42397, "spellId": 55677}, + {"itemId": 42398, "spellId": 55684}, + {"itemId": 42412, "spellId": 55690}, + {"itemId": 42396, "spellId": 55675}, + {"itemId": 42410, "spellId": 55676}, + {"itemId": 42399, "spellId": 55678}, + {"itemId": 42401, "spellId": 55683}, + {"itemId": 42417, "spellId": 55685}, + {"itemId": 42402, "spellId": 55686}, + {"itemId": 42405, "spellId": 55688}, + {"itemId": 42404, "spellId": 55691}, + {"itemId": 42416, "spellId": 55692}, + {"itemId": 45757, "spellId": 63237}, + {"itemId": 45758, "spellId": 63246}, + {"itemId": 45760, "spellId": 63248}, + {"itemId": 43342, "spellId": 57985}, + {"itemId": 43373, "spellId": 57986}, + {"itemId": 43370, "spellId": 57987}, + {"itemId": 43371, "spellId": 58009}, + {"itemId": 43372, "spellId": 58015}, + {"itemId": 43374, "spellId": 58228}, + {"itemId": 77101, "spellId": 107906}, + {"itemId": 41541, "spellId": 55436}, + {"itemId": 41527, "spellId": 55439}, + {"itemId": 41526, "spellId": 55442}, + {"itemId": 41540, "spellId": 55444}, + {"itemId": 41542, "spellId": 55445}, + {"itemId": 41539, "spellId": 55446}, + {"itemId": 41531, "spellId": 55447}, + {"itemId": 41532, "spellId": 55451}, + {"itemId": 41536, "spellId": 55453}, + {"itemId": 41524, "spellId": 55454}, + {"itemId": 41529, "spellId": 55455}, + {"itemId": 45771, "spellId": 63271}, + {"itemId": 45772, "spellId": 63273}, + {"itemId": 45775, "spellId": 63279}, + {"itemId": 71155, "spellId": 101052}, + {"itemId": 45770, "spellId": 63270}, + {"itemId": 41517, "spellId": 55437}, + {"itemId": 41535, "spellId": 55438}, + {"itemId": 41534, "spellId": 55440}, + {"itemId": 41538, "spellId": 55441}, + {"itemId": 41547, "spellId": 55443}, + {"itemId": 41537, "spellId": 55448}, + {"itemId": 41518, "spellId": 55449}, + {"itemId": 41530, "spellId": 55450}, + {"itemId": 41552, "spellId": 55452}, + {"itemId": 41533, "spellId": 55456}, + {"itemId": 43725, "spellId": 59289}, + {"itemId": 45776, "spellId": 63280}, + {"itemId": 45777, "spellId": 63291}, + {"itemId": 45778, "spellId": 63298}, + {"itemId": 43388, "spellId": 58057}, + {"itemId": 43381, "spellId": 58058}, + {"itemId": 43385, "spellId": 58059}, + {"itemId": 43386, "spellId": 58135}, + {"itemId": 44923, "spellId": 62132}, + {"itemId": 43344, "spellId": 89646}, + {"itemId": 42455, "spellId": 56218}, + {"itemId": 45779, "spellId": 63302}, + {"itemId": 45781, "spellId": 63304}, + {"itemId": 42464, "spellId": 56228}, + {"itemId": 42468, "spellId": 56229}, + {"itemId": 42472, "spellId": 56233}, + {"itemId": 42454, "spellId": 56235}, + {"itemId": 42456, "spellId": 56241}, + {"itemId": 42453, "spellId": 56242}, + {"itemId": 42459, "spellId": 56246}, + {"itemId": 42465, "spellId": 56248}, + {"itemId": 45780, "spellId": 63303}, + {"itemId": 50077, "spellId": 70947}, + {"itemId": 42462, "spellId": 56224}, + {"itemId": 42460, "spellId": 56249}, + {"itemId": 42463, "spellId": 56217}, + {"itemId": 42466, "spellId": 56226}, + {"itemId": 42470, "spellId": 56231}, + {"itemId": 42457, "spellId": 56232}, + {"itemId": 42467, "spellId": 56240}, + {"itemId": 42458, "spellId": 56244}, + {"itemId": 42473, "spellId": 56247}, + {"itemId": 42471, "spellId": 56250}, + {"itemId": 45782, "spellId": 63309}, + {"itemId": 45783, "spellId": 63310}, + {"itemId": 45789, "spellId": 63312}, + {"itemId": 45785, "spellId": 63320}, + {"itemId": 42461, "spellId": 56238}, + {"itemId": 43389, "spellId": 58079}, + {"itemId": 43392, "spellId": 58080}, + {"itemId": 43391, "spellId": 58081}, + {"itemId": 43394, "spellId": 58094}, + {"itemId": 43393, "spellId": 58107}, + {"itemId": 43423, "spellId": 58385}, + {"itemId": 43416, "spellId": 58367}, + {"itemId": 43424, "spellId": 58364}, + {"itemId": 43421, "spellId": 58368}, + {"itemId": 43432, "spellId": 58370}, + {"itemId": 43425, "spellId": 58375}, + {"itemId": 43422, "spellId": 58386}, + {"itemId": 43415, "spellId": 58388}, + {"itemId": 45790, "spellId": 63324}, + {"itemId": 43397, "spellId": 58097}, + {"itemId": 43413, "spellId": 58355}, + {"itemId": 43418, "spellId": 58357}, + {"itemId": 43431, "spellId": 58382}, + {"itemId": 45797, "spellId": 63329}, + {"itemId": 67482, "spellId": 94372}, + {"itemId": 43399, "spellId": 58098}, + {"itemId": 43430, "spellId": 58356}, + {"itemId": 43414, "spellId": 58366}, + {"itemId": 43417, "spellId": 58372}, + {"itemId": 43419, "spellId": 58377}, + {"itemId": 43428, "spellId": 58384}, + {"itemId": 43427, "spellId": 58387}, + {"itemId": 45792, "spellId": 63325}, + {"itemId": 45795, "spellId": 63328}, + {"itemId": 63481, "spellId": 89003}, + {"itemId": 67483, "spellId": 94374}, + {"itemId": 45794, "spellId": 63327}, + {"itemId": 43400, "spellId": 58104}, + {"itemId": 43395, "spellId": 58095}, + {"itemId": 43396, "spellId": 58096}, + {"itemId": 43398, "spellId": 58099}, + {"itemId": 43412, "spellId": 58369}, + {"itemId": 45793, "spellId": 63326}, + {"itemId": 49084, "spellId": 68164}, + {"itemId": 206953, "spellId": 414812}, + {"itemId": 43550, "spellId": 58669}, + {"itemId": 43542, "spellId": 58629}, + {"itemId": 43543, "spellId": 58647}, + {"itemId": 43534, "spellId": 58616}, + {"itemId": 43546, "spellId": 58631}, + {"itemId": 43551, "spellId": 58642}, + {"itemId": 43547, "spellId": 58671}, + {"itemId": 43549, "spellId": 58686}, + {"itemId": 43827, "spellId": 59336}, + {"itemId": 45804, "spellId": 63333}, + {"itemId": 45806, "spellId": 63335}, + {"itemId": 43536, "spellId": 58673}, + {"itemId": 43533, "spellId": 58623}, + {"itemId": 43825, "spellId": 59327}, + {"itemId": 43541, "spellId": 62259}, + {"itemId": 43552, "spellId": 58618}, + {"itemId": 43537, "spellId": 58620}, + {"itemId": 43553, "spellId": 58635}, + {"itemId": 43548, "spellId": 58657}, + {"itemId": 43554, "spellId": 58676}, + {"itemId": 43826, "spellId": 59332}, + {"itemId": 45799, "spellId": 63330}, + {"itemId": 45800, "spellId": 63331}, + {"itemId": 68793, "spellId": 96279}, + {"itemId": 43535, "spellId": 58640}, + {"itemId": 43539, "spellId": 58677}, + {"itemId": 43544, "spellId": 58680}, + {"itemId": 43671, "spellId": 59307}, + {"itemId": 43672, "spellId": 59309}, + {"itemId": 43673, "spellId": 60200}, + {"itemId": 42956, "spellId": 56800}, + {"itemId": 42969, "spellId": 56801}, + {"itemId": 42961, "spellId": 56802}, + {"itemId": 42967, "spellId": 56807}, + {"itemId": 42954, "spellId": 56808}, + {"itemId": 42973, "spellId": 56810}, + {"itemId": 42965, "spellId": 56814}, + {"itemId": 42972, "spellId": 56821}, + {"itemId": 45761, "spellId": 63249}, + {"itemId": 45762, "spellId": 63252}, + {"itemId": 45764, "spellId": 63253}, + {"itemId": 45768, "spellId": 63268}, + {"itemId": 42962, "spellId": 56803}, + {"itemId": 45766, "spellId": 63254}, + {"itemId": 42970, "spellId": 56798}, + {"itemId": 42960, "spellId": 56799}, + {"itemId": 42963, "spellId": 56804}, + {"itemId": 42971, "spellId": 56805}, + {"itemId": 42959, "spellId": 56806}, + {"itemId": 42966, "spellId": 56809}, + {"itemId": 42974, "spellId": 56811}, + {"itemId": 42964, "spellId": 56812}, + {"itemId": 42955, "spellId": 56813}, + {"itemId": 42957, "spellId": 56818}, + {"itemId": 42968, "spellId": 56819}, + {"itemId": 42958, "spellId": 56820}, + {"itemId": 45767, "spellId": 63256}, + {"itemId": 45769, "spellId": 63269}, + {"itemId": 63420, "spellId": 89758}, + {"itemId": 64493, "spellId": 91299}, + {"itemId": 43343, "spellId": 58017}, + {"itemId": 43377, "spellId": 58027}, + {"itemId": 43376, "spellId": 58032}, + {"itemId": 43378, "spellId": 58033}, + {"itemId": 43380, "spellId": 58038}, + {"itemId": 43379, "spellId": 58039} + ] + \ No newline at end of file diff --git a/proto/common.proto b/proto/common.proto index fea6c40760..d600f383a7 100644 --- a/proto/common.proto +++ b/proto/common.proto @@ -854,12 +854,15 @@ message ActionID { } message Glyphs { - int32 major1 = 1; - int32 major2 = 2; - int32 major3 = 3; - int32 minor1 = 4; - int32 minor2 = 5; - int32 minor3 = 6; + int32 prime1 = 1; + int32 prime2 = 2; + int32 prime3 = 3; + int32 major1 = 4; + int32 major2 = 5; + int32 major3 = 6; + int32 minor1 = 7; + int32 minor2 = 8; + int32 minor3 = 9; } // Custom options for a particular cooldown. diff --git a/proto/death_knight.proto b/proto/death_knight.proto index ce3e129d95..4ad5c36cdd 100644 --- a/proto/death_knight.proto +++ b/proto/death_knight.proto @@ -8,138 +8,109 @@ import "common.proto"; message DeathKnightTalents { // Blood int32 butchery = 1; - int32 subversion = 2; - int32 blade_barrier = 3; - int32 bladed_armor = 4; + int32 blade_barrier = 2; + int32 bladed_armor = 3; + int32 improved_blood_tap = 4; int32 scent_of_blood = 5; - int32 two_handed_weapon_specialization = 6; - bool rune_tap = 7; - int32 dark_conviction = 8; - int32 death_rune_mastery = 9; - int32 improved_rune_tap = 10; - int32 spell_deflection = 11; - int32 vendetta = 12; - int32 bloody_strikes = 13; - int32 veteran_of_the_third_war = 14; - bool mark_of_blood = 15; - int32 bloody_vengeance = 16; - int32 abominations_might = 17; - int32 bloodworms = 18; - bool hysteria = 19; - int32 improved_blood_presence = 20; - int32 improved_death_strike = 21; - int32 sudden_doom = 22; - bool vampiric_blood = 23; - int32 will_of_the_necropolis = 24; - bool heart_strike = 25; - int32 might_of_mograine = 26; - int32 blood_gorged = 27; - bool dancing_rune_weapon = 28; + int32 scarlet_fever = 6; + int32 hand_of_doom = 7; + int32 blood_caked_blade = 8; + bool bone_shield = 9; + int32 toughness = 10; + int32 abominations_might = 11; + int32 sanguine_fortitude = 12; + int32 blood_parasite = 13; + int32 improved_blood_presence = 14; + int32 will_of_the_necropolis = 15; + bool rune_tap = 16; + bool vampiric_blood = 17; + int32 improved_death_strike = 18; + int32 crimson_scourge = 19; + bool dancing_rune_weapon = 20; // Frost - int32 improved_icy_touch = 29; - int32 runic_power_mastery = 30; - int32 toughness = 31; - int32 icy_reach = 32; - int32 black_ice = 33; - int32 nerves_of_cold_steel = 34; - int32 icy_talons = 35; - bool lichborne = 36; - int32 annihilation = 37; - int32 killing_machine = 38; - int32 chill_of_the_grave = 39; - int32 endless_winter = 40; - int32 frigid_dreadplate = 41; - int32 glacier_rot = 42; - bool deathchill = 43; - bool improved_icy_talons = 44; - int32 merciless_combat = 45; - int32 rime = 46; - int32 chilblains = 47; - bool hungering_cold = 48; - int32 improved_frost_presence = 49; - int32 threat_of_thassarian = 50; - int32 blood_of_the_north = 51; - bool unbreakable_armor = 52; - int32 acclimation = 53; - bool frost_strike = 54; - int32 guile_of_gorefiend = 55; - int32 tundra_stalker = 56; - bool howling_blast = 57; + int32 runic_power_mastery = 21; + int32 icy_reach = 22; + int32 nerves_of_cold_steel = 23; + int32 annihilation = 24; + bool lichborne = 25; + int32 on_a_pale_horse = 26; + int32 endless_winter = 27; + int32 merciless_combat = 28; + int32 chill_of_the_grave = 29; + int32 killing_machine = 30; + int32 rime = 31; + bool pillar_of_frost = 32; + bool improved_icy_talons = 33; + int32 brittle_bones = 34; + int32 chilblains = 35; + bool hungering_cold = 36; + int32 improved_frost_presence = 37; + int32 threat_of_thassarian = 38; + int32 might_of_the_frozen_wastes = 39; + bool howling_blast = 40; // Unholy - int32 vicious_strikes = 58; - int32 virulence = 59; - int32 anticipation = 60; - int32 epidemic = 61; - int32 morbidity = 62; - int32 unholy_command = 63; - int32 ravenous_dead = 64; - int32 outbreak = 65; - int32 necrosis = 66; - bool corpse_explosion = 67; - int32 on_a_pale_horse = 68; - int32 blood_caked_blade = 69; - int32 night_of_the_dead = 70; - bool unholy_blight = 71; - int32 impurity = 72; - int32 dirge = 73; - int32 desecration = 74; - int32 magic_suppression = 75; - int32 reaping = 76; - bool master_of_ghouls = 77; - int32 desolation = 78; - bool anti_magic_zone = 79; - int32 improved_unholy_presence = 80; - bool ghoul_frenzy = 81; - int32 crypt_fever = 82; - bool bone_shield = 83; - int32 wandering_plague = 84; - int32 ebon_plaguebringer = 85; - bool scourge_strike = 86; - int32 rage_of_rivendare = 87; - bool summon_gargoyle = 88; + int32 unholy_command = 41; + int32 virulence = 42; + int32 epidemic = 43; + int32 desecration = 44; + int32 resilient_infection = 45; + int32 morbidity = 46; + int32 runic_corruption = 47; + bool unholy_frenzy = 48; + int32 contagion = 49; + int32 shadow_infusion = 50; + int32 deaths_advance = 51; + int32 magic_suppression = 52; + int32 rage_of_rivendare = 53; + bool unholy_blight = 54; + bool anti_magic_zone = 55; + int32 improved_unholy_presence = 56; + bool dark_transformation = 57; + int32 ebon_plaguebringer = 58; + int32 sudden_doom = 59; + bool summon_gargoyle = 60; } -enum DeathKnightMajorGlyph { - DeathknightMajorGlyphNone = 0; - GlyphOfAntiMagicShell = 43533; - GlyphOfBloodStrike = 43826; - GlyphOfBoneShield = 43536; - GlyphOfChainsOfIce = 43537; - GlyphOfDancingRuneWeapon = 45799; - GlyphOfDarkCommand = 43538; - GlyphOfDarkDeath = 45804; +enum DeathKnightPrimeGlyph { + DeathKnightPrimeGlyphNone = 0; GlyphOfDeathAndDecay = 43542; - GlyphOfDeathGrip = 43541; + GlyphOfDeathCoil = 45804; GlyphOfDeathStrike = 43827; - GlyphOfDisease = 45805; GlyphOfFrostStrike = 43543; GlyphOfHeartStrike = 43534; GlyphOfHowlingBlast = 45806; - GlyphOfHungeringCold = 45800; - GlyphOfIceboundFortitude = 43545; GlyphOfIcyTouch = 43546; GlyphOfObliterate = 43547; - GlyphOfPlagueStrike = 43548; + GlyphOfRaiseDead = 43549; GlyphOfRuneStrike = 43550; - GlyphOfRuneTap = 43825; GlyphOfScourgeStrike = 43551; +} +enum DeathKnightMajorGlyph { + DeathKnightMajorGlyphNone = 0; + GlyphOfAntiMagicShell = 43533; + GlyphOfBloodBoil = 43826; + GlyphOfBoneShield = 43536; + GlyphOfChainsOfIce = 43537; + GlyphOfDancingRuneWeapon = 45799; + GlyphOfDarkSuccor = 68793; + GlyphOfDeathGrip = 43541; + GlyphOfHungeringCold = 45800; + GlyphOfPestilence = 43548; + GlyphOfPillarOfFrost = 43553; + GlyphOfRuneTap = 43825; GlyphOfStrangulate = 43552; - GlyphOfTheGhoul = 43549; - GlyphOfUnbreakableArmor = 43553; - GlyphOfUnholyBlight = 45803; GlyphOfVampiricBlood = 43554; } - enum DeathKnightMinorGlyph { - DeathknightMinorGlyphNone = 0; + DeathKnightMinorGlyphNone = 0; GlyphOfBloodTap = 43535; - GlyphOfCorpseExplosion = 43671; + GlyphOfDeathGate = 43673; GlyphOfDeathSEmbrace = 43539; GlyphOfHornOfWinter = 43544; - GlyphOfPestilence = 43672; - GlyphOfRaiseDead = 43673; + GlyphOfPathOfFrost = 43671; + GlyphOfResilientGrip = 43672; } message DeathKnightOptions { diff --git a/proto/druid.proto b/proto/druid.proto index 9975c1c79c..d7aa593815 100644 --- a/proto/druid.proto +++ b/proto/druid.proto @@ -7,139 +7,123 @@ import "common.proto"; message DruidTalents { // Balance - int32 starlight_wrath = 1; - int32 genesis = 2; - int32 moonglow = 3; - int32 natures_majesty = 4; - int32 improved_moonfire = 5; - int32 brambles = 6; - int32 natures_grace = 7; - bool natures_splendor = 8; - int32 natures_reach = 9; - int32 vengeance = 10; - int32 celestial_focus = 11; - int32 lunar_guidance = 12; - bool insect_swarm = 13; - int32 improved_insect_swarm = 14; - int32 dreamstate = 15; - int32 moonfury = 16; - int32 balance_of_power = 17; - bool moonkin_form = 18; - int32 improved_moonkin_form = 19; - int32 improved_faerie_fire = 20; - int32 owlkin_frenzy = 21; - int32 wrath_of_cenarius = 22; - int32 eclipse = 23; - bool typhoon = 24; - bool force_of_nature = 25; - int32 gale_winds = 26; - int32 earth_and_moon = 27; - bool starfall = 28; + int32 natures_grace = 1; + int32 starlight_wrath = 2; + int32 natures_majesty = 3; + int32 genesis = 4; + int32 moonglow = 5; + int32 balance_of_power = 6; + int32 euphoria = 7; + bool moonkin_form = 8; + bool typhoon = 9; + int32 shooting_stars = 10; + int32 owlkin_frenzy = 11; + int32 gale_winds = 12; + bool solar_beam = 13; + int32 dreamstate = 14; + bool force_of_nature = 15; + bool sunfire = 16; + bool earth_and_moon = 17; + int32 fungal_growth = 18; + int32 lunar_shower = 19; + bool starfall = 20; // Feral Combat - int32 ferocity = 29; - int32 feral_aggression = 30; - int32 feral_instinct = 31; - int32 savage_fury = 32; - int32 thick_hide = 33; - int32 feral_swiftness = 34; - bool survival_instincts = 35; - int32 sharpened_claws = 36; - int32 shredding_attacks = 37; - int32 predatory_strikes = 38; - int32 primal_fury = 39; - int32 primal_precision = 40; - int32 brutal_impact = 41; - bool feral_charge = 42; - int32 nurturing_instinct = 43; - int32 natural_reaction = 44; - int32 heart_of_the_wild = 45; - int32 survival_of_the_fittest = 46; - bool leader_of_the_pack = 47; - int32 improved_leader_of_the_pack = 48; - int32 primal_tenacity = 49; - int32 protector_of_the_pack = 50; - int32 predatory_instincts = 51; - int32 infected_wounds = 52; - int32 king_of_the_jungle = 53; - bool mangle = 54; - int32 improved_mangle = 55; - int32 rend_and_tear = 56; - bool primal_gore = 57; - bool berserk = 58; + int32 feral_swiftness = 21; + int32 furor = 22; + int32 predatory_strikes = 23; + int32 infected_wounds = 24; + int32 fury_swipes = 25; + int32 primal_fury = 26; + int32 feral_aggression = 27; + int32 king_of_the_jungle = 28; + bool feral_charge = 29; + int32 stampede = 30; + int32 thick_hide = 31; + bool leader_of_the_pack = 32; + int32 brutal_impact = 33; + int32 nurturing_instinct = 34; + int32 primal_madness = 35; + bool survival_instincts = 36; + int32 endless_carnage = 37; + int32 natural_reaction = 38; + int32 blood_in_the_water = 39; + int32 rend_and_tear = 40; + bool pulverize = 41; + bool berserk = 42; // Restoration - int32 improved_mark_of_the_wild = 59; - int32 natures_focus = 60; - int32 furor = 61; - int32 naturalist = 62; - int32 subtlety = 63; - int32 natural_shapeshifter = 64; - int32 intensity = 65; - bool omen_of_clarity = 66; - int32 master_shapeshifter = 67; - int32 tranquil_spirit = 68; - int32 improved_rejuvenation = 69; - bool natures_swiftness = 70; - int32 gift_of_nature = 71; - int32 improved_tranquility = 72; - int32 empowered_touch = 73; - int32 natures_bounty = 74; - int32 living_spirit = 75; - bool swiftmend = 76; - int32 natural_perfection = 77; - int32 empowered_rejuvenation = 78; - int32 living_seed = 79; - int32 revitalize = 80; - bool tree_of_life = 81; - int32 improved_tree_of_life = 82; - int32 improved_barkskin = 83; - int32 gift_of_the_earthmother = 84; - bool wild_growth = 85; + int32 blessing_of_the_grove = 43; + int32 natural_shapeshifter = 44; + int32 naturalist = 45; + int32 heart_of_the_wild = 46; + int32 perseverance = 47; + bool master_shapeshifter = 48; + int32 improved_rejuvenation = 49; + int32 living_seed = 50; + int32 revitalize = 51; + bool natures_swiftness = 52; + int32 fury_of_stormrage = 53; + int32 natures_bounty = 54; + int32 empowered_touch = 55; + int32 malfurions_gift = 56; + int32 efflorescence = 57; + bool wild_growth = 58; + bool natures_cure = 59; + int32 natures_ward = 60; + int32 gift_of_the_earthmother = 61; + bool swift_rejuvenation = 62; + bool tree_of_life = 63; } +enum DruidPrimeGlyph { + DruidPrimeGlyphNone = 0; + GlyphOfBerserk = 45601; + GlyphOfBloodletting = 40901; + GlyphOfInsectSwarm = 40919; + GlyphOfLacerate = 67484; + GlyphOfLifebloom = 40915; + GlyphOfMangle = 40900; + GlyphOfMoonfire = 40923; + GlyphOfRegrowth = 40912; + GlyphOfRejuvenation = 40913; + GlyphOfRip = 40902; + GlyphOfSavageRoar = 45604; + GlyphOfStarfire = 40916; + GlyphOfStarsurge = 45603; + GlyphOfSwiftmend = 40906; + GlyphOfTigerSFury = 67487; + GlyphOfWrath = 40922; +} enum DruidMajorGlyph { DruidMajorGlyphNone = 0; GlyphOfBarkskin = 45623; - GlyphOfBerserk = 45601; - GlyphOfClaw = 48720; GlyphOfEntanglingRoots = 40924; + GlyphOfFaerieFire = 67485; + GlyphOfFeralCharge = 67486; + GlyphOfFerociousBite = 48720; GlyphOfFocus = 44928; GlyphOfFrenziedRegeneration = 40896; - GlyphOfGrowling = 40899; GlyphOfHealingTouch = 40914; GlyphOfHurricane = 40920; GlyphOfInnervate = 40908; - GlyphOfInsectSwarm = 40919; - GlyphOfLifebloom = 40915; - GlyphOfMangle = 40900; GlyphOfMaul = 40897; GlyphOfMonsoon = 45622; - GlyphOfMoonfire = 40923; - GlyphOfNourish = 45603; GlyphOfOmenOfClarity = 206580; - GlyphOfRake = 40903; - GlyphOfRapidRejuvenation = 50125; + GlyphOfPounce = 40903; GlyphOfRebirth = 40909; - GlyphOfRegrowth = 40912; - GlyphOfRejuvenation = 40913; - GlyphOfRip = 40902; - GlyphOfSavageRoar = 45604; - GlyphOfShred = 40901; + GlyphOfSolarBeam = 40899; GlyphOfStarfall = 40921; - GlyphOfStarfire = 40916; - GlyphOfSurvivalInstincts = 46372; - GlyphOfSwiftmend = 40906; + GlyphOfThorns = 43332; GlyphOfWildGrowth = 45602; - GlyphOfWrath = 40922; } enum DruidMinorGlyph { DruidMinorGlyphNone = 0; GlyphOfAquaticForm = 43316; GlyphOfChallengingRoar = 43334; GlyphOfDash = 43674; - GlyphOfTheWild = 43335; - GlyphOfThorns = 43332; + GlyphOfMarkOfTheWild = 43335; + GlyphOfTheTreant = 68039; GlyphOfTyphoon = 44922; GlyphOfUnburdenedRebirth = 43331; } diff --git a/proto/hunter.proto b/proto/hunter.proto index 5e0b8b82a5..2d89162a3d 100644 --- a/proto/hunter.proto +++ b/proto/hunter.proto @@ -7,176 +7,154 @@ import "common.proto"; message HunterTalents { // Beast Mastery - int32 improved_aspect_of_the_hawk = 1; - int32 endurance_training = 2; - int32 focused_fire = 3; - int32 improved_aspect_of_the_monkey = 4; - int32 thick_hide = 5; - int32 improved_revive_pet = 6; - int32 pathfinding = 7; - bool aspect_mastery = 8; - int32 unleashed_fury = 9; - int32 improved_mend_pet = 10; - int32 ferocity = 11; - int32 spirit_bond = 12; - bool intimidation = 13; - int32 bestial_discipline = 14; - int32 animal_handler = 15; - int32 frenzy = 16; - int32 ferocious_inspiration = 17; - bool bestial_wrath = 18; - int32 catlike_reflexes = 19; - int32 invigoration = 20; - int32 serpents_swiftness = 21; - int32 longevity = 22; - bool the_beast_within = 23; - int32 cobra_strikes = 24; - int32 kindred_spirits = 25; - bool beast_mastery = 26; + int32 improved_kill_command = 1; + int32 one_with_nature = 2; + int32 bestial_discipline = 3; + int32 pathfinding = 4; + int32 spirit_bond = 5; + int32 frenzy = 6; + int32 improved_mend_pet = 7; + int32 cobra_strikes = 8; + bool fervor = 9; + bool focus_fire = 10; + int32 longevity = 11; + int32 killing_streak = 12; + int32 crouching_tiger_hidden_chimera = 13; + bool bestial_wrath = 14; + bool ferocious_inspiration = 15; + int32 kindred_spirits = 16; + bool the_beast_within = 17; + int32 invigoration = 18; + bool beast_mastery = 19; // Marksmanship - int32 improved_concussive_shot = 27; - int32 focused_aim = 28; - int32 lethal_shots = 29; - int32 careful_aim = 30; - int32 improved_hunters_mark = 31; - int32 mortal_shots = 32; - int32 go_for_the_throat = 33; - int32 improved_arcane_shot = 34; - bool aimed_shot = 35; - int32 rapid_killing = 36; - int32 improved_stings = 37; - int32 efficiency = 38; - int32 concussive_barrage = 39; - bool readiness = 40; - int32 barrage = 41; - int32 combat_experience = 42; - int32 ranged_weapon_specialization = 43; - int32 piercing_shots = 44; - bool trueshot_aura = 45; - int32 improved_barrage = 46; - int32 master_marksman = 47; - int32 rapid_recuperation = 48; - int32 wild_quiver = 49; - bool silencing_shot = 50; - int32 improved_steady_shot = 51; - int32 marked_for_death = 52; - bool chimera_shot = 53; + int32 go_for_the_throat = 20; + int32 efficiency = 21; + int32 rapid_killing = 22; + int32 sic_em = 23; + int32 improved_steady_shot = 24; + int32 careful_aim = 25; + bool silencing_shot = 26; + int32 concussive_barrage = 27; + int32 piercing_shots = 28; + int32 bombardment = 29; + bool trueshot_aura = 30; + int32 termination = 31; + int32 resistance_is_futile = 32; + int32 rapid_recuperation = 33; + int32 master_marksman = 34; + bool readiness = 35; + int32 posthaste = 36; + int32 marked_for_death = 37; + bool chimera_shot = 38; // Survival - int32 improved_tracking = 54; - int32 hawk_eye = 55; - int32 savage_strikes = 56; - int32 surefooted = 57; - int32 entrapment = 58; - int32 trap_mastery = 59; - int32 survival_instincts = 60; - int32 survivalist = 61; - bool scatter_shot = 62; - int32 deflection = 63; - int32 survival_tactics = 64; - int32 t_n_t = 65; - int32 lock_and_load = 66; - int32 hunter_vs_wild = 67; - int32 killer_instinct = 68; - bool counterattack = 69; - int32 lightning_reflexes = 70; - int32 resourcefulness = 71; - int32 expose_weakness = 72; - bool wyvern_sting = 73; - int32 thrill_of_the_hunt = 74; - int32 master_tactician = 75; - int32 noxious_stings = 76; - int32 point_of_no_escape = 77; - bool black_arrow = 78; - int32 sniper_training = 79; - int32 hunting_party = 80; - bool explosive_shot = 81; + int32 hunter_vs_wild = 39; + int32 pathing = 40; + int32 improved_serpent_sting = 41; + int32 survival_tactics = 42; + int32 trap_mastery = 43; + int32 entrapment = 44; + int32 point_of_no_escape = 45; + int32 thrill_of_the_hunt = 46; + bool counterattack = 47; + int32 lock_and_load = 48; + int32 resourcefulness = 49; + int32 mirrored_blades = 50; + int32 t_n_t = 51; + int32 toxicology = 52; + bool wyvern_sting = 53; + int32 noxious_stings = 54; + bool hunting_party = 55; + int32 sniper_training = 56; + int32 serpent_spread = 57; + bool black_arrow = 58; } - -enum HunterMajorGlyph { - HunterMajorGlyphNone = 0; +enum HunterPrimeGlyph { + HunterPrimeGlyphNone = 0; GlyphOfAimedShot = 42897; GlyphOfArcaneShot = 42898; - GlyphOfAspectOfTheViper = 42901; - GlyphOfBestialWrath = 42902; GlyphOfChimeraShot = 45625; + GlyphOfDazzledPrey = 42909; + GlyphOfExplosiveShot = 45731; + GlyphOfKillCommand = 42915; + GlyphOfKillShot = 45732; + GlyphOfRapidFire = 42911; + GlyphOfSerpentSting = 42912; + GlyphOfSteadyShot = 42914; +} +enum HunterMajorGlyph { + HunterMajorGlyphNone = 0; + GlyphOfBestialWrath = 42902; + GlyphOfConcussiveShot = 42901; GlyphOfDeterrence = 42903; GlyphOfDisengage = 42904; - GlyphOfExplosiveShot = 45731; - GlyphOfExplosiveTrap = 45733; GlyphOfFreezingTrap = 42905; - GlyphOfFrostTrap = 42906; - GlyphOfHuntersMark = 42907; + GlyphOfIceTrap = 42906; GlyphOfImmolationTrap = 42908; - GlyphOfKillShot = 45732; + GlyphOfMasterSCall = 45733; GlyphOfMending = 42900; - GlyphOfMultiShot = 42910; - GlyphOfRapidFire = 42911; + GlyphOfMisdirection = 42907; GlyphOfRaptorStrike = 45735; GlyphOfScatterShot = 45734; - GlyphOfSerpentSting = 42912; + GlyphOfSilencingShot = 42910; GlyphOfSnakeTrap = 42913; - GlyphOfSteadyShot = 42914; - GlyphOfTheBeast = 42899; - GlyphOfTheHawk = 42909; - GlyphOfTrueshotAura = 42915; - GlyphOfVolley = 42916; + GlyphOfTrapLauncher = 42899; GlyphOfWyvernSting = 42917; } enum HunterMinorGlyph { HunterMinorGlyphNone = 0; + GlyphOfAspectOfThePack = 43355; GlyphOfFeignDeath = 43351; - GlyphOfMendPet = 43350; - GlyphOfPossessedStrength = 43354; + GlyphOfLesserProportion = 43350; GlyphOfRevivePet = 43338; GlyphOfScareBeast = 43356; - GlyphOfThePack = 43355; } message HunterPetTalents { - // Cunning - int32 cobra_reflexes = 1; - bool dive = 2; + // Ferocity + int32 serpent_swiftness = 1; + bool dash = 2; int32 great_stamina = 3; int32 natural_armor = 4; - bool boars_speed = 5; - int32 mobility = 6; - int32 owls_focus = 7; - int32 spiked_collar = 8; + int32 improved_cower = 5; + int32 bloodthirsty = 6; + int32 spiked_collar = 7; + bool boars_speed = 8; int32 culling_the_herd = 9; int32 lionhearted = 10; - bool carrion_feeder = 11; - int32 great_resistance = 12; - int32 cornered = 13; - int32 feeding_frenzy = 14; - bool wolverine_bite = 15; - bool roar_of_recovery = 16; - bool bullheaded = 17; - int32 grace_of_the_mantis = 18; + bool charge = 11; + bool heart_of_the_phoenix = 12; + int32 spiders_bite = 13; + int32 great_resistance = 14; + bool rabid = 15; + bool lick_your_wounds = 16; + bool call_of_the_wild = 17; + int32 shark_attack = 18; int32 wild_hunt = 19; - bool roar_of_sacrifice = 20; - - // Ferocity - int32 improved_cower = 21; - int32 bloodthirsty = 22; - bool heart_of_the_pheonix = 23; - int32 spiders_bite = 24; - bool rabid = 25; - bool lick_your_wounds = 26; - bool call_of_the_wild = 27; - int32 shark_attack = 28; // Tenacity - bool charge = 29; - int32 blood_of_the_rhino = 30; - int32 pet_barding = 31; - int32 guard_dog = 32; - bool thunderstomp = 33; - bool last_stand = 34; - bool taunt = 35; - bool intervene = 36; - int32 silverback = 37; + int32 blood_of_the_rhino = 20; + int32 pet_barding = 21; + int32 guard_dog = 22; + bool thunderstomp = 23; + int32 grace_of_the_mantis = 24; + bool last_stand = 25; + bool taunt = 26; + bool roar_of_sacrifice = 27; + bool intervene = 28; + int32 silverback = 29; + + // Cunning + bool dive = 30; + int32 mobility = 31; + int32 owls_focus = 32; + bool carrion_feeder = 33; + int32 cornered = 34; + int32 feeding_frenzy = 35; + bool wolverine_bite = 36; + bool roar_of_recovery = 37; + bool bullheaded = 38; } enum HunterStingType { diff --git a/proto/mage.proto b/proto/mage.proto index afa05e1231..53888b06aa 100644 --- a/proto/mage.proto +++ b/proto/mage.proto @@ -7,138 +7,113 @@ import "common.proto"; message MageTalents { // Arcane - int32 arcane_subtlety = 1; - int32 arcane_focus = 2; - int32 arcane_stability = 3; - int32 arcane_fortitude = 4; - int32 magic_absorption = 5; - int32 arcane_concentration = 6; - int32 magic_attunement = 7; - int32 spell_impact = 8; - int32 student_of_the_mind = 9; - bool focus_magic = 10; - int32 arcane_shielding = 11; - int32 improved_counterspell = 12; - int32 arcane_meditation = 13; - int32 torment_the_weak = 14; - int32 improved_blink = 15; - bool presence_of_mind = 16; - int32 arcane_mind = 17; - int32 prismatic_cloak = 18; - int32 arcane_instability = 19; - int32 arcane_potency = 20; - int32 arcane_empowerment = 21; + int32 arcane_concentration = 1; + int32 improved_counterspell = 2; + int32 netherwind_presence = 3; + int32 torment_the_weak = 4; + int32 invocation = 5; + int32 improved_arcane_missiles = 6; + int32 improved_blink = 7; + int32 arcane_flows = 8; + bool presence_of_mind = 9; + int32 missile_barrage = 10; + int32 prismatic_cloak = 11; + int32 improved_polymorph = 12; + bool arcane_tactics = 13; + int32 incanters_absorption = 14; + int32 improved_arcane_explosion = 16; + int32 arcane_potency = 17; + bool slow = 18; + int32 nether_vortex = 19; + bool focus_magic = 20; + int32 improved_mana_gem = 21; bool arcane_power = 22; - int32 incanters_absorption = 23; - int32 arcane_flows = 24; - int32 mind_mastery = 25; - bool slow = 26; - int32 missile_barrage = 27; - int32 netherwind_presence = 28; - int32 spell_power = 29; - bool arcane_barrage = 30; // Fire - int32 improved_fire_blast = 31; - int32 incineration = 32; - int32 improved_fireball = 33; - int32 ignite = 34; - int32 burning_determination = 35; - int32 world_in_flames = 36; - int32 flame_throwing = 37; - int32 impact = 38; - bool pyroblast = 39; - int32 burning_soul = 40; - int32 improved_scorch = 41; - int32 molten_shields = 42; - int32 master_of_elements = 43; - int32 playing_with_fire = 44; - int32 critical_mass = 45; - bool blast_wave = 46; - int32 blazing_speed = 47; - int32 fire_power = 48; - int32 pyromaniac = 49; - bool combustion = 50; - int32 molten_fury = 51; - int32 fiery_payback = 52; - int32 empowered_fire = 53; - int32 firestarter = 54; - bool dragons_breath = 55; - int32 hot_streak = 56; - int32 burnout = 57; - bool living_bomb = 58; + int32 master_of_elements = 23; + int32 burning_soul = 24; + int32 improved_fire_blast = 25; + int32 ignite = 26; + int32 fire_power = 27; + int32 blazing_speed = 28; + int32 impact = 29; + int32 cauterize = 30; + bool blast_wave = 31; + bool hot_streak = 32; + int32 improved_scorch = 33; + bool molten_shields = 34; + bool combustion = 35; + int32 improved_hot_streak = 36; + bool firestarter = 37; + int32 improved_flamestrike = 38; + bool dragons_breath = 39; + int32 molten_fury = 40; + int32 pyromaniac = 41; + int32 critical_mass = 42; + bool living_bomb = 43; // Frost - int32 frostbite = 59; - int32 improved_frostbolt = 60; - int32 ice_floes = 61; - int32 ice_shards = 62; - int32 frost_warding = 63; - int32 precision = 64; - int32 permafrost = 65; - int32 piercing_ice = 66; - bool icy_veins = 67; - int32 improved_blizzard = 68; - int32 arctic_reach = 69; - int32 frost_channeling = 70; - int32 shatter = 71; - bool cold_snap = 72; - int32 improved_cone_of_cold = 73; - int32 frozen_core = 74; - int32 cold_as_ice = 75; - int32 winters_chill = 76; - int32 shattered_barrier = 77; - bool ice_barrier = 78; - int32 arctic_winds = 79; - int32 empowered_frostbolt = 80; - int32 fingers_of_frost = 81; - int32 brain_freeze = 82; - bool summon_water_elemental = 83; - int32 enduring_winter = 84; - int32 chilled_to_the_bone = 85; - bool deep_freeze = 86; + int32 early_frost = 44; + int32 piercing_ice = 45; + int32 shatter = 46; + int32 ice_floes = 47; + int32 improved_cone_of_cold = 48; + int32 piercing_chill = 49; + int32 permafrost = 50; + int32 ice_shards = 51; + bool icy_veins = 52; + int32 fingers_of_frost = 53; + int32 improved_freeze = 54; + int32 enduring_winter = 55; + bool cold_snap = 56; + int32 brain_freeze = 57; + int32 shattered_barrier = 58; + bool ice_barrier = 59; + int32 reactive_barrier = 60; + int32 frostfire_orb = 61; + bool deep_freeze = 62; } - -enum MageMajorGlyph { - MageMajorGlyphNone = 0; +enum MagePrimeGlyph { + MagePrimeGlyphNone = 0; GlyphOfArcaneBarrage = 45738; GlyphOfArcaneBlast = 44955; - GlyphOfArcaneExplosion = 42734; GlyphOfArcaneMissiles = 42735; - GlyphOfArcanePower = 42736; - GlyphOfBlink = 42737; + GlyphOfConeOfCold = 42753; GlyphOfDeepFreeze = 45736; - GlyphOfEternalWater = 50045; - GlyphOfEvocation = 42738; - GlyphOfFireBlast = 42740; GlyphOfFireball = 42739; - GlyphOfFrostNova = 42741; GlyphOfFrostbolt = 42742; GlyphOfFrostfire = 44684; - GlyphOfIceArmor = 42743; + GlyphOfIceLance = 42745; + GlyphOfLivingBomb = 63539; + GlyphOfMageArmor = 42749; + GlyphOfMoltenArmor = 42751; + GlyphOfPyroblast = 42743; +} +enum MageMajorGlyph { + MageMajorGlyphNone = 0; + GlyphOfArcanePower = 42736; + GlyphOfBlastWave = 44920; + GlyphOfBlink = 42737; + GlyphOfDragonSBreath = 42754; + GlyphOfEvocation = 42738; + GlyphOfFrostArmor = 69773; + GlyphOfFrostNova = 42741; GlyphOfIceBarrier = 45740; GlyphOfIceBlock = 42744; - GlyphOfIceLance = 42745; GlyphOfIcyVeins = 42746; GlyphOfInvisibility = 42748; - GlyphOfLivingBomb = 45737; - GlyphOfMageArmor = 42749; - GlyphOfManaGem = 42750; - GlyphOfMirrorImage = 45739; - GlyphOfMoltenArmor = 42751; + GlyphOfManaShield = 50045; GlyphOfPolymorph = 42752; - GlyphOfRemoveCurse = 42753; - GlyphOfScorch = 42747; - GlyphOfWaterElemental = 42754; + GlyphOfSlow = 45737; } enum MageMinorGlyph { MageMinorGlyphNone = 0; - GlyphOfArcaneIntellect = 43339; - GlyphOfBlastWave = 44920; - GlyphOfFireWard = 43357; - GlyphOfFrostArmor = 43359; - GlyphOfFrostWard = 43360; + GlyphOfArcaneBrilliance = 43339; + GlyphOfArmors = 63416; + GlyphOfConjuring = 43359; + GlyphOfMirrorImage = 45739; GlyphOfSlowFall = 43364; + GlyphOfTheMonkey = 43360; GlyphOfThePenguin = 43361; } diff --git a/proto/paladin.proto b/proto/paladin.proto index 6338a338d8..f43b3b1236 100644 --- a/proto/paladin.proto +++ b/proto/paladin.proto @@ -5,130 +5,115 @@ option go_package = "./proto"; message PaladinTalents { // Holy - int32 spiritual_focus = 1; - int32 seals_of_the_pure = 2; - int32 healing_light = 3; - int32 divine_intellect = 4; - int32 unyielding_faith = 5; - bool aura_mastery = 6; - int32 illumination = 7; - int32 improved_lay_on_hands = 8; - int32 improved_concentration_aura = 9; - int32 improved_blessing_of_wisdom = 10; - int32 blessed_hands = 11; - int32 pure_of_heart = 12; - bool divine_favor = 13; - int32 sanctified_light = 14; - int32 purifying_power = 15; - int32 holy_power = 16; - int32 lights_grace = 17; - bool holy_shock = 18; + int32 arbiter_of_the_light = 1; + int32 protector_of_the_innocent = 2; + int32 judgements_of_the_pure = 3; + int32 clarity_of_purpose = 4; + int32 last_word = 5; + int32 blazing_light = 6; + int32 denounce = 7; + bool divine_favor = 8; + int32 infusion_of_light = 9; + int32 daybreak = 10; + int32 enlightened_judgements = 11; + bool beacon_of_light = 12; + int32 speed_of_light = 13; + bool sacred_cleansing = 14; + int32 conviction = 15; + bool aura_mastery = 16; + int32 paragon_of_virtue = 17; + int32 tower_of_radiance = 18; int32 blessed_life = 19; - int32 sacred_cleansing = 20; - int32 holy_guidance = 21; - bool divine_illumination = 22; - int32 judgements_of_the_pure = 23; - int32 infusion_of_light = 24; - int32 enlightened_judgements = 25; - bool beacon_of_light = 26; + bool light_of_dawn = 20; // Protection - int32 divinity = 27; - int32 divine_strength = 28; - int32 stoicism = 29; - int32 guardians_favor = 30; - int32 anticipation = 31; - bool divine_sacrifice = 32; - int32 improved_righteous_fury = 33; - int32 toughness = 34; - int32 divine_guardian = 35; - int32 improved_hammer_of_justice = 36; - int32 improved_devotion_aura = 37; - bool blessing_of_sanctuary = 38; - int32 reckoning = 39; - int32 sacred_duty = 40; - int32 one_handed_weapon_specialization = 41; - int32 spiritual_attunement = 42; - bool holy_shield = 43; - int32 ardent_defender = 44; - int32 redoubt = 45; - int32 combat_expertise = 46; - int32 touched_by_the_light = 47; - bool avengers_shield = 48; - int32 guarded_by_the_light = 49; - int32 shield_of_the_templar = 50; - int32 judgements_of_the_just = 51; - bool hammer_of_the_righteous = 52; + int32 divinity = 21; + int32 seals_of_the_pure = 22; + int32 eternal_glory = 23; + int32 judgements_of_the_just = 24; + int32 toughness = 25; + int32 improved_hammer_of_justice = 26; + int32 hallowed_ground = 27; + int32 sanctuary = 28; + bool hammer_of_the_righteous = 29; + int32 wrath_of_the_lightbringer = 30; + int32 reckoning = 31; + bool shield_of_the_righteous = 32; + int32 grand_crusader = 33; + bool vindication = 34; + bool holy_shield = 35; + int32 guarded_by_the_light = 36; + bool divine_guardian = 37; + int32 sacred_duty = 38; + int32 shield_of_the_templar = 39; + bool ardent_defender = 40; // Retribution - int32 deflection = 53; - int32 benediction = 54; - int32 improved_judgements = 55; - int32 heart_of_the_crusader = 56; - int32 improved_blessing_of_might = 57; - int32 vindication = 58; - int32 conviction = 59; - bool seal_of_command = 60; - int32 pursuit_of_justice = 61; - int32 eye_for_an_eye = 62; - int32 sanctity_of_battle = 63; - int32 crusade = 64; - int32 two_handed_weapon_specialization = 65; - bool sanctified_retribution = 66; - int32 vengeance = 67; - int32 divine_purpose = 68; - int32 the_art_of_war = 69; - bool repentance = 70; - int32 judgements_of_the_wise = 71; - int32 fanaticism = 72; - int32 sanctified_wrath = 73; - int32 swift_retribution = 74; - bool crusader_strike = 75; - int32 sheath_of_light = 76; - int32 righteous_vengeance = 77; - bool divine_storm = 78; + int32 eye_for_an_eye = 41; + int32 crusade = 42; + int32 improved_judgement = 43; + int32 guardians_favor = 44; + int32 rule_of_law = 45; + int32 pursuit_of_justice = 46; + bool communion = 47; + int32 the_art_of_war = 48; + int32 long_arm_of_the_law = 49; + bool divine_storm = 50; + bool sacred_shield = 51; + bool sanctity_of_battle = 52; + bool seals_of_command = 53; + int32 sanctified_wrath = 54; + int32 selfless_healer = 55; + bool repentance = 56; + int32 divine_purpose = 57; + int32 inquiry_of_faith = 58; + int32 acts_of_sacrifice = 59; + bool zealotry = 60; +} +enum PaladinPrimeGlyph { + PaladinPrimeGlyphNone = 0; + GlyphOfCrusaderStrike = 41098; + GlyphOfDivineFavor = 41106; + GlyphOfExorcism = 41103; + GlyphOfHammerOfTheRighteous = 45742; + GlyphOfHolyShock = 45746; + GlyphOfJudgement = 41092; + GlyphOfSealOfInsight = 41110; + GlyphOfSealOfTruth = 43869; + GlyphOfShieldOfTheRighteous = 45744; + GlyphOfTemplarSVerdict = 45743; + GlyphOfWordOfGlory = 41105; } - enum PaladinMajorGlyph { PaladinMajorGlyphNone = 0; - GlyphOfAvengerSShield = 41101; - GlyphOfAvengingWrath = 41107; GlyphOfBeaconOfLight = 45741; GlyphOfCleansing = 41104; GlyphOfConsecration = 41099; - GlyphOfCrusaderStrike = 41098; + GlyphOfDazingShield = 43868; GlyphOfDivinePlea = 45745; - GlyphOfDivineStorm = 45743; + GlyphOfDivineProtection = 41096; GlyphOfDivinity = 41108; - GlyphOfExorcism = 41103; - GlyphOfFlashOfLight = 41105; + GlyphOfFocusedShield = 41101; GlyphOfHammerOfJustice = 41095; - GlyphOfHammerOfTheRighteous = 45742; GlyphOfHammerOfWrath = 41097; - GlyphOfHolyLight = 41106; - GlyphOfHolyShock = 45746; GlyphOfHolyWrath = 43867; - GlyphOfJudgement = 41092; - GlyphOfRighteousDefense = 41100; + GlyphOfLayOnHands = 43367; + GlyphOfLightOfDawn = 41109; + GlyphOfRebuke = 41094; + GlyphOfReckoning = 204385; GlyphOfSalvation = 45747; - GlyphOfSealOfCommand = 41094; - GlyphOfSealOfLight = 41110; - GlyphOfSealOfRighteousness = 43868; - GlyphOfSealOfVengeance = 43869; - GlyphOfSealOfWisdom = 41109; - GlyphOfShieldOfRighteousness = 45744; - GlyphOfSpiritualAttunement = 41096; + GlyphOfTheAsceticCrusader = 41107; + GlyphOfTheLongWord = 66918; GlyphOfTurnEvil = 41102; - GlyphOfReckoning = 204385; } enum PaladinMinorGlyph { PaladinMinorGlyphNone = 0; GlyphOfBlessingOfKings = 43365; GlyphOfBlessingOfMight = 43340; - GlyphOfBlessingOfWisdom = 43366; - GlyphOfLayOnHands = 43367; - GlyphOfSenseUndead = 43368; - GlyphOfTheWise = 43369; + GlyphOfInsight = 43366; + GlyphOfJustice = 43369; + GlyphOfRighteousness = 41100; + GlyphOfTruth = 43368; } enum Blessings { diff --git a/proto/priest.proto b/proto/priest.proto index 1cf27f3c24..2e2725e1ae 100644 --- a/proto/priest.proto +++ b/proto/priest.proto @@ -5,126 +5,109 @@ option go_package = "./proto"; import "common.proto"; -// WotLK talents message PriestTalents { // Discipline - int32 unbreakable_will = 1; + int32 improved_power_word_shield = 1; int32 twin_disciplines = 2; - int32 silent_resolve = 3; - int32 improved_inner_fire = 4; - int32 improved_power_word_fortitude = 5; - int32 martyrdom = 6; - int32 meditation = 7; - bool inner_focus = 8; - int32 improved_power_word_shield = 9; - int32 absolution = 10; - int32 mental_agility = 11; - int32 improved_mana_burn = 12; - int32 reflective_shield = 13; - int32 mental_strength = 14; - bool soul_warding = 15; - int32 focused_power = 16; - int32 enlightenment = 17; - int32 focused_will = 18; - bool power_infusion = 19; - int32 improved_flash_heal = 20; - int32 renewed_hope = 21; - int32 rapture = 22; - int32 aspiration = 23; - int32 divine_aegis = 24; - bool pain_suppression = 25; - int32 grace = 26; - int32 borrowed_time = 27; - bool penance = 28; + int32 mental_agility = 3; + int32 evangelism = 4; + bool archangel = 5; + int32 inner_sanctum = 6; + int32 soul_warding = 7; + int32 renewed_hope = 8; + bool power_infusion = 9; + int32 atonement = 10; + bool inner_focus = 11; + int32 rapture = 12; + int32 borrowed_time = 13; + int32 reflective_shield = 14; + int32 strength_of_soul = 15; + int32 divine_aegis = 16; + bool pain_suppression = 17; + int32 train_of_thought = 18; + int32 focused_will = 19; + int32 grace = 20; + bool power_word_barrier = 21; // Holy - int32 healing_focus = 29; - int32 improved_renew = 30; - int32 holy_specialization = 31; - int32 spell_warding = 32; - int32 divine_fury = 33; - bool desperate_prayer = 34; - int32 blessed_recovery = 35; - int32 inspiration = 36; - int32 holy_reach = 37; - int32 improved_healing = 38; - int32 searing_light = 39; - int32 healing_prayers = 40; - bool spirit_of_redemption = 41; - int32 spiritual_guidance = 42; - int32 surge_of_light = 43; - int32 spiritual_healing = 44; - int32 holy_concentration = 45; - bool lightwell = 46; - int32 blessed_resilience = 47; - int32 body_and_soul = 48; - int32 empowered_healing = 49; - int32 serendipity = 50; - int32 empowered_renew = 51; - bool circle_of_healing = 52; - int32 test_of_faith = 53; - int32 divine_providence = 54; - bool guardian_spirit = 55; + int32 improved_renew = 22; + int32 empowered_healing = 23; + int32 divine_fury = 24; + bool desperate_prayer = 25; + int32 surge_of_light = 26; + int32 inspiration = 27; + int32 divine_touch = 28; + int32 holy_concentration = 29; + bool lightwell = 30; + int32 tome_of_light = 31; + bool rapid_renewal = 32; + bool spirit_of_redemption = 33; + int32 serendipity = 34; + int32 body_and_soul = 35; + bool chakra = 36; + bool revelations = 37; + int32 blessed_resilience = 38; + int32 test_of_faith = 39; + int32 heavenly_voice = 40; + bool circle_of_healing = 41; + bool guardian_spirit = 42; // Shadow - int32 spirit_tap = 56; - int32 improved_spirit_tap = 57; - int32 darkness = 58; - int32 shadow_affinity = 59; - int32 improved_shadow_word_pain = 60; - int32 shadow_focus = 61; - int32 improved_psychic_scream = 62; - int32 improved_mind_blast = 63; - bool mind_flay = 64; - int32 veiled_shadows = 65; - int32 shadow_reach = 66; - int32 shadow_weaving = 67; - bool silence = 68; - bool vampiric_embrace = 69; - int32 improved_vampiric_embrace = 70; - int32 focused_mind = 71; - int32 mind_melt = 72; - int32 improved_devouring_plague = 73; - bool shadowform = 74; - int32 shadow_power = 75; - int32 improved_shadowform = 76; - int32 misery = 77; - bool psychic_horror = 78; - bool vampiric_touch = 79; - int32 pain_and_suffering = 80; - int32 twisted_faith = 81; - bool dispersion = 82; + int32 darkness = 43; + int32 improved_shadow_word_pain = 44; + int32 veiled_shadows = 45; + int32 improved_psychic_scream = 46; + int32 improved_mind_blast = 47; + int32 improved_devouring_plague = 48; + int32 twisted_faith = 49; + bool shadowform = 50; + int32 phantasm = 51; + int32 harnessed_shadows = 52; + bool silence = 53; + bool vampiric_embrace = 54; + int32 masochism = 55; + int32 mind_melt = 56; + int32 pain_and_suffering = 57; + bool vampiric_touch = 58; + int32 paralysis = 59; + bool psychic_horror = 60; + int32 sin_and_punishment = 61; + int32 shadowy_apparition = 62; + bool dispersion = 63; } -enum PriestMajorGlyph { - PriestMajorGlyphNone = 0; - GlyphOfCircleOfHealing = 42396; - GlyphOfDispelMagic = 42397; +enum PriestPrimeGlyph { + PriestPrimeGlyphNone = 0; GlyphOfDispersion = 45753; - GlyphOfFade = 42398; - GlyphOfFearWard = 42399; GlyphOfFlashHeal = 42400; GlyphOfGuardianSpirit = 45755; - GlyphOfHolyNova = 42401; - GlyphOfHymnOfHope = 45758; - GlyphOfInnerFire = 42402; GlyphOfLightwell = 42403; - GlyphOfMassDispel = 42404; - GlyphOfMindControl = 42405; GlyphOfMindFlay = 42415; - GlyphOfMindSear = 45757; - GlyphOfPainSuppression = 45760; GlyphOfPenance = 45756; + GlyphOfPowerWordBarrier = 42407; GlyphOfPowerWordShield = 42408; GlyphOfPrayerOfHealing = 42409; - GlyphOfPsychicScream = 42410; GlyphOfRenew = 42411; - GlyphOfScourgeImprisonment = 42412; - GlyphOfShadow = 42407; GlyphOfShadowWordDeath = 42414; GlyphOfShadowWordPain = 42406; +} +enum PriestMajorGlyph { + PriestMajorGlyphNone = 0; + GlyphOfCircleOfHealing = 42396; + GlyphOfDesperation = 45760; + GlyphOfDispelMagic = 42397; + GlyphOfDivineAccuracy = 45758; + GlyphOfFade = 42398; + GlyphOfFearWard = 42399; + GlyphOfHolyNova = 42401; + GlyphOfInnerFire = 42402; + GlyphOfMassDispel = 42404; + GlyphOfPrayerOfMending = 42417; + GlyphOfPsychicHorror = 42405; + GlyphOfPsychicScream = 42410; + GlyphOfScourgeImprisonment = 42412; GlyphOfSmite = 42416; - GlyphOfSpiritOfRedemption = 42417; + GlyphOfSpiritTap = 45757; } enum PriestMinorGlyph { PriestMinorGlyphNone = 0; @@ -132,6 +115,7 @@ enum PriestMinorGlyph { GlyphOfFortitude = 43371; GlyphOfLevitate = 43370; GlyphOfShackleUndead = 43373; + GlyphOfShadow = 77101; GlyphOfShadowProtection = 43372; GlyphOfShadowfiend = 43374; } diff --git a/proto/rogue.proto b/proto/rogue.proto index 50685cb6c2..6a4eb93e5a 100644 --- a/proto/rogue.proto +++ b/proto/rogue.proto @@ -7,125 +7,104 @@ import "common.proto"; message RogueTalents { // Assassination - int32 improved_eviscerate = 1; - int32 remorseless_attacks = 2; - int32 malice = 3; + int32 deadly_momentum = 1; + int32 coup_de_grace = 2; + int32 lethality = 3; int32 ruthlessness = 4; - int32 blood_spatter = 5; + int32 quickening = 5; int32 puncturing_wounds = 6; - bool vigor = 7; - int32 improved_expose_armor = 8; - int32 lethality = 9; + int32 blackjack = 7; + int32 deadly_brew = 8; + bool cold_blood = 9; int32 vile_poisons = 10; - int32 improved_poisons = 11; - int32 fleet_footed = 12; - bool cold_blood = 13; - int32 improved_kidney_shot = 14; - int32 quick_recovery = 15; - int32 seal_fate = 16; - int32 murder = 17; - int32 deadly_brew = 18; - bool overkill = 19; - int32 deadened_nerves = 20; - int32 focused_attacks = 21; - int32 find_weakness = 22; - int32 master_poisoner = 23; - bool mutilate = 24; - int32 turn_the_tables = 25; - int32 cut_to_the_chase = 26; - bool hunger_for_blood = 27; + int32 deadened_nerves = 11; + int32 seal_fate = 12; + int32 murderous_intent = 13; + bool overkill = 14; + bool master_poisoner = 15; + int32 improved_expose_armor = 16; + int32 cut_to_the_chase = 17; + int32 venomous_wounds = 18; + bool vendetta = 19; // Combat - int32 improved_gouge = 28; - int32 improved_sinister_strike = 29; - int32 dual_wield_specialization = 30; - int32 improved_slice_and_dice = 31; - int32 deflection = 32; - int32 precision = 33; - int32 endurance = 34; - bool riposte = 35; - int32 close_quarters_combat = 36; - int32 improved_kick = 37; - int32 improved_sprint = 38; - int32 lightning_reflexes = 39; - int32 aggression = 40; - int32 mace_specialization = 41; - bool blade_flurry = 42; - int32 hack_and_slash = 43; - int32 weapon_expertise = 44; - int32 blade_twisting = 45; - int32 vitality = 46; - bool adrenaline_rush = 47; - int32 nerves_of_steel = 48; - int32 throwing_specialization = 49; - int32 combat_potency = 50; - int32 unfair_advantage = 51; - bool surprise_attacks = 52; - int32 savage_combat = 53; - int32 prey_on_the_weak = 54; - bool killing_spree = 55; + int32 improved_recuperate = 20; + int32 improved_sinister_strike = 21; + int32 precision = 22; + int32 improved_slice_and_dice = 23; + int32 improved_sprint = 24; + int32 aggression = 25; + int32 improved_kick = 26; + int32 lightning_reflexes = 27; + bool revealing_strike = 28; + int32 reinforced_leather = 29; + int32 improved_gouge = 30; + int32 combat_potency = 31; + int32 blade_twisting = 32; + int32 throwing_specialization = 33; + bool adrenaline_rush = 34; + int32 savage_combat = 35; + int32 bandits_guile = 36; + int32 restless_blades = 37; + bool killing_spree = 38; // Subtlety - int32 relentless_strikes = 56; - int32 master_of_deception = 57; - int32 opportunity = 58; - int32 sleight_of_hand = 59; - int32 dirty_tricks = 60; - int32 camouflage = 61; - int32 elusiveness = 62; - bool ghostly_strike = 63; - int32 serrated_blades = 64; - int32 setup = 65; - int32 initiative = 66; - int32 improved_ambush = 67; - int32 heightened_senses = 68; - bool preparation = 69; - int32 dirty_deeds = 70; - bool hemorrhage = 71; - int32 master_of_subtlety = 72; - int32 deadliness = 73; - int32 enveloping_shadows = 74; - bool premeditation = 75; - int32 cheat_death = 76; - int32 sinister_calling = 77; - int32 waylay = 78; - int32 honor_among_thieves = 79; - bool shadowstep = 80; - int32 filthy_tricks = 81; - int32 slaughter_from_the_shadows = 82; - bool shadow_dance = 83; + int32 nightstalker = 39; + int32 improved_ambush = 40; + int32 relentless_strikes = 41; + int32 elusiveness = 42; + int32 waylay = 43; + int32 opportunity = 44; + int32 initiative = 45; + int32 energetic_recovery = 46; + int32 find_weakness = 47; + bool hemorrhage = 48; + int32 honor_among_thieves = 49; + bool premeditation = 50; + int32 enveloping_shadows = 51; + int32 cheat_death = 52; + bool preparation = 53; + int32 sanguinary_vein = 54; + int32 slaughter_from_the_shadows = 55; + int32 serrated_blades = 56; + bool shadow_dance = 57; } +enum RoguePrimeGlyph { + RoguePrimeGlyphNone = 0; + GlyphOfAdrenalineRush = 42954; + GlyphOfBackstab = 42956; + GlyphOfEviscerate = 42961; + GlyphOfHemorrhage = 42967; + GlyphOfKillingSpree = 45762; + GlyphOfMutilate = 45768; + GlyphOfRevealingStrike = 42965; + GlyphOfRupture = 42969; + GlyphOfShadowDance = 45764; + GlyphOfSinisterStrike = 42972; + GlyphOfSliceAndDice = 42973; + GlyphOfVendetta = 45761; +} enum RogueMajorGlyph { RogueMajorGlyphNone = 0; - GlyphOfAdrenalineRush = 42954; GlyphOfAmbush = 42955; - GlyphOfBackstab = 42956; GlyphOfBladeFlurry = 42957; + GlyphOfBlind = 64493; GlyphOfCloakOfShadows = 45769; GlyphOfCripplingPoison = 42958; GlyphOfDeadlyThrow = 42959; GlyphOfEvasion = 42960; - GlyphOfEviscerate = 42961; GlyphOfExposeArmor = 42962; GlyphOfFanOfKnives = 45766; GlyphOfFeint = 42963; GlyphOfGarrote = 42964; - GlyphOfGhostlyStrike = 42965; GlyphOfGouge = 42966; - GlyphOfHemorrhage = 42967; - GlyphOfHungerForBlood = 45761; - GlyphOfKillingSpree = 45762; - GlyphOfMutilate = 45768; + GlyphOfKick = 42971; GlyphOfPreparation = 42968; - GlyphOfRupture = 42969; GlyphOfSap = 42970; - GlyphOfShadowDance = 45764; - GlyphOfSinisterStrike = 42972; - GlyphOfSliceAndDice = 42973; GlyphOfSprint = 42974; GlyphOfTricksOfTheTrade = 45767; - GlyphOfVigor = 42971; + GlyphOfVanish = 63420; } enum RogueMinorGlyph { RogueMinorGlyphNone = 0; @@ -133,8 +112,8 @@ enum RogueMinorGlyph { GlyphOfDistract = 43376; GlyphOfPickLock = 43377; GlyphOfPickPocket = 43343; + GlyphOfPoisons = 43380; GlyphOfSafeFall = 43378; - GlyphOfVanish = 43380; } message RogueOptions { diff --git a/proto/shaman.proto b/proto/shaman.proto index 6b03afce71..2572546e28 100644 --- a/proto/shaman.proto +++ b/proto/shaman.proto @@ -5,131 +5,112 @@ option go_package = "./proto"; message ShamanTalents { // Elemental - int32 convection = 1; - int32 concussion = 2; - int32 call_of_flame = 3; - int32 elemental_warding = 4; - int32 elemental_devastation = 5; + int32 acuity = 1; + int32 convection = 2; + int32 concussion = 3; + int32 call_of_flame = 4; + int32 elemental_warding = 5; int32 reverberation = 6; - bool elemental_focus = 7; - int32 elemental_fury = 8; - int32 improved_fire_nova = 9; - int32 eye_of_the_storm = 10; - int32 elemental_reach = 11; - bool call_of_thunder = 12; - int32 unrelenting_storm = 13; - int32 elemental_precision = 14; - int32 lightning_mastery = 15; - bool elemental_mastery = 16; - int32 storm_earth_and_fire = 17; - int32 booming_echoes = 18; - int32 elemental_oath = 19; - int32 lightning_overload = 20; - int32 astral_shift = 21; - bool totem_of_wrath = 22; - int32 lava_flows = 23; - int32 shamanism = 24; - bool thunderstorm = 25; + int32 elemental_precision = 7; + int32 rolling_thunder = 8; + bool elemental_focus = 9; + int32 elemental_reach = 10; + int32 elemental_oath = 11; + int32 lava_flows = 12; + bool fulmination = 13; + bool elemental_mastery = 14; + int32 earths_grasp = 15; + bool totemic_wrath = 16; + int32 feedback = 17; + int32 lava_surge = 18; + bool earthquake = 19; // Enhancement - int32 enhancing_totems = 26; - int32 earths_grasp = 27; - int32 ancestral_knowledge = 28; - int32 guardian_totems = 29; - int32 thundering_strikes = 30; - int32 improved_ghost_wolf = 31; - int32 improved_shields = 32; - int32 elemental_weapons = 33; - bool shamanistic_focus = 34; - int32 anticipation = 35; - int32 flurry = 36; - int32 toughness = 37; - int32 improved_windfury_totem = 38; - bool spirit_weapons = 39; - int32 mental_dexterity = 40; - int32 unleashed_rage = 41; - int32 weapon_mastery = 42; - int32 frozen_power = 43; - int32 dual_wield_specialization = 44; - bool dual_wield = 45; - bool stormstrike = 46; - int32 static_shock = 47; - bool lava_lash = 48; - int32 improved_stormstrike = 49; - int32 mental_quickness = 50; - bool shamanistic_rage = 51; - int32 earthen_power = 52; - int32 maelstrom_weapon = 53; - bool feral_spirit = 54; + int32 elemental_weapons = 20; + int32 focused_strikes = 21; + int32 improved_shields = 22; + int32 elemental_devastation = 23; + int32 flurry = 24; + int32 ancestral_swiftness = 25; + int32 totemic_reach = 26; + int32 toughness = 27; + bool stormstrike = 28; + int32 static_shock = 29; + int32 frozen_power = 30; + int32 seasoned_winds = 31; + int32 searing_flames = 32; + int32 earthen_power = 33; + bool shamanistic_rage = 34; + int32 unleashed_rage = 35; + int32 maelstrom_weapon = 36; + int32 improved_lava_lash = 37; + bool feral_spirit = 38; // Restoration - int32 improved_healing_wave = 55; - int32 totemic_focus = 56; - int32 improved_reincarnation = 57; - int32 healing_grace = 58; - int32 tidal_focus = 59; - int32 improved_water_shield = 60; - int32 healing_focus = 61; - bool tidal_force = 62; - int32 ancestral_healing = 63; - int32 restorative_totems = 64; - int32 tidal_mastery = 65; - int32 healing_way = 66; - bool natures_swiftness = 67; - int32 focused_mind = 68; - int32 purification = 69; - int32 natures_guardian = 70; - bool mana_tide_totem = 71; - bool cleanse_spirit = 72; - int32 blessing_of_the_eternals = 73; - int32 improved_chain_heal = 74; - int32 natures_blessing = 75; - int32 ancestral_awakening = 76; - bool earth_shield = 77; - int32 improved_earth_shield = 78; - int32 tidal_waves = 79; - bool riptide = 80; + int32 ancestral_resolve = 39; + int32 tidal_focus = 40; + int32 spark_of_life = 41; + int32 resurgence = 42; + int32 totemic_focus = 43; + int32 focused_insight = 44; + int32 natures_guardian = 45; + int32 ancestral_healing = 46; + bool natures_swiftness = 47; + int32 natures_blessing = 48; + int32 soothing_rains = 49; + bool improved_cleanse_spirit = 50; + int32 cleansing_waters = 51; + int32 ancestral_awakening = 52; + bool mana_tide_totem = 53; + int32 telluric_currents = 54; + bool spirit_link_totem = 55; + int32 tidal_waves = 56; + int32 blessing_of_the_eternals = 57; + bool riptide = 58; +} +enum ShamanPrimeGlyph { + ShamanPrimeGlyphNone = 0; + GlyphOfEarthShield = 45775; + GlyphOfEarthlivingWeapon = 41527; + GlyphOfFeralSpirit = 45771; + GlyphOfFireElementalTotem = 41529; + GlyphOfFlameShock = 41531; + GlyphOfFlametongueWeapon = 41532; + GlyphOfLavaBurst = 41524; + GlyphOfLavaLash = 41540; + GlyphOfLightningBolt = 41536; + GlyphOfRiptide = 45772; + GlyphOfShocking = 41526; + GlyphOfStormstrike = 41539; + GlyphOfUnleashedLightning = 71155; + GlyphOfWaterShield = 41541; + GlyphOfWindfuryWeapon = 41542; } - enum ShamanMajorGlyph { ShamanMajorGlyphNone = 0; GlyphOfChainHeal = 41517; GlyphOfChainLightning = 41518; - GlyphOfEarthShield = 45775; - GlyphOfEarthlivingWeapon = 41527; GlyphOfElementalMastery = 41552; - GlyphOfFeralSpirit = 45771; - GlyphOfFireElementalTotem = 41529; GlyphOfFireNova = 41530; - GlyphOfFlameShock = 41531; - GlyphOfFlametongueWeapon = 41532; GlyphOfFrostShock = 41547; + GlyphOfGhostWolf = 43725; + GlyphOfGroundingTotem = 41538; GlyphOfHealingStreamTotem = 41533; GlyphOfHealingWave = 41534; GlyphOfHex = 45777; - GlyphOfLava = 41524; - GlyphOfLavaLash = 41540; - GlyphOfLesserHealingWave = 41535; - GlyphOfLightningBolt = 41536; GlyphOfLightningShield = 41537; - GlyphOfManaTide = 41538; - GlyphOfRiptide = 45772; - GlyphOfShocking = 41526; + GlyphOfShamanisticRage = 45776; GlyphOfStoneclawTotem = 45778; - GlyphOfStormstrike = 41539; GlyphOfThunder = 45770; - GlyphOfTotemOfWrath = 45776; - GlyphOfWaterMastery = 41541; - GlyphOfWindfuryWeapon = 41542; + GlyphOfTotemicRecall = 41535; } enum ShamanMinorGlyph { ShamanMinorGlyphNone = 0; GlyphOfAstralRecall = 43381; - GlyphOfGhostWolf = 43725; GlyphOfRenewedLife = 43385; + GlyphOfTheArcticWolf = 43386; GlyphOfThunderstorm = 44923; GlyphOfWaterBreathing = 43344; - GlyphOfWaterShield = 43386; GlyphOfWaterWalking = 43388; } diff --git a/proto/warlock.proto b/proto/warlock.proto index eb6021af08..0e77f3b257 100644 --- a/proto/warlock.proto +++ b/proto/warlock.proto @@ -3,138 +3,115 @@ package proto; option go_package = "./proto"; -// WotLK talents message WarlockTalents { // Affliction - int32 improved_curse_of_agony = 1; - int32 suppression = 2; + int32 doom_and_gloom = 1; + int32 improved_life_tap = 2; int32 improved_corruption = 3; - int32 improved_curse_of_weakness = 4; - int32 improved_drain_soul = 5; - int32 improved_life_tap = 6; - int32 soul_siphon = 7; + int32 jinx = 4; + int32 soul_siphon = 5; + int32 siphon_life = 6; + bool curse_of_exhaustion = 7; int32 improved_fear = 8; - int32 fel_concentration = 9; - bool amplify_curse = 10; - int32 grim_reach = 11; - int32 nightfall = 12; - int32 empowered_corruption = 13; - int32 shadow_embrace = 14; - bool siphon_life = 15; - bool curse_of_exhaustion = 16; - int32 improved_felhunter = 17; - int32 shadow_mastery = 18; - int32 eradication = 19; - int32 contagion = 20; - bool dark_pact = 21; - int32 improved_howl_of_terror = 22; - int32 malediction = 23; - int32 deaths_embrace = 24; - bool unstable_affliction = 25; - bool pandemic = 26; - int32 everlasting_affliction = 27; - bool haunt = 28; + int32 eradication = 9; + int32 improved_howl_of_terror = 10; + bool soul_swap = 11; + int32 shadow_embrace = 12; + int32 deaths_embrace = 13; + int32 nightfall = 14; + bool soulburn_seed_of_corruption = 15; + int32 everlasting_affliction = 16; + int32 pandemic = 17; + bool haunt = 18; // Demonology - int32 improved_healthstone = 29; - int32 improved_imp = 30; - int32 demonic_embrace = 31; - int32 fel_synergy = 32; - int32 improved_health_funnel = 33; - int32 demonic_brutality = 34; - int32 fel_vitality = 35; - int32 improved_sayaad = 36; - bool soul_link = 37; - bool fel_domination = 38; - int32 demonic_aegis = 39; - int32 unholy_power = 40; - int32 master_summoner = 41; - bool mana_feed = 42; - int32 master_conjuror = 43; - int32 master_demonologist = 44; - int32 molten_core = 45; - int32 demonic_resilience = 46; - bool demonic_empowerment = 47; - int32 demonic_knowledge = 48; - int32 demonic_tactics = 49; - int32 decimation = 50; - int32 improved_demonic_tactics = 51; - bool summon_felguard = 52; - int32 nemesis = 53; - int32 demonic_pact = 54; - bool metamorphosis = 55; + int32 demonic_embrace = 19; + int32 dark_arts = 20; + int32 fel_synergy = 21; + int32 demonic_rebirth = 22; + int32 mana_feed = 23; + int32 demonic_aegis = 24; + int32 master_summoner = 25; + int32 impending_doom = 26; + bool demonic_empowerment = 27; + int32 improved_health_funnel = 28; + int32 molten_core = 29; + bool hand_of_guldan = 30; + int32 aura_of_foreboding = 31; + int32 ancient_grimoire = 32; + bool inferno = 33; + int32 decimation = 34; + int32 cremation = 35; + bool demonic_pact = 36; + bool metamorphosis = 37; // Destruction - int32 improved_shadow_bolt = 56; - int32 bane = 57; - int32 aftermath = 58; - int32 molten_skin = 59; - int32 cataclysm = 60; - int32 demonic_power = 61; - bool shadowburn = 62; - int32 ruin = 63; - int32 intensity = 64; - int32 destructive_reach = 65; - int32 improved_searing_pain = 66; - int32 backlash = 67; - int32 improved_immolate = 68; - bool devastation = 69; - int32 nether_protection = 70; - int32 emberstorm = 71; - bool conflagrate = 72; - int32 soul_leech = 73; - int32 pyroclasm = 74; - int32 shadow_and_flame = 75; - int32 improved_soul_leech = 76; - int32 backdraft = 77; - bool shadowfury = 78; - int32 empowered_imp = 79; - int32 fire_and_brimstone = 80; - bool chaos_bolt = 81; + int32 bane = 38; + int32 shadow_and_flame = 39; + int32 improved_immolate = 40; + int32 aftermath = 41; + int32 emberstorm = 42; + int32 improved_searing_pain = 43; + int32 improved_soul_fire = 44; + int32 backdraft = 45; + bool shadowburn = 46; + int32 burning_embers = 47; + int32 soul_leech = 48; + int32 backlash = 49; + bool nether_ward = 50; + int32 fire_and_brimstone = 51; + bool shadowfury = 52; + int32 nether_protection = 53; + int32 empowered_imp = 54; + bool bane_of_havoc = 55; + bool chaos_bolt = 56; } -enum WarlockMajorGlyph { - WarlockMajorGlyphNone = 0; +enum WarlockPrimeGlyph { + WarlockPrimeGlyphNone = 0; + GlyphOfBaneOfAgony = 42456; GlyphOfChaosBolt = 45781; GlyphOfConflagrate = 42454; GlyphOfCorruption = 42455; - GlyphOfCurseOfAgony = 42456; - GlyphOfDeathCoil = 42457; - GlyphOfDemonicCircle = 45782; - GlyphOfFear = 42458; GlyphOfFelguard = 42459; - GlyphOfFelhunter = 42460; GlyphOfHaunt = 45779; - GlyphOfHealthFunnel = 42461; - GlyphOfHealthstone = 42462; - GlyphOfHowlOfTerror = 42463; GlyphOfImmolate = 42464; GlyphOfImp = 42465; GlyphOfIncinerate = 42453; - GlyphOfLifeTap = 45785; + GlyphOfLashOfPain = 50077; GlyphOfMetamorphosis = 45780; - GlyphOfQuickDecay = 50077; - GlyphOfSearingPain = 42466; - GlyphOfShadowBolt = 42467; GlyphOfShadowburn = 42468; + GlyphOfUnstableAffliction = 42472; +} +enum WarlockMajorGlyph { + WarlockMajorGlyphNone = 0; + GlyphOfDeathCoilWl = 42457; + GlyphOfDemonicCircle = 45782; + GlyphOfFear = 42458; + GlyphOfFelhunter = 42460; + GlyphOfHealthstone = 42462; + GlyphOfHowlOfTerror = 42463; + GlyphOfLifeTap = 45785; + GlyphOfSeduction = 42471; + GlyphOfShadowBolt = 42467; GlyphOfShadowflame = 45783; - GlyphOfSiphonLife = 42469; GlyphOfSoulLink = 45789; + GlyphOfSoulSwap = 42466; GlyphOfSoulstone = 42470; - GlyphOfSuccubus = 42471; - GlyphOfUnstableAffliction = 42472; GlyphOfVoidwalker = 42473; } enum WarlockMinorGlyph { WarlockMinorGlyphNone = 0; - GlyphOfCurseOfExhausion = 43392; + GlyphOfCurseOfExhaustion = 43392; GlyphOfDrainSoul = 43390; + GlyphOfEyeOfKilrogg = 43391; + GlyphOfHealthFunnel = 42461; + GlyphOfRitualOfSouls = 43394; GlyphOfSubjugateDemon = 43393; - GlyphOfKilrogg = 43391; - GlyphOfSouls = 43394; GlyphOfUnendingBreath = 43389; } + message WarlockOptions { enum Summon { NoSummon = 0; diff --git a/proto/warrior.proto b/proto/warrior.proto index 06bdde705f..e08a4b867f 100644 --- a/proto/warrior.proto +++ b/proto/warrior.proto @@ -5,136 +5,114 @@ option go_package = "./proto"; message WarriorTalents { // Arms - int32 improved_heroic_strike = 1; - int32 deflection = 2; - int32 improved_rend = 3; - int32 improved_charge = 4; - int32 iron_will = 5; - int32 tactical_mastery = 6; - int32 improved_overpower = 7; - bool anger_management = 8; - int32 impale = 9; - int32 deep_wounds = 10; - int32 two_handed_weapon_specialization = 11; - int32 taste_for_blood = 12; - int32 poleaxe_specialization = 13; - bool sweeping_strikes = 14; - int32 mace_specialization = 15; - int32 sword_specialization = 16; - int32 weapon_mastery = 17; - int32 improved_hamstring = 18; - int32 trauma = 19; - int32 second_wind = 20; - bool mortal_strike = 21; - int32 strength_of_arms = 22; - int32 improved_slam = 23; - bool juggernaut = 24; - int32 improved_mortal_strike = 25; - int32 unrelenting_assault = 26; - int32 sudden_death = 27; - bool endless_rage = 28; - int32 blood_frenzy = 29; - int32 wrecking_crew = 30; - bool bladestorm = 31; + int32 war_academy = 1; + int32 field_dressing = 2; + int32 blitz = 3; + int32 tactical_mastery = 4; + int32 second_wind = 5; + int32 deep_wounds = 6; + int32 drums_of_war = 7; + int32 taste_for_blood = 8; + bool sweeping_strikes = 9; + int32 impale = 10; + int32 improved_hamstring = 11; + int32 improved_slam = 12; + bool deadly_calm = 13; + int32 blood_frenzy = 14; + int32 lambs_to_the_slaughter = 15; + bool juggernaut = 16; + int32 sudden_death = 17; + int32 wrecking_crew = 18; + bool throwdown = 19; + bool bladestorm = 20; // Fury - int32 armored_to_the_teeth = 32; - int32 booming_voice = 33; - int32 cruelty = 34; - int32 improved_demoralizing_shout = 35; - int32 unbridled_wrath = 36; - int32 improved_cleave = 37; - bool piercing_howl = 38; - int32 blood_craze = 39; - int32 commanding_presence = 40; - int32 dual_wield_specialization = 41; - int32 improved_execute = 42; - int32 enrage = 43; - int32 precision = 44; - bool death_wish = 45; - int32 improved_intercept = 46; - int32 improved_berserker_rage = 47; - int32 flurry = 48; - int32 intensify_rage = 49; - bool bloodthirst = 50; - int32 improved_whirlwind = 51; - int32 furious_attacks = 52; - int32 improved_berserker_stance = 53; - bool heroic_fury = 54; - bool rampage = 55; - int32 bloodsurge = 56; - int32 unending_fury = 57; - bool titans_grip = 58; + int32 blood_craze = 21; + int32 battle_trance = 22; + int32 cruelty = 23; + int32 executioner = 24; + int32 booming_voice = 25; + int32 rude_interruption = 26; + bool piercing_howl = 27; + int32 flurry = 28; + bool death_wish = 29; + int32 enrage = 30; + int32 die_by_the_sword = 31; + bool raging_blow = 32; + bool rampage = 33; + bool heroic_fury = 34; + bool furious_attacks = 35; + int32 meat_cleaver = 36; + int32 intensify_rage = 37; + int32 bloodsurge = 38; + int32 skirmisher = 39; + bool titans_grip = 40; + bool single_minded_fury = 41; // Protection - int32 improved_bloodrage = 59; - int32 shield_specialization = 60; - int32 improved_thunder_clap = 61; - int32 incite = 62; - int32 anticipation = 63; - bool last_stand = 64; - int32 improved_revenge = 65; - int32 shield_mastery = 66; - int32 toughness = 67; - int32 improved_spell_reflection = 68; - int32 improved_disarm = 69; - int32 puncture = 70; - int32 improved_disciplines = 71; - bool concussion_blow = 72; - int32 gag_order = 73; - int32 one_handed_weapon_specialization = 74; - int32 improved_defensive_stance = 75; - bool vigilance = 76; - int32 focused_rage = 77; - int32 vitality = 78; - int32 safeguard = 79; - bool warbringer = 80; - bool devastate = 81; - int32 critical_block = 82; - int32 sword_and_board = 83; - int32 damage_shield = 84; - bool shockwave = 85; + int32 incite = 42; + int32 toughness = 43; + int32 blood_and_thunder = 44; + int32 shield_specialization = 45; + int32 shield_mastery = 46; + int32 hold_the_line = 47; + int32 gag_order = 48; + bool last_stand = 49; + bool concussion_blow = 50; + int32 bastion_of_defense = 51; + bool warbringer = 52; + int32 improved_revenge = 53; + bool devastate = 54; + int32 impending_victory = 55; + int32 thunderstruck = 56; + bool vigilance = 57; + int32 heavy_repercussions = 58; + int32 safeguard = 59; + int32 sword_and_board = 60; + bool shockwave = 61; } - -enum WarriorMajorGlyph { - WarriorMajorGlyphNone = 0; - GlyphOfBarbaricInsults = 43420; +enum WarriorPrimeGlyph { + WarriorPrimeGlyphNone = 0; GlyphOfBladestorm = 45790; - GlyphOfBlocking = 43425; - GlyphOfBloodthirst = 43412; - GlyphOfCleaving = 43414; + GlyphOfBloodthirst = 43416; GlyphOfDevastate = 43415; - GlyphOfEnragedRegeneration = 45794; - GlyphOfExecution = 43416; - GlyphOfHamstring = 43417; - GlyphOfHeroicStrike = 43418; - GlyphOfIntervene = 43419; - GlyphOfLastStand = 43426; GlyphOfMortalStrike = 43421; GlyphOfOverpower = 43422; + GlyphOfRagingBlow = 43432; + GlyphOfRevenge = 43424; + GlyphOfShieldSlam = 43425; + GlyphOfSlam = 43423; +} +enum WarriorMajorGlyph { + WarriorMajorGlyphNone = 0; + GlyphOfCleaving = 43414; + GlyphOfColossusSmash = 63481; + GlyphOfDeathWish = 67483; + GlyphOfHeroicThrow = 43418; + GlyphOfIntercept = 67482; + GlyphOfIntervene = 43419; + GlyphOfLongCharge = 43397; + GlyphOfPiercingHowl = 43417; GlyphOfRapidCharge = 43413; - GlyphOfRending = 43423; GlyphOfResonatingPower = 43430; - GlyphOfRevenge = 43424; GlyphOfShieldWall = 45797; GlyphOfShockwave = 45792; GlyphOfSpellReflection = 45795; GlyphOfSunderArmor = 43427; GlyphOfSweepingStrikes = 43428; - GlyphOfTaunt = 43429; + GlyphOfThunderClap = 43399; GlyphOfVictoryRush = 43431; - GlyphOfVigilance = 45793; - GlyphOfWhirlwind = 43432; } enum WarriorMinorGlyph { WarriorMinorGlyphNone = 0; GlyphOfBattle = 43395; - GlyphOfBloodrage = 43396; - GlyphOfCharge = 43397; + GlyphOfBerserkerRage = 43396; + GlyphOfBloodyHealing = 43412; GlyphOfCommand = 49084; + GlyphOfDemoralizingShout = 43398; GlyphOfEnduringVictory = 43400; - GlyphOfMockingBlow = 43398; - GlyphOfThunderClap = 43399; + GlyphOfFuriousSundering = 45793; + GlyphOfIntimidatingShout = 45794; GlyphOfShatteringThrow = 206953; } diff --git a/sim/core/character.go b/sim/core/character.go index 83238aa870..4b8ff964eb 100644 --- a/sim/core/character.go +++ b/sim/core/character.go @@ -67,7 +67,7 @@ type Character struct { professions [2]proto.Profession - glyphs [6]int32 + glyphs [9]int32 PrimaryTalentTree uint8 // Provides major cooldown management behavior. @@ -130,7 +130,10 @@ func NewCharacter(party *Party, partyIndex int, player *proto.Player) Character character.Label = fmt.Sprintf("%s (#%d)", character.Name, character.Index+1) if player.Glyphs != nil { - character.glyphs = [6]int32{ + character.glyphs = [9]int32{ + player.Glyphs.Prime1, + player.Glyphs.Prime2, + player.Glyphs.Prime3, player.Glyphs.Major1, player.Glyphs.Major2, player.Glyphs.Major3, diff --git a/tools/database/wowhead_reforge_db.go b/tools/database/wowhead_reforge_db.go index adef9666a1..e2e13517a0 100644 --- a/tools/database/wowhead_reforge_db.go +++ b/tools/database/wowhead_reforge_db.go @@ -33,8 +33,7 @@ var statStringToEnum = map[string][]proto.Stat{ "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}, + "mastrtng": {proto.Stat_StatMastery}, } func mapStringToStat(statString string) []proto.Stat { diff --git a/tools/scrape_glyphs.py b/tools/scrape_glyphs.py index ca53cd33c9..0e341fa82d 100644 --- a/tools/scrape_glyphs.py +++ b/tools/scrape_glyphs.py @@ -9,10 +9,25 @@ import sys from selenium import webdriver -from selenium.webdriver.chrome.service import Service +from selenium.webdriver.chrome.service import Service as ChromeService +from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys -from webdriver_manager.chrome import ChromeDriverManager +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +chrome_options = Options() +chrome_options.add_argument('--headless') +chrome_options.add_argument('--no-sandbox') +chrome_options.add_argument('--disable-dev-shm-usage') +driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()),options=chrome_options) +if len(sys.argv) < 3: + raise Exception("Missing arguments, expected class_name and output_file_path") +class_name = sys.argv[1] +output_file_path = sys.argv[2] + +driver.implicitly_wait(2) if len(sys.argv) < 3: raise Exception("Missing arguments, expected class_name and output_file_path") @@ -22,6 +37,21 @@ # Convert "death-knight" to DeathKnight pretty_class_name = "".join(word.title() for i, word in enumerate(class_name.split("-"))) lower_class_name = "".join(word if i == 0 else word.title() for i, word in enumerate(class_name.split("-"))) +def get_glyphs_ids(): + glyphs_ids = [] + driver.get("https://www.wowhead.com/cata/spells/glyphs/"+class_name) + glyphs_list = driver.find_element(By.CLASS_NAME, "listview-mode-default") + rows = glyphs_list.find_elements(By.CLASS_NAME, "listview-row") + for row in rows: + cells = row.find_elements(By.TAG_NAME, "td") + label_elem = cells[1].find_element(By.TAG_NAME, "a") + glyph_name = label_elem.text + link = label_elem.get_attribute("href") + id_match = re.search(r"spell=(\d+)", link) + spell_id = int(id_match.group(1)) + glyphs_ids.append([glyph_name, spell_id]) + return glyphs_ids + def get_glyphs_data(glyph_button): glyph_button.click() @@ -55,17 +85,29 @@ def get_glyphs_data(glyph_button): return glyphs_data -driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) driver.implicitly_wait(2) driver.get('https://wowhead.com/cata/talent-calc/' + class_name) +try: + wait = WebDriverWait(driver, 10) + accept_button = wait.until(EC.element_to_be_clickable((By.ID, "onetrust-accept-btn-handler"))) + accept_button.click() + print("Clicked the 'I Accept' button.") +except Exception as e: + print("Error") +driver.implicitly_wait(2) glyph_slots = driver.find_elements(By.CLASS_NAME, "ctc-glyphs-group-slot") -major_glyph_slot = next(gs for gs in glyph_slots if int(gs.get_attribute("data-glyph-slot")) == 0) -minor_glyph_slot = next(gs for gs in glyph_slots if int(gs.get_attribute("data-glyph-slot")) == 3) +prime_glyph_slot = next(gs for gs in glyph_slots if int(gs.get_attribute("data-glyph-slot")) == 0) +major_glyph_slot = next(gs for gs in glyph_slots if int(gs.get_attribute("data-glyph-slot")) == 3) +minor_glyph_slot = next(gs for gs in glyph_slots if int(gs.get_attribute("data-glyph-slot")) == 6) +prime_glyphs_data = get_glyphs_data(prime_glyph_slot) +webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform() major_glyphs_data = get_glyphs_data(major_glyph_slot) webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform() minor_glyphs_data = get_glyphs_data(minor_glyph_slot) + +glyph_ids = get_glyphs_ids() driver.quit() def write_glyphs_proto(outfile, glyphs_data, glyph_type): @@ -91,14 +133,27 @@ def write_glyphs_config(outfile, glyphs_data, glyph_type): outfile.write("\t\t},\n") outfile.write("\t},\n") - +def write_glyphs_ids(outfile, glyphs_data, glyphs_ids): + # First, update glyph_data with the correct spell ID from glyphs_ids + for name, spell_id in glyphs_ids: + for glyph_data in glyphs_data: + if glyph_data["name"] == name: + outfile.write('{{"itemId": {},"spellId": {}}},\n'.format(glyph_data["id"], spell_id)) with open(output_file_path, "w") as outfile: + write_glyphs_proto(outfile, prime_glyphs_data, "Prime") write_glyphs_proto(outfile, major_glyphs_data, "Major") write_glyphs_proto(outfile, minor_glyphs_data, "Minor") - + outfile.write("\n") + outfile.write("\n") + outfile.write("\n") + write_glyphs_ids(outfile, prime_glyphs_data, glyph_ids) + write_glyphs_ids(outfile, major_glyphs_data, glyph_ids) + write_glyphs_ids(outfile, minor_glyphs_data, glyph_ids) + outfile.write("\n") outfile.write("\n") outfile.write("export const {}GlyphsConfig: GlyphsConfig = {{\n".format(lower_class_name)) + write_glyphs_config(outfile, prime_glyphs_data, "Prime") write_glyphs_config(outfile, major_glyphs_data, "Major") write_glyphs_config(outfile, minor_glyphs_data, "Minor") - outfile.write("};") + outfile.write("};") \ No newline at end of file diff --git a/tools/scrape_pet_talents.py b/tools/scrape_pet_talents.py new file mode 100644 index 0000000000..5621efe7c0 --- /dev/null +++ b/tools/scrape_pet_talents.py @@ -0,0 +1,64 @@ +#!/usr/bin/python + +# This tool generates the talents proto code, e.g. 'ShamanTalents' found in proto/shaman.proto. + +import json +import sys + +from selenium import webdriver +from selenium.webdriver.chrome.service import Service as ChromeService +from webdriver_manager.chrome import ChromeDriverManager +from selenium.webdriver.common.by import By +from selenium.webdriver.chrome.options import Options +chrome_options = Options() +chrome_options.add_argument('--headless') +chrome_options.add_argument('--no-sandbox') +chrome_options.add_argument('--disable-dev-shm-usage') +driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()),options=chrome_options) +if len(sys.argv) < 3: + raise Exception("Missing arguments, expected class_name and output_file_path") +class_name = sys.argv[1] +output_file_path = sys.argv[2] + +driver.implicitly_wait(2) + +driver.get('https://wowhead.com/cata/pet-talent-calc/') +trees = driver.find_elements(By.CLASS_NAME, "ctc-tree") + +with open(output_file_path, "w") as outfile: + # Convert "death-knight" to DeathKnight + pretty_class_name = "".join(word.title() for i, word in enumerate(class_name.split("-"))) + outfile.write("message {}Talents {{\n".format(pretty_class_name)) + + talent_idx = 1 + print(trees) + for tree_idx, tree in enumerate(trees): + title = tree.find_element(By.XPATH, ".//b").text + outfile.write("\t// {}\n".format(title)) + + tree_talents_data = [] + talents = tree.find_elements(By.CLASS_NAME, "ctc-tree-talent") + for talent in talents: + max_points = int(talent.get_attribute("data-max-points")) + field_type = "bool" if max_points == 1 else "int32" + + link = talent.find_element(By.XPATH, "./div/a").get_attribute("href") + name = "_".join(word for i, word in enumerate(link.split("/")[-1].split("-"))) + + print("Talent: " + name) + tree_talents_data.append({ + "row": int(talent.get_attribute("data-row")), + "col": int(talent.get_attribute("data-col")), + "name": name, + "field_type": field_type, + }) + + tree_talents_data.sort(key=lambda data: data["row"] * 4 + data["col"]) + for data in tree_talents_data: + outfile.write("\t{} {} = {};\n".format(data["field_type"], data["name"], talent_idx)) + talent_idx += 1 + + if tree_idx != len(trees) - 1: + outfile.write("\n") + + outfile.write("}") \ No newline at end of file diff --git a/tools/scrape_pet_talents_config.py b/tools/scrape_pet_talents_config.py new file mode 100644 index 0000000000..89ff07f2d5 --- /dev/null +++ b/tools/scrape_pet_talents_config.py @@ -0,0 +1,150 @@ +#!/usr/bin/python + +# This tool generates the talents config code, e.g. in ui/core/talents/shaman.ts. + +import json +import sys + +from typing import List + +from selenium import webdriver +from selenium.webdriver.chrome.service import Service as ChromeService +from webdriver_manager.chrome import ChromeDriverManager +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +chrome_options = Options() +chrome_options.add_argument('--headless') +chrome_options.add_argument('--no-sandbox') +chrome_options.add_argument('--disable-dev-shm-usage') +driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()),options=chrome_options) + +if len(sys.argv) < 3: + raise Exception("Missing arguments, expected className and outputFilePath") +className = sys.argv[1] +outputFilePath = sys.argv[2] + +def _between(s, start, end): + return s[(i := s.find(start) + len(start)): i + s[i:].find(end)] + + +driver.implicitly_wait(2) + + +def _get_spell_id_from_link(link): + parts = link.split("/") + for part in parts: + if "spell=" in part: + return int(part.split("=")[-1]) + raise ValueError("No spell ID found in the link") + + + +def get_other_spell_ranks(spell_name: str, ignore_int: int) -> List[int]: + overrides = { + "T N T": "t.n.t", + } + + formatted_spell_name = overrides.get(spell_name, spell_name.replace(' ', '+')) + driver.get(f"https://www.wowhead.com/cata/spells/pet-abilities/{className}/name:{formatted_spell_name}") + driver.implicitly_wait(2) + + spell_ids = [] + table = driver.find_element(By.CLASS_NAME, "listview-mode-default") + rows = table.find_elements(By.CLASS_NAME, "listview-row") + print(f"Found {len(rows)} for {spell_name}") + for row in rows: + questionable_elements = row.find_elements(By.XPATH, ".//*[contains(@style, 'inv_misc_questionmark.jpg')]") + + if questionable_elements: + # If any questionable elements found, skip this row + print("Skipping row") + continue + a_element = row.find_element(By.CLASS_NAME, "listview-cleartext") + href = a_element.get_attribute("href") + spell_id = _get_spell_id_from_link(href) + if spell_id != ignore_int: + spell_ids.append(spell_id) + + return spell_ids + +def rowcol(v): + return v["location"]["rowIdx"] + v["location"]["colIdx"]/10 + + +to_export = [] + +driver.get('https://wowhead.com/cata/pet-talent-calc/') +try: + wait = WebDriverWait(driver, 10) + accept_button = wait.until(EC.element_to_be_clickable((By.ID, "onetrust-accept-btn-handler"))) + accept_button.click() + print("Clicked the 'I Accept' button.") +except Exception as e: + print("No 'I Accept' button to click or error clicking it:", e) +driver.implicitly_wait(2) +trees = driver.find_elements(By.CLASS_NAME, "ctc-tree") +for tree in trees: + _working_talents = {} + + talents = tree.find_elements(By.CLASS_NAME, "ctc-tree-talent") + print("found %d talents\n".format(len(talents))) + for talent in talents: + row, col = int(talent.get_attribute("data-row")), int(talent.get_attribute("data-col")) + max_points = int(talent.get_attribute("data-max-points")) + link = talent.find_element(By.XPATH, "./div/a").get_attribute("href") + name = "".join(word if i == 0 else word.title() for i, word in enumerate(link.split("/")[-1].split("-"))) + fancyName = " ".join(word.title() for i, word in enumerate(link.split("/")[-1].split("-"))) + print(link) + print(_get_spell_id_from_link(link)) + _working_talents[(row, col)] = { + "fieldName": name, + "fancyName": fancyName, + "location": { + "rowIdx": row, + "colIdx": col, + }, + "spellIds": [_get_spell_id_from_link(link)], + "maxPoints": max_points, + } + + arrows = tree.find_elements(By.CLASS_NAME, "ctc-tree-talent-arrow") + for arrow in arrows: + prereq_row, prereq_col = int(arrow.get_attribute("data-row")), int(arrow.get_attribute("data-col")) + length = 0 + dsstr = arrow.get_attribute("data-size") + if dsstr: + length = int(dsstr) + + direction = arrow.get_attribute("class").split()[-1].split("-")[-1] + offset_row, offset_col = {"left": (0, -1), "right": (0, 1), "down": (1, 0)}[direction] + + end_row = prereq_row + offset_row * length + end_col = prereq_col + offset_col * length + + _working_talents[(end_row, end_col)]["prereqLocation"] = { + "rowIdx": prereq_row, + "colIdx": prereq_col, + } + + title = tree.find_element(By.XPATH, ".//b").text + background = tree.find_element(By.CLASS_NAME, "ctc-tree-talents-background").get_attribute("style") + values = list(_working_talents.values()) + values.sort(key=rowcol) + to_export.append({ + "name": title, + "backgroundUrl": _between(background, '"', '"'), + "talents": values, + }) + +for subtree in to_export: + for talent in subtree["talents"]: + if talent["maxPoints"] > 1: + talent["spellIds"] += get_other_spell_ranks(talent["fancyName"], talent["spellIds"][0]) + +json_data = json.dumps(to_export, indent=2) +with open(outputFilePath, "w") as outfile: + outfile.write(json_data) \ No newline at end of file diff --git a/tools/scrape_proto.sh b/tools/scrape_proto.sh new file mode 100644 index 0000000000..d48c63e343 --- /dev/null +++ b/tools/scrape_proto.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +# WoW Classic classes +classes=("druid" "death-knight" "hunter" "mage" "paladin" "priest" "rogue" "shaman" "warlock" "warrior") + +for class in "${classes[@]}"; do + # Replace "-" with "" for filenames + #python3 ./scrape_talents_proto.py $class ../proto/${class}.proto + python3 ./scrape_glyphs.py $class ../proto/tmp/${class}.proto.test + #python3 ./scrape_talents_config.py $class ../ui/core/talents/trees/${class}.json +done \ No newline at end of file diff --git a/tools/scrape_talents_config.py b/tools/scrape_talents_config.py index 93e4ee9ab5..8ab6fd3e4f 100644 --- a/tools/scrape_talents_config.py +++ b/tools/scrape_talents_config.py @@ -8,9 +8,19 @@ from typing import List from selenium import webdriver -from selenium.webdriver.chrome.service import Service -from selenium.webdriver.common.by import By +from selenium.webdriver.chrome.service import Service as ChromeService from webdriver_manager.chrome import ChromeDriverManager +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +chrome_options = Options() +chrome_options.add_argument('--headless') +chrome_options.add_argument('--no-sandbox') +chrome_options.add_argument('--disable-dev-shm-usage') +driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()),options=chrome_options) if len(sys.argv) < 3: raise Exception("Missing arguments, expected className and outputFilePath") @@ -21,21 +31,45 @@ def _between(s, start, end): return s[(i := s.find(start) + len(start)): i + s[i:].find(end)] -driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) driver.implicitly_wait(2) def _get_spell_id_from_link(link): - return int(link.split("/")[-2].split("=")[-1]) - - -def get_other_spell_ranks(spell_id: int) -> List[int]: - driver.get(f"https://wowhead.com/cata/spell={spell_id}#see-also-ability") - - see_also = driver.find_element(By.ID, "tab-see-also-ability") # ordered by rank - rows = see_also.find_elements(By.CLASS_NAME, "listview-row") - return [_get_spell_id_from_link(row.find_element(By.CLASS_NAME, "listview-cleartext").get_attribute("href")) - for row in rows] + parts = link.split("/") + for part in parts: + if "spell=" in part: + return int(part.split("=")[-1]) + raise ValueError("No spell ID found in the link") + + + +def get_other_spell_ranks(spell_name: str, ignore_int: int) -> List[int]: + overrides = { + "T N T": "t.n.t", + } + + formatted_spell_name = overrides.get(spell_name, spell_name.replace(' ', '+')) + driver.get(f"https://www.wowhead.com/cata/spells/talents/{className}/name:{formatted_spell_name}") + driver.implicitly_wait(2) + + spell_ids = [] + table = driver.find_element(By.CLASS_NAME, "listview-mode-default") + rows = table.find_elements(By.CLASS_NAME, "listview-row") + print(f"Found {len(rows)} for {spell_name}") + for row in rows: + questionable_elements = row.find_elements(By.XPATH, ".//*[contains(@style, 'inv_misc_questionmark.jpg')]") + + if questionable_elements: + # If any questionable elements found, skip this row + print("Skipping row") + continue + a_element = row.find_element(By.CLASS_NAME, "listview-cleartext") + href = a_element.get_attribute("href") + spell_id = _get_spell_id_from_link(href) + if spell_id != ignore_int: + spell_ids.append(spell_id) + + return spell_ids def rowcol(v): return v["location"]["rowIdx"] + v["location"]["colIdx"]/10 @@ -44,6 +78,14 @@ def rowcol(v): to_export = [] driver.get('https://wowhead.com/cata/talent-calc/' + className) +try: + wait = WebDriverWait(driver, 10) + accept_button = wait.until(EC.element_to_be_clickable((By.ID, "onetrust-accept-btn-handler"))) + accept_button.click() + print("Clicked the 'I Accept' button.") +except Exception as e: + print("No 'I Accept' button to click or error clicking it:", e) +driver.implicitly_wait(2) trees = driver.find_elements(By.CLASS_NAME, "ctc-tree") for tree in trees: _working_talents = {} @@ -55,8 +97,10 @@ def rowcol(v): max_points = int(talent.get_attribute("data-max-points")) link = talent.find_element(By.XPATH, "./div/a").get_attribute("href") name = "".join(word if i == 0 else word.title() for i, word in enumerate(link.split("/")[-1].split("-"))) + fancyName = " ".join(word.title() for i, word in enumerate(link.split("/")[-1].split("-"))) _working_talents[(row, col)] = { "fieldName": name, + "fancyName": fancyName, "location": { "rowIdx": row, "colIdx": col, @@ -84,7 +128,7 @@ def rowcol(v): "colIdx": prereq_col, } - title = tree.find_element(By.XPATH, "./div/b").text + title = tree.find_element(By.XPATH, ".//b").text background = tree.find_element(By.CLASS_NAME, "ctc-tree-talents-background").get_attribute("style") values = list(_working_talents.values()) values.sort(key=rowcol) @@ -97,8 +141,8 @@ def rowcol(v): for subtree in to_export: for talent in subtree["talents"]: if talent["maxPoints"] > 1: - talent["spellIds"] += get_other_spell_ranks(talent["spellIds"][0]) + talent["spellIds"] += get_other_spell_ranks(talent["fancyName"], talent["spellIds"][0]) json_data = json.dumps(to_export, indent=2) with open(outputFilePath, "w") as outfile: - outfile.write(json_data) + outfile.write(json_data) \ No newline at end of file diff --git a/tools/scrape_talents_proto.py b/tools/scrape_talents_proto.py index b1eef85216..69ee9b04ce 100644 --- a/tools/scrape_talents_proto.py +++ b/tools/scrape_talents_proto.py @@ -6,16 +6,20 @@ import sys from selenium import webdriver -from selenium.webdriver.chrome.service import Service -from selenium.webdriver.common.by import By +from selenium.webdriver.chrome.service import Service as ChromeService from webdriver_manager.chrome import ChromeDriverManager - +from selenium.webdriver.common.by import By +from selenium.webdriver.chrome.options import Options +chrome_options = Options() +chrome_options.add_argument('--headless') +chrome_options.add_argument('--no-sandbox') +chrome_options.add_argument('--disable-dev-shm-usage') +driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()),options=chrome_options) if len(sys.argv) < 3: raise Exception("Missing arguments, expected class_name and output_file_path") class_name = sys.argv[1] output_file_path = sys.argv[2] -driver = webdriver.Chrome(ChromeDriverManager().install()) driver.implicitly_wait(2) driver.get('https://wowhead.com/cata/talent-calc/' + class_name) @@ -27,8 +31,9 @@ outfile.write("message {}Talents {{\n".format(pretty_class_name)) talent_idx = 1 + print(trees) for tree_idx, tree in enumerate(trees): - title = tree.find_element(By.XPATH, "./div/b").text + title = tree.find_element(By.XPATH, ".//b").text outfile.write("\t// {}\n".format(title)) tree_talents_data = [] @@ -56,4 +61,4 @@ if tree_idx != len(trees) - 1: outfile.write("\n") - outfile.write("}") + outfile.write("}") \ No newline at end of file diff --git a/ui/core/components/exporters.tsx b/ui/core/components/exporters.tsx index 5a1540496c..298f13a2a1 100644 --- a/ui/core/components/exporters.tsx +++ b/ui/core/components/exporters.tsx @@ -259,12 +259,15 @@ export class IndividualWowheadGearPlannerExporter extends glyphStr += d[(spellId >> 5) & 0b00011111]; glyphStr += d[(spellId >> 0) & 0b00011111]; }; - addGlyph(glyphs.major1, 0); - addGlyph(glyphs.major2, 1); - addGlyph(glyphs.major3, 2); - addGlyph(glyphs.minor1, 3); - addGlyph(glyphs.minor2, 4); - addGlyph(glyphs.minor3, 5); + addGlyph(glyphs.prime1, 0); + addGlyph(glyphs.prime2, 1); + addGlyph(glyphs.prime3, 2); + addGlyph(glyphs.major1, 3); + addGlyph(glyphs.major2, 4); + addGlyph(glyphs.major3, 5); + addGlyph(glyphs.minor1, 6); + addGlyph(glyphs.minor2, 7); + addGlyph(glyphs.minor3, 8); if (glyphStr) { glyphBytes.push(0x30); for (let i = 0; i < glyphStr.length; i++) { diff --git a/ui/core/player.ts b/ui/core/player.ts index 80670b6e28..bc7bdec67d 100644 --- a/ui/core/player.ts +++ b/ui/core/player.ts @@ -868,6 +868,14 @@ export class Player { this.glyphsChangeEmitter.emit(eventID); } + getPrimeGlyps(): Array { + return [ + this.glyphs.prime1, + this.glyphs.prime2, + this.glyphs.prime3, + ].filter(glyph => glyph != 0) + } + getMajorGlyphs(): Array { return [this.glyphs.major1, this.glyphs.major2, this.glyphs.major3].filter(glyph => glyph != 0); } @@ -877,7 +885,7 @@ export class Player { } getAllGlyphs(): Array { - return this.getMajorGlyphs().concat(this.getMinorGlyphs()); + return this.getPrimeGlyps().concat(this.getMajorGlyphs().concat(this.getMinorGlyphs())); } getClassOptions(): ClassOptions { diff --git a/ui/core/talents/death_knight.ts b/ui/core/talents/death_knight.ts index 5eb9b5754a..58ef5ab8e2 100644 --- a/ui/core/talents/death_knight.ts +++ b/ui/core/talents/death_knight.ts @@ -1,147 +1,132 @@ -import { DeathKnightMajorGlyph, DeathKnightMinorGlyph, DeathKnightTalents } from '../proto/death_knight'; +import {DeathKnightMajorGlyph, DeathKnightMinorGlyph, DeathKnightPrimeGlyph, DeathKnightTalents } from '../proto/death_knight'; import { GlyphsConfig } from './glyphs_picker.jsx'; import { newTalentsConfig, TalentsConfig } from './talents_picker.jsx'; import DkTalentsJson from './trees/death_knight.json'; -export const deathknightTalentsConfig: TalentsConfig = newTalentsConfig(DkTalentsJson); +export const deathKnightTalentsConfig: TalentsConfig = newTalentsConfig(DkTalentsJson); -export const deathknightGlyphsConfig: GlyphsConfig = { - majorGlyphs: { - [DeathKnightMajorGlyph.GlyphOfAntiMagicShell]: { - name: 'Glyph of Anti-Magic Shell', - description: 'Increases the duration of your Anti-Magic Shell by 2 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_antimagicshell.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfBloodStrike]: { - name: 'Glyph of Blood Strike', - description: 'Your Blood Strike causes an additional 20% damage to snared targets.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_deathstrike.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfBoneShield]: { - name: 'Glyph of Bone Shield', - description: 'Adds 1 additional charge to your Bone Shield.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_chest_leather_13.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfChainsOfIce]: { - name: 'Glyph of Chains of Ice', - description: 'Your Chains of Ice also causes 144 to 156 Frost damage, increased by your attack power.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_chainsofice.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfDancingRuneWeapon]: { - name: 'Glyph of Dancing Rune Weapon', - description: 'Increases the duration of Dancing Rune Weapon by 5 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_sword_07.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfDarkCommand]: { - name: 'Glyph of Dark Command', - description: 'Increases the chance for your Dark Command ability to work successfully by 8%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_shamanrage.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfDarkDeath]: { - name: 'Glyph of Dark Death', - description: 'Increases the damage or healing done by Death Coil by 15%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_deathcoil.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfDeathAndDecay]: { +export const deathKnightGlyphsConfig: GlyphsConfig = { + primeGlyphs: { + [DeathKnightPrimeGlyph.GlyphOfDeathAndDecay]: { name: 'Glyph of Death and Decay', - description: 'Damage of your Death and Decay spell increased by 20%.', + description: 'Increases the duration of your Death and Decay spell by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_deathanddecay.jpg', }, - [DeathKnightMajorGlyph.GlyphOfDeathGrip]: { - name: 'Glyph of Death Grip', - description: 'When you deal a killing blow that grants honor or experience, the cooldown of your Death Grip is refreshed.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_strangulate.jpg', + [DeathKnightPrimeGlyph.GlyphOfDeathCoil]: { + name: 'Glyph of Death Coil', + description: 'Increases the damage or healing done by Death Coil by 15%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_deathcoil.jpg', }, - [DeathKnightMajorGlyph.GlyphOfDeathStrike]: { + [DeathKnightPrimeGlyph.GlyphOfDeathStrike]: { name: 'Glyph of Death Strike', - description: - "Increases your Death Strike's damage by 1% for every 1 runic power you currently have (up to a maximum of 25%). The runic power is not consumed by this effect.", + description: 'Increases your Death Strike\'s damage by 2% for every 5 Runic Power you currently have (up to a maximum of 40%). The Runic Power is not consumed by this effect.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_butcher2.jpg', }, - [DeathKnightMajorGlyph.GlyphOfDisease]: { - name: 'Glyph of Disease', - description: - 'Your Pestilence ability now refreshes disease durations and secondary effects of diseases on your primary target back to their maximum duration.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_plaguecloud.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfFrostStrike]: { + [DeathKnightPrimeGlyph.GlyphOfFrostStrike]: { name: 'Glyph of Frost Strike', description: 'Reduces the cost of your Frost Strike by 8 Runic Power.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_empowerruneblade2.jpg', }, - [DeathKnightMajorGlyph.GlyphOfHeartStrike]: { + [DeathKnightPrimeGlyph.GlyphOfHeartStrike]: { name: 'Glyph of Heart Strike', - description: 'Your Heart Strike also reduces the movement speed of your target by 50% for 10 sec.', + description: 'Increases the damage of your Heart Strike ability by 30%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_weapon_shortblade_40.jpg', }, - [DeathKnightMajorGlyph.GlyphOfHowlingBlast]: { + [DeathKnightPrimeGlyph.GlyphOfHowlingBlast]: { name: 'Glyph of Howling Blast', description: 'Your Howling Blast ability now infects your targets with Frost Fever.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_arcticwinds.jpg', }, - [DeathKnightMajorGlyph.GlyphOfHungeringCold]: { - name: 'Glyph of Hungering Cold', - description: 'Reduces the cost of Hungering Cold by 40 runic power.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_staff_15.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfIceboundFortitude]: { - name: 'Glyph of Icebound Fortitude', - description: 'Your Icebound Fortitude now always grants at least 40% damage reduction, regardless of your defense skill.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_iceboundfortitude.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfIcyTouch]: { + [DeathKnightPrimeGlyph.GlyphOfIcyTouch]: { name: 'Glyph of Icy Touch', description: 'Your Frost Fever disease deals 20% additional damage.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_icetouch.jpg', }, - [DeathKnightMajorGlyph.GlyphOfObliterate]: { + [DeathKnightPrimeGlyph.GlyphOfObliterate]: { name: 'Glyph of Obliterate', - description: 'Increases the damage of your Obliterate ability by 25%.', + description: 'Increases the damage of your Obliterate ability by 20%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_classicon.jpg', }, - [DeathKnightMajorGlyph.GlyphOfPlagueStrike]: { - name: 'Glyph of Plague Strike', - description: 'Your Plague Strike does 20% additional damage.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_empowerruneblade.jpg', + [DeathKnightPrimeGlyph.GlyphOfRaiseDead]: { + name: 'Glyph of Raise Dead', + description: 'Your Ghoul receives an additional 40% of your Strength and 40% of your Stamina.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_animatedead.jpg', }, - [DeathKnightMajorGlyph.GlyphOfRuneStrike]: { + [DeathKnightPrimeGlyph.GlyphOfRuneStrike]: { name: 'Glyph of Rune Strike', description: 'Increases the critical strike chance of your Rune Strike by 10%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_darkconviction.jpg', }, + [DeathKnightPrimeGlyph.GlyphOfScourgeStrike]: { + name: 'Glyph of Scourge Strike', + description: 'Increases the Shadow damage portion of your Scourge Strike by 30%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_scourgestrike.jpg', + }, + }, + majorGlyphs: { + [DeathKnightMajorGlyph.GlyphOfAntiMagicShell]: { + name: 'Glyph of Anti-Magic Shell', + description: 'Increases the duration of your Anti-Magic Shell by 2 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_antimagicshell.jpg', + }, + [DeathKnightMajorGlyph.GlyphOfBloodBoil]: { + name: 'Glyph of Blood Boil', + description: 'Increases the radius of your Blood Boil ability by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_bloodboil.jpg', + }, + [DeathKnightMajorGlyph.GlyphOfBoneShield]: { + name: 'Glyph of Bone Shield', + description: 'Increases your movement speed by 15% while Bone Shield is active. This does not stack with other movement-speed increasing effects.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_deathknight_boneshield.jpg', + }, + [DeathKnightMajorGlyph.GlyphOfChainsOfIce]: { + name: 'Glyph of Chains of Ice', + description: 'Your Chains of Ice also causes 144 to 156 Frost damage, with additional damage depending on your attack power.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_chainsofice.jpg', + }, + [DeathKnightMajorGlyph.GlyphOfDancingRuneWeapon]: { + name: 'Glyph of Dancing Rune Weapon', + description: 'Increases your threat generation by 50% while your Dancing Rune Weapon is active.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_sword_07.jpg', + }, + [DeathKnightMajorGlyph.GlyphOfDarkSuccor]: { + name: 'Glyph of Dark Succor', + description: 'Your next Death Strike performed while in Frost or Unholy Presence, within 15 sec after killing an enemy that yields experience or honor, will restore at least 20% of your maximum health.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_butcher2.jpg', + }, + [DeathKnightMajorGlyph.GlyphOfDeathGrip]: { + name: 'Glyph of Death Grip', + description: 'Increases the range of your Death Grip ability by 5 yards.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_strangulate.jpg', + }, + [DeathKnightMajorGlyph.GlyphOfHungeringCold]: { + name: 'Glyph of Hungering Cold', + description: 'Your Hungering Cold ability no longer costs runic power.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_staff_15.jpg', + }, + [DeathKnightMajorGlyph.GlyphOfPestilence]: { + name: 'Glyph of Pestilence', + description: 'Increases the radius of your Pestilence effect by 5 yards.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_plaguecloud.jpg', + }, + [DeathKnightMajorGlyph.GlyphOfPillarOfFrost]: { + name: 'Glyph of Pillar of Frost', + description: 'Empowers your Pillar of Frost, making you immune to all effects that cause loss of control of your character, but also freezing you in place while the ability is active.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_deathknight_pillaroffrost.jpg', + }, [DeathKnightMajorGlyph.GlyphOfRuneTap]: { name: 'Glyph of Rune Tap', - description: 'Your Rune Tap now heals you for an additional 1% of your maximum health, and also heals your party for 10% of their maximum health.', + description: 'Your Rune Tap also heals your party for 5% of their maximum health.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_runetap.jpg', }, - [DeathKnightMajorGlyph.GlyphOfScourgeStrike]: { - name: 'Glyph of Scourge Strike', - description: 'Your Scourge Strike increases the duration of your diseases on the target by 3 sec, up to a maximum of 9 additional seconds.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_scourgestrike.jpg', - }, [DeathKnightMajorGlyph.GlyphOfStrangulate]: { name: 'Glyph of Strangulate', - description: 'Reduces the cooldown of your Strangulate by 20 sec.', + description: 'Increases the Silence duration of your Strangulate ability by 2 sec when used on a target who is casting a spell.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_soulleech_3.jpg', }, - [DeathKnightMajorGlyph.GlyphOfTheGhoul]: { - name: 'Glyph of the Ghoul', - description: 'Your Ghoul receives an additional 40% of your Strength and 40% of your Stamina.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_animatedead.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfUnbreakableArmor]: { - name: 'Glyph of Unbreakable Armor', - description: 'Increases the total armor granted by Unbreakable Armor to 30%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_armor_helm_plate_naxxramas_raidwarrior_c_01.jpg', - }, - [DeathKnightMajorGlyph.GlyphOfUnholyBlight]: { - name: 'Glyph of Unholy Blight', - description: 'Increases the damage done by Unholy Blight by 40%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_contagion.jpg', - }, [DeathKnightMajorGlyph.GlyphOfVampiricBlood]: { name: 'Glyph of Vampiric Blood', - description: 'Increases the duration of your Vampiric Blood by 5 sec.', + description: 'Increases the bonus healing received while your Vampiric Blood is active by an additional 15%, but your Vampiric Blood no longer grants you health.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_lifedrain.jpg', }, }, @@ -151,14 +136,14 @@ export const deathknightGlyphsConfig: GlyphsConfig = { description: 'Your Blood Tap no longer causes damage to you.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_bloodtap.jpg', }, - [DeathKnightMinorGlyph.GlyphOfCorpseExplosion]: { - name: 'Glyph of Corpse Explosion', - description: 'Increases the radius of effect on Corpse Explosion by 5 yards.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_creature_disease_02.jpg', + [DeathKnightMinorGlyph.GlyphOfDeathGate]: { + name: 'Glyph of Death Gate', + description: 'Reduces the cast time of your Death Gate spell by 60%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_arcane_teleportundercity.jpg', }, [DeathKnightMinorGlyph.GlyphOfDeathSEmbrace]: { - name: "Glyph of Death's Embrace", - description: 'Your Death Coil refunds 20 runic power when used to heal.', + name: 'Glyph of Death\'s Embrace', + description: 'Your Death Coil refunds 20 Runic Power when used to heal an allied minion.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_deathcoil.jpg', }, [DeathKnightMinorGlyph.GlyphOfHornOfWinter]: { @@ -166,15 +151,15 @@ export const deathknightGlyphsConfig: GlyphsConfig = { description: 'Increases the duration of your Horn of Winter ability by 1 min.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_horn_02.jpg', }, - [DeathKnightMinorGlyph.GlyphOfPestilence]: { - name: 'Glyph of Pestilence', - description: 'Increases the radius of your Pestilence effect by 5 yards.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_plaguecloud.jpg', + [DeathKnightMinorGlyph.GlyphOfPathOfFrost]: { + name: 'Glyph of Path of Frost', + description: 'Your Path of Frost ability allows you to fall from a greater distance without suffering damage.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_pathoffrost.jpg', }, - [DeathKnightMinorGlyph.GlyphOfRaiseDead]: { - name: 'Glyph of Raise Dead', - description: 'Your Raise Dead spell no longer requires a reagent.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_animatedead.jpg', + [DeathKnightMinorGlyph.GlyphOfResilientGrip]: { + name: 'Glyph of Resilient Grip', + description: 'When your Death Grip ability fails because its target is immune, its cooldown is reset.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_deathknight_strangulate.jpg', }, }, -}; +}; \ No newline at end of file diff --git a/ui/core/talents/druid.ts b/ui/core/talents/druid.ts index cf9f2c9634..8baa8346ca 100644 --- a/ui/core/talents/druid.ts +++ b/ui/core/talents/druid.ts @@ -1,174 +1,189 @@ -import { DruidTalents, DruidMajorGlyph, DruidMinorGlyph } from '../proto/druid.js'; - +import {DruidMajorGlyph, DruidMinorGlyph,DruidPrimeGlyph, DruidTalents } from '../proto/druid.js'; import { GlyphsConfig, } from './glyphs_picker.js'; -import { TalentsConfig, newTalentsConfig } from './talents_picker.js'; - +import { newTalentsConfig,TalentsConfig } from './talents_picker.js'; import DruidTalentsJson from './trees/druid.json'; export const druidTalentsConfig: TalentsConfig = newTalentsConfig(DruidTalentsJson); export const druidGlyphsConfig: GlyphsConfig = { + primeGlyphs: { + [DruidPrimeGlyph.GlyphOfBerserk]: { + name: 'Glyph of Berserk', + description: 'Increases the duration of Berserk by 10 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_berserk.jpg', + }, + [DruidPrimeGlyph.GlyphOfBloodletting]: { + name: 'Glyph of Bloodletting', + description: 'Each time you Shred or Mangle in Cat Form, the duration of your Rip on the target is extended by 2 sec, up to a maximum of 6 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_vampiricaura.jpg', + }, + [DruidPrimeGlyph.GlyphOfInsectSwarm]: { + name: 'Glyph of Insect Swarm', + description: 'Increases the damage of your Insect Swarm ability by 30%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_insectswarm.jpg', + }, + [DruidPrimeGlyph.GlyphOfLacerate]: { + name: 'Glyph of Lacerate', + description: 'Increases the critical strike chance of your Lacerate ability by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_lacerate.jpg', + }, + [DruidPrimeGlyph.GlyphOfLifebloom]: { + name: 'Glyph of Lifebloom', + description: 'Increases the critical effect chance of your Lifebloom by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_herb_felblossom.jpg', + }, + [DruidPrimeGlyph.GlyphOfMangle]: { + name: 'Glyph of Mangle', + description: 'Increases the damage done by Mangle by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_mangle2.jpg', + }, + [DruidPrimeGlyph.GlyphOfMoonfire]: { + name: 'Glyph of Moonfire', + description: 'Increases the periodic damage of your Moonfire ability by 20%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_starfall.jpg', + }, + [DruidPrimeGlyph.GlyphOfRegrowth]: { + name: 'Glyph of Regrowth', + description: 'Your Regrowth heal-over-time will automatically refresh its duration on targets at or below 50% health.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_resistnature.jpg', + }, + [DruidPrimeGlyph.GlyphOfRejuvenation]: { + name: 'Glyph of Rejuvenation', + description: 'Increases the healing done by your Rejuvenation by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_rejuvenation.jpg', + }, + [DruidPrimeGlyph.GlyphOfRip]: { + name: 'Glyph of Rip', + description: 'Increases the periodic damage of your Rip by 15%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_ghoulfrenzy.jpg', + }, + [DruidPrimeGlyph.GlyphOfSavageRoar]: { + name: 'Glyph of Savage Roar', + description: 'Your Savage Roar ability grants an additional 5% bonus damage done.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_skinteeth.jpg', + }, + [DruidPrimeGlyph.GlyphOfStarfire]: { + name: 'Glyph of Starfire', + description: 'Your Starfire ability increases the duration of your Moonfire effect on the target by 3 sec, up to a maximum of 9 additional seconds. Only functions on the target with your most recently applied Moonfire.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_arcane_starfire.jpg', + }, + [DruidPrimeGlyph.GlyphOfStarsurge]: { + name: 'Glyph of Starsurge', + description: 'When your Starsurge deals damage, the cooldown remaining on your Starfall is reduced by 5 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_arcane_arcane03.jpg', + }, + [DruidPrimeGlyph.GlyphOfSwiftmend]: { + name: 'Glyph of Swiftmend', + description: 'Your Swiftmend ability no longer consumes a Rejuvenation or Regrowth effect from the target.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_relics_idolofrejuvenation.jpg', + }, + [DruidPrimeGlyph.GlyphOfTigerSFury]: { + name: 'Glyph of Tiger\'s Fury', + description: 'Reduces the cooldown of your Tiger\'s Fury ability by 3 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mount_jungletiger.jpg', + }, + [DruidPrimeGlyph.GlyphOfWrath]: { + name: 'Glyph of Wrath', + description: 'Increases the damage done by your Wrath by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_wrathv2.jpg', + }, + }, majorGlyphs: { [DruidMajorGlyph.GlyphOfBarkskin]: { name: 'Glyph of Barkskin', description: 'Reduces the chance you\'ll be critically hit by 25% while Barkskin is active.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_stoneclawtotem.jpg', }, - [DruidMajorGlyph.GlyphOfBerserk]: { - name: 'Glyph of Berserk', - description: 'Increases the duration of Berserk by 5 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_berserk.jpg', - }, - [DruidMajorGlyph.GlyphOfClaw]: { - name: 'Glyph of Claw', - description: 'Reduces the energy cost of your Claw ability by 5.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_rake.jpg', - }, [DruidMajorGlyph.GlyphOfEntanglingRoots]: { name: 'Glyph of Entangling Roots', - description: 'Increases the damage your Entangling Roots victims can take before the Entangling Roots automatically breaks by 20%.', + description: 'Reduces the cast time of your Entangling Roots by 0.2 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_stranglevines.jpg', }, + [DruidMajorGlyph.GlyphOfFaerieFire]: { + name: 'Glyph of Faerie Fire', + description: 'Increases the range of your Faerie Fire and Feral Faerie Fire abilities by 10 yds.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_faeriefire.jpg', + }, + [DruidMajorGlyph.GlyphOfFeralCharge]: { + name: 'Glyph of Feral Charge', + description: 'Reduces the cooldown of your Feral Charge (Cat) ability by 2 sec and the cooldown of your Feral Charge (Bear) ability by 1 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_pet_bear.jpg', + }, + [DruidMajorGlyph.GlyphOfFerociousBite]: { + name: 'Glyph of Ferocious Bite', + description: 'Your Ferocious Bite ability heals you for 1% of your maximum health for each 10 energy used.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_ferociousbite.jpg', + }, [DruidMajorGlyph.GlyphOfFocus]: { name: 'Glyph of Focus', description: 'Increases the damage done by Starfall by 10%, but decreases its radius by 50%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_starfall.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_arcane_arcanepotency.jpg', }, [DruidMajorGlyph.GlyphOfFrenziedRegeneration]: { name: 'Glyph of Frenzied Regeneration', - description: 'While Frenzied Regeneration is active, healing effects on you are 20% more powerful.', + description: 'While Frenzied Regeneration is active, healing effects on you are 30% more powerful but causes your Frenzied Regeneration to no longer convert rage into health.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_bullrush.jpg', }, - [DruidMajorGlyph.GlyphOfGrowling]: { - name: 'Glyph of Growling', - description: 'Increases the chance for your Growl ability to work successfully by 8%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_physical_taunt.jpg', - }, [DruidMajorGlyph.GlyphOfHealingTouch]: { name: 'Glyph of Healing Touch', - description: 'Decreases the cast time of Healing Touch by 1.5 sec, the mana cost by 25%, and the amount healed by 50%.', + description: 'When you cast Healing Touch, the cooldown on your Nature\'s Swiftness is reduced by 10 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_healingtouch.jpg', }, [DruidMajorGlyph.GlyphOfHurricane]: { name: 'Glyph of Hurricane', - description: 'Your Hurricane ability now also slows the movement speed of its victims by 20%.', + description: 'Your Hurricane ability now also slows the movement speed of its victims by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_cyclone.jpg', }, [DruidMajorGlyph.GlyphOfInnervate]: { name: 'Glyph of Innervate', - description: 'Innervate now grants the caster 45% of his base mana pool over 10 sec in addition to the normal effects of Innervate.', + description: 'When Innervate is cast on a friendly target other than the caster, the caster will gain 10% of maximum mana over 10 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_lightning.jpg', }, - [DruidMajorGlyph.GlyphOfInsectSwarm]: { - name: 'Glyph of Insect Swarm', - description: 'Increases the damage of your Insect Swarm ability by 30%, but it no longer affects your victim\'s chance to hit.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_insectswarm.jpg', - }, - [DruidMajorGlyph.GlyphOfLifebloom]: { - name: 'Glyph of Lifebloom', - description: 'Increases the duration of Lifebloom by 1 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_herb_felblossom.jpg', - }, - [DruidMajorGlyph.GlyphOfMangle]: { - name: 'Glyph of Mangle', - description: 'Increases the damage done by Mangle by 10%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_mangle2.jpg', - }, [DruidMajorGlyph.GlyphOfMaul]: { name: 'Glyph of Maul', - description: 'Your Maul ability now hits 1 additional target.', + description: 'Your Maul ability now hits 1 additional target for 50% damage.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_maul.jpg', }, [DruidMajorGlyph.GlyphOfMonsoon]: { name: 'Glyph of Monsoon', description: 'Reduces the cooldown of your Typhoon spell by 3 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_typhoon.jpg', - }, - [DruidMajorGlyph.GlyphOfMoonfire]: { - name: 'Glyph of Moonfire', - description: 'Increases the periodic damage of your Moonfire ability by 75%, but initial damage is decreased by 90%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_starfall.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_riptide.jpg', }, [DruidMajorGlyph.GlyphOfOmenOfClarity]: { name: 'Glyph of Omen of Clarity', description: 'Your Omen of Clarity talent has a 100% chance to be triggered by successfully casting Faerie Fire (Feral). Does not trigger on players or player-controlled pets.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_faeriefire.jpg', - }, - [DruidMajorGlyph.GlyphOfNourish]: { - name: 'Glyph of Nourish', - description: 'Your Nourish heals an additional 6% for each of your heal over time effects present on the target.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_nourish.jpg', - }, - [DruidMajorGlyph.GlyphOfRake]: { - name: 'Glyph of Rake', - description: 'Your Rake ability prevents targets from fleeing.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_disembowel.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_questionmark.jpg', }, - [DruidMajorGlyph.GlyphOfRapidRejuvenation]: { - name: 'Glyph of Rapid Rejuvenation', - description: 'Your haste now reduces the time between the periodic healing ticks of your Rejuvenation spell.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_rejuvenation.jpg', + [DruidMajorGlyph.GlyphOfPounce]: { + name: 'Glyph of Pounce', + description: 'Increases the range of your Pounce by 3 yards.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_supriseattack.jpg', }, [DruidMajorGlyph.GlyphOfRebirth]: { name: 'Glyph of Rebirth', description: 'Players resurrected by Rebirth are returned to life with 100% health.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_reincarnation.jpg', }, - [DruidMajorGlyph.GlyphOfRegrowth]: { - name: 'Glyph of Regrowth', - description: 'Increases the healing of your Regrowth spell by 20% if your Regrowth effect is still active on the target.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_resistnature.jpg', - }, - [DruidMajorGlyph.GlyphOfRejuvenation]: { - name: 'Glyph of Rejuvenation', - description: 'While your Rejuvenation targets are below 50% health, you will heal them for an additional 50% health.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_rejuvenation.jpg', - }, - [DruidMajorGlyph.GlyphOfRip]: { - name: 'Glyph of Rip', - description: 'Increases the duration of your Rip ability by 4 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_ghoulfrenzy.jpg', - }, - [DruidMajorGlyph.GlyphOfSavageRoar]: { - name: 'Glyph of Savage Roar', - description: 'Your Savage Roar ability grants an additional 3% bonus damage done.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_skinteeth.jpg', - }, - [DruidMajorGlyph.GlyphOfShred]: { - name: 'Glyph of Shred', - description: 'Each time you Shred, the duration of your Rip on the target is extended 2 sec, up to a maximum of 6 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_vampiricaura.jpg', + [DruidMajorGlyph.GlyphOfSolarBeam]: { + name: 'Glyph of Solar Beam', + description: 'Increases the duration of your Solar Beam silence effect by 5 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_vehicle_sonicshockwave.jpg', }, [DruidMajorGlyph.GlyphOfStarfall]: { name: 'Glyph of Starfall', description: 'Reduces the cooldown of Starfall by 30 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_starfall.jpg', }, - [DruidMajorGlyph.GlyphOfStarfire]: { - name: 'Glyph of Starfire', - description: 'Your Starfire ability increases the duration of your Moonfire effect on the target by 3 sec, up to a maximum of 9 additional seconds.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_arcane_starfire.jpg', - }, - [DruidMajorGlyph.GlyphOfSurvivalInstincts]: { - name: 'Glyph of Survival Instincts', - description: 'Your Survival Instincts ability grants an additional 15% of your maximum health.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_tigersroar.jpg', - }, - [DruidMajorGlyph.GlyphOfSwiftmend]: { - name: 'Glyph of Swiftmend', - description: 'Your Swiftmend ability no longer consumes a Rejuvenation or Regrowth effect from the target.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_relics_idolofrejuvenation.jpg', + [DruidMajorGlyph.GlyphOfThorns]: { + name: 'Glyph of Thorns', + description: 'Reduces the cooldown of your Thorns spell by 20 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_thorns.jpg', }, [DruidMajorGlyph.GlyphOfWildGrowth]: { name: 'Glyph of Wild Growth', - description: 'Wild Growth can affect 1 additional target.', + description: 'Wild Growth can affect 1 additional target, but its cooldown is increased by 2 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_flourish.jpg', }, - [DruidMajorGlyph.GlyphOfWrath]: { - name: 'Glyph of Wrath', - description: 'Reduces the pushback suffered from damaging attacks while casting your Wrath spell by 50%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_abolishmagic.jpg', - }, }, minorGlyphs: { [DruidMinorGlyph.GlyphOfAquaticForm]: { @@ -186,15 +201,15 @@ export const druidGlyphsConfig: GlyphsConfig = { description: 'Reduces the cooldown of your Dash ability by 20%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_dash.jpg', }, - [DruidMinorGlyph.GlyphOfTheWild]: { - name: 'Glyph of the Wild', - description: 'Mana cost of your Mark of the Wild and Gift of the Wild spells reduced by 50%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_regeneration.jpg', + [DruidMinorGlyph.GlyphOfMarkOfTheWild]: { + name: 'Glyph of Mark of the Wild', + description: 'Mana cost of your Mark of the Wild reduced by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_giftofthewild.jpg', }, - [DruidMinorGlyph.GlyphOfThorns]: { - name: 'Glyph of Thorns', - description: 'Increases the duration of your Thorns ability by 50 min when cast on yourself.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_thorns.jpg', + [DruidMinorGlyph.GlyphOfTheTreant]: { + name: 'Glyph of the Treant', + description: 'Your Tree of Life Form now resembles a Treant.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_treeoflife.jpg', }, [DruidMinorGlyph.GlyphOfTyphoon]: { name: 'Glyph of Typhoon', @@ -204,7 +219,7 @@ export const druidGlyphsConfig: GlyphsConfig = { [DruidMinorGlyph.GlyphOfUnburdenedRebirth]: { name: 'Glyph of Unburdened Rebirth', description: 'Your Rebirth spell no longer requires a reagent.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_reincarnation.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_wispsplodegreen.jpg', }, }, -}; +}; \ No newline at end of file diff --git a/ui/core/talents/factory.ts b/ui/core/talents/factory.ts index 1d71873f8c..fd619a08a9 100644 --- a/ui/core/talents/factory.ts +++ b/ui/core/talents/factory.ts @@ -1,7 +1,7 @@ import { PlayerSpec } from '../player_spec.js'; import { Class, Spec } from '../proto/common.js'; import { SpecTalents, specTypeFunctions } from '../proto_utils/utils.js'; -import { deathknightGlyphsConfig, deathknightTalentsConfig } from './death_knight.js'; +import { deathKnightGlyphsConfig, deathKnightTalentsConfig } from './death_knight.js'; import { druidGlyphsConfig, druidTalentsConfig } from './druid.js'; import { GlyphsConfig } from './glyphs_picker.js'; import { hunterGlyphsConfig, hunterTalentsConfig } from './hunter.js'; @@ -16,7 +16,7 @@ import { warriorGlyphsConfig, warriorTalentsConfig } from './warrior.js'; export const classTalentsConfig: Record> = { [Class.ClassUnknown]: [], - [Class.ClassDeathKnight]: deathknightTalentsConfig, + [Class.ClassDeathKnight]: deathKnightTalentsConfig, [Class.ClassDruid]: druidTalentsConfig, [Class.ClassShaman]: shamanTalentsConfig, [Class.ClassHunter]: hunterTalentsConfig, @@ -29,8 +29,8 @@ export const classTalentsConfig: Record> = { }; export const classGlyphsConfig: Record = { - [Class.ClassUnknown]: { majorGlyphs: [], minorGlyphs: [] }, - [Class.ClassDeathKnight]: deathknightGlyphsConfig, + [Class.ClassUnknown]: { primeGlyphs: [], majorGlyphs: [], minorGlyphs: [] }, + [Class.ClassDeathKnight]: deathKnightGlyphsConfig, [Class.ClassDruid]: druidGlyphsConfig, [Class.ClassShaman]: shamanGlyphsConfig, [Class.ClassHunter]: hunterGlyphsConfig, diff --git a/ui/core/talents/glyphs_picker.tsx b/ui/core/talents/glyphs_picker.tsx index 69f41bc86a..c81eed4013 100644 --- a/ui/core/talents/glyphs_picker.tsx +++ b/ui/core/talents/glyphs_picker.tsx @@ -1,19 +1,17 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars import { element } from 'tsx-vanilla'; -import { Glyphs } from '../proto/common.js'; -import { ItemQuality } from '../proto/common.js'; -import { ActionId } from '../proto_utils/action_id.js'; +import { BaseModal } from '../components/base_modal.js'; +import { Component } from '../components/component.js'; +import { ContentBlock } from '../components/content_block.js'; +import { Input } from '../components/input.js'; import { setItemQualityCssClass } from '../css_utils.js'; import { Player } from '../player.js'; +import { Glyphs , ItemQuality } from '../proto/common.js'; +import { ActionId } from '../proto_utils/action_id.js'; import { EventID, TypedEvent } from '../typed_event.js'; import { stringComparator } from '../utils.js'; -import { Component } from '../components/component.js'; -import { Input } from '../components/input.js'; -import { BaseModal } from '../components/base_modal.js'; -import { ContentBlock } from '../components/content_block.js'; - export type GlyphConfig = { name: string, description: string, @@ -21,6 +19,7 @@ export type GlyphConfig = { }; export type GlyphsConfig = { + primeGlyphs: Record, majorGlyphs: Record, minorGlyphs: Record, }; @@ -44,6 +43,7 @@ const emptyGlyphData: GlyphData = { export class GlyphsPicker extends Component { private readonly glyphsConfig: GlyphsConfig; + primeGlyphPickers: Array = []; majorGlyphPickers: Array = []; minorGlyphPickers: Array = []; @@ -55,25 +55,38 @@ export class GlyphsPicker extends Component {
Glyphs
) + const primeGlyphs = Object.keys(glyphsConfig.primeGlyphs).map(idStr => Number(idStr)); const majorGlyphs = Object.keys(glyphsConfig.majorGlyphs).map(idStr => Number(idStr)); const minorGlyphs = Object.keys(glyphsConfig.minorGlyphs).map(idStr => Number(idStr)); + const primeGlyphsData = primeGlyphs.map(glyph => this.getGlyphData(glyph)); const majorGlyphsData = majorGlyphs.map(glyph => this.getGlyphData(glyph)); const minorGlyphsData = minorGlyphs.map(glyph => this.getGlyphData(glyph)); + primeGlyphsData.sort((a, b) => stringComparator(a.name, b.name)); majorGlyphsData.sort((a, b) => stringComparator(a.name, b.name)); minorGlyphsData.sort((a, b) => stringComparator(a.name, b.name)); + const primeGlyphsBlock = new ContentBlock(this.rootElem, 'major-glyphs', { + header: { title: 'Major', extraCssClasses: ['border-0', 'mb-1'] } + }); + const majorGlyphsBlock = new ContentBlock(this.rootElem, 'major-glyphs', { header: { title: 'Major', extraCssClasses: ['border-0', 'mb-1'] } }); + const minorGlyphsBlock = new ContentBlock(this.rootElem, 'minor-glyphs', { header: { title: 'Minor', extraCssClasses: ['border-0', 'mb-1'] } }); + this.primeGlyphPickers = (['prime1', 'prime2', 'prime3'] as Array).map(glyphField => { + return new GlyphPicker(primeGlyphsBlock.bodyElement, player, primeGlyphsData, glyphField, true) + }); + this.majorGlyphPickers = (['major1', 'major2', 'major3'] as Array).map(glyphField => { return new GlyphPicker(majorGlyphsBlock.bodyElement, player, majorGlyphsData, glyphField, true) }); + this.minorGlyphPickers = (['minor1', 'minor2', 'minor3'] as Array).map(glyphField => { return new GlyphPicker(minorGlyphsBlock.bodyElement, player, minorGlyphsData, glyphField, false) }); @@ -215,7 +228,7 @@ class GlyphSelectorModal extends BaseModal { const searchQuery = searchInput.value.toLowerCase().split(" "); const name = listItemData.name.toLowerCase(); - var include = true; + let include = true; searchQuery.forEach(v => { if (!name.includes(v)) include = false; diff --git a/ui/core/talents/hunter.ts b/ui/core/talents/hunter.ts index ff493ea317..aea076709a 100644 --- a/ui/core/talents/hunter.ts +++ b/ui/core/talents/hunter.ts @@ -1,38 +1,73 @@ -import { HunterTalents, HunterMajorGlyph, HunterMinorGlyph, HunterPetTalents } from '../proto/hunter.js'; - +import { HunterMajorGlyph, HunterMinorGlyph, HunterPetTalents, HunterPrimeGlyph, HunterTalents } from '../proto/hunter.js'; import { GlyphsConfig } from './glyphs_picker.js'; -import { TalentsConfig, newTalentsConfig } from './talents_picker.js'; - +import { newTalentsConfig,TalentsConfig } from './talents_picker.js'; import HunterTalentJson from './trees/hunter.json'; export const hunterTalentsConfig: TalentsConfig = newTalentsConfig(HunterTalentJson); export const hunterGlyphsConfig: GlyphsConfig = { - majorGlyphs: { - [HunterMajorGlyph.GlyphOfAimedShot]: { + primeGlyphs: { + [HunterPrimeGlyph.GlyphOfAimedShot]: { name: 'Glyph of Aimed Shot', - description: 'Reduces the cooldown of your Aimed Shot ability by 2 sec.', + description: 'When you critically hit with Aimed Shot, you instantly gain 5 Focus.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_spear_07.jpg', }, - [HunterMajorGlyph.GlyphOfArcaneShot]: { + [HunterPrimeGlyph.GlyphOfArcaneShot]: { name: 'Glyph of Arcane Shot', - description: 'Your Arcane Shot refunds 20% of its mana cost if the target has one of your Stings active on it.', + description: 'Your Arcane Shot deals 12% more damage.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_impalingbolt.jpg', }, - [HunterMajorGlyph.GlyphOfAspectOfTheViper]: { - name: 'Glyph of Aspect of the Viper', - description: 'Increases the amount of mana gained from attacks while Aspect of the Viper is active by 10%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_aspectoftheviper.jpg', + [HunterPrimeGlyph.GlyphOfChimeraShot]: { + name: 'Glyph of Chimera Shot', + description: 'Reduces the cooldown of Chimera Shot by 1 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_chimerashot2.jpg', + }, + [HunterPrimeGlyph.GlyphOfDazzledPrey]: { + name: 'Glyph of Dazzled Prey', + description: 'Your Steady Shot and Cobra Shot abilities generate an additional 2 Focus on targets afflicted by a daze effect.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_cheatdeath.jpg', + }, + [HunterPrimeGlyph.GlyphOfExplosiveShot]: { + name: 'Glyph of Explosive Shot', + description: 'Increases the critical strike chance of Explosive Shot by 6%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_explosiveshot.jpg', + }, + [HunterPrimeGlyph.GlyphOfKillCommand]: { + name: 'Glyph of Kill Command', + description: 'Reduces the Focus cost of your Kill Command by 3.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_killcommand.jpg', + }, + [HunterPrimeGlyph.GlyphOfKillShot]: { + name: 'Glyph of Kill Shot', + description: 'If the damage from your Kill Shot fails to kill a target at or below 20% health, your Kill Shot\'s cooldown is instantly reset. This effect has a 6 sec cooldown.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_assassinate2.jpg', + }, + [HunterPrimeGlyph.GlyphOfRapidFire]: { + name: 'Glyph of Rapid Fire', + description: 'Increases the haste from Rapid Fire by an additional 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_runningshot.jpg', + }, + [HunterPrimeGlyph.GlyphOfSerpentSting]: { + name: 'Glyph of Serpent Sting', + description: 'Increases the periodic critical strike chance of your Serpent Sting by 6%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_quickshot.jpg', }, + [HunterPrimeGlyph.GlyphOfSteadyShot]: { + name: 'Glyph of Steady Shot', + description: 'Increases the damage dealt by Steady Shot by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_steadyshot.jpg', + }, + }, + majorGlyphs: { [HunterMajorGlyph.GlyphOfBestialWrath]: { name: 'Glyph of Bestial Wrath', description: 'Decreases the cooldown of Bestial Wrath by 20 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_ferociousbite.jpg', }, - [HunterMajorGlyph.GlyphOfChimeraShot]: { - name: 'Glyph of Chimera Shot', - description: 'Reduces the cooldown of Chimera Shot by 1 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_chimerashot2.jpg', + [HunterMajorGlyph.GlyphOfConcussiveShot]: { + name: 'Glyph of Concussive Shot', + description: 'Your Concussive Shot also limits the maximum run speed of your target.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_stun.jpg', }, [HunterMajorGlyph.GlyphOfDeterrence]: { name: 'Glyph of Deterrence', @@ -44,59 +79,39 @@ export const hunterGlyphsConfig: GlyphsConfig = { description: 'Decreases the cooldown of Disengage by 5 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_feint.jpg', }, - [HunterMajorGlyph.GlyphOfExplosiveShot]: { - name: 'Glyph of Explosive Shot', - description: 'Increases the critical strike chance of Explosive Shot by 4%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_explosiveshot.jpg', - }, - [HunterMajorGlyph.GlyphOfExplosiveTrap]: { - name: 'Glyph of Explosive Trap', - description: 'The periodic damage from your Explosive Trap can now be critical strikes.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_selfdestruct.jpg', - }, [HunterMajorGlyph.GlyphOfFreezingTrap]: { name: 'Glyph of Freezing Trap', - description: 'When your Freezing Trap breaks, the victim\'s movement speed is reduced by 30% for 4 sec.', + description: 'When your Freezing Trap breaks, the victim\'s movement speed is reduced by 70% for 4 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_chainsofice.jpg', }, - [HunterMajorGlyph.GlyphOfFrostTrap]: { - name: 'Glyph of Frost Trap', - description: 'Increases the radius of the effect from your Frost Trap by 2 yards.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_freezingbreath.jpg', - }, - [HunterMajorGlyph.GlyphOfHuntersMark]: { - name: 'Glyph of Hunter\'s Mark', - description: 'Increases the attack power bonus of your Hunter\'s Mark by 20%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_snipershot.jpg', + [HunterMajorGlyph.GlyphOfIceTrap]: { + name: 'Glyph of Ice Trap', + description: 'Increases the radius of the effect from your Ice Trap by 2 yards.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostnova.jpg', }, [HunterMajorGlyph.GlyphOfImmolationTrap]: { name: 'Glyph of Immolation Trap', - description: 'Decreases the duration of the effect from your Immolation Trap by 6 sec., but damage while active is increased by 100%.', + description: 'Decreases the duration of the effect from your Immolation Trap by 6 sec, but damage while active is increased by 100%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_flameshock.jpg', }, - [HunterMajorGlyph.GlyphOfKillShot]: { - name: 'Glyph of Kill Shot', - description: 'Reduces the cooldown of Kill Shot by 6 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_assassinate2.jpg', + [HunterMajorGlyph.GlyphOfMasterSCall]: { + name: 'Glyph of Master\'s Call', + description: 'Increases the duration of your Master\'s Call by 4 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_masterscall.jpg', }, [HunterMajorGlyph.GlyphOfMending]: { name: 'Glyph of Mending', - description: 'Increases the healing done by your Mend Pet ability by 40%.', + description: 'Increases the total amount of healing done by your Mend Pet ability by 60%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_mendpet.jpg', }, - [HunterMajorGlyph.GlyphOfMultiShot]: { - name: 'Glyph of Multi-Shot', - description: 'Decreases the cooldown of Multi-Shot by 1 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_upgrademoonglaive.jpg', - }, - [HunterMajorGlyph.GlyphOfRapidFire]: { - name: 'Glyph of Rapid Fire', - description: 'Increases the haste from Rapid Fire by an additional 8%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_runningshot.jpg', + [HunterMajorGlyph.GlyphOfMisdirection]: { + name: 'Glyph of Misdirection', + description: 'When you use Misdirection on your pet, the cooldown on your Misdirection is reset.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_misdirection.jpg', }, [HunterMajorGlyph.GlyphOfRaptorStrike]: { name: 'Glyph of Raptor Strike', - description: 'Reduces damage taken by 20% for 3 sec after using Raptor Strike.', + description: 'Reduces damage taken by 20% for 5 sec after using Raptor Strike.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_meleedamage.jpg', }, [HunterMajorGlyph.GlyphOfScatterShot]: { @@ -104,40 +119,20 @@ export const hunterGlyphsConfig: GlyphsConfig = { description: 'Increases the range of Scatter Shot by 3 yards.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_golemstormbolt.jpg', }, - [HunterMajorGlyph.GlyphOfSerpentSting]: { - name: 'Glyph of Serpent Sting', - description: 'Increases the duration of your Serpent Sting by 6 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_quickshot.jpg', + [HunterMajorGlyph.GlyphOfSilencingShot]: { + name: 'Glyph of Silencing Shot', + description: 'When you successfully silence an enemy\'s spell cast with Silencing Shot, you instantly gain 10 Focus.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_theblackarrow.jpg', }, [HunterMajorGlyph.GlyphOfSnakeTrap]: { name: 'Glyph of Snake Trap', description: 'Snakes from your Snake Trap take 90% reduced damage from area of effect spells.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_snaketrap.jpg', }, - [HunterMajorGlyph.GlyphOfSteadyShot]: { - name: 'Glyph of Steady Shot', - description: 'Increases the damage dealt by Steady Shot by 10% when your target is afflicted with Serpent Sting.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_steadyshot.jpg', - }, - [HunterMajorGlyph.GlyphOfTheBeast]: { - name: 'Glyph of the Beast', - description: 'Increases the attack power bonus of Aspect of the Beast for you and your pet by an additional 2%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mount_pinktiger.jpg', - }, - [HunterMajorGlyph.GlyphOfTheHawk]: { - name: 'Glyph of the Hawk', - description: 'Increases the haste bonus of the Improved Aspect of the Hawk effect by an additional 6%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_ravenform.jpg', - }, - [HunterMajorGlyph.GlyphOfTrueshotAura]: { - name: 'Glyph of Trueshot Aura', - description: 'While your Trueshot Aura is active, you have 10% increased critical strike chance on your Aimed Shot.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_trueshot.jpg', - }, - [HunterMajorGlyph.GlyphOfVolley]: { - name: 'Glyph of Volley', - description: 'Decreases the mana cost of Volley by 20%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_marksmanship.jpg', + [HunterMajorGlyph.GlyphOfTrapLauncher]: { + name: 'Glyph of Trap Launcher', + description: 'Reduces the Focus cost of Trap Launcher by 10.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_traplauncher.jpg', }, [HunterMajorGlyph.GlyphOfWyvernSting]: { name: 'Glyph of Wyvern Sting', @@ -146,20 +141,20 @@ export const hunterGlyphsConfig: GlyphsConfig = { }, }, minorGlyphs: { + [HunterMinorGlyph.GlyphOfAspectOfThePack]: { + name: 'Glyph of Aspect of the Pack', + description: 'Increases the range of your Aspect of the Pack ability by 15 yards.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mount_whitetiger.jpg', + }, [HunterMinorGlyph.GlyphOfFeignDeath]: { name: 'Glyph of Feign Death', description: 'Reduces the cooldown of your Feign Death spell by 5 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_feigndeath.jpg', }, - [HunterMinorGlyph.GlyphOfMendPet]: { - name: 'Glyph of Mend Pet', - description: 'Your Mend Pet spell increases your pet\'s happiness slightly.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_mendpet.jpg', - }, - [HunterMinorGlyph.GlyphOfPossessedStrength]: { - name: 'Glyph of Possessed Strength', - description: 'Increases the damage your pet inflicts while using Eyes of the Beast by 50%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_eyeoftheowl.jpg', + [HunterMinorGlyph.GlyphOfLesserProportion]: { + name: 'Glyph of Lesser Proportion', + description: 'Slightly reduces the size of your pet.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_bestialdiscipline.jpg', }, [HunterMinorGlyph.GlyphOfRevivePet]: { name: 'Glyph of Revive Pet', @@ -171,10 +166,5 @@ export const hunterGlyphsConfig: GlyphsConfig = { description: 'Reduces the pushback suffered from damaging attacks while casting Scare Beast by 75%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_druid_cower.jpg', }, - [HunterMinorGlyph.GlyphOfThePack]: { - name: 'Glyph of the Pack', - description: 'Increases the range of your Aspect of the Pack ability by 15 yards.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mount_jungletiger.jpg', - }, }, -}; +}; \ No newline at end of file diff --git a/ui/core/talents/hunter_pet.ts b/ui/core/talents/hunter_pet.ts index 8d60c8c598..f2c95dd8c7 100644 --- a/ui/core/talents/hunter_pet.ts +++ b/ui/core/talents/hunter_pet.ts @@ -231,7 +231,7 @@ export function getPetTalentsConfig(petType: PetType): TalentsConfig = newTalentsConfig(MageTalentJson); export const mageGlyphsConfig: GlyphsConfig = { - majorGlyphs: { - [MageMajorGlyph.GlyphOfArcaneBarrage]: { + primeGlyphs: { + [MagePrimeGlyph.GlyphOfArcaneBarrage]: { name: 'Glyph of Arcane Barrage', - description: 'Reduces the mana cost of Arcane Barrage by 20%.', + description: 'Increases the damage of your Arcane Barrage spell by 4%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_arcanebarrage.jpg', }, - [MageMajorGlyph.GlyphOfArcaneBlast]: { + [MagePrimeGlyph.GlyphOfArcaneBlast]: { name: 'Glyph of Arcane Blast', description: 'Increases the damage from your Arcane Blast buff by 3%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_arcane_blast.jpg', }, - [MageMajorGlyph.GlyphOfArcaneExplosion]: { - name: 'Glyph of Arcane Explosion', - description: 'Reduces mana cost of Arcane Explosion by 10%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_wispsplode.jpg', - }, - [MageMajorGlyph.GlyphOfArcaneMissiles]: { + [MagePrimeGlyph.GlyphOfArcaneMissiles]: { name: 'Glyph of Arcane Missiles', - description: 'Increases the critical strike damage bonus of Arcane Missiles by 25%.', + description: 'Increases the critical strike chance of your Arcane Missiles spell by 5%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_starfall.jpg', }, + [MagePrimeGlyph.GlyphOfConeOfCold]: { + name: 'Glyph of Cone of Cold', + description: 'Increases the damage of your Cone of Cold spell by 25%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_glacier.jpg', + }, + [MagePrimeGlyph.GlyphOfDeepFreeze]: { + name: 'Glyph of Deep Freeze', + description: 'Your Deep Freeze deals 20% additional damage.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_deepfreeze.jpg', + }, + [MagePrimeGlyph.GlyphOfFireball]: { + name: 'Glyph of Fireball', + description: 'Increases the critical strike chance of your Fireball spell by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_flamebolt.jpg', + }, + [MagePrimeGlyph.GlyphOfFrostbolt]: { + name: 'Glyph of Frostbolt', + description: 'Increases the critical strike chance of your Frostbolt spell by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostbolt02.jpg', + }, + [MagePrimeGlyph.GlyphOfFrostfire]: { + name: 'Glyph of Frostfire', + description: 'Increases the damage done by your Frostfire Bolt by 15% and your Frostfire Bolt now deals 3% additional damage over 12 sec, stacking up to 3 times, but no longer reduces the victim\'s movement speed.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_frostfirebolt.jpg', + }, + [MagePrimeGlyph.GlyphOfIceLance]: { + name: 'Glyph of Ice Lance', + description: 'Increases the damage of your Ice Lance spell by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostblast.jpg', + }, + [MagePrimeGlyph.GlyphOfLivingBomb]: { + name: 'Glyph of Living Bomb', + description: 'Increases the damage of your Living Bomb spell by 3%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_livingbomb.jpg', + }, + [MagePrimeGlyph.GlyphOfMageArmor]: { + name: 'Glyph of Mage Armor', + description: 'Your Mage Armor regenerates 20% more mana.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_magearmor.jpg', + }, + [MagePrimeGlyph.GlyphOfMoltenArmor]: { + name: 'Glyph of Molten Armor', + description: 'Your Molten Armor grants an additional 2% spell critical strike chance.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_moltenarmor.jpg', + }, + [MagePrimeGlyph.GlyphOfPyroblast]: { + name: 'Glyph of Pyroblast', + description: 'Increases the critical strike chance of your Pyroblast spell by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_fireball02.jpg', + }, + }, + majorGlyphs: { [MageMajorGlyph.GlyphOfArcanePower]: { name: 'Glyph of Arcane Power', - description: 'Increases the duration of Arcane Power by 3 sec.', + description: 'While Arcane Power is active the global cooldown of your Blink, Mana Shield, and Mirror Image is reduced to zero.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_lightning.jpg', }, + [MageMajorGlyph.GlyphOfBlastWave]: { + name: 'Glyph of Blast Wave', + description: 'Increases the duration of Blast Wave\'s slowing effect by 1 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_excorcism_02.jpg', + }, [MageMajorGlyph.GlyphOfBlink]: { name: 'Glyph of Blink', description: 'Increases the distance you travel with the Blink spell by 5 yards.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_arcane_blink.jpg', }, - [MageMajorGlyph.GlyphOfDeepFreeze]: { - name: 'Glyph of Deep Freeze', - description: 'Increases the range of Deep Freeze by 10 yards.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_deepfreeze.jpg', - }, - [MageMajorGlyph.GlyphOfEternalWater]: { - name: 'Glyph of Eternal Water', - description: 'Your Summon Water Elemental now lasts indefinitely, but your Water Elemental can no longer cast Freeze.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_summonwaterelemental_2.jpg', + [MageMajorGlyph.GlyphOfDragonSBreath]: { + name: 'Glyph of Dragon\'s Breath', + description: 'Reduces the cooldown of your Dragon\'s Breath by 3 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_head_dragon_01.jpg', }, [MageMajorGlyph.GlyphOfEvocation]: { name: 'Glyph of Evocation', - description: 'Your Evocation ability also causes you to regain 60% of your health over its duration.', + description: 'Your Evocation ability also causes you to regain 40% of your health over its duration.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_purge.jpg', }, - [MageMajorGlyph.GlyphOfFireBlast]: { - name: 'Glyph of Fire Blast', - description: 'Increases the critical strike chance of Fire Blast by 50% when the target is stunned or incapacitated.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_fireball.jpg', - }, - [MageMajorGlyph.GlyphOfFireball]: { - name: 'Glyph of Fireball', - description: 'Reduces the casting time of your Fireball spell by 0.15 sec, but removes the damage over time effect.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_flamebolt.jpg', + [MageMajorGlyph.GlyphOfFrostArmor]: { + name: 'Glyph of Frost Armor', + description: 'Your Frost Armor also causes you to regenerate 2% of your maximum mana every 5 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostarmor02.jpg', }, [MageMajorGlyph.GlyphOfFrostNova]: { name: 'Glyph of Frost Nova', description: 'Your Frost Nova targets can take an additional 20% damage before the Frost Nova effect automatically breaks.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostnova.jpg', }, - [MageMajorGlyph.GlyphOfFrostbolt]: { - name: 'Glyph of Frostbolt', - description: 'Increases the damage dealt by Frostbolt by 5%, but removes the slowing effect.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostbolt02.jpg', - }, - [MageMajorGlyph.GlyphOfFrostfire]: { - name: 'Glyph of Frostfire', - description: 'Increases the initial damage dealt by Frostfire Bolt by 2% and its critical strike chance by 2%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_frostfirebolt.jpg', - }, - [MageMajorGlyph.GlyphOfIceArmor]: { - name: 'Glyph of Ice Armor', - description: 'Your Ice Armor and Frost Armor spells grant an additional 50% armor and resistance.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostarmor02.jpg', - }, [MageMajorGlyph.GlyphOfIceBarrier]: { name: 'Glyph of Ice Barrier', description: 'Increases the amount of damage absorbed by your Ice Barrier by 30%.', @@ -94,11 +119,6 @@ export const mageGlyphsConfig: GlyphsConfig = { description: 'Your Frost Nova cooldown is now reset every time you use Ice Block.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frost.jpg', }, - [MageMajorGlyph.GlyphOfIceLance]: { - name: 'Glyph of Ice Lance', - description: 'Your Ice Lance now causes 4 times damage against frozen targets higher level than you instead of triple damage.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostblast.jpg', - }, [MageMajorGlyph.GlyphOfIcyVeins]: { name: 'Glyph of Icy Veins', description: 'Your Icy Veins ability also removes all movement slowing and cast time slowing effects.', @@ -106,90 +126,60 @@ export const mageGlyphsConfig: GlyphsConfig = { }, [MageMajorGlyph.GlyphOfInvisibility]: { name: 'Glyph of Invisibility', - description: 'Increases the duration of the Invisibility effect by 10 sec.', + description: 'Increases your movement speed while Invisible by 40%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_invisibility.jpg', }, - [MageMajorGlyph.GlyphOfLivingBomb]: { - name: 'Glyph of Living Bomb', - description: 'The periodic damage from your Living Bomb can now be critical strikes.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_livingbomb.jpg', - }, - [MageMajorGlyph.GlyphOfMageArmor]: { - name: 'Glyph of Mage Armor', - description: 'Your Mage Armor spell grants an additional 20% mana regeneration while casting.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_magearmor.jpg', - }, - [MageMajorGlyph.GlyphOfManaGem]: { - name: 'Glyph of Mana Gem', - description: 'Increases the mana received from using a mana gem by 40%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_gem_stone_01.jpg', - }, - [MageMajorGlyph.GlyphOfMirrorImage]: { - name: 'Glyph of Mirror Image', - description: 'Your Mirror Image spell now creates a 4th copy.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_magic_lesserinvisibilty.jpg', - }, - [MageMajorGlyph.GlyphOfMoltenArmor]: { - name: 'Glyph of Molten Armor', - description: 'Your Molten Armor grants an additional 20% of your spirit as critical strike rating.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_moltenarmor.jpg', + [MageMajorGlyph.GlyphOfManaShield]: { + name: 'Glyph of Mana Shield', + description: 'Reduces the cooldown of your Mana Shield by 2 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_detectlesserinvisibility.jpg', }, [MageMajorGlyph.GlyphOfPolymorph]: { name: 'Glyph of Polymorph', description: 'Your Polymorph spell also removes all damage over time effects from the target.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_polymorph.jpg', }, - [MageMajorGlyph.GlyphOfRemoveCurse]: { - name: 'Glyph of Remove Curse', - description: 'Your Remove Curse spell also makes the target immune to all curses for 4 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_removecurse.jpg', - }, - [MageMajorGlyph.GlyphOfScorch]: { - name: 'Glyph of Scorch', - description: 'Increases the damage of your Scorch spell by 20%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_soulburn.jpg', - }, - [MageMajorGlyph.GlyphOfWaterElemental]: { - name: 'Glyph of Water Elemental', - description: 'Reduces the cooldown of your Summon Water Elemental spell by 30 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_summonwaterelemental_2.jpg', + [MageMajorGlyph.GlyphOfSlow]: { + name: 'Glyph of Slow', + description: 'Increases the range of your Slow spell by 5 yards.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_slow.jpg', }, }, minorGlyphs: { - [MageMinorGlyph.GlyphOfArcaneIntellect]: { - name: 'Glyph of Arcane Intellect', - description: 'Reduces the mana cost of your Arcane Intellect and Arcane Brilliance spells by 50%.', + [MageMinorGlyph.GlyphOfArcaneBrilliance]: { + name: 'Glyph of Arcane Brilliance', + description: 'Reduces the mana cost of your Arcane Brilliance spell by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_magicalsentry.jpg', }, - [MageMinorGlyph.GlyphOfBlastWave]: { - name: 'Glyph of Blast Wave', - description: 'The mana cost of your Blast Wave spell is reduced by 15%, but it no longer knocks enemies back.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_excorcism_02.jpg', + [MageMinorGlyph.GlyphOfArmors]: { + name: 'Glyph of Armors', + description: 'Increases the duration of your Armor spells by 30 min.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_chillingarmor.jpg', }, - [MageMinorGlyph.GlyphOfFireWard]: { - name: 'Glyph of Fire Ward', - description: 'You have an additional 5% chance to reflect Fire spells while your Fire Ward is active.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_firearmor.jpg', + [MageMinorGlyph.GlyphOfConjuring]: { + name: 'Glyph of Conjuring', + description: 'Reduces the mana cost of your Conjuring spells by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_conjurefoodrank9.jpg', }, - [MageMinorGlyph.GlyphOfFrostArmor]: { - name: 'Glyph of Frost Armor', - description: 'Increases the duration of your Frost Armor and Ice Armor spells by 30 min.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostarmor02.jpg', - }, - [MageMinorGlyph.GlyphOfFrostWard]: { - name: 'Glyph of Frost Ward', - description: 'You have an additional 5% chance to reflect Frost spells while your Frost Ward is active.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostward.jpg', + [MageMinorGlyph.GlyphOfMirrorImage]: { + name: 'Glyph of Mirror Image', + description: 'Your Mirror Images cast Arcane Blast or Fireball instead of Frostbolt depending on your primary talent tree.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_magic_lesserinvisibilty.jpg', }, [MageMinorGlyph.GlyphOfSlowFall]: { name: 'Glyph of Slow Fall', description: 'Your Slow Fall spell no longer requires a reagent.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_magic_featherfall.jpg', }, + [MageMinorGlyph.GlyphOfTheMonkey]: { + name: 'Glyph of the Monkey', + description: 'Your Polymorph: Sheep spell polymorphs the target into a monkey instead.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_aspectofthemonkey.jpg', + }, [MageMinorGlyph.GlyphOfThePenguin]: { name: 'Glyph of the Penguin', description: 'Your Polymorph: Sheep spell polymorphs the target into a penguin instead.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_penguinpet.jpg', }, }, -}; +}; \ No newline at end of file diff --git a/ui/core/talents/paladin.ts b/ui/core/talents/paladin.ts index 02f30580a6..98bc92f121 100644 --- a/ui/core/talents/paladin.ts +++ b/ui/core/talents/paladin.ts @@ -1,190 +1,195 @@ -import { PaladinTalents, PaladinMajorGlyph, PaladinMinorGlyph } from '../proto/paladin.js'; - +import {PaladinMajorGlyph, PaladinMinorGlyph,PaladinPrimeGlyph, PaladinTalents } from '../proto/paladin.js'; import { GlyphsConfig } from './glyphs_picker.js'; -import { TalentsConfig, newTalentsConfig } from './talents_picker.js'; - +import { newTalentsConfig,TalentsConfig } from './talents_picker.js'; import PaladinTalentJson from './trees/paladin.json'; export const paladinTalentsConfig: TalentsConfig = newTalentsConfig(PaladinTalentJson); export const paladinGlyphsConfig: GlyphsConfig = { - majorGlyphs: { - [PaladinMajorGlyph.GlyphOfAvengerSShield]: { - name: 'Glyph of Avenger\'s Shield', - description: 'Your Avenger\'s Shield hits 2 fewer targets, but for 100% more damage.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_avengersshield.jpg', + primeGlyphs: { + [PaladinPrimeGlyph.GlyphOfCrusaderStrike]: { + name: 'Glyph of Crusader Strike', + description: 'Increases the critical strike chance of Crusader Strike by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_crusaderstrike.jpg', + }, + [PaladinPrimeGlyph.GlyphOfDivineFavor]: { + name: 'Glyph of Divine Favor', + description: 'Increases the duration of Divine Favor by 10 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_divineillumination.jpg', + }, + [PaladinPrimeGlyph.GlyphOfExorcism]: { + name: 'Glyph of Exorcism', + description: 'Your Exorcism causes an additional 20% of its damage over 6 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_excorcism_02.jpg', }, - [PaladinMajorGlyph.GlyphOfAvengingWrath]: { - name: 'Glyph of Avenging Wrath', - description: 'Reduces the cooldown of your Hammer of Wrath spell by 50% while Avenging Wrath is active.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_avenginewrath.jpg', + [PaladinPrimeGlyph.GlyphOfHammerOfTheRighteous]: { + name: 'Glyph of Hammer of the Righteous', + description: 'Increases the damage of both the physical and Holy components of Hammer of the Righteous by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_paladin_hammeroftherighteous.jpg', }, + [PaladinPrimeGlyph.GlyphOfHolyShock]: { + name: 'Glyph of Holy Shock', + description: 'Increases the critical effect chance of Holy Shock by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_searinglight.jpg', + }, + [PaladinPrimeGlyph.GlyphOfJudgement]: { + name: 'Glyph of Judgement', + description: 'Your Judgement deals 10% more damage.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_righteousfury.jpg', + }, + [PaladinPrimeGlyph.GlyphOfSealOfInsight]: { + name: 'Glyph of Seal of Insight', + description: 'While Seal of Insight is active, the effect of your healing spells is increased by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_healingaura.jpg', + }, + [PaladinPrimeGlyph.GlyphOfSealOfTruth]: { + name: 'Glyph of Seal of Truth', + description: 'Your Seal of Truth and Seal of Righteousness also grant 10 expertise while active.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_sealofvengeance.jpg', + }, + [PaladinPrimeGlyph.GlyphOfShieldOfTheRighteous]: { + name: 'Glyph of Shield of the Righteous', + description: 'Increases the damage of Shield of the Righteous by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_paladin_shieldofvengeance.jpg', + }, + [PaladinPrimeGlyph.GlyphOfTemplarSVerdict]: { + name: 'Glyph of Templar\'s Verdict', + description: 'Increases the damage of Templar\'s Verdict by 15%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_paladin_templarsverdict.jpg', + }, + [PaladinPrimeGlyph.GlyphOfWordOfGlory]: { + name: 'Glyph of Word of Glory', + description: 'Increases the healing done by Word of Glory by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_helmet_96.jpg', + }, + }, + majorGlyphs: { [PaladinMajorGlyph.GlyphOfBeaconOfLight]: { name: 'Glyph of Beacon of Light', - description: 'Increases the duration of Beacon of Light by 30 sec.', + description: 'Your Beacon of Light costs no mana.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_paladin_beaconoflight.jpg', }, [PaladinMajorGlyph.GlyphOfCleansing]: { name: 'Glyph of Cleansing', - description: 'Reduces the mana cost of your Cleanse and Purify spells by 20%.', + description: 'Reduces the mana cost of your Cleanse by 20%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_purify.jpg', }, [PaladinMajorGlyph.GlyphOfConsecration]: { name: 'Glyph of Consecration', - description: 'Increases the duration and cooldown of Consecration by 2 sec.', + description: 'Increases the duration and cooldown of Consecration by 20%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_innerfire.jpg', }, - [PaladinMajorGlyph.GlyphOfCrusaderStrike]: { - name: 'Glyph of Crusader Strike', - description: 'Reduces the mana cost of your Crusader Strike ability by 20%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_crusaderstrike.jpg', + [PaladinMajorGlyph.GlyphOfDazingShield]: { + name: 'Glyph of Dazing Shield', + description: 'Your Avenger\'s Shield now also dazes targets.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_avengersshield.jpg', }, [PaladinMajorGlyph.GlyphOfDivinePlea]: { name: 'Glyph of Divine Plea', - description: 'While Divine Plea is active, you take 3% reduced damage from all sources.', + description: 'Your Divine Plea provides an additional 6% of your total mana.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_aspiration.jpg', }, - [PaladinMajorGlyph.GlyphOfDivineStorm]: { - name: 'Glyph of Divine Storm', - description: 'Your Divine Storm now heals for an additional 15% of the damage it causes.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_paladin_divinestorm.jpg', + [PaladinMajorGlyph.GlyphOfDivineProtection]: { + name: 'Glyph of Divine Protection', + description: 'Removes the physical damage reduction of your Divine Protection, but increases the magical damage reduction by 20%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_divineprotection.jpg', }, [PaladinMajorGlyph.GlyphOfDivinity]: { name: 'Glyph of Divinity', - description: 'Your Lay on Hands grants twice as much mana as normal and also grants you as much mana as it grants your target.', + description: 'When you use Lay on Hands, you also gain 10% of your maximum mana.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_layonhands.jpg', }, - [PaladinMajorGlyph.GlyphOfExorcism]: { - name: 'Glyph of Exorcism', - description: 'Increases damage done by Exorcism by 20%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_excorcism_02.jpg', - }, - [PaladinMajorGlyph.GlyphOfFlashOfLight]: { - name: 'Glyph of Flash of Light', - description: 'Your Flash of Light has an additional 5% critical strike chance.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_flashheal.jpg', + [PaladinMajorGlyph.GlyphOfFocusedShield]: { + name: 'Glyph of Focused Shield', + description: 'Your Avenger\'s Shield hits 2 fewer targets, but for 30% more damage.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_avengersshield.jpg', }, [PaladinMajorGlyph.GlyphOfHammerOfJustice]: { name: 'Glyph of Hammer of Justice', description: 'Increases your Hammer of Justice range by 5 yards.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_sealofmight.jpg', }, - [PaladinMajorGlyph.GlyphOfHammerOfTheRighteous]: { - name: 'Glyph of Hammer of the Righteous', - description: 'Your Hammer of the Righteous hits 1 additional target.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_paladin_hammeroftherighteous.jpg', - }, [PaladinMajorGlyph.GlyphOfHammerOfWrath]: { name: 'Glyph of Hammer of Wrath', description: 'Reduces the mana cost of Hammer of Wrath by 100%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_thunderclap.jpg', - }, - [PaladinMajorGlyph.GlyphOfHolyLight]: { - name: 'Glyph of Holy Light', - description: 'Your Holy Light grants 10% of its heal amount to up to 5 friendly targets within 8 yards of the initial target.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_holybolt.jpg', - }, - [PaladinMajorGlyph.GlyphOfHolyShock]: { - name: 'Glyph of Holy Shock', - description: 'Reduces the cooldown of Holy Shock by 1 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_searinglight.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_hammer_04.jpg', }, [PaladinMajorGlyph.GlyphOfHolyWrath]: { name: 'Glyph of Holy Wrath', - description: 'Reduces the cooldown of your Holy Wrath spell by 15 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_excorcism.jpg', + description: 'Your Holy Wrath now also stuns Elementals and Dragonkin.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_purifyingpower.jpg', }, - [PaladinMajorGlyph.GlyphOfJudgement]: { - name: 'Glyph of Judgement', - description: 'Your Judgements deal 10% more damage.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_paladin_judgementred.jpg', + [PaladinMajorGlyph.GlyphOfLayOnHands]: { + name: 'Glyph of Lay on Hands', + description: 'Reduces the cooldown of your Lay on Hands spell by 3 min.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_layonhands.jpg', }, - [PaladinMajorGlyph.GlyphOfRighteousDefense]: { - name: 'Glyph of Righteous Defense', - description: 'Increases the chance for your Righteous Defense and Hand of Reckoning abilities to work successfully by 8% on each target.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_shoulder_37.jpg', + [PaladinMajorGlyph.GlyphOfLightOfDawn]: { + name: 'Glyph of Light of Dawn', + description: 'Light of Dawn affects 2 fewer targets, but heals each target for 25% more.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_paladin_lightofdawn.jpg', + }, + [PaladinMajorGlyph.GlyphOfRebuke]: { + name: 'Glyph of Rebuke', + description: 'Reduces the mana cost of Rebuke by 100%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_rebuke.jpg', + }, + [PaladinMajorGlyph.GlyphOfReckoning]: { + name: 'Glyph of Reckoning', + description: 'Your Hand of Reckoning spell no longer taunts the target and can deal damage to untauntable targets.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_questionmark.jpg', }, [PaladinMajorGlyph.GlyphOfSalvation]: { name: 'Glyph of Salvation', - description: 'When you cast Hand of Salvation on yourself, it also reduces damage taken by 20%.', + description: 'Hand of Salvation no longer permanently reduces threat over time but instead reduces all threat as long as Hand of Salvation lasts.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_sealofsalvation.jpg', }, - [PaladinMajorGlyph.GlyphOfSealOfCommand]: { - name: 'Glyph of Seal of Command', - description: 'You gain 8% of your base mana each time you use a Judgement with Seal of Command active.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_innerrage.jpg', - }, - [PaladinMajorGlyph.GlyphOfSealOfLight]: { - name: 'Glyph of Seal of Light', - description: 'While Seal of Light is active, the effect of your healing spells is increased by 5%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_healingaura.jpg', - }, - [PaladinMajorGlyph.GlyphOfSealOfRighteousness]: { - name: 'Glyph of Seal of Righteousness', - description: 'Increases the damage done by Seal of Righteousness by 10%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_thunderbolt.jpg', - }, - [PaladinMajorGlyph.GlyphOfSealOfVengeance]: { - name: 'Glyph of Seal of Vengeance', - description: 'Your Seal of Vengeance or Seal of Corruption also grants 10 expertise while active.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_sealofvengeance.jpg', - }, - [PaladinMajorGlyph.GlyphOfSealOfWisdom]: { - name: 'Glyph of Seal of Wisdom', - description: 'While Seal of Wisdom is active, the cost of your healing spells is reduced by 5%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_righteousnessaura.jpg', - }, - [PaladinMajorGlyph.GlyphOfShieldOfRighteousness]: { - name: 'Glyph of Shield of Righteousness', - description: 'Reduces the mana cost of Shield of Righteousness by 80%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_paladin_shieldofvengeance.jpg', + [PaladinMajorGlyph.GlyphOfTheAsceticCrusader]: { + name: 'Glyph of the Ascetic Crusader', + description: 'Reduces the mana cost of your Crusader Strike by 30%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_crusaderstrike.jpg', }, - [PaladinMajorGlyph.GlyphOfSpiritualAttunement]: { - name: 'Glyph of Spiritual Attunement', - description: 'Increases the amount of mana gained from your Spiritual Attunement spell by an additional 2%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_revivechampion.jpg', + [PaladinMajorGlyph.GlyphOfTheLongWord]: { + name: 'Glyph of the Long Word', + description: 'Your Word of Glory heals for 50% less up front, but provides an additional 50% healing over 6 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_helmet_96.jpg', }, [PaladinMajorGlyph.GlyphOfTurnEvil]: { name: 'Glyph of Turn Evil', description: 'Reduces the casting time of your Turn Evil spell by 100%, but increases the cooldown by 8 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_turnundead.jpg', }, - [PaladinMajorGlyph.GlyphOfReckoning]: { - name: 'Glyph of Reckoning', - description: 'Your Hand of Reckoning spell no longer taunts the target and can deal damage to untauntable targets.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_unyieldingfaith.jpg', - }, }, minorGlyphs: { [PaladinMinorGlyph.GlyphOfBlessingOfKings]: { name: 'Glyph of Blessing of Kings', - description: 'Reduces the mana cost of your Blessing of Kings and Greater Blessing of Kings spells by 50%.', + description: 'Reduces the mana cost of Blessing of Kings by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_magic_magearmor.jpg', }, [PaladinMinorGlyph.GlyphOfBlessingOfMight]: { name: 'Glyph of Blessing of Might', - description: 'Increases the duration of your Blessing of Might spell by 20 min when cast on yourself.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_fistofjustice.jpg', + description: 'Reduces the mana cost of your Blessing of Might by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_greaterblessingofkings.jpg', }, - [PaladinMinorGlyph.GlyphOfBlessingOfWisdom]: { - name: 'Glyph of Blessing of Wisdom', - description: 'Increases the duration of your Blessing of Wisdom spell by 20 min when cast on yourself.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_sealofwisdom.jpg', - }, - [PaladinMinorGlyph.GlyphOfLayOnHands]: { - name: 'Glyph of Lay on Hands', - description: 'Reduces the cooldown of your Lay on Hands spell by 5 min.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_layonhands.jpg', + [PaladinMinorGlyph.GlyphOfInsight]: { + name: 'Glyph of Insight', + description: 'Reduces the mana cost of Seal of Insight by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_healingaura.jpg', }, - [PaladinMinorGlyph.GlyphOfSenseUndead]: { - name: 'Glyph of Sense Undead', - description: 'Damage against Undead increased by 1% while your Sense Undead ability is active.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_senseundead.jpg', + [PaladinMinorGlyph.GlyphOfJustice]: { + name: 'Glyph of Justice', + description: 'Reduces the mana cost of Seal of Justice by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_sealofwrath.jpg', }, - [PaladinMinorGlyph.GlyphOfTheWise]: { - name: 'Glyph of the Wise', - description: 'Reduces the mana cost of your Seal of Wisdom spell by 50%.', + [PaladinMinorGlyph.GlyphOfRighteousness]: { + name: 'Glyph of Righteousness', + description: 'Reduces the mana cost of Seal of Righteousness by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_righteousnessaura.jpg', }, + [PaladinMinorGlyph.GlyphOfTruth]: { + name: 'Glyph of Truth', + description: 'Reduces the mana cost of Seal of Truth by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_sealofvengeance.jpg', + }, }, -}; +}; \ No newline at end of file diff --git a/ui/core/talents/priest.ts b/ui/core/talents/priest.ts index 923c1ee0ee..beff6562ba 100644 --- a/ui/core/talents/priest.ts +++ b/ui/core/talents/priest.ts @@ -1,28 +1,93 @@ -import { PriestTalents, PriestMajorGlyph, PriestMinorGlyph } from '../proto/priest.js'; - +import { PriestMajorGlyph, PriestMinorGlyph,PriestPrimeGlyph, PriestTalents } from '../proto/priest.js'; import { GlyphsConfig } from './glyphs_picker.js'; -import { TalentsConfig, newTalentsConfig } from './talents_picker.js'; - +import { newTalentsConfig,TalentsConfig } from './talents_picker.js'; import PriestTalentJson from './trees/priest.json'; export const priestTalentsConfig: TalentsConfig = newTalentsConfig(PriestTalentJson); export const priestGlyphsConfig: GlyphsConfig = { + primeGlyphs: { + [PriestPrimeGlyph.GlyphOfDispersion]: { + name: 'Glyph of Dispersion', + description: 'Reduces the cooldown on Dispersion by 45 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_dispersion.jpg', + }, + [PriestPrimeGlyph.GlyphOfFlashHeal]: { + name: 'Glyph of Flash Heal', + description: 'Increases the critical effect chance of your Flash Heal on targets at or below 25% health by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_flashheal.jpg', + }, + [PriestPrimeGlyph.GlyphOfGuardianSpirit]: { + name: 'Glyph of Guardian Spirit', + description: 'Reduces the cooldown of your Guardian Spirit by 30 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_guardianspirit.jpg', + }, + [PriestPrimeGlyph.GlyphOfLightwell]: { + name: 'Glyph of Lightwell', + description: 'Increases the total amount of charges of your Lightwell by 5.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_summonlightwell.jpg', + }, + [PriestPrimeGlyph.GlyphOfMindFlay]: { + name: 'Glyph of Mind Flay', + description: 'Increases the damage done by your Mind Flay spell by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_siphonmana.jpg', + }, + [PriestPrimeGlyph.GlyphOfPenance]: { + name: 'Glyph of Penance', + description: 'Reduces the cooldown of Penance by 2 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_penance.jpg', + }, + [PriestPrimeGlyph.GlyphOfPowerWordBarrier]: { + name: 'Glyph of Power Word: Barrier', + description: 'Increases the healing received while under Power Word: Barrier by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_powerwordbarrier.jpg', + }, + [PriestPrimeGlyph.GlyphOfPowerWordShield]: { + name: 'Glyph of Power Word: Shield', + description: 'Your Power Word: Shield also heals the target for 20% of the absorption amount.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_powerwordshield.jpg', + }, + [PriestPrimeGlyph.GlyphOfPrayerOfHealing]: { + name: 'Glyph of Prayer of Healing', + description: 'Your Prayer of Healing spell also heals an additional 20% of its initial heal over 6 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_prayerofhealing02.jpg', + }, + [PriestPrimeGlyph.GlyphOfRenew]: { + name: 'Glyph of Renew', + description: 'Increases the amount healed by your Renew by an additional 25%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_renew.jpg', + }, + [PriestPrimeGlyph.GlyphOfShadowWordDeath]: { + name: 'Glyph of Shadow Word: Death', + description: 'If your Shadow Word: Death fails to kill the target at or below 25% health, your Shadow Word: Death\'s cooldown is instantly reset. This effect cannot occur more often than once every 6 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_demonicfortitude.jpg', + }, + [PriestPrimeGlyph.GlyphOfShadowWordPain]: { + name: 'Glyph of Shadow Word: Pain', + description: 'Increases the periodic damage of your Shadow Word: Pain by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_shadowwordpain.jpg', + }, + }, majorGlyphs: { [PriestMajorGlyph.GlyphOfCircleOfHealing]: { name: 'Glyph of Circle of Healing', - description: 'Your Circle of Healing spell heals 1 additional target.', + description: 'Your Circle of Healing spell heals 1 additional target, but its mana cost is increased by 20%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_circleofrenewal.jpg', }, + [PriestMajorGlyph.GlyphOfDesperation]: { + name: 'Glyph of Desperation', + description: 'Allows Pain Suppression and Guardian Spirit to be cast while stunned.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_painsupression.jpg', + }, [PriestMajorGlyph.GlyphOfDispelMagic]: { name: 'Glyph of Dispel Magic', - description: 'Your Dispel Magic spell also heals your target for 3% of maximum health.', + description: 'Your Dispel Magic spell also heals your target for 3% of maximum health when you successfully dispel a magical effect.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_dispelmagic.jpg', }, - [PriestMajorGlyph.GlyphOfDispersion]: { - name: 'Glyph of Dispersion', - description: 'Reduces the cooldown on Dispersion by 45 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_dispersion.jpg', + [PriestMajorGlyph.GlyphOfDivineAccuracy]: { + name: 'Glyph of Divine Accuracy', + description: 'Increases your chance to hit with your Smite and Holy Fire spells by 18%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_holyprotection.jpg', }, [PriestMajorGlyph.GlyphOfFade]: { name: 'Glyph of Fade', @@ -31,129 +96,64 @@ export const priestGlyphsConfig: GlyphsConfig = { }, [PriestMajorGlyph.GlyphOfFearWard]: { name: 'Glyph of Fear Ward', - description: 'Reduces cooldown and duration of Fear Ward by 60 sec.', + description: 'Reduces the cooldown and duration of Fear Ward by 60 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_excorcism.jpg', }, - [PriestMajorGlyph.GlyphOfFlashHeal]: { - name: 'Glyph of Flash Heal', - description: 'Reduces the mana cost of your Flash Heal by 10%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_flashheal.jpg', - }, - [PriestMajorGlyph.GlyphOfGuardianSpirit]: { - name: 'Glyph of Guardian Spirit', - description: 'If your Guardian Spirit lasts its entire duration without being triggered, the cooldown is reset to 1 min.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_guardianspirit.jpg', - }, [PriestMajorGlyph.GlyphOfHolyNova]: { name: 'Glyph of Holy Nova', - description: 'Increases the damage and healing of your Holy Nova spell by an additional 20%.', + description: 'Reduces the global cooldown of your Holy Nova by .5 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_holynova.jpg', }, - [PriestMajorGlyph.GlyphOfHymnOfHope]: { - name: 'Glyph of Hymn of Hope', - description: 'Your Hymn of Hope lasts an additional 2 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_symbolofhope.jpg', - }, [PriestMajorGlyph.GlyphOfInnerFire]: { name: 'Glyph of Inner Fire', - description: 'Increases the armor from your Inner Fire spell by 50%.', + description: 'Increases the armor gained from your Inner Fire spell by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_innerfire.jpg', }, - [PriestMajorGlyph.GlyphOfLightwell]: { - name: 'Glyph of Lightwell', - description: 'Increases the amount healed by your Lightwell by 20%', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_summonlightwell.jpg', - }, [PriestMajorGlyph.GlyphOfMassDispel]: { name: 'Glyph of Mass Dispel', - description: 'Reduces the mana cost of Mass Dispel by 35%.', + description: 'Reduces the cast time of Mass Dispel by 1 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_arcane_massdispel.jpg', }, - [PriestMajorGlyph.GlyphOfMindControl]: { - name: 'Glyph of Mind Control', - description: 'Reduces the chance targets will resist or break your Mind Control spell by an additional 17%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_shadowworddominate.jpg', - }, - [PriestMajorGlyph.GlyphOfMindFlay]: { - name: 'Glyph of Mind Flay', - description: 'Increases the damage done by your Mind Flay spell by 10% when your target is afflicted with Shadow Word: Pain.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_siphonmana.jpg', - }, - [PriestMajorGlyph.GlyphOfMindSear]: { - name: 'Glyph of Mind Sear', - description: 'Increases the radius of effect on Mind Sear by 5 yards.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_mindshear.jpg', - }, - [PriestMajorGlyph.GlyphOfPainSuppression]: { - name: 'Glyph of Pain Suppression', - description: 'Allows Pain Suppression to be cast while stunned.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_painsupression.jpg', - }, - [PriestMajorGlyph.GlyphOfPenance]: { - name: 'Glyph of Penance', - description: 'Reduces the cooldown of Penance by 2 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_penance.jpg', - }, - [PriestMajorGlyph.GlyphOfPowerWordShield]: { - name: 'Glyph of Power Word: Shield', - description: 'Your Power Word: Shield also heals the target for 20% of the absorption amount.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_powerwordshield.jpg', + [PriestMajorGlyph.GlyphOfPrayerOfMending]: { + name: 'Glyph of Prayer of Mending', + description: 'The first charge of your Prayer of Mending heals for an additional 60%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_prayerofmendingtga.jpg', }, - [PriestMajorGlyph.GlyphOfPrayerOfHealing]: { - name: 'Glyph of Prayer of Healing', - description: 'Your Prayer of Healing spell also heals an additional 20% of its initial heal over 6 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_prayerofhealing02.jpg', + [PriestMajorGlyph.GlyphOfPsychicHorror]: { + name: 'Glyph of Psychic Horror', + description: 'Reduces the cooldown of your Psychic Horror by 30 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_psychichorrors.jpg', }, [PriestMajorGlyph.GlyphOfPsychicScream]: { name: 'Glyph of Psychic Scream', - description: 'Increases the duration of your Psychic Scream by 2 sec. and increases its cooldown by 8 sec.', + description: 'Targets of your Psychic Scream spell now tremble in place instead of fleeing in fear, but the cooldown of Psychic Scream is increased by 3 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_psychicscream.jpg', }, - [PriestMajorGlyph.GlyphOfRenew]: { - name: 'Glyph of Renew', - description: 'Reduces the duration of your Renew by 3 sec. but increases the amount healed each tick by 25%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_renew.jpg', - }, [PriestMajorGlyph.GlyphOfScourgeImprisonment]: { name: 'Glyph of Scourge Imprisonment', description: 'Reduces the cast time of your Shackle Undead by 1.0 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_slow.jpg', - }, - [PriestMajorGlyph.GlyphOfShadow]: { - name: 'Glyph of Shadow', - description: 'While in Shadowform, your non-periodic spell critical strikes increase your spell power by 30% of your Spirit for 10 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_mindsooth.jpg', - }, - [PriestMajorGlyph.GlyphOfShadowWordDeath]: { - name: 'Glyph of Shadow Word: Death', - description: 'Targets below 35% health take an additional 10% damage from your Shadow Word: Death spell.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_demonicfortitude.jpg', - }, - [PriestMajorGlyph.GlyphOfShadowWordPain]: { - name: 'Glyph of Shadow Word: Pain', - description: 'The periodic damage ticks of your Shadow Word: Pain spell restore 1% of your base mana.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_shadowwordpain.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_crusade.jpg', }, [PriestMajorGlyph.GlyphOfSmite]: { name: 'Glyph of Smite', description: 'Your Smite spell inflicts an additional 20% damage against targets afflicted by Holy Fire.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_holysmite.jpg', }, - [PriestMajorGlyph.GlyphOfSpiritOfRedemption]: { - name: 'Glyph of Spirit of Redemption', - description: 'Increases the duration of Spirit of Redemption by 6 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_enchant_essenceeternallarge.jpg', + [PriestMajorGlyph.GlyphOfSpiritTap]: { + name: 'Glyph of Spirit Tap', + description: 'When you kill a target with your Shadow Word: Death that yields experience or honor, you receive 12% of your total mana over 12 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_requiem.jpg', }, }, minorGlyphs: { [PriestMinorGlyph.GlyphOfFading]: { name: 'Glyph of Fading', description: 'Reduces the mana cost of your Fade spell by 30%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_magic_lesserinvisibilty.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mage_invisibility.jpg', }, [PriestMinorGlyph.GlyphOfFortitude]: { name: 'Glyph of Fortitude', - description: 'Reduces the mana cost of your Power Word: Fortitude and Prayer of Fortitude spells by 50%.', + description: 'Reduces the mana cost of your Power Word: Fortitude spell by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_wordfortitude.jpg', }, [PriestMinorGlyph.GlyphOfLevitate]: { @@ -166,10 +166,15 @@ export const priestGlyphsConfig: GlyphsConfig = { description: 'Increases the range of your Shackle Undead spell by 5 yards.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_slow.jpg', }, + [PriestMinorGlyph.GlyphOfShadow]: { + name: 'Glyph of Shadow', + description: 'Alters the appearance of your Shadowform.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_questionmark.jpg', + }, [PriestMinorGlyph.GlyphOfShadowProtection]: { name: 'Glyph of Shadow Protection', - description: 'Increases the duration of your Shadow Protection and Prayer of Shadow Protection spells by 10 min.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_antishadow.jpg', + description: 'Increases the duration of your Shadow Protection spell by 10 min.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_prayerofshadowprotection.jpg', }, [PriestMinorGlyph.GlyphOfShadowfiend]: { name: 'Glyph of Shadowfiend', @@ -177,4 +182,4 @@ export const priestGlyphsConfig: GlyphsConfig = { iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_shadowfiend.jpg', }, }, -}; +}; \ No newline at end of file diff --git a/ui/core/talents/rogue.ts b/ui/core/talents/rogue.ts index 8004c4fa86..86074298e3 100644 --- a/ui/core/talents/rogue.ts +++ b/ui/core/talents/rogue.ts @@ -1,34 +1,89 @@ -import { RogueTalents, RogueMajorGlyph, RogueMinorGlyph } from '../proto/rogue.js'; - +import { RogueMajorGlyph, RogueMinorGlyph,RoguePrimeGlyph, RogueTalents } from '../proto/rogue.js'; import { GlyphsConfig } from './glyphs_picker.js'; -import { TalentsConfig, newTalentsConfig } from './talents_picker.js'; - +import { newTalentsConfig,TalentsConfig } from './talents_picker.js'; import RogueTalentJson from './trees/rogue.json'; export const rogueTalentsConfig: TalentsConfig = newTalentsConfig(RogueTalentJson); export const rogueGlyphsConfig: GlyphsConfig = { - majorGlyphs: { - [RogueMajorGlyph.GlyphOfAdrenalineRush]: { + primeGlyphs: { + [RoguePrimeGlyph.GlyphOfAdrenalineRush]: { name: 'Glyph of Adrenaline Rush', description: 'Increases the duration of Adrenaline Rush by 5 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_shadowworddominate.jpg', }, + [RoguePrimeGlyph.GlyphOfBackstab]: { + name: 'Glyph of Backstab', + description: 'Your Backstab critical strikes grant you 5 Energy.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_backstab.jpg', + }, + [RoguePrimeGlyph.GlyphOfEviscerate]: { + name: 'Glyph of Eviscerate', + description: 'Increases the critical strike chance of Eviscerate by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_eviscerate.jpg', + }, + [RoguePrimeGlyph.GlyphOfHemorrhage]: { + name: 'Glyph of Hemorrhage', + description: 'Your Hemorrhage ability also causes the target to bleed, dealing 40% of the direct strike\'s damage over 24 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_lifedrain.jpg', + }, + [RoguePrimeGlyph.GlyphOfKillingSpree]: { + name: 'Glyph of Killing Spree', + description: 'Increases the bonus to your damage while Killing Spree is active by an additional 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_murderspree.jpg', + }, + [RoguePrimeGlyph.GlyphOfMutilate]: { + name: 'Glyph of Mutilate', + description: 'Reduces the cost of Mutilate by 5 Energy.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_shadowstrikes.jpg', + }, + [RoguePrimeGlyph.GlyphOfRevealingStrike]: { + name: 'Glyph of Revealing Strike', + description: 'Increases Revealing Strike\'s bonus effectiveness to your finishing moves by an additional 10%', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_sword_97.jpg', + }, + [RoguePrimeGlyph.GlyphOfRupture]: { + name: 'Glyph of Rupture', + description: 'Increases the duration of Rupture by 4 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_rupture.jpg', + }, + [RoguePrimeGlyph.GlyphOfShadowDance]: { + name: 'Glyph of Shadow Dance', + description: 'Increases the duration of Shadow Dance by 2 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_shadowdance.jpg', + }, + [RoguePrimeGlyph.GlyphOfSinisterStrike]: { + name: 'Glyph of Sinister Strike', + description: 'Your Sinister Strikes have a 20% chance to add an additional combo point.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_ritualofsacrifice.jpg', + }, + [RoguePrimeGlyph.GlyphOfSliceAndDice]: { + name: 'Glyph of Slice and Dice', + description: 'Increases the duration of Slice and Dice by 6 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_slicedice.jpg', + }, + [RoguePrimeGlyph.GlyphOfVendetta]: { + name: 'Glyph of Vendetta', + description: 'Increases the duration of your Vendetta ability by 20%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_deadliness.jpg', + }, + }, + majorGlyphs: { [RogueMajorGlyph.GlyphOfAmbush]: { name: 'Glyph of Ambush', description: 'Increases the range on Ambush by 5 yards.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_ambush.jpg', }, - [RogueMajorGlyph.GlyphOfBackstab]: { - name: 'Glyph of Backstab', - description: 'Your Backstab increases the duration of your Rupture effect on the target by 2 sec, up to a maximum of 6 additional sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_backstab.jpg', - }, [RogueMajorGlyph.GlyphOfBladeFlurry]: { name: 'Glyph of Blade Flurry', - description: 'Reduces the energy cost of Blade Flurry by 100%.', + description: 'Reduces the penalty to Energy generation while Blade Flurry is active by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_punishingblow.jpg', }, + [RogueMajorGlyph.GlyphOfBlind]: { + name: 'Glyph of Blind', + description: 'Your Blind ability also removes all damage over time effects from the target.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_mindsteal.jpg', + }, [RogueMajorGlyph.GlyphOfCloakOfShadows]: { name: 'Glyph of Cloak of Shadows', description: 'While Cloak of Shadows is active, you take 40% less physical damage.', @@ -49,11 +104,6 @@ export const rogueGlyphsConfig: GlyphsConfig = { description: 'Increases the duration of Evasion by 5 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_shadowward.jpg', }, - [RogueMajorGlyph.GlyphOfEviscerate]: { - name: 'Glyph of Eviscerate', - description: 'Increases the critical strike chance of Eviscerate by 10%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_eviscerate.jpg', - }, [RogueMajorGlyph.GlyphOfExposeArmor]: { name: 'Glyph of Expose Armor', description: 'Increases the duration of Expose Armor by 12 sec.', @@ -61,79 +111,39 @@ export const rogueGlyphsConfig: GlyphsConfig = { }, [RogueMajorGlyph.GlyphOfFanOfKnives]: { name: 'Glyph of Fan of Knives', - description: 'Increases the damage done by Fan of Knives by 20%.', + description: 'Increases the radius of your Fan of Knives ability by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_fanofknives.jpg', }, [RogueMajorGlyph.GlyphOfFeint]: { name: 'Glyph of Feint', - description: 'Reduces the energy cost of Feint by 20.', + description: 'Reduces the Energy cost of Feint by 20.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_feint.jpg', }, [RogueMajorGlyph.GlyphOfGarrote]: { name: 'Glyph of Garrote', - description: 'Reduces the duration of your Garrote ability by 3 sec and increases the total damage it deals by 20%.', + description: 'Increases the duration of your Garrote ability\'s silence effect by 1.5 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_garrote.jpg', }, - [RogueMajorGlyph.GlyphOfGhostlyStrike]: { - name: 'Glyph of Ghostly Strike', - description: 'Increases the damage dealt by Ghostly Strike by 40% and the duration of its effect by 4 sec, but increases its cooldown by 10 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_curse.jpg', - }, [RogueMajorGlyph.GlyphOfGouge]: { name: 'Glyph of Gouge', - description: 'Reduces the energy cost of Gouge by 15.', + description: 'Your Gouge ability no longer requires that the target be facing you.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_gouge.jpg', }, - [RogueMajorGlyph.GlyphOfHemorrhage]: { - name: 'Glyph of Hemorrhage', - description: 'Increases the damage bonus against targets afflicted by Hemorrhage by 40%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_lifedrain.jpg', - }, - [RogueMajorGlyph.GlyphOfHungerForBlood]: { - name: 'Glyph of Hunger For Blood', - description: 'Increases the bonus damage from Hunger For Blood by 3%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_hungerforblood.jpg', - }, - [RogueMajorGlyph.GlyphOfKillingSpree]: { - name: 'Glyph of Killing Spree', - description: 'Reduces the cooldown on Killing Spree by 45 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_murderspree.jpg', - }, - [RogueMajorGlyph.GlyphOfMutilate]: { - name: 'Glyph of Mutilate', - description: 'Reduces the cost of Mutilate by 5 energy.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_shadowstrikes.jpg', + [RogueMajorGlyph.GlyphOfKick]: { + name: 'Glyph of Kick', + description: 'Increases the cooldown of your Kick ability by 4 sec, but this cooldown is reduced by 6 sec when your Kick successfully interrupts a spell.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_kick.jpg', }, [RogueMajorGlyph.GlyphOfPreparation]: { name: 'Glyph of Preparation', - description: 'Your Preparation ability also instantly resets the cooldown of Blade Flurry, Dismantle, and Kick.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_antishadow.jpg', - }, - [RogueMajorGlyph.GlyphOfRupture]: { - name: 'Glyph of Rupture', - description: 'Increases the duration of Rupture by 4 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_rupture.jpg', + description: 'Your Preparation ability also instantly resets the cooldown of Kick, Dismantle, and Smoke Bomb.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_preparation.jpg', }, [RogueMajorGlyph.GlyphOfSap]: { name: 'Glyph of Sap', - description: 'Increases the duration of Sap by 20 sec.', + description: 'Increases the duration of Sap against non-player targets by 80 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_sap.jpg', }, - [RogueMajorGlyph.GlyphOfShadowDance]: { - name: 'Glyph of Shadow Dance', - description: 'Increases the duration of Shadow Dance by 2 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_shadowdance.jpg', - }, - [RogueMajorGlyph.GlyphOfSinisterStrike]: { - name: 'Glyph of Sinister Strike', - description: 'Your Sinister Strike critical strikes have a 50% chance to add an additional combo point.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_ritualofsacrifice.jpg', - }, - [RogueMajorGlyph.GlyphOfSliceAndDice]: { - name: 'Glyph of Slice and Dice', - description: 'Increases the duration of Slice and Dice by 3 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_slicedice.jpg', - }, [RogueMajorGlyph.GlyphOfSprint]: { name: 'Glyph of Sprint', description: 'Increases the movement speed of your Sprint ability by an additional 30%.', @@ -141,13 +151,13 @@ export const rogueGlyphsConfig: GlyphsConfig = { }, [RogueMajorGlyph.GlyphOfTricksOfTheTrade]: { name: 'Glyph of Tricks of the Trade', - description: 'The bonus damage and threat redirection granted by your Tricks of the Trade ability lasts an additional 4 sec.', + description: 'Removes the Energy cost of your Tricks of the Trade ability but reduces the recipient\'s damage bonus by 5%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_tricksofthetrade.jpg', }, - [RogueMajorGlyph.GlyphOfVigor]: { - name: 'Glyph of Vigor', - description: 'Vigor grants an additional 10 maximum energy.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_earthbindtotem.jpg', + [RogueMajorGlyph.GlyphOfVanish]: { + name: 'Glyph of Vanish', + description: 'Increases the duration of your Vanish effect by 2 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_vanish.jpg', }, }, minorGlyphs: { @@ -171,15 +181,15 @@ export const rogueGlyphsConfig: GlyphsConfig = { description: 'Increases the range of your Pick Pocket ability by 5 yards.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_bag_11.jpg', }, + [RogueMinorGlyph.GlyphOfPoisons]: { + name: 'Glyph of Poisons', + description: 'You apply poisons to your weapons 50% faster.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/trade_brewpoison.jpg', + }, [RogueMinorGlyph.GlyphOfSafeFall]: { name: 'Glyph of Safe Fall', description: 'Increases the distance your Safe Fall ability allows you to fall without taking damage.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_feather_01.jpg', }, - [RogueMinorGlyph.GlyphOfVanish]: { - name: 'Glyph of Vanish', - description: 'Increases your movement speed by 30% while the Vanish effect is active.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_vanish.jpg', - }, }, -}; +}; \ No newline at end of file diff --git a/ui/core/talents/shaman.ts b/ui/core/talents/shaman.ts index b5d93c4ced..3a3cc3907c 100644 --- a/ui/core/talents/shaman.ts +++ b/ui/core/talents/shaman.ts @@ -1,174 +1,183 @@ -import { ShamanTalents, ShamanMajorGlyph, ShamanMinorGlyph } from '../proto/shaman.js'; - +import { ShamanMajorGlyph, ShamanMinorGlyph,ShamanPrimeGlyph, ShamanTalents } from '../proto/shaman.js'; import { GlyphsConfig } from './glyphs_picker.js'; -import { TalentsConfig, newTalentsConfig } from './talents_picker.js'; - +import { newTalentsConfig,TalentsConfig } from './talents_picker.js'; import ShamanTalentJson from './trees/shaman.json'; export const shamanTalentsConfig: TalentsConfig = newTalentsConfig(ShamanTalentJson); - export const shamanGlyphsConfig: GlyphsConfig = { - majorGlyphs: { - [ShamanMajorGlyph.GlyphOfChainHeal]: { - name: 'Glyph of Chain Heal', - description: 'Your Chain Heal heals 1 additional target.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_healingwavegreater.jpg', - }, - [ShamanMajorGlyph.GlyphOfChainLightning]: { - name: 'Glyph of Chain Lightning', - description: 'Your Chain Lightning strikes 1 additional target.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_chainlightning.jpg', - }, - [ShamanMajorGlyph.GlyphOfEarthShield]: { + primeGlyphs: { + [ShamanPrimeGlyph.GlyphOfEarthShield]: { name: 'Glyph of Earth Shield', description: 'Increases the amount healed by your Earth Shield by 20%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_skinofearth.jpg', }, - [ShamanMajorGlyph.GlyphOfEarthlivingWeapon]: { + [ShamanPrimeGlyph.GlyphOfEarthlivingWeapon]: { name: 'Glyph of Earthliving Weapon', - description: 'Increases the chance for your Earthliving weapon to trigger by 5%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_earthlivingweapon.jpg', + description: 'Increases the effectiveness of your Earthliving weapon\'s periodic healing by 20%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_unleashweapon_life.jpg', }, - [ShamanMajorGlyph.GlyphOfElementalMastery]: { - name: 'Glyph of Elemental Mastery', - description: 'Reduces the cooldown of your Elemental Mastery ability by 30 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_wispheal.jpg', - }, - [ShamanMajorGlyph.GlyphOfFeralSpirit]: { + [ShamanPrimeGlyph.GlyphOfFeralSpirit]: { name: 'Glyph of Feral Spirit', description: 'Your spirit wolves gain an additional 30% of your attack power.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_feralspirit.jpg', }, - [ShamanMajorGlyph.GlyphOfFireElementalTotem]: { + [ShamanPrimeGlyph.GlyphOfFireElementalTotem]: { name: 'Glyph of Fire Elemental Totem', description: 'Reduces the cooldown of your Fire Elemental Totem by 5 min.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_elemental_totem.jpg', }, - [ShamanMajorGlyph.GlyphOfFireNova]: { - name: 'Glyph of Fire Nova', - description: 'Reduces the cooldown of your Fire Nova spell by 3 seconds.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_sealoffire.jpg', - }, - [ShamanMajorGlyph.GlyphOfFlameShock]: { + [ShamanPrimeGlyph.GlyphOfFlameShock]: { name: 'Glyph of Flame Shock', - description: 'Increases the critical strike damage bonus of your Flame Shock damage by 60%.', + description: 'Increases the duration of your Flame Shock by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_flameshock.jpg', }, - [ShamanMajorGlyph.GlyphOfFlametongueWeapon]: { + [ShamanPrimeGlyph.GlyphOfFlametongueWeapon]: { name: 'Glyph of Flametongue Weapon', description: 'Increases your spell critical strike chance by 2% on each of your weapons with Flametongue Weapon active.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_flametounge.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_unleashweapon_flame.jpg', + }, + [ShamanPrimeGlyph.GlyphOfLavaBurst]: { + name: 'Glyph of Lava Burst', + description: 'Your Lava Burst spell deals 10% more damage.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_lavaburst.jpg', + }, + [ShamanPrimeGlyph.GlyphOfLavaLash]: { + name: 'Glyph of Lava Lash', + description: 'Increases the damage dealt by your Lava Lash ability by 20%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_shaman_lavalash.jpg', + }, + [ShamanPrimeGlyph.GlyphOfLightningBolt]: { + name: 'Glyph of Lightning Bolt', + description: 'Increases the damage dealt by Lightning Bolt by 4%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_lightning.jpg', + }, + [ShamanPrimeGlyph.GlyphOfRiptide]: { + name: 'Glyph of Riptide', + description: 'Increases the duration of Riptide by 40%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_riptide.jpg', + }, + [ShamanPrimeGlyph.GlyphOfShocking]: { + name: 'Glyph of Shocking', + description: 'Reduces your global cooldown when casting your shock spells by 0.0 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_earthshock.jpg', + }, + [ShamanPrimeGlyph.GlyphOfStormstrike]: { + name: 'Glyph of Stormstrike', + description: 'Increases the critical strike chance bonus from your Stormstrike ability by an additional 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_shaman_stormstrike.jpg', + }, + [ShamanPrimeGlyph.GlyphOfUnleashedLightning]: { + name: 'Glyph of Unleashed Lightning', + description: 'Allows Lightning Bolt to be cast while moving.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_lightning.jpg', + }, + [ShamanPrimeGlyph.GlyphOfWaterShield]: { + name: 'Glyph of Water Shield', + description: 'Increases the passive mana regeneration of your Water Shield spell by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_shaman_watershield.jpg', + }, + [ShamanPrimeGlyph.GlyphOfWindfuryWeapon]: { + name: 'Glyph of Windfury Weapon', + description: 'Increases the chance per swing for Windfury Weapon to trigger by 2%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_unleashweapon_wind.jpg', + }, + }, + majorGlyphs: { + [ShamanMajorGlyph.GlyphOfChainHeal]: { + name: 'Glyph of Chain Heal', + description: 'Increases healing done by your Chain Heal spell to targets beyond the first by 15%, but decreases the amount received by the initial target by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_healingwavegreater.jpg', + }, + [ShamanMajorGlyph.GlyphOfChainLightning]: { + name: 'Glyph of Chain Lightning', + description: 'Your Chain Lightning spell now strikes 2 additional targets, but deals 10% less initial damage.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_chainlightning.jpg', + }, + [ShamanMajorGlyph.GlyphOfElementalMastery]: { + name: 'Glyph of Elemental Mastery', + description: 'While your Elemental Mastery ability is active, you take 20% less damage from all sources.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_wispheal.jpg', + }, + [ShamanMajorGlyph.GlyphOfFireNova]: { + name: 'Glyph of Fire Nova', + description: 'Increases the radius of your Fire Nova spell by 5 yards.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_firenova.jpg', }, [ShamanMajorGlyph.GlyphOfFrostShock]: { name: 'Glyph of Frost Shock', description: 'Increases the duration of your Frost Shock by 2 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_frostshock.jpg', }, + [ShamanMajorGlyph.GlyphOfGhostWolf]: { + name: 'Glyph of Ghost Wolf', + description: 'Your Ghost Wolf form grants an additional 5% movement speed.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_spiritwolf.jpg', + }, + [ShamanMajorGlyph.GlyphOfGroundingTotem]: { + name: 'Glyph of Grounding Totem', + description: 'Instead of absorbing a spell, your Grounding Totem reflects the next harmful spell back at its caster, but the cooldown of your Grounding Totem is increased by 35 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_groundingtotem.jpg', + }, [ShamanMajorGlyph.GlyphOfHealingStreamTotem]: { name: 'Glyph of Healing Stream Totem', - description: 'Your Healing Stream Totem heals for an additional 20%.', + description: 'Your Healing Stream Totem also increases the Fire, Frost, and Nature resistance of party and raid members within 30 yards by 85.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_spear_04.jpg', }, [ShamanMajorGlyph.GlyphOfHealingWave]: { name: 'Glyph of Healing Wave', description: 'Your Healing Wave also heals you for 20% of the healing effect when you heal someone else.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_magicimmunity.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_healingwavegreater.jpg', }, [ShamanMajorGlyph.GlyphOfHex]: { name: 'Glyph of Hex', - description: 'Increases the damage your Hex target can take before the Hex effect is removed by 20%.', + description: 'Reduces the cooldown of your Hex spell by 10 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_hex.jpg', }, - [ShamanMajorGlyph.GlyphOfLava]: { - name: 'Glyph of Lava', - description: 'Your Lava Burst spell gains an additional 10% of your spellpower.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_lavaburst.jpg', - }, - [ShamanMajorGlyph.GlyphOfLavaLash]: { - name: 'Glyph of Lava Lash', - description: 'Damage on your Lava Lash is increased by an additional 10% if your weapon is enchanted with Flametongue.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_shaman_lavalash.jpg', - }, - [ShamanMajorGlyph.GlyphOfLesserHealingWave]: { - name: 'Glyph of Lesser Healing Wave', - description: 'Your Lesser Healing Wave heals for 20% more if the target is also affected by Earth Shield.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_healingwavelesser.jpg', - }, - [ShamanMajorGlyph.GlyphOfLightningBolt]: { - name: 'Glyph of Lightning Bolt', - description: 'Increases the damage dealt by Lightning Bolt by 4%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_lightning.jpg', - }, [ShamanMajorGlyph.GlyphOfLightningShield]: { name: 'Glyph of Lightning Shield', - description: 'Increases the damage from Lightning Shield by 20%.', + description: 'Your Lightning Shield can no longer drop below 3 charges from dealing damage to attackers.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_lightningshield.jpg', }, - [ShamanMajorGlyph.GlyphOfManaTide]: { - name: 'Glyph of Mana Tide', - description: 'Your Mana Tide Totem grants an additional 1% of each target\'s maximum mana each time it pulses.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_healingwavegreater.jpg', - }, - [ShamanMajorGlyph.GlyphOfRiptide]: { - name: 'Glyph of Riptide', - description: 'Increases the duration of Riptide by 6 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_riptide.jpg', - }, - [ShamanMajorGlyph.GlyphOfShocking]: { - name: 'Glyph of Shocking', - description: 'Reduces your global cooldown when casting your shock spells by 0.5 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_earthshock.jpg', + [ShamanMajorGlyph.GlyphOfShamanisticRage]: { + name: 'Glyph of Shamanistic Rage', + description: 'Activating your Shamanistic Rage ability also cleanses you of all dispellable Magic debuffs.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_shamanrage.jpg', }, [ShamanMajorGlyph.GlyphOfStoneclawTotem]: { name: 'Glyph of Stoneclaw Totem', description: 'Your Stoneclaw Totem also places a damage absorb shield on you, equal to 4 times the strength of the shield it places on your totems.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_stoneclawtotem.jpg', }, - [ShamanMajorGlyph.GlyphOfStormstrike]: { - name: 'Glyph of Stormstrike', - description: 'Increases the Nature damage bonus from your Stormstrike ability by an additional 8%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_shaman_stormstrike.jpg', - }, [ShamanMajorGlyph.GlyphOfThunder]: { name: 'Glyph of Thunder', description: 'Reduces the cooldown on Thunderstorm by 10 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_thunderstorm.jpg', }, - [ShamanMajorGlyph.GlyphOfTotemOfWrath]: { - name: 'Glyph of Totem of Wrath', - description: 'When you cast Totem of Wrath, you gain 30% of the totem\'s bonus spell power for 5 min.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_totemofwrath.jpg', - }, - [ShamanMajorGlyph.GlyphOfWaterMastery]: { - name: 'Glyph of Water Mastery', - description: 'Increases the passive mana regeneration of your Water Shield spell by 30%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_shaman_watershield.jpg', - }, - [ShamanMajorGlyph.GlyphOfWindfuryWeapon]: { - name: 'Glyph of Windfury Weapon', - description: 'Increases the chance per swing for Windfury Weapon to trigger by 2%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_cyclone.jpg', + [ShamanMajorGlyph.GlyphOfTotemicRecall]: { + name: 'Glyph of Totemic Recall', + description: 'Causes your Totemic Recall ability to return an additional 50% of the mana cost of any recalled totems.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_totemrecall.jpg', }, }, minorGlyphs: { [ShamanMinorGlyph.GlyphOfAstralRecall]: { name: 'Glyph of Astral Recall', - description: 'Cooldown of your Astral Recall spell reduced by 7.5 min.', + description: 'Reduces the cooldown of your Astral Recall spell by 7.5 min.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_astralrecal.jpg', }, - [ShamanMinorGlyph.GlyphOfGhostWolf]: { - name: 'Glyph of Ghost Wolf', - description: 'Your Ghost Wolf form regenerates an additional 1% of your maximum health every 5 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_spiritwolf.jpg', - }, [ShamanMinorGlyph.GlyphOfRenewedLife]: { name: 'Glyph of Renewed Life', description: 'Your Reincarnation spell no longer requires a reagent.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_reincarnation.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_improvedreincarnation.jpg', + }, + [ShamanMinorGlyph.GlyphOfTheArcticWolf]: { + name: 'Glyph of the Arctic Wolf', + description: 'Alters the appearance of your Ghost Wolf transformation, causing it to resemble an arctic wolf.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_mount_whitedirewolf.jpg', }, [ShamanMinorGlyph.GlyphOfThunderstorm]: { name: 'Glyph of Thunderstorm', - description: 'Increases the mana you receive from your Thunderstorm spell by 2%, but it no longer knocks enemies back.', + description: 'Increases the mana you receive from your Thunderstorm spell by 2%, but it no longer knocks enemies back or reduces their movement speed.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shaman_thunderstorm.jpg', }, [ShamanMinorGlyph.GlyphOfWaterBreathing]: { @@ -176,15 +185,10 @@ export const shamanGlyphsConfig: GlyphsConfig = { description: 'Your Water Breathing spell no longer requires a reagent.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_demonbreath.jpg', }, - [ShamanMinorGlyph.GlyphOfWaterShield]: { - name: 'Glyph of Water Shield', - description: 'Increases the number of charges on your Water Shield spell by 1.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_shaman_watershield.jpg', - }, [ShamanMinorGlyph.GlyphOfWaterWalking]: { name: 'Glyph of Water Walking', description: 'Your Water Walking spell no longer requires a reagent.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_frost_windwalkon.jpg', }, }, -}; +}; \ No newline at end of file diff --git a/ui/core/talents/talents_picker.tsx b/ui/core/talents/talents_picker.tsx index de0ae19896..e4fb917fd7 100644 --- a/ui/core/talents/talents_picker.tsx +++ b/ui/core/talents/talents_picker.tsx @@ -12,9 +12,9 @@ import { ActionId } from '../proto_utils/action_id.js'; import { TypedEvent } from '../typed_event.js'; import { isRightClick, sum } from '../utils.js'; -const MAX_POINTS_PLAYER = 71; -const MAX_POINTS_HUNTER_PET = 16; -const MAX_POINTS_HUNTER_PET_BM = 20; +const MAX_POINTS_PLAYER = 41; +const MAX_POINTS_HUNTER_PET = 17; +const MAX_POINTS_HUNTER_PET_BM = 21; export interface TalentsPickerConfig extends InputConfig, string> { klass: Class; diff --git a/ui/core/talents/trees/death_knight.json b/ui/core/talents/trees/death_knight.json index 9a7d21d46c..bd120592fb 100644 --- a/ui/core/talents/trees/death_knight.json +++ b/ui/core/talents/trees/death_knight.json @@ -1,1165 +1,828 @@ [ { - "name": "Blood", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/398.jpg", - "talents": [ - { - "fieldName": "butchery", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 48979, - 49483 - ], - "maxPoints": 2 - }, - { - "fieldName": "subversion", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 48997, - 49490, - 49491 - ], - "maxPoints": 3 - }, - { - "fieldName": "bladeBarrier", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 49182, - 49500, - 49501, - 55225, - 55226 - ], - "maxPoints": 5 - }, - { - "fieldName": "bladedArmor", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 48978, - 49390, - 49391, - 49392, - 49393 - ], - "maxPoints": 5 - }, - { - "fieldName": "scentOfBlood", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 49004, - 49508, - 49509 - ], - "maxPoints": 3 - }, - { - "fieldName": "twoHandedWeaponSpecialization", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 55107, - 55108 - ], - "maxPoints": 2 - }, - { - "fieldName": "runeTap", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 48982 - ], - "maxPoints": 1 - }, - { - "fieldName": "darkConviction", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 48987, - 49477, - 49478, - 49479, - 49480 - ], - "maxPoints": 5 - }, - { - "fieldName": "deathRuneMastery", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 49467, - 50033, - 50034 - ], - "maxPoints": 3 - }, - { - "fieldName": "improvedRuneTap", - "location": { - "rowIdx": 3, - "colIdx": 0 - }, - "spellIds": [ - 48985, - 49488, - 49489 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 2, - "colIdx": 0 - } - }, - { - "fieldName": "spellDeflection", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 49145, - 49495, - 49497 - ], - "maxPoints": 3 - }, - { - "fieldName": "vendetta", - "location": { - "rowIdx": 3, - "colIdx": 3 - }, - "spellIds": [ - 49015, - 50154, - 55136 - ], - "maxPoints": 3 - }, - { - "fieldName": "bloodyStrikes", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 48977, - 49394, - 49395 - ], - "maxPoints": 3 - }, - { - "fieldName": "veteranOfTheThirdWar", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 49006, - 49526, - 50029 - ], - "maxPoints": 3 - }, - { - "fieldName": "markOfBlood", - "location": { - "rowIdx": 4, - "colIdx": 3 - }, - "spellIds": [ - 49005 - ], - "maxPoints": 1 - }, - { - "fieldName": "bloodyVengeance", - "location": { - "rowIdx": 5, - "colIdx": 1 - }, - "spellIds": [ - 48988, - 49503, - 49504 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 2, - "colIdx": 1 - } - }, - { - "fieldName": "abominationsMight", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 53137, - 53138 - ], - "maxPoints": 2 - }, - { - "fieldName": "bloodworms", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 49027, - 49542, - 49543 - ], - "maxPoints": 3 - }, - { - "fieldName": "hysteria", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 49016 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedBloodPresence", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 50365, - 50371 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedDeathStrike", - "location": { - "rowIdx": 7, - "colIdx": 0 - }, - "spellIds": [ - 62905, - 62908 - ], - "maxPoints": 2 - }, - { - "fieldName": "suddenDoom", - "location": { - "rowIdx": 7, - "colIdx": 1 - }, - "spellIds": [ - 49018, - 49529, - 49530 - ], - "maxPoints": 3 - }, - { - "fieldName": "vampiricBlood", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 55233 - ], - "maxPoints": 1 - }, - { - "fieldName": "willOfTheNecropolis", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 49189, - 50149, - 50150 - ], - "maxPoints": 3 - }, - { - "fieldName": "heartStrike", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 55050 - ], - "maxPoints": 1 - }, - { - "fieldName": "mightOfMograine", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 49023, - 49533, - 49534 - ], - "maxPoints": 3 - }, - { - "fieldName": "bloodGorged", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 61154, - 61155, - 61156, - 61157, - 61158 - ], - "maxPoints": 5 - }, - { - "fieldName": "dancingRuneWeapon", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 49028 - ], - "maxPoints": 1 - } - - ] + "name": "Blood", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/398.jpg", + "talents": [ + { + "fieldName": "butchery", + "fancyName": "Butchery", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 48979, + 49483 + ], + "maxPoints": 2 + }, + { + "fieldName": "bladeBarrier", + "fancyName": "Blade Barrier", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 49182, + 49500, + 49501 + ], + "maxPoints": 3 + }, + { + "fieldName": "bladedArmor", + "fancyName": "Bladed Armor", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 48978, + 49390, + 49391, + 49393 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedBloodTap", + "fancyName": "Improved Blood Tap", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 94553, + 94555 + ], + "maxPoints": 2 + }, + { + "fieldName": "scentOfBlood", + "fancyName": "Scent Of Blood", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 49004, + 49508, + 49509 + ], + "maxPoints": 3 + }, + { + "fieldName": "scarletFever", + "fancyName": "Scarlet Fever", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 81131, + 81132 + ], + "maxPoints": 2 + }, + { + "fieldName": "handOfDoom", + "fancyName": "Hand Of Doom", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 85793, + 85794 + ], + "maxPoints": 2 + }, + { + "fieldName": "bloodCakedBlade", + "fancyName": "Blood Caked Blade", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 49219, + 49627, + 49628 + ], + "maxPoints": 3 + }, + { + "fieldName": "boneShield", + "fancyName": "Bone Shield", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 49222 + ], + "maxPoints": 1 + }, + { + "fieldName": "toughness", + "fancyName": "Toughness", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 49042, + 49786, + 49787 + ], + "maxPoints": 3 + }, + { + "fieldName": "abominationsMight", + "fancyName": "Abominations Might", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 53137, + 53138 + ], + "maxPoints": 2 + }, + { + "fieldName": "sanguineFortitude", + "fancyName": "Sanguine Fortitude", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 81125, + 81127 + ], + "maxPoints": 2 + }, + { + "fieldName": "bloodParasite", + "fancyName": "Blood Parasite", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 49027, + 49542 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedBloodPresence", + "fancyName": "Improved Blood Presence", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 50365, + 50371 + ], + "maxPoints": 2 + }, + { + "fieldName": "willOfTheNecropolis", + "fancyName": "Will Of The Necropolis", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 52284, + 81163, + 81164 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "runeTap", + "fancyName": "Rune Tap", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 48982 + ], + "maxPoints": 1 + }, + { + "fieldName": "vampiricBlood", + "fancyName": "Vampiric Blood", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 55233 + ], + "maxPoints": 1 + }, + { + "fieldName": "improvedDeathStrike", + "fancyName": "Improved Death Strike", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 62905, + 62908, + 81138 + ], + "maxPoints": 3 + }, + { + "fieldName": "crimsonScourge", + "fancyName": "Crimson Scourge", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 81135, + 81136 + ], + "maxPoints": 2 + }, + { + "fieldName": "dancingRuneWeapon", + "fancyName": "Dancing Rune Weapon", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 49028 + ], + "maxPoints": 1 + } + ] }, { - "name": "Frost", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/399.jpg", - "talents": [ - { - "fieldName": "improvedIcyTouch", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 49175, - 50031, - 51456 - ], - "maxPoints": 3 - }, - { - "fieldName": "runicPowerMastery", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 49455, - 50147 - ], - "maxPoints": 2 - }, - { - "fieldName": "toughness", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 49042, - 49786, - 49787, - 49788, - 49789 - ], - "maxPoints": 5 - }, - { - "fieldName": "icyReach", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 55061, - 55062 - ], - "maxPoints": 2 - }, - { - "fieldName": "blackIce", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 49140, - 49661, - 49662, - 49663, - 49664 - ], - "maxPoints": 5 - }, - { - "fieldName": "nervesOfColdSteel", - "location": { - "rowIdx": 1, - "colIdx": 3 - }, - "spellIds": [ - 49226, - 50137, - 50138 - ], - "maxPoints": 3 - }, - { - "fieldName": "icyTalons", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 50880, - 50884, - 50885, - 50886, - 50887 - ], - "maxPoints": 5, - "prereqLocation": { - "rowIdx": 0, - "colIdx": 0 - } - }, - { - "fieldName": "lichborne", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 49039 - ], - "maxPoints": 1 - }, - { - "fieldName": "annihilation", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 51468, - 51472, - 51473 - ], - "maxPoints": 3 - }, - { - "fieldName": "killingMachine", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 51123, - 51127, - 51128, - 51129, - 51130 - ], - "maxPoints": 5 - }, - { - "fieldName": "chillOfTheGrave", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 49149, - 50115 - ], - "maxPoints": 2 - }, - { - "fieldName": "endlessWinter", - "location": { - "rowIdx": 3, - "colIdx": 3 - }, - "spellIds": [ - 49137, - 49657 - ], - "maxPoints": 2 - }, - { - "fieldName": "frigidDreadplate", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 49186, - 51108, - 51109 - ], - "maxPoints": 3 - }, - { - "fieldName": "glacierRot", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 49471, - 49790, - 49791 - ], - "maxPoints": 3 - }, - { - "fieldName": "deathchill", - "location": { - "rowIdx": 4, - "colIdx": 3 - }, - "spellIds": [ - 49796 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedIcyTalons", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 55610 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 2, - "colIdx": 0 - } - }, - { - "fieldName": "mercilessCombat", - "location": { - "rowIdx": 5, - "colIdx": 1 - }, - "spellIds": [ - 49024, - 49538 - ], - "maxPoints": 2 - }, - { - "fieldName": "rime", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 49188, - 56822, - 59057 - ], - "maxPoints": 3 - }, - { - "fieldName": "chilblains", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 50040, - 50041, - 50043 - ], - "maxPoints": 3 - }, - { - "fieldName": "hungeringCold", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 49203 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedFrostPresence", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 50384, - 50385 - ], - "maxPoints": 2 - }, - { - "fieldName": "threatOfThassarian", - "location": { - "rowIdx": 7, - "colIdx": 0 - }, - "spellIds": [ - 65661, - 66191, - 66192 - ], - "maxPoints": 3 - }, - { - "fieldName": "bloodOfTheNorth", - "location": { - "rowIdx": 7, - "colIdx": 1 - }, - "spellIds": [ - 54639, - 54638, - 54637 - ], - "maxPoints": 3 - }, - { - "fieldName": "unbreakableArmor", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 51271 - ], - "maxPoints": 1 - }, - { - "fieldName": "acclimation", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 49200, - 50151, - 50152 - ], - "maxPoints": 3 - }, - { - "fieldName": "frostStrike", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 49143 - ], - "maxPoints": 1 - }, - { - "fieldName": "guileOfGorefiend", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 50187, - 50190, - 50191 - ], - "maxPoints": 3 - }, - { - "fieldName": "tundraStalker", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 49202, - 50127, - 50128, - 50129, - 50130 - ], - "maxPoints": 5 - }, - { - "fieldName": "howlingBlast", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 49184 - ], - "maxPoints": 1 - } - ] + "name": "Frost", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/399.jpg", + "talents": [ + { + "fieldName": "runicPowerMastery", + "fancyName": "Runic Power Mastery", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 49455, + 50147, + 91145 + ], + "maxPoints": 3 + }, + { + "fieldName": "icyReach", + "fancyName": "Icy Reach", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 55061, + 55062 + ], + "maxPoints": 2 + }, + { + "fieldName": "nervesOfColdSteel", + "fancyName": "Nerves Of Cold Steel", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 49226, + 50137, + 50138 + ], + "maxPoints": 3 + }, + { + "fieldName": "annihilation", + "fancyName": "Annihilation", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 51468, + 51472, + 51473 + ], + "maxPoints": 3 + }, + { + "fieldName": "lichborne", + "fancyName": "Lichborne", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 49039 + ], + "maxPoints": 1 + }, + { + "fieldName": "onAPaleHorse", + "fancyName": "On A Pale Horse", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 51983, + 51986 + ], + "maxPoints": 2 + }, + { + "fieldName": "endlessWinter", + "fancyName": "Endless Winter", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 49137, + 49657 + ], + "maxPoints": 2 + }, + { + "fieldName": "mercilessCombat", + "fancyName": "Merciless Combat", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 49024, + 49538 + ], + "maxPoints": 2 + }, + { + "fieldName": "chillOfTheGrave", + "fancyName": "Chill Of The Grave", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 49149, + 50115 + ], + "maxPoints": 2 + }, + { + "fieldName": "killingMachine", + "fancyName": "Killing Machine", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 51123, + 51127, + 51128 + ], + "maxPoints": 3 + }, + { + "fieldName": "rime", + "fancyName": "Rime", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 49188, + 56822, + 59057 + ], + "maxPoints": 3 + }, + { + "fieldName": "pillarOfFrost", + "fancyName": "Pillar Of Frost", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 51271 + ], + "maxPoints": 1 + }, + { + "fieldName": "improvedIcyTalons", + "fancyName": "Improved Icy Talons", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 55610 + ], + "maxPoints": 1 + }, + { + "fieldName": "brittleBones", + "fancyName": "Brittle Bones", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 81327, + 81328 + ], + "maxPoints": 2 + }, + { + "fieldName": "chilblains", + "fancyName": "Chilblains", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 50040, + 50041 + ], + "maxPoints": 2 + }, + { + "fieldName": "hungeringCold", + "fancyName": "Hungering Cold", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 49203 + ], + "maxPoints": 1 + }, + { + "fieldName": "improvedFrostPresence", + "fancyName": "Improved Frost Presence", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 50384, + 50385 + ], + "maxPoints": 2 + }, + { + "fieldName": "threatOfThassarian", + "fancyName": "Threat Of Thassarian", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 65661, + 66191, + 66192 + ], + "maxPoints": 3 + }, + { + "fieldName": "mightOfTheFrozenWastes", + "fancyName": "Might Of The Frozen Wastes", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 81330, + 81332, + 81333 + ], + "maxPoints": 3 + }, + { + "fieldName": "howlingBlast", + "fancyName": "Howling Blast", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 49184 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] }, { - "name": "Unholy", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/400.jpg", - "talents": [ - { - "fieldName": "viciousStrikes", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 51745, - 51746 - ], - "maxPoints": 2 - }, - { - "fieldName": "virulence", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 48962, - 49567, - 49568 - ], - "maxPoints": 3 - }, - { - "fieldName": "anticipation", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 55129, - 55130, - 55131, - 55132, - 55133 - ], - "maxPoints": 5 - }, - { - "fieldName": "epidemic", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 49036, - 49562 - ], - "maxPoints": 2 - }, - { - "fieldName": "morbidity", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 48963, - 49564, - 49565 - ], - "maxPoints": 3 - }, - { - "fieldName": "unholyCommand", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 49588, - 49589 - ], - "maxPoints": 2 - }, - { - "fieldName": "ravenousDead", - "location": { - "rowIdx": 1, - "colIdx": 3 - }, - "spellIds": [ - 48965, - 49571, - 49572 - ], - "maxPoints": 3 - }, - { - "fieldName": "outbreak", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 49013, - 55236, - 55237 - ], - "maxPoints": 3 - }, - { - "fieldName": "necrosis", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 51459, - 51462, - 51463, - 51464, - 51465 - ], - "maxPoints": 5 - }, - { - "fieldName": "corpseExplosion", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 49158 - ], - "maxPoints": 1 - }, - { - "fieldName": "onAPaleHorse", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 49146, - 51267 - ], - "maxPoints": 2 - }, - { - "fieldName": "bloodCakedBlade", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 49219, - 49627, - 49628 - ], - "maxPoints": 3 - }, - { - "fieldName": "nightOfTheDead", - "location": { - "rowIdx": 3, - "colIdx": 3 - }, - "spellIds": [ - 55620, - 55623 - ], - "maxPoints": 2 - }, - { - "fieldName": "unholyBlight", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 49194 - ], - "maxPoints": 1 - }, - { - "fieldName": "impurity", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 49220, - 49633, - 49635, - 49636, - 49638 - ], - "maxPoints": 5 - }, - { - "fieldName": "dirge", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 49223, - 49599 - ], - "maxPoints": 2 - }, - { - "fieldName": "desecration", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 55666, - 55667 - ], - "maxPoints": 2 - }, - { - "fieldName": "magicSuppression", - "location": { - "rowIdx": 5, - "colIdx": 1 - }, - "spellIds": [ - 49224, - 49610, - 49611 - ], - "maxPoints": 3 - }, - { - "fieldName": "reaping", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 49208, - 56834, - 56835 - ], - "maxPoints": 3 - }, - { - "fieldName": "masterOfGhouls", - "location": { - "rowIdx": 5, - "colIdx": 3 - }, - "spellIds": [ - 52143 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 3, - "colIdx": 3 - } - }, - { - "fieldName": "desolation", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 66799, - 66814, - 66815, - 66816, - 66817 - ], - "maxPoints": 5 - }, - { - "fieldName": "antiMagicZone", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 51052 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 5, - "colIdx": 1 - } - }, - { - "fieldName": "improvedUnholyPresence", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 50391, - 50392 - ], - "maxPoints": 2 - }, - { - "fieldName": "ghoulFrenzy", - "location": { - "rowIdx": 6, - "colIdx": 3 - }, - "spellIds": [ - 63560 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 5, - "colIdx": 3 - } - }, - { - "fieldName": "cryptFever", - "location": { - "rowIdx": 7, - "colIdx": 1 - }, - "spellIds": [ - 49032, - 49631, - 49632 - ], - "maxPoints": 3 - }, - { - "fieldName": "boneShield", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 49222 - ], - "maxPoints": 1 - }, - { - "fieldName": "wanderingPlague", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 49217, - 49654, - 49655 - ], - "maxPoints": 3 - }, - { - "fieldName": "ebonPlaguebringer", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 51099, - 51160, - 51161 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 7, - "colIdx": 1 - } - }, - { - "fieldName": "scourgeStrike", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 55090 - ], - "maxPoints": 1 - }, - { - "fieldName": "rageOfRivendare", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 50117, - 50118, - 50119, - 50120, - 50121 - ], - "maxPoints": 5 - }, - { - "fieldName": "summonGargoyle", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 49206 - ], - "maxPoints": 1 - } - - ] + "name": "Unholy", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/400.jpg", + "talents": [ + { + "fieldName": "unholyCommand", + "fancyName": "Unholy Command", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 49588, + 49589 + ], + "maxPoints": 2 + }, + { + "fieldName": "virulence", + "fancyName": "Virulence", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 48962, + 49567, + 49568 + ], + "maxPoints": 3 + }, + { + "fieldName": "epidemic", + "fancyName": "Epidemic", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 49036, + 49562, + 81334 + ], + "maxPoints": 3 + }, + { + "fieldName": "desecration", + "fancyName": "Desecration", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 55666, + 55667 + ], + "maxPoints": 2 + }, + { + "fieldName": "resilientInfection", + "fancyName": "Resilient Infection", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 81338, + 81339 + ], + "maxPoints": 2 + }, + { + "fieldName": "morbidity", + "fancyName": "Morbidity", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 48963, + 49564, + 49565 + ], + "maxPoints": 3 + }, + { + "fieldName": "runicCorruption", + "fancyName": "Runic Corruption", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 51459, + 51462 + ], + "maxPoints": 2 + }, + { + "fieldName": "unholyFrenzy", + "fancyName": "Unholy Frenzy", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 49016 + ], + "maxPoints": 1 + }, + { + "fieldName": "contagion", + "fancyName": "Contagion", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 91316, + 91319 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 0, + "colIdx": 2 + } + }, + { + "fieldName": "shadowInfusion", + "fancyName": "Shadow Infusion", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 48965, + 49571, + 49572 + ], + "maxPoints": 3 + }, + { + "fieldName": "deathsAdvance", + "fancyName": "Deaths Advance", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 96269, + 96270 + ], + "maxPoints": 2 + }, + { + "fieldName": "magicSuppression", + "fancyName": "Magic Suppression", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 49224, + 49610, + 49611 + ], + "maxPoints": 3 + }, + { + "fieldName": "rageOfRivendare", + "fancyName": "Rage Of Rivendare", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 51745, + 51746, + 91323 + ], + "maxPoints": 3 + }, + { + "fieldName": "unholyBlight", + "fancyName": "Unholy Blight", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 49194 + ], + "maxPoints": 1 + }, + { + "fieldName": "antiMagicZone", + "fancyName": "Anti Magic Zone", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 51052 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 1 + } + }, + { + "fieldName": "improvedUnholyPresence", + "fancyName": "Improved Unholy Presence", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 50391, + 50392 + ], + "maxPoints": 2 + }, + { + "fieldName": "darkTransformation", + "fancyName": "Dark Transformation", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 63560 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 3 + } + }, + { + "fieldName": "ebonPlaguebringer", + "fancyName": "Ebon Plaguebringer", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 51099, + 51160 + ], + "maxPoints": 2 + }, + { + "fieldName": "suddenDoom", + "fancyName": "Sudden Doom", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 49018, + 49529, + 49530 + ], + "maxPoints": 3 + }, + { + "fieldName": "summonGargoyle", + "fancyName": "Summon Gargoyle", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 49206 + ], + "maxPoints": 1 + } + ] } -] \ No newline at end of file + ] \ No newline at end of file diff --git a/ui/core/talents/trees/druid.json b/ui/core/talents/trees/druid.json index 3d2032589b..70904a0968 100644 --- a/ui/core/talents/trees/druid.json +++ b/ui/core/talents/trees/druid.json @@ -1,1187 +1,881 @@ [ { - "name": "Balance", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/283.jpg", - "talents": [ - { - "fieldName": "starlightWrath", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 16814, - 16815, - 16816, - 16817, - 16818 - ], - "maxPoints": 5 - }, - { - "fieldName": "genesis", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 57810, - 57811, - 57812, - 57813, - 57814 - ], - "maxPoints": 5 - }, - { - "fieldName": "moonglow", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 16845, - 16846, - 16847 - ], - "maxPoints": 3 - }, - { - "fieldName": "naturesMajesty", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 35363, - 35364 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedMoonfire", - "location": { - "rowIdx": 1, - "colIdx": 3 - }, - "spellIds": [ - 16821, - 16822 - ], - "maxPoints": 2 - }, - { - "fieldName": "brambles", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 16836, - 16839, - 16840 - ], - "maxPoints": 3 - }, - { - "fieldName": "naturesGrace", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 16880, - 61345, - 61346 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 1, - "colIdx": 1 - } - }, - { - "fieldName": "naturesSplendor", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 57865 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 1, - "colIdx": 1 - } - }, - { - "fieldName": "naturesReach", - "location": { - "rowIdx": 2, - "colIdx": 3 - }, - "spellIds": [ - 16819, - 16820 - ], - "maxPoints": 2 - }, - { - "fieldName": "vengeance", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 16909, - 16910, - 16911, - 16912, - 16913 - ], - "maxPoints": 5 - }, - { - "fieldName": "celestialFocus", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 16850, - 16923, - 16924 - ], - "maxPoints": 3 - }, - { - "fieldName": "lunarGuidance", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 33589, - 33590, - 33591 - ], - "maxPoints": 3 - }, - { - "fieldName": "insectSwarm", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 5570 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedInsectSwarm", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 57849, - 57850, - 57851 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "dreamstate", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 33597, - 33599, - 33956 - ], - "maxPoints": 3 - }, - { - "fieldName": "moonfury", - "location": { - "rowIdx": 5, - "colIdx": 1 - }, - "spellIds": [ - 16896, - 16897, - 16899 - ], - "maxPoints": 3 - }, - { - "fieldName": "balanceOfPower", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 33592, - 33596 - ], - "maxPoints": 2 - }, - { - "fieldName": "moonkinForm", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 24858 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedMoonkinForm", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 48384, - 48395, - 48396 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "improvedFaerieFire", - "location": { - "rowIdx": 6, - "colIdx": 3 - }, - "spellIds": [ - 33600, - 33601, - 33602 - ], - "maxPoints": 3 - }, - { - "fieldName": "owlkinFrenzy", - "location": { - "rowIdx": 7, - "colIdx": 0 - }, - "spellIds": [ - 48389, - 48392, - 48393 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "wrathOfCenarius", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 33603, - 33604, - 33605, - 33606, - 33607 - ], - "maxPoints": 5 - }, - { - "fieldName": "eclipse", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 48516, - 48521, - 48525 - ], - "maxPoints": 3 - }, - { - "fieldName": "typhoon", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 50516 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "forceOfNature", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 33831 - ], - "maxPoints": 1 - }, - { - "fieldName": "galeWinds", - "location": { - "rowIdx": 8, - "colIdx": 3 - }, - "spellIds": [ - 48488, - 48514 - ], - "maxPoints": 2 - }, - { - "fieldName": "earthAndMoon", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 48506, - 48510, - 48511 - ], - "maxPoints": 3 - }, - { - "fieldName": "starfall", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 48505 - ], - "maxPoints": 1 - } - ] + "name": "Balance", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/752.jpg", + "talents": [ + { + "fieldName": "naturesGrace", + "fancyName": "Natures Grace", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 16880, + 61345, + 61346 + ], + "maxPoints": 3 + }, + { + "fieldName": "starlightWrath", + "fancyName": "Starlight Wrath", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 16814, + 16815, + 16816 + ], + "maxPoints": 3 + }, + { + "fieldName": "naturesMajesty", + "fancyName": "Natures Majesty", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 35363, + 35364 + ], + "maxPoints": 2 + }, + { + "fieldName": "genesis", + "fancyName": "Genesis", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 57810, + 57811, + 57812 + ], + "maxPoints": 3 + }, + { + "fieldName": "moonglow", + "fancyName": "Moonglow", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 16845, + 16846, + 16847 + ], + "maxPoints": 3 + }, + { + "fieldName": "balanceOfPower", + "fancyName": "Balance Of Power", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 33592, + 33596 + ], + "maxPoints": 2 + }, + { + "fieldName": "euphoria", + "fancyName": "Euphoria", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 81061, + 81062 + ], + "maxPoints": 2 + }, + { + "fieldName": "moonkinForm", + "fancyName": "Moonkin Form", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 24858 + ], + "maxPoints": 1 + }, + { + "fieldName": "typhoon", + "fancyName": "Typhoon", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 50516 + ], + "maxPoints": 1 + }, + { + "fieldName": "shootingStars", + "fancyName": "Shooting Stars", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 93398, + 93399 + ], + "maxPoints": 2 + }, + { + "fieldName": "owlkinFrenzy", + "fancyName": "Owlkin Frenzy", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 48389, + 48392, + 48393 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "galeWinds", + "fancyName": "Gale Winds", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 48488, + 48514 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 2 + } + }, + { + "fieldName": "solarBeam", + "fancyName": "Solar Beam", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 78675 + ], + "maxPoints": 1 + }, + { + "fieldName": "dreamstate", + "fancyName": "Dreamstate", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 33597, + 33599 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 0 + } + }, + { + "fieldName": "forceOfNature", + "fancyName": "Force Of Nature", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 33831 + ], + "maxPoints": 1 + }, + { + "fieldName": "sunfire", + "fancyName": "Sunfire", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 93401 + ], + "maxPoints": 1 + }, + { + "fieldName": "earthAndMoon", + "fancyName": "Earth And Moon", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 48506 + ], + "maxPoints": 1 + }, + { + "fieldName": "fungalGrowth", + "fancyName": "Fungal Growth", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 78788, + 78789 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "lunarShower", + "fancyName": "Lunar Shower", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 33603, + 33605, + 33604 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 2 + } + }, + { + "fieldName": "starfall", + "fancyName": "Starfall", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 48505 + ], + "maxPoints": 1 + } + ] }, { - "name": "Feral Combat", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/281.jpg", - "talents": [ - { - "fieldName": "ferocity", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 16934, - 16935, - 16936, - 16937, - 16938 - ], - "maxPoints": 5 - }, - { - "fieldName": "feralAggression", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 16858, - 16859, - 16860, - 16861, - 16862 - ], - "maxPoints": 5 - }, - { - "fieldName": "feralInstinct", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 16947, - 16948, - 16949 - ], - "maxPoints": 3 - }, - { - "fieldName": "savageFury", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 16998, - 16999 - ], - "maxPoints": 2 - }, - { - "fieldName": "thickHide", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 16929, - 16930, - 16931 - ], - "maxPoints": 3 - }, - { - "fieldName": "feralSwiftness", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 17002, - 24866 - ], - "maxPoints": 2 - }, - { - "fieldName": "survivalInstincts", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 61336 - ], - "maxPoints": 1 - }, - { - "fieldName": "sharpenedClaws", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 16942, - 16943, - 16944 - ], - "maxPoints": 3 - }, - { - "fieldName": "shreddingAttacks", - "location": { - "rowIdx": 3, - "colIdx": 0 - }, - "spellIds": [ - 16966, - 16968 - ], - "maxPoints": 2 - }, - { - "fieldName": "predatoryStrikes", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 16972, - 16974, - 16975 - ], - "maxPoints": 3 - }, - { - "fieldName": "primalFury", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 37116, - 37117 - ], - "maxPoints": 2, - "prereqLocation": { - "rowIdx": 2, - "colIdx": 2 - } - }, - { - "fieldName": "primalPrecision", - "location": { - "rowIdx": 3, - "colIdx": 3 - }, - "spellIds": [ - 48409, - 48410 - ], - "maxPoints": 2, - "prereqLocation": { - "rowIdx": 2, - "colIdx": 2 - } - }, - { - "fieldName": "brutalImpact", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 16940, - 16941 - ], - "maxPoints": 2 - }, - { - "fieldName": "feralCharge", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 49377 - ], - "maxPoints": 1 - }, - { - "fieldName": "nurturingInstinct", - "location": { - "rowIdx": 4, - "colIdx": 3 - }, - "spellIds": [ - 33872, - 33873 - ], - "maxPoints": 2 - }, - { - "fieldName": "naturalReaction", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 57878, - 57880, - 57881 - ], - "maxPoints": 3 - }, - { - "fieldName": "heartOfTheWild", - "location": { - "rowIdx": 5, - "colIdx": 1 - }, - "spellIds": [ - 17003, - 17004, - 17005, - 17006, - 24894 - ], - "maxPoints": 5, - "prereqLocation": { - "rowIdx": 3, - "colIdx": 1 - } - }, - { - "fieldName": "survivalOfTheFittest", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 33853, - 33855, - 33856 - ], - "maxPoints": 3 - }, - { - "fieldName": "leaderOfThePack", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 17007 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedLeaderOfThePack", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 34297, - 34300 - ], - "maxPoints": 2, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "primalTenacity", - "location": { - "rowIdx": 6, - "colIdx": 3 - }, - "spellIds": [ - 33851, - 33852, - 33957 - ], - "maxPoints": 3 - }, - { - "fieldName": "protectorOfThePack", - "location": { - "rowIdx": 7, - "colIdx": 0 - }, - "spellIds": [ - 57873, - 57876, - 57877 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "predatoryInstincts", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 33859, - 33866, - 33867 - ], - "maxPoints": 3 - }, - { - "fieldName": "infectedWounds", - "location": { - "rowIdx": 7, - "colIdx": 3 - }, - "spellIds": [ - 48483, - 48484, - 48485 - ], - "maxPoints": 3 - }, - { - "fieldName": "kingOfTheJungle", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 48492, - 48494, - 48495 - ], - "maxPoints": 3 - }, - { - "fieldName": "mangle", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 33917 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "improvedMangle", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 48532, - 48489, - 48491 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 8, - "colIdx": 1 - } - }, - { - "fieldName": "rendAndTear", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 48432, - 48433, - 48434, - 51268, - 51269 - ], - "maxPoints": 5 - }, - { - "fieldName": "primalGore", - "location": { - "rowIdx": 9, - "colIdx": 2 - }, - "spellIds": [ - 63503 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 9, - "colIdx": 1 - } - }, - { - "fieldName": "berserk", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 50334 - ], - "maxPoints": 1 - } - ] + "name": "Feral Combat", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/750.jpg", + "talents": [ + { + "fieldName": "feralSwiftness", + "fancyName": "Feral Swiftness", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 17002, + 24866 + ], + "maxPoints": 2 + }, + { + "fieldName": "furor", + "fancyName": "Furor", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 17056, + 17058, + 17059 + ], + "maxPoints": 3 + }, + { + "fieldName": "predatoryStrikes", + "fancyName": "Predatory Strikes", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 16972, + 16974 + ], + "maxPoints": 2 + }, + { + "fieldName": "infectedWounds", + "fancyName": "Infected Wounds", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 48483, + 48484 + ], + "maxPoints": 2 + }, + { + "fieldName": "furySwipes", + "fancyName": "Fury Swipes", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 48532, + 80552, + 80553 + ], + "maxPoints": 3 + }, + { + "fieldName": "primalFury", + "fancyName": "Primal Fury", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 37116, + 37117 + ], + "maxPoints": 2 + }, + { + "fieldName": "feralAggression", + "fancyName": "Feral Aggression", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 16858, + 16859 + ], + "maxPoints": 2 + }, + { + "fieldName": "kingOfTheJungle", + "fancyName": "King Of The Jungle", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 48492, + 48494, + 48495 + ], + "maxPoints": 3 + }, + { + "fieldName": "feralCharge", + "fancyName": "Feral Charge", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 49377 + ], + "maxPoints": 1 + }, + { + "fieldName": "stampede", + "fancyName": "Stampede", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 78892, + 78893 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "thickHide", + "fancyName": "Thick Hide", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 16929, + 16930, + 16931 + ], + "maxPoints": 3 + }, + { + "fieldName": "leaderOfThePack", + "fancyName": "Leader Of The Pack", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 17007 + ], + "maxPoints": 1 + }, + { + "fieldName": "brutalImpact", + "fancyName": "Brutal Impact", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 16940, + 16941 + ], + "maxPoints": 2 + }, + { + "fieldName": "nurturingInstinct", + "fancyName": "Nurturing Instinct", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 33872, + 33873 + ], + "maxPoints": 2 + }, + { + "fieldName": "primalMadness", + "fancyName": "Primal Madness", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 80316, + 80317 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 0 + } + }, + { + "fieldName": "survivalInstincts", + "fancyName": "Survival Instincts", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 61336 + ], + "maxPoints": 1 + }, + { + "fieldName": "endlessCarnage", + "fancyName": "Endless Carnage", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 80314, + 80315 + ], + "maxPoints": 2 + }, + { + "fieldName": "naturalReaction", + "fancyName": "Natural Reaction", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 57878, + 57880 + ], + "maxPoints": 2 + }, + { + "fieldName": "bloodInTheWater", + "fancyName": "Blood In The Water", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 80318, + 80319 + ], + "maxPoints": 2 + }, + { + "fieldName": "rendAndTear", + "fancyName": "Rend And Tear", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 48432, + 48433, + 48434 + ], + "maxPoints": 3 + }, + { + "fieldName": "pulverize", + "fancyName": "Pulverize", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 80313 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 5, + "colIdx": 1 + } + }, + { + "fieldName": "berserk", + "fancyName": "Berserk", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 50334 + ], + "maxPoints": 1 + } + ] }, { - "name": "Restoration", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/282.jpg", - "talents": [ - { - "fieldName": "improvedMarkOfTheWild", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 17050, - 17051 - ], - "maxPoints": 2 - }, - { - "fieldName": "naturesFocus", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 17063, - 17065, - 17066 - ], - "maxPoints": 3 - }, - { - "fieldName": "furor", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 17056, - 17058, - 17059, - 17060, - 17061 - ], - "maxPoints": 5 - }, - { - "fieldName": "naturalist", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 17069, - 17070, - 17071, - 17072, - 17073 - ], - "maxPoints": 5 - }, - { - "fieldName": "subtlety", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 17118, - 17119, - 17120 - ], - "maxPoints": 3 - }, - { - "fieldName": "naturalShapeshifter", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 16833, - 16834, - 16835 - ], - "maxPoints": 3 - }, - { - "fieldName": "intensity", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 17106, - 17107, - 17108 - ], - "maxPoints": 3 - }, - { - "fieldName": "omenOfClarity", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 16864 - ], - "maxPoints": 1 - }, - { - "fieldName": "masterShapeshifter", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 48411, - 48412 - ], - "maxPoints": 2, - "prereqLocation": { - "rowIdx": 1, - "colIdx": 2 - } - }, - { - "fieldName": "tranquilSpirit", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 24968, - 24969, - 24970, - 24971, - 24972 - ], - "maxPoints": 5 - }, - { - "fieldName": "improvedRejuvenation", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 17111, - 17112, - 17113 - ], - "maxPoints": 3 - }, - { - "fieldName": "naturesSwiftness", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 17116 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 2, - "colIdx": 0 - } - }, - { - "fieldName": "giftOfNature", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 17104, - 24943, - 24944, - 24945, - 24946 - ], - "maxPoints": 5 - }, - { - "fieldName": "improvedTranquility", - "location": { - "rowIdx": 4, - "colIdx": 3 - }, - "spellIds": [ - 17123, - 17124 - ], - "maxPoints": 2 - }, - { - "fieldName": "empoweredTouch", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 33879, - 33880 - ], - "maxPoints": 2 - }, - { - "fieldName": "naturesBounty", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 17074, - 17075, - 17076, - 17077, - 17078 - ], - "maxPoints": 5, - "prereqLocation": { - "rowIdx": 3, - "colIdx": 2 - } - }, - { - "fieldName": "livingSpirit", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 34151, - 34152, - 34153 - ], - "maxPoints": 3 - }, - { - "fieldName": "swiftmend", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 18562 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "naturalPerfection", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 33881, - 33882, - 33883 - ], - "maxPoints": 3 - }, - { - "fieldName": "empoweredRejuvenation", - "location": { - "rowIdx": 7, - "colIdx": 1 - }, - "spellIds": [ - 33886, - 33887, - 33888, - 33889, - 33890 - ], - "maxPoints": 5 - }, - { - "fieldName": "livingSeed", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 48496, - 48499, - 48500 - ], - "maxPoints": 3 - }, - { - "fieldName": "revitalize", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 48539, - 48544, - 48545 - ], - "maxPoints": 3 - }, - { - "fieldName": "treeOfLife", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 65139 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 7, - "colIdx": 1 - } - }, - { - "fieldName": "improvedTreeOfLife", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 48535, - 48536, - 48537 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 8, - "colIdx": 1 - } - }, - { - "fieldName": "improvedBarkskin", - "location": { - "rowIdx": 9, - "colIdx": 0 - }, - "spellIds": [ - 63410, - 63411 - ], - "maxPoints": 2 - }, - { - "fieldName": "giftOfTheEarthmother", - "location": { - "rowIdx": 9, - "colIdx": 2 - }, - "spellIds": [ - 51179, - 51180, - 51181, - 51182, - 51183 - ], - "maxPoints": 5 - }, - { - "fieldName": "wildGrowth", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 48438 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 8, - "colIdx": 1 - } - } - ] + "name": "Restoration", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/748.jpg", + "talents": [ + { + "fieldName": "blessingOfTheGrove", + "fancyName": "Blessing Of The Grove", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 78784, + 78785 + ], + "maxPoints": 2 + }, + { + "fieldName": "naturalShapeshifter", + "fancyName": "Natural Shapeshifter", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 16833, + 16834 + ], + "maxPoints": 2 + }, + { + "fieldName": "naturalist", + "fancyName": "Naturalist", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 17069, + 17070 + ], + "maxPoints": 2 + }, + { + "fieldName": "heartOfTheWild", + "fancyName": "Heart Of The Wild", + "location": { + "rowIdx": 0, + "colIdx": 3 + }, + "spellIds": [ + 17003, + 17004, + 17005 + ], + "maxPoints": 3 + }, + { + "fieldName": "perseverance", + "fancyName": "Perseverance", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 78734, + 78736, + 78735, + 78737, + 78738 + ], + "maxPoints": 3 + }, + { + "fieldName": "masterShapeshifter", + "fancyName": "Master Shapeshifter", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 48411 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 0, + "colIdx": 1 + } + }, + { + "fieldName": "improvedRejuvenation", + "fancyName": "Improved Rejuvenation", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 17111, + 17112, + 17113 + ], + "maxPoints": 3 + }, + { + "fieldName": "livingSeed", + "fancyName": "Living Seed", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 48496, + 48499, + 48500 + ], + "maxPoints": 3 + }, + { + "fieldName": "revitalize", + "fancyName": "Revitalize", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 48539, + 48544 + ], + "maxPoints": 2 + }, + { + "fieldName": "naturesSwiftness", + "fancyName": "Natures Swiftness", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 17116 + ], + "maxPoints": 1 + }, + { + "fieldName": "furyOfStormrage", + "fancyName": "Fury Of Stormrage", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 17104, + 24943 + ], + "maxPoints": 2 + }, + { + "fieldName": "naturesBounty", + "fancyName": "Natures Bounty", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 17074, + 17075, + 17076 + ], + "maxPoints": 3 + }, + { + "fieldName": "empoweredTouch", + "fancyName": "Empowered Touch", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 33879, + 33880 + ], + "maxPoints": 2 + }, + { + "fieldName": "malfurionsGift", + "fancyName": "Malfurions Gift", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 92363, + 92364 + ], + "maxPoints": 2 + }, + { + "fieldName": "efflorescence", + "fancyName": "Efflorescence", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 34151, + 81274, + 81275 + ], + "maxPoints": 3 + }, + { + "fieldName": "wildGrowth", + "fancyName": "Wild Growth", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 48438 + ], + "maxPoints": 1 + }, + { + "fieldName": "naturesCure", + "fancyName": "Natures Cure", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 88423 + ], + "maxPoints": 1 + }, + { + "fieldName": "naturesWard", + "fancyName": "Natures Ward", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 33881, + 33882 + ], + "maxPoints": 2 + }, + { + "fieldName": "giftOfTheEarthmother", + "fancyName": "Gift Of The Earthmother", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 51179, + 51180, + 51181 + ], + "maxPoints": 3 + }, + { + "fieldName": "swiftRejuvenation", + "fancyName": "Swift Rejuvenation", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 33886 + ], + "maxPoints": 1 + }, + { + "fieldName": "treeOfLife", + "fancyName": "Tree Of Life", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 33891 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] } -] \ No newline at end of file + ] \ No newline at end of file diff --git a/ui/core/talents/trees/hunter.json b/ui/core/talents/trees/hunter.json index 0bfae96722..1e83fde801 100644 --- a/ui/core/talents/trees/hunter.json +++ b/ui/core/talents/trees/hunter.json @@ -1,1121 +1,815 @@ [ { - "name": "Beast Mastery", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/361.jpg", - "talents": [ - { - "fieldName": "improvedAspectOfTheHawk", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 19552, - 19553, - 19554, - 19555, - 19556 - ], - "maxPoints": 5 - }, - { - "fieldName": "enduranceTraining", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 19583, - 19584, - 19585, - 19586, - 19587 - ], - "maxPoints": 5 - }, - { - "fieldName": "focusedFire", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 35029, - 35030 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedAspectOfTheMonkey", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 19549, - 19550, - 19551 - ], - "maxPoints": 3 - }, - { - "fieldName": "thickHide", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 19609, - 19610, - 19612 - ], - "maxPoints": 3 - }, - { - "fieldName": "improvedRevivePet", - "location": { - "rowIdx": 1, - "colIdx": 3 - }, - "spellIds": [ - 24443, - 19575 - ], - "maxPoints": 2 - }, - { - "fieldName": "pathfinding", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 19559, - 19560 - ], - "maxPoints": 2 - }, - { - "fieldName": "aspectMastery", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 53265 - ], - "maxPoints": 1 - }, - { - "fieldName": "unleashedFury", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 19616, - 19617, - 19618, - 19619, - 19620 - ], - "maxPoints": 5 - }, - { - "fieldName": "improvedMendPet", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 19572, - 19573 - ], - "maxPoints": 2 - }, - { - "fieldName": "ferocity", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 19598, - 19599, - 19600, - 19601, - 19602 - ], - "maxPoints": 5 - }, - { - "fieldName": "spiritBond", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 19578, - 20895 - ], - "maxPoints": 2 - }, - { - "fieldName": "intimidation", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 19577 - ], - "maxPoints": 1 - }, - { - "fieldName": "bestialDiscipline", - "location": { - "rowIdx": 4, - "colIdx": 3 - }, - "spellIds": [ - 19590, - 19592 - ], - "maxPoints": 2 - }, - { - "fieldName": "animalHandler", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 34453, - 34454 - ], - "maxPoints": 2 - }, - { - "fieldName": "frenzy", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 19621, - 19622, - 19623, - 19624, - 19625 - ], - "maxPoints": 5, - "prereqLocation": { - "rowIdx": 3, - "colIdx": 2 - } - }, - { - "fieldName": "ferociousInspiration", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 34455, - 34459, - 34460 - ], - "maxPoints": 3 - }, - { - "fieldName": "bestialWrath", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 19574 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "catlikeReflexes", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 34462, - 34464, - 34465 - ], - "maxPoints": 3 - }, - { - "fieldName": "invigoration", - "location": { - "rowIdx": 7, - "colIdx": 0 - }, - "spellIds": [ - 53252, - 53253 - ], - "maxPoints": 2, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 0 - } - }, - { - "fieldName": "serpentsSwiftness", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 34466, - 34467, - 34468, - 34469, - 34470 - ], - "maxPoints": 5 - }, - { - "fieldName": "longevity", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 53262, - 53263, - 53264 - ], - "maxPoints": 3 - }, - { - "fieldName": "theBeastWithin", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 34692 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "cobraStrikes", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 53256, - 53259, - 53260 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 7, - "colIdx": 2 - } - }, - { - "fieldName": "kindredSpirits", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 56314, - 56315, - 56316, - 56317, - 56318 - ], - "maxPoints": 5 - }, - { - "fieldName": "beastMastery", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 53270 - ], - "maxPoints": 1 - } - ] + "name": "Beast Mastery", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/811.jpg", + "talents": [ + { + "fieldName": "improvedKillCommand", + "fancyName": "Improved Kill Command", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 35029, + 35030 + ], + "maxPoints": 2 + }, + { + "fieldName": "oneWithNature", + "fancyName": "One With Nature", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 82682, + 82683, + 82684 + ], + "maxPoints": 3 + }, + { + "fieldName": "bestialDiscipline", + "fancyName": "Bestial Discipline", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 19590, + 19592, + 82687 + ], + "maxPoints": 3 + }, + { + "fieldName": "pathfinding", + "fancyName": "Pathfinding", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 19559, + 19560 + ], + "maxPoints": 2 + }, + { + "fieldName": "spiritBond", + "fancyName": "Spirit Bond", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 19578, + 20895 + ], + "maxPoints": 2 + }, + { + "fieldName": "frenzy", + "fancyName": "Frenzy", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 19621, + 19622, + 19623 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedMendPet", + "fancyName": "Improved Mend Pet", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 19572, + 19573 + ], + "maxPoints": 2 + }, + { + "fieldName": "cobraStrikes", + "fancyName": "Cobra Strikes", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 53256, + 53259, + 53260 + ], + "maxPoints": 3 + }, + { + "fieldName": "fervor", + "fancyName": "Fervor", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 82726 + ], + "maxPoints": 1 + }, + { + "fieldName": "focusFire", + "fancyName": "Focus Fire", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 82692 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 1, + "colIdx": 2 + } + }, + { + "fieldName": "longevity", + "fancyName": "Longevity", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 53262, + 53263, + 53264 + ], + "maxPoints": 3 + }, + { + "fieldName": "killingStreak", + "fancyName": "Killing Streak", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 82748, + 82749 + ], + "maxPoints": 2 + }, + { + "fieldName": "crouchingTigerHiddenChimera", + "fancyName": "Crouching Tiger Hidden Chimera", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 82898, + 82899 + ], + "maxPoints": 2 + }, + { + "fieldName": "bestialWrath", + "fancyName": "Bestial Wrath", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 19574 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "ferociousInspiration", + "fancyName": "Ferocious Inspiration", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 34460 + ], + "maxPoints": 1 + }, + { + "fieldName": "kindredSpirits", + "fancyName": "Kindred Spirits", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 56314, + 56315 + ], + "maxPoints": 2 + }, + { + "fieldName": "theBeastWithin", + "fancyName": "The Beast Within", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 34692 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "invigoration", + "fancyName": "Invigoration", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 53252, + 53253 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 2 + } + }, + { + "fieldName": "beastMastery", + "fancyName": "Beast Mastery", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 53270 + ], + "maxPoints": 1 + } + ] }, { - "name": "Marksmanship", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/363.jpg", - "talents": [ - { - "fieldName": "improvedConcussiveShot", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 19407, - 19412 - ], - "maxPoints": 2 - }, - { - "fieldName": "focusedAim", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 53620, - 53621, - 53622 - ], - "maxPoints": 3 - }, - { - "fieldName": "lethalShots", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 19426, - 19427, - 19429, - 19430, - 19431 - ], - "maxPoints": 5 - }, - { - "fieldName": "carefulAim", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 34482, - 34483, - 34484 - ], - "maxPoints": 3 - }, - { - "fieldName": "improvedHuntersMark", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 19421, - 19422, - 19423 - ], - "maxPoints": 3 - }, - { - "fieldName": "mortalShots", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 19485, - 19487, - 19488, - 19489, - 19490 - ], - "maxPoints": 5 - }, - { - "fieldName": "goForTheThroat", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 34950, - 34954 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedArcaneShot", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 19454, - 19455, - 19456 - ], - "maxPoints": 3 - }, - { - "fieldName": "aimedShot", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 19434 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 1, - "colIdx": 2 - } - }, - { - "fieldName": "rapidKilling", - "location": { - "rowIdx": 2, - "colIdx": 3 - }, - "spellIds": [ - 34948, - 34949 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedStings", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 19464, - 19465, - 19466 - ], - "maxPoints": 3 - }, - { - "fieldName": "efficiency", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 19416, - 19417, - 19418, - 19419, - 19420 - ], - "maxPoints": 5 - }, - { - "fieldName": "concussiveBarrage", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 35100, - 35102 - ], - "maxPoints": 2 - }, - { - "fieldName": "readiness", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 23989 - ], - "maxPoints": 1 - }, - { - "fieldName": "barrage", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 19461, - 19462, - 24691 - ], - "maxPoints": 3 - }, - { - "fieldName": "combatExperience", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 34475, - 34476 - ], - "maxPoints": 2 - }, - { - "fieldName": "rangedWeaponSpecialization", - "location": { - "rowIdx": 5, - "colIdx": 3 - }, - "spellIds": [ - 19507, - 19508, - 19509 - ], - "maxPoints": 3 - }, - { - "fieldName": "piercingShots", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 53234, - 53237, - 53238 - ], - "maxPoints": 3 - }, - { - "fieldName": "trueshotAura", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 19506 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "improvedBarrage", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 35104, - 35110, - 35111 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 2 - } - }, - { - "fieldName": "masterMarksman", - "location": { - "rowIdx": 7, - "colIdx": 1 - }, - "spellIds": [ - 34485, - 34486, - 34487, - 34488, - 34489 - ], - "maxPoints": 5 - }, - { - "fieldName": "rapidRecuperation", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 53228, - 53232 - ], - "maxPoints": 2 - }, - { - "fieldName": "wildQuiver", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 53215, - 53216, - 53217 - ], - "maxPoints": 3 - }, - { - "fieldName": "silencingShot", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 34490 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 7, - "colIdx": 1 - } - }, - { - "fieldName": "improvedSteadyShot", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 53221, - 53222, - 53224 - ], - "maxPoints": 3 - }, - { - "fieldName": "markedForDeath", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 53241, - 53243, - 53244, - 53245, - 53246 - ], - "maxPoints": 5 - }, - { - "fieldName": "chimeraShot", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 53209 - ], - "maxPoints": 1 - } - ] + "name": "Marksmanship", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/807.jpg", + "talents": [ + { + "fieldName": "goForTheThroat", + "fancyName": "Go For The Throat", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 34950, + 34954 + ], + "maxPoints": 2 + }, + { + "fieldName": "efficiency", + "fancyName": "Efficiency", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 19416, + 19417, + 19418 + ], + "maxPoints": 3 + }, + { + "fieldName": "rapidKilling", + "fancyName": "Rapid Killing", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 34948, + 34949 + ], + "maxPoints": 2 + }, + { + "fieldName": "sicEm", + "fancyName": "Sic Em", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 83340, + 83356 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 0, + "colIdx": 0 + } + }, + { + "fieldName": "improvedSteadyShot", + "fancyName": "Improved Steady Shot", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 53221, + 53222, + 53224 + ], + "maxPoints": 3 + }, + { + "fieldName": "carefulAim", + "fancyName": "Careful Aim", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 34482, + 34483 + ], + "maxPoints": 2 + }, + { + "fieldName": "silencingShot", + "fancyName": "Silencing Shot", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 34490 + ], + "maxPoints": 1 + }, + { + "fieldName": "concussiveBarrage", + "fancyName": "Concussive Barrage", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 35100, + 35102 + ], + "maxPoints": 2 + }, + { + "fieldName": "piercingShots", + "fancyName": "Piercing Shots", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 53234, + 53237, + 53238 + ], + "maxPoints": 3 + }, + { + "fieldName": "bombardment", + "fancyName": "Bombardment", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 35104, + 35110 + ], + "maxPoints": 2 + }, + { + "fieldName": "trueshotAura", + "fancyName": "Trueshot Aura", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 19506 + ], + "maxPoints": 1 + }, + { + "fieldName": "termination", + "fancyName": "Termination", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 83489, + 83490 + ], + "maxPoints": 2 + }, + { + "fieldName": "resistanceIsFutile", + "fancyName": "Resistance Is Futile", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 82893, + 82894 + ], + "maxPoints": 2 + }, + { + "fieldName": "rapidRecuperation", + "fancyName": "Rapid Recuperation", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 53228, + 53232 + ], + "maxPoints": 2 + }, + { + "fieldName": "masterMarksman", + "fancyName": "Master Marksman", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 34485, + 34486, + 34487 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "readiness", + "fancyName": "Readiness", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 23989 + ], + "maxPoints": 1 + }, + { + "fieldName": "posthaste", + "fancyName": "Posthaste", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 83558, + 83560 + ], + "maxPoints": 2 + }, + { + "fieldName": "markedForDeath", + "fancyName": "Marked For Death", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 53241, + 53243 + ], + "maxPoints": 2 + }, + { + "fieldName": "chimeraShot", + "fancyName": "Chimera Shot", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 53209 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] }, { - "name": "Survival", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/362.jpg", - "talents": [ - { - "fieldName": "improvedTracking", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 52783, - 52785, - 52786, - 52787, - 52788 - ], - "maxPoints": 5 - }, - { - "fieldName": "hawkEye", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 19498, - 19499, - 19500 - ], - "maxPoints": 3 - }, - { - "fieldName": "savageStrikes", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 19159, - 19160 - ], - "maxPoints": 2 - }, - { - "fieldName": "surefooted", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 19290, - 19294, - 24283 - ], - "maxPoints": 3 - }, - { - "fieldName": "entrapment", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 19184, - 19387, - 19388 - ], - "maxPoints": 3 - }, - { - "fieldName": "trapMastery", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 19376, - 63457, - 63458 - ], - "maxPoints": 3 - }, - { - "fieldName": "survivalInstincts", - "location": { - "rowIdx": 1, - "colIdx": 3 - }, - "spellIds": [ - 34494, - 34496 - ], - "maxPoints": 2 - }, - { - "fieldName": "survivalist", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 19255, - 19256, - 19257, - 19258, - 19259 - ], - "maxPoints": 5 - }, - { - "fieldName": "scatterShot", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 19503 - ], - "maxPoints": 1 - }, - { - "fieldName": "deflection", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 19295, - 19297, - 19298 - ], - "maxPoints": 3 - }, - { - "fieldName": "survivalTactics", - "location": { - "rowIdx": 2, - "colIdx": 3 - }, - "spellIds": [ - 19286, - 19287 - ], - "maxPoints": 2 - }, - { - "fieldName": "tNT", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 56333, - 56336, - 56337 - ], - "maxPoints": 3 - }, - { - "fieldName": "lockAndLoad", - "location": { - "rowIdx": 3, - "colIdx": 3 - }, - "spellIds": [ - 56342, - 56343, - 56344 - ], - "maxPoints": 3 - }, - { - "fieldName": "hunterVsWild", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 56339, - 56340, - 56341 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 2, - "colIdx": 0 - } - }, - { - "fieldName": "killerInstinct", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 19370, - 19371, - 19373 - ], - "maxPoints": 3 - }, - { - "fieldName": "counterattack", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 19306 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 2, - "colIdx": 2 - } - }, - { - "fieldName": "lightningReflexes", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 19168, - 19180, - 19181, - 24296, - 24297 - ], - "maxPoints": 5 - }, - { - "fieldName": "resourcefulness", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 34491, - 34492, - 34493 - ], - "maxPoints": 3 - }, - { - "fieldName": "exposeWeakness", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 34500, - 34502, - 34503 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 5, - "colIdx": 0 - } - }, - { - "fieldName": "wyvernSting", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 19386 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "thrillOfTheHunt", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 34497, - 34498, - 34499 - ], - "maxPoints": 3 - }, - { - "fieldName": "masterTactician", - "location": { - "rowIdx": 7, - "colIdx": 0 - }, - "spellIds": [ - 34506, - 34507, - 34508, - 34838, - 34839 - ], - "maxPoints": 5 - }, - { - "fieldName": "noxiousStings", - "location": { - "rowIdx": 7, - "colIdx": 1 - }, - "spellIds": [ - 53295, - 53296, - 53297 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "pointOfNoEscape", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 53298, - 53299 - ], - "maxPoints": 2 - }, - { - "fieldName": "blackArrow", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 3674 - ], - "maxPoints": 1 - }, - { - "fieldName": "sniperTraining", - "location": { - "rowIdx": 8, - "colIdx": 3 - }, - "spellIds": [ - 53302, - 53303, - 53304 - ], - "maxPoints": 3 - }, - { - "fieldName": "huntingParty", - "location": { - "rowIdx": 9, - "colIdx": 2 - }, - "spellIds": [ - 53290, - 53291, - 53292 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 2 - } - }, - { - "fieldName": "explosiveShot", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 53301 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 8, - "colIdx": 1 - } - } - ] + "name": "Survival", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/809.jpg", + "talents": [ + { + "fieldName": "hunterVsWild", + "fancyName": "Hunter Vs Wild", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 56339, + 56340, + 56341 + ], + "maxPoints": 3 + }, + { + "fieldName": "pathing", + "fancyName": "Pathing", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 52783, + 52785, + 52786 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedSerpentSting", + "fancyName": "Improved Serpent Sting", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 19464, + 82834 + ], + "maxPoints": 2 + }, + { + "fieldName": "survivalTactics", + "fancyName": "Survival Tactics", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 19286, + 19287 + ], + "maxPoints": 2 + }, + { + "fieldName": "trapMastery", + "fancyName": "Trap Mastery", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 19376, + 63457, + 63458 + ], + "maxPoints": 3 + }, + { + "fieldName": "entrapment", + "fancyName": "Entrapment", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 19184, + 19387 + ], + "maxPoints": 2 + }, + { + "fieldName": "pointOfNoEscape", + "fancyName": "Point Of No Escape", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 53298, + 53299 + ], + "maxPoints": 2 + }, + { + "fieldName": "thrillOfTheHunt", + "fancyName": "Thrill Of The Hunt", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 34497, + 34498, + 34499 + ], + "maxPoints": 3 + }, + { + "fieldName": "counterattack", + "fancyName": "Counterattack", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 19306 + ], + "maxPoints": 1 + }, + { + "fieldName": "lockAndLoad", + "fancyName": "Lock And Load", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 56342, + 56343 + ], + "maxPoints": 2 + }, + { + "fieldName": "resourcefulness", + "fancyName": "Resourcefulness", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 34491, + 34492, + 34493 + ], + "maxPoints": 3 + }, + { + "fieldName": "mirroredBlades", + "fancyName": "Mirrored Blades", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 83494, + 83495 + ], + "maxPoints": 2 + }, + { + "fieldName": "tNT", + "fancyName": "T N T", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 56333, + 56336 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 2 + } + }, + { + "fieldName": "toxicology", + "fancyName": "Toxicology", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 82832, + 82833 + ], + "maxPoints": 2 + }, + { + "fieldName": "wyvernSting", + "fancyName": "Wyvern Sting", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 19386 + ], + "maxPoints": 1 + }, + { + "fieldName": "noxiousStings", + "fancyName": "Noxious Stings", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 53295, + 53296 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "huntingParty", + "fancyName": "Hunting Party", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 53290 + ], + "maxPoints": 1 + }, + { + "fieldName": "sniperTraining", + "fancyName": "Sniper Training", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 53302, + 53303, + 53304 + ], + "maxPoints": 3 + }, + { + "fieldName": "serpentSpread", + "fancyName": "Serpent Spread", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 87934, + 87935 + ], + "maxPoints": 2 + }, + { + "fieldName": "blackArrow", + "fancyName": "Black Arrow", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 3674 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] } -] \ No newline at end of file + ] \ No newline at end of file diff --git a/ui/core/talents/trees/hunter_cunning.json b/ui/core/talents/trees/hunter_cunning.json index 0377f8f83c..3a0cc9ead2 100644 --- a/ui/core/talents/trees/hunter_cunning.json +++ b/ui/core/talents/trees/hunter_cunning.json @@ -1,255 +1,287 @@ [ - { - "name":"Cunning", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/411.jpg", - "talents":[ - { - "fieldName":"cobraReflexes", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 61682 - ], - "maxPoints":2 - }, - { - "fieldName":"dive", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 23145 - ], - "maxPoints":1 - }, - { - "fieldName":"greatStamina", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 61686 - ], - "maxPoints":3 - }, - { - "fieldName":"naturalArmor", - "location":{ - "rowIdx":0, - "colIdx":3 - }, - "spellIds":[ - 61689 - ], - "maxPoints":2 - }, - { - "fieldName":"boarsSpeed", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 19596 - ], - "maxPoints":1 - }, - { - "fieldName":"mobility", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 53554 - ], - "maxPoints":2 - }, - { - "fieldName":"owlsFocus", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 53514, - 53516 - ], - "maxPoints":2 - }, - { - "fieldName":"spikedCollar", - "location":{ - "rowIdx":1, - "colIdx":3 - }, - "spellIds":[ - 53182 - ], - "maxPoints":3 - }, - { - "fieldName":"cullingTheHerd", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 61680, - 61681, - 52858 - ], - "maxPoints":3 - }, - { - "fieldName":"lionhearted", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 53409, - 53411 - ], - "maxPoints":2 - }, - { - "fieldName":"carrionFeeder", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 54044 - ], - "maxPoints":1 - }, - { - "fieldName":"greatResistance", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 53427, - 53429 - ], - "maxPoints":3 - }, - { - "fieldName":"cornered", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 52234, - 53497 - ], - "maxPoints":2 - }, - { - "fieldName":"feedingFrenzy", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "prereqLocation":{ - "rowIdx":1, - "colIdx":3 - }, - "spellIds":[ - 53511 - ], - "maxPoints":2 - }, - { - "fieldName":"wolverineBite", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 53508 - ], - "maxPoints":1 - }, - { - "fieldName":"roarOfRecovery", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 53517 - ], - "maxPoints":1 - }, - { - "fieldName":"bullheaded", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 53490 - ], - "maxPoints":1 - }, - { - "fieldName":"graceOfTheMantis", - "location":{ - "rowIdx":4, - "colIdx":3 - }, - "spellIds":[ - 53450 - ], - "maxPoints":2 - }, - { - "fieldName":"wildHunt", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 62758, - 62762 - ], - "maxPoints":2 - }, - { - "fieldName":"roarOfSacrifice", - "location":{ - "rowIdx":5, - "colIdx":3 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":3 - }, - "spellIds":[ - 53480 - ], - "maxPoints":1 - } - ] - } - ] \ No newline at end of file + { + "name": "Cunning", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/411.jpg", + "talents": [ + { + "fieldName": "serpentSwiftness", + "fancyName": "Serpent Swiftness", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 61682, + 61683 + ], + "maxPoints": 2 + }, + { + "fieldName": "dive", + "fancyName": "Dive", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 23145 + ], + "maxPoints": 1 + }, + { + "fieldName": "greatStamina", + "fancyName": "Great Stamina", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 61686, + 61687, + 61688 + ], + "maxPoints": 3 + }, + { + "fieldName": "naturalArmor", + "fancyName": "Natural Armor", + "location": { + "rowIdx": 0, + "colIdx": 3 + }, + "spellIds": [ + 61689, + 61690 + ], + "maxPoints": 2 + }, + { + "fieldName": "boarsSpeed", + "fancyName": "Boars Speed", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 19596 + ], + "maxPoints": 1 + }, + { + "fieldName": "mobility", + "fancyName": "Mobility", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 53554, + 53483, + 53485, + 53555 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 0, + "colIdx": 1 + } + }, + { + "fieldName": "owlsFocus", + "fancyName": "Owls Focus", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 53514, + 53516 + ], + "maxPoints": 2 + }, + { + "fieldName": "spikedCollar", + "fancyName": "Spiked Collar", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 53182, + 53183, + 53184 + ], + "maxPoints": 3 + }, + { + "fieldName": "cullingTheHerd", + "fancyName": "Culling The Herd", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 61680, + 52858, + 61681 + ], + "maxPoints": 3 + }, + { + "fieldName": "lionhearted", + "fancyName": "Lionhearted", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 53409, + 53411 + ], + "maxPoints": 2 + }, + { + "fieldName": "carrionFeeder", + "fancyName": "Carrion Feeder", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 54044 + ], + "maxPoints": 1 + }, + { + "fieldName": "greatResistance", + "fancyName": "Great Resistance", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 53427, + 53429, + 53430 + ], + "maxPoints": 3 + }, + { + "fieldName": "cornered", + "fancyName": "Cornered", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 52234, + 53497 + ], + "maxPoints": 2 + }, + { + "fieldName": "feedingFrenzy", + "fancyName": "Feeding Frenzy", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 53511, + 53512 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 1, + "colIdx": 3 + } + }, + { + "fieldName": "wolverineBite", + "fancyName": "Wolverine Bite", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 53508 + ], + "maxPoints": 1 + }, + { + "fieldName": "roarOfRecovery", + "fancyName": "Roar Of Recovery", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 53517 + ], + "maxPoints": 1 + }, + { + "fieldName": "bullheaded", + "fancyName": "Bullheaded", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 53490 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 2 + } + }, + { + "fieldName": "graceOfTheMantis", + "fancyName": "Grace Of The Mantis", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 53450, + 53451 + ], + "maxPoints": 2 + }, + { + "fieldName": "wildHunt", + "fancyName": "Wild Hunt", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 62758, + 62762 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 0 + } + }, + { + "fieldName": "roarOfSacrifice", + "fancyName": "Roar Of Sacrifice", + "location": { + "rowIdx": 5, + "colIdx": 3 + }, + "spellIds": [ + 53480 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 3 + } + } + ] + } +] \ No newline at end of file diff --git a/ui/core/talents/trees/hunter_ferocity.json b/ui/core/talents/trees/hunter_ferocity.json index 382f62956d..5e20126191 100644 --- a/ui/core/talents/trees/hunter_ferocity.json +++ b/ui/core/talents/trees/hunter_ferocity.json @@ -1,238 +1,269 @@ [ - { - "name":"Ferocity", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/410.jpg", - "talents":[ - { - "fieldName":"cobraReflexes", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 61682 - ], - "maxPoints":2 - }, - { - "fieldName":"dive", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 23145 - ], - "maxPoints":1 - }, - { - "fieldName":"greatStamina", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 61686 - ], - "maxPoints":3 - }, - { - "fieldName":"naturalArmor", - "location":{ - "rowIdx":0, - "colIdx":3 - }, - "spellIds":[ - 61689 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedCower", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 53180 - ], - "maxPoints":2 - }, - { - "fieldName":"bloodthirsty", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 53186 - ], - "maxPoints":2 - }, - { - "fieldName":"spikedCollar", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 53182 - ], - "maxPoints":3 - }, - { - "fieldName":"boarsSpeed", - "location":{ - "rowIdx":1, - "colIdx":3 - }, - "spellIds":[ - 19596 - ], - "maxPoints":1 - }, - { - "fieldName":"cullingTheHerd", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 61680, - 61681, - 52858 - ], - "maxPoints":3 - }, - { - "fieldName":"lionhearted", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 53409, - 53411 - ], - "maxPoints":2 - }, - { - "fieldName":"charge", - "location":{ - "rowIdx":2, - "colIdx":3 - }, - "spellIds":[ - 61685 - ], - "maxPoints":1 - }, - { - "fieldName":"heartOfThePheonix", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 55709 - ], - "maxPoints":1 - }, - { - "fieldName":"spidersBite", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 53203 - ], - "maxPoints":3 - }, - { - "fieldName":"greatResistance", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "spellIds":[ - 53427, - 53429 - ], - "maxPoints":3 - }, - { - "fieldName":"rabid", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 53401 - ], - "maxPoints":1 - }, - { - "fieldName":"lickYourWounds", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 53426 - ], - "maxPoints":1 - }, - { - "fieldName":"callOfTheWild", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 53434 - ], - "maxPoints":1 - }, - { - "fieldName":"sharkAttack", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 62759 - ], - "maxPoints":2 - }, - { - "fieldName":"wildHunt", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 62758, - 62762 - ], - "maxPoints":2 - } - ] - } - ] \ No newline at end of file + { + "name": "Ferocity", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/410.jpg", + "talents": [ + { + "fieldName": "serpentSwiftness", + "fancyName": "Serpent Swiftness", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 61682, + 61683 + ], + "maxPoints": 2 + }, + { + "fieldName": "dash", + "fancyName": "Dash", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 61684 + ], + "maxPoints": 1 + }, + { + "fieldName": "greatStamina", + "fancyName": "Great Stamina", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 61686, + 61687, + 61688 + ], + "maxPoints": 3 + }, + { + "fieldName": "naturalArmor", + "fancyName": "Natural Armor", + "location": { + "rowIdx": 0, + "colIdx": 3 + }, + "spellIds": [ + 61689, + 61690 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedCower", + "fancyName": "Improved Cower", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 53180, + 53181 + ], + "maxPoints": 2 + }, + { + "fieldName": "bloodthirsty", + "fancyName": "Bloodthirsty", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 53186, + 53187 + ], + "maxPoints": 2 + }, + { + "fieldName": "spikedCollar", + "fancyName": "Spiked Collar", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 53182, + 53183, + 53184 + ], + "maxPoints": 3 + }, + { + "fieldName": "boarsSpeed", + "fancyName": "Boars Speed", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 19596 + ], + "maxPoints": 1 + }, + { + "fieldName": "cullingTheHerd", + "fancyName": "Culling The Herd", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 61680, + 52858, + 61681 + ], + "maxPoints": 3 + }, + { + "fieldName": "lionhearted", + "fancyName": "Lionhearted", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 53409, + 53411 + ], + "maxPoints": 2 + }, + { + "fieldName": "charge", + "fancyName": "Charge", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 61685 + ], + "maxPoints": 1 + }, + { + "fieldName": "heartOfThePhoenix", + "fancyName": "Heart Of The Phoenix", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 55709 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 1, + "colIdx": 1 + } + }, + { + "fieldName": "spidersBite", + "fancyName": "Spiders Bite", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 53203, + 53204, + 53205 + ], + "maxPoints": 3 + }, + { + "fieldName": "greatResistance", + "fancyName": "Great Resistance", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 53427, + 53429, + 53430 + ], + "maxPoints": 3 + }, + { + "fieldName": "rabid", + "fancyName": "Rabid", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 53401 + ], + "maxPoints": 1 + }, + { + "fieldName": "lickYourWounds", + "fancyName": "Lick Your Wounds", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 53426 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 1 + } + }, + { + "fieldName": "callOfTheWild", + "fancyName": "Call Of The Wild", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 53434 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 2 + } + }, + { + "fieldName": "sharkAttack", + "fancyName": "Shark Attack", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 62759, + 62760 + ], + "maxPoints": 2 + }, + { + "fieldName": "wildHunt", + "fancyName": "Wild Hunt", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 62758, + 62762 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 2 + } + } + ] + } +] \ No newline at end of file diff --git a/ui/core/talents/trees/hunter_tenacity.json b/ui/core/talents/trees/hunter_tenacity.json index 16986ca567..7e86e02aa9 100644 --- a/ui/core/talents/trees/hunter_tenacity.json +++ b/ui/core/talents/trees/hunter_tenacity.json @@ -1,253 +1,285 @@ [ - { - "name":"Tenacity", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/409.jpg", - "talents":[ - { - "fieldName":"cobraReflexes", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 61682 - ], - "maxPoints":2 - }, - { - "fieldName":"charge", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 61685 - ], - "maxPoints":1 - }, - { - "fieldName":"greatStamina", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 61686 - ], - "maxPoints":3 - }, - { - "fieldName":"naturalArmor", - "location":{ - "rowIdx":0, - "colIdx":3 - }, - "spellIds":[ - 61689 - ], - "maxPoints":2 - }, - { - "fieldName":"spikedCollar", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 53182 - ], - "maxPoints":3 - }, - { - "fieldName":"boarsSpeed", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 19596 - ], - "maxPoints":1 - }, - { - "fieldName":"bloodOfTheRhino", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 53481 - ], - "maxPoints":2 - }, - { - "fieldName":"petBarding", - "location":{ - "rowIdx":1, - "colIdx":3 - }, - "prereqLocation":{ - "rowIdx":0, - "colIdx":3 - }, - "spellIds":[ - 53175 - ], - "maxPoints":2 - }, - { - "fieldName":"cullingTheHerd", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 61680, - 61681, - 52858 - ], - "maxPoints":3 - }, - { - "fieldName":"guardDog", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 53178 - ], - "maxPoints":2 - }, - { - "fieldName":"lionhearted", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 53409, - 53411 - ], - "maxPoints":2 - }, - { - "fieldName":"thunderstomp", - "location":{ - "rowIdx":2, - "colIdx":3 - }, - "spellIds":[ - 63900 - ], - "maxPoints":1 - }, - { - "fieldName":"graceOfTheMantis", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 53450 - ], - "maxPoints":2 - }, - { - "fieldName":"greatResistance", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "spellIds":[ - 53427, - 53429 - ], - "maxPoints":3 - }, - { - "fieldName":"lastStand", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 53478 - ], - "maxPoints":1 - }, - { - "fieldName":"taunt", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 53477 - ], - "maxPoints":1 - }, - { - "fieldName":"roarOfSacrifice", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 53480 - ], - "maxPoints":1 - }, - { - "fieldName":"intervene", - "location":{ - "rowIdx":4, - "colIdx":3 - }, - "spellIds":[ - 53476 - ], - "maxPoints":1 - }, - { - "fieldName":"silverback", - "location":{ - "rowIdx":5, - "colIdx":1 - }, - "spellIds":[ - 62764 - ], - "maxPoints":2 - }, - { - "fieldName":"wildHunt", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 62758, - 62762 - ], - "maxPoints":2 - } - ] - } - ] \ No newline at end of file + { + "name": "Tenacity", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/409.jpg", + "talents": [ + { + "fieldName": "serpentSwiftness", + "fancyName": "Serpent Swiftness", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 61682, + 61683 + ], + "maxPoints": 2 + }, + { + "fieldName": "charge", + "fancyName": "Charge", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 61685 + ], + "maxPoints": 1 + }, + { + "fieldName": "greatStamina", + "fancyName": "Great Stamina", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 61686, + 61687, + 61688 + ], + "maxPoints": 3 + }, + { + "fieldName": "naturalArmor", + "fancyName": "Natural Armor", + "location": { + "rowIdx": 0, + "colIdx": 3 + }, + "spellIds": [ + 61689, + 61690 + ], + "maxPoints": 2 + }, + { + "fieldName": "spikedCollar", + "fancyName": "Spiked Collar", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 53182, + 53183, + 53184 + ], + "maxPoints": 3 + }, + { + "fieldName": "boarsSpeed", + "fancyName": "Boars Speed", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 19596 + ], + "maxPoints": 1 + }, + { + "fieldName": "bloodOfTheRhino", + "fancyName": "Blood Of The Rhino", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 53481, + 53482 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 0, + "colIdx": 2 + } + }, + { + "fieldName": "petBarding", + "fancyName": "Pet Barding", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 53175, + 53176 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 0, + "colIdx": 3 + } + }, + { + "fieldName": "cullingTheHerd", + "fancyName": "Culling The Herd", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 61680, + 52858, + 61681 + ], + "maxPoints": 3 + }, + { + "fieldName": "guardDog", + "fancyName": "Guard Dog", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 53178, + 53179 + ], + "maxPoints": 2 + }, + { + "fieldName": "lionhearted", + "fancyName": "Lionhearted", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 53409, + 53411 + ], + "maxPoints": 2 + }, + { + "fieldName": "thunderstomp", + "fancyName": "Thunderstomp", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 63900 + ], + "maxPoints": 1 + }, + { + "fieldName": "graceOfTheMantis", + "fancyName": "Grace Of The Mantis", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 53450, + 53451 + ], + "maxPoints": 2 + }, + { + "fieldName": "greatResistance", + "fancyName": "Great Resistance", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 53427, + 53429, + 53430 + ], + "maxPoints": 3 + }, + { + "fieldName": "lastStand", + "fancyName": "Last Stand", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 53478 + ], + "maxPoints": 1 + }, + { + "fieldName": "taunt", + "fancyName": "Taunt", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 53477 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "roarOfSacrifice", + "fancyName": "Roar Of Sacrifice", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 53480 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 2 + } + }, + { + "fieldName": "intervene", + "fancyName": "Intervene", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 53476 + ], + "maxPoints": 1 + }, + { + "fieldName": "silverback", + "fancyName": "Silverback", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 62764, + 62765 + ], + "maxPoints": 2 + }, + { + "fieldName": "wildHunt", + "fancyName": "Wild Hunt", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 62758, + 62762 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 2 + } + } + ] + } +] \ No newline at end of file diff --git a/ui/core/talents/trees/mage.json b/ui/core/talents/trees/mage.json index e13c4bb114..053365da7e 100644 --- a/ui/core/talents/trees/mage.json +++ b/ui/core/talents/trees/mage.json @@ -1,1156 +1,867 @@ [ { - "name": "Arcane", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/81.jpg", - "talents": [ - { - "fieldName": "arcaneSubtlety", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 11210, - 12592 - ], - "maxPoints": 2 - }, - { - "fieldName": "arcaneFocus", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 11222, - 12839, - 12840 - ], - "maxPoints": 3 - }, - { - "fieldName": "arcaneStability", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 11237, - 12463, - 12464, - 16769, - 16770 - ], - "maxPoints": 5 - }, - { - "fieldName": "arcaneFortitude", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 28574, - 54658, - 54659 - ], - "maxPoints": 3 - }, - { - "fieldName": "magicAbsorption", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 29441, - 29444 - ], - "maxPoints": 2 - }, - { - "fieldName": "arcaneConcentration", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 11213, - 12574, - 12575, - 12576, - 12577 - ], - "maxPoints": 5 - }, - { - "fieldName": "magicAttunement", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 11247, - 12606 - ], - "maxPoints": 2 - }, - { - "fieldName": "spellImpact", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 11242, - 12467, - 12469 - ], - "maxPoints": 3 - }, - { - "fieldName": "studentOfTheMind", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 44397, - 44398, - 44399 - ], - "maxPoints": 3 - }, - { - "fieldName": "focusMagic", - "location": { - "rowIdx": 2, - "colIdx": 3 - }, - "spellIds": [ - 54646 - ], - "maxPoints": 1 - }, - { - "fieldName": "arcaneShielding", - "location": { - "rowIdx": 3, - "colIdx": 0 - }, - "spellIds": [ - 11252, - 12605 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedCounterspell", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 11255, - 12598 - ], - "maxPoints": 2 - }, - { - "fieldName": "arcaneMeditation", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 18462, - 18463, - 18464 - ], - "maxPoints": 3 - }, - { - "fieldName": "tormentTheWeak", - "location": { - "rowIdx": 3, - "colIdx": 3 - }, - "spellIds": [ - 29447, - 55339, - 55340 - ], - "maxPoints": 3 - }, - { - "fieldName": "improvedBlink", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 31569, - 31570 - ], - "maxPoints": 2 - }, - { - "fieldName": "presenceOfMind", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 12043 - ], - "maxPoints": 1 - }, - { - "fieldName": "arcaneMind", - "location": { - "rowIdx": 4, - "colIdx": 3 - }, - "spellIds": [ - 11232, - 12500, - 12501, - 12502, - 12503 - ], - "maxPoints": 5 - }, - { - "fieldName": "prismaticCloak", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 31574, - 31575, - 54354 - ], - "maxPoints": 3 - }, - { - "fieldName": "arcaneInstability", - "location": { - "rowIdx": 5, - "colIdx": 1 - }, - "spellIds": [ - 15058, - 15059, - 15060 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "arcanePotency", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 31571, - 31572 - ], - "maxPoints": 2, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "arcaneEmpowerment", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 31579, - 31582, - 31583 - ], - "maxPoints": 3 - }, - { - "fieldName": "arcanePower", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 12042 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 5, - "colIdx": 1 - } - }, - { - "fieldName": "incantersAbsorption", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 44394, - 44395, - 44396 - ], - "maxPoints": 3 - }, - { - "fieldName": "arcaneFlows", - "location": { - "rowIdx": 7, - "colIdx": 1 - }, - "spellIds": [ - 44378, - 44379 - ], - "maxPoints": 2, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "mindMastery", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 31584, - 31585, - 31586, - 31587, - 31588 - ], - "maxPoints": 5 - }, - { - "fieldName": "slow", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 31589 - ], - "maxPoints": 1 - }, - { - "fieldName": "missileBarrage", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 44404, - 54486, - 54488, - 54489, - 54490 - ], - "maxPoints": 5 - }, - { - "fieldName": "netherwindPresence", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 44400, - 44402, - 44403 - ], - "maxPoints": 3 - }, - { - "fieldName": "spellPower", - "location": { - "rowIdx": 9, - "colIdx": 2 - }, - "spellIds": [ - 35578, - 35581 - ], - "maxPoints": 2 - }, - { - "fieldName": "arcaneBarrage", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 44425 - ], - "maxPoints": 1 - } - ] + "name": "Arcane", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/799.jpg", + "talents": [ + { + "fieldName": "arcaneConcentration", + "fancyName": "Arcane Concentration", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 11213, + 12574, + 12575 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedCounterspell", + "fancyName": "Improved Counterspell", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 11255, + 12598 + ], + "maxPoints": 2 + }, + { + "fieldName": "netherwindPresence", + "fancyName": "Netherwind Presence", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 44400, + 44402, + 44403 + ], + "maxPoints": 3 + }, + { + "fieldName": "tormentTheWeak", + "fancyName": "Torment The Weak", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 29447, + 55339, + 55340 + ], + "maxPoints": 3 + }, + { + "fieldName": "invocation", + "fancyName": "Invocation", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 84722, + 84723 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedArcaneMissiles", + "fancyName": "Improved Arcane Missiles", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 83513, + 83515 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedBlink", + "fancyName": "Improved Blink", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 31569, + 31570 + ], + "maxPoints": 2 + }, + { + "fieldName": "arcaneFlows", + "fancyName": "Arcane Flows", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 44378, + 44379 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "presenceOfMind", + "fancyName": "Presence Of Mind", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 12043 + ], + "maxPoints": 1 + }, + { + "fieldName": "missileBarrage", + "fancyName": "Missile Barrage", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 44404, + 54486 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 1, + "colIdx": 2 + } + }, + { + "fieldName": "prismaticCloak", + "fancyName": "Prismatic Cloak", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 31574, + 31575, + 54354 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedPolymorph", + "fancyName": "Improved Polymorph", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 11210, + 12592 + ], + "maxPoints": 2 + }, + { + "fieldName": "arcaneTactics", + "fancyName": "Arcane Tactics", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 82930 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "incantersAbsorption", + "fancyName": "Incanters Absorption", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 44394, + 44395 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedArcaneExplosion", + "fancyName": "Improved Arcane Explosion", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 90787, + 90788 + ], + "maxPoints": 2 + }, + { + "fieldName": "arcanePotency", + "fancyName": "Arcane Potency", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 31571, + 31572 + ], + "maxPoints": 2 + }, + { + "fieldName": "slow", + "fancyName": "Slow", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 31589 + ], + "maxPoints": 1 + }, + { + "fieldName": "netherVortex", + "fancyName": "Nether Vortex", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 86181, + 86209 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "focusMagic", + "fancyName": "Focus Magic", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 54646 + ], + "maxPoints": 1 + }, + { + "fieldName": "improvedManaGem", + "fancyName": "Improved Mana Gem", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 31584, + 31585, + 31586 + ], + "maxPoints": 2 + }, + { + "fieldName": "arcanePower?Spellmodifier=99064", + "fancyName": "Arcane Power?Spellmodifier=99064", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 12042 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] }, { - "name": "Fire", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/41.jpg", - "talents": [ - { - "fieldName": "improvedFireBlast", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 11078, - 11080 - ], - "maxPoints": 2 - }, - { - "fieldName": "incineration", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 18459, - 18460, - 54734 - ], - "maxPoints": 3 - }, - { - "fieldName": "improvedFireball", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 11069, - 12338, - 12339, - 12340, - 12341 - ], - "maxPoints": 5 - }, - { - "fieldName": "ignite", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 11119, - 11120, - 12846, - 12847, - 12848 - ], - "maxPoints": 5 - }, - { - "fieldName": "burningDetermination", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 54747, - 54749 - ], - "maxPoints": 2 - }, - { - "fieldName": "worldInFlames", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 11108, - 12349, - 12350 - ], - "maxPoints": 3 - }, - { - "fieldName": "flameThrowing", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 11100, - 12353 - ], - "maxPoints": 2 - }, - { - "fieldName": "impact", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 11103, - 12357, - 12358 - ], - "maxPoints": 3 - }, - { - "fieldName": "pyroblast", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 11366 - ], - "maxPoints": 1 - }, - { - "fieldName": "burningSoul", - "location": { - "rowIdx": 2, - "colIdx": 3 - }, - "spellIds": [ - 11083, - 12351 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedScorch", - "location": { - "rowIdx": 3, - "colIdx": 0 - }, - "spellIds": [ - 11095, - 12872, - 12873 - ], - "maxPoints": 3 - }, - { - "fieldName": "moltenShields", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 11094, - 13043 - ], - "maxPoints": 2 - }, - { - "fieldName": "masterOfElements", - "location": { - "rowIdx": 3, - "colIdx": 3 - }, - "spellIds": [ - 29074, - 29075, - 29076 - ], - "maxPoints": 3 - }, - { - "fieldName": "playingWithFire", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 31638, - 31639, - 31640 - ], - "maxPoints": 3 - }, - { - "fieldName": "criticalMass", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 11115, - 11367, - 11368 - ], - "maxPoints": 3 - }, - { - "fieldName": "blastWave", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 11113 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 2, - "colIdx": 2 - } - }, - { - "fieldName": "blazingSpeed", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 31641, - 31642 - ], - "maxPoints": 2 - }, - { - "fieldName": "firePower", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 11124, - 12378, - 12398, - 12399, - 12400 - ], - "maxPoints": 5 - }, - { - "fieldName": "pyromaniac", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 34293, - 34295, - 34296 - ], - "maxPoints": 3 - }, - { - "fieldName": "combustion", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 11129 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "moltenFury", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 31679, - 31680 - ], - "maxPoints": 2 - }, - { - "fieldName": "fieryPayback", - "location": { - "rowIdx": 7, - "colIdx": 0 - }, - "spellIds": [ - 64353, - 64357 - ], - "maxPoints": 2 - }, - { - "fieldName": "empoweredFire", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 31656, - 31657, - 31658 - ], - "maxPoints": 3 - }, - { - "fieldName": "firestarter", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 44442, - 44443 - ], - "maxPoints": 2, - "prereqLocation": { - "rowIdx": 8, - "colIdx": 1 - } - }, - { - "fieldName": "dragonsBreath", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 31661 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "hotStreak", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 44445, - 44446, - 44448 - ], - "maxPoints": 3 - }, - { - "fieldName": "burnout", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 44449, - 44469, - 44470, - 44471, - 44472 - ], - "maxPoints": 5 - }, - { - "fieldName": "livingBomb", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 44457 - ], - "maxPoints": 1 - } - ] + "name": "Fire", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/851.jpg", + "talents": [ + { + "fieldName": "masterOfElements", + "fancyName": "Master Of Elements", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 29074, + 29075, + 29076 + ], + "maxPoints": 2 + }, + { + "fieldName": "burningSoul", + "fancyName": "Burning Soul", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 11083, + 84254, + 84253 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedFireBlast", + "fancyName": "Improved Fire Blast", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 11078, + 11080 + ], + "maxPoints": 2 + }, + { + "fieldName": "ignite", + "fancyName": "Ignite", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 11119, + 11120, + 12846 + ], + "maxPoints": 3 + }, + { + "fieldName": "firePower", + "fancyName": "Fire Power", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 18459, + 54734, + 18460 + ], + "maxPoints": 3 + }, + { + "fieldName": "blazingSpeed", + "fancyName": "Blazing Speed", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 31641, + 31642 + ], + "maxPoints": 2 + }, + { + "fieldName": "impact", + "fancyName": "Impact", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 11103, + 12357, + 11242, + 12358, + 12467, + 12469 + ], + "maxPoints": 2 + }, + { + "fieldName": "cauterize", + "fancyName": "Cauterize", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 86948, + 86949 + ], + "maxPoints": 2 + }, + { + "fieldName": "blastWave", + "fancyName": "Blast Wave", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 11113 + ], + "maxPoints": 1 + }, + { + "fieldName": "hotStreak", + "fancyName": "Hot Streak", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 44445 + ], + "maxPoints": 1 + }, + { + "fieldName": "improvedScorch", + "fancyName": "Improved Scorch", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 11115, + 11367 + ], + "maxPoints": 2 + }, + { + "fieldName": "moltenShields", + "fancyName": "Molten Shields", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 11094 + ], + "maxPoints": 1 + }, + { + "fieldName": "combustion", + "fancyName": "Combustion", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 11129 + ], + "maxPoints": 1 + }, + { + "fieldName": "improvedHotStreak", + "fancyName": "Improved Hot Streak", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 44446, + 44448 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 2 + } + }, + { + "fieldName": "firestarter", + "fancyName": "Firestarter", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 86914 + ], + "maxPoints": 1 + }, + { + "fieldName": "improvedFlamestrike", + "fancyName": "Improved Flamestrike", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 84673, + 84674 + ], + "maxPoints": 2 + }, + { + "fieldName": "dragonsBreath", + "fancyName": "Dragons Breath", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 31661 + ], + "maxPoints": 1 + }, + { + "fieldName": "moltenFury", + "fancyName": "Molten Fury", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 31679, + 31680, + 86880 + ], + "maxPoints": 3 + }, + { + "fieldName": "pyromaniac", + "fancyName": "Pyromaniac", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 34293, + 34295, + 34296 + ], + "maxPoints": 2 + }, + { + "fieldName": "criticalMass", + "fancyName": "Critical Mass", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 11095, + 12873, + 12872 + ], + "maxPoints": 3 + }, + { + "fieldName": "livingBomb", + "fancyName": "Living Bomb", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 44457 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] }, { - "name": "Frost", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/61.jpg", - "talents": [ - { - "fieldName": "frostbite", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 11071, - 12496, - 12497 - ], - "maxPoints": 3 - }, - { - "fieldName": "improvedFrostbolt", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 11070, - 12473, - 16763, - 16765, - 16766 - ], - "maxPoints": 5 - }, - { - "fieldName": "iceFloes", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 31670, - 31672, - 55094 - ], - "maxPoints": 3 - }, - { - "fieldName": "iceShards", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 11207, - 12672, - 15047 - ], - "maxPoints": 3 - }, - { - "fieldName": "frostWarding", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 11189, - 28332 - ], - "maxPoints": 2 - }, - { - "fieldName": "precision", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 29438, - 29439, - 29440 - ], - "maxPoints": 3 - }, - { - "fieldName": "permafrost", - "location": { - "rowIdx": 1, - "colIdx": 3 - }, - "spellIds": [ - 11175, - 12569, - 12571 - ], - "maxPoints": 3 - }, - { - "fieldName": "piercingIce", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 11151, - 12952, - 12953 - ], - "maxPoints": 3 - }, - { - "fieldName": "icyVeins", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 12472 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedBlizzard", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 11185, - 12487, - 12488 - ], - "maxPoints": 3 - }, - { - "fieldName": "arcticReach", - "location": { - "rowIdx": 3, - "colIdx": 0 - }, - "spellIds": [ - 16757, - 16758 - ], - "maxPoints": 2 - }, - { - "fieldName": "frostChanneling", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 11160, - 12518, - 12519 - ], - "maxPoints": 3 - }, - { - "fieldName": "shatter", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 11170, - 12982, - 12983 - ], - "maxPoints": 3 - }, - { - "fieldName": "coldSnap", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 11958 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedConeOfCold", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 11190, - 12489, - 12490 - ], - "maxPoints": 3 - }, - { - "fieldName": "frozenCore", - "location": { - "rowIdx": 4, - "colIdx": 3 - }, - "spellIds": [ - 31667, - 31668, - 31669 - ], - "maxPoints": 3 - }, - { - "fieldName": "coldAsIce", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 55091, - 55092 - ], - "maxPoints": 2, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "wintersChill", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 11180, - 28592, - 28593 - ], - "maxPoints": 3 - }, - { - "fieldName": "shatteredBarrier", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 44745, - 54787 - ], - "maxPoints": 2, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "iceBarrier", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 11426 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "arcticWinds", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 31674, - 31675, - 31676, - 31677, - 31678 - ], - "maxPoints": 5 - }, - { - "fieldName": "empoweredFrostbolt", - "location": { - "rowIdx": 7, - "colIdx": 1 - }, - "spellIds": [ - 31682, - 31683 - ], - "maxPoints": 2 - }, - { - "fieldName": "fingersOfFrost", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 44543, - 44545 - ], - "maxPoints": 2 - }, - { - "fieldName": "brainFreeze", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 44546, - 44548, - 44549 - ], - "maxPoints": 3 - }, - { - "fieldName": "summonWaterElemental", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 31687 - ], - "maxPoints": 1 - }, - { - "fieldName": "enduringWinter", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 44557, - 44560, - 44561 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 8, - "colIdx": 1 - } - }, - { - "fieldName": "chilledToTheBone", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 44566, - 44567, - 44568, - 44570, - 44571 - ], - "maxPoints": 5 - }, - { - "fieldName": "deepFreeze", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 44572 - ], - "maxPoints": 1 - } - ] + "name": "Frost", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/823.jpg", + "talents": [ + { + "fieldName": "earlyFrost", + "fancyName": "Early Frost", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 83049, + 83050 + ], + "maxPoints": 2 + }, + { + "fieldName": "piercingIce", + "fancyName": "Piercing Ice", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 11151, + 12952, + 12953 + ], + "maxPoints": 3 + }, + { + "fieldName": "shatter", + "fancyName": "Shatter", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 11170, + 12982, + 12983, + 44745, + 54787 + ], + "maxPoints": 2 + }, + { + "fieldName": "iceFloes", + "fancyName": "Ice Floes", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 31670, + 31672, + 55094 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedConeOfCold", + "fancyName": "Improved Cone Of Cold", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 11190, + 12489 + ], + "maxPoints": 2 + }, + { + "fieldName": "piercingChill", + "fancyName": "Piercing Chill", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 83156, + 83157 + ], + "maxPoints": 2 + }, + { + "fieldName": "permafrost", + "fancyName": "Permafrost", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 11175, + 12569, + 12571 + ], + "maxPoints": 3 + }, + { + "fieldName": "iceShards", + "fancyName": "Ice Shards", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 11185, + 12487 + ], + "maxPoints": 2 + }, + { + "fieldName": "icyVeins", + "fancyName": "Icy Veins", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 12472 + ], + "maxPoints": 1 + }, + { + "fieldName": "fingersOfFrost", + "fancyName": "Fingers Of Frost", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 44543, + 44545, + 83074 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedFreeze", + "fancyName": "Improved Freeze", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 86259, + 86260, + 86314 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 2 + } + }, + { + "fieldName": "enduringWinter", + "fancyName": "Enduring Winter", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 44561, + 86500, + 86508 + ], + "maxPoints": 3 + }, + { + "fieldName": "coldSnap", + "fancyName": "Cold Snap", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 11958 + ], + "maxPoints": 1 + }, + { + "fieldName": "brainFreeze", + "fancyName": "Brain Freeze", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 44546, + 44548, + 44549 + ], + "maxPoints": 3 + }, + { + "fieldName": "shatteredBarrier", + "fancyName": "Shattered Barrier", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 44745, + 54787 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "iceBarrier?Spellmodifier=63095", + "fancyName": "Ice Barrier?Spellmodifier=63095", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 11426 + ], + "maxPoints": 1 + }, + { + "fieldName": "reactiveBarrier", + "fancyName": "Reactive Barrier", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 86303, + 86304 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "frostfireOrb", + "fancyName": "Frostfire Orb", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 84726, + 84727 + ], + "maxPoints": 2 + }, + { + "fieldName": "deepFreeze?Spellmodifier=11151%2C12952%2C12953%2C31674%2C31675%2C31676%2C31677%2C31678", + "fancyName": "Deep Freeze?Spellmodifier=11151%2C12952%2C12953%2C31674%2C31675%2C31676%2C31677%2C31678", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 44572 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] } -] \ No newline at end of file + ] \ No newline at end of file diff --git a/ui/core/talents/trees/paladin.json b/ui/core/talents/trees/paladin.json index 7d4ceaeeaa..88f3aa43ed 100644 --- a/ui/core/talents/trees/paladin.json +++ b/ui/core/talents/trees/paladin.json @@ -1,949 +1,827 @@ [ - { - "name":"Holy", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/classic/382.jpg", - "talents":[ - { - "fieldName":"spiritualFocus", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 20205 - ], - "maxPoints":5 - }, - { - "fieldName":"sealsOfThePure", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 20224, - 20225, - 20330 - ], - "maxPoints":5 - }, - { - "fieldName":"healingLight", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 20237 - ], - "maxPoints":3 - }, - { - "fieldName":"divineIntellect", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 20257 - ], - "maxPoints":5 - }, - { - "fieldName":"unyieldingFaith", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 9453, - 25836 - ], - "maxPoints":2 - }, - { - "fieldName":"auraMastery", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 31821 - ], - "maxPoints":1 - }, - { - "fieldName":"illumination", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 20210, - 20212 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedLayOnHands", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 20234 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedConcentrationAura", - "location":{ - "rowIdx":3, - "colIdx":0 - }, - "spellIds":[ - 20254 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedBlessingOfWisdom", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 20244 - ], - "maxPoints":2 - }, - { - "fieldName":"blessedHands", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "spellIds":[ - 53660 - ], - "maxPoints":2 - }, - { - "fieldName":"pureOfHeart", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 31822 - ], - "maxPoints":2 - }, - { - "fieldName":"divineFavor", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 20216 - ], - "maxPoints":1 - }, - { - "fieldName":"sanctifiedLight", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 20359 - ], - "maxPoints":3 - }, - { - "fieldName":"purifyingPower", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 31825 - ], - "maxPoints":2 - }, - { - "fieldName":"holyPower", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 5923, - 5924, - 5925, - 5926, - 25829 - ], - "maxPoints":5 - }, - { - "fieldName":"lightsGrace", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 31833, - 31835 - ], - "maxPoints":3 - }, - { - "fieldName":"holyShock", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 20473 - ], - "maxPoints":1 - }, - { - "fieldName":"blessedLife", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 31828 - ], - "maxPoints":3 - }, - { - "fieldName":"sacredCleansing", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 53551 - ], - "maxPoints":3 - }, - { - "fieldName":"holyGuidance", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 31837 - ], - "maxPoints":5 - }, - { - "fieldName":"divineIllumination", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 31842 - ], - "maxPoints":1 - }, - { - "fieldName":"judgementsOfThePure", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 53671, - 53673, - 54151, - 54154, - 54155 - ], - "maxPoints":5 - }, - { - "fieldName":"infusionOfLight", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 53569, - 53576 - ], - "maxPoints":2 - }, - { - "fieldName":"enlightenedJudgements", - "location":{ - "rowIdx":9, - "colIdx":2 - }, - "spellIds":[ - 53556 - ], - "maxPoints":2 - }, - { - "fieldName":"beaconOfLight", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 53563 - ], - "maxPoints":1 - } - ] - }, - { - "name":"Protection", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/classic/383.jpg", - "talents":[ - { - "fieldName":"divinity", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 63646 - ], - "maxPoints":5 - }, - { - "fieldName":"divineStrength", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 20262 - ], - "maxPoints":5 - }, - { - "fieldName":"stoicism", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 31844, - 31845, - 53519 - ], - "maxPoints":3 - }, - { - "fieldName":"guardiansFavor", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 20174 - ], - "maxPoints":2 - }, - { - "fieldName":"anticipation", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 20096 - ], - "maxPoints":5 - }, - { - "fieldName":"divineSacrifice", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 64205 - ], - "maxPoints":1 - }, - { - "fieldName":"improvedRighteousFury", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 20468 - ], - "maxPoints":3 - }, - { - "fieldName":"toughness", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 20143 - ], - "maxPoints":5 - }, - { - "fieldName":"divineGuardian", - "location":{ - "rowIdx":3, - "colIdx":0 - }, - "prereqLocation":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 53527, - 53530 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedHammerOfJustice", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 20487 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedDevotionAura", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 20138 - ], - "maxPoints":3 - }, - { - "fieldName":"blessingOfSanctuary", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 20911 - ], - "maxPoints":1 - }, - { - "fieldName":"reckoning", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 20177, - 20179, - 20181, - 20180, - 20182 - ], - "maxPoints":5 - }, - { - "fieldName":"sacredDuty", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 31848 - ], - "maxPoints":2 - }, - { - "fieldName":"oneHandedWeaponSpecialization", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 20196 - ], - "maxPoints":3 - }, - { - "fieldName":"spiritualAttunement", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 31785, - 33776 - ], - "maxPoints":2 - }, - { - "fieldName":"holyShield", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 20925 - ], - "maxPoints":1 - }, - { - "fieldName":"ardentDefender", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 31850 - ], - "maxPoints":3 - }, - { - "fieldName":"redoubt", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 20127, - 20130, - 20135 - ], - "maxPoints":3 - }, - { - "fieldName":"combatExpertise", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 31858 - ], - "maxPoints":3 - }, - { - "fieldName":"touchedByTheLight", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 53590 - ], - "maxPoints":3 - }, - { - "fieldName":"avengersShield", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 31935 - ], - "maxPoints":1 - }, - { - "fieldName":"guardedByTheLight", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 53583, - 53585 - ], - "maxPoints":2 - }, - { - "fieldName":"shieldOfTheTemplar", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 53709 - ], - "maxPoints":3 - }, - { - "fieldName":"judgementsOfTheJust", - "location":{ - "rowIdx":9, - "colIdx":2 - }, - "spellIds":[ - 53695 - ], - "maxPoints":2 - }, - { - "fieldName":"hammerOfTheRighteous", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 53595 - ], - "maxPoints":1 - } - ] - }, - { - "name":"Retribution", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/classic/381.jpg", - "talents":[ - { - "fieldName":"deflection", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 20060 - ], - "maxPoints":5 - }, - { - "fieldName":"benediction", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 20101 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedJudgements", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 25956 - ], - "maxPoints":2 - }, - { - "fieldName":"heartOfTheCrusader", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 20335 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedBlessingOfMight", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 20042, - 20045 - ], - "maxPoints":2 - }, - { - "fieldName":"vindication", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 9452, - 26016 - ], - "maxPoints":2 - }, - { - "fieldName":"conviction", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 20117 - ], - "maxPoints":5 - }, - { - "fieldName":"sealOfCommand", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 20375 - ], - "maxPoints":1 - }, - { - "fieldName":"pursuitOfJustice", - "location":{ - "rowIdx":2, - "colIdx":3 - }, - "spellIds":[ - 26022 - ], - "maxPoints":2 - }, - { - "fieldName":"eyeForAnEye", - "location":{ - "rowIdx":3, - "colIdx":0 - }, - "spellIds":[ - 9799, - 25988 - ], - "maxPoints":2 - }, - { - "fieldName":"sanctityOfBattle", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 32043, - 35396, - 35397 - ], - "maxPoints":3 - }, - { - "fieldName":"crusade", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "spellIds":[ - 31866 - ], - "maxPoints":3 - }, - { - "fieldName":"twoHandedWeaponSpecialization", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 20111 - ], - "maxPoints":3 - }, - { - "fieldName":"sanctifiedRetribution", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 31869 - ], - "maxPoints":1 - }, - { - "fieldName":"vengeance", - "location":{ - "rowIdx":5, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 20049, - 20056, - 20057 - ], - "maxPoints":3 - }, - { - "fieldName":"divinePurpose", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 31871 - ], - "maxPoints":2 - }, - { - "fieldName":"theArtOfWar", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 53486, - 53488 - ], - "maxPoints":2 - }, - { - "fieldName":"repentance", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 20066 - ], - "maxPoints":1 - }, - { - "fieldName":"judgementsOfTheWise", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 31876 - ], - "maxPoints":3 - }, - { - "fieldName":"fanaticism", - "location":{ - "rowIdx":7, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 31879 - ], - "maxPoints":3 - }, - { - "fieldName":"sanctifiedWrath", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 53375 - ], - "maxPoints":2 - }, - { - "fieldName":"swiftRetribution", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 53379, - 53484, - 53648 - ], - "maxPoints":3 - }, - { - "fieldName":"crusaderStrike", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 35395 - ], - "maxPoints":1 - }, - { - "fieldName":"sheathOfLight", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 53501 - ], - "maxPoints":3 - }, - { - "fieldName":"righteousVengeance", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 53380 - ], - "maxPoints":3 - }, - { - "fieldName":"divineStorm", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 53385 - ], - "maxPoints":1 - } - ] - } + { + "name": "Holy", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/831.jpg", + "talents": [ + { + "fieldName": "arbiterOfTheLight", + "fancyName": "Arbiter Of The Light", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 20359, + 20360 + ], + "maxPoints": 2 + }, + { + "fieldName": "protectorOfTheInnocent", + "fancyName": "Protector Of The Innocent", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 20138, + 20139, + 20140 + ], + "maxPoints": 3 + }, + { + "fieldName": "judgementsOfThePure", + "fancyName": "Judgements Of The Pure", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 53671, + 53673, + 54151 + ], + "maxPoints": 3 + }, + { + "fieldName": "clarityOfPurpose", + "fancyName": "Clarity Of Purpose", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 85462, + 85463, + 85464 + ], + "maxPoints": 3 + }, + { + "fieldName": "lastWord", + "fancyName": "Last Word", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 20234, + 20235 + ], + "maxPoints": 2 + }, + { + "fieldName": "blazingLight", + "fancyName": "Blazing Light", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 20237, + 20238 + ], + "maxPoints": 2 + }, + { + "fieldName": "denounce", + "fancyName": "Denounce", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 31825, + 85510 + ], + "maxPoints": 2 + }, + { + "fieldName": "divineFavor", + "fancyName": "Divine Favor", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 31842 + ], + "maxPoints": 1 + }, + { + "fieldName": "infusionOfLight", + "fancyName": "Infusion Of Light", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 53569, + 53576 + ], + "maxPoints": 2 + }, + { + "fieldName": "daybreak", + "fancyName": "Daybreak", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 88820, + 88821 + ], + "maxPoints": 2 + }, + { + "fieldName": "enlightenedJudgements", + "fancyName": "Enlightened Judgements", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 53556, + 53557 + ], + "maxPoints": 2 + }, + { + "fieldName": "beaconOfLight", + "fancyName": "Beacon Of Light", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 53563 + ], + "maxPoints": 1 + }, + { + "fieldName": "speedOfLight", + "fancyName": "Speed Of Light", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 85495, + 85498, + 85499 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 2 + } + }, + { + "fieldName": "sacredCleansing", + "fancyName": "Sacred Cleansing", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 53551 + ], + "maxPoints": 1 + }, + { + "fieldName": "conviction", + "fancyName": "Conviction", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 20049, + 20056, + 20057 + ], + "maxPoints": 3 + }, + { + "fieldName": "auraMastery", + "fancyName": "Aura Mastery", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 31821 + ], + "maxPoints": 1 + }, + { + "fieldName": "paragonOfVirtue", + "fancyName": "Paragon Of Virtue", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 93418, + 93417 + ], + "maxPoints": 2 + }, + { + "fieldName": "towerOfRadiance", + "fancyName": "Tower Of Radiance", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 84800, + 85511, + 85512 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 1 + } + }, + { + "fieldName": "blessedLife", + "fancyName": "Blessed Life", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 31828, + 31829 + ], + "maxPoints": 2 + }, + { + "fieldName": "lightOfDawn", + "fancyName": "Light Of Dawn", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 85222 + ], + "maxPoints": 1 + } + ] + }, + { + "name": "Protection", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/839.jpg", + "talents": [ + { + "fieldName": "divinity", + "fancyName": "Divinity", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 63646, + 63647, + 63648 + ], + "maxPoints": 3 + }, + { + "fieldName": "sealsOfThePure", + "fancyName": "Seals Of The Pure", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 20224, + 20225 + ], + "maxPoints": 2 + }, + { + "fieldName": "eternalGlory", + "fancyName": "Eternal Glory", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 87163, + 87164 + ], + "maxPoints": 2 + }, + { + "fieldName": "judgementsOfTheJust", + "fancyName": "Judgements Of The Just", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 53695, + 53696 + ], + "maxPoints": 2 + }, + { + "fieldName": "toughness", + "fancyName": "Toughness", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 20143, + 20145, + 20144 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedHammerOfJustice", + "fancyName": "Improved Hammer Of Justice", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 20487, + 20488 + ], + "maxPoints": 2 + }, + { + "fieldName": "hallowedGround", + "fancyName": "Hallowed Ground", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 84631, + 84633 + ], + "maxPoints": 2 + }, + { + "fieldName": "sanctuary", + "fancyName": "Sanctuary", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 20911, + 84628, + 84629 + ], + "maxPoints": 3 + }, + { + "fieldName": "hammerOfTheRighteous", + "fancyName": "Hammer Of The Righteous", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 53595 + ], + "maxPoints": 1 + }, + { + "fieldName": "wrathOfTheLightbringer", + "fancyName": "Wrath Of The Lightbringer", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 84635, + 84636 + ], + "maxPoints": 2 + }, + { + "fieldName": "reckoning", + "fancyName": "Reckoning", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 20177, + 20179 + ], + "maxPoints": 2 + }, + { + "fieldName": "shieldOfTheRighteous", + "fancyName": "Shield Of The Righteous", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 53600 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "grandCrusader", + "fancyName": "Grand Crusader", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 75806, + 85043 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 2 + } + }, + { + "fieldName": "vindication", + "fancyName": "Vindication", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 26016 + ], + "maxPoints": 1 + }, + { + "fieldName": "holyShield", + "fancyName": "Holy Shield", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 20925 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 1 + } + }, + { + "fieldName": "guardedByTheLight", + "fancyName": "Guarded By The Light", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 85639, + 85646 + ], + "maxPoints": 2 + }, + { + "fieldName": "divineGuardian", + "fancyName": "Divine Guardian", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 70940 + ], + "maxPoints": 1 + }, + { + "fieldName": "sacredDuty", + "fancyName": "Sacred Duty", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 53709, + 53710 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "shieldOfTheTemplar", + "fancyName": "Shield Of The Templar", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 31848, + 31849, + 84854 + ], + "maxPoints": 3 + }, + { + "fieldName": "ardentDefender", + "fancyName": "Ardent Defender", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 31850 + ], + "maxPoints": 1 + } + ] + }, + { + "name": "Retribution", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/855.jpg", + "talents": [ + { + "fieldName": "eyeForAnEye", + "fancyName": "Eye For An Eye", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 9799, + 25988 + ], + "maxPoints": 2 + }, + { + "fieldName": "crusade", + "fancyName": "Crusade", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 31866, + 75806, + 31867, + 31868, + 85043 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedJudgement", + "fancyName": "Improved Judgement", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 87174, + 87175 + ], + "maxPoints": 2 + }, + { + "fieldName": "guardiansFavor", + "fancyName": "Guardians Favor", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 20174, + 20175 + ], + "maxPoints": 2 + }, + { + "fieldName": "ruleOfLaw", + "fancyName": "Rule Of Law", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 85457, + 85458, + 87461 + ], + "maxPoints": 3 + }, + { + "fieldName": "pursuitOfJustice", + "fancyName": "Pursuit Of Justice", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 26022, + 26023 + ], + "maxPoints": 2 + }, + { + "fieldName": "communion", + "fancyName": "Communion", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 31876 + ], + "maxPoints": 1 + }, + { + "fieldName": "theArtOfWar", + "fancyName": "The Art Of War", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 53486, + 53488, + 87138 + ], + "maxPoints": 3 + }, + { + "fieldName": "longArmOfTheLaw", + "fancyName": "Long Arm Of The Law", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 87168, + 87172 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 0, + "colIdx": 2 + } + }, + { + "fieldName": "divineStorm", + "fancyName": "Divine Storm", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 53385 + ], + "maxPoints": 1 + }, + { + "fieldName": "sacredShield", + "fancyName": "Sacred Shield", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 85285 + ], + "maxPoints": 1 + }, + { + "fieldName": "sanctityOfBattle", + "fancyName": "Sanctity Of Battle", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 25956 + ], + "maxPoints": 1 + }, + { + "fieldName": "sealsOfCommand", + "fancyName": "Seals Of Command", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 85126 + ], + "maxPoints": 1 + }, + { + "fieldName": "sanctifiedWrath", + "fancyName": "Sanctified Wrath", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 53375, + 53376, + 90286 + ], + "maxPoints": 3 + }, + { + "fieldName": "selflessHealer", + "fancyName": "Selfless Healer", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 85803, + 85804 + ], + "maxPoints": 2 + }, + { + "fieldName": "repentance", + "fancyName": "Repentance", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 20066 + ], + "maxPoints": 1 + }, + { + "fieldName": "divinePurpose", + "fancyName": "Divine Purpose", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 85117, + 86172 + ], + "maxPoints": 2 + }, + { + "fieldName": "inquiryOfFaith", + "fancyName": "Inquiry Of Faith", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 53380, + 53381, + 53382 + ], + "maxPoints": 3 + }, + { + "fieldName": "actsOfSacrifice", + "fancyName": "Acts Of Sacrifice", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 85446, + 85795 + ], + "maxPoints": 2 + }, + { + "fieldName": "zealotry", + "fancyName": "Zealotry", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 85696 + ], + "maxPoints": 1 + } + ] + } ] \ No newline at end of file diff --git a/ui/core/talents/trees/priest.json b/ui/core/talents/trees/priest.json index b4860ee3bd..95fc6f816c 100644 --- a/ui/core/talents/trees/priest.json +++ b/ui/core/talents/trees/priest.json @@ -1,1104 +1,881 @@ [ - { - "name":"Discipline", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/201.jpg", - "talents":[ - { - "fieldName":"unbreakableWill", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 14522, - 14788, - 14789, - 14790, - 14791 - ], - "maxPoints":5 - }, - { - "fieldName":"twinDisciplines", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 47586, - 47587, - 47588, - 52802, - 52803 - ], - "maxPoints":5 - }, - { - "fieldName":"silentResolve", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 14523, - 14784, - 14785 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedInnerFire", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 14747, - 14770, - 14771 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedPowerWordFortitude", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 14749, - 14767 - ], - "maxPoints":2 - }, - { - "fieldName":"martyrdom", - "location":{ - "rowIdx":1, - "colIdx":3 - }, - "spellIds":[ - 14531, - 14774 - ], - "maxPoints":2 - }, - { - "fieldName":"meditation", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 14521, - 14776, - 14777 - ], - "maxPoints":3 - }, - { - "fieldName":"innerFocus", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 14751 - ], - "maxPoints":1 - }, - { - "fieldName":"improvedPowerWordShield", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 14748, - 14768, - 14769 - ], - "maxPoints":3 - }, - { - "fieldName":"absolution", - "location":{ - "rowIdx":3, - "colIdx":0 - }, - "spellIds":[ - 33167, - 33171, - 33172 - ], - "maxPoints":3 - }, - { - "fieldName":"mentalAgility", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 14520, - 14780, - 14781 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedManaBurn", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "spellIds":[ - 14750, - 14772 - ], - "maxPoints":2 - }, - { - "fieldName":"reflectiveShield", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 33201, - 33202 - ], - "maxPoints":2 - }, - { - "fieldName":"mentalStrength", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 18551, - 18552, - 18553, - 18554, - 18555 - ], - "maxPoints":5 - }, - { - "fieldName":"soulWarding", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 63574 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":2, - "colIdx":2 - } - }, - { - "fieldName":"focusedPower", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 33186, - 33190 - ], - "maxPoints":2 - }, - { - "fieldName":"enlightenment", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 34908, - 34909, - 34910 - ], - "maxPoints":3 - }, - { - "fieldName":"focusedWill", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 45234, - 45243, - 45244 - ], - "maxPoints":3 - }, - { - "fieldName":"powerInfusion", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 10060 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - } - }, - { - "fieldName":"improvedFlashHeal", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 63504, - 63505, - 63506 - ], - "maxPoints":3 - }, - { - "fieldName":"renewedHope", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 57470, - 57472 - ], - "maxPoints":2 - }, - { - "fieldName":"rapture", - "location":{ - "rowIdx":7, - "colIdx":1 - }, - "spellIds":[ - 47535, - 47536, - 47537 - ], - "maxPoints":3 - }, - { - "fieldName":"aspiration", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 47507, - 47508 - ], - "maxPoints":2 - }, - { - "fieldName":"divineAegis", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 47509, - 47511, - 47515 - ], - "maxPoints":3 - }, - { - "fieldName":"painSuppression", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 33206 - ], - "maxPoints":1 - }, - { - "fieldName":"grace", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 47516, - 47517 - ], - "maxPoints":2 - }, - { - "fieldName":"borrowedTime", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 52795, - 52797, - 52798, - 52799, - 52800 - ], - "maxPoints":5 - }, - { - "fieldName":"penance", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 47540 - ], - "maxPoints":1 - } - ] - }, - { - "name":"Holy", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/202.jpg", - "talents":[ - { - "fieldName":"healingFocus", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 14913, - 15012 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedRenew", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 14908, - 15020, - 17191 - ], - "maxPoints":3 - }, - { - "fieldName":"holySpecialization", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 14889, - 15008, - 15009, - 15010, - 15011 - ], - "maxPoints":5 - }, - { - "fieldName":"spellWarding", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 27900, - 27901, - 27902, - 27903, - 27904 - ], - "maxPoints":5 - }, - { - "fieldName":"divineFury", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 18530, - 18531, - 18533, - 18534, - 18535 - ], - "maxPoints":5 - }, - { - "fieldName":"desperatePrayer", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 19236 - ], - "maxPoints":1 - }, - { - "fieldName":"blessedRecovery", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 27811, - 27815, - 27816 - ], - "maxPoints":3 - }, - { - "fieldName":"inspiration", - "location":{ - "rowIdx":2, - "colIdx":3 - }, - "spellIds":[ - 14892, - 15362, - 15363 - ], - "maxPoints":3 - }, - { - "fieldName":"holyReach", - "location":{ - "rowIdx":3, - "colIdx":0 - }, - "spellIds":[ - 27789, - 27790 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedHealing", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 14912, - 15013, - 15014 - ], - "maxPoints":3 - }, - { - "fieldName":"searingLight", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 14909, - 15017 - ], - "maxPoints":2, - "prereqLocation":{ - "rowIdx":1, - "colIdx":2 - } - }, - { - "fieldName":"healingPrayers", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 14911, - 15018 - ], - "maxPoints":2 - }, - { - "fieldName":"spiritOfRedemption", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 20711 - ], - "maxPoints":1 - }, - { - "fieldName":"spiritualGuidance", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 14901, - 15028, - 15029, - 15030, - 15031 - ], - "maxPoints":5 - }, - { - "fieldName":"surgeOfLight", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 33150, - 33154 - ], - "maxPoints":2 - }, - { - "fieldName":"spiritualHealing", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 14898, - 15349, - 15354, - 15355, - 15356 - ], - "maxPoints":5 - }, - { - "fieldName":"holyConcentration", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 34753, - 34859, - 34860 - ], - "maxPoints":3 - }, - { - "fieldName":"lightwell", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 724 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - } - }, - { - "fieldName":"blessedResilience", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 33142, - 33145, - 33146 - ], - "maxPoints":3 - }, - { - "fieldName":"bodyAndSoul", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 64127, - 64129 - ], - "maxPoints":2 - }, - { - "fieldName":"empoweredHealing", - "location":{ - "rowIdx":7, - "colIdx":1 - }, - "spellIds":[ - 33158, - 33159, - 33160, - 33161, - 33162 - ], - "maxPoints":5 - }, - { - "fieldName":"serendipity", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 63730, - 63733, - 63737 - ], - "maxPoints":3 - }, - { - "fieldName":"empoweredRenew", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 63534, - 63542, - 63543 - ], - "maxPoints":3 - }, - { - "fieldName":"circleOfHealing", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 34861 - ], - "maxPoints":1 - }, - { - "fieldName":"testOfFaith", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 47558, - 47559, - 47560 - ], - "maxPoints":3 - }, - { - "fieldName":"divineProvidence", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 47562, - 47564, - 47565, - 47566, - 47567 - ], - "maxPoints":5 - }, - { - "fieldName":"guardianSpirit", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 47788 - ], - "maxPoints":1 - } - ] - }, - { - "name":"Shadow", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/203.jpg", - "talents":[ - { - "fieldName":"spiritTap", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 15270, - 15335, - 15336 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedSpiritTap", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 15337, - 15338 - ], - "maxPoints":2, - "prereqLocation":{ - "rowIdx":0, - "colIdx":0 - } - }, - { - "fieldName":"darkness", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 15259, - 15307, - 15308, - 15309, - 15310 - ], - "maxPoints":5 - }, - { - "fieldName":"shadowAffinity", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 15318, - 15272, - 15320 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedShadowWordPain", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 15275, - 15317 - ], - "maxPoints":2 - }, - { - "fieldName":"shadowFocus", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 15260, - 15327, - 15328 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedPsychicScream", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 15392, - 15448 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedMindBlast", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 15273, - 15312, - 15313, - 15314, - 15316 - ], - "maxPoints":5 - }, - { - "fieldName":"mindFlay", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 15407 - ], - "maxPoints":1 - }, - { - "fieldName":"veiledShadows", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 15274, - 15311 - ], - "maxPoints":2 - }, - { - "fieldName":"shadowReach", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 17322, - 17323 - ], - "maxPoints":2 - }, - { - "fieldName":"shadowWeaving", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "spellIds":[ - 15257, - 15331, - 15332 - ], - "maxPoints":3 - }, - { - "fieldName":"silence", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 15487 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":2, - "colIdx":0 - } - }, - { - "fieldName":"vampiricEmbrace", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 15286 - ], - "maxPoints":1 - }, - { - "fieldName":"improvedVampiricEmbrace", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 27839, - 27840 - ], - "maxPoints":2, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - } - }, - { - "fieldName":"focusedMind", - "location":{ - "rowIdx":4, - "colIdx":3 - }, - "spellIds":[ - 33213, - 33214, - 33215 - ], - "maxPoints":3 - }, - { - "fieldName":"mindMelt", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 14910, - 33371 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedDevouringPlague", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 63625, - 63626, - 63627 - ], - "maxPoints":3 - }, - { - "fieldName":"shadowform", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 15473 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - } - }, - { - "fieldName":"shadowPower", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 33221, - 33222, - 33223, - 33224, - 33225 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedShadowform", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 47569, - 47570 - ], - "maxPoints":2, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - } - }, - { - "fieldName":"misery", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 33191, - 33192, - 33193 - ], - "maxPoints":3 - }, - { - "fieldName":"psychicHorror", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 64044 - ], - "maxPoints":1 - }, - { - "fieldName":"vampiricTouch", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 34914 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - } - }, - { - "fieldName":"painAndSuffering", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 47580, - 47581, - 47582 - ], - "maxPoints":3 - }, - { - "fieldName":"twistedFaith", - "location":{ - "rowIdx":9, - "colIdx":2 - }, - "spellIds":[ - 47573, - 47577, - 47578, - 51166, - 51167 - ], - "maxPoints":5 - }, - { - "fieldName":"dispersion", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 47585 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":8, - "colIdx":1 - } - } - ] - } + { + "name": "Discipline", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/760.jpg", + "talents": [ + { + "fieldName": "improvedPowerWordShield", + "fancyName": "Improved Power Word Shield", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 14748, + 14768 + ], + "maxPoints": 2 + }, + { + "fieldName": "twinDisciplines", + "fancyName": "Twin Disciplines", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 47586, + 47587, + 47588 + ], + "maxPoints": 3 + }, + { + "fieldName": "mentalAgility", + "fancyName": "Mental Agility", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 14520, + 14781, + 14780 + ], + "maxPoints": 3 + }, + { + "fieldName": "evangelism", + "fancyName": "Evangelism", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 81659, + 81662 + ], + "maxPoints": 2 + }, + { + "fieldName": "archangel", + "fancyName": "Archangel", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 87151 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 1, + "colIdx": 0 + } + }, + { + "fieldName": "innerSanctum", + "fancyName": "Inner Sanctum", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 14747, + 14770, + 14771 + ], + "maxPoints": 3 + }, + { + "fieldName": "soulWarding", + "fancyName": "Soul Warding", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 63574, + 78500, + 78501 + ], + "maxPoints": 2 + }, + { + "fieldName": "renewedHope", + "fancyName": "Renewed Hope", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 57470, + 57472 + ], + "maxPoints": 2 + }, + { + "fieldName": "powerInfusion", + "fancyName": "Power Infusion", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 10060 + ], + "maxPoints": 1 + }, + { + "fieldName": "atonement", + "fancyName": "Atonement", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 14523, + 81749 + ], + "maxPoints": 2 + }, + { + "fieldName": "innerFocus", + "fancyName": "Inner Focus", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 89485 + ], + "maxPoints": 1 + }, + { + "fieldName": "rapture", + "fancyName": "Rapture", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 47535, + 47536, + 47537 + ], + "maxPoints": 3 + }, + { + "fieldName": "borrowedTime", + "fancyName": "Borrowed Time", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 52795, + 52797, + 52798 + ], + "maxPoints": 2 + }, + { + "fieldName": "reflectiveShield", + "fancyName": "Reflective Shield", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 33201, + 33202 + ], + "maxPoints": 2 + }, + { + "fieldName": "strengthOfSoul", + "fancyName": "Strength Of Soul", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 89488, + 89489 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 0 + } + }, + { + "fieldName": "divineAegis", + "fancyName": "Divine Aegis", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 47509, + 47511, + 47515 + ], + "maxPoints": 3 + }, + { + "fieldName": "painSuppression", + "fancyName": "Pain Suppression", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 33206 + ], + "maxPoints": 1 + }, + { + "fieldName": "trainOfThought", + "fancyName": "Train Of Thought", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 92295, + 92297 + ], + "maxPoints": 2 + }, + { + "fieldName": "focusedWill", + "fancyName": "Focused Will", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 45234, + 45243 + ], + "maxPoints": 2 + }, + { + "fieldName": "grace", + "fancyName": "Grace", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 47516, + 47517 + ], + "maxPoints": 2 + }, + { + "fieldName": "powerWordBarrier", + "fancyName": "Power Word Barrier", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 62618 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] + }, + { + "name": "Holy", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/813.jpg", + "talents": [ + { + "fieldName": "improvedRenew", + "fancyName": "Improved Renew", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 14908, + 15020 + ], + "maxPoints": 2 + }, + { + "fieldName": "empoweredHealing", + "fancyName": "Empowered Healing", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 33158, + 33159, + 33160 + ], + "maxPoints": 3 + }, + { + "fieldName": "divineFury", + "fancyName": "Divine Fury", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 18530, + 18531, + 18533 + ], + "maxPoints": 3 + }, + { + "fieldName": "desperatePrayer", + "fancyName": "Desperate Prayer", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 19236 + ], + "maxPoints": 1 + }, + { + "fieldName": "surgeOfLight", + "fancyName": "Surge Of Light", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 88687, + 88690 + ], + "maxPoints": 2 + }, + { + "fieldName": "inspiration", + "fancyName": "Inspiration", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 14892, + 15362 + ], + "maxPoints": 2 + }, + { + "fieldName": "divineTouch", + "fancyName": "Divine Touch", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 63534, + 63542 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 0, + "colIdx": 0 + } + }, + { + "fieldName": "holyConcentration", + "fancyName": "Holy Concentration", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 34753, + 34859 + ], + "maxPoints": 2 + }, + { + "fieldName": "lightwell?spellModifier=47586%2C47587%2C47588", + "fancyName": "Lightwell?Spellmodifier=47586%2C47587%2C47588", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 724 + ], + "maxPoints": 1 + }, + { + "fieldName": "tomeOfLight", + "fancyName": "Tome Of Light", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 14898, + 81625 + ], + "maxPoints": 2 + }, + { + "fieldName": "rapidRenewal", + "fancyName": "Rapid Renewal", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 95649 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 0 + } + }, + { + "fieldName": "spiritOfRedemption", + "fancyName": "Spirit Of Redemption", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 20711 + ], + "maxPoints": 1 + }, + { + "fieldName": "serendipity", + "fancyName": "Serendipity", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 63730, + 63733 + ], + "maxPoints": 2 + }, + { + "fieldName": "bodyAndSoul", + "fancyName": "Body And Soul", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 64127, + 64129 + ], + "maxPoints": 2 + }, + { + "fieldName": "chakra", + "fancyName": "Chakra", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 14751 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "revelations", + "fancyName": "Revelations", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 88627 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "blessedResilience", + "fancyName": "Blessed Resilience", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 33142, + 33145 + ], + "maxPoints": 2 + }, + { + "fieldName": "testOfFaith", + "fancyName": "Test Of Faith", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 47558, + 47559, + 47560 + ], + "maxPoints": 3 + }, + { + "fieldName": "heavenlyVoice", + "fancyName": "Heavenly Voice", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 87430, + 87431 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "circleOfHealing", + "fancyName": "Circle Of Healing", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 34861 + ], + "maxPoints": 1 + }, + { + "fieldName": "guardianSpirit", + "fancyName": "Guardian Spirit", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 47788 + ], + "maxPoints": 1 + } + ] + }, + { + "name": "Shadow", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/795.jpg", + "talents": [ + { + "fieldName": "darkness", + "fancyName": "Darkness", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 15259, + 15307, + 15308 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedShadowWordPain", + "fancyName": "Improved Shadow Word Pain", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 15275, + 15317 + ], + "maxPoints": 2 + }, + { + "fieldName": "veiledShadows", + "fancyName": "Veiled Shadows", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 15274, + 15311 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedPsychicScream", + "fancyName": "Improved Psychic Scream", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 15392, + 15448 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedMindBlast", + "fancyName": "Improved Mind Blast", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 15273, + 15312, + 15313 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedDevouringPlague", + "fancyName": "Improved Devouring Plague", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 63625, + 63626 + ], + "maxPoints": 2 + }, + { + "fieldName": "twistedFaith", + "fancyName": "Twisted Faith", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 47573, + 47577 + ], + "maxPoints": 2 + }, + { + "fieldName": "shadowform", + "fancyName": "Shadowform", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 15473 + ], + "maxPoints": 1 + }, + { + "fieldName": "phantasm", + "fancyName": "Phantasm", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 47569, + 47570 + ], + "maxPoints": 2 + }, + { + "fieldName": "harnessedShadows", + "fancyName": "Harnessed Shadows", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 33191, + 78228 + ], + "maxPoints": 2 + }, + { + "fieldName": "silence", + "fancyName": "Silence", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 15487 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 1, + "colIdx": 0 + } + }, + { + "fieldName": "vampiricEmbrace", + "fancyName": "Vampiric Embrace", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 15286 + ], + "maxPoints": 1 + }, + { + "fieldName": "masochism", + "fancyName": "Masochism", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 88994, + 88995 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 1 + } + }, + { + "fieldName": "mindMelt", + "fancyName": "Mind Melt", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 14910, + 33371 + ], + "maxPoints": 2 + }, + { + "fieldName": "painAndSuffering", + "fancyName": "Pain And Suffering", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 47580, + 47581 + ], + "maxPoints": 2 + }, + { + "fieldName": "vampiricTouch", + "fancyName": "Vampiric Touch", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 34914 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 1 + } + }, + { + "fieldName": "paralysis", + "fancyName": "Paralysis", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 87192, + 87195 + ], + "maxPoints": 2 + }, + { + "fieldName": "psychicHorror", + "fancyName": "Psychic Horror", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 64044 + ], + "maxPoints": 1 + }, + { + "fieldName": "sinAndPunishment", + "fancyName": "Sin And Punishment", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 87099, + 87100 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "shadowyApparition", + "fancyName": "Shadowy Apparition", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 78202, + 78203, + 78204 + ], + "maxPoints": 3 + }, + { + "fieldName": "dispersion", + "fancyName": "Dispersion", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 47585 + ], + "maxPoints": 1 + } + ] + } ] \ No newline at end of file diff --git a/ui/core/talents/trees/rogue.json b/ui/core/talents/trees/rogue.json index bdfefc1f2b..2d29548e94 100644 --- a/ui/core/talents/trees/rogue.json +++ b/ui/core/talents/trees/rogue.json @@ -1,1113 +1,791 @@ [ - { - "name":"Assassination", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/182.jpg", - "talents":[ - { - "fieldName":"improvedEviscerate", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 14162, - 14163, - 14164 - ], - "maxPoints":3 - }, - { - "fieldName":"remorselessAttacks", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 14144, - 14148 - ], - "maxPoints":2 - }, - { - "fieldName":"malice", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 14138, - 14139, - 14140, - 14141, - 14142 - ], - "maxPoints":5 - }, - { - "fieldName":"ruthlessness", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 14156, - 14160, - 14161 - ], - "maxPoints":3 - }, - { - "fieldName":"bloodSpatter", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 51632, - 51633 - ], - "maxPoints":2 - }, - { - "fieldName":"puncturingWounds", - "location":{ - "rowIdx":1, - "colIdx":3 - }, - "spellIds":[ - 13733, - 13865 - ], - "maxPoints":3 - }, - { - "fieldName":"vigor", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 14983 - ], - "maxPoints":1 - }, - { - "fieldName":"improvedExposeArmor", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 14168, - 14169 - ], - "maxPoints":2 - }, - { - "fieldName":"lethality", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 14128, - 14132, - 14135, - 14136, - 14137 - ], - "maxPoints":5 - }, - { - "fieldName":"vilePoisons", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 16513, - 16514, - 16515 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedPoisons", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 14113, - 14114, - 14115, - 14116, - 14117 - ], - "maxPoints":5 - }, - { - "fieldName":"fleetFooted", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 31208, - 31209 - ], - "maxPoints":2 - }, - { - "fieldName":"coldBlood", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 14177 - ], - "maxPoints":1 - }, - { - "fieldName":"improvedKidneyShot", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 14174, - 14175, - 14176 - ], - "maxPoints":3 - }, - { - "fieldName":"quickRecovery", - "location":{ - "rowIdx":4, - "colIdx":3 - }, - "spellIds":[ - 31244, - 31245 - ], - "maxPoints":2 - }, - { - "fieldName":"sealFate", - "location":{ - "rowIdx":5, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 14186, - 14190, - 14193, - 14194, - 14195 - ], - "maxPoints":5 - }, - { - "fieldName":"murder", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 14158, - 14159 - ], - "maxPoints":2 - }, - { - "fieldName":"deadlyBrew", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 51625, - 51626 - ], - "maxPoints":2 - }, - { - "fieldName":"overkill", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 58426 - ], - "maxPoints":1 - }, - { - "fieldName":"deadenedNerves", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 31380, - 31382, - 31383 - ], - "maxPoints":3 - }, - { - "fieldName":"focusedAttacks", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 51634, - 51635, - 51636 - ], - "maxPoints":3 - }, - { - "fieldName":"findWeakness", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 31234, - 31235, - 31236 - ], - "maxPoints":3 - }, - { - "fieldName":"masterPoisoner", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 31226, - 31227, - 58410 - ], - "maxPoints":3 - }, - { - "fieldName":"mutilate", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 1329 - ], - "maxPoints":1 - }, - { - "fieldName":"turnTheTables", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 51627, - 51628, - 51629 - ], - "maxPoints":3 - }, - { - "fieldName":"cutToTheChase", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 51664, - 51665, - 51667, - 51668, - 51669 - ], - "maxPoints":5 - }, - { - "fieldName":"hungerForBlood", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 51662 - ], - "maxPoints":1 - } - ] - }, - { - "name":"Combat", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/181.jpg", - "talents":[ - { - "fieldName":"improvedGouge", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 13741, - 13793, - 13792 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedSinisterStrike", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 13732, - 13863 - ], - "maxPoints":2 - }, - { - "fieldName":"dualWieldSpecialization", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 13715, - 13848, - 13849, - 13851, - 13852 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedSliceAndDice", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 14165, - 14166 - ], - "maxPoints":2 - }, - { - "fieldName":"deflection", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 13713, - 13853, - 13854 - ], - "maxPoints":3 - }, - { - "fieldName":"precision", - "location":{ - "rowIdx":1, - "colIdx":3 - }, - "spellIds":[ - 13705, - 13832, - 13843, - 13844, - 13845 - ], - "maxPoints":5 - }, - { - "fieldName":"endurance", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 13742, - 13872 - ], - "maxPoints":2 - }, - { - "fieldName":"riposte", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 14251 - ], - "maxPoints":1 - }, - { - "fieldName":"closeQuartersCombat", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 13706, - 13804, - 13805, - 13806, - 13807 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedKick", - "location":{ - "rowIdx":3, - "colIdx":0 - }, - "spellIds":[ - 13754, - 13867 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedSprint", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 13743, - 13875 - ], - "maxPoints":2 - }, - { - "fieldName":"lightningReflexes", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 13712, - 13788, - 13789 - ], - "maxPoints":3 - }, - { - "fieldName":"aggression", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "spellIds":[ - 18427, - 18428, - 18429, - 61330, - 61331 - ], - "maxPoints":5 - }, - { - "fieldName":"maceSpecialization", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 13709, - 13800, - 13801, - 13802, - 13803 - ], - "maxPoints":5 - }, - { - "fieldName":"bladeFlurry", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 13877 - ], - "maxPoints":1 - }, - { - "fieldName":"hackAndSlash", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 13960, - 13961, - 13962, - 13963, - 13964 - ], - "maxPoints":5 - }, - { - "fieldName":"weaponExpertise", - "location":{ - "rowIdx":5, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 30919, - 30920 - ], - "maxPoints":2 - }, - { - "fieldName":"bladeTwisting", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 31124, - 31126 - ], - "maxPoints":2 - }, - { - "fieldName":"vitality", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 31122, - 31123, - 61329 - ], - "maxPoints":3 - }, - { - "fieldName":"adrenalineRush", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 13750 - ], - "maxPoints":1 - }, - { - "fieldName":"nervesOfSteel", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 31130, - 31131 - ], - "maxPoints":2 - }, - { - "fieldName":"throwingSpecialization", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 5952, - 51679 - ], - "maxPoints":2 - }, - { - "fieldName":"combatPotency", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 35541, - 35550, - 35551, - 35552, - 35553 - ], - "maxPoints":5 - }, - { - "fieldName":"unfairAdvantage", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 51672, - 51674 - ], - "maxPoints":2 - }, - { - "fieldName":"surpriseAttacks", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 32601 - ], - "maxPoints":1 - }, - { - "fieldName":"savageCombat", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 51682, - 58413 - ], - "maxPoints":2 - }, - { - "fieldName":"preyOnTheWeak", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 51685, - 51686, - 51687, - 51688, - 51689 - ], - "maxPoints":5 - }, - { - "fieldName":"killingSpree", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 51690 - ], - "maxPoints":1 - } - ] - }, - { - "name":"Subtlety", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/183.jpg", - "talents":[ - { - "fieldName":"relentlessStrikes", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 14179, - 58422, - 58423, - 58424, - 58425 - ], - "maxPoints":5 - }, - { - "fieldName":"masterOfDeception", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 13958, - 13970, - 13971 - ], - "maxPoints":3 - }, - { - "fieldName":"opportunity", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 14057, - 14072 - ], - "maxPoints":2 - }, - { - "fieldName":"sleightOfHand", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 30892, - 30893 - ], - "maxPoints":2 - }, - { - "fieldName":"dirtyTricks", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 14076, - 14094 - ], - "maxPoints":2 - }, - { - "fieldName":"camouflage", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 13975, - 14062, - 14063 - ], - "maxPoints":3 - }, - { - "fieldName":"elusiveness", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 13981, - 14066 - ], - "maxPoints":2 - }, - { - "fieldName":"ghostlyStrike", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 14278 - ], - "maxPoints":1 - }, - { - "fieldName":"serratedBlades", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 14171, - 14172, - 14173 - ], - "maxPoints":3 - }, - { - "fieldName":"setup", - "location":{ - "rowIdx":3, - "colIdx":0 - }, - "spellIds":[ - 13983, - 14070, - 14071 - ], - "maxPoints":3 - }, - { - "fieldName":"initiative", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 13976, - 13979, - 13980 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedAmbush", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 14079, - 14080 - ], - "maxPoints":2 - }, - { - "fieldName":"heightenedSenses", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 30894, - 30895 - ], - "maxPoints":2 - }, - { - "fieldName":"preparation", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 14185 - ], - "maxPoints":1 - }, - { - "fieldName":"dirtyDeeds", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 14082, - 14083 - ], - "maxPoints":2 - }, - { - "fieldName":"hemorrhage", - "location":{ - "rowIdx":4, - "colIdx":3 - }, - "prereqLocation":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 16511 - ], - "maxPoints":1 - }, - { - "fieldName":"masterOfSubtlety", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 31221, - 31222, - 31223 - ], - "maxPoints":3 - }, - { - "fieldName":"deadliness", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 30902, - 30903, - 30904, - 30905, - 30906 - ], - "maxPoints":5 - }, - { - "fieldName":"envelopingShadows", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 31211, - 31212, - 31213 - ], - "maxPoints":3 - }, - { - "fieldName":"premeditation", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 14183 - ], - "maxPoints":1 - }, - { - "fieldName":"cheatDeath", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 31228, - 31229, - 31230 - ], - "maxPoints":3 - }, - { - "fieldName":"sinisterCalling", - "location":{ - "rowIdx":7, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 31216, - 31217, - 31218, - 31219, - 31220 - ], - "maxPoints":5 - }, - { - "fieldName":"waylay", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 51692, - 51696 - ], - "maxPoints":2 - }, - { - "fieldName":"honorAmongThieves", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 51698, - 51700, - 51701 - ], - "maxPoints":3 - }, - { - "fieldName":"shadowstep", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 36554 - ], - "maxPoints":1 - }, - { - "fieldName":"filthyTricks", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 58414, - 58415 - ], - "maxPoints":2 - }, - { - "fieldName":"slaughterFromTheShadows", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 51708, - 51709, - 51710, - 51711, - 51712 - ], - "maxPoints":5 - }, - { - "fieldName":"shadowDance", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 51713 - ], - "maxPoints":1 - } - ] - } + { + "name": "Assassination", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/182.jpg", + "talents": [ + { + "fieldName": "deadlyMomentum", + "fancyName": "Deadly Momentum", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 79121, + 79122 + ], + "maxPoints": 2 + }, + { + "fieldName": "coupDeGrace", + "fancyName": "Coup De Grace", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 14162, + 14163, + 14164 + ], + "maxPoints": 3 + }, + { + "fieldName": "lethality", + "fancyName": "Lethality", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 14128, + 14132, + 14135 + ], + "maxPoints": 3 + }, + { + "fieldName": "ruthlessness", + "fancyName": "Ruthlessness", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 14156, + 14160, + 14161 + ], + "maxPoints": 3 + }, + { + "fieldName": "quickening", + "fancyName": "Quickening", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 31208, + 31209 + ], + "maxPoints": 2 + }, + { + "fieldName": "puncturingWounds", + "fancyName": "Puncturing Wounds", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 13733, + 13865, + 13866 + ], + "maxPoints": 3 + }, + { + "fieldName": "blackjack", + "fancyName": "Blackjack", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 79123, + 79125 + ], + "maxPoints": 2 + }, + { + "fieldName": "deadlyBrew", + "fancyName": "Deadly Brew", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 51625, + 51626 + ], + "maxPoints": 2 + }, + { + "fieldName": "coldBlood", + "fancyName": "Cold Blood", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 14177 + ], + "maxPoints": 1 + }, + { + "fieldName": "vilePoisons", + "fancyName": "Vile Poisons", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 16513, + 16514, + 16515 + ], + "maxPoints": 3 + }, + { + "fieldName": "deadenedNerves", + "fancyName": "Deadened Nerves", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 31380, + 31382, + 31383 + ], + "maxPoints": 3 + }, + { + "fieldName": "sealFate", + "fancyName": "Seal Fate", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 14186, + 14190 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "murderousIntent", + "fancyName": "Murderous Intent", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 14158, + 14159 + ], + "maxPoints": 2 + }, + { + "fieldName": "overkill", + "fancyName": "Overkill", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 58426 + ], + "maxPoints": 1 + }, + { + "fieldName": "masterPoisoner", + "fancyName": "Master Poisoner", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 58410 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 2 + } + }, + { + "fieldName": "improvedExposeArmor", + "fancyName": "Improved Expose Armor", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 14168, + 14169 + ], + "maxPoints": 2 + }, + { + "fieldName": "cutToTheChase", + "fancyName": "Cut To The Chase", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 51664, + 51665, + 51667 + ], + "maxPoints": 3 + }, + { + "fieldName": "venomousWounds", + "fancyName": "Venomous Wounds", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 79133, + 79134 + ], + "maxPoints": 2 + }, + { + "fieldName": "vendetta", + "fancyName": "Vendetta", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 79140 + ], + "maxPoints": 1 + } + ] + }, + { + "name": "Combat", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/181.jpg", + "talents": [ + { + "fieldName": "improvedRecuperate", + "fancyName": "Improved Recuperate", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 79007, + 79008 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedSinisterStrike", + "fancyName": "Improved Sinister Strike", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 13732, + 13863, + 79004 + ], + "maxPoints": 3 + }, + { + "fieldName": "precision", + "fancyName": "Precision", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 13705, + 13832, + 13843 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedSliceAndDice", + "fancyName": "Improved Slice And Dice", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 14165, + 14166 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedSprint", + "fancyName": "Improved Sprint", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 13743, + 13875 + ], + "maxPoints": 2 + }, + { + "fieldName": "aggression", + "fancyName": "Aggression", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 18427, + 18428, + 18429 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedKick", + "fancyName": "Improved Kick", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 13754, + 13867 + ], + "maxPoints": 2 + }, + { + "fieldName": "lightningReflexes", + "fancyName": "Lightning Reflexes", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 13712, + 13788, + 13789 + ], + "maxPoints": 3 + }, + { + "fieldName": "revealingStrike", + "fancyName": "Revealing Strike", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 84617 + ], + "maxPoints": 1 + }, + { + "fieldName": "reinforcedLeather", + "fancyName": "Reinforced Leather", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 79077, + 79079 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedGouge", + "fancyName": "Improved Gouge", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 13741, + 13793 + ], + "maxPoints": 2 + }, + { + "fieldName": "combatPotency", + "fancyName": "Combat Potency", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 35541, + 35550, + 35551 + ], + "maxPoints": 3 + }, + { + "fieldName": "bladeTwisting", + "fancyName": "Blade Twisting", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 31124, + 31126 + ], + "maxPoints": 2 + }, + { + "fieldName": "throwingSpecialization", + "fancyName": "Throwing Specialization", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 5952, + 51679 + ], + "maxPoints": 2 + }, + { + "fieldName": "adrenalineRush", + "fancyName": "Adrenaline Rush", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 13750 + ], + "maxPoints": 1 + }, + { + "fieldName": "savageCombat", + "fancyName": "Savage Combat", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 51682, + 58413 + ], + "maxPoints": 2 + }, + { + "fieldName": "banditsGuile", + "fancyName": "Bandits Guile", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 84652, + 84653, + 84654 + ], + "maxPoints": 3 + }, + { + "fieldName": "restlessBlades", + "fancyName": "Restless Blades", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 79095, + 79096 + ], + "maxPoints": 2 + }, + { + "fieldName": "killingSpree", + "fancyName": "Killing Spree", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 51690 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] + }, + { + "name": "Subtlety", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/183.jpg", + "talents": [ + { + "fieldName": "nightstalker", + "fancyName": "Nightstalker", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 13975, + 14062 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedAmbush", + "fancyName": "Improved Ambush", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 14079, + 14080, + 84661 + ], + "maxPoints": 3 + }, + { + "fieldName": "relentlessStrikes", + "fancyName": "Relentless Strikes", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 14179, + 58422, + 58423 + ], + "maxPoints": 3 + }, + { + "fieldName": "elusiveness", + "fancyName": "Elusiveness", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 13981, + 14066 + ], + "maxPoints": 2 + }, + { + "fieldName": "waylay", + "fancyName": "Waylay", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 51692, + 51696 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 0, + "colIdx": 1 + } + }, + { + "fieldName": "opportunity", + "fancyName": "Opportunity", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 14057, + 14072, + 79141 + ], + "maxPoints": 3 + }, + { + "fieldName": "initiative", + "fancyName": "Initiative", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 13976, + 13979 + ], + "maxPoints": 2 + }, + { + "fieldName": "energeticRecovery", + "fancyName": "Energetic Recovery", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 79150, + 79151, + 79152 + ], + "maxPoints": 3 + }, + { + "fieldName": "findWeakness", + "fancyName": "Find Weakness", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 51632, + 91023 + ], + "maxPoints": 2 + }, + { + "fieldName": "hemorrhage", + "fancyName": "Hemorrhage", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 16511 + ], + "maxPoints": 1 + }, + { + "fieldName": "honorAmongThieves", + "fancyName": "Honor Among Thieves", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 51698, + 51700, + 51701 + ], + "maxPoints": 3 + }, + { + "fieldName": "premeditation", + "fancyName": "Premeditation", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 14183 + ], + "maxPoints": 1 + }, + { + "fieldName": "envelopingShadows", + "fancyName": "Enveloping Shadows", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 31211, + 31212, + 31213 + ], + "maxPoints": 3 + }, + { + "fieldName": "cheatDeath", + "fancyName": "Cheat Death", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 31228, + 31229, + 31230 + ], + "maxPoints": 3 + }, + { + "fieldName": "preparation", + "fancyName": "Preparation", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 14185 + ], + "maxPoints": 1 + }, + { + "fieldName": "sanguinaryVein", + "fancyName": "Sanguinary Vein", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 79146, + 79147 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 2 + } + }, + { + "fieldName": "slaughterFromTheShadows", + "fancyName": "Slaughter From The Shadows", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 51708, + 51709, + 51710 + ], + "maxPoints": 3 + }, + { + "fieldName": "serratedBlades", + "fancyName": "Serrated Blades", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 14171, + 14172 + ], + "maxPoints": 2 + }, + { + "fieldName": "shadowDance", + "fancyName": "Shadow Dance", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 51713 + ], + "maxPoints": 1 + } + ] + } ] \ No newline at end of file diff --git a/ui/core/talents/trees/shaman.json b/ui/core/talents/trees/shaman.json index 4a9866e9e7..2bb22826a4 100644 --- a/ui/core/talents/trees/shaman.json +++ b/ui/core/talents/trees/shaman.json @@ -1,1020 +1,806 @@ [ - { - "name":"Elemental", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/classic/261.jpg", - "talents":[ - { - "fieldName":"convection", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 16039, - 16109 - ], - "maxPoints":5 - }, - { - "fieldName":"concussion", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 16035, - 16105 - ], - "maxPoints":5 - }, - { - "fieldName":"callOfFlame", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 16038, - 16160, - 16161 - ], - "maxPoints":3 - }, - { - "fieldName":"elementalWarding", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 28996, - 28997, - 28998 - ], - "maxPoints":3 - }, - { - "fieldName":"elementalDevastation", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 30160, - 29179, - 29180 - ], - "maxPoints":3 - }, - { - "fieldName":"reverberation", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 16040, - 16113, - 16114, - 16115, - 16116 - ], - "maxPoints":5 - }, - { - "fieldName":"elementalFocus", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 16164 - ], - "maxPoints":1 - }, - { - "fieldName":"elementalFury", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 16089, - 60184, - 60185, - 60187, - 60188 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedFireNova", - "location":{ - "rowIdx":3, - "colIdx":0 - }, - "spellIds":[ - 16086, - 16544 - ], - "maxPoints":2 - }, - { - "fieldName":"eyeOfTheStorm", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "spellIds":[ - 29062, - 29064 - ], - "maxPoints":3 - }, - { - "fieldName":"elementalReach", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 28999 - ], - "maxPoints":2 - }, - { - "fieldName":"callOfThunder", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 16041 - ], - "maxPoints":1 - }, - { - "fieldName":"unrelentingStorm", - "location":{ - "rowIdx":4, - "colIdx":3 - }, - "spellIds":[ - 30664, - 30665, - 30666 - ], - "maxPoints":3 - }, - { - "fieldName":"elementalPrecision", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 30672, - 30673, - 30674 - ], - "maxPoints":3 - }, - { - "fieldName":"lightningMastery", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 16578 - ], - "maxPoints":5 - }, - { - "fieldName":"elementalMastery", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 16166 - ], - "maxPoints":1 - }, - { - "fieldName":"stormEarthAndFire", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 51483, - 51485, - 51486 - ], - "maxPoints":3 - }, - { - "fieldName":"boomingEchoes", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 63370, - 63372 - ], - "maxPoints":2 - }, - { - "fieldName":"elementalOath", - "location":{ - "rowIdx":7, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 51466, - 51470 - ], - "maxPoints":2 - }, - { - "fieldName":"lightningOverload", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 30675, - 30678, - 30679 - ], - "maxPoints":3 - }, - { - "fieldName":"astralShift", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 51474, - 51478, - 51479 - ], - "maxPoints":3 - }, - { - "fieldName":"totemOfWrath", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 30706 - ], - "maxPoints":1 - }, - { - "fieldName":"lavaFlows", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 51480, - 51481, - 51482 - ], - "maxPoints":3 - }, - { - "fieldName":"shamanism", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 62097 - ], - "maxPoints":5 - }, - { - "fieldName":"thunderstorm", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 51490 - ], - "maxPoints":1 - } - ] - }, - { - "name":"Enhancement", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/classic/263.jpg", - "talents":[ - { - "fieldName":"enhancingTotems", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 16259, - 16295, - 52456 - ], - "maxPoints":3 - }, - { - "fieldName":"earthsGrasp", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 16043, - 16130 - ], - "maxPoints":2 - }, - { - "fieldName":"ancestralKnowledge", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 17485 - ], - "maxPoints":5 - }, - { - "fieldName":"guardianTotems", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 16258, - 16293 - ], - "maxPoints":2 - }, - { - "fieldName":"thunderingStrikes", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 16255, - 16302 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedGhostWolf", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 16262, - 16287 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedShields", - "location":{ - "rowIdx":1, - "colIdx":3 - }, - "spellIds":[ - 16261, - 16290, - 51881 - ], - "maxPoints":3 - }, - { - "fieldName":"elementalWeapons", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 16266, - 29079, - 29080 - ], - "maxPoints":3 - }, - { - "fieldName":"shamanisticFocus", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 43338 - ], - "maxPoints":1 - }, - { - "fieldName":"anticipation", - "location":{ - "rowIdx":2, - "colIdx":3 - }, - "spellIds":[ - 16254, - 16271 - ], - "maxPoints":3 - }, - { - "fieldName":"flurry", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 16256, - 16281 - ], - "maxPoints":5 - }, - { - "fieldName":"toughness", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 16252, - 16306 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedWindfuryTotem", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 29192, - 29193 - ], - "maxPoints":2 - }, - { - "fieldName":"spiritWeapons", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 16268 - ], - "maxPoints":1 - }, - { - "fieldName":"mentalDexterity", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 51883 - ], - "maxPoints":3 - }, - { - "fieldName":"unleashedRage", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 30802, - 30808, - 30809 - ], - "maxPoints":3 - }, - { - "fieldName":"weaponMastery", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 29082, - 29084, - 29086 - ], - "maxPoints":3 - }, - { - "fieldName":"frozenPower", - "location":{ - "rowIdx":5, - "colIdx":3 - }, - "spellIds":[ - 63373, - 63374 - ], - "maxPoints":2 - }, - { - "fieldName":"dualWieldSpecialization", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 30816, - 30818 - ], - "maxPoints":3 - }, - { - "fieldName":"dualWield", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 30798 - ], - "maxPoints":1 - }, - { - "fieldName":"stormstrike", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 17364 - ], - "maxPoints":1 - }, - { - "fieldName":"staticShock", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 51525 - ], - "maxPoints":3 - }, - { - "fieldName":"lavaLash", - "location":{ - "rowIdx":7, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 60103 - ], - "maxPoints":1 - }, - { - "fieldName":"improvedStormstrike", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 51521, - 51522 - ], - "maxPoints":2 - }, - { - "fieldName":"mentalQuickness", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 30812 - ], - "maxPoints":3 - }, - { - "fieldName":"shamanisticRage", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 30823 - ], - "maxPoints":1 - }, - { - "fieldName":"earthenPower", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 51523, - 51524 - ], - "maxPoints":2 - }, - { - "fieldName":"maelstromWeapon", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 51528 - ], - "maxPoints":5 - }, - { - "fieldName":"feralSpirit", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 51533 - ], - "maxPoints":1 - } - ] - }, - { - "name":"Restoration", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/classic/262.jpg", - "talents":[ - { - "fieldName":"improvedHealingWave", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 16182, - 16226 - ], - "maxPoints":5 - }, - { - "fieldName":"totemicFocus", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 16173, - 16222 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedReincarnation", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 16184, - 16209 - ], - "maxPoints":2 - }, - { - "fieldName":"healingGrace", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 29187, - 29189, - 29191 - ], - "maxPoints":3 - }, - { - "fieldName":"tidalFocus", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 16179, - 16214 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedWaterShield", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 16180, - 16196, - 16198 - ], - "maxPoints":3 - }, - { - "fieldName":"healingFocus", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 16181, - 16230, - 16232 - ], - "maxPoints":3 - }, - { - "fieldName":"tidalForce", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 55198 - ], - "maxPoints":1 - }, - { - "fieldName":"ancestralUealing", - "location":{ - "rowIdx":2, - "colIdx":3 - }, - "spellIds":[ - 16176, - 16235 - ], - "maxPoints":3 - }, - { - "fieldName":"restorativeTotems", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 16187, - 16205 - ], - "maxPoints":3 - }, - { - "fieldName":"tidalMastery", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 16194, - 16218 - ], - "maxPoints":5 - }, - { - "fieldName":"healingWay", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 29206, - 29205, - 29202 - ], - "maxPoints":3 - }, - { - "fieldName":"naturesSwiftness", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 16188 - ], - "maxPoints":1 - }, - { - "fieldName":"focusedMind", - "location":{ - "rowIdx":4, - "colIdx":3 - }, - "spellIds":[ - 30864 - ], - "maxPoints":3 - }, - { - "fieldName":"purification", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 16178, - 16210 - ], - "maxPoints":5 - }, - { - "fieldName":"naturesGuardian", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 30881, - 30883 - ], - "maxPoints":5 - }, - { - "fieldName":"manaTideTotem", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "prereqLocation":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 16190 - ], - "maxPoints":1 - }, - { - "fieldName":"cleanseSpirit", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 51886 - ], - "maxPoints":1 - }, - { - "fieldName":"blessingOfTheEternals", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 51554, - 51555 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedChainHeal", - "location":{ - "rowIdx":7, - "colIdx":1 - }, - "spellIds":[ - 30872 - ], - "maxPoints":2 - }, - { - "fieldName":"naturesBlessing", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 30867 - ], - "maxPoints":3 - }, - { - "fieldName":"ancestralAwakening", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 51556 - ], - "maxPoints":3 - }, - { - "fieldName":"earthShield", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 974 - ], - "maxPoints":1 - }, - { - "fieldName":"improvedEarthShield", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "prereqLocation":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 51560 - ], - "maxPoints":2 - }, - { - "fieldName":"tidalWaves", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 51562 - ], - "maxPoints":5 - }, - { - "fieldName":"riptide", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 61295 - ], - "maxPoints":1 - } - ] - } + { + "name": "Elemental", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/261.jpg", + "talents": [ + { + "fieldName": "acuity", + "fancyName": "Acuity", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 17485, + 17486, + 17487 + ], + "maxPoints": 3 + }, + { + "fieldName": "convection", + "fancyName": "Convection", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 16039, + 16109 + ], + "maxPoints": 2 + }, + { + "fieldName": "concussion", + "fancyName": "Concussion", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 16035, + 16105, + 16106 + ], + "maxPoints": 3 + }, + { + "fieldName": "callOfFlame", + "fancyName": "Call Of Flame", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 16038, + 16160 + ], + "maxPoints": 2 + }, + { + "fieldName": "elementalWarding", + "fancyName": "Elemental Warding", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 28996, + 28997, + 28998 + ], + "maxPoints": 3 + }, + { + "fieldName": "reverberation", + "fancyName": "Reverberation", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 16040, + 16113 + ], + "maxPoints": 2 + }, + { + "fieldName": "elementalPrecision", + "fancyName": "Elemental Precision", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 30672, + 30673, + 30674 + ], + "maxPoints": 3 + }, + { + "fieldName": "rollingThunder", + "fancyName": "Rolling Thunder", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 88756, + 88764 + ], + "maxPoints": 2 + }, + { + "fieldName": "elementalFocus", + "fancyName": "Elemental Focus", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 16164 + ], + "maxPoints": 1 + }, + { + "fieldName": "elementalReach", + "fancyName": "Elemental Reach", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 28999, + 29000 + ], + "maxPoints": 2 + }, + { + "fieldName": "elementalOath", + "fancyName": "Elemental Oath", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 51466, + 51470 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "lavaFlows", + "fancyName": "Lava Flows", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 51480, + 51481, + 51482 + ], + "maxPoints": 3 + }, + { + "fieldName": "fulmination", + "fancyName": "Fulmination", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 88766 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 0 + } + }, + { + "fieldName": "elementalMastery", + "fancyName": "Elemental Mastery", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 16166 + ], + "maxPoints": 1 + }, + { + "fieldName": "earthsGrasp", + "fancyName": "Earths Grasp", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 51483, + 51485 + ], + "maxPoints": 2 + }, + { + "fieldName": "totemicWrath", + "fancyName": "Totemic Wrath", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 77746 + ], + "maxPoints": 1 + }, + { + "fieldName": "feedback", + "fancyName": "Feedback", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 86183, + 86184, + 86185 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "lavaSurge", + "fancyName": "Lava Surge", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 77755, + 77756 + ], + "maxPoints": 2 + }, + { + "fieldName": "earthquake", + "fancyName": "Earthquake", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 61882 + ], + "maxPoints": 1 + } + ] + }, + { + "name": "Enhancement", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/263.jpg", + "talents": [ + { + "fieldName": "elementalWeapons", + "fancyName": "Elemental Weapons", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 16266, + 29079 + ], + "maxPoints": 2 + }, + { + "fieldName": "focusedStrikes", + "fancyName": "Focused Strikes", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 77536, + 77537, + 77538 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedShields", + "fancyName": "Improved Shields", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 16261, + 16290, + 51881 + ], + "maxPoints": 3 + }, + { + "fieldName": "elementalDevastation", + "fancyName": "Elemental Devastation", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 30160, + 29179, + 29180 + ], + "maxPoints": 3 + }, + { + "fieldName": "flurry", + "fancyName": "Flurry", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 16256, + 16281, + 16282 + ], + "maxPoints": 3 + }, + { + "fieldName": "ancestralSwiftness", + "fancyName": "Ancestral Swiftness", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 16262, + 16287 + ], + "maxPoints": 2 + }, + { + "fieldName": "totemicReach", + "fancyName": "Totemic Reach", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 86935, + 86936 + ], + "maxPoints": 2 + }, + { + "fieldName": "toughness", + "fancyName": "Toughness", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 16252, + 16306, + 16307 + ], + "maxPoints": 3 + }, + { + "fieldName": "stormstrike", + "fancyName": "Stormstrike", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 17364 + ], + "maxPoints": 1 + }, + { + "fieldName": "staticShock", + "fancyName": "Static Shock", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 51525, + 51526, + 51527 + ], + "maxPoints": 3 + }, + { + "fieldName": "frozenPower", + "fancyName": "Frozen Power", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 63373, + 63374 + ], + "maxPoints": 2 + }, + { + "fieldName": "seasonedWinds", + "fancyName": "Seasoned Winds", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 16086, + 16544 + ], + "maxPoints": 2 + }, + { + "fieldName": "searingFlames", + "fancyName": "Searing Flames", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 77655, + 77656, + 77657 + ], + "maxPoints": 3 + }, + { + "fieldName": "earthenPower", + "fancyName": "Earthen Power", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 51523, + 51524 + ], + "maxPoints": 2 + }, + { + "fieldName": "shamanisticRage", + "fancyName": "Shamanistic Rage", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 30823 + ], + "maxPoints": 1 + }, + { + "fieldName": "unleashedRage", + "fancyName": "Unleashed Rage", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 30802, + 30808 + ], + "maxPoints": 2 + }, + { + "fieldName": "maelstromWeapon", + "fancyName": "Maelstrom Weapon", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 51528, + 51529, + 51530 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedLavaLash", + "fancyName": "Improved Lava Lash", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 77700, + 77701 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 2 + } + }, + { + "fieldName": "feralSpirit", + "fancyName": "Feral Spirit", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 51533 + ], + "maxPoints": 1 + } + ] + }, + { + "name": "Restoration", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/262.jpg", + "talents": [ + { + "fieldName": "ancestralResolve", + "fancyName": "Ancestral Resolve", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 77829, + 77830 + ], + "maxPoints": 2 + }, + { + "fieldName": "tidalFocus", + "fancyName": "Tidal Focus", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 16179, + 16214, + 16215 + ], + "maxPoints": 3 + }, + { + "fieldName": "sparkOfLife", + "fancyName": "Spark Of Life", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 84846, + 84847, + 84848 + ], + "maxPoints": 3 + }, + { + "fieldName": "resurgence", + "fancyName": "Resurgence", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 16180, + 16196 + ], + "maxPoints": 2 + }, + { + "fieldName": "totemicFocus", + "fancyName": "Totemic Focus", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 16173, + 16222 + ], + "maxPoints": 2 + }, + { + "fieldName": "focusedInsight", + "fancyName": "Focused Insight", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 77794, + 77795, + 77796 + ], + "maxPoints": 3 + }, + { + "fieldName": "naturesGuardian", + "fancyName": "Natures Guardian", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 30881, + 30883, + 30884 + ], + "maxPoints": 3 + }, + { + "fieldName": "ancestralHealing", + "fancyName": "Ancestral Healing", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 16176, + 16235 + ], + "maxPoints": 2 + }, + { + "fieldName": "naturesSwiftness", + "fancyName": "Natures Swiftness", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 16188 + ], + "maxPoints": 1 + }, + { + "fieldName": "naturesBlessing", + "fancyName": "Natures Blessing", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 30867, + 30868, + 30869 + ], + "maxPoints": 3 + }, + { + "fieldName": "soothingRains", + "fancyName": "Soothing Rains", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 16187, + 16205 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedCleanseSpirit", + "fancyName": "Improved Cleanse Spirit", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 77130 + ], + "maxPoints": 1 + }, + { + "fieldName": "cleansingWaters", + "fancyName": "Cleansing Waters", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 86959, + 86962 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 2 + } + }, + { + "fieldName": "ancestralAwakening", + "fancyName": "Ancestral Awakening", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 51556, + 51558, + 51557 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 0 + } + }, + { + "fieldName": "manaTideTotem", + "fancyName": "Mana Tide Totem", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 16190 + ], + "maxPoints": 1 + }, + { + "fieldName": "telluricCurrents", + "fancyName": "Telluric Currents", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 82984, + 82988 + ], + "maxPoints": 2 + }, + { + "fieldName": "spiritLinkTotem", + "fancyName": "Spirit Link Totem", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 98008 + ], + "maxPoints": 1 + }, + { + "fieldName": "tidalWaves", + "fancyName": "Tidal Waves", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 51562, + 51563, + 51564 + ], + "maxPoints": 3 + }, + { + "fieldName": "blessingOfTheEternals", + "fancyName": "Blessing Of The Eternals", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 51554, + 51555 + ], + "maxPoints": 2 + }, + { + "fieldName": "riptide", + "fancyName": "Riptide", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 61295 + ], + "maxPoints": 1 + } + ] + } ] \ No newline at end of file diff --git a/ui/core/talents/trees/warlock.json b/ui/core/talents/trees/warlock.json index 3202bacea2..36edb8c2eb 100644 --- a/ui/core/talents/trees/warlock.json +++ b/ui/core/talents/trees/warlock.json @@ -1,1106 +1,787 @@ [ - { - "name":"Affliction", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/302.jpg", - "talents":[ - { - "fieldName":"improvedCurseOfAgony", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 18827, - 18829 - ], - "maxPoints":2 - }, - { - "fieldName":"suppression", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 18174, - 18175, - 18176 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedCorruption", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 17810, - 17811, - 17812, - 17813, - 17814 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedCurseOfWeakness", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 18179, - 18180 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedDrainSoul", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 18213, - 18372 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedLifeTap", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 18182, - 18183 - ], - "maxPoints":2 - }, - { - "fieldName":"soulSiphon", - "location":{ - "rowIdx":1, - "colIdx":3 - }, - "spellIds":[ - 17804, - 17805 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedFear", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 53754, - 53759 - ], - "maxPoints":2 - }, - { - "fieldName":"felConcentration", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 17783, - 17784, - 17785 - ], - "maxPoints":3 - }, - { - "fieldName":"amplifyCurse", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 18288 - ], - "maxPoints":1 - }, - { - "fieldName":"grimReach", - "location":{ - "rowIdx":3, - "colIdx":0 - }, - "spellIds":[ - 18218, - 18219 - ], - "maxPoints":2 - }, - { - "fieldName":"nightfall", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 18094, - 18095 - ], - "maxPoints":2 - }, - { - "fieldName":"empoweredCorruption", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "spellIds":[ - 32381, - 32382, - 32383 - ], - "maxPoints":3 - }, - { - "fieldName":"shadowEmbrace", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 32385, - 32387, - 32392, - 32393, - 32394 - ], - "maxPoints":5 - }, - { - "fieldName":"siphonLife", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 63108 - ], - "maxPoints":1 - }, - { - "fieldName":"curseOfExhaustion", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 18223 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":2, - "colIdx":2 - } - }, - { - "fieldName":"improvedFelhunter", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 54037, - 54038 - ], - "maxPoints":2 - }, - { - "fieldName":"shadowMastery", - "location":{ - "rowIdx":5, - "colIdx":1 - }, - "spellIds":[ - 18271, - 18272, - 18273, - 18274, - 18275 - ], - "maxPoints":5, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - } - }, - { - "fieldName":"eradication", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 47195, - 47196, - 47197 - ], - "maxPoints":3 - }, - { - "fieldName":"contagion", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 30060, - 30061, - 30062, - 30063, - 30064 - ], - "maxPoints":5 - }, - { - "fieldName":"darkPact", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 18220 - ], - "maxPoints":1 - }, - { - "fieldName":"improvedHowlOfTerror", - "location":{ - "rowIdx":7, - "colIdx":0 - }, - "spellIds":[ - 30054, - 30057 - ], - "maxPoints":2 - }, - { - "fieldName":"malediction", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 32477, - 32483, - 32484 - ], - "maxPoints":3 - }, - { - "fieldName":"deathsEmbrace", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 47198, - 47199, - 47200 - ], - "maxPoints":3 - }, - { - "fieldName":"unstableAffliction", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 30108 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - } - }, - { - "fieldName":"pandemic", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 58435 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":8, - "colIdx":1 - } - }, - { - "fieldName":"everlastingAffliction", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 47201, - 47202, - 47203, - 47204, - 47205 - ], - "maxPoints":5 - }, - { - "fieldName":"haunt", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 48181 - ], - "maxPoints":1 - } - ] - }, - { - "name":"Demonology", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/303.jpg", - "talents":[ - { - "fieldName":"improvedHealthstone", - "location":{ - "rowIdx":0, - "colIdx":0 - }, - "spellIds":[ - 18692, - 18693 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedImp", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 18694, - 18695, - 18696 - ], - "maxPoints":3 - }, - { - "fieldName":"demonicEmbrace", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 18697, - 18698, - 18699 - ], - "maxPoints":3 - }, - { - "fieldName":"felSynergy", - "location":{ - "rowIdx":0, - "colIdx":3 - }, - "spellIds":[ - 47230, - 47231 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedHealthFunnel", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 18703, - 18704 - ], - "maxPoints":2 - }, - { - "fieldName":"demonicBrutality", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 18705, - 18706, - 18707 - ], - "maxPoints":3 - }, - { - "fieldName":"felVitality", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 18731, - 18743, - 18744 - ], - "maxPoints":3 - }, - { - "fieldName":"improvedSayaad", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 18754, - 18755, - 18756 - ], - "maxPoints":3 - }, - { - "fieldName":"soulLink", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 19028 - ], - "maxPoints":1 - }, - { - "fieldName":"felDomination", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 18708 - ], - "maxPoints":1 - }, - { - "fieldName":"demonicAegis", - "location":{ - "rowIdx":2, - "colIdx":3 - }, - "spellIds":[ - 30143, - 30144, - 30145 - ], - "maxPoints":3 - }, - { - "fieldName":"unholyPower", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 18769, - 18770, - 18771, - 18772, - 18773 - ], - "maxPoints":5, - "prereqLocation":{ - "rowIdx":2, - "colIdx":1 - } - }, - { - "fieldName":"masterSummoner", - "location":{ - "rowIdx":3, - "colIdx":2 - }, - "spellIds":[ - 18709, - 18710 - ], - "maxPoints":2, - "prereqLocation":{ - "rowIdx":2, - "colIdx":2 - } - }, - { - "fieldName":"manaFeed", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 30326 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":3, - "colIdx":1 - } - }, - { - "fieldName":"masterConjuror", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 18767, - 18768 - ], - "maxPoints":2 - }, - { - "fieldName":"masterDemonologist", - "location":{ - "rowIdx":5, - "colIdx":1 - }, - "spellIds":[ - 23785, - 23822, - 23823, - 23824, - 23825 - ], - "maxPoints":5, - "prereqLocation":{ - "rowIdx":3, - "colIdx":1 - } - }, - { - "fieldName":"moltenCore", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 47245, - 47246, - 47247 - ], - "maxPoints":3 - }, - { - "fieldName":"demonicResilience", - "location":{ - "rowIdx":6, - "colIdx":0 - }, - "spellIds":[ - 30319, - 30320, - 30321 - ], - "maxPoints":3 - }, - { - "fieldName":"demonicEmpowerment", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 47193 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":5, - "colIdx":1 - } - }, - { - "fieldName":"demonicKnowledge", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 35691, - 35692, - 35693 - ], - "maxPoints":3 - }, - { - "fieldName":"demonicTactics", - "location":{ - "rowIdx":7, - "colIdx":1 - }, - "spellIds":[ - 30242, - 30245, - 30246, - 30247, - 30248 - ], - "maxPoints":5 - }, - { - "fieldName":"decimation", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 63156, - 63158 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedDemonicTactics", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 54347, - 54348, - 54349 - ], - "maxPoints":3, - "prereqLocation":{ - "rowIdx":7, - "colIdx":1 - } - }, - { - "fieldName":"summonFelguard", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 30146 - ], - "maxPoints":1 - }, - { - "fieldName":"nemesis", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 63117, - 63121, - 63123 - ], - "maxPoints":3 - }, - { - "fieldName":"demonicPact", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 47236, - 47237, - 47238, - 47239, - 47240 - ], - "maxPoints":5 - }, - { - "fieldName":"metamorphosis", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 59672 - ], - "maxPoints":1 - } - ] - }, - { - "name":"Destruction", - "backgroundUrl":"https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/301.jpg", - "talents":[ - { - "fieldName":"improvedShadowBolt", - "location":{ - "rowIdx":0, - "colIdx":1 - }, - "spellIds":[ - 17793, - 17796, - 17801, - 17802, - 17803 - ], - "maxPoints":5 - }, - { - "fieldName":"bane", - "location":{ - "rowIdx":0, - "colIdx":2 - }, - "spellIds":[ - 17788, - 17789, - 17790, - 17791, - 17792 - ], - "maxPoints":5 - }, - { - "fieldName":"aftermath", - "location":{ - "rowIdx":1, - "colIdx":0 - }, - "spellIds":[ - 18119, - 18120 - ], - "maxPoints":2 - }, - { - "fieldName":"moltenSkin", - "location":{ - "rowIdx":1, - "colIdx":1 - }, - "spellIds":[ - 63349, - 63350, - 63351 - ], - "maxPoints":3 - }, - { - "fieldName":"cataclysm", - "location":{ - "rowIdx":1, - "colIdx":2 - }, - "spellIds":[ - 17778, - 17779, - 17780 - ], - "maxPoints":3 - }, - { - "fieldName":"demonicPower", - "location":{ - "rowIdx":2, - "colIdx":0 - }, - "spellIds":[ - 18126, - 18127 - ], - "maxPoints":2 - }, - { - "fieldName":"shadowburn", - "location":{ - "rowIdx":2, - "colIdx":1 - }, - "spellIds":[ - 17877 - ], - "maxPoints":1 - }, - { - "fieldName":"ruin", - "location":{ - "rowIdx":2, - "colIdx":2 - }, - "spellIds":[ - 17959, - 59738, - 59739, - 59740, - 59741 - ], - "maxPoints":5 - }, - { - "fieldName":"intensity", - "location":{ - "rowIdx":3, - "colIdx":0 - }, - "spellIds":[ - 18135, - 18136 - ], - "maxPoints":2 - }, - { - "fieldName":"destructiveReach", - "location":{ - "rowIdx":3, - "colIdx":1 - }, - "spellIds":[ - 17917, - 17918 - ], - "maxPoints":2 - }, - { - "fieldName":"improvedSearingPain", - "location":{ - "rowIdx":3, - "colIdx":3 - }, - "spellIds":[ - 17927, - 17929, - 17930 - ], - "maxPoints":3 - }, - { - "fieldName":"backlash", - "location":{ - "rowIdx":4, - "colIdx":0 - }, - "spellIds":[ - 34935, - 34938, - 34939 - ], - "maxPoints":3, - "prereqLocation":{ - "rowIdx":3, - "colIdx":0 - } - }, - { - "fieldName":"improvedImmolate", - "location":{ - "rowIdx":4, - "colIdx":1 - }, - "spellIds":[ - 17815, - 17833, - 17834 - ], - "maxPoints":3 - }, - { - "fieldName":"devastation", - "location":{ - "rowIdx":4, - "colIdx":2 - }, - "spellIds":[ - 18130 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":2, - "colIdx":2 - } - }, - { - "fieldName":"netherProtection", - "location":{ - "rowIdx":5, - "colIdx":0 - }, - "spellIds":[ - 30299, - 30301, - 30302 - ], - "maxPoints":3 - }, - { - "fieldName":"emberstorm", - "location":{ - "rowIdx":5, - "colIdx":2 - }, - "spellIds":[ - 17954, - 17955, - 17956, - 17957, - 17958 - ], - "maxPoints":5 - }, - { - "fieldName":"conflagrate", - "location":{ - "rowIdx":6, - "colIdx":1 - }, - "spellIds":[ - 17962 - ], - "maxPoints":1, - "prereqLocation":{ - "rowIdx":4, - "colIdx":1 - } - }, - { - "fieldName":"soulLeech", - "location":{ - "rowIdx":6, - "colIdx":2 - }, - "spellIds":[ - 30293, - 30295, - 30296 - ], - "maxPoints":3 - }, - { - "fieldName":"pyroclasm", - "location":{ - "rowIdx":6, - "colIdx":3 - }, - "spellIds":[ - 18096, - 18073, - 63245 - ], - "maxPoints":3 - }, - { - "fieldName":"shadowAndFlame", - "location":{ - "rowIdx":7, - "colIdx":1 - }, - "spellIds":[ - 30288, - 30289, - 30290, - 30291, - 30292 - ], - "maxPoints":5 - }, - { - "fieldName":"improvedSoulLeech", - "location":{ - "rowIdx":7, - "colIdx":2 - }, - "spellIds":[ - 54117, - 54118 - ], - "maxPoints":2, - "prereqLocation":{ - "rowIdx":6, - "colIdx":2 - } - }, - { - "fieldName":"backdraft", - "location":{ - "rowIdx":8, - "colIdx":0 - }, - "spellIds":[ - 47258, - 47259, - 47260 - ], - "maxPoints":3, - "prereqLocation":{ - "rowIdx":6, - "colIdx":1 - } - }, - { - "fieldName":"shadowfury", - "location":{ - "rowIdx":8, - "colIdx":1 - }, - "spellIds":[ - 30283 - ], - "maxPoints":1 - }, - { - "fieldName":"empoweredImp", - "location":{ - "rowIdx":8, - "colIdx":2 - }, - "spellIds":[ - 47220, - 47221, - 47223 - ], - "maxPoints":3 - }, - { - "fieldName":"fireAndBrimstone", - "location":{ - "rowIdx":9, - "colIdx":1 - }, - "spellIds":[ - 47266, - 47267, - 47268, - 47269, - 47270 - ], - "maxPoints":5 - }, - { - "fieldName":"chaosBolt", - "location":{ - "rowIdx":10, - "colIdx":1 - }, - "spellIds":[ - 50796 - ], - "maxPoints":1 - } - ] - } + { + "name": "Affliction", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/871.jpg", + "talents": [ + { + "fieldName": "doomAndGloom", + "fancyName": "Doom And Gloom", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 18827, + 18829 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedLifeTap", + "fancyName": "Improved Life Tap", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 18182, + 18183 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedCorruption", + "fancyName": "Improved Corruption", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 17810, + 17811, + 17812, + 17813, + 17814 + ], + "maxPoints": 3 + }, + { + "fieldName": "jinx", + "fancyName": "Jinx", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 18179, + 85479 + ], + "maxPoints": 2 + }, + { + "fieldName": "soulSiphon", + "fancyName": "Soul Siphon", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 17804, + 17805 + ], + "maxPoints": 2 + }, + { + "fieldName": "siphonLife", + "fancyName": "Siphon Life", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 63108, + 86667 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 1, + "colIdx": 1 + } + }, + { + "fieldName": "curseOfExhaustion", + "fancyName": "Curse Of Exhaustion", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 18223 + ], + "maxPoints": 1 + }, + { + "fieldName": "improvedFear", + "fancyName": "Improved Fear", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 53754, + 53759 + ], + "maxPoints": 2 + }, + { + "fieldName": "eradication", + "fancyName": "Eradication", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 47195, + 47196, + 47197 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedHowlOfTerror", + "fancyName": "Improved Howl Of Terror", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 30054, + 30057 + ], + "maxPoints": 2 + }, + { + "fieldName": "soulSwap", + "fancyName": "Soul Swap", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 86121 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 1, + "colIdx": 1 + } + }, + { + "fieldName": "shadowEmbrace", + "fancyName": "Shadow Embrace", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 32385, + 32387, + 32392 + ], + "maxPoints": 3 + }, + { + "fieldName": "deathsEmbrace", + "fancyName": "Deaths Embrace", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 47198, + 47199, + 47200 + ], + "maxPoints": 3 + }, + { + "fieldName": "nightfall", + "fancyName": "Nightfall", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 18094, + 18095 + ], + "maxPoints": 2 + }, + { + "fieldName": "soulburnSeedOfCorruption", + "fancyName": "Soulburn Seed Of Corruption", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 86664 + ], + "maxPoints": 1 + }, + { + "fieldName": "everlastingAffliction", + "fancyName": "Everlasting Affliction", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 47201, + 47202, + 47203 + ], + "maxPoints": 3 + }, + { + "fieldName": "pandemic", + "fancyName": "Pandemic", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 85099, + 85100 + ], + "maxPoints": 2 + }, + { + "fieldName": "haunt", + "fancyName": "Haunt", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 48181 + ], + "maxPoints": 1 + } + ] + }, + { + "name": "Demonology", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/867.jpg", + "talents": [ + { + "fieldName": "demonicEmbrace", + "fancyName": "Demonic Embrace", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 18697, + 18698, + 18699 + ], + "maxPoints": 3 + }, + { + "fieldName": "darkArts", + "fancyName": "Dark Arts", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 18694, + 85283, + 85284 + ], + "maxPoints": 3 + }, + { + "fieldName": "felSynergy", + "fancyName": "Fel Synergy", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 47230, + 47231 + ], + "maxPoints": 2 + }, + { + "fieldName": "demonicRebirth", + "fancyName": "Demonic Rebirth", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 88446, + 88447 + ], + "maxPoints": 2 + }, + { + "fieldName": "manaFeed", + "fancyName": "Mana Feed", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 30326, + 85175 + ], + "maxPoints": 2 + }, + { + "fieldName": "demonicAegis", + "fancyName": "Demonic Aegis", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 30143, + 30144 + ], + "maxPoints": 2 + }, + { + "fieldName": "masterSummoner", + "fancyName": "Master Summoner", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 18709, + 18710 + ], + "maxPoints": 2 + }, + { + "fieldName": "impendingDoom", + "fancyName": "Impending Doom", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 85106, + 85107, + 85108 + ], + "maxPoints": 3 + }, + { + "fieldName": "demonicEmpowerment", + "fancyName": "Demonic Empowerment", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 47193 + ], + "maxPoints": 1 + }, + { + "fieldName": "improvedHealthFunnel", + "fancyName": "Improved Health Funnel", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 18703, + 18704 + ], + "maxPoints": 2 + }, + { + "fieldName": "moltenCore", + "fancyName": "Molten Core", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 47245, + 47246, + 47247 + ], + "maxPoints": 3 + }, + { + "fieldName": "handOfGuldan", + "fancyName": "Hand Of Guldan", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 71521 + ], + "maxPoints": 1 + }, + { + "fieldName": "auraOfForeboding", + "fancyName": "Aura Of Foreboding", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 89604, + 89605 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 1 + } + }, + { + "fieldName": "ancientGrimoire", + "fancyName": "Ancient Grimoire", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 85109, + 85110 + ], + "maxPoints": 2 + }, + { + "fieldName": "inferno", + "fancyName": "Inferno", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 85105 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 1 + } + }, + { + "fieldName": "decimation", + "fancyName": "Decimation", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 63156, + 63158 + ], + "maxPoints": 2 + }, + { + "fieldName": "cremation", + "fancyName": "Cremation", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 85103, + 85104 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "demonicPact", + "fancyName": "Demonic Pact", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 47236 + ], + "maxPoints": 1 + }, + { + "fieldName": "metamorphosis", + "fancyName": "Metamorphosis", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 59672 + ], + "maxPoints": 1 + } + ] + }, + { + "name": "Destruction", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/865.jpg", + "talents": [ + { + "fieldName": "bane", + "fancyName": "Bane", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 17788, + 80240, + 17789, + 17790 + ], + "maxPoints": 3 + }, + { + "fieldName": "shadowAndFlame", + "fancyName": "Shadow And Flame", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 17793, + 17796, + 17801 + ], + "maxPoints": 3 + }, + { + "fieldName": "improvedImmolate", + "fancyName": "Improved Immolate", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 17815, + 17833, + 17834 + ], + "maxPoints": 2 + }, + { + "fieldName": "aftermath", + "fancyName": "Aftermath", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 85113, + 85114 + ], + "maxPoints": 2 + }, + { + "fieldName": "emberstorm", + "fancyName": "Emberstorm", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 17954, + 17955 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedSearingPain", + "fancyName": "Improved Searing Pain", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 17927, + 17929 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedSoulFire", + "fancyName": "Improved Soul Fire", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 18119, + 18120 + ], + "maxPoints": 2 + }, + { + "fieldName": "backdraft", + "fancyName": "Backdraft", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 47258, + 47259, + 47260 + ], + "maxPoints": 3 + }, + { + "fieldName": "shadowburn", + "fancyName": "Shadowburn", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 17877 + ], + "maxPoints": 1 + }, + { + "fieldName": "burningEmbers", + "fancyName": "Burning Embers", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 91986, + 85112 + ], + "maxPoints": 2 + }, + { + "fieldName": "soulLeech", + "fancyName": "Soul Leech", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 30293, + 30295, + 54118 + ], + "maxPoints": 2 + }, + { + "fieldName": "backlash", + "fancyName": "Backlash", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 34935, + 34939, + 34938 + ], + "maxPoints": 3 + }, + { + "fieldName": "netherWard", + "fancyName": "Nether Ward", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 91713 + ], + "maxPoints": 1 + }, + { + "fieldName": "fireAndBrimstone", + "fancyName": "Fire And Brimstone", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 47266, + 47267, + 47268, + 47269, + 47270 + ], + "maxPoints": 3 + }, + { + "fieldName": "shadowfury", + "fancyName": "Shadowfury", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 30283 + ], + "maxPoints": 1 + }, + { + "fieldName": "netherProtection", + "fancyName": "Nether Protection", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 30299, + 30301 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 3 + } + }, + { + "fieldName": "empoweredImp", + "fancyName": "Empowered Imp", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 47220, + 47221 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 0 + } + }, + { + "fieldName": "baneOfHavoc", + "fancyName": "Bane Of Havoc", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 80240 + ], + "maxPoints": 1 + }, + { + "fieldName": "chaosBolt", + "fancyName": "Chaos Bolt", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 50796 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] + } ] \ No newline at end of file diff --git a/ui/core/talents/trees/warrior.json b/ui/core/talents/trees/warrior.json index 841ca7962b..1d163720a3 100644 --- a/ui/core/talents/trees/warrior.json +++ b/ui/core/talents/trees/warrior.json @@ -1,1130 +1,845 @@ [ { - "name": "Arms", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/161.jpg", - "talents": [ - { - "fieldName": "improvedHeroicStrike", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 12282, - 12663, - 12664 - ], - "maxPoints": 3 - }, - { - "fieldName": "deflection", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 16462, - 16463, - 16464, - 16465, - 16466 - ], - "maxPoints": 5 - }, - { - "fieldName": "improvedRend", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 12286, - 12658 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedCharge", - "location": { - "rowIdx": 1, - "colIdx": 0 - }, - "spellIds": [ - 12285, - 12697 - ], - "maxPoints": 2 - }, - { - "fieldName": "ironWill", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 12300, - 12959, - 12960 - ], - "maxPoints": 3 - }, - { - "fieldName": "tacticalMastery", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 12295, - 12676, - 12677 - ], - "maxPoints": 3 - }, - { - "fieldName": "improvedOverpower", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 12290, - 12963 - ], - "maxPoints": 2 - }, - { - "fieldName": "angerManagement", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 12296 - ], - "maxPoints": 1 - }, - { - "fieldName": "impale", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 16493, - 16494 - ], - "maxPoints": 2 - }, - { - "fieldName": "deepWounds", - "location": { - "rowIdx": 2, - "colIdx": 3 - }, - "spellIds": [ - 12834, - 12849, - 12867 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 2, - "colIdx": 2 - } - }, - { - "fieldName": "twoHandedWeaponSpecialization", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 12163, - 12711, - 12712 - ], - "maxPoints": 3 - }, - { - "fieldName": "tasteForBlood", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 56636, - 56637, - 56638 - ], - "maxPoints": 3 - }, - { - "fieldName": "poleaxeSpecialization", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 12700, - 12781, - 12783, - 12784, - 12785 - ], - "maxPoints": 5 - }, - { - "fieldName": "sweepingStrikes", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 12328 - ], - "maxPoints": 1 - }, - { - "fieldName": "maceSpecialization", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 12284, - 12701, - 12702, - 12703, - 12704 - ], - "maxPoints": 5 - }, - { - "fieldName": "swordSpecialization", - "location": { - "rowIdx": 4, - "colIdx": 3 - }, - "spellIds": [ - 12281, - 12812, - 12813, - 12814, - 12815 - ], - "maxPoints": 5 - }, - { - "fieldName": "weaponMastery", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 20504, - 20505 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedHamstring", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 12289, - 12668, - 23695 - ], - "maxPoints": 3 - }, - { - "fieldName": "trauma", - "location": { - "rowIdx": 5, - "colIdx": 3 - }, - "spellIds": [ - 46854, - 46855 - ], - "maxPoints": 2 - }, - { - "fieldName": "secondWind", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 29834, - 29838 - ], - "maxPoints": 2 - }, - { - "fieldName": "mortalStrike", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 12294 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "strengthOfArms", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 46865, - 46866 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedSlam", - "location": { - "rowIdx": 6, - "colIdx": 3 - }, - "spellIds": [ - 12862, - 12330 - ], - "maxPoints": 2 - }, - { - "fieldName": "juggernaut", - "location": { - "rowIdx": 7, - "colIdx": 0 - }, - "spellIds": [ - 64976 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedMortalStrike", - "location": { - "rowIdx": 7, - "colIdx": 1 - }, - "spellIds": [ - 35446, - 35448, - 35449 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "unrelentingAssault", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 46859, - 46860 - ], - "maxPoints": 2 - }, - { - "fieldName": "suddenDeath", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 29723, - 29724, - 29725 - ], - "maxPoints": 3 - }, - { - "fieldName": "endlessRage", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 29623 - ], - "maxPoints": 1 - }, - { - "fieldName": "bloodFrenzy", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 29836, - 29859 - ], - "maxPoints": 2 - }, - { - "fieldName": "wreckingCrew", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 46867, - 56611, - 56612, - 56613, - 56614 - ], - "maxPoints": 5 - }, - { - "fieldName": "bladestorm", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 46924 - ], - "maxPoints": 1 - } - ] + "name": "Arms", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/746.jpg", + "talents": [ + { + "fieldName": "warAcademy", + "fancyName": "War Academy", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 84570, + 84571, + 84572 + ], + "maxPoints": 3 + }, + { + "fieldName": "fieldDressing", + "fancyName": "Field Dressing", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 84579, + 84580 + ], + "maxPoints": 2 + }, + { + "fieldName": "blitz", + "fancyName": "Blitz", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 80976, + 80977 + ], + "maxPoints": 2 + }, + { + "fieldName": "tacticalMastery", + "fancyName": "Tactical Mastery", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 12295, + 12676 + ], + "maxPoints": 2 + }, + { + "fieldName": "secondWind", + "fancyName": "Second Wind", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 29834, + 29838 + ], + "maxPoints": 2 + }, + { + "fieldName": "deepWounds", + "fancyName": "Deep Wounds", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 12834, + 12849, + 12867 + ], + "maxPoints": 3 + }, + { + "fieldName": "drumsOfWar", + "fancyName": "Drums Of War", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 12290, + 12963 + ], + "maxPoints": 2 + }, + { + "fieldName": "tasteForBlood", + "fancyName": "Taste For Blood", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 56636, + 56637, + 56638 + ], + "maxPoints": 3 + }, + { + "fieldName": "sweepingStrikes", + "fancyName": "Sweeping Strikes", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 12328 + ], + "maxPoints": 1 + }, + { + "fieldName": "impale", + "fancyName": "Impale", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 16493, + 16494 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 1, + "colIdx": 2 + } + }, + { + "fieldName": "improvedHamstring", + "fancyName": "Improved Hamstring", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 12289, + 12668 + ], + "maxPoints": 2 + }, + { + "fieldName": "improvedSlam", + "fancyName": "Improved Slam", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 86655, + 12330 + ], + "maxPoints": 2 + }, + { + "fieldName": "deadlyCalm", + "fancyName": "Deadly Calm", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 85730 + ], + "maxPoints": 1 + }, + { + "fieldName": "bloodFrenzy", + "fancyName": "Blood Frenzy", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 29836, + 29859 + ], + "maxPoints": 2 + }, + { + "fieldName": "lambsToTheSlaughter", + "fancyName": "Lambs To The Slaughter", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 84583, + 84588, + 84587 + ], + "maxPoints": 3 + }, + { + "fieldName": "juggernaut", + "fancyName": "Juggernaut", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 64976 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + }, + { + "fieldName": "suddenDeath", + "fancyName": "Sudden Death", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 29723, + 29725 + ], + "maxPoints": 2 + }, + { + "fieldName": "wreckingCrew", + "fancyName": "Wrecking Crew", + "location": { + "rowIdx": 5, + "colIdx": 0 + }, + "spellIds": [ + 46867, + 56611, + 56612 + ], + "maxPoints": 2 + }, + { + "fieldName": "throwdown", + "fancyName": "Throwdown", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 85388 + ], + "maxPoints": 1 + }, + { + "fieldName": "bladestorm", + "fancyName": "Bladestorm", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 46924 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 4, + "colIdx": 1 + } + } + ] }, { - "name": "Fury", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/164.jpg", - "talents": [ - { - "fieldName": "armoredToTheTeeth", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 61216, - 61221, - 61222 - ], - "maxPoints": 3 - }, - { - "fieldName": "boomingVoice", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 12321, - 12835 - ], - "maxPoints": 2 - }, - { - "fieldName": "cruelty", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 12320, - 12852, - 12853, - 12855, - 12856 - ], - "maxPoints": 5 - }, - { - "fieldName": "improvedDemoralizingShout", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 12324, - 12876, - 12877, - 12878, - 12879 - ], - "maxPoints": 5 - }, - { - "fieldName": "unbridledWrath", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 12322, - 12999, - 13000, - 13001, - 13002 - ], - "maxPoints": 5 - }, - { - "fieldName": "improvedCleave", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 12329, - 12950, - 20496 - ], - "maxPoints": 3 - }, - { - "fieldName": "piercingHowl", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 12323 - ], - "maxPoints": 1 - }, - { - "fieldName": "bloodCraze", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 16487, - 16489, - 16492 - ], - "maxPoints": 3 - }, - { - "fieldName": "commandingPresence", - "location": { - "rowIdx": 2, - "colIdx": 3 - }, - "spellIds": [ - 12318, - 12857, - 12858, - 12860, - 12861 - ], - "maxPoints": 5 - }, - { - "fieldName": "dualWieldSpecialization", - "location": { - "rowIdx": 3, - "colIdx": 0 - }, - "spellIds": [ - 23584, - 23585, - 23586, - 23587, - 23588 - ], - "maxPoints": 5 - }, - { - "fieldName": "improvedExecute", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 20502, - 20503 - ], - "maxPoints": 2 - }, - { - "fieldName": "enrage", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 12317, - 13045, - 13046, - 13047, - 13048 - ], - "maxPoints": 5 - }, - { - "fieldName": "precision", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 29590, - 29591, - 29592 - ], - "maxPoints": 3 - }, - { - "fieldName": "deathWish", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 12292 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedIntercept", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 29888, - 29889 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedBerserkerRage", - "location": { - "rowIdx": 5, - "colIdx": 0 - }, - "spellIds": [ - 20500, - 20501 - ], - "maxPoints": 2 - }, - { - "fieldName": "flurry", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 12319, - 12971, - 12972, - 12973, - 12974 - ], - "maxPoints": 5 - }, - { - "fieldName": "intensifyRage", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 46908, - 46909, - 56924 - ], - "maxPoints": 3 - }, - { - "fieldName": "bloodthirst", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 23881 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "improvedWhirlwind", - "location": { - "rowIdx": 6, - "colIdx": 3 - }, - "spellIds": [ - 29721, - 29776 - ], - "maxPoints": 2 - }, - { - "fieldName": "furiousAttacks", - "location": { - "rowIdx": 7, - "colIdx": 0 - }, - "spellIds": [ - 46910, - 46911 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedBerserkerStance", - "location": { - "rowIdx": 7, - "colIdx": 3 - }, - "spellIds": [ - 29759, - 29760, - 29761, - 29762, - 29763 - ], - "maxPoints": 5 - }, - { - "fieldName": "heroicFury", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 60970 - ], - "maxPoints": 1 - }, - { - "fieldName": "rampage", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 29801 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "bloodsurge", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 46913, - 46914, - 46915 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 6, - "colIdx": 1 - } - }, - { - "fieldName": "unendingFury", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 56927, - 56929, - 56930, - 56931, - 56932 - ], - "maxPoints": 5 - }, - { - "fieldName": "titansGrip", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 46917 - ], - "maxPoints": 1 - } - ] + "name": "Fury", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/815.jpg", + "talents": [ + { + "fieldName": "bloodCraze", + "fancyName": "Blood Craze", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 16487, + 16489, + 16492 + ], + "maxPoints": 3 + }, + { + "fieldName": "battleTrance", + "fancyName": "Battle Trance", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 12322, + 85741, + 85742 + ], + "maxPoints": 3 + }, + { + "fieldName": "cruelty", + "fancyName": "Cruelty", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 12320, + 12852 + ], + "maxPoints": 2 + }, + { + "fieldName": "executioner", + "fancyName": "Executioner", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 20502, + 20503 + ], + "maxPoints": 2 + }, + { + "fieldName": "boomingVoice", + "fancyName": "Booming Voice", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 12321, + 12835 + ], + "maxPoints": 2 + }, + { + "fieldName": "rudeInterruption", + "fancyName": "Rude Interruption", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 61216, + 61221 + ], + "maxPoints": 2 + }, + { + "fieldName": "piercingHowl", + "fancyName": "Piercing Howl", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 12323 + ], + "maxPoints": 1 + }, + { + "fieldName": "flurry", + "fancyName": "Flurry", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 12319, + 12971, + 12972 + ], + "maxPoints": 3 + }, + { + "fieldName": "deathWish", + "fancyName": "Death Wish", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 12292 + ], + "maxPoints": 1 + }, + { + "fieldName": "enrage", + "fancyName": "Enrage", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 12317, + 13045, + 13046 + ], + "maxPoints": 3 + }, + { + "fieldName": "dieByTheSword", + "fancyName": "Die By The Sword", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 81913, + 81914 + ], + "maxPoints": 2 + }, + { + "fieldName": "ragingBlow", + "fancyName": "Raging Blow", + "location": { + "rowIdx": 3, + "colIdx": 1 + }, + "spellIds": [ + 85288 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "rampage", + "fancyName": "Rampage", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 29801 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 1 + } + }, + { + "fieldName": "heroicFury", + "fancyName": "Heroic Fury", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 60970 + ], + "maxPoints": 1 + }, + { + "fieldName": "furiousAttacks", + "fancyName": "Furious Attacks", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 46910 + ], + "maxPoints": 1 + }, + { + "fieldName": "meatCleaver", + "fancyName": "Meat Cleaver", + "location": { + "rowIdx": 4, + "colIdx": 2 + }, + "spellIds": [ + 12329, + 12950 + ], + "maxPoints": 2 + }, + { + "fieldName": "intensifyRage", + "fancyName": "Intensify Rage", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 46908, + 46909 + ], + "maxPoints": 2 + }, + { + "fieldName": "bloodsurge", + "fancyName": "Bloodsurge", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 46913, + 46914, + 46915 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 1 + } + }, + { + "fieldName": "skirmisher", + "fancyName": "Skirmisher", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 29888, + 29889 + ], + "maxPoints": 2 + }, + { + "fieldName": "titansGrip", + "fancyName": "Titans Grip", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 46917 + ], + "maxPoints": 1 + }, + { + "fieldName": "singleMindedFury", + "fancyName": "Single Minded Fury", + "location": { + "rowIdx": 6, + "colIdx": 2 + }, + "spellIds": [ + 81099 + ], + "maxPoints": 1 + } + ] }, { - "name": "Protection", - "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/wrath/163.jpg", - "talents": [ - { - "fieldName": "improvedBloodrage", - "location": { - "rowIdx": 0, - "colIdx": 0 - }, - "spellIds": [ - 12301, - 12818 - ], - "maxPoints": 2 - }, - { - "fieldName": "shieldSpecialization", - "location": { - "rowIdx": 0, - "colIdx": 1 - }, - "spellIds": [ - 12298, - 12724, - 12725, - 12726, - 12727 - ], - "maxPoints": 5 - }, - { - "fieldName": "improvedThunderClap", - "location": { - "rowIdx": 0, - "colIdx": 2 - }, - "spellIds": [ - 12287, - 12665, - 12666 - ], - "maxPoints": 3 - }, - { - "fieldName": "incite", - "location": { - "rowIdx": 1, - "colIdx": 1 - }, - "spellIds": [ - 50685, - 50686, - 50687 - ], - "maxPoints": 3 - }, - { - "fieldName": "anticipation", - "location": { - "rowIdx": 1, - "colIdx": 2 - }, - "spellIds": [ - 55129, - 12750, - 12751, - 12752, - 12753 - ], - "maxPoints": 5 - }, - { - "fieldName": "lastStand", - "location": { - "rowIdx": 2, - "colIdx": 0 - }, - "spellIds": [ - 12975 - ], - "maxPoints": 1 - }, - { - "fieldName": "improvedRevenge", - "location": { - "rowIdx": 2, - "colIdx": 1 - }, - "spellIds": [ - 12797, - 12799 - ], - "maxPoints": 2 - }, - { - "fieldName": "shieldMastery", - "location": { - "rowIdx": 2, - "colIdx": 2 - }, - "spellIds": [ - 29598, - 29599 - ], - "maxPoints": 2 - }, - { - "fieldName": "toughness", - "location": { - "rowIdx": 2, - "colIdx": 3 - }, - "spellIds": [ - 12299, - 12761, - 12762, - 12763, - 12764 - ], - "maxPoints": 5 - }, - { - "fieldName": "improvedSpellReflection", - "location": { - "rowIdx": 3, - "colIdx": 0 - }, - "spellIds": [ - 59088, - 59089 - ], - "maxPoints": 2 - }, - { - "fieldName": "improvedDisarm", - "location": { - "rowIdx": 3, - "colIdx": 1 - }, - "spellIds": [ - 12313, - 12804 - ], - "maxPoints": 2 - }, - { - "fieldName": "puncture", - "location": { - "rowIdx": 3, - "colIdx": 2 - }, - "spellIds": [ - 12308, - 12810, - 12811 - ], - "maxPoints": 3 - }, - { - "fieldName": "improvedDisciplines", - "location": { - "rowIdx": 4, - "colIdx": 0 - }, - "spellIds": [ - 12312, - 12803 - ], - "maxPoints": 2 - }, - { - "fieldName": "concussionBlow", - "location": { - "rowIdx": 4, - "colIdx": 1 - }, - "spellIds": [ - 12809 - ], - "maxPoints": 1 - }, - { - "fieldName": "gagOrder", - "location": { - "rowIdx": 4, - "colIdx": 2 - }, - "spellIds": [ - 12311, - 12958 - ], - "maxPoints": 2 - }, - { - "fieldName": "oneHandedWeaponSpecialization", - "location": { - "rowIdx": 5, - "colIdx": 2 - }, - "spellIds": [ - 16538, - 16539, - 16540, - 16541, - 16542 - ], - "maxPoints": 5 - }, - { - "fieldName": "improvedDefensiveStance", - "location": { - "rowIdx": 6, - "colIdx": 0 - }, - "spellIds": [ - 29593, - 29594 - ], - "maxPoints": 2 - }, - { - "fieldName": "vigilance", - "location": { - "rowIdx": 6, - "colIdx": 1 - }, - "spellIds": [ - 50720 - ], - "maxPoints": 1, - "prereqLocation": { - "rowIdx": 4, - "colIdx": 1 - } - }, - { - "fieldName": "focusedRage", - "location": { - "rowIdx": 6, - "colIdx": 2 - }, - "spellIds": [ - 29787, - 29790, - 29792 - ], - "maxPoints": 3 - }, - { - "fieldName": "vitality", - "location": { - "rowIdx": 7, - "colIdx": 1 - }, - "spellIds": [ - 29140, - 29143, - 29144 - ], - "maxPoints": 3 - }, - { - "fieldName": "safeguard", - "location": { - "rowIdx": 7, - "colIdx": 2 - }, - "spellIds": [ - 46945, - 46949 - ], - "maxPoints": 2 - }, - { - "fieldName": "warbringer", - "location": { - "rowIdx": 8, - "colIdx": 0 - }, - "spellIds": [ - 57499 - ], - "maxPoints": 1 - }, - { - "fieldName": "devastate", - "location": { - "rowIdx": 8, - "colIdx": 1 - }, - "spellIds": [ - 20243 - ], - "maxPoints": 1 - }, - { - "fieldName": "criticalBlock", - "location": { - "rowIdx": 8, - "colIdx": 2 - }, - "spellIds": [ - 47294, - 47295, - 47296 - ], - "maxPoints": 3 - }, - { - "fieldName": "swordAndBoard", - "location": { - "rowIdx": 9, - "colIdx": 1 - }, - "spellIds": [ - 46951, - 46952, - 46953 - ], - "maxPoints": 3, - "prereqLocation": { - "rowIdx": 8, - "colIdx": 1 - } - }, - { - "fieldName": "damageShield", - "location": { - "rowIdx": 9, - "colIdx": 2 - }, - "spellIds": [ - 58872, - 58874 - ], - "maxPoints": 2 - }, - { - "fieldName": "shockwave", - "location": { - "rowIdx": 10, - "colIdx": 1 - }, - "spellIds": [ - 46968 - ], - "maxPoints": 1 - } - ] + "name": "Protection", + "backgroundUrl": "https://wow.zamimg.com/images/wow/talents/backgrounds/cata/845.jpg", + "talents": [ + { + "fieldName": "incite", + "fancyName": "Incite", + "location": { + "rowIdx": 0, + "colIdx": 0 + }, + "spellIds": [ + 50685, + 50686, + 50687 + ], + "maxPoints": 3 + }, + { + "fieldName": "toughness", + "fancyName": "Toughness", + "location": { + "rowIdx": 0, + "colIdx": 1 + }, + "spellIds": [ + 12299, + 12761, + 12762 + ], + "maxPoints": 3 + }, + { + "fieldName": "bloodAndThunder", + "fancyName": "Blood And Thunder", + "location": { + "rowIdx": 0, + "colIdx": 2 + }, + "spellIds": [ + 84614, + 84615 + ], + "maxPoints": 2 + }, + { + "fieldName": "shieldSpecialization", + "fancyName": "Shield Specialization", + "location": { + "rowIdx": 1, + "colIdx": 0 + }, + "spellIds": [ + 12298, + 12724, + 12725 + ], + "maxPoints": 3 + }, + { + "fieldName": "shieldMastery", + "fancyName": "Shield Mastery", + "location": { + "rowIdx": 1, + "colIdx": 1 + }, + "spellIds": [ + 29598, + 84607, + 84608 + ], + "maxPoints": 3 + }, + { + "fieldName": "holdTheLine", + "fancyName": "Hold The Line", + "location": { + "rowIdx": 1, + "colIdx": 2 + }, + "spellIds": [ + 84604, + 84621 + ], + "maxPoints": 2 + }, + { + "fieldName": "gagOrder", + "fancyName": "Gag Order", + "location": { + "rowIdx": 1, + "colIdx": 3 + }, + "spellIds": [ + 12311, + 12958 + ], + "maxPoints": 2 + }, + { + "fieldName": "lastStand", + "fancyName": "Last Stand", + "location": { + "rowIdx": 2, + "colIdx": 0 + }, + "spellIds": [ + 12975 + ], + "maxPoints": 1 + }, + { + "fieldName": "concussionBlow", + "fancyName": "Concussion Blow", + "location": { + "rowIdx": 2, + "colIdx": 1 + }, + "spellIds": [ + 12809 + ], + "maxPoints": 1 + }, + { + "fieldName": "bastionOfDefense", + "fancyName": "Bastion Of Defense", + "location": { + "rowIdx": 2, + "colIdx": 2 + }, + "spellIds": [ + 29593, + 29594 + ], + "maxPoints": 2 + }, + { + "fieldName": "warbringer", + "fancyName": "Warbringer", + "location": { + "rowIdx": 2, + "colIdx": 3 + }, + "spellIds": [ + 57499 + ], + "maxPoints": 1 + }, + { + "fieldName": "improvedRevenge", + "fancyName": "Improved Revenge", + "location": { + "rowIdx": 3, + "colIdx": 0 + }, + "spellIds": [ + 12797, + 12799 + ], + "maxPoints": 2 + }, + { + "fieldName": "devastate", + "fancyName": "Devastate", + "location": { + "rowIdx": 3, + "colIdx": 2 + }, + "spellIds": [ + 20243 + ], + "maxPoints": 1 + }, + { + "fieldName": "impendingVictory", + "fancyName": "Impending Victory", + "location": { + "rowIdx": 3, + "colIdx": 3 + }, + "spellIds": [ + 80128, + 80129 + ], + "maxPoints": 2, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 2 + } + }, + { + "fieldName": "thunderstruck", + "fancyName": "Thunderstruck", + "location": { + "rowIdx": 4, + "colIdx": 0 + }, + "spellIds": [ + 80979, + 80980 + ], + "maxPoints": 2 + }, + { + "fieldName": "vigilance", + "fancyName": "Vigilance", + "location": { + "rowIdx": 4, + "colIdx": 1 + }, + "spellIds": [ + 50720 + ], + "maxPoints": 1, + "prereqLocation": { + "rowIdx": 2, + "colIdx": 1 + } + }, + { + "fieldName": "heavyRepercussions", + "fancyName": "Heavy Repercussions", + "location": { + "rowIdx": 4, + "colIdx": 3 + }, + "spellIds": [ + 86894, + 86896 + ], + "maxPoints": 2 + }, + { + "fieldName": "safeguard", + "fancyName": "Safeguard", + "location": { + "rowIdx": 5, + "colIdx": 1 + }, + "spellIds": [ + 46945, + 46949 + ], + "maxPoints": 2 + }, + { + "fieldName": "swordAndBoard", + "fancyName": "Sword And Board", + "location": { + "rowIdx": 5, + "colIdx": 2 + }, + "spellIds": [ + 46951, + 46952, + 46953 + ], + "maxPoints": 3, + "prereqLocation": { + "rowIdx": 3, + "colIdx": 2 + } + }, + { + "fieldName": "shockwave", + "fancyName": "Shockwave", + "location": { + "rowIdx": 6, + "colIdx": 1 + }, + "spellIds": [ + 46968 + ], + "maxPoints": 1 + } + ] } -] \ No newline at end of file + ] \ No newline at end of file diff --git a/ui/core/talents/warlock.ts b/ui/core/talents/warlock.ts index ab7c339297..e8ade0dffb 100644 --- a/ui/core/talents/warlock.ts +++ b/ui/core/talents/warlock.ts @@ -1,35 +1,80 @@ -import { WarlockTalents, WarlockMajorGlyph, WarlockMinorGlyph } from '../proto/warlock.js'; - +import { WarlockMajorGlyph, WarlockMinorGlyph,WarlockPrimeGlyph, WarlockTalents } from '../proto/warlock.js'; import { GlyphsConfig } from './glyphs_picker.js'; -import { TalentsConfig, newTalentsConfig } from './talents_picker.js'; - +import { newTalentsConfig,TalentsConfig } from './talents_picker.js'; import WarlockTalentJson from './trees/warlock.json'; export const warlockTalentsConfig: TalentsConfig = newTalentsConfig(WarlockTalentJson); export const warlockGlyphsConfig: GlyphsConfig = { - majorGlyphs: { - [WarlockMajorGlyph.GlyphOfChaosBolt]: { + primeGlyphs: { + [WarlockPrimeGlyph.GlyphOfBaneOfAgony]: { + name: 'Glyph of Bane of Agony', + description: 'Increases the duration of your Bane of Agony by 4 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_curseofsargeras.jpg', + }, + [WarlockPrimeGlyph.GlyphOfChaosBolt]: { name: 'Glyph of Chaos Bolt', description: 'Reduces the cooldown on Chaos Bolt by 2 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warlock_chaosbolt.jpg', }, - [WarlockMajorGlyph.GlyphOfConflagrate]: { + [WarlockPrimeGlyph.GlyphOfConflagrate]: { name: 'Glyph of Conflagrate', - description: 'Your Conflagrate spell no longer consumes your Immolate or Shadowflame spell from the target.', + description: 'Reduces the cooldown of your Conflagrate by 2 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_fireball.jpg', }, - [WarlockMajorGlyph.GlyphOfCorruption]: { + [WarlockPrimeGlyph.GlyphOfCorruption]: { name: 'Glyph of Corruption', description: 'Your Corruption spell has a 4% chance to cause you to enter a Shadow Trance state after damaging the opponent. The Shadow Trance state reduces the casting time of your next Shadow Bolt spell by 100%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_abominationexplosion.jpg', }, - [WarlockMajorGlyph.GlyphOfCurseOfAgony]: { - name: 'Glyph of Curse of Agony', - description: 'Increases the duration of your Curse of Agony by 4 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_curseofsargeras.jpg', + [WarlockPrimeGlyph.GlyphOfFelguard]: { + name: 'Glyph of Felguard', + description: 'Increases the damage done by your Felguard\'s Legion Strike by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_summonfelguard.jpg', + }, + [WarlockPrimeGlyph.GlyphOfHaunt]: { + name: 'Glyph of Haunt', + description: 'The bonus damage granted by your Haunt spell is increased by an additional 3%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warlock_haunt.jpg', + }, + [WarlockPrimeGlyph.GlyphOfImmolate]: { + name: 'Glyph of Immolate', + description: 'Increases the periodic damage of your Immolate by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_immolation.jpg', + }, + [WarlockPrimeGlyph.GlyphOfImp]: { + name: 'Glyph of Imp', + description: 'Increases the damage done by your Imp\'s Firebolt spell by 20%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_summonimp.jpg', + }, + [WarlockPrimeGlyph.GlyphOfIncinerate]: { + name: 'Glyph of Incinerate', + description: 'Increases the damage done by Incinerate by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_burnout.jpg', }, - [WarlockMajorGlyph.GlyphOfDeathCoil]: { + [WarlockPrimeGlyph.GlyphOfLashOfPain]: { + name: 'Glyph of Lash of Pain', + description: 'Increases the damage done by your Succubus\' Lash of Pain by 25%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_curse.jpg', + }, + [WarlockPrimeGlyph.GlyphOfMetamorphosis]: { + name: 'Glyph of Metamorphosis', + description: 'Increases the duration of your Metamorphosis by 6 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_demonform.jpg', + }, + [WarlockPrimeGlyph.GlyphOfShadowburn]: { + name: 'Glyph of Shadowburn', + description: 'If your Shadowburn fails to kill the target at or below 20% health, your Shadowburn\'s cooldown is instantly reset. This effect has a 6 sec cooldown.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_scourgebuild.jpg', + }, + [WarlockPrimeGlyph.GlyphOfUnstableAffliction]: { + name: 'Glyph of Unstable Affliction', + description: 'Decreases the casting time of your Unstable Affliction by 0.2 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_unstableaffliction_3.jpg', + }, + }, + majorGlyphs: { + [WarlockMajorGlyph.GlyphOfDeathCoilWl]: { name: 'Glyph of Death Coil', description: 'Increases the duration of your Death Coil by 0.5 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_deathcoil.jpg', @@ -37,33 +82,18 @@ export const warlockGlyphsConfig: GlyphsConfig = { [WarlockMajorGlyph.GlyphOfDemonicCircle]: { name: 'Glyph of Demonic Circle', description: 'Reduces the cooldown on Demonic Circle by 4 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_demoniccirclesummon.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_demoniccircleteleport.jpg', }, [WarlockMajorGlyph.GlyphOfFear]: { name: 'Glyph of Fear', - description: 'Increases the damage your Fear target can take before the Fear effect is removed by 20%.', + description: 'Your Fear causes the target to tremble in place instead of fleeing in fear, but now causes Fear to have a 5 sec cooldown.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_possession.jpg', }, - [WarlockMajorGlyph.GlyphOfFelguard]: { - name: 'Glyph of Felguard', - description: 'Increases the Felguard\'s total attack power by 20%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_summonfelguard.jpg', - }, [WarlockMajorGlyph.GlyphOfFelhunter]: { name: 'Glyph of Felhunter', description: 'When your Felhunter uses Devour Magic, you will also be healed for that amount.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_summonfelhunter.jpg', }, - [WarlockMajorGlyph.GlyphOfHaunt]: { - name: 'Glyph of Haunt', - description: 'The bonus damage granted by your Haunt spell is increased by an additional 3%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warlock_haunt.jpg', - }, - [WarlockMajorGlyph.GlyphOfHealthFunnel]: { - name: 'Glyph of Health Funnel', - description: 'Reduces the pushback suffered from damaging attacks while channeling your Health Funnel spell by 100%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_lifedrain.jpg', - }, [WarlockMajorGlyph.GlyphOfHealthstone]: { name: 'Glyph of Healthstone', description: 'You receive 30% more healing from using a healthstone.', @@ -74,117 +104,82 @@ export const warlockGlyphsConfig: GlyphsConfig = { description: 'Reduces the cooldown on your Howl of Terror spell by 8 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_deathscream.jpg', }, - [WarlockMajorGlyph.GlyphOfImmolate]: { - name: 'Glyph of Immolate', - description: 'Increases the periodic damage of your Immolate by 10%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_immolation.jpg', - }, - [WarlockMajorGlyph.GlyphOfImp]: { - name: 'Glyph of Imp', - description: 'Increases the damage done by your Imp\'s Firebolt spell by 20%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_summonimp.jpg', - }, - [WarlockMajorGlyph.GlyphOfIncinerate]: { - name: 'Glyph of Incinerate', - description: 'Increases the damage done by Incinerate by 5%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_burnout.jpg', - }, [WarlockMajorGlyph.GlyphOfLifeTap]: { name: 'Glyph of Life Tap', - description: 'When you use Life Tap or Dark Pact, you gain 20% of your Spirit as spell power for 40 sec.', + description: 'Reduces the global cooldown of your Life Tap by 0.5 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_burningspirit.jpg', }, - [WarlockMajorGlyph.GlyphOfMetamorphosis]: { - name: 'Glyph of Metamorphosis', - description: 'Increases the duration of your Metamorphosis by 6 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_demonform.jpg', - }, - [WarlockMajorGlyph.GlyphOfQuickDecay]: { - name: 'Glyph of Quick Decay', - description: 'Your haste now reduces the time between periodic damage ticks of your Corruption spell.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_abominationexplosion.jpg', - }, - [WarlockMajorGlyph.GlyphOfSearingPain]: { - name: 'Glyph of Searing Pain', - description: 'Increases the critical strike bonus of your Searing Pain by 20%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_fire_soulburn.jpg', + [WarlockMajorGlyph.GlyphOfSeduction]: { + name: 'Glyph of Seduction', + description: 'Your Succubus\'s Seduction ability also removes all damage over time effects from the target.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_mindsteal.jpg', }, [WarlockMajorGlyph.GlyphOfShadowBolt]: { name: 'Glyph of Shadow Bolt', - description: 'Reduces the mana cost of your Shadow Bolt by 10%.', + description: 'Reduces the mana cost of your Shadow Bolt by 15%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_shadowbolt.jpg', }, - [WarlockMajorGlyph.GlyphOfShadowburn]: { - name: 'Glyph of Shadowburn', - description: 'Increases the critical strike chance of Shadowburn by 20% when the target is below 35% health.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_scourgebuild.jpg', - }, [WarlockMajorGlyph.GlyphOfShadowflame]: { name: 'Glyph of Shadowflame', - description: 'Your Shadowflame also applies a 70% movement speed slow on its victims.', + description: 'Your Shadowflame also applies a 70% movement speed slow to its victims.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warlock_shadowflame.jpg', }, - [WarlockMajorGlyph.GlyphOfSiphonLife]: { - name: 'Glyph of Siphon Life', - description: 'Increases the healing you receive from your Siphon Life talent by 25%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_requiem.jpg', - }, [WarlockMajorGlyph.GlyphOfSoulLink]: { name: 'Glyph of Soul Link', description: 'Increases the percentage of damage shared via your Soul Link by an additional 5%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_gathershadows.jpg', }, + [WarlockMajorGlyph.GlyphOfSoulSwap]: { + name: 'Glyph of Soul Swap', + description: 'Your Soul Swap leaves your damage-over-time spells behind on the target you Soul Swapped from, but gives Soul Swap a 30 sec cooldown.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warlock_soulswap.jpg', + }, [WarlockMajorGlyph.GlyphOfSoulstone]: { name: 'Glyph of Soulstone', - description: 'Increases the amount of health you gain from resurrecting via a Soulstone by 300%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_soulgem.jpg', - }, - [WarlockMajorGlyph.GlyphOfSuccubus]: { - name: 'Glyph of Succubus', - description: 'Your Succubus\'s Seduction ability also removes all damage over time effects from the target.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_summonsuccubus.jpg', - }, - [WarlockMajorGlyph.GlyphOfUnstableAffliction]: { - name: 'Glyph of Unstable Affliction', - description: 'Decreases the casting time of your Unstable Affliction by 0.2 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_unstableaffliction_3.jpg', + description: 'Increases the amount of health you gain from resurrecting via a Soulstone by an additional 40%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_orb_04.jpg', }, [WarlockMajorGlyph.GlyphOfVoidwalker]: { name: 'Glyph of Voidwalker', - description: 'Increases your Voidwalker\'s total Stamina by 20%.', + description: 'Increases your Voidwalker\'s total health by 20%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_summonvoidwalker.jpg', }, }, minorGlyphs: { - [WarlockMinorGlyph.GlyphOfCurseOfExhausion]: { - name: 'Glyph of Curse of Exhausion', + [WarlockMinorGlyph.GlyphOfCurseOfExhaustion]: { + name: 'Glyph of Curse of Exhaustion', description: 'Increases the range of your Curse of Exhaustion spell by 5 yards.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_grimward.jpg', }, [WarlockMinorGlyph.GlyphOfDrainSoul]: { name: 'Glyph of Drain Soul', - description: 'Your Drain Soul ability occasionally creates an additional soul shard.', + description: 'Your Drain Soul restores 10% of your total mana after you kill a target that yields experience or honor.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_haunting.jpg', }, - [WarlockMinorGlyph.GlyphOfSubjugateDemon]: { - name: 'Glyph of Subjugate Demon', - description: 'Reduces the cast time of your Subjugate Demon spell by 50%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_enslavedemon.jpg', - }, - [WarlockMinorGlyph.GlyphOfKilrogg]: { - name: 'Glyph of Kilrogg', + [WarlockMinorGlyph.GlyphOfEyeOfKilrogg]: { + name: 'Glyph of Eye of Kilrogg', description: 'Increases the movement speed of your Eye of Kilrogg by 50% and allows it to fly in areas where flying mounts are enabled.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_evileye.jpg', }, - [WarlockMinorGlyph.GlyphOfSouls]: { - name: 'Glyph of Souls', + [WarlockMinorGlyph.GlyphOfHealthFunnel]: { + name: 'Glyph of Health Funnel', + description: 'Reduces the pushback suffered from damaging attacks while channeling your Health Funnel spell by 100%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_lifedrain.jpg', + }, + [WarlockMinorGlyph.GlyphOfRitualOfSouls]: { + name: 'Glyph of Ritual of Souls', description: 'Reduces the mana cost of your Ritual of Souls spell by 70%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_shadesofdarkness.jpg', }, + [WarlockMinorGlyph.GlyphOfSubjugateDemon]: { + name: 'Glyph of Subjugate Demon', + description: 'Reduces the cast time of your Subjugate Demon spell by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_enslavedemon.jpg', + }, [WarlockMinorGlyph.GlyphOfUnendingBreath]: { name: 'Glyph of Unending Breath', description: 'Increases the swim speed of targets affected by your Unending Breath spell by 20%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_demonbreath.jpg', }, }, -}; +}; \ No newline at end of file diff --git a/ui/core/talents/warrior.ts b/ui/core/talents/warrior.ts index f923524bc2..c39d22936f 100644 --- a/ui/core/talents/warrior.ts +++ b/ui/core/talents/warrior.ts @@ -1,107 +1,112 @@ -import { WarriorTalents, WarriorMajorGlyph, WarriorMinorGlyph } from '../proto/warrior.js'; - +import { WarriorMajorGlyph, WarriorMinorGlyph,WarriorPrimeGlyph, WarriorTalents } from '../proto/warrior.js'; import { GlyphsConfig } from './glyphs_picker.js'; -import { TalentsConfig, newTalentsConfig } from './talents_picker.js'; - +import { newTalentsConfig,TalentsConfig } from './talents_picker.js'; import WarriorTalentJson from './trees/warrior.json'; export const warriorTalentsConfig: TalentsConfig = newTalentsConfig(WarriorTalentJson); export const warriorGlyphsConfig: GlyphsConfig = { - majorGlyphs: { - [WarriorMajorGlyph.GlyphOfBarbaricInsults]: { - name: 'Glyph of Barbaric Insults', - description: 'Your Mocking Blow ability generates 100% additional threat.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_punishingblow.jpg', - }, - [WarriorMajorGlyph.GlyphOfBladestorm]: { + primeGlyphs: { + [WarriorPrimeGlyph.GlyphOfBladestorm]: { name: 'Glyph of Bladestorm', description: 'Reduces the cooldown on Bladestorm by 15 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_bladestorm.jpg', }, - [WarriorMajorGlyph.GlyphOfBlocking]: { - name: 'Glyph of Blocking', - description: 'Increases your block value by 10% for 10 sec after using your Shield Slam ability.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_shield_05.jpg', - }, - [WarriorMajorGlyph.GlyphOfBloodthirst]: { + [WarriorPrimeGlyph.GlyphOfBloodthirst]: { name: 'Glyph of Bloodthirst', - description: 'Increases the healing you receive from your Bloodthirst ability by 100%.', + description: 'Increases the damage of Bloodthirst by 10%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_bloodlust.jpg', }, + [WarriorPrimeGlyph.GlyphOfDevastate]: { + name: 'Glyph of Devastate', + description: 'Increases the critical strike chance of Devastate by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_sword_11.jpg', + }, + [WarriorPrimeGlyph.GlyphOfMortalStrike]: { + name: 'Glyph of Mortal Strike', + description: 'Increases the damage of Mortal Strike by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_savageblow.jpg', + }, + [WarriorPrimeGlyph.GlyphOfOverpower]: { + name: 'Glyph of Overpower', + description: 'Increases the damage of Overpower by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_meleedamage.jpg', + }, + [WarriorPrimeGlyph.GlyphOfRagingBlow]: { + name: 'Glyph of Raging Blow', + description: 'Increases the critical strike chance of Raging Blow by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_hunter_swiftstrike.jpg', + }, + [WarriorPrimeGlyph.GlyphOfRevenge]: { + name: 'Glyph of Revenge', + description: 'Increases the damage of Revenge by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_revenge.jpg', + }, + [WarriorPrimeGlyph.GlyphOfShieldSlam]: { + name: 'Glyph of Shield Slam', + description: 'Increases the damage of Shield Slam by 10%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_shield_05.jpg', + }, + [WarriorPrimeGlyph.GlyphOfSlam]: { + name: 'Glyph of Slam', + description: 'Increases the critical strike chance of Slam by 5%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_decisivestrike.jpg', + }, + }, + majorGlyphs: { [WarriorMajorGlyph.GlyphOfCleaving]: { name: 'Glyph of Cleaving', description: 'Increases the number of targets your Cleave hits by 1.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_cleave.jpg', }, - [WarriorMajorGlyph.GlyphOfDevastate]: { - name: 'Glyph of Devastate', - description: 'Your Devastate ability now applies two stacks of Sunder Armor.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_sword_11.jpg', + [WarriorMajorGlyph.GlyphOfColossusSmash]: { + name: 'Glyph of Colossus Smash', + description: 'Your Colossus Smash also applies the Sunder Armor effect to your target.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_colossussmash.jpg', }, - [WarriorMajorGlyph.GlyphOfEnragedRegeneration]: { - name: 'Glyph of Enraged Regeneration', - description: 'Your Enraged Regeneration ability heals for an additional 10% of your health over its duration.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_focusedrage.jpg', + [WarriorMajorGlyph.GlyphOfDeathWish]: { + name: 'Glyph of Death Wish', + description: 'Death Wish no longer increases damage taken.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_deathpact.jpg', }, - [WarriorMajorGlyph.GlyphOfExecution]: { - name: 'Glyph of Execution', - description: 'Your Execute ability deals damage as if you had 10 additional rage.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_sword_48.jpg', + [WarriorMajorGlyph.GlyphOfHeroicThrow]: { + name: 'Glyph of Heroic Throw', + description: 'Your Heroic Throw applies a stack of Sunder Armor.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_axe_66.jpg', }, - [WarriorMajorGlyph.GlyphOfHamstring]: { - name: 'Glyph of Hamstring', - description: 'Gives your Hamstring ability a 10% chance to immobilize the target for 5 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_shockwave.jpg', - }, - [WarriorMajorGlyph.GlyphOfHeroicStrike]: { - name: 'Glyph of Heroic Strike', - description: 'You gain 10 rage when you critically strike with your Heroic Strike ability.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_ambush.jpg', + [WarriorMajorGlyph.GlyphOfIntercept]: { + name: 'Glyph of Intercept', + description: 'Increases the duration of your Intercept stun by 1 sec.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_sprint.jpg', }, [WarriorMajorGlyph.GlyphOfIntervene]: { name: 'Glyph of Intervene', - description: 'Increases the number attacks you intercept for your Intervene target by 1.', + description: 'Increases the number of attacks you intercept for your Intervene target by 1.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_victoryrush.jpg', }, - [WarriorMajorGlyph.GlyphOfLastStand]: { - name: 'Glyph of Last Stand', - description: 'Reduces the cooldown of your Last Stand ability by 1 min.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_ashestoashes.jpg', + [WarriorMajorGlyph.GlyphOfLongCharge]: { + name: 'Glyph of Long Charge', + description: 'Increases the range of your Charge ability by 5 yards.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_charge.jpg', }, - [WarriorMajorGlyph.GlyphOfMortalStrike]: { - name: 'Glyph of Mortal Strike', - description: 'Increases the damage of your Mortal Strike ability by 10%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_savageblow.jpg', - }, - [WarriorMajorGlyph.GlyphOfOverpower]: { - name: 'Glyph of Overpower', - description: 'Adds a 100% chance to enable your Overpower when your attacks are parried.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_meleedamage.jpg', + [WarriorMajorGlyph.GlyphOfPiercingHowl]: { + name: 'Glyph of Piercing Howl', + description: 'Increases the radius of Piercing Howl by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_deathscream.jpg', }, [WarriorMajorGlyph.GlyphOfRapidCharge]: { name: 'Glyph of Rapid Charge', - description: 'Reduces the cooldown of your Charge ability by 7%.', + description: 'Reduces the cooldown of your Charge ability by 1 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_charge.jpg', }, - [WarriorMajorGlyph.GlyphOfRending]: { - name: 'Glyph of Rending', - description: 'Increases the duration of your Rend ability by 6 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_gouge.jpg', - }, [WarriorMajorGlyph.GlyphOfResonatingPower]: { name: 'Glyph of Resonating Power', description: 'Reduces the rage cost of your Thunder Clap ability by 5.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_thunderclap.jpg', }, - [WarriorMajorGlyph.GlyphOfRevenge]: { - name: 'Glyph of Revenge', - description: 'After using Revenge, your next Heroic Strike costs no rage.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_revenge.jpg', - }, [WarriorMajorGlyph.GlyphOfShieldWall]: { name: 'Glyph of Shield Wall', - description: 'Reduces the cooldown on Shield Wall by 2 min, but Shield Wall now only reduces damage taken by 40%.', + description: 'Shield Wall now reduces damage taken by an additional 20%, but its cooldown is increased by 2 min.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_shieldwall.jpg', }, [WarriorMajorGlyph.GlyphOfShockwave]: { @@ -111,12 +116,12 @@ export const warriorGlyphsConfig: GlyphsConfig = { }, [WarriorMajorGlyph.GlyphOfSpellReflection]: { name: 'Glyph of Spell Reflection', - description: 'Reduces the cooldown on Spell Reflection by 1 sec.', + description: 'Reduces the cooldown on Spell Reflection by 5 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_shieldreflection.jpg', }, [WarriorMajorGlyph.GlyphOfSunderArmor]: { name: 'Glyph of Sunder Armor', - description: 'Your Sunder Armor ability affects a second nearby target.', + description: 'When you use Sunder Armor or Devastate, a second nearby target also receives Sunder Armor.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_sunder.jpg', }, [WarriorMajorGlyph.GlyphOfSweepingStrikes]: { @@ -124,67 +129,62 @@ export const warriorGlyphsConfig: GlyphsConfig = { description: 'Reduces the rage cost of your Sweeping Strikes ability by 100%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_rogue_slicedice.jpg', }, - [WarriorMajorGlyph.GlyphOfTaunt]: { - name: 'Glyph of Taunt', - description: 'Increases the chance for your Taunt ability to succeed by 8%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_reincarnation.jpg', + [WarriorMajorGlyph.GlyphOfThunderClap]: { + name: 'Glyph of Thunder Clap', + description: 'Increases the radius of your Thunder Clap ability by 2 yards.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_thunderclap.jpg', }, [WarriorMajorGlyph.GlyphOfVictoryRush]: { name: 'Glyph of Victory Rush', - description: 'Your Victory Rush ability has a 30% increased critical strike chance.', + description: 'Increases the total healing provided by your Victory Rush by 50%.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_devastate.jpg', }, - [WarriorMajorGlyph.GlyphOfVigilance]: { - name: 'Glyph of Vigilance', - description: 'Your Vigilance ability transfers an additional 5% of your target\'s threat to you.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_vigilance.jpg', - }, - [WarriorMajorGlyph.GlyphOfWhirlwind]: { - name: 'Glyph of Whirlwind', - description: 'Reduces the cooldown of your Whirlwind by 2 sec.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_whirlwind.jpg', - }, }, minorGlyphs: { [WarriorMinorGlyph.GlyphOfBattle]: { name: 'Glyph of Battle', - description: 'Increases the duration of your Battle Shout ability by 2 min.', + description: 'Increases the duration by 2 min and area of effect by 50% of your Battle Shout.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_battleshout.jpg', }, - [WarriorMinorGlyph.GlyphOfBloodrage]: { - name: 'Glyph of Bloodrage', - description: 'Reduces the health cost of your Bloodrage ability by 100%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_racial_bloodrage.jpg', + [WarriorMinorGlyph.GlyphOfBerserkerRage]: { + name: 'Glyph of Berserker Rage', + description: 'Berserker Rage generates 5 Rage when used.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_ancestralguardian.jpg', }, - [WarriorMinorGlyph.GlyphOfCharge]: { - name: 'Glyph of Charge', - description: 'Increases the range of your Charge ability by 5 yards.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_charge.jpg', + [WarriorMinorGlyph.GlyphOfBloodyHealing]: { + name: 'Glyph of Bloody Healing', + description: 'Increases the healing you receive from Bloodthirst by 40%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_bloodlust.jpg', }, [WarriorMinorGlyph.GlyphOfCommand]: { name: 'Glyph of Command', - description: 'Increases the duration of your Commanding Shout ability by 2 min.', + description: 'Increases the duration by 2 min and area of effect by 50% of your Commanding Shout.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_rallyingcry.jpg', }, + [WarriorMinorGlyph.GlyphOfDemoralizingShout]: { + name: 'Glyph of Demoralizing Shout', + description: 'Increases the duration by 15 sec and area of effect by 50% of your Demoralizing Shout.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_warcry.jpg', + }, [WarriorMinorGlyph.GlyphOfEnduringVictory]: { name: 'Glyph of Enduring Victory', description: 'Increases the window of opportunity in which you can use Victory Rush by 5 sec.', iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_devastate.jpg', }, - [WarriorMinorGlyph.GlyphOfMockingBlow]: { - name: 'Glyph of Mocking Blow', - description: 'Increases the damage of your Mocking Blow ability by 25%.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_punishingblow.jpg', + [WarriorMinorGlyph.GlyphOfFuriousSundering]: { + name: 'Glyph of Furious Sundering', + description: 'Reduces the cost of Sunder Armor by 50%.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_sunder.jpg', }, - [WarriorMinorGlyph.GlyphOfThunderClap]: { - name: 'Glyph of Thunder Clap', - description: 'Increases the radius of your Thunder Clap ability by 2 yards.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/spell_nature_thunderclap.jpg', + [WarriorMinorGlyph.GlyphOfIntimidatingShout]: { + name: 'Glyph of Intimidating Shout', + description: 'All targets of your Intimidating Shout now tremble in place instead of fleeing in fear.', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_golemthunderclap.jpg', }, [WarriorMinorGlyph.GlyphOfShatteringThrow]: { name: 'Glyph of Shattering Throw', description: 'Your Shattering Throw is now instant and can be used in any stance, but it no longer removes invulnerabilities and cannot be used on players or player-controlled targets.', - iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_shatteringthrow.jpg', + iconUrl: 'https://wow.zamimg.com/images/wow/icons/large/inv_misc_questionmark.jpg', }, }, -}; +}; \ No newline at end of file From 378db16652119218c6e0e8f59427fcde238ed114 Mon Sep 17 00:00:00 2001 From: Kevin Ferm Date: Tue, 12 Mar 2024 18:36:09 +0100 Subject: [PATCH 2/2] It builds --- ...ti_magic_shell.go => _anti_magic_shell.go} | 0 ...my_of_the_dead.go => _army_of_the_dead.go} | 0 .../{blood_boil.go => _blood_boil.go} | 0 .../{blood_strike.go => _blood_strike.go} | 0 .../{blood_tap.go => _blood_tap.go} | 0 .../{bloodworm_pet.go => _bloodworm_pet.go} | 0 .../{bone_shield.go => _bone_shield.go} | 0 ...rune_weapon.go => _dancing_rune_weapon.go} | 0 ...death_and_decay.go => _death_and_decay.go} | 0 .../{death_coil.go => _death_coil.go} | 0 .../{death_pact.go => _death_pact.go} | 0 .../{death_strike.go => _death_strike.go} | 0 .../{diseases.go => _diseases.go} | 0 ...rune_weapon.go => _empower_rune_weapon.go} | 0 .../{frost_strike.go => _frost_strike.go} | 0 .../{ghoul_frenzy.go => _ghoul_frenzy.go} | 0 .../{ghoul_pet.go => _ghoul_pet.go} | 0 .../{heart_strike.go => _heart_strike.go} | 0 .../{horn_of_winter.go => _horn_of_winter.go} | 0 .../{howling_blast.go => _howling_blast.go} | 0 ...nd_fortitude.go => _icebound_fortitude.go} | 0 .../{icy_touch.go => _icy_touch.go} | 0 sim/death_knight/{items.go => _items.go} | 0 .../{mark_of_blood.go => _mark_of_blood.go} | 0 .../{obliterate.go => _obliterate.go} | 0 .../{pestilence.go => _pestilence.go} | 0 .../{plague_strike.go => _plague_strike.go} | 0 .../{presences.go => _presences.go} | 0 .../{raise_dead.go => _raise_dead.go} | 0 .../{rune_strike.go => _rune_strike.go} | 0 .../{rune_tap.go => _rune_tap.go} | 0 .../{scourge_strike.go => _scourge_strike.go} | 0 ...summon_gargoyle.go => _summon_gargoyle.go} | 0 .../{talents_blood.go => _talents_blood.go} | 0 .../{talents_frost.go => _talents_frost.go} | 0 .../{talents_unholy.go => _talents_unholy.go} | 0 ...eakable_armor.go => _unbreakable_armor.go} | 0 .../{unholy_frenzy.go => _unholy_frenzy.go} | 0 .../{vampiric_blood.go => _vampiric_blood.go} | 0 sim/death_knight/blood/blood.go | 4 +- sim/death_knight/death_knight.go | 323 ++- sim/death_knight/frost/frost.go | 14 +- sim/death_knight/unholy/unholy.go | 14 +- sim/druid/{barkskin.go => _barkskin.go} | 0 sim/druid/{berserk.go => _berserk.go} | 0 ...ralizing_roar.go => _demoralizing_roar.go} | 0 sim/druid/{enrage.go => _enrage.go} | 0 sim/druid/{faerie_fire.go => _faerie_fire.go} | 0 sim/druid/{fake_gotw.go => _fake_gotw.go} | 0 sim/druid/{feral => _feral}/TestFeral.results | 0 .../{feral => _feral}/TestFeralApl.results | 0 sim/druid/{feral => _feral}/apl_values.go | 0 sim/druid/{feral => _feral}/feral.go | 46 +- sim/druid/{feral => _feral}/feral_test.go | 0 .../{feral => _feral}/pooling_actions.go | 0 sim/druid/{feral => _feral}/rotation.go | 0 sim/druid/{feral => _feral}/rotation_aoe.go | 0 .../{ferocious_bite.go => _ferocious_bite.go} | 0 ...force_of_nature.go => _force_of_nature.go} | 0 ...eneration.go => _frenzied_regeneration.go} | 0 sim/druid/{hurricane.go => _hurricane.go} | 0 sim/druid/{innervate.go => _innervate.go} | 0 .../{insect_swarm.go => _insect_swarm.go} | 0 sim/druid/{items.go => _items.go} | 0 sim/druid/{lacerate.go => _lacerate.go} | 0 sim/druid/{mangle.go => _mangle.go} | 0 sim/druid/{maul.go => _maul.go} | 0 sim/druid/{moonfire.go => _moonfire.go} | 0 sim/druid/{rake.go => _rake.go} | 0 sim/druid/{rebirth.go => _rebirth.go} | 0 sim/druid/{rip.go => _rip.go} | 0 .../{savage_defense.go => _savage_defense.go} | 0 sim/druid/{savage_roar.go => _savage_roar.go} | 0 sim/druid/{shred.go => _shred.go} | 0 sim/druid/{starfall.go => _starfall.go} | 0 sim/druid/{starfire.go => _starfire.go} | 0 ...al_instincts.go => _survival_instincts.go} | 0 sim/druid/{swipe.go => _swipe.go} | 0 sim/druid/{tigers_fury.go => _tigers_fury.go} | 0 sim/druid/{typhoon.go => _typhoon.go} | 0 sim/druid/{wrath.go => _wrath.go} | 0 sim/druid/balance/balance.go | 16 +- sim/druid/druid.go | 365 ++-- sim/druid/forms.go | 834 ++++---- sim/druid/talents.go | 1323 ++++++------ sim/hunter/{aimed_shot.go => _aimed_shot.go} | 0 .../{arcane_shot.go => _arcane_shot.go} | 0 sim/hunter/{aspects.go => _aspects.go} | 0 .../{black_arrow.go => _black_arrow.go} | 0 .../{chimera_shot.go => _chimera_shot.go} | 0 .../{explosive_shot.go => _explosive_shot.go} | 0 .../{explosive_trap.go => _explosive_trap.go} | 0 sim/hunter/{items.go => _items.go} | 0 .../{kill_command.go => _kill_command.go} | 0 sim/hunter/{kill_shot.go => _kill_shot.go} | 0 sim/hunter/{multi_shot.go => _multi_shot.go} | 0 sim/hunter/{pet.go => _pet.go} | 0 .../{pet_abilities.go => _pet_abilities.go} | 0 .../{pet_talents.go => _pet_talents.go} | 0 sim/hunter/{rapid_fire.go => _rapid_fire.go} | 0 .../{raptor_strike.go => _raptor_strike.go} | 0 .../{scorpid_sting.go => _scorpid_sting.go} | 0 .../{serpent_sting.go => _serpent_sting.go} | 0 .../{silencing_shot.go => _silencing_shot.go} | 0 .../{steady_shot.go => _steady_shot.go} | 0 sim/hunter/{volley.go => _volley.go} | 0 .../{wotlk_items.go => _wotlk_items.go} | 0 sim/hunter/hunter.go | 118 +- sim/hunter/talents.go | 1738 ++++++++-------- .../{arcane_barrage.go => _arcane_barrage.go} | 0 .../{arcane_blast.go => _arcane_blast.go} | 0 ...cane_explosion.go => _arcane_explosion.go} | 0 ...arcane_missiles.go => _arcane_missiles.go} | 0 sim/mage/{blast_wave.go => _blast_wave.go} | 0 sim/mage/{blizzard.go => _blizzard.go} | 0 sim/mage/{deep_freeze.go => _deep_freeze.go} | 0 .../{dragons_breath.go => _dragons_breath.go} | 0 sim/mage/{evocation.go => _evocation.go} | 0 sim/mage/{fire_blast.go => _fire_blast.go} | 0 sim/mage/{fireball.go => _fireball.go} | 0 sim/mage/{flamestrike.go => _flamestrike.go} | 0 sim/mage/{focus_magic.go => _focus_magic.go} | 0 sim/mage/{frostbolt.go => _frostbolt.go} | 0 .../{frostfire_bolt.go => _frostfire_bolt.go} | 0 sim/mage/{ice_lance.go => _ice_lance.go} | 0 sim/mage/{ignite.go => _ignite.go} | 0 sim/mage/{items.go => _items.go} | 0 sim/mage/{living_bomb.go => _living_bomb.go} | 0 sim/mage/{mana_gems.go => _mana_gems.go} | 0 .../{mirror_image.go => _mirror_image.go} | 0 sim/mage/{pyroblast.go => _pyroblast.go} | 0 sim/mage/{scorch.go => _scorch.go} | 0 ...water_elemental.go => _water_elemental.go} | 0 sim/mage/mage.go | 105 +- sim/mage/talents.go | 1646 ++++++++------- ...avengers_shield.go => _avengers_shield.go} | 0 .../{avenging_wrath.go => _avenging_wrath.go} | 0 .../{consecration.go => _consecration.go} | 0 ...crusader_strike.go => _crusader_strike.go} | 0 .../{divine_plea.go => _divine_plea.go} | 0 ...ne_protection.go => _divine_protection.go} | 0 .../{divine_storm.go => _divine_storm.go} | 0 sim/paladin/{exorcism.go => _exorcism.go} | 0 ...ghteous.go => _hammer_of_the_righteous.go} | 0 ...hammer_of_wrath.go => _hammer_of_wrath.go} | 0 ..._of_reckoning.go => _hand_of_reckoning.go} | 0 .../{holy_shield.go => _holy_shield.go} | 0 sim/paladin/{holy_wrath.go => _holy_wrath.go} | 0 sim/paladin/{items.go => _items.go} | 0 sim/paladin/{judgement.go => _judgement.go} | 0 .../{righteous_fury.go => _righteous_fury.go} | 0 sim/paladin/{seals.go => _seals.go} | 0 ...ousness.go => _shield_of_righteousness.go} | 0 sim/paladin/{soc.go => _soc.go} | 0 sim/paladin/{sor.go => _sor.go} | 0 sim/paladin/{sov.go => _sov.go} | 0 ...attunement.go => _spiritual_attunement.go} | 0 sim/paladin/paladin.go | 135 +- sim/paladin/protection/protection.go | 32 +- sim/paladin/retribution/retribution.go | 2 +- sim/paladin/talents.go | 1318 ++++++------ .../{binding_heal.go => _binding_heal.go} | 0 ...le_of_healing.go => _circle_of_healing.go} | 0 ...vouring_plague.go => _devouring_plague.go} | 0 sim/priest/{dispersion.go => _dispersion.go} | 0 sim/priest/{flash_heal.go => _flash_heal.go} | 0 .../{greater_heal.go => _greater_heal.go} | 0 sim/priest/{holy_fire.go => _holy_fire.go} | 0 .../{hymn_of_hope.go => _hymn_of_hope.go} | 0 sim/priest/{items.go => _items.go} | 0 sim/priest/{mind_blast.go => _mind_blast.go} | 0 sim/priest/{mind_flay.go => _mind_flay.go} | 0 sim/priest/{mind_sear.go => _mind_sear.go} | 0 sim/priest/{penance.go => _penance.go} | 0 .../{power_infusion.go => _power_infusion.go} | 0 ...r_word_shield.go => _power_word_shield.go} | 0 ...er_of_healing.go => _prayer_of_healing.go} | 0 ...er_of_mending.go => _prayer_of_mending.go} | 0 sim/priest/{renew.go => _renew.go} | 0 .../{set_bonuses.go => _set_bonuses.go} | 0 ...ow_word_death.go => _shadow_word_death.go} | 0 ...adow_word_pain.go => _shadow_word_pain.go} | 0 .../{shadowfiend.go => _shadowfiend.go} | 0 ...shadowfiend_pet.go => _shadowfiend_pet.go} | 0 sim/priest/{smite.go => _smite.go} | 0 .../{vampiric_touch.go => _vampiric_touch.go} | 0 sim/priest/discipline/discipline.go | 8 +- sim/priest/holy/holy.go | 10 +- sim/priest/priest.go | 179 +- sim/priest/talents.go | 980 +++++---- sim/register_all.go | 7 +- ...ion.results => _TestAssassination.results} | 0 ...TestCombat.results => _TestCombat.results} | 0 ...Subtlety.results => _TestSubtlety.results} | 0 sim/rogue/{ambush.go => _ambush.go} | 0 sim/rogue/{backstab.go => _backstab.go} | 0 sim/rogue/{envenom.go => _envenom.go} | 0 sim/rogue/{eviscerate.go => _eviscerate.go} | 0 .../{expose_armor.go => _expose_armor.go} | 0 .../{fan_of_knives.go => _fan_of_knives.go} | 0 sim/rogue/{feint.go => _feint.go} | 0 sim/rogue/{garrote.go => _garrote.go} | 0 .../{ghostly_strike.go => _ghostly_strike.go} | 0 .../{hack_and_slash.go => _hack_and_slash.go} | 0 sim/rogue/{hemorrhage.go => _hemorrhage.go} | 0 sim/rogue/{items.go => _items.go} | 0 .../{killing_spree.go => _killing_spree.go} | 0 ..._of_subtlety.go => _master_of_subtlety.go} | 0 sim/rogue/{mutilate.go => _mutilate.go} | 0 sim/rogue/{overkill.go => _overkill.go} | 0 sim/rogue/{poisons.go => _poisons.go} | 0 .../{premeditation.go => _premeditation.go} | 0 sim/rogue/{preparation.go => _preparation.go} | 0 sim/rogue/{rupture.go => _rupture.go} | 0 .../{shadow_dance.go => _shadow_dance.go} | 0 sim/rogue/{shadowstep.go => _shadowstep.go} | 0 sim/rogue/{shiv.go => _shiv.go} | 0 ...sinister_strike.go => _sinister_strike.go} | 0 .../{slice_and_dice.go => _slice_and_dice.go} | 0 sim/rogue/{stealth.go => _stealth.go} | 0 sim/rogue/{thistle_tea.go => _thistle_tea.go} | 0 ...f_the_trade.go => _tricks_of_the_trade.go} | 0 sim/rogue/{vanish.go => _vanish.go} | 0 sim/rogue/rogue.go | 165 +- sim/rogue/talents.go | 1285 ++++++------ sim/shaman/{apl_values.go => _apl_values.go} | 0 sim/shaman/{bloodlust.go => _bloodlust.go} | 0 ...chain_lightning.go => _chain_lightning.go} | 0 .../{electric_spell.go => _electric_spell.go} | 0 .../{feral_spirit.go => _feral_spirit.go} | 0 ...lemental_pet.go => _fire_elemental_pet.go} | 0 ...al_spells.go => _fire_elemental_spells.go} | 0 ...ntal_totem.go => _fire_elemental_totem.go} | 0 .../{fire_totems.go => _fire_totems.go} | 0 sim/shaman/{firenova.go => _firenova.go} | 0 sim/shaman/{heals.go => _heals.go} | 0 sim/shaman/{items.go => _items.go} | 0 .../{items_wotlk.go => _items_wotlk.go} | 0 sim/shaman/{lavaburst.go => _lavaburst.go} | 0 sim/shaman/{lavalash.go => _lavalash.go} | 0 .../{lightning_bolt.go => _lightning_bolt.go} | 0 ...ghtning_shield.go => _lightning_shield.go} | 0 ...amanistic_rage.go => _shamanistic_rage.go} | 0 sim/shaman/{shocks.go => _shocks.go} | 0 .../{spirit_wolves.go => _spirit_wolves.go} | 0 .../{stormstrike.go => _stormstrike.go} | 0 .../{thunderstorm.go => _thunderstorm.go} | 0 sim/shaman/{totems.go => _totems.go} | 0 .../{weapon_imbues.go => _weapon_imbues.go} | 0 sim/shaman/elemental/elemental.go | 34 +- sim/shaman/enhancement/enhancement.go | 76 +- sim/shaman/restoration/restoration.go | 32 +- sim/shaman/shaman.go | 265 ++- sim/shaman/talents.go | 974 +++++---- sim/warlock/{apl_values.go => _apl_values.go} | 0 sim/warlock/{chaos_bolt.go => _chaos_bolt.go} | 0 .../{conflagrate.go => _conflagrate.go} | 0 sim/warlock/{corruption.go => _corruption.go} | 0 sim/warlock/{curses.go => _curses.go} | 0 sim/warlock/{darkpact.go => _darkpact.go} | 0 ...empowerment.go => _demonic_empowerment.go} | 0 sim/warlock/{drain_soul.go => _drain_soul.go} | 0 sim/warlock/{haunt.go => _haunt.go} | 0 sim/warlock/{immolate.go => _immolate.go} | 0 sim/warlock/{incinerate.go => _incinerate.go} | 0 sim/warlock/{inferno.go => _inferno.go} | 0 sim/warlock/{items.go => _items.go} | 0 sim/warlock/{lifetap.go => _lifetap.go} | 0 .../{metamorphosis.go => _metamorphosis.go} | 0 sim/warlock/{pet.go => _pet.go} | 0 .../{pet_abilities.go => _pet_abilities.go} | 0 .../{searing_pain.go => _searing_pain.go} | 0 sim/warlock/{seed.go => _seed.go} | 0 sim/warlock/{shadowbolt.go => _shadowbolt.go} | 0 sim/warlock/{shadowburn.go => _shadowburn.go} | 0 sim/warlock/{soul_fire.go => _soul_fire.go} | 0 ..._affliction.go => _unstable_affliction.go} | 0 ...affliction_test.go => _affliction_test.go} | 0 ...demonology_test.go => _demonology_test.go} | 0 ...struction_test.go => _destruction_test.go} | 0 sim/warlock/talents.go | 1180 ++++++----- sim/warlock/warlock.go | 153 +- .../{berserker_rage.go => _berserker_rage.go} | 0 sim/warrior/{bloodrage.go => _bloodrage.go} | 0 .../{bloodthirst.go => _bloodthirst.go} | 0 ...concussion_blow.go => _concussion_blow.go} | 0 .../{deep_wounds.go => _deep_wounds.go} | 0 ...lizing_shout.go => _demoralizing_shout.go} | 0 sim/warrior/{devastate.go => _devastate.go} | 0 sim/warrior/{execute.go => _execute.go} | 0 ...ike_cleave.go => _heroic_strike_cleave.go} | 0 .../{heroic_throw.go => _heroic_throw.go} | 0 sim/warrior/{items.go => _items.go} | 0 .../{mortal_strike.go => _mortal_strike.go} | 0 sim/warrior/{overpower.go => _overpower.go} | 0 .../{recklessness.go => _recklessness.go} | 0 sim/warrior/{rend.go => _rend.go} | 0 sim/warrior/{revenge.go => _revenge.go} | 0 ...attering_throw.go => _shattering_throw.go} | 0 .../{shield_block.go => _shield_block.go} | 0 .../{shield_slam.go => _shield_slam.go} | 0 .../{shield_wall.go => _shield_wall.go} | 0 sim/warrior/{shockwave.go => _shockwave.go} | 0 sim/warrior/{shouts.go => _shouts.go} | 0 sim/warrior/{slam.go => _slam.go} | 0 sim/warrior/{stances.go => _stances.go} | 0 .../{sunder_armor.go => _sunder_armor.go} | 0 ...eeping_strikes.go => _sweeping_strikes.go} | 0 .../{thunder_clap.go => _thunder_clap.go} | 0 sim/warrior/{whirlwind.go => _whirlwind.go} | 0 .../arms/{arms_test.go => _arms_test.go} | 0 sim/warrior/arms/arms.go | 58 +- sim/warrior/fury/fury.go | 54 +- ...protection_test.go => _protection_test.go} | 0 sim/warrior/protection/protection.go | 66 +- sim/warrior/talents.go | 1830 ++++++++--------- sim/warrior/warrior.go | 78 +- ui/core/talents/glyphs_picker.tsx | 2 +- ui/death_knight/blood/inputs.ts | 26 +- ui/death_knight/blood/presets.ts | 54 +- ui/death_knight/frost/presets.ts | 36 +- ui/death_knight/frost/sim.ts | 14 +- ui/death_knight/inputs.ts | 16 +- ui/death_knight/unholy/inputs.ts | 34 +- ui/death_knight/unholy/presets.ts | 72 +- ui/death_knight/unholy/sim.ts | 16 +- ui/druid/balance/presets.ts | 72 +- ui/druid/feral/inputs.ts | 14 +- ui/druid/feral/presets.ts | 18 +- ui/druid/restoration/presets.ts | 36 +- ui/hunter/beast_mastery/inputs.ts | 8 - ui/hunter/beast_mastery/presets.ts | 18 +- ui/hunter/marksmanship/inputs.ts | 8 - ui/hunter/marksmanship/presets.ts | 18 +- ui/hunter/marksmanship/sim.ts | 2 +- ui/hunter/survival/inputs.ts | 16 +- ui/hunter/survival/presets.ts | 18 +- ui/hunter/survival/sim.ts | 2 +- ui/mage/arcane/inputs.ts | 16 +- ui/mage/arcane/presets.ts | 18 +- ui/mage/arcane/sim.ts | 18 +- ui/mage/fire/presets.ts | 18 +- ui/mage/fire/sim.ts | 18 +- ui/mage/frost/inputs.ts | 16 +- ui/mage/frost/presets.ts | 18 +- ui/mage/frost/sim.ts | 22 +- ui/paladin/holy/presets.ts | 18 +- ui/paladin/inputs.ts | 28 +- ui/paladin/protection/presets.ts | 18 +- ui/paladin/protection/sim.ts | 32 +- ui/paladin/retribution/presets.ts | 36 +- ui/paladin/retribution/sim.ts | 32 +- ui/priest/discipline/presets.ts | 36 +- ui/priest/discipline/sim.ts | 14 +- ui/priest/holy/presets.ts | 36 +- ui/priest/holy/sim.ts | 14 +- ui/priest/shadow/presets.ts | 36 +- ui/priest/shadow/sim.ts | 14 +- ui/raid/_raid_stats.ts | 1178 +++++++++++ ui/raid/assignments_picker.ts | 46 +- ui/raid/raid_stats.ts | 1178 ----------- ui/raid/raid_tab.ts | 10 +- ui/rogue/assassination/presets.ts | 36 +- ui/rogue/assassination/sim.ts | 256 +-- ui/rogue/combat/presets.ts | 24 +- ui/rogue/combat/sim.ts | 256 +-- ui/rogue/inputs.ts | 46 +- ui/rogue/subtlety/presets.ts | 24 +- ui/rogue/subtlety/sim.ts | 258 +-- ui/shaman/elemental/presets.ts | 18 +- ui/shaman/elemental/sim.ts | 16 +- ui/shaman/enhancement/presets.ts | 28 +- ui/shaman/inputs.ts | 50 +- ui/shaman/restoration/inputs.ts | 16 +- ui/shaman/restoration/presets.ts | 36 +- ui/shaman/restoration/sim.ts | 19 +- ui/warlock/affliction/presets.ts | 18 +- ui/warlock/affliction/sim.ts | 6 +- ui/warlock/demonology/presets.ts | 18 +- ui/warlock/demonology/sim.ts | 6 +- ui/warlock/destruction/presets.ts | 18 +- ui/warlock/destruction/sim.ts | 6 +- ui/warlock/inputs.ts | 32 +- ui/warrior/arms/presets.ts | 18 +- ui/warrior/arms/sim.ts | 20 +- ui/warrior/fury/presets.ts | 18 +- ui/warrior/fury/sim.ts | 20 +- ui/warrior/protection/presets.ts | 36 +- 388 files changed, 10027 insertions(+), 10109 deletions(-) rename sim/death_knight/{anti_magic_shell.go => _anti_magic_shell.go} (100%) rename sim/death_knight/{army_of_the_dead.go => _army_of_the_dead.go} (100%) rename sim/death_knight/{blood_boil.go => _blood_boil.go} (100%) rename sim/death_knight/{blood_strike.go => _blood_strike.go} (100%) rename sim/death_knight/{blood_tap.go => _blood_tap.go} (100%) rename sim/death_knight/{bloodworm_pet.go => _bloodworm_pet.go} (100%) rename sim/death_knight/{bone_shield.go => _bone_shield.go} (100%) rename sim/death_knight/{dancing_rune_weapon.go => _dancing_rune_weapon.go} (100%) rename sim/death_knight/{death_and_decay.go => _death_and_decay.go} (100%) rename sim/death_knight/{death_coil.go => _death_coil.go} (100%) rename sim/death_knight/{death_pact.go => _death_pact.go} (100%) rename sim/death_knight/{death_strike.go => _death_strike.go} (100%) rename sim/death_knight/{diseases.go => _diseases.go} (100%) rename sim/death_knight/{empower_rune_weapon.go => _empower_rune_weapon.go} (100%) rename sim/death_knight/{frost_strike.go => _frost_strike.go} (100%) rename sim/death_knight/{ghoul_frenzy.go => _ghoul_frenzy.go} (100%) rename sim/death_knight/{ghoul_pet.go => _ghoul_pet.go} (100%) rename sim/death_knight/{heart_strike.go => _heart_strike.go} (100%) rename sim/death_knight/{horn_of_winter.go => _horn_of_winter.go} (100%) rename sim/death_knight/{howling_blast.go => _howling_blast.go} (100%) rename sim/death_knight/{icebound_fortitude.go => _icebound_fortitude.go} (100%) rename sim/death_knight/{icy_touch.go => _icy_touch.go} (100%) rename sim/death_knight/{items.go => _items.go} (100%) rename sim/death_knight/{mark_of_blood.go => _mark_of_blood.go} (100%) rename sim/death_knight/{obliterate.go => _obliterate.go} (100%) rename sim/death_knight/{pestilence.go => _pestilence.go} (100%) rename sim/death_knight/{plague_strike.go => _plague_strike.go} (100%) rename sim/death_knight/{presences.go => _presences.go} (100%) rename sim/death_knight/{raise_dead.go => _raise_dead.go} (100%) rename sim/death_knight/{rune_strike.go => _rune_strike.go} (100%) rename sim/death_knight/{rune_tap.go => _rune_tap.go} (100%) rename sim/death_knight/{scourge_strike.go => _scourge_strike.go} (100%) rename sim/death_knight/{summon_gargoyle.go => _summon_gargoyle.go} (100%) rename sim/death_knight/{talents_blood.go => _talents_blood.go} (100%) rename sim/death_knight/{talents_frost.go => _talents_frost.go} (100%) rename sim/death_knight/{talents_unholy.go => _talents_unholy.go} (100%) rename sim/death_knight/{unbreakable_armor.go => _unbreakable_armor.go} (100%) rename sim/death_knight/{unholy_frenzy.go => _unholy_frenzy.go} (100%) rename sim/death_knight/{vampiric_blood.go => _vampiric_blood.go} (100%) rename sim/druid/{barkskin.go => _barkskin.go} (100%) rename sim/druid/{berserk.go => _berserk.go} (100%) rename sim/druid/{demoralizing_roar.go => _demoralizing_roar.go} (100%) rename sim/druid/{enrage.go => _enrage.go} (100%) rename sim/druid/{faerie_fire.go => _faerie_fire.go} (100%) rename sim/druid/{fake_gotw.go => _fake_gotw.go} (100%) rename sim/druid/{feral => _feral}/TestFeral.results (100%) rename sim/druid/{feral => _feral}/TestFeralApl.results (100%) rename sim/druid/{feral => _feral}/apl_values.go (100%) rename sim/druid/{feral => _feral}/feral.go (66%) rename sim/druid/{feral => _feral}/feral_test.go (100%) rename sim/druid/{feral => _feral}/pooling_actions.go (100%) rename sim/druid/{feral => _feral}/rotation.go (100%) rename sim/druid/{feral => _feral}/rotation_aoe.go (100%) rename sim/druid/{ferocious_bite.go => _ferocious_bite.go} (100%) rename sim/druid/{force_of_nature.go => _force_of_nature.go} (100%) rename sim/druid/{frenzied_regeneration.go => _frenzied_regeneration.go} (100%) rename sim/druid/{hurricane.go => _hurricane.go} (100%) rename sim/druid/{innervate.go => _innervate.go} (100%) rename sim/druid/{insect_swarm.go => _insect_swarm.go} (100%) rename sim/druid/{items.go => _items.go} (100%) rename sim/druid/{lacerate.go => _lacerate.go} (100%) rename sim/druid/{mangle.go => _mangle.go} (100%) rename sim/druid/{maul.go => _maul.go} (100%) rename sim/druid/{moonfire.go => _moonfire.go} (100%) rename sim/druid/{rake.go => _rake.go} (100%) rename sim/druid/{rebirth.go => _rebirth.go} (100%) rename sim/druid/{rip.go => _rip.go} (100%) rename sim/druid/{savage_defense.go => _savage_defense.go} (100%) rename sim/druid/{savage_roar.go => _savage_roar.go} (100%) rename sim/druid/{shred.go => _shred.go} (100%) rename sim/druid/{starfall.go => _starfall.go} (100%) rename sim/druid/{starfire.go => _starfire.go} (100%) rename sim/druid/{survival_instincts.go => _survival_instincts.go} (100%) rename sim/druid/{swipe.go => _swipe.go} (100%) rename sim/druid/{tigers_fury.go => _tigers_fury.go} (100%) rename sim/druid/{typhoon.go => _typhoon.go} (100%) rename sim/druid/{wrath.go => _wrath.go} (100%) rename sim/hunter/{aimed_shot.go => _aimed_shot.go} (100%) rename sim/hunter/{arcane_shot.go => _arcane_shot.go} (100%) rename sim/hunter/{aspects.go => _aspects.go} (100%) rename sim/hunter/{black_arrow.go => _black_arrow.go} (100%) rename sim/hunter/{chimera_shot.go => _chimera_shot.go} (100%) rename sim/hunter/{explosive_shot.go => _explosive_shot.go} (100%) rename sim/hunter/{explosive_trap.go => _explosive_trap.go} (100%) rename sim/hunter/{items.go => _items.go} (100%) rename sim/hunter/{kill_command.go => _kill_command.go} (100%) rename sim/hunter/{kill_shot.go => _kill_shot.go} (100%) rename sim/hunter/{multi_shot.go => _multi_shot.go} (100%) rename sim/hunter/{pet.go => _pet.go} (100%) rename sim/hunter/{pet_abilities.go => _pet_abilities.go} (100%) rename sim/hunter/{pet_talents.go => _pet_talents.go} (100%) rename sim/hunter/{rapid_fire.go => _rapid_fire.go} (100%) rename sim/hunter/{raptor_strike.go => _raptor_strike.go} (100%) rename sim/hunter/{scorpid_sting.go => _scorpid_sting.go} (100%) rename sim/hunter/{serpent_sting.go => _serpent_sting.go} (100%) rename sim/hunter/{silencing_shot.go => _silencing_shot.go} (100%) rename sim/hunter/{steady_shot.go => _steady_shot.go} (100%) rename sim/hunter/{volley.go => _volley.go} (100%) rename sim/hunter/{wotlk_items.go => _wotlk_items.go} (100%) rename sim/mage/{arcane_barrage.go => _arcane_barrage.go} (100%) rename sim/mage/{arcane_blast.go => _arcane_blast.go} (100%) rename sim/mage/{arcane_explosion.go => _arcane_explosion.go} (100%) rename sim/mage/{arcane_missiles.go => _arcane_missiles.go} (100%) rename sim/mage/{blast_wave.go => _blast_wave.go} (100%) rename sim/mage/{blizzard.go => _blizzard.go} (100%) rename sim/mage/{deep_freeze.go => _deep_freeze.go} (100%) rename sim/mage/{dragons_breath.go => _dragons_breath.go} (100%) rename sim/mage/{evocation.go => _evocation.go} (100%) rename sim/mage/{fire_blast.go => _fire_blast.go} (100%) rename sim/mage/{fireball.go => _fireball.go} (100%) rename sim/mage/{flamestrike.go => _flamestrike.go} (100%) rename sim/mage/{focus_magic.go => _focus_magic.go} (100%) rename sim/mage/{frostbolt.go => _frostbolt.go} (100%) rename sim/mage/{frostfire_bolt.go => _frostfire_bolt.go} (100%) rename sim/mage/{ice_lance.go => _ice_lance.go} (100%) rename sim/mage/{ignite.go => _ignite.go} (100%) rename sim/mage/{items.go => _items.go} (100%) rename sim/mage/{living_bomb.go => _living_bomb.go} (100%) rename sim/mage/{mana_gems.go => _mana_gems.go} (100%) rename sim/mage/{mirror_image.go => _mirror_image.go} (100%) rename sim/mage/{pyroblast.go => _pyroblast.go} (100%) rename sim/mage/{scorch.go => _scorch.go} (100%) rename sim/mage/{water_elemental.go => _water_elemental.go} (100%) rename sim/paladin/{avengers_shield.go => _avengers_shield.go} (100%) rename sim/paladin/{avenging_wrath.go => _avenging_wrath.go} (100%) rename sim/paladin/{consecration.go => _consecration.go} (100%) rename sim/paladin/{crusader_strike.go => _crusader_strike.go} (100%) rename sim/paladin/{divine_plea.go => _divine_plea.go} (100%) rename sim/paladin/{divine_protection.go => _divine_protection.go} (100%) rename sim/paladin/{divine_storm.go => _divine_storm.go} (100%) rename sim/paladin/{exorcism.go => _exorcism.go} (100%) rename sim/paladin/{hammer_of_the_righteous.go => _hammer_of_the_righteous.go} (100%) rename sim/paladin/{hammer_of_wrath.go => _hammer_of_wrath.go} (100%) rename sim/paladin/{hand_of_reckoning.go => _hand_of_reckoning.go} (100%) rename sim/paladin/{holy_shield.go => _holy_shield.go} (100%) rename sim/paladin/{holy_wrath.go => _holy_wrath.go} (100%) rename sim/paladin/{items.go => _items.go} (100%) rename sim/paladin/{judgement.go => _judgement.go} (100%) rename sim/paladin/{righteous_fury.go => _righteous_fury.go} (100%) rename sim/paladin/{seals.go => _seals.go} (100%) rename sim/paladin/{shield_of_righteousness.go => _shield_of_righteousness.go} (100%) rename sim/paladin/{soc.go => _soc.go} (100%) rename sim/paladin/{sor.go => _sor.go} (100%) rename sim/paladin/{sov.go => _sov.go} (100%) rename sim/paladin/{spiritual_attunement.go => _spiritual_attunement.go} (100%) rename sim/priest/{binding_heal.go => _binding_heal.go} (100%) rename sim/priest/{circle_of_healing.go => _circle_of_healing.go} (100%) rename sim/priest/{devouring_plague.go => _devouring_plague.go} (100%) rename sim/priest/{dispersion.go => _dispersion.go} (100%) rename sim/priest/{flash_heal.go => _flash_heal.go} (100%) rename sim/priest/{greater_heal.go => _greater_heal.go} (100%) rename sim/priest/{holy_fire.go => _holy_fire.go} (100%) rename sim/priest/{hymn_of_hope.go => _hymn_of_hope.go} (100%) rename sim/priest/{items.go => _items.go} (100%) rename sim/priest/{mind_blast.go => _mind_blast.go} (100%) rename sim/priest/{mind_flay.go => _mind_flay.go} (100%) rename sim/priest/{mind_sear.go => _mind_sear.go} (100%) rename sim/priest/{penance.go => _penance.go} (100%) rename sim/priest/{power_infusion.go => _power_infusion.go} (100%) rename sim/priest/{power_word_shield.go => _power_word_shield.go} (100%) rename sim/priest/{prayer_of_healing.go => _prayer_of_healing.go} (100%) rename sim/priest/{prayer_of_mending.go => _prayer_of_mending.go} (100%) rename sim/priest/{renew.go => _renew.go} (100%) rename sim/priest/{set_bonuses.go => _set_bonuses.go} (100%) rename sim/priest/{shadow_word_death.go => _shadow_word_death.go} (100%) rename sim/priest/{shadow_word_pain.go => _shadow_word_pain.go} (100%) rename sim/priest/{shadowfiend.go => _shadowfiend.go} (100%) rename sim/priest/{shadowfiend_pet.go => _shadowfiend_pet.go} (100%) rename sim/priest/{smite.go => _smite.go} (100%) rename sim/priest/{vampiric_touch.go => _vampiric_touch.go} (100%) rename sim/rogue/{TestAssassination.results => _TestAssassination.results} (100%) rename sim/rogue/{TestCombat.results => _TestCombat.results} (100%) rename sim/rogue/{TestSubtlety.results => _TestSubtlety.results} (100%) rename sim/rogue/{ambush.go => _ambush.go} (100%) rename sim/rogue/{backstab.go => _backstab.go} (100%) rename sim/rogue/{envenom.go => _envenom.go} (100%) rename sim/rogue/{eviscerate.go => _eviscerate.go} (100%) rename sim/rogue/{expose_armor.go => _expose_armor.go} (100%) rename sim/rogue/{fan_of_knives.go => _fan_of_knives.go} (100%) rename sim/rogue/{feint.go => _feint.go} (100%) rename sim/rogue/{garrote.go => _garrote.go} (100%) rename sim/rogue/{ghostly_strike.go => _ghostly_strike.go} (100%) rename sim/rogue/{hack_and_slash.go => _hack_and_slash.go} (100%) rename sim/rogue/{hemorrhage.go => _hemorrhage.go} (100%) rename sim/rogue/{items.go => _items.go} (100%) rename sim/rogue/{killing_spree.go => _killing_spree.go} (100%) rename sim/rogue/{master_of_subtlety.go => _master_of_subtlety.go} (100%) rename sim/rogue/{mutilate.go => _mutilate.go} (100%) rename sim/rogue/{overkill.go => _overkill.go} (100%) rename sim/rogue/{poisons.go => _poisons.go} (100%) rename sim/rogue/{premeditation.go => _premeditation.go} (100%) rename sim/rogue/{preparation.go => _preparation.go} (100%) rename sim/rogue/{rupture.go => _rupture.go} (100%) rename sim/rogue/{shadow_dance.go => _shadow_dance.go} (100%) rename sim/rogue/{shadowstep.go => _shadowstep.go} (100%) rename sim/rogue/{shiv.go => _shiv.go} (100%) rename sim/rogue/{sinister_strike.go => _sinister_strike.go} (100%) rename sim/rogue/{slice_and_dice.go => _slice_and_dice.go} (100%) rename sim/rogue/{stealth.go => _stealth.go} (100%) rename sim/rogue/{thistle_tea.go => _thistle_tea.go} (100%) rename sim/rogue/{tricks_of_the_trade.go => _tricks_of_the_trade.go} (100%) rename sim/rogue/{vanish.go => _vanish.go} (100%) rename sim/shaman/{apl_values.go => _apl_values.go} (100%) rename sim/shaman/{bloodlust.go => _bloodlust.go} (100%) rename sim/shaman/{chain_lightning.go => _chain_lightning.go} (100%) rename sim/shaman/{electric_spell.go => _electric_spell.go} (100%) rename sim/shaman/{feral_spirit.go => _feral_spirit.go} (100%) rename sim/shaman/{fire_elemental_pet.go => _fire_elemental_pet.go} (100%) rename sim/shaman/{fire_elemental_spells.go => _fire_elemental_spells.go} (100%) rename sim/shaman/{fire_elemental_totem.go => _fire_elemental_totem.go} (100%) rename sim/shaman/{fire_totems.go => _fire_totems.go} (100%) rename sim/shaman/{firenova.go => _firenova.go} (100%) rename sim/shaman/{heals.go => _heals.go} (100%) rename sim/shaman/{items.go => _items.go} (100%) rename sim/shaman/{items_wotlk.go => _items_wotlk.go} (100%) rename sim/shaman/{lavaburst.go => _lavaburst.go} (100%) rename sim/shaman/{lavalash.go => _lavalash.go} (100%) rename sim/shaman/{lightning_bolt.go => _lightning_bolt.go} (100%) rename sim/shaman/{lightning_shield.go => _lightning_shield.go} (100%) rename sim/shaman/{shamanistic_rage.go => _shamanistic_rage.go} (100%) rename sim/shaman/{shocks.go => _shocks.go} (100%) rename sim/shaman/{spirit_wolves.go => _spirit_wolves.go} (100%) rename sim/shaman/{stormstrike.go => _stormstrike.go} (100%) rename sim/shaman/{thunderstorm.go => _thunderstorm.go} (100%) rename sim/shaman/{totems.go => _totems.go} (100%) rename sim/shaman/{weapon_imbues.go => _weapon_imbues.go} (100%) rename sim/warlock/{apl_values.go => _apl_values.go} (100%) rename sim/warlock/{chaos_bolt.go => _chaos_bolt.go} (100%) rename sim/warlock/{conflagrate.go => _conflagrate.go} (100%) rename sim/warlock/{corruption.go => _corruption.go} (100%) rename sim/warlock/{curses.go => _curses.go} (100%) rename sim/warlock/{darkpact.go => _darkpact.go} (100%) rename sim/warlock/{demonic_empowerment.go => _demonic_empowerment.go} (100%) rename sim/warlock/{drain_soul.go => _drain_soul.go} (100%) rename sim/warlock/{haunt.go => _haunt.go} (100%) rename sim/warlock/{immolate.go => _immolate.go} (100%) rename sim/warlock/{incinerate.go => _incinerate.go} (100%) rename sim/warlock/{inferno.go => _inferno.go} (100%) rename sim/warlock/{items.go => _items.go} (100%) rename sim/warlock/{lifetap.go => _lifetap.go} (100%) rename sim/warlock/{metamorphosis.go => _metamorphosis.go} (100%) rename sim/warlock/{pet.go => _pet.go} (100%) rename sim/warlock/{pet_abilities.go => _pet_abilities.go} (100%) rename sim/warlock/{searing_pain.go => _searing_pain.go} (100%) rename sim/warlock/{seed.go => _seed.go} (100%) rename sim/warlock/{shadowbolt.go => _shadowbolt.go} (100%) rename sim/warlock/{shadowburn.go => _shadowburn.go} (100%) rename sim/warlock/{soul_fire.go => _soul_fire.go} (100%) rename sim/warlock/{unstable_affliction.go => _unstable_affliction.go} (100%) rename sim/warlock/affliction/{affliction_test.go => _affliction_test.go} (100%) rename sim/warlock/demonology/{demonology_test.go => _demonology_test.go} (100%) rename sim/warlock/destruction/{destruction_test.go => _destruction_test.go} (100%) rename sim/warrior/{berserker_rage.go => _berserker_rage.go} (100%) rename sim/warrior/{bloodrage.go => _bloodrage.go} (100%) rename sim/warrior/{bloodthirst.go => _bloodthirst.go} (100%) rename sim/warrior/{concussion_blow.go => _concussion_blow.go} (100%) rename sim/warrior/{deep_wounds.go => _deep_wounds.go} (100%) rename sim/warrior/{demoralizing_shout.go => _demoralizing_shout.go} (100%) rename sim/warrior/{devastate.go => _devastate.go} (100%) rename sim/warrior/{execute.go => _execute.go} (100%) rename sim/warrior/{heroic_strike_cleave.go => _heroic_strike_cleave.go} (100%) rename sim/warrior/{heroic_throw.go => _heroic_throw.go} (100%) rename sim/warrior/{items.go => _items.go} (100%) rename sim/warrior/{mortal_strike.go => _mortal_strike.go} (100%) rename sim/warrior/{overpower.go => _overpower.go} (100%) rename sim/warrior/{recklessness.go => _recklessness.go} (100%) rename sim/warrior/{rend.go => _rend.go} (100%) rename sim/warrior/{revenge.go => _revenge.go} (100%) rename sim/warrior/{shattering_throw.go => _shattering_throw.go} (100%) rename sim/warrior/{shield_block.go => _shield_block.go} (100%) rename sim/warrior/{shield_slam.go => _shield_slam.go} (100%) rename sim/warrior/{shield_wall.go => _shield_wall.go} (100%) rename sim/warrior/{shockwave.go => _shockwave.go} (100%) rename sim/warrior/{shouts.go => _shouts.go} (100%) rename sim/warrior/{slam.go => _slam.go} (100%) rename sim/warrior/{stances.go => _stances.go} (100%) rename sim/warrior/{sunder_armor.go => _sunder_armor.go} (100%) rename sim/warrior/{sweeping_strikes.go => _sweeping_strikes.go} (100%) rename sim/warrior/{thunder_clap.go => _thunder_clap.go} (100%) rename sim/warrior/{whirlwind.go => _whirlwind.go} (100%) rename sim/warrior/arms/{arms_test.go => _arms_test.go} (100%) rename sim/warrior/protection/{protection_test.go => _protection_test.go} (100%) create mode 100644 ui/raid/_raid_stats.ts delete mode 100644 ui/raid/raid_stats.ts diff --git a/sim/death_knight/anti_magic_shell.go b/sim/death_knight/_anti_magic_shell.go similarity index 100% rename from sim/death_knight/anti_magic_shell.go rename to sim/death_knight/_anti_magic_shell.go diff --git a/sim/death_knight/army_of_the_dead.go b/sim/death_knight/_army_of_the_dead.go similarity index 100% rename from sim/death_knight/army_of_the_dead.go rename to sim/death_knight/_army_of_the_dead.go diff --git a/sim/death_knight/blood_boil.go b/sim/death_knight/_blood_boil.go similarity index 100% rename from sim/death_knight/blood_boil.go rename to sim/death_knight/_blood_boil.go diff --git a/sim/death_knight/blood_strike.go b/sim/death_knight/_blood_strike.go similarity index 100% rename from sim/death_knight/blood_strike.go rename to sim/death_knight/_blood_strike.go diff --git a/sim/death_knight/blood_tap.go b/sim/death_knight/_blood_tap.go similarity index 100% rename from sim/death_knight/blood_tap.go rename to sim/death_knight/_blood_tap.go diff --git a/sim/death_knight/bloodworm_pet.go b/sim/death_knight/_bloodworm_pet.go similarity index 100% rename from sim/death_knight/bloodworm_pet.go rename to sim/death_knight/_bloodworm_pet.go diff --git a/sim/death_knight/bone_shield.go b/sim/death_knight/_bone_shield.go similarity index 100% rename from sim/death_knight/bone_shield.go rename to sim/death_knight/_bone_shield.go diff --git a/sim/death_knight/dancing_rune_weapon.go b/sim/death_knight/_dancing_rune_weapon.go similarity index 100% rename from sim/death_knight/dancing_rune_weapon.go rename to sim/death_knight/_dancing_rune_weapon.go diff --git a/sim/death_knight/death_and_decay.go b/sim/death_knight/_death_and_decay.go similarity index 100% rename from sim/death_knight/death_and_decay.go rename to sim/death_knight/_death_and_decay.go diff --git a/sim/death_knight/death_coil.go b/sim/death_knight/_death_coil.go similarity index 100% rename from sim/death_knight/death_coil.go rename to sim/death_knight/_death_coil.go diff --git a/sim/death_knight/death_pact.go b/sim/death_knight/_death_pact.go similarity index 100% rename from sim/death_knight/death_pact.go rename to sim/death_knight/_death_pact.go diff --git a/sim/death_knight/death_strike.go b/sim/death_knight/_death_strike.go similarity index 100% rename from sim/death_knight/death_strike.go rename to sim/death_knight/_death_strike.go diff --git a/sim/death_knight/diseases.go b/sim/death_knight/_diseases.go similarity index 100% rename from sim/death_knight/diseases.go rename to sim/death_knight/_diseases.go diff --git a/sim/death_knight/empower_rune_weapon.go b/sim/death_knight/_empower_rune_weapon.go similarity index 100% rename from sim/death_knight/empower_rune_weapon.go rename to sim/death_knight/_empower_rune_weapon.go diff --git a/sim/death_knight/frost_strike.go b/sim/death_knight/_frost_strike.go similarity index 100% rename from sim/death_knight/frost_strike.go rename to sim/death_knight/_frost_strike.go diff --git a/sim/death_knight/ghoul_frenzy.go b/sim/death_knight/_ghoul_frenzy.go similarity index 100% rename from sim/death_knight/ghoul_frenzy.go rename to sim/death_knight/_ghoul_frenzy.go diff --git a/sim/death_knight/ghoul_pet.go b/sim/death_knight/_ghoul_pet.go similarity index 100% rename from sim/death_knight/ghoul_pet.go rename to sim/death_knight/_ghoul_pet.go diff --git a/sim/death_knight/heart_strike.go b/sim/death_knight/_heart_strike.go similarity index 100% rename from sim/death_knight/heart_strike.go rename to sim/death_knight/_heart_strike.go diff --git a/sim/death_knight/horn_of_winter.go b/sim/death_knight/_horn_of_winter.go similarity index 100% rename from sim/death_knight/horn_of_winter.go rename to sim/death_knight/_horn_of_winter.go diff --git a/sim/death_knight/howling_blast.go b/sim/death_knight/_howling_blast.go similarity index 100% rename from sim/death_knight/howling_blast.go rename to sim/death_knight/_howling_blast.go diff --git a/sim/death_knight/icebound_fortitude.go b/sim/death_knight/_icebound_fortitude.go similarity index 100% rename from sim/death_knight/icebound_fortitude.go rename to sim/death_knight/_icebound_fortitude.go diff --git a/sim/death_knight/icy_touch.go b/sim/death_knight/_icy_touch.go similarity index 100% rename from sim/death_knight/icy_touch.go rename to sim/death_knight/_icy_touch.go diff --git a/sim/death_knight/items.go b/sim/death_knight/_items.go similarity index 100% rename from sim/death_knight/items.go rename to sim/death_knight/_items.go diff --git a/sim/death_knight/mark_of_blood.go b/sim/death_knight/_mark_of_blood.go similarity index 100% rename from sim/death_knight/mark_of_blood.go rename to sim/death_knight/_mark_of_blood.go diff --git a/sim/death_knight/obliterate.go b/sim/death_knight/_obliterate.go similarity index 100% rename from sim/death_knight/obliterate.go rename to sim/death_knight/_obliterate.go diff --git a/sim/death_knight/pestilence.go b/sim/death_knight/_pestilence.go similarity index 100% rename from sim/death_knight/pestilence.go rename to sim/death_knight/_pestilence.go diff --git a/sim/death_knight/plague_strike.go b/sim/death_knight/_plague_strike.go similarity index 100% rename from sim/death_knight/plague_strike.go rename to sim/death_knight/_plague_strike.go diff --git a/sim/death_knight/presences.go b/sim/death_knight/_presences.go similarity index 100% rename from sim/death_knight/presences.go rename to sim/death_knight/_presences.go diff --git a/sim/death_knight/raise_dead.go b/sim/death_knight/_raise_dead.go similarity index 100% rename from sim/death_knight/raise_dead.go rename to sim/death_knight/_raise_dead.go diff --git a/sim/death_knight/rune_strike.go b/sim/death_knight/_rune_strike.go similarity index 100% rename from sim/death_knight/rune_strike.go rename to sim/death_knight/_rune_strike.go diff --git a/sim/death_knight/rune_tap.go b/sim/death_knight/_rune_tap.go similarity index 100% rename from sim/death_knight/rune_tap.go rename to sim/death_knight/_rune_tap.go diff --git a/sim/death_knight/scourge_strike.go b/sim/death_knight/_scourge_strike.go similarity index 100% rename from sim/death_knight/scourge_strike.go rename to sim/death_knight/_scourge_strike.go diff --git a/sim/death_knight/summon_gargoyle.go b/sim/death_knight/_summon_gargoyle.go similarity index 100% rename from sim/death_knight/summon_gargoyle.go rename to sim/death_knight/_summon_gargoyle.go diff --git a/sim/death_knight/talents_blood.go b/sim/death_knight/_talents_blood.go similarity index 100% rename from sim/death_knight/talents_blood.go rename to sim/death_knight/_talents_blood.go diff --git a/sim/death_knight/talents_frost.go b/sim/death_knight/_talents_frost.go similarity index 100% rename from sim/death_knight/talents_frost.go rename to sim/death_knight/_talents_frost.go diff --git a/sim/death_knight/talents_unholy.go b/sim/death_knight/_talents_unholy.go similarity index 100% rename from sim/death_knight/talents_unholy.go rename to sim/death_knight/_talents_unholy.go diff --git a/sim/death_knight/unbreakable_armor.go b/sim/death_knight/_unbreakable_armor.go similarity index 100% rename from sim/death_knight/unbreakable_armor.go rename to sim/death_knight/_unbreakable_armor.go diff --git a/sim/death_knight/unholy_frenzy.go b/sim/death_knight/_unholy_frenzy.go similarity index 100% rename from sim/death_knight/unholy_frenzy.go rename to sim/death_knight/_unholy_frenzy.go diff --git a/sim/death_knight/vampiric_blood.go b/sim/death_knight/_vampiric_blood.go similarity index 100% rename from sim/death_knight/vampiric_blood.go rename to sim/death_knight/_vampiric_blood.go diff --git a/sim/death_knight/blood/blood.go b/sim/death_knight/blood/blood.go index f9ef860c8f..2b4c43c264 100644 --- a/sim/death_knight/blood/blood.go +++ b/sim/death_knight/blood/blood.go @@ -71,6 +71,6 @@ func (dk *BloodDeathKnight) Initialize() { func (dk *BloodDeathKnight) Reset(sim *core.Simulation) { dk.DeathKnight.Reset(sim) - dk.Presence = death_knight.UnsetPresence - dk.DeathKnight.PseudoStats.Stunned = false + //dk.Presence = death_knight.UnsetPresence + //dk.DeathKnight.PseudoStats.Stunned = false } diff --git a/sim/death_knight/death_knight.go b/sim/death_knight/death_knight.go index f173da407a..8ac327154a 100644 --- a/sim/death_knight/death_knight.go +++ b/sim/death_knight/death_knight.go @@ -1,13 +1,10 @@ package death_knight import ( - "math" "time" - "github.com/wowsims/cata/sim/common/wotlk" "github.com/wowsims/cata/sim/core" "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" ) const ( @@ -57,26 +54,26 @@ type DeathKnight struct { Inputs DeathKnightInputs - Ghoul *GhoulPet + //Ghoul *GhoulPet RaiseDead *core.Spell - Gargoyle *GargoylePet + //Gargoyle *GargoylePet SummonGargoyle *core.Spell SummonGargoyleAura *core.Aura GargoyleSummonDelay time.Duration OnGargoyleStartFirstCast func() - RuneWeapon *RuneWeaponPet + //RuneWeapon *RuneWeaponPet DancingRuneWeapon *core.Spell drwDmgSnapshot float64 drwPhysSnapshot float64 ArmyOfTheDead *core.Spell - ArmyGhoul []*GhoulPet + //ArmyGhoul []*GhoulPet - Bloodworm []*BloodwormPet + //Bloodworm []*BloodwormPet - Presence Presence + //Presence Presence IcyTouch *core.Spell BloodBoil *core.Spell @@ -241,56 +238,56 @@ func (dk *DeathKnight) AddRaidBuffs(raidBuffs *proto.RaidBuffs) { } func (dk *DeathKnight) ApplyTalents() { - dk.ResetBonusCoeffs() + // dk.ResetBonusCoeffs() - dk.ApplyBloodTalents() - dk.ApplyFrostTalents() - dk.ApplyUnholyTalents() + // dk.ApplyBloodTalents() + // dk.ApplyFrostTalents() + // dk.ApplyUnholyTalents() } func (dk *DeathKnight) Initialize() { - dk.registerPresences() - dk.registerIcyTouchSpell() - dk.registerPlagueStrikeSpell() - dk.registerObliterateSpell() - dk.registerBloodStrikeSpell() - dk.registerBloodTapSpell() - dk.registerHowlingBlastSpell() - dk.registerScourgeStrikeSpell() - dk.registerDeathCoilSpell() - dk.registerFrostStrikeSpell() - dk.registerDeathAndDecaySpell() - dk.registerDiseaseDots() - dk.registerGhoulFrenzySpell() - dk.registerBoneShieldSpell() - dk.registerUnbreakableArmorSpell() - dk.registerBloodBoilSpell() - dk.registerHornOfWinterSpell() - dk.registerPestilenceSpell() - dk.registerEmpowerRuneWeaponSpell() - dk.registerRuneTapSpell() - dk.registerIceboundFortitudeSpell() - dk.registerDeathStrikeSpell() - dk.registerHeartStrikeSpell() - dk.registerMarkOfBloodSpell() - dk.registerVampiricBloodSpell() - dk.registerAntiMagicShellSpell() - dk.registerRuneStrikeSpell() - dk.registerMindFreeze() - - dk.registerRaiseDeadCD() - dk.registerSummonGargoyleCD() - dk.registerArmyOfTheDeadCD() - dk.registerDancingRuneWeaponCD() - dk.registerDeathPactSpell() - dk.registerUnholyFrenzyCD() - - // allows us to use these auras in the APL pre-pull actions - wotlk.CreateBlackMagicProcAura(&dk.Character) - CreateVirulenceProcAura(&dk.Character) - - // for some reason re-using the same label as DMC:G proc causes tests to fail - dk.NewTemporaryStatsAura("DMC Greatness Pre-Pull Strength Proc", core.ActionID{SpellID: 60229}, stats.Stats{stats.Strength: 300}, time.Second*15) + // dk.registerPresences() + // dk.registerIcyTouchSpell() + // dk.registerPlagueStrikeSpell() + // dk.registerObliterateSpell() + // dk.registerBloodStrikeSpell() + // dk.registerBloodTapSpell() + // dk.registerHowlingBlastSpell() + // dk.registerScourgeStrikeSpell() + // dk.registerDeathCoilSpell() + // dk.registerFrostStrikeSpell() + // dk.registerDeathAndDecaySpell() + // dk.registerDiseaseDots() + // dk.registerGhoulFrenzySpell() + // dk.registerBoneShieldSpell() + // dk.registerUnbreakableArmorSpell() + // dk.registerBloodBoilSpell() + // dk.registerHornOfWinterSpell() + // dk.registerPestilenceSpell() + // dk.registerEmpowerRuneWeaponSpell() + // dk.registerRuneTapSpell() + // dk.registerIceboundFortitudeSpell() + // dk.registerDeathStrikeSpell() + // dk.registerHeartStrikeSpell() + // dk.registerMarkOfBloodSpell() + // dk.registerVampiricBloodSpell() + // dk.registerAntiMagicShellSpell() + // dk.registerRuneStrikeSpell() + // dk.registerMindFreeze() + + // dk.registerRaiseDeadCD() + // dk.registerSummonGargoyleCD() + // dk.registerArmyOfTheDeadCD() + // dk.registerDancingRuneWeaponCD() + // dk.registerDeathPactSpell() + // dk.registerUnholyFrenzyCD() + + // // allows us to use these auras in the APL pre-pull actions + // wotlk.CreateBlackMagicProcAura(&dk.Character) + // CreateVirulenceProcAura(&dk.Character) + + // // for some reason re-using the same label as DMC:G proc causes tests to fail + // dk.NewTemporaryStatsAura("DMC Greatness Pre-Pull Strength Proc", core.ActionID{SpellID: 60229}, stats.Stats{stats.Strength: 300}, time.Second*15) } func (dk *DeathKnight) registerMindFreeze() { @@ -321,19 +318,19 @@ func (dk *DeathKnight) registerMindFreeze() { } } -func (dk *DeathKnight) ResetBonusCoeffs() { - dk.bonusCoeffs = DeathKnightCoeffs{ - runeTapHealing: 0, +// func (dk *DeathKnight) ResetBonusCoeffs() { +// dk.bonusCoeffs = DeathKnightCoeffs{ +// runeTapHealing: 0, - glacierRotBonusCoeff: 1, - mercilessCombatBonusCoeff: 1, - impurityBonusCoeff: 1, - threatOfThassarianChance: 0, +// glacierRotBonusCoeff: 1, +// mercilessCombatBonusCoeff: 1, +// impurityBonusCoeff: 1, +// threatOfThassarianChance: 0, - wanderingPlagueMultiplier: 1, - scourgeStrikeShadowMultiplier: 1, - } -} +// wanderingPlagueMultiplier: 1, +// scourgeStrikeShadowMultiplier: 1, +// } +// } func (dk *DeathKnight) Reset(sim *core.Simulation) { dk.LastTickTime = -1 @@ -341,103 +338,103 @@ func (dk *DeathKnight) Reset(sim *core.Simulation) { dk.MakeTSRoRAssumptions = sim.Raid.Size() <= 1 } -func (dk *DeathKnight) IsFuStrike(spell *core.Spell) bool { - return spell == dk.Obliterate || spell == dk.ScourgeStrike || spell == dk.DeathStrike -} - -func (dk *DeathKnight) HasMajorGlyph(glyph proto.DeathKnightMajorGlyph) bool { - return dk.HasGlyph(int32(glyph)) -} -func (dk *DeathKnight) HasMinorGlyph(glyph proto.DeathKnightMinorGlyph) bool { - return dk.HasGlyph(int32(glyph)) -} - -func NewDeathKnight(character *core.Character, inputs DeathKnightInputs, talents string) *DeathKnight { - dk := &DeathKnight{ - Character: *character, - Talents: &proto.DeathKnightTalents{}, - Inputs: inputs, - RoRTSBonus: func(u *core.Unit) float64 { return 1.0 }, // default to no bonus for RoR/TS - } - core.FillTalentsProto(dk.Talents.ProtoReflect(), talents, TalentTreeSizes) - - maxRunicPower := 100.0 + 15.0*float64(dk.Talents.RunicPowerMastery) - currentRunicPower := math.Min(maxRunicPower, dk.Inputs.StartingRunicPower) - - dk.EnableRunicPowerBar( - currentRunicPower, - maxRunicPower, - 10*time.Second, - func(sim *core.Simulation, changeType core.RuneChangeType) { - if dk.onRuneSpendT10 != nil { - dk.onRuneSpendT10(sim, changeType) - } - if dk.onRuneSpendBladeBarrier != nil { - dk.onRuneSpendBladeBarrier(sim, changeType) - } - }, - nil, - ) - - dk.AddStatDependency(stats.Agility, stats.MeleeCrit, core.CritPerAgiMaxLevel[character.Class]*core.CritRatingPerCritChance) - dk.AddStatDependency(stats.Agility, stats.Dodge, core.DodgeRatingPerDodgeChance/84.74576271) - dk.AddStatDependency(stats.Strength, stats.AttackPower, 2) - dk.AddStatDependency(stats.Strength, stats.Parry, 0.25) - dk.AddStatDependency(stats.BonusArmor, stats.Armor, 1) - - dk.PseudoStats.CanParry = true - - // Base dodge unaffected by Diminishing Returns - dk.PseudoStats.BaseDodge += 0.03664 - dk.PseudoStats.BaseParry += 0.05 - - dk.PseudoStats.MeleeHasteRatingPerHastePercent /= 1.3 - - if dk.Talents.SummonGargoyle { - dk.Gargoyle = dk.NewGargoyle() - } - - dk.Ghoul = dk.NewGhoulPet(dk.Talents.MasterOfGhouls) - dk.OnGargoyleStartFirstCast = func() {} - dk.GargoyleSummonDelay = time.Millisecond * 2500 - - dk.ArmyGhoul = make([]*GhoulPet, 8) - for i := 0; i < 8; i++ { - dk.ArmyGhoul[i] = dk.NewArmyGhoulPet(i) - } - - if dk.Talents.Bloodworms > 0 { - dk.Bloodworm = make([]*BloodwormPet, 4) - for i := 0; i < 4; i++ { - dk.Bloodworm[i] = dk.NewBloodwormPet(i) - } - } - - if dk.Talents.DancingRuneWeapon { - dk.RuneWeapon = dk.NewRuneWeapon() - } - - // done here so enchants that modify stats are applied before stats are calculated - dk.registerItems() - - return dk -} - -func (dk *DeathKnight) AllDiseasesAreActive(target *core.Unit) bool { - return dk.FrostFeverSpell.Dot(target).IsActive() && dk.BloodPlagueSpell.Dot(target).IsActive() -} - -func (dk *DeathKnight) DiseasesAreActive(target *core.Unit) bool { - return dk.FrostFeverSpell.Dot(target).IsActive() || dk.BloodPlagueSpell.Dot(target).IsActive() -} - -func (dk *DeathKnight) DrwDiseasesAreActive(target *core.Unit) bool { - return dk.Talents.DancingRuneWeapon && dk.RuneWeapon.FrostFeverSpell.Dot(target).IsActive() || dk.RuneWeapon.BloodPlagueSpell.Dot(target).IsActive() -} - -func (dk *DeathKnight) bonusCritMultiplier(bonusTalentPoints int32) float64 { - return dk.MeleeCritMultiplier(1, 0.15*float64(bonusTalentPoints)) -} +// func (dk *DeathKnight) IsFuStrike(spell *core.Spell) bool { +// return spell == dk.Obliterate || spell == dk.ScourgeStrike || spell == dk.DeathStrike +// } + +// func (dk *DeathKnight) HasMajorGlyph(glyph proto.DeathKnightMajorGlyph) bool { +// return dk.HasGlyph(int32(glyph)) +// } +// func (dk *DeathKnight) HasMinorGlyph(glyph proto.DeathKnightMinorGlyph) bool { +// return dk.HasGlyph(int32(glyph)) +// } + + func NewDeathKnight(character *core.Character, inputs DeathKnightInputs, talents string) *DeathKnight { + dk := &DeathKnight{ + Character: *character, + Talents: &proto.DeathKnightTalents{}, + Inputs: inputs, + RoRTSBonus: func(u *core.Unit) float64 { return 1.0 }, // default to no bonus for RoR/TS + } + core.FillTalentsProto(dk.Talents.ProtoReflect(), talents, TalentTreeSizes) + +// maxRunicPower := 100.0 + 15.0*float64(dk.Talents.RunicPowerMastery) +// currentRunicPower := math.Min(maxRunicPower, dk.Inputs.StartingRunicPower) + +// dk.EnableRunicPowerBar( +// currentRunicPower, +// maxRunicPower, +// 10*time.Second, +// func(sim *core.Simulation, changeType core.RuneChangeType) { +// if dk.onRuneSpendT10 != nil { +// dk.onRuneSpendT10(sim, changeType) +// } +// if dk.onRuneSpendBladeBarrier != nil { +// dk.onRuneSpendBladeBarrier(sim, changeType) +// } +// }, +// nil, +// ) + +// dk.AddStatDependency(stats.Agility, stats.MeleeCrit, core.CritPerAgiMaxLevel[character.Class]*core.CritRatingPerCritChance) +// dk.AddStatDependency(stats.Agility, stats.Dodge, core.DodgeRatingPerDodgeChance/84.74576271) +// dk.AddStatDependency(stats.Strength, stats.AttackPower, 2) +// dk.AddStatDependency(stats.Strength, stats.Parry, 0.25) +// dk.AddStatDependency(stats.BonusArmor, stats.Armor, 1) + +// dk.PseudoStats.CanParry = true + +// // Base dodge unaffected by Diminishing Returns +// dk.PseudoStats.BaseDodge += 0.03664 +// dk.PseudoStats.BaseParry += 0.05 + +// dk.PseudoStats.MeleeHasteRatingPerHastePercent /= 1.3 + +// if dk.Talents.SummonGargoyle { +// dk.Gargoyle = dk.NewGargoyle() +// } + +// dk.Ghoul = dk.NewGhoulPet(dk.Talents.MasterOfGhouls) +// dk.OnGargoyleStartFirstCast = func() {} +// dk.GargoyleSummonDelay = time.Millisecond * 2500 + +// dk.ArmyGhoul = make([]*GhoulPet, 8) +// for i := 0; i < 8; i++ { +// dk.ArmyGhoul[i] = dk.NewArmyGhoulPet(i) +// } + +// if dk.Talents.Bloodworms > 0 { +// dk.Bloodworm = make([]*BloodwormPet, 4) +// for i := 0; i < 4; i++ { +// dk.Bloodworm[i] = dk.NewBloodwormPet(i) +// } +// } + +// if dk.Talents.DancingRuneWeapon { +// dk.RuneWeapon = dk.NewRuneWeapon() +// } + +// // done here so enchants that modify stats are applied before stats are calculated +// dk.registerItems() + + return dk + } + +// func (dk *DeathKnight) AllDiseasesAreActive(target *core.Unit) bool { +// return dk.FrostFeverSpell.Dot(target).IsActive() && dk.BloodPlagueSpell.Dot(target).IsActive() +// } + +// func (dk *DeathKnight) DiseasesAreActive(target *core.Unit) bool { +// return dk.FrostFeverSpell.Dot(target).IsActive() || dk.BloodPlagueSpell.Dot(target).IsActive() +// } + +// func (dk *DeathKnight) DrwDiseasesAreActive(target *core.Unit) bool { +// return dk.Talents.DancingRuneWeapon && dk.RuneWeapon.FrostFeverSpell.Dot(target).IsActive() || dk.RuneWeapon.BloodPlagueSpell.Dot(target).IsActive() +// } + +// func (dk *DeathKnight) bonusCritMultiplier(bonusTalentPoints int32) float64 { +// return dk.MeleeCritMultiplier(1, 0.15*float64(bonusTalentPoints)) +// } // Agent is a generic way to access underlying warrior on any of the agents. diff --git a/sim/death_knight/frost/frost.go b/sim/death_knight/frost/frost.go index d9c59a0ca0..93d1e537c2 100644 --- a/sim/death_knight/frost/frost.go +++ b/sim/death_knight/frost/frost.go @@ -51,13 +51,13 @@ func NewFrostDeathKnight(character *core.Character, player *proto.Player) *Frost return fdk } -func (fdk *FrostDeathKnight) FrostPointsInBlood() int32 { - return fdk.Talents.Butchery + fdk.Talents.Subversion + fdk.Talents.BladeBarrier + fdk.Talents.DarkConviction -} +// func (fdk *FrostDeathKnight) FrostPointsInBlood() int32 { +// return fdk.Talents.Butchery + fdk.Talents.Subversion + fdk.Talents.BladeBarrier + fdk.Talents.DarkConviction +// } -func (fdk *FrostDeathKnight) FrostPointsInFrost() int32 { - return fdk.Talents.ViciousStrikes + fdk.Talents.Virulence + fdk.Talents.Epidemic + fdk.Talents.RavenousDead + fdk.Talents.Necrosis + fdk.Talents.BloodCakedBlade -} +// func (fdk *FrostDeathKnight) FrostPointsInFrost() int32 { +// return fdk.Talents.ViciousStrikes + fdk.Talents.Virulence + fdk.Talents.Epidemic + fdk.Talents.RavenousDead + fdk.Talents.Necrosis + fdk.Talents.BloodCakedBlade +// } func (fdk *FrostDeathKnight) GetDeathKnight() *death_knight.DeathKnight { return fdk.DeathKnight @@ -69,5 +69,5 @@ func (fdk *FrostDeathKnight) Initialize() { func (fdk *FrostDeathKnight) Reset(sim *core.Simulation) { fdk.DeathKnight.Reset(sim) - fdk.Presence = death_knight.UnsetPresence + //fdk.Presence = death_knight.UnsetPresence } diff --git a/sim/death_knight/unholy/unholy.go b/sim/death_knight/unholy/unholy.go index 94f67f8b4f..7246744260 100644 --- a/sim/death_knight/unholy/unholy.go +++ b/sim/death_knight/unholy/unholy.go @@ -53,13 +53,13 @@ func NewUnholyDeathKnight(character *core.Character, player *proto.Player) *Unho return uhdk } -func (uhdk *UnholyDeathKnight) FrostPointsInBlood() int32 { - return uhdk.Talents.Butchery + uhdk.Talents.Subversion + uhdk.Talents.BladeBarrier + uhdk.Talents.DarkConviction -} +// func (uhdk *UnholyDeathKnight) FrostPointsInBlood() int32 { +// return uhdk.Talents.Butchery + uhdk.Talents.Subversion + uhdk.Talents.BladeBarrier + uhdk.Talents.DarkConviction +// } -func (uhdk *UnholyDeathKnight) FrostPointsInUnholy() int32 { - return uhdk.Talents.ViciousStrikes + uhdk.Talents.Virulence + uhdk.Talents.Epidemic + uhdk.Talents.RavenousDead + uhdk.Talents.Necrosis + uhdk.Talents.BloodCakedBlade -} +// func (uhdk *UnholyDeathKnight) FrostPointsInUnholy() int32 { +// return uhdk.Talents.ViciousStrikes + uhdk.Talents.Virulence + uhdk.Talents.Epidemic + uhdk.Talents.RavenousDead + uhdk.Talents.Necrosis + uhdk.Talents.BloodCakedBlade +// } func (uhdk *UnholyDeathKnight) GetDeathKnight() *death_knight.DeathKnight { return uhdk.DeathKnight @@ -71,5 +71,5 @@ func (uhdk *UnholyDeathKnight) Initialize() { func (uhdk *UnholyDeathKnight) Reset(sim *core.Simulation) { uhdk.DeathKnight.Reset(sim) - uhdk.Presence = death_knight.UnsetPresence + //uhdk.Presence = death_knight.UnsetPresence } diff --git a/sim/druid/barkskin.go b/sim/druid/_barkskin.go similarity index 100% rename from sim/druid/barkskin.go rename to sim/druid/_barkskin.go diff --git a/sim/druid/berserk.go b/sim/druid/_berserk.go similarity index 100% rename from sim/druid/berserk.go rename to sim/druid/_berserk.go diff --git a/sim/druid/demoralizing_roar.go b/sim/druid/_demoralizing_roar.go similarity index 100% rename from sim/druid/demoralizing_roar.go rename to sim/druid/_demoralizing_roar.go diff --git a/sim/druid/enrage.go b/sim/druid/_enrage.go similarity index 100% rename from sim/druid/enrage.go rename to sim/druid/_enrage.go diff --git a/sim/druid/faerie_fire.go b/sim/druid/_faerie_fire.go similarity index 100% rename from sim/druid/faerie_fire.go rename to sim/druid/_faerie_fire.go diff --git a/sim/druid/fake_gotw.go b/sim/druid/_fake_gotw.go similarity index 100% rename from sim/druid/fake_gotw.go rename to sim/druid/_fake_gotw.go diff --git a/sim/druid/feral/TestFeral.results b/sim/druid/_feral/TestFeral.results similarity index 100% rename from sim/druid/feral/TestFeral.results rename to sim/druid/_feral/TestFeral.results diff --git a/sim/druid/feral/TestFeralApl.results b/sim/druid/_feral/TestFeralApl.results similarity index 100% rename from sim/druid/feral/TestFeralApl.results rename to sim/druid/_feral/TestFeralApl.results diff --git a/sim/druid/feral/apl_values.go b/sim/druid/_feral/apl_values.go similarity index 100% rename from sim/druid/feral/apl_values.go rename to sim/druid/_feral/apl_values.go diff --git a/sim/druid/feral/feral.go b/sim/druid/_feral/feral.go similarity index 66% rename from sim/druid/feral/feral.go rename to sim/druid/_feral/feral.go index 00440050c1..2b6e4c747e 100644 --- a/sim/druid/feral/feral.go +++ b/sim/druid/_feral/feral.go @@ -34,26 +34,26 @@ func NewFeralDruid(character *core.Character, options *proto.Player) *FeralDruid latency: time.Duration(max(feralOptions.Options.LatencyMs, 1)) * time.Millisecond, } - cat.SelfBuffs.InnervateTarget = &proto.UnitReference{} - if feralOptions.Options.ClassOptions.InnervateTarget != nil { - cat.SelfBuffs.InnervateTarget = feralOptions.Options.ClassOptions.InnervateTarget - } + // cat.SelfBuffs.InnervateTarget = &proto.UnitReference{} + // if feralOptions.Options.ClassOptions.InnervateTarget != nil { + // cat.SelfBuffs.InnervateTarget = feralOptions.Options.ClassOptions.InnervateTarget + // } - cat.AssumeBleedActive = feralOptions.Options.AssumeBleedActive - cat.maxRipTicks = cat.MaxRipTicks() + // cat.AssumeBleedActive = feralOptions.Options.AssumeBleedActive + // //cat.maxRipTicks = cat.MaxRipTicks() - cat.EnableEnergyBar(100.0) + // cat.EnableEnergyBar(100.0) - cat.EnableRageBar(core.RageBarOptions{RageMultiplier: 1, MHSwingSpeed: 2.5}) + // cat.EnableRageBar(core.RageBarOptions{RageMultiplier: 1, MHSwingSpeed: 2.5}) - cat.EnableAutoAttacks(cat, core.AutoAttackOptions{ - // Base paw weapon. - MainHand: cat.GetCatWeapon(), - AutoSwingMelee: true, - }) - cat.ReplaceBearMHFunc = func(sim *core.Simulation, mhSwingSpell *core.Spell) *core.Spell { - return cat.checkReplaceMaul(sim, mhSwingSpell) - } + // cat.EnableAutoAttacks(cat, core.AutoAttackOptions{ + // // Base paw weapon. + // //MainHand: cat.GetCatWeapon(), + // AutoSwingMelee: true, + // }) + // cat.ReplaceBearMHFunc = func(sim *core.Simulation, mhSwingSpell *core.Spell) *core.Spell { + // return cat.checkReplaceMaul(sim, mhSwingSpell) + // } return cat } @@ -92,15 +92,15 @@ func (cat *FeralDruid) MissChance() float64 { func (cat *FeralDruid) Initialize() { cat.Druid.Initialize() - cat.RegisterFeralCatSpells() + //cat.RegisterFeralCatSpells() } func (cat *FeralDruid) Reset(sim *core.Simulation) { cat.Druid.Reset(sim) - cat.Druid.ClearForm(sim) - cat.CatFormAura.Activate(sim) - cat.readyToShift = false - cat.waitingForTick = false - cat.berserkUsed = false - cat.rotationAction = nil + // cat.Druid.ClearForm(sim) + // cat.CatFormAura.Activate(sim) + // cat.readyToShift = false + // cat.waitingForTick = false + // cat.berserkUsed = false + // cat.rotationAction = nil } diff --git a/sim/druid/feral/feral_test.go b/sim/druid/_feral/feral_test.go similarity index 100% rename from sim/druid/feral/feral_test.go rename to sim/druid/_feral/feral_test.go diff --git a/sim/druid/feral/pooling_actions.go b/sim/druid/_feral/pooling_actions.go similarity index 100% rename from sim/druid/feral/pooling_actions.go rename to sim/druid/_feral/pooling_actions.go diff --git a/sim/druid/feral/rotation.go b/sim/druid/_feral/rotation.go similarity index 100% rename from sim/druid/feral/rotation.go rename to sim/druid/_feral/rotation.go diff --git a/sim/druid/feral/rotation_aoe.go b/sim/druid/_feral/rotation_aoe.go similarity index 100% rename from sim/druid/feral/rotation_aoe.go rename to sim/druid/_feral/rotation_aoe.go diff --git a/sim/druid/ferocious_bite.go b/sim/druid/_ferocious_bite.go similarity index 100% rename from sim/druid/ferocious_bite.go rename to sim/druid/_ferocious_bite.go diff --git a/sim/druid/force_of_nature.go b/sim/druid/_force_of_nature.go similarity index 100% rename from sim/druid/force_of_nature.go rename to sim/druid/_force_of_nature.go diff --git a/sim/druid/frenzied_regeneration.go b/sim/druid/_frenzied_regeneration.go similarity index 100% rename from sim/druid/frenzied_regeneration.go rename to sim/druid/_frenzied_regeneration.go diff --git a/sim/druid/hurricane.go b/sim/druid/_hurricane.go similarity index 100% rename from sim/druid/hurricane.go rename to sim/druid/_hurricane.go diff --git a/sim/druid/innervate.go b/sim/druid/_innervate.go similarity index 100% rename from sim/druid/innervate.go rename to sim/druid/_innervate.go diff --git a/sim/druid/insect_swarm.go b/sim/druid/_insect_swarm.go similarity index 100% rename from sim/druid/insect_swarm.go rename to sim/druid/_insect_swarm.go diff --git a/sim/druid/items.go b/sim/druid/_items.go similarity index 100% rename from sim/druid/items.go rename to sim/druid/_items.go diff --git a/sim/druid/lacerate.go b/sim/druid/_lacerate.go similarity index 100% rename from sim/druid/lacerate.go rename to sim/druid/_lacerate.go diff --git a/sim/druid/mangle.go b/sim/druid/_mangle.go similarity index 100% rename from sim/druid/mangle.go rename to sim/druid/_mangle.go diff --git a/sim/druid/maul.go b/sim/druid/_maul.go similarity index 100% rename from sim/druid/maul.go rename to sim/druid/_maul.go diff --git a/sim/druid/moonfire.go b/sim/druid/_moonfire.go similarity index 100% rename from sim/druid/moonfire.go rename to sim/druid/_moonfire.go diff --git a/sim/druid/rake.go b/sim/druid/_rake.go similarity index 100% rename from sim/druid/rake.go rename to sim/druid/_rake.go diff --git a/sim/druid/rebirth.go b/sim/druid/_rebirth.go similarity index 100% rename from sim/druid/rebirth.go rename to sim/druid/_rebirth.go diff --git a/sim/druid/rip.go b/sim/druid/_rip.go similarity index 100% rename from sim/druid/rip.go rename to sim/druid/_rip.go diff --git a/sim/druid/savage_defense.go b/sim/druid/_savage_defense.go similarity index 100% rename from sim/druid/savage_defense.go rename to sim/druid/_savage_defense.go diff --git a/sim/druid/savage_roar.go b/sim/druid/_savage_roar.go similarity index 100% rename from sim/druid/savage_roar.go rename to sim/druid/_savage_roar.go diff --git a/sim/druid/shred.go b/sim/druid/_shred.go similarity index 100% rename from sim/druid/shred.go rename to sim/druid/_shred.go diff --git a/sim/druid/starfall.go b/sim/druid/_starfall.go similarity index 100% rename from sim/druid/starfall.go rename to sim/druid/_starfall.go diff --git a/sim/druid/starfire.go b/sim/druid/_starfire.go similarity index 100% rename from sim/druid/starfire.go rename to sim/druid/_starfire.go diff --git a/sim/druid/survival_instincts.go b/sim/druid/_survival_instincts.go similarity index 100% rename from sim/druid/survival_instincts.go rename to sim/druid/_survival_instincts.go diff --git a/sim/druid/swipe.go b/sim/druid/_swipe.go similarity index 100% rename from sim/druid/swipe.go rename to sim/druid/_swipe.go diff --git a/sim/druid/tigers_fury.go b/sim/druid/_tigers_fury.go similarity index 100% rename from sim/druid/tigers_fury.go rename to sim/druid/_tigers_fury.go diff --git a/sim/druid/typhoon.go b/sim/druid/_typhoon.go similarity index 100% rename from sim/druid/typhoon.go rename to sim/druid/_typhoon.go diff --git a/sim/druid/wrath.go b/sim/druid/_wrath.go similarity index 100% rename from sim/druid/wrath.go rename to sim/druid/_wrath.go diff --git a/sim/druid/balance/balance.go b/sim/druid/balance/balance.go index 8e5b75d956..c095897ed4 100644 --- a/sim/druid/balance/balance.go +++ b/sim/druid/balance/balance.go @@ -1,8 +1,6 @@ package balance import ( - "time" - "github.com/wowsims/cata/sim/core" "github.com/wowsims/cata/sim/core/proto" "github.com/wowsims/cata/sim/core/stats" @@ -60,16 +58,16 @@ func (moonkin *BalanceDruid) GetDruid() *druid.Druid { func (moonkin *BalanceDruid) Initialize() { moonkin.Druid.Initialize() - moonkin.RegisterBalanceSpells() + //moonkin.RegisterBalanceSpells() - if moonkin.OwlkinFrenzyAura != nil && moonkin.Options.OkfUptime > 0 { - moonkin.Env.RegisterPreFinalizeEffect(func() { - core.ApplyFixedUptimeAura(moonkin.OwlkinFrenzyAura, float64(moonkin.Options.OkfUptime), time.Second*5, 0) - }) - } + // if moonkin.OwlkinFrenzyAura != nil && moonkin.Options.OkfUptime > 0 { + // moonkin.Env.RegisterPreFinalizeEffect(func() { + // core.ApplyFixedUptimeAura(moonkin.OwlkinFrenzyAura, float64(moonkin.Options.OkfUptime), time.Second*5, 0) + // }) + // } } func (moonkin *BalanceDruid) Reset(sim *core.Simulation) { moonkin.Druid.Reset(sim) - moonkin.RebirthTiming = moonkin.Env.BaseDuration.Seconds() * sim.RandomFloat("Rebirth Timing") + //moonkin.RebirthTiming = moonkin.Env.BaseDuration.Seconds() * sim.RandomFloat("Rebirth Timing") } diff --git a/sim/druid/druid.go b/sim/druid/druid.go index 04a44f82a2..45dc7cf450 100644 --- a/sim/druid/druid.go +++ b/sim/druid/druid.go @@ -5,7 +5,6 @@ import ( "github.com/wowsims/cata/sim/core" "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" ) const ( @@ -20,7 +19,7 @@ type Druid struct { SelfBuffs Talents *proto.DruidTalents - StartingForm DruidForm + // StartingForm DruidForm RebirthUsed bool RebirthTiming float64 @@ -97,11 +96,11 @@ type Druid struct { ExtendingMoonfireStacks int LunarICD core.Cooldown SolarICD core.Cooldown - Treant1 *TreantPet - Treant2 *TreantPet - Treant3 *TreantPet + // Treant1 *TreantPet + // Treant2 *TreantPet + // Treant3 *TreantPet - form DruidForm + // form DruidForm disabledMCDs []*core.MajorCooldown } @@ -114,43 +113,43 @@ func (druid *Druid) GetCharacter() *core.Character { } func (druid *Druid) AddRaidBuffs(raidBuffs *proto.RaidBuffs) { - raidBuffs.GiftOfTheWild = max(raidBuffs.GiftOfTheWild, proto.TristateEffect_TristateEffectRegular) - if druid.Talents.ImprovedMarkOfTheWild == 2 { // probably could work on actually calculating the fraction effect later if we care. - raidBuffs.GiftOfTheWild = proto.TristateEffect_TristateEffectImproved - } - - raidBuffs.Thorns = max(raidBuffs.Thorns, proto.TristateEffect_TristateEffectRegular) - if druid.Talents.Brambles == 3 { - raidBuffs.Thorns = proto.TristateEffect_TristateEffectImproved - } - - if druid.InForm(Moonkin) && druid.Talents.MoonkinForm { - raidBuffs.MoonkinAura = max(raidBuffs.MoonkinAura, proto.TristateEffect_TristateEffectRegular) - if druid.Talents.ImprovedMoonkinForm > 0 { - // For now, we assume Improved Moonkin Form is maxed-out - raidBuffs.MoonkinAura = proto.TristateEffect_TristateEffectImproved - } - } - if druid.InForm(Cat|Bear) && druid.Talents.LeaderOfThePack { - raidBuffs.LeaderOfThePack = max(raidBuffs.LeaderOfThePack, proto.TristateEffect_TristateEffectRegular) - if druid.Talents.ImprovedLeaderOfThePack > 0 { - raidBuffs.LeaderOfThePack = proto.TristateEffect_TristateEffectImproved - } - } + // raidBuffs.GiftOfTheWild = max(raidBuffs.GiftOfTheWild, proto.TristateEffect_TristateEffectRegular) + // if druid.Talents.ImprovedMarkOfTheWild == 2 { // probably could work on actually calculating the fraction effect later if we care. + // raidBuffs.GiftOfTheWild = proto.TristateEffect_TristateEffectImproved + // } + + // raidBuffs.Thorns = max(raidBuffs.Thorns, proto.TristateEffect_TristateEffectRegular) + // if druid.Talents.Brambles == 3 { + // raidBuffs.Thorns = proto.TristateEffect_TristateEffectImproved + // } + + // if druid.InForm(Moonkin) && druid.Talents.MoonkinForm { + // raidBuffs.MoonkinAura = max(raidBuffs.MoonkinAura, proto.TristateEffect_TristateEffectRegular) + // if druid.Talents.ImprovedMoonkinForm > 0 { + // // For now, we assume Improved Moonkin Form is maxed-out + // raidBuffs.MoonkinAura = proto.TristateEffect_TristateEffectImproved + // } + // } + // if druid.InForm(Cat|Bear) && druid.Talents.LeaderOfThePack { + // raidBuffs.LeaderOfThePack = max(raidBuffs.LeaderOfThePack, proto.TristateEffect_TristateEffectRegular) + // if druid.Talents.ImprovedLeaderOfThePack > 0 { + // raidBuffs.LeaderOfThePack = proto.TristateEffect_TristateEffectImproved + // } + // } } -func (druid *Druid) BalanceCritMultiplier() float64 { - return druid.SpellCritMultiplier(1, 0.2*float64(druid.Talents.Vengeance)) -} +// func (druid *Druid) BalanceCritMultiplier() float64 { +// return druid.SpellCritMultiplier(1, 0.2*float64(druid.Talents.Vengeance)) +// } -func (druid *Druid) MeleeCritMultiplier(castedForm DruidForm) float64 { - // Assumes that Predatory Instincts is a primary rather than secondary modifier for now, but this needs to confirmed! - primaryModifier := 1.0 - if castedForm.Matches(Cat) { - primaryModifier = []float64{1, 1.03, 1.07, 1.10}[druid.Talents.PredatoryInstincts] - } - return druid.Character.MeleeCritMultiplier(primaryModifier, 0) -} +// func (druid *Druid) MeleeCritMultiplier(castedForm DruidForm) float64 { +// // Assumes that Predatory Instincts is a primary rather than secondary modifier for now, but this needs to confirmed! +// primaryModifier := 1.0 +// if castedForm.Matches(Cat) { +// primaryModifier = []float64{1, 1.03, 1.07, 1.10}[druid.Talents.PredatoryInstincts] +// } +// return druid.Character.MeleeCritMultiplier(primaryModifier, 0) +// } func (druid *Druid) HasMajorGlyph(glyph proto.DruidMajorGlyph) bool { return druid.HasGlyph(int32(glyph)) @@ -159,165 +158,165 @@ func (druid *Druid) HasMinorGlyph(glyph proto.DruidMinorGlyph) bool { return druid.HasGlyph(int32(glyph)) } -func (druid *Druid) TryMaul(sim *core.Simulation, mhSwingSpell *core.Spell) *core.Spell { - return druid.MaulReplaceMH(sim, mhSwingSpell) -} - -func (druid *Druid) RegisterSpell(formMask DruidForm, config core.SpellConfig) *DruidSpell { - prev := config.ExtraCastCondition - prevModify := config.Cast.ModifyCast - - ds := &DruidSpell{FormMask: formMask} - config.ExtraCastCondition = func(sim *core.Simulation, target *core.Unit) bool { - // Check if we're in allowed form to cast - // Allow 'humanoid' auto unshift casts - if (ds.FormMask != Any && !druid.InForm(ds.FormMask)) && !ds.FormMask.Matches(Humanoid) { - if sim.Log != nil { - sim.Log("Failed cast to spell %s, wrong form", ds.ActionID) - } - return false - } - return prev == nil || prev(sim, target) - } - config.Cast.ModifyCast = func(sim *core.Simulation, s *core.Spell, c *core.Cast) { - if !druid.InForm(ds.FormMask) && ds.FormMask.Matches(Humanoid) { - druid.ClearForm(sim) - } - if prevModify != nil { - prevModify(sim, s, c) - } - } - - ds.Spell = druid.Unit.RegisterSpell(config) - - return ds -} +// func (druid *Druid) TryMaul(sim *core.Simulation, mhSwingSpell *core.Spell) *core.Spell { +// return druid.MaulReplaceMH(sim, mhSwingSpell) +// } + +// func (druid *Druid) RegisterSpell(formMask DruidForm, config core.SpellConfig) *DruidSpell { +// prev := config.ExtraCastCondition +// prevModify := config.Cast.ModifyCast + +// ds := &DruidSpell{FormMask: formMask} +// config.ExtraCastCondition = func(sim *core.Simulation, target *core.Unit) bool { +// // Check if we're in allowed form to cast +// // Allow 'humanoid' auto unshift casts +// if (ds.FormMask != Any && !druid.InForm(ds.FormMask)) && !ds.FormMask.Matches(Humanoid) { +// if sim.Log != nil { +// sim.Log("Failed cast to spell %s, wrong form", ds.ActionID) +// } +// return false +// } +// return prev == nil || prev(sim, target) +// } +// config.Cast.ModifyCast = func(sim *core.Simulation, s *core.Spell, c *core.Cast) { +// if !druid.InForm(ds.FormMask) && ds.FormMask.Matches(Humanoid) { +// druid.ClearForm(sim) +// } +// if prevModify != nil { +// prevModify(sim, s, c) +// } +// } + +// ds.Spell = druid.Unit.RegisterSpell(config) + +// return ds +// } func (druid *Druid) Initialize() { - druid.BleedCategories = druid.GetEnemyExclusiveCategories(core.BleedEffectCategory) - - if druid.Talents.PrimalPrecision > 0 { - druid.PrimalPrecisionRecoveryMetrics = druid.NewEnergyMetrics(core.ActionID{SpellID: 48410}) - } - druid.registerFaerieFireSpell() - druid.registerRebirthSpell() - druid.registerInnervateCD() - druid.registerFakeGotw() -} - -func (druid *Druid) RegisterBalanceSpells() { - druid.registerHurricaneSpell() - druid.registerInsectSwarmSpell() - druid.registerMoonfireSpell() - druid.registerStarfireSpell() - druid.registerWrathSpell() - druid.registerStarfallSpell() - druid.registerTyphoonSpell() - druid.registerForceOfNatureCD() + // druid.BleedCategories = druid.GetEnemyExclusiveCategories(core.BleedEffectCategory) + + // if druid.Talents.PrimalPrecision > 0 { + // druid.PrimalPrecisionRecoveryMetrics = druid.NewEnergyMetrics(core.ActionID{SpellID: 48410}) + // } + // druid.registerFaerieFireSpell() + // druid.registerRebirthSpell() + // druid.registerInnervateCD() + // druid.registerFakeGotw() } -func (druid *Druid) RegisterFeralCatSpells() { - druid.registerBerserkCD() - druid.registerCatFormSpell() - druid.registerBearFormSpell() - druid.registerEnrageSpell() - druid.registerFerociousBiteSpell() - druid.registerMangleBearSpell() - druid.registerMangleCatSpell() - druid.registerMaulSpell() - druid.registerLacerateSpell() - druid.registerRakeSpell() - druid.registerRipSpell() - druid.registerSavageRoarSpell() - druid.registerShredSpell() - druid.registerSwipeBearSpell() - druid.registerSwipeCatSpell() - druid.registerTigersFurySpell() -} - -func (druid *Druid) RegisterFeralTankSpells() { - druid.registerBarkskinCD() - druid.registerBerserkCD() - druid.registerBearFormSpell() - druid.registerDemoralizingRoarSpell() - druid.registerEnrageSpell() - druid.registerFrenziedRegenerationCD() - druid.registerMangleBearSpell() - druid.registerMaulSpell() - druid.registerLacerateSpell() - druid.registerRakeSpell() - druid.registerRipSpell() - druid.registerSavageDefensePassive() - druid.registerSurvivalInstinctsCD() - druid.registerSwipeBearSpell() -} +// func (druid *Druid) RegisterBalanceSpells() { +// druid.registerHurricaneSpell() +// druid.registerInsectSwarmSpell() +// druid.registerMoonfireSpell() +// druid.registerStarfireSpell() +// druid.registerWrathSpell() +// druid.registerStarfallSpell() +// druid.registerTyphoonSpell() +// druid.registerForceOfNatureCD() +// } + +// func (druid *Druid) RegisterFeralCatSpells() { +// druid.registerBerserkCD() +// druid.registerCatFormSpell() +// druid.registerBearFormSpell() +// druid.registerEnrageSpell() +// druid.registerFerociousBiteSpell() +// druid.registerMangleBearSpell() +// druid.registerMangleCatSpell() +// druid.registerMaulSpell() +// druid.registerLacerateSpell() +// druid.registerRakeSpell() +// druid.registerRipSpell() +// druid.registerSavageRoarSpell() +// druid.registerShredSpell() +// druid.registerSwipeBearSpell() +// druid.registerSwipeCatSpell() +// druid.registerTigersFurySpell() +// } + +// func (druid *Druid) RegisterFeralTankSpells() { +// druid.registerBarkskinCD() +// druid.registerBerserkCD() +// druid.registerBearFormSpell() +// druid.registerDemoralizingRoarSpell() +// druid.registerEnrageSpell() +// druid.registerFrenziedRegenerationCD() +// druid.registerMangleBearSpell() +// druid.registerMaulSpell() +// druid.registerLacerateSpell() +// druid.registerRakeSpell() +// druid.registerRipSpell() +// druid.registerSavageDefensePassive() +// druid.registerSurvivalInstinctsCD() +// druid.registerSwipeBearSpell() +// } func (druid *Druid) Reset(_ *core.Simulation) { - druid.BleedsActive = 0 - druid.form = druid.StartingForm - druid.disabledMCDs = []*core.MajorCooldown{} - druid.RebirthUsed = false - druid.LunarICD.Timer.Reset() - druid.SolarICD.Timer.Reset() + // druid.BleedsActive = 0 + // druid.form = druid.StartingForm + // druid.disabledMCDs = []*core.MajorCooldown{} + // druid.RebirthUsed = false + // druid.LunarICD.Timer.Reset() + // druid.SolarICD.Timer.Reset() } -func New(char *core.Character, form DruidForm, selfBuffs SelfBuffs, talents string) *Druid { - druid := &Druid{ - Character: *char, - SelfBuffs: selfBuffs, - Talents: &proto.DruidTalents{}, - StartingForm: form, - form: form, - } - core.FillTalentsProto(druid.Talents.ProtoReflect(), talents, TalentTreeSizes) - druid.EnableManaBar() - - druid.AddStatDependency(stats.Strength, stats.AttackPower, 2) - druid.AddStatDependency(stats.BonusArmor, stats.Armor, 1) - druid.AddStatDependency(stats.Agility, stats.MeleeCrit, core.CritPerAgiMaxLevel[char.Class]*core.CritRatingPerCritChance) - // Druid get 0.0209 dodge per agi (before dr), roughly 1 per 47.846 - druid.AddStatDependency(stats.Agility, stats.Dodge, (0.0209)*core.DodgeRatingPerDodgeChance) - - // Druids get extra melee haste - druid.PseudoStats.MeleeHasteRatingPerHastePercent /= 1.3 - - // Base dodge is unaffected by Diminishing Returns - druid.PseudoStats.BaseDodge += 0.056097 - - if druid.Talents.ForceOfNature { - druid.Treant1 = druid.NewTreant() - druid.Treant2 = druid.NewTreant() - druid.Treant3 = druid.NewTreant() - } + func New(char *core.Character, form DruidForm, selfBuffs SelfBuffs, talents string) *Druid { + druid := &Druid{ + Character: *char, + SelfBuffs: selfBuffs, + Talents: &proto.DruidTalents{}, + //StartingForm: form, + //form: form, + } +// core.FillTalentsProto(druid.Talents.ProtoReflect(), talents, TalentTreeSizes) +// // druid.EnableManaBar() + +// // druid.AddStatDependency(stats.Strength, stats.AttackPower, 2) +// // druid.AddStatDependency(stats.BonusArmor, stats.Armor, 1) +// // druid.AddStatDependency(stats.Agility, stats.MeleeCrit, core.CritPerAgiMaxLevel[char.Class]*core.CritRatingPerCritChance) +// // // Druid get 0.0209 dodge per agi (before dr), roughly 1 per 47.846 +// // druid.AddStatDependency(stats.Agility, stats.Dodge, (0.0209)*core.DodgeRatingPerDodgeChance) + +// // // Druids get extra melee haste +// // druid.PseudoStats.MeleeHasteRatingPerHastePercent /= 1.3 + +// // // Base dodge is unaffected by Diminishing Returns +// // druid.PseudoStats.BaseDodge += 0.056097 + +// // if druid.Talents.ForceOfNature { +// // druid.Treant1 = druid.NewTreant() +// // druid.Treant2 = druid.NewTreant() +// // druid.Treant3 = druid.NewTreant() +// // } return druid } type DruidSpell struct { *core.Spell - FormMask DruidForm -} - -func (ds *DruidSpell) IsReady(sim *core.Simulation) bool { - if ds == nil { - return false - } - return ds.Spell.IsReady(sim) + //FormMask DruidForm } -func (ds *DruidSpell) CanCast(sim *core.Simulation, target *core.Unit) bool { - if ds == nil { - return false - } - return ds.Spell.CanCast(sim, target) -} - -func (ds *DruidSpell) IsEqual(s *core.Spell) bool { - if ds == nil || s == nil { - return false - } - return ds.Spell == s -} +// func (ds *DruidSpell) IsReady(sim *core.Simulation) bool { +// if ds == nil { +// return false +// } +// return ds.Spell.IsReady(sim) +// } + +// func (ds *DruidSpell) CanCast(sim *core.Simulation, target *core.Unit) bool { +// if ds == nil { +// return false +// } +// return ds.Spell.CanCast(sim, target) +// } + +// func (ds *DruidSpell) IsEqual(s *core.Spell) bool { +// if ds == nil || s == nil { +// return false +// } +// return ds.Spell == s +// } // Agent is a generic way to access underlying druid on any of the agents (for example balance druid.) type DruidAgent interface { diff --git a/sim/druid/forms.go b/sim/druid/forms.go index ad36d90ae9..9f6964b8b3 100644 --- a/sim/druid/forms.go +++ b/sim/druid/forms.go @@ -1,419 +1,419 @@ package druid -import ( - "math" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" -) - -type DruidForm uint8 - -const ( - Humanoid DruidForm = 1 << iota - Bear - Cat - Moonkin - Tree - Any = Humanoid | Bear | Cat | Moonkin | Tree -) - -// Converts from 0.009327 to 0.0085 -const AnimalSpiritRegenSuppression = 0.911337 - -func (form DruidForm) Matches(other DruidForm) bool { - return (form & other) != 0 -} - -func (druid *Druid) GetForm() DruidForm { - return druid.form -} - -func (druid *Druid) InForm(form DruidForm) bool { - return druid.form.Matches(form) -} - -func (druid *Druid) ClearForm(sim *core.Simulation) { - if druid.InForm(Cat) { - druid.CatFormAura.Deactivate(sim) - } else if druid.InForm(Bear) { - druid.BearFormAura.Deactivate(sim) - } else if druid.InForm(Moonkin) { - panic("cant clear moonkin form") - } - druid.form = Humanoid - druid.SetCurrentPowerBar(core.ManaBar) -} - -func (druid *Druid) GetCatWeapon() core.Weapon { - return core.Weapon{ - BaseDamageMin: 43, - BaseDamageMax: 66, - SwingSpeed: 1.0, - NormalizedSwingSpeed: 1.0, - CritMultiplier: druid.MeleeCritMultiplier(Cat), - AttackPowerPerDPS: core.DefaultAttackPowerPerDPS, - } -} - -func (druid *Druid) GetBearWeapon() core.Weapon { - return core.Weapon{ - BaseDamageMin: 109, - BaseDamageMax: 165, - SwingSpeed: 2.5, - NormalizedSwingSpeed: 2.5, - CritMultiplier: druid.MeleeCritMultiplier(Bear), - AttackPowerPerDPS: core.DefaultAttackPowerPerDPS, - } -} - -// Bonus stats for both cat and bear. -func (druid *Druid) GetFormShiftStats() stats.Stats { - s := stats.Stats{ - stats.AttackPower: float64(druid.Talents.PredatoryStrikes) * 0.5 * float64(druid.Level), - stats.MeleeCrit: float64(druid.Talents.SharpenedClaws) * 2 * core.CritRatingPerCritChance, - } - - if weapon := druid.GetMHWeapon(); weapon != nil { - dps := (weapon.WeaponDamageMax+weapon.WeaponDamageMin)/2.0/weapon.SwingSpeed + druid.PseudoStats.BonusMHDps - weapAp := weapon.Stats[stats.AttackPower] + weapon.Enchant.Stats[stats.AttackPower] - fap := math.Floor((dps - 54.8) * 14) - - s[stats.AttackPower] += fap - s[stats.AttackPower] += (fap + weapAp) * ((0.2 / 3) * float64(druid.Talents.PredatoryStrikes)) - } - - return s -} - -func (druid *Druid) GetDynamicPredStrikeStats() stats.Stats { - // Accounts for ap bonus for 'dynamic' enchants - // just scourgebane currently, this is a bit hacky but is needed as the bonus varies based on current target - // so has to be 'cached' differently - s := stats.Stats{} - if weapon := druid.GetMHWeapon(); weapon != nil { - bonusAp := 0.0 - if weapon.Enchant.EffectID == 3247 && druid.CurrentTarget.MobType == proto.MobType_MobTypeUndead { - bonusAp += 140 - } - s[stats.AttackPower] += bonusAp * ((0.2 / 3) * float64(druid.Talents.PredatoryStrikes)) - } - return s -} - -func (druid *Druid) registerCatFormSpell() { - actionID := core.ActionID{SpellID: 768} - - srm := druid.getSavageRoarMultiplier() - - statBonus := druid.GetFormShiftStats().Add(stats.Stats{ - stats.AttackPower: float64(druid.Level) * 2, - stats.MeleeCrit: 2 * float64(druid.Talents.MasterShapeshifter) * core.CritRatingPerCritChance, - }) - - agiApDep := druid.NewDynamicStatDependency(stats.Agility, stats.AttackPower, 1) - - var hotwDep *stats.StatDependency - if druid.Talents.HeartOfTheWild > 0 { - hotwDep = druid.NewDynamicMultiplyStat(stats.AttackPower, 1.0+0.02*float64(druid.Talents.HeartOfTheWild)) - } - - clawWeapon := druid.GetCatWeapon() - - predBonus := stats.Stats{} - - druid.CatFormAura = druid.RegisterAura(core.Aura{ - Label: "Cat Form", - ActionID: actionID, - Duration: core.NeverExpires, - BuildPhase: core.Ternary(druid.StartingForm.Matches(Cat), core.CharacterBuildPhaseBase, core.CharacterBuildPhaseNone), - OnGain: func(aura *core.Aura, sim *core.Simulation) { - if !druid.Env.MeasuringStats && druid.form != Humanoid { - druid.ClearForm(sim) - } - druid.form = Cat - druid.SetCurrentPowerBar(core.EnergyBar) - - druid.AutoAttacks.SetMH(clawWeapon) - - druid.PseudoStats.ThreatMultiplier *= 0.71 - druid.PseudoStats.SpiritRegenMultiplier *= AnimalSpiritRegenSuppression - druid.PseudoStats.BaseDodge += 0.02 * float64(druid.Talents.FeralSwiftness) - - predBonus = druid.GetDynamicPredStrikeStats() - druid.AddStatsDynamic(sim, predBonus) - druid.AddStatsDynamic(sim, statBonus) - druid.EnableDynamicStatDep(sim, agiApDep) - if hotwDep != nil { - druid.EnableDynamicStatDep(sim, hotwDep) - } - - if !druid.Env.MeasuringStats { - druid.AutoAttacks.SetReplaceMHSwing(nil) - druid.AutoAttacks.EnableAutoSwing(sim) - druid.manageCooldownsEnabled() - druid.UpdateManaRegenRates() - - // These buffs stay up, but corresponding changes don't - if druid.SavageRoarAura.IsActive() { - druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= srm - } - - if druid.PredatoryInstinctsAura != nil { - druid.PredatoryInstinctsAura.Activate(sim) - } - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - druid.form = Humanoid - - druid.AutoAttacks.SetMH(druid.WeaponFromMainHand(druid.MeleeCritMultiplier(Humanoid))) - - druid.PseudoStats.ThreatMultiplier /= 0.71 - druid.PseudoStats.SpiritRegenMultiplier /= AnimalSpiritRegenSuppression - druid.PseudoStats.BaseDodge -= 0.02 * float64(druid.Talents.FeralSwiftness) - - druid.AddStatsDynamic(sim, predBonus.Invert()) - druid.AddStatsDynamic(sim, statBonus.Invert()) - druid.DisableDynamicStatDep(sim, agiApDep) - if hotwDep != nil { - druid.DisableDynamicStatDep(sim, hotwDep) - } - - if !druid.Env.MeasuringStats { - druid.AutoAttacks.SetReplaceMHSwing(nil) - druid.AutoAttacks.EnableAutoSwing(sim) - druid.manageCooldownsEnabled() - druid.UpdateManaRegenRates() - - druid.TigersFuryAura.Deactivate(sim) - - // These buffs stay up, but corresponding changes don't - if druid.SavageRoarAura.IsActive() { - druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= srm - } - - if druid.PredatoryInstinctsAura != nil { - druid.PredatoryInstinctsAura.Deactivate(sim) - } - } - }, - }) - - energyMetrics := druid.NewEnergyMetrics(actionID) - - druid.CatForm = druid.RegisterSpell(Any, core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagAPL, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.35, - Multiplier: (1 - 0.2*float64(druid.Talents.KingOfTheJungle)) * (1 - 0.1*float64(druid.Talents.NaturalShapeshifter)), - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - IgnoreHaste: true, - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { - maxShiftEnergy := float64(20 * druid.Talents.Furor) - - energyDelta := maxShiftEnergy - druid.CurrentEnergy() - - if energyDelta < 0 { - druid.SpendEnergy(sim, -energyDelta, energyMetrics) - } - druid.CatFormAura.Activate(sim) - }, - }) -} - -func (druid *Druid) registerBearFormSpell() { - actionID := core.ActionID{SpellID: 9634} - healthMetrics := druid.NewHealthMetrics(actionID) - - statBonus := druid.GetFormShiftStats().Add(stats.Stats{ - stats.AttackPower: 3 * float64(druid.Level), - }) - - stamDep := druid.NewDynamicMultiplyStat(stats.Stamina, 1.25) - - var potpDep *stats.StatDependency - if druid.Talents.ProtectorOfThePack > 0 { - potpDep = druid.NewDynamicMultiplyStat(stats.AttackPower, 1.0+0.02*float64(druid.Talents.ProtectorOfThePack)) - } - - var hotwDep *stats.StatDependency - if druid.Talents.HeartOfTheWild > 0 { - hotwDep = druid.NewDynamicMultiplyStat(stats.Stamina, 1.0+0.02*float64(druid.Talents.HeartOfTheWild)) - } - - potpdtm := 1 - 0.04*float64(druid.Talents.ProtectorOfThePack) - - clawWeapon := druid.GetBearWeapon() - predBonus := stats.Stats{} - - druid.BearFormAura = druid.RegisterAura(core.Aura{ - Label: "Bear Form", - ActionID: actionID, - Duration: core.NeverExpires, - BuildPhase: core.Ternary(druid.StartingForm.Matches(Bear), core.CharacterBuildPhaseBase, core.CharacterBuildPhaseNone), - OnGain: func(aura *core.Aura, sim *core.Simulation) { - if !druid.Env.MeasuringStats && druid.form != Humanoid { - druid.ClearForm(sim) - } - druid.form = Bear - druid.SetCurrentPowerBar(core.RageBar) - - druid.AutoAttacks.SetMH(clawWeapon) - - druid.PseudoStats.ThreatMultiplier *= 2.1021 - druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1.0 + 0.02*float64(druid.Talents.MasterShapeshifter) - druid.PseudoStats.DamageTakenMultiplier *= potpdtm - druid.PseudoStats.SpiritRegenMultiplier *= AnimalSpiritRegenSuppression - druid.PseudoStats.BaseDodge += 0.02 * float64(druid.Talents.FeralSwiftness+druid.Talents.NaturalReaction) - - predBonus = druid.GetDynamicPredStrikeStats() - druid.AddStatsDynamic(sim, predBonus) - druid.AddStatsDynamic(sim, statBonus) - druid.ApplyDynamicEquipScaling(sim, stats.Armor, druid.BearArmorMultiplier()) - if potpDep != nil { - druid.EnableDynamicStatDep(sim, potpDep) - } - - // Preserve fraction of max health when shifting - healthFrac := druid.CurrentHealth() / druid.MaxHealth() - druid.EnableDynamicStatDep(sim, stamDep) - if hotwDep != nil { - druid.EnableDynamicStatDep(sim, hotwDep) - } - druid.GainHealth(sim, healthFrac*druid.MaxHealth()-druid.CurrentHealth(), healthMetrics) - - if !druid.Env.MeasuringStats { - druid.AutoAttacks.SetReplaceMHSwing(druid.ReplaceBearMHFunc) - druid.AutoAttacks.EnableAutoSwing(sim) - - druid.manageCooldownsEnabled() - druid.UpdateManaRegenRates() - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - druid.form = Humanoid - druid.AutoAttacks.SetMH(druid.WeaponFromMainHand(druid.MeleeCritMultiplier(Humanoid))) - - druid.PseudoStats.ThreatMultiplier /= 2.1021 - druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= 1.0 + 0.02*float64(druid.Talents.MasterShapeshifter) - druid.PseudoStats.DamageTakenMultiplier /= potpdtm - druid.PseudoStats.SpiritRegenMultiplier /= AnimalSpiritRegenSuppression - druid.PseudoStats.BaseDodge -= 0.02 * float64(druid.Talents.FeralSwiftness+druid.Talents.NaturalReaction) - - druid.AddStatsDynamic(sim, predBonus.Invert()) - druid.AddStatsDynamic(sim, statBonus.Invert()) - druid.RemoveDynamicEquipScaling(sim, stats.Armor, druid.BearArmorMultiplier()) - if potpDep != nil { - druid.DisableDynamicStatDep(sim, potpDep) - } - - healthFrac := druid.CurrentHealth() / druid.MaxHealth() - druid.DisableDynamicStatDep(sim, stamDep) - if hotwDep != nil { - druid.DisableDynamicStatDep(sim, hotwDep) - } - druid.RemoveHealth(sim, druid.CurrentHealth()-healthFrac*druid.MaxHealth()) - - if !druid.Env.MeasuringStats { - druid.AutoAttacks.SetReplaceMHSwing(nil) - druid.AutoAttacks.EnableAutoSwing(sim) - - druid.manageCooldownsEnabled() - druid.UpdateManaRegenRates() - druid.EnrageAura.Deactivate(sim) - druid.MaulQueueAura.Deactivate(sim) - } - }, - }) - - rageMetrics := druid.NewRageMetrics(actionID) - - furorProcChance := []float64{0, 0.2, 0.4, 0.6, 0.8, 1}[druid.Talents.Furor] - - druid.BearForm = druid.RegisterSpell(Any, core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagAPL, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.35, - Multiplier: (1 - 0.2*float64(druid.Talents.KingOfTheJungle)) * (1 - 0.1*float64(druid.Talents.NaturalShapeshifter)), - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - IgnoreHaste: true, - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { - rageDelta := 0 - druid.CurrentRage() - if sim.Proc(furorProcChance, "Furor") { - rageDelta += 10 - } - if rageDelta > 0 { - druid.AddRage(sim, rageDelta, rageMetrics) - } else if rageDelta < 0 { - druid.SpendRage(sim, -rageDelta, rageMetrics) - } - druid.BearFormAura.Activate(sim) - }, - }) -} - -func (druid *Druid) manageCooldownsEnabled() { - // Disable cooldowns not usable in form and/or delay others - if druid.StartingForm.Matches(Cat | Bear) { - for _, mcd := range druid.disabledMCDs { - mcd.Enable() - } - druid.disabledMCDs = nil - - if druid.InForm(Humanoid) { - // Disable cooldown that incurs a gcd, so we dont get stuck out of form when we dont need to (Greater Drums) - for _, mcd := range druid.GetMajorCooldowns() { - if mcd.Spell.DefaultCast.GCD > 0 { - mcd.Disable() - druid.disabledMCDs = append(druid.disabledMCDs, mcd) - } - } - } - } -} - -func (druid *Druid) applyMoonkinForm() { - if !druid.InForm(Moonkin) || !druid.Talents.MoonkinForm { - return - } - - druid.MultiplyStat(stats.Intellect, 1+(0.02*float64(druid.Talents.Furor))) - druid.PseudoStats.DamageDealtMultiplier *= 1 + (float64(druid.Talents.MasterShapeshifter) * 0.02) - if druid.Talents.ImprovedMoonkinForm > 0 { - druid.AddStatDependency(stats.Spirit, stats.SpellPower, 0.1*float64(druid.Talents.ImprovedMoonkinForm)) - } - - manaMetrics := druid.NewManaMetrics(core.ActionID{SpellID: 24858}) - druid.RegisterAura(core.Aura{ - Label: "Moonkin Form", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.DidCrit() { - if druid.Moonfire.IsEqual(spell) || druid.Starfire.IsEqual(spell) || druid.Wrath.IsEqual(spell) { - druid.AddMana(sim, 0.02*druid.MaxMana(), manaMetrics) - } - } - }, - }) -} +// import ( +// "math" + +// "github.com/wowsims/cata/sim/core" +// "github.com/wowsims/cata/sim/core/proto" +// "github.com/wowsims/cata/sim/core/stats" +// ) + + type DruidForm uint8 + + const ( + Humanoid DruidForm = 1 << iota + Bear + Cat + Moonkin + Tree + Any = Humanoid | Bear | Cat | Moonkin | Tree + ) + +// // Converts from 0.009327 to 0.0085 +// const AnimalSpiritRegenSuppression = 0.911337 + +// func (form DruidForm) Matches(other DruidForm) bool { +// return (form & other) != 0 +// } + +// func (druid *Druid) GetForm() DruidForm { +// return druid.form +// } + +// func (druid *Druid) InForm(form DruidForm) bool { +// return druid.form.Matches(form) +// } + +// func (druid *Druid) ClearForm(sim *core.Simulation) { +// if druid.InForm(Cat) { +// druid.CatFormAura.Deactivate(sim) +// } else if druid.InForm(Bear) { +// druid.BearFormAura.Deactivate(sim) +// } else if druid.InForm(Moonkin) { +// panic("cant clear moonkin form") +// } +// druid.form = Humanoid +// druid.SetCurrentPowerBar(core.ManaBar) +// } + +// func (druid *Druid) GetCatWeapon() core.Weapon { +// return core.Weapon{ +// BaseDamageMin: 43, +// BaseDamageMax: 66, +// SwingSpeed: 1.0, +// NormalizedSwingSpeed: 1.0, +// CritMultiplier: druid.MeleeCritMultiplier(Cat), +// AttackPowerPerDPS: core.DefaultAttackPowerPerDPS, +// } +// } + +// func (druid *Druid) GetBearWeapon() core.Weapon { +// return core.Weapon{ +// BaseDamageMin: 109, +// BaseDamageMax: 165, +// SwingSpeed: 2.5, +// NormalizedSwingSpeed: 2.5, +// CritMultiplier: druid.MeleeCritMultiplier(Bear), +// AttackPowerPerDPS: core.DefaultAttackPowerPerDPS, +// } +// } + +// // Bonus stats for both cat and bear. +// func (druid *Druid) GetFormShiftStats() stats.Stats { +// s := stats.Stats{ +// stats.AttackPower: float64(druid.Talents.PredatoryStrikes) * 0.5 * float64(druid.Level), +// stats.MeleeCrit: float64(druid.Talents.SharpenedClaws) * 2 * core.CritRatingPerCritChance, +// } + +// if weapon := druid.GetMHWeapon(); weapon != nil { +// dps := (weapon.WeaponDamageMax+weapon.WeaponDamageMin)/2.0/weapon.SwingSpeed + druid.PseudoStats.BonusMHDps +// weapAp := weapon.Stats[stats.AttackPower] + weapon.Enchant.Stats[stats.AttackPower] +// fap := math.Floor((dps - 54.8) * 14) + +// s[stats.AttackPower] += fap +// s[stats.AttackPower] += (fap + weapAp) * ((0.2 / 3) * float64(druid.Talents.PredatoryStrikes)) +// } + +// return s +// } + +// func (druid *Druid) GetDynamicPredStrikeStats() stats.Stats { +// // Accounts for ap bonus for 'dynamic' enchants +// // just scourgebane currently, this is a bit hacky but is needed as the bonus varies based on current target +// // so has to be 'cached' differently +// s := stats.Stats{} +// if weapon := druid.GetMHWeapon(); weapon != nil { +// bonusAp := 0.0 +// if weapon.Enchant.EffectID == 3247 && druid.CurrentTarget.MobType == proto.MobType_MobTypeUndead { +// bonusAp += 140 +// } +// s[stats.AttackPower] += bonusAp * ((0.2 / 3) * float64(druid.Talents.PredatoryStrikes)) +// } +// return s +// } + +// func (druid *Druid) registerCatFormSpell() { +// actionID := core.ActionID{SpellID: 768} + +// srm := druid.getSavageRoarMultiplier() + +// statBonus := druid.GetFormShiftStats().Add(stats.Stats{ +// stats.AttackPower: float64(druid.Level) * 2, +// stats.MeleeCrit: 2 * float64(druid.Talents.MasterShapeshifter) * core.CritRatingPerCritChance, +// }) + +// agiApDep := druid.NewDynamicStatDependency(stats.Agility, stats.AttackPower, 1) + +// var hotwDep *stats.StatDependency +// if druid.Talents.HeartOfTheWild > 0 { +// hotwDep = druid.NewDynamicMultiplyStat(stats.AttackPower, 1.0+0.02*float64(druid.Talents.HeartOfTheWild)) +// } + +// clawWeapon := druid.GetCatWeapon() + +// predBonus := stats.Stats{} + +// druid.CatFormAura = druid.RegisterAura(core.Aura{ +// Label: "Cat Form", +// ActionID: actionID, +// Duration: core.NeverExpires, +// BuildPhase: core.Ternary(druid.StartingForm.Matches(Cat), core.CharacterBuildPhaseBase, core.CharacterBuildPhaseNone), +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// if !druid.Env.MeasuringStats && druid.form != Humanoid { +// druid.ClearForm(sim) +// } +// druid.form = Cat +// druid.SetCurrentPowerBar(core.EnergyBar) + +// druid.AutoAttacks.SetMH(clawWeapon) + +// druid.PseudoStats.ThreatMultiplier *= 0.71 +// druid.PseudoStats.SpiritRegenMultiplier *= AnimalSpiritRegenSuppression +// druid.PseudoStats.BaseDodge += 0.02 * float64(druid.Talents.FeralSwiftness) + +// predBonus = druid.GetDynamicPredStrikeStats() +// druid.AddStatsDynamic(sim, predBonus) +// druid.AddStatsDynamic(sim, statBonus) +// druid.EnableDynamicStatDep(sim, agiApDep) +// if hotwDep != nil { +// druid.EnableDynamicStatDep(sim, hotwDep) +// } + +// if !druid.Env.MeasuringStats { +// druid.AutoAttacks.SetReplaceMHSwing(nil) +// druid.AutoAttacks.EnableAutoSwing(sim) +// druid.manageCooldownsEnabled() +// druid.UpdateManaRegenRates() + +// // These buffs stay up, but corresponding changes don't +// if druid.SavageRoarAura.IsActive() { +// druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= srm +// } + +// if druid.PredatoryInstinctsAura != nil { +// druid.PredatoryInstinctsAura.Activate(sim) +// } +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// druid.form = Humanoid + +// druid.AutoAttacks.SetMH(druid.WeaponFromMainHand(druid.MeleeCritMultiplier(Humanoid))) + +// druid.PseudoStats.ThreatMultiplier /= 0.71 +// druid.PseudoStats.SpiritRegenMultiplier /= AnimalSpiritRegenSuppression +// druid.PseudoStats.BaseDodge -= 0.02 * float64(druid.Talents.FeralSwiftness) + +// druid.AddStatsDynamic(sim, predBonus.Invert()) +// druid.AddStatsDynamic(sim, statBonus.Invert()) +// druid.DisableDynamicStatDep(sim, agiApDep) +// if hotwDep != nil { +// druid.DisableDynamicStatDep(sim, hotwDep) +// } + +// if !druid.Env.MeasuringStats { +// druid.AutoAttacks.SetReplaceMHSwing(nil) +// druid.AutoAttacks.EnableAutoSwing(sim) +// druid.manageCooldownsEnabled() +// druid.UpdateManaRegenRates() + +// druid.TigersFuryAura.Deactivate(sim) + +// // These buffs stay up, but corresponding changes don't +// if druid.SavageRoarAura.IsActive() { +// druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= srm +// } + +// if druid.PredatoryInstinctsAura != nil { +// druid.PredatoryInstinctsAura.Deactivate(sim) +// } +// } +// }, +// }) + +// energyMetrics := druid.NewEnergyMetrics(actionID) + +// druid.CatForm = druid.RegisterSpell(Any, core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagAPL, + +// ManaCost: core.ManaCostOptions{ +// BaseCost: 0.35, +// Multiplier: (1 - 0.2*float64(druid.Talents.KingOfTheJungle)) * (1 - 0.1*float64(druid.Talents.NaturalShapeshifter)), +// }, +// Cast: core.CastConfig{ +// DefaultCast: core.Cast{ +// GCD: core.GCDDefault, +// }, +// IgnoreHaste: true, +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { +// maxShiftEnergy := float64(20 * druid.Talents.Furor) + +// energyDelta := maxShiftEnergy - druid.CurrentEnergy() + +// if energyDelta < 0 { +// druid.SpendEnergy(sim, -energyDelta, energyMetrics) +// } +// druid.CatFormAura.Activate(sim) +// }, +// }) +// } + +// func (druid *Druid) registerBearFormSpell() { +// actionID := core.ActionID{SpellID: 9634} +// healthMetrics := druid.NewHealthMetrics(actionID) + +// statBonus := druid.GetFormShiftStats().Add(stats.Stats{ +// stats.AttackPower: 3 * float64(druid.Level), +// }) + +// stamDep := druid.NewDynamicMultiplyStat(stats.Stamina, 1.25) + +// var potpDep *stats.StatDependency +// if druid.Talents.ProtectorOfThePack > 0 { +// potpDep = druid.NewDynamicMultiplyStat(stats.AttackPower, 1.0+0.02*float64(druid.Talents.ProtectorOfThePack)) +// } + +// var hotwDep *stats.StatDependency +// if druid.Talents.HeartOfTheWild > 0 { +// hotwDep = druid.NewDynamicMultiplyStat(stats.Stamina, 1.0+0.02*float64(druid.Talents.HeartOfTheWild)) +// } + +// potpdtm := 1 - 0.04*float64(druid.Talents.ProtectorOfThePack) + +// clawWeapon := druid.GetBearWeapon() +// predBonus := stats.Stats{} + +// druid.BearFormAura = druid.RegisterAura(core.Aura{ +// Label: "Bear Form", +// ActionID: actionID, +// Duration: core.NeverExpires, +// BuildPhase: core.Ternary(druid.StartingForm.Matches(Bear), core.CharacterBuildPhaseBase, core.CharacterBuildPhaseNone), +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// if !druid.Env.MeasuringStats && druid.form != Humanoid { +// druid.ClearForm(sim) +// } +// druid.form = Bear +// druid.SetCurrentPowerBar(core.RageBar) + +// druid.AutoAttacks.SetMH(clawWeapon) + +// druid.PseudoStats.ThreatMultiplier *= 2.1021 +// druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1.0 + 0.02*float64(druid.Talents.MasterShapeshifter) +// druid.PseudoStats.DamageTakenMultiplier *= potpdtm +// druid.PseudoStats.SpiritRegenMultiplier *= AnimalSpiritRegenSuppression +// druid.PseudoStats.BaseDodge += 0.02 * float64(druid.Talents.FeralSwiftness+druid.Talents.NaturalReaction) + +// predBonus = druid.GetDynamicPredStrikeStats() +// druid.AddStatsDynamic(sim, predBonus) +// druid.AddStatsDynamic(sim, statBonus) +// druid.ApplyDynamicEquipScaling(sim, stats.Armor, druid.BearArmorMultiplier()) +// if potpDep != nil { +// druid.EnableDynamicStatDep(sim, potpDep) +// } + +// // Preserve fraction of max health when shifting +// healthFrac := druid.CurrentHealth() / druid.MaxHealth() +// druid.EnableDynamicStatDep(sim, stamDep) +// if hotwDep != nil { +// druid.EnableDynamicStatDep(sim, hotwDep) +// } +// druid.GainHealth(sim, healthFrac*druid.MaxHealth()-druid.CurrentHealth(), healthMetrics) + +// if !druid.Env.MeasuringStats { +// druid.AutoAttacks.SetReplaceMHSwing(druid.ReplaceBearMHFunc) +// druid.AutoAttacks.EnableAutoSwing(sim) + +// druid.manageCooldownsEnabled() +// druid.UpdateManaRegenRates() +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// druid.form = Humanoid +// druid.AutoAttacks.SetMH(druid.WeaponFromMainHand(druid.MeleeCritMultiplier(Humanoid))) + +// druid.PseudoStats.ThreatMultiplier /= 2.1021 +// druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= 1.0 + 0.02*float64(druid.Talents.MasterShapeshifter) +// druid.PseudoStats.DamageTakenMultiplier /= potpdtm +// druid.PseudoStats.SpiritRegenMultiplier /= AnimalSpiritRegenSuppression +// druid.PseudoStats.BaseDodge -= 0.02 * float64(druid.Talents.FeralSwiftness+druid.Talents.NaturalReaction) + +// druid.AddStatsDynamic(sim, predBonus.Invert()) +// druid.AddStatsDynamic(sim, statBonus.Invert()) +// druid.RemoveDynamicEquipScaling(sim, stats.Armor, druid.BearArmorMultiplier()) +// if potpDep != nil { +// druid.DisableDynamicStatDep(sim, potpDep) +// } + +// healthFrac := druid.CurrentHealth() / druid.MaxHealth() +// druid.DisableDynamicStatDep(sim, stamDep) +// if hotwDep != nil { +// druid.DisableDynamicStatDep(sim, hotwDep) +// } +// druid.RemoveHealth(sim, druid.CurrentHealth()-healthFrac*druid.MaxHealth()) + +// if !druid.Env.MeasuringStats { +// druid.AutoAttacks.SetReplaceMHSwing(nil) +// druid.AutoAttacks.EnableAutoSwing(sim) + +// druid.manageCooldownsEnabled() +// druid.UpdateManaRegenRates() +// druid.EnrageAura.Deactivate(sim) +// druid.MaulQueueAura.Deactivate(sim) +// } +// }, +// }) + +// rageMetrics := druid.NewRageMetrics(actionID) + +// furorProcChance := []float64{0, 0.2, 0.4, 0.6, 0.8, 1}[druid.Talents.Furor] + +// druid.BearForm = druid.RegisterSpell(Any, core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagAPL, + +// ManaCost: core.ManaCostOptions{ +// BaseCost: 0.35, +// Multiplier: (1 - 0.2*float64(druid.Talents.KingOfTheJungle)) * (1 - 0.1*float64(druid.Talents.NaturalShapeshifter)), +// }, +// Cast: core.CastConfig{ +// DefaultCast: core.Cast{ +// GCD: core.GCDDefault, +// }, +// IgnoreHaste: true, +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { +// rageDelta := 0 - druid.CurrentRage() +// if sim.Proc(furorProcChance, "Furor") { +// rageDelta += 10 +// } +// if rageDelta > 0 { +// druid.AddRage(sim, rageDelta, rageMetrics) +// } else if rageDelta < 0 { +// druid.SpendRage(sim, -rageDelta, rageMetrics) +// } +// druid.BearFormAura.Activate(sim) +// }, +// }) +// } + +// func (druid *Druid) manageCooldownsEnabled() { +// // Disable cooldowns not usable in form and/or delay others +// if druid.StartingForm.Matches(Cat | Bear) { +// for _, mcd := range druid.disabledMCDs { +// mcd.Enable() +// } +// druid.disabledMCDs = nil + +// if druid.InForm(Humanoid) { +// // Disable cooldown that incurs a gcd, so we dont get stuck out of form when we dont need to (Greater Drums) +// for _, mcd := range druid.GetMajorCooldowns() { +// if mcd.Spell.DefaultCast.GCD > 0 { +// mcd.Disable() +// druid.disabledMCDs = append(druid.disabledMCDs, mcd) +// } +// } +// } +// } +// } + +// func (druid *Druid) applyMoonkinForm() { +// if !druid.InForm(Moonkin) || !druid.Talents.MoonkinForm { +// return +// } + +// druid.MultiplyStat(stats.Intellect, 1+(0.02*float64(druid.Talents.Furor))) +// druid.PseudoStats.DamageDealtMultiplier *= 1 + (float64(druid.Talents.MasterShapeshifter) * 0.02) +// if druid.Talents.ImprovedMoonkinForm > 0 { +// druid.AddStatDependency(stats.Spirit, stats.SpellPower, 0.1*float64(druid.Talents.ImprovedMoonkinForm)) +// } + +// manaMetrics := druid.NewManaMetrics(core.ActionID{SpellID: 24858}) +// druid.RegisterAura(core.Aura{ +// Label: "Moonkin Form", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.DidCrit() { +// if druid.Moonfire.IsEqual(spell) || druid.Starfire.IsEqual(spell) || druid.Wrath.IsEqual(spell) { +// druid.AddMana(sim, 0.02*druid.MaxMana(), manaMetrics) +// } +// } +// }, +// }) +// } diff --git a/sim/druid/talents.go b/sim/druid/talents.go index 8ebb72a504..555081d9eb 100644 --- a/sim/druid/talents.go +++ b/sim/druid/talents.go @@ -1,14 +1,5 @@ package druid -import ( - "math" - "time" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" -) - func (druid *Druid) ThickHideMultiplier() float64 { thickHideMulti := 1.0 @@ -19,664 +10,664 @@ func (druid *Druid) ThickHideMultiplier() float64 { return thickHideMulti } -func (druid *Druid) BearArmorMultiplier() float64 { - sotfMulti := 1.0 + 0.33/3.0*float64(druid.Talents.SurvivalOfTheFittest) - return 4.7 * sotfMulti -} +// func (druid *Druid) BearArmorMultiplier() float64 { +// sotfMulti := 1.0 + 0.33/3.0*float64(druid.Talents.SurvivalOfTheFittest) +// return 4.7 * sotfMulti +// } func (druid *Druid) ApplyTalents() { - druid.AddStat(stats.SpellHit, float64(druid.Talents.BalanceOfPower)*2*core.SpellHitRatingPerHitChance) - druid.AddStat(stats.SpellCrit, float64(druid.Talents.NaturalPerfection)*1*core.CritRatingPerCritChance) - druid.PseudoStats.CastSpeedMultiplier *= 1 + (float64(druid.Talents.CelestialFocus) * 0.01) - druid.PseudoStats.DamageDealtMultiplier *= 1 + (float64(druid.Talents.EarthAndMoon) * 0.02) - druid.PseudoStats.SpiritRegenRateCasting = float64(druid.Talents.Intensity) * (0.5 / 3) - druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 + 0.02*float64(druid.Talents.Naturalist) - druid.ApplyEquipScaling(stats.Armor, druid.ThickHideMultiplier()) - - if druid.Talents.LunarGuidance > 0 { - bonus := 0.04 * float64(druid.Talents.LunarGuidance) - druid.AddStatDependency(stats.Intellect, stats.SpellPower, bonus) - } - - if druid.Talents.Dreamstate > 0 { - bonus := 0.04 * float64(druid.Talents.Dreamstate) - druid.AddStatDependency(stats.Intellect, stats.MP5, bonus) - } - - if druid.Talents.HeartOfTheWild > 0 { - bonus := 0.04 * float64(druid.Talents.HeartOfTheWild) - druid.MultiplyStat(stats.Intellect, 1.0+bonus) - } - - if druid.Talents.ImprovedFaerieFire > 0 && druid.CurrentTarget.HasAuraWithTag(core.FaerieFireAuraTag) { - druid.AddStat(stats.SpellCrit, float64(druid.Talents.ImprovedFaerieFire)*1*core.CritRatingPerCritChance) - } - - if druid.Talents.SurvivalOfTheFittest > 0 { - bonus := 0.02 * float64(druid.Talents.SurvivalOfTheFittest) - druid.MultiplyStat(stats.Stamina, 1.0+bonus) - druid.MultiplyStat(stats.Strength, 1.0+bonus) - druid.MultiplyStat(stats.Agility, 1.0+bonus) - druid.MultiplyStat(stats.Intellect, 1.0+bonus) - druid.MultiplyStat(stats.Spirit, 1.0+bonus) - druid.PseudoStats.ReducedCritTakenChance += 0.02 * float64(druid.Talents.SurvivalOfTheFittest) - } - - if druid.Talents.ImprovedMarkOfTheWild > 0 { - bonus := 0.01 * float64(druid.Talents.ImprovedMarkOfTheWild) - druid.MultiplyStat(stats.Stamina, 1.0+bonus) - druid.MultiplyStat(stats.Strength, 1.0+bonus) - druid.MultiplyStat(stats.Agility, 1.0+bonus) - druid.MultiplyStat(stats.Intellect, 1.0+bonus) - druid.MultiplyStat(stats.Spirit, 1.0+bonus) - } - - if druid.Talents.PrimalPrecision > 0 { - druid.AddStat(stats.Expertise, 5.0*float64(druid.Talents.PrimalPrecision)*core.ExpertisePerQuarterPercentReduction) - } - - if druid.Talents.LivingSpirit > 0 { - bonus := 0.05 * float64(druid.Talents.LivingSpirit) - druid.MultiplyStat(stats.Spirit, 1.0+bonus) - } - - druid.setupNaturesGrace() - druid.registerNaturesSwiftnessCD() - druid.applyEarthAndMoon() - druid.applyMoonkinForm() - druid.applyPrimalFury() - druid.applyOmenOfClarity() - druid.applyEclipse() - druid.applyImprovedLotp() - druid.applyPredatoryInstincts() - druid.applyNaturalReaction() - druid.applyOwlkinFrenzy() - druid.applyInfectedWounds() -} - -func (druid *Druid) setupNaturesGrace() { - if druid.Talents.NaturesGrace == 0 { - return - } - - druid.NaturesGraceProcAura = druid.RegisterAura(core.Aura{ - Label: "Natures Grace Proc", - ActionID: core.ActionID{SpellID: 16886}, - Duration: time.Second * 3, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - druid.MultiplyCastSpeed(1.2) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - druid.MultiplyCastSpeed(1 / 1.2) - }, - }) - - procChance := []float64{0, .33, .66, 1}[druid.Talents.NaturesGrace] - - druid.RegisterAura(core.Aura{ - Label: "Natures Grace", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Outcome.Matches(core.OutcomeCrit) { - return - } - if spell.Flags.Matches(SpellFlagNaturesGrace) && sim.Proc(procChance, "Natures Grace") { - druid.NaturesGraceProcAura.Activate(sim) - } - }, - }) -} - -func (druid *Druid) registerNaturesSwiftnessCD() { - if !druid.Talents.NaturesSwiftness { - return - } - actionID := core.ActionID{SpellID: 17116} - - var nsAura *core.Aura - nsSpell := druid.RegisterSpell(Humanoid|Moonkin|Tree, core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete, - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: druid.NewTimer(), - Duration: time.Minute * 3, - }, - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - nsAura.Activate(sim) - }, - }) - - nsAura = druid.RegisterAura(core.Aura{ - Label: "Natures Swiftness", - ActionID: actionID, - Duration: core.NeverExpires, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - if druid.Starfire != nil { - druid.Starfire.CastTimeMultiplier -= 1 - } - if druid.Wrath != nil { - druid.Wrath.CastTimeMultiplier -= 1 - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - if druid.Starfire != nil { - druid.Starfire.CastTimeMultiplier += 1 - } - if druid.Wrath != nil { - druid.Wrath.CastTimeMultiplier += 1 - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if !druid.Wrath.IsEqual(spell) && !druid.Starfire.IsEqual(spell) { - return - } - - // Remove the buff and put skill on CD - aura.Deactivate(sim) - nsSpell.CD.Use(sim) - druid.UpdateMajorCooldowns() - }, - }) - - druid.AddMajorCooldown(core.MajorCooldown{ - Spell: nsSpell.Spell, - Type: core.CooldownTypeDPS, - ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { - // Don't use NS unless we're casting a full-length starfire or wrath. - return !character.HasTemporarySpellCastSpeedIncrease() - }, - }) -} - -func (druid *Druid) applyEarthAndMoon() { - if druid.Talents.EarthAndMoon == 0 { - return - } - - eamAuras := druid.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { - return core.EarthAndMoonAura(target, druid.Talents.EarthAndMoon) - }) - druid.Env.RegisterPreFinalizeEffect(func() { - if druid.Starfire != nil { - druid.Starfire.RelatedAuras = append(druid.Starfire.RelatedAuras, eamAuras) - } - if druid.Wrath != nil { - druid.Wrath.RelatedAuras = append(druid.Wrath.RelatedAuras, eamAuras) - } - }) - - earthAndMoonSpell := druid.RegisterSpell(Any, core.SpellConfig{ - ActionID: core.ActionID{SpellID: 60432}, - ProcMask: core.ProcMaskSuppressedProc, - Flags: core.SpellFlagNoLogs, - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - eamAuras.Get(target).Activate(sim) - }, - }) - - druid.RegisterAura(core.Aura{ - Label: "Earth And Moon Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() && (druid.Starfire.IsEqual(spell) || druid.Wrath.IsEqual(spell)) { - earthAndMoonSpell.Cast(sim, result.Target) - } - }, - }) -} - -func (druid *Druid) applyPrimalFury() { - if druid.Talents.PrimalFury == 0 { - return - } - - procChance := []float64{0, 0.5, 1}[druid.Talents.PrimalFury] - actionID := core.ActionID{SpellID: 37117} - rageMetrics := druid.NewRageMetrics(actionID) - cpMetrics := druid.NewComboPointMetrics(actionID) - - druid.RegisterAura(core.Aura{ - Label: "Primal Fury", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if druid.InForm(Bear) { - if result.Outcome.Matches(core.OutcomeCrit) { - if sim.Proc(procChance, "Primal Fury") { - druid.AddRage(sim, 5, rageMetrics) - } - } - } else if druid.InForm(Cat) { - if druid.IsMangle(spell) || druid.Shred.IsEqual(spell) || druid.Rake.IsEqual(spell) { - if result.Outcome.Matches(core.OutcomeCrit) { - if sim.Proc(procChance, "Primal Fury") { - druid.AddComboPoints(sim, 1, cpMetrics) - } - } - } - } - }, - }) -} - -// Modifies the Bleed aura to apply the bonus. -func (druid *Druid) applyRendAndTear(aura core.Aura) core.Aura { - if druid.FerociousBite == nil || druid.Talents.RendAndTear == 0 || druid.AssumeBleedActive { - return aura - } - - bonusCrit := 5.0 * float64(druid.Talents.RendAndTear) * core.CritRatingPerCritChance - - aura.ApplyOnGain(func(aura *core.Aura, sim *core.Simulation) { - if druid.BleedsActive == 0 { - druid.FerociousBite.BonusCritRating += bonusCrit - } - druid.BleedsActive++ - }) - aura.ApplyOnExpire(func(aura *core.Aura, sim *core.Simulation) { - druid.BleedsActive-- - if druid.BleedsActive == 0 { - druid.FerociousBite.BonusCritRating -= bonusCrit - } - }) - - return aura -} - -func (druid *Druid) applyOmenOfClarity() { - // Feral 2p needs clearcasting aura - if !druid.Talents.OmenOfClarity && !druid.HasSetBonus(ItemSetNightsongBattlegear, 2) { - return - } - - // T10-2P - var lasherweave2P *core.Aura - if druid.HasSetBonus(ItemSetLasherweaveRegalia, 2) { - lasherweave2P = druid.RegisterAura(core.Aura{ - Label: "T10-2P proc", - ActionID: core.ActionID{SpellID: 70718}, - Duration: time.Second * 6, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexArcane] *= 1.15 - druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] *= 1.15 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexArcane] /= 1.15 - druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] /= 1.15 - }, - }) - } - - var affectedSpells []*DruidSpell - druid.ClearcastingAura = druid.RegisterAura(core.Aura{ - Label: "Clearcasting", - ActionID: core.ActionID{SpellID: 16870}, - Duration: time.Second * 15, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - affectedSpells = core.FilterSlice([]*DruidSpell{ - // Balance - druid.Hurricane, - druid.InsectSwarm, - druid.Moonfire, - // TODO druid.Starfall, not sure how the proc chance is affected. - druid.Starfire, - druid.Typhoon, - druid.Wrath, - - // Feral - druid.DemoralizingRoar, - druid.FerociousBite, - druid.Lacerate, - druid.MangleBear, - druid.MangleCat, - druid.Maul, - druid.Rake, - druid.Rip, - druid.Shred, - druid.SwipeBear, - druid.SwipeCat, - }, func(spell *DruidSpell) bool { return spell != nil }) - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.CostMultiplier -= 1 - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.CostMultiplier += 1 - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if aura.RemainingDuration(sim) == aura.Duration { - // OnCastComplete is called after OnSpellHitDealt / etc, so don't deactivate - // if it was just activated. - return - } - - for _, as := range affectedSpells { - if as.IsEqual(spell) { - aura.Deactivate(sim) - break - } - } - }, - }) - - if !druid.Talents.OmenOfClarity { - return - } - - druid.ProcOoc = func(sim *core.Simulation) { - druid.ClearcastingAura.Activate(sim) - if lasherweave2P != nil { - lasherweave2P.Activate(sim) - } - } - - hasOocGlyph := druid.HasMajorGlyph(proto.DruidMajorGlyph_GlyphOfOmenOfClarity) - - druid.RegisterAura(core.Aura{ - Label: "Omen of Clarity", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() { - return - } - - // https://github.com/JamminL/wotlk-classic-bugs/issues/66#issuecomment-1182017571 - if druid.HurricaneTickSpell.IsEqual(spell) { - curCastTickSpeed := spell.CurDot().TickPeriod().Seconds() / 10 - hurricaneCoeff := 1.0 - (7.0 / 9.0) - spellCoeff := hurricaneCoeff * curCastTickSpeed - chanceToProc := ((1.5 / 60) * 3.5) * spellCoeff - if sim.RandomFloat("Clearcasting") < chanceToProc { - druid.ProcOoc(sim) - } - } else if druid.AutoAttacks.PPMProc(sim, 3.5, core.ProcMaskMeleeWhiteHit, "Omen of Clarity", spell) { // Melee - druid.ProcOoc(sim) - } else if spell.Flags.Matches(SpellFlagOmenTrigger) { // Spells - // Heavily based on comment here - // https://github.com/JamminL/wotlk-classic-bugs/issues/66#issuecomment-1182017571 - // Instants are treated as 1.5 - // Uses current cast time rather than default cast time (PPM is constant with haste) - castTime := spell.CurCast.CastTime.Seconds() - if castTime == 0 { - castTime = 1.5 - } - - chanceToProc := (castTime / 60) * 3.5 - if druid.Typhoon.IsEqual(spell) { // Add Typhoon - chanceToProc *= 0.25 - } else if druid.Moonfire.IsEqual(spell) { // Add Moonfire - chanceToProc *= 0.076 - } else if druid.GiftOfTheWild.IsEqual(spell) { // Add Gift of the Wild - // the above comment says it's 0.0875 * (1-0.924) which apparently is out-dated, - // there is no longer an instant suppression factor - // we assume 30 targets (25man + pets) - chanceToProc = 1 - math.Pow(1-chanceToProc, 30) - } else { - chanceToProc *= 0.666 - } - if sim.RandomFloat("Clearcasting") < chanceToProc { - druid.ProcOoc(sim) - } - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if druid.FaerieFire.IsEqual(spell) && druid.InForm(Cat|Bear) && hasOocGlyph { - druid.ProcOoc(sim) - } - }, - }) -} - -func (druid *Druid) applyEclipse() { - druid.SolarICD = core.Cooldown{Timer: druid.NewTimer(), Duration: 0} - druid.LunarICD = core.Cooldown{Timer: druid.NewTimer(), Duration: 0} - if druid.Talents.Eclipse == 0 { - return - } - - // Delay between eclipses - eclipseDuration := time.Millisecond * 15000 - interEclipseDelay := eclipseDuration - time.Millisecond*500 - - // Solar - solarProcChance := (1.0 / 3.0) * float64(druid.Talents.Eclipse) - solarProcMultiplier := 1.4 + core.TernaryFloat64(druid.HasSetBonus(ItemSetNightsongGarb, 2), 0.07, 0) - druid.SolarICD.Duration = time.Millisecond * 30000 - druid.SolarEclipseProcAura = druid.RegisterAura(core.Aura{ - Icd: &druid.SolarICD, - Label: "Solar Eclipse proc", - Duration: eclipseDuration, - ActionID: core.ActionID{SpellID: 48517}, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - druid.Wrath.DamageMultiplier *= solarProcMultiplier - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - druid.Wrath.DamageMultiplier /= solarProcMultiplier - }, - }) - - druid.RegisterAura(core.Aura{ - Label: "Eclipse (Solar)", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Outcome.Matches(core.OutcomeCrit) { - return - } - if !druid.Starfire.IsEqual(spell) { - return - } - if !druid.SolarICD.Timer.IsReady(sim) { - return - } - if druid.LunarICD.Timer.TimeToReady(sim) > interEclipseDelay { - return - } - if sim.RandomFloat("Eclipse (Solar)") < solarProcChance { - druid.SolarICD.Use(sim) - druid.SolarEclipseProcAura.Activate(sim) - } - }, - }) - - // Lunar - lunarProcChance := 0.2 * float64(druid.Talents.Eclipse) - lunarBonusCrit := (40 + core.TernaryFloat64(druid.HasSetBonus(ItemSetNightsongGarb, 2), 7, 0)) * core.CritRatingPerCritChance - druid.LunarICD.Duration = time.Millisecond * 30000 - druid.LunarEclipseProcAura = druid.RegisterAura(core.Aura{ - Icd: &druid.LunarICD, - Label: "Lunar Eclipse proc", - Duration: eclipseDuration, - ActionID: core.ActionID{SpellID: 48518}, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - druid.Starfire.BonusCritRating += lunarBonusCrit - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - druid.Starfire.BonusCritRating -= lunarBonusCrit - }, - }) - druid.RegisterAura(core.Aura{ - Label: "Eclipse (Lunar)", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Outcome.Matches(core.OutcomeCrit) { - return - } - if !druid.Wrath.IsEqual(spell) { - return - } - if !druid.LunarICD.Timer.IsReady(sim) { - return - } - if druid.SolarICD.Timer.TimeToReady(sim) > interEclipseDelay { - return - } - if sim.RandomFloat("Eclipse (Lunar)") < lunarProcChance { - druid.LunarICD.Use(sim) - druid.LunarEclipseProcAura.Activate(sim) - } - }, - }) -} - -func (druid *Druid) applyOwlkinFrenzy() { - if druid.Talents.OwlkinFrenzy == 0 { - return - } - - druid.OwlkinFrenzyAura = druid.RegisterAura(core.Aura{ - Label: "Owlkin Frenzy proc", - ActionID: core.ActionID{SpellID: 48393}, - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - druid.PseudoStats.DamageDealtMultiplier *= 1.1 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - druid.PseudoStats.DamageDealtMultiplier /= 1.1 - }, - }) + // druid.AddStat(stats.SpellHit, float64(druid.Talents.BalanceOfPower)*2*core.SpellHitRatingPerHitChance) + // druid.AddStat(stats.SpellCrit, float64(druid.Talents.NaturalPerfection)*1*core.CritRatingPerCritChance) + // druid.PseudoStats.CastSpeedMultiplier *= 1 + (float64(druid.Talents.CelestialFocus) * 0.01) + // druid.PseudoStats.DamageDealtMultiplier *= 1 + (float64(druid.Talents.EarthAndMoon) * 0.02) + // druid.PseudoStats.SpiritRegenRateCasting = float64(druid.Talents.Intensity) * (0.5 / 3) + // druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 + 0.02*float64(druid.Talents.Naturalist) + // druid.ApplyEquipScaling(stats.Armor, druid.ThickHideMultiplier()) + + // if druid.Talents.LunarGuidance > 0 { + // bonus := 0.04 * float64(druid.Talents.LunarGuidance) + // druid.AddStatDependency(stats.Intellect, stats.SpellPower, bonus) + // } + + // if druid.Talents.Dreamstate > 0 { + // bonus := 0.04 * float64(druid.Talents.Dreamstate) + // druid.AddStatDependency(stats.Intellect, stats.MP5, bonus) + // } + + // if druid.Talents.HeartOfTheWild > 0 { + // bonus := 0.04 * float64(druid.Talents.HeartOfTheWild) + // druid.MultiplyStat(stats.Intellect, 1.0+bonus) + // } + + // if druid.Talents.ImprovedFaerieFire > 0 && druid.CurrentTarget.HasAuraWithTag(core.FaerieFireAuraTag) { + // druid.AddStat(stats.SpellCrit, float64(druid.Talents.ImprovedFaerieFire)*1*core.CritRatingPerCritChance) + // } + + // if druid.Talents.SurvivalOfTheFittest > 0 { + // bonus := 0.02 * float64(druid.Talents.SurvivalOfTheFittest) + // druid.MultiplyStat(stats.Stamina, 1.0+bonus) + // druid.MultiplyStat(stats.Strength, 1.0+bonus) + // druid.MultiplyStat(stats.Agility, 1.0+bonus) + // druid.MultiplyStat(stats.Intellect, 1.0+bonus) + // druid.MultiplyStat(stats.Spirit, 1.0+bonus) + // druid.PseudoStats.ReducedCritTakenChance += 0.02 * float64(druid.Talents.SurvivalOfTheFittest) + // } + + // if druid.Talents.ImprovedMarkOfTheWild > 0 { + // bonus := 0.01 * float64(druid.Talents.ImprovedMarkOfTheWild) + // druid.MultiplyStat(stats.Stamina, 1.0+bonus) + // druid.MultiplyStat(stats.Strength, 1.0+bonus) + // druid.MultiplyStat(stats.Agility, 1.0+bonus) + // druid.MultiplyStat(stats.Intellect, 1.0+bonus) + // druid.MultiplyStat(stats.Spirit, 1.0+bonus) + // } + + // if druid.Talents.PrimalPrecision > 0 { + // druid.AddStat(stats.Expertise, 5.0*float64(druid.Talents.PrimalPrecision)*core.ExpertisePerQuarterPercentReduction) + // } + + // if druid.Talents.LivingSpirit > 0 { + // bonus := 0.05 * float64(druid.Talents.LivingSpirit) + // druid.MultiplyStat(stats.Spirit, 1.0+bonus) + // } + + // druid.setupNaturesGrace() + // druid.registerNaturesSwiftnessCD() + // druid.applyEarthAndMoon() + // druid.applyMoonkinForm() + // druid.applyPrimalFury() + // druid.applyOmenOfClarity() + // druid.applyEclipse() + // druid.applyImprovedLotp() + // druid.applyPredatoryInstincts() + // druid.applyNaturalReaction() + // druid.applyOwlkinFrenzy() + // druid.applyInfectedWounds() } -func (druid *Druid) applyImprovedLotp() { - if druid.Talents.ImprovedLeaderOfThePack == 0 { - return - } - - actionID := core.ActionID{SpellID: 34300} - manaMetrics := druid.NewManaMetrics(actionID) - healthMetrics := druid.NewHealthMetrics(actionID) - manaRestore := float64(druid.Talents.ImprovedLeaderOfThePack) * 0.04 - healthRestore := 0.5 * manaRestore - - icd := core.Cooldown{ - Timer: druid.NewTimer(), - Duration: time.Second * 6, - } - - druid.RegisterAura(core.Aura{ - Icd: &icd, - Label: "Improved Leader of the Pack", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() { - return - } - if !spell.ProcMask.Matches(core.ProcMaskMeleeOrRanged) || !result.Outcome.Matches(core.OutcomeCrit) { - return - } - if !icd.IsReady(sim) { - return - } - icd.Use(sim) - druid.AddMana(sim, druid.MaxMana()*manaRestore, manaMetrics) - druid.GainHealth(sim, druid.MaxHealth()*healthRestore, healthMetrics) - }, - }) -} - -func (druid *Druid) applyPredatoryInstincts() { - if druid.Talents.PredatoryInstincts == 0 { - return - } - - onGainMod := druid.MeleeCritMultiplier(Cat) - onExpireMod := druid.MeleeCritMultiplier(Humanoid) - - druid.PredatoryInstinctsAura = druid.RegisterAura(core.Aura{ - Label: "Predatory Instincts", - Duration: core.NeverExpires, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - druid.Lacerate.CritMultiplier = onGainMod - druid.Rip.CritMultiplier = onGainMod - druid.Rake.CritMultiplier = onGainMod - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - druid.Lacerate.CritMultiplier = onExpireMod - druid.Rip.CritMultiplier = onExpireMod - druid.Rake.CritMultiplier = onExpireMod - }, - }) -} - -func (druid *Druid) applyNaturalReaction() { - if druid.Talents.NaturalReaction == 0 { - return - } - - actionID := core.ActionID{SpellID: 59072} - rageMetrics := druid.NewRageMetrics(actionID) - rageAdded := float64(druid.Talents.NaturalReaction) - - core.MakeProcTriggerAura(&druid.Unit, core.ProcTrigger{ - Name: "Natural Reaction Trigger", - Callback: core.CallbackOnSpellHitTaken, - ProcMask: core.ProcMaskMelee, - Handler: func(sim *core.Simulation, _ *core.Spell, result *core.SpellResult) { - if druid.InForm(Bear) && result.Outcome.Matches(core.OutcomeDodge) { - druid.AddRage(sim, rageAdded, rageMetrics) - } - }, - }) -} - -func (druid *Druid) applyInfectedWounds() { - if druid.Talents.InfectedWounds == 0 { - return - } - - iwAuras := druid.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { - return core.InfectedWoundsAura(target, druid.Talents.InfectedWounds) - }) - druid.Env.RegisterPreFinalizeEffect(func() { - if druid.Shred != nil { - druid.Shred.RelatedAuras = append(druid.Shred.RelatedAuras, iwAuras) - } - if druid.MangleCat != nil { - druid.MangleCat.RelatedAuras = append(druid.MangleCat.RelatedAuras, iwAuras) - } - if druid.MangleBear != nil { - druid.MangleBear.RelatedAuras = append(druid.MangleBear.RelatedAuras, iwAuras) - } - if druid.Maul != nil { - druid.Maul.RelatedAuras = append(druid.Maul.RelatedAuras, iwAuras) - } - }) - - druid.RegisterAura(core.Aura{ - Label: "Infected Wounds Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() && (druid.Shred.IsEqual(spell) || druid.Maul.IsEqual(spell) || druid.MangleCat.IsEqual(spell) || druid.MangleBear.IsEqual(spell)) { - iwAuras.Get(result.Target).Activate(sim) - } - }, - }) -} +// func (druid *Druid) setupNaturesGrace() { +// if druid.Talents.NaturesGrace == 0 { +// return +// } + +// druid.NaturesGraceProcAura = druid.RegisterAura(core.Aura{ +// Label: "Natures Grace Proc", +// ActionID: core.ActionID{SpellID: 16886}, +// Duration: time.Second * 3, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// druid.MultiplyCastSpeed(1.2) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// druid.MultiplyCastSpeed(1 / 1.2) +// }, +// }) + +// procChance := []float64{0, .33, .66, 1}[druid.Talents.NaturesGrace] + +// druid.RegisterAura(core.Aura{ +// Label: "Natures Grace", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Outcome.Matches(core.OutcomeCrit) { +// return +// } +// if spell.Flags.Matches(SpellFlagNaturesGrace) && sim.Proc(procChance, "Natures Grace") { +// druid.NaturesGraceProcAura.Activate(sim) +// } +// }, +// }) +// } + +// func (druid *Druid) registerNaturesSwiftnessCD() { +// if !druid.Talents.NaturesSwiftness { +// return +// } +// actionID := core.ActionID{SpellID: 17116} + +// var nsAura *core.Aura +// nsSpell := druid.RegisterSpell(Humanoid|Moonkin|Tree, core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagNoOnCastComplete, +// Cast: core.CastConfig{ +// CD: core.Cooldown{ +// Timer: druid.NewTimer(), +// Duration: time.Minute * 3, +// }, +// }, +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// nsAura.Activate(sim) +// }, +// }) + +// nsAura = druid.RegisterAura(core.Aura{ +// Label: "Natures Swiftness", +// ActionID: actionID, +// Duration: core.NeverExpires, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// if druid.Starfire != nil { +// druid.Starfire.CastTimeMultiplier -= 1 +// } +// if druid.Wrath != nil { +// druid.Wrath.CastTimeMultiplier -= 1 +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// if druid.Starfire != nil { +// druid.Starfire.CastTimeMultiplier += 1 +// } +// if druid.Wrath != nil { +// druid.Wrath.CastTimeMultiplier += 1 +// } +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if !druid.Wrath.IsEqual(spell) && !druid.Starfire.IsEqual(spell) { +// return +// } + +// // Remove the buff and put skill on CD +// aura.Deactivate(sim) +// nsSpell.CD.Use(sim) +// druid.UpdateMajorCooldowns() +// }, +// }) + +// druid.AddMajorCooldown(core.MajorCooldown{ +// Spell: nsSpell.Spell, +// Type: core.CooldownTypeDPS, +// ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { +// // Don't use NS unless we're casting a full-length starfire or wrath. +// return !character.HasTemporarySpellCastSpeedIncrease() +// }, +// }) +// } + +// func (druid *Druid) applyEarthAndMoon() { +// if druid.Talents.EarthAndMoon == 0 { +// return +// } + +// eamAuras := druid.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { +// return core.EarthAndMoonAura(target, druid.Talents.EarthAndMoon) +// }) +// druid.Env.RegisterPreFinalizeEffect(func() { +// if druid.Starfire != nil { +// druid.Starfire.RelatedAuras = append(druid.Starfire.RelatedAuras, eamAuras) +// } +// if druid.Wrath != nil { +// druid.Wrath.RelatedAuras = append(druid.Wrath.RelatedAuras, eamAuras) +// } +// }) + +// earthAndMoonSpell := druid.RegisterSpell(Any, core.SpellConfig{ +// ActionID: core.ActionID{SpellID: 60432}, +// ProcMask: core.ProcMaskSuppressedProc, +// Flags: core.SpellFlagNoLogs, +// ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { +// eamAuras.Get(target).Activate(sim) +// }, +// }) + +// druid.RegisterAura(core.Aura{ +// Label: "Earth And Moon Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Landed() && (druid.Starfire.IsEqual(spell) || druid.Wrath.IsEqual(spell)) { +// earthAndMoonSpell.Cast(sim, result.Target) +// } +// }, +// }) +// } + +// func (druid *Druid) applyPrimalFury() { +// if druid.Talents.PrimalFury == 0 { +// return +// } + +// procChance := []float64{0, 0.5, 1}[druid.Talents.PrimalFury] +// actionID := core.ActionID{SpellID: 37117} +// rageMetrics := druid.NewRageMetrics(actionID) +// cpMetrics := druid.NewComboPointMetrics(actionID) + +// druid.RegisterAura(core.Aura{ +// Label: "Primal Fury", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if druid.InForm(Bear) { +// if result.Outcome.Matches(core.OutcomeCrit) { +// if sim.Proc(procChance, "Primal Fury") { +// druid.AddRage(sim, 5, rageMetrics) +// } +// } +// } else if druid.InForm(Cat) { +// if druid.IsMangle(spell) || druid.Shred.IsEqual(spell) || druid.Rake.IsEqual(spell) { +// if result.Outcome.Matches(core.OutcomeCrit) { +// if sim.Proc(procChance, "Primal Fury") { +// druid.AddComboPoints(sim, 1, cpMetrics) +// } +// } +// } +// } +// }, +// }) +// } + +// // Modifies the Bleed aura to apply the bonus. +// func (druid *Druid) applyRendAndTear(aura core.Aura) core.Aura { +// if druid.FerociousBite == nil || druid.Talents.RendAndTear == 0 || druid.AssumeBleedActive { +// return aura +// } + +// bonusCrit := 5.0 * float64(druid.Talents.RendAndTear) * core.CritRatingPerCritChance + +// aura.ApplyOnGain(func(aura *core.Aura, sim *core.Simulation) { +// if druid.BleedsActive == 0 { +// druid.FerociousBite.BonusCritRating += bonusCrit +// } +// druid.BleedsActive++ +// }) +// aura.ApplyOnExpire(func(aura *core.Aura, sim *core.Simulation) { +// druid.BleedsActive-- +// if druid.BleedsActive == 0 { +// druid.FerociousBite.BonusCritRating -= bonusCrit +// } +// }) + +// return aura +// } + +// func (druid *Druid) applyOmenOfClarity() { +// // Feral 2p needs clearcasting aura +// if !druid.Talents.OmenOfClarity && !druid.HasSetBonus(ItemSetNightsongBattlegear, 2) { +// return +// } + +// // T10-2P +// var lasherweave2P *core.Aura +// if druid.HasSetBonus(ItemSetLasherweaveRegalia, 2) { +// lasherweave2P = druid.RegisterAura(core.Aura{ +// Label: "T10-2P proc", +// ActionID: core.ActionID{SpellID: 70718}, +// Duration: time.Second * 6, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexArcane] *= 1.15 +// druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] *= 1.15 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexArcane] /= 1.15 +// druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] /= 1.15 +// }, +// }) +// } + +// var affectedSpells []*DruidSpell +// druid.ClearcastingAura = druid.RegisterAura(core.Aura{ +// Label: "Clearcasting", +// ActionID: core.ActionID{SpellID: 16870}, +// Duration: time.Second * 15, +// OnInit: func(aura *core.Aura, sim *core.Simulation) { +// affectedSpells = core.FilterSlice([]*DruidSpell{ +// // Balance +// druid.Hurricane, +// druid.InsectSwarm, +// druid.Moonfire, +// // TODO druid.Starfall, not sure how the proc chance is affected. +// druid.Starfire, +// druid.Typhoon, +// druid.Wrath, + +// // Feral +// druid.DemoralizingRoar, +// druid.FerociousBite, +// druid.Lacerate, +// druid.MangleBear, +// druid.MangleCat, +// druid.Maul, +// druid.Rake, +// druid.Rip, +// druid.Shred, +// druid.SwipeBear, +// druid.SwipeCat, +// }, func(spell *DruidSpell) bool { return spell != nil }) +// }, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range affectedSpells { +// spell.CostMultiplier -= 1 +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range affectedSpells { +// spell.CostMultiplier += 1 +// } +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if aura.RemainingDuration(sim) == aura.Duration { +// // OnCastComplete is called after OnSpellHitDealt / etc, so don't deactivate +// // if it was just activated. +// return +// } + +// for _, as := range affectedSpells { +// if as.IsEqual(spell) { +// aura.Deactivate(sim) +// break +// } +// } +// }, +// }) + +// if !druid.Talents.OmenOfClarity { +// return +// } + +// druid.ProcOoc = func(sim *core.Simulation) { +// druid.ClearcastingAura.Activate(sim) +// if lasherweave2P != nil { +// lasherweave2P.Activate(sim) +// } +// } + +// hasOocGlyph := druid.HasMajorGlyph(proto.DruidMajorGlyph_GlyphOfOmenOfClarity) + +// druid.RegisterAura(core.Aura{ +// Label: "Omen of Clarity", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() { +// return +// } + +// // https://github.com/JamminL/wotlk-classic-bugs/issues/66#issuecomment-1182017571 +// if druid.HurricaneTickSpell.IsEqual(spell) { +// curCastTickSpeed := spell.CurDot().TickPeriod().Seconds() / 10 +// hurricaneCoeff := 1.0 - (7.0 / 9.0) +// spellCoeff := hurricaneCoeff * curCastTickSpeed +// chanceToProc := ((1.5 / 60) * 3.5) * spellCoeff +// if sim.RandomFloat("Clearcasting") < chanceToProc { +// druid.ProcOoc(sim) +// } +// } else if druid.AutoAttacks.PPMProc(sim, 3.5, core.ProcMaskMeleeWhiteHit, "Omen of Clarity", spell) { // Melee +// druid.ProcOoc(sim) +// } else if spell.Flags.Matches(SpellFlagOmenTrigger) { // Spells +// // Heavily based on comment here +// // https://github.com/JamminL/wotlk-classic-bugs/issues/66#issuecomment-1182017571 +// // Instants are treated as 1.5 +// // Uses current cast time rather than default cast time (PPM is constant with haste) +// castTime := spell.CurCast.CastTime.Seconds() +// if castTime == 0 { +// castTime = 1.5 +// } + +// chanceToProc := (castTime / 60) * 3.5 +// if druid.Typhoon.IsEqual(spell) { // Add Typhoon +// chanceToProc *= 0.25 +// } else if druid.Moonfire.IsEqual(spell) { // Add Moonfire +// chanceToProc *= 0.076 +// } else if druid.GiftOfTheWild.IsEqual(spell) { // Add Gift of the Wild +// // the above comment says it's 0.0875 * (1-0.924) which apparently is out-dated, +// // there is no longer an instant suppression factor +// // we assume 30 targets (25man + pets) +// chanceToProc = 1 - math.Pow(1-chanceToProc, 30) +// } else { +// chanceToProc *= 0.666 +// } +// if sim.RandomFloat("Clearcasting") < chanceToProc { +// druid.ProcOoc(sim) +// } +// } +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if druid.FaerieFire.IsEqual(spell) && druid.InForm(Cat|Bear) && hasOocGlyph { +// druid.ProcOoc(sim) +// } +// }, +// }) +// } + +// func (druid *Druid) applyEclipse() { +// druid.SolarICD = core.Cooldown{Timer: druid.NewTimer(), Duration: 0} +// druid.LunarICD = core.Cooldown{Timer: druid.NewTimer(), Duration: 0} +// if druid.Talents.Eclipse == 0 { +// return +// } + +// // Delay between eclipses +// eclipseDuration := time.Millisecond * 15000 +// interEclipseDelay := eclipseDuration - time.Millisecond*500 + +// // Solar +// solarProcChance := (1.0 / 3.0) * float64(druid.Talents.Eclipse) +// solarProcMultiplier := 1.4 + core.TernaryFloat64(druid.HasSetBonus(ItemSetNightsongGarb, 2), 0.07, 0) +// druid.SolarICD.Duration = time.Millisecond * 30000 +// druid.SolarEclipseProcAura = druid.RegisterAura(core.Aura{ +// Icd: &druid.SolarICD, +// Label: "Solar Eclipse proc", +// Duration: eclipseDuration, +// ActionID: core.ActionID{SpellID: 48517}, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// druid.Wrath.DamageMultiplier *= solarProcMultiplier +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// druid.Wrath.DamageMultiplier /= solarProcMultiplier +// }, +// }) + +// druid.RegisterAura(core.Aura{ +// Label: "Eclipse (Solar)", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Outcome.Matches(core.OutcomeCrit) { +// return +// } +// if !druid.Starfire.IsEqual(spell) { +// return +// } +// if !druid.SolarICD.Timer.IsReady(sim) { +// return +// } +// if druid.LunarICD.Timer.TimeToReady(sim) > interEclipseDelay { +// return +// } +// if sim.RandomFloat("Eclipse (Solar)") < solarProcChance { +// druid.SolarICD.Use(sim) +// druid.SolarEclipseProcAura.Activate(sim) +// } +// }, +// }) + +// // Lunar +// lunarProcChance := 0.2 * float64(druid.Talents.Eclipse) +// lunarBonusCrit := (40 + core.TernaryFloat64(druid.HasSetBonus(ItemSetNightsongGarb, 2), 7, 0)) * core.CritRatingPerCritChance +// druid.LunarICD.Duration = time.Millisecond * 30000 +// druid.LunarEclipseProcAura = druid.RegisterAura(core.Aura{ +// Icd: &druid.LunarICD, +// Label: "Lunar Eclipse proc", +// Duration: eclipseDuration, +// ActionID: core.ActionID{SpellID: 48518}, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// druid.Starfire.BonusCritRating += lunarBonusCrit +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// druid.Starfire.BonusCritRating -= lunarBonusCrit +// }, +// }) +// druid.RegisterAura(core.Aura{ +// Label: "Eclipse (Lunar)", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Outcome.Matches(core.OutcomeCrit) { +// return +// } +// if !druid.Wrath.IsEqual(spell) { +// return +// } +// if !druid.LunarICD.Timer.IsReady(sim) { +// return +// } +// if druid.SolarICD.Timer.TimeToReady(sim) > interEclipseDelay { +// return +// } +// if sim.RandomFloat("Eclipse (Lunar)") < lunarProcChance { +// druid.LunarICD.Use(sim) +// druid.LunarEclipseProcAura.Activate(sim) +// } +// }, +// }) +// } + +// func (druid *Druid) applyOwlkinFrenzy() { +// if druid.Talents.OwlkinFrenzy == 0 { +// return +// } + +// druid.OwlkinFrenzyAura = druid.RegisterAura(core.Aura{ +// Label: "Owlkin Frenzy proc", +// ActionID: core.ActionID{SpellID: 48393}, +// Duration: time.Second * 10, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// druid.PseudoStats.DamageDealtMultiplier *= 1.1 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// druid.PseudoStats.DamageDealtMultiplier /= 1.1 +// }, +// }) +// } + +// func (druid *Druid) applyImprovedLotp() { +// if druid.Talents.ImprovedLeaderOfThePack == 0 { +// return +// } + +// actionID := core.ActionID{SpellID: 34300} +// manaMetrics := druid.NewManaMetrics(actionID) +// healthMetrics := druid.NewHealthMetrics(actionID) +// manaRestore := float64(druid.Talents.ImprovedLeaderOfThePack) * 0.04 +// healthRestore := 0.5 * manaRestore + +// icd := core.Cooldown{ +// Timer: druid.NewTimer(), +// Duration: time.Second * 6, +// } + +// druid.RegisterAura(core.Aura{ +// Icd: &icd, +// Label: "Improved Leader of the Pack", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() { +// return +// } +// if !spell.ProcMask.Matches(core.ProcMaskMeleeOrRanged) || !result.Outcome.Matches(core.OutcomeCrit) { +// return +// } +// if !icd.IsReady(sim) { +// return +// } +// icd.Use(sim) +// druid.AddMana(sim, druid.MaxMana()*manaRestore, manaMetrics) +// druid.GainHealth(sim, druid.MaxHealth()*healthRestore, healthMetrics) +// }, +// }) +// } + +// func (druid *Druid) applyPredatoryInstincts() { +// if druid.Talents.PredatoryInstincts == 0 { +// return +// } + +// onGainMod := druid.MeleeCritMultiplier(Cat) +// onExpireMod := druid.MeleeCritMultiplier(Humanoid) + +// druid.PredatoryInstinctsAura = druid.RegisterAura(core.Aura{ +// Label: "Predatory Instincts", +// Duration: core.NeverExpires, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// druid.Lacerate.CritMultiplier = onGainMod +// druid.Rip.CritMultiplier = onGainMod +// druid.Rake.CritMultiplier = onGainMod +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// druid.Lacerate.CritMultiplier = onExpireMod +// druid.Rip.CritMultiplier = onExpireMod +// druid.Rake.CritMultiplier = onExpireMod +// }, +// }) +// } + +// func (druid *Druid) applyNaturalReaction() { +// if druid.Talents.NaturalReaction == 0 { +// return +// } + +// actionID := core.ActionID{SpellID: 59072} +// rageMetrics := druid.NewRageMetrics(actionID) +// rageAdded := float64(druid.Talents.NaturalReaction) + +// core.MakeProcTriggerAura(&druid.Unit, core.ProcTrigger{ +// Name: "Natural Reaction Trigger", +// Callback: core.CallbackOnSpellHitTaken, +// ProcMask: core.ProcMaskMelee, +// Handler: func(sim *core.Simulation, _ *core.Spell, result *core.SpellResult) { +// if druid.InForm(Bear) && result.Outcome.Matches(core.OutcomeDodge) { +// druid.AddRage(sim, rageAdded, rageMetrics) +// } +// }, +// }) +// } + +// func (druid *Druid) applyInfectedWounds() { +// if druid.Talents.InfectedWounds == 0 { +// return +// } + +// iwAuras := druid.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { +// return core.InfectedWoundsAura(target, druid.Talents.InfectedWounds) +// }) +// druid.Env.RegisterPreFinalizeEffect(func() { +// if druid.Shred != nil { +// druid.Shred.RelatedAuras = append(druid.Shred.RelatedAuras, iwAuras) +// } +// if druid.MangleCat != nil { +// druid.MangleCat.RelatedAuras = append(druid.MangleCat.RelatedAuras, iwAuras) +// } +// if druid.MangleBear != nil { +// druid.MangleBear.RelatedAuras = append(druid.MangleBear.RelatedAuras, iwAuras) +// } +// if druid.Maul != nil { +// druid.Maul.RelatedAuras = append(druid.Maul.RelatedAuras, iwAuras) +// } +// }) + +// druid.RegisterAura(core.Aura{ +// Label: "Infected Wounds Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Landed() && (druid.Shred.IsEqual(spell) || druid.Maul.IsEqual(spell) || druid.MangleCat.IsEqual(spell) || druid.MangleBear.IsEqual(spell)) { +// iwAuras.Get(result.Target).Activate(sim) +// } +// }, +// }) +// } diff --git a/sim/hunter/aimed_shot.go b/sim/hunter/_aimed_shot.go similarity index 100% rename from sim/hunter/aimed_shot.go rename to sim/hunter/_aimed_shot.go diff --git a/sim/hunter/arcane_shot.go b/sim/hunter/_arcane_shot.go similarity index 100% rename from sim/hunter/arcane_shot.go rename to sim/hunter/_arcane_shot.go diff --git a/sim/hunter/aspects.go b/sim/hunter/_aspects.go similarity index 100% rename from sim/hunter/aspects.go rename to sim/hunter/_aspects.go diff --git a/sim/hunter/black_arrow.go b/sim/hunter/_black_arrow.go similarity index 100% rename from sim/hunter/black_arrow.go rename to sim/hunter/_black_arrow.go diff --git a/sim/hunter/chimera_shot.go b/sim/hunter/_chimera_shot.go similarity index 100% rename from sim/hunter/chimera_shot.go rename to sim/hunter/_chimera_shot.go diff --git a/sim/hunter/explosive_shot.go b/sim/hunter/_explosive_shot.go similarity index 100% rename from sim/hunter/explosive_shot.go rename to sim/hunter/_explosive_shot.go diff --git a/sim/hunter/explosive_trap.go b/sim/hunter/_explosive_trap.go similarity index 100% rename from sim/hunter/explosive_trap.go rename to sim/hunter/_explosive_trap.go diff --git a/sim/hunter/items.go b/sim/hunter/_items.go similarity index 100% rename from sim/hunter/items.go rename to sim/hunter/_items.go diff --git a/sim/hunter/kill_command.go b/sim/hunter/_kill_command.go similarity index 100% rename from sim/hunter/kill_command.go rename to sim/hunter/_kill_command.go diff --git a/sim/hunter/kill_shot.go b/sim/hunter/_kill_shot.go similarity index 100% rename from sim/hunter/kill_shot.go rename to sim/hunter/_kill_shot.go diff --git a/sim/hunter/multi_shot.go b/sim/hunter/_multi_shot.go similarity index 100% rename from sim/hunter/multi_shot.go rename to sim/hunter/_multi_shot.go diff --git a/sim/hunter/pet.go b/sim/hunter/_pet.go similarity index 100% rename from sim/hunter/pet.go rename to sim/hunter/_pet.go diff --git a/sim/hunter/pet_abilities.go b/sim/hunter/_pet_abilities.go similarity index 100% rename from sim/hunter/pet_abilities.go rename to sim/hunter/_pet_abilities.go diff --git a/sim/hunter/pet_talents.go b/sim/hunter/_pet_talents.go similarity index 100% rename from sim/hunter/pet_talents.go rename to sim/hunter/_pet_talents.go diff --git a/sim/hunter/rapid_fire.go b/sim/hunter/_rapid_fire.go similarity index 100% rename from sim/hunter/rapid_fire.go rename to sim/hunter/_rapid_fire.go diff --git a/sim/hunter/raptor_strike.go b/sim/hunter/_raptor_strike.go similarity index 100% rename from sim/hunter/raptor_strike.go rename to sim/hunter/_raptor_strike.go diff --git a/sim/hunter/scorpid_sting.go b/sim/hunter/_scorpid_sting.go similarity index 100% rename from sim/hunter/scorpid_sting.go rename to sim/hunter/_scorpid_sting.go diff --git a/sim/hunter/serpent_sting.go b/sim/hunter/_serpent_sting.go similarity index 100% rename from sim/hunter/serpent_sting.go rename to sim/hunter/_serpent_sting.go diff --git a/sim/hunter/silencing_shot.go b/sim/hunter/_silencing_shot.go similarity index 100% rename from sim/hunter/silencing_shot.go rename to sim/hunter/_silencing_shot.go diff --git a/sim/hunter/steady_shot.go b/sim/hunter/_steady_shot.go similarity index 100% rename from sim/hunter/steady_shot.go rename to sim/hunter/_steady_shot.go diff --git a/sim/hunter/volley.go b/sim/hunter/_volley.go similarity index 100% rename from sim/hunter/volley.go rename to sim/hunter/_volley.go diff --git a/sim/hunter/wotlk_items.go b/sim/hunter/_wotlk_items.go similarity index 100% rename from sim/hunter/wotlk_items.go rename to sim/hunter/_wotlk_items.go diff --git a/sim/hunter/hunter.go b/sim/hunter/hunter.go index a76f5d0eb0..820dd5cd1d 100644 --- a/sim/hunter/hunter.go +++ b/sim/hunter/hunter.go @@ -21,7 +21,7 @@ type Hunter struct { MarksmanshipOptions *proto.MarksmanshipHunter_Options SurvivalOptions *proto.SurvivalHunter_Options - pet *HunterPet + //pet *HunterPet AmmoDPS float64 AmmoDamageBonus float64 @@ -79,53 +79,53 @@ func (hunter *Hunter) GetHunter() *Hunter { } func (hunter *Hunter) AddRaidBuffs(raidBuffs *proto.RaidBuffs) { - if hunter.Talents.TrueshotAura { - raidBuffs.TrueshotAura = true - } - if hunter.Talents.FerociousInspiration == 3 && hunter.pet != nil { - raidBuffs.FerociousInspiration = true - } + // if hunter.Talents.TrueshotAura { + // raidBuffs.TrueshotAura = true + // } + // if hunter.Talents.FerociousInspiration == 3 && hunter.pet != nil { + // raidBuffs.FerociousInspiration = true + // } } func (hunter *Hunter) AddPartyBuffs(_ *proto.PartyBuffs) { } func (hunter *Hunter) Initialize() { // Update auto crit multipliers now that we have the targets. - hunter.AutoAttacks.MHConfig().CritMultiplier = hunter.critMultiplier(false, false, false) - hunter.AutoAttacks.OHConfig().CritMultiplier = hunter.critMultiplier(false, false, false) - hunter.AutoAttacks.RangedConfig().CritMultiplier = hunter.critMultiplier(false, false, false) - - hunter.registerAspectOfTheDragonhawkSpell() - hunter.registerAspectOfTheViperSpell() - - multiShotTimer := hunter.NewTimer() - arcaneShotTimer := hunter.NewTimer() - fireTrapTimer := hunter.NewTimer() - - hunter.registerAimedShotSpell(multiShotTimer) - hunter.registerArcaneShotSpell(arcaneShotTimer) - hunter.registerBlackArrowSpell(fireTrapTimer) - hunter.registerChimeraShotSpell() - hunter.registerExplosiveShotSpell(arcaneShotTimer) - hunter.registerExplosiveTrapSpell(fireTrapTimer) - hunter.registerKillShotSpell() - hunter.registerMultiShotSpell(multiShotTimer) - hunter.registerRaptorStrikeSpell() - hunter.registerScorpidStingSpell() - hunter.registerSerpentStingSpell() - hunter.registerSilencingShotSpell() - hunter.registerSteadyShotSpell() - hunter.registerVolleySpell() - - hunter.registerKillCommandCD() - hunter.registerRapidFireCD() - - if hunter.Options.UseHuntersMark { - hunter.RegisterPrepullAction(0, func(sim *core.Simulation) { - huntersMarkAura := core.HuntersMarkAura(hunter.CurrentTarget, hunter.Talents.ImprovedHuntersMark, hunter.HasMajorGlyph(proto.HunterMajorGlyph_GlyphOfHuntersMark)) - huntersMarkAura.Activate(sim) - }) - } + // hunter.AutoAttacks.MHConfig().CritMultiplier = hunter.critMultiplier(false, false, false) + // hunter.AutoAttacks.OHConfig().CritMultiplier = hunter.critMultiplier(false, false, false) + // hunter.AutoAttacks.RangedConfig().CritMultiplier = hunter.critMultiplier(false, false, false) + + // hunter.registerAspectOfTheDragonhawkSpell() + // hunter.registerAspectOfTheViperSpell() + + // multiShotTimer := hunter.NewTimer() + // arcaneShotTimer := hunter.NewTimer() + // fireTrapTimer := hunter.NewTimer() + + // hunter.registerAimedShotSpell(multiShotTimer) + // hunter.registerArcaneShotSpell(arcaneShotTimer) + // hunter.registerBlackArrowSpell(fireTrapTimer) + // hunter.registerChimeraShotSpell() + // hunter.registerExplosiveShotSpell(arcaneShotTimer) + // hunter.registerExplosiveTrapSpell(fireTrapTimer) + // hunter.registerKillShotSpell() + // hunter.registerMultiShotSpell(multiShotTimer) + // hunter.registerRaptorStrikeSpell() + // hunter.registerScorpidStingSpell() + // hunter.registerSerpentStingSpell() + // hunter.registerSilencingShotSpell() + // hunter.registerSteadyShotSpell() + // hunter.registerVolleySpell() + + // hunter.registerKillCommandCD() + // hunter.registerRapidFireCD() + + // if hunter.Options.UseHuntersMark { + // hunter.RegisterPrepullAction(0, func(sim *core.Simulation) { + // huntersMarkAura := core.HuntersMarkAura(hunter.CurrentTarget, hunter.Talents.ImprovedHuntersMark, hunter.HasMajorGlyph(proto.HunterMajorGlyph_GlyphOfHuntersMark)) + // huntersMarkAura.Activate(sim) + // }) + // } } func (hunter *Hunter) Reset(_ *core.Simulation) { @@ -169,23 +169,23 @@ func NewHunter(character *core.Character, options *proto.Player, hunterOptions * hunter.NormalizedAmmoDamageBonus = hunter.AmmoDPS * 2.8 } - hunter.EnableAutoAttacks(hunter, core.AutoAttackOptions{ - // We don't know crit multiplier until later when we see the target so just - // use 0 for now. - MainHand: hunter.WeaponFromMainHand(0), - OffHand: hunter.WeaponFromOffHand(0), - Ranged: rangedWeapon, - ReplaceMHSwing: hunter.TryRaptorStrike, - AutoSwingRanged: true, - }) - hunter.AutoAttacks.RangedConfig().ApplyEffects = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseDamage := hunter.RangedWeaponDamage(sim, spell.RangedAttackPower(target)) + - hunter.AmmoDamageBonus + - spell.BonusWeaponDamage() - spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) - } - - hunter.pet = hunter.NewHunterPet() + // hunter.EnableAutoAttacks(hunter, core.AutoAttackOptions{ + // // We don't know crit multiplier until later when we see the target so just + // // use 0 for now. + // MainHand: hunter.WeaponFromMainHand(0), + // OffHand: hunter.WeaponFromOffHand(0), + // Ranged: rangedWeapon, + // ReplaceMHSwing: hunter.TryRaptorStrike, + // AutoSwingRanged: true, + // }) + // hunter.AutoAttacks.RangedConfig().ApplyEffects = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + // baseDamage := hunter.RangedWeaponDamage(sim, spell.RangedAttackPower(target)) + + // hunter.AmmoDamageBonus + + // spell.BonusWeaponDamage() + // spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) + // } + + // hunter.pet = hunter.NewHunterPet() hunter.AddStatDependency(stats.Strength, stats.AttackPower, 1) hunter.AddStatDependency(stats.Agility, stats.AttackPower, 1) diff --git a/sim/hunter/talents.go b/sim/hunter/talents.go index 2434fbc18c..33506063ce 100644 --- a/sim/hunter/talents.go +++ b/sim/hunter/talents.go @@ -1,878 +1,870 @@ package hunter -import ( - "time" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" -) - func (hunter *Hunter) ApplyTalents() { - if hunter.pet != nil { - hunter.applyFocusedFire() - hunter.applyFrenzy() - hunter.registerBestialWrathCD() - - hunter.pet.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*2*float64(hunter.Talents.Ferocity)) - hunter.pet.AddStat(stats.SpellCrit, core.CritRatingPerCritChance*2*float64(hunter.Talents.Ferocity)) - hunter.pet.AddStat(stats.Dodge, 3*core.DodgeRatingPerDodgeChance*float64(hunter.Talents.CatlikeReflexes)) - hunter.pet.PseudoStats.DamageDealtMultiplier *= 1 + 0.03*float64(hunter.Talents.UnleashedFury) - hunter.pet.PseudoStats.DamageDealtMultiplier *= 1 + 0.04*float64(hunter.Talents.KindredSpirits) - hunter.pet.PseudoStats.MeleeSpeedMultiplier *= 1 + 0.04*float64(hunter.Talents.SerpentsSwiftness) - - if hunter.Talents.AnimalHandler != 0 { - hunter.pet.MultiplyStat(stats.AttackPower, 1+(0.05*float64(hunter.Talents.AnimalHandler))) - } - hunter.pet.ApplyTalents() - } - - hunter.AddStat(stats.MeleeHit, core.MeleeHitRatingPerHitChance*1*float64(hunter.Talents.FocusedAim)) - hunter.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*1*float64(hunter.Talents.KillerInstinct)) - hunter.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*1*float64(hunter.Talents.MasterMarksman)) - hunter.AddStat(stats.Parry, core.ParryRatingPerParryChance*1*float64(hunter.Talents.Deflection)) - hunter.AddStat(stats.Dodge, 1*core.DodgeRatingPerDodgeChance*float64(hunter.Talents.CatlikeReflexes)) - hunter.PseudoStats.RangedSpeedMultiplier *= 1 + 0.04*float64(hunter.Talents.SerpentsSwiftness) - hunter.PseudoStats.DamageTakenMultiplier *= 1 - 0.02*float64(hunter.Talents.SurvivalInstincts) - hunter.AutoAttacks.RangedConfig().DamageMultiplier *= hunter.markedForDeathMultiplier() - - if hunter.Talents.LethalShots > 0 { - hunter.AddBonusRangedCritRating(1 * float64(hunter.Talents.LethalShots) * core.CritRatingPerCritChance) - } - if hunter.Talents.RangedWeaponSpecialization > 0 { - mult := 1 + []float64{0, .01, .03, .05}[hunter.Talents.RangedWeaponSpecialization] - hunter.OnSpellRegistered(func(spell *core.Spell) { - if spell.ProcMask.Matches(core.ProcMaskRanged) { - spell.DamageMultiplier *= mult - } - }) - } - - if hunter.Talents.EnduranceTraining > 0 { - healthBonus := 0.01 * float64(hunter.Talents.EnduranceTraining) - hunter.MultiplyStat(stats.Health, 1.0+healthBonus) - if hunter.pet != nil { - hunter.pet.MultiplyStat(stats.Health, 1.0+2*healthBonus) - } - } - - if hunter.Talents.ThickHide > 0 { - var hunterBonus, petBonus float64 - if hunter.Talents.ThickHide == 1 { - hunterBonus = 0.04 - petBonus = 0.07 - } else if hunter.Talents.ThickHide == 2 { - hunterBonus = 0.07 - petBonus = 0.14 - } else if hunter.Talents.ThickHide == 3 { - hunterBonus = 0.1 - petBonus = 0.2 - } - hunter.ApplyEquipScaling(stats.Armor, 1.0+hunterBonus) - if hunter.pet != nil { - hunter.pet.MultiplyStat(stats.Armor, 1.0+petBonus) - } - } - - if hunter.Talents.Survivalist > 0 { - hunter.MultiplyStat(stats.Stamina, 1.0+0.02*float64(hunter.Talents.Survivalist)) - } - - if hunter.Talents.CombatExperience > 0 { - bonus := 1.0 + (0.02 * float64(hunter.Talents.CombatExperience)) - hunter.MultiplyStat(stats.Agility, bonus) - hunter.MultiplyStat(stats.Intellect, bonus) - } - if hunter.Talents.CarefulAim > 0 { - hunter.AddStatDependency(stats.Intellect, stats.RangedAttackPower, (1.0/3.0)*float64(hunter.Talents.CarefulAim)) - } - if hunter.Talents.HunterVsWild > 0 { - bonus := 0.1 * float64(hunter.Talents.HunterVsWild) - hunter.AddStatDependency(stats.Stamina, stats.AttackPower, bonus) - hunter.AddStatDependency(stats.Stamina, stats.RangedAttackPower, bonus) - } - if hunter.Talents.LightningReflexes > 0 { - agiBonus := 0.03 * float64(hunter.Talents.LightningReflexes) - hunter.MultiplyStat(stats.Agility, 1.0+agiBonus) - } - if hunter.Talents.HuntingParty > 0 { - agiBonus := 0.01 * float64(hunter.Talents.HuntingParty) - hunter.MultiplyStat(stats.Agility, 1.0+agiBonus) - } - - hunter.applySpiritBond() - hunter.applyInvigoration() - hunter.applyCobraStrikes() - hunter.applyGoForTheThroat() - hunter.applyPiercingShots() - hunter.applyWildQuiver() - hunter.applyImprovedTracking() - hunter.applyThrillOfTheHunt() - hunter.applyLockAndLoad() - hunter.applyExposeWeakness() - hunter.applyMasterTactician() - hunter.applySniperTraining() - hunter.applyHuntingParty() - - hunter.registerReadinessCD() -} - -func (hunter *Hunter) critMultiplier(isRanged bool, isMFDSpell bool, doubleDipMS bool) float64 { - primaryModifier := 1.0 - secondaryModifier := 0.0 - mortalShotsFactor := 0.06 - - if doubleDipMS { - mortalShotsFactor = 0.12 - } - - if isRanged { - secondaryModifier += mortalShotsFactor * float64(hunter.Talents.MortalShots) - if isMFDSpell { - secondaryModifier += 0.02 * float64(hunter.Talents.MarkedForDeath) - } - } - - return hunter.MeleeCritMultiplier(primaryModifier, secondaryModifier) -} - -func (hunter *Hunter) markedForDeathMultiplier() float64 { - if hunter.Options.UseHuntersMark || hunter.Env.GetTarget(0).HasAuraWithTag(core.HuntersMarkAuraTag) { - return 1 + .01*float64(hunter.Talents.MarkedForDeath) - } else { - return 1 - } + // if hunter.pet != nil { + // hunter.applyFocusedFire() + // hunter.applyFrenzy() + // hunter.registerBestialWrathCD() + + // hunter.pet.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*2*float64(hunter.Talents.Ferocity)) + // hunter.pet.AddStat(stats.SpellCrit, core.CritRatingPerCritChance*2*float64(hunter.Talents.Ferocity)) + // hunter.pet.AddStat(stats.Dodge, 3*core.DodgeRatingPerDodgeChance*float64(hunter.Talents.CatlikeReflexes)) + // hunter.pet.PseudoStats.DamageDealtMultiplier *= 1 + 0.03*float64(hunter.Talents.UnleashedFury) + // hunter.pet.PseudoStats.DamageDealtMultiplier *= 1 + 0.04*float64(hunter.Talents.KindredSpirits) + // hunter.pet.PseudoStats.MeleeSpeedMultiplier *= 1 + 0.04*float64(hunter.Talents.SerpentsSwiftness) + + // if hunter.Talents.AnimalHandler != 0 { + // hunter.pet.MultiplyStat(stats.AttackPower, 1+(0.05*float64(hunter.Talents.AnimalHandler))) + // } + // hunter.pet.ApplyTalents() + // } + + // hunter.AddStat(stats.MeleeHit, core.MeleeHitRatingPerHitChance*1*float64(hunter.Talents.FocusedAim)) + // hunter.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*1*float64(hunter.Talents.KillerInstinct)) + // hunter.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*1*float64(hunter.Talents.MasterMarksman)) + // hunter.AddStat(stats.Parry, core.ParryRatingPerParryChance*1*float64(hunter.Talents.Deflection)) + // hunter.AddStat(stats.Dodge, 1*core.DodgeRatingPerDodgeChance*float64(hunter.Talents.CatlikeReflexes)) + // hunter.PseudoStats.RangedSpeedMultiplier *= 1 + 0.04*float64(hunter.Talents.SerpentsSwiftness) + // hunter.PseudoStats.DamageTakenMultiplier *= 1 - 0.02*float64(hunter.Talents.SurvivalInstincts) + // hunter.AutoAttacks.RangedConfig().DamageMultiplier *= hunter.markedForDeathMultiplier() + + // if hunter.Talents.LethalShots > 0 { + // hunter.AddBonusRangedCritRating(1 * float64(hunter.Talents.LethalShots) * core.CritRatingPerCritChance) + // } + // if hunter.Talents.RangedWeaponSpecialization > 0 { + // mult := 1 + []float64{0, .01, .03, .05}[hunter.Talents.RangedWeaponSpecialization] + // hunter.OnSpellRegistered(func(spell *core.Spell) { + // if spell.ProcMask.Matches(core.ProcMaskRanged) { + // spell.DamageMultiplier *= mult + // } + // }) + // } + + // if hunter.Talents.EnduranceTraining > 0 { + // healthBonus := 0.01 * float64(hunter.Talents.EnduranceTraining) + // hunter.MultiplyStat(stats.Health, 1.0+healthBonus) + // if hunter.pet != nil { + // hunter.pet.MultiplyStat(stats.Health, 1.0+2*healthBonus) + // } + // } + + // if hunter.Talents.ThickHide > 0 { + // var hunterBonus, petBonus float64 + // if hunter.Talents.ThickHide == 1 { + // hunterBonus = 0.04 + // petBonus = 0.07 + // } else if hunter.Talents.ThickHide == 2 { + // hunterBonus = 0.07 + // petBonus = 0.14 + // } else if hunter.Talents.ThickHide == 3 { + // hunterBonus = 0.1 + // petBonus = 0.2 + // } + // hunter.ApplyEquipScaling(stats.Armor, 1.0+hunterBonus) + // if hunter.pet != nil { + // hunter.pet.MultiplyStat(stats.Armor, 1.0+petBonus) + // } + // } + + // if hunter.Talents.Survivalist > 0 { + // hunter.MultiplyStat(stats.Stamina, 1.0+0.02*float64(hunter.Talents.Survivalist)) + // } + + // if hunter.Talents.CombatExperience > 0 { + // bonus := 1.0 + (0.02 * float64(hunter.Talents.CombatExperience)) + // hunter.MultiplyStat(stats.Agility, bonus) + // hunter.MultiplyStat(stats.Intellect, bonus) + // } + // if hunter.Talents.CarefulAim > 0 { + // hunter.AddStatDependency(stats.Intellect, stats.RangedAttackPower, (1.0/3.0)*float64(hunter.Talents.CarefulAim)) + // } + // if hunter.Talents.HunterVsWild > 0 { + // bonus := 0.1 * float64(hunter.Talents.HunterVsWild) + // hunter.AddStatDependency(stats.Stamina, stats.AttackPower, bonus) + // hunter.AddStatDependency(stats.Stamina, stats.RangedAttackPower, bonus) + // } + // if hunter.Talents.LightningReflexes > 0 { + // agiBonus := 0.03 * float64(hunter.Talents.LightningReflexes) + // hunter.MultiplyStat(stats.Agility, 1.0+agiBonus) + // } + // if hunter.Talents.HuntingParty > 0 { + // agiBonus := 0.01 * float64(hunter.Talents.HuntingParty) + // hunter.MultiplyStat(stats.Agility, 1.0+agiBonus) + // } + + // hunter.applySpiritBond() + // hunter.applyInvigoration() + // hunter.applyCobraStrikes() + // hunter.applyGoForTheThroat() + // hunter.applyPiercingShots() + // hunter.applyWildQuiver() + // hunter.applyImprovedTracking() + // hunter.applyThrillOfTheHunt() + // hunter.applyLockAndLoad() + // hunter.applyExposeWeakness() + // hunter.applyMasterTactician() + // hunter.applySniperTraining() + // hunter.applyHuntingParty() + + // hunter.registerReadinessCD() } -func (hunter *Hunter) applySpiritBond() { - if hunter.Talents.SpiritBond == 0 || hunter.pet == nil { - return - } - - hunter.PseudoStats.HealingTakenMultiplier *= 1 + 0.05*float64(hunter.Talents.SpiritBond) - hunter.pet.PseudoStats.HealingTakenMultiplier *= 1 + 0.05*float64(hunter.Talents.SpiritBond) - - actionID := core.ActionID{SpellID: 20895} - healthMultiplier := 0.01 * float64(hunter.Talents.SpiritBond) - healthMetrics := hunter.NewHealthMetrics(actionID) - petHealthMetrics := hunter.pet.NewHealthMetrics(actionID) - - hunter.RegisterResetEffect(func(sim *core.Simulation) { - core.StartPeriodicAction(sim, core.PeriodicActionOptions{ - Period: time.Second * 10, - OnAction: func(sim *core.Simulation) { - hunter.GainHealth(sim, hunter.MaxHealth()*healthMultiplier, healthMetrics) - hunter.pet.GainHealth(sim, hunter.pet.MaxHealth()*healthMultiplier, petHealthMetrics) - }, - }) - }) -} - -func (hunter *Hunter) applyInvigoration() { - if hunter.Talents.Invigoration == 0 || hunter.pet == nil { - return - } - - procChance := 0.5 * float64(hunter.Talents.Invigoration) - manaMetrics := hunter.NewManaMetrics(core.ActionID{SpellID: 53253}) - - hunter.pet.RegisterAura(core.Aura{ - Label: "Invigoration", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskMeleeSpecial | core.ProcMaskSpellDamage) { - return - } - - if !result.DidCrit() { - return - } - - if sim.Proc(procChance, "Invigoration") { - hunter.AddMana(sim, 0.01*hunter.MaxMana(), manaMetrics) - } - }, - }) -} - -func (hunter *Hunter) applyCobraStrikes() { - if hunter.Talents.CobraStrikes == 0 || hunter.pet == nil { - return - } - - actionID := core.ActionID{SpellID: 53260} - procChance := 0.2 * float64(hunter.Talents.CobraStrikes) - - hunter.pet.CobraStrikesAura = hunter.pet.RegisterAura(core.Aura{ - Label: "Cobra Strikes", - ActionID: actionID, - Duration: time.Second * 10, - MaxStacks: 2, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - hunter.pet.focusDump.BonusCritRating += 100 * core.CritRatingPerCritChance - if hunter.pet.specialAbility != nil { - hunter.pet.specialAbility.BonusCritRating += 100 * core.CritRatingPerCritChance - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - hunter.pet.focusDump.BonusCritRating -= 100 * core.CritRatingPerCritChance - if hunter.pet.specialAbility != nil { - hunter.pet.specialAbility.BonusCritRating -= 100 * core.CritRatingPerCritChance - } - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.ProcMask.Matches(core.ProcMaskMeleeSpecial | core.ProcMaskSpellDamage) { - aura.RemoveStack(sim) - } - }, - }) - - hunter.RegisterAura(core.Aura{ - Label: "Cobra Strikes", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.DidCrit() { - return - } - - if spell != hunter.ArcaneShot && spell != hunter.SteadyShot && spell != hunter.KillShot { - return - } - - if sim.RandomFloat("Cobra Strikes") < procChance { - hunter.pet.CobraStrikesAura.Activate(sim) - hunter.pet.CobraStrikesAura.SetStacks(sim, 2) - } - }, - }) -} - -func (hunter *Hunter) applyPiercingShots() { - if hunter.Talents.PiercingShots == 0 { - return - } - - psSpell := hunter.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 53238}, - SpellSchool: core.SpellSchoolPhysical, - ProcMask: core.ProcMaskEmpty, - Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagIgnoreModifiers, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - - Dot: core.DotConfig{ - Aura: core.Aura{ - Label: "PiercingShots", - Duration: time.Second * 8, - }, - NumberOfTicks: 8, - TickLength: time.Second * 1, - OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - // Specifically account for bleed modifiers, since it still affects the spell, but we're ignoring all modifiers. - dot.SnapshotAttackerMultiplier = target.PseudoStats.PeriodicPhysicalDamageTakenMultiplier - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) - }, - }, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - spell.Dot(target).ApplyOrReset(sim) - spell.CalcAndDealOutcome(sim, target, spell.OutcomeAlwaysHit) - }, - }) - - hunter.RegisterAura(core.Aura{ - Label: "Piercing Shots Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.DidCrit() { - return - } - if spell != hunter.AimedShot && spell != hunter.SteadyShot && spell != hunter.ChimeraShot { - return - } - - dot := psSpell.Dot(result.Target) - outstandingDamage := core.TernaryFloat64(dot.IsActive(), dot.SnapshotBaseDamage*float64(dot.NumberOfTicks-dot.TickCount), 0) - newDamage := result.Damage * 0.1 * float64(hunter.Talents.PiercingShots) - - dot.SnapshotBaseDamage = (outstandingDamage + newDamage) / float64(dot.NumberOfTicks) - psSpell.Cast(sim, result.Target) - }, - }) -} - -func (hunter *Hunter) applyWildQuiver() { - if hunter.Talents.WildQuiver == 0 { - return - } - - actionID := core.ActionID{SpellID: 53217} - procChance := 0.04 * float64(hunter.Talents.WildQuiver) - - wqSpell := hunter.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - SpellSchool: core.SpellSchoolNature, - ProcMask: core.ProcMaskRangedAuto, - Flags: core.SpellFlagNoOnCastComplete, - - DamageMultiplier: 0.8, - CritMultiplier: hunter.critMultiplier(false, false, false), - ThreatMultiplier: 1, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseDamage := spell.Unit.RangedWeaponDamage(sim, spell.RangedAttackPower(target)) + - spell.BonusWeaponDamage() - spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) - }, - }) - - hunter.RegisterAura(core.Aura{ - Label: "Wild Quiver Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell != hunter.AutoAttacks.RangedAuto() { - return - } - - if sim.RandomFloat("Wild Quiver") < procChance { - wqSpell.Cast(sim, result.Target) - } - }, - }) -} - -func (hunter *Hunter) applyFocusedFire() { - if hunter.Talents.FocusedFire == 0 || hunter.pet == nil { - return - } - - hunter.PseudoStats.DamageDealtMultiplier *= 1.0 + 0.01*float64(hunter.Talents.FocusedFire) -} - -func (hunter *Hunter) applyFrenzy() { - if hunter.Talents.Frenzy == 0 { - return - } - - procChance := 0.2 * float64(hunter.Talents.Frenzy) - - procAura := hunter.pet.RegisterAura(core.Aura{ - Label: "Frenzy Proc", - ActionID: core.ActionID{SpellID: 19625}, - Duration: time.Second * 8, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.MultiplyMeleeSpeed(sim, 1.3) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.MultiplyMeleeSpeed(sim, 1/1.3) - }, - }) - - hunter.pet.RegisterAura(core.Aura{ - Label: "Frenzy", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.DidCrit() { - return - } - if sim.Proc(procChance, "Frenzy") { - procAura.Activate(sim) - } - }, - }) -} - -func (hunter *Hunter) applyLongevity(dur time.Duration) time.Duration { - return time.Duration(float64(dur) * (1.0 - 0.1*float64(hunter.Talents.Longevity))) -} - -func (hunter *Hunter) registerBestialWrathCD() { - if !hunter.Talents.BestialWrath { - return - } - if hunter.Talents.TheBeastWithin { - hunter.PseudoStats.DamageDealtMultiplier *= 1.1 - } - - actionID := core.ActionID{SpellID: 19574} - - bestialWrathPetAura := hunter.pet.RegisterAura(core.Aura{ - Label: "Bestial Wrath Pet", - ActionID: actionID, - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.DamageDealtMultiplier *= 1.5 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.DamageDealtMultiplier /= 1.5 - }, - }) - - bestialWrathAura := hunter.RegisterAura(core.Aura{ - Label: "Bestial Wrath", - ActionID: actionID, - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.DamageDealtMultiplier *= 1.1 - aura.Unit.PseudoStats.CostMultiplier -= 0.5 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.DamageDealtMultiplier /= 1.1 - aura.Unit.PseudoStats.CostMultiplier += 0.5 - }, - }) - core.RegisterPercentDamageModifierEffect(bestialWrathAura, 1.1) - - bwSpell := hunter.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.1, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: 1, - }, - CD: core.Cooldown{ - Timer: hunter.NewTimer(), - Duration: hunter.applyLongevity(time.Minute*2 - core.TernaryDuration(hunter.HasMajorGlyph(proto.HunterMajorGlyph_GlyphOfBestialWrath), time.Second*20, 0)), - }, - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - bestialWrathPetAura.Activate(sim) - - if hunter.Talents.TheBeastWithin { - bestialWrathAura.Activate(sim) - } - }, - }) - - hunter.AddMajorCooldown(core.MajorCooldown{ - Spell: bwSpell, - Type: core.CooldownTypeDPS, - }) -} - -func (hunter *Hunter) applyGoForTheThroat() { - if hunter.Talents.GoForTheThroat == 0 { - return - } - if hunter.pet == nil { - return - } - - spellID := []int32{0, 34953, 34953}[hunter.Talents.GoForTheThroat] - focusMetrics := hunter.NewFocusMetrics(core.ActionID{SpellID: spellID}) - - amount := 25.0 * float64(hunter.Talents.GoForTheThroat) - - hunter.RegisterAura(core.Aura{ - Label: "Go for the Throat", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskRanged) || !result.DidCrit() { - return - } - if !hunter.pet.IsEnabled() { - return - } - hunter.pet.AddFocus(sim, amount, focusMetrics) - }, - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.DidCrit() { - return - } - if !hunter.pet.IsEnabled() { - return - } - hunter.pet.AddFocus(sim, amount, focusMetrics) - }, - }) -} - -func (hunter *Hunter) applyImprovedTracking() { - if hunter.Talents.ImprovedTracking == 0 { - return - } - - var applied bool - - hunter.RegisterResetEffect( - func(s *core.Simulation) { - if applied { - return - } - applied = true - - for _, target := range hunter.Env.Encounter.TargetUnits { - switch target.MobType { - case proto.MobType_MobTypeBeast, proto.MobType_MobTypeDemon, - proto.MobType_MobTypeDragonkin, proto.MobType_MobTypeElemental, - proto.MobType_MobTypeGiant, proto.MobType_MobTypeHumanoid, - proto.MobType_MobTypeUndead: - - hunter.AttackTables[target.UnitIndex].DamageDealtMultiplier *= 1.0 + 0.01*float64(hunter.Talents.ImprovedTracking) - } - } - }, - ) -} - -func (hunter *Hunter) applyLockAndLoad() { - if hunter.Talents.LockAndLoad == 0 { - return - } - - actionID := core.ActionID{SpellID: 56344} - procChance := []float64{0, 0.02, 0.04, 0.20}[hunter.Talents.LockAndLoad] - - icd := core.Cooldown{ - Timer: hunter.NewTimer(), - Duration: time.Second * 22, - } - - hunter.LockAndLoadAura = hunter.RegisterAura(core.Aura{ - Icd: &icd, - Label: "Lock and Load Proc", - ActionID: actionID, - Duration: time.Second * 12, - MaxStacks: 2, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - hunter.ArcaneShot.CostMultiplier -= 1 - if hunter.ExplosiveShotR4 != nil { - hunter.ExplosiveShotR4.CostMultiplier -= 1 - hunter.ExplosiveShotR3.CostMultiplier -= 1 - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - hunter.ArcaneShot.CostMultiplier += 1 - if hunter.ExplosiveShotR4 != nil { - hunter.ExplosiveShotR4.CostMultiplier += 1 - hunter.ExplosiveShotR3.CostMultiplier += 1 - } - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == hunter.ArcaneShot || spell == hunter.ExplosiveShotR4 || spell == hunter.ExplosiveShotR3 { - aura.RemoveStack(sim) - hunter.ArcaneShot.CD.Reset() // Shares the CD with explosive shot. - } - }, - }) - - hunter.RegisterAura(core.Aura{ - Label: "Lock and Load Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell != hunter.BlackArrow && spell != hunter.ExplosiveTrap { - return - } - - if !icd.IsReady(sim) { - return - } - - if sim.RandomFloat("Lock and Load") < procChance { - icd.Use(sim) - hunter.LockAndLoadAura.Activate(sim) - hunter.LockAndLoadAura.SetStacks(sim, 2) - } - }, - }) -} - -func (hunter *Hunter) applyThrillOfTheHunt() { - if hunter.Talents.ThrillOfTheHunt == 0 { - return - } - - procChance := float64(hunter.Talents.ThrillOfTheHunt) / 3 - manaMetrics := hunter.NewManaMetrics(core.ActionID{SpellID: 34499}) - - hunter.RegisterAura(core.Aura{ - Label: "Thrill of the Hunt", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - // mask 256 - if !spell.ProcMask.Matches(core.ProcMaskRangedSpecial) { - return - } - - if !result.DidCrit() { - return - } - - if sim.Proc(procChance, "ThrillOfTheHunt") { - hunter.AddMana(sim, spell.CurCast.Cost*0.4, manaMetrics) - } - }, - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.DidCrit() && (spell == hunter.ExplosiveShotR4 || spell == hunter.ExplosiveShotR3) { - // Explosive shot ticks can proc TotH but with 1/3 the bonus. - if sim.Proc(procChance, "ThrillOfTheHunt") { - hunter.AddMana(sim, spell.CurCast.Cost*0.4/3, manaMetrics) - } - } - }, - }) -} - -func (hunter *Hunter) applyExposeWeakness() { - if hunter.Talents.ExposeWeakness == 0 { - return - } - - actionID := core.ActionID{SpellID: 34503} - procChance := float64(hunter.Talents.ExposeWeakness) / 3 - - apDep := hunter.NewDynamicStatDependency(stats.Agility, stats.AttackPower, .25) - rapDep := hunter.NewDynamicStatDependency(stats.Agility, stats.RangedAttackPower, .25) - procAura := hunter.RegisterAura(core.Aura{ - Label: "Expose Weakness Proc", - ActionID: actionID, - Duration: time.Second * 7, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.EnableDynamicStatDep(sim, apDep) - aura.Unit.EnableDynamicStatDep(sim, rapDep) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.DisableDynamicStatDep(sim, apDep) - aura.Unit.DisableDynamicStatDep(sim, rapDep) - }, - }) - - hunter.RegisterAura(core.Aura{ - Label: "Expose Weakness Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskRanged) && spell != hunter.ExplosiveTrap { - return - } - - if !result.DidCrit() { - return - } - - if sim.Proc(procChance, "ExposeWeakness") { - procAura.Activate(sim) - } - }, - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.DidCrit() { - return - } - - if sim.Proc(procChance, "ExposeWeakness") { - procAura.Activate(sim) - } - }, - }) -} - -func (hunter *Hunter) applyMasterTactician() { - if hunter.Talents.MasterTactician == 0 { - return - } - - procChance := 0.1 - critBonus := 2 * core.CritRatingPerCritChance * float64(hunter.Talents.MasterTactician) - - procAura := hunter.NewTemporaryStatsAura("Master Tactician Proc", core.ActionID{SpellID: 34839}, stats.Stats{stats.MeleeCrit: critBonus}, time.Second*8) - - hunter.RegisterAura(core.Aura{ - Label: "Master Tactician", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskRanged) || !result.Landed() { - return - } - - if sim.RandomFloat("Master Tactician") > procChance { - return - } - - procAura.Activate(sim) - }, - }) -} - -func (hunter *Hunter) applySniperTraining() { - if hunter.Talents.SniperTraining == 0 { - return - } - - uptime := hunter.SurvivalOptions.SniperTrainingUptime - if uptime <= 0 { - return - } - uptime = min(1, uptime) - - dmgMod := .02 * float64(hunter.Talents.SniperTraining) - - stAura := hunter.RegisterAura(core.Aura{ - Label: "Sniper Training", - ActionID: core.ActionID{SpellID: 53304}, - Duration: time.Second * 15, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - hunter.SteadyShot.DamageMultiplierAdditive += dmgMod - if hunter.AimedShot != nil { - hunter.AimedShot.DamageMultiplierAdditive += dmgMod - } - if hunter.BlackArrow != nil { - hunter.BlackArrow.DamageMultiplierAdditive += dmgMod - } - if hunter.ExplosiveShotR4 != nil { - hunter.ExplosiveShotR4.DamageMultiplierAdditive += dmgMod - hunter.ExplosiveShotR3.DamageMultiplierAdditive += dmgMod - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - hunter.SteadyShot.DamageMultiplierAdditive -= dmgMod - if hunter.AimedShot != nil { - hunter.AimedShot.DamageMultiplierAdditive -= dmgMod - } - if hunter.BlackArrow != nil { - hunter.BlackArrow.DamageMultiplierAdditive -= dmgMod - } - if hunter.ExplosiveShotR4 != nil { - hunter.ExplosiveShotR4.DamageMultiplierAdditive -= dmgMod - hunter.ExplosiveShotR3.DamageMultiplierAdditive -= dmgMod - } - }, - }) - - core.ApplyFixedUptimeAura(stAura, uptime, time.Second*15, 1) -} - -func (hunter *Hunter) applyHuntingParty() { - if hunter.Talents.HuntingParty == 0 { - return - } - - procChance := float64(hunter.Talents.HuntingParty) / 3 - replSrc := hunter.Env.Raid.NewReplenishmentSource(core.ActionID{SpellID: 53292}) - - hunter.RegisterAura(core.Aura{ - Label: "Hunting Party", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.DidCrit() { - return - } - - if spell != hunter.SteadyShot && spell != hunter.ArcaneShot && spell != hunter.ExplosiveShotR4 && spell != hunter.ExplosiveShotR3 { - return - } - - if procChance == 1 || sim.RandomFloat("Hunting Party") < procChance { - hunter.Env.Raid.ProcReplenishment(sim, replSrc) - } - }, - }) -} - -func (hunter *Hunter) registerReadinessCD() { - if !hunter.Talents.Readiness { - return - } - - actionID := core.ActionID{SpellID: 23989} - - readinessSpell := hunter.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: time.Second * 1, - }, - IgnoreHaste: true, // Hunter GCD is locked - CD: core.Cooldown{ - Timer: hunter.NewTimer(), - Duration: time.Minute * 3, - }, - }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - // Don't use if there are no cooldowns to reset. - return !hunter.RapidFire.IsReady(sim) - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - hunter.RapidFire.CD.Reset() - hunter.MultiShot.CD.Reset() - hunter.ArcaneShot.CD.Reset() - hunter.KillShot.CD.Reset() - hunter.RaptorStrike.CD.Reset() - hunter.ExplosiveTrap.CD.Reset() - if hunter.KillCommand != nil { - hunter.KillCommand.CD.Reset() - } - if hunter.AimedShot != nil { - hunter.AimedShot.CD.Reset() - } - if hunter.SilencingShot != nil { - hunter.SilencingShot.CD.Reset() - } - if hunter.ChimeraShot != nil { - hunter.ChimeraShot.CD.Reset() - } - if hunter.BlackArrow != nil { - hunter.BlackArrow.CD.Reset() - } - - // TODO: This is needed because there are edge cases where core doesn't re-use Rapid Fire. - // Fix core so this isn't necessary. - core.StartDelayedAction(sim, core.DelayedActionOptions{ - DoAt: sim.CurrentTime + 1, - OnAction: func(_ *core.Simulation) { - hunter.UpdateMajorCooldowns() - }, - }) - }, - }) - - hunter.AddMajorCooldown(core.MajorCooldown{ - Spell: readinessSpell, - Type: core.CooldownTypeDPS, - ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { - // If RF is about to become ready naturally, wait so we can get 2x usages. - if !hunter.RapidFire.IsReady(sim) && hunter.RapidFire.TimeToReady(sim) < time.Second*10 { - return false - } - return !hunter.RapidFireAura.IsActive() || hunter.RapidFireAura.RemainingDuration(sim) < time.Second*10 - }, - }) -} +// func (hunter *Hunter) critMultiplier(isRanged bool, isMFDSpell bool, doubleDipMS bool) float64 { +// primaryModifier := 1.0 +// secondaryModifier := 0.0 +// mortalShotsFactor := 0.06 + +// if doubleDipMS { +// mortalShotsFactor = 0.12 +// } + +// if isRanged { +// secondaryModifier += mortalShotsFactor * float64(hunter.Talents.MortalShots) +// if isMFDSpell { +// secondaryModifier += 0.02 * float64(hunter.Talents.MarkedForDeath) +// } +// } + +// return hunter.MeleeCritMultiplier(primaryModifier, secondaryModifier) +// } + +// func (hunter *Hunter) markedForDeathMultiplier() float64 { +// if hunter.Options.UseHuntersMark || hunter.Env.GetTarget(0).HasAuraWithTag(core.HuntersMarkAuraTag) { +// return 1 + .01*float64(hunter.Talents.MarkedForDeath) +// } else { +// return 1 +// } +// } + +// func (hunter *Hunter) applySpiritBond() { +// if hunter.Talents.SpiritBond == 0 || hunter.pet == nil { +// return +// } + +// hunter.PseudoStats.HealingTakenMultiplier *= 1 + 0.05*float64(hunter.Talents.SpiritBond) +// hunter.pet.PseudoStats.HealingTakenMultiplier *= 1 + 0.05*float64(hunter.Talents.SpiritBond) + +// actionID := core.ActionID{SpellID: 20895} +// healthMultiplier := 0.01 * float64(hunter.Talents.SpiritBond) +// healthMetrics := hunter.NewHealthMetrics(actionID) +// petHealthMetrics := hunter.pet.NewHealthMetrics(actionID) + +// hunter.RegisterResetEffect(func(sim *core.Simulation) { +// core.StartPeriodicAction(sim, core.PeriodicActionOptions{ +// Period: time.Second * 10, +// OnAction: func(sim *core.Simulation) { +// hunter.GainHealth(sim, hunter.MaxHealth()*healthMultiplier, healthMetrics) +// hunter.pet.GainHealth(sim, hunter.pet.MaxHealth()*healthMultiplier, petHealthMetrics) +// }, +// }) +// }) +// } + +// func (hunter *Hunter) applyInvigoration() { +// if hunter.Talents.Invigoration == 0 || hunter.pet == nil { +// return +// } + +// procChance := 0.5 * float64(hunter.Talents.Invigoration) +// manaMetrics := hunter.NewManaMetrics(core.ActionID{SpellID: 53253}) + +// hunter.pet.RegisterAura(core.Aura{ +// Label: "Invigoration", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.ProcMask.Matches(core.ProcMaskMeleeSpecial | core.ProcMaskSpellDamage) { +// return +// } + +// if !result.DidCrit() { +// return +// } + +// if sim.Proc(procChance, "Invigoration") { +// hunter.AddMana(sim, 0.01*hunter.MaxMana(), manaMetrics) +// } +// }, +// }) +// } + +// func (hunter *Hunter) applyCobraStrikes() { +// if hunter.Talents.CobraStrikes == 0 || hunter.pet == nil { +// return +// } + +// actionID := core.ActionID{SpellID: 53260} +// procChance := 0.2 * float64(hunter.Talents.CobraStrikes) + +// hunter.pet.CobraStrikesAura = hunter.pet.RegisterAura(core.Aura{ +// Label: "Cobra Strikes", +// ActionID: actionID, +// Duration: time.Second * 10, +// MaxStacks: 2, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// hunter.pet.focusDump.BonusCritRating += 100 * core.CritRatingPerCritChance +// if hunter.pet.specialAbility != nil { +// hunter.pet.specialAbility.BonusCritRating += 100 * core.CritRatingPerCritChance +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// hunter.pet.focusDump.BonusCritRating -= 100 * core.CritRatingPerCritChance +// if hunter.pet.specialAbility != nil { +// hunter.pet.specialAbility.BonusCritRating -= 100 * core.CritRatingPerCritChance +// } +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell.ProcMask.Matches(core.ProcMaskMeleeSpecial | core.ProcMaskSpellDamage) { +// aura.RemoveStack(sim) +// } +// }, +// }) + +// hunter.RegisterAura(core.Aura{ +// Label: "Cobra Strikes", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.DidCrit() { +// return +// } + +// if spell != hunter.ArcaneShot && spell != hunter.SteadyShot && spell != hunter.KillShot { +// return +// } + +// if sim.RandomFloat("Cobra Strikes") < procChance { +// hunter.pet.CobraStrikesAura.Activate(sim) +// hunter.pet.CobraStrikesAura.SetStacks(sim, 2) +// } +// }, +// }) +// } + +// func (hunter *Hunter) applyPiercingShots() { +// if hunter.Talents.PiercingShots == 0 { +// return +// } + +// psSpell := hunter.RegisterSpell(core.SpellConfig{ +// ActionID: core.ActionID{SpellID: 53238}, +// SpellSchool: core.SpellSchoolPhysical, +// ProcMask: core.ProcMaskEmpty, +// Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagIgnoreModifiers, + +// DamageMultiplier: 1, +// ThreatMultiplier: 1, + +// Dot: core.DotConfig{ +// Aura: core.Aura{ +// Label: "PiercingShots", +// Duration: time.Second * 8, +// }, +// NumberOfTicks: 8, +// TickLength: time.Second * 1, +// OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { +// // Specifically account for bleed modifiers, since it still affects the spell, but we're ignoring all modifiers. +// dot.SnapshotAttackerMultiplier = target.PseudoStats.PeriodicPhysicalDamageTakenMultiplier +// dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) +// }, +// }, + +// ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { +// spell.Dot(target).ApplyOrReset(sim) +// spell.CalcAndDealOutcome(sim, target, spell.OutcomeAlwaysHit) +// }, +// }) + +// hunter.RegisterAura(core.Aura{ +// Label: "Piercing Shots Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.DidCrit() { +// return +// } +// if spell != hunter.AimedShot && spell != hunter.SteadyShot && spell != hunter.ChimeraShot { +// return +// } + +// dot := psSpell.Dot(result.Target) +// outstandingDamage := core.TernaryFloat64(dot.IsActive(), dot.SnapshotBaseDamage*float64(dot.NumberOfTicks-dot.TickCount), 0) +// newDamage := result.Damage * 0.1 * float64(hunter.Talents.PiercingShots) + +// dot.SnapshotBaseDamage = (outstandingDamage + newDamage) / float64(dot.NumberOfTicks) +// psSpell.Cast(sim, result.Target) +// }, +// }) +// } + +// func (hunter *Hunter) applyWildQuiver() { +// if hunter.Talents.WildQuiver == 0 { +// return +// } + +// actionID := core.ActionID{SpellID: 53217} +// procChance := 0.04 * float64(hunter.Talents.WildQuiver) + +// wqSpell := hunter.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// SpellSchool: core.SpellSchoolNature, +// ProcMask: core.ProcMaskRangedAuto, +// Flags: core.SpellFlagNoOnCastComplete, + +// DamageMultiplier: 0.8, +// CritMultiplier: hunter.critMultiplier(false, false, false), +// ThreatMultiplier: 1, + +// ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { +// baseDamage := spell.Unit.RangedWeaponDamage(sim, spell.RangedAttackPower(target)) + +// spell.BonusWeaponDamage() +// spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) +// }, +// }) + +// hunter.RegisterAura(core.Aura{ +// Label: "Wild Quiver Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell != hunter.AutoAttacks.RangedAuto() { +// return +// } + +// if sim.RandomFloat("Wild Quiver") < procChance { +// wqSpell.Cast(sim, result.Target) +// } +// }, +// }) +// } + +// func (hunter *Hunter) applyFocusedFire() { +// if hunter.Talents.FocusedFire == 0 || hunter.pet == nil { +// return +// } + +// hunter.PseudoStats.DamageDealtMultiplier *= 1.0 + 0.01*float64(hunter.Talents.FocusedFire) +// } + +// func (hunter *Hunter) applyFrenzy() { +// if hunter.Talents.Frenzy == 0 { +// return +// } + +// procChance := 0.2 * float64(hunter.Talents.Frenzy) + +// procAura := hunter.pet.RegisterAura(core.Aura{ +// Label: "Frenzy Proc", +// ActionID: core.ActionID{SpellID: 19625}, +// Duration: time.Second * 8, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.MultiplyMeleeSpeed(sim, 1.3) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.MultiplyMeleeSpeed(sim, 1/1.3) +// }, +// }) + +// hunter.pet.RegisterAura(core.Aura{ +// Label: "Frenzy", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.DidCrit() { +// return +// } +// if sim.Proc(procChance, "Frenzy") { +// procAura.Activate(sim) +// } +// }, +// }) +// } + +// func (hunter *Hunter) applyLongevity(dur time.Duration) time.Duration { +// return time.Duration(float64(dur) * (1.0 - 0.1*float64(hunter.Talents.Longevity))) +// } + +// func (hunter *Hunter) registerBestialWrathCD() { +// if !hunter.Talents.BestialWrath { +// return +// } +// if hunter.Talents.TheBeastWithin { +// hunter.PseudoStats.DamageDealtMultiplier *= 1.1 +// } + +// actionID := core.ActionID{SpellID: 19574} + +// bestialWrathPetAura := hunter.pet.RegisterAura(core.Aura{ +// Label: "Bestial Wrath Pet", +// ActionID: actionID, +// Duration: time.Second * 10, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.PseudoStats.DamageDealtMultiplier *= 1.5 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.PseudoStats.DamageDealtMultiplier /= 1.5 +// }, +// }) + +// bestialWrathAura := hunter.RegisterAura(core.Aura{ +// Label: "Bestial Wrath", +// ActionID: actionID, +// Duration: time.Second * 10, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.PseudoStats.DamageDealtMultiplier *= 1.1 +// aura.Unit.PseudoStats.CostMultiplier -= 0.5 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.PseudoStats.DamageDealtMultiplier /= 1.1 +// aura.Unit.PseudoStats.CostMultiplier += 0.5 +// }, +// }) +// core.RegisterPercentDamageModifierEffect(bestialWrathAura, 1.1) + +// bwSpell := hunter.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, + +// ManaCost: core.ManaCostOptions{ +// BaseCost: 0.1, +// }, +// Cast: core.CastConfig{ +// DefaultCast: core.Cast{ +// GCD: 1, +// }, +// CD: core.Cooldown{ +// Timer: hunter.NewTimer(), +// Duration: hunter.applyLongevity(time.Minute*2 - core.TernaryDuration(hunter.HasMajorGlyph(proto.HunterMajorGlyph_GlyphOfBestialWrath), time.Second*20, 0)), +// }, +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// bestialWrathPetAura.Activate(sim) + +// if hunter.Talents.TheBeastWithin { +// bestialWrathAura.Activate(sim) +// } +// }, +// }) + +// hunter.AddMajorCooldown(core.MajorCooldown{ +// Spell: bwSpell, +// Type: core.CooldownTypeDPS, +// }) +// } + +// func (hunter *Hunter) applyGoForTheThroat() { +// if hunter.Talents.GoForTheThroat == 0 { +// return +// } +// if hunter.pet == nil { +// return +// } + +// spellID := []int32{0, 34953, 34953}[hunter.Talents.GoForTheThroat] +// focusMetrics := hunter.NewFocusMetrics(core.ActionID{SpellID: spellID}) + +// amount := 25.0 * float64(hunter.Talents.GoForTheThroat) + +// hunter.RegisterAura(core.Aura{ +// Label: "Go for the Throat", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.ProcMask.Matches(core.ProcMaskRanged) || !result.DidCrit() { +// return +// } +// if !hunter.pet.IsEnabled() { +// return +// } +// hunter.pet.AddFocus(sim, amount, focusMetrics) +// }, +// OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.DidCrit() { +// return +// } +// if !hunter.pet.IsEnabled() { +// return +// } +// hunter.pet.AddFocus(sim, amount, focusMetrics) +// }, +// }) +// } + +// func (hunter *Hunter) applyImprovedTracking() { +// if hunter.Talents.ImprovedTracking == 0 { +// return +// } + +// var applied bool + +// hunter.RegisterResetEffect( +// func(s *core.Simulation) { +// if applied { +// return +// } +// applied = true + +// for _, target := range hunter.Env.Encounter.TargetUnits { +// switch target.MobType { +// case proto.MobType_MobTypeBeast, proto.MobType_MobTypeDemon, +// proto.MobType_MobTypeDragonkin, proto.MobType_MobTypeElemental, +// proto.MobType_MobTypeGiant, proto.MobType_MobTypeHumanoid, +// proto.MobType_MobTypeUndead: + +// hunter.AttackTables[target.UnitIndex].DamageDealtMultiplier *= 1.0 + 0.01*float64(hunter.Talents.ImprovedTracking) +// } +// } +// }, +// ) +// } + +// func (hunter *Hunter) applyLockAndLoad() { +// if hunter.Talents.LockAndLoad == 0 { +// return +// } + +// actionID := core.ActionID{SpellID: 56344} +// procChance := []float64{0, 0.02, 0.04, 0.20}[hunter.Talents.LockAndLoad] + +// icd := core.Cooldown{ +// Timer: hunter.NewTimer(), +// Duration: time.Second * 22, +// } + +// hunter.LockAndLoadAura = hunter.RegisterAura(core.Aura{ +// Icd: &icd, +// Label: "Lock and Load Proc", +// ActionID: actionID, +// Duration: time.Second * 12, +// MaxStacks: 2, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// hunter.ArcaneShot.CostMultiplier -= 1 +// if hunter.ExplosiveShotR4 != nil { +// hunter.ExplosiveShotR4.CostMultiplier -= 1 +// hunter.ExplosiveShotR3.CostMultiplier -= 1 +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// hunter.ArcaneShot.CostMultiplier += 1 +// if hunter.ExplosiveShotR4 != nil { +// hunter.ExplosiveShotR4.CostMultiplier += 1 +// hunter.ExplosiveShotR3.CostMultiplier += 1 +// } +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == hunter.ArcaneShot || spell == hunter.ExplosiveShotR4 || spell == hunter.ExplosiveShotR3 { +// aura.RemoveStack(sim) +// hunter.ArcaneShot.CD.Reset() // Shares the CD with explosive shot. +// } +// }, +// }) + +// hunter.RegisterAura(core.Aura{ +// Label: "Lock and Load Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell != hunter.BlackArrow && spell != hunter.ExplosiveTrap { +// return +// } + +// if !icd.IsReady(sim) { +// return +// } + +// if sim.RandomFloat("Lock and Load") < procChance { +// icd.Use(sim) +// hunter.LockAndLoadAura.Activate(sim) +// hunter.LockAndLoadAura.SetStacks(sim, 2) +// } +// }, +// }) +// } + +// func (hunter *Hunter) applyThrillOfTheHunt() { +// if hunter.Talents.ThrillOfTheHunt == 0 { +// return +// } + +// procChance := float64(hunter.Talents.ThrillOfTheHunt) / 3 +// manaMetrics := hunter.NewManaMetrics(core.ActionID{SpellID: 34499}) + +// hunter.RegisterAura(core.Aura{ +// Label: "Thrill of the Hunt", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// // mask 256 +// if !spell.ProcMask.Matches(core.ProcMaskRangedSpecial) { +// return +// } + +// if !result.DidCrit() { +// return +// } + +// if sim.Proc(procChance, "ThrillOfTheHunt") { +// hunter.AddMana(sim, spell.CurCast.Cost*0.4, manaMetrics) +// } +// }, +// OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.DidCrit() && (spell == hunter.ExplosiveShotR4 || spell == hunter.ExplosiveShotR3) { +// // Explosive shot ticks can proc TotH but with 1/3 the bonus. +// if sim.Proc(procChance, "ThrillOfTheHunt") { +// hunter.AddMana(sim, spell.CurCast.Cost*0.4/3, manaMetrics) +// } +// } +// }, +// }) +// } + +// func (hunter *Hunter) applyExposeWeakness() { +// if hunter.Talents.ExposeWeakness == 0 { +// return +// } + +// actionID := core.ActionID{SpellID: 34503} +// procChance := float64(hunter.Talents.ExposeWeakness) / 3 + +// apDep := hunter.NewDynamicStatDependency(stats.Agility, stats.AttackPower, .25) +// rapDep := hunter.NewDynamicStatDependency(stats.Agility, stats.RangedAttackPower, .25) +// procAura := hunter.RegisterAura(core.Aura{ +// Label: "Expose Weakness Proc", +// ActionID: actionID, +// Duration: time.Second * 7, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.EnableDynamicStatDep(sim, apDep) +// aura.Unit.EnableDynamicStatDep(sim, rapDep) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.DisableDynamicStatDep(sim, apDep) +// aura.Unit.DisableDynamicStatDep(sim, rapDep) +// }, +// }) + +// hunter.RegisterAura(core.Aura{ +// Label: "Expose Weakness Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.ProcMask.Matches(core.ProcMaskRanged) && spell != hunter.ExplosiveTrap { +// return +// } + +// if !result.DidCrit() { +// return +// } + +// if sim.Proc(procChance, "ExposeWeakness") { +// procAura.Activate(sim) +// } +// }, +// OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.DidCrit() { +// return +// } + +// if sim.Proc(procChance, "ExposeWeakness") { +// procAura.Activate(sim) +// } +// }, +// }) +// } + +// func (hunter *Hunter) applyMasterTactician() { +// if hunter.Talents.MasterTactician == 0 { +// return +// } + +// procChance := 0.1 +// critBonus := 2 * core.CritRatingPerCritChance * float64(hunter.Talents.MasterTactician) + +// procAura := hunter.NewTemporaryStatsAura("Master Tactician Proc", core.ActionID{SpellID: 34839}, stats.Stats{stats.MeleeCrit: critBonus}, time.Second*8) + +// hunter.RegisterAura(core.Aura{ +// Label: "Master Tactician", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.ProcMask.Matches(core.ProcMaskRanged) || !result.Landed() { +// return +// } + +// if sim.RandomFloat("Master Tactician") > procChance { +// return +// } + +// procAura.Activate(sim) +// }, +// }) +// } + +// func (hunter *Hunter) applySniperTraining() { +// if hunter.Talents.SniperTraining == 0 { +// return +// } + +// uptime := hunter.SurvivalOptions.SniperTrainingUptime +// if uptime <= 0 { +// return +// } +// uptime = min(1, uptime) + +// dmgMod := .02 * float64(hunter.Talents.SniperTraining) + +// stAura := hunter.RegisterAura(core.Aura{ +// Label: "Sniper Training", +// ActionID: core.ActionID{SpellID: 53304}, +// Duration: time.Second * 15, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// hunter.SteadyShot.DamageMultiplierAdditive += dmgMod +// if hunter.AimedShot != nil { +// hunter.AimedShot.DamageMultiplierAdditive += dmgMod +// } +// if hunter.BlackArrow != nil { +// hunter.BlackArrow.DamageMultiplierAdditive += dmgMod +// } +// if hunter.ExplosiveShotR4 != nil { +// hunter.ExplosiveShotR4.DamageMultiplierAdditive += dmgMod +// hunter.ExplosiveShotR3.DamageMultiplierAdditive += dmgMod +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// hunter.SteadyShot.DamageMultiplierAdditive -= dmgMod +// if hunter.AimedShot != nil { +// hunter.AimedShot.DamageMultiplierAdditive -= dmgMod +// } +// if hunter.BlackArrow != nil { +// hunter.BlackArrow.DamageMultiplierAdditive -= dmgMod +// } +// if hunter.ExplosiveShotR4 != nil { +// hunter.ExplosiveShotR4.DamageMultiplierAdditive -= dmgMod +// hunter.ExplosiveShotR3.DamageMultiplierAdditive -= dmgMod +// } +// }, +// }) + +// core.ApplyFixedUptimeAura(stAura, uptime, time.Second*15, 1) +// } + +// func (hunter *Hunter) applyHuntingParty() { +// if hunter.Talents.HuntingParty == 0 { +// return +// } + +// procChance := float64(hunter.Talents.HuntingParty) / 3 +// replSrc := hunter.Env.Raid.NewReplenishmentSource(core.ActionID{SpellID: 53292}) + +// hunter.RegisterAura(core.Aura{ +// Label: "Hunting Party", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.DidCrit() { +// return +// } + +// if spell != hunter.SteadyShot && spell != hunter.ArcaneShot && spell != hunter.ExplosiveShotR4 && spell != hunter.ExplosiveShotR3 { +// return +// } + +// if procChance == 1 || sim.RandomFloat("Hunting Party") < procChance { +// hunter.Env.Raid.ProcReplenishment(sim, replSrc) +// } +// }, +// }) +// } + +// func (hunter *Hunter) registerReadinessCD() { +// if !hunter.Talents.Readiness { +// return +// } + +// actionID := core.ActionID{SpellID: 23989} + +// readinessSpell := hunter.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, + +// Cast: core.CastConfig{ +// DefaultCast: core.Cast{ +// GCD: time.Second * 1, +// }, +// IgnoreHaste: true, // Hunter GCD is locked +// CD: core.Cooldown{ +// Timer: hunter.NewTimer(), +// Duration: time.Minute * 3, +// }, +// }, +// ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { +// // Don't use if there are no cooldowns to reset. +// return !hunter.RapidFire.IsReady(sim) +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// hunter.RapidFire.CD.Reset() +// hunter.MultiShot.CD.Reset() +// hunter.ArcaneShot.CD.Reset() +// hunter.KillShot.CD.Reset() +// hunter.RaptorStrike.CD.Reset() +// hunter.ExplosiveTrap.CD.Reset() +// if hunter.KillCommand != nil { +// hunter.KillCommand.CD.Reset() +// } +// if hunter.AimedShot != nil { +// hunter.AimedShot.CD.Reset() +// } +// if hunter.SilencingShot != nil { +// hunter.SilencingShot.CD.Reset() +// } +// if hunter.ChimeraShot != nil { +// hunter.ChimeraShot.CD.Reset() +// } +// if hunter.BlackArrow != nil { +// hunter.BlackArrow.CD.Reset() +// } + +// // TODO: This is needed because there are edge cases where core doesn't re-use Rapid Fire. +// // Fix core so this isn't necessary. +// core.StartDelayedAction(sim, core.DelayedActionOptions{ +// DoAt: sim.CurrentTime + 1, +// OnAction: func(_ *core.Simulation) { +// hunter.UpdateMajorCooldowns() +// }, +// }) +// }, +// }) + +// hunter.AddMajorCooldown(core.MajorCooldown{ +// Spell: readinessSpell, +// Type: core.CooldownTypeDPS, +// ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { +// // If RF is about to become ready naturally, wait so we can get 2x usages. +// if !hunter.RapidFire.IsReady(sim) && hunter.RapidFire.TimeToReady(sim) < time.Second*10 { +// return false +// } +// return !hunter.RapidFireAura.IsActive() || hunter.RapidFireAura.RemainingDuration(sim) < time.Second*10 +// }, +// }) +// } diff --git a/sim/mage/arcane_barrage.go b/sim/mage/_arcane_barrage.go similarity index 100% rename from sim/mage/arcane_barrage.go rename to sim/mage/_arcane_barrage.go diff --git a/sim/mage/arcane_blast.go b/sim/mage/_arcane_blast.go similarity index 100% rename from sim/mage/arcane_blast.go rename to sim/mage/_arcane_blast.go diff --git a/sim/mage/arcane_explosion.go b/sim/mage/_arcane_explosion.go similarity index 100% rename from sim/mage/arcane_explosion.go rename to sim/mage/_arcane_explosion.go diff --git a/sim/mage/arcane_missiles.go b/sim/mage/_arcane_missiles.go similarity index 100% rename from sim/mage/arcane_missiles.go rename to sim/mage/_arcane_missiles.go diff --git a/sim/mage/blast_wave.go b/sim/mage/_blast_wave.go similarity index 100% rename from sim/mage/blast_wave.go rename to sim/mage/_blast_wave.go diff --git a/sim/mage/blizzard.go b/sim/mage/_blizzard.go similarity index 100% rename from sim/mage/blizzard.go rename to sim/mage/_blizzard.go diff --git a/sim/mage/deep_freeze.go b/sim/mage/_deep_freeze.go similarity index 100% rename from sim/mage/deep_freeze.go rename to sim/mage/_deep_freeze.go diff --git a/sim/mage/dragons_breath.go b/sim/mage/_dragons_breath.go similarity index 100% rename from sim/mage/dragons_breath.go rename to sim/mage/_dragons_breath.go diff --git a/sim/mage/evocation.go b/sim/mage/_evocation.go similarity index 100% rename from sim/mage/evocation.go rename to sim/mage/_evocation.go diff --git a/sim/mage/fire_blast.go b/sim/mage/_fire_blast.go similarity index 100% rename from sim/mage/fire_blast.go rename to sim/mage/_fire_blast.go diff --git a/sim/mage/fireball.go b/sim/mage/_fireball.go similarity index 100% rename from sim/mage/fireball.go rename to sim/mage/_fireball.go diff --git a/sim/mage/flamestrike.go b/sim/mage/_flamestrike.go similarity index 100% rename from sim/mage/flamestrike.go rename to sim/mage/_flamestrike.go diff --git a/sim/mage/focus_magic.go b/sim/mage/_focus_magic.go similarity index 100% rename from sim/mage/focus_magic.go rename to sim/mage/_focus_magic.go diff --git a/sim/mage/frostbolt.go b/sim/mage/_frostbolt.go similarity index 100% rename from sim/mage/frostbolt.go rename to sim/mage/_frostbolt.go diff --git a/sim/mage/frostfire_bolt.go b/sim/mage/_frostfire_bolt.go similarity index 100% rename from sim/mage/frostfire_bolt.go rename to sim/mage/_frostfire_bolt.go diff --git a/sim/mage/ice_lance.go b/sim/mage/_ice_lance.go similarity index 100% rename from sim/mage/ice_lance.go rename to sim/mage/_ice_lance.go diff --git a/sim/mage/ignite.go b/sim/mage/_ignite.go similarity index 100% rename from sim/mage/ignite.go rename to sim/mage/_ignite.go diff --git a/sim/mage/items.go b/sim/mage/_items.go similarity index 100% rename from sim/mage/items.go rename to sim/mage/_items.go diff --git a/sim/mage/living_bomb.go b/sim/mage/_living_bomb.go similarity index 100% rename from sim/mage/living_bomb.go rename to sim/mage/_living_bomb.go diff --git a/sim/mage/mana_gems.go b/sim/mage/_mana_gems.go similarity index 100% rename from sim/mage/mana_gems.go rename to sim/mage/_mana_gems.go diff --git a/sim/mage/mirror_image.go b/sim/mage/_mirror_image.go similarity index 100% rename from sim/mage/mirror_image.go rename to sim/mage/_mirror_image.go diff --git a/sim/mage/pyroblast.go b/sim/mage/_pyroblast.go similarity index 100% rename from sim/mage/pyroblast.go rename to sim/mage/_pyroblast.go diff --git a/sim/mage/scorch.go b/sim/mage/_scorch.go similarity index 100% rename from sim/mage/scorch.go rename to sim/mage/_scorch.go diff --git a/sim/mage/water_elemental.go b/sim/mage/_water_elemental.go similarity index 100% rename from sim/mage/water_elemental.go rename to sim/mage/_water_elemental.go diff --git a/sim/mage/mage.go b/sim/mage/mage.go index 446f4cc5e8..2cb584ddec 100644 --- a/sim/mage/mage.go +++ b/sim/mage/mage.go @@ -3,7 +3,6 @@ package mage import ( "github.com/wowsims/cata/sim/core" "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" ) const ( @@ -23,8 +22,8 @@ type Mage struct { FireOptions *proto.FireMage_Options FrostOptions *proto.FrostMage_Options - waterElemental *WaterElemental - mirrorImage *MirrorImage + //waterElemental *WaterElemental + //mirrorImage *MirrorImage // Cached values for a few mechanics. bonusCritDamage float64 @@ -87,35 +86,35 @@ func (mage *Mage) HasMinorGlyph(glyph proto.MageMinorGlyph) bool { func (mage *Mage) AddRaidBuffs(raidBuffs *proto.RaidBuffs) { raidBuffs.ArcaneBrilliance = true - if mage.Talents.ArcaneEmpowerment == 3 { - raidBuffs.ArcaneEmpowerment = true - } + // if mage.Talents.ArcaneEmpowerment == 3 { + // raidBuffs.ArcaneEmpowerment = true + // } } func (mage *Mage) AddPartyBuffs(partyBuffs *proto.PartyBuffs) { } func (mage *Mage) Initialize() { - mage.registerArcaneBarrageSpell() - mage.registerArcaneBlastSpell() - mage.registerArcaneExplosionSpell() - mage.registerArcaneMissilesSpell() - mage.registerBlizzardSpell() - mage.registerDeepFreezeSpell() - mage.registerFireballSpell() - mage.registerFireBlastSpell() - mage.registerFlamestrikeSpells() - mage.registerFrostboltSpell() - mage.registerIceLanceSpell() - mage.registerPyroblastSpell() - mage.registerScorchSpell() - mage.registerLivingBombSpell() - mage.registerFrostfireBoltSpell() - mage.registerEvocation() - mage.registerManaGemsCD() - mage.registerMirrorImageCD() - mage.registerBlastWaveSpell() - mage.registerDragonsBreathSpell() - mage.registerSummonWaterElementalCD() + // mage.registerArcaneBarrageSpell() + // mage.registerArcaneBlastSpell() + // mage.registerArcaneExplosionSpell() + // mage.registerArcaneMissilesSpell() + // mage.registerBlizzardSpell() + // mage.registerDeepFreezeSpell() + // mage.registerFireballSpell() + // mage.registerFireBlastSpell() + // mage.registerFlamestrikeSpells() + // mage.registerFrostboltSpell() + // mage.registerIceLanceSpell() + // mage.registerPyroblastSpell() + // mage.registerScorchSpell() + // mage.registerLivingBombSpell() + // mage.registerFrostfireBoltSpell() + // mage.registerEvocation() + // mage.registerManaGemsCD() + // mage.registerMirrorImageCD() + // mage.registerBlastWaveSpell() + // mage.registerDragonsBreathSpell() + // mage.registerSummonWaterElementalCD() } func (mage *Mage) Reset(sim *core.Simulation) { @@ -127,32 +126,32 @@ func NewMage(character *core.Character, options *proto.Player, mageOptions *prot Talents: &proto.MageTalents{}, Options: mageOptions, } - core.FillTalentsProto(mage.Talents.ProtoReflect(), options.TalentsString, TalentTreeSizes) - - mage.bonusCritDamage = .25*float64(mage.Talents.SpellPower) + .1*float64(mage.Talents.Burnout) - mage.EnableManaBar() - - if mage.Options.Armor == proto.MageOptions_MageArmor { - mage.PseudoStats.SpiritRegenRateCasting += .5 - if mage.HasMajorGlyph(proto.MageMajorGlyph_GlyphOfMageArmor) { - mage.PseudoStats.SpiritRegenRateCasting += .2 - } - if mage.HasSetBonus(ItemSetKhadgarsRegalia, 2) { - mage.PseudoStats.SpiritRegenRateCasting += .1 - } - } else if mage.Options.Armor == proto.MageOptions_MoltenArmor { - //Need to switch to spirit crit calc - multi := 0.35 - if mage.HasMajorGlyph(proto.MageMajorGlyph_GlyphOfMoltenArmor) { - multi += .2 - } - if mage.HasSetBonus(ItemSetKhadgarsRegalia, 2) { - multi += .15 - } - mage.Character.AddStatDependency(stats.Spirit, stats.SpellCrit, multi) - } - - mage.mirrorImage = mage.NewMirrorImage() + // core.FillTalentsProto(mage.Talents.ProtoReflect(), options.TalentsString, TalentTreeSizes) + + // mage.bonusCritDamage = .25*float64(mage.Talents.SpellPower) + .1*float64(mage.Talents.Burnout) + // mage.EnableManaBar() + + // if mage.Options.Armor == proto.MageOptions_MageArmor { + // mage.PseudoStats.SpiritRegenRateCasting += .5 + // if mage.HasMajorGlyph(proto.MageMajorGlyph_GlyphOfMageArmor) { + // mage.PseudoStats.SpiritRegenRateCasting += .2 + // } + // if mage.HasSetBonus(ItemSetKhadgarsRegalia, 2) { + // mage.PseudoStats.SpiritRegenRateCasting += .1 + // } + // } else if mage.Options.Armor == proto.MageOptions_MoltenArmor { + // //Need to switch to spirit crit calc + // multi := 0.35 + // if mage.HasMajorGlyph(proto.MageMajorGlyph_GlyphOfMoltenArmor) { + // multi += .2 + // } + // if mage.HasSetBonus(ItemSetKhadgarsRegalia, 2) { + // multi += .15 + // } + // mage.Character.AddStatDependency(stats.Spirit, stats.SpellCrit, multi) + // } + + // mage.mirrorImage = mage.NewMirrorImage() return mage } diff --git a/sim/mage/talents.go b/sim/mage/talents.go index 1915fdadbc..d6c2f96117 100644 --- a/sim/mage/talents.go +++ b/sim/mage/talents.go @@ -1,832 +1,824 @@ package mage -import ( - "time" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" -) - func (mage *Mage) ApplyTalents() { - mage.applyArcaneConcentration() - mage.applyFocusMagic() - mage.applyIgnite() - mage.applyEmpoweredFire() - mage.applyMasterOfElements() - mage.applyWintersChill() - mage.applyMoltenFury() - mage.applyMissileBarrage() - mage.applyHotStreak() - mage.applyFingersOfFrost() - mage.applyBrainFreeze() - mage.applyFireStarter() - - mage.registerArcanePowerCD() - mage.registerPresenceOfMindCD() - mage.registerCombustionCD() - mage.registerIcyVeinsCD() - mage.registerColdSnapCD() - - mage.PseudoStats.SpiritRegenRateCasting += float64(mage.Talents.ArcaneMeditation) / 6 - - if mage.Talents.StudentOfTheMind > 0 { - mage.MultiplyStat(stats.Spirit, 1.0+[]float64{0, .04, .07, .10}[mage.Talents.StudentOfTheMind]) - } - - if mage.Talents.ArcaneMind > 0 { - mage.MultiplyStat(stats.Intellect, 1.0+0.03*float64(mage.Talents.ArcaneMind)) - } - - if mage.Talents.MindMastery > 0 { - mage.AddStatDependency(stats.Intellect, stats.SpellPower, 0.03*float64(mage.Talents.MindMastery)) - } - - mage.AddStat(stats.SpellCrit, float64(mage.Talents.ArcaneInstability)*1*core.CritRatingPerCritChance) - mage.PseudoStats.DamageDealtMultiplier *= 1 + .01*float64(mage.Talents.ArcaneInstability) - mage.PseudoStats.DamageDealtMultiplier *= 1 + .01*float64(mage.Talents.PlayingWithFire) - mage.PseudoStats.CastSpeedMultiplier *= 1 + .02*float64(mage.Talents.NetherwindPresence) - - mage.AddStat(stats.SpellCrit, float64(mage.Talents.Pyromaniac)*core.CritRatingPerCritChance) - mage.PseudoStats.SpiritRegenRateCasting += float64(mage.Talents.Pyromaniac) / 6 - - mage.AddStat(stats.SpellHit, float64(mage.Talents.Precision)*core.SpellHitRatingPerHitChance) - mage.PseudoStats.CostMultiplier *= 1 - .01*float64(mage.Talents.Precision) - - mage.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFrost] *= 1 + .02*float64(mage.Talents.PiercingIce) - mage.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFrost] *= 1 + .01*float64(mage.Talents.ArcticWinds) - mage.PseudoStats.CostMultiplier *= 1 - .04*float64(mage.Talents.FrostChanneling) - - magicAbsorptionBonus := 2 * float64(mage.Talents.MagicAbsorption) - mage.AddStat(stats.ArcaneResistance, magicAbsorptionBonus) - mage.AddStat(stats.FireResistance, magicAbsorptionBonus) - mage.AddStat(stats.FrostResistance, magicAbsorptionBonus) - mage.AddStat(stats.NatureResistance, magicAbsorptionBonus) - mage.AddStat(stats.ShadowResistance, magicAbsorptionBonus) -} - -func (mage *Mage) applyHotStreak() { - if mage.Talents.HotStreak == 0 { - return - } - - procChance := float64(mage.Talents.HotStreak) / 3 - t10ProcAura := mage.BloodmagesRegalia2pcAura() - - mage.HotStreakAura = mage.RegisterAura(core.Aura{ - Label: "HotStreak", - ActionID: core.ActionID{SpellID: 44448}, - Duration: time.Second * 10, - // This is handled in Pyroblast.ModifyCast instead. - //OnGain: func(aura *core.Aura, sim *core.Simulation) { - // if mage.Pyroblast != nil { - // mage.Pyroblast.CastTimeMultiplier -= 1 - // } - //}, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - //if mage.Pyroblast != nil { - // mage.Pyroblast.CastTimeMultiplier += 1 - //} - if t10ProcAura != nil { - t10ProcAura.Activate(sim) - } - }, - }) - - mage.hotStreakCritAura = mage.RegisterAura(core.Aura{ - Label: "Hot Streak Proc Aura", - ActionID: core.ActionID{SpellID: 44448, Tag: 1}, - MaxStacks: 2, - Duration: time.Hour, - }) - - mage.RegisterAura(core.Aura{ - Label: "Hot Streak Trigger", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.Flags.Matches(HotStreakSpells) { - return - } - - if !result.DidCrit() { - mage.hotStreakCritAura.SetStacks(sim, 0) - mage.hotStreakCritAura.Deactivate(sim) - return - } - - if mage.hotStreakCritAura.GetStacks() == 1 { - if procChance == 1 || sim.Proc(procChance, "Hot Streak") { - mage.hotStreakCritAura.SetStacks(sim, 0) - mage.hotStreakCritAura.Deactivate(sim) - - mage.HotStreakAura.Activate(sim) - } - } else { - mage.hotStreakCritAura.Activate(sim) - mage.hotStreakCritAura.AddStack(sim) - } - }, - }) - -} - -func (mage *Mage) applyArcaneConcentration() { - if mage.Talents.ArcaneConcentration == 0 { - return - } - - bonusCrit := float64(mage.Talents.ArcanePotency) * 15 * core.CritRatingPerCritChance - - // The result that caused the proc. Used to check we don't deactivate from the same proc. - var proccedAt time.Duration - var proccedSpell *core.Spell - - if mage.Talents.ArcanePotency > 0 { - mage.ArcanePotencyAura = mage.RegisterAura(core.Aura{ - Label: "Arcane Potency", - ActionID: core.ActionID{SpellID: 31572}, - Duration: time.Second * 15, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.AddStatDynamic(sim, stats.SpellCrit, bonusCrit) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.AddStatDynamic(sim, stats.SpellCrit, -bonusCrit) - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if !spell.Flags.Matches(SpellFlagMage) { - return - } - if proccedAt == sim.CurrentTime && proccedSpell == spell { - // Means this is another hit from the same cast that procced CC. - return - } - aura.Deactivate(sim) - }, - }) - } - - mage.ClearcastingAura = mage.RegisterAura(core.Aura{ - Label: "Clearcasting", - ActionID: core.ActionID{SpellID: 12536}, - Duration: time.Second * 15, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.CostMultiplier -= 1 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.CostMultiplier += 1 - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if !spell.Flags.Matches(SpellFlagMage) { - return - } - if spell.DefaultCast.Cost == 0 { - return - } - if spell == mage.ArcaneMissiles && mage.MissileBarrageAura.IsActive() { - return - } - if proccedAt == sim.CurrentTime && proccedSpell == spell { - // Means this is another hit from the same cast that procced CC. - return - } - aura.Deactivate(sim) - }, - }) - - mage.RegisterAura(core.Aura{ - Label: "Arcane Concentration", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.Flags.Matches(SpellFlagMage) || spell == mage.ArcaneMissiles { - return - } - - if !result.Landed() { - return - } - - procChance := 0.02 * float64(mage.Talents.ArcaneConcentration) - - // Arcane Missile ticks can proc CC, just at a low rate of about 1.5% with 5/5 Arcane Concentration - if spell == mage.ArcaneMissilesTickSpell { - procChance *= 0.15 - } - - if sim.RandomFloat("Arcane Concentration") > procChance { - return - } - - proccedAt = sim.CurrentTime - proccedSpell = spell - mage.ClearcastingAura.Activate(sim) - if mage.ArcanePotencyAura != nil { - mage.ArcanePotencyAura.Activate(sim) - } - }, - }) -} - -func (mage *Mage) applyMissileBarrage() { - if mage.Talents.MissileBarrage == 0 { - return - } - - t10ProcAura := mage.BloodmagesRegalia2pcAura() - - procChance := float64(mage.Talents.MissileBarrage) * .04 - mage.MissileBarrageAura = mage.RegisterAura(core.Aura{ - Label: "Missile Barrage Proc", - ActionID: core.ActionID{SpellID: 44401}, - Duration: time.Second * 15, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - mage.ArcaneMissiles.CostMultiplier -= 100 - mage.ArcaneMissiles.CastTimeMultiplier /= 2 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - mage.ArcaneMissiles.CostMultiplier += 100 - mage.ArcaneMissiles.CastTimeMultiplier *= 2 - if t10ProcAura != nil { - t10ProcAura.Activate(sim) - } - }, - }) - - mage.RegisterAura(core.Aura{ - Label: "Missile Barrage Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if !spell.Flags.Matches(BarrageSpells) { - return - } - - roll := sim.RandomFloat("Missile Barrage") - updChance := core.TernaryFloat64(spell.ActionID == mage.ArcaneBlast.ActionID, 2*procChance, procChance) - - if roll < updChance { - mage.MissileBarrageAura.Activate(sim) - } - }, - }) -} - -func (mage *Mage) registerPresenceOfMindCD() { - if !mage.Talents.PresenceOfMind { - return - } - - cooldown := 120.0 - if mage.Talents.ArcaneFlows > 0 { - cooldown *= 1 - (.15 * float64(mage.Talents.ArcaneFlows)) - } - - actionID := core.ActionID{SpellID: 12043} - - var spellToUse *core.Spell - mage.Env.RegisterPostFinalizeEffect(func() { - if mage.Pyroblast != nil { - spellToUse = mage.Pyroblast - } else if mage.PrimaryTalentTree == 1 { - spellToUse = mage.Fireball - } else if mage.PrimaryTalentTree == 2 { - spellToUse = mage.Frostbolt - } else { - spellToUse = mage.ArcaneBlast - } - }) - - spell := mage.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete, - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: mage.NewTimer(), - Duration: time.Duration(cooldown) * time.Second, - }, - }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - if !mage.GCD.IsReady(sim) { - return false - } - if mage.ArcanePowerAura.IsActive() { - return false - } - - manaCost := spellToUse.DefaultCast.Cost * mage.PseudoStats.CostMultiplier - if spellToUse == mage.ArcaneBlast { - manaCost *= float64(mage.ArcaneBlastAura.GetStacks()) * 1.75 - } - - return mage.CurrentMana() >= manaCost - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - if mage.ArcanePotencyAura != nil { - mage.ArcanePotencyAura.Activate(sim) - } - - normalCastTime := spellToUse.DefaultCast.CastTime - spellToUse.DefaultCast.CastTime = 0 - spellToUse.Cast(sim, mage.CurrentTarget) - spellToUse.DefaultCast.CastTime = normalCastTime - }, - }) - - mage.AddMajorCooldown(core.MajorCooldown{ - Spell: spell, - Type: core.CooldownTypeDPS, - }) -} - -func (mage *Mage) registerArcanePowerCD() { - if !mage.Talents.ArcanePower { - return - } - actionID := core.ActionID{SpellID: 12042} - - var affectedSpells []*core.Spell - mage.OnSpellRegistered(func(spell *core.Spell) { - if spell.Flags.Matches(SpellFlagMage) { - affectedSpells = append(affectedSpells, spell) - } - }) - - mage.ArcanePowerAura = mage.RegisterAura(core.Aura{ - Label: "Arcane Power", - ActionID: actionID, - Duration: core.TernaryDuration(mage.HasMajorGlyph(proto.MageMajorGlyph_GlyphOfArcanePower), time.Second*18, time.Second*15), - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.DamageMultiplierAdditive += 0.2 - spell.CostMultiplier += 0.2 - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.DamageMultiplierAdditive -= 0.2 - spell.CostMultiplier -= 0.2 - } - }, - }) - core.RegisterPercentDamageModifierEffect(mage.ArcanePowerAura, 1.2) - - spell := mage.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete, - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: mage.NewTimer(), - Duration: time.Second * time.Duration(120*(1-(.15*float64(mage.Talents.ArcaneFlows)))), - }, - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - mage.ArcanePowerAura.Activate(sim) - }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - return !mage.ArcanePotencyAura.IsActive() - }, - }) - - mage.AddMajorCooldown(core.MajorCooldown{ - Spell: spell, - Type: core.CooldownTypeDPS, - }) -} - -func (mage *Mage) applyMasterOfElements() { - if mage.Talents.MasterOfElements == 0 && mage.Talents.Burnout == 0 { - return - } - - refundCoeff := 0.1*float64(mage.Talents.MasterOfElements) - .01*float64(mage.Talents.Burnout) - manaMetrics := mage.NewManaMetrics(core.ActionID{SpellID: 29076}) - - mage.RegisterAura(core.Aura{ - Label: "Master of Elements", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.ProcMask.Matches(core.ProcMaskMeleeOrRanged) { - return - } - if spell.CurCast.Cost == 0 { - return - } - if result.DidCrit() { - if refundCoeff < 0 { - mage.SpendMana(sim, -1*spell.DefaultCast.Cost*refundCoeff, manaMetrics) - } else { - mage.AddMana(sim, spell.DefaultCast.Cost*refundCoeff, manaMetrics) - } - } - }, - }) -} - -func (mage *Mage) registerCombustionCD() { - if !mage.Talents.Combustion { - return - } - actionID := core.ActionID{SpellID: 11129} - cd := core.Cooldown{ - Timer: mage.NewTimer(), - Duration: time.Minute * 2, - } - - fireCombCritMult := mage.SpellCritMultiplier(1, mage.bonusCritDamage+.5) / mage.SpellCritMultiplier(1, mage.bonusCritDamage) - - frostfireCombCritMult := mage.SpellCritMultiplier(1, mage.bonusCritDamage+float64(mage.Talents.IceShards)/3+.5) / - mage.SpellCritMultiplier(1, mage.bonusCritDamage+float64(mage.Talents.IceShards)/3) - - var fireSpells []*core.Spell - mage.OnSpellRegistered(func(spell *core.Spell) { - if spell.SpellSchool.Matches(core.SpellSchoolFire) { - fireSpells = append(fireSpells, spell) - } - }) - - numCrits := 0 - const critPerStack = 10 * core.CritRatingPerCritChance - - mage.CombustionAura = mage.RegisterAura(core.Aura{ - Label: "Combustion", - ActionID: actionID, - Duration: core.NeverExpires, - MaxStacks: 20, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - numCrits = 0 - for _, spell := range fireSpells { - spell.CritMultiplier *= core.TernaryFloat64(spell != mage.FrostfireBolt, fireCombCritMult, frostfireCombCritMult) - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - cd.Use(sim) - mage.UpdateMajorCooldowns() - for _, spell := range fireSpells { - spell.CritMultiplier /= core.TernaryFloat64(spell != mage.FrostfireBolt, fireCombCritMult, frostfireCombCritMult) - } - }, - OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { - bonusCrit := critPerStack * float64(newStacks-oldStacks) - for _, spell := range fireSpells { - spell.BonusCritRating += bonusCrit - } - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.SpellSchool.Matches(core.SpellSchoolFire) || !spell.Flags.Matches(SpellFlagMage) { - return - } - if spell == mage.Ignite || spell == mage.LivingBomb { //LB dot action should be ignored - return - } - if !result.Landed() { - return - } - if numCrits >= 3 { - return - } - - // TODO: This wont work properly with flamestrike - aura.AddStack(sim) - - if result.DidCrit() { - numCrits++ - if numCrits == 3 { - aura.Deactivate(sim) - } - } - }, - }) - - spell := mage.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete, - Cast: core.CastConfig{ - CD: cd, - }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - return !mage.CombustionAura.IsActive() - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - mage.CombustionAura.Activate(sim) - mage.CombustionAura.AddStack(sim) - }, - }) - - mage.AddMajorCooldown(core.MajorCooldown{ - Spell: spell, - Type: core.CooldownTypeDPS, - }) -} - -func (mage *Mage) registerIcyVeinsCD() { - if !mage.Talents.IcyVeins { - return - } - - actionID := core.ActionID{SpellID: 12472} - - icyVeinsAura := mage.RegisterAura(core.Aura{ - Label: "Icy Veins", - ActionID: actionID, - Duration: time.Second * 20, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.MultiplyCastSpeed(1.2) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.MultiplyCastSpeed(1 / 1.2) - }, - }) - - mage.IcyVeins = mage.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.03, - }, - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: mage.NewTimer(), - Duration: time.Second * time.Duration(180*[]float64{1, .93, .86, .80}[mage.Talents.IceFloes]), - }, - }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - // Need to check for icy veins already active in case Cold Snap is used right after. - return !icyVeinsAura.IsActive() - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - icyVeinsAura.Activate(sim) - }, - }) - - mage.AddMajorCooldown(core.MajorCooldown{ - Spell: mage.IcyVeins, - Type: core.CooldownTypeDPS, - }) -} - -func (mage *Mage) registerColdSnapCD() { - if !mage.Talents.ColdSnap { - return - } - - cooldown := time.Duration(float64(time.Minute*8) * (1.0 - float64(mage.Talents.ColdAsIce)*0.1)) - actionID := core.ActionID{SpellID: 11958} - - spell := mage.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete, - - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: mage.NewTimer(), - Duration: cooldown, - }, - }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - // Don't use if there are no cooldowns to reset. - return (mage.IcyVeins != nil && !mage.IcyVeins.IsReady(sim)) || - (mage.SummonWaterElemental != nil && !mage.SummonWaterElemental.IsReady(sim)) - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - if mage.IcyVeins != nil { - mage.IcyVeins.CD.Reset() - } - if mage.SummonWaterElemental != nil { - mage.SummonWaterElemental.CD.Reset() - } - }, - }) - - mage.AddMajorCooldown(core.MajorCooldown{ - Spell: spell, - Type: core.CooldownTypeDPS, - ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { - // Ideally wait for both water ele and icy veins so we can reset both. - if mage.IcyVeins != nil && mage.IcyVeins.IsReady(sim) { - return false - } - if mage.SummonWaterElemental != nil && mage.SummonWaterElemental.IsReady(sim) { - return false - } - - return true - }, - }) -} - -func (mage *Mage) applyMoltenFury() { - if mage.Talents.MoltenFury == 0 { - return - } - - multiplier := 1.0 + 0.06*float64(mage.Talents.MoltenFury) - - mage.RegisterResetEffect(func(sim *core.Simulation) { - sim.RegisterExecutePhaseCallback(func(sim *core.Simulation, isExecute int32) { - if isExecute == 35 { - mage.PseudoStats.DamageDealtMultiplier *= multiplier - // For some reason Molten Fury doesn't apply to living bomb DoT, so cancel it out. - if mage.LivingBomb != nil { - mage.LivingBomb.DamageMultiplier /= multiplier - } - } - }) - }) -} - -func (mage *Mage) hasChillEffect(spell *core.Spell) bool { - return spell == mage.Frostbolt || spell == mage.FrostfireBolt || (spell == mage.Blizzard && mage.Talents.ImprovedBlizzard > 0) -} - -func (mage *Mage) applyFingersOfFrost() { - if mage.Talents.FingersOfFrost == 0 { - return - } - - bonusCrit := []float64{0, 17, 34, 50}[mage.Talents.Shatter] * core.CritRatingPerCritChance - iceLanceMultiplier := core.TernaryFloat64(mage.HasMajorGlyph(proto.MageMajorGlyph_GlyphOfIceLance), 4, 3) - - var proccedAt time.Duration - - mage.FingersOfFrostAura = mage.RegisterAura(core.Aura{ - Label: "Fingers of Frost Proc", - ActionID: core.ActionID{SpellID: 44545}, - Duration: time.Second * 15, - MaxStacks: 2, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - mage.AddStatDynamic(sim, stats.SpellCrit, bonusCrit) - mage.IceLance.DamageMultiplier *= iceLanceMultiplier - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - mage.AddStatDynamic(sim, stats.SpellCrit, -bonusCrit) - mage.IceLance.DamageMultiplier /= iceLanceMultiplier - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if proccedAt != sim.CurrentTime { - aura.RemoveStack(sim) - } - }, - }) - - procChance := []float64{0, .07, .15}[mage.Talents.FingersOfFrost] - mage.RegisterAura(core.Aura{ - Label: "Fingers of Frost Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if mage.hasChillEffect(spell) && sim.RandomFloat("Fingers of Frost") < procChance { - mage.FingersOfFrostAura.Activate(sim) - mage.FingersOfFrostAura.SetStacks(sim, 2) - proccedAt = sim.CurrentTime - } - }, - }) -} - -func (mage *Mage) applyBrainFreeze() { - if mage.Talents.BrainFreeze == 0 { - return - } - - hasT8_4pc := mage.HasSetBonus(ItemSetKirinTorGarb, 4) - t10ProcAura := mage.BloodmagesRegalia2pcAura() - - mage.BrainFreezeAura = mage.RegisterAura(core.Aura{ - Label: "Brain Freeze Proc", - ActionID: core.ActionID{SpellID: 44549}, - Duration: core.NeverExpires, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - mage.Fireball.CostMultiplier -= 100 - mage.Fireball.CastTimeMultiplier -= 1 - mage.FrostfireBolt.CostMultiplier -= 100 - mage.FrostfireBolt.CastTimeMultiplier -= 1 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - mage.Fireball.CostMultiplier += 100 - mage.Fireball.CastTimeMultiplier += 1 - mage.FrostfireBolt.CostMultiplier += 100 - mage.FrostfireBolt.CastTimeMultiplier += 1 - if t10ProcAura != nil { - t10ProcAura.Activate(sim) - } - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == mage.FrostfireBolt || spell == mage.Fireball { - if !hasT8_4pc || sim.RandomFloat("MageT84PC") > T84PcProcChance { - aura.Deactivate(sim) - } - } - }, - }) - - procChance := .05 * float64(mage.Talents.BrainFreeze) - mage.RegisterAura(core.Aura{ - Label: "Brain Freeze Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if mage.hasChillEffect(spell) && sim.RandomFloat("Brain Freeze") < procChance { - mage.BrainFreezeAura.Activate(sim) - } - }, - }) -} - -func (mage *Mage) applyWintersChill() { - if mage.Talents.WintersChill == 0 { - return - } - - procChance := []float64{0, 0.33, 0.66, 1}[mage.Talents.WintersChill] - - wcAuras := mage.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { - return core.WintersChillAura(target, 0) - }) - mage.Env.RegisterPreFinalizeEffect(func() { - for _, spell := range mage.GetSpellsMatchingSchool(core.SpellSchoolFrost) { - spell.RelatedAuras = append(spell.RelatedAuras, wcAuras) - } - }) - - mage.RegisterAura(core.Aura{ - Label: "Winters Chill Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() || !spell.SpellSchool.Matches(core.SpellSchoolFrost) { - return - } - - if sim.Proc(procChance, "Winters Chill") { - aura := wcAuras.Get(result.Target) - aura.Activate(sim) - if aura.IsActive() { - aura.AddStack(sim) - } - } - }, - }) + // mage.applyArcaneConcentration() + // mage.applyFocusMagic() + // mage.applyIgnite() + // mage.applyEmpoweredFire() + // mage.applyMasterOfElements() + // mage.applyWintersChill() + // mage.applyMoltenFury() + // mage.applyMissileBarrage() + // mage.applyHotStreak() + // mage.applyFingersOfFrost() + // mage.applyBrainFreeze() + // mage.applyFireStarter() + + // mage.registerArcanePowerCD() + // mage.registerPresenceOfMindCD() + // mage.registerCombustionCD() + // mage.registerIcyVeinsCD() + // mage.registerColdSnapCD() + + // mage.PseudoStats.SpiritRegenRateCasting += float64(mage.Talents.ArcaneMeditation) / 6 + + // if mage.Talents.StudentOfTheMind > 0 { + // mage.MultiplyStat(stats.Spirit, 1.0+[]float64{0, .04, .07, .10}[mage.Talents.StudentOfTheMind]) + // } + + // if mage.Talents.ArcaneMind > 0 { + // mage.MultiplyStat(stats.Intellect, 1.0+0.03*float64(mage.Talents.ArcaneMind)) + // } + + // if mage.Talents.MindMastery > 0 { + // mage.AddStatDependency(stats.Intellect, stats.SpellPower, 0.03*float64(mage.Talents.MindMastery)) + // } + + // mage.AddStat(stats.SpellCrit, float64(mage.Talents.ArcaneInstability)*1*core.CritRatingPerCritChance) + // mage.PseudoStats.DamageDealtMultiplier *= 1 + .01*float64(mage.Talents.ArcaneInstability) + // mage.PseudoStats.DamageDealtMultiplier *= 1 + .01*float64(mage.Talents.PlayingWithFire) + // mage.PseudoStats.CastSpeedMultiplier *= 1 + .02*float64(mage.Talents.NetherwindPresence) + + // mage.AddStat(stats.SpellCrit, float64(mage.Talents.Pyromaniac)*core.CritRatingPerCritChance) + // mage.PseudoStats.SpiritRegenRateCasting += float64(mage.Talents.Pyromaniac) / 6 + + // mage.AddStat(stats.SpellHit, float64(mage.Talents.Precision)*core.SpellHitRatingPerHitChance) + // mage.PseudoStats.CostMultiplier *= 1 - .01*float64(mage.Talents.Precision) + + // mage.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFrost] *= 1 + .02*float64(mage.Talents.PiercingIce) + // mage.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFrost] *= 1 + .01*float64(mage.Talents.ArcticWinds) + // mage.PseudoStats.CostMultiplier *= 1 - .04*float64(mage.Talents.FrostChanneling) + + // magicAbsorptionBonus := 2 * float64(mage.Talents.MagicAbsorption) + // mage.AddStat(stats.ArcaneResistance, magicAbsorptionBonus) + // mage.AddStat(stats.FireResistance, magicAbsorptionBonus) + // mage.AddStat(stats.FrostResistance, magicAbsorptionBonus) + // mage.AddStat(stats.NatureResistance, magicAbsorptionBonus) + // mage.AddStat(stats.ShadowResistance, magicAbsorptionBonus) } -func (mage *Mage) applyFireStarter() { - if mage.Talents.Firestarter == 0 { - return - } - - firestarterAura := mage.RegisterAura(core.Aura{ - Label: "Firestarter", - ActionID: core.ActionID{SpellID: 54741}, - Duration: 10 * time.Second, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - mage.Flamestrike.CostMultiplier -= 100 - mage.Flamestrike.CastTimeMultiplier -= 1 - mage.FlamestrikeRank8.CostMultiplier -= 100 - mage.FlamestrikeRank8.CastTimeMultiplier -= 1 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - mage.Flamestrike.CostMultiplier += 100 - mage.Flamestrike.CastTimeMultiplier += 1 - mage.FlamestrikeRank8.CostMultiplier += 100 - mage.FlamestrikeRank8.CastTimeMultiplier += 1 - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell == mage.Flamestrike || spell == mage.FlamestrikeRank8 { - aura.Deactivate(sim) - } - }, - }) - - mage.RegisterAura(core.Aura{ - Label: "Firestarter talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() { - return - } - - if spell == mage.BlastWave || spell == mage.DragonsBreath { - firestarterAura.Activate(sim) - } - }, - }) -} +// func (mage *Mage) applyHotStreak() { +// if mage.Talents.HotStreak == 0 { +// return +// } + +// procChance := float64(mage.Talents.HotStreak) / 3 +// t10ProcAura := mage.BloodmagesRegalia2pcAura() + +// mage.HotStreakAura = mage.RegisterAura(core.Aura{ +// Label: "HotStreak", +// ActionID: core.ActionID{SpellID: 44448}, +// Duration: time.Second * 10, +// // This is handled in Pyroblast.ModifyCast instead. +// //OnGain: func(aura *core.Aura, sim *core.Simulation) { +// // if mage.Pyroblast != nil { +// // mage.Pyroblast.CastTimeMultiplier -= 1 +// // } +// //}, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// //if mage.Pyroblast != nil { +// // mage.Pyroblast.CastTimeMultiplier += 1 +// //} +// if t10ProcAura != nil { +// t10ProcAura.Activate(sim) +// } +// }, +// }) + +// mage.hotStreakCritAura = mage.RegisterAura(core.Aura{ +// Label: "Hot Streak Proc Aura", +// ActionID: core.ActionID{SpellID: 44448, Tag: 1}, +// MaxStacks: 2, +// Duration: time.Hour, +// }) + +// mage.RegisterAura(core.Aura{ +// Label: "Hot Streak Trigger", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.Flags.Matches(HotStreakSpells) { +// return +// } + +// if !result.DidCrit() { +// mage.hotStreakCritAura.SetStacks(sim, 0) +// mage.hotStreakCritAura.Deactivate(sim) +// return +// } + +// if mage.hotStreakCritAura.GetStacks() == 1 { +// if procChance == 1 || sim.Proc(procChance, "Hot Streak") { +// mage.hotStreakCritAura.SetStacks(sim, 0) +// mage.hotStreakCritAura.Deactivate(sim) + +// mage.HotStreakAura.Activate(sim) +// } +// } else { +// mage.hotStreakCritAura.Activate(sim) +// mage.hotStreakCritAura.AddStack(sim) +// } +// }, +// }) + +// } + +// func (mage *Mage) applyArcaneConcentration() { +// if mage.Talents.ArcaneConcentration == 0 { +// return +// } + +// bonusCrit := float64(mage.Talents.ArcanePotency) * 15 * core.CritRatingPerCritChance + +// // The result that caused the proc. Used to check we don't deactivate from the same proc. +// var proccedAt time.Duration +// var proccedSpell *core.Spell + +// if mage.Talents.ArcanePotency > 0 { +// mage.ArcanePotencyAura = mage.RegisterAura(core.Aura{ +// Label: "Arcane Potency", +// ActionID: core.ActionID{SpellID: 31572}, +// Duration: time.Second * 15, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.AddStatDynamic(sim, stats.SpellCrit, bonusCrit) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.AddStatDynamic(sim, stats.SpellCrit, -bonusCrit) +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if !spell.Flags.Matches(SpellFlagMage) { +// return +// } +// if proccedAt == sim.CurrentTime && proccedSpell == spell { +// // Means this is another hit from the same cast that procced CC. +// return +// } +// aura.Deactivate(sim) +// }, +// }) +// } + +// mage.ClearcastingAura = mage.RegisterAura(core.Aura{ +// Label: "Clearcasting", +// ActionID: core.ActionID{SpellID: 12536}, +// Duration: time.Second * 15, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.PseudoStats.CostMultiplier -= 1 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.PseudoStats.CostMultiplier += 1 +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if !spell.Flags.Matches(SpellFlagMage) { +// return +// } +// if spell.DefaultCast.Cost == 0 { +// return +// } +// if spell == mage.ArcaneMissiles && mage.MissileBarrageAura.IsActive() { +// return +// } +// if proccedAt == sim.CurrentTime && proccedSpell == spell { +// // Means this is another hit from the same cast that procced CC. +// return +// } +// aura.Deactivate(sim) +// }, +// }) + +// mage.RegisterAura(core.Aura{ +// Label: "Arcane Concentration", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.Flags.Matches(SpellFlagMage) || spell == mage.ArcaneMissiles { +// return +// } + +// if !result.Landed() { +// return +// } + +// procChance := 0.02 * float64(mage.Talents.ArcaneConcentration) + +// // Arcane Missile ticks can proc CC, just at a low rate of about 1.5% with 5/5 Arcane Concentration +// if spell == mage.ArcaneMissilesTickSpell { +// procChance *= 0.15 +// } + +// if sim.RandomFloat("Arcane Concentration") > procChance { +// return +// } + +// proccedAt = sim.CurrentTime +// proccedSpell = spell +// mage.ClearcastingAura.Activate(sim) +// if mage.ArcanePotencyAura != nil { +// mage.ArcanePotencyAura.Activate(sim) +// } +// }, +// }) +// } + +// func (mage *Mage) applyMissileBarrage() { +// if mage.Talents.MissileBarrage == 0 { +// return +// } + +// t10ProcAura := mage.BloodmagesRegalia2pcAura() + +// procChance := float64(mage.Talents.MissileBarrage) * .04 +// mage.MissileBarrageAura = mage.RegisterAura(core.Aura{ +// Label: "Missile Barrage Proc", +// ActionID: core.ActionID{SpellID: 44401}, +// Duration: time.Second * 15, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// mage.ArcaneMissiles.CostMultiplier -= 100 +// mage.ArcaneMissiles.CastTimeMultiplier /= 2 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// mage.ArcaneMissiles.CostMultiplier += 100 +// mage.ArcaneMissiles.CastTimeMultiplier *= 2 +// if t10ProcAura != nil { +// t10ProcAura.Activate(sim) +// } +// }, +// }) + +// mage.RegisterAura(core.Aura{ +// Label: "Missile Barrage Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if !spell.Flags.Matches(BarrageSpells) { +// return +// } + +// roll := sim.RandomFloat("Missile Barrage") +// updChance := core.TernaryFloat64(spell.ActionID == mage.ArcaneBlast.ActionID, 2*procChance, procChance) + +// if roll < updChance { +// mage.MissileBarrageAura.Activate(sim) +// } +// }, +// }) +// } + +// func (mage *Mage) registerPresenceOfMindCD() { +// if !mage.Talents.PresenceOfMind { +// return +// } + +// cooldown := 120.0 +// if mage.Talents.ArcaneFlows > 0 { +// cooldown *= 1 - (.15 * float64(mage.Talents.ArcaneFlows)) +// } + +// actionID := core.ActionID{SpellID: 12043} + +// var spellToUse *core.Spell +// mage.Env.RegisterPostFinalizeEffect(func() { +// if mage.Pyroblast != nil { +// spellToUse = mage.Pyroblast +// } else if mage.PrimaryTalentTree == 1 { +// spellToUse = mage.Fireball +// } else if mage.PrimaryTalentTree == 2 { +// spellToUse = mage.Frostbolt +// } else { +// spellToUse = mage.ArcaneBlast +// } +// }) + +// spell := mage.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagNoOnCastComplete, +// Cast: core.CastConfig{ +// CD: core.Cooldown{ +// Timer: mage.NewTimer(), +// Duration: time.Duration(cooldown) * time.Second, +// }, +// }, +// ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { +// if !mage.GCD.IsReady(sim) { +// return false +// } +// if mage.ArcanePowerAura.IsActive() { +// return false +// } + +// manaCost := spellToUse.DefaultCast.Cost * mage.PseudoStats.CostMultiplier +// if spellToUse == mage.ArcaneBlast { +// manaCost *= float64(mage.ArcaneBlastAura.GetStacks()) * 1.75 +// } + +// return mage.CurrentMana() >= manaCost +// }, +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// if mage.ArcanePotencyAura != nil { +// mage.ArcanePotencyAura.Activate(sim) +// } + +// normalCastTime := spellToUse.DefaultCast.CastTime +// spellToUse.DefaultCast.CastTime = 0 +// spellToUse.Cast(sim, mage.CurrentTarget) +// spellToUse.DefaultCast.CastTime = normalCastTime +// }, +// }) + +// mage.AddMajorCooldown(core.MajorCooldown{ +// Spell: spell, +// Type: core.CooldownTypeDPS, +// }) +// } + +// func (mage *Mage) registerArcanePowerCD() { +// if !mage.Talents.ArcanePower { +// return +// } +// actionID := core.ActionID{SpellID: 12042} + +// var affectedSpells []*core.Spell +// mage.OnSpellRegistered(func(spell *core.Spell) { +// if spell.Flags.Matches(SpellFlagMage) { +// affectedSpells = append(affectedSpells, spell) +// } +// }) + +// mage.ArcanePowerAura = mage.RegisterAura(core.Aura{ +// Label: "Arcane Power", +// ActionID: actionID, +// Duration: core.TernaryDuration(mage.HasMajorGlyph(proto.MageMajorGlyph_GlyphOfArcanePower), time.Second*18, time.Second*15), +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range affectedSpells { +// spell.DamageMultiplierAdditive += 0.2 +// spell.CostMultiplier += 0.2 +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range affectedSpells { +// spell.DamageMultiplierAdditive -= 0.2 +// spell.CostMultiplier -= 0.2 +// } +// }, +// }) +// core.RegisterPercentDamageModifierEffect(mage.ArcanePowerAura, 1.2) + +// spell := mage.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagNoOnCastComplete, +// Cast: core.CastConfig{ +// CD: core.Cooldown{ +// Timer: mage.NewTimer(), +// Duration: time.Second * time.Duration(120*(1-(.15*float64(mage.Talents.ArcaneFlows)))), +// }, +// }, +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// mage.ArcanePowerAura.Activate(sim) +// }, +// ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { +// return !mage.ArcanePotencyAura.IsActive() +// }, +// }) + +// mage.AddMajorCooldown(core.MajorCooldown{ +// Spell: spell, +// Type: core.CooldownTypeDPS, +// }) +// } + +// func (mage *Mage) applyMasterOfElements() { +// if mage.Talents.MasterOfElements == 0 && mage.Talents.Burnout == 0 { +// return +// } + +// refundCoeff := 0.1*float64(mage.Talents.MasterOfElements) - .01*float64(mage.Talents.Burnout) +// manaMetrics := mage.NewManaMetrics(core.ActionID{SpellID: 29076}) + +// mage.RegisterAura(core.Aura{ +// Label: "Master of Elements", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell.ProcMask.Matches(core.ProcMaskMeleeOrRanged) { +// return +// } +// if spell.CurCast.Cost == 0 { +// return +// } +// if result.DidCrit() { +// if refundCoeff < 0 { +// mage.SpendMana(sim, -1*spell.DefaultCast.Cost*refundCoeff, manaMetrics) +// } else { +// mage.AddMana(sim, spell.DefaultCast.Cost*refundCoeff, manaMetrics) +// } +// } +// }, +// }) +// } + +// func (mage *Mage) registerCombustionCD() { +// if !mage.Talents.Combustion { +// return +// } +// actionID := core.ActionID{SpellID: 11129} +// cd := core.Cooldown{ +// Timer: mage.NewTimer(), +// Duration: time.Minute * 2, +// } + +// fireCombCritMult := mage.SpellCritMultiplier(1, mage.bonusCritDamage+.5) / mage.SpellCritMultiplier(1, mage.bonusCritDamage) + +// frostfireCombCritMult := mage.SpellCritMultiplier(1, mage.bonusCritDamage+float64(mage.Talents.IceShards)/3+.5) / +// mage.SpellCritMultiplier(1, mage.bonusCritDamage+float64(mage.Talents.IceShards)/3) + +// var fireSpells []*core.Spell +// mage.OnSpellRegistered(func(spell *core.Spell) { +// if spell.SpellSchool.Matches(core.SpellSchoolFire) { +// fireSpells = append(fireSpells, spell) +// } +// }) + +// numCrits := 0 +// const critPerStack = 10 * core.CritRatingPerCritChance + +// mage.CombustionAura = mage.RegisterAura(core.Aura{ +// Label: "Combustion", +// ActionID: actionID, +// Duration: core.NeverExpires, +// MaxStacks: 20, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// numCrits = 0 +// for _, spell := range fireSpells { +// spell.CritMultiplier *= core.TernaryFloat64(spell != mage.FrostfireBolt, fireCombCritMult, frostfireCombCritMult) +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// cd.Use(sim) +// mage.UpdateMajorCooldowns() +// for _, spell := range fireSpells { +// spell.CritMultiplier /= core.TernaryFloat64(spell != mage.FrostfireBolt, fireCombCritMult, frostfireCombCritMult) +// } +// }, +// OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { +// bonusCrit := critPerStack * float64(newStacks-oldStacks) +// for _, spell := range fireSpells { +// spell.BonusCritRating += bonusCrit +// } +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.SpellSchool.Matches(core.SpellSchoolFire) || !spell.Flags.Matches(SpellFlagMage) { +// return +// } +// if spell == mage.Ignite || spell == mage.LivingBomb { //LB dot action should be ignored +// return +// } +// if !result.Landed() { +// return +// } +// if numCrits >= 3 { +// return +// } + +// // TODO: This wont work properly with flamestrike +// aura.AddStack(sim) + +// if result.DidCrit() { +// numCrits++ +// if numCrits == 3 { +// aura.Deactivate(sim) +// } +// } +// }, +// }) + +// spell := mage.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagNoOnCastComplete, +// Cast: core.CastConfig{ +// CD: cd, +// }, +// ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { +// return !mage.CombustionAura.IsActive() +// }, +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// mage.CombustionAura.Activate(sim) +// mage.CombustionAura.AddStack(sim) +// }, +// }) + +// mage.AddMajorCooldown(core.MajorCooldown{ +// Spell: spell, +// Type: core.CooldownTypeDPS, +// }) +// } + +// func (mage *Mage) registerIcyVeinsCD() { +// if !mage.Talents.IcyVeins { +// return +// } + +// actionID := core.ActionID{SpellID: 12472} + +// icyVeinsAura := mage.RegisterAura(core.Aura{ +// Label: "Icy Veins", +// ActionID: actionID, +// Duration: time.Second * 20, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.MultiplyCastSpeed(1.2) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.MultiplyCastSpeed(1 / 1.2) +// }, +// }) + +// mage.IcyVeins = mage.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagNoOnCastComplete, + +// ManaCost: core.ManaCostOptions{ +// BaseCost: 0.03, +// }, +// Cast: core.CastConfig{ +// CD: core.Cooldown{ +// Timer: mage.NewTimer(), +// Duration: time.Second * time.Duration(180*[]float64{1, .93, .86, .80}[mage.Talents.IceFloes]), +// }, +// }, +// ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { +// // Need to check for icy veins already active in case Cold Snap is used right after. +// return !icyVeinsAura.IsActive() +// }, +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// icyVeinsAura.Activate(sim) +// }, +// }) + +// mage.AddMajorCooldown(core.MajorCooldown{ +// Spell: mage.IcyVeins, +// Type: core.CooldownTypeDPS, +// }) +// } + +// func (mage *Mage) registerColdSnapCD() { +// if !mage.Talents.ColdSnap { +// return +// } + +// cooldown := time.Duration(float64(time.Minute*8) * (1.0 - float64(mage.Talents.ColdAsIce)*0.1)) +// actionID := core.ActionID{SpellID: 11958} + +// spell := mage.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagNoOnCastComplete, + +// Cast: core.CastConfig{ +// CD: core.Cooldown{ +// Timer: mage.NewTimer(), +// Duration: cooldown, +// }, +// }, +// ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { +// // Don't use if there are no cooldowns to reset. +// return (mage.IcyVeins != nil && !mage.IcyVeins.IsReady(sim)) || +// (mage.SummonWaterElemental != nil && !mage.SummonWaterElemental.IsReady(sim)) +// }, +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// if mage.IcyVeins != nil { +// mage.IcyVeins.CD.Reset() +// } +// if mage.SummonWaterElemental != nil { +// mage.SummonWaterElemental.CD.Reset() +// } +// }, +// }) + +// mage.AddMajorCooldown(core.MajorCooldown{ +// Spell: spell, +// Type: core.CooldownTypeDPS, +// ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { +// // Ideally wait for both water ele and icy veins so we can reset both. +// if mage.IcyVeins != nil && mage.IcyVeins.IsReady(sim) { +// return false +// } +// if mage.SummonWaterElemental != nil && mage.SummonWaterElemental.IsReady(sim) { +// return false +// } + +// return true +// }, +// }) +// } + +// func (mage *Mage) applyMoltenFury() { +// if mage.Talents.MoltenFury == 0 { +// return +// } + +// multiplier := 1.0 + 0.06*float64(mage.Talents.MoltenFury) + +// mage.RegisterResetEffect(func(sim *core.Simulation) { +// sim.RegisterExecutePhaseCallback(func(sim *core.Simulation, isExecute int32) { +// if isExecute == 35 { +// mage.PseudoStats.DamageDealtMultiplier *= multiplier +// // For some reason Molten Fury doesn't apply to living bomb DoT, so cancel it out. +// if mage.LivingBomb != nil { +// mage.LivingBomb.DamageMultiplier /= multiplier +// } +// } +// }) +// }) +// } + +// func (mage *Mage) hasChillEffect(spell *core.Spell) bool { +// return spell == mage.Frostbolt || spell == mage.FrostfireBolt || (spell == mage.Blizzard && mage.Talents.ImprovedBlizzard > 0) +// } + +// func (mage *Mage) applyFingersOfFrost() { +// if mage.Talents.FingersOfFrost == 0 { +// return +// } + +// bonusCrit := []float64{0, 17, 34, 50}[mage.Talents.Shatter] * core.CritRatingPerCritChance +// iceLanceMultiplier := core.TernaryFloat64(mage.HasMajorGlyph(proto.MageMajorGlyph_GlyphOfIceLance), 4, 3) + +// var proccedAt time.Duration + +// mage.FingersOfFrostAura = mage.RegisterAura(core.Aura{ +// Label: "Fingers of Frost Proc", +// ActionID: core.ActionID{SpellID: 44545}, +// Duration: time.Second * 15, +// MaxStacks: 2, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// mage.AddStatDynamic(sim, stats.SpellCrit, bonusCrit) +// mage.IceLance.DamageMultiplier *= iceLanceMultiplier +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// mage.AddStatDynamic(sim, stats.SpellCrit, -bonusCrit) +// mage.IceLance.DamageMultiplier /= iceLanceMultiplier +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if proccedAt != sim.CurrentTime { +// aura.RemoveStack(sim) +// } +// }, +// }) + +// procChance := []float64{0, .07, .15}[mage.Talents.FingersOfFrost] +// mage.RegisterAura(core.Aura{ +// Label: "Fingers of Frost Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if mage.hasChillEffect(spell) && sim.RandomFloat("Fingers of Frost") < procChance { +// mage.FingersOfFrostAura.Activate(sim) +// mage.FingersOfFrostAura.SetStacks(sim, 2) +// proccedAt = sim.CurrentTime +// } +// }, +// }) +// } + +// func (mage *Mage) applyBrainFreeze() { +// if mage.Talents.BrainFreeze == 0 { +// return +// } + +// hasT8_4pc := mage.HasSetBonus(ItemSetKirinTorGarb, 4) +// t10ProcAura := mage.BloodmagesRegalia2pcAura() + +// mage.BrainFreezeAura = mage.RegisterAura(core.Aura{ +// Label: "Brain Freeze Proc", +// ActionID: core.ActionID{SpellID: 44549}, +// Duration: core.NeverExpires, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// mage.Fireball.CostMultiplier -= 100 +// mage.Fireball.CastTimeMultiplier -= 1 +// mage.FrostfireBolt.CostMultiplier -= 100 +// mage.FrostfireBolt.CastTimeMultiplier -= 1 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// mage.Fireball.CostMultiplier += 100 +// mage.Fireball.CastTimeMultiplier += 1 +// mage.FrostfireBolt.CostMultiplier += 100 +// mage.FrostfireBolt.CastTimeMultiplier += 1 +// if t10ProcAura != nil { +// t10ProcAura.Activate(sim) +// } +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == mage.FrostfireBolt || spell == mage.Fireball { +// if !hasT8_4pc || sim.RandomFloat("MageT84PC") > T84PcProcChance { +// aura.Deactivate(sim) +// } +// } +// }, +// }) + +// procChance := .05 * float64(mage.Talents.BrainFreeze) +// mage.RegisterAura(core.Aura{ +// Label: "Brain Freeze Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if mage.hasChillEffect(spell) && sim.RandomFloat("Brain Freeze") < procChance { +// mage.BrainFreezeAura.Activate(sim) +// } +// }, +// }) +// } + +// func (mage *Mage) applyWintersChill() { +// if mage.Talents.WintersChill == 0 { +// return +// } + +// procChance := []float64{0, 0.33, 0.66, 1}[mage.Talents.WintersChill] + +// wcAuras := mage.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { +// return core.WintersChillAura(target, 0) +// }) +// mage.Env.RegisterPreFinalizeEffect(func() { +// for _, spell := range mage.GetSpellsMatchingSchool(core.SpellSchoolFrost) { +// spell.RelatedAuras = append(spell.RelatedAuras, wcAuras) +// } +// }) + +// mage.RegisterAura(core.Aura{ +// Label: "Winters Chill Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() || !spell.SpellSchool.Matches(core.SpellSchoolFrost) { +// return +// } + +// if sim.Proc(procChance, "Winters Chill") { +// aura := wcAuras.Get(result.Target) +// aura.Activate(sim) +// if aura.IsActive() { +// aura.AddStack(sim) +// } +// } +// }, +// }) +// } + +// func (mage *Mage) applyFireStarter() { +// if mage.Talents.Firestarter == 0 { +// return +// } + +// firestarterAura := mage.RegisterAura(core.Aura{ +// Label: "Firestarter", +// ActionID: core.ActionID{SpellID: 54741}, +// Duration: 10 * time.Second, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// mage.Flamestrike.CostMultiplier -= 100 +// mage.Flamestrike.CastTimeMultiplier -= 1 +// mage.FlamestrikeRank8.CostMultiplier -= 100 +// mage.FlamestrikeRank8.CastTimeMultiplier -= 1 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// mage.Flamestrike.CostMultiplier += 100 +// mage.Flamestrike.CastTimeMultiplier += 1 +// mage.FlamestrikeRank8.CostMultiplier += 100 +// mage.FlamestrikeRank8.CastTimeMultiplier += 1 +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if spell == mage.Flamestrike || spell == mage.FlamestrikeRank8 { +// aura.Deactivate(sim) +// } +// }, +// }) + +// mage.RegisterAura(core.Aura{ +// Label: "Firestarter talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() { +// return +// } + +// if spell == mage.BlastWave || spell == mage.DragonsBreath { +// firestarterAura.Activate(sim) +// } +// }, +// }) +// } diff --git a/sim/paladin/avengers_shield.go b/sim/paladin/_avengers_shield.go similarity index 100% rename from sim/paladin/avengers_shield.go rename to sim/paladin/_avengers_shield.go diff --git a/sim/paladin/avenging_wrath.go b/sim/paladin/_avenging_wrath.go similarity index 100% rename from sim/paladin/avenging_wrath.go rename to sim/paladin/_avenging_wrath.go diff --git a/sim/paladin/consecration.go b/sim/paladin/_consecration.go similarity index 100% rename from sim/paladin/consecration.go rename to sim/paladin/_consecration.go diff --git a/sim/paladin/crusader_strike.go b/sim/paladin/_crusader_strike.go similarity index 100% rename from sim/paladin/crusader_strike.go rename to sim/paladin/_crusader_strike.go diff --git a/sim/paladin/divine_plea.go b/sim/paladin/_divine_plea.go similarity index 100% rename from sim/paladin/divine_plea.go rename to sim/paladin/_divine_plea.go diff --git a/sim/paladin/divine_protection.go b/sim/paladin/_divine_protection.go similarity index 100% rename from sim/paladin/divine_protection.go rename to sim/paladin/_divine_protection.go diff --git a/sim/paladin/divine_storm.go b/sim/paladin/_divine_storm.go similarity index 100% rename from sim/paladin/divine_storm.go rename to sim/paladin/_divine_storm.go diff --git a/sim/paladin/exorcism.go b/sim/paladin/_exorcism.go similarity index 100% rename from sim/paladin/exorcism.go rename to sim/paladin/_exorcism.go diff --git a/sim/paladin/hammer_of_the_righteous.go b/sim/paladin/_hammer_of_the_righteous.go similarity index 100% rename from sim/paladin/hammer_of_the_righteous.go rename to sim/paladin/_hammer_of_the_righteous.go diff --git a/sim/paladin/hammer_of_wrath.go b/sim/paladin/_hammer_of_wrath.go similarity index 100% rename from sim/paladin/hammer_of_wrath.go rename to sim/paladin/_hammer_of_wrath.go diff --git a/sim/paladin/hand_of_reckoning.go b/sim/paladin/_hand_of_reckoning.go similarity index 100% rename from sim/paladin/hand_of_reckoning.go rename to sim/paladin/_hand_of_reckoning.go diff --git a/sim/paladin/holy_shield.go b/sim/paladin/_holy_shield.go similarity index 100% rename from sim/paladin/holy_shield.go rename to sim/paladin/_holy_shield.go diff --git a/sim/paladin/holy_wrath.go b/sim/paladin/_holy_wrath.go similarity index 100% rename from sim/paladin/holy_wrath.go rename to sim/paladin/_holy_wrath.go diff --git a/sim/paladin/items.go b/sim/paladin/_items.go similarity index 100% rename from sim/paladin/items.go rename to sim/paladin/_items.go diff --git a/sim/paladin/judgement.go b/sim/paladin/_judgement.go similarity index 100% rename from sim/paladin/judgement.go rename to sim/paladin/_judgement.go diff --git a/sim/paladin/righteous_fury.go b/sim/paladin/_righteous_fury.go similarity index 100% rename from sim/paladin/righteous_fury.go rename to sim/paladin/_righteous_fury.go diff --git a/sim/paladin/seals.go b/sim/paladin/_seals.go similarity index 100% rename from sim/paladin/seals.go rename to sim/paladin/_seals.go diff --git a/sim/paladin/shield_of_righteousness.go b/sim/paladin/_shield_of_righteousness.go similarity index 100% rename from sim/paladin/shield_of_righteousness.go rename to sim/paladin/_shield_of_righteousness.go diff --git a/sim/paladin/soc.go b/sim/paladin/_soc.go similarity index 100% rename from sim/paladin/soc.go rename to sim/paladin/_soc.go diff --git a/sim/paladin/sor.go b/sim/paladin/_sor.go similarity index 100% rename from sim/paladin/sor.go rename to sim/paladin/_sor.go diff --git a/sim/paladin/sov.go b/sim/paladin/_sov.go similarity index 100% rename from sim/paladin/sov.go rename to sim/paladin/_sov.go diff --git a/sim/paladin/spiritual_attunement.go b/sim/paladin/_spiritual_attunement.go similarity index 100% rename from sim/paladin/spiritual_attunement.go rename to sim/paladin/_spiritual_attunement.go diff --git a/sim/paladin/paladin.go b/sim/paladin/paladin.go index 592e9e8334..dda452cce6 100644 --- a/sim/paladin/paladin.go +++ b/sim/paladin/paladin.go @@ -3,7 +3,6 @@ package paladin import ( "github.com/wowsims/cata/sim/core" "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" ) const ( @@ -94,21 +93,21 @@ func (paladin *Paladin) GetPaladin() *Paladin { } func (paladin *Paladin) AddRaidBuffs(raidBuffs *proto.RaidBuffs) { - raidBuffs.DevotionAura = max(raidBuffs.DevotionAura, core.MakeTristateValue( - paladin.PaladinAura == proto.PaladinAura_DevotionAura, - paladin.Talents.ImprovedDevotionAura == 5)) + // raidBuffs.DevotionAura = max(raidBuffs.DevotionAura, core.MakeTristateValue( + // paladin.PaladinAura == proto.PaladinAura_DevotionAura, + // paladin.Talents.ImprovedDevotionAura == 5)) - if paladin.PaladinAura == proto.PaladinAura_RetributionAura { - raidBuffs.RetributionAura = true - } + // if paladin.PaladinAura == proto.PaladinAura_RetributionAura { + // raidBuffs.RetributionAura = true + // } - if paladin.Talents.SanctifiedRetribution { - raidBuffs.SanctifiedRetribution = true - } + // if paladin.Talents.SanctifiedRetribution { + // raidBuffs.SanctifiedRetribution = true + // } - if paladin.Talents.SwiftRetribution == 3 { - raidBuffs.SwiftRetribution = paladin.Talents.SwiftRetribution == 3 // TODO: Fix-- though having something between 0/3 and 3/3 is unlikely - } + // if paladin.Talents.SwiftRetribution == 3 { + // raidBuffs.SwiftRetribution = paladin.Talents.SwiftRetribution == 3 // TODO: Fix-- though having something between 0/3 and 3/3 is unlikely + // } // TODO: Figure out a way to just start with 1 DG cooldown available without making a redundant Spell //if paladin.Talents.DivineGuardian == 2 { @@ -120,43 +119,43 @@ func (paladin *Paladin) AddPartyBuffs(_ *proto.PartyBuffs) { } func (paladin *Paladin) Initialize() { - // Update auto crit multipliers now that we have the targets. - paladin.AutoAttacks.MHConfig().CritMultiplier = paladin.MeleeCritMultiplier() - - paladin.registerSealOfVengeanceSpellAndAura() - paladin.registerSealOfRighteousnessSpellAndAura() - paladin.registerSealOfCommandSpellAndAura() - // paladin.setupSealOfTheCrusader() - // paladin.setupSealOfWisdom() - // paladin.setupSealOfLight() - // paladin.setupSealOfRighteousness() - // paladin.setupJudgementRefresh() - - paladin.registerCrusaderStrikeSpell() - paladin.registerDivineStormSpell() - paladin.registerConsecrationSpell() - paladin.registerHammerOfWrathSpell() - paladin.registerHolyWrathSpell() - - paladin.registerExorcismSpell() - paladin.registerHolyShieldSpell() - paladin.registerHammerOfTheRighteousSpell() - paladin.registerHandOfReckoningSpell() - paladin.registerShieldOfRighteousnessSpell() - paladin.registerAvengersShieldSpell() - paladin.registerJudgements() - - paladin.registerSpiritualAttunement() - paladin.registerDivinePleaSpell() - paladin.registerDivineProtectionSpell() - paladin.registerForbearanceDebuff() - - for i := int32(0); i < paladin.Env.GetNumTargets(); i++ { - unit := paladin.Env.GetTargetUnit(i) - if unit.MobType == proto.MobType_MobTypeDemon || unit.MobType == proto.MobType_MobTypeUndead { - paladin.DemonAndUndeadTargetCount += 1 - } - } + // // Update auto crit multipliers now that we have the targets. + // paladin.AutoAttacks.MHConfig().CritMultiplier = paladin.MeleeCritMultiplier() + + // paladin.registerSealOfVengeanceSpellAndAura() + // paladin.registerSealOfRighteousnessSpellAndAura() + // paladin.registerSealOfCommandSpellAndAura() + // // paladin.setupSealOfTheCrusader() + // // paladin.setupSealOfWisdom() + // // paladin.setupSealOfLight() + // // paladin.setupSealOfRighteousness() + // // paladin.setupJudgementRefresh() + + // paladin.registerCrusaderStrikeSpell() + // paladin.registerDivineStormSpell() + // paladin.registerConsecrationSpell() + // paladin.registerHammerOfWrathSpell() + // paladin.registerHolyWrathSpell() + + // paladin.registerExorcismSpell() + // paladin.registerHolyShieldSpell() + // paladin.registerHammerOfTheRighteousSpell() + // paladin.registerHandOfReckoningSpell() + // paladin.registerShieldOfRighteousnessSpell() + // paladin.registerAvengersShieldSpell() + // paladin.registerJudgements() + + // paladin.registerSpiritualAttunement() + // paladin.registerDivinePleaSpell() + // paladin.registerDivineProtectionSpell() + // paladin.registerForbearanceDebuff() + + // for i := int32(0); i < paladin.Env.GetNumTargets(); i++ { + // unit := paladin.Env.GetTargetUnit(i) + // if unit.MobType == proto.MobType_MobTypeDemon || unit.MobType == proto.MobType_MobTypeUndead { + // paladin.DemonAndUndeadTargetCount += 1 + // } + // } } func (paladin *Paladin) Reset(_ *core.Simulation) { @@ -170,32 +169,32 @@ func NewPaladin(character *core.Character, talentsStr string) *Paladin { Character: *character, Talents: &proto.PaladinTalents{}, } - core.FillTalentsProto(paladin.Talents.ProtoReflect(), talentsStr, TalentTreeSizes) + // core.FillTalentsProto(paladin.Talents.ProtoReflect(), talentsStr, TalentTreeSizes) - // This is used to cache its effect in talents.go - paladin.HasTuralyonsOrLiadrinsBattlegear2Pc = paladin.HasSetBonus(ItemSetTuralyonsBattlegear, 2) + // // This is used to cache its effect in talents.go + // paladin.HasTuralyonsOrLiadrinsBattlegear2Pc = paladin.HasSetBonus(ItemSetTuralyonsBattlegear, 2) - paladin.PseudoStats.CanParry = true + // paladin.PseudoStats.CanParry = true - paladin.EnableManaBar() - paladin.AddStatDependency(stats.Strength, stats.AttackPower, 2.0) - paladin.AddStatDependency(stats.Agility, stats.MeleeCrit, core.CritPerAgiMaxLevel[character.Class]*core.CritRatingPerCritChance) + // paladin.EnableManaBar() + // paladin.AddStatDependency(stats.Strength, stats.AttackPower, 2.0) + // paladin.AddStatDependency(stats.Agility, stats.MeleeCrit, core.CritPerAgiMaxLevel[character.Class]*core.CritRatingPerCritChance) - // Paladins get 0.0167 dodge per agi. ~1% per 59.88 - paladin.AddStatDependency(stats.Agility, stats.Dodge, (1.0/59.88)*core.DodgeRatingPerDodgeChance) + // // Paladins get 0.0167 dodge per agi. ~1% per 59.88 + // paladin.AddStatDependency(stats.Agility, stats.Dodge, (1.0/59.88)*core.DodgeRatingPerDodgeChance) - // Paladins get more melee haste from haste than other classes - paladin.PseudoStats.MeleeHasteRatingPerHastePercent /= 1.3 + // // Paladins get more melee haste from haste than other classes + // paladin.PseudoStats.MeleeHasteRatingPerHastePercent /= 1.3 - // Paladins get 1 block value per 2 str - paladin.AddStatDependency(stats.Strength, stats.BlockValue, .5) + // // Paladins get 1 block value per 2 str + // paladin.AddStatDependency(stats.Strength, stats.BlockValue, .5) - // Bonus Armor and Armor are treated identically for Paladins - paladin.AddStatDependency(stats.BonusArmor, stats.Armor, 1) + // // Bonus Armor and Armor are treated identically for Paladins + // paladin.AddStatDependency(stats.BonusArmor, stats.Armor, 1) - // Base dodge is unaffected by Diminishing Returns - paladin.PseudoStats.BaseDodge += 0.034943 - paladin.PseudoStats.BaseParry += 0.05 + // // Base dodge is unaffected by Diminishing Returns + // paladin.PseudoStats.BaseDodge += 0.034943 + // paladin.PseudoStats.BaseParry += 0.05 return paladin } diff --git a/sim/paladin/protection/protection.go b/sim/paladin/protection/protection.go index cac8e92e8b..a98f199713 100644 --- a/sim/paladin/protection/protection.go +++ b/sim/paladin/protection/protection.go @@ -32,21 +32,21 @@ func NewProtectionPaladin(character *core.Character, options *proto.Player) *Pro Seal: protOptions.Options.ClassOptions.Seal, } - prot.PaladinAura = protOptions.Options.ClassOptions.Aura + // prot.PaladinAura = protOptions.Options.ClassOptions.Aura - prot.HasGlyphAS = prot.HasMajorGlyph(proto.PaladinMajorGlyph_GlyphOfAvengerSShield) + // //prot.HasGlyphAS = prot.HasMajorGlyph(proto.PaladinMajorGlyph_GlyphOfAvengerSShield) - prot.EnableAutoAttacks(prot, core.AutoAttackOptions{ - MainHand: prot.WeaponFromMainHand(0), // Set crit multiplier later when we have targets. - AutoSwingMelee: true, - }) + // prot.EnableAutoAttacks(prot, core.AutoAttackOptions{ + // MainHand: prot.WeaponFromMainHand(0), // Set crit multiplier later when we have targets. + // AutoSwingMelee: true, + // }) - healingModel := options.HealingModel - if healingModel != nil { - if healingModel.InspirationUptime > 0.0 { - core.ApplyInspiration(prot.GetCharacter(), healingModel.InspirationUptime) - } - } + // healingModel := options.HealingModel + // if healingModel != nil { + // if healingModel.InspirationUptime > 0.0 { + // core.ApplyInspiration(prot.GetCharacter(), healingModel.InspirationUptime) + // } + // } return prot } @@ -69,11 +69,11 @@ func (prot *ProtectionPaladin) GetPaladin() *paladin.Paladin { func (prot *ProtectionPaladin) Initialize() { prot.Paladin.Initialize() - prot.ActivateRighteousFury() + // prot.ActivateRighteousFury() - if prot.Options.ClassOptions.UseAvengingWrath { - prot.RegisterAvengingWrathCD() - } + // if prot.Options.ClassOptions.UseAvengingWrath { + // prot.RegisterAvengingWrathCD() + // } } func (prot *ProtectionPaladin) Reset(sim *core.Simulation) { diff --git a/sim/paladin/retribution/retribution.go b/sim/paladin/retribution/retribution.go index 4f54c4a545..7bbcd11178 100644 --- a/sim/paladin/retribution/retribution.go +++ b/sim/paladin/retribution/retribution.go @@ -55,7 +55,7 @@ func (ret *RetributionPaladin) GetPaladin() *paladin.Paladin { func (ret *RetributionPaladin) Initialize() { ret.Paladin.Initialize() - ret.RegisterAvengingWrathCD() + //ret.RegisterAvengingWrathCD() } func (ret *RetributionPaladin) Reset(sim *core.Simulation) { diff --git a/sim/paladin/talents.go b/sim/paladin/talents.go index 27015e5b40..4790823cbb 100644 --- a/sim/paladin/talents.go +++ b/sim/paladin/talents.go @@ -1,13 +1,5 @@ package paladin -import ( - "time" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" -) - // TODO: // Sanctified Wrath (Damage penetration, questions over affected stats) @@ -16,670 +8,670 @@ func (paladin *Paladin) ToughnessArmorMultiplier() float64 { } func (paladin *Paladin) ApplyTalents() { - paladin.AddStat(stats.MeleeCrit, float64(paladin.Talents.Conviction)*core.CritRatingPerCritChance) - paladin.AddStat(stats.SpellCrit, float64(paladin.Talents.Conviction)*core.CritRatingPerCritChance) - paladin.AddStat(stats.MeleeCrit, float64(paladin.Talents.SanctityOfBattle)*core.CritRatingPerCritChance) - paladin.AddStat(stats.SpellCrit, float64(paladin.Talents.SanctityOfBattle)*core.CritRatingPerCritChance) - - paladin.PseudoStats.BaseParry += 0.01 * float64(paladin.Talents.Deflection) - paladin.PseudoStats.BaseDodge += 0.01 * float64(paladin.Talents.Anticipation) - - paladin.ApplyEquipScaling(stats.Armor, paladin.ToughnessArmorMultiplier()) - - if paladin.Talents.DivineStrength > 0 { - paladin.MultiplyStat(stats.Strength, 1.0+0.03*float64(paladin.Talents.DivineStrength)) - } - if paladin.Talents.DivineIntellect > 0 { - paladin.MultiplyStat(stats.Intellect, 1.0+0.02*float64(paladin.Talents.DivineIntellect)) - } - - if paladin.Talents.SheathOfLight > 0 { - // doesn't implement HOT - percentage := 0.10 * float64(paladin.Talents.SheathOfLight) - paladin.AddStatDependency(stats.AttackPower, stats.SpellPower, percentage) - } - - if paladin.Talents.TouchedByTheLight > 0 { - percentage := 0.20 * float64(paladin.Talents.TouchedByTheLight) - paladin.AddStatDependency(stats.Strength, stats.SpellPower, percentage) - } - - if paladin.Talents.SacredDuty > 0 { - paladin.MultiplyStat(stats.Stamina, 1.0+0.02*float64(paladin.Talents.SacredDuty)) - } - - if paladin.Talents.CombatExpertise > 0 { - paladin.AddStat(stats.Expertise, core.ExpertisePerQuarterPercentReduction*2*float64(paladin.Talents.CombatExpertise)) - paladin.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*2*float64(paladin.Talents.CombatExpertise)) - paladin.AddStat(stats.SpellCrit, core.CritRatingPerCritChance*2*float64(paladin.Talents.CombatExpertise)) - paladin.MultiplyStat(stats.Stamina, 1.0+0.02*float64(paladin.Talents.CombatExpertise)) - } - - if paladin.Talents.ShieldOfTheTemplar > 0 { - paladin.PseudoStats.DamageTakenMultiplier *= 1 - 0.01*float64(paladin.Talents.ShieldOfTheTemplar) - } - - paladin.applyRedoubt() - paladin.applyReckoning() - paladin.applyArdentDefender() - paladin.applyCrusade() - paladin.applyWeaponSpecialization() - paladin.applyVengeance() - paladin.applyHeartOfTheCrusader() - paladin.applyVindication() - paladin.applyArtOfWar() - paladin.applyJudgementsOfTheJust() - paladin.applyJudgementsOfTheWise() - paladin.applyRighteousVengeance() - paladin.applyMinorGlyphOfSenseUndead() - paladin.applyGuardedByTheLight() -} - -func (paladin *Paladin) getTalentSealsOfThePureBonus() float64 { - return 0.03 * float64(paladin.Talents.SealsOfThePure) -} - -func (paladin *Paladin) getTalentTwoHandedWeaponSpecializationBonus() float64 { - return 0.02 * float64(paladin.Talents.TwoHandedWeaponSpecialization) -} - -func (paladin *Paladin) getTalentSanctityOfBattleBonus() float64 { - return 0.05 * float64(paladin.Talents.SanctityOfBattle) -} - -func (paladin *Paladin) getTalentTheArtOfWarBonus() float64 { - return 0.05 * float64(paladin.Talents.TheArtOfWar) -} - -func (paladin *Paladin) getMajorGlyphSealOfRighteousnessBonus() float64 { - return core.TernaryFloat64(paladin.HasMajorGlyph(proto.PaladinMajorGlyph_GlyphOfSealOfRighteousness), .1, 0) -} - -func (paladin *Paladin) getMajorGlyphOfExorcismBonus() float64 { - return core.TernaryFloat64(paladin.HasMajorGlyph(proto.PaladinMajorGlyph_GlyphOfExorcism), 0.20, 0) -} - -func (paladin *Paladin) getMajorGlyphOfJudgementBonus() float64 { - return core.TernaryFloat64(paladin.HasMajorGlyph(proto.PaladinMajorGlyph_GlyphOfJudgement), 0.10, 0) -} - -func (paladin *Paladin) applyMinorGlyphOfSenseUndead() { - if !paladin.HasMinorGlyph(proto.PaladinMinorGlyph_GlyphOfSenseUndead) { - return - } - - var applied bool - - paladin.RegisterResetEffect( - func(s *core.Simulation) { - if !applied { - for i := int32(0); i < paladin.Env.GetNumTargets(); i++ { - unit := paladin.Env.GetTargetUnit(i) - if unit.MobType == proto.MobType_MobTypeUndead { - paladin.AttackTables[unit.UnitIndex].DamageDealtMultiplier *= 1.01 - } - } - applied = true - } - }, - ) -} + // paladin.AddStat(stats.MeleeCrit, float64(paladin.Talents.Conviction)*core.CritRatingPerCritChance) + // paladin.AddStat(stats.SpellCrit, float64(paladin.Talents.Conviction)*core.CritRatingPerCritChance) + // paladin.AddStat(stats.MeleeCrit, float64(paladin.Talents.SanctityOfBattle)*core.CritRatingPerCritChance) + // paladin.AddStat(stats.SpellCrit, float64(paladin.Talents.SanctityOfBattle)*core.CritRatingPerCritChance) -func (paladin *Paladin) applyRedoubt() { - if paladin.Talents.Redoubt == 0 { - return - } - - actionID := core.ActionID{SpellID: 20132} - - paladin.PseudoStats.BlockValueMultiplier += 0.10 * float64(paladin.Talents.Redoubt) - - bonusBlockRating := 10 * core.BlockRatingPerBlockChance * float64(paladin.Talents.Redoubt) - - procAura := paladin.RegisterAura(core.Aura{ - Label: "Redoubt Proc", - ActionID: actionID, - Duration: time.Second * 10, - MaxStacks: 5, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - paladin.AddStatDynamic(sim, stats.Block, bonusBlockRating) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - paladin.AddStatDynamic(sim, stats.Block, -bonusBlockRating) - }, - OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Outcome.Matches(core.OutcomeBlock) { - aura.RemoveStack(sim) - } - }, - }) - - paladin.RegisterAura(core.Aura{ - Label: "Redoubt", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() && spell.ProcMask.Matches(core.ProcMaskMeleeOrRanged) { - if sim.RandomFloat("Redoubt") < 0.1 { - procAura.Activate(sim) - procAura.SetStacks(sim, 5) - } - } - }, - }) -} + // paladin.PseudoStats.BaseParry += 0.01 * float64(paladin.Talents.Deflection) + // paladin.PseudoStats.BaseDodge += 0.01 * float64(paladin.Talents.Anticipation) -func (paladin *Paladin) applyReckoning() { - if paladin.Talents.Reckoning == 0 { - return - } - - actionID := core.ActionID{SpellID: 20182} - procChance := 0.02 * float64(paladin.Talents.Reckoning) - - var reckoningSpell *core.Spell - - procAura := paladin.RegisterAura(core.Aura{ - Label: "Reckoning Proc", - ActionID: actionID, - Duration: time.Second * 8, - MaxStacks: 4, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - config := *paladin.AutoAttacks.MHConfig() - config.ActionID = actionID - reckoningSpell = paladin.GetOrRegisterSpell(config) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == paladin.AutoAttacks.MHAuto() { - reckoningSpell.Cast(sim, result.Target) - } - }, - }) - - paladin.RegisterAura(core.Aura{ - Label: "Reckoning", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() && sim.RandomFloat("Reckoning") < procChance { - procAura.Activate(sim) - procAura.SetStacks(sim, 4) - } - }, - }) -} + // paladin.ApplyEquipScaling(stats.Armor, paladin.ToughnessArmorMultiplier()) -func (paladin *Paladin) applyArdentDefender() { - if paladin.Talents.ArdentDefender == 0 { - return - } - - var ardentDamageReduction float64 - switch paladin.Talents.ArdentDefender { - case 1: - ardentDamageReduction = 0.07 - case 2: - ardentDamageReduction = 0.13 - case 3: - ardentDamageReduction = 0.20 - } - - // 540 defense (+140) yields the full heal amount - ardentHealAmount := max(1.0, float64(paladin.GetStat(stats.Defense))/core.DefenseRatingPerDefense/140.0) * 0.10 * float64(paladin.Talents.ArdentDefender) - - // TBD? Buff to mark time spent fully below 35% and attribute absorbs - // rangeAura := paladin.RegisterAura(core.Aura{ - // Label: "Ardent Defender (Active)", - // ActionID: core.ActionID{SpellID: 31852}, - // Duration: core.NeverExpires, - // }) - - // paladin.RegisterAura(core.Aura{ - // Label: "Ardent Defender Talent", - // Duration: core.NeverExpires, - // OnReset: func(aura *core.Aura, sim *core.Simulation) { - // aura.Activate(sim) - // }, - // OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - // if aura.Unit.CurrentHealthPercent() < 0.35 { - // procAura.Activate(sim) + // if paladin.Talents.DivineStrength > 0 { + // paladin.MultiplyStat(stats.Strength, 1.0+0.03*float64(paladin.Talents.DivineStrength)) + // } + // if paladin.Talents.DivineIntellect > 0 { + // paladin.MultiplyStat(stats.Intellect, 1.0+0.02*float64(paladin.Talents.DivineIntellect)) // } - // }, - // }) - - // Debuff to show that AD has procced - procAura := paladin.RegisterAura(core.Aura{ - Label: "Ardent Defender", - ActionID: core.ActionID{SpellID: 66233}, - Duration: time.Second * 120.0, - }) - - // Spell to heal you when AD has procced; fire this before fatal damage so that a Death is not detected - procHeal := paladin.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 66233}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - CritMultiplier: 1, // Assuming this can't really crit? - ThreatMultiplier: 0.25, - DamageMultiplier: 1, - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - spell.CalcAndDealHealing(sim, &paladin.Unit, ardentHealAmount*paladin.MaxHealth(), spell.OutcomeHealingCrit) - }, - }) - - // >= 0.35, no effect - // < 0.35, pro-rated DR - // =< 0, proc death save - paladin.AddDynamicDamageTakenModifier(func(sim *core.Simulation, _ *core.Spell, result *core.SpellResult) { - incomingDamage := result.Damage - if (paladin.CurrentHealth()-incomingDamage)/paladin.MaxHealth() <= 0.35 { - //rangeAura.Activate(sim) - result.Damage -= (paladin.MaxHealth()*0.35 - (paladin.CurrentHealth() - incomingDamage)) * ardentDamageReduction - if sim.Log != nil { - paladin.Log(sim, "Ardent Defender reduced damage by %d", int32(incomingDamage-result.Damage)) - } - - incomingDamage2 := result.Damage - - // Now check death save, based on the reduced damage - if (result.Damage >= paladin.CurrentHealth()) && !procAura.IsActive() { - if paladin.CurrentHealth()+ardentHealAmount*paladin.MaxHealth() > paladin.MaxHealth() { - // We will overheal and wind up at the wrong HP value... Let's work around this - // TODO: Find a cleaner way to do this, using absorbs? - procHeal.Cast(sim, &paladin.Unit) - result.Damage = paladin.CurrentHealth() - ardentHealAmount*paladin.MaxHealth() - if sim.Log != nil { - paladin.Log(sim, "Ardent Defender proc reduced overkill damage by %d, compensating for overheal", int32(incomingDamage2-result.Damage)) - } - } else { - // Cleanest handling for < 70% HP, includes proper healing amount in metrics - result.Damage = paladin.CurrentHealth() - procHeal.Cast(sim, &paladin.Unit) - if sim.Log != nil { - paladin.Log(sim, "Ardent Defender proc reduced overkill damage by %d", int32(incomingDamage2-result.Damage)) - } - } - procAura.Activate(sim) - } - } - // TODO: Metrics, attribute reduced damage as absorption - }) -} - -// Because Crusade modifies unit specific attack tables, it must be applied at start of sim. -func (paladin *Paladin) applyCrusade() { - if paladin.Talents.Crusade == 0 { - return - } - - var applied bool - - paladin.RegisterResetEffect( - func(s *core.Simulation) { - if !applied { - for i := int32(0); i < paladin.Env.GetNumTargets(); i++ { - unit := paladin.Env.GetTargetUnit(i) - crusadeMod := 1.0 + (0.01 * float64(paladin.Talents.Crusade)) - switch unit.MobType { - case proto.MobType_MobTypeHumanoid, proto.MobType_MobTypeDemon, proto.MobType_MobTypeUndead, proto.MobType_MobTypeElemental: - paladin.AttackTables[unit.UnitIndex].DamageDealtMultiplier *= crusadeMod * crusadeMod - default: - paladin.AttackTables[unit.UnitIndex].DamageDealtMultiplier *= crusadeMod - } - } - applied = true - } - }, - ) -} - -// Prior to WOTLK, behavior was to double dip. -func (paladin *Paladin) MeleeCritMultiplier() float64 { - // return paladin.Character.MeleeCritMultiplier(paladin.crusadeMultiplier(), 0) - return paladin.DefaultMeleeCritMultiplier() -} -func (paladin *Paladin) SpellCritMultiplier() float64 { - // return paladin.Character.SpellCritMultiplier(paladin.crusadeMultiplier(), 0) - return paladin.DefaultSpellCritMultiplier() -} - -// Affects all physical damage or spells that can be rolled as physical -// It affects white, Windfury, Crusader Strike, Seals, and Judgement of Command / Blood -func (paladin *Paladin) applyWeaponSpecialization() { - // This impacts Crusader Strike, Melee Attacks, WF attacks - // Seals + Judgements need to be implemented separately - mhWeapon := paladin.GetMHWeapon() - - if mhWeapon == nil { - return - } - - switch mhWeapon.HandType { - case proto.HandType_HandTypeTwoHand: - paladin.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 + 0.02*float64(paladin.Talents.TwoHandedWeaponSpecialization) - case proto.HandType_HandTypeOneHand, proto.HandType_HandTypeMainHand: - if paladin.Talents.OneHandedWeaponSpecialization > 0 { - // Talent points are 4%, 7%, 10% - paladin.PseudoStats.DamageDealtMultiplier *= 1.01 + 0.03*float64(paladin.Talents.OneHandedWeaponSpecialization) - } - } -} - -func (paladin *Paladin) maybeProcVengeance(sim *core.Simulation, result *core.SpellResult) { - if result.DidCrit() && paladin.Talents.Vengeance > 0 { - paladin.VengeanceAura.Activate(sim) - paladin.VengeanceAura.AddStack(sim) - } -} - -// I don't know if the new stack of vengeance applies to the crit that triggered it or not -// Need to check this -func (paladin *Paladin) applyVengeance() { - if paladin.Talents.Vengeance == 0 { - return - } - - bonusPerStack := 0.01 * float64(paladin.Talents.Vengeance) - paladin.VengeanceAura = paladin.RegisterAura(core.Aura{ - Label: "Vengeance Proc", - ActionID: core.ActionID{SpellID: 20057}, - Duration: time.Second * 30, - MaxStacks: 3, - OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexHoly] /= 1 + (bonusPerStack * float64(oldStacks)) - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= 1 + (bonusPerStack * float64(oldStacks)) - - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexHoly] *= 1 + (bonusPerStack * float64(newStacks)) - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 + (bonusPerStack * float64(newStacks)) - }, - }) - - paladin.RegisterAura(core.Aura{ - Label: "Vengeance", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - paladin.maybeProcVengeance(sim, result) - }, - }) -} - -func (paladin *Paladin) applyHeartOfTheCrusader() { - if paladin.Talents.HeartOfTheCrusader == 0 { - return - } - - hotcAuras := paladin.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { - return core.HeartOfTheCrusaderDebuff(target, paladin.Talents.HeartOfTheCrusader) - }) - - paladin.RegisterAura(core.Aura{ - Label: "Heart of the Crusader", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.Flags.Matches(SpellFlagSecondaryJudgement) { - hotcAuras.Get(result.Target).Activate(sim) - } - }, - }) -} - -func (paladin *Paladin) applyVindication() { - if paladin.Talents.Vindication == 0 { - return - } - - vindicationAuras := paladin.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { - return core.VindicationAura(target, paladin.Talents.Vindication) - }) - paladin.RegisterAura(core.Aura{ - Label: "Vindication Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - // TODO: Replace with actual proc mask / proc chance - if result.Landed() && spell.ProcMask.Matches(core.ProcMaskMelee) { - vindicationAuras.Get(result.Target).Activate(sim) - } - }, - }) -} -func (paladin *Paladin) applyArtOfWar() { - if paladin.Talents.TheArtOfWar == 0 { - return - } - - castTimeReduction := 0.5 * float64(paladin.Talents.TheArtOfWar) - paladin.ArtOfWarInstantCast = paladin.RegisterAura(core.Aura{ - Label: "Art Of War", - ActionID: core.ActionID{SpellID: 53488}, - Duration: time.Second * 15, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - paladin.Exorcism.CastTimeMultiplier -= castTimeReduction - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - paladin.Exorcism.CastTimeMultiplier += castTimeReduction - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell == paladin.Exorcism { - aura.Deactivate(sim) - } - }, - }) - - paladin.RegisterAura(core.Aura{ - Label: "The Art of War", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.IsMelee() && !spell.Flags.Matches(SpellFlagSecondaryJudgement) { - return - } - - if spell == paladin.HammerOfWrath { - return - } - - if !result.Outcome.Matches(core.OutcomeCrit) { - return - } - - paladin.ArtOfWarInstantCast.Activate(sim) - }, - }) -} + // if paladin.Talents.SheathOfLight > 0 { + // // doesn't implement HOT + // percentage := 0.10 * float64(paladin.Talents.SheathOfLight) + // paladin.AddStatDependency(stats.AttackPower, stats.SpellPower, percentage) + // } -func (paladin *Paladin) applyJudgementsOfTheJust() { - if paladin.Talents.JudgementsOfTheJust == 0 { - return - } - - jojAuras := paladin.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { - return core.JudgementsOfTheJustAura(target, paladin.Talents.JudgementsOfTheJust) - }) - // This application can proc stuff - jojApplicationSpell := paladin.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 68055}, - ProcMask: core.ProcMaskProc, - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - jojAuras.Get(target).Activate(sim) - }, - }) - - paladin.RegisterAura(core.Aura{ - Label: "Judgements Of The Just Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() && spell.Flags.Matches(SpellFlagPrimaryJudgement) { - jojApplicationSpell.Cast(sim, result.Target) - } - }, - }) -} + // if paladin.Talents.TouchedByTheLight > 0 { + // percentage := 0.20 * float64(paladin.Talents.TouchedByTheLight) + // paladin.AddStatDependency(stats.Strength, stats.SpellPower, percentage) + // } -func (paladin *Paladin) applyJudgementsOfTheWise() { - if paladin.Talents.JudgementsOfTheWise == 0 { - return - } - - procChance := float64(paladin.Talents.JudgementsOfTheWise) / 3 - paladin.JowiseManaMetrics = paladin.NewManaMetrics(core.ActionID{SpellID: 31878}) - replSrc := paladin.Env.Raid.NewReplenishmentSource(core.ActionID{SpellID: 31878}) - - procSpell := paladin.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 31878}, - ApplyEffects: func(sim *core.Simulation, unit *core.Unit, _ *core.Spell) { - paladin.AddMana(sim, paladin.BaseMana*0.25, paladin.JowiseManaMetrics) - paladin.Env.Raid.ProcReplenishment(sim, replSrc) - }, - }) - - paladin.RegisterAura(core.Aura{ - Label: "Judgements of the Wise", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.Flags.Matches(SpellFlagSecondaryJudgement) || !result.Landed() { - return - } - - if procChance == 1 || sim.RandomFloat("judgements of the wise") < procChance { - procSpell.Cast(sim, nil) - } - }, - }) -} + // if paladin.Talents.SacredDuty > 0 { + // paladin.MultiplyStat(stats.Stamina, 1.0+0.02*float64(paladin.Talents.SacredDuty)) + // } -func (paladin *Paladin) applyRighteousVengeance() { - // Righteous Vengeance is a MAGIC debuff that pools 10/20/30% crit damage from Crusader Strike, Divine Storm, and Judgements. - // It drains the pool every 2 seconds at a rate of 1/4 of the pool size. - // And then deals that 1/4 as PHYSICAL damage. - if paladin.Talents.RighteousVengeance == 0 { - return - } - - dotActionID := core.ActionID{SpellID: 61840} // Righteous Vengeance - - rvDot := paladin.RegisterSpell(core.SpellConfig{ - ActionID: dotActionID.WithTag(2), - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskEmpty, - Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagMeleeMetrics | core.SpellFlagIgnoreModifiers, - - DamageMultiplier: 1, - CritMultiplier: paladin.MeleeCritMultiplier(), - ThreatMultiplier: 1, - - Dot: core.DotConfig{ - Aura: core.Aura{ - Label: "Righteous Vengeance", - }, - NumberOfTicks: 4, - TickLength: time.Second * 2, - - OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - if paladin.HasTuralyonsOrLiadrinsBattlegear2Pc { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.Spell.OutcomeMeleeSpecialCritOnly) - } else { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.Spell.OutcomeAlwaysHit) - } - }, - }, - }) - - rvSpell := paladin.RegisterSpell(core.SpellConfig{ - ActionID: dotActionID.WithTag(1), - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskProc, - Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagIgnoreModifiers, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - rvDot.Dot(target).ApplyOrReset(sim) - spell.CalcAndDealOutcome(sim, target, spell.OutcomeAlwaysHit) - }, - }) - - paladin.RegisterAura(core.Aura{ - Label: "Righteous Vengeance", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.DidCrit() { - return - } - if spell != paladin.CrusaderStrike && spell != paladin.DivineStorm && !spell.Flags.Matches(SpellFlagSecondaryJudgement) { - return - } - - dot := rvDot.Dot(result.Target) - - newDamage := result.Damage * (0.10 * float64(paladin.Talents.RighteousVengeance)) - outstandingDamage := core.TernaryFloat64(dot.IsActive(), dot.SnapshotBaseDamage*float64(dot.NumberOfTicks-dot.TickCount), 0) - - dot.SnapshotAttackerMultiplier = 1 - dot.SnapshotBaseDamage = (outstandingDamage + newDamage) / float64(dot.NumberOfTicks) - rvSpell.Cast(sim, result.Target) - }, - }) -} + // if paladin.Talents.CombatExpertise > 0 { + // paladin.AddStat(stats.Expertise, core.ExpertisePerQuarterPercentReduction*2*float64(paladin.Talents.CombatExpertise)) + // paladin.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*2*float64(paladin.Talents.CombatExpertise)) + // paladin.AddStat(stats.SpellCrit, core.CritRatingPerCritChance*2*float64(paladin.Talents.CombatExpertise)) + // paladin.MultiplyStat(stats.Stamina, 1.0+0.02*float64(paladin.Talents.CombatExpertise)) + // } -//nolint:unused -func (paladin *Paladin) applyFanaticism() { - // TODO: Possibly implement as aura. - if paladin.Talents.Fanaticism == 0 { - return - } + // if paladin.Talents.ShieldOfTheTemplar > 0 { + // paladin.PseudoStats.DamageTakenMultiplier *= 1 - 0.01*float64(paladin.Talents.ShieldOfTheTemplar) + // } - paladin.PseudoStats.ThreatMultiplier *= 1 - 0.10*float64(paladin.Talents.Fanaticism) + // paladin.applyRedoubt() + // paladin.applyReckoning() + // paladin.applyArdentDefender() + // paladin.applyCrusade() + // paladin.applyWeaponSpecialization() + // paladin.applyVengeance() + // paladin.applyHeartOfTheCrusader() + // paladin.applyVindication() + // paladin.applyArtOfWar() + // paladin.applyJudgementsOfTheJust() + // paladin.applyJudgementsOfTheWise() + // paladin.applyRighteousVengeance() + // paladin.applyMinorGlyphOfSenseUndead() + // paladin.applyGuardedByTheLight() } -func (paladin *Paladin) applyGuardedByTheLight() { - if paladin.Talents.GuardedByTheLight == 0 { - return - } - - paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexArcane] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) - paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexFire] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) - paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexFrost] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) - paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexHoly] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) - paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexNature] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) - paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexShadow] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) - - paladin.RegisterAura(core.Aura{ - Label: "Guarded By The Light", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() { - return - } - - if paladin.DivinePleaAura.IsActive() { - paladin.DivinePleaAura.Refresh(sim) - } - }, - }) -} +// func (paladin *Paladin) getTalentSealsOfThePureBonus() float64 { +// return 0.03 * float64(paladin.Talents.SealsOfThePure) +// } + +// func (paladin *Paladin) getTalentTwoHandedWeaponSpecializationBonus() float64 { +// return 0.02 * float64(paladin.Talents.TwoHandedWeaponSpecialization) +// } + +// func (paladin *Paladin) getTalentSanctityOfBattleBonus() float64 { +// return 0.05 * float64(paladin.Talents.SanctityOfBattle) +// } + +// func (paladin *Paladin) getTalentTheArtOfWarBonus() float64 { +// return 0.05 * float64(paladin.Talents.TheArtOfWar) +// } + +// func (paladin *Paladin) getMajorGlyphSealOfRighteousnessBonus() float64 { +// return core.TernaryFloat64(paladin.HasMajorGlyph(proto.PaladinMajorGlyph_GlyphOfSealOfRighteousness), .1, 0) +// } + +// func (paladin *Paladin) getMajorGlyphOfExorcismBonus() float64 { +// return core.TernaryFloat64(paladin.HasMajorGlyph(proto.PaladinMajorGlyph_GlyphOfExorcism), 0.20, 0) +// } + +// func (paladin *Paladin) getMajorGlyphOfJudgementBonus() float64 { +// return core.TernaryFloat64(paladin.HasMajorGlyph(proto.PaladinMajorGlyph_GlyphOfJudgement), 0.10, 0) +// } + +// func (paladin *Paladin) applyMinorGlyphOfSenseUndead() { +// if !paladin.HasMinorGlyph(proto.PaladinMinorGlyph_GlyphOfSenseUndead) { +// return +// } + +// var applied bool + +// paladin.RegisterResetEffect( +// func(s *core.Simulation) { +// if !applied { +// for i := int32(0); i < paladin.Env.GetNumTargets(); i++ { +// unit := paladin.Env.GetTargetUnit(i) +// if unit.MobType == proto.MobType_MobTypeUndead { +// paladin.AttackTables[unit.UnitIndex].DamageDealtMultiplier *= 1.01 +// } +// } +// applied = true +// } +// }, +// ) +// } + +// func (paladin *Paladin) applyRedoubt() { +// if paladin.Talents.Redoubt == 0 { +// return +// } + +// actionID := core.ActionID{SpellID: 20132} + +// paladin.PseudoStats.BlockValueMultiplier += 0.10 * float64(paladin.Talents.Redoubt) + +// bonusBlockRating := 10 * core.BlockRatingPerBlockChance * float64(paladin.Talents.Redoubt) + +// procAura := paladin.RegisterAura(core.Aura{ +// Label: "Redoubt Proc", +// ActionID: actionID, +// Duration: time.Second * 10, +// MaxStacks: 5, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// paladin.AddStatDynamic(sim, stats.Block, bonusBlockRating) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// paladin.AddStatDynamic(sim, stats.Block, -bonusBlockRating) +// }, +// OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Outcome.Matches(core.OutcomeBlock) { +// aura.RemoveStack(sim) +// } +// }, +// }) + +// paladin.RegisterAura(core.Aura{ +// Label: "Redoubt", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Landed() && spell.ProcMask.Matches(core.ProcMaskMeleeOrRanged) { +// if sim.RandomFloat("Redoubt") < 0.1 { +// procAura.Activate(sim) +// procAura.SetStacks(sim, 5) +// } +// } +// }, +// }) +// } + +// func (paladin *Paladin) applyReckoning() { +// if paladin.Talents.Reckoning == 0 { +// return +// } + +// actionID := core.ActionID{SpellID: 20182} +// procChance := 0.02 * float64(paladin.Talents.Reckoning) + +// var reckoningSpell *core.Spell + +// procAura := paladin.RegisterAura(core.Aura{ +// Label: "Reckoning Proc", +// ActionID: actionID, +// Duration: time.Second * 8, +// MaxStacks: 4, +// OnInit: func(aura *core.Aura, sim *core.Simulation) { +// config := *paladin.AutoAttacks.MHConfig() +// config.ActionID = actionID +// reckoningSpell = paladin.GetOrRegisterSpell(config) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == paladin.AutoAttacks.MHAuto() { +// reckoningSpell.Cast(sim, result.Target) +// } +// }, +// }) + +// paladin.RegisterAura(core.Aura{ +// Label: "Reckoning", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Landed() && sim.RandomFloat("Reckoning") < procChance { +// procAura.Activate(sim) +// procAura.SetStacks(sim, 4) +// } +// }, +// }) +// } + +// func (paladin *Paladin) applyArdentDefender() { +// if paladin.Talents.ArdentDefender == 0 { +// return +// } + +// var ardentDamageReduction float64 +// switch paladin.Talents.ArdentDefender { +// case 1: +// ardentDamageReduction = 0.07 +// case 2: +// ardentDamageReduction = 0.13 +// case 3: +// ardentDamageReduction = 0.20 +// } + +// // 540 defense (+140) yields the full heal amount +// ardentHealAmount := max(1.0, float64(paladin.GetStat(stats.Defense))/core.DefenseRatingPerDefense/140.0) * 0.10 * float64(paladin.Talents.ArdentDefender) + +// // TBD? Buff to mark time spent fully below 35% and attribute absorbs +// // rangeAura := paladin.RegisterAura(core.Aura{ +// // Label: "Ardent Defender (Active)", +// // ActionID: core.ActionID{SpellID: 31852}, +// // Duration: core.NeverExpires, +// // }) + +// // paladin.RegisterAura(core.Aura{ +// // Label: "Ardent Defender Talent", +// // Duration: core.NeverExpires, +// // OnReset: func(aura *core.Aura, sim *core.Simulation) { +// // aura.Activate(sim) +// // }, +// // OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// // if aura.Unit.CurrentHealthPercent() < 0.35 { +// // procAura.Activate(sim) +// // } +// // }, +// // }) + +// // Debuff to show that AD has procced +// procAura := paladin.RegisterAura(core.Aura{ +// Label: "Ardent Defender", +// ActionID: core.ActionID{SpellID: 66233}, +// Duration: time.Second * 120.0, +// }) + +// // Spell to heal you when AD has procced; fire this before fatal damage so that a Death is not detected +// procHeal := paladin.RegisterSpell(core.SpellConfig{ +// ActionID: core.ActionID{SpellID: 66233}, +// SpellSchool: core.SpellSchoolHoly, +// ProcMask: core.ProcMaskSpellHealing, +// CritMultiplier: 1, // Assuming this can't really crit? +// ThreatMultiplier: 0.25, +// DamageMultiplier: 1, +// ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { +// spell.CalcAndDealHealing(sim, &paladin.Unit, ardentHealAmount*paladin.MaxHealth(), spell.OutcomeHealingCrit) +// }, +// }) + +// // >= 0.35, no effect +// // < 0.35, pro-rated DR +// // =< 0, proc death save +// paladin.AddDynamicDamageTakenModifier(func(sim *core.Simulation, _ *core.Spell, result *core.SpellResult) { +// incomingDamage := result.Damage +// if (paladin.CurrentHealth()-incomingDamage)/paladin.MaxHealth() <= 0.35 { +// //rangeAura.Activate(sim) +// result.Damage -= (paladin.MaxHealth()*0.35 - (paladin.CurrentHealth() - incomingDamage)) * ardentDamageReduction +// if sim.Log != nil { +// paladin.Log(sim, "Ardent Defender reduced damage by %d", int32(incomingDamage-result.Damage)) +// } + +// incomingDamage2 := result.Damage + +// // Now check death save, based on the reduced damage +// if (result.Damage >= paladin.CurrentHealth()) && !procAura.IsActive() { +// if paladin.CurrentHealth()+ardentHealAmount*paladin.MaxHealth() > paladin.MaxHealth() { +// // We will overheal and wind up at the wrong HP value... Let's work around this +// // TODO: Find a cleaner way to do this, using absorbs? +// procHeal.Cast(sim, &paladin.Unit) +// result.Damage = paladin.CurrentHealth() - ardentHealAmount*paladin.MaxHealth() +// if sim.Log != nil { +// paladin.Log(sim, "Ardent Defender proc reduced overkill damage by %d, compensating for overheal", int32(incomingDamage2-result.Damage)) +// } +// } else { +// // Cleanest handling for < 70% HP, includes proper healing amount in metrics +// result.Damage = paladin.CurrentHealth() +// procHeal.Cast(sim, &paladin.Unit) +// if sim.Log != nil { +// paladin.Log(sim, "Ardent Defender proc reduced overkill damage by %d", int32(incomingDamage2-result.Damage)) +// } +// } +// procAura.Activate(sim) +// } +// } +// // TODO: Metrics, attribute reduced damage as absorption +// }) +// } + +// // Because Crusade modifies unit specific attack tables, it must be applied at start of sim. +// func (paladin *Paladin) applyCrusade() { +// if paladin.Talents.Crusade == 0 { +// return +// } + +// var applied bool + +// paladin.RegisterResetEffect( +// func(s *core.Simulation) { +// if !applied { +// for i := int32(0); i < paladin.Env.GetNumTargets(); i++ { +// unit := paladin.Env.GetTargetUnit(i) +// crusadeMod := 1.0 + (0.01 * float64(paladin.Talents.Crusade)) +// switch unit.MobType { +// case proto.MobType_MobTypeHumanoid, proto.MobType_MobTypeDemon, proto.MobType_MobTypeUndead, proto.MobType_MobTypeElemental: +// paladin.AttackTables[unit.UnitIndex].DamageDealtMultiplier *= crusadeMod * crusadeMod +// default: +// paladin.AttackTables[unit.UnitIndex].DamageDealtMultiplier *= crusadeMod +// } +// } +// applied = true +// } +// }, +// ) +// } + +// // Prior to WOTLK, behavior was to double dip. +// func (paladin *Paladin) MeleeCritMultiplier() float64 { +// // return paladin.Character.MeleeCritMultiplier(paladin.crusadeMultiplier(), 0) +// return paladin.DefaultMeleeCritMultiplier() +// } +// func (paladin *Paladin) SpellCritMultiplier() float64 { +// // return paladin.Character.SpellCritMultiplier(paladin.crusadeMultiplier(), 0) +// return paladin.DefaultSpellCritMultiplier() +// } + +// // Affects all physical damage or spells that can be rolled as physical +// // It affects white, Windfury, Crusader Strike, Seals, and Judgement of Command / Blood +// func (paladin *Paladin) applyWeaponSpecialization() { +// // This impacts Crusader Strike, Melee Attacks, WF attacks +// // Seals + Judgements need to be implemented separately +// mhWeapon := paladin.GetMHWeapon() + +// if mhWeapon == nil { +// return +// } + +// switch mhWeapon.HandType { +// case proto.HandType_HandTypeTwoHand: +// paladin.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 + 0.02*float64(paladin.Talents.TwoHandedWeaponSpecialization) +// case proto.HandType_HandTypeOneHand, proto.HandType_HandTypeMainHand: +// if paladin.Talents.OneHandedWeaponSpecialization > 0 { +// // Talent points are 4%, 7%, 10% +// paladin.PseudoStats.DamageDealtMultiplier *= 1.01 + 0.03*float64(paladin.Talents.OneHandedWeaponSpecialization) +// } +// } +// } + +// func (paladin *Paladin) maybeProcVengeance(sim *core.Simulation, result *core.SpellResult) { +// if result.DidCrit() && paladin.Talents.Vengeance > 0 { +// paladin.VengeanceAura.Activate(sim) +// paladin.VengeanceAura.AddStack(sim) +// } +// } + +// // I don't know if the new stack of vengeance applies to the crit that triggered it or not +// // Need to check this +// func (paladin *Paladin) applyVengeance() { +// if paladin.Talents.Vengeance == 0 { +// return +// } + +// bonusPerStack := 0.01 * float64(paladin.Talents.Vengeance) +// paladin.VengeanceAura = paladin.RegisterAura(core.Aura{ +// Label: "Vengeance Proc", +// ActionID: core.ActionID{SpellID: 20057}, +// Duration: time.Second * 30, +// MaxStacks: 3, +// OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexHoly] /= 1 + (bonusPerStack * float64(oldStacks)) +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= 1 + (bonusPerStack * float64(oldStacks)) + +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexHoly] *= 1 + (bonusPerStack * float64(newStacks)) +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 + (bonusPerStack * float64(newStacks)) +// }, +// }) + +// paladin.RegisterAura(core.Aura{ +// Label: "Vengeance", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// paladin.maybeProcVengeance(sim, result) +// }, +// }) +// } + +// func (paladin *Paladin) applyHeartOfTheCrusader() { +// if paladin.Talents.HeartOfTheCrusader == 0 { +// return +// } + +// hotcAuras := paladin.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { +// return core.HeartOfTheCrusaderDebuff(target, paladin.Talents.HeartOfTheCrusader) +// }) + +// paladin.RegisterAura(core.Aura{ +// Label: "Heart of the Crusader", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell.Flags.Matches(SpellFlagSecondaryJudgement) { +// hotcAuras.Get(result.Target).Activate(sim) +// } +// }, +// }) +// } + +// func (paladin *Paladin) applyVindication() { +// if paladin.Talents.Vindication == 0 { +// return +// } + +// vindicationAuras := paladin.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { +// return core.VindicationAura(target, paladin.Talents.Vindication) +// }) +// paladin.RegisterAura(core.Aura{ +// Label: "Vindication Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// // TODO: Replace with actual proc mask / proc chance +// if result.Landed() && spell.ProcMask.Matches(core.ProcMaskMelee) { +// vindicationAuras.Get(result.Target).Activate(sim) +// } +// }, +// }) +// } + +// func (paladin *Paladin) applyArtOfWar() { +// if paladin.Talents.TheArtOfWar == 0 { +// return +// } + +// castTimeReduction := 0.5 * float64(paladin.Talents.TheArtOfWar) +// paladin.ArtOfWarInstantCast = paladin.RegisterAura(core.Aura{ +// Label: "Art Of War", +// ActionID: core.ActionID{SpellID: 53488}, +// Duration: time.Second * 15, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// paladin.Exorcism.CastTimeMultiplier -= castTimeReduction +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// paladin.Exorcism.CastTimeMultiplier += castTimeReduction +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if spell == paladin.Exorcism { +// aura.Deactivate(sim) +// } +// }, +// }) + +// paladin.RegisterAura(core.Aura{ +// Label: "The Art of War", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.IsMelee() && !spell.Flags.Matches(SpellFlagSecondaryJudgement) { +// return +// } + +// if spell == paladin.HammerOfWrath { +// return +// } + +// if !result.Outcome.Matches(core.OutcomeCrit) { +// return +// } + +// paladin.ArtOfWarInstantCast.Activate(sim) +// }, +// }) +// } + +// func (paladin *Paladin) applyJudgementsOfTheJust() { +// if paladin.Talents.JudgementsOfTheJust == 0 { +// return +// } + +// jojAuras := paladin.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { +// return core.JudgementsOfTheJustAura(target, paladin.Talents.JudgementsOfTheJust) +// }) +// // This application can proc stuff +// jojApplicationSpell := paladin.RegisterSpell(core.SpellConfig{ +// ActionID: core.ActionID{SpellID: 68055}, +// ProcMask: core.ProcMaskProc, +// ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { +// jojAuras.Get(target).Activate(sim) +// }, +// }) + +// paladin.RegisterAura(core.Aura{ +// Label: "Judgements Of The Just Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Landed() && spell.Flags.Matches(SpellFlagPrimaryJudgement) { +// jojApplicationSpell.Cast(sim, result.Target) +// } +// }, +// }) +// } + +// func (paladin *Paladin) applyJudgementsOfTheWise() { +// if paladin.Talents.JudgementsOfTheWise == 0 { +// return +// } + +// procChance := float64(paladin.Talents.JudgementsOfTheWise) / 3 +// paladin.JowiseManaMetrics = paladin.NewManaMetrics(core.ActionID{SpellID: 31878}) +// replSrc := paladin.Env.Raid.NewReplenishmentSource(core.ActionID{SpellID: 31878}) + +// procSpell := paladin.RegisterSpell(core.SpellConfig{ +// ActionID: core.ActionID{SpellID: 31878}, +// ApplyEffects: func(sim *core.Simulation, unit *core.Unit, _ *core.Spell) { +// paladin.AddMana(sim, paladin.BaseMana*0.25, paladin.JowiseManaMetrics) +// paladin.Env.Raid.ProcReplenishment(sim, replSrc) +// }, +// }) + +// paladin.RegisterAura(core.Aura{ +// Label: "Judgements of the Wise", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.Flags.Matches(SpellFlagSecondaryJudgement) || !result.Landed() { +// return +// } + +// if procChance == 1 || sim.RandomFloat("judgements of the wise") < procChance { +// procSpell.Cast(sim, nil) +// } +// }, +// }) +// } + +// func (paladin *Paladin) applyRighteousVengeance() { +// // Righteous Vengeance is a MAGIC debuff that pools 10/20/30% crit damage from Crusader Strike, Divine Storm, and Judgements. +// // It drains the pool every 2 seconds at a rate of 1/4 of the pool size. +// // And then deals that 1/4 as PHYSICAL damage. +// if paladin.Talents.RighteousVengeance == 0 { +// return +// } + +// dotActionID := core.ActionID{SpellID: 61840} // Righteous Vengeance + +// rvDot := paladin.RegisterSpell(core.SpellConfig{ +// ActionID: dotActionID.WithTag(2), +// SpellSchool: core.SpellSchoolHoly, +// ProcMask: core.ProcMaskEmpty, +// Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagMeleeMetrics | core.SpellFlagIgnoreModifiers, + +// DamageMultiplier: 1, +// CritMultiplier: paladin.MeleeCritMultiplier(), +// ThreatMultiplier: 1, + +// Dot: core.DotConfig{ +// Aura: core.Aura{ +// Label: "Righteous Vengeance", +// }, +// NumberOfTicks: 4, +// TickLength: time.Second * 2, + +// OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { +// if paladin.HasTuralyonsOrLiadrinsBattlegear2Pc { +// dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.Spell.OutcomeMeleeSpecialCritOnly) +// } else { +// dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.Spell.OutcomeAlwaysHit) +// } +// }, +// }, +// }) + +// rvSpell := paladin.RegisterSpell(core.SpellConfig{ +// ActionID: dotActionID.WithTag(1), +// SpellSchool: core.SpellSchoolHoly, +// ProcMask: core.ProcMaskProc, +// Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagIgnoreModifiers, + +// ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { +// rvDot.Dot(target).ApplyOrReset(sim) +// spell.CalcAndDealOutcome(sim, target, spell.OutcomeAlwaysHit) +// }, +// }) + +// paladin.RegisterAura(core.Aura{ +// Label: "Righteous Vengeance", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.DidCrit() { +// return +// } +// if spell != paladin.CrusaderStrike && spell != paladin.DivineStorm && !spell.Flags.Matches(SpellFlagSecondaryJudgement) { +// return +// } + +// dot := rvDot.Dot(result.Target) + +// newDamage := result.Damage * (0.10 * float64(paladin.Talents.RighteousVengeance)) +// outstandingDamage := core.TernaryFloat64(dot.IsActive(), dot.SnapshotBaseDamage*float64(dot.NumberOfTicks-dot.TickCount), 0) + +// dot.SnapshotAttackerMultiplier = 1 +// dot.SnapshotBaseDamage = (outstandingDamage + newDamage) / float64(dot.NumberOfTicks) +// rvSpell.Cast(sim, result.Target) +// }, +// }) +// } + +// //nolint:unused +// func (paladin *Paladin) applyFanaticism() { +// // TODO: Possibly implement as aura. +// if paladin.Talents.Fanaticism == 0 { +// return +// } + +// paladin.PseudoStats.ThreatMultiplier *= 1 - 0.10*float64(paladin.Talents.Fanaticism) +// } + +// func (paladin *Paladin) applyGuardedByTheLight() { +// if paladin.Talents.GuardedByTheLight == 0 { +// return +// } + +// paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexArcane] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) +// paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexFire] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) +// paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexFrost] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) +// paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexHoly] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) +// paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexNature] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) +// paladin.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexShadow] *= 1 - 0.03*float64(paladin.Talents.GuardedByTheLight) + +// paladin.RegisterAura(core.Aura{ +// Label: "Guarded By The Light", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() { +// return +// } + +// if paladin.DivinePleaAura.IsActive() { +// paladin.DivinePleaAura.Refresh(sim) +// } +// }, +// }) +// } diff --git a/sim/priest/binding_heal.go b/sim/priest/_binding_heal.go similarity index 100% rename from sim/priest/binding_heal.go rename to sim/priest/_binding_heal.go diff --git a/sim/priest/circle_of_healing.go b/sim/priest/_circle_of_healing.go similarity index 100% rename from sim/priest/circle_of_healing.go rename to sim/priest/_circle_of_healing.go diff --git a/sim/priest/devouring_plague.go b/sim/priest/_devouring_plague.go similarity index 100% rename from sim/priest/devouring_plague.go rename to sim/priest/_devouring_plague.go diff --git a/sim/priest/dispersion.go b/sim/priest/_dispersion.go similarity index 100% rename from sim/priest/dispersion.go rename to sim/priest/_dispersion.go diff --git a/sim/priest/flash_heal.go b/sim/priest/_flash_heal.go similarity index 100% rename from sim/priest/flash_heal.go rename to sim/priest/_flash_heal.go diff --git a/sim/priest/greater_heal.go b/sim/priest/_greater_heal.go similarity index 100% rename from sim/priest/greater_heal.go rename to sim/priest/_greater_heal.go diff --git a/sim/priest/holy_fire.go b/sim/priest/_holy_fire.go similarity index 100% rename from sim/priest/holy_fire.go rename to sim/priest/_holy_fire.go diff --git a/sim/priest/hymn_of_hope.go b/sim/priest/_hymn_of_hope.go similarity index 100% rename from sim/priest/hymn_of_hope.go rename to sim/priest/_hymn_of_hope.go diff --git a/sim/priest/items.go b/sim/priest/_items.go similarity index 100% rename from sim/priest/items.go rename to sim/priest/_items.go diff --git a/sim/priest/mind_blast.go b/sim/priest/_mind_blast.go similarity index 100% rename from sim/priest/mind_blast.go rename to sim/priest/_mind_blast.go diff --git a/sim/priest/mind_flay.go b/sim/priest/_mind_flay.go similarity index 100% rename from sim/priest/mind_flay.go rename to sim/priest/_mind_flay.go diff --git a/sim/priest/mind_sear.go b/sim/priest/_mind_sear.go similarity index 100% rename from sim/priest/mind_sear.go rename to sim/priest/_mind_sear.go diff --git a/sim/priest/penance.go b/sim/priest/_penance.go similarity index 100% rename from sim/priest/penance.go rename to sim/priest/_penance.go diff --git a/sim/priest/power_infusion.go b/sim/priest/_power_infusion.go similarity index 100% rename from sim/priest/power_infusion.go rename to sim/priest/_power_infusion.go diff --git a/sim/priest/power_word_shield.go b/sim/priest/_power_word_shield.go similarity index 100% rename from sim/priest/power_word_shield.go rename to sim/priest/_power_word_shield.go diff --git a/sim/priest/prayer_of_healing.go b/sim/priest/_prayer_of_healing.go similarity index 100% rename from sim/priest/prayer_of_healing.go rename to sim/priest/_prayer_of_healing.go diff --git a/sim/priest/prayer_of_mending.go b/sim/priest/_prayer_of_mending.go similarity index 100% rename from sim/priest/prayer_of_mending.go rename to sim/priest/_prayer_of_mending.go diff --git a/sim/priest/renew.go b/sim/priest/_renew.go similarity index 100% rename from sim/priest/renew.go rename to sim/priest/_renew.go diff --git a/sim/priest/set_bonuses.go b/sim/priest/_set_bonuses.go similarity index 100% rename from sim/priest/set_bonuses.go rename to sim/priest/_set_bonuses.go diff --git a/sim/priest/shadow_word_death.go b/sim/priest/_shadow_word_death.go similarity index 100% rename from sim/priest/shadow_word_death.go rename to sim/priest/_shadow_word_death.go diff --git a/sim/priest/shadow_word_pain.go b/sim/priest/_shadow_word_pain.go similarity index 100% rename from sim/priest/shadow_word_pain.go rename to sim/priest/_shadow_word_pain.go diff --git a/sim/priest/shadowfiend.go b/sim/priest/_shadowfiend.go similarity index 100% rename from sim/priest/shadowfiend.go rename to sim/priest/_shadowfiend.go diff --git a/sim/priest/shadowfiend_pet.go b/sim/priest/_shadowfiend_pet.go similarity index 100% rename from sim/priest/shadowfiend_pet.go rename to sim/priest/_shadowfiend_pet.go diff --git a/sim/priest/smite.go b/sim/priest/_smite.go similarity index 100% rename from sim/priest/smite.go rename to sim/priest/_smite.go diff --git a/sim/priest/vampiric_touch.go b/sim/priest/_vampiric_touch.go similarity index 100% rename from sim/priest/vampiric_touch.go rename to sim/priest/_vampiric_touch.go diff --git a/sim/priest/discipline/discipline.go b/sim/priest/discipline/discipline.go index edf5af41e4..acb66a7ab9 100644 --- a/sim/priest/discipline/discipline.go +++ b/sim/priest/discipline/discipline.go @@ -67,12 +67,12 @@ func (discPriest *DisciplinePriest) GetMainTarget() *core.Unit { func (discPriest *DisciplinePriest) Initialize() { discPriest.CurrentTarget = discPriest.GetMainTarget() discPriest.Priest.Initialize() - discPriest.Priest.RegisterHealingSpells() + // discPriest.Priest.RegisterHealingSpells() - // discPriest.ApplyRapture(discPriest.Options.RapturesPerMinute) - discPriest.RegisterHymnOfHopeCD() + // // discPriest.ApplyRapture(discPriest.Options.RapturesPerMinute) + // discPriest.RegisterHymnOfHopeCD() } func (discPriest *DisciplinePriest) Reset(sim *core.Simulation) { - discPriest.Priest.Reset(sim) + //discPriest.Priest.Reset(sim) } diff --git a/sim/priest/holy/holy.go b/sim/priest/holy/holy.go index ac654dbf14..3ee868065f 100644 --- a/sim/priest/holy/holy.go +++ b/sim/priest/holy/holy.go @@ -55,12 +55,12 @@ func (holyPriest *HolyPriest) GetPriest() *priest.Priest { func (holyPriest *HolyPriest) Initialize() { holyPriest.Priest.Initialize() - holyPriest.RegisterHolyFireSpell() - holyPriest.RegisterSmiteSpell() - holyPriest.RegisterPenanceSpell() - holyPriest.RegisterHymnOfHopeCD() + // holyPriest.RegisterHolyFireSpell() + // holyPriest.RegisterSmiteSpell() + // holyPriest.RegisterPenanceSpell() + // holyPriest.RegisterHymnOfHopeCD() } func (holyPriest *HolyPriest) Reset(sim *core.Simulation) { - holyPriest.Priest.Reset(sim) + //holyPriest.Priest.Reset(sim) } diff --git a/sim/priest/priest.go b/sim/priest/priest.go index fb241e1f9a..77e94ce72b 100644 --- a/sim/priest/priest.go +++ b/sim/priest/priest.go @@ -1,11 +1,8 @@ package priest import ( - "time" - "github.com/wowsims/cata/sim/core" "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" ) var TalentTreeSizes = [3]int{28, 27, 27} @@ -19,8 +16,8 @@ type Priest struct { Latency float64 - ShadowfiendAura *core.Aura - ShadowfiendPet *Shadowfiend + //ShadowfiendAura *core.Aura + //ShadowfiendPet *Shadowfiend // cached cast stuff // TODO: aoe multi-target situations will need multiple spells ticking for each target. @@ -96,91 +93,91 @@ func (priest *Priest) GetCharacter() *core.Character { return &priest.Character } -func (priest *Priest) HasMajorGlyph(glyph proto.PriestMajorGlyph) bool { - return priest.HasGlyph(int32(glyph)) -} -func (priest *Priest) HasMinorGlyph(glyph proto.PriestMinorGlyph) bool { - return priest.HasGlyph(int32(glyph)) -} +// func (priest *Priest) HasMajorGlyph(glyph proto.PriestMajorGlyph) bool { +// return priest.HasGlyph(int32(glyph)) +// } +// func (priest *Priest) HasMinorGlyph(glyph proto.PriestMinorGlyph) bool { +// return priest.HasGlyph(int32(glyph)) +// } -func (priest *Priest) AddRaidBuffs(raidBuffs *proto.RaidBuffs) { - raidBuffs.ShadowProtection = true - raidBuffs.DivineSpirit = true +// func (priest *Priest) AddRaidBuffs(raidBuffs *proto.RaidBuffs) { +// raidBuffs.ShadowProtection = true +// raidBuffs.DivineSpirit = true - raidBuffs.PowerWordFortitude = max(raidBuffs.PowerWordFortitude, core.MakeTristateValue( - true, - priest.Talents.ImprovedPowerWordFortitude == 2)) -} +// raidBuffs.PowerWordFortitude = max(raidBuffs.PowerWordFortitude, core.MakeTristateValue( +// true, +// priest.Talents.ImprovedPowerWordFortitude == 2)) +// } func (priest *Priest) AddPartyBuffs(_ *proto.PartyBuffs) { } func (priest *Priest) Initialize() { - statDep := priest.NewDynamicStatDependency(stats.Spirit, stats.SpellPower, 0.3) - priest.ShadowyInsightAura = priest.GetOrRegisterAura(core.Aura{ - Label: "Shadowy Insight", - Duration: time.Second * 10, - ActionID: core.ActionID{SpellID: 61792}, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - priest.EnableDynamicStatDep(sim, statDep) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - priest.DisableDynamicStatDep(sim, statDep) - }, - }) - - priest.registerSetBonuses() - priest.registerDevouringPlagueSpell() - priest.registerShadowWordPainSpell() - priest.registerMindBlastSpell() - priest.registerShadowWordDeathSpell() - priest.registerShadowfiendSpell() - priest.registerVampiricTouchSpell() - priest.registerDispersionSpell() - - priest.registerPowerInfusionCD() - - priest.MindFlayAPL = priest.newMindFlaySpell(0) - priest.MindSearAPL = priest.newMindSearSpell(0) - - priest.MindFlay = []*core.Spell{ - nil, // So we can use # of ticks as the index - priest.newMindFlaySpell(1), - priest.newMindFlaySpell(2), - priest.newMindFlaySpell(3), - } - priest.MindSear = []*core.Spell{ - nil, // So we can use # of ticks as the index - priest.newMindSearSpell(1), - priest.newMindSearSpell(2), - priest.newMindSearSpell(3), - priest.newMindSearSpell(4), - priest.newMindSearSpell(5), - } + // statDep := priest.NewDynamicStatDependency(stats.Spirit, stats.SpellPower, 0.3) + // priest.ShadowyInsightAura = priest.GetOrRegisterAura(core.Aura{ + // Label: "Shadowy Insight", + // Duration: time.Second * 10, + // ActionID: core.ActionID{SpellID: 61792}, + // OnGain: func(aura *core.Aura, sim *core.Simulation) { + // priest.EnableDynamicStatDep(sim, statDep) + // }, + // OnExpire: func(aura *core.Aura, sim *core.Simulation) { + // priest.DisableDynamicStatDep(sim, statDep) + // }, + // }) + + // priest.registerSetBonuses() + // priest.registerDevouringPlagueSpell() + // priest.registerShadowWordPainSpell() + // priest.registerMindBlastSpell() + // priest.registerShadowWordDeathSpell() + // priest.registerShadowfiendSpell() + // priest.registerVampiricTouchSpell() + // priest.registerDispersionSpell() + + // priest.registerPowerInfusionCD() + + // priest.MindFlayAPL = priest.newMindFlaySpell(0) + // priest.MindSearAPL = priest.newMindSearSpell(0) + + // priest.MindFlay = []*core.Spell{ + // nil, // So we can use # of ticks as the index + // priest.newMindFlaySpell(1), + // priest.newMindFlaySpell(2), + // priest.newMindFlaySpell(3), + // } + // priest.MindSear = []*core.Spell{ + // nil, // So we can use # of ticks as the index + // priest.newMindSearSpell(1), + // priest.newMindSearSpell(2), + // priest.newMindSearSpell(3), + // priest.newMindSearSpell(4), + // priest.newMindSearSpell(5), + // } } -func (priest *Priest) RegisterHealingSpells() { - priest.registerPenanceHealSpell() - priest.registerBindingHealSpell() - priest.registerCircleOfHealingSpell() - priest.registerFlashHealSpell() - priest.registerGreaterHealSpell() - priest.registerPowerWordShieldSpell() - priest.registerPrayerOfHealingSpell() - priest.registerPrayerOfMendingSpell() - priest.registerRenewSpell() -} - -func (priest *Priest) AddShadowWeavingStack(sim *core.Simulation) { - if priest.ShadowWeavingAura != nil { - priest.ShadowWeavingAura.Activate(sim) - priest.ShadowWeavingAura.AddStack(sim) - } -} +// func (priest *Priest) RegisterHealingSpells() { +// priest.registerPenanceHealSpell() +// priest.registerBindingHealSpell() +// priest.registerCircleOfHealingSpell() +// priest.registerFlashHealSpell() +// priest.registerGreaterHealSpell() +// priest.registerPowerWordShieldSpell() +// priest.registerPrayerOfHealingSpell() +// priest.registerPrayerOfMendingSpell() +// priest.registerRenewSpell() +// } + +// func (priest *Priest) AddShadowWeavingStack(sim *core.Simulation) { +// if priest.ShadowWeavingAura != nil { +// priest.ShadowWeavingAura.Activate(sim) +// priest.ShadowWeavingAura.AddStack(sim) +// } +// } func (priest *Priest) Reset(_ *core.Simulation) { - priest.MindFlayModifier = 1 - priest.MindBlastModifier = 1 +// priest.MindFlayModifier = 1 +// priest.MindBlastModifier = 1 } func New(char *core.Character, selfBuffs SelfBuffs, talents string) *Priest { @@ -189,21 +186,21 @@ func New(char *core.Character, selfBuffs SelfBuffs, talents string) *Priest { SelfBuffs: selfBuffs, Talents: &proto.PriestTalents{}, } - core.FillTalentsProto(priest.Talents.ProtoReflect(), talents, TalentTreeSizes) + // core.FillTalentsProto(priest.Talents.ProtoReflect(), talents, TalentTreeSizes) - priest.EnableManaBar() - priest.ShadowfiendPet = priest.NewShadowfiend() + // priest.EnableManaBar() + // //priest.ShadowfiendPet = priest.NewShadowfiend() - if selfBuffs.UseInnerFire { - multi := 1 + float64(priest.Talents.ImprovedInnerFire)*0.15 - sp := 120.0 * multi - armor := 2440 * multi * core.TernaryFloat64(priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfInnerFire), 1.5, 1) - priest.AddStat(stats.SpellPower, sp) - priest.AddStat(stats.Armor, armor) - } + // if selfBuffs.UseInnerFire { + // multi := 1 + float64(priest.Talents.ImprovedInnerFire)*0.15 + // sp := 120.0 * multi + // armor := 2440 * multi * core.TernaryFloat64(priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfInnerFire), 1.5, 1) + // priest.AddStat(stats.SpellPower, sp) + // priest.AddStat(stats.Armor, armor) + // } - return priest -} + return priest + } // Agent is a generic way to access underlying priest on any of the agents. type PriestAgent interface { diff --git a/sim/priest/talents.go b/sim/priest/talents.go index dbe71d942b..fccb98a665 100644 --- a/sim/priest/talents.go +++ b/sim/priest/talents.go @@ -1,13 +1,5 @@ package priest -import ( - "strconv" - "time" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/stats" -) - func (priest *Priest) ApplyTalents() { // TODO: // Reflective Shield @@ -18,491 +10,491 @@ func (priest *Priest) ApplyTalents() { // Test of Faith // Guardian Spirit - priest.applyDivineAegis() - priest.applyGrace() - priest.applyBorrowedTime() - priest.applyInspiration() - priest.applyHolyConcentration() - priest.applySerendipity() - priest.applySurgeOfLight() - priest.applyMisery() - priest.applyShadowWeaving() - priest.applyImprovedSpiritTap() - priest.registerInnerFocus() - - priest.AddStat(stats.SpellCrit, 1*float64(priest.Talents.FocusedWill)*core.CritRatingPerCritChance) - priest.PseudoStats.SpiritRegenRateCasting = []float64{0.0, 0.17, 0.33, 0.5}[priest.Talents.Meditation] - priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexArcane] *= 1 - .02*float64(priest.Talents.SpellWarding) - priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexHoly] *= 1 - .02*float64(priest.Talents.SpellWarding) - priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexFire] *= 1 - .02*float64(priest.Talents.SpellWarding) - priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexFrost] *= 1 - .02*float64(priest.Talents.SpellWarding) - priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexNature] *= 1 - .02*float64(priest.Talents.SpellWarding) - priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexShadow] *= 1 - .02*float64(priest.Talents.SpellWarding) - - if priest.Talents.Shadowform { - priest.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= 1.15 - } - - if priest.Talents.SpiritualGuidance > 0 { - priest.AddStatDependency(stats.Spirit, stats.SpellPower, 0.05*float64(priest.Talents.SpiritualGuidance)) - } - - if priest.Talents.MentalStrength > 0 { - priest.MultiplyStat(stats.Intellect, 1.0+0.03*float64(priest.Talents.MentalStrength)) - } - - if priest.Talents.ImprovedPowerWordFortitude > 0 { - priest.MultiplyStat(stats.Stamina, 1.0+.02*float64(priest.Talents.ImprovedPowerWordFortitude)) - } - - if priest.Talents.Enlightenment > 0 { - priest.MultiplyStat(stats.Spirit, 1+.02*float64(priest.Talents.Enlightenment)) - priest.PseudoStats.CastSpeedMultiplier *= 1 + .02*float64(priest.Talents.Enlightenment) - } - - if priest.Talents.FocusedPower > 0 { - priest.PseudoStats.DamageDealtMultiplier *= 1 + .02*float64(priest.Talents.FocusedPower) - } - - if priest.Talents.SpiritOfRedemption { - priest.MultiplyStat(stats.Spirit, 1.05) - } - - if priest.Talents.TwistedFaith > 0 { - priest.AddStatDependency(stats.Spirit, stats.SpellPower, 0.04*float64(priest.Talents.TwistedFaith)) - } -} - -func (priest *Priest) applyDivineAegis() { - if priest.Talents.DivineAegis == 0 { - return - } - - divineAegis := priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 47515}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagHelpful, - - DamageMultiplier: 1 * - (0.1 * float64(priest.Talents.DivineAegis)) * - core.TernaryFloat64(priest.HasSetBonus(ItemSetZabrasRaiment, 4), 1.1, 1), - ThreatMultiplier: 1, - - Shield: core.ShieldConfig{ - Aura: core.Aura{ - Label: "Divine Aegis", - Duration: time.Second * 12, - }, - }, - }) - - priest.RegisterAura(core.Aura{ - Label: "Divine Aegis Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnHealDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Outcome.Matches(core.OutcomeCrit) { - divineAegis.Shield(result.Target).Apply(sim, result.Damage) - } - }, - }) + // priest.applyDivineAegis() + // priest.applyGrace() + // priest.applyBorrowedTime() + // priest.applyInspiration() + // priest.applyHolyConcentration() + // priest.applySerendipity() + // priest.applySurgeOfLight() + // priest.applyMisery() + // priest.applyShadowWeaving() + // priest.applyImprovedSpiritTap() + // priest.registerInnerFocus() + + // priest.AddStat(stats.SpellCrit, 1*float64(priest.Talents.FocusedWill)*core.CritRatingPerCritChance) + // priest.PseudoStats.SpiritRegenRateCasting = []float64{0.0, 0.17, 0.33, 0.5}[priest.Talents.Meditation] + // priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexArcane] *= 1 - .02*float64(priest.Talents.SpellWarding) + // priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexHoly] *= 1 - .02*float64(priest.Talents.SpellWarding) + // priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexFire] *= 1 - .02*float64(priest.Talents.SpellWarding) + // priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexFrost] *= 1 - .02*float64(priest.Talents.SpellWarding) + // priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexNature] *= 1 - .02*float64(priest.Talents.SpellWarding) + // priest.PseudoStats.SchoolDamageTakenMultiplier[stats.SchoolIndexShadow] *= 1 - .02*float64(priest.Talents.SpellWarding) + + // if priest.Talents.Shadowform { + // priest.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= 1.15 + // } + + // if priest.Talents.SpiritualGuidance > 0 { + // priest.AddStatDependency(stats.Spirit, stats.SpellPower, 0.05*float64(priest.Talents.SpiritualGuidance)) + // } + + // if priest.Talents.MentalStrength > 0 { + // priest.MultiplyStat(stats.Intellect, 1.0+0.03*float64(priest.Talents.MentalStrength)) + // } + + // if priest.Talents.ImprovedPowerWordFortitude > 0 { + // priest.MultiplyStat(stats.Stamina, 1.0+.02*float64(priest.Talents.ImprovedPowerWordFortitude)) + // } + + // if priest.Talents.Enlightenment > 0 { + // priest.MultiplyStat(stats.Spirit, 1+.02*float64(priest.Talents.Enlightenment)) + // priest.PseudoStats.CastSpeedMultiplier *= 1 + .02*float64(priest.Talents.Enlightenment) + // } + + // if priest.Talents.FocusedPower > 0 { + // priest.PseudoStats.DamageDealtMultiplier *= 1 + .02*float64(priest.Talents.FocusedPower) + // } + + // if priest.Talents.SpiritOfRedemption { + // priest.MultiplyStat(stats.Spirit, 1.05) + // } + + // if priest.Talents.TwistedFaith > 0 { + // priest.AddStatDependency(stats.Spirit, stats.SpellPower, 0.04*float64(priest.Talents.TwistedFaith)) + // } } -func (priest *Priest) applyGrace() { - if priest.Talents.Grace == 0 { - return - } - - procChance := .5 * float64(priest.Talents.Grace) - - auras := make([]*core.Aura, len(priest.Env.AllUnits)) - for _, unit := range priest.Env.AllUnits { - if !priest.IsOpponent(unit) { - aura := unit.RegisterAura(core.Aura{ - Label: "Grace" + strconv.Itoa(int(priest.Index)), - ActionID: core.ActionID{SpellID: 47517}, - Duration: time.Second * 15, - MaxStacks: 3, - OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) { - priest.AttackTables[aura.Unit.UnitIndex].HealingDealtMultiplier /= 1 + .03*float64(oldStacks) - priest.AttackTables[aura.Unit.UnitIndex].HealingDealtMultiplier *= 1 + .03*float64(newStacks) - }, - }) - auras[unit.UnitIndex] = aura - } - } - - priest.RegisterAura(core.Aura{ - Label: "Grace Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnHealDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == priest.FlashHeal || spell == priest.GreaterHeal || spell == priest.PenanceHeal { - if sim.Proc(procChance, "Grace") { - aura := auras[result.Target.UnitIndex] - aura.Activate(sim) - aura.AddStack(sim) - } - } - }, - }) -} - -// This one is called from healing priest sim initialization because it needs an input. -func (priest *Priest) ApplyRapture(ppm float64) { - if priest.Talents.Rapture == 0 { - return - } - - if ppm <= 0 { - return - } - - raptureManaCoeff := []float64{0, .015, .020, .025}[priest.Talents.Rapture] - raptureMetrics := priest.NewManaMetrics(core.ActionID{SpellID: 47537}) - - priest.RegisterResetEffect(func(sim *core.Simulation) { - core.StartPeriodicAction(sim, core.PeriodicActionOptions{ - Period: time.Minute / time.Duration(ppm), - OnAction: func(sim *core.Simulation) { - priest.AddMana(sim, raptureManaCoeff*priest.MaxMana(), raptureMetrics) - }, - }) - }) -} - -func (priest *Priest) applyBorrowedTime() { - if priest.Talents.BorrowedTime == 0 { - return - } - - multiplier := 1 + .05*float64(priest.Talents.BorrowedTime) - - procAura := priest.RegisterAura(core.Aura{ - Label: "Borrowed Time", - ActionID: core.ActionID{SpellID: 52800}, - Duration: time.Second * 6, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - priest.MultiplyCastSpeed(multiplier) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - priest.MultiplyCastSpeed(1 / multiplier) - }, - }) - - priest.RegisterAura(core.Aura{ - Label: "Borrwed Time Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell == priest.PowerWordShield { - procAura.Activate(sim) - } else if spell.CurCast.CastTime > 0 { - procAura.Deactivate(sim) - } - }, - }) -} - -func (priest *Priest) applyInspiration() { - if priest.Talents.Inspiration == 0 { - return - } - - auras := make([]*core.Aura, len(priest.Env.AllUnits)) - for _, unit := range priest.Env.AllUnits { - if !priest.IsOpponent(unit) { - aura := core.InspirationAura(unit, priest.Talents.Inspiration) - auras[unit.UnitIndex] = aura - } - } - - priest.RegisterAura(core.Aura{ - Label: "Inspiration Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnHealDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == priest.FlashHeal || - spell == priest.GreaterHeal || - spell == priest.BindingHeal || - spell == priest.PrayerOfMending || - spell == priest.PrayerOfHealing || - spell == priest.CircleOfHealing || - spell == priest.PenanceHeal { - auras[result.Target.UnitIndex].Activate(sim) - } - }, - }) -} - -func (priest *Priest) applyHolyConcentration() { - if priest.Talents.HolyConcentration == 0 { - return - } - - multiplier := 1 + []float64{0, .16, .32, .50}[priest.Talents.HolyConcentration] - - procAura := priest.RegisterAura(core.Aura{ - Label: "Holy Concentration", - ActionID: core.ActionID{SpellID: 34860}, - Duration: time.Second * 8, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - priest.PseudoStats.SpiritRegenMultiplier *= multiplier - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - priest.PseudoStats.SpiritRegenMultiplier /= multiplier - }, - }) - - priest.RegisterAura(core.Aura{ - Label: "Holy Concentration Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnHealDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.DidCrit() && - (spell == priest.FlashHeal || spell == priest.GreaterHeal || spell == priest.EmpoweredRenew) { - procAura.Activate(sim) - } - }, - }) -} - -func (priest *Priest) applySerendipity() { - if priest.Talents.Serendipity == 0 { - return - } - - reductionPerStack := .04 * float64(priest.Talents.Serendipity) - - procAura := priest.RegisterAura(core.Aura{ - Label: "Serendipity", - ActionID: core.ActionID{SpellID: 63737}, - Duration: time.Second * 20, - MaxStacks: 3, - OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) { - priest.PrayerOfHealing.CastTimeMultiplier += reductionPerStack * float64(oldStacks) - priest.PrayerOfHealing.CastTimeMultiplier -= reductionPerStack * float64(newStacks) - priest.GreaterHeal.CastTimeMultiplier += reductionPerStack * float64(oldStacks) - priest.GreaterHeal.CastTimeMultiplier -= reductionPerStack * float64(newStacks) - }, - }) - - priest.RegisterAura(core.Aura{ - Label: "Serendipity Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell == priest.FlashHeal || spell == priest.BindingHeal { - procAura.Activate(sim) - procAura.AddStack(sim) - } else if spell == priest.GreaterHeal || spell == priest.PrayerOfHealing { - procAura.Deactivate(sim) - } - }, - }) -} - -func (priest *Priest) applySurgeOfLight() { - if priest.Talents.SurgeOfLight == 0 { - return - } - - procHandler := func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == priest.Smite || spell == priest.FlashHeal { - aura.Deactivate(sim) - } - } - - priest.SurgeOfLightProcAura = priest.RegisterAura(core.Aura{ - Label: "Surge of Light Proc", - ActionID: core.ActionID{SpellID: 33154}, - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - if priest.Smite != nil { - priest.Smite.CastTimeMultiplier -= 1 - priest.Smite.CostMultiplier -= 1 - priest.Smite.BonusCritRating -= 100 * core.CritRatingPerCritChance - } - if priest.FlashHeal != nil { - priest.FlashHeal.CastTimeMultiplier -= 1 - priest.FlashHeal.CostMultiplier -= 1 - priest.FlashHeal.BonusCritRating -= 100 * core.CritRatingPerCritChance - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - if priest.Smite != nil { - priest.Smite.CastTimeMultiplier += 1 - priest.Smite.CostMultiplier += 1 - priest.Smite.BonusCritRating += 100 * core.CritRatingPerCritChance - } - if priest.FlashHeal != nil { - priest.FlashHeal.CastTimeMultiplier += 1 - priest.FlashHeal.CostMultiplier += 1 - priest.FlashHeal.BonusCritRating += 100 * core.CritRatingPerCritChance - } - }, - OnSpellHitDealt: procHandler, - OnHealDealt: procHandler, - }) - - procChance := 0.25 * float64(priest.Talents.SurgeOfLight) - icd := core.Cooldown{ - Timer: priest.NewTimer(), - Duration: time.Second * 6, - } - priest.SurgeOfLightProcAura.Icd = &icd - - handler := func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if icd.IsReady(sim) && result.Outcome.Matches(core.OutcomeCrit) && sim.RandomFloat("SurgeOfLight") < procChance { - icd.Use(sim) - priest.SurgeOfLightProcAura.Activate(sim) - } - } - - priest.RegisterAura(core.Aura{ - Label: "Surge of Light", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: handler, - OnHealDealt: handler, - }) -} - -func (priest *Priest) applyMisery() { - if priest.Talents.Misery == 0 { - return - } - - miseryAuras := priest.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { - return core.MiseryAura(target, priest.Talents.Misery) - }) - priest.Env.RegisterPreFinalizeEffect(func() { - priest.ShadowWordPain.RelatedAuras = append(priest.ShadowWordPain.RelatedAuras, miseryAuras) - if priest.VampiricTouch != nil { - priest.VampiricTouch.RelatedAuras = append(priest.VampiricTouch.RelatedAuras, miseryAuras) - } - if priest.MindFlay[1] != nil { - priest.MindFlayAPL.RelatedAuras = append(priest.MindFlayAPL.RelatedAuras, miseryAuras) - priest.MindFlay[1].RelatedAuras = append(priest.MindFlay[1].RelatedAuras, miseryAuras) - priest.MindFlay[2].RelatedAuras = append(priest.MindFlay[2].RelatedAuras, miseryAuras) - priest.MindFlay[3].RelatedAuras = append(priest.MindFlay[3].RelatedAuras, miseryAuras) - } - }) - - priest.RegisterAura(core.Aura{ - Label: "Priest Shadow Effects", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() { - return - } - - if spell == priest.ShadowWordPain || spell == priest.VampiricTouch || spell.ActionID.SpellID == priest.MindFlay[1].ActionID.SpellID { - miseryAuras.Get(result.Target).Activate(sim) - } - }, - }) -} - -func (priest *Priest) applyShadowWeaving() { - if priest.Talents.ShadowWeaving == 0 { - return - } - - priest.ShadowWeavingAura = priest.GetOrRegisterAura(core.Aura{ - Label: "Shadow Weaving", - ActionID: core.ActionID{SpellID: 15258}, - Duration: time.Second * 15, - MaxStacks: 5, - OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] /= 1.0 + 0.02*float64(oldStacks) - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= 1.0 + 0.02*float64(newStacks) - }, - }) -} - -func (priest *Priest) applyImprovedSpiritTap() { - if priest.Talents.ImprovedSpiritTap == 0 { - return - } - - increase := 1 + 0.05*float64(priest.Talents.ImprovedSpiritTap) - statDep := priest.NewDynamicMultiplyStat(stats.Spirit, increase) - regen := []float64{0, 0.17, 0.33}[priest.Talents.ImprovedSpiritTap] - - priest.ImprovedSpiritTap = priest.GetOrRegisterAura(core.Aura{ - Label: "Improved Spirit Tap", - ActionID: core.ActionID{SpellID: 59000}, - Duration: time.Second * 8, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - priest.EnableDynamicStatDep(sim, statDep) - priest.PseudoStats.SpiritRegenRateCasting += regen - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - priest.DisableDynamicStatDep(sim, statDep) - priest.PseudoStats.SpiritRegenRateCasting -= regen - }, - }) -} - -func (priest *Priest) registerInnerFocus() { - if !priest.Talents.InnerFocus { - return - } - - actionID := core.ActionID{SpellID: 14751} - - priest.InnerFocusAura = priest.RegisterAura(core.Aura{ - Label: "Inner Focus", - ActionID: actionID, - Duration: core.NeverExpires, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.AddStatDynamic(sim, stats.SpellCrit, 25*core.CritRatingPerCritChance) - aura.Unit.PseudoStats.CostMultiplier -= 1 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.AddStatDynamic(sim, stats.SpellCrit, -25*core.CritRatingPerCritChance) - aura.Unit.PseudoStats.CostMultiplier += 1 - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - // Remove the buff and put skill on CD - aura.Deactivate(sim) - priest.InnerFocus.CD.Use(sim) - priest.UpdateMajorCooldowns() - }, - }) - - priest.InnerFocus = priest.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagAPL, - - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: priest.NewTimer(), - Duration: time.Duration(float64(time.Minute*3) * (1 - .1*float64(priest.Talents.Aspiration))), - }, - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - priest.InnerFocusAura.Activate(sim) - }, - }) -} +// func (priest *Priest) applyDivineAegis() { +// if priest.Talents.DivineAegis == 0 { +// return +// } + +// divineAegis := priest.RegisterSpell(core.SpellConfig{ +// ActionID: core.ActionID{SpellID: 47515}, +// SpellSchool: core.SpellSchoolHoly, +// ProcMask: core.ProcMaskSpellHealing, +// Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagHelpful, + +// DamageMultiplier: 1 * +// (0.1 * float64(priest.Talents.DivineAegis)) * +// core.TernaryFloat64(priest.HasSetBonus(ItemSetZabrasRaiment, 4), 1.1, 1), +// ThreatMultiplier: 1, + +// Shield: core.ShieldConfig{ +// Aura: core.Aura{ +// Label: "Divine Aegis", +// Duration: time.Second * 12, +// }, +// }, +// }) + +// priest.RegisterAura(core.Aura{ +// Label: "Divine Aegis Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnHealDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Outcome.Matches(core.OutcomeCrit) { +// divineAegis.Shield(result.Target).Apply(sim, result.Damage) +// } +// }, +// }) +// } + +// func (priest *Priest) applyGrace() { +// if priest.Talents.Grace == 0 { +// return +// } + +// procChance := .5 * float64(priest.Talents.Grace) + +// auras := make([]*core.Aura, len(priest.Env.AllUnits)) +// for _, unit := range priest.Env.AllUnits { +// if !priest.IsOpponent(unit) { +// aura := unit.RegisterAura(core.Aura{ +// Label: "Grace" + strconv.Itoa(int(priest.Index)), +// ActionID: core.ActionID{SpellID: 47517}, +// Duration: time.Second * 15, +// MaxStacks: 3, +// OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) { +// priest.AttackTables[aura.Unit.UnitIndex].HealingDealtMultiplier /= 1 + .03*float64(oldStacks) +// priest.AttackTables[aura.Unit.UnitIndex].HealingDealtMultiplier *= 1 + .03*float64(newStacks) +// }, +// }) +// auras[unit.UnitIndex] = aura +// } +// } + +// priest.RegisterAura(core.Aura{ +// Label: "Grace Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnHealDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == priest.FlashHeal || spell == priest.GreaterHeal || spell == priest.PenanceHeal { +// if sim.Proc(procChance, "Grace") { +// aura := auras[result.Target.UnitIndex] +// aura.Activate(sim) +// aura.AddStack(sim) +// } +// } +// }, +// }) +// } + +// // This one is called from healing priest sim initialization because it needs an input. +// func (priest *Priest) ApplyRapture(ppm float64) { +// if priest.Talents.Rapture == 0 { +// return +// } + +// if ppm <= 0 { +// return +// } + +// raptureManaCoeff := []float64{0, .015, .020, .025}[priest.Talents.Rapture] +// raptureMetrics := priest.NewManaMetrics(core.ActionID{SpellID: 47537}) + +// priest.RegisterResetEffect(func(sim *core.Simulation) { +// core.StartPeriodicAction(sim, core.PeriodicActionOptions{ +// Period: time.Minute / time.Duration(ppm), +// OnAction: func(sim *core.Simulation) { +// priest.AddMana(sim, raptureManaCoeff*priest.MaxMana(), raptureMetrics) +// }, +// }) +// }) +// } + +// func (priest *Priest) applyBorrowedTime() { +// if priest.Talents.BorrowedTime == 0 { +// return +// } + +// multiplier := 1 + .05*float64(priest.Talents.BorrowedTime) + +// procAura := priest.RegisterAura(core.Aura{ +// Label: "Borrowed Time", +// ActionID: core.ActionID{SpellID: 52800}, +// Duration: time.Second * 6, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// priest.MultiplyCastSpeed(multiplier) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// priest.MultiplyCastSpeed(1 / multiplier) +// }, +// }) + +// priest.RegisterAura(core.Aura{ +// Label: "Borrwed Time Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if spell == priest.PowerWordShield { +// procAura.Activate(sim) +// } else if spell.CurCast.CastTime > 0 { +// procAura.Deactivate(sim) +// } +// }, +// }) +// } + +// func (priest *Priest) applyInspiration() { +// if priest.Talents.Inspiration == 0 { +// return +// } + +// auras := make([]*core.Aura, len(priest.Env.AllUnits)) +// for _, unit := range priest.Env.AllUnits { +// if !priest.IsOpponent(unit) { +// aura := core.InspirationAura(unit, priest.Talents.Inspiration) +// auras[unit.UnitIndex] = aura +// } +// } + +// priest.RegisterAura(core.Aura{ +// Label: "Inspiration Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnHealDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == priest.FlashHeal || +// spell == priest.GreaterHeal || +// spell == priest.BindingHeal || +// spell == priest.PrayerOfMending || +// spell == priest.PrayerOfHealing || +// spell == priest.CircleOfHealing || +// spell == priest.PenanceHeal { +// auras[result.Target.UnitIndex].Activate(sim) +// } +// }, +// }) +// } + +// func (priest *Priest) applyHolyConcentration() { +// if priest.Talents.HolyConcentration == 0 { +// return +// } + +// multiplier := 1 + []float64{0, .16, .32, .50}[priest.Talents.HolyConcentration] + +// procAura := priest.RegisterAura(core.Aura{ +// Label: "Holy Concentration", +// ActionID: core.ActionID{SpellID: 34860}, +// Duration: time.Second * 8, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// priest.PseudoStats.SpiritRegenMultiplier *= multiplier +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// priest.PseudoStats.SpiritRegenMultiplier /= multiplier +// }, +// }) + +// priest.RegisterAura(core.Aura{ +// Label: "Holy Concentration Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnHealDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.DidCrit() && +// (spell == priest.FlashHeal || spell == priest.GreaterHeal || spell == priest.EmpoweredRenew) { +// procAura.Activate(sim) +// } +// }, +// }) +// } + +// func (priest *Priest) applySerendipity() { +// if priest.Talents.Serendipity == 0 { +// return +// } + +// reductionPerStack := .04 * float64(priest.Talents.Serendipity) + +// procAura := priest.RegisterAura(core.Aura{ +// Label: "Serendipity", +// ActionID: core.ActionID{SpellID: 63737}, +// Duration: time.Second * 20, +// MaxStacks: 3, +// OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) { +// priest.PrayerOfHealing.CastTimeMultiplier += reductionPerStack * float64(oldStacks) +// priest.PrayerOfHealing.CastTimeMultiplier -= reductionPerStack * float64(newStacks) +// priest.GreaterHeal.CastTimeMultiplier += reductionPerStack * float64(oldStacks) +// priest.GreaterHeal.CastTimeMultiplier -= reductionPerStack * float64(newStacks) +// }, +// }) + +// priest.RegisterAura(core.Aura{ +// Label: "Serendipity Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if spell == priest.FlashHeal || spell == priest.BindingHeal { +// procAura.Activate(sim) +// procAura.AddStack(sim) +// } else if spell == priest.GreaterHeal || spell == priest.PrayerOfHealing { +// procAura.Deactivate(sim) +// } +// }, +// }) +// } + +// func (priest *Priest) applySurgeOfLight() { +// if priest.Talents.SurgeOfLight == 0 { +// return +// } + +// procHandler := func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == priest.Smite || spell == priest.FlashHeal { +// aura.Deactivate(sim) +// } +// } + +// priest.SurgeOfLightProcAura = priest.RegisterAura(core.Aura{ +// Label: "Surge of Light Proc", +// ActionID: core.ActionID{SpellID: 33154}, +// Duration: time.Second * 10, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// if priest.Smite != nil { +// priest.Smite.CastTimeMultiplier -= 1 +// priest.Smite.CostMultiplier -= 1 +// priest.Smite.BonusCritRating -= 100 * core.CritRatingPerCritChance +// } +// if priest.FlashHeal != nil { +// priest.FlashHeal.CastTimeMultiplier -= 1 +// priest.FlashHeal.CostMultiplier -= 1 +// priest.FlashHeal.BonusCritRating -= 100 * core.CritRatingPerCritChance +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// if priest.Smite != nil { +// priest.Smite.CastTimeMultiplier += 1 +// priest.Smite.CostMultiplier += 1 +// priest.Smite.BonusCritRating += 100 * core.CritRatingPerCritChance +// } +// if priest.FlashHeal != nil { +// priest.FlashHeal.CastTimeMultiplier += 1 +// priest.FlashHeal.CostMultiplier += 1 +// priest.FlashHeal.BonusCritRating += 100 * core.CritRatingPerCritChance +// } +// }, +// OnSpellHitDealt: procHandler, +// OnHealDealt: procHandler, +// }) + +// procChance := 0.25 * float64(priest.Talents.SurgeOfLight) +// icd := core.Cooldown{ +// Timer: priest.NewTimer(), +// Duration: time.Second * 6, +// } +// priest.SurgeOfLightProcAura.Icd = &icd + +// handler := func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if icd.IsReady(sim) && result.Outcome.Matches(core.OutcomeCrit) && sim.RandomFloat("SurgeOfLight") < procChance { +// icd.Use(sim) +// priest.SurgeOfLightProcAura.Activate(sim) +// } +// } + +// priest.RegisterAura(core.Aura{ +// Label: "Surge of Light", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: handler, +// OnHealDealt: handler, +// }) +// } + +// func (priest *Priest) applyMisery() { +// if priest.Talents.Misery == 0 { +// return +// } + +// miseryAuras := priest.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { +// return core.MiseryAura(target, priest.Talents.Misery) +// }) +// priest.Env.RegisterPreFinalizeEffect(func() { +// priest.ShadowWordPain.RelatedAuras = append(priest.ShadowWordPain.RelatedAuras, miseryAuras) +// if priest.VampiricTouch != nil { +// priest.VampiricTouch.RelatedAuras = append(priest.VampiricTouch.RelatedAuras, miseryAuras) +// } +// if priest.MindFlay[1] != nil { +// priest.MindFlayAPL.RelatedAuras = append(priest.MindFlayAPL.RelatedAuras, miseryAuras) +// priest.MindFlay[1].RelatedAuras = append(priest.MindFlay[1].RelatedAuras, miseryAuras) +// priest.MindFlay[2].RelatedAuras = append(priest.MindFlay[2].RelatedAuras, miseryAuras) +// priest.MindFlay[3].RelatedAuras = append(priest.MindFlay[3].RelatedAuras, miseryAuras) +// } +// }) + +// priest.RegisterAura(core.Aura{ +// Label: "Priest Shadow Effects", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() { +// return +// } + +// if spell == priest.ShadowWordPain || spell == priest.VampiricTouch || spell.ActionID.SpellID == priest.MindFlay[1].ActionID.SpellID { +// miseryAuras.Get(result.Target).Activate(sim) +// } +// }, +// }) +// } + +// func (priest *Priest) applyShadowWeaving() { +// if priest.Talents.ShadowWeaving == 0 { +// return +// } + +// priest.ShadowWeavingAura = priest.GetOrRegisterAura(core.Aura{ +// Label: "Shadow Weaving", +// ActionID: core.ActionID{SpellID: 15258}, +// Duration: time.Second * 15, +// MaxStacks: 5, +// OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] /= 1.0 + 0.02*float64(oldStacks) +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= 1.0 + 0.02*float64(newStacks) +// }, +// }) +// } + +// func (priest *Priest) applyImprovedSpiritTap() { +// if priest.Talents.ImprovedSpiritTap == 0 { +// return +// } + +// increase := 1 + 0.05*float64(priest.Talents.ImprovedSpiritTap) +// statDep := priest.NewDynamicMultiplyStat(stats.Spirit, increase) +// regen := []float64{0, 0.17, 0.33}[priest.Talents.ImprovedSpiritTap] + +// priest.ImprovedSpiritTap = priest.GetOrRegisterAura(core.Aura{ +// Label: "Improved Spirit Tap", +// ActionID: core.ActionID{SpellID: 59000}, +// Duration: time.Second * 8, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// priest.EnableDynamicStatDep(sim, statDep) +// priest.PseudoStats.SpiritRegenRateCasting += regen +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// priest.DisableDynamicStatDep(sim, statDep) +// priest.PseudoStats.SpiritRegenRateCasting -= regen +// }, +// }) +// } + +// func (priest *Priest) registerInnerFocus() { +// if !priest.Talents.InnerFocus { +// return +// } + +// actionID := core.ActionID{SpellID: 14751} + +// priest.InnerFocusAura = priest.RegisterAura(core.Aura{ +// Label: "Inner Focus", +// ActionID: actionID, +// Duration: core.NeverExpires, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.AddStatDynamic(sim, stats.SpellCrit, 25*core.CritRatingPerCritChance) +// aura.Unit.PseudoStats.CostMultiplier -= 1 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.AddStatDynamic(sim, stats.SpellCrit, -25*core.CritRatingPerCritChance) +// aura.Unit.PseudoStats.CostMultiplier += 1 +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// // Remove the buff and put skill on CD +// aura.Deactivate(sim) +// priest.InnerFocus.CD.Use(sim) +// priest.UpdateMajorCooldowns() +// }, +// }) + +// priest.InnerFocus = priest.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagAPL, + +// Cast: core.CastConfig{ +// CD: core.Cooldown{ +// Timer: priest.NewTimer(), +// Duration: time.Duration(float64(time.Minute*3) * (1 - .1*float64(priest.Talents.Aspiration))), +// }, +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// priest.InnerFocusAura.Activate(sim) +// }, +// }) +// } diff --git a/sim/register_all.go b/sim/register_all.go index 91cd8adb9f..b1e81cd9c1 100644 --- a/sim/register_all.go +++ b/sim/register_all.go @@ -6,7 +6,10 @@ import ( frostDeathKnight "github.com/wowsims/cata/sim/death_knight/frost" "github.com/wowsims/cata/sim/death_knight/unholy" "github.com/wowsims/cata/sim/druid/balance" - "github.com/wowsims/cata/sim/druid/feral" + + // Todo: Feral has too tight rotation + // Needs work even without presets etc + //"github.com/wowsims/cata/sim/druid/feral" restoDruid "github.com/wowsims/cata/sim/druid/restoration" _ "github.com/wowsims/cata/sim/encounters" "github.com/wowsims/cata/sim/hunter/beast_mastery" @@ -48,7 +51,7 @@ func RegisterAll() { unholy.RegisterUnholyDeathKnight() balance.RegisterBalanceDruid() - feral.RegisterFeralDruid() + // feral.RegisterFeralDruid() // feralTank.RegisterFeralTankDruid() restoDruid.RegisterRestorationDruid() diff --git a/sim/rogue/TestAssassination.results b/sim/rogue/_TestAssassination.results similarity index 100% rename from sim/rogue/TestAssassination.results rename to sim/rogue/_TestAssassination.results diff --git a/sim/rogue/TestCombat.results b/sim/rogue/_TestCombat.results similarity index 100% rename from sim/rogue/TestCombat.results rename to sim/rogue/_TestCombat.results diff --git a/sim/rogue/TestSubtlety.results b/sim/rogue/_TestSubtlety.results similarity index 100% rename from sim/rogue/TestSubtlety.results rename to sim/rogue/_TestSubtlety.results diff --git a/sim/rogue/ambush.go b/sim/rogue/_ambush.go similarity index 100% rename from sim/rogue/ambush.go rename to sim/rogue/_ambush.go diff --git a/sim/rogue/backstab.go b/sim/rogue/_backstab.go similarity index 100% rename from sim/rogue/backstab.go rename to sim/rogue/_backstab.go diff --git a/sim/rogue/envenom.go b/sim/rogue/_envenom.go similarity index 100% rename from sim/rogue/envenom.go rename to sim/rogue/_envenom.go diff --git a/sim/rogue/eviscerate.go b/sim/rogue/_eviscerate.go similarity index 100% rename from sim/rogue/eviscerate.go rename to sim/rogue/_eviscerate.go diff --git a/sim/rogue/expose_armor.go b/sim/rogue/_expose_armor.go similarity index 100% rename from sim/rogue/expose_armor.go rename to sim/rogue/_expose_armor.go diff --git a/sim/rogue/fan_of_knives.go b/sim/rogue/_fan_of_knives.go similarity index 100% rename from sim/rogue/fan_of_knives.go rename to sim/rogue/_fan_of_knives.go diff --git a/sim/rogue/feint.go b/sim/rogue/_feint.go similarity index 100% rename from sim/rogue/feint.go rename to sim/rogue/_feint.go diff --git a/sim/rogue/garrote.go b/sim/rogue/_garrote.go similarity index 100% rename from sim/rogue/garrote.go rename to sim/rogue/_garrote.go diff --git a/sim/rogue/ghostly_strike.go b/sim/rogue/_ghostly_strike.go similarity index 100% rename from sim/rogue/ghostly_strike.go rename to sim/rogue/_ghostly_strike.go diff --git a/sim/rogue/hack_and_slash.go b/sim/rogue/_hack_and_slash.go similarity index 100% rename from sim/rogue/hack_and_slash.go rename to sim/rogue/_hack_and_slash.go diff --git a/sim/rogue/hemorrhage.go b/sim/rogue/_hemorrhage.go similarity index 100% rename from sim/rogue/hemorrhage.go rename to sim/rogue/_hemorrhage.go diff --git a/sim/rogue/items.go b/sim/rogue/_items.go similarity index 100% rename from sim/rogue/items.go rename to sim/rogue/_items.go diff --git a/sim/rogue/killing_spree.go b/sim/rogue/_killing_spree.go similarity index 100% rename from sim/rogue/killing_spree.go rename to sim/rogue/_killing_spree.go diff --git a/sim/rogue/master_of_subtlety.go b/sim/rogue/_master_of_subtlety.go similarity index 100% rename from sim/rogue/master_of_subtlety.go rename to sim/rogue/_master_of_subtlety.go diff --git a/sim/rogue/mutilate.go b/sim/rogue/_mutilate.go similarity index 100% rename from sim/rogue/mutilate.go rename to sim/rogue/_mutilate.go diff --git a/sim/rogue/overkill.go b/sim/rogue/_overkill.go similarity index 100% rename from sim/rogue/overkill.go rename to sim/rogue/_overkill.go diff --git a/sim/rogue/poisons.go b/sim/rogue/_poisons.go similarity index 100% rename from sim/rogue/poisons.go rename to sim/rogue/_poisons.go diff --git a/sim/rogue/premeditation.go b/sim/rogue/_premeditation.go similarity index 100% rename from sim/rogue/premeditation.go rename to sim/rogue/_premeditation.go diff --git a/sim/rogue/preparation.go b/sim/rogue/_preparation.go similarity index 100% rename from sim/rogue/preparation.go rename to sim/rogue/_preparation.go diff --git a/sim/rogue/rupture.go b/sim/rogue/_rupture.go similarity index 100% rename from sim/rogue/rupture.go rename to sim/rogue/_rupture.go diff --git a/sim/rogue/shadow_dance.go b/sim/rogue/_shadow_dance.go similarity index 100% rename from sim/rogue/shadow_dance.go rename to sim/rogue/_shadow_dance.go diff --git a/sim/rogue/shadowstep.go b/sim/rogue/_shadowstep.go similarity index 100% rename from sim/rogue/shadowstep.go rename to sim/rogue/_shadowstep.go diff --git a/sim/rogue/shiv.go b/sim/rogue/_shiv.go similarity index 100% rename from sim/rogue/shiv.go rename to sim/rogue/_shiv.go diff --git a/sim/rogue/sinister_strike.go b/sim/rogue/_sinister_strike.go similarity index 100% rename from sim/rogue/sinister_strike.go rename to sim/rogue/_sinister_strike.go diff --git a/sim/rogue/slice_and_dice.go b/sim/rogue/_slice_and_dice.go similarity index 100% rename from sim/rogue/slice_and_dice.go rename to sim/rogue/_slice_and_dice.go diff --git a/sim/rogue/stealth.go b/sim/rogue/_stealth.go similarity index 100% rename from sim/rogue/stealth.go rename to sim/rogue/_stealth.go diff --git a/sim/rogue/thistle_tea.go b/sim/rogue/_thistle_tea.go similarity index 100% rename from sim/rogue/thistle_tea.go rename to sim/rogue/_thistle_tea.go diff --git a/sim/rogue/tricks_of_the_trade.go b/sim/rogue/_tricks_of_the_trade.go similarity index 100% rename from sim/rogue/tricks_of_the_trade.go rename to sim/rogue/_tricks_of_the_trade.go diff --git a/sim/rogue/vanish.go b/sim/rogue/_vanish.go similarity index 100% rename from sim/rogue/vanish.go rename to sim/rogue/_vanish.go diff --git a/sim/rogue/rogue.go b/sim/rogue/rogue.go index 8db854b4c5..7c4e56e85d 100644 --- a/sim/rogue/rogue.go +++ b/sim/rogue/rogue.go @@ -5,7 +5,6 @@ import ( "github.com/wowsims/cata/sim/core" "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" ) const ( @@ -105,13 +104,13 @@ func (rogue *Rogue) GetRogue() *Rogue { func (rogue *Rogue) AddRaidBuffs(_ *proto.RaidBuffs) {} func (rogue *Rogue) AddPartyBuffs(_ *proto.PartyBuffs) {} -func (rogue *Rogue) finisherFlags() core.SpellFlag { - flags := SpellFlagFinisher - if rogue.Talents.SurpriseAttacks { - flags |= core.SpellFlagCannotBeDodged - } - return flags -} +// func (rogue *Rogue) finisherFlags() core.SpellFlag { +// flags := SpellFlagFinisher +// if rogue.Talents.SurpriseAttacks { +// flags |= core.SpellFlagCannotBeDodged +// } +// return flags +// } // Apply the effect of successfully casting a finisher to combo points func (rogue *Rogue) ApplyFinisher(sim *core.Simulation, spell *core.Spell) { @@ -129,40 +128,40 @@ func (rogue *Rogue) HasMinorGlyph(glyph proto.RogueMinorGlyph) bool { } func (rogue *Rogue) Initialize() { - // Update auto crit multipliers now that we have the targets. - rogue.AutoAttacks.MHConfig().CritMultiplier = rogue.MeleeCritMultiplier(false) - rogue.AutoAttacks.OHConfig().CritMultiplier = rogue.MeleeCritMultiplier(false) - - if rogue.Talents.QuickRecovery > 0 { - rogue.QuickRecoveryMetrics = rogue.NewEnergyMetrics(core.ActionID{SpellID: 31245}) - } - - rogue.costModifier = rogue.makeCostModifier() - - rogue.registerStealthAura() - rogue.registerBackstabSpell() - rogue.registerDeadlyPoisonSpell() - rogue.registerPoisonAuras() - rogue.registerEviscerate() - rogue.registerExposeArmorSpell() - rogue.registerFanOfKnives() - rogue.registerFeintSpell() - rogue.registerGarrote() - rogue.registerHemorrhageSpell() - rogue.registerInstantPoisonSpell() - rogue.registerWoundPoisonSpell() - rogue.registerMutilateSpell() - rogue.registerRupture() - rogue.registerShivSpell() - rogue.registerSinisterStrikeSpell() - rogue.registerSliceAndDice() - rogue.registerThistleTeaCD() - rogue.registerTricksOfTheTradeSpell() - rogue.registerAmbushSpell() - rogue.registerEnvenom() - rogue.registerVanishSpell() - - rogue.finishingMoveEffectApplier = rogue.makeFinishingMoveEffectApplier() + // // Update auto crit multipliers now that we have the targets. + // rogue.AutoAttacks.MHConfig().CritMultiplier = rogue.MeleeCritMultiplier(false) + // rogue.AutoAttacks.OHConfig().CritMultiplier = rogue.MeleeCritMultiplier(false) + + // if rogue.Talents.QuickRecovery > 0 { + // rogue.QuickRecoveryMetrics = rogue.NewEnergyMetrics(core.ActionID{SpellID: 31245}) + // } + + // rogue.costModifier = rogue.makeCostModifier() + + // rogue.registerStealthAura() + // rogue.registerBackstabSpell() + // rogue.registerDeadlyPoisonSpell() + // rogue.registerPoisonAuras() + // rogue.registerEviscerate() + // rogue.registerExposeArmorSpell() + // rogue.registerFanOfKnives() + // rogue.registerFeintSpell() + // rogue.registerGarrote() + // rogue.registerHemorrhageSpell() + // rogue.registerInstantPoisonSpell() + // rogue.registerWoundPoisonSpell() + // rogue.registerMutilateSpell() + // rogue.registerRupture() + // rogue.registerShivSpell() + // rogue.registerSinisterStrikeSpell() + // rogue.registerSliceAndDice() + // rogue.registerThistleTeaCD() + // rogue.registerTricksOfTheTradeSpell() + // rogue.registerAmbushSpell() + // rogue.registerEnvenom() + // rogue.registerVanishSpell() + + // rogue.finishingMoveEffectApplier = rogue.makeFinishingMoveEffectApplier() } func (rogue *Rogue) ApplyEnergyTickMultiplier(multiplier float64) { @@ -175,53 +174,53 @@ func (rogue *Rogue) Reset(sim *core.Simulation) { } } -func (rogue *Rogue) MeleeCritMultiplier(applyLethality bool) float64 { - primaryModifier := rogue.preyOnTheWeakMultiplier(rogue.CurrentTarget) - var secondaryModifier float64 - if applyLethality { - secondaryModifier += 0.06 * float64(rogue.Talents.Lethality) - } - return rogue.Character.MeleeCritMultiplier(primaryModifier, secondaryModifier) -} -func (rogue *Rogue) SpellCritMultiplier() float64 { - primaryModifier := rogue.preyOnTheWeakMultiplier(rogue.CurrentTarget) - return rogue.Character.SpellCritMultiplier(primaryModifier, 0) -} +// func (rogue *Rogue) MeleeCritMultiplier(applyLethality bool) float64 { +// primaryModifier := rogue.preyOnTheWeakMultiplier(rogue.CurrentTarget) +// var secondaryModifier float64 +// if applyLethality { +// secondaryModifier += 0.06 * float64(rogue.Talents.Lethality) +// } +// return rogue.Character.MeleeCritMultiplier(primaryModifier, secondaryModifier) +// } +// func (rogue *Rogue) SpellCritMultiplier() float64 { +// primaryModifier := rogue.preyOnTheWeakMultiplier(rogue.CurrentTarget) +// return rogue.Character.SpellCritMultiplier(primaryModifier, 0) +// } func NewRogue(character *core.Character, talents string) *Rogue { rogue := &Rogue{ Character: *character, Talents: &proto.RogueTalents{}, } - core.FillTalentsProto(rogue.Talents.ProtoReflect(), talents, TalentTreeSizes) - - // Passive rogue threat reduction: https://wotlk.wowhead.com/spell=21184/rogue-passive-dnd - rogue.PseudoStats.ThreatMultiplier *= 0.71 - rogue.PseudoStats.CanParry = true - - maxEnergy := 100.0 - if rogue.Talents.Vigor { - maxEnergy += 10 - } - if rogue.HasMajorGlyph(proto.RogueMajorGlyph_GlyphOfVigor) { - maxEnergy += 10 - } - if rogue.HasSetBonus(Arena, 4) { - maxEnergy += 10 - } - rogue.EnableEnergyBar(maxEnergy) - rogue.ApplyEnergyTickMultiplier([]float64{0, 0.08, 0.16, 0.25}[rogue.Talents.Vitality]) - - rogue.EnableAutoAttacks(rogue, core.AutoAttackOptions{ - MainHand: rogue.WeaponFromMainHand(0), // Set crit multiplier later when we have targets. - OffHand: rogue.WeaponFromOffHand(0), // Set crit multiplier later when we have targets. - AutoSwingMelee: true, - }) - rogue.applyPoisons() - - rogue.AddStatDependency(stats.Strength, stats.AttackPower, 1) - rogue.AddStatDependency(stats.Agility, stats.AttackPower, 1) - rogue.AddStatDependency(stats.Agility, stats.MeleeCrit, core.CritPerAgiMaxLevel[character.Class]*core.CritRatingPerCritChance) + // core.FillTalentsProto(rogue.Talents.ProtoReflect(), talents, TalentTreeSizes) + + // // Passive rogue threat reduction: https://wotlk.wowhead.com/spell=21184/rogue-passive-dnd + // rogue.PseudoStats.ThreatMultiplier *= 0.71 + // rogue.PseudoStats.CanParry = true + + // maxEnergy := 100.0 + // if rogue.Talents.Vigor { + // maxEnergy += 10 + // } + // if rogue.HasMajorGlyph(proto.RogueMajorGlyph_GlyphOfVigor) { + // maxEnergy += 10 + // } + // if rogue.HasSetBonus(Arena, 4) { + // maxEnergy += 10 + // } + // rogue.EnableEnergyBar(maxEnergy) + // rogue.ApplyEnergyTickMultiplier([]float64{0, 0.08, 0.16, 0.25}[rogue.Talents.Vitality]) + + // rogue.EnableAutoAttacks(rogue, core.AutoAttackOptions{ + // MainHand: rogue.WeaponFromMainHand(0), // Set crit multiplier later when we have targets. + // OffHand: rogue.WeaponFromOffHand(0), // Set crit multiplier later when we have targets. + // AutoSwingMelee: true, + // }) + // rogue.applyPoisons() + + // rogue.AddStatDependency(stats.Strength, stats.AttackPower, 1) + // rogue.AddStatDependency(stats.Agility, stats.AttackPower, 1) + // rogue.AddStatDependency(stats.Agility, stats.MeleeCrit, core.CritPerAgiMaxLevel[character.Class]*core.CritRatingPerCritChance) return rogue } diff --git a/sim/rogue/talents.go b/sim/rogue/talents.go index 02b4c1153c..91ae9c3c7c 100644 --- a/sim/rogue/talents.go +++ b/sim/rogue/talents.go @@ -1,649 +1,640 @@ package rogue -import ( - "math" - "time" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" -) - -func (rogue *Rogue) ApplyTalents() { - rogue.applyMurder() - rogue.applySlaughterFromTheShadows() - rogue.applySealFate() - rogue.applyWeaponSpecializations() - rogue.applyCombatPotency() - rogue.applyFocusedAttacks() - rogue.applyInitiative() - - rogue.AddStat(stats.Dodge, core.DodgeRatingPerDodgeChance*2*float64(rogue.Talents.LightningReflexes)) - rogue.PseudoStats.MeleeSpeedMultiplier *= []float64{1, 1.03, 1.06, 1.10}[rogue.Talents.LightningReflexes] - rogue.AddStat(stats.Parry, core.ParryRatingPerParryChance*2*float64(rogue.Talents.Deflection)) - rogue.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*1*float64(rogue.Talents.Malice)) - rogue.AddStat(stats.MeleeHit, core.MeleeHitRatingPerHitChance*1*float64(rogue.Talents.Precision)) - rogue.AddStat(stats.SpellHit, core.SpellHitRatingPerHitChance*1*float64(rogue.Talents.Precision)) - rogue.AddStat(stats.Expertise, core.ExpertisePerQuarterPercentReduction*5*float64(rogue.Talents.WeaponExpertise)) - rogue.AddStat(stats.ArmorPenetration, core.ArmorPenPerPercentArmor*3*float64(rogue.Talents.SerratedBlades)) - rogue.AutoAttacks.OHConfig().DamageMultiplier *= rogue.dwsMultiplier() - - if rogue.Talents.Deadliness > 0 { - rogue.MultiplyStat(stats.AttackPower, 1.0+0.02*float64(rogue.Talents.Deadliness)) - } - - if rogue.Talents.SavageCombat > 0 { - rogue.MultiplyStat(stats.AttackPower, 1.0+0.02*float64(rogue.Talents.SavageCombat)) - } - - if rogue.Talents.SinisterCalling > 0 { - rogue.MultiplyStat(stats.Agility, 1.0+0.03*float64(rogue.Talents.SinisterCalling)) - } - - rogue.registerOverkill() - rogue.registerHungerForBlood() - rogue.registerColdBloodCD() - rogue.registerBladeFlurryCD() - rogue.registerAdrenalineRushCD() - rogue.registerKillingSpreeCD() - rogue.registerShadowstepCD() - rogue.registerShadowDanceCD() - rogue.registerMasterOfSubtletyCD() - rogue.registerPreparationCD() - rogue.registerPremeditation() - rogue.registerGhostlyStrikeSpell() - rogue.registerDirtyDeeds() - rogue.registerHonorAmongThieves() -} - -// dwsMultiplier returns the offhand damage multiplier -func (rogue *Rogue) dwsMultiplier() float64 { - return 1 + 0.1*float64(rogue.Talents.DualWieldSpecialization) -} - -func getRelentlessStrikesSpellID(talentPoints int32) int32 { - if talentPoints == 1 { - return 14179 - } - return 58420 + talentPoints -} - -func (rogue *Rogue) makeFinishingMoveEffectApplier() func(sim *core.Simulation, numPoints int32) { - ruthlessnessMetrics := rogue.NewComboPointMetrics(core.ActionID{SpellID: 14161}) - relentlessStrikesMetrics := rogue.NewEnergyMetrics(core.ActionID{SpellID: getRelentlessStrikesSpellID(rogue.Talents.RelentlessStrikes)}) - var mayhemMetrics *core.ResourceMetrics - if rogue.HasSetBonus(Tier10, 4) { - mayhemMetrics = rogue.NewComboPointMetrics(core.ActionID{SpellID: 70802}) - } - - return func(sim *core.Simulation, numPoints int32) { - if t := rogue.Talents.Ruthlessness; t > 0 { - if sim.RandomFloat("Ruthlessness") < 0.2*float64(t) { - rogue.AddComboPoints(sim, 1, ruthlessnessMetrics) - } - } - if t := rogue.Talents.RelentlessStrikes; t > 0 { - if sim.RandomFloat("RelentlessStrikes") < 0.04*float64(t*numPoints) { - rogue.AddEnergy(sim, 25, relentlessStrikesMetrics) - } - } - if mayhemMetrics != nil { - if sim.RandomFloat("Mayhem") < 0.13 { - rogue.AddComboPoints(sim, 3, mayhemMetrics) - } - } - } -} - -func (rogue *Rogue) makeCostModifier() func(baseCost float64) float64 { - if rogue.HasSetBonus(Tier7, 4) { - return func(baseCost float64) float64 { - return math.RoundToEven(0.95 * baseCost) - } - } - return func(baseCost float64) float64 { - return baseCost - } -} - -func (rogue *Rogue) applyMurder() { - rogue.PseudoStats.DamageDealtMultiplier *= rogue.murderMultiplier() -} - -func (rogue *Rogue) murderMultiplier() float64 { - return 1.0 + 0.02*float64(rogue.Talents.Murder) -} - -func (rogue *Rogue) applySlaughterFromTheShadows() { - rogue.PseudoStats.DamageDealtMultiplier *= rogue.slaughterFromTheShadowsMultiplier() -} - -func (rogue *Rogue) slaughterFromTheShadowsMultiplier() float64 { - return 1.0 + 0.01*float64(rogue.Talents.SlaughterFromTheShadows) -} - -func (rogue *Rogue) registerHungerForBlood() { - if !rogue.Talents.HungerForBlood { - return - } - actionID := core.ActionID{SpellID: 51662} - multiplier := 1.05 - if rogue.HasMajorGlyph(proto.RogueMajorGlyph_GlyphOfHungerForBlood) { - multiplier += 0.03 - } - rogue.HungerForBloodAura = rogue.RegisterAura(core.Aura{ - Label: "Hunger for Blood", - ActionID: actionID, - Duration: time.Minute, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - rogue.PseudoStats.DamageDealtMultiplier *= multiplier - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - rogue.PseudoStats.DamageDealtMultiplier *= 1 / multiplier - }, - }) - - rogue.HungerForBlood = rogue.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagAPL, - - EnergyCost: core.EnergyCostOptions{ - Cost: 15, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: time.Second, - }, - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { - rogue.HungerForBloodAura.Activate(sim) - }, - }) -} - -func (rogue *Rogue) preyOnTheWeakMultiplier(_ *core.Unit) float64 { - // TODO: Use the following predicate if/when health values are modeled, - // but note that this would have to be applied dynamically in that case. - //if rogue.CurrentTarget != nil && - //rogue.CurrentTarget.HasHealthBar() && - //rogue.CurrentTarget.CurrentHealthPercent() < rogue.CurrentHealthPercent() - return 1 + 0.04*float64(rogue.Talents.PreyOnTheWeak) -} - -func (rogue *Rogue) registerDirtyDeeds() { - if rogue.Talents.DirtyDeeds == 0 { - return - } - - actionID := core.ActionID{SpellID: 14083} - - rogue.RegisterResetEffect(func(sim *core.Simulation) { - sim.RegisterExecutePhaseCallback(func(sim *core.Simulation, isExecute int32) { - if isExecute == 35 { - rogue.DirtyDeedsAura.Activate(sim) - } - }) - }) - - rogue.DirtyDeedsAura = rogue.RegisterAura(core.Aura{ - Label: "Dirty Deeds", - ActionID: actionID, - Duration: core.NeverExpires, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range rogue.Spellbook { - if spell.Flags.Matches(SpellFlagBuilder|SpellFlagFinisher) && spell.DamageMultiplier > 0 { - spell.DamageMultiplier *= rogue.DirtyDeedsMultiplier() - } - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range rogue.Spellbook { - if spell.Flags.Matches(SpellFlagBuilder|SpellFlagFinisher) && spell.DamageMultiplier > 0 { - spell.DamageMultiplier /= rogue.DirtyDeedsMultiplier() - } - } - }, - }) -} - -func (rogue *Rogue) DirtyDeedsMultiplier() float64 { - if rogue.Talents.DirtyDeeds == 0 { - return 1 - } - - return 1 + 0.1*float64(rogue.Talents.DirtyDeeds) -} - -func (rogue *Rogue) registerColdBloodCD() { - if !rogue.Talents.ColdBlood { - return - } - - actionID := core.ActionID{SpellID: 14177} - - coldBloodAura := rogue.RegisterAura(core.Aura{ - Label: "Cold Blood", - ActionID: actionID, - Duration: core.NeverExpires, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range rogue.Spellbook { - if spell.Flags.Matches(SpellFlagColdBlooded) { - spell.BonusCritRating += 100 * core.CritRatingPerCritChance - } - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range rogue.Spellbook { - if spell.Flags.Matches(SpellFlagColdBlooded) { - spell.BonusCritRating -= 100 * core.CritRatingPerCritChance - } - } - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - // for Fan of Knives and Mutilate, the offhand hit comes first and is ignored, so the aura doesn't fade too early - if spell.Flags.Matches(SpellFlagColdBlooded) && spell.ProcMask.Matches(core.ProcMaskMeleeMH) { - aura.Deactivate(sim) - } - }, - }) - - rogue.ColdBlood = rogue.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: rogue.NewTimer(), - Duration: time.Minute * 3, - }, - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { - coldBloodAura.Activate(sim) - }, - }) - - rogue.AddMajorCooldown(core.MajorCooldown{ - Spell: rogue.ColdBlood, - Type: core.CooldownTypeDPS, - }) -} - -func (rogue *Rogue) applySealFate() { - if rogue.Talents.SealFate == 0 { - return - } - - procChance := 0.2 * float64(rogue.Talents.SealFate) - cpMetrics := rogue.NewComboPointMetrics(core.ActionID{SpellID: 14195}) - - icd := core.Cooldown{ - Timer: rogue.NewTimer(), - Duration: 500 * time.Millisecond, - } - - rogue.RegisterAura(core.Aura{ - Label: "Seal Fate", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.Flags.Matches(SpellFlagBuilder) { - return - } - - if !result.Outcome.Matches(core.OutcomeCrit) { - return - } - - if icd.IsReady(sim) && sim.Proc(procChance, "Seal Fate") { - rogue.AddComboPoints(sim, 1, cpMetrics) - icd.Use(sim) - } - }, - }) -} - -func (rogue *Rogue) applyInitiative() { - if rogue.Talents.Initiative == 0 { - return - } - - procChance := []float64{0, 0.33, 0.66, 1.0}[rogue.Talents.Initiative] - cpMetrics := rogue.NewComboPointMetrics(core.ActionID{SpellID: 13980}) - - rogue.RegisterAura(core.Aura{ - Label: "Initiative", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == rogue.Garrote || spell == rogue.Ambush { - if result.Landed() { - if sim.Proc(procChance, "Initiative") { - rogue.AddComboPoints(sim, 1, cpMetrics) - } - } - } - }, - }) -} - -func (rogue *Rogue) applyWeaponSpecializations() { - if hns := rogue.Talents.HackAndSlash; hns > 0 { - if mask := rogue.GetProcMaskForTypes(proto.WeaponType_WeaponTypeSword, proto.WeaponType_WeaponTypeAxe); mask != core.ProcMaskUnknown { - rogue.registerHackAndSlash(mask) - } - } - - if cqc := rogue.Talents.CloseQuartersCombat; cqc > 0 { - switch rogue.GetProcMaskForTypes(proto.WeaponType_WeaponTypeDagger, proto.WeaponType_WeaponTypeFist) { - case core.ProcMaskMelee: - rogue.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*float64(cqc)) - case core.ProcMaskMeleeMH: - // the default character pane displays critical strike chance for main hand only - rogue.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*float64(cqc)) - rogue.OnSpellRegistered(func(spell *core.Spell) { - if spell.ProcMask.Matches(core.ProcMaskMeleeOH) { - spell.BonusCritRating -= core.CritRatingPerCritChance * float64(cqc) - } - }) - case core.ProcMaskMeleeOH: - rogue.OnSpellRegistered(func(spell *core.Spell) { - if spell.ProcMask.Matches(core.ProcMaskMeleeOH) { - spell.BonusCritRating += core.CritRatingPerCritChance * float64(cqc) - } - }) - } - } - - if ms := rogue.Talents.MaceSpecialization; ms > 0 { - if mask := rogue.GetProcMaskForTypes(proto.WeaponType_WeaponTypeMace); mask != core.ProcMaskUnknown { - rogue.AddStat(stats.ArmorPenetration, core.ArmorPenPerPercentArmor*3*float64(ms)) - } - } -} - -func (rogue *Rogue) applyCombatPotency() { - if rogue.Talents.CombatPotency == 0 { - return - } - - const procChance = 0.2 - energyBonus := 3.0 * float64(rogue.Talents.CombatPotency) - energyMetrics := rogue.NewEnergyMetrics(core.ActionID{SpellID: 35553}) - - rogue.RegisterAura(core.Aura{ - Label: "Combat Potency", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - // from 3.0.3 patch notes: "Combat Potency: Now only works with auto attacks" - if !result.Landed() || !spell.ProcMask.Matches(core.ProcMaskMeleeOHAuto) { - return - } - - if sim.RandomFloat("Combat Potency") < procChance { - rogue.AddEnergy(sim, energyBonus, energyMetrics) - } - }, - }) -} - -func (rogue *Rogue) applyFocusedAttacks() { - if rogue.Talents.FocusedAttacks == 0 { - return - } - - procChance := []float64{0, 0.33, 0.66, 1}[rogue.Talents.FocusedAttacks] - energyMetrics := rogue.NewEnergyMetrics(core.ActionID{SpellID: 51637}) - - rogue.RegisterAura(core.Aura{ - Label: "Focused Attacks", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskMelee) || !result.DidCrit() { - return - } - // Fan of Knives OH hits do not trigger focused attacks - if spell.ProcMask.Matches(core.ProcMaskMeleeOH) && spell.IsSpellAction(FanOfKnivesSpellID) { - return - } - if sim.Proc(procChance, "Focused Attacks") { - rogue.AddEnergy(sim, 2, energyMetrics) - } - }, - }) -} - -var BladeFlurryActionID = core.ActionID{SpellID: 13877} -var BladeFlurryHitID = core.ActionID{SpellID: 22482} - -func (rogue *Rogue) registerBladeFlurryCD() { - if !rogue.Talents.BladeFlurry { - return - } - - var curDmg float64 - bfHit := rogue.RegisterSpell(core.SpellConfig{ - ActionID: BladeFlurryHitID, - SpellSchool: core.SpellSchoolPhysical, - ProcMask: core.ProcMaskEmpty, // No proc mask, so it won't proc itself. - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagNoOnCastComplete | core.SpellFlagIgnoreAttackerModifiers, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - spell.CalcAndDealDamage(sim, target, curDmg, spell.OutcomeAlwaysHit) - }, - }) - - const hasteBonus = 1.2 - const inverseHasteBonus = 1 / 1.2 - - dur := time.Second * 15 - - rogue.BladeFlurryAura = rogue.RegisterAura(core.Aura{ - Label: "Blade Flurry", - ActionID: BladeFlurryActionID, - Duration: dur, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - rogue.MultiplyMeleeSpeed(sim, hasteBonus) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - rogue.MultiplyMeleeSpeed(sim, inverseHasteBonus) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if sim.GetNumTargets() < 2 { - return - } - if result.Damage == 0 || !spell.ProcMask.Matches(core.ProcMaskMelee) { - return - } - // Fan of Knives off-hand hits are not cloned - if spell.IsSpellAction(FanOfKnivesSpellID) && spell.ProcMask.Matches(core.ProcMaskMeleeOH) { - return - } - - // Undo armor reduction to get the raw damage value. - curDmg = result.Damage / result.ResistanceMultiplier - - bfHit.Cast(sim, rogue.Env.NextTargetUnit(result.Target)) - bfHit.SpellMetrics[result.Target.UnitIndex].Casts-- - }, - }) - - cooldownDur := time.Minute * 2 - rogue.BladeFlurry = rogue.RegisterSpell(core.SpellConfig{ - ActionID: BladeFlurryActionID, - Flags: core.SpellFlagAPL, - - EnergyCost: core.EnergyCostOptions{ - Cost: core.TernaryFloat64(rogue.HasMajorGlyph(proto.RogueMajorGlyph_GlyphOfBladeFlurry), 0, 25), - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: time.Second, - }, - IgnoreHaste: true, - CD: core.Cooldown{ - Timer: rogue.NewTimer(), - Duration: cooldownDur, - }, - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { - rogue.BreakStealth(sim) - rogue.BladeFlurryAura.Activate(sim) - }, - }) - - rogue.AddMajorCooldown(core.MajorCooldown{ - Spell: rogue.BladeFlurry, - Type: core.CooldownTypeDPS, - Priority: core.CooldownPriorityDefault, - ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { - if sim.GetRemainingDuration() > cooldownDur+dur { - // We'll have enough time to cast another BF, so use it immediately to make sure we get the 2nd one. - return true - } - - // Since this is our last BF, wait until we have SND / procs up. - sndTimeRemaining := rogue.SliceAndDiceAura.RemainingDuration(sim) - // TODO: Wait for dst/mongoose procs - return sndTimeRemaining >= time.Second - }, - }) -} - -var AdrenalineRushActionID = core.ActionID{SpellID: 13750} - -func (rogue *Rogue) registerAdrenalineRushCD() { - if !rogue.Talents.AdrenalineRush { - return - } - - rogue.AdrenalineRushAura = rogue.RegisterAura(core.Aura{ - Label: "Adrenaline Rush", - ActionID: AdrenalineRushActionID, - Duration: core.TernaryDuration(rogue.HasMajorGlyph(proto.RogueMajorGlyph_GlyphOfAdrenalineRush), time.Second*20, time.Second*15), - OnGain: func(aura *core.Aura, sim *core.Simulation) { - rogue.ResetEnergyTick(sim) - rogue.ApplyEnergyTickMultiplier(1.0) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - rogue.ResetEnergyTick(sim) - rogue.ApplyEnergyTickMultiplier(-1.0) - }, - }) - - adrenalineRushSpell := rogue.RegisterSpell(core.SpellConfig{ - ActionID: AdrenalineRushActionID, - - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: time.Second, - }, - IgnoreHaste: true, - CD: core.Cooldown{ - Timer: rogue.NewTimer(), - Duration: time.Minute * 3, - }, - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { - rogue.BreakStealth(sim) - rogue.AdrenalineRushAura.Activate(sim) - }, - }) - - rogue.AddMajorCooldown(core.MajorCooldown{ - Spell: adrenalineRushSpell, - Type: core.CooldownTypeDPS, - Priority: core.CooldownPriorityBloodlust, - ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { - thresh := 45.0 - return rogue.CurrentEnergy() <= thresh - }, - }) -} - -func (rogue *Rogue) registerKillingSpreeCD() { - if !rogue.Talents.KillingSpree { - return - } - rogue.registerKillingSpreeSpell() -} - -func (rogue *Rogue) registerHonorAmongThieves() { - // When anyone in your group critically hits with a damage or healing spell or ability, - // you have a [33%/66%/100%] chance to gain a combo point on your current target. - // This effect cannot occur more than once per second. - if rogue.Talents.HonorAmongThieves == 0 { - return - } - - procChance := []float64{0, 0.33, 0.66, 1}[rogue.Talents.HonorAmongThieves] - comboMetrics := rogue.NewComboPointMetrics(core.ActionID{SpellID: 51701}) - honorAmongThievesID := core.ActionID{SpellID: 51701} - - icd := core.Cooldown{ - Timer: rogue.NewTimer(), - Duration: time.Second, - } - - maybeProc := func(sim *core.Simulation) { - if icd.IsReady(sim) && sim.Proc(procChance, "honor of thieves") { - rogue.AddComboPoints(sim, 1, comboMetrics) - icd.Use(sim) - } - } - - rogue.HonorAmongThieves = rogue.RegisterAura(core.Aura{ - Label: "Honor Among Thieves", - ActionID: honorAmongThievesID, - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnGain: func(_ *core.Aura, sim *core.Simulation) { - // In an ideal party, you'd probably get up to 6 ability crits/s (Rate = 600). - // Survival Hunters, Enhancement Shamans, and Assassination Rogues are particularly good. - if rogue.SubtletyOptions.HonorAmongThievesCritRate <= 0 { - return - } - - if rogue.SubtletyOptions.HonorAmongThievesCritRate > 2000 { - rogue.SubtletyOptions.HonorAmongThievesCritRate = 2000 // limited, so performance doesn't suffer - } - - rateToDuration := float64(time.Second) * 100 / float64(rogue.SubtletyOptions.HonorAmongThievesCritRate) - - pa := &core.PendingAction{} - pa.OnAction = func(sim *core.Simulation) { - maybeProc(sim) - pa.NextActionAt = sim.CurrentTime + time.Duration(sim.RandomExpFloat("next party crit")*rateToDuration) - sim.AddPendingAction(pa) - } - pa.NextActionAt = sim.CurrentTime + time.Duration(sim.RandomExpFloat("next party crit")*rateToDuration) - sim.AddPendingAction(pa) - }, - OnSpellHitDealt: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.DidCrit() && !spell.ProcMask.Matches(core.ProcMaskMeleeMHAuto|core.ProcMaskMeleeOHAuto|core.ProcMaskRangedAuto) { - maybeProc(sim) - } - }, - OnPeriodicDamageDealt: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.DidCrit() { - maybeProc(sim) - } - }, - }) -} + func (rogue *Rogue) ApplyTalents() { +// rogue.applyMurder() +// rogue.applySlaughterFromTheShadows() +// rogue.applySealFate() +// rogue.applyWeaponSpecializations() +// rogue.applyCombatPotency() +// rogue.applyFocusedAttacks() +// rogue.applyInitiative() + +// rogue.AddStat(stats.Dodge, core.DodgeRatingPerDodgeChance*2*float64(rogue.Talents.LightningReflexes)) +// rogue.PseudoStats.MeleeSpeedMultiplier *= []float64{1, 1.03, 1.06, 1.10}[rogue.Talents.LightningReflexes] +// rogue.AddStat(stats.Parry, core.ParryRatingPerParryChance*2*float64(rogue.Talents.Deflection)) +// rogue.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*1*float64(rogue.Talents.Malice)) +// rogue.AddStat(stats.MeleeHit, core.MeleeHitRatingPerHitChance*1*float64(rogue.Talents.Precision)) +// rogue.AddStat(stats.SpellHit, core.SpellHitRatingPerHitChance*1*float64(rogue.Talents.Precision)) +// rogue.AddStat(stats.Expertise, core.ExpertisePerQuarterPercentReduction*5*float64(rogue.Talents.WeaponExpertise)) +// rogue.AddStat(stats.ArmorPenetration, core.ArmorPenPerPercentArmor*3*float64(rogue.Talents.SerratedBlades)) +// rogue.AutoAttacks.OHConfig().DamageMultiplier *= rogue.dwsMultiplier() + +// if rogue.Talents.Deadliness > 0 { +// rogue.MultiplyStat(stats.AttackPower, 1.0+0.02*float64(rogue.Talents.Deadliness)) +// } + +// if rogue.Talents.SavageCombat > 0 { +// rogue.MultiplyStat(stats.AttackPower, 1.0+0.02*float64(rogue.Talents.SavageCombat)) +// } + +// if rogue.Talents.SinisterCalling > 0 { +// rogue.MultiplyStat(stats.Agility, 1.0+0.03*float64(rogue.Talents.SinisterCalling)) +// } + +// rogue.registerOverkill() +// rogue.registerHungerForBlood() +// rogue.registerColdBloodCD() +// rogue.registerBladeFlurryCD() +// rogue.registerAdrenalineRushCD() +// rogue.registerKillingSpreeCD() +// rogue.registerShadowstepCD() +// rogue.registerShadowDanceCD() +// rogue.registerMasterOfSubtletyCD() +// rogue.registerPreparationCD() +// rogue.registerPremeditation() +// rogue.registerGhostlyStrikeSpell() +// rogue.registerDirtyDeeds() +// rogue.registerHonorAmongThieves() + } + +// // dwsMultiplier returns the offhand damage multiplier +// func (rogue *Rogue) dwsMultiplier() float64 { +// return 1 + 0.1*float64(rogue.Talents.DualWieldSpecialization) +// } + +// func getRelentlessStrikesSpellID(talentPoints int32) int32 { +// if talentPoints == 1 { +// return 14179 +// } +// return 58420 + talentPoints +// } + +// func (rogue *Rogue) makeFinishingMoveEffectApplier() func(sim *core.Simulation, numPoints int32) { +// ruthlessnessMetrics := rogue.NewComboPointMetrics(core.ActionID{SpellID: 14161}) +// relentlessStrikesMetrics := rogue.NewEnergyMetrics(core.ActionID{SpellID: getRelentlessStrikesSpellID(rogue.Talents.RelentlessStrikes)}) +// var mayhemMetrics *core.ResourceMetrics +// if rogue.HasSetBonus(Tier10, 4) { +// mayhemMetrics = rogue.NewComboPointMetrics(core.ActionID{SpellID: 70802}) +// } + +// return func(sim *core.Simulation, numPoints int32) { +// if t := rogue.Talents.Ruthlessness; t > 0 { +// if sim.RandomFloat("Ruthlessness") < 0.2*float64(t) { +// rogue.AddComboPoints(sim, 1, ruthlessnessMetrics) +// } +// } +// if t := rogue.Talents.RelentlessStrikes; t > 0 { +// if sim.RandomFloat("RelentlessStrikes") < 0.04*float64(t*numPoints) { +// rogue.AddEnergy(sim, 25, relentlessStrikesMetrics) +// } +// } +// if mayhemMetrics != nil { +// if sim.RandomFloat("Mayhem") < 0.13 { +// rogue.AddComboPoints(sim, 3, mayhemMetrics) +// } +// } +// } +// } + +// func (rogue *Rogue) makeCostModifier() func(baseCost float64) float64 { +// if rogue.HasSetBonus(Tier7, 4) { +// return func(baseCost float64) float64 { +// return math.RoundToEven(0.95 * baseCost) +// } +// } +// return func(baseCost float64) float64 { +// return baseCost +// } +// } + +// func (rogue *Rogue) applyMurder() { +// rogue.PseudoStats.DamageDealtMultiplier *= rogue.murderMultiplier() +// } + +// func (rogue *Rogue) murderMultiplier() float64 { +// return 1.0 + 0.02*float64(rogue.Talents.Murder) +// } + +// func (rogue *Rogue) applySlaughterFromTheShadows() { +// rogue.PseudoStats.DamageDealtMultiplier *= rogue.slaughterFromTheShadowsMultiplier() +// } + +// func (rogue *Rogue) slaughterFromTheShadowsMultiplier() float64 { +// return 1.0 + 0.01*float64(rogue.Talents.SlaughterFromTheShadows) +// } + +// func (rogue *Rogue) registerHungerForBlood() { +// if !rogue.Talents.HungerForBlood { +// return +// } +// actionID := core.ActionID{SpellID: 51662} +// multiplier := 1.05 +// if rogue.HasMajorGlyph(proto.RogueMajorGlyph_GlyphOfHungerForBlood) { +// multiplier += 0.03 +// } +// rogue.HungerForBloodAura = rogue.RegisterAura(core.Aura{ +// Label: "Hunger for Blood", +// ActionID: actionID, +// Duration: time.Minute, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// rogue.PseudoStats.DamageDealtMultiplier *= multiplier +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// rogue.PseudoStats.DamageDealtMultiplier *= 1 / multiplier +// }, +// }) + +// rogue.HungerForBlood = rogue.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagAPL, + +// EnergyCost: core.EnergyCostOptions{ +// Cost: 15, +// }, +// Cast: core.CastConfig{ +// DefaultCast: core.Cast{ +// GCD: time.Second, +// }, +// }, +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { +// rogue.HungerForBloodAura.Activate(sim) +// }, +// }) +// } + +// func (rogue *Rogue) preyOnTheWeakMultiplier(_ *core.Unit) float64 { +// // TODO: Use the following predicate if/when health values are modeled, +// // but note that this would have to be applied dynamically in that case. +// //if rogue.CurrentTarget != nil && +// //rogue.CurrentTarget.HasHealthBar() && +// //rogue.CurrentTarget.CurrentHealthPercent() < rogue.CurrentHealthPercent() +// return 1 + 0.04*float64(rogue.Talents.PreyOnTheWeak) +// } + +// func (rogue *Rogue) registerDirtyDeeds() { +// if rogue.Talents.DirtyDeeds == 0 { +// return +// } + +// actionID := core.ActionID{SpellID: 14083} + +// rogue.RegisterResetEffect(func(sim *core.Simulation) { +// sim.RegisterExecutePhaseCallback(func(sim *core.Simulation, isExecute int32) { +// if isExecute == 35 { +// rogue.DirtyDeedsAura.Activate(sim) +// } +// }) +// }) + +// rogue.DirtyDeedsAura = rogue.RegisterAura(core.Aura{ +// Label: "Dirty Deeds", +// ActionID: actionID, +// Duration: core.NeverExpires, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range rogue.Spellbook { +// if spell.Flags.Matches(SpellFlagBuilder|SpellFlagFinisher) && spell.DamageMultiplier > 0 { +// spell.DamageMultiplier *= rogue.DirtyDeedsMultiplier() +// } +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range rogue.Spellbook { +// if spell.Flags.Matches(SpellFlagBuilder|SpellFlagFinisher) && spell.DamageMultiplier > 0 { +// spell.DamageMultiplier /= rogue.DirtyDeedsMultiplier() +// } +// } +// }, +// }) +// } + +// func (rogue *Rogue) DirtyDeedsMultiplier() float64 { +// if rogue.Talents.DirtyDeeds == 0 { +// return 1 +// } + +// return 1 + 0.1*float64(rogue.Talents.DirtyDeeds) +// } + +// func (rogue *Rogue) registerColdBloodCD() { +// if !rogue.Talents.ColdBlood { +// return +// } + +// actionID := core.ActionID{SpellID: 14177} + +// coldBloodAura := rogue.RegisterAura(core.Aura{ +// Label: "Cold Blood", +// ActionID: actionID, +// Duration: core.NeverExpires, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range rogue.Spellbook { +// if spell.Flags.Matches(SpellFlagColdBlooded) { +// spell.BonusCritRating += 100 * core.CritRatingPerCritChance +// } +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range rogue.Spellbook { +// if spell.Flags.Matches(SpellFlagColdBlooded) { +// spell.BonusCritRating -= 100 * core.CritRatingPerCritChance +// } +// } +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// // for Fan of Knives and Mutilate, the offhand hit comes first and is ignored, so the aura doesn't fade too early +// if spell.Flags.Matches(SpellFlagColdBlooded) && spell.ProcMask.Matches(core.ProcMaskMeleeMH) { +// aura.Deactivate(sim) +// } +// }, +// }) + +// rogue.ColdBlood = rogue.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, + +// Cast: core.CastConfig{ +// CD: core.Cooldown{ +// Timer: rogue.NewTimer(), +// Duration: time.Minute * 3, +// }, +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { +// coldBloodAura.Activate(sim) +// }, +// }) + +// rogue.AddMajorCooldown(core.MajorCooldown{ +// Spell: rogue.ColdBlood, +// Type: core.CooldownTypeDPS, +// }) +// } + +// func (rogue *Rogue) applySealFate() { +// if rogue.Talents.SealFate == 0 { +// return +// } + +// procChance := 0.2 * float64(rogue.Talents.SealFate) +// cpMetrics := rogue.NewComboPointMetrics(core.ActionID{SpellID: 14195}) + +// icd := core.Cooldown{ +// Timer: rogue.NewTimer(), +// Duration: 500 * time.Millisecond, +// } + +// rogue.RegisterAura(core.Aura{ +// Label: "Seal Fate", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.Flags.Matches(SpellFlagBuilder) { +// return +// } + +// if !result.Outcome.Matches(core.OutcomeCrit) { +// return +// } + +// if icd.IsReady(sim) && sim.Proc(procChance, "Seal Fate") { +// rogue.AddComboPoints(sim, 1, cpMetrics) +// icd.Use(sim) +// } +// }, +// }) +// } + +// func (rogue *Rogue) applyInitiative() { +// if rogue.Talents.Initiative == 0 { +// return +// } + +// procChance := []float64{0, 0.33, 0.66, 1.0}[rogue.Talents.Initiative] +// cpMetrics := rogue.NewComboPointMetrics(core.ActionID{SpellID: 13980}) + +// rogue.RegisterAura(core.Aura{ +// Label: "Initiative", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == rogue.Garrote || spell == rogue.Ambush { +// if result.Landed() { +// if sim.Proc(procChance, "Initiative") { +// rogue.AddComboPoints(sim, 1, cpMetrics) +// } +// } +// } +// }, +// }) +// } + +// func (rogue *Rogue) applyWeaponSpecializations() { +// if hns := rogue.Talents.HackAndSlash; hns > 0 { +// if mask := rogue.GetProcMaskForTypes(proto.WeaponType_WeaponTypeSword, proto.WeaponType_WeaponTypeAxe); mask != core.ProcMaskUnknown { +// rogue.registerHackAndSlash(mask) +// } +// } + +// if cqc := rogue.Talents.CloseQuartersCombat; cqc > 0 { +// switch rogue.GetProcMaskForTypes(proto.WeaponType_WeaponTypeDagger, proto.WeaponType_WeaponTypeFist) { +// case core.ProcMaskMelee: +// rogue.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*float64(cqc)) +// case core.ProcMaskMeleeMH: +// // the default character pane displays critical strike chance for main hand only +// rogue.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*float64(cqc)) +// rogue.OnSpellRegistered(func(spell *core.Spell) { +// if spell.ProcMask.Matches(core.ProcMaskMeleeOH) { +// spell.BonusCritRating -= core.CritRatingPerCritChance * float64(cqc) +// } +// }) +// case core.ProcMaskMeleeOH: +// rogue.OnSpellRegistered(func(spell *core.Spell) { +// if spell.ProcMask.Matches(core.ProcMaskMeleeOH) { +// spell.BonusCritRating += core.CritRatingPerCritChance * float64(cqc) +// } +// }) +// } +// } + +// if ms := rogue.Talents.MaceSpecialization; ms > 0 { +// if mask := rogue.GetProcMaskForTypes(proto.WeaponType_WeaponTypeMace); mask != core.ProcMaskUnknown { +// rogue.AddStat(stats.ArmorPenetration, core.ArmorPenPerPercentArmor*3*float64(ms)) +// } +// } +// } + +// func (rogue *Rogue) applyCombatPotency() { +// if rogue.Talents.CombatPotency == 0 { +// return +// } + +// const procChance = 0.2 +// energyBonus := 3.0 * float64(rogue.Talents.CombatPotency) +// energyMetrics := rogue.NewEnergyMetrics(core.ActionID{SpellID: 35553}) + +// rogue.RegisterAura(core.Aura{ +// Label: "Combat Potency", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// // from 3.0.3 patch notes: "Combat Potency: Now only works with auto attacks" +// if !result.Landed() || !spell.ProcMask.Matches(core.ProcMaskMeleeOHAuto) { +// return +// } + +// if sim.RandomFloat("Combat Potency") < procChance { +// rogue.AddEnergy(sim, energyBonus, energyMetrics) +// } +// }, +// }) +// } + +// func (rogue *Rogue) applyFocusedAttacks() { +// if rogue.Talents.FocusedAttacks == 0 { +// return +// } + +// procChance := []float64{0, 0.33, 0.66, 1}[rogue.Talents.FocusedAttacks] +// energyMetrics := rogue.NewEnergyMetrics(core.ActionID{SpellID: 51637}) + +// rogue.RegisterAura(core.Aura{ +// Label: "Focused Attacks", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.ProcMask.Matches(core.ProcMaskMelee) || !result.DidCrit() { +// return +// } +// // Fan of Knives OH hits do not trigger focused attacks +// if spell.ProcMask.Matches(core.ProcMaskMeleeOH) && spell.IsSpellAction(FanOfKnivesSpellID) { +// return +// } +// if sim.Proc(procChance, "Focused Attacks") { +// rogue.AddEnergy(sim, 2, energyMetrics) +// } +// }, +// }) +// } + +// var BladeFlurryActionID = core.ActionID{SpellID: 13877} +// var BladeFlurryHitID = core.ActionID{SpellID: 22482} + +// func (rogue *Rogue) registerBladeFlurryCD() { +// if !rogue.Talents.BladeFlurry { +// return +// } + +// var curDmg float64 +// bfHit := rogue.RegisterSpell(core.SpellConfig{ +// ActionID: BladeFlurryHitID, +// SpellSchool: core.SpellSchoolPhysical, +// ProcMask: core.ProcMaskEmpty, // No proc mask, so it won't proc itself. +// Flags: core.SpellFlagMeleeMetrics | core.SpellFlagNoOnCastComplete | core.SpellFlagIgnoreAttackerModifiers, + +// DamageMultiplier: 1, +// ThreatMultiplier: 1, + +// ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { +// spell.CalcAndDealDamage(sim, target, curDmg, spell.OutcomeAlwaysHit) +// }, +// }) + +// const hasteBonus = 1.2 +// const inverseHasteBonus = 1 / 1.2 + +// dur := time.Second * 15 + +// rogue.BladeFlurryAura = rogue.RegisterAura(core.Aura{ +// Label: "Blade Flurry", +// ActionID: BladeFlurryActionID, +// Duration: dur, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// rogue.MultiplyMeleeSpeed(sim, hasteBonus) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// rogue.MultiplyMeleeSpeed(sim, inverseHasteBonus) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if sim.GetNumTargets() < 2 { +// return +// } +// if result.Damage == 0 || !spell.ProcMask.Matches(core.ProcMaskMelee) { +// return +// } +// // Fan of Knives off-hand hits are not cloned +// if spell.IsSpellAction(FanOfKnivesSpellID) && spell.ProcMask.Matches(core.ProcMaskMeleeOH) { +// return +// } + +// // Undo armor reduction to get the raw damage value. +// curDmg = result.Damage / result.ResistanceMultiplier + +// bfHit.Cast(sim, rogue.Env.NextTargetUnit(result.Target)) +// bfHit.SpellMetrics[result.Target.UnitIndex].Casts-- +// }, +// }) + +// cooldownDur := time.Minute * 2 +// rogue.BladeFlurry = rogue.RegisterSpell(core.SpellConfig{ +// ActionID: BladeFlurryActionID, +// Flags: core.SpellFlagAPL, + +// EnergyCost: core.EnergyCostOptions{ +// Cost: core.TernaryFloat64(rogue.HasMajorGlyph(proto.RogueMajorGlyph_GlyphOfBladeFlurry), 0, 25), +// }, +// Cast: core.CastConfig{ +// DefaultCast: core.Cast{ +// GCD: time.Second, +// }, +// IgnoreHaste: true, +// CD: core.Cooldown{ +// Timer: rogue.NewTimer(), +// Duration: cooldownDur, +// }, +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { +// rogue.BreakStealth(sim) +// rogue.BladeFlurryAura.Activate(sim) +// }, +// }) + +// rogue.AddMajorCooldown(core.MajorCooldown{ +// Spell: rogue.BladeFlurry, +// Type: core.CooldownTypeDPS, +// Priority: core.CooldownPriorityDefault, +// ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { +// if sim.GetRemainingDuration() > cooldownDur+dur { +// // We'll have enough time to cast another BF, so use it immediately to make sure we get the 2nd one. +// return true +// } + +// // Since this is our last BF, wait until we have SND / procs up. +// sndTimeRemaining := rogue.SliceAndDiceAura.RemainingDuration(sim) +// // TODO: Wait for dst/mongoose procs +// return sndTimeRemaining >= time.Second +// }, +// }) +// } + +// var AdrenalineRushActionID = core.ActionID{SpellID: 13750} + +// func (rogue *Rogue) registerAdrenalineRushCD() { +// if !rogue.Talents.AdrenalineRush { +// return +// } + +// rogue.AdrenalineRushAura = rogue.RegisterAura(core.Aura{ +// Label: "Adrenaline Rush", +// ActionID: AdrenalineRushActionID, +// Duration: core.TernaryDuration(rogue.HasMajorGlyph(proto.RogueMajorGlyph_GlyphOfAdrenalineRush), time.Second*20, time.Second*15), +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// rogue.ResetEnergyTick(sim) +// rogue.ApplyEnergyTickMultiplier(1.0) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// rogue.ResetEnergyTick(sim) +// rogue.ApplyEnergyTickMultiplier(-1.0) +// }, +// }) + +// adrenalineRushSpell := rogue.RegisterSpell(core.SpellConfig{ +// ActionID: AdrenalineRushActionID, + +// Cast: core.CastConfig{ +// DefaultCast: core.Cast{ +// GCD: time.Second, +// }, +// IgnoreHaste: true, +// CD: core.Cooldown{ +// Timer: rogue.NewTimer(), +// Duration: time.Minute * 3, +// }, +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { +// rogue.BreakStealth(sim) +// rogue.AdrenalineRushAura.Activate(sim) +// }, +// }) + +// rogue.AddMajorCooldown(core.MajorCooldown{ +// Spell: adrenalineRushSpell, +// Type: core.CooldownTypeDPS, +// Priority: core.CooldownPriorityBloodlust, +// ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { +// thresh := 45.0 +// return rogue.CurrentEnergy() <= thresh +// }, +// }) +// } + +// func (rogue *Rogue) registerKillingSpreeCD() { +// if !rogue.Talents.KillingSpree { +// return +// } +// rogue.registerKillingSpreeSpell() +// } + +// func (rogue *Rogue) registerHonorAmongThieves() { +// // When anyone in your group critically hits with a damage or healing spell or ability, +// // you have a [33%/66%/100%] chance to gain a combo point on your current target. +// // This effect cannot occur more than once per second. +// if rogue.Talents.HonorAmongThieves == 0 { +// return +// } + +// procChance := []float64{0, 0.33, 0.66, 1}[rogue.Talents.HonorAmongThieves] +// comboMetrics := rogue.NewComboPointMetrics(core.ActionID{SpellID: 51701}) +// honorAmongThievesID := core.ActionID{SpellID: 51701} + +// icd := core.Cooldown{ +// Timer: rogue.NewTimer(), +// Duration: time.Second, +// } + +// maybeProc := func(sim *core.Simulation) { +// if icd.IsReady(sim) && sim.Proc(procChance, "honor of thieves") { +// rogue.AddComboPoints(sim, 1, comboMetrics) +// icd.Use(sim) +// } +// } + +// rogue.HonorAmongThieves = rogue.RegisterAura(core.Aura{ +// Label: "Honor Among Thieves", +// ActionID: honorAmongThievesID, +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnGain: func(_ *core.Aura, sim *core.Simulation) { +// // In an ideal party, you'd probably get up to 6 ability crits/s (Rate = 600). +// // Survival Hunters, Enhancement Shamans, and Assassination Rogues are particularly good. +// if rogue.SubtletyOptions.HonorAmongThievesCritRate <= 0 { +// return +// } + +// if rogue.SubtletyOptions.HonorAmongThievesCritRate > 2000 { +// rogue.SubtletyOptions.HonorAmongThievesCritRate = 2000 // limited, so performance doesn't suffer +// } + +// rateToDuration := float64(time.Second) * 100 / float64(rogue.SubtletyOptions.HonorAmongThievesCritRate) + +// pa := &core.PendingAction{} +// pa.OnAction = func(sim *core.Simulation) { +// maybeProc(sim) +// pa.NextActionAt = sim.CurrentTime + time.Duration(sim.RandomExpFloat("next party crit")*rateToDuration) +// sim.AddPendingAction(pa) +// } +// pa.NextActionAt = sim.CurrentTime + time.Duration(sim.RandomExpFloat("next party crit")*rateToDuration) +// sim.AddPendingAction(pa) +// }, +// OnSpellHitDealt: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.DidCrit() && !spell.ProcMask.Matches(core.ProcMaskMeleeMHAuto|core.ProcMaskMeleeOHAuto|core.ProcMaskRangedAuto) { +// maybeProc(sim) +// } +// }, +// OnPeriodicDamageDealt: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.DidCrit() { +// maybeProc(sim) +// } +// }, +// }) +// } diff --git a/sim/shaman/apl_values.go b/sim/shaman/_apl_values.go similarity index 100% rename from sim/shaman/apl_values.go rename to sim/shaman/_apl_values.go diff --git a/sim/shaman/bloodlust.go b/sim/shaman/_bloodlust.go similarity index 100% rename from sim/shaman/bloodlust.go rename to sim/shaman/_bloodlust.go diff --git a/sim/shaman/chain_lightning.go b/sim/shaman/_chain_lightning.go similarity index 100% rename from sim/shaman/chain_lightning.go rename to sim/shaman/_chain_lightning.go diff --git a/sim/shaman/electric_spell.go b/sim/shaman/_electric_spell.go similarity index 100% rename from sim/shaman/electric_spell.go rename to sim/shaman/_electric_spell.go diff --git a/sim/shaman/feral_spirit.go b/sim/shaman/_feral_spirit.go similarity index 100% rename from sim/shaman/feral_spirit.go rename to sim/shaman/_feral_spirit.go diff --git a/sim/shaman/fire_elemental_pet.go b/sim/shaman/_fire_elemental_pet.go similarity index 100% rename from sim/shaman/fire_elemental_pet.go rename to sim/shaman/_fire_elemental_pet.go diff --git a/sim/shaman/fire_elemental_spells.go b/sim/shaman/_fire_elemental_spells.go similarity index 100% rename from sim/shaman/fire_elemental_spells.go rename to sim/shaman/_fire_elemental_spells.go diff --git a/sim/shaman/fire_elemental_totem.go b/sim/shaman/_fire_elemental_totem.go similarity index 100% rename from sim/shaman/fire_elemental_totem.go rename to sim/shaman/_fire_elemental_totem.go diff --git a/sim/shaman/fire_totems.go b/sim/shaman/_fire_totems.go similarity index 100% rename from sim/shaman/fire_totems.go rename to sim/shaman/_fire_totems.go diff --git a/sim/shaman/firenova.go b/sim/shaman/_firenova.go similarity index 100% rename from sim/shaman/firenova.go rename to sim/shaman/_firenova.go diff --git a/sim/shaman/heals.go b/sim/shaman/_heals.go similarity index 100% rename from sim/shaman/heals.go rename to sim/shaman/_heals.go diff --git a/sim/shaman/items.go b/sim/shaman/_items.go similarity index 100% rename from sim/shaman/items.go rename to sim/shaman/_items.go diff --git a/sim/shaman/items_wotlk.go b/sim/shaman/_items_wotlk.go similarity index 100% rename from sim/shaman/items_wotlk.go rename to sim/shaman/_items_wotlk.go diff --git a/sim/shaman/lavaburst.go b/sim/shaman/_lavaburst.go similarity index 100% rename from sim/shaman/lavaburst.go rename to sim/shaman/_lavaburst.go diff --git a/sim/shaman/lavalash.go b/sim/shaman/_lavalash.go similarity index 100% rename from sim/shaman/lavalash.go rename to sim/shaman/_lavalash.go diff --git a/sim/shaman/lightning_bolt.go b/sim/shaman/_lightning_bolt.go similarity index 100% rename from sim/shaman/lightning_bolt.go rename to sim/shaman/_lightning_bolt.go diff --git a/sim/shaman/lightning_shield.go b/sim/shaman/_lightning_shield.go similarity index 100% rename from sim/shaman/lightning_shield.go rename to sim/shaman/_lightning_shield.go diff --git a/sim/shaman/shamanistic_rage.go b/sim/shaman/_shamanistic_rage.go similarity index 100% rename from sim/shaman/shamanistic_rage.go rename to sim/shaman/_shamanistic_rage.go diff --git a/sim/shaman/shocks.go b/sim/shaman/_shocks.go similarity index 100% rename from sim/shaman/shocks.go rename to sim/shaman/_shocks.go diff --git a/sim/shaman/spirit_wolves.go b/sim/shaman/_spirit_wolves.go similarity index 100% rename from sim/shaman/spirit_wolves.go rename to sim/shaman/_spirit_wolves.go diff --git a/sim/shaman/stormstrike.go b/sim/shaman/_stormstrike.go similarity index 100% rename from sim/shaman/stormstrike.go rename to sim/shaman/_stormstrike.go diff --git a/sim/shaman/thunderstorm.go b/sim/shaman/_thunderstorm.go similarity index 100% rename from sim/shaman/thunderstorm.go rename to sim/shaman/_thunderstorm.go diff --git a/sim/shaman/totems.go b/sim/shaman/_totems.go similarity index 100% rename from sim/shaman/totems.go rename to sim/shaman/_totems.go diff --git a/sim/shaman/weapon_imbues.go b/sim/shaman/_weapon_imbues.go similarity index 100% rename from sim/shaman/weapon_imbues.go rename to sim/shaman/_weapon_imbues.go diff --git a/sim/shaman/elemental/elemental.go b/sim/shaman/elemental/elemental.go index 678d9d2598..9c76830e85 100644 --- a/sim/shaman/elemental/elemental.go +++ b/sim/shaman/elemental/elemental.go @@ -40,25 +40,25 @@ func NewElementalShaman(character *core.Character, options *proto.Player) *Eleme Shaman: shaman.NewShaman(character, options.TalentsString, totems, selfBuffs, inRange), } - if mh := ele.GetMHWeapon(); mh != nil { - ele.ApplyFlametongueImbueToItem(mh, false) - } + // if mh := ele.GetMHWeapon(); mh != nil { + // ele.ApplyFlametongueImbueToItem(mh, false) + // } - if oh := ele.GetOHWeapon(); oh != nil { - ele.ApplyFlametongueImbueToItem(oh, false) - } + // if oh := ele.GetOHWeapon(); oh != nil { + // ele.ApplyFlametongueImbueToItem(oh, false) + // } - if ele.Talents.FeralSpirit { - // Enable Auto Attacks but don't enable auto swinging - ele.EnableAutoAttacks(ele, core.AutoAttackOptions{ - MainHand: ele.WeaponFromMainHand(ele.DefaultMeleeCritMultiplier()), - OffHand: ele.WeaponFromOffHand(ele.DefaultMeleeCritMultiplier()), - }) - ele.SpiritWolves = &shaman.SpiritWolves{ - SpiritWolf1: ele.NewSpiritWolf(1), - SpiritWolf2: ele.NewSpiritWolf(2), - } - } + // if ele.Talents.FeralSpirit { + // // Enable Auto Attacks but don't enable auto swinging + // ele.EnableAutoAttacks(ele, core.AutoAttackOptions{ + // MainHand: ele.WeaponFromMainHand(ele.DefaultMeleeCritMultiplier()), + // OffHand: ele.WeaponFromOffHand(ele.DefaultMeleeCritMultiplier()), + // }) + // // ele.SpiritWolves = &shaman.SpiritWolves{ + // // SpiritWolf1: ele.NewSpiritWolf(1), + // // SpiritWolf2: ele.NewSpiritWolf(2), + // // } + // } return ele } diff --git a/sim/shaman/enhancement/enhancement.go b/sim/shaman/enhancement/enhancement.go index ebcf670aab..61d085ba73 100644 --- a/sim/shaman/enhancement/enhancement.go +++ b/sim/shaman/enhancement/enhancement.go @@ -43,29 +43,29 @@ func NewEnhancementShaman(character *core.Character, options *proto.Player) *Enh Shaman: shaman.NewShaman(character, options.TalentsString, totems, selfBuffs, true), } - // Enable Auto Attacks for this spec - enh.EnableAutoAttacks(enh, core.AutoAttackOptions{ - MainHand: enh.WeaponFromMainHand(enh.DefaultMeleeCritMultiplier()), - OffHand: enh.WeaponFromOffHand(enh.DefaultMeleeCritMultiplier()), - AutoSwingMelee: true, - }) - - enh.ApplySyncType(enhOptions.SyncType) - enh.ApplyFlametongueImbue(enh.getImbueProcMask(proto.ShamanImbue_FlametongueWeapon), false) - enh.ApplyFlametongueImbue(enh.getImbueProcMask(proto.ShamanImbue_FlametongueWeaponDownrank), true) - - if !enh.HasMHWeapon() { - enh.SelfBuffs.ImbueMH = proto.ShamanImbue_NoImbue - } - - if !enh.HasOHWeapon() { - enh.SelfBuffs.ImbueOH = proto.ShamanImbue_NoImbue - } - - enh.SpiritWolves = &shaman.SpiritWolves{ - SpiritWolf1: enh.NewSpiritWolf(1), - SpiritWolf2: enh.NewSpiritWolf(2), - } + // // Enable Auto Attacks for this spec + // enh.EnableAutoAttacks(enh, core.AutoAttackOptions{ + // MainHand: enh.WeaponFromMainHand(enh.DefaultMeleeCritMultiplier()), + // OffHand: enh.WeaponFromOffHand(enh.DefaultMeleeCritMultiplier()), + // AutoSwingMelee: true, + // }) + + // enh.ApplySyncType(enhOptions.SyncType) + // enh.ApplyFlametongueImbue(enh.getImbueProcMask(proto.ShamanImbue_FlametongueWeapon), false) + // enh.ApplyFlametongueImbue(enh.getImbueProcMask(proto.ShamanImbue_FlametongueWeaponDownrank), true) + + // if !enh.HasMHWeapon() { + // enh.SelfBuffs.ImbueMH = proto.ShamanImbue_NoImbue + // } + + // if !enh.HasOHWeapon() { + // enh.SelfBuffs.ImbueOH = proto.ShamanImbue_NoImbue + // } + + // enh.SpiritWolves = &shaman.SpiritWolves{ + // SpiritWolf1: enh.NewSpiritWolf(1), + // SpiritWolf2: enh.NewSpiritWolf(2), + // } return enh } @@ -91,21 +91,21 @@ func (enh *EnhancementShaman) GetShaman() *shaman.Shaman { func (enh *EnhancementShaman) Initialize() { enh.Shaman.Initialize() - // In the Initialize due to frost brand adding the aura to the enemy - enh.RegisterFrostbrandImbue(enh.getImbueProcMask(proto.ShamanImbue_FrostbrandWeapon)) - enh.RegisterFlametongueImbue(enh.getImbueProcMask(proto.ShamanImbue_FlametongueWeapon), false) - enh.RegisterFlametongueImbue(enh.getImbueProcMask(proto.ShamanImbue_FlametongueWeaponDownrank), true) - enh.RegisterWindfuryImbue(enh.getImbueProcMask(proto.ShamanImbue_WindfuryWeapon)) - - if enh.ItemSwap.IsEnabled() { - mh := enh.ItemSwap.GetItem(proto.ItemSlot_ItemSlotMainHand) - enh.ApplyFlametongueImbueToItem(mh, true) - oh := enh.ItemSwap.GetItem(proto.ItemSlot_ItemSlotOffHand) - enh.ApplyFlametongueImbueToItem(oh, false) - enh.RegisterOnItemSwap(func(_ *core.Simulation) { - enh.ApplySyncType(proto.ShamanSyncType_Auto) - }) - } + // // In the Initialize due to frost brand adding the aura to the enemy + // enh.RegisterFrostbrandImbue(enh.getImbueProcMask(proto.ShamanImbue_FrostbrandWeapon)) + // enh.RegisterFlametongueImbue(enh.getImbueProcMask(proto.ShamanImbue_FlametongueWeapon), false) + // enh.RegisterFlametongueImbue(enh.getImbueProcMask(proto.ShamanImbue_FlametongueWeaponDownrank), true) + // enh.RegisterWindfuryImbue(enh.getImbueProcMask(proto.ShamanImbue_WindfuryWeapon)) + + // if enh.ItemSwap.IsEnabled() { + // mh := enh.ItemSwap.GetItem(proto.ItemSlot_ItemSlotMainHand) + // enh.ApplyFlametongueImbueToItem(mh, true) + // oh := enh.ItemSwap.GetItem(proto.ItemSlot_ItemSlotOffHand) + // enh.ApplyFlametongueImbueToItem(oh, false) + // enh.RegisterOnItemSwap(func(_ *core.Simulation) { + // enh.ApplySyncType(proto.ShamanSyncType_Auto) + // }) + // } } func (enh *EnhancementShaman) Reset(sim *core.Simulation) { diff --git a/sim/shaman/restoration/restoration.go b/sim/shaman/restoration/restoration.go index 6a657718dc..4053f1861d 100644 --- a/sim/shaman/restoration/restoration.go +++ b/sim/shaman/restoration/restoration.go @@ -39,12 +39,12 @@ func NewRestorationShaman(character *core.Character, options *proto.Player) *Res Shaman: shaman.NewShaman(character, options.TalentsString, totems, selfBuffs, false), } - if resto.HasMHWeapon() { - resto.ApplyEarthlivingImbueToItem(resto.GetMHWeapon()) - } - if resto.HasOHWeapon() { - resto.ApplyEarthlivingImbueToItem(resto.GetOHWeapon()) - } + // if resto.HasMHWeapon() { + // resto.ApplyEarthlivingImbueToItem(resto.GetMHWeapon()) + // } + // if resto.HasOHWeapon() { + // resto.ApplyEarthlivingImbueToItem(resto.GetOHWeapon()) + // } return resto } @@ -71,17 +71,17 @@ func (resto *RestorationShaman) GetMainTarget() *core.Unit { } func (resto *RestorationShaman) Initialize() { - resto.CurrentTarget = resto.GetMainTarget() + // resto.CurrentTarget = resto.GetMainTarget() - // Has to be here because earthliving can cast hots and needs Env to be set to create the hots. - procMask := core.ProcMaskUnknown - if resto.HasMHWeapon() { - procMask |= core.ProcMaskMeleeMH - } - if resto.HasOHWeapon() { - procMask |= core.ProcMaskMeleeOH - } - resto.RegisterEarthlivingImbue(procMask) + // // Has to be here because earthliving can cast hots and needs Env to be set to create the hots. + // procMask := core.ProcMaskUnknown + // if resto.HasMHWeapon() { + // procMask |= core.ProcMaskMeleeMH + // } + // if resto.HasOHWeapon() { + // procMask |= core.ProcMaskMeleeOH + // } + // resto.RegisterEarthlivingImbue(procMask) resto.Shaman.Initialize() resto.Shaman.RegisterHealingSpells() diff --git a/sim/shaman/shaman.go b/sim/shaman/shaman.go index abb6435c11..404b0ad0f6 100644 --- a/sim/shaman/shaman.go +++ b/sim/shaman/shaman.go @@ -5,7 +5,6 @@ import ( "github.com/wowsims/cata/sim/core" "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" ) var TalentTreeSizes = [3]int{25, 29, 26} @@ -28,33 +27,33 @@ func NewShaman(character *core.Character, talents string, totems *proto.ShamanTo SelfBuffs: selfBuffs, thunderstormInRange: thunderstormRange, } - shaman.waterShieldManaMetrics = shaman.NewManaMetrics(core.ActionID{SpellID: 57960}) + // shaman.waterShieldManaMetrics = shaman.NewManaMetrics(core.ActionID{SpellID: 57960}) - core.FillTalentsProto(shaman.Talents.ProtoReflect(), talents, TalentTreeSizes) - shaman.EnableManaBar() + // core.FillTalentsProto(shaman.Talents.ProtoReflect(), talents, TalentTreeSizes) + // shaman.EnableManaBar() - if shaman.Totems.Fire == proto.FireTotem_TotemOfWrath && !shaman.Talents.TotemOfWrath { - shaman.Totems.Fire = proto.FireTotem_FlametongueTotem - } + // if shaman.Totems.Fire == proto.FireTotem_TotemOfWrath && !shaman.Talents.TotemOfWrath { + // shaman.Totems.Fire = proto.FireTotem_FlametongueTotem + // } - // Add Shaman stat dependencies - shaman.AddStatDependency(stats.Strength, stats.AttackPower, 1) - shaman.AddStatDependency(stats.Agility, stats.AttackPower, 1) - shaman.AddStatDependency(stats.Agility, stats.MeleeCrit, core.CritPerAgiMaxLevel[character.Class]*core.CritRatingPerCritChance) - shaman.AddStatDependency(stats.BonusArmor, stats.Armor, 1) - // Set proper Melee Haste scaling - shaman.PseudoStats.MeleeHasteRatingPerHastePercent /= 1.3 + // // Add Shaman stat dependencies + // shaman.AddStatDependency(stats.Strength, stats.AttackPower, 1) + // shaman.AddStatDependency(stats.Agility, stats.AttackPower, 1) + // shaman.AddStatDependency(stats.Agility, stats.MeleeCrit, core.CritPerAgiMaxLevel[character.Class]*core.CritRatingPerCritChance) + // shaman.AddStatDependency(stats.BonusArmor, stats.Armor, 1) + // // Set proper Melee Haste scaling + // shaman.PseudoStats.MeleeHasteRatingPerHastePercent /= 1.3 - if selfBuffs.Shield == proto.ShamanShield_WaterShield { - shaman.AddStat(stats.MP5, 100) - } + // if selfBuffs.Shield == proto.ShamanShield_WaterShield { + // shaman.AddStat(stats.MP5, 100) + // } - // When using the tier bonus for snapshotting we do not use the bonus spell - if totems.EnhTierTenBonus { - totems.BonusSpellpower = 0 - } + // // When using the tier bonus for snapshotting we do not use the bonus spell + // if totems.EnhTierTenBonus { + // totems.BonusSpellpower = 0 + // } - shaman.FireElemental = shaman.NewFireElemental(float64(totems.BonusSpellpower)) + // //shaman.FireElemental = shaman.NewFireElemental(float64(totems.BonusSpellpower)) return shaman } @@ -109,9 +108,9 @@ type Shaman struct { FrostShock *core.Spell FeralSpirit *core.Spell - SpiritWolves *SpiritWolves + //SpiritWolves *SpiritWolves - FireElemental *FireElemental + //FireElemental *FireElemental FireElementalTotem *core.Spell MagmaTotem *core.Spell @@ -163,53 +162,53 @@ func (shaman *Shaman) HasMinorGlyph(glyph proto.ShamanMinorGlyph) bool { } func (shaman *Shaman) AddRaidBuffs(raidBuffs *proto.RaidBuffs) { - switch shaman.Totems.Fire { - case proto.FireTotem_TotemOfWrath: - raidBuffs.TotemOfWrath = true - case proto.FireTotem_FlametongueTotem: - raidBuffs.FlametongueTotem = true - } - - switch shaman.Totems.Water { - case proto.WaterTotem_ManaSpringTotem: - raidBuffs.ManaSpringTotem = max(raidBuffs.ManaSpringTotem, proto.TristateEffect_TristateEffectRegular) - if shaman.Talents.RestorativeTotems == 5 { - raidBuffs.ManaSpringTotem = proto.TristateEffect_TristateEffectImproved - } - } - - switch shaman.Totems.Air { - case proto.AirTotem_WrathOfAirTotem: - raidBuffs.WrathOfAirTotem = true - case proto.AirTotem_WindfuryTotem: - wfVal := proto.TristateEffect_TristateEffectRegular - if shaman.Talents.ImprovedWindfuryTotem > 0 { - wfVal = proto.TristateEffect_TristateEffectImproved - } - raidBuffs.WindfuryTotem = max(wfVal, raidBuffs.WindfuryTotem) - } - - switch shaman.Totems.Earth { - case proto.EarthTotem_StrengthOfEarthTotem: - totem := proto.TristateEffect_TristateEffectRegular - if shaman.Talents.EnhancingTotems == 3 { - totem = proto.TristateEffect_TristateEffectImproved - } - raidBuffs.StrengthOfEarthTotem = max(raidBuffs.StrengthOfEarthTotem, totem) - case proto.EarthTotem_StoneskinTotem: - raidBuffs.StoneskinTotem = max(raidBuffs.StoneskinTotem, core.MakeTristateValue( - true, - shaman.Talents.GuardianTotems == 2, - )) - } - - if shaman.Talents.UnleashedRage > 0 { - raidBuffs.UnleashedRage = true - } - - if shaman.Talents.ElementalOath > 0 { - raidBuffs.ElementalOath = true - } + // switch shaman.Totems.Fire { + // case proto.FireTotem_TotemOfWrath: + // raidBuffs.TotemOfWrath = true + // case proto.FireTotem_FlametongueTotem: + // raidBuffs.FlametongueTotem = true + // } + + // switch shaman.Totems.Water { + // case proto.WaterTotem_ManaSpringTotem: + // raidBuffs.ManaSpringTotem = max(raidBuffs.ManaSpringTotem, proto.TristateEffect_TristateEffectRegular) + // if shaman.Talents.RestorativeTotems == 5 { + // raidBuffs.ManaSpringTotem = proto.TristateEffect_TristateEffectImproved + // } + // } + + // switch shaman.Totems.Air { + // case proto.AirTotem_WrathOfAirTotem: + // raidBuffs.WrathOfAirTotem = true + // case proto.AirTotem_WindfuryTotem: + // wfVal := proto.TristateEffect_TristateEffectRegular + // if shaman.Talents.ImprovedWindfuryTotem > 0 { + // wfVal = proto.TristateEffect_TristateEffectImproved + // } + // raidBuffs.WindfuryTotem = max(wfVal, raidBuffs.WindfuryTotem) + // } + + // switch shaman.Totems.Earth { + // case proto.EarthTotem_StrengthOfEarthTotem: + // totem := proto.TristateEffect_TristateEffectRegular + // if shaman.Talents.EnhancingTotems == 3 { + // totem = proto.TristateEffect_TristateEffectImproved + // } + // raidBuffs.StrengthOfEarthTotem = max(raidBuffs.StrengthOfEarthTotem, totem) + // case proto.EarthTotem_StoneskinTotem: + // raidBuffs.StoneskinTotem = max(raidBuffs.StoneskinTotem, core.MakeTristateValue( + // true, + // shaman.Talents.GuardianTotems == 2, + // )) + // } + + // if shaman.Talents.UnleashedRage > 0 { + // raidBuffs.UnleashedRage = true + // } + + // if shaman.Talents.ElementalOath > 0 { + // raidBuffs.ElementalOath = true + // } } func (shaman *Shaman) AddPartyBuffs(partyBuffs *proto.PartyBuffs) { if shaman.Talents.ManaTideTotem { @@ -220,73 +219,73 @@ func (shaman *Shaman) AddPartyBuffs(partyBuffs *proto.PartyBuffs) { } func (shaman *Shaman) Initialize() { - shaman.registerChainLightningSpell() - shaman.registerFeralSpirit() - shaman.registerFireElementalTotem() - shaman.registerFireNovaSpell() - shaman.registerLavaBurstSpell() - shaman.registerLavaLashSpell() - shaman.registerLightningBoltSpell() - shaman.registerLightningShieldSpell() - shaman.registerMagmaTotemSpell() - shaman.registerManaSpringTotemSpell() - shaman.registerHealingStreamTotemSpell() - shaman.registerSearingTotemSpell() - shaman.registerShocks() - shaman.registerStormstrikeSpell() - shaman.registerStrengthOfEarthTotemSpell() - shaman.registerThunderstormSpell() - shaman.registerTotemOfWrathSpell() - shaman.registerFlametongueTotemSpell() - shaman.registerTremorTotemSpell() - shaman.registerStoneskinTotemSpell() - shaman.registerWindfuryTotemSpell() - shaman.registerWrathOfAirTotemSpell() - - // This registration must come after all the totems are registered - shaman.registerCallOfTheElements() - - shaman.registerBloodlustCD() - - shaman.NewTemporaryStatsAura("DC Pre-Pull SP Proc", core.ActionID{SpellID: 60494}, stats.Stats{stats.SpellPower: 765}, time.Second*10) + // shaman.registerChainLightningSpell() + // shaman.registerFeralSpirit() + // shaman.registerFireElementalTotem() + // shaman.registerFireNovaSpell() + // shaman.registerLavaBurstSpell() + // shaman.registerLavaLashSpell() + // shaman.registerLightningBoltSpell() + // shaman.registerLightningShieldSpell() + // shaman.registerMagmaTotemSpell() + // shaman.registerManaSpringTotemSpell() + // shaman.registerHealingStreamTotemSpell() + // shaman.registerSearingTotemSpell() + // shaman.registerShocks() + // shaman.registerStormstrikeSpell() + // shaman.registerStrengthOfEarthTotemSpell() + // shaman.registerThunderstormSpell() + // shaman.registerTotemOfWrathSpell() + // shaman.registerFlametongueTotemSpell() + // shaman.registerTremorTotemSpell() + // shaman.registerStoneskinTotemSpell() + // shaman.registerWindfuryTotemSpell() + // shaman.registerWrathOfAirTotemSpell() + + // // This registration must come after all the totems are registered + // shaman.registerCallOfTheElements() + + // shaman.registerBloodlustCD() + + // shaman.NewTemporaryStatsAura("DC Pre-Pull SP Proc", core.ActionID{SpellID: 60494}, stats.Stats{stats.SpellPower: 765}, time.Second*10) } func (shaman *Shaman) RegisterHealingSpells() { - shaman.registerAncestralHealingSpell() - shaman.registerLesserHealingWaveSpell() - shaman.registerHealingWaveSpell() - shaman.registerRiptideSpell() - shaman.registerEarthShieldSpell() - shaman.registerChainHealSpell() - - if shaman.Talents.TidalWaves > 0 { - shaman.tidalWaveProc = shaman.GetOrRegisterAura(core.Aura{ - Label: "Tidal Wave Proc", - ActionID: core.ActionID{SpellID: 53390}, - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Deactivate(sim) - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - shaman.HealingWave.CastTimeMultiplier *= 0.7 - shaman.LesserHealingWave.BonusCritRating += core.CritRatingPerCritChance * 25 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - shaman.HealingWave.CastTimeMultiplier /= 0.7 - shaman.LesserHealingWave.BonusCritRating -= core.CritRatingPerCritChance * 25 - }, - MaxStacks: 2, - }) - } + // shaman.registerAncestralHealingSpell() + // shaman.registerLesserHealingWaveSpell() + // shaman.registerHealingWaveSpell() + // shaman.registerRiptideSpell() + // shaman.registerEarthShieldSpell() + // shaman.registerChainHealSpell() + + // if shaman.Talents.TidalWaves > 0 { + // shaman.tidalWaveProc = shaman.GetOrRegisterAura(core.Aura{ + // Label: "Tidal Wave Proc", + // ActionID: core.ActionID{SpellID: 53390}, + // Duration: core.NeverExpires, + // OnReset: func(aura *core.Aura, sim *core.Simulation) { + // aura.Deactivate(sim) + // }, + // OnGain: func(aura *core.Aura, sim *core.Simulation) { + // shaman.HealingWave.CastTimeMultiplier *= 0.7 + // shaman.LesserHealingWave.BonusCritRating += core.CritRatingPerCritChance * 25 + // }, + // OnExpire: func(aura *core.Aura, sim *core.Simulation) { + // shaman.HealingWave.CastTimeMultiplier /= 0.7 + // shaman.LesserHealingWave.BonusCritRating -= core.CritRatingPerCritChance * 25 + // }, + // MaxStacks: 2, + // }) + // } } func (shaman *Shaman) Reset(sim *core.Simulation) { - if shaman.Totems.Fire == proto.FireTotem_TotemOfWrath { - shaman.applyToWDebuff(sim) - } + // if shaman.Totems.Fire == proto.FireTotem_TotemOfWrath { + // shaman.applyToWDebuff(sim) + // } } -func (shaman *Shaman) ElementalCritMultiplier(secondary float64) float64 { - critBonus := 0.2*float64(shaman.Talents.ElementalFury) + secondary - return shaman.SpellCritMultiplier(1, critBonus) -} +// func (shaman *Shaman) ElementalCritMultiplier(secondary float64) float64 { +// critBonus := 0.2*float64(shaman.Talents.ElementalFury) + secondary +// return shaman.SpellCritMultiplier(1, critBonus) +// } diff --git a/sim/shaman/talents.go b/sim/shaman/talents.go index e8a04fa928..67e8ec90f6 100644 --- a/sim/shaman/talents.go +++ b/sim/shaman/talents.go @@ -1,497 +1,489 @@ package shaman -import ( - "time" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" -) - func (shaman *Shaman) ApplyTalents() { // We are going to treat this like a snapshot if you have the glyph. - if shaman.HasMajorGlyph(proto.ShamanMajorGlyph_GlyphOfTotemOfWrath) { - shaman.AddStat(stats.SpellPower, 280*0.3) - } - - shaman.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*1*float64(shaman.Talents.ThunderingStrikes)) - shaman.AddStat(stats.SpellCrit, core.CritRatingPerCritChance*1*float64(shaman.Talents.ThunderingStrikes)) - shaman.AddStat(stats.Dodge, core.DodgeRatingPerDodgeChance*1*float64(shaman.Talents.Anticipation)) - shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= []float64{1, 1.04, 1.07, 1.1}[shaman.Talents.WeaponMastery] - - shaman.AddStat(stats.Expertise, 3*core.ExpertisePerQuarterPercentReduction*float64(shaman.Talents.UnleashedRage)) - - if shaman.Talents.DualWieldSpecialization > 0 && shaman.HasOHWeapon() { - shaman.AddStat(stats.MeleeHit, core.MeleeHitRatingPerHitChance*2*float64(shaman.Talents.DualWieldSpecialization)) - } - - shaman.AddStat(stats.SpellCrit, float64(shaman.Talents.BlessingOfTheEternals)*2*core.CritRatingPerCritChance) - if shaman.Talents.Toughness > 0 { - shaman.MultiplyStat(stats.Stamina, 1.0+0.02*float64(shaman.Talents.Toughness)) - } - if shaman.Talents.UnrelentingStorm > 0 { - shaman.AddStatDependency(stats.Intellect, stats.MP5, 0.04*float64(shaman.Talents.UnrelentingStorm)) - } - if shaman.Talents.AncestralKnowledge > 0 { - shaman.MultiplyStat(stats.Intellect, 1.0+0.02*float64(shaman.Talents.AncestralKnowledge)) - } - if shaman.Talents.MentalQuickness > 0 { - shaman.AddStatDependency(stats.AttackPower, stats.SpellPower, 0.1*float64(shaman.Talents.MentalQuickness)) - } - if shaman.Talents.MentalDexterity > 0 { - shaman.AddStatDependency(stats.Intellect, stats.AttackPower, []float64{0, 0.33, 0.66, 1}[shaman.Talents.MentalDexterity]) - } - if shaman.Talents.NaturesBlessing > 0 { - shaman.AddStatDependency(stats.Intellect, stats.SpellPower, 0.1*float64(shaman.Talents.NaturesBlessing)) - } - - if shaman.Talents.SpiritWeapons { - shaman.PseudoStats.ThreatMultiplier *= 0.7 - shaman.PseudoStats.CanParry = true - } - - shaman.applyElementalFocus() - shaman.applyElementalDevastation() - shaman.applyFlurry() - shaman.applyMaelstromWeapon() - shaman.registerElementalMasteryCD() - shaman.registerNaturesSwiftnessCD() - shaman.registerShamanisticRageCD() - shaman.registerManaTideTotemCD() + // if shaman.HasMajorGlyph(proto.ShamanMajorGlyph_GlyphOfTotemOfWrath) { + // shaman.AddStat(stats.SpellPower, 280*0.3) + // } + + // shaman.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*1*float64(shaman.Talents.ThunderingStrikes)) + // shaman.AddStat(stats.SpellCrit, core.CritRatingPerCritChance*1*float64(shaman.Talents.ThunderingStrikes)) + // shaman.AddStat(stats.Dodge, core.DodgeRatingPerDodgeChance*1*float64(shaman.Talents.Anticipation)) + // shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= []float64{1, 1.04, 1.07, 1.1}[shaman.Talents.WeaponMastery] + + // shaman.AddStat(stats.Expertise, 3*core.ExpertisePerQuarterPercentReduction*float64(shaman.Talents.UnleashedRage)) + + // if shaman.Talents.DualWieldSpecialization > 0 && shaman.HasOHWeapon() { + // shaman.AddStat(stats.MeleeHit, core.MeleeHitRatingPerHitChance*2*float64(shaman.Talents.DualWieldSpecialization)) + // } + + // shaman.AddStat(stats.SpellCrit, float64(shaman.Talents.BlessingOfTheEternals)*2*core.CritRatingPerCritChance) + // if shaman.Talents.Toughness > 0 { + // shaman.MultiplyStat(stats.Stamina, 1.0+0.02*float64(shaman.Talents.Toughness)) + // } + // if shaman.Talents.UnrelentingStorm > 0 { + // shaman.AddStatDependency(stats.Intellect, stats.MP5, 0.04*float64(shaman.Talents.UnrelentingStorm)) + // } + // if shaman.Talents.AncestralKnowledge > 0 { + // shaman.MultiplyStat(stats.Intellect, 1.0+0.02*float64(shaman.Talents.AncestralKnowledge)) + // } + // if shaman.Talents.MentalQuickness > 0 { + // shaman.AddStatDependency(stats.AttackPower, stats.SpellPower, 0.1*float64(shaman.Talents.MentalQuickness)) + // } + // if shaman.Talents.MentalDexterity > 0 { + // shaman.AddStatDependency(stats.Intellect, stats.AttackPower, []float64{0, 0.33, 0.66, 1}[shaman.Talents.MentalDexterity]) + // } + // if shaman.Talents.NaturesBlessing > 0 { + // shaman.AddStatDependency(stats.Intellect, stats.SpellPower, 0.1*float64(shaman.Talents.NaturesBlessing)) + // } + + // if shaman.Talents.SpiritWeapons { + // shaman.PseudoStats.ThreatMultiplier *= 0.7 + // shaman.PseudoStats.CanParry = true + // } + + // shaman.applyElementalFocus() + // shaman.applyElementalDevastation() + // shaman.applyFlurry() + // shaman.applyMaelstromWeapon() + // shaman.registerElementalMasteryCD() + // shaman.registerNaturesSwiftnessCD() + // shaman.registerShamanisticRageCD() + // shaman.registerManaTideTotemCD() } -func (shaman *Shaman) spellThreatMultiplier() float64 { - return []float64{1, 0.9, 0.8, 0.7}[shaman.Talents.ElementalPrecision] -} - -func (shaman *Shaman) applyElementalFocus() { - if !shaman.Talents.ElementalFocus { - return - } - - oathBonus := 1 + (0.05 * float64(shaman.Talents.ElementalOath)) - var affectedSpells []*core.Spell - - // TODO: fix this. - // Right now: Set to 3 so that the spell that cast it consumes a charge down to expected 2. - // Correct fix would be to figure out how to make 'onCastComplete' fire before 'onspellhitdealt' without breaking all the other things. - maxStacks := int32(3) - - clearcastingAura := shaman.RegisterAura(core.Aura{ - Label: "Clearcasting", - ActionID: core.ActionID{SpellID: 16246}, - Duration: time.Second * 15, - MaxStacks: maxStacks, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - affectedSpells = core.FilterSlice([]*core.Spell{ - shaman.LightningBolt, - shaman.ChainLightning, - shaman.LavaBurst, - shaman.FireNova, - shaman.EarthShock, - shaman.FlameShock, - shaman.FrostShock, - }, func(spell *core.Spell) bool { return spell != nil }) - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.CostMultiplier -= 0.4 - } - if oathBonus > 1 { - shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] *= oathBonus - shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= oathBonus - shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFrost] *= oathBonus - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.CostMultiplier += 0.4 - } - if oathBonus > 1 { - shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] /= oathBonus - shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] /= oathBonus - shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFrost] /= oathBonus - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if !spell.Flags.Matches(SpellFlagShock | SpellFlagFocusable) { - return - } - if spell.ActionID.Tag == 6 { // Filter LO casts - return - } - aura.RemoveStack(sim) - }, - }) - - shaman.RegisterAura(core.Aura{ - Label: "Elemental Focus", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.Flags.Matches(SpellFlagShock | SpellFlagFocusable) { - return - } - if !result.Outcome.Matches(core.OutcomeCrit) { - return - } - clearcastingAura.Activate(sim) - clearcastingAura.SetStacks(sim, maxStacks) - }, - }) -} - -func (shaman *Shaman) applyElementalDevastation() { - if shaman.Talents.ElementalDevastation == 0 { - return - } - - critBonus := 3.0 * float64(shaman.Talents.ElementalDevastation) * core.CritRatingPerCritChance - procAura := shaman.NewTemporaryStatsAura("Elemental Devastation Proc", core.ActionID{SpellID: 30160}, stats.Stats{stats.MeleeCrit: critBonus}, time.Second*10) - - shaman.RegisterAura(core.Aura{ - Label: "Elemental Devastation", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskSpellDamage) { - return - } - if !result.Outcome.Matches(core.OutcomeCrit) { - return - } - procAura.Activate(sim) - }, - }) -} - -var eleMasterActionID = core.ActionID{SpellID: 16166} - -func (shaman *Shaman) registerElementalMasteryCD() { - if !shaman.Talents.ElementalMastery { - return - } - - cdTimer := shaman.NewTimer() - cd := time.Minute * 3 - - if shaman.HasMajorGlyph(proto.ShamanMajorGlyph_GlyphOfElementalMastery) { - cd -= time.Second * 30 - } - - // TODO: Share CD with Natures Swiftness - - buffAura := shaman.RegisterAura(core.Aura{ - Label: "Elemental Mastery Haste", - ActionID: core.ActionID{SpellID: 64701}, - Duration: time.Second * 15, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - shaman.MultiplyCastSpeed(1.15) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - shaman.MultiplyCastSpeed(1 / 1.15) - }, - }) - - emAura := shaman.RegisterAura(core.Aura{ - Label: "Elemental Mastery", - ActionID: eleMasterActionID, - Duration: core.NeverExpires, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - shaman.ChainLightning.CastTimeMultiplier -= 1 - shaman.LavaBurst.CastTimeMultiplier -= 1 - shaman.LightningBolt.CastTimeMultiplier -= 1 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - shaman.ChainLightning.CastTimeMultiplier += 1 - shaman.LavaBurst.CastTimeMultiplier += 1 - shaman.LightningBolt.CastTimeMultiplier += 1 - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell != shaman.LightningBolt && spell != shaman.ChainLightning && spell != shaman.LavaBurst { - return - } - // Remove the buff and put skill on CD - aura.Deactivate(sim) - cdTimer.Set(sim.CurrentTime + cd) - shaman.UpdateMajorCooldowns() - }, - }) - - eleMastSpell := shaman.RegisterSpell(core.SpellConfig{ - ActionID: eleMasterActionID, - Flags: core.SpellFlagNoOnCastComplete, - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: cdTimer, - Duration: cd, - }, - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - buffAura.Activate(sim) - emAura.Activate(sim) - }, - }) - - shaman.AddMajorCooldown(core.MajorCooldown{ - Spell: eleMastSpell, - Type: core.CooldownTypeDPS, - }) - - if shaman.HasSetBonus(ItemSetFrostWitchRegalia, 2) { - shaman.RegisterAura(core.Aura{ - Label: "Shaman T10 Elemental 2P Bonus", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if (spell == shaman.LightningBolt || spell == shaman.ChainLightning) && !eleMastSpell.CD.IsReady(sim) { - *eleMastSpell.CD.Timer = core.Timer(time.Duration(*eleMastSpell.CD.Timer) - time.Second*2) - shaman.UpdateMajorCooldowns() // this could get expensive because it will be called all the time. - } - }, - }) - } -} - -func (shaman *Shaman) registerNaturesSwiftnessCD() { - if !shaman.Talents.NaturesSwiftness { - return - } - actionID := core.ActionID{SpellID: 16188} - cdTimer := shaman.NewTimer() - cd := time.Minute * 3 - - nsAura := shaman.RegisterAura(core.Aura{ - Label: "Natures Swiftness", - ActionID: actionID, - Duration: core.NeverExpires, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - shaman.ChainLightning.CastTimeMultiplier -= 1 - shaman.LavaBurst.CastTimeMultiplier -= 1 - shaman.LightningBolt.CastTimeMultiplier -= 1 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - shaman.ChainLightning.CastTimeMultiplier += 1 - shaman.LavaBurst.CastTimeMultiplier += 1 - shaman.LightningBolt.CastTimeMultiplier += 1 - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell != shaman.LightningBolt && spell != shaman.ChainLightning && spell != shaman.LavaBurst { - return - } - - // Remove the buff and put skill on CD - aura.Deactivate(sim) - cdTimer.Set(sim.CurrentTime + cd) - shaman.UpdateMajorCooldowns() - }, - }) - - nsSpell := shaman.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete, - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: cdTimer, - Duration: cd, - }, - }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - // Don't use NS unless we're casting a full-length lightning bolt, which is - // the only spell shamans have with a cast longer than GCD. - return !shaman.HasTemporarySpellCastSpeedIncrease() - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - nsAura.Activate(sim) - }, - }) - - shaman.AddMajorCooldown(core.MajorCooldown{ - Spell: nsSpell, - Type: core.CooldownTypeDPS, - }) -} - -func (shaman *Shaman) applyFlurry() { - if shaman.Talents.Flurry == 0 { - return - } - - bonus := 1.0 + 0.06*float64(shaman.Talents.Flurry) - - if shaman.HasSetBonus(ItemSetEarthshatterBattlegear, 4) { - bonus += 0.05 - } - - inverseBonus := 1 / bonus - - procAura := shaman.RegisterAura(core.Aura{ - Label: "Flurry Proc", - ActionID: core.ActionID{SpellID: 16280}, - Duration: core.NeverExpires, - MaxStacks: 3, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - shaman.MultiplyMeleeSpeed(sim, bonus) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - shaman.MultiplyMeleeSpeed(sim, inverseBonus) - }, - }) - - icd := core.Cooldown{ - Timer: shaman.NewTimer(), - Duration: time.Millisecond * 500, - } - - shaman.RegisterAura(core.Aura{ - Label: "Flurry", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskMelee) { - return - } - - if result.Outcome.Matches(core.OutcomeCrit) { - procAura.Activate(sim) - procAura.SetStacks(sim, 3) - icd.Reset() // the "charge protection" ICD isn't up yet - return - } - - // Remove a stack. - if procAura.IsActive() && spell.ProcMask.Matches(core.ProcMaskMeleeWhiteHit) && icd.IsReady(sim) { - icd.Use(sim) - procAura.RemoveStack(sim) - } - }, - }) -} - -func (shaman *Shaman) applyMaelstromWeapon() { - if shaman.Talents.MaelstromWeapon == 0 { - return - } - - var t10BonusAura *core.Aura - enhT10Bonus := false - if shaman.HasSetBonus(ItemSetFrostWitchBattlegear, 4) { - enhT10Bonus = true - - statDep := shaman.NewDynamicMultiplyStat(stats.AttackPower, 1.2) - t10BonusAura = shaman.RegisterAura(core.Aura{ - Label: "Maelstrom Power", - ActionID: core.ActionID{SpellID: 70831}, - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - shaman.EnableDynamicStatDep(sim, statDep) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - shaman.DisableDynamicStatDep(sim, statDep) - }, - }) - } - - // TODO: Don't forget to make it so that AA don't reset when casting when MW is active - // for LB / CL / LvB - // They can't actually hit while casting, but the AA timer doesnt reset if you cast during the AA timer. - - // For sim purposes maelstrom weapon only impacts CL / LB - shaman.MaelstromWeaponAura = shaman.RegisterAura(core.Aura{ - Label: "MaelstromWeapon Proc", - ActionID: core.ActionID{SpellID: 53817}, - Duration: time.Second * 30, - MaxStacks: 5, - OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { - multDiff := 0.2 * float64(newStacks-oldStacks) - shaman.LightningBolt.CastTimeMultiplier -= multDiff - shaman.ChainLightning.CastTimeMultiplier -= multDiff - - if enhT10Bonus && shaman.MaelstromWeaponAura.GetStacks() == 5 { - if sim.RandomFloat("Maelstrom Power") < 0.15 { - t10BonusAura.Activate(sim) - } - } - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.Flags.Matches(SpellFlagElectric) { - return - } - shaman.MaelstromWeaponAura.Deactivate(sim) - }, - }) - - ppmm := shaman.AutoAttacks.NewPPMManager(core.TernaryFloat64(shaman.HasSetBonus(ItemSetWorldbreakerBattlegear, 4), 2.4, 2.0)* - float64(shaman.Talents.MaelstromWeapon), core.ProcMaskMelee) - // This aura is hidden, just applies stacks of the proc aura. - shaman.RegisterAura(core.Aura{ - Label: "MaelstromWeapon", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() { - return - } - - if ppmm.Proc(sim, spell.ProcMask, "Maelstrom Weapon") { - shaman.MaelstromWeaponAura.Activate(sim) - shaman.MaelstromWeaponAura.AddStack(sim) - } - }, - }) -} - -func (shaman *Shaman) registerManaTideTotemCD() { - if !shaman.Talents.ManaTideTotem { - return - } - - mttAura := core.ManaTideTotemAura(shaman.GetCharacter(), shaman.Index) - mttSpell := shaman.RegisterSpell(core.SpellConfig{ - ActionID: core.ManaTideTotemActionID, - Flags: core.SpellFlagNoOnCastComplete, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: time.Second, - }, - IgnoreHaste: true, - CD: core.Cooldown{ - Timer: shaman.NewTimer(), - Duration: time.Minute * 5, - }, - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - mttAura.Activate(sim) - - // If healing stream is active, cancel it while mana tide is up. - if shaman.HealingStreamTotem.Hot(&shaman.Unit).IsActive() { - for _, agent := range shaman.Party.Players { - shaman.HealingStreamTotem.Hot(&agent.GetCharacter().Unit).Cancel(sim) - } - } - - // TODO: Current water totem buff needs to be removed from party/raid. - if shaman.Totems.Water != proto.WaterTotem_NoWaterTotem { - shaman.TotemExpirations[WaterTotem] = sim.CurrentTime + time.Second*12 - } - }, - }) - - shaman.AddMajorCooldown(core.MajorCooldown{ - Spell: mttSpell, - Type: core.CooldownTypeDPS, - ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { - return sim.CurrentTime > time.Second*30 - }, - }) -} +// func (shaman *Shaman) spellThreatMultiplier() float64 { +// return []float64{1, 0.9, 0.8, 0.7}[shaman.Talents.ElementalPrecision] +// } + +// func (shaman *Shaman) applyElementalFocus() { +// if !shaman.Talents.ElementalFocus { +// return +// } + +// oathBonus := 1 + (0.05 * float64(shaman.Talents.ElementalOath)) +// var affectedSpells []*core.Spell + +// // TODO: fix this. +// // Right now: Set to 3 so that the spell that cast it consumes a charge down to expected 2. +// // Correct fix would be to figure out how to make 'onCastComplete' fire before 'onspellhitdealt' without breaking all the other things. +// maxStacks := int32(3) + +// clearcastingAura := shaman.RegisterAura(core.Aura{ +// Label: "Clearcasting", +// ActionID: core.ActionID{SpellID: 16246}, +// Duration: time.Second * 15, +// MaxStacks: maxStacks, +// OnInit: func(aura *core.Aura, sim *core.Simulation) { +// affectedSpells = core.FilterSlice([]*core.Spell{ +// shaman.LightningBolt, +// shaman.ChainLightning, +// shaman.LavaBurst, +// shaman.FireNova, +// shaman.EarthShock, +// shaman.FlameShock, +// shaman.FrostShock, +// }, func(spell *core.Spell) bool { return spell != nil }) +// }, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range affectedSpells { +// spell.CostMultiplier -= 0.4 +// } +// if oathBonus > 1 { +// shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] *= oathBonus +// shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= oathBonus +// shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFrost] *= oathBonus +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range affectedSpells { +// spell.CostMultiplier += 0.4 +// } +// if oathBonus > 1 { +// shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] /= oathBonus +// shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] /= oathBonus +// shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFrost] /= oathBonus +// } +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if !spell.Flags.Matches(SpellFlagShock | SpellFlagFocusable) { +// return +// } +// if spell.ActionID.Tag == 6 { // Filter LO casts +// return +// } +// aura.RemoveStack(sim) +// }, +// }) + +// shaman.RegisterAura(core.Aura{ +// Label: "Elemental Focus", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.Flags.Matches(SpellFlagShock | SpellFlagFocusable) { +// return +// } +// if !result.Outcome.Matches(core.OutcomeCrit) { +// return +// } +// clearcastingAura.Activate(sim) +// clearcastingAura.SetStacks(sim, maxStacks) +// }, +// }) +// } + +// func (shaman *Shaman) applyElementalDevastation() { +// if shaman.Talents.ElementalDevastation == 0 { +// return +// } + +// critBonus := 3.0 * float64(shaman.Talents.ElementalDevastation) * core.CritRatingPerCritChance +// procAura := shaman.NewTemporaryStatsAura("Elemental Devastation Proc", core.ActionID{SpellID: 30160}, stats.Stats{stats.MeleeCrit: critBonus}, time.Second*10) + +// shaman.RegisterAura(core.Aura{ +// Label: "Elemental Devastation", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.ProcMask.Matches(core.ProcMaskSpellDamage) { +// return +// } +// if !result.Outcome.Matches(core.OutcomeCrit) { +// return +// } +// procAura.Activate(sim) +// }, +// }) +// } + +// var eleMasterActionID = core.ActionID{SpellID: 16166} + +// func (shaman *Shaman) registerElementalMasteryCD() { +// if !shaman.Talents.ElementalMastery { +// return +// } + +// cdTimer := shaman.NewTimer() +// cd := time.Minute * 3 + +// if shaman.HasMajorGlyph(proto.ShamanMajorGlyph_GlyphOfElementalMastery) { +// cd -= time.Second * 30 +// } + +// // TODO: Share CD with Natures Swiftness + +// buffAura := shaman.RegisterAura(core.Aura{ +// Label: "Elemental Mastery Haste", +// ActionID: core.ActionID{SpellID: 64701}, +// Duration: time.Second * 15, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// shaman.MultiplyCastSpeed(1.15) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// shaman.MultiplyCastSpeed(1 / 1.15) +// }, +// }) + +// emAura := shaman.RegisterAura(core.Aura{ +// Label: "Elemental Mastery", +// ActionID: eleMasterActionID, +// Duration: core.NeverExpires, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// shaman.ChainLightning.CastTimeMultiplier -= 1 +// shaman.LavaBurst.CastTimeMultiplier -= 1 +// shaman.LightningBolt.CastTimeMultiplier -= 1 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// shaman.ChainLightning.CastTimeMultiplier += 1 +// shaman.LavaBurst.CastTimeMultiplier += 1 +// shaman.LightningBolt.CastTimeMultiplier += 1 +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell != shaman.LightningBolt && spell != shaman.ChainLightning && spell != shaman.LavaBurst { +// return +// } +// // Remove the buff and put skill on CD +// aura.Deactivate(sim) +// cdTimer.Set(sim.CurrentTime + cd) +// shaman.UpdateMajorCooldowns() +// }, +// }) + +// eleMastSpell := shaman.RegisterSpell(core.SpellConfig{ +// ActionID: eleMasterActionID, +// Flags: core.SpellFlagNoOnCastComplete, +// Cast: core.CastConfig{ +// CD: core.Cooldown{ +// Timer: cdTimer, +// Duration: cd, +// }, +// }, +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// buffAura.Activate(sim) +// emAura.Activate(sim) +// }, +// }) + +// shaman.AddMajorCooldown(core.MajorCooldown{ +// Spell: eleMastSpell, +// Type: core.CooldownTypeDPS, +// }) + +// if shaman.HasSetBonus(ItemSetFrostWitchRegalia, 2) { +// shaman.RegisterAura(core.Aura{ +// Label: "Shaman T10 Elemental 2P Bonus", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if (spell == shaman.LightningBolt || spell == shaman.ChainLightning) && !eleMastSpell.CD.IsReady(sim) { +// *eleMastSpell.CD.Timer = core.Timer(time.Duration(*eleMastSpell.CD.Timer) - time.Second*2) +// shaman.UpdateMajorCooldowns() // this could get expensive because it will be called all the time. +// } +// }, +// }) +// } +// } + +// func (shaman *Shaman) registerNaturesSwiftnessCD() { +// if !shaman.Talents.NaturesSwiftness { +// return +// } +// actionID := core.ActionID{SpellID: 16188} +// cdTimer := shaman.NewTimer() +// cd := time.Minute * 3 + +// nsAura := shaman.RegisterAura(core.Aura{ +// Label: "Natures Swiftness", +// ActionID: actionID, +// Duration: core.NeverExpires, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// shaman.ChainLightning.CastTimeMultiplier -= 1 +// shaman.LavaBurst.CastTimeMultiplier -= 1 +// shaman.LightningBolt.CastTimeMultiplier -= 1 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// shaman.ChainLightning.CastTimeMultiplier += 1 +// shaman.LavaBurst.CastTimeMultiplier += 1 +// shaman.LightningBolt.CastTimeMultiplier += 1 +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if spell != shaman.LightningBolt && spell != shaman.ChainLightning && spell != shaman.LavaBurst { +// return +// } + +// // Remove the buff and put skill on CD +// aura.Deactivate(sim) +// cdTimer.Set(sim.CurrentTime + cd) +// shaman.UpdateMajorCooldowns() +// }, +// }) + +// nsSpell := shaman.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// Flags: core.SpellFlagNoOnCastComplete, +// Cast: core.CastConfig{ +// CD: core.Cooldown{ +// Timer: cdTimer, +// Duration: cd, +// }, +// }, +// ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { +// // Don't use NS unless we're casting a full-length lightning bolt, which is +// // the only spell shamans have with a cast longer than GCD. +// return !shaman.HasTemporarySpellCastSpeedIncrease() +// }, +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// nsAura.Activate(sim) +// }, +// }) + +// shaman.AddMajorCooldown(core.MajorCooldown{ +// Spell: nsSpell, +// Type: core.CooldownTypeDPS, +// }) +// } + +// func (shaman *Shaman) applyFlurry() { +// if shaman.Talents.Flurry == 0 { +// return +// } + +// bonus := 1.0 + 0.06*float64(shaman.Talents.Flurry) + +// if shaman.HasSetBonus(ItemSetEarthshatterBattlegear, 4) { +// bonus += 0.05 +// } + +// inverseBonus := 1 / bonus + +// procAura := shaman.RegisterAura(core.Aura{ +// Label: "Flurry Proc", +// ActionID: core.ActionID{SpellID: 16280}, +// Duration: core.NeverExpires, +// MaxStacks: 3, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// shaman.MultiplyMeleeSpeed(sim, bonus) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// shaman.MultiplyMeleeSpeed(sim, inverseBonus) +// }, +// }) + +// icd := core.Cooldown{ +// Timer: shaman.NewTimer(), +// Duration: time.Millisecond * 500, +// } + +// shaman.RegisterAura(core.Aura{ +// Label: "Flurry", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.ProcMask.Matches(core.ProcMaskMelee) { +// return +// } + +// if result.Outcome.Matches(core.OutcomeCrit) { +// procAura.Activate(sim) +// procAura.SetStacks(sim, 3) +// icd.Reset() // the "charge protection" ICD isn't up yet +// return +// } + +// // Remove a stack. +// if procAura.IsActive() && spell.ProcMask.Matches(core.ProcMaskMeleeWhiteHit) && icd.IsReady(sim) { +// icd.Use(sim) +// procAura.RemoveStack(sim) +// } +// }, +// }) +// } + +// func (shaman *Shaman) applyMaelstromWeapon() { +// if shaman.Talents.MaelstromWeapon == 0 { +// return +// } + +// var t10BonusAura *core.Aura +// enhT10Bonus := false +// if shaman.HasSetBonus(ItemSetFrostWitchBattlegear, 4) { +// enhT10Bonus = true + +// statDep := shaman.NewDynamicMultiplyStat(stats.AttackPower, 1.2) +// t10BonusAura = shaman.RegisterAura(core.Aura{ +// Label: "Maelstrom Power", +// ActionID: core.ActionID{SpellID: 70831}, +// Duration: time.Second * 10, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// shaman.EnableDynamicStatDep(sim, statDep) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// shaman.DisableDynamicStatDep(sim, statDep) +// }, +// }) +// } + +// // TODO: Don't forget to make it so that AA don't reset when casting when MW is active +// // for LB / CL / LvB +// // They can't actually hit while casting, but the AA timer doesnt reset if you cast during the AA timer. + +// // For sim purposes maelstrom weapon only impacts CL / LB +// shaman.MaelstromWeaponAura = shaman.RegisterAura(core.Aura{ +// Label: "MaelstromWeapon Proc", +// ActionID: core.ActionID{SpellID: 53817}, +// Duration: time.Second * 30, +// MaxStacks: 5, +// OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { +// multDiff := 0.2 * float64(newStacks-oldStacks) +// shaman.LightningBolt.CastTimeMultiplier -= multDiff +// shaman.ChainLightning.CastTimeMultiplier -= multDiff + +// if enhT10Bonus && shaman.MaelstromWeaponAura.GetStacks() == 5 { +// if sim.RandomFloat("Maelstrom Power") < 0.15 { +// t10BonusAura.Activate(sim) +// } +// } +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.Flags.Matches(SpellFlagElectric) { +// return +// } +// shaman.MaelstromWeaponAura.Deactivate(sim) +// }, +// }) + +// ppmm := shaman.AutoAttacks.NewPPMManager(core.TernaryFloat64(shaman.HasSetBonus(ItemSetWorldbreakerBattlegear, 4), 2.4, 2.0)* +// float64(shaman.Talents.MaelstromWeapon), core.ProcMaskMelee) +// // This aura is hidden, just applies stacks of the proc aura. +// shaman.RegisterAura(core.Aura{ +// Label: "MaelstromWeapon", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() { +// return +// } + +// if ppmm.Proc(sim, spell.ProcMask, "Maelstrom Weapon") { +// shaman.MaelstromWeaponAura.Activate(sim) +// shaman.MaelstromWeaponAura.AddStack(sim) +// } +// }, +// }) +// } + +// func (shaman *Shaman) registerManaTideTotemCD() { +// if !shaman.Talents.ManaTideTotem { +// return +// } + +// mttAura := core.ManaTideTotemAura(shaman.GetCharacter(), shaman.Index) +// mttSpell := shaman.RegisterSpell(core.SpellConfig{ +// ActionID: core.ManaTideTotemActionID, +// Flags: core.SpellFlagNoOnCastComplete, +// Cast: core.CastConfig{ +// DefaultCast: core.Cast{ +// GCD: time.Second, +// }, +// IgnoreHaste: true, +// CD: core.Cooldown{ +// Timer: shaman.NewTimer(), +// Duration: time.Minute * 5, +// }, +// }, +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { +// mttAura.Activate(sim) + +// // If healing stream is active, cancel it while mana tide is up. +// if shaman.HealingStreamTotem.Hot(&shaman.Unit).IsActive() { +// for _, agent := range shaman.Party.Players { +// shaman.HealingStreamTotem.Hot(&agent.GetCharacter().Unit).Cancel(sim) +// } +// } + +// // TODO: Current water totem buff needs to be removed from party/raid. +// if shaman.Totems.Water != proto.WaterTotem_NoWaterTotem { +// shaman.TotemExpirations[WaterTotem] = sim.CurrentTime + time.Second*12 +// } +// }, +// }) + +// shaman.AddMajorCooldown(core.MajorCooldown{ +// Spell: mttSpell, +// Type: core.CooldownTypeDPS, +// ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { +// return sim.CurrentTime > time.Second*30 +// }, +// }) +// } diff --git a/sim/warlock/apl_values.go b/sim/warlock/_apl_values.go similarity index 100% rename from sim/warlock/apl_values.go rename to sim/warlock/_apl_values.go diff --git a/sim/warlock/chaos_bolt.go b/sim/warlock/_chaos_bolt.go similarity index 100% rename from sim/warlock/chaos_bolt.go rename to sim/warlock/_chaos_bolt.go diff --git a/sim/warlock/conflagrate.go b/sim/warlock/_conflagrate.go similarity index 100% rename from sim/warlock/conflagrate.go rename to sim/warlock/_conflagrate.go diff --git a/sim/warlock/corruption.go b/sim/warlock/_corruption.go similarity index 100% rename from sim/warlock/corruption.go rename to sim/warlock/_corruption.go diff --git a/sim/warlock/curses.go b/sim/warlock/_curses.go similarity index 100% rename from sim/warlock/curses.go rename to sim/warlock/_curses.go diff --git a/sim/warlock/darkpact.go b/sim/warlock/_darkpact.go similarity index 100% rename from sim/warlock/darkpact.go rename to sim/warlock/_darkpact.go diff --git a/sim/warlock/demonic_empowerment.go b/sim/warlock/_demonic_empowerment.go similarity index 100% rename from sim/warlock/demonic_empowerment.go rename to sim/warlock/_demonic_empowerment.go diff --git a/sim/warlock/drain_soul.go b/sim/warlock/_drain_soul.go similarity index 100% rename from sim/warlock/drain_soul.go rename to sim/warlock/_drain_soul.go diff --git a/sim/warlock/haunt.go b/sim/warlock/_haunt.go similarity index 100% rename from sim/warlock/haunt.go rename to sim/warlock/_haunt.go diff --git a/sim/warlock/immolate.go b/sim/warlock/_immolate.go similarity index 100% rename from sim/warlock/immolate.go rename to sim/warlock/_immolate.go diff --git a/sim/warlock/incinerate.go b/sim/warlock/_incinerate.go similarity index 100% rename from sim/warlock/incinerate.go rename to sim/warlock/_incinerate.go diff --git a/sim/warlock/inferno.go b/sim/warlock/_inferno.go similarity index 100% rename from sim/warlock/inferno.go rename to sim/warlock/_inferno.go diff --git a/sim/warlock/items.go b/sim/warlock/_items.go similarity index 100% rename from sim/warlock/items.go rename to sim/warlock/_items.go diff --git a/sim/warlock/lifetap.go b/sim/warlock/_lifetap.go similarity index 100% rename from sim/warlock/lifetap.go rename to sim/warlock/_lifetap.go diff --git a/sim/warlock/metamorphosis.go b/sim/warlock/_metamorphosis.go similarity index 100% rename from sim/warlock/metamorphosis.go rename to sim/warlock/_metamorphosis.go diff --git a/sim/warlock/pet.go b/sim/warlock/_pet.go similarity index 100% rename from sim/warlock/pet.go rename to sim/warlock/_pet.go diff --git a/sim/warlock/pet_abilities.go b/sim/warlock/_pet_abilities.go similarity index 100% rename from sim/warlock/pet_abilities.go rename to sim/warlock/_pet_abilities.go diff --git a/sim/warlock/searing_pain.go b/sim/warlock/_searing_pain.go similarity index 100% rename from sim/warlock/searing_pain.go rename to sim/warlock/_searing_pain.go diff --git a/sim/warlock/seed.go b/sim/warlock/_seed.go similarity index 100% rename from sim/warlock/seed.go rename to sim/warlock/_seed.go diff --git a/sim/warlock/shadowbolt.go b/sim/warlock/_shadowbolt.go similarity index 100% rename from sim/warlock/shadowbolt.go rename to sim/warlock/_shadowbolt.go diff --git a/sim/warlock/shadowburn.go b/sim/warlock/_shadowburn.go similarity index 100% rename from sim/warlock/shadowburn.go rename to sim/warlock/_shadowburn.go diff --git a/sim/warlock/soul_fire.go b/sim/warlock/_soul_fire.go similarity index 100% rename from sim/warlock/soul_fire.go rename to sim/warlock/_soul_fire.go diff --git a/sim/warlock/unstable_affliction.go b/sim/warlock/_unstable_affliction.go similarity index 100% rename from sim/warlock/unstable_affliction.go rename to sim/warlock/_unstable_affliction.go diff --git a/sim/warlock/affliction/affliction_test.go b/sim/warlock/affliction/_affliction_test.go similarity index 100% rename from sim/warlock/affliction/affliction_test.go rename to sim/warlock/affliction/_affliction_test.go diff --git a/sim/warlock/demonology/demonology_test.go b/sim/warlock/demonology/_demonology_test.go similarity index 100% rename from sim/warlock/demonology/demonology_test.go rename to sim/warlock/demonology/_demonology_test.go diff --git a/sim/warlock/destruction/destruction_test.go b/sim/warlock/destruction/_destruction_test.go similarity index 100% rename from sim/warlock/destruction/destruction_test.go rename to sim/warlock/destruction/_destruction_test.go diff --git a/sim/warlock/talents.go b/sim/warlock/talents.go index a789fcb17d..f7b535f271 100644 --- a/sim/warlock/talents.go +++ b/sim/warlock/talents.go @@ -1,600 +1,590 @@ package warlock -import ( - "math" - "slices" - "time" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" -) - func (warlock *Warlock) ApplyTalents() { - // Demonic Embrace - if warlock.Talents.DemonicEmbrace > 0 { - warlock.MultiplyStat(stats.Stamina, 1.01+(float64(warlock.Talents.DemonicEmbrace)*0.03)) - } - - // Molten Skin - warlock.PseudoStats.DamageTakenMultiplier *= 1. - 0.02*float64(warlock.Talents.MoltenSkin) - - // Malediction - maledictionMultiplier := 1. + 0.01*float64(warlock.Talents.Malediction) - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= maledictionMultiplier - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= maledictionMultiplier - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexArcane] *= maledictionMultiplier - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] *= maledictionMultiplier - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexHoly] *= maledictionMultiplier - - warlock.setupDemonicPact() - - // Suppression (Add 1% hit per point) - warlock.AddStat(stats.SpellHit, float64(warlock.Talents.Suppression)*core.SpellHitRatingPerHitChance) - - // Backlash (Add 1% crit per point) - warlock.AddStat(stats.SpellCrit, float64(warlock.Talents.Backlash)*core.CritRatingPerCritChance) - - warlock.applyDeathsEmbrace() - - // Fel Vitality - if warlock.Talents.FelVitality > 0 { - bonus := 1.0 + 0.01*float64(warlock.Talents.FelVitality) - warlock.MultiplyStat(stats.Mana, bonus) - warlock.MultiplyStat(stats.Health, bonus) - } - - // Demonic Tactics, applies even without pet out - if warlock.Talents.DemonicTactics > 0 { - warlock.AddStats(stats.Stats{ - stats.MeleeCrit: float64(warlock.Talents.DemonicTactics) * 2 * core.CritRatingPerCritChance, - stats.SpellCrit: float64(warlock.Talents.DemonicTactics) * 2 * core.CritRatingPerCritChance, - }) - } - - warlock.setupNightfall() - warlock.setupShadowEmbrace() - warlock.setupEradication() - warlock.setupMoltenCore() - warlock.setupDecimation() - warlock.setupPyroclasm() - warlock.setupBackdraft() - warlock.setupImprovedSoulLeech() - warlock.setupEmpoweredImp() - warlock.setupGlyphOfLifeTapAura() -} - -func (warlock *Warlock) applyDeathsEmbrace() { - if warlock.Talents.DeathsEmbrace <= 0 { - return - } - - multiplier := 1.0 + 0.04*float64(warlock.Talents.DeathsEmbrace) - warlock.RegisterResetEffect(func(sim *core.Simulation) { - sim.RegisterExecutePhaseCallback(func(sim *core.Simulation, isExecute int32) { - if isExecute == 35 { - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= multiplier - } - }) - }) -} - -func (warlock *Warlock) applyWeaponImbue() { - if warlock.Options.WeaponImbue == proto.WarlockOptions_GrandFirestone { - warlock.AddStat(stats.SpellCrit, 49*(1+1.5*float64(warlock.Talents.MasterConjuror))) - } - if warlock.Options.WeaponImbue == proto.WarlockOptions_GrandSpellstone { - warlock.AddStat(stats.SpellHaste, 60*(1+1.5*float64(warlock.Talents.MasterConjuror))) - } -} - -func (warlock *Warlock) setupGlyphOfLifeTapAura() { - if !warlock.HasMajorGlyph(proto.WarlockMajorGlyph_GlyphOfLifeTap) { - return - } - - statDep := warlock.NewDynamicStatDependency(stats.Spirit, stats.SpellPower, 0.2) - warlock.GlyphOfLifeTapAura = warlock.RegisterAura(core.Aura{ - Label: "Glyph Of LifeTap Aura", - ActionID: core.ActionID{SpellID: 63321}, - Duration: time.Second * 40, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.EnableDynamicStatDep(sim, statDep) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.DisableDynamicStatDep(sim, statDep) - }, - }) -} - -func (warlock *Warlock) setupEmpoweredImp() { - if warlock.Talents.EmpoweredImp <= 0 || warlock.Options.Summon != proto.WarlockOptions_Imp { - return - } - - warlock.Pet.PseudoStats.DamageDealtMultiplier *= 1.0 + 0.1*float64(warlock.Talents.EmpoweredImp) - - var affectedSpells []*core.Spell - warlock.EmpoweredImpAura = warlock.RegisterAura(core.Aura{ - Label: "Empowered Imp Proc Aura", - ActionID: core.ActionID{SpellID: 47283}, - Duration: time.Second * 8, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - affectedSpells = core.FilterSlice([]*core.Spell{ - warlock.Immolate, - warlock.ShadowBolt, - warlock.Incinerate, - warlock.Shadowburn, - warlock.SoulFire, - warlock.ChaosBolt, - warlock.SearingPain, - // missing: shadowfury, shadowflame, seed explosion (not dot) - // rain of fire (consumes proc on cast start, but doesn't increase crit, ticks - // also consume the proc but do seem to benefit from the increaesed crit) - }, func(spell *core.Spell) bool { return spell != nil }) - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.BonusCritRating += 100 * core.CritRatingPerCritChance - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.BonusCritRating -= 100 * core.CritRatingPerCritChance - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if slices.Contains(affectedSpells, spell) { - aura.Deactivate(sim) - } - }, - }) - - warlock.Pet.RegisterAura(core.Aura{ - Label: "Empowered Imp Hidden Aura", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.DidCrit() { - warlock.EmpoweredImpAura.Activate(sim) - } - }, - }) -} - -func (warlock *Warlock) setupDecimation() { - if warlock.Talents.Decimation <= 0 { - return - } - - decimationMod := 0.2 * float64(warlock.Talents.Decimation) - warlock.DecimationAura = warlock.RegisterAura(core.Aura{ - Label: "Decimation Proc Aura", - ActionID: core.ActionID{SpellID: 63167}, - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.SoulFire.CastTimeMultiplier -= decimationMod - warlock.SoulFire.DefaultCast.GCD = time.Duration(float64(warlock.SoulFire.DefaultCast.GCD) * (1 - decimationMod)) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.SoulFire.CastTimeMultiplier += decimationMod - warlock.SoulFire.DefaultCast.GCD = time.Duration(float64(warlock.SoulFire.DefaultCast.GCD) / (1 - decimationMod)) - }, - }) - - decimation := warlock.RegisterAura(core.Aura{ - Label: "Decimation Talent Hidden Aura", - Duration: core.NeverExpires, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() && (spell == warlock.ShadowBolt || spell == warlock.Incinerate || spell == warlock.SoulFire) { - warlock.DecimationAura.Activate(sim) - } - }, - }) - - warlock.RegisterResetEffect(func(sim *core.Simulation) { - sim.RegisterExecutePhaseCallback(func(sim *core.Simulation, isExecute int32) { - if isExecute == 35 { - decimation.Activate(sim) - } - }) - }) -} - -func (warlock *Warlock) setupPyroclasm() { - if warlock.Talents.Pyroclasm <= 0 { - return - } - - pyroclasmDamageBonus := 1 + 0.02*float64(warlock.Talents.Pyroclasm) - - warlock.PyroclasmAura = warlock.RegisterAura(core.Aura{ - Label: "Pyroclasm", - ActionID: core.ActionID{SpellID: 63244}, - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= pyroclasmDamageBonus - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= pyroclasmDamageBonus - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] /= pyroclasmDamageBonus - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] /= pyroclasmDamageBonus - }, - }) - - warlock.RegisterAura(core.Aura{ - Label: "Pyroclasm Talent Hidden Aura", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if (spell == warlock.Conflagrate || spell == warlock.SearingPain) && result.DidCrit() { - warlock.PyroclasmAura.Activate(sim) - } - }, - }) -} - -func (warlock *Warlock) setupEradication() { - if warlock.Talents.Eradication <= 0 { - return - } - - castSpeedMultiplier := []float64{1, 1.06, 1.12, 1.20}[warlock.Talents.Eradication] - warlock.EradicationAura = warlock.RegisterAura(core.Aura{ - Label: "Eradication", - ActionID: core.ActionID{SpellID: 64371}, - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.MultiplyCastSpeed(castSpeedMultiplier) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.MultiplyCastSpeed(1 / castSpeedMultiplier) - }, - }) - - warlock.RegisterAura(core.Aura{ - Label: "Eradication Talent Hidden Aura", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == warlock.Corruption { - if sim.Proc(0.06, "Eradication") { - warlock.EradicationAura.Activate(sim) - } - } - }, - }) -} - -func (warlock *Warlock) ShadowEmbraceDebuffAura(target *core.Unit) *core.Aura { - shadowEmbraceBonus := 0.01 * float64(warlock.Talents.ShadowEmbrace) - - return target.GetOrRegisterAura(core.Aura{ - Label: "Shadow Embrace-" + warlock.Label, - ActionID: core.ActionID{SpellID: 32391}, - Duration: time.Second * 12, - MaxStacks: 3, - OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { - warlock.AttackTables[aura.Unit.UnitIndex].HauntSEDamageTakenMultiplier /= 1.0 + shadowEmbraceBonus*float64(oldStacks) - warlock.AttackTables[aura.Unit.UnitIndex].HauntSEDamageTakenMultiplier *= 1.0 + shadowEmbraceBonus*float64(newStacks) - }, - }) -} - -func (warlock *Warlock) setupShadowEmbrace() { - if warlock.Talents.ShadowEmbrace <= 0 { - return - } - - warlock.ShadowEmbraceAuras = warlock.NewEnemyAuraArray(warlock.ShadowEmbraceDebuffAura) - - warlock.RegisterAura(core.Aura{ - Label: "Shadow Embrace Talent Hidden Aura", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if (spell == warlock.ShadowBolt || spell == warlock.Haunt) && result.Landed() { - aura := warlock.ShadowEmbraceAuras.Get(result.Target) - aura.Activate(sim) - aura.AddStack(sim) - } - }, - }) -} - -func (warlock *Warlock) setupNightfall() { - if warlock.Talents.Nightfall <= 0 && !warlock.HasMajorGlyph(proto.WarlockMajorGlyph_GlyphOfCorruption) { - return - } - - nightfallProcChance := 0.02*float64(warlock.Talents.Nightfall) + - 0.04*core.TernaryFloat64(warlock.HasMajorGlyph(proto.WarlockMajorGlyph_GlyphOfCorruption), 1, 0) - - warlock.NightfallProcAura = warlock.RegisterAura(core.Aura{ - Label: "Nightfall Shadow Trance", - ActionID: core.ActionID{SpellID: 17941}, - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.ShadowBolt.CastTimeMultiplier -= 1 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.ShadowBolt.CastTimeMultiplier += 1 - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - // Check if the shadowbolt was instant cast and not a normal one - if spell == warlock.ShadowBolt && spell.CurCast.CastTime == 0 { - aura.Deactivate(sim) - } - }, - }) - - warlock.RegisterAura(core.Aura{ - Label: "Nightfall Hidden Aura", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == warlock.Corruption { // TODO: also works on drain life... - if sim.Proc(nightfallProcChance, "Nightfall") { - warlock.NightfallProcAura.Activate(sim) - } - } - }, - }) -} - -func (warlock *Warlock) setupMoltenCore() { - if warlock.Talents.MoltenCore <= 0 { - return - } - - castReduction := 0.1 * float64(warlock.Talents.MoltenCore) - moltenCoreDamageBonus := 1 + 0.06*float64(warlock.Talents.MoltenCore) - moltenCoreCritBonus := 5 * float64(warlock.Talents.MoltenCore) * core.CritRatingPerCritChance - - warlock.MoltenCoreAura = warlock.RegisterAura(core.Aura{ - Label: "Molten Core Proc Aura", - ActionID: core.ActionID{SpellID: 71165}, - Duration: time.Second * 15, - MaxStacks: 3, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.Incinerate.DamageMultiplier *= moltenCoreDamageBonus - warlock.Incinerate.CastTimeMultiplier -= castReduction - warlock.Incinerate.DefaultCast.GCD = time.Duration(float64(warlock.Incinerate.DefaultCast.GCD) * (1 - castReduction)) - warlock.SoulFire.DamageMultiplier *= moltenCoreDamageBonus - warlock.SoulFire.BonusCritRating += moltenCoreCritBonus - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.Incinerate.DamageMultiplier /= moltenCoreDamageBonus - warlock.Incinerate.CastTimeMultiplier += castReduction - warlock.Incinerate.DefaultCast.GCD = time.Duration(float64(warlock.Incinerate.DefaultCast.GCD) / (1 - castReduction)) - warlock.SoulFire.DamageMultiplier /= moltenCoreDamageBonus - warlock.SoulFire.BonusCritRating -= moltenCoreCritBonus - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell == warlock.Incinerate || spell == warlock.SoulFire { - aura.RemoveStack(sim) - } - }, - }) - - warlock.RegisterAura(core.Aura{ - Label: "Molten Core Hidden Aura", - // ActionID: core.ActionID{SpellID: 47247}, - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == warlock.Corruption { - if sim.Proc(0.04*float64(warlock.Talents.MoltenCore), "Molten Core") { - warlock.MoltenCoreAura.Activate(sim) - warlock.MoltenCoreAura.SetStacks(sim, 3) - } - } - }, - }) -} - -func (warlock *Warlock) setupBackdraft() { - if warlock.Talents.Backdraft <= 0 { - return - } - - castTimeModifier := 0.1 * float64(warlock.Talents.Backdraft) - var affectedSpells []*core.Spell - - warlock.BackdraftAura = warlock.RegisterAura(core.Aura{ - Label: "Backdraft Proc Aura", - ActionID: core.ActionID{SpellID: 54277}, - Duration: time.Second * 15, - MaxStacks: 3, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - affectedSpells = core.FilterSlice([]*core.Spell{ - warlock.Incinerate, - warlock.SoulFire, - warlock.ShadowBolt, - warlock.ChaosBolt, - warlock.Immolate, - warlock.SearingPain, - }, func(spell *core.Spell) bool { return spell != nil }) - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, destroSpell := range affectedSpells { - destroSpell.CastTimeMultiplier -= castTimeModifier - destroSpell.DefaultCast.GCD = time.Duration(float64(destroSpell.DefaultCast.GCD) * (1 - castTimeModifier)) - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, destroSpell := range affectedSpells { - destroSpell.CastTimeMultiplier += castTimeModifier - destroSpell.DefaultCast.GCD = time.Duration(float64(destroSpell.DefaultCast.GCD) / (1 - castTimeModifier)) - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if slices.Contains(affectedSpells, spell) { - aura.RemoveStack(sim) - } - }, - }) - - warlock.RegisterAura(core.Aura{ - Label: "Backdraft Hidden Aura", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == warlock.Conflagrate && result.Landed() { - warlock.BackdraftAura.Activate(sim) - warlock.BackdraftAura.SetStacks(sim, 3) - } - }, - }) -} - -func (warlock *Warlock) everlastingAfflictionRefresh(sim *core.Simulation, target *core.Unit) { - procChance := 0.2 * float64(warlock.Talents.EverlastingAffliction) - - if warlock.Corruption.Dot(target).IsActive() && sim.Proc(procChance, "EverlastingAffliction") { - warlock.Corruption.Dot(target).Rollover(sim) - } + // // Demonic Embrace + // if warlock.Talents.DemonicEmbrace > 0 { + // warlock.MultiplyStat(stats.Stamina, 1.01+(float64(warlock.Talents.DemonicEmbrace)*0.03)) + // } + + // // Molten Skin + // warlock.PseudoStats.DamageTakenMultiplier *= 1. - 0.02*float64(warlock.Talents.MoltenSkin) + + // // Malediction + // maledictionMultiplier := 1. + 0.01*float64(warlock.Talents.Malediction) + // warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= maledictionMultiplier + // warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= maledictionMultiplier + // warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexArcane] *= maledictionMultiplier + // warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] *= maledictionMultiplier + // warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexHoly] *= maledictionMultiplier + + // warlock.setupDemonicPact() + + // // Suppression (Add 1% hit per point) + // warlock.AddStat(stats.SpellHit, float64(warlock.Talents.Suppression)*core.SpellHitRatingPerHitChance) + + // // Backlash (Add 1% crit per point) + // warlock.AddStat(stats.SpellCrit, float64(warlock.Talents.Backlash)*core.CritRatingPerCritChance) + + // warlock.applyDeathsEmbrace() + + // // Fel Vitality + // if warlock.Talents.FelVitality > 0 { + // bonus := 1.0 + 0.01*float64(warlock.Talents.FelVitality) + // warlock.MultiplyStat(stats.Mana, bonus) + // warlock.MultiplyStat(stats.Health, bonus) + // } + + // // Demonic Tactics, applies even without pet out + // if warlock.Talents.DemonicTactics > 0 { + // warlock.AddStats(stats.Stats{ + // stats.MeleeCrit: float64(warlock.Talents.DemonicTactics) * 2 * core.CritRatingPerCritChance, + // stats.SpellCrit: float64(warlock.Talents.DemonicTactics) * 2 * core.CritRatingPerCritChance, + // }) + // } + + // warlock.setupNightfall() + // warlock.setupShadowEmbrace() + // warlock.setupEradication() + // warlock.setupMoltenCore() + // warlock.setupDecimation() + // warlock.setupPyroclasm() + // warlock.setupBackdraft() + // warlock.setupImprovedSoulLeech() + // warlock.setupEmpoweredImp() + // warlock.setupGlyphOfLifeTapAura() } -func (warlock *Warlock) setupImprovedSoulLeech() { - if warlock.Talents.ImprovedSoulLeech <= 0 { - return - } - - soulLeechProcChance := 0.1 * float64(warlock.Talents.SoulLeech) - impSoulLeechProcChance := float64(warlock.Talents.ImprovedSoulLeech) / 2. - actionID := core.ActionID{SpellID: 54118} - impSoulLeechManaMetric := warlock.NewManaMetrics(actionID) - var impSoulLeechPetManaMetric *core.ResourceMetrics - if warlock.Pet != nil { - impSoulLeechPetManaMetric = warlock.Pet.NewManaMetrics(actionID) - } - replSrc := warlock.Env.Raid.NewReplenishmentSource(core.ActionID{SpellID: 54118}) - - warlock.RegisterAura(core.Aura{ - Label: "Improved Soul Leech Hidden Aura", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if (spell == warlock.Conflagrate || spell == warlock.ShadowBolt || spell == warlock.ChaosBolt || - spell == warlock.SoulFire || spell == warlock.Incinerate) && result.Landed() { - if !sim.Proc(soulLeechProcChance, "SoulLeech") { - return - } - - restorePct := float64(warlock.Talents.ImprovedSoulLeech) / 100 - warlock.AddMana(sim, warlock.MaxMana()*restorePct, impSoulLeechManaMetric) - pet := warlock.Pet - if pet != nil { - pet.AddMana(sim, pet.MaxMana()*restorePct, impSoulLeechPetManaMetric) - } - - if sim.Proc(impSoulLeechProcChance, "ImprovedSoulLeech") { - warlock.Env.Raid.ProcReplenishment(sim, replSrc) - } - } - }, - }) -} - -func (warlock *Warlock) updateDPASP(sim *core.Simulation) { - if sim.CurrentTime < 0 { - return - } - - dpspCurrent := warlock.DemonicPactAura.ExclusiveEffects[0].Priority - currentTimeJump := sim.CurrentTime.Seconds() - warlock.PreviousTime.Seconds() - - if currentTimeJump > 0 { - warlock.DPSPAggregate += dpspCurrent * currentTimeJump - warlock.Metrics.UpdateDpasp(dpspCurrent * currentTimeJump) - - if sim.Log != nil { - warlock.Log(sim, "[Info] Demonic Pact spell power bonus average [%.0f]", - warlock.DPSPAggregate/sim.CurrentTime.Seconds()) - } - } - - warlock.PreviousTime = sim.CurrentTime -} - -func (warlock *Warlock) setupDemonicPact() { - if warlock.Talents.DemonicPact == 0 { - return - } - - dpMult := 0.02 * float64(warlock.Talents.DemonicPact) - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= 1. + dpMult - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= 1. + dpMult - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexArcane] *= 1. + dpMult - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] *= 1. + dpMult - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexHoly] *= 1. + dpMult - - if warlock.Options.Summon == proto.WarlockOptions_NoSummon { - return - } - - icd := core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: 1 * time.Second, - } - - var demonicPactAuras [25]*core.Aura - for _, party := range warlock.Party.Raid.Parties { - for _, player := range party.Players { - demonicPactAuras[player.GetCharacter().Index] = core.DemonicPactAura(player.GetCharacter()) - } - } - warlock.DemonicPactAura = demonicPactAuras[warlock.Index] - - warlock.Pet.RegisterAura(core.Aura{ - Label: "Demonic Pact Hidden Aura", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - warlock.PreviousTime = 0 - aura.Activate(sim) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.updateDPASP(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.DidCrit() || !icd.IsReady(sim) { - return - } - - icd.Use(sim) - - lastBonus := 0.0 - if warlock.DemonicPactAura.IsActive() { - lastBonus = warlock.DemonicPactAura.ExclusiveEffects[0].Priority - } - newSPBonus := math.Round(dpMult * (warlock.GetStat(stats.SpellPower) - lastBonus)) - - if warlock.DemonicPactAura.RemainingDuration(sim) < 10*time.Second || newSPBonus >= lastBonus { - warlock.updateDPASP(sim) - for _, dpAura := range demonicPactAuras { - if dpAura != nil { - dpAura.ExclusiveEffects[0].SetPriority(sim, newSPBonus) - dpAura.Activate(sim) - } - } - } - }, - }) -} +// func (warlock *Warlock) applyDeathsEmbrace() { +// if warlock.Talents.DeathsEmbrace <= 0 { +// return +// } + +// multiplier := 1.0 + 0.04*float64(warlock.Talents.DeathsEmbrace) +// warlock.RegisterResetEffect(func(sim *core.Simulation) { +// sim.RegisterExecutePhaseCallback(func(sim *core.Simulation, isExecute int32) { +// if isExecute == 35 { +// warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= multiplier +// } +// }) +// }) +// } + +// func (warlock *Warlock) applyWeaponImbue() { +// if warlock.Options.WeaponImbue == proto.WarlockOptions_GrandFirestone { +// warlock.AddStat(stats.SpellCrit, 49*(1+1.5*float64(warlock.Talents.MasterConjuror))) +// } +// if warlock.Options.WeaponImbue == proto.WarlockOptions_GrandSpellstone { +// warlock.AddStat(stats.SpellHaste, 60*(1+1.5*float64(warlock.Talents.MasterConjuror))) +// } +// } + +// func (warlock *Warlock) setupGlyphOfLifeTapAura() { +// if !warlock.HasMajorGlyph(proto.WarlockMajorGlyph_GlyphOfLifeTap) { +// return +// } + +// statDep := warlock.NewDynamicStatDependency(stats.Spirit, stats.SpellPower, 0.2) +// warlock.GlyphOfLifeTapAura = warlock.RegisterAura(core.Aura{ +// Label: "Glyph Of LifeTap Aura", +// ActionID: core.ActionID{SpellID: 63321}, +// Duration: time.Second * 40, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// warlock.EnableDynamicStatDep(sim, statDep) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warlock.DisableDynamicStatDep(sim, statDep) +// }, +// }) +// } + +// func (warlock *Warlock) setupEmpoweredImp() { +// if warlock.Talents.EmpoweredImp <= 0 || warlock.Options.Summon != proto.WarlockOptions_Imp { +// return +// } + +// warlock.Pet.PseudoStats.DamageDealtMultiplier *= 1.0 + 0.1*float64(warlock.Talents.EmpoweredImp) + +// var affectedSpells []*core.Spell +// warlock.EmpoweredImpAura = warlock.RegisterAura(core.Aura{ +// Label: "Empowered Imp Proc Aura", +// ActionID: core.ActionID{SpellID: 47283}, +// Duration: time.Second * 8, +// OnInit: func(aura *core.Aura, sim *core.Simulation) { +// affectedSpells = core.FilterSlice([]*core.Spell{ +// warlock.Immolate, +// warlock.ShadowBolt, +// warlock.Incinerate, +// warlock.Shadowburn, +// warlock.SoulFire, +// warlock.ChaosBolt, +// warlock.SearingPain, +// // missing: shadowfury, shadowflame, seed explosion (not dot) +// // rain of fire (consumes proc on cast start, but doesn't increase crit, ticks +// // also consume the proc but do seem to benefit from the increaesed crit) +// }, func(spell *core.Spell) bool { return spell != nil }) +// }, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range affectedSpells { +// spell.BonusCritRating += 100 * core.CritRatingPerCritChance +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// for _, spell := range affectedSpells { +// spell.BonusCritRating -= 100 * core.CritRatingPerCritChance +// } +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if slices.Contains(affectedSpells, spell) { +// aura.Deactivate(sim) +// } +// }, +// }) + +// warlock.Pet.RegisterAura(core.Aura{ +// Label: "Empowered Imp Hidden Aura", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.DidCrit() { +// warlock.EmpoweredImpAura.Activate(sim) +// } +// }, +// }) +// } + +// func (warlock *Warlock) setupDecimation() { +// if warlock.Talents.Decimation <= 0 { +// return +// } + +// decimationMod := 0.2 * float64(warlock.Talents.Decimation) +// warlock.DecimationAura = warlock.RegisterAura(core.Aura{ +// Label: "Decimation Proc Aura", +// ActionID: core.ActionID{SpellID: 63167}, +// Duration: time.Second * 10, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// warlock.SoulFire.CastTimeMultiplier -= decimationMod +// warlock.SoulFire.DefaultCast.GCD = time.Duration(float64(warlock.SoulFire.DefaultCast.GCD) * (1 - decimationMod)) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warlock.SoulFire.CastTimeMultiplier += decimationMod +// warlock.SoulFire.DefaultCast.GCD = time.Duration(float64(warlock.SoulFire.DefaultCast.GCD) / (1 - decimationMod)) +// }, +// }) + +// decimation := warlock.RegisterAura(core.Aura{ +// Label: "Decimation Talent Hidden Aura", +// Duration: core.NeverExpires, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Landed() && (spell == warlock.ShadowBolt || spell == warlock.Incinerate || spell == warlock.SoulFire) { +// warlock.DecimationAura.Activate(sim) +// } +// }, +// }) + +// warlock.RegisterResetEffect(func(sim *core.Simulation) { +// sim.RegisterExecutePhaseCallback(func(sim *core.Simulation, isExecute int32) { +// if isExecute == 35 { +// decimation.Activate(sim) +// } +// }) +// }) +// } + +// func (warlock *Warlock) setupPyroclasm() { +// if warlock.Talents.Pyroclasm <= 0 { +// return +// } + +// pyroclasmDamageBonus := 1 + 0.02*float64(warlock.Talents.Pyroclasm) + +// warlock.PyroclasmAura = warlock.RegisterAura(core.Aura{ +// Label: "Pyroclasm", +// ActionID: core.ActionID{SpellID: 63244}, +// Duration: time.Second * 10, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= pyroclasmDamageBonus +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= pyroclasmDamageBonus +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] /= pyroclasmDamageBonus +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] /= pyroclasmDamageBonus +// }, +// }) + +// warlock.RegisterAura(core.Aura{ +// Label: "Pyroclasm Talent Hidden Aura", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if (spell == warlock.Conflagrate || spell == warlock.SearingPain) && result.DidCrit() { +// warlock.PyroclasmAura.Activate(sim) +// } +// }, +// }) +// } + +// func (warlock *Warlock) setupEradication() { +// if warlock.Talents.Eradication <= 0 { +// return +// } + +// castSpeedMultiplier := []float64{1, 1.06, 1.12, 1.20}[warlock.Talents.Eradication] +// warlock.EradicationAura = warlock.RegisterAura(core.Aura{ +// Label: "Eradication", +// ActionID: core.ActionID{SpellID: 64371}, +// Duration: time.Second * 10, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.MultiplyCastSpeed(castSpeedMultiplier) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.MultiplyCastSpeed(1 / castSpeedMultiplier) +// }, +// }) + +// warlock.RegisterAura(core.Aura{ +// Label: "Eradication Talent Hidden Aura", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == warlock.Corruption { +// if sim.Proc(0.06, "Eradication") { +// warlock.EradicationAura.Activate(sim) +// } +// } +// }, +// }) +// } + +// func (warlock *Warlock) ShadowEmbraceDebuffAura(target *core.Unit) *core.Aura { +// shadowEmbraceBonus := 0.01 * float64(warlock.Talents.ShadowEmbrace) + +// return target.GetOrRegisterAura(core.Aura{ +// Label: "Shadow Embrace-" + warlock.Label, +// ActionID: core.ActionID{SpellID: 32391}, +// Duration: time.Second * 12, +// MaxStacks: 3, +// OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { +// warlock.AttackTables[aura.Unit.UnitIndex].HauntSEDamageTakenMultiplier /= 1.0 + shadowEmbraceBonus*float64(oldStacks) +// warlock.AttackTables[aura.Unit.UnitIndex].HauntSEDamageTakenMultiplier *= 1.0 + shadowEmbraceBonus*float64(newStacks) +// }, +// }) +// } + +// func (warlock *Warlock) setupShadowEmbrace() { +// if warlock.Talents.ShadowEmbrace <= 0 { +// return +// } + +// warlock.ShadowEmbraceAuras = warlock.NewEnemyAuraArray(warlock.ShadowEmbraceDebuffAura) + +// warlock.RegisterAura(core.Aura{ +// Label: "Shadow Embrace Talent Hidden Aura", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if (spell == warlock.ShadowBolt || spell == warlock.Haunt) && result.Landed() { +// aura := warlock.ShadowEmbraceAuras.Get(result.Target) +// aura.Activate(sim) +// aura.AddStack(sim) +// } +// }, +// }) +// } + +// func (warlock *Warlock) setupNightfall() { +// if warlock.Talents.Nightfall <= 0 && !warlock.HasMajorGlyph(proto.WarlockMajorGlyph_GlyphOfCorruption) { +// return +// } + +// nightfallProcChance := 0.02*float64(warlock.Talents.Nightfall) + +// 0.04*core.TernaryFloat64(warlock.HasMajorGlyph(proto.WarlockMajorGlyph_GlyphOfCorruption), 1, 0) + +// warlock.NightfallProcAura = warlock.RegisterAura(core.Aura{ +// Label: "Nightfall Shadow Trance", +// ActionID: core.ActionID{SpellID: 17941}, +// Duration: time.Second * 10, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// warlock.ShadowBolt.CastTimeMultiplier -= 1 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warlock.ShadowBolt.CastTimeMultiplier += 1 +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// // Check if the shadowbolt was instant cast and not a normal one +// if spell == warlock.ShadowBolt && spell.CurCast.CastTime == 0 { +// aura.Deactivate(sim) +// } +// }, +// }) + +// warlock.RegisterAura(core.Aura{ +// Label: "Nightfall Hidden Aura", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == warlock.Corruption { // TODO: also works on drain life... +// if sim.Proc(nightfallProcChance, "Nightfall") { +// warlock.NightfallProcAura.Activate(sim) +// } +// } +// }, +// }) +// } + +// func (warlock *Warlock) setupMoltenCore() { +// if warlock.Talents.MoltenCore <= 0 { +// return +// } + +// castReduction := 0.1 * float64(warlock.Talents.MoltenCore) +// moltenCoreDamageBonus := 1 + 0.06*float64(warlock.Talents.MoltenCore) +// moltenCoreCritBonus := 5 * float64(warlock.Talents.MoltenCore) * core.CritRatingPerCritChance + +// warlock.MoltenCoreAura = warlock.RegisterAura(core.Aura{ +// Label: "Molten Core Proc Aura", +// ActionID: core.ActionID{SpellID: 71165}, +// Duration: time.Second * 15, +// MaxStacks: 3, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// warlock.Incinerate.DamageMultiplier *= moltenCoreDamageBonus +// warlock.Incinerate.CastTimeMultiplier -= castReduction +// warlock.Incinerate.DefaultCast.GCD = time.Duration(float64(warlock.Incinerate.DefaultCast.GCD) * (1 - castReduction)) +// warlock.SoulFire.DamageMultiplier *= moltenCoreDamageBonus +// warlock.SoulFire.BonusCritRating += moltenCoreCritBonus +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warlock.Incinerate.DamageMultiplier /= moltenCoreDamageBonus +// warlock.Incinerate.CastTimeMultiplier += castReduction +// warlock.Incinerate.DefaultCast.GCD = time.Duration(float64(warlock.Incinerate.DefaultCast.GCD) / (1 - castReduction)) +// warlock.SoulFire.DamageMultiplier /= moltenCoreDamageBonus +// warlock.SoulFire.BonusCritRating -= moltenCoreCritBonus +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if spell == warlock.Incinerate || spell == warlock.SoulFire { +// aura.RemoveStack(sim) +// } +// }, +// }) + +// warlock.RegisterAura(core.Aura{ +// Label: "Molten Core Hidden Aura", +// // ActionID: core.ActionID{SpellID: 47247}, +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == warlock.Corruption { +// if sim.Proc(0.04*float64(warlock.Talents.MoltenCore), "Molten Core") { +// warlock.MoltenCoreAura.Activate(sim) +// warlock.MoltenCoreAura.SetStacks(sim, 3) +// } +// } +// }, +// }) +// } + +// func (warlock *Warlock) setupBackdraft() { +// if warlock.Talents.Backdraft <= 0 { +// return +// } + +// castTimeModifier := 0.1 * float64(warlock.Talents.Backdraft) +// var affectedSpells []*core.Spell + +// warlock.BackdraftAura = warlock.RegisterAura(core.Aura{ +// Label: "Backdraft Proc Aura", +// ActionID: core.ActionID{SpellID: 54277}, +// Duration: time.Second * 15, +// MaxStacks: 3, +// OnInit: func(aura *core.Aura, sim *core.Simulation) { +// affectedSpells = core.FilterSlice([]*core.Spell{ +// warlock.Incinerate, +// warlock.SoulFire, +// warlock.ShadowBolt, +// warlock.ChaosBolt, +// warlock.Immolate, +// warlock.SearingPain, +// }, func(spell *core.Spell) bool { return spell != nil }) +// }, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// for _, destroSpell := range affectedSpells { +// destroSpell.CastTimeMultiplier -= castTimeModifier +// destroSpell.DefaultCast.GCD = time.Duration(float64(destroSpell.DefaultCast.GCD) * (1 - castTimeModifier)) +// } +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// for _, destroSpell := range affectedSpells { +// destroSpell.CastTimeMultiplier += castTimeModifier +// destroSpell.DefaultCast.GCD = time.Duration(float64(destroSpell.DefaultCast.GCD) / (1 - castTimeModifier)) +// } +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if slices.Contains(affectedSpells, spell) { +// aura.RemoveStack(sim) +// } +// }, +// }) + +// warlock.RegisterAura(core.Aura{ +// Label: "Backdraft Hidden Aura", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == warlock.Conflagrate && result.Landed() { +// warlock.BackdraftAura.Activate(sim) +// warlock.BackdraftAura.SetStacks(sim, 3) +// } +// }, +// }) +// } + +// func (warlock *Warlock) everlastingAfflictionRefresh(sim *core.Simulation, target *core.Unit) { +// procChance := 0.2 * float64(warlock.Talents.EverlastingAffliction) + +// if warlock.Corruption.Dot(target).IsActive() && sim.Proc(procChance, "EverlastingAffliction") { +// warlock.Corruption.Dot(target).Rollover(sim) +// } +// } + +// func (warlock *Warlock) setupImprovedSoulLeech() { +// if warlock.Talents.ImprovedSoulLeech <= 0 { +// return +// } + +// soulLeechProcChance := 0.1 * float64(warlock.Talents.SoulLeech) +// impSoulLeechProcChance := float64(warlock.Talents.ImprovedSoulLeech) / 2. +// actionID := core.ActionID{SpellID: 54118} +// impSoulLeechManaMetric := warlock.NewManaMetrics(actionID) +// var impSoulLeechPetManaMetric *core.ResourceMetrics +// if warlock.Pet != nil { +// impSoulLeechPetManaMetric = warlock.Pet.NewManaMetrics(actionID) +// } +// replSrc := warlock.Env.Raid.NewReplenishmentSource(core.ActionID{SpellID: 54118}) + +// warlock.RegisterAura(core.Aura{ +// Label: "Improved Soul Leech Hidden Aura", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if (spell == warlock.Conflagrate || spell == warlock.ShadowBolt || spell == warlock.ChaosBolt || +// spell == warlock.SoulFire || spell == warlock.Incinerate) && result.Landed() { +// if !sim.Proc(soulLeechProcChance, "SoulLeech") { +// return +// } + +// restorePct := float64(warlock.Talents.ImprovedSoulLeech) / 100 +// warlock.AddMana(sim, warlock.MaxMana()*restorePct, impSoulLeechManaMetric) +// pet := warlock.Pet +// if pet != nil { +// pet.AddMana(sim, pet.MaxMana()*restorePct, impSoulLeechPetManaMetric) +// } + +// if sim.Proc(impSoulLeechProcChance, "ImprovedSoulLeech") { +// warlock.Env.Raid.ProcReplenishment(sim, replSrc) +// } +// } +// }, +// }) +// } + +// func (warlock *Warlock) updateDPASP(sim *core.Simulation) { +// if sim.CurrentTime < 0 { +// return +// } + +// dpspCurrent := warlock.DemonicPactAura.ExclusiveEffects[0].Priority +// currentTimeJump := sim.CurrentTime.Seconds() - warlock.PreviousTime.Seconds() + +// if currentTimeJump > 0 { +// warlock.DPSPAggregate += dpspCurrent * currentTimeJump +// warlock.Metrics.UpdateDpasp(dpspCurrent * currentTimeJump) + +// if sim.Log != nil { +// warlock.Log(sim, "[Info] Demonic Pact spell power bonus average [%.0f]", +// warlock.DPSPAggregate/sim.CurrentTime.Seconds()) +// } +// } + +// warlock.PreviousTime = sim.CurrentTime +// } + +// func (warlock *Warlock) setupDemonicPact() { +// if warlock.Talents.DemonicPact == 0 { +// return +// } + +// dpMult := 0.02 * float64(warlock.Talents.DemonicPact) +// warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= 1. + dpMult +// warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= 1. + dpMult +// warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexArcane] *= 1. + dpMult +// warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] *= 1. + dpMult +// warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexHoly] *= 1. + dpMult + +// if warlock.Options.Summon == proto.WarlockOptions_NoSummon { +// return +// } + +// icd := core.Cooldown{ +// Timer: warlock.NewTimer(), +// Duration: 1 * time.Second, +// } + +// var demonicPactAuras [25]*core.Aura +// for _, party := range warlock.Party.Raid.Parties { +// for _, player := range party.Players { +// demonicPactAuras[player.GetCharacter().Index] = core.DemonicPactAura(player.GetCharacter()) +// } +// } +// warlock.DemonicPactAura = demonicPactAuras[warlock.Index] + +// warlock.Pet.RegisterAura(core.Aura{ +// Label: "Demonic Pact Hidden Aura", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// warlock.PreviousTime = 0 +// aura.Activate(sim) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warlock.updateDPASP(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.DidCrit() || !icd.IsReady(sim) { +// return +// } + +// icd.Use(sim) + +// lastBonus := 0.0 +// if warlock.DemonicPactAura.IsActive() { +// lastBonus = warlock.DemonicPactAura.ExclusiveEffects[0].Priority +// } +// newSPBonus := math.Round(dpMult * (warlock.GetStat(stats.SpellPower) - lastBonus)) + +// if warlock.DemonicPactAura.RemainingDuration(sim) < 10*time.Second || newSPBonus >= lastBonus { +// warlock.updateDPASP(sim) +// for _, dpAura := range demonicPactAuras { +// if dpAura != nil { +// dpAura.ExclusiveEffects[0].SetPriority(sim, newSPBonus) +// dpAura.Activate(sim) +// } +// } +// } +// }, +// }) +// } diff --git a/sim/warlock/warlock.go b/sim/warlock/warlock.go index e81656df02..b74e4b7d58 100644 --- a/sim/warlock/warlock.go +++ b/sim/warlock/warlock.go @@ -5,7 +5,6 @@ import ( "github.com/wowsims/cata/sim/core" "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" ) var TalentTreeSizes = [3]int{28, 27, 26} @@ -15,7 +14,7 @@ type Warlock struct { Talents *proto.WarlockTalents Options *proto.WarlockOptions - Pet *WarlockPet + //Pet *WarlockPet ShadowBolt *core.Spell Incinerate *core.Spell @@ -62,7 +61,7 @@ type Warlock struct { GlyphOfLifeTapAura *core.Aura SpiritsoftheDamnedAura *core.Aura - Infernal *InfernalPet + //Infernal *InfernalPet Inferno *core.Spell // The sum total of demonic pact spell power * seconds. @@ -88,69 +87,69 @@ func (warlock *Warlock) GrandFirestoneBonus() float64 { } func (warlock *Warlock) Initialize() { - warlock.registerIncinerateSpell() - warlock.registerShadowBoltSpell() - warlock.registerImmolateSpell() - warlock.registerCorruptionSpell() - warlock.registerCurseOfElementsSpell() - warlock.registerCurseOfWeaknessSpell() - warlock.registerCurseOfTonguesSpell() - warlock.registerCurseOfAgonySpell() - warlock.registerCurseOfDoomSpell() - warlock.registerLifeTapSpell() - warlock.registerSeedSpell() - warlock.registerSoulFireSpell() - warlock.registerUnstableAfflictionSpell() - warlock.registerDrainSoulSpell() - warlock.registerConflagrateSpell() - warlock.registerHauntSpell() - warlock.registerChaosBoltSpell() - warlock.registerDemonicEmpowermentSpell() - warlock.registerMetamorphosisSpell() - warlock.registerDarkPactSpell() - warlock.registerShadowBurnSpell() - warlock.registerSearingPainSpell() - warlock.registerInfernoSpell() - warlock.registerBlackBook() - - // Do this post-finalize so cast speed is updated with new stats - warlock.Env.RegisterPostFinalizeEffect(func() { - // if itemswap is enabled, correct for any possible haste changes - var correction stats.Stats - if warlock.ItemSwap.IsEnabled() { - correction = warlock.ItemSwap.CalcStatChanges([]proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand, - proto.ItemSlot_ItemSlotOffHand, proto.ItemSlot_ItemSlotRanged}) - - warlock.AddStats(correction) - warlock.MultiplyCastSpeed(1.0) - } - - if warlock.Options.Summon != proto.WarlockOptions_NoSummon && warlock.Talents.DemonicKnowledge > 0 { - warlock.RegisterPrepullAction(-999*time.Second, func(sim *core.Simulation) { - // TODO: investigate a better way of handling this like a "reverse inheritance" for pets. - // TODO: this will break if we ever get stamina/intellect from procs, but there aren't - // many such effects and none that we care about - bonus := (warlock.Pet.GetStat(stats.Stamina) + warlock.Pet.GetStat(stats.Intellect)) * - (0.04 * float64(warlock.Talents.DemonicKnowledge)) - if bonus != warlock.petStmBonusSP { - warlock.AddStatDynamic(sim, stats.SpellPower, bonus-warlock.petStmBonusSP) - warlock.petStmBonusSP = bonus - } - }) - } - }) + // warlock.registerIncinerateSpell() + // warlock.registerShadowBoltSpell() + // warlock.registerImmolateSpell() + // warlock.registerCorruptionSpell() + // warlock.registerCurseOfElementsSpell() + // warlock.registerCurseOfWeaknessSpell() + // warlock.registerCurseOfTonguesSpell() + // warlock.registerCurseOfAgonySpell() + // warlock.registerCurseOfDoomSpell() + // warlock.registerLifeTapSpell() + // warlock.registerSeedSpell() + // warlock.registerSoulFireSpell() + // warlock.registerUnstableAfflictionSpell() + // warlock.registerDrainSoulSpell() + // warlock.registerConflagrateSpell() + // warlock.registerHauntSpell() + // warlock.registerChaosBoltSpell() + // warlock.registerDemonicEmpowermentSpell() + // warlock.registerMetamorphosisSpell() + // warlock.registerDarkPactSpell() + // warlock.registerShadowBurnSpell() + // warlock.registerSearingPainSpell() + // warlock.registerInfernoSpell() + // warlock.registerBlackBook() + + // // Do this post-finalize so cast speed is updated with new stats + // warlock.Env.RegisterPostFinalizeEffect(func() { + // // if itemswap is enabled, correct for any possible haste changes + // var correction stats.Stats + // if warlock.ItemSwap.IsEnabled() { + // correction = warlock.ItemSwap.CalcStatChanges([]proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand, + // proto.ItemSlot_ItemSlotOffHand, proto.ItemSlot_ItemSlotRanged}) + + // warlock.AddStats(correction) + // warlock.MultiplyCastSpeed(1.0) + // } + + // if warlock.Options.Summon != proto.WarlockOptions_NoSummon && warlock.Talents.DemonicKnowledge > 0 { + // warlock.RegisterPrepullAction(-999*time.Second, func(sim *core.Simulation) { + // // TODO: investigate a better way of handling this like a "reverse inheritance" for pets. + // // TODO: this will break if we ever get stamina/intellect from procs, but there aren't + // // many such effects and none that we care about + // bonus := (warlock.Pet.GetStat(stats.Stamina) + warlock.Pet.GetStat(stats.Intellect)) * + // (0.04 * float64(warlock.Talents.DemonicKnowledge)) + // if bonus != warlock.petStmBonusSP { + // warlock.AddStatDynamic(sim, stats.SpellPower, bonus-warlock.petStmBonusSP) + // warlock.petStmBonusSP = bonus + // } + // }) + // } + // }) } func (warlock *Warlock) AddRaidBuffs(raidBuffs *proto.RaidBuffs) { - raidBuffs.BloodPact = max(raidBuffs.BloodPact, core.MakeTristateValue( - warlock.Options.Summon == proto.WarlockOptions_Imp, - warlock.Talents.ImprovedImp == 2, - )) - - raidBuffs.FelIntelligence = max(raidBuffs.FelIntelligence, core.MakeTristateValue( - warlock.Options.Summon == proto.WarlockOptions_Felhunter, - warlock.Talents.ImprovedFelhunter == 2, - )) + // raidBuffs.BloodPact = max(raidBuffs.BloodPact, core.MakeTristateValue( + // warlock.Options.Summon == proto.WarlockOptions_Imp, + // warlock.Talents.ImprovedImp == 2, + // )) + + // raidBuffs.FelIntelligence = max(raidBuffs.FelIntelligence, core.MakeTristateValue( + // warlock.Options.Summon == proto.WarlockOptions_Felhunter, + // warlock.Talents.ImprovedFelhunter == 2, + // )) } func (warlock *Warlock) Reset(sim *core.Simulation) { @@ -165,25 +164,25 @@ func NewWarlock(character *core.Character, options *proto.Player, warlockOptions Talents: &proto.WarlockTalents{}, Options: warlockOptions, } - core.FillTalentsProto(warlock.Talents.ProtoReflect(), options.TalentsString, TalentTreeSizes) - warlock.EnableManaBar() + // core.FillTalentsProto(warlock.Talents.ProtoReflect(), options.TalentsString, TalentTreeSizes) + // warlock.EnableManaBar() - warlock.AddStatDependency(stats.Strength, stats.AttackPower, 1) + // warlock.AddStatDependency(stats.Strength, stats.AttackPower, 1) - if warlock.Options.Armor == proto.WarlockOptions_FelArmor { - demonicAegisMultiplier := 1 + float64(warlock.Talents.DemonicAegis)*0.1 - amount := 180.0 * demonicAegisMultiplier - warlock.AddStat(stats.SpellPower, amount) - warlock.AddStatDependency(stats.Spirit, stats.SpellPower, 0.3*demonicAegisMultiplier) - } + // if warlock.Options.Armor == proto.WarlockOptions_FelArmor { + // demonicAegisMultiplier := 1 + float64(warlock.Talents.DemonicAegis)*0.1 + // amount := 180.0 * demonicAegisMultiplier + // warlock.AddStat(stats.SpellPower, amount) + // warlock.AddStatDependency(stats.Spirit, stats.SpellPower, 0.3*demonicAegisMultiplier) + // } - if warlock.Options.Summon != proto.WarlockOptions_NoSummon { - warlock.Pet = warlock.NewWarlockPet() - } + // if warlock.Options.Summon != proto.WarlockOptions_NoSummon { + // warlock.Pet = warlock.NewWarlockPet() + // } - warlock.Infernal = warlock.NewInfernal() + // warlock.Infernal = warlock.NewInfernal() - warlock.applyWeaponImbue() + // warlock.applyWeaponImbue() return warlock } diff --git a/sim/warrior/berserker_rage.go b/sim/warrior/_berserker_rage.go similarity index 100% rename from sim/warrior/berserker_rage.go rename to sim/warrior/_berserker_rage.go diff --git a/sim/warrior/bloodrage.go b/sim/warrior/_bloodrage.go similarity index 100% rename from sim/warrior/bloodrage.go rename to sim/warrior/_bloodrage.go diff --git a/sim/warrior/bloodthirst.go b/sim/warrior/_bloodthirst.go similarity index 100% rename from sim/warrior/bloodthirst.go rename to sim/warrior/_bloodthirst.go diff --git a/sim/warrior/concussion_blow.go b/sim/warrior/_concussion_blow.go similarity index 100% rename from sim/warrior/concussion_blow.go rename to sim/warrior/_concussion_blow.go diff --git a/sim/warrior/deep_wounds.go b/sim/warrior/_deep_wounds.go similarity index 100% rename from sim/warrior/deep_wounds.go rename to sim/warrior/_deep_wounds.go diff --git a/sim/warrior/demoralizing_shout.go b/sim/warrior/_demoralizing_shout.go similarity index 100% rename from sim/warrior/demoralizing_shout.go rename to sim/warrior/_demoralizing_shout.go diff --git a/sim/warrior/devastate.go b/sim/warrior/_devastate.go similarity index 100% rename from sim/warrior/devastate.go rename to sim/warrior/_devastate.go diff --git a/sim/warrior/execute.go b/sim/warrior/_execute.go similarity index 100% rename from sim/warrior/execute.go rename to sim/warrior/_execute.go diff --git a/sim/warrior/heroic_strike_cleave.go b/sim/warrior/_heroic_strike_cleave.go similarity index 100% rename from sim/warrior/heroic_strike_cleave.go rename to sim/warrior/_heroic_strike_cleave.go diff --git a/sim/warrior/heroic_throw.go b/sim/warrior/_heroic_throw.go similarity index 100% rename from sim/warrior/heroic_throw.go rename to sim/warrior/_heroic_throw.go diff --git a/sim/warrior/items.go b/sim/warrior/_items.go similarity index 100% rename from sim/warrior/items.go rename to sim/warrior/_items.go diff --git a/sim/warrior/mortal_strike.go b/sim/warrior/_mortal_strike.go similarity index 100% rename from sim/warrior/mortal_strike.go rename to sim/warrior/_mortal_strike.go diff --git a/sim/warrior/overpower.go b/sim/warrior/_overpower.go similarity index 100% rename from sim/warrior/overpower.go rename to sim/warrior/_overpower.go diff --git a/sim/warrior/recklessness.go b/sim/warrior/_recklessness.go similarity index 100% rename from sim/warrior/recklessness.go rename to sim/warrior/_recklessness.go diff --git a/sim/warrior/rend.go b/sim/warrior/_rend.go similarity index 100% rename from sim/warrior/rend.go rename to sim/warrior/_rend.go diff --git a/sim/warrior/revenge.go b/sim/warrior/_revenge.go similarity index 100% rename from sim/warrior/revenge.go rename to sim/warrior/_revenge.go diff --git a/sim/warrior/shattering_throw.go b/sim/warrior/_shattering_throw.go similarity index 100% rename from sim/warrior/shattering_throw.go rename to sim/warrior/_shattering_throw.go diff --git a/sim/warrior/shield_block.go b/sim/warrior/_shield_block.go similarity index 100% rename from sim/warrior/shield_block.go rename to sim/warrior/_shield_block.go diff --git a/sim/warrior/shield_slam.go b/sim/warrior/_shield_slam.go similarity index 100% rename from sim/warrior/shield_slam.go rename to sim/warrior/_shield_slam.go diff --git a/sim/warrior/shield_wall.go b/sim/warrior/_shield_wall.go similarity index 100% rename from sim/warrior/shield_wall.go rename to sim/warrior/_shield_wall.go diff --git a/sim/warrior/shockwave.go b/sim/warrior/_shockwave.go similarity index 100% rename from sim/warrior/shockwave.go rename to sim/warrior/_shockwave.go diff --git a/sim/warrior/shouts.go b/sim/warrior/_shouts.go similarity index 100% rename from sim/warrior/shouts.go rename to sim/warrior/_shouts.go diff --git a/sim/warrior/slam.go b/sim/warrior/_slam.go similarity index 100% rename from sim/warrior/slam.go rename to sim/warrior/_slam.go diff --git a/sim/warrior/stances.go b/sim/warrior/_stances.go similarity index 100% rename from sim/warrior/stances.go rename to sim/warrior/_stances.go diff --git a/sim/warrior/sunder_armor.go b/sim/warrior/_sunder_armor.go similarity index 100% rename from sim/warrior/sunder_armor.go rename to sim/warrior/_sunder_armor.go diff --git a/sim/warrior/sweeping_strikes.go b/sim/warrior/_sweeping_strikes.go similarity index 100% rename from sim/warrior/sweeping_strikes.go rename to sim/warrior/_sweeping_strikes.go diff --git a/sim/warrior/thunder_clap.go b/sim/warrior/_thunder_clap.go similarity index 100% rename from sim/warrior/thunder_clap.go rename to sim/warrior/_thunder_clap.go diff --git a/sim/warrior/whirlwind.go b/sim/warrior/_whirlwind.go similarity index 100% rename from sim/warrior/whirlwind.go rename to sim/warrior/_whirlwind.go diff --git a/sim/warrior/arms/arms_test.go b/sim/warrior/arms/_arms_test.go similarity index 100% rename from sim/warrior/arms/arms_test.go rename to sim/warrior/arms/_arms_test.go diff --git a/sim/warrior/arms/arms.go b/sim/warrior/arms/arms.go index c44cb584b4..3c32670d22 100644 --- a/sim/warrior/arms/arms.go +++ b/sim/warrior/arms/arms.go @@ -39,24 +39,24 @@ func NewArmsWarrior(character *core.Character, options *proto.Player) *ArmsWarri Options: armsOptions, } - rbo := core.RageBarOptions{ - StartingRage: armsOptions.ClassOptions.StartingRage, - RageMultiplier: core.TernaryFloat64(war.Talents.EndlessRage, 1.25, 1), - } - if mh := war.GetMHWeapon(); mh != nil { - rbo.MHSwingSpeed = mh.SwingSpeed - } - if oh := war.GetOHWeapon(); oh != nil { - rbo.OHSwingSpeed = oh.SwingSpeed - } + // rbo := core.RageBarOptions{ + // StartingRage: armsOptions.ClassOptions.StartingRage, + // RageMultiplier: core.TernaryFloat64(war.Talents.EndlessRage, 1.25, 1), + // } + // if mh := war.GetMHWeapon(); mh != nil { + // rbo.MHSwingSpeed = mh.SwingSpeed + // } + // if oh := war.GetOHWeapon(); oh != nil { + // rbo.OHSwingSpeed = oh.SwingSpeed + // } - war.EnableRageBar(rbo) - war.EnableAutoAttacks(war, core.AutoAttackOptions{ - MainHand: war.WeaponFromMainHand(war.DefaultMeleeCritMultiplier()), - OffHand: war.WeaponFromOffHand(war.DefaultMeleeCritMultiplier()), - AutoSwingMelee: true, - ReplaceMHSwing: war.TryHSOrCleave, - }) + // war.EnableRageBar(rbo) + // war.EnableAutoAttacks(war, core.AutoAttackOptions{ + // MainHand: war.WeaponFromMainHand(war.DefaultMeleeCritMultiplier()), + // OffHand: war.WeaponFromOffHand(war.DefaultMeleeCritMultiplier()), + // AutoSwingMelee: true, + // ReplaceMHSwing: war.TryHSOrCleave, + // }) return war } @@ -68,19 +68,19 @@ func (war *ArmsWarrior) GetWarrior() *warrior.Warrior { func (war *ArmsWarrior) Initialize() { war.Warrior.Initialize() - if war.Options.UseRecklessness { - war.RegisterRecklessnessCD() - } + // if war.Options.UseRecklessness { + // war.RegisterRecklessnessCD() + // } - if war.Options.ClassOptions.UseShatteringThrow { - war.RegisterShatteringThrowCD() - } + // if war.Options.ClassOptions.UseShatteringThrow { + // war.RegisterShatteringThrowCD() + // } - war.BattleStanceAura.BuildPhase = core.CharacterBuildPhaseTalents + // war.BattleStanceAura.BuildPhase = core.CharacterBuildPhaseTalents } -func (war *ArmsWarrior) Reset(sim *core.Simulation) { - war.Warrior.Reset(sim) - war.BattleStanceAura.Activate(sim) - war.Stance = warrior.BattleStance -} +// func (war *ArmsWarrior) Reset(sim *core.Simulation) { +// war.Warrior.Reset(sim) +// war.BattleStanceAura.Activate(sim) +// war.Stance = warrior.BattleStance +// } diff --git a/sim/warrior/fury/fury.go b/sim/warrior/fury/fury.go index cc7d041c16..9cf464fa8f 100644 --- a/sim/warrior/fury/fury.go +++ b/sim/warrior/fury/fury.go @@ -39,24 +39,24 @@ func NewFuryWarrior(character *core.Character, options *proto.Player) *FuryWarri Options: furyOptions, } - rbo := core.RageBarOptions{ - StartingRage: furyOptions.ClassOptions.StartingRage, - RageMultiplier: core.TernaryFloat64(war.Talents.EndlessRage, 1.25, 1), - } - if mh := war.GetMHWeapon(); mh != nil { - rbo.MHSwingSpeed = mh.SwingSpeed - } - if oh := war.GetOHWeapon(); oh != nil { - rbo.OHSwingSpeed = oh.SwingSpeed - } + // rbo := core.RageBarOptions{ + // StartingRage: furyOptions.ClassOptions.StartingRage, + // RageMultiplier: core.TernaryFloat64(war.Talents.EndlessRage, 1.25, 1), + // } + // if mh := war.GetMHWeapon(); mh != nil { + // rbo.MHSwingSpeed = mh.SwingSpeed + // } + // if oh := war.GetOHWeapon(); oh != nil { + // rbo.OHSwingSpeed = oh.SwingSpeed + // } - war.EnableRageBar(rbo) - war.EnableAutoAttacks(war, core.AutoAttackOptions{ - MainHand: war.WeaponFromMainHand(war.DefaultMeleeCritMultiplier()), - OffHand: war.WeaponFromOffHand(war.DefaultMeleeCritMultiplier()), - AutoSwingMelee: true, - ReplaceMHSwing: war.TryHSOrCleave, - }) + // war.EnableRageBar(rbo) + // war.EnableAutoAttacks(war, core.AutoAttackOptions{ + // MainHand: war.WeaponFromMainHand(war.DefaultMeleeCritMultiplier()), + // OffHand: war.WeaponFromOffHand(war.DefaultMeleeCritMultiplier()), + // AutoSwingMelee: true, + // ReplaceMHSwing: war.TryHSOrCleave, + // }) return war } @@ -68,19 +68,19 @@ func (war *FuryWarrior) GetWarrior() *warrior.Warrior { func (war *FuryWarrior) Initialize() { war.Warrior.Initialize() - if war.Options.UseRecklessness { - war.RegisterRecklessnessCD() - } + // if war.Options.UseRecklessness { + // war.RegisterRecklessnessCD() + // } - if war.Options.ClassOptions.UseShatteringThrow { - war.RegisterShatteringThrowCD() - } + // if war.Options.ClassOptions.UseShatteringThrow { + // war.RegisterShatteringThrowCD() + // } - war.BerserkerStanceAura.BuildPhase = core.CharacterBuildPhaseTalents + // war.BerserkerStanceAura.BuildPhase = core.CharacterBuildPhaseTalents } func (war *FuryWarrior) Reset(sim *core.Simulation) { - war.Warrior.Reset(sim) - war.BerserkerStanceAura.Activate(sim) - war.Stance = warrior.BerserkerStance + // war.Warrior.Reset(sim) + // war.BerserkerStanceAura.Activate(sim) + // war.Stance = warrior.BerserkerStance } diff --git a/sim/warrior/protection/protection_test.go b/sim/warrior/protection/_protection_test.go similarity index 100% rename from sim/warrior/protection/protection_test.go rename to sim/warrior/protection/_protection_test.go diff --git a/sim/warrior/protection/protection.go b/sim/warrior/protection/protection.go index e1631f31fb..3a5840cfb8 100644 --- a/sim/warrior/protection/protection.go +++ b/sim/warrior/protection/protection.go @@ -37,31 +37,31 @@ func NewProtectionWarrior(character *core.Character, options *proto.Player) *Pro Options: protOptions, } - rbo := core.RageBarOptions{ - StartingRage: protOptions.ClassOptions.StartingRage, - RageMultiplier: core.TernaryFloat64(war.Talents.EndlessRage, 1.25, 1), - } - if mh := war.GetMHWeapon(); mh != nil { - rbo.MHSwingSpeed = mh.SwingSpeed - } - if oh := war.GetOHWeapon(); oh != nil { - rbo.OHSwingSpeed = oh.SwingSpeed - } + // rbo := core.RageBarOptions{ + // StartingRage: protOptions.ClassOptions.StartingRage, + // RageMultiplier: core.TernaryFloat64(war.Talents.EndlessRage, 1.25, 1), + // } + // if mh := war.GetMHWeapon(); mh != nil { + // rbo.MHSwingSpeed = mh.SwingSpeed + // } + // if oh := war.GetOHWeapon(); oh != nil { + // rbo.OHSwingSpeed = oh.SwingSpeed + // } - war.EnableRageBar(rbo) - war.EnableAutoAttacks(war, core.AutoAttackOptions{ - MainHand: war.WeaponFromMainHand(war.DefaultMeleeCritMultiplier()), - OffHand: war.WeaponFromOffHand(war.DefaultMeleeCritMultiplier()), - AutoSwingMelee: true, - ReplaceMHSwing: war.TryHSOrCleave, - }) + // war.EnableRageBar(rbo) + // war.EnableAutoAttacks(war, core.AutoAttackOptions{ + // MainHand: war.WeaponFromMainHand(war.DefaultMeleeCritMultiplier()), + // OffHand: war.WeaponFromOffHand(war.DefaultMeleeCritMultiplier()), + // AutoSwingMelee: true, + // ReplaceMHSwing: war.TryHSOrCleave, + // }) - healingModel := options.HealingModel - if healingModel != nil { - if healingModel.InspirationUptime > 0.0 { - core.ApplyInspiration(war.GetCharacter(), healingModel.InspirationUptime) - } - } + // healingModel := options.HealingModel + // if healingModel != nil { + // if healingModel.InspirationUptime > 0.0 { + // core.ApplyInspiration(war.GetCharacter(), healingModel.InspirationUptime) + // } + // } return war } @@ -73,18 +73,18 @@ func (war *ProtectionWarrior) GetWarrior() *warrior.Warrior { func (war *ProtectionWarrior) Initialize() { war.Warrior.Initialize() - war.RegisterShieldWallCD() - war.RegisterShieldBlockCD() - war.DefensiveStanceAura.BuildPhase = core.CharacterBuildPhaseTalents + // war.RegisterShieldWallCD() + // war.RegisterShieldBlockCD() + // war.DefensiveStanceAura.BuildPhase = core.CharacterBuildPhaseTalents - if war.Options.ClassOptions.UseShatteringThrow { - war.RegisterShatteringThrowCD() - } + // if war.Options.ClassOptions.UseShatteringThrow { + // war.RegisterShatteringThrowCD() + // } } func (war *ProtectionWarrior) Reset(sim *core.Simulation) { - war.Warrior.Reset(sim) - war.DefensiveStanceAura.Activate(sim) - war.Stance = warrior.DefensiveStance - war.Warrior.PseudoStats.Stunned = false + // war.Warrior.Reset(sim) + // war.DefensiveStanceAura.Activate(sim) + // war.Stance = warrior.DefensiveStance + // war.Warrior.PseudoStats.Stunned = false } diff --git a/sim/warrior/talents.go b/sim/warrior/talents.go index caa0524c9e..fdf59eafe9 100644 --- a/sim/warrior/talents.go +++ b/sim/warrior/talents.go @@ -1,928 +1,920 @@ package warrior -import ( - "time" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" -) - func (warrior *Warrior) ToughnessArmorMultiplier() float64 { return 1.0 + 0.02*float64(warrior.Talents.Toughness) } func (warrior *Warrior) ApplyTalents() { - warrior.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*1*float64(warrior.Talents.Cruelty)) - warrior.AddStat(stats.MeleeHit, core.MeleeHitRatingPerHitChance*1*float64(warrior.Talents.Precision)) - warrior.ApplyEquipScaling(stats.Armor, warrior.ToughnessArmorMultiplier()) - warrior.PseudoStats.BaseDodge += 0.01 * float64(warrior.Talents.Anticipation) - warrior.PseudoStats.BaseParry += 0.01 * float64(warrior.Talents.Deflection) - warrior.PseudoStats.DodgeReduction += 0.01 * float64(warrior.Talents.WeaponMastery) - warrior.AutoAttacks.OHConfig().DamageMultiplier *= 1 + 0.05*float64(warrior.Talents.DualWieldSpecialization) - - if warrior.Talents.ArmoredToTheTeeth > 0 { - coeff := float64(warrior.Talents.ArmoredToTheTeeth) - warrior.AddStatDependency(stats.Armor, stats.AttackPower, coeff/108.0) - } - - if warrior.Talents.StrengthOfArms > 0 { - warrior.MultiplyStat(stats.Strength, 1.0+0.02*float64(warrior.Talents.StrengthOfArms)) - warrior.MultiplyStat(stats.Stamina, 1.0+0.02*float64(warrior.Talents.StrengthOfArms)) - warrior.AddStat(stats.Expertise, core.ExpertisePerQuarterPercentReduction*2*float64(warrior.Talents.StrengthOfArms)) - } - - // Shield Mastery, Shield Block, Glyph of Blocking, Eternal Earthsiege treated as additive sources - if warrior.Talents.ShieldMastery > 0 { - warrior.PseudoStats.BlockValueMultiplier += 0.15 * float64(warrior.Talents.ShieldMastery) - } - - if warrior.Talents.Vitality > 0 { - warrior.MultiplyStat(stats.Stamina, 1.0+0.03*float64(warrior.Talents.Vitality)) - warrior.MultiplyStat(stats.Strength, 1.0+0.02*float64(warrior.Talents.Vitality)) - warrior.AddStat(stats.Expertise, core.ExpertisePerQuarterPercentReduction*2*float64(warrior.Talents.Vitality)) - } - - warrior.applyAngerManagement() - warrior.applyDeepWounds() - warrior.applyTitansGrip() - warrior.applyOneHandedWeaponSpecialization() - warrior.applyTwoHandedWeaponSpecialization() - warrior.applyWeaponSpecializations() - warrior.applyTrauma() - warrior.applyBloodFrenzy() - warrior.applyUnbridledWrath() - warrior.applyFlurry() - warrior.applyWreckingCrew() - warrior.applyShieldSpecialization() - warrior.registerDeathWishCD() - warrior.registerSweepingStrikesCD() - warrior.registerLastStandCD() - warrior.applyTasteForBlood() - warrior.applyBloodsurge() - warrior.applySuddenDeath() - warrior.RegisterBladestormCD() - warrior.applyDamageShield() - warrior.applyCriticalBlock() - warrior.applySwordAndBoard() -} - -// Multiplicative with all other modifiers and only applies to the block damage event -func (warrior *Warrior) applyCriticalBlock() { - if warrior.Talents.CriticalBlock == 0 { - return - } - - dummyCriticalBlockSpell := warrior.GetOrRegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 47296}, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagNoOnCastComplete, - }) - - warrior.AddDynamicDamageTakenModifier(func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Outcome.Matches(core.OutcomeBlock) && !result.Outcome.Matches(core.OutcomeMiss) && !result.Outcome.Matches(core.OutcomeParry) && !result.Outcome.Matches(core.OutcomeDodge) { - procChance := 0.2 * float64(warrior.Talents.CriticalBlock) - if sim.RandomFloat("Critical Block Roll") <= procChance { - blockValue := warrior.BlockValue() - result.Damage = max(0, result.Damage-blockValue) - dummyCriticalBlockSpell.Cast(sim, spell.Unit) - } - } - }) -} - -func (warrior *Warrior) applyDamageShield() { - if warrior.Talents.DamageShield == 0 { - return - } - - coeff := 0.1 * float64(warrior.Talents.DamageShield) - damageShieldProcSpell := warrior.GetOrRegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 58874}, - SpellSchool: core.SpellSchoolPhysical, - ProcMask: core.ProcMaskEmpty, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagNoOnCastComplete, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseDamage := coeff * warrior.BlockValue() - spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeAlwaysHit) - }, - }) - - core.MakePermanent(warrior.GetOrRegisterAura(core.Aura{ - Label: "Damage Shield Trigger", - Duration: core.NeverExpires, - OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() && !result.Outcome.Matches(core.OutcomeBlock) { - return - } - - if spell.SpellSchool != core.SpellSchoolPhysical { - return - } - - damageShieldProcSpell.Cast(sim, spell.Unit) - }, - })) -} - -func (warrior *Warrior) applyAngerManagement() { - if !warrior.Talents.AngerManagement { - return - } - - rageMetrics := warrior.NewRageMetrics(core.ActionID{SpellID: 12296}) - - warrior.RegisterResetEffect(func(sim *core.Simulation) { - core.StartPeriodicAction(sim, core.PeriodicActionOptions{ - Period: time.Second * 3, - OnAction: func(sim *core.Simulation) { - warrior.AddRage(sim, 1, rageMetrics) - warrior.LastAMTick = sim.CurrentTime - }, - }) - }) -} -func (warrior *Warrior) applyTasteForBlood() { - if warrior.Talents.TasteForBlood == 0 { - return - } - - procChance := []float64{0, 0.33, 0.66, 1}[warrior.Talents.TasteForBlood] - - icd := core.Cooldown{ - Timer: warrior.NewTimer(), - Duration: time.Second * 6, - } - - warrior.RegisterAura(core.Aura{ - Label: "Taste for Blood", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell != warrior.Rend { - return - } - - if !icd.IsReady(sim) { - return - } - - if sim.RandomFloat("Taste for Blood") > procChance { - return - } - - icd.Use(sim) - warrior.OverpowerAura.Duration = time.Second * 9 - warrior.OverpowerAura.Activate(sim) - warrior.OverpowerAura.Duration = time.Second * 5 - warrior.lastOverpowerProc = sim.CurrentTime - }, - }) -} - -func (warrior *Warrior) applyTrauma() { - if warrior.Talents.Trauma == 0 { - return - } - - traumaAuras := warrior.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { - return core.TraumaAura(target, int(warrior.Talents.Trauma)) - }) - - warrior.RegisterAura(core.Aura{ - Label: "Trauma", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Outcome.Matches(core.OutcomeCrit) { - return - } - - if !spell.SpellSchool.Matches(core.SpellSchoolPhysical) || !spell.ProcMask.Matches(core.ProcMaskMelee) { - return - } - - proc := traumaAuras.Get(result.Target) - proc.Duration = time.Minute * 1 - proc.Activate(sim) - }, - }) -} - -func (warrior *Warrior) isBloodsurgeActive() bool { - return warrior.BloodsurgeAura.IsActive() || (warrior.Talents.Bloodsurge > 0 && warrior.Ymirjar4pcProcAura.IsActive()) -} - -func (warrior *Warrior) applyBloodsurge() { - if warrior.Talents.Bloodsurge == 0 { - return - } - - procChance := []float64{0, 0.07, 0.13, 0.2}[warrior.Talents.Bloodsurge] - - ymirjar4Set := warrior.HasSetBonus(ItemSetYmirjarLordsBattlegear, 4) - - warrior.BloodsurgeAura = warrior.RegisterAura(core.Aura{ - Label: "Bloodsurge Proc", - ActionID: core.ActionID{SpellID: 46916}, - Duration: time.Second * 5, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warrior.Slam.DefaultCast.CastTime = 0 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.Slam.DefaultCast.CastTime = 1500 * time.Millisecond - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == warrior.Slam { // removed even if slam doesn't land - aura.Deactivate(sim) - } - }, - }) - - if ymirjar4Set { - warrior.Ymirjar4pcProcAura = warrior.RegisterAura(core.Aura{ - Label: "Ymirjar 4pc (Bloodsurge) Proc", - ActionID: core.ActionID{SpellID: 70847}, - Duration: time.Second * 10, - MaxStacks: 2, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - if warrior.BloodsurgeAura.IsActive() { - warrior.BloodsurgeAura.Deactivate(sim) - } - - aura.SetStacks(sim, aura.MaxStacks) - warrior.Slam.DefaultCast.CastTime = 0 - warrior.Slam.DefaultCast.GCD = core.GCDMin - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.Slam.DefaultCast.CastTime = 1500 * time.Millisecond - warrior.Slam.DefaultCast.GCD = core.GCDDefault - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell == warrior.Slam { - aura.RemoveStack(sim) - } - }, - }) - } - - warrior.RegisterAura(core.Aura{ - Label: "Bloodsurge", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() { - return - } - - if !spell.Flags.Matches(SpellFlagBloodsurge) { - return - } - - if sim.RandomFloat("Bloodsurge") > procChance { - return - } - - warrior.lastBloodsurgeProc = sim.CurrentTime - - // as per https://www.wowhead.com/cata/spell=70847/item-warrior-t10-melee-4p-bonus#comments, - // the improved aura is not overwritten by the regular one, but simply refreshed - if ymirjar4Set && (sim.RandomFloat("Ymirjar 4pc") < 0.2 || warrior.Ymirjar4pcProcAura.IsActive()) { - warrior.BloodsurgeAura.Deactivate(sim) - warrior.Ymirjar4pcProcAura.Activate(sim) - - warrior.BloodsurgeValidUntil = sim.CurrentTime + warrior.Ymirjar4pcProcAura.Duration - return - } - - warrior.BloodsurgeValidUntil = sim.CurrentTime + warrior.BloodsurgeAura.Duration - warrior.BloodsurgeAura.Activate(sim) - }, - }) -} -func (warrior *Warrior) applyBloodFrenzy() { - if warrior.Talents.BloodFrenzy == 0 { - return - } - - warrior.PseudoStats.MeleeSpeedMultiplier *= 1 + 0.05*float64(warrior.Talents.BloodFrenzy) - - bfAuras := warrior.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { - return core.BloodFrenzyAura(target, warrior.Talents.BloodFrenzy) - }) - warrior.Env.RegisterPreFinalizeEffect(func() { - if warrior.Rend != nil { - warrior.Rend.RelatedAuras = append(warrior.Rend.RelatedAuras, bfAuras) - } - if warrior.DeepWounds != nil { - warrior.DeepWounds.RelatedAuras = append(warrior.DeepWounds.RelatedAuras, bfAuras) - } - }) - - warrior.RegisterAura(core.Aura{ - Label: "Blood Frenzy Talent", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() { - return - } - - if spell == warrior.Rend || spell == warrior.DeepWounds { - aura := bfAuras.Get(result.Target) - dot := warrior.Rend.Dot(result.Target) - aura.Duration = dot.TickLength * time.Duration(dot.NumberOfTicks) - aura.Activate(sim) - } - }, - }) -} - -func (warrior *Warrior) applyTitansGrip() { - if !warrior.Talents.TitansGrip { - return - } - if !warrior.AutoAttacks.IsDualWielding { - return - } - if warrior.MainHand().HandType != proto.HandType_HandTypeTwoHand && warrior.OffHand().HandType != proto.HandType_HandTypeTwoHand { - return - } - - warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 - 0.1 -} - -func (warrior *Warrior) applyTwoHandedWeaponSpecialization() { - if warrior.Talents.TwoHandedWeaponSpecialization == 0 { - return - } - if warrior.MainHand().HandType != proto.HandType_HandTypeTwoHand { - return - } - - warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 + 0.02*float64(warrior.Talents.TwoHandedWeaponSpecialization) -} - -func (warrior *Warrior) applyOneHandedWeaponSpecialization() { - if warrior.Talents.OneHandedWeaponSpecialization == 0 { - return - } - if warrior.MainHand().HandType == proto.HandType_HandTypeTwoHand { - return - } - - warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 + 0.02*float64(warrior.Talents.OneHandedWeaponSpecialization) + // warrior.AddStat(stats.MeleeCrit, core.CritRatingPerCritChance*1*float64(warrior.Talents.Cruelty)) + // warrior.AddStat(stats.MeleeHit, core.MeleeHitRatingPerHitChance*1*float64(warrior.Talents.Precision)) + // warrior.ApplyEquipScaling(stats.Armor, warrior.ToughnessArmorMultiplier()) + // warrior.PseudoStats.BaseDodge += 0.01 * float64(warrior.Talents.Anticipation) + // warrior.PseudoStats.BaseParry += 0.01 * float64(warrior.Talents.Deflection) + // warrior.PseudoStats.DodgeReduction += 0.01 * float64(warrior.Talents.WeaponMastery) + // warrior.AutoAttacks.OHConfig().DamageMultiplier *= 1 + 0.05*float64(warrior.Talents.DualWieldSpecialization) + + // if warrior.Talents.ArmoredToTheTeeth > 0 { + // coeff := float64(warrior.Talents.ArmoredToTheTeeth) + // warrior.AddStatDependency(stats.Armor, stats.AttackPower, coeff/108.0) + // } + + // if warrior.Talents.StrengthOfArms > 0 { + // warrior.MultiplyStat(stats.Strength, 1.0+0.02*float64(warrior.Talents.StrengthOfArms)) + // warrior.MultiplyStat(stats.Stamina, 1.0+0.02*float64(warrior.Talents.StrengthOfArms)) + // warrior.AddStat(stats.Expertise, core.ExpertisePerQuarterPercentReduction*2*float64(warrior.Talents.StrengthOfArms)) + // } + + // // Shield Mastery, Shield Block, Glyph of Blocking, Eternal Earthsiege treated as additive sources + // if warrior.Talents.ShieldMastery > 0 { + // warrior.PseudoStats.BlockValueMultiplier += 0.15 * float64(warrior.Talents.ShieldMastery) + // } + + // if warrior.Talents.Vitality > 0 { + // warrior.MultiplyStat(stats.Stamina, 1.0+0.03*float64(warrior.Talents.Vitality)) + // warrior.MultiplyStat(stats.Strength, 1.0+0.02*float64(warrior.Talents.Vitality)) + // warrior.AddStat(stats.Expertise, core.ExpertisePerQuarterPercentReduction*2*float64(warrior.Talents.Vitality)) + // } + + // warrior.applyAngerManagement() + // warrior.applyDeepWounds() + // warrior.applyTitansGrip() + // warrior.applyOneHandedWeaponSpecialization() + // warrior.applyTwoHandedWeaponSpecialization() + // warrior.applyWeaponSpecializations() + // warrior.applyTrauma() + // warrior.applyBloodFrenzy() + // warrior.applyUnbridledWrath() + // warrior.applyFlurry() + // warrior.applyWreckingCrew() + // warrior.applyShieldSpecialization() + // warrior.registerDeathWishCD() + // warrior.registerSweepingStrikesCD() + // warrior.registerLastStandCD() + // warrior.applyTasteForBlood() + // warrior.applyBloodsurge() + // warrior.applySuddenDeath() + // warrior.RegisterBladestormCD() + // warrior.applyDamageShield() + // warrior.applyCriticalBlock() + // warrior.applySwordAndBoard() } -func (warrior *Warrior) applyWeaponSpecializations() { - if ss := warrior.Talents.SwordSpecialization; ss > 0 { - if mask := warrior.GetProcMaskForTypes(proto.WeaponType_WeaponTypeSword); mask != core.ProcMaskUnknown { - warrior.registerSwordSpecialization(mask) - } - } - - if pas := warrior.Talents.PoleaxeSpecialization; pas > 0 { - // the default character pane displays critical strike chance for main hand only - switch warrior.GetProcMaskForTypes(proto.WeaponType_WeaponTypeAxe, proto.WeaponType_WeaponTypePolearm) { - case core.ProcMaskMelee: - warrior.AddStat(stats.MeleeCrit, 1*core.CritRatingPerCritChance*float64(pas)) - case core.ProcMaskMeleeMH: - warrior.AddStat(stats.MeleeCrit, 1*core.CritRatingPerCritChance*float64(pas)) - warrior.OnSpellRegistered(func(spell *core.Spell) { - if spell.ProcMask.Matches(core.ProcMaskMeleeOH) { - spell.BonusCritRating -= 1 * core.CritRatingPerCritChance * float64(pas) - } - }) - case core.ProcMaskMeleeOH: - warrior.OnSpellRegistered(func(spell *core.Spell) { - if spell.ProcMask.Matches(core.ProcMaskMeleeOH) { - spell.BonusCritRating += 1 * core.CritRatingPerCritChance * float64(pas) - } - }) - } - } - - if ms := warrior.Talents.MaceSpecialization; ms > 0 { - if mask := warrior.GetProcMaskForTypes(proto.WeaponType_WeaponTypeMace); mask != core.ProcMaskEmpty { - warrior.AddStat(stats.ArmorPenetration, 3*core.ArmorPenPerPercentArmor*float64(ms)) - } - } -} - -func (warrior *Warrior) registerSwordSpecialization(procMask core.ProcMask) { - var swordSpecializationSpell *core.Spell - icd := core.Cooldown{ - Timer: warrior.NewTimer(), - Duration: time.Second * 6, - } - procChance := 0.02 * float64(warrior.Talents.SwordSpecialization) - - warrior.RegisterAura(core.Aura{ - Label: "Sword Specialization", - Duration: core.NeverExpires, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - config := *warrior.AutoAttacks.MHConfig() - config.ActionID = core.ActionID{SpellID: 12281} - swordSpecializationSpell = warrior.GetOrRegisterSpell(config) - }, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() { - return - } - if !spell.ProcMask.Matches(procMask) { - return - } - if spell == warrior.WhirlwindOH { - return // OH WW hits can't proc this - } - if !icd.IsReady(sim) { - return - } - if sim.RandomFloat("Sword Specialization") < procChance { - icd.Use(sim) - aura.Unit.AutoAttacks.MaybeReplaceMHSwing(sim, swordSpecializationSpell).Cast(sim, result.Target) - } - }, - }) -} - -func (warrior *Warrior) applyUnbridledWrath() { - if warrior.Talents.UnbridledWrath == 0 { - return - } - - ppmm := warrior.AutoAttacks.NewPPMManager(3*float64(warrior.Talents.UnbridledWrath), core.ProcMaskMeleeWhiteHit) - - rageMetrics := warrior.NewRageMetrics(core.ActionID{SpellID: 13002}) - - warrior.RegisterAura(core.Aura{ - Label: "Unbridled Wrath", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Damage == 0 { - return - } - - if ppmm.Proc(sim, spell.ProcMask, "Unbrided Wrath") { - warrior.AddRage(sim, 1, rageMetrics) - } - }, - }) -} - -func (warrior *Warrior) applyFlurry() { - if warrior.Talents.Flurry == 0 { - return - } - - bonus := 1 + 0.05*float64(warrior.Talents.Flurry) - inverseBonus := 1 / bonus - - procAura := warrior.RegisterAura(core.Aura{ - Label: "Flurry Proc", - ActionID: core.ActionID{SpellID: 12974}, - Duration: core.NeverExpires, - MaxStacks: 3, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warrior.MultiplyMeleeSpeed(sim, bonus) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.MultiplyMeleeSpeed(sim, inverseBonus) - }, - }) - - warrior.RegisterAura(core.Aura{ - Label: "Flurry", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskMelee) && !spell.Flags.Matches(SpellFlagWhirlwindOH) { - return - } - - if result.Outcome.Matches(core.OutcomeCrit) { - procAura.Activate(sim) - procAura.SetStacks(sim, 3) - return - } - - // Remove a stack. - if procAura.IsActive() && spell.ProcMask.Matches(core.ProcMaskMeleeWhiteHit) { - procAura.RemoveStack(sim) - } - }, - }) -} - -func (warrior *Warrior) applyWreckingCrew() { - if warrior.Talents.WreckingCrew == 0 { - return - } - - bonus := 1 + 0.02*float64(warrior.Talents.WreckingCrew) - - procAura := warrior.RegisterAura(core.Aura{ - Label: "Enrage", - ActionID: core.ActionID{SpellID: 57518}, - Duration: time.Second * 12, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= bonus - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= bonus - }, - }) - warrior.RegisterAura(core.Aura{ - Label: "Wrecking Crew", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskMelee) { - return - } - - if !result.Outcome.Matches(core.OutcomeCrit) { - return - } - - procAura.Activate(sim) - }, - }) - core.RegisterPercentDamageModifierEffect(procAura, bonus) -} - -func (warrior *Warrior) IsSuddenDeathActive() bool { - return warrior.SuddenDeathAura.IsActive() || (warrior.Talents.SuddenDeath > 0 && warrior.Ymirjar4pcProcAura.IsActive()) -} - -func (warrior *Warrior) applySuddenDeath() { - if warrior.Talents.SuddenDeath == 0 { - return - } - - rageMetrics := warrior.NewRageMetrics(core.ActionID{SpellID: 29724}) - - minRageKept := []float64{0, 3, 7, 10}[warrior.Talents.SuddenDeath] - procChance := []float64{0, 0.03, 0.06, 0.09}[warrior.Talents.SuddenDeath] - - warrior.SuddenDeathAura = warrior.RegisterAura(core.Aura{ - Label: "Sudden Death Proc", - ActionID: core.ActionID{SpellID: 29724}, - Duration: time.Second * 10, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() || spell != warrior.Execute { // removed only when landed - return - } - if rageRefund := minRageKept - warrior.CurrentRage(); rageRefund > 0 { // refund only when below minRageKept - warrior.AddRage(sim, rageRefund, rageMetrics) - } - aura.Deactivate(sim) - }, - }) - - ymirjar4Set := warrior.HasSetBonus(ItemSetYmirjarLordsBattlegear, 4) - - if ymirjar4Set { - warrior.Ymirjar4pcProcAura = warrior.RegisterAura(core.Aura{ - Label: "Ymirjar 4pc (Sudden Death) Proc", - ActionID: core.ActionID{SpellID: 70847}, - Duration: time.Second * 20, - MaxStacks: 2, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.SetStacks(sim, aura.MaxStacks) - warrior.Execute.DefaultCast.GCD = core.GCDMin - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.Execute.DefaultCast.GCD = core.GCDDefault - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() || spell != warrior.Execute { - return - } - if rageRefund := minRageKept - warrior.CurrentRage(); rageRefund > 0 { - warrior.AddRage(sim, rageRefund, rageMetrics) - } - aura.RemoveStack(sim) - }, - }) - } - - warrior.RegisterAura(core.Aura{ - Label: "Sudden Death", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() || !spell.ProcMask.Matches(core.ProcMaskMelee) { - return - } - - if sim.RandomFloat("Sudden Death") > procChance { - return - } - - // as per https://www.wowhead.com/cata/spell=70847/item-warrior-t10-melee-4p-bonus#comments, - // the improved aura is not overwritten by the regular one, but simply refreshed - if ymirjar4Set && (warrior.Ymirjar4pcProcAura.IsActive() || sim.RandomFloat("Ymirjar 4pc") < 0.2) { - warrior.SuddenDeathAura.Deactivate(sim) - - warrior.Ymirjar4pcProcAura.Activate(sim) - return - } - - warrior.SuddenDeathAura.Activate(sim) - }, - }) -} - -func (warrior *Warrior) applyShieldSpecialization() { - if warrior.Talents.ShieldSpecialization == 0 { - return - } - - warrior.AddStat(stats.Block, core.BlockRatingPerBlockChance*1*float64(warrior.Talents.ShieldSpecialization)) - - procChance := 0.2 * float64(warrior.Talents.ShieldSpecialization) - rageAdded := float64(warrior.Talents.ShieldSpecialization) - rageMetrics := warrior.NewRageMetrics(core.ActionID{SpellID: 12727}) - - warrior.RegisterAura(core.Aura{ - Label: "Shield Specialization", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Outcome.Matches(core.OutcomeBlock | core.OutcomeDodge | core.OutcomeParry) { - if sim.Proc(procChance, "Shield Specialization") { - warrior.AddRage(sim, rageAdded, rageMetrics) - } - } - }, - }) -} - -func (warrior *Warrior) registerDeathWishCD() { - if !warrior.Talents.DeathWish { - return - } - - actionID := core.ActionID{SpellID: 12292} - - deathWishAura := warrior.RegisterAura(core.Aura{ - Label: "Death Wish", - ActionID: actionID, - Duration: time.Second * 30, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1.2 - warrior.PseudoStats.DamageTakenMultiplier *= 1.05 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= 1.2 - warrior.PseudoStats.DamageTakenMultiplier /= 1.05 - }, - }) - core.RegisterPercentDamageModifierEffect(deathWishAura, 1.2) - - deathWishSpell := warrior.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - - RageCost: core.RageCostOptions{ - Cost: 10, - }, - Cast: core.CastConfig{ - IgnoreHaste: true, - CD: core.Cooldown{ - Timer: warrior.NewTimer(), - Duration: warrior.intensifyRageCooldown(time.Minute * 3), - }, - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { - deathWishAura.Activate(sim) - warrior.WaitUntil(sim, sim.CurrentTime+core.GCDDefault) - }, - }) - - warrior.AddMajorCooldown(core.MajorCooldown{ - Spell: deathWishSpell, - Type: core.CooldownTypeDPS, - }) -} - -func (warrior *Warrior) registerLastStandCD() { - if !warrior.Talents.LastStand { - return - } - - actionID := core.ActionID{SpellID: 12975} - healthMetrics := warrior.NewHealthMetrics(actionID) - - var bonusHealth float64 - lastStandAura := warrior.RegisterAura(core.Aura{ - Label: "Last Stand", - ActionID: actionID, - Duration: time.Second * 20, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - bonusHealth = warrior.MaxHealth() * 0.3 - warrior.AddStatsDynamic(sim, stats.Stats{stats.Health: bonusHealth}) - warrior.GainHealth(sim, bonusHealth, healthMetrics) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.AddStatsDynamic(sim, stats.Stats{stats.Health: -bonusHealth}) - }, - }) - - lastStandSpell := warrior.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: warrior.NewTimer(), - Duration: core.TernaryDuration(warrior.HasMajorGlyph(proto.WarriorMajorGlyph_GlyphOfLastStand), time.Minute*3, time.Minute*2), - }, - }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - return warrior.StanceMatches(DefensiveStance) - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { - lastStandAura.Activate(sim) - }, - }) - - warrior.AddMajorCooldown(core.MajorCooldown{ - Spell: lastStandSpell, - Type: core.CooldownTypeSurvival, - }) -} - -func (warrior *Warrior) RegisterBladestormCD() { - if !warrior.Talents.Bladestorm { - return - } - - actionID := core.ActionID{SpellID: 46924} - numHits := min(4, warrior.Env.GetNumTargets()) - results := make([]*core.SpellResult, numHits) - - if warrior.AutoAttacks.IsDualWielding { - warrior.BladestormOH = warrior.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - SpellSchool: core.SpellSchoolPhysical, - ProcMask: core.ProcMaskMeleeOHSpecial, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, - - DamageMultiplier: 1 + 0.05*float64(warrior.Talents.DualWieldSpecialization), - CritMultiplier: warrior.critMultiplier(oh), - ThreatMultiplier: 1.25, - }) - } - - warrior.Bladestorm = warrior.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - SpellSchool: core.SpellSchoolPhysical, - ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagChanneled | core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, - - RageCost: core.RageCostOptions{ - Cost: 25 - float64(warrior.Talents.FocusedRage), - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - CD: core.Cooldown{ - Timer: warrior.NewTimer(), - Duration: core.TernaryDuration(warrior.HasMajorGlyph(proto.WarriorMajorGlyph_GlyphOfBladestorm), time.Second*75, time.Second*90), - }, - IgnoreHaste: true, - }, - - DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(mh), - ThreatMultiplier: 1.25, - - Dot: core.DotConfig{ - IsAOE: true, - Aura: core.Aura{ - Label: "Bladestorm", - }, - NumberOfTicks: 6, - TickLength: time.Second * 1, - OnTick: func(sim *core.Simulation, _ *core.Unit, dot *core.Dot) { - target := warrior.CurrentTarget - spell := dot.Spell - - curTarget := target - for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { - baseDamage := 0 + - spell.Unit.MHNormalizedWeaponDamage(sim, spell.MeleeAttackPower()) + - spell.BonusWeaponDamage() - results[hitIndex] = spell.CalcDamage(sim, curTarget, baseDamage, spell.OutcomeMeleeWeaponSpecialHitAndCrit) - - curTarget = sim.Environment.NextTargetUnit(curTarget) - } - - curTarget = target - for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { - spell.DealDamage(sim, results[hitIndex]) - curTarget = sim.Environment.NextTargetUnit(curTarget) - } - - if warrior.BladestormOH != nil { - curTarget = target - for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { - baseDamage := 0 + - spell.Unit.OHNormalizedWeaponDamage(sim, spell.MeleeAttackPower()) + - spell.BonusWeaponDamage() - results[hitIndex] = warrior.BladestormOH.CalcDamage(sim, curTarget, baseDamage, warrior.BladestormOH.OutcomeMeleeWeaponSpecialHitAndCrit) - - curTarget = sim.Environment.NextTargetUnit(curTarget) - } - - curTarget = target - for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { - warrior.BladestormOH.DealDamage(sim, results[hitIndex]) - curTarget = sim.Environment.NextTargetUnit(curTarget) - } - } - }, - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { - dot := spell.AOEDot() - dot.Apply(sim) - dot.TickOnce(sim) - }, - }) - - warrior.AddMajorCooldown(core.MajorCooldown{ - Spell: warrior.Bladestorm, - Type: core.CooldownTypeDPS, - }) -} - -func (warrior *Warrior) applySwordAndBoard() { - if warrior.Talents.SwordAndBoard == 0 { - return - } - - sabAura := warrior.GetOrRegisterAura(core.Aura{ - Label: "Sword And Board", - ActionID: core.ActionID{SpellID: 46953}, - Duration: 5 * time.Second, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warrior.ShieldSlam.CostMultiplier -= 1 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.ShieldSlam.CostMultiplier += 1 - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell == warrior.ShieldSlam { - aura.Deactivate(sim) - } - }, - }) - - procChance := 0.1 * float64(warrior.Talents.SwordAndBoard) - core.MakePermanent(warrior.GetOrRegisterAura(core.Aura{ - Label: "Sword And Board Trigger", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.Landed() { - return - } - - if !(spell == warrior.Revenge || spell == warrior.Devastate) { - return - } - - if sim.RandomFloat("Sword And Board") < procChance { - sabAura.Activate(sim) - warrior.ShieldSlam.CD.Reset() - } - }, - })) -} +// // Multiplicative with all other modifiers and only applies to the block damage event +// func (warrior *Warrior) applyCriticalBlock() { +// if warrior.Talents.CriticalBlock == 0 { +// return +// } + +// dummyCriticalBlockSpell := warrior.GetOrRegisterSpell(core.SpellConfig{ +// ActionID: core.ActionID{SpellID: 47296}, +// Flags: core.SpellFlagMeleeMetrics | core.SpellFlagNoOnCastComplete, +// }) + +// warrior.AddDynamicDamageTakenModifier(func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Outcome.Matches(core.OutcomeBlock) && !result.Outcome.Matches(core.OutcomeMiss) && !result.Outcome.Matches(core.OutcomeParry) && !result.Outcome.Matches(core.OutcomeDodge) { +// procChance := 0.2 * float64(warrior.Talents.CriticalBlock) +// if sim.RandomFloat("Critical Block Roll") <= procChance { +// blockValue := warrior.BlockValue() +// result.Damage = max(0, result.Damage-blockValue) +// dummyCriticalBlockSpell.Cast(sim, spell.Unit) +// } +// } +// }) +// } + +// func (warrior *Warrior) applyDamageShield() { +// if warrior.Talents.DamageShield == 0 { +// return +// } + +// coeff := 0.1 * float64(warrior.Talents.DamageShield) +// damageShieldProcSpell := warrior.GetOrRegisterSpell(core.SpellConfig{ +// ActionID: core.ActionID{SpellID: 58874}, +// SpellSchool: core.SpellSchoolPhysical, +// ProcMask: core.ProcMaskEmpty, +// Flags: core.SpellFlagMeleeMetrics | core.SpellFlagNoOnCastComplete, + +// DamageMultiplier: 1, +// ThreatMultiplier: 1, + +// ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { +// baseDamage := coeff * warrior.BlockValue() +// spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeAlwaysHit) +// }, +// }) + +// core.MakePermanent(warrior.GetOrRegisterAura(core.Aura{ +// Label: "Damage Shield Trigger", +// Duration: core.NeverExpires, +// OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() && !result.Outcome.Matches(core.OutcomeBlock) { +// return +// } + +// if spell.SpellSchool != core.SpellSchoolPhysical { +// return +// } + +// damageShieldProcSpell.Cast(sim, spell.Unit) +// }, +// })) +// } + +// func (warrior *Warrior) applyAngerManagement() { +// if !warrior.Talents.AngerManagement { +// return +// } + +// rageMetrics := warrior.NewRageMetrics(core.ActionID{SpellID: 12296}) + +// warrior.RegisterResetEffect(func(sim *core.Simulation) { +// core.StartPeriodicAction(sim, core.PeriodicActionOptions{ +// Period: time.Second * 3, +// OnAction: func(sim *core.Simulation) { +// warrior.AddRage(sim, 1, rageMetrics) +// warrior.LastAMTick = sim.CurrentTime +// }, +// }) +// }) +// } +// func (warrior *Warrior) applyTasteForBlood() { +// if warrior.Talents.TasteForBlood == 0 { +// return +// } + +// procChance := []float64{0, 0.33, 0.66, 1}[warrior.Talents.TasteForBlood] + +// icd := core.Cooldown{ +// Timer: warrior.NewTimer(), +// Duration: time.Second * 6, +// } + +// warrior.RegisterAura(core.Aura{ +// Label: "Taste for Blood", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell != warrior.Rend { +// return +// } + +// if !icd.IsReady(sim) { +// return +// } + +// if sim.RandomFloat("Taste for Blood") > procChance { +// return +// } + +// icd.Use(sim) +// warrior.OverpowerAura.Duration = time.Second * 9 +// warrior.OverpowerAura.Activate(sim) +// warrior.OverpowerAura.Duration = time.Second * 5 +// warrior.lastOverpowerProc = sim.CurrentTime +// }, +// }) +// } + +// func (warrior *Warrior) applyTrauma() { +// if warrior.Talents.Trauma == 0 { +// return +// } + +// traumaAuras := warrior.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { +// return core.TraumaAura(target, int(warrior.Talents.Trauma)) +// }) + +// warrior.RegisterAura(core.Aura{ +// Label: "Trauma", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Outcome.Matches(core.OutcomeCrit) { +// return +// } + +// if !spell.SpellSchool.Matches(core.SpellSchoolPhysical) || !spell.ProcMask.Matches(core.ProcMaskMelee) { +// return +// } + +// proc := traumaAuras.Get(result.Target) +// proc.Duration = time.Minute * 1 +// proc.Activate(sim) +// }, +// }) +// } + +// func (warrior *Warrior) isBloodsurgeActive() bool { +// return warrior.BloodsurgeAura.IsActive() || (warrior.Talents.Bloodsurge > 0 && warrior.Ymirjar4pcProcAura.IsActive()) +// } + +// func (warrior *Warrior) applyBloodsurge() { +// if warrior.Talents.Bloodsurge == 0 { +// return +// } + +// procChance := []float64{0, 0.07, 0.13, 0.2}[warrior.Talents.Bloodsurge] + +// ymirjar4Set := warrior.HasSetBonus(ItemSetYmirjarLordsBattlegear, 4) + +// warrior.BloodsurgeAura = warrior.RegisterAura(core.Aura{ +// Label: "Bloodsurge Proc", +// ActionID: core.ActionID{SpellID: 46916}, +// Duration: time.Second * 5, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// warrior.Slam.DefaultCast.CastTime = 0 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warrior.Slam.DefaultCast.CastTime = 1500 * time.Millisecond +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == warrior.Slam { // removed even if slam doesn't land +// aura.Deactivate(sim) +// } +// }, +// }) + +// if ymirjar4Set { +// warrior.Ymirjar4pcProcAura = warrior.RegisterAura(core.Aura{ +// Label: "Ymirjar 4pc (Bloodsurge) Proc", +// ActionID: core.ActionID{SpellID: 70847}, +// Duration: time.Second * 10, +// MaxStacks: 2, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// if warrior.BloodsurgeAura.IsActive() { +// warrior.BloodsurgeAura.Deactivate(sim) +// } + +// aura.SetStacks(sim, aura.MaxStacks) +// warrior.Slam.DefaultCast.CastTime = 0 +// warrior.Slam.DefaultCast.GCD = core.GCDMin +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warrior.Slam.DefaultCast.CastTime = 1500 * time.Millisecond +// warrior.Slam.DefaultCast.GCD = core.GCDDefault +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if spell == warrior.Slam { +// aura.RemoveStack(sim) +// } +// }, +// }) +// } + +// warrior.RegisterAura(core.Aura{ +// Label: "Bloodsurge", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() { +// return +// } + +// if !spell.Flags.Matches(SpellFlagBloodsurge) { +// return +// } + +// if sim.RandomFloat("Bloodsurge") > procChance { +// return +// } + +// warrior.lastBloodsurgeProc = sim.CurrentTime + +// // as per https://www.wowhead.com/cata/spell=70847/item-warrior-t10-melee-4p-bonus#comments, +// // the improved aura is not overwritten by the regular one, but simply refreshed +// if ymirjar4Set && (sim.RandomFloat("Ymirjar 4pc") < 0.2 || warrior.Ymirjar4pcProcAura.IsActive()) { +// warrior.BloodsurgeAura.Deactivate(sim) +// warrior.Ymirjar4pcProcAura.Activate(sim) + +// warrior.BloodsurgeValidUntil = sim.CurrentTime + warrior.Ymirjar4pcProcAura.Duration +// return +// } + +// warrior.BloodsurgeValidUntil = sim.CurrentTime + warrior.BloodsurgeAura.Duration +// warrior.BloodsurgeAura.Activate(sim) +// }, +// }) +// } +// func (warrior *Warrior) applyBloodFrenzy() { +// if warrior.Talents.BloodFrenzy == 0 { +// return +// } + +// warrior.PseudoStats.MeleeSpeedMultiplier *= 1 + 0.05*float64(warrior.Talents.BloodFrenzy) + +// bfAuras := warrior.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { +// return core.BloodFrenzyAura(target, warrior.Talents.BloodFrenzy) +// }) +// warrior.Env.RegisterPreFinalizeEffect(func() { +// if warrior.Rend != nil { +// warrior.Rend.RelatedAuras = append(warrior.Rend.RelatedAuras, bfAuras) +// } +// if warrior.DeepWounds != nil { +// warrior.DeepWounds.RelatedAuras = append(warrior.DeepWounds.RelatedAuras, bfAuras) +// } +// }) + +// warrior.RegisterAura(core.Aura{ +// Label: "Blood Frenzy Talent", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() { +// return +// } + +// if spell == warrior.Rend || spell == warrior.DeepWounds { +// aura := bfAuras.Get(result.Target) +// dot := warrior.Rend.Dot(result.Target) +// aura.Duration = dot.TickLength * time.Duration(dot.NumberOfTicks) +// aura.Activate(sim) +// } +// }, +// }) +// } + +// func (warrior *Warrior) applyTitansGrip() { +// if !warrior.Talents.TitansGrip { +// return +// } +// if !warrior.AutoAttacks.IsDualWielding { +// return +// } +// if warrior.MainHand().HandType != proto.HandType_HandTypeTwoHand && warrior.OffHand().HandType != proto.HandType_HandTypeTwoHand { +// return +// } + +// warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 - 0.1 +// } + +// func (warrior *Warrior) applyTwoHandedWeaponSpecialization() { +// if warrior.Talents.TwoHandedWeaponSpecialization == 0 { +// return +// } +// if warrior.MainHand().HandType != proto.HandType_HandTypeTwoHand { +// return +// } + +// warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 + 0.02*float64(warrior.Talents.TwoHandedWeaponSpecialization) +// } + +// func (warrior *Warrior) applyOneHandedWeaponSpecialization() { +// if warrior.Talents.OneHandedWeaponSpecialization == 0 { +// return +// } +// if warrior.MainHand().HandType == proto.HandType_HandTypeTwoHand { +// return +// } + +// warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1 + 0.02*float64(warrior.Talents.OneHandedWeaponSpecialization) +// } + +// func (warrior *Warrior) applyWeaponSpecializations() { +// if ss := warrior.Talents.SwordSpecialization; ss > 0 { +// if mask := warrior.GetProcMaskForTypes(proto.WeaponType_WeaponTypeSword); mask != core.ProcMaskUnknown { +// warrior.registerSwordSpecialization(mask) +// } +// } + +// if pas := warrior.Talents.PoleaxeSpecialization; pas > 0 { +// // the default character pane displays critical strike chance for main hand only +// switch warrior.GetProcMaskForTypes(proto.WeaponType_WeaponTypeAxe, proto.WeaponType_WeaponTypePolearm) { +// case core.ProcMaskMelee: +// warrior.AddStat(stats.MeleeCrit, 1*core.CritRatingPerCritChance*float64(pas)) +// case core.ProcMaskMeleeMH: +// warrior.AddStat(stats.MeleeCrit, 1*core.CritRatingPerCritChance*float64(pas)) +// warrior.OnSpellRegistered(func(spell *core.Spell) { +// if spell.ProcMask.Matches(core.ProcMaskMeleeOH) { +// spell.BonusCritRating -= 1 * core.CritRatingPerCritChance * float64(pas) +// } +// }) +// case core.ProcMaskMeleeOH: +// warrior.OnSpellRegistered(func(spell *core.Spell) { +// if spell.ProcMask.Matches(core.ProcMaskMeleeOH) { +// spell.BonusCritRating += 1 * core.CritRatingPerCritChance * float64(pas) +// } +// }) +// } +// } + +// if ms := warrior.Talents.MaceSpecialization; ms > 0 { +// if mask := warrior.GetProcMaskForTypes(proto.WeaponType_WeaponTypeMace); mask != core.ProcMaskEmpty { +// warrior.AddStat(stats.ArmorPenetration, 3*core.ArmorPenPerPercentArmor*float64(ms)) +// } +// } +// } + +// func (warrior *Warrior) registerSwordSpecialization(procMask core.ProcMask) { +// var swordSpecializationSpell *core.Spell +// icd := core.Cooldown{ +// Timer: warrior.NewTimer(), +// Duration: time.Second * 6, +// } +// procChance := 0.02 * float64(warrior.Talents.SwordSpecialization) + +// warrior.RegisterAura(core.Aura{ +// Label: "Sword Specialization", +// Duration: core.NeverExpires, +// OnInit: func(aura *core.Aura, sim *core.Simulation) { +// config := *warrior.AutoAttacks.MHConfig() +// config.ActionID = core.ActionID{SpellID: 12281} +// swordSpecializationSpell = warrior.GetOrRegisterSpell(config) +// }, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() { +// return +// } +// if !spell.ProcMask.Matches(procMask) { +// return +// } +// if spell == warrior.WhirlwindOH { +// return // OH WW hits can't proc this +// } +// if !icd.IsReady(sim) { +// return +// } +// if sim.RandomFloat("Sword Specialization") < procChance { +// icd.Use(sim) +// aura.Unit.AutoAttacks.MaybeReplaceMHSwing(sim, swordSpecializationSpell).Cast(sim, result.Target) +// } +// }, +// }) +// } + +// func (warrior *Warrior) applyUnbridledWrath() { +// if warrior.Talents.UnbridledWrath == 0 { +// return +// } + +// ppmm := warrior.AutoAttacks.NewPPMManager(3*float64(warrior.Talents.UnbridledWrath), core.ProcMaskMeleeWhiteHit) + +// rageMetrics := warrior.NewRageMetrics(core.ActionID{SpellID: 13002}) + +// warrior.RegisterAura(core.Aura{ +// Label: "Unbridled Wrath", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Damage == 0 { +// return +// } + +// if ppmm.Proc(sim, spell.ProcMask, "Unbrided Wrath") { +// warrior.AddRage(sim, 1, rageMetrics) +// } +// }, +// }) +// } + +// func (warrior *Warrior) applyFlurry() { +// if warrior.Talents.Flurry == 0 { +// return +// } + +// bonus := 1 + 0.05*float64(warrior.Talents.Flurry) +// inverseBonus := 1 / bonus + +// procAura := warrior.RegisterAura(core.Aura{ +// Label: "Flurry Proc", +// ActionID: core.ActionID{SpellID: 12974}, +// Duration: core.NeverExpires, +// MaxStacks: 3, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// warrior.MultiplyMeleeSpeed(sim, bonus) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warrior.MultiplyMeleeSpeed(sim, inverseBonus) +// }, +// }) + +// warrior.RegisterAura(core.Aura{ +// Label: "Flurry", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.ProcMask.Matches(core.ProcMaskMelee) && !spell.Flags.Matches(SpellFlagWhirlwindOH) { +// return +// } + +// if result.Outcome.Matches(core.OutcomeCrit) { +// procAura.Activate(sim) +// procAura.SetStacks(sim, 3) +// return +// } + +// // Remove a stack. +// if procAura.IsActive() && spell.ProcMask.Matches(core.ProcMaskMeleeWhiteHit) { +// procAura.RemoveStack(sim) +// } +// }, +// }) +// } + +// func (warrior *Warrior) applyWreckingCrew() { +// if warrior.Talents.WreckingCrew == 0 { +// return +// } + +// bonus := 1 + 0.02*float64(warrior.Talents.WreckingCrew) + +// procAura := warrior.RegisterAura(core.Aura{ +// Label: "Enrage", +// ActionID: core.ActionID{SpellID: 57518}, +// Duration: time.Second * 12, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= bonus +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// aura.Unit.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= bonus +// }, +// }) +// warrior.RegisterAura(core.Aura{ +// Label: "Wrecking Crew", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !spell.ProcMask.Matches(core.ProcMaskMelee) { +// return +// } + +// if !result.Outcome.Matches(core.OutcomeCrit) { +// return +// } + +// procAura.Activate(sim) +// }, +// }) +// core.RegisterPercentDamageModifierEffect(procAura, bonus) +// } + +// func (warrior *Warrior) IsSuddenDeathActive() bool { +// return warrior.SuddenDeathAura.IsActive() || (warrior.Talents.SuddenDeath > 0 && warrior.Ymirjar4pcProcAura.IsActive()) +// } + +// func (warrior *Warrior) applySuddenDeath() { +// if warrior.Talents.SuddenDeath == 0 { +// return +// } + +// rageMetrics := warrior.NewRageMetrics(core.ActionID{SpellID: 29724}) + +// minRageKept := []float64{0, 3, 7, 10}[warrior.Talents.SuddenDeath] +// procChance := []float64{0, 0.03, 0.06, 0.09}[warrior.Talents.SuddenDeath] + +// warrior.SuddenDeathAura = warrior.RegisterAura(core.Aura{ +// Label: "Sudden Death Proc", +// ActionID: core.ActionID{SpellID: 29724}, +// Duration: time.Second * 10, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() || spell != warrior.Execute { // removed only when landed +// return +// } +// if rageRefund := minRageKept - warrior.CurrentRage(); rageRefund > 0 { // refund only when below minRageKept +// warrior.AddRage(sim, rageRefund, rageMetrics) +// } +// aura.Deactivate(sim) +// }, +// }) + +// ymirjar4Set := warrior.HasSetBonus(ItemSetYmirjarLordsBattlegear, 4) + +// if ymirjar4Set { +// warrior.Ymirjar4pcProcAura = warrior.RegisterAura(core.Aura{ +// Label: "Ymirjar 4pc (Sudden Death) Proc", +// ActionID: core.ActionID{SpellID: 70847}, +// Duration: time.Second * 20, +// MaxStacks: 2, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// aura.SetStacks(sim, aura.MaxStacks) +// warrior.Execute.DefaultCast.GCD = core.GCDMin +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warrior.Execute.DefaultCast.GCD = core.GCDDefault +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() || spell != warrior.Execute { +// return +// } +// if rageRefund := minRageKept - warrior.CurrentRage(); rageRefund > 0 { +// warrior.AddRage(sim, rageRefund, rageMetrics) +// } +// aura.RemoveStack(sim) +// }, +// }) +// } + +// warrior.RegisterAura(core.Aura{ +// Label: "Sudden Death", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() || !spell.ProcMask.Matches(core.ProcMaskMelee) { +// return +// } + +// if sim.RandomFloat("Sudden Death") > procChance { +// return +// } + +// // as per https://www.wowhead.com/cata/spell=70847/item-warrior-t10-melee-4p-bonus#comments, +// // the improved aura is not overwritten by the regular one, but simply refreshed +// if ymirjar4Set && (warrior.Ymirjar4pcProcAura.IsActive() || sim.RandomFloat("Ymirjar 4pc") < 0.2) { +// warrior.SuddenDeathAura.Deactivate(sim) + +// warrior.Ymirjar4pcProcAura.Activate(sim) +// return +// } + +// warrior.SuddenDeathAura.Activate(sim) +// }, +// }) +// } + +// func (warrior *Warrior) applyShieldSpecialization() { +// if warrior.Talents.ShieldSpecialization == 0 { +// return +// } + +// warrior.AddStat(stats.Block, core.BlockRatingPerBlockChance*1*float64(warrior.Talents.ShieldSpecialization)) + +// procChance := 0.2 * float64(warrior.Talents.ShieldSpecialization) +// rageAdded := float64(warrior.Talents.ShieldSpecialization) +// rageMetrics := warrior.NewRageMetrics(core.ActionID{SpellID: 12727}) + +// warrior.RegisterAura(core.Aura{ +// Label: "Shield Specialization", +// Duration: core.NeverExpires, +// OnReset: func(aura *core.Aura, sim *core.Simulation) { +// aura.Activate(sim) +// }, +// OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if result.Outcome.Matches(core.OutcomeBlock | core.OutcomeDodge | core.OutcomeParry) { +// if sim.Proc(procChance, "Shield Specialization") { +// warrior.AddRage(sim, rageAdded, rageMetrics) +// } +// } +// }, +// }) +// } + +// func (warrior *Warrior) registerDeathWishCD() { +// if !warrior.Talents.DeathWish { +// return +// } + +// actionID := core.ActionID{SpellID: 12292} + +// deathWishAura := warrior.RegisterAura(core.Aura{ +// Label: "Death Wish", +// ActionID: actionID, +// Duration: time.Second * 30, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1.2 +// warrior.PseudoStats.DamageTakenMultiplier *= 1.05 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= 1.2 +// warrior.PseudoStats.DamageTakenMultiplier /= 1.05 +// }, +// }) +// core.RegisterPercentDamageModifierEffect(deathWishAura, 1.2) + +// deathWishSpell := warrior.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, + +// RageCost: core.RageCostOptions{ +// Cost: 10, +// }, +// Cast: core.CastConfig{ +// IgnoreHaste: true, +// CD: core.Cooldown{ +// Timer: warrior.NewTimer(), +// Duration: warrior.intensifyRageCooldown(time.Minute * 3), +// }, +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { +// deathWishAura.Activate(sim) +// warrior.WaitUntil(sim, sim.CurrentTime+core.GCDDefault) +// }, +// }) + +// warrior.AddMajorCooldown(core.MajorCooldown{ +// Spell: deathWishSpell, +// Type: core.CooldownTypeDPS, +// }) +// } + +// func (warrior *Warrior) registerLastStandCD() { +// if !warrior.Talents.LastStand { +// return +// } + +// actionID := core.ActionID{SpellID: 12975} +// healthMetrics := warrior.NewHealthMetrics(actionID) + +// var bonusHealth float64 +// lastStandAura := warrior.RegisterAura(core.Aura{ +// Label: "Last Stand", +// ActionID: actionID, +// Duration: time.Second * 20, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// bonusHealth = warrior.MaxHealth() * 0.3 +// warrior.AddStatsDynamic(sim, stats.Stats{stats.Health: bonusHealth}) +// warrior.GainHealth(sim, bonusHealth, healthMetrics) +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warrior.AddStatsDynamic(sim, stats.Stats{stats.Health: -bonusHealth}) +// }, +// }) + +// lastStandSpell := warrior.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, + +// Cast: core.CastConfig{ +// CD: core.Cooldown{ +// Timer: warrior.NewTimer(), +// Duration: core.TernaryDuration(warrior.HasMajorGlyph(proto.WarriorMajorGlyph_GlyphOfLastStand), time.Minute*3, time.Minute*2), +// }, +// }, +// ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { +// return warrior.StanceMatches(DefensiveStance) +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { +// lastStandAura.Activate(sim) +// }, +// }) + +// warrior.AddMajorCooldown(core.MajorCooldown{ +// Spell: lastStandSpell, +// Type: core.CooldownTypeSurvival, +// }) +// } + +// func (warrior *Warrior) RegisterBladestormCD() { +// if !warrior.Talents.Bladestorm { +// return +// } + +// actionID := core.ActionID{SpellID: 46924} +// numHits := min(4, warrior.Env.GetNumTargets()) +// results := make([]*core.SpellResult, numHits) + +// if warrior.AutoAttacks.IsDualWielding { +// warrior.BladestormOH = warrior.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// SpellSchool: core.SpellSchoolPhysical, +// ProcMask: core.ProcMaskMeleeOHSpecial, +// Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, + +// DamageMultiplier: 1 + 0.05*float64(warrior.Talents.DualWieldSpecialization), +// CritMultiplier: warrior.critMultiplier(oh), +// ThreatMultiplier: 1.25, +// }) +// } + +// warrior.Bladestorm = warrior.RegisterSpell(core.SpellConfig{ +// ActionID: actionID, +// SpellSchool: core.SpellSchoolPhysical, +// ProcMask: core.ProcMaskMeleeMHSpecial, +// Flags: core.SpellFlagChanneled | core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, + +// RageCost: core.RageCostOptions{ +// Cost: 25 - float64(warrior.Talents.FocusedRage), +// }, +// Cast: core.CastConfig{ +// DefaultCast: core.Cast{ +// GCD: core.GCDDefault, +// }, +// CD: core.Cooldown{ +// Timer: warrior.NewTimer(), +// Duration: core.TernaryDuration(warrior.HasMajorGlyph(proto.WarriorMajorGlyph_GlyphOfBladestorm), time.Second*75, time.Second*90), +// }, +// IgnoreHaste: true, +// }, + +// DamageMultiplier: 1, +// CritMultiplier: warrior.critMultiplier(mh), +// ThreatMultiplier: 1.25, + +// Dot: core.DotConfig{ +// IsAOE: true, +// Aura: core.Aura{ +// Label: "Bladestorm", +// }, +// NumberOfTicks: 6, +// TickLength: time.Second * 1, +// OnTick: func(sim *core.Simulation, _ *core.Unit, dot *core.Dot) { +// target := warrior.CurrentTarget +// spell := dot.Spell + +// curTarget := target +// for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { +// baseDamage := 0 + +// spell.Unit.MHNormalizedWeaponDamage(sim, spell.MeleeAttackPower()) + +// spell.BonusWeaponDamage() +// results[hitIndex] = spell.CalcDamage(sim, curTarget, baseDamage, spell.OutcomeMeleeWeaponSpecialHitAndCrit) + +// curTarget = sim.Environment.NextTargetUnit(curTarget) +// } + +// curTarget = target +// for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { +// spell.DealDamage(sim, results[hitIndex]) +// curTarget = sim.Environment.NextTargetUnit(curTarget) +// } + +// if warrior.BladestormOH != nil { +// curTarget = target +// for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { +// baseDamage := 0 + +// spell.Unit.OHNormalizedWeaponDamage(sim, spell.MeleeAttackPower()) + +// spell.BonusWeaponDamage() +// results[hitIndex] = warrior.BladestormOH.CalcDamage(sim, curTarget, baseDamage, warrior.BladestormOH.OutcomeMeleeWeaponSpecialHitAndCrit) + +// curTarget = sim.Environment.NextTargetUnit(curTarget) +// } + +// curTarget = target +// for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { +// warrior.BladestormOH.DealDamage(sim, results[hitIndex]) +// curTarget = sim.Environment.NextTargetUnit(curTarget) +// } +// } +// }, +// }, + +// ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { +// dot := spell.AOEDot() +// dot.Apply(sim) +// dot.TickOnce(sim) +// }, +// }) + +// warrior.AddMajorCooldown(core.MajorCooldown{ +// Spell: warrior.Bladestorm, +// Type: core.CooldownTypeDPS, +// }) +// } + +// func (warrior *Warrior) applySwordAndBoard() { +// if warrior.Talents.SwordAndBoard == 0 { +// return +// } + +// sabAura := warrior.GetOrRegisterAura(core.Aura{ +// Label: "Sword And Board", +// ActionID: core.ActionID{SpellID: 46953}, +// Duration: 5 * time.Second, +// OnGain: func(aura *core.Aura, sim *core.Simulation) { +// warrior.ShieldSlam.CostMultiplier -= 1 +// }, +// OnExpire: func(aura *core.Aura, sim *core.Simulation) { +// warrior.ShieldSlam.CostMultiplier += 1 +// }, +// OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { +// if spell == warrior.ShieldSlam { +// aura.Deactivate(sim) +// } +// }, +// }) + +// procChance := 0.1 * float64(warrior.Talents.SwordAndBoard) +// core.MakePermanent(warrior.GetOrRegisterAura(core.Aura{ +// Label: "Sword And Board Trigger", +// OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { +// if !result.Landed() { +// return +// } + +// if !(spell == warrior.Revenge || spell == warrior.Devastate) { +// return +// } + +// if sim.RandomFloat("Sword And Board") < procChance { +// sabAura.Activate(sim) +// warrior.ShieldSlam.CD.Reset() +// } +// }, +// })) +// } diff --git a/sim/warrior/warrior.go b/sim/warrior/warrior.go index 2b6d22ff4c..2dcff213e9 100644 --- a/sim/warrior/warrior.go +++ b/sim/warrior/warrior.go @@ -30,7 +30,7 @@ type Warrior struct { WarriorInputs // Current state - Stance Stance + //Stance Stance RendValidUntil time.Duration BloodsurgeValidUntil time.Duration revengeProcAura *core.Aura @@ -105,39 +105,39 @@ func (warrior *Warrior) AddPartyBuffs(_ *proto.PartyBuffs) { } func (warrior *Warrior) Initialize() { - warrior.AutoAttacks.MHConfig().CritMultiplier = warrior.autoCritMultiplier(mh) - warrior.AutoAttacks.OHConfig().CritMultiplier = warrior.autoCritMultiplier(oh) - - primaryTimer := warrior.NewTimer() - overpowerRevengeTimer := warrior.NewTimer() - - warrior.reactionTime = time.Millisecond * 500 - - warrior.registerShouts() - warrior.registerStances() - warrior.registerBerserkerRageSpell() - warrior.registerBloodthirstSpell(primaryTimer) - warrior.registerCleaveSpell() - warrior.registerDemoralizingShoutSpell() - warrior.registerDevastateSpell() - warrior.registerExecuteSpell() - warrior.registerHeroicStrikeSpell() - warrior.registerMortalStrikeSpell(primaryTimer) - warrior.registerOverpowerSpell(overpowerRevengeTimer) - warrior.registerRevengeSpell(overpowerRevengeTimer) - warrior.registerShieldSlamSpell() - warrior.registerSlamSpell() - warrior.registerThunderClapSpell() - warrior.registerWhirlwindSpell() - warrior.registerShockwaveSpell() - warrior.registerConcussionBlowSpell() - warrior.RegisterHeroicThrow() - warrior.RegisterRendSpell() - - warrior.SunderArmor = warrior.newSunderArmorSpell(false) - warrior.SunderArmorDevastate = warrior.newSunderArmorSpell(true) - - warrior.registerBloodrageCD() + // warrior.AutoAttacks.MHConfig().CritMultiplier = warrior.autoCritMultiplier(mh) + // warrior.AutoAttacks.OHConfig().CritMultiplier = warrior.autoCritMultiplier(oh) + + // primaryTimer := warrior.NewTimer() + // overpowerRevengeTimer := warrior.NewTimer() + + // warrior.reactionTime = time.Millisecond * 500 + + // warrior.registerShouts() + // warrior.registerStances() + // warrior.registerBerserkerRageSpell() + // warrior.registerBloodthirstSpell(primaryTimer) + // warrior.registerCleaveSpell() + // warrior.registerDemoralizingShoutSpell() + // warrior.registerDevastateSpell() + // warrior.registerExecuteSpell() + // warrior.registerHeroicStrikeSpell() + // warrior.registerMortalStrikeSpell(primaryTimer) + // warrior.registerOverpowerSpell(overpowerRevengeTimer) + // warrior.registerRevengeSpell(overpowerRevengeTimer) + // warrior.registerShieldSlamSpell() + // warrior.registerSlamSpell() + // warrior.registerThunderClapSpell() + // warrior.registerWhirlwindSpell() + // warrior.registerShockwaveSpell() + // warrior.registerConcussionBlowSpell() + // warrior.RegisterHeroicThrow() + // warrior.RegisterRendSpell() + + // warrior.SunderArmor = warrior.newSunderArmorSpell(false) + // warrior.SunderArmorDevastate = warrior.newSunderArmorSpell(true) + + // warrior.registerBloodrageCD() } func (warrior *Warrior) Reset(_ *core.Simulation) { @@ -182,11 +182,11 @@ func (warrior *Warrior) autoCritMultiplier(hand hand) float64 { } func primary(warrior *Warrior, hand hand) float64 { - if warrior.Talents.PoleaxeSpecialization > 0 { - if (hand == mh && isPoleaxe(warrior.MainHand())) || (hand == oh && isPoleaxe(warrior.OffHand())) { - return 1 + 0.01*float64(warrior.Talents.PoleaxeSpecialization) - } - } + // if warrior.Talents.PoleaxeSpecialization > 0 { + // if (hand == mh && isPoleaxe(warrior.MainHand())) || (hand == oh && isPoleaxe(warrior.OffHand())) { + // return 1 + 0.01*float64(warrior.Talents.PoleaxeSpecialization) + // } + // } return 1 } diff --git a/ui/core/talents/glyphs_picker.tsx b/ui/core/talents/glyphs_picker.tsx index c81eed4013..50ed35c171 100644 --- a/ui/core/talents/glyphs_picker.tsx +++ b/ui/core/talents/glyphs_picker.tsx @@ -95,7 +95,7 @@ export class GlyphsPicker extends Component { // In case we ever want to parse description from tooltip HTML. //static descriptionRegex = /(.*)<\/a>/g; getGlyphData(glyph: number): GlyphData { - const glyphConfig = this.glyphsConfig.majorGlyphs[glyph] || this.glyphsConfig.minorGlyphs[glyph]; + const glyphConfig = this.glyphsConfig.primeGlyphs[glyph] || this.glyphsConfig.majorGlyphs[glyph] || this.glyphsConfig.minorGlyphs[glyph]; return { id: glyph, diff --git a/ui/death_knight/blood/inputs.ts b/ui/death_knight/blood/inputs.ts index d45d338884..66a7501e6b 100644 --- a/ui/death_knight/blood/inputs.ts +++ b/ui/death_knight/blood/inputs.ts @@ -14,19 +14,19 @@ import { TypedEvent } from '../../core/typed_event'; // Configuration for spec-specific UI elements on the settings tab. // These don't need to be in a separate file but it keeps things cleaner. -export const DrwPestiApply = InputHelpers.makeSpecOptionsBooleanInput({ - fieldName: 'drwPestiApply', - label: 'DRW Pestilence Add', - labelTooltip: - 'There is currently an interaction with DRW and pestilence where you can use pestilence to force DRW to apply diseases if they are already applied by the DK. It only works with Glyph of Disease and if there is an off target. This toggle forces the sim to assume there is an off target.', - showWhen: (player: Player) => - player.getTalentTree() == 0 && - (player.getGlyphs().major1 == DeathKnightMajorGlyph.GlyphOfDisease || - player.getGlyphs().major2 == DeathKnightMajorGlyph.GlyphOfDisease || - player.getGlyphs().major3 == DeathKnightMajorGlyph.GlyphOfDisease), - changeEmitter: (player: Player) => - TypedEvent.onAny([player.specOptionsChangeEmitter, player.rotationChangeEmitter, player.talentsChangeEmitter]), -}); +// export const DrwPestiApply = InputHelpers.makeSpecOptionsBooleanInput({ +// fieldName: 'drwPestiApply', +// label: 'DRW Pestilence Add', +// labelTooltip: +// 'There is currently an interaction with DRW and pestilence where you can use pestilence to force DRW to apply diseases if they are already applied by the DK. It only works with Glyph of Disease and if there is an off target. This toggle forces the sim to assume there is an off target.', +// showWhen: (player: Player) => +// player.getTalentTree() == 0 && +// (player.getGlyphs().major1 == DeathKnightMajorGlyph.GlyphOfDisease || +// player.getGlyphs().major2 == DeathKnightMajorGlyph.GlyphOfDisease || +// player.getGlyphs().major3 == DeathKnightMajorGlyph.GlyphOfDisease), +// changeEmitter: (player: Player) => +// TypedEvent.onAny([player.specOptionsChangeEmitter, player.rotationChangeEmitter, player.talentsChangeEmitter]), +// }); export const DefensiveCdDelay = InputHelpers.makeSpecOptionsNumberInput({ fieldName: 'defensiveDelay', diff --git a/ui/death_knight/blood/presets.ts b/ui/death_knight/blood/presets.ts index 002d4ced5c..15ef55bf01 100644 --- a/ui/death_knight/blood/presets.ts +++ b/ui/death_knight/blood/presets.ts @@ -20,45 +20,45 @@ export const BLOOD_AGGRO_ROTATION_PRESET_DEFAULT = PresetUtils.makePresetAPLRota export const BloodTalents = { name: 'Blood', data: SavedTalents.create({ - talentsString: '005512153330030320102013-3050505000023-005', - glyphs: Glyphs.create({ - major1: DeathKnightMajorGlyph.GlyphOfDisease, - major2: DeathKnightMajorGlyph.GlyphOfRuneStrike, - major3: DeathKnightMajorGlyph.GlyphOfDarkCommand, - minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, - minor2: DeathKnightMinorGlyph.GlyphOfBloodTap, - minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, - }), + // talentsString: '005512153330030320102013-3050505000023-005', + // glyphs: Glyphs.create({ + // major1: DeathKnightMajorGlyph.GlyphOfDisease, + // major2: DeathKnightMajorGlyph.GlyphOfRuneStrike, + // major3: DeathKnightMajorGlyph.GlyphOfDarkCommand, + // minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, + // minor2: DeathKnightMinorGlyph.GlyphOfBloodTap, + // minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, + // }), }), }; export const BloodAggroTalents = { name: 'Blood Aggro', data: SavedTalents.create({ - talentsString: '0355220530303303201020131301--0052003050032', - glyphs: Glyphs.create({ - major1: DeathKnightMajorGlyph.GlyphOfDancingRuneWeapon, - major2: DeathKnightMajorGlyph.GlyphOfRuneStrike, - major3: DeathKnightMajorGlyph.GlyphOfDarkCommand, - minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, - minor2: DeathKnightMinorGlyph.GlyphOfBloodTap, - minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, - }), + // talentsString: '0355220530303303201020131301--0052003050032', + // glyphs: Glyphs.create({ + // major1: DeathKnightMajorGlyph.GlyphOfDancingRuneWeapon, + // major2: DeathKnightMajorGlyph.GlyphOfRuneStrike, + // major3: DeathKnightMajorGlyph.GlyphOfDarkCommand, + // minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, + // minor2: DeathKnightMinorGlyph.GlyphOfBloodTap, + // minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, + // }), }), }; export const DoubleBuffBloodTalents = { name: '2B Blood', data: SavedTalents.create({ - talentsString: '005512153330030320102013-3050505000023201-002', - glyphs: Glyphs.create({ - major1: DeathKnightMajorGlyph.GlyphOfDisease, - major2: DeathKnightMajorGlyph.GlyphOfRuneStrike, - major3: DeathKnightMajorGlyph.GlyphOfDarkCommand, - minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, - minor2: DeathKnightMinorGlyph.GlyphOfBloodTap, - minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, - }), + // talentsString: '005512153330030320102013-3050505000023201-002', + // glyphs: Glyphs.create({ + // major1: DeathKnightMajorGlyph.GlyphOfDisease, + // major2: DeathKnightMajorGlyph.GlyphOfRuneStrike, + // major3: DeathKnightMajorGlyph.GlyphOfDarkCommand, + // minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, + // minor2: DeathKnightMinorGlyph.GlyphOfBloodTap, + // minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, + // }), }), }; diff --git a/ui/death_knight/frost/presets.ts b/ui/death_knight/frost/presets.ts index 0c1146ba80..03ab0e8886 100644 --- a/ui/death_knight/frost/presets.ts +++ b/ui/death_knight/frost/presets.ts @@ -31,30 +31,30 @@ export const FROST_UH_PESTI_ROTATION_PRESET_DEFAULT = PresetUtils.makePresetAPLR export const FrostTalents = { name: 'Frost BL', data: SavedTalents.create({ - talentsString: '23050005-32005350352203012300033101351', - glyphs: Glyphs.create({ - major1: DeathKnightMajorGlyph.GlyphOfObliterate, - major2: DeathKnightMajorGlyph.GlyphOfFrostStrike, - major3: DeathKnightMajorGlyph.GlyphOfDisease, - minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, - minor2: DeathKnightMinorGlyph.GlyphOfPestilence, - minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, - }), + // talentsString: '23050005-32005350352203012300033101351', + // glyphs: Glyphs.create({ + // major1: DeathKnightMajorGlyph.GlyphOfObliterate, + // major2: DeathKnightMajorGlyph.GlyphOfFrostStrike, + // major3: DeathKnightMajorGlyph.GlyphOfDisease, + // minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, + // minor2: DeathKnightMinorGlyph.GlyphOfPestilence, + // minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, + // }), }), }; export const FrostUnholyTalents = { name: 'Frost UH', data: SavedTalents.create({ - talentsString: '01-32002350342203012300033101351-230200305003', - glyphs: Glyphs.create({ - major1: DeathKnightMajorGlyph.GlyphOfObliterate, - major2: DeathKnightMajorGlyph.GlyphOfFrostStrike, - major3: DeathKnightMajorGlyph.GlyphOfDisease, - minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, - minor2: DeathKnightMinorGlyph.GlyphOfPestilence, - minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, - }), + // talentsString: '01-32002350342203012300033101351-230200305003', + // glyphs: Glyphs.create({ + // major1: DeathKnightMajorGlyph.GlyphOfObliterate, + // major2: DeathKnightMajorGlyph.GlyphOfFrostStrike, + // major3: DeathKnightMajorGlyph.GlyphOfDisease, + // minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, + // minor2: DeathKnightMinorGlyph.GlyphOfPestilence, + // minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, + // }), }), }; diff --git a/ui/death_knight/frost/sim.ts b/ui/death_knight/frost/sim.ts index d746efe7cb..05329f0788 100644 --- a/ui/death_knight/frost/sim.ts +++ b/ui/death_knight/frost/sim.ts @@ -131,14 +131,14 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecFrostDeathKnight, { // Inputs to include in the 'Other' section on the settings tab. otherInputs: { inputs: [ - DeathKnightInputs.StartingRunicPower(), - DeathKnightInputs.PetUptime(), - FrostInputs.UseAMSInput, - FrostInputs.AvgAMSSuccessRateInput, - FrostInputs.AvgAMSHitInput, + // DeathKnightInputs.StartingRunicPower(), + // DeathKnightInputs.PetUptime(), + // FrostInputs.UseAMSInput, + // FrostInputs.AvgAMSSuccessRateInput, + // FrostInputs.AvgAMSHitInput, - OtherInputs.TankAssignment, - OtherInputs.InFrontOfTarget, + // OtherInputs.TankAssignment, + // OtherInputs.InFrontOfTarget, ], }, itemSwapSlots: [ItemSlot.ItemSlotMainHand, ItemSlot.ItemSlotOffHand], diff --git a/ui/death_knight/inputs.ts b/ui/death_knight/inputs.ts index 1d37eb6557..990cc339bb 100644 --- a/ui/death_knight/inputs.ts +++ b/ui/death_knight/inputs.ts @@ -12,11 +12,11 @@ export const StartingRunicPower = () => labelTooltip: 'Initial RP at the start of each iteration.', }); -export const PetUptime = () => - InputHelpers.makeClassOptionsNumberInput({ - fieldName: 'petUptime', - label: 'Ghoul Uptime (%)', - labelTooltip: 'Percent of the fight duration for which your ghoul will be on target.', - percent: true, - showWhen: (player: Player) => player.getTalents().masterOfGhouls, - }); +// export const PetUptime = () => +// InputHelpers.makeClassOptionsNumberInput({ +// fieldName: 'petUptime', +// label: 'Ghoul Uptime (%)', +// labelTooltip: 'Percent of the fight duration for which your ghoul will be on target.', +// percent: true, +// showWhen: (player: Player) => player.getTalents().masterOfGhouls, +// }); diff --git a/ui/death_knight/unholy/inputs.ts b/ui/death_knight/unholy/inputs.ts index d73f67a9cd..d06dba7d02 100644 --- a/ui/death_knight/unholy/inputs.ts +++ b/ui/death_knight/unholy/inputs.ts @@ -6,23 +6,23 @@ import { EventID, TypedEvent } from '../../core/typed_event'; // Configuration for spec-specific UI elements on the settings tab. // These don't need to be in a separate file but it keeps things cleaner. -export const SelfUnholyFrenzy = InputHelpers.makeSpecOptionsBooleanInput({ - fieldName: 'unholyFrenzyTarget', - label: 'Self Unholy Frenzy', - labelTooltip: 'Cast Unholy Frenzy on yourself.', - extraCssClasses: ['within-raid-sim-hide'], - getValue: (player: Player) => player.getSpecOptions().unholyFrenzyTarget?.type == UnitType.Player, - setValue: (eventID: EventID, player: Player, newValue: boolean) => { - const newOptions = player.getSpecOptions(); - newOptions.unholyFrenzyTarget = UnitReference.create({ - type: newValue ? UnitType.Player : UnitType.Unknown, - index: 0, - }); - player.setSpecOptions(eventID, newOptions); - }, - showWhen: (player: Player) => player.getTalents().hysteria, - changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), -}); +// export const SelfUnholyFrenzy = InputHelpers.makeSpecOptionsBooleanInput({ +// fieldName: 'unholyFrenzyTarget', +// label: 'Self Unholy Frenzy', +// labelTooltip: 'Cast Unholy Frenzy on yourself.', +// extraCssClasses: ['within-raid-sim-hide'], +// getValue: (player: Player) => player.getSpecOptions().unholyFrenzyTarget?.type == UnitType.Player, +// setValue: (eventID: EventID, player: Player, newValue: boolean) => { +// const newOptions = player.getSpecOptions(); +// newOptions.unholyFrenzyTarget = UnitReference.create({ +// type: newValue ? UnitType.Player : UnitType.Unknown, +// index: 0, +// }); +// player.setSpecOptions(eventID, newOptions); +// }, +// showWhen: (player: Player) => player.getTalents().hysteria, +// changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), +// }); export const UseAMSInput = InputHelpers.makeSpecOptionsBooleanInput({ fieldName: 'useAms', diff --git a/ui/death_knight/unholy/presets.ts b/ui/death_knight/unholy/presets.ts index c706ae8659..4dfa498d62 100644 --- a/ui/death_knight/unholy/presets.ts +++ b/ui/death_knight/unholy/presets.ts @@ -37,60 +37,60 @@ export const UNHOLY_DND_AOE_ROTATION_PRESET_DEFAULT = PresetUtils.makePresetAPLR export const UnholyDualWieldTalents = { name: 'Unholy DW', data: SavedTalents.create({ - talentsString: '-320043500002-2300303050032152000150013133051', - glyphs: Glyphs.create({ - major1: DeathKnightMajorGlyph.GlyphOfTheGhoul, - major2: DeathKnightMajorGlyph.GlyphOfIcyTouch, - major3: DeathKnightMajorGlyph.GlyphOfDeathAndDecay, - minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, - minor2: DeathKnightMinorGlyph.GlyphOfPestilence, - minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, - }), + // talentsString: '-320043500002-2300303050032152000150013133051', + // glyphs: Glyphs.create({ + // major1: DeathKnightMajorGlyph.GlyphOfTheGhoul, + // major2: DeathKnightMajorGlyph.GlyphOfIcyTouch, + // major3: DeathKnightMajorGlyph.GlyphOfDeathAndDecay, + // minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, + // minor2: DeathKnightMinorGlyph.GlyphOfPestilence, + // minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, + // }), }), }; export const UnholyDualWieldSSTalents = { name: 'Unholy DW SS', data: SavedTalents.create({ - talentsString: '-320033500002-2301303050032151000150013133151', - glyphs: Glyphs.create({ - major1: DeathKnightMajorGlyph.GlyphOfTheGhoul, - major2: DeathKnightMajorGlyph.GlyphOfIcyTouch, - major3: DeathKnightMajorGlyph.GlyphOfDeathAndDecay, - minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, - minor2: DeathKnightMinorGlyph.GlyphOfPestilence, - minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, - }), + // talentsString: '-320033500002-2301303050032151000150013133151', + // glyphs: Glyphs.create({ + // major1: DeathKnightMajorGlyph.GlyphOfTheGhoul, + // major2: DeathKnightMajorGlyph.GlyphOfIcyTouch, + // major3: DeathKnightMajorGlyph.GlyphOfDeathAndDecay, + // minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, + // minor2: DeathKnightMinorGlyph.GlyphOfPestilence, + // minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, + // }), }), }; export const Unholy2HTalents = { name: 'Unholy 2H', data: SavedTalents.create({ - talentsString: '-320050500002-2302003350032052000150013133151', - glyphs: Glyphs.create({ - major1: DeathKnightMajorGlyph.GlyphOfTheGhoul, - major2: DeathKnightMajorGlyph.GlyphOfIcyTouch, - major3: DeathKnightMajorGlyph.GlyphOfDarkDeath, - minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, - minor2: DeathKnightMinorGlyph.GlyphOfPestilence, - minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, - }), + // talentsString: '-320050500002-2302003350032052000150013133151', + // glyphs: Glyphs.create({ + // major1: DeathKnightMajorGlyph.GlyphOfTheGhoul, + // major2: DeathKnightMajorGlyph.GlyphOfIcyTouch, + // major3: DeathKnightMajorGlyph.GlyphOfDarkDeath, + // minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, + // minor2: DeathKnightMinorGlyph.GlyphOfPestilence, + // minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, + // }), }), }; export const UnholyAoeTalents = { name: 'Unholy AOE', data: SavedTalents.create({ - talentsString: '-320050500002-2302303050032052000150013133151', - glyphs: Glyphs.create({ - major1: DeathKnightMajorGlyph.GlyphOfTheGhoul, - major2: DeathKnightMajorGlyph.GlyphOfIcyTouch, - major3: DeathKnightMajorGlyph.GlyphOfDeathAndDecay, - minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, - minor2: DeathKnightMinorGlyph.GlyphOfPestilence, - minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, - }), + // talentsString: '-320050500002-2302303050032052000150013133151', + // glyphs: Glyphs.create({ + // major1: DeathKnightMajorGlyph.GlyphOfTheGhoul, + // major2: DeathKnightMajorGlyph.GlyphOfIcyTouch, + // major3: DeathKnightMajorGlyph.GlyphOfDeathAndDecay, + // minor1: DeathKnightMinorGlyph.GlyphOfHornOfWinter, + // minor2: DeathKnightMinorGlyph.GlyphOfPestilence, + // minor3: DeathKnightMinorGlyph.GlyphOfRaiseDead, + // }), }), }; diff --git a/ui/death_knight/unholy/sim.ts b/ui/death_knight/unholy/sim.ts index b4b0600b17..95ef53f19e 100644 --- a/ui/death_knight/unholy/sim.ts +++ b/ui/death_knight/unholy/sim.ts @@ -147,15 +147,15 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecUnholyDeathKnight, { // Inputs to include in the 'Other' section on the settings tab. otherInputs: { inputs: [ - DeathKnightInputs.StartingRunicPower(), - DeathKnightInputs.PetUptime(), - UnholyInputs.SelfUnholyFrenzy, - UnholyInputs.UseAMSInput, - UnholyInputs.AvgAMSSuccessRateInput, - UnholyInputs.AvgAMSHitInput, + // DeathKnightInputs.StartingRunicPower(), + // DeathKnightInputs.PetUptime(), + // UnholyInputs.SelfUnholyFrenzy, + // UnholyInputs.UseAMSInput, + // UnholyInputs.AvgAMSSuccessRateInput, + // UnholyInputs.AvgAMSHitInput, - OtherInputs.TankAssignment, - OtherInputs.InFrontOfTarget, + // OtherInputs.TankAssignment, + // OtherInputs.InFrontOfTarget, ], }, itemSwapSlots: [ItemSlot.ItemSlotMainHand, ItemSlot.ItemSlotOffHand], diff --git a/ui/druid/balance/presets.ts b/ui/druid/balance/presets.ts index 9ce45e7bc1..19afd8a00a 100644 --- a/ui/druid/balance/presets.ts +++ b/ui/druid/balance/presets.ts @@ -47,60 +47,60 @@ export const ROTATION_PRESET_P4_STARFIRE_APL = PresetUtils.makePresetAPLRotation export const Phase1Talents = { name: 'Phase 1', data: SavedTalents.create({ - talentsString: '5032003115331303213305311231--205003012', - glyphs: Glyphs.create({ - major1: DruidMajorGlyph.GlyphOfFocus, - major2: DruidMajorGlyph.GlyphOfInsectSwarm, - major3: DruidMajorGlyph.GlyphOfStarfall, - minor1: DruidMinorGlyph.GlyphOfTyphoon, - minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, - minor3: DruidMinorGlyph.GlyphOfTheWild, - }), + // talentsString: '5032003115331303213305311231--205003012', + // glyphs: Glyphs.create({ + // major1: DruidMajorGlyph.GlyphOfFocus, + // major2: DruidMajorGlyph.GlyphOfInsectSwarm, + // major3: DruidMajorGlyph.GlyphOfStarfall, + // minor1: DruidMinorGlyph.GlyphOfTyphoon, + // minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, + // minor3: DruidMinorGlyph.GlyphOfTheWild, + // }), }), }; export const Phase2Talents = { name: 'Phase 2', data: SavedTalents.create({ - talentsString: '5012203115331303213305311231--205003012', - glyphs: Glyphs.create({ - major1: DruidMajorGlyph.GlyphOfStarfire, - major2: DruidMajorGlyph.GlyphOfInsectSwarm, - major3: DruidMajorGlyph.GlyphOfStarfall, - minor1: DruidMinorGlyph.GlyphOfTyphoon, - minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, - minor3: DruidMinorGlyph.GlyphOfTheWild, - }), + // talentsString: '5012203115331303213305311231--205003012', + // glyphs: Glyphs.create({ + // major1: DruidMajorGlyph.GlyphOfStarfire, + // major2: DruidMajorGlyph.GlyphOfInsectSwarm, + // major3: DruidMajorGlyph.GlyphOfStarfall, + // minor1: DruidMinorGlyph.GlyphOfTyphoon, + // minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, + // minor3: DruidMinorGlyph.GlyphOfTheWild, + // }), }), }; export const Phase3Talents = { name: 'Phase 3', data: SavedTalents.create({ - talentsString: '5102223115331303213305311031--205003012', - glyphs: Glyphs.create({ - major1: DruidMajorGlyph.GlyphOfStarfire, - major2: DruidMajorGlyph.GlyphOfMoonfire, - major3: DruidMajorGlyph.GlyphOfStarfall, - minor1: DruidMinorGlyph.GlyphOfTyphoon, - minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, - minor3: DruidMinorGlyph.GlyphOfTheWild, - }), + // talentsString: '5102223115331303213305311031--205003012', + // glyphs: Glyphs.create({ + // major1: DruidMajorGlyph.GlyphOfStarfire, + // major2: DruidMajorGlyph.GlyphOfMoonfire, + // major3: DruidMajorGlyph.GlyphOfStarfall, + // minor1: DruidMinorGlyph.GlyphOfTyphoon, + // minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, + // minor3: DruidMinorGlyph.GlyphOfTheWild, + // }), }), }; export const Phase4Talents = { name: 'Phase 4', data: SavedTalents.create({ - talentsString: '5102223115331303213305311031--205003012', - glyphs: Glyphs.create({ - major1: DruidMajorGlyph.GlyphOfFocus, - major2: DruidMajorGlyph.GlyphOfInsectSwarm, - major3: DruidMajorGlyph.GlyphOfStarfall, - minor1: DruidMinorGlyph.GlyphOfTyphoon, - minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, - minor3: DruidMinorGlyph.GlyphOfTheWild, - }), + // talentsString: '5102223115331303213305311031--205003012', + // glyphs: Glyphs.create({ + // major1: DruidMajorGlyph.GlyphOfFocus, + // major2: DruidMajorGlyph.GlyphOfInsectSwarm, + // major3: DruidMajorGlyph.GlyphOfStarfall, + // minor1: DruidMinorGlyph.GlyphOfTyphoon, + // minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, + // minor3: DruidMinorGlyph.GlyphOfTheWild, + // }), }), }; diff --git a/ui/druid/feral/inputs.ts b/ui/druid/feral/inputs.ts index 03637bad3e..8970e2ddb2 100644 --- a/ui/druid/feral/inputs.ts +++ b/ui/druid/feral/inputs.ts @@ -41,13 +41,13 @@ export const FeralDruidRotationConfig = { { name: 'AOE', value: AplType.Aoe }, ], }), - InputHelpers.makeRotationBooleanInput({ - fieldName: 'prePopOoc', - label: 'Pre-pop Clearcasting', - labelTooltip: 'Start fight with clearcasting', - showWhen: (player: Player) => player.getTalents().omenOfClarity, - changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), - }), + // InputHelpers.makeRotationBooleanInput({ + // fieldName: 'prePopOoc', + // label: 'Pre-pop Clearcasting', + // labelTooltip: 'Start fight with clearcasting', + // showWhen: (player: Player) => player.getTalents().omenOfClarity, + // changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), + // }), InputHelpers.makeRotationBooleanInput({ fieldName: 'prePopBerserk', label: 'Pre-pop Berserk', diff --git a/ui/druid/feral/presets.ts b/ui/druid/feral/presets.ts index 07b98fa310..06d200bdb3 100644 --- a/ui/druid/feral/presets.ts +++ b/ui/druid/feral/presets.ts @@ -63,15 +63,15 @@ export const SIMPLE_ROTATION_DEFAULT = PresetUtils.makePresetSimpleRotation('Sim export const StandardTalents = { name: 'Standard', data: SavedTalents.create({ - talentsString: '-543202132322010053120030310511-203503012', - glyphs: Glyphs.create({ - major1: DruidMajorGlyph.GlyphOfOmenOfClarity, - major2: DruidMajorGlyph.GlyphOfSavageRoar, - major3: DruidMajorGlyph.GlyphOfShred, - minor1: DruidMinorGlyph.GlyphOfDash, - minor2: DruidMinorGlyph.GlyphOfTheWild, - minor3: DruidMinorGlyph.GlyphOfUnburdenedRebirth, - }), + // talentsString: '-543202132322010053120030310511-203503012', + // glyphs: Glyphs.create({ + // major1: DruidMajorGlyph.GlyphOfOmenOfClarity, + // major2: DruidMajorGlyph.GlyphOfSavageRoar, + // major3: DruidMajorGlyph.GlyphOfShred, + // minor1: DruidMinorGlyph.GlyphOfDash, + // minor2: DruidMinorGlyph.GlyphOfTheWild, + // minor3: DruidMinorGlyph.GlyphOfUnburdenedRebirth, + // }), }), }; diff --git a/ui/druid/restoration/presets.ts b/ui/druid/restoration/presets.ts index e7a9f1b087..1666dbd30c 100644 --- a/ui/druid/restoration/presets.ts +++ b/ui/druid/restoration/presets.ts @@ -33,29 +33,29 @@ export const P4_PRESET = PresetUtils.makePresetGear('P4 Preset', P4Gear); export const CelestialFocusTalents = { name: 'Celestial Focus', data: SavedTalents.create({ - talentsString: '05320031103--230023312131502331050313051', - glyphs: Glyphs.create({ - major1: DruidMajorGlyph.GlyphOfWildGrowth, - major2: DruidMajorGlyph.GlyphOfSwiftmend, - major3: DruidMajorGlyph.GlyphOfNourish, - minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, - minor3: DruidMinorGlyph.GlyphOfTheWild, - minor1: DruidMinorGlyph.GlyphOfDash, - }), + // talentsString: '05320031103--230023312131502331050313051', + // glyphs: Glyphs.create({ + // major1: DruidMajorGlyph.GlyphOfWildGrowth, + // major2: DruidMajorGlyph.GlyphOfSwiftmend, + // major3: DruidMajorGlyph.GlyphOfNourish, + // minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, + // minor3: DruidMinorGlyph.GlyphOfTheWild, + // minor1: DruidMinorGlyph.GlyphOfDash, + // }), }), }; export const ThiccRestoTalents = { name: 'Thicc Resto', data: SavedTalents.create({ - talentsString: '05320001--230023312331502531053313051', - glyphs: Glyphs.create({ - major1: DruidMajorGlyph.GlyphOfWildGrowth, - major2: DruidMajorGlyph.GlyphOfSwiftmend, - major3: DruidMajorGlyph.GlyphOfNourish, - minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, - minor3: DruidMinorGlyph.GlyphOfTheWild, - minor1: DruidMinorGlyph.GlyphOfDash, - }), + // talentsString: '05320001--230023312331502531053313051', + // glyphs: Glyphs.create({ + // major1: DruidMajorGlyph.GlyphOfWildGrowth, + // major2: DruidMajorGlyph.GlyphOfSwiftmend, + // major3: DruidMajorGlyph.GlyphOfNourish, + // minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, + // minor3: DruidMinorGlyph.GlyphOfTheWild, + // minor1: DruidMinorGlyph.GlyphOfDash, + // }), }), }; diff --git a/ui/hunter/beast_mastery/inputs.ts b/ui/hunter/beast_mastery/inputs.ts index 9ef90f7bec..fc75dc7ebc 100644 --- a/ui/hunter/beast_mastery/inputs.ts +++ b/ui/hunter/beast_mastery/inputs.ts @@ -33,14 +33,6 @@ export const BMRotationConfig = { label: 'Trap Weave', labelTooltip: 'Uses Explosive Trap at appropriate times. Note that selecting this will disable Black Arrow because they share a CD.', }), - InputHelpers.makeRotationBooleanInput({ - fieldName: 'allowExplosiveShotDownrank', - label: 'Allow ES Downrank', - labelTooltip: 'Weaves Explosive Shot Rank 3 during LNL procs. This works because the rank 3 and rank 4 dots can stack.', - showWhen: (player: Player) => - player.getSimpleRotation().type != RotationType.Custom && player.getTalents().explosiveShot && player.getTalents().lockAndLoad > 0, - changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), - }), InputHelpers.makeRotationBooleanInput({ fieldName: 'multiDotSerpentSting', label: 'Multi-Dot Serpent Sting', diff --git a/ui/hunter/beast_mastery/presets.ts b/ui/hunter/beast_mastery/presets.ts index 6086795686..783c243695 100644 --- a/ui/hunter/beast_mastery/presets.ts +++ b/ui/hunter/beast_mastery/presets.ts @@ -51,15 +51,15 @@ export const ROTATION_PRESET_AOE = PresetUtils.makePresetAPLRotation('AOE', AoeA export const BeastMasteryTalents = { name: 'Beast Mastery', data: SavedTalents.create({ - talentsString: '51200201505112243120531251-025305101', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfBestialWrath, - major2: MajorGlyph.GlyphOfSteadyShot, - major3: MajorGlyph.GlyphOfSerpentSting, - minor1: MinorGlyph.GlyphOfFeignDeath, - minor2: MinorGlyph.GlyphOfRevivePet, - minor3: MinorGlyph.GlyphOfMendPet, - }), + // talentsString: '51200201505112243120531251-025305101', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfBestialWrath, + // major2: MajorGlyph.GlyphOfSteadyShot, + // major3: MajorGlyph.GlyphOfSerpentSting, + // minor1: MinorGlyph.GlyphOfFeignDeath, + // minor2: MinorGlyph.GlyphOfRevivePet, + // minor3: MinorGlyph.GlyphOfMendPet, + // }), }), }; diff --git a/ui/hunter/marksmanship/inputs.ts b/ui/hunter/marksmanship/inputs.ts index 62009ee96b..441596ce8a 100644 --- a/ui/hunter/marksmanship/inputs.ts +++ b/ui/hunter/marksmanship/inputs.ts @@ -33,14 +33,6 @@ export const MMRotationConfig = { label: 'Trap Weave', labelTooltip: 'Uses Explosive Trap at appropriate times. Note that selecting this will disable Black Arrow because they share a CD.', }), - InputHelpers.makeRotationBooleanInput({ - fieldName: 'allowExplosiveShotDownrank', - label: 'Allow ES Downrank', - labelTooltip: 'Weaves Explosive Shot Rank 3 during LNL procs. This works because the rank 3 and rank 4 dots can stack.', - showWhen: (player: Player) => - player.getSimpleRotation().type != RotationType.Custom && player.getTalents().explosiveShot && player.getTalents().lockAndLoad > 0, - changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), - }), InputHelpers.makeRotationBooleanInput({ fieldName: 'multiDotSerpentSting', label: 'Multi-Dot Serpent Sting', diff --git a/ui/hunter/marksmanship/presets.ts b/ui/hunter/marksmanship/presets.ts index 08a7cd0935..9d2a1d3a18 100644 --- a/ui/hunter/marksmanship/presets.ts +++ b/ui/hunter/marksmanship/presets.ts @@ -53,15 +53,15 @@ export const ROTATION_PRESET_AOE = PresetUtils.makePresetAPLRotation('AOE', AoeA export const MarksmanTalents = { name: 'Marksman', data: SavedTalents.create({ - talentsString: '502-025335101030013233135031051-5000032', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfSerpentSting, - major2: MajorGlyph.GlyphOfSteadyShot, - major3: MajorGlyph.GlyphOfExplosiveTrap, - minor1: MinorGlyph.GlyphOfFeignDeath, - minor2: MinorGlyph.GlyphOfRevivePet, - minor3: MinorGlyph.GlyphOfMendPet, - }), + // talentsString: '502-025335101030013233135031051-5000032', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfSerpentSting, + // major2: MajorGlyph.GlyphOfSteadyShot, + // major3: MajorGlyph.GlyphOfExplosiveTrap, + // minor1: MinorGlyph.GlyphOfFeignDeath, + // minor2: MinorGlyph.GlyphOfRevivePet, + // minor3: MinorGlyph.GlyphOfMendPet, + // }), }), }; diff --git a/ui/hunter/marksmanship/sim.ts b/ui/hunter/marksmanship/sim.ts index 7ccf00e9f3..4e978e8f55 100644 --- a/ui/hunter/marksmanship/sim.ts +++ b/ui/hunter/marksmanship/sim.ts @@ -64,7 +64,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecMarksmanshipHunter, { ], modifyDisplayStats: (player: Player) => { let stats = new Stats(); - stats = stats.addStat(Stat.StatMeleeCrit, player.getTalents().lethalShots * 1 * Mechanics.MELEE_CRIT_RATING_PER_CRIT_CHANCE); + //stats = stats.addStat(Stat.StatMeleeCrit, player.getTalents().lethalShots * 1 * Mechanics.MELEE_CRIT_RATING_PER_CRIT_CHANCE); const rangedWeapon = player.getEquippedItem(ItemSlot.ItemSlotRanged); if (rangedWeapon?.enchant?.effectId == 3608) { diff --git a/ui/hunter/survival/inputs.ts b/ui/hunter/survival/inputs.ts index abf9f42248..6a4a09691a 100644 --- a/ui/hunter/survival/inputs.ts +++ b/ui/hunter/survival/inputs.ts @@ -42,14 +42,14 @@ export const SVRotationConfig = { label: 'Trap Weave', labelTooltip: 'Uses Explosive Trap at appropriate times. Note that selecting this will disable Black Arrow because they share a CD.', }), - InputHelpers.makeRotationBooleanInput({ - fieldName: 'allowExplosiveShotDownrank', - label: 'Allow ES Downrank', - labelTooltip: 'Weaves Explosive Shot Rank 3 during LNL procs. This works because the rank 3 and rank 4 dots can stack.', - showWhen: (player: Player) => - player.getSimpleRotation().type != RotationType.Custom && player.getTalents().explosiveShot && player.getTalents().lockAndLoad > 0, - changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), - }), + // InputHelpers.makeRotationBooleanInput({ + // fieldName: 'allowExplosiveShotDownrank', + // label: 'Allow ES Downrank', + // labelTooltip: 'Weaves Explosive Shot Rank 3 during LNL procs. This works because the rank 3 and rank 4 dots can stack.', + // showWhen: (player: Player) => + // player.getSimpleRotation().type != RotationType.Custom && player.getTalents().explosiveShot && player.getTalents().lockAndLoad > 0, + // changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), + // }), InputHelpers.makeRotationBooleanInput({ fieldName: 'multiDotSerpentSting', label: 'Multi-Dot Serpent Sting', diff --git a/ui/hunter/survival/presets.ts b/ui/hunter/survival/presets.ts index ae31eb1ab1..3c4a1afded 100644 --- a/ui/hunter/survival/presets.ts +++ b/ui/hunter/survival/presets.ts @@ -53,15 +53,15 @@ export const ROTATION_PRESET_AOE = PresetUtils.makePresetAPLRotation('AOE', AoeA export const SurvivalTalents = { name: 'Survival', data: SavedTalents.create({ - talentsString: '-005305101-5000032500033330531135301331', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfSerpentSting, - major2: MajorGlyph.GlyphOfExplosiveTrap, - major3: MajorGlyph.GlyphOfKillShot, - minor1: MinorGlyph.GlyphOfFeignDeath, - minor2: MinorGlyph.GlyphOfRevivePet, - minor3: MinorGlyph.GlyphOfMendPet, - }), + // talentsString: '-005305101-5000032500033330531135301331', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfSerpentSting, + // major2: MajorGlyph.GlyphOfExplosiveTrap, + // major3: MajorGlyph.GlyphOfKillShot, + // minor1: MinorGlyph.GlyphOfFeignDeath, + // minor2: MinorGlyph.GlyphOfRevivePet, + // minor3: MinorGlyph.GlyphOfMendPet, + // }), }), }; diff --git a/ui/hunter/survival/sim.ts b/ui/hunter/survival/sim.ts index 923015f2b1..580cfb0a8a 100644 --- a/ui/hunter/survival/sim.ts +++ b/ui/hunter/survival/sim.ts @@ -65,7 +65,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecSurvivalHunter, { ], modifyDisplayStats: (player: Player) => { let stats = new Stats(); - stats = stats.addStat(Stat.StatMeleeCrit, player.getTalents().lethalShots * 1 * Mechanics.MELEE_CRIT_RATING_PER_CRIT_CHANCE); + //stats = stats.addStat(Stat.StatMeleeCrit, player.getTalents().lethalShots * 1 * Mechanics.MELEE_CRIT_RATING_PER_CRIT_CHANCE); const rangedWeapon = player.getEquippedItem(ItemSlot.ItemSlotRanged); if (rangedWeapon?.enchant?.effectId == 3608) { diff --git a/ui/mage/arcane/inputs.ts b/ui/mage/arcane/inputs.ts index 78d58aa954..68ab47b9eb 100644 --- a/ui/mage/arcane/inputs.ts +++ b/ui/mage/arcane/inputs.ts @@ -42,13 +42,13 @@ export const MageRotationConfig = { showWhen: (player: Player) => player.getTalentTree() == 0, changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), }), - InputHelpers.makeRotationBooleanInput({ - fieldName: 'useArcaneBarrage', - label: 'Use Arcane Barrage', - labelTooltip: 'Includes Arcane Barrage in the rotation.', - enableWhen: (player: Player) => player.getTalents().arcaneBarrage, - showWhen: (player: Player) => player.getTalentTree() == 0, - changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), - }), + // InputHelpers.makeRotationBooleanInput({ + // fieldName: 'useArcaneBarrage', + // label: 'Use Arcane Barrage', + // labelTooltip: 'Includes Arcane Barrage in the rotation.', + // enableWhen: (player: Player) => player.getTalents().arcaneBarrage, + // showWhen: (player: Player) => player.getTalentTree() == 0, + // changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), + // }), ], }; diff --git a/ui/mage/arcane/presets.ts b/ui/mage/arcane/presets.ts index 257194dfd3..fb3a512947 100644 --- a/ui/mage/arcane/presets.ts +++ b/ui/mage/arcane/presets.ts @@ -44,15 +44,15 @@ export const ARCANE_ROTATION_PRESET_AOE = PresetUtils.makePresetAPLRotation('Arc export const ArcaneTalents = { name: 'Arcane', data: SavedTalents.create({ - talentsString: '23000513310033015032310250532-03-023303001', - glyphs: Glyphs.create({ - major1: MageMajorGlyph.GlyphOfArcaneBlast, - major2: MageMajorGlyph.GlyphOfArcaneMissiles, - major3: MageMajorGlyph.GlyphOfMoltenArmor, - minor1: MageMinorGlyph.GlyphOfSlowFall, - minor2: MageMinorGlyph.GlyphOfFrostWard, - minor3: MageMinorGlyph.GlyphOfBlastWave, - }), + // talentsString: '23000513310033015032310250532-03-023303001', + // glyphs: Glyphs.create({ + // major1: MageMajorGlyph.GlyphOfArcaneBlast, + // major2: MageMajorGlyph.GlyphOfArcaneMissiles, + // major3: MageMajorGlyph.GlyphOfMoltenArmor, + // minor1: MageMinorGlyph.GlyphOfSlowFall, + // minor2: MageMinorGlyph.GlyphOfFrostWard, + // minor3: MageMinorGlyph.GlyphOfBlastWave, + // }), }), }; diff --git a/ui/mage/arcane/sim.ts b/ui/mage/arcane/sim.ts index ac7184ab2b..0e223e7ed7 100644 --- a/ui/mage/arcane/sim.ts +++ b/ui/mage/arcane/sim.ts @@ -36,17 +36,17 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecArcaneMage, { Stat.StatSpellHaste, Stat.StatMP5, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); - if (player.getTalentTree() === 0) { - stats = stats.addStat(Stat.StatSpellHit, player.getTalents().arcaneFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); - } + // if (player.getTalentTree() === 0) { + // stats = stats.addStat(Stat.StatSpellHit, player.getTalents().arcaneFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); + // } - return { - talents: stats, - }; - }, + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. diff --git a/ui/mage/fire/presets.ts b/ui/mage/fire/presets.ts index 19d116f108..3f21725f81 100644 --- a/ui/mage/fire/presets.ts +++ b/ui/mage/fire/presets.ts @@ -59,15 +59,15 @@ export const FIRE_ROTATION_PRESET_AOE = PresetUtils.makePresetAPLRotation('Fire export const FireTalents = { name: 'Fire', data: SavedTalents.create({ - talentsString: '23000503110003-0055030012303331053120301351', - glyphs: Glyphs.create({ - major1: MageMajorGlyph.GlyphOfFireball, - major2: MageMajorGlyph.GlyphOfMoltenArmor, - major3: MageMajorGlyph.GlyphOfLivingBomb, - minor1: MageMinorGlyph.GlyphOfSlowFall, - minor2: MageMinorGlyph.GlyphOfFrostWard, - minor3: MageMinorGlyph.GlyphOfBlastWave, - }), + // talentsString: '23000503110003-0055030012303331053120301351', + // glyphs: Glyphs.create({ + // major1: MageMajorGlyph.GlyphOfFireball, + // major2: MageMajorGlyph.GlyphOfMoltenArmor, + // major3: MageMajorGlyph.GlyphOfLivingBomb, + // minor1: MageMinorGlyph.GlyphOfSlowFall, + // minor2: MageMinorGlyph.GlyphOfFrostWard, + // minor3: MageMinorGlyph.GlyphOfBlastWave, + // }), }), }; diff --git a/ui/mage/fire/sim.ts b/ui/mage/fire/sim.ts index ffa2481b3f..b29cbe308d 100644 --- a/ui/mage/fire/sim.ts +++ b/ui/mage/fire/sim.ts @@ -35,17 +35,17 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecFireMage, { Stat.StatSpellHaste, Stat.StatMP5, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); - if (player.getTalentTree() === 0) { - stats = stats.addStat(Stat.StatSpellHit, player.getTalents().arcaneFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); - } + // if (player.getTalentTree() === 0) { + // stats = stats.addStat(Stat.StatSpellHit, player.getTalents().arcaneFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); + // } - return { - talents: stats, - }; - }, + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. diff --git a/ui/mage/frost/inputs.ts b/ui/mage/frost/inputs.ts index a2b11f177d..125b61c564 100644 --- a/ui/mage/frost/inputs.ts +++ b/ui/mage/frost/inputs.ts @@ -6,14 +6,14 @@ import { TypedEvent } from '../../core/typed_event'; // Configuration for spec-specific UI elements on the settings tab. // These don't need to be in a separate file but it keeps things cleaner. -export const WaterElementalDisobeyChance = InputHelpers.makeSpecOptionsNumberInput({ - fieldName: 'waterElementalDisobeyChance', - percent: true, - label: 'Water Ele Disobey %', - labelTooltip: 'Percent of Water Elemental actions which will fail. This represents the Water Elemental moving around or standing still instead of casting.', - changeEmitter: (player: Player) => TypedEvent.onAny([player.specOptionsChangeEmitter, player.talentsChangeEmitter]), - showWhen: (player: Player) => player.getTalents().summonWaterElemental, -}); +// export const WaterElementalDisobeyChance = InputHelpers.makeSpecOptionsNumberInput({ +// fieldName: 'waterElementalDisobeyChance', +// percent: true, +// label: 'Water Ele Disobey %', +// labelTooltip: 'Percent of Water Elemental actions which will fail. This represents the Water Elemental moving around or standing still instead of casting.', +// changeEmitter: (player: Player) => TypedEvent.onAny([player.specOptionsChangeEmitter, player.talentsChangeEmitter]), +// showWhen: (player: Player) => player.getTalents().summonWaterElemental, +// }); export const MageRotationConfig = { inputs: [ diff --git a/ui/mage/frost/presets.ts b/ui/mage/frost/presets.ts index f4d3becfaa..cb0dd3b6d4 100644 --- a/ui/mage/frost/presets.ts +++ b/ui/mage/frost/presets.ts @@ -37,15 +37,15 @@ export const FROST_ROTATION_PRESET_AOE = PresetUtils.makePresetAPLRotation('Fros export const FrostTalents = { name: 'Frost', data: SavedTalents.create({ - talentsString: '23000503110003--0533030310233100030152231351', - glyphs: Glyphs.create({ - major1: MageMajorGlyph.GlyphOfFrostbolt, - major2: MageMajorGlyph.GlyphOfEternalWater, - major3: MageMajorGlyph.GlyphOfMoltenArmor, - minor1: MageMinorGlyph.GlyphOfSlowFall, - minor2: MageMinorGlyph.GlyphOfFrostWard, - minor3: MageMinorGlyph.GlyphOfBlastWave, - }), + // talentsString: '23000503110003--0533030310233100030152231351', + // glyphs: Glyphs.create({ + // major1: MageMajorGlyph.GlyphOfFrostbolt, + // major2: MageMajorGlyph.GlyphOfEternalWater, + // major3: MageMajorGlyph.GlyphOfMoltenArmor, + // minor1: MageMinorGlyph.GlyphOfSlowFall, + // minor2: MageMinorGlyph.GlyphOfFrostWard, + // minor3: MageMinorGlyph.GlyphOfBlastWave, + // }), }), }; diff --git a/ui/mage/frost/sim.ts b/ui/mage/frost/sim.ts index fb2db78650..7fe844d0e0 100644 --- a/ui/mage/frost/sim.ts +++ b/ui/mage/frost/sim.ts @@ -35,17 +35,17 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecFrostMage, { Stat.StatSpellHaste, Stat.StatMP5, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); - if (player.getTalentTree() === 0) { - stats = stats.addStat(Stat.StatSpellHit, player.getTalents().arcaneFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); - } + // if (player.getTalentTree() === 0) { + // stats = stats.addStat(Stat.StatSpellHit, player.getTalents().arcaneFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); + // } - return { - talents: stats, - }; - }, + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. @@ -110,7 +110,9 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecFrostMage, { excludeBuffDebuffInputs: [], // Inputs to include in the 'Other' section on the settings tab. otherInputs: { - inputs: [FrostInputs.WaterElementalDisobeyChance, OtherInputs.ReactionTime, OtherInputs.DistanceFromTarget, OtherInputs.TankAssignment], + inputs: [ + //FrostInputs.WaterElementalDisobeyChance, + OtherInputs.ReactionTime, OtherInputs.DistanceFromTarget, OtherInputs.TankAssignment], }, encounterPicker: { // Whether to include 'Execute Duration (%)' in the 'Encounter' section of the settings tab. diff --git a/ui/paladin/holy/presets.ts b/ui/paladin/holy/presets.ts index ce3d90dfed..1d0b5d6880 100644 --- a/ui/paladin/holy/presets.ts +++ b/ui/paladin/holy/presets.ts @@ -24,15 +24,15 @@ export const P4_PRESET = PresetUtils.makePresetGear('P4 Preset', P4Gear); export const StandardTalents = { name: 'Standard', data: SavedTalents.create({ - talentsString: '50350151020013053100515221-50023131203', - glyphs: { - major1: PaladinMajorGlyph.GlyphOfHolyLight, - major2: PaladinMajorGlyph.GlyphOfSealOfWisdom, - major3: PaladinMajorGlyph.GlyphOfBeaconOfLight, - minor2: PaladinMinorGlyph.GlyphOfLayOnHands, - minor1: PaladinMinorGlyph.GlyphOfSenseUndead, - minor3: PaladinMinorGlyph.GlyphOfBlessingOfKings, - }, + // talentsString: '50350151020013053100515221-50023131203', + // glyphs: { + // major1: PaladinMajorGlyph.GlyphOfHolyLight, + // major2: PaladinMajorGlyph.GlyphOfSealOfWisdom, + // major3: PaladinMajorGlyph.GlyphOfBeaconOfLight, + // minor2: PaladinMinorGlyph.GlyphOfLayOnHands, + // minor1: PaladinMinorGlyph.GlyphOfSenseUndead, + // minor3: PaladinMinorGlyph.GlyphOfBlessingOfKings, + // }, }), }; diff --git a/ui/paladin/inputs.ts b/ui/paladin/inputs.ts index e116ffea46..11cd12bf41 100644 --- a/ui/paladin/inputs.ts +++ b/ui/paladin/inputs.ts @@ -16,20 +16,20 @@ export const AuraSelection = () => ], }); -export const StartingSealSelection = () => - InputHelpers.makeClassOptionsEnumIconInput({ - fieldName: 'seal', - values: [ - { actionId: ActionId.fromSpellId(42463), value: PaladinSeal.Vengeance }, - { actionId: ActionId.fromSpellId(20154), value: PaladinSeal.Righteousness }, - { - actionId: ActionId.fromSpellId(20424), - value: PaladinSeal.Command, - showWhen: (player: Player) => player.getTalents().sealOfCommand, - }, - ], - changeEmitter: (player: Player) => player.changeEmitter, - }); +// export const StartingSealSelection = () => +// InputHelpers.makeClassOptionsEnumIconInput({ +// fieldName: 'seal', +// values: [ +// { actionId: ActionId.fromSpellId(42463), value: PaladinSeal.Vengeance }, +// { actionId: ActionId.fromSpellId(20154), value: PaladinSeal.Righteousness }, +// { +// actionId: ActionId.fromSpellId(20424), +// value: PaladinSeal.Command, +// showWhen: (player: Player) => player.getTalents().sealOfCommand, +// }, +// ], +// changeEmitter: (player: Player) => player.changeEmitter, +// }); export const JudgementSelection = () => InputHelpers.makeClassOptionsEnumIconInput({ diff --git a/ui/paladin/protection/presets.ts b/ui/paladin/protection/presets.ts index b0962cc9d0..b599408646 100644 --- a/ui/paladin/protection/presets.ts +++ b/ui/paladin/protection/presets.ts @@ -35,15 +35,15 @@ export const ROTATION_DEFAULT = PresetUtils.makePresetAPLRotation('Default (969) export const GenericAoeTalents = { name: 'Baseline Example', data: SavedTalents.create({ - talentsString: '-05005135200132311333312321-511302012003', - glyphs: { - major1: PaladinMajorGlyph.GlyphOfSealOfVengeance, - major2: PaladinMajorGlyph.GlyphOfRighteousDefense, - major3: PaladinMajorGlyph.GlyphOfDivinePlea, - minor1: PaladinMinorGlyph.GlyphOfSenseUndead, - minor2: PaladinMinorGlyph.GlyphOfLayOnHands, - minor3: PaladinMinorGlyph.GlyphOfBlessingOfKings, - }, + // talentsString: '-05005135200132311333312321-511302012003', + // glyphs: { + // major1: PaladinMajorGlyph.GlyphOfSealOfVengeance, + // major2: PaladinMajorGlyph.GlyphOfRighteousDefense, + // major3: PaladinMajorGlyph.GlyphOfDivinePlea, + // minor1: PaladinMinorGlyph.GlyphOfSenseUndead, + // minor2: PaladinMinorGlyph.GlyphOfLayOnHands, + // minor3: PaladinMinorGlyph.GlyphOfBlessingOfKings, + // }, }), }; diff --git a/ui/paladin/protection/sim.ts b/ui/paladin/protection/sim.ts index 0fa7732b91..b5bad8f357 100644 --- a/ui/paladin/protection/sim.ts +++ b/ui/paladin/protection/sim.ts @@ -74,22 +74,22 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecProtectionPaladin, { Stat.StatShadowResistance, Stat.StatFrostResistance, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); - TypedEvent.freezeAllAndDo(() => { - if ( - player.getMajorGlyphs().includes(PaladinMajorGlyph.GlyphOfSealOfVengeance) && - player.getSpecOptions().classOptions?.seal == PaladinSeal.Vengeance - ) { - stats = stats.addStat(Stat.StatExpertise, 10 * Mechanics.EXPERTISE_PER_QUARTER_PERCENT_REDUCTION); - } - }); + // TypedEvent.freezeAllAndDo(() => { + // if ( + // player.getMajorGlyphs().includes(PaladinMajorGlyph.GlyphOfSealOfVengeance) && + // player.getSpecOptions().classOptions?.seal == PaladinSeal.Vengeance + // ) { + // stats = stats.addStat(Stat.StatExpertise, 10 * Mechanics.EXPERTISE_PER_QUARTER_PERCENT_REDUCTION); + // } + // }); - return { - talents: stats, - }; - }, + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. gear: Presets.P3_PRESET.gear, @@ -170,7 +170,9 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecProtectionPaladin, { }, // IconInputs to include in the 'Player' section on the settings tab. - playerIconInputs: [PaladinInputs.AuraSelection(), PaladinInputs.JudgementSelection(), PaladinInputs.StartingSealSelection()], + playerIconInputs: [PaladinInputs.AuraSelection(), PaladinInputs.JudgementSelection(), + //PaladinInputs.StartingSealSelection() + ], // Buff and Debuff inputs to include/exclude, overriding the EP-based defaults. includeBuffDebuffInputs: [BuffDebuffInputs.HealthBuff], excludeBuffDebuffInputs: [], diff --git a/ui/paladin/retribution/presets.ts b/ui/paladin/retribution/presets.ts index 09b7389b11..3de381e8bb 100644 --- a/ui/paladin/retribution/presets.ts +++ b/ui/paladin/retribution/presets.ts @@ -34,30 +34,30 @@ export const ROTATION_PRESET_DEFAULT = PresetUtils.makePresetAPLRotation('Defaul export const AuraMasteryTalents = { name: 'Aura Mastery', data: SavedTalents.create({ - talentsString: '050501-05-05232051203331302133231331', - glyphs: Glyphs.create({ - major1: PaladinMajorGlyph.GlyphOfSealOfVengeance, - major2: PaladinMajorGlyph.GlyphOfJudgement, - major3: PaladinMajorGlyph.GlyphOfReckoning, - minor1: PaladinMinorGlyph.GlyphOfSenseUndead, - minor2: PaladinMinorGlyph.GlyphOfLayOnHands, - minor3: PaladinMinorGlyph.GlyphOfBlessingOfKings, - }), + // talentsString: '050501-05-05232051203331302133231331', + // glyphs: Glyphs.create({ + // major1: PaladinMajorGlyph.GlyphOfSealOfVengeance, + // major2: PaladinMajorGlyph.GlyphOfJudgement, + // major3: PaladinMajorGlyph.GlyphOfReckoning, + // minor1: PaladinMinorGlyph.GlyphOfSenseUndead, + // minor2: PaladinMinorGlyph.GlyphOfLayOnHands, + // minor3: PaladinMinorGlyph.GlyphOfBlessingOfKings, + // }), }), }; export const DivineSacTalents = { name: 'Divine Sacrifice & Guardian', data: SavedTalents.create({ - talentsString: '03-453201002-05222051203331302133201331', - glyphs: Glyphs.create({ - major1: PaladinMajorGlyph.GlyphOfSealOfVengeance, - major2: PaladinMajorGlyph.GlyphOfJudgement, - major3: PaladinMajorGlyph.GlyphOfReckoning, - minor1: PaladinMinorGlyph.GlyphOfSenseUndead, - minor2: PaladinMinorGlyph.GlyphOfLayOnHands, - minor3: PaladinMinorGlyph.GlyphOfBlessingOfKings, - }), + // talentsString: '03-453201002-05222051203331302133201331', + // glyphs: Glyphs.create({ + // major1: PaladinMajorGlyph.GlyphOfSealOfVengeance, + // major2: PaladinMajorGlyph.GlyphOfJudgement, + // major3: PaladinMajorGlyph.GlyphOfReckoning, + // minor1: PaladinMinorGlyph.GlyphOfSenseUndead, + // minor2: PaladinMinorGlyph.GlyphOfLayOnHands, + // minor3: PaladinMinorGlyph.GlyphOfBlessingOfKings, + // }), }), }; diff --git a/ui/paladin/retribution/sim.ts b/ui/paladin/retribution/sim.ts index 5910641c39..40e160e91d 100644 --- a/ui/paladin/retribution/sim.ts +++ b/ui/paladin/retribution/sim.ts @@ -58,22 +58,22 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecRetributionPaladin, { Stat.StatMana, Stat.StatHealth, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); - TypedEvent.freezeAllAndDo(() => { - if ( - player.getMajorGlyphs().includes(PaladinMajorGlyph.GlyphOfSealOfVengeance) && - player.getSpecOptions().classOptions?.seal == PaladinSeal.Vengeance - ) { - stats = stats.addStat(Stat.StatExpertise, 10 * Mechanics.EXPERTISE_PER_QUARTER_PERCENT_REDUCTION); - } - }); + // TypedEvent.freezeAllAndDo(() => { + // if ( + // player.getMajorGlyphs().includes(PaladinMajorGlyph.GlyphOfSealOfVengeance) && + // player.getSpecOptions().classOptions?.seal == PaladinSeal.Vengeance + // ) { + // stats = stats.addStat(Stat.StatExpertise, 10 * Mechanics.EXPERTISE_PER_QUARTER_PERCENT_REDUCTION); + // } + // }); - return { - talents: stats, - }; - }, + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. @@ -147,7 +147,9 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecRetributionPaladin, { }, // IconInputs to include in the 'Player' section on the settings tab. - playerIconInputs: [PaladinInputs.AuraSelection(), PaladinInputs.JudgementSelection(), PaladinInputs.StartingSealSelection()], + playerIconInputs: [PaladinInputs.AuraSelection(), PaladinInputs.JudgementSelection(), + //PaladinInputs.StartingSealSelection() + ], // Buff and Debuff inputs to include/exclude, overriding the EP-based defaults. includeBuffDebuffInputs: [BuffDebuffInputs.ReplenishmentBuff], excludeBuffDebuffInputs: [], diff --git a/ui/priest/discipline/presets.ts b/ui/priest/discipline/presets.ts index 23e515ff19..561013c0f3 100644 --- a/ui/priest/discipline/presets.ts +++ b/ui/priest/discipline/presets.ts @@ -33,30 +33,30 @@ export const ROTATION_PRESET_AOE4PLUS = PresetUtils.makePresetAPLRotation('AOE ( export const StandardTalents = { name: 'Standard', data: SavedTalents.create({ - talentsString: '05032031--325023051223010323151301351', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfShadow, - major2: MajorGlyph.GlyphOfMindFlay, - major3: MajorGlyph.GlyphOfDispersion, - minor1: MinorGlyph.GlyphOfFortitude, - minor2: MinorGlyph.GlyphOfShadowProtection, - minor3: MinorGlyph.GlyphOfShadowfiend, - }), + // talentsString: '05032031--325023051223010323151301351', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfShadow, + // major2: MajorGlyph.GlyphOfMindFlay, + // major3: MajorGlyph.GlyphOfDispersion, + // minor1: MinorGlyph.GlyphOfFortitude, + // minor2: MinorGlyph.GlyphOfShadowProtection, + // minor3: MinorGlyph.GlyphOfShadowfiend, + // }), }), }; export const EnlightenmentTalents = { name: 'Enlightenment', data: SavedTalents.create({ - talentsString: '05032031303005022--3250230012230101231513011', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfShadow, - major2: MajorGlyph.GlyphOfMindFlay, - major3: MajorGlyph.GlyphOfShadowWordDeath, - minor1: MinorGlyph.GlyphOfFortitude, - minor2: MinorGlyph.GlyphOfShadowProtection, - minor3: MinorGlyph.GlyphOfShadowfiend, - }), + // talentsString: '05032031303005022--3250230012230101231513011', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfShadow, + // major2: MajorGlyph.GlyphOfMindFlay, + // major3: MajorGlyph.GlyphOfShadowWordDeath, + // minor1: MinorGlyph.GlyphOfFortitude, + // minor2: MinorGlyph.GlyphOfShadowProtection, + // minor3: MinorGlyph.GlyphOfShadowfiend, + // }), }), }; diff --git a/ui/priest/discipline/sim.ts b/ui/priest/discipline/sim.ts index 333bdc9f16..d0df3c200d 100644 --- a/ui/priest/discipline/sim.ts +++ b/ui/priest/discipline/sim.ts @@ -33,14 +33,14 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecDisciplinePriest, { Stat.StatSpellHaste, Stat.StatMP5, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); - stats = stats.addStat(Stat.StatSpellHit, player.getTalents().shadowFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); + // stats = stats.addStat(Stat.StatSpellHit, player.getTalents().shadowFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); - return { - talents: stats, - }; - }, + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. diff --git a/ui/priest/holy/presets.ts b/ui/priest/holy/presets.ts index 111ab1396b..4f1fc414ac 100644 --- a/ui/priest/holy/presets.ts +++ b/ui/priest/holy/presets.ts @@ -30,30 +30,30 @@ export const ROTATION_PRESET_AOE4PLUS = PresetUtils.makePresetAPLRotation('AOE ( export const StandardTalents = { name: 'Standard', data: SavedTalents.create({ - talentsString: '05032031--325023051223010323151301351', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfShadow, - major2: MajorGlyph.GlyphOfMindFlay, - major3: MajorGlyph.GlyphOfDispersion, - minor1: MinorGlyph.GlyphOfFortitude, - minor2: MinorGlyph.GlyphOfShadowProtection, - minor3: MinorGlyph.GlyphOfShadowfiend, - }), + // talentsString: '05032031--325023051223010323151301351', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfShadow, + // major2: MajorGlyph.GlyphOfMindFlay, + // major3: MajorGlyph.GlyphOfDispersion, + // minor1: MinorGlyph.GlyphOfFortitude, + // minor2: MinorGlyph.GlyphOfShadowProtection, + // minor3: MinorGlyph.GlyphOfShadowfiend, + // }), }), }; export const EnlightenmentTalents = { name: 'Enlightenment', data: SavedTalents.create({ - talentsString: '05032031303005022--3250230012230101231513011', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfShadow, - major2: MajorGlyph.GlyphOfMindFlay, - major3: MajorGlyph.GlyphOfShadowWordDeath, - minor1: MinorGlyph.GlyphOfFortitude, - minor2: MinorGlyph.GlyphOfShadowProtection, - minor3: MinorGlyph.GlyphOfShadowfiend, - }), + // talentsString: '05032031303005022--3250230012230101231513011', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfShadow, + // major2: MajorGlyph.GlyphOfMindFlay, + // major3: MajorGlyph.GlyphOfShadowWordDeath, + // minor1: MinorGlyph.GlyphOfFortitude, + // minor2: MinorGlyph.GlyphOfShadowProtection, + // minor3: MinorGlyph.GlyphOfShadowfiend, + // }), }), }; diff --git a/ui/priest/holy/sim.ts b/ui/priest/holy/sim.ts index 71fdd4310d..168bdc48e1 100644 --- a/ui/priest/holy/sim.ts +++ b/ui/priest/holy/sim.ts @@ -33,14 +33,14 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecHolyPriest, { Stat.StatSpellHaste, Stat.StatMP5, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); - stats = stats.addStat(Stat.StatSpellHit, player.getTalents().shadowFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); + // stats = stats.addStat(Stat.StatSpellHit, player.getTalents().shadowFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); - return { - talents: stats, - }; - }, + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. diff --git a/ui/priest/shadow/presets.ts b/ui/priest/shadow/presets.ts index 42fca6b91e..0a3be10a23 100644 --- a/ui/priest/shadow/presets.ts +++ b/ui/priest/shadow/presets.ts @@ -35,30 +35,30 @@ export const ROTATION_PRESET_AOE4PLUS = PresetUtils.makePresetAPLRotation('AOE ( export const StandardTalents = { name: 'Standard', data: SavedTalents.create({ - talentsString: '05032031--325023051223010323151301351', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfShadow, - major2: MajorGlyph.GlyphOfMindFlay, - major3: MajorGlyph.GlyphOfDispersion, - minor1: MinorGlyph.GlyphOfFortitude, - minor2: MinorGlyph.GlyphOfShadowProtection, - minor3: MinorGlyph.GlyphOfShadowfiend, - }), + // talentsString: '05032031--325023051223010323151301351', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfShadow, + // major2: MajorGlyph.GlyphOfMindFlay, + // major3: MajorGlyph.GlyphOfDispersion, + // minor1: MinorGlyph.GlyphOfFortitude, + // minor2: MinorGlyph.GlyphOfShadowProtection, + // minor3: MinorGlyph.GlyphOfShadowfiend, + // }), }), }; export const EnlightenmentTalents = { name: 'Enlightenment', data: SavedTalents.create({ - talentsString: '05032031303005022--3250230012230101231513011', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfShadow, - major2: MajorGlyph.GlyphOfMindFlay, - major3: MajorGlyph.GlyphOfShadowWordDeath, - minor1: MinorGlyph.GlyphOfFortitude, - minor2: MinorGlyph.GlyphOfShadowProtection, - minor3: MinorGlyph.GlyphOfShadowfiend, - }), + // talentsString: '05032031303005022--3250230012230101231513011', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfShadow, + // major2: MajorGlyph.GlyphOfMindFlay, + // major3: MajorGlyph.GlyphOfShadowWordDeath, + // minor1: MinorGlyph.GlyphOfFortitude, + // minor2: MinorGlyph.GlyphOfShadowProtection, + // minor3: MinorGlyph.GlyphOfShadowfiend, + // }), }), }; diff --git a/ui/priest/shadow/sim.ts b/ui/priest/shadow/sim.ts index c01a972659..cd05cffa2d 100644 --- a/ui/priest/shadow/sim.ts +++ b/ui/priest/shadow/sim.ts @@ -34,14 +34,14 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecShadowPriest, { Stat.StatSpellHaste, Stat.StatMP5, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); - stats = stats.addStat(Stat.StatSpellHit, player.getTalents().shadowFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); + // stats = stats.addStat(Stat.StatSpellHit, player.getTalents().shadowFocus * 1 * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); - return { - talents: stats, - }; - }, + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. diff --git a/ui/raid/_raid_stats.ts b/ui/raid/_raid_stats.ts new file mode 100644 index 0000000000..64e3fcb693 --- /dev/null +++ b/ui/raid/_raid_stats.ts @@ -0,0 +1,1178 @@ +// import { Tooltip } from 'bootstrap'; + +// import { Component } from '../core/components/component.js'; +// import { Player } from '../core/player.js'; +// import { PlayerClasses } from '../core/player_classes'; +// import { PlayerSpecs } from '../core/player_specs'; +// import { Class, RaidBuffs, Spec } from '../core/proto/common.js'; +// import { HunterOptions_PetType as HunterPetType } from '../core/proto/hunter.js'; +// import { PaladinAura } from '../core/proto/paladin.js'; +// import { AirTotem, EarthTotem, FireTotem, WaterTotem } from '../core/proto/shaman.js'; +// import { WarlockOptions_Summon as WarlockSummon } from '../core/proto/warlock.js'; +// import { WarriorShout } from '../core/proto/warrior.js'; +// import { ActionId } from '../core/proto_utils/action_id.js'; +// import { ClassSpecs, SpecTalents, textCssClassForClass } from '../core/proto_utils/utils.js'; +// import { Raid } from '../core/raid.js'; +// import { sum } from '../core/utils.js'; +// import { RaidSimUI } from './raid_sim_ui.js'; + +// interface RaidStatsOptions { +// sections: Array; +// } + +// interface RaidStatsSectionOptions { +// label: string; +// categories: Array; +// } + +// interface RaidStatsCategoryOptions { +// label: string; +// effects: Array; +// } + +// type PlayerProvider = { class?: Class; condition: (player: Player) => boolean }; +// type RaidProvider = (raid: Raid) => boolean; + +// interface RaidStatsEffectOptions { +// label: string; +// actionId?: ActionId; +// playerData?: PlayerProvider; +// raidData?: RaidProvider; +// } + +// export class RaidStats extends Component { +// private readonly categories: Array; + +// constructor(parent: HTMLElement, raidSimUI: RaidSimUI) { +// super(parent, 'raid-stats'); + +// const categories: Array = []; +// RAID_STATS_OPTIONS.sections.forEach(section => { +// const sectionElem = document.createElement('div'); +// sectionElem.classList.add('raid-stats-section'); +// this.rootElem.appendChild(sectionElem); +// sectionElem.innerHTML = ` +//
+// +//
+//
+// `; +// const contentElem = sectionElem.getElementsByClassName('raid-stats-section-content')[0] as HTMLDivElement; + +// section.categories.forEach(categoryOptions => { +// categories.push(new RaidStatsCategory(contentElem, raidSimUI, categoryOptions)); +// }); +// }); +// this.categories = categories; + +// raidSimUI.changeEmitter.on(_eventID => this.categories.forEach(c => c.update())); +// } +// } + +// class RaidStatsCategory extends Component { +// readonly raidSimUI: RaidSimUI; +// private readonly options: RaidStatsCategoryOptions; +// private readonly effects: Array; +// private readonly counterElem: HTMLElement; +// private readonly tooltipElem: HTMLElement; + +// constructor(parent: HTMLElement, raidSimUI: RaidSimUI, options: RaidStatsCategoryOptions) { +// super(parent, 'raid-stats-category-root'); +// this.raidSimUI = raidSimUI; +// this.options = options; + +// this.rootElem.innerHTML = ` +//
+// +// ${options.label} +// +// `; + +// this.counterElem = this.rootElem.querySelector('.raid-stats-category-counter') as HTMLElement; +// this.tooltipElem = document.createElement('div'); +// this.tooltipElem.innerHTML = ` +// +// `; + +// this.effects = options.effects.map(opt => new RaidStatsEffect(this.tooltipElem, raidSimUI, opt)); + +// if (options.effects.length != 1 || options.effects[0].playerData?.class) { +// const statsLink = this.rootElem.querySelector('.raid-stats-category') as HTMLElement; + +// // Using the title option here because outerHTML sanitizes and filters out the img src options +// Tooltip.getOrCreateInstance(statsLink, { +// customClass: 'raid-stats-category-tooltip', +// html: true, +// placement: 'right', +// title: this.tooltipElem, +// }); +// } +// } + +// update() { +// this.effects.forEach(effect => effect.update()); + +// const total = sum(this.effects.map(effect => effect.count)); +// this.counterElem.textContent = String(total); + +// const statsLink = this.rootElem.querySelector('.raid-stats-category') as HTMLElement; + +// if (total == 0) { +// statsLink?.classList.remove('active'); +// } else { +// statsLink?.classList.add('active'); +// } +// } +// } + +// class RaidStatsEffect extends Component { +// readonly raidSimUI: RaidSimUI; +// private readonly options: RaidStatsEffectOptions; +// private readonly counterElem: HTMLElement; + +// curPlayers: Array>; +// count: number; + +// constructor(parent: HTMLElement, raidSimUI: RaidSimUI, options: RaidStatsEffectOptions) { +// super(parent, 'raid-stats-effect'); +// this.raidSimUI = raidSimUI; +// this.options = options; + +// this.curPlayers = []; +// this.count = 0; + +// this.rootElem.innerHTML = ` +// +// +// ${options.label} +// `; +// this.counterElem = this.rootElem.querySelector('.raid-stats-effect-counter') as HTMLElement; + +// if (this.options.playerData?.class) { +// const labelElem = this.rootElem.querySelector('.raid-stats-effect-label') as HTMLElement; +// const playerCssClass = textCssClassForClass(PlayerClasses.fromProto(this.options.playerData.class)); +// labelElem.classList.add(playerCssClass); +// } + +// const iconElem = this.rootElem.querySelector('.raid-stats-effect-icon') as HTMLImageElement; +// if (options.actionId) { +// options.actionId.fill().then(actionId => (iconElem.src = actionId.iconUrl)); +// } else { +// iconElem.remove(); +// } +// } + +// update() { +// if (this.options.playerData) { +// this.curPlayers = this.raidSimUI.getActivePlayers().filter(p => this.options.playerData!.condition(p)); +// } + +// const raidData = this.options.raidData && this.options.raidData(this.raidSimUI.sim.raid); + +// this.count = this.curPlayers.length + (raidData ? 1 : 0); +// this.counterElem.textContent = String(this.count); +// if (this.count == 0) { +// this.rootElem.classList.remove('active'); +// } else { +// this.rootElem.classList.add('active'); +// } +// } +// } + +// function negateIf(val: boolean, cond: boolean): boolean { +// return cond ? !val : val; +// } + +// function playerClass(clazz: T, extraCondition?: (player: Player>) => boolean): PlayerProvider { +// return { +// class: clazz, +// condition: (player: Player): boolean => { +// return player.isClass(clazz) && (!extraCondition || extraCondition(player)); +// }, +// }; +// } +// function playerClassAndTalentInternal( +// clazz: T, +// talentName: keyof SpecTalents>, +// negateTalent: boolean, +// extraCondition?: (player: Player>) => boolean, +// ): PlayerProvider { +// return { +// class: clazz, +// condition: (player: Player): boolean => { +// return ( +// player.isClass(clazz) && +// negateIf(Boolean((player.getTalents() as any)[talentName]), negateTalent) && +// (!extraCondition || extraCondition(player)) +// ); +// }, +// }; +// } +// function playerClassAndTalent( +// clazz: T, +// talentName: keyof SpecTalents>, +// extraCondition?: (player: Player>) => boolean, +// ): PlayerProvider { +// return playerClassAndTalentInternal(clazz, talentName, false, extraCondition); +// } +// function playerClassAndMissingTalent( +// clazz: T, +// talentName: keyof SpecTalents>, +// extraCondition?: (player: Player>) => boolean, +// ): PlayerProvider { +// return playerClassAndTalentInternal(clazz, talentName, true, extraCondition); +// } +// function playerSpecAndTalentInternal( +// spec: T, +// talentName: keyof SpecTalents, +// negateTalent: boolean, +// extraCondition?: (player: Player) => boolean, +// ): PlayerProvider { +// return { +// class: PlayerSpecs.fromProto(spec).classID, +// condition: (player: Player): boolean => { +// return ( +// player.isSpec(spec) && negateIf(Boolean((player.getTalents() as any)[talentName]), negateTalent) && (!extraCondition || extraCondition(player)) +// ); +// }, +// }; +// } +// function playerSpecAndTalent(spec: T, talentName: keyof SpecTalents, extraCondition?: (player: Player) => boolean): PlayerProvider { +// return playerSpecAndTalentInternal(spec, talentName, false, extraCondition); +// } +// function playerSpecAndMissingTalent( +// spec: T, +// talentName: keyof SpecTalents, +// extraCondition?: (player: Player) => boolean, +// ): PlayerProvider { +// return playerSpecAndTalentInternal(spec, talentName, true, extraCondition); +// } + +// function raidBuff(buffName: keyof RaidBuffs): RaidProvider { +// return (raid: Raid): boolean => { +// return Boolean(raid.getBuffs()[buffName]); +// }; +// } + +// const RAID_STATS_OPTIONS: RaidStatsOptions = { +// sections: [ +// { +// label: 'Roles', +// categories: [ +// { +// label: 'Tanks', +// effects: [ +// { +// label: 'Tanks', +// playerData: { condition: player => player.getSpec().isTankSpec }, +// }, +// ], +// }, +// { +// label: 'Healers', +// effects: [ +// { +// label: 'Healers', +// playerData: { condition: player => player.getSpec().isHealingSpec }, +// }, +// ], +// }, +// { +// label: 'Melee', +// effects: [ +// { +// label: 'Melee', +// playerData: { condition: player => player.getSpec().isMeleeDpsSpec }, +// }, +// ], +// }, +// { +// label: 'Ranged', +// effects: [ +// { +// label: 'Ranged', +// playerData: { condition: player => player.getSpec().isRangedDpsSpec }, +// }, +// ], +// }, +// ], +// }, +// { +// label: 'Buffs', +// categories: [ +// { +// label: 'Bloodlust', +// effects: [ +// { +// label: 'Bloodlust', +// actionId: ActionId.fromSpellId(2825), +// playerData: playerClass(Class.ClassShaman), +// }, +// ], +// }, +// { +// label: 'Stats', +// effects: [ +// { +// label: 'Improved Gift of the Wild', +// actionId: ActionId.fromSpellId(17051), +// playerData: playerClassAndTalent(Class.ClassDruid, 'improvedMarkOfTheWild'), +// }, +// { +// label: 'Gift of the Wild', +// actionId: ActionId.fromSpellId(48470), +// playerData: playerClassAndMissingTalent(Class.ClassDruid, 'improvedMarkOfTheWild'), +// }, +// { +// label: 'Drums of the Wild', +// actionId: ActionId.fromItemId(49634), +// raidData: raidBuff('drumsOfTheWild'), +// }, +// ], +// }, +// { +// label: 'Stats %', +// effects: [ +// { +// label: 'Blessing of Kings', +// actionId: ActionId.fromSpellId(25898), +// playerData: playerClass(Class.ClassPaladin), +// }, +// { +// label: 'Drums of Forgotten Kings', +// actionId: ActionId.fromItemId(49633), +// raidData: raidBuff('drumsOfForgottenKings'), +// }, +// { +// label: 'Blessing of Sanctuary', +// actionId: ActionId.fromSpellId(25899), +// playerData: playerClass(Class.ClassPaladin), +// }, +// ], +// }, +// { +// label: 'Armor', +// effects: [ +// { +// label: 'Improved Devotion Aura', +// actionId: ActionId.fromSpellId(20140), +// playerData: playerClassAndTalent( +// Class.ClassPaladin, +// 'improvedDevotionAura', +// player => player.getSpecOptions().classOptions?.aura == PaladinAura.DevotionAura, +// ), +// }, +// { +// label: 'Devotion Aura', +// actionId: ActionId.fromSpellId(48942), +// playerData: playerClassAndMissingTalent( +// Class.ClassPaladin, +// 'improvedDevotionAura', +// player => player.getSpecOptions().classOptions?.aura == PaladinAura.DevotionAura, +// ), +// }, +// { +// label: 'Improved Stoneskin Totem', +// actionId: ActionId.fromSpellId(16293), +// playerData: playerClassAndTalent( +// Class.ClassShaman, +// 'guardianTotems', +// player => player.getSpecOptions().classOptions?.totems?.earth == EarthTotem.StoneskinTotem, +// ), +// }, +// { +// label: 'Stoneskin Totem', +// actionId: ActionId.fromSpellId(58753), +// playerData: playerClassAndMissingTalent( +// Class.ClassShaman, +// 'guardianTotems', +// player => player.getSpecOptions().classOptions?.totems?.earth == EarthTotem.StoneskinTotem, +// ), +// }, +// { +// label: 'Scroll of Protection', +// actionId: ActionId.fromItemId(43468), +// raidData: raidBuff('scrollOfProtection'), +// }, +// ], +// }, +// { +// label: 'Stamina', +// effects: [ +// { +// label: 'Improved Power Word Fortitude', +// actionId: ActionId.fromSpellId(14767), +// playerData: playerClassAndTalent(Class.ClassPriest, 'improvedPowerWordFortitude'), +// }, +// { +// label: 'Power Word Fortitude', +// actionId: ActionId.fromSpellId(48161), +// playerData: playerClassAndMissingTalent(Class.ClassPriest, 'improvedPowerWordFortitude'), +// }, +// { +// label: 'Scroll of Stamina', +// actionId: ActionId.fromItemId(37094), +// raidData: raidBuff('scrollOfStamina'), +// }, +// ], +// }, +// { +// label: 'Str + Agi', +// effects: [ +// { +// label: 'Improved Strength of Earth Totem', +// actionId: ActionId.fromSpellId(52456), +// playerData: playerClassAndTalent( +// Class.ClassShaman, +// 'enhancingTotems', +// player => player.getSpecOptions().classOptions?.totems?.earth == EarthTotem.StrengthOfEarthTotem, +// ), +// }, +// { +// label: 'Strength of Earth Totem', +// actionId: ActionId.fromSpellId(58643), +// playerData: playerClassAndMissingTalent( +// Class.ClassShaman, +// 'enhancingTotems', +// player => player.getSpecOptions().classOptions?.totems?.earth == EarthTotem.StrengthOfEarthTotem, +// ), +// }, +// { +// label: 'Horn of Winter', +// actionId: ActionId.fromSpellId(57623), +// playerData: playerClass(Class.ClassDeathKnight), +// }, +// { +// label: 'Scroll of Strength', +// actionId: ActionId.fromItemId(43466), +// raidData: raidBuff('scrollOfStrength'), +// }, +// { +// label: 'Scroll of Agility', +// actionId: ActionId.fromItemId(43464), +// raidData: raidBuff('scrollOfAgility'), +// }, +// ], +// }, +// { +// label: 'Intellect', +// effects: [ +// { +// label: 'Arcane Brilliance', +// actionId: ActionId.fromSpellId(43002), +// playerData: playerClass(Class.ClassMage), +// }, +// { +// label: 'Improved Fel Intelligence', +// actionId: ActionId.fromSpellId(54038), +// playerData: playerClassAndTalent( +// Class.ClassWarlock, +// 'improvedFelhunter', +// player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Felhunter, +// ), +// }, +// { +// label: 'Fel Intelligence', +// actionId: ActionId.fromSpellId(57567), +// playerData: playerClassAndMissingTalent( +// Class.ClassWarlock, +// 'improvedFelhunter', +// player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Felhunter, +// ), +// }, +// { +// label: 'Scroll of Intellect', +// actionId: ActionId.fromItemId(37092), +// raidData: raidBuff('scrollOfIntellect'), +// }, +// ], +// }, +// { +// label: 'Spirit', +// effects: [ +// { +// label: 'Divine Spirit', +// actionId: ActionId.fromSpellId(48073), +// playerData: playerClass(Class.ClassPriest), +// }, +// { +// label: 'Improved Fel Intelligence', +// actionId: ActionId.fromSpellId(54038), +// playerData: playerClassAndTalent( +// Class.ClassWarlock, +// 'improvedFelhunter', +// player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Felhunter, +// ), +// }, +// { +// label: 'Fel Intelligence', +// actionId: ActionId.fromSpellId(57567), +// playerData: playerClassAndMissingTalent( +// Class.ClassWarlock, +// 'improvedFelhunter', +// player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Felhunter, +// ), +// }, +// { +// label: 'Scroll of Spirit', +// actionId: ActionId.fromItemId(37098), +// raidData: raidBuff('scrollOfSpirit'), +// }, +// ], +// }, +// { +// label: 'Atk Pwr', +// effects: [ +// { +// label: 'Improved Blessing of Might', +// actionId: ActionId.fromSpellId(20045), +// playerData: playerClass(Class.ClassPaladin), +// }, +// { +// label: 'Blessing of Might', +// actionId: ActionId.fromSpellId(48934), +// playerData: playerClass(Class.ClassPaladin), +// }, +// { +// label: 'Improved Battle Shout', +// actionId: ActionId.fromSpellId(12861), +// playerData: playerClassAndTalent( +// Class.ClassWarrior, +// 'commandingPresence', +// player => player.getSpecOptions().classOptions?.shout == WarriorShout.WarriorShoutBattle, +// ), +// }, +// { +// label: 'Battle Shout', +// actionId: ActionId.fromSpellId(47436), +// playerData: playerClassAndMissingTalent( +// Class.ClassWarrior, +// 'commandingPresence', +// player => player.getSpecOptions().classOptions?.shout == WarriorShout.WarriorShoutBattle, +// ), +// }, +// ], +// }, +// { +// label: 'Atk Pwr %', +// effects: [ +// { +// label: "Abomination's Might", +// actionId: ActionId.fromSpellId(53138), +// playerData: playerClassAndTalent(Class.ClassDeathKnight, 'abominationsMight'), +// }, +// { +// label: 'Unleashed Rage', +// actionId: ActionId.fromSpellId(30809), +// playerData: playerClassAndTalent(Class.ClassShaman, 'unleashedRage'), +// }, +// { +// label: 'Trueshot Aura', +// actionId: ActionId.fromSpellId(19506), +// playerData: playerClassAndTalent(Class.ClassHunter, 'trueshotAura'), +// }, +// ], +// }, +// { +// label: 'Damage %', +// effects: [ +// { +// label: 'Sanctified Retribution', +// actionId: ActionId.fromSpellId(31869), +// playerData: playerClassAndTalent(Class.ClassPaladin, 'sanctifiedRetribution'), +// }, +// { +// label: 'Arcane Empowerment', +// actionId: ActionId.fromSpellId(31583), +// playerData: playerClassAndTalent(Class.ClassMage, 'arcaneEmpowerment'), +// }, +// { +// label: 'Ferocious Inspiration', +// actionId: ActionId.fromSpellId(34460), +// playerData: playerClassAndTalent(Class.ClassHunter, 'ferociousInspiration'), +// }, +// ], +// }, +// { +// label: 'Mit %', +// effects: [ +// { +// label: 'Renewed Hope', +// actionId: ActionId.fromSpellId(57472), +// playerData: playerClassAndTalent(Class.ClassPriest, 'renewedHope'), +// }, +// { +// label: 'Blessing Of Sanctuary', +// actionId: ActionId.fromSpellId(25899), +// playerData: playerClass(Class.ClassPaladin), +// }, +// { +// label: 'Vigilance', +// actionId: ActionId.fromSpellId(50720), +// playerData: playerClassAndTalent(Class.ClassWarrior, 'vigilance'), +// }, +// ], +// }, +// { +// label: 'Haste %', +// effects: [ +// { +// label: 'Swift Retribution', +// actionId: ActionId.fromSpellId(53648), +// playerData: playerClassAndTalent(Class.ClassPaladin, 'swiftRetribution'), +// }, +// { +// label: 'Improved Moonkin Form', +// actionId: ActionId.fromSpellId(48396), +// playerData: playerClassAndTalent(Class.ClassDruid, 'improvedMoonkinForm'), +// }, +// ], +// }, +// { +// label: 'MP5', +// effects: [ +// { +// label: 'Improved Blessing of Wisdom', +// actionId: ActionId.fromSpellId(20245), +// playerData: playerClassAndTalent(Class.ClassPaladin, 'improvedBlessingOfWisdom'), +// }, +// { +// label: 'Blessing of Wisdom', +// actionId: ActionId.fromSpellId(48938), +// playerData: playerClassAndMissingTalent(Class.ClassPaladin, 'improvedBlessingOfWisdom'), +// }, +// { +// label: 'Improved Mana Spring Totem', +// actionId: ActionId.fromSpellId(16206), +// playerData: playerClassAndTalent( +// Class.ClassShaman, +// 'restorativeTotems', +// player => player.getSpecOptions().classOptions?.totems?.water == WaterTotem.ManaSpringTotem, +// ), +// }, +// { +// label: 'Mana Spring Totem', +// actionId: ActionId.fromSpellId(58774), +// playerData: playerClassAndMissingTalent( +// Class.ClassShaman, +// 'restorativeTotems', +// player => player.getSpecOptions().classOptions?.totems?.water == WaterTotem.ManaSpringTotem, +// ), +// }, +// ], +// }, +// { +// label: 'Melee Crit', +// effects: [ +// { +// label: 'Leader of the Pack', +// actionId: ActionId.fromSpellId(17007), +// playerData: playerClassAndTalent(Class.ClassDruid, 'leaderOfThePack'), +// }, +// { +// label: 'Rampage', +// actionId: ActionId.fromSpellId(29801), +// playerData: playerClassAndTalent(Class.ClassWarrior, 'rampage'), +// }, +// ], +// }, +// { +// label: 'Melee Haste', +// effects: [ +// { +// label: 'Improved Icy Talons', +// actionId: ActionId.fromSpellId(55610), +// playerData: playerClassAndTalent(Class.ClassDeathKnight, 'improvedIcyTalons'), +// }, +// { +// label: 'Improved Windfury Totem', +// actionId: ActionId.fromSpellId(29193), +// playerData: playerClassAndTalent( +// Class.ClassShaman, +// 'improvedWindfuryTotem', +// player => player.getSpecOptions().classOptions?.totems?.air == AirTotem.WindfuryTotem, +// ), +// }, +// { +// label: 'Windfury Totem', +// actionId: ActionId.fromSpellId(65990), +// playerData: playerClassAndMissingTalent( +// Class.ClassShaman, +// 'improvedWindfuryTotem', +// player => player.getSpecOptions().classOptions?.totems?.air == AirTotem.WindfuryTotem, +// ), +// }, +// ], +// }, +// { +// label: 'Spell Power', +// effects: [ +// { +// label: 'Demonic Pact', +// actionId: ActionId.fromSpellId(47240), +// playerData: playerClassAndTalent(Class.ClassWarlock, 'demonicPact'), +// }, +// { +// label: 'Totem of Wrath', +// actionId: ActionId.fromSpellId(57722), +// playerData: playerClassAndTalent( +// Class.ClassShaman, +// 'totemOfWrath', +// player => player.getSpecOptions().classOptions?.totems?.fire == FireTotem.TotemOfWrath, +// ), +// }, +// { +// label: 'Flametongue Totem', +// actionId: ActionId.fromSpellId(58656), +// playerData: playerClass( +// Class.ClassShaman, +// player => player.getSpecOptions().classOptions?.totems?.fire == FireTotem.FlametongueTotem, +// ), +// }, +// ], +// }, +// { +// label: 'Spell Crit', +// effects: [ +// { +// label: 'Moonkin Form', +// actionId: ActionId.fromSpellId(24907), +// playerData: playerSpecAndTalent(Spec.SpecBalanceDruid, 'moonkinForm'), +// }, +// { +// label: 'Elemental Oath', +// actionId: ActionId.fromSpellId(51470), +// playerData: playerClassAndTalent(Class.ClassShaman, 'elementalOath'), +// }, +// ], +// }, +// { +// label: 'Spell Haste', +// effects: [ +// { +// label: 'Wrath of Air Totem', +// actionId: ActionId.fromSpellId(3738), +// playerData: playerClass(Class.ClassShaman, player => player.getSpecOptions().classOptions?.totems?.air == AirTotem.WrathOfAirTotem), +// }, +// ], +// }, +// { +// label: 'Health', +// effects: [ +// { +// label: 'Improved Commanding Shout', +// actionId: ActionId.fromSpellId(12861), +// playerData: playerClassAndTalent( +// Class.ClassWarrior, +// 'commandingPresence', +// player => player.getSpecOptions().classOptions?.shout == WarriorShout.WarriorShoutCommanding, +// ), +// }, +// { +// label: 'Commanding Shout', +// actionId: ActionId.fromSpellId(47440), +// playerData: playerClassAndMissingTalent( +// Class.ClassWarrior, +// 'commandingPresence', +// player => player.getSpecOptions().classOptions?.shout == WarriorShout.WarriorShoutCommanding, +// ), +// }, +// { +// label: 'Improved Imp', +// actionId: ActionId.fromSpellId(18696), +// playerData: playerClassAndTalent( +// Class.ClassWarlock, +// 'improvedImp', +// player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Imp, +// ), +// }, +// { +// label: 'Blood Pact', +// actionId: ActionId.fromSpellId(47982), +// playerData: playerClassAndMissingTalent( +// Class.ClassWarlock, +// 'improvedImp', +// player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Imp, +// ), +// }, +// ], +// }, +// { +// label: 'Replenishment', +// effects: [ +// { +// label: 'Vampiric Touch', +// actionId: ActionId.fromSpellId(48160), +// playerData: playerSpecAndTalent(Spec.SpecShadowPriest, 'vampiricTouch'), +// }, +// { +// label: 'Judgements of the Wise', +// actionId: ActionId.fromSpellId(31878), +// playerData: playerSpecAndTalent(Spec.SpecRetributionPaladin, 'judgementsOfTheWise'), +// }, +// { +// label: 'Hunting Party', +// actionId: ActionId.fromSpellId(53292), +// playerData: playerSpecAndTalent(Spec.SpecSurvivalHunter, 'huntingParty'), +// }, +// { +// label: 'Improved Soul Leech', +// actionId: ActionId.fromSpellId(54118), +// playerData: playerSpecAndTalent(Spec.SpecDestructionWarlock, 'improvedSoulLeech'), +// }, +// { +// label: 'Enduring Winter', +// actionId: ActionId.fromSpellId(44561), +// playerData: playerSpecAndTalent(Spec.SpecFrostMage, 'enduringWinter'), +// }, +// ], +// }, +// ], +// }, +// { +// label: 'External Buffs', +// categories: [ +// { +// label: 'Innervate', +// effects: [ +// { +// label: 'Innervate', +// actionId: ActionId.fromSpellId(29166), +// playerData: playerClass(Class.ClassDruid), +// }, +// ], +// }, +// { +// label: 'Power Infusion', +// effects: [ +// { +// label: 'Power Infusion', +// actionId: ActionId.fromSpellId(10060), +// playerData: playerClassAndTalent(Class.ClassPriest, 'powerInfusion'), +// }, +// ], +// }, +// { +// label: 'Focus Magic', +// effects: [ +// { +// label: 'Focus Magic', +// actionId: ActionId.fromSpellId(54648), +// playerData: playerClassAndTalent(Class.ClassMage, 'focusMagic'), +// }, +// ], +// }, +// { +// label: 'Tricks of the Trade', +// effects: [ +// { +// label: 'Tricks of the Trade', +// actionId: ActionId.fromSpellId(57933), +// playerData: playerClass(Class.ClassRogue), +// }, +// ], +// }, +// { +// label: 'Unholy Frenzy', +// effects: [ +// { +// label: 'Unholy Frenzy', +// actionId: ActionId.fromSpellId(49016), +// playerData: playerClassAndTalent(Class.ClassDeathKnight, 'hysteria'), +// }, +// ], +// }, +// { +// label: 'Pain Suppression', +// effects: [ +// { +// label: 'Pain Suppression', +// actionId: ActionId.fromSpellId(33206), +// playerData: playerClassAndTalent(Class.ClassPriest, 'painSuppression'), +// }, +// ], +// }, +// { +// label: 'Divine Guardian', +// effects: [ +// { +// label: 'Divine Guardian', +// actionId: ActionId.fromSpellId(53530), +// playerData: playerClassAndTalent(Class.ClassPaladin, 'divineGuardian'), +// }, +// ], +// }, +// ], +// }, +// { +// label: 'DPS Debuffs', +// categories: [ +// { +// label: 'Major ArP', +// effects: [ +// { +// label: 'Sunder Armor', +// actionId: ActionId.fromSpellId(47467), +// playerData: playerClass(Class.ClassWarrior), +// }, +// { +// label: 'Expose Armor', +// actionId: ActionId.fromSpellId(8647), +// playerData: playerClass(Class.ClassRogue), +// }, +// { +// label: 'Acid Spit', +// actionId: ActionId.fromSpellId(55754), +// playerData: playerClass(Class.ClassHunter, player => player.getSpecOptions().classOptions?.petType == HunterPetType.Worm), +// }, +// ], +// }, +// { +// label: 'Minor ArP', +// effects: [ +// { +// label: 'Faerie Fire', +// actionId: ActionId.fromSpellId(770), +// playerData: playerClass(Class.ClassDruid, player => player.getSpec() != Spec.SpecRestorationDruid), +// }, +// { +// label: 'Curse of Weakness', +// actionId: ActionId.fromSpellId(50511), +// playerData: playerClass(Class.ClassWarlock), +// }, +// { +// label: 'Sting', +// actionId: ActionId.fromSpellId(56631), +// playerData: playerClass(Class.ClassHunter, player => player.getSpecOptions().classOptions?.petType == HunterPetType.Wasp), +// }, +// { +// label: 'Spore Cloud', +// actionId: ActionId.fromSpellId(53598), +// playerData: playerClass(Class.ClassHunter, player => player.getSpecOptions().classOptions?.petType == HunterPetType.Bat), +// }, +// ], +// }, +// { +// label: 'Phys Vuln', +// effects: [ +// { +// label: 'Blood Frenzy', +// actionId: ActionId.fromSpellId(29859), +// playerData: playerClassAndTalent(Class.ClassWarrior, 'bloodFrenzy'), +// }, +// { +// label: 'Savage Combat', +// actionId: ActionId.fromSpellId(58413), +// playerData: playerClassAndTalent(Class.ClassRogue, 'savageCombat'), +// }, +// ], +// }, +// { +// label: 'Bleed', +// effects: [ +// { +// label: 'Mangle', +// actionId: ActionId.fromSpellId(16862), +// playerData: playerClass(Class.ClassDruid, player => [Spec.SpecFeralDruid].includes(player.getSpec())), +// }, +// { +// label: 'Trauma', +// actionId: ActionId.fromSpellId(46855), +// playerData: playerClassAndTalent(Class.ClassWarrior, 'trauma'), +// }, +// { +// label: 'Stampede', +// actionId: ActionId.fromSpellId(57393), +// playerData: playerClass(Class.ClassHunter, player => player.getSpecOptions().classOptions?.petType == HunterPetType.Rhino), +// }, +// ], +// }, +// { +// label: 'Crit', +// effects: [ +// { +// label: 'Totem of Wrath', +// actionId: ActionId.fromSpellId(30706), +// playerData: playerClassAndTalent( +// Class.ClassShaman, +// 'totemOfWrath', +// player => player.getSpecOptions().classOptions?.totems?.fire == FireTotem.TotemOfWrath, +// ), +// }, +// { +// label: 'Heart of the Crusader', +// actionId: ActionId.fromSpellId(20337), +// playerData: playerClassAndTalent(Class.ClassPaladin, 'heartOfTheCrusader', player => +// [Spec.SpecRetributionPaladin, Spec.SpecProtectionPaladin].includes(player.getSpec()), +// ), +// }, +// { +// label: 'Master Poisoner', +// actionId: ActionId.fromSpellId(58410), +// playerData: playerClassAndTalent(Class.ClassRogue, 'masterPoisoner'), +// }, +// ], +// }, +// { +// label: 'Spell Crit', +// effects: [ +// { +// label: 'Improved Shadow Bolt', +// actionId: ActionId.fromSpellId(17803), +// playerData: playerClassAndTalent(Class.ClassWarlock, 'improvedShadowBolt'), +// }, +// { +// label: 'Improved Scorch', +// actionId: ActionId.fromSpellId(12873), +// playerData: playerClassAndTalent(Class.ClassMage, 'improvedScorch'), +// }, +// { +// label: "Winter's Chill", +// actionId: ActionId.fromSpellId(28593), +// playerData: playerClassAndTalent(Class.ClassMage, 'wintersChill'), +// }, +// ], +// }, +// { +// label: 'Spell Hit', +// effects: [ +// { +// label: 'Misery', +// actionId: ActionId.fromSpellId(33198), +// playerData: playerSpecAndTalent(Spec.SpecShadowPriest, 'misery'), +// }, +// { +// label: 'Improved Faerie Fire', +// actionId: ActionId.fromSpellId(33602), +// playerData: playerSpecAndTalent(Spec.SpecBalanceDruid, 'improvedFaerieFire'), +// }, +// ], +// }, +// { +// label: 'Spell Dmg', +// effects: [ +// { +// label: 'Ebon Plaguebringer', +// actionId: ActionId.fromSpellId(51161), +// playerData: playerClassAndTalent(Class.ClassDeathKnight, 'ebonPlaguebringer'), +// }, +// { +// label: 'Earth and Moon', +// actionId: ActionId.fromSpellId(48511), +// playerData: playerSpecAndTalent(Spec.SpecBalanceDruid, 'earthAndMoon'), +// }, +// { +// label: 'Curse of Elements', +// actionId: ActionId.fromSpellId(47865), +// playerData: playerClass(Class.ClassWarlock), +// }, +// ], +// }, +// ], +// }, +// { +// label: 'Mitigation Debuffs', +// categories: [ +// { +// label: 'Atk Pwr', +// effects: [ +// { +// label: 'Vindication', +// actionId: ActionId.fromSpellId(26016), +// playerData: playerClassAndTalent(Class.ClassPaladin, 'vindication', player => +// [Spec.SpecRetributionPaladin, Spec.SpecProtectionPaladin].includes(player.getSpec()), +// ), +// }, +// { +// label: 'Improved Demoralizing Shout', +// actionId: ActionId.fromSpellId(12879), +// playerData: playerClassAndTalent(Class.ClassWarrior, 'improvedDemoralizingShout'), +// }, +// { +// label: 'Demoralizing Shout', +// actionId: ActionId.fromSpellId(47437), +// playerData: playerClassAndMissingTalent(Class.ClassWarrior, 'improvedDemoralizingShout'), +// }, +// { +// label: 'Improved Demoralizing Roar', +// actionId: ActionId.fromSpellId(16862), +// playerData: playerSpecAndTalent(Spec.SpecFeralDruid, 'feralAggression'), +// }, +// { +// label: 'Demoralizing Roar', +// actionId: ActionId.fromSpellId(48560), +// playerData: playerSpecAndMissingTalent(Spec.SpecFeralDruid, 'feralAggression'), +// }, +// { +// label: 'Improved Curse of Weakness', +// actionId: ActionId.fromSpellId(18180), +// playerData: playerClassAndTalent(Class.ClassWarlock, 'improvedCurseOfWeakness'), +// }, +// { +// label: 'Curse of Weakness', +// actionId: ActionId.fromSpellId(50511), +// playerData: playerClassAndMissingTalent(Class.ClassWarlock, 'improvedCurseOfWeakness'), +// }, +// { +// label: 'Demoralizing Screech', +// actionId: ActionId.fromSpellId(55487), +// playerData: playerClass(Class.ClassHunter, player => player.getSpecOptions().classOptions?.petType == HunterPetType.CarrionBird), +// }, +// ], +// }, +// { +// label: 'Atk Speed', +// effects: [ +// { +// label: 'Improved Thunder Clap', +// actionId: ActionId.fromSpellId(12666), +// playerData: playerClassAndTalent(Class.ClassWarrior, 'improvedThunderClap'), +// }, +// { +// label: 'Thunder Clap', +// actionId: ActionId.fromSpellId(47502), +// playerData: playerClassAndMissingTalent(Class.ClassWarrior, 'improvedThunderClap'), +// }, +// { +// label: 'Improved Frost Fever', +// actionId: ActionId.fromSpellId(51456), +// playerData: playerClassAndTalent(Class.ClassDeathKnight, 'improvedIcyTouch'), +// }, +// { +// label: 'Frost Fever', +// actionId: ActionId.fromSpellId(51456), +// playerData: playerClassAndMissingTalent(Class.ClassDeathKnight, 'improvedIcyTouch'), +// }, +// { +// label: 'Judgements of the Just', +// actionId: ActionId.fromSpellId(53696), +// playerData: playerClassAndTalent(Class.ClassPaladin, 'judgementsOfTheJust'), +// }, +// { +// label: 'Infected Wounds', +// actionId: ActionId.fromSpellId(48485), +// playerData: playerClassAndTalent(Class.ClassDruid, 'infectedWounds', player => +// [Spec.SpecFeralDruid, Spec.SpecFeralDruid].includes(player.getSpec()), +// ), +// }, +// ], +// }, +// { +// label: 'Miss', +// effects: [ +// { +// label: 'Insect Swarm', +// actionId: ActionId.fromSpellId(65855), +// playerData: playerSpecAndTalent(Spec.SpecBalanceDruid, 'insectSwarm'), +// }, +// { +// label: 'Scorpid Sting', +// actionId: ActionId.fromSpellId(3043), +// playerData: playerClass(Class.ClassHunter), +// }, +// ], +// }, +// ], +// }, +// ], +// }; diff --git a/ui/raid/assignments_picker.ts b/ui/raid/assignments_picker.ts index b8eaad893e..f2de2f8897 100644 --- a/ui/raid/assignments_picker.ts +++ b/ui/raid/assignments_picker.ts @@ -15,7 +15,7 @@ export class AssignmentsPicker extends Component { private readonly innervatesPicker: InnervatesPicker; private readonly powerInfusionsPicker: PowerInfusionsPicker; private readonly tricksOfTheTradesPicker: TricksOfTheTradesPicker; - private readonly unholyFrenzyPicker: UnholyFrenzyPicker; + //private readonly unholyFrenzyPicker: UnholyFrenzyPicker; private readonly focusMagicsPicker: FocusMagicsPicker; constructor(parentElem: HTMLElement, raidSimUI: RaidSimUI) { @@ -25,7 +25,7 @@ export class AssignmentsPicker extends Component { this.innervatesPicker = new InnervatesPicker(this.rootElem, raidSimUI); this.powerInfusionsPicker = new PowerInfusionsPicker(this.rootElem, raidSimUI); this.tricksOfTheTradesPicker = new TricksOfTheTradesPicker(this.rootElem, raidSimUI); - this.unholyFrenzyPicker = new UnholyFrenzyPicker(this.rootElem, raidSimUI); + //this.unholyFrenzyPicker = new UnholyFrenzyPicker(this.rootElem, raidSimUI); this.focusMagicsPicker = new FocusMagicsPicker(this.rootElem, raidSimUI); } } @@ -173,27 +173,27 @@ class TricksOfTheTradesPicker extends AssignedBuffPicker { } } -class UnholyFrenzyPicker extends AssignedBuffPicker { - getTitle(): string { - return 'Unholy Frenzy'; - } - - getSourcePlayers(): Array> { - return this.raidSimUI - .getActivePlayers() - .filter(player => player.isSpec(Spec.SpecUnholyDeathKnight) && (player.getTalents() as DeathKnightTalents).hysteria); - } - - getPlayerValue(player: Player): UnitReference { - return (player as Player).getSpecOptions().unholyFrenzyTarget || emptyUnitReference(); - } - - setPlayerValue(eventID: EventID, player: Player, newValue: UnitReference) { - const newOptions = (player as Player).getSpecOptions(); - newOptions.unholyFrenzyTarget = newValue; - player.setSpecOptions(eventID, newOptions); - } -} +// class UnholyFrenzyPicker extends AssignedBuffPicker { +// getTitle(): string { +// return 'Unholy Frenzy'; +// } + +// getSourcePlayers(): Array> { +// return this.raidSimUI +// .getActivePlayers() +// .filter(player => player.isSpec(Spec.SpecUnholyDeathKnight) && (player.getTalents() as DeathKnightTalents).hysteria); +// } + +// getPlayerValue(player: Player): UnitReference { +// return (player as Player).getSpecOptions().unholyFrenzyTarget || emptyUnitReference(); +// } + +// setPlayerValue(eventID: EventID, player: Player, newValue: UnitReference) { +// const newOptions = (player as Player).getSpecOptions(); +// newOptions.unholyFrenzyTarget = newValue; +// player.setSpecOptions(eventID, newOptions); +// } +// } class FocusMagicsPicker extends AssignedBuffPicker { getTitle(): string { diff --git a/ui/raid/raid_stats.ts b/ui/raid/raid_stats.ts deleted file mode 100644 index 37f3a15b5b..0000000000 --- a/ui/raid/raid_stats.ts +++ /dev/null @@ -1,1178 +0,0 @@ -import { Tooltip } from 'bootstrap'; - -import { Component } from '../core/components/component.js'; -import { Player } from '../core/player.js'; -import { PlayerClasses } from '../core/player_classes'; -import { PlayerSpecs } from '../core/player_specs'; -import { Class, RaidBuffs, Spec } from '../core/proto/common.js'; -import { HunterOptions_PetType as HunterPetType } from '../core/proto/hunter.js'; -import { PaladinAura } from '../core/proto/paladin.js'; -import { AirTotem, EarthTotem, FireTotem, WaterTotem } from '../core/proto/shaman.js'; -import { WarlockOptions_Summon as WarlockSummon } from '../core/proto/warlock.js'; -import { WarriorShout } from '../core/proto/warrior.js'; -import { ActionId } from '../core/proto_utils/action_id.js'; -import { ClassSpecs, SpecTalents, textCssClassForClass } from '../core/proto_utils/utils.js'; -import { Raid } from '../core/raid.js'; -import { sum } from '../core/utils.js'; -import { RaidSimUI } from './raid_sim_ui.js'; - -interface RaidStatsOptions { - sections: Array; -} - -interface RaidStatsSectionOptions { - label: string; - categories: Array; -} - -interface RaidStatsCategoryOptions { - label: string; - effects: Array; -} - -type PlayerProvider = { class?: Class; condition: (player: Player) => boolean }; -type RaidProvider = (raid: Raid) => boolean; - -interface RaidStatsEffectOptions { - label: string; - actionId?: ActionId; - playerData?: PlayerProvider; - raidData?: RaidProvider; -} - -export class RaidStats extends Component { - private readonly categories: Array; - - constructor(parent: HTMLElement, raidSimUI: RaidSimUI) { - super(parent, 'raid-stats'); - - const categories: Array = []; - RAID_STATS_OPTIONS.sections.forEach(section => { - const sectionElem = document.createElement('div'); - sectionElem.classList.add('raid-stats-section'); - this.rootElem.appendChild(sectionElem); - sectionElem.innerHTML = ` -
- -
-
- `; - const contentElem = sectionElem.getElementsByClassName('raid-stats-section-content')[0] as HTMLDivElement; - - section.categories.forEach(categoryOptions => { - categories.push(new RaidStatsCategory(contentElem, raidSimUI, categoryOptions)); - }); - }); - this.categories = categories; - - raidSimUI.changeEmitter.on(_eventID => this.categories.forEach(c => c.update())); - } -} - -class RaidStatsCategory extends Component { - readonly raidSimUI: RaidSimUI; - private readonly options: RaidStatsCategoryOptions; - private readonly effects: Array; - private readonly counterElem: HTMLElement; - private readonly tooltipElem: HTMLElement; - - constructor(parent: HTMLElement, raidSimUI: RaidSimUI, options: RaidStatsCategoryOptions) { - super(parent, 'raid-stats-category-root'); - this.raidSimUI = raidSimUI; - this.options = options; - - this.rootElem.innerHTML = ` - - - ${options.label} - - `; - - this.counterElem = this.rootElem.querySelector('.raid-stats-category-counter') as HTMLElement; - this.tooltipElem = document.createElement('div'); - this.tooltipElem.innerHTML = ` - - `; - - this.effects = options.effects.map(opt => new RaidStatsEffect(this.tooltipElem, raidSimUI, opt)); - - if (options.effects.length != 1 || options.effects[0].playerData?.class) { - const statsLink = this.rootElem.querySelector('.raid-stats-category') as HTMLElement; - - // Using the title option here because outerHTML sanitizes and filters out the img src options - Tooltip.getOrCreateInstance(statsLink, { - customClass: 'raid-stats-category-tooltip', - html: true, - placement: 'right', - title: this.tooltipElem, - }); - } - } - - update() { - this.effects.forEach(effect => effect.update()); - - const total = sum(this.effects.map(effect => effect.count)); - this.counterElem.textContent = String(total); - - const statsLink = this.rootElem.querySelector('.raid-stats-category') as HTMLElement; - - if (total == 0) { - statsLink?.classList.remove('active'); - } else { - statsLink?.classList.add('active'); - } - } -} - -class RaidStatsEffect extends Component { - readonly raidSimUI: RaidSimUI; - private readonly options: RaidStatsEffectOptions; - private readonly counterElem: HTMLElement; - - curPlayers: Array>; - count: number; - - constructor(parent: HTMLElement, raidSimUI: RaidSimUI, options: RaidStatsEffectOptions) { - super(parent, 'raid-stats-effect'); - this.raidSimUI = raidSimUI; - this.options = options; - - this.curPlayers = []; - this.count = 0; - - this.rootElem.innerHTML = ` - - - ${options.label} - `; - this.counterElem = this.rootElem.querySelector('.raid-stats-effect-counter') as HTMLElement; - - if (this.options.playerData?.class) { - const labelElem = this.rootElem.querySelector('.raid-stats-effect-label') as HTMLElement; - const playerCssClass = textCssClassForClass(PlayerClasses.fromProto(this.options.playerData.class)); - labelElem.classList.add(playerCssClass); - } - - const iconElem = this.rootElem.querySelector('.raid-stats-effect-icon') as HTMLImageElement; - if (options.actionId) { - options.actionId.fill().then(actionId => (iconElem.src = actionId.iconUrl)); - } else { - iconElem.remove(); - } - } - - update() { - if (this.options.playerData) { - this.curPlayers = this.raidSimUI.getActivePlayers().filter(p => this.options.playerData!.condition(p)); - } - - const raidData = this.options.raidData && this.options.raidData(this.raidSimUI.sim.raid); - - this.count = this.curPlayers.length + (raidData ? 1 : 0); - this.counterElem.textContent = String(this.count); - if (this.count == 0) { - this.rootElem.classList.remove('active'); - } else { - this.rootElem.classList.add('active'); - } - } -} - -function negateIf(val: boolean, cond: boolean): boolean { - return cond ? !val : val; -} - -function playerClass(clazz: T, extraCondition?: (player: Player>) => boolean): PlayerProvider { - return { - class: clazz, - condition: (player: Player): boolean => { - return player.isClass(clazz) && (!extraCondition || extraCondition(player)); - }, - }; -} -function playerClassAndTalentInternal( - clazz: T, - talentName: keyof SpecTalents>, - negateTalent: boolean, - extraCondition?: (player: Player>) => boolean, -): PlayerProvider { - return { - class: clazz, - condition: (player: Player): boolean => { - return ( - player.isClass(clazz) && - negateIf(Boolean((player.getTalents() as any)[talentName]), negateTalent) && - (!extraCondition || extraCondition(player)) - ); - }, - }; -} -function playerClassAndTalent( - clazz: T, - talentName: keyof SpecTalents>, - extraCondition?: (player: Player>) => boolean, -): PlayerProvider { - return playerClassAndTalentInternal(clazz, talentName, false, extraCondition); -} -function playerClassAndMissingTalent( - clazz: T, - talentName: keyof SpecTalents>, - extraCondition?: (player: Player>) => boolean, -): PlayerProvider { - return playerClassAndTalentInternal(clazz, talentName, true, extraCondition); -} -function playerSpecAndTalentInternal( - spec: T, - talentName: keyof SpecTalents, - negateTalent: boolean, - extraCondition?: (player: Player) => boolean, -): PlayerProvider { - return { - class: PlayerSpecs.fromProto(spec).classID, - condition: (player: Player): boolean => { - return ( - player.isSpec(spec) && negateIf(Boolean((player.getTalents() as any)[talentName]), negateTalent) && (!extraCondition || extraCondition(player)) - ); - }, - }; -} -function playerSpecAndTalent(spec: T, talentName: keyof SpecTalents, extraCondition?: (player: Player) => boolean): PlayerProvider { - return playerSpecAndTalentInternal(spec, talentName, false, extraCondition); -} -function playerSpecAndMissingTalent( - spec: T, - talentName: keyof SpecTalents, - extraCondition?: (player: Player) => boolean, -): PlayerProvider { - return playerSpecAndTalentInternal(spec, talentName, true, extraCondition); -} - -function raidBuff(buffName: keyof RaidBuffs): RaidProvider { - return (raid: Raid): boolean => { - return Boolean(raid.getBuffs()[buffName]); - }; -} - -const RAID_STATS_OPTIONS: RaidStatsOptions = { - sections: [ - { - label: 'Roles', - categories: [ - { - label: 'Tanks', - effects: [ - { - label: 'Tanks', - playerData: { condition: player => player.getSpec().isTankSpec }, - }, - ], - }, - { - label: 'Healers', - effects: [ - { - label: 'Healers', - playerData: { condition: player => player.getSpec().isHealingSpec }, - }, - ], - }, - { - label: 'Melee', - effects: [ - { - label: 'Melee', - playerData: { condition: player => player.getSpec().isMeleeDpsSpec }, - }, - ], - }, - { - label: 'Ranged', - effects: [ - { - label: 'Ranged', - playerData: { condition: player => player.getSpec().isRangedDpsSpec }, - }, - ], - }, - ], - }, - { - label: 'Buffs', - categories: [ - { - label: 'Bloodlust', - effects: [ - { - label: 'Bloodlust', - actionId: ActionId.fromSpellId(2825), - playerData: playerClass(Class.ClassShaman), - }, - ], - }, - { - label: 'Stats', - effects: [ - { - label: 'Improved Gift of the Wild', - actionId: ActionId.fromSpellId(17051), - playerData: playerClassAndTalent(Class.ClassDruid, 'improvedMarkOfTheWild'), - }, - { - label: 'Gift of the Wild', - actionId: ActionId.fromSpellId(48470), - playerData: playerClassAndMissingTalent(Class.ClassDruid, 'improvedMarkOfTheWild'), - }, - { - label: 'Drums of the Wild', - actionId: ActionId.fromItemId(49634), - raidData: raidBuff('drumsOfTheWild'), - }, - ], - }, - { - label: 'Stats %', - effects: [ - { - label: 'Blessing of Kings', - actionId: ActionId.fromSpellId(25898), - playerData: playerClass(Class.ClassPaladin), - }, - { - label: 'Drums of Forgotten Kings', - actionId: ActionId.fromItemId(49633), - raidData: raidBuff('drumsOfForgottenKings'), - }, - { - label: 'Blessing of Sanctuary', - actionId: ActionId.fromSpellId(25899), - playerData: playerClass(Class.ClassPaladin), - }, - ], - }, - { - label: 'Armor', - effects: [ - { - label: 'Improved Devotion Aura', - actionId: ActionId.fromSpellId(20140), - playerData: playerClassAndTalent( - Class.ClassPaladin, - 'improvedDevotionAura', - player => player.getSpecOptions().classOptions?.aura == PaladinAura.DevotionAura, - ), - }, - { - label: 'Devotion Aura', - actionId: ActionId.fromSpellId(48942), - playerData: playerClassAndMissingTalent( - Class.ClassPaladin, - 'improvedDevotionAura', - player => player.getSpecOptions().classOptions?.aura == PaladinAura.DevotionAura, - ), - }, - { - label: 'Improved Stoneskin Totem', - actionId: ActionId.fromSpellId(16293), - playerData: playerClassAndTalent( - Class.ClassShaman, - 'guardianTotems', - player => player.getSpecOptions().classOptions?.totems?.earth == EarthTotem.StoneskinTotem, - ), - }, - { - label: 'Stoneskin Totem', - actionId: ActionId.fromSpellId(58753), - playerData: playerClassAndMissingTalent( - Class.ClassShaman, - 'guardianTotems', - player => player.getSpecOptions().classOptions?.totems?.earth == EarthTotem.StoneskinTotem, - ), - }, - { - label: 'Scroll of Protection', - actionId: ActionId.fromItemId(43468), - raidData: raidBuff('scrollOfProtection'), - }, - ], - }, - { - label: 'Stamina', - effects: [ - { - label: 'Improved Power Word Fortitude', - actionId: ActionId.fromSpellId(14767), - playerData: playerClassAndTalent(Class.ClassPriest, 'improvedPowerWordFortitude'), - }, - { - label: 'Power Word Fortitude', - actionId: ActionId.fromSpellId(48161), - playerData: playerClassAndMissingTalent(Class.ClassPriest, 'improvedPowerWordFortitude'), - }, - { - label: 'Scroll of Stamina', - actionId: ActionId.fromItemId(37094), - raidData: raidBuff('scrollOfStamina'), - }, - ], - }, - { - label: 'Str + Agi', - effects: [ - { - label: 'Improved Strength of Earth Totem', - actionId: ActionId.fromSpellId(52456), - playerData: playerClassAndTalent( - Class.ClassShaman, - 'enhancingTotems', - player => player.getSpecOptions().classOptions?.totems?.earth == EarthTotem.StrengthOfEarthTotem, - ), - }, - { - label: 'Strength of Earth Totem', - actionId: ActionId.fromSpellId(58643), - playerData: playerClassAndMissingTalent( - Class.ClassShaman, - 'enhancingTotems', - player => player.getSpecOptions().classOptions?.totems?.earth == EarthTotem.StrengthOfEarthTotem, - ), - }, - { - label: 'Horn of Winter', - actionId: ActionId.fromSpellId(57623), - playerData: playerClass(Class.ClassDeathKnight), - }, - { - label: 'Scroll of Strength', - actionId: ActionId.fromItemId(43466), - raidData: raidBuff('scrollOfStrength'), - }, - { - label: 'Scroll of Agility', - actionId: ActionId.fromItemId(43464), - raidData: raidBuff('scrollOfAgility'), - }, - ], - }, - { - label: 'Intellect', - effects: [ - { - label: 'Arcane Brilliance', - actionId: ActionId.fromSpellId(43002), - playerData: playerClass(Class.ClassMage), - }, - { - label: 'Improved Fel Intelligence', - actionId: ActionId.fromSpellId(54038), - playerData: playerClassAndTalent( - Class.ClassWarlock, - 'improvedFelhunter', - player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Felhunter, - ), - }, - { - label: 'Fel Intelligence', - actionId: ActionId.fromSpellId(57567), - playerData: playerClassAndMissingTalent( - Class.ClassWarlock, - 'improvedFelhunter', - player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Felhunter, - ), - }, - { - label: 'Scroll of Intellect', - actionId: ActionId.fromItemId(37092), - raidData: raidBuff('scrollOfIntellect'), - }, - ], - }, - { - label: 'Spirit', - effects: [ - { - label: 'Divine Spirit', - actionId: ActionId.fromSpellId(48073), - playerData: playerClass(Class.ClassPriest), - }, - { - label: 'Improved Fel Intelligence', - actionId: ActionId.fromSpellId(54038), - playerData: playerClassAndTalent( - Class.ClassWarlock, - 'improvedFelhunter', - player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Felhunter, - ), - }, - { - label: 'Fel Intelligence', - actionId: ActionId.fromSpellId(57567), - playerData: playerClassAndMissingTalent( - Class.ClassWarlock, - 'improvedFelhunter', - player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Felhunter, - ), - }, - { - label: 'Scroll of Spirit', - actionId: ActionId.fromItemId(37098), - raidData: raidBuff('scrollOfSpirit'), - }, - ], - }, - { - label: 'Atk Pwr', - effects: [ - { - label: 'Improved Blessing of Might', - actionId: ActionId.fromSpellId(20045), - playerData: playerClass(Class.ClassPaladin), - }, - { - label: 'Blessing of Might', - actionId: ActionId.fromSpellId(48934), - playerData: playerClass(Class.ClassPaladin), - }, - { - label: 'Improved Battle Shout', - actionId: ActionId.fromSpellId(12861), - playerData: playerClassAndTalent( - Class.ClassWarrior, - 'commandingPresence', - player => player.getSpecOptions().classOptions?.shout == WarriorShout.WarriorShoutBattle, - ), - }, - { - label: 'Battle Shout', - actionId: ActionId.fromSpellId(47436), - playerData: playerClassAndMissingTalent( - Class.ClassWarrior, - 'commandingPresence', - player => player.getSpecOptions().classOptions?.shout == WarriorShout.WarriorShoutBattle, - ), - }, - ], - }, - { - label: 'Atk Pwr %', - effects: [ - { - label: "Abomination's Might", - actionId: ActionId.fromSpellId(53138), - playerData: playerClassAndTalent(Class.ClassDeathKnight, 'abominationsMight'), - }, - { - label: 'Unleashed Rage', - actionId: ActionId.fromSpellId(30809), - playerData: playerClassAndTalent(Class.ClassShaman, 'unleashedRage'), - }, - { - label: 'Trueshot Aura', - actionId: ActionId.fromSpellId(19506), - playerData: playerClassAndTalent(Class.ClassHunter, 'trueshotAura'), - }, - ], - }, - { - label: 'Damage %', - effects: [ - { - label: 'Sanctified Retribution', - actionId: ActionId.fromSpellId(31869), - playerData: playerClassAndTalent(Class.ClassPaladin, 'sanctifiedRetribution'), - }, - { - label: 'Arcane Empowerment', - actionId: ActionId.fromSpellId(31583), - playerData: playerClassAndTalent(Class.ClassMage, 'arcaneEmpowerment'), - }, - { - label: 'Ferocious Inspiration', - actionId: ActionId.fromSpellId(34460), - playerData: playerClassAndTalent(Class.ClassHunter, 'ferociousInspiration'), - }, - ], - }, - { - label: 'Mit %', - effects: [ - { - label: 'Renewed Hope', - actionId: ActionId.fromSpellId(57472), - playerData: playerClassAndTalent(Class.ClassPriest, 'renewedHope'), - }, - { - label: 'Blessing Of Sanctuary', - actionId: ActionId.fromSpellId(25899), - playerData: playerClass(Class.ClassPaladin), - }, - { - label: 'Vigilance', - actionId: ActionId.fromSpellId(50720), - playerData: playerClassAndTalent(Class.ClassWarrior, 'vigilance'), - }, - ], - }, - { - label: 'Haste %', - effects: [ - { - label: 'Swift Retribution', - actionId: ActionId.fromSpellId(53648), - playerData: playerClassAndTalent(Class.ClassPaladin, 'swiftRetribution'), - }, - { - label: 'Improved Moonkin Form', - actionId: ActionId.fromSpellId(48396), - playerData: playerClassAndTalent(Class.ClassDruid, 'improvedMoonkinForm'), - }, - ], - }, - { - label: 'MP5', - effects: [ - { - label: 'Improved Blessing of Wisdom', - actionId: ActionId.fromSpellId(20245), - playerData: playerClassAndTalent(Class.ClassPaladin, 'improvedBlessingOfWisdom'), - }, - { - label: 'Blessing of Wisdom', - actionId: ActionId.fromSpellId(48938), - playerData: playerClassAndMissingTalent(Class.ClassPaladin, 'improvedBlessingOfWisdom'), - }, - { - label: 'Improved Mana Spring Totem', - actionId: ActionId.fromSpellId(16206), - playerData: playerClassAndTalent( - Class.ClassShaman, - 'restorativeTotems', - player => player.getSpecOptions().classOptions?.totems?.water == WaterTotem.ManaSpringTotem, - ), - }, - { - label: 'Mana Spring Totem', - actionId: ActionId.fromSpellId(58774), - playerData: playerClassAndMissingTalent( - Class.ClassShaman, - 'restorativeTotems', - player => player.getSpecOptions().classOptions?.totems?.water == WaterTotem.ManaSpringTotem, - ), - }, - ], - }, - { - label: 'Melee Crit', - effects: [ - { - label: 'Leader of the Pack', - actionId: ActionId.fromSpellId(17007), - playerData: playerClassAndTalent(Class.ClassDruid, 'leaderOfThePack'), - }, - { - label: 'Rampage', - actionId: ActionId.fromSpellId(29801), - playerData: playerClassAndTalent(Class.ClassWarrior, 'rampage'), - }, - ], - }, - { - label: 'Melee Haste', - effects: [ - { - label: 'Improved Icy Talons', - actionId: ActionId.fromSpellId(55610), - playerData: playerClassAndTalent(Class.ClassDeathKnight, 'improvedIcyTalons'), - }, - { - label: 'Improved Windfury Totem', - actionId: ActionId.fromSpellId(29193), - playerData: playerClassAndTalent( - Class.ClassShaman, - 'improvedWindfuryTotem', - player => player.getSpecOptions().classOptions?.totems?.air == AirTotem.WindfuryTotem, - ), - }, - { - label: 'Windfury Totem', - actionId: ActionId.fromSpellId(65990), - playerData: playerClassAndMissingTalent( - Class.ClassShaman, - 'improvedWindfuryTotem', - player => player.getSpecOptions().classOptions?.totems?.air == AirTotem.WindfuryTotem, - ), - }, - ], - }, - { - label: 'Spell Power', - effects: [ - { - label: 'Demonic Pact', - actionId: ActionId.fromSpellId(47240), - playerData: playerClassAndTalent(Class.ClassWarlock, 'demonicPact'), - }, - { - label: 'Totem of Wrath', - actionId: ActionId.fromSpellId(57722), - playerData: playerClassAndTalent( - Class.ClassShaman, - 'totemOfWrath', - player => player.getSpecOptions().classOptions?.totems?.fire == FireTotem.TotemOfWrath, - ), - }, - { - label: 'Flametongue Totem', - actionId: ActionId.fromSpellId(58656), - playerData: playerClass( - Class.ClassShaman, - player => player.getSpecOptions().classOptions?.totems?.fire == FireTotem.FlametongueTotem, - ), - }, - ], - }, - { - label: 'Spell Crit', - effects: [ - { - label: 'Moonkin Form', - actionId: ActionId.fromSpellId(24907), - playerData: playerSpecAndTalent(Spec.SpecBalanceDruid, 'moonkinForm'), - }, - { - label: 'Elemental Oath', - actionId: ActionId.fromSpellId(51470), - playerData: playerClassAndTalent(Class.ClassShaman, 'elementalOath'), - }, - ], - }, - { - label: 'Spell Haste', - effects: [ - { - label: 'Wrath of Air Totem', - actionId: ActionId.fromSpellId(3738), - playerData: playerClass(Class.ClassShaman, player => player.getSpecOptions().classOptions?.totems?.air == AirTotem.WrathOfAirTotem), - }, - ], - }, - { - label: 'Health', - effects: [ - { - label: 'Improved Commanding Shout', - actionId: ActionId.fromSpellId(12861), - playerData: playerClassAndTalent( - Class.ClassWarrior, - 'commandingPresence', - player => player.getSpecOptions().classOptions?.shout == WarriorShout.WarriorShoutCommanding, - ), - }, - { - label: 'Commanding Shout', - actionId: ActionId.fromSpellId(47440), - playerData: playerClassAndMissingTalent( - Class.ClassWarrior, - 'commandingPresence', - player => player.getSpecOptions().classOptions?.shout == WarriorShout.WarriorShoutCommanding, - ), - }, - { - label: 'Improved Imp', - actionId: ActionId.fromSpellId(18696), - playerData: playerClassAndTalent( - Class.ClassWarlock, - 'improvedImp', - player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Imp, - ), - }, - { - label: 'Blood Pact', - actionId: ActionId.fromSpellId(47982), - playerData: playerClassAndMissingTalent( - Class.ClassWarlock, - 'improvedImp', - player => player.getSpecOptions().classOptions?.summon == WarlockSummon.Imp, - ), - }, - ], - }, - { - label: 'Replenishment', - effects: [ - { - label: 'Vampiric Touch', - actionId: ActionId.fromSpellId(48160), - playerData: playerSpecAndTalent(Spec.SpecShadowPriest, 'vampiricTouch'), - }, - { - label: 'Judgements of the Wise', - actionId: ActionId.fromSpellId(31878), - playerData: playerSpecAndTalent(Spec.SpecRetributionPaladin, 'judgementsOfTheWise'), - }, - { - label: 'Hunting Party', - actionId: ActionId.fromSpellId(53292), - playerData: playerSpecAndTalent(Spec.SpecSurvivalHunter, 'huntingParty'), - }, - { - label: 'Improved Soul Leech', - actionId: ActionId.fromSpellId(54118), - playerData: playerSpecAndTalent(Spec.SpecDestructionWarlock, 'improvedSoulLeech'), - }, - { - label: 'Enduring Winter', - actionId: ActionId.fromSpellId(44561), - playerData: playerSpecAndTalent(Spec.SpecFrostMage, 'enduringWinter'), - }, - ], - }, - ], - }, - { - label: 'External Buffs', - categories: [ - { - label: 'Innervate', - effects: [ - { - label: 'Innervate', - actionId: ActionId.fromSpellId(29166), - playerData: playerClass(Class.ClassDruid), - }, - ], - }, - { - label: 'Power Infusion', - effects: [ - { - label: 'Power Infusion', - actionId: ActionId.fromSpellId(10060), - playerData: playerClassAndTalent(Class.ClassPriest, 'powerInfusion'), - }, - ], - }, - { - label: 'Focus Magic', - effects: [ - { - label: 'Focus Magic', - actionId: ActionId.fromSpellId(54648), - playerData: playerClassAndTalent(Class.ClassMage, 'focusMagic'), - }, - ], - }, - { - label: 'Tricks of the Trade', - effects: [ - { - label: 'Tricks of the Trade', - actionId: ActionId.fromSpellId(57933), - playerData: playerClass(Class.ClassRogue), - }, - ], - }, - { - label: 'Unholy Frenzy', - effects: [ - { - label: 'Unholy Frenzy', - actionId: ActionId.fromSpellId(49016), - playerData: playerClassAndTalent(Class.ClassDeathKnight, 'hysteria'), - }, - ], - }, - { - label: 'Pain Suppression', - effects: [ - { - label: 'Pain Suppression', - actionId: ActionId.fromSpellId(33206), - playerData: playerClassAndTalent(Class.ClassPriest, 'painSuppression'), - }, - ], - }, - { - label: 'Divine Guardian', - effects: [ - { - label: 'Divine Guardian', - actionId: ActionId.fromSpellId(53530), - playerData: playerClassAndTalent(Class.ClassPaladin, 'divineGuardian'), - }, - ], - }, - ], - }, - { - label: 'DPS Debuffs', - categories: [ - { - label: 'Major ArP', - effects: [ - { - label: 'Sunder Armor', - actionId: ActionId.fromSpellId(47467), - playerData: playerClass(Class.ClassWarrior), - }, - { - label: 'Expose Armor', - actionId: ActionId.fromSpellId(8647), - playerData: playerClass(Class.ClassRogue), - }, - { - label: 'Acid Spit', - actionId: ActionId.fromSpellId(55754), - playerData: playerClass(Class.ClassHunter, player => player.getSpecOptions().classOptions?.petType == HunterPetType.Worm), - }, - ], - }, - { - label: 'Minor ArP', - effects: [ - { - label: 'Faerie Fire', - actionId: ActionId.fromSpellId(770), - playerData: playerClass(Class.ClassDruid, player => player.getSpec() != Spec.SpecRestorationDruid), - }, - { - label: 'Curse of Weakness', - actionId: ActionId.fromSpellId(50511), - playerData: playerClass(Class.ClassWarlock), - }, - { - label: 'Sting', - actionId: ActionId.fromSpellId(56631), - playerData: playerClass(Class.ClassHunter, player => player.getSpecOptions().classOptions?.petType == HunterPetType.Wasp), - }, - { - label: 'Spore Cloud', - actionId: ActionId.fromSpellId(53598), - playerData: playerClass(Class.ClassHunter, player => player.getSpecOptions().classOptions?.petType == HunterPetType.Bat), - }, - ], - }, - { - label: 'Phys Vuln', - effects: [ - { - label: 'Blood Frenzy', - actionId: ActionId.fromSpellId(29859), - playerData: playerClassAndTalent(Class.ClassWarrior, 'bloodFrenzy'), - }, - { - label: 'Savage Combat', - actionId: ActionId.fromSpellId(58413), - playerData: playerClassAndTalent(Class.ClassRogue, 'savageCombat'), - }, - ], - }, - { - label: 'Bleed', - effects: [ - { - label: 'Mangle', - actionId: ActionId.fromSpellId(16862), - playerData: playerClass(Class.ClassDruid, player => [Spec.SpecFeralDruid].includes(player.getSpec())), - }, - { - label: 'Trauma', - actionId: ActionId.fromSpellId(46855), - playerData: playerClassAndTalent(Class.ClassWarrior, 'trauma'), - }, - { - label: 'Stampede', - actionId: ActionId.fromSpellId(57393), - playerData: playerClass(Class.ClassHunter, player => player.getSpecOptions().classOptions?.petType == HunterPetType.Rhino), - }, - ], - }, - { - label: 'Crit', - effects: [ - { - label: 'Totem of Wrath', - actionId: ActionId.fromSpellId(30706), - playerData: playerClassAndTalent( - Class.ClassShaman, - 'totemOfWrath', - player => player.getSpecOptions().classOptions?.totems?.fire == FireTotem.TotemOfWrath, - ), - }, - { - label: 'Heart of the Crusader', - actionId: ActionId.fromSpellId(20337), - playerData: playerClassAndTalent(Class.ClassPaladin, 'heartOfTheCrusader', player => - [Spec.SpecRetributionPaladin, Spec.SpecProtectionPaladin].includes(player.getSpec()), - ), - }, - { - label: 'Master Poisoner', - actionId: ActionId.fromSpellId(58410), - playerData: playerClassAndTalent(Class.ClassRogue, 'masterPoisoner'), - }, - ], - }, - { - label: 'Spell Crit', - effects: [ - { - label: 'Improved Shadow Bolt', - actionId: ActionId.fromSpellId(17803), - playerData: playerClassAndTalent(Class.ClassWarlock, 'improvedShadowBolt'), - }, - { - label: 'Improved Scorch', - actionId: ActionId.fromSpellId(12873), - playerData: playerClassAndTalent(Class.ClassMage, 'improvedScorch'), - }, - { - label: "Winter's Chill", - actionId: ActionId.fromSpellId(28593), - playerData: playerClassAndTalent(Class.ClassMage, 'wintersChill'), - }, - ], - }, - { - label: 'Spell Hit', - effects: [ - { - label: 'Misery', - actionId: ActionId.fromSpellId(33198), - playerData: playerSpecAndTalent(Spec.SpecShadowPriest, 'misery'), - }, - { - label: 'Improved Faerie Fire', - actionId: ActionId.fromSpellId(33602), - playerData: playerSpecAndTalent(Spec.SpecBalanceDruid, 'improvedFaerieFire'), - }, - ], - }, - { - label: 'Spell Dmg', - effects: [ - { - label: 'Ebon Plaguebringer', - actionId: ActionId.fromSpellId(51161), - playerData: playerClassAndTalent(Class.ClassDeathKnight, 'ebonPlaguebringer'), - }, - { - label: 'Earth and Moon', - actionId: ActionId.fromSpellId(48511), - playerData: playerSpecAndTalent(Spec.SpecBalanceDruid, 'earthAndMoon'), - }, - { - label: 'Curse of Elements', - actionId: ActionId.fromSpellId(47865), - playerData: playerClass(Class.ClassWarlock), - }, - ], - }, - ], - }, - { - label: 'Mitigation Debuffs', - categories: [ - { - label: 'Atk Pwr', - effects: [ - { - label: 'Vindication', - actionId: ActionId.fromSpellId(26016), - playerData: playerClassAndTalent(Class.ClassPaladin, 'vindication', player => - [Spec.SpecRetributionPaladin, Spec.SpecProtectionPaladin].includes(player.getSpec()), - ), - }, - { - label: 'Improved Demoralizing Shout', - actionId: ActionId.fromSpellId(12879), - playerData: playerClassAndTalent(Class.ClassWarrior, 'improvedDemoralizingShout'), - }, - { - label: 'Demoralizing Shout', - actionId: ActionId.fromSpellId(47437), - playerData: playerClassAndMissingTalent(Class.ClassWarrior, 'improvedDemoralizingShout'), - }, - { - label: 'Improved Demoralizing Roar', - actionId: ActionId.fromSpellId(16862), - playerData: playerSpecAndTalent(Spec.SpecFeralDruid, 'feralAggression'), - }, - { - label: 'Demoralizing Roar', - actionId: ActionId.fromSpellId(48560), - playerData: playerSpecAndMissingTalent(Spec.SpecFeralDruid, 'feralAggression'), - }, - { - label: 'Improved Curse of Weakness', - actionId: ActionId.fromSpellId(18180), - playerData: playerClassAndTalent(Class.ClassWarlock, 'improvedCurseOfWeakness'), - }, - { - label: 'Curse of Weakness', - actionId: ActionId.fromSpellId(50511), - playerData: playerClassAndMissingTalent(Class.ClassWarlock, 'improvedCurseOfWeakness'), - }, - { - label: 'Demoralizing Screech', - actionId: ActionId.fromSpellId(55487), - playerData: playerClass(Class.ClassHunter, player => player.getSpecOptions().classOptions?.petType == HunterPetType.CarrionBird), - }, - ], - }, - { - label: 'Atk Speed', - effects: [ - { - label: 'Improved Thunder Clap', - actionId: ActionId.fromSpellId(12666), - playerData: playerClassAndTalent(Class.ClassWarrior, 'improvedThunderClap'), - }, - { - label: 'Thunder Clap', - actionId: ActionId.fromSpellId(47502), - playerData: playerClassAndMissingTalent(Class.ClassWarrior, 'improvedThunderClap'), - }, - { - label: 'Improved Frost Fever', - actionId: ActionId.fromSpellId(51456), - playerData: playerClassAndTalent(Class.ClassDeathKnight, 'improvedIcyTouch'), - }, - { - label: 'Frost Fever', - actionId: ActionId.fromSpellId(51456), - playerData: playerClassAndMissingTalent(Class.ClassDeathKnight, 'improvedIcyTouch'), - }, - { - label: 'Judgements of the Just', - actionId: ActionId.fromSpellId(53696), - playerData: playerClassAndTalent(Class.ClassPaladin, 'judgementsOfTheJust'), - }, - { - label: 'Infected Wounds', - actionId: ActionId.fromSpellId(48485), - playerData: playerClassAndTalent(Class.ClassDruid, 'infectedWounds', player => - [Spec.SpecFeralDruid, Spec.SpecFeralDruid].includes(player.getSpec()), - ), - }, - ], - }, - { - label: 'Miss', - effects: [ - { - label: 'Insect Swarm', - actionId: ActionId.fromSpellId(65855), - playerData: playerSpecAndTalent(Spec.SpecBalanceDruid, 'insectSwarm'), - }, - { - label: 'Scorpid Sting', - actionId: ActionId.fromSpellId(3043), - playerData: playerClass(Class.ClassHunter), - }, - ], - }, - ], - }, - ], -}; diff --git a/ui/raid/raid_tab.ts b/ui/raid/raid_tab.ts index 30c4179c37..ff3e3ad35e 100644 --- a/ui/raid/raid_tab.ts +++ b/ui/raid/raid_tab.ts @@ -1,11 +1,11 @@ -import { RaidPicker } from "./raid_picker"; -import { RaidSimUI } from "./raid_sim_ui"; -import { RaidStats } from "./raid_stats"; import { SavedDataManager } from "../core/components/saved_data_manager"; import { SimTab } from "../core/components/sim_tab"; +import { Raid as RaidProto } from "../core/proto/api"; import { BlessingsAssignments, SavedRaid } from "../core/proto/ui"; import { EventID, TypedEvent } from "../core/typed_event"; -import { Raid as RaidProto } from "../core/proto/api"; +//import { RaidStats } from "./_raid_stats"; +import { RaidPicker } from "./raid_picker"; +import { RaidSimUI } from "./raid_sim_ui"; export class RaidTab extends SimTab { protected simUI: RaidSimUI; @@ -33,7 +33,7 @@ export class RaidTab extends SimTab { protected buildTabContent() { this.simUI.raidPicker = new RaidPicker(this.leftPanel, this.simUI); - new RaidStats(this.leftPanel, this.simUI); + //new RaidStats(this.leftPanel, this.simUI); const savedRaidManager = new SavedDataManager(this.rightPanel, this.simUI, { label: 'Raid', diff --git a/ui/rogue/assassination/presets.ts b/ui/rogue/assassination/presets.ts index b85be85430..1f4da282b0 100644 --- a/ui/rogue/assassination/presets.ts +++ b/ui/rogue/assassination/presets.ts @@ -37,36 +37,36 @@ export const ROTATION_PRESET_AOE = PresetUtils.makePresetAPLRotation('Fan AOE', export const AssassinationTalents137 = { name: 'Assassination 13/7', data: SavedTalents.create({ - talentsString: '005303104352100520103331051-005005003-502', - glyphs: Glyphs.create({ - major1: RogueMajorGlyph.GlyphOfMutilate, - major2: RogueMajorGlyph.GlyphOfTricksOfTheTrade, - major3: RogueMajorGlyph.GlyphOfHungerForBlood, - }), + // talentsString: '005303104352100520103331051-005005003-502', + // glyphs: Glyphs.create({ + // major1: RogueMajorGlyph.GlyphOfMutilate, + // major2: RogueMajorGlyph.GlyphOfTricksOfTheTrade, + // major3: RogueMajorGlyph.GlyphOfHungerForBlood, + // }), }), }; export const AssassinationTalents182 = { name: 'Assassination 18/2', data: SavedTalents.create({ - talentsString: '005303104352100520103331051-005005005003-2', - glyphs: Glyphs.create({ - major1: RogueMajorGlyph.GlyphOfMutilate, - major2: RogueMajorGlyph.GlyphOfTricksOfTheTrade, - major3: RogueMajorGlyph.GlyphOfHungerForBlood, - }), + // talentsString: '005303104352100520103331051-005005005003-2', + // glyphs: Glyphs.create({ + // major1: RogueMajorGlyph.GlyphOfMutilate, + // major2: RogueMajorGlyph.GlyphOfTricksOfTheTrade, + // major3: RogueMajorGlyph.GlyphOfHungerForBlood, + // }), }), }; export const AssassinationTalentsBF = { name: 'Assassination Blade Flurry', data: SavedTalents.create({ - talentsString: '005303104352100520103231-005205005003001-501', - glyphs: Glyphs.create({ - major1: RogueMajorGlyph.GlyphOfMutilate, - major2: RogueMajorGlyph.GlyphOfTricksOfTheTrade, - major3: RogueMajorGlyph.GlyphOfBladeFlurry, - }), + // talentsString: '005303104352100520103231-005205005003001-501', + // glyphs: Glyphs.create({ + // major1: RogueMajorGlyph.GlyphOfMutilate, + // major2: RogueMajorGlyph.GlyphOfTricksOfTheTrade, + // major3: RogueMajorGlyph.GlyphOfBladeFlurry, + // }), }), }; diff --git a/ui/rogue/assassination/sim.ts b/ui/rogue/assassination/sim.ts index 1b5a407cf1..1c1006cb1e 100644 --- a/ui/rogue/assassination/sim.ts +++ b/ui/rogue/assassination/sim.ts @@ -29,129 +29,129 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecAssassinationRogue, { cssScheme: PlayerClasses.getCssClass(PlayerClasses.Rogue), // List any known bugs / issues here and they'll be shown on the site. knownIssues: ['Rotations are not fully optimized, especially for non-standard setups.'], - warnings: [ - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.sim.encounter.changeEmitter, - getContent: () => { - let hasNoArmor = false; - for (const target of simUI.sim.encounter.targets) { - if (new Stats(target.stats).getStat(Stat.StatArmor) <= 0) { - hasNoArmor = true; - break; - } - } - if (hasNoArmor) { - return 'One or more targets have no armor. Check advanced encounter settings.'; - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if ( - simUI.player.getTalents().mutilate && - (simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType != WeaponType.WeaponTypeDagger || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType != WeaponType.WeaponTypeDagger) - ) { - return '"Mutilate" talent selected, but daggers not equipped in both hands.'; - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if (simUI.player.getTalents().hackAndSlash) { - if ( - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeSword || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeAxe || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeSword || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeAxe - ) { - return ''; - } else { - return '"Hack and Slash" talent selected, but swords or axes not equipped.'; - } - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if (simUI.player.getTalents().closeQuartersCombat) { - if ( - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeFist || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeDagger || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeFist || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeDagger - ) { - return ''; - } else { - return '"Close Quarters Combat" talent selected, but fists or daggers not equipped.'; - } - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if (simUI.player.getTalents().maceSpecialization) { - if ( - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeMace || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeMace - ) { - return ''; - } else { - return '"Mace Specialization" talent selected, but maces not equipped.'; - } - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - const mhWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponSpeed; - const ohWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponSpeed; - const mhImbue = simUI.player.getSpecOptions().classOptions!.mhImbue; - const ohImbue = simUI.player.getSpecOptions().classOptions!.ohImbue; - if ( - typeof mhWeaponSpeed == 'undefined' || - typeof ohWeaponSpeed == 'undefined' || - !simUI.player.getSpecOptions().classOptions!.applyPoisonsManually - ) { - return ''; - } - if (mhWeaponSpeed < ohWeaponSpeed && ohImbue == RogueOptions_PoisonImbue.DeadlyPoison) { - return 'Deadly poison applied to slower (off hand) weapon.'; - } - if (ohWeaponSpeed < mhWeaponSpeed && mhImbue == RogueOptions_PoisonImbue.DeadlyPoison) { - return 'Deadly poison applied to slower (main hand) weapon.'; - } - return ''; - }, - }; - }, - ], + // warnings: [ + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.sim.encounter.changeEmitter, + // getContent: () => { + // let hasNoArmor = false; + // for (const target of simUI.sim.encounter.targets) { + // if (new Stats(target.stats).getStat(Stat.StatArmor) <= 0) { + // hasNoArmor = true; + // break; + // } + // } + // if (hasNoArmor) { + // return 'One or more targets have no armor. Check advanced encounter settings.'; + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if ( + // simUI.player.getTalents().mutilate && + // (simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType != WeaponType.WeaponTypeDagger || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType != WeaponType.WeaponTypeDagger) + // ) { + // return '"Mutilate" talent selected, but daggers not equipped in both hands.'; + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if (simUI.player.getTalents().hackAndSlash) { + // if ( + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeSword || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeAxe || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeSword || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeAxe + // ) { + // return ''; + // } else { + // return '"Hack and Slash" talent selected, but swords or axes not equipped.'; + // } + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if (simUI.player.getTalents().closeQuartersCombat) { + // if ( + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeFist || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeDagger || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeFist || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeDagger + // ) { + // return ''; + // } else { + // return '"Close Quarters Combat" talent selected, but fists or daggers not equipped.'; + // } + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if (simUI.player.getTalents().maceSpecialization) { + // if ( + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeMace || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeMace + // ) { + // return ''; + // } else { + // return '"Mace Specialization" talent selected, but maces not equipped.'; + // } + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // const mhWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponSpeed; + // const ohWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponSpeed; + // const mhImbue = simUI.player.getSpecOptions().classOptions!.mhImbue; + // const ohImbue = simUI.player.getSpecOptions().classOptions!.ohImbue; + // if ( + // typeof mhWeaponSpeed == 'undefined' || + // typeof ohWeaponSpeed == 'undefined' || + // !simUI.player.getSpecOptions().classOptions!.applyPoisonsManually + // ) { + // return ''; + // } + // if (mhWeaponSpeed < ohWeaponSpeed && ohImbue == RogueOptions_PoisonImbue.DeadlyPoison) { + // return 'Deadly poison applied to slower (off hand) weapon.'; + // } + // if (ohWeaponSpeed < mhWeaponSpeed && mhImbue == RogueOptions_PoisonImbue.DeadlyPoison) { + // return 'Deadly poison applied to slower (main hand) weapon.'; + // } + // return ''; + // }, + // }; + // }, + // ], // All stats for which EP should be calculated. epStats: [ @@ -257,11 +257,11 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecAssassinationRogue, { // Inputs to include in the 'Other' section on the settings tab. otherInputs: { inputs: [ - RogueInputs.StartingOverkillDuration(), - RogueInputs.VanishBreakTime(), - RogueInputs.AssumeBleedActive(), - OtherInputs.TankAssignment, - OtherInputs.InFrontOfTarget, + // RogueInputs.StartingOverkillDuration(), + // RogueInputs.VanishBreakTime(), + // RogueInputs.AssumeBleedActive(), + // OtherInputs.TankAssignment, + // OtherInputs.InFrontOfTarget, ], }, encounterPicker: { diff --git a/ui/rogue/combat/presets.ts b/ui/rogue/combat/presets.ts index 89f95f4b9f..870851cba7 100644 --- a/ui/rogue/combat/presets.ts +++ b/ui/rogue/combat/presets.ts @@ -37,24 +37,24 @@ export const ROTATION_PRESET_AOE = PresetUtils.makePresetAPLRotation('Fan AOE', export const CombatHackTalents = { name: 'Combat Axes/Swords', data: SavedTalents.create({ - talentsString: '00532010414-0252051000035015223100501251', - glyphs: Glyphs.create({ - major1: RogueMajorGlyph.GlyphOfKillingSpree, - major2: RogueMajorGlyph.GlyphOfTricksOfTheTrade, - major3: RogueMajorGlyph.GlyphOfRupture, - }), + // talentsString: '00532010414-0252051000035015223100501251', + // glyphs: Glyphs.create({ + // major1: RogueMajorGlyph.GlyphOfKillingSpree, + // major2: RogueMajorGlyph.GlyphOfTricksOfTheTrade, + // major3: RogueMajorGlyph.GlyphOfRupture, + // }), }), }; export const CombatCQCTalents = { name: 'Combat Fists', data: SavedTalents.create({ - talentsString: '00532010414-0252051050035010223100501251', - glyphs: Glyphs.create({ - major1: RogueMajorGlyph.GlyphOfKillingSpree, - major2: RogueMajorGlyph.GlyphOfTricksOfTheTrade, - major3: RogueMajorGlyph.GlyphOfRupture, - }), + // talentsString: '00532010414-0252051050035010223100501251', + // glyphs: Glyphs.create({ + // major1: RogueMajorGlyph.GlyphOfKillingSpree, + // major2: RogueMajorGlyph.GlyphOfTricksOfTheTrade, + // major3: RogueMajorGlyph.GlyphOfRupture, + // }), }), }; diff --git a/ui/rogue/combat/sim.ts b/ui/rogue/combat/sim.ts index b99aae001d..2af3cf0370 100644 --- a/ui/rogue/combat/sim.ts +++ b/ui/rogue/combat/sim.ts @@ -29,129 +29,129 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecCombatRogue, { cssScheme: PlayerClasses.getCssClass(PlayerClasses.Rogue), // List any known bugs / issues here and they'll be shown on the site. knownIssues: ['Rotations are not fully optimized, especially for non-standard setups.'], - warnings: [ - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.sim.encounter.changeEmitter, - getContent: () => { - let hasNoArmor = false; - for (const target of simUI.sim.encounter.targets) { - if (new Stats(target.stats).getStat(Stat.StatArmor) <= 0) { - hasNoArmor = true; - break; - } - } - if (hasNoArmor) { - return 'One or more targets have no armor. Check advanced encounter settings.'; - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if ( - simUI.player.getTalents().mutilate && - (simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType != WeaponType.WeaponTypeDagger || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType != WeaponType.WeaponTypeDagger) - ) { - return '"Mutilate" talent selected, but daggers not equipped in both hands.'; - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if (simUI.player.getTalents().hackAndSlash) { - if ( - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeSword || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeAxe || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeSword || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeAxe - ) { - return ''; - } else { - return '"Hack and Slash" talent selected, but swords or axes not equipped.'; - } - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if (simUI.player.getTalents().closeQuartersCombat) { - if ( - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeFist || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeDagger || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeFist || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeDagger - ) { - return ''; - } else { - return '"Close Quarters Combat" talent selected, but fists or daggers not equipped.'; - } - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if (simUI.player.getTalents().maceSpecialization) { - if ( - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeMace || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeMace - ) { - return ''; - } else { - return '"Mace Specialization" talent selected, but maces not equipped.'; - } - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - const mhWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponSpeed; - const ohWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponSpeed; - const mhImbue = simUI.player.getSpecOptions().classOptions!.mhImbue; - const ohImbue = simUI.player.getSpecOptions().classOptions!.ohImbue; - if ( - typeof mhWeaponSpeed == 'undefined' || - typeof ohWeaponSpeed == 'undefined' || - !simUI.player.getSpecOptions().classOptions!.applyPoisonsManually - ) { - return ''; - } - if (mhWeaponSpeed < ohWeaponSpeed && ohImbue == RogueOptions_PoisonImbue.DeadlyPoison) { - return 'Deadly poison applied to slower (off hand) weapon.'; - } - if (ohWeaponSpeed < mhWeaponSpeed && mhImbue == RogueOptions_PoisonImbue.DeadlyPoison) { - return 'Deadly poison applied to slower (main hand) weapon.'; - } - return ''; - }, - }; - }, - ], + // warnings: [ + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.sim.encounter.changeEmitter, + // getContent: () => { + // let hasNoArmor = false; + // for (const target of simUI.sim.encounter.targets) { + // if (new Stats(target.stats).getStat(Stat.StatArmor) <= 0) { + // hasNoArmor = true; + // break; + // } + // } + // if (hasNoArmor) { + // return 'One or more targets have no armor. Check advanced encounter settings.'; + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if ( + // simUI.player.getTalents().mutilate && + // (simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType != WeaponType.WeaponTypeDagger || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType != WeaponType.WeaponTypeDagger) + // ) { + // return '"Mutilate" talent selected, but daggers not equipped in both hands.'; + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if (simUI.player.getTalents().hackAndSlash) { + // if ( + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeSword || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeAxe || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeSword || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeAxe + // ) { + // return ''; + // } else { + // return '"Hack and Slash" talent selected, but swords or axes not equipped.'; + // } + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if (simUI.player.getTalents().closeQuartersCombat) { + // if ( + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeFist || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeDagger || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeFist || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeDagger + // ) { + // return ''; + // } else { + // return '"Close Quarters Combat" talent selected, but fists or daggers not equipped.'; + // } + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if (simUI.player.getTalents().maceSpecialization) { + // if ( + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeMace || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeMace + // ) { + // return ''; + // } else { + // return '"Mace Specialization" talent selected, but maces not equipped.'; + // } + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // const mhWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponSpeed; + // const ohWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponSpeed; + // const mhImbue = simUI.player.getSpecOptions().classOptions!.mhImbue; + // const ohImbue = simUI.player.getSpecOptions().classOptions!.ohImbue; + // if ( + // typeof mhWeaponSpeed == 'undefined' || + // typeof ohWeaponSpeed == 'undefined' || + // !simUI.player.getSpecOptions().classOptions!.applyPoisonsManually + // ) { + // return ''; + // } + // if (mhWeaponSpeed < ohWeaponSpeed && ohImbue == RogueOptions_PoisonImbue.DeadlyPoison) { + // return 'Deadly poison applied to slower (off hand) weapon.'; + // } + // if (ohWeaponSpeed < mhWeaponSpeed && mhImbue == RogueOptions_PoisonImbue.DeadlyPoison) { + // return 'Deadly poison applied to slower (main hand) weapon.'; + // } + // return ''; + // }, + // }; + // }, + // ], // All stats for which EP should be calculated. epStats: [ @@ -257,11 +257,11 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecCombatRogue, { // Inputs to include in the 'Other' section on the settings tab. otherInputs: { inputs: [ - RogueInputs.StartingOverkillDuration(), - RogueInputs.VanishBreakTime(), - RogueInputs.AssumeBleedActive(), - OtherInputs.TankAssignment, - OtherInputs.InFrontOfTarget, + // RogueInputs.StartingOverkillDuration(), + // RogueInputs.VanishBreakTime(), + // RogueInputs.AssumeBleedActive(), + // OtherInputs.TankAssignment, + // OtherInputs.InFrontOfTarget, ], }, encounterPicker: { diff --git a/ui/rogue/inputs.ts b/ui/rogue/inputs.ts index 4aec729550..c7b29bfc49 100644 --- a/ui/rogue/inputs.ts +++ b/ui/rogue/inputs.ts @@ -31,31 +31,31 @@ export const OffHandImbue = () => ], }); -export const StartingOverkillDuration = () => - InputHelpers.makeClassOptionsNumberInput({ - fieldName: 'startingOverkillDuration', - label: 'Starting Overkill duration', - labelTooltip: 'Initial Overkill buff duration at the start of each iteration.', - showWhen: (player: Player) => player.getTalents().overkill || player.getTalents().masterOfSubtlety > 0, - }); +// export const StartingOverkillDuration = () => +// InputHelpers.makeClassOptionsNumberInput({ +// fieldName: 'startingOverkillDuration', +// label: 'Starting Overkill duration', +// labelTooltip: 'Initial Overkill buff duration at the start of each iteration.', +// showWhen: (player: Player) => player.getTalents().overkill || player.getTalents().masterOfSubtlety > 0, +// }); -export const VanishBreakTime = () => - InputHelpers.makeClassOptionsNumberInput({ - fieldName: 'vanishBreakTime', - label: 'Vanish Break Time', - labelTooltip: 'Time it takes to start attacking after casting Vanish.', - extraCssClasses: ['experimental'], - showWhen: (player: Player) => player.getTalents().overkill || player.getTalents().masterOfSubtlety > 0, - }); +// export const VanishBreakTime = () => +// InputHelpers.makeClassOptionsNumberInput({ +// fieldName: 'vanishBreakTime', +// label: 'Vanish Break Time', +// labelTooltip: 'Time it takes to start attacking after casting Vanish.', +// extraCssClasses: ['experimental'], +// showWhen: (player: Player) => player.getTalents().overkill || player.getTalents().masterOfSubtlety > 0, +// }); -export const AssumeBleedActive = () => - InputHelpers.makeClassOptionsBooleanInput({ - fieldName: 'assumeBleedActive', - label: 'Assume Bleed Always Active', - labelTooltip: "Assume bleed always exists for 'Hunger for Blood' activation. Otherwise will only calculate based on own garrote/rupture.", - extraCssClasses: ['within-raid-sim-hide'], - showWhen: (player: Player) => player.getTalents().hungerForBlood, - }); +// export const AssumeBleedActive = () => +// InputHelpers.makeClassOptionsBooleanInput({ +// fieldName: 'assumeBleedActive', +// label: 'Assume Bleed Always Active', +// labelTooltip: "Assume bleed always exists for 'Hunger for Blood' activation. Otherwise will only calculate based on own garrote/rupture.", +// extraCssClasses: ['within-raid-sim-hide'], +// showWhen: (player: Player) => player.getTalents().hungerForBlood, +// }); export const ApplyPoisonsManually = () => InputHelpers.makeClassOptionsBooleanInput({ diff --git a/ui/rogue/subtlety/presets.ts b/ui/rogue/subtlety/presets.ts index 20a20e0e2a..f8e8fdf435 100644 --- a/ui/rogue/subtlety/presets.ts +++ b/ui/rogue/subtlety/presets.ts @@ -25,24 +25,24 @@ export const ROTATION_PRESET_AOE = PresetUtils.makePresetAPLRotation('Fan AOE', export const SubtletyTalents = { name: 'Subtlety', data: SavedTalents.create({ - talentsString: '30532010114--5022012030321121350115031151', - glyphs: Glyphs.create({ - major1: RogueMajorGlyph.GlyphOfEviscerate, - major2: RogueMajorGlyph.GlyphOfRupture, - major3: RogueMajorGlyph.GlyphOfTricksOfTheTrade, - }), + // talentsString: '30532010114--5022012030321121350115031151', + // glyphs: Glyphs.create({ + // major1: RogueMajorGlyph.GlyphOfEviscerate, + // major2: RogueMajorGlyph.GlyphOfRupture, + // major3: RogueMajorGlyph.GlyphOfTricksOfTheTrade, + // }), }), }; export const HemoSubtletyTalents = { name: 'Hemo Sub', data: SavedTalents.create({ - talentsString: '30532010135--502201203032112135011503122', - glyphs: Glyphs.create({ - major1: RogueMajorGlyph.GlyphOfEviscerate, - major2: RogueMajorGlyph.GlyphOfRupture, - major3: RogueMajorGlyph.GlyphOfTricksOfTheTrade, - }), + // talentsString: '30532010135--502201203032112135011503122', + // glyphs: Glyphs.create({ + // major1: RogueMajorGlyph.GlyphOfEviscerate, + // major2: RogueMajorGlyph.GlyphOfRupture, + // major3: RogueMajorGlyph.GlyphOfTricksOfTheTrade, + // }), }), }; diff --git a/ui/rogue/subtlety/sim.ts b/ui/rogue/subtlety/sim.ts index d91359d9ec..675d35187c 100644 --- a/ui/rogue/subtlety/sim.ts +++ b/ui/rogue/subtlety/sim.ts @@ -29,129 +29,129 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecSubtletyRogue, { cssScheme: PlayerClasses.getCssClass(PlayerClasses.Rogue), // List any known bugs / issues here and they'll be shown on the site. knownIssues: ['Rotations are not fully optimized, especially for non-standard setups.'], - warnings: [ - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.sim.encounter.changeEmitter, - getContent: () => { - let hasNoArmor = false; - for (const target of simUI.sim.encounter.targets) { - if (new Stats(target.stats).getStat(Stat.StatArmor) <= 0) { - hasNoArmor = true; - break; - } - } - if (hasNoArmor) { - return 'One or more targets have no armor. Check advanced encounter settings.'; - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if ( - simUI.player.getTalents().mutilate && - (simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType != WeaponType.WeaponTypeDagger || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType != WeaponType.WeaponTypeDagger) - ) { - return '"Mutilate" talent selected, but daggers not equipped in both hands.'; - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if (simUI.player.getTalents().hackAndSlash) { - if ( - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeSword || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeAxe || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeSword || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeAxe - ) { - return ''; - } else { - return '"Hack and Slash" talent selected, but swords or axes not equipped.'; - } - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if (simUI.player.getTalents().closeQuartersCombat) { - if ( - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeFist || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeDagger || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeFist || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeDagger - ) { - return ''; - } else { - return '"Close Quarters Combat" talent selected, but fists or daggers not equipped.'; - } - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - if (simUI.player.getTalents().maceSpecialization) { - if ( - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeMace || - simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeMace - ) { - return ''; - } else { - return '"Mace Specialization" talent selected, but maces not equipped.'; - } - } else { - return ''; - } - }, - }; - }, - (simUI: IndividualSimUI) => { - return { - updateOn: simUI.player.changeEmitter, - getContent: () => { - const mhWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponSpeed; - const ohWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponSpeed; - const mhImbue = simUI.player.getSpecOptions().classOptions!.mhImbue; - const ohImbue = simUI.player.getSpecOptions().classOptions!.ohImbue; - if ( - typeof mhWeaponSpeed == 'undefined' || - typeof ohWeaponSpeed == 'undefined' || - !simUI.player.getSpecOptions().classOptions!.applyPoisonsManually - ) { - return ''; - } - if (mhWeaponSpeed < ohWeaponSpeed && ohImbue == RogueOptions_PoisonImbue.DeadlyPoison) { - return 'Deadly poison applied to slower (off hand) weapon.'; - } - if (ohWeaponSpeed < mhWeaponSpeed && mhImbue == RogueOptions_PoisonImbue.DeadlyPoison) { - return 'Deadly poison applied to slower (main hand) weapon.'; - } - return ''; - }, - }; - }, - ], + // warnings: [ + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.sim.encounter.changeEmitter, + // getContent: () => { + // let hasNoArmor = false; + // for (const target of simUI.sim.encounter.targets) { + // if (new Stats(target.stats).getStat(Stat.StatArmor) <= 0) { + // hasNoArmor = true; + // break; + // } + // } + // if (hasNoArmor) { + // return 'One or more targets have no armor. Check advanced encounter settings.'; + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if ( + // simUI.player.getTalents().mutilate && + // (simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType != WeaponType.WeaponTypeDagger || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType != WeaponType.WeaponTypeDagger) + // ) { + // return '"Mutilate" talent selected, but daggers not equipped in both hands.'; + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if (simUI.player.getTalents().hackAndSlash) { + // if ( + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeSword || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeAxe || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeSword || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeAxe + // ) { + // return ''; + // } else { + // return '"Hack and Slash" talent selected, but swords or axes not equipped.'; + // } + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if (simUI.player.getTalents().closeQuartersCombat) { + // if ( + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeFist || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeDagger || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeFist || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeDagger + // ) { + // return ''; + // } else { + // return '"Close Quarters Combat" talent selected, but fists or daggers not equipped.'; + // } + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // if (simUI.player.getTalents().maceSpecialization) { + // if ( + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponType == WeaponType.WeaponTypeMace || + // simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponType == WeaponType.WeaponTypeMace + // ) { + // return ''; + // } else { + // return '"Mace Specialization" talent selected, but maces not equipped.'; + // } + // } else { + // return ''; + // } + // }, + // }; + // }, + // (simUI: IndividualSimUI) => { + // return { + // updateOn: simUI.player.changeEmitter, + // getContent: () => { + // const mhWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotMainHand)?.item.weaponSpeed; + // const ohWeaponSpeed = simUI.player.getGear().getEquippedItem(ItemSlot.ItemSlotOffHand)?.item.weaponSpeed; + // const mhImbue = simUI.player.getSpecOptions().classOptions!.mhImbue; + // const ohImbue = simUI.player.getSpecOptions().classOptions!.ohImbue; + // if ( + // typeof mhWeaponSpeed == 'undefined' || + // typeof ohWeaponSpeed == 'undefined' || + // !simUI.player.getSpecOptions().classOptions!.applyPoisonsManually + // ) { + // return ''; + // } + // if (mhWeaponSpeed < ohWeaponSpeed && ohImbue == RogueOptions_PoisonImbue.DeadlyPoison) { + // return 'Deadly poison applied to slower (off hand) weapon.'; + // } + // if (ohWeaponSpeed < mhWeaponSpeed && mhImbue == RogueOptions_PoisonImbue.DeadlyPoison) { + // return 'Deadly poison applied to slower (main hand) weapon.'; + // } + // return ''; + // }, + // }; + // }, + // ], // All stats for which EP should be calculated. epStats: [ @@ -257,12 +257,12 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecSubtletyRogue, { // Inputs to include in the 'Other' section on the settings tab. otherInputs: { inputs: [ - RogueInputs.StartingOverkillDuration(), - RogueInputs.VanishBreakTime(), - RogueInputs.AssumeBleedActive(), - SubInputs.HonorAmongThievesCritRate, - OtherInputs.TankAssignment, - OtherInputs.InFrontOfTarget, + // RogueInputs.StartingOverkillDuration(), + // RogueInputs.VanishBreakTime(), + // RogueInputs.AssumeBleedActive(), + // SubInputs.HonorAmongThievesCritRate, + // OtherInputs.TankAssignment, + // OtherInputs.InFrontOfTarget, ], }, encounterPicker: { diff --git a/ui/shaman/elemental/presets.ts b/ui/shaman/elemental/presets.ts index ecb31f5753..7bc1fcef8b 100644 --- a/ui/shaman/elemental/presets.ts +++ b/ui/shaman/elemental/presets.ts @@ -40,15 +40,15 @@ export const ROTATION_PRESET_ADVANCED = PresetUtils.makePresetAPLRotation('Advan export const StandardTalents = { name: 'Standard', data: SavedTalents.create({ - talentsString: '0533001523213351322301351-005050031', - glyphs: Glyphs.create({ - major1: ShamanMajorGlyph.GlyphOfFlametongueWeapon, - major2: ShamanMajorGlyph.GlyphOfTotemOfWrath, - major3: ShamanMajorGlyph.GlyphOfLightningBolt, - minor1: ShamanMinorGlyph.GlyphOfThunderstorm, - minor2: ShamanMinorGlyph.GlyphOfWaterShield, - minor3: ShamanMinorGlyph.GlyphOfGhostWolf, - }), + // talentsString: '0533001523213351322301351-005050031', + // glyphs: Glyphs.create({ + // major1: ShamanMajorGlyph.GlyphOfFlametongueWeapon, + // major2: ShamanMajorGlyph.GlyphOfTotemOfWrath, + // major3: ShamanMajorGlyph.GlyphOfLightningBolt, + // minor1: ShamanMinorGlyph.GlyphOfThunderstorm, + // minor2: ShamanMinorGlyph.GlyphOfWaterShield, + // minor3: ShamanMinorGlyph.GlyphOfGhostWolf, + // }), }), }; diff --git a/ui/shaman/elemental/sim.ts b/ui/shaman/elemental/sim.ts index 81b30a44b7..40d4b83d95 100644 --- a/ui/shaman/elemental/sim.ts +++ b/ui/shaman/elemental/sim.ts @@ -51,14 +51,14 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecElementalShaman, { Stat.StatSpellHaste, Stat.StatMP5, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); - stats = stats.addStat(Stat.StatSpellHit, player.getTalents().elementalPrecision * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); - stats = stats.addStat(Stat.StatSpellCrit, player.getTalents().tidalMastery * 1 * Mechanics.SPELL_CRIT_RATING_PER_CRIT_CHANCE); - return { - talents: stats, - }; - }, + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); + // stats = stats.addStat(Stat.StatSpellHit, player.getTalents().elementalPrecision * Mechanics.SPELL_HIT_RATING_PER_HIT_CHANCE); + // stats = stats.addStat(Stat.StatSpellCrit, player.getTalents().tidalMastery * 1 * Mechanics.SPELL_CRIT_RATING_PER_CRIT_CHANCE); + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. diff --git a/ui/shaman/enhancement/presets.ts b/ui/shaman/enhancement/presets.ts index f590f8df4d..f5f6a1d7a7 100644 --- a/ui/shaman/enhancement/presets.ts +++ b/ui/shaman/enhancement/presets.ts @@ -47,26 +47,26 @@ export const ROTATION_PHASE_3 = PresetUtils.makePresetAPLRotation('Phase 3', Pha export const StandardTalents = { name: 'Standard', data: SavedTalents.create({ - talentsString: '053030152-30405003105021333031131031051', - glyphs: Glyphs.create({ - major1: ShamanMajorGlyph.GlyphOfFireNova, - major2: ShamanMajorGlyph.GlyphOfFlametongueWeapon, - major3: ShamanMajorGlyph.GlyphOfFeralSpirit, - //minor glyphs dont affect damage done, all convenience/QoL - }), + // talentsString: '053030152-30405003105021333031131031051', + // glyphs: Glyphs.create({ + // major1: ShamanMajorGlyph.GlyphOfFireNova, + // major2: ShamanMajorGlyph.GlyphOfFlametongueWeapon, + // major3: ShamanMajorGlyph.GlyphOfFeralSpirit, + // //minor glyphs dont affect damage done, all convenience/QoL + // }), }), }; export const Phase3Talents = { name: 'Phase 3', data: SavedTalents.create({ - talentsString: '053030152-30505003105001333031131131051', - glyphs: Glyphs.create({ - major1: ShamanMajorGlyph.GlyphOfFireNova, - major2: ShamanMajorGlyph.GlyphOfFlametongueWeapon, - major3: ShamanMajorGlyph.GlyphOfFeralSpirit, - //minor glyphs dont affect damage done, all convenience/QoL - }), + // talentsString: '053030152-30505003105001333031131131051', + // glyphs: Glyphs.create({ + // major1: ShamanMajorGlyph.GlyphOfFireNova, + // major2: ShamanMajorGlyph.GlyphOfFlametongueWeapon, + // major3: ShamanMajorGlyph.GlyphOfFeralSpirit, + // //minor glyphs dont affect damage done, all convenience/QoL + // }), }), }; diff --git a/ui/shaman/inputs.ts b/ui/shaman/inputs.ts index 6433a482c4..3a83850022 100644 --- a/ui/shaman/inputs.ts +++ b/ui/shaman/inputs.ts @@ -91,31 +91,31 @@ export function TotemsSection(parentElem: HTMLElement, simUI: IndividualSimUI) => player.getTalents().totemOfWrath, - }, - { actionId: ActionId.fromSpellId(58656), value: FireTotem.FlametongueTotem }, - ], - equals: (a: FireTotem, b: FireTotem) => a == b, - zeroValue: FireTotem.NoFireTotem, - changedEvent: (player: Player) => player.specOptionsChangeEmitter, - getValue: (player: Player) => player.getSpecOptions().classOptions?.totems?.fire || FireTotem.NoFireTotem, - setValue: (eventID: EventID, player: Player, newValue: number) => { - const newOptions = player.getSpecOptions(); - if (!newOptions.classOptions?.totems) newOptions.classOptions!.totems = ShamanTotems.create(); - newOptions.classOptions!.totems.fire = newValue; - player.setSpecOptions(eventID, newOptions); - }, - }); + // const _fireTotemPicker = new IconEnumPicker(totemDropdownGroup, simUI.player, { + // extraCssClasses: ['fire-totem-picker'], + // numColumns: 1, + // values: [ + // { color: '#ffb3ba', value: FireTotem.NoFireTotem }, + // { actionId: ActionId.fromSpellId(58734), value: FireTotem.MagmaTotem }, + // { actionId: ActionId.fromSpellId(58704), value: FireTotem.SearingTotem }, + // { + // actionId: ActionId.fromSpellId(57722), + // value: FireTotem.TotemOfWrath, + // showWhen: (player: Player) => player.getTalents().totemOfWrath, + // }, + // { actionId: ActionId.fromSpellId(58656), value: FireTotem.FlametongueTotem }, + // ], + // equals: (a: FireTotem, b: FireTotem) => a == b, + // zeroValue: FireTotem.NoFireTotem, + // changedEvent: (player: Player) => player.specOptionsChangeEmitter, + // getValue: (player: Player) => player.getSpecOptions().classOptions?.totems?.fire || FireTotem.NoFireTotem, + // setValue: (eventID: EventID, player: Player, newValue: number) => { + // const newOptions = player.getSpecOptions(); + // if (!newOptions.classOptions?.totems) newOptions.classOptions!.totems = ShamanTotems.create(); + // newOptions.classOptions!.totems.fire = newValue; + // player.setSpecOptions(eventID, newOptions); + // }, + // }); const _airTotemPicker = new IconEnumPicker(totemDropdownGroup, simUI.player, { extraCssClasses: ['air-totem-picker'], diff --git a/ui/shaman/restoration/inputs.ts b/ui/shaman/restoration/inputs.ts index a3911f608f..2b2a307437 100644 --- a/ui/shaman/restoration/inputs.ts +++ b/ui/shaman/restoration/inputs.ts @@ -6,11 +6,11 @@ import { TypedEvent } from '../../core/typed_event'; // Configuration for spec-specific UI elements on the settings tab. // These don't need to be in a separate file but it keeps things cleaner. -export const TriggerEarthShield = InputHelpers.makeSpecOptionsNumberInput({ - fieldName: 'earthShieldPPM', - label: 'Earth Shield PPM', - labelTooltip: 'How many times Earth Shield should be triggered per minute.', - showWhen: (player: Player) => player.getTalents().earthShield, - changeEmitter: (player: Player) => - TypedEvent.onAny([player.specOptionsChangeEmitter, player.rotationChangeEmitter, player.talentsChangeEmitter]), -}); +// export const TriggerEarthShield = InputHelpers.makeSpecOptionsNumberInput({ +// fieldName: 'earthShieldPPM', +// label: 'Earth Shield PPM', +// labelTooltip: 'How many times Earth Shield should be triggered per minute.', +// showWhen: (player: Player) => player.getTalents().earthShield, +// changeEmitter: (player: Player) => +// TypedEvent.onAny([player.specOptionsChangeEmitter, player.rotationChangeEmitter, player.talentsChangeEmitter]), +// }); diff --git a/ui/shaman/restoration/presets.ts b/ui/shaman/restoration/presets.ts index 975deb3914..752262de32 100644 --- a/ui/shaman/restoration/presets.ts +++ b/ui/shaman/restoration/presets.ts @@ -23,29 +23,29 @@ export const P4_PRESET = PresetUtils.makePresetGear('P4 Preset', P4Gear); export const TankHealingTalents = { name: 'Tank Healing', data: SavedTalents.create({ - talentsString: '-30205033-05005331335010501122331251', - glyphs: Glyphs.create({ - major1: ShamanMajorGlyph.GlyphOfEarthlivingWeapon, - major2: ShamanMajorGlyph.GlyphOfEarthShield, - major3: ShamanMajorGlyph.GlyphOfLesserHealingWave, - minor2: ShamanMinorGlyph.GlyphOfWaterShield, - minor1: ShamanMinorGlyph.GlyphOfRenewedLife, - minor3: ShamanMinorGlyph.GlyphOfGhostWolf, - }), + // talentsString: '-30205033-05005331335010501122331251', + // glyphs: Glyphs.create({ + // major1: ShamanMajorGlyph.GlyphOfEarthlivingWeapon, + // major2: ShamanMajorGlyph.GlyphOfEarthShield, + // major3: ShamanMajorGlyph.GlyphOfLesserHealingWave, + // minor2: ShamanMinorGlyph.GlyphOfWaterShield, + // minor1: ShamanMinorGlyph.GlyphOfRenewedLife, + // minor3: ShamanMinorGlyph.GlyphOfGhostWolf, + // }), }), }; export const RaidHealingTalents = { name: 'Raid Healing', data: SavedTalents.create({ - talentsString: '-3020503-50005331335310501122331251', - glyphs: Glyphs.create({ - major1: ShamanMajorGlyph.GlyphOfChainHeal, - major2: ShamanMajorGlyph.GlyphOfEarthShield, - major3: ShamanMajorGlyph.GlyphOfEarthlivingWeapon, - minor2: ShamanMinorGlyph.GlyphOfWaterShield, - minor1: ShamanMinorGlyph.GlyphOfRenewedLife, - minor3: ShamanMinorGlyph.GlyphOfGhostWolf, - }), + // talentsString: '-3020503-50005331335310501122331251', + // glyphs: Glyphs.create({ + // major1: ShamanMajorGlyph.GlyphOfChainHeal, + // major2: ShamanMajorGlyph.GlyphOfEarthShield, + // major3: ShamanMajorGlyph.GlyphOfEarthlivingWeapon, + // minor2: ShamanMinorGlyph.GlyphOfWaterShield, + // minor1: ShamanMinorGlyph.GlyphOfRenewedLife, + // minor3: ShamanMinorGlyph.GlyphOfGhostWolf, + // }), }), }; diff --git a/ui/shaman/restoration/sim.ts b/ui/shaman/restoration/sim.ts index cb4feed721..55ae80e47f 100644 --- a/ui/shaman/restoration/sim.ts +++ b/ui/shaman/restoration/sim.ts @@ -33,13 +33,13 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecRestorationShaman, { Stat.StatSpellHaste, Stat.StatMP5, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); - stats = stats.addStat(Stat.StatSpellCrit, player.getTalents().tidalMastery * 1 * Mechanics.SPELL_CRIT_RATING_PER_CRIT_CHANCE); - return { - talents: stats, - }; - }, + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); + // stats = stats.addStat(Stat.StatSpellCrit, player.getTalents().tidalMastery * 1 * Mechanics.SPELL_CRIT_RATING_PER_CRIT_CHANCE); + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. @@ -88,7 +88,10 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecRestorationShaman, { excludeBuffDebuffInputs: [], // Inputs to include in the 'Other' section on the settings tab. otherInputs: { - inputs: [RestorationInputs.TriggerEarthShield, OtherInputs.TankAssignment], + inputs: [ + // RestorationInputs.TriggerEarthShield, + // OtherInputs.TankAssignment + ], }, customSections: [ShamanInputs.TotemsSection], encounterPicker: { diff --git a/ui/warlock/affliction/presets.ts b/ui/warlock/affliction/presets.ts index 3988163220..8d2560bccd 100644 --- a/ui/warlock/affliction/presets.ts +++ b/ui/warlock/affliction/presets.ts @@ -57,15 +57,15 @@ export const APL_Affliction_Default = PresetUtils.makePresetAPLRotation('Afflict export const AfflictionTalents = { name: 'Affliction', data: SavedTalents.create({ - talentsString: '2350002030023510253500331151--550000051', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfQuickDecay, - major2: MajorGlyph.GlyphOfLifeTap, - major3: MajorGlyph.GlyphOfHaunt, - minor1: MinorGlyph.GlyphOfSouls, - minor2: MinorGlyph.GlyphOfDrainSoul, - minor3: MinorGlyph.GlyphOfSubjugateDemon, - }), + // talentsString: '2350002030023510253500331151--550000051', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfQuickDecay, + // major2: MajorGlyph.GlyphOfLifeTap, + // major3: MajorGlyph.GlyphOfHaunt, + // minor1: MinorGlyph.GlyphOfSouls, + // minor2: MinorGlyph.GlyphOfDrainSoul, + // minor3: MinorGlyph.GlyphOfSubjugateDemon, + // }), }), }; diff --git a/ui/warlock/affliction/sim.ts b/ui/warlock/affliction/sim.ts index 8f353f6973..a6c01147f2 100644 --- a/ui/warlock/affliction/sim.ts +++ b/ui/warlock/affliction/sim.ts @@ -67,7 +67,11 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecAfflictionWarlock, { }, // IconInputs to include in the 'Player' section on the settings tab. - playerIconInputs: [WarlockInputs.PetInput(), WarlockInputs.ArmorInput(), WarlockInputs.WeaponImbueInput()], + playerIconInputs: [ + // WarlockInputs.PetInput(), + // WarlockInputs.ArmorInput(), + // WarlockInputs.WeaponImbueInput() + ], // Buff and Debuff inputs to include/exclude, overriding the EP-based defaults. includeBuffDebuffInputs: [ diff --git a/ui/warlock/demonology/presets.ts b/ui/warlock/demonology/presets.ts index 59c5f175c8..13cf4f8e5b 100644 --- a/ui/warlock/demonology/presets.ts +++ b/ui/warlock/demonology/presets.ts @@ -52,15 +52,15 @@ export const APL_Demo_Default = PresetUtils.makePresetAPLRotation('Demo', DemoAp export const DemonologyTalents = { name: 'Demonology', data: SavedTalents.create({ - talentsString: '-203203301035012530135201351-550000052', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfLifeTap, - major2: MajorGlyph.GlyphOfQuickDecay, - major3: MajorGlyph.GlyphOfFelguard, - minor1: MinorGlyph.GlyphOfSouls, - minor2: MinorGlyph.GlyphOfDrainSoul, - minor3: MinorGlyph.GlyphOfSubjugateDemon, - }), + // talentsString: '-203203301035012530135201351-550000052', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfLifeTap, + // major2: MajorGlyph.GlyphOfQuickDecay, + // major3: MajorGlyph.GlyphOfFelguard, + // minor1: MinorGlyph.GlyphOfSouls, + // minor2: MinorGlyph.GlyphOfDrainSoul, + // minor3: MinorGlyph.GlyphOfSubjugateDemon, + // }), }), }; diff --git a/ui/warlock/demonology/sim.ts b/ui/warlock/demonology/sim.ts index 0e52bd6ac0..e7039014c4 100644 --- a/ui/warlock/demonology/sim.ts +++ b/ui/warlock/demonology/sim.ts @@ -67,7 +67,11 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecDemonologyWarlock, { }, // IconInputs to include in the 'Player' section on the settings tab. - playerIconInputs: [WarlockInputs.PetInput(), WarlockInputs.ArmorInput(), WarlockInputs.WeaponImbueInput()], + playerIconInputs: [ + // WarlockInputs.PetInput(), + // WarlockInputs.ArmorInput(), + // WarlockInputs.WeaponImbueInput() + ], // Buff and Debuff inputs to include/exclude, overriding the EP-based defaults. includeBuffDebuffInputs: [ diff --git a/ui/warlock/destruction/presets.ts b/ui/warlock/destruction/presets.ts index c487b2c12e..455ee60cb9 100644 --- a/ui/warlock/destruction/presets.ts +++ b/ui/warlock/destruction/presets.ts @@ -59,15 +59,15 @@ export const APL_Destro_Default = PresetUtils.makePresetAPLRotation('Destro', De export const DestructionTalents = { name: 'Destruction', data: SavedTalents.create({ - talentsString: '-03310030003-05203205210331051335230351', - glyphs: Glyphs.create({ - major1: MajorGlyph.GlyphOfConflagrate, - major2: MajorGlyph.GlyphOfLifeTap, - major3: MajorGlyph.GlyphOfIncinerate, - minor1: MinorGlyph.GlyphOfSouls, - minor2: MinorGlyph.GlyphOfDrainSoul, - minor3: MinorGlyph.GlyphOfSubjugateDemon, - }), + // talentsString: '-03310030003-05203205210331051335230351', + // glyphs: Glyphs.create({ + // major1: MajorGlyph.GlyphOfConflagrate, + // major2: MajorGlyph.GlyphOfLifeTap, + // major3: MajorGlyph.GlyphOfIncinerate, + // minor1: MinorGlyph.GlyphOfSouls, + // minor2: MinorGlyph.GlyphOfDrainSoul, + // minor3: MinorGlyph.GlyphOfSubjugateDemon, + // }), }), }; diff --git a/ui/warlock/destruction/sim.ts b/ui/warlock/destruction/sim.ts index 74575b1d97..ec0e56d6c4 100644 --- a/ui/warlock/destruction/sim.ts +++ b/ui/warlock/destruction/sim.ts @@ -67,7 +67,11 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecDestructionWarlock, { }, // IconInputs to include in the 'Player' section on the settings tab. - playerIconInputs: [WarlockInputs.PetInput(), WarlockInputs.ArmorInput(), WarlockInputs.WeaponImbueInput()], + playerIconInputs: [ + // WarlockInputs.PetInput(), + // WarlockInputs.ArmorInput(), + // WarlockInputs.WeaponImbueInput() + ], // Buff and Debuff inputs to include/exclude, overriding the EP-based defaults. includeBuffDebuffInputs: [ diff --git a/ui/warlock/inputs.ts b/ui/warlock/inputs.ts index 01b7a72fb3..8701b0ee9a 100644 --- a/ui/warlock/inputs.ts +++ b/ui/warlock/inputs.ts @@ -27,22 +27,22 @@ export const WeaponImbueInput = () => ], }); -export const PetInput = () => - InputHelpers.makeClassOptionsEnumIconInput({ - fieldName: 'summon', - values: [ - { value: Summon.NoSummon, tooltip: 'No Pet' }, - { actionId: ActionId.fromSpellId(688), value: Summon.Imp }, - { actionId: ActionId.fromSpellId(712), value: Summon.Succubus }, - { actionId: ActionId.fromSpellId(691), value: Summon.Felhunter }, - { - actionId: ActionId.fromSpellId(30146), - value: Summon.Felguard, - showWhen: (player: Player) => player.getTalents().summonFelguard, - }, - ], - changeEmitter: (player: Player) => player.changeEmitter, - }); +// export const PetInput = () => +// InputHelpers.makeClassOptionsEnumIconInput({ +// fieldName: 'summon', +// values: [ +// { value: Summon.NoSummon, tooltip: 'No Pet' }, +// { actionId: ActionId.fromSpellId(688), value: Summon.Imp }, +// { actionId: ActionId.fromSpellId(712), value: Summon.Succubus }, +// { actionId: ActionId.fromSpellId(691), value: Summon.Felhunter }, +// { +// actionId: ActionId.fromSpellId(30146), +// value: Summon.Felguard, +// showWhen: (player: Player) => player.getTalents().summonFelguard, +// }, +// ], +// changeEmitter: (player: Player) => player.changeEmitter, +// }); export const DetonateSeed = () => InputHelpers.makeClassOptionsBooleanInput({ diff --git a/ui/warrior/arms/presets.ts b/ui/warrior/arms/presets.ts index d4a07d4202..e60ed637bc 100644 --- a/ui/warrior/arms/presets.ts +++ b/ui/warrior/arms/presets.ts @@ -37,15 +37,15 @@ export const ROTATION_ARMS_SUNDER = PresetUtils.makePresetAPLRotation('Arms + Su export const ArmsTalents = { name: 'Arms', data: SavedTalents.create({ - talentsString: '3022032023335100102012213231251-305-2033', - glyphs: Glyphs.create({ - major1: WarriorMajorGlyph.GlyphOfRending, - major2: WarriorMajorGlyph.GlyphOfMortalStrike, - major3: WarriorMajorGlyph.GlyphOfExecution, - minor1: WarriorMinorGlyph.GlyphOfThunderClap, - minor2: WarriorMinorGlyph.GlyphOfCommand, - minor3: WarriorMinorGlyph.GlyphOfShatteringThrow, - }), + // talentsString: '3022032023335100102012213231251-305-2033', + // glyphs: Glyphs.create({ + // major1: WarriorMajorGlyph.GlyphOfRending, + // major2: WarriorMajorGlyph.GlyphOfMortalStrike, + // major3: WarriorMajorGlyph.GlyphOfExecution, + // minor1: WarriorMinorGlyph.GlyphOfThunderClap, + // minor2: WarriorMinorGlyph.GlyphOfCommand, + // minor3: WarriorMinorGlyph.GlyphOfShatteringThrow, + // }), }), }; diff --git a/ui/warrior/arms/sim.ts b/ui/warrior/arms/sim.ts index 2a1f4cbe92..21a5b61fea 100644 --- a/ui/warrior/arms/sim.ts +++ b/ui/warrior/arms/sim.ts @@ -45,16 +45,16 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecArmsWarrior, { Stat.StatArmorPenetration, Stat.StatArmor, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); - if (!player.getInFrontOfTarget()) { - // When behind target, dodge is the only outcome affected by Expertise. - stats = stats.addStat(Stat.StatExpertise, player.getTalents().weaponMastery * 4 * Mechanics.EXPERTISE_PER_QUARTER_PERCENT_REDUCTION); - } - return { - talents: stats, - }; - }, + // modifyDisplayStats: (player: Player) => { + // let stats = new Stats(); + // if (!player.getInFrontOfTarget()) { + // // When behind target, dodge is the only outcome affected by Expertise. + // stats = stats.addStat(Stat.StatExpertise, player.getTalents().weaponMastery * 4 * Mechanics.EXPERTISE_PER_QUARTER_PERCENT_REDUCTION); + // } + // return { + // talents: stats, + // }; + // }, defaults: { // Default equipped gear. diff --git a/ui/warrior/fury/presets.ts b/ui/warrior/fury/presets.ts index b5c67dbde7..3990d08697 100644 --- a/ui/warrior/fury/presets.ts +++ b/ui/warrior/fury/presets.ts @@ -33,15 +33,15 @@ export const ROTATION_FURY_SUNDER = PresetUtils.makePresetAPLRotation('Fury + Su export const FuryTalents = { name: 'Fury', data: SavedTalents.create({ - talentsString: '32002301233-305053000520310053120500351', - glyphs: Glyphs.create({ - major1: WarriorMajorGlyph.GlyphOfWhirlwind, - major2: WarriorMajorGlyph.GlyphOfHeroicStrike, - major3: WarriorMajorGlyph.GlyphOfExecution, - minor1: WarriorMinorGlyph.GlyphOfCommand, - minor2: WarriorMinorGlyph.GlyphOfShatteringThrow, - minor3: WarriorMinorGlyph.GlyphOfCharge, - }), + // talentsString: '32002301233-305053000520310053120500351', + // glyphs: Glyphs.create({ + // major1: WarriorMajorGlyph.GlyphOfWhirlwind, + // major2: WarriorMajorGlyph.GlyphOfHeroicStrike, + // major3: WarriorMajorGlyph.GlyphOfExecution, + // minor1: WarriorMinorGlyph.GlyphOfCommand, + // minor2: WarriorMinorGlyph.GlyphOfShatteringThrow, + // minor3: WarriorMinorGlyph.GlyphOfCharge, + // }), }), }; diff --git a/ui/warrior/fury/sim.ts b/ui/warrior/fury/sim.ts index 07487810c3..2eef9a56a4 100644 --- a/ui/warrior/fury/sim.ts +++ b/ui/warrior/fury/sim.ts @@ -45,16 +45,16 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecFuryWarrior, { Stat.StatArmorPenetration, Stat.StatArmor, ], - modifyDisplayStats: (player: Player) => { - let stats = new Stats(); - if (!player.getInFrontOfTarget()) { - // When behind target, dodge is the only outcome affected by Expertise. - stats = stats.addStat(Stat.StatExpertise, player.getTalents().weaponMastery * 4 * Mechanics.EXPERTISE_PER_QUARTER_PERCENT_REDUCTION); - } - return { - talents: stats, - }; - }, + // modifyDisplayStats: (player: Player) => { + // //let stats = new Stats(); + // if (!player.getInFrontOfTarget()) { + // // When behind target, dodge is the only outcome affected by Expertise. + // //stats = stats.addStat(Stat.StatExpertise, player.getTalents().weaponMastery * 4 * Mechanics.EXPERTISE_PER_QUARTER_PERCENT_REDUCTION); + // } + // return { + // // talents: stats, + // }; + // }, defaults: { // Default equipped gear. diff --git a/ui/warrior/protection/presets.ts b/ui/warrior/protection/presets.ts index 4165ab0d6e..385ed64b7e 100644 --- a/ui/warrior/protection/presets.ts +++ b/ui/warrior/protection/presets.ts @@ -35,30 +35,30 @@ export const ROTATION_PRESET_SIMPLE = PresetUtils.makePresetSimpleRotation('Simp export const StandardTalents = { name: 'Standard', data: SavedTalents.create({ - talentsString: '2500030023-302-053351225000012521030113321', - glyphs: Glyphs.create({ - major1: WarriorMajorGlyph.GlyphOfBlocking, - major2: WarriorMajorGlyph.GlyphOfVigilance, - major3: WarriorMajorGlyph.GlyphOfDevastate, - minor1: WarriorMinorGlyph.GlyphOfCharge, - minor2: WarriorMinorGlyph.GlyphOfThunderClap, - minor3: WarriorMinorGlyph.GlyphOfCommand, - }), + // talentsString: '2500030023-302-053351225000012521030113321', + // glyphs: Glyphs.create({ + // major1: WarriorMajorGlyph.GlyphOfBlocking, + // major2: WarriorMajorGlyph.GlyphOfVigilance, + // major3: WarriorMajorGlyph.GlyphOfDevastate, + // minor1: WarriorMinorGlyph.GlyphOfCharge, + // minor2: WarriorMinorGlyph.GlyphOfThunderClap, + // minor3: WarriorMinorGlyph.GlyphOfCommand, + // }), }), }; export const UATalents = { name: 'UA', data: SavedTalents.create({ - talentsString: '35023301230051002020120002-2-05035122500000252', - glyphs: Glyphs.create({ - major1: WarriorMajorGlyph.GlyphOfRevenge, - major2: WarriorMajorGlyph.GlyphOfHeroicStrike, - major3: WarriorMajorGlyph.GlyphOfSweepingStrikes, - minor1: WarriorMinorGlyph.GlyphOfCharge, - minor2: WarriorMinorGlyph.GlyphOfThunderClap, - minor3: WarriorMinorGlyph.GlyphOfCommand, - }), + // talentsString: '35023301230051002020120002-2-05035122500000252', + // glyphs: Glyphs.create({ + // major1: WarriorMajorGlyph.GlyphOfRevenge, + // major2: WarriorMajorGlyph.GlyphOfHeroicStrike, + // major3: WarriorMajorGlyph.GlyphOfSweepingStrikes, + // minor1: WarriorMinorGlyph.GlyphOfCharge, + // minor2: WarriorMinorGlyph.GlyphOfThunderClap, + // minor3: WarriorMinorGlyph.GlyphOfCommand, + // }), }), };