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.
3565 lines
102 KiB
3565 lines
102 KiB
local ADDON_NAME,Internal = ...
|
|
local L = Internal.L
|
|
|
|
local GetActiveCovenantID = C_Covenants.GetActiveCovenantID
|
|
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 ]]
|
|
|
|
BtWLoadoutsSoulbindDropDownMixin = {}
|
|
function BtWLoadoutsSoulbindDropDownMixin:OnShow()
|
|
if not self.initialized then
|
|
UIDropDownMenu_Initialize(self, self.Init);
|
|
self.initialized = true
|
|
end
|
|
end
|
|
function BtWLoadoutsSoulbindDropDownMixin:Init(level, menuList)
|
|
local info = UIDropDownMenu_CreateInfo();
|
|
local selected = self:GetValue();
|
|
|
|
info.func = function (button, arg1, arg2, checked)
|
|
self:SetValue(button, arg1, arg2, checked)
|
|
end
|
|
if (level or 1) == 1 then
|
|
if self.includeNone then
|
|
info.text = L["None"];
|
|
info.checked = selected == nil;
|
|
UIDropDownMenu_AddButton(info, level);
|
|
end
|
|
|
|
for covenantID = 1,4 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.checked = selected == soulbindData.ID;
|
|
UIDropDownMenu_AddButton(info, level);
|
|
end
|
|
end
|
|
end
|
|
function BtWLoadoutsSoulbindDropDownMixin:GetValue()
|
|
end
|
|
function BtWLoadoutsSoulbindDropDownMixin:SetValue(button, classIndex, classFile, checked)
|
|
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 {}
|
|
local conduits = set.conduits or {}
|
|
|
|
wipe(nodes)
|
|
wipe(conduits)
|
|
|
|
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
|
|
local conduitID = C_Soulbinds.GetInstalledConduitID(node.ID)
|
|
if conduitID ~= 0 then
|
|
conduits[node.ID] = conduitID
|
|
end
|
|
end
|
|
|
|
set.nodes = nodes
|
|
set.conduits = conduits
|
|
set.classID = select(3, UnitClass("player"))
|
|
|
|
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
|
|
-- In General, For Player, For Player Spec
|
|
local function SetIsValid(set)
|
|
set = GetSet(set);
|
|
|
|
local soulbindData = GetSoulbindData(set.soulbindID)
|
|
local playerCovenantID = GetActiveCovenantID()
|
|
|
|
return true, (soulbindData.covenantID ==playerCovenantID )
|
|
end
|
|
local function GetByName(name)
|
|
return Internal.GetSetByName("soulbinds", name, SetIsValid)
|
|
end
|
|
local function IsSetActive(set, ignoreConduits)
|
|
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
|
|
return false
|
|
end
|
|
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
|
|
if set.conduits and not ignoreConduits then
|
|
for nodeID,conduitID in pairs(set.conduits) do
|
|
local node = GetSoulbindNode(nodeID)
|
|
if C_Soulbinds.GetInstalledConduitID(nodeID) ~= conduitID and node.state ~= Enum.SoulbindNodeState.Unavailable then
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return true;
|
|
end
|
|
local function IsSetConduitsActive(set)
|
|
if set.conduits and next(set.conduits) then
|
|
for nodeID,conduitID in pairs(set.conduits) do
|
|
local node = GetSoulbindNode(nodeID)
|
|
if node and node.state ~= Enum.SoulbindNodeState.Unavailable and C_Soulbinds.GetInstalledConduitID(nodeID) ~= conduitID then
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
|
|
return true;
|
|
end
|
|
local function CombineSets(result, state, ...)
|
|
result = result or {};
|
|
|
|
local classID = select(3, UnitClass("player"))
|
|
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 (set.classID == nil or set.classID == classID) and Internal.AreRestrictionsValidForPlayer(set.restrictions) then
|
|
result.soulbindID = set.soulbindID
|
|
result.nodes = set.nodes
|
|
result.conduits = set.conduits
|
|
end
|
|
end
|
|
|
|
if state and state.blockers and not IsSetActive(result) then
|
|
local conduitsActive = IsSetConduitsActive(result)
|
|
if not conduitsActive then
|
|
state.blockers[Internal.GetForgeOfBondsBlocker()] = IsSetActive(result, true)
|
|
end
|
|
-- If the conduits are already set we wont need to go to a forge so we may need a tome or rested area
|
|
-- If we need to swap conduits but allowPartial has been set we may need a tome or rested area
|
|
if not C_Soulbinds.CanSwitchActiveSoulbindTreeBranch() and (conduitsActive or state.allowPartial) then
|
|
state.blockers[Internal.GetRestedTomeBlocker()] = true
|
|
end
|
|
state.blockers[Internal.GetCombatBlocker()] = true
|
|
state.blockers[Internal.GetMythicPlusBlocker()] = true
|
|
state.blockers[Internal.GetJailersChainBlocker()] = true
|
|
end
|
|
end
|
|
|
|
return result;
|
|
end
|
|
local function ActivateSet(set, state)
|
|
local complete = true;
|
|
|
|
if not IsSetActive(set) then
|
|
local soulbindData = GetSoulbindData(set.soulbindID)
|
|
if C_Soulbinds.GetActiveSoulbindID() ~= set.soulbindID then
|
|
Internal.LogMessage("Switching soulbind to %s", soulbindData.name)
|
|
ActivateSoulbind(set.soulbindID)
|
|
end
|
|
|
|
if set.nodes and C_Soulbinds.CanSwitchActiveSoulbindTreeBranch() 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
|
|
Internal.LogMessage("Switching soulbind tree node to %d", nodeID)
|
|
SelectSoulbindNode(nodeID)
|
|
complete = false
|
|
end
|
|
end
|
|
local socketedAny = false
|
|
if set.conduits and C_Soulbinds.CanModifySoulbind() then
|
|
for nodeID,conduitID in pairs(set.conduits) do
|
|
local node = GetSoulbindNode(nodeID)
|
|
if C_Soulbinds.GetInstalledConduitID(nodeID) ~= conduitID and node.state ~= Enum.SoulbindNodeState.Unavailable then
|
|
Internal.LogMessage("Socket conduit %d into node %d", conduitID, nodeID)
|
|
C_Soulbinds.ModifyNode(nodeID, conduitID, Enum.SoulbindConduitTransactionType.Install)
|
|
socketedAny = true
|
|
end
|
|
end
|
|
end
|
|
|
|
if socketedAny then
|
|
C_Soulbinds.CommitPendingConduitsInSoulbind(set.soulbindID)
|
|
complete = false
|
|
end
|
|
end
|
|
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 = 1,4 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",
|
|
add = AddSet,
|
|
get = GetSets,
|
|
getByName = 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 GetConduitName(conduitType)
|
|
if conduitType == Enum.SoulbindConduitType.Potency then
|
|
return CONDUIT_POTENCY;
|
|
elseif conduitType == Enum.SoulbindConduitType.Endurance then
|
|
return CONDUIT_ENDURANCE;
|
|
elseif conduitType == Enum.SoulbindConduitType.Finesse then
|
|
return CONDUIT_FINESSE;
|
|
end
|
|
end
|
|
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
|
|
local function GetConduitIconScale(conduitType)
|
|
if conduitType == Enum.SoulbindConduitType.Potency then
|
|
return 1.0;
|
|
elseif conduitType == Enum.SoulbindConduitType.Endurance then
|
|
return 1.0;
|
|
elseif conduitType == Enum.SoulbindConduitType.Finesse then
|
|
return 1.0;
|
|
end
|
|
end
|
|
|
|
local conduits = {
|
|
{ -- Stalwart Guardian
|
|
conduitID = 5,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 0,
|
|
conduitItemID = 180842,
|
|
},
|
|
{ -- Brutal Vitality
|
|
conduitID = 7,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 0,
|
|
conduitItemID = 180844,
|
|
},
|
|
{ -- Inspiring Presence
|
|
conduitID = 8,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 0,
|
|
conduitItemID = 180847,
|
|
},
|
|
{ -- Safeguard
|
|
conduitID = 9,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 0,
|
|
conduitItemID = 180896,
|
|
},
|
|
{ -- Fueled by Violence
|
|
conduitID = 10,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 42,
|
|
covenantID = 0,
|
|
conduitItemID = 180932,
|
|
},
|
|
{ -- Ashen Juggernaut
|
|
conduitID = 11,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 0,
|
|
conduitItemID = 180933,
|
|
},
|
|
{ -- Crash the Ramparts
|
|
conduitID = 12,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 40,
|
|
covenantID = 0,
|
|
conduitItemID = 180935,
|
|
},
|
|
{ -- Cacophonous Roar
|
|
conduitID = 13,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 0,
|
|
conduitItemID = 180943,
|
|
},
|
|
{ -- Merciless Bonegrinder
|
|
conduitID = 14,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 40,
|
|
covenantID = 0,
|
|
conduitItemID = 180944,
|
|
},
|
|
{ -- Harm Denial
|
|
conduitID = 15,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 0,
|
|
conduitItemID = 181373,
|
|
},
|
|
{ -- Inner Fury
|
|
conduitID = 16,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 26,
|
|
covenantID = 0,
|
|
conduitItemID = 181376,
|
|
},
|
|
{ -- Unrelenting Cold
|
|
conduitID = 17,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 22,
|
|
covenantID = 0,
|
|
conduitItemID = 181383,
|
|
},
|
|
{ -- Shivering Core
|
|
conduitID = 18,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 22,
|
|
covenantID = 0,
|
|
conduitItemID = 181389,
|
|
},
|
|
{ -- Calculated Strikes
|
|
conduitID = 19,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 26,
|
|
covenantID = 0,
|
|
conduitItemID = 181435,
|
|
},
|
|
{ -- Icy Propulsion
|
|
conduitID = 20,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 22,
|
|
covenantID = 0,
|
|
conduitItemID = 181455,
|
|
},
|
|
{ -- Ice Bite
|
|
conduitID = 21,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 22,
|
|
covenantID = 0,
|
|
conduitItemID = 181461,
|
|
},
|
|
{ -- Coordinated Offensive
|
|
conduitID = 22,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 26,
|
|
covenantID = 0,
|
|
conduitItemID = 181462,
|
|
},
|
|
{ -- Winter's Protection
|
|
conduitID = 23,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 0,
|
|
conduitItemID = 181464,
|
|
},
|
|
{ -- Xuen's Bond
|
|
conduitID = 24,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 26,
|
|
covenantID = 0,
|
|
conduitItemID = 181465,
|
|
},
|
|
{ -- Grounding Breath
|
|
conduitID = 25,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 0,
|
|
conduitItemID = 181466,
|
|
},
|
|
{ -- Flow of Time
|
|
conduitID = 26,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 0,
|
|
conduitItemID = 181467,
|
|
},
|
|
{ -- Indelible Victory
|
|
conduitID = 27,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 0,
|
|
conduitItemID = 181469,
|
|
},
|
|
{ -- Jade Bond
|
|
conduitID = 28,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 25,
|
|
covenantID = 0,
|
|
conduitItemID = 181495,
|
|
},
|
|
{ -- Grounding Surge
|
|
conduitID = 29,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 0,
|
|
conduitItemID = 181498,
|
|
},
|
|
{ -- Infernal Cascade
|
|
conduitID = 30,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 23,
|
|
covenantID = 0,
|
|
conduitItemID = 181504,
|
|
},
|
|
{ -- Resplendent Mist
|
|
conduitID = 31,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 25,
|
|
covenantID = 0,
|
|
conduitItemID = 181505,
|
|
},
|
|
{ -- Master Flame
|
|
conduitID = 32,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 23,
|
|
covenantID = 0,
|
|
conduitItemID = 181506,
|
|
},
|
|
{ -- Fortifying Ingredients
|
|
conduitID = 33,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 0,
|
|
conduitItemID = 181508,
|
|
},
|
|
{ -- Arcane Prodigy
|
|
conduitID = 34,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 21,
|
|
covenantID = 0,
|
|
conduitItemID = 181509,
|
|
},
|
|
{ -- Lingering Numbness
|
|
conduitID = 35,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 0,
|
|
conduitItemID = 181510,
|
|
},
|
|
{ -- Nether Precision
|
|
conduitID = 36,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 21,
|
|
covenantID = 0,
|
|
conduitItemID = 181511,
|
|
},
|
|
{ -- Dizzying Tumble
|
|
conduitID = 37,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 0,
|
|
conduitItemID = 181512,
|
|
},
|
|
{ -- Discipline of the Grove
|
|
conduitID = 38,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 3,
|
|
conduitItemID = 181539,
|
|
},
|
|
{ -- Gift of the Lich
|
|
conduitID = 39,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 4,
|
|
conduitItemID = 181553,
|
|
},
|
|
{ -- Ire of the Ascended
|
|
conduitID = 40,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 1,
|
|
conduitItemID = 181600,
|
|
},
|
|
{ -- Swift Transference
|
|
conduitID = 41,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 0,
|
|
conduitItemID = 181624,
|
|
},
|
|
{ -- Tumbling Technique
|
|
conduitID = 42,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 0,
|
|
conduitItemID = 181640,
|
|
},
|
|
{ -- Siphoned Malice
|
|
conduitID = 43,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 2,
|
|
conduitItemID = 181639,
|
|
},
|
|
{ -- Rising Sun Revival
|
|
conduitID = 44,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 25,
|
|
covenantID = 0,
|
|
conduitItemID = 181641,
|
|
},
|
|
{ -- Cryo-Freeze
|
|
conduitID = 45,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 0,
|
|
conduitItemID = 181698,
|
|
},
|
|
{ -- Scalding Brew
|
|
conduitID = 46,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 24,
|
|
covenantID = 0,
|
|
conduitItemID = 181700,
|
|
},
|
|
{ -- Celestial Effervescence
|
|
conduitID = 47,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 24,
|
|
covenantID = 0,
|
|
conduitItemID = 181705,
|
|
},
|
|
{ -- Diverted Energy
|
|
conduitID = 48,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 0,
|
|
conduitItemID = 181707,
|
|
},
|
|
{ -- Unnerving Focus
|
|
conduitID = 49,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 42,
|
|
covenantID = 0,
|
|
conduitItemID = 181709,
|
|
},
|
|
{ -- Depths of Insanity
|
|
conduitID = 50,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 41,
|
|
covenantID = 0,
|
|
conduitItemID = 181712,
|
|
},
|
|
{ -- Magi's Brand
|
|
conduitID = 51,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 21,
|
|
covenantID = 0,
|
|
conduitItemID = 181734,
|
|
},
|
|
{ -- Hack and Slash
|
|
conduitID = 52,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 41,
|
|
covenantID = 0,
|
|
conduitItemID = 181735,
|
|
},
|
|
{ -- Flame Accretion
|
|
conduitID = 53,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 23,
|
|
covenantID = 0,
|
|
conduitItemID = 181736,
|
|
},
|
|
{ -- Nourishing Chi
|
|
conduitID = 54,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 25,
|
|
covenantID = 0,
|
|
conduitItemID = 181737,
|
|
},
|
|
{ -- Artifice of the Archmage
|
|
conduitID = 55,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 21,
|
|
covenantID = 0,
|
|
conduitItemID = 181738,
|
|
},
|
|
{ -- Evasive Stride
|
|
conduitID = 56,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 24,
|
|
covenantID = 0,
|
|
conduitItemID = 181740,
|
|
},
|
|
{ -- Walk with the Ox
|
|
conduitID = 57,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 24,
|
|
covenantID = 0,
|
|
conduitItemID = 181742,
|
|
},
|
|
{ -- Incantation of Swiftness
|
|
conduitID = 58,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 0,
|
|
conduitItemID = 181756,
|
|
},
|
|
{ -- Strike with Clarity
|
|
conduitID = 59,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 1,
|
|
conduitItemID = 181759,
|
|
},
|
|
{ -- Bone Marrow Hops
|
|
conduitID = 60,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 4,
|
|
conduitItemID = 181770,
|
|
},
|
|
{ -- Tempest Barrier
|
|
conduitID = 61,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 162,
|
|
covenantID = 0,
|
|
conduitItemID = 181769,
|
|
},
|
|
{ -- Imbued Reflections
|
|
conduitID = 62,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 2,
|
|
conduitItemID = 181774,
|
|
},
|
|
{ -- Way of the Fae
|
|
conduitID = 63,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 164,
|
|
covenantID = 3,
|
|
conduitItemID = 181775,
|
|
},
|
|
{ -- Vicious Contempt
|
|
conduitID = 64,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 41,
|
|
covenantID = 0,
|
|
conduitItemID = 181776,
|
|
},
|
|
{ -- Eternal Hunger
|
|
conduitID = 65,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 7,
|
|
covenantID = 0,
|
|
conduitItemID = 181786,
|
|
},
|
|
{ -- Translucent Image
|
|
conduitID = 66,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 0,
|
|
conduitItemID = 181826,
|
|
},
|
|
{ -- Move with Grace
|
|
conduitID = 67,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 0,
|
|
conduitItemID = 181827,
|
|
},
|
|
{ -- Chilled Resilience
|
|
conduitID = 68,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 0,
|
|
conduitItemID = 181834,
|
|
},
|
|
{ -- Clear Mind
|
|
conduitID = 69,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 0,
|
|
conduitItemID = 181837,
|
|
},
|
|
{ -- Spirit Drain
|
|
conduitID = 70,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 0,
|
|
conduitItemID = 181836,
|
|
},
|
|
{ -- Charitable Soul
|
|
conduitID = 71,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 0,
|
|
conduitItemID = 181838,
|
|
},
|
|
{ -- Light's Inspiration
|
|
conduitID = 72,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 0,
|
|
conduitItemID = 181840,
|
|
},
|
|
{ -- Power Unto Others
|
|
conduitID = 73,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 0,
|
|
conduitItemID = 181842,
|
|
},
|
|
{ -- Reinforced Shell
|
|
conduitID = 74,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 0,
|
|
conduitItemID = 181841,
|
|
},
|
|
{ -- Shining Radiance
|
|
conduitID = 75,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 31,
|
|
covenantID = 0,
|
|
conduitItemID = 181843,
|
|
},
|
|
{ -- Pain Transformation
|
|
conduitID = 76,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 31,
|
|
covenantID = 0,
|
|
conduitItemID = 181844,
|
|
},
|
|
{ -- Exaltation
|
|
conduitID = 77,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 31,
|
|
covenantID = 0,
|
|
conduitItemID = 181845,
|
|
},
|
|
{ -- Lasting Spirit
|
|
conduitID = 78,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 32,
|
|
covenantID = 0,
|
|
conduitItemID = 181847,
|
|
},
|
|
{ -- Accelerated Cold
|
|
conduitID = 79,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 6,
|
|
covenantID = 0,
|
|
conduitItemID = 181848,
|
|
},
|
|
{ -- Withering Plague
|
|
conduitID = 80,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 5,
|
|
covenantID = 0,
|
|
conduitItemID = 181866,
|
|
},
|
|
{ -- Swift Penitence
|
|
conduitID = 81,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 31,
|
|
covenantID = 0,
|
|
conduitItemID = 181867,
|
|
},
|
|
{ -- Focused Mending
|
|
conduitID = 82,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 32,
|
|
covenantID = 0,
|
|
conduitItemID = 181942,
|
|
},
|
|
{ -- Eradicating Blow
|
|
conduitID = 83,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 6,
|
|
covenantID = 0,
|
|
conduitItemID = 181943,
|
|
},
|
|
{ -- Resonant Words
|
|
conduitID = 84,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 32,
|
|
covenantID = 0,
|
|
conduitItemID = 181944,
|
|
},
|
|
{ -- Mental Recovery
|
|
conduitID = 85,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 0,
|
|
conduitItemID = 181962,
|
|
},
|
|
{ -- Blood Bond
|
|
conduitID = 86,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 5,
|
|
covenantID = 0,
|
|
conduitItemID = 181963,
|
|
},
|
|
{ -- Courageous Ascension
|
|
conduitID = 87,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 1,
|
|
conduitItemID = 181974,
|
|
},
|
|
{ -- Hardened Bones
|
|
conduitID = 88,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 0,
|
|
conduitItemID = 181975,
|
|
},
|
|
{ -- Embrace Death
|
|
conduitID = 89,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 7,
|
|
covenantID = 0,
|
|
conduitItemID = 181980,
|
|
},
|
|
{ -- Festering Transfusion
|
|
conduitID = 90,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 4,
|
|
conduitItemID = 181981,
|
|
},
|
|
{ -- Everfrost
|
|
conduitID = 91,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 6,
|
|
covenantID = 0,
|
|
conduitItemID = 181982,
|
|
},
|
|
{ -- Astral Protection
|
|
conduitID = 92,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 0,
|
|
conduitItemID = 182105,
|
|
},
|
|
{ -- Refreshing Waters
|
|
conduitID = 93,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 0,
|
|
conduitItemID = 182106,
|
|
},
|
|
{ -- Vital Accretion
|
|
conduitID = 94,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 0,
|
|
conduitItemID = 182107,
|
|
},
|
|
{ -- Thunderous Paws
|
|
conduitID = 95,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 0,
|
|
conduitItemID = 182108,
|
|
},
|
|
{ -- Totemic Surge
|
|
conduitID = 96,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 0,
|
|
conduitItemID = 182109,
|
|
},
|
|
{ -- Crippling Hex
|
|
conduitID = 97,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 0,
|
|
conduitItemID = 182110,
|
|
},
|
|
{ -- Spiritual Resonance
|
|
conduitID = 98,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 0,
|
|
conduitItemID = 182111,
|
|
},
|
|
{ -- Fleeting Wind
|
|
conduitID = 99,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 0,
|
|
conduitItemID = 182113,
|
|
},
|
|
{ -- Pyroclastic Shock
|
|
conduitID = 100,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 11,
|
|
covenantID = 0,
|
|
conduitItemID = 182125,
|
|
},
|
|
{ -- Fae Fermata
|
|
conduitID = 101,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 3,
|
|
conduitItemID = 182129,
|
|
},
|
|
{ -- High Voltage
|
|
conduitID = 102,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 11,
|
|
covenantID = 0,
|
|
conduitItemID = 182126,
|
|
},
|
|
{ -- Shake the Foundations
|
|
conduitID = 103,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 11,
|
|
covenantID = 0,
|
|
conduitItemID = 182127,
|
|
},
|
|
{ -- Call of Flame
|
|
conduitID = 104,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 11,
|
|
covenantID = 0,
|
|
conduitItemID = 182128,
|
|
},
|
|
{ -- Shattered Perceptions
|
|
conduitID = 105,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 166,
|
|
covenantID = 2,
|
|
conduitItemID = 182130,
|
|
},
|
|
{ -- Unending Grip
|
|
conduitID = 106,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 0,
|
|
conduitItemID = 182132,
|
|
},
|
|
{ -- Haunting Apparitions
|
|
conduitID = 107,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 33,
|
|
covenantID = 0,
|
|
conduitItemID = 182131,
|
|
},
|
|
{ -- Insatiable Appetite
|
|
conduitID = 108,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 0,
|
|
conduitItemID = 182133,
|
|
},
|
|
{ -- Unruly Winds
|
|
conduitID = 109,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 12,
|
|
covenantID = 0,
|
|
conduitItemID = 182134,
|
|
},
|
|
{ -- Focused Lightning
|
|
conduitID = 110,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 12,
|
|
covenantID = 0,
|
|
conduitItemID = 182135,
|
|
},
|
|
{ -- Magma Fist
|
|
conduitID = 111,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 12,
|
|
covenantID = 0,
|
|
conduitItemID = 182137,
|
|
},
|
|
{ -- Chilled to the Core
|
|
conduitID = 112,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 12,
|
|
covenantID = 0,
|
|
conduitItemID = 182136,
|
|
},
|
|
{ -- Mind Devourer
|
|
conduitID = 113,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 33,
|
|
covenantID = 0,
|
|
conduitItemID = 182138,
|
|
},
|
|
{ -- Rabid Shadows
|
|
conduitID = 114,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 33,
|
|
covenantID = 0,
|
|
conduitItemID = 182139,
|
|
},
|
|
{ -- Dissonant Echoes
|
|
conduitID = 115,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 33,
|
|
covenantID = 0,
|
|
conduitItemID = 182140,
|
|
},
|
|
{ -- Holy Oration
|
|
conduitID = 116,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 32,
|
|
covenantID = 0,
|
|
conduitItemID = 182141,
|
|
},
|
|
{ -- Embrace of Earth
|
|
conduitID = 117,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 4,
|
|
covenantID = 0,
|
|
conduitItemID = 182142,
|
|
},
|
|
{ -- Swirling Currents
|
|
conduitID = 118,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 4,
|
|
covenantID = 0,
|
|
conduitItemID = 182143,
|
|
},
|
|
{ -- Heavy Rainfall
|
|
conduitID = 119,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 4,
|
|
covenantID = 0,
|
|
conduitItemID = 182145,
|
|
},
|
|
{ -- Nature's Focus
|
|
conduitID = 120,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 4,
|
|
covenantID = 0,
|
|
conduitItemID = 182144,
|
|
},
|
|
{ -- Meat Shield
|
|
conduitID = 121,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 5,
|
|
covenantID = 0,
|
|
conduitItemID = 182187,
|
|
},
|
|
{ -- Unleashed Frenzy
|
|
conduitID = 122,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 6,
|
|
covenantID = 0,
|
|
conduitItemID = 182201,
|
|
},
|
|
{ -- Debilitating Malady
|
|
conduitID = 123,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 5,
|
|
covenantID = 0,
|
|
conduitItemID = 182203,
|
|
},
|
|
{ -- Convocation of the Dead
|
|
conduitID = 124,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 7,
|
|
covenantID = 0,
|
|
conduitItemID = 182206,
|
|
},
|
|
{ -- Lingering Plague
|
|
conduitID = 125,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 7,
|
|
covenantID = 0,
|
|
conduitItemID = 182208,
|
|
},
|
|
{ -- Impenetrable Gloom
|
|
conduitID = 126,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 2,
|
|
conduitItemID = 182288,
|
|
},
|
|
{ -- Brutal Grasp
|
|
conduitID = 127,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 4,
|
|
conduitItemID = 182292,
|
|
},
|
|
{ -- Proliferation
|
|
conduitID = 128,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 1,
|
|
conduitItemID = 182295,
|
|
},
|
|
{ -- Divine Call
|
|
conduitID = 129,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 0,
|
|
conduitItemID = 182304,
|
|
},
|
|
{ -- Fel Defender
|
|
conduitID = 130,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 0,
|
|
conduitItemID = 182316,
|
|
},
|
|
{ -- Viscous Ink
|
|
conduitID = 131,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 0,
|
|
conduitItemID = 182318,
|
|
},
|
|
{ -- Shattered Restoration
|
|
conduitID = 132,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 0,
|
|
conduitItemID = 182317,
|
|
},
|
|
{ -- Shielding Words
|
|
conduitID = 133,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 0,
|
|
conduitItemID = 182307,
|
|
},
|
|
{ -- Felfire Haste
|
|
conduitID = 134,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 0,
|
|
conduitItemID = 182324,
|
|
},
|
|
{ -- Ravenous Consumption
|
|
conduitID = 135,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 0,
|
|
conduitItemID = 182325,
|
|
},
|
|
{ -- Enfeebled Mark
|
|
conduitID = 137,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 1,
|
|
conduitItemID = 182321,
|
|
},
|
|
{ -- Demonic Parole
|
|
conduitID = 138,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 0,
|
|
conduitItemID = 182330,
|
|
},
|
|
{ -- Empowered Release
|
|
conduitID = 139,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 2,
|
|
conduitItemID = 182331,
|
|
},
|
|
{ -- Spirit Attunement
|
|
conduitID = 140,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 3,
|
|
conduitItemID = 182335,
|
|
},
|
|
{ -- Golden Path
|
|
conduitID = 141,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 0,
|
|
conduitItemID = 182336,
|
|
},
|
|
{ -- Pure Concentration
|
|
conduitID = 142,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 0,
|
|
conduitItemID = 182338,
|
|
},
|
|
{ -- Necrotic Barrage
|
|
conduitID = 143,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 4,
|
|
conduitItemID = 182339,
|
|
},
|
|
{ -- Fel Celerity
|
|
conduitID = 144,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 0,
|
|
conduitItemID = 182340,
|
|
},
|
|
{ -- Lost in Darkness
|
|
conduitID = 145,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 0,
|
|
conduitItemID = 182344,
|
|
},
|
|
{ -- Elysian Dirge
|
|
conduitID = 146,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 1,
|
|
conduitItemID = 182345,
|
|
},
|
|
{ -- Tumbling Waves
|
|
conduitID = 147,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 4,
|
|
conduitItemID = 182346,
|
|
},
|
|
{ -- Essential Extraction
|
|
conduitID = 148,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 3,
|
|
conduitItemID = 182347,
|
|
},
|
|
{ -- Lavish Harvest
|
|
conduitID = 149,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 13,
|
|
covenantID = 2,
|
|
conduitItemID = 182348,
|
|
},
|
|
{ -- Relentless Onslaught
|
|
conduitID = 150,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 9,
|
|
covenantID = 0,
|
|
conduitItemID = 182368,
|
|
},
|
|
{ -- Dancing with Fate
|
|
conduitID = 151,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 9,
|
|
covenantID = 0,
|
|
conduitItemID = 182383,
|
|
},
|
|
{ -- Serrated Glaive
|
|
conduitID = 152,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 9,
|
|
covenantID = 0,
|
|
conduitItemID = 182384,
|
|
},
|
|
{ -- Growing Inferno
|
|
conduitID = 153,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 0,
|
|
conduitItemID = 182385,
|
|
},
|
|
{ -- Piercing Verdict
|
|
conduitID = 154,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 1,
|
|
conduitItemID = 182440,
|
|
},
|
|
{ -- Marksman's Advantage
|
|
conduitID = 157,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 0,
|
|
conduitItemID = 182441,
|
|
},
|
|
{ -- Veteran's Repute
|
|
conduitID = 158,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 4,
|
|
conduitItemID = 182442,
|
|
},
|
|
{ -- Light's Barding
|
|
conduitID = 159,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 0,
|
|
conduitItemID = 182448,
|
|
},
|
|
{ -- Resolute Barrier
|
|
conduitID = 160,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 0,
|
|
conduitItemID = 182449,
|
|
},
|
|
{ -- Wrench Evil
|
|
conduitID = 161,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 0,
|
|
conduitItemID = 182456,
|
|
},
|
|
{ -- Accrued Vitality
|
|
conduitID = 162,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 0,
|
|
conduitItemID = 182460,
|
|
},
|
|
{ -- Echoing Blessings
|
|
conduitID = 163,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 0,
|
|
conduitItemID = 182461,
|
|
},
|
|
{ -- Expurgation
|
|
conduitID = 164,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 29,
|
|
covenantID = 0,
|
|
conduitItemID = 182462,
|
|
},
|
|
{ -- Harrowing Punishment
|
|
conduitID = 165,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 2,
|
|
conduitItemID = 182463,
|
|
},
|
|
{ -- Harmony of the Tortollan
|
|
conduitID = 166,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 0,
|
|
conduitItemID = 182464,
|
|
},
|
|
{ -- Truth's Wake
|
|
conduitID = 167,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 29,
|
|
covenantID = 0,
|
|
conduitItemID = 182465,
|
|
},
|
|
{ -- Shade of Terror
|
|
conduitID = 168,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 0,
|
|
conduitItemID = 182466,
|
|
},
|
|
{ -- Mortal Combo
|
|
conduitID = 169,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 40,
|
|
covenantID = 0,
|
|
conduitItemID = 182468,
|
|
},
|
|
{ -- Rejuvenating Wind
|
|
conduitID = 170,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 0,
|
|
conduitItemID = 182469,
|
|
},
|
|
{ -- Demonic Momentum
|
|
conduitID = 171,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 0,
|
|
conduitItemID = 182470,
|
|
},
|
|
{ -- Soul Furnace
|
|
conduitID = 172,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 10,
|
|
covenantID = 0,
|
|
conduitItemID = 182471,
|
|
},
|
|
{ -- Resilience of the Hunter
|
|
conduitID = 173,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 0,
|
|
conduitItemID = 182476,
|
|
},
|
|
{ -- Corrupting Leer
|
|
conduitID = 174,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 37,
|
|
covenantID = 0,
|
|
conduitItemID = 182478,
|
|
},
|
|
{ -- Reversal of Fortune
|
|
conduitID = 175,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 0,
|
|
conduitItemID = 182480,
|
|
},
|
|
{ -- Templar's Vindication
|
|
conduitID = 176,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 29,
|
|
covenantID = 0,
|
|
conduitItemID = 182559,
|
|
},
|
|
{ -- Enkindled Spirit
|
|
conduitID = 177,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 27,
|
|
covenantID = 0,
|
|
conduitItemID = 182582,
|
|
},
|
|
{ -- Cheetah's Vigor
|
|
conduitID = 178,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 0,
|
|
conduitItemID = 182584,
|
|
},
|
|
{ -- Demon Muzzle
|
|
conduitID = 179,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 10,
|
|
covenantID = 0,
|
|
conduitItemID = 182598,
|
|
},
|
|
{ -- Roaring Fire
|
|
conduitID = 180,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 10,
|
|
covenantID = 0,
|
|
conduitItemID = 182604,
|
|
},
|
|
{ -- Tactical Retreat
|
|
conduitID = 181,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 0,
|
|
conduitItemID = 182605,
|
|
},
|
|
{ -- Virtuous Command
|
|
conduitID = 182,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 29,
|
|
covenantID = 0,
|
|
conduitItemID = 182608,
|
|
},
|
|
{ -- Ferocious Appetite
|
|
conduitID = 183,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 44,
|
|
covenantID = 0,
|
|
conduitItemID = 182610,
|
|
},
|
|
{ -- Resplendent Light
|
|
conduitID = 184,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 27,
|
|
covenantID = 0,
|
|
conduitItemID = 182622,
|
|
},
|
|
{ -- One With the Beast
|
|
conduitID = 185,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 44,
|
|
covenantID = 0,
|
|
conduitItemID = 182621,
|
|
},
|
|
{ -- Show of Force
|
|
conduitID = 186,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 42,
|
|
covenantID = 0,
|
|
conduitItemID = 182624,
|
|
},
|
|
{ -- Repeat Decree
|
|
conduitID = 187,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 1,
|
|
conduitItemID = 182646,
|
|
},
|
|
{ -- Sharpshooter's Focus
|
|
conduitID = 188,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 14,
|
|
covenantID = 0,
|
|
conduitItemID = 182648,
|
|
},
|
|
{ -- Brutal Projectiles
|
|
conduitID = 189,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 14,
|
|
covenantID = 0,
|
|
conduitItemID = 182649,
|
|
},
|
|
{ -- Destructive Reverberations
|
|
conduitID = 190,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 3,
|
|
conduitItemID = 182651,
|
|
},
|
|
{ -- Disturb the Peace
|
|
conduitID = 191,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 168,
|
|
covenantID = 0,
|
|
conduitItemID = 182656,
|
|
},
|
|
{ -- Deadly Chain
|
|
conduitID = 192,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 14,
|
|
covenantID = 0,
|
|
conduitItemID = 182657,
|
|
},
|
|
{ -- Focused Light
|
|
conduitID = 193,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 27,
|
|
covenantID = 0,
|
|
conduitItemID = 182667,
|
|
},
|
|
{ -- Untempered Dedication
|
|
conduitID = 194,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 27,
|
|
covenantID = 0,
|
|
conduitItemID = 182675,
|
|
},
|
|
{ -- Vengeful Shock
|
|
conduitID = 195,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 28,
|
|
covenantID = 0,
|
|
conduitItemID = 182681,
|
|
},
|
|
{ -- Punish the Guilty
|
|
conduitID = 196,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 28,
|
|
covenantID = 0,
|
|
conduitItemID = 182677,
|
|
},
|
|
{ -- Resolute Defender
|
|
conduitID = 197,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 28,
|
|
covenantID = 0,
|
|
conduitItemID = 182684,
|
|
},
|
|
{ -- Increased Scrutiny
|
|
conduitID = 198,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 2,
|
|
conduitItemID = 182685,
|
|
},
|
|
{ -- Powerful Precision
|
|
conduitID = 199,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 14,
|
|
covenantID = 0,
|
|
conduitItemID = 182686,
|
|
},
|
|
{ -- Brooding Pool
|
|
conduitID = 200,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 4,
|
|
conduitItemID = 182706,
|
|
},
|
|
{ -- Rolling Agony
|
|
conduitID = 201,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 37,
|
|
covenantID = 0,
|
|
conduitItemID = 182736,
|
|
},
|
|
{ -- Focused Malignancy
|
|
conduitID = 202,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 37,
|
|
covenantID = 0,
|
|
conduitItemID = 182743,
|
|
},
|
|
{ -- Withering Bolt
|
|
conduitID = 203,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 37,
|
|
covenantID = 0,
|
|
conduitItemID = 182747,
|
|
},
|
|
{ -- Borne of Blood
|
|
conduitID = 204,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 39,
|
|
covenantID = 0,
|
|
conduitItemID = 182748,
|
|
},
|
|
{ -- Carnivorous Stalkers
|
|
conduitID = 205,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 39,
|
|
covenantID = 0,
|
|
conduitItemID = 182750,
|
|
},
|
|
{ -- Tyrant's Soul
|
|
conduitID = 206,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 39,
|
|
covenantID = 0,
|
|
conduitItemID = 182751,
|
|
},
|
|
{ -- Fel Commando
|
|
conduitID = 207,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 39,
|
|
covenantID = 0,
|
|
conduitItemID = 182752,
|
|
},
|
|
{ -- Duplicitous Havoc
|
|
conduitID = 208,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 38,
|
|
covenantID = 0,
|
|
conduitItemID = 182754,
|
|
},
|
|
{ -- Royal Decree
|
|
conduitID = 209,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 28,
|
|
covenantID = 0,
|
|
conduitItemID = 182753,
|
|
},
|
|
{ -- The Long Summer
|
|
conduitID = 210,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 3,
|
|
conduitItemID = 182767,
|
|
},
|
|
{ -- Ashen Remains
|
|
conduitID = 211,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 38,
|
|
covenantID = 0,
|
|
conduitItemID = 182755,
|
|
},
|
|
{ -- Combusting Engine
|
|
conduitID = 212,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 38,
|
|
covenantID = 0,
|
|
conduitItemID = 182769,
|
|
},
|
|
{ -- Righteous Might
|
|
conduitID = 213,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 4,
|
|
conduitItemID = 182770,
|
|
},
|
|
{ -- Infernal Brand
|
|
conduitID = 214,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 38,
|
|
covenantID = 0,
|
|
conduitItemID = 182772,
|
|
},
|
|
{ -- Hallowed Discernment
|
|
conduitID = 215,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 2,
|
|
conduitItemID = 182777,
|
|
},
|
|
{ -- Ringing Clarity
|
|
conduitID = 216,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 30,
|
|
covenantID = 1,
|
|
conduitItemID = 182778,
|
|
},
|
|
{ -- Soul Tithe
|
|
conduitID = 217,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 1,
|
|
conduitItemID = 182960,
|
|
},
|
|
{ -- Fatal Decimation
|
|
conduitID = 218,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 4,
|
|
conduitItemID = 182961,
|
|
},
|
|
{ -- Catastrophic Origin
|
|
conduitID = 219,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 2,
|
|
conduitItemID = 182962,
|
|
},
|
|
{ -- Soul Eater
|
|
conduitID = 220,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 3,
|
|
conduitItemID = 182964,
|
|
},
|
|
{ -- Kilrogg's Cunning
|
|
conduitID = 221,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 0,
|
|
conduitItemID = 183044,
|
|
},
|
|
{ -- Diabolic Bloodstone
|
|
conduitID = 222,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 167,
|
|
covenantID = 0,
|
|
conduitItemID = 183076,
|
|
},
|
|
{ -- Echoing Call
|
|
conduitID = 223,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 44,
|
|
covenantID = 0,
|
|
conduitItemID = 183132,
|
|
},
|
|
{ -- Strength of the Pack
|
|
conduitID = 224,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 20,
|
|
covenantID = 0,
|
|
conduitItemID = 183167,
|
|
},
|
|
{ -- Reverberation
|
|
conduitID = 225,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 1,
|
|
conduitItemID = 183492,
|
|
},
|
|
{ -- Stinging Strike
|
|
conduitID = 226,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 20,
|
|
covenantID = 0,
|
|
conduitItemID = 183184,
|
|
},
|
|
{ -- Sudden Fractures
|
|
conduitID = 227,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 4,
|
|
conduitItemID = 183493,
|
|
},
|
|
{ -- Septic Shock
|
|
conduitID = 228,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 3,
|
|
conduitItemID = 183494,
|
|
},
|
|
{ -- Lashing Scars
|
|
conduitID = 229,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 2,
|
|
conduitItemID = 183495,
|
|
},
|
|
{ -- Nimble Fingers
|
|
conduitID = 230,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 0,
|
|
conduitItemID = 183496,
|
|
},
|
|
{ -- Recuperator
|
|
conduitID = 231,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 0,
|
|
conduitItemID = 183497,
|
|
},
|
|
{ -- Cloaked in Shadows
|
|
conduitID = 232,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 0,
|
|
conduitItemID = 183498,
|
|
},
|
|
{ -- Quick Decisions
|
|
conduitID = 233,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 0,
|
|
conduitItemID = 183499,
|
|
},
|
|
{ -- Fade to Nothing
|
|
conduitID = 234,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 0,
|
|
conduitItemID = 183500,
|
|
},
|
|
{ -- Rushed Setup
|
|
conduitID = 235,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 0,
|
|
conduitItemID = 183501,
|
|
},
|
|
{ -- Prepared for All
|
|
conduitID = 236,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 165,
|
|
covenantID = 0,
|
|
conduitItemID = 183502,
|
|
},
|
|
{ -- Poisoned Katar
|
|
conduitID = 237,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 34,
|
|
covenantID = 0,
|
|
conduitItemID = 183503,
|
|
},
|
|
{ -- Well-Placed Steel
|
|
conduitID = 238,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 34,
|
|
covenantID = 0,
|
|
conduitItemID = 183504,
|
|
},
|
|
{ -- Maim, Mangle
|
|
conduitID = 239,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 34,
|
|
covenantID = 0,
|
|
conduitItemID = 183505,
|
|
},
|
|
{ -- Lethal Poisons
|
|
conduitID = 240,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 34,
|
|
covenantID = 0,
|
|
conduitItemID = 183506,
|
|
},
|
|
{ -- Triple Threat
|
|
conduitID = 241,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 35,
|
|
covenantID = 0,
|
|
conduitItemID = 183507,
|
|
},
|
|
{ -- Ambidexterity
|
|
conduitID = 242,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 35,
|
|
covenantID = 0,
|
|
conduitItemID = 183508,
|
|
},
|
|
{ -- Sleight of Hand
|
|
conduitID = 243,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 35,
|
|
covenantID = 0,
|
|
conduitItemID = 183509,
|
|
},
|
|
{ -- Count the Odds
|
|
conduitID = 244,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 35,
|
|
covenantID = 0,
|
|
conduitItemID = 183510,
|
|
},
|
|
{ -- Deeper Daggers
|
|
conduitID = 245,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 36,
|
|
covenantID = 0,
|
|
conduitItemID = 183511,
|
|
},
|
|
{ -- Planned Execution
|
|
conduitID = 246,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 36,
|
|
covenantID = 0,
|
|
conduitItemID = 183512,
|
|
},
|
|
{ -- Stiletto Staccato
|
|
conduitID = 247,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 36,
|
|
covenantID = 0,
|
|
conduitItemID = 183513,
|
|
},
|
|
{ -- Perforated Veins
|
|
conduitID = 248,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 36,
|
|
covenantID = 0,
|
|
conduitItemID = 183514,
|
|
},
|
|
{ -- Controlled Destruction
|
|
conduitID = 249,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 23,
|
|
covenantID = 0,
|
|
conduitItemID = 183197,
|
|
},
|
|
{ -- Withering Ground
|
|
conduitID = 250,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 43,
|
|
covenantID = 3,
|
|
conduitItemID = 183199,
|
|
},
|
|
{ -- Deadly Tandem
|
|
conduitID = 251,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 20,
|
|
covenantID = 0,
|
|
conduitItemID = 183202,
|
|
},
|
|
{ -- Flame Infusion
|
|
conduitID = 252,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 20,
|
|
covenantID = 0,
|
|
conduitItemID = 183396,
|
|
},
|
|
{ -- Bloodletting
|
|
conduitID = 253,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 44,
|
|
covenantID = 0,
|
|
conduitItemID = 183402,
|
|
},
|
|
{ -- Tough as Bark
|
|
conduitID = 254,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 0,
|
|
conduitItemID = 183464,
|
|
},
|
|
{ -- Ursine Vigor
|
|
conduitID = 255,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 0,
|
|
conduitItemID = 183465,
|
|
},
|
|
{ -- Innate Resolve
|
|
conduitID = 256,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 0,
|
|
conduitItemID = 183466,
|
|
},
|
|
{ -- Tireless Pursuit
|
|
conduitID = 257,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 0,
|
|
conduitItemID = 183467,
|
|
},
|
|
{ -- Born Anew
|
|
conduitID = 258,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 0,
|
|
conduitItemID = 183468,
|
|
},
|
|
{ -- Front of the Pack
|
|
conduitID = 259,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 0,
|
|
conduitItemID = 183469,
|
|
},
|
|
{ -- Born of the Wilds
|
|
conduitID = 260,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 0,
|
|
conduitItemID = 183470,
|
|
},
|
|
{ -- Stellar Inspiration
|
|
conduitID = 261,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 15,
|
|
covenantID = 0,
|
|
conduitItemID = 183476,
|
|
},
|
|
{ -- Precise Alignment
|
|
conduitID = 262,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 15,
|
|
covenantID = 0,
|
|
conduitItemID = 183477,
|
|
},
|
|
{ -- Fury of the Skies
|
|
conduitID = 263,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 15,
|
|
covenantID = 0,
|
|
conduitItemID = 183478,
|
|
},
|
|
{ -- Umbral Intensity
|
|
conduitID = 264,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 15,
|
|
covenantID = 0,
|
|
conduitItemID = 183479,
|
|
},
|
|
{ -- Taste for Blood
|
|
conduitID = 265,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 16,
|
|
covenantID = 0,
|
|
conduitItemID = 183480,
|
|
},
|
|
{ -- Incessant Hunter
|
|
conduitID = 266,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 16,
|
|
covenantID = 0,
|
|
conduitItemID = 183481,
|
|
},
|
|
{ -- Sudden Ambush
|
|
conduitID = 267,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 16,
|
|
covenantID = 0,
|
|
conduitItemID = 183482,
|
|
},
|
|
{ -- Carnivorous Instinct
|
|
conduitID = 268,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 16,
|
|
covenantID = 0,
|
|
conduitItemID = 183483,
|
|
},
|
|
{ -- Unchecked Aggression
|
|
conduitID = 269,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 17,
|
|
covenantID = 0,
|
|
conduitItemID = 183484,
|
|
},
|
|
{ -- Savage Combatant
|
|
conduitID = 270,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 17,
|
|
covenantID = 0,
|
|
conduitItemID = 183485,
|
|
},
|
|
{ -- Well-Honed Instincts
|
|
conduitID = 271,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 0,
|
|
conduitItemID = 183486,
|
|
},
|
|
{ -- Layered Mane
|
|
conduitID = 272,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 17,
|
|
covenantID = 0,
|
|
conduitItemID = 183487,
|
|
},
|
|
{ -- Unstoppable Growth
|
|
conduitID = 273,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 18,
|
|
covenantID = 0,
|
|
conduitItemID = 183488,
|
|
},
|
|
{ -- Flash of Clarity
|
|
conduitID = 274,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 18,
|
|
covenantID = 0,
|
|
conduitItemID = 183489,
|
|
},
|
|
{ -- Floral Recycling
|
|
conduitID = 275,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 18,
|
|
covenantID = 0,
|
|
conduitItemID = 183490,
|
|
},
|
|
{ -- Ready for Anything
|
|
conduitID = 276,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 18,
|
|
covenantID = 0,
|
|
conduitItemID = 183491,
|
|
},
|
|
{ -- Deep Allegiance
|
|
conduitID = 277,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 1,
|
|
conduitItemID = 183471,
|
|
},
|
|
{ -- Evolved Swarm
|
|
conduitID = 278,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 4,
|
|
conduitItemID = 183472,
|
|
},
|
|
{ -- Conflux of Elements
|
|
conduitID = 279,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 3,
|
|
conduitItemID = 183473,
|
|
},
|
|
{ -- Endless Thirst
|
|
conduitID = 280,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 48,
|
|
covenantID = 2,
|
|
conduitItemID = 183474,
|
|
},
|
|
{ -- Unnatural Malice
|
|
conduitID = 281,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 8,
|
|
covenantID = 3,
|
|
conduitItemID = 183463,
|
|
},
|
|
{ -- Ambuscade
|
|
conduitID = 282,
|
|
conduitType = 0,
|
|
conduitSpecSetID = 163,
|
|
covenantID = 0,
|
|
conduitItemID = 184587,
|
|
},
|
|
{ -- Condensed Anima Sphere
|
|
conduitID = 283,
|
|
conduitType = 2,
|
|
conduitSpecSetID = 2,
|
|
covenantID = 0,
|
|
conduitItemID = 187506,
|
|
},
|
|
{ -- Adaptive Armor Fragment
|
|
conduitID = 284,
|
|
conduitType = 1,
|
|
conduitSpecSetID = 1,
|
|
covenantID = 0,
|
|
conduitItemID = 187507,
|
|
},
|
|
}
|
|
local conduitsByID = {}
|
|
local conduitsByItemID = {}
|
|
for _,conduit in ipairs(conduits) do
|
|
conduit.conduitRank = 11
|
|
conduit.conduitItemLevel = 278
|
|
|
|
local specIDs = C_SpecializationInfo.GetSpecIDs(conduit.conduitSpecSetID)
|
|
if #specIDs == 1 then
|
|
conduit.conduitSpecName = select(2, GetSpecializationInfoByID(specIDs[1]))
|
|
end
|
|
|
|
conduitsByID[conduit.conduitID] = conduit
|
|
conduitsByItemID[conduit.conduitItemID] = conduit
|
|
end
|
|
|
|
local function GetConduitByID(itemID)
|
|
return conduitsByID[itemID]
|
|
end
|
|
local function GetConduitByItemID(itemID)
|
|
return conduitsByItemID[itemID]
|
|
end
|
|
local function CheckConduitCovenant(conduitData, covenantID)
|
|
return conduitData.covenantID == 0 or conduitData.covenantID == covenantID
|
|
end
|
|
local function CheckConduitClass(conduitData, classID)
|
|
local specIDs = C_SpecializationInfo.GetSpecIDs(conduitData.conduitSpecSetID)
|
|
|
|
if conduitData.conduitID == 284 then -- Tank only conduit
|
|
local classInfo = C_CreatureInfo.GetClassInfo(classID)
|
|
for _,specID in ipairs(specIDs) do
|
|
local classFile = select(6, GetSpecializationInfoByID(specID))
|
|
if classInfo.classFile == classFile then
|
|
conduitData.conduitSpecName = select(2, GetSpecializationInfoByID(specID))
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
if #specIDs == 0 or #specIDs > 4 then
|
|
return true
|
|
end
|
|
local classInfo = C_CreatureInfo.GetClassInfo(classID)
|
|
local classFile = select(6, GetSpecializationInfoByID(specIDs[1]))
|
|
return classInfo.classFile == classFile
|
|
end
|
|
|
|
local function GetConduitCollection(classID, covenantID, conduitType)
|
|
local results = {}
|
|
if classID ~= nil then
|
|
for _,conduit in ipairs(conduits) do
|
|
if conduit.conduitType == conduitType and CheckConduitCovenant(conduit, covenantID) and CheckConduitClass(conduit, classID) then
|
|
results[#results+1] = conduit
|
|
end
|
|
end
|
|
end
|
|
return results
|
|
end
|
|
|
|
|
|
local ConduitTypeCollapsed = {}
|
|
|
|
BtWLoadoutsConduitListCategoryButtonMixin = {};
|
|
function BtWLoadoutsConduitListCategoryButtonMixin:Init(conduitType, collapsed)
|
|
local name = self.Container.Name;
|
|
name:SetText(GetConduitName(conduitType));
|
|
name:SetWidth(name:GetStringWidth() + 40);
|
|
|
|
local icon = self.Container.ConduitIcon;
|
|
icon:SetAtlas(GetConduitEmblemAtlas(conduitType));
|
|
icon:SetScale(GetConduitIconScale(conduitType));
|
|
icon:SetPoint("LEFT", name, "RIGHT", -40, -1);
|
|
|
|
self.collapsed = collapsed;
|
|
self:SetCollapsedVisuals(collapsed);
|
|
end
|
|
function BtWLoadoutsConduitListCategoryButtonMixin:OnEnter()
|
|
for index, texture in ipairs(self.Container.Hovers) do
|
|
texture:Show();
|
|
end
|
|
end
|
|
function BtWLoadoutsConduitListCategoryButtonMixin:OnLeave()
|
|
for index, texture in ipairs(self.Container.Hovers) do
|
|
texture:Hide();
|
|
end
|
|
GameTooltip_Hide();
|
|
end
|
|
function BtWLoadoutsConduitListCategoryButtonMixin:OnMouseDown()
|
|
self.Container:AdjustPointsOffset(1, -1);
|
|
end
|
|
function BtWLoadoutsConduitListCategoryButtonMixin:OnMouseUp()
|
|
self.Container:AdjustPointsOffset(-1, 1);
|
|
end
|
|
function BtWLoadoutsConduitListCategoryButtonMixin:SetCollapsedVisuals(collapsed)
|
|
if collapsed then
|
|
self.Container.ExpandableIcon:SetAtlas("Soulbinds_Collection_CategoryHeader_Expand", TextureKitConstants.UseAtlasSize);
|
|
else
|
|
self.Container.ExpandableIcon:SetAtlas("Soulbinds_Collection_CategoryHeader_Collapse", TextureKitConstants.UseAtlasSize);
|
|
end
|
|
end
|
|
function BtWLoadoutsConduitListCategoryButtonMixin:SetCollapsed(collapsed)
|
|
local changed = self.collapsed ~= collapsed;
|
|
if not changed then
|
|
return;
|
|
end
|
|
self.collapsed = collapsed;
|
|
|
|
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF);
|
|
|
|
self:SetCollapsedVisuals(collapsed);
|
|
end
|
|
|
|
BtWLoadoutsConduitListConduitButtonMixin = {};
|
|
BtWLoadoutsConduitListConduitButtonMixin.State = {
|
|
Uninstalled = 1,
|
|
Installed = 2,
|
|
Pending = 3,
|
|
}
|
|
function BtWLoadoutsConduitListConduitButtonMixin:OnLoad()
|
|
self:RegisterForDrag("LeftButton");
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:Init(owner, conduitData)
|
|
self.owner = owner
|
|
self.conduitData = conduitData;
|
|
|
|
local itemID = conduitData.conduitItemID;
|
|
local item = Item:CreateFromItemID(itemID);
|
|
local itemCallback = function()
|
|
self.ConduitName:SetSize(150, 30);
|
|
self.ConduitName:SetText(item:GetItemName());
|
|
self.ConduitName:SetHeight(self.ConduitName:GetStringHeight());
|
|
|
|
local yOffset = self.ConduitName:GetNumLines() > 1 and -6 or 0;
|
|
self.ConduitName:ClearAllPoints();
|
|
self.ConduitName:SetPoint("BOTTOMLEFT", self.Icon, "RIGHT", 10, yOffset);
|
|
self.ConduitName:SetWidth(150);
|
|
|
|
self.ItemLevel:SetPoint("TOPLEFT", self.ConduitName, "BOTTOMLEFT", 0, 0);
|
|
self.ItemLevel:SetText(conduitData.conduitItemLevel);
|
|
end;
|
|
item:ContinueOnItemLoad(itemCallback);
|
|
|
|
local icon = item:GetItemIcon();
|
|
self.Icon:SetTexture(icon);
|
|
self.Icon2:SetTexture(icon);
|
|
self.IconPulse:SetTexture(icon);
|
|
|
|
local conduitQuality = C_Soulbinds.GetConduitQuality(conduitData.conduitID, conduitData.conduitRank);
|
|
local color = ITEM_QUALITY_COLORS[conduitQuality];
|
|
local r, g, b = color.r, color.g, color.b;
|
|
self.IconOverlay:SetVertexColor(r, g, b);
|
|
self.IconOverlay2:SetVertexColor(r, g, b);
|
|
self.IconOverlayDark:SetVertexColor(0, 0, 0);
|
|
self.ConduitName:SetTextColor(r, g, b);
|
|
|
|
local conduitSpecName = conduitData.conduitSpecName;
|
|
if conduitSpecName then
|
|
local specIDs = C_SpecializationInfo.GetSpecIDs(conduitData.conduitSpecSetID);
|
|
self.Spec.Icon:SetTexture(select(4, GetSpecializationInfoByID(specIDs[1])));
|
|
|
|
self.Spec:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(self.Spec, "ANCHOR_RIGHT");
|
|
GameTooltip_AddHighlightLine(GameTooltip, conduitSpecName);
|
|
GameTooltip:Show();
|
|
end);
|
|
self.Spec:SetScript("OnLeave", function()
|
|
GameTooltip_Hide();
|
|
end);
|
|
self.Spec:Show();
|
|
else
|
|
self.Spec:Hide();
|
|
self.Spec:SetScript("OnEnter", nil);
|
|
self.Spec:SetScript("OnLeave", nil);
|
|
end
|
|
|
|
self:Update();
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:OnEvent(event, ...)
|
|
if event == "CURSOR_CHANGED" then
|
|
local cursorType, itemID = GetCursorInfo()
|
|
local pending = cursorType == "item" and itemID == self.conduitData.conduitItemID;
|
|
self.PendingBackground:SetShown(pending);
|
|
end
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:OnShow()
|
|
FrameUtil.RegisterFrameForEvents(self, {
|
|
"CURSOR_CHANGED",
|
|
});
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:OnHide()
|
|
FrameUtil.UnregisterFrameForEvents(self, {
|
|
"CURSOR_CHANGED",
|
|
});
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:MatchesID(conduitID)
|
|
return self.conduitData.conduitID == conduitID;
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:UpdateVisuals(state)
|
|
local installed = state == BtWLoadoutsConduitListConduitButtonMixin.State.Installed;
|
|
local pending = state == BtWLoadoutsConduitListConduitButtonMixin.State.Pending;
|
|
local dark = installed or pending;
|
|
self.ConduitName:SetAlpha(dark and .5 or 1);
|
|
self.ItemLevel:SetAlpha(dark and .2 or 1);
|
|
self.IconOverlayDark:SetShown(dark);
|
|
self.IconDark:SetShown(dark);
|
|
|
|
self.Pending:SetShown(pending);
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:Update()
|
|
self:UpdateVisuals(self:GetState());
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:GetState()
|
|
if self.owner and self.conduitData then
|
|
local installed = self.owner:IsConduitSlotted(self.conduitData.conduitID)
|
|
if installed then
|
|
return BtWLoadoutsConduitListConduitButtonMixin.State.Installed;
|
|
end
|
|
end
|
|
|
|
-- local soulbindID = Soulbinds.GetOpenSoulbindID();
|
|
-- local conduitID = self.conduitData.conduitID;
|
|
|
|
-- local pendingInstallNodeID = C_Soulbinds.FindNodeIDPendingInstall(soulbindID, conduitID);
|
|
-- if pendingInstallNodeID > 0 then
|
|
-- return BtWLoadoutsConduitListConduitButtonMixin.State.Pending;
|
|
-- end
|
|
|
|
-- local pendingUninstallNodeID = C_Soulbinds.FindNodeIDPendingUninstall(soulbindID, conduitID);
|
|
-- if pendingUninstallNodeID > 0 then
|
|
-- return BtWLoadoutsConduitListConduitButtonMixin.State.Uninstalled;
|
|
-- end
|
|
|
|
-- local installed = C_Soulbinds.IsConduitInstalledInSoulbind(soulbindID, conduitID);
|
|
-- if installed then
|
|
-- return BtWLoadoutsConduitListConduitButtonMixin.State.Installed;
|
|
-- end
|
|
|
|
return BtWLoadoutsConduitListConduitButtonMixin.State.Uninstalled;
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:OnClick(buttonName)
|
|
if buttonName == "LeftButton" then
|
|
local linked = false;
|
|
if IsModifiedClick("CHATLINK") then
|
|
local link = C_Soulbinds.GetConduitHyperlink(self.conduitData.conduitID, self.conduitData.conduitRank);
|
|
linked = HandleModifiedItemClick(link);
|
|
end
|
|
|
|
if not linked then
|
|
self:CreateCursor();
|
|
end
|
|
elseif buttonName == "RightButton" then
|
|
--@TODO highlight conduit within tree?
|
|
end
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:OnDragStart()
|
|
self:CreateCursor();
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:CreateCursor()
|
|
SetCursorVirtualItem(self.conduitData.conduitItemID, Enum.UICursorType.ConduitCollectionItem);
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:OnEnter()
|
|
for index, texture in ipairs(self.Hovers) do
|
|
texture:Show();
|
|
end
|
|
|
|
GameTooltip:SetOwner(self.Icon, "ANCHOR_RIGHT", 178, 0);
|
|
if IsModifiedClick("SHIFT") then
|
|
GameTooltip:SetEnhancedConduit(self.conduitData.conduitID, self.conduitData.conduitRank);
|
|
else
|
|
GameTooltip:SetConduit(self.conduitData.conduitID, self.conduitData.conduitRank);
|
|
end
|
|
GameTooltip:Show();
|
|
end
|
|
function BtWLoadoutsConduitListConduitButtonMixin:OnLeave()
|
|
if self.conduitOnSpellLoadCb then
|
|
self.conduitOnSpellLoadCb();
|
|
self.conduitOnSpellLoadCb = nil;
|
|
end
|
|
|
|
GameTooltip_Hide();
|
|
|
|
for index, texture in ipairs(self.Hovers) do
|
|
texture:Hide();
|
|
end
|
|
end
|
|
|
|
BtWLoadoutsConduitListSectionMixin = {}
|
|
function BtWLoadoutsConduitListSectionMixin:OnLoad()
|
|
self.CategoryButton:SetScript("OnClick", function(button, buttonName, down)
|
|
local newCollapsed = self.Container:IsShown();
|
|
self:GetElementData().collapsed = newCollapsed;
|
|
self:SetCollapsed(newCollapsed);
|
|
end);
|
|
|
|
self.pool = CreateFramePool("BUTTON", self.Container, "BtWLoadoutsConduitListConduitButtonTemplate");
|
|
end
|
|
function BtWLoadoutsConduitListSectionMixin:Init(owner, elementData)
|
|
self.pool:ReleaseAll();
|
|
|
|
self.owner = owner
|
|
|
|
local conduitDatas = CopyTable(elementData.conduitDatas);
|
|
self.conduitType = elementData.conduitType;
|
|
|
|
local frames = {};
|
|
local count = #conduitDatas;
|
|
local function FactoryFunction(index)
|
|
if index > count then
|
|
return nil;
|
|
end
|
|
|
|
local frame = self.pool:Acquire();
|
|
table.insert(frames, frame);
|
|
frame:SetPoint("LEFT", self.Container, "LEFT", 0, 0);
|
|
frame:SetPoint("RIGHT", self.Container, "RIGHT", 0, 0);
|
|
frame:Show();
|
|
return frame;
|
|
end
|
|
|
|
local direction, stride, x, y, paddingX, paddingY = GridLayoutMixin.Direction.TopLeftToBottomRight, 1, 0, 1, 0, 0;
|
|
local anchor = AnchorUtil.CreateAnchor("TOPLEFT", self.Container, "TOPLEFT");
|
|
local layout = AnchorUtil.CreateGridLayout(direction, stride, paddingX, paddingY);
|
|
AnchorUtil.GridLayoutFactoryByCount(FactoryFunction, count, anchor, layout);
|
|
|
|
self.CategoryButton:Init(self.conduitType, elementData.collapsed);
|
|
|
|
self:SetCollapsed(elementData.collapsed);
|
|
|
|
if self.currentContinuable then
|
|
self.currentContinuable:Cancel();
|
|
end
|
|
self.currentContinuable = ContinuableContainer:Create();
|
|
|
|
for index, conduitData in ipairs(conduitDatas) do
|
|
if not conduitData.conduitSpecName then
|
|
conduitData.sortingCategory = 1;
|
|
else
|
|
conduitData.sortingCategory = 2;
|
|
end
|
|
|
|
conduitData.item = Item:CreateFromItemID(conduitData.conduitItemID);
|
|
self.currentContinuable:AddContinuable(conduitData.item);
|
|
end
|
|
|
|
self.currentContinuable:ContinueOnLoad(function()
|
|
local sorter = function(lhs, rhs)
|
|
if lhs.sortingCategory == rhs.sortingCategory then
|
|
if (not lhs.conduitSpecName or not rhs.conduitSpecName) or lhs.conduitSpecName == rhs.conduitSpecName then
|
|
if lhs.conduitRank ~= rhs.conduitRank then
|
|
return lhs.conduitRank > rhs.conduitRank;
|
|
end
|
|
return lhs.item:GetItemName() < rhs.item:GetItemName();
|
|
else
|
|
return lhs.conduitSpecName < rhs.conduitSpecName;
|
|
end
|
|
else
|
|
return lhs.sortingCategory < rhs.sortingCategory;
|
|
end
|
|
end;
|
|
table.sort(conduitDatas, sorter);
|
|
|
|
for index, conduitData in ipairs(conduitDatas) do
|
|
frames[index]:Init(self.owner, conduitData);
|
|
end
|
|
|
|
local newConduitData = elementData.newConduitData;
|
|
if newConduitData then
|
|
elementData.newConduitData = nil;
|
|
self:PlayUpdateAnim(newConduitData);
|
|
end
|
|
end);
|
|
end
|
|
function BtWLoadoutsConduitListSectionMixin:Update()
|
|
for conduitButton in self.pool:EnumerateActive() do
|
|
conduitButton:Update();
|
|
end
|
|
end
|
|
function BtWLoadoutsConduitListSectionMixin:FindConduitButton(conduitID)
|
|
for conduitButton in self.pool:EnumerateActive() do
|
|
if conduitButton:MatchesID(conduitID) then
|
|
return conduitButton;
|
|
end
|
|
end
|
|
end
|
|
function BtWLoadoutsConduitListSectionMixin:IsCollapsed()
|
|
return self:GetElementData().collapsed;
|
|
end
|
|
function BtWLoadoutsConduitListSectionMixin:SetCollapsed(collapsed)
|
|
ConduitTypeCollapsed[self.conduitType] = collapsed
|
|
self.CategoryButton:SetCollapsed(collapsed);
|
|
|
|
local shown = not collapsed;
|
|
self.Container:SetShown(shown);
|
|
self.Spacer:SetShown(shown);
|
|
self:Layout();
|
|
end
|
|
|
|
BtWLoadoutsConduitListMixin = {}
|
|
function BtWLoadoutsConduitListMixin:OnLoad()
|
|
local buttonHeight = 42;
|
|
local topSpacer = 10;
|
|
local bottomSpacer = 5;
|
|
local catButtonExtent = 23;
|
|
local containerOffset = 5;
|
|
local expandedExtent = catButtonExtent + topSpacer + bottomSpacer + containerOffset;
|
|
local collapsedExtent = catButtonExtent + topSpacer;
|
|
|
|
local view = CreateScrollBoxListLinearView();
|
|
view:SetElementExtentCalculator(function(dataIndex, elementData)
|
|
if elementData.collapsed then
|
|
return collapsedExtent;
|
|
else
|
|
return (#elementData.conduitDatas * buttonHeight) + expandedExtent;
|
|
end
|
|
end);
|
|
if Internal.IsDragonflightPatch then
|
|
view:SetElementInitializer("BtWLoadoutsConduitListSectionTemplate", function(list, elementData)
|
|
list:Init(self.owner, elementData);
|
|
end);
|
|
else
|
|
view:SetElementInitializer("EventFrame", "BtWLoadoutsConduitListSectionTemplate", function(list, elementData)
|
|
list:Init(self.owner, elementData);
|
|
end);
|
|
end
|
|
|
|
ScrollUtil.InitScrollBoxListWithScrollBar(self.ScrollBox, self.ScrollBar, view);
|
|
ScrollUtil.AddResizableChildrenBehavior(self.ScrollBox);
|
|
end
|
|
function BtWLoadoutsConduitListMixin:Init(owner, classID, covenantID)
|
|
if self.classID == classID and self.covenantID == covenantID then
|
|
return
|
|
end
|
|
|
|
self.owner = owner
|
|
self.classID = classID
|
|
self.covenantID = covenantID
|
|
|
|
local conduitTypes = {
|
|
Enum.SoulbindConduitType.Endurance,
|
|
Enum.SoulbindConduitType.Finesse,
|
|
Enum.SoulbindConduitType.Potency,
|
|
};
|
|
|
|
local listDatas = {};
|
|
for i, conduitType in ipairs(conduitTypes) do
|
|
local conduitDatas = GetConduitCollection(classID, covenantID, conduitType);
|
|
if #conduitDatas > 0 then
|
|
table.insert(listDatas, {conduitDatas = conduitDatas, conduitType = conduitType, collapsed = ConduitTypeCollapsed[conduitType]});
|
|
end
|
|
end
|
|
|
|
local dataProvider = CreateDataProvider(listDatas);
|
|
self.ScrollBox:SetDataProvider(dataProvider);
|
|
end
|
|
function BtWLoadoutsConduitListMixin:Update()
|
|
self.ScrollBox:ForEachFrame(function(list)
|
|
list:Update();
|
|
end);
|
|
end
|
|
|
|
BtWLoadoutsSoulbindNodeMixin = {}
|
|
function BtWLoadoutsSoulbindNodeMixin:Init(owner, node)
|
|
self.owner = owner
|
|
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:SetConduit(conduitID)
|
|
if conduitID and conduitID ~= 0 then
|
|
local conduit = GetConduitByID(conduitID)
|
|
|
|
local spellID = C_Soulbinds.GetConduitSpellID(conduit.conduitID, conduit.conduitRank)
|
|
self.Icon:SetTexture(GetSpellTexture(spellID))
|
|
self.Icon:Show()
|
|
|
|
self.conduit = conduit
|
|
else
|
|
self.Icon:SetShown(self.node.conduitType == nil)
|
|
|
|
self.conduit = nil
|
|
end
|
|
end
|
|
function BtWLoadoutsSoulbindNodeMixin:OnClick(button)
|
|
local node = self.node
|
|
|
|
if node.conduitType ~= nil then
|
|
local cursorType, itemID = GetCursorInfo()
|
|
local conduit = cursorType == "item" and GetConduitByItemID(itemID)
|
|
if conduit then
|
|
if conduit.conduitType == node.conduitType then
|
|
if self.owner:SetNodeConduit(node.ID, conduit.conduitID) then
|
|
ClearCursor()
|
|
end
|
|
-- self:SetConduit(node.ID)
|
|
end
|
|
return
|
|
end
|
|
end
|
|
if button == "LeftButton" then
|
|
self.owner:ToggleNode(node.ID)
|
|
else
|
|
if node.conduitType ~= nil then
|
|
self.owner:SetNodeConduit(node.ID, nil)
|
|
-- self:SetConduit(nil)
|
|
end
|
|
end
|
|
end
|
|
function BtWLoadoutsSoulbindNodeMixin:OnEnter()
|
|
self.MouseOverlay:Show();
|
|
if self.node.spellID ~= 0 then
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
|
|
GameTooltip:SetSpellByID(self.node.spellID);
|
|
GameTooltip:Show();
|
|
elseif self.conduit then
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
|
|
if IsModifiedClick("SHIFT") then
|
|
GameTooltip:SetEnhancedConduit(self.conduit.conduitID, self.conduit.conduitRank);
|
|
else
|
|
GameTooltip:SetConduit(self.conduit.conduitID, self.conduit.conduitRank);
|
|
end
|
|
GameTooltip:Show();
|
|
end
|
|
end
|
|
function BtWLoadoutsSoulbindNodeMixin:OnLeave()
|
|
self.MouseOverlay:Hide();
|
|
GameTooltip: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.tempConduits = {} -- Conduits for different classes for currently selected soulbind
|
|
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.SoulbindDropDown.GetValue = function ()
|
|
if self.set then
|
|
return self.set.soulbindID
|
|
end
|
|
end
|
|
self.SoulbindDropDown.SetValue = function (_, _, arg1)
|
|
CloseDropDownMenus();
|
|
|
|
local set = self.set;
|
|
if set then
|
|
local soulbindID = set.soulbindID
|
|
local classID = set.classID
|
|
|
|
local temp = self.temp;
|
|
local tempConduits = self.tempConduits
|
|
|
|
if classID then
|
|
if tempConduits[classID] then
|
|
wipe(tempConduits[classID]);
|
|
else
|
|
tempConduits[classID] = {};
|
|
end
|
|
for nodeID,conduitID in pairs(set.conduits) do
|
|
tempConduits[classID][nodeID] = conduitID
|
|
end
|
|
end
|
|
|
|
if temp[soulbindID] then
|
|
wipe(temp[soulbindID].nodes);
|
|
else
|
|
temp[soulbindID] = {nodes = {}};
|
|
end
|
|
for nodeID in pairs(set.nodes) do
|
|
temp[soulbindID].nodes[nodeID] = true;
|
|
end
|
|
temp[soulbindID].conduits = tempConduits
|
|
|
|
soulbindID = arg1;
|
|
set.soulbindID = soulbindID;
|
|
|
|
wipe(set.nodes);
|
|
wipe(set.conduits);
|
|
if temp[soulbindID] then
|
|
for nodeID in pairs(temp[soulbindID].nodes) do
|
|
set.nodes[nodeID] = true;
|
|
end
|
|
self.tempConduits = temp[soulbindID].conduits
|
|
if self.tempConduits[classID] then
|
|
for nodeID,conduitID in pairs(self.tempConduits[classID]) do
|
|
set.conduits[nodeID] = conduitID
|
|
end
|
|
end
|
|
else
|
|
self.tempConduits = {}
|
|
end
|
|
|
|
self:Update()
|
|
end
|
|
end
|
|
|
|
self.ClassDropDown.includeNone = true;
|
|
UIDropDownMenu_SetWidth(self.ClassDropDown, 203);
|
|
UIDropDownMenu_JustifyText(self.ClassDropDown, "LEFT");
|
|
|
|
self.ClassDropDown.GetValue = function ()
|
|
if self.set then
|
|
return self.set.classID
|
|
end
|
|
end
|
|
self.ClassDropDown.SetValue = function (_, _, arg1)
|
|
CloseDropDownMenus();
|
|
|
|
local set = self.set;
|
|
if set then
|
|
local classID = set.classID
|
|
|
|
local tempConduits = self.tempConduits
|
|
if classID then
|
|
if tempConduits[classID] then
|
|
wipe(tempConduits[classID]);
|
|
else
|
|
tempConduits[classID] = {};
|
|
end
|
|
for nodeID,conduitID in pairs(set.conduits) do
|
|
tempConduits[classID][nodeID] = conduitID;
|
|
end
|
|
end
|
|
|
|
classID = arg1
|
|
set.classID = classID
|
|
|
|
wipe(set.conduits);
|
|
if classID then
|
|
if tempConduits[classID] then
|
|
for nodeID,conduitID in pairs(tempConduits[classID]) do
|
|
set.conduits[nodeID] = conduitID;
|
|
end
|
|
end
|
|
end
|
|
|
|
self:Update()
|
|
end
|
|
end
|
|
|
|
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:SetSoulbind(soulbindID)
|
|
if self.soulbind and self.soulbind.ID == soulbindID then
|
|
return
|
|
end
|
|
|
|
local soulbind = GetSoulbindData(soulbindID)
|
|
local nodes = soulbind.tree.nodes
|
|
local nodesByID = {}
|
|
|
|
for _,node in ipairs(nodes) do
|
|
nodesByID[node.ID] = node
|
|
end
|
|
for _,node in ipairs(nodes) do
|
|
for _,parentID in ipairs(node.parentNodeIDs) do
|
|
local parent = nodesByID[parentID]
|
|
if not parent.childNodeIDs then
|
|
parent.childNodeIDs = {}
|
|
end
|
|
parent.childNodeIDs[#parent.childNodeIDs+1] = node.ID
|
|
end
|
|
end
|
|
|
|
soulbind.tree.nodesByID = nodesByID
|
|
|
|
self.soulbind = soulbind
|
|
end
|
|
function BtWLoadoutsSoulbindsMixin:GetSoulbind()
|
|
return self.soulbind
|
|
end
|
|
|
|
function BtWLoadoutsSoulbindsMixin:ToggleNode(nodeID)
|
|
local nodes = self.set and self.set.nodes
|
|
self:SetNodeEnabled(nodeID, not nodes[nodeID])
|
|
end
|
|
function BtWLoadoutsSoulbindsMixin:SetNodeEnabled(nodeID, enabled)
|
|
local set = self.set
|
|
if set then
|
|
local nodes = set.nodes
|
|
|
|
local soulbindData = self:GetSoulbind()
|
|
local nodesByID = soulbindData.tree.nodesByID
|
|
local targetNode = nodesByID[nodeID]
|
|
|
|
while targetNode.childNodeIDs and #targetNode.childNodeIDs == 1 do
|
|
local childID = targetNode.childNodeIDs[1]
|
|
local child = nodesByID[childID]
|
|
|
|
if #child.parentNodeIDs ~= 1 then
|
|
break
|
|
end
|
|
|
|
targetNode = child
|
|
end
|
|
|
|
if enabled then
|
|
for _,node in pairs(nodesByID) do
|
|
if node.row == targetNode.row then
|
|
nodes[node.ID] = nil
|
|
end
|
|
end
|
|
end
|
|
nodes[targetNode.ID] = enabled and true or nil
|
|
|
|
while #targetNode.parentNodeIDs == 1 do
|
|
local parentID = targetNode.parentNodeIDs[1]
|
|
targetNode = nodesByID[parentID]
|
|
|
|
if not targetNode.childNodeIDs or #targetNode.childNodeIDs ~= 1 then
|
|
break
|
|
end
|
|
|
|
if enabled then
|
|
for _,node in pairs(nodesByID) do
|
|
if node.row == targetNode.row then
|
|
nodes[node.ID] = nil
|
|
end
|
|
end
|
|
end
|
|
nodes[targetNode.ID] = enabled and true or nil
|
|
end
|
|
|
|
self:Update()
|
|
end
|
|
end
|
|
function BtWLoadoutsSoulbindsMixin:IsNodeEnabled(nodeID)
|
|
local nodes = self.set and self.set.nodes
|
|
return nodes[nodeID] and true or false
|
|
end
|
|
|
|
function BtWLoadoutsSoulbindsMixin:SetNodeConduit(nodeID, conduitID)
|
|
if not self.set or self.set.classID == nil then
|
|
return false
|
|
end
|
|
|
|
if conduitID ~= nil then
|
|
local conduit = GetConduitByID(conduitID)
|
|
if not CheckConduitClass(conduit, self.set.classID) then
|
|
return false
|
|
end
|
|
end
|
|
|
|
local conduits = self.set.conduits
|
|
for nodeID,nodeConduitID in pairs(conduits) do
|
|
if conduitID == nodeConduitID then
|
|
conduits[nodeID] = nil
|
|
end
|
|
end
|
|
conduits[nodeID] = conduitID
|
|
|
|
self:Update()
|
|
|
|
return true
|
|
end
|
|
function BtWLoadoutsSoulbindsMixin:IsConduitSlotted(conduitID)
|
|
local conduits = self.set and self.set.conduits
|
|
for _,nodeConduitID in pairs(conduits) do
|
|
if conduitID == nodeConduitID then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function BtWLoadoutsSoulbindsMixin:Update()
|
|
self:GetParent():SetTitle(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;
|
|
self:SetSoulbind(soulbindID)
|
|
local soulbindData = self:GetSoulbind()
|
|
|
|
UpdateSetFilters(set)
|
|
sidebar:Update()
|
|
|
|
set.restrictions = set.restrictions or {}
|
|
self.RestrictionsDropDown:SetSelections(set.restrictions)
|
|
self.RestrictionsDropDown:SetLimitations("class", set.classID)
|
|
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);
|
|
|
|
if not set.conduits then
|
|
set.conduits = {}
|
|
end
|
|
|
|
local selected = set.nodes;
|
|
local conduits = set.conduits;
|
|
|
|
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() + 24) - 17)
|
|
nodeFrame:Init(self, node)
|
|
nodeFrame:SetConduit(conduits[node.ID])
|
|
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]
|
|
|
|
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
|
|
|
|
if set.classID then
|
|
local classInfo = C_CreatureInfo.GetClassInfo(set.classID)
|
|
local classColor = C_ClassColor.GetClassColor(classInfo.classFile)
|
|
UIDropDownMenu_SetText(self.ClassDropDown, classColor:WrapTextInColorCode(classInfo.className));
|
|
else
|
|
UIDropDownMenu_SetText(self.ClassDropDown, L["None"]);
|
|
end
|
|
UIDropDownMenu_EnableDropDown(self.ClassDropDown);
|
|
self.ConduitList:Init(self, set.classID, soulbindData.covenantID)
|
|
self.ConduitList:Update()
|
|
|
|
local playerClassID = select(3, UnitClass("player"))
|
|
local playerCovenantID = GetActiveCovenantID()
|
|
local playerSoulbindID = GetActiveSoulbindID()
|
|
self:GetParent().RefreshButton:SetEnabled(soulbindID == playerSoulbindID)
|
|
self:GetParent().ActivateButton:SetEnabled(soulbindData.covenantID == playerCovenantID and soulbindData.unlocked and (set.classID == nil or set.classID == playerClassID));
|
|
|
|
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:Init(self, node)
|
|
nodeFrame:SetSelected(false)
|
|
nodeFrame:Show()
|
|
|
|
self.nodesByID[node.ID] = nodeFrame
|
|
end
|
|
|
|
local helpTipBox = self:GetParent().HelpTipBox;
|
|
helpTipBox:Hide();
|
|
end
|
|
end
|
|
function BtWLoadoutsSoulbindsMixin:SetEnabled(value)
|
|
BtWLoadoutsTabFrame_SetEnabled(self, value)
|
|
end
|
|
function BtWLoadoutsSoulbindsMixin:SetSetByID(setID)
|
|
self.set = GetSet(setID)
|
|
end
|
|
|