diff --git a/assets/img/tank_warlock_background.jpg b/assets/img/tank_warlock_background.jpg deleted file mode 100644 index e07233e64..000000000 Binary files a/assets/img/tank_warlock_background.jpg and /dev/null differ diff --git a/makefile b/makefile index 6516a8005..9d6f460a5 100644 --- a/makefile +++ b/makefile @@ -25,7 +25,6 @@ HTML_INDECIES := ui/balance_druid/index.html \ ui/healing_priest/index.html \ ui/shadow_priest/index.html \ ui/warlock/index.html \ - ui/tank_warlock/index.html \ ui/warrior/index.html \ ui/tank_warrior/index.html \ ui/raid/index.html \ diff --git a/proto/api.proto b/proto/api.proto index 6d06c6e0a..280e83d25 100644 --- a/proto/api.proto +++ b/proto/api.proto @@ -15,7 +15,7 @@ import "shaman.proto"; import "warlock.proto"; import "warrior.proto"; -// NextIndex: 49 +// NextIndex: 47 message Player { // Label used for logging. string name = 1; @@ -76,9 +76,8 @@ message Player { ElementalShaman elemental_shaman = 33; EnhancementShaman enhancement_shaman = 34; RestorationShaman restoration_shaman = 35; - WardenShaman warden_shaman = 47; + WardenShaman warden_shaman = 39; Warlock warlock = 36; - TankWarlock tank_warlock = 39; Warrior warrior = 37; TankWarrior tank_warrior = 38; } diff --git a/proto/common.proto b/proto/common.proto index a2d0679b0..febbcb396 100644 --- a/proto/common.proto +++ b/proto/common.proto @@ -3,7 +3,7 @@ package proto; option go_package = "./proto"; -// NextIndex: 24 +// NextIndex: 23 enum Spec { SpecBalanceDruid = 0; SpecFeralDruid = 12; @@ -12,7 +12,7 @@ enum Spec { SpecElementalShaman = 1; SpecEnhancementShaman = 9; SpecRestorationShaman = 19; - SpecWardenShaman = 23; + SpecWardenShaman = 21; SpecHunter = 8; SpecMage = 2; SpecHolyPaladin = 20; @@ -23,7 +23,6 @@ enum Spec { SpecHealingPriest = 17; SpecShadowPriest = 4; SpecWarlock = 5; - SpecTankWarlock = 21; SpecWarrior = 6; SpecTankWarrior = 11; } diff --git a/proto/warlock.proto b/proto/warlock.proto index 2021b5120..b47cded01 100644 --- a/proto/warlock.proto +++ b/proto/warlock.proto @@ -61,46 +61,6 @@ message WarlockTalents { bool conflagrate = 50; } -enum WarlockRune { - WarlockRuneNone = 0; - - RuneHelmVengeance = 426195; - RuneHelmPandemic = 427712; - RuneHelmBackdraft = 427713; - - RuneCloakMarkOfChaos = 440892; - RuneCloakInfernalArmor = 440882; - RuneCloakSoulSiphon = 403511; - - RuneChestLakeOfFire = 403666; - RuneChestMasterChanneler = 403668; - RuneChestDemonicTactics = 412727; - - RuneBracerUnstableAffliction = 427717; - RuneBracerImmolationAura = 427726; - RuneBracerIncinerate = 412758; - RuneBracerSummonFelguard = 427733; - - RuneHandsHaunt = 403501; - RuneHandsChaosBolt = 403629; - RuneHandsShadowBoltVolley = 403628; - RuneHandsMetamorphosis = 403789; - - RuneBeltInvocation = 426243; - RuneBeltGrimoireOfSynergy = 426301; - RuneBeltShadowAndFlame = 426316; - - RuneLegsEverlastingAffliction = 412689; - RuneLegsDemonicGrace = 425463; - RuneLegsDemonicPact = 425464; - - RuneBootsDemonicKnowledge = 412732; - RuneBootsDanceOfTheWicked = 412798; - RuneBootsShadowflame = 426320; - RuneBootsDecimation = 440870; - -} - message WarlockRotation { } @@ -111,13 +71,11 @@ message WarlockOptions { Voidwalker = 2; Succubus = 3; Felhunter = 4; - Felguard = 5; } enum Armor { NoArmor = 0; DemonArmor = 1; - FelArmor = 2; } enum WeaponImbue { diff --git a/sim/common/vanilla/item_sets/crafted.go b/sim/common/vanilla/item_sets/crafted.go index 2c7806d86..4af7c4228 100644 --- a/sim/common/vanilla/item_sets/crafted.go +++ b/sim/common/vanilla/item_sets/crafted.go @@ -2,6 +2,7 @@ package item_sets import ( "github.com/wowsims/classic/sim/core" + "github.com/wowsims/classic/sim/core/proto" "github.com/wowsims/classic/sim/core/stats" ) @@ -63,9 +64,11 @@ var ItemSetBloodvineGarb = core.NewItemSet(core.ItemSet{ Name: "Bloodvine Garb", Bonuses: map[int32]core.ApplyEffect{ // Improves your chance to get a critical strike with spells by 2%. - 2: func(agent core.Agent) { + 3: func(agent core.Agent) { character := agent.GetCharacter() - character.AddStat(stats.SpellCrit, 2*core.SpellCritRatingPerCritChance) + if character.HasProfession(proto.Profession_Tailoring) { + character.AddStat(stats.SpellCrit, 2*core.SpellCritRatingPerCritChance) + } }, }, }) diff --git a/sim/register_all.go b/sim/register_all.go index d8882b131..aa23374f7 100644 --- a/sim/register_all.go +++ b/sim/register_all.go @@ -25,7 +25,6 @@ import ( // restoShaman "github.com/wowsims/classic/sim/shaman/restoration" dpsWarlock "github.com/wowsims/classic/sim/warlock/dps" - tankWarlock "github.com/wowsims/classic/sim/warlock/tank" dpsWarrior "github.com/wowsims/classic/sim/warrior/dps_warrior" tankWarrior "github.com/wowsims/classic/sim/warrior/tank_warrior" ) @@ -58,5 +57,4 @@ func RegisterAll() { protection.RegisterProtectionPaladin() retribution.RegisterRetributionPaladin() dpsWarlock.RegisterDpsWarlock() - tankWarlock.RegisterTankWarlock() } diff --git a/sim/warlock/_item_sets_pve.go b/sim/warlock/_item_sets_pve.go deleted file mode 100644 index 66db12422..000000000 --- a/sim/warlock/_item_sets_pve.go +++ /dev/null @@ -1,603 +0,0 @@ -package warlock - -import ( - "slices" - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" - "github.com/wowsims/classic/sim/core/stats" -) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 3 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetNightmareProphetsGarb = core.NewItemSet(core.ItemSet{ - Name: "Nightmare Prophet's Garb", - Bonuses: map[int32]core.ApplyEffect{ - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.MeleeHit, 1) - c.AddStat(stats.SpellHit, 1) - }, - 3: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - warlock.shadowSparkAura = warlock.GetOrRegisterAura(core.Aura{ - Label: "Shadow Spark Proc", - ActionID: core.ActionID{SpellID: 450013}, - Duration: time.Second * 12, - MaxStacks: 2, - }) - - core.MakePermanent(warlock.GetOrRegisterAura(core.Aura{ - Label: "Shadow Spark", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_WarlockShadowCleave && result.Landed() { - warlock.shadowSparkAura.Activate(sim) - warlock.shadowSparkAura.AddStack(sim) - } - }, - })) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 4 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetDeathmistRaiment = core.NewItemSet(core.ItemSet{ - Name: "Deathmist Raiment", - 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 melee autoattacks and spellcasts have a 6% chance to heal you for 270 to 330 health. - 4: func(agent core.Agent) { - c := agent.GetCharacter() - manaMetrics := c.NewManaMetrics(core.ActionID{SpellID: 450583}) - - handler := func(sim *core.Simulation, spell *core.Spell, _ *core.SpellResult) { - if c.HasManaBar() { - c.AddMana(sim, sim.Roll(270, 300), manaMetrics) - } - } - - core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ - Name: "S03 - Heal Proc on Cast - Dreadmist Raiment (Melee Auto)", - Callback: core.CallbackOnSpellHitDealt, - Outcome: core.OutcomeLanded, - ProcMask: core.ProcMaskWhiteHit, - ProcChance: 0.06, - Handler: handler, - }) - core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ - Name: "S03 - Heal Proc on Cast - Dreadmist Raiment (Spell Cast)", - Callback: core.CallbackOnCastComplete, - ProcMask: core.ProcMaskSpellDamage | core.ProcMaskSpellHealing, - ProcChance: 0.06, - Handler: handler, - }) - }, - // +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 ItemSetCorruptedFelheart = core.NewItemSet(core.ItemSet{ - Name: "Corrupted Felheart", - Bonuses: map[int32]core.ApplyEffect{ - // Lifetap generates 50% more mana and 100% less threat. - 2: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Warlock - Damage 2P Bonus", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.LifeTap { - spell.DamageMultiplier *= 1.5 - spell.ThreatMultiplier *= -1 - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.LifeTap { - spell.DamageMultiplier /= 1.5 - spell.ThreatMultiplier *= -1 - } - }, - }) - }, - // Increases your critical strike chance with spells and attacks by 2%. - 4: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStats(stats.Stats{ - stats.MeleeCrit: 2 * core.CritRatingPerCritChance, - stats.SpellCrit: 2 * core.CritRatingPerCritChance, - }) - }, - // Your Nightfall talent has a 4% increased chance to trigger. - // Incinerate has a 4% chance to trigger the Warlock’s Decimation. - 6: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - warlock6pt1Aura := warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Warlock - Damage 6P Bonus", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnGain: func(_ *core.Aura, _ *core.Simulation) { - warlock.nightfallProcChance += 0.04 - }, - OnExpire: func(_ *core.Aura, _ *core.Simulation) { - warlock.nightfallProcChance -= 0.04 - }, - }) - - if !warlock.HasRune(proto.WarlockRune_RuneBracerIncinerate) || !warlock.HasRune(proto.WarlockRune_RuneBootsDecimation) { - return - } - - warlock6pt1Aura.OnSpellHitDealt = func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_WarlockIncinerate && result.Landed() && sim.Proc(.04, "T1 6P Incinerate Proc") { - warlock.DecimationAura.Activate(sim) - } - } - }, - }, -}) - -var ItemSetWickedFelheart = core.NewItemSet(core.ItemSet{ - Name: "Wicked Felheart", - Bonuses: map[int32]core.ApplyEffect{ - // Banish is now instant cast, and can be cast on yourself while you are a Demon. You cannot Banish yourself while you have Forbearance, and doing so will give you Forbearance for 1 min. - 2: func(agent core.Agent) { - // TODO: Banish not implemented - }, - // Each time you take damage, you and your pet gain mana equal to the damage taken, up to a maximum of 420 mana per event. Can only occur once every few seconds. - 4: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - actionID := core.ActionID{SpellID: 457572} - icd := core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: time.Millisecond * 3500, - } - manaMetrics := warlock.NewManaMetrics(actionID) - for _, pet := range warlock.BasePets { - pet.T1Tank4PManaMetrics = pet.NewManaMetrics(actionID) - } - warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Warlock - Tank 4P Bonus", - 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 icd.IsReady(sim) { - restoreAmount := min(result.Damage, 420) - warlock.AddMana(sim, restoreAmount, manaMetrics) - if warlock.ActivePet != nil { - warlock.ActivePet.AddMana(sim, restoreAmount, warlock.ActivePet.T1Tank4PManaMetrics) - } - } - }, - }) - }, - // Your Shadow Cleave hits have a 20% chance to grant you a Soul Shard, reset the cooldown on Soul Fire, and make your next Soul Fire within 10 sec instant. - 6: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - soulFireCastTime := SoulFireCastTime - procAura := warlock.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 457643}, - Label: "Soul Fire!", - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.SoulFire { - spell.DefaultCast.CastTime = 0 - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.SoulFire { - spell.DefaultCast.CastTime = soulFireCastTime - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell.SpellCode == SpellCode_WarlockSoulFire { - aura.Deactivate(sim) - } - }, - }) - - icd := core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: time.Millisecond * 100, - } - - warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Warlock - Tank 6P Bonus", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - soulFireCastTime = warlock.SoulFire[0].DefaultCast.CastTime - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() && spell.SpellCode == SpellCode_WarlockShadowCleave && icd.IsReady(sim) && sim.Proc(0.2, "Soul Fire! Proc") { - procAura.Activate(sim) - icd.Use(sim) - } - }, - }) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 5 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetWickedNemesis = core.NewItemSet(core.ItemSet{ - Name: "Wicked Nemesis", - Bonuses: map[int32]core.ApplyEffect{ - - // While you are targeting an enemy within 30 yards, - // Life Tap grants you mana at the expense of your target's health - // but deals 50% reduced damage to them. Mana gained remains unchanged - // Bluepost: Tier 2 tank warlock 2 set can no longer crit - 2: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - var healthMetrics [LifeTapRanks + 1]*core.ResourceMetrics - - for i, spellId := range LifeTapSpellId { - healthMetrics[i] = warlock.NewHealthMetrics(core.ActionID{SpellID: spellId}) - } - - warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warlock - Tank 2P Bonus", - 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 spell.SpellCode == SpellCode_WarlockLifeTap { - warlock.GainHealth(sim, result.Damage, healthMetrics[spell.Rank]) - } - }, - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell.SpellCode == SpellCode_WarlockLifeTap && warlock.CurrentTarget != nil { - // Enemy hit can partially resist and cannot crit - spell.Flags &= ^core.SpellFlagBinary - spell.DamageMultiplier /= 2 - var damageResult = spell.CalcDamage(sim, warlock.CurrentTarget, LifeTapBaseDamage[spell.Rank], spell.OutcomeMagicHit) - spell.DealDamage(sim, damageResult) - spell.DamageMultiplier *= 2 - spell.Flags |= core.SpellFlagBinary - } - }, - }, - ) - }, - // While Metamorphosis is active, your offensive abilities and Demon summons cost no Soul Shards. - // In addition, you heal for 15% of your maximum health when you damage a target with Shadowburn - 4: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - healingSpell := warlock.GetOrRegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 468062}, - SpellSchool: core.SpellSchoolPhysical, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagPassiveSpell | core.SpellFlagHelpful, - - DamageMultiplier: 1, - ThreatMultiplier: 0, - }) - - warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warlock - Tank 4P Bonus", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_WarlockShadowburn && result.Landed() { - healAmount := warlock.MaxHealth() * 0.15 - healingSpell.CalcAndDealHealing(sim, healingSpell.Unit, healAmount, healingSpell.OutcomeHealing) - } - }, - }) - }, - // Any excess healing you deal to yourself is converted into a shield that absorbs damage. - // This shield can absorb uf to 30% of your maximum health, and stacks from multiple heals. - 6: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - shieldIncreaseAmount := 0.0 - currentShieldAmount := 0.0 - - shieldSpell := warlock.GetOrRegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 470279}, - ProcMask: core.ProcMaskSpellHealing, - SpellSchool: core.SpellSchoolShadow, - Flags: core.SpellFlagPassiveSpell, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - - Shield: core.ShieldConfig{ - SelfOnly: true, - Aura: core.Aura{ - Label: "Demonic Aegis", - Duration: 12 * time.Second, - }, - }, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - spell.SelfShield().Apply(sim, currentShieldAmount) - }, - }) - - warlock.RegisterAura(core.Aura{ - Duration: core.NeverExpires, - Label: "S03 - Item - T2 - Warlock - Tank 6P Bonus", - - OnReset: func(aura *core.Aura, sim *core.Simulation) { - shieldIncreaseAmount = 0.0 - currentShieldAmount = 0.0 - aura.Activate(sim) - }, - OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if currentShieldAmount <= 0 || result.Damage <= 0 || spell.SpellCode == SpellCode_WarlockLifeTap { - return - } - - damageAbsorbed := min(result.Damage, currentShieldAmount) - currentShieldAmount -= damageAbsorbed - - warlock.GainHealth(sim, damageAbsorbed, shieldSpell.HealthMetrics(result.Target)) - - if currentShieldAmount <= 0 { - currentShieldAmount = 0 - shieldSpell.SelfShield().Deactivate(sim) - } - }, - OnHealDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - shieldIncreaseAmount = result.Damage + warlock.CurrentHealth() - warlock.MaxHealth() - if shieldIncreaseAmount > 0 { - currentShieldAmount += shieldIncreaseAmount - currentShieldAmount = min(warlock.MaxHealth()*0.30, currentShieldAmount) - shieldSpell.Cast(sim, result.Target) - } - }, - }) - }, - }, -}) - -var ItemSetCorruptedNemesis = core.NewItemSet(core.ItemSet{ - Name: "Corrupted Nemesis", - Bonuses: map[int32]core.ApplyEffect{ - // Increases the damage of your periodic spells and Felguard pet by 10% - 2: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - if warlock.HasRune(proto.WarlockRune_RuneBracerSummonFelguard) { - warlock.Felguard.PseudoStats.DamageDealtMultiplier *= 1.10 - } - - core.MakePermanent(warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warlock - Damage 2P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.Spellbook { - if spell.Flags.Matches(SpellFlagWarlock) && len(spell.Dots()) > 0 { - spell.DamageMultiplier *= 1.10 - } - } - }, - })) - }, - // Periodic damage from your Shadowflame, Unstable Affliction, and Curse of Agony spells and damage done by your Felguard have a 4% chance to grant the Shadow Trance effect. - 4: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - procChance := 0.04 - - affectedSpellCodes := []int32{SpellCode_WarlockCurseOfAgony, SpellCode_WarlockShadowflame, SpellCode_WarlockUnstableAffliction} - core.MakePermanent(warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warlock - Damage 4P Bonus", - OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if slices.Contains(affectedSpellCodes, spell.SpellCode) && sim.Proc(procChance, "Proc Shadow Trance") { - warlock.ShadowTranceAura.Activate(sim) - } - }, - })) - - if !warlock.HasRune(proto.WarlockRune_RuneBracerSummonFelguard) { - return - } - - core.MakePermanent(warlock.Felguard.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Warlock - Damage 4P Bonus - Felguard Bonus", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() && sim.Proc(procChance, "Proc Shadow Trance") { - warlock.ShadowTranceAura.Activate(sim) - } - }, - })) - }, - // Shadowbolt deals 10% increased damage for each of your effects afflicting the target, up to a maximum of 30%. - 6: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - warlock.shadowBoltActiveEffectMultiplierPer = .10 - warlock.shadowBoltActiveEffectMultiplierMax = 1.30 - }, - }, -}) - -var ItemSetDemoniacsThreads = core.NewItemSet(core.ItemSet{ - Name: "Demoniac's Threads", - Bonuses: map[int32]core.ApplyEffect{ - // Increases damage and healing done by magical spells and effects by up to 12. - 2: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - warlock.AddStat(stats.SpellPower, 12) - }, - // Increases the Attack Power and Spell Damage your Demon pet gains from your attributes by 20%. - 3: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - core.MakePermanent(warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - ZG - Warlock - Demonology 3P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, pet := range warlock.BasePets { - oldStatInheritance := pet.GetStatInheritance() - pet.UpdateStatInheritance( - func(ownerStats stats.Stats) stats.Stats { - s := oldStatInheritance(ownerStats) - s[stats.AttackPower] *= 1.20 - s[stats.SpellPower] *= 1.20 - return s - }, - ) - } - }, - })) - }, - // Increases the benefits of your Master Demonologist talent by 50%. - 5: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - warlock.masterDemonologistBonus += .50 - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 5 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetDoomcallersCorruption = core.NewItemSet(core.ItemSet{ - Name: "Doomcaller's Corruption", - Bonuses: map[int32]core.ApplyEffect{ - // Reduces the cooldown on your Chaos Bolt by 50% and increases its damage done by 10%. - 2: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - if !warlock.HasRune(proto.WarlockRune_RuneHandsChaosBolt) { - return - } - - warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Warlock - Damage 2P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - warlock.ChaosBolt.CD.Duration /= 2 - warlock.ChaosBolt.DamageMultiplier *= 1.10 - }, - }) - }, - // Each time you hit a target with Conflagrate, you gain 2% increased Fire damage for 20 sec, stacking up to 5 times. - 4: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - - buffAura := warlock.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 1214088}, - Label: "Infernalist", - Duration: time.Second * 20, - MaxStacks: 5, - OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) { - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= 1 + 0.02*(float64(newStacks-oldStacks)) - }, - }) - - core.MakePermanent(warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Warlock - Damage 4P Bonus", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_WarlockConflagrate && result.Landed() { - buffAura.Activate(sim) - buffAura.AddStack(sim) - } - }, - })) - }, - }, -}) - -var ItemSetDoomcallersMalevolence = core.NewItemSet(core.ItemSet{ - Name: "Doomcaller's Malevolence", - Bonuses: map[int32]core.ApplyEffect{ - // Reduces the cooldown on your Shadow Cleave by 1.5 sec. - 2: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - if !warlock.HasRune(proto.WarlockRune_RuneHandsMetamorphosis) { - return - } - - warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Warlock - Tank 2P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.ShadowCleave { - spell.CD.Duration -= time.Millisecond * 1500 - } - }, - }) - }, - // You keep the benefits of your Master Demonologist talent while Demonic Sacrifice is active. - 4: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - core.MakePermanent(warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - TAQ - Warlock - Tank 4P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - warlock.disableMasterDemonologistOnSacrifice = false - }, - })) - }, - }, -}) - -var ItemSetImplementsOfUnspokenNames = core.NewItemSet(core.ItemSet{ - Name: "Implements of Unspoken Names", - Bonuses: map[int32]core.ApplyEffect{ - // For 6 sec after using Shadowcleave, your Searing Pain strikes 1 additional target within melee range. - 3: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - if !warlock.HasRune(proto.WarlockRune_RuneHandsMetamorphosis) || len(warlock.Env.Encounter.TargetUnits) <= 1 { - return - } - - buffAura := warlock.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 1214156}, - Label: "Spreading Pain", - Duration: time.Second * 6, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellCode == SpellCode_WarlockSearingPain { - aura.Deactivate(sim) - spell.ApplyEffects(sim, warlock.Env.NextTargetUnit(result.Target), spell) - } - }, - }) - - core.MakePermanent(warlock.RegisterAura(core.Aura{ - Label: "S03 - Item - RAQ - Warlock - Tank 3P Bonus", - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell.SpellCode == SpellCode_WarlockShadowCleave { - buffAura.Activate(sim) - } - }, - })) - }, - }, -}) diff --git a/sim/warlock/_item_sets_pvp.go b/sim/warlock/_item_sets_pvp.go deleted file mode 100644 index 7fb6a3999..000000000 --- a/sim/warlock/_item_sets_pvp.go +++ /dev/null @@ -1,129 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/stats" -) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 4 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetChampionsThreads = core.NewItemSet(core.ItemSet{ - Name: "Champion's Threads", - 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) - }, - // Reduces the casting time of your Immolate spell by 0.2 sec. - 4: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - warlock.GetOrRegisterAura(core.Aura{ - Label: "Immolate Cast Time Reduction", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.Immolate { - spell.DefaultCast.CastTime -= time.Millisecond * 200 - } - }, - }) - }, - // +20 Stamina. - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 20) - }, - }, -}) - -var ItemSetLieutenantCommandersThreads = core.NewItemSet(core.ItemSet{ - Name: "Lieutenant Commander's Threads", - 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) - }, - // Reduces the casting time of your Immolate spell by 0.2 sec. - 4: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - warlock.GetOrRegisterAura(core.Aura{ - Label: "Immolate Cast Time Reduction", - ActionID: core.ActionID{SpellID: 23047}, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.Immolate { - spell.DefaultCast.CastTime -= time.Millisecond * 200 - } - }, - }) - }, - // +20 Stamina. - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 20) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 5 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetWarlordsThreads = core.NewItemSet(core.ItemSet{ - Name: "Warlord's Threads", - Bonuses: map[int32]core.ApplyEffect{ - // +20 Stamina. - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 20) - }, - // Reduces the casting time of your Immolate spell by 0.2 sec. - 3: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - warlock.GetOrRegisterAura(core.Aura{ - Label: "Immolate Cast Time Reduction", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.Immolate { - spell.DefaultCast.CastTime -= time.Millisecond * 200 - } - }, - }) - }, - // 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) - }, - }, -}) - -var ItemSetFieldMarshalsThreads = core.NewItemSet(core.ItemSet{ - Name: "Field Marshal's Threads", - Bonuses: map[int32]core.ApplyEffect{ - // +20 Stamina. - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 20) - }, - // Reduces the casting time of your Immolate spell by 0.2 sec. - 3: func(agent core.Agent) { - warlock := agent.(WarlockAgent).GetWarlock() - warlock.GetOrRegisterAura(core.Aura{ - Label: "Immolate Cast Time Reduction", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.Immolate { - spell.DefaultCast.CastTime -= time.Millisecond * 200 - } - }, - }) - }, - // 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) - }, - }, -}) diff --git a/sim/warlock/apl_values.go b/sim/warlock/apl_values.go index 240c0275d..111c8fc2a 100644 --- a/sim/warlock/apl_values.go +++ b/sim/warlock/apl_values.go @@ -63,11 +63,6 @@ func (value *APLValueWarlockShouldRecastDrainSoul) GetBool(sim *core.Simulation) } hauntRefresh := 1000 * time.Second - if warlock.HauntDebuffAuras != nil { - hauntRefresh = warlock.HauntDebuffAuras.Get(warlock.CurrentTarget).RemainingDuration(sim) - - warlock.Haunt.CastTime() - - warlock.Haunt.TravelTime() - } // the amount of ticks we have left, assuming we continue channeling dsDot := warlock.ChanneledDot diff --git a/sim/warlock/armors.go b/sim/warlock/armors.go index dc06b4a02..649b6c4ec 100644 --- a/sim/warlock/armors.go +++ b/sim/warlock/armors.go @@ -1,8 +1,6 @@ package warlock import ( - "time" - "github.com/wowsims/classic/sim/core" "github.com/wowsims/classic/sim/core/stats" ) @@ -41,29 +39,3 @@ func (warlock *Warlock) applyDemonArmor() { }, }) } - -// Surrounds the caster with fel energy, increasing spell damage and healing by 1 plus additional spell damage and healing equal to 50% of your Spirit. -// In addition, you regain 2% of your maximum health every 5 sec. -func (warlock *Warlock) applyFelArmor() { - actionID := core.ActionID{SpellID: 403619} - - warlock.AddStat(stats.SpellPower, 60) - warlock.AddStatDependency(stats.Spirit, stats.SpellPower, .50) - - healthMetrics := warlock.NewHealthMetrics(actionID) - warlock.GetOrRegisterAura(core.Aura{ - Label: "Fel Armor", - ActionID: actionID, - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - core.StartPeriodicAction(sim, core.PeriodicActionOptions{ - Period: time.Second * 5, - Priority: core.ActionPriorityAuto, - OnAction: func(sim *core.Simulation) { - warlock.GainHealth(sim, warlock.MaxHealth()*.02, healthMetrics) - }, - }) - }, - }) -} diff --git a/sim/warlock/chaos_bolt.go b/sim/warlock/chaos_bolt.go deleted file mode 100644 index 6c7647970..000000000 --- a/sim/warlock/chaos_bolt.go +++ /dev/null @@ -1,51 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" -) - -// TODO: Classic warlock verify chaos bolt mechanics -func (warlock *Warlock) registerChaosBoltSpell() { - if !warlock.HasRune(proto.WarlockRune_RuneHandsChaosBolt) { - return - } - - spellCoeff := 0.714 - baseLowDamage := warlock.baseRuneAbilityDamage() * 5.22 - baseHighDamage := warlock.baseRuneAbilityDamage() * 6.62 - - warlock.ChaosBolt = warlock.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 403629}, - SpellSchool: core.SpellSchoolFire, - DefenseType: core.DefenseTypeMagic, - ProcMask: core.ProcMaskSpellDamage, - Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | WarlockFlagDestruction, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.07, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: time.Millisecond * 2500, - }, - CD: core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: time.Second * 12, - }, - }, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - BonusCoefficient: spellCoeff, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseDamage := sim.Roll(baseLowDamage, baseHighDamage) - // Assuming 100% hit for all target levels, numbers could be updated for level comparison later - spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeMagicCrit) - }, - }) -} diff --git a/sim/warlock/conflagrate.go b/sim/warlock/conflagrate.go index 8602a7f52..1987e48c1 100644 --- a/sim/warlock/conflagrate.go +++ b/sim/warlock/conflagrate.go @@ -4,15 +4,11 @@ import ( "time" "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" ) const ConflagrateRanks = 4 func (warlock *Warlock) getConflagrateConfig(rank int) core.SpellConfig { - hasBackdraftRune := warlock.HasRune(proto.WarlockRune_RuneHelmBackdraft) - hasShadowflameRune := warlock.HasRune(proto.WarlockRune_RuneBootsShadowflame) - spellId := [ConflagrateRanks + 1]int32{0, 17962, 18930, 18931, 18932}[rank] baseDamageMin := [ConflagrateRanks + 1]float64{0, 249, 319, 395, 447}[rank] baseDamageMax := [ConflagrateRanks + 1]float64{0, 316, 400, 491, 557}[rank] @@ -44,7 +40,7 @@ func (warlock *Warlock) getConflagrateConfig(rank int) core.SpellConfig { }, }, ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - return warlock.getActiveImmolateSpell(target) != nil || (hasShadowflameRune && warlock.Shadowflame.Dot(target).IsActive()) + return warlock.getActiveImmolateSpell(target) != nil }, DamageMultiplier: 1, @@ -54,33 +50,11 @@ func (warlock *Warlock) getConflagrateConfig(rank int) core.SpellConfig { ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := sim.Roll(baseDamageMin, baseDamageMax) - result := spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeMagicHitAndCrit) - - if result.Landed() && hasBackdraftRune { - warlock.BackdraftAura.Activate(sim) - } - - // Conflag now doesn't consume Immo or Shadowflame when using Backdraft - if !hasBackdraftRune { - immoTime := core.NeverExpires - shadowflameTime := core.NeverExpires - - immoSpell := warlock.getActiveImmolateSpell(target) - if immoSpell != nil { - immoDot := immoSpell.Dot(target) - immoTime = core.TernaryDuration(immoDot.IsActive(), immoDot.RemainingDuration(sim), core.NeverExpires) - } - - if hasShadowflameRune { - sfDot := warlock.Shadowflame.Dot(target) - shadowflameTime = core.TernaryDuration(sfDot.IsActive(), sfDot.RemainingDuration(sim), core.NeverExpires) - } + spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeMagicHitAndCrit) - if immoTime < shadowflameTime { - immoSpell.Dot(target).Deactivate(sim) - } else { - warlock.Shadowflame.Dot(target).Deactivate(sim) - } + immoSpell := warlock.getActiveImmolateSpell(target) + if immoSpell != nil { + immoSpell.Dot(target).Deactivate(sim) } }, } diff --git a/sim/warlock/corruption.go b/sim/warlock/corruption.go index 6ecb66bd3..cb6f21d06 100644 --- a/sim/warlock/corruption.go +++ b/sim/warlock/corruption.go @@ -5,7 +5,6 @@ import ( "time" "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" ) const CorruptionRanks = 7 @@ -19,8 +18,6 @@ func (warlock *Warlock) getCorruptionConfig(rank int) core.SpellConfig { level := [CorruptionRanks + 1]int{0, 4, 14, 24, 34, 44, 54, 60}[rank] castTime := time.Millisecond * (2000 - (400 * time.Duration(warlock.Talents.ImprovedCorruption))) - hasInvocationRune := warlock.HasRune(proto.WarlockRune_RuneBeltInvocation) - hasPandemicRune := warlock.HasRune(proto.WarlockRune_RuneHelmPandemic) return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, @@ -28,7 +25,7 @@ func (warlock *Warlock) getCorruptionConfig(rank int) core.SpellConfig { SpellCode: SpellCode_WarlockCorruption, ProcMask: core.ProcMaskSpellDamage, DefenseType: core.DefenseTypeMagic, - Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | core.SpellFlagPureDot | WarlockFlagAffliction | WarlockFlagHaunt, + Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | core.SpellFlagPureDot | WarlockFlagAffliction, Rank: rank, RequiredLevel: level, @@ -42,7 +39,7 @@ func (warlock *Warlock) getCorruptionConfig(rank int) core.SpellConfig { }, }, - CritDamageBonus: core.TernaryFloat64(hasPandemicRune, 1, 0), + CritDamageBonus: 0, DamageMultiplier: 1, ThreatMultiplier: 1, @@ -58,19 +55,9 @@ func (warlock *Warlock) getCorruptionConfig(rank int) core.SpellConfig { OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) { dot.Snapshot(target, baseDamage, isRollover) - if !isRollover { - if warlock.zilaGularAura.IsActive() { - dot.SnapshotAttackerMultiplier *= 1.25 - warlock.zilaGularAura.Deactivate(sim) - } - } }, OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - if hasPandemicRune { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit) - } else { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) - } + dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) }, }, @@ -78,11 +65,6 @@ func (warlock *Warlock) getCorruptionConfig(rank int) core.SpellConfig { result := spell.CalcOutcome(sim, target, spell.OutcomeMagicHitNoHitCounter) if result.Landed() { dot := spell.Dot(target) - - if hasInvocationRune && dot.IsActive() { - warlock.InvocationRefresh(sim, dot) - } - dot.Apply(sim) } spell.DealOutcome(sim, result) @@ -90,15 +72,9 @@ func (warlock *Warlock) getCorruptionConfig(rank int) core.SpellConfig { ExpectedTickDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, useSnapshot bool) *core.SpellResult { if useSnapshot { dot := spell.Dot(target) - if hasPandemicRune { - return dot.CalcSnapshotDamage(sim, target, dot.Spell.OutcomeExpectedMagicCrit) - } return dot.CalcSnapshotDamage(sim, target, dot.Spell.OutcomeExpectedMagicAlwaysHit) } else { baseDamage := baseDamage / float64(ticks) - if hasPandemicRune { - return spell.CalcPeriodicDamage(sim, target, baseDamage, spell.OutcomeExpectedMagicCrit) - } return spell.CalcPeriodicDamage(sim, target, baseDamage, spell.OutcomeExpectedMagicAlwaysHit) } }, diff --git a/sim/warlock/curses.go b/sim/warlock/curses.go index 41013d83a..cd09c3a06 100644 --- a/sim/warlock/curses.go +++ b/sim/warlock/curses.go @@ -5,7 +5,6 @@ import ( "time" "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" ) const CurseOfAgonyRanks = 6 @@ -20,10 +19,6 @@ func (warlock *Warlock) getCurseOfAgonyBaseConfig(rank int) core.SpellConfig { manaCost := [CurseOfAgonyRanks + 1]float64{0, 25, 50, 90, 130, 170, 215}[rank] level := [CurseOfAgonyRanks + 1]int{0, 8, 18, 28, 38, 48, 58}[rank] - hasInvocationRune := warlock.HasRune(proto.WarlockRune_RuneBeltInvocation) - hasPandemicRune := warlock.HasRune(proto.WarlockRune_RuneHelmPandemic) - hasMarkOfChaosRune := warlock.HasRune(proto.WarlockRune_RuneCloakMarkOfChaos) - baseDamage *= 1 + warlock.shadowMasteryBonus() snapshotBaseDmgNoBonus := 0.0 @@ -32,7 +27,7 @@ func (warlock *Warlock) getCurseOfAgonyBaseConfig(rank int) core.SpellConfig { ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolShadow, DefenseType: core.DefenseTypeMagic, - Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | core.SpellFlagPureDot | WarlockFlagAffliction | WarlockFlagHaunt, + Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | core.SpellFlagPureDot | WarlockFlagAffliction, ProcMask: core.ProcMaskSpellDamage, RequiredLevel: level, Rank: rank, @@ -46,7 +41,7 @@ func (warlock *Warlock) getCurseOfAgonyBaseConfig(rank int) core.SpellConfig { }, }, - CritDamageBonus: core.TernaryFloat64(hasPandemicRune, 1, 0), + CritDamageBonus: 0, DamageMultiplierAdditive: 1, DamageMultiplier: 1, @@ -73,20 +68,9 @@ func (warlock *Warlock) getCurseOfAgonyBaseConfig(rank int) core.SpellConfig { snapshotBaseDmgNoBonus = baseDmg * 0.5 dot.Snapshot(target, snapshotBaseDmgNoBonus, isRollover) - - if !isRollover { - if warlock.zilaGularAura.IsActive() { - dot.SnapshotAttackerMultiplier *= 1.25 - warlock.zilaGularAura.Deactivate(sim) - } - } }, OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - if hasPandemicRune { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit) - } else { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) - } + dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) if dot.TickCount%4 == 0 { // CoA ramp up dot.SnapshotBaseDamage += snapshotBaseDmgNoBonus } @@ -102,16 +86,8 @@ func (warlock *Warlock) getCurseOfAgonyBaseConfig(rank int) core.SpellConfig { activeCurse.Deactivate(sim) } - if hasInvocationRune && dot.IsActive() { - warlock.InvocationRefresh(sim, dot) - } - dot.Apply(sim) warlock.ActiveCurseAura[target.UnitIndex] = dot.Aura - - if hasMarkOfChaosRune { - warlock.applyMarkOfChaosDebuff(sim, target, dot.Duration) - } } spell.DealOutcome(sim, result) }, @@ -130,8 +106,6 @@ func (warlock *Warlock) registerCurseOfAgonySpell() { } func (warlock *Warlock) registerCurseOfRecklessnessSpell() { - hasMarkOfChaosRune := warlock.HasRune(proto.WarlockRune_RuneCloakMarkOfChaos) - playerLevel := warlock.Level warlock.CurseOfRecklessnessAuras = warlock.NewEnemyAuraArray(core.CurseOfRecklessnessAura) @@ -186,10 +160,6 @@ func (warlock *Warlock) registerCurseOfRecklessnessSpell() { warlock.ActiveCurseAura[target.UnitIndex] = aura warlock.ActiveCurseAura.Get(target).Activate(sim) - - if hasMarkOfChaosRune { - warlock.applyMarkOfChaosDebuff(sim, target, time.Minute*2) - } } }, @@ -354,12 +324,9 @@ func (warlock *Warlock) registerCurseOfDoomSpell() { return } - hasPandemicRune := warlock.HasRune(proto.WarlockRune_RuneHelmPandemic) - hasMarkOfChaosRune := warlock.HasRune(proto.WarlockRune_RuneCloakMarkOfChaos) - warlock.CurseOfDoom = warlock.RegisterSpell(core.SpellConfig{ SpellCode: SpellCode_WarlockCurseOfDoom, - ActionID: core.ActionID{SpellID: 449432}, // New spell created for SoD + ActionID: core.ActionID{SpellID: 603}, SpellSchool: core.SpellSchoolShadow, DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, @@ -380,11 +347,12 @@ func (warlock *Warlock) registerCurseOfDoomSpell() { }, }, - CritDamageBonus: core.TernaryFloat64(hasPandemicRune, 1, 0), + CritDamageBonus: 0, DamageMultiplier: 1, ThreatMultiplier: 1 - 0.1*float64(warlock.Talents.ImprovedDrainSoul), FlatThreatBonus: 160, + BonusCoefficient: 1, Dot: core.DotConfig{ Aura: core.Aura{ @@ -396,11 +364,7 @@ func (warlock *Warlock) registerCurseOfDoomSpell() { dot.Snapshot(target, 3200, isRollover) }, OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - if hasPandemicRune { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit) - } else { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) - } + dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) }, }, @@ -414,10 +378,6 @@ func (warlock *Warlock) registerCurseOfDoomSpell() { dot.Apply(sim) warlock.ActiveCurseAura[target.UnitIndex] = dot.Aura - - if hasMarkOfChaosRune { - warlock.applyMarkOfChaosDebuff(sim, target, dot.Duration) - } } }, }) diff --git a/sim/warlock/demonic_grace.go b/sim/warlock/demonic_grace.go deleted file mode 100644 index aa65137e4..000000000 --- a/sim/warlock/demonic_grace.go +++ /dev/null @@ -1,52 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" - "github.com/wowsims/classic/sim/core/stats" -) - -func (warlock *Warlock) registerDemonicGraceSpell() { - if !warlock.HasRune(proto.WarlockRune_RuneLegsDemonicGrace) { - return - } - - warlock.DemonicGraceAura = warlock.RegisterAura(core.Aura{ - Label: "Demonic Grace Aura", - ActionID: core.ActionID{SpellID: 425463}, - Duration: time.Second * 6, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.AddStatDynamic(sim, stats.Dodge, 20*core.DodgeRatingPerDodgeChance) - warlock.AddStatDynamic(sim, stats.MeleeCrit, 20*core.CritRatingPerCritChance) - warlock.AddStatDynamic(sim, stats.SpellCrit, 20*core.SpellCritRatingPerCritChance) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.AddStatDynamic(sim, stats.Dodge, -20*core.DodgeRatingPerDodgeChance) - warlock.AddStatDynamic(sim, stats.MeleeCrit, -20*core.CritRatingPerCritChance) - warlock.AddStatDynamic(sim, stats.SpellCrit, -20*core.SpellCritRatingPerCritChance) - }, - }) - - warlock.DemonicGrace = warlock.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 425463}, - Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | WarlockFlagDemonology, - - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: time.Second * 20, - }, - }, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - warlock.DemonicGraceAura.Activate(sim) - }, - }) - - warlock.AddMajorCooldown(core.MajorCooldown{ - Spell: warlock.DemonicGrace, - Type: core.CooldownTypeDPS, - }) -} diff --git a/sim/warlock/dps/TestAffliction.results b/sim/warlock/dps/TestAffliction.results deleted file mode 100644 index 0bfa0c765..000000000 --- a/sim/warlock/dps/TestAffliction.results +++ /dev/null @@ -1,162 +0,0 @@ -character_stats_results: { - key: "TestAffliction-Phase4-Lvl60-CharacterStats-Default" - value: { - final_stats: 194.35 - final_stats: 203.55 - final_stats: 437.7475 - final_stats: 258.75 - final_stats: 239.2 - final_stats: 564.6 - final_stats: 0 - final_stats: 40 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 159 - final_stats: 45.25 - final_stats: 5 - final_stats: 28.96938 - final_stats: 0 - final_stats: 0 - final_stats: 814.35 - final_stats: 0 - final_stats: 25.1775 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 4974.25 - final_stats: 0 - final_stats: 0 - final_stats: 1353.1 - final_stats: 540 - final_stats: 0 - final_stats: 5 - final_stats: 0 - final_stats: 12.1775 - final_stats: 5 - final_stats: 0 - final_stats: 5911.475 - final_stats: 27 - final_stats: 76 - final_stats: 60 - final_stats: 60 - final_stats: 60 - final_stats: 384 - final_stats: 0 - final_stats: 35 - final_stats: 0 - } -} -stat_weights_results: { - key: "TestAffliction-Phase4-Lvl60-StatWeights-Default" - value: { - weights: 0 - weights: 0 - weights: 0 - weights: 0.02841 - weights: 0 - weights: 0.28413 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 3.47155 - weights: 0.74065 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Average-Default" - value: { - dps: 503.11693 - tps: 355.02362 - hps: 207.21698 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-placeholder-Affliction Warlock-affliction-FullBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 500.4467 - tps: 822.12009 - hps: 206.57229 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-placeholder-Affliction Warlock-affliction-FullBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 500.4467 - tps: 352.10643 - hps: 206.57229 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-placeholder-Affliction Warlock-affliction-FullBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 523.21588 - tps: 376.7872 - hps: 196.21055 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-placeholder-Affliction Warlock-affliction-NoBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 308.23238 - tps: 748.95525 - hps: 119.78727 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-placeholder-Affliction Warlock-affliction-NoBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 308.23238 - tps: 224.64519 - hps: 119.78727 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-placeholder-Affliction Warlock-affliction-NoBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 334.51601 - tps: 250.15416 - hps: 112.94454 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-SwitchInFrontOfTarget-Default" - value: { - dps: 500.4467 - tps: 352.10643 - hps: 206.57229 - } -} diff --git a/sim/warlock/dps/TestDemonology.results b/sim/warlock/dps/TestDemonology.results deleted file mode 100644 index 7574a8037..000000000 --- a/sim/warlock/dps/TestDemonology.results +++ /dev/null @@ -1,154 +0,0 @@ -character_stats_results: { - key: "TestDemonology-Phase2-Lvl40-CharacterStats-Default" - value: { - final_stats: 120.75 - final_stats: 80.5 - final_stats: 398.46925 - final_stats: 189.75 - final_stats: 158.4125 - final_stats: 524.20625 - final_stats: 0 - final_stats: 40 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 159 - final_stats: 32.75 - final_stats: 5 - final_stats: 29.67145 - final_stats: 0 - final_stats: 0 - final_stats: 566.75 - final_stats: 0 - final_stats: 20.6189 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 3489.25 - final_stats: 0 - final_stats: 0 - final_stats: 986 - final_stats: 440 - final_stats: 0 - final_stats: 5 - final_stats: 0 - final_stats: 7.6189 - final_stats: 5 - final_stats: 0 - final_stats: 4738.6925 - final_stats: 13 - final_stats: 46 - final_stats: 30 - final_stats: 30 - final_stats: 30 - final_stats: 263 - final_stats: 0 - final_stats: 35 - final_stats: 0 - } -} -stat_weights_results: { - key: "TestDemonology-Phase2-Lvl40-StatWeights-Default" - value: { - weights: 0 - weights: 0 - weights: 0 - weights: 0.004 - weights: 0 - weights: 0.0709 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0.13387 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - } -} -dps_results: { - key: "TestDemonology-Phase2-Lvl40-Average-Default" - value: { - dps: 76.1651 - tps: 80.20343 - } -} -dps_results: { - key: "TestDemonology-Phase2-Lvl40-Settings-Orc-placeholder-Demonology Warlock-demonology-FullBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 75.78854 - tps: 89.68818 - } -} -dps_results: { - key: "TestDemonology-Phase2-Lvl40-Settings-Orc-placeholder-Demonology Warlock-demonology-FullBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 75.78854 - tps: 79.81293 - } -} -dps_results: { - key: "TestDemonology-Phase2-Lvl40-Settings-Orc-placeholder-Demonology Warlock-demonology-FullBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 81.78573 - tps: 100.98705 - } -} -dps_results: { - key: "TestDemonology-Phase2-Lvl40-Settings-Orc-placeholder-Demonology Warlock-demonology-NoBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 52.79904 - tps: 54.97303 - } -} -dps_results: { - key: "TestDemonology-Phase2-Lvl40-Settings-Orc-placeholder-Demonology Warlock-demonology-NoBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 52.79904 - tps: 54.97303 - } -} -dps_results: { - key: "TestDemonology-Phase2-Lvl40-Settings-Orc-placeholder-Demonology Warlock-demonology-NoBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 55.93888 - tps: 67.23421 - } -} -dps_results: { - key: "TestDemonology-Phase2-Lvl40-SwitchInFrontOfTarget-Default" - value: { - dps: 75.78854 - tps: 79.81293 - } -} diff --git a/sim/warlock/dps/TestDestruction.results b/sim/warlock/dps/TestDestruction.results deleted file mode 100644 index 877530544..000000000 --- a/sim/warlock/dps/TestDestruction.results +++ /dev/null @@ -1,154 +0,0 @@ -character_stats_results: { - key: "TestDestruction-Phase4-Lvl60-CharacterStats-Default" - value: { - final_stats: 194.35 - final_stats: 203.55 - final_stats: 503.40962 - final_stats: 258.75 - final_stats: 227.24 - final_stats: 558.62 - final_stats: 0 - final_stats: 40 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 159 - final_stats: 45.25 - final_stats: 5 - final_stats: 28.96938 - final_stats: 0 - final_stats: 0 - final_stats: 814.35 - final_stats: 0 - final_stats: 25.1775 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 4974.25 - final_stats: 0 - final_stats: 0 - final_stats: 1353.1 - final_stats: 540 - final_stats: 0 - final_stats: 5 - final_stats: 0 - final_stats: 12.1775 - final_stats: 5 - final_stats: 0 - final_stats: 6568.09625 - final_stats: 27 - final_stats: 76 - final_stats: 60 - final_stats: 60 - final_stats: 60 - final_stats: 384 - final_stats: 0 - final_stats: 35 - final_stats: 0 - } -} -stat_weights_results: { - key: "TestDestruction-Phase4-Lvl60-StatWeights-Default" - value: { - weights: 0 - weights: 0 - weights: 0 - weights: 0.23734 - weights: 0 - weights: 0.35633 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 5.08727 - weights: 2.46119 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Average-Default" - value: { - dps: 662.52898 - tps: 495.4123 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-placeholder-Destruction Warlock-destruction-FullBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 664.84066 - tps: 1093.96523 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-placeholder-Destruction Warlock-destruction-FullBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 664.84066 - tps: 498.74818 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-placeholder-Destruction Warlock-destruction-FullBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 728.86416 - tps: 587.44758 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-placeholder-Destruction Warlock-destruction-NoBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 124.33411 - tps: 892.43736 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-placeholder-Destruction Warlock-destruction-NoBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 124.33411 - tps: 49.90734 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-placeholder-Destruction Warlock-destruction-NoBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 108.5207 - tps: 34.05603 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-SwitchInFrontOfTarget-Default" - value: { - dps: 664.58069 - tps: 498.37335 - } -} diff --git a/sim/warlock/dps/TestWarlock.results b/sim/warlock/dps/TestWarlock.results new file mode 100644 index 000000000..af3049fbc --- /dev/null +++ b/sim/warlock/dps/TestWarlock.results @@ -0,0 +1,196 @@ +character_stats_results: { + key: "TestWarlock-Phase4-Lvl60-CharacterStats-Default" + value: { + final_stats: 195.5 + final_stats: 194.35 + final_stats: 559.682 + final_stats: 342.7 + final_stats: 258.9225 + final_stats: 496 + final_stats: 0 + final_stats: 40 + final_stats: 0 + final_stats: 0 + final_stats: 0 + final_stats: 161 + final_stats: 41.25 + final_stats: 0 + final_stats: 32.35455 + final_stats: 0 + final_stats: 0 + final_stats: 815.5 + final_stats: 0 + final_stats: 24.7175 + final_stats: 0 + final_stats: 0 + final_stats: 0 + final_stats: 6233.5 + final_stats: 0 + final_stats: 0 + final_stats: 1974.7 + final_stats: 540 + final_stats: 0 + final_stats: 5 + final_stats: 0 + final_stats: 11.7175 + final_stats: 5 + final_stats: 0 + final_stats: 7130.82 + final_stats: 43 + final_stats: 75 + final_stats: 76 + final_stats: 60 + final_stats: 85 + final_stats: 384 + final_stats: 0 + final_stats: 65 + final_stats: 0 + } +} +stat_weights_results: { + key: "TestWarlock-Phase4-Lvl60-StatWeights-Default" + value: { + weights: 0 + weights: 0 + weights: 0 + weights: 0.06971 + weights: 0 + weights: 0.85007 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 9.82568 + weights: 4.96062 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Average-Default" + value: { + dps: 922.93664 + tps: 985.15323 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-FullBuffs-Consumes-LongMultiTarget" + value: { + dps: 910.29517 + tps: 2100.18562 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-FullBuffs-Consumes-LongSingleTarget" + value: { + dps: 910.29517 + tps: 972.17928 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-FullBuffs-Consumes-ShortSingleTarget" + value: { + dps: 944.73183 + tps: 987.76278 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-NoBuffs-Consumes-LongMultiTarget" + value: { + dps: 528.6421 + tps: 1808.84642 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-NoBuffs-Consumes-LongSingleTarget" + value: { + dps: 528.6421 + tps: 593.64701 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-NoBuffs-Consumes-ShortSingleTarget" + value: { + dps: 562.41626 + tps: 613.12879 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-FullBuffs-Consumes-LongMultiTarget" + value: { + dps: 1122.5486 + tps: 2089.17391 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-FullBuffs-Consumes-LongSingleTarget" + value: { + dps: 1122.5486 + tps: 951.82139 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-FullBuffs-Consumes-ShortSingleTarget" + value: { + dps: 1177.62985 + tps: 988.25245 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-NoBuffs-Consumes-LongMultiTarget" + value: { + dps: 608.4618 + tps: 1804.7454 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-NoBuffs-Consumes-LongSingleTarget" + value: { + dps: 608.4618 + tps: 591.27545 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-NoBuffs-Consumes-ShortSingleTarget" + value: { + dps: 645.2379 + tps: 613.25236 + } +} +dps_results: { + key: "TestWarlock-Phase4-Lvl60-SwitchInFrontOfTarget-Default" + value: { + dps: 910.29517 + tps: 972.17928 + } +} diff --git a/sim/warlock/dps/TestWarlockDSRuin.results b/sim/warlock/dps/TestWarlockDSRuin.results new file mode 100644 index 000000000..0738d121d --- /dev/null +++ b/sim/warlock/dps/TestWarlockDSRuin.results @@ -0,0 +1,161 @@ +character_stats_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-CharacterStats-Default" + value: { + final_stats: 195.5 + final_stats: 194.35 + final_stats: 559.682 + final_stats: 342.7 + final_stats: 258.9225 + final_stats: 496 + final_stats: 0 + final_stats: 40 + final_stats: 0 + final_stats: 0 + final_stats: 0 + final_stats: 161 + final_stats: 41.25 + final_stats: 0 + final_stats: 32.35455 + final_stats: 0 + final_stats: 0 + final_stats: 815.5 + final_stats: 0 + final_stats: 24.7175 + final_stats: 0 + final_stats: 0 + final_stats: 0 + final_stats: 6233.5 + final_stats: 0 + final_stats: 0 + final_stats: 1974.7 + final_stats: 540 + final_stats: 0 + final_stats: 5 + final_stats: 0 + final_stats: 11.7175 + final_stats: 5 + final_stats: 0 + final_stats: 7130.82 + final_stats: 43 + final_stats: 75 + final_stats: 76 + final_stats: 60 + final_stats: 85 + final_stats: 384 + final_stats: 0 + final_stats: 65 + final_stats: 0 + } +} +stat_weights_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-StatWeights-Default" + value: { + weights: 0 + weights: 0 + weights: 0 + weights: 0.06971 + weights: 0 + weights: 0.85007 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 9.82568 + weights: 4.96062 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + } +} +dps_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-AllItems-Demoniac'sThreads" + value: { + dps: 880.20312 + tps: 942.81885 + } +} +dps_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-Average-Default" + value: { + dps: 922.93664 + tps: 985.15323 + } +} +dps_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-FullBuffs-Consumes-LongMultiTarget" + value: { + dps: 910.29517 + tps: 2100.18562 + } +} +dps_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-FullBuffs-Consumes-LongSingleTarget" + value: { + dps: 910.29517 + tps: 972.17928 + } +} +dps_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-FullBuffs-Consumes-ShortSingleTarget" + value: { + dps: 944.73183 + tps: 987.76278 + } +} +dps_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-NoBuffs-Consumes-LongMultiTarget" + value: { + dps: 528.6421 + tps: 1808.84642 + } +} +dps_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-NoBuffs-Consumes-LongSingleTarget" + value: { + dps: 528.6421 + tps: 593.64701 + } +} +dps_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-Settings-Orc-mc-DS/Ruin Warlock-rotation-NoBuffs-Consumes-ShortSingleTarget" + value: { + dps: 562.41626 + tps: 613.12879 + } +} +dps_results: { + key: "TestWarlockDSRuin-Phase1-Lvl60-SwitchInFrontOfTarget-Default" + value: { + dps: 910.29517 + tps: 972.17928 + } +} diff --git a/sim/warlock/dps/TestWarlockSMRuin.results b/sim/warlock/dps/TestWarlockSMRuin.results new file mode 100644 index 000000000..04614ce6b --- /dev/null +++ b/sim/warlock/dps/TestWarlockSMRuin.results @@ -0,0 +1,161 @@ +character_stats_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-CharacterStats-Default" + value: { + final_stats: 195.5 + final_stats: 194.35 + final_stats: 486.68 + final_stats: 342.7 + final_stats: 272.55 + final_stats: 496 + final_stats: 0 + final_stats: 40 + final_stats: 0 + final_stats: 0 + final_stats: 0 + final_stats: 161 + final_stats: 41.25 + final_stats: 0 + final_stats: 32.35455 + final_stats: 0 + final_stats: 0 + final_stats: 815.5 + final_stats: 0 + final_stats: 24.7175 + final_stats: 0 + final_stats: 0 + final_stats: 0 + final_stats: 6233.5 + final_stats: 0 + final_stats: 0 + final_stats: 1974.7 + final_stats: 540 + final_stats: 0 + final_stats: 5 + final_stats: 0 + final_stats: 11.7175 + final_stats: 5 + final_stats: 0 + final_stats: 6400.8 + final_stats: 43 + final_stats: 75 + final_stats: 76 + final_stats: 60 + final_stats: 85 + final_stats: 384 + final_stats: 0 + final_stats: 65 + final_stats: 0 + } +} +stat_weights_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-StatWeights-Default" + value: { + weights: 0 + weights: 0 + weights: 0 + weights: -0.29728 + weights: 0 + weights: 0.69357 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 10.98591 + weights: 4.811 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + weights: 0 + } +} +dps_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-AllItems-Demoniac'sThreads" + value: { + dps: 1090.09072 + tps: 922.35578 + } +} +dps_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-Average-Default" + value: { + dps: 1132.51449 + tps: 962.70775 + } +} +dps_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-FullBuffs-Consumes-LongMultiTarget" + value: { + dps: 1122.5486 + tps: 2089.17391 + } +} +dps_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-FullBuffs-Consumes-LongSingleTarget" + value: { + dps: 1122.5486 + tps: 951.82139 + } +} +dps_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-FullBuffs-Consumes-ShortSingleTarget" + value: { + dps: 1177.62985 + tps: 988.25245 + } +} +dps_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-NoBuffs-Consumes-LongMultiTarget" + value: { + dps: 608.4618 + tps: 1804.7454 + } +} +dps_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-NoBuffs-Consumes-LongSingleTarget" + value: { + dps: 608.4618 + tps: 591.27545 + } +} +dps_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-Settings-Orc-mc-SM/Ruin Warlock-rotation-NoBuffs-Consumes-ShortSingleTarget" + value: { + dps: 645.2379 + tps: 613.25236 + } +} +dps_results: { + key: "TestWarlockSMRuin-Phase1-Lvl60-SwitchInFrontOfTarget-Default" + value: { + dps: 1122.5486 + tps: 951.82139 + } +} diff --git a/sim/warlock/dps/dps_warlock_test.go b/sim/warlock/dps/dps_warlock_test.go index 8500de2d5..f1ac36563 100644 --- a/sim/warlock/dps/dps_warlock_test.go +++ b/sim/warlock/dps/dps_warlock_test.go @@ -12,20 +12,20 @@ func init() { RegisterDpsWarlock() } -func TestAffliction(t *testing.T) { +func TestWarlockSMRuin(t *testing.T) { core.RunTestSuite(t, t.Name(), core.FullCharacterTestSuiteGenerator([]core.CharacterSuiteConfig{ { Class: proto.Class_ClassWarlock, - Phase: 4, + Phase: 1, Level: 60, Race: proto.Race_RaceOrc, - Talents: Phase4AffTalents, - GearSet: core.GetGearSet("../../../ui/warlock/gear_sets", "placeholder"), - Rotation: core.GetAplRotation("../../../ui/warlock/apls/p4", "affliction"), + Talents: TalentsSMRuin, + GearSet: core.GetGearSet("../../../ui/warlock/gear_sets", "mc"), + Rotation: core.GetAplRotation("../../../ui/warlock/apls/", "rotation"), Buffs: core.FullBuffs, - Consumes: Phase4Consumes, - SpecOptions: core.SpecOptionsCombo{Label: "Affliction Warlock", SpecOptions: DefaultAfflictionWarlock}, + Consumes: Consumes, + SpecOptions: core.SpecOptionsCombo{Label: "SM/Ruin Warlock", SpecOptions: DefaultDestroWarlock}, ItemFilter: ItemFilters, EPReferenceStat: proto.Stat_StatSpellPower, @@ -34,41 +34,20 @@ func TestAffliction(t *testing.T) { })) } -func TestDemonology(t *testing.T) { +func TestWarlockDSRuin(t *testing.T) { core.RunTestSuite(t, t.Name(), core.FullCharacterTestSuiteGenerator([]core.CharacterSuiteConfig{ { Class: proto.Class_ClassWarlock, - Level: 40, - Race: proto.Race_RaceOrc, - - Talents: Phase2DemonologyTalents, - GearSet: core.GetGearSet("../../../ui/warlock/gear_sets", "placeholder"), - Rotation: core.GetAplRotation("../../../ui/warlock/apls/p2", "demonology"), - Buffs: core.FullBuffs, - Consumes: Phase4Consumes, - SpecOptions: core.SpecOptionsCombo{Label: "Demonology Warlock", SpecOptions: DefaultDemonologyWarlock}, - - ItemFilter: ItemFilters, - EPReferenceStat: proto.Stat_StatSpellPower, - StatsToWeigh: Stats, - }, - })) -} - -func TestDestruction(t *testing.T) { - core.RunTestSuite(t, t.Name(), core.FullCharacterTestSuiteGenerator([]core.CharacterSuiteConfig{ - { - Class: proto.Class_ClassWarlock, - Phase: 4, + Phase: 1, Level: 60, Race: proto.Race_RaceOrc, - Talents: Phase4DestroTalents, - GearSet: core.GetGearSet("../../../ui/warlock/gear_sets", "placeholder"), - Rotation: core.GetAplRotation("../../../ui/warlock/apls/p4", "destruction"), + Talents: TalentsDSRuin, + GearSet: core.GetGearSet("../../../ui/warlock/gear_sets", "mc"), + Rotation: core.GetAplRotation("../../../ui/warlock/apls/", "rotation"), Buffs: core.FullBuffs, - Consumes: Phase4Consumes, - SpecOptions: core.SpecOptionsCombo{Label: "Destruction Warlock", SpecOptions: DefaultDestroWarlock}, + Consumes: Consumes, + SpecOptions: core.SpecOptionsCombo{Label: "DS/Ruin Warlock", SpecOptions: DefaultDestroWarlock}, ItemFilter: ItemFilters, EPReferenceStat: proto.Stat_StatSpellPower, @@ -77,50 +56,21 @@ func TestDestruction(t *testing.T) { })) } -var Phase1DestructionTalents = "-03-0550201" - -var Phase2AfflictionTalents = "3500253012201105--1" -var Phase2DemonologyTalents = "-2050033132501051" -var Phase2DestructionTalents = "-01-055020512000415" - -var Phase3BackdraftTalents = "-032004-5050205102005151" -var Phase3NFRuinTalents = "25002500102-03-50502051020001" - -var Phase4AffTalents = "4500253012201005--50502051020001" -var Phase4DestroTalents = "05002-035004-5050205102005151" +var TalentsSMRuin = "5502203112201105--52500051020001" +var TalentsDSRuin = "25002-2050300152201-52500051020001" var DefaultDestroWarlock = &proto.Player_Warlock{ Warlock: &proto.Warlock{ Options: &proto.WarlockOptions{ - Armor: proto.WarlockOptions_FelArmor, - Summon: proto.WarlockOptions_Imp, - WeaponImbue: proto.WarlockOptions_NoWeaponImbue, - }, - }, -} - -var DefaultAfflictionWarlock = &proto.Player_Warlock{ - Warlock: &proto.Warlock{ - Options: &proto.WarlockOptions{ - Armor: proto.WarlockOptions_FelArmor, - Summon: proto.WarlockOptions_Imp, - WeaponImbue: proto.WarlockOptions_NoWeaponImbue, - }, - }, -} - -var DefaultDemonologyWarlock = &proto.Player_Warlock{ - Warlock: &proto.Warlock{ - Options: &proto.WarlockOptions{ - Armor: proto.WarlockOptions_FelArmor, - Summon: proto.WarlockOptions_Felguard, + Armor: proto.WarlockOptions_DemonArmor, + Summon: proto.WarlockOptions_Succubus, WeaponImbue: proto.WarlockOptions_NoWeaponImbue, }, }, } -var Phase4Consumes = core.ConsumesCombo{ - Label: "P4-Consumes", +var Consumes = core.ConsumesCombo{ + Label: "Consumes", Consumes: &proto.Consumes{ DefaultPotion: proto.Potions_MajorManaPotion, Flask: proto.Flask_FlaskOfSupremePower, diff --git a/sim/warlock/drain_life.go b/sim/warlock/drain_life.go index 2e1019045..30e39f154 100644 --- a/sim/warlock/drain_life.go +++ b/sim/warlock/drain_life.go @@ -5,16 +5,12 @@ import ( "time" "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" ) const DrainLifeRanks = 6 func (warlock *Warlock) getDrainLifeBaseConfig(rank int) core.SpellConfig { - hasMasterChannelerRune := warlock.HasRune(proto.WarlockRune_RuneChestMasterChanneler) - hasSoulSiphonRune := warlock.HasRune(proto.WarlockRune_RuneCloakSoulSiphon) - - numTicks := core.TernaryInt32(hasMasterChannelerRune, 15, 5) + numTicks := int32(5) spellId := [DrainLifeRanks + 1]int32{0, 689, 699, 709, 7651, 11699, 11700}[rank] spellCoeff := [DrainLifeRanks + 1]float64{0, .078, .1, .1, .1, .1, .1}[rank] @@ -22,10 +18,6 @@ func (warlock *Warlock) getDrainLifeBaseConfig(rank int) core.SpellConfig { manaCost := [DrainLifeRanks + 1]float64{0, 55, 85, 135, 185, 240, 300}[rank] level := [DrainLifeRanks + 1]int{0, 14, 22, 30, 38, 46, 54}[rank] - if hasMasterChannelerRune { - manaCost *= 2 - } - baseDamage *= 1 + warlock.shadowMasteryBonus() + 0.02*float64(warlock.Talents.ImprovedDrainLife) actionID := core.ActionID{SpellID: spellId} @@ -46,7 +38,7 @@ func (warlock *Warlock) getDrainLifeBaseConfig(rank int) core.SpellConfig { SpellCode: SpellCode_WarlockDrainLife, DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, - Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | WarlockFlagAffliction | WarlockFlagHaunt, + Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | WarlockFlagAffliction | core.SpellFlagChanneled, RequiredLevel: level, Rank: rank, @@ -74,23 +66,13 @@ func (warlock *Warlock) getDrainLifeBaseConfig(rank int) core.SpellConfig { OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) { dot.Snapshot(target, baseDamage, isRollover) - - if hasSoulSiphonRune { - dot.SnapshotAttackerMultiplier *= warlock.calcSoulSiphonMultiplier(target, false) - } - // Drain Life heals so it snapshots target modifiers // Update 2024-06-29: It no longer snapshots on PTR // dot.SnapshotAttackerMultiplier *= dot.Spell.TargetDamageMultiplier(dot.Spell.Unit.AttackTables[target.UnitIndex][dot.Spell.CastType], true) }, OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { result := dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) - health := result.Damage - if hasMasterChannelerRune { - health *= 1.5 - } - healingSpell.CalcAndDealHealing(sim, healingSpell.Unit, health, healingSpell.OutcomeHealing) }, }, @@ -114,15 +96,6 @@ func (warlock *Warlock) getDrainLifeBaseConfig(rank int) core.SpellConfig { }, } - if hasMasterChannelerRune { - spellConfig.Cast.CD = core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: 15 * time.Second, - } - } else { - spellConfig.Flags |= core.SpellFlagChanneled - } - return spellConfig } diff --git a/sim/warlock/drain_soul.go b/sim/warlock/drain_soul.go index 22916ceef..03d2ac49e 100644 --- a/sim/warlock/drain_soul.go +++ b/sim/warlock/drain_soul.go @@ -5,17 +5,14 @@ import ( "time" "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" ) const DrainSoulRanks = 4 func (warlock *Warlock) getDrainSoulBaseConfig(rank int) core.SpellConfig { - hasSoulSiphonRune := warlock.HasRune(proto.WarlockRune_RuneCloakSoulSiphon) - baseNumTicks := int32(5) - numTicks := core.TernaryInt32(hasSoulSiphonRune, 15, baseNumTicks) - tickLength := time.Second * time.Duration(core.TernaryInt32(hasSoulSiphonRune, 1, 3)) + numTicks := baseNumTicks + tickLength := time.Second * 3 spellId := [DrainSoulRanks + 1]int32{0, 1120, 8288, 8289, 11675}[rank] spellCoeff := [DrainSoulRanks + 1]float64{0, 0.063, 0.1, 0.1, 0.1}[rank] @@ -29,7 +26,7 @@ func (warlock *Warlock) getDrainSoulBaseConfig(rank int) core.SpellConfig { SpellSchool: core.SpellSchoolShadow, DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, - Flags: core.SpellFlagAPL | core.SpellFlagChanneled | core.SpellFlagResetAttackSwing | WarlockFlagAffliction | WarlockFlagHaunt, + Flags: core.SpellFlagAPL | core.SpellFlagChanneled | core.SpellFlagResetAttackSwing | WarlockFlagAffliction, RequiredLevel: level, Rank: rank, @@ -56,10 +53,6 @@ func (warlock *Warlock) getDrainSoulBaseConfig(rank int) core.SpellConfig { OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) { dot.Snapshot(target, baseDamage, isRollover) - - if hasSoulSiphonRune { - dot.SnapshotAttackerMultiplier *= warlock.calcSoulSiphonMultiplier(target, sim.IsExecutePhase20()) - } }, OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) diff --git a/sim/warlock/felguard.go b/sim/warlock/felguard.go deleted file mode 100644 index 0a4c262e3..000000000 --- a/sim/warlock/felguard.go +++ /dev/null @@ -1,187 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" - "github.com/wowsims/classic/sim/core/stats" -) - -func (warlock *Warlock) makeFelguard() *WarlockPet { - cfg := PetConfig{ - Name: "Felguard", - PowerModifier: 0.77, - } - switch warlock.Level { - case 25: - cfg.Stats = stats.Stats{ - stats.Strength: 50, - stats.Agility: 40, - stats.Stamina: 87, - stats.Intellect: 35, - stats.Spirit: 61, - stats.Mana: 653, - stats.MP5: 0, - stats.MeleeCrit: 3.2685 * core.CritRatingPerCritChance, - stats.SpellCrit: 3.3355 * core.CritRatingPerCritChance, - } - cfg.AutoAttacks = core.AutoAttackOptions{ - MainHand: core.Weapon{ - BaseDamageMin: 24, - BaseDamageMax: 40, - SwingSpeed: 2, - }, - AutoSwingMelee: true, - } - case 40: - cfg.Stats = stats.Stats{ - stats.Strength: 74, - stats.Agility: 58, - stats.Stamina: 148, - stats.Intellect: 49, - stats.Spirit: 97, - stats.Mana: 653, - stats.MP5: 0, - stats.MeleeCrit: 3.2685 * core.CritRatingPerCritChance, - stats.SpellCrit: 3.3355 * core.CritRatingPerCritChance, - } - cfg.AutoAttacks = core.AutoAttackOptions{ - MainHand: core.Weapon{ - BaseDamageMin: 24, - BaseDamageMax: 40, - SwingSpeed: 2, - }, - AutoSwingMelee: true, - } - case 50: - cfg.Stats = stats.Stats{ - stats.Strength: 107, - stats.Agility: 71, - stats.Stamina: 190, - stats.Intellect: 59, - stats.Spirit: 123, - stats.Mana: 912, - stats.MP5: 0, - stats.MeleeCrit: 3.2685 * core.CritRatingPerCritChance, - stats.SpellCrit: 3.3355 * core.CritRatingPerCritChance, - } - cfg.AutoAttacks = core.AutoAttackOptions{ - MainHand: core.Weapon{ - BaseDamageMin: 67, - BaseDamageMax: 101, - SwingSpeed: 2, - }, - AutoSwingMelee: true, - } - case 60: - cfg.Stats = stats.Stats{ - stats.Strength: 129, - stats.Agility: 85, - stats.Stamina: 290, - stats.Intellect: 70, - stats.Spirit: 150, - stats.Mana: 1066, - stats.MP5: 0, - stats.MeleeCrit: 3.2685 * core.CritRatingPerCritChance, - stats.SpellCrit: 3.3355 * core.CritRatingPerCritChance, - } - cfg.AutoAttacks = core.AutoAttackOptions{ - MainHand: core.Weapon{ - BaseDamageMin: 87, - BaseDamageMax: 128, - SwingSpeed: 2, - }, - AutoSwingMelee: true, - } - } - - pet := warlock.makePet(cfg, warlock.Options.Summon == proto.WarlockOptions_Felguard) - // Felguard was given a ~20% damage buff on July 3rd that doesn't seem accounted for in base stats - pet.PseudoStats.DamageDealtMultiplier *= 1.20 - - return pet -} - -func (wp *WarlockPet) registerFelguardCleaveSpell() { - results := make([]*core.SpellResult, min(2, wp.Env.GetNumTargets())) - - wp.primaryAbility = wp.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 427744}, - SpellSchool: core.SpellSchoolPhysical, - DefenseType: core.DefenseTypeMelee, - ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagMeleeMetrics, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.1, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - IgnoreHaste: true, - CD: core.Cooldown{ - Timer: wp.NewTimer(), - Duration: time.Second * 6, - }, - }, - - DamageMultiplier: wp.AutoAttacks.MHConfig().DamageMultiplier, - ThreatMultiplier: 1, - BonusCoefficient: 1, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - for idx := range results { - baseDamage := 2.0 + spell.Unit.MHWeaponDamage(sim, spell.MeleeAttackPower()) - results[idx] = spell.CalcDamage(sim, target, baseDamage, spell.OutcomeMeleeSpecialHitAndCrit) - target = sim.Environment.NextTargetUnit(target) - } - for _, result := range results { - spell.DealDamage(sim, result) - } - }, - }) -} - -func (wp *WarlockPet) registerFelguardDemonicFrenzyAura() { - statDeps := make([]*stats.StatDependency, 11) // 10 stacks + zero condition - for i := 1; i < 11; i++ { - statDeps[i] = wp.NewDynamicMultiplyStat(stats.AttackPower, 1.0+.05*float64(i)) - } - - // Make a dummy copy on the Warlock for APL tracking - ownerAura := wp.owner.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 460907}, - Label: "Demonic Frenzy", - Duration: time.Second * 10, - MaxStacks: 10, - }) - - demonicFrenzyAura := wp.RegisterAura(core.Aura{ - ActionID: core.ActionID{SpellID: 460907}, - Label: "Demonic Frenzy", - Duration: time.Second * 10, - MaxStacks: 10, - OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) { - if oldStacks != 0 { - aura.Unit.DisableDynamicStatDep(sim, statDeps[oldStacks]) - } - if newStacks != 0 { - aura.Unit.EnableDynamicStatDep(sim, statDeps[newStacks]) - } - }, - }) - - core.MakePermanent(wp.RegisterAura(core.Aura{ - Label: "Demonic Frenzy Trigger", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() { - demonicFrenzyAura.Activate(sim) - demonicFrenzyAura.AddStack(sim) - ownerAura.Activate(sim) - ownerAura.AddStack(sim) - } - }, - })) -} diff --git a/sim/warlock/haunt.go b/sim/warlock/haunt.go deleted file mode 100644 index bb74d543c..000000000 --- a/sim/warlock/haunt.go +++ /dev/null @@ -1,77 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" -) - -func hauntMultiplier(spell *core.Spell, _ *core.AttackTable) float64 { - return core.TernaryFloat64(spell.Flags.Matches(WarlockFlagHaunt), 1.2, 1) -} - -func (warlock *Warlock) registerHauntSpell() { - if !warlock.HasRune(proto.WarlockRune_RuneHandsHaunt) { - return - } - - actionID := core.ActionID{SpellID: 403501} - - spellCoeff := 0.429 - baseLowDamage := warlock.baseRuneAbilityDamage() * 2.51 - baseHighDamage := warlock.baseRuneAbilityDamage() * 2.95 - - warlock.HauntDebuffAuras = warlock.NewEnemyAuraArray(func(target *core.Unit, level int32) *core.Aura { - return target.GetOrRegisterAura(core.Aura{ - Label: "Haunt-" + warlock.Label, - ActionID: actionID, - Duration: time.Second * 12, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.AttackTables[aura.Unit.UnitIndex][proto.CastType_CastTypeMainHand].DamageDoneByCasterMultiplier = hauntMultiplier - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.AttackTables[aura.Unit.UnitIndex][proto.CastType_CastTypeMainHand].DamageDoneByCasterMultiplier = nil - }, - }) - }) - - warlock.Haunt = warlock.RegisterSpell(core.SpellConfig{ - SpellCode: SpellCode_WarlockHaunt, - ActionID: actionID, - SpellSchool: core.SpellSchoolShadow, - DefenseType: core.DefenseTypeMagic, - ProcMask: core.ProcMaskSpellDamage, - Flags: core.SpellFlagAPL | core.SpellFlagBinary | core.SpellFlagResetAttackSwing | WarlockFlagAffliction, - MissileSpeed: 20, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.12, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - CD: core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: time.Second * 12, - }, - }, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - BonusCoefficient: spellCoeff, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseDamage := sim.Roll(baseLowDamage, baseHighDamage) - result := spell.CalcDamage(sim, target, baseDamage, spell.OutcomeMagicHitAndCrit) - spell.WaitTravelTime(sim, func(sim *core.Simulation) { - spell.DealDamage(sim, result) - if result.Landed() { - warlock.HauntDebuffAuras.Get(result.Target).Activate(sim) - } - }) - }, - RelatedAuras: []core.AuraArray{warlock.HauntDebuffAuras}, - }) -} diff --git a/sim/warlock/immolate.go b/sim/warlock/immolate.go index 361efabf1..971c22b65 100644 --- a/sim/warlock/immolate.go +++ b/sim/warlock/immolate.go @@ -5,7 +5,6 @@ import ( "time" "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" ) const ImmolateRanks = 8 @@ -20,11 +19,6 @@ func (warlock *Warlock) getImmolateConfig(rank int) core.SpellConfig { manaCost := [ImmolateRanks + 1]float64{0, 25, 45, 90, 155, 220, 295, 370, 380}[rank] level := [ImmolateRanks + 1]int{0, 1, 10, 20, 30, 40, 50, 60, 60}[rank] - hasInvocationRune := warlock.HasRune(proto.WarlockRune_RuneBeltInvocation) - hasPandemicRune := warlock.HasRune(proto.WarlockRune_RuneHelmPandemic) - hasUnstableAffliction := warlock.HasRune(proto.WarlockRune_RuneBracerUnstableAffliction) - hasShadowflameRune := warlock.HasRune(proto.WarlockRune_RuneBootsShadowflame) - return core.SpellConfig{ SpellCode: SpellCode_WarlockImmolate, ActionID: core.ActionID{SpellID: spellId}, @@ -49,9 +43,6 @@ func (warlock *Warlock) getImmolateConfig(rank int) core.SpellConfig { }, CastTime: func(spell *core.Spell) time.Duration { durationDecrease := time.Duration(0) - if warlock.shadowSparkAura.IsActive() { - durationDecrease = (spell.DefaultCast.CastTime / 2) * time.Duration(warlock.shadowSparkAura.GetStacks()) - } return spell.DefaultCast.CastTime - durationDecrease }, }, @@ -74,14 +65,7 @@ func (warlock *Warlock) getImmolateConfig(rank int) core.SpellConfig { }, OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { var result *core.SpellResult - if hasPandemicRune { - // We add the crit damage bonus and remove it after the call to not affect the initial damage portion of the spell - dot.Spell.CritDamageBonus += 1 - result = dot.CalcSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit) - dot.Spell.CritDamageBonus -= 1 - } else { - result = dot.CalcSnapshotDamage(sim, target, dot.OutcomeTick) - } + result = dot.CalcSnapshotDamage(sim, target, dot.OutcomeTick) dot.Spell.DealPeriodicDamage(sim, result) }, }, @@ -94,19 +78,6 @@ func (warlock *Warlock) getImmolateConfig(rank int) core.SpellConfig { if result.Landed() { dot := spell.Dot(target) - - // UA, Immo, Shadowflame exclusivity - if hasUnstableAffliction && warlock.UnstableAffliction.Dot(target).IsActive() { - warlock.UnstableAffliction.Dot(target).Deactivate(sim) - } - if hasShadowflameRune && warlock.Shadowflame.Dot(target).IsActive() { - warlock.Shadowflame.Dot(target).Deactivate(sim) - } - - if hasInvocationRune && dot.IsActive() { - warlock.InvocationRefresh(sim, dot) - } - dot.Apply(sim) } diff --git a/sim/warlock/immolation_aura.go b/sim/warlock/immolation_aura.go deleted file mode 100644 index 270d821db..000000000 --- a/sim/warlock/immolation_aura.go +++ /dev/null @@ -1,103 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" - "github.com/wowsims/classic/sim/core/stats" -) - -// Immolation Aura now triggers from being attacked rather than as a periodic effect. This cannot occur more than once per second, and does not require the attack to hit. -// Immolation Aura now also increases fire damage by 10%. -func (warlock *Warlock) registerImmolationAuraSpell() { - if !warlock.HasRune(proto.WarlockRune_RuneBracerImmolationAura) { - return - } - - spellCoeff := 0.045 - baseDamage := warlock.baseRuneAbilityDamage() * 0.2 - - immoAuraProc := warlock.GetOrRegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 427725}, - SpellSchool: core.SpellSchoolFire, - DefenseType: core.DefenseTypeMagic, - ProcMask: core.ProcMaskEmpty, - Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagPassiveSpell, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - BonusCoefficient: spellCoeff, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - for _, aoeTarget := range sim.Encounter.TargetUnits { - spell.CalcAndDealDamage(sim, aoeTarget, baseDamage, spell.OutcomeAlwaysHit) - } - }, - }) - - var pa *core.PendingAction - immoAura := warlock.RegisterAura(core.Aura{ - Label: "Immolation Aura", - ActionID: core.ActionID{SpellID: int32(proto.WarlockRune_RuneBracerImmolationAura)}, - Duration: core.NeverExpires, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - pa = core.NewPeriodicAction(sim, core.PeriodicActionOptions{ - Period: time.Second * 2, - OnAction: func(s *core.Simulation) { - immoAuraProc.Cast(sim, warlock.CurrentTarget) - }, - }) - // Dont proc damage in prepull - if pa.NextActionAt < 0 { - pa.NextActionAt = 0 - } - sim.AddPendingAction(pa) - - for si := stats.SchoolIndexArcane; si < stats.SchoolLen; si++ { - warlock.PseudoStats.SchoolDamageTakenMultiplier[si] *= 0.9 - } - - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= 1.10 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - pa.Cancel(sim) - - for si := stats.SchoolIndexArcane; si < stats.SchoolLen; si++ { - warlock.PseudoStats.SchoolDamageTakenMultiplier[si] /= 0.9 - } - - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] /= 1.10 - }, - }) - - core.MakeProcTriggerAura(&warlock.Unit, core.ProcTrigger{ - Name: "Immolation Aura Trigger", - Callback: core.CallbackOnSpellHitTaken, - ProcMask: core.ProcMaskSpellDamage, - ICD: time.Second * 1, - Handler: func(sim *core.Simulation, _ *core.Spell, _ *core.SpellResult) { - immoAura.Activate(sim) - }, - }) - - warlock.ImmolationAura = warlock.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: int32(proto.WarlockRune_RuneBracerImmolationAura)}, - SpellSchool: core.SpellSchoolFire, - Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | core.SpellFlagNoOnCastComplete | WarlockFlagDestruction, - - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - }, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - if immoAura.IsActive() { - immoAura.Deactivate(sim) - } else { - immoAura.Activate(sim) - } - }, - }) -} diff --git a/sim/warlock/incinerate.go b/sim/warlock/incinerate.go deleted file mode 100644 index 9c00620e6..000000000 --- a/sim/warlock/incinerate.go +++ /dev/null @@ -1,65 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" - "github.com/wowsims/classic/sim/core/stats" -) - -const IncinerateCastTime = time.Millisecond * 2250 - -func (warlock *Warlock) registerIncinerateSpell() { - if !warlock.HasRune(proto.WarlockRune_RuneBracerIncinerate) { - return - } - spellCoeff := 0.714 - baseLowDamage := warlock.baseRuneAbilityDamage() * 2.22 - baseHighDamage := warlock.baseRuneAbilityDamage() * 2.58 - - warlock.IncinerateAura = warlock.RegisterAura(core.Aura{ - Label: "Incinerate Aura", - ActionID: core.ActionID{SpellID: int32(proto.WarlockRune_RuneBracerIncinerate)}, - Duration: time.Second * 15, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= 1.40 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] /= 1.40 - }, - }) - - warlock.Incinerate = warlock.RegisterSpell(core.SpellConfig{ - SpellCode: SpellCode_WarlockIncinerate, - ActionID: core.ActionID{SpellID: 412758}, - SpellSchool: core.SpellSchoolFire, - DefenseType: core.DefenseTypeMagic, - ProcMask: core.ProcMaskSpellDamage, - Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | core.SpellFlagBinary | WarlockFlagDestruction, - MissileSpeed: 24, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.14, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: IncinerateCastTime, - }, - }, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - BonusCoefficient: spellCoeff, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - var baseDamage = sim.Roll(baseLowDamage, baseHighDamage) - result := spell.CalcDamage(sim, target, baseDamage, spell.OutcomeMagicHitAndCrit) - warlock.IncinerateAura.Activate(sim) - spell.WaitTravelTime(sim, func(sim *core.Simulation) { - spell.DealDamage(sim, result) - }) - }, - }) -} diff --git a/sim/warlock/infernal_armor.go b/sim/warlock/infernal_armor.go deleted file mode 100644 index 64a076697..000000000 --- a/sim/warlock/infernal_armor.go +++ /dev/null @@ -1,52 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" -) - -func (warlock *Warlock) registerInfernalArmorCD() { - if !warlock.HasRune(proto.WarlockRune_RuneCloakInfernalArmor) { - return - } - - actionID := core.ActionID{SpellID: int32(proto.WarlockRune_RuneCloakInfernalArmor)} - - // TODO: Unsure if there's a better way to do this - physResistanceMultiplier := 1.0 - infernalArmorAura := warlock.RegisterAura(core.Aura{ - ActionID: actionID, - Label: "Infernal Armor", - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - attackTable := warlock.CurrentTarget.AttackTables[warlock.UnitIndex][proto.CastType_CastTypeMainHand] - physResistanceMultiplier = 1 - attackTable.GetArmorDamageModifier() - warlock.PseudoStats.SchoolDamageTakenMultiplier.MultiplyMagicSchools(physResistanceMultiplier) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.PseudoStats.SchoolDamageTakenMultiplier.MultiplyMagicSchools(1 / physResistanceMultiplier) - }, - }) - - spell := warlock.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - SpellSchool: core.SpellSchoolShadow, - Flags: core.SpellFlagNoOnCastComplete, - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: time.Minute * 1, - }, - }, - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - infernalArmorAura.Activate(sim) - }, - }) - - warlock.AddMajorCooldown(core.MajorCooldown{ - Spell: spell, - Type: core.CooldownTypeSurvival, - }) -} diff --git a/sim/warlock/item_sets_pve.go b/sim/warlock/item_sets_pve.go new file mode 100644 index 000000000..28041b78a --- /dev/null +++ b/sim/warlock/item_sets_pve.go @@ -0,0 +1,120 @@ +package warlock + +import ( + "time" + + "github.com/wowsims/classic/sim/core" + "github.com/wowsims/classic/sim/core/stats" +) + +var ItemSetDeathmistRaiment = core.NewItemSet(core.ItemSet{ + Name: "Deathmist Raiment", + Bonuses: map[int32]core.ApplyEffect{ + // +8 All Resistances. + 2: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddResistances(8) + }, + // 4pc: When struck in combat has a chance of causing the attacker to flee in terror for 2 seconds. + // 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 ItemSetFelheartRaiment = core.NewItemSet(core.ItemSet{ + Name: "Felheart Raiment", + Bonuses: map[int32]core.ApplyEffect{ + // 3 pieces: Health or Mana gained from Drain Life and Drain Mana increased by 15%. + // 5 pieces: Your pet gains 15 stamina and 100 spell resistance against all schools of magic. + // 8 pieces: Mana cost of Shadow spells reduced by 15%. + 8: func(agent core.Agent) { + warlock := agent.(WarlockAgent).GetWarlock() + for _, spell := range warlock.Spellbook { + if spell.SpellSchool.Matches(core.SpellSchoolShadow) { + spell.Cost.Multiplier -= 15 + } + } + }, + }, +}) + +var ItemSetNemesisRaiment = core.NewItemSet(core.ItemSet{ + Name: "Nemesis Raiment", + Bonuses: map[int32]core.ApplyEffect{ + // 3 pieces: Increases damage and healing done by magical spells and effects by up to 23. + 3: func(agent core.Agent) { + agent.GetCharacter().AddStat(stats.SpellPower, 23) + }, + // 5 pieces: Your pet gains 20 stamina and 130 spell resistance against all schools of magic. + // 8 pieces: Reduces the threat generated by your Destruction spells by 20%. + }, +}) + +var ItemSetDemoniacsThreads = core.NewItemSet(core.ItemSet{ + Name: "Demoniac's Threads", + Bonuses: map[int32]core.ApplyEffect{ + // Increases damage and healing done by magical spells and effects by up to 12. + 2: func(agent core.Agent) { + warlock := agent.(WarlockAgent).GetWarlock() + warlock.AddStat(stats.SpellPower, 12) + }, + // 3 pieces: Increases the damage of Corruption by 2%. + 3: func(agent core.Agent) { + warlock := agent.(WarlockAgent).GetWarlock() + for _, corr := range warlock.Corruption { + corr.DamageMultiplierAdditive += 0.02 + } + }, + // 5 pieces: Decreases the cooldown of Death Coil by 15%. + 5: func(agent core.Agent) { + warlock := agent.(WarlockAgent).GetWarlock() + for _, spell := range warlock.DeathCoil { + spell.CD.Duration = time.Duration(float64(spell.CD.Duration) * 0.85) + } + }, + }, +}) + +var ItemSetDoomcallersAttire = core.NewItemSet(core.ItemSet{ + Name: "Doomcaller's Attire", + Bonuses: map[int32]core.ApplyEffect{ + // 3 pieces: 5% increased damage on your Immolate spell. + 4: func(agent core.Agent) { + warlock := agent.(WarlockAgent).GetWarlock() + for _, corr := range warlock.Immolate { + corr.BaseDamageMultiplierAdditive += 0.05 + } + }, + // 5 pieces: Reduces the mana cost of Shadow Bolt by 15%. + 5: func(agent core.Agent) { + warlock := agent.(WarlockAgent).GetWarlock() + for _, spell := range warlock.ShadowBolt { + spell.Cost.Multiplier -= 15 + } + }, + }, +}) + +var ItemSetPlagueheartRaiment = core.NewItemSet(core.ItemSet{ + Name: "Plagueheart Raiment", + Bonuses: map[int32]core.ApplyEffect{ + // 2 pieces: Your Shadow Bolts now have a chance to heal you for 270 to 330. + // 4 pieces: Increases damage caused by your Corruption by 12%. + 4: func(agent core.Agent) { + warlock := agent.(WarlockAgent).GetWarlock() + for _, corr := range warlock.Corruption { + corr.DamageMultiplierAdditive += 0.12 + } + }, + // 6 pieces: Your spell critical hits generate 25% less threat. In addition, Corruption, Immolate, Curse of Agony, and Siphon Life generate 25% less threat. + // 8 pieces: Reduces health cost of your Life Tap by 12%. + }, +}) diff --git a/sim/warlock/item_sets_pvp.go b/sim/warlock/item_sets_pvp.go new file mode 100644 index 000000000..6e7d191d2 --- /dev/null +++ b/sim/warlock/item_sets_pvp.go @@ -0,0 +1,80 @@ +package warlock + +import ( + "time" + + "github.com/wowsims/classic/sim/core" + "github.com/wowsims/classic/sim/core/stats" +) + +var bluePvPBonuses = 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) + }, + // Reduces the casting time of your Immolate spell by 0.2 sec. + 4: func(agent core.Agent) { + warlock := agent.(WarlockAgent).GetWarlock() + warlock.GetOrRegisterAura(core.Aura{ + Label: "Immolate Cast Time Reduction", + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range warlock.Immolate { + spell.DefaultCast.CastTime -= time.Millisecond * 200 + spell.DefaultCast.GCD -= time.Millisecond * 200 + } + }, + }) + }, + // +20 Stamina. + 6: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.Stamina, 20) + }, +} + +var ItemSetChampionsThreads = core.NewItemSet(core.ItemSet{ + Name: "Champion's Dreadgear", + Bonuses: bluePvPBonuses, +}) + +var ItemSetLieutenantCommandersThreads = core.NewItemSet(core.ItemSet{ + Name: "Lieutenant Commander's Dreadgear", + Bonuses: bluePvPBonuses, +}) + +var epicPvpBonuses = map[int32]core.ApplyEffect{ + // +20 Stamina. + 2: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.Stamina, 20) + }, + // Reduces the casting time of your Immolate spell by 0.2 sec. + 3: func(agent core.Agent) { + warlock := agent.(WarlockAgent).GetWarlock() + warlock.GetOrRegisterAura(core.Aura{ + Label: "Immolate Cast Time Reduction", + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range warlock.Immolate { + spell.DefaultCast.CastTime -= time.Millisecond * 200 + spell.DefaultCast.GCD -= time.Millisecond * 200 + } + }, + }) + }, + // 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) + }, +} + +var ItemSetWarlordsThreads = core.NewItemSet(core.ItemSet{ + Name: "Warlord's Threads", + Bonuses: epicPvpBonuses, +}) + +var ItemSetFieldMarshalsThreads = core.NewItemSet(core.ItemSet{ + Name: "Field Marshal's Threads", + Bonuses: epicPvpBonuses, +}) diff --git a/sim/warlock/lifetap.go b/sim/warlock/lifetap.go index b67bd3054..fc2d3a9d3 100644 --- a/sim/warlock/lifetap.go +++ b/sim/warlock/lifetap.go @@ -53,14 +53,7 @@ func (warlock *Warlock) getLifeTapBaseConfig(rank int) core.SpellConfig { spell.DealDamage(sim, result) } - if warlock.MetamorphosisAura != nil && warlock.MetamorphosisAura.IsActive() { - restore *= 2 - } - warlock.AddMana(sim, restore, manaMetrics) - if warlock.ActivePet != nil { - warlock.ActivePet.AddMana(sim, restore, warlock.ActivePet.LifeTapManaMetrics) - } }, } } diff --git a/sim/warlock/metamorphosis.go b/sim/warlock/metamorphosis.go deleted file mode 100644 index 8802d83b4..000000000 --- a/sim/warlock/metamorphosis.go +++ /dev/null @@ -1,57 +0,0 @@ -package warlock - -import ( - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" - "github.com/wowsims/classic/sim/core/stats" -) - -func (warlock *Warlock) registerMetamorphosisSpell() { - if !warlock.HasRune(proto.WarlockRune_RuneHandsMetamorphosis) { - return - } - - actionID := core.ActionID{SpellID: 403789} - warlock.MetamorphosisAura = warlock.RegisterAura(core.Aura{ - Label: "Metamorphosis Aura", - ActionID: actionID, - Duration: core.NeverExpires, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.ApplyDynamicEquipScaling(sim, stats.Armor, 6) - warlock.ApplyDynamicEquipScaling(sim, stats.BonusArmor, 6) - warlock.PseudoStats.DamageDealtMultiplier *= 0.85 - warlock.PseudoStats.ReducedCritTakenChance += 6 - warlock.PseudoStats.ThreatMultiplier *= 1.77 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.RemoveDynamicEquipScaling(sim, stats.Armor, 6) - warlock.RemoveDynamicEquipScaling(sim, stats.BonusArmor, 6) - warlock.PseudoStats.DamageDealtMultiplier /= 0.85 - warlock.PseudoStats.ReducedCritTakenChance -= 6 - warlock.PseudoStats.ThreatMultiplier /= 1.77 - }, - }) - - manaMetrics := warlock.NewManaMetrics(actionID) - - warlock.Metamorphosis = warlock.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagAPL | WarlockFlagDemonology, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - }, - ManaCost: core.ManaCostOptions{ - BaseCost: 1.0, - }, - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) { - if warlock.MetamorphosisAura.IsActive() { - warlock.MetamorphosisAura.Deactivate(sim) - warlock.AddMana(sim, warlock.BaseMana, manaMetrics) - } else { - warlock.MetamorphosisAura.Activate(sim) - } - }, - }) -} diff --git a/sim/warlock/pet.go b/sim/warlock/pet.go index 967fe53e9..dc0148c2a 100644 --- a/sim/warlock/pet.go +++ b/sim/warlock/pet.go @@ -22,7 +22,6 @@ type WarlockPet struct { DanceOfTheWickedManaMetrics *core.ResourceMetrics LifeTapManaMetrics *core.ResourceMetrics - T1Tank4PManaMetrics *core.ResourceMetrics // https://www.wowhead.com/classic/spell=457572/s03-item-t1-warlock-tank-4p-bonus manaPooling bool } @@ -38,8 +37,6 @@ func (warlock *Warlock) setDefaultActivePet() { switch warlock.Options.Summon { case proto.WarlockOptions_Imp: warlock.ActivePet = warlock.Imp - case proto.WarlockOptions_Felguard: - warlock.ActivePet = warlock.Felguard case proto.WarlockOptions_Felhunter: warlock.ActivePet = warlock.Felhunter case proto.WarlockOptions_Succubus: @@ -81,11 +78,6 @@ func (warlock *Warlock) registerPets() { warlock.Voidwalker = warlock.makeVoidwalker() warlock.BasePets = []*WarlockPet{warlock.Felhunter, warlock.Imp, warlock.Succubus, warlock.Voidwalker} - - if warlock.HasRune(proto.WarlockRune_RuneBracerSummonFelguard) { - warlock.Felguard = warlock.makeFelguard() - warlock.BasePets = append(warlock.BasePets, warlock.Felguard) - } } func (warlock *Warlock) makePet(cfg PetConfig, enabledOnStart bool) *WarlockPet { @@ -129,10 +121,6 @@ func (warlock *Warlock) makePet(cfg PetConfig, enabledOnStart bool) *WarlockPet } func (warlock *Warlock) registerPetAbilities() { - if warlock.Felguard != nil { - warlock.Felguard.registerFelguardCleaveSpell() - warlock.Felguard.registerFelguardDemonicFrenzyAura() - } warlock.Imp.registerImpFireboltSpell() warlock.Succubus.registerSuccubusLashOfPainSpell() } diff --git a/sim/warlock/rain_of_fire.go b/sim/warlock/rain_of_fire.go index a876ee50f..3811af789 100644 --- a/sim/warlock/rain_of_fire.go +++ b/sim/warlock/rain_of_fire.go @@ -5,24 +5,18 @@ import ( "time" "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" ) const RainOfFireRanks = 4 func (warlock *Warlock) getRainOfFireBaseConfig(rank int) core.SpellConfig { - hasLakeOfFireRune := warlock.HasRune(proto.WarlockRune_RuneChestLakeOfFire) - spellId := [RainOfFireRanks + 1]int32{0, 5740, 6219, 11677, 11678}[rank] spellCoeff := [RainOfFireRanks + 1]float64{0, 0.083, 0.083, 0.083, 0.083}[rank] baseDamage := [RainOfFireRanks + 1]float64{0, 42, 92, 155, 226}[rank] manaCost := [RainOfFireRanks + 1]float64{0, 295, 605, 885, 1185}[rank] level := [RainOfFireRanks + 1]int{0, 20, 34, 46, 58}[rank] - flags := core.SpellFlagAPL | core.SpellFlagResetAttackSwing | WarlockFlagDestruction - if !hasLakeOfFireRune { - flags |= core.SpellFlagChanneled - } + flags := core.SpellFlagAPL | core.SpellFlagResetAttackSwing | WarlockFlagDestruction | core.SpellFlagChanneled config := core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, @@ -69,13 +63,6 @@ func (warlock *Warlock) getRainOfFireBaseConfig(rank int) core.SpellConfig { }, } - if hasLakeOfFireRune { - config.Cast.CD = core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: time.Second * 8, - } - } - return config } diff --git a/sim/warlock/runes.go b/sim/warlock/runes.go deleted file mode 100644 index 5414e36ae..000000000 --- a/sim/warlock/runes.go +++ /dev/null @@ -1,518 +0,0 @@ -package warlock - -import ( - "fmt" - "slices" - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" - "github.com/wowsims/classic/sim/core/stats" -) - -func (warlock *Warlock) ApplyRunes() { - // Helm runes - warlock.applyVengeance() - warlock.applyBackdraft() - - // Cloak Runes - warlock.applyDecimation() - warlock.registerInfernalArmorCD() - - // Chest Runes - warlock.applyDemonicTactics() - - // Bracer Runes - warlock.registerIncinerateSpell() - warlock.registerUnstableAfflictionSpell() - warlock.registerImmolationAuraSpell() - - // Glove Runes - warlock.registerHauntSpell() - warlock.registerChaosBoltSpell() - warlock.registerMetamorphosisSpell() - warlock.registerShadowCleaveSpell() - - // Belt Runes - warlock.applyGrimoireOfSynergy() - warlock.applyShadowAndFlame() - - // Pants Runes - warlock.applyEverlastingAffliction() - warlock.applyDemonicPact() - warlock.registerDemonicGraceSpell() - - // Boots Runes - warlock.applyDemonicKnowledge() - warlock.applyDanceOfTheWicked() - warlock.registerShadowflameSpell() - warlock.applyMarkOfChaos() -} - -func (warlock *Warlock) applyVengeance() { - if !warlock.HasRune(proto.WarlockRune_RuneHelmVengeance) { - return - } - - actionID := core.ActionID{SpellID: int32(proto.WarlockRune_RuneHelmVengeance)} - healthMetrics := warlock.NewHealthMetrics(actionID) - var bonusHealth float64 - - aura := warlock.RegisterAura(core.Aura{ - Label: "Vengeance", - ActionID: actionID, - Duration: time.Second * 20, - - OnGain: func(aura *core.Aura, sim *core.Simulation) { - bonusHealth = warlock.MaxHealth() * 0.30 - warlock.AddStatsDynamic(sim, stats.Stats{stats.Health: bonusHealth}) - warlock.GainHealth(sim, bonusHealth, healthMetrics) - - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.AddStatsDynamic(sim, stats.Stats{stats.Health: -bonusHealth}) - healthDiff := warlock.CurrentHealth() - warlock.MaxHealth() - if healthDiff > 0 { - warlock.RemoveHealth(sim, healthDiff) - } - }, - }) - - spell := warlock.GetOrRegisterSpell(core.SpellConfig{ - ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete, - - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: time.Minute * 3, - }, - }, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - aura.Activate(sim) - }, - }) - - warlock.AddMajorCooldown(core.MajorCooldown{ - Spell: spell, - Type: core.CooldownTypeSurvival, - ShouldActivate: func(sim *core.Simulation, character *core.Character) bool { - return character.CurrentHealthPercent() < 0.5 - }, - }) -} - -func (warlock *Warlock) applyBackdraft() { - if !warlock.HasRune(proto.WarlockRune_RuneHelmBackdraft) { - return - } - - warlock.BackdraftAura = warlock.RegisterAura(core.Aura{ - Label: "Backdraft", - ActionID: core.ActionID{SpellID: 427714}, - Duration: time.Second * 15, - - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.MultiplyCastSpeed(1.3) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.MultiplyCastSpeed(1 / 1.3) - }, - }) -} - -func (warlock *Warlock) applyDecimation() { - if !warlock.HasRune(proto.WarlockRune_RuneBootsDecimation) { - return - } - - affectedSpellCodes := []int32{SpellCode_WarlockShadowBolt, SpellCode_WarlockShadowCleave, SpellCode_WarlockIncinerate, SpellCode_WarlockSoulFire} - - warlock.DecimationAura = warlock.RegisterAura(core.Aura{ - Label: "Decimation", - ActionID: core.ActionID{SpellID: 440873}, - Duration: time.Second * 10, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.SoulFire { - spell.CastTimeMultiplier *= .6 - } - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range warlock.SoulFire { - spell.CastTimeMultiplier /= .6 - } - }, - }) - - // Hidden trigger aura - core.MakePermanent(warlock.RegisterAura(core.Aura{ - Label: "Decimation Trigger", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() && sim.IsExecutePhase35() && slices.Contains(affectedSpellCodes, spell.SpellCode) { - warlock.DecimationAura.Activate(sim) - } - }, - })) -} - -func (warlock *Warlock) applyMarkOfChaos() { - if !warlock.HasRune(proto.WarlockRune_RuneCloakMarkOfChaos) { - return - } - - // warlock.MarkOfChaosAuras = warlock.NewEnemyAuraArray(func(target *core.Unit, _ int32) *core.Aura { - // return core.MarkOfChaosDebuffAura(target) - // }) -} - -func (warlock *Warlock) applyMarkOfChaosDebuff(sim *core.Simulation, target *core.Unit, duration time.Duration) { - aura := warlock.MarkOfChaosAuras.Get(target) - // Only expire if not set as a permanent raid debuff. - if !aura.IsPermanent() { - aura.Duration = duration - aura.UpdateExpires(sim, sim.CurrentTime+duration) - } - aura.Activate(sim) -} - -func (warlock *Warlock) InvocationRefresh(sim *core.Simulation, dot *core.Dot) { - if dot.RemainingDuration(sim) < time.Second*6 { - ticksLeft := dot.NumberOfTicks - dot.TickCount - for i := int32(0); i < ticksLeft; i++ { - dot.TickOnce(sim) - } - } -} - -func (warlock *Warlock) applyEverlastingAffliction() { - if !warlock.HasRune(proto.WarlockRune_RuneLegsEverlastingAffliction) { - return - } - - affectedSpellCodes := []int32{SpellCode_WarlockDrainLife, SpellCode_WarlockDrainSoul, SpellCode_WarlockShadowBolt, SpellCode_WarlockShadowCleave, SpellCode_WarlockSearingPain, SpellCode_WarlockIncinerate, SpellCode_WarlockHaunt} - warlock.RegisterAura(core.Aura{ - Label: "Everlasting Affliction Trigger", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.Landed() && slices.Contains(affectedSpellCodes, spell.SpellCode) { - for _, spell := range warlock.Corruption { - if spell.Dot(result.Target).IsActive() { - spell.Dot(result.Target).Rollover(sim) - } - } - } - }, - }) -} - -func (warlock *Warlock) applyDanceOfTheWicked() { - if !warlock.HasRune(proto.WarlockRune_RuneBootsDanceOfTheWicked) { - return - } - - actionId := core.ActionID{SpellID: 412800} - dodgeModifier := warlock.NewDynamicStatDependency(stats.SpellCrit, stats.Dodge, 1) - - dotwAura := warlock.GetOrRegisterAura(core.Aura{ - Label: "Dance of the Wicked Proc", - ActionID: actionId, - Duration: 15 * time.Second, - - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.EnableDynamicStatDep(sim, dodgeModifier) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.DisableDynamicStatDep(sim, dodgeModifier) - }, - }) - - manaMetric := warlock.NewManaMetrics(actionId) - for _, pet := range warlock.BasePets { - pet.DanceOfTheWickedManaMetrics = pet.NewManaMetrics(actionId) - } - - handler := func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskDirect) { - return - } - - if !result.DidCrit() { - return - } - - dotwAura.Activate(sim) - - warlock.AddMana(sim, warlock.MaxMana()*0.02, manaMetric) - if warlock.ActivePet != nil { - warlock.ActivePet.AddMana(sim, warlock.ActivePet.MaxMana()*0.02, warlock.ActivePet.DanceOfTheWickedManaMetrics) - } - } - - core.MakePermanent(warlock.GetOrRegisterAura(core.Aura{ - Label: "Dance of the Wicked", - OnSpellHitDealt: handler, - OnPeriodicDamageDealt: handler, - })) -} - -func (warlock *Warlock) applyDemonicKnowledge() { - if !warlock.HasRune(proto.WarlockRune_RuneBootsDemonicKnowledge) { - return - } - - for _, pet := range warlock.BasePets { - oldOnPetEnable := pet.OnPetEnable - pet.OnPetEnable = func(sim *core.Simulation) { - oldOnPetEnable(sim) - warlock.DemonicKnowledgeAura.Activate(sim) - } - - oldOnPetDisable := pet.OnPetDisable - pet.OnPetDisable = func(sim *core.Simulation) { - oldOnPetDisable(sim) - warlock.DemonicKnowledgeAura.Deactivate(sim) - } - } - - warlock.DemonicKnowledgeAura = warlock.GetOrRegisterAura(core.Aura{ - Label: "Demonic Knowledge", - ActionID: core.ActionID{SpellID: int32(proto.WarlockRune_RuneBootsDemonicKnowledge)}, - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - warlock.demonicKnowledgeSp = 0 - }, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.demonicKnowledgeSp = (warlock.ActivePet.GetStat(stats.Stamina) + warlock.ActivePet.GetStat(stats.Intellect)) * .03 - warlock.AddStatDynamic(sim, stats.SpellPower, warlock.demonicKnowledgeSp) - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.AddStatDynamic(sim, stats.SpellPower, -warlock.demonicKnowledgeSp) - warlock.demonicKnowledgeSp = 0 - }, - }) -} - -func (warlock *Warlock) applyGrimoireOfSynergy() { - if !warlock.HasRune(proto.WarlockRune_RuneBeltGrimoireOfSynergy) { - return - } - - actionID := core.ActionID{SpellID: 426303} - dmgMod := 1.10 - procChance := 0.10 - - procAuraConfig := core.Aura{ - Label: "Grimoire of Synergy Proc", - ActionID: actionID, - Duration: time.Second * 15, - OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.DamageDealtMultiplier *= dmgMod - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.PseudoStats.DamageDealtMultiplier /= dmgMod - }, - } - - handlerFunc := func(procAura *core.Aura) func(*core.Aura, *core.Simulation, *core.Spell, *core.SpellResult) { - return func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.ProcMask.Matches(core.ProcMaskDirect) { - return - } - - if sim.RandomFloat("Grimoire of Synergy") > procChance { - return - } - - procAura.Activate(sim) - } - } - warlockProcAura := warlock.GetOrRegisterAura(procAuraConfig) - for _, pet := range warlock.BasePets { - petProcAura := pet.GetOrRegisterAura(procAuraConfig) - core.MakePermanent(warlock.GetOrRegisterAura(core.Aura{ - Label: fmt.Sprintf("Grimoire of Synergy Trigger (%s)", pet.Name), - OnSpellHitDealt: handlerFunc(petProcAura), - OnPeriodicDamageDealt: handlerFunc(petProcAura), - })) - core.MakePermanent(pet.GetOrRegisterAura(core.Aura{ - Label: "Grimoire of Synergy Trigger", - OnSpellHitDealt: handlerFunc(warlockProcAura), - OnPeriodicDamageDealt: handlerFunc(warlockProcAura), - })) - } -} - -func (warlock *Warlock) applyShadowAndFlame() { - if !warlock.HasRune(proto.WarlockRune_RuneBeltShadowAndFlame) { - return - } - - procAura := warlock.GetOrRegisterAura(core.Aura{ - Label: "Shadow and Flame proc", - ActionID: core.ActionID{SpellID: 426311}, - Duration: time.Second * 10, - - OnGain: func(aura *core.Aura, sim *core.Simulation) { - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= 1.10 - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] *= 1.10 - }, - OnExpire: func(aura *core.Aura, sim *core.Simulation) { - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] /= 1.10 - warlock.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexShadow] /= 1.10 - }, - }) - - procHandler := func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !spell.SpellSchool.Matches(core.SpellSchoolFire | core.SpellSchoolShadow) { - return - } - - if !result.DidCrit() { - return - } - - procAura.Activate(sim) - } - - core.MakePermanent(warlock.GetOrRegisterAura(core.Aura{ - Label: "Shadow and Flame", - OnSpellHitDealt: procHandler, - OnPeriodicDamageDealt: procHandler, - })) -} - -// https://www.wowhead.com/classic/spell=403511/soul-siphon -// Causes your Drain Soul to to deal damage 3 times faster and increases the amount drained by your Drain Life and Drain Soul spells by an additional -// 6% for each of your Warlock Shadow effects afflicting the target, up to a maximum of 18% additional effect. -// When Drain Soul is cast on a target below 20% health, it instead gains 50% per effect, up to a maximum of 150%. -const SoulSiphonDoTMultiplier = 0.06 -const SoulSiphonDoTMultiplierExecute = 1.00 -const SoulSiphonDoTMultiplierMax = 0.18 -const SoulSiphonDoTMultiplierMaxExecute = 3.00 - -func (warlock *Warlock) calcSoulSiphonMultiplier(target *core.Unit, executeBonus bool) float64 { - multiplier := 1.0 - perDoTMultiplier := core.TernaryFloat64(executeBonus, SoulSiphonDoTMultiplierExecute, SoulSiphonDoTMultiplier) - maxMultiplier := 1 + core.TernaryFloat64(executeBonus, SoulSiphonDoTMultiplierMaxExecute, SoulSiphonDoTMultiplierMax) - - for _, spell := range warlock.Corruption { - if spell.Dot(target).IsActive() { - multiplier += perDoTMultiplier - break - } - } - - for _, spell := range warlock.CurseOfAgony { - if spell.Dot(target).IsActive() { - multiplier += perDoTMultiplier - break - } - } - - if warlock.CurseOfDoom != nil && warlock.CurseOfDoom.Dot(target).IsActive() { - multiplier += perDoTMultiplier - } - - for _, spell := range warlock.SiphonLife { - if spell.Dot(target).IsActive() { - multiplier += perDoTMultiplier - break - } - } - - if warlock.UnstableAffliction != nil && warlock.UnstableAffliction.Dot(target).IsActive() { - multiplier += perDoTMultiplier - } - - if warlock.Shadowflame != nil && warlock.Shadowflame.Dot(target).IsActive() { - multiplier += perDoTMultiplier - } - - if warlock.Haunt != nil && warlock.HauntDebuffAuras.Get(target).IsActive() { - multiplier += perDoTMultiplier - } - - return min(multiplier, maxMultiplier) -} - -// Increases the melee and spell critical strike chance of you and your pet by 10%. -func (warlock *Warlock) applyDemonicTactics() { - if !warlock.HasRune(proto.WarlockRune_RuneChestDemonicTactics) { - return - } - - warlock.AddStat(stats.MeleeCrit, 10*core.CritRatingPerCritChance) - warlock.AddStat(stats.SpellCrit, 10*core.SpellCritRatingPerCritChance) -} - -func (warlock *Warlock) getHighestSP() float64 { - return warlock.GetStat(stats.SpellPower) + warlock.GetStat(stats.SpellDamage) + max(warlock.GetStat(stats.FirePower), warlock.GetStat(stats.ShadowPower)) -} - -func (warlock *Warlock) applyDemonicPact() { - if !warlock.HasRune(proto.WarlockRune_RuneLegsDemonicPact) { - return - } - - warlock.PseudoStats.SchoolDamageDealtMultiplier.MultiplyMagicSchools(1.10) - - if warlock.Options.Summon == proto.WarlockOptions_NoSummon { - return - } - - /* icd := core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: 1 * time.Second, - } - - spellPower := max(warlock.getHighestSP()*0.1, float64(warlock.Level)/2.0) - demonicPactAuras := warlock.NewRaidAuraArray(func(u *core.Unit) *core.Aura { - return core.DemonicPactAura(u, spellPower, core.CharacterBuildPhaseNone) - }) - - dpTriggerConfig := core.Aura{ - Label: "Demonic Pact Trigger", - Duration: core.NeverExpires, - OnReset: func(aura *core.Aura, sim *core.Simulation) { - aura.Activate(sim) - }, - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if !result.DidCrit() || !icd.IsReady(sim) { - return - } - - icd.Use(sim) - - lastBonus := 0.0 - currentSP := warlock.getHighestSP() - warlockAura := demonicPactAuras.Get(&warlock.Unit) - - // Remove DP bonus from SP bonus if active - if warlockAura.IsActive() { - lastBonus = demonicPactAuras.Get(&warlock.Unit).ExclusiveEffects[0].Priority - } - newSPBonus := max(math.Round(0.10*(currentSP-lastBonus)), math.Round(float64(warlock.Level)/2)) - - if warlockAura.RemainingDuration(sim) < 10*time.Second || newSPBonus >= lastBonus { - for _, dpAura := range demonicPactAuras { - if dpAura != nil { - // Force expire/gain because of new sp bonus - dpAura.Deactivate(sim) - - dpAura.ExclusiveEffects[0].SetPriority(sim, newSPBonus) - dpAura.Activate(sim) - dpAura.SetStacks(sim, int32(newSPBonus)) - } - } - } - }, - } - - for _, pet := range warlock.BasePets { - pet.RegisterAura(dpTriggerConfig) - } */ -} diff --git a/sim/warlock/searing_pain.go b/sim/warlock/searing_pain.go index 94f304b62..e80c90926 100644 --- a/sim/warlock/searing_pain.go +++ b/sim/warlock/searing_pain.go @@ -34,13 +34,6 @@ func (warlock *Warlock) getSearingPainBaseConfig(rank int) core.SpellConfig { GCD: core.GCDDefault, CastTime: castTime, }, - ModifyCast: func(sim *core.Simulation, spell *core.Spell, cast *core.Cast) { - if warlock.MetamorphosisAura != nil && warlock.MetamorphosisAura.IsActive() { - spell.DefaultCast.CastTime = 0 - } else { - spell.DefaultCast.CastTime = castTime - } - }, }, BonusCritRating: 2.0 * float64(warlock.Talents.ImprovedSearingPain) * core.CritRatingPerCritChance, diff --git a/sim/warlock/shadow_cleave.go b/sim/warlock/shadow_cleave.go deleted file mode 100644 index b15a83fb8..000000000 --- a/sim/warlock/shadow_cleave.go +++ /dev/null @@ -1,90 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" - "github.com/wowsims/classic/sim/core/stats" -) - -func (warlock *Warlock) getShadowCleaveBaseConfig(rank int) core.SpellConfig { - spellCoeff := [11]float64{0, .047, .1, .187, .286, .286, .286, .286, .286, .286, .286}[rank] - baseDamage := [11][]float64{{0}, {3, 7}, {7, 12}, {14, 23}, {26, 39}, {42, 64}, {60, 91}, {82, 124}, {105, 158}, {128, 193}, {136, 204}}[rank] - spellId := [11]int32{0, 403835, 403839, 403840, 403841, 403842, 403843, 403844, 403848, 403851, 403852}[rank] - manaCost := [11]float64{0, 12, 20, 35, 55, 80, 105, 132, 157, 185, 190}[rank] - level := [11]int{0, 1, 6, 12, 20, 28, 36, 44, 52, 60, 60}[rank] - - results := make([]*core.SpellResult, min(10, warlock.Env.GetNumTargets())) - - return core.SpellConfig{ - ActionID: core.ActionID{SpellID: spellId}, - SpellSchool: core.SpellSchoolShadow, - SpellCode: SpellCode_WarlockShadowCleave, - DefenseType: core.DefenseTypeMagic, - ProcMask: core.ProcMaskSpellDamage, - Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | WarlockFlagDestruction, - RequiredLevel: level, - Rank: rank, - - ManaCost: core.ManaCostOptions{ - FlatCost: manaCost, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - CD: core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: time.Second * 6, - }, - }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - return warlock.MetamorphosisAura.IsActive() - }, - - DamageMultiplier: 1, - ThreatMultiplier: 2, // Undocumented 2x multiplier - BonusCoefficient: spellCoeff, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - for idx := range results { - damage := sim.Roll(baseDamage[0], baseDamage[1]) - results[idx] = spell.CalcDamage(sim, target, damage, spell.OutcomeMagicHitAndCrit) - target = sim.Environment.NextTargetUnit(target) - } - - hasHit := false - for _, result := range results { - if result.Landed() { - hasHit = true - spell.DealDamage(sim, result) - } - } - - if stacks := int32(warlock.GetStat(stats.Defense)); hasHit && stacks > 0 { - warlock.defendersResolveAura.Activate(sim) - if warlock.defendersResolveAura.GetStacks() != stacks { - warlock.defendersResolveAura.SetStacks(sim, stacks) - } - } - }, - } -} - -func (warlock *Warlock) registerShadowCleaveSpell() { - if !warlock.HasRune(proto.WarlockRune_RuneHandsMetamorphosis) { - return - } - - warlock.defendersResolveAura = core.DefendersResolveSpellDamage(warlock.GetCharacter()) - - warlock.ShadowCleave = make([]*core.Spell, 0) - for rank := 1; rank <= ShadowBoltRanks; rank++ { - config := warlock.getShadowCleaveBaseConfig(rank) - - if config.RequiredLevel <= int(warlock.Level) { - warlock.ShadowCleave = append(warlock.ShadowCleave, warlock.GetOrRegisterSpell(config)) - } - } -} diff --git a/sim/warlock/shadowbolt.go b/sim/warlock/shadowbolt.go index 5cd62ad70..c8f6d2cb8 100644 --- a/sim/warlock/shadowbolt.go +++ b/sim/warlock/shadowbolt.go @@ -4,14 +4,11 @@ import ( "time" "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" ) const ShadowBoltRanks = 10 func (warlock *Warlock) getShadowBoltBaseConfig(rank int) core.SpellConfig { - hasMarkOfChaosRune := warlock.HasRune(proto.WarlockRune_RuneCloakMarkOfChaos) - spellCoeff := [ShadowBoltRanks + 1]float64{0, .14, .299, .56, .857, .857, .857, .857, .857, .857, .857}[rank] baseDamage := [ShadowBoltRanks + 1][]float64{{0}, {13, 18}, {26, 32}, {52, 61}, {92, 104}, {150, 170}, {213, 240}, {292, 327}, {373, 415}, {455, 507}, {482, 538}}[rank] spellId := [ShadowBoltRanks + 1]int32{0, 686, 695, 705, 1088, 1106, 7641, 11659, 11660, 11661, 25307}[rank] @@ -19,10 +16,9 @@ func (warlock *Warlock) getShadowBoltBaseConfig(rank int) core.SpellConfig { level := [ShadowBoltRanks + 1]int{0, 1, 6, 12, 20, 28, 36, 44, 52, 60, 60}[rank] castTime := [ShadowBoltRanks + 1]int32{0, 1700, 2200, 2800, 3000, 3000, 3000, 3000, 3000, 3000, 3000}[rank] - shadowboltVolley := warlock.HasRune(proto.WarlockRune_RuneHandsShadowBoltVolley) - damageMulti := core.TernaryFloat64(shadowboltVolley, 0.95, 1.0) + damageMulti := 1.0 - results := make([]*core.SpellResult, min(core.TernaryInt32(shadowboltVolley, 5, 1), warlock.Env.GetNumTargets())) + results := make([]*core.SpellResult, 1, warlock.Env.GetNumTargets()) return core.SpellConfig{ SpellCode: SpellCode_WarlockShadowBolt, @@ -43,9 +39,6 @@ func (warlock *Warlock) getShadowBoltBaseConfig(rank int) core.SpellConfig { CastTime: time.Millisecond * time.Duration(castTime), }, }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - return warlock.MetamorphosisAura == nil || !warlock.MetamorphosisAura.IsActive() - }, DamageMultiplier: damageMulti, ThreatMultiplier: 1, @@ -68,10 +61,6 @@ func (warlock *Warlock) getShadowBoltBaseConfig(rank int) core.SpellConfig { } } - if hasMarkOfChaosRune && warlock.MarkOfChaosAuras.Get(warlock.CurrentTarget).IsActive() { - activeEffectMultiplier += warlock.shadowBoltActiveEffectMultiplierPer - } - activeEffectMultiplier = min(warlock.shadowBoltActiveEffectMultiplierMax, activeEffectMultiplier) } diff --git a/sim/warlock/shadowflame.go b/sim/warlock/shadowflame.go deleted file mode 100644 index 575979b32..000000000 --- a/sim/warlock/shadowflame.go +++ /dev/null @@ -1,101 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" -) - -const ShadowflameCastTime = time.Second * 2 - -func (warlock *Warlock) registerShadowflameSpell() { - if !warlock.HasRune(proto.WarlockRune_RuneBootsShadowflame) { - return - } - - hasInvocationRune := warlock.HasRune(proto.WarlockRune_RuneBeltInvocation) - hasPandemicRune := warlock.HasRune(proto.WarlockRune_RuneHelmPandemic) - - baseSpellCoeff := 0.20 - dotSpellCoeff := 0.13 - baseDamage := warlock.baseRuneAbilityDamage() * 2.26 - dotDamage := warlock.baseRuneAbilityDamage() * 0.61 - - numTicks := int32(5) - tickLength := time.Second * 3 - - warlock.Shadowflame = warlock.RegisterSpell(core.SpellConfig{ - SpellCode: SpellCode_WarlockShadowflame, - ActionID: core.ActionID{SpellID: 426320}, - SpellSchool: core.SpellSchoolFire | core.SpellSchoolShadow, - DefenseType: core.DefenseTypeMagic, - ProcMask: core.ProcMaskSpellDamage, - Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | WarlockFlagAffliction | WarlockFlagDestruction | WarlockFlagHaunt, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.27, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: time.Second * 2, - }, - }, - - Dot: core.DotConfig{ - Aura: core.Aura{ - Label: "Shadowflame" + warlock.Label, - }, - - NumberOfTicks: numTicks, - TickLength: tickLength, - BonusCoefficient: dotSpellCoeff, - - OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) { - dot.Snapshot(target, dotDamage, isRollover) - }, - OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - var result *core.SpellResult - if hasPandemicRune { - // We add the crit damage bonus and remove it after the call to not affect the initial damage portion of the spell - dot.Spell.CritDamageBonus += 1 - result = dot.CalcSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit) - dot.Spell.CritDamageBonus -= 1 - } else { - result = dot.CalcSnapshotDamage(sim, target, dot.OutcomeTick) - } - dot.Spell.DealPeriodicDamage(sim, result) - }, - }, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - BonusCoefficient: baseSpellCoeff, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - oldMultiplier := spell.DamageMultiplier - spell.DamageMultiplier *= 1 + warlock.improvedImmolateBonus() - result := spell.CalcDamage(sim, target, baseDamage, spell.OutcomeMagicHitAndCrit) - spell.DamageMultiplier = oldMultiplier - - if result.Landed() { - dot := spell.Dot(target) - - // Shadowflame and Immolate are exclusive - immoDot := warlock.getActiveImmolateSpell(target) - if immoDot != nil { - immoDot.Dot(target).Deactivate(sim) - } - - if hasInvocationRune && dot.IsActive() { - warlock.InvocationRefresh(sim, dot) - } - - dot.Apply(sim) - } - - spell.DealDamage(sim, result) - }, - }) -} diff --git a/sim/warlock/siphon_life.go b/sim/warlock/siphon_life.go index 58ba9ab6c..3bad95577 100644 --- a/sim/warlock/siphon_life.go +++ b/sim/warlock/siphon_life.go @@ -5,7 +5,6 @@ import ( "time" "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" ) const SiphonLifeRanks = 4 @@ -22,15 +21,12 @@ func (warlock *Warlock) getSiphonLifeBaseConfig(rank int) core.SpellConfig { baseDamage *= 1 + warlock.shadowMasteryBonus() - hasInvocationRune := warlock.HasRune(proto.WarlockRune_RuneBeltInvocation) - hasPandemicRune := warlock.HasRune(proto.WarlockRune_RuneHelmPandemic) - return core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolShadow, DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, - Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | core.SpellFlagBinary | WarlockFlagAffliction | WarlockFlagHaunt, + Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | core.SpellFlagBinary | WarlockFlagAffliction, RequiredLevel: level, Rank: rank, @@ -43,7 +39,7 @@ func (warlock *Warlock) getSiphonLifeBaseConfig(rank int) core.SpellConfig { }, }, - CritDamageBonus: core.TernaryFloat64(hasPandemicRune, 1, 0), + CritDamageBonus: 0, DamageMultiplierAdditive: 1, DamageMultiplier: 1, @@ -72,11 +68,7 @@ func (warlock *Warlock) getSiphonLifeBaseConfig(rank int) core.SpellConfig { dot.Spell.Flags |= core.SpellFlagIgnoreTargetModifiers var result *core.SpellResult - if hasPandemicRune { - result = dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit) - } else { - result = dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) - } + result = dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) // revert flag changes dot.Spell.Flags ^= core.SpellFlagIgnoreTargetModifiers @@ -90,10 +82,6 @@ func (warlock *Warlock) getSiphonLifeBaseConfig(rank int) core.SpellConfig { result := spell.CalcOutcome(sim, target, spell.OutcomeMagicHitNoHitCounter) if result.Landed() { dot := spell.Dot(target) - if hasInvocationRune && dot.IsActive() { - warlock.InvocationRefresh(sim, dot) - } - dot.Apply(sim) } }, diff --git a/sim/warlock/soul_fire.go b/sim/warlock/soul_fire.go index d66c3f579..97c553ecc 100644 --- a/sim/warlock/soul_fire.go +++ b/sim/warlock/soul_fire.go @@ -4,15 +4,12 @@ import ( "time" "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" ) const SoulFireRanks = 2 const SoulFireCastTime = time.Millisecond * 6000 func (warlock *Warlock) getSoulFireBaseConfig(rank int) core.SpellConfig { - hasDecimationRune := warlock.HasRune(proto.WarlockRune_RuneBootsDecimation) - spellId := [SoulFireRanks + 1]int32{0, 6353, 17924}[rank] baseDamage := [SoulFireRanks + 1][]float64{{0, 0}, {628, 789}, {715, 894}}[rank] manaCost := [SoulFireRanks + 1]float64{0, 305, 335}[rank] @@ -53,11 +50,9 @@ func (warlock *Warlock) getSoulFireBaseConfig(rank int) core.SpellConfig { }, } - if !hasDecimationRune { - config.Cast.CD = core.Cooldown{ - Timer: warlock.NewTimer(), - Duration: time.Minute, - } + config.Cast.CD = core.Cooldown{ + Timer: warlock.NewTimer(), + Duration: time.Minute, } return config diff --git a/sim/warlock/summon_demon.go b/sim/warlock/summon_demon.go index fa8b10720..7d8e32aed 100644 --- a/sim/warlock/summon_demon.go +++ b/sim/warlock/summon_demon.go @@ -22,25 +22,6 @@ func (warlock *Warlock) registerSummonDemon() { }, } - // Felguard - if warlock.Felguard != nil { - warlock.SummonDemonSpells = append(warlock.SummonDemonSpells, warlock.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 427733}, - SpellSchool: core.SpellSchoolShadow, - ProcMask: core.ProcMaskEmpty, - Flags: core.SpellFlagAPL, - - ManaCost: core.ManaCostOptions{ - FlatCost: warlock.BaseMana * 0.80 * (1 - .20*float64(warlock.Talents.MasterSummoner)), - }, - Cast: cast, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - warlock.changeActivePet(sim, warlock.Felguard, false) - }, - })) - } - // Felhunter warlock.SummonDemonSpells = append(warlock.SummonDemonSpells, warlock.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 691}, diff --git a/sim/warlock/talents.go b/sim/warlock/talents.go index 3a3ba14d8..44f01820f 100644 --- a/sim/warlock/talents.go +++ b/sim/warlock/talents.go @@ -156,22 +156,15 @@ func (warlock *Warlock) applyNightfall() { for _, spell := range warlock.ShadowBolt { spell.CastTimeMultiplier -= 1 } - for _, spell := range warlock.ShadowCleave { - spell.CD.Reset() - spell.DamageMultiplier *= 2 - } }, OnExpire: func(aura *core.Aura, sim *core.Simulation) { for _, spell := range warlock.ShadowBolt { spell.CastTimeMultiplier += 1 } - for _, spell := range warlock.ShadowCleave { - spell.DamageMultiplier /= 2 - } }, OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { // Check if the shadowbolt was instant cast and not a normal one - if (spell.SpellCode == SpellCode_WarlockShadowBolt && spell.CurCast.CastTime == 0) || spell.SpellCode == SpellCode_WarlockShadowCleave { + if spell.SpellCode == SpellCode_WarlockShadowBolt && spell.CurCast.CastTime == 0 { aura.Deactivate(sim) } }, @@ -183,12 +176,10 @@ func (warlock *Warlock) applyNightfall() { warlock.nightfallProcChance = 0.02 * float64(warlock.Talents.Nightfall) - hasSoulSiphonRune := warlock.HasRune(proto.WarlockRune_RuneCloakSoulSiphon) - core.MakePermanent(warlock.RegisterAura(core.Aura{ Label: "Nightfall Hidden Aura", OnPeriodicDamageDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if (spell.SpellCode == SpellCode_WarlockCorruption || spell.SpellCode == SpellCode_WarlockDrainLife || (hasSoulSiphonRune && spell.SpellCode == SpellCode_WarlockDrainSoul)) && sim.Proc(warlock.nightfallProcChance, "Nightfall") { + if (spell.SpellCode == SpellCode_WarlockCorruption || spell.SpellCode == SpellCode_WarlockDrainLife) && sim.Proc(warlock.nightfallProcChance, "Nightfall") { warlock.ShadowTranceAura.Activate(sim) } }, @@ -289,13 +280,11 @@ func (warlock *Warlock) applyMasterDemonologist() { warlock.disableMasterDemonologistOnSacrifice = true - hasMetaRune := warlock.HasRune(proto.WarlockRune_RuneHandsMetamorphosis) - points := float64(warlock.Talents.MasterDemonologist) bonusMultiplier := 1 + warlock.masterDemonologistBonus damageDealtMultiplier := 1 + (0.02 * points * bonusMultiplier) damageTakenMultiplier := 1 - (0.02 * points * bonusMultiplier) - threatMultiplier := 1 + (core.TernaryFloat64(hasMetaRune, 0.04*points, -0.04*points) * bonusMultiplier) + threatMultiplier := 1 + -0.04*points*bonusMultiplier bonusResistance := 2 * points * bonusMultiplier masterDemonologistConfig := core.Aura{ @@ -308,11 +297,6 @@ func (warlock *Warlock) applyMasterDemonologist() { } switch warlock.ActivePet { - case warlock.Felguard: - aura.Unit.PseudoStats.DamageDealtMultiplier *= damageDealtMultiplier - aura.Unit.PseudoStats.DamageTakenMultiplier *= damageTakenMultiplier - aura.Unit.PseudoStats.ThreatMultiplier *= threatMultiplier - aura.Unit.AddResistancesDynamic(sim, bonusResistance) case warlock.Felhunter: aura.Unit.AddResistancesDynamic(sim, bonusResistance) case warlock.Imp: @@ -329,11 +313,6 @@ func (warlock *Warlock) applyMasterDemonologist() { } switch warlock.ActivePet { - case warlock.Felguard: - aura.Unit.PseudoStats.DamageDealtMultiplier /= damageDealtMultiplier - aura.Unit.PseudoStats.DamageTakenMultiplier /= damageTakenMultiplier - aura.Unit.PseudoStats.ThreatMultiplier /= threatMultiplier - aura.Unit.AddResistancesDynamic(sim, -bonusResistance) case warlock.Felhunter: aura.Unit.AddResistancesDynamic(sim, -bonusResistance) case warlock.Imp: @@ -516,11 +495,6 @@ func (warlock *Warlock) applyDemonicSacrifice() { ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { switch warlock.ActivePet { - case warlock.Felguard: - felhunterAura.Activate(sim) - impAura.Activate(sim) - succubusAura.Activate(sim) - voidwalkerAura.Activate(sim) case warlock.Felhunter: felhunterAura.Activate(sim) case warlock.Imp: @@ -550,7 +524,7 @@ func (warlock *Warlock) applyImprovedShadowBolt() { return core.ImprovedShadowBoltAura(unit, warlock.Talents.ImprovedShadowBolt, stackCount) }) - affectedSpellCodes := []int32{SpellCode_WarlockShadowBolt, SpellCode_WarlockShadowCleave, SpellCode_WarlockShadowflame} + affectedSpellCodes := []int32{SpellCode_WarlockShadowBolt} core.MakePermanent(warlock.RegisterAura(core.Aura{ Label: "ISB Trigger", OnInit: func(aura *core.Aura, sim *core.Simulation) { @@ -588,7 +562,7 @@ func (warlock *Warlock) applyBane() { points := time.Duration(warlock.Talents.Bane) warlock.OnSpellRegistered(func(spell *core.Spell) { - if spell.SpellCode == SpellCode_WarlockShadowBolt || spell.SpellCode == SpellCode_WarlockImmolate || spell.SpellCode == SpellCode_WarlockShadowflame { + if spell.SpellCode == SpellCode_WarlockShadowBolt || spell.SpellCode == SpellCode_WarlockImmolate { spell.DefaultCast.CastTime -= time.Millisecond * 100 * points } else if spell.SpellCode == SpellCode_WarlockSoulFire { spell.DefaultCast.CastTime -= time.Millisecond * 400 * points diff --git a/sim/warlock/tank/TestAffliction.results b/sim/warlock/tank/TestAffliction.results deleted file mode 100644 index 6402954b9..000000000 --- a/sim/warlock/tank/TestAffliction.results +++ /dev/null @@ -1,162 +0,0 @@ -character_stats_results: { - key: "TestAffliction-Phase4-Lvl60-CharacterStats-Default" - value: { - final_stats: 192.05 - final_stats: 190.9 - final_stats: 309.465 - final_stats: 194.35 - final_stats: 231.15 - final_stats: 325.575 - final_stats: 0 - final_stats: 40 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 40 - final_stats: 41.25 - final_stats: 0 - final_stats: 25.90678 - final_stats: 0 - final_stats: 0 - final_stats: 812.05 - final_stats: 0 - final_stats: 24.545 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 4008.25 - final_stats: 0 - final_stats: 0 - final_stats: 765.8 - final_stats: 540 - final_stats: 0 - final_stats: 5 - final_stats: 0 - final_stats: 11.545 - final_stats: 5 - final_stats: 0 - final_stats: 4628.65 - final_stats: 27 - final_stats: 60 - final_stats: 60 - final_stats: 60 - final_stats: 60 - final_stats: 384 - final_stats: 0 - final_stats: 35 - final_stats: 0 - } -} -stat_weights_results: { - key: "TestAffliction-Phase4-Lvl60-StatWeights-Default" - value: { - weights: 0 - weights: 0 - weights: 0 - weights: -0.24219 - weights: 0 - weights: 0.07296 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 3.66598 - weights: 1.00627 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Average-Default" - value: { - dps: 395.84375 - tps: 281.87701 - hps: 143.33867 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-blank-Affliction Warlock-p4_destro_aff_tank-FullBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 395.57517 - tps: 703.08928 - hps: 142.8239 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-blank-Affliction Warlock-p4_destro_aff_tank-FullBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 395.57517 - tps: 283.01063 - hps: 142.8239 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-blank-Affliction Warlock-p4_destro_aff_tank-FullBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 452.30043 - tps: 318.40647 - hps: 145.6732 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-blank-Affliction Warlock-p4_destro_aff_tank-NoBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 223.03096 - tps: 698.11297 - hps: 82.49614 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-blank-Affliction Warlock-p4_destro_aff_tank-NoBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 223.03096 - tps: 179.23118 - hps: 82.49614 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-Settings-Orc-blank-Affliction Warlock-p4_destro_aff_tank-NoBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 245.33588 - tps: 198.82781 - hps: 87.92117 - } -} -dps_results: { - key: "TestAffliction-Phase4-Lvl60-SwitchInFrontOfTarget-Default" - value: { - dps: 390.74659 - tps: 276.99213 - hps: 143.19304 - } -} diff --git a/sim/warlock/tank/TestDemonology.results b/sim/warlock/tank/TestDemonology.results deleted file mode 100644 index 726842093..000000000 --- a/sim/warlock/tank/TestDemonology.results +++ /dev/null @@ -1,162 +0,0 @@ -character_stats_results: { - key: "TestDemonology-Phase4-Lvl60-CharacterStats-Default" - value: { - final_stats: 192.05 - final_stats: 190.9 - final_stats: 355.88475 - final_stats: 194.35 - final_stats: 219.5925 - final_stats: 319.79625 - final_stats: 0 - final_stats: 61 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 40 - final_stats: 41.25 - final_stats: 0 - final_stats: 25.90678 - final_stats: 0 - final_stats: 0 - final_stats: 812.05 - final_stats: 0 - final_stats: 24.545 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 4008.25 - final_stats: 0 - final_stats: 0 - final_stats: 765.8 - final_stats: 540 - final_stats: 0 - final_stats: 5 - final_stats: 0 - final_stats: 11.545 - final_stats: 5 - final_stats: 0 - final_stats: 5092.8475 - final_stats: 27 - final_stats: 60 - final_stats: 60 - final_stats: 60 - final_stats: 60 - final_stats: 384 - final_stats: 0 - final_stats: 35 - final_stats: 0 - } -} -stat_weights_results: { - key: "TestDemonology-Phase4-Lvl60-StatWeights-Default" - value: { - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0.02972 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0.51017 - weights: 0.29947 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - } -} -dps_results: { - key: "TestDemonology-Phase4-Lvl60-Average-Default" - value: { - dps: 47.54011 - tps: 54.8855 - hps: 2.70296 - } -} -dps_results: { - key: "TestDemonology-Phase4-Lvl60-Settings-Orc-blank-Demonology Warlock-p4_demo_tank-FullBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 35.20133 - tps: 97.83623 - hps: 2.65522 - } -} -dps_results: { - key: "TestDemonology-Phase4-Lvl60-Settings-Orc-blank-Demonology Warlock-p4_demo_tank-FullBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 35.20133 - tps: 42.64598 - hps: 2.65522 - } -} -dps_results: { - key: "TestDemonology-Phase4-Lvl60-Settings-Orc-blank-Demonology Warlock-p4_demo_tank-FullBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 57.07716 - tps: 79.38914 - hps: 13.78919 - } -} -dps_results: { - key: "TestDemonology-Phase4-Lvl60-Settings-Orc-blank-Demonology Warlock-p4_demo_tank-NoBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 20.24215 - tps: 78.72015 - hps: 1.57632 - } -} -dps_results: { - key: "TestDemonology-Phase4-Lvl60-Settings-Orc-blank-Demonology Warlock-p4_demo_tank-NoBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 20.24215 - tps: 25.67848 - hps: 1.57632 - } -} -dps_results: { - key: "TestDemonology-Phase4-Lvl60-Settings-Orc-blank-Demonology Warlock-p4_demo_tank-NoBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 33.98654 - tps: 48.23407 - hps: 8.38795 - } -} -dps_results: { - key: "TestDemonology-Phase4-Lvl60-SwitchInFrontOfTarget-Default" - value: { - dps: 41.88046 - tps: 49.34478 - hps: 2.65522 - } -} diff --git a/sim/warlock/tank/TestDestruction.results b/sim/warlock/tank/TestDestruction.results deleted file mode 100644 index e8ddeebe6..000000000 --- a/sim/warlock/tank/TestDestruction.results +++ /dev/null @@ -1,162 +0,0 @@ -character_stats_results: { - key: "TestDestruction-Phase4-Lvl60-CharacterStats-Default" - value: { - final_stats: 192.05 - final_stats: 190.9 - final_stats: 309.465 - final_stats: 194.35 - final_stats: 231.15 - final_stats: 325.575 - final_stats: 0 - final_stats: 40 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 40 - final_stats: 41.25 - final_stats: 0 - final_stats: 25.90678 - final_stats: 0 - final_stats: 0 - final_stats: 812.05 - final_stats: 0 - final_stats: 24.545 - final_stats: 0 - final_stats: 0 - final_stats: 0 - final_stats: 4008.25 - final_stats: 0 - final_stats: 0 - final_stats: 765.8 - final_stats: 540 - final_stats: 0 - final_stats: 5 - final_stats: 0 - final_stats: 11.545 - final_stats: 5 - final_stats: 0 - final_stats: 4628.65 - final_stats: 27 - final_stats: 60 - final_stats: 60 - final_stats: 60 - final_stats: 60 - final_stats: 384 - final_stats: 0 - final_stats: 35 - final_stats: 0 - } -} -stat_weights_results: { - key: "TestDestruction-Phase4-Lvl60-StatWeights-Default" - value: { - weights: 0 - weights: 0 - weights: 0 - weights: 0.91009 - weights: 0 - weights: 0.11006 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 3.92216 - weights: 1.09794 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - weights: 0 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Average-Default" - value: { - dps: 389.2209 - tps: 277.26564 - hps: 136.1828 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-blank-Destruction Warlock-p4_destro_aff_tank-FullBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 388.3852 - tps: 702.12766 - hps: 133.92194 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-blank-Destruction Warlock-p4_destro_aff_tank-FullBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 388.3852 - tps: 276.76072 - hps: 133.92194 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-blank-Destruction Warlock-p4_destro_aff_tank-FullBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 437.42061 - tps: 307.31494 - hps: 140.78957 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-blank-Destruction Warlock-p4_destro_aff_tank-NoBuffs-P4-Consumes-LongMultiTarget" - value: { - dps: 217.59792 - tps: 687.37145 - hps: 79.34399 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-blank-Destruction Warlock-p4_destro_aff_tank-NoBuffs-P4-Consumes-LongSingleTarget" - value: { - dps: 217.59792 - tps: 175.07065 - hps: 79.34399 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-Settings-Orc-blank-Destruction Warlock-p4_destro_aff_tank-NoBuffs-P4-Consumes-ShortSingleTarget" - value: { - dps: 238.92422 - tps: 192.95731 - hps: 84.6674 - } -} -dps_results: { - key: "TestDestruction-Phase4-Lvl60-SwitchInFrontOfTarget-Default" - value: { - dps: 387.76787 - tps: 277.39069 - hps: 136.72322 - } -} diff --git a/sim/warlock/tank/tank_warlock.go b/sim/warlock/tank/tank_warlock.go deleted file mode 100644 index cf8870368..000000000 --- a/sim/warlock/tank/tank_warlock.go +++ /dev/null @@ -1,61 +0,0 @@ -package tank - -import ( - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" - "github.com/wowsims/classic/sim/warlock" -) - -func RegisterTankWarlock() { - core.RegisterAgentFactory( - proto.Player_TankWarlock{}, - proto.Spec_SpecTankWarlock, - func(character *core.Character, options *proto.Player) core.Agent { - return NewTankWarlock(character, options) - }, - func(player *proto.Player, spec interface{}) { - playerSpec, ok := spec.(*proto.Player_TankWarlock) - if !ok { - panic("Invalid spec value for Warrior!") - } - player.Spec = playerSpec - }, - ) -} - -type TankWarlock struct { - *warlock.Warlock -} - -func NewTankWarlock(character *core.Character, options *proto.Player) *TankWarlock { - warlock := &TankWarlock{ - Warlock: warlock.NewWarlock(character, options, options.GetTankWarlock().Options), - } - - warlock.PseudoStats.CanParry = false - warlock.PseudoStats.CanBlock = false - - warlock.EnableAutoAttacks(warlock, core.AutoAttackOptions{ - MainHand: warlock.WeaponFromMainHand(), - OffHand: warlock.WeaponFromOffHand(), - AutoSwingMelee: true, - }) - - return warlock -} - -func (warlock *TankWarlock) OnGCDReady(sim *core.Simulation) { - return -} - -func (warlock *TankWarlock) GetWarlock() *warlock.Warlock { - return warlock.Warlock -} - -func (warlock *TankWarlock) Initialize() { - warlock.Warlock.Initialize() -} - -func (warlock *TankWarlock) Reset(sim *core.Simulation) { - warlock.Warlock.Reset(sim) -} diff --git a/sim/warlock/tank/tank_warlock_test.go b/sim/warlock/tank/tank_warlock_test.go deleted file mode 100644 index e3fff1248..000000000 --- a/sim/warlock/tank/tank_warlock_test.go +++ /dev/null @@ -1,155 +0,0 @@ -package tank - -import ( - "testing" - - _ "github.com/wowsims/classic/sim/common" - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" -) - -func init() { - RegisterTankWarlock() -} - -func TestAffliction(t *testing.T) { - core.RunTestSuite(t, t.Name(), core.FullCharacterTestSuiteGenerator([]core.CharacterSuiteConfig{ - { - Class: proto.Class_ClassWarlock, - Phase: 4, - Level: 60, - Race: proto.Race_RaceOrc, - - Talents: Phase4AffTalents, - GearSet: core.GetGearSet("../../../ui/tank_warlock/gear_sets", "blank"), - Rotation: core.GetAplRotation("../../../ui/tank_warlock/apls", "p4_destro_aff_tank"), - Buffs: core.FullBuffs, - Consumes: Phase4Consumes, - SpecOptions: core.SpecOptionsCombo{Label: "Affliction Warlock", SpecOptions: DefaultAfflictionWarlock}, - - ItemFilter: ItemFilters, - EPReferenceStat: proto.Stat_StatSpellPower, - StatsToWeigh: Stats, - }, - })) -} - -func TestDemonology(t *testing.T) { - core.RunTestSuite(t, t.Name(), core.FullCharacterTestSuiteGenerator([]core.CharacterSuiteConfig{ - { - Class: proto.Class_ClassWarlock, - Phase: 4, - Level: 60, - Race: proto.Race_RaceOrc, - - Talents: Phase4DemoTalents, - GearSet: core.GetGearSet("../../../ui/tank_warlock/gear_sets", "blank"), - Rotation: core.GetAplRotation("../../../ui/tank_warlock/apls", "p4_demo_tank"), - Buffs: core.FullBuffs, - Consumes: Phase4Consumes, - SpecOptions: core.SpecOptionsCombo{Label: "Demonology Warlock", SpecOptions: DefaultDemonologyWarlock}, - - ItemFilter: ItemFilters, - EPReferenceStat: proto.Stat_StatSpellPower, - StatsToWeigh: Stats, - }, - })) -} - -func TestDestruction(t *testing.T) { - core.RunTestSuite(t, t.Name(), core.FullCharacterTestSuiteGenerator([]core.CharacterSuiteConfig{ - { - Class: proto.Class_ClassWarlock, - Phase: 4, - Level: 60, - Race: proto.Race_RaceOrc, - - Talents: Phase4DestroTalents, - GearSet: core.GetGearSet("../../../ui/tank_warlock/gear_sets", "blank"), - Rotation: core.GetAplRotation("../../../ui/tank_warlock/apls", "p4_destro_aff_tank"), - Buffs: core.FullBuffs, - Consumes: Phase4Consumes, - SpecOptions: core.SpecOptionsCombo{Label: "Destruction Warlock", SpecOptions: DefaultDestroWarlock}, - - ItemFilter: ItemFilters, - EPReferenceStat: proto.Stat_StatSpellPower, - StatsToWeigh: Stats, - }, - })) -} - -var Phase1AfflictionTalents = "05002-005" -var Phase1DestructionTalents = "-03-0550201" - -var Phase2DemonologyTalents = "-2050033112501251" -var Phase2DestructionTalents = "-035-05500050025001" - -var Phase3DestructionTalents = "05-03-505020500050515" - -var Phase4AffTalents = "5500253011201002-03-50502051002001" -var Phase4DemoTalents = "-205004015250105-50500050005001" -var Phase4DestroTalents = "45002400102-03-505020510050115" - -var DefaultDestroWarlock = &proto.Player_TankWarlock{ - TankWarlock: &proto.TankWarlock{ - Options: &proto.WarlockOptions{ - Armor: proto.WarlockOptions_FelArmor, - Summon: proto.WarlockOptions_Imp, - WeaponImbue: proto.WarlockOptions_NoWeaponImbue, - }, - }, -} - -var DefaultAfflictionWarlock = &proto.Player_TankWarlock{ - TankWarlock: &proto.TankWarlock{ - Options: &proto.WarlockOptions{ - Armor: proto.WarlockOptions_FelArmor, - Summon: proto.WarlockOptions_Imp, - WeaponImbue: proto.WarlockOptions_NoWeaponImbue, - }, - }, -} - -var DefaultDemonologyWarlock = &proto.Player_TankWarlock{ - TankWarlock: &proto.TankWarlock{ - Options: &proto.WarlockOptions{ - Armor: proto.WarlockOptions_FelArmor, - Summon: proto.WarlockOptions_Felguard, - WeaponImbue: proto.WarlockOptions_Firestone, - }, - }, -} - -var Phase4Consumes = core.ConsumesCombo{ - Label: "P4-Consumes", - Consumes: &proto.Consumes{ - DefaultPotion: proto.Potions_MajorManaPotion, - Flask: proto.Flask_FlaskOfSupremePower, - FirePowerBuff: proto.FirePowerBuff_ElixirOfGreaterFirepower, - ShadowPowerBuff: proto.ShadowPowerBuff_ElixirOfShadowPower, - Food: proto.Food_FoodTenderWolfSteak, - MainHandImbue: proto.WeaponImbue_WizardOil, - SpellPowerBuff: proto.SpellPowerBuff_GreaterArcaneElixir, - }, -} - -var ItemFilters = core.ItemFilter{ - WeaponTypes: []proto.WeaponType{ - proto.WeaponType_WeaponTypeSword, - proto.WeaponType_WeaponTypeDagger, - }, - HandTypes: []proto.HandType{ - proto.HandType_HandTypeOffHand, - }, - ArmorType: proto.ArmorType_ArmorTypeCloth, - RangedWeaponTypes: []proto.RangedWeaponType{ - proto.RangedWeaponType_RangedWeaponTypeWand, - }, -} - -var Stats = []proto.Stat{ - proto.Stat_StatIntellect, - proto.Stat_StatSpellPower, - proto.Stat_StatSpellHit, - proto.Stat_StatSpellCrit, -} diff --git a/sim/warlock/unstable_affliction.go b/sim/warlock/unstable_affliction.go deleted file mode 100644 index 186d9c71c..000000000 --- a/sim/warlock/unstable_affliction.go +++ /dev/null @@ -1,92 +0,0 @@ -package warlock - -import ( - "time" - - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/proto" -) - -func (warlock *Warlock) registerUnstableAfflictionSpell() { - if !warlock.HasRune(proto.WarlockRune_RuneBracerUnstableAffliction) { - return - } - - hasInvocationRune := warlock.HasRune(proto.WarlockRune_RuneBeltInvocation) - hasPandemicRune := warlock.HasRune(proto.WarlockRune_RuneHelmPandemic) - - baseDamage := warlock.baseRuneAbilityDamage() * 1.1 - - warlock.UnstableAffliction = warlock.GetOrRegisterSpell(core.SpellConfig{ - SpellCode: SpellCode_WarlockUnstableAffliction, - ActionID: core.ActionID{SpellID: int32(proto.WarlockRune_RuneBracerUnstableAffliction)}, - SpellSchool: core.SpellSchoolShadow, - ProcMask: core.ProcMaskSpellDamage, - DefenseType: core.DefenseTypeMagic, - Flags: core.SpellFlagAPL | WarlockFlagHaunt | core.SpellFlagBinary | core.SpellFlagResetAttackSwing | core.SpellFlagPureDot | WarlockFlagAffliction, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.15, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: time.Millisecond * 1500, - }, - }, - - CritDamageBonus: core.TernaryFloat64(hasPandemicRune, 1, 0), - - DamageMultiplier: 1, - ThreatMultiplier: 1, - - Dot: core.DotConfig{ - Aura: core.Aura{ - Label: "UnstableAffliction-" + warlock.Label, - }, - - NumberOfTicks: 6, - TickLength: time.Second * 3, - BonusCoefficient: 0.2, - - OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) { - dot.Snapshot(target, baseDamage, isRollover) - }, - OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - if hasPandemicRune { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit) - } else { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) - } - }, - }, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - result := spell.CalcOutcome(sim, target, spell.OutcomeMagicHitNoHitCounter) - if result.Landed() { - dot := spell.Dot(target) - - // UA is mutually exclusive with Immolate - immoDot := warlock.getActiveImmolateSpell(target) - if immoDot != nil { - immoDot.Dot(target).Deactivate(sim) - } - - if hasInvocationRune && dot.IsActive() { - warlock.InvocationRefresh(sim, dot) - } - - dot.Apply(sim) - } - spell.DealOutcome(sim, result) - }, - ExpectedTickDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, useSnapshot bool) *core.SpellResult { - if useSnapshot { - dot := spell.Dot(target) - return dot.CalcSnapshotDamage(sim, target, dot.Spell.OutcomeExpectedMagicAlwaysHit) - } else { - return spell.CalcPeriodicDamage(sim, target, baseDamage, spell.OutcomeExpectedMagicAlwaysHit) - } - }, - }) -} diff --git a/sim/warlock/warlock.go b/sim/warlock/warlock.go index 23eac536c..376b40622 100644 --- a/sim/warlock/warlock.go +++ b/sim/warlock/warlock.go @@ -13,7 +13,6 @@ const ( WarlockFlagAffliction = core.SpellFlagAgentReserved1 WarlockFlagDemonology = core.SpellFlagAgentReserved2 WarlockFlagDestruction = core.SpellFlagAgentReserved3 - WarlockFlagHaunt = core.SpellFlagAgentReserved4 SpellFlagWarlock = WarlockFlagAffliction | WarlockFlagDemonology | WarlockFlagDestruction ) @@ -29,17 +28,12 @@ const ( SpellCode_WarlockDemonicSacrifice SpellCode_WarlockDrainLife SpellCode_WarlockDrainSoul - SpellCode_WarlockHaunt SpellCode_WarlockImmolate - SpellCode_WarlockIncinerate SpellCode_WarlockLifeTap SpellCode_WarlockSearingPain - SpellCode_WarlockShadowflame - SpellCode_WarlockShadowCleave SpellCode_WarlockShadowBolt SpellCode_WarlockShadowburn SpellCode_WarlockSoulFire - SpellCode_WarlockUnstableAffliction ) type Warlock struct { @@ -50,7 +44,6 @@ type Warlock struct { BasePets []*WarlockPet ActivePet *WarlockPet Felhunter *WarlockPet - Felguard *WarlockPet Imp *WarlockPet Succubus *WarlockPet Voidwalker *WarlockPet @@ -58,27 +51,20 @@ type Warlock struct { // Doomguard *DoomguardPet // Infernal *InfernalPet - ChaosBolt *core.Spell - Conflagrate []*core.Spell - Corruption []*core.Spell - DarkPact *core.Spell - DrainSoul []*core.Spell - Haunt *core.Spell - Immolate []*core.Spell - Incinerate *core.Spell - LifeTap []*core.Spell - SearingPain []*core.Spell - ShadowBolt []*core.Spell - ShadowCleave []*core.Spell - Shadowburn []*core.Spell - SoulFire []*core.Spell - DemonicGrace *core.Spell - DrainLife []*core.Spell - RainOfFire []*core.Spell - SiphonLife []*core.Spell - DeathCoil []*core.Spell - Shadowflame *core.Spell - UnstableAffliction *core.Spell + Conflagrate []*core.Spell + Corruption []*core.Spell + DarkPact *core.Spell + DrainSoul []*core.Spell + Immolate []*core.Spell + LifeTap []*core.Spell + SearingPain []*core.Spell + ShadowBolt []*core.Spell + Shadowburn []*core.Spell + SoulFire []*core.Spell + DrainLife []*core.Spell + RainOfFire []*core.Spell + SiphonLife []*core.Spell + DeathCoil []*core.Spell ActiveCurseAura core.AuraArray CurseOfElements *core.Spell @@ -100,31 +86,17 @@ type Warlock struct { DebuffSpells []*core.Spell SummonDemonSpells []*core.Spell - DemonicKnowledgeAura *core.Aura - HauntDebuffAuras core.AuraArray ImmolationAura *core.Spell - IncinerateAura *core.Aura - Metamorphosis *core.Spell - MetamorphosisAura *core.Aura ShadowTranceAura *core.Aura - PyroclasmAura *core.Aura - DemonicGraceAura *core.Aura AmplifyCurseAura *core.Aura - BackdraftAura *core.Aura ImprovedShadowBoltAuras core.AuraArray - MarkOfChaosAuras core.AuraArray SoulLinkAura *core.Aura - DecimationAura *core.Aura MasterDemonologistAura *core.Aura - zilaGularAura *core.Aura - shadowSparkAura *core.Aura - defendersResolveAura *core.Aura // The sum total of demonic pact spell power * seconds. DPSPAggregate float64 // Extra state and logic variables - demonicKnowledgeSp float64 masterDemonologistBonus float64 // Bonus multiplier applied to the Master Demonologist talent disableMasterDemonologistOnSacrifice bool // Whether to disable the Master Demonologist buff after Sacrificing a pet. Used by TAQ 4pc nightfallProcChance float64 @@ -217,8 +189,6 @@ func NewWarlock(character *core.Character, options *proto.Player, warlockOptions switch warlock.Options.Armor { case proto.WarlockOptions_DemonArmor: warlock.applyDemonArmor() - case proto.WarlockOptions_FelArmor: - warlock.applyFelArmor() } warlock.registerPets() @@ -229,14 +199,6 @@ func NewWarlock(character *core.Character, options *proto.Player, warlockOptions return warlock } -func (warlock *Warlock) HasRune(rune proto.WarlockRune) bool { - return false // warlock.HasRuneById(int32(rune)) -} - -func (warlock *Warlock) baseRuneAbilityDamage() float64 { - return 6.568597 + 0.672028*float64(warlock.Level) + 0.031721*float64(warlock.Level*warlock.Level) -} - func (warlock *Warlock) OnGCDReady(_ *core.Simulation) { } diff --git a/tools/database/gen_db/main.go b/tools/database/gen_db/main.go index 748756101..ef0816c73 100644 --- a/tools/database/gen_db/main.go +++ b/tools/database/gen_db/main.go @@ -488,11 +488,6 @@ func GetAllRotationSpellIds() map[string][]int32 { Level: 60, Equipment: &proto.EquipmentSpec{}, }, &proto.Player_Warlock{Warlock: &proto.Warlock{Options: &proto.WarlockOptions{}}}), nil, nil, nil)}, - {Name: "tank warlock", Raid: core.SinglePlayerRaidProto(core.WithSpec(&proto.Player{ - Class: proto.Class_ClassWarlock, - Level: 60, - Equipment: &proto.EquipmentSpec{}, - }, &proto.Player_TankWarlock{TankWarlock: &proto.TankWarlock{Options: &proto.WarlockOptions{}}}), nil, nil, nil)}, } ret_db := make(map[string][]int32, 0) diff --git a/ui/core/components/individual_sim_ui/settings_tab.ts b/ui/core/components/individual_sim_ui/settings_tab.ts index 328fdacaa..82db9c62a 100644 --- a/ui/core/components/individual_sim_ui/settings_tab.ts +++ b/ui/core/components/individual_sim_ui/settings_tab.ts @@ -227,9 +227,8 @@ export class SettingsTab extends SimTab { TypedEvent.onAny([this.simUI.player.talentsChangeEmitter, this.simUI.player.getRaid()!.debuffsChangeEmitter]).on(() => { const isWlAndIsb = (this.simUI.player as Player)?.getTalents().improvedShadowBolt > 0; - const isTankWlAndIsb = (this.simUI.player as Player)?.getTalents().improvedShadowBolt > 0; const externalIsb = this.simUI.player.getRaid()?.getDebuffs()?.improvedShadowBolt == true; - if (externalIsb || isWlAndIsb || isTankWlAndIsb) { + if (externalIsb || isWlAndIsb) { contentBlock.rootElem.classList.remove('hide'); } else { contentBlock.rootElem.classList.add('hide'); diff --git a/ui/core/components/inputs/warlock_inputs.ts b/ui/core/components/inputs/warlock_inputs.ts index dd2e7d5a8..ecdb41eeb 100644 --- a/ui/core/components/inputs/warlock_inputs.ts +++ b/ui/core/components/inputs/warlock_inputs.ts @@ -5,7 +5,6 @@ import { WarlockOptions_MaxFireboltRank as MaxFireboltRank, WarlockOptions_Summon as Summon, WarlockOptions_WeaponImbue as WeaponImbue, - WarlockRune, } from '../../proto/warlock.js'; import { ActionId } from '../../proto_utils/action_id.js'; import { WarlockSpecs } from '../../proto_utils/utils.js'; @@ -28,7 +27,7 @@ export const ArmorInput = () => }, { actionId: () => ActionId.fromSpellId(403619), - value: Armor.FelArmor, + value: Armor.DemonArmor, }, ], }); diff --git a/ui/core/components/sim_title_dropdown.tsx b/ui/core/components/sim_title_dropdown.tsx index 4029ae56b..5212a298d 100644 --- a/ui/core/components/sim_title_dropdown.tsx +++ b/ui/core/components/sim_title_dropdown.tsx @@ -59,7 +59,6 @@ export class SimTitleDropdown extends Component { [Spec.SpecHealingPriest]: 'Healing', [Spec.SpecShadowPriest]: 'Shadow', [Spec.SpecWarlock]: 'DPS', - [Spec.SpecTankWarlock]: 'Tank', [Spec.SpecWarrior]: 'DPS', [Spec.SpecTankWarrior]: 'Tank', }; diff --git a/ui/core/launched_sims.ts b/ui/core/launched_sims.ts index e2ec4479d..1a4c9ce27 100644 --- a/ui/core/launched_sims.ts +++ b/ui/core/launched_sims.ts @@ -96,10 +96,6 @@ export const simLaunchStatuses: Record = { phase: Phase.Phase5, status: LaunchStatus.Alpha, }, - [Spec.SpecTankWarlock]: { - phase: Phase.Phase4, - status: LaunchStatus.Alpha, - }, [Spec.SpecWarrior]: { phase: Phase.Phase5, status: LaunchStatus.Alpha, diff --git a/ui/core/proto_utils/utils.ts b/ui/core/proto_utils/utils.ts index e02435ef2..32303255d 100644 --- a/ui/core/proto_utils/utils.ts +++ b/ui/core/proto_utils/utils.ts @@ -91,7 +91,7 @@ export type PaladinSpecs = Spec.SpecHolyPaladin | Spec.SpecRetributionPaladin | export type PriestSpecs = Spec.SpecHealingPriest | Spec.SpecShadowPriest; export type RogueSpecs = Spec.SpecRogue | Spec.SpecTankRogue; export type ShamanSpecs = Spec.SpecElementalShaman | Spec.SpecEnhancementShaman | Spec.SpecRestorationShaman | Spec.SpecWardenShaman; -export type WarlockSpecs = Spec.SpecWarlock | Spec.SpecTankWarlock; +export type WarlockSpecs = Spec.SpecWarlock; export type WarriorSpecs = Spec.SpecWarrior | Spec.SpecTankWarrior; export type ClassSpecs = T extends Class.ClassDruid @@ -137,7 +137,6 @@ export const naturalSpecOrder: Array = [ Spec.SpecRestorationShaman, Spec.SpecWardenShaman, Spec.SpecWarlock, - Spec.SpecTankWarlock, Spec.SpecWarrior, Spec.SpecTankWarrior, ]; @@ -173,7 +172,6 @@ export const specNames: Record = { [Spec.SpecHealingPriest]: 'Priest', [Spec.SpecShadowPriest]: 'Shadow Priest', [Spec.SpecWarlock]: 'DPS Warlock', - [Spec.SpecTankWarlock]: 'Tank Warlock', [Spec.SpecWarrior]: 'DPS Warrior', [Spec.SpecTankWarrior]: 'Tank Warrior', }; @@ -257,7 +255,6 @@ export const titleIcons: Record = { [Spec.SpecHealingPriest]: 'https://wow.zamimg.com/images/wow/icons/large/spell_holy_guardianspirit.jpg', [Spec.SpecShadowPriest]: 'https://wow.zamimg.com/images/wow/icons/large/class_priest.jpg', [Spec.SpecWarlock]: 'https://wow.zamimg.com/images/wow/icons/large/class_warlock.jpg', - [Spec.SpecTankWarlock]: 'https://wow.zamimg.com/images/wow/icons/large/spell_shadow_demonform.jpg', [Spec.SpecWarrior]: 'https://wow.zamimg.com/images/wow/icons/large/class_warrior.jpg', [Spec.SpecTankWarrior]: 'https://wow.zamimg.com/images/wow/icons/large/ability_warrior_defensivestance.jpg', }; @@ -385,8 +382,6 @@ export type SpecRotation = T extends Spec.SpecBalanceDruid ? ShadowPriestRotation : T extends Spec.SpecWarlock ? WarlockRotation - : T extends Spec.SpecTankWarlock - ? WarlockRotation : T extends Spec.SpecWarrior ? WarriorRotation : T extends Spec.SpecTankWarrior @@ -439,8 +434,6 @@ export type SpecTalents = T extends Spec.SpecBalanceDruid ? PriestTalents : T extends Spec.SpecWarlock ? WarlockTalents - : T extends Spec.SpecTankWarlock - ? WarlockTalents : T extends Spec.SpecWarrior ? WarriorTalents : T extends Spec.SpecTankWarrior @@ -502,8 +495,6 @@ export type SpecOptions = T extends Spec.SpecBalanceDruid ? ShadowPriestOptions : T extends Spec.SpecWarlock ? WarlockOptions - : T extends Spec.SpecTankWarlock - ? WarlockOptions : T extends Spec.SpecWarrior ? WarriorOptions : T extends Spec.SpecTankWarrior @@ -568,8 +559,6 @@ export type SpecProto = T extends Spec.SpecBalanceDruid ? ShadowPriest : T extends Spec.SpecWarlock ? Warlock - : T extends Spec.SpecTankWarlock - ? Warlock : T extends Spec.SpecWarrior ? Warrior : T extends Spec.SpecTankWarrior @@ -984,27 +973,6 @@ export const specTypeFunctions: Record> = { optionsFromJson: obj => WarlockOptions.fromJson(obj), optionsFromPlayer: player => (player.spec.oneofKind == 'warlock' ? player.spec.warlock.options || WarlockOptions.create() : WarlockOptions.create()), }, - [Spec.SpecTankWarlock]: { - rotationCreate: () => WarlockRotation.create(), - rotationEquals: (a, b) => WarlockRotation.equals(a as WarlockRotation, b as WarlockRotation), - rotationCopy: a => WarlockRotation.clone(a as WarlockRotation), - rotationToJson: a => WarlockRotation.toJson(a as WarlockRotation), - rotationFromJson: obj => WarlockRotation.fromJson(obj), - - talentsCreate: () => WarlockTalents.create(), - talentsEquals: (a, b) => WarlockTalents.equals(a as WarlockTalents, b as WarlockTalents), - talentsCopy: a => WarlockTalents.clone(a as WarlockTalents), - talentsToJson: a => WarlockTalents.toJson(a as WarlockTalents), - talentsFromJson: obj => WarlockTalents.fromJson(obj), - - optionsCreate: () => WarlockOptions.create(), - optionsEquals: (a, b) => WarlockOptions.equals(a as WarlockOptions, b as WarlockOptions), - optionsCopy: a => WarlockOptions.clone(a as WarlockOptions), - optionsToJson: a => WarlockOptions.toJson(a as WarlockOptions), - optionsFromJson: obj => WarlockOptions.fromJson(obj), - optionsFromPlayer: player => - player.spec.oneofKind == 'tankWarlock' ? player.spec.tankWarlock.options || WarlockOptions.create() : WarlockOptions.create(), - }, [Spec.SpecWarrior]: { rotationCreate: () => WarriorRotation.create(), rotationEquals: (a, b) => WarriorRotation.equals(a as WarriorRotation, b as WarriorRotation), @@ -1089,7 +1057,6 @@ export const specToClass: Record = { [Spec.SpecRestorationShaman]: Class.ClassShaman, [Spec.SpecWardenShaman]: Class.ClassShaman, [Spec.SpecWarlock]: Class.ClassWarlock, - [Spec.SpecTankWarlock]: Class.ClassWarlock, [Spec.SpecWarrior]: Class.ClassWarrior, [Spec.SpecTankWarrior]: Class.ClassWarrior, }; @@ -1123,7 +1090,6 @@ export const specToEligibleRaces: Record> = { [Spec.SpecHealingPriest]: priestRaces, [Spec.SpecShadowPriest]: priestRaces, [Spec.SpecWarlock]: warlockRaces, - [Spec.SpecTankWarlock]: warlockRaces, [Spec.SpecWarrior]: warriorRaces, [Spec.SpecTankWarrior]: warriorRaces, }; @@ -1140,7 +1106,6 @@ const tankSpecs: Array = [ Spec.SpecFeralTankDruid, Spec.SpecProtectionPaladin, Spec.SpecTankWarrior, - Spec.SpecTankWarlock, Spec.SpecTankRogue, Spec.SpecWardenShaman, ]; @@ -1182,7 +1147,6 @@ export const specToLocalStorageKey: Record = { [Spec.SpecHealingPriest]: '__classic_healing_priest', [Spec.SpecShadowPriest]: '__classic_shadow_priest', [Spec.SpecWarlock]: '__classic_warlock', - [Spec.SpecTankWarlock]: '__classic_tank_warlock', [Spec.SpecWarrior]: '__classic_warrior', [Spec.SpecTankWarrior]: '__classic_tank_warrior', }; @@ -1336,14 +1300,6 @@ export function withSpecProto(spec: Spec, player: PlayerP }), }; return copy; - case Spec.SpecTankWarlock: - copy.spec = { - oneofKind: 'tankWarlock', - tankWarlock: TankWarlock.create({ - options: specOptions as WarlockOptions, - }), - }; - return copy; case Spec.SpecWarrior: copy.spec = { oneofKind: 'warrior', @@ -1759,7 +1715,6 @@ export function makeDefaultBlessings(numPaladins: number): BlessingsAssignments { spec: Spec.SpecRestorationShaman, blessings: [] }, { spec: Spec.SpecWardenShaman, blessings: [] }, { spec: Spec.SpecWarlock, blessings: [Blessings.BlessingOfWisdom, Blessings.BlessingOfKings] }, - { spec: Spec.SpecTankWarlock, blessings: [Blessings.BlessingOfWisdom, Blessings.BlessingOfMight, Blessings.BlessingOfKings] }, { spec: Spec.SpecWarrior, blessings: [Blessings.BlessingOfKings, Blessings.BlessingOfMight] }, { spec: Spec.SpecTankWarrior, blessings: [Blessings.BlessingOfKings, Blessings.BlessingOfMight, Blessings.BlessingOfSanctuary] }, ]); diff --git a/ui/index.html b/ui/index.html index c9d558e0c..0c98ecb09 100644 --- a/ui/index.html +++ b/ui/index.html @@ -255,44 +255,16 @@

Classic

-