comparison Modules/Crafting.lua @ 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 e8d3c299542c
children 78c6d905c2e1 7f81764aa03a
comparison
equal deleted inserted replaced
127:4f26dc55455d 128:451d8a19edea
8 8
9 local validateMoney = ItemAuditor.validateMoney 9 local validateMoney = ItemAuditor.validateMoney
10 local parseMoney = ItemAuditor.parseMoney 10 local parseMoney = ItemAuditor.parseMoney
11 11
12 local realData = {} 12 local realData = {}
13 local nameMap = nil
14 local shoppingList = nil
13 15
14 local vellumLevelMap = { 16 local vellumLevelMap = {
15 [38682] = 37602, -- Armor Vellum => Armor Vellum II 17 [38682] = 37602, -- Armor Vellum => Armor Vellum II
16 [37602] = 43145, -- Armor Vellum II => Armor Vellum III 18 [37602] = 43145, -- Armor Vellum II => Armor Vellum III
17 [39349] = 39350, -- Weapon Vellum => Weapon Vellum II 19 [39349] = 39350, -- Weapon Vellum => Weapon Vellum II
18 [39350] = 43146, -- Weapon Vellum II => Weapon Vellum III 20 [39350] = 43146, -- Weapon Vellum II => Weapon Vellum III
19 } 21 }
22
23 function Crafting:OnInitialize()
24 local allQueues = ItemAuditor.db.factionrealm.queue
25 if not allQueues[UnitName("player")] then
26 allQueues[UnitName("player")] = {}
27 end
28 realData = allQueues[UnitName("player")]
29
30 self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
31 end
32
33 local function getQueueLocation(name)
34 if not nameMap then
35 nameMap = {}
36 for key, data in pairs(realData) do
37 nameMap[data.skillName] = key
38 end
39 end
40 return nameMap[name]
41 end
42
43 --@debug@
44 Crafting.getQueueLocation = getQueueLocation
45 function Crafting.getNameMap()
46 return nameMap
47 end
48
49 function Crafting.getRealData()
50 return realData
51 end
52 --@end-debug@
53
54 function Crafting:UNIT_SPELLCAST_SUCCEEDED(event, unit, spell)
55 if unit == "player" and getQueueLocation(spell) then
56 local data = realData[getQueueLocation(spell)]
57 data.queue = data.queue - 1
58 ItemAuditor:RefreshCraftingTable()
59 end
60 end
20 61
21 local queueDestinations = {} 62 local queueDestinations = {}
22 local displayCraftingDestinations = {} 63 local displayCraftingDestinations = {}
23 function Crafting.RegisterQueueDestination(name, destination) 64 function Crafting.RegisterQueueDestination(name, destination)
24 queueDestinations[name] = destination 65 queueDestinations[name] = destination
150 191
151 -- ItemAuditor:GetModule('Crafting').filter_queued = false 192 -- ItemAuditor:GetModule('Crafting').filter_queued = false
152 Crafting.filter_have_mats = false 193 Crafting.filter_have_mats = false
153 Crafting.filter_show_all = false 194 Crafting.filter_show_all = false
154 local function tableFilter(self, row, ...) 195 local function tableFilter(self, row, ...)
196 if Crafting.nameFilter then
197 return string.find(row[1], Crafting.nameFilter) ~= nil
198 end
199
155 if Crafting.filter_show_all then 200 if Crafting.filter_show_all then
156 return true 201 return true
157 end 202 end
158 203
159 -- column 5 is how many should be crafted 204 -- column 5 is how many should be crafted
187 craftingTable.frame:SetPoint("BOTTOMRIGHT", craftingContent, 0, 30) 232 craftingTable.frame:SetPoint("BOTTOMRIGHT", craftingContent, 0, 30)
188 233
189 craftingTable:RegisterEvents({ 234 craftingTable:RegisterEvents({
190 ["OnEnter"] = function (rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...) 235 ["OnEnter"] = function (rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
191 if realrow then 236 if realrow then
192 local data = realData[realrow] 237 if column == 1 then
193 238 local data = realData[realrow]
194 GameTooltip:SetOwner(rowFrame, "ANCHOR_CURSOR") 239
195 GameTooltip:SetHyperlink(data.link) 240 GameTooltip:SetOwner(rowFrame, "ANCHOR_CURSOR")
196 GameTooltip:Show() 241 GameTooltip:SetHyperlink(data.link)
242 GameTooltip:Show()
243 elseif column == 2 then
244 local data = realData[realrow]
245 GameTooltip:SetOwner(rowFrame, "ANCHOR_CURSOR")
246 GameTooltip:SetText(format('Create %sx%s', data.link, data.queue))
247 for i, reagent in pairs(data.reagents) do
248 GameTooltip:AddDoubleLine("\124cffffffff"..reagent.link, format("\124cffffffff%s/%s", reagent.count-reagent.need, reagent.count))
249 --[[
250 reagents[reagentId] = {
251 link = reagentLink,
252 itemID = vellumID,
253 name = reagentName,
254 count = 1,
255 price = self:GetReagentCost(reagentLink, 1),
256 need = 0, -- This will get populated after the decisions have been made. it can't
257 -- be done before that because highest profit items get priority on materials.
258 }]]
259 end
260 GameTooltip:Show()
261 end
197 end 262 end
198 end, 263 end,
199 ["OnLeave"] = function (rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...) 264 ["OnLeave"] = function (rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
200 GameTooltip:Hide() 265 GameTooltip:Hide()
201 end, 266 end,
272 end 337 end
273 338
274 btnProcess:SetScript("OnClick", function (self, button, down) 339 btnProcess:SetScript("OnClick", function (self, button, down)
275 local data = ItemAuditor:GetCraftingRow(1) 340 local data = ItemAuditor:GetCraftingRow(1)
276 if data then 341 if data then
342 -- This will make sure the correct tradeskill window is open.
343 local tradeskillName = GetTradeSkillLine()
344 if data.tradeskillName ~= tradeskillName then
345 CastSpellByName(data.tradeskillName)
346 end
347
277 local queue = data.queue 348 local queue = data.queue
278 local vellumID = nil 349 local vellumID = nil
279 _, _, _, _, altVerb = GetTradeSkillInfo(data.tradeSkillIndex) 350 _, _, _, _, altVerb = GetTradeSkillInfo(data.tradeSkillIndex)
280 if altVerb == 'Enchant' and LSW.scrollData[data.recipeID] ~= nil then 351 if altVerb == 'Enchant' and LSW.scrollData[data.recipeID] ~= nil then
281 vellumID = LSW.scrollData[data.recipeID]["vellumID"] 352 vellumID = LSW.scrollData[data.recipeID]["vellumID"]
285 DoTradeSkill(data.tradeSkillIndex, queue) 356 DoTradeSkill(data.tradeSkillIndex, queue)
286 if vellumID then 357 if vellumID then
287 useVellum(vellumID) 358 useVellum(vellumID)
288 end 359 end
289 360
290 data.queue = data.queue - queue
291 ItemAuditor:RefreshCraftingTable()
292 UpdateProcessTooltip() 361 UpdateProcessTooltip()
293 end 362 end
294 end) 363 end)
295 364
296 btnProcess:SetScript("OnEnter", UpdateProcessTooltip) 365 btnProcess:SetScript("OnEnter", UpdateProcessTooltip)
416 }, 485 },
417 } 486 }
418 487
419 Crafting.RegisterCraftingDecider('Is Profitable', isProfitable, isProfitableOptions) 488 Crafting.RegisterCraftingDecider('Is Profitable', isProfitable, isProfitableOptions)
420 489
421 490 function Crafting.ClearProfession(tradeskillName)
491 -- This will initialize nameMap if it isn't already.
492 getQueueLocation('')
493
494 for key = #(realData), 1, -1 do
495 if realData[key].tradeskillName == tradeskillName then
496 nameMap[realData[key].tradeskillName] = nil
497 tremove(realData, key)
498 end
499 end
500 end
422 501
423 local tableData = {} 502 local tableData = {}
424 function ItemAuditor:UpdateCraftingTable() 503 function ItemAuditor:UpdateCraftingTable()
425 if LSW == nil then 504 if LSW == nil then
426 self:Print("This feature requires LilSparky's Workshop.") 505 self:Print("This feature requires LilSparky's Workshop.")
430 elseif AucAdvanced and AucAdvanced.Version then 509 elseif AucAdvanced and AucAdvanced.Version then
431 else 510 else
432 self:Print("This feature requires Auctionator, Auctioneer, AuctionLite, or AuctionMaster.") 511 self:Print("This feature requires Auctionator, Auctioneer, AuctionLite, or AuctionMaster.")
433 return 512 return
434 end 513 end
435 wipe(realData) 514 local tradeskillName = GetTradeSkillLine()
515 Crafting.ClearProfession(tradeskillName)
516 shoppingList = nil
517
436 wipe(tableData) 518 wipe(tableData)
437 519
438 local profitableItems = {} 520 local profitableItems = {}
439 local profitableIndex = 1 521 local profitableIndex = 1
440 local numChecked = 0 522 local numChecked = 0
441 local row = 1 523 local row = #(realData)+1
442 524 local numTradeSkills = GetNumTradeSkills()
443 for i = 1, GetNumTradeSkills() do 525 if tradeskillName == 'UNKNOWN' then
526 numTradeSkills = 0
527 end
528
529 for i = 1, numTradeSkills do
444 local itemLink = GetTradeSkillItemLink(i) 530 local itemLink = GetTradeSkillItemLink(i)
445 local itemId = Utils.GetItemID(itemLink) 531 local itemId = Utils.GetItemID(itemLink)
446 local vellumID = nil 532 local vellumID = nil
533
534 local spellName = itemName
447 535
448 --Figure out if its an enchant or not 536 --Figure out if its an enchant or not
449 _, _, _, _, altVerb = GetTradeSkillInfo(i) 537 _, _, _, _, altVerb = GetTradeSkillInfo(i)
450 if LSW.scrollData[itemId] ~= nil and altVerb == 'Enchant' then 538 if LSW.scrollData[itemId] ~= nil and altVerb == 'Enchant' then
451 -- Ask LSW for the correct scroll 539 -- Ask LSW for the correct scroll
501 local data = { 589 local data = {
502 recipeLink = recipeLink, 590 recipeLink = recipeLink,
503 recipeID = Utils.GetItemID(recipeLink), 591 recipeID = Utils.GetItemID(recipeLink),
504 link = itemLink, 592 link = itemLink,
505 name = itemName, 593 name = itemName,
594 skillName = skillName,
506 count = count, 595 count = count,
507 price = price, 596 price = price,
508 cost = totalCost, 597 cost = totalCost,
509 profit = price - totalCost, 598 profit = price - totalCost,
510 reagents = reagents, 599 reagents = reagents,
511 count = count, 600 count = count,
512 tradeSkillIndex = i, 601 tradeSkillIndex = i,
513 queue = 0, 602 queue = 0,
514 winner = "", 603 winner = "",
604 tradeskillName = tradeskillName,
515 } 605 }
516 606
517 data.winner, data.queue = Decide(data) 607 data.winner, data.queue = Decide(data)
518 --[[ 608 --[[
519 If it wasn't vetoed we need to reduce the number by how many are owned 609 If it wasn't vetoed we need to reduce the number by how many are owned
524 end 614 end
525 615
526 -- If a tradeskill makes 5 at a time and something asks for 9, we should only 616 -- If a tradeskill makes 5 at a time and something asks for 9, we should only
527 -- craft twice to get 10. 617 -- craft twice to get 10.
528 data.queue = ceil(data.queue / GetTradeSkillNumMade(i)) 618 data.queue = ceil(data.queue / GetTradeSkillNumMade(i))
529 619
530 realData[row] = data 620 realData[row] = data
621 nameMap[skillName] = row
531 row = row + 1 622 row = row + 1
532 end 623 end
533 end 624 end
534 end 625 end
535 table.sort(realData, function(a, b) return a.profit*max(1, a.queue) > b.profit*max(1, b.queue) end) 626 table.sort(realData, function(a, b) return a.profit*max(1, a.queue) > b.profit*max(1, b.queue) end)
562 craftingTable:SetFilter(tableFilter) 653 craftingTable:SetFilter(tableFilter)
563 self:RefreshCraftingTable() 654 self:RefreshCraftingTable()
564 end 655 end
565 end 656 end
566 657
658
659 local numOwned = {}
660
661 local function BuildShoppingList(character, queue)
662 for key, data in pairs(queue) do
663 if data.queue > 0 then
664 for id, reagent in pairs(data.reagents) do
665 if not numOwned[reagent.link] then
666 numOwned[reagent.link] = ItemAuditor:GetItemCount(Utils.GetItemID(reagent.link))
667 end
668 numOwned[reagent.link] = numOwned[reagent.link] - reagent.count
669
670 shoppingList[reagent.itemID] = shoppingList[reagent.itemID] or {
671 total = 0,
672 need = 0,
673 characters = {}
674 }
675 local slItem = shoppingList[reagent.itemID]
676
677
678 if numOwned[reagent.link] < 0 and not vellumLevelMap[reagent.itemID] then
679 reagent.need = min(reagent.count, abs(numOwned[reagent.link]))
680 elseif numOwned[reagent.link] >= 0 then
681 reagent.need = 0
682 end
683 shoppingList[reagent.itemID].total = shoppingList[reagent.itemID].total + reagent.count
684 shoppingList[reagent.itemID].need = shoppingList[reagent.itemID].need + reagent.need
685
686 slItem.characters[UnitName("player")] = slItem.characters[UnitName("player")] or {}
687 slItem.characters[UnitName("player")][data.recipeLink] = {
688 count = reagent.count,
689 need = reagent.need,
690 }
691 end
692 end
693 end
694 end
695
696 function Crafting.GetShoppingList(itemID)
697 if not shoppingList then
698 shoppingList = {}
699 wipe(numOwned)
700
701 -- This is done here instead of in the loop to make sure the current
702 -- character gets the first pick of materials.
703 local me = UnitName("player")
704 BuildShoppingList(me, realData)
705
706 for alt, queue in pairs(ItemAuditor.db.factionrealm.queue) do
707 if alt ~= me then
708 BuildShoppingList(alt, queue)
709 end
710 end
711 elseif shoppingList[itemID] then
712 local data = shoppingList[itemID]
713 if data.need ~= max(0, data.total - ItemAuditor:GetItemCount(itemID)) then
714 shoppingList = nil
715 -- I'm rebuilding the list instead of just the item because
716 -- it will be eaiser than tracking down the queued recipes that
717 -- need to change. If this becomes a problem, I may change it.
718 return Crafting.GetShoppingList(itemID)
719 end
720 end
721
722 return shoppingList[itemID]
723 end
724
567 function ItemAuditor:RefreshCraftingTable() 725 function ItemAuditor:RefreshCraftingTable()
726 tableData = {}
727 nameMap = {}
568 for key, data in pairs(realData) do 728 for key, data in pairs(realData) do
729 nameMap[data.name] = key
730
569 tableData[key] = { 731 tableData[key] = {
570 data.name, 732 data.name,
571 data.cost, 733 data.cost,
572 data.price, 734 data.price,
573 data.winner, 735 data.winner,