WoWInterface SVN NeedToKnow-Updated

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /trunk
    from Rev 14 to Rev 32
    Reverse comparison

Rev 14 → Rev 32

NeedToKnow/NeedToKnow.lua
16,7 → 16,7
NeedToKnow = {};
-- NEEDTOKNOW = {} is defined in the localization file, which must be loaded before this file
 
NEEDTOKNOW.VERSION = "2.5.1";
NEEDTOKNOW.VERSION = "2.8.2";
NEEDTOKNOW.MAXGROUPS = 4;
NEEDTOKNOW.MAXBARS = 6;
NEEDTOKNOW.UPDATE_INTERVAL = 0.05;
38,12 → 38,16
NEEDTOKNOW.BAR_DEFAULTS = {
Enabled = true,
AuraName = "",
-- AuraName = {""},
-- Priority = "list" or "maxtime" or "mintime",
Unit = "player",
BuffOrDebuff = "HELPFUL",
OnlyMine = true,
BarColor = { r=0.6, g=0.6, b=0.6, a=1.0 },
TimeFormat = "Fmt_SingleUnit",
vct_enabled = false,
vct_color = { r=0.6, g=0.6, b=0.0, a=0.3 },
vct_spell = "",
vct_extra = 0,
bDetectExtends = false,
};
NEEDTOKNOW.GROUP_DEFAULTS = {
Enabled = false,
113,53 → 117,121
-- EXECUTIVE FRAME
-- ---------------
 
function NeedToKnow.ExecutiveFrame_OnEvent(self, event, arg1)
if ( event == "ADDON_LOADED" and arg1 == "NeedToKnow") then
function NeedToKnow.ExecutiveFrame_OnEvent(self, event, ...)
if ( event == "ADDON_LOADED" and select(1,...) == "NeedToKnow") then
if ( not NeedToKnow_Settings ) then
NeedToKnow_Settings = CopyTable(NEEDTOKNOW.DEFAULTS);
NeedToKnow_Settings["Spec"][1]["Groups"][1]["Enabled"] = true;
NeedToKnow_Settings["Spec"][2]["Groups"][1]["Enabled"] = true;
elseif ( NeedToKnow_Settings["Version"] < NEEDTOKNOW.VERSION and not NEEDTOKNOW.UPGRADED) then
else
NeedToKnow.SafeUpgrade();
end
 
if ( not NeedToKnow_Visible ) then
NeedToKnow_Visible = true;
end
NeedToKnow.last_cast = {}; -- [spell][guidTarget] = { time, dur }
NeedToKnow.nSent = 0;
NeedToKnow.totem_drops = {}; -- array 1-4 of precise times the totems appeared
 
SlashCmdList["NEEDTOKNOW"] = NeedToKnow.SlashCommand;
SLASH_NEEDTOKNOW1 = "/needtoknow";
SLASH_NEEDTOKNOW2 = "/ntk";
else
local fnName = "ExecutiveFrame_"..event;
local fn = NeedToKnow[fnName];
if ( fn ) then
fn(...);
end
end
end
 
elseif ( event == "PLAYER_LOGIN") then
-- save group positions if upgrading from version that used layout-local.txt
if ( NeedToKnow_Settings["Version"] < "2.1" ) then
for groupID = 1, NEEDTOKNOW.MAXGROUPS do
NeedToKnow.SavePosition(_G["NeedToKnow_Group"..groupID], groupID);
end
NeedToKnow_Settings["Version"] = NEEDTOKNOW.VERSION;
function NeedToKnow.ExecutiveFrame_UNIT_SPELLCAST_SUCCEEDED(unit, spell, rank)
if unit == "player" then
local r = NeedToKnow.last_cast[spell];
if ( r and r.state == 1 ) then
r.state = 2;
 
elseif (NeedToKnow_Settings["Version"] < "2.4") then
local tempSettings = CopyTable(NeedToKnow_Settings);
NeedToKnow.Reset();
-- A little extra safety just in case we get two SUCCEEDED entries
-- before we get the combat log events for them (though I don't
-- think this is possible.)
NeedToKnow.last_success = spell;
 
NeedToKnow_Settings = CopyTable(tempSettings);
NeedToKnow_Settings["Version"] = NEEDTOKNOW.VERSION;
NeedToKnow.Update();
NeedToKnow.UIPanel_Update();
-- We need the actual target, which we can only get from the combat log.
-- Thankfully, the combat log event always comes after this one, so we
-- don't need to register for the combat log for long at all.
NeedToKnow_ExecutiveFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
 
if ( NeedToKnow.nSent > 1 ) then
NeedToKnow.nSent = NeedToKnow.nSent - 1;
else
NeedToKnow.nSent = 0;
NeedToKnow_ExecutiveFrame:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED");
end
end
 
NeedToKnow.Update();
end
end
 
elseif ( event == "PLAYER_TALENT_UPDATE" ) then
NEEDTOKNOW.CURRENTSPEC = GetActiveTalentGroup();
NeedToKnow.Update();
NeedToKnow.UIPanel_Update();
function NeedToKnow.ExecutiveFrame_COMBAT_LOG_EVENT_UNFILTERED(time, event, guidCaster, ...)
-- the time that's passed in appears to be time of day, not game time like everything else.
time = GetTime();
-- TODO: Is checking r.state sufficient or must event be checked instead?
if ( guidCaster == NeedToKnow.guidPlayer ) then
local guidTarget, _, _, _, spell = select(3, ...);
local r = NeedToKnow.last_cast[spell];
if ( r and r.state == 2) then
r.state = 0;
-- record this spellcast
if ( not r[guidTarget] ) then
r[guidTarget] = { time = time, dur = 0 };
else
r[guidTarget].time = time;
r[guidTarget].dur = 0;
end
 
-- Use this event to expire some targets. This should limit us to
-- two combats' worth of targets (since GC doesn't happen in combat)
for kG, vG in pairs(r) do
if ( type(vG) == "table" and ( vG.time + 300 < time ) ) then
r[kG] = nil;
end
end
end
 
if ( spell == NeedToKnow.last_success ) then
-- We saw our spell, we can disconnect from the spam hose
NeedToKnow_ExecutiveFrame:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
end
end
 
end
 
function NeedToKnow.ExecutiveFrame_PLAYER_LOGIN()
-- save group positions if upgrading from version that used layout-local.txt
if ( not NeedToKnow_Settings.OldVersion or
NeedToKnow_Settings.OldVersion < "2.1" ) then
for groupID = 1, NEEDTOKNOW.MAXGROUPS do
NeedToKnow.SavePosition(_G["NeedToKnow_Group"..groupID], groupID);
end
 
elseif (NeedToKnow_Settings["Version"] < "2.4") then
NeedToKnow.UIPanel_Update();
end
 
NeedToKnow.guidPlayer = UnitGUID("player");
NEEDTOKNOW.CURRENTSPEC = GetActiveTalentGroup();
 
NeedToKnow.Update();
NeedToKnow.UIPanel_Update();
end
 
function NeedToKnow.ExecutiveFrame_PLAYER_TALENT_UPDATE()
NEEDTOKNOW.CURRENTSPEC = GetActiveTalentGroup();
NeedToKnow.Update();
NeedToKnow.UIPanel_Update();
end
 
 
 
function NeedToKnow.SafeUpgrade()
if ( NeedToKnow_Settings["Version"] < "2.0" ) then -- total settings clear if v1.x
NeedToKnow_Settings = CopyTable(NEEDTOKNOW.DEFAULTS);
184,37 → 256,53
 
NeedToKnow.Update();
NeedToKnow.UIPanel_Update();
 
else
NeedToKnow_Settings = NeedToKnow.AddNewSettings(NeedToKnow_Settings, NEEDTOKNOW.DEFAULTS);
NeedToKnow_Settings["Version"] = NEEDTOKNOW.VERSION;
end
NeedToKnow_Settings.OldVersion = NeedToKnow_Settings["Version"];
NeedToKnow_Settings["Version"] = NEEDTOKNOW.VERSION;
 
-- Add any new settings
for iS,vS in ipairs(NeedToKnow_Settings["Spec"]) do
for kD, vD in pairs(NEEDTOKNOW.SPEC_DEFAULTS) do
if nil == vS[kD] then
vS[kD] = NeedToKnow.deepcopy(vD);
end
end
for iG,vG in ipairs(vS["Groups"]) do
for kD, vD in pairs(NEEDTOKNOW.GROUP_DEFAULTS) do
if nil == vG[kD] then
vG[kD] = NeedToKnow.deepcopy(vD);
end
end
for iB, vB in ipairs(vG["Bars"]) do
for kD, vD in pairs(NEEDTOKNOW.BAR_DEFAULTS) do
if nil == vB[kD] then
vB[kD] = NeedToKnow.deepcopy(vD);
end
end
end
end
end
end
 
function NeedToKnow.AddNewSettings(settings, defaults)
for k, v in pairs(defaults) do
if ( not settings[k] ) then
if ( type(v) == "table" ) then
settings[k] = {};
settings[k] = NeedToKnow.AddNewSettings(settings[k], defaults[k]);
else
settings[k] = v;
end
 
--[[
elseif ( type(v) == "table" ) and ( type(settings[k]) ~= "table" ) then
local oldSetting = settings[k];
settings[k] = {};
settings[k][1] = oldSetting;
-- settings[k] = {settings[k]};
--]]
 
elseif ( type(v) == "table" ) then
settings[k] = NeedToKnow.AddNewSettings(settings[k], defaults[k]);
-- 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
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 settings;
return _copy(object)
end
 
function NeedToKnow.Update()
307,6 → 395,8
-- BARS
-- ----
 
-- 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)
local barName = "NeedToKnow_Group"..groupID.."Bar"..barID;
local bar = _G[barName];
317,10 → 407,12
 
local groupSettings = NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID];
local barSettings = groupSettings["Bars"][barID];
bar.settings = barSettings;
bar.auraName = barSettings.AuraName;
bar.buffOrDebuff = barSettings.BuffOrDebuff;
bar.unit = barSettings.Unit;
bar.onlyMine = barSettings.OnlyMine;
if ( barSettings.Unit == "mhand" or barSettings.Unit == "ohand" ) then
bar.unit = "player";
end
bar.nextUpdate = GetTime() + NEEDTOKNOW.UPDATE_INTERVAL;
 
bar.fixedDuration = groupSettings.FixedDuration;
337,47 → 429,84
background:SetHeight(bar:GetHeight() + 2*NeedToKnow_Settings["BarPadding"]);
background:SetVertexColor(unpack(NeedToKnow_Settings["BkgdColor"]));
 
bar.text:SetText(bar.auraName);
-- Set up the Visual Cast Time overlay. It isn't a part of the template
-- because most bars won't use it and thus don't need to pay the cost of
-- a hidden frame
if ( barSettings.vct_enabled ) then
if ( nil == bar.vct ) then
bar.vct = bar:CreateTexture(barName.."VisualCast", "ARTWORK");
bar.vct:SetPoint("TOPLEFT", bar, "TOPLEFT");
end
local argb = barSettings.vct_color;
bar.vct:SetTexture(argb.r, argb.g, argb.b, argb.a );
bar.vct:SetBlendMode("ADD");
bar.vct:SetHeight(bar:GetHeight());
elseif (nil ~= bar.vct) then
bar.vct:Hide();
end
 
if ( NeedToKnow_Settings["Locked"] ) then
-- Set up the bar to be functional
bar:EnableMouse(0);
bar:Hide();
bar.spark:Show();
bar.time:Show();
if ( barSettings.Enabled ) then
NeedToKnow.SetScripts(bar);
-- Events were cleared while unlocked, so need to check the bar again n ow
NeedToKnow.Bar_AuraCheck(bar);
else
NeedToKnow.ClearScripts(bar);
bar:Hide();
end
else
NeedToKnow.ClearScripts(bar);
-- Set up the bar to be configured
bar:EnableMouse(1);
bar:Show();
bar.spark:Hide();
bar.time:Hide();
end
if ( bar.vct ) then
bar.vct:SetWidth( bar:GetWidth() / 16);
bar.vct:Show();
end
local txt = bar.auraName;
if ( barSettings.bDetectExtends == true ) then
txt = txt .. " + 3s";
end
bar.text:SetText(txt);
 
if ( barSettings.Enabled ) then
bar:SetAlpha(1);
else
bar:SetAlpha(0.4);
if ( barSettings.Enabled ) then
bar:SetAlpha(1);
else
bar:SetAlpha(0.4);
end
end
 
if ( NeedToKnow_Settings["Locked"] and barSettings.Enabled ) then
NeedToKnow.SetScripts(bar);
NeedToKnow.Bar_AuraCheck(bar); -- a check for when the addon gets locked
else
NeedToKnow.ClearScripts(bar);
end
end
 
function NeedToKnow.SetScripts(bar)
bar:SetScript("OnEvent", NeedToKnow.Bar_OnEvent);
bar:SetScript("OnUpdate", NeedToKnow.Bar_OnUpdate);
bar:RegisterEvent("PLAYER_TARGET_CHANGED");
bar:RegisterEvent("PLAYER_FOCUS_CHANGED");
if bar.unit == "targettarget" then
 
if ( "TOTEM" == bar.settings.BuffOrDebuff ) then
bar:RegisterEvent("PLAYER_TOTEM_UPDATE");
elseif ( "mhand" == bar.settings.Unit or "ohand" == bar.settings.Unit ) then
bar:RegisterEvent("UNIT_INVENTORY_CHANGED");
elseif ( bar.unit == "targettarget" ) then
-- WORKAROUND: PLAYER_TARGET_CHANGED happens immediately, UNIT_TARGET every couple seconds
bar:RegisterEvent("PLAYER_TARGET_CHANGED");
bar:RegisterEvent("UNIT_TARGET");
-- WORKAROUND: Don't get UNIT_AURA for targettarget
bar:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
else
bar:RegisterEvent("UNIT_AURA");
if ( bar.unit == "focus" ) then
bar:RegisterEvent("PLAYER_FOCUS_CHANGED");
elseif ( bar.unit == "target" ) then
bar:RegisterEvent("PLAYER_TARGET_CHANGED");
end
end
if "TOTEM" == bar.buffOrDebuff then
bar:RegisterEvent("PLAYER_TOTEM_UPDATE");
 
if bar.settings.bDetectExtends then
bar:RegisterEvent("UNIT_SPELLCAST_SENT");
end
bar:RegisterEvent("UNIT_AURA");
bar:RegisterEvent("UNIT_TARGET");
end
 
function NeedToKnow.ClearScripts(bar)
388,7 → 517,9
bar:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
bar:UnregisterEvent("PLAYER_TOTEM_UPDATE");
bar:UnregisterEvent("UNIT_AURA");
bar:UnregisterEvent("UNIT_INVENTORY_CHANGED");
bar:UnregisterEvent("UNIT_TARGET");
bar:UnregisterEvent("UNIT_SPELLCAST_SENT");
end
 
function NeedToKnow.Bar_OnEvent(self, event, ...)
398,8 → 529,7
if ( NEEDTOKNOW.AURAEVENTS[combatEvent] ) then
local guidTarget = select(6, ...)
if ( guidTarget == UnitGUID(self.unit) ) then
local idSpell = select(9, ...)
local nameSpell = select(10, ...)
local idSpell, nameSpell = select(9, ...)
if (self.auraName:find(idSpell) or
self.auraName:find(nameSpell))
then
408,75 → 538,293
end
elseif ( combatEvent == "UNIT_DIED" ) and ( select(6, ...) == UnitGUID(self.unit) ) then
NeedToKnow.Bar_AuraCheck(self);
-- elseif ((combatEvent == "ENCHANT_APPLIED") or ( combatEvent == "ENCHANT_REMOVED")) and ( self.BuffOrDebuff == "WEAPON" ) and ( string.find( self.auraName, select (9, ...)) ) and ( UnitGUID(self.unit) == select (6, ...) ) then
end
elseif ( event == "PLAYER_TOTEM_UPDATE" ) then
NeedToKnow.Bar_AuraCheck(self);
elseif ( event == "UNIT_AURA" ) and ( select(1, ...) == self.unit ) then
NeedToKnow.Bar_AuraCheck(self);
elseif ( event == "UNIT_INVENTORY_CHANGED" and select(1, ...) == self.unit ) then
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
elseif ( event == "UNIT_TARGET" and select(1, ...) == "target" ) then
NeedToKnow.Bar_AuraCheck(self);
elseif ( event == "UNIT_SPELLCAST_SENT" ) then
local unit, spell = select(1, ...);
if unit == "player" and self.buffName == spell then
local r = NeedToKnow.last_cast[spell];
if ( r and r.state == 0 ) then
r.state = 1;
NeedToKnow.nSent = NeedToKnow.nSent + 1;
NeedToKnow_ExecutiveFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED");
end
end
end
end
 
-- AuraCheck calls on this to compute the "text" of the bar
-- It is separated out like this in part to be hooked by other addons
function NeedToKnow.ComputeBarText(buffName, count, extended)
local text;
if ( count > 1 ) then
text = buffName.." ["..count.."]";
else
text = buffName;
end
if ( extended and extended > 1 ) then
text = text .. string.format(" + %.0fs", extended);
end
return text;
end
 
-- Called by NeedToKnow.UpdateVCT, which is called from AuraCheck and possibly
-- by Bar_Update depending on vct_refresh. In addition to refactoring out some
-- code from the long AuraCheck, this also provides a convenient hook for other addons
function NeedToKnow.ComputeVCTDuration(bar)
local vct_duration = 0;
 
local spellToTime = bar.settings.vct_spell
if ( nil == spellToTime or "" == spellToTime ) then
spellToTime = bar.buffName;
end
local _, _, _, _, _, _, castTime = GetSpellInfo(spellToTime);
 
if ( castTime ) then
vct_duration = castTime / 1000;
bar.vct_refresh = true;
else
bar.vct_refresh = false;
end
 
if ( bar.settings.vct_extra ) then
vct_duration = vct_duration + bar.settings.vct_extra;
end
return vct_duration;
end
 
function NeedToKnow.UpdateVCT(bar)
local vct_duration = NeedToKnow.ComputeVCTDuration(bar);
 
if ( bar.duration ) then
vct_width = (vct_duration * bar:GetWidth()) / bar.duration;
if (vct_width > bar:GetWidth()) then
vct_width = bar:GetWidth();
end
else
vct_width = 0;
end
 
if ( vct_width > 1 ) then
bar.vct:SetWidth(vct_width);
bar.vct:Show();
else
bar.vct:Hide();
end
end
 
function NeedToKnow.ConfigureVisibleBar(bar, count, extended)
local text = NeedToKnow.ComputeBarText(bar.buffName, count, extended);
bar.text:SetText(text);
 
-- Is this an aura with a finite duration?
local vct_width = 0;
if ( bar.duration > 0 ) then
bar:SetMinMaxValues(0, bar.duration);
local timeLeft = bar.expirationTime - GetTime();
bar:SetValue(timeLeft);
 
-- Hide the spark if it's "off the bar"
if ( timeLeft > bar.duration ) then
bar.spark:Hide();
else
bar.spark:SetPoint("CENTER", bar, "LEFT", bar:GetWidth()*timeLeft/bar.duration, 0);
bar.spark:Show();
end
 
-- Determine the size of the visual cast bar
if ( bar.settings.vct_enabled ) then
NeedToKnow.UpdateVCT(bar);
end
 
bar.time:Show();
else
-- Hide the time text and spark for auras with "infinite" duration
bar:SetMinMaxValues(0, 1);
bar:SetValue(1);
 
bar.time:Hide();
bar.spark:Hide();
 
if ( bar.vct ) then
bar.vct:Hide();
end
end
end
 
function NeedToKnow.GetUtilityTooltips()
if ( not NeedToKnow_Tooltip1 ) then
for idxTip = 1,2 do
local ttname = "NeedToKnow_Tooltip"..idxTip;
local tt = CreateFrame("GameTooltip", ttname)
tt:SetOwner(UIParent, "ANCHOR_NONE")
tt.left = {}
tt.right = tt:CreateFontString()
tt.right:SetFontObject(GameFontNormal)
for i = 1, 30 do
tt.left[i] = tt:CreateFontString()
tt.left[i]:SetFontObject(GameFontNormal)
tt:AddFontStrings(tt.left[i], tt.right)
end
end
end
local tt1,tt2 = NeedToKnow_Tooltip1, NeedToKnow_Tooltip2;
tt1:ClearLines();
tt2:ClearLines();
return tt1,tt2;
end
 
function NeedToKnow.DetermineTempEnchantFromTooltip(i_invID)
local tt1,tt2 = NeedToKnow.GetUtilityTooltips();
 
tt1:SetInventoryItem("player", i_invID);
local n,h = tt1:GetItem();
 
tt2:SetHyperlink(h);
 
-- Look for green lines present in tt1 that are missing from tt2
local nLines1, nLines2 = tt1:NumLines(), tt2:NumLines();
local i1, i2 = 1,1;
while ( i1 <= nLines1 ) do
local txt1 = tt1.left[i1];
if ( txt1:GetTextColor() ~= 0 ) then
i1 = i1 + 1;
elseif ( i2 <= nLines2 ) then
local txt2 = tt2.left[i2];
if ( txt2:GetTextColor() ~= 0 ) then
i2 = i2 + 1;
elseif (txt1:GetText() == txt2:GetText()) then
i1 = i1 + 1;
i2 = i2 + 1;
else
break;
end
else
break;
end
end
if ( i1 <= nLines1 ) then
local line = tt1.left[i1]:GetText();
local iter = line:gmatch("[^%s]+");
local name, rank = iter(), iter();
return name, rank;
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, buffIconPath
local buffName, count, duration, expirationTime, caster
local settings = bar.settings;
 
if ( UnitExists(bar.unit) ) then
-- Determine if the bar should be showing anything
if ( UnitExists(bar.unit) ) then
local isWeapon;
if ( "mhand" == settings.Unit or
"ohand" == settings.Unit )
then
isWeapon = true;
end
 
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);
end
if ( hasOffHandEnchant and "ohand" == settings.Unit ) then
offHandEnchantName, offHandEnchantRank = NeedToKnow.DetermineTempEnchantFromTooltip(17);
end
end
 
local startIndex=1;
local numBuffs;
_ , numBuffs = string.gsub(bar.auraName, "," , ",")
for idxBuff=0, numBuffs do
local endIndex = bar.auraName:find(",",startIndex,true) or (string.len(bar.auraName)+1)
local barSpell = strtrim(string.sub(bar.auraName, startIndex, endIndex-1))
local filter = bar.buffOrDebuff
local filter = settings.BuffOrDebuff
local _, nDigits = barSpell:find("^[0-9]+")
local spellName, spellRank, spellIconPath;
local isSpellID = nDigits == barSpell:len();
if isSpellID then
spellName, spellRank , spellIconPath = GetSpellInfo(barSpell);
end
local isSpellID = ( nDigits == barSpell:len() );
 
if ( bar.buffOrDebuff == "TOTEM" ) then
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 = GetTotemInfo(iSlot);
local sComp = barSpell
local sComp = barSpell;
if isSpellID then sComp = spellName end
if totemName and
totemName:find(sComp)
then
buffName = totemName
duration = totemDuration
expirationTime = startTime + duration
count = 1
caster = "player";
break;
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;
count = 1;
caster = "player";
break;
end
end
elseif isWeapon then
-- todo: use substring instead?
if ( "mhand" == settings.Unit and mainHandEnchantName == 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 == barSpell ) then
buffName = mainHandEnchantName
count = offHandCharges;
if ( count < 1 ) then count = 1 end
duration = 1800
expirationTime = GetTime() + offHandExpiration/1000
caster = "player"
end
else
if bar.onlyMine then
filter = filter .. "|PLAYER"
if settings.OnlyMine then
filter = filter .. "|PLAYER";
end
 
if isSpellID then
local j = 1
-- 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
buffName, buffRank, buffIconPath, count, _, duration, expirationTime, caster = UnitAura(bar.unit, j, filter);
local buffRank, spellID, buffIconPath;
buffName, buffRank, buffIconPath, count, _, duration, expirationTime, caster, _, _, spellID = UnitAura(bar.unit, j, filter);
if (not buffName) then
break;
end
 
if (spellName == buffName and
spellIconPath == buffIconPath and
spellRank == buffRank )
then
break
if (spellID == barID) then
break;
else
buffName, count, duration, expirationTime, caster, buffIconPath = nil;
buffName, count, duration, expirationTime, caster = nil;
end
j=j+1;
end
492,58 → 840,105
startIndex=endIndex+1;
end
end
 
if ( not duration ) then
bar:Hide();
return;
else --if ( ( caster == "player" ) or ( caster == "pet" ) or ( caster == "vehicle" ) or not bar.onlyMine ) then
bar.duration = bar.fixedDuration or duration;
local timeLeft = expirationTime - GetTime();
bar.expirationTime = expirationTime;
bar:SetMinMaxValues(0, bar.duration);
bar:SetValue(timeLeft);
bar.spark:SetPoint("CENTER", bar, "LEFT", bar:GetWidth()*min(1, timeLeft/bar.duration), 0);
if ( count > 1 ) then
bar.text:SetText(buffName.." ["..count.."]");
end
 
-- There is an aura this bar is watching! Set it up
duration = tonumber(duration);
if ( duration ) then
-- Handle duration increases
local extended;
if (settings.bDetectExtends) then
local curStart = expirationTime - duration;
local guidTarget = UnitGUID(bar.unit);
if ( not NeedToKnow.last_cast[buffName] ) then
NeedToKnow.last_cast[buffName] = { state=0 };
end
local r = NeedToKnow.last_cast[buffName];
 
if ( not r[guidTarget] ) then
r[guidTarget] = { time=curStart, dur=duration };
elseif ( r[guidTarget].dur == 0 ) then
r[guidTarget].dur = duration
else
bar.text:SetText(buffName);
local rStart = r[guidTarget];
extended = expirationTime - rStart.time - rStart.dur;
if ( extended > 1 ) then
duration = rStart.dur;
end
end
bar:Show();
return;
end
bar:Hide(); -- move along. these aren't the buffs you're looking for.
else
 
bar.duration = tonumber(bar.fixedDuration) or duration;
bar.expirationTime = expirationTime;
bar.buffName = buffName;
 
NeedToKnow.ConfigureVisibleBar(bar, count, extended);
bar:Show();
else
bar:Hide();
end
end
 
--[[function NeedToKnow.Bar_WeaponCheck(bar)
local buffName, count, duration, expirationTime, caster, numBuffs
local startIndex=1;
_ , numBuffs = string.gsub(bar.auraName, "," , ",")
for i=0, numBuffs do
local endIndex = bar.auraName:find(",",startIndex,true) or (string.len(bar.auraName)+1);
function NeedToKnow.Fmt_SingleUnit(i_fSeconds)
return string.format(SecondsToTimeAbbrev(i_fSeconds));
end
 
buffName, _, _, count, _, duration, expirationTime, caster = UnitAura(bar.unit, strtrim(string.sub(bar.auraName, startIndex, endIndex-1)), nil, bar.buffOrDebuff);
if ( duration ) then
break;
else
startIndex=endIndex+1;
end
 
end
function NeedToKnow.Fmt_TwoUnits(i_fSeconds)
if ( i_fSeconds < 6040 ) then
local nMinutes, nSeconds;
nMinutes = floor(i_fSeconds / 60);
nSeconds = floor(i_fSeconds - nMinutes*60);
return string.format("%02d:%02d", nMinutes, nSeconds);
else
string.format(SecondsToTimeAbbrev(i_fSeconds));
end
end
 
]]--
function NeedToKnow.Fmt_Float(i_fSeconds)
return string.format("%0.1f", i_fSeconds);
end
 
function NeedToKnow.Bar_OnUpdate(self, elapsed)
local now = GetTime();
if ( now > self.nextUpdate ) then
self.nextUpdate = now + NEEDTOKNOW.UPDATE_INTERVAL;
 
local timeLeft = self.expirationTime - GetTime();
timeLeft = max(0, timeLeft);
self:SetValue(timeLeft);
self.time:SetFormattedText(SecondsToTimeAbbrev(timeLeft));
self.spark:SetPoint("CENTER", self, "LEFT", self:GetWidth()*min(1, timeLeft/self.duration), 0);
-- WORKAROUND: Although the existence of the enchant is correct at UNIT_INVENTORY_CHANGED
-- the expiry time is not yet correct. So we update the expiration every update :(
local origUnit = self.settings.Unit;
if ( origUnit == "mhand" ) then
-- The expiry time doesn't update right away, so we have to poll it
local mhEnchant, mhExpire = GetWeaponEnchantInfo()
self.expirationTime = GetTime() + mhExpire/1000;
elseif ( origUnit == "ohand" ) then
local _, _, _, ohEnchant, ohExpire = GetWeaponEnchantInfo()
self.expirationTime = GetTime() + ohExpire/1000;
end
 
if ( self.duration > 0 ) then
local timeLeft = self.expirationTime - GetTime();
timeLeft = max(0, timeLeft);
self:SetValue(timeLeft);
local fn = NeedToKnow[self.settings.TimeFormat];
local oldText = self.time:GetText();
local newText;
if ( fn ) then
newText = fn(timeLeft);
else
newText = string.format(SecondsToTimeAbbrev(timeLeft));
end
 
if ( newText ~= oldText ) then
self.time:SetText(newText);
end
if ( timeLeft <= self.duration ) then
self.spark:SetPoint("CENTER", self, "LEFT", self:GetWidth()*timeLeft/self.duration, 0);
self.spark:Show();
end
 
if ( self.vct_refresh ) then
NeedToKnow.UpdateVCT(self);
end
end
end
end
\ No newline at end of file +end
NeedToKnow/NeedToKnow.toc
1,7 → 1,7
## Interface: 30200
## Title: NeedToKnow
## Author: Bilt of Lightninghoof US
## Version: 2.6.0
## Interface: 30300
## Title: NeedToKnow - Updated!
## Author: Kitjan
## Version: 2.8.2
## Notes: Buff/debuff timer bars, original code by Nephthys of Hyjal-US Added support for multiple buffs per bar.
## OptionalDeps: LibStub,LibSharedMedia-3.0
## DefaultState: Enabled
NeedToKnow/NeedToKnow_Localization.lua
6,7 → 6,21
NEEDTOKNOW.BARMENU_TOTEM = "Totem";
NEEDTOKNOW.CMD_HIDE = "hide";
NEEDTOKNOW.CMD_SHOW = "show";
 
NEEDTOKNOW.BARMENU_TIMEFORMAT = "Time Format";
NEEDTOKNOW.FMT_SINGLEUNIT = "Single unit (2 m)";
NEEDTOKNOW.FMT_TWOUNITS = "Minutes and seconds (01:10)";
NEEDTOKNOW.FMT_FLOAT = "Fractional Seconds (70.1)";
NEEDTOKNOW.BARMENU_VISUALCASTTIME = "Visual Cast Time";
NEEDTOKNOW.BARMENU_VCT_ENABLE = "Enable for this bar";
NEEDTOKNOW.BARMENU_VCT_COLOR = "Overlay color";
NEEDTOKNOW.BARMENU_VCT_SPELL = "Choose cast time by spell";
NEEDTOKNOW.BARMENU_VCT_EXTRA = "Set additional time";
NEEDTOKNOW.BARMENU_MAIN_HAND = "Main Hand";
NEEDTOKNOW.BARMENU_OFF_HAND = "Off Hand";
NEEDTOKNOW.CHOOSE_VCT_SPELL_DIALOG = "Enter the name of a spell (in your spellbook) whose cast time will determine the base length of the visual cast time. If left blank, the aura name will be used as the spell name. To force this to be 0, type 0.";
NEEDTOKNOW.CHOOSE_VCT_EXTRA_DIALOG = "Enter an amount of seconds that will be added to the cast time of the spell. Ex: 1.5";
 
 
if ( GetLocale() == "deDE" ) then
-- Thanks, sp00n & Fxfighter EU-Echsenkessel!
NEEDTOKNOW.BAR_TOOLTIP1 = "NeedToKnow";
NeedToKnow/NeedToKnow_Options.lua
153,6 → 153,9
info.swatchFunc = NeedToKnow.SetColor;
info.cancelFunc = NeedToKnow.CancelColor;
info.extraInfo = variable;
-- Not sure if I should leave this state around or not. It seems like the
-- correct strata to have it at anyway, so I'm going to leave it there for now
ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG");
OpenColorPicker(info);
end
 
199,6 → 202,7
end
NeedToKnow.Show(true);
PlaySound("UChatScrollButton");
NeedToKnow.last_cast = {};
NeedToKnow.Update();
end
 
233,21 → 237,19
button2 = CANCEL,
hasEditBox = 1,
maxLetters = 255,
OnShow = function()
local edit = getglobal(this:GetName().."EditBox");
local groupID = NeedToKnow.CurrentBar["groupID"];
local barID = NeedToKnow.CurrentBar["barID"];
local curval = NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID]["AuraName"];
edit:SetFocus();
edit:SetText(curval);
end,
OnAccept = function(iconNumber)
local text = getglobal(this:GetParent():GetName().."EditBox"):GetText();
NeedToKnow.BarMenu_ChooseName(text);
local variable = this:GetParent().variable;
if ( nil ~= variable ) then
NeedToKnow.BarMenu_ChooseName(text, variable);
end
end,
EditBoxOnEnterPressed = function(iconNumber)
local text = getglobal(this:GetParent():GetName().."EditBox"):GetText();
NeedToKnow.BarMenu_ChooseName(text);
local variable = this:GetParent().variable;
if ( nil ~= variable ) then
NeedToKnow.BarMenu_ChooseName(text, variable);
end
this:GetParent():Hide();
end,
EditBoxOnEscapePressed = function()
265,9 → 267,16
};
 
NeedToKnow.BarMenu_MoreOptions = {
{ VariableName = "BuffOrDebuff", MenuText = NEEDTOKNOW.BARMENU_BUFFORDEBUFF, HasSubmenu = true },
{ VariableName = "Unit", MenuText = NEEDTOKNOW.BARMENU_CHOOSEUNIT, HasSubmenu = true },
};
{ VariableName = "Enabled", MenuText = NEEDTOKNOW.BARMENU_ENABLE },
{ VariableName = "AuraName", MenuText = NEEDTOKNOW.BARMENU_CHOOSENAME, Type = "Dialog", DialogText = "CHOOSENAME_DIALOG" },
{ VariableName = "BuffOrDebuff", MenuText = NEEDTOKNOW.BARMENU_BUFFORDEBUFF, Type = "Submenu" },
{ VariableName = "Unit", MenuText = NEEDTOKNOW.BARMENU_CHOOSEUNIT, Type = "Submenu" },
{ VariableName = "TimeFormat", MenuText = NEEDTOKNOW.BARMENU_TIMEFORMAT, Type = "Submenu" },
{ VariableName = "VisualCastTime", MenuText = NEEDTOKNOW.BARMENU_VISUALCASTTIME, Type = "Submenu" },
{ VariableName = "bDetectExtends", MenuText = "Track duration increases" }, -- FIXME: Localization
{ VariableName = "OnlyMine", MenuText = NEEDTOKNOW.BARMENU_ONLYMINE },
{ VariableName = "BarColor", MenuText = NEEDTOKNOW.BARMENU_BARCOLOR, Type = "Color" },
}
 
NeedToKnow.BarMenu_SubMenus = {
-- the keys on this table need to match the settings variable names
276,6 → 285,11
{ Setting = "HARMFUL", MenuText = NEEDTOKNOW.BARMENU_DEBUFF },
{ Setting = "TOTEM", MenuText = NEEDTOKNOW.BARMENU_TOTEM },
},
TimeFormat = {
{ Setting = "Fmt_SingleUnit", MenuText = NEEDTOKNOW.FMT_SINGLEUNIT },
{ Setting = "Fmt_TwoUnits", MenuText = NEEDTOKNOW.FMT_TWOUNITS },
{ Setting = "Fmt_Float", MenuText = NEEDTOKNOW.FMT_FLOAT },
},
Unit = {
{ Setting = "player", MenuText = NEEDTOKNOW.BARMENU_PLAYER },
{ Setting = "target", MenuText = NEEDTOKNOW.BARMENU_TARGET },
283,7 → 297,15
{ Setting = "focus", MenuText = NEEDTOKNOW.BARMENU_FOCUS },
{ Setting = "pet", MenuText = NEEDTOKNOW.BARMENU_PET },
{ Setting = "vehicle", MenuText = NEEDTOKNOW.BARMENU_VEHICLE },
{ Setting = "mhand", MenuText = NEEDTOKNOW.BARMENU_MAIN_HAND },
{ Setting = "ohand", MenuText = NEEDTOKNOW.BARMENU_OFF_HAND },
},
VisualCastTime = {
{ VariableName = "vct_enabled", MenuText = NEEDTOKNOW.BARMENU_VCT_ENABLE },
{ VariableName = "vct_color", MenuText = NEEDTOKNOW.BARMENU_VCT_COLOR, Type = "Color" },
{ VariableName = "vct_spell", MenuText = NEEDTOKNOW.BARMENU_VCT_SPELL, Type = "Dialog", DialogText = "CHOOSE_VCT_SPELL_DIALOG" },
{ VariableName = "vct_extra", MenuText = NEEDTOKNOW.BARMENU_VCT_EXTRA, Type = "Dialog", DialogText = "CHOOSE_VCT_SPELL_DIALOG", Numeric=true },
},
};
 
function NeedToKnow.Bar_OnEnter(self)
303,21 → 325,101
end
end
 
function NeedToKnow.BarMenu_AddButton(barSettings, i_desc, i_parent)
info = UIDropDownMenu_CreateInfo();
local type = i_desc["Type"];
info.text = i_desc["MenuText"];
info.value = i_desc["VariableName"];
if ( nil == info.value and nil ~= i_desc["Setting"]) then
info.value = i_parent;
type = "SetVar";
end;
 
local varSettings = barSettings[info.value];
if ( not varSettings and (type == "Check" or type == "Color") ) then
print (string.format("NTK: Could not find %s in", info.value), barSettings);
return
end
 
info.hasArrow = false;
info.checked = false;
--info.notCheckable = true; -- Doesn't prevent checking, just formats the line differently
info.keepShownOnClick = true;
 
if ( nil == type or type == "Check" ) then
info.func = NeedToKnow.BarMenu_ToggleSetting;
info.checked = (nil ~= varSettings and varSettings);
info.notCheckable = false;
elseif ( type == "SetVar" ) then
info.func = NeedToKnow.BarMenu_ChooseSetting;
info.value = i_desc["Setting"];
info.checked = (varSettings == info.value);
info.notCheckable = false;
info.keepShownOnClick = false;
elseif ( type == "Submenu" ) then
info.hasArrow = true;
elseif ( type == "Dialog" ) then
info.func = NeedToKnow.BarMenu_ShowNameDialog;
info.keepShownOnClick = false;
info.value = {variable = i_desc.VariableName, text = i_desc.DialogText, numeric = i_desc.Numeric };
elseif ( type == "Color" ) then
info.hasColorSwatch = 1;
info.hasOpacity = true;
info.r = varSettings.r;
info.g = varSettings.g;
info.b = varSettings.b;
info.opacity = 1 - varSettings.a;
info.swatchFunc = NeedToKnow.BarMenu_SetColor;
info.opacityFunc = NeedToKnow.BarMenu_SetOpacity;
info.cancelFunc = NeedToKnow.BarMenu_CancelColor;
 
info.func = UIDropDownMenuButton_OpenColorPicker;
info.keepShownOnClick = false;
end
 
UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
 
if ( type == "Color" ) then
-- Sadly, extraInfo isn't a field propogated to the button
-- Code to get the button copied from UIDropDownMenu_AddButton
local level = UIDROPDOWNMENU_MENU_LEVEL;
local listFrame = _G["DropDownList"..level];
local index = listFrame and (listFrame.numButtons) or 1;
local listFrameName = listFrame:GetName();
local button = getglobal(listFrameName.."Button"..index);
button.extraInfo = info.value;
end
end
 
function NeedToKnow.BarMenu_Initialize()
local groupID = NeedToKnow.CurrentBar["groupID"];
local barID = NeedToKnow.CurrentBar["barID"];
local barSettings = NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID];
 
if ( UIDROPDOWNMENU_MENU_LEVEL == 2 ) then
if ( UIDROPDOWNMENU_MENU_VALUE == "VisualCastTime" ) then
-- Create a summary title for the visual cast time submenu
local title = "";
if ( barSettings.vct_spell and "" ~= barSettings.vct_spell ) then
title = title .. barSettings.vct_spell;
end
local fExtra = tonumber(barSettings.vct_extra);
if ( fExtra and fExtra > 0 ) then
if ("" ~= title) then
title = title .. " + ";
end
title = title .. string.format("%0.1fs", fExtra);
end
if ( "" ~= title ) then
local info = UIDropDownMenu_CreateInfo();
info.text = title;
info.isTitle = true;
UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
end
end
local subMenus = NeedToKnow.BarMenu_SubMenus;
for index, value in ipairs(subMenus[UIDROPDOWNMENU_MENU_VALUE]) do
-- here, UIDROPDOWNMENU_MENU_VALUE is the setting name
local info = UIDropDownMenu_CreateInfo();
info.text = subMenus[UIDROPDOWNMENU_MENU_VALUE][index]["MenuText"];
info.value = subMenus[UIDROPDOWNMENU_MENU_VALUE][index]["Setting"];
info.checked = ( info.value == NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID][UIDROPDOWNMENU_MENU_VALUE] );
info.func = NeedToKnow.BarMenu_ChooseSetting;
UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
NeedToKnow.BarMenu_AddButton(barSettings, value, UIDROPDOWNMENU_MENU_VALUE);
end
return;
end
330,61 → 432,12
UIDropDownMenu_AddButton(info);
end
 
-- enable bar
info = UIDropDownMenu_CreateInfo();
info.value = "Enabled";
info.text = NEEDTOKNOW.BARMENU_ENABLE;
info.checked = barSettings.Enabled;
info.func = NeedToKnow.BarMenu_ToggleSetting;
info.keepShownOnClick = true;
UIDropDownMenu_AddButton(info);
 
-- choose aura name
info = UIDropDownMenu_CreateInfo();
info.value = "NEEDTOKNOW.BARMENU_CHOOSENAME";
info.text = NEEDTOKNOW.BARMENU_CHOOSENAME;
info.func = NeedToKnow.BarMenu_ShowNameDialog;
UIDropDownMenu_AddButton(info);
 
local moreOptions = NeedToKnow.BarMenu_MoreOptions;
for index, value in ipairs(moreOptions) do
info = UIDropDownMenu_CreateInfo();
info.text = moreOptions[index]["MenuText"];
info.value = moreOptions[index]["VariableName"];
info.hasArrow = moreOptions[index]["HasSubmenu"];
if not info.hasArrow then
info.func = NeedToKnow.BarMenu_ToggleSetting;
info.checked = NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["bars"][barID][info.value];
end
info.keepShownOnClick = true;
UIDropDownMenu_AddButton(info);
NeedToKnow.BarMenu_AddButton(barSettings, moreOptions[index]);
end
 
-- only show if cast by self?
info = UIDropDownMenu_CreateInfo();
info.value = "OnlyMine";
info.text = NEEDTOKNOW.BARMENU_ONLYMINE;
info.checked = barSettings.OnlyMine;
info.func = NeedToKnow.BarMenu_ToggleSetting;
info.keepShownOnClick = true;
UIDropDownMenu_AddButton(info);
 
-- choose bar color
info = UIDropDownMenu_CreateInfo();
info.text = NEEDTOKNOW.BARMENU_BARCOLOR;
info.hasColorSwatch = 1;
info.hasOpacity = true;
info.r = barSettings.BarColor.r;
info.g = barSettings.BarColor.g;
info.b = barSettings.BarColor.b;
info.opacity = 1 - barSettings.BarColor.a;
info.func = UIDropDownMenuButton_OpenColorPicker;
info.swatchFunc = NeedToKnow.BarMenu_SetColor;
info.opacityFunc = NeedToKnow.BarMenu_SetOpacity;
info.cancelFunc = NeedToKnow.BarMenu_CancelColor;
UIDropDownMenu_AddButton(info);
 
info = UIDropDownMenu_CreateInfo();
info.disabled = true;
UIDropDownMenu_AddButton(info);
 
394,47 → 447,153
info.func = NeedToKnow.BarMenu_ClearSettings;
UIDropDownMenu_AddButton(info);
 
if ( false == barSettings.OnlyMine ) then
NeedToKnow.BarMenu_UncheckAndDisable(groupID, barID, "bDetectExtends");
end
end
 
function NeedToKnow.BarMenu_ToggleSetting()
function NeedToKnow.BarMenu_ToggleSetting(self, a1, a2, checked)
local groupID = NeedToKnow.CurrentBar["groupID"];
local barID = NeedToKnow.CurrentBar["barID"];
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID][this.value] = this.checked;
if ( this.value == "OnlyMine" ) then
if ( false == this.checked ) then
NeedToKnow.BarMenu_UncheckAndDisable(groupID, barID, "bDetectExtends");
else
NeedToKnow.BarMenu_EnableItem(groupID, barID, "bDetectExtends");
end
end
NeedToKnow.Bar_Update(groupID, barID);
end
 
function NeedToKnow.BarMenu_ChooseSetting()
function NeedToKnow.BarMenu_UncheckAndDisable(groupID, barID, i_valueName)
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID][i_valueName] = false;
 
local listFrame = _G["DropDownList"..1];
local listFrameName = listFrame:GetName();
local n = listFrame.numButtons;
for index=1,n do
local button = getglobal(listFrameName.."Button"..index);
local txt = button.value;
if ( txt == i_valueName ) then
getglobal(listFrameName.."Button"..index.."Check"):Hide();
button.checked = false;
button:Disable();
break;
end;
end
end
 
function NeedToKnow.BarMenu_EnableItem(groupID, barID, i_valueName)
local listFrame = _G["DropDownList"..1];
 
local listFrameName = listFrame:GetName();
local n = listFrame.numButtons;
for index=1,n do
local button = getglobal(listFrameName.."Button"..index);
local txt = button.value;
if ( txt == i_valueName ) then
button:Enable();
break;
end;
end
end
 
function NeedToKnow.BarMenu_ChooseSetting(self, a1, a2, checked)
local groupID = NeedToKnow.CurrentBar["groupID"];
local barID = NeedToKnow.CurrentBar["barID"];
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID][UIDROPDOWNMENU_MENU_VALUE] = this.value;
NeedToKnow.Bar_Update(groupID, barID);
end
 
function NeedToKnow.BarMenu_ShowNameDialog()
-- TODO: There has to be a better way to do this, this has pretty bad user feel
function NeedToKnow.EditBox_Numeric_OnTextChanged(self, isUserInput)
if ( isUserInput ) then
local txt = self:GetText();
local culled = txt:gsub("[^0-9.]",""); -- Remove non-digits
local iPeriod = culled:find("[.]");
if ( nil ~= iPeriod ) then
local before = culled:sub(1, iPeriod);
local after = string.gsub( culled:sub(iPeriod+1), "[.]", "" );
culled = before .. after;
end
if ( txt ~= culled ) then
self:SetText(culled);
end
end
 
if ( NeedToKnow.EditBox_Original_OnTextChanged ) then
NeedToKnow.EditBox_Original_OnTextChanged(self, isUserInput);
end
end
 
function NeedToKnow.BarMenu_ShowNameDialog(self, a1, a2, checked)
StaticPopupDialogs["NEEDTOKNOW.CHOOSENAME_DIALOG"].text = NEEDTOKNOW[this.value.text];
local dialog = StaticPopup_Show("NEEDTOKNOW.CHOOSENAME_DIALOG");
dialog.variable = this.value.variable;
 
local edit = getglobal(dialog:GetName().."EditBox");
local groupID = NeedToKnow.CurrentBar["groupID"];
local barID = NeedToKnow.CurrentBar["barID"];
local curval = NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID][dialog.variable];
 
local numeric = this.value.numeric or false;
-- TODO: There has to be a better way to do this, this has pretty bad user feel
if ( nil == NeedToKnow.EditBox_Original_OnTextChanged ) then
NeedToKnow.EditBox_Original_OnTextChanged = edit:GetScript("OnTextChanged");
end
if ( numeric ) then
edit:SetScript("OnTextChanged", NeedToKnow.EditBox_Numeric_OnTextChanged);
else
edit:SetScript("OnTextChanged", NeedToKnow.EditBox_Original_OnTextChanged);
end
edit:SetFocus();
edit:SetText(curval);
 
end
 
function NeedToKnow.BarMenu_ChooseName(text)
function NeedToKnow.BarMenu_ChooseName(text, variable)
local groupID = NeedToKnow.CurrentBar["groupID"];
local barID = NeedToKnow.CurrentBar["barID"];
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID]["AuraName"] = text;
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID][variable] = text;
NeedToKnow.Bar_Update(groupID, barID);
end
 
function MemberDump(v, bIndex)
print("members")
for index, value in pairs(v) do
print(" ", index, value);
end
local mt = getmetatable(v)
if ( mt ) then
print("metatable")
for index, value in pairs(mt) do
print(" ", index, value);
end
if ( mt.__index and bIndex) then
print("__index")
for index, value in pairs(mt.__index) do
print(" ", index, value);
end
end
end
end
 
function NeedToKnow.BarMenu_SetColor()
local groupID = NeedToKnow.CurrentBar["groupID"];
local barID = NeedToKnow.CurrentBar["barID"];
local r,g,b = ColorPickerFrame:GetColorRGB();
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID]["BarColor"]["r"] = r;
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID]["BarColor"]["g"] = g;
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID]["BarColor"]["b"] = b;
local varSettings = NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID][ColorPickerFrame.extraInfo];
 
varSettings.r,varSettings.g,varSettings.b = ColorPickerFrame:GetColorRGB();
NeedToKnow.Bar_Update(groupID, barID);
end
 
function NeedToKnow.BarMenu_SetOpacity()
local groupID = NeedToKnow.CurrentBar["groupID"];
local barID = NeedToKnow.CurrentBar["barID"];
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID]["BarColor"]["a"] = 1 - OpacitySliderFrame:GetValue();
local varSettings = NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID][ColorPickerFrame.extraInfo];
 
varSettings.a = 1 - OpacitySliderFrame:GetValue();
NeedToKnow.Bar_Update(groupID, barID);
end
 
442,10 → 601,12
if ( previousValues.r ) then
local groupID = NeedToKnow.CurrentBar["groupID"];
local barID = NeedToKnow.CurrentBar["barID"];
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID]["BarColor"]["r"] = previousValues.r;
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID]["BarColor"]["g"] = previousValues.g;
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID]["BarColor"]["b"] = previousValues.b;
NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID]["BarColor"]["a"] = 1 - previousValues.opacity;
local varSettings = NeedToKnow_Settings["Spec"][NEEDTOKNOW.CURRENTSPEC]["Groups"][groupID]["Bars"][barID][ColorPickerFrame.extraInfo];
 
varSettings.r = previousValues.r;
varSettings.g = previousValues.g;
varSettings.b = previousValues.b;
varSettings.a = 1 - previousValues.opacity;
NeedToKnow.Bar_Update(groupID, barID);
end
end
NeedToKnow/readme.txt
1,22 → 1,13
 
--------------------
NeedToKnow
by Nephthys of Hyjal
by Kitjan
--------------------
 
 
NeedToKnow allows you to monitor specific buffs and debuffs of your choosing as timer bars that always appear in a consistent place on your screen in a consistent color. It's especially useful for monitoring frequently used short-duration buffs and debuffs. For example, a rogue could configure NeedToKnow to show timer bars for Slice and Dice, Rupture, and their own stack of Deadly Poison VII. A death knight could use it to track their own diseases on a mob. NeedToKnow also works with procs and on-use trinkets. The number, size, position, and appearance of timer bars are all customizable.
 
 
---------------------------
New in latest version (2.2)
---------------------------
 
- Added option to show bars with a fixed maximum duration
- Fixed an issue with targetoftarget
- Added koKR and deDE localization
 
 
------------
Instructions
------------
27,17 → 18,63
 
 
----------
To do list
Change log
----------
 
- Add option to track multiple buffs/debuffs with a single bar
- Add options to customize text display
2.8.0
- Added the ability to track increases in spell duration, especially useful for dps druids
- Marked as being a 3.3 addon
- Fixed: Took advantage of a new 3.3 API to get the spell id of active buffs and debuffs. Bars that check spellid should be much more reliable and, for example, be able to tell the difference between the two different Death's Verdict procs
- Fixed: Totem timing is much more accurate
- Fixed: Visual cast times now updates based on changes in haste and other casting-time-affecting abilities
 
2.7.1
- Fixed: Accidentally removed the background color picker
 
----------
Change log
----------
2.7.0
- Added options for how the time text is formatted. The current style is the default, with mm:ss and ss.t as other options
- Added "visual cast time" overlay which can be used to tell when there's less than some critical amount of time left on an aura
- Hid the spark when the aura lasts longer than the bar (either an infinite duration, or using the Max duration feature.)
- Hid the time text when the aura has an infinite duration
 
2.6.0
- Added support for a new "Buff or Debuff" type: Totem. Type in the name of the totem to watch for (can be a partial string.)
- Fixed a parse error in the DE localization
- Slightly improved performance of "target of target"
- Added two new /ntk options: show and hide. They can be used to temporarily show and hide the ntk groups.
 
2.5.2
-Changed event parsing to try to be more robust (see autobot's errors)
 
2.5.1
-Trying a different strategy for identifying "only cast by me" spells
-When editing the watched auras, the edit field starts with the current value
-Configuring by SpellID is automatically detected and does not need a menu item checked
 
2.5
-Fixed ToT issue
-Added support for SpellID
 
2.4.3
-Added SharedMedia support, uses LibSharedMedia-3.0
-Greatly improved performance
 
2.4.2
-Fixed a bug with the multiple buffs per line
-Fixed a small bug with resize button showing
-Optimized performance slightly
 
2.4.1
 
-Fixed character restriction on buff names, no accepts up to 255 characters.
-Added Russian localization
 
2.4
 
-Brought up to 3.2 API standards
-Added multiple buffs/debuffs per bar
-Dual-Specialization support
 
Version 2.2
- Added option to show bars with a fixed maximum duration
- Fixed an issue with targetoftarget
. Property changes : Added: svn:ignore + archive zips