-- $Revision$ -- Cauldron queue management functions CauldronQueue = {}; --[[ The following table describes a queue item in the "main" and "intermediate" sections of the queue: queueItem = { ["name"] = "<name of skill>", ["icon"] = "<icon path>", ["tradeskill"] = "<name of tradeskill>", ["amount"] = <amount>, ["priority"] = <priority>, ["link"] = "<link>", }; The following table describes a reagent needed by items in the queue. reagent = { ["name"] = "<name of item>", ["icon"] = "<icon path>", ["amount"] = <amount>, ["tradeskill"] = "<tradeskill that caused this reagent to be listed>", ["link"] = "<link>", }; --]] function CauldronQueue:NewQueue() local queue = { ["main"] = {}, ["intermediate"] = {}, ["reagents"] = {}, }; return queue; end function CauldronQueue:NewItem(name, icon, amount, priority, tradeskill, link) local queueItem = { ["name"] = name or "", ["icon"] = icon or "", ["tradeskill"] = tradeskill or "", ["link"] = link, ["amount"] = amount or 1, ["priority"] = priority or 0, }; return queueItem; end function CauldronQueue:NewReagent(name, icon, amount, tradeskill, link) local reagent = { ["name"] = name or "", ["icon"] = icon or "", ["amount"] = amount or 1, ["tradeskill"] = tradeskill, ["link"] = link, }; return reagent; end function CauldronQueue:GetItems(queue) -- sanity checks if not queue then Cauldron:error("GetItems: No queue found!"); return nil; end local items = {}; for _, item in pairs(queue.main) do if item.amount > 0 then table.insert(items, item); end end -- sort the list table.sort(items, function(r1, r2) return r2.priority < r1.priority; end); return items; end function CauldronQueue:GetIntermediates(queue) -- sanity checks if not queue then Cauldron:error("GetIntermediates: No queue found!"); return nil; end local items = {}; for _, item in pairs(queue.intermediate) do -- if tradeskill then -- if tradeskill == item.tradeskill then -- table.insert(items, item); -- end -- else local t = CopyTable(item); local skillInfo = Cauldron:GetSkillInfo(t.tradeskill, t.name); if skillInfo and (skillInfo.available > 0) then -- increase the priority of items that can be crafted, so that they appear at the top of the list t.priority = t.priority + 1000; end table.insert(items, t); -- end end -- sort the list table.sort(items, function(r1, r2) return r2.priority < r1.priority; end); return items; end function CauldronQueue:GetReagents(queue) -- sanity checks if not queue then Cauldron:error("GetReagents: No queue found!"); return nil; end local items = {}; for _, item in pairs(queue.reagents) do -- if tradeskill then -- if tradeskill == item.tradeskill then -- table.insert(items, item); -- end -- else table.insert(items, item); -- end end return items; end function CauldronQueue:AddItem(queue, skillInfo, amount, suppressCalc) -- sanity checks if not queue then Cauldron:error("AddItem: No queue found!"); return; end if not queue.main then queue.main = {}; end -- look for the item in the "main" section local item = queue.main[skillInfo.name]; if item then -- it's there, so increase the amount item.amount = item.amount + amount; else -- it's not there, so create a new instance queue.main[skillInfo.name] = CauldronQueue:NewItem(skillInfo.name, skillInfo.icon, amount, nil, skillInfo.tradeskill, skillInfo.itemLink); end if not suppressCalc then CauldronQueue:CalculateAllRequiredItems(queue); end end function CauldronQueue:CalculateAllRequiredItems(queue) -- sanity checks if not queue then Cauldron:error("CalculateAllRequiredItems: No queue found!"); -- Cauldron:Print(debugstack(1)); return; end -- reset the intermediate and reagent lists queue.intermediate = {}; queue.reagents = {}; -- iterate over the queued items for name, queueInfo in pairs(queue.main) do local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name); CauldronQueue:CalculateRequiredItems(queue, skillInfo, queueInfo.amount, queueInfo.priority); end end function CauldronQueue:CalculateRequiredItems(queue, skillInfo, amount, priority) -- sanity checks if not queue then Cauldron:error("CalculateRequiredItems: No queue found!"); return; end -- get the intermediates and reagents for the item local intermediates, reagents = Cauldron:GetRequiredItems(skillInfo, amount); -- check the intermediate list; if the item is available somewhere (inventory, bank, alt, etc.) -- then move it to the reagent list; otherwise, update the intermediate list in the queue -- update the intermediate and reagent lists for i, reagent in ipairs(intermediates) do local count = Cauldron:ReagentCount(reagent.name); if count.has >= reagent.numRequired then -- add the item to the reagent list if the character has all the required amount table.insert(reagents, reagent); else local amount = reagent.numRequired; -- if the character has some, add that amount to the reagent list if count.has > 0 then -- create a reagent copy of the item local newItem = CopyTable(reagent); newItem.numRequired = count.has; table.insert(reagents, newItem); -- adjust item count to how many need to be crafted amount = reagent.numRequired - count.has; end -- add the remaining amount to the intermediate list if amount > 0 then -- adjust the amount if the item produces more than one per execution local intSkillInfo = Cauldron:GetSkillInfoForItem(reagent.name); if intSkillInfo then if intSkillInfo.minMade > 1 then -- we ignore maxMade, since if it is greater than minMade, then the amount -- produced is variable, so we err on the side of caution and account for -- only ever making the minimum possible; besides, each execution of the -- skill will cause the reagent list to be reassessed, so producing more -- will be handled appropriately amount = math.ceil(amount / intSkillInfo.minMade); end end CauldronQueue:AddIntermediate(queue, reagent, amount, priority); -- add the intermediate's reagents also CauldronQueue:CalculateRequiredItems(queue, intSkillInfo, amount, priority); end end end for i, reagent in ipairs(reagents) do CauldronQueue:AddReagent(queue, reagent, reagent.numRequired, skillInfo.tradeskill, reagent.link); end end function CauldronQueue:AddIntermediate(queue, reagent, amount, priority) -- sanity checks if not queue then Cauldron:error("AddIntermediate: No queue found!"); return; end amount = math.max(0, tonumber(amount) or 0); if not queue.intermediate then queue.intermediate = {}; end -- look for the item in the "intermediate" section local item = queue.intermediate[reagent.name]; if item then -- it's there, so increase the amount item.amount = item.amount + amount; else -- it's not there, so create a new instance if reagent.name then local skillInfo = Cauldron:GetSkillInfoForItem(reagent.name); if skillInfo then local newItem = CauldronQueue:NewItem(reagent.name, reagent.icon, amount, nil, skillInfo.tradeskill, reagent.link); newItem.priority = priority or 0; queue.intermediate[reagent.name] = newItem; else Cauldron:error("AddIntermediate: no skill info found for reagent: "..reagent.name); end else -- this shouldn't occur unless there's something wrong with the reagent info, but if it does, the user can report this error Cauldron:error("AddIntermediate: reagent.name is nil! Please report this. (skillIndex: "..reagent.skillIndex..", index: "..reagent.index..")"); end end end function CauldronQueue:AddReagent(queue, reagent, amount, tradeskill) -- sanity checks if not queue then Cauldron:error("AddReagent: No queue found!"); return; end amount = math.max(1, tonumber(amount) or 1); if not queue.reagents then queue.reagents = {}; end -- look for the item in the "reagents" section local item = queue.reagents[reagent.name]; if item then -- it's there, so increase the amount item.amount = (tonumber(item.amount) or 0) + amount; else -- it's not there, so create a new instance if reagent.name then queue.reagents[reagent.name] = CauldronQueue:NewReagent(reagent.name, reagent.icon, amount, tradeskill, reagent.link); else -- this shouldn't occur unless there's something wrong with the reagent info, but if it does, the user can report this error Cauldron:error("AddReagent: reagent.name is nil!"); end end end function CauldronQueue:AdjustItemCount(queue, name, delta) -- sanity checks if not queue then Cauldron:error("AdjustItemCount: No queue found!"); return; end local item; -- = queue.main[name]; for qName, qInfo in pairs(queue.main) do local qItem = Cauldron:GetNameFromLink(qInfo.link); if name == qItem then item = qInfo; break; end end -- check for a mapped item, like "perfect" gem cuts, etc. --[[ TODO if not item then local map = Cauldron.vars.results[Cauldron:GetIdFromLink()]; end --]] Cauldron:debug("AdjustItemCount: item="..tostring(item)); if item then Cauldron:debug("AdjustItemCount: item.amount="..item.amount); item.amount = item.amount + delta; Cauldron:debug("AdjustItemCount: item.amount(delta)="..item.amount); if item.amount < 1 then Cauldron:debug("AdjustItemCount: remove item: "..name); queue.main[name] = nil; end end Cauldron:debug("AdjustItemCount: calculate required items"); CauldronQueue:CalculateAllRequiredItems(queue); end function CauldronQueue:RemoveItem(queue, itemName) Cauldron:debug("RemoveItem enter"); -- sanity checks if (not queue) and (not itemName) then Cauldron:error("RemoveItem: No queue or item name found!"); return; end if queue.main[itemName] then queue.main[itemName] = nil; CauldronQueue:CalculateAllRequiredItems(queue); end Cauldron:debug("RemoveItem exit"); end function CauldronQueue:IncreasePriority(queue, itemName, top) Cauldron:debug("IncreasePriority enter"); -- sanity checks if (not queue) and (not itemName) then Cauldron:error("IncreasePriority: No queue or item name found!"); return; end local item = queue.main[itemName]; if item then local priority = item.priority + 1; local highest = 0; if top then for _, info in pairs(queue.main) do if info.priority > highest then highest = info.priority; end end priority = highest + 1; end item.priority = priority; end Cauldron:debug("IncreasePriority exit"); end function CauldronQueue:DecreasePriority(queue, itemName, bottom) Cauldron:debug("DecreasePriority enter"); -- sanity checks if (not queue) and (not itemName) then Cauldron:error("DecreasePriority: No queue or item name found!"); return; end local item = queue.main[itemName]; if item then local priority = item.priority - 1; local lowest = 0; if top then for _, info in pairs(queue.main) do if info.priority < lowest then lowest = info.priority; end end priority = lowest - 1; end item.priority = priority; end Cauldron:debug("DecreasePriority exit"); end function CauldronQueue:ClearQueue(queue) Cauldron:debug("ClearQueue enter"); -- sanity checks if not queue then Cauldron:error("ClearQueue: No queue found!"); return; end --[[ if tradeskill then Cauldron:debug("ClearQueue: clearing tradeskill: "..tradeskill); -- set aside the current main queue Cauldron:debug("ClearQueue: set aside main table"); local main = queue.main; -- clear out the tables Cauldron:debug("ClearQueue: clear out tables"); queue.main = {}; -- iterate over the items and re-add the ones not for the specified tradeskill Cauldron:debug("ClearQueue: iterate over items"); for i, item in ipairs(main) do Cauldron:debug("ClearQueue: item: "..i); if item.tradeskill ~= tradeskill then -- get the skill for the item Cauldron:debug("ClearQueue: item.tradeskill: "..item.tradeskill); local skillInfo = Cauldron:GetSkillInfo(item.tradeskill, item.name); -- recalculate Cauldron:debug("ClearQueue: recalculate"); CauldronQueue:AddItem(queue, skillInfo, item.amount, true); end end CauldronQueue:CalculateAllRequiredItems(queue); else --]] queue.main = {}; queue.intermediate = {}; queue.reagents = {}; Cauldron:debug("ClearQueue exit"); end function CauldronQueue:GetIntermediateItem(queue, itemName) -- sanity checks if not queue then Cauldron:error("GetIntermediateItem: No queue found!"); return nil; end return queue.intermediate[itemName]; end function CauldronQueue:GetReagentItem(queue, itemName) -- sanity checks if not queue then Cauldron:error("GetReagentItem: No queue found!"); return nil; end return queue.reagents[itemName]; end