diff --git a/proto/apl.proto b/proto/apl.proto index 1d97dcda94..b2e809addd 100644 --- a/proto/apl.proto +++ b/proto/apl.proto @@ -82,6 +82,7 @@ message APLValue { APLValueSpellCanCast spell_can_cast = 19; APLValueSpellIsReady spell_is_ready = 20; APLValueSpellTimeToReady spell_time_to_ready = 21; + APLValueSpellCastTime spell_cast_time = 35; // Aura values APLValueAuraIsActive aura_is_active = 22; @@ -91,6 +92,8 @@ message APLValue { // Dot values APLValueDotIsActive dot_is_active = 6; APLValueDotRemainingTime dot_remaining_time = 13; + + // Last Index - 35 } } @@ -234,6 +237,9 @@ message APLValueSpellIsReady { message APLValueSpellTimeToReady { ActionID spell_id = 1; } +message APLValueSpellCastTime { + ActionID spell_id = 1; +} message APLValueAuraIsActive { ActionID aura_id = 1; diff --git a/sim/core/apl_value.go b/sim/core/apl_value.go index c7fcb98e19..7d925524f7 100644 --- a/sim/core/apl_value.go +++ b/sim/core/apl_value.go @@ -114,6 +114,8 @@ func (rot *APLRotation) newAPLValue(config *proto.APLValue) APLValue { return rot.newValueSpellIsReady(config.GetSpellIsReady()) case *proto.APLValue_SpellTimeToReady: return rot.newValueSpellTimeToReady(config.GetSpellTimeToReady()) + case *proto.APLValue_SpellCastTime: + return rot.newValueSpellCastTime(config.GetSpellCastTime()) // Auras case *proto.APLValue_AuraIsActive: diff --git a/sim/core/apl_values_spell.go b/sim/core/apl_values_spell.go index 50ad4e70b9..52ec236562 100644 --- a/sim/core/apl_values_spell.go +++ b/sim/core/apl_values_spell.go @@ -75,3 +75,25 @@ func (value *APLValueSpellTimeToReady) Type() proto.APLValueType { func (value *APLValueSpellTimeToReady) GetDuration(sim *Simulation) time.Duration { return value.spell.TimeToReady(sim) } + +type APLValueSpellCastTime struct { + defaultAPLValueImpl + spell *Spell +} + +func (rot *APLRotation) newValueSpellCastTime(config *proto.APLValueSpellCastTime) APLValue { + unit := rot.unit + spell := unit.aplGetSpell(config.SpellId) + if spell == nil { + return nil + } + return &APLValueSpellCastTime{ + spell: spell, + } +} +func (value *APLValueSpellCastTime) Type() proto.APLValueType { + return proto.APLValueType_ValueTypeDuration +} +func (value *APLValueSpellCastTime) GetDuration(sim *Simulation) time.Duration { + return value.spell.Unit.ApplyCastSpeedForSpell(value.spell.DefaultCast.CastTime, value.spell) +} diff --git a/sim/druid/barkskin.go b/sim/druid/barkskin.go index ffd8e2f931..3da8c1c18d 100644 --- a/sim/druid/barkskin.go +++ b/sim/druid/barkskin.go @@ -38,7 +38,7 @@ func (druid *Druid) registerBarkskinCD() { druid.Barkskin = druid.RegisterSpell(core.SpellConfig{ ActionID: actionId, - Flags: SpellFlagOmenTrigger, + Flags: SpellFlagOmenTrigger | core.SpellFlagAPL, Cast: core.CastConfig{ CD: core.Cooldown{ Timer: druid.NewTimer(), diff --git a/sim/druid/faerie_fire.go b/sim/druid/faerie_fire.go index 27c50d5eb7..d3613f053b 100644 --- a/sim/druid/faerie_fire.go +++ b/sim/druid/faerie_fire.go @@ -29,6 +29,7 @@ func (druid *Druid) registerFaerieFireSpell() { } flatThreatBonus = 632. } + flags |= core.SpellFlagAPL druid.FaerieFireAuras = druid.NewEnemyAuraArray(func(target *core.Unit) *core.Aura { return core.FaerieFireAura(target, druid.Talents.ImprovedFaerieFire) diff --git a/sim/druid/force_of_nature.go b/sim/druid/force_of_nature.go index e1cf1bfe99..5d077d7f8d 100644 --- a/sim/druid/force_of_nature.go +++ b/sim/druid/force_of_nature.go @@ -19,7 +19,7 @@ func (druid *Druid) registerForceOfNatureCD() { }) druid.ForceOfNature = druid.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 65861}, - + Flags: core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: 0.12, Multiplier: 1, diff --git a/sim/druid/hurricane.go b/sim/druid/hurricane.go index 1d41586be5..3a102b2b52 100644 --- a/sim/druid/hurricane.go +++ b/sim/druid/hurricane.go @@ -11,7 +11,7 @@ func (druid *Druid) registerHurricaneSpell() { ActionID: core.ActionID{SpellID: 48467}, SpellSchool: core.SpellSchoolNature, ProcMask: core.ProcMaskSpellDamage, - Flags: core.SpellFlagChanneled | SpellFlagOmenTrigger, + Flags: core.SpellFlagChanneled | SpellFlagOmenTrigger | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: 0.81, diff --git a/sim/druid/insect_swarm.go b/sim/druid/insect_swarm.go index dae24e0106..c6a28f25c5 100644 --- a/sim/druid/insect_swarm.go +++ b/sim/druid/insect_swarm.go @@ -39,7 +39,7 @@ func (druid *Druid) registerInsectSwarmSpell() { ActionID: core.ActionID{SpellID: 48468}, SpellSchool: core.SpellSchoolNature, ProcMask: core.ProcMaskSpellDamage, - Flags: SpellFlagOmenTrigger, + Flags: SpellFlagOmenTrigger | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: 0.08, diff --git a/sim/druid/moonfire.go b/sim/druid/moonfire.go index ad6923eb5a..45d47f68bf 100644 --- a/sim/druid/moonfire.go +++ b/sim/druid/moonfire.go @@ -27,7 +27,7 @@ func (druid *Druid) registerMoonfireSpell() { ActionID: core.ActionID{SpellID: 48463}, SpellSchool: core.SpellSchoolArcane, ProcMask: core.ProcMaskSpellDamage, - Flags: SpellFlagNaturesGrace | SpellFlagOmenTrigger, + Flags: SpellFlagNaturesGrace | SpellFlagOmenTrigger | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: 0.21, diff --git a/sim/druid/rebirth.go b/sim/druid/rebirth.go index c87f02d540..af0514de0c 100644 --- a/sim/druid/rebirth.go +++ b/sim/druid/rebirth.go @@ -17,7 +17,7 @@ func (druid *Druid) registerRebirthSpell() { druid.Rebirth = druid.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 48477}, - Flags: SpellFlagOmenTrigger, + Flags: SpellFlagOmenTrigger | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: baseCost, diff --git a/sim/druid/starfall.go b/sim/druid/starfall.go index 5c0cc782f5..20ebaf7850 100644 --- a/sim/druid/starfall.go +++ b/sim/druid/starfall.go @@ -20,7 +20,7 @@ func (druid *Druid) registerStarfallSpell() { ActionID: core.ActionID{SpellID: 53201}, SpellSchool: core.SpellSchoolArcane, ProcMask: core.ProcMaskSpellDamage, - Flags: SpellFlagNaturesGrace | SpellFlagOmenTrigger, + Flags: SpellFlagNaturesGrace | SpellFlagOmenTrigger | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: 0.35, diff --git a/sim/druid/starfire.go b/sim/druid/starfire.go index 32692a878a..5be42f33f3 100644 --- a/sim/druid/starfire.go +++ b/sim/druid/starfire.go @@ -21,7 +21,7 @@ func (druid *Druid) registerStarfireSpell() { ActionID: core.ActionID{SpellID: 48465}, SpellSchool: core.SpellSchoolArcane, ProcMask: core.ProcMaskSpellDamage, - Flags: SpellFlagNaturesGrace | SpellFlagOmenTrigger, + Flags: SpellFlagNaturesGrace | SpellFlagOmenTrigger | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: 0.16, diff --git a/sim/druid/typhoon.go b/sim/druid/typhoon.go index 15d5dd35f9..ac943977d1 100644 --- a/sim/druid/typhoon.go +++ b/sim/druid/typhoon.go @@ -16,7 +16,7 @@ func (druid *Druid) registerTyphoonSpell() { ActionID: core.ActionID{SpellID: 61384}, SpellSchool: core.SpellSchoolNature, ProcMask: core.ProcMaskSpellDamage, - Flags: SpellFlagOmenTrigger, + Flags: SpellFlagOmenTrigger | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCost: 0.25, diff --git a/sim/druid/wrath.go b/sim/druid/wrath.go index aa89e01493..520efbca64 100644 --- a/sim/druid/wrath.go +++ b/sim/druid/wrath.go @@ -18,7 +18,7 @@ func (druid *Druid) registerWrathSpell() { ActionID: core.ActionID{SpellID: 48461}, SpellSchool: core.SpellSchoolNature, ProcMask: core.ProcMaskSpellDamage, - Flags: SpellFlagNaturesGrace | SpellFlagOmenTrigger, + Flags: SpellFlagNaturesGrace | SpellFlagOmenTrigger | core.SpellFlagAPL, MissileSpeed: 20, ManaCost: core.ManaCostOptions{ diff --git a/ui/balance_druid/presets.ts b/ui/balance_druid/presets.ts index 8a1c0724e0..32859a34c6 100644 --- a/ui/balance_druid/presets.ts +++ b/ui/balance_druid/presets.ts @@ -12,7 +12,7 @@ import { RaidTarget, Spec, TristateEffect } from '../core/proto/common.js'; -import { SavedTalents } from '../core/proto/ui.js'; +import { SavedRotation, SavedTalents } from '../core/proto/ui.js'; import { BalanceDruid_Options as BalanceDruidOptions, @@ -28,6 +28,7 @@ import { import * as Tooltips from '../core/constants/tooltips.js'; import { NO_TARGET } from "../core/proto_utils/utils"; import { Player } from "../core/player"; +import { APLRotation } from '../core/proto/apl.js'; // Preset options for this spec. // Eventually we will import these values for the raid sim too, so its good to @@ -274,3 +275,24 @@ export const P3_PRESET_ALLI = { }`), }; + +export const ROTATION_PRESET_BASIC_APL = { +name: 'Basic APL', +rotation: SavedRotation.create({ + specRotationOptionsJson: BalanceDruidRotation.toJsonString(DefaultRotation), + rotation: APLRotation.fromJsonString(`{ + "enabled": true, + "priorityList": [ + {"hide":true,"action":{"condition":{"not":{"val":{"auraIsActive":{"auraId":{}}}}},"castSpell":{"spellId":{"spellId":770}}}}, + {"action":{"condition":{"or":{"vals":[{"cmp":{"op":"OpGt","lhs":{"auraRemainingTime":{"auraId":{"spellId":48518}}},"rhs":{"const":{"val":"10s"}}}},{"cmp":{"op":"OpLt","lhs":{"remainingTime":{}},"rhs":{"const":{"val":"15s"}}}}]}},"autocastOtherCooldowns":{}}}, + {"action":{"condition":{"spellIsReady":{"spellId":{"spellId":65861}}},"castSpell":{"spellId":{"spellId":65861}}}}, + {"action":{"condition":{"and":{"vals":[{"not":{"val":{"auraIsActive":{"auraId":{"spellId":48518}}}}},{"spellIsReady":{"spellId":{"spellId":53201}}}]}},"castSpell":{"spellId":{"spellId":53201}}}}, + {"action":{"condition":{"cmp":{"op":"OpGt","lhs":{"numberTargets":{}},"rhs":{"const":{"val":"3"}}}},"castSpell":{"spellId":{"spellId":48467}}}}, + {"action":{"condition":{"cmp":{"op":"OpLt","lhs":{"auraRemainingTime":{"auraId":{"spellId":48518}}},"rhs":{"spellCastTime":{"spellId":{"spellId":48465}}}}},"multidot":{"spellId":{"spellId":48463},"maxDots":3,"maxOverlap":{"const":{"val":"0ms"}}}}}, + {"action":{"condition":{"cmp":{"op":"OpLt","lhs":{"auraRemainingTime":{"auraId":{"spellId":48518}}},"rhs":{"spellCastTime":{"spellId":{"spellId":48465}}}}},"multidot":{"spellId":{"spellId":48468},"maxDots":3,"maxOverlap":{"const":{"val":"0ms"}}}}}, + {"action":{"condition":{"cmp":{"op":"OpGt","lhs":{"auraRemainingTime":{"auraId":{"spellId":48517}}},"rhs":{"spellCastTime":{"spellId":{"spellId":48461}}}}},"castSpell":{"spellId":{"spellId":48461}}}}, + {"action":{"castSpell":{"spellId":{"spellId":48465}}}} + ] + }`), +}), +}; \ No newline at end of file diff --git a/ui/balance_druid/sim.ts b/ui/balance_druid/sim.ts index 4f9183048e..25c969e72d 100644 --- a/ui/balance_druid/sim.ts +++ b/ui/balance_druid/sim.ts @@ -110,6 +110,9 @@ export class BalanceDruidSimUI extends IndividualSimUI { Presets.Phase2Talents, Presets.Phase3Talents, ], + rotations: [ + Presets.ROTATION_PRESET_BASIC_APL, + ], // Preset gear configurations that the user can quickly select. gear: [ Presets.PRE_RAID_PRESET, diff --git a/ui/core/components/individual_sim_ui/apl_values.ts b/ui/core/components/individual_sim_ui/apl_values.ts index 10f2ac9783..09bb3ecd76 100644 --- a/ui/core/components/individual_sim_ui/apl_values.ts +++ b/ui/core/components/individual_sim_ui/apl_values.ts @@ -34,6 +34,7 @@ import { APLValueRuneCooldown, APLValueNextRuneCooldown, APLValueNumberTargets, + APLValueSpellCastTime, APLValueCurrentNonDeathRuneCount, } from '../../proto/apl.js'; @@ -546,6 +547,15 @@ const valueTypeFactories: Record, ValueTypeConfig AplHelpers.actionIdFieldConfig('spellId', 'castable_spells'), ], }), + ['spellCastTime']: inputBuilder({ + label: 'Cast Time', + submenu: ['Spell'], + shortDescription: 'Amount of time to cast the spell including any haste and spell cast time adjustments.', + newValue: APLValueSpellCastTime.create, + fields: [ + AplHelpers.actionIdFieldConfig('spellId', 'castable_spells'), + ], + }), // Auras ['auraIsActive']: inputBuilder({ diff --git a/ui/core/launched_sims.ts b/ui/core/launched_sims.ts index 12f5120866..0d46184fa9 100644 --- a/ui/core/launched_sims.ts +++ b/ui/core/launched_sims.ts @@ -40,7 +40,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.Unlaunched, + [Spec.SpecBalanceDruid]: LaunchStatus.Alpha, [Spec.SpecFeralDruid]: LaunchStatus.Unlaunched, [Spec.SpecFeralTankDruid]: LaunchStatus.Unlaunched, [Spec.SpecRestorationDruid]: LaunchStatus.Unlaunched,