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.

367 lines
15 KiB

-- ------------------------------------------------------------------------------ --
-- 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. --
-- ------------------------------------------------------------------------------ --
-- register this file with Ace Libraries
local TSM = select(2, ...)
TSM = LibStub("AceAddon-3.0"):NewAddon(TSM, "TSM_Crafting", "AceEvent-3.0", "AceConsole-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Crafting") -- loads the localization table
-- default values for the savedDB
local savedDBDefaults = {
global = {
optionsTreeStatus = {},
tooltip = true,
materialTooltip = true,
ignoreCharacters = {},
ignoreGuilds = {},
profitPercent = 0,
defaultMatCostMethod = "min(dbmarket, crafting, vendorbuy, convert(dbmarket))",
defaultCraftPriceMethod = "dbminbuyout",
priceColumn = 1,
ignoreCDCraftCost = true,
neverCraftInks = true,
frameQueueOpen = nil,
showingDefaultFrame = nil,
matsInTooltip = true,
showAllProfessions = false,
showAllProfessionsSortKey = "name",
showAllProfessionsSortDescending = false,
},
realm = {
tradeSkills = {},
crafts = {},
mats = {},
queueStatus = { collapsed = {} },
professionsTabCollapsed = {},
sourceStatus = { collapsed = {} },
gathering = { crafter = nil, professions = {}, neededMats = {}, availableMats = {}, gatheredMats = false, gatherAll = false, destroyingMats = {}, destroyDisable = false, evenStacks = true },
craftingCostCache = {}
},
}
-- Called once the player has loaded WOW.
function TSM:OnEnable()
-- create shortcuts to TradeSkillMaster_Crafting's modules
for moduleName, module in pairs(TSM.modules) do
TSM[moduleName] = module
end
-- load the savedDB into TSM.db
TSM.db = LibStub:GetLibrary("AceDB-3.0"):New("AscensionTSM_CraftingDB", savedDBDefaults, true)
TSM:UpdateCraftReverseLookup()
-- register this module with TSM
TSM:RegisterModule()
-- fix vellum issue
for spellid, data in pairs(TSM.db.realm.crafts) do
for itemString in pairs(data.mats) do
if itemString == "item:52510" then
TSM.db.realm.crafts[spellid].mats["item:52510:0:0:0:0:0:0"] = 1
TSM.db.realm.crafts[spellid].mats[itemString] = nil
elseif itemString == "item:52511" then
TSM.db.realm.crafts[spellid].mats["item:52511:0:0:0:0:0:0"] = 1
TSM.db.realm.crafts[spellid].mats[itemString] = nil
end
end
end
-- if currently casting a spell, keep track of the id
TSM.currentspell = nil
if TSM.db.realm.mats["item:52510"] then
local name = TSMAPI:GetSafeItemInfo("item:52510:0:0:0:0:0:0") or nil
TSM.db.realm.mats["item:52510:0:0:0:0:0:0"] = {}
TSM.db.realm.mats["item:52510:0:0:0:0:0:0"].name = name
TSM.db.realm.mats["item:52510"] = nil
end
if TSM.db.realm.mats["item:52511"] then
local name = TSMAPI:GetSafeItemInfo("item:52511:0:0:0:0:0:0") or nil
TSM.db.realm.mats["item:52511:0:0:0:0:0:0"] = {}
TSM.db.realm.mats["item:52511:0:0:0:0:0:0"].name = name
TSM.db.realm.mats["item:52511"] = nil
end
local func, err = TSMAPI:ParseCustomPrice(TSM.db.global.defaultCraftPriceMethod, "crafting")
if not func then
TSM:Printf(L["Your default craft value method was invalid so it has been returned to the default. Details: %s"], err)
TSM.db.global.defaultCraftPriceMethod = savedDBDefaults.defaultCraftPriceMethod
end
for name, operation in pairs(TSM.operations) do
if operation.craftPriceMethod then
local func, err = TSMAPI:ParseCustomPrice(TSM.db.global.defaultCraftPriceMethod, "crafting")
if not func then
TSM:Printf(L["Your craft value method for '%s' was invalid so it has been returned to the default. Details: %s"], name, err)
operation.craftPriceMethod = TSM.operationDefaults.craftPriceMethod
end
end
end
end
-- registers this module with TSM by first setting all fields and then calling TSMAPI:NewModule().
function TSM:RegisterModule()
TSM.icons = { { side = "module", desc = "Crafting", slashCommand = "crafting", callback = "Options:LoadCrafting", icon = "Interface\\Icons\\INV_Misc_Gear_08" } }
TSM.operations = { maxOperations = 5, callbackOptions = "Options:Load", callbackInfo = "GetOperationInfo" }
TSM.priceSources = {
{ key = "Crafting", label = L["Crafting Cost"], callback = "GetCraftingCost" },
{ key = "matPrice", label = L["Crafting Material Cost"], callback = "GetCraftingMatCost" },
}
TSM.moduleAPIs = {
{ key = "addQueue", callback = "Queue:addQueue" },
{ key = "removeQueue", callback = "Queue:removeQueue" },
{ key = "getQueue", callback = "Queue:getQueue" },
{ key = "getCDCrafts", callback = "getCDCrafts" },
{ key = "getCraftingFrameStatus", callback = "CraftingGUI:GetStatus" },
}
TSM.tooltipOptions = { callback = "Options:LoadTooltipOptions" }
TSM.slashCommands = {
{ key = "profession", label = L["Opens the Crafting window to the first profession."], callback = "CraftingGUI:OpenFirstProfession" },
{ key = "restock_help", label = "Tells you why a specific item is not being restocked and added to the queue.", callback = "RestockHelp" },
}
TSM.sync = { callback = "Sync:Callback" }
TSMAPI:NewModule(TSM)
end
TSM.operationDefaults = {
minRestock = 1, -- min of 1
maxRestock = 3, -- max of 3
minProfit = 1000000,
craftPriceMethod = nil,
ignorePlayer = {},
ignorerealm = {},
relationships = {},
}
function TSM:GetOperationInfo(name)
TSMAPI:UpdateOperation("Crafting", name)
local operation = TSM.operations[name]
if not operation then return end
if operation.minProfit then
return format(L["Restocking to a max of %d (min of %d) with a min profit."], operation.maxRestock, operation.minRestock)
else
return format(L["Restocking to a max of %d (min of %d) with no min profit."], operation.maxRestock, operation.minRestock)
end
end
function TSM:GetTooltip(itemString)
if not TSM.db.global.tooltip then return end
local text = {}
local moneyCoinsTooltip = TSMAPI:GetMoneyCoinsTooltip()
TSM:UpdateCraftReverseLookup()
itemString = TSMAPI:GetBaseItemString(itemString) -- show craft costs against random enchants
if TSM.craftReverseLookup[itemString] then
if TSM.db.global.tooltip then
local spellID, cost, buyout, profit = TSM.Cost:GetLowestCraftPrices(itemString)
local color
if profit and profit < 0 then
color = "|cffff0000"
else
color = "|cff00ff00"
end
if cost then
local costText, profitText
if moneyCoinsTooltip then
costText = (TSMAPI:FormatTextMoneyIcon(cost, "|cffffffff", true) or "|cffffffff---|r")
profitText = (TSMAPI:FormatTextMoneyIcon(profit, color, true) or "|cffffffff---|r")
else
costText = (TSMAPI:FormatTextMoney(cost, "|cffffffff", true) or "|cffffffff---|r")
profitText = (TSMAPI:FormatTextMoney(profit, color, true) or "|cffffffff---|r")
end
if profit then
local profitPercent = profit / cost * 100
local profitPercText = format("%s%.0f%%|r",color, profitPercent)
if profit>0 then
tinsert(text, { left = " " .. L["Crafting Cost"], right = format("%s (%s | %s profit)", costText, profitText, profitPercText) })
else
tinsert(text, { left = " " .. L["Crafting Cost"], right = format("%s (%s | %s loss)", costText, profitText, profitPercText) })
end
else
-- tinsert(text, { left = " " .. L["Crafting Cost"], right = format(L["%s (%s profit)"], costText, profitText) })
tinsert(text, { left = " " .. L["Crafting Cost"], right = format("%s", costText) })
end
if TSM.db.global.matsInTooltip and TSM.db.realm.crafts[spellID] then
for matItemString, matQuantity in pairs(TSM.db.realm.crafts[spellID].mats) do
local name, _, quality = TSMAPI:GetSafeItemInfo(matItemString)
if name then
local mat = TSM.db.realm.mats[matItemString]
if mat then
local cost = TSM:GetCustomPrice(mat.customValue or TSM.db.global.defaultMatCostMethod, matItemString)
if cost then
-- local colorName = format("|c%s%s%s%s|r",select(4,GetItemQualityColor(quality)),name, " x ", matQuantity)
local colorName = format("%s%s%s%s|r",select(4,GetItemQualityColor(quality)), name, " x ", matQuantity)
if matQuantity > 1 then
if moneyCoinsTooltip then
tinsert(text, { left = " " .. colorName, right = "ea: "..TSMAPI:FormatTextMoneyIcon(cost, "|cffffffff", true).." | total: "..TSMAPI:FormatTextMoneyIcon(cost*matQuantity, "|cffffffff", true)})
else
tinsert(text, { left = " " .. colorName, right = "ea: "..TSMAPI:FormatTextMoney(cost, "|cffffffff", true).." | total: "..TSMAPI:FormatTextMoney(cost*matQuantity, "|cffffffff", true)})
end
else
if moneyCoinsTooltip then
tinsert(text, { left = " " .. colorName, right = TSMAPI:FormatTextMoneyIcon(cost*matQuantity, "|cffffffff", true) })
else
tinsert(text, { left = " " .. colorName, right = TSMAPI:FormatTextMoney(cost*matQuantity, "|cffffffff", true) })
end
end
end
end
end
end
end
end
end
end
if TSM.db.global.materialTooltip then
local mat = TSM.db.realm.mats[itemString]
if mat then
local cost = TSM:GetCustomPrice(mat.customValue or TSM.db.global.defaultMatCostMethod, itemString)
if cost then
local costText
if moneyCoinsTooltip then
costText = (TSMAPI:FormatTextMoneyIcon(cost, "|cffffffff", true) or "|cffffffff---|r")
else
costText = (TSMAPI:FormatTextMoney(cost, "|cffffffff", true) or "|cffffffff---|r")
end
tinsert(text, { left = " " .. L["Mat Cost"], right = format("%s", costText) })
end
end
end
if #text > 0 then
tinsert(text, 1, "|cffffff00" .. "TSM Crafting:")
return text
end
end
function TSM:GetCraftingCost(link)
link = select(2, TSMAPI:GetSafeItemInfo(link))
local itemString = TSMAPI:GetBaseItemString(link)
if not itemString then return end
TSM:UpdateCraftReverseLookup()
local _, cost = TSM.Cost:GetLowestCraftPrices(itemString)
if cost then
TSM.db.realm.craftingCostCache[itemString] = cost
end
return TSM.db.realm.craftingCostCache[itemString]
end
function TSM:GetCraftingMatCost(link)
link = select(2, TSMAPI:GetSafeItemInfo(link))
local itemString = TSMAPI:GetBaseItemString(link)
if not itemString then return end
TSM:UpdateCraftReverseLookup()
return TSM.Cost:GetMatCost(itemString)
end
local reverseLookupUpdate = 0
function TSM:UpdateCraftReverseLookup()
-- if reverseLookupUpdate >= time() - 30 then return end
reverseLookupUpdate = time()
TSM.craftReverseLookup = {}
for spellID, data in pairs(TSM.db.realm.crafts) do
TSM.craftReverseLookup[data.itemID] = TSM.craftReverseLookup[data.itemID] or {}
tinsert(TSM.craftReverseLookup[data.itemID], spellID)
end
end
function TSM:GetCustomPrice(priceMethod, itemString)
local func = TSMAPI:ParseCustomPrice(priceMethod)
return func and func(itemString)
end
function TSM:getCDCrafts()
local crafts = {}
for spellID, data in pairs(TSM.db.realm.crafts) do
if data.hasCD then
crafts[spellID] = data.name
end
end
return crafts
end
function TSM:RestockHelp(link)
local itemString = TSMAPI:GetItemString(link)
if not itemString then
return print("No item specified. Usage: /tsm restock_help [ITEM_LINK]")
end
TSM:Printf("Restock help for %s:", link)
-- check if the item is in a group
local groupPath = TSMAPI:GetGroupPath(itemString)
if not groupPath then
return print("This item is not in a TSM group.")
end
-- check that there's a crafting operation applied
local operation = (TSMAPI:GetItemOperation(itemString, "Crafting") or {})[1]
if not operation then
return print(format("There is no TSM_Crafting operation applied to this item's TSM group (%s).", TSMAPI:FormatGroupPath(groupPath)))
end
-- check if it's an invalid operation
local opSettings = TSM.operations[operation]
if opSettings.minRestock > opSettings.maxRestock then
return print(format(L["'%s' is an invalid operation! Min restock of %d is higher than max restock of %d."], operation, opSettings.minRestock, opSettings.maxRestock))
end
-- check that this item is craftable
TSM:UpdateCraftReverseLookup()
local spellID = TSM.craftReverseLookup[itemString] and TSM.craftReverseLookup[itemString][1]
if not spellID or not TSM.db.realm.crafts[spellID] then
return print("You don't know how to craft this item.")
end
-- check the restock quantity
local numHave = TSM.Inventory:GetTotalQuantity(itemString)
if numHave >= opSettings.maxRestock then
return print(format("You already have at least your max restock quantity of this item. You have %d and the max restock quantity is %d", numHave, opSettings.maxRestock))
elseif (opSettings.maxRestock - numHave) < opSettings.minRestock then
return print(format("The number which would be queued (%d) is less than the min restock quantity (%d).", (opSettings.maxRestock - numHave), opSettings.minRestock))
end
-- check the prices on the item and the min profit
if opSettings.minProfit then
local cheapestSpellID, cost, craftedValue, profit = TSM.Cost:GetLowestCraftPrices(itemString)
-- check that there's a crafted value
if not craftedValue then
local craftPriceMethod = operation and operation.craftPriceMethod or TSM.db.global.defaultCraftPriceMethod
return print(format("The 'Craft Value Method' (%s) did not return a value for this item. If it is based on some price database (AuctionDB, TSM_WoWuction, TUJ, etc), then ensure that you have scanned for or downloaded the data as appropriate.", craftPriceMethod))
end
-- check that there's a crafted cost
if not cost then
return print("This item does not have a crafting cost. Check that all of its mats have mat prices. If the mat prices are based on some price database (AuctionDB, TSM_WoWuction, TUJ, etc), then ensure that you have scanned for or downloaded the data as appropriate.")
end
-- check that there's a profit
if not profit then
return print("There is a crafting cost and crafted item value, but TSM_Crafting wasn't able to calculate a profit. This shouldn't happen!")
end
local minProfit = TSM:GetCustomPrice(opSettings.minProfit, itemString)
if not minProfit then
return print(format("The min profit (%s) did not evalulate to a valid value for this item.", opSettings.minProfit))
end
if profit < minProfit then
return print(format("The profit of this item (%s) is below the min profit (%s).", TSMAPI:FormatTextMoney(profit), TSMAPI:FormatTextMoney(minProfit)))
end
end
print("This item will be added to the queue when you restock its group. If this isn't happening, make a post on the TSM forums with a screenshot of the item's tooltip, operation settings, and your general TSM_Crafting options.")
end