/branches
-- ---------------------- |
-- ---------------------- |
-- NeedToKnow |
-- by Kitjan, lieandswell |
-- ---------------------- |
if not trace then trace = print end |
--function maybe_trace(...) |
--local so_far = "" |
--local p = _G |
--for idx = 1,40,1 do |
--local v = select(idx,...) |
--if not v then |
--break |
--end |
--p = p[v] |
--if not p then |
--if so_far == "" then |
--trace("global variable",v,"does not exist") |
--else |
--trace(so_far,"does not have member",v) |
--end |
--return; |
--end |
--so_far = so_far .. "." .. v |
--end |
--trace(so_far,"=",p) |
--end |
-- |
-- ------------- |
-- ADDON GLOBALS |
-- ------------- |
-- NEEDTOKNOW = {} is defined in the localization file, which must be loaded before this file |
NEEDTOKNOW.VERSION = "3.2.0" |
NEEDTOKNOW.VERSION = "3.3.00" |
NEEDTOKNOW.UPDATE_INTERVAL = 0.05 |
NEEDTOKNOW.MAXBARS = 20 |
-- Get the localized name of spell 75, which is "Auto Shot" in US English |
NEEDTOKNOW.AUTO_SHOT = GetSpellInfo(75) |
-- COMBAT_LOG_EVENT_UNFILTERED events where select(6,...) is the caster, 9 is the spellid, and 10 is the spell name |
-- (used for Target-of-target monitoring) |
NEEDTOKNOW.AURAEVENTS = { |
blink_boss = false, |
blink_label = "", |
buffcd_duration = 0, |
buffcd_reset_spells = "", |
usable_duration = 0, |
append_cd = true, |
append_usable = false, |
FixedDuration = nil, |
} |
NEEDTOKNOW.DEFAULTS = { |
Version = NEEDTOKNOW.VERSION, |
Version = NEEDTOKNOW.VERSION, |
OldVersion = NEEDTOKNOW.VERSION, |
Profiles = {}, |
Chars = {}, |
BarPadding = 3, |
} |
-- ------------------- |
-- SharedMedia Support |
-- ------------------- |
NeedToKnow.LSM = LibStub("LibSharedMedia-3.0", true) |
NeedToKnow.LSM = LibStub("LibSharedMedia-3.0", true) |
if not NeedToKnow.LSM:Fetch("statusbar", "Aluminum", true) then NeedToKnow.LSM:Register("statusbar", "Aluminum", [[Interface\Addons\NeedToKnow\Textures\Aluminum.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Armory", true) then NeedToKnow.LSM:Register("statusbar", "Armory", [[Interface\Addons\NeedToKnow\Textures\Armory.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "BantoBar", true) then NeedToKnow.LSM:Register("statusbar", "BantoBar", [[Interface\Addons\NeedToKnow\Textures\BantoBar.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "DarkBottom", true) then NeedToKnow.LSM:Register("statusbar", "DarkBottom", [[Interface\Addons\NeedToKnow\Textures\Darkbottom.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Default", true) then NeedToKnow.LSM:Register("statusbar", "Default", [[Interface\Addons\NeedToKnow\Textures\Default.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Flat", true) then NeedToKnow.LSM:Register("statusbar", "Flat", [[Interface\Addons\NeedToKnow\Textures\Flat.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Glaze", true) then NeedToKnow.LSM:Register("statusbar", "Glaze", [[Interface\Addons\NeedToKnow\Textures\Glaze.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Gloss", true) then NeedToKnow.LSM:Register("statusbar", "Gloss", [[Interface\Addons\NeedToKnow\Textures\Gloss.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Graphite", true) then NeedToKnow.LSM:Register("statusbar", "Graphite", [[Interface\Addons\NeedToKnow\Textures\Graphite.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Minimalist", true) then NeedToKnow.LSM:Register("statusbar", "Minimalist", [[Interface\Addons\NeedToKnow\Textures\Minimalist.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Otravi", true) then NeedToKnow.LSM:Register("statusbar", "Otravi", [[Interface\Addons\NeedToKnow\Textures\Otravi.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Smooth", true) then NeedToKnow.LSM:Register("statusbar", "Smooth", [[Interface\Addons\NeedToKnow\Textures\Smooth.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Smooth v2", true) then NeedToKnow.LSM:Register("statusbar", "Smooth v2", [[Interface\Addons\NeedToKnow\Textures\Smoothv2.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Striped", true) then NeedToKnow.LSM:Register("statusbar", "Striped", [[Interface\Addons\NeedToKnow\Textures\Striped.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Aluminum", true) then NeedToKnow.LSM:Register("statusbar", "Aluminum", [[Interface\Addons\NeedToKnow\Textures\Aluminum.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Armory", true) then NeedToKnow.LSM:Register("statusbar", "Armory", [[Interface\Addons\NeedToKnow\Textures\Armory.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "BantoBar", true) then NeedToKnow.LSM:Register("statusbar", "BantoBar", [[Interface\Addons\NeedToKnow\Textures\BantoBar.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "DarkBottom", true) then NeedToKnow.LSM:Register("statusbar", "DarkBottom", [[Interface\Addons\NeedToKnow\Textures\Darkbottom.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Default", true) then NeedToKnow.LSM:Register("statusbar", "Default", [[Interface\Addons\NeedToKnow\Textures\Default.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Flat", true) then NeedToKnow.LSM:Register("statusbar", "Flat", [[Interface\Addons\NeedToKnow\Textures\Flat.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Glaze", true) then NeedToKnow.LSM:Register("statusbar", "Glaze", [[Interface\Addons\NeedToKnow\Textures\Glaze.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Gloss", true) then NeedToKnow.LSM:Register("statusbar", "Gloss", [[Interface\Addons\NeedToKnow\Textures\Gloss.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Graphite", true) then NeedToKnow.LSM:Register("statusbar", "Graphite", [[Interface\Addons\NeedToKnow\Textures\Graphite.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Minimalist", true) then NeedToKnow.LSM:Register("statusbar", "Minimalist", [[Interface\Addons\NeedToKnow\Textures\Minimalist.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Otravi", true) then NeedToKnow.LSM:Register("statusbar", "Otravi", [[Interface\Addons\NeedToKnow\Textures\Otravi.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Smooth", true) then NeedToKnow.LSM:Register("statusbar", "Smooth", [[Interface\Addons\NeedToKnow\Textures\Smooth.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Smooth v2", true) then NeedToKnow.LSM:Register("statusbar", "Smooth v2", [[Interface\Addons\NeedToKnow\Textures\Smoothv2.tga]]) end |
if not NeedToKnow.LSM:Fetch("statusbar", "Striped", true) then NeedToKnow.LSM:Register("statusbar", "Striped", [[Interface\Addons\NeedToKnow\Textures\Striped.tga]]) end |
-- --------------- |
-- EXECUTIVE FRAME |
-- --------------- |
end |
end |
function NeedToKnow.ExecutiveFrame_UNIT_SPELLCAST_SUCCEEDED(unit, spell, rank) |
if unit == "player" then |
local r = NeedToKnow.last_cast[spell] |
end |
end |
function NeedToKnow.ExecutiveFrame_COMBAT_LOG_EVENT_UNFILTERED(tod, event, guidCaster, ...) |
-- the time that's passed in appears to be time of day, not game time like everything else. |
local time = GetTime() |
NeedToKnow.last_cast = {} -- [spell][guidTarget] = { time, dur } |
NeedToKnow.nSent = 0 |
NeedToKnow.totem_drops = {} -- array 1-4 of precise times the totems appeared |
NeedToKnow.weapon_enchants = { mhand = {}, ohand = {} } |
SlashCmdList["NEEDTOKNOW"] = NeedToKnow.SlashCommand |
SLASH_NEEDTOKNOW1 = "/needtoknow" |
end |
end |
function NeedToKnow.ExecutiveFrame_PLAYER_LOGIN() |
NeedToKnowLoader.SafeUpgrade() |
NeedToKnow.ExecutiveFrame_PLAYER_TALENT_UPDATE() |
NeedToKnow.ExecutiveFrame_ADDON_LOADED = nil |
NeedToKnow.ExecutiveFrame_PLAYER_LOGIN = nil |
NeedToKnowLoader = nil |
NeedToKnow.UpdateWeaponEnchants() |
end |
function NeedToKnow.ExecutiveFrame_PLAYER_TALENT_UPDATE() |
local spec = GetActiveTalentGroup() |
if NeedToKnow.CharSettings then |
local spec = GetActiveTalentGroup() |
local profile = NeedToKnow.CharSettings.Specs[spec] |
if not profile then |
profile = NeedToKnow.CreateProfile(CopyTable(NEEDTOKNOW.PROFILE_DEFAULTS), spec) |
local profile = NeedToKnow.CharSettings.Specs[spec] |
if not profile then |
profile = NeedToKnow.CreateProfile(CopyTable(NEEDTOKNOW.PROFILE_DEFAULTS), spec) |
end |
NeedToKnow.ChangeProfile(profile); |
end |
NeedToKnow.ChangeProfile(profile); |
end |
function NeedToKnow.RemoveDefaultValues(t, def, k) |
if not k then k = "" end |
if not def then |
end |
function NeedToKnow.CompressProfile(profileSettings) |
for k,p in pairs(NeedToKnow_Globals.Profiles) do |
if p == profileSettings then |
trace("Compressing",k) |
end |
end |
-- Remove unused bars/groups |
for iG,vG in ipairs(profileSettings["Groups"]) do |
if iG > profileSettings.nGroups then |
end |
-- DEBUG: remove k, it's just for debugging |
function NeedToKnow.AddDefaultsToTable(t, def, k) |
if type(t) ~= "table" then return end |
if not def then |
return |
end |
if not k then k = "" end |
local n = table.maxn(t) |
if n > 0 then |
if type(t) ~= "table" then return end |
if not def then |
return |
end |
if not k then k = "" end |
local n = table.maxn(t) |
if n > 0 then |
for i=1,n do |
local rhs = def[i] |
if not rhs then rhs = def[1] end |
if not t[i] then |
t[i] = NeedToKnow.deepcopy(rhs) |
else |
NeedToKnow.AddDefaultsToTable(t[i], rhs, k .. " " .. i) |
end |
local rhs = def[i] |
if not rhs then rhs = def[1] end |
if not t[i] then |
t[i] = NeedToKnow.DeepCopy(rhs) |
else |
NeedToKnow.AddDefaultsToTable(t[i], rhs, k .. " " .. i) |
end |
end |
else |
else |
for kD,vD in pairs(def) do |
if not t[kD] then |
t[kD] = NeedToKnow.deepcopy(vD) |
else |
NeedToKnow.AddDefaultsToTable(t[kD], vD, k .. " " .. kD) |
end |
if not t[kD] then |
if type(vD) == "table" then |
t[kD] = NeedToKnow.DeepCopy(vD) |
else |
t[kD] = vD |
end |
else |
NeedToKnow.AddDefaultsToTable(t[kD], vD, k .. " " .. kD) |
end |
end |
end |
end |
end |
function NeedToKnow.UncompressProfile(profileSettings) |
end |
end |
NeedToKnow.AddDefaultsToTable(profileSettings, NEEDTOKNOW.PROFILE_DEFAULTS) |
for k,p in pairs(NeedToKnow_Globals.Profiles) do |
if p == profileSettings then |
trace("Uncompressing",k) |
end |
end |
NeedToKnow.AddDefaultsToTable(profileSettings, NEEDTOKNOW.PROFILE_DEFAULTS) |
if ( not profileSettings["BarFont"] or profileSettings["BarFont"] == "DEFAULT" ) then |
profileSettings["BarFont"] = GameFontHighlight:GetFont() |
end |
-- fill in any missing defaults |
NeedToKnow.UncompressProfile(NeedToKnow.ProfileSettings) |
-- Hide any groups not in use |
local iGroup = NeedToKnow.ProfileSettings.nGroups + 1 |
while true do |
end |
for iS,vS in pairs(NeedToKnow_Globals.Profiles) do |
-- DEBUG: This is just to debug the uncompress/compress code by forcing it to happen |
NeedToKnow.UncompressProfile(vS) |
if vS.bUncompressed then |
NeedToKnow.CompressProfile(vS) |
-- Copies anything (int, table, whatever). Unlike CopyTable, deepcopy can |
-- recreate a recursive reference structure (CopyTable will stack overflow.) |
-- Copied from http://lua-users.org/wiki/CopyTable |
function NeedToKnow.deepcopy(object) |
local lookup_table = {} |
local function _copy(object) |
if type(object) ~= "table" then |
return object |
elseif lookup_table[object] then |
return lookup_table[object] |
end |
function NeedToKnow.DeepCopy(object) |
if type(object) ~= "table" then |
return object |
else |
local new_table = {} |
lookup_table[object] = new_table |
for index, value in pairs(object) do |
new_table[_copy(index)] = _copy(value) |
for k,v in pairs(object) do |
new_table[k] = NeedToKnow.DeepCopy(v) |
end |
return setmetatable(new_table, getmetatable(object)) |
return new_table |
end |
return _copy(object) |
end |
---- Copies anything (int, table, whatever). Unlike DeepCopy (and CopyTable), CopyRefGraph can |
---- recreate a recursive reference structure (CopyTable will stack overflow.) |
---- Copied from http://lua-users.org/wiki/CopyTable |
--function NeedToKnow.CopyRefGraph(object) |
--local lookup_table = {} |
--local function _copy(object) |
--if type(object) ~= "table" then |
--return object |
--elseif lookup_table[object] then |
--return lookup_table[object] |
--end |
--local new_table = {} |
--lookup_table[object] = new_table |
--for index, value in pairs(object) do |
--new_table[_copy(index)] = _copy(value) |
--end |
--return setmetatable(new_table, getmetatable(object)) |
--end |
--return _copy(object) |
--end |
function NeedToKnow.Update() |
if UnitExists("player") and NeedToKnow.ProfileSettings then |
for groupID = 1, NeedToKnow.ProfileSettings.nGroups do |
end |
end |
function NeedToKnow.Show(bShow) |
NeedToKnow_Visible = bShow |
for groupID = 1, NeedToKnow.ProfileSettings.nGroups do |
NeedToKnow.ClearScripts(bar) |
end |
end |
local resizeButton = _G[groupName.."ResizeButton"] |
resizeButton:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", 8, -8) |
break |
end |
end |
if ( NeedToKnow.CharSettings["Locked"] ) then |
resizeButton:Hide() |
else |
-- BARS |
-- ---- |
-- Attempt to figure out if a name is an item or a spell, and if a spell |
-- try to choose a spell with that name that has a cooldown |
-- This may fail for valid names if the client doesn't have the data for |
-- that spell yet (just logged in or changed talent specs), in which case |
-- we mark that spell to try again later |
function NeedToKnow.SetupSpellCooldown(bar, idx, barSpell) |
local isSpellID = barSpell:match("%d+") == barSpell |
if ( barSpell == "Auto Shot" or |
barSpell == NEEDTOKNOW.AUTO_SHOT or |
barSpell == "75" ) |
then |
bar.settings.bAutoShot = true |
bar.cd_functions[idx] = NeedToKnow.GetAutoShotCooldown |
elseif not isSpellID then |
local item_id = NeedToKnow.GetItemIDString(barSpell) |
if item_id then |
bar.spells[idx] = item_id |
bar.cd_functions[idx] = NeedToKnow.GetItemCooldown |
else |
local betterSpell = barSpell |
betterSpell = NeedToKnow.TryToFindSpellWithCD(barSpell) |
if nil ~= betterSpell then |
bar.spells[idx] = betterSpell |
elseif not GetSpellCooldown(barSpell) then |
bar.cd_functions[idx] = NeedToKnow.GetUnresolvedCooldown |
end |
end |
end |
end |
-- Called when the configuration of the bar has changed, when the addon |
-- is loaded or when ntk is locked and unlocked |
function NeedToKnow.Bar_Update(groupID, barID) |
bar:SetPoint("RIGHT", group, "RIGHT", 0, 0) |
trace("Creating bar for", groupID, barID) |
end |
local background = _G[barName.."Background"] |
bar.spark = _G[barName.."Spark"] |
bar.text = _G[barName.."Text"] |
groupSettings.Bars[barID] = CopyTable(NEEDTOKNOW.BAR_DEFAULTS) |
end |
bar.auraName = barSettings.AuraName |
if ( barSettings.BuffOrDebuff == "BUFFCD" or |
barSettings.BuffOrDebuff == "TOTEM" or |
barSettings.BuffOrDebuff == "USABLE" or |
barSettings.Unit = "player" |
end |
-- Split the spell names |
bar.spells = {} |
bar.functions = {} |
for barSpell in bar.auraName:gmatch("([^,]+)") do |
barSpell = strtrim(barSpell) |
table.insert(bar.spells, barSpell) |
table.insert(bar.functions, NeedToKnow.GetSpellCooldown) |
end |
-- split the user name overrides |
bar.spell_names = {} |
for un in barSettings.show_text_user:gmatch("([^,]+)") do |
un = strtrim(un) |
table.insert(bar.spell_names, un) |
end |
-- Look for certain special "spell" names |
barSettings.bAutoShot = nil |
if ( barSettings.BuffOrDebuff == "CASTCD" ) then |
for idx, barSpell in ipairs(bar.spells) do |
if ( barSpell == "Auto Shot" or |
barSpell == NEEDTOKNOW.AUTO_SHOT or |
barSpell == "75" ) |
then |
barSettings.bAutoShot = true |
bar.functions[idx] = NeedToKnow.GetAutoShotCooldown |
elseif (barSpell:match("%d+") ~= barSpell) then |
local item_id = NeedToKnow.GetItemIDString(barSpell) |
if item_id then |
bar.spells[idx] = item_id |
bar.functions[idx] = NeedToKnow.GetItemCooldown |
end |
end |
end |
end |
bar.settings = barSettings |
bar.unit = barSettings.Unit |
bar.nextUpdate = GetTime() + NEEDTOKNOW.UPDATE_INTERVAL |
end |
if ( NeedToKnow.CharSettings["Locked"] ) then |
-- Set up the bar to be functional |
bar:EnableMouse(0) |
local enabled = barSettings.Enabled |
if ( enabled and barSettings.BuffOrDebuff == "BUFFCD" ) then |
local dur = tonumber(barSettings.buffcd_duration) |
if (not dur or dur < 1) then |
print("Internal cooldown bar watching",barSettings.AuraName,"did not set a cooldown duration. Disabling the bar") |
enabled = false |
local enabled = groupSettings.Enabled and barSettings.Enabled |
if enabled then |
-- Set up the bar to be functional |
-- click through |
bar:EnableMouse(0) |
-- Split the spell names |
bar.spells = {} |
bar.cd_functions = {} |
for barSpell in bar.auraName:gmatch("([^,]+)") do |
barSpell = strtrim(barSpell) |
table.insert(bar.spells, barSpell) |
end |
end |
-- split the user name overrides |
bar.spell_names = {} |
for un in barSettings.show_text_user:gmatch("([^,]+)") do |
un = strtrim(un) |
table.insert(bar.spell_names, un) |
end |
-- split the "reset" spells (for internal cooldowns which reset when the player gains an aura) |
if barSettings.buffcd_reset_spells and barSettings.buffcd_reset_spells ~= "" then |
bar.reset_spells = {} |
bar.reset_start = {} |
for resetSpell in barSettings.buffcd_reset_spells:gmatch("([^,]+)") do |
resetSpell = strtrim(resetSpell) |
table.insert(bar.reset_spells, resetSpell) |
table.insert(bar.reset_start, 0) |
end |
else |
bar.reset_spells = nil |
bar.reset_start = nil |
end |
barSettings.bAutoShot = nil |
-- Determine which helper functions to use |
if "BUFFCD" == barSettings.BuffOrDebuff then |
bar.fnCheck = NeedToKnow.AuraCheck_BUFFCD |
elseif "TOTEM" == barSettings.BuffOrDebuff then |
bar.fnCheck = NeedToKnow.AuraCheck_TOTEM |
elseif "USABLE" == barSettings.BuffOrDebuff then |
bar.fnCheck = NeedToKnow.AuraCheck_USABLE |
elseif "CASTCD" == barSettings.BuffOrDebuff then |
bar.fnCheck = NeedToKnow.AuraCheck_CASTCD |
for idx, barSpell in ipairs(bar.spells) do |
table.insert(bar.cd_functions, NeedToKnow.GetSpellCooldown) |
NeedToKnow.SetupSpellCooldown(bar, idx, barSpell) |
end |
elseif "mhand" == barSettings.Unit or "ohand" == barSettings.Unit then |
bar.fnCheck = NeedToKnow.AuraCheck_Weapon |
elseif barSettings.show_all_stacks then |
bar.fnCheck = NeedToKnow.AuraCheck_AllStacks |
else |
bar.fnCheck = NeedToKnow.AuraCheck_Single |
end |
if ( enabled ) then |
if ( barSettings.BuffOrDebuff == "BUFFCD" ) then |
local dur = tonumber(barSettings.buffcd_duration) |
if (not dur or dur < 1) then |
print("Internal cooldown bar watching",barSettings.AuraName,"did not set a cooldown duration. Disabling the bar") |
enabled = false |
end |
end |
NeedToKnow.SetScripts(bar) |
-- Events were cleared while unlocked, so need to check the bar again now |
NeedToKnow.Bar_AuraCheck(bar) |
bar:RegisterEvent("PLAYER_FOCUS_CHANGED") |
elseif ( bar.unit == "target" ) then |
bar:RegisterEvent("PLAYER_TARGET_CHANGED") |
elseif ( bar.unit == "pet" ) then |
bar:RegisterEvent("UNIT_PET") |
end |
end |
elseif ( event == "UNIT_AURA" ) and ( select(1, ...) == self.unit ) then |
NeedToKnow.Bar_AuraCheck(self) |
elseif ( event == "UNIT_INVENTORY_CHANGED" and select(1, ...) == "player" ) then |
NeedToKnow.UpdateWeaponEnchants() |
NeedToKnow.Bar_AuraCheck(self) |
elseif ( event == "PLAYER_TARGET_CHANGED" ) or ( event == "PLAYER_FOCUS_CHANGED" ) then |
NeedToKnow.Bar_AuraCheck(self) |
elseif ( event == "UNIT_TARGET" and select(1, ...) == "target" ) then |
NeedToKnow.Bar_AuraCheck(self) |
elseif ( event == "UNIT_PET" and select(1, ...) == "player" ) then |
NeedToKnow.Bar_AuraCheck(self) |
elseif ( event == "UNIT_SPELLCAST_SENT" ) then |
local unit, spell = select(1, ...) |
if ( self.settings.bDetectExtends ) then |
-- Force an update to get all the bars to the current position (sharing code) |
-- This will call UpdateVCT again, but that seems ok |
bar.nextUpdate = -NEEDTOKNOW.UPDATE_INTERVAL |
NeedToKnow.Bar_OnUpdate(bar, 0) |
if bar.expirationTime > GetTime() then |
NeedToKnow.Bar_OnUpdate(bar, 0) |
end |
bar.time:Show() |
else |
local tt = CreateFrame("GameTooltip", ttname) |
tt:SetOwner(UIParent, "ANCHOR_NONE") |
tt.left = {} |
tt.right = {} |
-- Most of the tooltip lines share the same text widget, |
-- But we need to query the third one for cooldown info |
tt.right1 = tt:CreateFontString() |
tt.right1:SetFontObject(GameFontNormal) |
tt.right3 = tt:CreateFontString() |
tt.right3:SetFontObject(GameFontNormal) |
for i = 1, 30 do |
tt.left[i] = tt:CreateFontString() |
tt.left[i]:SetFontObject(GameFontNormal) |
if i ~= 3 then |
tt:AddFontStrings(tt.left[i], tt.right1) |
if i < 5 then |
tt.right[i] = tt:CreateFontString() |
tt.right[i]:SetFontObject(GameFontNormal) |
tt:AddFontStrings(tt.left[i], tt.right[i]) |
else |
tt:AddFontStrings(tt.left[i], tt.right3) |
tt:AddFontStrings(tt.left[i], tt.right[4]) |
end |
end |
end |
-- Get the number and unit of the cooldown from the tooltip |
local tt1 = NeedToKnow.GetUtilityTooltips() |
tt1:SetHyperlink( GetSpellLink(spell) ) |
local cd = tt1.right3:GetText() |
local n_cd, unit_cd |
if cd then |
cd = cd:lower() |
n_cd, unit_cd = cd:match("(%d+) (.+) ") |
end |
local lnk = GetSpellLink(spell) |
local cd, n_cd, unit_cd |
if lnk and lnk ~= "" then |
tt1:SetHyperlink( lnk ) |
for iTT=3,2,-1 do |
cd = tt1.right[iTT]:GetText() |
if cd then |
cd = cd:lower() |
n_cd, unit_cd = cd:match("(%d+) (.+) ") |
end |
if n_cd then break end |
end |
end |
-- unit_ref will be "|4sec:sec;" in english, so do a find rather than a == |
if not n_cd then |
end |
-- Search the player's spellbook for a spell that matches |
-- todo: cache this result? |
function NeedToKnow.TryToFindSpellWithCD(barSpell) |
if NeedToKnow.DetermineShortCooldownFromTooltip(barSpell) > 0 then return barSpell end |
for iBook = 1, GetNumSpellTabs() do |
local sBook,_,iFirst,nSpells = GetSpellTabInfo(iBook) |
for iSpell=iFirst+1, iFirst+nSpells do |
local sName = GetSpellInfo(iSpell, sBook) |
if sName == barSpell then |
local sLink = GetSpellLink(iSpell, sBook) |
local sID = sLink:match("spell:(%d+)") |
local start = GetSpellCooldown(sID) |
if start then |
local ttcd = NeedToKnow.DetermineShortCooldownFromTooltip(sID) |
if ttcd and ttcd>0 then |
return sID |
end |
end |
end |
end |
end |
end |
function NeedToKnow.GetItemIDString(id_or_name) |
local _, link = GetItemInfo(id_or_name) |
if link then |
end |
-- Helper for NeedToKnow.AuraCheck_CASTCD which gets the autoshot cooldown |
function NeedToKnow.GetAutoShotCooldown(bar) |
local tNow = GetTime() |
if ( bar.tAutoShotStart and bar.tAutoShotStart + bar.tAutoShotCD > tNow ) then |
end |
-- Helper for NeedToKnow.AuraCheck_CASTCD for names we haven't figured out yet |
function NeedToKnow.GetUnresolvedCooldown(bar, barSpell, idxName) |
NeedToKnow.SetupSpellCooldown(bar, idxName, barSpell) |
local fn = bar.cd_functions[idxName] |
if NeedToKnow.GetUnresolvedCooldown ~= fn then |
-- Have to re-evaluate barSpell since SetupSpellCooldown may have changed bar.spells |
return fn(bar, bar.spells[idxName], idxName) |
end |
end |
-- Wrapper around GetSpellCooldown with extra sauce |
-- Expected to return start, cd_len, enable, buffName, iconpath |
function NeedToKnow.GetSpellCooldown(bar, barSpell) |
-- Wrapper around GetItemCooldown |
-- Expected to return start, cd_len, enable, buffName, iconpath |
function NeedToKnow.GetItemCooldown(bar, item_id) |
function NeedToKnow.GetItemCooldown(bar, item_id, idx) |
local start, cd_len, enable = GetItemCooldown(item_id) |
if start then |
local name, _, _, _, _, _, _, _, icon = GetItemInfo(item_id) |
end |
-- Scrapes the current tooltips for the player's weapons to tease out |
-- the name of the current weapon imbue (and not just the name of the |
-- weapon, like you get from the Blizzard API.) This info gets cached |
-- on the bar so we don't have to compute it every Bar_AuraCheck |
function NeedToKnow.UpdateWeaponEnchants() |
local mdata = NeedToKnow.weapon_enchants.mhand |
local odata = NeedToKnow.weapon_enchants.ohand |
mdata.present, mdata.expiration, mdata.charges, |
odata.present, odata.expiration, odata.charges |
= GetWeaponEnchantInfo() |
if ( mdata.present ) then |
local oldname = mdata.name |
mdata.name = NeedToKnow.DetermineTempEnchantFromTooltip(16) |
if not mdata.name then |
mdata.name = "Unknown" |
print("Warning: NTK couldn't figure out what enchant is on the main hand weapon") |
end |
mdata.expiration = GetTime() + mdata.expiration/1000 |
if oldname ~= mdata.name then |
_,_,mdata.icon = GetSpellInfo(mdata.name) |
end |
else |
mdata.name=nil |
end |
if ( odata.present ) then |
local oldname = odata.name |
odata.name = NeedToKnow.DetermineTempEnchantFromTooltip(17) |
if not odata.name then |
odata.name = "Unknown" |
print("Warning: NTK couldn't figure out what enchant is on the off-hand weapon") |
end |
odata.expiration = GetTime() + odata.expiration/1000 |
if oldname ~= odata.name then |
_,_,odata.icon = GetSpellInfo(odata.name) |
end |
else |
odata.name = nil |
end |
end |
-- Bar_AuraCheck helper for Totem bars, this returns data if |
-- a totem matching barSpell is currently out. |
function NeedToKnow.AuraCheck_TOTEM(bar, idxName, barSpell, isSpellID) |
local spellName, spellRank, spellIconPath |
if ( isSpellID ) then |
spellName, spellRank, spellIconPath = GetSpellInfo(barSpell) |
end |
for iSlot=1, 4 do |
local haveTotem, totemName, startTime, totemDuration, totemIcon = GetTotemInfo(iSlot) |
local sComp = barSpell |
if isSpellID then sComp = spellName end |
if ( totemName and totemName:find(sComp) ) then |
-- WORKAROUND: The startTime reported here is both cast to an int and off by |
-- a latency meaning it can be significantly low. So we cache the GetTime |
-- that the totem actually appeared, so long as GetTime is reasonably close to |
-- startTime (since the totems may have been out for awhile before this runs.) |
if ( not NeedToKnow.totem_drops[iSlot] or |
NeedToKnow.totem_drops[iSlot] < startTime ) |
then |
local precise = GetTime() |
if ( precise - startTime > 1 ) then |
precise = startTime + 1 |
end |
NeedToKnow.totem_drops[iSlot] = precise |
end |
return totemDuration, -- duration |
totemName, -- name |
1, -- count |
NeedToKnow.totem_drops[iSlot] + totemDuration, -- expiration time |
totemIcon, -- icon path |
"player" -- caster |
end |
end |
end |
-- Bar_AuraCheck helper that checks the bar.weapon_enchants |
-- (computed by UpdateWeaponEnchants) for the given spell. |
-- FIXME: this is the only bar type that does not work with spell ids. |
function NeedToKnow.AuraCheck_Weapon(bar, idxName, barSpell, isSpellID) |
local data = NeedToKnow.weapon_enchants[bar.settings.Unit] |
if ( data.present and data.name and data.name:find(barSpell) ) then |
return 1800, -- duration TODO: Get real duration? |
data.name, -- name |
data.charges, -- count |
data.expiration, -- expiration time |
data.icon, -- icon path |
"player" -- caster |
end |
end |
-- Bar_AuraCheck helper that checks for spell/item use cooldowns |
-- Relies on NeedToKnow.GetAutoShotCooldown, NeedToKnow.GetSpellCooldown |
-- and NeedToKnow.GetItemCooldown. Bar_Update will have already pre-processed |
-- this list so that bar.cd_functions[idxName] can do something with barSpell |
function NeedToKnow.AuraCheck_CASTCD(bar, idxName, barSpell, isSpellID) |
local func = bar.cd_functions[idxName] |
local start, cd_len, should_cooldown, buffName, iconPath = func(bar, barSpell, idxName) |
-- filter out the GCD, we only care about actual spell CDs |
if start and cd_len <= 1.5 and func ~= NeedToKnow.GetAutoShotCooldown then |
if bar.expirationTime then |
start = bar.expirationTime - bar.duration |
cd_len = bar.duration |
else |
start = nil |
end |
end |
if start and cd_len then |
local tNow = GetTime() |
local tEnd = start + cd_len |
if ( tEnd > tNow + 0.1 ) then |
return cd_len, -- duration |
buffName, -- name |
1, -- count |
tEnd, -- expiration time |
iconPath, -- icon path |
"player" -- caster |
end |
end |
end |
-- Bar_AuraCheck helper for watching "Is Usable", which means that the action |
-- bar button for the spell lights up. This is mostly useful for Victory Rush |
function NeedToKnow.AuraCheck_USABLE(bar, idxName, barSpell, isSpellID) |
local key |
local settings = bar.settings |
if ( isSpellID ) then key = tonumber(barSpell) else key = barSpell end |
if ( not key ) then key = "" end |
local spellName, _, iconPath = GetSpellInfo(key) |
if ( spellName ) then |
local isUsable, notEnoughMana = IsUsableSpell(spellName) |
if (isUsable or notEnoughMana) then |
local duration = settings.usable_duration |
local expirationTime |
local tNow = GetTime() |
if ( not bar.expirationTime or |
(bar.expirationTime > 0 and bar.expirationTime < tNow - 0.01) ) |
then |
duration = settings.usable_duration |
expirationTime = tNow + duration |
else |
duration = bar.duration |
expirationTime = bar.expirationTime |
end |
return duration, -- duration |
spellName, -- name |
1, -- count |
expirationTime, -- expiration time |
iconPath, -- icon path |
"player" -- caster |
end |
end |
end |
-- Bar_AuraCheck helper for watching "internal cooldowns", which is like a spell |
-- cooldown for spells cast automatically (procs). The "reset on buff" logic |
-- is still handled by |
function NeedToKnow.AuraCheck_BUFFCD(bar, idxName, barSpell, isSpellID) |
local duration, buffName, _, expiration, iconPath, caster = NeedToKnow.AuraCheck_Single(bar, idxName, barSpell, isSpellID) |
local tNow = GetTime() |
if ( duration ) then |
if expiration == 0 then |
-- TODO: This really doesn't work very well as a substitute for telling when the aura was appliedS |
if not bar.expirationTime then |
local nDur = tonumber(bar.settings.buffcd_duration) |
return nDur, buffName, 1, nDur+tNow, iconPath, caster |
else |
return bar.duration, -- duration |
bar.buffName, -- name |
1, -- count |
bar.expirationTime, -- expiration time |
bar.iconPath, -- icon path |
"player" -- caster |
end |
end |
local tStart = expiration - duration |
duration = tonumber(bar.settings.buffcd_duration) |
expiration = tStart + duration |
if ( expiration > tNow ) then |
return duration, -- duration |
buffName, -- name |
-- Seeing the charges on the CD bar violated least surprise for me |
1, -- count |
expiration, -- expiration time |
iconPath, -- icon path |
caster -- caster |
end |
elseif ( bar.expirationTime and bar.expirationTime > tNow + 0.1 ) then |
return bar.duration, -- duration |
bar.buffName, -- name |
1, -- count |
bar.expirationTime, -- expiration time |
bar.iconPath, -- icon path |
"player" -- caster |
end |
end |
-- Bar_AuraCheck helper that looks for the first instance of a buff |
-- Uses the UnitAura filters exclusively if it can |
function NeedToKnow.AuraCheck_Single(bar, idxName, barSpell, isSpellID) |
local settings = bar.settings |
local filter = settings.BuffOrDebuff |
if settings.OnlyMine then |
filter = filter .. "|PLAYER" |
end |
if isSpellID then |
-- WORKAROUND: The second parameter to UnitAura can't be a spellid, so I have |
-- to walk them all |
local barID = tonumber(barSpell) |
local j = 1 |
while true do |
local buffName, _, iconPath, count, _, duration, expirationTime, caster, _, _, spellID |
= UnitAura(bar.unit, j, filter) |
if (not buffName) then |
break |
end |
if (spellID == barID) then |
return duration, -- duration |
buffName, -- name |
count, -- count |
expirationTime, -- expiration time |
iconPath, -- icon path |
caster -- caster |
end |
j=j+1 |
end |
else |
local buffName, _ , iconPath, count, _, duration, expirationTime, caster |
= UnitAura(bar.unit, barSpell, nil, filter) |
return duration, -- duration |
buffName, -- name |
count, -- count |
expirationTime, -- expiration time |
iconPath, -- icon path |
caster -- caster |
end |
end |
-- Bar_AuraCheck helper that updates bar.all_stacks (but returns nil) |
-- by scanning all the auras on the unit |
function NeedToKnow.AuraCheck_AllStacks(bar, idxName, barSpell, isSpellID) |
local j = 1 |
local matchID |
if isSpellID then matchID = tonumber(barSpell) end |
local all_stacks = bar.all_stacks |
while true do |
local buffName, _, iconPath, count, _, duration, expirationTime, caster, _, _, spellID |
= UnitAura(bar.unit, j, filter) |
if (not buffName) then |
break |
end |
if (isSpellID and spellID == matchID) or (not isSpellID and barSpell == buffName) then |
if (not count or count < 1) then count = 1 end |
if ( 0 == all_stacks.total or all_stacks.min.expirationTime > expirationTime ) then |
all_stacks.min.idxName = idxName |
all_stacks.min.buffName = buffName |
all_stacks.min.caster = caster |
all_stacks.min.duration = duration |
all_stacks.min.expirationTime = expirationTime |
all_stacks.min.iconPath = iconPath |
end |
if ( 0 == all_stacks.total or all_stacks.max.expirationTime < expirationTime ) then |
all_stacks.max.duration = duration |
all_stacks.max.expirationTime = expirationTime |
end |
all_stacks.total = all_stacks.total + count |
end |
j = j+1 |
end |
end |
-- Called whenever the state of auras on the bar's unit may have changed |
function NeedToKnow.Bar_AuraCheck(bar) |
local buffName, count, duration, expirationTime, caster, iconPath |
local idxName = 0 |
local all_stacks |
local settings = bar.settings |
local bUnitExists, isWeapon |
if ( settings.BuffOrDebuff == "CASTCD" or |
settings.BuffOrDebuff == "BUFFCD" or |
settings.BuffOrDebuff == "USABLE" or |
settings.BuffOrDebuff == "TOTEM" ) |
then |
if "mhand" == settings.Unit or |
"ohand" == settings.Unit then |
isWeapon = true |
bUnitExists = true |
elseif "player" == settings.Unit then |
bUnitExists = true |
else |
if ( "mhand" == settings.Unit or |
"ohand" == settings.Unit ) |
then |
isWeapon = true |
bUnitExists = true |
else |
bUnitExists = UnitExists(bar.unit) |
end |
bUnitExists = UnitExists(settings.Unit) |
end |
-- Determine if the bar should be showing anything |
if ( bUnitExists ) then |
local mainHandEnchantName, mainHandEnchantRank, offHandEnchantName, offHandEnchantRank |
local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges |
if ( isWeapon ) then |
hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo() |
if ( hasMainHandEnchant and "mhand" == settings.Unit ) then |
mainHandEnchantName, mainHandEnchantRank = NeedToKnow.DetermineTempEnchantFromTooltip(16) |
local all_stacks |
local idxName, duration, buffName, count, expirationTime, iconPath, caster |
if ( bUnitExists ) then |
if ( settings.show_all_stacks ) then |
if ( not bar.all_stacks ) then |
bar.all_stacks = |
{ |
min = |
{ |
buffName = "", |
duration = 0, |
expirationTime = 0, |
iconPath = "", |
caster = "" |
}, |
max = |
{ |
duration = 0, |
expirationTime = 0, |
}, |
total = 0 |
} |
else |
bar.all_stacks.total = 0 |
end |
if ( hasOffHandEnchant and "ohand" == settings.Unit ) then |
offHandEnchantName, offHandEnchantRank = NeedToKnow.DetermineTempEnchantFromTooltip(17) |
end |
all_stacks = bar.all_stacks |
end |
-- Call the helper function for each of the spells in the list |
for idx, barSpell in ipairs(bar.spells) do |
idxName = idx |
local filter = settings.BuffOrDebuff |
local _, nDigits = barSpell:find("^%d+") |
local isSpellID = ( nDigits == barSpell:len() ) |
if ( settings.BuffOrDebuff == "TOTEM" ) then |
local spellName, spellRank, spellIconPath |
if ( isSpellID ) then |
spellName, spellRank, spellIconPath = GetSpellInfo(barSpell) |
end |
for iSlot=1, 4 do |
local haveTotem, totemName, startTime, totemDuration, totemIcon = GetTotemInfo(iSlot) |
local sComp = barSpell |
if isSpellID then sComp = spellName end |
if ( totemName and totemName:find(sComp) ) then |
-- WORKAROUND: The startTime reported here is both cast to an int and off by |
-- a latency meaning it can be significantly low. So we cache the GetTime |
-- that the totem actually appeared, so long as GetTime is reasonably close to |
-- startTime (since the totems may have been out for awhile before this runs.) |
if ( not NeedToKnow.totem_drops[iSlot] or |
NeedToKnow.totem_drops[iSlot] < startTime ) |
then |
local precise = GetTime() |
if ( precise - startTime > 1 ) then |
precise = startTime + 1 |
end |
NeedToKnow.totem_drops[iSlot] = precise |
end |
buffName = totemName |
duration = totemDuration |
expirationTime = NeedToKnow.totem_drops[iSlot] + duration |
iconPath = totemIcon |
count = 1 |
caster = "player" |
break |
end |
end |
elseif isWeapon then |
if ( "mhand" == settings.Unit and mainHandEnchantName and mainHandEnchantName:find(barSpell) ) then |
buffName = mainHandEnchantName |
count = mainHandCharges |
if ( count < 1 ) then count = 1 end |
duration = 1800 |
expirationTime = GetTime() + mainHandExpiration/1000 |
caster = "player" |
elseif ( "ohand" == settings.Unit and offHandEnchantName and offHandEnchantName:find(barSpell) ) then |
buffName = offHandEnchantName |
count = offHandCharges |
if ( not count or count < 1 ) then count = 1 end |
duration = 1800 |
expirationTime = GetTime() + offHandExpiration/1000 |
caster = "player" |
end |
elseif settings.BuffOrDebuff == "CASTCD" then |
local start, cd_len, should_cooldown |
local func = bar.functions[idxName] |
start, cd_len, should_cooldown, buffName, iconPath = func(bar, barSpell) |
-- filter out the GCD, we only care about actual spell CDs |
if start and cd_len <= 1.5 and func ~= NeedToKnow.GetAutoShotCooldown then |
if bar.expirationTime then |
start = bar.expirationTime - bar.duration |
cd_len = bar.duration |
else |
start = nil |
end |
end |
if start and cd_len then |
local tNow = GetTime() |
local tEnd = start + cd_len |
if ( tEnd > tNow + 0.1 ) then |
count = 1 |
duration = cd_len |
expirationTime = tEnd |
cast = "player" |
end |
end |
elseif settings.BuffOrDebuff == "USABLE" then |
local key |
if ( isSpellID ) then key = tonumber(barSpell) else key = barSpell end |
if ( not key ) then key = "" end |
local spellName |
spellName, _, iconPath = GetSpellInfo(key) |
if ( spellName ) then |
local isUsable, notEnoughMana = IsUsableSpell(spellName) |
if (isUsable or notEnoughMana) then |
duration = settings.usable_duration |
buffName = spellName |
count = 1 |
local tNow = GetTime() |
if ( not bar.expirationTime or |
(bar.expirationTime > 0 and bar.expirationTime < tNow - 0.01) ) |
then |
duration = settings.usable_duration |
expirationTime = tNow + duration |
else |
duration = bar.duration |
expirationTime = bar.expirationTime |
end |
end |
end |
else |
if settings.OnlyMine then |
filter = filter .. "|PLAYER" |
end |
if isSpellID then |
-- WORKAROUND: The second parameter to UnitAura can't be a spellid, so I have |
-- to walk them all |
local barID = tonumber(barSpell) |
local j = 1 |
while true do |
local buffRank, spellID |
buffName, buffRank, iconPath, count, _, duration, expirationTime, caster, _, _, spellID = UnitAura(bar.unit, j, filter) |
if (not buffName) then |
break |
end |
if (spellID == barID) then |
break |
else |
duration = nil |
end |
j=j+1 |
end |
else |
buffName, _ , iconPath, count, _, duration, expirationTime, caster = UnitAura(bar.unit, barSpell, nil, filter) |
end |
end |
duration, buffName, count, expirationTime, iconPath, caster |
= bar.fnCheck(bar, idx, barSpell, isSpellID); |
if ( duration ) then |
if duration then |
if not count or count < 1 then |
count = 1 |
end |
if ( settings.show_all_stacks ) then |
if ( not all_stacks ) then |
all_stacks = |
{ |
min = |
{ |
buffName = "", |
duration = 0, |
expirationTime = 0, |
iconPath = "", |
caster = "" |
}, |
max = |
{ |
duration = 0, |
expirationTime = 0, |
}, |
total = 0 |
} |
end |
all_stacks.total = all_stacks.total + count |
if ( 0 == all_stacks.min.expirationTime or all_stacks.min.expirationTime > expirationTime ) then |
all_stacks.min.idxName = idxName |
all_stacks.min.buffName = buffName |
all_stacks.min.caster = caster |
all_stacks.min.duration = duration |
all_stacks.min.expirationTime = expirationTime |
all_stacks.min.iconPath = iconPath |
end |
if ( 0 == all_stacks.max.expirationTime or all_stacks.max.expirationTime < expirationTime ) then |
all_stacks.max.duration = duration |
all_stacks.max.expirationTime = expirationTime |
end |
else |
break |
end |
idxName = idx |
break |
end |
end |
end |
if ( all_stacks ) then |
if ( all_stacks and all_stacks.total > 0 ) then |
idxName = all_stacks.min.idxName |
buffName = all_stacks.min.buffName |
caster = all_stacks.min.caster |
count = all_stacks.total |
end |
-- There is an aura this bar is watching! Set it up |
duration = tonumber(duration) |
if ( settings.BuffOrDebuff == "BUFFCD" ) then |
-- Cancel the work done above if a reset spell is encountered |
-- (reset_spells will only be set for BUFFCD) |
if ( bar.reset_spells ) then |
local maxStart = 0 |
local tNow = GetTime() |
count = 1 -- Seeing the charges on the CD bar violated least surprise for me |
if ( duration ) then |
local tStart = expirationTime - duration |
duration = tonumber(settings.buffcd_duration) |
expirationTime = tStart + duration |
if ( expirationTime <= tNow ) then |
duration = nil |
-- Keep track of when the reset auras were last applied to the player |
for idx, resetSpell in ipairs(bar.reset_spells) do |
local _, nDigits = resetSpell:find("^%d+") |
local isSpellID = ( nDigits == resetSpell:len() ) |
-- Note this relies on BUFFCD setting the target to player, and that the onlyMine will work either way |
local resetDuration, _, _, resetExpiration |
= NeedToKnow.AuraCheck_Single(bar, idx, resetSpell, isSpellID) |
local tStart |
if resetDuration then |
if 0 == resetDuration then |
tStart = bar.reset_start[idx] |
if 0 == tStart then |
tStart = tNow |
end |
else |
tStart = resetExpiration-resetDuration |
end |
bar.reset_start[idx] = tStart |
if tStart > maxStart then maxStart = tStart end |
else |
bar.reset_start[idx] = 0 |
end |
elseif ( bar.expirationTime and bar.expirationTime > tNow + 0.1 ) then |
duration = bar.duration |
expirationTime = bar.expirationTime |
buffName = bar.buffName |
iconPath = bar.iconPath |
end |
if duration and maxStart > expirationTime-duration then |
duration = nil |
end |
end |
-- There is an aura this bar is watching! Set it up |
if ( duration ) then |
duration = tonumber(duration) |
-- Handle duration increases |
local extended |
if (settings.bDetectExtends) then |
end |
end |
function NeedToKnow.Fmt_SingleUnit(i_fSeconds) |
return string.format(SecondsToTimeAbbrev(i_fSeconds)) |
end |
function NeedToKnow.Fmt_TwoUnits(i_fSeconds) |
if ( i_fSeconds < 6040 ) then |
local nMinutes, nSeconds |
end |
end |
if ( self.duration > 0 ) then |
if ( self.duration and self.duration > 0 ) then |
local duration = self.fixedDuration or self.duration |
local bar1_timeLeft = self.expirationTime - GetTime() |
if ( bar1_timeLeft < 0 ) then |
## Interface: 30300 |
## Title: NeedToKnow |
## Author: Kitjan, lieandswell |
## Version: 3.1.7 |
## Version: 3.3.0 |
## Notes: Timer bars for buffs, debuffs, cooldowns, etc. |
## X-Compatible-With: 40000 |
## X-Credits: Bilt, Fxfighter EU-Echsenkessel, metalchoir, sp00n, Vlakarados, wowui.cn |
NEEDTOKNOW.UIPANEL_TOOLTIP_BARTEXTURE = "Choose the texture graphic for timer bars"; |
NEEDTOKNOW.CMD_RESET = "reset"; |
NEEDTOKNOW.UIPANEL_CONFIGMODE = "Config mode"; |
NEEDTOKNOW.UIPANEL_CONFIGMODE_TOOLTIP = "Unlock timer bars and make them configurable"; |
NEEDTOKNOW.UIPANEL_PLAYMODE = "Play mode"; |
NEEDTOKNOW.UIPANEL_PLAYMODE_TOOLTIP = "Lock and enable timer bars, making them click-through"; |
NEEDTOKNOW.UIPANEL_CONFIGMODE = "Config mode"; |
NEEDTOKNOW.UIPANEL_CONFIGMODE_TOOLTIP = "Unlock timer bars and make them configurable"; |
NEEDTOKNOW.UIPANEL_PLAYMODE = "Play mode"; |
NEEDTOKNOW.UIPANEL_PLAYMODE_TOOLTIP = "Lock and enable timer bars, making them click-through"; |
NEEDTOKNOW.UIPANEL_APPEARANCE = "Appearance"; |
NEEDTOKNOW.UIPANEL_BACKGROUNDCOLOR = "Background color"; |
NEEDTOKNOW.CHOOSE_VCT_EXTRA_DIALOG = "Enter an amount of seconds that will be added to the cast time of the spell. Ex: 1.5"; |
NEEDTOKNOW.CHOOSE_BLINK_TITLE_DIALOG = "Enter the text to display on the bar when it is blinking."; |
NEEDTOKNOW.BUFFCD_DURATION_DIALOG = "Enter the cooldown duration triggered by the buffs watched by this bar."; |
NEEDTOKNOW.BUFFCD_RESET_DIALOG = "Enter the buff (or buffs) to watch for which reset the cooldown to 0."; |
NEEDTOKNOW.USABLE_DURATION_DIALOG = "Enter the cooldown duration triggered by the abilities watched by this bar."; |
Opt_BUFFCD = |
{ |
{ VariableName = "buffcd_duration", MenuText = "Cooldown duration...", Type = "Dialog", DialogText = "BUFFCD_DURATION_DIALOG", Numeric=true }, |
{ VariableName = "buffcd_reset_spells", MenuText = "Reset on buff...", Type = "Dialog", DialogText = "BUFFCD_RESET_DIALOG" }, |
{ VariableName = "append_cd", MenuText = "Append \"CD\"" }, -- FIXME: Localization |
}, |
Opt_USABLE = |