changeset 128:451d8a19edea

Ticket 33 - Implemented a persistent queue. This allows the crafting queue to be seen even if your tradeskills aren't open and allows you to mix all of your tradeskills into a single queue.
author Asa Ayers <Asa.Ayers@Gmail.com>
date Thu, 02 Sep 2010 23:59:09 -0700
parents 4f26dc55455d
children 5f6182a97d40 7f81764aa03a
files CHANGELOG.txt Core.lua Modules/Crafting.lua Modules/Tooltip.lua
diffstat 4 files changed, 209 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.txt	Thu Sep 02 23:29:17 2010 -0700
+++ b/CHANGELOG.txt	Thu Sep 02 23:59:09 2010 -0700
@@ -6,6 +6,7 @@
 - Changed Total Profit to Profit Each to match the rest of the interface. Cost and Estimated Sale are both Each.
 - When using the process button for Enchanting, ItemAuditor will check which vellum is used and will use the vellum from your inventory. If the correct vellum is not found, it will upgrade to the next level (use vellum II instead of vellum I). This also means that you have to press process for each scroll to be created.
 - Changed the Have Mats column to show the number of items you could create with the materials you have instead of just a y/n. The have mats filter simply checks that you can make at least 1.
+- Ticket 33 - Implemented a persistent queue. This allows the crafting queue to be seen even if your tradeskills aren't open and allows you to mix all of your tradeskills into a single queue.
 
 2010-09-01  Asa Ayers  <Asa.Ayers@Gmail.com>
 
--- a/Core.lua	Thu Sep 02 23:29:17 2010 -0700
+++ b/Core.lua	Thu Sep 02 23:59:09 2010 -0700
@@ -68,6 +68,7 @@
 		items = {},
 		outbound_cod = {},
 		mailbox = {},
+		queue = {}
 	},
 }
 
--- a/Modules/Crafting.lua	Thu Sep 02 23:29:17 2010 -0700
+++ b/Modules/Crafting.lua	Thu Sep 02 23:59:09 2010 -0700
@@ -10,6 +10,8 @@
 local parseMoney = ItemAuditor.parseMoney
 
 local realData = {}
+local nameMap = nil
+local shoppingList = nil
 
 local vellumLevelMap = {
 	[38682] = 37602, -- Armor Vellum => Armor Vellum II
@@ -18,6 +20,45 @@
 	[39350] = 43146, -- Weapon Vellum II => Weapon Vellum III
 }
 
+function Crafting:OnInitialize()
+	local allQueues = ItemAuditor.db.factionrealm.queue
+	if not allQueues[UnitName("player")] then
+		allQueues[UnitName("player")] = {}
+	end
+	realData = allQueues[UnitName("player")]
+
+	self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
+end
+
+local function getQueueLocation(name)
+	if not nameMap then
+		nameMap = {}
+		for key, data in pairs(realData) do
+			nameMap[data.skillName] = key
+		end
+	end
+	return nameMap[name]
+end
+
+--@debug@
+Crafting.getQueueLocation = getQueueLocation
+function Crafting.getNameMap()
+	return nameMap
+end
+
+function Crafting.getRealData()
+	return realData
+end
+--@end-debug@
+
+function Crafting:UNIT_SPELLCAST_SUCCEEDED(event, unit, spell)
+	if unit == "player" and getQueueLocation(spell) then
+		local data = realData[getQueueLocation(spell)]
+		data.queue = data.queue - 1
+		ItemAuditor:RefreshCraftingTable()
+	end
+end
+
 local queueDestinations = {}
 local displayCraftingDestinations = {}
 function Crafting.RegisterQueueDestination(name, destination)
@@ -152,6 +193,10 @@
 Crafting.filter_have_mats = false
 Crafting.filter_show_all = false
 local function tableFilter(self, row, ...)
+	if Crafting.nameFilter then
+		return string.find(row[1], Crafting.nameFilter) ~= nil
+	end
+
 	if Crafting.filter_show_all then
 		return true
 	end
@@ -189,11 +234,31 @@
 		craftingTable:RegisterEvents({
 			["OnEnter"] = function (rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
 				if realrow then
-					local data = realData[realrow]
-					
-					GameTooltip:SetOwner(rowFrame, "ANCHOR_CURSOR")
-					GameTooltip:SetHyperlink(data.link)
-					GameTooltip:Show()
+					if column == 1 then
+						local data = realData[realrow]
+
+						GameTooltip:SetOwner(rowFrame, "ANCHOR_CURSOR")
+						GameTooltip:SetHyperlink(data.link)
+						GameTooltip:Show()
+					elseif column == 2 then
+						local data = realData[realrow]
+						GameTooltip:SetOwner(rowFrame, "ANCHOR_CURSOR")
+						GameTooltip:SetText(format('Create %sx%s', data.link, data.queue))
+						for i, reagent in pairs(data.reagents) do
+							GameTooltip:AddDoubleLine("\124cffffffff"..reagent.link, format("\124cffffffff%s/%s", reagent.count-reagent.need, reagent.count))
+--[[
+							reagents[reagentId] = {
+								link = reagentLink,
+								itemID = vellumID,
+								name = reagentName,
+								count = 1,
+								price = self:GetReagentCost(reagentLink, 1),
+								need = 0, -- This will get populated after the decisions have been made. it can't
+								-- be done before that because highest profit items get priority on materials.
+							}]]
+						end
+						GameTooltip:Show()
+					end
 				end
 			end,
 			["OnLeave"] = function (rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
@@ -274,6 +339,12 @@
 		btnProcess:SetScript("OnClick", function (self, button, down)
 			local data = ItemAuditor:GetCraftingRow(1)
 			if data then
+				-- This will make sure the correct tradeskill window is open.
+				local tradeskillName = GetTradeSkillLine()
+				if data.tradeskillName ~= tradeskillName then
+					CastSpellByName(data.tradeskillName)
+				end
+			
 				local queue = data.queue
 				local vellumID = nil
 				_, _, _, _, altVerb = GetTradeSkillInfo(data.tradeSkillIndex)
@@ -287,8 +358,6 @@
 					useVellum(vellumID)
 				end
 
-				data.queue = data.queue - queue
-				ItemAuditor:RefreshCraftingTable()
 				UpdateProcessTooltip()
 			end
 		end)
@@ -418,7 +487,17 @@
 
 Crafting.RegisterCraftingDecider('Is Profitable', isProfitable, isProfitableOptions)
 
+function Crafting.ClearProfession(tradeskillName)
+	-- This will initialize nameMap if it isn't already.
+	getQueueLocation('')
 
+	for key = #(realData), 1, -1 do
+		if realData[key].tradeskillName == tradeskillName then
+			nameMap[realData[key].tradeskillName] = nil
+			tremove(realData, key)
+		end
+	end
+end
 
 local tableData = {}
 function ItemAuditor:UpdateCraftingTable()
@@ -432,18 +511,27 @@
 		self:Print("This feature requires Auctionator, Auctioneer, AuctionLite, or AuctionMaster.")
 		return
 	end
-	wipe(realData)
+	local tradeskillName = GetTradeSkillLine()
+	Crafting.ClearProfession(tradeskillName)
+	shoppingList = nil
+	
 	wipe(tableData)
 	
 	local profitableItems = {}
 	local profitableIndex = 1
 	local numChecked = 0
-	local row = 1
+	local row = #(realData)+1
+	local numTradeSkills = GetNumTradeSkills()
+	if tradeskillName == 'UNKNOWN' then
+		numTradeSkills  = 0
+	end
 	
-	for i = 1, GetNumTradeSkills() do
+	for i = 1, numTradeSkills do
 		local itemLink = GetTradeSkillItemLink(i)
 		local itemId = Utils.GetItemID(itemLink)
 		local vellumID = nil
+		
+		local spellName = itemName
 
 		--Figure out if its an enchant or not
 		_, _, _, _, altVerb = GetTradeSkillInfo(i)
@@ -503,6 +591,7 @@
 					recipeID = Utils.GetItemID(recipeLink),
 					link = itemLink,
 					name = itemName,
+					skillName = skillName,
 					count = count,
 					price = price,
 					cost = totalCost,
@@ -512,6 +601,7 @@
 					tradeSkillIndex = i,
 					queue = 0,
 					winner = "",
+					tradeskillName = tradeskillName,
 				}
 				
 				data.winner, data.queue = Decide(data)
@@ -526,8 +616,9 @@
 				-- If a tradeskill makes 5 at a time and something asks for 9, we should only 
 				-- craft twice to get 10.
 				data.queue = ceil(data.queue / GetTradeSkillNumMade(i))
-				
+
 				realData[row] = data
+				nameMap[skillName] = row
 				row = row + 1
 			end
 		end
@@ -564,8 +655,79 @@
 	end
 end
 
+
+local numOwned = {}
+
+local function BuildShoppingList(character, queue)
+	for key, data in pairs(queue) do
+		if data.queue > 0 then
+			for id, reagent in pairs(data.reagents) do
+				if not numOwned[reagent.link] then
+					numOwned[reagent.link] = ItemAuditor:GetItemCount(Utils.GetItemID(reagent.link))
+				end
+				numOwned[reagent.link] = numOwned[reagent.link] - reagent.count
+
+				shoppingList[reagent.itemID] = shoppingList[reagent.itemID] or {
+					total = 0,
+					need = 0,
+					characters = {}
+				}
+				local slItem = shoppingList[reagent.itemID]
+
+				
+				if numOwned[reagent.link] < 0 and not vellumLevelMap[reagent.itemID] then
+					reagent.need = min(reagent.count, abs(numOwned[reagent.link]))
+				elseif numOwned[reagent.link] >= 0 then
+					reagent.need = 0
+				end
+				shoppingList[reagent.itemID].total = shoppingList[reagent.itemID].total + reagent.count
+				shoppingList[reagent.itemID].need = shoppingList[reagent.itemID].need + reagent.need
+
+				slItem.characters[UnitName("player")] = slItem.characters[UnitName("player")] or {}
+				slItem.characters[UnitName("player")][data.recipeLink] = {
+					count = reagent.count,
+					need = reagent.need,
+				}
+			end
+		end
+	end
+end
+
+function Crafting.GetShoppingList(itemID)
+	if not shoppingList then
+		shoppingList = {}
+		wipe(numOwned)
+
+		-- This is done here instead of in the loop to make sure the current
+		-- character gets the first pick of materials.
+		local me = UnitName("player")
+		BuildShoppingList(me, realData)
+
+		for alt, queue in pairs(ItemAuditor.db.factionrealm.queue) do
+			if alt ~= me then
+				BuildShoppingList(alt, queue)
+			end
+		end
+	elseif shoppingList[itemID] then
+		local data = shoppingList[itemID]
+		if data.need ~= max(0, data.total - ItemAuditor:GetItemCount(itemID)) then
+			shoppingList = nil
+			-- I'm rebuilding the list instead of just the item because
+			-- it will be eaiser than tracking down the queued recipes that
+			-- need to change. If this becomes a problem, I may change it.
+			return Crafting.GetShoppingList(itemID)
+		end
+	end
+
+	return shoppingList[itemID]
+end
+
 function ItemAuditor:RefreshCraftingTable()
+	tableData = {}
+	nameMap = {}
 	for key, data in pairs(realData) do
+		nameMap[data.name] = key
+
 		tableData[key] = {
 			data.name,
 			data.cost,
--- a/Modules/Tooltip.lua	Thu Sep 02 23:29:17 2010 -0700
+++ b/Modules/Tooltip.lua	Thu Sep 02 23:59:09 2010 -0700
@@ -1,10 +1,16 @@
 local ItemAuditor = select(2, ...)
 local Tooltip = ItemAuditor:NewModule("Tooltip")
 
+local Crafting
+local Utils = ItemAuditor:GetModule("Utils")
+
 local function ShowTipWithPricing(tip, link, num)
 	if (link == nil) then
 		return;
 	end
+	if not Crafting then
+		Crafting = ItemAuditor:GetModule("Crafting")
+	end
 
 	-- local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, _, _, _, _, itemVendorPrice = GetItemInfo (link);
 	-- local _, _, Color, Ltype, Id, Enchant, Gem1, Gem2, Gem3, Gem4, Suffix, Unique, LinkLvl, Name = string.find(link, "|?c?f?f?(%x*)|?H?([^:]*):?(%d+):?(%d*):?(%d*):?(%d*):?(%d*):?(%d*):?(%-?%d*):?(%-?%d*):?(%d*)|?h?%[?([^%[%]]*)%]?|?h?|?r?")
@@ -41,6 +47,34 @@
 			show = true
 		end
 	end
+
+	
+	shoppingList = Crafting.GetShoppingList(Utils.GetItemID(link))
+	if shoppingList then
+		tip:AddDoubleLine("\124cffffffffIA Queue", "\124cffffffffhave/total")
+		for character, recipes in pairs(shoppingList.characters) do
+			local count = 0
+			local need = 0
+			local color = '\124cff00ff00' -- green
+			for link, data in pairs(recipes) do
+				need = need + data.need
+				count = count + data.count
+			end
+			if need > 0 then
+				color = '\124cffff0000' -- red
+			end
+			tip:AddDoubleLine("\124cffffffff"..character, format("%s%s/%s", color, count-need, count))
+			if true then -- show details
+				for link, data in pairs(recipes) do
+					if data.need > 0 then
+						tip:AddDoubleLine("\124cffffffff"..link, format("\124cffffffff%s/%s", data.count-data.need, data.count))
+					end
+				end
+			end
+
+		end
+		show = true
+	end
 	
 	if show then 
 		tip:Show()