diff --git a/api/api.lua b/api/api.lua index d5cb942a..076a8e79 100644 --- a/api/api.lua +++ b/api/api.lua @@ -27,10 +27,8 @@ function pfUI.api.UnitInRange(unit) return nil elseif CheckInteractDistance(unit, 4) then return 1 - elseif pfUI.rangecheck then - return pfUI.rangecheck:UnitInSpellRange(unit) else - return nil + return librange:UnitInSpellRange(unit) end end diff --git a/libs/librange.lua b/libs/librange.lua new file mode 100644 index 00000000..0817da7e --- /dev/null +++ b/libs/librange.lua @@ -0,0 +1,186 @@ +-- load pfUI environment +setfenv(1, pfUI:GetEnvironment()) + +--[[ librange ]]-- +-- A pfUI library that detects and caches distance to units. +-- +-- librange:UnitInSpellRange(unit) +-- Returns `1` if the unit is within a 40y range +-- + +local librange = CreateFrame("Frame", "pfRangecheck", UIParent) + +-- table of 40y spells per class +local spells = { + ["PALADIN"] = { + "Interface\\Icons\\Spell_Holy_FlashHeal", + "Interface\\Icons\\Spell_Holy_HolyBolt", + }, + ["PRIEST"] = { + "Interface\\Icons\\Spell_Holy_FlashHeal", + "Interface\\Icons\\Spell_Holy_LesserHeal", + "Interface\\Icons\\Spell_Holy_Heal", + "Interface\\Icons\\Spell_Holy_GreaterHeal", + "Interface\\Icons\\Spell_Holy_Renew", + }, + ["DRUID"] = { + "Interface\\Icons\\Spell_Nature_HealingTouch", + "Interface\\Icons\\Spell_Nature_ResistNature", + "Interface\\Icons\\Spell_Nature_Rejuvenation", + }, + ["SHAMAN"] = { + "Interface\\Icons\\Spell_Nature_MagicImmunity", + "Interface\\Icons\\Spell_Nature_HealingWaveLesser", + "Interface\\Icons\\Spell_Nature_HealingWaveGreater", + }, +} + +-- units that should be scanned +local units = {} +table.insert(units, "pet") +for i=1,4 do table.insert(units, "party" .. i) end +for i=1,4 do table.insert(units, "partypet" .. i) end +for i=1,40 do table.insert(units, "raid" .. i) end +for i=1,40 do table.insert(units, "raidpet" .. i) end +local numunits = table.getn(units) + +-- cache for unit relations +local unitcache = {} + +-- actual unit-range table +local unitdata = { } + +librange.id = 1 + +librange:Hide() +librange:RegisterEvent("ACTIONBAR_SLOT_CHANGED") +librange:RegisterEvent("PLAYER_ENTERING_WORLD") +librange:RegisterEvent("PLAYER_ENTER_COMBAT") +librange:RegisterEvent("PLAYER_LEAVE_COMBAT") +librange:SetScript("OnEvent", function() + local _, class = UnitClass("player") + + -- disable range checking activities + if C.unitframes.rangecheck == "0" or not spells[class] then + this:Hide() + return + end + + this.interval = tonumber(C.unitframes.rangechecki)/numunits + + if event == "ACTIONBAR_SLOT_CHANGED" or event == "PLAYER_ENTERING_WORLD" then + librange.slot = this:GetRangeSlot() + elseif event == "PLAYER_ENTER_COMBAT" then + this.lastattack = GetTime() + this:Hide() + elseif event == "PLAYER_LEAVE_COMBAT" then + if not this:ReAttack() then + this:Show() + end + end +end) + +librange:SetScript("OnUpdate", function() + if ( this.tick or 1) > GetTime() then + return + else + this.tick = GetTime() + this.interval + end + + -- skip invalid units + while not this:NeedRangeScan(units[this.id]) and this.id <= numunits do + this.id = this.id + 1 + end + + if this.id <= numunits and librange.slot then + local unit = units[this.id] + if not UnitIsUnit("target", unit) then + -- suspend for various conditions + if pfUI.loot and pfUI.loot:IsShown() then return nil end + if LootFrame and LootFrame:IsShown() then return nil end + if InspectFrame and InspectFrame:IsShown() then return nil end + if TradeFrame and TradeFrame:IsShown() then return nil end + + pfScanActive = true + TargetUnit(unit) + unitdata[unit] = IsActionInRange(librange.slot) + TargetLastTarget() + pfScanActive = false + this:ReAttack() + end + + this.id = this.id + 1 + else + this.id = 1 + end +end) + +function librange:ReAttack() + -- we accidentally broke the autoattack... restoring the old state + if this.lastattack and this.lastattack + this.interval > GetTime() and UnitCanAttack("player", "target") then + AttackTarget() + return true + else + return nil + end +end + +function librange:NeedRangeScan(unit) + if not UnitExists(unit) then return nil end + if not UnitIsVisible(unit) then return nil end + if CheckInteractDistance(unit, 4) then return nil end + return true +end + +function librange:GetRealUnit(unit) + if unitdata[unit] then return unit end + + if unitcache[unit] then + if UnitIsUnit(unitcache[unit], unit) then + return unitcache[unit] + end + end + + for id, realunit in pairs(units) do + if UnitIsUnit(realunit, unit) then + unitcache[unit] = realunit + return realunit + end + end + + return unit +end + +function librange:GetRangeSlot() + for i=1,120 do + local texture = GetActionTexture(i) + for _, check in pairs(spells[class]) do + if check == texture then + return i + end + end + end + + return nil +end + +function librange:UnitInSpellRange(unit) + if not librange.slot then return nil end + + if UnitIsUnit("target", unit) then + return IsActionInRange(librange.slot) == 1 and 1 or nil + end + + local unit = librange:GetRealUnit(unit) + + if unitdata[unit] and unitdata[unit] == 1 then + return 1 + elseif not unitdata[unit] then + return 1 + else + return nil + end +end + +-- add libdebuff to pfUI API +pfUI.api.librange = librange diff --git a/modules/rangecheck.lua b/modules/rangecheck.lua index 5f0d8860..e69de29b 100644 --- a/modules/rangecheck.lua +++ b/modules/rangecheck.lua @@ -1,171 +0,0 @@ -pfUI:RegisterModule("rangecheck", function () - - if C.unitframes.rangecheck == "0" then return end - - -- table of 40y spells per class - local spells = { - ["PALADIN"] = { - "Interface\\Icons\\Spell_Holy_FlashHeal", - "Interface\\Icons\\Spell_Holy_HolyBolt", - }, - ["PRIEST"] = { - "Interface\\Icons\\Spell_Holy_FlashHeal", - "Interface\\Icons\\Spell_Holy_LesserHeal", - "Interface\\Icons\\Spell_Holy_Heal", - "Interface\\Icons\\Spell_Holy_GreaterHeal", - "Interface\\Icons\\Spell_Holy_Renew", - }, - ["DRUID"] = { - "Interface\\Icons\\Spell_Nature_HealingTouch", - "Interface\\Icons\\Spell_Nature_ResistNature", - "Interface\\Icons\\Spell_Nature_Rejuvenation", - }, - ["SHAMAN"] = { - "Interface\\Icons\\Spell_Nature_MagicImmunity", - "Interface\\Icons\\Spell_Nature_HealingWaveLesser", - "Interface\\Icons\\Spell_Nature_HealingWaveGreater", - }, - } - - local _, class = UnitClass("player") - if not spells[class] then return end - - -- units that should be scanned - local units = {} - table.insert(units, "pet") - for i=1,4 do table.insert(units, "party" .. i) end - for i=1,4 do table.insert(units, "partypet" .. i) end - for i=1,40 do table.insert(units, "raid" .. i) end - for i=1,40 do table.insert(units, "raidpet" .. i) end - local numunits = table.getn(units) - - -- cache for unit relations - local unitcache = {} - - -- actual unit-range table - local unitdata = { } - - -- the interval between each range check - local interval = tonumber(C.unitframes.rangechecki)/numunits - - pfUI.rangecheck = CreateFrame("Frame", "pfRangecheck", UIParent) - pfUI.rangecheck.id = 1 - pfUI.rangecheck:RegisterEvent("ACTIONBAR_SLOT_CHANGED") - pfUI.rangecheck:RegisterEvent("PLAYER_ENTERING_WORLD") - pfUI.rangecheck:RegisterEvent("PLAYER_ENTER_COMBAT") - pfUI.rangecheck:RegisterEvent("PLAYER_LEAVE_COMBAT") - pfUI.rangecheck:SetScript("OnEvent", function() - if event == "ACTIONBAR_SLOT_CHANGED" or event == "PLAYER_ENTERING_WORLD" then - pfUI.rangecheck.slot = this:GetRangeSlot() - elseif event == "PLAYER_ENTER_COMBAT" then - this.lastattack = GetTime() - this:Hide() - elseif event == "PLAYER_LEAVE_COMBAT" then - if not this:ReAttack() then - this:Show() - end - end - end) - - pfUI.rangecheck:SetScript("OnUpdate", function() - if ( this.tick or 1) > GetTime() then - return - else - this.tick = GetTime() + interval - end - - -- skip invalid units - while not this:NeedRangeScan(units[this.id]) and this.id <= numunits do - this.id = this.id + 1 - end - - if this.id <= numunits and pfUI.rangecheck.slot then - local unit = units[this.id] - if not UnitIsUnit("target", unit) then - -- suspend for various conditions - if pfUI.loot and pfUI.loot:IsShown() then return nil end - if LootFrame and LootFrame:IsShown() then return nil end - if InspectFrame and InspectFrame:IsShown() then return nil end - if TradeFrame and TradeFrame:IsShown() then return nil end - - pfScanActive = true - TargetUnit(unit) - unitdata[unit] = IsActionInRange(pfUI.rangecheck.slot) - TargetLastTarget() - pfScanActive = false - this:ReAttack() - end - - this.id = this.id + 1 - else - this.id = 1 - end - end) - - function pfUI.rangecheck:ReAttack() - -- we accidentally broke the autoattack... restoring the old state - if this.lastattack and this.lastattack + interval > GetTime() and UnitCanAttack("player", "target") then - AttackTarget() - return true - else - return nil - end - end - - function pfUI.rangecheck:NeedRangeScan(unit) - if not UnitExists(unit) then return nil end - if not UnitIsVisible(unit) then return nil end - if CheckInteractDistance(unit, 4) then return nil end - return true - end - - function pfUI.rangecheck:GetRealUnit(unit) - if unitdata[unit] then return unit end - - if unitcache[unit] then - if UnitIsUnit(unitcache[unit], unit) then - return unitcache[unit] - end - end - - for id, realunit in pairs(units) do - if UnitIsUnit(realunit, unit) then - unitcache[unit] = realunit - return realunit - end - end - - return unit - end - - function pfUI.rangecheck:GetRangeSlot() - for i=1,120 do - local texture = GetActionTexture(i) - for _, check in pairs(spells[class]) do - if check == texture then - return i - end - end - end - - return nil - end - - function pfUI.rangecheck:UnitInSpellRange(unit) - if not pfUI.rangecheck.slot then return nil end - - if UnitIsUnit("target", unit) then - return IsActionInRange(pfUI.rangecheck.slot) == 1 and 1 or nil - end - - local unit = pfUI.rangecheck:GetRealUnit(unit) - - if unitdata[unit] and unitdata[unit] == 1 then - return 1 - elseif not unitdata[unit] then - return 1 - else - return nil - end - end -end) diff --git a/pfUI.toc b/pfUI.toc index eab16bc4..4b0a0b4b 100644 --- a/pfUI.toc +++ b/pfUI.toc @@ -42,6 +42,7 @@ api\unitframes.lua # libs libs\libcast.lua libs\libdebuff.lua +libs\librange.lua # modules modules\firstrun.lua @@ -51,7 +52,6 @@ modules\hoverbind.lua modules\updatenotify.lua modules\actionbar.lua modules\hunterbar.lua -modules\rangecheck.lua modules\chat.lua modules\bubbles.lua modules\addons.lua