-- if not C_Covenants or GetExpansionLevel() ~= 8 then -- Skip for pre-Shadowlands -- return -- end BTWLOADOUTS_SOULBINDS_ACTIVE = GetExpansionLevel() == 8 local ADDON_NAME,Internal = ... local L = Internal.L local GetActiveCovenantID = C_Covenants.GetActiveCovenantID local GetCovenantIDs = C_Covenants.GetCovenantIDs local GetCovenantData = C_Covenants.GetCovenantData local ActivateSoulbind = C_Soulbinds.ActivateSoulbind local GetActiveSoulbindID = C_Soulbinds.GetActiveSoulbindID local GetSoulbindData = C_Soulbinds.GetSoulbindData local GetSoulbindNode = C_Soulbinds.GetNode local SelectSoulbindNode = C_Soulbinds.SelectNode local HelpTipBox_Anchor = Internal.HelpTipBox_Anchor; local HelpTipBox_SetText = Internal.HelpTipBox_SetText; local function CompareSets(a, b) if a.soulbindID ~= b.soulbindID then return false end if not tCompare(a.nodes, b.nodes, 10) then return false end if type(a.restrictions) ~= type(b.restrictions) and not tCompare(a.restrictions, b.restrictions, 10) then return false end return true end --[[ SOULBIND DROPDOWN ]] local function SoulbindDropDown_OnClick(self, arg1, arg2, checked) local tab = BtWLoadoutsFrame.Soulbinds; CloseDropDownMenus(); local set = tab.set; local temp = tab.temp; local soulbindID = set.soulbindID; if temp[soulbindID] then wipe(temp[soulbindID]); else temp[soulbindID] = {}; end for nodeID in pairs(set.nodes) do temp[soulbindID][nodeID] = true; end -- Clear the current talents and copy back the previously selected talents if they exist soulbindID = arg1; set.soulbindID = soulbindID; wipe(set.nodes); if temp[soulbindID] then for nodeID in pairs(temp[soulbindID]) do set.nodes[nodeID] = true; end end BtWLoadoutsFrame:Update(); end local function SoulbindDropDownInit(self, level, menuList) local info = UIDropDownMenu_CreateInfo(); local set = self:GetParent().set; local selected = set and set.soulbindID; if (level or 1) == 1 then if self.includeNone then info.text = L["None"]; info.func = SoulbindDropDown_OnClick; info.checked = selected == nil; UIDropDownMenu_AddButton(info, level); end for _,covenantID in ipairs(GetCovenantIDs()) do local covenantData = GetCovenantData(covenantID) info.text = covenantData.name; info.hasArrow, info.menuList = true, covenantData.ID; info.keepShownOnClick = true; info.notCheckable = true; UIDropDownMenu_AddButton(info, level); end else local covenantData = GetCovenantData(menuList) for _,soulbindID in ipairs(covenantData.soulbindIDs) do local soulbindData = GetSoulbindData(soulbindID) info.text = soulbindData.name; info.arg1 = soulbindData.ID; info.func = SoulbindDropDown_OnClick; info.checked = selected == soulbindData.ID; UIDropDownMenu_AddButton(info, level); end end end BtWLoadoutsSoulbindDropDownMixin = {} function BtWLoadoutsSoulbindDropDownMixin:OnShow() if not self.initialized then UIDropDownMenu_Initialize(self, SoulbindDropDownInit); self.initialized = true end end --[[ SET HANDLING ]] local function UpdateSetFilters(set) set.filters = set.filters or {} local filters = set.filters wipe(filters) Internal.UpdateRestrictionFilters(set) filters.soulbind = set.soulbindID local soulbindData = GetSoulbindData(set.soulbindID) filters.covenant = soulbindData.covenantID set.filters = filters return set end local function RefreshSet(set) local nodes = set.nodes or {} wipe(nodes) local soulbindData = GetSoulbindData(set.soulbindID) for _,node in ipairs(soulbindData.tree.nodes) do if node.state == Enum.SoulbindNodeState.Selected then nodes[node.ID] = true end end set.nodes = nodes return UpdateSetFilters(set) end local function AddSet() local soulbindID = GetActiveSoulbindID() if soulbindID == 0 then soulbindID = 7 -- Default to pelagos because why not end local soulbindData = GetSoulbindData(soulbindID) return Internal.AddSet("soulbinds", RefreshSet({ soulbindID = soulbindID, name = format(L["New %s Set"], soulbindData.name), useCount = 0, nodes = {}, })) end local function DeleteSet(id) Internal.DeleteSet(BtWLoadoutsSets.soulbinds, id); if type(id) == "table" then id = id.setID; end for _,set in pairs(BtWLoadoutsSets.profiles) do if type(set) == "table" then for index,setID in ipairs(set.soulbinds) do if setID == id then table.remove(set.soulbinds, index) end end end end local frame = BtWLoadoutsFrame.Soulbinds; local set = frame.set; if set.setID == id then frame.set = nil BtWLoadoutsFrame:Update(); end end local function GetSet(id) if type(id) == "table" then return id; elseif id < 0 then -- Fake a soulbind set local set = GetSoulbindData(math.abs(id)) set.soulbindID = set.ID set.setID = -set.ID set.ID = nil return set else return BtWLoadoutsSets.soulbinds[id] end end local function GetSets(id, ...) if id ~= nil then return GetSet(id), GetSets(...); end end local function IsSetActive(set) if set.soulbindID then local covenantID = GetActiveCovenantID() if covenantID then local soulbindID = GetActiveSoulbindID() local soulbindData = GetSoulbindData(set.soulbindID) -- The target soulbind is unlocked, is for the players covenant, so is valid for the character if soulbindData.unlocked and soulbindData.covenantID == covenantID then if set.soulbindID == soulbindID then if set.nodes then for nodeID in pairs(set.nodes) do local node = GetSoulbindNode(nodeID) if node.state ~= Enum.SoulbindNodeState.Selected and node.state ~= Enum.SoulbindNodeState.Unavailable then return false end end return true else return true end else return false end end end end return true; end local function CombineSets(result, state, ...) result = result or {}; local covenantID = GetActiveCovenantID() if covenantID then for i=1,select('#', ...) do local set = select(i, ...); local soulbindData = GetSoulbindData(set.soulbindID) if soulbindData.covenantID == covenantID and soulbindData.unlocked and Internal.AreRestrictionsValidForPlayer(set.restrictions) then result.soulbindID = set.soulbindID result.nodes = set.nodes end end local soulbindID = GetActiveSoulbindID() if state and not IsSetActive(result) then state.noCombatSwap = true state.noTaxiSwap = true -- Maybe check for rested area or tomb first? state.blockedByJailersChains = true if not C_Soulbinds.CanModifySoulbind() then state.needTome = true end end end return result; end local function ActivateSet(set, state) local complete = true; if (not state or ((not state.ignoreTome or C_Soulbinds.CanModifySoulbind()) and not state.ignoreJailersChains)) and not IsSetActive(set) then local soulbindData = GetSoulbindData(set.soulbindID) Internal.LogMessage("Switching soulbind to %s", soulbindData.name) ActivateSoulbind(set.soulbindID) if set.nodes then for nodeID in pairs(set.nodes) do local node = GetSoulbindNode(nodeID) if node.state ~= Enum.SoulbindNodeState.Selected and node.state ~= Enum.SoulbindNodeState.Unavailable then SelectSoulbindNode(nodeID) end end end complete = false end return complete end local function CheckErrors(errorState, set) set = GetSet(set) if not Internal.AreRestrictionsValidFor(set.restrictions, errorState.specID) then return L["Incompatible Restrictions"] end end local genericSoulbindSets = {} for _,covenantID in ipairs(GetCovenantIDs()) do local covenantData = GetCovenantData(covenantID) for index,soulbindID in ipairs(covenantData.soulbindIDs) do local soulbindData = GetSoulbindData(soulbindID) genericSoulbindSets[#genericSoulbindSets+1] = UpdateSetFilters({ setID = -soulbindData.ID, name = soulbindData.name, soulbindID = soulbindData.ID, covenantID = covenantID, order = -20 + (index * 4 + covenantID), }) end end -- Initializes the set dropdown menu for the Loadouts page local function SetDropDownInit(self, set, index) local temp = {} for _,set in pairs(genericSoulbindSets) do temp[set.setID] = set end for _,set in pairs(BtWLoadoutsSets.soulbinds) do if type(set) == "table" then temp[set.setID] = set end end self:SetSelected(index and set.soulbinds[index] or nil) self:SetSets(temp) self:SetFilters(BtWLoadoutsFilters.soulbinds) self:SetCategories(BtWLoadoutsCategories.soulbinds) self:SetIncludeNone(index ~= nil) self:OnItemClick(function (self, setID) local index = index or (#set.soulbinds + 1) if set.soulbinds[index] then local subset = GetSet(set.soulbinds[index]); subset.useCount = (subset.useCount or 1) - 1; end if setID == "none" then table.remove(set.soulbinds, index); elseif setID == "new" then local subset = AddSet(); set.soulbinds[index] = subset.setID; BtWLoadoutsFrame.Soulbinds.set = subset; PanelTemplates_SetTab(BtWLoadoutsFrame, BtWLoadoutsFrame.Soulbinds:GetID()); BtWLoadoutsHelpTipFlags["TUTORIAL_CREATE_TALENT_SET"] = true; else -- Change to a specific set set.soulbinds[index] = setID; end if set.soulbinds[index] then local subset = GetSet(set.soulbinds[index]); subset.useCount = (subset.useCount or 0) + 1; end self:SetSelected(set.soulbinds[index]) CloseDropDownMenus() BtWLoadoutsFrame:Update(); end) end Internal.AddLoadoutSegment({ id = "soulbinds", name = L["Soulbinds"], events = "SOULBIND_ACTIVATED", enabled = BTWLOADOUTS_SOULBINDS_ACTIVE, add = AddSet, get = GetSets, combine = CombineSets, isActive = IsSetActive, activate = ActivateSet, dropdowninit = SetDropDownInit, checkerrors = CheckErrors, export = function (set) return { version = 1, name = set.name, soulbindID = set.soulbindID, nodes = set.nodes, restrictions = set.restrictions, } end, import = function (source, version, name, ...) assert(version == 1) local soulbindID = source.soulbindID or ... return Internal.AddSet("soulbinds", UpdateSetFilters({ soulbindID = soulbindID, name = name or source.name, useCount = 0, nodes = source.nodes, restrictions = source.restrictions, })) end, getByValue = function (set) -- If the nodes is missing then we just want the faux set if set.nodes == nil then return GetSet(-set.soulbindID) else return Internal.GetSetByValue(BtWLoadoutsSets.soulbinds, set, CompareSets) end end, verify = function (source, ...) local soulbindID = source.soulbindID or ... if not soulbindID or not GetSoulbindData(soulbindID) then return false, L["Invalid soulbind"] end if source.nodes ~= nil and type(source.nodes) ~= "table" then return false, L["Invalid nodes"] end if source.restrictions ~= nil and type(source.restrictions) ~= "table" then return false, L["Missing restrictions"] end -- @TODO verify talent ids? return true end, }) -- [[ TAB UI ]] local function GetConduitEmblemAtlas(conduitType) if conduitType == Enum.SoulbindConduitType.Potency then return "Soulbinds_Tree_Conduit_Icon_Attack"; elseif conduitType == Enum.SoulbindConduitType.Endurance then return "Soulbinds_Tree_Conduit_Icon_Protect"; elseif conduitType == Enum.SoulbindConduitType.Finesse then return "Soulbinds_Tree_Conduit_Icon_Utility"; end end BtWLoadoutsSoulbindNodeMixin = {} function BtWLoadoutsSoulbindNodeMixin:SetNode(node) self.node = node self.Icon:SetTexture(node.icon) if node.conduitType ~= nil then local atlas = GetConduitEmblemAtlas(node.conduitType); self.Emblem:Show() self.EmblemBg:Show() self.Emblem:SetAtlas(atlas); self.EmblemBg:SetAtlas(atlas) self.EmblemBg:SetVertexColor(0, 0, 0); self.Icon:Hide(); self.Ring:SetAtlas("Soulbinds_Tree_Conduit_Ring", false); self.MouseOverlay:SetAtlas("Soulbinds_Tree_Conduit_Ring", false); else self.Emblem:Hide() self.EmblemBg:Hide() self.Icon:Show(); self.Ring:SetAtlas("Soulbinds_Tree_Ring", false); self.MouseOverlay:SetAtlas("Soulbinds_Tree_Ring", false); end end function BtWLoadoutsSoulbindNodeMixin:SetSelected(selected) if not selected then self.Icon:SetDesaturated(false); self.IconOverlay:Show(); self.Ring:SetDesaturated(true); self.MouseOverlay:SetDesaturated(true); else self.Icon:SetDesaturated(false); self.IconOverlay:Hide(); self.Ring:SetDesaturated(false); self.MouseOverlay:SetDesaturated(false); end end function BtWLoadoutsSoulbindNodeMixin:OnClick() local container = self:GetParent():GetParent():GetParent() local node = self.node local nodes = container.set.nodes local selected = not nodes[node.ID] while node.childNodeIDs and #node.childNodeIDs == 1 do local childID = node.childNodeIDs[1] if #container.nodesByID[childID].node.parentNodeIDs ~= 1 then break end node = container.nodesByID[childID].node end for _,frame in pairs(container.nodesByID) do if frame.node.row == node.row then nodes[frame.node.ID] = nil end end nodes[node.ID] = selected and true or nil while #node.parentNodeIDs == 1 do local parentID = node.parentNodeIDs[1] node = container.nodesByID[parentID].node if not node.childNodeIDs or #node.childNodeIDs ~= 1 then break end for _,frame in pairs(container.nodesByID) do if frame.node.row == node.row then nodes[frame.node.ID] = nil end end nodes[node.ID] = selected and true or nil end container:Update() end function BtWLoadoutsSoulbindNodeMixin:OnEnter() self.MouseOverlay:Show(); end function BtWLoadoutsSoulbindNodeMixin:OnLeave() self.MouseOverlay:Hide(); end local SoulbindTreeLinkDirections = { Vertical = 1, Converge = 2, Diverge = 3, }; BtWLoadoutsSoulbindTreeNodeLinkMixin = {} function BtWLoadoutsSoulbindTreeNodeLinkMixin:Init(direction, angle) if direction == SoulbindTreeLinkDirections.Vertical then self.Background:SetAtlas("Soulbinds_Tree_Connector_Vertical", true); self.FillMask:SetAtlas("Soulbinds_Tree_Connector_Vertical_Mask", true); elseif direction == SoulbindTreeLinkDirections.Converge then self.Background:SetAtlas("Soulbinds_Tree_Connector_Diagonal_Close", true); self.FillMask:SetAtlas("Soulbinds_Tree_Connector_Diagonal_Close_Mask", true); elseif direction == SoulbindTreeLinkDirections.Diverge then self.Background:SetAtlas("Soulbinds_Tree_Connector_Diagonal_Far", true); self.FillMask:SetAtlas("Soulbinds_Tree_Connector_Diagonal_Far_Mask", true); end self:RotateTextures(angle); end function BtWLoadoutsSoulbindTreeNodeLinkMixin:OnHide() self.FlowAnim1:Stop(); self.FlowAnim2:Stop(); self.FlowAnim3:Stop(); self.FlowAnim4:Stop(); self.FlowAnim5:Stop(); self.FlowAnim6:Stop(); end function BtWLoadoutsSoulbindTreeNodeLinkMixin:Reset() self:SetState(Enum.SoulbindNodeState.Unselected); end function BtWLoadoutsSoulbindTreeNodeLinkMixin:SetState(state) self.state = state; if state == Enum.SoulbindNodeState.Unselected or state == Enum.SoulbindNodeState.Unavailable then self:DesaturateHierarchy(1); for _, foreground in ipairs(self.foregrounds) do foreground:SetShown(false); end self.FlowAnim1:Stop(); self.FlowAnim2:Stop(); self.FlowAnim3:Stop(); self.FlowAnim4:Stop(); self.FlowAnim5:Stop(); self.FlowAnim6:Stop(); elseif state == Enum.SoulbindNodeState.Selectable then self:DesaturateHierarchy(0); for _, foreground in ipairs(self.foregrounds) do foreground:SetShown(true); foreground:SetVertexColor(.3, .3, .3); end self.FlowAnim1:Play(); self.FlowAnim2:Play(); self.FlowAnim3:Play(); self.FlowAnim4:Play(); self.FlowAnim5:Play(); self.FlowAnim6:Play(); elseif state == Enum.SoulbindNodeState.Selected then self:DesaturateHierarchy(0); for _, foreground in ipairs(self.foregrounds) do foreground:SetShown(true); foreground:SetVertexColor(.192, .686, .941); end self.FlowAnim1:Play(); self.FlowAnim2:Play(); self.FlowAnim3:Play(); self.FlowAnim4:Play(); self.FlowAnim5:Play(); self.FlowAnim6:Play(); end end function BtWLoadoutsSoulbindTreeNodeLinkMixin:GetState() return self.state; end BtWLoadoutsSoulbindsMixin = {} function BtWLoadoutsSoulbindsMixin:OnLoad() self.RestrictionsDropDown:SetSupportedTypes("spec", "race") self.RestrictionsDropDown:SetScript("OnChange", function () self:Update() end) self.temp = {} self.nodes = CreateFramePool("BUTTON", self.Scroll:GetScrollChild(), "BtWLoadoutsSoulbindNodeTemplate"); self.links = CreateFramePool("FRAME", self.Scroll, "BtWLoadoutsSoulbindTreeNodeLinkTemplate"); self.nodesByID = {} end function BtWLoadoutsSoulbindsMixin:OnShow() if not self.initialized then UIDropDownMenu_SetWidth(self.SoulbindDropDown, 170); UIDropDownMenu_JustifyText(self.SoulbindDropDown, "LEFT"); self.initialized = true; end end function BtWLoadoutsSoulbindsMixin:ChangeSet(set) self.set = set self:Update() end function BtWLoadoutsSoulbindsMixin:UpdateSetName(value) if self.set and self.set.name ~= not value then self.set.name = value; self:Update(); end end function BtWLoadoutsSoulbindsMixin:OnButtonClick(button) CloseDropDownMenus() if button.isAdd then BtWLoadoutsHelpTipFlags["TUTORIAL_NEW_SET"] = true; self.Name:ClearFocus() self:ChangeSet(AddSet()) C_Timer.After(0, function () self.Name:HighlightText() self.Name:SetFocus() end) elseif button.isDelete then local set = self.set if set.useCount > 0 then StaticPopup_Show("BTWLOADOUTS_DELETEINUSESET", set.name, nil, { set = set, func = DeleteSet, }) else StaticPopup_Show("BTWLOADOUTS_DELETESET", set.name, nil, { set = set, func = DeleteSet, }) end elseif button.isRefresh then local set = self.set; RefreshSet(set) self:Update() elseif button.isExport then local set = self.set; self:GetParent():SetExport(Internal.Export("soulbinds", set.setID)) elseif button.isActivate then local set = self.set; Internal.ActivateProfile({ soulbinds = {set.setID} }); end end function BtWLoadoutsSoulbindsMixin:OnSidebarItemClick(button) CloseDropDownMenus() if button.isHeader then button.collapsed[button.id] = not button.collapsed[button.id] self:Update() else if IsModifiedClick("SHIFT") then local set = GetSet(button.id); Internal.ActivateProfile({ soulbinds = {button.id} }); else self.Name:ClearFocus(); self:ChangeSet(GetSet(button.id)) end end end function BtWLoadoutsSoulbindsMixin:OnSidebarItemDoubleClick(button) CloseDropDownMenus() if button.isHeader then return end local set = GetSet(button.id); Internal.ActivateProfile({ soulbinds = {button.id} }); end function BtWLoadoutsSoulbindsMixin:OnSidebarItemDragStart(button) CloseDropDownMenus() if button.isHeader then return end local icon = "INV_Misc_QuestionMark"; local set = GetSet(button.id); local command = format("/btwloadouts activate soulbinds %d", button.id); if set.specID then icon = select(4, GetSpecializationInfoByID(set.specID)); end if command then local macroId; local numMacros = GetNumMacros(); for i=1,numMacros do if GetMacroBody(i):trim() == command then macroId = i; break; end end if not macroId then if numMacros == MAX_ACCOUNT_MACROS then print(L["Cannot create any more macros"]); return; end if InCombatLockdown() then print(L["Cannot create macros while in combat"]); return; end macroId = CreateMacro(set.name, icon, command, false); else -- Rename the macro while not in combat if not InCombatLockdown() then icon = select(2,GetMacroInfo(macroId)) EditMacro(macroId, set.name, icon, command) end end if macroId then PickupMacro(macroId); end end end function BtWLoadoutsSoulbindsMixin:Update() self:GetParent().TitleText:SetText(L["Soulbinds"]); local sidebar = BtWLoadoutsFrame.Sidebar sidebar:SetSupportedFilters("covenant", "spec", "class", "role", "race") sidebar:SetSets(BtWLoadoutsSets.soulbinds) sidebar:SetCollapsed(BtWLoadoutsCollapsed.soulbinds) sidebar:SetCategories(BtWLoadoutsCategories.soulbinds) sidebar:SetFilters(BtWLoadoutsFilters.soulbinds) sidebar:SetSelected(self.set) sidebar:Update() self.set = sidebar:GetSelected() local set = self.set local showingNPE = BtWLoadoutsFrame:SetNPEShown(set == nil, L["Soulbinds"], L["Create soulbind trees for switching between soulbind paths, leave rows blank to not skip them. Conduits are not affected."]) self:GetParent().ExportButton:SetEnabled(true) self:GetParent().DeleteButton:SetEnabled(true); if not showingNPE then local soulbindID = set.soulbindID; local soulbindData = GetSoulbindData(soulbindID) UpdateSetFilters(set) sidebar:Update() set.restrictions = set.restrictions or {} self.RestrictionsDropDown:SetSelections(set.restrictions) self.RestrictionsDropDown:SetLimitations() self.RestrictionsButton:SetEnabled(true); if not self.Name:HasFocus() then self.Name:SetText(set.name or ""); end UIDropDownMenu_SetSelectedValue(self.SoulbindDropDown, soulbindID); UIDropDownMenu_SetText(self.SoulbindDropDown, soulbindData.name); UIDropDownMenu_EnableDropDown(self.SoulbindDropDown); local selected = set.nodes; self.nodes:ReleaseAll() self.links:ReleaseAll() wipe(self.nodesByID) for _,node in ipairs(soulbindData.tree.nodes) do local nodeFrame = self.nodes:Acquire() nodeFrame:SetFrameLevel(6) nodeFrame:SetPoint("TOP", (node.column - 1) * (nodeFrame:GetWidth() + 30), -node.row * (nodeFrame:GetHeight() + 12) - 17) nodeFrame:SetNode(node) nodeFrame:SetSelected(selected[node.ID]) nodeFrame:Show() self.nodesByID[node.ID] = nodeFrame end for _, linkFromFrame in pairs(self.nodesByID) do if linkFromFrame.node.row > 0 then for _,parentID in ipairs(linkFromFrame.node.parentNodeIDs) do local linkToFrame = self.nodesByID[parentID] linkToFrame.node.childNodeIDs = linkToFrame.node.childNodeIDs or {} linkToFrame.node.childNodeIDs[#linkToFrame.node.childNodeIDs+1] = linkFromFrame.node.ID local linkFrame = self.links:Acquire() linkFrame:SetFrameLevel(2) local toColumn = linkToFrame.node.column; local fromColumn = linkFromFrame.node.column; local offset = toColumn - fromColumn; if offset < 0 then linkFrame:SetPoint("BOTTOMRIGHT", linkFromFrame, "CENTER"); linkFrame:SetPoint("TOPLEFT", linkToFrame, "CENTER"); elseif offset > 0 then linkFrame:SetPoint("BOTTOMLEFT", linkFromFrame, "CENTER"); linkFrame:SetPoint("TOPRIGHT", linkToFrame, "CENTER"); else linkFrame:SetPoint("BOTTOM", linkFromFrame, "CENTER"); linkFrame:SetPoint("TOP", linkToFrame, "CENTER"); end local direction; local diagonal = toColumn ~= fromColumn; if diagonal then direction = SoulbindTreeLinkDirections.Converge else direction = SoulbindTreeLinkDirections.Vertical; end local quarter = (math.pi * 0.5); local angle = RegionUtil.CalculateAngleBetween(linkToFrame, linkFromFrame) - quarter; linkFrame:Init(direction, angle); linkFrame:SetState((selected[linkToFrame.node.ID] and selected[linkFromFrame.node.ID]) and Enum.SoulbindNodeState.Selected or Enum.SoulbindNodeState.Unselected); linkFrame:Show(); end end end local playerCovenantID = GetActiveCovenantID() local playerSoulbindID = GetActiveSoulbindID() self:GetParent().RefreshButton:SetEnabled(soulbindID == playerSoulbindID) self:GetParent().ActivateButton:SetEnabled(soulbindData.covenantID == playerCovenantID and soulbindData.unlocked); local helpTipBox = self:GetParent().HelpTipBox; helpTipBox:Hide(); else local soulbindID = GetActiveSoulbindID() if soulbindID == 0 then soulbindID = 7 -- Default to pelagos because why not end local soulbindData = GetSoulbindData(soulbindID) self.Name:SetText(format(L["New %s Set"], soulbindData.name)); self.nodes:ReleaseAll() self.links:ReleaseAll() for _,node in ipairs(soulbindData.tree.nodes) do local nodeFrame = self.nodes:Acquire() nodeFrame:SetFrameLevel(6) nodeFrame:SetPoint("TOP", self.Inset, "TOP", (node.column - 1) * (nodeFrame:GetWidth() + 30), -node.row * (nodeFrame:GetHeight() + 12) - 17) nodeFrame:SetNode(node) nodeFrame:SetSelected(false) nodeFrame:Show() self.nodesByID[node.ID] = nodeFrame end local helpTipBox = self:GetParent().HelpTipBox; helpTipBox:Hide(); end end function BtWLoadoutsSoulbindsMixin:SetSetByID(setID) self.set = GetSet(setID) end