Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Item] Add all phase 4 trinkets including item notices #1059

Merged
merged 13 commits into from
Oct 2, 2024
Merged
294 changes: 276 additions & 18 deletions sim/common/cata/other_effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import (
"github.com/wowsims/cata/sim/core/stats"
)

type ItemVersion int32

const (
ItemVersionLFR ItemVersion = 0
ItemVersionNormal ItemVersion = 1 << iota
ItemVersionHeroic
)
hillerstorm marked this conversation as resolved.
Show resolved Hide resolved

func init() {
core.NewItemEffect(63839, func(agent core.Agent) {
character := agent.GetCharacter()
Expand Down Expand Up @@ -297,8 +305,8 @@ func init() {
})
})

for _, hc := range []bool{false, true} {
heroic := hc // Need to copy value because iterator variables are not captured by closure
for _, version := range []ItemVersion{ItemVersionNormal, ItemVersionHeroic} {
heroic := version == ItemVersionHeroic
labelSuffix := core.Ternary(heroic, " (Heroic)", "")

leadenItemID := core.TernaryInt32(heroic, 56347, 55816)
Expand Down Expand Up @@ -731,22 +739,7 @@ func init() {
Duration: time.Second * 30,
MaxStacks: int32(shieldAmount),
OnReset: func(aura *core.Aura, sim *core.Simulation) {
currentShield = 0.0
},
OnSpellHitTaken: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
if currentShield <= 0 || result.Damage <= 0 {
return
}

damageReduced := min(result.Damage, currentShield)
currentShield -= damageReduced
aura.SetStacks(sim, int32(currentShield))

character.GainHealth(sim, damageReduced, shieldSpell.HealthMetrics(result.Target))

if currentShield <= 0 {
shieldSpell.SelfShield().Deactivate(sim)
}
currentShield = 0
},
OnExpire: func(aura *core.Aura, sim *core.Simulation) {
currentShield = 0
Expand All @@ -762,6 +755,24 @@ func init() {
},
})

character.AddDynamicDamageTakenModifier(func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
shield := shieldSpell.SelfShield()
if shield.IsActive() && result.Damage > 0 {
absorbedDamage := min(currentShield, result.Damage)
result.Damage -= absorbedDamage
currentShield -= absorbedDamage
shield.Aura.SetStacks(sim, int32(currentShield))

if sim.Log != nil {
character.Log(sim, "Loom of Fate absorbed %.1f damage", absorbedDamage)
}

if currentShield <= 0 {
shield.Deactivate(sim)
}
}
})
hillerstorm marked this conversation as resolved.
Show resolved Hide resolved

core.MakePermanent(character.GetOrRegisterAura(core.Aura{
Label: "Spidersilk Spindle",
Icd: &core.Cooldown{
Expand Down Expand Up @@ -825,6 +836,253 @@ func init() {
})
})
}

for version, _ := range []ItemVersion{ItemVersionLFR, ItemVersionNormal, ItemVersionHeroic} {
hillerstorm marked this conversation as resolved.
Show resolved Hide resolved
labelSuffix := []string{" (LFR)", "", " (Heroic)"}[version]

vialItemID := []int32{77979, 77207, 77999}[version]
core.NewItemEffect(vialItemID, func(agent core.Agent) {
character := agent.GetCharacter()

actionID := core.ActionID{SpellID: []int32{109721, 107994, 109724}[version]}
minDmg := []float64{3568, 4028, 4546}[version]
maxDmg := []float64{5353, 6042, 6819}[version]
hillerstorm marked this conversation as resolved.
Show resolved Hide resolved

lightningStrike := character.RegisterSpell(core.SpellConfig{
ActionID: actionID,
SpellSchool: core.SpellSchoolPhysical,
ProcMask: core.ProcMaskEmpty,
Flags: core.SpellFlagPassiveSpell,

Cast: core.CastConfig{
DefaultCast: core.Cast{
NonEmpty: true,
},
},

DamageMultiplier: 1,
CritMultiplier: character.DefaultMeleeCritMultiplier(),
ThreatMultiplier: 1,

ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
spell.CalcAndDealDamage(sim, target, sim.Roll(minDmg, maxDmg), spell.OutcomeMeleeSpecialCritOnly)
},
})

core.MakeProcTriggerAura(&character.Unit, core.ProcTrigger{
Name: "Vial of Shadows Trigger" + labelSuffix,
ActionID: core.ActionID{ItemID: vialItemID},
Callback: core.CallbackOnSpellHitDealt,
ProcMask: core.ProcMaskMeleeOrRanged | core.ProcMaskProc,
Outcome: core.OutcomeLanded,
Harmful: true,
ProcChance: 0.45,
ICD: time.Second * 9,
Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
lightningStrike.Cast(sim, result.Target)
},
})
})

fetishItemID := []int32{77982, 77210, 78002}[version]
core.NewItemEffect(fetishItemID, func(agent core.Agent) {
hillerstorm marked this conversation as resolved.
Show resolved Hide resolved
character := agent.GetCharacter()
numTargets := character.Env.GetNumTargets()

actionID := core.ActionID{SpellID: []int32{109753, 107998, 109755}[version]}
minDmg := []float64{8029, 9063, 10230}[version]
maxDmg := []float64{12044, 13594, 15345}[version]
apMod := []float64{0.598, 0.675, 0.762}[version]

whirlingMaw := character.RegisterSpell(core.SpellConfig{
ActionID: actionID,
SpellSchool: core.SpellSchoolPhysical,
ProcMask: core.ProcMaskEmpty,
Flags: core.SpellFlagPassiveSpell,

Cast: core.CastConfig{
DefaultCast: core.Cast{
NonEmpty: true,
},
},

DamageMultiplier: 1,
CritMultiplier: character.DefaultMeleeCritMultiplier(),
ThreatMultiplier: 1,

ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
results := make([]*core.SpellResult, numTargets)

for idx := int32(0); idx < numTargets; idx++ {
baseDamage := sim.Roll(minDmg, maxDmg) +
apMod*spell.MeleeAttackPower()
results[idx] = spell.CalcDamage(sim, sim.Environment.GetTargetUnit(idx), baseDamage, spell.OutcomeMeleeSpecialCritOnly)
}

for idx := int32(0); idx < numTargets; idx++ {
spell.DealDamage(sim, results[idx])
}
},
})

core.MakeProcTriggerAura(&character.Unit, core.ProcTrigger{
Name: "Bone-Link Fetish Trigger" + labelSuffix,
ActionID: core.ActionID{ItemID: fetishItemID},
Callback: core.CallbackOnSpellHitDealt,
ProcMask: core.ProcMaskMeleeOrRanged | core.ProcMaskProc,
Outcome: core.OutcomeLanded,
Harmful: true,
ProcChance: 0.15,
ICD: time.Second * 27,
Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
whirlingMaw.Cast(sim, result.Target)
},
})
})

cunningItemID := []int32{77980, 77208, 78000}[version]
core.NewItemEffect(cunningItemID, func(agent core.Agent) {
character := agent.GetCharacter()
numTargets := character.Env.GetNumTargets()

actionID := core.ActionID{SpellID: []int32{109798, 108005, 109800}[version]}
minDmg := []float64{2498, 2820, 3183}[version]
maxDmg := []float64{3747, 4230, 4774}[version]
spMod := []float64{0.277, 0.313, 0.353}[version]

shadowboltVolley := character.RegisterSpell(core.SpellConfig{
ActionID: actionID,
SpellSchool: core.SpellSchoolShadow,
ProcMask: core.ProcMaskEmpty,
Flags: core.SpellFlagPassiveSpell,

MissileSpeed: 20,

Cast: core.CastConfig{
DefaultCast: core.Cast{
NonEmpty: true,
},
},

DamageMultiplier: 1,
CritMultiplier: character.DefaultSpellCritMultiplier(),
ThreatMultiplier: 1,

BonusCoefficient: spMod,

ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
results := make([]*core.SpellResult, numTargets)

for idx := int32(0); idx < numTargets; idx++ {
results[idx] = spell.CalcDamage(sim, sim.Environment.GetTargetUnit(idx), sim.Roll(minDmg, maxDmg), spell.OutcomeMagicCrit)
}

spell.WaitTravelTime(sim, func(sim *core.Simulation) {
for idx := int32(0); idx < numTargets; idx++ {
spell.DealDamage(sim, results[idx])
}
})
},
})

core.MakeProcTriggerAura(&character.Unit, core.ProcTrigger{
Name: "Cunning of the Cruel Trigger" + labelSuffix,
ActionID: core.ActionID{ItemID: cunningItemID},
Callback: core.CallbackOnSpellHitDealt | core.CallbackOnPeriodicDamageDealt,
ProcMask: core.ProcMaskSpellDamage | core.ProcMaskProc,
Outcome: core.OutcomeLanded,
Harmful: true,
ProcChance: 0.45,
ICD: time.Second * 9,
Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
shadowboltVolley.Cast(sim, result.Target)
},
})
})

prideItemID := []int32{77983, 77211, 78003}[version]
core.NewItemEffect(prideItemID, func(agent core.Agent) {
character := agent.GetCharacter()

absorbModifier := []float64{0.43, 0.50, 0.56}[version]

currentShield := 0.0
var shieldSpell *core.Spell
shieldSpell = character.GetOrRegisterSpell(core.SpellConfig{
ActionID: core.ActionID{SpellID: 108008},
ProcMask: core.ProcMaskSpellHealing,
SpellSchool: core.SpellSchoolHoly,
Flags: core.SpellFlagHelpful |
core.SpellFlagPassiveSpell |
core.SpellFlagIgnoreModifiers |
core.SpellFlagNoSpellMods,

DamageMultiplier: 1,
ThreatMultiplier: 1,

Shield: core.ShieldConfig{
SelfOnly: true,
Aura: core.Aura{
Label: "Indomitable",
Duration: time.Second * 6,
OnReset: func(aura *core.Aura, sim *core.Simulation) {
currentShield = 0
},
OnExpire: func(aura *core.Aura, sim *core.Simulation) {
currentShield = 0
},
},
},

ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
shield := shieldSpell.SelfShield()
shield.Apply(sim, currentShield)
shield.Aura.MaxStacks = int32(currentShield)
shield.Aura.SetStacks(sim, shield.Aura.MaxStacks)
},
})

character.AddDynamicDamageTakenModifier(func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
shield := shieldSpell.SelfShield()
if shield.IsActive() && result.Damage > 0 {
absorbedDamage := min(currentShield, result.Damage)
result.Damage -= absorbedDamage
currentShield -= absorbedDamage
shield.Aura.SetStacks(sim, int32(currentShield))

if sim.Log != nil {
character.Log(sim, "Indomitable Pride absorbed %.1f damage", absorbedDamage)
}

if currentShield <= 0 {
shield.Deactivate(sim)
}
}
})

icd := core.Cooldown{
Timer: character.NewTimer(),
Duration: time.Minute,
}

core.MakeProcTriggerAura(&character.Unit, core.ProcTrigger{
Name: "Indomitable Pride Trigger" + labelSuffix,
ActionID: core.ActionID{ItemID: prideItemID},
Callback: core.CallbackOnSpellHitTaken,
Outcome: core.OutcomeLanded,
Harmful: true,
ProcChance: 1,
Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
preHitHp := character.CurrentHealth() + result.Damage
if icd.IsReady(sim) && character.CurrentHealthPercent() < 0.50 && preHitHp >= 0.50 {
icd.Use(sim)
currentShield = result.Damage * absorbModifier
shieldSpell.Cast(sim, result.Target)
}
},
})
})
}
}

// Takes in the SpellResult for the triggering spell, and returns the damage per
Expand Down
29 changes: 22 additions & 7 deletions sim/common/cata/stat_bonus_cds.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ func init() {
shared.NewStrengthActive(62469, 1605, time.Second*20, time.Minute*2) // Impatience of Youth (Horde)
shared.NewStrengthActive(61034, 1605, time.Second*20, time.Minute*2) // Vicious Gladiator's Badge of Victory
shared.NewStrengthActive(69002, 1277, time.Second*15, time.Minute) // Essence of the Eternal Flame
shared.NewStrengthActive(77987, 2029, time.Second*15, time.Second*90) // Rotting Skull 384 - Not available to players
shared.NewStrengthActive(77116, 2290, time.Second*15, time.Second*90) // Rotting Skull 397 - Valor Points
shared.NewStrengthActive(78007, 2585, time.Second*15, time.Second*90) // Rotting Skull 410 - Not available to players

// AGILITY
shared.NewAgilityActive(63840, 1095, time.Second*15, time.Second*90) // Juju of Nimbleness
Expand All @@ -42,6 +45,9 @@ func init() {
shared.NewAgilityActive(68709, 1605, time.Second*20, time.Minute*2) // Unsolvable Riddle (No Faction)
shared.NewAgilityActive(61033, 1605, time.Second*20, time.Minute*2) // Vicious Gladiator's Badge of Conquest
shared.NewAgilityActive(69001, 1277, time.Second*15, time.Minute) // Ancient Petrified Seed
shared.NewAgilityActive(77984, 2029, time.Second*15, time.Second*90) // Kiroptyric Sigil 384 - Not available to players
shared.NewAgilityActive(77113, 2290, time.Second*15, time.Second*90) // Kiroptyric Sigil 397 - Valor Points
shared.NewAgilityActive(78004, 2585, time.Second*15, time.Second*90) // Kiroptyric Sigil 410 - Not available to players

// SPIRIT
shared.NewSpiritActive(67101, 555, time.Second*20, time.Minute*2) // Unquenchable Flame
Expand All @@ -55,15 +61,24 @@ func init() {
shared.NewDodgeActive(65109, 1812, time.Second*20, time.Minute*2) // Vial of Stolen Memories (Heroic)
shared.NewDodgeActive(70143, 1700, time.Second*20, time.Minute*2) // Moonwell Phial
shared.NewDodgeActive(232015, 1520, time.Second*20, time.Minute*2) // Brawler's Trophy
shared.NewDodgeActive(77988, 2029, time.Second*15, time.Second*90) // Fire of the Deep 384 - Not available to players
shared.NewDodgeActive(77117, 2290, time.Second*15, time.Second*90) // Fire of the Deep 397 - Valor Points
shared.NewDodgeActive(78008, 2585, time.Second*15, time.Second*90) // Fire of the Deep 410 - Not available to players

// SpellPower
shared.NewSpellPowerActive(61429, 970, time.Second*15, time.Second*90) // Insignia of the Earthen Lord
shared.NewSpellPowerActive(55256, 765, time.Second*20, time.Minute*2) // Sea Star
shared.NewSpellPowerActive(56290, 1425, time.Second*20, time.Minute*2) // Sea Star (Heroic)
shared.NewSpellPowerActive(52353, 1425, time.Second*20, time.Minute*2) // Figurine - Jeweled Serpent
shared.NewSpellPowerActive(64688, 1520, time.Second*20, time.Minute*2) // Bloodthirsty Gladiator's Badge of Dominance
shared.NewSpellPowerActive(58183, 1926, time.Second*20, time.Minute*2) // Soul Casket
shared.NewSpellPowerActive(61035, 1605, time.Second*20, time.Minute*2) // Vicious Gladiator's Badge of Dominance
shared.NewSpellPowerActive(61429, 970, time.Second*15, time.Second*90) // Insignia of the Earthen Lord
shared.NewSpellPowerActive(55256, 765, time.Second*20, time.Minute*2) // Sea Star
shared.NewSpellPowerActive(56290, 1425, time.Second*20, time.Minute*2) // Sea Star (Heroic)
shared.NewSpellPowerActive(52353, 1425, time.Second*20, time.Minute*2) // Figurine - Jeweled Serpent
shared.NewSpellPowerActive(64688, 1520, time.Second*20, time.Minute*2) // Bloodthirsty Gladiator's Badge of Dominance
shared.NewSpellPowerActive(58183, 1926, time.Second*20, time.Minute*2) // Soul Casket
shared.NewSpellPowerActive(61035, 1605, time.Second*20, time.Minute*2) // Vicious Gladiator's Badge of Dominance
shared.NewSpellPowerActive(77985, 2029, time.Second*15, time.Second*90) // Bottled Wishes 384 - Not available to players
shared.NewSpellPowerActive(77114, 2290, time.Second*15, time.Second*90) // Bottled Wishes 397 - Valor Points
shared.NewSpellPowerActive(78005, 2585, time.Second*15, time.Second*90) // Bottled Wishes 410 - Not available to players
shared.NewSpellPowerActive(77986, 2029, time.Second*15, time.Second*90) // Reflection of the Light 384 - Not available to players
shared.NewSpellPowerActive(77115, 2290, time.Second*15, time.Second*90) // Reflection of the Light 397 - Valor Points
shared.NewSpellPowerActive(78006, 2585, time.Second*15, time.Second*90) // Reflection of the Light 410 - Not available to players

// HEALTH
shared.NewHealthActive(61433, 6985, time.Second*15, time.Minute*3) // Insignia of Diplomacy
Expand Down
Loading
Loading