From 4a51a54a2715d6fe9741fe245e5908596f5b4654 Mon Sep 17 00:00:00 2001 From: sanguinerarogue Date: Sat, 7 Dec 2024 23:10:20 -0700 Subject: [PATCH] First pass at mage set implementation --- assets/database/db.bin | Bin 5098725 -> 5098725 bytes assets/database/db.json | 6 +- assets/database/leftover_db.bin | Bin 849828 -> 849828 bytes assets/database/leftover_db.json | 4 +- sim/common/vanilla/item_sets/dungeon_set_1.go | 2 +- sim/mage/TestP1Mage.results | 70 +++ sim/mage/_item_sets_pve.go | 484 ------------------ sim/mage/counterspell.go | 2 +- sim/mage/evocation.go | 4 +- sim/mage/flamestrike.go | 1 + sim/mage/item_sets_pve.go | 441 ++++++++++++++++ .../{_item_sets_pvp.go => item_sets_pvp.go} | 0 sim/mage/items.go | 131 +---- sim/mage/mage.go | 3 + sim/warlock/dps/TestWarlockDSRuin.results | 8 +- sim/warlock/dps/TestWarlockSMRuin.results | 8 +- tools/database/gen_db/main.go | 4 +- ui/core/proto_utils/names.ts | 8 +- 18 files changed, 560 insertions(+), 616 deletions(-) delete mode 100644 sim/mage/_item_sets_pve.go create mode 100644 sim/mage/item_sets_pve.go rename sim/mage/{_item_sets_pvp.go => item_sets_pvp.go} (100%) diff --git a/assets/database/db.bin b/assets/database/db.bin index 314a49264d77e02c18e2ca7377f5ad4de64251cd..0f34528c8cc35639f1980a0f0c769a063c6e113a 100644 GIT binary patch delta 259 zcmWN=$u0w70KoBlH5f}RwJ*gCYN@ePduwKlt>Ri&2bUfjjZ@?BPv$@mgiIaWcmwi1 zfauX%^wu}fi0_yDDlalrQEw51s6(Tk1{%?6qL~(23DZV99dr_*i*9=8rH_6F7-WcH zqKq)g7zQTeOfX4|DW;iWmN;`*%(K8EODwa(Dr>BhV1rGz*k*@a_DGUq|HH1=XG?@HFaaH?fXR?E5crQ7s!SB_oFNxPOWzGzYX%M*s~en#?P yEs#j+-=1(ozgArS+!Ru#me60D!U(#JWIpDYm4bS#o~T9jR6SGArCGW7$ovE9K4#kh diff --git a/assets/database/db.json b/assets/database/db.json index 8ea77aa85..da8f841f7 100644 --- a/assets/database/db.json +++ b/assets/database/db.json @@ -8742,8 +8742,8 @@ {"effectId":63,"spellId":13538,"name":"Enchant Chest - Lesser Absorption","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":66,"spellId":7457,"name":"Enchant Bracer - Minor Stamina","type":6,"stats":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":66,"spellId":7863,"name":"Enchant Boots - Minor Stamina","type":10,"stats":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, -{"effectId":241,"spellId":7745,"name":"Enchant 2H Weapon - Minor Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":241,"spellId":13503,"name":"Enchant Weapon - Lesser Striking","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, +{"effectId":241,"spellId":7745,"name":"Enchant 2H Weapon - Minor Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":242,"spellId":7748,"name":"Enchant Chest - Lesser Health","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":243,"spellId":7766,"name":"Enchant Bracer - Minor Spirit","type":6,"stats":[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":246,"spellId":7776,"name":"Enchant Chest - Lesser Mana","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, @@ -10471,8 +10471,10 @@ {"id":11255,"name":"Improved Counterspell","icon":"spell_frost_iceshock","rank":1}, {"id":11269,"name":"Ambush","icon":"ability_rogue_ambush","rank":6}, {"id":11275,"name":"Rupture","icon":"ability_rogue_rupture","rank":6,"hasBuff":true}, +{"id":11281,"name":"Backstab","icon":"ability_backstab","rank":8}, {"id":11290,"name":"Garrote","icon":"ability_rogue_garrote","rank":6,"hasBuff":true}, {"id":11294,"name":"Sinister Strike","icon":"spell_shadow_ritualofsacrifice","rank":8}, +{"id":11300,"name":"Eviscerate","icon":"ability_rogue_eviscerate","rank":8}, {"id":11306,"name":"Fire Nova","icon":"spell_fire_sealoffire","rank":4}, {"id":11307,"name":"Fire Nova","icon":"spell_fire_sealoffire","rank":5}, {"id":11314,"name":"Fire Nova Totem","icon":"spell_fire_sealoffire","rank":4}, @@ -12700,7 +12702,6 @@ {"id":25297,"name":"Healing Touch","icon":"spell_nature_healingtouch","rank":11}, {"id":25298,"name":"Starfire","icon":"spell_arcane_starfire","rank":7}, {"id":25299,"name":"Rejuvenation","icon":"spell_nature_rejuvenation","rank":11,"hasBuff":true}, -{"id":25300,"name":"Backstab","icon":"ability_backstab","rank":9}, {"id":25304,"name":"Frostbolt","icon":"spell_frost_frostbolt02","rank":11,"hasBuff":true}, {"id":25306,"name":"Fireball","icon":"spell_fire_flamebolt","rank":12,"hasBuff":true}, {"id":25307,"name":"Shadow Bolt","icon":"spell_shadow_shadowbolt","rank":10}, @@ -12872,7 +12873,6 @@ {"id":30906,"name":"Deadliness","icon":"inv_weapon_crossbow_11","rank":5}, {"id":30919,"name":"Weapon Expertise","icon":"spell_holy_blessingofstrength","rank":1}, {"id":30920,"name":"Weapon Expertise","icon":"spell_holy_blessingofstrength","rank":2}, -{"id":31016,"name":"Eviscerate","icon":"ability_rogue_eviscerate"}, {"id":31018,"name":"Ferocious Bite","icon":"ability_druid_ferociousbite"}, {"id":400574,"name":"Arcane Blast","icon":"spell_arcane_blast"}, {"id":400610,"name":"Arcane Barrage","icon":"ability_mage_arcanebarrage"}, diff --git a/assets/database/leftover_db.bin b/assets/database/leftover_db.bin index b3740b07f13ddb82e56cf521e4177c35dfd54617..120938f01b3ea650e74652ae2e2c54c3a5daf51d 100644 GIT binary patch delta 87 zcmZ4T-gwD-F7M2#)7Pc1l7LFFq7OocVEj$Li+mG<^Ok&(_z{@j*aeJ5m qPg?PI_g0>%jNA7#^K>(AzthH(roR2cdXR|II-Wkp?Wr4i?A-uVXCIUR delta 87 zcmZ4T-gwD-F7M2#)7Pc1l7LFFq7OocVEj$Li+Yj;aOkvz^z{@jjB?A-uWcpswx diff --git a/assets/database/leftover_db.json b/assets/database/leftover_db.json index e6326a0b5..6b2f85cf2 100644 --- a/assets/database/leftover_db.json +++ b/assets/database/leftover_db.json @@ -1511,8 +1511,8 @@ {"effectId":929,"itemId":16217,"spellId":20069,"name":"Enchant Shield - Greater Stamina","type":13,"enchantType":2,"stats":[0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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":930,"spellId":13947,"name":"Enchant Gloves - Riding Skill","type":7,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":931,"spellId":13948,"name":"Enchant Gloves - Minor Haste","type":7,"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":943,"spellId":13529,"name":"Enchant 2H Weapon - Lesser 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":943,"spellId":13693,"name":"Enchant Weapon - 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":943,"spellId":13529,"name":"Enchant 2H Weapon - Lesser 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":963,"spellId":13937,"name":"Enchant 2H Weapon - Greater 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":1483,"itemId":11622,"spellId":15340,"name":"Lesser Arcanum of Rumination","type":1,"extraTypes":[9],"enchantType":3,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":1503,"itemId":11642,"spellId":15389,"name":"Lesser Arcanum of Constitution","type":1,"extraTypes":[9],"enchantType":3,"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,100,0,0,0,0,0,0,0,0,0],"quality":2}, @@ -1538,8 +1538,8 @@ {"effectId":1893,"spellId":20028,"name":"Enchant Chest - Major Mana","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":1894,"spellId":20029,"name":"Enchant Weapon - Icy Chill","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":1896,"spellId":20030,"name":"Enchant 2H Weapon - Superior Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, -{"effectId":1897,"spellId":13695,"name":"Enchant 2H Weapon - Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":1897,"spellId":20031,"name":"Enchant Weapon - Superior Striking","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, +{"effectId":1897,"spellId":13695,"name":"Enchant 2H Weapon - Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1}, {"effectId":1898,"spellId":20032,"name":"Enchant Weapon - Lifestealing","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":3}, {"effectId":1899,"spellId":20033,"name":"Enchant Weapon - Unholy Weapon","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, {"effectId":1900,"spellId":20034,"name":"Enchant Weapon - Crusader","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2}, diff --git a/sim/common/vanilla/item_sets/dungeon_set_1.go b/sim/common/vanilla/item_sets/dungeon_set_1.go index 66fd5a9e7..0e120ce93 100644 --- a/sim/common/vanilla/item_sets/dungeon_set_1.go +++ b/sim/common/vanilla/item_sets/dungeon_set_1.go @@ -121,7 +121,7 @@ var ItemSetMagistersRegalia = core.NewItemSet(core.ItemSet{ }, // When struck in combat has a chance of freezing the attacker in place for 3 sec. 6: func(agent core.Agent) { - //Not implemented due to raid boss immunity + // No implementation in sim }, // +8 All Resistances. 8: func(agent core.Agent) { diff --git a/sim/mage/TestP1Mage.results b/sim/mage/TestP1Mage.results index 3df624e50..bf6ec44af 100644 --- a/sim/mage/TestP1Mage.results +++ b/sim/mage/TestP1Mage.results @@ -96,6 +96,76 @@ stat_weights_results: { weights: 0 } } +dps_results: { + key: "TestP1Mage-Phase1-AllItems-ArcanistRegalia" + value: { + dps: 97.10096 + tps: 90.36367 + } +} +dps_results: { + key: "TestP1Mage-Phase1-AllItems-Champion'sRegalia" + value: { + dps: 84.10533 + tps: 91.33828 + } +} +dps_results: { + key: "TestP1Mage-Phase1-AllItems-EnigmaVestments" + value: { + dps: 107.96625 + tps: 114.91555 + } +} +dps_results: { + key: "TestP1Mage-Phase1-AllItems-FieldMarshal'sRegalia" + value: { + dps: 106.14672 + tps: 113.43537 + } +} +dps_results: { + key: "TestP1Mage-Phase1-AllItems-FrostfireRegalia" + value: { + dps: 146.34232 + tps: 134.14575 + } +} +dps_results: { + key: "TestP1Mage-Phase1-AllItems-Illusionist'sAttire" + value: { + dps: 85.18755 + tps: 92.46523 + } +} +dps_results: { + key: "TestP1Mage-Phase1-AllItems-LieutenantCommander'sRegalia" + value: { + dps: 84.10533 + tps: 91.33828 + } +} +dps_results: { + key: "TestP1Mage-Phase1-AllItems-NetherwindRegalia" + value: { + dps: 107.93251 + tps: 101.39714 + } +} +dps_results: { + key: "TestP1Mage-Phase1-AllItems-Sorcerer'sRegalia" + value: { + dps: 92.73649 + tps: 100.01821 + } +} +dps_results: { + key: "TestP1Mage-Phase1-AllItems-Warlord'sRegalia" + value: { + dps: 106.14672 + tps: 113.43537 + } +} dps_results: { key: "TestP1Mage-Phase1-Average-Default" value: { diff --git a/sim/mage/_item_sets_pve.go b/sim/mage/_item_sets_pve.go deleted file mode 100644 index 5930dacde..000000000 --- a/sim/mage/_item_sets_pve.go +++ /dev/null @@ -1,484 +0,0 @@ -package mage - -import ( - "math" - "slices" - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" - "github.com/wowsims/classic/sim/core/stats" -) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 4 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetSorcerersRegalia = core.NewItemSet(core.ItemSet{ - Name: "Sorcerer's Regalia", - Bonuses: map[int32]core.ApplyEffect{ - // Increases damage and healing done by magical spells and effects by up to 23. - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.SpellPower, 23) - }, - // Your spellcasts have a 6% chance to energize you for 300 mana. - 4: func(agent core.Agent) { - c := agent.GetCharacter() - actionID := core.ActionID{SpellID: 450527} - manaMetrics := c.NewManaMetrics(actionID) - - core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ - Name: "S03 - Mana Proc on Cast - Magister's Regalia", - Callback: core.CallbackOnSpellHitDealt, - Outcome: core.OutcomeLanded, - ProcMask: core.ProcMaskSpellDamage | core.ProcMaskSpellHealing, - 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 ItemSetArcanistMoment = core.NewItemSet(core.ItemSet{ - Name: "Arcanist Moment", - Bonuses: map[int32]core.ApplyEffect{ - // Your Temporal Beacons last 20% longer. - 2: func(agent core.Agent) { - // Nothing to do - }, - // Increases all chronomantic healing you deal by 10%. - 4: func(agent core.Agent) { - // Nothing to do - }, - // Each time you heal a target with Regeneration, the remaining cooldown on Rewind Time is reduced by 1 sec. - 6: func(agent core.Agent) { - // Nothing to do - }, - }, -}) - -var ItemSetArcanistInsight = core.NewItemSet(core.ItemSet{ - Name: "Arcanist Insight", - Bonuses: map[int32]core.ApplyEffect{ - // You are immune to all damage while channeling Evocation. - 2: func(agent core.Agent) { - // May important later but for now nothing to do - }, - // You gain 1% increased damage for 15 sec each time you cast a spell from a different school of magic. - 4: func(agent core.Agent) { - // TODO: This is all a bit of an assumption about how this may work without having more information. - // We may need to rework it as we get more information - mage := agent.(MageAgent).GetMage() - - damageMultiplierPerSchool := 1.01 - auraDuration := time.Second * 15 - - arcaneAura := mage.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Mage - Damage 4P Bonus (Arcane)", - ActionID: core.ActionID{SpellID: 456398}.WithTag(int32(stats.SchoolIndexArcane)), - Duration: auraDuration, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - mage.PseudoStats.DamageDealtMultiplier *= damageMultiplierPerSchool - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - mage.PseudoStats.DamageDealtMultiplier /= damageMultiplierPerSchool - }, - }) - - fireAura := mage.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Mage - Damage 4P Bonus (Fire)", - ActionID: core.ActionID{SpellID: 456398}.WithTag(int32(stats.SchoolIndexFire)), - Duration: auraDuration, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - mage.PseudoStats.DamageDealtMultiplier *= damageMultiplierPerSchool - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - mage.PseudoStats.DamageDealtMultiplier /= damageMultiplierPerSchool - }, - }) - - frostAura := mage.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Mage - Damage 4P Bonus (Frost)", - ActionID: core.ActionID{SpellID: 456398}.WithTag(int32(stats.SchoolIndexFrost)), - Duration: auraDuration, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - mage.PseudoStats.DamageDealtMultiplier *= damageMultiplierPerSchool - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - mage.PseudoStats.DamageDealtMultiplier /= damageMultiplierPerSchool - }, - }) - - core.MakePermanent(mage.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Mage - Damage 4P Bonus", - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell.SpellSchool.Matches(core.SpellSchoolPhysical) { - return - } - if spell.SpellSchool.Matches(core.SpellSchoolArcane) { - arcaneAura.Activate(sim) - } - if spell.SpellSchool.Matches(core.SpellSchoolFire) { - fireAura.Activate(sim) - } - if spell.SpellSchool.Matches(core.SpellSchoolFrost) { - frostAura.Activate(sim) - } - }, - })) - }, - // Mage Armor increases your mana regeneration while casting by an additional 15%. Molten Armor increases your spell damage and healing by 18. Ice Armor grants 20% increased chance to trigger Fingers of Frost. - 6: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - - bonusFoFProcChance := .20 - bonusSpiritRegenRateCasting := .15 - bonusSpellPower := 18.0 - - core.MakePermanent(mage.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 456402}, - Label: "S03 - Item - T1 - Mage - Damage 6P Bonus", - BuildPhase: core.CharacterBuildPhaseBuffs, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - switch mage.Options.Armor { - case proto.Mage_Options_IceArmor: - mage.FingersOfFrostProcChance += bonusFoFProcChance - case proto.Mage_Options_MageArmor: - mage.PseudoStats.SpiritRegenRateCasting += bonusSpiritRegenRateCasting - case proto.Mage_Options_MoltenArmor: - if aura.Unit.Env.MeasuringStats && aura.Unit.Env.State != core.Finalized { - mage.AddStat(stats.SpellPower, bonusSpellPower) - } else { - mage.AddStatDynamic(sim, stats.SpellPower, bonusSpellPower) - } - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - switch mage.Options.Armor { - case proto.Mage_Options_IceArmor: - mage.FingersOfFrostProcChance -= bonusFoFProcChance - case proto.Mage_Options_MageArmor: - mage.PseudoStats.SpiritRegenRateCasting -= bonusSpiritRegenRateCasting - case proto.Mage_Options_MoltenArmor: - if mage.Options.Armor == proto.Mage_Options_MoltenArmor && aura.Unit.Env.MeasuringStats && aura.Unit.Env.State != core.Finalized { - mage.AddStat(stats.SpellPower, -bonusSpellPower) - } else { - mage.AddStatDynamic(sim, stats.SpellPower, -bonusSpellPower) - } - } - }, - })) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 5 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetNetherwindInsight = core.NewItemSet(core.ItemSet{ - Name: "Netherwind Insight", - Bonuses: map[int32]core.ApplyEffect{ - // Decreases the threat generated by your Fire spells by 20%. - 2: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - mage.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Mage - Damage 2P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range mage.Spellbook { - if spell.SpellSchool == core.SpellSchoolFire && spell.Flags.Matches(SpellFlagMage) { - spell.ThreatMultiplier *= .80 - } - } - }, - }) - }, - // Your Pyroblast deals 20% increased damage to targets afflicted with your Fireball's periodic effect. - 4: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - mage.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Mage - Damage 4P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - fireballSpells := core.FilterSlice(mage.Fireball, func(spell *core.Spell) bool { return spell != nil }) - - for _, spell := range mage.Pyroblast { - if spell == nil { - continue - } - - oldApplyEffects := spell.ApplyEffects - spell.ApplyEffects = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - multiplier := 1.0 - - for _, spell := range fireballSpells { - if spell.Dot(target).IsActive() { - multiplier *= 1.20 - break - } - } - - spell.DamageMultiplier *= multiplier - oldApplyEffects(sim, target, spell) - spell.DamageMultiplier /= multiplier - } - } - }, - }) - }, - // Your Fireball's periodic effect gains increased damage over its duration equal to 20% of its impact damage. - 6: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - mage.MaintainFireballDoT = true - core.MakePermanent(mage.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 467399}, - Label: "S03 - Item - T2 - Mage - Damage 6P Bonus", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_MageFireball && result.Landed() { - mage.BonusFireballDoTAmount += result.Damage * 1.00 / float64(spell.Dot(result.Target).NumberOfTicks) - } - }, - })) - }, - }, -}) - -var ItemSetNetherwindMoment = core.NewItemSet(core.ItemSet{ - Name: "Netherwind Moment", - Bonuses: map[int32]core.ApplyEffect{ - // Your Arcane Missiles refunds 10% of its base mana cost each time it deals damage. - 2: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - actionID := core.ActionID{SpellID: 467401} - manaMetrics := mage.NewManaMetrics(actionID) - core.MakePermanent(mage.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Mage - Healer 2P Bonus", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_MageArcaneMissilesTick && result.Landed() { - mage.AddMana(sim, mage.ArcaneMissiles[spell.Rank].Cost.BaseCost*0.1, manaMetrics) - } - }, - })) - }, - // Arcane Blast gains a 10% additional change to trigger Missile Barrage, and Missile Barrage now affects Regeneration the same way it affects Arcane Missiles. - 4: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - mage.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Mage - Healer 4P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - mage.ArcaneBlastMissileBarrageChance += .10 - }, - }) - }, - // Your Temporal Beacons caused by Mass Regeneration now last 30 sec. - 6: func(agent core.Agent) { - }, - }, -}) - -var ItemSetIllusionistsAttire = core.NewItemSet(core.ItemSet{ - Name: "Illusionist's Attire", - Bonuses: map[int32]core.ApplyEffect{ - // Increases damage done by Frost spells and effects by up to 14. - 2: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - mage.AddStat(stats.FrostPower, 14) - }, - // Increases the chance to trigger your Fingers of Frost rune by an additional 15%. - 3: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - mage.RegisterAura(core.Aura{ - Label: "S03 - Item - ZG - Mage - Frost 3P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - mage.FingersOfFrostProcChance += .15 - }, - }) - }, - // Increases damage done by your Frostbolt spell by 65%. - 5: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - mage.RegisterAura(core.Aura{ - Label: "S03 - Item - ZG - Mage - Frost 5P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range mage.Frostbolt { - if spell != nil { - spell.DamageMultiplier *= 1.65 - } - } - - if mage.SpellfrostBolt != nil { - mage.SpellfrostBolt.DamageMultiplier *= 1.65 - } - }, - }) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 6 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetEnigmaInsight = core.NewItemSet(core.ItemSet{ - Name: "Enigma Insight", - Bonuses: map[int32]core.ApplyEffect{ - // Your Fire Blast now also causes your next Fire spell to gain 50% increased critical strike chance for 10 sec. - 2: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - - var affectedSpells []*core.Spell - - buffAura := mage.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 1213317}, - Label: "Fire Blast", - Duration: time.Second * 10, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - affectedSpells = core.FilterSlice(mage.Spellbook, func(spell *core.Spell) bool { - return spell.Flags.Matches(SpellFlagMage) && spell.SpellSchool.Matches(core.SpellSchoolFire) && !spell.Flags.Matches(core.SpellFlagPassiveSpell) - }) - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.BonusCritRating += 50 * core.SpellCritRatingPerCritChance - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range affectedSpells { - spell.BonusCritRating -= 50 * core.SpellCritRatingPerCritChance - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - // OnCastComplete is called after OnSpellHitDealt / etc, so don't deactivate if it was just activated. - if aura.RemainingDuration(sim) == aura.Duration { - return - } - - if !slices.Contains(affectedSpells, spell) { - return - } - - core.StartDelayedAction(sim, core.DelayedActionOptions{ - DoAt: sim.CurrentTime + core.SpellBatchWindow, - OnAction: func(sim *core.Simulation) { - if aura.IsActive() { - aura.Deactivate(sim) - } - }, - }) - }, - }) - - core.MakePermanent(mage.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Mage - Fire 2P Bonus", - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell.SpellCode == SpellCode_MageFireBlast { - buffAura.Activate(sim) - } - }, - })) - }, - // Increases the damage done by your Ignite talent by 20%. - 4: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - if mage.Talents.Ignite == 0 { - return - } - - mage.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Mage - Fire 4P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - mage.Ignite.DamageMultiplier *= 1.20 - }, - }) - }, - }, -}) - -var ItemSetEnigmaMoment = core.NewItemSet(core.ItemSet{ - Name: "Enigma Moment", - Bonuses: map[int32]core.ApplyEffect{ - // Your Arcane Blast increases damage and healing done by an additional 10% per stack. - 2: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - mage.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Mage - Arcane 2P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - mage.ArcaneBlastDamageMultiplier += 0.10 - }, - }) - }, - // Your Mana Shield, Fire Ward, and Frost Ward absorb 50% more damage and also place a Temporal Beacon on the target for 30 sec. - 4: func(agent core.Agent) { - // Nothing to do - }, - }, -}) - -var ItemSetTrappingsOfVaultedSecrets = core.NewItemSet(core.ItemSet{ - Name: "Trappings of Vaulted Secrets", - Bonuses: map[int32]core.ApplyEffect{ - // Your Fireball, Frostfire Bolt, and Balefire Bolt spells gain 5% increased damage for each of your Fire effects on your target, up to a maximum increased of 20%. - 3: func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - - hasImprovedScorch := mage.Talents.ImprovedScorch > 0 - - mage.RegisterAura(core.Aura{ - Label: "S03 - Item - RAQ - Mage - Fire 3P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - dotSpells := core.FilterSlice(mage.Spellbook, func(spell *core.Spell) bool { - return spell.Flags.Matches(SpellFlagMage) && spell.SpellSchool.Matches(core.SpellSchoolFire) && len(spell.Dots()) > 0 - }) - - affectedSpells := core.FilterSlice( - core.Flatten( - [][]*core.Spell{ - mage.Fireball, - {mage.FrostfireBolt}, - {mage.BalefireBolt}, - }, - ), func(spell *core.Spell) bool { return spell != nil }, - ) - - for _, spell := range affectedSpells { - oldApplyEffects := spell.ApplyEffects - spell.ApplyEffects = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - multiplier := 1.0 - - for _, spell := range dotSpells { - if spell.Dot(target).IsActive() { - multiplier += 0.05 - } - } - - if hasImprovedScorch && mage.ImprovedScorchAuras.Get(target).IsActive() { - multiplier += 0.05 - } - - multiplier = math.Max(1.20, multiplier) - - // TODO: Additive or Multiplicative? - spell.DamageMultiplier *= multiplier - oldApplyEffects(sim, target, spell) - spell.DamageMultiplier /= multiplier - } - } - }, - }) - }, - }, -}) diff --git a/sim/mage/counterspell.go b/sim/mage/counterspell.go index 1d1ec34b1..d6e97ced4 100644 --- a/sim/mage/counterspell.go +++ b/sim/mage/counterspell.go @@ -9,7 +9,7 @@ import ( // This exists purely so that it can be used to extend the arcane buff from the mage T1 4pc // Not relevant in classic currently but will keep func (mage *Mage) registerCounterspellSpell() { - mage.RegisterSpell(core.SpellConfig{ + mage.Counterspell = mage.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 2139}, SpellSchool: core.SpellSchoolArcane, ProcMask: core.ProcMaskSpellDamage, diff --git a/sim/mage/evocation.go b/sim/mage/evocation.go index 2666ea7c8..b9e20c906 100644 --- a/sim/mage/evocation.go +++ b/sim/mage/evocation.go @@ -30,7 +30,7 @@ func (mage *Mage) registerEvocationCD() { }, }) - evocation := mage.GetOrRegisterSpell(core.SpellConfig{ + mage.Evocation = mage.GetOrRegisterSpell(core.SpellConfig{ ActionID: actionID, Flags: core.SpellFlagHelpful | core.SpellFlagChanneled | core.SpellFlagAPL, @@ -72,7 +72,7 @@ func (mage *Mage) registerEvocationCD() { }) mage.AddMajorCooldown(core.MajorCooldown{ - Spell: evocation, + Spell: mage.Evocation, Type: core.CooldownTypeMana, ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { if character.HasActiveAuraWithTag(core.InnervateAuraTag) || character.HasActiveAuraWithTag(core.ManaTideTotemAuraTag) { diff --git a/sim/mage/flamestrike.go b/sim/mage/flamestrike.go index faded12b9..c047d1307 100644 --- a/sim/mage/flamestrike.go +++ b/sim/mage/flamestrike.go @@ -50,6 +50,7 @@ func (mage *Mage) newFlamestrikeSpellConfig(rank int) core.SpellConfig { DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | core.SpellFlagAPL, + SpellCode: SpellCode_MageFlamestrike, RequiredLevel: level, Rank: rank, diff --git a/sim/mage/item_sets_pve.go b/sim/mage/item_sets_pve.go new file mode 100644 index 000000000..86e180c61 --- /dev/null +++ b/sim/mage/item_sets_pve.go @@ -0,0 +1,441 @@ +package mage + +import ( + "slices" + "time" + + "github.com/wowsims/classic/sim/core" + "github.com/wowsims/classic/sim/core/stats" +) + +/////////////////////////////////////////////////////////////////////////// +// Classic Phase 1 - Molten Core +/////////////////////////////////////////////////////////////////////////// + +var ItemSetArcanistRegalia = core.NewItemSet(core.ItemSet{ + Name: "Arcanist Regalia", + Bonuses: map[int32]core.ApplyEffect{ + // Increases damage and healing done by magical spells and effects by up to 18. + 3: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.SpellPower, 18) + }, + // Decreases the magical resistances of your spell targets by 10. + 5: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.SpellPenetration, 10) + }, + // Decreases the threat generated by your spells by 15%. + 8: func(agent core.Agent) { + mage := agent.(MageAgent).GetMage() + mage.RegisterAura(core.Aura{ + Label: "Subtlety", + ActionID: core.ActionID{SpellID: 23545}, + Duration: core.NeverExpires, + OnReset: func(aura *core.Aura, sim *core.Simulation){ + mage.PseudoStats.ThreatMultiplier /= 1.15 + }, + }) + }, + }, +}) + +/////////////////////////////////////////////////////////////////////////// +// Phase 2 Item Sets - Dire Maul +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// Phase 3 Item Sets - BWL +/////////////////////////////////////////////////////////////////////////// + +var ItemSetNetherwindRegalia = core.NewItemSet(core.ItemSet{ + Name: "Netherwind Regalia", + Bonuses: map[int32]core.ApplyEffect{ + // Reduces the threat generated by your Scorch, Arcane Missiles, Fireball, and Frostbolt spells. + 3: func(agent core.Agent) { + mage := agent.(MageAgent).GetMage() + mage.RegisterAura(core.Aura{ + Label: "Friendly Nukes", + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range mage.Spellbook { + if spell.SpellCode == SpellCode_MageFireball || spell.SpellCode == SpellCode_MageArcaneMissilesTick { + spell.FlatThreatBonus -= 20 + } + if spell.SpellCode == SpellCode_MageScorch || spell.SpellCode == SpellCode_MageFrostbolt { + spell.FlatThreatBonus -= 100 + } + } + }, + }) + }, + // Increases the radius of Arcane Explosion, Flamestrike, and Blizzard by 25%. + 5: func(agent core.Agent) { + // No implementation in sim + }, + // 10% chance after casting Arcane Missiles, Fireball, or Frostbolt that your next spell with a casting time under 10 seconds cast instantly. + 8: func(agent core.Agent) { + mage := agent.(MageAgent).GetMage() + actionID := core.ActionID{SpellID: 22008} + + affectedSpells := []*core.Spell{} + netherwindFocusAura := mage.RegisterAura(core.Aura{ + Label: "Netherwind Focus", + ActionID: actionID, + Duration: time.Second * 10, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for spellIdx := range mage.Spellbook { + if spell := mage.Spellbook[spellIdx]; spell.DefaultCast.CastTime > 0 && spell.DefaultCast.CastTime <= 10 { + affectedSpells = append(affectedSpells, spell) + } + } + }, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + core.Each(affectedSpells, func(spell *core.Spell) { + spell.CastTimeMultiplier -= 1 + }) + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + core.Each(affectedSpells, func(spell *core.Spell) { + spell.CastTimeMultiplier += 1 + }) + }, + OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { + if !slices.Contains(affectedSpells, spell) { + return + } + aura.Deactivate(sim) + }, + }) + + mage.RegisterAura(core.Aura{ + Label: "Netherwind Focus - Proc Aura", + Duration: core.NeverExpires, + OnReset: func(aura *core.Aura, sim *core.Simulation) { + aura.Activate(sim) + }, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if (spell.SpellCode == SpellCode_MageArcaneMissiles || spell.SpellCode == SpellCode_MageFireball || spell.SpellCode == SpellCode_MageFrostbolt) { + netherwindFocusAura.Activate(sim) + } + }, + }) + }, + }, +}) +/////////////////////////////////////////////////////////////////////////// +// Phase 4 Item Sets - ZG and AB +/////////////////////////////////////////////////////////////////////////// + +var ItemSetIllusionistsAttire = core.NewItemSet(core.ItemSet{ + Name: "Illusionist's Attire", + Bonuses: map[int32]core.ApplyEffect{ + // Increases damage and healing done by magical spells and effects by up to 12. + 2: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.SpellPower, 12) + }, + // Decreases the mana cost of Arcane Intellect and Arcane Brilliance by 5%. + 3: func(agent core.Agent) { + // No implementation in sim + }, + // Reduces the casting time of your Flamestrike spell by 0.5 sec. + 5: func(agent core.Agent) { + mage := agent.(MageAgent).GetMage() + mage.RegisterAura(core.Aura{ + Label: "Improved Flamestrike", + ActionID: core.ActionID{SpellID: 24491}, + Duration: core.NeverExpires, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range mage.Spellbook { + if spell.SpellCode == SpellCode_MageFlamestrike { + spell.DefaultCast.CastTime -= time.Millisecond * 500 + spell.DefaultCast.GCD -= time.Millisecond * 500 + } + } + }, + }) + }, + }, +}) + +/////////////////////////////////////////////////////////////////////////// +// Phase 5 Item Sets - AQ +/////////////////////////////////////////////////////////////////////////// + + +var ItemSetSorcerersRegalia = core.NewItemSet(core.ItemSet{ + Name: "Sorcerer's Regalia", + Bonuses: map[int32]core.ApplyEffect{ + // +8 All Resistances. + 2: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddResistances(8) + }, + // Your spellcasts have a 6% chance to energize you for 300 mana. + 4: func(agent core.Agent) { + // No implementation in sim + }, + // Increases damage and healing done by magical spells and effects by up to 23. + 6: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.SpellPower, 23) + }, + // +200 Armor. + 8: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.Armor, 200) + }, + }, +}) + +var ItemSetEnigmaVestments = core.NewItemSet(core.ItemSet{ + Name: "Enigma Vestments", + Bonuses: map[int32]core.ApplyEffect{ + // Your Blizzard spell has a 30% chance to be uninterruptible. + 3: func(agent core.Agent) { + // No implementation in sim + }, + // Grants +5% increased spell hit chance for 20 sec when one of your spells is resisted. + 5: func(agent core.Agent) { + mage := agent.(MageAgent).GetMage() + actionID := core.ActionID{SpellID: 26129} + + enigmasAnswerAura := mage.RegisterAura(core.Aura{ + Label: "Enigma's Answer", + ActionID: actionID, + Duration: time.Second * 20, + MaxStacks: 4, + OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) { + mage.AddStatDynamic(sim, stats.SpellHit, float64(-5 * oldStacks)) + mage.AddStatDynamic(sim, stats.SpellHit, float64(5 * newStacks)) + }, + }) + + // Wowhead suggests this does not work on all spell (imp scorch and arcane missiles). Would need testing to confirm. + mage.RegisterAura(core.Aura{ + Label: "Enigma Resist Bonus", + Duration: core.NeverExpires, + OnReset: func(aura *core.Aura, sim *core.Simulation) { + aura.Activate(sim) + }, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if result.Outcome.Matches(core.OutcomeMiss) && spell.ProcMask.Matches(core.ProcMaskDirect) { + enigmasAnswerAura.Activate(sim) + enigmasAnswerAura.AddStack(sim) + } + }, + }) + }, + }, +}) + +/////////////////////////////////////////////////////////////////////////// +// Phase 6 Item Sets - Naxx +/////////////////////////////////////////////////////////////////////////// + +var ItemSetFrostfireRegalia = core.NewItemSet(core.ItemSet{ + Name: "Frostfire Regalia", + Bonuses: map[int32]core.ApplyEffect{ + // Reduces cooldown on your Evocation by 1 minute. + 2: func(agent core.Agent) { + mage := agent.(MageAgent).GetMage() + mage.RegisterAura(core.Aura{ + Label: "Evocation", + OnInit: func(aura *core.Aura, sim *core.Simulation) { + if mage.Evocation != nil { + mage.Evocation.CD.Duration -= time.Second * 60 + } + }, + }) + }, + // Gives your Mage Armor a chance when struck by a harmful spell to increase resistance against that school of magic by 35 for 30 sec. (Proc chance: 20%) + // Fire - https://www.wowhead.com/classic/spell=28765/fire-resistance + // Frost - https://www.wowhead.com/classic/spell=28766/frost-resistance + // Nature - https://www.wowhead.com/classic/spell=28768/nature-resistance + // Shadow - https://www.wowhead.com/classic/spell=28769/shadow-resistance + // Arcane - https://www.wowhead.com/classic/spell=28770/arcane-resistance + + 4: func(agent core.Agent) { + mage := agent.(MageAgent).GetMage() + + fireWardingAura := mage.RegisterAura(core.Aura{ + Label: "Fire Resistance", + ActionID: core.ActionID{SpellID: 28765}, + Duration: time.Second * 30, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + mage.AddStatDynamic(sim, stats.FireResistance, 35) + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + mage.AddStatDynamic(sim, stats.FireResistance, -35) + }, + }) + + frostWardingAura := mage.RegisterAura(core.Aura{ + Label: "Frost Resistance", + ActionID: core.ActionID{SpellID: 28766}, + Duration: time.Second * 30, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + mage.AddStatDynamic(sim, stats.FrostResistance, 35) + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + mage.AddStatDynamic(sim, stats.FrostResistance, -35) + }, + }) + + natureWardingAura := mage.RegisterAura(core.Aura{ + Label: "Nature Resistance", + ActionID: core.ActionID{SpellID: 28768}, + Duration: time.Second * 30, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + mage.AddStatDynamic(sim, stats.NatureResistance, 35) + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + mage.AddStatDynamic(sim, stats.NatureResistance, -35) + }, + }) + + shadowWardingAura := mage.RegisterAura(core.Aura{ + Label: "Shadow Resistance", + ActionID: core.ActionID{SpellID: 28769}, + Duration: time.Second * 30, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + mage.AddStatDynamic(sim, stats.ShadowResistance, 35) + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + mage.AddStatDynamic(sim, stats.ShadowResistance, -35) + }, + }) + + arcaneWardingAura := mage.RegisterAura(core.Aura{ + Label: "Arcane Resistance", + ActionID: core.ActionID{SpellID: 28770}, + Duration: time.Second * 30, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + mage.AddStatDynamic(sim, stats.ArcaneResistance, 35) + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + mage.AddStatDynamic(sim, stats.ArcaneResistance, -35) + }, + }) + + // Wowhead suggests this does not work on all spell (imp scorch and arcane missiles). Would need testing to confirm. + mage.RegisterAura(core.Aura{ + Label: "Adaptive Warding", + Duration: core.NeverExpires, + OnReset: func(aura *core.Aura, sim *core.Simulation) { + aura.Activate(sim) + }, + OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + if sim.Proc(0.20, "Adaptive Warding") { + if spell.SpellSchool.Matches(core.SpellSchoolFire) { + fireWardingAura.Activate(sim) + return + } + if spell.SpellSchool.Matches(core.SpellSchoolFrost) { + frostWardingAura.Activate(sim) + return + } + if spell.SpellSchool.Matches(core.SpellSchoolNature) { + natureWardingAura.Activate(sim) + return + } + if spell.SpellSchool.Matches(core.SpellSchoolShadow) { + shadowWardingAura.Activate(sim) + return + } + if spell.SpellSchool.Matches(core.SpellSchoolArcane) { + arcaneWardingAura.Activate(sim) + return + } + } + }, + }) + }, + // Your damage spells have a chance to cause your target to take up to 200 increased damage from subsequent spells. (Proc chance: 20%) + 6: func(agent core.Agent) { + mage := agent.(MageAgent).GetMage() + + procAuras := mage.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { + return target.GetOrRegisterAura(core.Aura{ + Label: "Elemental Vulnerability", + ActionID: core.ActionID{SpellID: 28772}, + Duration: time.Second * 30, + MaxStacks: 1, + + OnGain: func(aura *core.Aura, sim *core.Simulation) { + aura.SetStacks(sim, aura.MaxStacks) + + for si := stats.SchoolIndexArcane; si < stats.SchoolLen; si++ { + aura.Unit.PseudoStats.SchoolBonusDamageTaken[si] += 200 + } + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + for si := stats.SchoolIndexArcane; si < stats.SchoolLen; si++ { + aura.Unit.PseudoStats.SchoolBonusDamageTaken[si] -= 200 + } + }, + OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + // OnCastComplete is called after OnSpellHitDealt / etc, so don't deactivate if it was just activated. + if aura.RemainingDuration(sim) == aura.Duration { + return + } + + if result.Landed() && spell.ProcMask.Matches(core.ProcMaskDirect) { + aura.RemoveStack(sim) + } + }, + }) + }) + + handler := func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + procAuras.Get(result.Target).Activate(sim) + } + + core.MakeProcTriggerAura(&mage.Unit, core.ProcTrigger{ + ActionID: core.ActionID{SpellID: 28771}, + Name: "Elemental Vulnerability", + Callback: core.CallbackOnSpellHitDealt, + Outcome: core.OutcomeLanded, + ProcMask: core.ProcMaskSpellDamage, + ProcChance: 0.2, + Handler: handler, + }) + }, + // Your damage spells have a chance to displace you, causing the next spell cast to generate no threat. (Proc chance: 15%) + 8: func(agent core.Agent) { + mage := agent.(MageAgent).GetMage() + + notThereAura := mage.RegisterAura(core.Aura{ + Label: "Not There", + ActionID: core.ActionID{SpellID: 28762}, + Duration: time.Second * 8, + OnGain: func(aura *core.Aura, sim *core.Simulation) { + mage.PseudoStats.ThreatMultiplier -= 1 + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + mage.PseudoStats.ThreatMultiplier += 1 + }, + OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { + // OnCastComplete is called after OnSpellHitDealt / etc, so don't deactivate if it was just activated. + if aura.RemainingDuration(sim) == aura.Duration { + return + } + aura.Deactivate(sim) + }, + }) + + mage.RegisterAura(core.Aura{ + Label: "NotThere", + Duration: core.NeverExpires, + OnReset: func(aura *core.Aura, sim *core.Simulation) { + aura.Activate(sim) + }, + OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult){ + if sim.Proc(0.15, "Not There") && result.Landed() && spell.ProcMask.Matches(core.ProcMaskDirect) { + notThereAura.Activate(sim) + } + }, + }) + }, + }, +}) \ No newline at end of file diff --git a/sim/mage/_item_sets_pvp.go b/sim/mage/item_sets_pvp.go similarity index 100% rename from sim/mage/_item_sets_pvp.go rename to sim/mage/item_sets_pvp.go diff --git a/sim/mage/items.go b/sim/mage/items.go index fd9d40c87..79a42955c 100644 --- a/sim/mage/items.go +++ b/sim/mage/items.go @@ -9,12 +9,9 @@ import ( const ( FireRuby = 20036 - // StaffOfOrder = 229909 - // StaffOfInferno = 229971 - // StaffOfRime = 229972 - // MindQuickeningGem = 230243 - // HazzarahsCharmOfChilledMagic = 231282 - // JewelOfKajaro = 231324 + MindQuickeningGem = 19339 + HazzarahsCharmOfMagic = 19959 + JewelOfKajaro = 19601 ) func init() { @@ -67,26 +64,24 @@ func init() { }) }) - // https://www.wowhead.com/classic/item=231282/hazzarahs-charm-of-chilled-magic - // Use: Increases the critical hit chance of your Frostbolt and Frozen Orb spells by 5%, and increases the critical hit damage of your Frostbolt and Frozen Orb spells by 50% for 20 sec. - // (2 Min Cooldown) - /* core.NewItemEffect(HazzarahsCharmOfChilledMagic, func(agent core.Agent) { + // https://www.wowhead.com/classic/item=19959/hazzarahs-charm-of-magic + // Increases the critical hit chance of your Arcane spells by 5%, and increases the critical hit damage of your Arcane spells by 50% for 20 sec. + // (3 Min Cooldown) + core.NewItemEffect(HazzarahsCharmOfMagic, func(agent core.Agent) { mage := agent.(MageAgent).GetMage() duration := time.Second * 20 affectedSpells := []*core.Spell{} aura := mage.RegisterAura(core.Aura{ - ActionID: core.ActionID{ItemID: HazzarahsCharmOfChilledMagic}, - Label: "Frost Potency", + ActionID: core.ActionID{SpellID: 24544}, + Label: "Arcane Potency", Duration: duration, OnInit: func(aura *core.Aura, sim *core.Simulation) { - affectedSpells = core.FilterSlice( - core.Flatten([][]*core.Spell{mage.Frostbolt, {mage.SpellfrostBolt}}), func(spell *core.Spell) bool { return spell != nil }, - ) - - if mage.HasRune(proto.MageRune_RuneCloakFrozenOrb) { - affectedSpells = append(affectedSpells, core.MapSlice(mage.frozenOrbPets, func(orb *FrozenOrb) *core.Spell { return orb.FrozenOrbTick })...) + for spellIdx := range mage.Spellbook { + if spell := mage.Spellbook[spellIdx]; spell.SpellSchool == core.SpellSchoolArcane { + affectedSpells = append(affectedSpells, spell) + } } }, OnGain: func(aura *core.Aura, sim *core.Simulation) { @@ -104,13 +99,13 @@ func init() { }) spell := mage.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{ItemID: HazzarahsCharmOfChilledMagic}, + ActionID: core.ActionID{ItemID: HazzarahsCharmOfMagic}, SpellSchool: core.SpellSchoolArcane, Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagOffensiveEquipment, Cast: core.CastConfig{ CD: core.Cooldown{ Timer: mage.NewTimer(), - Duration: time.Minute * 2, + Duration: time.Minute * 3, }, SharedCD: core.Cooldown{ Timer: mage.GetOffensiveTrinketCD(), @@ -129,23 +124,20 @@ func init() { }) }) - // https://www.wowhead.com/classic/item=231324/jewel-of-kajaro - // Equip: Reduces the cooldown on your Frozen Orb spell by 10 sec. + // https://www.wowhead.com/classic/item=19601/jewel-of-kajaro + // Equip: Reduces the cooldown of Counterspell by 2 sec. core.NewItemEffect(JewelOfKajaro, func(agent core.Agent) { mage := agent.(MageAgent).GetMage() - if !mage.HasRune(proto.MageRune_RuneCloakFrozenOrb) { - return - } mage.RegisterAura(core.Aura{ - Label: "Decreased Frozen Orb Cooldown", + Label: "Improved Counterspell", OnInit: func(aura *core.Aura, sim *core.Simulation) { - mage.FrozenOrb.CD.Duration -= time.Second * 10 + mage.Counterspell.CD.Duration -= time.Second * 2 }, }) }) - // https://www.wowhead.com/classic/item=230243/mind-quickening-gem + // https://www.wowhead.com/classic/item=19339/mind-quickening-gem // Use: Quickens the mind, increasing the Mage's casting speed of non-channeled spells by 33% for 20 sec. (2 Min Cooldown) core.NewItemEffect(MindQuickeningGem, func(agent core.Agent) { mage := agent.(MageAgent).GetMage() @@ -154,7 +146,7 @@ func init() { duration := time.Second * 20 buffAura := mage.RegisterAura(core.Aura{ - ActionID: actionID, + ActionID: core.ActionID{SpellID: 23723}, Label: "Mind Quickening", Duration: duration, OnGain: func(aura *core.Aura, sim *core.Simulation) { @@ -171,7 +163,7 @@ func init() { Cast: core.CastConfig{ CD: core.Cooldown{ Timer: mage.NewTimer(), - Duration: time.Minute * 2, + Duration: time.Minute * 5, }, SharedCD: core.Cooldown{ Timer: mage.GetOffensiveTrinketCD(), @@ -190,84 +182,5 @@ func init() { }) }) - // https://www.wowhead.com/classic/item=229971/staff-of-inferno - // Equip: When Improved Scorch is talented, targets hit by your Blast Wave will also have 5 stacks of Fire Vulnerability applied to them. - core.NewItemEffect(StaffOfInferno, func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - if mage.Talents.ImprovedScorch == 0 { - return - } - - core.MakePermanent(mage.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 469237}, - Label: "Staff of Inferno", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_MageBlastWave && result.Landed() { - aura := mage.ImprovedScorchAuras.Get(result.Target) - aura.Activate(sim) - aura.SetStacks(sim, 5) - } - }, - })) - }) - - core.NewItemEffect(StaffOfOrder, func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - if !mage.Talents.PresenceOfMind { - return - } - - core.MakePermanent(mage.RegisterAura(core.Aura{ - Label: "Staff of Order", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellSchool == core.SpellSchoolArcane && spell.ProcMask.Matches(core.ProcMaskSpellDamage) && result.Landed() { - mage.PresenceOfMind.CD.Set(mage.PresenceOfMind.CD.ReadyAt() - time.Second) - } - }, - })) - }) - - core.NewItemEffect(StaffOfRime, func(agent core.Agent) { - mage := agent.(MageAgent).GetMage() - if !mage.Talents.IceBarrier { - return - } - - statsAura := mage.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 469238}, - Label: "Staff of Rime", - Duration: time.Minute, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - mage.AddStatDynamic(sim, stats.FrostPower, 100) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - mage.AddStatDynamic(sim, stats.FrostPower, -100) - }, - }) - - mage.RegisterAura(core.Aura{ - Label: "Staff of Rime Dummy", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, aura := range mage.IceBarrierAuras { - if aura == nil { - continue - } - - oldOnGain := aura.OnGain - aura.OnGain = func(aura *core.Aura, sim *core.Simulation) { - oldOnGain(aura, sim) - statsAura.Activate(sim) - } - - oldOnExpire := aura.OnExpire - aura.OnExpire = func(aura *core.Aura, sim *core.Simulation) { - oldOnExpire(aura, sim) - statsAura.Deactivate(sim) - } - } - }, - }) - }) */ - core.AddEffectsToTest = true } diff --git a/sim/mage/mage.go b/sim/mage/mage.go index 8944e68aa..b7db349b9 100644 --- a/sim/mage/mage.go +++ b/sim/mage/mage.go @@ -20,6 +20,7 @@ const ( SpellCode_MageBlastWave SpellCode_MageFireball SpellCode_MageFireBlast + SpellCode_MageFlamestrike SpellCode_MageFrostbolt SpellCode_MageIgnite SpellCode_MageScorch @@ -57,6 +58,8 @@ type Mage struct { ArcaneMissilesTickSpell []*core.Spell BlastWave []*core.Spell Blizzard []*core.Spell + Counterspell *core.Spell + Evocation *core.Spell Fireball []*core.Spell FireBlast []*core.Spell Flamestrike []*core.Spell diff --git a/sim/warlock/dps/TestWarlockDSRuin.results b/sim/warlock/dps/TestWarlockDSRuin.results index 695113d49..ea3a204c1 100644 --- a/sim/warlock/dps/TestWarlockDSRuin.results +++ b/sim/warlock/dps/TestWarlockDSRuin.results @@ -106,8 +106,8 @@ dps_results: { dps_results: { key: "TestWarlockDSRuin-Phase1-AllItems-DeathmistRaiment" value: { - dps: 861.87319 - tps: 922.49357 + dps: 793.71062 + tps: 846.83968 } } dps_results: { @@ -155,8 +155,8 @@ dps_results: { dps_results: { key: "TestWarlockDSRuin-Phase1-AllItems-PlagueheartRaiment" value: { - dps: 1007.47674 - tps: 1069.18079 + dps: 941.36791 + tps: 996.27398 } } dps_results: { diff --git a/sim/warlock/dps/TestWarlockSMRuin.results b/sim/warlock/dps/TestWarlockSMRuin.results index 0fe707b71..bd91e54a1 100644 --- a/sim/warlock/dps/TestWarlockSMRuin.results +++ b/sim/warlock/dps/TestWarlockSMRuin.results @@ -106,8 +106,8 @@ dps_results: { dps_results: { key: "TestWarlockSMRuin-Phase1-AllItems-DeathmistRaiment" value: { - dps: 1080.97179 - tps: 903.66134 + dps: 993.7709 + tps: 821.18879 } } dps_results: { @@ -155,8 +155,8 @@ dps_results: { dps_results: { key: "TestWarlockSMRuin-Phase1-AllItems-PlagueheartRaiment" value: { - dps: 1235.01715 - tps: 1049.06851 + dps: 1138.48078 + tps: 955.41236 } } dps_results: { diff --git a/tools/database/gen_db/main.go b/tools/database/gen_db/main.go index 9583aab2e..d1a11f2d4 100644 --- a/tools/database/gen_db/main.go +++ b/tools/database/gen_db/main.go @@ -529,10 +529,10 @@ func GetPhaseData(item *proto.UIItem) int32 { if dropSource != nil { // Zone IDs as defined by WoWHead - does NOT match the in-game Zone ID! // P1 - Molten Core, Ony - if slices.Contains([]int32{2717, 2159}, dropSource.ZoneId) { + if slices.Contains([]int32{2717, 2159}, dropSource.ZoneId) || dropSource.NpcId == 10184 { return 1 } - + // P2 - Dire Maul if dropSource.ZoneId == 2557 { return 2 diff --git a/ui/core/proto_utils/names.ts b/ui/core/proto_utils/names.ts index 8312ff539..9d023e002 100644 --- a/ui/core/proto_utils/names.ts +++ b/ui/core/proto_utils/names.ts @@ -324,12 +324,12 @@ export const sourceNames: Map = new Map([ export const raidNames: Map = new Map([ [RaidFilterOption.RaidUnknown, 'Unknown'], - [RaidFilterOption.RaidMoltenCore, "Molten Core"], + [RaidFilterOption.RaidMoltenCore, 'Molten Core'], [RaidFilterOption.RaidOnyxiasLair, "Onyxia's Lair"], - [RaidFilterOption.RaidBlackwingLair, "Blackwing Lair"], + [RaidFilterOption.RaidBlackwingLair, 'Blackwing Lair'], [RaidFilterOption.RaidZulGurub, "Zul'Gurub"], - [RaidFilterOption.RaidRuinsOfAQ, "AQ 20"], - [RaidFilterOption.RaidTempleOfAQ, "AQ 40"], + [RaidFilterOption.RaidRuinsOfAQ, 'AQ 20'], + [RaidFilterOption.RaidTempleOfAQ, 'AQ 40'], [RaidFilterOption.RaidNaxxramas, 'Naxxramas'], ]);