From deb5574dc43cdadd3e31d5a14b72c96f2847fff3 Mon Sep 17 00:00:00 2001 From: Kayla Glick Date: Tue, 24 Dec 2024 02:02:54 -0500 Subject: [PATCH] warrior phase 7 shoulder runes --- assets/database/db.bin | Bin 6249252 -> 6250319 bytes assets/database/db.json | 22 +- assets/database/leftover_db.bin | Bin 918064 -> 919131 bytes assets/database/leftover_db.json | 18 + .../wowhead_shoulder_rune_tooltips.csv | 2 +- proto/warrior.proto | 284 +++++---- sim/warrior/item_sets_pve.go | 571 ------------------ sim/warrior/item_sets_pve_phase_4.go | 287 +++++++++ sim/warrior/item_sets_pve_phase_5.go | 281 +++++++++ sim/warrior/item_sets_pve_phase_6.go | 163 +++++ sim/warrior/runes.go | 53 ++ sim/warrior/talents.go | 17 +- tools/database/rune_overrides.go | 9 +- tools/scrape_shoulder_runes.py | 3 +- 14 files changed, 994 insertions(+), 716 deletions(-) create mode 100644 sim/warrior/item_sets_pve_phase_4.go create mode 100644 sim/warrior/item_sets_pve_phase_5.go create mode 100644 sim/warrior/item_sets_pve_phase_6.go diff --git a/assets/database/db.bin b/assets/database/db.bin index b713f6b8fede1f8b23a78f006ab86c47ff7a86e0..265b2fb9d4e5963924ac6bef0d14d705c24e5de5 100644 GIT binary patch delta 890 zcmZXSOHUI~7>3h|dd3S%EI zB1Ro|#KfOqm_!rf#<+CN)_>qaV~iNTHjtFMcsKJsdA@VrGjEqxoL@h#I49wN6C03+ zjo5_EU=XkcTd@t>k&hkNi2}H=3xy~`F-lO1GPqF=54`Z90wVm_jXelpFZQ7l`*8pV zaR`TT1V?cURXC1n)ZheaQHPVLM-UBYL=#S-8K-duEojAAgwTd|bl@C1(S>fD#|2!( zCG?;d62kA~s%raljr_!6S5?a|9d=Kx9Idpw2jzK(y)-~yW|xO#%4JF)rQcp2QofXW zg6zlpE>}_5NX11XDw;7a%4)>aBATjO3loZ06r@J>lbDihre95neca@URVpAzE$kOj z-fXH>HO)8|+l>T|s7ceBno=sfY2WW$Uu)bjhLfCIy%UP)7NlDChmeA7nXH+s%RGV< zWPfSC?${xoG!w>nW{FRb8rbBAE?053A;eWPcGF1d)|+X?SDt1bb(p?jRe`N-1BtA)nUylm{a@} r=}KSId|mA=QTk7kF(Yy-BXJ0`i(?Aq3gs&08fAcT-Ci6Uoc{I?v#2^! delta 261 zcmWm2%Q8Y?0KoA%hlq%B%OzA4ayd?NtK3St6bBz2q;{U7g~flSg&8|<;1NvU!i=p& zi`H$uM>9T)-{#l+ZtEZQw*G>KP6wSh=%O1ZJ@n$DkABmgE*UPvCR&(ea zgj3EqCr^P3F0r`cnww8ynDQ$o-Zg2M;#HGYTs%i)ru;wkl6cc~Rz7dE898OV^!bcM|a;RfbSX zDNon2NVodLgebRB513+FsK&Z%S&!yM z%rR`=L~Ae~Iho%No_G>c^ht^4a2_nyvldm}^f`3gO(d>i+d><_Tt1N)9Kq&Yu8m)0 zdUCMrCX9!ceHb`AiuCkXLZOX&=oJ7H>GyRP*5si+`blPhu+Uc4p~eI01zfiei3vxs z(Do@pbfnv2Pm{I)si4={91A{ccuWfY;s-I4*53d!)cRZ#zDeW?XC=`waQx{DSsMQj D{yOmb delta 75 zcmV-R0JQ(xj5x4_IDmu!gaU*Egam{Iga(8Mgb0KQgbIWUv<%*cw{nOKk^#5gh76Pe hw*-m|?47rTDGiPRx9}$ol>xUCD-FoLw+8MFRTwnY9HRgL diff --git a/assets/database/leftover_db.json b/assets/database/leftover_db.json index 2887be42f3..331be38b8e 100644 --- a/assets/database/leftover_db.json +++ b/assets/database/leftover_db.json @@ -1930,6 +1930,24 @@ {"id":462853,"name":"Engrave Pants - Hand of Sacrifice","icon":"spell_holy_sealofsacrifice","type":9,"classAllowlist":[4]}, {"id":468758,"name":"Engrave Ring - Healing Specialization","icon":"spell_holy_greaterheal","type":11,"classAllowlist":[1,3,4,5,7]}, {"id":468762,"name":"Engrave Ring - Meditation Specialization","icon":"spell_holy_greaterheal","type":11,"classAllowlist":[1,2,3,4,5,7,8]}, +{"id":1219957,"name":"Soul of the Tactician","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219958,"name":"Soul of the War Veteran","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219960,"name":"Soul of the Battle Forecaster","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219962,"name":"Soul of the Bloodseeker","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219964,"name":"Soul of the Titan","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219966,"name":"Soul of the Destroyer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219968,"name":"Soul of the Deathbound","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219970,"name":"Soul of the Sanguinist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219974,"name":"Soul of the Savage","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219976,"name":"Soul of Enmity","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9,4]}, +{"id":1219978,"name":"Soul of the Deflective","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219980,"name":"Soul of the Revenger","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219982,"name":"Soul of the Incessant","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219984,"name":"Soul of the Thunderbringer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219986,"name":"Soul of the Sentinel","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219988,"name":"Soul of the Southpaw","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219990,"name":"Soul of the Gladiator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, +{"id":1219992,"name":"Soul of the Aftershock","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[9]}, {"id":1220034,"name":"Soul of the Refined","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, {"id":1220106,"name":"Soul of the Hastened Healer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[5]}, {"id":1220110,"name":"Soul of the Celebrant","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[5]}, diff --git a/assets/db_inputs/wowhead_shoulder_rune_tooltips.csv b/assets/db_inputs/wowhead_shoulder_rune_tooltips.csv index 570e49cb81..dfe5c0e8e3 100644 --- a/assets/db_inputs/wowhead_shoulder_rune_tooltips.csv +++ b/assets/db_inputs/wowhead_shoulder_rune_tooltips.csv @@ -5,7 +5,7 @@ 1220364,{"name":"Soul of the Cometcaller","quality":3,"icon":"spell_holy_divinespirit","tooltip":"
Soul of the Cometcaller
Item Level 55

Binds when picked up
Unique (20)
Classes: Druid
Requires Level 55
Use: Permanently imbue your shoulders with the Soul of the Cometcaller:

Reduces the cast time and global cooldown of Starfire by 0.5 sec.

","spells":[]} 1220307,{"name":"Soul of the Beast","quality":3,"icon":"spell_holy_divinespirit","tooltip":"
Soul of the Beast
Item Level 55

Binds when picked up
Unique (20)
Classes: Druid
Requires Level 55
Use: Permanently imbue your shoulders with the Soul of the Beast:

Your Mangle(Bear), Swipe(Bear), Maul, and Lacerate abilities gain 5% increased critical strike chance against targets afflicted by your Lacerate.

","spells":[]} 1220328,{"name":"Soul of the Benevolet Seer","quality":3,"icon":"spell_holy_divinespirit","tooltip":"
Soul of the Benevolet Seer
Item Level 55

Binds when picked up
Unique (20)
Classes: Druid
Requires Level 55
Use: Permanently imbue your shoulders with the Soul of the Benevolet Seer:

Reduces the cooldown of your Rebirth and Innervate spells by 65%.

","spells":[]} -1219956,{"name":"Soul of the Tactician","quality":3,"icon":"spell_holy_divinespirit","tooltip":"
Soul of the Tactician
Item Level 55

Binds when picked up
Unique (20)
Classes: Warrior
Requires Level 55
Use: Permanently imbue your shoulders with the Soul of the Tactician:

After changing stances, your next offensive ability's rage cost is reduced by 10.

","spells":[]} +1219957,{"name":"Soul of the Tactician","quality":3,"icon":"spell_holy_divinespirit","tooltip":"
Soul of the Tactician
Item Level 55

Binds when picked up
Unique (20)
Classes: Warrior
Requires Level 55
Use: Permanently imbue your shoulders with the Soul of the Tactician:

After changing stances, your next offensive ability's rage cost is reduced by 10.

","spells":[]} 1219964,{"name":"Soul of the Titan","quality":3,"icon":"spell_holy_divinespirit","tooltip":"
Soul of the Titan
Item Level 55

Binds when picked up
Unique (20)
Classes: Warrior
Requires Level 55
Use: Permanently imbue your shoulders with the Soul of the Titan:

Your Heroic Strike, Slam, and Overpower abilities deal 25 + (5 * ComboPoints)% more damage.

","spells":[]} 1219976,{"name":"Soul of Enmity","quality":3,"icon":"spell_holy_divinespirit","tooltip":"
Soul of Enmity
Item Level 55

Binds when picked up
Unique (20)
Classes: Warrior, Paladin
Requires Level 55
Use: Permanently imbue your shoulders with the Soul of Enmity:

Increases all threat you generate in Defensive Stance by an additional 10% and increases all damage you deal in Gladiator Stance by 4%.

","spells":[]} 1220072,{"name":"Soul of the Preyseeker","quality":3,"icon":"spell_holy_divinespirit","tooltip":"
Soul of the Preyseeker
Item Level 55

Binds when picked up
Unique (20)
Classes: Hunter
Requires Level 55
Use: Permanently imbue your shoulders with the Soul of the Preyseeker:

While tracking a creature type, you deal 3% increased damage to that creature type.

","spells":[]} diff --git a/proto/warrior.proto b/proto/warrior.proto index 1d6b434a16..3d03fb7142 100644 --- a/proto/warrior.proto +++ b/proto/warrior.proto @@ -4,158 +4,174 @@ package proto; option go_package = "./proto"; message WarriorTalents { - // Arms - int32 improved_heroic_strike = 1; - int32 deflection = 2; - int32 improved_rend = 3; - int32 improved_charge = 4; - int32 tactical_mastery = 5; - int32 improved_thunder_clap = 6; - int32 improved_overpower = 7; - bool anger_management = 8; - int32 deep_wounds = 9; - int32 two_handed_weapon_specialization = 10; - int32 impale = 11; - int32 axe_specialization = 12; - bool sweeping_strikes = 13; - int32 mace_specialization = 14; - int32 sword_specialization = 15; - int32 polearm_specialization = 16; - int32 improved_hamstring = 17; - bool mortal_strike = 18; - - // Fury - int32 booming_voice = 19; - int32 cruelty = 20; - int32 improved_demoralizing_shout = 21; - int32 unbridled_wrath = 22; - int32 improved_cleave = 23; - bool piercing_howl = 24; - int32 blood_craze = 25; - int32 improved_battle_shout = 26; - int32 dual_wield_specialization = 27; - int32 improved_execute = 28; - int32 enrage = 29; - int32 improved_slam = 30; - bool death_wish = 31; - int32 improved_intercept = 32; - int32 improved_berserker_rage = 33; - int32 flurry = 34; - bool bloodthirst = 35; - - // Protection - int32 shield_specialization = 36; - int32 anticipation = 37; - int32 improved_bloodrage = 38; - int32 toughness = 39; - int32 iron_will = 40; - bool last_stand = 41; - int32 improved_shield_block = 42; - int32 improved_revenge = 43; - int32 defiance = 44; - int32 improved_sunder_armor = 45; - int32 improved_disarm = 46; - int32 improved_taunt = 47; - int32 improved_shield_wall = 48; - bool concussion_blow = 49; - int32 improved_shield_bash = 50; - int32 one_handed_weapon_specialization = 51; - bool shield_slam = 52; + // Arms + int32 improved_heroic_strike = 1; + int32 deflection = 2; + int32 improved_rend = 3; + int32 improved_charge = 4; + int32 tactical_mastery = 5; + int32 improved_thunder_clap = 6; + int32 improved_overpower = 7; + bool anger_management = 8; + int32 deep_wounds = 9; + int32 two_handed_weapon_specialization = 10; + int32 impale = 11; + int32 axe_specialization = 12; + bool sweeping_strikes = 13; + int32 mace_specialization = 14; + int32 sword_specialization = 15; + int32 polearm_specialization = 16; + int32 improved_hamstring = 17; + bool mortal_strike = 18; + + // Fury + int32 booming_voice = 19; + int32 cruelty = 20; + int32 improved_demoralizing_shout = 21; + int32 unbridled_wrath = 22; + int32 improved_cleave = 23; + bool piercing_howl = 24; + int32 blood_craze = 25; + int32 improved_battle_shout = 26; + int32 dual_wield_specialization = 27; + int32 improved_execute = 28; + int32 enrage = 29; + int32 improved_slam = 30; + bool death_wish = 31; + int32 improved_intercept = 32; + int32 improved_berserker_rage = 33; + int32 flurry = 34; + bool bloodthirst = 35; + + // Protection + int32 shield_specialization = 36; + int32 anticipation = 37; + int32 improved_bloodrage = 38; + int32 toughness = 39; + int32 iron_will = 40; + bool last_stand = 41; + int32 improved_shield_block = 42; + int32 improved_revenge = 43; + int32 defiance = 44; + int32 improved_sunder_armor = 45; + int32 improved_disarm = 46; + int32 improved_taunt = 47; + int32 improved_shield_wall = 48; + bool concussion_blow = 49; + int32 improved_shield_bash = 50; + int32 one_handed_weapon_specialization = 51; + bool shield_slam = 52; } enum WarriorRune { - WarriorRuneNone = 0; - - // Helm - RuneEndlessRage = 403218; - RuneTasteForBlood = 426953; - RuneVigilance = 426972; - RuneShieldMastery = 426980; - - // Cloak - RuneSuddenDeath = 440113; - RuneFreshMeat = 440484; - RuneShockwave = 440488; - - // Chest - RuneFlagellation = 402877; - RuneRagingBlow = 402911; - RuneBloodFrenzy = 412507; - RuneWarbringer = 425421; - - // Bracers - RuneRampage = 426940; - RuneSwordAndBoard = 426978; - RuneWreckingCrew = 427065; - - // Hands - RuneVictoryRush = 402927; - RuneDevastate = 403195; - - RuneSingleMindedFury = 413404; - RuneQuickStrike = 429765; - - // Waist - RuneFocusedRage = 29787; - RunePreciseTiming = 402922; - RuneBloodSurge = 413380; - - // Legs - RuneFuriousThunder = 403219; - RuneFrenziedAssault = 425412; - RuneConsumedByRage = 425418; - - // Feet - RuneEnragedRegeneration = 403467; - RuneIntervene = 403472; - RuneRallyingCry = 426491; - RuneGladiatorStance = 412513; - - // Utility - RuneCommandingShout = 403446; + WarriorRuneNone = 0; + + // Helm + RuneEndlessRage = 403218; + RuneTasteForBlood = 426953; + RuneVigilance = 426972; + RuneShieldMastery = 426980; + + // Shoulders + RuneShouldersAftershock = 1219992; + RuneShouldersBattleForecaster = 1219960; + RuneShouldersBloodseeker = 1219962; + RuneShouldersDeathbound = 1219968; + RuneShouldersDeflective = 1219978; + RuneShouldersDestroyer = 1219966; + RuneShouldersEnmity = 1219976; + RuneShouldersGladiator = 1219990; + RuneShouldersIncessant = 1219982; + RuneShouldersRevenger = 1219980; + RuneShouldersSanguinist = 1219970; + RuneShouldersSavage = 1219974; + RuneShouldersSentinel = 1219986; + RuneShouldersSouthpaw = 1219988; + RuneShouldersTactician = 1219957; + RuneShouldersThunderbringer = 1219984; + RuneShouldersTitan = 1219964; + RuneShouldersWarVeteran = 1219958; + + // Cloak + RuneSuddenDeath = 440113; + RuneFreshMeat = 440484; + RuneShockwave = 440488; + + // Chest + RuneFlagellation = 402877; + RuneRagingBlow = 402911; + RuneBloodFrenzy = 412507; + RuneWarbringer = 425421; + + // Bracers + RuneRampage = 426940; + RuneSwordAndBoard = 426978; + RuneWreckingCrew = 427065; + + // Hands + RuneVictoryRush = 402927; + RuneDevastate = 403195; + RuneSingleMindedFury = 413404; + RuneQuickStrike = 429765; + + // Waist + RuneFocusedRage = 29787; + RunePreciseTiming = 402922; + RuneBloodSurge = 413380; + + // Legs + RuneFuriousThunder = 403219; + RuneFrenziedAssault = 425412; + RuneConsumedByRage = 425418; + + // Feet + RuneEnragedRegeneration = 403467; + RuneIntervene = 403472; + RuneRallyingCry = 426491; + RuneGladiatorStance = 412513; } enum WarriorShout { - WarriorShoutNone = 0; - WarriorShoutBattle = 1; - WarriorShoutCommanding = 2; + WarriorShoutNone = 0; + WarriorShoutBattle = 1; + WarriorShoutCommanding = 2; } enum WarriorStance { - WarriorStanceNone = 0; - WarriorStanceBattle = 1; - WarriorStanceDefensive = 2; - WarriorStanceBerserker = 3; - WarriorStanceGladiator = 4; + WarriorStanceNone = 0; + WarriorStanceBattle = 1; + WarriorStanceDefensive = 2; + WarriorStanceBerserker = 3; + WarriorStanceGladiator = 4; } message Warrior { - message Rotation { - } + message Rotation { + } - message Options { - reserved 2; - reserved "use_recklessness"; + message Options { + reserved 2; + reserved "use_recklessness"; - double starting_rage = 1; - bool stance_snapshot = 6; + double starting_rage = 1; + bool stance_snapshot = 6; - WarriorShout shout = 3; - WarriorStance stance = 7; - } - Options options = 3; + WarriorShout shout = 3; + WarriorStance stance = 7; + } + Options options = 3; } message TankWarrior { - message Rotation { - } + message Rotation { + } - message Options { - double starting_rage = 1; - bool stance_snapshot = 6; + message Options { + double starting_rage = 1; + bool stance_snapshot = 6; - WarriorShout shout = 3; - WarriorStance stance = 7; - } - Options options = 3; + WarriorShout shout = 3; + WarriorStance stance = 7; + } + Options options = 3; } diff --git a/sim/warrior/item_sets_pve.go b/sim/warrior/item_sets_pve.go index 34fb161b9d..755b141692 100644 --- a/sim/warrior/item_sets_pve.go +++ b/sim/warrior/item_sets_pve.go @@ -1,572 +1 @@ package warrior - -import ( - "slices" - "time" - - "github.com/wowsims/sod/sim/core" - "github.com/wowsims/sod/sim/core/proto" - "github.com/wowsims/sod/sim/core/stats" -) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 4 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetBattlegearOfValor = core.NewItemSet(core.ItemSet{ - Name: "Battlegear of Heroism", - Bonuses: map[int32]core.ApplyEffect{ - // +40 Attack Power. - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStats(stats.Stats{ - stats.AttackPower: 40, - stats.RangedAttackPower: 40, - }) - }, - // Chance on melee attack to heal you for 88 to 132 and energize you for 10 Rage - 4: func(agent core.Agent) { - c := agent.GetCharacter() - actionID := core.ActionID{SpellID: 450587} - healthMetrics := c.NewHealthMetrics(core.ActionID{SpellID: 450589}) - rageMetrics := c.NewRageMetrics(core.ActionID{SpellID: 450589}) - - core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ - ActionID: actionID, - Name: "S03 - Warrior Armor Heal Trigger - Battlegear of Valor", - Callback: core.CallbackOnSpellHitDealt, - Outcome: core.OutcomeLanded, - ProcMask: core.ProcMaskMelee, - PPM: 1, - Handler: func(sim *core.Simulation, spell *core.Spell, _ *core.SpellResult) { - c.GainHealth(sim, sim.Roll(88, 132), healthMetrics) - if c.HasRageBar() { - c.AddRage(sim, 10, rageMetrics) - } - }, - }) - }, - // +8 All Resistances. - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddResistances(8) - }, - // +200 Armor. - 8: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Armor, 200) - }, - }, -}) - -var ItemSetUnstoppableMight = core.NewItemSet(core.ItemSet{ - Name: "Unstoppable Might", - Bonuses: map[int32]core.ApplyEffect{ - // After changing stances, your next offensive ability's rage cost is reduced by 10. - 2: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - - var affectedSpells []*core.Spell - tacticianAura := warrior.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 464241}, - Label: "Tactician", - Duration: time.Second * 10, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warrior.Spellbook { - if spell.Cost != nil && spell.Cost.CostType() == core.CostTypeRage && !spell.Flags.Matches(core.SpellFlagHelpful) { - affectedSpells = append(affectedSpells, spell) - } - } - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.Cost.FlatModifier -= 10 - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.Cost.FlatModifier += 10 - } - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if slices.Contains(affectedSpells, spell) { - aura.Deactivate(sim) - } - }, - }) - - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Warrior - Damage 2P Bonus Trigger", - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if slices.Contains(StanceCodes, spell.SpellCode) { - tacticianAura.Activate(sim) - } - }, - })) - }, - // For 15 sec after leaving a stance, you can use abilities requiring that stance as if you were still in that stance. - 4: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - - duration := time.Second * 15 - - battleStanceAura := warrior.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 457706}, - Label: "Echoes of Battle Stance", - Duration: duration, - }) - defStanceAura := warrior.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 457699}, - Label: "Echoes of Defensive Stance", - Duration: duration, - }) - berserkStanceAura := warrior.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 457708}, - Label: "Echoes of Berserker Stance", - Duration: duration, - }) - gladStanceAura := warrior.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 457819}, - Label: "Echoes of Gladiator Stance", - Duration: duration, - }) - - // We're assuming these will be exclusive but TBD - warrior.newStanceOverrideExclusiveEffect(BattleStance, battleStanceAura) - warrior.newStanceOverrideExclusiveEffect(DefensiveStance, defStanceAura) - warrior.newStanceOverrideExclusiveEffect(BerserkerStance, berserkStanceAura) - warrior.newStanceOverrideExclusiveEffect(AnyStance, gladStanceAura) - - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Warrior - Damage 4P Bonus Trigger", - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if slices.Contains(StanceCodes, spell.SpellCode) { - switch warrior.PreviousStance { - case BattleStance: - battleStanceAura.Activate(sim) - case DefensiveStance: - defStanceAura.Activate(sim) - case BerserkerStance: - berserkStanceAura.Activate(sim) - case GladiatorStance: - gladStanceAura.Activate(sim) - } - } - }, - })) - }, - // For the first 10 sec after activating a stance, you can gain an additional benefit: - // Battle Stance/Gladiator Stance: 10% increased damage done. - // Berserker Stance: 10% increased critical strike chance. - // Defensive Stance: 10% reduced Physical damage taken. - 6: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - - duration := time.Second * 15 - - battleAura := warrior.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 457816}, - Label: "Battle Forecast", - Duration: duration, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1.10 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= 1.10 - }, - }) - defenseAura := warrior.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 457814}, - Label: "Defense Forecast", - Duration: duration, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warrior.PseudoStats.DamageTakenMultiplier *= 0.90 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.PseudoStats.DamageTakenMultiplier /= 0.90 - }, - }) - berserkAura := warrior.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 457817}, - Label: "Berserker Forecast", - Duration: duration, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warrior.AddStatDynamic(sim, stats.MeleeCrit, 10*core.CritRatingPerCritChance) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.AddStatDynamic(sim, stats.MeleeCrit, -10*core.CritRatingPerCritChance) - }, - }) - - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Warrior - Damage 6P Bonus Trigger", - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - switch spell.SpellCode { - case SpellCode_WarriorStanceBattle: - battleAura.Activate(sim) - case SpellCode_WarriorStanceGladiator: - battleAura.Activate(sim) - case SpellCode_WarriorStanceDefensive: - defenseAura.Activate(sim) - case SpellCode_WarriorStanceBerserker: - berserkAura.Activate(sim) - } - }, - })) - }, - }, -}) - -var ItemSetImmoveableMight = core.NewItemSet(core.ItemSet{ - Name: "Immoveable Might", - Bonuses: map[int32]core.ApplyEffect{ - // Increases the block value of your shield by 30. - 2: func(agent core.Agent) { - character := agent.GetCharacter() - character.AddStat(stats.BlockValue, 30) - }, - // You gain 1 extra Rage every time you take any damage or deal auto attack damage. - 4: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - warrior.AddDamageDealtRageBonus(1) - warrior.AddDamageTakenRageBonus(1) - }, - // Increases all threat you generate in Defensive Stance by an additional 10% and increases all damage you deal in Gladiator Stance by 4%. - 6: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Warrior - Tank 6P Bonus", - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warrior.defensiveStanceThreatMultiplier *= 1.10 - warrior.gladiatorStanceDamageMultiplier *= 1.04 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.defensiveStanceThreatMultiplier /= 1.10 - warrior.gladiatorStanceDamageMultiplier /= 1.04 - }, - })) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 5 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetUnstoppableWrath = core.NewItemSet(core.ItemSet{ - Name: "Unstoppable Wrath", - Bonuses: map[int32]core.ApplyEffect{ - // Overpower critical strikes refresh the duration of Rend on your target back to its maximum duration. - 2: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warrior - Damage 2P Bonus", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_WarriorOverpower && result.DidCrit() { - if dot := warrior.Rend.Dot(result.Target); dot.IsActive() { - dot.Refresh(sim) - } - } - }, - })) - }, - // Increases the damage of Heroic Strike, Overpower, and Slam by 25% - 4: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warrior - Damage 4P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - warrior.HeroicStrike.DamageMultiplier *= 1.25 - warrior.Overpower.DamageMultiplier *= 1.25 - if warrior.SlamMH != nil { - warrior.SlamMH.DamageMultiplier *= 1.25 - } - if warrior.SlamOH != nil { - warrior.SlamMH.DamageMultiplier *= 1.25 - } - if warrior.QuickStrike != nil { - warrior.QuickStrike.DamageMultiplier *= 1.25 - } - }, - }) - }, - // Your Slam hits reset the remaining cooldown on your Mortal Strike, Bloodthirst, and Shield Slam abilities. - 6: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - var affectedSpells []*WarriorSpell - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warrior - Damage 6P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range []*WarriorSpell{warrior.Bloodthirst, warrior.MortalStrike, warrior.ShieldSlam} { - if spell != nil { - affectedSpells = append(affectedSpells, spell) - } - } - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_WarriorSlamMH && result.Landed() { - for _, spell := range affectedSpells { - spell.CD.Reset() - } - } - }, - })) - }, - }, -}) - -var ItemSetImmoveableWrath = core.NewItemSet(core.ItemSet{ - Name: "Immoveable Wrath", - Bonuses: map[int32]core.ApplyEffect{ - // You gain 10 Rage every time you Parry or one of your attacks is Parried. - 2: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - - actionID := core.ActionID{SpellID: 468066} - rageMetrics := warrior.NewRageMetrics(actionID) - - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warrior - Protection 2P Bonus", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.ProcMask.Matches(core.ProcMaskMelee) && result.DidParry() { - warrior.AddRage(sim, 10, rageMetrics) - } - }, - OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.DidParry() { - warrior.AddRage(sim, 10, rageMetrics) - } - }, - })) - }, - // Revenge also grants you Flurry, increasing your attack speed by 30% for the next 3 swings. - 4: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - - flurryAura := warrior.makeFlurryAura(5) - // The consumption trigger may not exist if the Warrior doesn't talent into Flurry - warrior.makeFlurryConsumptionTrigger(flurryAura) - - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warrior - Protection 4P Bonus", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_WarriorRevenge { - flurryAura.Activate(sim) - flurryAura.SetStacks(sim, 3) - } - }, - })) - }, - // When your target Parries an attack, you instantly Retaliate for 200% weapon damage to that target. - // Retaliate cannot be Dodged, Blocked, or Parried, but can only occur once every 30 sec per target. - 6: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - - retaliate := warrior.RegisterSpell(AnyStance, core.SpellConfig{ - ActionID: core.ActionID{SpellID: 468071}, - SpellSchool: core.SpellSchoolPhysical, - DefenseType: core.DefenseTypeMelee, - ProcMask: core.ProcMaskMeleeMHSpecial, // Retaliate and Retaliation count as normal yellow hits that can proc things - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagNoOnCastComplete | core.SpellFlagPassiveSpell, - - CritDamageBonus: warrior.impale(), - DamageMultiplier: 1, - ThreatMultiplier: 1, - BonusCoefficient: 1, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - spell.CalcAndDealDamage(sim, target, warrior.MHNormalizedWeaponDamage(sim, spell.MeleeAttackPower()), spell.OutcomeMeleeSpecialNoBlockDodgeParry) - }, - }) - - icds := warrior.NewEnemyICDArray(func(u *core.Unit) *core.Cooldown { - return &core.Cooldown{ - Timer: warrior.NewTimer(), - Duration: time.Second * 30, - } - }) - - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warrior - Protection 6P Bonus", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskMelee) || !result.DidParry() { - return - } - - if icd := icds.Get(result.Target); icd.IsReady(sim) { - retaliate.Cast(sim, result.Target) - icd.Use(sim) - } - }, - })) - }, - }, -}) - -var ItemSetVindicatorsBattlegear = core.NewItemSet(core.ItemSet{ - Name: "Vindicator's Battlegear", - Bonuses: map[int32]core.ApplyEffect{ - // Increased Defense +7. - 2: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - warrior.AddStat(stats.Defense, 7) - }, - // Reduces the cooldown on your Shield Slam ability by 2 sec. - 3: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - if !warrior.Talents.ShieldSlam { - return - } - - warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - ZG - Warrior - Gladiator 3P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - warrior.ShieldSlam.CD.Duration -= time.Second * 2 - }, - }) - }, - // Reduces the cooldown on your Bloodrage ability by 30 sec while you are in Gladiator Stance. - 5: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - if !warrior.HasRune(proto.WarriorRune_RuneGladiatorStance) { - return - } - - warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warrior - Protection 6P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - idx := slices.IndexFunc(warrior.GladiatorStanceAura.ExclusiveEffects, func(ee *core.ExclusiveEffect) bool { - return ee.Category.Name == stanceEffectCategory - }) - ee := warrior.GladiatorStanceAura.ExclusiveEffects[idx] - oldOnGain := ee.OnGain - ee.OnGain = func(ee *core.ExclusiveEffect, sim *core.Simulation) { - oldOnGain(ee, sim) - warrior.Bloodrage.CD.Duration -= time.Second * 30 - } - - oldOnExpire := ee.OnExpire - ee.OnExpire = func(ee *core.ExclusiveEffect, sim *core.Simulation) { - oldOnExpire(ee, sim) - warrior.Bloodrage.CD.Duration += time.Second * 30 - } - }, - }) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 6 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetConquerorsAdvance = core.NewItemSet(core.ItemSet{ - Name: "Conqueror's Advance", - Bonuses: map[int32]core.ApplyEffect{ - // Reduces the cooldown on your Death Wish by 50%. - 2: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - if !warrior.Talents.DeathWish { - return - } - - warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Warrior - Damage 2P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - warrior.DeathWish.CD.Duration /= 2 - }, - }) - }, - // You deal 15% increased damage while any nearby enemy is afflicted with both your Rend and your Deep Wounds. - 4: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - if warrior.Talents.DeepWounds == 0 { - return - } - - buffAura := warrior.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 1214166}, - Label: "Bloodythirsty", - Duration: time.Second * 3, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warrior.PseudoStats.DamageDealtMultiplier *= 1.15 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warrior.PseudoStats.DamageDealtMultiplier /= 1.15 - }, - }) - - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Warrior - Damage 4P Bonus", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if (spell.SpellCode == SpellCode_WarriorDeepWounds && warrior.Rend.Dot(result.Target).IsActive()) || - (spell.SpellCode == SpellCode_WarriorRend && warrior.DeepWounds.Dot(result.Target).IsActive()) { - buffAura.Activate(sim) - } - }, - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if (spell.SpellCode == SpellCode_WarriorDeepWounds && warrior.Rend.Dot(result.Target).IsActive()) || - (spell.SpellCode == SpellCode_WarriorRend && warrior.DeepWounds.Dot(result.Target).IsActive()) { - buffAura.Activate(sim) - } - }, - })) - }, - }, -}) - -var ItemSetConquerorsBulwark = core.NewItemSet(core.ItemSet{ - Name: "Conqueror's Bulwark", - Bonuses: map[int32]core.ApplyEffect{ - // Reduces the cooldown on Thunder Clap by 100%. - 2: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - - warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Warrior - Tank 2P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - warrior.ThunderClap.CD.Duration = 0 - }, - }) - }, - // Your Shield Slam deals 100% increased threat and its cooldown is reset if it is Dodged, Parried, or Blocked. - 4: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - if !warrior.Talents.ShieldSlam { - return - } - - core.MakePermanent(warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Warrior - Tank 4P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - warrior.ShieldSlam.ThreatMultiplier *= 2 - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_WarriorShieldSlam && result.Outcome.Matches(core.OutcomeDodge|core.OutcomeParry|core.OutcomeBlock) { - spell.CD.Reset() - } - }, - })) - }, - }, -}) - -var ItemSetBattlegearOfUnyieldingStrength = core.NewItemSet(core.ItemSet{ - Name: "Battlegear of Unyielding Strength", - Bonuses: map[int32]core.ApplyEffect{ - // Reduces the cooldown on Shockwave by 50%. - 3: func(agent core.Agent) { - warrior := agent.(WarriorAgent).GetWarrior() - if !warrior.HasRune(proto.WarriorRune_RuneShockwave) { - return - } - - warrior.RegisterAura(core.Aura{ - Label: "S03 - Item - RAQ - Warrior - Tank 3P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - warrior.Shockwave.CD.Duration /= 2 - }, - }) - }, - }, -}) diff --git a/sim/warrior/item_sets_pve_phase_4.go b/sim/warrior/item_sets_pve_phase_4.go new file mode 100644 index 0000000000..e6803cf0e5 --- /dev/null +++ b/sim/warrior/item_sets_pve_phase_4.go @@ -0,0 +1,287 @@ +package warrior + +import ( + "slices" + "time" + + "github.com/wowsims/sod/sim/core" + "github.com/wowsims/sod/sim/core/stats" +) + +var ItemSetBattlegearOfValor = core.NewItemSet(core.ItemSet{ + Name: "Battlegear of Heroism", + Bonuses: map[int32]core.ApplyEffect{ + // +40 Attack Power. + 2: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStats(stats.Stats{ + stats.AttackPower: 40, + stats.RangedAttackPower: 40, + }) + }, + // Chance on melee attack to heal you for 88 to 132 and energize you for 10 Rage + 4: func(agent core.Agent) { + c := agent.GetCharacter() + actionID := core.ActionID{SpellID: 450587} + healthMetrics := c.NewHealthMetrics(core.ActionID{SpellID: 450589}) + rageMetrics := c.NewRageMetrics(core.ActionID{SpellID: 450589}) + + core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ + ActionID: actionID, + Name: "S03 - Warrior Armor Heal Trigger - Battlegear of Valor", + Callback: core.CallbackOnSpellHitDealt, + Outcome: core.OutcomeLanded, + ProcMask: core.ProcMaskMelee, + PPM: 1, + Handler: func(sim *core.Simulation, spell *core.Spell, _ *core.SpellResult) { + c.GainHealth(sim, sim.Roll(88, 132), healthMetrics) + if c.HasRageBar() { + c.AddRage(sim, 10, rageMetrics) + } + }, + }) + }, + // +8 All Resistances. + 6: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddResistances(8) + }, + // +200 Armor. + 8: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.Armor, 200) + }, + }, +}) + +var ItemSetUnstoppableMight = core.NewItemSet(core.ItemSet{ + Name: "Unstoppable Might", + Bonuses: map[int32]core.ApplyEffect{ + 2: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT1Damage2PBonus() + }, + 4: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT1Damage4PBonus() + }, + 6: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT1Damage6PBonus() + }, + }, +}) + +// After changing stances, your next offensive ability's rage cost is reduced by 10. +func (warrior *Warrior) applyT1Damage2PBonus() { + label := "S03 - Item - T1 - Warrior - Damage 2P Bonus" + if warrior.HasAura(label) { + return + } + + var affectedSpells []*core.Spell + tacticianAura := warrior.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 464241}, + Label: "Tactician", + Duration: time.Second * 10, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range warrior.Spellbook { + if spell.Cost != nil && spell.Cost.CostType() == core.CostTypeRage && !spell.Flags.Matches(core.SpellFlagHelpful) { + affectedSpells = append(affectedSpells, spell) + } + } + }, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range affectedSpells { + spell.Cost.FlatModifier -= 10 + } + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range affectedSpells { + spell.Cost.FlatModifier += 10 + } + }, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if slices.Contains(affectedSpells, spell) { + aura.Deactivate(sim) + } + }, + }) + + core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, + OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { + if slices.Contains(StanceCodes, spell.SpellCode) { + tacticianAura.Activate(sim) + } + }, + })) +} + +// For 15 sec after leaving a stance, you can use abilities requiring that stance as if you were still in that stance. +func (warrior *Warrior) applyT1Damage4PBonus() { + label := "S03 - Item - T1 - Warrior - Damage 4P Bonus" + if warrior.HasAura(label) { + return + } + + duration := time.Second * 15 + + battleStanceAura := warrior.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 457706}, + Label: "Echoes of Battle Stance", + Duration: duration, + }) + defStanceAura := warrior.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 457699}, + Label: "Echoes of Defensive Stance", + Duration: duration, + }) + berserkStanceAura := warrior.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 457708}, + Label: "Echoes of Berserker Stance", + Duration: duration, + }) + gladStanceAura := warrior.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 457819}, + Label: "Echoes of Gladiator Stance", + Duration: duration, + }) + + // We're assuming these will be exclusive but TBD + warrior.newStanceOverrideExclusiveEffect(BattleStance, battleStanceAura) + warrior.newStanceOverrideExclusiveEffect(DefensiveStance, defStanceAura) + warrior.newStanceOverrideExclusiveEffect(BerserkerStance, berserkStanceAura) + warrior.newStanceOverrideExclusiveEffect(AnyStance, gladStanceAura) + + core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, + OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { + if slices.Contains(StanceCodes, spell.SpellCode) { + switch warrior.PreviousStance { + case BattleStance: + battleStanceAura.Activate(sim) + case DefensiveStance: + defStanceAura.Activate(sim) + case BerserkerStance: + berserkStanceAura.Activate(sim) + case GladiatorStance: + gladStanceAura.Activate(sim) + } + } + }, + })) +} + +// For the first 10 sec after activating a stance, you can gain an additional benefit: +// Battle Stance/Gladiator Stance: 10% increased damage done. +// Berserker Stance: 10% increased critical strike chance. +// Defensive Stance: 10% reduced Physical damage taken. +func (warrior *Warrior) applyT1Damage6PBonus() { + label := "S03 - Item - T1 - Warrior - Damage 6P Bonus" + if warrior.HasAura(label) { + return + } + + duration := time.Second * 15 + + battleAura := warrior.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 457816}, + Label: "Battle Forecast", + Duration: duration, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1.10 + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + warrior.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= 1.10 + }, + }) + defenseAura := warrior.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 457814}, + Label: "Defense Forecast", + Duration: duration, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + warrior.PseudoStats.DamageTakenMultiplier *= 0.90 + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + warrior.PseudoStats.DamageTakenMultiplier /= 0.90 + }, + }) + berserkAura := warrior.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 457817}, + Label: "Berserker Forecast", + Duration: duration, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + warrior.AddStatDynamic(sim, stats.MeleeCrit, 10*core.CritRatingPerCritChance) + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + warrior.AddStatDynamic(sim, stats.MeleeCrit, -10*core.CritRatingPerCritChance) + }, + }) + + core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, + OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { + switch spell.SpellCode { + case SpellCode_WarriorStanceBattle: + battleAura.Activate(sim) + case SpellCode_WarriorStanceGladiator: + battleAura.Activate(sim) + case SpellCode_WarriorStanceDefensive: + defenseAura.Activate(sim) + case SpellCode_WarriorStanceBerserker: + berserkAura.Activate(sim) + } + }, + })) +} + +var ItemSetImmoveableMight = core.NewItemSet(core.ItemSet{ + Name: "Immoveable Might", + Bonuses: map[int32]core.ApplyEffect{ + // Increases the block value of your shield by 30. + 2: func(agent core.Agent) { + character := agent.GetCharacter() + character.AddStat(stats.BlockValue, 30) + }, + 4: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT1Tank4PBonus() + }, + 6: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT1Tank6PBonus() + }, + }, +}) + +// You gain 1 extra Rage every time you take any damage or deal auto attack damage. +func (warrior *Warrior) applyT1Tank4PBonus() { + label := "S03 - Item - T1 - Warrior - Tank 4P Bonus" + if warrior.HasAura(label) { + return + } + + warrior.RegisterAura(core.Aura{ + Label: label, + }) + + warrior.AddDamageDealtRageBonus(1) + warrior.AddDamageTakenRageBonus(1) +} + +// Increases all threat you generate in Defensive Stance by an additional 10% and increases all damage you deal in Gladiator Stance by 4%. +func (warrior *Warrior) applyT1Tank6PBonus() { + label := "S03 - Item - T1 - Warrior - Tank 6P Bonus" + if warrior.HasAura(label) { + return + } + + warrior.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + warrior.defensiveStanceThreatMultiplier *= 1.10 + warrior.gladiatorStanceDamageMultiplier *= 1.04 + }, + }) +} diff --git a/sim/warrior/item_sets_pve_phase_5.go b/sim/warrior/item_sets_pve_phase_5.go new file mode 100644 index 0000000000..c1a5b86461 --- /dev/null +++ b/sim/warrior/item_sets_pve_phase_5.go @@ -0,0 +1,281 @@ +package warrior + +import ( + "slices" + "time" + + "github.com/wowsims/sod/sim/core" + "github.com/wowsims/sod/sim/core/proto" + "github.com/wowsims/sod/sim/core/stats" +) + +var ItemSetUnstoppableWrath = core.NewItemSet(core.ItemSet{ + Name: "Unstoppable Wrath", + Bonuses: map[int32]core.ApplyEffect{ + 2: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT2Damage2PBonus() + }, + 4: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT2Damage4PBonus() + }, + 6: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT2Damage6PBonus() + }, + }, +}) + +// Overpower critical strikes refresh the duration of Rend on your target back to its maximum duration. +func (warrior *Warrior) applyT2Damage2PBonus() { + label := "S03 - Item - T2 - Warrior - Damage 2P Bonus" + if warrior.HasAura(label) { + return + } + + core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if spell.SpellCode == SpellCode_WarriorOverpower && result.DidCrit() { + if dot := warrior.Rend.Dot(result.Target); dot.IsActive() { + dot.Refresh(sim) + } + } + }, + })) +} + +// Increases the damage of Heroic Strike, Overpower, and Slam by 25% +func (warrior *Warrior) applyT2Damage4PBonus() { + label := "S03 - Item - T2 - Warrior - Damage 4P Bonus" + if warrior.HasAura(label) { + return + } + + warrior.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + warrior.HeroicStrike.DamageMultiplier *= 1.25 + warrior.Overpower.DamageMultiplier *= 1.25 + if warrior.SlamMH != nil { + warrior.SlamMH.DamageMultiplier *= 1.25 + } + if warrior.SlamOH != nil { + warrior.SlamMH.DamageMultiplier *= 1.25 + } + if warrior.QuickStrike != nil { + warrior.QuickStrike.DamageMultiplier *= 1.25 + } + }, + }) +} + +// Your Slam hits reset the remaining cooldown on your Mortal Strike, Bloodthirst, and Shield Slam abilities. +func (warrior *Warrior) applyT2Damage6PBonus() { + label := "S03 - Item - T2 - Warrior - Damage 6P Bonus" + if warrior.HasAura(label) { + return + } + + var affectedSpells []*WarriorSpell + core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range []*WarriorSpell{warrior.Bloodthirst, warrior.MortalStrike, warrior.ShieldSlam} { + if spell != nil { + affectedSpells = append(affectedSpells, spell) + } + } + }, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if spell.SpellCode == SpellCode_WarriorSlamMH && result.Landed() { + for _, spell := range affectedSpells { + spell.CD.Reset() + } + } + }, + })) +} + +var ItemSetImmoveableWrath = core.NewItemSet(core.ItemSet{ + Name: "Immoveable Wrath", + Bonuses: map[int32]core.ApplyEffect{ + 2: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT2Protection2PBonus() + }, + 4: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT2Protection4PBonus() + }, + 6: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyT2Protection6PBonus() + }, + }, +}) + +// You gain 10 Rage every time you Parry or one of your attacks is Parried. +func (warrior *Warrior) applyT2Protection2PBonus() { + label := "S03 - Item - T2 - Warrior - Protection 2P Bonus" + if warrior.HasAura(label) { + return + } + + rageMetrics := warrior.NewRageMetrics(core.ActionID{SpellID: 468066}) + + core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if spell.ProcMask.Matches(core.ProcMaskMelee) && result.DidParry() { + warrior.AddRage(sim, 10, rageMetrics) + } + }, + OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if result.DidParry() { + warrior.AddRage(sim, 10, rageMetrics) + } + }, + })) +} + +// Revenge also grants you Flurry, increasing your attack speed by 30% for the next 3 swings. +func (warrior *Warrior) applyT2Protection4PBonus() { + label := "S03 - Item - T2 - Warrior - Protection 4P Bonus" + if warrior.HasAura(label) { + return + } + + flurryAura := warrior.makeFlurryAura(5) + // The consumption trigger may not exist if the Warrior doesn't talent into Flurry + warrior.makeFlurryConsumptionTrigger(flurryAura) + + core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if spell.SpellCode == SpellCode_WarriorRevenge { + flurryAura.Activate(sim) + flurryAura.SetStacks(sim, 3) + } + }, + })) +} + +// When your target Parries an attack, you instantly Retaliate for 200% weapon damage to that target. +// Retaliate cannot be Dodged, Blocked, or Parried, but can only occur once every 30 sec per target. +func (warrior *Warrior) applyT2Protection6PBonus() { + label := "S03 - Item - T2 - Warrior - Protection 6P Bonus" + if warrior.HasAura(label) { + return + } + + retaliate := warrior.RegisterSpell(AnyStance, core.SpellConfig{ + ActionID: core.ActionID{SpellID: 468071}, + SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, + ProcMask: core.ProcMaskMeleeMHSpecial, // Retaliate and Retaliation count as normal yellow hits that can proc things + Flags: core.SpellFlagMeleeMetrics | core.SpellFlagNoOnCastComplete | core.SpellFlagPassiveSpell, + + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, + ThreatMultiplier: 1, + BonusCoefficient: 1, + + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + spell.CalcAndDealDamage(sim, target, warrior.MHNormalizedWeaponDamage(sim, spell.MeleeAttackPower()), spell.OutcomeMeleeSpecialNoBlockDodgeParry) + }, + }) + + icds := warrior.NewEnemyICDArray(func(u *core.Unit) *core.Cooldown { + return &core.Cooldown{ + Timer: warrior.NewTimer(), + Duration: time.Second * 30, + } + }) + + core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if !spell.ProcMask.Matches(core.ProcMaskMelee) || !result.DidParry() { + return + } + + if icd := icds.Get(result.Target); icd.IsReady(sim) { + retaliate.Cast(sim, result.Target) + icd.Use(sim) + } + }, + })) +} + +var ItemSetVindicatorsBattlegear = core.NewItemSet(core.ItemSet{ + Name: "Vindicator's Battlegear", + Bonuses: map[int32]core.ApplyEffect{ + // Increased Defense +7. + 2: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.AddStat(stats.Defense, 7) + }, + 3: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyZGGladiator3PBonus() + }, + 5: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyZGGladiator5PBonus() + }, + }, +}) + +// Reduces the cooldown on your Shield Slam ability by 2 sec. +func (warrior *Warrior) applyZGGladiator3PBonus() { + if !warrior.Talents.ShieldSlam { + return + } + + label := "S03 - Item - ZG - Warrior - Gladiator 3P Bonus" + if warrior.HasAura(label) { + return + } + + warrior.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + warrior.ShieldSlam.CD.Duration -= time.Second * 2 + }, + }) +} + +// Reduces the cooldown on your Bloodrage ability by 30 sec while you are in Gladiator Stance. +func (warrior *Warrior) applyZGGladiator5PBonus() { + if !warrior.HasRune(proto.WarriorRune_RuneGladiatorStance) { + return + } + + label := "S03 - Item - T1 - Warrior - Gladiator 5P Bonus" + if warrior.HasAura(label) { + return + } + + warrior.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + idx := slices.IndexFunc(warrior.GladiatorStanceAura.ExclusiveEffects, func(ee *core.ExclusiveEffect) bool { + return ee.Category.Name == stanceEffectCategory + }) + ee := warrior.GladiatorStanceAura.ExclusiveEffects[idx] + oldOnGain := ee.OnGain + ee.OnGain = func(ee *core.ExclusiveEffect, sim *core.Simulation) { + oldOnGain(ee, sim) + warrior.Bloodrage.CD.Duration -= time.Second * 30 + } + + oldOnExpire := ee.OnExpire + ee.OnExpire = func(ee *core.ExclusiveEffect, sim *core.Simulation) { + oldOnExpire(ee, sim) + warrior.Bloodrage.CD.Duration += time.Second * 30 + } + }, + }) +} diff --git a/sim/warrior/item_sets_pve_phase_6.go b/sim/warrior/item_sets_pve_phase_6.go new file mode 100644 index 0000000000..fbc920fb6c --- /dev/null +++ b/sim/warrior/item_sets_pve_phase_6.go @@ -0,0 +1,163 @@ +package warrior + +import ( + "time" + + "github.com/wowsims/sod/sim/core" + "github.com/wowsims/sod/sim/core/proto" +) + +var ItemSetConquerorsAdvance = core.NewItemSet(core.ItemSet{ + Name: "Conqueror's Advance", + Bonuses: map[int32]core.ApplyEffect{ + 2: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyTAQDamage2PBonus() + }, + 4: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyTAQDamage4PBonus() + }, + }, +}) + +// Reduces the cooldown on your Death Wish by 50%. +func (warrior *Warrior) applyTAQDamage2PBonus() { + if !warrior.Talents.DeathWish { + return + } + + label := "S03 - Item - TAQ - Warrior - Damage 2P Bonus" + if warrior.HasAura(label) { + return + } + + warrior.RegisterAura(core.Aura{ + Label: "S03 - Item - TAQ - Warrior - Damage 2P Bonus", + OnInit: func(aura *core.Aura, sim *core.Simulation) { + warrior.DeathWish.CD.Duration /= 2 + }, + }) +} + +// You deal 15% increased damage while any nearby enemy is afflicted with both your Rend and your Deep Wounds. +func (warrior *Warrior) applyTAQDamage4PBonus() { + if warrior.Talents.DeepWounds == 0 { + return + } + + label := "S03 - Item - TAQ - Warrior - Damage 4P Bonus" + if warrior.HasAura(label) { + return + } + + buffAura := warrior.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 1214166}, + Label: "Bloodythirsty", + Duration: time.Second * 3, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + warrior.PseudoStats.DamageDealtMultiplier *= 1.15 + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + warrior.PseudoStats.DamageDealtMultiplier /= 1.15 + }, + }) + + core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if (spell.SpellCode == SpellCode_WarriorDeepWounds && warrior.Rend.Dot(result.Target).IsActive()) || + (spell.SpellCode == SpellCode_WarriorRend && warrior.DeepWounds.Dot(result.Target).IsActive()) { + buffAura.Activate(sim) + } + }, + OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if (spell.SpellCode == SpellCode_WarriorDeepWounds && warrior.Rend.Dot(result.Target).IsActive()) || + (spell.SpellCode == SpellCode_WarriorRend && warrior.DeepWounds.Dot(result.Target).IsActive()) { + buffAura.Activate(sim) + } + }, + })) +} + +var ItemSetConquerorsBulwark = core.NewItemSet(core.ItemSet{ + Name: "Conqueror's Bulwark", + Bonuses: map[int32]core.ApplyEffect{ + 2: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyTAQTank2PBonus() + }, + 4: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyTAQTank4PBonus() + }, + }, +}) + +// Reduces the cooldown on Thunder Clap by 100%. +func (warrior *Warrior) applyTAQTank2PBonus() { + label := "S03 - Item - TAQ - Warrior - Tank 2P Bonus" + if warrior.HasAura(label) { + return + } + + warrior.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + warrior.ThunderClap.CD.Duration = 0 + }, + }) +} + +// Your Shield Slam deals 100% increased threat and its cooldown is reset if it is Dodged, Parried, or Blocked. +func (warrior *Warrior) applyTAQTank4PBonus() { + if !warrior.Talents.ShieldSlam { + return + } + + label := "S03 - Item - TAQ - Warrior - Tank 4P Bonus" + if warrior.HasAura(label) { + return + } + + core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + warrior.ShieldSlam.ThreatMultiplier *= 2 + }, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if spell.SpellCode == SpellCode_WarriorShieldSlam && result.Outcome.Matches(core.OutcomeDodge|core.OutcomeParry|core.OutcomeBlock) { + spell.CD.Reset() + } + }, + })) +} + +var ItemSetBattlegearOfUnyieldingStrength = core.NewItemSet(core.ItemSet{ + Name: "Battlegear of Unyielding Strength", + Bonuses: map[int32]core.ApplyEffect{ + 3: func(agent core.Agent) { + warrior := agent.(WarriorAgent).GetWarrior() + warrior.applyRAQTank3PBonus() + }, + }, +}) + +// Reduces the cooldown on Shockwave by 50%. +func (warrior *Warrior) applyRAQTank3PBonus() { + if !warrior.HasRune(proto.WarriorRune_RuneShockwave) { + return + } + + label := "S03 - Item - RAQ - Warrior - Tank 3P Bonus" + if warrior.HasAura(label) { + return + } + + warrior.RegisterAura(core.Aura{ + Label: "S03 - Item - RAQ - Warrior - Tank 3P Bonus", + OnInit: func(aura *core.Aura, sim *core.Simulation) { + warrior.Shockwave.CD.Duration /= 2 + }, + }) +} diff --git a/sim/warrior/runes.go b/sim/warrior/runes.go index 8b5d1f7272..5b5cff725b 100644 --- a/sim/warrior/runes.go +++ b/sim/warrior/runes.go @@ -16,6 +16,9 @@ func (warrior *Warrior) ApplyRunes() { warrior.applyShieldMastery() warrior.applyTasteForBlood() + // Shoulders + warrior.applyShoulderRuneEffect() + // Cloak warrior.applySuddenDeath() warrior.applyFreshMeat() @@ -48,6 +51,56 @@ func (warrior *Warrior) ApplyRunes() { // Gladiator implemented on stances.go } +func (warrior *Warrior) applyShoulderRuneEffect() { + if warrior.Equipment.Shoulders().Rune == int32(proto.WarriorRune_WarriorRuneNone) { + return + } + + switch warrior.Equipment.Shoulders().Rune { + // Damage + case int32(proto.WarriorRune_RuneShouldersTactician): + warrior.applyT1Damage2PBonus() + case int32(proto.WarriorRune_RuneShouldersWarVeteran): + warrior.applyT1Damage4PBonus() + case int32(proto.WarriorRune_RuneShouldersBattleForecaster): + warrior.applyT1Damage6PBonus() + case int32(proto.WarriorRune_RuneShouldersBloodseeker): + warrior.applyT2Damage2PBonus() + case int32(proto.WarriorRune_RuneShouldersTitan): + warrior.applyT2Damage4PBonus() + case int32(proto.WarriorRune_RuneShouldersDestroyer): + warrior.applyT2Damage6PBonus() + case int32(proto.WarriorRune_RuneShouldersDeathbound): + warrior.applyTAQDamage2PBonus() + case int32(proto.WarriorRune_RuneShouldersSanguinist): + warrior.applyTAQDamage4PBonus() + + // Tank + case int32(proto.WarriorRune_RuneShouldersSavage): + warrior.applyT1Tank4PBonus() + case int32(proto.WarriorRune_RuneShouldersEnmity): + warrior.applyT1Tank6PBonus() + case int32(proto.WarriorRune_RuneShouldersDeflective): + warrior.applyT2Protection2PBonus() + case int32(proto.WarriorRune_RuneShouldersRevenger): + warrior.applyT2Protection4PBonus() + case int32(proto.WarriorRune_RuneShouldersIncessant): + warrior.applyT2Protection6PBonus() + case int32(proto.WarriorRune_RuneShouldersThunderbringer): + warrior.applyTAQTank2PBonus() + case int32(proto.WarriorRune_RuneShouldersSentinel): + warrior.applyTAQTank4PBonus() + case int32(proto.WarriorRune_RuneShouldersAftershock): + warrior.applyRAQTank3PBonus() + + // Gladiator + case int32(proto.WarriorRune_RuneShouldersSouthpaw): + warrior.applyZGGladiator3PBonus() + case int32(proto.WarriorRune_RuneShouldersGladiator): + warrior.applyZGGladiator5PBonus() + } +} + func (warrior *Warrior) applyVigilance() { if !warrior.HasRune(proto.WarriorRune_RuneVigilance) { return diff --git a/sim/warrior/talents.go b/sim/warrior/talents.go index a9131ef64f..bf121c2d9b 100644 --- a/sim/warrior/talents.go +++ b/sim/warrior/talents.go @@ -333,9 +333,14 @@ func (warrior *Warrior) makeFlurryAura(points int32) *core.Aura { spellID := []int32{12319, 12971, 12972, 12973, 12974}[points-1] attackSpeed := []float64{1.1, 1.15, 1.2, 1.25, 1.3}[points-1] + label := fmt.Sprintf("Flurry Proc (%d)", spellID) + + if aura := warrior.GetAura(label); aura != nil { + return aura + } aura := warrior.GetOrRegisterAura(core.Aura{ - Label: fmt.Sprintf("Flurry Proc (%d)", spellID), + Label: label, ActionID: core.ActionID{SpellID: spellID}, Duration: core.NeverExpires, MaxStacks: 3, @@ -357,12 +362,18 @@ func (warrior *Warrior) makeFlurryAura(points int32) *core.Aura { // With the Protection T2 4pc it's possible to have 2 different Flurry auras if using less than 5/5 points in Flurry. // The two different buffs don't stack whatsoever. Instead the stronger aura takes precedence and each one is only refreshed by the corresponding triggers. func (warrior *Warrior) makeFlurryConsumptionTrigger(flurryAura *core.Aura) *core.Aura { + label := fmt.Sprintf("Flurry Consume Trigger - %d", flurryAura.ActionID.SpellID) + if aura := warrior.GetAura(label); aura != nil { + return aura + } + icd := core.Cooldown{ Timer: warrior.NewTimer(), Duration: time.Millisecond * 500, } - return core.MakePermanent(warrior.GetOrRegisterAura(core.Aura{ - Label: fmt.Sprintf("Flurry Consume Trigger - %d", flurryAura.ActionID.SpellID), + + return core.MakePermanent(warrior.RegisterAura(core.Aura{ + Label: label, OnSpellHitDealt: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { // Remove a stack. if flurryAura.IsActive() && spell.ProcMask.Matches(core.ProcMaskMeleeWhiteHit) && icd.IsReady(sim) { diff --git a/tools/database/rune_overrides.go b/tools/database/rune_overrides.go index 622d0f8282..ac519d9ca7 100644 --- a/tools/database/rune_overrides.go +++ b/tools/database/rune_overrides.go @@ -49,8 +49,9 @@ var RuneOverrides = []*proto.UIRune{ // Classes that have shoulder rune implementations completed to not confuse users var ShoulderRuneClassAllowlist = map[proto.Class]bool{ - proto.Class_ClassDruid: true, - proto.Class_ClassMage: true, - proto.Class_ClassPriest: true, - proto.Class_ClassShaman: true, + proto.Class_ClassDruid: true, + proto.Class_ClassMage: true, + proto.Class_ClassPriest: true, + proto.Class_ClassShaman: true, + proto.Class_ClassWarrior: true, } diff --git a/tools/scrape_shoulder_runes.py b/tools/scrape_shoulder_runes.py index 55c3f7c3f3..52dfef1dd4 100644 --- a/tools/scrape_shoulder_runes.py +++ b/tools/scrape_shoulder_runes.py @@ -82,7 +82,8 @@ def get_tooltips_response(id): mismatchedIds = { "1219819": 1220096, # This sole spell is missing a related spell to reference - "1220354": 1220355 + "1220354": 1220355, + "1219956": 1219957 } for id in item_ids: