Restore Real Health Numbers and fix aura dragging
Restore Real Health Numbers as a standalone module with a lazy Vanilla health estimator fallback, keep Big Health presentation-only, clarify the module tooltip, and fix aura dragging for BuffButton0/BuffButton32/TempEnchant1 without StartMoving().
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
local _G = ShaguTweaks.GetGlobalEnv()
|
||||
|
||||
-- Real-health fallback for stock Vanilla servers.
|
||||
--
|
||||
-- Turtle WoW and some custom clients expose real UnitHealth/UnitHealthMax
|
||||
-- values directly. Stock 1.12 often exposes target health as 0..100 instead.
|
||||
-- Keep the original ShaguTweaks estimation idea, but leave it completely
|
||||
-- dormant until Real Health Numbers asks for it and only listen to combat/
|
||||
-- health events while the current target actually needs estimation.
|
||||
|
||||
local mobdb = {}
|
||||
local targetKey
|
||||
local damage = 0
|
||||
local percent = 0
|
||||
|
||||
local libhealth = CreateFrame("Frame")
|
||||
libhealth.enabled = false
|
||||
libhealth.reqhit = 2
|
||||
libhealth.reqdmg = 10
|
||||
|
||||
local function InitCache()
|
||||
ShaguTweaks_cache = ShaguTweaks_cache or {}
|
||||
ShaguTweaks_cache["libhealth"] = ShaguTweaks_cache["libhealth"] or {}
|
||||
mobdb = ShaguTweaks_cache["libhealth"]
|
||||
end
|
||||
|
||||
local function IsPercentHealth(unit)
|
||||
if not unit or not UnitExists(unit) then return false end
|
||||
|
||||
local cur = _G.UnitHealth(unit)
|
||||
local max = _G.UnitHealthMax(unit)
|
||||
|
||||
return cur ~= nil and max == 100 and cur <= 100
|
||||
end
|
||||
|
||||
local function StopSampling()
|
||||
libhealth:UnregisterEvent("UNIT_COMBAT")
|
||||
libhealth:UnregisterEvent("UNIT_HEALTH")
|
||||
end
|
||||
|
||||
local function StartSampling()
|
||||
libhealth:RegisterEvent("UNIT_COMBAT")
|
||||
libhealth:RegisterEvent("UNIT_HEALTH")
|
||||
end
|
||||
|
||||
local function SelectTarget()
|
||||
StopSampling()
|
||||
|
||||
damage = 0
|
||||
percent = _G.UnitHealth("target") or 0
|
||||
targetKey = nil
|
||||
|
||||
if not IsPercentHealth("target") then return end
|
||||
|
||||
local name = UnitName("target")
|
||||
local level = UnitLevel("target")
|
||||
if not name or not level then return end
|
||||
|
||||
targetKey = string.format("%s:%s", name, level)
|
||||
StartSampling()
|
||||
end
|
||||
|
||||
local function GetCachedHealth(unitstr, cur, max)
|
||||
local name = UnitName(unitstr)
|
||||
local level = UnitLevel(unitstr)
|
||||
if not name or not level then return cur, max end
|
||||
|
||||
local key = string.format("%s:%s", name, level)
|
||||
local data = mobdb[key]
|
||||
if data and data[1] and data[2]
|
||||
and data[2] > libhealth.reqdmg
|
||||
and (not data[3] or data[3] > libhealth.reqhit) then
|
||||
return ceil(data[1] / 100 * cur), data[1], true
|
||||
end
|
||||
|
||||
return cur, max
|
||||
end
|
||||
|
||||
-- ClassicAPI can expose the real health deficit even when stock UnitHealth()
|
||||
-- still reports a percentage. Use that as an immediate estimate when possible.
|
||||
-- At 100% there is no deficit to derive a maximum from, so the historical
|
||||
-- combat estimator/cache remains useful.
|
||||
local function GetMissingHealthEstimate(unitstr, cur, max)
|
||||
if max ~= 100 or cur >= 100 then return end
|
||||
if type(_G.UnitHealthMissing) ~= "function" then return end
|
||||
|
||||
local missing = _G.UnitHealthMissing(unitstr)
|
||||
local lostPercent = 100 - cur
|
||||
if not missing or missing <= 0 or lostPercent <= 0 then return end
|
||||
|
||||
local estimatedMax = ceil(missing / lostPercent * 100)
|
||||
if estimatedMax < 100 then return end
|
||||
|
||||
local estimatedCur = estimatedMax - missing
|
||||
if estimatedCur < 0 then estimatedCur = 0 end
|
||||
|
||||
return estimatedCur, estimatedMax, true
|
||||
end
|
||||
|
||||
function libhealth:GetUnitHealth(unitstr)
|
||||
-- Preserve the old public library behavior for external consumers while
|
||||
-- keeping the estimator lazy: the first actual query activates it.
|
||||
if not self.enabled then self:Enable() end
|
||||
|
||||
local cur = _G.UnitHealth(unitstr)
|
||||
local max = _G.UnitHealthMax(unitstr)
|
||||
|
||||
if not cur or not max then return cur or 0, max or 0 end
|
||||
|
||||
-- Real values are already available: do not estimate.
|
||||
if cur > 100 or max > 100 or max < 100 then
|
||||
return cur, max, true
|
||||
end
|
||||
|
||||
local missingCur, missingMax, missingKnown =
|
||||
GetMissingHealthEstimate(unitstr, cur, max)
|
||||
if missingKnown then
|
||||
return missingCur, missingMax, true
|
||||
end
|
||||
|
||||
return GetCachedHealth(unitstr, cur, max)
|
||||
end
|
||||
|
||||
function libhealth:GetUnitHealthByName(name, level, cur, max)
|
||||
if not self.enabled then self:Enable() end
|
||||
|
||||
if not cur or not max then return cur or 0, max or 0 end
|
||||
|
||||
if cur > 100 or max > 100 or max < 100 then
|
||||
return cur, max, true
|
||||
end
|
||||
|
||||
if not name or not level then return cur, max end
|
||||
|
||||
local key = string.format("%s:%s", name, level)
|
||||
local data = mobdb[key]
|
||||
if data and data[1] and data[2]
|
||||
and data[2] > libhealth.reqdmg
|
||||
and (not data[3] or data[3] > libhealth.reqhit) then
|
||||
return ceil(data[1] / 100 * cur), data[1], true
|
||||
end
|
||||
|
||||
return cur, max
|
||||
end
|
||||
|
||||
function libhealth:Enable()
|
||||
if self.enabled then return end
|
||||
self.enabled = true
|
||||
|
||||
InitCache()
|
||||
|
||||
self:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
self:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||
SelectTarget()
|
||||
end
|
||||
|
||||
function libhealth:Disable()
|
||||
if not self.enabled then return end
|
||||
self.enabled = false
|
||||
|
||||
self:UnregisterAllEvents()
|
||||
targetKey = nil
|
||||
damage = 0
|
||||
percent = 0
|
||||
end
|
||||
|
||||
libhealth:SetScript("OnEvent", function()
|
||||
if not libhealth.enabled then return end
|
||||
|
||||
if event == "PLAYER_ENTERING_WORLD" then
|
||||
InitCache()
|
||||
SelectTarget()
|
||||
elseif event == "PLAYER_TARGET_CHANGED" then
|
||||
SelectTarget()
|
||||
elseif targetKey and event == "UNIT_COMBAT" and arg1 == "target" then
|
||||
if arg2 == "HEAL" then return end
|
||||
|
||||
local amount = tonumber(arg4) or 0
|
||||
if amount > 0 then
|
||||
damage = damage + amount
|
||||
end
|
||||
elseif targetKey and event == "UNIT_HEALTH" and arg1 == "target" then
|
||||
local currentPercent = _G.UnitHealth("target") or 0
|
||||
local diff = percent - currentPercent
|
||||
|
||||
if damage > 0 and diff > 0 then
|
||||
local estimate = ceil(damage / diff * 100)
|
||||
local data = mobdb[targetKey]
|
||||
|
||||
if not data or not data[2] or diff > data[2] then
|
||||
mobdb[targetKey] = {
|
||||
estimate,
|
||||
diff,
|
||||
data and data[3] and data[3] + 1 or 1,
|
||||
}
|
||||
elseif data then
|
||||
data[3] = data[3] and data[3] + 1 or 1
|
||||
end
|
||||
end
|
||||
|
||||
damage = 0
|
||||
percent = currentPercent
|
||||
end
|
||||
end)
|
||||
|
||||
ShaguTweaks.libhealth = libhealth
|
||||
Reference in New Issue
Block a user