Skip to content

Commit a1da168

Browse files
committed
Add support for Generic Trait Trees (such as skyriding, D.R.I.V.E., and more)
1 parent c1b8306 commit a1da168

File tree

1 file changed

+161
-70
lines changed

1 file changed

+161
-70
lines changed

ResearchViewer.lua

Lines changed: 161 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,31 @@ local orderHalls = {
1919
["DEMONHUNTER"] = 125,
2020
}
2121

22+
local tocVersion = select(4, GetBuildInfo())
23+
2224
local increment = CreateCounter();
2325
ResearchViewer.talentTrees = {
26+
["The War Within"] = {
27+
order = increment(),
28+
tocVersion >= 110107 and { isTraitTree = true, id = 1061, name = GENERIC_TRAIT_FRAME_TITAN_CONSOLE_TITLE } or nil,
29+
{ isTraitTree = true, id = 1057, name = GENERIC_TRAIT_FRAME_VISIONS_TITLE },
30+
{ isTraitTree = true, id = 1056, name = GENERIC_TRAIT_FRAME_DRIVE_TITLE },
31+
{ isTraitTree = true, id = 1060, name = "Brann Delve Season 2" },
32+
{ isTraitTree = true, id = 1046, name = GENERIC_TRAIT_FRAME_THE_VIZIER_TITLE },
33+
{ isTraitTree = true, id = 1045, name = GENERIC_TRAIT_FRAME_THE_GENERAL_TITLE },
34+
{ isTraitTree = true, id = 1042, name = GENERIC_TRAIT_FRAME_THE_WEAVER_TITLE },
35+
{ isTraitTree = true, id = 1054, name = "??" },
36+
{ isTraitTree = true, id = 898, name = "??" },
37+
{ isTraitTree = true, id = 876, name = "??" },
38+
{ isTraitTree = true, id = 875, name = "??" },
39+
{ isTraitTree = true, id = 775, name = "??" },
40+
{ isTraitTree = true, id = 751, name = "??" },
41+
{ isTraitTree = true, id = 672, name = GENERIC_TRAIT_FRAME_DRAGONRIDING_TITLE },
42+
{ isTraitTree = true, id = 874, name = "Brann Delve Season 1" },
43+
},
2444
Dragonflight = {
2545
order = increment(),
46+
{ isTraitTree = true, id = 672, name = GENERIC_TRAIT_FRAME_DRAGONRIDING_TITLE },
2647
{ type = 111, id = 489, name = "Expedition Supplies" },
2748
{ type = 111, id = 493, name = "Cobalt Assembly Arcana" },
2849
{ type = 111, id = 486, name = "Select Your Companion" },
@@ -154,8 +175,24 @@ ResearchViewer.neverImplemented = {
154175
},
155176
}
156177

157-
EventUtil.ContinueOnAddOnLoaded(name, function()
158-
ResearchViewer:OnInitialize()
178+
local f = CreateFrame("Frame")
179+
f:RegisterEvent("ADDON_LOADED")
180+
f:SetScript("OnEvent", function(_, _, addonName)
181+
if addonName == name then
182+
ResearchViewer:OnInitialize()
183+
end
184+
if addonName == "Blizzard_OrderHallUI" then
185+
ResearchViewer:MakeDropDownButton(OrderHallTalentFrame)
186+
OrderHallTalentFrame:HookScript("OnHide", function()
187+
ResearchViewer.selectedTreeInfo = nil
188+
end)
189+
end
190+
if addonName == "Blizzard_GenericTraitUI" then
191+
ResearchViewer:MakeDropDownButton(GenericTraitFrame)
192+
GenericTraitFrame:HookScript("OnHide", function()
193+
ResearchViewer.selectedTreeInfo = nil
194+
end)
195+
end
159196
end)
160197

161198
function ResearchViewer:OnInitialize()
@@ -171,32 +208,32 @@ function ResearchViewer:OnInitialize()
171208
end
172209

173210
local original = C_Garrison.GetCurrentGarrTalentTreeID
174-
C_Garrison.GetCurrentGarrTalentTreeID = function()
175-
if ResearchViewer.selectedTreeInfo then return ResearchViewer.selectedTreeInfo.id end
211+
C_Garrison.GetCurrentGarrTalentTreeID = function() ---@diagnostic disable-line: duplicate-set-field
212+
if self.selectedTreeInfo then return self.selectedTreeInfo.id end
176213

177214
return original()
178215
end
179216

180217
local ResearchViewerLDB = LibStub("LibDataBroker-1.1"):NewDataObject(
181-
name,
182-
{
183-
type = "launcher",
184-
text = "Research Viewer",
185-
icon = "interface/icons/inv_misc_book_11.blp",
186-
OnClick = function()
187-
if IsShiftKeyDown() then
188-
ResearchViewer.db.ldbOptions.hide = true
189-
LibDBIcon:Hide(name)
190-
return
191-
end
192-
ResearchViewer:OpenResearchView()
193-
end,
194-
OnTooltipShow = function(tooltip)
195-
tooltip:AddLine("Research Viewer")
196-
tooltip:AddLine("|cffeda55fClick|r to view various research trees from the field.")
197-
tooltip:AddLine("|cffeda55fShift-Click|r to hide this button. ('/rv reset' to restore)")
198-
end,
199-
}
218+
name,
219+
{
220+
type = "launcher",
221+
text = "Research Viewer",
222+
icon = "interface/icons/inv_misc_book_11.blp",
223+
OnClick = function()
224+
if IsShiftKeyDown() then
225+
self.db.ldbOptions.hide = true
226+
LibDBIcon:Hide(name)
227+
return
228+
end
229+
self:OpenResearchView()
230+
end,
231+
OnTooltipShow = function(tooltip)
232+
tooltip:AddLine("Research Viewer")
233+
tooltip:AddLine("|cffeda55fClick|r to view various research/generic talent trees from the field.")
234+
tooltip:AddLine("|cffeda55fShift-Click|r to hide this button. ('/rv reset' to restore)")
235+
end,
236+
}
200237
)
201238
LibDBIcon:Register("ResearchViewer", ResearchViewerLDB, self.db.ldbOptions)
202239

@@ -233,34 +270,31 @@ function ResearchViewer:OnInitialize()
233270
-- the first time you get tree info after launching the game, it's very slow
234271
-- so instead of having a full second of lag when you open the research viewer,
235272
-- we'll just get the info now, and spread it out a bit over time
236-
local treeIds = self:GetTreeList()
237-
local treeIdList = {}
238-
for _, treeId in pairs(treeIds) do
239-
table.insert(treeIdList, treeId)
240-
end
273+
local treeIDList = GetValuesArray(self:GetTreeList())
241274
local ticker
242275
local i = 0
243276
ticker = C_Timer.NewTicker(0.2, function()
244277
i = i + 1
245-
local treeId = treeIdList[i]
246-
if not treeId then
278+
local treeID = treeIDList[i]
279+
if not treeID then
247280
ticker:Cancel()
248281
return
249282
end
250-
ResearchViewer:TreeExists(treeId)
283+
ResearchViewer:TreeExists(treeID)
251284
end)
252285
end
253286

287+
--- @return table<number, number>
254288
function ResearchViewer:GetTreeList(treeList, tables)
255289
treeList = treeList or {}
256290
tables = tables or { ni = self.neverImplemented, tt = self.talentTrees }
257291

258292
for key, value in pairs(tables) do
259-
if (type(key) == "number") then
260-
if value.id then
293+
if value and type(key) == "number" then
294+
if value.id and not value.isTraitTree then
261295
treeList[value.id] = value.id
262296
end
263-
elseif key ~= "order" then
297+
elseif value and key ~= "order" then
264298
self:GetTreeList(treeList, value)
265299
end
266300
end
@@ -279,11 +313,11 @@ function ResearchViewer:GetOrderedTreeIDs(list, subItems)
279313
local temp = {}
280314
local orderOffset = #subItems + 10
281315
for key, value in pairs(subItems) do
282-
if type(key) == "number" then
316+
if value and type(key) == "number" then
283317
if not value.special then
284318
table.insert(temp, { id = value.id, order = key })
285319
end
286-
elseif key ~= "order" then
320+
elseif value and key ~= "order" then
287321
table.insert(temp, { subItems = value, order = value.order + orderOffset })
288322
end
289323
end
@@ -316,11 +350,12 @@ function ResearchViewer:AlreadyAdded(textLine, tooltip)
316350
end
317351
end
318352

319-
function ResearchViewer:MakeDropDownButton()
320-
local dropdown = CreateFrame("DropdownButton", nil, OrderHallTalentFrame, "WowStyle1DropdownTemplate");
353+
--- @param parent GenericTraitFrame|OrderHallTalentFrame
354+
function ResearchViewer:MakeDropDownButton(parent)
355+
local dropdown = CreateFrame("DropdownButton", nil, parent, "WowStyle1DropdownTemplate");
321356

322-
dropdown:OverrideText("Select another Research tree")
323-
dropdown:SetWidth(230)
357+
dropdown:OverrideText("Select another tree")
358+
dropdown:SetWidth(165)
324359
dropdown:SetPoint("TOPRIGHT", 10, 20)
325360
dropdown:EnableMouseWheel(true)
326361
function dropdown:PickTreeID(treeID)
@@ -331,6 +366,7 @@ function ResearchViewer:MakeDropDownButton()
331366
end)
332367
end
333368
function dropdown:Increment()
369+
if not ResearchViewer.selectedTreeInfo then return end
334370
local currentTreeID = ResearchViewer.selectedTreeInfo.id
335371
local currentIndex = ResearchViewer.orderedTreeIDsMap[currentTreeID]
336372
local nextIndex = currentIndex + 1
@@ -340,6 +376,7 @@ function ResearchViewer:MakeDropDownButton()
340376
self:PickTreeID(ResearchViewer.orderedTreeIDs[nextIndex])
341377
end
342378
function dropdown:Decrement()
379+
if not ResearchViewer.selectedTreeInfo then return end
343380
local currentTreeID = ResearchViewer.selectedTreeInfo.id
344381
local currentIndex = ResearchViewer.orderedTreeIDsMap[currentTreeID]
345382
local nextIndex = currentIndex - 1
@@ -350,11 +387,9 @@ function ResearchViewer:MakeDropDownButton()
350387
end
351388

352389
dropdown:SetupMenu(function(_, rootDescription)
353-
self:GenerateMenu(rootDescription)
390+
self:GenerateMenu(rootDescription, parent)
354391
end)
355392

356-
dropdown:Hide()
357-
358393
if C_AddOns.IsAddOnLoaded("ElvUI") and ElvUI then
359394
ElvUI[1]:GetModule("Skins"):HandleDropDownBox(dropdown)
360395
end
@@ -364,25 +399,37 @@ end
364399

365400
function ResearchViewer:OpenResearchView()
366401
OrderHall_LoadUI()
367-
self.selectedTreeInfo = self.charDb and self.charDb.lastSelected or self.talentTrees.Shadowlands[1]
368-
self:OpenSelectedResearch()
402+
self.selectedTreeInfo = self.charDb and self.charDb.lastSelected or self.talentTrees['The War Within'][1] or self.talentTrees['The War Within'][2]
403+
if self.selectedTreeInfo.isTraitTree then
404+
self:OpenGenericTalentTree(self.selectedTreeInfo.id)
405+
else
406+
self:OpenSelectedResearch()
407+
end
369408
end
370409

371-
local hooked = false
372-
function ResearchViewer:OpenSelectedResearch()
373-
OrderHallTalentFrame:SetGarrisonType(self.selectedTreeInfo.type, self.selectedTreeInfo.id)
410+
function ResearchViewer:OpenGenericTalentTree(treeID)
374411
self.charDb.lastSelected = self.selectedTreeInfo
375-
ToggleOrderHallTalentUI()
376-
self.dropdownButton = self.dropdownButton or self:MakeDropDownButton()
377-
self.dropdownButton:Show()
378-
if not hooked then
379-
hooked = true
380-
OrderHallTalentFrame:HookScript("OnHide", function()
381-
ResearchViewer.selectedTreeInfo = nil
382-
end)
412+
local systemID = C_Traits.GetSystemIDByTreeID(treeID)
413+
414+
GenericTraitUI_LoadUI();
415+
GenericTraitFrame:Hide();
416+
GenericTraitFrame:SetSystemID(systemID);
417+
GenericTraitFrame:SetTreeID(treeID);
418+
ShowUIPanel(GenericTraitFrame);
419+
if GenericTraitFrame:GetNumPoints() == 0 then
420+
GenericTraitFrame:SetPoint('TOPLEFT', 16, -116); -- roughly where it would normally open
421+
end
422+
if not tIndexOf(UISpecialFrames, 'GenericTraitFrame') then
423+
table.insert(UISpecialFrames, 'GenericTraitFrame');
383424
end
384425
end
385426

427+
function ResearchViewer:OpenSelectedResearch()
428+
self.charDb.lastSelected = self.selectedTreeInfo
429+
OrderHallTalentFrame:SetGarrisonType(self.selectedTreeInfo.type, self.selectedTreeInfo.id)
430+
ShowUIPanel(OrderHallTalentFrame);
431+
end
432+
386433
local treeExistsCache = {}
387434
function ResearchViewer:TreeExists(treeId)
388435
if treeExistsCache[treeId] ~= nil then
@@ -396,23 +443,51 @@ function ResearchViewer:TreeExists(treeId)
396443
return exists
397444
end
398445

446+
function ResearchViewer:TraitTreeExists(treeId)
447+
return not not C_Traits.GetConfigIDByTreeID(treeId)
448+
end
449+
399450
--- @param rootDescription RootMenuDescriptionProxy
400-
function ResearchViewer:GenerateMenu(rootDescription)
451+
--- @param owner GenericTraitFrame|OrderHallTalentFrame
452+
function ResearchViewer:GenerateMenu(rootDescription, owner)
401453
if not self.orderedTreeIDs then
402454
self.orderedTreeIDs = self:GetOrderedTreeIDs()
403455
self.orderedTreeIDsMap = tInvert(self.orderedTreeIDs)
404456
end
405457
local function openTree(data)
406-
ToggleOrderHallTalentUI()
458+
HideUIPanel(owner)
459+
460+
self.selectedTreeInfo = data
461+
if data.isTraitTree then
462+
HideUIPanel(GenericTraitFrame)
407463

408-
ResearchViewer.selectedTreeInfo = data
409-
ResearchViewer:OpenSelectedResearch()
464+
self:OpenGenericTalentTree(data.id)
465+
else
466+
HideUIPanel(OrderHallTalentFrame)
467+
468+
self:OpenSelectedResearch()
469+
end
410470
end
411471
local function isSelected(data)
412-
return data[self.selectedTreeInfo.id] or (data.id == self.selectedTreeInfo.id and data.type == self.selectedTreeInfo.type)
472+
if self.selectedTreeInfo then
473+
return
474+
data[(self.selectedTreeInfo.isTraitTree and 'T' or 'R') .. self.selectedTreeInfo.id]
475+
or (
476+
data.id == self.selectedTreeInfo.id
477+
and (data.type == self.selectedTreeInfo.type or data.isTraitTree == self.selectedTreeInfo.isTraitTree)
478+
)
479+
elseif owner == GenericTraitFrame and GenericTraitFrame:GetTalentTreeID() then
480+
return
481+
data.isTraitTree and data.id == GenericTraitFrame:GetTalentTreeID()
482+
or (
483+
data['T' .. GenericTraitFrame:GetTalentTreeID()]
484+
)
485+
end
486+
487+
return false
413488
end
414489

415-
rootDescription:CreateTitle('Select another Research tree')
490+
rootDescription:CreateTitle('Select another tree')
416491
self:GenerateSubMenuButtons(rootDescription, self.talentTrees, isSelected, openTree)
417492
local neverImplementedData = {}
418493
local neverImplemented = rootDescription:CreateRadio("Never Implemented", isSelected, openTree, neverImplementedData)
@@ -425,16 +500,20 @@ end
425500
--- @param isSelectedFunc fun(data: any): boolean
426501
function ResearchViewer:GenerateSubMenuButtons(parentDescription, list, isSelectedFunc, setValueFunc, parentDataTables)
427502
local orderedList = {}
503+
local notAvailableList = {}
428504
local orderOffset = #list + 10
429505
for key, value in pairs(list) do
430506
if type(key) == "number" then
431-
local treeExists = self:TreeExists(value.id)
432-
table.insert(orderedList, {
433-
name = ("%s (%d%s)"):format(value.name, value.id, (treeExists and '' or ' - not available')),
434-
order = key,
435-
value = value,
436-
isTree = true,
437-
})
507+
local treeExists = (value.isTraitTree and self:TraitTreeExists(value.id)) or (not value.isTraitTree and self:TreeExists(value.id))
508+
table.insert(
509+
treeExists and orderedList or notAvailableList,
510+
{
511+
name = ("%s (%s%d%s)"):format(value.name, (value.isTraitTree and 'T' or 'R'), value.id, (treeExists and '' or ' - not available')),
512+
order = key,
513+
value = value,
514+
isTree = true,
515+
}
516+
)
438517
elseif key ~= "order" then
439518
table.insert(orderedList, { name = key, order = value.order + orderOffset, value = value, isTree = false })
440519
end
@@ -447,7 +526,7 @@ function ResearchViewer:GenerateSubMenuButtons(parentDescription, list, isSelect
447526
data = entry.value
448527
if parentDataTables then
449528
for _, parentData in ipairs(parentDataTables) do
450-
parentData[entry.value.id] = true
529+
parentData[(entry.value.isTraitTree and 'T' or 'R') .. entry.value.id] = true
451530
end
452531
end
453532
else
@@ -460,4 +539,16 @@ function ResearchViewer:GenerateSubMenuButtons(parentDescription, list, isSelect
460539
self:GenerateSubMenuButtons(subMenuButton, entry.value, isSelectedFunc, setValueFunc, dataTables)
461540
end
462541
end
542+
if next(notAvailableList) then
543+
local dataTables = CreateFromMixins(parentDataTables or {})
544+
local data = {}
545+
table.insert(dataTables, data)
546+
local subParent = parentDescription:CreateRadio("Not Available", isSelectedFunc, setValueFunc, data)
547+
for _, entry in ipairs(notAvailableList) do
548+
subParent:CreateRadio(entry.name, isSelectedFunc, setValueFunc, entry.value)
549+
for _, parentData in ipairs(dataTables) do
550+
parentData[(entry.value.isTraitTree and 'T' or 'R') .. entry.value.id] = true
551+
end
552+
end
553+
end
463554
end

0 commit comments

Comments
 (0)