vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | --[[ |
2 | Enchantrix Addon for World of Warcraft(tm). |
||
3 | Version: 3.6.1 (Platypus) |
||
4 | Revision: $Id: EnxStorage.lua 899 2006-06-05 11:03:30Z aradan $ |
||
5 | |||
6 | Database functions and saved variables. |
||
7 | |||
8 | License: |
||
9 | This program is free software; you can redistribute it and/or |
||
10 | modify it under the terms of the GNU General Public License |
||
11 | as published by the Free Software Foundation; either version 2 |
||
12 | of the License, or (at your option) any later version. |
||
13 | |||
14 | This program is distributed in the hope that it will be useful, |
||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
17 | GNU General Public License for more details. |
||
18 | |||
19 | You should have received a copy of the GNU General Public License |
||
20 | along with this program(see GLP.txt); if not, write to the Free Software |
||
21 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
22 | ]] |
||
23 | |||
24 | -- Global functions |
||
25 | local addonLoaded -- Enchantrix.Storage.AddonLoaded() |
||
26 | local saveDisenchant -- Enchantrix.Storage.SaveDisenchant() |
||
27 | local getItemDisenchants -- Enchantrix.Storage.GetItemDisenchants() |
||
28 | |||
29 | -- Local functions |
||
30 | local unserialize |
||
31 | local serialize |
||
32 | local mergeDisenchant |
||
33 | local normalizeDisenchant |
||
34 | local cleanupDisenchant |
||
35 | local disenchantTotal |
||
36 | local disenchantListHash |
||
37 | local mergeDisenchantLists |
||
38 | local saveLocal |
||
39 | local getLocal |
||
40 | |||
41 | -- Database |
||
42 | local LocalBaseItems = {} -- EnchantedLocal merged by item id |
||
43 | local EnchantedItemTypes = {} -- LocalBaseItems and EnchantedBaseItems merged by type |
||
44 | |||
45 | local N_DISENCHANTS = 1 |
||
46 | local N_REAGENTS = 2 |
||
47 | |||
48 | Enchantrix.State.MAX_ITEM_ID = 26000 |
||
49 | |||
50 | local const = Enchantrix.Constants |
||
51 | |||
52 | function addonLoaded() |
||
53 | -- Create and setup saved variables |
||
54 | if not EnchantConfig then EnchantConfig = {} end |
||
55 | if not EnchantConfig.filters then EnchantConfig.filters = {} end |
||
56 | if not EnchantConfigChar then EnchantConfigChar = {} end |
||
57 | if not EnchantConfigChar.filters then EnchantConfigChar.filters = {} end |
||
58 | |||
59 | if not EnchantConfig.cache then EnchantConfig.cache = {} end |
||
60 | if not EnchantConfig.cache.reagentinfo then EnchantConfig.cache.reagentinfo = {} end |
||
61 | if not EnchantConfig.cache.names then EnchantConfig.cache.names = {} end |
||
62 | |||
63 | if not EnchantedLocal then EnchantedLocal = {} end |
||
64 | if not EnchantedBaseItems then EnchantedBaseItems = {} end |
||
65 | |||
66 | if not EnchantConfig.zomgBlizzardAreMeanies then |
||
67 | -- Push disenchant reagents into cache if needed |
||
68 | for id in Enchantrix.Constants.StaticPrices do |
||
69 | if not (Enchantrix.Util.GetReagentInfo(id)) then |
||
70 | EnchantConfig.zomgBlizzardAreMeanies = true |
||
71 | GameTooltip:SetHyperlink(string.format("item:%d:0:0:0", id)) |
||
72 | GameTooltip:Hide() |
||
73 | EnchantConfig.zomgBlizzardAreMeanies = nil |
||
74 | end |
||
75 | end |
||
76 | else |
||
77 | -- We were kicked from the server last time, better not try that again for a while |
||
78 | EnchantConfig.zomgBlizzardAreMeanies = nil |
||
79 | end |
||
80 | |||
81 | mergeDisenchantLists() |
||
82 | end |
||
83 | |||
84 | function unserialize(str) |
||
85 | -- Break up a disenchant string to a table for easy manipulation |
||
86 | local tbl = {} |
||
87 | if type(str) == "string" then |
||
88 | for de in Enchantrix.Util.Spliterator(str, ";") do |
||
89 | local _, _, id, d, r = string.find(de, "(%d+):(%d+):(%d+)") |
||
90 | id, d, r = tonumber(id), tonumber(d), tonumber(r) |
||
91 | if (id and d > 0 and r > 0) then |
||
92 | tbl[id] = {[N_DISENCHANTS] = d, [N_REAGENTS] = r} |
||
93 | end |
||
94 | end |
||
95 | end |
||
96 | return tbl |
||
97 | end |
||
98 | |||
99 | function serialize(tbl) |
||
100 | -- Serialize a table into a string |
||
101 | if type(tbl) == "table" then |
||
102 | local str |
||
103 | for id, counts in pairs(tbl) do |
||
104 | if (type(id) == "number" and counts[N_DISENCHANTS] > 0 and counts[N_REAGENTS] > 0) then |
||
105 | if (str) then |
||
106 | str = string.format("%s;%d:%d:%d:0", str, id, counts[N_DISENCHANTS], counts[N_REAGENTS]) |
||
107 | else |
||
108 | str = string.format("%d:%d:%d:0", id, counts[N_DISENCHANTS], counts[N_REAGENTS]) |
||
109 | end |
||
110 | end |
||
111 | end |
||
112 | return str |
||
113 | end |
||
114 | end |
||
115 | |||
116 | function mergeDisenchant(str1, str2) |
||
117 | -- Merge two disenchant strings into a single string |
||
118 | local tbl1, tbl2 = unserialize(str1), unserialize(str2) |
||
119 | for id, counts in pairs(tbl2) do |
||
120 | if (not tbl1[id]) then |
||
121 | tbl1[id] = counts |
||
122 | else |
||
123 | tbl1[id][N_DISENCHANTS] = tbl1[id][N_DISENCHANTS] + counts[N_DISENCHANTS] |
||
124 | tbl1[id][N_REAGENTS] = tbl1[id][N_REAGENTS] + counts[N_REAGENTS] |
||
125 | end |
||
126 | end |
||
127 | return serialize(tbl1) |
||
128 | end |
||
129 | |||
130 | function normalizeDisenchant(str) |
||
131 | -- Divide all counts in disenchant string by gcd |
||
132 | local div = 0 |
||
133 | local count = 0 |
||
134 | local tbl = unserialize(str) |
||
135 | for id, counts in pairs(tbl) do |
||
136 | div = Enchantrix.Util.GCD(div, counts[N_DISENCHANTS]) |
||
137 | div = Enchantrix.Util.GCD(div, counts[N_REAGENTS]) |
||
138 | count = count + 1 |
||
139 | end |
||
140 | -- Only normalize if there's more than one kind of reagent |
||
141 | if count > 1 then |
||
142 | for id, counts in pairs(tbl) do |
||
143 | counts[N_DISENCHANTS] = counts[N_DISENCHANTS] / div |
||
144 | counts[N_REAGENTS] = counts[N_REAGENTS] / div |
||
145 | end |
||
146 | return serialize(tbl) |
||
147 | end |
||
148 | return str |
||
149 | end |
||
150 | |||
151 | function cleanupDisenchant(str, id) |
||
152 | -- Remove reagents that don't appear in level rules table |
||
153 | if (type(str) == "string") and (id ~= nil) then |
||
154 | local _, _, quality, level, _, _, _, equip = GetItemInfo(id) |
||
155 | local itype = const.InventoryTypes[equip] |
||
156 | if quality and itype then |
||
157 | local tbl = unserialize(str) |
||
158 | local clean = {} |
||
159 | level = Enchantrix.Util.RoundUp(level, 5) |
||
160 | for id, counts in pairs(tbl) do |
||
161 | if const.LevelRules[itype][level][id] then |
||
162 | if quality == 2 then |
||
163 | -- Uncommon item, remove nexus crystal |
||
164 | if (const.LevelRules[itype][level][id] < const.CRYSTAL) then |
||
165 | clean[id] = counts |
||
166 | end |
||
167 | else |
||
168 | -- Rare or epic item, remove dusts and essences |
||
169 | if (const.LevelRules[itype][level][id] > const.ESSENCE_GREATER) then |
||
170 | clean[id] = counts |
||
171 | end |
||
172 | end |
||
173 | end |
||
174 | end |
||
175 | return serialize(clean) |
||
176 | end |
||
177 | end |
||
178 | return str |
||
179 | end |
||
180 | |||
181 | function disenchantTotal(str) |
||
182 | -- Return total number of disenchants |
||
183 | local tot = 0 |
||
184 | local tbl = unserialize(str) |
||
185 | for id in tbl do |
||
186 | tot = tot + tbl[id][N_DISENCHANTS] |
||
187 | end |
||
188 | return tot |
||
189 | end |
||
190 | |||
191 | function disenchantListHash() |
||
192 | -- Generate a hash for DisenchantList |
||
193 | local hash = 1 |
||
194 | local id |
||
195 | for sig, val in pairs(DisenchantList) do |
||
196 | id = Enchantrix.Util.GetItemIdFromSig(sig) |
||
197 | Enchantrix.State.MAX_ITEM_ID = math.max(Enchantrix.State.MAX_ITEM_ID, id or 0) |
||
198 | hash = math.mod(3 * hash + 2 * (id or 0) + string.len(val), 16777216) |
||
199 | end |
||
200 | return hash |
||
201 | end |
||
202 | |||
203 | function mergeDisenchantLists() |
||
204 | -- Merge DisenchantList by base item, i.e. all "Foobar of <x>" are merged into "Foobar" |
||
205 | -- This can be rather time consuming so we store this in a saved variable and use a hash |
||
206 | -- signature to determine if we need to update the table |
||
207 | local hash = disenchantListHash() |
||
208 | if (not EnchantedBaseItems.hash) then |
||
209 | EnchantedBaseItems.hash = -hash |
||
210 | end |
||
211 | if (EnchantedBaseItems.hash ~= hash) then |
||
212 | -- Hash has changed, update EnchantedBaseItems |
||
213 | EnchantedBaseItems = {} |
||
214 | for sig, disenchant in pairs(DisenchantList) do |
||
215 | local item = Enchantrix.Util.GetItemIdFromSig(sig) |
||
216 | if (Enchantrix.Util.IsDisenchantable(item)) then |
||
217 | EnchantedBaseItems[item] = mergeDisenchant(EnchantedBaseItems[item], |
||
218 | normalizeDisenchant(disenchant)) |
||
219 | end |
||
220 | end |
||
221 | EnchantedBaseItems.hash = hash |
||
222 | end |
||
223 | |||
224 | -- We don't need DisenchantList anymore |
||
225 | DisenchantList = nil |
||
226 | |||
227 | -- Merge items from EnchantedLocal |
||
228 | for sig, disenchant in pairs(EnchantedLocal) do |
||
229 | local item = Enchantrix.Util.GetItemIdFromSig(sig) |
||
230 | if type(disenchant) == "table" then |
||
231 | saveLocal(sig, disenchant) |
||
232 | disenchant = EnchantedLocal[sig] |
||
233 | end |
||
234 | if Enchantrix.Util.IsDisenchantable(item) and (type(disenchant) == "string") then |
||
235 | LocalBaseItems[item] = mergeDisenchant(LocalBaseItems[item], disenchant) |
||
236 | end |
||
237 | end |
||
238 | |||
239 | -- Merge by item type |
||
240 | for id, disenchant in pairs(EnchantedBaseItems) do |
||
241 | local itype = Enchantrix.Util.GetItemType(id) |
||
242 | if itype then |
||
243 | EnchantedItemTypes[itype] = mergeDisenchant(EnchantedItemTypes[itype], disenchant) |
||
244 | end |
||
245 | end |
||
246 | for id, disenchant in pairs(LocalBaseItems) do |
||
247 | local itype = Enchantrix.Util.GetItemType(id) |
||
248 | if itype then |
||
249 | EnchantedItemTypes[itype] = mergeDisenchant(EnchantedItemTypes[itype], disenchant) |
||
250 | end |
||
251 | end |
||
252 | |||
253 | -- Take out the trash |
||
254 | collectgarbage() |
||
255 | end |
||
256 | |||
257 | function saveDisenchant(sig, reagentID, count) |
||
258 | -- Update tables after a disenchant has been detected |
||
259 | assert(type(sig) == "string"); assert(tonumber(reagentID)); assert(tonumber(count)) |
||
260 | |||
261 | local id = Enchantrix.Util.GetItemIdFromSig(sig) |
||
262 | local itype = Enchantrix.Util.GetItemType(id) |
||
263 | local disenchant = string.format("%d:1:%d:0", reagentID, count) |
||
264 | EnchantedLocal[sig] = mergeDisenchant(EnchantedLocal[sig], disenchant) |
||
265 | LocalBaseItems[id] = mergeDisenchant(LocalBaseItems[id], disenchant) |
||
266 | if itype then |
||
267 | EnchantedItemTypes[itype] = mergeDisenchant(EnchantedItemTypes[itype], disenchant) |
||
268 | end |
||
269 | end |
||
270 | |||
271 | function saveLocal(sig, lData) |
||
272 | local str = ""; |
||
273 | for eResult, eData in lData do |
||
274 | eResult = tonumber(eResult) |
||
275 | if not eResult then |
||
276 | return |
||
277 | end |
||
278 | if (eData and type(eData) == "table") then |
||
279 | local iCount = tonumber(eData.i) or 0; |
||
280 | local dCount = tonumber(eData.d) or 0; |
||
281 | local oCount = tonumber(eData.o) or 0; |
||
282 | local serial = string.format("%d:%d:%d:%d", eResult, iCount, dCount, oCount); |
||
283 | if (str == "") then str = serial else str = str..";"..serial end |
||
284 | else |
||
285 | eData = nil; |
||
286 | end |
||
287 | end |
||
288 | EnchantedLocal[sig] = str; |
||
289 | end |
||
290 | |||
291 | function getLocal(sig) |
||
292 | local enchantItem = {}; |
||
293 | if (EnchantedLocal and EnchantedLocal[sig]) then |
||
294 | if (type(EnchantedLocal[sig]) == "table") then |
||
295 | -- Time to convert it into the new serialized format |
||
296 | saveLocal(sig, EnchantedLocal[sig]); |
||
297 | end |
||
298 | |||
299 | -- Get the string and break it apart |
||
300 | for enchantResult in Enchantrix.Util.Spliterator(EnchantedLocal[sig], ";") do |
||
301 | local enchantBreak = Enchantrix.Util.Split(enchantResult, ":"); |
||
302 | local rSig = tonumber(enchantBreak[1]) or 0; |
||
303 | local iCount = tonumber(enchantBreak[2]) or 0; |
||
304 | local dCount = tonumber(enchantBreak[3]) or 0; |
||
305 | local oCount = tonumber(enchantBreak[4]) or 0; |
||
306 | |||
307 | enchantItem[rSig] = { i=iCount, d=dCount, o=oCount }; |
||
308 | end |
||
309 | end |
||
310 | return enchantItem; |
||
311 | end |
||
312 | |||
313 | function getItemDisenchants(sig, name, useCache) |
||
314 | local disenchantsTo = {}; |
||
315 | |||
316 | if (not Enchantrix.Storage.Price_Cache) or (time()-Enchantrix.Storage.Price_Cache.t > 300) then |
||
317 | Enchantrix.Storage.Price_Cache = {t=time()}; |
||
318 | end |
||
319 | |||
320 | -- Automatically convert any named EnchantedLocal items to new items |
||
321 | if (name and EnchantedLocal[name]) then |
||
322 | local iData = getLocal(name) |
||
323 | for dName, count in iData do |
||
324 | local link = Enchantrix.Util.GetLinkFromName(dName); |
||
325 | local dSig = Enchantrix.Util.GetItemIdFromLink(link) |
||
326 | if (dSig ~= nil) then |
||
327 | if (not iData[dSig]) then iData[dSig] = {}; end |
||
328 | local oCount = tonumber(iData[dSig].o); |
||
329 | if (oCount == nil) then oCount = 0; end |
||
330 | iData[dSig].o = ""..count; |
||
331 | end |
||
332 | end |
||
333 | EnchantedLocal[name] = nil; |
||
334 | saveLocal(sig, iData); |
||
335 | end |
||
336 | |||
337 | local item = Enchantrix.Util.GetItemIdFromSig(sig) |
||
338 | if (not (item and Enchantrix.Util.IsDisenchantable(item))) then |
||
339 | -- Item is not disenchantable |
||
340 | return {} |
||
341 | end |
||
342 | |||
343 | -- If there is data, then work out the disenchant data |
||
344 | if (EnchantedBaseItems[item] or LocalBaseItems[item]) then |
||
345 | local biTotal = 0; |
||
346 | local bdTotal = 0; |
||
347 | local iTotal = 0; |
||
348 | local dTotal = 0; |
||
349 | |||
350 | local baseDisenchant = EnchantedBaseItems[item] |
||
351 | |||
352 | local itype = Enchantrix.Util.GetItemType(item) |
||
353 | if (itype and EnchantedItemTypes[itype]) then |
||
354 | if (disenchantTotal(EnchantedItemTypes[itype]) > disenchantTotal(baseDisenchant)) then |
||
355 | baseDisenchant = EnchantedItemTypes[itype] |
||
356 | end |
||
357 | end |
||
358 | |||
359 | baseDisenchant = cleanupDisenchant(baseDisenchant, item) |
||
360 | |||
361 | if (baseDisenchant) then |
||
362 | -- Base Disenchantments are now serialized |
||
363 | local baseResults = unserialize(baseDisenchant) |
||
364 | for dSig, counts in pairs(baseResults) do |
||
365 | if (dSig > 0) then |
||
366 | disenchantsTo[dSig] = { |
||
367 | biCount = counts[N_DISENCHANTS], |
||
368 | bdCount = counts[N_REAGENTS], |
||
369 | iCount = 0, |
||
370 | dCount = 0, |
||
371 | } |
||
372 | biTotal = biTotal + counts[N_DISENCHANTS] |
||
373 | bdTotal = bdTotal + counts[N_REAGENTS] |
||
374 | end |
||
375 | end |
||
376 | end |
||
377 | |||
378 | if (LocalBaseItems[item]) then |
||
379 | local enchantedLocal = unserialize(LocalBaseItems[item]) |
||
380 | for dSig, counts in pairs(enchantedLocal) do |
||
381 | if (dSig and dSig > 0) then |
||
382 | if (not disenchantsTo[dSig]) then |
||
383 | disenchantsTo[dSig] = {biCount = 0, bdCount = 0, iCount = 0, dCount = 0} |
||
384 | end |
||
385 | disenchantsTo[dSig].dCount = counts[N_REAGENTS] |
||
386 | disenchantsTo[dSig].iCount = counts[N_DISENCHANTS] |
||
387 | |||
388 | dTotal = dTotal + counts[N_REAGENTS] |
||
389 | iTotal = iTotal + counts[N_DISENCHANTS] |
||
390 | end |
||
391 | end |
||
392 | end |
||
393 | |||
394 | local total = biTotal + iTotal; |
||
395 | |||
396 | local hspGuess = 0; |
||
397 | local medianGuess = 0; |
||
398 | local marketGuess = 0; |
||
399 | if (total > 0) then |
||
400 | for dSig, counts in pairs(disenchantsTo) do |
||
401 | local item = 0; |
||
402 | if (dSig) then item = tonumber(dSig); end |
||
403 | local dName = Enchantrix.Util.GetReagentInfo(item); |
||
404 | if (not dName) then dName = "Item "..dSig; end |
||
405 | local count = (counts.biCount or 0) + (counts.iCount or 0); |
||
406 | local countI = (counts.biCount or 0) + (counts.iCount or 0); |
||
407 | local countD = (counts.bdCount or 0) + (counts.dCount or 0); |
||
408 | local pct = tonumber(string.format("%0.1f", count / total * 100)); |
||
409 | local rate |
||
410 | if (countI > 0) then |
||
411 | rate = countD / countI |
||
412 | end |
||
413 | |||
414 | local count = 1; |
||
415 | if (rate and rate > 0) then count = rate; end |
||
416 | disenchantsTo[dSig].name = dName; |
||
417 | disenchantsTo[dSig].pct = pct; |
||
418 | disenchantsTo[dSig].rate = count; |
||
419 | |||
420 | local hsp, med, mkt = Enchantrix.Util.GetReagentPrice(item) |
||
421 | |||
422 | local hspValue = (hsp or 0) * pct * count / 100 |
||
423 | local medValue = (med or 0) * pct * count / 100 |
||
424 | local mktValue = (mkt or 0) * pct * count / 100 |
||
425 | |||
426 | disenchantsTo[dSig].hspValue = hspValue; |
||
427 | disenchantsTo[dSig].medValue = medValue; |
||
428 | disenchantsTo[dSig].mktValue = mktValue; |
||
429 | |||
430 | hspGuess = hspGuess + hspValue; |
||
431 | medianGuess = medianGuess + medValue; |
||
432 | marketGuess = marketGuess + mktValue; |
||
433 | end |
||
434 | end |
||
435 | |||
436 | local confidence = math.log(math.min(total, 19)+1)/3; |
||
437 | |||
438 | disenchantsTo.totals = {}; |
||
439 | disenchantsTo.totals.hspValue = hspGuess or 0; |
||
440 | disenchantsTo.totals.medValue = medianGuess or 0; |
||
441 | disenchantsTo.totals.mktValue = marketGuess or 0; |
||
442 | disenchantsTo.totals.biCount = biTotal or 0; |
||
443 | disenchantsTo.totals.bdCount = bdTotal or 0; |
||
444 | disenchantsTo.totals.dCount = dTotal or 0; |
||
445 | disenchantsTo.totals.iCount = iTotal or 0; |
||
446 | disenchantsTo.totals.total = total or 0; |
||
447 | disenchantsTo.totals.conf = confidence or 0; |
||
448 | end |
||
449 | |||
450 | return disenchantsTo; |
||
451 | end |
||
452 | |||
453 | Enchantrix.Storage = { |
||
454 | Revision = "$Revision: 899 $", |
||
455 | AddonLoaded = addonLoaded, |
||
456 | |||
457 | GetItemDisenchants = getItemDisenchants, |
||
458 | SaveDisenchant = saveDisenchant, |
||
459 | } |