You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
13 KiB
379 lines
13 KiB
local Tinkr, Bastion = ...
|
|
|
|
local HolyPaladinModule = Bastion.Module:New('HolyPaladin')
|
|
local Player = Bastion.UnitManager:Get('player')
|
|
local Target = Bastion.UnitManager:Get('target')
|
|
local MELEE_RANGE = 5 -- Adjust this value based on your class's melee range
|
|
|
|
-- Initialize SpellBook
|
|
local SpellBook = Bastion.SpellBook:New()
|
|
|
|
-- Power type constant
|
|
local HOLY_POWER = Enum.PowerType.HolyPower
|
|
|
|
-- Healing threshold variable
|
|
local healingThreshold = 90
|
|
|
|
-- Spells
|
|
local AutoAttack = SpellBook:GetSpell(6603)
|
|
local BeaconOfVirtue = SpellBook:GetSpell(200025)
|
|
local BlessingOfSummer = SpellBook:GetSpell(388007)
|
|
local SacredWeapon = SpellBook:GetSpell(383395)
|
|
local Consecration = SpellBook:GetSpell(26573)
|
|
local Judgment = SpellBook:GetSpell(275773)
|
|
local HolyPrism = SpellBook:GetSpell(114165)
|
|
local WordOfGlory = SpellBook:GetSpell(85673)
|
|
local ShieldOfTheRighteous = SpellBook:GetSpell(53600)
|
|
local HolyShock = SpellBook:GetSpell(20473)
|
|
local HolyLight = SpellBook:GetSpell(82326)
|
|
local CrusaderStrike = SpellBook:GetSpell(35395)
|
|
local HammerOfWrath = SpellBook:GetSpell(24275)
|
|
local FlashOfLight = SpellBook:GetSpell(19750)
|
|
local LightOfDawn = SpellBook:GetSpell(85222)
|
|
local DivineShield = SpellBook:GetSpell(642)
|
|
local LayOnHands = SpellBook:GetSpell(633)
|
|
local BlessingOfProtection = SpellBook:GetSpell(1022)
|
|
local BlessingOfSacrifice = SpellBook:GetSpell(6940)
|
|
local AvengingWrath = SpellBook:GetSpell(31884)
|
|
|
|
-- Buffs
|
|
local DivineFavorBuff = SpellBook:GetSpell(388039)
|
|
local InfusionOfLightBuff = SpellBook:GetSpell(54149)
|
|
local ConsecrationBuff = SpellBook:GetSpell(188370)
|
|
|
|
-- 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 BestTarget = Bastion.UnitManager:CreateCustomUnit('besttarget', function()
|
|
local bestMeleeTarget = nil
|
|
local bestRangedTarget = nil
|
|
local highestMeleeHealth = 0
|
|
local highestRangedHealth = 0
|
|
|
|
Bastion.UnitManager:EnumEnemies(function(unit)
|
|
if unit:IsAffectingCombat() and unit:GetDistance(Player) <= 40 and Player:CanSee(unit) then
|
|
local health = unit:GetHealth()
|
|
if unit:GetDistance(Player) <= MELEE_RANGE then
|
|
-- Melee target
|
|
if health > highestMeleeHealth then
|
|
highestMeleeHealth = health
|
|
bestMeleeTarget = unit
|
|
end
|
|
else
|
|
-- Ranged target
|
|
if health > highestRangedHealth then
|
|
highestRangedHealth = health
|
|
bestRangedTarget = unit
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- Return the best melee target if it exists, otherwise return the best ranged target
|
|
return bestMeleeTarget or bestRangedTarget or Target
|
|
end)
|
|
|
|
local ExecuteTarget = Bastion.UnitManager:CreateCustomUnit('executetarget', function()
|
|
local target = nil
|
|
Bastion.UnitManager:EnumEnemies(function(unit)
|
|
if unit:IsAffectingCombat() and unit:GetDistance(Player) <= 30 and Player:CanSee(unit)
|
|
and unit:GetHP() < 20 then
|
|
target = unit
|
|
return true
|
|
end
|
|
end)
|
|
return target or Bastion.UnitManager:Get('none')
|
|
end)
|
|
|
|
-- Custom Functions
|
|
|
|
local function IsInMeleeRange(unit)
|
|
return Player:GetDistance(unit) <= MELEE_RANGE
|
|
end
|
|
|
|
-- Create APLs
|
|
local DefaultAPL = Bastion.APL:New('default')
|
|
local HealingAPL = Bastion.APL:New('healing')
|
|
local DamageAPL = Bastion.APL:New('damage')
|
|
local CooldownAPL = Bastion.APL:New('cooldown')
|
|
local DefensiveAPL = Bastion.APL:New('defensive')
|
|
local ExecuteAPL = Bastion.APL:New('execute')
|
|
local DamagePriorityAPL = Bastion.APL:New('damagepriority')
|
|
|
|
-- Utility function to check if healing is needed
|
|
local function HealingNeeded()
|
|
return Lowest:GetHP() < healingThreshold
|
|
end
|
|
|
|
-- Utility function to check if emergency healing is needed
|
|
local function EmergencyHealingNeeded()
|
|
return Lowest:GetHP() < 50
|
|
end
|
|
|
|
-- Utility function to check if Beacon of Virtue should be cast
|
|
local function ShouldCastBeaconOfVirtue()
|
|
local lowHealthCount = 0
|
|
local totalPartyMembers = 0
|
|
Bastion.UnitManager:EnumFriends(function(unit)
|
|
if unit:GetDistance(Player) <= 40 and Player:CanSee(unit) then
|
|
totalPartyMembers = totalPartyMembers + 1
|
|
if unit:GetHP() < 80 then
|
|
lowHealthCount = lowHealthCount + 1
|
|
end
|
|
end
|
|
end)
|
|
return lowHealthCount >= math.min(3, math.ceil(totalPartyMembers * 0.6))
|
|
end
|
|
|
|
-- Utility function to check if anyone in the party needs healing
|
|
local function AnyoneNeedsHealing()
|
|
local needsHealing = false
|
|
Bastion.UnitManager:EnumFriends(function(unit)
|
|
if unit:GetHP() < healingThreshold then
|
|
needsHealing = true
|
|
return true
|
|
end
|
|
end)
|
|
return needsHealing
|
|
end
|
|
|
|
-- Variables for auto-attack tracking
|
|
local lastAutoAttackTime = 0
|
|
|
|
-- Event handler for auto-attack tracking
|
|
Bastion.Globals.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function()
|
|
local _, subEvent, _, sourceGUID, _, _, _, _, _, _, _, spellID = CombatLogGetCurrentEventInfo()
|
|
if sourceGUID == Player:GetGUID() and (subEvent == "SWING_DAMAGE" or subEvent == "SWING_MISSED") then
|
|
lastAutoAttackTime = GetTime()
|
|
end
|
|
end)
|
|
|
|
-- Function to check if auto-attacking
|
|
local function IsAutoAttacking()
|
|
return GetTime() - lastAutoAttackTime < 2
|
|
end
|
|
|
|
-- Function to check if we're in an aggressive damage phase
|
|
local function AggressiveDamagePhase()
|
|
return Player:GetAuras():FindMy(AvengingWrath):IsUp() or
|
|
Player:GetPower(HOLY_POWER) >= 4 or
|
|
(Player:GetPartyHPAround(40, 90) == 0 and Player:GetHP() > 80)
|
|
end
|
|
|
|
-- Healing APL
|
|
HealingAPL:AddSpell(
|
|
BeaconOfVirtue:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and
|
|
ShouldCastBeaconOfVirtue() and
|
|
Player:GetPower(HOLY_POWER) >= 3 and
|
|
not Player:IsCastingOrChanneling()
|
|
end):SetTarget(Lowest):OnCast(function()
|
|
WordOfGlory:ForceCast(Lowest)
|
|
end)
|
|
)
|
|
|
|
HealingAPL:AddSpell(
|
|
HolyPrism:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and HealingNeeded()
|
|
end):SetTarget(Lowest)
|
|
)
|
|
|
|
HealingAPL:AddSpell(
|
|
WordOfGlory:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and Player:GetPower(HOLY_POWER) >= 3 and HealingNeeded()
|
|
end):SetTarget(Lowest)
|
|
)
|
|
|
|
HealingAPL:AddSpell(
|
|
HolyShock:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and HealingNeeded()
|
|
end):SetTarget(Lowest)
|
|
)
|
|
|
|
HealingAPL:AddSpell(
|
|
LightOfDawn:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and Player:GetPower(HOLY_POWER) >= 3 and Player:GetPartyHPAround(15, healingThreshold) >= 3
|
|
end):SetTarget(Player)
|
|
)
|
|
|
|
HealingAPL:AddSpell(
|
|
FlashOfLight:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and (Player:GetAuras():FindMy(InfusionOfLightBuff):IsUp() or EmergencyHealingNeeded())
|
|
end):SetTarget(Lowest)
|
|
)
|
|
|
|
HealingAPL:AddSpell(
|
|
HolyLight:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and Player:GetAuras():FindMy(DivineFavorBuff):IsUp() and HealingNeeded()
|
|
end):SetTarget(Lowest)
|
|
)
|
|
|
|
-- Damage APL
|
|
DamageAPL:AddSpell(
|
|
AutoAttack:CastableIf(function(self)
|
|
return BestTarget:Exists() and not IsAutoAttacking() and Player:CanSee(BestTarget) and Player:IsWithinCombatDistance(BestTarget, 5)
|
|
end):SetTarget(BestTarget):OnCast(function()
|
|
lastAutoAttackTime = GetTime()
|
|
end)
|
|
)
|
|
|
|
DamageAPL:AddSpell(
|
|
Judgment:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and BestTarget:Exists() and Player:IsWithinCombatDistance(BestTarget, 30) and not Player:IsCastingOrChanneling()
|
|
end):SetTarget(BestTarget)
|
|
)
|
|
|
|
DamageAPL:AddSpell(
|
|
HolyPrism:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and BestTarget:Exists() and Player:IsWithinCombatDistance(BestTarget, 30) and not Player:IsCastingOrChanneling()
|
|
end):SetTarget(BestTarget)
|
|
)
|
|
|
|
DamageAPL:AddSpell(
|
|
CrusaderStrike:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and BestTarget:Exists() and IsInMeleeRange(BestTarget) and not Player:IsCastingOrChanneling()
|
|
end):SetTarget(BestTarget)
|
|
)
|
|
|
|
-- Execute APL
|
|
ExecuteAPL:AddSpell(
|
|
HammerOfWrath:CastableIf(function(self)
|
|
return ExecuteTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
|
|
end):SetTarget(ExecuteTarget)
|
|
)
|
|
|
|
-- Cooldown APL
|
|
CooldownAPL:AddSpell(
|
|
AvengingWrath:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and Player:GetPartyHPAround(40, 75) >= 3
|
|
end):SetTarget(Player)
|
|
)
|
|
|
|
CooldownAPL:AddSpell(
|
|
BlessingOfSummer:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and BestTarget:Exists() and Player:IsWithinCombatDistance(BestTarget, 30) and not Player:IsCastingOrChanneling()
|
|
end):SetTarget(Player)
|
|
)
|
|
|
|
CooldownAPL:AddSpell(
|
|
SacredWeapon:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and BestTarget:Exists() and Player:IsWithinCombatDistance(BestTarget, 30) and not Player:IsCastingOrChanneling()
|
|
end):SetTarget(Player)
|
|
)
|
|
|
|
CooldownAPL:AddSpell(
|
|
Consecration:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and
|
|
not Player:GetAuras():FindMy(ConsecrationBuff):IsUp() and
|
|
BestTarget:Exists() and
|
|
Player:IsWithinCombatDistance(BestTarget, 10) and
|
|
not Player:IsMoving() and
|
|
not Player:IsCastingOrChanneling()
|
|
end):SetTarget(Player)
|
|
)
|
|
|
|
-- Defensive APL
|
|
DefensiveAPL:AddSpell(
|
|
DivineShield:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and Player:GetHP() < 20
|
|
end):SetTarget(Player)
|
|
)
|
|
|
|
DefensiveAPL:AddSpell(
|
|
LayOnHands:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and Lowest:GetHP() < 10
|
|
end):SetTarget(Lowest)
|
|
)
|
|
|
|
DefensiveAPL:AddSpell(
|
|
BlessingOfProtection:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and Lowest:GetHP() < 30 and not Lowest:IsTank()
|
|
end):SetTarget(Lowest)
|
|
)
|
|
|
|
DefensiveAPL:AddSpell(
|
|
BlessingOfSacrifice:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and Tank:GetHP() < 50 and Player:GetHP() > 50
|
|
end):SetTarget(Tank)
|
|
)
|
|
|
|
-- Damage Priority APL
|
|
DamagePriorityAPL:AddSpell(
|
|
Judgment:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and BestTarget:Exists() and Player:IsWithinCombatDistance(BestTarget, 30) and not Player:IsCastingOrChanneling()
|
|
end):SetTarget(BestTarget)
|
|
)
|
|
|
|
DamagePriorityAPL:AddSpell(
|
|
HolyShock:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and BestTarget:Exists() and Player:IsWithinCombatDistance(BestTarget, 40) and not Player:IsCastingOrChanneling()
|
|
end):SetTarget(BestTarget)
|
|
)
|
|
|
|
DamagePriorityAPL:AddSpell(
|
|
CrusaderStrike:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and BestTarget:Exists() and IsInMeleeRange(BestTarget) and not Player:IsCastingOrChanneling()
|
|
end):SetTarget(BestTarget)
|
|
)
|
|
|
|
DamagePriorityAPL:AddSpell(
|
|
ShieldOfTheRighteous:CastableIf(function(self)
|
|
return self:IsKnownAndUsable() and BestTarget:Exists() and IsInMeleeRange(BestTarget) and not Player:IsCastingOrChanneling() and Player:GetPower(HOLY_POWER) >= 3 and not HealingNeeded()
|
|
end):SetTarget(BestTarget)
|
|
)
|
|
|
|
-- Default APL
|
|
DefaultAPL:AddAPL(DefensiveAPL, function() return true end)
|
|
DefaultAPL:AddAPL(CooldownAPL, function() return true end)
|
|
DefaultAPL:AddAPL(HealingAPL, function() return HealingNeeded() end)
|
|
DefaultAPL:AddAPL(ExecuteAPL, function() return true end)
|
|
DefaultAPL:AddAPL(DamagePriorityAPL, function() return not HealingNeeded() and AggressiveDamagePhase() end)
|
|
DefaultAPL:AddAPL(DamageAPL, function() return not HealingNeeded() end)
|
|
|
|
HolyPaladinModule:Sync(function()
|
|
if Player:IsAffectingCombat() then
|
|
healingThreshold = AggressiveDamagePhase() and 85 or 90
|
|
DefaultAPL:Execute()
|
|
else
|
|
healingThreshold = 100
|
|
if AnyoneNeedsHealing() then
|
|
HealingAPL:Execute()
|
|
end
|
|
end
|
|
end)
|
|
|
|
Bastion:Register(HolyPaladinModule) |