annotate Modules/Crafting.lua @ 137:526036e4358f

Ticket 42 - In order to fix an issue with having multiple items that are the same base item with different enchants, all costs are now tracked against the base item instead of the exact item.
author Asa Ayers <Asa.Ayers@Gmail.com>
date Sat, 02 Oct 2010 19:21:56 -0700
parents a529a4a4ccbe
children 106c1523777e
rev   line source
Asa@63 1 local ItemAuditor = select(2, ...)
Asa@124 2 local Crafting = ItemAuditor:NewModule("Crafting", 'AceEvent-3.0')
Asa@59 3
Asa@86 4 local Utils = ItemAuditor:GetModule("Utils")
Asa@86 5
Asa@59 6 local AceGUI = LibStub("AceGUI-3.0")
Asa@59 7 local ScrollingTable = LibStub("ScrollingTable")
Asa@59 8
Asa@59 9 local validateMoney = ItemAuditor.validateMoney
Asa@59 10 local parseMoney = ItemAuditor.parseMoney
Asa@59 11
Asa@59 12 local realData = {}
Asa@128 13 local nameMap = nil
Asa@59 14
Asa@124 15 local vellumLevelMap = {
Asa@124 16 [38682] = 37602, -- Armor Vellum => Armor Vellum II
Asa@124 17 [37602] = 43145, -- Armor Vellum II => Armor Vellum III
Asa@124 18 [39349] = 39350, -- Weapon Vellum => Weapon Vellum II
Asa@124 19 [39350] = 43146, -- Weapon Vellum II => Weapon Vellum III
Asa@124 20 }
Asa@67 21
Asa@128 22 function Crafting:OnInitialize()
Asa@128 23 self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
Asa@128 24 end
Asa@128 25
Asa@128 26 local function getQueueLocation(name)
Asa@128 27 if not nameMap then
Asa@128 28 nameMap = {}
Asa@128 29 for key, data in pairs(realData) do
Asa@128 30 nameMap[data.skillName] = key
Asa@128 31 end
Asa@128 32 end
Asa@128 33 return nameMap[name]
Asa@128 34 end
Asa@128 35
Asa@128 36 --@debug@
Asa@128 37 Crafting.getQueueLocation = getQueueLocation
Asa@128 38 function Crafting.getNameMap()
Asa@128 39 return nameMap
Asa@128 40 end
Asa@128 41
Asa@128 42 function Crafting.getRealData()
Asa@128 43 return realData
Asa@128 44 end
Asa@128 45 --@end-debug@
Asa@128 46
Asa@128 47 function Crafting:UNIT_SPELLCAST_SUCCEEDED(event, unit, spell)
Asa@128 48 if unit == "player" and getQueueLocation(spell) then
Asa@128 49 local data = realData[getQueueLocation(spell)]
Asa@128 50 data.queue = data.queue - 1
Asa@128 51 ItemAuditor:RefreshCraftingTable()
Asa@128 52 end
Asa@128 53 end
Asa@128 54
Asa@68 55 local queueDestinations = {}
Asa@70 56 local displayCraftingDestinations = {}
Asa@68 57 function Crafting.RegisterQueueDestination(name, destination)
Asa@68 58 queueDestinations[name] = destination
Asa@70 59 displayCraftingDestinations[name] = name
Asa@70 60 end
Asa@70 61
Asa@70 62 function Crafting.UnRegisterQueueDestination(name)
Asa@70 63 queueDestinations[name] = nil
Asa@70 64 displayCraftingDestinations[name] = nil
Asa@70 65 end
Asa@70 66
Asa@70 67 function Crafting.GetQueueDestination()
Asa@70 68 local dest = ItemAuditor.db.profile.queue_destination
Asa@70 69 if dest and queueDestinations[dest] then
Asa@70 70 return queueDestinations[dest], dest
Asa@70 71 end
Asa@133 72 -- If there is none selected or the selected option has
Asa@70 73 -- dissapeared, choose the first one in the list
Asa@70 74 for name, func in pairs(queueDestinations) do
Asa@70 75 if dest then
Asa@70 76 ItemAuditor:Print("%s is no longer available as a queue destination. %s is the new default", dest, name)
Asa@70 77 end
Asa@70 78 ItemAuditor.db.profile.queue_destination = name
Asa@70 79 return func, name
Asa@70 80 end
Asa@133 81
Asa@70 82 error('Unable to determine queue destination.')
Asa@68 83 end
Asa@68 84
Asa@68 85 function ItemAuditor:GetCraftingThreshold()
Asa@101 86 return self.db.char.profitable_threshold
Asa@68 87 end
Asa@68 88
Asa@67 89 ItemAuditor.Options.args.crafting_options = {
Asa@70 90 name = "Crafting",
Asa@67 91 type = 'group',
Asa@67 92 args = {
Asa@70 93 queue_destination = {
Asa@70 94 type = "select",
Asa@70 95 name = "Queue Destination",
Asa@70 96 desc = "Select the addon who's queue you would like ItemAuditor to post to.",
Asa@70 97 values = displayCraftingDestinations,
Asa@70 98 get = function() return select(2, Crafting.GetQueueDestination()) end,
Asa@70 99 set = function(info, value) ItemAuditor.db.profile.queue_destination = value end,
Asa@72 100 order = 1,
Asa@70 101 },
Asa@72 102 deciders = {
Asa@72 103 type="header",
Asa@72 104 name="Crafting Deciders",
Asa@72 105 order = 10,
Asa@72 106 },
Asa@67 107 },
Asa@67 108 }
Asa@67 109
Asa@59 110 local function displayMoney(rowFrame, cellFrame, data, cols, row, realrow, column, fShow, table, ...)
Asa@59 111 if fShow == true then
Asa@59 112 local money = data[realrow][column]
Asa@59 113 if money then
Asa@59 114 cellFrame.text:SetText(ItemAuditor:FormatMoney(tonumber(money)))
Asa@59 115 else
Asa@59 116 cellFrame.text:SetText("")
Asa@59 117 end
Asa@133 118
Asa@59 119 end
Asa@59 120 end
Asa@59 121
Asa@59 122 local craftingCols = {
Asa@59 123 { name= "Item", width = 200, defaultsort = "desc",
Asa@59 124 ['DoCellUpdate'] = function(rowFrame, cellFrame, data, cols, row, realrow, column, fShow, table, ...)
Asa@59 125 if fShow == true then
Asa@59 126 local data = realData[realrow]
Asa@59 127 cellFrame.text:SetText(data.link)
Asa@59 128 end
Asa@59 129 end,
Asa@59 130 },
Asa@133 131 { name= "Cost Each", width = 100, align = "RIGHT",
Asa@59 132 ['DoCellUpdate'] = displayMoney,
Asa@59 133 },
Asa@133 134 { name= "Est Sale Each", width = 100, align = "RIGHT",
Asa@59 135 ['DoCellUpdate'] = displayMoney,
Asa@59 136 },
Asa@99 137 { name= "Decided By", width = 125, align = "RIGHT",
Asa@133 138
Asa@59 139 },
Asa@133 140 { name= "craft", width = 50, align = "RIGHT",
Asa@133 141
Asa@59 142 },
Asa@133 143 { name= "Have Mats", width = 60, align = "RIGHT",
Asa@133 144
Asa@99 145 },
Asa@123 146 { name= "Profit Each", width = 100, align = "RIGHT",
Asa@59 147 ['DoCellUpdate'] = displayMoney,
Asa@59 148 },
Asa@59 149 }
Asa@59 150
Asa@68 151 function Crafting.ExportToSkillet(data)
Asa@68 152 local skillString = select(3, string.find(data.recipeLink, "^|%x+|H(.+)|h%[.+%]"))
Asa@68 153 local _, skillId = strsplit(":", skillString)
Asa@133 154
Asa@68 155 ItemAuditor:AddToQueue(skillId,tradeSkillIndex, data.queue)
Asa@68 156 end
Asa@68 157
Asa@68 158 Crafting.RegisterQueueDestination('Skillet', Crafting.ExportToSkillet)
Asa@68 159
Asa@68 160
Asa@68 161
Asa@68 162 function Crafting.Export(destination)
Asa@68 163 if type(destination) == 'function' then
Asa@68 164 -- do nothing
Asa@68 165 elseif destination == nil then
Asa@70 166 destination = Crafting.GetQueueDestination()
Asa@68 167 elseif type(destination) == 'string' then
Asa@68 168 destination = queueDestinations[destination]
Asa@68 169 else
Asa@68 170 error('destination must be a function or a string')
Asa@68 171 end
Asa@133 172
Asa@59 173 local index = 1
Asa@59 174 local data = ItemAuditor:GetCraftingRow(index)
Asa@59 175 while data do
Asa@68 176 if data.queue > 0 then
Asa@68 177 destination(data)
Asa@68 178 end
Asa@61 179 index = index + 1
Asa@61 180 data = ItemAuditor:GetCraftingRow(index)
Asa@133 181
Asa@59 182 end
Asa@59 183 end
Asa@59 184
Asa@74 185 -- ItemAuditor:GetModule('Crafting').filter_queued = false
Asa@99 186 Crafting.filter_have_mats = false
Asa@99 187 Crafting.filter_show_all = false
Asa@74 188 local function tableFilter(self, row, ...)
Asa@128 189 if Crafting.nameFilter then
Asa@128 190 return string.find(row[1], Crafting.nameFilter) ~= nil
Asa@128 191 end
Asa@128 192
Asa@99 193 if Crafting.filter_show_all then
Asa@99 194 return true
Asa@99 195 end
Asa@99 196
Asa@74 197 -- column 5 is how many should be crafted
Asa@126 198 if Crafting.filter_have_mats and row[6] == 0 then
Asa@99 199 return false
Asa@99 200 end
Asa@99 201 if strfind(row[4], 'VETO: .*') or row[5] == 0 then
Asa@74 202 return false
Asa@74 203 end
Asa@74 204 return true
Asa@74 205 end
Asa@74 206
Asa@59 207 local craftingContent = false
Asa@59 208 local craftingTable = false
Asa@60 209 local btnProcess = false
Asa@59 210 local function ShowCrafting(container)
Asa@59 211 if craftingContent == false then
Asa@59 212 local window = container.frame
Asa@59 213 craftingContent = CreateFrame("Frame",nil,window)
Asa@133 214 craftingContent:SetBackdropColor(0, 0, 1, 0.5)
Asa@59 215 craftingContent:SetBackdropBorderColor(1, 0, 0, 1)
Asa@133 216
Asa@59 217 craftingContent:SetPoint("TOPLEFT", window, 10, -50)
Asa@59 218 craftingContent:SetPoint("BOTTOMRIGHT",window, -10, 10)
Asa@133 219
Asa@59 220 craftingTable = ScrollingTable:CreateST(craftingCols, 22, nil, nil, craftingContent )
Asa@133 221
Asa@133 222 IAcc = craftingContent
Asa@59 223 IAccWindow = window
Asa@59 224 craftingTable.frame:SetPoint("TOPLEFT",craftingContent, 0,0)
Asa@59 225 craftingTable.frame:SetPoint("BOTTOMRIGHT", craftingContent, 0, 30)
Asa@133 226
Asa@59 227 craftingTable:RegisterEvents({
Asa@59 228 ["OnEnter"] = function (rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
Asa@59 229 if realrow then
Asa@134 230 local data = realData[realrow]
Asa@134 231
Asa@134 232 GameTooltip:SetOwner(rowFrame, "ANCHOR_CURSOR")
Asa@134 233 GameTooltip:SetHyperlink(data.link)
Asa@134 234 GameTooltip:Show()
Asa@59 235 end
Asa@59 236 end,
Asa@59 237 ["OnLeave"] = function (rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
Asa@59 238 GameTooltip:Hide()
Asa@59 239 end,
Asa@59 240 });
Asa@133 241
Asa@99 242 local craftingView = CreateFrame("Button", nil, craftingContent, "UIPanelButtonTemplate")
Asa@99 243 craftingView:SetText("View")
Asa@99 244 craftingView:SetSize(50, 25)
Asa@99 245 craftingView:SetPoint("BOTTOMLEFT", craftingContent, 0, 0)
Asa@99 246
Asa@99 247 local menu = {
Asa@99 248 { text = "View", isTitle = true},
Asa@99 249 { text = "To be crafted", func = function()
Asa@99 250 Crafting.filter_have_mats = false
Asa@99 251 Crafting.filter_show_all = false
Asa@99 252 ItemAuditor:RefreshCraftingTable()
Asa@99 253 end },
Asa@99 254 { text = "Have Mats", func = function()
Asa@99 255 Crafting.filter_have_mats = true
Asa@99 256 Crafting.filter_show_all = false
Asa@99 257 ItemAuditor:RefreshCraftingTable()
Asa@99 258 end },
Asa@99 259 { text = "All", func = function()
Asa@99 260 Crafting.filter_have_mats = false
Asa@99 261 Crafting.filter_show_all = true
Asa@99 262 ItemAuditor:RefreshCraftingTable()
Asa@99 263 end },
Asa@99 264 }
Asa@99 265 local menuFrame = CreateFrame("Frame", "ExampleMenuFrame", UIParent, "UIDropDownMenuTemplate")
Asa@99 266 craftingView:SetScript("OnClick", function (self, button, down)
Asa@99 267 EasyMenu(menu, menuFrame, "cursor", 0 , 0, "MENU");
Asa@99 268 end)
Asa@99 269
Asa@99 270
Asa@59 271 btnProcess = CreateFrame("Button", nil, craftingContent, "UIPanelButtonTemplate")
Asa@59 272 btnProcess:SetText("Process")
Asa@133 273 btnProcess:SetSize(100, 25)
Asa@59 274 btnProcess:SetPoint("BOTTOMRIGHT", craftingContent, 0, 0)
Asa@59 275 btnProcess:RegisterForClicks("LeftButtonUp");
Asa@133 276
Asa@60 277 local function UpdateProcessTooltip(btn)
Asa@59 278 local data = ItemAuditor:GetCraftingRow(1)
Asa@59 279 if data then
Asa@59 280 GameTooltip:SetOwner(this, "ANCHOR_CURSOR")
Asa@59 281 GameTooltip:SetText(format('Create %sx%s', data.link, data.queue))
Asa@59 282 GameTooltip:Show()
Asa@59 283 end
Asa@60 284 end
Asa@124 285
Asa@124 286 --[[
Asa@124 287 When enchanting UseContainerItem seems to be protected, so the enchants
Asa@124 288 have to be done one at a time.
Asa@124 289 ]]
Asa@124 290 local function useVellum(vellumID, idealVellum)
Asa@124 291 for bagID = 0, NUM_BAG_SLOTS do
Asa@124 292 for slotID = 0, GetContainerNumSlots(bagID) do
Asa@124 293 local link = GetContainerItemLink(bagID, slotID)
Asa@124 294 local id = Utils.GetItemID(link);
Asa@124 295 if id == vellumID then
Asa@124 296 if idealVellum then
Asa@124 297 ItemAuditor:Print("Using %s instead of %s.",
Asa@124 298 select(2, GetItemInfo(vellumID)),
Asa@124 299 select(2, GetItemInfo(idealVellum))
Asa@124 300 )
Asa@124 301 end
Asa@124 302 UseContainerItem(bagID, slotID)
Asa@124 303 return
Asa@124 304 end
Asa@124 305 end
Asa@124 306 end
Asa@124 307 if vellumLevelMap[vellumID] then
Asa@124 308 return useVellum(vellumLevelMap[vellumID], idealVellum or vellumID)
Asa@124 309 end
Asa@124 310 end
Asa@133 311
Asa@60 312 btnProcess:SetScript("OnClick", function (self, button, down)
Asa@60 313 local data = ItemAuditor:GetCraftingRow(1)
Asa@60 314 if data then
Asa@128 315 -- This will make sure the correct tradeskill window is open.
Asa@128 316 local tradeskillName = GetTradeSkillLine()
Asa@128 317 if data.tradeskillName ~= tradeskillName then
Asa@128 318 CastSpellByName(data.tradeskillName)
Asa@128 319 end
Asa@133 320
Asa@124 321 local queue = data.queue
Asa@124 322 local vellumID = nil
Asa@124 323 _, _, _, _, altVerb = GetTradeSkillInfo(data.tradeSkillIndex)
Asa@124 324 if altVerb == 'Enchant' and LSW.scrollData[data.recipeID] ~= nil then
Asa@124 325 vellumID = LSW.scrollData[data.recipeID]["vellumID"]
Asa@124 326 queue = 1
Asa@124 327 end
Asa@124 328 ItemAuditor:Print('Crafting %sx%s', data.link, queue)
Asa@124 329 DoTradeSkill(data.tradeSkillIndex, queue)
Asa@124 330 if vellumID then
Asa@124 331 useVellum(vellumID)
Asa@124 332 end
Asa@124 333
Asa@60 334 UpdateProcessTooltip()
Asa@60 335 end
Asa@59 336 end)
Asa@59 337
Asa@60 338 btnProcess:SetScript("OnEnter", UpdateProcessTooltip)
Asa@60 339
Asa@59 340 btnProcess:SetScript("OnLeave", function()
Asa@59 341 GameTooltip:Hide()
Asa@59 342 end)
Asa@133 343
Asa@59 344 btnSkillet = CreateFrame("Button", nil, craftingContent, "UIPanelButtonTemplate")
Asa@99 345
Asa@133 346 btnSkillet:SetSize(125, 25)
Asa@59 347 btnSkillet:SetPoint("BOTTOMRIGHT", btnProcess, 'BOTTOMLEFT', 0, 0)
Asa@59 348 btnSkillet:RegisterForClicks("LeftButtonUp");
Asa@59 349 btnSkillet:SetScript("OnClick", function (self, button, down)
Asa@70 350 Crafting.Export()
Asa@59 351 end)
Asa@133 352
Asa@59 353 end
Asa@70 354 local destination = select(2, Crafting.GetQueueDestination())
Asa@70 355 btnSkillet:SetText("Export to "..destination)
Asa@133 356
Asa@59 357 craftingContent:Show()
Asa@133 358
Asa@59 359 if container.parent then
Asa@59 360 local width = 80
Asa@133 361 for i, data in pairs(craftingCols) do
Asa@59 362 width = width + data.width
Asa@59 363 end
Asa@59 364 container.parent:SetWidth(width);
Asa@59 365 end
Asa@133 366
Asa@59 367 ItemAuditor:RegisterEvent("TRADE_SKILL_SHOW", function()
Asa@59 368 if craftingContent and craftingContent:IsVisible() then
Asa@59 369 ItemAuditor:UpdateCraftingTable()
Asa@59 370 end
Asa@59 371 end)
Asa@59 372 ItemAuditor:UpdateCraftingTable()
Asa@133 373
Asa@59 374 return craftingContent
Asa@59 375 end
Asa@59 376
Asa@59 377 ItemAuditor:RegisterTab('Crafting', 'tab_crafting', ShowCrafting)
Asa@59 378 function ItemAuditor:DisplayCrafting()
Asa@59 379 self:CreateFrame('tab_crafting')
Asa@59 380 end
Asa@59 381
Asa@59 382 local craftingDeciders = {}
Asa@59 383
Asa@72 384 function Crafting.RegisterCraftingDecider(name, decider, options)
Asa@59 385 craftingDeciders[name] = decider
Asa@133 386
Asa@72 387 ItemAuditor.Options.args.crafting_options.args['chk'..name] = {
Asa@72 388 type = "toggle",
Asa@72 389 name = "Enable "..name,
Asa@72 390 get = function() return not ItemAuditor.db.profile.disabled_deciders[name] end,
Asa@72 391 set = function(info, value) ItemAuditor.db.profile.disabled_deciders[name] = not value end,
Asa@72 392 order = 11,
Asa@72 393 }
Asa@133 394
Asa@72 395 if options then
Asa@72 396 ItemAuditor.Options.args.crafting_options.args['decider_'..name] = {
Asa@72 397 handler = {},
Asa@72 398 name = name,
Asa@72 399 type = 'group',
Asa@72 400 args = options,
Asa@72 401 }
Asa@72 402 end
Asa@59 403 end
Asa@59 404
Asa@59 405 local lastWinnder = ""
Asa@59 406 local function Decide(data)
Asa@59 407 local newDecision = 0
Asa@74 408 local reason = ""
Asa@59 409 for name, decider in pairs(craftingDeciders) do
Asa@72 410 if not ItemAuditor.db.profile.disabled_deciders[name] and name ~= lastWinner then
Asa@74 411 newDecision, reason = decider(data)
Asa@133 412
Asa@59 413 if newDecision > data.queue then
Asa@59 414 data.queue = newDecision
Asa@74 415 lastWinner = (reason or name)
Asa@59 416 return Decide(data)
Asa@59 417 elseif newDecision < 0 then
Asa@59 418 lastWinner = ""
Asa@74 419 return 'VETO: '..(reason or name), -1
Asa@59 420 end
Asa@59 421 end
Asa@59 422 end
Asa@133 423
Asa@59 424 winner = lastWinner
Asa@59 425 lastWinner = ""
Asa@133 426
Asa@77 427 data.queue = ceil(data.queue / GetTradeSkillNumMade(data.tradeSkillIndex))
Asa@133 428
Asa@59 429 return winner, data.queue
Asa@59 430 end
Asa@59 431
Asa@59 432 local function isProfitable(data)
Asa@59 433 if data.profit > 0 and data.profit > ItemAuditor:GetCraftingThreshold() then
Asa@59 434 return 1
Asa@59 435 end
Asa@99 436 return -1, 'Not Profitable'
Asa@59 437 end
Asa@72 438
Asa@101 439 local isProfitableOptions = {
Asa@101 440 profitable_threshold = {
Asa@101 441 type = "input",
Asa@101 442 name = "Crafting Threshold",
Asa@101 443 desc = "Don't create items that will make less than this amount of profit",
Asa@101 444 get = function() return
Asa@101 445 Utils.FormatMoney(ItemAuditor:GetCraftingThreshold(), '', true)
Asa@101 446 end,
Asa@101 447 validate = function(info, value)
Asa@101 448 if not Utils.validateMoney(value) then
Asa@101 449 return "Invalid money format"
Asa@101 450 end
Asa@101 451 return true
Asa@101 452 end,
Asa@101 453 set = function(info, value)
Asa@101 454 ItemAuditor.db.char.profitable_threshold = Utils.parseMoney(value)
Asa@101 455 end,
Asa@101 456 usage = "###g ##s ##c",
Asa@101 457 order = 0,
Asa@101 458 },
Asa@101 459 }
Asa@101 460
Asa@101 461 Crafting.RegisterCraftingDecider('Is Profitable', isProfitable, isProfitableOptions)
Asa@59 462
Asa@74 463
Asa@59 464
Asa@59 465 local tableData = {}
Asa@59 466 function ItemAuditor:UpdateCraftingTable()
Asa@59 467 if LSW == nil then
Asa@59 468 self:Print("This feature requires LilSparky's Workshop.")
Asa@59 469 return
Asa@59 470 end
Asa@59 471 if GetAuctionBuyout ~= nil then
Asa@59 472 elseif AucAdvanced and AucAdvanced.Version then
Asa@59 473 else
Asa@59 474 self:Print("This feature requires Auctionator, Auctioneer, AuctionLite, or AuctionMaster.")
Asa@59 475 return
Asa@59 476 end
Asa@128 477 local tradeskillName = GetTradeSkillLine()
Asa@133 478
Asa@59 479 wipe(tableData)
Asa@133 480
Asa@59 481 local profitableItems = {}
Asa@59 482 local profitableIndex = 1
Asa@59 483 local numChecked = 0
Asa@128 484 local numTradeSkills = GetNumTradeSkills()
Asa@128 485 if tradeskillName == 'UNKNOWN' then
Asa@128 486 numTradeSkills = 0
Asa@128 487 end
Asa@133 488
Asa@134 489 local row = 1
Asa@59 490
Asa@128 491 for i = 1, numTradeSkills do
Asa@59 492 local itemLink = GetTradeSkillItemLink(i)
Asa@86 493 local itemId = Utils.GetItemID(itemLink)
Asa@124 494 local vellumID = nil
Asa@59 495
Asa@59 496 --Figure out if its an enchant or not
Asa@59 497 _, _, _, _, altVerb = GetTradeSkillInfo(i)
Asa@59 498 if LSW.scrollData[itemId] ~= nil and altVerb == 'Enchant' then
Asa@59 499 -- Ask LSW for the correct scroll
Asa@124 500 local sd = LSW.scrollData[itemId]
Asa@124 501 itemId = sd.scrollID
Asa@124 502 vellumID = sd.vellumID
Asa@59 503 end
Asa@59 504
Asa@59 505 local recipeLink = GetTradeSkillRecipeLink(i)
Asa@59 506 local stackSize = 1
Asa@59 507 if recipeLink ~= nil and itemId ~= nil then
Asa@59 508 local skillName, skillType, numAvailable, isExpanded, altVerb = GetTradeSkillInfo(i)
Asa@59 509 local itemName, itemLink= GetItemInfo(itemId)
Asa@133 510
Asa@74 511 -- This check has to be here for things like Inscription Research that don't produce an item.
Asa@74 512 if itemLink then
Asa@82 513 local count = ItemAuditor:GetItemCount(itemId)
Asa@74 514 local reagents = {}
Asa@74 515 local totalCost = 0
Asa@74 516 for reagentId = 1, GetTradeSkillNumReagents(i) do
Asa@74 517 local reagentName, _, reagentCount = GetTradeSkillReagentInfo(i, reagentId);
Asa@74 518 local reagentLink = GetTradeSkillReagentItemLink(i, reagentId)
Asa@102 519 local reagentTotalCost = self:GetReagentCost(reagentLink, reagentCount)
Asa@133 520
Asa@74 521 reagents[reagentId] = {
Asa@93 522 link = reagentLink,
Asa@124 523 itemID = Utils.GetItemID(reagentLink),
Asa@74 524 name = reagentName,
Asa@74 525 count = reagentCount,
Asa@102 526 price = reagentTotalCost / reagentCount,
Asa@94 527 need = 0, -- This will get populated after the decisions have been made. it can't
Asa@94 528 -- be done before that because highest profit items get priority on materials.
Asa@74 529 }
Asa@102 530 totalCost = totalCost + reagentTotalCost
Asa@74 531 end
Asa@124 532 if vellumID then
Asa@124 533 reagentId = GetTradeSkillNumReagents(i) + 1
Asa@124 534 local reagentName, reagentLink = GetItemInfo(vellumID)
Asa@124 535 reagents[reagentId] = {
Asa@124 536 link = reagentLink,
Asa@124 537 itemID = vellumID,
Asa@124 538 name = reagentName,
Asa@124 539 count = 1,
Asa@124 540 price = self:GetReagentCost(reagentLink, 1),
Asa@124 541 need = 0, -- This will get populated after the decisions have been made. it can't
Asa@124 542 -- be done before that because highest profit items get priority on materials.
Asa@124 543 }
Asa@124 544 totalCost = totalCost + self:GetReagentCost(reagentLink, 1)
Asa@124 545 end
Asa@116 546
Asa@116 547 local price = (self:GetAuctionPrice(itemLink) or 0)
Asa@116 548 totalCost = totalCost + (price * ItemAuditor:GetAHCut())
Asa@74 549 local data = {
Asa@74 550 recipeLink = recipeLink,
Asa@95 551 recipeID = Utils.GetItemID(recipeLink),
Asa@74 552 link = itemLink,
Asa@74 553 name = itemName,
Asa@128 554 skillName = skillName,
Asa@74 555 count = count,
Asa@110 556 price = price,
Asa@74 557 cost = totalCost,
Asa@110 558 profit = price - totalCost,
Asa@74 559 reagents = reagents,
Asa@74 560 count = count,
Asa@74 561 tradeSkillIndex = i,
Asa@74 562 queue = 0,
Asa@74 563 winner = "",
Asa@128 564 tradeskillName = tradeskillName,
Asa@74 565 }
Asa@133 566
Asa@74 567 data.winner, data.queue = Decide(data)
Asa@99 568 --[[
Asa@99 569 If it wasn't vetoed we need to reduce the number by how many are owned
Asa@99 570 but this should not go below 0
Asa@99 571 ]]
Asa@99 572 if data.queue > 0 then
Asa@99 573 data.queue = max(0, data.queue - count)
Asa@99 574 end
Asa@133 575
Asa@133 576 -- If a tradeskill makes 5 at a time and something asks for 9, we should only
Asa@74 577 -- craft twice to get 10.
Asa@74 578 data.queue = ceil(data.queue / GetTradeSkillNumMade(i))
Asa@128 579
Asa@74 580 realData[row] = data
Asa@128 581 nameMap[skillName] = row
Asa@74 582 row = row + 1
Asa@59 583 end
Asa@59 584 end
Asa@59 585 end
Asa@99 586 table.sort(realData, function(a, b) return a.profit*max(1, a.queue) > b.profit*max(1, b.queue) end)
Asa@94 587
Asa@94 588 local numOwned = {}
Asa@124 589
Asa@94 590 for key, data in pairs(realData) do
Asa@126 591 data.haveMaterials = data.queue
Asa@94 592 for id, reagent in pairs(data.reagents) do
Asa@126 593 local needEach = reagent.count
Asa@122 594 reagent.count = reagent.count * data.queue
Asa@122 595
Asa@94 596 if not numOwned[reagent.link] then
Asa@94 597 numOwned[reagent.link] = ItemAuditor:GetItemCount(ItemAuditor:GetIDFromLink(reagent.link))
Asa@94 598 end
Asa@126 599 data.haveMaterials = min(data.haveMaterials, floor(numOwned[reagent.link] / needEach))
Asa@94 600 numOwned[reagent.link] = numOwned[reagent.link] - reagent.count
Asa@94 601
Asa@124 602 -- Vellums count in cost, but not against whether or not you have the mats.
Asa@124 603 -- I chose to do it this way because you can use a higher level of vellum
Asa@124 604 -- and I'm not sure the best way to determine cost and materials in that situation.
Asa@124 605 if numOwned[reagent.link] < 0 and not vellumLevelMap[reagent.itemID] then
Asa@94 606 reagent.need = min(reagent.count, abs(numOwned[reagent.link]))
Asa@94 607 end
Asa@94 608 end
Asa@126 609 data.haveMaterials = max(0, data.haveMaterials)
Asa@94 610 end
Asa@94 611
Asa@68 612 if craftingTable then
Asa@68 613 craftingTable:SetFilter(tableFilter)
Asa@68 614 self:RefreshCraftingTable()
Asa@68 615 end
Asa@60 616 end
Asa@60 617
Asa@60 618 function ItemAuditor:RefreshCraftingTable()
Asa@131 619 -- If the crafting table hasn't been created/displayed, there is no
Asa@131 620 -- reason to try to update it.
Asa@131 621 if not craftingTable then
Asa@131 622 return
Asa@131 623 end
Asa@128 624 tableData = {}
Asa@128 625 nameMap = {}
Asa@59 626 for key, data in pairs(realData) do
Asa@128 627 nameMap[data.name] = key
Asa@128 628
Asa@59 629 tableData[key] = {
Asa@59 630 data.name,
Asa@59 631 data.cost,
Asa@59 632 data.price,
Asa@59 633 data.winner,
Asa@99 634 abs(data.queue),
Asa@126 635 data.haveMaterials,
Asa@123 636 data.profit,
Asa@59 637 }
Asa@59 638 end
Asa@60 639 craftingTable:SetData(tableData, true)
Asa@133 640
Asa@60 641 if self:GetCraftingRow(1) then
Asa@60 642 btnProcess:Enable()
Asa@60 643 else
Asa@60 644 btnProcess:Disable()
Asa@60 645 end
Asa@59 646 end
Asa@59 647
Asa@59 648 function ItemAuditor:GetCraftingRow(row)
Asa@59 649 if craftingTable then
Asa@59 650 for _, index in pairs(craftingTable.sorttable) do
Asa@59 651 local tableRow = tableData[index]
Asa@59 652 if tableFilter(nil, tableRow) then
Asa@59 653 row = row - 1
Asa@59 654 if row == 0 then
Asa@59 655 return realData[index]
Asa@59 656 end
Asa@59 657 end
Asa@59 658 end
Asa@59 659 elseif realData then
Asa@59 660 return realData[row]
Asa@59 661 end
Asa@59 662 return nil
Asa@59 663 end
Asa@67 664 ItemAuditor.Options.args.crafting = {
Asa@67 665 type = "execute",
Asa@67 666 name = "crafting",
Asa@67 667 desc = "This opens a window to configure a crafting queue.",
Asa@67 668 func = "DisplayCrafting",
Asa@67 669 guiHidden = false,
Asa@67 670 }