152 lines
4.5 KiB
Lua
152 lines
4.5 KiB
Lua
-- ScaledLifeTap 4.1 - embedded gear scanner
|
|
-- A trimmed-down replacement for BonusScanner that only totals spell damage
|
|
-- and shadow damage. It scans lazily: equipment changes just mark the cache
|
|
-- dirty, and the actual tooltip scan happens the next time Life Tap is cast.
|
|
-- No OnUpdate handler, no per-frame work.
|
|
|
|
local L = SCALEDLIFETAP_L
|
|
local Scanner = {}
|
|
ScaledLifeTap_Scanner = Scanner
|
|
|
|
-- equipment slot ids worth scanning (shirt=4 and tabard=19 never carry spell damage)
|
|
local SLOTS = { 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }
|
|
local MAX_AGE = 60 -- seconds; safety net for temporary enchants (wizard oil) expiring
|
|
|
|
local TIPNAME = "ScaledLifeTapScanTip"
|
|
local tip, lines
|
|
local dirty = true
|
|
local lastScan = -1000
|
|
local dmg, shadow = 0, 0
|
|
|
|
-- per-scan state
|
|
local curSet, countedSets = nil, {}
|
|
|
|
local find, sub, len, gsub = string.find, string.sub, string.len, string.gsub
|
|
local EQUIP, SET = L.EQUIP, L.SET
|
|
local EQUIP_LEN, SET_LEN = string.len(L.EQUIP), string.len(L.SET)
|
|
|
|
local function add(kind, value)
|
|
value = tonumber(value)
|
|
if not value then return end
|
|
if kind == "D" then dmg = dmg + value elseif kind == "S" then shadow = shadow + value end
|
|
end
|
|
|
|
local function trim(s)
|
|
s = gsub(s, "^%s+", "")
|
|
s = gsub(s, "%s+$", "")
|
|
s = gsub(s, "%.$", "")
|
|
return s
|
|
end
|
|
|
|
-- "Shadow Damage", "Fire Damage", ... (BonusScanner's stage1/stage2 composite match)
|
|
local function checkToken(token, value)
|
|
local kind = L.LOOKUP[token]
|
|
if kind then add(kind, value); return true end
|
|
local school
|
|
for i = 1, table.getn(L.STAGE1) do
|
|
if find(token, L.STAGE1[i][1], 1, 1) then school = L.STAGE1[i][2] end
|
|
end
|
|
if not school then return false end
|
|
for i = 1, table.getn(L.STAGE2) do
|
|
if find(token, L.STAGE2[i], 1, 1) then
|
|
if school == "SHADOW" then add("S", value) end
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- "+30 Spell Damage", "Shadow Damage +20", "+8 Spell Damage and Healing/+5 Stamina"
|
|
local function checkGeneric(line)
|
|
local found = false
|
|
while len(line) > 0 do
|
|
local part
|
|
local pos = find(line, "/", 1, true)
|
|
if pos then part, line = sub(line, 1, pos - 1), sub(line, pos + 1) else part, line = line, "" end
|
|
part = trim(part)
|
|
local _, _, value, token = find(part, "^%+(%d+)%%?(.*)$")
|
|
if not value then _, _, token, value = find(part, "^(.*)%+(%d+)%%?$") end
|
|
if token and value and checkToken(trim(token), value) then found = true end
|
|
end
|
|
return found
|
|
end
|
|
|
|
local function checkPassive(text)
|
|
for i = 1, table.getn(L.PASSIVE) do
|
|
local _, _, value = find(text, L.PASSIVE[i][1])
|
|
if value then add(L.PASSIVE[i][2], value); return end
|
|
end
|
|
checkGeneric(text)
|
|
end
|
|
|
|
local function checkOther(line)
|
|
for i = 1, table.getn(L.OTHER) do
|
|
if find(line, L.OTHER[i][1]) then add("D", L.OTHER[i][2]); return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function scanLine(line)
|
|
if sub(line, 1, EQUIP_LEN) == EQUIP then
|
|
checkPassive(sub(line, EQUIP_LEN + 1))
|
|
elseif sub(line, 1, SET_LEN) == SET then
|
|
-- only active set bonuses start with "Set: "; count each set once
|
|
if curSet and not countedSets[curSet] then checkPassive(sub(line, SET_LEN + 1)) end
|
|
else
|
|
local _, _, setName = find(line, L.SETNAME)
|
|
if setName then
|
|
curSet = setName
|
|
elseif not checkGeneric(line) then
|
|
checkOther(line)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function ensureTooltip()
|
|
if tip then return end
|
|
tip = CreateFrame("GameTooltip", TIPNAME, nil, "GameTooltipTemplate")
|
|
lines = {}
|
|
for i = 1, 30 do lines[i] = getglobal(TIPNAME .. "TextLeft" .. i) end
|
|
end
|
|
|
|
function Scanner:Scan()
|
|
ensureTooltip()
|
|
dmg, shadow = 0, 0
|
|
for k in pairs(countedSets) do countedSets[k] = nil end
|
|
for s = 1, table.getn(SLOTS) do
|
|
tip:SetOwner(WorldFrame or UIParent, "ANCHOR_NONE")
|
|
tip:ClearLines()
|
|
curSet = nil
|
|
if tip:SetInventoryItem("player", SLOTS[s]) then
|
|
local n = tip:NumLines()
|
|
if n > 30 then n = 30 end
|
|
for i = 2, n do
|
|
local fs = lines[i]
|
|
local text = fs and fs:GetText()
|
|
if text then scanLine(text) end
|
|
end
|
|
if curSet then countedSets[curSet] = true end
|
|
end
|
|
end
|
|
tip:Hide()
|
|
dirty = false
|
|
lastScan = GetTime()
|
|
end
|
|
|
|
function Scanner:MarkDirty() dirty = true end
|
|
|
|
-- returns generic spell damage, shadow spell damage
|
|
function Scanner:Get()
|
|
if dirty or (GetTime() - lastScan) > MAX_AGE then self:Scan() end
|
|
return dmg, shadow
|
|
end
|
|
|
|
-- exposed for tests / debugging: parse arbitrary tooltip lines
|
|
function Scanner:ParseLines(list)
|
|
dmg, shadow, curSet = 0, 0, nil
|
|
for k in pairs(countedSets) do countedSets[k] = nil end
|
|
for i = 1, table.getn(list) do scanLine(list[i]) end
|
|
dirty = true
|
|
return dmg, shadow
|
|
end
|