Skip to content

Instantly share code, notes, and snippets.

@JonathonAshworth
Last active January 27, 2017 08:39
Show Gist options
  • Save JonathonAshworth/f2a5f59da1139cb855ae578a58299bc2 to your computer and use it in GitHub Desktop.
Save JonathonAshworth/f2a5f59da1139cb855ae578a58299bc2 to your computer and use it in GitHub Desktop.
Frost Death Knight rotation weakaura
aura_env.updateInterval = 0.05
aura_env.lastUpdate = GetTime()
-- SpellID of the spell icon we're showing
aura_env.recommended = 212812
-- How many milliseconds until we should use the next ability
aura_env.recommendedWait = 0
-- Abilities
aura_env.abilities = {
frost_strike = 49143,
howling_blast = 49184,
obliterate = 49020,
remorseless_winter = 196770,
obliteration = 207256,
empower_rune_weapon = 47568,
none = 212812 -- ? icon
}
-- Buffs
aura_env.buffs = {
icy_talons = 194879,
obliteration = 207256,
rime = 59052,
killing_machine = 51124
}
-- Get names for each buff since the WoW API is fucking trash and inexplicably needs them over spellIds for some queries
aura_env.buffNames = {}
for k,v in pairs(aura_env.buffs) do
aura_env.buffNames[v] = GetSpellInfo(v)
end
-- Debuffs
aura_env.debuffs = {
frost_fever = 55095
}
-- Get names of debuffs
aura_env.debuffNames = {}
for k,v in pairs(aura_env.debuffs) do
aura_env.debuffNames[v] = GetSpellInfo(v)
end
-- Call to set recommended, makes code more readable later
function aura_env.recommend(spell, wait)
aura_env.recommended = aura_env.abilities[spell]
aura_env.recommendedWait = wait
end
-- Get the recommended next spell
function aura_env.getRecommendation(runicPower, numRunes, cooldowns, buffDurations, buffCounts, debuffDurations)
-- Priority list implementation is here
-- (1) Build Icy Talons if it's below 3
if runicPower >= 25 and buffCounts["icy_talons"] < 3 then return "frost_strike"
-- (2) Maintain Icy Talons if it's about to drop off
elseif runicPower >= 25 and buffDurations["icy_talons"] < 2 then return "frost_strike"
-- (3) Inflict Frost Fever if it's not up or about to drop off
elseif (numRunes >= 1 or buffDurations["rime"] > 0) and debuffDurations["frost_fever"] < 2 then return "howling_blast"
-- (4) Dump Runic Power if it's going to cap
elseif runicPower >= 70 then return "frost_strike"
-- (5) Use up Rime procs if we're not in Obliteration
elseif buffDurations["rime"] > 0 and buffDurations["obliteration"] == 0 then return "howling_blast"
-- (6) Fire up Obliteration if we have enough resources to sustain it
elseif cooldowns["obliteration"] == 0 and runicPower >= 25 and numRunes >= 2 then return "obliteration"
-- (7) Use up Killing Machine procs
elseif numRunes >= 2 and buffDurations["killing_machine"] > 0 then return "obliterate"
-- (8) Use Frost Strike if Obliteration is up
elseif runicPower >= 25 and buffDurations["obliteration"] > 0 then return "frost_strike"
-- (9) Use Remorseless Winter if it's up
elseif numRunes >= 1 and cooldowns["remorseless_winter"] == 0 then return "remorseless_winter"
-- (10) Use obliterate without a killing machine proc
elseif numRunes >= 2 then return "obliterate"
-- (11) Use frost strike if we have enough runic power
elseif runicPower >= 40 then return "frost_strike"
-- (12) Empower Rune Weapon if we have nothing else to do
elseif cooldowns["empower_rune_weapon"] == 0 then return "empower_rune_weapon"
-- (13) Otherwise do nothing until we have enough RP, runes or procs
else return "none" end
end
-- Simulates waiting for a particular number of seconds
function aura_env.wait(length, runicPower, runes, cooldowns, buffDurations, buffCounts, debuffDurations)
-- sim runic power change (assumes runic attenuation talent)
-- TODO: Other passive runic power changes?
local mainSpd, offSpd = UnitAttackSpeed("player")
local mainRunicPower = length / mainSpd
local offRunicPower = length / offSpd
local newRunicPower = runicPower + mainRunicPower + offRunicPower
-- runes
local newRunes = {}
for k,v in pairs(runes) do
newRunes[k] = v - length
if(newRunes[k] < 0) then newRunes[k] = 0 end
end
-- cooldowns
local newCooldowns = {}
for k,v in pairs(cooldowns) do
newCooldowns[k] = v - length
if(newCooldowns[k] < 0) then newCooldowns[k] = 0 end
end
-- buff durations
local newBuffDurations = {}
for k,v in pairs(buffDurations) do
newBuffDurations[k] = v - length
if(newBuffDurations[k] < 0) then newBuffDurations[k] = 0 end
end
-- buff counts
local newBuffCounts = {}
for k,v in pairs(buffCounts) do
if(newBuffDurations[k] == 0) then newBuffCounts[k] = 0
else newBuffCounts[k] = buffCounts[k] end
end
-- debuff durations
local newDebuffDurations = {}
for k,v in pairs(debuffDurations) do
newDebuffDurations[k] = v - length
if(newDebuffDurations[k] < 0) then newDebuffDurations[k] = 0 end
end
return newRunicPower, newRunes, newCooldowns, newBuffDurations, newBuffCounts, newDebuffDurations
end
-- Takes the rune cooldowns and returns the number of runes that are ready to use
function aura_env.numRunes(runes)
local num = 0
for k,v in pairs(runes) do
if v == 0 then
num = num + 1
end
end
return num
end
-- Custom, Status, Every Frame
function()
-- This function runs on every frame
-- no point updating all the time if the player is running at 300 fps
-- so skip everything if it's already been run in the last n seconds
-- can change update interval in the init section
local now = GetTime()
if now < aura_env.lastUpdate + aura_env.updateInterval then
return true
end
aura_env.lastUpdate = now
local gcdStart, gcdDuration = GetSpellCooldown(61304) -- 61304 = GCD
local gcdEndpoint = gcdStart + gcdDuration
local baselineTime = max( now, gcdEndpoint ) -- "jump" to the end of the GCD if it's active and use that as a baseline for further calculations
-- Get resources
local runicPower = UnitPower("player", SPELL_POWER_RUNIC_POWER)
local runes = {}
for i = 1,6 do
local start, duration = GetRuneCooldown(i)
if start == 0 then
runes[i] = 0
else
runes[i] = start + duration - baselineTime
end
end
-- Get cooldowns
local cooldowns = {}
for k,v in pairs(aura_env.abilities) do
local start, duration = GetSpellCooldown(v)
cooldowns[k] = max(0, start + duration - baselineTime)
end
-- Get relevant buffs
local buffDurations = {}
local buffCounts = {}
for k,v in pairs(aura_env.buffs) do
local _,_,_,count,_,_,expires = UnitBuff("player", aura_env.buffNames[v], nil, 'PLAYER')
if expires == nil then
buffDurations[k] = 0
buffCounts[k] = 0
else
if expires - baselineTime < 0 then
buffDurations[k] = 0
buffCounts[k] = 0
else
buffDurations[k] = expires - baselineTime
buffCounts[k] = count
end
end
end
-- Get relevant debuffs
local debuffDurations = {}
for k,v in pairs(aura_env.debuffs) do
local _,_,_,_,_,_,expires = UnitDebuff("target", aura_env.debuffNames[v], nil, 'PLAYER')
if expires == nil then
debuffDurations[k] = 0
else
debuffDurations[k] = max(0, expires - baselineTime)
end
end
local recommendation = "none"
local waitRecommendation = 0
while recommendation == "none" do
recommendation = aura_env.getRecommendation(runicPower, aura_env.numRunes(runes), cooldowns, buffDurations, buffCounts, debuffDurations)
if recommendation == "none" and waitRecommendation < 5 then
-- wait 0.05 seconds and try again
runicPower, runes, cooldowns, buffDurations, buffCounts, debuffDurations = aura_env.wait(0.05, runicPower, runes, cooldowns, buffDurations, buffCounts, debuffDurations)
waitRecommendation = waitRecommendation + 0.05
end
end
-- If we sim forward 5 seconds and there's still nothing to do then obviously something is fucked, path of frost should never show up
-- Set the recommendation
aura_env.recommend(recommendation, waitRecommendation)
return true
end
function()
local gcdStart, gcdDuration = GetSpellCooldown(61304)
if gcdStart == 0 and gcdDuration == 0 then
if aura_env.recommendedWait == 0 then
return 0,0
else
return gcdDuration + 5, GetTime() + aura_env.recommendedWait
end
else
if aura_env.recommendedWait == 0 then
return gcdDuration, gcdStart + gcdDuration
else
return gcdDuration + 5, gcdStart + gcdDuration + aura_env.recommendedWait
end
end
end
function()
return GetSpellTexture(aura_env.recommended)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment