vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --[[---------------------------------------------------------------------------------
2 Class declaration
3 ------------------------------------------------------------------------------------]]
4  
5 local elapsed = 0
6 local visible,frames,dirty,aura,dirtyStatus = {},{},{},{},{}
7 local marked,selected,sort,keys,registry= {},{},{},{},{}
8 local feign,soulstone,inrange,innervate,poweri = {},{},{},{},{}
9 local anyDirty,dirtyRoster
10 local force = 0
11  
12 local debug = false
13  
14 PerfectRaid = {
15 name = 'PerfectRaid',
16 description = "PerfectRaid is a very minimal set of configurable raid frames.",
17 version = '1.0',
18 releaseDate = '2006-02-12',
19 author = 'Cladhaire',
20 email = 'cladhaire@gmail.com',
21 website = 'http://cladhaire.wowinterface.com',
22  
23 Initialize = function(self)
24 self:Debug("Initializing PefectRaid.")
25 self.poolsize = 0
26 self.frames = frames
27 self.visible = visible
28 self.tooltip = PerfectRaidTooltip
29 self.master = CreateFrame("Frame", "PerfectRaidFrame", UIParent)
30 self.master:SetScript("OnEvent", self.EventHandler)
31 self.master:SetScript("OnUpdate", self.OnUpdate)
32 self.master:SetMovable(true)
33  
34 self:RegisterEvent("PLAYER_ENTERING_WORLD")
35 self:RegisterEvent("RAID_ROSTER_UPDATE")
36 self:RegisterEvent("ADDON_LOADED")
37  
38 self.defaults = { Align = "left",
39 Select = "none",
40 Sort = "groupname",
41 BackdropBar = "bar 0 0 0 1",
42 BackdropFrame = "frame 0 0 0 0",
43 Truncate = true,
44 LowMana = 25,
45 Scale = 1,
46 Voffset = -5,
47 Filter = false,
48 RangeCheck = false,
49 }
50 end,
51  
52 Enable = function (self)
53 self.enabled = true
54 self:RegisterEvent("UNIT_HEALTH")
55 self:RegisterEvent("UNIT_AURA")
56 self:RegisterEvent("PLAYER_TARGET_CHANGED")
57 self:RegisterEvent("CHAT_MSG_SYSTEM")
58  
59 self:RangeHooks()
60  
61 if not self.virtualfont then
62 self.virtualfont = self.master:CreateFontString(nil, "ARTWORK")
63 self.virtualfont:SetFontObject(GameFontHighlightSmall)
64 end
65  
66 -- Enable the OnUpdates
67 self.master:Show()
68  
69 -- If we find WatchDog, enable click-casting
70 if WatchDog_OnClick then
71 PerfectRaidCustomClick = WatchDog_OnClick
72 end
73 end,
74  
75 Disable = function(self)
76 self:UnhookAll()
77 self.enabled = nil
78 self.master:Hide()
79 end,
80  
81 RangeHooks = function(self)
82 if self.opt.RangeCheck and not self:IsHooked("CastSpell") then
83 self:Hook("CastSpell")
84 self:Hook("CastSpellByName")
85 self:Hook("UseAction")
86 else
87 self:UnhookAll()
88 end
89 end,
90  
91 CheckVariables = function(self)
92 PerfectRaidOpt = PerfectRaidOpt or {}
93 self.opt = PerfectRaidOpt
94 setmetatable(self.opt, {__index=self.defaults, __call=function(v) return self.opt[v] end})
95  
96 if not self.opt.PosX then
97 self.master:ClearAllPoints()
98 self.master:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
99 self.master:SetWidth(100)
100 self.master:SetHeight(100)
101 else
102 self.master:ClearAllPoints()
103 self.master:SetPoint("TOPLEFT", UIParent, "TOPLEFT", self.opt.PosX, self.opt.PosY)
104 self.master:SetWidth(100)
105 self.master:SetHeight(100)
106 end
107 end,
108  
109 SetOpt = function(self, var, val)
110 if self.defaults[var] == val then
111 self.opt[var] = nil
112 else
113 self.opt[var] = val
114 end
115 end,
116  
117 --[[---------------------------------------------------------------------------------
118 Event handlers
119 ------------------------------------------------------------------------------------]]
120  
121 ADDON_LOADED = function(self)
122 self:Debug("ADDON_LOADED")
123 AceHookLib:Embed(PerfectRaid, "1.4")
124  
125 if string.lower(arg1) == "perfectraid" then
126 self:UnregisterEvent("ADDON_LOADED")
127 self:CheckVariables()
128 self:RestorePosition()
129  
130 if not self.cmd then
131 self:Debug("Registering chat commands.")
132 self.cmd = self.AceChatCmd:new(PERFECTRAID.CHAT_COMMANDS, PERFECTRAID.CHAT_OPTIONS)
133 self.cmd.app = self
134 self.cmd:Register(self)
135 end
136 end
137 end,
138  
139 PLAYER_ENTERING_WORLD = function(self)
140 self:Debug("PLAYER_ENTERING_WORLD")
141 self:RAID_ROSTER_UPDATE()
142 end,
143  
144 RAID_ROSTER_UPDATE = function(self)
145 self:Debug("RAID_ROSTER_UPDATE")
146 if GetNumRaidMembers() > 0 then
147 if not self.enabled then
148 self:Debug("You've joined a raid-- enabling PerfectRaid.")
149 end
150 self:Enable()
151 dirtyRoster = true
152 elseif self.enabled then
153 self:Disable()
154 end
155 end,
156  
157 UNIT_HEALTH = function(self)
158 --self:Debug("UNIT_HEALTH for %s.",arg1)
159 if visible[arg1] then
160 anyDirty = true
161 dirty[arg1] = true
162 end
163 end,
164  
165 UNIT_AURA = function(self)
166 --self:Debug("UNIT_AURA for %s.",arg1)
167 if visible[arg1] then
168 anyDirty = true
169 dirtyStatus[arg1] = true
170 end
171 end,
172  
173 PLAYER_TARGET_CHANGED = function(self)
174 self:Debug("PLAYER_TARGET_CHANGED")
175  
176 for k,v in pairs(visible) do
177 if UnitIsUnit(k, "target") then
178 local f = frames[k]
179 marked[k] = true
180 f.Prefix:SetText(self.mark)
181 f.Prefix:SetTextColor(1,1,0)
182 --[[
183 elseif UnitIsUnit(k, "targettarget") then
184 marked[k] = true
185 f.Prefix:SetText(self.ttmark)
186 f.Prefix:SetTextColor(1,1,0)
187 --]]
188 elseif marked[k] then
189 local f = frames[k]
190 marked[k] = nil
191 if selected[k] then
192 f.Prefix:SetTextColor(1,1,1)
193 if self.opt.Select == "number" then
194 f.Prefix:SetText(f.group)
195 else
196 f.Prefix:SetText(">")
197 end
198 else
199 f.Prefix:SetText()
200 end
201 end
202 end
203 end,
204  
205 CHAT_MSG_SYSTEM = function(self)
206 if string.find(arg1, ERR_RAID_YOU_LEFT) then
207 self:Disable()
208 end
209 end,
210  
211 CastSpell = function(self,a1,a2,a3)
212 rangecheck = true
213 self.Hooks.CastSpell.orig(a1,a2,a3)
214  
215 if SpellIsTargeting() then
216 for k,v in visible do
217 if SpellCanTargetUnit(k) then
218 frames[k]:SetAlpha(1.0)
219 else
220 frames[k]:SetAlpha(0.5)
221 end
222 end
223 end
224 end,
225  
226 CastSpellByName = function(self,a1,a2,a3)
227 rangecheck = true
228 self.Hooks.CastSpellByName.orig(a1,a2,a3)
229  
230 if SpellIsTargeting() then
231 for k,v in visible do
232 if SpellCanTargetUnit(k) then
233 frames[k]:SetAlpha(1.0)
234 else
235 frames[k]:SetAlpha(0.5)
236 end
237 end
238 end
239 end,
240  
241 UseAction = function(self,a1,a2,a3)
242 rangecheck = true
243 self.Hooks.UseAction.orig(a1,a2,a3)
244  
245 if SpellIsTargeting() then
246 for k,v in visible do
247 if SpellCanTargetUnit(k) then
248 frames[k]:SetAlpha(1.0)
249 else
250 frames[k]:SetAlpha(0.5)
251 end
252 end
253 end
254 end,
255  
256 --[[---------------------------------------------------------------------------------
257 Main Addon
258 ------------------------------------------------------------------------------------]]
259  
260 OnUpdate = function()
261 elapsed = elapsed + arg1
262 force = force + arg1
263  
264 if elapsed > 0.20 and (anyDirty or dirtyRoster) then
265 local self = PerfectRaid
266 elapsed = 0
267 anyDirty = nil
268  
269 if dirtyRoster then
270 self:UpdateVisibility()
271 for k,v in pairs(visible) do
272 self:UpdateUnit(k)
273 self:UpdateStatus(k)
274 end
275 dirtyRoster = nil
276 end
277  
278 for k,v in pairs(dirty) do
279 dirty[k] = nil
280 self:UpdateUnit(k)
281 end
282  
283 for k,v in pairs(dirtyStatus) do
284 dirtyStatus[k] = nil
285 self:UpdateStatus(k)
286 end
287 elseif force > 1.0 then
288 force = 0
289 elapsed = 0
290 anyDirty = nil
291  
292 for k,v in pairs(visible) do
293 dirty[k] = nil
294 PerfectRaid:UpdateUnit(k)
295 end
296 end
297 end,
298  
299 UpdateUnit = function(self, unit)
300 if not UnitExists(unit) then return end
301  
302 local f = frames[unit]
303  
304 if UnitClass(unit) then
305 local _,class = UnitClass(unit)
306 f.Name:SetText(PERFECTRAID.CLASSES[class]..UnitName(unit).."|r")
307 else
308 f.Name:SetText(UnitName(unit) or "Unknown")
309 end
310  
311 local hp = UnitIsConnected(unit) and UnitHealth(unit) or 0
312 local hpmax = UnitHealthMax(unit)
313 local hpp = (hpmax ~= 0) and floor((hp / hpmax) * 100) or 0
314  
315 if UnitPowerType(unit) == 0 then
316  
317 local mana = UnitMana(unit) or 0
318 local max = UnitManaMax(unit) or 1
319 local mpp = floor((mana / max) * 100)
320  
321 if max > 0 and mpp <= self.opt.LowMana and not f.lowmana then
322 dirtyStatus[unit] = true
323 f.lowmana = true
324 self:UpdateStatus(unit)
325 elseif f.lowmana and max > 0 and mpp > self.opt.LowMana then
326 f.lowmana = nil
327 self:UpdateStatus(unit)
328 end
329 end
330  
331 if not feign[unit] then
332 f.Bar:SetValue(hpp)
333 f.Bar:SetStatusBarColor(self:GetHPSeverity(hp/hpmax,1))
334 else
335 f.Bar:SetValue(100)
336 f.Bar:SetStatusBarColor(0, 0.9, 0.78)
337 end
338  
339 end,
340  
341 UpdateVisibility = function(self)
342 local num = GetNumRaidMembers()
343 if num == 0 then return end
344  
345 if num >= self.poolsize then self:CreateFrame(num) end
346  
347 frames[1]:Show()
348 visible["raid1"] = true
349  
350 for i=2,num do
351 frames[i]:Show()
352 local id = "raid"..i
353 visible[id] = true
354 end
355  
356 for i=(num+1),self.poolsize do
357 visible["raid"..i] = nil
358 if not frames[i] then break end
359 frames[i]:Hide()
360 end
361  
362 for k,v in visible do
363 if not UnitName(k) then
364 dirtyRoster = true
365 return
366 end
367 end
368  
369 self:Sort(nil, true)
370 self:Align(nil, true)
371 self:Select(nil, true)
372 self:SetBackdrop(nil, true)
373 self:SetScale(nil, true)
374 end,
375  
376 UpdateStatus = function(self, unit)
377  
378 soulstone[unit] = nil
379 feign[unit] = nil
380 innervate[unit] = nil
381 poweri[unit] = nil
382  
383 if UnitIsDead(unit) then
384 for i=1,32 do
385 local texture = UnitBuff(unit, i)
386 if texture == "Interface\\Icons\\Ability_Rogue_FeignDeath" then
387 feign[unit] = true
388 break
389 end
390 end
391 if not feign[unit] then
392 self.frames[unit].Status:SetText("|cffff0000Dead|r")
393 return
394 end
395 end
396  
397 if UnitIsGhost(unit) then
398 self.frames[unit].Status:SetText("|cff9d9d9dGhost|r")
399 return
400 elseif not UnitIsConnected(unit) then
401 self.frames[unit].Status:SetText("|cffff8000Offline|r")
402 return
403 else
404 -- Clear Feign Death when it comes off
405 if feign[unit] and not UnitIsDead(unit) then feign[unit] = nil end
406  
407 for k,v in pairs(aura) do aura[k] = nil end
408  
409 if UnitPowerType(unit) == 0 and not feign[unit] then
410  
411 local mana = UnitMana(unit) or 0
412 local max = UnitManaMax(unit) or 1
413 local mpp = floor((mana / max) * 100)
414  
415 if max > 0 and mpp <= self.opt.LowMana then
416 aura.LowMana = true
417 end
418 end
419  
420 -- No easy way out, so we need to scan the debuffs
421 for i=1,16 do
422 if UnitDebuff(unit, i) then
423 PerfectRaidTooltipTextRight1:SetText("")
424 PerfectRaidTooltip:SetUnitDebuff(unit, i, self.opt.Filter)
425 local type = PerfectRaidTooltipTextRight1:GetText()
426 if PERFECTRAID.COLORS[type] then
427 aura[type] = true
428 end
429 end
430 for i=1,32 do
431 local texture = UnitBuff(unit, i)
432 if not texture then break end
433 if texture == "Interface\\Icons\\Spell_Shadow_SoulGem" then
434 soulstone[unit] = true
435 elseif texture == "Interface\\Icons\\Spell_Nature_Lightning" then
436 innervate[unit] = true
437 elseif texture == "Interface\\Icons\\Spell_Holy_PowerInfusion" then
438 poweri[unit] = true
439 end
440 end
441 end
442  
443 local output = string.format("%s%s%s%s%s%s%s%s%s",
444 (soulstone[unit] and PERFECTRAID.COLORS.Soulstone) or "",
445 (innervate[unit] and PERFECTRAID.COLORS.Innervate) or "",
446 (poweri[unit] and PERFECTRAID.COLORS.PowerInfusion) or "",
447 (feign[unit] and PERFECTRAID.COLORS.FeignDeath) or "",
448 (aura[PERFECTRAID.CURSE] and PERFECTRAID.COLORS.Curse) or "",
449 (aura[PERFECTRAID.DISEASE] and PERFECTRAID.COLORS.Disease) or "",
450 (aura[PERFECTRAID.MAGIC] and PERFECTRAID.COLORS.Magic) or "",
451 (aura[PERFECTRAID.POISON] and PERFECTRAID.COLORS.Poison) or "",
452 (aura.LowMana and PERFECTRAID.COLORS.LowMana) or "")
453 self.frames[unit].Status:SetText(output)
454 end
455 end,
456  
457 OnClick = function(self)
458 local unit = this.unit
459 if UnitIsUnit(unit, "player") then unit = "player" end
460  
461 local button = arg1
462  
463 -- To enable click-casting on this frame, all anyone has to do is
464 -- set PerfectRaidCustomClick
465  
466 if PerfectRaidCustomClick then
467 PerfectRaidCustomClick(arg1, unit)
468 else
469 if not UnitExists(unit) then return end
470  
471 if SpellIsTargeting() then
472 if button == "LeftButton" then SpellTargetUnit(unit)
473 elseif button == "RightButton" then SpellStopTargeting() end
474 return
475 end
476  
477 if CursorHasItem() then
478 if button == "LeftButton" then
479 if unit=="player" then AutoEquipCursorItem()
480 else DropItemOnUnit(unit) end
481 else PutItemInBackpack() end
482 return
483 end
484  
485 TargetUnit(unit)
486 end
487 end,
488  
489 --[[---------------------------------------------------------------------------------
490 Options handlers
491 ------------------------------------------------------------------------------------]]
492  
493 -- Type is optional and defaults to the current sort type
494 Sort = function(self, msg, force)
495 if GetNumRaidMembers() == 0 then return end
496  
497 -- Clear the sort table
498 for k,v in pairs(sort) do sort[k] = nil table.setn(sort, 0) end
499  
500 -- Insert all the active raid ids in the table
501 for k in visible do
502 table.insert(sort, k)
503 if not UnitName(k) then return end
504 end
505  
506 msg = msg or self.opt.Sort
507 msg = string.lower(msg)
508  
509 -- Sort the table based on criteria
510 if msg == "class" then
511 if not force then self:Msg("Sorting by Class.") end
512 table.sort(sort, function(a,b)
513 keys[a] = UnitClass(a)
514 keys[b] = UnitClass(b)
515 if UnitClass(a) == UnitClass(b) then
516 return UnitName(a) < UnitName(b)
517 else
518 return UnitClass(a) < UnitClass(b)
519 end end)
520  
521 elseif msg == "raid" then
522 if not force then self:Msg("Sorting by Raid.") end
523 -- We don't need to sort if we're sorting raid, since we're in order
524  
525 elseif msg == "name" then
526 if not force then self:Msg("Sorting by Name.") end
527 table.sort(sort, function(a,b) return UnitName(a) < UnitName(b) end)
528  
529 elseif msg == "group" then
530 if not force then self:Msg("Sorting by Group.") end
531 local sortGroup = function(a,b)
532 local _,_,groupA = GetRaidRosterInfo(self.frames[a].id)
533 local _,_,groupB = GetRaidRosterInfo(self.frames[b].id)
534 keys[a] = groupA
535 keys[b] = groupB
536 return groupA < groupB
537 end
538 table.sort(sort, sortGroup)
539  
540 elseif msg == "groupclass" then
541 if not force then self:Msg("Sorting by Group/Class.") end
542 local sortGroupName = function(a,b)
543 local _,_,groupA = GetRaidRosterInfo(self.frames[a].id)
544 local _,_,groupB = GetRaidRosterInfo(self.frames[b].id)
545 keys[a] = groupA
546 keys[b] = groupB
547 if groupA == groupB then
548 return UnitClass(a) < UnitClass(b)
549 else
550 return groupA < groupB
551 end
552 end
553 table.sort(sort, sortGroupName)
554 end
555  
556 self:SetOpt("Sort", msg)
557  
558 -- We need to ensure that all the frames we need exist at this point
559 local f = self.frames[sort[1]]
560 f:ClearAllPoints()
561 f:SetPoint("TOPLEFT", PerfectRaidFrame, "TOPLEFT", 0, 0)
562 local last = f
563  
564 local vfont = self.virtualfont
565 local truncate = self.opt.Truncate
566 local length
567  
568 if truncate then
569 vfont:SetText("Spartikus")
570 length = vfont:GetStringWidth()
571 else
572 length = f.Name:GetStringWidth()
573 end
574  
575 local seperator = self.opt.Voffset
576 local seperate, voffset = nil, 0
577 if msg == "group" or msg == "groupclass" or msg == "class" then
578 seperate = true
579 end
580  
581 for i=2,table.getn(sort) do
582 local v = sort[i]
583 local f = frames[v]
584  
585 if seperate then
586 if keys[v] ~= keys[last.unit] then
587 voffset = seperator
588 else
589 voffset = 0
590 end
591 else
592 voffset = 0
593 end
594  
595 if not truncate then
596 vfont:SetText(UnitName(v))
597 local len = vfont:GetStringWidth()
598 if len > length then length = len end
599 end
600  
601 f:ClearAllPoints()
602 f:SetPoint("TOPLEFT", last, "BOTTOMLEFT", 0, voffset)
603 last = self.frames[v]
604 end
605  
606 for k,v in visible do
607 local f = frames[k]
608 f.Name:SetWidth(length + 5)
609 end
610 end,
611  
612 Select = function(self, msg, force)
613 if GetNumRaidMembers() == 0 then return end
614  
615 local _,type,sub
616  
617 if msg then
618 _,_,type,sub = string.find(msg, "(%w+)%s*(%w*)")
619 else
620 type = self.opt.Select
621 sub = self.opt.SelectSub
622 end
623  
624 if sub then sub = string.upper(sub) end
625 local num = tonumber(sub)
626  
627 if self.opt.Align == "right" then
628 self.mark = "<"
629 self.ttmark = "<<"
630 else
631 self.mark = ">"
632 self.ttmark = ">>"
633 end
634  
635 if type == "group" and num then
636 if not force then self:Msg("Selecting group #" .. num.. ".") end
637 for k,v in pairs(visible) do
638 local _,_,g = GetRaidRosterInfo(self.frames[k].id)
639 selected[k] = (g == num)
640 end
641 elseif type == "class" and PERFECTRAID.CLASSES[sub] then
642 if not force then self:Msg("Selecting by class: " .. string.upper(string.sub(sub,1,1)) .. string.lower(string.sub(sub,2,-1)) .. ".") end
643 for k,v in pairs(visible) do
644 local _,class = UnitClass(k)
645 selected[k] = (class == sub)
646 end
647 elseif type == "all" then
648 if not force then self:Msg("Selecting all raid members.") end
649 for k,v in pairs(visible) do
650 selected[k] = true
651 end
652 elseif type == "none" then
653 if not force then self:Msg("Selecting nothing.") end
654 for k,v in pairs(visible) do
655 selected[k] = false
656 end
657 elseif type == "number" then
658 if not force then self:Msg("Showing group numbers.") end
659 for k,v in pairs(visible) do
660 local num = self.frames[k].id
661 local _,_,g = GetRaidRosterInfo(num)
662 self.frames[k].group = g
663 self.frames[k].Prefix:SetText(g)
664 selected[k] = true
665 self:SetOpt("Select", type)
666 end
667 return
668 end
669  
670 self:SetOpt("Select", type)
671 if sub then self:SetOpt("SelectSub", sub) end
672  
673 for k,v in pairs(selected) do
674 local f = self.frames[k]
675 f.marked = v
676  
677 -- Change the direction of the mark if we're facing right
678 if v then
679 f.Prefix:SetText(self.mark)
680 else
681 f.Prefix:SetText("")
682 end
683 end
684 end,
685  
686 Show = function(self)
687 if self.master then self.master:Show() end
688 end,
689  
690 Hide = function(self)
691 if self.master then self.master:Hide() end
692 end,
693  
694 Reset = function(self)
695 self:Msg("Resetting all settings to defaults.")
696  
697 local f = self.master
698  
699 f:ClearAllPoints()
700 f:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
701 f:Show()
702  
703 for k,v in pairs(self.opt) do
704 self.opt[k] = nil
705 end
706  
707 self:UpdateVisibility()
708 self:SavePosition()
709 end,
710  
711 Align = function(self, msg, force)
712 msg = msg or self.opt.Align
713 msg = string.lower(msg)
714 local justify, point, relative, offset
715  
716 if msg == "left" then
717 if not force then self:Msg("Aligning frames to the left.") end
718 justify = "RIGHT"
719 point = "LEFT"
720 relative = "RIGHT"
721 offset = 5
722  
723 elseif msg == "right" then
724 if not force then self:Msg("Aligning frames to the right.") end
725 justify = "LEFT"
726 point = "RIGHT"
727 relative = "LEFT"
728 offset = -5
729 end
730  
731 for i,f in ipairs(self.frames) do
732 f.Prefix:ClearAllPoints()
733 f.Name:ClearAllPoints()
734 f.Bar:ClearAllPoints()
735 f.Status:ClearAllPoints()
736  
737 -- Prefix gets "LEFT, LEFT" or "RIGHT, RIGHT" since its always on the edge
738 f.Prefix:SetPoint(point, f, point, 0, 0)
739 f.Name:SetPoint(point, f.Prefix, relative, 0, 0)
740 f.Name:SetJustifyH(justify)
741 f.Bar:SetPoint(point, f.Name, relative, offset, 0)
742 f.Status:SetPoint(point, f.Bar, relative, offset, 0)
743 f.Status:SetJustifyH(justify)
744 end
745  
746 -- Refresh the selection
747 self:SetOpt("Align", msg)
748 self:Select(nil, true)
749 end,
750  
751 SetBackdrop = function(self, msg, force)
752 if not msg then
753 self:SetBackdrop(self.opt.BackdropBar, true)
754 self:SetBackdrop(self.opt.BackdropFrame, true)
755 return
756 end
757  
758 msg = string.lower(msg)
759 local _,_,type,r,g,b,a = string.find(msg, "(%a+)%s*(%d*%.?%d*)%s*(%d*%.?%d*)%s*(%d*%.?%d*)%s*(%d*%.?%d*)")
760 r,g,b,a = r or 0, g or 0, b or 0, a or 0
761  
762 if type == "bar" then
763 self:SetOpt("BackdropBar", msg)
764 for k,v in visible do
765 local f = frames[k]
766 f.Bar:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",
767 tile = true, tileSize = 32,
768 insets = { left = 0, right = 0, top = 0, bottom = 0 }});
769 f.Bar:SetBackdropColor(r,g,b,a)
770 end
771 elseif type == "frame" then
772 self:SetOpt("BackdropFrame", msg)
773 for k,v in visible do
774 local f = frames[k]
775 f:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",
776 tile = true, tileSize = 32,
777 insets = { left = 0, right = 0, top = 0, bottom = 0 }});
778 f:SetBackdropColor(r,g,b,a)
779 end
780 else
781 self:Msg("Usage is /praid [bar|frame] r g b a.")
782 return
783 end
784  
785 if not force then self:Msg("Setting backdrop for %s to %s, %s, %s, %s.", type, r, g, b, a) end
786 end,
787  
788 Truncate = function(self)
789 if self.opt.Truncate then
790 self:Msg("Truncate names is |cFF00FF00Off|r.")
791 self:SetOpt("Truncate", false)
792 else
793 self:Msg("Truncate names is |cFF00FF00On|r.")
794 self:SetOpt("Truncate", true)
795 end
796 self:UpdateVisibility()
797 end,
798  
799 SetLowMana = function(self, msg)
800 if not msg then
801 self:Msg("/praid manathreshold takes a number 0-100 as its only option.")
802 return
803 end
804  
805 local num = tonumber(msg)
806 if num and (num >= 0 and num <= 100) then
807 self:SetOpt("LowMana", num)
808 self:Msg("Setting the low mana threshold to %d", num)
809 end
810 end,
811  
812 SetScale = function(self, msg, force)
813 if force then msg = self.opt.Scale end
814  
815 if not msg then
816 self:Msg("/praid scale takes a number from 0-2.")
817 return
818 end
819  
820 local num = tonumber(msg)
821 if num and (num > 0 and num < 2) then
822 self:SetOpt("Scale", num)
823 self.master:SetScale(num)
824 if not force then self:Msg("Setting the scale to %d", num) end
825 end
826 end,
827  
828 SetVoffset = function(self, msg)
829 if not msg then msg = self.opt.Voffset end
830  
831 if not msg then
832 self:Msg("/praid scale takes any number greater than 0.")
833 return
834 end
835  
836 self:Msg("Setting the vertical offset to %s.", msg)
837  
838 local num = tonumber(msg)
839 self:SetOpt("Voffset", num)
840  
841 self:UpdateVisibility()
842 end,
843  
844 SortNeed = function(self, msg)
845  
846 end,
847  
848 ToggleFilter = function(self)
849 if self.opt.Filter then
850 self:Msg("Debuff filter is |cFF00FF00Off|r.")
851 self:SetOpt("Filter", false)
852 else
853 self:Msg("Debuff filter is |cFF00FF00On|r.")
854 self:SetOpt("Filter", true)
855 end
856 self:UpdateVisibility()
857 end,
858  
859 ToggleRangeCheck = function(self)
860 if self.opt.RangeCheck then
861 self:Msg("Range checking is |cFF00FF00Off|r.")
862 self:SetOpt("RangeCheck", false)
863 for k,v in visible do
864 frames[k]:SetAlpha(1.0)
865 end
866 else
867 self:Msg("Range checking is |cFF00FF00On|r.")
868 self:SetOpt("RangeCheck", true)
869 end
870  
871 self:RangeHooks()
872 end,
873  
874 --[[---------------------------------------------------------------------------------
875 Utility functions
876 ------------------------------------------------------------------------------------]]
877  
878 -- Type is stored in TextRight1
879 --local type = PerfectRaidTooltipTextRight1:GetText()
880  
881 CreateFrame = function(self, num)
882 -- We need to allocate up to num frames
883  
884 if self.poolsize >= num then return end
885  
886 --[[
887 local mem,thr = gcinfo()
888 self:Msg("Memory Usage Before: %s [%s].", mem, thr)
889 --]]
890 local side = self.opt.Align
891  
892 local justify,point,relative,offset
893  
894 if side == "left" then
895 justify = "RIGHT"
896 point = "LEFT"
897 relative = "RIGHT"
898 offset = 5
899 elseif side == "right" then
900 justify = "LEFT"
901 point = "RIGHT"
902 relative = "LEFT"
903 offset = -5
904 end
905  
906 for i=(self.poolsize + 1),num do
907 local frame = CreateFrame("Button", nil, PerfectRaidFrame)
908 frame:EnableMouse(true)
909 frame.unit = "raid"..i
910 frame.id = i
911 frame:SetWidth(225)
912 frame:SetHeight(13)
913 frame:SetMovable(true)
914 frame:RegisterForDrag("LeftButton")
915 frame:SetScript("OnDragStart", function() self["master"]:StartMoving() end)
916 frame:SetScript("OnDragStop", function() self["master"]:StopMovingOrSizing() self:SavePosition() end)
917 frame:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp", "Button4Up", "Button5Up")
918 frame:SetScript("OnClick", self.OnClick)
919 frame:SetParent(self.master)
920  
921 local font = frame:CreateFontString(nil, "ARTWORK")
922 font:SetFontObject(GameFontHighlightSmall)
923 font:SetText("WW")
924 font:SetJustifyH("CENTER")
925 font:SetWidth(font:GetStringWidth())
926 font:SetHeight(14)
927 font:Show()
928 font:ClearAllPoints()
929 font:SetPoint(point, frame, relative,0, 0)
930 -- Add this font string to the frame
931 frame.Prefix = font
932  
933 font = frame:CreateFontString(nil, "ARTWORK")
934 font:SetFontObject(GameFontHighlightSmall)
935 font:SetText()
936 font:SetJustifyH(justify)
937 font:SetWidth(55)
938 font:SetHeight(12)
939 font:Show()
940 font:ClearAllPoints()
941 font:SetPoint(point, frame.Prefix, relative, offset, 0)
942 -- Add this font string to the frame
943 frame.Name = font
944  
945 local bar = CreateFrame("StatusBar", nil, frame)
946 bar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
947 bar:SetMinMaxValues(0,100)
948 bar:ClearAllPoints()
949 bar:SetPoint(point, frame.Name, relative, offset, 0)
950 bar:SetWidth(60)
951 bar:SetHeight(7)
952 bar:Show()
953 -- Add this status bar to the frame
954 frame.Bar = bar
955  
956 font = frame:CreateFontString(nil, "ARTWORK")
957 font:SetFontObject(GameFontHighlightSmall)
958 font:SetText("")
959 font:SetJustifyH(justify)
960 font:SetWidth(font:GetStringWidth())
961 font:SetHeight(12)
962 font:Show()
963 font:ClearAllPoints()
964 font:SetPoint(point, frame.Bar, relative, offset, 0)
965 -- Add this font string to the frame
966 frame.Status = font
967  
968 -- Lets set the frame in the indexed array
969 frames[i] = frame
970 frames["raid"..i] = frame
971 self.poolsize = i
972 end
973  
974 mem2,thr2 = gcinfo()
975 --[[
976 self:Msg("Memory Usage After: %s [%s].", mem2, thr2)
977 self:Msg("Frame creation change: %s [%s].", mem2 - mem, thr2 - thr)
978 --]]
979 end,
980  
981 GetHPSeverity = function(self, percent,smooth)
982 if (percent<=0 or percent>1.0) then return 0.35,0.35,0.35 end
983  
984 if smooth then
985 if (percent >= 0.5) then
986 return (1.0-percent)*2, 1.0, 0.0
987 else
988 return 1.0, percent*2, 0.0
989 end
990 else
991 return 0,1,0
992 end
993 end,
994  
995 SavePosition = function(self)
996 local f = self.master
997 local x,y = f:GetLeft(), f:GetTop()
998 local s = f:GetEffectiveScale()
999  
1000 x,y = x*s,y*s
1001  
1002 self:SetOpt("PosX", x)
1003 self:SetOpt("PosY", y)
1004 end,
1005  
1006 RestorePosition = function(self)
1007 local x = self.opt.PosX
1008 local y = self.opt.PosY
1009  
1010 if not x or not y then return end
1011  
1012 local f = PerfectRaidFrame
1013 local s = f:GetEffectiveScale()
1014  
1015 x,y = x/s,y/s
1016  
1017 f:ClearAllPoints()
1018 f:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
1019 end,
1020  
1021 RegisterEvent = function(self, event)
1022 registry[event] = event
1023 self.master:RegisterEvent(event)
1024 end,
1025  
1026 UnregisterEvent = function(self, event)
1027 registry[event] = nil
1028 self.master:UnregisterEvent(event)
1029 end,
1030  
1031 UnregisterAllEvents = function(self)
1032 for k,v in pairs(registry) do
1033 registry[k] = nil
1034 self.master:UnregisterEvent(k)
1035 end
1036 end,
1037  
1038 EventHandler = function()
1039 local self = PerfectRaid
1040 if registry[event] then
1041 if self[event] then
1042 self[event](self)
1043 end
1044 end
1045 end,
1046  
1047 Msg = function(self,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9)
1048 if not msg then return end
1049 local output
1050 if a1 then output = string.format(msg,a1,a2,a3,a4,a5,a6,a7,a8,a9) end
1051 DEFAULT_CHAT_FRAME:AddMessage(string.format("|cffffff78PerfectRaid:|r %s", output or msg))
1052 end,
1053  
1054 Debug = function(self,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9)
1055 if not msg or not debug then return end
1056 local output
1057 if a1 then output = string.format(msg,a1,a2,a3,a4,a5,a6,a7,a8,a9) end
1058 DEFAULT_CHAT_FRAME:AddMessage(string.format("|cFF00E6C6PerfectRaid:|r %s", output or msg))
1059 end,
1060  
1061 Test = function(self, command, args)
1062 self:Msg("Test Command: %s Args: %s.", tostring(command), tostring(args))
1063 end,
1064  
1065 SortNeed = function(self, command, args)
1066 self:Msg("SortNeed Command: %s Args: %s.", tostring(command), tostring(args))
1067 end,
1068 }
1069  
1070 PerfectRaid:Initialize()
1071 p = PerfectRaid