Quantcast

CRITICAL! I get another feature. Added Loot Manager and fixed a whole bunch of bugs. Feedback welcome.

ckaotik [03-11-10 - 23:37]
CRITICAL! I get another feature. Added Loot Manager and fixed a whole bunch of bugs. Feedback welcome.
Filename
Broker_Garbage.toc
core.lua
deDE.lua
enUS.lua
lootmanager.lua
lootmanager_options.lua
options.lua
readme.txt
diff --git a/Broker_Garbage.toc b/Broker_Garbage.toc
index a73ef09..1cb3597 100644
--- a/Broker_Garbage.toc
+++ b/Broker_Garbage.toc
@@ -8,11 +8,12 @@
 ## Notes: Full bags no more! Find your least valuable item .. and destroy it!
 ## Notes-deDE: Endlich wieder Platz! Finde dein billigstes Item ... und zerstöre es.
 ## Author: ckaotik
-## Version: 3.3v16
+## Version: 3.3v17beta1
 ## X-Embeds: LibPeriodicTable-3.1
 ## X-Category: Inventory
-## X-Credits: GarbageFu, Tekkub
+## X-Credits: GarbageFu(Jaerin/wmrojer), tekKonfig(Tekkub), KarniCrap(Karnifex)

+# dependencies. comment (with '#') if you do not wish to load these (only if another addon already does so)
 Libs\LibStub.lua
 Libs\LibQTip-1.0.lua
 Libs\CallbackHandler-1.0.lua
@@ -24,8 +25,14 @@ Libs\LibPeriodicTable-3.1-Misc\LibPeriodicTable-3.1-Misc.lua
 Libs\LibPeriodicTable-3.1-Tradeskill\LibPeriodicTable-3.1-Tradeskill.lua
 Libs\LibPeriodicTable-3.1-TradeskillResultMats\LibPeriodicTable-3.1-TradeskillResultMats.lua

+# localization files
 enUS.lua
 deDE.lua

+# loot manager functionality can be disabled here. comment (with '#') lootmanager.lua to disable
 core.lua
-options.lua
\ No newline at end of file
+lootmanager.lua
+
+# options. when disabling the Loot Manager, disable lootmanager_options.lua, too
+options.lua
+lootmanager_options.lua
\ No newline at end of file
diff --git a/core.lua b/core.lua
index 9434486..abea259 100644
--- a/core.lua
+++ b/core.lua
@@ -32,6 +32,17 @@ BrokerGarbage.defaultGlobalSettings = {
 	autoSellToVendor = true,
 	autoRepairAtVendor = true,
 	neverRepairGuildBank = false,
+	useLootManager = false,
+	restackIfNeeded = true,
+	restackFullInventory = false,
+	autoLoot = false,
+	autoLootSkinning = true,
+	autoLootFishing = true,
+	autoLootPickpocket = true,
+	autoDestroy = false,
+	tooFewSlots = 0,
+	openContainers = true,
+	openClams = true,

 	-- default values
 	tooltipMaxHeight = 220,
@@ -63,6 +74,7 @@ BrokerGarbage.defaultLocalSettings = {

 	-- behavior
 	neverRepairGuildBank = false,
+	selectiveLooting = false,

 	-- default values
 	moneyLostByDeleting = 0,
@@ -78,6 +90,15 @@ local cost = 0
 local lastReminder = time()

 BrokerGarbage.tt = nil
+BrokerGarbage.warnings = {}
+BrokerGarbage.tagAuction	= "|cFF2bff58A"		-- green
+BrokerGarbage.tagVendor		= "|cFFff9c5aV"		-- orange
+BrokerGarbage.tagVendorList	= "|cFFff592dV"		-- slightly darker orange
+BrokerGarbage.tagDisenchant	= "|cFFe052ffD"		-- purple
+BrokerGarbage.tagInclude	= "|cFFFFFFFFI"		-- white
+
+BrokerGarbage.clams = {15874, 5523, 5524, 7973, 24476, 36781, 45909}
+BrokerGarbage.playerClass = select(2,UnitClass("player"))

 -- event handler
 local function eventHandler(self, event, ...)
@@ -111,7 +132,7 @@ local function eventHandler(self, event, ...)
 		elseif sellValue ~= 0 and BG_GlobalDB.autoSellToVendor then
 			-- autosell only
 			BrokerGarbage:Print(format(BrokerGarbage.locale.sell, BrokerGarbage:FormatMoney(sellValue)))
-
+
 		end

 		sellValue = 0
@@ -124,10 +145,10 @@ local function eventHandler(self, event, ...)

 	elseif locked and event == "MERCHANT_CLOSED" then
 		-- fallback unlock
-		sellValue = 0
 		cost = 0
-		locked = false
+		sellValue = 0
 		BrokerGarbage.toSellValue = 0
+		locked = false
 		BrokerGarbage:Debug("lock released")

 		BrokerGarbage:ScanInventory()
@@ -136,14 +157,14 @@ local function eventHandler(self, event, ...)
 		BrokerGarbage:CheckSettings()

 		if not locked and loaded then
-			warnings = BrokerGarbage:ScanInventory()
+			BrokerGarbage:ScanInventory()
 		end
-
+
 	elseif event == "BAG_UPDATE" then
 		if not locked and loaded then
 			BrokerGarbage:ScanInventory()
 		end
-
+
 	end
 end

@@ -244,19 +265,44 @@ end

 function BrokerGarbage:CheckSettings()
 	-- check for settings
-	if not BG_GlobalDB then BG_GlobalDB = {} end
+	local first = false
+	if not BG_GlobalDB then BG_GlobalDB = {}; first = true end
 	for key, value in pairs(BrokerGarbage.defaultGlobalSettings) do
 		if BG_GlobalDB[key] == nil then
 			BG_GlobalDB[key] = value
 		end
 	end

-	if not BG_LocalDB then BG_LocalDB = {} end
+	if not BG_LocalDB then BG_LocalDB = {}; first = true end
 	for key, value in pairs(BrokerGarbage.defaultLocalSettings) do
 		if BG_LocalDB[key] == nil then
 			BG_LocalDB[key] = value
 		end
 	end
+
+	if first then
+		BrokerGarbage:CreateDefaultLists()
+	end
+end
+
+function BrokerGarbage:CreateDefaultLists()
+	BG_GlobalDB.include[46106] = true		-- argentum lance
+	BG_GlobalDB.include[6265] = 20			-- soulshards
+	BG_GlobalDB.include["Consumable.Water.Conjured"] = true
+
+	BG_LocalDB.exclude["Tradeskill.Mat"] = true
+	if BrokerGarbage.playerClass == "HUNTER" then
+		BG_LocalDB.exclude["Misc.Reagent.Ammo"] = true
+	elseif BrokerGarbage.playerClass == "WARRIOR" or BrokerGarbage.playerClass == "ROGUE" or BrokerGarbage.playerClass == "DEATHKNIGHT" then
+		BG_LocalDB.autoSellList["Consumable.Water"] = true
+	elseif BrokerGarbage.playerClass == "SHAMAN" then
+		BG_LocalDB.include[17058] = 20		-- fish oil
+		BG_LocalDB.include[17057] = 20		-- scales
+	end
+	BG_LocalDB.exclude["Misc.Reagent.Class."..string.gsub(string.lower(BrokerGarbage.playerClass), "^.", string.upper)] = true
+
+	BG_GlobalDB.forceVendorPrice["Consumable.Food.Edible"] = true
+	BG_GlobalDB.forceVendorPrice["Consumable.Water.Basic"] = true
 end

 function BrokerGarbage:FormatMoney(amount)
@@ -323,6 +369,21 @@ function BrokerGarbage:Find(table, value)
 	return false
 end

+function BrokerGarbage:IsItem(itemID, itemTable)
+	if type(itemTable) == "number" then
+		return itemID == itemTable
+
+	else
+		for _, ID in pairs(itemTable) do
+			if itemID == ID then
+				return true
+			end
+		end
+	end
+
+	return false
+end
+
 -- joins any number of tables together, one after the other. elements within the input-tables will get mixed, though
 function BrokerGarbage:JoinTables(...)
 	local result = {}
@@ -390,6 +451,16 @@ function BrokerGarbage:GetItemID(itemLink)
 	return tonumber(itemID)
 end

+function BrokerGarbage:GetTradeSkill(skillName)
+	for i=1, GetNumSkillLines() do
+		local name, _, _, skillRank, _, _, _, _, _, _, _, _, _ = GetSkillLineInfo(i)
+		if name == skillName then
+			return skillRank
+		end
+	end
+	return nil
+end
+
 function BrokerGarbage:CanDisenchant(itemLink)
 	if (itemLink) then
 		local _, _, quality, level, _, _, _, count, slot = GetItemInfo(itemLink)
@@ -400,17 +471,9 @@ function BrokerGarbage:CanDisenchant(itemLink)
 			and (not count or count == 1) then

 			-- can we DE ourself?
-			local enchanting = GetSpellInfo(7411)
+			local enchanting = select(1,GetSpellInfo(7411))
 			if IsUsableSpell(enchanting) then
-				local skill
-				for i=1, GetNumSkillLines() do
-					local name, _, _, skillRank, _, _, _, _, _, _, _, _, _ = GetSkillLineInfo(i)
-					if name == enchanting then
-						skill = skillRank
-						BrokerGarbage:Debug("DE Skill", skill)
-						break
-					end
-				end
+				local skill = BrokerGarbage:GetTradeSkill(enchanting) or 0

 				local requiredSkill = 0
 				if level <= 20 then
@@ -428,10 +491,8 @@ function BrokerGarbage:CanDisenchant(itemLink)
 				else
 					requiredSkill = 375
 				end
-				BrokerGarbage:Debug("Required DE Skill", requiredSkill)

 				if skill >= requiredSkill then
-					BrokerGarbage:Debug("Can Diss.")
 					return true
 				end
 				-- if skill is too low, still check if we can send it
@@ -475,7 +536,7 @@ function BrokerGarbage:Tooltip(wut)
 	-- shows up to n lines of deletable items
 	local lineNum
 	local cheapList = BrokerGarbage:GetCheapest(BG_GlobalDB.tooltipNumItems)
-	for i = 1, #cheapList do
+	for i = 1, #cheapList do
 		-- adds lines: itemLink, count, itemPrice, source
 		lineNum = BrokerGarbage.tt:AddLine(
 			select(2,GetItemInfo(cheapList[i].itemID)),
@@ -575,10 +636,10 @@ end

 -- calculates the value of a stack/partial stack of an item
 function BrokerGarbage:GetItemValue(itemLink, count)
-	local vendorPrice = select(11,GetItemInfo(itemLink))
 	local itemID = BrokerGarbage:GetItemID(itemLink)
-	local auctionPrice, disenchantPrice, temp, source
-	local DE = false
+	local DE = BrokerGarbage:CanDisenchant(itemLink)
+	local vendorPrice = select(11,GetItemInfo(itemLink))
+	local auctionPrice, disenchantPrice, source

 	if vendorPrice == 0 then vendorPrice = nil end
 	if not count then count = GetItemCount(itemLink, false, false) end
@@ -600,17 +661,17 @@ function BrokerGarbage:GetItemValue(itemLink, count)
 		end
 	end
 	if select(3,GetItemInfo(itemLink)) == 0 or useVendorPrice then
-		return vendorPrice and vendorPrice*count or nil, "|cFFF5DEB3V" -- orange
+		return vendorPrice and vendorPrice*count or nil, BrokerGarbage.tagVendor
 	end

 	-- calculate auction value
 	if IsAddOnLoaded("Auctionator") then
 		auctionPrice = Atr_GetAuctionBuyout(itemLink)
-		disenchantPrice = Atr_GetDisenchantValue(itemLink)
+		disenchantPrice = DE and Atr_GetDisenchantValue(itemLink)

 	elseif IsAddOnLoaded("AuctionLite") then
 		auctionPrice = AuctionLite:GetAuctionValue(itemLink)
-		disenchantPrice = AuctionLite:GetDisenchantValue(itemLink)
+		disenchantPrice = DE and AuctionLite:GetDisenchantValue(itemLink)

 	elseif IsAddOnLoaded("WOWEcon_PriceMod")  then
 		auctionPrice = Wowecon.API.GetAuctionPrice_ByLink(itemLink, Wowecon.API.SERVER_PRICE)
@@ -620,6 +681,7 @@ function BrokerGarbage:GetItemValue(itemLink, count)
 		for i,data in pairs(DeData) do
 			disenchantPrice = disenchantPrice + (Wowecon.API.GetAuctionPrice_ByLink(data[1], Wowecon.API.SERVER_PRICE) * data[3])
 		end
+		disenchantPrice = DE and disenchantPrice

 	elseif IsAddOnLoaded("Auc-Advanced") then
 		auctionPrice = AucAdvanced.API.GetMarketValue(itemLink)
@@ -627,52 +689,79 @@ function BrokerGarbage:GetItemValue(itemLink, count)

 	else
 		auctionPrice = GetAuctionBuyout and GetAuctionBuyout(itemLink) or nil
-		disenchantPrice = GetDisenchantValue and GetDisenchantValue(itemLink) or nil
-
-		-- no auctionPrice => no auction addon loaded
+		disenchantPrice = DE and GetDisenchantValue and GetDisenchantValue(itemLink) or nil
+
 	end

-	-- DE items might be worth more than auction selling
-	if BrokerGarbage:CanDisenchant(itemLink) then
-		DE = true
-		--auctionPrice = (disenchantPrice > auctionPrice) and disenchantPrice or auctionPrice
+	local maximum = math.max((disenchantPrice or 0), (auctionPrice or 0), (vendorPrice or 0))
+	if vendorPrice and maximum == vendorPrice then
+		return vendorPrice, BrokerGarbage.tagVendor
+
+	elseif auctionPrice and maximum == auctionPrice then
+		return auctionPrice, BrokerGarbage.tagAuction
+
+	elseif disenchantPrice and maximum == disenchantPrice then
+		return disenchantPrice, BrokerGarbage.tagDisenchant
+
+	else
+		return nil, nil
 	end
+end
+
+-- finds all occurences of the given item and returns the best location to delete from
+function BrokerGarbage:FindSlotToDelete(itemID, ignoreFullStack)
+	local locations = {}
+	local maxStack = select(8, GetItemInfo(itemID))

-	if vendorPrice then
-		if auctionPrice and disenchantPrice and DE then
-			if auctionPrice > disenchantPrice then
-				temp = auctionPrice
-				source = "|cFF9F9F5FA"	-- greenish
-			else
-				temp = disenchantPrice
-				source = "|cFF7171C6DE"	-- purple
+	local numSlots, freeSlots, ratio, bagType
+	for container = 0,4 do
+		numSlots = GetContainerNumSlots(container)
+		freeSlots, bagType = GetContainerFreeSlots(container)
+		if not numSlots or not freeSlots then break end
+		ratio = #freeSlots/numSlots
+
+		for slot = 1, numSlots do
+			local _,count,locked,_,_,canOpen,itemLink = GetContainerItemInfo(container, slot)
+
+			if itemLink and BrokerGarbage:GetItemID(itemLink) == itemID then
+				if not ignoreFullStack or (ignoreFullStack and count < maxStack) then
+					-- found one
+					table.insert(locations, {
+						slot = slot,
+						bag = container,
+						count = count,
+						ratio = ratio,
+						bagType = (bagType or 0)
+					})
+				end
 			end
-		elseif auctionPrice then
-			temp = auctionPrice
-			source = "|cFF9F9F5FA" -- greenish
-		else
-			temp = 0
 		end
-
-		-- return highest price found
-		if vendorPrice > temp then
-			return vendorPrice * count, "|cFFF5DEB3V" -- orange
+	end
+
+	-- recommend the location with the largest ratio that is NOT a specialty bag
+	table.sort(locations, function(a,b)
+		if a.bagType == 0 and b.bagType ~= 0 then
+			return true
 		else
-			return temp * count or 0, source
-		end
-	else
-		return nil
-	end
+			-- return a.ratio > b.ratio
+			return a.count < b.count
+		end
+	end)
+	return locations
 end

--- deletes the item in a given location of your bags. no questions asked
+-- deletes the item in a given location of your bags. takes either link/bag/slot or an itemTable as created by GetCheapest()
 function BrokerGarbage:Delete(itemLink, bag, slot)
 	if type(itemLink) == "table" then
-		bag = itemLink[2]
-		slot = itemLink[3]
-		itemLink = itemLink[1]
+		bag = itemLink[1].bag
+		slot = itemLink[1].slot
+		itemLink = select(2,GetItemInfo(itemLink[1].itemID))
 	end

+	-- security check
+	local itemID = GetContainerItemID(bag, slot)
+	if not select(2,GetItemInfo(itemID)) == itemLink then return end
+
 	PickupContainerItem(bag, slot)
 	DeleteCursorItem()					-- comment this line to prevent item deletion
 	BG_GlobalDB.itemsDropped = BG_GlobalDB.itemsDropped + 1
@@ -684,75 +773,141 @@ end
 -- scans your inventory for possible junk items and updates LDB display
 function BrokerGarbage:ScanInventory()
 	BrokerGarbage.inventory = {}
-	BrokerGarbage.toSellValue = 0
-	local cheapestItem, freeSlots
-	local warnings = {}
+	BrokerGarbage.unopened = {}
+	local limitedItemsChecked = {}

-	local maxSpace = 0		-- will contain total number of inventory space
-	local freeSpace = 0		-- will contain total number of free bag space
+	BrokerGarbage.toSellValue = 0
+	BrokerGarbage.totalBagSpace = 0
+	BrokerGarbage.totalFreeSlots = 0

 	for container = 0,4 do
 		local numSlots = GetContainerNumSlots(container)
 		if numSlots then
 			freeSlots = GetContainerFreeSlots(container)
-			freeSpace = freeSpace + (freeSlots and #freeSlots or 0)
-			maxSpace = maxSpace + GetContainerNumSlots(container)
+			BrokerGarbage.totalFreeSlots = BrokerGarbage.totalFreeSlots + (freeSlots and #freeSlots or 0)
+			BrokerGarbage.totalBagSpace = BrokerGarbage.totalBagSpace + numSlots

-			for slot = 1, GetContainerNumSlots(container) do
+			for slot = 1, numSlots do
 				local itemID = GetContainerItemID(container,slot)
 				if itemID then
 					-- GetContainerItemInfo sucks big time ... just don't use it for quality IDs!!!!!!!
-					local _,count,locked,_,_,canOpen,itemLink = GetContainerItemInfo(container, slot)
+					local _,count,locked,_,_,_,itemLink = GetContainerItemInfo(container, slot)
 					local quality = select(3,GetItemInfo(itemID))
+					local isClam = BrokerGarbage:IsItem(itemID, BrokerGarbage.clams)

-					if canOpen and BG_GlobalDB.showWarnings then
-						tinsert(warnings, format(BrokerGarbage.locale.openPlease,
-							select(2,GetItemInfo(itemID))))
+					if canOpen or isClam then
+						local _,_,_,_,_,type,subType,_,_,tex = GetItemInfo(itemID)
+						tinsert(BrokerGarbage.unopened, {
+							bag = container,
+							slot = slot,
+							itemID = itemID,
+							clam = isClam,
+						})
+						if BG_GlobalDB.showWarnings then
+							local notice = format(BrokerGarbage.locale.openPlease, select(2,GetItemInfo(itemID)))
+							if not BrokerGarbage:Find(BrokerGarbage.warnings, notice) then
+								tinsert(BrokerGarbage.warnings, notice)
+							end
+						end
 					end

 					-- check if this item belongs to an excluded category
-					local inCategory, skip
+					local isExclude, skip
 					for setName,_ in pairs(BrokerGarbage:JoinTables(BG_GlobalDB.exclude, BG_LocalDB.exclude)) do
 						if type(setName) == "string" then
-							_, inCategory = BrokerGarbage.PT:ItemInSet(itemID, setName)
+							_, isExclude = BrokerGarbage.PT:ItemInSet(itemID, setName)
 						end
-						-- item is on save list, skip
-						if inCategory then
-							skip = true
-							break
+						if isExclude then
+							skip = true; break
 						end
 					end
-					inCategory = nil
-					if not skip then
-						for setName,_ in pairs(BrokerGarbage:JoinTables(BG_GlobalDB.autoSellList, BG_LocalDB.autoSellList, BG_LocalDB.include, BG_GlobalDB.include)) do
+
+					local isSell, isInclude
+					-- this saves excluded items
+					if not skip and not BG_GlobalDB.exclude[itemID] and not BG_LocalDB.exclude[itemID] then
+						local force = false
+
+						-- check if item is in a category of Include List
+						for setName,_ in pairs(BrokerGarbage:JoinTables(BG_LocalDB.include, BG_GlobalDB.include)) do
 							if type(setName) == "string" then
-								_, inCategory = BrokerGarbage.PT:ItemInSet(itemID, setName)
+								_, isInclude = BrokerGarbage.PT:ItemInSet(itemID, setName)
 							end
-							if inCategory then inCategory = setName; break end
+							if isInclude then isInclude = setName; break end
 						end
-					end
-
-					if quality and
-						(quality <= BG_GlobalDB.dropQuality or inCategory
-						or BG_GlobalDB.include[itemID] or BG_LocalDB.include[itemID]
-						or BG_GlobalDB.autoSellList[itemID] or BG_LocalDB.autoSellList[itemID])
-						and not BG_GlobalDB.exclude[itemID] and not BG_LocalDB.exclude[itemID] and not skip then	-- save excluded items!!!

-						local force = false
+						-- check if item is in a category of Sell List
+						for setName,_ in pairs(BrokerGarbage:JoinTables(BG_GlobalDB.autoSellList, BG_LocalDB.autoSellList)) do
+							if type(setName) == "string" then
+								_, isSell = BrokerGarbage.PT:ItemInSet(itemID, setName)
+							end
+							if isSell then isSell = setName; break end
+						end
+
+						-- ----------------------------------------------------------------------
+
+						-- get price and tag
 						local value, source = BrokerGarbage:GetItemValue(itemLink,count)
-						-- make included items appear in tooltip list as "forced"
-						if BG_GlobalDB.include[itemID] or BG_LocalDB.include[itemID]
-							or BG_GlobalDB.include[inCategory] or BG_LocalDB.include[inCategory] then
-							if not value then value = 0 end
+						if isInclude or BG_GlobalDB.include[itemID] or BG_LocalDB.include[itemID] then
+							-- Include List item
 							force = true
-							source = "|cFF8C1717I"	-- overwrites former value, I as in "include"
-						end
+
+							local limited = BrokerGarbage:Find(limitedItemsChecked, itemID)
+							if not limited then
+								if BG_GlobalDB.include[itemID] and type(BG_GlobalDB.include[itemID]) == "number"
+									or BG_LocalDB.include[itemID] and type(BG_LocalDB.include[itemID]) == "number" then
+
+									-- this is a limited item - only check it once
+									tinsert(limitedItemsChecked, itemID)
+									limited = true
+
+									local stackSize = select(8, GetItemInfo(itemID))
+									local limit = tonumber(BG_GlobalDB.include[itemID]) or tonumber(BG_LocalDB.include[itemID])
+									local saveStacks = ceil(limit/stackSize)
+									local locations = BrokerGarbage:FindSlotToDelete(itemID)
+
+									if #locations > saveStacks then
+										local itemCount = 0
+										for i = #locations, 1, -1 do
+											if itemCount < limit then
+												itemCount = itemCount + locations[i].count
+											else
+												tinsert(BrokerGarbage.inventory, {
+													bag = locations[i].bag,
+													slot = locations[i].slot,
+													itemID = itemID,
+													quality = quality,
+													count = locations[i].count,
+													value = 0,
+													source = BrokerGarbage.tagInclude,
+													force = force,
+												})
+											end
+										end
+									end
+								end
+							end
+
+							if not limited then
+								value = value or 0
+								source = BrokerGarbage.tagInclude
+							else
+								value = nil
+							end

+						elseif isSell or BG_GlobalDB.autoSellList[itemID] or BG_LocalDB.autoSellList[itemID] then
+							-- AutoSell List item
+							value = select(11,GetItemInfo(itemID))
+							source = BrokerGarbage.tagVendorList
+
+						--elseif quality and quality <= BG_GlobalDB.dropQuality then
+							-- regular gray/junk treshold item
+							--force = false
+						end
+
 						if value then
 							-- save if we have something sellable
-							if quality == 0
+							if quality == 0 or isSell
 								or BG_GlobalDB.autoSellList[itemID] or BG_LocalDB.autoSellList[itemID] then
-								BrokerGarbage:Debug("Added for selling:", itemID, GetItemInfo(itemID) or "")
 								BrokerGarbage.toSellValue = BrokerGarbage.toSellValue + value
 							end

@@ -767,9 +922,6 @@ function BrokerGarbage:ScanInventory()
 								force = force,
 							}

-							if not cheapestItem or cheapestItem.value >= value then
-								cheapestItem = currentItem
-							end
 							tinsert(BrokerGarbage.inventory, currentItem)
 						end
 					end
@@ -778,14 +930,16 @@ function BrokerGarbage:ScanInventory()
 		end
 	end

-	if cheapestItem then
+	local cheapestItem = BrokerGarbage:GetCheapest()
+
+	if cheapestItem ~= {} then
 		LDB.text = format(BG_GlobalDB.LDBformat,
-			select(2,GetItemInfo(cheapestItem.itemID)),
-			cheapestItem.count,
-			BrokerGarbage:FormatMoney(cheapestItem.value),
-			freeSpace,
-			maxSpace)
-		BrokerGarbage.cheapestItem = cheapestItem
+			select(2,GetItemInfo(cheapestItem[1].itemID)),
+			cheapestItem[1].count,
+			BrokerGarbage:FormatMoney(cheapestItem[1].value),
+			BrokerGarbage.totalFreeSlots,
+			BrokerGarbage.totalBagSpace)
+		BrokerGarbage.cheapestItem = cheapestItem[1]
 	else
 		LDB.text = BrokerGarbage.locale.label
 		BrokerGarbage.cheapestItem = nil
@@ -797,10 +951,9 @@ end
 -- returns the n cheapest items in your bags  in a table
 function BrokerGarbage:GetCheapest(number)
 	if not number then number = 1 end
-	local cheapestItems = {}
+	local cheapestItems, temp = {}, {}

 	-- get forced items
-	local count = 0
 	for _, itemTable in pairs(BrokerGarbage.inventory) do
 		local skip = false

@@ -808,15 +961,22 @@ function BrokerGarbage:GetCheapest(number)
 			if usedTable == itemTable then skip = true end
 		end

-		if not skip and itemTable.force and count < number then
-			tinsert(cheapestItems, itemTable)
-			count = count + 1
+		if not skip and itemTable.force then
+			tinsert(temp, itemTable)
 		end
 	end
-	table.sort(cheapestItems, function(a, b)
+	table.sort(temp, function(a, b)
 		return a.value < b.value
 	end)

+	if #temp <= number then
+		cheapestItems = temp
+	else
+		for i = 1, number do
+			tinsert(cheapestItems, temp[i])
+		end
+	end
+
 	-- fill with non-forced
 	if #cheapestItems < number then
 		local minPrice, minTable
@@ -923,15 +1083,11 @@ function BrokerGarbage:AutoRepair()
 	end
 end

-
 -- Wishlist
 -- ---------------------------------------------------------
+-- tooltip: if item has a count treshold set, don't show if we're below that treshold
 -- show lootable containers in your bag! make "open items" not as spammy
 -- increase/decrease loot treshold with mousewheel on LDB
--- restack if necessary
--- ask before deleting / treshold
--- search list frames (similar to gnomishvendorshrinker)
+-- restack if necessary	-> PickupContainerItem // SplitContainerItem
 -- fubar_garbagefu: Soulbound, Quest, Bind on Pickup, Bind on Equip/Use.
--- ignore special bags
--- drop-beyond-treshold: only keep 5 soulshards
--- feature: selective looting (only crafting materials, greens+ , ...)
\ No newline at end of file
+-- ignore special bags
\ No newline at end of file
diff --git a/deDE.lua b/deDE.lua
index 434163c..a096b04 100644
--- a/deDE.lua
+++ b/deDE.lua
@@ -18,6 +18,8 @@ BrokerGarbage.locale = {
 	itemDeleted = "%s wurde gelöscht.",

 	openPlease = "Bitte öffne %s - es nimmt unnötig Platz weg.",
+	openClams = "Du hast eine %s im Inventar!",
+	couldNotLoot = "%s wurde nicht geplündert, da es zu billig ist.",
 	slashCommandHelp = "Nutze |cffc0c0c0/garbage config|r um die Einstellungen zu öffnen oder |cffc0c0c0/garbage format |cffc0c0ffformatstring|r um das Format der LDB Anzeige anzupassen. |cffc0c0c0/garbage format reset|r setzt das LDB Format zurück. Für Statistiken, gib |cffc0c0c0/garbage stats|r ein.",
 	statistics = "Statistik:\nGesamtverdienst (alle Charaktere): %1$s\nGesamtverlust (alle Charaktere): %2$s",

@@ -119,7 +121,7 @@ BrokerGarbage.locale = {

 	-- List Options Panel
 	LOPTitle = "Positiv-Listen",
-	LOPSubTitle = "Um Items hinzuzufügen, ziehe sie auf das jeweilige '+'. Um sie zu entfernen, wähle sie aus und klicke auf '-'.",
+	LOPSubTitle = "Zum Hinzufügen ziehe Items auf das jeweilige '+'. Zum Entfernen wähle sie aus und klicke auf '-'. Nutze Kategorien per Rechts-Klick auf '+'.",

 		-- Exclude List
 	LOPExcludeHeader = "Ausschlussliste - Items hier werden nie verkauft/gelöscht.",
@@ -137,10 +139,10 @@ BrokerGarbage.locale = {

 	-- AutoSell Options Panel
 	LONTitle = "Negativ-Listen",
-	LONSubTitle = "Um Items hinzuzufügen, ziehe sie auf das jeweilige '+'. Um sie zu entfernen, wähle sie aus und klicke auf '-'.",
+	LONSubTitle = "Analog zu den Positiv-Listen. Um eine maximale Anzahl für ein bestimmtes Item festzulegen, nutze das Mausrad über dem Item-Icon.",

 		-- Include List
-	LONIncludeHeader = "Einschlussliste - Items hier werden mit als erstes im Tooltip gezeigt.",
+	LONIncludeHeader = "Einschlussliste - Items werden zuerst angezeigt und vom LM nicht geplündert.",
 	LONIncludePlusTT = "Items hinzufügen, indem du sie hierher ziehst/hier ablegst. Rechtsklick, um Kategorien hinzuzufügen!",
 	LONIncludeMinusTT = "Wähle Items, die du entfernen willst. Dann klicke hier.",
 	LONIncludePromoteTT = "Klicke, um alle markierten Items in die globale Einschlussliste zu übernehmen.",
@@ -155,7 +157,51 @@ BrokerGarbage.locale = {

 	-- LibPeriodicTable texts
 	PTCategoryTooltipHeader = "Kategorien hinzufügen",
-	PTCategoryTooltipText = "Füge Kategorien hinzu, indem du auf die entsprechenden Einträge clickst."
+	PTCategoryTooltipText = "Füge Kategorien hinzu, indem du auf die entsprechenden Einträge clickst.",
+
+	-- Loot Manager
+	CreatureTypeBeast = "Wildtier",
+	Quest = "Quest",
+	You = "Ihr",
+
+	LMTitle = "Loot Manager",
+	LMSubTitle = "Der Loot Manager kann den gesamten Lootvorgang verwalten, wenn du ihn lässt.\nHalte SHIFT beim Plündern lange gedrückt, wenn du sonst Autoloot an hast, aber einmalig 'per Hand' plündern möchtest.",
+
+	LMEnableTitle = "Loot Manager aktivieren",
+	LMEnableTooltip = "Aktiviert den Loot Manager.",
+
+	LMSelectiveTitle = "Selektives Looten",
+	LMSelectiveTooltip = "Wenn ausgewählt, entscheidet Broker_Garbage von selbst, welche Items gelootet werden.",
+
+	LMAutoLootTitle = "Autoloot",
+	LMAutoLootTooltip = "Wenn nicht ausgewählt, wird Broker_Garbage nur bei bestimmten Gelegenheiten looten.",
+
+	LMAutoLootSkinningTitle = "Kürschnern",
+	LMAutoLootSkinningTooltip = "Wenn ausgewählt, wird Broker_Garbage versuchen, durch dich kürschnerbare Kreaturen zu looten.",
+
+	LMAutoLootPickpocketTitle = "Taschendiebstahl",
+	LMAutoLootPickpocketTooltip = "Wenn ausgewählt, wird Broker_Garbage automatisch plündern, wenn du ein Schurke in Verstohlenheit bist.",
+
+	LMAutoLootFishingTitle = "Angeln",
+	LMAutoLootFishingTooltip = "Wenn ausgewählt, wird Broker_Garbage automatisch plündern, wenn du gerade angelst.",
+
+	LMAutoDestroyTitle = "Auto-Zerstören",
+	LMAutoDestroyTooltip = "Wenn ausgewählt, wird Broker_Garbage bei zu wenig Platz versuchen, welchen zu schaffen.",
+
+	LMFreeSlotsTitle = "Min. freier Inventarplatz",
+	LMFreeSlotsTooltip = "Setze das Minimum an freien Taschenplätzen, bei dem Broker_Garbage automatisch Platz schaffen soll.",
+
+	LMRestackTitle = "Automatisch stapeln",
+	LMRestackTooltip = "Wenn ausgewählt, wird Broker_Garbage automatisch die von dir beobachteten Gegenstände nach dem Plündern stapeln, um Platz zu schaffen.",
+
+	LMFullRestackTitle = "Gesamtes Inventar",
+	LMFullRestackTooltip = "Wenn ausgewählt, wird Broker_Garbage dein gesamtes Inventar zum Restacken beobachten.",
+
+	LMOpenContainersTitle = "Warne: Behälter",
+	LMOpenContainersTooltip = "Wenn ausgewählt, wird Broker_Garbage eine Warnung ausgeben, solltest du ungeöffnete Behälter bei dir haben.",
+
+	LMOpenClamsTitle = "Warne: Muscheln",
+	LMOpenClamsTooltip = "Wenn ausgewählt, wird Broker_Garbage eine Warnung ausgeben, wenn du ungeöffnete Muscheln im Inventar hast. Da diese aber nun stapelbar sind, verlierst du durch deaktivieren dieser Option keinen Taschenplatz.",
 }

 end
\ No newline at end of file
diff --git a/enUS.lua b/enUS.lua
index 8d91a02..91a60d8 100644
--- a/enUS.lua
+++ b/enUS.lua
@@ -18,6 +18,8 @@ BrokerGarbage.locale = {
 	itemDeleted = "%s has been deleted.",

 	openPlease = "Please open your %s. It's in your bags, stealing your space!",
+	openClams = "You own a %s. Maybe consider opening it.",
+	couldNotLoot = "I did not loot %s because it's too cheap.",
 	slashCommandHelp = "Use |cffc0c0c0/garbage config|r to open the config menu or |cffc0c0c0/garbage format |cc0c0c0ffformatstring|r to change the LDB display style or |cffc0c0c0/garbage format reset|r to reset it. For statistics type |cffc0c0c0/garbage stats|r.",
 	statistics = "Statistics:\nTotal earnings (all characters): %1$s\nTotal losses (all characters): %2$s",

@@ -119,7 +121,7 @@ BrokerGarbage.locale = {

 	-- List Options Panel
 	LOPTitle = "Positive Lists",
-	LOPSubTitle = "To add Items to lists, drag them over the corresponding '+' icon, to remove them select them and click the '-'.",
+	LOPSubTitle = "To add Items to lists, drag them over the corresponding '+' icon, to remove them select them and click the '-'. To add categories right-click on '+'.",

 		-- Exclude List
 	LOPExcludeHeader = "Exclude List - these items will never be sold/deleted.",
@@ -137,10 +139,10 @@ BrokerGarbage.locale = {

 	-- AutoSell Options Panel
 	LONTitle = "Negative Lists",
-	LONSubTitle = "To add Items to lists, drag them over the corresponding '+' icon, to remove them select them and click the '-'.",
+	LONSubTitle = "Similar usage to Positive Lists. To set an item limit, use your mousewheel when over the item icon.",

 		-- Include List
-	LONIncludeHeader = "Include List - these items will be shown first in the tooltip.",
+	LONIncludeHeader = "Include List - items will be shown first and not be looted by the Loot Manager.",
 	LONIncludePlusTT = "Add items to the Exclude List by dragging/placing them on me. Right click on me for categories!",
 	LONIncludeMinusTT = "Select items you want to remove, then click here.",
 	LONIncludePromoteTT = "Selected items will be written onto your global Include List, as seen by every character.",
@@ -155,6 +157,50 @@ BrokerGarbage.locale = {

 	-- LibPeriodicTable texts
 	PTCategoryTooltipHeader = "Add Categories",
-	PTCategoryTooltipText = "Navigate through this menu and add any of these categories by clicking on them."
+	PTCategoryTooltipText = "Navigate through this menu and add any of these categories by clicking on them.",
+
+	-- Loot Manager
+	CreatureTypeBeast = "Beast",
+	Quest = "Quest",
+	You = "You",			-- as in "You receive ..."
+
+	LMTitle = "Loot Manager",
+	LMSubTitle = "The Loot Manager takes control of your looting if you want it to do so.\nIf you usually autoloot, hold down SHIFT for a while when looting a corpse to disable it once.",
+
+	LMEnableTitle = "Enable Loot Manager",
+	LMEnableTooltip = "Check to enable the Loot Manager.",
+
+	LMSelectiveTitle = "Selective Looting",
+	LMSelectiveTooltip = "Check to let Broker_Garbage determine which items to loot.",
+
+	LMAutoLootTitle = "Autoloot",
+	LMAutoLootTooltip = "If unchecked, Broker_Garbage will only loot on special occations.",
+
+	LMAutoLootSkinningTitle = "Skinning",
+	LMAutoLootSkinningTooltip = "If checked, Broker_Garbage will loot if the creature is skinnable by you.",
+
+	LMAutoLootPickpocketTitle = "Pickpocket",
+	LMAutoLootPickpocketTooltip = "If checked, Broker_Garbage will loot if you are a Rogue and stealthed.",
+
+	LMAutoLootFishingTitle = "Fishing",
+	LMAutoLootFishingTooltip = "If checked, Broker_Garbage will loot if you are currently fishing.",
+
+	LMAutoDestroyTitle = "Autodestroy",
+	LMAutoDestroyTooltip = "If checked, Broker_Garbage will take actions when your inventory space is (almost) full.",
+
+	LMFreeSlotsTitle = "Minimum free slots",
+	LMFreeSlotsTooltip = "Set the minimum numer of free slots for autodestroy to take action.",
+
+	LMRestackTitle = "Automatic restack",
+	LMRestackTooltip = "Check to automatically compress your watched inventory items after looting.",
+
+	LMFullRestackTitle = "Full inventory",
+	LMFullRestackTooltip = "When checked will look at your whole inventory for restackable items, not just the watched items.",
+
+	LMOpenContainersTitle = "Warn: Containers",
+	LMOpenContainersTooltip = "When checked, Broker_Garbage will warn you when you have unopened containers in you inventory.",
+
+	LMOpenClamsTitle = "Warn: Clams",
+	LMOpenClamsTooltip = "When checked, Broker_Garbage will warn you when you have clams in you inventory. As these now do stack, you are not wasting any slots by unchecking this.",
 }

diff --git a/lootmanager.lua b/lootmanager.lua
new file mode 100644
index 0000000..e1d505a
--- /dev/null
+++ b/lootmanager.lua
@@ -0,0 +1,484 @@
+-- This is BrokerGarbage's Loot Manager - inspired by KarniCrap
+-- It allows you to manage auto looting and dropping of "too many" items
+_, BrokerGarbage = ...
+
+-- register events
+local function eventHandler(self, event, ...)
+	if not BG_GlobalDB.useLootManager then return end
+
+	if event == "CHAT_MSG_LOOT" then
+		if strfind(arg1, BrokerGarbage.locale.You) and BG_GlobalDB.autoDestroy then
+			BrokerGarbage:AutoDestroy()
+		end
+
+	elseif event == "LOOT_OPENED" then
+		local numSlots = 0
+		-- restack (relevant) inventory
+		if BG_GlobalDB.restackIfNeeded then
+			local justStacked = {}
+			if BG_GlobalDB.restackFullInventory then
+				for container = 0, 4 do
+					numSlots = GetContainerNumSlots(container)
+					if numSlots then
+						for slot = 1, numSlots do
+							local itemID = GetContainerItemID(container,slot)
+							if itemID and not BrokerGarbage:Find(justStacked, itemID) then
+								BrokerGarbage:Restack(itemID)
+								table.insert(justStacked, itemID)
+							end
+						end
+					end
+				end
+			else
+				for i, itemTable in pairs(BrokerGarbage.inventory) do
+					if not BrokerGarbage:Find(justStacked, itemTable.itemID) then
+						BrokerGarbage:Restack(itemTable.itemID)
+						table.insert(justStacked, itemTable.itemID)
+					end
+				end
+			end
+		end
+		-- looting
+		if BG_LocalDB.selectiveLooting then
+			local autoloot = arg1
+			if BrokerGarbage.currentRestackItems ~= nil then
+				BrokerGarbage.afterRestack = function()
+					BrokerGarbage:SelectiveLooting(autoloot)
+				end
+			else
+				BrokerGarbage:SelectiveLooting(autoloot)
+			end
+		end
+
+	elseif event == "LOOT_CLOSED" then
+		if BG_LocalDB.selectiveLooting then
+			BrokerGarbage:CheckAndClearInv()
+		end
+
+		if BG_GlobalDB.openContainers then
+			BrokerGarbage:OpenContainers()
+		end
+
+	elseif event == "ITEM_UNLOCKED" then
+		-- keep restacking
+		if BrokerGarbage:RestackStep() then
+			-- wait for next update
+			BrokerGarbage:Debug("Still restacking...", BrokerGarbage.currentRestackItems)
+		else
+			-- we're done
+			frame:UnregisterEvent("ITEM_UNLOCKED")
+			BrokerGarbage.currentRestackItems = nil
+			BrokerGarbage:Debug("Unregistered ITEM_UNLOCKED")
+
+			if BrokerGarbage.afterRestack ~= nil then
+				BrokerGarbage:afterRestack()
+				BrokerGarbage.afterRestack = nil
+			end
+		end
+	end
+end
+
+local frame = CreateFrame("Frame")
+frame:RegisterEvent("CHAT_MSG_LOOT")
+frame:RegisterEvent("LOOT_OPENED")
+frame:RegisterEvent("LOOT_CLOSED")
+frame:SetScript("OnEvent", eventHandler)
+
+-- ---------------------------------------------------------
+-- Helper functions
+-- ---------------------------------------------------------
+-- restacks items so when deleting you lose as few items as possible
+function BrokerGarbage:Restack(itemID)
+	if BrokerGarbage.currentRestackItems then
+		tinsert(BrokerGarbage.currentRestackItems, itemID)
+	else
+		BrokerGarbage.currentRestackItems = { itemID }
+		if BrokerGarbage:RestackStep() then
+			-- wait for moved items
+			frame:RegisterEvent("ITEM_UNLOCKED")
+		else
+			-- nothing to restack
+			if BrokerGarbage.afterRestack ~= nil then
+				BrokerGarbage:afterRestack()
+				BrokerGarbage.afterRestack = nil
+			end
+		end
+	end
+end
+
+local function NextRestackStep()
+	-- go to next item if there is one
+	tremove(BrokerGarbage.currentRestackItems, 1)
+	if #(BrokerGarbage.currentRestackItems) <= 0 then
+		BrokerGarbage.currentRestackItems = nil
+		return false
+	else
+		return BrokerGarbage:RestackStep()
+	end
+end
+
+-- move 1 item for restacking
+function BrokerGarbage:RestackStep()
+	if not BrokerGarbage.currentRestackItems then return false end
+	local itemID = BrokerGarbage.currentRestackItems[1]
+	if not itemID then return NextRestackStep() end
+
+	local count = GetItemCount(itemID)
+	if not count or count <= 1 then return NextRestackStep() end
+
+	local locations = BrokerGarbage:FindSlotToDelete(itemID, true)
+	local maxLoc = #locations
+	if maxLoc <= 1 then
+		return NextRestackStep()
+	end -- we're done, nothing to restack
+
+	if GetContainerItemInfo(locations[1].bag, locations[1].slot) then
+		ClearCursor()
+		PickupContainerItem(locations[1].bag, locations[1].slot)
+		PickupContainerItem(locations[maxLoc].bag, locations[maxLoc].slot)
+
+		BrokerGarbage:Debug("Restack from/to", locations[1].count, locations[maxLoc].count)
+	end
+	return true
+end
+
+-- calls restack and deletes as many items as needed
+function BrokerGarbage:DeletePartialStack(itemID, num)
+	local locations = BrokerGarbage:FindSlotToDelete(itemID)
+	local maxStack = select(8, GetItemInfo(itemID))
+
+	SplitContainerItem(locations[1].bag, locations[1].slot, num)
+	if CursorHasItem() then
+		BrokerGarbage:Debug("DeletePartialStack", select(2,GetItemInfo(itemID)), num, locations[1].bag, locations[1].slot)
+		DeleteCursorItem()
+	end
+end
+
+-- checks the inventory for items that can and should be dropped/restacked
+function BrokerGarbage:CheckAndClearInv()
+	local numSlots
+	-- restack
+	local justStacked = {}
+	if BG_GlobalDB.restackIfNeeded and BG_GlobalDB.restackFullInventory then
+		for container = 0, 4 do
+			numSlots = GetContainerNumSlots(container)
+			if numSlots then
+				for slot = 1, numSlots do
+					local itemID = GetContainerItemID(container,slot)
+					if itemID and not BrokerGarbage:Find(justStacked, itemID) then
+						BrokerGarbage:Restack(itemID)
+						table.insert(justStacked, itemID)
+					end
+				end
+			end
+		end
+	elseif BG_GlobalDB.restackIfNeeded then
+		for i, itemTable in pairs(BrokerGarbage.inventory) do
+			if not BrokerGarbage:Find(justStacked, itemTable.itemID) then
+				BrokerGarbage:Restack(itemTable.itemID)
+				table.insert(justStacked, itemTable.itemID)
+			end
+		end
+	end
+
+	-- drop until conditions are met
+	--while BrokerGarbage.totalFreeSlots <= BG_GlobalDB.tooFewSlots do
+	--	BrokerGarbage:Delete(BrokerGarbage:GetCheapest())	-- automatically takes included items
+	--	BrokerGarbage:ScanInventory()
+	--end
+end
+
+-- drops Include List (Blacklist) items
+function BrokerGarbage:AntiCrap()
+	local numSlots, itemID
+	for bag = 0, 4 do
+		numSlots = GetContainerNumSlots(container)
+		if numSlots then
+			for slot = 1, numSlots do
+				itemID = GetContainerItemID(container,slot)
+				if not IsInteresting(select(2,GetItemInfo(itemID))) then
+					BrokerGarbage:Delete(select(2,GetItemInfo(itemID)), bag, slot)
+				end
+			end
+		end
+	end
+end
+
+-- warns of container - clams and/or containers
+function BrokerGarbage:OpenContainers()
+	--[[if BrokerGarbage.totalFreeSlots < 2 then
+		BrokerGarbage:Print("Too few slots to securely loot containers! Please make some room.")
+		return
+	end]]--
+
+	-- only containers
+	if BG_GlobalDB.openContainers then
+		local itemLink
+
+		for i, itemTable in pairs(BrokerGarbage.unopened) do
+			if not itemTable.clam then
+				itemLink = select(2,GetItemInfo(itemTable.itemID))
+				BrokerGarbage:Print(format(BrokerGarbage.locale.openPlease, itemLink))
+				-- UseContainerItem(itemTable.container, itemTable.slot)
+				tremove(BrokerGarbage.unopened, i)
+			end
+		end
+	end
+
+	-- only clams
+	if BG_GlobalDB.openClams then
+		-- opening clams
+		local auctionType = select(6,GetAuctionItemClasses())
+		local auctionSubType = GetAuctionItemSubClasses(6)
+		local itemLink
+
+		for i, itemTable in pairs(BrokerGarbage.unopened) do
+			if itemTable.clam then
+				-- UseContainerItem(itemTable.bag, itemTable.slot)
+				itemLink = select(2,GetItemInfo(itemTable.itemID))
+				BrokerGarbage:Print(format(BrokerGarbage.locale.openClams, itemLink))
+				tremove(BrokerGarbage.unopened, i)
+			end
+		end
+	end
+end
+
+--[[ returns number of free inventory slots // currently unused
+function BrokerGarbage:GetNumSlots()
+	local total = 0
+	local free = 0
+	local numSlots = 0
+	local freeSlots = 0
+
+	for container = 0, 4 do
+		freeSlots = select(1,GetContainerFreeSlots(container)) or {}
+		free = free + #freeSlots
+		numSlots = GetContainerNumSlots(container)
+		if numSlots then
+			total = total + numSlots
+		end
+	end
+	return total, free
+end ]]--
+
+-- returns true if the requested mob is skinnable with our skill
+function BrokerGarbage:CanSkin(mobLevel)
+	local isSkinner = IsUsableSpell(select(1,GetSpellInfo(8613))) and BrokerGarbage:GetTradeSkill(select(1,GetSpellInfo(8613)))
+	if not isSkinner then return false end
+	local maxLevel
+	if isSkinner < 100 then
+		maxLevel = floor(isSkinner/10) + 10
+	else
+		maxLevel = floor(isSkinner/5)
+	end
+
+	return maxLevel >= mobLevel
+end
+
+-- determines if an item should be lootet
+function BrokerGarbage:IsInteresting(itemLink)
+	local itemID = BrokerGarbage:GetItemID(itemLink)
+
+	local negativeList = BrokerGarbage:JoinTables(BG_GlobalDB.include, BG_LocalDB.include)
+	if negativeList[itemID] then
+		return false
+	else
+		-- check if the item belongs to a category
+		local inCategory
+		for setName,_ in pairs(negativeList) do
+			if type(setName) == "string" then
+				_, inCategory = BrokerGarbage.PT:ItemInSet(itemID, setName)
+			end
+			if inCategory then return false end
+		end
+	end
+
+	return true
+
+	--local positiveList = BrokerGarbage:JoinTables(BG_GlobalDB.exclude, BG_LocalDB.exclude)
+	--local sellList = BrokerGarbage:JoinTables(BG_GlobalDB.forceVendorPrice, BG_GlobalDB.autoSellList, BG_LocalDB.autoSellList)
+end
+
+-- hook UpdateButton function for non-autoloot
+local LootFrame_UpdateButton_orig = LootFrame_UpdateButton
+function LootFrame_UpdateButton(index)
+	LootFrame_UpdateButton_orig(index)
+
+	local slot = (LOOTFRAME_NUMBUTTONS * (LootFrame.page - 1)) + index
+	_, itemName, quantity,  quality, locked = GetLootSlotInfo(slot)
+	itemLink = GetLootSlotLink(slot)
+	if not itemLink then return end
+	if BrokerGarbage:IsInteresting(itemLink) then
+		_G["LootButton"..index.."IconTexture"]:SetDesaturated(false)
+		_G["LootButton"..index.."IconTexture"]:SetAlpha(1)
+	else
+		_G["LootButton"..index.."IconTexture"]:SetDesaturated(true)
+		_G["LootButton"..index.."IconTexture"]:SetAlpha(0.5)
+	end
+end
+
+-- ---------------------------------------------------------
+-- lootmanager functionality from here
+-- ---------------------------------------------------------
+-- for use in CHAT_MSG_LOOT event - destroys watched items as needed
+function BrokerGarbage:AutoDestroy()
+	local count
+	local location = {}
+
+	for itemID,maxCount in pairs(BrokerGarbage:JoinTables(BG_LocalDB.include, BG_GlobalDB.include)) do
+		if type(itemID) == "number" and type(maxCount) == number then
+			count = GetItemCount(itemID)
+
+			-- delete excess items
+			local i = 1
+			location = BrokerGarbage:FindSlotToDelete(itemID)
+			while count > maxCount do
+				-- save the last stack, even if it itself is over our treshold (for stackable items)
+				if i == #location then break end
+				BrokerGarbage:Delete(GetItemInfo(itemID), location[i].bag, location[i].slot)
+
+				count = GetItemCount(itemID)
+				i = i + 1
+			end
+		end
+	end
+end
+
+-- for use in LOOT_OPENED event
+function BrokerGarbage:SelectiveLooting(autoloot)
+	if IsShiftKeyDown() then return end
+	local numItems = GetNumLootItems()
+	local texture, quantity, quality, locked, itemLink
+	local trouble, looted
+	local mobLevel = UnitExists("target") and UnitIsDead("target") and UnitLevel("target")
+	local mobType = UnitCreatureType("target") == BrokerGarbage.locale.CreatureTypeBeast
+
+	if autoloot ~= 0 or BG_GlobalDB.autoLoot or (BG_GlobalDB.autoLootPickpocket and BrokerGarbage.playerClass == "ROGUE" and IsStealthed()) or (BG_GlobalDB.autoLootFishing and IsFishingLoot()) then
+		for slot = 1,numItems do
+			if LootSlotIsItem(slot) then
+				_, _, quantity,  quality, locked = GetLootSlotInfo(slot)
+				itemLink = GetLootSlotLink(slot)
+
+				-- check if we even want this!
+				if BrokerGarbage:IsInteresting(itemLink) then
+					if not locked then
+						if BrokerGarbage.totalFreeSlots <= BG_GlobalDB.tooFewSlots then
+							-- try to compress and make room
+							local itemID = BrokerGarbage:GetItemID(itemLink)
+							local maxStack = select(8, GetItemInfo(itemID))
+							local inBags = mod(GetItemCount(itemID), maxStack)
+							local compareTo = BrokerGarbage:GetCheapest()
+
+							if inBags > 0 and inBags + quantity > maxStack and BG_GlobalDB.autoDestroy then
+								-- we can fit x more in ... *squeeze*
+								local amount = quantity + inBags - maxStack
+								if compareTo[1] and (BrokerGarbage:GetItemValue(itemLink, (quantity-amount)) or 0) < compareTo[1].value then
+									BrokerGarbage:DeletePartialStack(itemID, amount)
+									BrokerGarbage:Debug("Item can be made to fit.", itemLink)
+									looted = true
+								end
+							elseif inBags > 0 then
+								-- this item fits without us doing anything
+								looted = true
+							end
+
+							-- bad luck :/ maybe delete stuff that's worth less? always loot quest items
+							if BG_GlobalDB.autoDestroy and not looted and compareTo[1]
+								and ((BrokerGarbage:GetItemValue(itemLink, quantity) or 0) > compareTo[1].value
+									or select(6,GetItemInfo(itemLink)) == BrokerGarbage.locale.Quest) then
+
+								BrokerGarbage:Delete(select(2,GetItemInfo(compareTo[1].itemID)), compareTo[1].bag, compareTo[1].slot)
+								LootSlot(slot)
+							elseif looted then
+								-- regular looting
+								LootSlot(slot)
+							else
+								-- something is in there, but not valuable enough for us to take it
+								BrokerGarbage:Print(format(BrokerGarbage.locale.couldNotLoot, itemLink))
+							end
+						else
+							-- just loot normally
+							LootSlot(slot)
+						end
+					else
+						-- we should be able to loot this, but we are not. somebody set up us the bomb!
+						trouble = true
+						BrokerGarbage:Debug("Ooops! Something went wrong there. Item is locked", itemLink)
+					end
+				end
+			else
+				-- always take money
+				LootSlot(slot)
+			end
+		end
+		if (GetNumLootItems() ~= 0 and not trouble) or GetNumLootItems() == 0 then
+			CloseLoot()
+		end
+
+	elseif BG_GlobalDB.autoLootSkinning and mobType and BrokerGarbage:CanSkin(mobLevel) then
+		-- clear the mob for skinning
+		BrokerGarbage:Debug("Clearing for Skinning")
+
+		if numItems > BrokerGarbage.totalFreeSlots then
+			-- this might be too much for our inventory to take
+			for slot = 1,numItems do
+				if numItems > BrokerGarbage.totalFreeSlots then
+					_, _, quantity,  quality, locked = GetLootSlotInfo(slot)
+					itemLink = GetLootSlotLink(slot)
+
+					local itemID = BrokerGarbage:GetItemID(itemLink)
+					local maxStack = select(8, GetItemInfo(itemID))
+					local inBags = mod(GetItemCount(itemID), maxStack)
+					local compareTo = BrokerGarbage:GetCheapest()
+
+					if inBags > 0 and inBags + quantity <= maxStack then
+						-- it stacks
+						LootSlot(slot)
+						numItems = numItems - 1
+
+					elseif not IsInteresting(itemLink) then
+						-- loot and immediately destroy
+						LootSlot(slot)
+						numItems = numItems - 1
+						if BG_GlobalDB.autoDestroy then BrokerGarbage:AntiCrap() end
+
+					elseif BG_GlobalDB.autoDestroy then
+						if inBags > 0 and inBags + quantity > maxStack then
+							-- squeeze
+							local amount = quantity + inBags - maxStack
+							if compareTo[1]
+								and (BrokerGarbage:GetItemValue(itemLink, (quantity-amount)) or 0) < compareTo[1].value then
+
+								BrokerGarbage:DeletePartialStack(itemID, amount)
+								LootSlot(slot)
+								numItems = numItems - 1
+							else
+								-- must... delete... cheap... item
+								BrokerGarbage:Delete(compareTo)
+								LootSlot(slot)
+								numItems = numItems - 1
+							end
+						else
+							-- must delete cheap item
+							BrokerGarbage:Delete(compareTo)
+							LootSlot(slot)
+							numItems = numItems - 1
+						end
+					end
+				else
+					-- lucky, something stacked and there's no more trouble
+					LootSlot(slot)
+					numItems = numItems - 1
+				end
+			end
+
+		else
+			-- loot & check later
+			for slot = 1,numItems do
+				LootSlot(slot)
+			end
+		end
+		CloseLoot()
+	end
+end
+BrokerGarbage.lootManager = true
\ No newline at end of file
diff --git a/lootmanager_options.lua b/lootmanager_options.lua
new file mode 100644
index 0000000..4e29f9b
--- /dev/null
+++ b/lootmanager_options.lua
@@ -0,0 +1,196 @@
+_, BrokerGarbage = ...
+
+BrokerGarbage:CheckSettings()
+
+local function Update(self)
+	BrokerGarbage:lootManagerOptionsUpdate(self)
+end
+
+local function ShowOptions(frame)
+	local title = LibStub("tekKonfig-Heading").new(BrokerGarbage.lootManagerOptions, "Broker_Garbage - " .. BrokerGarbage.locale.LMTitle)
+
+	local subtitle = BrokerGarbage.lootManagerOptions:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+	subtitle:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
+	subtitle:SetPoint("RIGHT", BrokerGarbage.lootManagerOptions, -32, 0)
+	subtitle:SetHeight(45)
+	subtitle:SetNonSpaceWrap(true)
+	subtitle:SetJustifyH("LEFT")
+	subtitle:SetJustifyV("TOP")
+	subtitle:SetText(BrokerGarbage.locale.LMSubTitle)
+
+	local enable = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMEnableTitle, "TOPLEFT", subtitle, "BOTTOMLEFT", -2, -4)
+	enable.tiptext = BrokerGarbage.locale.LMEnableTooltip
+	enable:SetChecked(BG_GlobalDB.useLootManager)
+	local checksound = enable:GetScript("OnClick")
+	enable:SetScript("OnClick", function(enable)
+		checksound(enable)
+		BG_GlobalDB.useLootManager = not BG_GlobalDB.useLootManager
+		Update()
+	end)
+
+	-- -- Selective Looting -------------------------------------------------------
+	local selective = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMSelectiveTitle, "TOPLEFT", enable, "BOTTOMLEFT", 14, -20)
+	selective.tiptext = BrokerGarbage.locale.LMSelectiveTooltip
+	selective:SetChecked(BG_LocalDB.selectiveLooting)
+	selective:SetScript("OnClick", function(selective)
+		checksound(selective)
+		BG_LocalDB.selectiveLooting = not BG_LocalDB.selectiveLooting
+		Update()
+	end)
+
+
+	local autoLoot = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMAutoLootTitle, "TOPLEFT", selective, "BOTTOMLEFT", 14, 0)
+	autoLoot.tiptext = BrokerGarbage.locale.LMAutoLootTooltip
+	autoLoot:SetChecked(BG_GlobalDB.autoLoot)
+	autoLoot:SetScript("OnClick", function(autoLoot)
+		checksound(autoLoot)
+		BG_GlobalDB.autoLoot = not BG_GlobalDB.autoLoot
+		Update()
+	end)
+
+	local autoLoot_skinning = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMAutoLootSkinningTitle, "TOPLEFT", autoLoot, "BOTTOMLEFT", 14, 0)
+	autoLoot_skinning.tiptext = BrokerGarbage.locale.LMAutoLootSkinningTooltip
+	autoLoot_skinning:SetChecked(BG_GlobalDB.autoLootSkinning)
+	autoLoot_skinning:SetScript("OnClick", function(autoLoot_skinning)
+		checksound(autoLoot_skinning)
+		BG_GlobalDB.autoLootSkinning = not BG_GlobalDB.autoLootSkinning
+	end)
+
+	local autoLoot_pickpocket = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMAutoLootPickpocketTitle, "TOPLEFT", autoLoot_skinning, "BOTTOMLEFT", 0, 0)
+	autoLoot_pickpocket.tiptext = BrokerGarbage.locale.LMAutoLootPickpocketTooltip
+	autoLoot_pickpocket:SetChecked(BG_GlobalDB.autoLootPickpocket)
+	autoLoot_pickpocket:SetScript("OnClick", function(autoLoot_pickpocket)
+		checksound(autoLoot_pickpocket)
+		BG_GlobalDB.autoLootPickpocket = not BG_GlobalDB.autoLootPickpocket
+	end)
+
+	local autoLoot_fishing = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMAutoLootFishingTitle, "TOPLEFT", autoLoot_pickpocket, "BOTTOMLEFT", 0, 0)
+	autoLoot_fishing.tiptext = BrokerGarbage.locale.LMAutoLootFishingTooltip
+	autoLoot_fishing:SetChecked(BG_GlobalDB.autoLootPickpocket)
+	autoLoot_fishing:SetScript("OnClick", function(autoLoot_fishing)
+		checksound(autoLoot_fishing)
+		BG_GlobalDB.autoLootFishing = not BG_GlobalDB.autoLootFishing
+	end)
+
+
+	local autoDestroy = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMAutoDestroyTitle, "TOPLEFT", autoLoot_fishing, "BOTTOMLEFT", -14, 0)
+	autoDestroy.tiptext = BrokerGarbage.locale.LMAutoDestroyTooltip
+	autoDestroy:SetChecked(BG_GlobalDB.autoDestroy)
+	autoDestroy:SetScript("OnClick", function(autoDestroy)
+		checksound(autoDestroy)
+		BG_GlobalDB.autoDestroy = not BG_GlobalDB.autoDestroy
+		Update()
+	end)
+
+	local minFreeSlots = LibStub("tekKonfig-Slider").new(BrokerGarbage.lootManagerOptions, BrokerGarbage.locale.LMFreeSlotsTitle, 0, 30, "TOPLEFT", autoDestroy, "BOTTOMLEFT", 14, -20)
+	minFreeSlots.tiptext = BrokerGarbage.locale.LMFreeSlotsTooltip
+	minFreeSlots:SetWidth(200)
+	minFreeSlots:SetValueStep(1)
+	minFreeSlots:SetValue(BG_GlobalDB.tooFewSlots)
+	minFreeSlots.text = minFreeSlots:CreateFontString("$parentCenterText", "ARTWORK", "GameFontHighlightSmall")
+	minFreeSlots.text:SetPoint("TOP", minFreeSlots, "BOTTOM", 0, 3)
+	minFreeSlots.text:SetText(BG_GlobalDB.tooFewSlots)
+	minFreeSlots:SetScript("OnValueChanged", function(minFreeSlots)
+		BG_GlobalDB.tooFewSlots = minFreeSlots:GetValue()
+		minFreeSlots.text:SetText(BG_GlobalDB.tooFewSlots)
+		BrokerGarbage:ScanInventory()
+	end)
+
+	-- -- Restack -----------------------------------------------------------------
+	local restack = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMRestackTitle, "TOPLEFT", selective, "TOPLEFT", 200, 0)
+	restack.tiptext = BrokerGarbage.locale.LMRestackTooltip
+	restack:SetChecked(BG_GlobalDB.restackIfNeeded)
+	restack:SetScript("OnClick", function(restack)
+		checksound(restack)
+		BG_GlobalDB.restackIfNeeded = not BG_GlobalDB.restackIfNeeded
+		Update()
+	end)
+
+	local fullRestack = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMFullRestackTitle, "TOPLEFT", restack, "BOTTOMLEFT", 14, 0)
+	fullRestack.tiptext = BrokerGarbage.locale.LMFullRestackTooltip
+	fullRestack:SetChecked(BG_GlobalDB.restackFullInventory)
+	fullRestack:SetScript("OnClick", function(fullRestack)
+		checksound(fullRestack)
+		BG_GlobalDB.restackFullInventory = not BG_GlobalDB.restackFullInventory
+	end)
+
+	-- -- Opening Items -----------------------------------------------------------
+	local openContainers = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMOpenContainersTitle, "TOPLEFT", fullRestack, "BOTTOMLEFT", -14, -20)
+	openContainers.tiptext = BrokerGarbage.locale.LMOpenContainersTooltip
+	openContainers:SetChecked(BG_GlobalDB.openContainers)
+	openContainers:SetScript("OnClick", function(openContainers)
+		checksound(openContainers)
+		BG_GlobalDB.openContainers = not BG_GlobalDB.openContainers
+	end)
+
+	local openClams = LibStub("tekKonfig-Checkbox").new(BrokerGarbage.lootManagerOptions, nil, BrokerGarbage.locale.LMOpenClamsTitle, "TOPLEFT", openContainers, "BOTTOMLEFT", 0, 0)
+	openClams.tiptext = BrokerGarbage.locale.LMOpenClamsTooltip
+	openClams:SetChecked(BG_GlobalDB.openClams)
+	openClams:SetScript("OnClick", function(openClams)
+		checksound(openClams)
+		BG_GlobalDB.openClams = not BG_GlobalDB.openClams
+	end)
+
+	function BrokerGarbage.lootManagerOptionsUpdate(self)
+		if BG_GlobalDB.useLootManager then
+			restack:Enable()
+			if BG_GlobalDB.restackIfNeeded then
+				fullRestack:Enable()
+			else
+				fullRestack:Disable()
+			end
+
+			openContainers:Enable()
+			openClams:Enable()
+
+			selective:Enable()
+			if BG_LocalDB.selectiveLooting then
+				autoLoot:Enable()
+				autoDestroy:Enable()
+
+				if not BG_GlobalDB.autoLoot then
+					autoLoot_skinning:Enable()
+					autoLoot_pickpocket:Enable()
+					autoLoot_fishing:Enable()
+				else
+					autoLoot_skinning:Disable()
+					autoLoot_pickpocket:Disable()
+					autoLoot_fishing:Disable()
+				end
+
+				if BG_GlobalDB.autoDestroy then
+					minFreeSlots:Enable()
+				else
+					minFreeSlots:Disable()
+				end
+			else
+				autoLoot:Disable()
+				autoDestroy:Disable()
+				autoLoot_skinning:Disable()
+				autoLoot_pickpocket:Disable()
+				autoLoot_fishing:Disable()
+				minFreeSlots:Disable()
+			end
+
+		else
+			restack:Disable()
+				fullRestack:Disable()
+
+			openContainers:Disable()
+			openClams:Disable()
+
+			selective:Disable()
+				autoLoot:Disable()
+					autoLoot_skinning:Disable()
+					autoLoot_pickpocket:Disable()
+					autoLoot_fishing:Disable()
+				autoDestroy:Disable()
+					minFreeSlots:Disable()
+		end
+	end
+
+	BrokerGarbage:lootManagerOptionsUpdate()
+	BrokerGarbage.lootManagerOptions:SetScript("OnShow", BrokerGarbage.lootManagerOptionsUpdate)
+end
+
+BrokerGarbage.lootManagerOptions:SetScript("OnShow", ShowOptions)
\ No newline at end of file
diff --git a/options.lua b/options.lua
index 42165cf..88c64fe 100644
--- a/options.lua
+++ b/options.lua
@@ -4,13 +4,13 @@ BrokerGarbage:CheckSettings()

 -- rarity strings (no need to localize)
 BrokerGarbage.quality = {
-	[0] = "|cff9D9D9D"..ITEM_QUALITY0_DESC.."|r",
-	[1] = "|cffFFFFFF"..ITEM_QUALITY1_DESC.."|r",
-	[2] = "|cff1EFF00"..ITEM_QUALITY2_DESC.."|r",
-	[3] = "|cff0070FF"..ITEM_QUALITY3_DESC.."|r",
-	[4] = "|cffa335ee"..ITEM_QUALITY4_DESC.."|r",
-	[5] = "|cffff8000"..ITEM_QUALITY5_DESC.."|r",
-	[6] = "|cffE6CC80"..ITEM_QUALITY6_DESC.."|r",
+	[0] = select(4,GetItemQualityColor(0))..ITEM_QUALITY0_DESC.."|r",
+	[1] = select(4,GetItemQualityColor(1))..ITEM_QUALITY1_DESC.."|r",
+	[2] = select(4,GetItemQualityColor(2))..ITEM_QUALITY2_DESC.."|r",
+	[3] = select(4,GetItemQualityColor(3))..ITEM_QUALITY3_DESC.."|r",
+	[4] = select(4,GetItemQualityColor(4))..ITEM_QUALITY4_DESC.."|r",
+	[5] = select(4,GetItemQualityColor(5))..ITEM_QUALITY5_DESC.."|r",
+	[6] = select(4,GetItemQualityColor(6))..ITEM_QUALITY6_DESC.."|r",
 	}

 -- create drop down menu table for PT sets
@@ -54,10 +54,18 @@ BrokerGarbage.options:Hide()

 -- default / main options
 BrokerGarbage.basicOptions = CreateFrame("Frame", "BrokerGarbageOptionsPositiveFrame", InterfaceOptionsFramePanelContainer)
-BrokerGarbage.basicOptions.name = "Basic Settings"
+BrokerGarbage.basicOptions.name = BrokerGarbage.locale.BasicOptionsTitle
 BrokerGarbage.basicOptions.parent = "Broker_Garbage"
 BrokerGarbage.basicOptions:Hide()

+-- Loot Manager options
+if BrokerGarbage.lootManager then
+	BrokerGarbage.lootManagerOptions = CreateFrame("Frame", "BrokerGarbageOptionsFrame", InterfaceOptionsFramePanelContainer)
+	BrokerGarbage.lootManagerOptions.name = BrokerGarbage.locale.LMTitle
+	BrokerGarbage.lootManagerOptions.parent = "Broker_Garbage"
+	BrokerGarbage.lootManagerOptions:Hide()
+end
+
 -- list options: positive panel
 BrokerGarbage.listOptionsPositive = CreateFrame("Frame", "BrokerGarbageOptionsPositiveFrame", InterfaceOptionsFramePanelContainer)
 BrokerGarbage.listOptionsPositive.name = BrokerGarbage.locale.LOPTitle
@@ -237,7 +245,7 @@ local function ShowOptions(frame)
 	localmoneyinfo:SetNonSpaceWrap(true)
 	localmoneyinfo:SetJustifyH("LEFT")
 	localmoneyinfo:SetJustifyV("TOP")
-	localmoneyinfo:SetText(format(BrokerGarbage.locale.LocalStatisticsHeading, GetUnitName("player")))
+	localmoneyinfo:SetText(format(BrokerGarbage.locale.LocalStatisticsHeading, UnitName("player")))

 	local localearned = BrokerGarbage.options:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
 	localearned:SetWidth(150)
@@ -283,6 +291,7 @@ local function ShowOptions(frame)
 	globalreset:SetWidth(150)
 	globalreset:SetScript("OnClick", function()
 		BrokerGarbage:ResetAll(true)
+		UpdateStats()
 	end)

 	local localreset = LibStub("tekKonfig-Button").new(BrokerGarbage.options, "TOPLEFT", globalreset, "TOPRIGHT", 20, 0)
@@ -291,6 +300,7 @@ local function ShowOptions(frame)
 	localreset:SetWidth(150)
 	localreset:SetScript("OnClick", function()
 		BrokerGarbage:ResetAll(false)
+		UpdateStats()
 	end)

 	-- when panel is shown this will update the statistics data
@@ -776,8 +786,52 @@ local function ShowListOptions(frame)
 	emptyAutoSellList:SetNormalTexture("Interface\\Buttons\\Ui-grouploot-pass-up")
 	emptyAutoSellList.tiptext = BrokerGarbage.locale.LONAutoSellEmptyTT

-	-- function that updates & shows items from various lists
+	-- function to set the drop treshold (limit) via the mousewheel
+	local function OnMouseWheel(self, dir)
+		if type(self.itemID) ~= "number" then return end
+		BrokerGarbage.debug = self
+		local list, text
+
+		if dir == 1 then
+			-- up
+			if self.isGlobal then
+				list = BG_GlobalDB[self.list]
+			else
+				list = BG_LocalDB[self.list]
+			end
+
+			-- change stuff
+			if list[self.itemID] == true then
+				list[self.itemID] = 1
+			else
+				list[self.itemID] = list[self.itemID] + 1
+			end
+			self.limit:SetText(list[self.itemID])
+
+		else
+			-- down
+			if self.isGlobal then
+				list = BG_GlobalDB[self.list]
+			else
+				list = BG_LocalDB[self.list]
+			end
+
+			-- change stuff
+			if list[self.itemID] == true then
+				text = ""
+			elseif list[self.itemID] == 1 then
+				list[self.itemID] = true
+				text = ""
+			else
+				list[self.itemID] = list[self.itemID] - 1
+				text = list[self.itemID]
+			end
+			self.limit:SetText(text)
+		end
+	end
+
 	local numCols = 8
+	-- function that updates & shows items from various lists
 	function BrokerGarbage:ListOptionsUpdate(listName)
 		if not listName then
 			BrokerGarbage:ListOptionsUpdate("include")
@@ -850,10 +904,10 @@ local function ShowListOptions(frame)
 				local itemLink, texture
 				if type(itemID) ~= "number" then
 					-- this is an item category
-					BrokerGarbage:Debug("Encountered Category String!", itemID)
 					itemLink = nil
 					button.tiptext = itemID		-- category description string
 					texture = "Interface\\Icons\\Trade_engineering"
+
 				else
 					-- this is an explicit item
 					_, itemLink, _, _, _, _, _, _, _, texture, _ = GetItemInfo(itemID)
@@ -863,14 +917,18 @@ local function ShowListOptions(frame)
 					-- everything's fine
 					button.itemID = itemID
 					button.itemLink = itemLink
+					button.isGlobal = globalList[itemID] or false
+					button.limit:SetText((button.isGlobal and globalList[itemID] ~= true and globalList[itemID])
+						or (localList[itemID] ~= true and localList[itemID]) or "")
 					button:SetNormalTexture(texture)
-					button:GetNormalTexture():SetDesaturated(globalList[itemID] or false)		-- desaturate global list items
+					button:GetNormalTexture():SetDesaturated(button.isGlobal)		-- desaturate global list items
 				else
 					-- an item the server has not seen
 					button.itemID = itemID
 					button.tiptext = "ID: "..itemID
 					button:SetNormalTexture("Interface\\Icons\\Inv_misc_questionmark")
 				end
+				button.list = listName
 				button:SetChecked(false)
 				button:Show()
 			else
@@ -880,6 +938,17 @@ local function ShowListOptions(frame)
 				iconbutton:SetWidth(36)
 				iconbutton:SetHeight(36)

+				local limit = iconbutton:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+				limit:SetPoint("BOTTOMLEFT", iconbutton, "BOTTOMLEFT", 2, 1)
+				limit:SetPoint("BOTTOMLEFT", iconbutton, "BOTTOMLEFT", 2, 1)
+				limit:SetPoint("BOTTOMRIGHT", iconbutton, "BOTTOMRIGHT", -3, 1)
+				limit:SetHeight(20)
+				limit:SetJustifyH("RIGHT")
+				limit:SetJustifyV("BOTTOM")
+				limit:SetText("")
+
+				iconbutton.limit = limit
+
 				iconbutton:SetNormalTexture("Interface\\Icons\\Inv_misc_questionmark")
 				iconbutton:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
 				iconbutton:SetCheckedTexture("Interface\\Buttons\\UI-Button-Outline")
@@ -889,9 +958,26 @@ local function ShowListOptions(frame)
 				tex:SetPoint("CENTER")
 				tex:SetWidth(36/37*66) tex:SetHeight(36/37*66)

+				iconbutton:SetScript("OnClick", function(self)
+					local check = self:GetChecked()
+					BrokerGarbage:Debug("OnClick", check)
+
+					if IsModifiedClick("CHATLINK") and ChatFrameEditBox:IsVisible() then
+						-- post item link
+						ChatFrameEditBox:Insert(self.itemLink)
+						self:SetChecked(not check)
+					elseif not IsModifierKeyDown() then
+						self:SetChecked(check)
+					else
+						self:SetChecked(not check)
+					end
+				end)
 				iconbutton:SetScript("OnEnter", ShowTooltip)
 				iconbutton:SetScript("OnLeave", HideTooltip)
-				-- TODO: iconbutton:RegisterForClicks("Rightclick")
+				if listName == "include" then
+					iconbutton:EnableMouseWheel(true)
+					iconbutton:SetScript("OnMouseWheel", OnMouseWheel)
+				end

 				if index == 1 then
 					-- place first icon
@@ -919,14 +1005,14 @@ local function ShowListOptions(frame)

 	local function ItemDrop(self, item)
 		local cursorType, itemID, link = GetCursorInfo()
-		if not cursorType == "item" and not item then
+		BrokerGarbage:Print("ItemDrop - "..(item or "").." ("..(link or "").."/"..(itemID or "")..")"..(cursorType or ""))
+
+		if (not itemID and (item == "RightButton" or item == "LeftButton" or item == "MiddleButton")) then
 			return
 		end

 		-- find the item we want to add
-		if item and item == "RightButton" then
-			return
-		elseif not item or item == "LeftButton" then
+		if itemID then
 			-- real items
 			itemID = itemID
 		else
@@ -1129,21 +1215,21 @@ local function ShowListOptions(frame)
 		elseif self == promote then
 			for i, button in pairs(BrokerGarbage.listButtons.exclude) do
 				if button:GetChecked() then
-					BG_GlobalDB.exclude[button.itemID] = true
+					BG_GlobalDB.exclude[button.itemID] = BG_LocalDB.exclude[button.itemID]
 				end
 			end
 			BrokerGarbage:ListOptionsUpdate("exclude")
 		elseif self == promote3 then
 			for i, button in pairs(BrokerGarbage.listButtons.include) do
 				if button:GetChecked() then
-					BG_GlobalDB.include[button.itemID] = true
+					BG_GlobalDB.include[button.itemID] = BG_LocalDB.include[button.itemID]
 				end
 			end
 			BrokerGarbage:ListOptionsUpdate("include")
 		elseif self == promote3 then
 			for i, button in pairs(BrokerGarbage.listButtons.autosell) do
 				if button:GetChecked() then
-					BG_GlobalDB.autoSellList[button.itemID] = true
+					BG_GlobalDB.autoSellList[button.itemID] = BG_LocalDB.autoSellList[button.itemID]
 				end
 			end
 			BrokerGarbage:ListOptionsUpdate("autosell")
@@ -1233,6 +1319,7 @@ BrokerGarbage.listOptionsNegative:SetScript("OnShow", ShowListOptions)

 InterfaceOptions_AddCategory(BrokerGarbage.options)
 InterfaceOptions_AddCategory(BrokerGarbage.basicOptions)
+InterfaceOptions_AddCategory(BrokerGarbage.lootManagerOptions)
 InterfaceOptions_AddCategory(BrokerGarbage.listOptionsPositive)
 InterfaceOptions_AddCategory(BrokerGarbage.listOptionsNegative)
 LibStub("tekKonfig-AboutPanel").new("Broker_Garbage", "Broker_Garbage")
@@ -1259,6 +1346,20 @@ function SlashCmdList.BROKERGARBAGE(msg, editbox)
 	elseif command == "options" or command == "config" or command == "option" or command == "menu" then
 		InterfaceOptionsFrame_OpenToCategory(BrokerGarbage.options)

+	elseif command == "limit" or command == "glimit" or command == "globallimit" then
+		local itemID, count = rest:match("^[^0-9]-([0-9]+).-([0-9]+)$")
+		itemID = tonumber(itemID)
+		count = tonumber(count)
+
+		if string.find(command, "g") then
+			BG_GlobalDB.include[itemID] = count
+		else
+			BG_LocalDB.include[itemID] = count
+		end
+		local itemLink = select(2,GetItemInfo(itemID))
+		BrokerGarbage:Print(format("%s has been assigned a limit of %d.", itemLink, count))
+		BrokerGarbage:ListOptionsUpdate("include")
+
 	else
 		BrokerGarbage:Print(BrokerGarbage.locale.slashCommandHelp)
 	end
diff --git a/readme.txt b/readme.txt
index 36e8dfc..1d15de8 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,7 +1,7 @@
 Broker_Garbage
 ==============
 Author: ckaotik
-Version: 3.3v16
+Version: 3.3v17
 WoW Version: 3.3.2 (TOC 30300)

 WoWInterface: http://www.wowinterface.com/downloads/info15531-Broker_Garbage.html
@@ -55,6 +55,7 @@ Items on this list will never have their auction value used. This is useful for
 * Include List
 Items on this list will be always be shown in the drop Tooltip, no matter what Quality Treshold you might have set. If you have too many, you won't see any other items in the tooltip. Caution!
 Grayed out items on there are items that are on your global list, active for all characters. Colorful ones are just for your current character.
+Since 3.3v17 include list items also can have a limit set. Use this if for example you only want to keep 5 Soulshards. Excess items will be listed in the Tooltip!

 * Auto-Sell List
 Items on this list will be sold whenever you talk to a vendor. Items of higher quality than your Quality Treshold WILL be sold, just keep that in mind.
@@ -87,7 +88,26 @@ Some examples:
 "%1$sx%2$d"						->		[Hearthstone]x1
 "%4$d/%5$d - %1$s"				->		18/48 - [Hearthstone]

-8. How you can help
+8. Slash Commands
+-----------------
+Broker_Garbage supports a hand full of slash commands. These are /garbage or short, /garb. Parameters supported:
+
+	/garb format <formatstring>
+See information on this one above, in part 7.
+
+	/garb stats -or- /garb total -or- /garbage trash
+Prints very simplified statistics to the chat frame. Further statistics/details can be found in the options menu.
+
+	/garb option -or- /garb options -or- /garb menu -or- /garb config
+All of these just open up the config window ;)
+
+	/garb limit <itemLink or itemID> <amount>
+This will add the corresponding item to the character's include list and add a limit to it.
+
+	/garb glimit -or- /garb globallimit
+Same as the above, just adds the item to the global include list.
+
+9. How you can help
 -----------------
 I still need a few translations to get done. If you would like to help me with that, please do so on http://wow.curseforge.com/addons/broker_garbage/localization/  .
 Likewise, I need people to test the addon with different auction addons. If you have one that isn't yet supported, make a Feature Suggestion (see 4.).