Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions sim/core/spell.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ type SpellConfig struct {

CritDamageBonus float64

JumpTargets int32

BaseDamageMultiplierAdditivePct int64
DamageMultiplier float64
DamageMultiplierAdditivePct int64
Expand Down Expand Up @@ -182,6 +184,8 @@ type Spell struct {
dots DotArray
aoeDot *Dot

JumpTargets int32

shields ShieldArray
selfShield *Shield

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)
}
}
Comment on lines +644 to +658

@FelixPflaum FelixPflaum Mar 24, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only spells that chain in the sim are, I think, Chain Lightning, Multi Shot and Cleave. The better place to have that functionality is in the ApplyEffects function of the individual spells as it is done currently. Just replace the hardcoded chain count there instead.

Not to mention CL also requires the target number to calculate its dmg. That would even require adding an additional parameter for just those few spells.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the above. This functionality is very invasive to be in-here for the sake of a couple of spells which can just implement it into its own effects.

}

func (spell *Spell) ApplyAOEThreatIgnoreMultipliers(threatAmount float64) {
Expand Down
48 changes: 22 additions & 26 deletions sim/hunter/multi_shot.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
}
})

Expand Down