Narci_EquipmentSetManager = {}; local ESM = Narci_EquipmentSetManager; local L = Narci.L; local EquipmentSetDB; --NarcissusDB_PC.EquipmentSetDB local EquipmentSetManagerFrame; local MAX_TALENT_TIERS = 7; local MAX_SETS = MAX_EQUIPMENT_SETS_PER_PLAYER or 10; local Format_Digit = "%.2f"; local PREFIX_RED = "|cffff5050"; local PREFIX_YELLOW = "|cFFFFD100"; local PREFIX_GREY = "|cffa6a6a6"; --65% White local ICON_NEW_SET = "Interface\\AddOns\\Narcissus\\Art\\Widgets\\EquipmentSetManager\\NewSet"; local ICON_SELECTED = " |TInterface\\AddOns\\Narcissus\\Art\\Widgets\\Arrows\\Tick:12:12:0:0:64:64:0:64:0:64|t"; local SETBUTTON_HEIGHT = 48; local _; local FadeFrame = NarciFadeUI.Fade; local GetItemStats = NarciAPI_GetItemStats; local SmartFontType = NarciAPI.SmartFontType; local GetAllSelectedTalentIDsAndIcons = NarciAPI.GetAllSelectedTalentIDsAndIcons; local DoesItemExist = C_Item.DoesItemExist; local C_EquipmentSet = C_EquipmentSet; local GetNumEquipmentSets = C_EquipmentSet.GetNumEquipmentSets; --Returns the number of saved equipment sets. local GetItemLocations = C_EquipmentSet.GetItemLocations; local GetEquipmentSetInfo = C_EquipmentSet.GetEquipmentSetInfo; local UnpackLocation = EquipmentManager_UnpackLocation; local GetItemInventoryType = C_Item.GetItemInventoryType; local After = C_Timer.After; local sin = math.sin; local cos = math.cos; local max = math.max; local pi = math.pi; local NarciThemeUtil = NarciThemeUtil; ----------------------------------------------------------------------------------- --[[ LibEasing -- -- Original Lua implementations -- from 'EmmanuelOga' -- https://github.com/EmmanuelOga/easing/ -- -- Adapted from -- Tweener's easing functions (Penner's Easing Equations) -- and http://code.google.com/p/tweener/ (jstweener javascript version) --]] local function outSine(t, b, c, d) return c * sin(t / d * (pi / 2)) + b end local function inOutSine(t, b, c, d) return -c / 2 * (cos(pi * t / d) - 1) + b end ----------------------------------------------------------------------------------- local DataProvider = {}; function DataProvider:SetNumMissingSets(numMissing) if numMissing < 0 then if not self.numMissing then self.numMissing = 0; else self.numMissing = max(0, self.numMissing - 1); end else self.numMissing = numMissing; end return self.numMissing; end function DataProvider:GetNumMissingSets() if not self.numMissing then self.numMissing = 0; return 0 else return self.numMissing; end end local function GetMaxAndKey(table) --Get the biggest and 2nd biggest number in a table and their keys --/dump GetMaxAndKey({1,128,129,126}) if not table and type(table) ~="table" and #table < 2 then return; end; local max1,key1, max2, key2; for k, v in pairs(table) do if not max1 then max1 = v; key1 = k; elseif not max2 then max2 = v; key2 = k; end if table[k] > max1 then max2 = max1; key2 = key1; max1 = v; key1 = k; elseif max2 and table[k] > max2 then max2 = v; key2 = k end end return max1,key1, max2, key2; end local RepositionFrame = CreateFrame("Frame", nil, nil, "NarciUpdateFrameTemplate"); RepositionFrame.isOpen = false; RepositionFrame:Hide(); RepositionFrame.duration = 0.35; local function RepositionFrame_OnShow(self) if not self.anchorTo then self.anchorTo = Narci_RadarChartFrame; end self.point, self.relativeTo, self.relativePoint, _, self.StartPoint = self.anchorTo:GetPoint(); end local function UpdateEquipmentSetButtonPosition(parentOffset) --offset: -24 ~ -96 → 48 ~ 0 y = 2/3 * x + 64 local buttons = ESM.buttons; local button = buttons[1]; local offset = parentOffset * 2 / 3 + 64; button:SetPoint("TOP", button:GetParent(), "TOP", 0, offset); for i = 2, #buttons do buttons[i]:SetPoint("TOP", buttons[i -1], "BOTTOM", 0, offset); end end local function RepositionFrame_OnUpdate(self, elapsed) self.t = self.t + elapsed local EndPoint = self.EndPoint; local StartPoint = self.StartPoint; local offset = outSine(self.t, StartPoint, EndPoint - StartPoint, self.duration); if self.t >= self.duration then offset = EndPoint; self:Hide(); end self.anchorTo:SetPoint(self.point, self.relativeTo, self.relativePoint, 0, offset); UpdateEquipmentSetButtonPosition(offset); end RepositionFrame:SetScript("OnShow", RepositionFrame_OnShow); RepositionFrame:SetScript("OnUpdate", RepositionFrame_OnUpdate); ---------------------------------------------------------------------------------- ---- For GamePad ---- function ESM:GetSetButtons() return self.buttons end function ESM:GetNumSetButtons() return self.numSetButton or 1 end function ESM:OnNumSetsChanged(numSets) end ---------------------------------------------------------------------------------- local function LoadSetInfo(SetButton, SetName) local equipmentSetID = SetButton.setID; if not EquipmentSetDB or not equipmentSetID then return end local texs = SetButton.texs; local icon; local SetInfo = EquipmentSetDB[equipmentSetID]; local tier = 1; if SetInfo and SetName == SetInfo[1] then local SavedTalents = SetInfo[2]; for i = #SavedTalents, 1, -1 do icon = SavedTalents[tier][2]; texs[i]:SetTexture(icon); texs[i]:Show(); tier = tier + 1; end end end local function SaveSetInfo(setID) --Save current set name and talents in the database if not EquipmentSetDB then return; end; local talentInfo = GetAllSelectedTalentIDsAndIcons(); local name = GetEquipmentSetInfo(setID); if name then EquipmentSetDB[setID] = {name, talentInfo}; end end local function WipeSetInfo(setID) if not EquipmentSetDB then return; end; EquipmentSetDB[setID] = nil; end local function AsignTalentIcons(button) --/run Narci_EquipmentSetManager:AsignTalentIcons(TV) local texs = button.texs; local talentInfo = GetAllSelectedTalentIDsAndIcons(); local tiers = #talentInfo; if not tiers or tiers < 1 then return; end; local index = 1; for i = tiers, 1, -1 do texs[index]:SetTexture(talentInfo[i].texture); texs[index]:Show(); index = index + 1; end end local function FadeInTalentIcons(button, action) local texFrame = button.texFrame; if action then FadeFrame(texFrame, 0.15, 1); else FadeFrame(texFrame, 0.2, 0.4); end end local function SetBackgroundColor(self) local r, g, b = NarciThemeUtil:GetColor(); self.Bar2:SetColorTexture(r, g, b, 0.75); self.Color:SetColorTexture(r, g, b, 0.75); end local function AnimateBackgroundColor(self) local r, g, b = NarciThemeUtil:GetColor(); self.Color:SetColorTexture(r, g, b, 0.75); self.BarColors = {r, g, b}; self.Bar2.animBling:Play(); end local function ResetBackgroundColor(button) button.Bar1:SetColorTexture(0.1, 0.1, 0.1, 0.75); button.Bar2:SetColorTexture(0.25, 0.25, 0.25, 0.75); button.Color:SetColorTexture(0.2, 0.2, 0.2, 0.75); end local function ResetAllBackgroundColor() local buttons = ESM.buttons; for i = 1, #buttons do ResetBackgroundColor(buttons[i]); end end local KeyStats = {"prim", "stamina", "crit", "haste", "mastery", "versatility", "ilvl", "gems"}; local StatsName = {["crit"] = NARCI_CRITICAL_STRIKE, ["haste"] = STAT_HASTE, ["mastery"] = STAT_MASTERY, ["versatility"] = STAT_VERSATILITY,}; local function InventoryTypeToInventorySlotID(Types) if not Types then return {}; end; local SlotIDs = {}; local slotID; for _, v in pairs(Types) do slotID = nil; if v > 0 and v < 11 then --this is the range where SlotID matches the TypeID slotID = v; elseif v == 11 then --finger if not SlotIDs[11] then slotID = 11; else slotID = 12; end elseif v == 12 then --trinket if not SlotIDs[13] then slotID = 13; else slotID = 14; end elseif v == 13 or v == 21 then --One-Hand/Main hand slotID = 16; elseif v == 14 or v == 22 then --Off-hand slotID = 17; elseif v == 15 or v == 17 then --Ranged/Two-Hand slotID = 16; elseif v == 16 then --Back slotID = 15; elseif v == 19 then --Tabard slotID = 19; elseif v == 20 then --Shirt slotID = 5; end if slotID then SlotIDs[slotID] = true; end end return SlotIDs; end local function GetTotalStats(equipmentSetID) --print("|cFFFFD100"..equipmentSetID.."|r"); local locations = GetItemLocations(equipmentSetID) if not locations then return; end; local player, bank, bags, voidStorage, slot, bag; local itemlocation; local TotalStats, Stats = {}, {}; local toltalItems = 0; --Ignore 4/19 Tabard & shirt local inventoryType; local IncludedTypes = {}; local KeyStats = KeyStats; local function add(key) TotalStats[key] = TotalStats[key] + Stats[key]; end for i = 1, #KeyStats do TotalStats[KeyStats[i]] = 0; end for k, v in pairs(locations) do itemlocation = nil; if k ~= 4 and k ~= 19 and v then --ignore shirt and tabard during calculation toltalItems = toltalItems + 1; player, bank, bags, voidStorage, slot, bag = UnpackLocation(v); if bag and slot then --print("bag: "..bag.." slot: "..slot); itemlocation = ItemLocation:CreateFromBagAndSlot(bag, slot); if itemlocation then inventoryType = GetItemInventoryType(itemlocation); tinsert(IncludedTypes, inventoryType); end elseif slot then --print("slot: "..slot); itemlocation = ItemLocation:CreateFromEquipmentSlot(slot); end if itemlocation then Stats = GetItemStats(itemlocation); local itemName = C_Item.GetItemName(itemlocation); --print(string.format("|cff959595%s:|r %s, %s, %s, %s, %s", itemName, Stats.crit, Stats.haste, Stats.mastery, Stats.versatility, Stats.stamina)); for j = 1, #KeyStats do add(KeyStats[j]) end end end end TotalStats.AverageIlvl = math.floor(100*TotalStats.ilvl/toltalItems + 0.5)/100; TotalStats.IncludedSlots = InventoryTypeToInventorySlotID(IncludedTypes); return TotalStats; end local RelevantSlots = {1, 2, 3, 5, 6, 7, 8, 9 ,10 ,11, 12, 13, 14 ,15, 16, 17}; --Irrelevant: 4 Shirt, 19 Tabard local HealthFactor = 1; local function GetHPFactor() --Calculate stamina → Health conversion rate local ConversionRate; local stamina, _, posBuff, negBuff = UnitStat("player", LE_UNIT_STAT_STAMINA); local BasicStamima = stamina - posBuff - negBuff; local Health = UnitHealth("player"); if stamina == 0 then ConversionRate = 20; else ConversionRate = Health / stamina; end --Calculate stamina gain from current equipment local Stats; local StaminaFromItems = 0; local itemlocation; for i = 1, #RelevantSlots do itemlocation = ItemLocation:CreateFromEquipmentSlot(RelevantSlots[i]); if DoesItemExist(itemlocation) then Stats = GetItemStats(itemlocation); StaminaFromItems = StaminaFromItems + Stats.stamina; end end HealthFactor = ConversionRate * stamina / (StaminaFromItems + BasicStamima) ; end --[[ --Deprecated Method local function GetHealthFactor() --Calculate stamina → Health conversion rate local ConversionRate; local stamina = UnitStat("player", LE_UNIT_STAT_STAMINA); local Health = UnitHealth("player"); if stamina == 0 then ConversionRate = 20; else ConversionRate = Health / stamina; end --Calculate Stamina bonus from spec (tank) and Heart --Gained from Azerite Heart Essence local EXP = 0; --exponential local slotId = 2; --Neck local itemLocation = ItemLocation:CreateFromEquipmentSlot(slotId); if DoesItemExist(itemLocation) and C_AzeriteItem.IsAzeriteItem(itemLocation) then local GetMilestoneInfo = C_AzeriteEssence.GetMilestoneInfo; local info; for i = 110, 113 do info = GetMilestoneInfo(i); if info and info.unlocked then EXP = EXP + 1; else break; end end end local HeartBonus = 1.03^EXP; --3% --Gained from Armor Skill local spec = GetSpecialization() or 1; local role = GetSpecializationRole(spec); local ArmorBonus = 1; if role == "TANK" and UnitLevel("player") >= 50 then --Prim stat bonus starts at level 50 **9.0 Level Squash ArmorBonus = 1.05; end --Gained from other spell local SpellBonus = 1; if IsSpellKnown(203513) then --Demonic Wards DH SpellBonus = 1.65; elseif IsSpellKnown(48263) then --Veteran of the Third War DK if role == "TANK" then SpellBonus = 1.65; else SpellBonus = 1.10; end end print(string.format("%s | %s, %s, %s", ConversionRate, HeartBonus, ArmorBonus, SpellBonus)); HealthFactor = ConversionRate * HeartBonus * ArmorBonus * SpellBonus; end --]] local function GetEquipmentSetStatsAndHealth(equipmentSetID) local Stats, tempTable = {}, {}; tempTable = GetTotalStats(equipmentSetID); if not tempTable then return; end; Stats.crit, Stats.haste, Stats.mastery, Stats.versatility = tempTable.crit, tempTable.haste, tempTable.mastery, tempTable.versatility; local max1, key1, max2, key2 = GetMaxAndKey(Stats) local stat, effectiveStat, posBuff, negBuff = UnitStat("player", LE_UNIT_STAT_STAMINA); local base = stat - posBuff - negBuff; local health = (base + tempTable.stamina) * HealthFactor; --HP20/Stamina --print("HP: "..health) health = math.floor(health / 1000); return max1,key1, max2, key2, health, tempTable; end local isDuplicatedSet = false; local function InitializeOptionalSetButton(frame, equipmentSetID, avgItemLevel) --/run Narci_EquipmentSetManager:InitializeOptionalSetButton(TV) equipmentSetID = equipmentSetID or 1; --AsignTalentIcons(frame); local name, iconFileID, setID, isEquipped, numItems, _, _, numLost, _ = GetEquipmentSetInfo(equipmentSetID); frame.numLost = numLost; local max1,key1, max2, key2, health, statsTable = GetEquipmentSetStatsAndHealth(equipmentSetID); local statString = StatsName[key1]; if key2 then --statString = statString.." |cff959595".."||".."|r "..StatsName[key2]; statString = statString.." || "..StatsName[key2]; end frame.SetIcon.Icon:SetTexture(iconFileID); frame.iconID = iconFileID; frame.SetName:SetText(name); frame.SetName:Disable(); After(0, function() SmartFontType(frame.SetName); end) frame.Health:SetText(health.." K") frame.statsTable = statsTable; frame.setID = equipmentSetID; local ilvl = math.floor(statsTable.AverageIlvl); if avgItemLevel and ilvl < avgItemLevel - 15 then frame.IlvlBackground:SetColorTexture(1, 0.3137, 0.3137, 1); --Mark it red statString = PREFIX_RED .. L["Low Item Level"]; else frame.IlvlBackground:SetColorTexture(1, 1, 1, 0.6); statString = PREFIX_GREY .. statString; end if numItems < 11 then--Naked set ilvl = "N/A"; frame.IlvlBackground:SetColorTexture(1, 1, 1, 0.25); end frame.Ilvl:SetText(ilvl); local isItemMissing = numLost > 0; frame.hasMissingItem = isItemMissing; if isItemMissing then if numLost == 1 then statString = L["1 Missing Item"]; else statString = string.format(L["n Missing Items"], numLost); end if numLost < 3 then statString = PREFIX_YELLOW .. statString; else statString = PREFIX_RED .. statString; end end if isDuplicatedSet and isEquipped then statString = PREFIX_YELLOW .. L["Duplicated Set"]; end isDuplicatedSet = (isDuplicatedSet or isEquipped); frame.Enhancement:SetText(statString); if isEquipped then SetBackgroundColor(frame); end LoadSetInfo(frame, name); frame.Bar1:SetHeight(SETBUTTON_HEIGHT / 2); frame.TalentAnchor:SetPoint("RIGHT", frame.Bar1, "TOPRIGHT", 0, -12); frame:Show(); --print("setID: "..setID) return isItemMissing end local UpdateEquipmentNum; local ShouldUpdateEquipment = false; local ShouldUpdateTalent = false; local function ShowOrHideSettings(self, visibility, useAnimation) if useAnimation then if visibility then FadeFrame(self.ConfirmButton, 0.15, 1); FadeFrame(self.CancelButton, 0.15, 1); FadeFrame(self.DeleteButton, 0.15, 1); else FadeFrame(self.DeleteButton, 0.15, 0); FadeFrame(self.ConfirmButton, 0.15, 0); FadeFrame(self.CancelButton, 0.15, 0); end else self.DeleteButton:SetShown(visibility); self.ConfirmButton:SetShown(visibility); self.CancelButton:SetShown(visibility); end end local function UpdateScrollRange() local frame = EquipmentSetManagerFrame; local savedSets = GetNumEquipmentSets() or 0; local TotalButton = math.min(savedSets + 1, MAX_SETS); local buttonHeight = SETBUTTON_HEIGHT; local TotalTab = max(TotalButton - 4, 1); local MaxScroll = math.floor((TotalTab - 0.5) * buttonHeight + 0.5); frame.ListScrollFrame.range = MaxScroll; frame.ListScrollFrame.scrollBar:SetMinMaxValues(0, MaxScroll) --[[ Switch.Level:SetText(savedSets.."/"..MAX_SETS); Switch.Header:SetText("SETS"); --]] end local function InitializeEquipmentSetManager() --Refresh stamina factor GetHPFactor(); isDuplicatedSet = false; ------------------------ local button; local buttons = ESM.buttons; local SetIDs = C_EquipmentSet.GetEquipmentSetIDs() or {}; local setID; local totalSets = GetNumEquipmentSets(); local avgItemLevel = GetAverageItemLevel(); local isItemMissing; local numMissing = 0; local numVisible = 0; for i = 1, MAX_SETS do setID = SetIDs[i]; button = buttons[i]; if setID then isItemMissing = InitializeOptionalSetButton(button, setID, avgItemLevel); ShowOrHideSettings(button, false, true); if isItemMissing then if numMissing then numMissing = numMissing + 1; else numMissing = 1; end end numVisible = numVisible + 1; else button.setID = nil; button.SetIcon.Icon:SetTexture(ICON_NEW_SET); button.SetName:SetText(PAPERDOLL_NEWEQUIPMENTSET); button.SetName:Enable(); button.SetName:ClearFocus(); if i == totalSets + 1 then button:Show(); --to create new set: if there are 3 saved sets, this button will be #4 numVisible = numVisible + 1; else button:Hide(); end button:Reset(); end button:SetID(i); button:SetHeight(SETBUTTON_HEIGHT); end DataProvider:SetNumMissingSets(numMissing); Narci_NavBar:UpdateSets(totalSets, numMissing); ESM.numSetButton = numVisible; ESM:OnNumSetsChanged(numVisible); end local function SetEnhancements(c, h, m, v) --crit, haste, mastery, versatility --In order to preview the stats on each set, the radar chart and four enchancement stats stop auto updating once equipment set manager is activated --So enchancement stats need to be set manually local Radar = Narci_RadarChartFrame; local ConvertRatio = Narci.ConvertRatio; local table = {{c, "crit"}, {h, "haste"}, {m, "mastery"}, {v, "versatility"}}; local stat = 0; local percent = 0; local statBase = 0; local ratio = 0; local ratingText; local percentageText; local key; for i = 1, #table do key = table[i][2]; stat = table[i][1]; --rating statBase = ConvertRatio[key.."Base"]; ratio = ConvertRatio[key] or ratio; percent = max(0, stat * ratio + statBase); --Convert a rating to percentage / + basic percent (example: 10% basic critical chance) percentageText = string.format(Format_Digit, percent).."%"; key = string.gsub(key, "^%l", string.upper) Radar[key].ValueRating:SetText(stat); Radar[key].Value:SetText(percentageText); end end local function HighlightRelevantSlots(table) local slotTable = Narci.slotTable; for i = 1, #slotTable do slotTable[i].Highlight:Hide(); slotTable[i].Highlight:SetAlpha(0); end if not table then return; end; for k, v in pairs(table) do if v then slotTable[k].Highlight:Show(); slotTable[k].Highlight:SetAlpha(1); end end end ---------------------------------------------------------- --Event listener local function InitializeScripts() local Overlay1 = EquipmentSetManagerFrame.ListScrollFrame.OverlayFrame1; local SaveItemButton = Overlay1.SaveItem; local SaveTalentButton = Overlay1.SaveTalent; local function ChangeColorAndText(self) if self.IsOn then self.Background:SetColorTexture(self.r, self.g, self.b); self:SetText(self.EnabledText.. ICON_SELECTED); else self.Background:SetColorTexture(0.2, 0.2, 0.2); self:SetText(PREFIX_GREY .. self.EnabledText); end end local function SaveButton_OnShow(self) ChangeColorAndText(self); end local function SaveItemButton_OnClick(self) self.IsOn = not self.IsOn; ShouldUpdateEquipment = self.IsOn; ChangeColorAndText(self); end local function SaveTalentButton_OnClick(self) self.IsOn = not self.IsOn; ShouldUpdateTalent = self.IsOn; ChangeColorAndText(self); end SaveItemButton:SetScript("OnShow", SaveButton_OnShow); SaveTalentButton:SetScript("OnShow", SaveButton_OnShow); SaveItemButton:SetScript("OnClick", SaveItemButton_OnClick); SaveTalentButton:SetScript("OnClick", SaveTalentButton_OnClick); SaveItemButton.EnabledText = L["Update Items"]; SaveItemButton.DisabledText = L["Don't Update Items"]; SaveTalentButton.EnabledText = L["Update Talents"]; SaveTalentButton.DisabledText = L["Don't Update Talents"]; end ---------------------------------------------------------- NarciEquipmentSetButtonMixin = {}; local function NarciEquipmentSetButton_AnimFrame_OnShow(self) local _; local SetButton = self:GetParent(); self.StartHeight = SetButton.Bar1:GetHeight(); _, _ , _, self.StartX = SetButton.TalentAnchor:GetPoint(); --self.fontName = SetButton.SetName:GetFont() --fontName, fontHeight, fontFlags end local function NarciEquipmentSetButton_AnimFrame_OnUpdate(self, elapsed) local t = self.t; local delay = self.Delay; local height = inOutSine(t, self.StartHeight, self.EndHeight - self.StartHeight , 0.25); local offset; if t >= 0.25 then height = self.EndHeight; else offset = self.StartX; end if t <= 0.25 + delay and t >= delay then offset = outSine(t - delay, self.StartX, self.EndX - self.StartX , 0.25); elseif t > 0.25 + delay then offset = self.EndX; self:Hide(); end local parent = self:GetParent(); parent.Bar1:SetHeight(height); parent.TalentAnchor:SetPoint("RIGHT", parent.Bar1, "TOPRIGHT", offset, -12); --parent.SetName:SetHeight(10 + height/12) --parent.SetName:SetFont(self.fontName, 10 + height/12); self.t = self.t + elapsed; end local function ShowFlyoutBlack(state) if state then Narci_FlyoutBlack:In(); else Narci_FlyoutBlack:Out(); end end local function HideIconSelector() local ListScrollFrame = Narci_EquipmentSetManagerFrame.ListScrollFrame; local Overlay1 = ListScrollFrame.OverlayFrame1; local Overlay2 = ListScrollFrame.OverlayFrame2; ESM.IconSelector:Hide(); Overlay1:Hide(); Overlay2:Hide(); ShowFlyoutBlack(false); end local function ShowIconSelector(SetButton) local Selector = ESM.IconSelector; Selector:Load(); local specName, specIcon, roleIcon, dungeonIcon, pvpIcon, spellIcons, roleName, spellNames = ESM:GetCurrentSpecializationNameAndIcons(); --Icon Selector Selector:ClearAllPoints(); Selector:SetFrameLevel(40); Selector.SetButton = SetButton; local icons = Selector.icons; local buttons = Selector.buttons; icons[1]:SetTexture(roleIcon); buttons[1].iconID = roleIcon; buttons[1].name = roleName; icons[2]:SetTexture(dungeonIcon); buttons[2].iconID = dungeonIcon; buttons[2].name = CHALLENGES; icons[3]:SetTexture(pvpIcon); buttons[3].iconID = pvpIcon; buttons[3].name = PVP; local icon, button; --print(#spellIcons) for i = 4, #icons do icon = spellIcons[i - 3]; button = buttons[i]; icons[i]:SetTexture(icon); if icon then button.iconID = icon; button.name = spellNames[i - 3]; button:Enable(); else button.iconID = nil; button.name = ""; button:Disable(); end end Selector:SetPoint("BOTTOMRIGHT", Narci_EquipmentSetManagerFrame, "BOTTOMLEFT", -4, 0); FadeFrame(Selector, 0.15, 1); ShowFlyoutBlack(true); return specName, specIcon; end local function CollapseButton(self) local AnimFrame = self.AnimFrame; AnimFrame:Hide(); AnimFrame.EndHeight = SETBUTTON_HEIGHT / 2; AnimFrame.EndX = 0; AnimFrame.Delay = 0.225; self.SetName:Disable(); ShowOrHideSettings(self, false, true); AnimFrame:Show(); end local function ExpandButton(self) local AnimFrame = self.AnimFrame; AnimFrame:Hide(); FadeFrame(self.Highlight, 0.15, 0); AnimFrame.EndHeight = SETBUTTON_HEIGHT; AnimFrame.EndX = 140; AnimFrame.Delay = 0; self.SetName:Enable(); self.SetName:SetFocus(); ShowOrHideSettings(self, true, true); local ListScrollFrame = Narci_EquipmentSetManagerFrame.ListScrollFrame; local Overlay1 = ListScrollFrame.OverlayFrame1; local Overlay2 = ListScrollFrame.OverlayFrame2; FadeFrame(ESM.IconSelector, 0.15, 1); FadeFrame(Overlay1, 0.15, 1); FadeFrame(Overlay2, 0.15, 1); AnimFrame:Show(); end local function SetToEditMode(self, bool, showExtraButton) --self = SetButton --Collapsing animation if bool then ExpandButton(self); else CollapseButton(self); return; end local ListScrollFrame = Narci_EquipmentSetManagerFrame.ListScrollFrame; local Overlay1 = ListScrollFrame.OverlayFrame1; local Overlay2 = ListScrollFrame.OverlayFrame2; Overlay1:ClearAllPoints(); Overlay2:ClearAllPoints(); Overlay1:SetPoint("TOPLEFT", ListScrollFrame, "TOPLEFT", 4, 0); Overlay1:SetPoint("BOTTOMRIGHT", self, "TOPRIGHT", 0, 0); Overlay2:SetPoint("BOTTOMRIGHT", ListScrollFrame, "BOTTOMRIGHT", -4, 0); Overlay2:SetPoint("TOPLEFT", self, "BOTTOMLEFT", 0, 0); local SaveItem = Overlay1.SaveItem; local SaveTalent = Overlay1.SaveTalent; Overlay1.TargetButton = self; if showExtraButton then SaveItem:ClearAllPoints(); SaveTalent:ClearAllPoints(); if self:GetID() == 1 then SaveItem:SetPoint("TOPLEFT", Overlay2, "TOPLEFT", 0, 0); SaveItem:SetPoint("TOPRIGHT", Overlay2, "TOP", 0, 0); else SaveItem:SetPoint("BOTTOMLEFT", Overlay1, "BOTTOMLEFT", 0, 0); SaveItem:SetPoint("BOTTOMRIGHT", Overlay1, "BOTTOM", 0, 0); end SaveTalent:SetPoint("LEFT", SaveItem, "RIGHT", 0, 0); SaveTalent:SetPoint("RIGHT", Overlay1, "RIGHT", 0, 0); if self.numLost ~= 0 and ShouldUpdateEquipment and UpdateEquipmentNum == self:GetID() then SaveItem.IsOn = true; end SaveItem:Show(); SaveTalent:Show(); else SaveItem:Hide(); SaveTalent:Hide(); end Narci_EquipmentSetManagerFrame.ArtFrame.Shadow:SetAlpha(0); end local function PlayBling(self) local Bling = EquipmentSetManagerFrame.BlingFrame; Bling:StopAnimating(); Bling:ClearAllPoints(); Bling:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0); Bling:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 0); Bling.Bling.animIn:Play(); PlaySound(117310); end local function PlayHighlight(self) local Highlight = EquipmentSetManagerFrame.HighlightFrame; Highlight:StopAnimating(); Highlight:ClearAllPoints(); Highlight:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0); Highlight:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 0); local r, g, b = NarciThemeUtil:GetColor(); local w = 0.4; r, g, b = r + w, g + w, b + w; Highlight.Color:SetColorTexture(r, g, b); Highlight.Color.animIn:Play(); end local function ShowNewSetButton() local savedSets = GetNumEquipmentSets(); local buttons = ESM.buttons; if savedSets < MAX_SETS then FadeFrame(buttons[savedSets + 1], 0.35, 1, 0); end UpdateScrollRange(); end local IgnoreSlotsForSave = C_EquipmentSet.IgnoreSlotForSave; local GetEquipmentSetIDByName = C_EquipmentSet.GetEquipmentSetID; local function IsNameDuplicated(name, setID) --Check if the new name has been taken local oldID = GetEquipmentSetIDByName(name); if oldID and oldID ~= setID then return true; else return false; end end local function CreateNewSet(self) --self = SetButton local specName, specIcon = ShowIconSelector(self); self.SetName:Enable(); self.SetName:SetFocus(); self.SetName:SetText(specName); self.SetName:HighlightText(); FadeFrame(self.Highlight, 0.15, 0); SetToEditMode(self, true, false); self:SetIconWithTransition(specIcon, specName); end local function ConfirmButton_OnClick(self) local SetButton = self:GetParent(); local setID = SetButton.setID; local name = SetButton.SetName:GetText() or SetButton.TextBackup or ""; local icon = SetButton.iconID; Narci_AlertFrame_Autohide:SetAnchor(SetButton); if IsNameDuplicated(name, setID) then --A set with that name already exists Narci_AlertFrame_Autohide:AddMessage(EQUIPMENT_SETS_CANT_RENAME, true); return; end SetToEditMode(SetButton, false); HideIconSelector(); if setID then if type(icon) == "number" then C_EquipmentSet.ModifyEquipmentSet(setID, name, icon); else C_EquipmentSet.ModifyEquipmentSet(setID, name); end local name, _, _, isEquipped = GetEquipmentSetInfo(setID); if ShouldUpdateTalent then SaveSetInfo(setID); --print("Talent Saved") end if ShouldUpdateEquipment then C_EquipmentSet.SaveEquipmentSet(setID); end LoadSetInfo(SetButton, name); After(0.25, function() isDuplicatedSet = false; InitializeOptionalSetButton(SetButton, setID); if not SetButton.hasMissingItem then DataProvider:SetNumMissingSets(-1); end local numMissing = DataProvider:GetNumMissingSets(); local savedSets = GetNumEquipmentSets(); Narci_NavBar:UpdateSets(savedSets, numMissing); end) else if type(icon) == "number" then C_EquipmentSet.CreateEquipmentSet(name, icon); else C_EquipmentSet.CreateEquipmentSet(name); end After(0.25, function() IgnoreSlotsForSave(4); IgnoreSlotsForSave(19); local NewSetID = GetEquipmentSetIDByName(name); if NewSetID then C_EquipmentSet.SaveEquipmentSet(NewSetID); SaveSetInfo(NewSetID); InitializeOptionalSetButton(SetButton, NewSetID); ShowNewSetButton(); end end) end SetButton.SetName:ClearFocus(); PlayBling(SetButton); DataProvider:SetNumMissingSets(-1) if SetButton.hasMissingItem then DataProvider.numMissing = DataProvider.numMissing + 1; end local savedSets = GetNumEquipmentSets(); local numMissing = DataProvider:GetNumMissingSets(); Narci_NavBar:UpdateSets(savedSets, numMissing); local numVisible = savedSets + 1; if numVisible > MAX_SETS then numVisible = MAX_SETS; end ESM.numSetButton = numVisible; ESM:OnNumSetsChanged(numVisible); end local function CancelButton_OnClick(self) local SetButton = self:GetParent(); local setID = SetButton.setID; if setID and type(setID) == "number" then local name, iconFileID = GetEquipmentSetInfo(setID); SetButton.SetName:SetText(name); SetButton:SetIconWithTransition(iconFileID); SetToEditMode(SetButton, false); else SetButton.SetName:Disable(); SetButton.SetName:SetText(PAPERDOLL_NEWEQUIPMENTSET); SetButton:SetIconWithTransition(ICON_NEW_SET); ShowOrHideSettings(SetButton, false, true); end HideIconSelector(); end local function DeleteTimer_OnPlay(self) local SetButton = self:GetParent():GetParent():GetParent(); local setID = SetButton.setID; if not (setID and type(setID) == "number") then SetButton.CancelButton:Click(); end ShouldUpdateEquipment = false; end local function DeleteTimer_OnFinished(self) local SetButton = self:GetParent():GetParent():GetParent(); Narci_EquipmentSetManagerFrame.ArtFrame.Shadow:SetAlpha(0); local setID = SetButton.setID; if setID and type(setID) == "number" then self:GetParent().FadeOut:Play(); SetButton.EraseFrame:Show(); C_EquipmentSet.DeleteEquipmentSet(setID); WipeSetInfo(setID); local savedSets = GetNumEquipmentSets() or 0; HideIconSelector(); if not SetButton.hasMissingItem then DataProvider:SetNumMissingSets(-1); end local numMissing = DataProvider:GetNumMissingSets(); Narci_NavBar:UpdateSets(savedSets, numMissing); end end local function SetIcon_OnPostClick(self) self:GetParent():Click("RightButton"); end local function RepositionButton(deletedButton) --After deleting a set, replace it with the button beneath it then move it to the bottom of the list local buttons = ESM.buttons; local ID = deletedButton:GetID(); --Re-index for i = ID, (MAX_SETS - 1) do buttons[i] = buttons[i + 1]; end buttons[MAX_SETS] = deletedButton; --Reposition local button = buttons[ID]; deletedButton:ClearAllPoints(); button:ClearAllPoints(); deletedButton:SetPoint("TOP", buttons[MAX_SETS - 1], "BOTTOM", 0, 0); if ID == 1 then button:SetPoint("TOP", deletedButton:GetParent(), "TOP", 0, 0); else button:SetPoint("TOP", buttons[ID - 1], "BOTTOM", 0, 0); end end local function NarciEquipmentSetButton_EraseFrame_OnUpdate(self, elapsed) local t = self.t; local height = inOutSine(t, SETBUTTON_HEIGHT, 0.001 - SETBUTTON_HEIGHT , 0.4); if t >= 0.4 then height = 0.001; self:Hide(); local SetButton = self:GetParent(); ShowOrHideSettings(SetButton, false, true); RepositionButton(SetButton); After(0.2, InitializeEquipmentSetManager); end self:GetParent():SetHeight(height); self.t = self.t + elapsed; end function NarciEquipmentSetButtonMixin:OnLoad() self.texs = {}; self.statsTable = {}; self.statsTable.crit = 0; self.statsTable.haste = 0; self.statsTable.mastery = 0; self.statsTable.versatility = 0; self.setID = nil; --Create Talent Icon local texFrame = CreateFrame("Frame", nil, self); self.SetName:SetFrameLevel(texFrame:GetFrameLevel() + 1) texFrame:SetAlpha(0.4); local offset = 4; local tex; for i = 1, MAX_TALENT_TIERS do tex = texFrame:CreateTexture(nil,"OVERLAY", "NarciEquipmentSetTalentTexture", 1); if i == 1 then tex:SetPoint("RIGHT", self.TalentAnchor, "RIGHT", -6 - 8, 0); else tex:SetPoint("RIGHT", self.texs[i-1], "LEFT", -offset, 0); end tinsert(self.texs, tex); end self.texFrame = texFrame; self.BarColors = {0.25, 0.25, 0.25}; self:RegisterForClicks("LeftButtonUp", "RightButtonUp"); self:RegisterForDrag("LeftButton"); self.AnimFrame:SetScript("OnShow", NarciEquipmentSetButton_AnimFrame_OnShow); self.AnimFrame:SetScript("OnUpdate", NarciEquipmentSetButton_AnimFrame_OnUpdate); self.EraseFrame:SetScript("OnUpdate", NarciEquipmentSetButton_EraseFrame_OnUpdate); self.Color = self.SetName.RightEndColor; --Lays above talent icons self.ConfirmButton:SetScript("OnClick", ConfirmButton_OnClick); self.CancelButton:SetScript("OnClick", CancelButton_OnClick); self.DeleteButton.Fill.Timer:SetScript("OnPlay", DeleteTimer_OnPlay); self.DeleteButton.Fill.Timer:SetScript("OnFinished", DeleteTimer_OnFinished); self.SetIcon:SetScript("PostClick", SetIcon_OnPostClick); self.Highlight:SetAlpha(0); self:SetScript("OnLoad", nil); self.OnLoad = nil; end function NarciEquipmentSetButtonMixin:SetIconWithTransition(iconFileID, iconName) self.iconID = iconFileID; self.iconName = iconName; local SetIcon = self.SetIcon; SetIcon:StopAnimating(); SetIcon.IconTemp:SetTexture(iconFileID); SetIcon.IconTemp:SetAlpha(1); SetIcon.Icon.Transition:Play(); end function NarciEquipmentSetButtonMixin:Reset() local height, offset; if self.setID and type(self.setID) == "number" then height = SETBUTTON_HEIGHT / 2; offset = 0; else height = SETBUTTON_HEIGHT; offset = 140; ResetBackgroundColor(self); --Remove talent icons local texs = self.texs; for i = 1, MAX_TALENT_TIERS do texs[i]:SetTexture(nil); texs[i]:Hide(); end end self.numLost = 0; self.SetName:Disable(); self.Bar1:SetHeight(height); self.TalentAnchor:SetPoint("RIGHT", self.Bar1, "TOPRIGHT", offset, -12); ShowOrHideSettings(self, false, false); end function NarciEquipmentSetButtonMixin:OnEnter() if self.SetName:HasFocus() then return; end; FadeFrame(self.Highlight, 0.5, 0.15); FadeInTalentIcons(self, true); --Stats Preview if self.setID then local c, h, m, v = self.statsTable.crit, self.statsTable.haste, self.statsTable.mastery, self.statsTable.versatility; Narci_RadarChartFrame:AnimateValue(c, h, m, v); SetEnhancements(c, h, m, v); end HighlightRelevantSlots(self.statsTable.IncludedSlots); --All set buttons share the same shadow local shadow = EquipmentSetManagerFrame.ArtFrame.Shadow; local _, anchorTo = shadow:GetPoint(); if not anchorTo or anchorTo ~= self then shadow:ClearAllPoints(); shadow:SetPoint("CENTER", self, "CENTER", 0 , 0); FadeFrame(shadow, 0.25, 0.6, 0); end --Show Tooltip --NarciTooltip:NewText("Double-click to activate\nRight-click to modify"); end function NarciEquipmentSetButtonMixin:OnLeave() if self:IsMouseOver() and EquipmentSetManagerFrame:IsMouseOver() then return end FadeFrame(self.Highlight, 1, 0); FadeInTalentIcons(self, false); HighlightRelevantSlots(); EquipmentSetManagerFrame.ArtFrame.Shadow:SetAlpha(0); end function NarciEquipmentSetButtonMixin:OnClick(button) if not self.setID or self.setID == nil then CreateNewSet(self); return end if button == "RightButton" then SetToEditMode(self, true, true); self.iconName = L["Old Icon"]; ShowIconSelector(self); end end function NarciEquipmentSetButtonMixin:OnDoubleClick(button) if not self.setID or InCombatLockdown() or type(self.setID) ~= "number" or button ~="LeftButton" then return; end; self:RegisterEvent("EQUIPMENT_SWAP_FINISHED"); Narci_AlertFrame_Autohide:SetAnchor(self); C_EquipmentSet.UseEquipmentSet(self.setID); ShouldUpdateEquipment = true; UpdateEquipmentNum = self:GetID(); end function NarciEquipmentSetButtonMixin:OnDragStart() if not self.setID or type(self.setID) ~= "number" then return; end; C_EquipmentSet.PickupEquipmentSet(self.setID); end function NarciEquipmentSetButtonMixin:OnEvent(event,...) if event == "UI_ERROR_MESSAGE" then local _, msg = ... Narci_AlertFrame_Autohide:AddMessage(msg); elseif event == "EQUIPMENT_SWAP_FINISHED" then local result, setID = ...; self:UnregisterEvent("EQUIPMENT_SWAP_FINISHED"); if result then HighlightRelevantSlots(); After(0.2, InitializeEquipmentSetManager); ResetAllBackgroundColor(); PlayHighlight(self); AnimateBackgroundColor(self); --Succeed else FadeFrame(self.RedOverlay, 0.1, 1); After(0.5, function() FadeFrame(self.RedOverlay, 0.45, 0); end) self.animError:Play(); --Failed to change set end end end local function CreateEquipmentSetButtons(self) local ScrollChild = self.ScrollChild; local button; local buttons = {}; for i = 1 , MAX_SETS do button = CreateFrame("Button", nil, ScrollChild, "NarciEquipmentSetButtonTemplate"); --"NarciEquipmentSetButton"..i if i == 1 then button:SetPoint("TOP", ScrollChild, "TOP", 0, 0); else button:SetPoint("TOP", buttons[i - 1], "BOTTOM", 0, 0); end tinsert(buttons, button); end ESM.buttons = buttons; end local function UpdateInnerShadowStates(self) local currValue = self:GetValue(); local minVal, maxVal = self:GetMinMaxValues(); if ( currValue >= maxVal -20) then self.BottomShadow:Hide(); else self.BottomShadow:Show(); end if ( currValue <= minVal +20) then self.TopShadow:Hide(); else self.TopShadow:Show(); end end function Narci_EquipmentSetManager_ScrollFrame_OnLoad(self) local buttonHeight = SETBUTTON_HEIGHT; local TotalTab = MAX_SETS - 4; local TotalHeight = math.floor(TotalTab * buttonHeight + 0.5); local MaxScroll = math.floor((TotalTab - 0.5) * buttonHeight + 0.5); self.scrollBar:SetMinMaxValues(0, MaxScroll) self.scrollBar:SetValueStep(0.001); self.buttonHeight = TotalHeight; self.range = MaxScroll; self.scrollBar:SetScript("OnValueChanged", function(bar, value) self:SetVerticalScroll(value); UpdateInnerShadowStates(bar); end) CreateEquipmentSetButtons(self); NarciAPI_SmoothScroll_Initialization(self, nil, nil, 2/(TotalTab), 0.14, 0.4); end NarciViewUtil.showSetsCallBack = function() --NarciViewUtil is declared in NarciAPI.lua InitializeEquipmentSetManager(); ShouldUpdateEquipment = false; ESM.isOpen = true; UpdateScrollRange(); local Overlay1 = EquipmentSetManagerFrame.ListScrollFrame.OverlayFrame1; local SaveItemButton = Overlay1.SaveItem; local SaveTalentButton = Overlay1.SaveTalent; local r, g, b = NarciThemeUtil:GetColor(); SaveItemButton.r, SaveItemButton.g, SaveItemButton.b = r, g, b; SaveTalentButton.r, SaveTalentButton.g, SaveTalentButton.b = r, g, b; end NarciViewUtil.hideSetsCallBack = function() ESM.isOpen = false; HideIconSelector(); end ------------------------------------------------------------------- local EL = CreateFrame("Frame"); EL:RegisterEvent("PLAYER_ENTERING_WORLD"); --[[ EL:RegisterEvent("EQUIPMENT_SETS_CHANGED"); EL:RegisterEvent("EQUIPMENT_SWAP_FINISHED"); EL:RegisterEvent("EQUIPMENT_SWAP_PENDING"); EL:RegisterEvent("TRANSMOG_OUTFITS_CHANGED"); EL:RegisterEvent("WEAR_EQUIPMENT_SET"); --]] EL:SetScript("OnEvent", function(self, event, ...) if event == "PLAYER_ENTERING_WORLD" then self:UnregisterEvent("PLAYER_ENTERING_WORLD"); After(1, function() NarcissusDB_PC = NarcissusDB_PC or {}; EquipmentSetDB = NarcissusDB_PC.EquipmentSetDB; EquipmentSetManagerFrame = Narci_EquipmentSetManagerFrame; InitializeScripts(); end); end --[[ print(PREFIX_YELLOW .. event .. "|r"); if event == "EQUIPMENT_SWAP_FINISHED" then local result, setID = ...; if not setID then return; end; print("Set #"..setID.." "..tostring(result)); elseif event == "WEAR_EQUIPMENT_SET" then local setID = ...; print("Wearing Set #"..setID); elseif event == "EQUIPMENT_SETS_CHANGED" then local a = ...; print(a); end --]] end)