vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --------------------------------------------------------
2 -- Ralak's Needy List
3 -- a UI modification by Ralak of Kel'Thuzad
4 -- German Localization by Nitram from DE-Azshara
5 -- French Localization by Olivier Bockstal
6 --------------------------------------------------------
7 NL_CURRENT_VERSION = 2.05;
8  
9 NL_DEBUG_MODE = false;
10  
11 NL_MAX_TOOLTIP_BUFFS = 16;
12 NL_MAX_TOOLTIP_DEBUFFS = 16;
13 NL_MAX_NEEDS = 12;
14 NL_BLACK_LIST = {};
15 NL_MINIMIZED = false;
16 NL_SLOTS = {};
17 NL_NUM_NEEDY_UNITS = 0;
18  
19 NL_PLAYERCLASS = "";
20 NL_ITERATOR = 1;
21  
22 NeedyListDetails = {
23 name = 'Ralak\'s Needy List',
24 description = 'Monitor needy units in your party or raid group.',
25 version = NL_CURRENT_VERSION,
26 releaseDate = 'June 25, 2006',
27 author = 'Carson Knittig',
28 email = 'needylist@gmail.com',
29 category = MYADDONS_CATEGORY_RAID,
30 frame = 'NLMainFrame',
31 optionsframe = 'NLConfigFrame'
32 };
33  
34 NL_CLASS_COLORS = {};
35 NL_CLASS_COLORS[NL_PRIEST_NAME] = {r = 1.0, g = 1.0, b = 1.0};
36 NL_CLASS_COLORS[NL_DRUID_NAME] = {r = 0.0, g = 1.0, b = 0.0};
37 NL_CLASS_COLORS[NL_MAGE_NAME] = {r = 0.0, g = 0.0, b = 1.0};
38 NL_CLASS_COLORS[NL_PALADIN_NAME] = {r = 1.0, g = 1.0, b = 0.0};
39 NL_CLASS_COLORS[NL_WARLOCK_NAME] = {r = 0.5, g = 0.25, b = 0.6};
40 NL_CLASS_COLORS[NL_ROGUE_NAME] = {r = 0.5, g = 0.5, b = 0.5};
41 NL_CLASS_COLORS[NL_SHAMAN_NAME] = {r = 1.0, g = 1.0, b = 0.0};
42 NL_CLASS_COLORS[NL_WARRIOR_NAME] = {r = 1.0, g = 0.0, b = 0.0};
43 NL_CLASS_COLORS[NL_BEAST_NAME] = {r = 0.5, g = 0.4, b = 0.25};
44 NL_CLASS_COLORS[NL_DEMON_NAME] = {r = 1.0, g = 0.6, b = 0.25};
45 NL_CLASS_COLORS["Default"] = {r = 0.25, g = 0.25, b = 0.25};
46  
47 NL_WEAKENED_SOUL = "Interface\\Icons\\Spell_Holy_AshesToAshes";
48 NL_BANISH = "Interface\\Icons\\Spell_Shadow_Cripple";
49 NL_PHASE_SHIFT = "Interface\\Icons\\Spell_Shadow_ImpPhaseShift";
50 NL_MINDCONTROL = "Interface\\Icons\\Spell_Shadow_ShadowWordDominate";
51 NL_MINDCONTROLCAP = "Interface\\Icons\\Spell_Magic_MageArmor";
52 NL_FEIGNDEATH = "Interface\\Icons\\Ability_Rogue_FeignDeath";
53  
54 NL_CLICK_INDICES = {LeftButton = 1, RightButton = 2, MiddleButton = 3, Button4 = 4, Button5 = 5};
55  
56 NL_ICON_LOCATION = "Interface\\Icons\\";
57  
58 NLAnchors = { {
59 AnchorPoint = "TOPLEFT",
60 ReferenceAnchorPoint = "BOTTOMLEFT",
61 Offset = -1,
62 },
63 {
64 AnchorPoint = "BOTTOMLEFT",
65 ReferenceAnchorPoint = "TOPLEFT",
66 Offset = 1,
67 }
68 };
69  
70 function NL_Msg(msg)
71 DEFAULT_CHAT_FRAME:AddMessage(msg);
72 end
73  
74 function NL_DebugMsg(msg)
75 if( NL_DEBUG_MODE ) then
76 DEFAULT_CHAT_FRAME:AddMessage(msg);
77 end
78 end
79  
80 function NL_PrintTable()
81 local test1, test2, test3, test4 = NLMemberplayer:GetPoint("TOPLEFT");
82 table.foreach( test2, NL_Msg );
83 NL_Msg( test3 .. test4 );
84 end
85  
86 function NL_OnLoad()
87 -- Register Events
88 NLMainFrame:RegisterEvent("UNIT_NAME_UPDATE");
89 NLMainFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
90 NLMainFrame:RegisterEvent("UNIT_HEALTH");
91 NLMainFrame:RegisterEvent("UNIT_MANA");
92 NLMainFrame:RegisterEvent("UNIT_RAGE");
93 NLMainFrame:RegisterEvent("UNIT_FOCUS");
94 NLMainFrame:RegisterEvent("UNIT_ENERGY");
95 NLMainFrame:RegisterEvent("UNIT_AURA");
96 NLMainFrame:RegisterEvent("PARTY_MEMBERS_CHANGED");
97 NLMainFrame:RegisterEvent("RAID_ROSTER_UPDATE");
98 NLMainFrame:RegisterEvent("UNIT_PET");
99 NLMainFrame:RegisterEvent("VARIABLES_LOADED");
100 NLMainFrame:RegisterEvent("PLAYER_TARGET_CHANGED");
101  
102 -- Add Slash Commands
103 SlashCmdList["NLCONFIG"] = NL_Configure;
104 SLASH_NLCONFIG1 = "/nlconfig";
105  
106 -- get this player's class so we know which buffs and debuffs to notify him/her of
107 NL_PLAYERCLASS = UnitClass("player");
108  
109 if( DEFAULT_CHAT_FRAME ) then
110 DEFAULT_CHAT_FRAME:AddMessage(NL_STR_INTRO_PREFIX..NL_CURRENT_VERSION..NL_STR_INTRO_SUFFIX);
111 DEFAULT_CHAT_FRAME:AddMessage(NL_STR_INTRO_DESC);
112 end
113  
114 -- set the units on each frame so they never have to be set again
115 NLMemberplayer.Unit = "player";
116 NLMemberpet.Unit = "pet";
117 NLMembertarget.Unit = "target";
118 for NL_ITERATOR=1, 4 do
119 getglobal("NLMemberparty"..NL_ITERATOR).Unit = "party"..NL_ITERATOR;
120 getglobal("NLMemberpartypet"..NL_ITERATOR).Unit = "partypet"..NL_ITERATOR;
121 end
122 for NL_ITERATOR=1, 40 do
123 getglobal("NLMemberraid"..NL_ITERATOR).Unit = "raid"..NL_ITERATOR;
124 getglobal("NLMemberraidpet"..NL_ITERATOR).Unit = "raidpet"..NL_ITERATOR;
125 end
126 end
127  
128 function NL_CheckIfEnabled()
129 local bRaid = GetNumRaidMembers() > 0;
130 local bParty = UnitExists("party1") and not bRaid;
131 local bSolo = not ( bParty or bRaid );
132  
133 if( ( bRaid and NLConfig.UseInRaid == 1 ) or ( bParty and NLConfig.UseInParty == 1 ) or ( bSolo and NLConfig.UseWhenSolo == 1 ) ) then
134 NL_Enable();
135 else
136 NL_Disable();
137 end
138 end
139  
140 function NL_Disable()
141 NL_ENABLED = false;
142  
143 NLHeader:Hide();
144  
145 getglobal("NLMemberplayer"):Hide();
146 getglobal("NLMemberpet"):Hide();
147 for NL_ITERATOR=1, 4 do
148 getglobal("NLMemberparty"..NL_ITERATOR):Hide();
149 getglobal("NLMemberpartypet"..NL_ITERATOR):Hide();
150 end
151 for NL_ITERATOR=1, 40 do
152 getglobal("NLMemberraid"..NL_ITERATOR):Hide();
153 getglobal("NLMemberraidpet"..NL_ITERATOR):Hide();
154 end
155 end
156  
157 function NL_Enable()
158 NL_ENABLED = true;
159  
160 NLHeader:Show();
161  
162 NLMember_CheckAllUnits();
163 end
164  
165 function NL_Configure()
166 NLConfigFrame:Show();
167 end
168  
169 function NL_OnEvent(event, arg1)
170  
171 --Player loaded completely
172 if ( event == "UNIT_NAME_UPDATE" and arg1 == "player" ) or (event=="PLAYER_ENTERING_WORLD") then
173 -- get the configs for this player
174 NLConfig = NL_GetConfigForCurrentPlayer( false );
175  
176 NL_CheckIfEnabled();
177 if( not NL_ENABLED ) then
178 return;
179 end
180  
181 NLHeader:Show();
182  
183 NLMember_CheckAllUnits();
184  
185 return;
186 end
187  
188 if( NLConfig == nil ) then
189 return;
190 end
191  
192 -- this check is only for enabling the needy list based on party status
193 if( event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE" ) then
194 NL_CheckIfEnabled();
195 end
196  
197 if( not NL_ENABLED ) then
198 return;
199 end
200  
201 if( event == "PLAYER_TARGET_CHANGED" ) then
202 NL_CheckTarget();
203 return;
204 end
205  
206 -- if this is a stat or buff change on a unit
207 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
208 -- if the unit is blacklisted or never shown, just return
209 if( arg1 ~= "target" ) then
210 for NL_ITERATOR = 1, table.getn(NL_BLACK_LIST) do
211 if( NL_BLACK_LIST[NL_ITERATOR].Unit == arg1 ) then
212 return;
213 end
214 end
215 end
216  
217 -- if I'm in a raid group, only use units with raid in their name
218 local criteria;
219 if( GetNumRaidMembers() > 0 ) then
220 criteria = string.find( arg1, "raid" ) ~= nil;
221 elseif( GetNumPartyMembers() > 0 ) then
222 criteria = string.find( arg1, "party" ) ~= nil or arg1 == "player" or arg1 == "pet";
223 else
224 criteria = arg1 == "player" or arg1 == "pet";
225 end
226  
227 -- if this player is in the raid or party, or is the default player
228 if( criteria or (arg1 == "target" and UnitIsFriend("target", "player") and NLConfig.ShowTargetFrame == 1)) then
229 if( getglobal("NLMember"..arg1).TopNeed and getglobal("NLMember"..arg1).TopNeed == 0 ) then
230 return;
231 end
232  
233 if( not NL_CheckForResurrectionNeed( arg1 ) ) then
234 if( NLConfig.ResurrectionNeedIndex ) then
235 if( getglobal("NLMember"..arg1).Needs[NLConfig.ResurrectionNeedIndex] ) then
236 getglobal("NLMember"..arg1).Needs[NLConfig.ResurrectionNeedIndex] = false;
237 NL_CheckAllNeeds(arg1);
238 return;
239 end
240 end
241  
242 if( event == "UNIT_HEALTH" ) then
243 if( NL_CheckHealth( arg1 ) ) then
244 NL_AddToList( arg1 );
245 else
246 NL_RemoveFromList( arg1 );
247 end
248 elseif( event == "UNIT_AURA" ) then
249 if( NL_CheckAura( arg1 ) ) then
250 NL_AddToList( arg1 );
251 if( getglobal("NLMember"..arg1):IsShown() ) then
252 NL_UpdateAura( arg1 );
253 end
254 else
255 NL_RemoveFromList( arg1 );
256 end
257 else
258 if( NL_CheckMana( arg1 ) ) then
259 NL_AddToList( arg1 );
260 else
261 NL_RemoveFromList( arg1 );
262 end
263 end
264 if( getglobal("NLMember"..arg1):IsShown() ) then
265 NL_UpdateUnit( arg1 );
266 end
267 end
268 end
269  
270 return;
271 end
272  
273 if( event == "UNIT_PET" ) then
274 local criteria;
275 local prefix;
276 local suffix;
277 if( GetNumRaidMembers() > 0 ) then
278 criteria = string.find( arg1, "raid" ) ~= nil;
279 prefix = "raid";
280 suffix = string.sub( arg1, 5 );
281 else
282 -- 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
283 -- no sense updating twice!
284 if( arg1 == "player" ) then
285 NL_CheckAllNeeds( "pet" );
286 return;
287 else
288 criteria = string.find( arg1, "party" ) ~= nil;
289 prefix = "party";
290 suffix = string.sub( arg1, 6 );
291 end
292 end
293  
294 -- if we're in a raid, check raid members
295 -- if not, check party members, or do nothing if we already found the player
296 if( criteria ) then
297 local petUnit = prefix .. "pet" .. suffix;
298 NL_DebugMsg( "pet event for "..petUnit .. " was caught");
299 NL_CheckAllNeeds( petUnit );
300 end
301 return;
302 end
303  
304 if( event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE" ) then
305 NLMember_CheckAllUnits();
306 return;
307 end
308  
309 if( event == "VARIABLES_LOADED" ) then
310 -- Register the addon in myAddOns
311 if(myAddOnsFrame_Register) then
312 myAddOnsFrame_Register(NeedyListDetails);
313 end
314  
315 return;
316 end
317 end
318  
319 function NL_UnitPassesFilter( unit, filter )
320 if( filter == nil or filter.Type == "Everyone" ) then
321 return true;
322 end
323  
324 if( filter.Type == "Units" ) then
325 if( string.find( filter.Names, UnitName( unit ) ) ) then
326 local foundName = string.sub( filter.Names, string.find( filter.Names, UnitName( unit ) ) );
327 if( string.find( foundName, "," ) ) then
328 foundName = string.sub( foundName, string.find( foundName, "," ) - 1 );
329 end
330 if( foundName == UnitName( unit ) ) then
331 return true;
332 end
333 end
334 end
335  
336 -- if the filter is by party, use the unit name to determine which party and check if that party is being monitored
337 -- party filter is only valid in raids, so if you're not in a raid, pretend filter is everyone
338 if( filter.Type == "Multi" ) then
339 local bPassedPartyCheck = false;
340 if( unit == "target" ) then
341 bPassedPartyCheck = true;
342 else
343 if( ( UnitInParty(unit) or string.find( unit, "partypet" ) or unit == "pet" ) and filter.Names["My Party"] ) then
344 bPassedPartyCheck = true;
345 elseif( string.find( unit, "raid" ) ~= nil ) then
346 local raidIndex;
347 if( string.find( unit, "raidpet" ) ~= nil ) then
348 raidIndex = string.sub( unit, 8 );
349 else
350 raidIndex = string.sub( unit, 5 );
351 end
352  
353 local name, rank, subgroup = GetRaidRosterInfo(raidIndex);
354  
355 if( filter.Names["Party " .. subgroup] ) then
356 bPassedPartyCheck = true;
357 end
358 end
359 end
360  
361 if( bPassedPartyCheck ) then
362 if( string.find( unit, "pet" ) ~= nil ) then
363 if( filter.Names[UnitCreatureType( unit )] ) then
364 return true;
365 end
366 else
367 if( filter.Names[UnitClass( unit )] ) then
368 return true;
369 end
370 end
371 end
372 end
373  
374 return false;
375 end
376  
377 function NL_ClearNeedDetails(member)
378 -- clear the need buttons in the needdetails frame
379 local frameName = "NLMember" .. member;
380 for NL_ITERATOR=1, NL_MAX_NEEDS do
381 getglobal(frameName .. "NeedsDetailsNeed" .. NL_ITERATOR):Hide();
382 end
383 getglobal(frameName .. "NeedsDetails"):Hide();
384 end
385  
386 function NL_GetUnitBuffsAndDebuffs( member )
387 local buffList = {};
388 local debuffList = {};
389 local debuffTypeList = {};
390  
391 NL_ITERATOR = 1;
392 local buff = UnitBuff(member, NL_ITERATOR);
393 while( buff ~= nil ) do
394 buffList[buff] = true;
395 NL_ITERATOR = NL_ITERATOR + 1;
396 buff = UnitBuff(member, NL_ITERATOR);
397 end
398  
399 NL_ITERATOR = 1;
400 local debuff = UnitDebuff(member, NL_ITERATOR);
401  
402 while( debuff ~= nil ) do
403 -- do not add the ignored debuffs to the debuff lists
404 if( debuff ~= NL_ICON_LOCATION.."Spell_Holy_MindVision" ) then
405 debuffList[debuff] = true;
406  
407 NL_BuffTooltipTextRight1:SetText(nil);
408 NL_BuffTooltip:SetUnitDebuff( member, NL_ITERATOR );
409 local debuffType = NL_BuffTooltipTextRight1:GetText();
410  
411 if( debuffType ) then
412 debuffTypeList[debuffType] = true;
413 end
414 end
415  
416 NL_ITERATOR = NL_ITERATOR + 1;
417 debuff = UnitDebuff(member, NL_ITERATOR);
418 end
419  
420 if( string.find( member, "pet" ) and ((buffList and buffList[NL_PHASE_SHIFT]) or (debuffList and debuffList[NL_BANISH] )) ) then
421 NL_RemoveFromList( member );
422 return nil;
423 end
424 if( debuffList and (debuffList[NL_MINDCONTROL] or debuffList[NL_MINDCONTROLCAP]) and UnitIsFriend("player", member) ) then
425 NL_RemoveFromList( member );
426 return nil;
427 end
428  
429 return buffList, debuffList, debuffTypeList;
430 end
431  
432 function NL_CheckAura( member )
433 local buffList, debuffList, debuffTypeList = NL_GetUnitBuffsAndDebuffs( member );
434  
435 if( buffList == nil ) then
436 return false;
437 end
438  
439 local foundNewTopNeed = false;
440  
441 local unitFrame = getglobal("NLMember"..member);
442  
443 -- 0 and 1 are never show and sticky, so don't need to go thru them here
444 for NL_ITERATOR = 2, NLConfig.NumNeeds - 1 do
445 local CurrentNeed = NLConfig.Needs[NL_ITERATOR];
446 if( CurrentNeed.Toggle == 1 and NL_UnitPassesFilter( member, CurrentNeed.Filter ) ) then
447 local FoundNeed = false;
448 if( CurrentNeed.Name == "WellFed" ) then
449 if( not buffList[NL_ICON_LOCATION .. NL_OTHER.WellFed.Icon] ) then
450 FoundNeed = true;
451 end
452 elseif( CurrentNeed.Type == "BUFF" and debuffList ) then
453 if( not NL_FindInBuffList( CurrentNeed.Name, buffList ) ) then
454 -- if the buff is power word shield, need to look for the weakened soul debuff before finding need
455 if( CurrentNeed.Name == "PWShield" ) then
456 if( not debuffList[NL_WEAKENED_SOUL] ) then
457 FoundNeed = true;
458 end
459 else
460 -- didn't find buff on unit, need it
461 FoundNeed = true;
462 end
463 end
464 elseif( CurrentNeed.Type == "ENCHANT" ) then
465 local hasMainHandEnchant, mainHandExpiration, mainHandCharges,
466 hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo()
467 if( NL_PLAYERCLASS == NL_SHAMAN_NAME ) then
468 if( hasMainHandEnchant ~= 1 ) then
469 FoundNeed = true;
470 end
471 elseif( NL_PLAYERCLASS == NL_ROGUE_NAME ) then
472 if( ( CurrentNeed.Name == "MainhandPoison" and hasMainHandEnchant ~= 1 ) or
473 ( CurrentNeed.Name == "OffhandPoison" and hasOffHandEnchant ~= 1 ) ) then
474 FoundNeed = true;
475 end
476 end
477 elseif( CurrentNeed.Type == "DEBUFF" and debuffTypeList ) then
478 if( debuffTypeList[CurrentNeed.Name] ) then
479 -- found debuff on unit, this is the highest priority need
480 FoundNeed = true;
481 end
482 end
483  
484 if( FoundNeed ) then
485 unitFrame.Needs[NL_ITERATOR] = true;
486 if( not foundNewTopNeed ) then
487 NL_SetNewTopNeed( unitFrame, NL_ITERATOR );
488 foundNewTopNeed = true;
489 end
490 elseif( NL_ITERATOR ~= NLConfig.HealthNeedIndex and NL_ITERATOR ~= NLConfig.ManaNeedIndex and NL_ITERATOR ~= NLConfig.ResurrectionNeedIndex ) then
491 unitFrame.Needs[NL_ITERATOR] = false;
492 if( unitFrame.TopNeed == NL_ITERATOR ) then
493 NL_SetNewTopNeed( unitFrame, NL_ITERATOR );
494 end
495 end
496 end
497 end
498  
499 if( unitFrame.TopNeed and unitFrame.TopNeed > 0 ) then
500 return true;
501 end
502  
503 return false;
504 end
505  
506 function NL_CheckHealth( member )
507 if( not NL_GetUnitBuffsAndDebuffs( member ) ) then
508 return false;
509 end
510  
511 local unitFrame = getglobal("NLMember"..member);
512 unitFrame.CurrentHealth = UnitHealth( member ) / UnitHealthMax( member ) * 100;
513  
514 if( not NLConfig.HealthNeedIndex ) then
515 if( unitFrame.TopNeed and unitFrame.TopNeed > 0 ) then
516 return true;
517 end
518 return false;
519 end
520  
521 local HealthNeed = NLConfig.Needs[NLConfig.HealthNeedIndex];
522 if( HealthNeed.Toggle == 1 and NL_UnitPassesFilter( member, HealthNeed.Filter ) ) then
523 if(unitFrame.CurrentHealth < HealthNeed.Threshold or
524 (unitFrame.CurrentHealth < min(HealthNeed.Threshold + 5,99) and unitFrame.SlotIndex and
525 unitFrame.TopNeed == NLConfig.HealthNeedIndex ) ) then
526 -- needs health
527 unitFrame.Needs[NLConfig.HealthNeedIndex] = true;
528 else
529 unitFrame.Needs[NLConfig.HealthNeedIndex] = false;
530 end
531 else
532 unitFrame.Needs[NLConfig.HealthNeedIndex] = false;
533 end
534  
535 return NL_SetNewTopNeed( unitFrame, NLConfig.HealthNeedIndex );
536 end
537  
538 function NL_CheckMana( member )
539 if( not NL_GetUnitBuffsAndDebuffs( member ) ) then
540 return false;
541 end
542  
543 local unitFrame = getglobal("NLMember"..member);
544 unitFrame.CurrentMana = UnitMana( member ) / UnitManaMax( member ) * 100;
545  
546 if( not NLConfig.ManaNeedIndex ) then
547 if( unitFrame.TopNeed and unitFrame.TopNeed > 0 ) then
548 return true;
549 end
550 return false;
551 end
552  
553 local ManaNeed = NLConfig.Needs[NLConfig.ManaNeedIndex];
554 if( ManaNeed.Toggle == 1 and NL_UnitPassesFilter( member, ManaNeed.Filter ) ) then
555 if( UnitPowerType(member) == 0 and (unitFrame.CurrentMana < ManaNeed.Threshold or
556 (unitFrame.CurrentMana < min(ManaNeed.Threshold + 5,99) and unitFrame:IsShown() and
557 NLConfig.ManaNeedIndex and unitFrame.TopNeed == NLConfig.ManaNeedIndex ) ) ) then
558 -- needs mana
559 unitFrame.Needs[NLConfig.ManaNeedIndex] = true;
560 else
561 unitFrame.Needs[NLConfig.ManaNeedIndex] = false;
562 end
563 else
564 unitFrame.Needs[NLConfig.ManaNeedIndex] = false;
565 end
566  
567 return NL_SetNewTopNeed( unitFrame, NLConfig.ManaNeedIndex );
568 end
569  
570 function NL_SetNewTopNeed( unitFrame, index )
571 if( unitFrame.Needs[index] == true and (not unitFrame.TopNeed or unitFrame.TopNeed > index) ) then
572 unitFrame.TopNeed = index;
573 elseif( unitFrame.Needs[index] == false and unitFrame.TopNeed == index ) then
574 -- the next need is the new top need because health is no longer a need
575 -- find the first true need in the unit's needs
576 for NL_ITERATOR = 1, NLConfig.NumNeeds - 1 do
577 if( unitFrame.Needs[NL_ITERATOR] ) then
578 unitFrame.TopNeed = NL_ITERATOR;
579 return true;
580 end
581 end
582  
583 -- if we got here, there is no longer a top need, so this unit can be removed
584 unitFrame.TopNeed = nil;
585 return false;
586 end
587  
588 return true;
589 end
590  
591 function NL_CheckAllNeeds( member )
592 -- first, make sure the unit exists
593 if( not UnitExists( member ) or UnitName( member ) == "" or UnitName( member ) == nil or not UnitIsConnected( member ) ) then
594 NL_RemoveFromList( member );
595 return;
596 end
597  
598 -- check if never show
599 if( NLConfig.Needs[0].Toggle == 1 and NL_UnitPassesFilter( getglobal("NLMember"..member).Unit, NLConfig.Needs[0].Filter ) ) then
600 getglobal("NLMember"..member).TopNeed = 0;
601 return;
602 end
603  
604 -- check if stickied
605 if( NLConfig.Needs[1].Toggle == 1 and NL_UnitPassesFilter( getglobal("NLMember"..member).Unit, NLConfig.Needs[1].Filter ) ) then
606 getglobal("NLMember"..member).TopNeed = 1;
607 getglobal("NLMember"..member).Needs[1] = true;
608 end
609  
610 if( NL_CheckForResurrectionNeed( member ) ) then
611 return;
612 end
613  
614 -- make sure to set the resurrection need to false if we got here
615 if( NLConfig.ResurrectionNeedIndex ) then
616 if( getglobal("NLMember"..member).TopNeed == NLConfig.ResurrectionNeedIndex ) then
617 getglobal("NLMember"..member).TopNeed = nil;
618 end
619 getglobal("NLMember"..member).Needs[NLConfig.ResurrectionNeedIndex] = false;
620 end
621  
622 NL_CheckHealth( member );
623 NL_CheckMana( member );
624 NL_CheckAura( member );
625 if( getglobal("NLMember"..member).TopNeed and getglobal("NLMember"..member).TopNeed > 0 ) then
626 NL_AddToList( member );
627 else
628 NL_RemoveFromList( member );
629 end
630 end
631  
632 function NL_CheckForResurrectionNeed( member )
633 -- if the unit is dead or a ghost, they either have
634 if( UnitIsDead(member) or UnitIsGhost(member) or UnitHealth(member) <= 0 ) then
635 if( UnitClass(member) == "Hunter" ) then
636 local buffList = NL_GetUnitBuffsAndDebuffs( member );
637  
638 if( buffList and buffList[NL_FEIGNDEATH] ) then
639 return false;
640 end
641 end
642 -- 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
643 if( NLConfig.ResurrectionNeedIndex and NLConfig.Needs[NLConfig.ResurrectionNeedIndex].Toggle == 1 ) then
644 if( not UnitIsUnit( member, "player" ) ) then
645 if( getglobal("NLMember"..member).TopNeed ~= 1 ) then
646 getglobal("NLMember"..member).TopNeed = NLConfig.ResurrectionNeedIndex;
647 end
648 getglobal("NLMember"..member).Needs[NLConfig.ResurrectionNeedIndex] = true;
649 NL_AddToList( member );
650 if( getglobal("NLMember"..member):IsShown() ) then
651 NL_UpdateAura( member );
652 NL_UpdateUnit( member );
653 end
654 return true;
655 end
656 end
657 if( getglobal("NLMember"..member).TopNeed ~= 1 ) then
658 NL_RemoveFromList( member );
659 end
660 return true;
661 end
662  
663 return false;
664 end
665  
666 function NL_GetMaxRankPlayerCanCast( spellName )
667 NL_ITERATOR = 1;
668 local foundSpellName, foundSpellRank;
669 local highestMatch = nil;
670  
671 repeat
672 foundSpellName, foundSpellRank = GetSpellName(NL_ITERATOR, BOOKTYPE_SPELL);
673 if( spellName == foundSpellName ) then
674 if( foundSpellRank == nil ) then
675 return nil;
676 end
677 highestMatch = tonumber(string.sub( foundSpellRank, 6 ));
678 end
679 NL_ITERATOR = NL_ITERATOR + 1;
680 until not foundSpellName
681  
682 return highestMatch;
683 end
684  
685 function NL_GetMaxRankUnitCanReceive( spellRanks, unitLevel )
686 NL_ITERATOR = 1;
687 while spellRanks[NL_ITERATOR] and unitLevel + 10 >= spellRanks[NL_ITERATOR] do
688 NL_ITERATOR = NL_ITERATOR + 1;
689 end
690  
691 return NL_ITERATOR - 1;
692 end
693  
694 function NL_CureNeedOnUnit( needName, unit, mousebutton )
695 -- once in a while the interface can miss an event, leaving you with a unit whose needs have already been fixed
696 -- do a check needs before casting, to make sure this is still a need on this unit
697 NL_CheckAllNeeds(unit);
698 NL_ITERATOR = 1;
699 local needFrame = getglobal("NLMember".. unit .. "NeedsDetailsNeed"..NL_ITERATOR);
700 while( needFrame and needFrame.NeedName and needFrame.NeedName ~= needName ) do
701 NL_ITERATOR = NL_ITERATOR + 1;
702 needFrame = getglobal("NLMember".. unit .. "NeedsDetailsNeed"..NL_ITERATOR);
703 end
704  
705 -- if it wasn't found as a need, it's been cured, so just return
706 if( not needFrame or needFrame.NeedName == nil ) then
707 return;
708 end
709  
710 local spellName = nil;
711 local spellRanks = nil;
712 local spellCanTargetEnemy = false;
713 local spellNeedsNoTarget = false;
714 local isBuff = false;
715  
716 local clickIndex = NL_CLICK_INDICES[mousebutton];
717  
718 -- find a cure spell that I can cast for this problem based on the player's level
719 if( NL_BUFF_SPELLS[NL_PLAYERCLASS] and NL_BUFF_SPELLS[NL_PLAYERCLASS][needName] ) then
720 spellName = NL_BUFF_SPELLS[NL_PLAYERCLASS][needName][clickIndex];
721 spellRanks = NL_BUFF_SPELLS[NL_PLAYERCLASS][needName].Ranks;
722 spellCanTargetEnemy = NL_BUFF_SPELLS[NL_PLAYERCLASS][needName].CanTargetEnemy;
723 spellNeedsNoTarget = NL_BUFF_SPELLS[NL_PLAYERCLASS][needName].NoTarget;
724 isBuff = true;
725 elseif( NL_CURE_SPELLS[NL_PLAYERCLASS] and NL_CURE_SPELLS[NL_PLAYERCLASS][needName] ) then
726 -- it's a debuff, find the cure spell for it
727 spellName = NL_CURE_SPELLS[NL_PLAYERCLASS][needName][clickIndex];
728 spellRanks = NL_CURE_SPELLS[NL_PLAYERCLASS][needName].Ranks;
729 spellCanTargetEnemy = NL_CURE_SPELLS[NL_PLAYERCLASS][needName].CanTargetEnemy;
730 elseif( NL_ENCHANT_SPELLS[NL_PLAYERCLASS] and NL_ENCHANT_SPELLS[NL_PLAYERCLASS][needName] ) then
731 if( NL_PLAYERCLASS == "Rogue" ) then
732 return;
733 end
734  
735 spellName = NL_ENCHANT_SPELLS[NL_PLAYERCLASS][needName][clickIndex];
736 spellRanks = NL_ENCHANT_SPELLS[NL_PLAYERCLASS][needName].Ranks;
737 spellCanTargetEnemy = NL_ENCHANT_SPELLS[NL_PLAYERCLASS][needName].CanTargetEnemy;
738 elseif( needName == "Health" ) then
739 if( NLConfig.HealSpells ) then
740 spellName = NLConfig.HealSpells[clickIndex];
741 end
742 elseif( needName == "Mana" ) then
743 spellName = "Innervate";
744 end
745  
746 if( spellName ) then
747 local hadTarget = false;
748  
749 -- cast pet spells here
750 -- fire shield seems unique in that it requires your target to actually change
751 -- most other spells don't require a target to start casting
752 -- therefore Fire Shield is the only spell that will not add units to the blacklist
753 if( spellName == "Fire Shield" ) then
754 local switchedTarget = false;
755 local targetWasEnemy = false;
756 local friendlyTargetName = "";
757 if( UnitExists( "target" ) ) then
758 hadTarget = true;
759 end
760  
761 if( UnitIsEnemy( "player", "target" ) ) then
762 targetWasEnemy = true;
763 else
764 friendlyTargetName = UnitName("target");
765 end
766 TargetUnit( unit );
767 switchedTarget = true;
768 -- find the action on the pet bar that matches this spell name
769 NL_ITERATOR = 1;
770 while( spellName ~= GetPetActionInfo(NL_ITERATOR) and NL_ITERATOR < 12 ) do
771 NL_ITERATOR = NL_ITERATOR + 1;
772 end
773  
774 if( spellName == GetPetActionInfo(NL_ITERATOR) ) then
775 CastPetAction(NL_ITERATOR);
776 end
777  
778 if( hadTarget == false ) then
779 ClearTarget();
780 elseif( switchedTarget ) then
781 if( targetWasEnemy ) then
782 TargetLastEnemy();
783 else
784 TargetByName(friendlyTargetName);
785 end
786 end
787 -- cast the highest ranked spell based on player level
788 elseif( string.sub( spellName, 0, 1 ) ~= "[" ) then
789 -- if the unit is not already the target
790 -- AND
791 -- if the spell needs a target
792 -- and the player has a target
793 -- and
794 -- the spell can target enemies OR (the spell can't target the enemy AND the target is friendly)
795 -- Clear the target
796 if( unit ~= "target" and (not spellNeedsNoTarget and UnitExists( "target" ) and (spellCanTargetEnemy or (not spellCanTargetEnemy and UnitIsFriend("player","target"))))) then
797 hadTarget = true;
798 ClearTarget();
799 end
800  
801 -- figure out the rank of the spell to cast based on level
802 if( not spellNeedsNoTarget ) then
803 if( spellRanks ) then
804 local validRank = NL_GetMaxRankPlayerCanCast( spellName );
805 if( validRank ) then
806 local allowedRank = validRank;
807 if( isBuff ) then
808 allowedRank = NL_GetMaxRankUnitCanReceive( spellRanks, UnitLevel(unit) );
809 end
810 if( validRank > 0 and allowedRank > 0 ) then
811 -- cast the maximum rank of this spell
812 CastSpellByName( spellName .. "("..NL_LANG_RANK.." " .. min(validRank,allowedRank) .. ")" );
813 end
814 else
815 CastSpellByName( spellName );
816 end
817 else
818 CastSpellByName( spellName );
819 end
820 else
821 -- the spell needs no target, so just cast it. The game will find the correct rank to cast.
822 CastSpellByName( spellName );
823 end
824 else
825 if( unit ~= "target" and UnitExists( "target" ) and UnitIsFriend("player","target")) then
826 hadTarget = true;
827 ClearTarget();
828 end
829  
830 local bagNum, slotNum;
831 local done = false;
832 for bagNum = 0, NUM_BAG_FRAMES do
833 local numSlots = GetContainerNumSlots(bagNum);
834 for slotNum = 1, numSlots do
835 local itemLink = GetContainerItemLink(bagNum, slotNum);
836 local itemName = string.sub(spellName, 2, string.len(spellName) - 1);
837 if( itemLink and string.find(itemLink, itemName) ) then
838 UseContainerItem(bagNum, slotNum);
839 done = true;
840 break;
841 end
842 end
843 if( done ) then
844 break;
845 end
846 end
847 end
848  
849 if( not spellNeedsNoTarget ) then
850 if ( SpellIsTargeting() ) then
851 if( SpellCanTargetUnit(unit) ) then
852 -- message the person we're casting on, if notifications are enabled
853 if( NLConfig.SpellNotify == 1 ) then
854 SendChatMessage( "I'm casting "..spellName.." on you.", "WHISPER", this.language, UnitName(unit) );
855 end
856 SpellTargetUnit(unit);
857 else
858 -- blacklist the unit, so they drop to the end of the list for however long the 'out of range' timer is set for
859 -- for now, remove them from the list and set a timer on them
860 SpellStopTargeting();
861 -- ONLY if the unit isn't stickied and the blacklist delay is above 0
862 if( getglobal("NLMember"..unit).TopNeed ~= 1 and NLConfig.BlackListDelay > 0 ) then
863 NLBlacklistUnit( unit );
864 end
865 end
866 end
867  
868 if( hadTarget == true ) then
869 TargetLastTarget();
870 end
871 end
872 end
873 end
874  
875 function NL_PulloutIfInvisible( unit )
876 -- previous frame won't be nil on a frame that has been removed already but not pulled out
877 if( getglobal( "NLMember"..unit ).PendingRemoval ) then
878 NL_RemoveFromList( unit );
879 getglobal( "NLMember"..unit ).PendingRemoval = false;
880 end
881 end
882  
883 function NL_PulloutAllInvisibleFrames()
884 if( GetNumRaidMembers() > 0 ) then
885 -- iterate through all frames
886 for NL_ITERATOR = 1, 40 do
887 NL_PulloutIfInvisible( "raid" .. NL_ITERATOR );
888 NL_PulloutIfInvisible( "raidpet" .. NL_ITERATOR );
889 end
890 else
891 -- iterate through all frames
892 NL_PulloutIfInvisible( "player" );
893 NL_PulloutIfInvisible( "pet" );
894  
895 for NL_ITERATOR = 1, 4 do
896 NL_PulloutIfInvisible( "party" .. NL_ITERATOR );
897 NL_PulloutIfInvisible( "partypet" .. NL_ITERATOR );
898 end
899 end
900 end
901  
902 function NL_ResortSingleUnit( unit )
903 if( not UnitExists(unit) ) then
904 return;
905 end
906  
907 -- if the frame has a slot index it has a need
908 if( getglobal("NLMember"..unit).SlotIndex ) then
909 getglobal("NLMember"..unit).SlotIndex = nil;
910 if( getglobal("NLMember"..unit).TopNeed ) then
911 NL_AddToList(unit);
912 end
913 end
914 end
915  
916 function NL_SortAllVisibleFrames()
917 NL_NUM_NEEDY_UNITS = 0;
918 NL_SLOTS = {};
919  
920 if( GetNumRaidMembers() > 0 ) then
921 -- iterate through all frames
922 for NL_ITERATOR = 1, 40 do
923 NL_ResortSingleUnit( "raid" .. NL_ITERATOR );
924 NL_ResortSingleUnit( "raidpet" .. NL_ITERATOR );
925 end
926 else
927 -- iterate through all frames
928 NL_ResortSingleUnit( "player" );
929 NL_ResortSingleUnit( "pet" );
930  
931 for NL_ITERATOR = 1, 4 do
932 NL_ResortSingleUnit( "party" .. NL_ITERATOR );
933 NL_ResortSingleUnit( "partypet" .. NL_ITERATOR );
934 end
935 end
936 end
937  
938 function NL_OnUpdate( elapsed )
939 if( not NL_MOUSE_IN_FRAME and not NL_LIST_IS_SORTED ) then
940 -- do a generic sort of all visible units
941 if( NLConfig.AutoSort == 1 ) then
942 NL_PulloutAllInvisibleFrames();
943 NL_SortAllVisibleFrames();
944 else
945 NL_PulloutAllInvisibleFrames();
946 end
947  
948 NL_LIST_IS_SORTED = true;
949 end
950  
951 NL_ITERATOR = 1;
952 while( NL_BLACK_LIST[NL_ITERATOR] ) do
953 NL_BLACK_LIST[NL_ITERATOR].Time = NL_BLACK_LIST[NL_ITERATOR].Time - elapsed;
954  
955 if( NL_BLACK_LIST[NL_ITERATOR].Time <= 0 ) then
956 -- check needs and remove this unit from the blacklist
957 local member = NL_BLACK_LIST[NL_ITERATOR].Unit;
958 table.remove(NL_BLACK_LIST, NL_ITERATOR);
959 NL_CheckAllNeeds( member );
960 else
961 NL_ITERATOR = NL_ITERATOR + 1;
962 end
963 end
964 end
965  
966 function NL_FindInBuffList( needName, buffList )
967 if( NL_BUFF_SPELLS[ NL_PLAYERCLASS ] ) then
968 if( NL_BUFF_SPELLS[ NL_PLAYERCLASS ][needName] ) then
969 if( NL_BUFF_SPELLS[ NL_PLAYERCLASS ][needName].Icons[1] and buffList[NL_ICON_LOCATION..NL_BUFF_SPELLS[ NL_PLAYERCLASS ][needName].Icons[1]] ) then
970 return true;
971 elseif( NL_BUFF_SPELLS[ NL_PLAYERCLASS ][needName].Icons[2] and buffList[NL_ICON_LOCATION..NL_BUFF_SPELLS[ NL_PLAYERCLASS ][needName].Icons[2]] ) then
972 return true;
973 end
974 end
975 end
976  
977 return false;
978 end
979  
980 function NL_AddToList(member)
981 if( not UnitExists(member) or UnitName(member) == nil or UnitName(member) == "" or UnitName(member) == "Unknown Entity" ) then
982 NL_RemoveFromList(member);
983 return nil;
984 end
985  
986 getglobal("NLMember"..member.."Name"):SetText( string.sub(UnitName(member),1,NLConfig.FrameWidth/8) );
987 local frame = getglobal("NLMember"..member);
988  
989 if( frame.TopNeed == nil ) then
990 return;
991 end
992  
993 if( frame.PendingRemoval ) then
994 frame.PendingRemoval = false;
995 frame:Show();
996 end
997  
998 if( NLConfig.ColorByClass == 1 ) then
999 local class = "";
1000 if( string.find( member, "pet" ) ~= nil ) then
1001 class = UnitCreatureType(member);
1002 else
1003 class = UnitClass(member);
1004 end
1005  
1006 if( NL_CLASS_COLORS[class] ) then
1007 frame:SetBackdropColor(NL_CLASS_COLORS[class].r, NL_CLASS_COLORS[class].g, NL_CLASS_COLORS[class].b, 1);
1008 else
1009 frame:SetBackdropColor(NL_CLASS_COLORS["Default"].r, NL_CLASS_COLORS["Default"].g, NL_CLASS_COLORS["Default"].b, 1);
1010 end
1011 elseif( NLConfig.Needs[frame.TopNeed] ~= nil ) then
1012 frame:SetBackdropColor(NLConfig.Needs[frame.TopNeed].BGColor.r, NLConfig.Needs[frame.TopNeed].BGColor.g, NLConfig.Needs[frame.TopNeed].BGColor.b, 0.8);
1013 end
1014  
1015 -- target has special treatment, as it should not be in the list
1016 if( member == "target" ) then
1017 frame:Show();
1018 return frame;
1019 end
1020  
1021 if( not frame.SlotIndex ) then
1022 frame.SlotIndex = NL_NUM_NEEDY_UNITS;
1023 NL_SLOTS[NL_NUM_NEEDY_UNITS] = frame;
1024 NL_NUM_NEEDY_UNITS = NL_NUM_NEEDY_UNITS + 1;
1025 NLAnchorFrame( frame );
1026 end
1027  
1028 if( NLConfig.AutoSort == 1 and not NL_MOUSE_IN_FRAME ) then
1029 NLSortFrameIntoList(frame);
1030 end
1031  
1032 if( NL_MINIMIZED ) then
1033 NLHeaderMinimized:Show();
1034 else
1035 NLHeader:Show();
1036 end
1037  
1038 return frame;
1039 end
1040  
1041 function NLAnchorFrame( frame )
1042 if( frame ~= NL_SLOTS[frame.SlotIndex] ) then
1043 NLBlacklistUnit(frame.Unit);
1044 end
1045  
1046 if( frame.SlotIndex < NLConfig.MaxUnits ) then
1047 if( not frame:IsShown() ) then
1048 -- draw the details of the frame, because it's now being made visible
1049 frame:Show();
1050 end
1051 frame:ClearAllPoints();
1052 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) );
1053 else
1054 frame:Hide();
1055 end
1056 end
1057  
1058 function NLBlacklistUnit( unit )
1059 NL_RemoveFromList(unit);
1060 local newBlackListItem = {};
1061 newBlackListItem.Unit = unit;
1062 newBlackListItem.Time = NLConfig.BlackListDelay;
1063 table.insert(NL_BLACK_LIST, newBlackListItem);
1064 end
1065  
1066 function NLSortFrameDown( frame )
1067 local nextFrame = nil;
1068 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
1069 NL_DebugMsg("Removing " .. NL_SLOTS[frame.SlotIndex+1].Unit .. " from list because its TopNeed is nil");
1070 NL_RemoveFromList(NL_SLOTS[frame.SlotIndex+1].Unit);
1071 -- at this point, the removed frame should shift the rest up, and this frame can still be sorted downward
1072 end
1073 while( frame.SlotIndex < NL_NUM_NEEDY_UNITS - 1 and ( NL_SLOTS[frame.SlotIndex].TopNeed > NL_SLOTS[frame.SlotIndex+1].TopNeed
1074 or (NL_SLOTS[frame.SlotIndex].TopNeed == NL_SLOTS[frame.SlotIndex+1].TopNeed and
1075 ( ( NL_SLOTS[frame.SlotIndex].TopNeed == NLConfig.HealthNeedIndex and NL_SLOTS[frame.SlotIndex].CurrentHealth > NL_SLOTS[frame.SlotIndex+1].CurrentHealth ) or
1076 ( ( NLConfig.ManaNeedIndex and NL_SLOTS[frame.SlotIndex].TopNeed == NLConfig.ManaNeedIndex and NL_SLOTS[frame.SlotIndex].CurrentMana > NL_SLOTS[frame.SlotIndex+1].CurrentMana ) ) ) ) ) ) do
1077 nextFrame = NL_SLOTS[frame.SlotIndex+1];
1078 nextFrame.SlotIndex = frame.SlotIndex;
1079 frame.SlotIndex = frame.SlotIndex + 1;
1080 NL_SLOTS[frame.SlotIndex] = frame;
1081 NL_SLOTS[nextFrame.SlotIndex] = nextFrame;
1082  
1083 NLAnchorFrame( frame );
1084 NLAnchorFrame( nextFrame );
1085  
1086 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
1087 NL_DebugMsg("Removing " .. NL_SLOTS[frame.SlotIndex+1].Unit .. " from list because its TopNeed is nil");
1088 NL_RemoveFromList(NL_SLOTS[frame.SlotIndex+1].Unit);
1089 -- at this point, the removed frame should shift the rest up, and this frame can still be sorted downward
1090 end
1091 end
1092 end
1093  
1094 function NLSortFrameUp( frame )
1095 local previousFrame = nil;
1096 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
1097 NL_DebugMsg("Removing " .. NL_SLOTS[frame.SlotIndex-1].Unit .. " from list because its TopNeed is nil");
1098 NL_RemoveFromList(NL_SLOTS[frame.SlotIndex-1].Unit);
1099 -- at this point, the removed frame should shift the rest up, and this frame can still be sorted upward
1100 end
1101 while( frame.SlotIndex > 0 and ( NL_SLOTS[frame.SlotIndex].TopNeed < NL_SLOTS[frame.SlotIndex-1].TopNeed
1102 or (NL_SLOTS[frame.SlotIndex].TopNeed == NL_SLOTS[frame.SlotIndex-1].TopNeed and
1103 ( ( NL_SLOTS[frame.SlotIndex].TopNeed == NLConfig.HealthNeedIndex and NL_SLOTS[frame.SlotIndex].CurrentHealth < NL_SLOTS[frame.SlotIndex-1].CurrentHealth ) or
1104 ( NLConfig.ManaNeedIndex and NL_SLOTS[frame.SlotIndex].TopNeed == NLConfig.ManaNeedIndex and NL_SLOTS[frame.SlotIndex].CurrentMana < NL_SLOTS[frame.SlotIndex-1].CurrentMana ) ) ) ) ) do
1105 previousFrame = NL_SLOTS[frame.SlotIndex-1];
1106 previousFrame.SlotIndex = frame.SlotIndex;
1107 frame.SlotIndex = frame.SlotIndex - 1;
1108 NL_SLOTS[frame.SlotIndex] = frame;
1109 NL_SLOTS[previousFrame.SlotIndex] = previousFrame;
1110  
1111 NLAnchorFrame( frame );
1112 NLAnchorFrame( previousFrame );
1113  
1114 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
1115 NL_DebugMsg("Removing " .. NL_SLOTS[frame.SlotIndex-1].Unit .. " from list because its TopNeed is nil");
1116 NL_RemoveFromList(NL_SLOTS[frame.SlotIndex-1].Unit);
1117 -- at this point, the removed frame should shift the rest up, and this frame can still be sorted upward
1118 end
1119 end
1120 end
1121  
1122 function NLSortFrameIntoList(frame)
1123 NLSortFrameUp( frame );
1124 NLSortFrameDown( frame );
1125 end
1126  
1127 function NLShiftRemainingUp( index )
1128 while( index < NL_NUM_NEEDY_UNITS - 1 ) do
1129 NL_SLOTS[index] = NL_SLOTS[index+1];
1130 NL_SLOTS[index].SlotIndex = index;
1131  
1132 NLAnchorFrame( NL_SLOTS[index] );
1133  
1134 index = index + 1;
1135 end
1136 end
1137  
1138 function NL_RemoveFromList(member)
1139 -- sort to bottom of list (so all other units shift up)
1140 if( not member ) then
1141 return;
1142 end
1143  
1144 local frame = getglobal("NLMember"..member);
1145  
1146 -- target has special treatment, as it should not be in the list
1147 if( member == "target" ) then
1148 frame:Hide();
1149 return;
1150 end
1151  
1152 if( NL_MOUSE_IN_FRAME ) then
1153 frame.PendingRemoval = true;
1154 frame:Hide();
1155 return;
1156 end
1157  
1158 if( frame.SlotIndex ) then
1159 NL_SLOTS[frame.SlotIndex] = nil;
1160 frame:Hide();
1161 NLShiftRemainingUp( frame.SlotIndex );
1162 NL_NUM_NEEDY_UNITS = NL_NUM_NEEDY_UNITS - 1;
1163 frame.SlotIndex = nil;
1164 frame.TopNeed = nil;
1165 end
1166  
1167 if( NLConfig.HideHeader == 1 and NL_NUM_NEEDY_UNITS == 0 ) then
1168 NLHeader:Hide();
1169 NLHeaderMinimized:Hide();
1170 end
1171 end
1172  
1173 function NL_MouseEnteredFrame()
1174 NL_MOUSE_IN_FRAME = true;
1175 NL_LIST_IS_SORTED = false;
1176 end
1177  
1178 function NL_MouseLeftFrame()
1179 NL_MOUSE_IN_FRAME = false;
1180 end
1181  
1182 function NL_UpdateUnit(id)
1183 NL_UpdateNeeds( id );
1184 local frame = "NLMember" .. id;
1185 if( NLConfig.ShowHealthNum == 1 ) then
1186 if( NLConfig.ShowHealthLost == 1 ) then
1187 getglobal(frame .. "HealthNum"):SetText(UnitHealth(id)-UnitHealthMax(id));
1188 else
1189 getglobal(frame .. "HealthNum"):SetText(UnitHealth(id) .. "/" .. UnitHealthMax(id));
1190 end
1191 getglobal(frame .. "HealthNum"):Show();
1192 elseif( getglobal(frame .. "HealthNum"):IsShown() ) then
1193 getglobal(frame .. "HealthNum"):Hide();
1194 end
1195  
1196 if( UnitIsDead(id) or UnitIsGhost(id) or UnitHealth(id) == 0 ) then
1197 getglobal(frame .. "HPBar"):Hide();
1198 getglobal(frame .. "MPBar"):Hide();
1199 if( NLConfig.ShowHealth == 1 or NLConfig.ShowMana == 1 ) then
1200 if( UnitIsGhost(id) ) then
1201 getglobal(frame .. "Status"):SetText("Ghost");
1202 elseif( UnitIsDead(id) or UnitHealth(id) == 0 ) then
1203 getglobal(frame .. "Status"):SetText("Dead");
1204 end
1205 getglobal(frame .. "Status"):Show();
1206 end
1207 return;
1208 else
1209 getglobal(frame .. "Status"):Hide();
1210 if( NLConfig.ShowHealth == 1 ) then
1211 getglobal(frame .. "HPBar"):Show();
1212 else
1213 getglobal(frame .. "HPBar"):Hide();
1214 end
1215 -- determine the color for the power bar
1216 local info = ManaBarColor[UnitPowerType(id)];
1217 getglobal(frame .. "MPBar"):SetStatusBarColor(info.r, info.g, info.b);
1218 if( NLConfig.ShowMana == 1 ) then
1219 getglobal(frame .. "MPBar"):Show();
1220 else
1221 getglobal(frame .. "MPBar"):Hide();
1222 end
1223 end
1224  
1225 -- set the name in the frame
1226 if( getglobal(frame).CurrentHealth ) then
1227 local percent = floor(getglobal(frame).CurrentHealth);
1228 if ( percent and percent > 0 ) then
1229 if ( percent > 100 ) then
1230 percent = 100;
1231 end
1232 getglobal(frame .. "HPBar"):SetValue(percent);
1233 local hppercent = percent/100;
1234 local r, g;
1235 if ( hppercent > 0.5 and hppercent <= 1) then
1236 g = 1;
1237 r = (1.0 - hppercent) * 2;
1238 elseif ( hppercent >= 0 and hppercent <= 0.5 ) then
1239 r = 1.0;
1240 g = hppercent * 2;
1241 else
1242 r = 0;
1243 g = 1;
1244 end
1245 getglobal(frame .. "HPBar"):SetStatusBarColor(r, g, 0);
1246 end
1247 end
1248  
1249 -- get the class of the player and update the mana bar appropriately
1250 if( UnitManaMax(id) == 0 ) then
1251 getglobal(frame .. "MPBar"):SetValue(0);
1252 else
1253 if( getglobal(frame).CurrentMana ) then
1254 local percent = floor(getglobal(frame).CurrentMana);
1255 getglobal(frame .. "MPBar"):SetValue(percent);
1256 end
1257 end
1258 end
1259  
1260 function NL_UpdateAura( unit )
1261 if( not UnitExists(unit) ) then
1262 return;
1263 end
1264  
1265 local frame = "NLMember" .. unit;
1266  
1267 if( NLConfig.ShowBuffs == 0 and NLConfig.ShowHealBuffs == 0 ) then
1268 getglobal(frame .. "BuffsDetails"):SetWidth( 5 );
1269 getglobal(frame .. "BuffsDetails"):Hide();
1270 else
1271 local buff;
1272 local numBuffs = 0;
1273 local index = 1;
1274 for NL_ITERATOR=1, NL_MAX_TOOLTIP_BUFFS do
1275 buff = UnitBuff(unit, NL_ITERATOR);
1276 if ( buff and (NLConfig.ShowBuffs == 1 or (NLConfig.ShowHealBuffs == 1 and
1277 (buff == NL_ICON_LOCATION .. "Spell_Nature_Rejuvenation" or
1278 buff == NL_ICON_LOCATION .. "Spell_Nature_ResistNature" or
1279 buff == NL_ICON_LOCATION .. "Spell_Holy_Renew" )
1280 ) ) ) then
1281 getglobal(frame .. "BuffsDetailsBuff"..index):SetNormalTexture(buff);
1282 getglobal(frame .. "BuffsDetailsBuff"..index):Show();
1283 getglobal(frame .. "BuffsDetailsBuff"..index):SetID(index);
1284 if( getglobal(frame .. "BuffsDetailsBuff"..index) == NL_MOUSE_OVER_FRAME ) then
1285 GameTooltip:SetUnitBuff( getglobal(frame).Unit, NL_ITERATOR );
1286 end
1287 index = index + 1;
1288 numBuffs = numBuffs + 1;
1289 end
1290 end
1291 for NL_ITERATOR=index, NL_MAX_TOOLTIP_BUFFS do
1292 getglobal(frame .. "BuffsDetailsBuff"..NL_ITERATOR):Hide();
1293 end
1294  
1295 getglobal(frame .. "BuffsDetailsBuff1"):ClearAllPoints();
1296 getglobal(frame .. "BuffsDetailsBuff1"):SetPoint( "TOPLEFT", frame .. "BuffsDetails", "TOPLEFT", 5, -5 );
1297 getglobal(frame .. "BuffsDetails"):SetHeight( 26 );
1298 -- Size the tooltip
1299 if ( numBuffs > 0 ) then
1300 getglobal(frame .. "BuffsDetails"):SetWidth( (numBuffs * 17) + 9 );
1301 getglobal(frame .. "BuffsDetails"):Show();
1302 else
1303 getglobal(frame .. "BuffsDetails"):SetWidth( 5 );
1304 getglobal(frame .. "BuffsDetails"):Hide();
1305 end
1306 end
1307  
1308 if( NLConfig.ShowDebuffs == 0 ) then
1309 getglobal(frame .. "DebuffsDetails"):SetWidth( 5 );
1310 getglobal(frame .. "DebuffsDetails"):Hide();
1311 else
1312 local buff;
1313 local numDebuffs = 0;
1314 local index = 1;
1315 for NL_ITERATOR=1, NL_MAX_TOOLTIP_DEBUFFS do
1316 buff = UnitDebuff(unit, NL_ITERATOR);
1317  
1318 if ( buff ) then
1319 getglobal(frame .. "DebuffsDetailsDebuff"..index):SetNormalTexture(buff);
1320 getglobal(frame .. "DebuffsDetailsDebuff"..index):Show();
1321 getglobal(frame .. "DebuffsDetailsDebuff"..index):SetID(index);
1322 if( getglobal(frame .. "DebuffsDetailsDebuff"..index) == NL_MOUSE_OVER_FRAME ) then
1323 GameTooltip:SetUnitDebuff( getglobal(frame).Unit, NL_ITERATOR );
1324 end
1325 index = index + 1;
1326 numDebuffs = numDebuffs + 1;
1327 end
1328 end
1329 for NL_ITERATOR=index, NL_MAX_TOOLTIP_DEBUFFS do
1330 getglobal(frame .. "DebuffsDetailsDebuff"..NL_ITERATOR):Hide();
1331 end
1332  
1333 getglobal(frame .. "DebuffsDetailsDebuff1"):ClearAllPoints();
1334 getglobal(frame .. "DebuffsDetailsDebuff1"):SetPoint( "TOPLEFT", frame .. "DebuffsDetails", "TOPLEFT", 5, -5 );
1335 getglobal(frame .. "DebuffsDetails"):SetHeight( 26 );
1336 -- Size the tooltip
1337 if ( numDebuffs > 0 ) then
1338 getglobal(frame .. "DebuffsDetails"):SetWidth( (numDebuffs * 17) + 9 );
1339 getglobal(frame .. "DebuffsDetails"):Show();
1340 else
1341 getglobal(frame .. "DebuffsDetails"):SetWidth( 5 );
1342 getglobal(frame .. "DebuffsDetails"):Hide();
1343 end
1344 end
1345 end
1346  
1347 function NL_UpdateNeeds( member )
1348 local frame = getglobal( "NLMember"..member );
1349 if( not frame or not frame.TopNeed or frame.TopNeed < 1 or NLConfig.ShowNeeds == 0 ) then
1350 NL_ClearNeedDetails( member );
1351 return;
1352 end
1353  
1354 local needFrameIndex = 1;
1355  
1356 -- if resurrection is a need of this unit
1357 if( frame.Needs[NLConfig.ResurrectionNeedIndex] ) then
1358 if( NL_CURE_SPELLS[NL_PLAYERCLASS] and NL_CURE_SPELLS[NL_PLAYERCLASS].Resurrection ) then
1359 iconName = NL_CURE_SPELLS[NL_PLAYERCLASS].Resurrection.Icon;
1360 if( iconName ~= "" ) then
1361 local needFrame = getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex);
1362 if( NLConfig.LargeNeedIcons == 1 ) then
1363 getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetWidth( 22 );
1364 getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetHeight( 22 );
1365 else
1366 getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetWidth( 16 );
1367 getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetHeight( 16 );
1368 end
1369 needFrame:SetNormalTexture(NL_ICON_LOCATION .. iconName);
1370 needFrame.NeedName = "Resurrection";
1371 needFrame:Show();
1372 if( needFrame == NL_MOUSE_OVER_FRAME ) then
1373 NL_MouseOverNeedButton(needFrame);
1374 end
1375 needFrameIndex = needFrameIndex + 1;
1376 end
1377 end
1378 else
1379 for NL_ITERATOR=2, NLConfig.NumNeeds - 1 do
1380 local iconName = "";
1381 if( frame.Needs[NL_ITERATOR] ) then
1382 if( NL_BUFF_SPELLS[NL_PLAYERCLASS] and NL_BUFF_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name] ) then
1383 iconName = NL_BUFF_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name].Icons[1];
1384 elseif( NL_CURE_SPELLS[NL_PLAYERCLASS] and NL_CURE_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name] ) then
1385 iconName = NL_CURE_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name].Icon;
1386 elseif( NL_ENCHANT_SPELLS[NL_PLAYERCLASS] and NL_ENCHANT_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name] ) then
1387 iconName = NL_ENCHANT_SPELLS[NL_PLAYERCLASS][NLConfig.Needs[NL_ITERATOR].Name].Icon;
1388 elseif( NL_OTHER[NLConfig.Needs[NL_ITERATOR].Name] ) then
1389 iconName = NL_OTHER[NLConfig.Needs[NL_ITERATOR].Name].Icon;
1390 end
1391  
1392 if( iconName ~= "" ) then
1393 local needFrame = getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex);
1394 if( NLConfig.LargeNeedIcons == 1 ) then
1395 getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetWidth( 22 );
1396 getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetHeight( 22 );
1397 else
1398 getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetWidth( 16 );
1399 getglobal(frame:GetName() .. "NeedsDetailsNeed"..needFrameIndex):SetHeight( 16 );
1400 end
1401 needFrame:SetNormalTexture(NL_ICON_LOCATION .. iconName);
1402 needFrame.NeedName = NLConfig.Needs[NL_ITERATOR].Name;
1403 needFrame:Show();
1404 if( needFrame == NL_MOUSE_OVER_FRAME ) then
1405 NL_MouseOverNeedButton(needFrame);
1406 end
1407 needFrameIndex = needFrameIndex + 1;
1408 if( needFrameIndex > NL_MAX_NEEDS ) then
1409 -- this is a break condition, we don't need to see more needs
1410 NL_ITERATOR = NLConfig.NumNeeds;
1411 end
1412 end
1413 end
1414 end
1415 end
1416  
1417 local needCount = needFrameIndex - 1;
1418  
1419 for NL_ITERATOR=needFrameIndex, NL_MAX_NEEDS - 1 do
1420 getglobal(frame:GetName() .. "NeedsDetailsNeed"..NL_ITERATOR):Hide();
1421 end
1422  
1423 if( NLConfig.LargeNeedIcons == 1 ) then
1424 getglobal(frame:GetName() .. "NeedsDetails"):SetWidth( needCount * 23 + 9 );
1425 getglobal(frame:GetName() .. "NeedsDetails"):SetHeight( 32 );
1426 else
1427 getglobal(frame:GetName() .. "NeedsDetails"):SetWidth( needCount * 17 + 9 );
1428 getglobal(frame:GetName() .. "NeedsDetails"):SetHeight( 26 );
1429 end
1430 getglobal(frame:GetName() .. "NeedsDetailsNeed1"):ClearAllPoints();
1431 getglobal(frame:GetName() .. "NeedsDetailsNeed1"):SetPoint( "TOPLEFT", frame:GetName() .. "NeedsDetails", "TOPLEFT", 5, -5 );
1432 if( needCount > 0 ) then
1433 getglobal(frame:GetName() .. "NeedsDetails"):Show();
1434 else
1435 getglobal(frame:GetName() .. "NeedsDetails"):Hide();
1436 end
1437 end
1438  
1439 function NL_SetTooltipOwner( frame, anchor )
1440 if( NLConfig.ShowTooltips == 1 ) then
1441 GameTooltip:SetOwner(frame, anchor);
1442 else
1443 GameTooltip:Hide();
1444 end
1445 end
1446  
1447 function NLMember_OnEnter(frame)
1448 NL_SetTooltipOwner( frame, "ANCHOR_TOPLEFT" );
1449 GameTooltip:SetUnit( frame.Unit );
1450 end
1451  
1452 function NLMember_OnLeave(frame)
1453 GameTooltip:Hide();
1454 end
1455  
1456 function NLMember_OnClick(button, frame)
1457 if( NLConfig.UseCastParty == 1 and CastParty_OnClickByUnit ~= nil ) then
1458 CastParty_OnClickByUnit( button, frame.Unit );
1459 else
1460 if ( button == "LeftButton" ) then
1461 -- determine which unit was clicked
1462 if ( SpellIsTargeting() ) then
1463 SpellTargetUnit(frame.Unit);
1464 elseif ( CursorHasItem() ) then
1465 DropItemOnUnit(frame.Unit);
1466 else
1467 TargetUnit(frame.Unit);
1468 end
1469 else
1470 if( SpellIsTargeting() ) then
1471 SpellStopTargeting();
1472 return;
1473 end
1474 end
1475 end
1476 end
1477  
1478 function NLMember_CheckAllUnits()
1479 NL_NUM_NEEDY_UNITS = 0;
1480 if( NLConfig.HideHeader == 1 ) then
1481 NLHeader:Hide();
1482 end
1483  
1484 NL_SLOTS = {};
1485  
1486 -- hide all frames
1487 NLMemberplayer:Hide();
1488 NLMemberplayer.SlotIndex = nil;
1489 NLMemberplayer.TopNeed = nil;
1490 NLMemberplayer.Needs = {};
1491 NLMemberpet:Hide();
1492 NLMemberpet.SlotIndex = nil;
1493 NLMemberpet.TopNeed = nil;
1494 NLMemberpet.Needs = {};
1495  
1496 for NL_ITERATOR = 1, 4 do
1497 getglobal("NLMemberparty"..NL_ITERATOR):Hide();
1498 getglobal("NLMemberparty"..NL_ITERATOR).SlotIndex = nil;
1499 getglobal("NLMemberparty"..NL_ITERATOR).TopNeed = nil;
1500 getglobal("NLMemberparty"..NL_ITERATOR).Needs = {};
1501 getglobal("NLMemberpartypet"..NL_ITERATOR):Hide();
1502 getglobal("NLMemberpartypet"..NL_ITERATOR).SlotIndex = nil;
1503 getglobal("NLMemberpartypet"..NL_ITERATOR).TopNeed = nil;
1504 getglobal("NLMemberpartypet"..NL_ITERATOR).Needs = {};
1505 end
1506 for NL_ITERATOR = 1, 40 do
1507 getglobal("NLMemberraid"..NL_ITERATOR):Hide();
1508 getglobal("NLMemberraid"..NL_ITERATOR).SlotIndex = nil;
1509 getglobal("NLMemberraid"..NL_ITERATOR).TopNeed = nil;
1510 getglobal("NLMemberraid"..NL_ITERATOR).Needs = {};
1511 getglobal("NLMemberraidpet"..NL_ITERATOR):Hide();
1512 getglobal("NLMemberraidpet"..NL_ITERATOR).SlotIndex = nil;
1513 getglobal("NLMemberraidpet"..NL_ITERATOR).TopNeed = nil;
1514 getglobal("NLMemberraidpet"..NL_ITERATOR).Needs = {};
1515 end
1516  
1517 -- if player in a raid, check all 40 units, otherwise just check player and party
1518 if( GetNumRaidMembers() > 0 ) then
1519 for NL_ITERATOR = 1, 40 do
1520 if( UnitExists( "raid" .. NL_ITERATOR ) ) then
1521 NL_CheckAllNeeds( "raid" .. NL_ITERATOR );
1522 if( UnitExists( "raidpet" .. NL_ITERATOR ) ) then
1523 NL_CheckAllNeeds( "raidpet" .. NL_ITERATOR );
1524 end
1525 end
1526 end
1527 else
1528 if( UnitExists( "player" ) ) then
1529 NL_CheckAllNeeds( "player" );
1530 if( UnitExists( "pet" ) ) then
1531 NL_CheckAllNeeds( "pet" );
1532 end
1533 end
1534  
1535 for NL_ITERATOR = 1, 4 do
1536 if( UnitExists( "party" .. NL_ITERATOR ) ) then
1537 NL_CheckAllNeeds( "party" .. NL_ITERATOR );
1538 if( UnitExists( "partypet" .. NL_ITERATOR ) ) then
1539 NL_CheckAllNeeds( "partypet" .. NL_ITERATOR );
1540 end
1541 end
1542 end
1543 end
1544  
1545 NL_CheckTarget();
1546 end
1547  
1548 function NL_CheckTarget()
1549 NLMembertarget.Needs = {};
1550 NLMembertarget.TopNeed = nil;
1551 NLMembertarget:Hide();
1552  
1553 if( NLConfig.ShowTargetFrame == 1 ) then
1554 if( UnitExists( "target" ) and UnitIsFriend( "target", "player" ) ) then
1555 NL_CheckAllNeeds( "target" );
1556 else
1557 NLMembertarget:Hide();
1558 end
1559 end
1560 end
1561  
1562 function NL_MouseOverNeedButton(frame)
1563 NL_SetTooltipOwner(frame:GetParent():GetParent(), "ANCHOR_TOPLEFT");
1564 local tooltipText = "";
1565 if( NL_BUFF_SPELLS[NL_PLAYERCLASS] and NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName] and NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] ) then
1566 if( NL_BUFF_SPELLS[NL_PLAYERCLASS] and NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName] ) then
1567 if( NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] ) then
1568 tooltipText = "Left-click to cast " .. NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] .. ".";
1569 end
1570 if( NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName][2] ) then
1571 tooltipText = tooltipText .. "\nRight-click to cast " .. NL_BUFF_SPELLS[NL_PLAYERCLASS][frame.NeedName][2] .. ".";
1572 end
1573 end
1574 elseif( NL_ENCHANT_SPELLS[NL_PLAYERCLASS] and NL_ENCHANT_SPELLS[NL_PLAYERCLASS][frame.NeedName] and NL_ENCHANT_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] ) then
1575 if( NL_PLAYERCLASS == "Rogue" ) then
1576 tooltipText = "Needs " .. NL_ENCHANT_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] .. ".";
1577 else
1578 tooltipText = "Needs " .. NL_ENCHANT_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] .. ".\nClick here to fix.";
1579 end
1580 elseif( frame.NeedName == "Resurrection" ) then
1581 if( NL_CURE_SPELLS[NL_PLAYERCLASS] and NL_CURE_SPELLS[NL_PLAYERCLASS].Resurrection ) then
1582 tooltipText = "Left-click to cast " .. NL_CURE_SPELLS[NL_PLAYERCLASS].Resurrection[1] .. ".";
1583 end
1584 elseif( frame.NeedName == "WellFed" ) then
1585 tooltipText = "Needs to be well fed.";
1586 elseif( frame.NeedName == "Health" ) then
1587 tooltipText = "Needs healing.";
1588 if( NLConfig.HealSpells ) then
1589 if( NLConfig.HealSpells[1] ) then
1590 tooltipText = tooltipText .. "\nLeft-click to cast " .. NLConfig.HealSpells[1] .. ".";
1591 end
1592 if( NLConfig.HealSpells[2] ) then
1593 tooltipText = tooltipText .. "\nRight-click to cast " .. NLConfig.HealSpells[2] .. ".";
1594 end
1595 if( NLConfig.HealSpells[3] ) then
1596 tooltipText = tooltipText .. "\nMiddle-click to cast " .. NLConfig.HealSpells[3] .. ".";
1597 end
1598 if( NLConfig.HealSpells[4] ) then
1599 tooltipText = tooltipText .. "\nClick button 4 to cast " .. NLConfig.HealSpells[4] .. ".";
1600 end
1601 if( NLConfig.HealSpells[5] ) then
1602 tooltipText = tooltipText .. "\nClick button 5 to cast " .. NLConfig.HealSpells[5] .. ".";
1603 end
1604 end
1605 if( tooltipText == "Needs healing." ) then
1606 tooltipText = tooltipText .. "\nUse 'Configure Spells' from the configuration window to add heal spells.";
1607 end
1608 elseif( frame.NeedName == "Mana" ) then
1609 tooltipText = "Needs mana.\nLeft-click to cast Innervate.";
1610 else
1611 tooltipText = "Needs cure for " .. frame.NeedName .. ".";
1612 if( NL_CURE_SPELLS[NL_PLAYERCLASS] and NL_CURE_SPELLS[NL_PLAYERCLASS][frame.NeedName] ) then
1613 if( NL_CURE_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] ) then
1614 tooltipText = tooltipText .. "\nLeft-click to cast " .. NL_CURE_SPELLS[NL_PLAYERCLASS][frame.NeedName][1] .. ".";
1615 end
1616 if( NL_CURE_SPELLS[NL_PLAYERCLASS][frame.NeedName][2] ) then
1617 tooltipText = tooltipText .. "\nRight-click to cast " .. NL_CURE_SPELLS[NL_PLAYERCLASS][frame.NeedName][2] .. ".";
1618 end
1619 end
1620 end
1621 GameTooltip:SetText( tooltipText );
1622 end
1623  
1624 function NL_CureTopNeed(button)
1625 for NL_ITERATOR = 0, NL_NUM_NEEDY_UNITS - 1 do
1626 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
1627 NL_CureNeedOnUnit( NLConfig.Needs[NL_SLOTS[NL_ITERATOR].TopNeed].Name, NL_SLOTS[NL_ITERATOR].Unit, button );
1628 return;
1629 end
1630 end
1631 end
1632  
1633 function NL_SortList()
1634 if( NL_MOUSE_IN_FRAME ) then
1635 NL_MOUSE_IN_FRAME = false;
1636 NL_SortAllVisibleFrames();
1637 NL_MOUSE_IN_FRAME = true;
1638 else
1639 NL_SortAllVisibleFrames();
1640 end
1641 end