From cc6f2b08a2e28bc09e1fc13ee34a8b587d8073f0 Mon Sep 17 00:00:00 2001 From: jarves Date: Fri, 14 Jul 2023 16:05:02 -0500 Subject: [PATCH] feral: enable apl rotation Signed-off-by: jarves --- proto/druid.proto | 4 ++-- sim/druid/enrage.go | 2 +- sim/druid/fake_gotw.go | 2 +- sim/druid/feral/feral.go | 8 ++++++-- sim/druid/feral/feral_test.go | 6 +++--- sim/druid/feral/rotation.go | 16 ++++++++++++++++ sim/druid/ferocious_bite.go | 2 +- sim/druid/forms.go | 4 ++-- sim/druid/mangle.go | 4 ++-- sim/druid/maul.go | 2 +- sim/druid/rake.go | 2 +- sim/druid/rip.go | 2 +- sim/druid/savage_roar.go | 2 +- sim/druid/shred.go | 2 +- sim/druid/swipe.go | 2 +- sim/druid/tigers_fury.go | 2 +- ui/core/launched_sims.ts | 2 +- ui/feral_druid/inputs.ts | 33 ++++++++++++++++----------------- ui/feral_druid/presets.ts | 11 +++++++++-- ui/feral_druid/sim.ts | 5 +++-- 20 files changed, 70 insertions(+), 43 deletions(-) diff --git a/proto/druid.proto b/proto/druid.proto index 1ff33ec1ca..f78bdb3192 100644 --- a/proto/druid.proto +++ b/proto/druid.proto @@ -248,15 +248,15 @@ message FeralDruid { bool manual_params = 17; float max_ff_delay = 20; AplType rotation_type = 21; + bool pre_pop_berserk = 22; + bool pre_pop_ooc = 23; } Rotation rotation = 1; message Options { RaidTarget innervate_target = 1; int32 latency_ms = 2; - bool prepop_ooc = 3; bool assume_bleed_active = 4; - bool pre_pop_berserk = 5; } Options options = 3; } diff --git a/sim/druid/enrage.go b/sim/druid/enrage.go index ae8afa62b5..5c960b352e 100644 --- a/sim/druid/enrage.go +++ b/sim/druid/enrage.go @@ -41,7 +41,7 @@ func (druid *Druid) registerEnrageSpell() { spell := druid.RegisterSpell(core.SpellConfig{ ActionID: actionID, - + Flags: core.SpellFlagAPL, Cast: core.CastConfig{ CD: core.Cooldown{ Timer: druid.NewTimer(), diff --git a/sim/druid/fake_gotw.go b/sim/druid/fake_gotw.go index 42837cc4ea..7c8f02bc08 100644 --- a/sim/druid/fake_gotw.go +++ b/sim/druid/fake_gotw.go @@ -12,7 +12,7 @@ func (druid *Druid) registerFakeGotw() { druid.GiftOfTheWild = druid.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 48470}, - Flags: SpellFlagOmenTrigger | core.SpellFlagHelpful, + Flags: SpellFlagOmenTrigger | core.SpellFlagHelpful | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: baseCost, diff --git a/sim/druid/feral/feral.go b/sim/druid/feral/feral.go index 78ccef75ff..03532ffe7e 100644 --- a/sim/druid/feral/feral.go +++ b/sim/druid/feral/feral.go @@ -41,12 +41,12 @@ func NewFeralDruid(character core.Character, options *proto.Player) *FeralDruid cat.AssumeBleedActive = feralOptions.Options.AssumeBleedActive cat.maxRipTicks = cat.MaxRipTicks() - cat.prepopOoc = feralOptions.Options.PrepopOoc + cat.prepopOoc = feralOptions.Rotation.PrePopOoc cat.RaidBuffTargets = int(core.MaxInt32(feralOptions.Rotation.RaidTargets, 1)) if !feralOptions.Rotation.ManualParams { cat.RaidBuffTargets = 30 } - cat.PrePopBerserk = feralOptions.Options.PrePopBerserk + cat.PrePopBerserk = feralOptions.Rotation.PrePopBerserk cat.setupRotation(feralOptions.Rotation) cat.EnableEnergyBar(100.0, cat.OnEnergyGain) @@ -100,6 +100,10 @@ func (cat *FeralDruid) Initialize() { cat.Druid.Initialize() cat.RegisterFeralCatSpells() + if cat.IsUsingAPL { + return + } + if cat.prepopOoc && cat.Talents.OmenOfClarity { cat.RegisterPrepullAction(-time.Second, func(sim *core.Simulation) { cat.ProcOoc(sim) diff --git a/sim/druid/feral/feral_test.go b/sim/druid/feral/feral_test.go index b33832a545..7c3fd4f659 100644 --- a/sim/druid/feral/feral_test.go +++ b/sim/druid/feral/feral_test.go @@ -150,7 +150,6 @@ var PlayerOptionsMonoCat = &proto.Player_FeralDruid{ Options: &proto.FeralDruid_Options{ InnervateTarget: &proto.RaidTarget{TargetIndex: -1}, // no Innervate LatencyMs: 100, - PrepopOoc: true, AssumeBleedActive: true, }, Rotation: &proto.FeralDruid_Rotation{ @@ -170,6 +169,7 @@ var PlayerOptionsMonoCat = &proto.Player_FeralDruid{ SnekWeave: false, FlowerWeave: false, RaidTargets: 30, + PrePopOoc: true, }, }, } @@ -179,7 +179,6 @@ var PlayerOptionsMonoCatNoBleed = &proto.Player_FeralDruid{ Options: &proto.FeralDruid_Options{ InnervateTarget: &proto.RaidTarget{TargetIndex: -1}, // no Innervate LatencyMs: 100, - PrepopOoc: true, AssumeBleedActive: false, }, Rotation: &proto.FeralDruid_Rotation{ @@ -199,6 +198,7 @@ var PlayerOptionsMonoCatNoBleed = &proto.Player_FeralDruid{ SnekWeave: false, FlowerWeave: false, RaidTargets: 30, + PrePopOoc: true, }, }, } @@ -208,7 +208,6 @@ var PlayerOptionsFlowerCatAoe = &proto.Player_FeralDruid{ Options: &proto.FeralDruid_Options{ InnervateTarget: &proto.RaidTarget{TargetIndex: -1}, // no Innervate LatencyMs: 100, - PrepopOoc: true, AssumeBleedActive: false, }, Rotation: &proto.FeralDruid_Rotation{ @@ -228,6 +227,7 @@ var PlayerOptionsFlowerCatAoe = &proto.Player_FeralDruid{ SnekWeave: false, FlowerWeave: true, RaidTargets: 30, + PrePopOoc: true, }, }, } diff --git a/sim/druid/feral/rotation.go b/sim/druid/feral/rotation.go index 3e98911c0c..14dc3e26fc 100644 --- a/sim/druid/feral/rotation.go +++ b/sim/druid/feral/rotation.go @@ -10,6 +10,10 @@ import ( ) func (cat *FeralDruid) OnEnergyGain(sim *core.Simulation) { + if cat.IsUsingAPL { + return + } + cat.TryUseCooldowns(sim) if cat.InForm(druid.Cat) && !cat.readyToShift { cat.doTigersFury(sim) @@ -17,6 +21,10 @@ func (cat *FeralDruid) OnEnergyGain(sim *core.Simulation) { } func (cat *FeralDruid) OnGCDReady(sim *core.Simulation) { + if cat.IsUsingAPL { + return + } + cat.TryUseCooldowns(sim) if !cat.GCD.IsReady(sim) { return @@ -49,6 +57,10 @@ func (cat *FeralDruid) OnGCDReady(sim *core.Simulation) { } func (cat *FeralDruid) OnAutoAttack(sim *core.Simulation, spell *core.Spell) { + if cat.IsUsingAPL { + return + } + if cat.InForm(druid.Humanoid) { panic("auto attack out of form?") } @@ -81,6 +93,10 @@ func (cat *FeralDruid) NextRotationAction(sim *core.Simulation, kickAt time.Dura // Ported from https://github.com/NerdEgghead/WOTLK_cat_sim func (cat *FeralDruid) checkReplaceMaul(sim *core.Simulation) *core.Spell { + if cat.IsUsingAPL { + return nil + } + // If we will have enough time and Energy leeway to stay in // Dire Bear Form once the GCD expires, then only Maul if we // will be left with enough Rage to cast Mangle or Lacerate diff --git a/sim/druid/ferocious_bite.go b/sim/druid/ferocious_bite.go index 18e9eb354c..98fce1b17d 100644 --- a/sim/druid/ferocious_bite.go +++ b/sim/druid/ferocious_bite.go @@ -13,7 +13,7 @@ func (druid *Druid) registerFerociousBiteSpell() { ActionID: core.ActionID{SpellID: 48577}, SpellSchool: core.SpellSchoolPhysical, ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, + Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ Cost: 35, diff --git a/sim/druid/forms.go b/sim/druid/forms.go index 45e9ddd0e4..2ea4a76a34 100644 --- a/sim/druid/forms.go +++ b/sim/druid/forms.go @@ -206,7 +206,7 @@ func (druid *Druid) registerCatFormSpell() { druid.CatForm = druid.RegisterSpell(core.SpellConfig{ ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete, + Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: 0.35, @@ -342,7 +342,7 @@ func (druid *Druid) registerBearFormSpell() { druid.BearForm = druid.RegisterSpell(core.SpellConfig{ ActionID: actionID, - Flags: core.SpellFlagNoOnCastComplete, + Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: 0.35, diff --git a/sim/druid/mangle.go b/sim/druid/mangle.go index 29f8d1dee3..f2105c99d8 100644 --- a/sim/druid/mangle.go +++ b/sim/druid/mangle.go @@ -20,7 +20,7 @@ func (druid *Druid) registerMangleBearSpell() { ActionID: core.ActionID{SpellID: 48564}, SpellSchool: core.SpellSchoolPhysical, ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, + Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, RageCost: core.RageCostOptions{ Cost: 20 - float64(druid.Talents.Ferocity), @@ -76,7 +76,7 @@ func (druid *Druid) registerMangleCatSpell() { ActionID: core.ActionID{SpellID: 48566}, SpellSchool: core.SpellSchoolPhysical, ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, + Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ Cost: 45.0 - 2*float64(druid.Talents.ImprovedMangle) - float64(druid.Talents.Ferocity) - core.TernaryFloat64(druid.HasSetBonus(ItemSetThunderheartHarness, 2), 5, 0), diff --git a/sim/druid/maul.go b/sim/druid/maul.go index 426f183b2e..7272c6a2dd 100644 --- a/sim/druid/maul.go +++ b/sim/druid/maul.go @@ -19,7 +19,7 @@ func (druid *Druid) registerMaulSpell(rageThreshold float64) { ActionID: core.ActionID{SpellID: 48480}, SpellSchool: core.SpellSchoolPhysical, ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagNoOnCastComplete, + Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagNoOnCastComplete | core.SpellFlagAPL, RageCost: core.RageCostOptions{ Cost: 15 - float64(druid.Talents.Ferocity), diff --git a/sim/druid/rake.go b/sim/druid/rake.go index b71a5325e4..e0e804668d 100644 --- a/sim/druid/rake.go +++ b/sim/druid/rake.go @@ -15,7 +15,7 @@ func (druid *Druid) registerRakeSpell() { ActionID: core.ActionID{SpellID: 48574}, SpellSchool: core.SpellSchoolPhysical, ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIgnoreResists, + Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIgnoreResists | core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ Cost: 40 - float64(druid.Talents.Ferocity), diff --git a/sim/druid/rip.go b/sim/druid/rip.go index 746bb707af..453521fbe6 100644 --- a/sim/druid/rip.go +++ b/sim/druid/rip.go @@ -23,7 +23,7 @@ func (druid *Druid) registerRipSpell() { ActionID: core.ActionID{SpellID: 49800}, SpellSchool: core.SpellSchoolPhysical, ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagMeleeMetrics, + Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ Cost: 30 - core.TernaryFloat64(druid.HasSetBonus(ItemSetLasherweaveBattlegear, 2), 10, 0), diff --git a/sim/druid/savage_roar.go b/sim/druid/savage_roar.go index 7456aeb460..f1deb86222 100644 --- a/sim/druid/savage_roar.go +++ b/sim/druid/savage_roar.go @@ -42,7 +42,7 @@ func (druid *Druid) registerSavageRoarSpell() { srSpell := druid.RegisterSpell(core.SpellConfig{ ActionID: actionID, - + Flags: core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ Cost: 25, }, diff --git a/sim/druid/shred.go b/sim/druid/shred.go index 9800edf1ea..3a35c5dfe7 100644 --- a/sim/druid/shred.go +++ b/sim/druid/shred.go @@ -20,7 +20,7 @@ func (druid *Druid) registerShredSpell() { ActionID: core.ActionID{SpellID: 48572}, SpellSchool: core.SpellSchoolPhysical, ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, + Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ Cost: 60 - 9*float64(druid.Talents.ShreddingAttacks), diff --git a/sim/druid/swipe.go b/sim/druid/swipe.go index ea10e8cdb3..ed082006e1 100644 --- a/sim/druid/swipe.go +++ b/sim/druid/swipe.go @@ -22,7 +22,7 @@ func (druid *Druid) registerSwipeBearSpell() { ActionID: core.ActionID{SpellID: 48562}, SpellSchool: core.SpellSchoolPhysical, ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, + Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, RageCost: core.RageCostOptions{ Cost: 20 - float64(druid.Talents.Ferocity), diff --git a/sim/druid/tigers_fury.go b/sim/druid/tigers_fury.go index f3c54f2601..e9bab4abd4 100644 --- a/sim/druid/tigers_fury.go +++ b/sim/druid/tigers_fury.go @@ -28,7 +28,7 @@ func (druid *Druid) registerTigersFurySpell() { spell := druid.RegisterSpell(core.SpellConfig{ ActionID: actionID, - + Flags: core.SpellFlagAPL, Cast: core.CastConfig{ CD: core.Cooldown{ Timer: druid.NewTimer(), diff --git a/ui/core/launched_sims.ts b/ui/core/launched_sims.ts index 25531117e2..b67aca573a 100644 --- a/ui/core/launched_sims.ts +++ b/ui/core/launched_sims.ts @@ -41,7 +41,7 @@ export const simLaunchStatuses: Record = { // Alpha and Beta show an info notice at the top of the page. export const aplLaunchStatuses: Record = { [Spec.SpecBalanceDruid]: LaunchStatus.Alpha, - [Spec.SpecFeralDruid]: LaunchStatus.Unlaunched, + [Spec.SpecFeralDruid]: LaunchStatus.Alpha, [Spec.SpecFeralTankDruid]: LaunchStatus.Unlaunched, [Spec.SpecRestorationDruid]: LaunchStatus.Unlaunched, [Spec.SpecElementalShaman]: LaunchStatus.Alpha, diff --git a/ui/feral_druid/inputs.ts b/ui/feral_druid/inputs.ts index 2e1542745e..21bf1b0957 100644 --- a/ui/feral_druid/inputs.ts +++ b/ui/feral_druid/inputs.ts @@ -42,22 +42,6 @@ export const LatencyMs = InputHelpers.makeSpecOptionsNumberInput({ - fieldName: 'prepopOoc', - label: 'Pre-pop Clearcasting', - labelTooltip: 'Start fight with clearcasting', - showWhen: (player: Player) => player.getTalents().omenOfClarity, - changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), -}) - -export const PrepopBerserk = InputHelpers.makeSpecOptionsBooleanInput({ - fieldName: 'prePopBerserk', - label: 'Pre-pop Berserk', - labelTooltip: 'Pre pop berserk 1 sec before fight', - showWhen: (player: Player) => player.getTalents().berserk, - changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), -}) - export const AssumeBleedActive = InputHelpers.makeSpecOptionsBooleanInput({ fieldName: 'assumeBleedActive', label: 'Assume Bleed Always Active', @@ -85,6 +69,20 @@ export const FeralDruidRotationConfig = { { name: 'AOE', value: AplType.Aoe }, ], }), + InputHelpers.makeRotationBooleanInput({ + fieldName: 'prePopOoc', + label: 'Pre-pop Clearcasting', + labelTooltip: 'Start fight with clearcasting', + showWhen: (player: Player) => player.getTalents().omenOfClarity, + changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), + }), + InputHelpers.makeRotationBooleanInput({ + fieldName: 'prePopBerserk', + label: 'Pre-pop Berserk', + labelTooltip: 'Pre pop berserk 1 sec before fight', + showWhen: (player: Player) => player.getTalents().berserk, + changeEmitter: (player: Player) => TypedEvent.onAny([player.rotationChangeEmitter, player.talentsChangeEmitter]), + }), InputHelpers.makeRotationBooleanInput({ fieldName: 'manualParams', label: 'Manual Advanced Parameters', @@ -136,10 +134,11 @@ export const FeralDruidRotationConfig = { showWhen: ShouldShowAdvParamAoe, }), InputHelpers.makeRotationNumberInput({ + extraCssClasses: ['used-in-apl'], fieldName: 'raidTargets', label: 'GotW Raid Targets', labelTooltip: 'Raid size to assume for clearcast proc chance (can include pets as well, so 25 man raid potentically can be ~30)', - showWhen: (player: Player) => ShouldShowAdvParamAoe(player) && player.getRotation().flowerWeave == true, + showWhen: (player: Player) => player.aplRotation.enabled || (ShouldShowAdvParamAoe(player) && player.getRotation().flowerWeave == true), }), // Can be uncommented if/when analytical bite mode is added //InputHelpers.makeRotationEnumInput({ diff --git a/ui/feral_druid/presets.ts b/ui/feral_druid/presets.ts index 46d7e11ffa..302fb82edb 100644 --- a/ui/feral_druid/presets.ts +++ b/ui/feral_druid/presets.ts @@ -4,7 +4,7 @@ import { EquipmentSpec } from '../core/proto/common.js'; import { Potions } from '../core/proto/common.js'; import { Flask } from '../core/proto/common.js'; import { Glyphs } from '../core/proto/common.js'; -import { SavedTalents } from '../core/proto/ui.js'; +import { SavedRotation, SavedTalents } from '../core/proto/ui.js'; import { FeralDruid_Rotation as FeralDruidRotation, @@ -62,11 +62,11 @@ export const DefaultRotation = FeralDruidRotation.create({ flowerWeave: false, raidTargets: 30, maxFfDelay: 0.1, + prePopOoc: true, }); export const DefaultOptions = FeralDruidOptions.create({ latencyMs: 100, - prepopOoc: true, assumeBleedActive: true, }); @@ -76,6 +76,13 @@ export const DefaultConsumes = Consumes.create({ defaultPotion: Potions.PotionOfSpeed, }); +export const ROTATION_PRESET_LEGACY_DEFAULT = { + name: 'Legacy Default', + rotation: SavedRotation.create({ + specRotationOptionsJson: FeralDruidRotation.toJsonString(DefaultRotation), + }), +} + export const PreRaid_PRESET = { name: 'PreRaid', tooltip: Tooltips.BASIC_BIS_DISCLAIMER, diff --git a/ui/feral_druid/sim.ts b/ui/feral_druid/sim.ts index 3fa72c0fef..255315c9f4 100644 --- a/ui/feral_druid/sim.ts +++ b/ui/feral_druid/sim.ts @@ -130,8 +130,6 @@ export class FeralDruidSimUI extends IndividualSimUI { otherInputs: { inputs: [ DruidInputs.LatencyMs, - DruidInputs.PrepopOoc, - DruidInputs.PrepopBerserk, DruidInputs.AssumeBleedActive, OtherInputs.TankAssignment, OtherInputs.InFrontOfTarget, @@ -147,6 +145,9 @@ export class FeralDruidSimUI extends IndividualSimUI { talents: [ Presets.StandardTalents, ], + rotations: [ + Presets.ROTATION_PRESET_LEGACY_DEFAULT, + ], // Preset gear configurations that the user can quickly select. gear: [ Presets.PreRaid_PRESET,