Basic rotations that work
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.
OkRotations/BloodDK.lua

308 lines
9.4 KiB

local Tinkr, Bastion = ...
local BloodDKModule = Bastion.Module:New('BloodDeathKnight')
local Player = Bastion.UnitManager:Get('player')
local Target = Bastion.UnitManager:Get('target')
local SpellBook = Bastion.SpellBook:New()
-- Spells
local DeathStrike = SpellBook:GetSpell(49998)
local Marrowrend = SpellBook:GetSpell(195182)
local HeartStrike = SpellBook:GetSpell(206930)
local BloodBoil = SpellBook:GetSpell(50842)
local DeathAndDecay = SpellBook:GetSpell(43265)
local DancingRuneWeapon = SpellBook:GetSpell(49028)
local Tombstone = SpellBook:GetSpell(219809)
local Bonestorm = SpellBook:GetSpell(194844)
local AbominationLimb = SpellBook:GetSpell(315443)
local DeathsCaress = SpellBook:GetSpell(195292)
local RaiseDead = SpellBook:GetSpell(46585)
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 MindFreeze = SpellBook:GetSpell(47528)
local Asphyxiate = SpellBook:GetSpell(221562)
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 and unit:IsAffectingCombat() then
count = count + 1
end
end)
return count
end
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
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
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')
-- Threat Management APL
ThreatAPL:AddSpell(
DeathsCaress:CastableIf(function(self)
return self:IsKnownAndUsable() and Target:GetDistance(Player) > 10
end):SetTarget(Target)
)
ThreatAPL:AddSpell(
DeathGrip: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()
end):SetTarget(Target)
)
UtilityAPL:AddSpell(
Asphyxiate:CastableIf(function(self)
return self:IsKnownAndUsable() and not Target:IsStunned()
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)
return self:IsKnownAndUsable() and not Player:GetAuras():FindMy(DancingRuneWeaponBuff):IsUp()
end):SetTarget(Player)
)
CooldownAPL:AddSpell(
AbominationLimb:CastableIf(function(self)
return self:IsKnownAndUsable()
end):SetTarget(Player)
)
CooldownAPL:AddSpell(
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(
VampiricBlood:CastableIf(function(self)
return self:IsKnownAndUsable() and Player:GetHP() <= 60
end):SetTarget(Player)
)
DefensiveAPL:AddSpell(
IceboundFortitude:CastableIf(function(self)
return self:IsKnownAndUsable() and Player:GetHP() <= 40
end):SetTarget(Player)
)
DefensiveAPL:AddSpell(
AntiMagicShell:CastableIf(function(self)
return self:IsKnownAndUsable() and Player:GetHP() <= 70
end):SetTarget(Player)
)
-- Default APL
DefaultAPL:AddSpell(
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 = GetBoneShieldStacks()
return self:IsKnownAndUsable() and
(boneShieldCount <= 6 or
(boneShieldCount <= 7 and Player:GetAuras():FindMy(BoneShield):GetRemainingTime() < 3))
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
Tombstone:CastableIf(function(self)
return self:IsKnownAndUsable() and GetBoneShieldStacks() >= 6
and not Player:GetAuras():FindMy(DancingRuneWeaponBuff):IsUp()
and Player:GetAuras():FindMy(DeathAndDecayBuff):IsUp()
and DancingRuneWeapon:GetCooldownRemaining() > 25
end):SetTarget(Player)
)
DefaultAPL:AddSpell(
BloodBoil:CastableIf(function(self)
return self:IsKnownAndUsable() and self:GetCharges() > 1
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
DeathStrike:CastableIf(function(self)
return self:IsKnownAndUsable() and ShouldUseDeathStrike()
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
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)
)
DefaultAPL:AddSpell(
HeartStrike:CastableIf(function(self)
return self:IsKnownAndUsable()
end):SetTarget(Target)
)
-- 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
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
end)
end
return
end
-- 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
end)
end
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
-- Single target threat management
if Target:Exists() and not Target:GetAuras():FindMy(BloodPlague):IsUp() then
if Target:GetDistance(Player) <= 10 then
BloodBoil:Cast(Target)
elseif DeathsCaress:IsKnownAndUsable() then
DeathsCaress:Cast(Target)
end
end
-- Maintain Coagulopathy and Icy Talons
if Player:GetAuras():FindMy(Coagulopathy):GetRemainingTime() < 2 or Player:GetAuras():FindMy(IcyTalons):GetRemainingTime() < 2 then
DeathStrike:Cast(Target)
end
DefaultAPL:Execute()
end)
Bastion:Register(BloodDKModule)