Quantcast

Added LootManager, various other cleanups and fixes done.

F16Gaming [03-22-12 - 20:13]
Added LootManager, various other cleanups and fixes done.
Filename
Command.lua
CommandManager.lua
LootManager.lua
PlayerManager.lua
RollManager.lua
String.lua
Table.lua
load.xml
diff --git a/Command.lua b/Command.lua
index 23ffe50..2481902 100644
--- a/Command.lua
+++ b/Command.lua
@@ -32,7 +32,7 @@
 Command = {
 	Name = "Command",
 	Version = GetAddOnMetadata("Command", "Version"),
-	VersionNum = 4, -- Increment on every release
+	VersionNum = 5, -- Increment on every release
 	VersionChecked = false, -- Prevent spam of "New Version" notice
 	Loaded = false,
 	VarVersion = 2,
diff --git a/CommandManager.lua b/CommandManager.lua
index 092b853..948b54e 100644
--- a/CommandManager.lua
+++ b/CommandManager.lua
@@ -38,6 +38,7 @@ local CM = C.CommandManager
 local PM = C.PlayerManager
 local QM = C.QueueManager
 local RM = C.RollManager
+local LM = C.LootManager
 local GT = C.GroupTools
 local CES = C.Extensions.String
 local CET = C.Extensions.Table
@@ -77,6 +78,7 @@ end
 -- @param command Command name to check.
 --
 function CM:HasCommand(command)
+	command = command:lower()
 	if self.Commands[command] then return true end
 	for _,v in pairs(self.Commands) do
 		if CET:HasValue(v.Alias, command) then return true end
@@ -89,6 +91,7 @@ end
 -- @return Callback for the command, nil if no command was found.
 --
 function CM:GetCommand(command)
+	command = command:lower()
 	if self.Commands[command] then
 		return self.Commands[command]
 	end
@@ -99,6 +102,7 @@ function CM:GetCommand(command)
 end

 function CM:GetRealName(name)
+	name = name:lower()
 	if self.Commands[name] then return name end
 	for k,v in pairs(self.Commands) do
 		if CET:HasValue(v.Alias, name) then return k end
@@ -130,6 +134,7 @@ end
 -- @return Error message if not successful, otherwise nil.
 --
 function CM:HandleCommand(command, args, isChat, player)
+	command = command:lower()
 	local cmd = self:GetCommand(command)
 	if cmd then
 		if isChat then
@@ -154,6 +159,9 @@ function CM:AutoHelp()
 end

 CM:Register({"__DEFAULT__", "help", "h"}, PM.Access.Local, function(args, sender, isChat)
+	if isChat then
+		return "Type !commands for a listing of commands available."
+	end
 	CM:AutoHelp()
 	return "End of help message."
 end, "Prints this help message.")
@@ -164,11 +172,7 @@ CM:Register({"commands", "cmds", "cmdlist", "listcmds", "listcommands", "command
 		all = args[1] == "all"
 	end
 	local cmds = CM:GetCommands(all)
-	local msg = ""
-	for _,v in pairs(cmds) do
-		msg = msg .. v .. ", "
-	end
-	return CES:Cut(msg, 240)
+	return CES:Fit(cmds, 240, ", ") -- Max length is 255, "[Command] " takes up 10. This leaves us with 5 characters grace.
 end, "Print all registered commands.")

 CM:Register({"version", "ver", "v"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
@@ -176,35 +180,41 @@ CM:Register({"version", "ver", "v"}, PM.Access.Groups.User.Level, function(args,
 end, "Print the version of Command")

 CM:Register({"lock", "lockdown"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
-	if #args <= 0 then
-		return false, "Too few arguments. Usage: lock <player>"
+	if type(args[1]) == "string" then
+		return PM:SetLocked(PM:GetOrCreatePlayer(args[1]), true)
+	else
+		return PM:SetLocked(sender, true)
 	end
-	local player = PM:GetOrCreatePlayer(args[1])
-	return PM:SetLocked(player, true)
 end, "Lock a player.")

 CM:Register({"unlock", "open"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
-	if #args <= 0 then
-		return false, "Too few arguments. Usage: lock <player>"
+	if type(args[1]) == "string" then
+		return PM:SetLocked(PM:GetOrCreatePlayer(args[1]), false)
+	else
+		return PM:SetLocked(sender, false)
 	end
-	local player = PM:GetOrCreatePlayer(args[1])
-	return PM:SetLocked(player, false)
 end, "Unlock a player.")

 CM:Register({"getaccess"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
-	if #args <= 0 then
-		return false, "Too few arguments. Usage: getaccess <player>"
+	local msg = "%s's access is %d (%s)"
+	if type(args[1]) == "string" then
+		local player = PM:GetOrCreatePlayer(args[1])
+		return msg:format(player.Info.Name, PM.Access.Groups[player.Info.Group].Level, player.Info.Group)
+	else
+		return msg:format(sender.Info.Name, PM.Access.Groups[sender.Info.Group].Level, sender.Info.Group)
 	end
-	local player = PM:GetOrCreatePlayer(args[1])
-	return tostring(PM.Access.Groups[player.Info.Group].Level) .. " (" .. tostring(player.Info.Group) .. ")"
 end, "Get the access level of a user.")

 CM:Register({"setaccess"}, PM.Access.Local, function(args, sender, isChat)
-	if #args <= 1 then
-		return false, "Too few arguments. Usage: setaccess <player> <group>"
+	if #args < 1 then
+		return false, "Too few arguments. Usage: setaccess [player] <group>"
+	end
+	if #args >= 2 then
+		local player = PM:GetOrCreatePlayer(args[1])
+		return PM:SetAccessGroup(player, args[2])
+	else
+		return PM:SetAccessGroup(sender, args[1])
 	end
-	local player = PM:GetOrCreatePlayer(args[1])
-	return PM:SetAccessGroup(player, args[2])
 end, "Set the access level of a user.")

 CM:Register({"owner"}, PM.Access.Local, function(args, sender, isChat)
@@ -216,30 +226,32 @@ CM:Register({"owner"}, PM.Access.Local, function(args, sender, isChat)
 end, "Promote a player to owner rank.")

 CM:Register({"admin"}, PM.Access.Groups.Owner.Level, function(args, sender, isChat)
-	if #args <= 0 then
-		return false, "Missing argument: name"
-	end
 	if isChat then
 		return false, "This command is not allowed to be used from the chat."
 	end
+	if #args <= 0 then
+		return false, "Missing argument: name"
+	end
 	local player = PM:GetOrCreatePlayer(args[1])
 	return PM:SetAdmin(player)
 end, "Promote a player to admin rank.")

 CM:Register({"op"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
-	if #args <= 0 then
-		return false, "Missing argument: name"
+	if type(args[1]) == "string" then
+		local player = PM:GetOrCreatePlayer(args[1])
+		return PM:SetOp(player)
+	else
+		return PM:SetOp(sender)
 	end
-	local player = PM:GetOrCreatePlayer(args[1])
-	return PM:SetOp(player)
 end, "Promote a player to op rank.")

 CM:Register({"user"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
-	if #args <= 0 then
-		return false, "Missing argument: name"
+	if type(args[1]) == "string" then
+		local player = PM:GetOrCreatePlayer(args[1])
+		return PM:SetUser(player)
+	else
+		return PM:SetUser(sender)
 	end
-	local player = PM:GetOrCreatePlayer(args[1])
-	return PM:SetUser(player)
 end, "Promote a player to user rank.")

 CM:Register({"ban"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
@@ -251,11 +263,12 @@ CM:Register({"ban"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat
 end, "Ban a player.")

 CM:Register({"invite", "inv"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
-	if #args <= 0 then
-		return false, "Missing argument: name"
+	if type(args[1]) == "string" then
+		local player = PM:GetOrCreatePlayer(args[1])
+		return PM:Invite(player, sender)
+	else
+		return PM:Invite(sender, sender)
 	end
-	local player = PM:GetOrCreatePlayer(args[1])
-	return PM:Invite(player, sender)
 end, "Invite a player to group.")

 CM:Register({"inviteme", "invme"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
@@ -496,7 +509,7 @@ CM:Register({"readycheck", "rc"}, PM.Access.Groups.Op.Level, function(args, send
 		return false, "Ready check not running or I have already responded."
 	end
 	local arg = tostring(args[1]):lower()
-	if arg == "accept" or arg == "yes" then
+	if arg:match("^[ay]") then -- Accept
 		C.Data.ReadyCheckRunning = false
 		if ReadyCheckFrameYesButton then
 			ReadyCheckFrameYesButton:Click()
@@ -504,7 +517,7 @@ CM:Register({"readycheck", "rc"}, PM.Access.Groups.Op.Level, function(args, send
 		ConfirmReadyCheck(true)
 		status = GetReadyCheckStatus("player")
 		return "Accepted ready check."
-	elseif arg == "decline" or arg == "no" then
+	elseif arg:match("^[dn]") then -- Decline
 		C.Data.ReadyCheckRunning = false
 		if ReadyCheckFrameNoButton then
 			ReadyCheckFrameNoButton:Click()
@@ -518,12 +531,52 @@ CM:Register({"readycheck", "rc"}, PM.Access.Groups.Op.Level, function(args, send
 	return false, "Failed to accept or decline ready check."
 end, "Respond to ready check or initate a new one.")

+CM:Register({"loot", "l"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+	local usage = "Usage: loot <type||threshold||master||pass>"
+	if #args <= 0 then
+		return false, usage
+	end
+	args[1] = args[1]:lower()
+	if args[1]:match("^ty") or args[1]:match("^me") or args[1] == "t" then
+		if #args < 2 then
+			return false, "No loot method specified."
+		end
+		local method = args[2]:lower()
+		return LM:SetLootMethod(method, args[3])
+	elseif args[1]:match("^th") or args[1]:match("^l") then
+		if #args < 2 then
+			return false, "No loot threshold specified."
+		end
+		return LM:SetLootThreshold(args[2])
+	elseif args[1]:match("^m") then
+		if #args < 2 then
+			return false, "No master looter specified."
+		end
+		return LM:SetLootMaster(args[2])
+	elseif args[1]:match("^p") then
+		local p = args[2]
+		if type(p) == "string" then
+			if p:lower():match("^[eay]") then
+				p = true
+			elseif p:lower():match("^[dn]") then
+				p = false
+			else
+				p = nil
+			end
+		else
+			p = nil
+		end
+		return LM:SetLootPass(p)
+	end
+	return false, usage
+end, "Provides various loot functions.")
+
 CM:Register({"roll", "r"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
 	if #args <= 0 then
 		return RM:StartRoll(sender.Info.Name)
 	end
 	args[1] = args[1]:lower()
-	if args[1] == "start" then
+	if args[1]:match("^sta") then
 		if #args < 2 then
 			return false, "Usage: roll start <[time] [item]>"
 		end
@@ -545,39 +598,39 @@ CM:Register({"roll", "r"}, PM.Access.Groups.Op.Level, function(args, sender, isC
 			end
 		end
 		return RM:StartRoll(sender.Info.Name, item, time)
-	elseif args[1] == "pass" then
+	elseif args[1]:match("^p") then
 		return RM:PassRoll(sender.Info.Name)
-	elseif args[1] == "stop" then
+	elseif args[1]:match("^sto") then
 		return RM:StopRoll()
-	elseif args[1] == "time" then
+	elseif args[1]:match("^t") then
 		return RM:GetTime()
-	elseif args[1] == "do" then
+	elseif args[1]:match("^d") then
 		local min, max
 		if #args >= 3 then
 			min = tonumber(args[2])
 			max = tonumber(args[3])
 		end
-		if not min and (args[2] == "pass" or args[2] == "p" or args[2] == "skip") then
+		if not min and args[2]:match("^[ps]") then
 			return RM:PassRoll()
 		else
 			return RM:DoRoll(min, max)
 		end
-	elseif args[1] == "set" then
+	elseif args[1]:match("^se") then
 		if #args < 3 then
-			return false, "Usage: roll set <min||max> <amount>"
+			return false, "Usage: roll set <min||max||time> <amount>"
 		end
 		args[2] = args[2]:lower()
-		if args[2] == "min" then
+		if args[2]:match("^mi") then
 			return RM:SetMin(tonumber(args[3]))
-		elseif args[2] == "max" then
+		elseif args[2]:match("^ma") then
 			return RM:SetMax(tonumber(args[3]))
-		elseif args[2] == "time" then
+		elseif args[2]:match("^t") then
 			return RM:SetTime(tonumber(args[3]))
 		else
-			return false, "Usage: roll set <min||max> <amount>"
+			return false, "Usage: roll set <min||max||time> <amount>"
 		end
 	end
-	return false, "Usage: roll [start||stop||time||do||set]"
+	return false, "Usage: roll [start||stop||pass||time||do||set]"
 end, "Provides tools for managing or starting/stopping rolls.")

 for i,v in ipairs(CM.Slash) do
@@ -596,7 +649,13 @@ SlashCmdList[C.Name:upper()] = function(msg, editBox)
 	end
 	local result, err = CM:HandleCommand(cmd, t, false, PM:GetOrCreatePlayer(UnitName("player")))
 	if result then
-		C.Logger:Normal(tostring(result))
+		if type(result) == "table" then
+			for _,v in ipairs(result) do
+				C.Logger:Normal(tostring(v))
+			end
+		else
+			C.Logger:Normal(tostring(result))
+		end
 	else
 		C.Logger:Error(tostring(err))
 	end
diff --git a/LootManager.lua b/LootManager.lua
new file mode 100644
index 0000000..2e06edb
--- /dev/null
+++ b/LootManager.lua
@@ -0,0 +1,158 @@
+--[[
+	* Copyright (c) 2011 by Adam Hellberg.
+	*
+	* This file is part of Command.
+	*
+	* Command is free software: you can redistribute it and/or modify
+	* it under the terms of the GNU General Public License as published by
+	* the Free Software Foundation, either version 3 of the License, or
+	* (at your option) any later version.
+	*
+	* Command is distributed in the hope that it will be useful,
+	* but WITHOUT ANY WARRANTY; without even the implied warranty of
+	* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	* GNU General Public License for more details.
+	*
+	* You should have received a copy of the GNU General Public License
+	* along with Command. If not, see <http://www.gnu.org/licenses/>.
+--]]
+
+local C = Command
+
+--- Table holding all LootManager methods.
+-- This is referenced "LM" in LootManager.lua.
+-- @name Command.LootManager
+-- @class table
+--
+C.LootManager = {
+}
+
+local LM = C.LootManager
+local GT = C.GroupTools
+
+local function ParseLootMethod(method)
+	if type(method) ~= "string" then return "group" end
+	method = method:lower()
+	if method:match("^f") then
+		return "freeforall"
+	elseif method:match("^g") then
+		return "group"
+	elseif method:match("^m") then
+		return "master"
+	elseif method:match("^n") then
+		return "needbeforegreed"
+	elseif method:match("^r") then
+		return "roundrobin"
+	end
+	return "group"
+end
+
+local function ParseThreshold(threshold)
+	if type(threshold) == "string" then
+		threshold = threshold:lower()
+		if threshold:match("^[ug]") then -- Uncommon/Green
+			return 2
+		elseif threshold:match("^[rsb]") then -- Rare/Superior/Blue
+			return 3
+		elseif threshold:match("^[ep]") then -- Epic/Purple
+			return 4
+		elseif threshold:match("^[lo]") then -- Legendary/Orange
+			return 5
+		elseif threshold:match("^a") then -- Artifact
+			return 6
+		elseif threshold:match("^h") then -- Heirloom
+			return 7
+		end
+	elseif type(threshold) == "number" then
+		return threshold
+	end
+	return 0
+end
+
+local function PrettyThreshold(level)
+	if level == 2 then
+		return "Uncommon"
+	elseif level == 3 then
+		return "Rare"
+	elseif level == 4 then
+		return "Epic"
+	elseif level == 5 then
+		return "Legendary"
+	elseif level == 6 then
+		return "Artifact"
+	elseif level == 7 then
+		return "Heirloom"
+	end
+	return "Unknown"
+end
+
+function LM:SetLootMethod(method, master)
+	if not GT:IsGroupLeader() then
+		return false, "Unable to change loot method, not group leader."
+	end
+	method = ParseLootMethod(method)
+	if method == GetLootMethod() then
+		return false, "The loot method is already set to " .. method .. "!"
+	elseif method == "master" then
+		if not master then
+			master = UnitName("player")
+			--return false, "A master looter must be specified when setting loot method to Master Loot."
+		elseif not GT:IsInGroup(master) then
+			return false, ("%q is not in the group and cannot be set as the master looter."):format(master)
+		end
+		SetLootMethod(method, master)
+		return ("Successfully set the loot method to %s (%s)!"):format(method, master)
+	end
+	SetLootMethod(method)
+	return ("Successfully set the loot method to %s!"):format(method)
+end
+
+function LM:SetLootMaster(master)
+	if not GT:IsGroupLeader() then
+		return false, "Unable to change master looter, not group leader."
+	end
+	local method = GetLootMethod()
+	if method ~= "master" then
+		return false, "Cannot set master looter when loot method is set to " .. method
+	end
+	if not master then
+		return false, "Master looter not specified."
+	elseif not GT:IsInGroup(master) then
+		return false, ("%q is not in the group and cannot be set as the master looter."):format(master)
+	end
+	SetLootMethod("master", master)
+	return ("Successfully set %s as the master looter!"):format(master)
+end
+
+function LM:SetLootThreshold(threshold)
+	if not GT:IsGroupLeader() then
+		return false, "Unable to change loot threshold, not group leader."
+	end
+	threshold = ParseThreshold(threshold)
+	if threshold < 2 or threshold > 7 then
+		return false, "Invalid loot threshold specified, please specify a loot threshold between 2 and 7 (inclusive)."
+	end
+	SetLootThreshold(threshold)
+	return "Successfully set the loot threshold to " .. PrettyThreshold(threshold) .. "!"
+end
+
+function LM:SetLootPass(pass)
+	local msg = UnitName("player") .. " is %s passing on loot."
+	if type(pass) == "nil" then
+		local current = GetOptOutOfLoot()
+		SetOptOutOfLoot(not current)
+		if current then
+			msg = msg:format("not")
+		else
+			msg = msg:format("now")
+		end
+	else
+		SetOptOutOfLoot(pass)
+		if pass then
+			msg = msg:format("now")
+		else
+			msg = msg:format("not")
+		end
+	end
+	return msg
+end
diff --git a/PlayerManager.lua b/PlayerManager.lua
index 22cd028..1494f1b 100644
--- a/PlayerManager.lua
+++ b/PlayerManager.lua
@@ -178,7 +178,7 @@ end
 -- @return Player from list of players if exists, otherwise a new player object.
 --
 function PM:GetOrCreatePlayer(name)
-	name = name:gsub("^%l", string.upper)
+	name = name:lower():gsub("^%l", string.upper)
 	if CET:HasKey(Players, name) then
 		return Players[name]
 	else
diff --git a/RollManager.lua b/RollManager.lua
index c6c1c5c..1018b4d 100644
--- a/RollManager.lua
+++ b/RollManager.lua
@@ -58,13 +58,13 @@ local function RollTimerUpdate(_, elapsed)
 		RollTimer.LastWarning = ceil(RollTimer.Current)
 	end

-	if RollTimer.Current < RollTimer.Time then return end
+	if RollTimer.Current < RollTimer.Time and RollCount < RM.NumGroupMembers then return end

 	RollTimer.Frame:SetScript("OnUpdate", nil)
 	RollTimer.Current = 0
 	RollTimer.LastWarning = 0

-	RM:StopRoll(true, true)
+	RM:StopRoll(true, RollCount < RM.NumGroupMembers)
 end

 function RM:Init()
@@ -184,7 +184,7 @@ function RM:AddRoll(name, roll)
 	Rollers[name] = tonumber(roll)
 	RollCount = RollCount + 1
 	CM:SendMessage(("%d/%d players have rolled!"):format(RollCount, self.NumGroupMembers), "SMART")
-	if RollCount >= self.NumGroupMembers then RM:StopRoll(true) end
+	--if RollCount >= self.NumGroupMembers then RM:StopRoll(true) end
 end

 function RM:PassRoll(name)
@@ -194,7 +194,7 @@ function RM:PassRoll(name)
 	end
 	Rollers[name] = -1
 	RollCount = RollCount + 1
-	if RollCount >= self.NumGroupMembers then RM:StopRoll(true) end
+	--if RollCount >= self.NumGroupMembers then RM:StopRoll(true) end
 	return ("%s has passed on the roll."):format(name)
 end

@@ -217,21 +217,29 @@ function RM:AnnounceResult(expire)
 		return
 	end
 	local name
-	local roll = 0
+	local roll = -1 -- Minimum roll is 0
 	local additional = {}
 	local numAdditional = 0
 	for k,v in pairs(Rollers) do
-		if tonumber(v) > roll then
-			roll = tonumber(v)
+		local r = tonumber(v)
+		if r > roll then
+			roll = r
 			name = k
 			wipe(additional)
-		elseif tonumber(v) == roll then
-			additional[k] = tonumber(v)
+		elseif r == roll and r ~= -1 then
+			additional[k] = r
 			numAdditional = numAdditional + 1
 		end
 	end
 	local msg
-	if numAdditional <= 0 then
+	if roll == -1 then
+		msg = "Everyone passed on the roll! There is no winner"
+		if self.Item then
+			msg = msg .. " for " .. self.Item
+		end
+		msg = msg .. "."
+		CM:SendMessage(msg, "SMART")
+	elseif numAdditional <= 0 then
 		msg = "The winner is: " .. name .. "! With a roll of " .. roll
 		if self.Item then
 			msg = msg .. " for " .. self.Item
diff --git a/String.lua b/String.lua
index 56adca8..f56166a 100644
--- a/String.lua
+++ b/String.lua
@@ -17,12 +17,12 @@
 	* along with Command. If not, see <http://www.gnu.org/licenses/>.
 --]]

-if type(Command.Extensions) ~= "table" then
-	Command.Extensions = {}
-end
-
 local C = Command

+if type(C.Extensions) ~= "table" then
+	C.Extensions = {}
+end
+
 --- Table containing all String methods.
 -- This is referenced "CES" in String.lua.
 -- @name Command.Extentions.String
@@ -107,3 +107,36 @@ function CES:Cut(s, l)
 	end
 	return t
 end
+
+--- Split a string into parts to fit the length specified.
+-- Works like Cut() except keeps words together to make it more pretty.
+-- @param s The string to fit.
+-- @param l Max length of each part.
+-- @param d Delimiter to separate each word with.
+-- @return Table containing the parts.
+--
+function CES:Fit(s, l, d)
+	if (type(s) ~= "string" and type(s) ~= "table") or type(l) ~= "number" then
+		error("Invalid parameters passed, expected [string, number], got: [" .. type(s) .. ", " .. type(l) .. "]!")
+		return
+	end
+	d = d or " "
+	if type(s) == "table" then s = C.Extensions.Table:Join(s) end
+	if s:len() <= l then return s end
+	local words = self:Split(s)
+	local parts = {}
+	local part = ""
+	for i=1, #words do
+		part = part .. words[i]
+		if i >= #words then
+			table.insert(parts, part)
+			break
+		elseif (part .. words[i + 1]):len() >= l then
+			table.insert(parts, part)
+			part = ""
+		else
+			part = part .. d
+		end
+	end
+	return parts
+end
diff --git a/Table.lua b/Table.lua
index 697ecb7..aeb3d81 100644
--- a/Table.lua
+++ b/Table.lua
@@ -75,3 +75,24 @@ function CET:Copy(tbl, cache)
 	end
 	return copy
 end
+
+--- Join table values together to create a string.
+-- @param tbl Table to join.
+-- @param d Delimiter to use between values.
+-- @return String containing the joined values of the table.
+--
+function CET:Join(tbl, d)
+	if type(tbl) ~= "table" then
+		error("Expected argument of type [table], got [" .. type(tbl) .. "]!")
+		return
+	end
+	d = d or " "
+	if #tbl <= 0 then return "" end
+	local s = tostring(tbl[1])
+	if #tbl > 1 then
+		for i=2, #tbl do
+			s = s .. d .. tostring(tbl[i])
+		end
+	end
+	return s
+end
diff --git a/load.xml b/load.xml
index cada1d3..3f79a87 100644
--- a/load.xml
+++ b/load.xml
@@ -27,6 +27,7 @@
 	<Script file="PlayerManager.lua" />
 	<Script file="QueueManager.lua" />
 	<Script file="RollManager.lua" />
+	<Script file="LootManager.lua" />
 	<Script file="AddonComm.lua" />
 	<Script file="CommandManager.lua" />
 	<Script file="ChatManager.lua" />