local Tinkr, Bastion = ... local GuardianModule = Bastion.Module:New('GuardianDruid') local Player = Bastion.UnitManager:Get('player') local Target = Bastion.UnitManager:Get('target') local SpellBook = Bastion.SpellBook:New() -- Spells local Moonfire = SpellBook:GetSpell(8921) local Thrash = SpellBook:GetSpell(77758) local Ironfur = SpellBook:GetSpell(192081) local Maul = SpellBook:GetSpell(6807) local Mangle = SpellBook:GetSpell(33917) local Swipe = SpellBook:GetSpell(213771) local LunarBeam = SpellBook:GetSpell(204066) local Raze = SpellBook:GetSpell(391286) local Barkskin = SpellBook:GetSpell(22812) local Incarnation = SpellBook:GetSpell(102558) local RageOfTheSleeper = SpellBook:GetSpell(200851) local HeartOfTheWild = SpellBook:GetSpell(319454) local FrenziedRegeneration = SpellBook:GetSpell(22842) local SkullBash = SpellBook:GetSpell(106839) local IncapacitatingRoar = SpellBook:GetSpell(99) -- Forms local BearForm = SpellBook:GetSpell(5487) local CatForm = SpellBook:GetSpell(768) local TravelForm = SpellBook:GetSpell(783) -- Buffs local MoonfireDot = SpellBook:GetSpell(164812) local ThrashDot = SpellBook:GetSpell(192090) local IronfurBuff = SpellBook:GetSpell(192081) local ToothAndClawBuff = SpellBook:GetSpell(135286) local GalacticGuardianBuff = SpellBook:GetSpell(213708) local IncarnationBuff = SpellBook:GetSpell(102558) local BearFormBuff = SpellBook:GetSpell(5487) local CatFormBuff = SpellBook:GetSpell(768) local TravelFormBuff = SpellBook:GetSpell(783) -- Create APLs local DefaultAPL = Bastion.APL:New('default') local AoEAPL = Bastion.APL:New('aoe') local CooldownAPL = Bastion.APL:New('cooldown') local DefensiveAPL = Bastion.APL:New('defensive') local StanceAPL = Bastion.APL:New('stance') local InterruptAPL = Bastion.APL:New('interrupt') -- Helper functions local function GetLowestThrashStack() local lowestStack = 5 local lowestDuration = 100 local enemiesInRange = 0 Bastion.UnitManager:EnumEnemies(function(unit) if unit:IsAffectingCombat() and unit:GetDistance(Player) <= 8 then enemiesInRange = enemiesInRange + 1 local aura = unit:GetAuras():FindMy(ThrashDot) local stacks = aura:GetCount() local duration = aura:GetRemainingTime() if stacks < lowestStack then lowestStack = stacks lowestDuration = duration elseif stacks == lowestStack and duration < lowestDuration then lowestDuration = duration end end end) return lowestStack, enemiesInRange, lowestDuration end local function IsInCombatForm() return Player:GetAuras():FindMy(BearFormBuff):IsUp() or Player:GetAuras():FindMy(CatFormBuff):IsUp() end local function IsInTravelForm() return Player:GetAuras():FindMy(TravelFormBuff):IsUp() end -- Stance Management APL StanceAPL:AddSpell( BearForm:CastableIf(function(self) return not IsInTravelForm() and Player:IsAffectingCombat() and not Player:GetAuras():FindMy(BearFormBuff):IsUp() end):SetTarget(Player) ) StanceAPL:AddSpell( TravelForm:CastableIf(function(self) return not IsInTravelForm() and not Player:IsAffectingCombat() and Player:IsOutdoors() and not Player:GetAuras():FindMy(TravelFormBuff):IsUp() end):SetTarget(Player) ) StanceAPL:AddSpell( CatForm:CastableIf(function(self) return not IsInTravelForm() and not Player:IsAffectingCombat() and Player:IsIndoors() and not Player:GetAuras():FindMy(CatFormBuff):IsUp() end):SetTarget(Player) ) -- Cooldown APL CooldownAPL:AddSpell( Incarnation:CastableIf(function(self) return not Player:GetAuras():FindMy(IncarnationBuff):IsUp() end):SetTarget(Player) ) CooldownAPL:AddSpell( RageOfTheSleeper:CastableIf(function(self) return true end):SetTarget(Player) ) CooldownAPL:AddSpell( LunarBeam:CastableIf(function(self) return true end):SetTarget(Target) ) CooldownAPL:AddSpell( HeartOfTheWild:CastableIf(function(self) return true end):SetTarget(Player) ) -- Defensive APL DefensiveAPL:AddSpell( Ironfur:CastableIf(function(self) return Player:GetPower() >= 40 or (Player:GetPower() >= 25 and Player:GetAuras():FindMy(IronfurBuff):GetRemainingTime() < 2) end):SetTarget(Player) ) DefensiveAPL:AddSpell( Barkskin:CastableIf(function(self) return Player:GetHP() <= 70 end):SetTarget(Player) ) DefensiveAPL:AddSpell( FrenziedRegeneration:CastableIf(function(self) return Player:GetHP() <= 60 end):SetTarget(Player) ) -- Interrupt APL InterruptAPL:AddSpell( SkullBash:CastableIf(function(self) return Target:IsInterruptible() end):SetTarget(Target) ) InterruptAPL:AddSpell( IncapacitatingRoar:CastableIf(function(self) return Player:GetEnemies(10) > 1 and not Target:IsInterruptible() end):SetTarget(Player) ) -- Default APL (Single Target) DefaultAPL:AddSpell( Mangle:CastableIf(function(self) return self:IsInRange(Target) end):SetTarget(Target) ) DefaultAPL:AddSpell( Thrash:CastableIf(function(self) local lowestStack, enemiesInRange, lowestDuration = GetLowestThrashStack() return lowestStack < 5 or lowestDuration < 4.5 end):SetTarget(Player) ) DefaultAPL:AddSpell( Moonfire:CastableIf(function(self) return self:IsInRange(Target) and ( Player:GetAuras():FindMy(GalacticGuardianBuff):IsUp() or not Target:GetAuras():FindMy(MoonfireDot):IsUp() or Target:GetAuras():FindMy(MoonfireDot):GetRemainingTime() < 3 ) end):SetTarget(Target) ) DefaultAPL:AddSpell( Maul:CastableIf(function(self) return self:IsInRange(Target) and (Player:GetAuras():FindMy(ToothAndClawBuff):IsUp() or Player:GetPower() >= 90) end):SetTarget(Target) ) DefaultAPL:AddSpell( Swipe:CastableIf(function(self) return self:IsInRange(Target) end):SetTarget(Target) ) -- AoE APL AoEAPL:AddSpell( Thrash:CastableIf(function(self) local lowestStack, enemiesInRange, lowestDuration = GetLowestThrashStack() return lowestStack < 5 or lowestDuration < 4.5 end):SetTarget(Player) ) AoEAPL:AddSpell( Swipe:CastableIf(function(self) return Player:GetEnemies(8) > 0 end):SetTarget(Target) ) AoEAPL:AddSpell( Mangle:CastableIf(function(self) return self:IsInRange(Target) end):SetTarget(Target) ) AoEAPL:AddSpell( Moonfire:CastableIf(function(self) return self:IsInRange(Target) and ( Player:GetAuras():FindMy(GalacticGuardianBuff):IsUp() or not Target:GetAuras():FindMy(MoonfireDot):IsUp() or Target:GetAuras():FindMy(MoonfireDot):GetRemainingTime() < 3 ) end):SetTarget(Target) ) AoEAPL:AddSpell( Raze:CastableIf(function(self) return self:IsInRange(Target) and Player:GetAuras():FindMy(ToothAndClawBuff):IsUp() end):SetTarget(Target) ) -- Main rotation logic GuardianModule:Sync(function() if IsInTravelForm() then return -- Do nothing if in Travel Form end StanceAPL:Execute() if not Player:IsAffectingCombat() then return end -- Combat rotations InterruptAPL:Execute() DefensiveAPL:Execute() CooldownAPL:Execute() if Player:GetEnemies(8) >= 3 then AoEAPL:Execute() else DefaultAPL:Execute() end end) Bastion:Register(GuardianModule)