diff --git a/RestoDruid.lua b/RestoDruid.lua new file mode 100644 index 0000000..3ed4213 --- /dev/null +++ b/RestoDruid.lua @@ -0,0 +1,225 @@ +local Tinkr, Bastion = ... + +local RestoModule = Bastion.Module:New('RestoDruid') +local Player = Bastion.UnitManager:Get('player') +local Target = Bastion.UnitManager:Get('target') +local lastEfflorescenceCast = 0 + + +-- Initialize SpellBook +local SpellBook = Bastion.SpellBook:New() + +-- Spells +local Efflorescence = SpellBook:GetSpell(145205) +local Lifebloom = SpellBook:GetSpell(33763) +local Innervate = SpellBook:GetSpell(29166) +local Swiftmend = SpellBook:GetSpell(18562) +local WildGrowth = SpellBook:GetSpell(48438) +local Rejuvenation = SpellBook:GetSpell(774) +local Tranquility = SpellBook:GetSpell(740) +local Ironbark = SpellBook:GetSpell(102342) +local NaturesSwiftness = SpellBook:GetSpell(132158) +local Regrowth = SpellBook:GetSpell(8936) +local Flourish = SpellBook:GetSpell(197721) +local IncarnationTreeOfLife = SpellBook:GetSpell(33891) +local CenarionWard = SpellBook:GetSpell(102351) +local ConvokeTheSpirits = SpellBook:GetSpell(391528) +local GroveGuardians = SpellBook:GetSpell(341523) +local SoulOfTheForest = SpellBook:GetSpell(114108) +local NaturesCure = SpellBook:GetSpell(88423) + +-- Buffs +local SoulOfTheForestBuff = SpellBook:GetSpell(114108) +local ClearcastingBuff = SpellBook:GetSpell(16870) +local ReforestationBuff = SpellBook:GetSpell(392160) + +-- Custom Units +local Lowest = Bastion.UnitManager:CreateCustomUnit('lowest', function(unit) + local lowest = nil + local lowestHP = math.huge + + Bastion.UnitManager:EnumFriends(function(unit) + if unit:IsDead() or Player:GetDistance(unit) > 40 or not Player:CanSee(unit) then + return false + end + + local hp = unit:GetHP() + if hp < lowestHP then + lowest = unit + lowestHP = hp + end + end) + + return lowest or Player +end) + +local Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit) + local tank = nil + + Bastion.UnitManager:EnumFriends(function(unit) + if Player:GetDistance(unit) > 40 or not Player:CanSee(unit) or unit:IsDead() then + return false + end + + if unit:IsTank() then + tank = unit + return true + end + end) + + return tank or Player +end) + +-- APLs +local DefaultAPL = Bastion.APL:New('default') +local CooldownAPL = Bastion.APL:New('cooldown') + +-- Helper Functions +local function GetRejuvCount() + local count = 0 + Bastion.UnitManager:EnumFriends(function(unit) + if unit:GetAuras():FindMy(Rejuvenation):IsUp() then + count = count + 1 + end + end) + return count +end + +local function ShouldUseFlourish() + return GetRejuvCount() >= 3 and WildGrowth:GetTimeSinceLastCast() <= 6 +end + +-- Default APL +DefaultAPL:AddSpell( + Efflorescence:CastableIf(function(self) + local currentTime = GetTime() + return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and (currentTime - lastEfflorescenceCast) > 10 + end):SetTarget(Bastion.UnitManager:Get('none')):OnCast(function(self) + local loc = Bastion.UnitManager:FindFriendsCentroid(10, 40) + self:Click(loc) + lastEfflorescenceCast = GetTime() + end) +) + +DefaultAPL:AddSpell( + Lifebloom:CastableIf(function(self) + return Tank:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and (not Tank:GetAuras():FindMy(Lifebloom):IsUp() or + Tank:GetAuras():FindMy(Lifebloom):GetRemainingTime() <= 4.5) + end):SetTarget(Tank) +) + +DefaultAPL:AddSpell( + Rejuvenation:CastableIf(function(self) + return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Lowest:GetHP() <= 90 and not Player:GetAuras():FindMy(SoulOfTheForestBuff):IsUp() + end):SetTarget(Lowest) +) + +DefaultAPL:AddSpell( + Swiftmend:CastableIf(function(self) + return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Lowest:GetHP() <= 60 + end):SetTarget(Lowest) +) + +DefaultAPL:AddSpell( + WildGrowth:CastableIf(function(self) + return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and (Player:GetAuras():FindMy(SoulOfTheForestBuff):IsUp() or + Player:GetPartyHPAround(30, 90) >= 3) + and not Player:IsMoving() + end):SetTarget(Player) +) + +DefaultAPL:AddSpell( + Regrowth:CastableIf(function(self) + return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Lowest:GetHP() < 70 and + (Player:GetAuras():FindMy(ClearcastingBuff):IsUp() or + NaturesSwiftness:GetTimeSinceLastCast() < 2) + and not Player:IsMoving() + end):SetTarget(Lowest) +) + +DefaultAPL:AddSpell( + CenarionWard:CastableIf(function(self) + return Tank:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Tank:GetHP() <= 90 + end):SetTarget(Tank) +) + +DefaultAPL:AddSpell( + NaturesCure:CastableIf(function(self) + return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Lowest:GetAuras():HasAnyDispelableAura(NaturesCure) + end):SetTarget(Lowest) +) + +-- Cooldown APL +CooldownAPL:AddSpell( + Tranquility:CastableIf(function(self) + return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:GetPartyHPAround(40, 70) >= 3 + end):SetTarget(Player) +) + +CooldownAPL:AddSpell( + Innervate:CastableIf(function(self) + return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:GetPP() <= 80 + end):SetTarget(Player) +) + +CooldownAPL:AddSpell( + Ironbark:CastableIf(function(self) + return Tank:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Tank:GetHP() <= 70 + end):SetTarget(Tank) +) + +CooldownAPL:AddSpell( + NaturesSwiftness:CastableIf(function(self) + return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Lowest:GetHP() < 50 + end):SetTarget(Lowest) +) + +CooldownAPL:AddSpell( + Flourish:CastableIf(function(self) + return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and ShouldUseFlourish() + end):SetTarget(Player) +) + +CooldownAPL:AddSpell( + IncarnationTreeOfLife:CastableIf(function(self) + return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:GetPartyHPAround(40, 80) >= 3 + end):SetTarget(Player) +) + +CooldownAPL:AddSpell( + ConvokeTheSpirits:CastableIf(function(self) + return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:GetAuras():FindMy(ReforestationBuff):GetCount() == 3 + end):SetTarget(Player) +) + +CooldownAPL:AddSpell( + GroveGuardians:CastableIf(function(self) + return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and self:GetCharges() == 3 + end):SetTarget(Player) +) + +-- Module Sync +RestoModule:Sync(function() + if Player:IsAffectingCombat() then + CooldownAPL:Execute() + DefaultAPL:Execute() + end +end) + +Bastion:Register(RestoModule) \ No newline at end of file