You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1039 lines
30 KiB

local E = select(2, ...):unpack()
local P, CM = E.Party, E.Comm
local pairs, ipairs, type, wipe, concat, format, gsub = pairs, ipairs, type, table.wipe, table.concat, string.format, string.gsub
local UnitIsConnected, CanInspect, CheckInteractDistance = UnitIsConnected, CanInspect, CheckInteractDistance
local GetPvpTalentInfoByID, GetTalentInfo, GetGlyphSocketInfo = GetPvpTalentInfoByID, GetTalentInfo, GetGlyphSocketInfo
local GetItemInfoInstant = C_Item and C_Item.GetItemInfoInstant or GetItemInfoInstant
local C_SpecializationInfo_GetInspectSelectedPvpTalent = C_SpecializationInfo and C_SpecializationInfo.GetInspectSelectedPvpTalent
local C_SpecializationInfo_GetPvpTalentSlotInfo = C_SpecializationInfo and C_SpecializationInfo.GetPvpTalentSlotInfo
local C_Traits_GetNodeInfo = C_Traits and C_Traits.GetNodeInfo
local C_Soulbinds_GetConduitSpellID = C_Soulbinds and C_Soulbinds.GetConduitSpellID
local InspectQueueFrame = CreateFrame("Frame")
local InspectTooltip, tooltipData
if not E.isDF then
InspectTooltip = CreateFrame("GameTooltip", "OmniCDInspectToolTip", nil, "GameTooltipTemplate")
InspectTooltip:SetOwner(UIParent, "ANCHOR_NONE")
end
local LibDeflate = LibStub("LibDeflate")
local INSPECT_DELAY = 2
local INSPECT_INTERVAL = 1
local INSPECT_PAUSE_TIME = 2
local INSPECT_TIMEOUT = 300
local nextInquiryTime = 0
local elapsedTime = 0
local isPaused
local queriedGUID
local queueEntries = {}
local staleEntries = {}
CM.SERIALIZATION_VERSION = 6
CM.ACECOMM = LibStub("AceComm-3.0"):Embed(CM)
function CM:Enable()
if self.enabled then
return
end
self.AddonPrefix = E.AddOn
self:RegisterComm(self.AddonPrefix, 'CHAT_MSG_ADDON')
self:RegisterEvent('PLAYER_EQUIPMENT_CHANGED')
self:RegisterEvent('PLAYER_LEAVING_WORLD')
if E.isWOTLKC or E.isCata then
self:RegisterEvent('PLAYER_TALENT_UPDATE')
elseif E.preMoP then
self:RegisterEvent('CHARACTER_POINTS_CHANGED')
else
self:RegisterUnitEvent('PLAYER_SPECIALIZATION_CHANGED', "player")
self:RegisterEvent('COVENANT_CHOSEN')
self:RegisterEvent('SOULBIND_ACTIVATED')
self:RegisterEvent('SOULBIND_NODE_LEARNED')
self:RegisterEvent('SOULBIND_NODE_UNLEARNED')
self:RegisterEvent('SOULBIND_NODE_UPDATED')
self:RegisterEvent('SOULBIND_CONDUIT_INSTALLED')
self:RegisterEvent('SOULBIND_PATH_CHANGED')
self:RegisterEvent('COVENANT_SANCTUM_RENOWN_LEVEL_CHANGED')
self:RegisterEvent('TRAIT_CONFIG_UPDATED')
end
self:SetScript("OnEvent", function(self, event, ...)
self[event](self, ...)
end)
self:InitInspect()
self:InitCooldownSync()
self.enabled = true
end
function CM:Disable()
if not self.enabled then
return
end
self:UnregisterAllEvents()
self:DisableInspect()
self:DesyncFromGroup()
self.enabled = false
end
local function InspectQueueFrame_OnUpdate(_, elapsed)
elapsedTime = elapsedTime + elapsed
if elapsedTime > INSPECT_INTERVAL then
CM:RequestInspect()
elapsedTime = 0
end
end
function CM:InitInspect()
if self.initInspect then
return
end
InspectQueueFrame:Hide()
InspectQueueFrame:SetScript("OnUpdate", InspectQueueFrame_OnUpdate)
self.initInspect = true
end
function CM:EnableInspect()
if self.enabledInspect or next(queueEntries) == nil then
return
end
self:RegisterEvent('INSPECT_READY')
InspectQueueFrame:Show()
self.enabledInspect = true
end
function CM:DisableInspect()
if not self.enabledInspect then
return
end
ClearInspectPlayer()
self:UnregisterEvent('INSPECT_READY')
InspectQueueFrame:Hide()
wipe(P.pendingQueue)
wipe(queueEntries)
wipe(staleEntries)
queriedGUID = nil
isPaused = nil
self.enabledInspect = false
end
function CM:DequeueInspect(guid, addToStale)
if queriedGUID == guid then
queriedGUID = nil
end
staleEntries[guid] = addToStale and queueEntries[guid] or nil
queueEntries[guid] = nil
end
function CM:EnqueueInspect(force, guid)
local addedTime = GetTime()
if force then
wipe(P.pendingQueue)
wipe(queueEntries)
wipe(staleEntries)
for infoGUID in pairs(P.groupInfo) do
if infoGUID == E.userGUID then
self:InspectUser()
else
queueEntries[infoGUID] = addedTime
end
end
elseif guid then
if guid == E.userGUID then
self:InspectUser()
else
queueEntries[guid] = addedTime
end
else
local numPending = #P.pendingQueue
if numPending == 0 then return end
for i = numPending, 1, -1 do
local pendingGUID = P.pendingQueue[i]
queueEntries[pendingGUID] = addedTime
P.pendingQueue[i] = nil
end
end
if isPaused then
nextInquiryTime = 0
isPaused = nil
end
self:EnableInspect()
end
function CM:RequestInspect()
local now = GetTime()
if now < nextInquiryTime or UnitIsDead("player") or (InspectFrame and InspectFrame:IsShown()) then
return
end
local stale = queriedGUID
if stale then
staleEntries[stale] = queueEntries[stale]
queueEntries[stale] = nil
queriedGUID = nil
end
if next(queueEntries) == nil then
if next(staleEntries) then
local copy = queueEntries
queueEntries = staleEntries
staleEntries = copy
nextInquiryTime = now + INSPECT_PAUSE_TIME
isPaused = true
else
self:DisableInspect()
end
return
end
isPaused = nil
for unitGUID, addedTime in pairs(queueEntries) do
local info = P.groupInfo[unitGUID]
local isSyncedUnit = self.syncedGroupMembers[unitGUID]
if info and not isSyncedUnit then
local unit = info.unit
local elapsed = now - addedTime
if not UnitIsConnected(unit) or elapsed > INSPECT_TIMEOUT or info.isAdminObsForMDI then
self:DequeueInspect(unitGUID)
elseif E.preMoP and (InCombatLockdown() or not CheckInteractDistance(unit,1))
or not CanInspect(unit) then
staleEntries[unitGUID] = addedTime
queueEntries[unitGUID] = nil
else
nextInquiryTime = now + INSPECT_DELAY
queriedGUID = unitGUID
NotifyInspect(unit)
return
end
else
self:DequeueInspect(unitGUID)
end
end
end
function CM:INSPECT_READY(guid)
if queriedGUID == guid then
self:InspectUnit(guid)
end
end
local INVSLOT_INDEX = {
INVSLOT_HEAD,
INVSLOT_NECK,
INVSLOT_SHOULDER,
INVSLOT_CHEST,
INVSLOT_WAIST,
INVSLOT_LEGS,
INVSLOT_FEET,
INVSLOT_WRIST,
INVSLOT_HAND,
INVSLOT_FINGER1,
INVSLOT_FINGER2,
INVSLOT_TRINKET1,
INVSLOT_TRINKET2,
INVSLOT_BACK,
INVSLOT_MAINHAND,
INVSLOT_OFFHAND,
}
local NUM_INVSLOTS = #INVSLOT_INDEX
E.essenceData = {
[2] = { 293019, 298080, 298081, 298081, 294668, 298082, 298083, 298083 },
[3] = { 293031, 300009, 300010, 300010, 294910, 300012, 300013, 300013 },
[4] = { 295186, 298628, 299334, 299334, 295078, 298627, 299333, 299333 },
[5] = { 295258, 299336, 299338, 299338, 295246, 299335, 299337, 299337 },
[6] = { 295337, 299345, 299347, 299347, 295293, 299343, 299346, 299346 },
[7] = { 294926, 300002, 300003, 300003, 294964, 300004, 300005, 300005 },
[12] = { 295373, 299349, 299353, 299353, 295365, 299348, 299350, 299350 },
[13] = { 295746, 300015, 300016, 300016, 295750, 300018, 300020, 300020 },
[14] = { 295840, 299355, 299358, 299358, 295834, 299354, 299357, 299357 },
[15] = { 302731, 302982, 302983, 302983, 302916, 302984, 302985, 302985 },
[16] = { 296036, 310425, 310442, 310442, 293030, 310422, 310426, 310426 },
[17] = { 296072, 299875, 299876, 299876, 296050, 299878, 299879, 299879 },
[18] = { 296094, 299882, 299883, 299883, 296081, 299885, 299887, 299887 },
[19] = { 296197, 299932, 299933, 299933, 296136, 299935, 299936, 299936 },
[20] = { 293032, 299943, 299944, 299944, 296207, 299939, 299940, 299940 },
[21] = { 296230, 299958, 299959, 299959, 303448, 303474, 303476, 303476 },
[22] = { 296325, 299368, 299370, 299370, 296320, 299367, 299369, 299369 },
[23] = { 297108, 298273, 298277, 298277, 297147, 298274, 298275, 298275 },
[24] = { 297375, 298309, 298312, 298312, 297411, 298302, 298304, 298304 },
[25] = { 298168, 299273, 299275, 299275, 298193, 299274, 299277, 299277 },
[27] = { 298357, 299372, 299374, 299374, 298268, 299371, 299373, 299373 },
[28] = { 298452, 299376, 299378, 299378, 298407, 299375, 299377, 299377 },
[32] = { 303823, 304088, 304121, 304121, 304081, 304089, 304123, 304123 },
[33] = { 295046, 299984, 299988, 299988, 295164, 299989, 299991, 299991 },
[34] = { 310592, 310601, 310602, 310602, 310603, 310607, 310608, 310608 },
[35] = { 310690, 311194, 311195, 311195, 310712, 311197, 311198, 311198 },
[36] = { 311203, 311302, 311303, 311303, 311210, 311304, 311306, 311306 },
[37] = { 312725, 313921, 313922, 313922, 312771, 313919, 313920, 313920 },
}
CM.essencePowerIDs = {}
for essenceID, essencePowers in pairs(E.essenceData) do
local link = E.postBFA and C_AzeriteEssence.GetEssenceHyperlink(essenceID, 1)
if link and link ~= "" then
link = link:match("%[(.-)%]"):gsub("%-","%%-")
essencePowers.name = link
essencePowers.ID = essenceID
for i = 1, #essencePowers do
local spellID = essencePowers[i]
local rank1ID = essencePowers[i > 4 and 5 or 1]
CM.essencePowerIDs[spellID] = rank1ID
end
end
end
function E:IsEssenceRankUpgraded(id)
return id and id ~= CM.essencePowerIDs[id]
end
local function GetNumTooltipLines()
if InspectTooltip then
return InspectTooltip:NumLines()
end
return tooltipData and tooltipData.lines and #tooltipData.lines or 0
end
local function GetTooltipLineData(i)
local lineData
if tooltipData then
lineData = tooltipData.lines[i]
return lineData, lineData.leftText
elseif InspectTooltip then
lineData = _G["OmniCDInspectToolTipTextLeft" .. i]
return lineData, lineData:GetText()
end
end
local function GetTooltipLineTextColor(lineData)
if not lineData then
return 1, 1, 1
elseif tooltipData then
return lineData.leftColor.r, lineData.leftColor.g, lineData.leftColor.b
elseif InspectTooltip then
return lineData:GetTextColor()
end
end
local ITEM_LEVEL = gsub(ITEM_LEVEL,"%%d","(%%d+)")
local function FindAzeriteEssencePower(info, specID, list)
local heartOfAzerothLevel
local majorID
local numLines = math.min(16, GetNumTooltipLines())
for j = 2, numLines do
local lineData, text = GetTooltipLineData(j)
if text and text ~= "" then
if not heartOfAzerothLevel then
heartOfAzerothLevel = strmatch(text, ITEM_LEVEL)
if heartOfAzerothLevel then
heartOfAzerothLevel = tonumber(heartOfAzerothLevel)
end
elseif j > 10 then
for essenceID, essencePowers in pairs(E.essenceData) do
if strfind(text, essencePowers.name .. "$") == 1 then
local r, _, b = GetTooltipLineTextColor(lineData)
local rank = 3
if r < .01 then
rank = 2
elseif r > .90 then
rank = 4
elseif b < .01 then
rank = 1
end
if not majorID and GetTooltipLineData(j - 1) == " " then
majorID = essencePowers[rank]
local rank1 = essencePowers[1]
info.talentData[rank1] = "AE"
info.talentData["essMajorRank1"] = rank1
info.talentData["essMajorID"] = majorID
if list then
list[#list + 1] = majorID .. ":AE"
end
if E.essMajorConflict[majorID] then
local pvpTalent = E.pvpTalentsByEssMajorConflict[specID]
if pvpTalent then
info.talentData[pvpTalent] = "AE"
if list then
list[#list + 1] = pvpTalent
end
end
end
if rank1 ~= 296325 then
break
end
end
local minorID = essencePowers[rank + 4]
if E.essMinorStrive[minorID] then
local mult = (90.1 - ((heartOfAzerothLevel - 117) * 0.15)) / 100
if P.isInPvPInstance then
mult = 0.2 + mult * 0.8
end
mult = math.max(0.75, math.min(0.9, mult))
info.talentData["essStriveMult"] = mult
if list then
list[#list + 1] = mult .. ":ae"
end
return
end
break
end
end
end
end
end
end
local function FindAzeritePower(info, list)
local numLines = GetNumTooltipLines()
for j = 10, numLines do
local _, text = GetTooltipLineData(j)
if text and text ~= "" and strfind(text, "^-") == 1 then
for _, v in pairs(E.spell_cxmod_azerite) do
if strfind(text, v.name .. "$") == 3 then
info.talentData[v.azerite] = "A"
if list then list[#list + 1] = v.azerite .. ":A" end
return
end
end
end
end
end
local S_ITEM_SET_NAME = "^" .. ITEM_SET_NAME:gsub("([%(%)])", "%%%1"):gsub("%%%d?$?d", "(%%d+)"):gsub("%%%d?$?s", "(.+)") .. "$"
local function FindSetBonus(info, specBonus, list)
local bonusID, numRequired = specBonus[1], specBonus[2]
local numLines = GetNumTooltipLines()
for j = 10, numLines do
local _, text = GetTooltipLineData(j)
if text and text ~= "" then
local name, numEquipped, numFullSet = strmatch(text, S_ITEM_SET_NAME)
if name and numEquipped and numFullSet then
numEquipped = tonumber(numEquipped)
if numEquipped and numEquipped >= numRequired then
info.talentData[bonusID] = "S"
if list then list[#list + 1] = bonusID .. ":S" end
local bonusID2 = specBonus[3]
if bonusID2 and numEquipped >= specBonus[4] then
info.talentData[bonusID2] = "S"
if list then list[#list + 1] = bonusID2 .. ":S" end
end
end
return bonusID
end
end
end
end
local function FindCraftedRuneforgeLegendary(info, itemLink, list)
local _,_,_,_,_,_,_,_,_,_,_,_,_, numBonusIDs, bonusIDs = strsplit(":", itemLink, 15)
numBonusIDs = tonumber(numBonusIDs)
if numBonusIDs and bonusIDs then
local t = { strsplit(":", bonusIDs, numBonusIDs + 1) }
for j = 1, numBonusIDs do
local bonusID = t[j]
bonusID = tonumber(bonusID)
local runeforgeDescID = E.runeforge_bonus_to_descid[bonusID]
if runeforgeDescID then
if type(runeforgeDescID) == "table" then
for _, descID in pairs(runeforgeDescID) do
info.talentData[descID] = "R"
if list then list[#list + 1] = descID .. ":R" end
end
else
info.talentData[runeforgeDescID] = "R"
if list then list[#list + 1] = runeforgeDescID .. ":R" end
end
return
end
end
end
end
local runeforgeBaseItems = {
[1] = { 173245, 172317, 172325, 171415 },
[2] = { 178927, 178927, 178927, 178927 },
[3] = { 173247, 172319, 172327, 171417 },
[5] = { 173241, 172314, 172322, 171412 },
[6] = { 173248, 172320, 172328, 171418 },
[7] = { 173246, 172318, 172326, 171416 },
[8] = { 173243, 172315, 172323, 171413 },
[9] = { 173249, 172321, 172329, 171419 },
[10] = { 173244, 172316, 172324, 171414 },
[11] = { 178926, 178926, 178926, 178926 },
[12] = { 178926, 178926, 178926, 178926 },
[15] = { 173242, 173242, 173242, 173242 },
}
--[[
if we're separating player insepct:
local itemID = GetInventoryItemID(unit, slotID)
local itemLink = GetInventoryItemLink(unit, slotID)
local itemLocation = ItemLocation:CreateFromEquipmentSlot(slotID)
local isRuenforgeBaseItem = C_LegendaryCrafting.IsValidRuneforgeBaseItem(itemLocation)
local isRuneforgeLegendary = C_LegendaryCrafting.IsRuneforgeLegendary(itemLocation)
]]
local function GetEquippedItemData(info, unit, specID, list)
local moveToStale
local numRuneforge = 0
local numTierSetBonus = 0
local foundTierSpecBonus
local e
if list then list[#list + 1] = "^M"; e = { "^E" }; end
for i = 1, NUM_INVSLOTS do
local slotID = INVSLOT_INDEX[i]
local itemLink = GetInventoryItemLink(unit, slotID)
if itemLink then
local itemID, _,_,_,_,_, subclassID = GetItemInfoInstant(itemLink)
if itemID then
if i < 10 then
local tierSetBonus = E.item_set_bonus[itemID]
local equipBonusID = E.item_equip_bonus[itemID]
subclassID = subclassID == 0 and 1 or subclassID
local unityRuneforgeLegendary = E.item_unity[itemID]
local isCraftedRuneforgeLegendary = numRuneforge <= 2
and runeforgeBaseItems[slotID]
and itemID == runeforgeBaseItems[slotID][subclassID]
if InspectTooltip then
InspectTooltip:SetInventoryItem(unit, slotID)
else --[[https://wowpedia.fandom.com/wiki/Patch_10.0.2/API_changes#Tooltip_Changes]]
tooltipData = C_TooltipInfo.GetInventoryItem(unit, slotID)
--[[ deprecated in 10.1, removed in 11.0
if tooltipData and TooltipUtil.SurfaceArgs then
TooltipUtil.SurfaceArgs(tooltipData)
for _, line in ipairs(tooltipData.lines) do
TooltipUtil.SurfaceArgs(line)
end
end
]]
end
if equipBonusID then
info.talentData[equipBonusID] = true
if list then list[#list + 1] = equipBonusID .. ":S" end
end
if tierSetBonus then
local specBonus = E.preMoP and tierSetBonus or tierSetBonus[specID]
if specBonus and numTierSetBonus < 2 and specBonus[1] ~= foundTierSpecBonus then
foundTierSpecBonus = FindSetBonus(info, specBonus, list)
if foundTierSpecBonus then
numTierSetBonus = numTierSetBonus + 1
end
end
elseif isCraftedRuneforgeLegendary then
FindCraftedRuneforgeLegendary(info, itemLink, list)
numRuneforge = numRuneforge + 1
elseif unityRuneforgeLegendary then
if type(unityRuneforgeLegendary) == "table" then
for _, runeforgeDescID in pairs(unityRuneforgeLegendary) do
info.talentData[runeforgeDescID] = "R"
if list then list[#list + 1] = runeforgeDescID .. ":R" end
end
else
info.talentData[unityRuneforgeLegendary] = "R"
if list then list[#list + 1] = unityRuneforgeLegendary .. ":R" end
end
numRuneforge = numRuneforge + 1
elseif itemID == 158075 then
FindAzeriteEssencePower(info, specID, list)
elseif C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItemByID(itemLink) then
FindAzeritePower(info, list)
end
if InspectTooltip then
InspectTooltip:ClearLines()
end
end
itemID = E.item_merged[itemID] or itemID
info.itemData[itemID] = true
if e then e[#e + 1] = itemID end
elseif not moveToStale then
moveToStale = true
end
end
end
if e then
list[#list + 1] = concat(e, ",")
e = nil
end
return moveToStale
end
local talentIDFix = {
[103211] = 377779,
[103216] = 343240,
[103224] = 377623
}
local talentChargeFix = {
[36554] = { [259]=1, [261]=1 },
[191634] = true,
[47568] = true,
[5394] = true
}
local MAX_NUM_TALENTS = MAX_NUM_TALENTS or ((E.isWOTLKC or E.isCata) and 31 or 25)
local GetSelectedTalentData = (E.isDF and function(info, inspectUnit, isInspect)
local list, c
if not isInspect then
list, c = { CM.SERIALIZATION_VERSION, true, "^T" }, 4
end
for i = 1, 3 do
local talentID
if isInspect then
talentID = C_SpecializationInfo_GetInspectSelectedPvpTalent(inspectUnit, i)
else
local slotInfo = C_SpecializationInfo_GetPvpTalentSlotInfo(i)
talentID = slotInfo and slotInfo.selectedTalentID
end
if talentID then
local _,_,_,_,_, spellID = GetPvpTalentInfoByID(talentID)
info.talentData[spellID] = "PVP"
if list then
list[c] = -spellID
c = c + 1
end
end
end
local configID = isInspect and Constants.TraitConsts.INSPECT_TRAIT_CONFIG_ID or C_ClassTalents.GetActiveConfigID()
if configID then
local configInfo = C_Traits.GetConfigInfo(configID)
if configInfo then
for _, treeID in ipairs(configInfo.treeIDs) do
local treeNodes = C_Traits.GetTreeNodes(treeID)
for _, treeNodeID in ipairs(treeNodes) do
local treeNode = C_Traits_GetNodeInfo(configID, treeNodeID)
local activeEntry = treeNode.activeEntry
if activeEntry then
local activeRank = treeNode.activeRank
if activeRank > 0 then
local activeEntryID = activeEntry.entryID
local entryInfo = C_Traits.GetEntryInfo(configID, activeEntryID)
local definitionID = entryInfo.definitionID
if definitionID then
local definitionInfo = C_Traits.GetDefinitionInfo(definitionID)
local spellID = definitionInfo.spellID
spellID = talentIDFix[activeEntryID] or spellID
if spellID and (not treeNode.subTreeID or treeNode.subTreeActive) then
if talentChargeFix[spellID] then
if talentChargeFix[spellID] == true then
if info.talentData[spellID] then
activeRank = 2
end
elseif talentChargeFix[spellID][info.spec] then
activeRank = 2
end
end
info.talentData[spellID] = activeRank
if list then
list[c] = activeRank > 1 and format("%s:%s", spellID, activeRank) or spellID
c = c + 1
end
end
end
end
end
end
end
end
end
return list
end) or (E.isSL and function(info, inspectUnit, isInspect)
local list
if not isInspect then
list = { CM.SERIALIZATION_VERSION, true, "^T" }
end
for i = 1, 3 do
local talentID
if isInspect then
talentID = C_SpecializationInfo_GetInspectSelectedPvpTalent(inspectUnit, i)
else
local slotInfo = C_SpecializationInfo_GetPvpTalentSlotInfo(i)
talentID = slotInfo and slotInfo.selectedTalentID
end
if talentID then
local _,_,_,_,_, spellID = GetPvpTalentInfoByID(talentID)
info.talentData[spellID] = "PVP"
if list then list[#list + 1] = -spellID end
end
end
local specGroupIndex = 1
for tier = 1, MAX_TALENT_TIERS do
for column = 1, NUM_TALENT_COLUMNS do
local _,_,_, selected, _, spellID = GetTalentInfo(tier, column, specGroupIndex , isInspect, inspectUnit)
if selected then
info.talentData[spellID] = true
if list then list[#list + 1] = spellID end
break
end
end
end
return list
end) or (E.isWOTLKC and function(info, inspectUnit, isInspect)
local list
if not isInspect then
list = { CM.SERIALIZATION_VERSION, true, "^T" }
end
local talentGroup = GetActiveTalentGroup and GetActiveTalentGroup(isInspect, nil)
if list then
for i = 1, 6 do
local _,_, glyphSpellID = GetGlyphSocketInfo(i, talentGroup)
if glyphSpellID then
info.talentData[glyphSpellID] = true
list[#list + 1] = glyphSpellID
end
end
end
for tabIndex = 1, 3 do
for talentIndex = 1, MAX_NUM_TALENTS do
local name, _,_,_, currentRank = GetTalentInfo(tabIndex, talentIndex, isInspect, inspectUnit, talentGroup)
if not name then
break
end
if currentRank > 0 then
local talentRankIDs = E.talentNameToRankIDs[name]
if talentRankIDs then
if type(talentRankIDs[1]) == "table" then
for _, t in pairs(talentRankIDs) do
local talentID = t[currentRank]
if talentID then
info.talentData[talentID] = true
if list then list[#list + 1] = talentID end
end
end
else
local talentID = talentRankIDs[currentRank]
if talentID then
info.talentData[talentID] = true
if list then list[#list + 1] = talentID end
end
end
end
end
end
end
return list
end) or (E.isCata and function(info, inspectUnit, isInspect)
local list
if not isInspect then
list = { CM.SERIALIZATION_VERSION, true, "^T" }
end
local talentGroup = GetActiveTalentGroup and GetActiveTalentGroup(isInspect, nil)
local primaryTree = GetPrimaryTalentTree(isInspect, nil, talentGroup)
if primaryTree then
info.spec = primaryTree
info.talentData[primaryTree] = true
if list then list[#list + 1] = primaryTree end
end
if list then
for i = 1, 9 do
local _,_,_, glyphSpellID = GetGlyphSocketInfo(i, talentGroup)
if glyphSpellID then
info.talentData[glyphSpellID] = true
list[#list + 1] = glyphSpellID
end
end
end
for tabIndex = 1, 3 do
for talentIndex = 1, MAX_NUM_TALENTS do
local name, _,_,_, currentRank = GetTalentInfo(tabIndex, talentIndex, isInspect, inspectUnit, talentGroup)
if not name then
break
end
if currentRank > 0 then
local talentRankIDs = E.talentNameToRankIDs[name]
if talentRankIDs then
if type(talentRankIDs[1]) == "table" then
for _, t in pairs(talentRankIDs) do
local talentID = t[currentRank]
if talentID then
info.talentData[talentID] = true
if list then list[#list + 1] = talentID end
end
end
else
local talentID = talentRankIDs[currentRank]
if talentID then
info.talentData[talentID] = true
if list then list[#list + 1] = talentID end
end
end
end
end
end
end
return list
end) or function(info, inspectUnit, isInspect)
local list
if not isInspect then
list = { CM.SERIALIZATION_VERSION, true, "^T" }
end
for tabIndex = 1, 3 do
for talentIndex = 1, MAX_NUM_TALENTS do
local name, _,_,_, currentRank = GetTalentInfo(tabIndex, talentIndex, isInspect, inspectUnit)
if not name then
break
end
if currentRank > 0 then
local talentRankIDs = E.talentNameToRankIDs[name]
if talentRankIDs then
if type(talentRankIDs[1]) == "table" then
for _, t in pairs(talentRankIDs) do
local talentID = t[currentRank]
if talentID then
info.talentData[talentID] = true
if list then list[#list + 1] = talentID end
end
end
else
local talentID = talentRankIDs[currentRank]
if talentID then
info.talentData[talentID] = true
if list then list[#list + 1] = talentID end
end
end
end
end
end
end
return list
end
function CM:InspectUnit(guid)
local info = P.groupInfo[guid]
if not info or self.syncedGroupMembers[guid] then
ClearInspectPlayer()
return
end
local inspectUnit = info.unit
local specID = E.preMoP and info.raceID or GetInspectSpecialization(inspectUnit)
if not specID or specID == 0 then
return
end
info.spec = specID
if info.name == "" or info.name == UNKNOWN then
info.name = GetUnitName(inspectUnit, true)
end
if info.level == 200 then
local lvl = UnitLevel(inspectUnit)
if lvl > 0 then
info.level = lvl
end
end
if not E.preMoP then
info.spellHasteMult = 1/(1 + UnitSpellHaste(info.unit)/100)
end
wipe(info.talentData)
wipe(info.itemData)
GetSelectedTalentData(info, inspectUnit, true)
local failed = GetEquippedItemData(info, inspectUnit, specID)
ClearInspectPlayer()
self:DequeueInspect(guid, failed)
P:UpdateUnitBar(guid)
end
local enhancedSoulbindRowRenownLevel = {
[1] = { [1] = 63, [3] = 66, [5] = 68, [6] = 72, [8] = 73, [10] = 78 },
[2] = { [1] = 61, [3] = 64, [5] = 67, [6] = 70, [8] = 75, [10] = 79 },
[3] = { [1] = 62, [3] = 65, [5] = 69, [6] = 71, [8] = 74, [10] = 77 },
[4] = { [1] = 63, [3] = 66, [5] = 68, [6] = 72, [8] = 73, [10] = 78 },
[5] = { [1] = 61, [3] = 64, [5] = 67, [6] = 70, [8] = 75, [10] = 79 },
[6] = { [1] = 62, [3] = 65, [5] = 69, [6] = 71, [8] = 74, [10] = 77 },
[7] = { [1] = 63, [3] = 66, [5] = 68, [6] = 72, [8] = 73, [10] = 78 },
[8] = { [1] = 63, [3] = 66, [5] = 68, [6] = 72, [8] = 73, [10] = 78 },
[9] = { [1] = 61, [3] = 64, [5] = 67, [6] = 70, [8] = 75, [10] = 79 },
[10] = { [1] = 62, [3] = 65, [5] = 69, [6] = 71, [8] = 74, [10] = 77 },
[13] = { [1] = 61, [3] = 64, [5] = 67, [6] = 70, [8] = 75, [10] = 79 },
[18] = { [1] = 62, [3] = 65, [5] = 69, [6] = 71, [8] = 74, [10] = 77 },
}
local function IsSoulbindRowEnhanced(soulbindID, row, renownLevel)
local minLevel = enhancedSoulbindRowRenownLevel[soulbindID] and enhancedSoulbindRowRenownLevel[soulbindID][row]
if minLevel then
return renownLevel >= minLevel
end
end
local function GetCovenantSoulbindData(info, list)
wipe(info.shadowlandsData)
local covenantID = C_Covenants.GetActiveCovenantID()
if covenantID == 0 then
return
end
local covenantSpellID = E.covenant_to_spellid[covenantID]
info.shadowlandsData.covenantID = covenantID
info.talentData[covenantSpellID] = "C"
list[#list + 1] = "^C," .. covenantID
local soulbindID = C_Soulbinds.GetActiveSoulbindID()
if soulbindID == 0 then
return
end
info.shadowlandsData.soulbindID = soulbindID
list[#list + 1] = soulbindID
local soulbindData = C_Soulbinds.GetSoulbindData(soulbindID)
local nodes = soulbindData.tree and soulbindData.tree.nodes
if not nodes then
return
end
local renownLevel = C_CovenantSanctumUI.GetRenownLevel()
for i = 1, #nodes do
local node = nodes[i]
if node.state == Enum.SoulbindNodeState.Selected then
local conduitID, conduitRank, row, spellID = node.conduitID, node.conduitRank, node.row, node.spellID
if conduitID ~= 0 then
spellID = C_Soulbinds_GetConduitSpellID(conduitID, conduitRank)
if IsSoulbindRowEnhanced(soulbindID, row, renownLevel) then
conduitRank = conduitRank + 2
end
local rankValue = E.soulbind_conduits_rank[spellID] and (E.soulbind_conduits_rank[spellID][conduitRank] or E.soulbind_conduits_rank[spellID][1])
if rankValue then
info.talentData[spellID] = rankValue
list[#list + 1] = format("%s:%s", spellID, rankValue)
end
elseif E.soulbind_abilities[spellID] then
info.talentData[spellID] = 0
list[#list + 1] = spellID
end
end
end
end
local function FindValidSpellID(info, v)
if type(v) ~= "table" then
return info.spec == v or (P:IsTalentForPvpStatus(v, info) and true)
end
if v[1] > 0 then
for _, id in pairs(v) do
if info.spec == id or P:IsTalentForPvpStatus(id, info) then
return true
end
end
else
local spellID
for i = 1, #v, 2 do
local tid, sid = v[i], v[i + 1]
tid = i == 1 and -tid or tid
spellID = P:IsTalentForPvpStatus(tid, info) and sid
end
return spellID or true
end
end
function CM:UpdateCooldownSyncIDs(info)
if E.preCata or info.isAdminObsForMDI then return end
wipe(self.cooldownSyncIDs)
local notRaid = P.zone ~= "raid"
for id, t in E.pairs(E.sync_cooldowns.ALL, E.sync_cooldowns[E.userClass]) do
if notRaid or E.sync_in_raid[id] then
local spellID
for i = 1, #t do
local v = t[i]
spellID = not v or FindValidSpellID(info, v)
if not spellID then break end
end
if spellID then
self.cooldownSyncIDs[spellID == true and id or spellID] = { 0, -1 }
end
end
end
self:ToggleCooldownSync()
end
function CM:InspectUser()
local info = P.userInfo
local specID
if E.preMoP then
specID = info.raceID
else
local specIndex = GetSpecialization()
specID = GetSpecializationInfo(specIndex)
end
if not specID or specID == 0 then
return false
end
info.spec = specID
wipe(info.talentData)
wipe(info.itemData)
local dataList = GetSelectedTalentData(info, "player")
GetEquippedItemData(info, "player", specID, dataList)
if E.postBFA then
GetCovenantSoulbindData(info, dataList)
info.spellHasteMult = 1/(1 + UnitSpellHaste("player")/100)
elseif E.isClassic or E.isBCC then
local speed = UnitRangedDamage("player")
if speed and speed > 0 then
info.rangedWeaponSpeed = speed
dataList[#dataList + 1] = -speed
end
end
dataList[2] = info.spec
local serializedData = concat(dataList, ","):gsub(",%^", "^")
local compressedData = LibDeflate:CompressDeflate(serializedData)
local encodedData = LibDeflate:EncodeForWoWAddonChannel(compressedData)
self.serializedSyncData = encodedData
self:UpdateCooldownSyncIDs(info)
if P.groupInfo[E.userGUID] then
P:UpdateUnitBar(E.userGUID)
end
return true
end