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.

472 lines
17 KiB

--lua
local unpack, select, pairs, wipe, type, tContains, tinsert, tremove, tsort, tconcat
= unpack, select, pairs, wipe, type, tContains, table.insert, table.remove, table.sort, table.concat
--WoW API
local GetGuildInfo, GuildControlSetRank, GuildControlGetRankFlags, GetUnitName, GetItemInfoFromHyperlink, SendChatMessage, GetInventorySlotInfo, GetSpecializationInfo, GetChannelList, EnumerateServerChannels, IsInGroup, IsInGuild, UnitInRaid
= GetGuildInfo, GuildControlSetRank, GuildControlGetRankFlags, GetUnitName, GetItemInfoFromHyperlink, SendChatMessage, GetInventorySlotInfo, GetSpecializationInfo, GetChannelList, EnumerateServerChannels, IsInGroup, IsInGuild, UnitInRaid
local BestInSlot, L, AceGUI = unpack(select(2, ...))
local Overview = BestInSlot:GetMenuPrototype(L["Overview"])
local selectedReport, selectedChannel
local dropdownDungeon, dropdownDifficulty, dropdownReport, dropdownFilter
local reportButton
local contentContainer
local hasContent
local requiredItems = {}
local processedItems
local bossLootGroups
local misc
local customitems
local specFilter
local showObtainedOnly = true
Overview.Width = 700
Overview.Height = 600
--TODO: GuildControlSetRank() protected function since 7.3. return put to false until workaround.
function Overview:IsOfficer()
--local rank = select(3, GetGuildInfo("player"))
--rank = rank + 1
--GuildControlSetRank(rank)
--local officer = select(3, GuildControlGetRankFlags())
local officer = false
return officer
end
local function tableSize(table)
local size = 0
for _ in pairs(table) do
size = size + 1
end
if size == 0 then size = nil end
return size
end
function Overview:ReportRequiredItems()
local selectedDungeon = self:GetSelected(self.INSTANCE)
local selectedDifficulty = self:GetSelected(self.DIFFICULTY)
local playerName = GetUnitName("player")
local notAcquiredItems = {}
for i=1,#requiredItems do
if #requiredItems[i] > 0 then
for j=1,#requiredItems[i] do
if not self:HasItem(requiredItems[i][j], selectedDifficulty) then
if not notAcquiredItems[i] then
notAcquiredItems[i] = {}
end
tinsert(notAcquiredItems[i], self:GetItem(GetItemInfoFromHyperlink(requiredItems[i][j]), id, selectedDifficulty).link)
end
end
end
end
local str = {}
for i,list in pairs(notAcquiredItems) do
local bossName = self:GetDescription(self.BOSS, selectedDungeon, i)
str[#str+1] = bossName
for j=1,#list do
if (#list[j] + #str[#str]) > 250 then
str[#str + 1] = bossName..": "..list[j]
else
if j == 1 then
str[#str] = str[#str]..": "..list[j]
else
str[#str] = str[#str].." & "..list[j]
end
end
end
end
if not tableSize(notAcquiredItems) then
SendChatMessage(
(L["%1$s needs nothing from %2$s %3$s"]):format(
playerName,
self:GetDescription(self.INSTANCE, selectedDungeon),
self:GetDifficulties(self.INSTANCE, selectedDungeon)[selectedDifficulty]
),
selectedReport, nil, selectedChannel
)
else
--local bislink = self:GetModule("BiSLink")
local msg
--if bislink:IsEnabled() then
-- msg = bislink:GetShareLink(playerName, self.INSTANCE, selectedDungeon, selectedDifficulty, self:GetSelected(self.SPECIALIZATION))
--else
msg = (L["%1$s needs the following bosses from %2$s %3$s"]):format(
playerName,
self:GetDescription(self.INSTANCE, selectedDungeon),
self:GetDifficulties(self.INSTANCE, selectedDungeon)[selectedDifficulty]
)
--end
SendChatMessage(msg, selectedReport, nil, selectedChannel)
for i=1,#str do
SendChatMessage(str[i], selectedReport, nil, selectedChannel)
end
end
end
local function count(table)
local counter = 0
for _, v in pairs(table) do
if v then
counter = counter + 1
end
end
return counter
end
function Overview:CheckSlotData(bisList, slotId, selectedDungeon, selectedRaidTier, selectedDifficulty, specName)
if bisList[slotId] and type(bisList[slotId].item) == "number" then
local id = bisList[slotId].item
local hasItem = self:HasItem(id, selectedDifficulty, true)
local hasItemOnHigherDifficulty = hasItem and hasItem > selectedDifficulty
local item = self:GetItem(id)
if not showObtainedOnly or not hasItem then
if item then
local bosses
if item.multiplesources and item.multiplesources[selectedDungeon] then
for bossid in pairs(item.multiplesources[selectedDungeon]) do
bosses = bossid
break
end
elseif item.dungeon == selectedDungeon then
bosses = item.bossid
end
if bosses or item.misc or item.customitem then
local label = processedItems[item.itemid] or self:GetItemLinkLabel(id, selectedDifficulty)
local udt = label:GetUserDataTable()
local specs = udt.specs or {}
local firstLabel = #specs == 0
if not tContains(specs, specName) then
specs[#specs+1] = specName
end
udt.specs = specs
label:SetFullWidth(true)
label:SetFont(GameFontNormalSmall:GetFont(), 14, nil)
local text = item.link
if count(specFilter) ~= 1 then
text = ("%s (%s)"):format(text, tconcat(specs, "/"))
end
if hasItemOnHigherDifficulty then
text = ("%s - %s"):format(text, (L["You have this item on '%s'"]):format(self:GetDescription(self.DIFFICULTY, selectedDungeon, hasItem)))
elseif hasItem then
text = ("%s - %s"):format(text, L["You have this item"])
end
label:SetText(text)
if firstLabel then
if bosses then
local bossGroup = bossLootGroups[bosses]
bossGroup:AddChild(label)
tinsert(requiredItems[bosses], item.link)
elseif item.misc then
misc = misc or {}
if not misc[item.misc] then misc[item.misc] = {} end
tinsert(misc[item.misc], label)
elseif item.customitem then
customitems = customitems or {}
tinsert(customitems, label)
end
processedItems[item.itemid] = label
end
end
end
end
end
end
function Overview:UpdateContent()
local selectedDungeon = self:GetSelected(self.INSTANCE)
local selectedRaidTier = self:GetSelected(self.RAIDTIER)
local selectedDifficulty = self:GetSelected(self.DIFFICULTY)
wipe(requiredItems)
contentContainer:ReleaseChildren()
local bossList = self:GetInstanceBosses(selectedDungeon)
local difficulties = self:GetDifficulties(self.INSTANCE, selectedDungeon)
bossLootGroups = {}
for i=1,#bossList do
local bossGroup = AceGUI:Create("SimpleGroup")
bossGroup:SetFullWidth(true)
bossGroup:SetLayout("Flow")
local label = AceGUI:Create("Heading")
label:SetFullWidth(true)
label:SetText(bossList[i])
bossGroup:AddChild(label)
tinsert(bossLootGroups, bossGroup)
requiredItems[i] = {}
end
misc = nil
customitems = nil
local slots = self.slots
local specs = self:GetCustomLists(self:GetAllSpecializations())
processedItems = {}
for specId, specName in pairs(specs) do
local list = specId
local bisList = self:GetOrderedBestInSlotItems(selectedRaidTier, selectedDifficulty, list)
if type(specId) == "string" then
specId = specName
specName = list
end
if count(specFilter) == 0 or specFilter[list] then
for i=1,#slots do
local slotId = GetInventorySlotInfo(slots[i])
self:CheckSlotData(bisList, slotId, selectedDungeon, selectedRaidTier, selectedDifficulty, specName)
end
if selectedRaidTier >= 70000 and selectedRaidTier < 80000 and self.Artifacts then
local artifactBis = {self.Artifacts:GetBestInSlotRelics(selectedRaidTier, selectedDifficulty, specId)}
local formattedList = {}
for i=1,3 do
formattedList[29 + i] = {item = artifactBis[i]}
end
for i=1,3 do
self:CheckSlotData(formattedList, 29 + i, selectedDungeon, selectedRaidTier, selectedDifficulty, specName)
end
end
end
end
for i=#bossLootGroups,1, -1 do
if #bossLootGroups[i].children == 1 then --When it only has the boss label, thus no loot
bossLootGroups[i]:Release()
tremove(bossLootGroups, i)
end
end
if #bossLootGroups == 0 and not misc then
local label = AceGUI:Create("Label")
label:SetFullWidth(true)
label:SetFont(GameFontNormalSmall:GetFont(), 14, nil)
label:SetText(
"\n"..L["It looks like this instance does not drop any of your BestInSlot items."].."\n"..
"\n"..L["It could also be that you haven't set the BestInSlot for this raid tier yet"].."\n"..
"\n"..L["You can use the BiS Manager on the left to set your BestInSlot"]
)
hasContent = false
reportButton:SetDisabled(true)
contentContainer:AddChild(label)
else
hasContent = true
if selectedReport then
reportButton:SetDisabled(false)
end
for i=1,#bossLootGroups do
contentContainer:AddChild(bossLootGroups[i])
end
if misc then
for miscDesc, labels in pairs(misc) do
local miscgroup = AceGUI:Create("SimpleGroup")
miscgroup:SetFullWidth(true)
miscgroup:SetLayout("Flow")
local header = AceGUI:Create("Heading")
header:SetText(miscDesc)
header:SetFullWidth(true)
miscgroup:AddChild(header)
for i=1,#labels do
miscgroup:AddChild(labels[i])
end
contentContainer:AddChild(miscgroup)
end
end
if customitems then
local customItemGroup = AceGUI:Create("SimpleGroup")
customItemGroup:SetFullWidth(true)
customItemGroup:SetLayout("Flow")
local header = AceGUI:Create("Heading")
header:SetText(L["Custom Items"])
header:SetFullWidth(true)
customItemGroup:AddChild(header)
for i=1,#customitems do
customItemGroup:AddChild(customitems[i])
end
contentContainer:AddChild(customItemGroup)
end
self:ShowTutorial(L["Overview"], 1)
end
end
local function dropdownDungeonOnValueChanged(widget,_,value)
local selectedDungeon = value
Overview:UpdateContent()
end
local function dropdownDifficultyOnValueChanged(_,_,value)
Overview:SetSelected(Overview.DIFFICULTY, value)
local raidTier = Overview:GetSelected(Overview.RAIDTIER)
Overview:UpdateContent()
end
local function dropdownFilterOnValueChanged(widget,event, spec, value)
if spec ~= 'obtainedOnly' then
specFilter[spec] = value
else
showObtainedOnly = value
end
Overview:UpdateContent()
end
local function packChannels(...)
local channels = {...}
local result = {}
for i=1,#channels do
local id = channels[i]
i = i + 1
local name = channels[i]
result[i] = name
end
return result
end
local function packGlobalChannels(...)
return {...}
end
function Overview:Draw(container)
container:PauseLayout()
specFilter = self.db.char.options.overviewfilter
dropdownDungeon = self:GetDropdown(self.INSTANCE, nil, dropdownDungeonOnValueChanged)
dropdownDungeon:SetPoint("TOPLEFT", container.frame, "TOPLEFT", 10, -10)
container:AddChild(dropdownDungeon)
dropdownDifficulty = self:GetDropdown(self.DIFFICULTY, nil, dropdownDifficultyOnValueChanged)
dropdownDifficulty:SetPoint("TOPLEFT", dropdownDungeon.frame, "TOPRIGHT")
dropdownDifficulty:SetWidth(120)
dropdownDifficulty:SetCallback("OnValueChanged", dropdownDifficultyOnValueChanged)
container:AddChild(dropdownDifficulty)
dropdownFilter = AceGUI:Create("Dropdown")
dropdownFilter:SetList({})
local specs = self:GetAllSpecializations()
local customLists, hasCustomLists = self:GetCustomLists()
if hasCustomLists then
dropdownFilter:AddItem("header1", L["Specialization"])
dropdownFilter:SetItemDisabled("header1")
end
for k,v in pairs(specs) do
dropdownFilter:AddItem(k,v)
end
if hasCustomLists then
dropdownFilter:AddItem("spacer3", "")
dropdownFilter:AddItem("header2", L["Custom Lists"])
dropdownFilter:SetItemDisabled("spacer3", true)
dropdownFilter:SetItemDisabled("header2", true)
for k,v in pairs(customLists) do
dropdownFilter:AddItem(k, k)
end
end
dropdownFilter:AddItem("spacer", "")
dropdownFilter:AddItem("obtainedOnly", L["Only show missing items"])
dropdownFilter:AddItem("spacer2", "")
dropdownFilter:SetItemDisabled("spacer", true)
dropdownFilter:SetItemDisabled("spacer2", true)
dropdownFilter:SetMultiselect(true)
dropdownFilter:SetItemValue('obtainedOnly', showObtainedOnly)
dropdownFilter:SetItemDisabled('spacer', true)
dropdownFilter:SetItemDisabled('spacer2', true)
if hasCustomLists then
dropdownFilter:SetItemDisabled("header1", true)
dropdownFilter:SetItemDisabled("header2", true)
dropdownFilter:SetItemDisabled("spacer3", true)
end
if count(specFilter) == 0 then
local filter = GetSpecializationInfo(self:GetSpecialization())
dropdownFilter:SetItemValue(filter, true)
specFilter[filter] = true
else
for specId in pairs(specFilter) do
if specFilter[specId] then
dropdownFilter:SetItemValue(specId, true)
end
end
end
dropdownFilter:SetLabel(FILTER) -- Blizzard global string
dropdownFilter:SetPoint("TOPLEFT", dropdownDifficulty.frame, "TOPRIGHT")
dropdownFilter:SetPoint("TOPRIGHT", container.frame, "TOPRIGHT", -10, -10)
dropdownFilter:SetCallback("OnValueChanged", dropdownFilterOnValueChanged)
container:AddChild(dropdownFilter)
container:SetUserData("filter", dropdownFilter)
contentContainer = AceGUI:Create("ScrollFrame")
contentContainer:SetPoint("TOPLEFT", dropdownDungeon.frame, "BOTTOMLEFT")
contentContainer:SetPoint("BOTTOMRIGHT", container.frame, "BOTTOMRIGHT", -10, 50)
contentContainer:SetLayout("List")
container:AddChild(contentContainer)
dropdownReport = AceGUI:Create("Dropdown")
dropdownReport:SetPoint("TOPLEFT", contentContainer.frame, "BOTTOMLEFT")
dropdownReport:SetLabel(L["Report your BestInSlot to:"])
dropdownReport:SetText(L["Select an option"])
local dropdownList = {
SAY = _G["SAY"],
PARTY = _G["PARTY"],
GUILD = _G["GUILD"],
OFFICER = _G["OFFICER"],
RAID = _G["RAID"],
INSTANCE_CHAT = _G["INSTANCE_CHAT"]
}
dropdownReport:SetList(dropdownList)
local channels = packChannels(GetChannelList())
local globalchannels = packGlobalChannels(EnumerateServerChannels())
for i=1,#channels / 2 do
local id = channels[(i * 2) - 1]
local name = channels[i * 2]
if id and name and not tContains(globalchannels, name) then
dropdownReport:AddItem("channel"..id, name)
end
end
if not IsInGroup() then
dropdownReport:SetItemDisabled("PARTY", true)
end
if not IsInGuild() then
dropdownReport:SetItemDisabled("GUILD", true)
dropdownReport:SetItemDisabled("OFFICER", true)
elseif not self:IsOfficer() then
dropdownReport:SetItemDisabled("OFFICER", true)
end
if not UnitInRaid("player") then
dropdownReport:SetItemDisabled("RAID", true)
end
if not IsInGroup(LE_PARTY_CATEGORY_INSTANCE) then
dropdownReport:SetItemDisabled("INSTANCE_CHAT", true)
end
if selectedReport then
dropdownReport:SetValue(selectedReport)
end
dropdownReport:SetCallback("OnValueChanged", function(_,_, value)
if value:find("channel") then
selectedReport = "CHANNEL"
selectedChannel = value:sub(8)
else
selectedReport = value
selectedChannel = nil
end
if hasContent then
reportButton:SetDisabled(false)
end
end)
container:SetUserData("report", dropdownReport)
container:AddChild(dropdownReport)
reportButton = AceGUI:Create("Button")
reportButton:SetText(L["Report BestInSlot"])
reportButton:SetDisabled(selectedReport == nil)
reportButton:SetPoint("BOTTOMLEFT", dropdownReport.frame, "BOTTOMRIGHT")
reportButton:SetCallback("OnClick", function() Overview:ReportRequiredItems() end)
container:AddChild(reportButton)
local raidTier = self:GetSelected(self.RAIDTIER)
Overview:UpdateContent()
end
function Overview:Close()
dropdownDungeon, dropdownDifficulty, dropdownReport, dropdownFilter = nil
reportButton = nil
contentContainer = nil
hasContent = nil
wipe(requiredItems)
end
Overview:RegisterTutorials(L["Overview"], {
[1] = {text = L["On this page you can overview your BestInSlot list per instance."], xOffset = 0, yOffset = -50, container = "content", onRequest = true},
[2] = {text = L["The filter is set to only show the items you have not obtained yet. You can also make multiple specializations appear here."], xOffset = 0, yOffset = -25, container = "content", element = "filter", UpArrow = true},
[3] = {text = L["If you want to share your BestInSlot list, you can report it here."], text2 = L["Note: This could send a long list of items depending on the amount of items you still need, and might be considered spam."], xOffset = 0, yOffset = 25, container = "content", element = "report", DownArrow = true}
})