vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | --[[--------------------------------------------------------------------------------- |
2 | Detox |
||
3 | written by Maia/Proudmoore, |
||
4 | code based on the Decursive 1.9.7 core code by Archarodim and Quu. |
||
5 | The name 'Detox' was provided by Tem. |
||
6 | ------------------------------------------------------------------------------------]] |
||
7 | |||
8 | local vmajor,vminor = "0.4", tonumber(string.sub("$Revision: 12266 $", 12, -3)) |
||
9 | |||
10 | --[[--------------------------------------------------------------------------------- |
||
11 | locals |
||
12 | ------------------------------------------------------------------------------------]] |
||
13 | |||
14 | local compost = AceLibrary("Compost-2.0") |
||
15 | local L = AceLibrary("AceLocale-2.0"):new("Detox") |
||
16 | local BS = AceLibrary("Babble-Spell-2.0") |
||
17 | local BC = AceLibrary("Babble-Class-2.0") |
||
18 | local tablet = AceLibrary("Tablet-2.0") |
||
19 | local aura = nil -- AceLibrary("SpecialEvents-Aura-2.0") |
||
20 | local RL = nil -- AceLibrary("RosterLib-2.0") |
||
21 | |||
22 | local last_DemonType = nil |
||
23 | local curr_DemonType = nil |
||
24 | local castTarget = nil |
||
25 | local soundPlayed = false |
||
26 | local hasSpells = false |
||
27 | local blacklist = {} |
||
28 | local outofrange = {} |
||
29 | local spells = {} -- will be filled with available spells |
||
30 | local priorityIndex = {} -- this table references name to index of the priority table |
||
31 | local priority = {} -- this integer keyed table will hold subtables containing name, unitid and priority for each unit in our roster |
||
32 | |||
33 | local DebuffTypeColor = {} |
||
34 | DebuffTypeColor["none"] = { r = 0.80, g = 0, b = 0 } |
||
35 | DebuffTypeColor["Magic"] = { r = 0.20, g = 0.60, b = 1.00 } |
||
36 | DebuffTypeColor["Curse"] = { r = 0.60, g = 0.00, b = 1.00 } |
||
37 | DebuffTypeColor["Disease"] = { r = 0.60, g = 0.40, b = 0 } |
||
38 | DebuffTypeColor["Poison"] = { r = 0.00, g = 0.60, b = 0 } |
||
39 | |||
40 | local invisible = { |
||
41 | [BS["Prowl"]] = true, |
||
42 | [BS["Stealth"]] = true, |
||
43 | [BS["Shadowmeld"]] = true, |
||
44 | } |
||
45 | |||
46 | local ignore = { |
||
47 | [BS["Banish"]] = true, |
||
48 | [BS["Phase Shift"]] = true, |
||
49 | [L["Frost Trap Aura"]] = true, |
||
50 | } |
||
51 | |||
52 | local skip = { |
||
53 | [L["Dreamless Sleep"]] = true, |
||
54 | [L["Greater Dreamless Sleep"]] = true, |
||
55 | } |
||
56 | |||
57 | local cleaningSpells = { |
||
58 | [BS["Cure Disease"]] = true, |
||
59 | [BS["Abolish Disease"]] = true, |
||
60 | [BS["Purify"]] = true, |
||
61 | [BS["Cleanse"]] = true, |
||
62 | [BS["Dispel Magic"]] = true, |
||
63 | [BS["Cure Poison"]] = true, |
||
64 | [BS["Abolish Poison"]] = true, |
||
65 | [BS["Remove Lesser Curse"]] = true, |
||
66 | [BS["Remove Curse"]] = true, |
||
67 | [BS["Purge"]] = true, |
||
68 | [BS["Devour Magic"]] = true, |
||
69 | [BS["Stoneform"]] = true, |
||
70 | } |
||
71 | |||
72 | BINDING_HEADER_DETOX = "Detox" |
||
73 | BINDING_NAME_CLEAN = L["Clean group"] |
||
74 | BINDING_NAME_PRIORITYTOGGLE = L["Toggle target priority"] |
||
75 | BINDING_NAME_PRIORITYTOGGLEGROUP = L["Toggle target group priority"] |
||
76 | BINDING_NAME_PRIORITYTOGGLECLASS = L["Toggle target class priority"] |
||
77 | |||
78 | --[[--------------------------------------------------------------------------------- |
||
79 | defaults and AceOptions table |
||
80 | ------------------------------------------------------------------------------------]] |
||
81 | |||
82 | local defaults = { |
||
83 | showPriorities = true, |
||
84 | ignoreStealthed = true, |
||
85 | blacklistTime = 5, |
||
86 | checkAbolish = true, |
||
87 | ignorePets = false, |
||
88 | liveDisplay = 5, |
||
89 | filter = true, |
||
90 | range = true, |
||
91 | sound = true, |
||
92 | feedback = true, |
||
93 | updateSpeed = 0.5, |
||
94 | priorityNames = {}, |
||
95 | priorityGroups = {}, |
||
96 | priorityClasses = {}, |
||
97 | debuffsInSkipList = { |
||
98 | BS["Silence"], |
||
99 | L["Ancient Hysteria"], |
||
100 | L["Ignite Mana"], |
||
101 | L["Tainted Mind"], |
||
102 | L["Magma Shackles"], |
||
103 | L["Cripple"], |
||
104 | L["Dust Cloud"], |
||
105 | L["Widow's Embrace"], |
||
106 | L["Curse of Tongues"], |
||
107 | L["Sonic Burst"], |
||
108 | L["Thunderclap"], |
||
109 | L["Delusions of Jin'do"] |
||
110 | }, |
||
111 | skipByClass = { |
||
112 | ["WARRIOR"] = { |
||
113 | [L["Ancient Hysteria"]] = true, |
||
114 | [L["Ignite Mana"]] = true, |
||
115 | [L["Tainted Mind"]] = true, |
||
116 | [L["Widow's Embrace"]] = true, |
||
117 | [L["Curse of Tongues"]] = true, |
||
118 | [L["Delusions of Jin'do"]]= true, |
||
119 | }, |
||
120 | ["ROGUE"] = { |
||
121 | [BS["Silence"]] = true, |
||
122 | [L["Ancient Hysteria"]] = true, |
||
123 | [L["Ignite Mana"]] = true, |
||
124 | [L["Tainted Mind"]] = true, |
||
125 | [L["Widow's Embrace"]] = true, |
||
126 | [L["Curse of Tongues"]] = true, |
||
127 | [L["Sonic Burst"]] = true, |
||
128 | [L["Delusions of Jin'do"]]= true, |
||
129 | }, |
||
130 | ["HUNTER"] = { |
||
131 | [L["Magma Shackles"]] = true, |
||
132 | [L["Delusions of Jin'do"]]= true, |
||
133 | }, |
||
134 | ["MAGE"] = { |
||
135 | [L["Magma Shackles"]] = true, |
||
136 | [L["Cripple"]] = true, |
||
137 | [L["Dust Cloud"]] = true, |
||
138 | [L["Thunderclap"]] = true, |
||
139 | [L["Delusions of Jin'do"]]= true, |
||
140 | }, |
||
141 | ["WARLOCK"] = { |
||
142 | [L["Cripple"]] = true, |
||
143 | [L["Dust Cloud"]] = true, |
||
144 | [L["Thunderclap"]] = true, |
||
145 | [L["Delusions of Jin'do"]]= true, |
||
146 | }, |
||
147 | ["DRUID"] = { |
||
148 | [L["Cripple"]] = true, |
||
149 | [L["Dust Cloud"]] = true, |
||
150 | [L["Thunderclap"]] = true, |
||
151 | [L["Delusions of Jin'do"]]= true, |
||
152 | }, |
||
153 | ["PALADIN"] = { |
||
154 | [L["Cripple"]] = true, |
||
155 | [L["Dust Cloud"]] = true, |
||
156 | [L["Delusions of Jin'do"]]= true, |
||
157 | }, |
||
158 | ["PRIEST"] = { |
||
159 | [L["Cripple"]] = true, |
||
160 | [L["Dust Cloud"]] = true, |
||
161 | [L["Thunderclap"]] = true, |
||
162 | [L["Delusions of Jin'do"]]= true, |
||
163 | }, |
||
164 | ["SHAMAN"] = { |
||
165 | [L["Cripple"]] = true, |
||
166 | [L["Dust Cloud"]] = true, |
||
167 | [L["Delusions of Jin'do"]]= true, |
||
168 | } |
||
169 | } |
||
170 | } |
||
171 | |||
172 | local options = { |
||
173 | type = 'group', |
||
174 | args = { |
||
175 | clean = { |
||
176 | type = 'execute', |
||
177 | name = L["Clean group"], |
||
178 | desc = L["Will attempt to clean a player in your raid/party."], |
||
179 | func = function() |
||
180 | Detox:Clean() |
||
181 | end, |
||
182 | order = 101, |
||
183 | }, |
||
184 | spacer = { type = "header", order = 102 }, |
||
185 | livelistoptions = { |
||
186 | type = 'group', |
||
187 | name = L["Live list"], |
||
188 | desc = L["Options for the live list."], |
||
189 | order = 110, |
||
190 | args = { |
||
191 | show = { |
||
192 | type = 'toggle', |
||
193 | name = L["Show live list"], |
||
194 | desc = L["Detaches the live list from the Detox icon."], |
||
195 | get = function() return Detox:IsTooltipDetached() end, |
||
196 | set = function() Detox:ToggleTooltipDetached() end, |
||
197 | order = 100 |
||
198 | }, |
||
199 | sound = { |
||
200 | type = 'toggle', |
||
201 | name = L["Play sound if unit needs decursing"], |
||
202 | desc = L["Play sound if unit needs decursing"]..".", |
||
203 | get = function() return Detox.db.profile.sound end, |
||
204 | set = function() |
||
205 | Detox.db.profile.sound = not Detox.db.profile.sound |
||
206 | end, |
||
207 | order = 101 |
||
208 | }, |
||
209 | showpriorizations = { |
||
210 | type = 'toggle', |
||
211 | name = L["Show priorities"], |
||
212 | desc = L["Displays who is prioritized in the live list."], |
||
213 | get = function() return Detox.db.profile.showPriorities end, |
||
214 | set = function() Detox.db.profile.showPriorities = not Detox.db.profile.showPriorities end, |
||
215 | order = 102, |
||
216 | }, |
||
217 | live = { |
||
218 | type = 'range', |
||
219 | name = L["Max debuffs shown"], |
||
220 | desc = L["Defines the max number of debuffs to display in the live list."], |
||
221 | get = function() return Detox.db.profile.liveDisplay end, |
||
222 | set = function(v) |
||
223 | Detox.db.profile.liveDisplay = v |
||
224 | end, |
||
225 | min = 0, |
||
226 | max = 20, |
||
227 | step = 1, |
||
228 | isPercent = false, |
||
229 | order = 103, |
||
230 | }, |
||
231 | speed = { |
||
232 | type = 'range', |
||
233 | name = L["Update speed"], |
||
234 | desc = L["Defines the speed the live list is updated, in seconds."], |
||
235 | get = function() return Detox.db.profile.updateSpeed end, |
||
236 | set = function(v) |
||
237 | Detox.db.profile.updateSpeed = v |
||
238 | Detox:CancelScheduledEvent("liveList") |
||
239 | Detox:ScheduleRepeatingEvent("liveList", Detox.Update, v, Detox) |
||
240 | end, |
||
241 | min = 0.2, |
||
242 | max = 2, |
||
243 | step = 0.1, |
||
244 | isPercent = false, |
||
245 | order = 104, |
||
246 | }, |
||
247 | }, |
||
248 | }, |
||
249 | priority = { |
||
250 | type = 'group', |
||
251 | name = L["Priority"], |
||
252 | desc = L["These units will be priorized when curing."], |
||
253 | order = 120, |
||
254 | args = {} |
||
255 | }, |
||
256 | filter = { |
||
257 | type = 'group', |
||
258 | name = L["Filter"], |
||
259 | desc = L["Options for filtering various debuffs and conditions."], |
||
260 | order = 130, |
||
261 | args = { |
||
262 | filter = { |
||
263 | type = 'toggle', |
||
264 | name = L["Filter by type"], |
||
265 | desc = L["Only show debuffs you can cure."], |
||
266 | get = function() return Detox.db.profile.filter end, |
||
267 | set = function() |
||
268 | Detox.db.profile.filter = not Detox.db.profile.filter |
||
269 | end, |
||
270 | order = 103, |
||
271 | }, |
||
272 | range = { |
||
273 | type = 'toggle', |
||
274 | name = L["Filter by range"], |
||
275 | desc = L["Only show units in range."], |
||
276 | get = function() return Detox.db.profile.range end, |
||
277 | set = function() |
||
278 | Detox.db.profile.range = not Detox.db.profile.range |
||
279 | end, |
||
280 | order = 104 |
||
281 | }, |
||
282 | stealth = { |
||
283 | type = 'toggle', |
||
284 | name = L["Filter stealthed units"], |
||
285 | desc = L["It is recommended not to cure stealthed units."], |
||
286 | get = function() return Detox.db.profile.ignoreStealthed end, |
||
287 | set = function() |
||
288 | Detox.db.profile.ignoreStealthed = not Detox.db.profile.ignoreStealthed |
||
289 | end, |
||
290 | order = 105 |
||
291 | }, |
||
292 | abolish = { |
||
293 | type = 'toggle', |
||
294 | name = L["Filter Abolished units"], |
||
295 | desc = L["Skip units that have an active Abolish buff."], |
||
296 | get = function() return Detox.db.profile.checkAbolish end, |
||
297 | set = function() |
||
298 | Detox.db.profile.checkAbolish = not Detox.db.profile.checkAbolish |
||
299 | end, |
||
300 | order = 106 |
||
301 | }, |
||
302 | pets = { |
||
303 | type = 'toggle', |
||
304 | name = L["Filter pets"], |
||
305 | desc = L["Pets are also your friends."], |
||
306 | get = function() return Detox.db.profile.ignorePets end, |
||
307 | set = function() |
||
308 | Detox.db.profile.ignorePets = not Detox.db.profile.ignorePets |
||
309 | Detox:UpdatePriority() |
||
310 | end, |
||
311 | order = 107 |
||
312 | }, |
||
313 | debuff = { |
||
314 | type = 'group', |
||
315 | name = L["Debuff"], |
||
316 | desc = L["Filter by debuff and class."], |
||
317 | order = 400, |
||
318 | args = {} |
||
319 | }, |
||
320 | }, |
||
321 | }, |
||
322 | blacklist = { |
||
323 | type = 'range', |
||
324 | name = L["Seconds to blacklist"], |
||
325 | desc = L["Units that are out of Line of Sight will be blacklisted for the set duration."], |
||
326 | get = function() return Detox.db.profile.blacklistTime end, |
||
327 | set = function(v) |
||
328 | Detox.db.profile.blacklistTime = v |
||
329 | end, |
||
330 | min = 1, |
||
331 | max = 20, |
||
332 | step = 1, |
||
333 | isPercent = false, |
||
334 | order = 140 |
||
335 | }, |
||
336 | feedback = { |
||
337 | type = 'toggle', |
||
338 | name = L["Show detoxing in scrolling combat frame"], |
||
339 | desc = L["This will use SCT5 when available, otherwise Blizzards Floating Combat Text."], |
||
340 | get = function() return Detox.db.profile.feedback end, |
||
341 | set = function() |
||
342 | Detox.db.profile.feedback = not Detox.db.profile.feedback |
||
343 | end, |
||
344 | order = 150 |
||
345 | }, |
||
346 | }, |
||
347 | } |
||
348 | |||
349 | --[[--------------------------------------------------------------------------------- |
||
350 | Initialization |
||
351 | ------------------------------------------------------------------------------------]] |
||
352 | |||
353 | Detox = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceDB-2.0", "AceConsole-2.0", "AceDebug-2.0", "FuBarPlugin-2.0") |
||
354 | |||
355 | -- stuff for FuBar: |
||
356 | Detox.hasIcon = true |
||
357 | Detox.defaultPosition = "LEFT" |
||
358 | Detox.defaultMinimapPosition = 250 |
||
359 | Detox.cannotDetachTooltip = false |
||
360 | Detox.tooltipHiddenWhenEmpty = true |
||
361 | Detox.hideWithoutStandby = true |
||
362 | Detox.clickableTooltip = true |
||
363 | Detox.independentProfile = true |
||
364 | |||
365 | function Detox:OnInitialize() |
||
366 | self:RegisterDB("DetoxDB") |
||
367 | self:RegisterDefaults('profile', defaults ) |
||
368 | self:RegisterChatCommand({'/detox'}, options ) |
||
369 | self.OnMenuRequest = options |
||
370 | self.OnMenuRequest.args.lockTooltip.hidden = true |
||
371 | self.OnMenuRequest.args.detachTooltip.hidden = true |
||
372 | if not FuBar then |
||
373 | self.OnMenuRequest.args.hide.guiName = "Hide minimap icon" |
||
374 | self.OnMenuRequest.args.hide.desc = "Hide minimap icon" |
||
375 | end |
||
376 | end |
||
377 | |||
378 | |||
379 | function Detox:OnEnable() |
||
380 | if not aura then aura = AceLibrary("SpecialEvents-Aura-2.0") end |
||
381 | if not RL then RL = AceLibrary("RosterLib-2.0") end |
||
382 | |||
383 | self:RegisterEvent("SPELLCAST_STOP") |
||
384 | self:RegisterEvent("UNIT_PET",1) |
||
385 | self:RegisterEvent("SPELLS_CHANGED","RescanSpellbook",1) |
||
386 | self:RegisterEvent("LEARNED_SPELL_IN_TAB","RescanSpellbook",1) |
||
387 | self:RegisterEvent("UI_ERROR_MESSAGE") |
||
388 | self:RegisterEvent("RosterLib_RosterChanged") |
||
389 | self:ParseSpellbook() |
||
390 | self:ScheduleRepeatingEvent(self.OnUpdate, 1, self) |
||
391 | self:ScheduleRepeatingEvent("liveList", self.Update, Detox.db.profile.updateSpeed or 0.5, self) -- this is the FuBar live list update! |
||
392 | self.debugging = self:IsDebugging() |
||
393 | self:PopulateSkipList() |
||
394 | end |
||
395 | |||
396 | |||
397 | function Detox:OnDisable() |
||
398 | local detached = self:IsTooltipDetached() |
||
399 | if detached then |
||
400 | self:ReattachTooltip() |
||
401 | self.db.profile.detachedTooltip.detached = true |
||
402 | end |
||
403 | end |
||
404 | |||
405 | |||
406 | function Detox:OnClick() -- FuBarPlugin |
||
407 | self:Clean() |
||
408 | end |
||
409 | |||
410 | function Detox:IsDebugging() return self.db.profile.debugging end |
||
411 | function Detox:SetDebugging(debugging) self.db.profile.debugging = debugging; self.debugging = debugging; end |
||
412 | |||
413 | --[[--------------------------------------------------------------------------------- |
||
414 | Events |
||
415 | ------------------------------------------------------------------------------------]] |
||
416 | |||
417 | function Detox:OnUpdate() |
||
418 | self:UpdateBlacklist() |
||
419 | end |
||
420 | |||
421 | |||
422 | function Detox:UpdateBlacklist() |
||
423 | for unit in pairs(blacklist) do |
||
424 | blacklist[unit] = blacklist[unit] - 1 |
||
425 | if blacklist[unit] < 0 then |
||
426 | blacklist[unit] = nil |
||
427 | end |
||
428 | end |
||
429 | end |
||
430 | |||
431 | |||
432 | function Detox:RosterLib_RosterChanged(tbl) |
||
433 | for name in pairs(tbl) do |
||
434 | local u = tbl[name] |
||
435 | if not u.name then -- someone left the raid |
||
436 | for i = table.getn(priority), 1, -1 do |
||
437 | if not RL.roster[priority[i].name] then |
||
438 | priorityIndex[priority[i].name] = nil |
||
439 | compost:Reclaim(priority[i]) |
||
440 | priority[i] = nil |
||
441 | table.remove(priority, i) |
||
442 | end |
||
443 | end |
||
444 | end |
||
445 | end |
||
446 | self:UpdatePriority() |
||
447 | end |
||
448 | |||
449 | |||
450 | function Detox:SPELLCAST_STOP() |
||
451 | castTarget = nil |
||
452 | end |
||
453 | |||
454 | |||
455 | function Detox:UNIT_PET(unit) |
||
456 | if unit == "player" then |
||
457 | self:ScheduleEvent(self.CheckPet, 2, self) |
||
458 | end |
||
459 | end |
||
460 | |||
461 | |||
462 | function Detox:UI_ERROR_MESSAGE(arg1) |
||
463 | if arg1 == SPELL_FAILED_LINE_OF_SIGHT then |
||
464 | if castTarget and not UnitIsUnit(castTarget, "player") then |
||
465 | blacklist[castTarget] = Detox.db.profile.blacklistTime |
||
466 | end |
||
467 | end |
||
468 | end |
||
469 | |||
470 | |||
471 | --[[--------------------------------------------------------------------------------- |
||
472 | Spellbook |
||
473 | ------------------------------------------------------------------------------------]] |
||
474 | |||
475 | |||
476 | function Detox:ParseSpellbook() |
||
477 | compost:Reclaim(spells,1) |
||
478 | spells = compost:Acquire() |
||
479 | hasSpells = false |
||
480 | local BookType = BOOKTYPE_SPELL |
||
481 | local break_flag = false |
||
482 | local i = 1 |
||
483 | local maxRankMagic = 0 |
||
484 | local maxRankEnemyMagic = 0 |
||
485 | while not break_flag do |
||
486 | while (true) do -- HUH? |
||
487 | local name, rank = GetSpellName(i, BookType) |
||
488 | if not name then |
||
489 | if BookType == BOOKTYPE_PET then |
||
490 | break_flag = true |
||
491 | break |
||
492 | end |
||
493 | BookType = BOOKTYPE_PET |
||
494 | i = 1 |
||
495 | break |
||
496 | end |
||
497 | if cleaningSpells[name] then |
||
498 | hasSpells = true |
||
499 | spells["cooldown"] = compost:Acquire(i, BookType) |
||
500 | if name == BS["Cure Disease"] or name == BS["Purify"] then |
||
501 | spells["disease1"] = compost:Acquire(i, BookType, name) |
||
502 | end |
||
503 | if name == BS["Abolish Disease"] or name == BS["Cleanse"] then |
||
504 | spells["disease2"] = compost:Acquire(i, BookType, name) |
||
505 | end |
||
506 | if name == BS["Cure Poison"] or name == BS["Purify"] then |
||
507 | spells["poison1"] = compost:Acquire(i, BookType, name) |
||
508 | end |
||
509 | if name == BS["Abolish Poison"] or name == BS["Cleanse"] then |
||
510 | spells["poison2"] = compost:Acquire(i, BookType, name) |
||
511 | end |
||
512 | if name == BS["Remove Curse"] or name == BS["Remove Lesser Curse"] then |
||
513 | spells["curse"] = compost:Acquire(i, BookType, name) |
||
514 | end |
||
515 | if name == BS["Stoneform"] then |
||
516 | spells["poison3"] = compost:Acquire(i, BookType, name) |
||
517 | end |
||
518 | if name == BS["Cleanse"] or name == BS["Dispel Magic"] or name == BS["Devour Magic"] then |
||
519 | if rank and string.find(rank, L["Rank (%d+)"]) then |
||
520 | local ranknum = string.gsub(rank, L["Rank (%d+)"], "%1") |
||
521 | if tonumber(ranknum) > maxRankMagic then |
||
522 | spells["magic"] = compost:Acquire(i, BookType, name) |
||
523 | maxRankMagic = tonumber(ranknum) |
||
524 | end |
||
525 | else |
||
526 | spells["magic"] = compost:Acquire(i, BookType, name) |
||
527 | end |
||
528 | end |
||
529 | if name == BS["Dispel Magic"] or name == BS["Purge"] or name == BS["Devour Magic"] then |
||
530 | if rank and string.find(rank, L["Rank (%d+)"]) then |
||
531 | local ranknum = string.gsub(rank, L["Rank (%d+)"], "%1") |
||
532 | if tonumber(ranknum) > maxRankEnemyMagic then |
||
533 | spells["enemymagic"] = compost:Acquire(i, BookType, name) |
||
534 | maxRankEnemyMagic = tonumber(ranknum) |
||
535 | end |
||
536 | else |
||
537 | spells["enemymagic"] = compost:Acquire(i, BookType, name) |
||
538 | end |
||
539 | end |
||
540 | end |
||
541 | i = i + 1 |
||
542 | end |
||
543 | end |
||
544 | end |
||
545 | |||
546 | |||
547 | function Detox:RescanSpellbook() |
||
548 | if not hasSpells then return end |
||
549 | local valid = true |
||
550 | for spell in pairs(spells) do |
||
551 | if GetSpellName(spells[spell][1], spells[spell][2]) ~= spells[spell][3] then |
||
552 | valid = false |
||
553 | end |
||
554 | end |
||
555 | if not valid then |
||
556 | self:ParseSpellbook() |
||
557 | end |
||
558 | end |
||
559 | |||
560 | |||
561 | function Detox:CheckPet() |
||
562 | curr_DemonType = UnitCreatureFamily("pet") |
||
563 | if last_DemonType ~= curr_DemonType then |
||
564 | last_DemonType = curr_DemonType |
||
565 | self:ParseSpellbook() |
||
566 | end |
||
567 | end |
||
568 | |||
569 | |||
570 | --[[--------------------------------------------------------------------------------- |
||
571 | Cleaning |
||
572 | ------------------------------------------------------------------------------------]] |
||
573 | |||
574 | |||
575 | function Detox:Clean() |
||
576 | if not hasSpells then |
||
577 | self:ParseSpellbook() |
||
578 | if not hasSpells then |
||
579 | return false |
||
580 | end |
||
581 | end |
||
582 | -- check for cooldown |
||
583 | local _, cooldown = GetSpellCooldown(spells["cooldown"][1], spells["cooldown"][2]) |
||
584 | if cooldown ~= 0 then |
||
585 | return false |
||
586 | end |
||
587 | -- temporarily disable selfcasting |
||
588 | local selfCast = GetCVar("autoSelfCast") |
||
589 | SetCVar("autoSelfCast", "0") |
||
590 | local cleanedType = nil |
||
591 | local cleanedName = nil |
||
592 | castTarget = nil |
||
593 | -- save original target |
||
594 | local targetIsEnemy = false |
||
595 | local targetFriendlyName = nil |
||
596 | if UnitExists("target") then |
||
597 | if UnitIsFriend("target","player") then |
||
598 | targetFriendlyName = UnitName("target") |
||
599 | else |
||
600 | targetIsEnemy = true |
||
601 | end |
||
602 | end |
||
603 | if SpellIsTargeting() then SpellStopTargeting() end |
||
604 | -- try to clean target first |
||
605 | if UnitExists("target") then |
||
606 | cleanedType = self:CureUnit("target") |
||
607 | if cleanedType then |
||
608 | cleanedName = UnitName("target") |
||
609 | end |
||
610 | end |
||
611 | -- couldn't clean target, check for MCd units |
||
612 | if not cleanedType and spells["enemymagic"] then |
||
613 | for k,v in ipairs(priority) do |
||
614 | if v.pri == 0 then break end |
||
615 | local unit = v.unitid |
||
616 | if UnitIsCharmed(unit) |
||
617 | and not blacklist[unit] then |
||
618 | cleanedType = self:CureUnit(unit) |
||
619 | if cleanedType then |
||
620 | cleanedName = UnitName(unit) |
||
621 | break |
||
622 | end |
||
623 | end |
||
624 | end |
||
625 | end |
||
626 | -- now do the rest (this is duplicated code, gah!) |
||
627 | if not cleanedType then |
||
628 | for k,v in ipairs(priority) do |
||
629 | if v.pri == 0 then break end |
||
630 | local unit = v.unitid |
||
631 | if not blacklist[unit] |
||
632 | and not UnitIsCharmed(unit) then |
||
633 | cleanedType = self:CureUnit(unit) |
||
634 | if cleanedType then |
||
635 | cleanedName = UnitName(unit) |
||
636 | break |
||
637 | end |
||
638 | end |
||
639 | end |
||
640 | end |
||
641 | -- now try blacklist |
||
642 | if not cleanedType then |
||
643 | for unit in pairs(blacklist) do |
||
644 | cleanedType = self:CureUnit(unit) |
||
645 | if cleanedType then |
||
646 | cleanedName = UnitName(unit) |
||
647 | blacklist[unit] = nil |
||
648 | break |
||
649 | end |
||
650 | end |
||
651 | end |
||
652 | -- now try enemies |
||
653 | if not cleanedType and spells["enemymagic"] then |
||
654 | for n, u in pairs(RL.roster) do |
||
655 | if UnitExists(u.unitid.."target") then |
||
656 | cleanedType = self:CureUnit(u.unitid.."target") |
||
657 | if cleanedType then |
||
658 | cleanedName = UnitName(u.unitid.."target") |
||
659 | self:Debug("dispelled enemy",cleanedName) |
||
660 | break |
||
661 | end |
||
662 | end |
||
663 | end |
||
664 | end |
||
665 | --restore original target |
||
666 | if targetIsEnemy then |
||
667 | if not UnitIsEnemy("target","player") then |
||
668 | TargetLastEnemy() |
||
669 | end |
||
670 | elseif targetFriendlyName then |
||
671 | if targetFriendlyName ~= UnitName("target") then |
||
672 | TargetByName(targetFriendlyName) |
||
673 | end |
||
674 | elseif UnitExists("target") then |
||
675 | ClearTarget() |
||
676 | end |
||
677 | -- restore self-cast |
||
678 | SetCVar("autoSelfCast", selfCast) -- maybe not do this here but on a delayed timer? |
||
679 | -- scrolling combat text notification |
||
680 | if cleanedType and cleanedName and self.db.profile.feedback then |
||
681 | local text = string.format(L["Cleaned %s"], cleanedName) |
||
682 | local color = DebuffTypeColor[cleanedType] |
||
683 | if SCT and SCT_MSG_FRAME then -- SCT 5.x |
||
684 | SCT_MSG_FRAME:AddMessage( text, color.r, color.g, color.b, 1 ) |
||
685 | elseif MikSBT then -- Mik's Scrolling Battle Text(MSBT) |
||
686 | MikSBT.DisplayMessage(text, MikSBT.DISPLAYTYPE_NOTIFICATION, true, color.r * 255, color.g * 255, color.b * 255) |
||
687 | elseif CombatText_AddMessage then |
||
688 | -- CHECK FOR COMBAT TEXT |
||
689 | CombatText_AddMessage(text, COMBAT_TEXT_SCROLL_FUNCTION, color.r, color.g, color.b, nil, nil) |
||
690 | end |
||
691 | end |
||
692 | return cleanedType and true or false |
||
693 | end |
||
694 | |||
695 | |||
696 | function Detox:UnitCurable(unit) |
||
697 | if not UnitExists(unit) then return false end |
||
698 | if not UnitIsVisible(unit) then return false end |
||
699 | if Detox.db.profile.range and not CheckInteractDistance(unit, 4) and not curr_DemonType then return false end |
||
700 | -- check if unit is stealthed |
||
701 | if Detox.db.profile.ignoreStealthed then |
||
702 | for buff in pairs(invisible) do |
||
703 | if aura:UnitHasBuff(unit, buff) then return false end |
||
704 | end |
||
705 | end |
||
706 | -- check if we need to ignore unit |
||
707 | for debuff in pairs(ignore) do |
||
708 | if aura:UnitHasDebuff(unit, debuff) then return false end |
||
709 | end |
||
710 | -- check for debuffs that are buffs |
||
711 | for debuff in pairs(skip) do |
||
712 | if aura:UnitHasDebuff(unit, debuff) then return false end |
||
713 | end |
||
714 | -- check for debuffs we want to skip for specific classes when in combat |
||
715 | if UnitAffectingCombat("player") then |
||
716 | local _, class = UnitClass(unit) |
||
717 | if Detox.db.profile.skipByClass[class] then |
||
718 | for debuff in Detox.db.profile.skipByClass[class] do |
||
719 | if Detox.db.profile.skipByClass[class][debuff] then |
||
720 | if aura:UnitHasDebuff(unit, debuff) then return false end |
||
721 | end |
||
722 | end |
||
723 | end |
||
724 | end |
||
725 | if Detox.db.profile.checkAbolish and aura:UnitHasBuff(unit, BS["Abolish Poison"]) then return false end |
||
726 | if Detox.db.profile.checkAbolish and aura:UnitHasBuff(unit, BS["Abolish Disease"]) then return false end |
||
727 | return true |
||
728 | end |
||
729 | |||
730 | |||
731 | function Detox:CureUnit(unit) |
||
732 | if not self:UnitCurable(unit) then return false end |
||
733 | local cleaned = false |
||
734 | local skip |
||
735 | local type |
||
736 | -- check if we can clean a magic debuff |
||
737 | if (spells["magic"] or spells["enemymagic"]) and aura:UnitHasDebuffType(unit, "Magic") then |
||
738 | type = "Magic" |
||
739 | -- check for MC |
||
740 | if spells["enemymagic"] and UnitIsCharmed(unit) and UnitCanAttack("player", unit) then |
||
741 | cleaned = self:CastCuringSpell(spells["enemymagic"], unit) |
||
742 | elseif spells["magic"] and not UnitCanAttack("player", unit) then |
||
743 | cleaned = self:CastCuringSpell(spells["magic"], unit) |
||
744 | end |
||
745 | end |
||
746 | -- check if we can clean a curse |
||
747 | if not cleaned and spells["curse"] and not UnitIsCharmed(unit) and aura:UnitHasDebuffType(unit, "Curse") then |
||
748 | type = "Curse" |
||
749 | cleaned = self:CastCuringSpell(spells["curse"], unit) |
||
750 | end |
||
751 | -- check if we can clean poison |
||
752 | skip = ( Detox.db.profile.checkAbolish and aura:UnitHasBuff(unit, BS["Abolish Poison"]) ) or false |
||
753 | if not cleaned and ( spells["poison1"] or spells["poison2"] ) and not UnitIsCharmed(unit) and not skip and aura:UnitHasDebuffType(unit, "Poison") then |
||
754 | type = "Poison" |
||
755 | if spells["poison2"] and not aura:UnitHasBuff(unit, BS["Abolish Poison"]) then |
||
756 | cleaned = self:CastCuringSpell(spells["poison2"], unit) |
||
757 | else |
||
758 | cleaned = self:CastCuringSpell(spells["poison1"], unit) |
||
759 | end |
||
760 | end |
||
761 | -- check if we can use stoneform to clean our own poison |
||
762 | if not cleaned and unit == "player" and spells["poison3"] and aura:UnitHasDebuffType(unit, "Poison") then |
||
763 | type = "Poison" |
||
764 | cleaned = self:CastCuringSpell(spells["poison3"], unit) |
||
765 | end |
||
766 | -- check if we can clean disease |
||
767 | skip = ( Detox.db.profile.checkAbolish and aura:UnitHasBuff(unit, BS["Abolish Disease"]) ) or false |
||
768 | if not cleaned and ( spells["disease1"] or spells["disease2"] ) and not UnitIsCharmed(unit) and not skip and aura:UnitHasDebuffType(unit, "Disease") then |
||
769 | type = "Disease" |
||
770 | if spells["disease2"] and not aura:UnitHasBuff(unit, BS["Abolish Disease"]) then |
||
771 | cleaned = self:CastCuringSpell(spells["disease2"], unit) |
||
772 | else |
||
773 | cleaned = self:CastCuringSpell(spells["disease1"], unit) |
||
774 | end |
||
775 | end |
||
776 | if cleaned then return type else return nil end |
||
777 | end |
||
778 | |||
779 | |||
780 | function Detox:CastCuringSpell(spellID, unit) |
||
781 | if UnitIsDeadOrGhost("player") then return false end |
||
782 | if spellID[1] == 0 then return false end |
||
783 | if spellID[2] ~= BOOKTYPE_PET and not CheckInteractDistance(unit, 4) then return false end |
||
784 | local spellCasted = false |
||
785 | local castingOnTarget = false |
||
786 | -- check if we plan to clean our current target |
||
787 | if unit ~= "target" then |
||
788 | ClearTarget() |
||
789 | end |
||
790 | -- cast spell |
||
791 | castTarget = unit |
||
792 | CastSpell(spellID[1], spellID[2]) |
||
793 | if SpellIsTargeting() then -- check if spell is usable |
||
794 | SpellTargetUnit(unit) |
||
795 | end |
||
796 | spellCasted = true |
||
797 | -- if spell is still targetting, we had a problem with casting on the unit |
||
798 | if SpellIsTargeting() then |
||
799 | SpellStopTargeting() |
||
800 | spellCasted = false |
||
801 | end |
||
802 | -- we're done |
||
803 | return spellCasted |
||
804 | end |
||
805 | |||
806 | |||
807 | --[[--------------------------------------------------------------------------------- |
||
808 | Debuff skipping |
||
809 | ------------------------------------------------------------------------------------]] |
||
810 | |||
811 | |||
812 | function Detox:AddSkippedDebuff(debuffName) |
||
813 | for k, name in Detox.db.profile.debuffsInSkipList do |
||
814 | if name == debuffName then return end |
||
815 | end |
||
816 | table.insert(Detox.db.profile.debuffsInSkipList, debuffName) |
||
817 | self:PopulateSkipList() |
||
818 | end |
||
819 | |||
820 | -- XXX Please note that we don't remove the class ignores for this debuff. |
||
821 | -- XXX Should we? |
||
822 | function Detox:RemoveSkippedDebuff(debuffName) |
||
823 | for k, name in Detox.db.profile.debuffsInSkipList do |
||
824 | if name == debuffName then |
||
825 | table.remove(Detox.db.profile.debuffsInSkipList, k) |
||
826 | end |
||
827 | end |
||
828 | self:PopulateSkipList() |
||
829 | end |
||
830 | |||
831 | |||
832 | function Detox:PopulateSkipList() |
||
833 | local classes = { "Warrior", "Priest", "Druid", "Shaman", "Paladin", "Mage", "Warlock", "Hunter", "Rogue" } |
||
834 | |||
835 | if options.args.filter.args.debuff.args["add"] then |
||
836 | compost:Reclaim(options.args.filter.args.debuff.args["add"]) |
||
837 | options.args.filter.args.debuff.args["add"] = nil |
||
838 | |||
839 | for k, debuff in pairs(Detox.db.profile.debuffsInSkipList) do |
||
840 | local d = string.gsub(debuff, " ", "") |
||
841 | compost:Reclaim(options.args.filter.args.debuff.args["remove"][d]) |
||
842 | options.args.filter.args.debuff.args["remove"][d] = nil |
||
843 | end |
||
844 | compost:Reclaim(options.args.filter.args.debuff.args["remove"]) |
||
845 | options.args.filter.args.debuff.args["remove"] = nil |
||
846 | end |
||
847 | |||
848 | -- |class| is also the spacer some time during the loop |
||
849 | for class in pairs(options.args.filter.args.debuff.args) do |
||
850 | for debuff in pairs(options.args.filter.args.debuff.args[class]) do |
||
851 | local d = string.gsub(debuff, " ", "") |
||
852 | -- If we just added a debuff, it will not be in the menu yet, so |
||
853 | -- check in case we try to reclaim it. |
||
854 | if options.args.filter.args.debuff.args[class][d] then |
||
855 | compost:Reclaim(options.args.filter.args.debuff.args[class][d]) |
||
856 | options.args.filter.args.debuff.args[class][d] = nil |
||
857 | end |
||
858 | end |
||
859 | compost:Reclaim(options.args.filter.args.debuff.args[class]) |
||
860 | options.args.filter.args.debuff.args[class] = nil |
||
861 | end |
||
862 | |||
863 | -- create add option in dewdrop |
||
864 | options.args.filter.args.debuff.args["add"] = compost:Acquire() |
||
865 | options.args.filter.args.debuff.args["add"].type = 'text' |
||
866 | options.args.filter.args.debuff.args["add"].name = L["Add"] |
||
867 | options.args.filter.args.debuff.args["add"].desc = L["Adds a new debuff to the class submenus."] |
||
868 | options.args.filter.args.debuff.args["add"].get = false |
||
869 | options.args.filter.args.debuff.args["add"].set = function(v) self:AddSkippedDebuff(v) end |
||
870 | options.args.filter.args.debuff.args["add"].usage = L["<debuff name>"] |
||
871 | options.args.filter.args.debuff.args["add"].order = 101 |
||
872 | |||
873 | -- create remove option in dewdrop |
||
874 | options.args.filter.args.debuff.args["remove"] = compost:Acquire() |
||
875 | options.args.filter.args.debuff.args["remove"].type = 'group' |
||
876 | options.args.filter.args.debuff.args["remove"].name = L["Remove"] |
||
877 | options.args.filter.args.debuff.args["remove"].desc = L["Removes a debuff from the class submenus."] |
||
878 | options.args.filter.args.debuff.args["remove"].args = compost:Acquire() |
||
879 | options.args.filter.args.debuff.args["remove"].order = 102 |
||
880 | -- create list of debuffs in subfolder |
||
881 | for k, debuff in pairs(Detox.db.profile.debuffsInSkipList) do |
||
882 | local debuffName = debuff |
||
883 | local d = string.gsub(debuffName, " ", "") |
||
884 | options.args.filter.args.debuff.args["remove"].args[d] = compost:Acquire() |
||
885 | options.args.filter.args.debuff.args["remove"].args[d].type = 'execute' |
||
886 | options.args.filter.args.debuff.args["remove"].args[d].name = debuffName |
||
887 | options.args.filter.args.debuff.args["remove"].args[d].desc = string.format(L["Remove %s from the class submenus."], debuffName) |
||
888 | options.args.filter.args.debuff.args["remove"].args[d].func = function() return self:RemoveSkippedDebuff(debuffName) end |
||
889 | end |
||
890 | |||
891 | -- create spacer |
||
892 | options.args.filter.args.debuff.args.spacer = { type = "header", order = 103 } |
||
893 | |||
894 | -- create list of debuffs |
||
895 | for k, debuff in pairs(Detox.db.profile.debuffsInSkipList) do |
||
896 | local debuffName = debuff |
||
897 | local d = string.gsub(debuffName, " ", "") |
||
898 | options.args.filter.args.debuff.args[d] = compost:Acquire() |
||
899 | options.args.filter.args.debuff.args[d].type = 'group' |
||
900 | options.args.filter.args.debuff.args[d].name = debuffName |
||
901 | options.args.filter.args.debuff.args[d].desc = string.format(L["Classes to filter for: %s."], debuffName) |
||
902 | options.args.filter.args.debuff.args[d].args = compost:Acquire() |
||
903 | options.args.filter.args.debuff.args[d].order = 200 |
||
904 | -- create submenu for classes |
||
905 | for k, class in pairs(classes) do |
||
906 | local className = class |
||
907 | options.args.filter.args.debuff.args[d].args[className] = compost:Acquire() |
||
908 | options.args.filter.args.debuff.args[d].args[className].type = 'toggle' |
||
909 | options.args.filter.args.debuff.args[d].args[className].name = BC[className] |
||
910 | options.args.filter.args.debuff.args[d].args[className].desc = string.format(L["Toggle filtering %s on %s."], debuffName, BC[className]) |
||
911 | options.args.filter.args.debuff.args[d].args[className].get = |
||
912 | function() return Detox.db.profile.skipByClass[string.upper(className)][debuffName] end |
||
913 | options.args.filter.args.debuff.args[d].args[className].set = |
||
914 | function() |
||
915 | Detox.db.profile.skipByClass[string.upper(className)][debuffName] = not Detox.db.profile.skipByClass[string.upper(className)][debuffName] |
||
916 | end |
||
917 | end |
||
918 | end |
||
919 | |||
920 | |||
921 | |||
922 | end |
||
923 | |||
924 | |||
925 | --[[--------------------------------------------------------------------------------- |
||
926 | Priority |
||
927 | ------------------------------------------------------------------------------------]] |
||
928 | |||
929 | function Detox:PriorityPrint(target, priority) |
||
930 | if priority then |
||
931 | self:Print(string.format(L["%s was added to the priority list."], target)) |
||
932 | else |
||
933 | self:Print(string.format(L["%s has been removed from the priority list."], target)) |
||
934 | end |
||
935 | end |
||
936 | |||
937 | function Detox:PriorityToggle(targetType) |
||
938 | if not UnitExists("target") then |
||
939 | self:Print(L["Can't add/remove current target to priority list, it doesn't exist."]) |
||
940 | return |
||
941 | end |
||
942 | local target = UnitName("target") |
||
943 | if not targetType then |
||
944 | if not RL.roster[target] then |
||
945 | self:Print(L["Can't add/remove current target to priority list, it's not in your raid."]) |
||
946 | return |
||
947 | end |
||
948 | Detox.db.profile.priorityNames[target] = not Detox.db.profile.priorityNames[target] |
||
949 | self:PriorityPrint(target, Detox.db.profile.priorityNames[target]) |
||
950 | else |
||
951 | local targetGroup = nil |
||
952 | local targetClass = nil |
||
953 | |||
954 | for n, u in pairs(RL.roster) do |
||
955 | if u and u.name and u.class ~= "PET" then |
||
956 | if not targetGroup and u.name == target then |
||
957 | targetGroup = u.subgroup |
||
958 | targetClass = u.class |
||
959 | break |
||
960 | end |
||
961 | end |
||
962 | end |
||
963 | |||
964 | if targetType == "class" and targetClass then |
||
965 | Detox.db.profile.priorityClasses[targetClass] = not Detox.db.profile.priorityClasses[targetClass] |
||
966 | self:PriorityPrint(string.format(L["Class %s"], targetClass), Detox.db.profile.priorityClasses[targetClass]) |
||
967 | elseif targetType == "group" and targetGroup then |
||
968 | Detox.db.profile.priorityGroups[targetGroup] = not Detox.db.profile.priorityGroups[targetGroup] |
||
969 | self:PriorityPrint(string.format(L["Group %s"], targetGroup), Detox.db.profile.priorityGroups[targetGroup]) |
||
970 | else |
||
971 | self:Print(L["Can't add/remove current target to priority list, it's not in your raid."]) |
||
972 | return |
||
973 | end |
||
974 | end |
||
975 | self:UpdatePriority() |
||
976 | end |
||
977 | |||
978 | local function sortPri(a,b) |
||
979 | return a.pri > b.pri |
||
980 | end |
||
981 | |||
982 | function Detox:UpdatePriority() |
||
983 | self:CreateOptionsTable() |
||
984 | -- update and sort all units. this task has a few steps: |
||
985 | local datasubtable, index |
||
986 | for name, u in pairs(RL.roster) do |
||
987 | -- see if that unit is in our priorityIndex table |
||
988 | index = priorityIndex[name] |
||
989 | -- either use the existing subtable or create a new one |
||
990 | datasubtable = index and priority[index] or compost:Acquire() |
||
991 | datasubtable.pri = self:GetPriority(name) |
||
992 | datasubtable.unitid = u.unitid |
||
993 | if not index then |
||
994 | -- our subtable still needs a name |
||
995 | datasubtable.name = name |
||
996 | -- add that subtable to the priority table |
||
997 | table.insert(priority, datasubtable) |
||
998 | priorityIndex[name] = table.getn(priority) -- maybe not needed, but for safety reasons it can't hurt. |
||
999 | end |
||
1000 | end |
||
1001 | -- now re-sort the priority table |
||
1002 | table.sort(priority, sortPri) |
||
1003 | -- save the current index for all names |
||
1004 | for k,v in ipairs(priority) do |
||
1005 | priorityIndex[v.name] = k |
||
1006 | end |
||
1007 | end |
||
1008 | |||
1009 | |||
1010 | function Detox:CreateOptionsTable() |
||
1011 | -- we need to update the dewdrop menu, so lets clear the old one and inject new stuff: |
||
1012 | for class in options.args.priority.args do |
||
1013 | for unit in options.args.priority.args[class].args do |
||
1014 | compost:Reclaim(options.args.priority.args[class].args[unit]) |
||
1015 | options.args.priority.args[class].args[unit] = nil |
||
1016 | end |
||
1017 | compost:Reclaim(options.args.priority.args[class]) |
||
1018 | options.args.priority.args[class] = nil |
||
1019 | end |
||
1020 | |||
1021 | compost:Reclaim(options.args.priority.args["group"]) |
||
1022 | |||
1023 | options.args.priority.args["group"] = compost:Acquire() |
||
1024 | options.args.priority.args["group"].type = 'group' |
||
1025 | options.args.priority.args["group"].name = L["Groups"] |
||
1026 | options.args.priority.args["group"].desc = L["Prioritize by group."] |
||
1027 | options.args.priority.args["group"].order = 100 |
||
1028 | options.args.priority.args["group"].args = compost:Acquire() |
||
1029 | for i = 1, 8 do |
||
1030 | local x = i |
||
1031 | options.args.priority.args["group"].args["group"..i] = compost:Acquire() |
||
1032 | options.args.priority.args["group"].args["group"..i].type = 'toggle' |
||
1033 | options.args.priority.args["group"].args["group"..i].name = string.format(L["Group %s"], i) |
||
1034 | options.args.priority.args["group"].args["group"..i].desc = string.format(L["Prioritize group %s."], i) |
||
1035 | options.args.priority.args["group"].args["group"..i].order = 100 + i |
||
1036 | options.args.priority.args["group"].args["group"..i].get = |
||
1037 | function() return Detox.db.profile.priorityGroups[x] end |
||
1038 | options.args.priority.args["group"].args["group"..i].set = |
||
1039 | function() |
||
1040 | Detox.db.profile.priorityGroups[x] = not Detox.db.profile.priorityGroups[x] |
||
1041 | Detox:UpdatePriority() |
||
1042 | end |
||
1043 | end |
||
1044 | |||
1045 | -- create subgroups |
||
1046 | for name, unit in pairs(RL.roster) do |
||
1047 | if unit and unit.class ~= "PET" then |
||
1048 | local n = name |
||
1049 | local u = unit |
||
1050 | if not options.args.priority.args[u.class] then |
||
1051 | options.args.priority.args[u.class] = compost:Acquire() |
||
1052 | options.args.priority.args[u.class].type = 'group' |
||
1053 | -- convert class name. gah. |
||
1054 | -- we need this as Babble-Class doesnt know capitalized class names, nor does it know "PET" |
||
1055 | local c = strupper(strsub(u.class, 1, 1)) .. strlower(strsub(u.class, 2)) |
||
1056 | if c ~= "Pet" then c = BC[c] end |
||
1057 | options.args.priority.args[u.class].name = c |
||
1058 | options.args.priority.args[u.class].desc = c |
||
1059 | options.args.priority.args[u.class].order = 101 |
||
1060 | options.args.priority.args[u.class].args = compost:Acquire() |
||
1061 | |||
1062 | -- Create "all <class>" item |
||
1063 | if not options.args.priority.args[u.class].args[c] then |
||
1064 | options.args.priority.args[u.class].args[c] = compost:Acquire() |
||
1065 | options.args.priority.args[u.class].args[c].type = 'toggle' |
||
1066 | options.args.priority.args[u.class].args[c].name = string.format(L["Every %s"], c) |
||
1067 | options.args.priority.args[u.class].args[c].desc = string.format(L["Prioritize every %s."], c) |
||
1068 | options.args.priority.args[u.class].args[c].order = 100 |
||
1069 | options.args.priority.args[u.class].args[c].get = |
||
1070 | function() return Detox.db.profile.priorityClasses[u.class] end |
||
1071 | options.args.priority.args[u.class].args[c].set = |
||
1072 | function() |
||
1073 | Detox.db.profile.priorityClasses[u.class] = not Detox.db.profile.priorityClasses[u.class] |
||
1074 | Detox:UpdatePriority() |
||
1075 | end |
||
1076 | end |
||
1077 | end |
||
1078 | options.args.priority.args[u.class].args[n] = compost:Acquire() |
||
1079 | options.args.priority.args[u.class].args[n].type = 'toggle' |
||
1080 | options.args.priority.args[u.class].args[n].name = n |
||
1081 | options.args.priority.args[u.class].args[n].desc = string.format(L["Prioritize %s."], n) |
||
1082 | options.args.priority.args[u.class].args[n].order = 101 |
||
1083 | options.args.priority.args[u.class].args[n].get = |
||
1084 | function() return Detox.db.profile.priorityNames[n] end |
||
1085 | options.args.priority.args[u.class].args[n].set = |
||
1086 | function() |
||
1087 | Detox.db.profile.priorityNames[n] = not Detox.db.profile.priorityNames[n] |
||
1088 | Detox:UpdatePriority() |
||
1089 | end |
||
1090 | end |
||
1091 | end |
||
1092 | end |
||
1093 | |||
1094 | |||
1095 | function Detox:GetPriority(name) |
||
1096 | local playergroup = (RL.roster[UnitName("player")] and RL.roster[UnitName("player")].subgroup) or 1 |
||
1097 | local pri |
||
1098 | local grp = RL.roster[name].subgroup |
||
1099 | local cls = RL.roster[name].class |
||
1100 | -- priority range 1000 - 0. |
||
1101 | if name == UnitName("player") then pri = 800 |
||
1102 | elseif playergroup == grp then pri = 700 |
||
1103 | elseif playergroup < grp then pri = 700 - (grp - playergroup)*10 |
||
1104 | else pri = 700 - (grp + 8 - playergroup)*10 |
||
1105 | end |
||
1106 | if cls == "PET" then |
||
1107 | if Detox.db.profile.ignorePets then pri = 0 else pri = pri - 200 end |
||
1108 | end |
||
1109 | if Detox.db.profile.priorityNames[name] then pri = pri + 200 end -- unit in individual priority list |
||
1110 | if Detox.db.profile.priorityClasses[cls] then pri = pri + 200 end -- unit in prioritized class |
||
1111 | if Detox.db.profile.priorityGroups[grp] then pri = pri + 200 end -- unit in prioritized group |
||
1112 | return pri |
||
1113 | end |
||
1114 | |||
1115 | |||
1116 | --[[--------------------------------------------------------------------------------- |
||
1117 | Live display and other FuBar stuff |
||
1118 | ------------------------------------------------------------------------------------]] |
||
1119 | |||
1120 | |||
1121 | function Detox:OnTooltipUpdate() |
||
1122 | local cat = nil |
||
1123 | local lines = 0 |
||
1124 | for k,v in ipairs(priority) do |
||
1125 | if v.pri == 0 then break end |
||
1126 | if lines > Detox.db.profile.liveDisplay then break end |
||
1127 | local unit = v.unitid |
||
1128 | if UnitIsVisible(unit) and not blacklist[unit] and self:UnitCurable(unit) then |
||
1129 | for debuffname, count, type, texture in aura:DebuffIter(unit) do |
||
1130 | if ( not Detox.db.profile.filter and ( type == "Magic" or type == "Poison" or type == "Disease" or type == "Curse" ) ) |
||
1131 | or ( type == "Magic" and spells["magic"] ) |
||
1132 | or ( type == "Poison" and ( spells["poison1"] or spells["poison2"] ) ) |
||
1133 | or ( type == "Disease" and ( spells["disease1"] or spells["disease2"] ) ) |
||
1134 | or ( type == "Curse" and spells["curse"] ) |
||
1135 | then |
||
1136 | local r,g,b = self:GetRaidColors(unit) |
||
1137 | if count == 0 then count = 1 end |
||
1138 | lines = lines + 1 |
||
1139 | if not cat then |
||
1140 | cat = tablet:AddCategory("columns", 2, "text", "", "text2", "", "showWithoutChildren", false, "hideBlankLine", false) |
||
1141 | end |
||
1142 | cat:AddLine( |
||
1143 | "text", string.format("%s (%dx)", debuffname, count), |
||
1144 | "textR", DebuffTypeColor[type].r, |
||
1145 | "textG", DebuffTypeColor[type].g, |
||
1146 | "textB", DebuffTypeColor[type].b, |
||
1147 | "text2", UnitName(unit), |
||
1148 | "text2R", r, |
||
1149 | "text2G", g, |
||
1150 | "text2B", b, |
||
1151 | "hasCheck", true, |
||
1152 | "checked", true, |
||
1153 | "checkIcon", texture, |
||
1154 | "func", function(unit) Detox:CureUnit(unit) end, |
||
1155 | "arg1", unit, |
||
1156 | "justify", "LEFT", |
||
1157 | "justify2", "LEFT" |
||
1158 | ) |
||
1159 | -- update fubar display (icon + text) to display the first |
||
1160 | -- debuff we find. |
||
1161 | if lines == 1 then |
||
1162 | self:SetIcon(texture) |
||
1163 | self:SetText(string.format("|cff%02x%02x%02x%s|r", DebuffTypeColor[type].r*255, DebuffTypeColor[type].g*255, DebuffTypeColor[type].b*255, UnitName(unit))) |
||
1164 | end |
||
1165 | end |
||
1166 | end |
||
1167 | end |
||
1168 | end |
||
1169 | -- play sound |
||
1170 | if Detox.db.profile.sound then |
||
1171 | if lines == 0 then |
||
1172 | soundPlayed = false |
||
1173 | elseif not soundPlayed then |
||
1174 | PlaySoundFile("Sound\\interface\\AuctionWindowOpen.wav") |
||
1175 | soundPlayed = true |
||
1176 | end |
||
1177 | end |
||
1178 | -- Reset FuBar text and display |
||
1179 | if lines == 0 then |
||
1180 | self:SetIcon(true) |
||
1181 | self:SetText("Detox") |
||
1182 | end |
||
1183 | -- Show the prioritized units |
||
1184 | if Detox.db.profile.showPriorities then |
||
1185 | local priCat = nil |
||
1186 | local text = nil |
||
1187 | for k,v in ipairs(priority) do |
||
1188 | if v.pri > 700 then |
||
1189 | if not priCat then priCat = tablet:AddCategory("columns", 1, "text", L["Priorities"]) end |
||
1190 | local name = v.name |
||
1191 | if not text then |
||
1192 | text = name |
||
1193 | else |
||
1194 | text = text..", "..name |
||
1195 | end |
||
1196 | end |
||
1197 | end |
||
1198 | if priCat then priCat:AddLine("text", text..".", "wrap", true) end |
||
1199 | end |
||
1200 | end |
||
1201 | |||
1202 | |||
1203 | function Detox:OnClick() |
||
1204 | self:Clean() |
||
1205 | end |
||
1206 | |||
1207 | |||
1208 | function Detox:GetRaidColors(unit) |
||
1209 | local _,class = UnitClass(unit) |
||
1210 | if RAID_CLASS_COLORS[class] then |
||
1211 | return RAID_CLASS_COLORS[class].r, RAID_CLASS_COLORS[class].g, RAID_CLASS_COLORS[class].b |
||
1212 | else |
||
1213 | return 0.5, 0.5, 0.5 |
||
1214 | end |
||
1215 | end |