diff --git a/assets/database/db.bin b/assets/database/db.bin index 6cad37e21b..c2233a1a0e 100644 Binary files a/assets/database/db.bin and b/assets/database/db.bin differ diff --git a/assets/database/db.json b/assets/database/db.json index ac13bd9dae..8dd66a7222 100644 --- a/assets/database/db.json +++ b/assets/database/db.json @@ -11389,6 +11389,7 @@ {"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":1219972,"name":"Soul of the Pristine Blocker","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, {"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]}, @@ -11437,6 +11438,24 @@ {"id":1220064,"name":"Soul of the Umbral Blade","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[8]}, {"id":1220066,"name":"Soul of the Ritualist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[8]}, {"id":1220068,"name":"Soul of the Pain Spreader","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[8]}, +{"id":1220070,"name":"Soul of the Misleader","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220072,"name":"Soul of the Preyseeker","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220074,"name":"Soul of the Sharpshooter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220076,"name":"Soul of the Hazard Harrier","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220078,"name":"Soul of the Alternator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220080,"name":"Soul of the Toxinologist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220082,"name":"Soul of the Bounty Hunter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220084,"name":"Soul of the Trick Shooter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220086,"name":"Soul of the Beast Tender","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220088,"name":"Soul of the Hound Master","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220090,"name":"Soul of the Alpha Tamer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220092,"name":"Soul of the Huntsman","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220094,"name":"Soul of the Retaliator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220096,"name":"Soul of Echoes","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220098,"name":"Soul of the Lethal Lasher","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220100,"name":"Soul of the Kineticist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220102,"name":"Soul of the Strategist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220104,"name":"Soul of the Deadly Striker","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, {"id":1220106,"name":"Soul of the Hastened Healer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[5]}, {"id":1220108,"name":"Soul of the Refined","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[5]}, {"id":1220110,"name":"Soul of the Celebrant","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[5]}, @@ -11474,6 +11493,31 @@ {"id":1220174,"name":"Soul of the Pyromaniac","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[3]}, {"id":1220176,"name":"Soul of the Igniter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[3]}, {"id":1220178,"name":"Soul of the Torcher","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[3]}, +{"id":1220182,"name":"Soul of the Lightwarden","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220184,"name":"Soul of the Radiant Defender","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220186,"name":"Soul of the Shieldbearer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220188,"name":"Soul of the Bastion","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220190,"name":"Soul of the Reckoner","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220192,"name":"Soul of the Ironclad","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220194,"name":"Soul of the Guardian","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220196,"name":"Soul of the Peacekeeper","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220198,"name":"Soul of the Refined","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220200,"name":"Soul of the Exemplar","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220202,"name":"Soul of the Inquisitor","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220204,"name":"Soul of the Sovereign","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220206,"name":"Soul of the Dominus","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220208,"name":"Soul of the Vindicator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220210,"name":"Soul of the Altruist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220212,"name":"Soul of the Arbiter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220214,"name":"Soul of the Sealbearer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220216,"name":"Soul of the Justicar","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220218,"name":"Soul of the Judicator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220220,"name":"Soul of the Ascendant","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220222,"name":"Soul of the Retributor","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220224,"name":"Soul of the Excommunicator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220226,"name":"Soul of the Lightbringer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220228,"name":"Soul of the Exile","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220230,"name":"Soul of the Templar","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, {"id":1220232,"name":"Soul of the Windwalker","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, {"id":1220234,"name":"Soul of the Shield Master","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, {"id":1220236,"name":"Soul of the Totemic Protector","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, @@ -11508,6 +11552,7 @@ {"id":1220295,"name":"Soul of the Ancestral Warden","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, {"id":1220297,"name":"Soul of the Corrupt","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, {"id":1220299,"name":"Soul of the Gentle Paw","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[1]}, +{"id":1220301,"name":"Soul of the Ferocious","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[1]}, {"id":1220303,"name":"Soul of the Shifter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[1]}, {"id":1220305,"name":"Soul of the Territorial","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[1]}, {"id":1220307,"name":"Soul of the Beast","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[1]}, diff --git a/assets/database/leftover_db.bin b/assets/database/leftover_db.bin index a8d3de4311..5bca59f168 100644 Binary files a/assets/database/leftover_db.bin and b/assets/database/leftover_db.bin differ diff --git a/assets/database/leftover_db.json b/assets/database/leftover_db.json index 2c712cde96..d488b598e1 100644 --- a/assets/database/leftover_db.json +++ b/assets/database/leftover_db.json @@ -1488,8 +1488,8 @@ {"effectId":63,"spellId":13538,"name":"Enchant Chest - Lesser Absorption","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":66,"spellId":7457,"name":"Enchant Bracer - Minor Stamina","type":6,"stats":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":66,"spellId":7863,"name":"Enchant Boots - Minor Stamina","type":10,"stats":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, -{"effectId":241,"spellId":13503,"name":"Enchant Weapon - Lesser Striking","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":241,"spellId":7745,"name":"Enchant 2H Weapon - Minor Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, +{"effectId":241,"spellId":13503,"name":"Enchant Weapon - Lesser Striking","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":242,"spellId":7748,"name":"Enchant Chest - Lesser Health","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":243,"spellId":7766,"name":"Enchant Bracer - Minor Spirit","type":6,"stats":[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":246,"spellId":7776,"name":"Enchant Chest - Lesser Mana","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, @@ -1944,6 +1944,7 @@ {"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":1219972,"name":"Soul of the Pristine Blocker","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, {"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]}, @@ -1992,6 +1993,24 @@ {"id":1220064,"name":"Soul of the Umbral Blade","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[8]}, {"id":1220066,"name":"Soul of the Ritualist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[8]}, {"id":1220068,"name":"Soul of the Pain Spreader","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[8]}, +{"id":1220070,"name":"Soul of the Misleader","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220072,"name":"Soul of the Preyseeker","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220074,"name":"Soul of the Sharpshooter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220076,"name":"Soul of the Hazard Harrier","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220078,"name":"Soul of the Alternator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220080,"name":"Soul of the Toxinologist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220082,"name":"Soul of the Bounty Hunter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220084,"name":"Soul of the Trick Shooter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220086,"name":"Soul of the Beast Tender","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220088,"name":"Soul of the Hound Master","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220090,"name":"Soul of the Alpha Tamer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220092,"name":"Soul of the Huntsman","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220094,"name":"Soul of the Retaliator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220096,"name":"Soul of Echoes","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220098,"name":"Soul of the Lethal Lasher","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220100,"name":"Soul of the Kineticist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220102,"name":"Soul of the Strategist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, +{"id":1220104,"name":"Soul of the Deadly Striker","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[2]}, {"id":1220106,"name":"Soul of the Hastened Healer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[5]}, {"id":1220108,"name":"Soul of the Refined","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[5]}, {"id":1220110,"name":"Soul of the Celebrant","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[5]}, @@ -2029,6 +2048,31 @@ {"id":1220174,"name":"Soul of the Pyromaniac","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[3]}, {"id":1220176,"name":"Soul of the Igniter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[3]}, {"id":1220178,"name":"Soul of the Torcher","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[3]}, +{"id":1220182,"name":"Soul of the Lightwarden","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220184,"name":"Soul of the Radiant Defender","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220186,"name":"Soul of the Shieldbearer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220188,"name":"Soul of the Bastion","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220190,"name":"Soul of the Reckoner","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220192,"name":"Soul of the Ironclad","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220194,"name":"Soul of the Guardian","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220196,"name":"Soul of the Peacekeeper","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220198,"name":"Soul of the Refined","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220200,"name":"Soul of the Exemplar","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220202,"name":"Soul of the Inquisitor","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220204,"name":"Soul of the Sovereign","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220206,"name":"Soul of the Dominus","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220208,"name":"Soul of the Vindicator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220210,"name":"Soul of the Altruist","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220212,"name":"Soul of the Arbiter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220214,"name":"Soul of the Sealbearer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220216,"name":"Soul of the Justicar","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220218,"name":"Soul of the Judicator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220220,"name":"Soul of the Ascendant","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220222,"name":"Soul of the Retributor","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220224,"name":"Soul of the Excommunicator","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220226,"name":"Soul of the Lightbringer","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220228,"name":"Soul of the Exile","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, +{"id":1220230,"name":"Soul of the Templar","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[4]}, {"id":1220232,"name":"Soul of the Windwalker","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, {"id":1220234,"name":"Soul of the Shield Master","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, {"id":1220236,"name":"Soul of the Totemic Protector","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, @@ -2063,6 +2107,7 @@ {"id":1220295,"name":"Soul of the Ancestral Warden","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, {"id":1220297,"name":"Soul of the Corrupt","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[7]}, {"id":1220299,"name":"Soul of the Gentle Paw","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[1]}, +{"id":1220301,"name":"Soul of the Ferocious","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[1]}, {"id":1220303,"name":"Soul of the Shifter","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[1]}, {"id":1220305,"name":"Soul of the Territorial","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[1]}, {"id":1220307,"name":"Soul of the Beast","icon":"spell_holy_divinespirit","type":3,"classAllowlist":[1]}, diff --git a/assets/db_inputs/wowhead_shoulder_rune_tooltips.csv b/assets/db_inputs/wowhead_shoulder_rune_tooltips.csv index 13eeb8bc88..920621fe70 100644 --- a/assets/db_inputs/wowhead_shoulder_rune_tooltips.csv +++ b/assets/db_inputs/wowhead_shoulder_rune_tooltips.csv @@ -196,7 +196,7 @@ 1220264,{"name":"Soul of the Refined","quality":3,"icon":"spell_holy_divinespirit","tooltip":"
Soul of the Refined
Item Level 55

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

Increases your critical strike chance with spells and attacks by 2%.

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

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

Your spell critical strikes now have a 100% chance trigger your Elemental Focus talent.

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

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

Reduces the cooldown of Enrage by 30 sec and it no longer reduces your armor.

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

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

Raptor Strike increases the damage done by your next other melee ability (excluding Wing Clip) within 5 sec by 20%.

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

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

Raptor Strike increases the damage done by your next other melee ability (excluding Wing Clip) within 5 sec by 20%.

","spells":[]} 1220170,{"name":"Soul of Fiery Convergence","quality":3,"icon":"spell_holy_divinespirit","tooltip":"
Soul of Fiery Convergence
Item Level 55

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

Your Pyroblast deals 20% increased damage to targets afflicted with your Fireball's periodic effect.

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

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

For 6 sec after using Shadowcleave, your Searing Pain strikes 1 additional target within melee range.

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

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

Your Riptide increases the amount healed by Chain Heal by an additional 25%.

","spells":[]} diff --git a/proto/hunter.proto b/proto/hunter.proto index d030f828fc..dee4a1fb6e 100644 --- a/proto/hunter.proto +++ b/proto/hunter.proto @@ -114,6 +114,7 @@ enum HunterRune { RuneShouldersBeastTender = 1220086; RuneShouldersBountyHunter = 1220082; RuneShouldersDeadlyStriker = 1220104; + RuneShouldersEchoes = 1220096; RuneShouldersFerocious = 1220301; RuneShouldersHazardHarrier = 1220076; RuneShouldersHoundMaster = 1220088; diff --git a/sim/core/focus.go b/sim/core/focus.go index ca8e715fba..951d195459 100644 --- a/sim/core/focus.go +++ b/sim/core/focus.go @@ -56,6 +56,10 @@ func (fb *focusBar) MaxFocus() float64 { return fb.maxFocus } +func (fb *focusBar) IncreaseMaxFocus(value float64) { + fb.maxFocus += value +} + func (fb *focusBar) CurrentFocusPerTick() float64 { return fb.focusPerTick * fb.focusRegenMultiplier } diff --git a/sim/hunter/aimed_shot.go b/sim/hunter/aimed_shot.go index f475b6bc86..fdfe5fede0 100644 --- a/sim/hunter/aimed_shot.go +++ b/sim/hunter/aimed_shot.go @@ -13,8 +13,6 @@ func (hunter *Hunter) getAimedShotConfig(rank int, timer *core.Timer) core.Spell manaCost := [7]float64{0, 75, 115, 160, 210, 260, 310}[rank] level := [7]int{0, 0, 28, 36, 44, 52, 60}[rank] - has2PDragonStalkerPursuit := hunter.HasSetBonus(ItemSetDragonstalkerPursuit, 2) - return core.SpellConfig{ SpellCode: SpellCode_HunterAimedShot, ActionID: core.ActionID{SpellID: spellId}, @@ -65,9 +63,6 @@ func (hunter *Hunter) getAimedShotConfig(rank int, timer *core.Timer) core.Spell hunter.AmmoDamageBonus + baseDamage - if has2PDragonStalkerPursuit && (target.HasActiveAuraWithTag("ImmolationTrap") || hunter.HasActiveAuraWithTag("ExplosiveTrap")) { - baseDamage *= 1.20 - } result := spell.CalcDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) spell.WaitTravelTime(sim, func(s *core.Simulation) { spell.DealDamage(sim, result) diff --git a/sim/hunter/item_sets_pve.go b/sim/hunter/item_sets_pve.go index aa2c18f9f1..d8e8ebc25e 100644 --- a/sim/hunter/item_sets_pve.go +++ b/sim/hunter/item_sets_pve.go @@ -1,10 +1,7 @@ package hunter import ( - "time" - "github.com/wowsims/sod/sim/core" - "github.com/wowsims/sod/sim/core/proto" "github.com/wowsims/sod/sim/core/stats" ) @@ -26,494 +23,3 @@ var ItemSetDreadHuntersChain = core.NewItemSet(core.ItemSet{ }, }, }) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 4 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetBeastmasterArmor = core.NewItemSet(core.ItemSet{ - Name: "Beastmaster Armor", - 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, - }) - }, - // Your melee and ranged autoattacks have a 6% chance to energize you for 300 mana. - 4: func(agent core.Agent) { - c := agent.GetCharacter() - actionID := core.ActionID{SpellID: 450577} - manaMetrics := c.NewManaMetrics(actionID) - - core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ - ActionID: actionID, - Name: "S03 - Mana Proc on Cast - Beaststalker Armor", - Callback: core.CallbackOnSpellHitDealt, - Outcome: core.OutcomeLanded, - ProcMask: core.ProcMaskWhiteHit, - ProcChance: 0.06, - Handler: func(sim *core.Simulation, spell *core.Spell, _ *core.SpellResult) { - if c.HasManaBar() { - c.AddMana(sim, 300, manaMetrics) - } - }, - }) - }, - // +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 ItemSetGiantstalkerProwess = core.NewItemSet(core.ItemSet{ - Name: "Giantstalker Prowess", - Bonuses: map[int32]core.ApplyEffect{ - // Your Mongoose Bite also reduces its target's chance to Dodge by 1% and increases your chance to hit by 1% for 30 sec. - 2: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - - procBonus := stats.Stats{ - stats.SpellHit: 1, - stats.MeleeHit: 1, - } - - stalkerAura := hunter.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 458403}, - Label: "Stalker", - Duration: time.Second * 30, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.AddStatsDynamic(sim, procBonus) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.AddStatsDynamic(sim, procBonus.Invert()) - }, - }) - - debuffAuras := hunter.NewEnemyAuraArray(core.MeleeHunterDodgeReductionAura) - core.MakePermanent(hunter.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Hunter - Melee 2P Bonus Trigger", - OnSpellHitDealt: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_HunterMongooseBite && result.Landed() { - debuffAuras.Get(result.Target).Activate(sim) - stalkerAura.Activate(sim) - } - }, - })) - }, - // While tracking a creature type, you deal 3% increased damage to that creature type. - // Unsure if this stacks with the Pursuit 4p - 4: func(agent core.Agent) { - c := agent.GetCharacter() - // Just adding 3% damage to assume the hunter is tracking their target's type - c.PseudoStats.DamageDealtMultiplier *= 1.03 - }, - // Mongoose Bite also activates for 5 sec whenever your target Parries or Blocks or when your melee attack misses. - 6: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - core.MakePermanent(hunter.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Hunter - Melee 6P Bonus Trigger", - OnSpellHitDealt: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.ProcMask.Matches(core.ProcMaskMelee) && (result.Outcome == core.OutcomeMiss || result.Outcome == core.OutcomeBlock || result.Outcome == core.OutcomeParry) { - hunter.DefensiveState.Activate(sim) - } - }, - })) - }, - }, -}) - -var ItemSetGiantstalkerPursuit = core.NewItemSet(core.ItemSet{ - Name: "Giantstalker Pursuit", - Bonuses: map[int32]core.ApplyEffect{ - // You generate 100% more threat for 8 sec after using Distracting Shot. - 2: func(agent core.Agent) { - // Nothing to do - }, - // While tracking a creature type, you deal 3% increased damage to that creature type. - // Unsure if this stacks with the Prowess 4p - 4: func(agent core.Agent) { - c := agent.GetCharacter() - // Just adding 3% damage to assume the hunter is tracking their target's type - c.PseudoStats.DamageDealtMultiplier *= 1.03 - }, - // Your next Shot ability within 12 sec after Aimed Shot deals 20% more damage. - 6: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - - if !hunter.Talents.AimedShot { - return - } - - procAura := hunter.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 456379}, - Label: "S03 - Item - T1 - Hunter - Ranged 6P Bonus", - Duration: time.Second * 12, - - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range hunter.Shots { - if spell != nil { - spell.DamageMultiplierAdditive += 0.20 - } - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range hunter.Shots { - if spell != nil { - spell.DamageMultiplierAdditive -= 0.20 - } - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if !spell.Flags.Matches(SpellFlagShot) || (aura.RemainingDuration(sim) == aura.Duration && spell.SpellCode == SpellCode_HunterAimedShot) { - return - } - - aura.Deactivate(sim) - }, - }) - - core.MakePermanent(hunter.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Hunter - Ranged 6P Bonus Trigger", - OnCastComplete: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell.SpellCode == SpellCode_HunterAimedShot { - procAura.Activate(sim) - } - }, - })) - }, - }, -}) - -var ItemSetDragonstalkerProwess = core.NewItemSet(core.ItemSet{ - Name: "Dragonstalker's Prowess", - Bonuses: map[int32]core.ApplyEffect{ - // Raptor Strike increases the damage done by your next other melee ability within 5 sec by 20%. - 2: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - - affectedSpells := make(map[*core.Spell]bool) - - procAura := hunter.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 467331}, - Label: "Clever Strikes", - Duration: time.Second * 5, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range hunter.MeleeSpells { - if spell.SpellCode != SpellCode_HunterRaptorStrikeHit && spell.SpellCode != SpellCode_HunterRaptorStrike && spell.SpellCode != SpellCode_HunterWingClip { - affectedSpells[spell] = true - } - } - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for spell := range affectedSpells { - spell.DamageMultiplierAdditive += 0.20 - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for spell := range affectedSpells { - spell.DamageMultiplierAdditive -= 0.20 - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if !affectedSpells[spell] { - return - } - - aura.Deactivate(sim) - }, - }) - - core.MakePermanent(hunter.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Hunter - Melee 2P Bonus Trigger", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_HunterRaptorStrikeHit { - procAura.Activate(sim) - } - }, - })) - }, - // Increases damage dealt by your main hand weapon with Raptor Strike and Wyvern Strike by 20%. - 4: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - - hunter.OnSpellRegistered(func(spell *core.Spell) { - if spell.SpellCode == SpellCode_HunterWyvernStrike || (spell.SpellCode == SpellCode_HunterRaptorStrikeHit && spell.ProcMask.Matches(core.ProcMaskMeleeMHSpecial)) { - spell.DamageMultiplierAdditive += 0.20 - } - }) - }, - // Your periodic damage has a 5% chance to reset the cooldown on one of your Strike abilities. The Strike with the longest remaining cooldown is always chosen. - 6: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - core.MakePermanent(hunter.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Hunter - Melee 6P Bonus Trigger", - ActionID: core.ActionID{SpellID: 467334}, - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if sim.Proc(0.05, "T2 Melee 6PC Strike Reset") { - maxSpell := hunter.RaptorStrike - - for _, strike := range hunter.Strikes { - if strike.TimeToReady(sim) > maxSpell.TimeToReady(sim) { - maxSpell = strike - } - } - - maxSpell.CD.Reset() - aura.Activate(sim) // used for metrics - } - }, - })) - }, - }, -}) - -var ItemSetDragonstalkerPursuit = core.NewItemSet(core.ItemSet{ - Name: "Dragonstalker's Pursuit", - Bonuses: map[int32]core.ApplyEffect{ - // Your Aimed Shot deals 20% more damage to targets afflicted by one of your trap effects. - 2: func(agent core.Agent) { - // Implemented in aimed_shot.go - }, - // Your damaging Shot abilities deal 10% increased damage if the previous damaging Shot used was different than the current one. - 4: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - - shotSpells := []*core.Spell{} - procAura := hunter.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 467312}, - Label: "S03 - Item - T2 - Hunter - Ranged 4P Bonus", - Duration: time.Second * 12, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - shotSpells = core.FilterSlice(hunter.Shots, func(s *core.Spell) bool { return s != nil }) - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range shotSpells { - if spell.SpellCode != hunter.LastShot.SpellCode { - spell.DamageMultiplierAdditive += 0.10 - } - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range shotSpells { - if spell.SpellCode != hunter.LastShot.SpellCode { - spell.DamageMultiplierAdditive -= 0.10 - } - } - }, - }) - - core.MakePermanent(hunter.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Hunter - Ranged 4P Bonus Trigger", - OnCastComplete: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell.Flags.Matches(SpellFlagShot) { - procAura.Deactivate(sim) - hunter.LastShot = spell - procAura.Activate(sim) - } - }, - })) - }, - // Your Serpent Sting damage is increased by 25% of your Attack Power over its normal duration. - 6: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - core.MakePermanent(hunter.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Hunter - Ranged 6P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - hunter.SerpentStingAPCoeff += 0.25 - }, - })) - }, - }, -}) - -var ItemSetPredatorArmor = core.NewItemSet(core.ItemSet{ - Name: "Predator's Armor", - Bonuses: map[int32]core.ApplyEffect{ - // +20 Attack Power. - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.AttackPower, 20) - c.AddStat(stats.RangedAttackPower, 20) - }, - // Increases the Attack Power your Beast pet gains from your attributes by 20%. - 3: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - if hunter.pet == nil { - return - } - - core.MakePermanent(hunter.RegisterAura(core.Aura{ - Label: "Predator's Armor 3P", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - oldStatInheritance := hunter.pet.GetStatInheritance() - hunter.pet.UpdateStatInheritance( - func(ownerStats stats.Stats) stats.Stats { - s := oldStatInheritance(ownerStats) - s[stats.AttackPower] *= 1.20 - return s - }, - ) - }, - })) - }, - // Increases the Focus regeneration of your Beast pet by 20%. - 5: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - if hunter.pet == nil { - return - } - - hunter.RegisterAura(core.Aura{ - Label: "Predator's Armor 5P", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - hunter.pet.AddFocusRegenMultiplier(0.20) - }, - }) - }, - }, -}) - -var TrappingsOfTheUnseenPath = core.NewItemSet(core.ItemSet{ - Name: "Trappings of the Unseen Path", - Bonuses: map[int32]core.ApplyEffect{ - // Increases the Focus regeneration of your Beast pet by 100%. - 3: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - if hunter.pet == nil { - return - } - - hunter.RegisterAura(core.Aura{ - Label: "Trappings of the Unseen Path 3P", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - hunter.pet.AddFocusRegenMultiplier(1.00) - }, - }) - }, - }, -}) - -var StrikersProwess = core.NewItemSet(core.ItemSet{ - Name: "Striker's Prowess", - Bonuses: map[int32]core.ApplyEffect{ - // Increases Wyvern Strike DoT by 50% and increases your pet's maximum focus by 50. - 2: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - - hunter.RegisterAura(core.Aura{ - Label: "Striker's Prowess 2P", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - if hunter.WyvernStrike != nil { - hunter.WyvernStrike.PeriodicDamageMultiplierAdditive += 0.50 - } - - // Focus implementation in pet.go - }, - }) - }, - // Increases the Impact Damage of Mongoose Bite and all Strikes by 15% - 4: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - hunter.RegisterAura(core.Aura{ - Label: "Striker's Prowess 4P", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range hunter.Strikes { - spell.ImpactDamageMultiplierAdditive += 0.15 - } - hunter.RaptorStrikeMH.ImpactDamageMultiplierAdditive += 0.15 - hunter.RaptorStrikeOH.ImpactDamageMultiplierAdditive += 0.15 - hunter.MongooseBite.ImpactDamageMultiplierAdditive += 0.15 - }, - }) - }, - }, -}) - -var StrikersPursuit = core.NewItemSet(core.ItemSet{ - Name: "Striker's Pursuit", - Bonuses: map[int32]core.ApplyEffect{ - // Increases Kill Shot damage by 50% against non-player targets. - 2: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - if !hunter.HasRune(proto.HunterRune_RuneLegsKillShot) { - return - } - - hunter.RegisterAura(core.Aura{ - Label: "Striker's Pursuit 4P", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - hunter.KillShot.DamageMultiplierAdditive += 0.20 - }, - }) - }, - // Kill Shot's cooldown is reduced by 50%. - // While Rapid Fire is active with Rapid killing engraved, Kill Shot has no cooldown and fires 3 additional Kill Shots at 33% damage, with a minimum range. - 4: func(agent core.Agent) { - hunter := agent.(HunterAgent).GetHunter() - if !hunter.HasRune(proto.HunterRune_RuneLegsKillShot) { - return - } - - clonedShotConfig := hunter.newKillShotConfig() - clonedShotConfig.ActionID.Tag = 1 - clonedShotConfig.Flags |= core.SpellFlagNoOnCastComplete | core.SpellFlagPassiveSpell - clonedShotConfig.Flags ^= core.SpellFlagAPL - clonedShotConfig.Cast.DefaultCast.GCD = 0 - clonedShotConfig.Cast.DefaultCast.Cost = 0 - clonedShotConfig.Cast.CD = core.Cooldown{} - clonedShotConfig.ManaCost.BaseCost = 0 - clonedShotConfig.ManaCost.FlatCost = 0 - clonedShotConfig.MetricSplits = 0 - clonedShotConfig.DamageMultiplier *= 0.30 - clonedShotConfig.ExtraCastCondition = func(sim *core.Simulation, target *core.Unit) bool { - return hunter.DistanceFromTarget >= core.MinRangedAttackDistance - } - - clonedShot := hunter.RegisterSpell(clonedShotConfig) - - hunter.RegisterAura(core.Aura{ - Label: "Striker's Pursuit 2P", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - hunter.KillShot.CD.FlatModifier -= 6 * time.Second - - if !hunter.HasRune(proto.HunterRune_RuneHelmRapidKilling) { - return - } - - oldApplyEffects := hunter.KillShot.ApplyEffects - hunter.KillShot.ApplyEffects = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - oldApplyEffects(sim, target, spell) - - if hunter.RapidFireAura.IsActive() { - spell.CD.Reset() - - for i := 1; i < 4; i++ { - core.StartDelayedAction(sim, core.DelayedActionOptions{ - DoAt: sim.CurrentTime + time.Duration(i*375)*time.Millisecond, - OnAction: func(sim *core.Simulation) { - // Ensure that the cloned shots get any damage amps from the main Kill Shot ability - clonedShot.DamageMultiplier *= spell.DamageMultiplier - clonedShot.DamageMultiplierAdditive += spell.DamageMultiplierAdditive - 1 - clonedShot.Cast(sim, target) - clonedShot.DamageMultiplier /= spell.DamageMultiplier - clonedShot.DamageMultiplierAdditive -= spell.DamageMultiplierAdditive - 1 - }, - }) - } - } - } - }, - }) - }, - }, -}) diff --git a/sim/hunter/item_sets_pve_phase_4.go b/sim/hunter/item_sets_pve_phase_4.go new file mode 100644 index 0000000000..c8e659d898 --- /dev/null +++ b/sim/hunter/item_sets_pve_phase_4.go @@ -0,0 +1,219 @@ +package hunter + +import ( + "time" + + "github.com/wowsims/sod/sim/core" + "github.com/wowsims/sod/sim/core/stats" +) + +var ItemSetBeastmasterArmor = core.NewItemSet(core.ItemSet{ + Name: "Beastmaster Armor", + 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, + }) + }, + // Your melee and ranged autoattacks have a 6% chance to energize you for 300 mana. + 4: func(agent core.Agent) { + c := agent.GetCharacter() + actionID := core.ActionID{SpellID: 450577} + manaMetrics := c.NewManaMetrics(actionID) + + core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ + ActionID: actionID, + Name: "S03 - Mana Proc on Cast - Beaststalker Armor", + Callback: core.CallbackOnSpellHitDealt, + Outcome: core.OutcomeLanded, + ProcMask: core.ProcMaskWhiteHit, + ProcChance: 0.06, + Handler: func(sim *core.Simulation, spell *core.Spell, _ *core.SpellResult) { + if c.HasManaBar() { + c.AddMana(sim, 300, manaMetrics) + } + }, + }) + }, + // +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 ItemSetGiantstalkerProwess = core.NewItemSet(core.ItemSet{ + Name: "Giantstalker Prowess", + Bonuses: map[int32]core.ApplyEffect{ + 2: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT1Melee2PBonus() + }, + 4: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT1Melee4PBonus() + }, + 6: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT1Melee6PBonus() + }, + }, +}) + +// Your Mongoose Bite also reduces its target's chance to Dodge by 1% and increases your chance to hit by 1% for 30 sec. +func (hunter *Hunter) applyT1Melee2PBonus() { + label := "S03 - Item - T1 - Hunter - Melee 2P Bonus" + if hunter.HasAura(label) { + return + } + + procBonus := stats.Stats{ + stats.SpellHit: 1, + stats.MeleeHit: 1, + } + + stalkerAura := hunter.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 458403}, + Label: "Stalker", + Duration: time.Second * 30, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + aura.Unit.AddStatsDynamic(sim, procBonus) + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + aura.Unit.AddStatsDynamic(sim, procBonus.Invert()) + }, + }) + + debuffAuras := hunter.NewEnemyAuraArray(core.MeleeHunterDodgeReductionAura) + core.MakePermanent(hunter.RegisterAura(core.Aura{ + Label: label, + OnSpellHitDealt: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if spell.SpellCode == SpellCode_HunterMongooseBite && result.Landed() { + debuffAuras.Get(result.Target).Activate(sim) + stalkerAura.Activate(sim) + } + }, + })) +} + +// While tracking a creature type, you deal 3% increased damage to that creature type. +// Unsure if this stacks with the Pursuit 4p +func (hunter *Hunter) applyT1Melee4PBonus() { + label := "S03 - Item - T1 - Hunter - Melee 4P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + // Just adding 3% damage to assume the hunter is tracking their target's type + hunter.PseudoStats.DamageDealtMultiplier *= 1.03 + }, + }) +} + +// Mongoose Bite also activates for 5 sec whenever your target Parries or Blocks or when your melee attack misses. +func (hunter *Hunter) applyT1Melee6PBonus() { + label := "S03 - Item - T1 - Hunter - Melee 6P Bonus" + if hunter.HasAura(label) { + return + } + + core.MakePermanent(hunter.RegisterAura(core.Aura{ + Label: label, + OnSpellHitDealt: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if spell.ProcMask.Matches(core.ProcMaskMelee) && !result.Landed() { + hunter.DefensiveState.Activate(sim) + } + }, + })) +} + +var ItemSetGiantstalkerPursuit = core.NewItemSet(core.ItemSet{ + Name: "Giantstalker Pursuit", + Bonuses: map[int32]core.ApplyEffect{ + // You generate 100% more threat for 8 sec after using Distracting Shot. + 2: func(agent core.Agent) { + // Do nothing + }, + 4: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT1Ranged4PBonus() + }, + 6: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT1Ranged6PBonus() + }, + }, +}) + +// While tracking a creature type, you deal 3% increased damage to that creature type. +// Unsure if this stacks with the Prowess 4p +func (hunter *Hunter) applyT1Ranged4PBonus() { + label := "S03 - Item - T1 - Hunter - Ranged 4P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + // Just adding 3% damage to assume the hunter is tracking their target's type + hunter.PseudoStats.DamageDealtMultiplier *= 1.03 + }, + }) +} + +// Your next Shot ability within 12 sec after Aimed Shot deals 20% more damage. +func (hunter *Hunter) applyT1Ranged6PBonus() { + if !hunter.Talents.AimedShot { + return + } + + label := "S03 - Item - T1 - Hunter - Ranged 6P Bonus" + if hunter.HasAura(label) { + return + } + + procAura := hunter.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 456382}, + Label: "Precision", + Duration: time.Second * 12, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range hunter.Shots { + spell.DamageMultiplierAdditive += 0.20 + } + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range hunter.Shots { + spell.DamageMultiplierAdditive -= 0.20 + } + }, + OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { + if !spell.Flags.Matches(SpellFlagShot) || (aura.RemainingDuration(sim) == aura.Duration && spell.SpellCode == SpellCode_HunterAimedShot) { + return + } + + aura.Deactivate(sim) + }, + }) + + core.MakePermanent(hunter.RegisterAura(core.Aura{ + Label: label, + OnCastComplete: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell) { + if spell.SpellCode == SpellCode_HunterAimedShot { + procAura.Activate(sim) + } + }, + })) +} diff --git a/sim/hunter/item_sets_pve_phase_5.go b/sim/hunter/item_sets_pve_phase_5.go new file mode 100644 index 0000000000..a27442c394 --- /dev/null +++ b/sim/hunter/item_sets_pve_phase_5.go @@ -0,0 +1,294 @@ +package hunter + +import ( + "time" + + "github.com/wowsims/sod/sim/core" + "github.com/wowsims/sod/sim/core/stats" +) + +var ItemSetDragonstalkerProwess = core.NewItemSet(core.ItemSet{ + Name: "Dragonstalker's Prowess", + Bonuses: map[int32]core.ApplyEffect{ + 2: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT2Melee2PBonus() + }, + 4: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT2Melee4PBonus() + }, + 6: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT2Melee6PBonus() + }, + }, +}) + +// Raptor Strike increases the damage done by your next other melee ability within 5 sec by 20%. +func (hunter *Hunter) applyT2Melee2PBonus() { + label := "S03 - Item - T2 - Hunter - Melee 2P Bonus" + if hunter.HasAura(label) { + return + } + + affectedSpells := make(map[*core.Spell]bool) + + procAura := hunter.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 467331}, + Label: "Clever Strikes", + Duration: time.Second * 5, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range hunter.MeleeSpells { + if spell.SpellCode != SpellCode_HunterRaptorStrikeHit && spell.SpellCode != SpellCode_HunterRaptorStrike && spell.SpellCode != SpellCode_HunterWingClip { + affectedSpells[spell] = true + } + } + }, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + for spell := range affectedSpells { + spell.DamageMultiplierAdditive += 0.20 + } + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + for spell := range affectedSpells { + spell.DamageMultiplierAdditive -= 0.20 + } + }, + OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { + if !affectedSpells[spell] { + return + } + + aura.Deactivate(sim) + }, + }) + + core.MakePermanent(hunter.RegisterAura(core.Aura{ + Label: label, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if spell.SpellCode == SpellCode_HunterRaptorStrikeHit { + procAura.Activate(sim) + } + }, + })) +} + +// Increases damage dealt by your main hand weapon with Raptor Strike and Wyvern Strike by 20%. +func (hunter *Hunter) applyT2Melee4PBonus() { + label := "S03 - Item - T2 - Hunter - Melee 4P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range []*core.Spell{hunter.RaptorStrike, hunter.RaptorStrikeMH, hunter.WyvernStrike} { + if spell == nil { + continue + } + + spell.DamageMultiplierAdditive += 0.20 + } + }, + }) +} + +// Your periodic damage has a 5% chance to reset the cooldown on one of your Strike abilities. +// The Strike with the longest remaining cooldown is always chosen. +func (hunter *Hunter) applyT2Melee6PBonus() { + label := "S03 - Item - T2 - Hunter - Melee 6P Bonus" + if hunter.HasAura(label) { + return + } + + core.MakePermanent(hunter.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 467334}, // Tracking in APL + Label: label, + OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if sim.Proc(0.05, "T2 Melee 6PC Strike Reset") { + maxSpell := hunter.RaptorStrike + + for _, strike := range hunter.Strikes { + if strike.TimeToReady(sim) > maxSpell.TimeToReady(sim) { + maxSpell = strike + } + } + + maxSpell.CD.Reset() + aura.Activate(sim) // used for metrics + } + }, + })) +} + +var ItemSetDragonstalkerPursuit = core.NewItemSet(core.ItemSet{ + Name: "Dragonstalker's Pursuit", + Bonuses: map[int32]core.ApplyEffect{ + 2: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT2Ranged2PBonus() + }, + 4: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT2Ranged4PBonus() + }, + 6: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyT2Ranged6PBonus() + }, + }, +}) + +// Your Aimed Shot deals 20% more damage to targets afflicted by one of your trap effects. +func (hunter *Hunter) applyT2Ranged2PBonus() { + if !hunter.Talents.AimedShot { + return + } + + label := "S03 - Item - T2 - Hunter - Ranged 2P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + oldApplyEffects := hunter.AimedShot.ApplyEffects + hunter.AimedShot.ApplyEffects = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + modifier := 0.0 + if target.HasActiveAuraWithTag("ImmolationTrap") || hunter.HasActiveAuraWithTag("ExplosiveTrap") { + modifier += 0.20 + } + + spell.DamageMultiplierAdditive += modifier + oldApplyEffects(sim, target, spell) + spell.DamageMultiplierAdditive -= modifier + } + }, + }) +} + +// Your damaging Shot abilities deal 10% increased damage if the previous damaging Shot used was different than the current one. +func (hunter *Hunter) applyT2Ranged4PBonus() { + label := "S03 - Item - T2 - Hunter - Ranged 4P Bonus" + if hunter.HasAura(label) { + return + } + + shotSpells := []*core.Spell{} + procAura := hunter.RegisterAura(core.Aura{ + ActionID: core.ActionID{SpellID: 467312}, + Label: label + " Proc", + Duration: time.Second * 12, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + shotSpells = core.FilterSlice(hunter.Shots, func(s *core.Spell) bool { return s != nil }) + }, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range shotSpells { + if spell.SpellCode != hunter.LastShot.SpellCode { + spell.DamageMultiplierAdditive += 0.10 + } + } + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range shotSpells { + if spell.SpellCode != hunter.LastShot.SpellCode { + spell.DamageMultiplierAdditive -= 0.10 + } + } + }, + }) + + core.MakePermanent(hunter.RegisterAura(core.Aura{ + Label: label, + OnCastComplete: func(_ *core.Aura, sim *core.Simulation, spell *core.Spell) { + if spell.Flags.Matches(SpellFlagShot) { + procAura.Deactivate(sim) + hunter.LastShot = spell + procAura.Activate(sim) + } + }, + })) +} + +// Your Serpent Sting damage is increased by 25% of your Attack Power over its normal duration. +func (hunter *Hunter) applyT2Ranged6PBonus() { + label := "S03 - Item - T2 - Hunter - Ranged 6P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + hunter.SerpentStingAPCoeff += 0.25 + }, + }) +} + +var ItemSetPredatorArmor = core.NewItemSet(core.ItemSet{ + Name: "Predator's Armor", + Bonuses: map[int32]core.ApplyEffect{ + // +20 Attack Power. + 2: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.AttackPower, 20) + c.AddStat(stats.RangedAttackPower, 20) + }, + 3: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyZGBeastmaster3PBonus() + }, + 5: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyZGBeastmaster5PBonus() + }, + }, +}) + +// Increases the Attack Power your Beast pet gains from your attributes by 20%. +func (hunter *Hunter) applyZGBeastmaster3PBonus() { + if hunter.pet == nil { + return + } + + label := "S03 - Item - ZG - Hunter - Beastmaster 3P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + oldStatInheritance := hunter.pet.GetStatInheritance() + hunter.pet.UpdateStatInheritance( + func(ownerStats stats.Stats) stats.Stats { + s := oldStatInheritance(ownerStats) + s[stats.AttackPower] *= 1.20 + return s + }, + ) + }, + }) +} + +// Increases the Focus regeneration of your Beast pet by 20%. +func (hunter *Hunter) applyZGBeastmaster5PBonus() { + if hunter.pet == nil { + return + } + + label := "S03 - Item - ZG - Hunter - Beastmaster 5P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + hunter.pet.AddFocusRegenMultiplier(0.20) + }, + }) +} diff --git a/sim/hunter/item_sets_pve_phase_6.go b/sim/hunter/item_sets_pve_phase_6.go new file mode 100644 index 0000000000..589c437e0c --- /dev/null +++ b/sim/hunter/item_sets_pve_phase_6.go @@ -0,0 +1,190 @@ +package hunter + +import ( + "time" + + "github.com/wowsims/sod/sim/core" + "github.com/wowsims/sod/sim/core/proto" +) + +var StrikersProwess = core.NewItemSet(core.ItemSet{ + Name: "Striker's Prowess", + Bonuses: map[int32]core.ApplyEffect{ + 2: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyTAQMelee2PBonus() + }, + 4: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyTAQMelee4PBonus() + }, + }, +}) + +// Increases Wyvern Strike DoT by 50% and increases your pet's maximum focus by 50. +func (hunter *Hunter) applyTAQMelee2PBonus() { + label := "S03 - Item - TAQ - Hunter - Melee 2P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + if hunter.WyvernStrike != nil { + hunter.WyvernStrike.PeriodicDamageMultiplierAdditive += 0.50 + } + + if hunter.pet != nil { + hunter.pet.IncreaseMaxFocus(50) + } + }, + }) +} + +// Increases the Impact Damage of Mongoose Bite and all Strikes by 15% +func (hunter *Hunter) applyTAQMelee4PBonus() { + label := "S03 - Item - TAQ - Hunter - Melee 4P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range hunter.Strikes { + spell.ImpactDamageMultiplierAdditive += 0.15 + } + hunter.RaptorStrikeMH.ImpactDamageMultiplierAdditive += 0.15 + hunter.RaptorStrikeOH.ImpactDamageMultiplierAdditive += 0.15 + hunter.MongooseBite.ImpactDamageMultiplierAdditive += 0.15 + }, + }) +} + +var StrikersPursuit = core.NewItemSet(core.ItemSet{ + Name: "Striker's Pursuit", + Bonuses: map[int32]core.ApplyEffect{ + 2: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyTAQRanged2PBonus() + }, + 4: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyTAQRanged4PBonus() + }, + }, +}) + +// Increases Kill Shot damage by 50% against non-player targets. +func (hunter *Hunter) applyTAQRanged2PBonus() { + if !hunter.HasRune(proto.HunterRune_RuneLegsKillShot) { + return + } + + label := "S03 - Item - TAQ - Hunter - Ranged 2P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + hunter.KillShot.DamageMultiplierAdditive += 0.20 + }, + }) +} + +// Kill Shot's cooldown is reduced by 50%. +// While Rapid Fire is active with Rapid killing engraved, Kill Shot has no cooldown and fires 3 additional Kill Shots at 30% damage, with a minimum range. +func (hunter *Hunter) applyTAQRanged4PBonus() { + if !hunter.HasRune(proto.HunterRune_RuneLegsKillShot) { + return + } + + label := "S03 - Item - TAQ - Hunter - Ranged 4P Bonus" + if hunter.HasAura(label) { + return + } + + clonedShotConfig := hunter.newKillShotConfig() + clonedShotConfig.ActionID.Tag = 1 + clonedShotConfig.Flags |= core.SpellFlagNoOnCastComplete | core.SpellFlagPassiveSpell + clonedShotConfig.Flags ^= core.SpellFlagAPL + clonedShotConfig.Cast.DefaultCast.GCD = 0 + clonedShotConfig.Cast.DefaultCast.Cost = 0 + clonedShotConfig.Cast.CD = core.Cooldown{} + clonedShotConfig.ManaCost.BaseCost = 0 + clonedShotConfig.ManaCost.FlatCost = 0 + clonedShotConfig.MetricSplits = 0 + clonedShotConfig.DamageMultiplier *= 0.30 + clonedShotConfig.ExtraCastCondition = func(sim *core.Simulation, target *core.Unit) bool { + return hunter.DistanceFromTarget >= core.MinRangedAttackDistance + } + + clonedShot := hunter.RegisterSpell(clonedShotConfig) + clonedShot.DamageMultiplierAdditive += 0.20 // Add the 2p bonus 20% + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + hunter.KillShot.CD.FlatModifier -= 6 * time.Second + + if !hunter.HasRune(proto.HunterRune_RuneHelmRapidKilling) { + return + } + + oldApplyEffects := hunter.KillShot.ApplyEffects + hunter.KillShot.ApplyEffects = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + oldApplyEffects(sim, target, spell) + + if hunter.RapidFireAura.IsActive() { + spell.CD.Reset() + + for i := 1; i < 4; i++ { + core.StartDelayedAction(sim, core.DelayedActionOptions{ + DoAt: sim.CurrentTime + time.Duration(i*375)*time.Millisecond, + OnAction: func(sim *core.Simulation) { + // Ensure that the cloned shots get any damage amps from the main Kill Shot ability + clonedShot.DamageMultiplier *= spell.DamageMultiplier + clonedShot.DamageMultiplierAdditive += spell.DamageMultiplierAdditive - 1 + clonedShot.Cast(sim, target) + clonedShot.DamageMultiplier /= spell.DamageMultiplier + clonedShot.DamageMultiplierAdditive -= spell.DamageMultiplierAdditive - 1 + }, + }) + } + } + } + }, + }) +} + +var TrappingsOfTheUnseenPath = core.NewItemSet(core.ItemSet{ + Name: "Trappings of the Unseen Path", + Bonuses: map[int32]core.ApplyEffect{ + 3: func(agent core.Agent) { + hunter := agent.(HunterAgent).GetHunter() + hunter.applyRAQBeastmastery5PBonus() + }, + }, +}) + +// Increases the Focus regeneration of your Beast pet by 100%. +func (hunter *Hunter) applyRAQBeastmastery5PBonus() { + if hunter.pet == nil { + return + } + + label := "S03 - Item - RAQ - Hunter - Beastmastery 5P Bonus" + if hunter.HasAura(label) { + return + } + + hunter.RegisterAura(core.Aura{ + Label: label, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + hunter.pet.AddFocusRegenMultiplier(1.00) + }, + }) +} diff --git a/sim/hunter/pet.go b/sim/hunter/pet.go index b935149df3..a90628cd01 100644 --- a/sim/hunter/pet.go +++ b/sim/hunter/pet.go @@ -185,12 +185,7 @@ func (hp *HunterPet) Initialize() { hp.specialAbility = hp.NewPetAbility(hp.config.SpecialAbility, true) hp.focusDump = hp.NewPetAbility(hp.config.FocusDump, false) - maxFocus := core.MaxFocus - if hp.hunterOwner.HasSetBonus(StrikersProwess, 2) { - maxFocus += 50 - } - - hp.EnableFocusBar(maxFocus, 1, func(sim *core.Simulation) { + hp.EnableFocusBar(core.MaxFocus, 1, func(sim *core.Simulation) { if hp.GCD.IsReady(sim) { hp.OnGCDReady(sim) } diff --git a/sim/hunter/runes.go b/sim/hunter/runes.go index 15e4bc5b62..0baeba64fc 100644 --- a/sim/hunter/runes.go +++ b/sim/hunter/runes.go @@ -10,6 +10,8 @@ import ( ) func (hunter *Hunter) ApplyRunes() { + hunter.applyShoulderRuneEffect() + if hunter.HasRune(proto.HunterRune_RuneChestLoneWolf) && hunter.pet == nil { hunter.PseudoStats.DamageDealtMultiplier *= 1.30 } @@ -52,6 +54,54 @@ func (hunter *Hunter) ApplyRunes() { hunter.applyResourcefulness() } +func (hunter *Hunter) applyShoulderRuneEffect() { + if hunter.Equipment.Shoulders().Rune == int32(proto.HunterRune_HunterRuneNone) { + return + } + + switch hunter.Equipment.Shoulders().Rune { + // Melee + case int32(proto.HunterRune_RuneShouldersHuntsman): + hunter.applyT1Melee2PBonus() + case int32(proto.HunterRune_RuneShouldersRetaliator): + hunter.applyT1Melee6PBonus() + case int32(proto.HunterRune_RuneShouldersEchoes): + hunter.applyT2Melee2PBonus() + case int32(proto.HunterRune_RuneShouldersLethalLasher): + hunter.applyT2Melee4PBonus() + case int32(proto.HunterRune_RuneShouldersKineticist): + hunter.applyT2Melee6PBonus() + case int32(proto.HunterRune_RuneShouldersStrategist): + hunter.applyTAQMelee2PBonus() + case int32(proto.HunterRune_RuneShouldersDeadlyStriker): + hunter.applyTAQMelee4PBonus() + + // Ranged + case int32(proto.HunterRune_RuneShouldersPreyseeker): + hunter.applyT1Ranged4PBonus() + case int32(proto.HunterRune_RuneShouldersSharpshooter): + hunter.applyT1Ranged6PBonus() + case int32(proto.HunterRune_RuneShouldersHazardHarrier): + hunter.applyT2Ranged2PBonus() + case int32(proto.HunterRune_RuneShouldersAlternator): + hunter.applyT2Ranged4PBonus() + case int32(proto.HunterRune_RuneShouldersToxinologist): + hunter.applyT2Ranged6PBonus() + case int32(proto.HunterRune_RuneShouldersBountyHunter): + hunter.applyTAQRanged2PBonus() + case int32(proto.HunterRune_RuneShouldersTrickShooter): + hunter.applyTAQRanged4PBonus() + + // Beastmaster + case int32(proto.HunterRune_RuneShouldersBeastTender): + hunter.applyZGBeastmaster3PBonus() + case int32(proto.HunterRune_RuneShouldersHoundMaster): + hunter.applyZGBeastmaster5PBonus() + case int32(proto.HunterRune_RuneshouldersAlphaTamer): + hunter.applyRAQBeastmastery5PBonus() + } +} + // TODO: 2024-06-13 - Rune seemingly replaced with Wyvern Strike // func (hunter *Hunter) applyInvigoration() { // if !hunter.HasRune(proto.HunterRune_RuneBootsInvigoration) || hunter.pet == nil { diff --git a/tools/database/gen_db/main.go b/tools/database/gen_db/main.go index aa1177adb6..cee2610bfc 100644 --- a/tools/database/gen_db/main.go +++ b/tools/database/gen_db/main.go @@ -167,9 +167,7 @@ func main() { } for id, rune := range shoulderRuneTooltips { - if database.ShoulderRuneClassAllowlist[rune.GetRequiredClasses()[0]] { - db.AddShoulderRune(id, rune) - } + db.AddShoulderRune(id, rune) } db.MergeItems(database.ItemOverrides) diff --git a/tools/database/rune_overrides.go b/tools/database/rune_overrides.go index 48ff852a5d..07fa2d9b11 100644 --- a/tools/database/rune_overrides.go +++ b/tools/database/rune_overrides.go @@ -46,16 +46,3 @@ var RuneOverrides = []*proto.UIRune{ // As of 2024-06-13 Cobra Slayer is being missed by the scraper because the rune engraving ability is missing "Engrave Rune" in the name {Id: 458393, Name: "Engrave Gloves - Cobra Slayer", Icon: "spell_nature_guardianward", Type: proto.ItemType_ItemTypeHands, ClassAllowlist: []proto.Class{proto.Class_ClassHunter}}, } - -// Classes that have shoulder rune implementations completed to not confuse users -var ShoulderRuneClassAllowlist = map[proto.Class]bool{ - proto.Class_ClassDruid: true, - // proto.Class_ClassHunter: true, - proto.Class_ClassMage: true, - // proto.Class_ClassPaladin: true, - proto.Class_ClassPriest: true, - proto.Class_ClassRogue: true, - proto.Class_ClassShaman: true, - proto.Class_ClassWarlock: true, - proto.Class_ClassWarrior: true, -}