annotate Modules/Crafting.lua @ 71:aaf9a155995b

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