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