Skip to content
Merged
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
45 changes: 19 additions & 26 deletions sim/common/item_effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,18 +233,27 @@ func init() {
// Chance on hit: Increases Attack Power against Undead by 200 for 10 sec.
// 1 PPM from Armaments Discord
itemhelpers.CreateWeaponProcAura(ArgentAvenger, "Argent Avenger", 1.0, func(character *core.Character) *core.Aura {
matchingTargets := core.FilterSlice(
character.Env.Encounter.TargetUnits,
func(unit *core.Unit) bool { return unit.MobType == proto.MobType_MobTypeUndead },
)

return character.GetOrRegisterAura(core.Aura{
ActionID: core.ActionID{SpellID: 17352},
Label: "Argent Avenger",
Duration: time.Second * 10,
OnGain: func(aura *core.Aura, sim *core.Simulation) {
if character.CurrentTarget.MobType == proto.MobType_MobTypeUndead {
character.PseudoStats.MobTypeAttackPower += 200
for _, target := range matchingTargets {
for _, at := range character.AttackTables[target.UnitIndex] {
at.BonusAttackPowerTaken += 200
}
}
},
OnExpire: func(aura *core.Aura, sim *core.Simulation) {
if character.CurrentTarget.MobType == proto.MobType_MobTypeUndead {
character.PseudoStats.MobTypeAttackPower -= 200
for _, target := range matchingTargets {
for _, at := range character.AttackTables[target.UnitIndex] {
at.BonusAttackPowerTaken -= 200
}
}
},
})
Expand Down Expand Up @@ -893,13 +902,8 @@ func init() {
})

// https://www.wowhead.com/classic/item=10696/enchanted-azsharite-felbane-sword
core.NewItemEffect(EnchantedAzshariteSword, func(agent core.Agent) {
character := agent.GetCharacter()

if character.CurrentTarget.MobType == proto.MobType_MobTypeElemental {
character.PseudoStats.MobTypeAttackPower += 33
}
})
// Equip: +33 Attack Power when fighting Demons.
core.NewMobTypeAttackPowerEffect(EnchantedAzshariteSword, []proto.MobType{proto.MobType_MobTypeDemon}, 33)

// https://www.wowhead.com/classic/item=18202/eskhandars-left-claw
// Chance on hit: Slows enemy's movement by 60% and causes them to bleed for 150 damage over 30 sec.
Expand Down Expand Up @@ -998,13 +1002,8 @@ func init() {
})

// https://www.wowhead.com/classic/item=18310/fiendish-machete
core.NewItemEffect(FiendishMachete, func(agent core.Agent) {
character := agent.GetCharacter()

if character.CurrentTarget.MobType == proto.MobType_MobTypeElemental {
character.PseudoStats.MobTypeAttackPower += 36
}
})
// Equip: +36 Attack Power when fighting Elementals.
core.NewMobTypeAttackPowerEffect(FiendishMachete, []proto.MobType{proto.MobType_MobTypeElemental}, 36)

// https://www.wowhead.com/classic/item=870/fiery-war-axe
itemhelpers.CreateWeaponProcSpell(FieryWarAxe, "Fiery War Axe", 1.0, func(character *core.Character) *core.Spell {
Expand Down Expand Up @@ -1803,13 +1802,7 @@ func init() {
itemhelpers.CreateWeaponCoHProcDamage(PendulumOfDoom, "Pendulum of Doom", 0.5, 10373, core.SpellSchoolPhysical, 250, 100, 0, core.DefenseTypeMelee)

// https://www.wowhead.com/classic/item=12709/pips-skinner
core.NewItemEffect(PipsSkinner, func(agent core.Agent) {
character := agent.GetCharacter()

if character.CurrentTarget.MobType == proto.MobType_MobTypeBeast {
character.PseudoStats.MobTypeAttackPower += 45
}
})
core.NewMobTypeAttackPowerEffect(PipsSkinner, []proto.MobType{proto.MobType_MobTypeBeast}, 45)

// https://www.wowhead.com/classic/item=18816/perditions-blade
// Chance on hit: Blasts a target for 40 to 56 Fire damage.
Expand Down Expand Up @@ -1877,7 +1870,7 @@ func init() {
BonusCoefficient: 1,

ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
damage := 5.0 + spell.Unit.MHNormalizedWeaponDamage(sim, spell.MeleeAttackPower())
damage := 5.0 + spell.Unit.MHNormalizedWeaponDamage(sim, spell.MeleeAttackPower(target))
for _, aoeTarget := range sim.Encounter.TargetUnits {
spell.CalcAndDealDamage(sim, aoeTarget, damage, spell.OutcomeMeleeSpecialHitAndCrit)
}
Expand Down
13 changes: 11 additions & 2 deletions sim/common/item_sets/item_sets_pve.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,17 @@ var ItemSetUndeadSlayersArmor = core.NewItemSet(core.ItemSet{
// Increases your damage against undead by 2%.
3: func(agent core.Agent) {
character := agent.GetCharacter()
if character.CurrentTarget.MobType == proto.MobType_MobTypeUndead {
character.PseudoStats.DamageDealtMultiplier *= 1.02

delta := 1.02
for _, target := range character.Env.Encounter.TargetUnits {
if target.MobType != proto.MobType_MobTypeUndead {
continue
}

for _, at := range character.AttackTables[target.UnitIndex] {
at.DamageDealtMultiplier *= delta
at.CritMultiplier *= delta
}
}
},
},
Expand Down
4 changes: 2 additions & 2 deletions sim/core/attack.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ func (unit *Unit) EnableAutoAttacks(agent Agent, options AutoAttackOptions) {

autoInProgress := *spell

baseDamage := autoInProgress.Unit.MHWeaponDamage(sim, autoInProgress.MeleeAttackPower())
baseDamage := autoInProgress.Unit.MHWeaponDamage(sim, autoInProgress.MeleeAttackPower(target))
result := autoInProgress.CalcDamage(sim, target, baseDamage, autoInProgress.OutcomeMeleeWhite)

StartDelayedAction(sim, DelayedActionOptions{
Expand Down Expand Up @@ -496,7 +496,7 @@ func (unit *Unit) EnableAutoAttacks(agent Agent, options AutoAttackOptions) {
ApplyEffects: func(sim *Simulation, target *Unit, spell *Spell) {

autoInProgress := *spell
baseDamage := autoInProgress.Unit.OHWeaponDamage(sim, autoInProgress.MeleeAttackPower())
baseDamage := autoInProgress.Unit.OHWeaponDamage(sim, autoInProgress.MeleeAttackPower(target))
result := autoInProgress.CalcDamage(sim, target, baseDamage, autoInProgress.OutcomeMeleeWhite)

StartDelayedAction(sim, DelayedActionOptions{
Expand Down
20 changes: 16 additions & 4 deletions sim/core/consumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,14 @@ func addImbueStats(character *Character, imbue proto.WeaponImbue, isMh bool, sha
stats.SpellCrit: 1 * SpellCritRatingPerCritChance,
})
case proto.WeaponImbue_BlessedWizardOil:
if character.CurrentTarget.MobType == proto.MobType_MobTypeUndead {
character.PseudoStats.MobTypeSpellPower += 60
for _, target := range character.Env.Encounter.TargetUnits {
if target.MobType != proto.MobType_MobTypeUndead {
continue
}

for _, at := range character.AttackTables[target.UnitIndex] {
at.BonusSpellDamageTaken += 60
}
}

// Mana Oils
Expand Down Expand Up @@ -152,8 +158,14 @@ func addImbueStats(character *Character, imbue proto.WeaponImbue, isMh bool, sha
character.AddBonusRangedCritRating(-2.0)
}
case proto.WeaponImbue_ConsecratedSharpeningStone:
if character.CurrentTarget.MobType == proto.MobType_MobTypeUndead {
character.PseudoStats.MobTypeAttackPower += 100
for _, target := range character.Env.Encounter.TargetUnits {
if target.MobType != proto.MobType_MobTypeUndead {
continue
}

for _, at := range character.AttackTables[target.UnitIndex] {
at.BonusAttackPowerTaken += 100
}
}

// Weightstones
Expand Down
16 changes: 12 additions & 4 deletions sim/core/debuffs.go
Original file line number Diff line number Diff line change
Expand Up @@ -806,10 +806,14 @@ func HuntersMarkAura(target *Unit, points int32) *Aura {
aura.NewExclusiveEffect("HuntersMark", true, ExclusiveEffect{
Priority: bonus,
OnGain: func(ee *ExclusiveEffect, sim *Simulation) {
ee.Aura.Unit.PseudoStats.BonusRangedAttackPowerTaken += bonus
for _, unit := range sim.Environment.Raid.AllUnits {
unit.AttackTables[target.UnitIndex][proto.CastType_CastTypeRanged].BonusAttackPowerTaken += bonus
}
},
OnExpire: func(ee *ExclusiveEffect, sim *Simulation) {
ee.Aura.Unit.PseudoStats.BonusRangedAttackPowerTaken -= bonus
for _, unit := range sim.Environment.Raid.AllUnits {
unit.AttackTables[target.UnitIndex][proto.CastType_CastTypeRanged].BonusAttackPowerTaken -= bonus
}
},
})

Expand All @@ -824,10 +828,14 @@ func ExposeWeaknessAura(target *Unit) *Aura {
Label: "Expose Weakness",
Duration: time.Second * 7,
OnGain: func(aura *Aura, sim *Simulation) {
target.PseudoStats.BonusRangedAttackPowerTaken += bonus
for _, unit := range sim.Environment.Raid.AllUnits {
unit.AttackTables[target.UnitIndex][proto.CastType_CastTypeRanged].BonusAttackPowerTaken += bonus
}
},
OnExpire: func(aura *Aura, sim *Simulation) {
target.PseudoStats.BonusRangedAttackPowerTaken -= bonus
for _, unit := range sim.Environment.Raid.AllUnits {
unit.AttackTables[target.UnitIndex][proto.CastType_CastTypeRanged].BonusAttackPowerTaken -= bonus
}
},
})

Expand Down
61 changes: 53 additions & 8 deletions sim/core/item_effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,20 +150,65 @@ func NewSimpleStatDefensiveTrinketEffect(itemID int32, bonus stats.Stats, durati
}, nil)
}

// TODO: These should ideally be done at the AttackTable level
// Apply a +X Attack Power when fighting Mob Type effect
// These effects seem to always apply to both melee and ranged attack power in-game
// Apply Aura: Mod Melee Attack Power vs Creature (Mob Type)
// Apply Aura: Mod Ranged Attack Power vs Creature (Mob Type)
func NewMobTypeAttackPowerEffect(itemID int32, mobTypes []proto.MobType, bonus float64) {
NewItemEffect(itemID, func(agent Agent) {
character := agent.GetCharacter()
if slices.Contains(mobTypes, character.CurrentTarget.MobType) {
character.PseudoStats.MobTypeAttackPower += bonus
}

matchingTargets := FilterSlice(
character.Env.Encounter.TargetUnits,
func(unit *Unit) bool { return slices.Contains(mobTypes, unit.MobType) },
)

MakePermanent(character.GetOrRegisterAura(Aura{
Label: fmt.Sprintf("Mob type Attack Power Bonus - %s (%d)", mobTypes, itemID),
OnGain: func(aura *Aura, sim *Simulation) {
for _, target := range matchingTargets {
for _, at := range character.AttackTables[target.UnitIndex] {
at.BonusAttackPowerTaken += bonus
}
}
},
OnExpire: func(aura *Aura, sim *Simulation) {
for _, target := range matchingTargets {
for _, at := range character.AttackTables[target.UnitIndex] {
at.BonusAttackPowerTaken -= bonus
}
}
},
}))
})
}

// Apply a +X Spell Damage when fighting Mob Type effect
func NewMobTypeSpellPowerEffect(itemID int32, mobTypes []proto.MobType, bonus float64) {
NewItemEffect(itemID, func(agent Agent) {
character := agent.GetCharacter()
if slices.Contains(mobTypes, character.CurrentTarget.MobType) {
character.PseudoStats.MobTypeSpellPower += bonus
}

matchingTargets := FilterSlice(
character.Env.Encounter.TargetUnits,
func(unit *Unit) bool { return slices.Contains(mobTypes, unit.MobType) },
)

MakePermanent(character.GetOrRegisterAura(Aura{
Label: fmt.Sprintf("Mob type Spell Damage Bonus - %s (%d)", mobTypes, itemID),
OnGain: func(aura *Aura, sim *Simulation) {
for _, target := range matchingTargets {
for _, at := range character.AttackTables[target.UnitIndex] {
at.BonusSpellDamageTaken += bonus
}
}
},
OnExpire: func(aura *Aura, sim *Simulation) {
for _, target := range matchingTargets {
for _, at := range character.AttackTables[target.UnitIndex] {
at.BonusSpellDamageTaken -= bonus
}
}
},
}))
})
}
}
36 changes: 22 additions & 14 deletions sim/core/spell_result.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,17 @@ func (spell *Spell) ThreatFromDamage(outcome HitOutcome, damage float64) float64
}
}

func (spell *Spell) MeleeAttackPower() float64 {
return spell.Unit.stats[stats.AttackPower] + spell.Unit.PseudoStats.MobTypeAttackPower
func (spell *Spell) MeleeAttackPower(target *Unit) float64 {
return spell.Unit.stats[stats.AttackPower] +
spell.Unit.AttackTables[target.Index][spell.CastType].BonusAttackPowerTaken
}

func (spell *Spell) RangedAttackPower(target *Unit, ignoreTargetModifiers bool) float64 {
return TernaryFloat64(ignoreTargetModifiers,
spell.Unit.stats[stats.RangedAttackPower],
spell.Unit.stats[stats.RangedAttackPower]+
spell.Unit.PseudoStats.MobTypeAttackPower+
target.PseudoStats.BonusRangedAttackPowerTaken)
spell.Unit.AttackTables[target.Index][spell.CastType].BonusAttackPowerTaken,
)
}

func (spell *Spell) PhysicalHitChance(attackTable *AttackTable) float64 {
Expand All @@ -128,8 +129,14 @@ func (spell *Spell) PhysicalCritCheck(sim *Simulation, attackTable *AttackTable)
return sim.RandomFloat("Physical Crit Roll") < spell.PhysicalCritChance(attackTable)
}

// The combined bonus damage (aka spell power) for this spell's school(s).
func (spell *Spell) GetBonusDamage() float64 {
// The combined bonus damage (aka spell power) for this spell's school(s) **including** mob type specific spell power.
func (spell *Spell) GetBonusDamage(target *Unit) float64 {
return spell.GetSchoolDamage() +
spell.Unit.AttackTables[target.Index][spell.CastType].BonusSpellDamageTaken
}

// The combined bonus damage (aka spell power) for this spell's school(s) **excluding** mob type specific spell power.
func (spell *Spell) GetSchoolDamage() float64 {
var schoolBonusDamage float64

switch spell.SchoolIndex {
Expand Down Expand Up @@ -178,8 +185,7 @@ func (spell *Spell) GetBonusDamage() float64 {
return spell.BonusDamage +
schoolBonusDamage +
spell.Unit.GetStat(stats.SpellPower) +
spell.Unit.GetStat(stats.SpellDamage) +
spell.Unit.PseudoStats.MobTypeSpellPower
spell.Unit.GetStat(stats.SpellDamage)
}

func (spell *Spell) SpellHitChance(target *Unit) float64 {
Expand Down Expand Up @@ -310,14 +316,16 @@ func (spell *Spell) calcDamageInternal(sim *Simulation, target *Unit, baseDamage
spell.ApplyPostOutcomeDamageModifiers(sim, result)
afterPostOutcome := result.Damage

bonusDamage := spell.GetBonusDamage(target)

spell.Unit.Log(
sim,
"%s %s [DEBUG] MAP+Bonus: %0.01f, RAP+Bonus: %0.01f, SP+Bonus: %0.01f, BaseDamage:%0.01f, AfterAttackerMods:%0.01f, AfterResistances:%0.01f, AfterTargetMods:%0.01f, AfterOutcome:%0.01f, AfterPostOutcome:%0.01f",
target.LogLabel(),
spell.ActionID,
spell.Unit.GetStat(stats.AttackPower)+TernaryFloat64(spell.SchoolIndex == stats.SchoolIndexPhysical, spell.GetBonusDamage(), 0),
spell.Unit.GetStat(stats.RangedAttackPower)+TernaryFloat64(spell.SchoolIndex == stats.SchoolIndexPhysical, spell.GetBonusDamage(), 0),
spell.GetBonusDamage(),
spell.Unit.GetStat(stats.AttackPower)+TernaryFloat64(spell.SchoolIndex == stats.SchoolIndexPhysical, bonusDamage, 0),
spell.Unit.GetStat(stats.RangedAttackPower)+TernaryFloat64(spell.SchoolIndex == stats.SchoolIndexPhysical, bonusDamage, 0),
bonusDamage,
baseDamage,
afterAttackMods,
afterResistances,
Expand All @@ -337,7 +345,7 @@ func (spell *Spell) CalcDamage(sim *Simulation, target *Unit, baseDamage float64
baseDamage *= spell.BaseDamageMultiplierAdditive

if spell.BonusCoefficient > 0 {
baseDamage += spell.BonusCoefficient * spell.GetBonusDamage()
baseDamage += spell.BonusCoefficient * spell.GetBonusDamage(target)
}

return spell.calcDamageInternal(sim, target, baseDamage, attackerMultiplier, false, outcomeApplier)
Expand All @@ -350,7 +358,7 @@ func (spell *Spell) CalcPeriodicDamage(sim *Simulation, target *Unit, baseDamage
attackerMultiplier *= dot.DamageMultiplier

if dot.BonusCoefficient > 0 {
baseDamage += dot.BonusCoefficient * spell.GetBonusDamage()
baseDamage += dot.BonusCoefficient * spell.GetBonusDamage(target)
}

return spell.calcDamageInternal(sim, target, baseDamage, attackerMultiplier, true, outcomeApplier)
Expand All @@ -364,7 +372,7 @@ func (dot *Dot) Snapshot(target *Unit, baseDamage float64, isRollover bool) {
if !isRollover {
dot.SnapshotBaseDamage = baseDamage * dot.Spell.BaseDamageMultiplierAdditive
if dot.BonusCoefficient > 0 {
dot.SnapshotBaseDamage += dot.BonusCoefficient * dot.Spell.GetBonusDamage()
dot.SnapshotBaseDamage += dot.BonusCoefficient * dot.Spell.GetBonusDamage(target)
}

attackTable := dot.Spell.Unit.AttackTables[target.UnitIndex][dot.Spell.CastType]
Expand Down
Loading
Loading