@ -14,43 +14,87 @@ local DancingRuneWeapon = SpellBook:GetSpell(49028)
local Tombstone = SpellBook : GetSpell ( 219809 )
local Bonestorm = SpellBook : GetSpell ( 194844 )
local AbominationLimb = SpellBook : GetSpell ( 315443 )
local EmpowerRuneWeapon = SpellBook : GetSpell ( 47568 )
local DeathsCaress = SpellBook : GetSpell ( 195292 )
local RaiseDead = SpellBook : GetSpell ( 46585 )
local BlindingSleet = SpellBook : GetSpell ( 207167 )
local Consumption = SpellBook : GetSpell ( 274156 )
local SoulReaper = SpellBook : GetSpell ( 343294 )
local VampiricBlood = SpellBook : GetSpell ( 55233 )
local IceboundFortitude = SpellBook : GetSpell ( 48792 )
local AntiMagicShell = SpellBook : GetSpell ( 48707 )
local GorefiendGrasp = SpellBook : GetSpell ( 108199 )
local MindFreeze = SpellBook : GetSpell ( 47528 )
local Asphyxiate = SpellBook : GetSpell ( 221562 )
local RaiseAlly = SpellBook : GetSpell ( 61999 )
local AntiMagicZone = SpellBook : GetSpell ( 51052 )
local VampiricBlood = SpellBook : GetSpell ( 55233 )
local DeathGrip = SpellBook : GetSpell ( 49576 )
local GorefiendGrasp = SpellBook : GetSpell ( 108199 )
-- Buffs
local BoneShield = SpellBook : GetSpell ( 195181 )
local DancingRuneWeaponBuff = SpellBook : GetSpell ( 81256 )
local DeathAndDecayBuff = SpellBook : GetSpell ( 188290 )
local Coagulopathy = SpellBook : GetSpell ( 391481 )
local IcyTalons = SpellBook : GetSpell ( 194879 )
-- Debuffs
local BloodPlague = SpellBook : GetSpell ( 55078 )
-- Helper Functions
local function GetEnemiesInRange ( range )
local count = 0
Bastion.UnitManager : EnumEnemies ( function ( unit )
if unit : GetDistance ( Player ) <= range then
if unit : GetDistance ( Player ) <= range and unit : IsAffectingCombat ( ) then
count = count + 1
end
end )
return count
end
local function HasEnoughRunicPower ( cost )
return Player : GetPower ( ) >= cost
local function GetLowestThreatEnemy ( )
local lowestThreatUnit = nil
local lowestThreat = math.huge
Bastion.UnitManager : EnumEnemies ( function ( unit )
if unit : IsAffectingCombat ( ) and unit : GetDistance ( Player ) <= 30 then
local _ , _ , scaledPercent = UnitDetailedThreatSituation ( Player : GetOMToken ( ) , unit : GetOMToken ( ) )
if scaledPercent and scaledPercent < lowestThreat then
lowestThreatUnit = unit
lowestThreat = scaledPercent
end
end
end )
return lowestThreatUnit
end
local function GetBoneShieldStacks ( )
return Player : GetAuras ( ) : FindMy ( BoneShield ) : GetCount ( )
end
local function ShouldUseDeathStrike ( )
local hp = Player : GetHP ( )
local runicPower = Player : GetPower ( )
return hp <= 70 or runicPower > 110 or ( hp <= 85 and runicPower >= 45 )
end
local function GetBestDeathAndDecayLocation ( )
return Bastion.UnitManager : FindEnemiesCentroid ( 10 , 30 )
end
return hp <= 70 or runicPower > 110 or ( hp <= 85 and HasEnoughRunicPower ( 45 ) )
local function ShouldUseBonestorm ( )
return GetBoneShieldStacks ( ) > 10 and
not Player : GetAuras ( ) : FindMy ( DancingRuneWeaponBuff ) : IsUp ( ) and
Player : GetAuras ( ) : FindMy ( DeathAndDecayBuff ) : IsUp ( ) and
Player : GetPower ( ) >= 100 and
DancingRuneWeapon : GetCooldownRemaining ( ) > 0
end
local function GetAvailableRunes ( )
local count = 0
for i = 1 , 6 do
local start , duration , runeReady = GetRuneCooldown ( i )
if runeReady then
count = count + 1
end
end
return count
end
-- Create APLs
@ -58,20 +102,28 @@ local DefaultAPL = Bastion.APL:New('default')
local CooldownAPL = Bastion.APL : New ( ' cooldown ' )
local DefensiveAPL = Bastion.APL : New ( ' defensive ' )
local UtilityAPL = Bastion.APL : New ( ' utility ' )
local ThreatAPL = Bastion.APL : New ( ' threat ' )
-- Utility APL
Utility APL: AddSpell (
BlindingSleet : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and GetEnemiesInRange ( 12 ) >= 3
end ) : SetTarget ( Player )
-- Threat Management APL
Threat APL: AddSpell (
DeathsCaress : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Target : GetDistance ( Player ) > 10
end ) : SetTarget ( Target )
)
Utility APL: AddSpell (
Go ref iendGras p : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and GetEnemiesInRange ( 15 ) >= 3
Threat APL: AddSpell (
Death Grip: CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Target : GetDistance ( Player ) > 10
end ) : SetTarget ( Target )
)
ThreatAPL : AddSpell (
BloodBoil : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and self : GetCharges ( ) > 0 and GetEnemiesInRange ( 10 ) > 1
end ) : SetTarget ( Player )
)
-- Utility APL
UtilityAPL : AddSpell (
MindFreeze : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Target : IsCasting ( ) and Target : IsInterruptible ( )
@ -84,6 +136,12 @@ UtilityAPL:AddSpell(
end ) : SetTarget ( Target )
)
UtilityAPL : AddSpell (
GorefiendGrasp : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and GetEnemiesInRange ( 15 ) >= 3
end ) : SetTarget ( Target )
)
-- Cooldown APL
CooldownAPL : AddSpell (
DancingRuneWeapon : CastableIf ( function ( self )
@ -98,40 +156,51 @@ CooldownAPL:AddSpell(
)
CooldownAPL : AddSpell (
EmpowerRuneWeapon : CastableIf ( function ( self )
Bonestorm : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and ShouldUseBonestorm ( )
end ) : SetTarget ( Player )
)
CooldownAPL : AddSpell (
RaiseDead : CastableIf ( function ( self )
return self : IsKnownAndUsable ( )
end ) : SetTarget ( Player )
)
-- Defensive APL
DefensiveAPL : AddSpell (
AntiMagicShell : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Player : GetHP ( ) <= 7 0
VampiricBlood : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Player : GetHP ( ) <= 6 0
end ) : SetTarget ( Player )
)
DefensiveAPL : AddSpell (
AntiMagicZon e: CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Player : GetHP ( ) <= 5 0
IceboundFortitud e: CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Player : GetHP ( ) <= 4 0
end ) : SetTarget ( Player )
)
DefensiveAPL : AddSpell (
VampiricBlood : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Player : GetHP ( ) <= 6 0
AntiMagicShell : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Player : GetHP ( ) <= 7 0
end ) : SetTarget ( Player )
)
-- Default APL
DefaultAPL : AddSpell (
DeathStrike : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and ShouldUseDeathStrike ( )
end ) : SetTarget ( Target )
DeathAndDecay : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and not Player : GetAuras ( ) : FindMy ( DeathAndDecayBuff ) : IsUp ( ) and GetEnemiesInRange ( 10 ) > 0
end ) : SetTarget ( Player ) : OnCast ( function ( self )
local loc = GetBestDeathAndDecayLocation ( )
if loc then
self : Click ( loc )
end
end )
)
DefaultAPL : AddSpell (
Marrowrend : CastableIf ( function ( self )
local boneShieldCount = Player : GetAuras ( ) : FindMy ( BoneShield ) : GetCount ( )
local boneShieldCount = GetBoneShieldStacks ( )
return self : IsKnownAndUsable ( ) and
( boneShieldCount <= 6 or
( boneShieldCount <= 7 and Player : GetAuras ( ) : FindMy ( BoneShield ) : GetRemainingTime ( ) < 3 ) )
@ -140,37 +209,34 @@ DefaultAPL:AddSpell(
DefaultAPL : AddSpell (
Tombstone : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Player : GetAuras ( ) : FindMy ( BoneShield ) : GetCount ( ) > 6
return self : IsKnownAndUsable ( ) and GetBoneShieldStacks ( ) >= 6
and not Player : GetAuras ( ) : FindMy ( DancingRuneWeaponBuff ) : IsUp ( )
and Player : GetAuras ( ) : FindMy ( DeathAndDecayBuff ) : IsUp ( )
and DancingRuneWeapon : GetCooldownRemaining ( ) > 0
and DancingRuneWeapon : GetCooldownRemaining ( ) > 25
end ) : SetTarget ( Player )
)
DefaultAPL : AddSpell (
Bonestorm : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Player : GetAuras ( ) : FindMy ( BoneShield ) : GetCount ( ) > 11
and not Player : GetAuras ( ) : FindMy ( DancingRuneWeaponBuff ) : IsUp ( )
and Player : GetAuras ( ) : FindMy ( DeathAndDecayBuff ) : IsUp ( )
and HasEnoughRunicPower ( 100 )
and DancingRuneWeapon : GetCooldownRemaining ( ) > 0
end ) : SetTarget ( Player )
BloodBoil : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and self : GetCharges ( ) > 1
end ) : SetTarget ( Target )
)
DefaultAPL : AddSpell (
DeathAndDecay : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and not Player : GetAuras ( ) : FindMy ( DeathAndDecayBuff ) : IsUp ( )
end ) : SetTarget ( Player ) : OnCast ( function ( self )
local loc = Bastion.UnitManager : FindEnemiesCentroid ( 10 , 30 )
if loc then
self : Click ( loc )
end
end )
DeathStrike : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and ShouldUseDeathStrike ( )
end ) : SetTarget ( Target )
)
DefaultAPL : AddSpell (
BloodBoil : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and self : GetCharges ( ) > 1
Consumption : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and GetAvailableRunes ( ) >= 2
end ) : SetTarget ( Target )
)
DefaultAPL : AddSpell (
SoulReaper : CastableIf ( function ( self )
return self : IsKnownAndUsable ( ) and Target : GetHP ( ) <= 35
end ) : SetTarget ( Target )
)
@ -180,113 +246,62 @@ DefaultAPL:AddSpell(
end ) : SetTarget ( Target )
)
-- Opener sequence
local OpenerSequence = Bastion.Sequencer : New ( {
function ( self )
if DeathAndDecay : IsKnownAndUsable ( ) then
DeathAndDecay : Cast ( Player ) : OnCast ( function ( self )
local loc = Bastion.UnitManager : FindEnemiesCentroid ( 10 , 30 )
if loc then
self : Click ( loc )
end
end )
return true
end
return false
end ,
function ( self )
if DeathsCaress : IsKnownAndUsable ( ) then
DeathsCaress : Cast ( Target )
return true
end
return false
end ,
function ( self )
if RaiseDead : IsKnownAndUsable ( ) then
RaiseDead : Cast ( Player )
return true
-- Main rotation logic
BloodDKModule : Sync ( function ( )
-- Check if the player is mounted
if IsMounted ( ) or Player : IsMounted ( ) then
return -- Exit the function if mounted, pausing the rotation
end
return false
end ,
function ( self )
if DancingRuneWeapon : IsKnownAndUsable ( ) then
DancingRuneWeapon : Cast ( Player )
if not Player : IsAffectingCombat ( ) then
if not Target : Exists ( ) or Target : IsDead ( ) then
Bastion.UnitManager : EnumEnemies ( function ( unit )
if unit : IsAlive ( ) and unit : GetDistance ( Player ) <= 30 then
Target = unit
return true
end
return false
end ,
function ( self )
if BloodBoil : IsKnownAndUsable ( ) then
BloodBoil : Cast ( Target )
return true
end )
end
return false
end ,
function ( self )
if Tombstone : IsKnownAndUsable ( ) then
Tombstone : Cast ( Player )
return true
return
end
return false
end ,
function ( self )
if HeartStrike : IsKnownAndUsable ( ) then
HeartStrike : Cast ( Target )
-- Dynamic target selection and threat management
local lowestThreatEnemy = GetLowestThreatEnemy ( )
if lowestThreatEnemy then
Target = lowestThreatEnemy
elseif not Target : Exists ( ) or Target : IsDead ( ) or Target : GetDistance ( Player ) > 30 then
Bastion.UnitManager : EnumEnemies ( function ( unit )
if unit : IsAlive ( ) and unit : GetDistance ( Player ) <= 30 and unit : IsAffectingCombat ( ) then
Target = unit
return true
end
return false
end ,
function ( self )
if DeathStrike : IsKnownAndUsable ( ) and ShouldUseDeathStrike ( ) then
DeathStrike : Cast ( Target )
return true
end )
end
return false
end ,
function ( self )
if HeartStrike : IsKnownAndUsable ( ) then
HeartStrike : Cast ( Target )
return true
ThreatAPL : Execute ( )
DefensiveAPL : Execute ( )
UtilityAPL : Execute ( )
CooldownAPL : Execute ( )
-- AoE threat management
if GetEnemiesInRange ( 10 ) > 1 and BloodBoil : IsKnownAndUsable ( ) and BloodBoil : GetCharges ( ) > 0 then
BloodBoil : Cast ( Player )
end
return false
end ,
function ( self )
if BloodBoil : IsKnownAndUsable ( ) then
-- Single target threat management
if Target : Exists ( ) and not Target : GetAuras ( ) : FindMy ( BloodPlague ) : IsUp ( ) then
if Target : GetDistance ( Player ) <= 10 then
BloodBoil : Cast ( Target )
return true
end
return false
end ,
function ( self )
if DeathStrike : IsKnownAndUsable ( ) and ShouldUseDeathStrike ( ) then
DeathStrike : Cast ( Target )
return true
elseif DeathsCaress : IsKnownAndUsable ( ) then
DeathsCaress : Cast ( Target )
end
return false
end ,
function ( self )
if Marrowrend : IsKnownAndUsable ( ) then
Marrowrend : Cast ( Target )
return true
end
return false
end ,
} , function ( )
return not Player : IsAffectingCombat ( )
end )
DefaultAPL : AddSequence ( OpenerSequence , function ( )
return not Player : IsAffectingCombat ( )
end )
BloodDKModule : Sync ( function ( )
if not Player : IsAffectingCombat ( ) then
return
-- Maintain Coagulopathy and Icy Talons
if Player : GetAuras ( ) : FindMy ( Coagulopathy ) : GetRemainingTime ( ) < 2 or Player : GetAuras ( ) : FindMy ( IcyTalons ) : GetRemainingTime ( ) < 2 then
DeathStrike : Cast ( Target )
end
DefensiveAPL : Execute ( )
UtilityAPL : Execute ( )
CooldownAPL : Execute ( )
DefaultAPL : Execute ( )
end )