Skip to content

Commit

Permalink
Merge pull request #189 from wowsims/deathknight
Browse files Browse the repository at this point in the history
Deathknight damage coefficient stacking and bug fixes
  • Loading branch information
rosenrusinov authored Jul 19, 2022
2 parents 930979b + 3169b62 commit 4bd2d8c
Show file tree
Hide file tree
Showing 12 changed files with 81 additions and 27 deletions.
29 changes: 28 additions & 1 deletion sim/core/runic_power.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,21 @@ func RuneReadyAt(sim *Simulation, runes *[2]Rune) time.Duration {
return readyAt
}

func NextRuneReadyAt(sim *Simulation, runes *[2]Rune) time.Duration {
readyAt := NeverExpires
pa := runes[0].pas[0]
if pa != nil {
readyAt = MinDuration(readyAt, pa.NextActionAt)
}

pa = runes[1].pas[0]
if pa != nil {
readyAt = MinDuration(readyAt, pa.NextActionAt)
}

return readyAt
}

func (rp *runicPowerBar) BloodRuneReadyAt(sim *Simulation) time.Duration {
return RuneReadyAt(sim, &rp.bloodRunes)
}
Expand All @@ -231,6 +246,18 @@ func (rp *runicPowerBar) UnholyRuneReadyAt(sim *Simulation) time.Duration {
return RuneReadyAt(sim, &rp.unholyRunes)
}

func (rp *runicPowerBar) NextBloodRuneReadyAt(sim *Simulation) time.Duration {
return NextRuneReadyAt(sim, &rp.bloodRunes)
}

func (rp *runicPowerBar) NextFrostRuneReadyAt(sim *Simulation) time.Duration {
return NextRuneReadyAt(sim, &rp.frostRunes)
}

func (rp *runicPowerBar) NextUnholyRuneReadyAt(sim *Simulation) time.Duration {
return NextRuneReadyAt(sim, &rp.unholyRunes)
}

func (rp *runicPowerBar) CurrentBloodRunes() int32 {
return CurrentRunesOfType(&rp.bloodRunes, RuneState_Normal)
}
Expand Down Expand Up @@ -405,9 +432,9 @@ func RegenRuneAndCancelPAs(sim *Simulation, r *Rune) {
} else if r.state == RuneState_DeathSpent {
r.state = RuneState_Death
}
r.lastRegenTime = sim.CurrentTime

if r.pas[0] != nil {
r.lastRegenTime = sim.CurrentTime
r.pas[0].Cancel(sim)
r.pas[0] = nil
}
Expand Down
2 changes: 1 addition & 1 deletion sim/deathknight/blood_strike.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var BloodStrikeOHOutcome = core.OutcomeHit
func (deathKnight *DeathKnight) newBloodStrikeSpell(isMH bool) *core.Spell {
weaponBaseDamage := core.BaseDamageFuncMeleeWeapon(core.MainHand, false, 306.0, 0.4, true)
if !isMH {
weaponBaseDamage = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 306.0, 0.4, true)
weaponBaseDamage = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 306.0, 0.4*deathKnight.nervesOfColdSteelBonus(), true)
}

guileOfGorefiend := deathKnight.Talents.GuileOfGorefiend > 0
Expand Down
7 changes: 5 additions & 2 deletions sim/deathknight/bone_shield.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func (deathKnight *DeathKnight) registerBoneShieldSpell() {
OnReset: func(aura *core.Aura, sim *core.Simulation) {
deathKnight.BoneShieldAura.Activate(sim)
deathKnight.BoneShieldAura.UpdateExpires(sim.CurrentTime + time.Minute*4)
deathKnight.BoneShieldAura.SetStacks(sim, 3)
},
OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, spellEffect *core.SpellEffect) {
aura.RemoveStack(sim)
Expand All @@ -32,11 +33,13 @@ func (deathKnight *DeathKnight) registerBoneShieldSpell() {
}
},
OnGain: func(aura *core.Aura, sim *core.Simulation) {
aura.Unit.PseudoStats.DamageDealtMultiplier *= 1.02
deathKnight.ModifyAdditiveDamageModifier(sim, 0.02)

aura.Unit.PseudoStats.DamageTakenMultiplier *= 0.8
},
OnExpire: func(aura *core.Aura, sim *core.Simulation) {
aura.Unit.PseudoStats.DamageDealtMultiplier /= 1.02
deathKnight.ModifyAdditiveDamageModifier(sim, -0.02)

aura.Unit.PseudoStats.DamageTakenMultiplier /= 0.8
},
})
Expand Down
11 changes: 9 additions & 2 deletions sim/deathknight/deathknight.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,19 @@ type DeathKnight struct {
EbonPlagueAura *core.Aura

// Dynamic trackers
RageOfRivendareActive bool
TundraStalkerActive bool
additiveDamageModifier float64

// TODO: Is there a better way?
// Item Auras
SigilOfAwarenessAura *core.Aura
}

func (deathKnight *DeathKnight) ModifyAdditiveDamageModifier(sim *core.Simulation, value float64) {
deathKnight.PseudoStats.DamageDealtMultiplier /= deathKnight.additiveDamageModifier
deathKnight.additiveDamageModifier += value
deathKnight.PseudoStats.DamageDealtMultiplier *= deathKnight.additiveDamageModifier
}

func (deathKnight *DeathKnight) GetCharacter() *core.Character {
return &deathKnight.Character
}
Expand Down Expand Up @@ -219,6 +224,8 @@ func NewDeathKnight(character core.Character, options proto.Player) *DeathKnight
Talents: *deathKnightOptions.Talents,
Options: *deathKnightOptions.Options,
Rotation: *deathKnightOptions.Rotation,

additiveDamageModifier: 1,
}

maxRunicPower := 100.0 + 15.0*float64(deathKnight.Talents.RunicPowerMastery)
Expand Down
12 changes: 10 additions & 2 deletions sim/deathknight/empower_rune_weapon.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,22 @@ func (deathKnight *DeathKnight) registerEmpowerRuneWeaponSpell() {
},
},
ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
blood := deathKnight.CurrentBloodRunes()
frost := deathKnight.CurrentFrostRunes()
unholy := deathKnight.CurrentUnholyRunes()

deathKnight.RegenAllRunes(sim)

deathKnight.GainRuneMetrics(sim, deathKnight.EmpowerRuneWeapon.BloodRuneMetrics(), "blood", blood, deathKnight.CurrentBloodRunes())
deathKnight.GainRuneMetrics(sim, deathKnight.EmpowerRuneWeapon.FrostRuneMetrics(), "frost", frost, deathKnight.CurrentFrostRunes())
deathKnight.GainRuneMetrics(sim, deathKnight.EmpowerRuneWeapon.UnholyRuneMetrics(), "unholy", unholy, deathKnight.CurrentUnholyRunes())

amountOfRunicPower := 25.0
deathKnight.AddRunicPower(sim, amountOfRunicPower, deathKnight.UnbreakableArmor.RunicPowerMetrics())
deathKnight.AddRunicPower(sim, amountOfRunicPower, deathKnight.EmpowerRuneWeapon.RunicPowerMetrics())
},
})
}

func (deathKnight *DeathKnight) CanEmpowerRuneWeapon(sim *core.Simulation) bool {
return deathKnight.EmpowerRuneWeapon.IsReady(sim) && deathKnight.EmpowerRuneWeapon.CD.IsReady(sim)
return deathKnight.EmpowerRuneWeapon.IsReady(sim)
}
2 changes: 1 addition & 1 deletion sim/deathknight/frost_strike.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ var FrostStrikeOHOutcome = core.OutcomeHit
func (deathKnight *DeathKnight) newFrostStrikeHitSpell(isMH bool) *core.Spell {
weaponBaseDamage := core.BaseDamageFuncMeleeWeapon(core.MainHand, false, 138.0, 0.55, true)
if !isMH {
weaponBaseDamage = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 138.0, 0.55, true)
weaponBaseDamage = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 138.0, 0.55*deathKnight.nervesOfColdSteelBonus(), true)
}

effect := core.SpellEffect{
Expand Down
2 changes: 1 addition & 1 deletion sim/deathknight/obliterate.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (deathKnight *DeathKnight) newObliterateHitSpell(isMH bool) *core.Spell {
bonusBaseDamage := core.TernaryFloat64(deathKnight.SigilOfAwarenessAura.IsActive(), 336.0, 0.0)
weaponBaseDamage := core.BaseDamageFuncMeleeWeapon(core.MainHand, false, 467.0+bonusBaseDamage, 0.8, true)
if !isMH {
weaponBaseDamage = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 467.0+bonusBaseDamage, 0.8, true)
weaponBaseDamage = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 467.0+bonusBaseDamage, 0.8*deathKnight.nervesOfColdSteelBonus(), true)
}

return weaponBaseDamage(sim, hitEffect, spell) *
Expand Down
4 changes: 2 additions & 2 deletions sim/deathknight/pestilence.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ func (deathKnight *DeathKnight) registerPestilenceSpell() {
} else {
// Apply diseases on every other target
// TODO: Snapshot the current values of main target disease and roll over to off targets
if deathKnight.TargetHasDisease(FrostFeverAuraLabel, spellEffect.Target) {
if deathKnight.TargetHasDisease(FrostFeverAuraLabel, deathKnight.CurrentTarget) {
deathKnight.FrostFeverDisease[unitHit.Index].Apply(sim)
}
if deathKnight.TargetHasDisease(FrostFeverAuraLabel, spellEffect.Target) {
if deathKnight.TargetHasDisease(FrostFeverAuraLabel, deathKnight.CurrentTarget) {
deathKnight.BloodPlagueDisease[unitHit.Index].Apply(sim)
}
}
Expand Down
2 changes: 1 addition & 1 deletion sim/deathknight/plague_strike.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var PlagueStrikeOHOutcome = core.OutcomeHit
func (deathKnight *DeathKnight) newPlagueStrikeSpell(isMH bool) *core.Spell {
weaponBaseDamage := core.BaseDamageFuncMeleeWeapon(core.MainHand, false, 189.0, 0.5, true)
if !isMH {
weaponBaseDamage = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 189.0, 0.5, true)
weaponBaseDamage = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 189.0, 0.5*deathKnight.nervesOfColdSteelBonus(), true)
}

outbreakBonus := 1.0 + 0.1*float64(deathKnight.Talents.Outbreak)
Expand Down
6 changes: 4 additions & 2 deletions sim/deathknight/presences.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,13 @@ func (deathKnight *DeathKnight) registerBloodPresenceAura() {
Duration: core.NeverExpires,
OnGain: func(aura *core.Aura, sim *core.Simulation) {
aura.Unit.PseudoStats.ThreatMultiplier *= threatMult
aura.Unit.PseudoStats.DamageDealtMultiplier *= 1.0 + damageBonusCoeff

deathKnight.ModifyAdditiveDamageModifier(sim, damageBonusCoeff)
},
OnExpire: func(aura *core.Aura, sim *core.Simulation) {
aura.Unit.PseudoStats.ThreatMultiplier /= threatMult
aura.Unit.PseudoStats.DamageDealtMultiplier /= 1.0 + damageBonusCoeff

deathKnight.ModifyAdditiveDamageModifier(sim, -damageBonusCoeff)
},
})
}
Expand Down
24 changes: 15 additions & 9 deletions sim/deathknight/talents_frost.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,12 @@ func (deathKnight *DeathKnight) ApplyFrostTalents() {
// Pointless to Implement

// Black Ice
deathKnight.PseudoStats.FrostDamageDealtMultiplier += 0.02 * float64(deathKnight.Talents.BlackIce)
deathKnight.PseudoStats.ShadowDamageDealtMultiplier += 0.02 * float64(deathKnight.Talents.BlackIce)
deathKnight.PseudoStats.FrostDamageDealtMultiplier *= 1.0 + 0.02*float64(deathKnight.Talents.BlackIce)
deathKnight.PseudoStats.ShadowDamageDealtMultiplier *= 1.0 + 0.02*float64(deathKnight.Talents.BlackIce)

// Nerves Of Cold Steel
deathKnight.AddStat(stats.MeleeHit, core.MeleeHitRatingPerHitChance*float64(deathKnight.Talents.NervesOfColdSteel))
if deathKnight.Talents.NervesOfColdSteel == 1 {
deathKnight.AutoAttacks.OHEffect.BaseDamage.Calculator = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 0, 1.08, true)
} else if deathKnight.Talents.NervesOfColdSteel == 2 {
deathKnight.AutoAttacks.OHEffect.BaseDamage.Calculator = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 0, 1.16, true)
} else {
deathKnight.AutoAttacks.OHEffect.BaseDamage.Calculator = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 0, 1.25, true)
}
deathKnight.AutoAttacks.OHEffect.BaseDamage.Calculator = core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 0, deathKnight.nervesOfColdSteelBonus(), true)

// Icy Talons
deathKnight.applyIcyTalons()
Expand Down Expand Up @@ -93,6 +87,18 @@ func (deathKnight *DeathKnight) ApplyFrostTalents() {
deathKnight.AddStat(stats.Expertise, 1.0*float64(deathKnight.Talents.TundraStalker)*core.ExpertisePerQuarterPercentReduction)
}

func (deathKnight *DeathKnight) nervesOfColdSteelBonus() float64 {
bonusCoeff := 1.0
if deathKnight.Talents.NervesOfColdSteel == 1 {
bonusCoeff = 1.08
} else if deathKnight.Talents.NervesOfColdSteel == 2 {
bonusCoeff = 1.16
} else {
bonusCoeff = 1.25
}
return bonusCoeff
}

func (deathKnight *DeathKnight) glacielRotBonus(target *core.Unit) float64 {
glacierRotCoeff := 1.0
if deathKnight.Talents.GlacierRot == 1 {
Expand Down
7 changes: 4 additions & 3 deletions sim/deathknight/talents_unholy.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func (deathKnight *DeathKnight) applyBloodCakedBlade() {
target := deathKnight.CurrentTarget

mhBaseDamage := core.BaseDamageFuncMeleeWeapon(core.MainHand, false, 0, 1.0, true)
ohBaseDamage := core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 0, 1.0, true)
ohBaseDamage := core.BaseDamageFuncMeleeWeapon(core.OffHand, false, 0, 1.0*deathKnight.nervesOfColdSteelBonus(), true)

var isMH = false
bloodCakedBladeHit := deathKnight.RegisterSpell(core.SpellConfig{
Expand Down Expand Up @@ -230,16 +230,17 @@ func (deathKnight *DeathKnight) applyDesolation() {
}

actionID := core.ActionID{SpellID: 66803}
bonusDamageCoeff := 0.01 * float64(deathKnight.Talents.Desolation)

deathKnight.DesolationAura = deathKnight.RegisterAura(core.Aura{
ActionID: actionID,
Label: "Desolation",
Duration: time.Second * 20.0,
OnGain: func(aura *core.Aura, sim *core.Simulation) {
aura.Unit.PseudoStats.DamageDealtMultiplier *= 1.0 + 0.01*float64(deathKnight.Talents.Desolation)
deathKnight.ModifyAdditiveDamageModifier(sim, bonusDamageCoeff)
},
OnExpire: func(aura *core.Aura, sim *core.Simulation) {
aura.Unit.PseudoStats.DamageDealtMultiplier /= 1.0 + 0.01*float64(deathKnight.Talents.Desolation)
deathKnight.ModifyAdditiveDamageModifier(sim, -bonusDamageCoeff)
},
})
}
Expand Down

0 comments on commit 4bd2d8c

Please sign in to comment.