local Tinkr, Bastion = ... local DiscPriestModule = Bastion.Module:New('DiscPriest') local Player = Bastion.UnitManager:Get('player') local Target = Bastion.UnitManager:Get('target') -- Initialize SpellBook local SpellBook = Bastion.SpellBook:New() -- Spells local PowerWordShield = SpellBook:GetSpell(17) local Penance = SpellBook:GetSpell(47540) local PowerWordRadiance = SpellBook:GetSpell(194509) local Shadowfiend = SpellBook:GetSpell(34433) local Mindbender = SpellBook:GetSpell(123040) local Rapture = SpellBook:GetSpell(47536) local PainSuppression = SpellBook:GetSpell(33206) local PowerWordBarrier = SpellBook:GetSpell(62618) local Schism = SpellBook:GetSpell(214621) local ShadowCovenant = SpellBook:GetSpell(314867) local MindBlast = SpellBook:GetSpell(8092) local ShadowWordDeath = SpellBook:GetSpell(32379) local Smite = SpellBook:GetSpell(585) local FlashHeal = SpellBook:GetSpell(2061) local Renew = SpellBook:GetSpell(139) local Fade = SpellBook:GetSpell(586) local DesperatePrayer = SpellBook:GetSpell(19236) local VoidwraithTalent = SpellBook:GetSpell(406786) local Voidwraith = SpellBook:GetSpell(406786) -- Buffs and Debuffs local Atonement = SpellBook:GetSpell(194384) local PowerOfTheDarkSide = SpellBook:GetSpell(198068) local ShadowCovenantBuff = SpellBook:GetSpell(322105) local WeakenedSoul = SpellBook:GetSpell(6788) -- 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) local AtoneTarget = Bastion.UnitManager:CreateCustomUnit('atonetarget', function(unit) local target = nil local lowestAtonementTime = 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 atonementBuff = unit:GetAuras():FindMy(Atonement) if not atonementBuff:IsUp() then if unit:GetHP() >= 70 and unit:GetHP() <= 90 then target = unit return true end elseif atonementBuff:GetRemainingTime() < lowestAtonementTime then target = unit lowestAtonementTime = atonementBuff:GetRemainingTime() end end) return target or Player end) -- Target the highest HP enemy for DPS APL local HighestHPTarget = Bastion.UnitManager:CreateCustomUnit('highesthptarget', function(unit) local target = nil local highestHP = 0 Bastion.UnitManager:EnumEnemies(function(unit) if unit:IsAffectingCombat() and Player:IsWithinCombatDistance(unit, 40) and Player:CanSee(unit) then local hp = unit:GetHP() if hp > highestHP then target = unit highestHP = hp end end end) return target or Target end) -- APLs local DefaultAPL = Bastion.APL:New('default') local CooldownAPL = Bastion.APL:New('cooldown') local DefensiveAPL = Bastion.APL:New('defensive') local DpsAPL = Bastion.APL:New('dps') -- Helper Functions local function ShouldUseRadiance() local countWithoutAtonement = 0 Bastion.UnitManager:EnumFriends(function(unit) if not unit:IsDead() and Player:GetDistance(unit) <= 40 and Player:CanSee(unit) and not unit:GetAuras():FindMy(Atonement):IsUp() then countWithoutAtonement = countWithoutAtonement + 1 end end) return countWithoutAtonement >= 3 end -- Default APL DefaultAPL:AddSpell( PowerWordShield:CastableIf(function(self) return AtoneTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not AtoneTarget:GetAuras():FindMy(PowerWordShield):IsUp() and not AtoneTarget:GetAuras():FindMy(WeakenedSoul):IsUp() end):SetTarget(AtoneTarget) ) DefaultAPL:AddSpell( PowerWordRadiance:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and ShouldUseRadiance() end):SetTarget(Player) ) DefaultAPL:AddSpell( Penance:CastableIf(function(self) return AtoneTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not AtoneTarget:GetAuras():FindMy(Atonement):IsUp() end):SetTarget(AtoneTarget) ) DefaultAPL:AddSpell( Renew:CastableIf(function(self) return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Lowest:GetHP() < 90 and not Lowest:GetAuras():FindMy(Renew):IsUp() end):SetTarget(Lowest) ) DefaultAPL:AddSpell( FlashHeal:CastableIf(function(self) return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Lowest:GetHP() < 70 and not Lowest:GetAuras():FindMy(Atonement):IsUp() end):SetTarget(Lowest) ) -- Cooldown APL CooldownAPL:AddSpell( Rapture:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(40, 75) >= 3 end):SetTarget(Player) ) CooldownAPL:AddSpell( PowerWordBarrier:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(40, 70) >= 3 end):SetTarget(Player) ) CooldownAPL:AddSpell( ShadowCovenant:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(40, 80) >= 3 end):SetTarget(Player) ) CooldownAPL:AddSpell( Shadowfiend:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not VoidwraithTalent:IsKnownAndUsable() end):SetTarget(HighestHPTarget) ) CooldownAPL:AddSpell( Voidwraith:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(HighestHPTarget) ) -- Defensive APL DefensiveAPL:AddSpell( Fade:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetHP() < 90 end):SetTarget(Player) ) DefensiveAPL:AddSpell( DesperatePrayer:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetHP() < 50 end):SetTarget(Player) ) DefensiveAPL:AddSpell( PainSuppression:CastableIf(function(self) return Tank:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Tank:GetHP() < 40 end):SetTarget(Tank) ) -- DPS APL DpsAPL:AddSpell( Schism:CastableIf(function(self) return HighestHPTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsWithinCombatDistance(HighestHPTarget, 40) end):SetTarget(HighestHPTarget) ) DpsAPL:AddSpell( Penance:CastableIf(function(self) return HighestHPTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsWithinCombatDistance(HighestHPTarget, 40) end):SetTarget(HighestHPTarget) ) DpsAPL:AddSpell( MindBlast:CastableIf(function(self) return HighestHPTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsWithinCombatDistance(HighestHPTarget, 40) end):SetTarget(HighestHPTarget) ) DpsAPL:AddSpell( ShadowWordDeath:CastableIf(function(self) return HighestHPTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and HighestHPTarget:GetHP() < 20 and Player:IsWithinCombatDistance(HighestHPTarget, 40) end):SetTarget(HighestHPTarget) ) DpsAPL:AddSpell( Smite:CastableIf(function(self) return HighestHPTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsWithinCombatDistance(HighestHPTarget, 40) end):SetTarget(HighestHPTarget) ) -- Module Sync DiscPriestModule:Sync(function() if Player:IsMounted() then return end -- Prioritize Defensive APL DefensiveAPL:Execute() if Player:IsAffectingCombat() then -- Prioritize cooldowns if necessary CooldownAPL:Execute() -- Apply Atonement to targets before proceeding with DPS if AtoneTarget:Exists() and not AtoneTarget:GetAuras():FindMy(Atonement):IsUp() then if not AtoneTarget:GetAuras():FindMy(PowerWordShield):IsUp() and not AtoneTarget:GetAuras():FindMy(WeakenedSoul):IsUp() then PowerWordShield:Cast(AtoneTarget) elseif AtoneTarget:GetHP() <= 90 and not AtoneTarget:GetAuras():FindMy(Renew):IsUp() then Renew:Cast(AtoneTarget) elseif AtoneTarget:GetHP() <= 80 then FlashHeal:Cast(AtoneTarget) elseif AtoneTarget:GetAuras():FindMy(Atonement):IsUp() and Penance:IsKnownAndUsable() then Penance:Cast(AtoneTarget) end end -- Execute Default and DPS APLs DefaultAPL:Execute() DpsAPL:Execute() else -- Out of combat healing and preparation if AtoneTarget:Exists() and not AtoneTarget:GetAuras():FindMy(Atonement):IsUp() then if not AtoneTarget:GetAuras():FindMy(PowerWordShield):IsUp() and not AtoneTarget:GetAuras():FindMy(WeakenedSoul):IsUp() then PowerWordShield:Cast(AtoneTarget) elseif AtoneTarget:GetHP() <= 90 and not AtoneTarget:GetAuras():FindMy(Renew):IsUp() then Renew:Cast(AtoneTarget) elseif AtoneTarget:GetHP() <= 80 then FlashHeal:Cast(AtoneTarget) elseif AtoneTarget:GetAuras():FindMy(Atonement):IsUp() and Penance:IsKnownAndUsable() then Penance:Cast(AtoneTarget) end end -- Top off teammates' health to 100% Bastion.UnitManager:EnumFriends(function(unit) if unit:GetHP() < 100 and Player:CanSee(unit) and Player:GetDistance(unit) <= 40 then if not unit:GetAuras():FindMy(WeakenedSoul):IsUp() and PowerWordShield:IsKnownAndUsable() then PowerWordShield:Cast(unit) elseif FlashHeal:IsKnownAndUsable() then FlashHeal:Cast(unit) elseif Renew:IsKnownAndUsable() and not unit:GetAuras():FindMy(Renew):IsUp() then Renew:Cast(unit) end end end) -- Prepare for combat by applying buffs and debuffs if Target:Exists() and Target:IsEnemy() and PurgeTheWicked:IsKnownAndUsable() and not Player:IsCastingOrChanneling() then if not Target:GetAuras():FindMy(PurgeTheWickedDebuff):IsUp() and Player:IsWithinCombatDistance(Target, 40) then PurgeTheWicked:Cast(Target) end end end end) -- Register the DiscPriest module with Bastion Bastion:Register(DiscPriestModule)