yellowfive@57: local Amr = LibStub("AceAddon-3.0"):GetAddon("AskMrRobot") yellowfive@57: local L = LibStub("AceLocale-3.0"):GetLocale("AskMrRobot", true) yellowfive@57: local AceGUI = LibStub("AceGUI-3.0") yellowfive@57: yellowfive@57: local _panelSplash yellowfive@57: local _panelStartLoot yellowfive@57: local _lblStartLoot yellowfive@57: local _btnStartLoot yellowfive@57: local _scrollHistory yellowfive@57: local _tabs yellowfive@57: yellowfive@57: local _messagePrefixes = { yellowfive@57: RosterRequestGear = "_TRR", yellowfive@57: RosterGear = "_TRG", yellowfive@57: ItemExportRequestGear = "_TLR", yellowfive@57: ItemExportGear = "_TLG", yellowfive@57: ItemExportLoot = "_TLL", yellowfive@57: SyncRequest = "_TSR", yellowfive@57: Sync = "_TSS" yellowfive@57: } yellowfive@57: yellowfive@57: Amr.LootMessagePrefixes = { yellowfive@57: Start = "_TCS", yellowfive@57: Roll = "_TCR", yellowfive@57: Veto = "_TCV", yellowfive@57: Rand = "_TCD", yellowfive@57: Give = "_TCG", yellowfive@57: Finish = "_TCF" yellowfive@57: } yellowfive@57: yellowfive@57: local function renderExportWindow(container, instructions, text) yellowfive@57: yellowfive@57: local bg = Amr:RenderCoverChrome(container, 800, 450) yellowfive@57: yellowfive@57: local lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetWidth(750) yellowfive@57: lbl:SetText(L.TeamExportHelp) yellowfive@57: lbl:SetPoint("TOP", bg.content, "TOP", 0, -10) yellowfive@57: bg:AddChild(lbl) yellowfive@57: yellowfive@57: local lbl2 = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl2:SetWidth(750) yellowfive@57: lbl2:SetText(instructions) yellowfive@57: lbl2:SetPoint("TOP", lbl.frame, "BOTTOM", 0, -10) yellowfive@57: bg:AddChild(lbl2) yellowfive@57: yellowfive@57: local txt = AceGUI:Create("AmrUiTextarea") yellowfive@57: txt:SetWidth(750) yellowfive@57: txt:SetHeight(300) yellowfive@57: txt:SetPoint("TOP", lbl2.frame, "BOTTOM", 0, -10) yellowfive@57: txt:SetFont(Amr.CreateFont("Regular", 12, Amr.Colors.Text)) yellowfive@57: txt:SetText(text) yellowfive@57: bg:AddChild(txt) yellowfive@57: yellowfive@57: local btn = AceGUI:Create("AmrUiButton") yellowfive@57: btn:SetText(L.TeamButtonExportClose) yellowfive@57: btn:SetBackgroundColor(Amr.Colors.Green) yellowfive@57: btn:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) yellowfive@57: btn:SetWidth(120) yellowfive@57: btn:SetHeight(28) yellowfive@57: btn:SetPoint("TOPLEFT", txt.frame, "BOTTOMLEFT", 0, -10) yellowfive@57: btn:SetCallback("OnClick", function(widget) Amr:HideCover() end) yellowfive@57: bg:AddChild(btn) yellowfive@57: yellowfive@57: return txt yellowfive@57: end yellowfive@57: yellowfive@57: local function renderImportWindow(container) yellowfive@57: yellowfive@57: local bg = Amr:RenderCoverChrome(container, 700, 450) yellowfive@57: yellowfive@57: local lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetWidth(600) yellowfive@57: lbl:SetText(L.TeamImportRankingsHeader) yellowfive@57: lbl:SetPoint("TOP", bg.content, "TOP", 0, -10) yellowfive@57: bg:AddChild(lbl) yellowfive@57: yellowfive@57: local txt = AceGUI:Create("AmrUiTextarea") yellowfive@57: txt:SetWidth(600) yellowfive@57: txt:SetHeight(300) yellowfive@57: txt:SetPoint("TOP", lbl.frame, "BOTTOM", 0, -10) yellowfive@57: txt:SetFont(Amr.CreateFont("Regular", 12, Amr.Colors.Text)) yellowfive@57: bg:AddChild(txt) yellowfive@57: yellowfive@57: local btnImportOk = AceGUI:Create("AmrUiButton") yellowfive@57: btnImportOk:SetText(L.ImportButtonOk) yellowfive@57: btnImportOk:SetBackgroundColor(Amr.Colors.Green) yellowfive@57: btnImportOk:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) yellowfive@57: btnImportOk:SetWidth(120) yellowfive@57: btnImportOk:SetHeight(28) yellowfive@57: btnImportOk:SetPoint("TOPLEFT", txt.frame, "BOTTOMLEFT", 0, -10) yellowfive@57: bg:AddChild(btnImportOk) yellowfive@57: yellowfive@57: local btnImportCancel = AceGUI:Create("AmrUiButton") yellowfive@57: btnImportCancel:SetText(L.ImportButtonCancel) yellowfive@57: btnImportCancel:SetBackgroundColor(Amr.Colors.Green) yellowfive@57: btnImportCancel:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) yellowfive@57: btnImportCancel:SetWidth(120) yellowfive@57: btnImportCancel:SetHeight(28) yellowfive@57: btnImportCancel:SetPoint("LEFT", btnImportOk.frame, "RIGHT", 20, 0) yellowfive@57: btnImportCancel:SetCallback("OnClick", function(widget) Amr:HideCover() end) yellowfive@57: bg:AddChild(btnImportCancel) yellowfive@57: yellowfive@57: local lblErr = AceGUI:Create("AmrUiLabel") yellowfive@57: lblErr:SetWidth(600) yellowfive@57: lblErr:SetFont(Amr.CreateFont("Bold", 14, Amr.Colors.Red)) yellowfive@57: lblErr:SetText("") yellowfive@57: lblErr:SetPoint("TOPLEFT", btnImportOk.frame, "BOTTOMLEFT", 0, -20) yellowfive@57: bg:AddChild(lblErr) yellowfive@57: yellowfive@57: btnImportOk:SetCallback("OnClick", function(widget) yellowfive@57: local msg = txt:GetText() yellowfive@57: local err = Amr:ImportRankings(msg) yellowfive@57: if err then yellowfive@57: lblErr:SetText(err) yellowfive@57: txt:SetFocus(true) yellowfive@57: else yellowfive@57: Amr:HideCover() yellowfive@57: Amr:RefreshTeamUi() yellowfive@57: end yellowfive@57: end) yellowfive@57: yellowfive@57: return txt yellowfive@57: end yellowfive@57: yellowfive@57: local function renderVersionWindow(container) yellowfive@57: yellowfive@57: local windowWidth = 500 yellowfive@57: local lbl, lbl2 yellowfive@57: local bg, border = Amr:RenderCoverChrome(container, windowWidth, 600) yellowfive@57: yellowfive@57: lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetWidth(windowWidth - 60) yellowfive@57: lbl:SetJustifyH("CENTER") yellowfive@57: lbl:SetFont(Amr.CreateFont("Bold", 24, Amr.Colors.TextHeaderActive)) yellowfive@57: lbl:SetText(L.TeamVersionTitle) yellowfive@57: lbl:SetPoint("TOP", bg.content, "TOP", 0, -10) yellowfive@57: bg:AddChild(lbl) yellowfive@57: yellowfive@57: if not IsInGroup() and not IsInRaid() then yellowfive@57: lbl2 = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl2:SetWidth(windowWidth - 20) yellowfive@57: lbl2:SetJustifyH("CENTER") yellowfive@57: lbl2:SetFont(Amr.CreateFont("Italic", 16, Amr.Colors.TextTan)) yellowfive@57: lbl2:SetText(L.TeamVersionNoGroup) yellowfive@57: lbl2:SetPoint("TOP", lbl.frame, "BOTTOM", 0, -25) yellowfive@57: bg:AddChild(lbl2) yellowfive@57: border:SetHeight(150) yellowfive@57: else yellowfive@57: local units = Amr:GetGroupUnitIdentifiers() yellowfive@57: yellowfive@57: local missing = {} yellowfive@57: local tooLow = {} yellowfive@57: yellowfive@57: for i, unitId in ipairs(units) do yellowfive@57: local realm, name = Amr:GetRealmAndName(unitId) yellowfive@57: if realm then yellowfive@57: local ver = Amr:GetAddonVersion(realm, name) yellowfive@57: if ver == 0 then yellowfive@57: table.insert(missing, { unitId, realm, name }) yellowfive@57: elseif ver < Amr.MIN_ADDON_VERSION then yellowfive@57: table.insert(tooLow, { unitId, realm, name, ver }) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: if #missing == 0 and #tooLow == 0 then yellowfive@57: lbl2 = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl2:SetWidth(windowWidth - 20) yellowfive@57: lbl2:SetJustifyH("CENTER") yellowfive@57: lbl2:SetFont(Amr.CreateFont("Italic", 16, Amr.Colors.TextTan)) yellowfive@57: lbl2:SetText(L.TeamVersionGood) yellowfive@57: lbl2:SetPoint("TOP", lbl.frame, "BOTTOM", 0, -25) yellowfive@57: bg:AddChild(lbl2) yellowfive@57: border:SetHeight(150) yellowfive@57: else yellowfive@57: local prev = lbl yellowfive@57: local h = 0 yellowfive@57: yellowfive@57: -- helper to render a player name yellowfive@57: local function renderItem(obj, showVer) yellowfive@57: lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetWidth(120) yellowfive@57: yellowfive@57: local cls, clsEn = UnitClass(obj[1]) yellowfive@57: local color = clsEn and Amr.Colors.Classes[clsEn] or Amr.Colors.TextHeaderDisabled yellowfive@57: lbl:SetFont(Amr.CreateFont("Regular", 14, color)) yellowfive@57: yellowfive@57: lbl:SetText(obj[3]) yellowfive@57: lbl:SetPoint("TOPLEFT", prev.frame, "BOTTOMLEFT", 0, -5) yellowfive@57: bg:AddChild(lbl) yellowfive@57: prev = lbl yellowfive@57: h = h + lbl:GetHeight() + 5 yellowfive@57: yellowfive@57: if showVer then yellowfive@57: lbl2 = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl2:SetWidth(60) yellowfive@57: lbl2:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White)) yellowfive@57: lbl2:SetText("v" .. obj[4]) yellowfive@57: lbl2:SetPoint("LEFT", lbl.frame, "RIGHT", 5, 0) yellowfive@57: bg:AddChild(lbl2) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: if #missing > 0 then yellowfive@57: lbl2 = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl2:SetWidth(180) yellowfive@57: lbl2:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.Red)) yellowfive@57: lbl2:SetText(L.TeamVersionMissing) yellowfive@57: lbl2:SetJustifyH("CENTER") yellowfive@57: lbl2:SetPoint("TOP", prev.frame, "BOTTOM", 0, -20) yellowfive@57: bg:AddChild(lbl2) yellowfive@57: h = h + lbl2:GetHeight() + 20 yellowfive@57: yellowfive@57: prev = lbl2 yellowfive@57: for i, obj in ipairs(missing) do yellowfive@57: renderItem(obj) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: if #tooLow > 0 then yellowfive@57: lbl2 = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl2:SetWidth(180) yellowfive@57: lbl2:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.Gold)) yellowfive@57: lbl2:SetText(L.TeamVersionOld) yellowfive@57: lbl2:SetJustifyH("CENTER") yellowfive@57: lbl2:SetPoint("TOP", prev.frame, "BOTTOM", 0, -20) yellowfive@57: bg:AddChild(lbl2) yellowfive@57: h = h + lbl2:GetHeight() + 20 yellowfive@57: yellowfive@57: prev = lbl2 yellowfive@57: for i, obj in ipairs(tooLow) do yellowfive@57: renderItem(obj, true) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: border:SetHeight(h + 100) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: local btn = AceGUI:Create("AmrUiButton") yellowfive@57: btn:SetText(L.TeamButtonExportClose) yellowfive@57: btn:SetBackgroundColor(Amr.Colors.Green) yellowfive@57: btn:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) yellowfive@57: btn:SetWidth(120) yellowfive@57: btn:SetHeight(28) yellowfive@57: btn:SetPoint("BOTTOM", bg.content, "BOTTOM", 0, 10) yellowfive@57: btn:SetCallback("OnClick", function(widget) Amr:HideCover() end) yellowfive@57: bg:AddChild(btn) yellowfive@57: end yellowfive@57: yellowfive@57: local function onVersionClick() yellowfive@57: -- show a window with players who do not have the addon or too low a version yellowfive@57: Amr:ShowCover(renderVersionWindow) yellowfive@57: end yellowfive@57: yellowfive@57: local function onExportRosterClick() yellowfive@57: yellowfive@57: Amr:ShowCover(L.TeamExportRosterLoading) yellowfive@57: yellowfive@57: Amr:ExportRosterAsync(function(txt) yellowfive@57: Amr:HideCover() yellowfive@57: yellowfive@57: if not txt then yellowfive@57: Amr:ShowAlert(L.TeamAlertNoGroup, L.AlertOk) yellowfive@57: return yellowfive@57: end yellowfive@57: yellowfive@57: Amr:ShowCover(function(container) yellowfive@57: local textbox = renderExportWindow(container, L.TeamExportRosterText, txt) yellowfive@57: textbox:SetFocus(true) yellowfive@57: end) yellowfive@57: end) yellowfive@57: yellowfive@57: end yellowfive@57: yellowfive@57: local function onExportLootClick() yellowfive@57: yellowfive@57: Amr:ShowCover(L.TeamExportRosterLoading) yellowfive@57: yellowfive@57: Amr:ExportLootAsync(function(txt) yellowfive@57: Amr:HideCover() yellowfive@57: yellowfive@57: if txt == "NOGROUP" then yellowfive@57: Amr:ShowAlert(L.TeamAlertNoGroup, L.AlertOk) yellowfive@57: return yellowfive@57: elseif txt == "NOLOOT" then yellowfive@57: Amr:ShowAlert(L.TeamAlertNoLoot, L.AlertOk) yellowfive@57: return yellowfive@57: else yellowfive@57: Amr:ShowCover(function(container) yellowfive@57: local textbox = renderExportWindow(container, L.TeamExportLootText, txt) yellowfive@57: textbox:SetFocus(true) yellowfive@57: end) yellowfive@57: end yellowfive@57: end) yellowfive@57: end yellowfive@57: yellowfive@57: local function onImportRankingsClick() yellowfive@57: Amr:ShowCover(function(container) yellowfive@57: local textbox = renderImportWindow(container) yellowfive@57: textbox:SetFocus(true) yellowfive@57: end) yellowfive@57: end yellowfive@57: yellowfive@57: local function renderTab(tab, container) yellowfive@57: yellowfive@57: local lbl, lbl2 yellowfive@57: yellowfive@57: if tab == "Member" then yellowfive@57: local lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetWidth(500) yellowfive@57: lbl:SetFont(Amr.CreateFont("Regular", 24, Amr.Colors.TextTan)) yellowfive@57: lbl:SetText(L.TeamMemberText) yellowfive@57: lbl:SetPoint("TOPLEFT", container.content, "TOPLEFT", 0, -40) yellowfive@57: container:AddChild(lbl) yellowfive@57: yellowfive@57: -- if loot is still going on, show a button to re-show the loot window yellowfive@57: if Amr.db.char.TeamOpt.LootInProgress then yellowfive@57: lbl2 = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl2:SetWidth(500) yellowfive@57: lbl2:SetFont(Amr.CreateFont("Italic", 18, Amr.Colors.TextTan)) yellowfive@57: lbl2:SetText(L.TeamMemberShowLootLabel) yellowfive@57: lbl2:SetPoint("TOPLEFT", lbl.frame, "BOTTOMLEFT", 0, -60) yellowfive@57: container:AddChild(lbl2) yellowfive@57: yellowfive@57: local btn = AceGUI:Create("AmrUiButton") yellowfive@57: btn:SetWidth(180) yellowfive@57: btn:SetHeight(26) yellowfive@57: btn:SetBackgroundColor(Amr.Colors.Blue) yellowfive@57: btn:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) yellowfive@57: btn:SetText(L.TeamMemberShowLoot) yellowfive@57: btn:SetPoint("TOPLEFT", lbl2.frame, "BOTTOMLEFT", 0, -10) yellowfive@57: btn:SetCallback("OnClick", function(widget) yellowfive@57: Amr:ShowLootWindow() yellowfive@57: Amr:RefreshLootWindow() yellowfive@57: Amr:RefreshLootRolls() yellowfive@57: end) yellowfive@57: container:AddChild(btn) yellowfive@57: end yellowfive@57: yellowfive@57: elseif tab == "Leader" then yellowfive@57: yellowfive@57: local lblNum = AceGUI:Create("AmrUiLabel") yellowfive@57: lblNum:SetFont(Amr.CreateFont("Bold", 26, Amr.Colors.White)) yellowfive@57: lblNum:SetText("0.") yellowfive@57: lblNum:SetWidth(40) yellowfive@57: lblNum:SetPoint("TOPLEFT", container.content, "TOPLEFT", 6, -40) yellowfive@57: container:AddChild(lblNum) yellowfive@57: yellowfive@57: local btnVersion = AceGUI:Create("AmrUiButton") yellowfive@57: btnVersion:SetText(L.TeamButtonVersionText) yellowfive@57: btnVersion:SetBackgroundColor(Amr.Colors.Orange) yellowfive@57: btnVersion:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) yellowfive@57: btnVersion:SetWidth(180) yellowfive@57: btnVersion:SetHeight(26) yellowfive@57: btnVersion:SetPoint("LEFT", lblNum.frame, "RIGHT", 0, -1) yellowfive@57: btnVersion:SetCallback("OnClick", onVersionClick) yellowfive@57: container:AddChild(btnVersion) yellowfive@57: yellowfive@57: lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.TextTan)) yellowfive@57: lbl:SetText(L.TeamExportVersionLabel) yellowfive@57: lbl:SetWidth(400) yellowfive@57: lbl:SetPoint("TOPLEFT", btnVersion.frame, "TOPRIGHT", 20, 0) yellowfive@57: container:AddChild(lbl) yellowfive@57: yellowfive@57: lblNum = AceGUI:Create("AmrUiLabel") yellowfive@57: lblNum:SetFont(Amr.CreateFont("Bold", 26, Amr.Colors.White)) yellowfive@57: lblNum:SetText("1.") yellowfive@57: lblNum:SetWidth(40) yellowfive@57: lblNum:SetPoint("TOPRIGHT", btnVersion.frame, "BOTTOMLEFT", 0, -39) yellowfive@57: container:AddChild(lblNum) yellowfive@57: yellowfive@57: local btnRoster = AceGUI:Create("AmrUiButton") yellowfive@57: btnRoster:SetText(L.TeamButtonExportRosterText) yellowfive@57: btnRoster:SetBackgroundColor(Amr.Colors.Orange) yellowfive@57: btnRoster:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) yellowfive@57: btnRoster:SetWidth(180) yellowfive@57: btnRoster:SetHeight(26) yellowfive@57: btnRoster:SetPoint("LEFT", lblNum.frame, "RIGHT", 0, -1) yellowfive@57: btnRoster:SetCallback("OnClick", onExportRosterClick) yellowfive@57: container:AddChild(btnRoster) yellowfive@57: yellowfive@57: lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.TextTan)) yellowfive@57: lbl:SetText(L.TeamExportRosterLabel) yellowfive@57: lbl:SetWidth(400) yellowfive@57: lbl:SetPoint("TOPLEFT", btnRoster.frame, "TOPRIGHT", 20, 0) yellowfive@57: container:AddChild(lbl) yellowfive@57: yellowfive@57: lblNum = AceGUI:Create("AmrUiLabel") yellowfive@57: lblNum:SetFont(Amr.CreateFont("Bold", 26, Amr.Colors.White)) yellowfive@57: lblNum:SetText("2.") yellowfive@57: lblNum:SetWidth(40) yellowfive@57: lblNum:SetPoint("TOPRIGHT", btnRoster.frame, "BOTTOMLEFT", 0, -89) yellowfive@57: container:AddChild(lblNum) yellowfive@57: yellowfive@57: local btnLoot = AceGUI:Create("AmrUiButton") yellowfive@57: btnLoot:SetText(L.TeamButtonExportLootText) yellowfive@57: btnLoot:SetBackgroundColor(Amr.Colors.Orange) yellowfive@57: btnLoot:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) yellowfive@57: btnLoot:SetWidth(180) yellowfive@57: btnLoot:SetHeight(26) yellowfive@57: btnLoot:SetPoint("LEFT", lblNum.frame, "RIGHT", 0, -1) yellowfive@57: btnLoot:SetCallback("OnClick", onExportLootClick) yellowfive@57: container:AddChild(btnLoot) yellowfive@57: yellowfive@57: lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.TextTan)) yellowfive@57: lbl:SetText(L.TeamExportLootLabel) yellowfive@57: lbl:SetWidth(400) yellowfive@57: lbl:SetPoint("TOPLEFT", btnLoot.frame, "TOPRIGHT", 20, 0) yellowfive@57: container:AddChild(lbl) yellowfive@57: yellowfive@57: lbl2 = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl2:SetFont(Amr.CreateFont("Bold", 14, Amr.Colors.Blue)) yellowfive@57: lbl2:SetText(L.TeamExportLootLabel2) yellowfive@57: lbl2:SetWidth(400) yellowfive@57: lbl2:SetPoint("TOPLEFT", lbl.frame, "BOTTOMLEFT", 0, -5) yellowfive@57: container:AddChild(lbl2) yellowfive@57: yellowfive@57: lblNum = AceGUI:Create("AmrUiLabel") yellowfive@57: lblNum:SetFont(Amr.CreateFont("Bold", 26, Amr.Colors.White)) yellowfive@57: lblNum:SetText("3.") yellowfive@57: lblNum:SetWidth(40) yellowfive@57: lblNum:SetPoint("TOPRIGHT", btnLoot.frame, "BOTTOMLEFT", 0, -89) yellowfive@57: container:AddChild(lblNum) yellowfive@57: yellowfive@57: local btnRank = AceGUI:Create("AmrUiButton") yellowfive@57: btnRank:SetText(L.TeamButtonImportRankingsText) yellowfive@57: btnRank:SetBackgroundColor(Amr.Colors.Green) yellowfive@57: btnRank:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) yellowfive@57: btnRank:SetWidth(180) yellowfive@57: btnRank:SetHeight(26) yellowfive@57: btnRank:SetPoint("LEFT", lblNum.frame, "RIGHT", 0, -1) yellowfive@57: btnRank:SetCallback("OnClick", onImportRankingsClick) yellowfive@57: container:AddChild(btnRank) yellowfive@57: yellowfive@57: lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.TextTan)) yellowfive@57: lbl:SetText(L.TeamImportRankingsLabel) yellowfive@57: lbl:SetWidth(400) yellowfive@57: lbl:SetPoint("TOPLEFT", btnRank.frame, "TOPRIGHT", 20, 0) yellowfive@57: container:AddChild(lbl) yellowfive@57: yellowfive@57: _panelStartLoot = AceGUI:Create("AmrUiPanel") yellowfive@57: _panelStartLoot:SetLayout("None") yellowfive@57: _panelStartLoot:SetBackgroundColor(Amr.Colors.Black, 0) yellowfive@57: _panelStartLoot:SetPoint("TOPLEFT", lblNum.frame, "BOTTOMLEFT", 0, -90) yellowfive@57: container:AddChild(_panelStartLoot) yellowfive@57: _panelStartLoot:SetVisible(false) yellowfive@57: yellowfive@57: lblNum = AceGUI:Create("AmrUiLabel") yellowfive@57: lblNum:SetFont(Amr.CreateFont("Bold", 26, Amr.Colors.White)) yellowfive@57: lblNum:SetText("4.") yellowfive@57: lblNum:SetWidth(40) yellowfive@57: lblNum:SetPoint("TOPLEFT", _panelStartLoot.content, "TOPLEFT") yellowfive@57: _panelStartLoot:AddChild(lblNum) yellowfive@57: yellowfive@57: _btnStartLoot = AceGUI:Create("AmrUiButton") yellowfive@57: _btnStartLoot:SetText(L.TeamButtonStartLootText) yellowfive@57: _btnStartLoot:SetBackgroundColor(Amr.Colors.Blue) yellowfive@57: _btnStartLoot:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) yellowfive@57: _btnStartLoot:SetWidth(180) yellowfive@57: _btnStartLoot:SetHeight(26) yellowfive@57: _btnStartLoot:SetPoint("LEFT", lblNum.frame, "RIGHT", 0, -1) yellowfive@57: _btnStartLoot:SetCallback("OnClick", function(widget) yellowfive@57: if Amr.db.char.TeamOpt.LootInProgress then yellowfive@57: Amr:ShowLootWindow() yellowfive@57: Amr:RefreshLootWindow() yellowfive@57: Amr:RefreshLootRolls() yellowfive@57: else yellowfive@57: Amr:StartLoot() yellowfive@57: end yellowfive@57: end) yellowfive@57: _panelStartLoot:AddChild(_btnStartLoot) yellowfive@57: yellowfive@57: _lblStartLoot = AceGUI:Create("AmrUiLabel") yellowfive@57: _lblStartLoot:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.Text)) yellowfive@57: _lblStartLoot:SetWidth(400) yellowfive@57: _lblStartLoot:SetPoint("LEFT", _btnStartLoot.frame, "RIGHT", 20, 0) yellowfive@57: _panelStartLoot:AddChild(_lblStartLoot) yellowfive@57: end yellowfive@57: yellowfive@57: -- loot history shows on either tab yellowfive@57: lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetFont(Amr.CreateFont("Regular", 16, Amr.Colors.TextTan)) yellowfive@57: lbl:SetText(L.TeamHistoryTitle) yellowfive@57: lbl:SetWidth(280) yellowfive@57: lbl:SetPoint("TOPRIGHT", container.content, "TOPRIGHT", 0, -12) yellowfive@57: container:AddChild(lbl) yellowfive@57: yellowfive@57: local panelHistory = AceGUI:Create("AmrUiPanel") yellowfive@57: panelHistory:SetLayout("Fill") yellowfive@57: panelHistory:SetBackgroundColor(Amr.Colors.Black, 0.3) yellowfive@57: panelHistory:SetPoint("TOPRIGHT", lbl.frame, "BOTTOMRIGHT", 0, -5) yellowfive@57: panelHistory:SetPoint("BOTTOMLEFT", container.content, "BOTTOMRIGHT", -280, 0) yellowfive@57: container:AddChild(panelHistory) yellowfive@57: yellowfive@57: _scrollHistory = AceGUI:Create("AmrUiScrollFrame") yellowfive@57: _scrollHistory:SetLayout("List") yellowfive@57: panelHistory:AddChild(_scrollHistory) yellowfive@57: end yellowfive@57: yellowfive@57: local function renderHistory() yellowfive@57: if not _scrollHistory then return end yellowfive@57: _scrollHistory:ReleaseChildren() yellowfive@57: yellowfive@57: -- history is list of objects with: yellowfive@57: -- link, result, class, name yellowfive@57: yellowfive@57: local history = Amr.db.char.TeamOpt.History yellowfive@57: local historyWidth = 260 yellowfive@57: yellowfive@57: local emptyMsg = nil yellowfive@57: if not IsInGroup() and not IsInRaid() then yellowfive@57: emptyMsg = L.TeamHistoryNoGroup yellowfive@57: elseif not history or #history == 0 then yellowfive@57: emptyMsg = L.TeamHistoryEmpty yellowfive@57: end yellowfive@57: yellowfive@57: if emptyMsg then yellowfive@57: local panel = AceGUI:Create("AmrUiPanel") yellowfive@57: panel:SetLayout("None") yellowfive@57: panel:SetBackgroundColor(Amr.Colors.Black, 0) yellowfive@57: panel:SetWidth(historyWidth) yellowfive@57: panel:SetHeight(30) yellowfive@57: _scrollHistory:AddChild(panel) yellowfive@57: yellowfive@57: local lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetWidth(historyWidth) yellowfive@57: lbl:SetJustifyH("CENTER") yellowfive@57: lbl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.TextTan)) yellowfive@57: lbl:SetText(emptyMsg) yellowfive@57: lbl:SetPoint("LEFT", panel.content, "LEFT", 8, 0) yellowfive@57: panel:AddChild(lbl) yellowfive@57: else yellowfive@57: for i = #history, 1, -1 do yellowfive@57: local obj = history[i] yellowfive@57: local itemLink = obj.link yellowfive@57: yellowfive@57: local panel = AceGUI:Create("AmrUiPanel") yellowfive@57: panel:SetLayout("None") yellowfive@57: panel:SetBackgroundColor(Amr.Colors.Black, 0) yellowfive@57: panel:SetWidth(historyWidth) yellowfive@57: panel:SetHeight(45) yellowfive@57: _scrollHistory:AddChild(panel) yellowfive@57: yellowfive@57: local lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetWidth(historyWidth - 5) yellowfive@57: lbl:SetWordWrap(false) yellowfive@57: lbl:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.Text)) yellowfive@57: lbl:SetPoint("TOPLEFT", panel.content, "TOPLEFT", 5, -5) yellowfive@57: panel:AddChild(lbl) yellowfive@57: yellowfive@57: Amr.GetItemInfo(itemLink, function(obj, name, link) yellowfive@57: -- set item name, tooltip yellowfive@57: obj:SetText(link:gsub("%[", ""):gsub("%]", "")) yellowfive@57: Amr:SetItemTooltip(obj, link, "ANCHOR_BOTTOMRIGHT", 0, obj.frame:GetHeight()) yellowfive@57: end, lbl) yellowfive@57: yellowfive@57: lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetWidth(historyWidth - 5) yellowfive@57: lbl:SetWordWrap(false) yellowfive@57: lbl:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.White)) yellowfive@57: yellowfive@57: if obj.result == "Disenchant" then yellowfive@57: lbl:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.TextHeaderDisabled)) yellowfive@57: lbl:SetText(L.TeamLootOptionDisenchant) yellowfive@57: else yellowfive@57: local color = obj.class and Amr.Colors.Classes[obj.class] or Amr.Colors.TextHeaderDisabled yellowfive@57: lbl:SetText((obj.result == "??" and "" or L["TeamLootOption" .. obj.result] .. ": ") .."|c" .. Amr.ColorToHex(color, 1) .. obj.name .. "|r") yellowfive@57: end yellowfive@57: yellowfive@57: lbl:SetPoint("BOTTOMLEFT", panel.content, "BOTTOMLEFT", 5, 8) yellowfive@57: panel:AddChild(lbl) yellowfive@57: yellowfive@57: local line = AceGUI:Create("AmrUiPanel") yellowfive@57: line:SetBackgroundColor(Amr.Colors.Black, 1) yellowfive@57: line:SetWidth(historyWidth) yellowfive@57: line:SetHeight(1) yellowfive@57: line:SetPoint("BOTTOM", panel.content, "BOTTOM") yellowfive@57: panel:AddChild(line) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: local function onTabSelected(container, event, group) yellowfive@57: container:ReleaseChildren() yellowfive@57: yellowfive@57: -- clear references to tab elements yellowfive@57: _panelStartLoot = nil yellowfive@57: _lblStartLoot = nil yellowfive@57: _btnStartLoot = nil yellowfive@57: _scrollHistory = nil yellowfive@57: yellowfive@57: Amr.db.char.TeamOpt.Role = group yellowfive@57: renderTab(group, container) yellowfive@57: Amr:RefreshTeamUi() yellowfive@57: end yellowfive@57: yellowfive@57: -- renders the main UI for the Team Optimizer tab yellowfive@57: function Amr:RenderTabTeam(container) yellowfive@57: yellowfive@57: -- splash screen to customize team optimizer ui for the user yellowfive@57: if not Amr.db.char.TeamOpt.Role then yellowfive@57: _panelSplash = AceGUI:Create("AmrUiPanel") yellowfive@57: _panelSplash:SetLayout("None") yellowfive@57: _panelSplash:SetBackgroundColor(Amr.Colors.Black, 0) yellowfive@57: _panelSplash:SetPoint("TOPLEFT", container.content, "TOPLEFT") yellowfive@57: _panelSplash:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMRIGHT") yellowfive@57: container:AddChild(_panelSplash) yellowfive@57: yellowfive@57: local lblSplash = AceGUI:Create("AmrUiLabel") yellowfive@57: lblSplash:SetWidth(800) yellowfive@57: lblSplash:SetJustifyH("CENTER") yellowfive@57: lblSplash:SetFont(Amr.CreateFont("Regular", 24, Amr.Colors.Text)) yellowfive@57: lblSplash:SetText(L.TeamSplashHeader) yellowfive@57: lblSplash:SetPoint("TOP", _panelSplash.content, "TOP", 0, -40) yellowfive@57: _panelSplash:AddChild(lblSplash) yellowfive@57: yellowfive@57: local btn = AceGUI:Create("AmrUiButton") yellowfive@57: btn:SetText(L.TeamTabLeaderText) yellowfive@57: btn:SetBackgroundColor(Amr.Colors.Orange) yellowfive@57: btn:SetFont(Amr.CreateFont("Bold", 24, Amr.Colors.White)) yellowfive@57: btn:SetWidth(280) yellowfive@57: btn:SetHeight(60) yellowfive@57: btn:SetPoint("TOPRIGHT", lblSplash.frame, "BOTTOM", -50, -50) yellowfive@57: btn:SetCallback("OnClick", function(widget) yellowfive@57: Amr.db.char.TeamOpt.Role = "Leader" yellowfive@57: _panelSplash:SetVisible(false) yellowfive@57: _tabs:SetVisible(true) yellowfive@57: _tabs:SelectTab("Leader") yellowfive@57: end) yellowfive@57: _panelSplash:AddChild(btn) yellowfive@57: yellowfive@57: local lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetWidth(280) yellowfive@57: lbl:SetJustifyH("CENTER") yellowfive@57: lbl:SetFont(Amr.CreateFont("Italic", 16, Amr.Colors.TextTan)) yellowfive@57: lbl:SetText(L.TeamSplashLeaderLabel) yellowfive@57: lbl:SetPoint("TOP", btn.frame, "BOTTOM", 0, -20) yellowfive@57: _panelSplash:AddChild(lbl) yellowfive@57: yellowfive@57: btn = AceGUI:Create("AmrUiButton") yellowfive@57: btn:SetText(L.TeamTabMemberText) yellowfive@57: btn:SetBackgroundColor(Amr.Colors.Orange) yellowfive@57: btn:SetFont(Amr.CreateFont("Bold", 24, Amr.Colors.White)) yellowfive@57: btn:SetWidth(280) yellowfive@57: btn:SetHeight(60) yellowfive@57: btn:SetPoint("TOPLEFT", lblSplash.frame, "BOTTOM", 50, -50) yellowfive@57: btn:SetCallback("OnClick", function(widget) yellowfive@57: Amr.db.char.TeamOpt.Role = "Member" yellowfive@57: _panelSplash:SetVisible(false) yellowfive@57: _tabs:SetVisible(true) yellowfive@57: _tabs:SelectTab("Member") yellowfive@57: end) yellowfive@57: _panelSplash:AddChild(btn) yellowfive@57: yellowfive@57: lbl = AceGUI:Create("AmrUiLabel") yellowfive@57: lbl:SetWidth(280) yellowfive@57: lbl:SetJustifyH("CENTER") yellowfive@57: lbl:SetFont(Amr.CreateFont("Italic", 16, Amr.Colors.TextTan)) yellowfive@57: lbl:SetText(L.TeamSplashMemberLabel) yellowfive@57: lbl:SetPoint("TOP", btn.frame, "BOTTOM", 0, -20) yellowfive@57: _panelSplash:AddChild(lbl) yellowfive@57: end yellowfive@57: yellowfive@57: -- tabstrip yellowfive@57: _tabs = AceGUI:Create("AmrUiTabGroup") yellowfive@57: _tabs:SetLayout("None") yellowfive@57: _tabs:SetTabs({ yellowfive@57: {text=L.TeamTabLeaderText, value="Leader", style="bold"}, yellowfive@57: {text=L.TeamTabMemberText, value="Member", style="bold"} yellowfive@57: }) yellowfive@57: _tabs:SetPoint("TOPLEFT", container.content, "TOPLEFT", 6, -30) yellowfive@57: _tabs:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMRIGHT") yellowfive@57: _tabs:SetCallback("OnGroupSelected", onTabSelected) yellowfive@57: container:AddChild(_tabs) yellowfive@57: yellowfive@57: local role = Amr.db.char.TeamOpt.Role yellowfive@57: yellowfive@57: _tabs:SetVisible(not not role) yellowfive@57: if role then yellowfive@57: -- if a role has been chosen, select the proper tab (which will also refresh the UI) yellowfive@57: _tabs:SelectTab(role) yellowfive@57: else yellowfive@57: -- no role, refresh the UI manually yellowfive@57: self:RefreshTeamUi() yellowfive@57: end yellowfive@57: yellowfive@57: end yellowfive@57: yellowfive@57: function Amr:ReleaseTabTeam() yellowfive@57: _panelSplash = nil yellowfive@57: _panelStartLoot = nil yellowfive@57: _lblStartLoot = nil yellowfive@57: _btnStartLoot = nil yellowfive@57: _scrollHistory = nil yellowfive@57: _tabs = nil yellowfive@57: end yellowfive@57: yellowfive@57: function Amr:RefreshTeamUi() yellowfive@57: yellowfive@57: -- if rankings have been loaded, render the 'start loot' panel yellowfive@57: if _panelStartLoot then yellowfive@57: local rankString = Amr.db.global.TeamOpt.RankingString yellowfive@57: if rankString then yellowfive@57: _panelStartLoot:SetVisible(true) yellowfive@57: _lblStartLoot:SetText(L.TeamStartLootLabel(#Amr.db.global.TeamOpt.Rankings)) yellowfive@57: _btnStartLoot:SetText(Amr.db.char.TeamOpt.LootInProgress and L.TeamButtonResumeLootText or L.TeamButtonStartLootText) yellowfive@57: else yellowfive@57: _panelStartLoot:SetVisible(false) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- render loot history yellowfive@57: renderHistory() yellowfive@57: end yellowfive@57: yellowfive@57: local function getItemIdsFromLinks(all, list) yellowfive@57: for i, v in ipairs(list) do yellowfive@57: local obj = Amr.ParseItemLink(v) yellowfive@57: local id = Amr.GetItemUniqueId(obj) yellowfive@57: if id then yellowfive@57: table.insert(all, id) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- update AllItems, used to determine when a new item is actually a new equippable item yellowfive@57: local function snapshotAllItems(data) yellowfive@57: yellowfive@57: local all = {} yellowfive@57: for k, v in pairs(data.Equipped[data.ActiveSpec]) do yellowfive@57: local obj = Amr.ParseItemLink(v) yellowfive@57: local id = Amr.GetItemUniqueId(obj) yellowfive@57: if id then yellowfive@57: table.insert(all, id) yellowfive@57: end yellowfive@57: end yellowfive@57: getItemIdsFromLinks(all, data.BagItems) yellowfive@57: getItemIdsFromLinks(all, data.BankItems) yellowfive@57: getItemIdsFromLinks(all, data.VoidItems) yellowfive@57: yellowfive@57: table.sort(all) yellowfive@57: return all yellowfive@57: end yellowfive@57: yellowfive@57: local function sendGear(prefix, empty) yellowfive@57: yellowfive@57: local region = Amr.RegionNames[GetCurrentRegion()] yellowfive@57: local realm = GetRealmName() yellowfive@57: local name = UnitName("player") yellowfive@57: yellowfive@57: -- get all data, including inventory yellowfive@57: local txt = "_" yellowfive@57: if not empty then yellowfive@57: local data = Amr:ExportCharacter() yellowfive@57: txt = Amr.Serializer:SerializePlayerData(data, true) yellowfive@57: yellowfive@57: -- snapshot items when gear is sent yellowfive@57: Amr.db.char.TeamOpt.AllItems = snapshotAllItems(data) yellowfive@57: end yellowfive@57: yellowfive@57: local msg = string.format("%s\n%s\n%s\n%s\n%s", prefix, region, realm, name, txt) yellowfive@57: Amr:SendAmrCommMessage(msg) yellowfive@57: end yellowfive@57: yellowfive@57: local function toPlayerKey(realm, name) yellowfive@57: return name .. "-" .. realm yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: ------------------------------------------------------------------------------------------------ yellowfive@57: -- Loot Export yellowfive@57: ------------------------------------------------------------------------------------------------ yellowfive@57: yellowfive@57: -- prune out any characters no longer in the player's group yellowfive@57: local function pruneGearForItemExport() yellowfive@57: yellowfive@57: local newInfo = {} yellowfive@57: local units = Amr:GetGroupUnitIdentifiers() yellowfive@57: yellowfive@57: for i, unitId in ipairs(units) do yellowfive@57: local realm, name = Amr:GetRealmAndName(unitId) yellowfive@57: if realm then yellowfive@57: local key = toPlayerKey(realm, name) yellowfive@57: newInfo[key] = Amr.db.global.TeamOpt.LootGear[key] yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: Amr.db.global.TeamOpt.LootGear = newInfo yellowfive@57: end yellowfive@57: yellowfive@57: local function scanMasterLoot() yellowfive@57: -- only care if we are in a raid or group yellowfive@57: if not IsInGroup() and not IsInRaid() then return end yellowfive@57: yellowfive@57: -- we only care about the master looter yellowfive@57: if not IsMasterLooter() then return end yellowfive@57: yellowfive@57: -- guid of the unit being looted yellowfive@57: local npcGuid = UnitGUID("target") yellowfive@57: if not npcGuid then yellowfive@57: -- this could wack shit out... but no raid bosses drop loot from containers right now, so should be fine yellowfive@57: npcGuid = "container" yellowfive@57: end yellowfive@57: yellowfive@57: -- if we already have loot data for this unit, then we can ignore yellowfive@57: if Amr.db.char.TeamOpt.LootGuid == npcGuid then return end yellowfive@57: yellowfive@57: local loot = {} yellowfive@57: for i = 1, GetNumLootItems() do yellowfive@57: --local texture, item, quantity, quality, locked = GetLootSlotInfo(i) yellowfive@57: local lootType = GetLootSlotType(i) yellowfive@57: if lootType == 1 then yellowfive@57: local link = GetLootSlotLink(i) yellowfive@57: table.insert(loot, link) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: Amr.db.char.TeamOpt.LootGuid = npcGuid yellowfive@57: Amr.db.char.TeamOpt.Loot = loot yellowfive@57: yellowfive@57: -- publish loot information to everyone else running the addon in case team optimizer user is not the master looter yellowfive@57: local msg = _messagePrefixes.ItemExportLoot .. "\n" .. npcGuid .. "\n" .. table.concat(loot, "\n") yellowfive@57: Amr:SendAmrCommMessage(msg) yellowfive@57: end yellowfive@57: yellowfive@57: local function onLootReceived(parts) yellowfive@57: yellowfive@57: Amr.db.char.TeamOpt.LootGuid = parts[2] yellowfive@57: yellowfive@57: local loot = {} yellowfive@57: for i = 3, #parts do yellowfive@57: table.insert(loot, parts[i]) yellowfive@57: end yellowfive@57: Amr.db.char.TeamOpt.Loot = loot yellowfive@57: end yellowfive@57: yellowfive@57: local function onLeaveGroup() yellowfive@57: -- if the current player is no longer in a group or raid, finish any looting in progress yellowfive@57: Amr:FinishLoot(true) yellowfive@57: yellowfive@57: -- clear loot when leave a group yellowfive@57: Amr.db.char.TeamOpt.Loot = {} yellowfive@57: Amr.db.char.TeamOpt.LootGuid = nil yellowfive@57: Amr.db.global.TeamOpt.LootGear = {} yellowfive@57: end yellowfive@57: yellowfive@57: local function onGroupChanged() yellowfive@57: yellowfive@57: if not IsInGroup() and not IsInRaid() then yellowfive@57: onLeaveGroup() yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: local _lootExPlayersRemaining = 0 yellowfive@57: local _lootExRoster = nil yellowfive@57: local _lootExCallback = nil yellowfive@57: yellowfive@57: local function serializeLootExport() yellowfive@57: if not IsInGroup() and not IsInRaid() then return "NOGROUP" end yellowfive@57: yellowfive@57: local loot = Amr.db.char.TeamOpt.Loot yellowfive@57: if not loot or #loot == 0 then return "NOLOOT" end yellowfive@57: yellowfive@57: local itemObjects = {} yellowfive@57: for i, link in ipairs(loot) do yellowfive@57: local obj = Amr.ParseItemLink(link) yellowfive@57: if obj then yellowfive@57: table.insert(itemObjects, obj) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- DEBUG: just grab all currently equipped items yellowfive@57: --[[ yellowfive@57: itemObjects = {} yellowfive@57: local blah = Amr:ExportCharacter() yellowfive@57: for k, v in pairs(blah.Equipped[blah.ActiveSpec]) do yellowfive@57: local obj = Amr.ParseItemLink(v) yellowfive@57: if obj then yellowfive@57: table.insert(itemObjects, obj) yellowfive@57: end yellowfive@57: end yellowfive@57: ]] yellowfive@57: yellowfive@57: local parts = {} yellowfive@57: yellowfive@57: -- unique ids of items yellowfive@57: local lootPart = {} yellowfive@57: for i, obj in ipairs(itemObjects) do yellowfive@57: table.insert(lootPart, Amr.GetItemUniqueId(obj)) yellowfive@57: end yellowfive@57: table.insert(parts, table.concat(lootPart, ";")) yellowfive@57: yellowfive@57: -- gear for players who have gained loot since the last item import or roster export yellowfive@57: pruneGearForItemExport() yellowfive@57: local lootGear = Amr.db.global.TeamOpt.LootGear yellowfive@57: for k, v in pairs(lootGear) do yellowfive@57: table.insert(parts, v) yellowfive@57: end yellowfive@57: yellowfive@57: return table.concat(parts, "\n") yellowfive@57: end yellowfive@57: yellowfive@57: local function onLootExportCompleted() yellowfive@57: yellowfive@57: -- fill in LootGear with just those players who have changed yellowfive@57: Amr.db.global.TeamOpt.LootGear = _lootExRoster yellowfive@57: yellowfive@57: if _lootExCallback then yellowfive@57: local txt = serializeLootExport() yellowfive@57: _lootExCallback(txt) yellowfive@57: end yellowfive@57: yellowfive@57: -- reset state yellowfive@57: _lootExPlayersRemaining = 0 yellowfive@57: _lootExRoster = nil yellowfive@57: _lootExCallback = nil yellowfive@57: end yellowfive@57: yellowfive@57: -- called when this player's gear info has been requested by someone exporting loot yellowfive@57: local function onGearForLootExportRequested() yellowfive@57: yellowfive@57: local hasNewItem = false yellowfive@57: local oldItems = Amr.db.char.TeamOpt.AllItems yellowfive@57: yellowfive@57: if oldItems and #oldItems > 0 then yellowfive@57: -- see if any new equippable items have been gained by comparing to the last snapshot yellowfive@57: local data = Amr:ExportCharacter() yellowfive@57: local allItems = snapshotAllItems(data) yellowfive@57: yellowfive@57: if #oldItems ~= #allItems then yellowfive@57: hasNewItem = true yellowfive@57: else yellowfive@57: -- go through items from front to back, if there are any that don't match then something has changed yellowfive@57: for i = 1, #allItems do yellowfive@57: local oldItem = oldItems[i] yellowfive@57: local newItem = allItems[i] yellowfive@57: if oldItem ~= newItem then yellowfive@57: hasNewItem = true yellowfive@57: break yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- whenever a new item is received, send out updated gear information that should be added to the next item export yellowfive@57: sendGear(_messagePrefixes.ItemExportGear, not hasNewItem) yellowfive@57: end yellowfive@57: yellowfive@57: local function onGearForLootExportReceived(region, realm, name, data) yellowfive@57: -- if I am not listening for incoming gear data for an item export, then ignore this message yellowfive@57: if _lootExPlayersRemaining == 0 then return end yellowfive@57: yellowfive@57: local key = toPlayerKey(realm, name) yellowfive@57: if not data or data == "_" then yellowfive@57: _lootExRoster[key] = nil yellowfive@57: else yellowfive@57: _lootExRoster[key] = data yellowfive@57: end yellowfive@57: yellowfive@57: _lootExPlayersRemaining = _lootExPlayersRemaining - 1 yellowfive@57: if _lootExPlayersRemaining <= 0 then yellowfive@57: onLootExportCompleted() yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- Export the current loot, including any known gear data for players with the in-game addon, but only if it has changed since the last snapshot. yellowfive@57: -- This is asynchronous because it needs to wait for gear data to arrive from each player. yellowfive@57: function Amr:ExportLootAsync(callback) yellowfive@57: yellowfive@57: if not IsInGroup() and not IsInRaid() then yellowfive@57: callback("NOGROUP") yellowfive@57: end yellowfive@57: yellowfive@57: local loot = Amr.db.char.TeamOpt.Loot yellowfive@57: if not loot or #loot == 0 then yellowfive@57: callback("NOLOOT") yellowfive@57: end yellowfive@57: yellowfive@57: local playersNoGear = {} yellowfive@57: _lootExPlayersRemaining = 0 yellowfive@57: yellowfive@57: local units = self:GetGroupUnitIdentifiers() yellowfive@57: for i, unitId in ipairs(units) do yellowfive@57: local realm, name = self:GetRealmAndName(unitId) yellowfive@57: if realm then yellowfive@57: local ver = self:GetAddonVersion(realm, name) yellowfive@57: local key = toPlayerKey(realm, name) yellowfive@57: yellowfive@57: if ver >= Amr.MIN_ADDON_VERSION then yellowfive@57: _lootExPlayersRemaining = _lootExPlayersRemaining + 1 yellowfive@57: else yellowfive@57: table.insert(playersNoGear, unitId) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: _lootExRoster = {} yellowfive@57: _lootExCallback = callback yellowfive@57: yellowfive@57: if _lootExPlayersRemaining > 0 then yellowfive@57: -- send a message to receive player data, when the last player is received onLootExportCompleted will be called yellowfive@57: Amr:SendAmrCommMessage(_messagePrefixes.ItemExportRequestGear) yellowfive@57: else yellowfive@57: -- don't need to wait for anybody, just call immediately yellowfive@57: onLootExportCompleted() yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: ------------------------------------------------------------------------------------------------ yellowfive@57: -- Roster Export yellowfive@57: ------------------------------------------------------------------------------------------------ yellowfive@57: yellowfive@57: local _rosterPlayersRemaining = 0 yellowfive@57: local _roster = nil yellowfive@57: local _rosterCallback = nil yellowfive@57: yellowfive@57: local function onRosterCompleted() yellowfive@57: yellowfive@57: if _rosterCallback then yellowfive@57: -- serialize the roster yellowfive@57: local parts = {} yellowfive@57: for key, data in pairs(_roster) do yellowfive@57: table.insert(parts, data) yellowfive@57: end yellowfive@57: local msg = table.concat(parts, "\n") yellowfive@57: yellowfive@57: -- send to callback yellowfive@57: _rosterCallback(msg) yellowfive@57: end yellowfive@57: yellowfive@57: -- reset state yellowfive@57: _rosterPlayersRemaining = 0 yellowfive@57: _roster = nil yellowfive@57: _rosterCallback = nil yellowfive@57: yellowfive@57: -- clear out loot gear needed, an export will refresh everyone at the time of export yellowfive@57: Amr.db.global.TeamOpt.LootGear = {} yellowfive@57: end yellowfive@57: yellowfive@57: -- called when this player's gear info has been requested by someone exporting the raid roster yellowfive@57: local function onGearForRosterRequested() yellowfive@57: yellowfive@57: sendGear(_messagePrefixes.RosterGear) yellowfive@57: end yellowfive@57: yellowfive@57: local function onGearForRosterReceived(region, realm, name, data) yellowfive@57: -- if I am not listening for incoming gear data for the roster, then ignore this message yellowfive@57: if _rosterPlayersRemaining == 0 then return end yellowfive@57: yellowfive@57: local key = toPlayerKey(realm, name) yellowfive@57: _roster[key] = data yellowfive@57: yellowfive@57: _rosterPlayersRemaining = _rosterPlayersRemaining - 1 yellowfive@57: if _rosterPlayersRemaining <= 0 then yellowfive@57: onRosterCompleted() yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- Export the current roster, including any known gear data for players with the in-game addon. yellowfive@57: -- This is asynchronous because it needs to wait for gear data to arrive from each player. yellowfive@57: function Amr:ExportRosterAsync(callback) yellowfive@57: if not IsInGroup() and not IsInRaid() then yellowfive@57: callback() yellowfive@57: return yellowfive@57: end yellowfive@57: yellowfive@57: local playersNoGear = {} yellowfive@57: _rosterPlayersRemaining = 0 yellowfive@57: yellowfive@57: local units = self:GetGroupUnitIdentifiers() yellowfive@57: for i, unitId in ipairs(units) do yellowfive@57: local realm, name = self:GetRealmAndName(unitId) yellowfive@57: if realm then yellowfive@57: local ver = self:GetAddonVersion(realm, name) yellowfive@57: local key = toPlayerKey(realm, name) yellowfive@57: yellowfive@57: if ver >= Amr.MIN_ADDON_VERSION then yellowfive@57: _rosterPlayersRemaining = _rosterPlayersRemaining + 1 yellowfive@57: else yellowfive@57: table.insert(playersNoGear, unitId) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- fill the roster with any players who can't send us data yellowfive@57: _roster = {} yellowfive@57: for i, unitId in ipairs(playersNoGear) do yellowfive@57: local realm, name = self:GetRealmAndName(unitId) yellowfive@57: if realm then yellowfive@57: local key = toPlayerKey(realm, name) yellowfive@57: local obj = { yellowfive@57: Region = Amr.RegionNames[GetCurrentRegion()], yellowfive@57: Realm = realm, yellowfive@57: Name = name yellowfive@57: } yellowfive@57: _roster[key] = Amr.Serializer:SerializePlayerIdentity(obj) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: _rosterCallback = callback yellowfive@57: yellowfive@57: if _rosterPlayersRemaining > 0 then yellowfive@57: -- send a message to receive player data, when the last player is received onRosterCompleted will be called yellowfive@57: Amr:SendAmrCommMessage(_messagePrefixes.RosterRequestGear) yellowfive@57: else yellowfive@57: -- don't need to wait for anybody, just call immediately yellowfive@57: onRosterCompleted() yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: ------------------------------------------------------------------------------------------------ yellowfive@57: -- Ranking Import yellowfive@57: ------------------------------------------------------------------------------------------------ yellowfive@57: yellowfive@57: -- helper to parse import item identifier format into an item object yellowfive@57: local function parseItemIdentifier(ident) yellowfive@57: yellowfive@57: local parts = { strsplit(":", ident) } yellowfive@57: local item = {} yellowfive@57: item.id = tonumber(parts[1]) yellowfive@57: item.enchantId = 0 yellowfive@57: item.gemIds = { 0, 0, 0, 0 } yellowfive@57: item.suffixId = math.abs(tonumber(parts[2])) yellowfive@57: item.upgradeId = tonumber(parts[3]) yellowfive@94: item.level = tonumber(parts[4]) yellowfive@57: yellowfive@94: if #parts > 4 then yellowfive@57: item.bonusIds = {} yellowfive@94: for b = 5, #parts do yellowfive@57: table.insert(item.bonusIds, tonumber(parts[b])) yellowfive@57: end yellowfive@57: table.sort(item.bonusIds) yellowfive@57: end yellowfive@57: yellowfive@57: return item yellowfive@57: end yellowfive@57: yellowfive@57: function Amr:ParseRankingString(data) yellowfive@57: local rankings = {} yellowfive@57: yellowfive@57: local player = Amr:ExportCharacter() yellowfive@57: local myUnitId = Amr:GetUnitId(player.Realm, player.Name) yellowfive@57: local ml = IsMasterLooter() yellowfive@57: yellowfive@57: local itemList = { strsplit("\n", data) } yellowfive@57: for i = 1, #itemList do yellowfive@57: local ranking = {} yellowfive@57: yellowfive@57: local itemParts = { strsplit("_", itemList[i]) } yellowfive@57: yellowfive@57: -- first part has the item identifier yellowfive@57: ranking.item = parseItemIdentifier(itemParts[1]) yellowfive@57: yellowfive@57: -- second part has item info yellowfive@57: local infoParts = { strsplit(";", itemParts[2]) } yellowfive@57: ranking.itemInfo = { yellowfive@57: slot = infoParts[1], yellowfive@57: subclass = infoParts[2], yellowfive@57: weaponType = infoParts[3], yellowfive@57: armorType = infoParts[4] yellowfive@57: } yellowfive@57: yellowfive@57: local meInList = false yellowfive@57: yellowfive@57: -- parse each ranking yellowfive@57: ranking.ranks = {} yellowfive@57: for j = 3, #itemParts do yellowfive@57: local rankParts = { strsplit(";", itemParts[j]) } yellowfive@57: yellowfive@57: local rank = {} yellowfive@57: rank.realm = rankParts[1] yellowfive@57: rank.name = rankParts[2] yellowfive@57: rank.specId = tonumber(rankParts[3]) yellowfive@57: if rankParts[4] ~= "--" then yellowfive@57: rank.equipped = parseItemIdentifier(rankParts[4]) yellowfive@57: end yellowfive@57: rank.score = tonumber(rankParts[5]) yellowfive@57: rank.isEquipped = rankParts[6] == "t" yellowfive@57: rank.notRanked = rankParts[7] == "t" yellowfive@57: rank.offspec = rankParts[8] == "t" yellowfive@57: rank.enchantingSkill = tonumber(rankParts[9]) yellowfive@57: yellowfive@57: table.insert(ranking.ranks, rank) yellowfive@57: yellowfive@57: if myUnitId == Amr:GetUnitId(rank.realm, rank.name) then yellowfive@57: meInList = true yellowfive@57: rank.isMasterLooter = ml yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- if the current player is the master looter and he is not in the list, then add him at the end yellowfive@57: if ml and not meInList then yellowfive@57: local rank = { yellowfive@57: realm = player.Realm, yellowfive@57: name = player.Name, yellowfive@57: specId = player.Specs[player.ActiveSpec], yellowfive@57: equipped = "--", yellowfive@57: score = 0, yellowfive@57: isEquipped = false, yellowfive@57: notRanked = true, yellowfive@57: offspec = false, yellowfive@57: enchantingSkill = 0, yellowfive@57: isMasterLooter = true yellowfive@57: } yellowfive@57: table.insert(ranking.ranks, rank) yellowfive@57: end yellowfive@57: yellowfive@57: table.insert(rankings, ranking) yellowfive@57: end yellowfive@57: yellowfive@57: return rankings yellowfive@57: end yellowfive@57: yellowfive@57: -- import rankings from the website, save into the database, returns a string error if can't import for some reason yellowfive@57: function Amr:ImportRankings(data) yellowfive@57: yellowfive@57: if not data or string.len(data) == 0 then yellowfive@57: return L.ImportErrorEmpty yellowfive@57: end yellowfive@57: yellowfive@57: local success, rankings = pcall(Amr.ParseRankingString, self, data) yellowfive@57: yellowfive@57: if not success then yellowfive@57: return L.ImportErrorFormat yellowfive@57: end yellowfive@57: yellowfive@57: -- finish any looting in progress, effectively canceling it, user will have to press Start Loot again yellowfive@57: Amr:FinishLoot() yellowfive@57: yellowfive@57: -- save the rankings yellowfive@57: Amr.db.global.TeamOpt.Rankings = rankings yellowfive@57: Amr.db.global.TeamOpt.RankingString = data yellowfive@57: yellowfive@57: -- clear loot gear needed on successful ranking import yellowfive@57: Amr.db.global.TeamOpt.LootGear = {} yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: ------------------------------------------------------------------------------------------------ yellowfive@57: -- Loot Distribution yellowfive@57: ------------------------------------------------------------------------------------------------ yellowfive@57: yellowfive@57: function Amr:StartLoot() yellowfive@57: yellowfive@57: if not IsInGroup() and not IsInRaid() then yellowfive@57: Amr:ShowAlert(L.TeamAlertNoGroup, L.AlertOk) yellowfive@57: return yellowfive@57: end yellowfive@57: yellowfive@57: -- broadcast the loot data to everyone, this triggers the loot window to show yellowfive@57: local msg = string.format("%s\n%s", Amr.LootMessagePrefixes.Start, Amr.db.global.TeamOpt.RankingString) yellowfive@57: Amr:SendAmrCommMessage(msg) yellowfive@57: end yellowfive@57: yellowfive@57: function Amr:FinishLoot(clearHistory) yellowfive@57: yellowfive@57: -- reset all state yellowfive@57: Amr.db.char.TeamOpt.LootInProgress = false yellowfive@57: yellowfive@57: -- don't reset these for now... only reset these if someone leaves a group yellowfive@57: --Amr.db.char.TeamOpt.Loot = {} yellowfive@57: --Amr.db.char.TeamOpt.LootGuid = nil yellowfive@57: --Amr.db.global.TeamOpt.LootGear = {} yellowfive@57: yellowfive@57: Amr.db.global.TeamOpt.Rankings = {} yellowfive@57: Amr.db.global.TeamOpt.RankingString = nil yellowfive@57: yellowfive@57: Amr.db.char.TeamOpt.Rolls = {} yellowfive@57: yellowfive@57: if clearHistory then yellowfive@57: Amr.db.char.TeamOpt.History = {} yellowfive@57: end yellowfive@57: yellowfive@57: -- close the loot window yellowfive@57: Amr:HideLootWindow() yellowfive@57: yellowfive@57: -- re-render the team optimizer UI yellowfive@57: Amr:RefreshTeamUi() yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: ------------------------------------------------------------------------------------------------ yellowfive@57: -- Synchronization yellowfive@57: ------------------------------------------------------------------------------------------------ yellowfive@57: local _waitingForSync = false yellowfive@57: yellowfive@57: -- check if we need to synchronize yellowfive@57: local function checkSync() yellowfive@57: -- if loot is in progress and this person is not the ML, send a request to synchronize on startup, this player may have missed some data yellowfive@57: if not IsMasterLooter() and Amr.db.char.TeamOpt.LootInProgress then yellowfive@57: _waitingForSync = true yellowfive@57: Amr:SendAmrCommMessage(_messagePrefixes.SyncRequest) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- send data to anyone who needs to synchronize their loot data: history, rolls, rankings yellowfive@57: local function sendSyncData() yellowfive@57: -- only the master looter sends sync data to ensure that everyone gets the same stuff and we don't spam yellowfive@57: if not IsMasterLooter() then return end yellowfive@57: yellowfive@57: local msgParts = {} yellowfive@57: table.insert(msgParts, _messagePrefixes.Sync) yellowfive@57: table.insert(msgParts, Amr:Serialize(Amr.db.char.TeamOpt.History)) yellowfive@57: table.insert(msgParts, Amr:Serialize(Amr.db.char.TeamOpt.Rolls)) yellowfive@57: table.insert(msgParts, Amr:Serialize(Amr.db.global.TeamOpt.Rankings)) yellowfive@57: yellowfive@57: Amr:SendAmrCommMessage(table.concat(msgParts, "\n")) yellowfive@57: end yellowfive@57: yellowfive@57: local function receiveSyncData(parts) yellowfive@57: if not _waitingForSync then return end yellowfive@57: _waitingForSync = false yellowfive@57: yellowfive@57: local success, obj = Amr:Deserialize(parts[2]) yellowfive@57: if success then yellowfive@57: Amr.db.char.TeamOpt.History = obj yellowfive@57: end yellowfive@57: yellowfive@57: success, obj = Amr:Deserialize(parts[3]) yellowfive@57: if success then yellowfive@57: Amr.db.char.TeamOpt.Rolls = obj yellowfive@57: end yellowfive@57: yellowfive@57: success, obj = Amr:Deserialize(parts[4]) yellowfive@57: if success then yellowfive@57: Amr.db.global.TeamOpt.Rankings = obj yellowfive@57: end yellowfive@57: yellowfive@57: -- refresh any windows that may be visible yellowfive@57: Amr:RefreshTeamUi() yellowfive@57: Amr:RefreshLootWindow() yellowfive@57: Amr:RefreshLootRolls() yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: function Amr:ProcessTeamMessage(message) yellowfive@57: yellowfive@57: local parts = {} yellowfive@57: for part in string.gmatch(message, "([^\n]+)") do yellowfive@57: table.insert(parts, part) yellowfive@57: end yellowfive@57: yellowfive@57: local prefix = parts[1] yellowfive@57: yellowfive@57: if prefix == _messagePrefixes.RosterRequestGear then yellowfive@57: -- request for me to send my gear data yellowfive@57: onGearForRosterRequested() yellowfive@57: elseif prefix == _messagePrefixes.ItemExportRequestGear then yellowfive@57: -- request for me to send my gear data yellowfive@57: onGearForLootExportRequested() yellowfive@57: elseif prefix == _messagePrefixes.ItemExportLoot then yellowfive@57: -- the last loot that dropped yellowfive@57: onLootReceived(parts) yellowfive@57: elseif prefix == _messagePrefixes.SyncRequest then yellowfive@57: sendSyncData() yellowfive@57: elseif prefix == _messagePrefixes.Sync then yellowfive@57: receiveSyncData(parts) yellowfive@57: elseif prefix == Amr.LootMessagePrefixes.Start then yellowfive@57: Amr:OnStartLootReceived(parts) yellowfive@57: elseif prefix == Amr.LootMessagePrefixes.Roll then yellowfive@57: Amr:OnLootRollReceived(parts) yellowfive@57: elseif prefix == Amr.LootMessagePrefixes.Veto then yellowfive@57: Amr:OnLootVetoReceived(parts) yellowfive@57: elseif prefix == Amr.LootMessagePrefixes.Rand then yellowfive@57: Amr:OnLootRandReceived(parts) yellowfive@57: elseif prefix == Amr.LootMessagePrefixes.Give then yellowfive@57: Amr:OnLootGiveReceived(parts) yellowfive@57: elseif prefix == Amr.LootMessagePrefixes.Finish then yellowfive@57: Amr:FinishLoot() yellowfive@57: else yellowfive@57: -- message will be of format: prefix\nregion\nrealm\nname\n[stuff] yellowfive@57: local region = parts[2] yellowfive@57: local realm = parts[3] yellowfive@57: local name = parts[4] yellowfive@57: local data = parts[5] yellowfive@57: yellowfive@57: if prefix == _messagePrefixes.RosterGear then yellowfive@57: -- receive gear data from someone yellowfive@57: onGearForRosterReceived(region, realm, name, data) yellowfive@57: elseif prefix == _messagePrefixes.ItemExportGear then yellowfive@57: -- receive gear data for item export yellowfive@57: onGearForLootExportReceived(region, realm, name, data) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: function Amr:InitializeTeamOpt() yellowfive@57: yellowfive@57: if not IsInGroup() and not IsInRaid() then yellowfive@57: onLeaveGroup() yellowfive@57: end yellowfive@57: yellowfive@57: Amr:AddEventHandler("LOOT_OPENED", scanMasterLoot) yellowfive@57: Amr:AddEventHandler("GROUP_ROSTER_UPDATE", onGroupChanged) yellowfive@57: yellowfive@57: checkSync() yellowfive@57: end