-
Notifications
You must be signed in to change notification settings - Fork 6
/
Inventory.lua
349 lines (340 loc) · 15.2 KB
/
Inventory.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
local addonName,addonTable = ...
local DA = _G[addonName] -- for DebugAids.lua
--[[
Skillet: A tradeskill window replacement.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]--
local PT = LibStub("LibPeriodicTable-3.1")
--
-- recursive reagent craftability check
-- not considering alts
-- does consider queued recipes
--
function Skillet:InventoryReagentCraftability(reagentID)
--DA.DEBUG(1,"InventoryReagentCraftability("..tostring(reagentID)..") -- "..tostring((C_Item.GetItemInfo(reagentID))))
if not reagentID or type(reagentID) == "table" or reagentID == 0 then
return 0, 0
end
local player = Skillet.currentPlayer
if self.visited[reagentID] then
local reagentA, reagentC, reagentCV = self:GetInventory(player, reagentID)
return reagentC, reagentCV
end
self.visited[reagentID] = true
local numReagentsCrafted = 0
local numReagentsCraftedVendor = 0
local skillIndexLookup = self.data.skillIndexLookup
local recipeSource = self.db.global.itemRecipeSource[reagentID]
if recipeSource then
--DA.DEBUG(2," ReagentCraftability: reagentID= "..tostring(reagentID).."("..tostring((C_Item.GetItemInfo(reagentID))).."), recipeSource= "..DA.DUMP1(recipeSource))
for childRecipeID in pairs(recipeSource) do
local childRecipe = self:GetRecipe(childRecipeID)
local childSkillIndex = skillIndexLookup[childRecipeID]
if childSkillIndex and childRecipe and #childRecipe.reagentData > 0 and
not self.TradeSkillIgnoredMats[childRecipeID] and not self.db.realm.userIgnoredMats[player][childRecipeID] then
local numCraftable = 100000
local numCraftableVendor = 100000
for i=1,#childRecipe.reagentData,1 do
local childReagent = childRecipe.reagentData[i]
local numReagentOnHand = C_Item.GetItemCount(childReagent.reagentID,true,false,true,true)
local numReagentCraftable, numReagentCraftableVendor = self:InventoryReagentCraftability(childReagent.reagentID)
numReagentCraftable = numReagentCraftable + numReagentOnHand
numReagentCraftableVendor = numReagentCraftableVendor + numReagentOnHand
numCraftable = math.min(numCraftable, math.floor(numReagentCraftable/childReagent.numNeeded))
if not self:VendorSellsReagent(childReagent.reagentID) then
numCraftableVendor = math.min(numCraftableVendor, math.floor(numReagentCraftableVendor/childReagent.numNeeded))
else
--DA.DEBUG(2," ReagentCraftability: VendorSellsReagent")
end
end
numReagentsCrafted = numReagentsCrafted + numCraftable * childRecipe.numMade
numReagentsCraftedVendor = numReagentsCraftedVendor + numCraftableVendor * childRecipe.numMade
end
end
else
--DA.DEBUG(2," ReagentCraftability: reagentID= "..tostring(reagentID).."("..tostring((C_Item.GetItemInfo(reagentID))).."), recipeSource= nil")
end
local queued = 0
if self.db.realm.reagentsInQueue[player] then
queued = self.db.realm.reagentsInQueue[player][reagentID] or 0
end
local numInBoth = self:GetInventory(player, reagentID)
local numCrafted = numReagentsCrafted + queued
local numCraftedVendor = numReagentsCraftedVendor + queued
if numCraftedVendor == 0 then
self.db.realm.inventoryData[player][reagentID] = numInBoth
else
self.db.realm.inventoryData[player][reagentID] = numInBoth.." "..numCrafted.." "..numCraftedVendor
end
return numCrafted, numCraftedVendor
end
--
-- recipe iteration check: calculate how many times a recipe can be iterated with materials available
-- (not to be confused with the reagent craftability which is designed to determine how many
-- craftable reagents are available for recipe iterations)
--
function Skillet:InventorySkillIterations(tradeID, recipe)
--DA.DEBUG(1,"InventorySkillIterations("..tostring(tradeID)..", "..tostring(recipe.name)..")")
local player = Skillet.currentPlayer
local faction = self.db.realm.faction[player]
if recipe then -- make sure that recipe is in the database before continuing
local recipeID = recipe.spellID
local numMade = recipe.numMade
local numCraft = 100000
local numCraftable = 100000
local numCraftableVendor = 100000
local numCraftVendor = 100000
local numCraftAlts = 100000
local vendorOnly = true
local reagents = {}
for i=1,#recipe.reagentData do
if recipe.reagentData[i].reagentID then
table.insert(reagents, {reagentID = recipe.reagentData[i].reagentID, numNeeded = recipe.reagentData[i].numNeeded })
end
end
if recipe.modifiedData then
for i=1,#recipe.modifiedData do
if recipe.modifiedData[i].reagentID then
-- table.insert(reagents, {reagentID = recipe.modifiedData[i].reagentID, numNeeded = recipe.modifiedData[i].numNeeded })
table.insert(reagents, {reagentID = recipe.modifiedData[i].schematic.reagents, numNeeded = recipe.modifiedData[i].numNeeded })
end
end
end
for _,reagent in pairs(reagents) do
local reagentID = reagent.reagentID
local numNeeded = reagent.numNeeded
local reagentAvailable = 0
local reagentCraftable = 0
local reagentCraftableVendor = 0
local reagentAvailableAlts = 0
reagentAvailable, reagentCraftable, reagentCraftableVendor = self:GetInventory(player, reagentID)
if reagentCraftable == 0 then
reagentCraftable, reagentCraftableVendor = self:InventoryReagentCraftability(reagentID)
end
for alt in pairs(self.db.realm.inventoryData) do
if alt ~= player and self.db.realm.faction[alt] == faction then
local altBoth = self:GetInventory(alt, reagentID)
reagentAvailableAlts = reagentAvailableAlts + altBoth
end
end
if Skillet.db.profile.use_guildbank_as_alt then
local guildName = GetGuildInfo("player")
local cachedGuildbank = Skillet.db.global.cachedGuildbank
if guildName and cachedGuildbank[guildName] then
if type(reagentID) ~= "table" then
reagentAvailableAlts = reagentAvailableAlts + (cachedGuildbank[guildName][reagentID] or 0)
elseif type(reagentID) == "table" then
for i=1,#reagentID do
reagentAvailableAlts = reagentAvailableAlts + (cachedGuildbank[guildName][reagentID[i].itemID] or 0)
end
end
end
end
if type(reagentID) ~= "table" and self:VendorSellsReagent(reagentID) then -- if it's available from a vendor, then only worry about bag inventory
local vendorAvailable, vendorAvailableAlts = Skillet:VendorItemAvailable(reagentID)
numCraft = math.min(numCraft, math.floor(reagentAvailable/numNeeded))
numCraftable = math.min(numCraftable, math.floor((reagentAvailable+reagentCraftable)/numNeeded))
numCraftVendor = math.min(numCraftVendor, math.floor(vendorAvailable/numNeeded))
numCraftAlts = math.min(numCraftAlts, math.floor(vendorAvailableAlts/numNeeded))
else
vendorOnly = false
numCraft = math.min(numCraft, math.floor(reagentAvailable/numNeeded))
numCraftable = math.min(numCraftable, math.floor((reagentAvailable+reagentCraftable)/numNeeded))
numCraftableVendor = math.min(numCraftableVendor, math.floor((reagentAvailable+reagentCraftableVendor)/numNeeded))
numCraftVendor = math.min(numCraftVendor, numCraftableVendor)
numCraftAlts = math.min(numCraftAlts, math.floor(reagentAvailableAlts/numNeeded))
end
end --for
recipe.vendorOnly = vendorOnly
if numCraftable == numCraftVendor then
numCraftVendor = 0 -- only keep vendor count if different
end
if numCraft == numCraftable then
numCraftable = 0 -- only keep craftable count if different
end
--DA.DEBUG(1," SkillIterations: recipeID= "..tostring(recipeID).."("..tostring(recipe.name)..") numCraft= "..tostring(numCraft)..", numCraftable= "..tostring(numCraftable)..", numCraftVendor= "..tostring(numCraftVendor)..", numCraftAlts= "..tostring(numCraftAlts))
return numCraft * numMade, numCraftable * numMade, numCraftVendor * numMade, numCraftAlts * numMade
else
--DA.DEBUG(1," SkillIterations: recipeID= "..tostring(recipeID).."("..tostring(recipe.name)..") has no reagent data")
end
return 0, 0, 0, 0
end
function Skillet:InventoryScan()
--DA.DEBUG(0,"InventoryScan()")
local player = self.currentPlayer
if self.linkedSkill or self.isGuild or player ~= UnitName("player") then
return
end
local cachedInventory = self.db.realm.inventoryData[player]
if not cachedInventory then
cachedInventory = {}
end
local inventoryData = {}
local reagent
local numInBoth
if self.db.global.itemRecipeUsedIn then
for reagentID in pairs(self.db.global.itemRecipeUsedIn) do
--DA.DEBUG(2,"reagent "..tostring(C_Item.GetItemInfo(reagentID)).." "..tostring(inventoryData[reagentID]))
if reagentID and not inventoryData[reagentID] then -- have we calculated this one yet?
--DA.DEBUG(2,"Using API")
numInBoth = C_Item.GetItemCount(reagentID,true,false,true,true) -- both bank and bags
inventoryData[reagentID] = tostring(numInBoth) -- only what we have for now (no craftability info)
--DA.DEBUG(2,"inventoryData["..reagentID.."]="..inventoryData[reagentID])
end
end
end
self.visited = {} -- this is a simple infinite loop avoidance scheme: basically, don't visit the same node twice
if inventoryData then
--
-- now calculate the craftability of these same reagents
--
for reagentID,inventory in pairs(inventoryData) do
local numCrafted, numCraftedVendor = self:InventoryReagentCraftability(reagentID)
if numCraftedVendor > 0 then
inventoryData[reagentID] = tostring(inventoryData[reagentID]).." "..tostring(numCrafted).." "..tostring(numCraftedVendor)
end
end
--
-- remove any reagents that don't show up in our inventory
--
for reagentID,inventory in pairs(inventoryData) do
if inventoryData[reagentID] == 0 or inventoryData[reagentID] == "0" or inventoryData[reagentID] == "0 0" or inventoryData[reagentID] == "0 0 0" then
inventoryData[reagentID] = nil
cachedInventory[reagentID] = nil
else
cachedInventory[reagentID] = inventoryData[reagentID]
end
end
end
--DA.DEBUG(0,"InventoryScan: return")
end
function Skillet:GetInventory(player, reagentID)
--DA.DEBUG(0,"GetInventory("..tostring(player)..", "..tostring(reagentID)..")")
if player and reagentID then
local have = 0
local make = 0
local wven = 0
local found = false
if self.db.realm.inventoryData[player] then
if type(reagentID) ~= "table" then
if self.db.realm.inventoryData[player][reagentID] then
found = true
--DA.DEBUG(1,"GetInventory: reagentID= "..tostring(reagentID)..", inventoryData= "..tostring(self.db.realm.inventoryData[player][reagentID]))
have, make, wven = string.split(" ", self.db.realm.inventoryData[player][reagentID])
end
else
--DA.DEBUG(2,"GetInventory(I): #reagentID= "..tostring(#reagentID)..", reagentID= "..DA.DUMP1(reagentID))
for i = 1, #reagentID do
if self.db.realm.inventoryData[player][reagentID[i].itemID] then
found = true
--DA.DEBUG(2,"GetInventory: itemID= "..tostring(reagentID[i].itemID)..", inventoryData= "..tostring(self.db.realm.inventoryData[player][reagentID[i].itemID]))
local h, m, v = string.split(" ", self.db.realm.inventoryData[player][reagentID[i].itemID])
have = have + (tonumber(h) or 0)
make = make + (tonumber(m) or 0)
wven = wven + (tonumber(v) or 0)
end
end
end
if found then
return tonumber(have) or 0, tonumber(make) or 0, tonumber(wven) or 0
end
end
if player == self.currentPlayer then
if type(reagentID) ~= "table" then
have = C_Item.GetItemCount(reagentID,true,false,true,true) or 0
else
--DA.DEBUG(2,"GetInventory(C): #reagentID= "..tostring(#reagentID)..", reagentID= "..DA.DUMP1(reagentID))
for i = 1, #reagentID do
--DA.DEBUG(2,"GetInventory: itemID= "..tostring(reagentID[i].itemID))
have = have + (C_Item.GetItemCount(reagentID[i].itemID,true,false,true,true) or 0)
end
end
return have, 0, 0
end
end
return 0, 0, 0 -- have, make, make with vendor
end
--
-- queries for vendor info for a particular itemID
--
function Skillet:VendorSellsReagent(itemID)
--DA.DEBUG(0,"VendorSellsReagent("..tostring(itemID)..")")
if self.db.global.MissingVendorItems[itemID] then
if type(self.db.global.MissingVendorItems[itemID]) == 'table' then
if Skillet.db.profile.use_altcurrency_vendor_items then
--DA.DEBUG(1,"VendorSellsReagent: "..tostring(itemID))
return true
end
else
--DA.DEBUG(1,"VendorSellsReagent: "..tostring(itemID))
return true
end
end
--
-- Check the LibPeriodicTable data next
--
if PT then
if itemID~=0 and PT:ItemInSet(itemID,"Tradeskill.Mat.BySource.Vendor") then
--DA.DEBUG(1,"VendorSellsReagent: "..tostring(itemID))
return true
end
end
return false
end
--
-- returns the number of items that can be bought limited by the amount of currency available
--
function Skillet:VendorItemAvailable(itemID)
--DA.DEBUG(0,"VendorItemAvailable("..tostring(itemID)..")")
local _, divider, currency
local currencyAvailable = 0
local currencyAvailableAlts = 0
if self.SpecialVendorItems[itemID] then
divider = self.SpecialVendorItems[itemID][1]
currency = self.SpecialVendorItems[itemID][2]
currencyAvailable = self:GetInventory(self.currentPlayer, currency)
for alt in pairs(self.db.realm.inventoryData) do
if alt ~= self.currentPlayer then
local altBoth = self:GetInventory(alt, currency)
currencyAvailableAlts = currencyAvailableAlts + (altBoth or 0)
end
end
return math.floor(currencyAvailable / divider), math.floor(currencyAvailableAlts / divider)
elseif self.db.global.MissingVendorItems[itemID] then
local MissingVendorItem = self.db.global.MissingVendorItems[itemID]
if type(MissingVendorItem) == 'table' then -- table entries are {name, quantity, currencyName, currencyID, currencyCount}
if Skillet.db.profile.use_altcurrency_vendor_items then
--DA.DEBUG(1,"MissingVendorItem="..DA.DUMP1(MissingVendorItem))
if MissingVendorItem[4] > 0 then
currencyAvailable = self:GetInventory(self.currentPlayer, MissingVendorItem[4])
else
local cinfo = C_CurrencyInfo.GetCurrencyInfo(-1 * MissingVendorItem[4])
if cinfo then
--DA.DEBUG(1,"cinfo="..DA.DUMP1(cinfo))
currencyAvailable = cinfo.quantity
end
end
--DA.DEBUG(1,"currencyAvailable="..tostring(currencyAvailable))
--
-- compute how many this player can buy with alternate currency and return 0 for alts
--
return math.floor(MissingVendorItem[2] * currencyAvailable / (MissingVendorItem[5] or 1)), 0
else
return 0, 0 -- vendor sells item for an alternate currency and we are ignoring it.
end
else
return 100000, 100000 -- vendor sells item for gold, price is not available so assume lots of gold
end
else
return 100000, 100000 -- vendor sells item for gold, price is not available so assume lots of gold
end
end