Files
SuperCleveRoidMacros/Extensions/Tooltip/Generic.lua
T

544 lines
18 KiB
Lua

--[[
Author: Dennis Werner Garske (DWG) / brian / Mewtiny
License: MIT License
]]
local _G = _G or getfenv(0)
local CleveRoids = _G.CleveRoids or {}
-- PERFORMANCE: Upvalues for frequently called functions
local GetTime = GetTime
local GetContainerItemLink = GetContainerItemLink
local GetContainerItemInfo = GetContainerItemInfo
local GetContainerNumSlots = GetContainerNumSlots
local GetInventoryItemLink = GetInventoryItemLink
local GetInventoryItemTexture = GetInventoryItemTexture
local GetInventoryItemCount = GetInventoryItemCount
local GetItemInfo = GetItemInfo
local GetSpellName = GetSpellName
local GetSpellTexture = GetSpellTexture
local tonumber = tonumber
local type = type
local pairs = pairs
local string_find = string.find
local string_lower = string.lower
local string_gsub = string.gsub
local table_insert = table.insert
local table_getn = table.getn
-- Indexes all spells the current player and pet knows
function CleveRoids.IndexSpells()
local spells = {}
local i = 0
local book = 1
local bookType = CleveRoids.bookTypes[book]
local maxBooks = table.getn(CleveRoids.bookTypes)
spells[bookType] = {}
while true do
i = i + 1
local spellName, spellRank = GetSpellName(i, bookType)
if not spellName then
i = 0
book = book + 1
if book > maxBooks then
break
end
bookType = CleveRoids.bookTypes[book]
spells[bookType] = {}
else
local cost, reagent = CleveRoids.GetSpellCost(i, bookType)
local texture = GetSpellTexture(i, bookType)
if not spells[bookType][spellName] then
spells[bookType][spellName] = {
spellSlot = i,
name = spellName,
bookType = bookType,
texture = texture,
cost = cost,
reagent = reagent,
}
end
if spellRank and not spells[bookType][spellName][spellRank] then
spells[bookType][spellName][spellRank] = {
spellSlot = i,
name = spellName,
rank = spellRank,
bookType = bookType,
texture = texture,
cost = cost,
reagent = reagent
}
spells[bookType][spellName].highest = spells[bookType][spellName][spellRank]
end
if reagent then
CleveRoids.countedItemTypes[reagent] = true
end
end
end
CleveRoids.Spells = spells
end
-- Indexes all pet spells and their action bar slots
function CleveRoids.IndexPetSpells()
local petSpells = {}
if not UnitExists("pet") then
CleveRoids.PetSpells = petSpells
return
end
for i = 1, NUM_PET_ACTION_SLOTS do
local name, subtext, texture, isToken = GetPetActionInfo(i)
if name and not isToken then
-- Store the spell name and its slot
petSpells[name] = {
slot = i,
name = name,
subtext = subtext,
texture = texture
}
end
end
CleveRoids.PetSpells = petSpells
end
-- Gets a pet spell by name
function CleveRoids.GetPetSpell(spellName)
if not spellName or not CleveRoids.PetSpells then
return nil
end
spellName = CleveRoids.Trim(spellName)
return CleveRoids.PetSpells[spellName]
end
function CleveRoids.IndexTalents()
local talents = {[1] = true}
for tab = 1, GetNumTalentTabs() do
for i = 1, GetNumTalents(tab) do
local name, _, _, _, rank = GetTalentInfo(tab, i)
talents[name] = tonumber(rank)
end
end
CleveRoids.Talents = talents
end
-- Lightweight equipment-only indexing for combat situations
-- Updates existing cache rather than rebuilding it
function CleveRoids.IndexEquippedItems()
local items = CleveRoids.Items or {}
for inventoryID = 0, 19 do
local link = GetInventoryItemLink("player", inventoryID)
if link then
local _, _, itemID = string.find(link, "item:(%d+)")
local name, link, _, _, itemType, itemSubType, _, _, texture = GetItemInfo(itemID)
if name then
local count = GetInventoryItemCount("player", inventoryID)
if not items[name] then
items[name] = {
inventoryID = inventoryID,
id = itemID,
name = name,
count = count,
texture = texture,
link = link,
}
items[itemID] = name
local lowerName = string.lower(name)
if lowerName ~= name then
items[lowerName] = name
end
else
-- Update existing entry with current equipment state
items[name].inventoryID = inventoryID
items[name].count = count
end
end
else
-- Slot is now empty - clear inventoryID from any item that was there
-- This is handled lazily by GetItem() fallback, so we skip expensive iteration
end
end
CleveRoids.lastGetItem = nil
CleveRoids.Items = items
end
function CleveRoids.IndexItems()
local items = {}
local NUM_BAG_SLOTS = NUM_BAG_SLOTS -- Upvalue for bag constant
-- Scan bags (reverse order to prefer first stack)
for bagID = 0, NUM_BAG_SLOTS do
local numSlots = GetContainerNumSlots(bagID)
for slot = numSlots, 1, -1 do
local link = GetContainerItemLink(bagID, slot)
if link then
local _, _, itemID = string_find(link, "item:(%d+)")
local name, itemLink, _, _, itemType, itemSubType, _, _, texture = GetItemInfo(itemID)
if name then
local _, count = GetContainerItemInfo(bagID, slot)
local existing = items[name]
if not existing then
items[name] = {
bagID = bagID,
slot = slot,
id = itemID,
name = name,
type = itemType,
count = count,
texture = texture,
link = itemLink,
bagSlots = {{bagID, slot}},
slotsIndex = 1,
}
items[itemID] = name
local lowerName = string_lower(name)
if lowerName ~= name then
items[lowerName] = name
end
else
existing.count = (existing.count or 0) + (count or 0)
table_insert(existing.bagSlots, {bagID, slot})
end
end
end
end
end
-- Scan equipped items
for inventoryID = 0, 19 do
local link = GetInventoryItemLink("player", inventoryID)
if link then
local _, _, itemID = string_find(link, "item:(%d+)")
local name, itemLink, _, _, itemType, itemSubType, _, _, texture = GetItemInfo(itemID)
if name then
local count = GetInventoryItemCount("player", inventoryID)
local existing = items[name]
if not existing then
items[name] = {
inventoryID = inventoryID,
id = itemID,
name = name,
count = count,
texture = texture,
link = itemLink,
}
items[itemID] = name
local lowerName = string_lower(name)
if lowerName ~= name then
items[lowerName] = name
end
else
existing.inventoryID = inventoryID
existing.count = (existing.count or 0) + (count or 0)
end
end
end
end
CleveRoids.lastGetItem = nil
CleveRoids.Items = items
-- relink an item action to the item if it wasn't in inventory/bags before
for slot, actions in CleveRoids.Actions do
for i, action in actions.list do
if action.item then
action.item = CleveRoids.GetItem(action.action)
end
end
end
end
function CleveRoids.ClearSlot(slots, slot)
if slots[slot] then
slots[slots[slot]] = nil
end
slots[slot] = nil
end
-- Local helper for 1.12.1: safely get action button info via tooltip
function CleveRoids.GetActionButtonInfo(slot)
if not CleveRoidsActionTooltip then
CreateFrame("GameTooltip", "CleveRoidsActionTooltip", UIParent, "GameTooltipTemplate")
end
local tooltip = CleveRoidsActionTooltip
tooltip:SetOwner(UIParent, "ANCHOR_NONE")
tooltip:ClearLines()
tooltip:SetAction(slot)
local name, rank
local text = _G["CleveRoidsActionTooltipTextLeft1"]
if text then name = text:GetText() end
local text2 = _G["CleveRoidsActionTooltipTextLeft2"]
if text2 then
local maybeRank = text2:GetText()
-- Rank lines usually start with "Rank"
if maybeRank and string.find(maybeRank, "Rank") then
rank = maybeRank
end
end
-- Determine if it's an item or spell based on texture (heuristic)
local tex = GetActionTexture(slot)
local actionType = tex and "SPELL" or "ITEM"
return actionType, tex, name, rank
end
function CleveRoids.IndexActionSlot(slot)
if not HasAction(slot) then
CleveRoids.Actions[slot] = nil
-- When clearing a reactive slot, check if we need to find it elsewhere
local clearedReactiveName = CleveRoids.reactiveSlots[slot]
CleveRoids.ClearSlot(CleveRoids.reactiveSlots, slot)
CleveRoids.ClearSlot(CleveRoids.actionSlots, slot)
-- If we cleared a reactive spell, rescan to find it in another slot
if clearedReactiveName then
for i = 1, 120 do
if i ~= slot and HasAction(i) then
local _, _, scanName = CleveRoids.GetActionButtonInfo(i)
if scanName == clearedReactiveName then
CleveRoids.reactiveSlots[clearedReactiveName] = i
CleveRoids.reactiveSlots[i] = clearedReactiveName
break
end
end
end
end
else
local actionType, _, name, rank = CleveRoids.GetActionButtonInfo(slot)
if name then
local reactiveName = CleveRoids.reactiveSpells[name] and name
local actionSlotName = name..(rank and ("("..rank..")") or "")
if reactiveName then
-- Always update the mapping to ensure we track the correct slot
-- Clear old mapping for this spell name first
local oldSlot = CleveRoids.reactiveSlots[reactiveName]
if oldSlot and oldSlot ~= slot then
CleveRoids.reactiveSlots[oldSlot] = nil
end
CleveRoids.reactiveSlots[reactiveName] = slot
CleveRoids.reactiveSlots[slot] = reactiveName
elseif not reactiveName then
CleveRoids.ClearSlot(CleveRoids.reactiveSlots, slot)
end
if actionType == "SPELL" or actionType == "ITEM" then
if not CleveRoids.actionSlots[actionSlotName] then
CleveRoids.actionSlots[actionSlotName] = slot
CleveRoids.actionSlots[slot] = actionSlotName
end
end
end
end
CleveRoids.TestForActiveAction(CleveRoids.GetAction(slot))
CleveRoids.SendEventForAction(slot, "ACTIONBAR_SLOT_CHANGED", slot)
end
function CleveRoids.IndexActionBars()
for i = 1, 120 do
CleveRoids.IndexActionSlot(i)
end
end
function CleveRoids.GetSpell(text)
text = CleveRoids.Trim(text)
local rs, _, rank = string.find(text, "[^%s]%((Rank %d+)%)$")
local name = rank and string.sub(text, 1, rs) or text
for book, spells in CleveRoids.Spells do
if spells and spells[name] then
return spells[name][rank or "highest"]
end
end
end
function CleveRoids.GetTalent(text)
text = CleveRoids.Trim(text)
return CleveRoids.Talents[text]
end
-- PERFORMANCE: Helper functions defined once (not inline per-call)
local function makeInventoryItem(inventoryID, link, Items)
if not link then link = GetInventoryItemLink("player", inventoryID) end
if not link then return end
local _, _, itemID = string_find(link, "item:(%d+)")
itemID = itemID and tonumber(itemID) or nil
local name = itemID and GetItemInfo(itemID) or nil
local texture = GetInventoryItemTexture("player", inventoryID)
local count = GetInventoryItemCount("player", inventoryID)
local it = {
inventoryID = inventoryID,
id = itemID,
name = name,
texture = texture,
link = link,
count = count
}
if name then
Items[name] = it
local lowerName = string_lower(name)
if lowerName ~= name then
Items[lowerName] = name
end
end
if itemID then Items[itemID] = name end
return it
end
local function makeBagItem(bagID, slot, link, Items)
if not link then
link = GetContainerItemLink(bagID, slot)
end
if not link then return end
local _, _, itemID = string_find(link, "item:(%d+)")
itemID = itemID and tonumber(itemID) or nil
local name, _, _, _, _, _, _, _, texture = GetItemInfo(itemID)
local count = 0
local tex, itemCount = GetContainerItemInfo(bagID, slot)
if itemCount then count = itemCount end
if not texture then texture = tex end
local it = {
bagID = bagID,
slot = slot,
id = itemID,
name = name,
texture = texture,
link = link,
count = count,
bagSlots = { { bagID, slot } },
slotsIndex = 1
}
if name then
Items[name] = it
local lowerName = string_lower(name)
if lowerName ~= name then
Items[lowerName] = name
end
end
if itemID then Items[itemID] = name end
return it
end
function CleveRoids.GetItem(text)
if not text or text == "" then return end
local Items = CleveRoids.Items
local item = Items[text] or Items[tostring(text)]
if not item then
local lowerText = string_lower(text)
local canonicalName = Items[lowerText]
if canonicalName and type(canonicalName) == "string" then
item = Items[canonicalName]
end
end
if item then
if type(item) == "table" then
return item
else
return Items[tostring(item)]
end
end
local qid = tonumber(text)
local qname = (type(text) == "string") and string_lower(text) or nil
-- Direct inventory slot lookup by ID
if qid and qid >= 1 and qid <= 19 then
local it = makeInventoryItem(qid, nil, Items)
if it then return it end
end
-- Scan equipped items
for inv = 1, 19 do
local link = GetInventoryItemLink("player", inv)
if link then
local _, _, itemID = string_find(link, "item:(%d+)")
itemID = itemID and tonumber(itemID) or nil
if qid and itemID and qid == itemID then
return makeInventoryItem(inv, link, Items)
elseif qname and itemID then
local nm = GetItemInfo(itemID)
if nm and string_lower(nm) == qname then
return makeInventoryItem(inv, link, Items)
end
end
end
end
-- Scan bags
for bag = 0, 4 do
local slots = GetContainerNumSlots(bag) or 0
for slot = 1, slots do
local link = GetContainerItemLink(bag, slot)
if link then
local _, _, itemID = string_find(link, "item:(%d+)")
itemID = itemID and tonumber(itemID) or nil
if qid and itemID and qid == itemID then
return makeBagItem(bag, slot, link, Items)
elseif qname and itemID then
local nm = GetItemInfo(itemID)
if nm and string_lower(nm) == qname then
return makeBagItem(bag, slot, link, Items)
end
end
end
end
end
local name, link, _, _, _, _, _, _, texture = GetItemInfo(text)
if not name then return end
local fallback = { id = text, name = name, link = link, texture = texture }
CleveRoids.Items[name] = fallback
local lowerName = string.lower(name)
if lowerName ~= name then
CleveRoids.Items[lowerName] = name
end
return fallback
end
function CleveRoids.GetNextBagSlotForUse(item, text)
if not item then return end
if CleveRoids.lastGetItem == CleveRoids.GetItem(text) then
if table.getn(item.bagSlots) > item.slotsIndex then
item.slotsIndex = item.slotsIndex + 1
item.bagID, item.slot = unpack(item.bagSlots[item.slotsIndex])
end
end
CleveRoids.lastGetItem = item
return item
end
local Extension = CleveRoids.RegisterExtension("Generic_show")
Extension.RegisterEvent("SPELLS_CHANGED", "SPELLS_CHANGED")
function Extension.OnLoad()
end
function Extension.SPELLS_CHANGED()
end