2 Name: LibRangeCheck-2.0
3 Revision: $Revision: 98 $
5 Website: http://www.wowace.com/projects/librangecheck-2-0/
6 Description: A range checking library based on interact distances and spell ranges
11 --- LibRangeCheck-2.0 provides an easy way to check for ranges and get suitable range checking functions for specific ranges.\\
12 -- The checkers use spell and item range checks, or interact based checks for special units where those two cannot be used.\\
13 -- The lib handles the refreshing of checker lists in case talents / spells / glyphs change and in some special cases when equipment changes (for example some of the mage pvp gloves change the range of the Fire Blast spell), and also handles the caching of items used for item-based range checks.\\
14 -- A callback is provided for those interested in checker changes.
16 -- local rc = LibStub("LibRangeCheck-2.0")
18 -- rc.RegisterCallback(self, rc.CHECKERS_CHANGED, function() print("need to refresh my stored checkers") end)
20 -- local minRange, maxRange = rc:GetRange('target')
21 -- if not minRange then
22 -- print("cannot get range estimate for target")
23 -- elseif not maxRange then
24 -- print("target is over " .. minRange .. " yards")
26 -- print("target is between " .. minRange .. " and " .. maxRange .. " yards")
29 -- local meleeChecker = rc:GetFriendMaxChecker(rc.MeleeRange) -- 5 yds
31 -- -- TODO: check if unit is valid, etc
32 -- if meleeChecker("party" .. i) then
33 -- print("Party member " .. i .. " is in Melee range")
37 -- local safeDistanceChecker = rc:GetHarmMinChecker(30)
38 -- -- negate the result of the checker!
39 -- local isSafelyAway = not safeDistanceChecker('target')
42 -- @name LibRangeCheck-2.0
43 local MAJOR_VERSION
= "LibRangeCheck-2.0"
44 local MINOR_VERSION
= tonumber(("$Revision: 98 $"):match("%d+")) + 100000
46 local lib
, oldminor
= LibStub
:NewLibrary(MAJOR_VERSION
, MINOR_VERSION
)
53 local UpdateDelay
= .5
54 local ItemRequestTimeout
= 10.0
56 -- interact distance based checks. ranges are based on my own measurements (thanks for all the folks who helped me with this)
57 local DefaultInteractList
= {
63 -- interact list overrides for races
64 local InteractLists
= {
79 -- list of friendly spells that have different ranges
80 local FriendSpells
= {}
81 -- list of harmful spells that have different ranges
84 FriendSpells
["DRUID"] = {
85 5185, -- ["Healing Touch"], -- 40
86 467, -- ["Thorns"], -- 30 (Nature's Reach: 33, 36)
87 1126, -- ["Mark of the Wild"], -- 30
89 HarmSpells
["DRUID"] = {
90 16979, -- ["Feral Charge"], -- 8-25
91 5176, -- ["Wrath"], -- 30 (Nature's Reach: 33, 36)
92 33786, -- ["Cyclone"], -- 20 (Nature's Reach: 22, 24; Gale Winds: +10/20%)
93 6795, -- ["Growl"], -- 20
94 5211, -- ["Bash"], -- 5
97 FriendSpells
["HUNTER"] = {}
98 HarmSpells
["HUNTER"] = {
99 1130, -- ["Hunter's Mark"] -- 100
100 53351, -- ["Kill Shot"] -- 5-45 (Hawk Eye: 47, 49, 51)
101 75, -- ["Auto Shot"], -- 5-35 (Hawk Eye: 37, 39, 41)
102 2764, -- ["Throw"], -- 30
103 19503, -- ["Scatter Shot"], -- 15 (Hawk Eye: 17, 19, 21; Glyph of Scatter Shot: +3)
104 2974, -- ["Wing Clip"], -- 5
107 FriendSpells
["MAGE"] = {
108 475, -- ["Remove Curse"], -- 40 (Magic Attunement: 43, 46)
109 1459, -- ["Arcane Intellect"], -- 30 (Magic Attunement: 33, 36)
111 HarmSpells
["MAGE"] = {
112 44614, -- ["Frostfire Bolt"], -- 40
113 133, -- ["Fireball"], -- 35 (Flame Throwing: 38, 41)
114 116, -- ["Frostbolt"], -- 30 (Arctic Reach: 33, 36)
115 30455, -- ["Ice Lance"], -- 30 (Arctic Reach: 33, 36, Glyph of Ice Lance: +5)
116 5143, -- ["Arcane Missiles"], -- 30 (Magic Attunement: 33, 36; Glyph of Arcane Missiles: +5)
117 30451, -- ["Arcane Blast"], -- 30 (Magic Attunement: 33, 36)
118 2948, -- ["Scorch"], -- 30 (Flame Throwing: 33, 36)
119 5019, -- ["Shoot"], -- 30
120 2136, -- ["Fire Blast"], -- 20 (Flame Throwing: 23, 26; Gladiator Gloves: +5)
123 FriendSpells
["PALADIN"] = {
124 635, -- ["Holy Light"], -- 40
125 19740, -- ["Blessing of Might"], -- 30
126 20473, -- ["Holy Shock"], -- 20
128 HarmSpells
["PALADIN"] = {
129 24275, -- ["Hammer of Wrath"], -- 30 (Glyph of Hammer of Wrath: +5)
130 20473, -- ["Holy Shock"], -- 20
131 20271, -- ["Judgement"], -- 10
132 35395, -- ["Crusader Strike"], -- 5
135 FriendSpells
["PRIEST"] = {
136 2050, -- ["Lesser Heal"], -- 40
137 1243, -- ["Power Word: Fortitude"], -- 30
139 HarmSpells
["PRIEST"] = {
140 585, -- ["Smite"], -- 30 (Holy Reach: 33, 36)
141 589, -- ["Shadow Word: Pain"], -- 30 (Shadow Reach: 33, 36)
142 5019, -- ["Shoot"], -- 30
143 15407, -- ["Mind Flay"], -- 20 (Shadow Reach: 22, 24, Glyph of Mind Flay: +10)
146 FriendSpells
["ROGUE"] = {}
147 HarmSpells
["ROGUE"] = {
148 2764, -- ["Throw"], -- 30
149 26679, -- ["Deadly Throw"], -- 30 (Glyph of Deadly Throw: +5)
150 2094, -- ["Blind"], -- 10 (Dirty Tricks: 12, 15)
151 2098, -- ["Eviscerate"], -- 5
154 FriendSpells
["SHAMAN"] = {
155 331, -- ["Healing Wave"], -- 40
156 526, -- ["Cure Poison"], -- 30
158 HarmSpells
["SHAMAN"] = {
159 403, -- ["Lightning Bolt"], -- 30 (Storm Reach: 33, 36)
160 370, -- ["Purge"], -- 30
161 8050, -- ["Flame Shock"], -- 20 (Elemental Reach: 27, 35; Gladiator Gloves: +5)
162 -- 8042, -- ["Earth Shock"], -- 20 (Storm, Earth and Fire: 21-25; Gladiator Gloves: +5)
163 8056, -- ["Frost Shock"], -- 20 (Gladiator Gloves: +5)
166 FriendSpells
["WARRIOR"] = {}
167 HarmSpells
["WARRIOR"] = {
168 100, -- ["Charge"], -- 8-25 (Glyph of Charge: +5)
169 3018, -- ["Shoot"], -- 30
170 2764, -- ["Throw"], -- 30
171 355, -- ["Taunt"], -- 30
172 5246, -- ["Intimidating Shout"], -- 8
173 772, -- ["Rend"], -- 5
176 FriendSpells
["WARLOCK"] = {
177 5697, -- ["Unending Breath"], -- 30 (demo)
179 HarmSpells
["WARLOCK"] = {
180 5019, -- ["Shoot"], -- 30
181 348, -- ["Immolate"], -- 30 (Destructive Reach: 33, 36)
182 172, -- ["Corruption"], -- 30 (Grim Reach: 33, 36)
183 18223, -- ["Curse of Exhaustion"], -- 30 (Grim Reach: 33, 36, Glyph of Curse of Exhaustion: +5)
184 5782, -- ["Fear"], -- 20 (Grim Reach: 22, 24)
185 17877, -- ["Shadowburn"], -- 20 (Destructive Reach: 22, 24)
188 FriendSpells
["DEATHKNIGHT"] = {
190 HarmSpells
["DEATHKNIGHT"] = {
191 47541, -- ["Death Coil"], -- 30
192 47476, -- ["Strangulate"], -- 30 (Glyph of Strangulate: +20)
193 45477, -- ["Icy Touch"], -- 20 (Icy Reach: 25, 30)
194 56222, -- ["Dark Command"], -- 20
195 50842, -- ["Pestilence"], -- 5
196 45902, -- ["Blood Strike"], -- 5, but requires weapon, use Pestilence if possible, so keep it after Pestilence in this list
199 -- Items [Special thanks to Maldivia for the nice list]
201 local FriendItems
= {
206 34368, -- Attuned Crystal Cores
207 33278, -- Burning Torch
210 32321, -- Sparrowhawk Net
213 1251, -- Linen Bandage
214 2581, -- Heavy Linen Bandage
215 3530, -- Wool Bandage
216 3531, -- Heavy Wool Bandage
217 6450, -- Silk Bandage
218 6451, -- Heavy Silk Bandage
219 8544, -- Mageweave Bandage
220 8545, -- Heavy Mageweave Bandage
221 14529, -- Runecloth Bandage
222 14530, -- Heavy Runecloth Bandage
223 21990, -- Netherweave Bandage
224 21991, -- Heavy Netherweave Bandage
225 34721, -- Frostweave Bandage
226 34722, -- Heavy Frostweave Bandage
227 -- 38643, -- Thick Frostweave Bandage
228 -- 38640, -- Dense Frostweave Bandage
234 31463, -- Zezzak's Shard
237 1180, -- Scroll of Stamina
238 1478, -- Scroll of Protection II
239 3012, -- Scroll of Agility
240 1712, -- Scroll of Spirit II
241 2290, -- Scroll of Intellect II
242 1711, -- Scroll of Stamina II
243 34191, -- Handful of Snowflakes
246 18904, -- Zorbin's Ultra-Shrinker
249 34471, -- Vial of the Sunwell
252 32698, -- Wrangling Rope
255 32825, -- Soul Cannon
256 37887, -- Seeds of Nature's Wrath
259 35278, -- Reinforced Net
268 34368, -- Attuned Crystal Cores
269 33278, -- Burning Torch
272 32321, -- Sparrowhawk Net
275 33069, -- Sturdy Rope
278 10645, -- Gnomish Death Ray
281 24268, -- Netherweave Net
282 41509, -- Frostweave Net
283 31463, -- Zezzak's Shard
286 835, -- Large Rope Net
287 7734, -- Six Demon Bag
288 34191, -- Handful of Snowflakes
291 24269, -- Heavy Netherweave Net
292 18904, -- Zorbin's Ultra-Shrinker
295 28767, -- The Decapitator
298 32698, -- Wrangling Rope
301 32825, -- Soul Cannon
302 37887, -- Seeds of Nature's Wrath
305 35278, -- Reinforced Net
309 -- This could've been done by checking player race as well and creating tables for those, but it's easier like this
310 for k
, v
in pairs(FriendSpells
) do
311 tinsert(v
, 28880) -- ["Gift of the Naaru"]
313 for k
, v
in pairs(HarmSpells
) do
314 tinsert(v
, 28734) -- ["Mana Tap"]
317 -- >> END OF STATIC CONFIG
321 local setmetatable
= setmetatable
322 local tonumber = tonumber
324 local tostring = tostring
329 local tinsert = tinsert
330 local tremove = tremove
331 local BOOKTYPE_SPELL
= BOOKTYPE_SPELL
332 local GetSpellInfo
= GetSpellInfo
333 local GetSpellName
= GetSpellName
334 local GetItemInfo
= GetItemInfo
335 local UnitCanAttack
= UnitCanAttack
336 local UnitCanAssist
= UnitCanAssist
337 local UnitExists
= UnitExists
338 local UnitIsDeadOrGhost
= UnitIsDeadOrGhost
339 local CheckInteractDistance
= CheckInteractDistance
340 local IsSpellInRange
= IsSpellInRange
341 local IsItemInRange
= IsItemInRange
342 local UnitClass
= UnitClass
343 local UnitRace
= UnitRace
344 local GetInventoryItemLink
= GetInventoryItemLink
345 local GetTime
= GetTime
346 local HandSlotId
= GetInventorySlotInfo("HandsSlot")
347 local TT
= ItemRefTooltip
351 local itemRequestTimeoutAt
354 local friendItemRequests
355 local harmItemRequests
358 -- minRangeCheck is a function to check if spells with minimum range are really out of range, or fail due to range < minRange. See :init() for its setup
359 local minRangeCheck
= function(unit
) return CheckInteractDistance(unit
, 2) end
361 local checkers_Spell
= setmetatable({}, {
362 __index
= function(t
, spellIdx
)
363 local func
= function(unit
)
364 if IsSpellInRange(spellIdx
, BOOKTYPE_SPELL
, unit
) == 1 then
372 local checkers_SpellWithMin
= setmetatable({}, {
373 __index
= function(t
, spellIdx
)
374 local func
= function(unit
)
375 if IsSpellInRange(spellIdx
, BOOKTYPE_SPELL
, unit
) == 1 then
377 elseif minRangeCheck(unit
) then
385 local checkers_Item
= setmetatable({}, {
386 __index
= function(t
, item
)
387 local func
= function(unit
)
388 if IsItemInRange(item
, unit
) == 1 then
396 local checkers_Interact
= setmetatable({}, {
397 __index
= function(t
, index
)
398 local func
= function(unit
)
399 if CheckInteractDistance(unit
, index
) then
410 local function copyTable(src
, dst
)
411 if type(dst
) ~= "table" then dst
= {} end
412 if type(src
) == "table" then
413 for k
, v
in pairs(src
) do
414 if type(v
) == "table" then
415 v
= copyTable(v
, dst
[k
])
424 local function initItemRequests(cacheAll
)
425 friendItemRequests
= copyTable(FriendItems
)
426 harmItemRequests
= copyTable(HarmItems
)
427 cacheAllItems
= cacheAll
431 local function requestItemInfo(itemId
)
432 if not itemId
then return end
433 TT
:SetHyperlink(string.format("item:%d", itemId
))
436 -- return the spellIndex of the given spell by scanning the spellbook
437 local function findSpellIdx(spellName
)
440 local spell
, rank
= GetSpellName(i
, BOOKTYPE_SPELL
)
441 if not spell
then return nil end
442 if spell
== spellName
then return i
end
448 -- minRange should be nil if there's no minRange, not 0
449 local function addChecker(t
, range
, minRange
, checker
)
450 local rc
= { ["range"] = range
, ["minRange"] = minRange
, ["checker"] = checker
}
453 if rc
.range
== v
.range
then return end
454 if rc
.range
> v
.range
then
462 local function createCheckerList(spellList
, itemList
, interactList
)
465 for i
= 1, #spellList
do
466 local sid
= spellList
[i
]
467 local name
, _
, _
, _
, _
, _
, _
, minRange
, range
= GetSpellInfo(sid
)
468 local spellIdx
= findSpellIdx(name
)
469 if spellIdx
and range
then
470 minRange
= math
.floor(minRange
+ 0.5)
471 range
= math
.floor(range
+ 0.5)
472 -- print("### spell: " .. tostring(name) .. ", " .. tostring(minRange) .. " - " .. tostring(range))
473 if minRange
== 0 then -- getRange() expects minRange to be nil in this case
480 addChecker(res
, range
, minRange
, checkers_SpellWithMin
[spellIdx
])
482 addChecker(res
, range
, minRange
, checkers_Spell
[spellIdx
])
489 for range
, items
in pairs(itemList
) do
491 local item
= items
[i
]
492 if GetItemInfo(item
) then
493 addChecker(res
, range
, nil, checkers_Item
[item
])
500 if interactList
and not next(res
) then
501 for index
, range
in pairs(interactList
) do
502 addChecker(res
, range
, nil, checkers_Interact
[index
])
509 -- returns minRange, maxRange or nil
510 local function getRange(unit
, checkerList
)
511 local min, max = 0, nil
512 for i
= 1, #checkerList
do
513 local rc
= checkerList
[i
]
514 if not max or max > rc
.range
then
516 local inRange
, inMinRange
= rc
.checker(unit
)
520 min, max = rc
.minRange
, rc
.range
521 elseif min > rc
.range
then
526 elseif rc
.checker(unit
) then
528 elseif min > rc
.range
then
538 local function updateCheckers(origList
, newList
)
539 if #origList
~= #newList
then
541 copyTable(newList
, origList
)
544 for i
= 1, #origList
do
545 if origList
[i
].range
~= newList
[i
].range
or origList
[i
].checker
~= newList
[i
].checker
then
547 copyTable(newList
, origList
)
553 local function rcIterator(checkerList
)
554 local curr
= #checkerList
556 local rc
= checkerList
[curr
]
561 return rc
.range
, rc
.checker
565 local function getMinChecker(checkerList
, range
)
566 local checker
, checkerRange
567 for i
= 1, #checkerList
do
568 local rc
= checkerList
[i
]
569 if rc
.range
< range
then
570 return checker
, checkerRange
572 checker
, checkerRange
= rc
.checker
, rc
.range
574 return checker
, checkerRange
577 local function getMaxChecker(checkerList
, range
)
578 for i
= 1, #checkerList
do
579 local rc
= checkerList
[i
]
580 if rc
.range
<= range
then
581 return rc
.checker
, rc
.range
586 local function getChecker(checkerList
, range
)
587 for i
= 1, #checkerList
do
588 local rc
= checkerList
[i
]
589 if rc
.range
== range
then
595 local function null()
598 local function createSmartChecker(friendChecker
, harmChecker
, miscChecker
)
599 miscChecker
= miscChecker
or null
600 friendChecker
= friendChecker
or miscChecker
601 harmChecker
= harmChecker
or miscChecker
602 return function(unit
)
603 if not UnitExists(unit
) then
606 if UnitIsDeadOrGhost(unit
) then
607 return miscChecker(unit
)
609 if UnitCanAttack("player", unit
) then
610 return harmChecker(unit
)
611 elseif UnitCanAssist("player", unit
) then
612 return friendChecker(unit
)
614 return miscChecker(unit
)
620 -- OK, here comes the actual lib
622 -- pre-initialize the checkerLists here so that we can return some meaningful result even if
623 -- someone manages to call us before we're properly initialized. miscRC should be independent of
624 -- race/class/talents, so it's safe to initialize it here
625 -- friendRC and harmRC will be properly initialized later when we have all the necessary data for them
626 lib
.checkerCache_Spell
= lib
.checkerCache_Spell
or {}
627 lib
.checkerCache_Item
= lib
.checkerCache_Item
or {}
628 lib
.miscRC
= createCheckerList(nil, nil, DefaultInteractList
)
629 lib
.friendRC
= createCheckerList(nil, nil, DefaultInteractList
)
630 lib
.harmRC
= createCheckerList(nil, nil, DefaultInteractList
)
632 lib
.failedItemRequests
= {}
638 --- The callback name that is fired when checkers are changed.
640 lib
.CHECKERS_CHANGED
= "CHECKERS_CHANGED"
641 -- "export" it, maybe someone will need it for formatting
642 --- Constant for Melee range (5yd).
644 lib
.MeleeRange
= MeleeRange
646 function lib
:findSpellIndex(spell
)
647 if type(spell
) == 'number' then
648 spell
= GetSpellInfo(spell
)
650 if not spell
then return nil end
651 return findSpellIdx(spell
)
654 -- returns the range estimate as a string
655 -- deprecated, use :getRange(unit) instead and build your own strings
656 -- (checkVisible is not used any more, kept for compatibility only)
657 function lib
:getRangeAsString(unit
, checkVisible
, showOutOfRange
)
658 local minRange
, maxRange
= self
:getRange(unit
)
659 if not minRange
then return nil end
661 return showOutOfRange
and minRange
.. " +" or nil
663 return minRange
.. " - " .. maxRange
666 -- initialize RangeCheck if not yet initialized or if "forced"
667 function lib
:init(forced
)
668 if self
.initialized
and (not forced
) then return end
669 self
.initialized
= true
670 local _
, playerClass
= UnitClass("player")
671 local _
, playerRace
= UnitRace("player")
674 -- first try to find a nice item we can use for minRangeCheck
675 if HarmItems
[15] then
676 local items
= HarmItems
[15]
678 local item
= items
[i
]
679 if GetItemInfo(item
) then
680 minRangeCheck
= function(unit
)
681 return (IsItemInRange(item
, unit
) == 1)
687 if not minRangeCheck
then
688 -- ok, then try to find some class specific spell
689 if playerClass
== "WARRIOR" then
690 -- for warriors, use Intimidating Shout if available
691 local name
= GetSpellInfo(5246) -- ["Intimidating Shout"]
692 local spellIdx
= findSpellIdx(name
)
694 minRangeCheck
= function(unit
)
695 return (IsSpellInRange(spellIdx
, BOOKTYPE_SPELL
, unit
) == 1)
698 elseif playerClass
== "ROGUE" then
699 -- for rogues, use Blind if available
700 local name
= GetSpellInfo(2094) -- ["Blind"]
701 local spellIdx
= findSpellIdx(name
)
703 minRangeCheck
= function(unit
)
704 return (IsSpellInRange(spellIdx
, BOOKTYPE_SPELL
, unit
) == 1)
709 if not minRangeCheck
then
710 -- fall back to interact distance checks
711 if playerClass
== "HUNTER" or playerRace
== "Tauren" then
712 -- for hunters, use interact4 as it's safer
713 -- for Taurens interact4 is actually closer than 25yd and interact2 is closer than 8yd, so we can't use that
714 minRangeCheck
= checkers_Interact
[4]
716 minRangeCheck
= checkers_Interact
[2]
720 local interactList
= InteractLists
[playerRace
] or DefaultInteractList
721 self
.handSlotItem
= GetInventoryItemLink("player", HandSlotId
)
722 local changed
= false
723 if updateCheckers(self
.friendRC
, createCheckerList(FriendSpells
[playerClass
], FriendItems
, interactList
)) then
726 if updateCheckers(self
.harmRC
, createCheckerList(HarmSpells
[playerClass
], HarmItems
, interactList
)) then
729 if updateCheckers(self
.miscRC
, createCheckerList(nil, nil, interactList
)) then
732 if changed
and self
.callbacks
then
733 self
.callbacks
:Fire(self
.CHECKERS_CHANGED
)
737 --- Return an iterator for checkers usable on friendly units as (**range**, **checker**) pairs.
738 function lib
:GetFriendCheckers()
739 return rcIterator(self
.friendRC
)
742 --- Return an iterator for checkers usable on enemy units as (**range**, **checker**) pairs.
743 function lib
:GetHarmCheckers()
744 return rcIterator(self
.harmRC
)
747 --- Return an iterator for checkers usable on miscellaneous units as (**range**, **checker**) pairs. These units are neither enemy nor friendly, such as people in sanctuaries or corpses.
748 function lib
:GetMiscCheckers()
749 return rcIterator(self
.miscRC
)
752 --- Return a checker suitable for out-of-range checking on friendly units, that is, a checker whose range is equal or larger than the requested range.
753 -- @param range the range to check for.
754 -- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
755 function lib
:GetFriendMinChecker(range
)
756 return getMinChecker(self
.friendRC
, range
)
759 --- Return a checker suitable for out-of-range checking on enemy units, that is, a checker whose range is equal or larger than the requested range.
760 -- @param range the range to check for.
761 -- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
762 function lib
:GetHarmMinChecker(range
)
763 return getMinChecker(self
.harmRC
, range
)
766 --- Return a checker suitable for out-of-range checking on miscellaneous units, that is, a checker whose range is equal or larger than the requested range.
767 -- @param range the range to check for.
768 -- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
769 function lib
:GetMiscMinChecker(range
)
770 return getMinChecker(self
.miscRC
, range
)
773 --- Return a checker suitable for in-range checking on friendly units, that is, a checker whose range is equal or smaller than the requested range.
774 -- @param range the range to check for.
775 -- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
776 function lib
:GetFriendMaxChecker(range
)
777 return getMaxChecker(self
.friendRC
, range
)
780 --- Return a checker suitable for in-range checking on enemy units, that is, a checker whose range is equal or smaller than the requested range.
781 -- @param range the range to check for.
782 -- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
783 function lib
:GetHarmMaxChecker(range
)
784 return getMaxChecker(self
.harmRC
, range
)
787 --- Return a checker suitable for in-range checking on miscellaneous units, that is, a checker whose range is equal or smaller than the requested range.
788 -- @param range the range to check for.
789 -- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
790 function lib
:GetMiscMaxChecker(range
)
791 return getMaxChecker(self
.miscRC
, range
)
794 --- Return a checker for the given range for friendly units.
795 -- @param range the range to check for.
796 -- @return **checker** function or **nil** if no suitable checker is available.
797 function lib
:GetFriendChecker(range
)
798 return getChecker(self
.friendRC
, range
)
801 --- Return a checker for the given range for enemy units.
802 -- @param range the range to check for.
803 -- @return **checker** function or **nil** if no suitable checker is available.
804 function lib
:GetHarmChecker(range
)
805 return getChecker(self
.harmRC
, range
)
808 --- Return a checker for the given range for miscellaneous units.
809 -- @param range the range to check for.
810 -- @return **checker** function or **nil** if no suitable checker is available.
811 function lib
:GetMiscChecker(range
)
812 return getChecker(self
.miscRC
, range
)
815 --- Return a checker suitable for out-of-range checking that checks the unit type and calls the appropriate checker (friend/harm/misc).
816 -- @param range the range to check for.
817 -- @return **checker** function.
818 function lib
:GetSmartMinChecker(range
)
819 return createSmartChecker(
820 getMinChecker(self
.friendRC
, range
),
821 getMinChecker(self
.harmRC
, range
),
822 getMinChecker(self
.miscRC
, range
))
825 --- Return a checker suitable for in-of-range checking that checks the unit type and calls the appropriate checker (friend/harm/misc).
826 -- @param range the range to check for.
827 -- @return **checker** function.
828 function lib
:GetSmartMaxChecker(range
)
829 return createSmartChecker(
830 getMaxChecker(self
.friendRC
, range
),
831 getMaxChecker(self
.harmRC
, range
),
832 getMaxChecker(self
.miscRC
, range
))
835 --- Return a checker for the given range that checks the unit type and calls the appropriate checker (friend/harm/misc).
836 -- @param range the range to check for.
837 -- @param fallback optional fallback function that gets called as fallback(unit) if a checker is not available for the given type (friend/harm/misc) at the requested range. The default fallback function return nil.
838 -- @return **checker** function.
839 function lib
:GetSmartChecker(range
, fallback
)
840 return createSmartChecker(
841 getChecker(self
.friendRC
, range
) or fallback
,
842 getChecker(self
.harmRC
, range
) or fallback
,
843 getChecker(self
.miscRC
, range
) or fallback
)
846 --- Get a range estimate as **minRange**, **maxRange**.
847 -- @param unit the target unit to check range to.
848 -- @return **minRange**, **maxRange** pair if a range estimate could be determined, **nil** otherwise. **maxRange** is **nil** if **unit** is further away than the highest possible range we can check.
849 -- Includes checks for unit validity and friendly/enemy status.
851 -- local rc = LibStub("LibRangeCheck-2.0")
852 -- local minRange, maxRange = rc:GetRange('target')
853 function lib
:GetRange(unit
)
854 if not UnitExists(unit
) then
857 if UnitIsDeadOrGhost(unit
) then
858 return getRange(unit
, self
.miscRC
)
860 if UnitCanAttack("player", unit
) then
861 return getRange(unit
, self
.harmRC
)
862 elseif UnitCanAssist("player", unit
) then
863 return getRange(unit
, self
.friendRC
)
865 return getRange(unit
, self
.miscRC
)
869 -- keep this for compatibility
870 lib
.getRange
= lib
.GetRange
874 function lib
:OnEvent(event
, ...)
875 if type(self
[event
]) == 'function' then
876 self
[event
](self
, event
, ...)
880 function lib
:LEARNED_SPELL_IN_TAB()
884 function lib
:CHARACTER_POINTS_CHANGED()
888 function lib
:PLAYER_TALENT_UPDATE()
892 function lib
:GLYPH_ADDED()
896 function lib
:GLYPH_REMOVED()
900 function lib
:GLYPH_UPDATED()
904 function lib
:UNIT_INVENTORY_CHANGED(event
, unit
)
905 if self
.initialized
and unit
== "player" and self
.handSlotItem
~= GetInventoryItemLink("player", HandSlotId
) then
910 function lib
:processItemRequests(itemRequests
)
912 local range
, items
= next(itemRequests
)
913 if not range
then return end
915 local i
, item
= next(items
)
917 itemRequests
[range
] = nil
919 elseif self
.failedItemRequests
[item
] then
921 elseif GetItemInfo(item
) then
922 if itemRequestTimeoutAt
then
924 itemRequestTimeoutAt
= nil
926 if not cacheAllItems
then
927 itemRequests
[range
] = nil
931 elseif not itemRequestTimeoutAt
then
932 requestItemInfo(item
)
933 itemRequestTimeoutAt
= GetTime() + ItemRequestTimeout
935 elseif GetTime() > itemRequestTimeoutAt
then
936 if cacheAllItems
then
937 print(MAJOR_VERSION
.. ": timeout for item: " .. tostring(item
))
939 self
.failedItemRequests
[item
] = true
940 itemRequestTimeoutAt
= nil
943 return true -- still waiting for server response
949 function lib
:initialOnUpdate()
951 if friendItemRequests
then
952 if self
:processItemRequests(friendItemRequests
) then return end
953 friendItemRequests
= nil
955 if harmItemRequests
then
956 if self
:processItemRequests(harmItemRequests
) then return end
957 harmItemRequests
= nil
959 if foundNewItems
then
963 if cacheAllItems
then
964 print(MAJOR_VERSION
.. ": finished cache")
970 function lib
:scheduleInit()
971 self
.initialized
= nil
978 -- << load-time initialization
980 function lib
:activate()
981 if not self
.frame
then
982 local frame
= CreateFrame("Frame")
984 frame
:RegisterEvent("LEARNED_SPELL_IN_TAB")
985 frame
:RegisterEvent("CHARACTER_POINTS_CHANGED")
986 frame
:RegisterEvent("PLAYER_TALENT_UPDATE")
987 frame
:RegisterEvent("GLYPH_ADDED")
988 frame
:RegisterEvent("GLYPH_REMOVED")
989 frame
:RegisterEvent("GLYPH_UPDATED")
990 local _
, playerClass
= UnitClass("player")
991 if playerClass
== "MAGE" or playerClass
== "SHAMAN" then
992 -- Mage and Shaman gladiator gloves modify spell ranges
993 frame
:RegisterEvent("UNIT_INVENTORY_CHANGED")
997 self
.frame
:SetScript("OnEvent", function(frame
, ...) self
:OnEvent(...) end)
998 self
.frame
:SetScript("OnUpdate", function(frame
, elapsed
)
999 lastUpdate
= lastUpdate
+ elapsed
1000 if lastUpdate
< UpdateDelay
then
1004 self
:initialOnUpdate()
1009 --- BEGIN CallbackHandler stuff
1012 local lib
= lib
-- to keep a ref even though later we nil lib
1013 --- Register a callback to get called when checkers are updated
1015 -- @name lib.RegisterCallback
1017 -- rc.RegisterCallback(self, rc.CHECKERS_CHANGED, "myCallback")
1019 -- rc.RegisterCallback(self, "CHECKERS_CHANGED", someCallbackFunction)
1020 -- @see CallbackHandler-1.0 documentation for more details
1021 lib
.RegisterCallback
= lib
.RegisterCallback
or function(...)
1022 local CBH
= LibStub("CallbackHandler-1.0")
1023 lib
.RegisterCallback
= nil -- extra safety, we shouldn't get this far if CBH is not found, but better an error later than an infinite recursion now
1024 lib
.callbacks
= CBH
:New(lib
)
1025 -- ok, CBH hopefully injected or new shiny RegisterCallback
1026 return lib
.RegisterCallback(...)
1030 --- END CallbackHandler stuff