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.

525 lines
20 KiB

--lua
local unpack, select, type, pairs, tContains, wipe, tinsert, tsort
= unpack, select, type, pairs, tContains, wipe, table.insert, table.sort
-- WoW Api
local GetGuildInfo, GetItemInfo, GetItemInfoFromHyperlink, GetItemIcon, GetOSLocale, GetNumSpecializationsForClassID, GetSpecializationInfoForClassID, GetInventorySlotInfo, IsInGuild, CreateFrame, StaticPopup_Show, EasyMenu
= GetGuildInfo, GetItemInfo, GetItemInfoFromHyperlink, GetItemIcon, GetOSLocale, GetNumSpecializationsForClassID, GetSpecializationInfoForClassID, GetInventorySlotInfo, IsInGuild, CreateFrame, StaticPopup_Show, EasyMenu
local BestInSlot, L, AceGUI = unpack(select(2, ...))
local GuildLists = BestInSlot:GetMenuPrototype(L["Guild BiS lists"])
local dropdownRaidTier, dropdownDifficulty, dropdownFilter, contentPanel
local selectedCharacter, selectedSort
local itemGroups = {}
local SORT_NAME, SORT_CLASS, SORT_GUILDRANKS = NAME, CLASS, GUILDCONTROL_GUILDRANKS
GuildLists.Height = function() if GuildLists.Artifacts then return 650 else return 600 end end
GuildLists.Width = 800
local classIds = {
WARRIOR = 1,
PALADIN = 2,
HUNTER = 3,
ROGUE = 4,
PRIEST = 5,
DEATHKNIGHT = 6,
SHAMAN = 7,
MAGE = 8,
WARLOCK = 9,
MONK = 10,
DRUID = 11,
DEMONHUNTER = 12,
}
local function deleteCachedData(dialog, character, table)
if type(table) ~= "table" or type(character) ~= "string" then return end
local guildCache = GuildLists.db.factionrealm[GetGuildInfo("player")]
if table.all then
guildCache[character] = nil
elseif table.spec then
guildCache[character][table.raidtier][table.difficulty][table.spec] = nil
elseif table.difficulty then
guildCache[character][table.raidtier][table.difficulty] = nil
elseif table.raidtier then
guildCache[character][table.raidtier] = nil
end
GuildLists:SendEvent("GuildCacheUpdated")
GuildLists:GeneratePlayerScrollContainer()
end
local function confirmDeletion(dialog, arg1, arg2)
local popup = StaticPopup_Show("BESTINSLOT_CONFIRMDELETECACHE", dialog.value)
popup:SetFrameStrata("TOOLTIP")
popup.data = arg1
popup.data2 = arg2
end
local function showHistory(dailog, character, data)
local raidtier = data.raidtier
local difficulty = data.difficulty
GuildLists:SetMenu(GuildLists.History.menuid, character, raidtier, difficulty)
end
local function GeneratePlayerScrollContainer()
GuildLists:GeneratePlayerScrollContainer()
end
function GuildLists:GetContextMenu(character, spec)
local menu = {}
local raidTier = dropdownRaidTier:GetValue()
local difficulty = dropdownDifficulty:GetValue()
if self.History:HasHistory(character, raidTier, difficulty) then
tinsert(menu, {text = L["Show history for %s"]:format(character), func = showHistory, arg1 = character, arg2 = {raidtier = raidTier, difficulty = difficulty}})
else
tinsert(menu, {text = L["There is no history available for %s"]:format(character), disabled = true})
end
tinsert(menu, {text = L["Delete options"], isTitle = true})
if spec ~= nil then
tinsert(menu, { text = L["Delete this specialization from this raid tier"], func = confirmDeletion, arg1 = character, arg2 = {raidtier = raidTier, difficulty = difficulty, spec = spec} })
end
tinsert(menu, {text = L["Delete %s from this difficulty"]:format(character), func = confirmDeletion, arg1 = character, arg2 = {raidtier = raidTier, difficulty = difficulty}})
tinsert(menu, { text = L["Delete %s from this raidtier"]:format(character), func = confirmDeletion, arg1 = character, arg2 = {raidtier = raidTier}})
tinsert(menu, { text = L["Delete %s completely."]:format(character), func = confirmDeletion, arg1 = character, arg2 = {all = true}})
tinsert(menu, { text = CLOSE})
if not self.dialog then
self.dialog = CreateFrame("Frame", "BiSGuildListDialog", UIParent, "UIDropDownMenuTemplate")
self.dialog:SetFrameStrata("TOOLTIP")
end
-- Make the menu appear at the cursor:
EasyMenu(menu, self.dialog, "cursor", 0 , 0, "MENU")
self.dialog:Show()
end
function GuildLists:SetCustomItem(itemlink, specId)
if not self.processedSlots then return end
local _, link, _, _, _, _, _, _, equipSlot, texture = GetItemInfo(itemlink)
local slotId, slotId2 = self:GetItemSlotID(equipSlot, specId)
if slotId2 and tContains(self.processedSlots, slotId) then
slotId = slotId2
end
local label = itemGroups[slotId]:GetUserData("label")
local icon = itemGroups[slotId]:GetUserData("icon")
label:SetText(link)
label:SetUserData("itemid", GetItemInfoFromHyperlink(link))
label:SetUserData("itemlink", link)
label:SetUserData("difficulty", 1)
icon:SetImage(texture)
tinsert(self.processedSlots, slotId)
end
function GuildLists:FillItemGroupsForSpec(specId)
if not selectedCharacter then self.console:AddError("Selected Character variable is not set!") return end
local difficulty = dropdownDifficulty:GetValue()
local BiSList = selectedCharacter[specId]
self.processedSlots = {}
local selectedRaidTier = self:GetSelected(self.RAIDTIER)
if selectedRaidTier >= 70000 and selectedRaidTier < 80000 and self.Artifacts then
local artMH, artOH = self.Artifacts:ForSpecialization(specId)
local label = itemGroups[16]:GetUserData("label")
local icon = itemGroups[16]:GetUserData("icon")
label:SetText(artMH.link)
label:SetUserData("itemid", artMH.id)
label:SetUserData("itemlink", artMH.link)
icon:SetImage(artMH.texture)
tinsert(self.processedSlots, 16)
if artOH then
local label = itemGroups[17]:GetUserData("label")
local icon = itemGroups[17]:GetUserData("icon")
label:SetText(artOH.link)
label:SetUserData("itemid", artOH.id)
label:SetUserData("itemlink", artOH.link)
icon:SetImage(artOH.texture)
tinsert(self.processedSlots, 17)
end
end
for i in pairs(BiSList) do
if not BiSList[i].customitem then
local item = self:GetItem(BiSList[i].item, difficulty)
if item ~= nil then
local slotId, slotId2 = self:GetItemSlotID(item.equipSlot, specId)
if slotId2 and tContains(self.processedSlots, slotId) then
slotId = slotId2
end
if not slotId then
slotId = i
end
local label = itemGroups[slotId]:GetUserData("label")
local icon = itemGroups[slotId]:GetUserData("icon")
label:SetText(item.link)
label:SetUserData("itemid", item.itemid)
label:SetUserData("itemlink", item.link)
label:SetUserData("difficulty", difficulty)
icon:SetImage(GetItemIcon(item.itemid))
tinsert(self.processedSlots, slotId)
end
else
local name = GetItemInfo(BiSList[i].item)
if not name then
local eventId = self:RegisterEvent("GET_ITEM_INFO_RECEIVED", function(_, itemid)
if BiSList[i].item == itemid then
GuildLists:SetCustomItem(BiSList[i].customitem, specId)
end
end)
C_Timer.NewTimer(0.5, function() self:UnregisterEvent("GET_ITEM_INFO_RECEIVED", eventId) end)
else
GuildLists:SetCustomItem(BiSList[i].customitem, specId)
end
end
end
for slotId, itemGroup in pairs(itemGroups) do
local processed = false
for i=1,#self.processedSlots do
if slotId == self.processedSlots[i] then
processed = true
break
end
end
if not processed then
local label = itemGroups[slotId]:GetUserData("label")
local icon = itemGroups[slotId]:GetUserData("icon")
label:SetText("")
label:SetUserData("itemid", nil)
label:SetUserData("itemlink", nil)
label:SetUserData("difficulty", nil)
icon:SetImage(unpack(icon:GetUserData("default")))
end
end
end
local function setRelicDefaults(specId)
local relics = GuildLists.Artifacts:GetRelicsForSpecialization(specId)
local texture = GuildLists.Artifacts:GetTexture()
for i=1,3 do
local itemGroup = itemGroups[i+29]
if itemGroup then
local icon = itemGroup:GetUserData("icon")
local relicCoords = GuildLists.Artifacts:GetTextureCoordinatesForRelic(relics[i])
icon:SetUserData("default", {texture, unpack(relicCoords)})
end
end
end
local function specIconOnClick(icon, event, button)
if button == "LeftButton" then
local selectedSpec = icon:GetUserData("specid")
if GuildLists.Artifacts then
setRelicDefaults(selectedSpec)
end
GuildLists:FillItemGroupsForSpec(selectedSpec)
elseif button == "RightButton" then
GuildLists:GetContextMenu(icon:GetUserData("player"), icon:GetUserData("specid"))
end
end
function GuildLists:GetOrderTable(players)
local order = selectedSort or SORT_NAME
local sorted = {}
for k in pairs(players) do
sorted[#sorted + 1] = k
end
if order == SORT_NAME then return self:GetNameOrder(sorted) end
if order == SORT_CLASS then return self:GetClassOrder(sorted) end
if order == SORT_GUILDRANKS then return self:GetGuildRankOrder(sorted) end
end
local function indexOfValue(tbl, value)
for k, v in pairs(tbl) do
if v == value then return k end
end
end
function GuildLists:GetNameOrder(players)
tsort(players)
return players
end
function GuildLists:GetClassOrder(players)
local function sort(a, b)
local indexA = indexOfValue(CLASS_SORT_ORDER, self:GetPlayerClass(a)) or -1
local indexB = indexOfValue(CLASS_SORT_ORDER, self:GetPlayerClass(b)) or -1
if indexA == -1 then return true
elseif indexB == -1 then return false end
local indexDif = indexA - indexB
if indexDif == 0 then
return a < b --sort by name if the class is the same
else
return indexDif < 0
end
end
tsort(players, sort)
return players
end
function GuildLists:GetGuildRankOrder(players)
tsort(players, function(a,b)
local rankA = self:GetGuildRank(a) or -1
local rankB = self:GetGuildRank(b) or -1
if rankA == -1 then return true
elseif rankB == -1 then return false
end
if rankA == rankB then return a < b end
return rankA < rankB
end)
return players
end
local function itemGroupHelper(textureName, slotId, width, ...)
local itemGroup = AceGUI:Create("SimpleGroup")
itemGroup:SetHeight(45)
itemGroup:PauseLayout()
itemGroup:SetRelativeWidth(width or 0.49)
local icon = AceGUI:Create("Icon")
icon:SetImageSize(40,40)
icon:SetWidth(40)
icon:SetHeight(45)
icon:SetImage(textureName, ...)
icon:SetPoint("TOPLEFT", itemGroup.frame, "TOPLEFT")
icon:SetUserData("default", {textureName})
itemGroup:AddChild(icon)
itemGroup:SetUserData("icon", icon)
local label = GuildLists:GetItemLinkLabel("PLACEHOLDER")
label:SetFontObject(GameFontNormal)
label:SetPoint("LEFT", icon.frame, "RIGHT")
label:SetWidth(260)
itemGroup:AddChild(label)
itemGroup:SetUserData("label", label)
icon:SetCallback("OnEnter", function(widget, ...) label:Fire("OnEnter", ...) end)
icon:SetCallback("OnLeave", function(widget, ...) label:Fire("OnLeave", ...) end)
icon:SetCallback("OnClick", function(widget, ...) label:Fire("OnClick", ...) end)
itemGroup:SetCallback("OnRelease", function()
itemGroups[slotId] = nil
end)
itemGroups[slotId] = itemGroup
return itemGroup
end
function GuildLists:GeneratePlayerBiSList(player, class)
if contentPanel == nil then return end
if self.dialog and self.dialog:IsShown() then
self.dialog:Hide()
end
contentPanel:ReleaseChildren()
contentPanel:SetWidth(600)
contentPanel:SetHeight(485)
contentPanel:SetLayout("Flow")
local label = AceGUI:Create("InteractiveLabel")
label:SetText(L["Return to character selection"])
label:SetWidth(295)
label:SetHeight(24)
label:SetFontObject(GameFontNormal)
label:SetColor(1, 1, 0)
label:SetCallback("OnClick", function() GuildLists:GeneratePlayerScrollContainer() end)
label:SetImage("Interface\\Buttons\\UI-SpellbookIcon-PrevPage-Up")
label:SetHighlight("Interface\\Buttons\\UI-Common-MouseHilight")
label:SetImageSize(24,24)
contentPanel:AddChild(label)
local label = AceGUI:Create("Label")
if (player):sub(-1) == "s" and GetOSLocale() == "enUS" then
label:SetText(string.format("%s' BestInSlot lists", self:GetPlayerString(player)))
else
label:SetText(string.format(L["%s's BestInSlot lists"], self:GetPlayerString(player)))
end
label:SetFontObject(GameFontNormal)
label:SetHeight(24)
label:SetWidth(295)
label:SetColor(1, 1, 0)
contentPanel:AddChild(label)
local numSpecs = GetNumSpecializationsForClassID(classIds[class])
for i=1,numSpecs do
local icon = AceGUI:Create("Icon")
local specId, specName, specDescr, specTexture = GetSpecializationInfoForClassID(classIds[class],i)
icon:SetImage(specTexture)
icon:SetLabel(specName)
icon:SetUserData("specid", specId)
icon:SetUserData("player", player)
icon:SetImageSize(30,30)
icon:SetHeight(50)
icon.frame:RegisterForClicks("AnyDown")
icon:SetCallback("OnClick", specIconOnClick)
icon:SetRelativeWidth(1 / numSpecs - 0.01)
icon:SetDisabled(selectedCharacter[specId] == nil)
if i == 1 then
self.frame:GetUserData("content"):SetUserData("talent", icon)
end
contentPanel:AddChild(icon)
end
local slots = self.slots
for i=1,#slots do
local slotId, textureName = GetInventorySlotInfo(slots[i])
local itemGroup = itemGroups[slotId]
if not itemGroup then
itemGroup = itemGroupHelper(textureName, slotId)
contentPanel:AddChild(itemGroup)
end
end
if self.Artifacts then
local placeHolderTexture = self.Artifacts:GetTexture()
local placeHolderCoords = self.Artifacts:GetPlaceholderLocation()
for i=1,3 do
local itemGroup = itemGroups[29 + i]
if not itemGroup then
itemGroup = itemGroupHelper(placeHolderTexture, 29 + i, 0.32, unpack(placeHolderCoords))
itemGroups[29+i] = itemGroup
contentPanel:AddChild(itemGroup)
end
end
end
self:ShowTutorial(L["Guild BiS lists"], 4)
dropdownFilter:SetDisabled(true)
end
local function playerIconOnClick(widget, event, button)
if button == "LeftButton" then
local table = widget:GetUserDataTable()
local player = widget:GetUserData("char")
local playerClass = widget:GetUserData("class")
local raidTier = dropdownRaidTier:GetValue()
selectedCharacter = GuildLists.db.factionrealm[GetGuildInfo("player")][player][raidTier][dropdownDifficulty:GetValue()]
GuildLists:GeneratePlayerBiSList(player, playerClass)
elseif button == "RightButton" then
GuildLists:GetContextMenu(widget:GetUserData("char"))
end
end
function GuildLists:GeneratePlayerScrollContainer()
if contentPanel == nil then return end
selectedCharacter = nil
local raidTier = self:GetSelected(self.RAIDTIER)
local difficulty = self:GetSelected(self.DIFFICULTY)
local guild = GetGuildInfo("player")
local players = self:GetCacheData()
local sortedTable = self:GetOrderTable(players)
contentPanel:ReleaseChildren()
contentPanel:SetWidth(600)
contentPanel:SetHeight(485)
contentPanel:SetLayout("Fill")
local scroll = AceGUI:Create("ScrollFrame")
scroll:SetLayout("Flow")
contentPanel:AddChild(scroll)
local first = true
for i=1,#sortedTable do
local player = sortedTable[i]
local playerData = players[player]
local hasABiSList = false
for j=1,#playerData do
if playerData.guild == guild and playerData[j][1] == raidTier and playerData[j][2] == difficulty then
hasABiSList = true
break
end
end
if hasABiSList then
local playerClass = self:GetPlayerClass(player) or UNKNOWN
if playerClass ~= UNKNOWN then
local icon = AceGUI:Create("Icon")
icon:SetLabel(self:GetPlayerString(player))
icon:SetImage("Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES", unpack(CLASS_ICON_TCOORDS[playerClass]))
icon:SetRelativeWidth(0.14)
icon:SetUserData("char", player)
icon:SetUserData("class", playerClass)
icon.frame:RegisterForClicks("AnyDown")
icon:SetCallback("OnClick", playerIconOnClick)
scroll:AddChild(icon)
if first then
self.frame:GetUserData("content"):SetUserData("firstchar", icon)
first = false
end
end
end
end
dropdownFilter:SetDisabled(false)
end
function GuildLists:FillFilterOptions(dropdown)
local list = {
[SORT_NAME] = SORT_NAME,
[SORT_CLASS] = SORT_CLASS,
[SORT_GUILDRANKS] = SORT_GUILDRANKS,
}
local order = {SORT_NAME, SORT_CLASS, SORT_GUILDRANKS}
dropdown:SetList(list, order)
dropdown:SetValue(selectedSort or SORT_NAME)
end
local function filterOnValueChanged(dropdown, _, value)
selectedSort = value
GuildLists:GeneratePlayerScrollContainer()
end
function GuildLists:Draw(container)
dropdownRaidTier = self:GetDropdown(self.RAIDTIER, nil, GeneratePlayerScrollContainer)
dropdownRaidTier:SetRelativeWidth(0.32)
dropdownDifficulty = self:GetDropdown(self.DIFFICULTY, nil, GeneratePlayerScrollContainer)
dropdownDifficulty:SetRelativeWidth(0.32)
dropdownFilter = AceGUI:Create("Dropdown")
dropdownFilter:SetLabel(COMPACT_UNIT_FRAME_PROFILE_SORTBY)
dropdownFilter:SetRelativeWidth(0.32)
dropdownFilter:SetCallback("OnValueChanged", filterOnValueChanged)
self:FillFilterOptions(dropdownFilter)
container:AddChild(dropdownRaidTier)
container:AddChild(dropdownDifficulty)
container:AddChild(dropdownFilter)
container:SetUserData("raidtier", dropdownRaidTier)
if dropdownRaidTier.disabled and dropdownDifficulty.disabled then
local label = AceGUI:Create("Label")
label:SetFont(GameFontNormal:GetFont(), 14, nil)
label:SetFullWidth(true)
label:SetText(L["There are no Best in Slot lists from any of your guild members available. Have you requested their Best In Slot info?"])
container:AddChild(label)
else
contentPanel = AceGUI:Create("SimpleGroup")
contentPanel:SetWidth(600)
contentPanel:SetHeight(485)
contentPanel:SetPoint("TOPLEFT", dropdownRaidTier.frame, "BOTTOMLEFT", 10, 10)
container:AddChild(contentPanel)
GuildLists:GeneratePlayerScrollContainer()
GuildLists:ShowTutorial(L["Guild BiS lists"], 1)
end
end
function GuildLists:Close()
contentPanel:ClearAllPoints()
dropdownDifficulty = nil
dropdownRaidTier = nil
dropdownFilter = nil
contentPanel = nil
wipe(itemGroups)
if self.processedSlots then
wipe(self.processedSlots)
end
end
function GuildLists:IsShown()
if IsInGuild() then
local _,raidtiers,_, difficulties = GuildLists:GetCacheData()
return #raidtiers > 0
end
return false
end
GuildLists:RegisterTutorials(L["Guild BiS lists"], {
[1] = {text = L["On this page you can view the BestInSlot lists of your guild."], xOffset = 0, yOffset = -50, container = "content", onRequest = true},
[2] = {text = L["The dropdowns will only show BestInSlot lists that you have available."], text2 = (L["You can request BestInSlot lists in the '%s' page."]):format(L["Request BiS"]), xOffset = 0, yOffset = -10, container = "content", element = "raidtier", UpArrow = true },
[3] = {text = L["Click on the class icons to view that characters BestInSlot list."], text2 = L["Right clicking the icons gives you options to delete them from your Saved Variables."], xOffset = 0, yOffset = -20, container = "content", element = "firstchar", UpArrow = true},
[4] = {text = L["Click on any specialization icon to view that specializations list."], text2 = L["Only the specializations that you received are enabled."], xOffset = 0, yOffset = -20, container = "content", element = "talent", onRequest = true, UpArrow = true}
})
StaticPopupDialogs["BESTINSLOT_CONFIRMDELETECACHE"] = {
text = L["You've picked: %s"].."\n"..L["Deleting this is irreversible. Are you sure?"],
button1 = YES,
button2 = NO,
OnAccept = deleteCachedData,
whileDead = true,
hideOnEscape = true,
preferredIndex = 3,
exclusive = 1,
}