Mercurial > wow > askmrrobot
diff Loot.lua @ 57:01b63b8ed811 v21
total rewrite to version 21
author | yellowfive |
---|---|
date | Fri, 05 Jun 2015 11:05:15 -0700 |
parents | |
children | cf2b6b9a8337 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Loot.lua Fri Jun 05 11:05:15 2015 -0700 @@ -0,0 +1,1037 @@ +local Amr = LibStub("AceAddon-3.0"):GetAddon("AskMrRobot") +local L = LibStub("AceLocale-3.0"):GetLocale("AskMrRobot", true) +local AceGUI = LibStub("AceGUI-3.0") + +local _frameLoot +local _panelLoot +local _selectedIndex +local _disenchant = {} +local _rankPanels +local _lootButtons + +local _widthItemList = 220 +local _widthRankList = 640 +local _widthSpacing = 10 +local _widthRank = 48 +local _widthRankBar = 195 +local _widthRollType = 45 +local _widthColPadding = 8 +local _widthRollExtraSpacing = 4 + +local _rollTypePos = { + Need = 1, + Off = 2, + Greed = 3, + Pass = 4 +} + +-- get the index of the loot item that matches up to the specified item +local function getLootIndex(itemIndex) + + local ranking = Amr.db.global.TeamOpt.Rankings[itemIndex] + if not ranking then return nil end + + local itemUniqueId = Amr.GetItemUniqueId(ranking.item) + for i = 1, GetNumLootItems() do + --local texture, item, quantity, quality, locked = GetLootSlotInfo(i) + local lootType = GetLootSlotType(i) + if lootType == 1 then + local link = GetLootSlotLink(i) + local lootItem = Amr.ParseItemLink(link) + if Amr.GetItemUniqueId(lootItem) == itemUniqueId then + return i, link + end + end + end +end + +local function getLootCandidateIndex(lootIndex, realm, name) + -- remove spaces to ensure proper matches, and make all lower + realm = string.gsub(realm, "%s+", "") + realm = string.lower(realm) + name = string.lower(name) + + local nameMatches = {} + for i = 1, 40 do + local candidate = GetMasterLootCandidate(lootIndex, i) + if candidate then + local candidateName = candidate + local candidateRealm = GetRealmName() + + -- see if realm is in the name + local splitPos = string.find(candidateName, "-") + if splitPos ~= nil then + candidateRealm = string.sub(candidateName, splitPos + 1) + candidateName = string.sub(candidateName, 1, splitPos - 1) + end + + -- remove spaces to ensure proper matches, and make all lower + candidateRealm = string.gsub(candidateRealm, "%s+", "") + candidateRealm = string.lower(candidateRealm) + candidateName = string.lower(candidateName) + + -- if perfect match then we are done + if candidateRealm == realm and candidateName == name then + return i + end + + if candidateName == name then + table.insert(nameMatches, i) + end + end + end + + -- only one player with same name, must be the player of interest + if #nameMatches == 1 then + return nameMatches[1] + end + + -- could not be found or ambiguous + return nil +end + +-- helper to send a message telling everyone that an item was just given out +local function sendGiveLootMessage(itemLink, unitId, isDisenchant) + -- some display info + local cls, clsEn = UnitClass(unitId) + local name = UnitName(unitId) + + local result = isDisenchant and "Disenchant" or (roll and roll.rollType or nil) + if result == nil then result = "??" end + + local msg = string.format("%s\n%d\n%s\n%s\n%s\n%s", Amr.LootMessagePrefixes.Give, _selectedIndex, itemLink, result, clsEn, name) + Amr:SendAmrCommMessage(msg) +end + +local function onGiveLootClick(widget) + local rollIndex = widget:GetUserData("index") + + local rankings = Amr.db.global.TeamOpt.Rankings + local ranking = rankings[_selectedIndex] + local rank = ranking and ranking.ranks[rollIndex] or nil + if rank then + local roll = Amr.db.char.TeamOpt.Rolls[_selectedIndex][rollIndex] + local isDisenchant = not not _disenchant[_selectedIndex] + + local unitId = Amr:GetUnitId(rank.realm, rank.name) + if unitId then + -- find the item and loot candidate index + local itemIndex, itemLink = getLootIndex(_selectedIndex) + + -- for debugging when don't actually have any loot + --itemLink = Amr.CreateItemLink(ranking.item) + + local playerIndex = itemIndex and getLootCandidateIndex(itemIndex, rank.realm, rank.name) or nil + if itemIndex and playerIndex then + GiveMasterLoot(itemIndex, playerIndex) + sendGiveLootMessage(itemLink, unitId, isDisenchant) + return + end + + end + end + + -- if we make it here, we could not give out the item for some reason + Amr:Print(L.LootMasterGiveFail) +end + +function Amr:OnLootGiveReceived(parts) + if not parts or #parts < 6 then return end + + local rankings = Amr.db.global.TeamOpt.Rankings + + -- index of the item that was given, flag it to hide it from the ui now + local index = tonumber(parts[2]) + local ranking = rankings[index] + if ranking then + ranking.given = true + end + + -- change the selected item index to the next ungiven item + for i, obj in ipairs(rankings) do + if not obj.given then + _selectedIndex = i + break + end + end + + -- add a loot history entry + local entry = { + link = parts[3], + result = parts[4], + class = parts[5], + name = parts[6] + } + table.insert(Amr.db.char.TeamOpt.History, entry) + + -- redraw any open windows + Amr:RefreshTeamUi() + Amr:RefreshLootWindow() + Amr:RefreshLootRolls() + + -- if this is the master looter, check if all items have been given out + if IsMasterLooter() then + local allDone = true + for i, ranking in ipairs(rankings) do + if not ranking.given then + allDone = false + break + end + end + + if allDone then + -- send a message indicating that looting is done + Amr:SendAmrCommMessage(Amr.LootMessagePrefixes.Finish) + end + end + +end + +local function onDisenchantClick() + local val = not _disenchant[_selectedIndex] + _disenchant[_selectedIndex] = val + + Amr:RefreshLootWindow() + Amr:RefreshLootRolls() +end + +local function onRollClick() + -- generate a roll for everyone on the current item + local rands = {} + + local ranking = Amr.db.global.TeamOpt.Rankings[_selectedIndex] + for i, rank in ipairs(ranking.ranks) do + local r = math.random(100) + rands[i] = r + end + + -- transmit the roll data to all group members + local msg = string.format("%s\n%d\n%s", Amr.LootMessagePrefixes.Rand, _selectedIndex, Amr:Serialize(rands)) + Amr:SendAmrCommMessage(msg) +end + +function Amr:OnLootRandReceived(parts) + if not parts or #parts < 3 then return end + + local index = tonumber(parts[2]) + local success, rands = Amr:Deserialize(parts[3]) + if not index or not success then return end + + local rolls = Amr.db.char.TeamOpt.Rolls[index] + for i, r in pairs(rands) do + local roll = rolls[i] + if not roll then + roll = {} + rolls[i] = roll + end + + roll.rand = r + end + + Amr:RefreshLootRolls() +end + +local function onVetoClick(widget) + local rollIndex = widget:GetUserData("rollIndex") + local rollType = widget:GetUserData("rollType") + + -- acts like a toggle + local roll = Amr.db.char.TeamOpt.Rolls[_selectedIndex][rollIndex] + local veto = not roll or not roll.vetoes or not roll.vetoes[rollType] + + -- send a message that a veto has been changed + local msg = string.format("%s\n%d\n%d\n%s\n%s", Amr.LootMessagePrefixes.Veto, _selectedIndex, rollIndex, rollType, veto and "t" or "f") + Amr:SendAmrCommMessage(msg) +end + +function Amr:OnLootVetoReceived(parts) + if not parts or #parts < 5 then return end + + local itemIndex = tonumber(parts[2]) + local rollIndex = tonumber(parts[3]) + local rollType = parts[4] + local veto = parts[5] == "t" + + if itemIndex and rollIndex then + local roll = Amr.db.char.TeamOpt.Rolls[itemIndex][rollIndex] + if not roll then + roll = {} + Amr.db.char.TeamOpt.Rolls[itemIndex][rollIndex] = roll + end + + if not roll.vetoes then + roll.vetoes = {} + end + + roll.vetoes[rollType] = veto + + -- if the player chose this option, have to remove it because it has been vetoed + if veto and roll.rollType == rollType then + roll.rollType = nil + end + + Amr:RefreshLootRolls() + end +end + +-- a user choice for what they want to do on an item +local function doRoll(rollType) + + local msg = string.format("%s\n%d\n%s\n%s\n%s", Amr.LootMessagePrefixes.Roll, _selectedIndex, rollType, GetRealmName(), UnitName("player")) + Amr:SendAmrCommMessage(msg) +end + +function Amr:OnLootRollReceived(parts) + local index = tonumber(parts[2]) + local rollType = parts[3] + local realm = parts[4] + local name = parts[5] + + -- for now, this code matches up name/realm to one in the rankings + -- TODO: more robust handling of players with same name but different realms in the same group on non-english clients + local nameMatches = {} + local ranking = Amr.db.global.TeamOpt.Rankings[index] + for i, rank in ipairs(ranking.ranks) do + if name == rank.name and realm == rank.realm then + nameMatches = {} + break + end + + if name == rank.name then + table.insert(nameMatches, rank) + end + end + if #nameMatches == 1 then + realm = nameMatches[1].realm + name = nameMatches[1].name + end + + -- find index of the ranking + local rankIndex = nil + for i, rank in ipairs(ranking.ranks) do + if name == rank.name and realm == rank.realm then + rankIndex = i + break + end + end + + if rankIndex then + local obj = Amr.db.char.TeamOpt.Rolls[index][rankIndex] + if not obj then + obj = {} + Amr.db.char.TeamOpt.Rolls[index][rankIndex] = obj + end + obj.rollType = rollType + end + + Amr:RefreshLootRolls() +end + +local function renderRollType(rp, rollType, roll, index) + + local icon = rp:GetUserData(rollType) + if not icon and roll then + -- create icon if we need one + icon = AceGUI:Create("AmrUiTextButton") + icon:SetWidth(16) + icon:SetHeight(16) + local pos = _rollTypePos[rollType] + local left = _widthRank + _widthColPadding + _widthRankBar + (pos * _widthColPadding) + ((pos - 1) * _widthRollType) + ((_widthRollType - 16) / 2) + icon:SetPoint("LEFT", rp.content, "LEFT", left, 0) + rp:AddChild(icon) + rp:SetUserData(rollType, icon) + + icon:SetUserData("rollType", rollType) + icon:SetUserData("rollIndex", index) + icon:SetVisible(false) + + icon:SetCallback("OnClick", onVetoClick) + end + + if icon then + if roll and roll.rollType == rollType then + icon:SetVisible(true) + icon:SetBackgroundImage("Interface\\AddOns\\" .. Amr.ADDON_NAME .. "\\Media\\IconCheck") + icon:SetHoverBackgroundImage("Interface\\AddOns\\" .. Amr.ADDON_NAME .. "\\Media\\IconCheck") + elseif roll and roll.vetoes and roll.vetoes[rollType] then + icon:SetVisible(true) + icon:SetBackgroundImage("Interface\\AddOns\\" .. Amr.ADDON_NAME .. "\\Media\\IconX") + icon:SetHoverBackgroundImage("Interface\\AddOns\\" .. Amr.ADDON_NAME .. "\\Media\\IconX") + else + icon:SetVisible(false) + end + + icon:SetDisabled(not IsMasterLooter()) + end + + -- update button state for this roll type + if _lootButtons and _lootButtons[rollType] then + _lootButtons[rollType]:SetDisabled(roll and roll.vetoes and roll.vetoes[rollType]) + end +end + +-- gets the current winner based on rolls and currently selected roll type for each user (returns index into rankings for item, or -1 if no winner yet) +local function getWinner(itemIndex) + + local rolls = Amr.db.char.TeamOpt.Rolls[itemIndex] + if not rolls then return -1 end + + -- go through and find the highest priority roll type + local bestRollType + local bestTypePos = 100 + for i, roll in pairs(rolls) do + if roll.rollType then + local rollPos = _rollTypePos[roll.rollType] + if rollPos < bestTypePos and rollPos < _rollTypePos["Pass"] then + bestRollType = roll.rollType + bestTypePos = rollPos + end + end + end + + -- nobody has chosen anything yet + if not bestRollType then return -1 end + + -- find highest roll in the highest priority roll type + local maxRoll = -1 + local bestRoll = -1 + for i, roll in pairs(rolls) do + if roll.rollType == bestRollType and roll.rand and roll.rand > maxRoll then + bestRoll = i + maxRoll = roll.rand + end + end + + return bestRoll +end + +function Amr:RefreshLootRolls() + if not _rankPanels then return end + + local ranking = Amr.db.global.TeamOpt.Rankings[_selectedIndex] + local rolls = Amr.db.char.TeamOpt.Rolls[_selectedIndex] + local isDisenchant = _disenchant[_selectedIndex] + + local winnerIndex = getWinner(_selectedIndex) + + for i, rp in pairs(_rankPanels) do + local rank = ranking.ranks[i] + local roll = rolls[i] + if isDisenchant then roll = nil end + + -- clear or set the value of each roll column + renderRollType(rp, "Need", roll, i) + renderRollType(rp, "Off", roll, i) + renderRollType(rp, "Greed", roll, i) + renderRollType(rp, "Pass", roll, i) + + -- render the random roll + local lbl = rp:GetUserData("randLabel") + if roll and roll.rand then + if not lbl then + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetJustifyH("RIGHT") + + local left = _widthRank + _widthColPadding + _widthRankBar + (5 * _widthColPadding) + (5 * _widthRollType) + lbl:SetPoint("RIGHT", rp.content, "LEFT", left, 0) + rp:AddChild(lbl) + rp:SetUserData("randLabel", lbl) + end + + -- highlight this roll if winner, otherwise unhighlight + if i == winnerIndex then + lbl:SetFont(Amr.CreateFont("Bold", 18, Amr.Colors.BrightGreen)) + else + lbl:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White)) + end + + lbl:SetText(roll.rand) + else + if lbl then + lbl:SetVisible(false) + end + end + + -- if this person does not have the addon, show a message (except in DE mode) + local hasAddon = true + local unitId = Amr:GetUnitId(rank.realm, rank.name) + if unitId then + local realm, name = Amr:GetRealmAndName(unitId) + if realm then + local ver = Amr:GetAddonVersion(realm, name) + hasAddon = ver >= Amr.MIN_ADDON_VERSION + end + end + + lbl = rp:GetUserData("noaddonLabel") + if not hasAddon and not isDisenchant then + if not lbl then + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.Red)) + lbl:SetText(L.LootRankLabelNoAddon) + lbl:SetPoint("LEFT", rp.content, "LEFT", _widthRank + _widthColPadding + _widthRankBar + _widthColPadding + 5, 0) + rp:AddChild(lbl) + rp:SetUserData("noaddonLabel", lbl) + end + else + if lbl then + lbl:SetVisible(false) + end + end + + end +end + +-- helper to create the column bg and header for rank list +local function createLootRankColumn(container, prevColumn, width, txt, txtAlign, extraPadding) + extraPadding = extraPadding and extraPadding or 0 + + local panel = AceGUI:Create("AmrUiPanel") + panel:SetBackgroundColor(Amr.Colors.Black, 0.3) + container:AddChild(panel) + + if prevColumn then + -- pad a bit to right of previous column + panel:SetPoint("TOPLEFT", prevColumn.content, "TOPRIGHT", _widthColPadding + extraPadding, 0) + panel:SetPoint("BOTTOMRIGHT", prevColumn.content, "BOTTOMRIGHT", _widthColPadding + extraPadding + width, 0) + else + -- first column abs position in the main ranking panel + panel:SetPoint("TOPLEFT", container.content, "TOPLEFT", _widthItemList + _widthSpacing, -115) + panel:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMLEFT", _widthItemList + _widthSpacing + width, 0) + end + + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetWordWrap(false) + lbl:SetFont(Amr.CreateFont("Regular", 12, Amr.Colors.TextHeaderDisabled)) + lbl:SetText(txt) + lbl:SetJustifyH(txtAlign) + lbl:SetWidth(width) + lbl:SetPoint("BOTTOMLEFT", panel.content, "TOPLEFT", 0, 5) + container:AddChild(lbl) + + return panel, lbl +end + +function Amr:RefreshLootWindow() + if not _panelLoot then return end + + -- clear out any children of the main loot frame and re-render + _panelLoot:ReleaseChildren() + _rankPanels = {} + _lootButtons = {} + + local ml = IsMasterLooter() + local myUnitId = Amr:GetUnitId(GetRealmName(), UnitName("player")) + + local rankings = Amr.db.global.TeamOpt.Rankings + if rankings and #rankings > 0 then + + -- make sure that an item is selected + if not _selectedIndex then + for i, ranking in ipairs(rankings) do + if not ranking.given then + _selectedIndex = i + break + end + end + end + + -- render list of items + local panelItems = AceGUI:Create("AmrUiPanel") + panelItems:SetLayout("Fill") + panelItems:SetWidth(_widthItemList) + panelItems:SetBackgroundColor(Amr.Colors.Black, 0) + panelItems:SetPoint("TOPLEFT", _panelLoot.content, "TOPLEFT", 0, 0) + panelItems:SetPoint("BOTTOMLEFT", _panelLoot.content, "BOTTOMLEFT") + _panelLoot:AddChild(panelItems) + + local scrollItems = AceGUI:Create("AmrUiScrollFrame") + scrollItems:SetLayout("List") + panelItems:AddChild(scrollItems) + + -- render the divider between items and ranks + local divider = AceGUI:Create("AmrUiPanel") + divider:SetBackgroundColor(Amr.Colors.Black, 0.5) + divider:SetPoint("TOPLEFT", _panelLoot.content, "TOPLEFT", _widthItemList, 0) + divider:SetPoint("BOTTOMRIGHT", _panelLoot.content, "BOTTOMLEFT", _widthItemList + 5, 0) + _panelLoot:AddChild(divider) + + local btn, btn2, lbl, lbl2, panel, panel2, chk + + local remainingItems = {} + for i, ranking in ipairs(rankings) do + if not ranking.given then + remainingItems[i] = ranking + end + end + + for i, ranking in pairs(remainingItems) do + btn = AceGUI:Create("AmrUiTextButton") + btn:SetWidth(_widthItemList) + btn:SetHeight(50) + btn:SetJustifyH("LEFT") + btn:SetJustifyV("TOP") + btn:SetTextPadding(9, nil, nil, 2) + btn:SetWordWrap(false) + btn:SetUserData("index", i) + + local f + if _selectedIndex == i then + f = Amr.CreateFont("Bold", 16, Amr.Colors.Text) + btn:SetBackgroundColor(Amr.Colors.Black, 0.5) + btn:SetHoverBackgroundColor(Amr.Colors.Black, 0.5) + else + f = Amr.CreateFont("Regular", 14, Amr.Colors.Text) + btn:SetHoverBackgroundColor(Amr.Colors.Black, 0.2) + end + + btn:SetFont(f) + btn:SetHoverFont(f) + + scrollItems:AddChild(btn) + + btn:SetCallback("OnClick", function(widget) + Amr:SelectLootItem(widget:GetUserData("index")) + end) + + local rankLink = Amr.CreateItemLink(ranking.item) + Amr.GetItemInfo(rankLink, function(obj, name, link) + -- set item name, tooltip + obj:SetText(" " .. link:gsub("%[", ""):gsub("%]", "")) + Amr:SetItemTooltip(obj, link, "ANCHOR_BOTTOMLEFT", 0, obj.frame:GetHeight()) + end, btn) + + -- add a label for slot, armor type + local slotText = Amr.SlotEnumDisplayText[ranking.itemInfo.slot] + if ranking.itemInfo.slot == 'MainHand' then + slotText = ranking.itemInfo.subclass == 'TwoHand' and L.TwoHand or L.OneHand + elseif ranking.itemInfo.slot == 'OffHand' then + slotText = L.OffHand + end + + if ranking.itemInfo.armorType == 'None' and ranking.itemInfo.weaponType ~= 'None' then + if ranking.itemInfo.weaponType ~= 'OffHand' then + slotText = slotText .. ", " .. L.WeaponTypes[ranking.itemInfo.weaponType] + end + elseif ranking.itemInfo.armorType ~= 'None' then + slotText = slotText .. ", " .. L.ArmorTypes[ranking.itemInfo.armorType] + end + + btn:SetSubtextFont(Amr.CreateFont("Regular", 13, Amr.Colors.TextGray)) + btn:SetSubtextJustifyH("LEFT") + btn:SetSubtextJustifyV("BOTTOM") + btn:SetSubtextPadding(nil, nil, 9, 7) + btn:SetSubtextWordWrap(false) + btn:SetSubtext(slotText) + + + local isDisenchant = not not _disenchant[i] + + if _selectedIndex == i then + + -- see if I am in the list + local canLoot = false + for j, rank in ipairs(ranking.ranks) do + local unitId = Amr:GetUnitId(rank.realm, rank.name) + if unitId == myUnitId then + canLoot = not rank.notRanked or rank.offspec + break + end + end + + -- render loot options + if canLoot then + btn = AceGUI:Create("AmrUiButton") + btn:SetWidth(120) + btn:SetHeight(26) + btn:SetFont(Amr.CreateFont("Bold", 15, Amr.Colors.White)) + btn:SetBackgroundColor(Amr.Colors.Green) + btn:SetText(L.TeamLootOptionNeed) + btn:SetPoint("TOPLEFT", _panelLoot.content, "TOPLEFT", _widthItemList + _widthSpacing, -7) + btn:SetCallback("OnClick", function(widget) doRoll("Need") end) + _panelLoot:AddChild(btn) + _lootButtons["Need"] = btn + + btn2 = AceGUI:Create("AmrUiButton") + btn2:SetWidth(120) + btn2:SetHeight(26) + btn2:SetFont(Amr.CreateFont("Bold", 15, Amr.Colors.White)) + btn2:SetBackgroundColor(Amr.Colors.Orange) + btn2:SetText(L.TeamLootOptionPass) + btn2:SetPoint("TOPLEFT", btn.frame, "BOTTOMLEFT", 0, -15) + btn2:SetCallback("OnClick", function(widget) doRoll("Pass") end) + _panelLoot:AddChild(btn2) + _lootButtons["Pass"] = btn2 + + btn = AceGUI:Create("AmrUiButton") + btn:SetWidth(120) + btn:SetHeight(26) + btn:SetFont(Amr.CreateFont("Bold", 15, Amr.Colors.White)) + btn:SetBackgroundColor(Amr.Colors.Blue) + btn:SetText(L.TeamLootOptionOff) + btn:SetPoint("BOTTOMLEFT", btn2.frame, "TOPRIGHT", 15, 15) + btn:SetCallback("OnClick", function(widget) doRoll("Off") end) + _panelLoot:AddChild(btn) + _lootButtons["Off"] = btn + + btn2 = AceGUI:Create("AmrUiButton") + btn2:SetWidth(120) + btn2:SetHeight(26) + btn2:SetFont(Amr.CreateFont("Bold", 15, Amr.Colors.White)) + btn2:SetBackgroundColor(Amr.Colors.Blue) + btn2:SetText(L.TeamLootOptionGreed) + btn2:SetPoint("TOPLEFT", btn.frame, "BOTTOMLEFT", 0, -15) + btn2:SetCallback("OnClick", function(widget) doRoll("Greed") end) + _panelLoot:AddChild(btn2) + _lootButtons["Greed"] = btn2 + else + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.TextTan)) + lbl:SetText(L.LootIneligible) + lbl:SetWidth(255) + lbl:SetPoint("TOPLEFT", _panelLoot.content, "TOPLEFT", _widthItemList + _widthSpacing, -7) + _panelLoot:AddChild(lbl) + end + + -- master loot options + if ml then + chk = AceGUI:Create("AmrUiCheckBox") + chk:SetText(L.LootMasterDisenchantText) + chk:SetPoint("TOPRIGHT", _panelLoot.content, "TOPRIGHT", -18, -12) + chk:SetCallback("OnClick", onDisenchantClick) + chk:SetChecked(_disenchant[i]) + _panelLoot:AddChild(chk) + + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetWidth(120) + lbl:SetJustifyH("CENTER") + lbl:SetText(L.LootMasterDisenchantLabel) + lbl:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.TextTan)) + lbl:SetPoint("TOP", chk.frame, "BOTTOM", 0, -5) + _panelLoot:AddChild(lbl) + + btn2 = AceGUI:Create("AmrUiButton") + btn2:SetWidth(120) + btn2:SetHeight(26) + btn2:SetFont(Amr.CreateFont("Bold", 15, Amr.Colors.White)) + btn2:SetBackgroundColor(Amr.Colors.Green) + btn2:SetText(L.LootMasterRollText) + btn2:SetPoint("RIGHT", chk.frame, "LEFT", -50, 0) + btn2:SetCallback("OnClick", onRollClick) + _panelLoot:AddChild(btn2) + + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetWidth(120) + lbl:SetJustifyH("CENTER") + lbl:SetText(L.LootMasterRollLabel) + lbl:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.TextTan)) + lbl:SetPoint("TOP", btn2.frame, "BOTTOM", 0, -5) + _panelLoot:AddChild(lbl) + + end + + -- backgrounds for the rank list and headers + panel = createLootRankColumn(_panelLoot, nil, _widthRank, isDisenchant and "" or L.LootRankHeaderRank, "RIGHT") + panel = createLootRankColumn(_panelLoot, panel, _widthRankBar, isDisenchant and L.LootRankHeaderScoreDisenchant or L.LootRankHeaderScore, "LEFT") + + if not isDisenchant then + panel = createLootRankColumn(_panelLoot, panel, _widthRollType, L.LootRankHeaderNeed, "CENTER") + panel = createLootRankColumn(_panelLoot, panel, _widthRollType, L.LootRankHeaderOff, "CENTER") + panel = createLootRankColumn(_panelLoot, panel, _widthRollType, L.LootRankHeaderGreed, "CENTER") + panel = createLootRankColumn(_panelLoot, panel, _widthRollType, L.LootRankHeaderPass, "CENTER") + panel = createLootRankColumn(_panelLoot, panel, _widthRollType, L.LootRankHeaderRoll, "RIGHT", _widthRollExtraSpacing) + end + + -- rank list for selected item + panel = AceGUI:Create("AmrUiPanel") + panel:SetLayout("Fill") + panel:SetBackgroundColor(Amr.Colors.Black, 0) + panel:SetPoint("TOPLEFT", _panelLoot.content, "TOPLEFT", _widthItemList + _widthSpacing, -115) + panel:SetPoint("BOTTOMRIGHT", _panelLoot.content, "BOTTOMRIGHT") + _panelLoot:AddChild(panel) + + local scrollRanks = AceGUI:Create("AmrUiScrollFrame") + scrollRanks:SetLayout("List") + panel:AddChild(scrollRanks) + + -- find min and max value, used for sizing the bars + local rankMin = -0.02 + local rankMax = 0.02 + for j, rank in ipairs(ranking.ranks) do + if rank.score < rankMin then + rankMin = rank.score + end + if rank.score > rankMax then + rankMax = rank.score + end + end + + -- just make min less than max if they are the same, doesn't really matter what it is, would be a wacky case + if rankMin == rankMax then + rankMin = rankMax - 1 + end + + local minWidth = 10 + local maxWidth = _widthRankBar - 36 - 65 - 2 -- reserve 36 for icon, 65 for bar label, and 2 for a border around the bar + local rankCount = 0 + + for j, rank in ipairs(ranking.ranks) do + local unitId = Amr:GetUnitId(rank.realm, rank.name) + if unitId then + local skip = false + if isDisenchant then + skip = true + if rank.isMasterLooter or (rank.enchantingSkill and rank.enchantingSkill > 0) then + skip = false + end + end + + if not skip then + rankCount = rankCount + 1 + + local rp = AceGUI:Create("AmrUiPanel") + rp:SetLayout("None") + rp:SetBackgroundColor(Amr.Colors.Black, 0) + rp:SetWidth(_widthRankList) + rp:SetHeight(45) + scrollRanks:AddChild(rp) + _rankPanels[j] = rp + + if not isDisenchant then + panel = AceGUI:Create("AmrUiPanel") + panel:SetBackgroundColor(Amr.Colors.Black, 1) + panel:SetPoint("TOPLEFT", rp.content, "BOTTOMLEFT", 0, 0) + panel:SetPoint("BOTTOMRIGHT", rp.content, "BOTTOMRIGHT", -120, -1) + rp:AddChild(panel) + end + + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetFont(Amr.CreateFont("Bold", 32, Amr.Colors.White)) + lbl:SetText(rankCount) + lbl:SetWidth(_widthRank - 6) + lbl:SetJustifyH("RIGHT") + lbl:SetPoint("BOTTOMLEFT", rp.content, "BOTTOMLEFT", 0, 3) + rp:AddChild(lbl) + + local cls, clsEn = UnitClass(unitId) + local color = clsEn and Amr.Colors.Classes[clsEn] or Amr.Colors.TextHeaderDisabled + + local icon = AceGUI:Create("AmrUiIcon") + icon:SetIconBorderColor(color) + icon:SetWidth(36) + icon:SetHeight(36) + icon:SetIcon("Interface\\Icons\\" .. Amr.SpecIcons[rank.specId]) + icon:SetPoint("BOTTOMLEFT", rp.content, "BOTTOMLEFT", 48 + 8, 0) + rp:AddChild(icon) + + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetFont(Amr.CreateFont("Bold", 16, color)) + lbl:SetText(UnitName(unitId)) + lbl:SetWidth(_widthRankBar - 36 - 8) -- 4px on left and right side + lbl:SetPoint("TOPLEFT", icon.frame, "TOPRIGHT", 4, -2) + rp:AddChild(lbl) + + if isDisenchant or rank.notRanked then + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetFont(Amr.CreateFont("Italic", 13, Amr.Colors.TextHeaderDisabled)) + lbl:SetWidth(_widthRankBar - 36 - 4) -- 4px on left side + lbl:SetWordWrap(false) + lbl:SetPoint("BOTTOMLEFT", icon.frame, "BOTTOMRIGHT", 4, 2) + rp:AddChild(lbl) + + if isDisenchant then + -- will be disenchanter or ML if we are DEing the item + lbl:SetText((rank.enchantingSkill and rank.enchantingSkill > 0) and string.format(L.LootRankLabelDisenchant .. " (%d)", rank.enchantingSkill) or L.LootRankLabelMasterLooter) + else + -- if this is off spec or just a disenchanter, no score bar just description text + lbl:SetText(rank.offspec and L.LootRankLabelOff or ((rank.enchantingSkill and rank.enchantingSkill > 0) and string.format(L.LootRankLabelDisenchant .. " (%d)", rank.enchantingSkill) or L.LootRankLabelMasterLooter)) + end + else + local scoreText = rank.score .. "%" + local val = rank.score; + if rank.isEquipped then + scoreText = "E" + val = 0 + elseif val >= 0 then + scoreText = "+" .. scoreText + end + + local per = (val - rankMin) / (rankMax - rankMin); + local w = minWidth + (per * (maxWidth - minWidth)); + color = val > 0 and Amr.Colors.BarHigh or (val == 0 and Amr.Colors.BarMed or Amr.Colors.BarLow) + + panel = AceGUI:Create("AmrUiPanel") + panel:SetLayout("None") + panel:SetWidth(w + 2) + panel:SetHeight(16) + panel:SetBackgroundColor(Amr.Colors.Black, 1) + panel:SetPoint("BOTTOMLEFT", icon.frame, "BOTTOMRIGHT", 0, -1) + rp:AddChild(panel) + + panel2 = AceGUI:Create("AmrUiPanel") + panel2:SetLayout("None") + panel2:SetWidth(w) + panel2:SetHeight(14) + panel2:SetBackgroundColor(color, 1) + panel2:SetPoint("TOPLEFT", panel.content, "TOPLEFT", 1, -1) + panel:AddChild(panel2) + + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetFont(Amr.CreateFont("Bold", 13, color)) + lbl:SetText(scoreText) + lbl:SetWidth(63) + lbl:SetWordWrap(false) + lbl:SetPoint("LEFT", panel.content, "RIGHT", 2, 0) + rp:AddChild(lbl) + end + + if ml then + btn2 = AceGUI:Create("AmrUiButton") + btn2:SetHeight(24) + btn2:SetFont(Amr.CreateFont("Regular", 13, Amr.Colors.White)) + btn2:SetBackgroundColor(Amr.Colors.Green) + + if isDisenchant then + btn2:SetWidth(200) + btn2:SetText(L.LootMasterGiveDisenchant) + btn2:SetPoint("LEFT", rp.content, "LEFT", _widthRank + _widthRankBar + (3 * _widthColPadding), 0) + else + btn2:SetWidth(85) + btn2:SetText(L.LootMasterGiveLoot) + btn2:SetPoint("RIGHT", rp.content, "RIGHT", -30, 0) + end + + btn2:SetUserData("index", j) + btn2:SetCallback("OnClick", onGiveLootClick) + rp:AddChild(btn2) + end + end + + end + end + + end + + end + + else + local lbl = AceGUI:Create("AmrUiLabel") + lbl:SetFont(Amr.CreateFont("Italic", 16, Amr.Colors.TextTan)) + lbl:SetWidth(800) + lbl:SetText(L.LootEmpty) + lbl:SetPoint("CENTER", _panelLoot.content, "CENTER") + _panelLoot:AddChild(lbl) + end + +end + +-- select a particular loot item to display +function Amr:SelectLootItem(index) + _selectedIndex = index + self:RefreshLootWindow() + self:RefreshLootRolls() +end + +local function onLootFrameClose(widget) + AceGUI:Release(widget) + _frameLoot = nil + _panelLoot = nil + _rankPanels = nil + _lootButtons = nil +end + +function Amr:HideLootWindow() + if not _frameLoot then return end + _frameLoot:Hide() +end + +function Amr:ShowLootWindow() + if not _frameLoot then + _frameLoot = AceGUI:Create("AmrUiFrame") + _frameLoot:SetStatusTable(Amr.db.profile.lootWindow) -- window position is remembered in db + _frameLoot:SetCallback("OnClose", onLootFrameClose) + _frameLoot:SetLayout("None") + _frameLoot:SetWidth(900) + _frameLoot:SetHeight(600) + _frameLoot:SetBorderColor(Amr.Colors.BorderBlue) + _frameLoot:SetBackgroundColor(Amr.Colors.Bg) + + local lbl = AceGUI:Create("AmrUiLabel") + lbl:SetWidth(600) + lbl:SetFont(Amr.CreateFont("Bold", 28, Amr.Colors.White)) + lbl:SetText(L.LootTitle) + lbl:SetWordWrap(false) + lbl:SetJustifyH("CENTER") + lbl:SetPoint("TOP", _frameLoot.content, "TOP", 0, 30) + _frameLoot:AddChild(lbl) + + lbl:SetCallback("OnMouseDown", function(widget) _frameLoot:StartMove() end) + lbl:SetCallback("OnMouseUp", function(widget) _frameLoot:EndMove() end) + + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetWidth(_widthItemList) + lbl:SetFont(Amr.CreateFont("Regular", 18, Amr.Colors.TextHeaderActive)) + lbl:SetText(L.LootHelpItems) + lbl:SetPoint("TOPLEFT", _frameLoot.content, "TOPLEFT", 0, -10) + _frameLoot:AddChild(lbl) + + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetWidth(_widthItemList) + lbl:SetFont(Amr.CreateFont("Regular", 18, Amr.Colors.TextHeaderActive)) + lbl:SetText(L.LootHelpRanks) + lbl:SetPoint("TOPLEFT", _frameLoot.content, "TOPLEFT", _widthItemList + _widthSpacing, -10) + _frameLoot:AddChild(lbl) + + if IsMasterLooter() then + lbl = AceGUI:Create("AmrUiLabel") + lbl:SetWidth(_widthItemList) + lbl:SetFont(Amr.CreateFont("Regular", 18, Amr.Colors.TextHeaderActive)) + lbl:SetText(L.LootHelpMaster) + lbl:SetPoint("TOPLEFT", _frameLoot.content, "TOPLEFT", _widthItemList + _widthSpacing + _widthRank + _widthRankBar + _widthRollType + (_widthColPadding * 3), -10) + _frameLoot:AddChild(lbl) + end + + _panelLoot = AceGUI:Create("AmrUiPanel") + _panelLoot:SetLayout("None") + _panelLoot:SetBackgroundColor(Amr.Colors.Black, 0) + _panelLoot:SetPoint("TOPLEFT", _frameLoot.content, "TOPLEFT", 0, -40) + _panelLoot:SetPoint("BOTTOMRIGHT", _frameLoot.content, "BOTTOMRIGHT", 0, 0) + _frameLoot:AddChild(_panelLoot) + else + _frameLoot:Show() + end + + _frameLoot:Raise() +end + +function Amr:OnStartLootReceived(parts) + local data = {} + for i = 2, #parts do + table.insert(data, parts[i]) + end + data = table.concat(data, "\n") + + -- reset rankings to the new data sent out by person in control + local rankings = Amr:ParseRankingString(data) + Amr.db.global.TeamOpt.Rankings = rankings + + -- reset disenchant state + _disenchant = {} + + -- reset roll information when loot is started + local rolls = {} + for i = 1, #rankings do + table.insert(rolls, {}) + end + Amr.db.char.TeamOpt.Rolls = rolls + + -- select first item by default + _selectedIndex = #rankings > 0 and 1 or nil + + -- begin looting + Amr.db.char.TeamOpt.LootInProgress = true + + Amr:RefreshTeamUi() + Amr:ShowLootWindow() + Amr:RefreshLootWindow() +end