annotate Modules/Crafting.lua @ 86:8d5ad3b71f6f

Removed references to Skillet in core functionality. Skillet really should be optional.
author Asa Ayers <Asa.Ayers@Gmail.com>
date Sat, 07 Aug 2010 11:16:21 -0700
parents e9f7bc9199ca
children 693f664aad2b
rev   line source
Asa@63 1 local ItemAuditor = select(2, ...)
Asa@63 2 local Crafting = ItemAuditor:NewModule("Crafting")
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@59 13
Asa@67 14
Asa@68 15 local queueDestinations = {}
Asa@70 16 local displayCraftingDestinations = {}
Asa@68 17 function Crafting.RegisterQueueDestination(name, destination)
Asa@68 18 queueDestinations[name] = destination
Asa@70 19 displayCraftingDestinations[name] = name
Asa@70 20 end
Asa@70 21
Asa@70 22 function Crafting.UnRegisterQueueDestination(name)
Asa@70 23 queueDestinations[name] = nil
Asa@70 24 displayCraftingDestinations[name] = nil
Asa@70 25 end
Asa@70 26
Asa@70 27 function Crafting.GetQueueDestination()
Asa@70 28 local dest = ItemAuditor.db.profile.queue_destination
Asa@70 29 if dest and queueDestinations[dest] then
Asa@70 30 return queueDestinations[dest], dest
Asa@70 31 end
Asa@70 32 -- If there is none selected or the selected option has
Asa@70 33 -- dissapeared, choose the first one in the list
Asa@70 34 for name, func in pairs(queueDestinations) do
Asa@70 35 if dest then
Asa@70 36 ItemAuditor:Print("%s is no longer available as a queue destination. %s is the new default", dest, name)
Asa@70 37 end
Asa@70 38 ItemAuditor.db.profile.queue_destination = name
Asa@70 39 return func, name
Asa@70 40 end
Asa@70 41
Asa@70 42 error('Unable to determine queue destination.')
Asa@68 43 end
Asa@68 44
Asa@67 45 -- TODO: Convert this to a text field.
Asa@67 46 local craftingThresholds = {5000, 10000, 50000}
Asa@67 47 local craftingThresholdsDisplay = {}
Asa@67 48
Asa@67 49 for key, value in pairs(craftingThresholds) do
Asa@67 50 craftingThresholdsDisplay[key] = ItemAuditor:FormatMoney(value, '', true)
Asa@67 51 -- craftingThresholdsDisplay[key] = value
Asa@67 52 end
Asa@67 53
Asa@68 54 function ItemAuditor:GetCraftingThreshold()
Asa@68 55 local key = ItemAuditor.db.char.crafting_threshold
Asa@68 56 return craftingThresholds[key]
Asa@68 57 end
Asa@68 58
Asa@67 59 ItemAuditor.Options.args.crafting_options = {
Asa@70 60 name = "Crafting",
Asa@67 61 type = 'group',
Asa@67 62 args = {
Asa@67 63 crafting_threshold = {
Asa@67 64 type = "select",
Asa@67 65 name = "Crafting Threshold",
Asa@67 66 desc = "Don't create items that will make less than this amount of profit",
Asa@67 67 values = craftingThresholdsDisplay,
Asa@67 68 get = function() return ItemAuditor.db.char.crafting_threshold end,
Asa@67 69 set = function(info, value) ItemAuditor.db.char.crafting_threshold = value end,
Asa@72 70 order = 0,
Asa@67 71 },
Asa@70 72 queue_destination = {
Asa@70 73 type = "select",
Asa@70 74 name = "Queue Destination",
Asa@70 75 desc = "Select the addon who's queue you would like ItemAuditor to post to.",
Asa@70 76 values = displayCraftingDestinations,
Asa@70 77 get = function() return select(2, Crafting.GetQueueDestination()) end,
Asa@70 78 set = function(info, value) ItemAuditor.db.profile.queue_destination = value end,
Asa@72 79 order = 1,
Asa@70 80 },
Asa@72 81 deciders = {
Asa@72 82 type="header",
Asa@72 83 name="Crafting Deciders",
Asa@72 84 order = 10,
Asa@72 85 },
Asa@72 86
Asa@67 87 },
Asa@67 88 }
Asa@67 89
Asa@59 90 local function displayMoney(rowFrame, cellFrame, data, cols, row, realrow, column, fShow, table, ...)
Asa@59 91 if fShow == true then
Asa@59 92 local money = data[realrow][column]
Asa@59 93 if money then
Asa@59 94 cellFrame.text:SetText(ItemAuditor:FormatMoney(tonumber(money)))
Asa@59 95 else
Asa@59 96 cellFrame.text:SetText("")
Asa@59 97 end
Asa@59 98
Asa@59 99 end
Asa@59 100 end
Asa@59 101
Asa@59 102 local craftingCols = {
Asa@59 103 { name= "Item", width = 200, defaultsort = "desc",
Asa@59 104 ['DoCellUpdate'] = function(rowFrame, cellFrame, data, cols, row, realrow, column, fShow, table, ...)
Asa@59 105 if fShow == true then
Asa@59 106 local data = realData[realrow]
Asa@59 107 cellFrame.text:SetText(data.link)
Asa@59 108 end
Asa@59 109 end,
Asa@59 110 },
Asa@59 111 { name= "Cost Each", width = 100, align = "RIGHT",
Asa@59 112 ['DoCellUpdate'] = displayMoney,
Asa@59 113 },
Asa@59 114 { name= "Est Sale Each", width = 100, align = "RIGHT",
Asa@59 115 ['DoCellUpdate'] = displayMoney,
Asa@59 116 },
Asa@59 117 { name= "Decided By", width = 100, align = "RIGHT",
Asa@59 118
Asa@59 119 },
Asa@59 120 { name= "craft", width = 50, align = "RIGHT",
Asa@59 121
Asa@59 122 },
Asa@59 123 { name= "Total Profit", width = 100, align = "RIGHT",
Asa@59 124 ['DoCellUpdate'] = displayMoney,
Asa@59 125 },
Asa@59 126 }
Asa@59 127
Asa@68 128 function Crafting.ExportToSkillet(data)
Asa@68 129 local skillString = select(3, string.find(data.recipeLink, "^|%x+|H(.+)|h%[.+%]"))
Asa@68 130 local _, skillId = strsplit(":", skillString)
Asa@68 131
Asa@68 132 ItemAuditor:AddToQueue(skillId,tradeSkillIndex, data.queue)
Asa@68 133 end
Asa@68 134
Asa@68 135 Crafting.RegisterQueueDestination('Skillet', Crafting.ExportToSkillet)
Asa@68 136
Asa@68 137
Asa@68 138
Asa@68 139 function Crafting.Export(destination)
Asa@68 140 if type(destination) == 'function' then
Asa@68 141 -- do nothing
Asa@68 142 elseif destination == nil then
Asa@70 143 destination = Crafting.GetQueueDestination()
Asa@68 144 elseif type(destination) == 'string' then
Asa@68 145 destination = queueDestinations[destination]
Asa@68 146 else
Asa@68 147 error('destination must be a function or a string')
Asa@68 148 end
Asa@68 149
Asa@59 150 local index = 1
Asa@59 151 local data = ItemAuditor:GetCraftingRow(index)
Asa@59 152 while data do
Asa@68 153 if data.queue > 0 then
Asa@68 154 destination(data)
Asa@68 155 end
Asa@61 156 index = index + 1
Asa@61 157 data = ItemAuditor:GetCraftingRow(index)
Asa@59 158
Asa@59 159 end
Asa@59 160 end
Asa@59 161
Asa@74 162 -- ItemAuditor:GetModule('Crafting').filter_queued = false
Asa@74 163 Crafting.filter_queued = true
Asa@74 164 local function tableFilter(self, row, ...)
Asa@74 165 -- column 5 is how many should be crafted
Asa@74 166 if Crafting.filter_queued and row[5] <= 0 then
Asa@74 167 return false
Asa@74 168 end
Asa@74 169 return true
Asa@74 170 end
Asa@74 171
Asa@59 172 local craftingContent = false
Asa@59 173 local craftingTable = false
Asa@60 174 local btnProcess = false
Asa@59 175 local function ShowCrafting(container)
Asa@59 176 if craftingContent == false then
Asa@59 177 local window = container.frame
Asa@59 178 craftingContent = CreateFrame("Frame",nil,window)
Asa@59 179 craftingContent:SetBackdropColor(0, 0, 1, 0.5)
Asa@59 180 craftingContent:SetBackdropBorderColor(1, 0, 0, 1)
Asa@59 181
Asa@59 182 craftingContent:SetPoint("TOPLEFT", window, 10, -50)
Asa@59 183 craftingContent:SetPoint("BOTTOMRIGHT",window, -10, 10)
Asa@59 184
Asa@59 185 craftingTable = ScrollingTable:CreateST(craftingCols, 22, nil, nil, craftingContent )
Asa@59 186
Asa@59 187 IAcc = craftingContent
Asa@59 188 IAccWindow = window
Asa@59 189 craftingTable.frame:SetPoint("TOPLEFT",craftingContent, 0,0)
Asa@59 190 craftingTable.frame:SetPoint("BOTTOMRIGHT", craftingContent, 0, 30)
Asa@59 191
Asa@59 192 craftingTable:RegisterEvents({
Asa@59 193 ["OnEnter"] = function (rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
Asa@59 194 if realrow then
Asa@59 195 local data = realData[realrow]
Asa@59 196
Asa@59 197 GameTooltip:SetOwner(rowFrame, "ANCHOR_CURSOR")
Asa@59 198 GameTooltip:SetHyperlink(data.link)
Asa@59 199 GameTooltip:Show()
Asa@59 200 end
Asa@59 201 end,
Asa@59 202 ["OnLeave"] = function (rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
Asa@59 203 GameTooltip:Hide()
Asa@59 204 end,
Asa@59 205 });
Asa@59 206
Asa@59 207
Asa@59 208 btnProcess = CreateFrame("Button", nil, craftingContent, "UIPanelButtonTemplate")
Asa@59 209 btnProcess:SetText("Process")
Asa@59 210 btnProcess:SetSize(100, 25)
Asa@59 211 btnProcess:SetPoint("BOTTOMRIGHT", craftingContent, 0, 0)
Asa@59 212 btnProcess:RegisterForClicks("LeftButtonUp");
Asa@59 213
Asa@60 214 local function UpdateProcessTooltip(btn)
Asa@59 215 local data = ItemAuditor:GetCraftingRow(1)
Asa@59 216 if data then
Asa@59 217 GameTooltip:SetOwner(this, "ANCHOR_CURSOR")
Asa@59 218 GameTooltip:SetText(format('Create %sx%s', data.link, data.queue))
Asa@59 219 GameTooltip:Show()
Asa@59 220 end
Asa@60 221 end
Asa@60 222 btnProcess:SetScript("OnClick", function (self, button, down)
Asa@60 223 local data = ItemAuditor:GetCraftingRow(1)
Asa@60 224 if data then
Asa@60 225 ItemAuditor:Print('Crafting %sx%s', data.link, data.queue)
Asa@60 226 DoTradeSkill(data.tradeSkillIndex, data.queue)
Asa@60 227 data.queue = 0
Asa@60 228 ItemAuditor:RefreshCraftingTable()
Asa@60 229 UpdateProcessTooltip()
Asa@60 230 end
Asa@59 231 end)
Asa@59 232
Asa@60 233 btnProcess:SetScript("OnEnter", UpdateProcessTooltip)
Asa@60 234
Asa@59 235 btnProcess:SetScript("OnLeave", function()
Asa@59 236 GameTooltip:Hide()
Asa@59 237 end)
Asa@59 238
Asa@59 239 btnSkillet = CreateFrame("Button", nil, craftingContent, "UIPanelButtonTemplate")
Asa@70 240
Asa@70 241
Asa@59 242 btnSkillet:SetSize(125, 25)
Asa@59 243 btnSkillet:SetPoint("BOTTOMRIGHT", btnProcess, 'BOTTOMLEFT', 0, 0)
Asa@59 244 btnSkillet:RegisterForClicks("LeftButtonUp");
Asa@59 245 btnSkillet:SetScript("OnClick", function (self, button, down)
Asa@70 246 Crafting.Export()
Asa@59 247 end)
Asa@59 248
Asa@59 249 end
Asa@70 250 local destination = select(2, Crafting.GetQueueDestination())
Asa@70 251 btnSkillet:SetText("Export to "..destination)
Asa@70 252
Asa@59 253 craftingContent:Show()
Asa@59 254
Asa@59 255 if container.parent then
Asa@59 256 local width = 80
Asa@59 257 for i, data in pairs(craftingCols) do
Asa@59 258 width = width + data.width
Asa@59 259 end
Asa@59 260 container.parent:SetWidth(width);
Asa@59 261 end
Asa@59 262
Asa@59 263 ItemAuditor:RegisterEvent("TRADE_SKILL_SHOW", function()
Asa@59 264 if craftingContent and craftingContent:IsVisible() then
Asa@59 265 ItemAuditor:UpdateCraftingTable()
Asa@59 266 end
Asa@59 267 end)
Asa@59 268 ItemAuditor:UpdateCraftingTable()
Asa@59 269
Asa@59 270 return craftingContent
Asa@59 271 end
Asa@59 272
Asa@59 273
Asa@59 274
Asa@59 275 ItemAuditor:RegisterTab('Crafting', 'tab_crafting', ShowCrafting)
Asa@59 276 function ItemAuditor:DisplayCrafting()
Asa@59 277 self:CreateFrame('tab_crafting')
Asa@59 278 end
Asa@59 279
Asa@59 280 local craftingDeciders = {}
Asa@59 281
Asa@72 282 function Crafting.RegisterCraftingDecider(name, decider, options)
Asa@59 283 craftingDeciders[name] = decider
Asa@72 284
Asa@72 285 ItemAuditor.Options.args.crafting_options.args['chk'..name] = {
Asa@72 286 type = "toggle",
Asa@72 287 name = "Enable "..name,
Asa@72 288 get = function() return not ItemAuditor.db.profile.disabled_deciders[name] end,
Asa@72 289 set = function(info, value) ItemAuditor.db.profile.disabled_deciders[name] = not value end,
Asa@72 290 order = 11,
Asa@72 291 }
Asa@72 292
Asa@72 293 if options then
Asa@72 294 ItemAuditor.Options.args.crafting_options.args['decider_'..name] = {
Asa@72 295 handler = {},
Asa@72 296 name = name,
Asa@72 297 type = 'group',
Asa@72 298 args = options,
Asa@72 299 }
Asa@72 300 end
Asa@59 301 end
Asa@59 302
Asa@59 303 local lastWinnder = ""
Asa@59 304 local function Decide(data)
Asa@59 305 local newDecision = 0
Asa@74 306 local reason = ""
Asa@59 307 for name, decider in pairs(craftingDeciders) do
Asa@72 308 if not ItemAuditor.db.profile.disabled_deciders[name] and name ~= lastWinner then
Asa@74 309 newDecision, reason = decider(data)
Asa@74 310
Asa@59 311 if newDecision > data.queue then
Asa@59 312 data.queue = newDecision
Asa@74 313 lastWinner = (reason or name)
Asa@59 314 return Decide(data)
Asa@59 315 elseif newDecision < 0 then
Asa@59 316 lastWinner = ""
Asa@74 317 return 'VETO: '..(reason or name), -1
Asa@59 318 end
Asa@59 319 end
Asa@59 320 end
Asa@59 321
Asa@59 322 winner = lastWinner
Asa@59 323 lastWinner = ""
Asa@59 324
Asa@77 325 data.queue = ceil(data.queue / GetTradeSkillNumMade(data.tradeSkillIndex))
Asa@77 326
Asa@59 327 return winner, data.queue
Asa@59 328 end
Asa@59 329
Asa@59 330 local function isProfitable(data)
Asa@59 331 if data.profit > 0 and data.profit > ItemAuditor:GetCraftingThreshold() then
Asa@59 332 return 1
Asa@59 333 end
Asa@59 334 return -1
Asa@59 335 end
Asa@72 336
Asa@64 337 Crafting.RegisterCraftingDecider('Is Profitable', isProfitable)
Asa@59 338
Asa@74 339
Asa@59 340
Asa@59 341 local tableData = {}
Asa@59 342 function ItemAuditor:UpdateCraftingTable()
Asa@59 343 if LSW == nil then
Asa@59 344 self:Print("This feature requires LilSparky's Workshop.")
Asa@59 345 return
Asa@59 346 end
Asa@59 347 if GetAuctionBuyout ~= nil then
Asa@59 348 elseif AucAdvanced and AucAdvanced.Version then
Asa@59 349 else
Asa@59 350 self:Print("This feature requires Auctionator, Auctioneer, AuctionLite, or AuctionMaster.")
Asa@59 351 return
Asa@59 352 end
Asa@59 353 wipe(realData)
Asa@59 354 wipe(tableData)
Asa@59 355
Asa@59 356 local profitableItems = {}
Asa@59 357 local profitableIndex = 1
Asa@59 358 local numChecked = 0
Asa@59 359 local row = 1
Asa@59 360
Asa@59 361 for i = 1, GetNumTradeSkills() do
Asa@59 362 local itemLink = GetTradeSkillItemLink(i)
Asa@86 363 local itemId = Utils.GetItemID(itemLink)
Asa@59 364
Asa@59 365 --Figure out if its an enchant or not
Asa@59 366 _, _, _, _, altVerb = GetTradeSkillInfo(i)
Asa@59 367 if LSW.scrollData[itemId] ~= nil and altVerb == 'Enchant' then
Asa@59 368 -- Ask LSW for the correct scroll
Asa@59 369 itemId = LSW.scrollData[itemId]["scrollID"]
Asa@59 370 end
Asa@59 371
Asa@59 372 local recipeLink = GetTradeSkillRecipeLink(i)
Asa@59 373 local stackSize = 1
Asa@59 374 if recipeLink ~= nil and itemId ~= nil then
Asa@59 375 local skillName, skillType, numAvailable, isExpanded, altVerb = GetTradeSkillInfo(i)
Asa@59 376 local itemName, itemLink= GetItemInfo(itemId)
Asa@74 377
Asa@74 378 -- This check has to be here for things like Inscription Research that don't produce an item.
Asa@74 379 if itemLink then
Asa@82 380 local count = ItemAuditor:GetItemCount(itemId)
Asa@74 381 local reagents = {}
Asa@74 382 local totalCost = 0
Asa@74 383 for reagentId = 1, GetTradeSkillNumReagents(i) do
Asa@74 384 local reagentName, _, reagentCount = GetTradeSkillReagentInfo(i, reagentId);
Asa@74 385 local reagentLink = GetTradeSkillReagentItemLink(i, reagentId)
Asa@74 386
Asa@74 387 reagents[reagentId] = {
Asa@74 388 name = reagentName,
Asa@74 389 count = reagentCount,
Asa@74 390 price = self:GetReagentCost(reagentLink, reagentCount),
Asa@74 391 }
Asa@74 392 totalCost = totalCost + self:GetReagentCost(reagentLink, reagentCount)
Asa@74 393 end
Asa@74 394 local data = {
Asa@74 395 recipeLink = recipeLink,
Asa@74 396 link = itemLink,
Asa@74 397 name = itemName,
Asa@74 398 count = count,
Asa@74 399 price = (self:GetAuctionPrice(itemLink) or 0),
Asa@74 400 cost = totalCost,
Asa@74 401 profit = (self:GetAuctionPrice(itemLink) or 0) - totalCost,
Asa@74 402 reagents = reagents,
Asa@74 403 count = count,
Asa@74 404 tradeSkillIndex = i,
Asa@74 405 queue = 0,
Asa@74 406 winner = "",
Asa@74 407 }
Asa@59 408
Asa@74 409 data.winner, data.queue = Decide(data)
Asa@74 410 data.queue = data.queue - count
Asa@74 411
Asa@74 412 -- If a tradeskill makes 5 at a time and something asks for 9, we should only
Asa@74 413 -- craft twice to get 10.
Asa@74 414 data.queue = ceil(data.queue / GetTradeSkillNumMade(i))
Asa@74 415
Asa@74 416 realData[row] = data
Asa@74 417 row = row + 1
Asa@59 418 end
Asa@59 419 end
Asa@59 420 end
Asa@59 421 table.sort(realData, function(a, b) return a.profit*a.queue > b.profit*b.queue end)
Asa@68 422 if craftingTable then
Asa@68 423 craftingTable:SetFilter(tableFilter)
Asa@68 424 self:RefreshCraftingTable()
Asa@68 425 end
Asa@60 426 end
Asa@60 427
Asa@60 428 function ItemAuditor:RefreshCraftingTable()
Asa@59 429 for key, data in pairs(realData) do
Asa@59 430 tableData[key] = {
Asa@59 431 data.name,
Asa@59 432 data.cost,
Asa@59 433 data.price,
Asa@59 434 data.winner,
Asa@59 435 data.queue,
Asa@59 436 data.profit*data.queue,
Asa@59 437 }
Asa@59 438 end
Asa@60 439 craftingTable:SetData(tableData, true)
Asa@59 440
Asa@60 441 if self:GetCraftingRow(1) then
Asa@60 442 btnProcess:Enable()
Asa@60 443 else
Asa@60 444 btnProcess:Disable()
Asa@60 445 end
Asa@59 446 end
Asa@59 447
Asa@59 448 function ItemAuditor:GetCraftingRow(row)
Asa@59 449 if craftingTable then
Asa@59 450 for _, index in pairs(craftingTable.sorttable) do
Asa@59 451 local tableRow = tableData[index]
Asa@59 452 if tableFilter(nil, tableRow) then
Asa@59 453 row = row - 1
Asa@59 454 if row == 0 then
Asa@59 455 return realData[index]
Asa@59 456 end
Asa@59 457 end
Asa@59 458 end
Asa@59 459 elseif realData then
Asa@59 460 return realData[row]
Asa@59 461 end
Asa@59 462 return nil
Asa@59 463 end
Asa@67 464 ItemAuditor.Options.args.crafting = {
Asa@67 465 type = "execute",
Asa@67 466 name = "crafting",
Asa@67 467 desc = "This opens a window to configure a crafting queue.",
Asa@67 468 func = "DisplayCrafting",
Asa@67 469 guiHidden = false,
Asa@67 470 }