vanilla-wow-addons – Rev 1
?pathlinks?
--------------------------------------------------------
-- Ralak's Needy List
-- a UI modification by Ralak of Kel'Thuzad
-- German Localization by Nitram from DE-Azshara
-- French Localization by Olivier Bockstal
--------------------------------------------------------
NL_CURRENT_VERSION = 2.05;
NL_DEBUG_MODE = false;
NL_MAX_TOOLTIP_BUFFS = 16;
NL_MAX_TOOLTIP_DEBUFFS = 16;
NL_MAX_NEEDS = 12;
NL_BLACK_LIST = {};
NL_MINIMIZED = false;
NL_SLOTS = {};
NL_NUM_NEEDY_UNITS = 0;
NL_PLAYERCLASS = "";
NL_ITERATOR = 1;
NeedyListDetails = {
name = 'Ralak\'s Needy List',
description = 'Monitor needy units in your party or raid group.',
version = NL_CURRENT_VERSION,
releaseDate = 'June 25, 2006',
author = 'Carson Knittig',
email = 'needylist@gmail.com',
category = MYADDONS_CATEGORY_RAID,
frame = 'NLMainFrame',
optionsframe = 'NLConfigFrame'
};
NL_CLASS_COLORS = {};
NL_CLASS_COLORS[NL_PRIEST_NAME] = {r = 1.0, g = 1.0, b = 1.0};
NL_CLASS_COLORS[NL_DRUID_NAME] = {r = 0.0, g = 1.0, b = 0.0};
NL_CLASS_COLORS[NL_MAGE_NAME] = {r = 0.0, g = 0.0, b = 1.0};
NL_CLASS_COLORS[NL_PALADIN_NAME] = {r = 1.0, g = 1.0, b = 0.0};
NL_CLASS_COLORS[NL_WARLOCK_NAME] = {r = 0.5, g = 0.25, b = 0.6};
NL_CLASS_COLORS[NL_ROGUE_NAME] = {r = 0.5, g = 0.5, b = 0.5};
NL_CLASS_COLORS[NL_SHAMAN_NAME] = {r = 1.0, g = 1.0, b = 0.0};
NL_CLASS_COLORS[NL_WARRIOR_NAME] = {r = 1.0, g = 0.0, b = 0.0};
NL_CLASS_COLORS[NL_BEAST_NAME] = {r = 0.5, g = 0.4, b = 0.25};
NL_CLASS_COLORS[NL_DEMON_NAME] = {r = 1.0, g = 0.6, b = 0.25};
NL_CLASS_COLORS["Default"] = {r = 0.25, g = 0.25, b = 0.25};
NL_WEAKENED_SOUL = "Interface\\Icons\\Spell_Holy_AshesToAshes";
NL_BANISH = "Interface\\Icons\\Spell_Shadow_Cripple";
NL_PHASE_SHIFT = "Interface\\Icons\\Spell_Shadow_ImpPhaseShift";
NL_MINDCONTROL = "Interface\\Icons\\Spell_Shadow_ShadowWordDominate";
NL_MINDCONTROLCAP = "Interface\\Icons\\Spell_Magic_MageArmor";
NL_FEIGNDEATH = "Interface\\Icons\\Ability_Rogue_FeignDeath";
NL_CLICK_INDICES = {LeftButton = 1, RightButton = 2, MiddleButton = 3, Button4 = 4, Button5 = 5};
NL_ICON_LOCATION = "Interface\\Icons\\";
NLAnchors = { {
AnchorPoint = "TOPLEFT",
ReferenceAnchorPoint = "BOTTOMLEFT",
Offset = -1,
},
{
AnchorPoint = "BOTTOMLEFT",
ReferenceAnchorPoint = "TOPLEFT",
Offset = 1,
}
};
function NL_Msg(msg)
DEFAULT_CHAT_FRAME:AddMessage(msg);
end
function NL_DebugMsg(msg)
if( NL_DEBUG_MODE ) then
DEFAULT_CHAT_FRAME:AddMessage(msg);
end
end
function NL_PrintTable()
local test1, test2, test3, test4 = NLMemberplayer:GetPoint("TOPLEFT");
table.foreach( test2, NL_Msg );
NL_Msg( test3 .. test4 );
end
function NL_OnLoad()
-- Register Events
NLMainFrame:RegisterEvent("UNIT_NAME_UPDATE");
NLMainFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
NLMainFrame:RegisterEvent("UNIT_HEALTH");
NLMainFrame:RegisterEvent("UNIT_MANA");
NLMainFrame:RegisterEvent("UNIT_RAGE");
NLMainFrame:RegisterEvent("UNIT_FOCUS");
NLMainFrame:RegisterEvent("UNIT_ENERGY");
NLMainFrame:RegisterEvent("UNIT_AURA");
NLMainFrame:RegisterEvent("PARTY_MEMBERS_CHANGED");
NLMainFrame:RegisterEvent("RAID_ROSTER_UPDATE");
NLMainFrame:RegisterEvent("UNIT_PET");
NLMainFrame:RegisterEvent("VARIABLES_LOADED");
NLMainFrame:RegisterEvent("PLAYER_TARGET_CHANGED");
-- Add Slash Commands
SlashCmdList["NLCONFIG"] = NL_Configure;
SLASH_NLCONFIG1 = "/nlconfig";
-- get this player's class so we know which buffs and debuffs to notify him/her of
NL_PLAYERCLASS = UnitClass("player");
if( DEFAULT_CHAT_FRAME ) then
DEFAULT_CHAT_FRAME:AddMessage(NL_STR_INTRO_PREFIX..NL_CURRENT_VERSION..NL_STR_INTRO_SUFFIX);
DEFAULT_CHAT_FRAME:AddMessage(NL_STR_INTRO_DESC);
end
-- set the units on each frame so they never have to be set again
NLMemberplayer.Unit = "player";
NLMemberpet.Unit = "pet";
NLMembertarget.Unit = "target";
for NL_ITERATOR=1, 4 do
getglobal("NLMemberparty"..NL_ITERATOR).Unit = "party"..NL_ITERATOR;
getglobal("NLMemberpartypet"..NL_ITERATOR).Unit = "partypet"..NL_ITERATOR;
end
for NL_ITERATOR=1, 40 do
getglobal("NLMemberraid"..NL_ITERATOR).Unit = "raid"..NL_ITERATOR;
getglobal("NLMemberraidpet"..NL_ITERATOR).Unit = "raidpet"..NL_ITERATOR;
end
end
function NL_CheckIfEnabled()
local bRaid = GetNumRaidMembers() > 0;
local bParty = UnitExists("party1") and not bRaid;
local bSolo = not ( bParty or bRaid );
if( ( bRaid and NLConfig.UseInRaid == 1 ) or ( bParty and NLConfig.UseInParty == 1 ) or ( bSolo and NLConfig.UseWhenSolo == 1 ) ) then
NL_Enable();
else
NL_Disable();
end
end
function NL_Disable()
NL_ENABLED = false;
NLHeader:Hide();
getglobal("NLMemberplayer"):Hide();
getglobal("NLMemberpet"):Hide();
for NL_ITERATOR=1, 4 do
getglobal("NLMemberparty"..NL_ITERATOR):Hide();
getglobal("NLMemberpartypet"..NL_ITERATOR):Hide();
end
for NL_ITERATOR=1, 40 do
getglobal("NLMemberraid"..NL_ITERATOR):Hide();
getglobal("NLMemberraidpet"..NL_ITERATOR):Hide();
end
end
function NL_Enable()
NL_ENABLED = true;
NLHeader:Show();
NLMember_CheckAllUnits();
end
function NL_Configure()
NLConfigFrame:Show();
end
function NL_OnEvent(event, arg1)
--Player loaded completely
if ( event == "UNIT_NAME_UPDATE" and arg1 == "player" ) or (event=="PLAYER_ENTERING_WORLD") then
-- get the configs for this player
NLConfig = NL_GetConfigForCurrentPlayer( false );
NL_CheckIfEnabled();
if( not NL_ENABLED ) then
return;
end
NLHeader:Show();
NLMember_CheckAllUnits();
return;
end
if( NLConfig == nil ) then
return;
end
-- this check is only for enabling the needy list based on party status
if( event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE" ) then
NL_CheckIfEnabled();
end
if( not NL_ENABLED ) then
return;
end
if( event == "PLAYER_TARGET_CHANGED" ) then
NL_CheckTarget();
return;
end
-- if this is a stat or buff change on a unit
if ( event == "UNIT_HEALTH" or event == "UNIT_MANA" or event == "UNIT_RAGE" or event == "UNIT_FOCUS" or event == "UNIT_ENERGY" or event == "UNIT_AURA" ) then
-- if the unit is blacklisted or never shown, just return
if( arg1 ~= "target" ) then
for NL_ITERATOR = 1, table.getn(NL_BLACK_LIST) do
if( NL_BLACK_LIST[NL_ITERATOR].Unit == arg1 ) then
return;
end
end
end
-- if I'm in a raid group, only use units with raid in their name
local criteria;
if( GetNumRaidMembers() > 0 ) then
criteria = string.find( arg1, "raid" ) ~= nil;
elseif( GetNumPartyMembers() > 0 ) then
criteria = string.find( arg1, "party" ) ~= nil or arg1 == "player" or arg1 == "pet";
else
criteria = arg1 == "player" or arg1 == "pet";
end
-- if this player is in the raid or party, or is the default player
if( criteria or (arg1 == "target" and UnitIsFriend("target", "player") and NLConfig.ShowTargetFrame == 1)) then
if( getglobal("NLMember"..arg1).TopNeed and getglobal("NLMember"..arg1).TopNeed == 0 ) then
return;
end
if( not NL_CheckForResurrectionNeed( arg1 ) ) then
if( NLConfig.ResurrectionNeedIndex ) then
if( getglobal("NLMember"..arg1).Needs[NLConfig.ResurrectionNeedIndex] ) then
getglobal("NLMember"..arg1).Needs[NLConfig.ResurrectionNeedIndex] = false;
NL_CheckAllNeeds(arg1);
return;
end
end
if( event == "UNIT_HEALTH" ) then
if( NL_CheckHealth( arg1 ) ) then
NL_AddToList( arg1 );
else
NL_RemoveFromList( arg1 );
end
elseif( event == "UNIT_AURA" ) then
if( NL_CheckAura( arg1 ) ) then
NL_AddToList( arg1 );
if( getglobal("NLMember"..arg1):IsShown() ) then
NL_UpdateAura( arg1 );
end
else
NL_RemoveFromList( arg1 );
end
else
if( NL_CheckMana( arg1 ) ) then
NL_AddToList( arg1 );
else
NL_RemoveFromList( arg1 );
end
end
if( getglobal("NLMember"..arg1):IsShown() ) then
NL_UpdateUnit( arg1 );
end
end
end
return;
end
if( event == "UNIT_PET" ) then
local criteria;
local prefix;
local suffix;
if( GetNumRaidMembers() > 0 ) then
criteria = string.find( arg1, "raid" ) ~= nil;
prefix = "raid";
suffix = string.sub( arg1, 5 );
else
-- the reason we only check the player here is because in a raid, the player is treated as a raid member as well as the player
-- no sense updating twice!
if( arg1 == "player" ) then
NL_CheckAllNeeds( "pet" );
return;
else
criteria = string.find( arg1, "party" ) ~= nil;
prefix = "party";
suffix = string.sub( arg1, 6 );
end
end
-- if we're in a raid, check raid members
-- if not, check party members, or do nothing if we already found the player
if( criteria ) then
local petUnit = prefix .. "pet" .. suffix;
NL_DebugMsg( "pet event for "..petUnit .. " was caught");
NL_CheckAllNeeds( petUnit );
end
return;
end
if( event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE" ) then
NLMember_CheckAllUnits();
return;
end
if( event == "VARIABLES_LOADED" ) then
-- Register the addon in myAddOns
if(myAddOnsFrame_Register) then
myAddOnsFrame_Register(NeedyListDetails);
end
return;
end
end
function NL_UnitPassesFilter( unit, filter )
if( filter == nil or filter.Type == "Everyone" ) then
return true;
end
if( filter.Type == "Units" ) then
if( string.find( filter.Names, UnitName( unit ) ) ) then
local foundName = string.sub( filter.Names, string.find( filter.Names, UnitName( unit ) ) );
if( string.find( foundName, "," ) ) then
foundName = string.sub( foundName, string.find( foundName, "," ) - 1 );
end
if( foundName == UnitName( unit ) ) then
return true;
end
end
end
-- if the filter is by party, use the unit name to determine which party and check if that party is being monitored
-- party filter is only valid in raids, so if you're not in a raid, pretend filter is everyone
if( filter.Type == "Multi" ) then
local bPassedPartyCheck = false;
if( unit == "target" ) then
bPassedPartyCheck = true;
else
if( ( UnitInParty(unit) or string.find( unit, "partypet" ) or unit == "pet" ) and filter.Names["My Party"] ) then
bPassedPartyCheck = true;
elseif( string.find( unit, "raid" ) ~= nil ) then
local raidIndex;
if( string.find( unit, "raidpet" ) ~= nil ) then
raidIndex = string.sub( unit, 8 );
else
raidIndex = string.sub( unit, 5 );
end
local name, rank, subgroup = GetRaidRosterInfo(raidIndex);
if( filter.Names["Party " .. subgroup] ) then
bPassedPartyCheck = true;
end
end
end
if( bPassedPartyCheck ) then
if( string.find( unit, "pet" ) ~= nil ) then
if( filter.Names[UnitCreatureType( unit )] ) then
return true;
end
else
if( filter.Names[UnitClass( unit )] ) then
return true;
end
end
end
end
return false;
end
function NL_ClearNeedDetails(member)
-- clear the need buttons in the needdetails frame
local frameName = "NLMember" .. member;
for NL_ITERATOR=1, NL_MAX_NEEDS do
getglobal(frameName .. "NeedsDetailsNeed" .. NL_ITERATOR):Hide();
end
getglobal(frameName .. "NeedsDetails"):Hide();
end
function NL_GetUnitBuffsAndDebuffs( member )
local buffList = {};
local debuffList = {};
local debuffTypeList = {};
NL_ITERATOR = 1;
local buff = UnitBuff(member, NL_ITERATOR);
while( buff ~= nil ) do
buffList[buff] = true;
NL_ITERATOR = NL_ITERATOR + 1;
buff = UnitBuff(member, NL_ITERATOR);
end
NL_ITERATOR = 1;
local debuff = UnitDebuff(member, NL_ITERATOR);
while( debuff ~= nil ) do
-- do not add the ignored debuffs to the debuff lists
if( debuff ~= NL_ICON_LOCATION.."Spell_Holy_MindVision" ) then
debuffList[debuff] = true;
NL_BuffTooltipTextRight1:SetText(nil);
NL_BuffTooltip:SetUnitDebuff( member, NL_ITERATOR );
local debuffType = NL_BuffTooltipTextRight1:GetText();
if( debuffType ) then
debuffTypeList[debuffType] = true;
end
end
NL_ITERATOR = NL_ITERATOR + 1;
debuff = UnitDebuff(member, NL_ITERATOR);
end
if( string.find( member, "pet" ) and ((buffList and buffList[NL_PHASE_SHIFT]) or (debuffList and debuffList[NL_BANISH] )) ) then
NL_RemoveFromList( member );
return nil;
end
if( debuffList and (debuffList[NL_MINDCONTROL] or debuffList[NL_MINDCONTROLCAP]) and UnitIsFriend("player", member) ) then
NL_RemoveFromList( member );
return nil;
end
return buffList, debuffList, debuffTypeList;
end
function NL_CheckAura( member )
local buffList, debuffList, debuffTypeList = NL_GetUnitBuffsAndDebuffs( member );
if( buffList == nil ) then
return false;
end
local foundNewTopNeed = false;
local unitFrame = getglobal("NLMember"..member);
-- 0 and 1 are never show and sticky, so don't need to go thru them here
for NL_ITERATOR = 2, NLConfig.NumNeeds - 1 do
local CurrentNeed = NLConfig.Needs[NL_ITERATOR];
if( CurrentNeed.Toggle == 1 and NL_UnitPassesFilter( member, CurrentNeed.Filter ) ) then
local FoundNeed = false;
if( CurrentNeed.Name == "WellFed" ) then
if( not buffList[NL_ICON_LOCATION .. NL_OTHER.WellFed.Icon] ) then
FoundNeed = true;
end
elseif( CurrentNeed.Type == "BUFF" and debuffList ) then
if( not NL_FindInBuffList( CurrentNeed.Name, buffList ) ) then
-- if the buff is power word shield, need to look for the weakened soul debuff before finding need
if( CurrentNeed.Name == "PWShield" ) then
if( not debuffList[NL_WEAKENED_SOUL] ) then
FoundNeed = true;
end
else
-- didn't find buff on unit, need it
FoundNeed = true;
end
end
elseif( CurrentNeed.Type == "ENCHANT" ) then
local hasMainHandEnchant, mainHandExpiration, mainHandCharges,
hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo()
if( NL_PLAYERCLASS == NL_SHAMAN_NAME ) then
if( hasMainHandEnchant ~= 1 ) then
FoundNeed = true;
end
elseif( NL_PLAYERCLASS == NL_ROGUE_NAME ) then
if( ( CurrentNeed.Name == "MainhandPoison" and hasMainHandEnchant ~= 1 ) or
( CurrentNeed.Name == "OffhandPoison" and hasOffHandEnchant ~= 1 ) ) then
FoundNeed = true;
end
end
elseif( CurrentNeed.Type == "DEBUFF" and debuffTypeList ) then
if( debuffTypeList[CurrentNeed.Name] ) then
-- found debuff on unit, this is the highest priority need
FoundNeed = true;
end
end
if( FoundNeed ) then
unitFrame.Needs[NL_ITERATOR] = true;
if( not foundNewTopNeed ) then
NL_SetNewTopNeed( unitFrame, NL_ITERATOR );
foundNewTopNeed = true;
end
elseif( NL_ITERATOR ~= NLConfig.HealthNeedIndex and NL_ITERATOR ~= NLConfig.ManaNeedIndex and NL_ITERATOR ~= NLConfig.ResurrectionNeedIndex ) then
unitFrame.Needs[NL_ITERATOR] = false;
if( unitFrame.TopNeed == NL_ITERATOR ) then
NL_SetNewTopNeed( unitFrame, NL_ITERATOR );
end
end
end
end
if( unitFrame.TopNeed and unitFrame.TopNeed > 0 ) then
return true;
end
return false;
end
function NL_CheckHealth( member )
if( not NL_GetUnitBuffsAndDebuffs( member ) ) then
return false;
end
local unitFrame = getglobal("NLMember"..member);
unitFrame.CurrentHealth = UnitHealth( member ) / UnitHealthMax( member ) * 100;
if( not NLConfig.HealthNeedIndex ) then
if( unitFrame.TopNeed and unitFrame.TopNeed > 0 ) then
return true;
end
return false;
end
local HealthNeed = NLConfig.Needs[NLConfig.HealthNeedIndex];
if( HealthNeed.Toggle == 1 and NL_UnitPassesFilter( member, HealthNeed.Filter ) ) then
if(unitFrame.CurrentHealth < HealthNeed.Threshold or
(unitFrame.CurrentHealth < min(HealthNeed.Threshold + 5,99) and unitFrame.SlotIndex and
unitFrame.TopNeed == NLConfig.HealthNeedIndex ) ) then
-- needs health
unitFrame.Needs[NLConfig.HealthNeedIndex] = true;
else
unitFrame.Needs[NLConfig.HealthNeedIndex] = false;
end
else
unitFrame.Needs[NLConfig.HealthNeedIndex] = false;
end
return NL_SetNewTopNeed( unitFrame, NLConfig.HealthNeedIndex );
end
function NL_CheckMana( member )
if( not NL_GetUnitBuffsAndDebuffs( member ) ) then
return false;
end
local unitFrame = getglobal("NLMember"..member);
unitFrame.CurrentMana = UnitMana( member ) / UnitManaMax( member ) * 100;
if( not NLConfig.ManaNeedIndex ) then
if( unitFrame.TopNeed and unitFrame.TopNeed > 0 ) then
return true;
end
return false;
end
local ManaNeed = NLConfig.Needs[NLConfig.ManaNeedIndex];
if( ManaNeed.Toggle == 1 and NL_UnitPassesFilter( member, ManaNeed.Filter ) ) then
if( UnitPowerType(member) == 0 and (unitFrame.CurrentMana < ManaNeed.Threshold or
(unitFrame.CurrentMana < min(ManaNeed.Threshold + 5,99) and unitFrame:IsShown() and
NLConfig.ManaNeedIndex and unitFrame.TopNeed == NLConfig.ManaNeedIndex ) ) ) then
-- needs mana
unitFrame.Needs[NLConfig.ManaNeedIndex] = true;
else
unitFrame.Needs[NLConfig.ManaNeedIndex] = false;
end
else
unitFrame.Needs[NLConfig.ManaNeedIndex] = false;
end
return NL_SetNewTopNeed( unitFrame, NLConfig.ManaNeedIndex );
end
function NL_SetNewTopNeed( unitFrame, index )
if( unitFrame.Needs[index] == true and (not unitFrame.TopNeed or unitFrame.TopNeed > index) ) then
unitFrame.TopNeed = index;
elseif( unitFrame.Needs[index] == false and unitFrame.TopNeed == index ) then
-- the next need is the new top need because health is no longer a need
-- find the first true need in the unit's needs
for NL_ITERATOR = 1, NLConfig.NumNeeds - 1 do
if( unitFrame.Needs[NL_ITERATOR] ) then
unitFrame.TopNeed = NL_ITERATOR;
return true;
end
end
-- if we got here, there is no longer a top need, so this unit can be removed
unitFrame.TopNeed = nil;
return false;
end
return true;
end
function NL_CheckAllNeeds( member )
-- first, make sure the unit exists
if( not UnitExists( member ) or UnitName( member ) == "" or UnitName( member ) == nil or not UnitIsConnected( member ) ) then
NL_RemoveFromList( member );
return;
end
-- check if never show
if( NLConfig.Needs[0].Toggle == 1 and NL_UnitPassesFilter( getglobal("NLMember"..member).Unit, NLConfig.Needs[0].Filter ) ) then
getglobal("NLMember"..member).TopNeed = 0;
return;
end
-- check if stickied
if( NLConfig.Needs[1].Toggle == 1 and NL_UnitPassesFilter( getglobal("NLMember"..member).Unit, NLConfig.Needs[1].Filter ) ) then
getglobal("NLMember"..member).TopNeed = 1;
getglobal("NLMember"..member).Needs[1] = true;
end
if( NL_CheckForResurrectionNeed( member ) ) then
return;
end
-- make sure to set the resurrection need to false if we got here
if( NLConfig.ResurrectionNeedIndex ) then
if( getglobal("NLMember"..member).TopNeed == NLConfig.ResurrectionNeedIndex ) then
getglobal("NLMember"..member).TopNeed = nil;
end
getglobal("NLMember"..member).Needs[NLConfig.ResurrectionNeedIndex] = false;
end
NL_CheckHealth( member );
NL_CheckMana( member );
NL_CheckAura( member );
if( getglobal("NLMember"..member).TopNeed and getglobal("NLMember"..member).TopNeed > 0 ) then
NL_AddToList( member );
else
NL_RemoveFromList( member );
end
end
function NL_CheckForResurrectionNeed( member )
-- if the unit is dead or a ghost, they either have
if( UnitIsDead(member) or UnitIsGhost(member) or UnitHealth(member) <= 0 ) then
if( UnitClass(member) == "Hunter" ) then
local buffList = NL_GetUnitBuffsAndDebuffs( member );
if( buffList and buffList[NL_FEIGNDEATH] ) then
return false;
end
end
-- if unit is the player, then do not monitor resurrection need, because a) can't rez yourself b) it's obvious when you need a rez
if( NLConfig.ResurrectionNeedIndex and NLConfig.Needs[NLConfig.ResurrectionNeedIndex].Toggle == 1 ) then
if( not UnitIsUnit( member, "player" ) ) then
if( getglobal("NLMember"..member).TopNeed ~= 1 ) then
getglobal("NLMember"..member).TopNeed = NLConfig.ResurrectionNeedIndex;
end
getglobal("NLMember"..member).Needs[NLConfig.ResurrectionNeedIndex] = true;
NL_AddToList( member );
if( getglobal("NLMember"..member):IsShown() ) then
NL_UpdateAura( member );
NL_UpdateUnit( member );
end
return true;
end
end
if( getglobal("NLMember"..member).TopNeed ~= 1 ) then
NL_RemoveFromList( member );
end
return true;
end
return false;
end
function NL_GetMaxRankPlayerCanCast( spellName )
NL_ITERATOR = 1;
local foundSpellName, foundSpellRank;
local highestMatch = nil;
repeat
foundSpellName, foundSpellRank = GetSpellName(NL_ITERATOR, BOOKTYPE_SPELL);
if( spellName == foundSpellName ) then
if( foundSpellRank == nil ) then
return nil;
end
highestMatch = tonumber(string.sub( foundSpellRank, 6 ));
end
NL_ITERATOR = NL_ITERATOR + 1;
until not foundSpellName
return highestMatch;
end
function NL_GetMaxRankUnitCanReceive( spellRanks, unitLevel )
NL_ITERATOR = 1;
while spellRanks[NL_ITERATOR] and unitLevel + 10 >= spellRanks[NL_ITERATOR] do
NL_ITERATOR = NL_ITERATOR + 1;
end
return NL_ITERATOR - 1;
end
function NL_CureNeedOnUnit( needName, unit, mousebutton )
-- once in a while the interface can miss an event, leaving you with a unit whose needs have already been fixed
-- do a check needs before casting, to make sure this is still a need on this unit
NL_CheckAllNeeds(unit);
NL_ITERATOR = 1;
local needFrame = getglobal("NLMember".. unit .. "NeedsDetailsNeed"..NL_ITERATOR);
while( needFrame and needFrame.NeedName and needFrame.NeedName ~= needName ) do
NL_ITERATOR = NL_ITERATOR + 1;
needFrame = getglobal("NLMember".. unit .. "NeedsDetailsNeed"..NL_ITERATOR);
end
-- if it wasn't found as a need, it's been cured, so just return
if( not needFrame or needFrame.NeedName == nil ) then
return;
end
local spellName = nil;
local spellRanks = nil;
local spellCanTargetEnemy = false;
local spellNeedsNoTarget = false;
local isBuff = false;
local clickIndex = NL_CLICK_INDICES[mousebutton];
-- find a cure spell that I can cast for this problem based on the player's level
if( NL_BUFF_SPELLS[NL_PLAYERCLASS] and NL_BUFF_SPELLS[NL_PLAYERCLASS][needName] ) then
spellName = NL_BUFF_SPELLS[NL_PLAYERCLASS][needName][clickIndex];
spellRanks = NL_BUFF_SPELLS[NL_PLAYERCLASS][needName].Ranks;
spellCanTargetEnemy = NL_BUFF_SPELLS[NL_PLAYERCLASS][needName].CanTargetEnemy;
spellNeedsNoTarget = NL_BUFF_SPELLS[NL_PLAYERCLASS][needName].NoTarget;
isBuff = true;
elseif( NL_CURE_SPELLS[NL_PLAYERCLASS] and NL_CURE_SPELLS[NL_PLAYERCLASS][needName] ) then
-- it's a debuff, find the cure spell for it
spellName = NL_CURE_SPELLS[NL_PLAYERCLASS][needName][clickIndex];
spellRanks = NL_CURE_SPELLS[NL_PLAYERCLASS][needName].Ranks;
spellCanTargetEnemy = NL_CURE_SPELLS[NL_PLAYERCLASS][needName].CanTargetEnemy;
elseif( NL_ENCHANT_SPELLS[NL_PLAYERCLASS] and NL_ENCHANT_SPELLS[NL_PLAYERCLASS][needName] ) then
if( NL_PLAYERCLASS == "Rogue" ) then
return;
end
spellName = NL_ENCHANT_SPELLS[NL_PLAYERCLASS][needName][clickIndex];
spellRanks = NL_ENCHANT_SPELLS[NL_PLAYERCLASS][needName].Ranks;
spellCanTargetEnemy = NL_ENCHANT_SPELLS[NL_PLAYERCLASS][needName].CanTargetEnemy;
elseif( needName == "Health" ) then
if( NLConfig.HealSpells ) then
spellName = NLConfig.HealSpells[clickIndex];
end
elseif( needName == "Mana" ) then
spellName = "Innervate";
end
if( spellName ) then
local hadTarget = false;
-- cast pet spells here
-- fire shield seems unique in that it requires your target to actually change
-- most other spells don't require a target to start casting
-- therefore Fire Shield is the only spell that will not add units to the blacklist
if( spellName == "Fire Shield" ) then
local switchedTarget = false;
local targetWasEnemy = false;
local friendlyTargetName = "";
if( UnitExists( "target" ) ) then
hadTarget = true;
end
if( UnitIsEnemy( "player", "target" ) ) then
targetWasEnemy = true;
else
friendlyTargetName = UnitName("target");
end
TargetUnit( unit );
switchedTarget = true;
-- find the action on the pet bar that matches this spell name
NL_ITERATOR = 1;
while( spellName ~= GetPetActionInfo(NL_ITERATOR) and NL_ITERATOR < 12 ) do
NL_ITERATOR = NL_ITERATOR + 1;
end
if( spellName == GetPetActionInfo(NL_ITERATOR) ) then
CastPetAction(NL_ITERATOR);
end
if( hadTarget == false ) then
ClearTarget();
elseif( switchedTarget ) then
if( targetWasEnemy ) then
TargetLastEnemy();
else
TargetByName(friendlyTargetName);
end
end
-- cast the highest ranked spell based on player level
elseif( string.sub( spellName, 0, 1 ) ~= "[" ) then
-- if the unit is not already the target
-- AND
-- if the spell needs a target
-- and the player has a target
-- and
-- the spell can target enemies OR (the spell can't target the enemy AND the target is friendly)
-- Clear the target
if( unit ~= "target" and (not spellNeedsNoTarget and UnitExists( "target" ) and (spellCanTargetEnemy or (not spellCanTargetEnemy and UnitIsFriend("player","target"))))) then
hadTarget = true;
ClearTarget();
end
-- figure out the rank of the spell to cast based on level
if( not spellNeedsNoTarget ) then
if( spellRanks ) then
local validRank = NL_GetMaxRankPlayerCanCast( spellName );
if( validRank ) then
local allowedRank = validRank;
if( isBuff ) then
allowedRank = NL_GetMaxRankUnitCanReceive( spellRanks, UnitLevel(unit) );
end
if( validRank > 0 and allowedRank > 0 ) then
-- cast the maximum rank of this spell
CastSpellByName( spellName .. "("..NL_LANG_RANK.." " .. min(validRank,allowedRank) .. ")" );
end
else
CastSpellByName( spellName );
end
else
CastSpellByName( spellName );
end
else
-- the spell needs no target, so just cast it. The game will find the correct rank to cast.
CastSpellByName( spellName );
end
else
if( unit ~= "target" and UnitExists( "target" ) and UnitIsFriend("player","target")) then
hadTarget = true;
ClearTarget();
end
local bagNum, slotNum;
local done = false;
for bagNum = 0, NUM_BAG_FRAMES do
local numSlots = GetContainerNumSlots(bagNum);
for slotNum = 1, numSlots do
local itemLink = GetContainerItemLink(bagNum, slotNum);
local itemName = string.sub(spellName, 2, string.len(spellName) - 1);
if( itemLink and string.find(itemLink, itemName) ) then
UseContainerItem(bagNum, slotNum);
done = true;
break;
end
end
if( done ) then
break;
end
end
end
if( not spellNeedsNoTarget ) then
if ( SpellIsTargeting() ) then
if( SpellCanTargetUnit(unit) ) then
-- message the person we're casting on, if notifications are enabled
if( NLConfig.SpellNotify == 1 ) then
SendChatMessage( "I'm casting "..spellName.." on you.", "WHISPER", this.language, UnitName(unit) );
end
SpellTargetUnit(unit);
else
-- blacklist the unit, so they drop to the end of the list for however long the 'out of range' timer is set for
-- for now, remove them from the list and set a timer on them
SpellStopTargeting();
-- ONLY if the unit isn't stickied and the blacklist delay is above 0
if( getglobal("NLMember"..unit).TopNeed ~= 1 and NLConfig.BlackListDelay > 0 ) then
NLBlacklistUnit( unit );
end
end
end
if( hadTarget == true ) then
TargetLastTarget();
end
end
end
end
function NL_PulloutIfInvisible( unit )
-- previous frame won't be nil on a frame that has been removed already but not pulled out
if( getglobal( "NLMember"..unit ).PendingRemoval ) then
NL_RemoveFromList( unit );
getglobal( "NLMember"..unit ).PendingRemoval = false;
end
end
function NL_PulloutAllInvisibleFrames()
if( GetNumRaidMembers() > 0 ) then
-- iterate through all frames
for NL_ITERATOR = 1, 40 do
NL_PulloutIfInvisible( "raid" .. NL_ITERATOR );
NL_PulloutIfInvisible( "raidpet" .. NL_ITERATOR );
end
else
-- iterate through all frames
NL_PulloutIfInvisible( "player" );
NL_PulloutIfInvisible( "pet" );
for NL_ITERATOR = 1, 4 do
NL_PulloutIfInvisible( "party" .. NL_ITERATOR );
NL_PulloutIfInvisible( "partypet" .. NL_ITERATOR );
end
end
end
function NL_ResortSingleUnit( unit )
if( not UnitExists(unit) ) then
return;
end
-- if the frame has a slot index it has a need
if( getglobal("NLMember"..unit).SlotIndex ) then
getglobal("NLMember"..unit).SlotIndex = nil;
if( getglobal("NLMember"..unit).TopNeed ) then
NL_AddToList(unit);
end
end
end
function NL_SortAllVisibleFrames()
NL_NUM_NEEDY_UNITS = 0;
NL_SLOTS = {};
if( GetNumRaidMembers() > 0 ) then
-- iterate through all frames
for NL_ITERATOR = 1, 40 do
NL_ResortSingleUnit( "raid" .. NL_ITERATOR );
NL_ResortSingleUnit( "raidpet" .. NL_ITERATOR );
end
else
-- iterate through all frames
NL_ResortSingleUnit( "player" );
NL_ResortSingleUnit( "pet" );
for NL_ITERATOR = 1, 4 do
NL_ResortSingleUnit( "party" .. NL_ITERATOR );
NL_ResortSingleUnit( "partypet" .. NL_ITERATOR );
end
end
end
function NL_OnUpdate( elapsed )
if( not NL_MOUSE_IN_FRAME and not NL_LIST_IS_SORTED ) then
-- do a generic sort of all visible units
if( NLConfig.AutoSort == 1 ) then
NL_PulloutAllInvisibleFrames();
NL_SortAllVisibleFrames();
else
NL_PulloutAllInvisibleFrames();
end
NL_LIST_IS_SORTED = true;
end
NL_ITERATOR = 1;
while( NL_BLACK_LIST[NL_ITERATOR] ) do
NL_BLACK_LIST[NL_ITERATOR].Time = NL_BLACK_LIST[NL_ITERATOR].Time - elapsed;
if( NL_BLACK_LIST[NL_ITERATOR].Time <= 0 ) then
-- check needs and remove this unit from the blacklist
local member = NL_BLACK_LIST[NL_ITERATOR].Unit;
table.remove(NL_BLACK_LIST, NL_ITERATOR);
NL_CheckAllNeeds( member );
else
NL_ITERATOR = NL_ITERATOR + 1;
end
end
end
function NL_FindInBuffList( needName, buffList )
if( NL_BUFF_SPELLS[ NL_PLAYERCLASS ] ) then
if( NL_BUFF_SPELLS[ NL_PLAYERCLASS ][needName] ) then
if( NL_BUFF_SPELLS[ NL_PLAYERCLASS ][needName].Icons[1] and buffList[NL_ICON_LOCATION..NL_BUFF_SPELLS[ NL_PLAYERCLASS ][needName].Icons[1]] ) then
return true;
elseif( NL_BUFF_SPELLS[ NL_PLAYERCLASS ][needName].Icons[2] and buffList[NL_ICON_LOCATION..NL_BUFF_SPELLS[ NL_PLAYERCLASS ][needName].Icons[2]] ) then
return true;
end
end
end
return false;
end
function NL_AddToList(member)
if( not UnitExists(member) or UnitName(member) == nil or UnitName(member) == "" or UnitName(member) == "Unknown Entity" ) then
NL_RemoveFromList(member);
return nil;
end
getglobal("NLMember"..member.."Name"):SetText( string.sub(UnitName(member),1,NLConfig.FrameWidth/8) );
local frame = getglobal("NLMember"..member);
if( frame.TopNeed == nil ) then
return;
end
if( frame.PendingRemoval ) then
frame.PendingRemoval = false;
frame:Show();
end
if( NLConfig.ColorByClass == 1 ) then
local class = "";
if( string.find( member, "pet" ) ~= nil ) then
class = UnitCreatureType(member);
else
class = UnitClass(member);
end
if( NL_CLASS_COLORS[class] ) then
frame:SetBackdropColor(NL_CLASS_COLORS[class].r, NL_CLASS_COLORS[class].g, NL_CLASS_COLORS[class].b, 1);
else
frame:SetBackdropColor(NL_CLASS_COLORS["Default"].r, NL_CLASS_COLORS["Default"].g, NL_CLASS_COLORS["Default"].b, 1);
end
elseif( NLConfig.Needs[frame.TopNeed] ~= nil ) then
frame:SetBackdropColor(NLConfig.Needs[frame.TopNeed].BGColor.r, NLConfig.Needs[frame.TopNeed].BGColor.g, NLConfig.Needs[frame.TopNeed].BGColor.b, 0.8);
end
-- target has special treatment, as it should not be in the list
if( member == "target" ) then
frame:Show();
return frame;
end
if( not frame.SlotIndex ) then
frame.SlotIndex = NL_NUM_NEEDY_UNITS;
NL_SLOTS[NL_NUM_NEEDY_UNITS] = frame;
NL_NUM_NEEDY_UNITS = NL_NUM_NEEDY_UNITS + 1;
NLAnchorFrame( frame );
end
if( NLConfig.AutoSort == 1 and not NL_MOUSE_IN_FRAME ) then
NLSortFrameIntoList(frame);
end
if( NL_MINIMIZED ) then
NLHeaderMinimized:Show();
else
NLHeader:Show();
end
return frame;
end
function NLAnchorFrame( frame )
if( frame ~= NL_SLOTS[frame.SlotIndex] ) then
NLBlacklistUnit(frame.Unit);
end
if( frame.SlotIndex < NLConfig.MaxUnits ) then
if( not frame:IsShown() ) then
-- draw the details of the frame, because it's now being made visible
frame:Show();
end
frame:ClearAllPoints();
frame:SetPoint( NLAnchors[NLConfig.InvertList+1].AnchorPoint, NLHeader, NLAnchors[NLConfig.InvertList+1].ReferenceAnchorPoint, 0, NLAnchors[NLConfig.InvertList+1].Offset * (frame:GetHeight() - 5) * frame.SlotIndex - (5 * NLAnchors[NLConfig.InvertList+1].Offset) );
else
frame:Hide();
end
end
function NLBlacklistUnit( unit )
NL_RemoveFromList(unit);
local newBlackListItem = {};
newBlackListItem.Unit = unit;
newBlackListItem.Time = NLConfig.BlackListDelay;
table.insert(NL_BLACK_LIST, newBlackListItem);
end
function NLSortFrameDown( frame )
local nextFrame = nil;
while( frame.SlotIndex < NL_NUM_NEEDY_UNITS - 1 and NL_SLOTS[frame.SlotIndex+1] and NL_SLOTS[frame.SlotIndex+1].Unit and not NL_SLOTS[frame.SlotIndex+1].TopNeed ) do
NL_DebugMsg("Removing " .. NL_SLOTS[frame.SlotIndex+1].Unit .. " from list because its TopNeed is nil");
NL_RemoveFromList(NL_SLOTS[frame.SlotIndex+1].Unit);
-- at this point, the removed frame should shift the rest up, and this frame can still be sorted downward
end
while( frame.SlotIndex < NL_NUM_NEEDY_UNITS - 1 and ( NL_SLOTS[frame.SlotIndex].TopNeed > NL_SLOTS[frame.SlotIndex+1].TopNeed
or (NL_SLOTS[frame.SlotIndex].TopNeed == NL_SLOTS[frame.SlotIndex+1].TopNeed and
( ( NL_SLOTS[frame.SlotIndex].TopNeed == NLConfig.HealthNeedIndex and NL_SLOTS[frame.SlotIndex].CurrentHealth > NL_SLOTS[frame.SlotIndex+1].CurrentHealth ) or
( ( NLConfig.ManaNeedIndex and NL_SLOTS[frame.SlotIndex].TopNeed == NLConfig.ManaNeedIndex and NL_SLOTS[frame.SlotIndex].CurrentMana > NL_SLOTS[frame.SlotIndex+1].CurrentMana ) ) ) ) ) ) do
nextFrame = NL_SLOTS[frame.SlotIndex+1];
nextFrame.SlotIndex = frame.SlotIndex;
frame.SlotIndex = frame.SlotIndex + 1;
NL_SLOTS[frame.SlotIndex] = frame;
NL_SLOTS[nextFrame.SlotIndex] = nextFrame;
NLAnchorFrame( frame );
NLAnchorFrame( nextFrame );
if( frame.SlotIndex < NL_NUM_NEEDY_UNITS - 1 and NL_SLOTS[frame.SlotIndex+1] and NL_SLOTS[frame.SlotIndex+1].Unit and not NL_SLOTS[frame.SlotIndex+1].TopNeed ) then
NL_DebugMsg("Removing " .. NL_SLOTS[frame.SlotIndex+1].Unit .. " from list because its TopNeed is nil");
NL_RemoveFromList(NL_SLOTS[frame.SlotIndex+1].Unit);
-- at this point, the removed frame should shift the rest up, and this frame can still be sorted downward
end
end
end
function NLSortFrameUp( frame )
local previousFrame = nil;
while( frame.SlotIndex > 0 and NL_SLOTS[frame.SlotIndex-1] and NL_SLOTS[frame.SlotIndex-1].Unit and not NL_SLOTS[frame.SlotIndex-1].TopNeed ) do
NL_DebugMsg("Removing " .. NL_SLOTS[frame.SlotIndex-1].Unit .. " from list because its TopNeed is nil");
NL_RemoveFromList(NL_SLOTS[frame.SlotIndex-1].Unit);
-- at this point, the removed frame should shift the rest up, and this frame can still be sorted upward
end
while( frame.SlotIndex > 0 and ( NL_SLOTS[frame.SlotIndex].TopNeed < NL_SLOTS[frame.SlotIndex-1].TopNeed
or (NL_SLOTS[frame.SlotIndex].TopNeed == NL_SLOTS[frame.SlotIndex-1].TopNeed and
( ( NL_SLOTS[frame.SlotIndex].TopNeed == NLConfig.HealthNeedIndex and NL_SLOTS[frame.SlotIndex].CurrentHealth < NL_SLOTS[frame.SlotIndex-1].CurrentHealth ) or
( NLConfig.ManaNeedIndex and NL_SLOTS[frame.SlotIndex].TopNeed == NLConfig.ManaNeedIndex and NL_SLOTS[frame.SlotIndex].CurrentMana < NL_SLOTS[frame.SlotIndex-1].CurrentMana ) ) ) ) ) do
previousFrame = NL_SLOTS[frame.SlotIndex-1];
previousFrame.SlotIndex = frame.SlotIndex;
frame.SlotIndex = frame.SlotIndex - 1;
NL_SLOTS[frame.SlotIndex] = frame;
NL_SLOTS[previousFrame.SlotIndex] = previousFrame;
NLAnchorFrame( frame );
NLAnchorFrame( previousFrame );
if( frame.SlotIndex > 0 and NL_SLOTS[frame.SlotIndex-1] and NL_SLOTS[frame.SlotIndex-1].Unit and not NL_SLOTS[frame.SlotIndex-1].TopNeed ) then
NL_DebugMsg("Removing " .. NL_SLOTS[frame.SlotIndex-1].Unit .. " from list because its TopNeed is nil");
NL_RemoveFromList(NL_SLOTS[frame.SlotIndex-1].Unit);
-- at this point, the removed frame should shift the rest up, and this frame can still be sorted upward
end
end
end
function NLSortFrameIntoList(frame)
NLSortFrameUp( frame );
NLSortFrameDown( frame );
end
function NLShiftRemainingUp( index )
while( index < NL_NUM_NEEDY_UNITS - 1 ) do
NL_SLOTS[index] = NL_SLOTS[index+1];
NL_SLOTS[index].SlotIndex = index;
NLAnchorFrame( NL_SLOTS[index] );
index = index + 1;
end
end
function NL_RemoveFromList(member)
-- sort to bottom of list (so all other units shift up)
if( not member ) then
return;
end
local frame = getglobal("NLMember"..member);
-- target has special treatment, as it should not be in the list
if( member == "target" ) then
frame:Hide();
return;
end
if( NL_MOUSE_IN_FRAME ) then
frame.PendingRemoval = true;
frame:Hide();
return;
end
if( frame.SlotIndex ) then
NL_SLOTS[frame.SlotIndex] = nil;
frame:Hide();
NLShiftRemainingUp( frame.SlotIndex );
NL_NUM_NEEDY_UNITS = NL_NUM_NEEDY_UNITS - 1;
frame.SlotIndex = nil;
frame.TopNeed = nil;
end
if( NLConfig.HideHeader == 1 and NL_NUM_NEEDY_UNITS == 0 ) then
NLHeader:Hide();
NLHeaderMinimized:Hide();
end
end
function NL_MouseEnteredFrame()
NL_MOUSE_IN_FRAME = true;
NL_LIST_IS_SORTED = false;
end
function NL_MouseLeftFrame()
NL_MOUSE_IN_FRAME = false;
end
function NL_UpdateUnit(id)
NL_UpdateNeeds( id );
local frame = "NLMember" .. id;
if( NLConfig.ShowHealthNum == 1 ) then
if( NLConfig.ShowHealthLost == 1 ) then
getglobal(frame .. "HealthNum"):SetText(UnitHealth(id)-UnitHealthMax(id));
else
getglobal(frame .. "HealthNum"):SetText(UnitHealth(id) .. "/" .. UnitHealthMax(id));
end
getglobal(frame .. "HealthNum"):Show();
elseif( getglobal(frame .. "HealthNum"):IsShown() ) then
getglobal(frame .. "HealthNum"):Hide();
end
if( UnitIsDead(id) or UnitIsGhost(id) or UnitHealth(id) == 0 ) then
getglobal(frame .. "HPBar"):Hide();
getglobal(frame .. "MPBar"):Hide();
if( NLConfig.ShowHealth == 1 or NLConfig.ShowMana == 1 ) then
if( UnitIsGhost(id) ) then
getglobal(frame .. "Status"):SetText("Ghost");
elseif( UnitIsDead(id) or UnitHealth(id) == 0 ) then
getglobal(frame .. "Status"):SetText("Dead");
end
getglobal(frame .. "Status"):Show();
end
return;
else
getglobal(frame .. "Status"):Hide();
if( NLConfig.ShowHealth == 1 ) then
getglobal(frame .. "HPBar"):Show();
else
getglobal(frame .. "HPBar"):Hide();
end
-- determine the color for the power bar
local info = ManaBarColor[UnitPowerType(id)];
getglobal(frame .. "MPBar"):SetStatusBarColor(info.r, info.g, info.b);
if( NLConfig.ShowMana == 1 ) then
getglobal(frame .. "MPBar"):Show();
else
getglobal(frame .. "MPBar"):Hide();
end
end
-- set the name in the frame
if( getglobal(frame).CurrentHealth ) then
local percent = floor(getglobal(frame).CurrentHealth);
if ( percent and percent > 0 ) then
if ( percent > 100 ) then
percent = 100;
end
getglobal(frame .. "HPBar"):SetValue(percent);
local hppercent = percent/100;
local r, g;
if ( hppercent > 0.5 and hppercent <= 1) then
g = 1;
r = (1.0 - hppercent) * 2;
elseif ( hppercent >= 0 and hppercent <= 0.5 ) then
r = 1.0;
g = hppercent * 2;
else
r = 0;
g = 1;
end
getglobal(frame .. "HPBar"):SetStatusBarColor(r, g, 0);
end
end
-- get the class of the player and update the mana bar appropriately
if( UnitManaMax(id) == 0 ) then
getglobal(frame .. "MPBar"):SetValue(0);
else
if( getglobal(frame).CurrentMana ) then
local percent = floor(getglobal(frame).CurrentMana);
getglobal(frame .. "MPBar"):SetValue(percent);
end
end
end
function NL_UpdateAura( unit )
if( not UnitExists(unit) ) then
return;
end
local frame = "NLMember" .. unit;
if( NLConfig.ShowBuffs == 0 and NLConfig.ShowHealBuffs == 0 ) then
getglobal(frame .. "BuffsDetails"):SetWidth( 5 );
getglobal(frame .. "BuffsDetails"):Hide();
else
local buff;
local numBuffs = 0;
local index = 1;
for NL_ITERATOR=1, NL_MAX_TOOLTIP_BUFFS do
buff = UnitBuff(unit, NL_ITERATOR);
if ( buff and (NLConfig.ShowBuffs == 1 or (NLConfig.ShowHealBuffs == 1 and
(buff == NL_ICON_LOCATION .. "Spell_Nature_Rejuvenation" or
buff == NL_ICON_LOCATION .. "Spell_Nature_ResistNature" or
buff == NL_ICON_LOCATION .. "Spell_Holy_Renew" )
) ) ) then
getglobal(frame .. "BuffsDetailsBuff"..index):SetNormalTexture(buff);
getglobal(frame .. "BuffsDetailsBuff"..index):Show();
getglobal(frame .. "BuffsDetailsBuff"..index):SetID(index);
if( getglobal(frame .. "BuffsDetailsBuff"..index) == NL_MOUSE_OVER_FRAME ) then
GameTooltip:SetUnitBuff( getglobal(frame).Unit, NL_ITERATOR );
end
index = index + 1;
numBuffs = numBuffs + 1;
end
end
for NL_ITERATOR=index, NL_MAX_TOOLTIP_BUFFS do
getglobal(frame .. "BuffsDetailsBuff"..NL_ITERATOR):Hide();
end
getglobal(frame .. "BuffsDetailsBuff1"):ClearAllPoints();
getglobal(frame .. "BuffsDetailsBuff1"):SetPoint( "TOPLEFT", frame .. "BuffsDetails", "TOPLEFT", 5, -5 );
getglobal(frame .. "BuffsDetails"):SetHeight( 26 );
-- Size the tooltip
if ( numBuffs > 0 ) then
getglobal(frame .. "BuffsDetails"):SetWidth( (numBuffs * 17) + 9 );
getglobal(frame .. "BuffsDetails"):Show();
else
getglobal(frame .. "BuffsDetails"):SetWidth( 5 );
getglobal(frame .. "BuffsDetails"):Hide();
end
end
if( NLConfig.ShowDebuffs == 0 ) then
getglobal(frame .. "DebuffsDetails"):SetWidth( 5 );
getglobal(frame .. "DebuffsDetails"):Hide();
else
local buff;
local numDebuffs = 0;
local index = 1;
for NL_ITERATOR=1, NL_MAX_TOOLTIP_DEBUFFS do
buff = UnitDebuff(unit, NL_ITERATOR);
if ( buff ) then
getglobal(frame .. "DebuffsDetailsDebuff"..index):SetNormalTexture(buff);
getglobal(frame .. "DebuffsDetailsDebuff"..index):Show();
getglobal(frame .. "DebuffsDetailsDebuff"..index):SetID(index);
if( getglobal(frame .. "DebuffsDetailsDebuff"..index) == NL_MOUSE_OVER_FRAME ) then
GameTooltip:SetUnitDebuff( getglobal(frame).Unit, NL_ITERATOR );
end
index = index + 1;
numDebuffs = numDebuffs + 1;
end
end
for NL_ITERATOR=index, NL_MAX_TOOLTIP_DEBUFFS do
getglobal(frame .. "DebuffsDetailsDebuff"..NL_ITERATOR):Hide();
end
getglobal(frame .. "DebuffsDetailsDebuff1"):ClearAllPoints();
getglobal(frame .. "DebuffsDetailsDebuff1"):SetPoint( "TOPLEFT", frame .. "DebuffsDetails", "TOPLEFT", 5, -5 );
getglobal(frame .. "DebuffsDetails"):SetHeight( 26 );
-- Size the tooltip
if ( numDebuffs > 0 ) then
getglobal(frame .. "DebuffsDetails"):SetWidth( (numDebuffs * 17) + 9 );
getglobal(frame .. "DebuffsDetails"):Show();
else
getglobal(frame .. "DebuffsDetails"):SetWidth( 5 );
getglobal(frame .. "DebuffsDetails"):Hide();
end
end
end
function NL_UpdateNeeds( member )
local frame = getglobal( "NLMember"..member );
if( not frame or not frame.TopNeed or frame.TopNeed < 1 or NLConfig.ShowNeeds == 0 ) then
NL_ClearNeedDetails( member );
return;
end
local needFrameIndex = 1;
-- if resurrection is a need of this unit
if( frame.Needs[NLConfig.ResurrectionNeedIndex] ) then
if( NL_CURE_SPELLS[NL_PLAYERCLASS] and NL_CURE_SPELLS[NL_PLAYERCLASS].Resurrection ) then
iconName = NL_CURE_SPELLS[NL_PLAYERCLASS].Resurrection.Icon;
if( iconName ~= "" ) then
local needFrame = getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex);
if( NLConfig.LargeNeedIcons == 1 ) then
getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetWidth( 22 );
getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetHeight( 22 );
else
getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetWidth( 16 );
getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetHeight( 16 );
end
needFrame:SetNormalTexture(NL_ICON_LOCATION .. iconName);
needFrame.NeedName = "Resurrection";
needFrame:Show();
if( needFrame == NL_MOUSE_OVER_FRAME ) then
NL_MouseOverNeedButton(needFrame);
end
needFrameIndex = needFrameIndex + 1;
end
end
else
for NL_ITERATOR=2, NLConfig.NumNeeds - 1 do
local iconName = "";
if( frame.Needs[NL_ITERATOR] ) then
if( NL_BUFF_SPELLS[NL_PLAYERCLASS] and NL_BUFF_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name] ) then
iconName = NL_BUFF_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name].Icons[1];
elseif( NL_CURE_SPELLS[NL_PLAYERCLASS] and NL_CURE_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name] ) then
iconName = NL_CURE_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name].Icon;
elseif( NL_ENCHANT_SPELLS[NL_PLAYERCLASS] and NL_ENCHANT_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name] ) then
iconName = NL_ENCHANT_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name].Icon;
elseif( NL_OTHER[NLConfig.Needs[NL_ITERATOR].Name] ) then
iconName = NL_OTHER[NLConfig.Needs[NL_ITERATOR].Name].Icon;
end
if( iconName ~= "" ) then
local needFrame = getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex);
if( NLConfig.LargeNeedIcons == 1 ) then
getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetWidth( 22 );
getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetHeight( 22 );
else
getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetWidth( 16 );
getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetHeight( 16 );
end
needFrame:SetNormalTexture(NL_ICON_LOCATION .. iconName);
needFrame.NeedName = NLConfig.Needs[NL_ITERATOR].Name;
needFrame:Show();
if( needFrame == NL_MOUSE_OVER_FRAME ) then
NL_MouseOverNeedButton(needFrame);
end
needFrameIndex = needFrameIndex + 1;
if( needFrameIndex > NL_MAX_NEEDS ) then
-- this is a break condition, we don't need to see more needs
NL_ITERATOR = NLConfig.NumNeeds;
end
end
end
end
end
local needCount = needFrameIndex - 1;
for NL_ITERATOR=needFrameIndex, NL_MAX_NEEDS - 1 do
getglobal(frame:GetName() .. "NeedsDetailsNeed"..NL_ITERATOR):Hide();
end
if( NLConfig.LargeNeedIcons == 1 ) then
getglobal(frame:GetName() .. "NeedsDetails"):SetWidth( needCount * 23 + 9 );
getglobal(frame:GetName() .. "NeedsDetails"):SetHeight( 32 );
else
getglobal(frame:GetName() .. "NeedsDetails"):SetWidth( needCount * 17 + 9 );
getglobal(frame:GetName() .. "NeedsDetails"):SetHeight( 26 );
end
getglobal(frame:GetName() .. "NeedsDetailsNeed1"):ClearAllPoints();
getglobal(frame:GetName() .. "NeedsDetailsNeed1"):SetPoint( "TOPLEFT", frame:GetName() .. "NeedsDetails", "TOPLEFT", 5, -5 );
if( needCount > 0 ) then
getglobal(frame:GetName() .. "NeedsDetails"):Show();
else
getglobal(frame:GetName() .. "NeedsDetails"):Hide();
end
end
function NL_SetTooltipOwner( frame, anchor )
if( NLConfig.ShowTooltips == 1 ) then
GameTooltip:SetOwner(frame, anchor);
else
GameTooltip:Hide();
end
end
function NLMember_OnEnter(frame)
NL_SetTooltipOwner( frame, "ANCHOR_TOPLEFT" );
GameTooltip:SetUnit( frame.Unit );
end
function NLMember_OnLeave(frame)
GameTooltip:Hide();
end
function NLMember_OnClick(button, frame)
if( NLConfig.UseCastParty == 1 and CastParty_OnClickByUnit ~= nil ) then
CastParty_OnClickByUnit( button, frame.Unit );
else
if ( button == "LeftButton" ) then
-- determine which unit was clicked
if ( SpellIsTargeting() ) then
SpellTargetUnit(frame.Unit);
elseif ( CursorHasItem() ) then
DropItemOnUnit(frame.Unit);
else
TargetUnit(frame.Unit);
end
else
if( SpellIsTargeting() ) then
SpellStopTargeting();
return;
end
end
end
end
function NLMember_CheckAllUnits()
NL_NUM_NEEDY_UNITS = 0;
if( NLConfig.HideHeader == 1 ) then
NLHeader:Hide();
end
NL_SLOTS = {};
-- hide all frames
NLMemberplayer:Hide();
NLMemberplayer.SlotIndex = nil;
NLMemberplayer.TopNeed = nil;
NLMemberplayer.Needs = {};
NLMemberpet:Hide();
NLMemberpet.SlotIndex = nil;
NLMemberpet.TopNeed = nil;
NLMemberpet.Needs = {};
for NL_ITERATOR = 1, 4 do
getglobal("NLMemberparty"..NL_ITERATOR):Hide();
getglobal("NLMemberparty"..NL_ITERATOR).SlotIndex = nil;
getglobal("NLMemberparty"..NL_ITERATOR).TopNeed = nil;
getglobal("NLMemberparty"..NL_ITERATOR).Needs = {};
getglobal("NLMemberpartypet"..NL_ITERATOR):Hide();
getglobal("NLMemberpartypet"..NL_ITERATOR).SlotIndex = nil;
getglobal("NLMemberpartypet"..NL_ITERATOR).TopNeed = nil;
getglobal("NLMemberpartypet"..NL_ITERATOR).Needs = {};
end
for NL_ITERATOR = 1, 40 do
getglobal("NLMemberraid"..NL_ITERATOR):Hide();
getglobal("NLMemberraid"..NL_ITERATOR).SlotIndex = nil;
getglobal("NLMemberraid"..NL_ITERATOR).TopNeed = nil;
getglobal("NLMemberraid"..NL_ITERATOR).Needs = {};
getglobal("NLMemberraidpet"..NL_ITERATOR):Hide();
getglobal("NLMemberraidpet"..NL_ITERATOR).SlotIndex = nil;
getglobal("NLMemberraidpet"..NL_ITERATOR).TopNeed = nil;
getglobal("NLMemberraidpet"..NL_ITERATOR).Needs = {};
end
-- if player in a raid, check all 40 units, otherwise just check player and party
if( GetNumRaidMembers() > 0 ) then
for NL_ITERATOR = 1, 40 do
if( UnitExists( "raid" .. NL_ITERATOR ) ) then
NL_CheckAllNeeds( "raid" .. NL_ITERATOR );
if( UnitExists( "raidpet" .. NL_ITERATOR ) ) then
NL_CheckAllNeeds( "raidpet" .. NL_ITERATOR );
end
end
end
else
if( UnitExists( "player" ) ) then
NL_CheckAllNeeds( "player" );
if( UnitExists( "pet" ) ) then
NL_CheckAllNeeds( "pet" );
end
end
for NL_ITERATOR = 1, 4 do
if( UnitExists( "party" .. NL_ITERATOR ) ) then
NL_CheckAllNeeds( "party" .. NL_ITERATOR );
if( UnitExists( "partypet" .. NL_ITERATOR ) ) then
NL_CheckAllNeeds( "partypet" .. NL_ITERATOR );
end
end
end
end
NL_CheckTarget();
end
function NL_CheckTarget()
NLMembertarget.Needs = {};
NLMembertarget.TopNeed = nil;
NLMembertarget:Hide();
if( NLConfig.ShowTargetFrame == 1 ) then
if( UnitExists( "target" ) and UnitIsFriend( "target", "player" ) ) then
NL_CheckAllNeeds( "target" );
else
NLMembertarget:Hide();
end
end
end
function NL_MouseOverNeedButton(frame)
NL_SetTooltipOwner(frame:GetParent():GetParent(), "ANCHOR_TOPLEFT");
local tooltipText = "";
if( NL_BUFF_SPELLS[NL_PLAYERCLASS] and NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName] and NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] ) then
if( NL_BUFF_SPELLS[NL_PLAYERCLASS] and NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName] ) then
if( NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] ) then
tooltipText = "Left-click to cast " .. NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] .. ".";
end
if( NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName][2] ) then
tooltipText = tooltipText .. "\nRight-click to cast " .. NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName][2] .. ".";
end
end
elseif( NL_ENCHANT_SPELLS[NL_PLAYERCLASS] and NL_ENCHANT_SPELLS[NL_PLAYERCLASS][frame.NeedName] and NL_ENCHANT_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] ) then
if( NL_PLAYERCLASS == "Rogue" ) then
tooltipText = "Needs " .. NL_ENCHANT_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] .. ".";
else
tooltipText = "Needs " .. NL_ENCHANT_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] .. ".\nClick here to fix.";
end
elseif( frame.NeedName == "Resurrection" ) then
if( NL_CURE_SPELLS[NL_PLAYERCLASS] and NL_CURE_SPELLS[NL_PLAYERCLASS].Resurrection ) then
tooltipText = "Left-click to cast " .. NL_CURE_SPELLS[NL_PLAYERCLASS].Resurrection[1] .. ".";
end
elseif( frame.NeedName == "WellFed" ) then
tooltipText = "Needs to be well fed.";
elseif( frame.NeedName == "Health" ) then
tooltipText = "Needs healing.";
if( NLConfig.HealSpells ) then
if( NLConfig.HealSpells[1] ) then
tooltipText = tooltipText .. "\nLeft-click to cast " .. NLConfig.HealSpells[1] .. ".";
end
if( NLConfig.HealSpells[2] ) then
tooltipText = tooltipText .. "\nRight-click to cast " .. NLConfig.HealSpells[2] .. ".";
end
if( NLConfig.HealSpells[3] ) then
tooltipText = tooltipText .. "\nMiddle-click to cast " .. NLConfig.HealSpells[3] .. ".";
end
if( NLConfig.HealSpells[4] ) then
tooltipText = tooltipText .. "\nClick button 4 to cast " .. NLConfig.HealSpells[4] .. ".";
end
if( NLConfig.HealSpells[5] ) then
tooltipText = tooltipText .. "\nClick button 5 to cast " .. NLConfig.HealSpells[5] .. ".";
end
end
if( tooltipText == "Needs healing." ) then
tooltipText = tooltipText .. "\nUse 'Configure Spells' from the configuration window to add heal spells.";
end
elseif( frame.NeedName == "Mana" ) then
tooltipText = "Needs mana.\nLeft-click to cast Innervate.";
else
tooltipText = "Needs cure for " .. frame.NeedName .. ".";
if( NL_CURE_SPELLS[NL_PLAYERCLASS] and NL_CURE_SPELLS[NL_PLAYERCLASS][frame.NeedName] ) then
if( NL_CURE_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] ) then
tooltipText = tooltipText .. "\nLeft-click to cast " .. NL_CURE_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] .. ".";
end
if( NL_CURE_SPELLS[NL_PLAYERCLASS][frame.NeedName][2] ) then
tooltipText = tooltipText .. "\nRight-click to cast " .. NL_CURE_SPELLS[NL_PLAYERCLASS][frame.NeedName][2] .. ".";
end
end
end
GameTooltip:SetText( tooltipText );
end
function NL_CureTopNeed(button)
for NL_ITERATOR = 0, NL_NUM_NEEDY_UNITS - 1 do
if( NL_SLOTS[NL_ITERATOR] and NL_SLOTS[NL_ITERATOR].TopNeed and NL_SLOTS[NL_ITERATOR].TopNeed > 1 and NL_SLOTS[NL_ITERATOR].Unit ) then
NL_CureNeedOnUnit( NLConfig.Needs[NL_SLOTS[NL_ITERATOR].TopNeed].Name, NL_SLOTS[NL_ITERATOR].Unit, button );
return;
end
end
end
function NL_SortList()
if( NL_MOUSE_IN_FRAME ) then
NL_MOUSE_IN_FRAME = false;
NL_SortAllVisibleFrames();
NL_MOUSE_IN_FRAME = true;
else
NL_SortAllVisibleFrames();
end
end