From 7d534661d3d836c63e823d398d9f6560c127b734 Mon Sep 17 00:00:00 2001 From: Nathan Berman Date: Mon, 24 Mar 2025 05:31:41 +0000 Subject: [PATCH 1/3] jumptargets for chaining abilities --- sim/core/spell.go | 31 ++++++++++++++++++++------ sim/hunter/multi_shot.go | 48 ++++++++++++++++++---------------------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/sim/core/spell.go b/sim/core/spell.go index 9471b11c36..99ab33a11c 100644 --- a/sim/core/spell.go +++ b/sim/core/spell.go @@ -46,6 +46,8 @@ type SpellConfig struct { CritDamageBonus float64 + JumpTargets int32 + BaseDamageMultiplierAdditivePct int64 DamageMultiplier float64 DamageMultiplierAdditivePct int64 @@ -182,6 +184,8 @@ type Spell struct { dots DotArray aoeDot *Dot + JumpTargets int32 + shields ShieldArray selfShield *Shield @@ -240,6 +244,10 @@ func (unit *Unit) RegisterSpell(config SpellConfig) *Spell { } } + if config.JumpTargets == 0 { + config.JumpTargets = 1 + } + spell := &Spell{ ActionID: config.ActionID, ClassSpellMask: config.ClassSpellMask, @@ -292,6 +300,8 @@ func (unit *Unit) RegisterSpell(config SpellConfig) *Spell { RelatedAuras: config.RelatedAuras, RelatedDotSpell: config.RelatedDotSpell, RelatedSelfBuff: config.RelatedSelfBuff, + + JumpTargets: config.JumpTargets, } spell.updateBaseDamageMultiplier() @@ -631,14 +641,21 @@ func (spell *Spell) applyEffects(sim *Simulation, target *Unit) { spell.SpellMetrics[target.UnitIndex].Casts++ spell.casts++ - // Not sure if we want to split this flag into its own? - // Both are used to optimize away unneccesery calls and 99% - // of the time are gonna be used together. For now just in one - if !spell.Flags.Matches(SpellFlagNoOnCastComplete) { - spell.Unit.OnApplyEffects(sim, target, spell) - } + targetsToHit := min(spell.JumpTargets, sim.Environment.GetNumTargets()) + for targetIndex := int32(0); targetIndex < targetsToHit; targetIndex++ { + // Not sure if we want to split this flag into its own? + // Both are used to optimize away unneccesery calls and 99% + // of the time are gonna be used together. For now just in one + if !spell.Flags.Matches(SpellFlagNoOnCastComplete) { + spell.Unit.OnApplyEffects(sim, target, spell) + } + + spell.ApplyEffects(sim, target, spell) - spell.ApplyEffects(sim, target, spell) + if targetIndex < targetsToHit-1 { + target = sim.Environment.NextTargetUnit(target) + } + } } func (spell *Spell) ApplyAOEThreatIgnoreMultipliers(threatAmount float64) { diff --git a/sim/hunter/multi_shot.go b/sim/hunter/multi_shot.go index cecdb17177..30e77fdce1 100644 --- a/sim/hunter/multi_shot.go +++ b/sim/hunter/multi_shot.go @@ -13,8 +13,8 @@ func (hunter *Hunter) getMultiShotConfig(rank int, timer *core.Timer) core.Spell manaCost := [6]float64{0, 100, 140, 175, 210, 230}[rank] level := [6]int{0, 18, 30, 42, 54, 60}[rank] - numHits := min(3+hunter.MultiShotBonusTargets, hunter.Env.GetNumTargets()) - results := make([]*core.SpellResult, numHits) + //numHits := min(3+hunter.MultiShotBonusTargets, hunter.Env.GetNumTargets()) + //results := make([]*core.SpellResult, numHits) hasSerpentSpread := hunter.HasRune(proto.HunterRune_RuneLegsSerpentSpread) @@ -61,37 +61,33 @@ func (hunter *Hunter) getMultiShotConfig(rank int, timer *core.Timer) core.Spell ThreatMultiplier: 1, BonusCoefficient: 1, - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { - baseDamage := baseDamage + - hunter.AutoAttacks.Ranged().CalculateNormalizedWeaponDamage(sim, spell.RangedAttackPower(target, false)) + - hunter.AmmoDamageBonus + JumpTargets: 3, - results[hitIndex] = spell.CalcDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + baseDamage := baseDamage + + hunter.AutoAttacks.Ranged().CalculateNormalizedWeaponDamage(sim, spell.RangedAttackPower(target, false)) + + hunter.AmmoDamageBonus - target = sim.Environment.NextTargetUnit(target) - } + result := spell.CalcDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) hunter.AutoAttacks.EnableAutoSwing(sim) spell.WaitTravelTime(sim, func(s *core.Simulation) { - for _, result := range results { - spell.DealDamage(sim, result) - - if hasSerpentSpread { - serpentStingAura := hunter.SerpentSting.Dot(result.Target) - serpentStingTicks := serpentStingAura.NumberOfTicks - if serpentStingAura.IsActive() { - // If less then 4 ticks are left then we rollover with a 4 tick duration - serpentStingAura.NumberOfTicks = max(4, serpentStingAura.NumberOfTicks-serpentStingAura.TickCount) - serpentStingAura.Rollover(sim) - } else { - // Else we apply with a 4 tick duration - serpentStingAura.NumberOfTicks = 4 - serpentStingAura.Apply(sim) - } - serpentStingAura.NumberOfTicks = serpentStingTicks + spell.DealDamage(sim, result) + + if hasSerpentSpread { + serpentStingAura := hunter.SerpentSting.Dot(result.Target) + serpentStingTicks := serpentStingAura.NumberOfTicks + if serpentStingAura.IsActive() { + // If less then 4 ticks are left then we rollover with a 4 tick duration + serpentStingAura.NumberOfTicks = max(4, serpentStingAura.NumberOfTicks-serpentStingAura.TickCount) + serpentStingAura.Rollover(sim) + } else { + // Else we apply with a 4 tick duration + serpentStingAura.NumberOfTicks = 4 + serpentStingAura.Apply(sim) } + serpentStingAura.NumberOfTicks = serpentStingTicks } }) From 537a6de0340912fe9808b09364305fc9be5e3ead Mon Sep 17 00:00:00 2001 From: Nathan Berman Date: Mon, 24 Mar 2025 05:31:55 +0000 Subject: [PATCH 2/3] Revert "jumptargets for chaining abilities" This reverts commit 7d534661d3d836c63e823d398d9f6560c127b734. --- sim/core/spell.go | 31 ++++++-------------------- sim/hunter/multi_shot.go | 48 ++++++++++++++++++++++------------------ 2 files changed, 33 insertions(+), 46 deletions(-) diff --git a/sim/core/spell.go b/sim/core/spell.go index 99ab33a11c..9471b11c36 100644 --- a/sim/core/spell.go +++ b/sim/core/spell.go @@ -46,8 +46,6 @@ type SpellConfig struct { CritDamageBonus float64 - JumpTargets int32 - BaseDamageMultiplierAdditivePct int64 DamageMultiplier float64 DamageMultiplierAdditivePct int64 @@ -184,8 +182,6 @@ type Spell struct { dots DotArray aoeDot *Dot - JumpTargets int32 - shields ShieldArray selfShield *Shield @@ -244,10 +240,6 @@ func (unit *Unit) RegisterSpell(config SpellConfig) *Spell { } } - if config.JumpTargets == 0 { - config.JumpTargets = 1 - } - spell := &Spell{ ActionID: config.ActionID, ClassSpellMask: config.ClassSpellMask, @@ -300,8 +292,6 @@ func (unit *Unit) RegisterSpell(config SpellConfig) *Spell { RelatedAuras: config.RelatedAuras, RelatedDotSpell: config.RelatedDotSpell, RelatedSelfBuff: config.RelatedSelfBuff, - - JumpTargets: config.JumpTargets, } spell.updateBaseDamageMultiplier() @@ -641,21 +631,14 @@ func (spell *Spell) applyEffects(sim *Simulation, target *Unit) { spell.SpellMetrics[target.UnitIndex].Casts++ spell.casts++ - targetsToHit := min(spell.JumpTargets, sim.Environment.GetNumTargets()) - for targetIndex := int32(0); targetIndex < targetsToHit; targetIndex++ { - // Not sure if we want to split this flag into its own? - // Both are used to optimize away unneccesery calls and 99% - // of the time are gonna be used together. For now just in one - if !spell.Flags.Matches(SpellFlagNoOnCastComplete) { - spell.Unit.OnApplyEffects(sim, target, spell) - } - - spell.ApplyEffects(sim, target, spell) - - if targetIndex < targetsToHit-1 { - target = sim.Environment.NextTargetUnit(target) - } + // Not sure if we want to split this flag into its own? + // Both are used to optimize away unneccesery calls and 99% + // of the time are gonna be used together. For now just in one + if !spell.Flags.Matches(SpellFlagNoOnCastComplete) { + spell.Unit.OnApplyEffects(sim, target, spell) } + + spell.ApplyEffects(sim, target, spell) } func (spell *Spell) ApplyAOEThreatIgnoreMultipliers(threatAmount float64) { diff --git a/sim/hunter/multi_shot.go b/sim/hunter/multi_shot.go index 30e77fdce1..cecdb17177 100644 --- a/sim/hunter/multi_shot.go +++ b/sim/hunter/multi_shot.go @@ -13,8 +13,8 @@ func (hunter *Hunter) getMultiShotConfig(rank int, timer *core.Timer) core.Spell manaCost := [6]float64{0, 100, 140, 175, 210, 230}[rank] level := [6]int{0, 18, 30, 42, 54, 60}[rank] - //numHits := min(3+hunter.MultiShotBonusTargets, hunter.Env.GetNumTargets()) - //results := make([]*core.SpellResult, numHits) + numHits := min(3+hunter.MultiShotBonusTargets, hunter.Env.GetNumTargets()) + results := make([]*core.SpellResult, numHits) hasSerpentSpread := hunter.HasRune(proto.HunterRune_RuneLegsSerpentSpread) @@ -61,33 +61,37 @@ func (hunter *Hunter) getMultiShotConfig(rank int, timer *core.Timer) core.Spell ThreatMultiplier: 1, BonusCoefficient: 1, - JumpTargets: 3, - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseDamage := baseDamage + - hunter.AutoAttacks.Ranged().CalculateNormalizedWeaponDamage(sim, spell.RangedAttackPower(target, false)) + - hunter.AmmoDamageBonus + for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { + baseDamage := baseDamage + + hunter.AutoAttacks.Ranged().CalculateNormalizedWeaponDamage(sim, spell.RangedAttackPower(target, false)) + + hunter.AmmoDamageBonus + + results[hitIndex] = spell.CalcDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) - result := spell.CalcDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) + target = sim.Environment.NextTargetUnit(target) + } hunter.AutoAttacks.EnableAutoSwing(sim) spell.WaitTravelTime(sim, func(s *core.Simulation) { - spell.DealDamage(sim, result) - - if hasSerpentSpread { - serpentStingAura := hunter.SerpentSting.Dot(result.Target) - serpentStingTicks := serpentStingAura.NumberOfTicks - if serpentStingAura.IsActive() { - // If less then 4 ticks are left then we rollover with a 4 tick duration - serpentStingAura.NumberOfTicks = max(4, serpentStingAura.NumberOfTicks-serpentStingAura.TickCount) - serpentStingAura.Rollover(sim) - } else { - // Else we apply with a 4 tick duration - serpentStingAura.NumberOfTicks = 4 - serpentStingAura.Apply(sim) + for _, result := range results { + spell.DealDamage(sim, result) + + if hasSerpentSpread { + serpentStingAura := hunter.SerpentSting.Dot(result.Target) + serpentStingTicks := serpentStingAura.NumberOfTicks + if serpentStingAura.IsActive() { + // If less then 4 ticks are left then we rollover with a 4 tick duration + serpentStingAura.NumberOfTicks = max(4, serpentStingAura.NumberOfTicks-serpentStingAura.TickCount) + serpentStingAura.Rollover(sim) + } else { + // Else we apply with a 4 tick duration + serpentStingAura.NumberOfTicks = 4 + serpentStingAura.Apply(sim) + } + serpentStingAura.NumberOfTicks = serpentStingTicks } - serpentStingAura.NumberOfTicks = serpentStingTicks } }) From f5a8880f601cc27fe35567e33d9c0b3489093bc5 Mon Sep 17 00:00:00 2001 From: Nathan Berman Date: Mon, 24 Mar 2025 05:32:46 +0000 Subject: [PATCH 3/3] jumptargets for chaining abilities --- sim/core/spell.go | 31 ++++++++++++++++++++------ sim/hunter/multi_shot.go | 48 ++++++++++++++++++---------------------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/sim/core/spell.go b/sim/core/spell.go index 9471b11c36..99ab33a11c 100644 --- a/sim/core/spell.go +++ b/sim/core/spell.go @@ -46,6 +46,8 @@ type SpellConfig struct { CritDamageBonus float64 + JumpTargets int32 + BaseDamageMultiplierAdditivePct int64 DamageMultiplier float64 DamageMultiplierAdditivePct int64 @@ -182,6 +184,8 @@ type Spell struct { dots DotArray aoeDot *Dot + JumpTargets int32 + shields ShieldArray selfShield *Shield @@ -240,6 +244,10 @@ func (unit *Unit) RegisterSpell(config SpellConfig) *Spell { } } + if config.JumpTargets == 0 { + config.JumpTargets = 1 + } + spell := &Spell{ ActionID: config.ActionID, ClassSpellMask: config.ClassSpellMask, @@ -292,6 +300,8 @@ func (unit *Unit) RegisterSpell(config SpellConfig) *Spell { RelatedAuras: config.RelatedAuras, RelatedDotSpell: config.RelatedDotSpell, RelatedSelfBuff: config.RelatedSelfBuff, + + JumpTargets: config.JumpTargets, } spell.updateBaseDamageMultiplier() @@ -631,14 +641,21 @@ func (spell *Spell) applyEffects(sim *Simulation, target *Unit) { spell.SpellMetrics[target.UnitIndex].Casts++ spell.casts++ - // Not sure if we want to split this flag into its own? - // Both are used to optimize away unneccesery calls and 99% - // of the time are gonna be used together. For now just in one - if !spell.Flags.Matches(SpellFlagNoOnCastComplete) { - spell.Unit.OnApplyEffects(sim, target, spell) - } + targetsToHit := min(spell.JumpTargets, sim.Environment.GetNumTargets()) + for targetIndex := int32(0); targetIndex < targetsToHit; targetIndex++ { + // Not sure if we want to split this flag into its own? + // Both are used to optimize away unneccesery calls and 99% + // of the time are gonna be used together. For now just in one + if !spell.Flags.Matches(SpellFlagNoOnCastComplete) { + spell.Unit.OnApplyEffects(sim, target, spell) + } + + spell.ApplyEffects(sim, target, spell) - spell.ApplyEffects(sim, target, spell) + if targetIndex < targetsToHit-1 { + target = sim.Environment.NextTargetUnit(target) + } + } } func (spell *Spell) ApplyAOEThreatIgnoreMultipliers(threatAmount float64) { diff --git a/sim/hunter/multi_shot.go b/sim/hunter/multi_shot.go index cecdb17177..30e77fdce1 100644 --- a/sim/hunter/multi_shot.go +++ b/sim/hunter/multi_shot.go @@ -13,8 +13,8 @@ func (hunter *Hunter) getMultiShotConfig(rank int, timer *core.Timer) core.Spell manaCost := [6]float64{0, 100, 140, 175, 210, 230}[rank] level := [6]int{0, 18, 30, 42, 54, 60}[rank] - numHits := min(3+hunter.MultiShotBonusTargets, hunter.Env.GetNumTargets()) - results := make([]*core.SpellResult, numHits) + //numHits := min(3+hunter.MultiShotBonusTargets, hunter.Env.GetNumTargets()) + //results := make([]*core.SpellResult, numHits) hasSerpentSpread := hunter.HasRune(proto.HunterRune_RuneLegsSerpentSpread) @@ -61,37 +61,33 @@ func (hunter *Hunter) getMultiShotConfig(rank int, timer *core.Timer) core.Spell ThreatMultiplier: 1, BonusCoefficient: 1, - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { - baseDamage := baseDamage + - hunter.AutoAttacks.Ranged().CalculateNormalizedWeaponDamage(sim, spell.RangedAttackPower(target, false)) + - hunter.AmmoDamageBonus + JumpTargets: 3, - results[hitIndex] = spell.CalcDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + baseDamage := baseDamage + + hunter.AutoAttacks.Ranged().CalculateNormalizedWeaponDamage(sim, spell.RangedAttackPower(target, false)) + + hunter.AmmoDamageBonus - target = sim.Environment.NextTargetUnit(target) - } + result := spell.CalcDamage(sim, target, baseDamage, spell.OutcomeRangedHitAndCrit) hunter.AutoAttacks.EnableAutoSwing(sim) spell.WaitTravelTime(sim, func(s *core.Simulation) { - for _, result := range results { - spell.DealDamage(sim, result) - - if hasSerpentSpread { - serpentStingAura := hunter.SerpentSting.Dot(result.Target) - serpentStingTicks := serpentStingAura.NumberOfTicks - if serpentStingAura.IsActive() { - // If less then 4 ticks are left then we rollover with a 4 tick duration - serpentStingAura.NumberOfTicks = max(4, serpentStingAura.NumberOfTicks-serpentStingAura.TickCount) - serpentStingAura.Rollover(sim) - } else { - // Else we apply with a 4 tick duration - serpentStingAura.NumberOfTicks = 4 - serpentStingAura.Apply(sim) - } - serpentStingAura.NumberOfTicks = serpentStingTicks + spell.DealDamage(sim, result) + + if hasSerpentSpread { + serpentStingAura := hunter.SerpentSting.Dot(result.Target) + serpentStingTicks := serpentStingAura.NumberOfTicks + if serpentStingAura.IsActive() { + // If less then 4 ticks are left then we rollover with a 4 tick duration + serpentStingAura.NumberOfTicks = max(4, serpentStingAura.NumberOfTicks-serpentStingAura.TickCount) + serpentStingAura.Rollover(sim) + } else { + // Else we apply with a 4 tick duration + serpentStingAura.NumberOfTicks = 4 + serpentStingAura.Apply(sim) } + serpentStingAura.NumberOfTicks = serpentStingTicks } })