Skip to content

Commit

Permalink
Merge pull request #126 from wowsims/new_bombs
Browse files Browse the repository at this point in the history
Refactor Explosives to SoD and add new ones from P2
  • Loading branch information
rosenrusinov authored Feb 7, 2024
2 parents f9d0b0f + caf747a commit 40b9bf8
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 238 deletions.
2 changes: 2 additions & 0 deletions proto/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ enum Explosive {
ExplosiveSolidDynamite = 1;
ExplosiveDenseDynamite = 2;
ExplosiveThoriumGrenade = 3;
ExplosiveEzThroRadiationBomb = 4;
ExplosiveHighYieldRadiationBomb = 5;
}

enum Potions {
Expand Down
2 changes: 1 addition & 1 deletion sim/core/apl_actions_casting.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (rot *APLRotation) newActionCastSpell(config *proto.APLActionCastSpell) APL
}
}
func (action *APLActionCastSpell) IsReady(sim *Simulation) bool {
return action.spell.CanCast(sim, action.target.Get()) && (!action.spell.Flags.Matches(SpellFlagMCD) || action.spell.Unit.GCD.IsReady(sim))
return action.spell.CanCast(sim, action.target.Get()) && (!action.spell.Flags.Matches(SpellFlagMCD) || action.spell.Unit.GCD.IsReady(sim) || action.spell.DefaultCast.GCD == 0)
}
func (action *APLActionCastSpell) Execute(sim *Simulation) {
action.spell.Cast(sim, action.target.Get())
Expand Down
4 changes: 2 additions & 2 deletions sim/core/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc {
}

if effectiveTime := spell.CurCast.EffectiveTime(); effectiveTime != 0 {
if spell.Flags.Matches(SpellFlagHunterRanged) {
effectiveTime = min(effectiveTime, spell.Unit.GCD.TimeToReady(sim))
if spell.Flags.Matches(SpellFlagCastTimeNoGCD) {
effectiveTime = max(effectiveTime, spell.Unit.GCD.TimeToReady(sim))
}
spell.SpellMetrics[target.UnitIndex].TotalCastTime += effectiveTime
spell.Unit.SetGCDTimer(sim, sim.CurrentTime+effectiveTime)
Expand Down
118 changes: 108 additions & 10 deletions sim/core/consumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func applyConsumeEffects(agent Agent, partyBuffs *proto.PartyBuffs) {
})
}

if consumes.EnchantedSigil != proto.EnchantedSigil_UnknownSigil {
if character.HasProfession(proto.Profession_Enchanting) && consumes.EnchantedSigil != proto.EnchantedSigil_UnknownSigil {
switch consumes.EnchantedSigil {
case proto.EnchantedSigil_InnovationSigil:
character.AddStats(stats.Stats{
Expand Down Expand Up @@ -240,20 +240,19 @@ var SapperActionID = ActionID{ItemID: 10646}
var SolidDynamiteActionID = ActionID{ItemID: 10507}
var DenseDynamiteActionID = ActionID{ItemID: 18641}
var ThoriumGrenadeActionID = ActionID{ItemID: 15993}
var EzThroRadiationBombActionID = ActionID{ItemID: 215168}
var HighYieldRadiationBombActionID = ActionID{ItemID: 215127}

func registerExplosivesCD(agent Agent, consumes *proto.Consumes) {
character := agent.GetCharacter()
hasFiller := consumes.FillerExplosive != proto.Explosive_ExplosiveUnknown

if !character.HasProfession(proto.Profession_Engineering) {
return
}
if !consumes.Sapper && !hasFiller {
return
}
sharedTimer := character.NewTimer()

if consumes.Sapper {
if consumes.Sapper && character.HasProfession(proto.Profession_Engineering) {
character.AddMajorCooldown(MajorCooldown{
Spell: character.newSapperSpell(sharedTimer),
Type: CooldownTypeDPS | CooldownTypeExplosive,
Expand All @@ -262,6 +261,10 @@ func registerExplosivesCD(agent Agent, consumes *proto.Consumes) {
}

if hasFiller {
if consumes.FillerExplosive != proto.Explosive_ExplosiveEzThroRadiationBomb && !character.HasProfession(proto.Profession_Engineering) {
return
}

var filler *Spell
switch consumes.FillerExplosive {
case proto.Explosive_ExplosiveSolidDynamite:
Expand All @@ -270,6 +273,10 @@ func registerExplosivesCD(agent Agent, consumes *proto.Consumes) {
filler = character.newDenseDynamiteSpell(sharedTimer)
case proto.Explosive_ExplosiveThoriumGrenade:
filler = character.newThoriumGrenadeSpell(sharedTimer)
case proto.Explosive_ExplosiveEzThroRadiationBomb:
filler = character.newEzThroRadiationBombSpell(sharedTimer)
case proto.Explosive_ExplosiveHighYieldRadiationBomb:
filler = character.newHighYieldRadiationBombSpell(sharedTimer)
}

character.AddMajorCooldown(MajorCooldown{
Expand All @@ -281,16 +288,26 @@ func registerExplosivesCD(agent Agent, consumes *proto.Consumes) {
}

// Creates a spell object for the common explosive case.
func (character *Character) newBasicExplosiveSpellConfig(sharedTimer *Timer, actionID ActionID, school SpellSchool, minDamage float64, maxDamage float64, cooldown Cooldown, _ float64, _ float64) SpellConfig {
dealSelfDamage := actionID.SameAction(SapperActionID)
func (character *Character) newBasicExplosiveSpellConfig(sharedTimer *Timer, actionID ActionID, school SpellSchool, minDamage float64, maxDamage float64, cooldown Cooldown, selfMinDamage float64, selfMaxDamage float64) SpellConfig {
isSapper := actionID.SameAction(SapperActionID)

var defaultCast Cast
if !isSapper {
defaultCast = Cast{
CastTime: time.Second,
}
}

return SpellConfig{
ActionID: actionID,
SpellSchool: school,
ProcMask: ProcMaskEmpty,
Flags: SpellFlagCastTimeNoGCD,

Cast: CastConfig{
CD: cooldown,
DefaultCast: defaultCast,
CD: cooldown,
IgnoreHaste: true,
SharedCD: Cooldown{
Timer: sharedTimer,
Duration: time.Minute,
Expand All @@ -309,8 +326,8 @@ func (character *Character) newBasicExplosiveSpellConfig(sharedTimer *Timer, act
spell.CalcAndDealDamage(sim, aoeTarget, baseDamage, spell.OutcomeMagicHitAndCrit)
}

if dealSelfDamage {
baseDamage := sim.Roll(minDamage, maxDamage)
if isSapper {
baseDamage := sim.Roll(selfMinDamage, selfMaxDamage)
spell.CalcAndDealDamage(sim, &character.Unit, baseDamage, spell.OutcomeMagicHitAndCrit)
}
},
Expand All @@ -329,6 +346,87 @@ func (character *Character) newThoriumGrenadeSpell(sharedTimer *Timer) *Spell {
return character.GetOrRegisterSpell(character.newBasicExplosiveSpellConfig(sharedTimer, ThoriumGrenadeActionID, SpellSchoolFire, 300, 500, Cooldown{}, 0, 0))
}

// Creates a spell object for the common explosive case.
func (character *Character) newRadiationBombSpellConfig(sharedTimer *Timer, actionID ActionID, minDamage float64, maxDamage float64, dotDamage float64, cooldown Cooldown) SpellConfig {
return SpellConfig{
ActionID: actionID,
SpellSchool: SpellSchoolFire,
ProcMask: ProcMaskEmpty,
Flags: SpellFlagCastTimeNoGCD,

Cast: CastConfig{
DefaultCast: Cast{
CastTime: time.Second,
},
IgnoreHaste: true,
CD: cooldown,
SharedCD: Cooldown{
Timer: sharedTimer,
Duration: time.Minute,
},
},

// Explosives always have 1% resist chance, so just give them hit cap.
BonusHitRating: 100 * SpellHitRatingPerHitChance,
DamageMultiplier: 1,
CritMultiplier: 2,
ThreatMultiplier: 1,

Dot: DotConfig{
Aura: Aura{
Label: actionID.String(),
},

NumberOfTicks: 5,
TickLength: time.Second * 2,

OnSnapshot: func(sim *Simulation, target *Unit, dot *Dot, isRollover bool) {
// Use nature school for dot modifiers
dot.Spell.SpellSchool = SpellSchoolNature
dot.Spell.SchoolIndex = stats.SchoolIndexNature

dot.SnapshotBaseDamage = dotDamage

dot.SnapshotCritChance = dot.Spell.SpellCritChance(target)
dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(dot.Spell.Unit.AttackTables[target.UnitIndex])

// Revert to fire school
dot.Spell.SpellSchool = SpellSchoolFire
dot.Spell.SchoolIndex = stats.SchoolIndexFire
},
OnTick: func(sim *Simulation, target *Unit, dot *Dot) {
// Use nature school for dot ticks
dot.Spell.SpellSchool = SpellSchoolNature
dot.Spell.SchoolIndex = stats.SchoolIndexNature

dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick)

// Revert to fire school
dot.Spell.SpellSchool = SpellSchoolFire
dot.Spell.SchoolIndex = stats.SchoolIndexFire
},
},

ApplyEffects: func(sim *Simulation, target *Unit, spell *Spell) {
for _, aoeTarget := range sim.Encounter.TargetUnits {
baseDamage := sim.Roll(minDamage, maxDamage) * sim.Encounter.AOECapMultiplier()

result := spell.CalcAndDealDamage(sim, aoeTarget, baseDamage, spell.OutcomeMagicHitAndCrit)

if result.Landed() {
spell.Dot(aoeTarget).Apply(sim)
}
}
},
}
}
func (character *Character) newEzThroRadiationBombSpell(sharedTimer *Timer) *Spell {
return character.GetOrRegisterSpell(character.newRadiationBombSpellConfig(sharedTimer, EzThroRadiationBombActionID, 112, 188, 10, Cooldown{}))
}
func (character *Character) newHighYieldRadiationBombSpell(sharedTimer *Timer) *Spell {
return character.GetOrRegisterSpell(character.newRadiationBombSpellConfig(sharedTimer, HighYieldRadiationBombActionID, 150, 250, 25, Cooldown{}))
}

func registerPotionCD(agent Agent, consumes *proto.Consumes) {
character := agent.GetCharacter()
defaultPotion := consumes.DefaultPotion
Expand Down
2 changes: 1 addition & 1 deletion sim/core/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ const (
SpellFlagPrepullPotion // Indicates this spell is the prepull potion.
SpellFlagCombatPotion // Indicates this spell is the combat potion.
SpellFlagResetAttackSwing // Indicates this spell resets the melee swing timer.
SpellFlagHunterRanged // Indicates this spell is hunters Auto shot spell
SpellFlagCastTimeNoGCD // Indicates this spell is hunters Auto shot spell
SpellFlagPureDot // Indicates this spell is a dot with no initial damage component

// Used to let agents categorize their spells.
Expand Down
2 changes: 1 addition & 1 deletion sim/hunter/hunter.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func NewHunter(character *core.Character, options *proto.Player) *Hunter {
AutoSwingMelee: true,
})

hunter.AutoAttacks.RangedConfig().Flags |= core.SpellFlagHunterRanged
hunter.AutoAttacks.RangedConfig().Flags |= core.SpellFlagCastTimeNoGCD
hunter.AutoAttacks.RangedConfig().Cast = core.CastConfig{
DefaultCast: core.Cast{
CastTime: time.Millisecond * 500,
Expand Down
Loading

0 comments on commit 40b9bf8

Please sign in to comment.