local addon, ns = ... ns.DB = setmetatable({}, {__index = function(t, k) return _G[addon .. "DB"][k] end}) ns.Events = CreateFrame("Frame", addon .. "Frame", UIParent) ns.Functions = {} ns.Locals = function() return ns.DB, ns.Events, ns.Functions, ns.Strings, ns.L end local db, events, F, S, L = ns:Locals() -------------------- * // ** GENERAL FUNCTIONS ** // * -------------------- function F:count(table) local counter = 0 for k, v in pairs(table) do counter = counter + 1 end return counter end function F:InTable(table, value) local found = false for k, v in pairs(table) do if v == value then return k end end return false end F.pairsByKeys = function(_, t, f) local a = {} for n in pairs(t) do table.insert(a, n) end table.sort(a, f) local i = 0 -- iterator variable local iter = function () -- iterator function i = i + 1 if a[i] == nil then return nil else return a[i], t[a[i]] end end return iter end function F:Print(msg) local prefix = "|cff71C671(LMT) |r" print(prefix .. msg) end function F:SendChatMessage(msg, rw) local channel rw = rw or false for i = 1, GetNumGroupMembers() do if GetRaidRosterInfo(i) == GetUnitName("PLAYER") then channel = ((UnitInRaid("PLAYER") and select(2, GetRaidRosterInfo(i))>0) and rw) and "RAID_WARNING" or (UnitInRaid("PLAYER") and "RAID" or "PARTY") end end SendChatMessage("(LMT) " .. msg, channel) end -------------------- * // ** ADDON FUNCTIONS ** // * -------------------- function ns:ValidateDatabase() local currentVersion = GetAddOnMetadata(addon, "Version") local defaults = { reserves = {}, settings = { AssignToRandomTimer = 10, ConfirmAssignToRandom = false, ConfirmRollAndAssign = false, HideConfirmation = false, RollAndAssignTimer = 10, SortByName = true }, version = currentVersion } if db and not db.version then -- Fixing db.version 1.0 db.AssignToRandomTimer = db.AssignToRandomTimer or db.RandomTimer db.RollAndAssignTimer = db.RollAndAssignTimer or db.RollTimer db.ConfirmAssignToRandom = db.ConfirmAssignToRandom or db.ConfirmRandom -- elseif db and db.version < currentVersion then -- if db.version == 2.0 then -- end end LootMasterToolsDB = LootMasterToolsDB or defaults for k, v in pairs(db.settings) do if defaults.settings[k] == nil then db.settings[k] = nil end end for k, v in pairs(defaults.settings) do if db.settings[k] == nil then db.settings[k] = v end end LootMasterToolsDB.version = (db.version and db.version == currentVersion) and db.version or currentVersion end -------------------- * // ** Loot.lua ** // * -------------------- local rollers = {} local slots = {} function F:AssignLoot(type, item, winner, open_rolls) local itemLink, winnerName, losers, tie_announce if type == "roll" then itemLink = F:GetRollItemLink(item) winner, losers, tie_announce = F:GetRollWinner(item, itemLink) if winner == "" then F:Print(string.format(S.LootError1, itemLink)) return end winnerName = winner[1] elseif type == "loot" then itemLink = item winnerName = winner elseif type == "random" then itemLink = item winner, losers, tie_announce = F:GetRandomWinner(item, itemLink) winnerName = winner[1] end local itemSlot = F:GetLootSlot(itemLink) if not winnerName or not itemSlot then return end local itemQTY for i = 1, MAX_RAID_MEMBERS do if GetMasterLootCandidate(itemSlot, i) == winnerName then itemQTY = F:CountQuantity(itemLink) GiveMasterLoot(itemSlot, i) slots[itemSlot] = {itemLink, itemQTY, type, tie_announce, winnerName, winner, losers, open_rolls} break end end end function events:LOOT_SLOT_CLEARED(event, slot, ...) if slots[slot] == nil then return end local itemLink = slots[slot][1] local itemQTY = slots[slot][2] local type = slots[slot][3] local tie_announce = slots[slot][4] local winnerName = slots[slot][5] local winner = slots[slot][6] local losers = slots[slot][7] local open_rolls = slots[slot][8] if F:CountQuantity(itemLink) < itemQTY then if type == "roll" then if tie_announce then F:SendChatMessage(string.format(S.TieBreaker, tie_announce, itemLink), true) F:SendChatMessage(string.format(S.Winner, winnerName, winner[3])) F:SendChatMessage(S.Losers .. F:ParseLosers(losers, winner[2])) end elseif type == "random" then F:SendChatMessage(string.format(S.RandomLootAnnouncement, itemLink), true) if tie_announce then F:SendChatMessage(string.format(S.TieBreaker, tie_announce, itemLink), true) end F:SendChatMessage(string.format(S.Winner, winnerName, winner[3])) F:SendChatMessage(S.Losers .. F:ParseLosers(losers, winner[2])) end for k, v in pairs(open_rolls) do if itemLink == v then open_rolls[k] = nil break end end else F:Print(string.format(S.LootError2, itemLink, winnerName)) end if F:count(open_rolls) == 0 then events:UnregisterEvent("LOOT_ROLLS_COMPLETE") end slots[slot] = nil end function F:CountQuantity(itemLink) local available = 0 for i = 1, GetNumLootItems() do if GetLootSlotLink(i) == itemLink then available = available + 1 end end return available end function F:GetLootSlot(itemLink) if not LootFrame:IsVisible() then return end for i = 1, GetNumLootItems() do local link = GetLootSlotLink(i) if link == itemLink then return i end end end function F:GetRandomWinner(item, itemLink) local winner table.wipe(rollers) for i = 1, GetNumGroupMembers() do rollers[i] = {2, math.floor(math.random(1, 100)), GetRaidRosterInfo(i)} end return F:ParseRolls(rollers, itemLink) end function F:GetRollItemLink(item) for i = 1, C_LootHistory.GetNumItems() do local rollID, itemLink = C_LootHistory.GetItem(i) if rollID == item then return itemLink end end end function F:GetRollWinner(item, itemLink) for i = 1, C_LootHistory.GetNumItems() do local rollID, itemLink, numPlayers, isDone = C_LootHistory.GetItem(i) if rollID == item and isDone then table.wipe(rollers) for x = 1, numPlayers do local name, _, type, roll = C_LootHistory.GetPlayerInfo(i, x) rollers[x] = {type, roll, name} end return F:ParseRolls(rollers, itemLink) end end end function F:PlayerEligibleForLoot(name, slot) for i = 1, GetNumGroupMembers() do local player = GetRaidRosterInfo(i) if player == name then for x = 1, GetNumGroupMembers() do if GetMasterLootCandidate(slot, x) == name then return select(7, GetRaidRosterInfo(i)) == GetInstanceInfo() and true end end end end end function F:ParseLosers(losers, winnerID) losers[winnerID] = nil local msg = "" for k, v in pairs(losers) do if msg == "" then msg = v[3] .. " (" .. v[2] .. ")" else msg = msg .. ", " .. v[3] .. " (" .. v[2] .. ")" end end return msg end local priorities = { [0] = 1, -- pass [1] = 3, -- need [2] = 2, -- greed [3] = 2 -- disenchant } local tied = {} function F:ParseRolls(rolls, itemLink) local winnerName, winnerID local highPriority = 0 local highRoll = 0 for k, v in pairs(rollers) do local priority = priorities[v[1]] local roll = v[2] local name = v[3] local eligible = F:PlayerEligibleForLoot(name, 1) if roll and eligible then if priority > highPriority then table.wipe(tied) winnerName = name winnerID = k highRoll = roll highPriority = priority elseif priority == highPriority then if roll > highRoll then table.wipe(tied) winnerName = name winnerID = k highRoll = roll highPriority = priority elseif roll == highRoll then if itemLink and highPriority > 0 then tinsert(tied, {name, k}) else local tie_breaker = math.floor(math.random(1, 100)) while tie_breaker == highRoll do tie_breaker = math.floor(math.random(1, 100)) end if tie_breaker > highRoll then table.wipe(tied) winnerName = name winnerID = k highRoll = roll highPriority = priority else roll = tie_breaker end end end end elseif not eligible then rollers[k] = nil end end local names if not winnerID then return "" elseif F:count(tied) > 0 then tinsert(tied, {winnerName, winnerID}) highRoll = 0 for k, v in pairs(tied) do roll = math.floor(math.random(1, 100)) while roll == highRoll do roll = math.floor(math.random(1, 100)) end if roll > highRoll then winnerName = v[1] winnerID = v[2] highRoll = roll end rollers[v[2]] = {2, roll, v[1]} names = (k == F:count(tied) and (names .. L[" and "]) or (names and (names .. ", ") or "")) .. v[1] end table.wipe(tied) end local winner = {winnerName, winnerID, highRoll} return winner, rollers, names end function F:ProcessOpenRolls(open_rolls) if not LootFrame:IsVisible() then return end for i = 1, GetNumLootItems() do local itemLink = GetLootSlotLink(i) for k, v in pairs(open_rolls) do if itemLink == v then for x = 1, C_LootHistory.GetNumItems() do local rollID, _, _, isDone = C_LootHistory.GetItem(x) if rollID == k and isDone then F:AssignLoot("roll", rollID, nil, open_rolls) end end end end end end