From 12fa0af2cdda4668a643129ea97099cef1b9ac49 Mon Sep 17 00:00:00 2001 From: Kayla Glick Date: Tue, 31 Dec 2024 18:10:55 -0500 Subject: [PATCH 1/6] starting shaman --- sim/shaman/_item_sets_pvp.go | 256 -------------- sim/shaman/chain_heal.go | 86 ----- sim/shaman/healing_wave.go | 73 ---- .../{_item_sets_pve.go => item_sets_pve.go} | 316 +----------------- sim/shaman/item_sets_pvp.go | 108 ++++++ sim/shaman/lesser_healing_wave.go | 81 ----- ui/core/launched_sims.ts | 4 +- ui/elemental_shaman/index.ts | 5 +- ui/index.html | 8 +- 9 files changed, 134 insertions(+), 803 deletions(-) delete mode 100644 sim/shaman/_item_sets_pvp.go delete mode 100644 sim/shaman/chain_heal.go delete mode 100644 sim/shaman/healing_wave.go rename sim/shaman/{_item_sets_pve.go => item_sets_pve.go} (60%) create mode 100644 sim/shaman/item_sets_pvp.go delete mode 100644 sim/shaman/lesser_healing_wave.go diff --git a/sim/shaman/_item_sets_pvp.go b/sim/shaman/_item_sets_pvp.go deleted file mode 100644 index 01b78f6ee6..0000000000 --- a/sim/shaman/_item_sets_pvp.go +++ /dev/null @@ -1,256 +0,0 @@ -package shaman - -import ( - "github.com/wowsims/classic/sim/core" - "github.com/wowsims/classic/sim/core/stats" -) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 3 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetBloodGuardsMail = core.NewItemSet(core.ItemSet{ - Name: "Blood Guard's Mail", - Bonuses: map[int32]core.ApplyEffect{ - 3: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 15) - }, - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.AttackPower, 30) - }, - }, -}) - -var ItemSetBloodGuardsInscribedMail = core.NewItemSet(core.ItemSet{ - Name: "Blood Guard's Inscribed Mail", - Bonuses: map[int32]core.ApplyEffect{ - 3: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 15) - }, - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.HealingPower, 33) - }, - }, -}) - -var ItemSetBloodGuardsPulsingMail = core.NewItemSet(core.ItemSet{ - Name: "Blood Guard's Pulsing Mail", - Bonuses: map[int32]core.ApplyEffect{ - 3: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 15) - }, - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.SpellPower, 18) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 4 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetChampionsWartide = core.NewItemSet(core.ItemSet{ - Name: "Champion's Wartide", - Bonuses: map[int32]core.ApplyEffect{ - // Increases healing done by spells and effects by up to 44. - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.HealingPower, 44) - }, - // Improves your chance to get a critical strike with all Shock spells by 2%. - 4: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - shaman.GetOrRegisterAura(core.Aura{ - Label: "Shaman Shock Crit Bonus", - ActionID: core.ActionID{SpellID: 22804}, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range core.Flatten([][]*core.Spell{shaman.EarthShock, shaman.FlameShock, shaman.FrostShock}) { - if spell != nil { - spell.BonusCritRating += 2 * core.CritRatingPerCritChance - } - } - }, - }) - }, - // +20 Stamina. - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 20) - }, - }, -}) - -var ItemSetChampionsThunderfist = core.NewItemSet(core.ItemSet{ - Name: "Champion's Thunderfist", - 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) - }, - // Improves your chance to get a critical strike with all Shock spells by 2%. - 4: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - shaman.GetOrRegisterAura(core.Aura{ - Label: "Shaman Shock Crit Bonus", - ActionID: core.ActionID{SpellID: 22804}, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range core.Flatten([][]*core.Spell{shaman.EarthShock, shaman.FlameShock, shaman.FrostShock}) { - if spell != nil { - spell.BonusCritRating += 2 * core.CritRatingPerCritChance - } - } - }, - }) - }, - // +20 Stamina. - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 20) - }, - }, -}) - -var ItemSetChampionsEarthshaker = core.NewItemSet(core.ItemSet{ - Name: "Champion's Earthshaker", - Bonuses: map[int32]core.ApplyEffect{ - // +40 Attack Power. - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStats(stats.Stats{ - stats.AttackPower: 40, - stats.RangedAttackPower: 40, - }) - }, - // Improves your chance to get a critical strike with all Shock spells by 2%. - 4: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - shaman.GetOrRegisterAura(core.Aura{ - Label: "Shaman Shock Crit Bonus", - ActionID: core.ActionID{SpellID: 22804}, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range core.Flatten([][]*core.Spell{shaman.EarthShock, shaman.FlameShock, shaman.FrostShock}) { - if spell != nil { - spell.BonusCritRating += 2 * core.CritRatingPerCritChance - } - } - }, - }) - }, - // +20 Stamina. - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 20) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 3 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetWarlordsWartide = core.NewItemSet(core.ItemSet{ - Name: "Warlord's Wartide", - Bonuses: map[int32]core.ApplyEffect{ - // +20 Stamina. - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 20) - }, - // Improves your chance to get a critical strike with all Shock spells by 2%. - 4: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - shaman.GetOrRegisterAura(core.Aura{ - Label: "Shaman Shock Crit Bonus", - ActionID: core.ActionID{SpellID: 22804}, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range core.Flatten([][]*core.Spell{shaman.EarthShock, shaman.FlameShock, shaman.FrostShock}) { - if spell != nil { - spell.BonusCritRating += 2 * core.CritRatingPerCritChance - } - } - }, - }) - }, - // Increases healing done by spells and effects by up to 44. - // Increases healing done by up to 44 and damage done by up to 15 for all magical spells and effects. - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStats(stats.Stats{ - stats.HealingPower: 88, - stats.SpellDamage: 15, - }) - }, - }, -}) - -var ItemSetWarlordsThunderfist = core.NewItemSet(core.ItemSet{ - Name: "Warlord's Thunderfist", - Bonuses: map[int32]core.ApplyEffect{ - // +20 Stamina. - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 20) - }, - // Improves your chance to get a critical strike with all Shock spells by 2%. - 4: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - shaman.GetOrRegisterAura(core.Aura{ - Label: "Shaman Shock Crit Bonus", - ActionID: core.ActionID{SpellID: 22804}, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range core.Flatten([][]*core.Spell{shaman.EarthShock, shaman.FlameShock, shaman.FrostShock}) { - if spell != nil { - spell.BonusCritRating += 2 * core.CritRatingPerCritChance - } - } - }, - }) - }, - // 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 ItemSetWarlordsEarthshaker = core.NewItemSet(core.ItemSet{ - Name: "Warlord's Earthshaker", - Bonuses: map[int32]core.ApplyEffect{ - // +20 Stamina. - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 20) - }, - // Improves your chance to get a critical strike with all Shock spells by 2%. - 4: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - shaman.GetOrRegisterAura(core.Aura{ - Label: "Shaman Shock Crit Bonus", - ActionID: core.ActionID{SpellID: 22804}, - OnInit: func(aura *core.Aura, sim *core.Simulation) { - for _, spell := range core.Flatten([][]*core.Spell{shaman.EarthShock, shaman.FlameShock, shaman.FrostShock}) { - if spell != nil { - spell.BonusCritRating += 2 * core.CritRatingPerCritChance - } - } - }, - }) - }, - // +40 Attack Power. - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStats(stats.Stats{ - stats.AttackPower: 40, - stats.RangedAttackPower: 40, - }) - }, - }, -}) diff --git a/sim/shaman/chain_heal.go b/sim/shaman/chain_heal.go deleted file mode 100644 index 394235fbc0..0000000000 --- a/sim/shaman/chain_heal.go +++ /dev/null @@ -1,86 +0,0 @@ -package shaman - -import ( - "time" - - "github.com/wowsims/classic/sim/core" -) - -const ChainHealRanks = 3 -const ChainHealTargetCount = int32(3) - -var ChainHealSpellId = [ChainHealRanks + 1]int32{0, 1064, 10622, 10623} -var ChainHealBaseHealing = [ChainHealRanks + 1][]float64{{0}, {332, 381}, {416, 477}, {567, 646}} -var ChainHealSpellCoef = [ChainHealRanks + 1]float64{0, .714, .714, .714} -var ChainHealCastTime = [ChainHealRanks + 1]int32{0, 2500, 2500, 2500} -var ChainHealManaCost = [ChainHealRanks + 1]float64{0, 260, 315, 405} -var ChainHealLevel = [ChainHealRanks + 1]int{0, 40, 46, 54} - -func (shaman *Shaman) registerChainHealSpell() { - shaman.ChainHeal = make([]*core.Spell, ChainHealRanks+1) - - for rank := 1; rank <= ChainHealRanks; rank++ { - config := shaman.newChainHealSpellConfig(rank) - - if config.RequiredLevel <= int(shaman.Level) { - shaman.ChainHeal[rank] = shaman.RegisterSpell(config) - } - } -} - -func (shaman *Shaman) newChainHealSpellConfig(rank int) core.SpellConfig { - spellId := ChainHealSpellId[rank] - baseHealingMultiplier := 1 + shaman.purificationHealingModifier() - baseHealingLow := ChainHealBaseHealing[rank][0] * baseHealingMultiplier - baseHealingHigh := ChainHealBaseHealing[rank][1] * baseHealingMultiplier - spellCoeff := ChainHealSpellCoef[rank] - castTime := ChainHealCastTime[rank] - manaCost := ChainHealManaCost[rank] - level := ChainHealLevel[rank] - - bounceCoef := 0.50 // 50% reduction per bounce - targetCount := ChainHealTargetCount - - return core.SpellConfig{ - ActionID: core.ActionID{SpellID: spellId}, - SpellCode: SpellCode_ShamanChainHeal, - DefenseType: core.DefenseTypeMagic, - SpellSchool: core.SpellSchoolNature, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL | SpellFlagShaman, - - RequiredLevel: level, - Rank: rank, - - ManaCost: core.ManaCostOptions{ - FlatCost: manaCost, - }, - - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: time.Millisecond * time.Duration(castTime), - }, - }, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - BonusCoefficient: spellCoeff, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - targets := sim.Environment.Raid.GetFirstNPlayersOrPets(targetCount) - curTarget := targets[0] - origMult := spell.DamageMultiplier - // TODO: This bounces to most hurt friendly... - for hitIndex := 0; hitIndex < len(targets); hitIndex++ { - originalDamageMultiplier := spell.DamageMultiplier - spell.CalcAndDealHealing(sim, curTarget, sim.Roll(baseHealingLow, baseHealingHigh), spell.OutcomeHealingCrit) - spell.DamageMultiplier = originalDamageMultiplier - spell.DamageMultiplier *= bounceCoef - - curTarget = targets[hitIndex] - } - spell.DamageMultiplier = origMult - }, - } -} diff --git a/sim/shaman/healing_wave.go b/sim/shaman/healing_wave.go deleted file mode 100644 index 2a633bbb6e..0000000000 --- a/sim/shaman/healing_wave.go +++ /dev/null @@ -1,73 +0,0 @@ -package shaman - -import ( - "time" - - "github.com/wowsims/classic/sim/core" -) - -const HealingWaveRanks = 10 - -var HealingWaveSpellId = [HealingWaveRanks + 1]int32{0, 331, 332, 547, 913, 939, 959, 8005, 10395, 10396, 25357} -var HealingWaveBaseHealing = [HealingWaveRanks + 1][]float64{{0}, {36, 47}, {69, 83}, {136, 163}, {279, 328}, {378, 443}, {552, 639}, {759, 874}, {1026, 1177}, {1389, 1583}, {1620, 1850}} -var HealingWaveSpellCoef = [HealingWaveRanks + 1]float64{0, .123, .271, .5, .793, .857, .857, .857, .857, .857, .857} -var HealingWaveCastTime = [HealingWaveRanks + 1]int32{0, 1500, 2000, 2500, 3000, 3000, 3000, 3000, 3000, 3000, 3000} -var HealingWaveManaCost = [HealingWaveRanks + 1]float64{0, 25, 45, 80, 155, 200, 265, 340, 440, 560, 620} -var HealingWaveLevel = [HealingWaveRanks + 1]int{0, 1, 6, 12, 18, 24, 32, 40, 48, 56, 60} - -func (shaman *Shaman) registerHealingWaveSpell() { - shaman.HealingWave = make([]*core.Spell, HealingWaveRanks+1) - - for rank := 1; rank <= HealingWaveRanks; rank++ { - config := shaman.newHealingWaveSpellConfig(rank) - - if config.RequiredLevel <= int(shaman.Level) { - shaman.HealingWave[rank] = shaman.RegisterSpell(config) - } - } -} - -func (shaman *Shaman) newHealingWaveSpellConfig(rank int) core.SpellConfig { - spellId := HealingWaveSpellId[rank] - baseHealingMultiplier := 1 + shaman.purificationHealingModifier() - baseHealingLow := HealingWaveBaseHealing[rank][0] * baseHealingMultiplier - baseHealingHigh := HealingWaveBaseHealing[rank][1] * baseHealingMultiplier - spellCoeff := HealingWaveSpellCoef[rank] - castTime := HealingWaveCastTime[rank] - manaCost := HealingWaveManaCost[rank] - level := HealingWaveLevel[rank] - - return core.SpellConfig{ - ActionID: core.ActionID{SpellID: spellId}, - SpellCode: SpellCode_ShamanHealingWave, - SpellSchool: core.SpellSchoolNature, - DefenseType: core.DefenseTypeMagic, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL | SpellFlagShaman, - - RequiredLevel: level, - Rank: rank, - - ManaCost: core.ManaCostOptions{ - FlatCost: manaCost, - }, - - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: time.Millisecond * time.Duration( - castTime-(100*shaman.Talents.ImprovedHealingWave), - ), - }, - }, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - BonusCoefficient: spellCoeff, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - // TODO: Take Healing Way into account 6% stacking up to 3x - spell.CalcAndDealHealing(sim, spell.Unit, sim.Roll(baseHealingLow, baseHealingHigh), spell.OutcomeHealingCrit) - }, - } -} diff --git a/sim/shaman/_item_sets_pve.go b/sim/shaman/item_sets_pve.go similarity index 60% rename from sim/shaman/_item_sets_pve.go rename to sim/shaman/item_sets_pve.go index 9e13af11e3..c38164eef9 100644 --- a/sim/shaman/_item_sets_pve.go +++ b/sim/shaman/item_sets_pve.go @@ -9,129 +9,16 @@ import ( "github.com/wowsims/classic/sim/core/stats" ) -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 2 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetElectromanticStormbringer = core.NewItemSet(core.ItemSet{ - Name: "Electromantic Stormbringer's Chain", - Bonuses: map[int32]core.ApplyEffect{ - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.SpellPower, 12) - }, - 3: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - shaman.OnSpellRegistered(func(spell *core.Spell) { - if spell.SpellCode == SpellCode_ShamanLightningBolt { - spell.DefaultCast.CastTime -= time.Millisecond * 100 - } - }) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 3 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var OstracizedBerserksBattlemail = core.NewItemSet(core.ItemSet{ - Name: "Ostracized Berserker's Battlemail", - Bonuses: map[int32]core.ApplyEffect{ - 2: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.AttackPower, 20) - }, - 3: func(agent core.Agent) { - c := agent.GetCharacter() - - procAura := c.GetOrRegisterAura(core.Aura{ - Label: "Fiery Strength Proc", - ActionID: core.ActionID{SpellID: 449932}, - Duration: time.Second * 12, - MaxStacks: 10, - OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) { - statsDelta := float64(newStacks-oldStacks) * 5.0 - aura.Unit.AddStatDynamic(sim, stats.AttackPower, statsDelta) - }, - }) - - core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ - Name: "Fiery Strength", - Callback: core.CallbackOnSpellHitDealt | core.CallbackOnPeriodicDamageDealt, - Outcome: core.OutcomeLanded, - ProcMask: core.ProcMaskDirect, - Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if spell.SpellSchool.Matches(core.SpellSchoolFire) { - procAura.Activate(sim) - procAura.AddStack(sim) - } - }, - }) - }, - }, -}) - -var ItemSetEmeraldChainmail = core.NewItemSet(core.ItemSet{ - Name: "Emerald Chainmail", - Bonuses: map[int32]core.ApplyEffect{ - 3: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 10) - }, - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.SpellPower, 12) - }, - }, -}) - -var ItemSetEmeraldScalemail = core.NewItemSet(core.ItemSet{ - Name: "Emerald Scalemail", - Bonuses: map[int32]core.ApplyEffect{ - 3: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 10) - }, - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.AttackPower, 20) - }, - }, -}) - -var ItemSetEmeraldLadenChain = core.NewItemSet(core.ItemSet{ - Name: "Emerald Laden Chain", - Bonuses: map[int32]core.ApplyEffect{ - 3: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.Stamina, 10) - }, - 6: func(agent core.Agent) { - c := agent.GetCharacter() - c.AddStat(stats.HealingPower, 22) - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 4 Item Sets -/////////////////////////////////////////////////////////////////////////// - var ItemSetTheFiveThunders = core.NewItemSet(core.ItemSet{ Name: "The Five Thunders", Bonuses: map[int32]core.ApplyEffect{ - // +40 Attack Power, up to 23 increased damage from spells, and up to 44 increased healing from spells. + // +8 All Resistances. 2: func(agent core.Agent) { c := agent.GetCharacter() - c.AddStats(stats.Stats{ - stats.AttackPower: 40, - stats.RangedAttackPower: 40, - stats.SpellDamage: 23, - stats.HealingPower: 44, - }) + c.AddResistances(8) }, - // 6% chance on mainhand autoattack and 4% chance on spellcast to increase your damage and healing done by magical spells and effects by up to 95 for 10 sec. + // Chance on spell cast to increase your damage and healing by up to 95 for 10 sec. + // (Proc chance: 4%) 4: func(agent core.Agent) { c := agent.GetCharacter() @@ -140,14 +27,6 @@ var ItemSetTheFiveThunders = core.NewItemSet(core.ItemSet{ procAura.Activate(sim) } - core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ - Name: "Item - The Furious Storm Proc (MH Auto)", - Callback: core.CallbackOnSpellHitDealt, - Outcome: core.OutcomeLanded, - ProcMask: core.ProcMaskMeleeMHAuto, - ProcChance: 0.06, - Handler: handler, - }) core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ Name: "Item - The Furious Storm Proc (Spell Cast)", Callback: core.CallbackOnCastComplete, @@ -156,7 +35,7 @@ var ItemSetTheFiveThunders = core.NewItemSet(core.ItemSet{ Handler: handler, }) }, - // +8 All Resistances. + // Increases damage and healing done by magical spells and effects by up to 23. 6: func(agent core.Agent) { c := agent.GetCharacter() c.AddResistances(8) @@ -169,198 +48,39 @@ var ItemSetTheFiveThunders = core.NewItemSet(core.ItemSet{ }, }) -var ItemSetEarthfuryEruption = core.NewItemSet(core.ItemSet{ - Name: "Earthfury Eruption", +var ItemSetTheEarthfury = core.NewItemSet(core.ItemSet{ + Name: "The Earthfury", Bonuses: map[int32]core.ApplyEffect{ - // The radius of your totems that affect friendly targets is increased to 40 yd. + // The radius of your totems that affect friendly targets is increased to 30 yd. 2: func(agent core.Agent) { // Nothing to do }, - // Your Lightning Bolt critical strikes have a 35% chance to reset the cooldown on Lava Burst and Chain Lightning and make the next Lava Burst, Chain Heal, or Chain Lightning within 10 sec instant. + // After casting your Healing Wave or Lesser Healing Wave spell, gives you a 25% chance to gain Mana equal to 35% of the base cost of the spell. 4: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - shaman.GetOrRegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Shaman - Elemental 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_ShamanLightningBolt && spell.ProcMask.Matches(core.ProcMaskSpellDamage) && result.DidCrit() && sim.Proc(.35, "Power Surge") { - shaman.PowerSurgeDamageAura.Activate(sim) - } - }, - }) - }, - // Lava Burst now also refreshes the duration of Flame Shock on your target back to 12 sec. - 6: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - core.MakePermanent(shaman.GetOrRegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Shaman - Elemental 6P Bonus", - OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { - if spell.SpellCode == SpellCode_ShamanLavaBurst { - for _, spell := range shaman.FlameShock { - if spell == nil { - continue - } - - if dot := spell.Dot(shaman.CurrentTarget); dot.IsActive() { - dot.NumberOfTicks = dot.OriginalNumberOfTicks - dot.Rollover(sim) - } - } - } - }, - })) - }, - }, -}) - -var ItemSetEarthfuryRelief = core.NewItemSet(core.ItemSet{ - Name: "Earthfury Relief", - Bonuses: map[int32]core.ApplyEffect{ - // The radius of your totems that affect friendly targets is increased to 40 yd. - 2: func(agent core.Agent) { // Nothing to do }, - // After casting your Healing Wave, Lesser Healing Wave, or Riptide spell, gives you a 25% chance to gain Mana equal to 35% of the base cost of the spell. - 4: func(agent core.Agent) { - // Not implementing for now - }, - // Your Healing Wave will now jump to additional nearby targets. Each jump reduces the effectiveness of the heal by 80%, and the spell will jump to up to 2 additional targets. + // Your Healing Wave will now jump to additional nearby targets. Each jump reduces the effectiveness of the heal by 80%, and the spell will jump to up to two additional targets. 6: func(agent core.Agent) { - // Not implementing for now - }, - }, -}) - -var ItemSetEarthfuryImpact = core.NewItemSet(core.ItemSet{ - Name: "Earthfury Impact", - Bonuses: map[int32]core.ApplyEffect{ - // The radius of your totems that affect friendly targets is increased to 40 yd. - 2: func(agent core.Agent) { // Nothing to do }, - // 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 Flurry talent grants an additional 10% increase to your attack speed. - 6: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - shaman.RegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Shaman - Enhancement 6P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - shaman.bonusFlurrySpeed += .10 - }, - }) - }, }, }) -var ItemSetEarthfuryResolve = core.NewItemSet(core.ItemSet{ - Name: "Earthfury Resolve", +var ItemSetTheTenStorms = core.NewItemSet(core.ItemSet{ + Name: "The Ten Storms", Bonuses: map[int32]core.ApplyEffect{ - // Increases your attack speed by 30% for your next 3 swings after you parry, dodge, or block. + // Increases the amount healed by Chain Heal to targets beyond the first by 30%. 2: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - - flurryAura := shaman.makeFlurryAura(5) - // The consumption trigger may not exist if the Shaman doesn't talent into Flurry - shaman.makeFlurryConsumptionTrigger(flurryAura) - - core.MakePermanent(shaman.GetOrRegisterAura(core.Aura{ - Label: "S03 - Item - T1 - Shaman - Tank 2P Bonus", - OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if result.DidParry() || result.DidDodge() || result.DidBlock() { - flurryAura.Activate(sim) - flurryAura.SetStacks(sim, 3) - } - }, - })) - }, - // Your parries and dodges also activate your Shield Mastery rune ability. - 4: func(agent core.Agent) { - // Implemented in runes.go - }, - // Your Stoneskin Totem also reduces Physical damage taken by 5% and your Windwall Totem also reduces Magical damage taken by 5%. - 6: func(agent core.Agent) { - // Debuffs implemented in core/buffs.go, activated with a raid buff setting or in earth_totems.go and air_totems.go - }, - }, -}) - -/////////////////////////////////////////////////////////////////////////// -// SoD Phase 5 Item Sets -/////////////////////////////////////////////////////////////////////////// - -var ItemSetEruptionOfTheTenStorms = core.NewItemSet(core.ItemSet{ - Name: "Eruption of the Ten Storms", - Bonuses: map[int32]core.ApplyEffect{ - // Your spell critical strikes now have a 100% chance trigger your Elemental Focus talent. - 2: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - if !shaman.Talents.ElementalFocus { - return - } - - core.MakePermanent(shaman.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Shaman - Elemental 2P Bonus", - OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - if shaman.isShamanDamagingSpell(spell) && result.DidCrit() { - shaman.ClearcastingAura.Activate(sim) - shaman.ClearcastingAura.SetStacks(sim, shaman.ClearcastingAura.MaxStacks) - } - }, - })) + // Nothing to do }, - // Loyal Beta from your Spirit of the Alpha ability now also increases Fire, Frost, and Nature damage by 5%. + // Improves your chance to get a critical strike with Nature spells by 3%. 4: func(agent core.Agent) { shaman := agent.(ShamanAgent).GetShaman() - if !shaman.HasRune(proto.ShamanRune_RuneFeetSpiritOfTheAlpha) { - return - } - - core.MakePermanent(shaman.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Shaman - Elemental 4P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - oldOnGain := shaman.LoyalBetaAura.OnGain - shaman.LoyalBetaAura.OnGain = func(aura *core.Aura, sim *core.Simulation) { - oldOnGain(aura, sim) - shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFrost] *= 1.05 - shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexFire] *= 1.05 - shaman.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexNature] *= 1.05 - } - }, - })) + shaman.PseudoStats.SchoolBonusCritChance[stats.SchoolIndexNature] += 3 * core.SpellCritRatingPerCritChance }, - // While Clearcasting is active, you deal 15% more non-Physical damage. + // When you cast a Healing Wave or Lesser Healing Wave, there is a 25% chance the target also receives a free Lightning Shield that causes 50 Nature damage to attacker on hit. 6: func(agent core.Agent) { - shaman := agent.(ShamanAgent).GetShaman() - if !shaman.Talents.ElementalFocus { - return - } - - core.MakePermanent(shaman.RegisterAura(core.Aura{ - Label: "S03 - Item - T2 - Shaman - Elemental 6P Bonus", - OnInit: func(aura *core.Aura, sim *core.Simulation) { - oldOnGain := shaman.ClearcastingAura.OnGain - shaman.ClearcastingAura.OnGain = func(aura *core.Aura, sim *core.Simulation) { - oldOnGain(aura, sim) - shaman.PseudoStats.SchoolDamageDealtMultiplier.MultiplyMagicSchools(1.15) - } - - oldOnExpire := shaman.ClearcastingAura.OnExpire - shaman.ClearcastingAura.OnExpire = func(aura *core.Aura, sim *core.Simulation) { - oldOnExpire(aura, sim) - shaman.PseudoStats.SchoolDamageDealtMultiplier.MultiplyMagicSchools(1 / 1.15) - } - }, - })) + // Nothing to do }, }, }) diff --git a/sim/shaman/item_sets_pvp.go b/sim/shaman/item_sets_pvp.go new file mode 100644 index 0000000000..4890d2ea17 --- /dev/null +++ b/sim/shaman/item_sets_pvp.go @@ -0,0 +1,108 @@ +package shaman + +import ( + "github.com/wowsims/classic/sim/core" + "github.com/wowsims/classic/sim/core/stats" +) + +var ItemSetChampionsEarthshaker = core.NewItemSet(core.ItemSet{ + Name: "Champion's Earthshaker", + Bonuses: map[int32]core.ApplyEffect{ + // +40 Attack Power. + 2: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStats(stats.Stats{ + stats.AttackPower: 40, + stats.RangedAttackPower: 40, + }) + }, + // Improves your chance to get a critical strike with all Shock spells by 2%. + 4: func(agent core.Agent) { + shaman := agent.(ShamanAgent).GetShaman() + shaman.GetOrRegisterAura(core.Aura{ + Label: "Shaman Shock Crit Bonus", + ActionID: core.ActionID{SpellID: 22804}, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range core.Flatten([][]*core.Spell{shaman.EarthShock, shaman.FlameShock, shaman.FrostShock}) { + if spell != nil { + spell.BonusCritRating += 2 * core.CritRatingPerCritChance + } + } + }, + }) + }, + // +15 Stamina. + 6: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.Stamina, 15) + }, + }, +}) + +var ItemSetChampionsStormcaller = core.NewItemSet(core.ItemSet{ + Name: "Champion's Stormcaller", + Bonuses: map[int32]core.ApplyEffect{ + // +40 Attack Power. + 2: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStats(stats.Stats{ + stats.AttackPower: 40, + stats.RangedAttackPower: 40, + }) + }, + // Improves your chance to get a critical strike with all Shock spells by 2%. + 4: func(agent core.Agent) { + shaman := agent.(ShamanAgent).GetShaman() + shaman.GetOrRegisterAura(core.Aura{ + Label: "Shaman Shock Crit Bonus", + ActionID: core.ActionID{SpellID: 22804}, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range core.Flatten([][]*core.Spell{shaman.EarthShock, shaman.FlameShock, shaman.FrostShock}) { + if spell != nil { + spell.BonusCritRating += 2 * core.CritRatingPerCritChance + } + } + }, + }) + }, + // +20 Stamina. + 6: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.Stamina, 20) + }, + }, +}) + +var ItemSetWarlordsEarthshaker = core.NewItemSet(core.ItemSet{ + Name: "Warlord's Earthshaker", + Bonuses: map[int32]core.ApplyEffect{ + // +20 Stamina. + 2: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStat(stats.Stamina, 20) + }, + // Improves your chance to get a critical strike with all Shock spells by 2%. + 4: func(agent core.Agent) { + shaman := agent.(ShamanAgent).GetShaman() + shaman.GetOrRegisterAura(core.Aura{ + Label: "Shaman Shock Crit Bonus", + ActionID: core.ActionID{SpellID: 22804}, + OnInit: func(aura *core.Aura, sim *core.Simulation) { + for _, spell := range core.Flatten([][]*core.Spell{shaman.EarthShock, shaman.FlameShock, shaman.FrostShock}) { + if spell != nil { + spell.BonusCritRating += 2 * core.CritRatingPerCritChance + } + } + }, + }) + }, + // +40 Attack Power. + 6: func(agent core.Agent) { + c := agent.GetCharacter() + c.AddStats(stats.Stats{ + stats.AttackPower: 40, + stats.RangedAttackPower: 40, + }) + }, + }, +}) diff --git a/sim/shaman/lesser_healing_wave.go b/sim/shaman/lesser_healing_wave.go deleted file mode 100644 index 4158d5df7d..0000000000 --- a/sim/shaman/lesser_healing_wave.go +++ /dev/null @@ -1,81 +0,0 @@ -package shaman - -import ( - "time" - - "github.com/wowsims/classic/sim/core" -) - -const LesserHealingWaveRanks = 6 - -var LesserHealingWaveSpellId = [LesserHealingWaveRanks + 1]int32{0, 8004, 8008, 8010, 10466, 10467, 10468} -var LesserHealingWaveBaseHealing = [LesserHealingWaveRanks + 1][]float64{{0}, {170, 195}, {257, 292}, {347, 391}, {473, 529}, {649, 723}, {832, 928}} -var LesserHealingWaveSpellCoef = [LesserHealingWaveRanks + 1]float64{0, .429, .429, .429, .429, .429, .429} -var LesserHealingWaveCastTime = [LesserHealingWaveRanks + 1]int32{0, 1500, 1500, 1500, 1500, 1500, 1500} -var LesserHealingWaveManaCost = [LesserHealingWaveRanks + 1]float64{0, 105, 145, 185, 235, 305, 380} -var LesserHealingWaveLevel = [LesserHealingWaveRanks + 1]int{0, 20, 28, 36, 44, 52, 60} - -func (shaman *Shaman) registerLesserHealingWaveSpell() { - shaman.LesserHealingWave = make([]*core.Spell, LesserHealingWaveRanks+1) - - for rank := 1; rank <= LesserHealingWaveRanks; rank++ { - config := shaman.newLesserHealingWaveSpellConfig(rank) - - if config.RequiredLevel <= int(shaman.Level) { - shaman.LesserHealingWave[rank] = shaman.RegisterSpell(config) - } - } -} - -func (shaman *Shaman) newLesserHealingWaveSpellConfig(rank int) core.SpellConfig { - spellId := LesserHealingWaveSpellId[rank] - baseHealingMultiplier := 1 + shaman.purificationHealingModifier() - baseHealingLow := LesserHealingWaveBaseHealing[rank][0] * baseHealingMultiplier - baseHealingHigh := LesserHealingWaveBaseHealing[rank][1] * baseHealingMultiplier - spellCoeff := LesserHealingWaveSpellCoef[rank] - castTime := LesserHealingWaveCastTime[rank] - manaCost := LesserHealingWaveManaCost[rank] - level := LesserHealingWaveLevel[rank] - - switch shaman.Ranged().ID { - case TotemOfTheStorm: - baseHealingLow += 53 - baseHealingHigh += 53 - } - - return core.SpellConfig{ - ActionID: core.ActionID{SpellID: spellId}, - SpellCode: SpellCode_ShamanLesserHealingWave, - SpellSchool: core.SpellSchoolNature, - DefenseType: core.DefenseTypeMagic, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL | SpellFlagShaman, - MetricSplits: 6, - - RequiredLevel: level, - Rank: rank, - - ManaCost: core.ManaCostOptions{ - FlatCost: manaCost, - }, - - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: time.Millisecond * time.Duration(castTime), - }, - ModifyCast: func(sim *core.Simulation, spell *core.Spell, cast *core.Cast) { - castTime := shaman.ApplyCastSpeedForSpell(cast.CastTime, spell) - shaman.AutoAttacks.StopMeleeUntil(sim, sim.CurrentTime+castTime, false) - }, - }, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - BonusCoefficient: spellCoeff, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - spell.CalcAndDealHealing(sim, spell.Unit, sim.Roll(baseHealingLow, baseHealingHigh), spell.OutcomeHealingCrit) - }, - } -} diff --git a/ui/core/launched_sims.ts b/ui/core/launched_sims.ts index ce28e5eedd..9dc52ad7c6 100644 --- a/ui/core/launched_sims.ts +++ b/ui/core/launched_sims.ts @@ -42,11 +42,11 @@ export const simLaunchStatuses: Record = { }, [Spec.SpecElementalShaman]: { phase: Phase.Phase1, - status: LaunchStatus.Unlaunched, + status: LaunchStatus.Alpha, }, [Spec.SpecEnhancementShaman]: { phase: Phase.Phase1, - status: LaunchStatus.Unlaunched, + status: LaunchStatus.Alpha, }, [Spec.SpecRestorationShaman]: { phase: Phase.Phase1, diff --git a/ui/elemental_shaman/index.ts b/ui/elemental_shaman/index.ts index 86535f75c2..2167e3b983 100644 --- a/ui/elemental_shaman/index.ts +++ b/ui/elemental_shaman/index.ts @@ -1,11 +1,10 @@ +import { Player } from '../core/player.js'; import { Spec } from '../core/proto/common.js'; import { Sim } from '../core/sim.js'; -import { Player } from '../core/player.js'; import { TypedEvent } from '../core/typed_event.js'; - import { ElementalShamanSimUI } from './sim.js'; const sim = new Sim(); const player = new Player(Spec.SpecElementalShaman, sim); sim.raid.setPlayer(TypedEvent.nextEventID(), 0, player); -const simUI = new ElementalShamanSimUI(document.body, player); +new ElementalShamanSimUI(document.body, player); diff --git a/ui/index.html b/ui/index.html index 9baf77679e..52bada856b 100644 --- a/ui/index.html +++ b/ui/index.html @@ -180,25 +180,25 @@

Classic