You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
9.4 KiB

4 years ago
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster_Crafting --
-- http://www.curse.com/addons/wow/tradeskillmaster_crafting --
-- --
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
-- All Rights Reserved* - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
-- load the parent file (TSM) into a local variable and register this file as a module
local TSM = select(2, ...)
local Queue = TSM:NewModule("Queue")
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Crafting") -- loads the localization table
local MAX_QUEUE_STAGES = 10
local inventoryTotals = {}
local notified = {}
function Queue:ValidateOperation(operation, opName)
if not operation then return end
if operation.minRestock > operation.maxRestock then
-- invalid cause min > max restock quantity (shouldn't happen)
if not notified[opName] then
notified[opName] = true
TSM:Printf(L["'%s' is an invalid operation! Min restock of %d is higher than max restock of %d."], opName, operation.minRestock, operation.maxRestock)
end
return
end
return true
end
function Queue:CreateRestockQueue(groupInfo)
TSM:UpdateCraftReverseLookup()
local numItems = 0
for _, data in pairs(groupInfo) do
for _, opName in ipairs(data.operations) do
TSMAPI:UpdateOperation("Crafting", opName)
local opSettings = TSM.operations[opName]
if Queue:ValidateOperation(opSettings, opName) then
-- it's a valid operation
for itemString in pairs(data.items) do
itemString = TSMAPI:GetItemString(itemString)
local spellID = TSM.craftReverseLookup[itemString] and TSM.craftReverseLookup[itemString][1]
if spellID and TSM.db.realm.crafts[spellID] then
4 years ago
local maxQueueCount = max(opSettings.maxRestock - TSM.Inventory:GetTotalQuantity(itemString), 0)
local numToQueue = 0
if not opSettings.minProfit then
-- no minimum, so queue as many as we can
numToQueue = maxQueueCount
else
-- queue it if the profit is at least the min profit
local cheapestSpellID, cost, _, profit = TSM.Cost:GetLowestCraftPrices(itemString)
local minProfit = TSM:GetCustomPrice(opSettings.minProfit, itemString)
if minProfit and profit and profit >= minProfit then
spellID = cheapestSpellID
numToQueue = maxQueueCount
end
end
local craft = TSM.db.realm.crafts[spellID]
4 years ago
craft.queued = floor(numToQueue / craft.numResult)
craft.queued = craft.queued >= opSettings.minRestock and craft.queued or 0
if craft.queued > 0 then
numItems = numItems + 1
end
end
end
end
end
end
if numItems==0 then
TSM:Printf("There are no items to restock.")
end
TSMAPI:FireEvent("CRAFTING:QUEUE:RESTOCKED", numItems)
end
function Queue:HasLoop(itemString, steps, visited)
steps = steps + 1
if steps > 10 then return true end
if visited[itemString] then return true end
visited[itemString] = true
local craftCost = TSM:GetCustomPrice("Crafting", itemString)
local mat = TSM.db.realm.mats[itemString]
4 years ago
local lowestCost = TSM:GetCustomPrice(mat.customValue or TSM.db.global.defaultMatCostMethod, itemString)
if craftCost and lowestCost and craftCost <= lowestCost and (not TSM.db.global.neverCraftInks or not TSMAPI.InkConversions[itemString]) then
local spellID = TSM.Cost:GetLowestCraftPrices(itemString, true)
if spellID and TSM.db.realm.crafts[spellID] then
for matItemString in pairs(TSM.db.realm.crafts[spellID].mats) do
4 years ago
if Queue:HasLoop(matItemString, steps, CopyTable(visited)) then
return true
end
end
end
end
end
function Queue:GetIntermediateCrafts(mats, usedItems, usedMats, tempMats)
local subCrafts = {}
for profession, data in pairs(mats) do
tempMats[profession] = tempMats[profession] or {}
for itemString, quantity in pairs(data) do
usedItems[itemString] = usedItems[itemString] or 0
local numHave = (inventoryTotals[itemString] or 0) - usedItems[itemString]
if TSMAPI.SOULBOUND_MATS[itemString] then
numHave = numHave + GetItemCount(itemString, true)
end
if numHave > 0 then
if numHave >= quantity then
usedItems[itemString] = usedItems[itemString] + quantity
tempMats[profession][itemString] = (tempMats[profession][itemString] or 0) + quantity
quantity = 0
mats[profession][itemString] = nil
else
usedItems[itemString] = numHave
quantity = quantity - numHave
tempMats[profession][itemString] = (tempMats[profession][itemString] or 0) + numHave
mats[profession][itemString] = mats[profession][itemString] - numHave
end
end
if quantity > 0 and not Queue:HasLoop(itemString, 0, {}) then
local mat = TSM.db.realm.mats[itemString]
4 years ago
local craftCost = TSM:GetCustomPrice("Crafting", itemString)
local lowestCost = TSM:GetCustomPrice(mat.customValue or TSM.db.global.defaultMatCostMethod, itemString)
if craftCost and lowestCost and craftCost <= lowestCost and (not TSM.db.global.neverCraftInks or not TSMAPI.InkConversions[itemString]) then
local spellID = TSM.Cost:GetLowestCraftPrices(itemString, true)
if spellID and TSM.db.realm.crafts[spellID] then
local numResult = TSM.db.realm.crafts[spellID].numResult
4 years ago
quantity = ceil(quantity / numResult)
subCrafts[TSM.db.realm.crafts[spellID].profession] = subCrafts[TSM.db.realm.crafts[spellID].profession] or {}
subCrafts[TSM.db.realm.crafts[spellID].profession][spellID] = (subCrafts[TSM.db.realm.crafts[spellID].profession][spellID] or 0) + quantity
TSM.db.realm.crafts[spellID].queued = TSM.db.realm.crafts[spellID].queued + quantity
TSM.db.realm.crafts[spellID].intermediateQueued = (TSM.db.realm.crafts[spellID].intermediateQueued or 0) + quantity
4 years ago
mats[profession][itemString] = nil
usedMats[profession] = usedMats[profession] or {}
usedMats[profession][itemString] = numHave
end
end
end
end
end
local newSubCrafts
for profession, data in pairs(subCrafts) do
for spellID, quantity in pairs(data) do
newSubCrafts = true
for itemString, matQuantity in pairs(TSM.db.realm.crafts[spellID].mats) do
4 years ago
mats[profession] = mats[profession] or {}
mats[profession][itemString] = (mats[profession][itemString] or 0) + matQuantity * quantity
end
end
end
return newSubCrafts and subCrafts
end
function Queue:GetQueue()
local tempCrafts, queuedCrafts, mats = {}, {}, {}
local totalCost, totalProfit
-- first queue up all the normally queued stuff
for spellID, data in pairs(TSM.db.realm.crafts) do
4 years ago
if data.intermediateQueued then
data.queued = max(data.queued - data.intermediateQueued, 0)
data.intermediateQueued = nil
end
if data.queued > 0 then
local cost, buyout, profit = TSM.Cost:GetCraftPrices(spellID)
if cost then
totalCost = (totalCost or 0) + cost * data.queued
end
if profit then
totalProfit = (totalProfit or 0) + profit * data.queued
end
tempCrafts[data.profession] = tempCrafts[data.profession] or {}
tempCrafts[data.profession][spellID] = data.queued
for itemString, quantity in pairs(data.mats) do
mats[data.profession] = mats[data.profession] or {}
mats[data.profession][itemString] = (mats[data.profession][itemString] or 0) + quantity * data.queued
end
end
end
for profession, data in pairs(tempCrafts) do
queuedCrafts[profession] = queuedCrafts[profession] or {}
tinsert(queuedCrafts[profession], 1, { crafts = data })
end
-- queue intermediate crafts
local usedItems, usedMats, tempMats = {}, {}, {}
inventoryTotals = select(4, TSM.Inventory:GetTotals())
for i = 1, MAX_QUEUE_STAGES - 1 do
local subCrafts = Queue:GetIntermediateCrafts(mats, usedItems, usedMats, tempMats)
if not subCrafts then break end
for profession, data in pairs(subCrafts) do
queuedCrafts[profession] = queuedCrafts[profession] or {}
tinsert(queuedCrafts[profession], 1, { crafts = data })
end
end
-- readd usedMats back in
for profession, data in pairs(tempMats) do
for itemString, quantity in pairs(data) do
mats[profession][itemString] = (mats[profession][itemString] or 0) + quantity
end
end
for profession, data in pairs(usedMats) do
if mats[profession] then
for itemString, quantity in pairs(data) do
mats[profession][itemString] = (mats[profession][itemString] or 0) + quantity
end
end
end
-- give each stage the appropriate name
for profession, stages in pairs(queuedCrafts) do
for i, stageInfo in ipairs(stages) do
stageInfo.name = format(L["Stage %d"], i)
end
end
totalCost = totalCost or "---"
totalProfit = totalProfit or "---"
return queuedCrafts, mats, totalCost, totalProfit
end
function Queue:ClearQueue()
for spellID, data in pairs(TSM.db.realm.crafts) do
4 years ago
data.queued = 0
data.intermediateQueued = nil
end
end
function Queue:addQueue(spellID, quantity)
local craft = TSM.db.realm.crafts[spellID]
4 years ago
if not craft then return end
quantity = quantity or 1
craft.queued = craft.queued + quantity
TSM.CraftingGUI:UpdateQueue()
end
function Queue:removeQueue(spellID, quantity)
local craft = TSM.db.realm.crafts[spellID]
4 years ago
if not craft then return end
quantity = quantity or 1
craft.queued = max(craft.queued - quantity, 0)
TSM.CraftingGUI:UpdateQueue()
end
function Queue:getQueue(spellID)
local craft = TSM.db.realm.crafts[spellID]
4 years ago
return craft.queued
end