-------------------------------------------------------- -- 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