--Patch: 9.1.0 --Features: Shards of Domination (Special Gems) --Determine items by itemIDs? --or socket texture? --https://www.wowhead.com/guides/sanctum-of-domination-raid-loot-chains-of-domination-9-1#accessories local NUM_SHARDS_MAX = 5; local COLOR_GREE = "|cff20ff20"; local COLOR_DOMINATION = "|cff66bbff"; local unpack = unpack; local GetItemInfoInstant = GetItemInfoInstant; local ItemLocation = ItemLocation; local DoesItemExist = C_Item.DoesItemExist; local GetItemLink = C_Item.GetItemLink; local GetItemID = C_Item.GetItemID; local GetPlayerAuraBySpellID = GetPlayerAuraBySpellID; local FadeFrame = NarciFadeUI.Fade; local PaperDollIndicator; local function Mixin(object, mixin) for k, v in pairs(mixin) do object[k] = v; end end local SHARD_OF_DOMINATION; local TP = _G["NarciVirtualTooltip"]; --For tooltip scanning local dominationItems = { 186287, 186325, 186324, 186286, 186320, 186282, 186322, 186284, 186283, 186321, --Cloth 186330, 186292, 186298, 186336, 186296, 186334, 186295, 186333, 186363, 186337, 186299, --Leather 186341, 186304, 186342, 186305, 186340, 186303, 186338, 186301, 186343, 186306, --Mail 186350, 186315, 186314, 186349, 186347, 186312, 186316, 186351, 186369, 186346, 186311, --Plate --Sold by Death's Advance 187538, 187539, 187540, 187541, --Sold by the Archivist 187534, 187535, 187536, 187537, }; local shardData = { --R2 Ominious R3 Desolate R4 Forboding R5 Portentous --[itemID] = {typeID, rank, effectID}, typeID: 1 Unholy/ 2 Frost/ 3 Blood effectID: 1 Healing(SHOW_COMBAT_HEALING) / 2 Defensive(ABSORB)/ 3 Tertiary(STAT_SPEED)/ 4 Tertiary(STAT_LIFESTEAL)/ 5 Offensive(CLUB_FINDER_DAMAGE) --Unholy [187079] = {2, 1, 1}, --Zed R1 Healing [187292] = {2, 2, 1}, --Zed R2 [187301] = {2, 3, 1}, --Zed R3 [187310] = {2, 4, 1}, --Zed R4 [187320] = {2, 5, 1}, --Zed R5 [187076] = {2, 1, 3}, --Oth R1 Tertiary [187291] = {2, 2, 3}, --Oth R2 [187300] = {2, 3, 3}, --Oth R3 [187309] = {2, 4, 3}, --Oth R4 [187319] = {2, 5, 3}, --Oth R5 [187073] = {2, 1, 5}, --Dyz R1 Offensive [187290] = {2, 2, 5}, --Dyz R2 [187299] = {2, 3, 5}, --Dyz R3 [187308] = {2, 4, 5}, --Dyz R4 [187318] = {2, 5, 5}, --Dyz R5 --Frost [187071] = {1, 1, 1}, --Tel R1 Healing [187289] = {1, 2, 1}, --Tel R2 [187298] = {1, 3, 1}, --Tel R3 [187307] = {1, 4, 1}, --Tel R4 [187317] = {1, 5, 1}, --Tel R5 [187065] = {1, 1, 2}, --Kyr R1 Defensive [187288] = {1, 2, 2}, --Kyr R2 [187297] = {1, 3, 2}, --Kyr R3 [187306] = {1, 4, 2}, --Kyr R4 [187316] = {1, 5, 2}, --Kyr R5 [187063] = {1, 1, 5}, --Cor R1 Offensive [187287] = {1, 2, 5}, --Cor R2 [187296] = {1, 3, 5}, --Cor R3 [187305] = {1, 4, 5}, --Cor R4 [187315] = {1, 5, 5}, --Cor R5 --Blood [187061] = {3, 1, 4}, --Rev R1 Tertiary [187286] = {3, 2, 4}, --Rev R2 [187295] = {3, 3, 4}, --Rev R3 [187304] = {3, 4, 4}, --Rev R4 [187314] = {3, 5, 4}, --Rev R5 [187059] = {3, 1, 1}, --Jas R1 Healing [187285] = {3, 2, 1}, --Jas R2 [187294] = {3, 3, 1}, --Jas R3 [187303] = {3, 4, 1}, --Jas R4 [187313] = {3, 5, 1}, --Jas R5 [187057] = {3, 1, 5}, --Bek R1 Offensive [187284] = {3, 2, 5}, --Bek R2 [187293] = {3, 3, 5}, --Bek R3 [187302] = {3, 4, 5}, --Bek R4 [187312] = {3, 5, 5}, --Bek R5 }; Narci.DominationShards = shardData; local shardEffects = { [1] = SHOW_COMBAT_HEALING, [2] = ABSORB, [3] = STAT_SPEED, [4] = STAT_LIFESTEAL, [5] = CLUB_FINDER_DAMAGE, } local shardTypes = { [1] = "Frost", [2] = "Unholy", [3] = "Blood", }; local typeColors = { [1] = "C41E3A", [2] = "", [3] = "", }; local shardSchool = { {name = "FROST", spellIcon = 135833, spellID = 355724, color = {66, 129, 220}, }, {name = "UNHOLY", spellIcon = 425955, color = {144, 33, 255}, }, {name = "BLOOD", spellIcon = 132096, color = {200, 28, 28}, }, }; for k, v in pairs(shardSchool) do local name = _G["RUNE_COST_"..v.name]; if name then name = string.gsub(name, "%%s", ""); --Remove %s name = string.gsub(name, "^%s*(.-)%s*$", "%1"); --Remove space v.localizedName = name; else v.localizedName = name; end end local function GetShardBonus(itemID) if itemID then local data = shardData[itemID]; if data then return "|cff808080R"..data[2].."|r ".. (shardEffects[ data[3] ] or "") end end end local function GetDominationShardTexture(itemID) if itemID then local data = shardData[itemID]; if data then return "Interface/AddOns/Narcissus/Art/GemBorder/Domination/"..(shardTypes[data[1]] or "Empty") end end end local isDominationItem = {}; for _, id in pairs(dominationItems) do isDominationItem[id] = true; end dominationItems = nil; local function DoesItemHaveDomationSocket(itemID) return isDominationItem[itemID] end local function GetItemDominationGem(itemLink) if not itemLink then return; end local gemName, gemLink = GetItemGem(itemLink, 1) if gemName then return gemName, gemLink; end local tex, texID; for i = 1, 3 do tex = _G["NarciVirtualTooltip".."Texture"..i] if tex then tex = tex:SetTexture(nil); end end TP:SetHyperlink(itemLink); for i = 1, 3 do tex = _G["NarciVirtualTooltip".."Texture"..i] texID = tex and tex:GetTexture(); if texID == 4095404 then return "Empty", nil; end end end local DataProvider = {}; function DataProvider:GetShardInfo(itemLink) --return type, rank if not itemLink then return 0, 0 end local itemID = GetItemInfoInstant(itemLink); if itemID and shardData[itemID] then return unpack(shardData[itemID]); else return 0, 0 end end function DataProvider:GetShardEffect(item) if not item then return end; if type(item) == "number" then TP:SetItemByID(item); else TP:SetHyperlink(item); end local line = _G["NarciVirtualTooltipTextLeft5"]; if line then return line:GetText(); end end function DataProvider:GetShardTypeLocalizedName(shardType) return shardSchool[shardType].localizedName; end function DataProvider:GetBonusSpellInfo(shardType) local spellID = shardSchool[shardType].spellID; if not spellID then return end; if C_Spell.IsSpellDataCached(spellID) then local name = GetSpellInfo(spellID); return name, GetSpellDescription(spellID); else C_Spell.RequestLoadSpellData(spellID); end end function DataProvider:GetHeaderText() if SHARD_OF_DOMINATION then return SHARD_OF_DOMINATION else TP:SetItemByID(187063); local line2 = _G["NarciVirtualTooltipTextLeft2"]; SHARD_OF_DOMINATION = line2 and line2:GetText(); return SHARD_OF_DOMINATION or (COLOR_DOMINATION.."Shard of Domination".."|r"); end end local candidateSlots = { [1] = "Head", [3] = "Shoulder", [5] = "Chest", [6] = "Waist", [8] = "Feet", [9] = "Wrist", [10] = "Hand", }; local function SortFunc_Items(a,b) local typeA, rankA = DataProvider:GetShardInfo(a.gemLink); local typeB, rankB = DataProvider:GetShardInfo(b.gemLink); if typeA == typeB then if rankA == rankB then return a.slotID < b.slotID; else return rankA > rankB; end else return typeA < typeB end end local function GetEquippedDomiationGearData() local itemID, itemLink; local gemName, gemLink; local numItems = 0; local data = {}; local itemLocation = ItemLocation:CreateEmpty(); for slotID in pairs(candidateSlots) do itemLocation:SetEquipmentSlot(slotID); if DoesItemExist(itemLocation) then itemID = GetItemID(itemLocation); if DoesItemHaveDomationSocket(itemID) then numItems = numItems + 1; itemLink = GetItemLink(itemLocation); gemName, gemLink = GetItemDominationGem(itemLink); data[numItems] = {slotID = slotID, gemName = gemName, gemLink = gemLink}; end end end if numItems > 0 then table.sort(data, SortFunc_Items); return data end end local SlotHighlighter = {}; function SlotHighlighter:Load() self.slots = {}; self.highlights = {}; for slotID, slotName in pairs(candidateSlots) do self.slots[slotID] = _G["Character"..slotName.."Slot"]; end self.Load = nil; end function SlotHighlighter:HighlightSlot(slotID, shardType, shardRank) if self.Load then self:Load(); end local slotButton = self.slots[slotID]; if slotButton then local highlight = self.highlights[slotID]; if not highlight then highlight = CreateFrame("Frame", nil, slotButton, "NarciDomimationItemHighlight"); highlight:ClearAllPoints(); highlight:SetPoint("TOPLEFT", slotButton, "TOPLEFT", -18, 18); highlight:SetPoint("BOTTOMRIGHT", slotButton, "BOTTOMRIGHT", 18, -18); local a = 2 * highlight:GetSize(); highlight.BorderHighlight:SetSize(a, a); self.highlights[slotID] = highlight; end highlight:Set(shardType, shardRank); highlight:Shine(); end end function SlotHighlighter:DehighlightAllSlots() if self.highlights then for k, highlight in pairs(self.highlights) do highlight:Hide(); end end end function SlotHighlighter:HighlightAllSlots() self:DehighlightAllSlots(); local itemData = GetEquippedDomiationGearData(); if itemData then local itemLink, shardType, shardRank; for _, data in pairs(itemData) do itemLink = data.gemLink; shardType, shardRank = DataProvider:GetShardInfo(itemLink); SlotHighlighter:HighlightSlot(data.slotID, shardType, shardRank); end end end NarciAPI.GetDominationShardBonus = GetShardBonus; NarciAPI.DoesItemHaveDomationSocket = DoesItemHaveDomationSocket; NarciAPI.GetItemDominationGem = GetItemDominationGem; NarciAPI.GetEquippedDomiationGearData = GetEquippedDomiationGearData; NarciAPI.GetDominationShardTexture = GetDominationShardTexture; --------------------------------------------------------------- NarciDominationItemHighlightMixin = {}; function NarciDominationItemHighlightMixin:Set(shardType, rank) local r, g, b; if shardType and shardSchool[shardType] then r, g, b = unpack(shardSchool[shardType].color); r, g, b = r/255, g/255, b/255; else shardType = 4; r, g, b = 1, 1, 1; end self.BorderHighlight:SetVertexColor(r, g, b); --self.BorderHighlight:SetTexCoord(0.25 * (shardType - 1), 0.25 * shardType, 0.5, 0.75); if rank and rank <= 5 then self.RankIndicator:Show(); local texX, texY; if rank < 5 then texY = 0; texX = (rank - 1) * 0.25; else texY = 0.5; texX = (rank - 5) * 0.25; end self.RankIndicator:SetTexCoord(texX, texX + 0.25, texY, texY + 0.5); self.RankIndicator:SetVertexColor(r, g, b); else self.RankIndicator:Hide(); end end function NarciDominationItemHighlightMixin:Shine() self:Show(); self.BorderHighlight:Show(); self.BorderHighlight.Shine:Stop(); self.BorderHighlight.Shine:Play(); end --Test --[[ NarciAPI.HighlightDominationItems = function() SlotHighlighter:HighlightAllSlots(); end GameTooltip:HookScript("OnTooltipSetItem", function(f) local name, link = f:GetItem(); link = string.match(link, "item[%-?%d:]+") GameTooltip:AddLine(link); GameTooltip:Show(); end); --]] --[[ /script DEFAULT_CHAT_FRAME:AddMessage("\124cffa335ee\124Hitem:187284::::::::60:::::\124h[Ominous Shard of Bek]\124h\124r"); --]] local ShardMixin = {}; function ShardMixin:Shine() end function ShardMixin:SetType(typeID) typeID = typeID or 4; --4 is Empty if typeID == 0 then typeID = 4; end self:SetTexCoord(0.25 * (typeID - 1), 0.25 *typeID, 0, 1); end local EventListener = CreateFrame("Frame"); EventListener:RegisterEvent("PLAYER_ENTERING_WORLD"); EventListener:SetScript("OnEvent", function(self, event) if event == "PLAYER_ENTERING_WORLD" then self:UnregisterEvent(event); for i = 1, 3 do DataProvider:GetBonusSpellInfo(i); --cache end else if not self.pauseUpdate then self.pauseUpdate = true; C_Timer.After(0, function() PaperDollIndicator:Update(); self.pauseUpdate = nil; end); end end end); function EventListener:On() self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED"); end function EventListener:Off() self:UnregisterEvent("PLAYER_EQUIPMENT_CHANGED"); end NarciDominationIndicatorMixin = {}; function NarciDominationIndicatorMixin:OnLoad() PaperDollIndicator = self; local parentFrame = CharacterStatsPane.ItemLevelFrame; self:ClearAllPoints(); self:SetParent(parentFrame); self:SetFrameStrata("HIGH"); self:SetPoint("CENTER", parentFrame, "RIGHT", 10, 0); parentFrame:HookScript("OnShow", function() if self.isEnabled then EventListener:On(); self:Update(); end end); parentFrame:HookScript("OnHide", function() EventListener:Off(); end); end function NarciDominationIndicatorMixin:OnEnter() local data = GetEquippedDomiationGearData(); if not data then return end; local tooltip = GameTooltip; SharedTooltip_SetBackdropStyle(tooltip, GAME_TOOLTIP_BACKDROP_STYLE_RUNEFORGE_LEGENDARY); tooltip:SetOwner(self, "ANCHOR_NONE"); tooltip:SetPoint("TOPLEFT", self, "TOPRIGHT", 0, -10); tooltip:SetMinimumWidth(320); GameTooltip_AddBlankLineToTooltip(tooltip); local isFristLine = true; local itemLink, shardEffect, shardType, typeName, shardRank; local lastType = 0; local numData = #data; self:SetNodeLayout(numData); for i = 1, numData do itemLink = data[i].gemLink; shardEffect = DataProvider:GetShardEffect(itemLink); shardType, shardRank = DataProvider:GetShardInfo(itemLink); self.nodes[i]:SetType(shardType); if isFristLine then isFristLine = false; tooltip:SetText( DataProvider:GetHeaderText() ); local completeTypeID = self.completeTypeID; if completeTypeID then local spellName, spellDescription = DataProvider:GetBonusSpellInfo(completeTypeID); if spellName and spellDescription then tooltip:AddLine(spellName, 1, 1, 1, true); tooltip:AddLine(spellDescription, 0.1255, 1, 0.1255, true); end end if self.numEmpty then tooltip:AddLine(self.numEmpty.. " "..EMPTY.." " .. EMPTY_SOCKET_DOMINATION, 0.5, 0.5, 0.5, true); end end if shardType ~= 0 and shardType ~= lastType then lastType = shardType; typeName = DataProvider:GetShardTypeLocalizedName(shardType); GameTooltip_AddBlankLineToTooltip(tooltip); tooltip:AddLine(typeName, 1, 1, 1, true); end if shardEffect then tooltip:AddLine(COLOR_DOMINATION.."Rank "..shardRank.."|r "..shardEffect, 0.8, 0.8, 0.8, true, 0); end --Highlight Slot SlotHighlighter:HighlightSlot(data[i].slotID, shardType, shardRank); end tooltip:Show(); --FadeFrame(self.Highlight, 0.25, 1); self.Highlight:Show(); self:CheckSetBonus(); end function NarciDominationIndicatorMixin:OnLeave() GameTooltip:Hide(); --FadeFrame(self.Highlight, 0.25, 0); SlotHighlighter:DehighlightAllSlots(); self.Highlight:Hide(); end function NarciDominationIndicatorMixin:OnShow() end function NarciDominationIndicatorMixin:OnHide() end function NarciDominationIndicatorMixin:SetEnabled(state) self.isEnabled = state; if state then if CharacterFrame:IsVisible() then EventListener:On(); self:Update(); end else self:Hide(); EventListener:Off(); end end function NarciDominationIndicatorMixin:IsNarcissusUI() local id = self:GetID(); return (id and id == 1) end function NarciDominationIndicatorMixin:Update() local data = GetEquippedDomiationGearData(); if data then self:Show(); else self:Hide(); return false; end local numShards = #data; self:SetNodeLayout(numShards); self.completeTypeID = nil; local itemLink, shardEffect, shardType, shardRank; local lastType; local numSetPiece = 0; local numEmpty = 0; for i = 1, numShards do itemLink = data[i].gemLink; shardEffect = DataProvider:GetShardEffect(itemLink); --Load Data shardType, shardRank = DataProvider:GetShardInfo(itemLink); self.nodes[i]:SetType(shardType); if shardType == 0 then numEmpty = numEmpty + 1; else if shardType ~= lastType then numSetPiece = 1; lastType = shardType; else numSetPiece = numSetPiece + 1; if numSetPiece >= 3 then self.completeTypeID = shardType; end end end end if numEmpty > 0 then self.numEmpty = numEmpty; else self.numEmpty = nil; end self:CheckSetBonus(); return true; end function NarciDominationIndicatorMixin:ShowTooltip(tooltip, point, relativeTo, relativePoint, offsetX, offsetY) local data = GetEquippedDomiationGearData(); if not data or not tooltip then return end; SharedTooltip_SetBackdropStyle(tooltip, GAME_TOOLTIP_BACKDROP_STYLE_RUNEFORGE_LEGENDARY); tooltip:SetOwner(self, "ANCHOR_NONE"); tooltip:SetPoint(point, relativeTo, relativePoint, offsetX, offsetY); tooltip:SetMinimumWidth(320); GameTooltip_AddBlankLineToTooltip(tooltip); local isFristLine = true; local itemLink, shardEffect, shardType, typeName, shardRank; local lastType = 0; local numData = #data; for i = 1, numData do itemLink = data[i].gemLink; shardEffect = DataProvider:GetShardEffect(itemLink); shardType, shardRank = DataProvider:GetShardInfo(itemLink); if isFristLine then isFristLine = false; tooltip:SetText( DataProvider:GetHeaderText() ); local completeTypeID = self.completeTypeID; if completeTypeID then local spellName, spellDescription = DataProvider:GetBonusSpellInfo(completeTypeID); if spellName and spellDescription then tooltip:AddLine(spellName, 1, 1, 1, true); tooltip:AddLine(spellDescription, 0.1255, 1, 0.1255, true); end end if self.numEmpty then tooltip:AddLine(self.numEmpty.. " "..EMPTY.." " .. EMPTY_SOCKET_DOMINATION, 0.5, 0.5, 0.5, true); end end if shardType ~= 0 and shardType ~= lastType then lastType = shardType; typeName = DataProvider:GetShardTypeLocalizedName(shardType); GameTooltip_AddBlankLineToTooltip(tooltip); tooltip:AddLine(typeName, 1, 1, 1, true); end if shardEffect then tooltip:AddLine(COLOR_DOMINATION.."Rank "..shardRank.."|r "..shardEffect, 0.8, 0.8, 0.8, true, 0); end end tooltip:Show(); end local nodeLayout = { [1] = {0}, [2] = {1, -1}, [3] = {2, 0, -2}, [4] = {2, 1, -1, -2}, [5] = {2, 1, 0, -1, -2}, }; function NarciDominationIndicatorMixin:SetNodeLayout(numShards) if not self.nodes then self.nodes = {}; end local isNarcissus = self:IsNarcissusUI(); if numShards > 0 then local layout = nodeLayout[numShards]; if not layout then return end; local node; local pi2 = 2 * math.pi; for i = 1, numShards do node = self.nodes[i]; if not node then node = self:CreateTexture(nil, "OVERLAY", "NarciDominationIndicatorNodeTemplate", 5); node:ClearAllPoints(); node:SetPoint("CENTER", self, "CENTER", 0, 0); local a = self:GetWidth(); node:SetSize(a/2, a); if isNarcissus then node:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Widgets\\Domination\\ShardNode"); else node:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Widgets\\Domination\\ShardNodeTiny"); end Mixin(node, ShardMixin); node:SetType(4); self.nodes[i] = node; end node:SetRotation(layout[i]/6 * pi2); node:Show(); end for i = numShards + 1, #self.nodes do self.nodes[i]:Hide(); end else for i = 1, #self.nodes do self.nodes[i]:Hide(); end end end function NarciDominationIndicatorMixin:CheckSetBonus() local setID = self.completeTypeID; if setID then local icon = shardSchool[setID].spellIcon; if self.IconBorder then self.IconBorder:Show(); else self.Background:SetTexCoord(0.25, 0.5, 0, 0.25); end self.SpellIcon:Show(); self.SpellIcon:SetTexture(icon); local _, isBonusActive = GetPlayerAuraBySpellID(355752); --Runic Dominion Maw & Torghast if isBonusActive then self.SpellIcon:SetVertexColor(1, 1, 1); self.SpellIcon:SetDesaturated(false); else self.SpellIcon:SetVertexColor(0.6, 0.6, 0.6); self.SpellIcon:SetDesaturated(true); end else if self.IconBorder then self.IconBorder:Hide(); else self.Background:SetTexCoord(0, 0.25, 0, 0.25); end self.SpellIcon:Hide(); end end --/dump UnitBuff("player", 6) --Narcissus UI