Mercurial > wow > itemauditor
comparison Core.lua @ 0:169f5211fc7f
First public revision.
At this point ItemAuditor watches mail for auctions sold or purchased, watches for buy/sell (money and 1 item type change) and conversions/tradeskills. Milling isn't working yet because there is too much time between the first event and the last event.
| author | Asa Ayers <Asa.Ayers@Gmail.com> |
|---|---|
| date | Thu, 20 May 2010 19:22:19 -0700 |
| parents | |
| children | 6c87720c301c |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:169f5211fc7f |
|---|---|
| 1 local addon = LibStub("AceAddon-3.0"):NewAddon("ItemAuditor", "AceConsole-3.0", "AceEvent-3.0", "AceBucket-3.0") | |
| 2 | |
| 3 ItemAuditor = addon | |
| 4 | |
| 5 local WHITE = "|cFFFFFFFF" | |
| 6 local RED = "|cFFFF0000" | |
| 7 local GREEN = "|cFF00FF00" | |
| 8 local YELLOW = "|cFFFFFF00" | |
| 9 local ORANGE = "|cFFFF7F00" | |
| 10 local TEAL = "|cFF00FF9A" | |
| 11 local GOLD = "|cFFFFD700" | |
| 12 | |
| 13 function addon:OnInitialize() | |
| 14 -- declare defaults to be used in the DB | |
| 15 local DB_defaults = { | |
| 16 char = { | |
| 17 debug = false | |
| 18 }, | |
| 19 factionrealm = { | |
| 20 item_account = {} | |
| 21 }, | |
| 22 } | |
| 23 self.db = LibStub("AceDB-3.0"):New("ItemAuditorDB", DB_defaults, true) | |
| 24 self.db.factionrealm.backup = self.db.factionrealm.item_account | |
| 25 | |
| 26 self.db.char.debug = true | |
| 27 | |
| 28 --[[ | |
| 29 Fine Thread = 510 | |
| 30 Greater Magic Essence = 120000 | |
| 31 Simple Kilt = 5913 | |
| 32 Bolt of Linen Cloth = 5672 | |
| 33 ]] | |
| 34 | |
| 35 self:RegisterOptions() | |
| 36 | |
| 37 self:Debug("Hello, world! OnInitialize") | |
| 38 | |
| 39 self:RegisterEvent("MAIL_SHOW") | |
| 40 self:WatchBags() | |
| 41 end | |
| 42 | |
| 43 function IA_tcount(tab) | |
| 44 local n = #tab | |
| 45 if (n == 0) then | |
| 46 for _ in pairs(tab) do | |
| 47 n = n + 1 | |
| 48 end | |
| 49 end | |
| 50 return n | |
| 51 end | |
| 52 | |
| 53 | |
| 54 local options = { | |
| 55 name = "ItemAuditor", | |
| 56 handler = ItemAuditor, | |
| 57 type = 'group', | |
| 58 args = { | |
| 59 debug = { | |
| 60 type = "toggle", | |
| 61 name = "Debug", | |
| 62 desc = "Toggles debug messages in chat", | |
| 63 get = "GetDebug", | |
| 64 set = "SetDebug" | |
| 65 }, | |
| 66 dump = { | |
| 67 type = "execute", | |
| 68 name = "dump", | |
| 69 desc = "dumps IA database", | |
| 70 func = "DumpInfo", | |
| 71 }, | |
| 72 options = { | |
| 73 type = "execute", | |
| 74 name = "options", | |
| 75 desc = "Show Blizzard's options GUI", | |
| 76 func = "ShowOptionsGUI", | |
| 77 guiHidden = true, | |
| 78 }, | |
| 79 }, | |
| 80 } | |
| 81 | |
| 82 | |
| 83 function addon:DumpInfo() | |
| 84 self:Print("self.db.char") | |
| 85 DevTools_Dump(self.db.char) | |
| 86 self:Print("self.db.factionrealm") | |
| 87 DevTools_Dump(self.db.factionrealm) | |
| 88 end | |
| 89 | |
| 90 function addon:RegisterOptions() | |
| 91 self.optionsFrame = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("ItemAuditor", "ItemAuditor") | |
| 92 | |
| 93 LibStub("AceConfig-3.0"):RegisterOptionsTable("ItemAuditor", options, {"ia"}) | |
| 94 | |
| 95 self:RegisterChatCommand("fuck", "ChatCommand") | |
| 96 end | |
| 97 | |
| 98 function addon:GetMessage(info) | |
| 99 return self.message | |
| 100 end | |
| 101 | |
| 102 function addon:SetMessage(info, newValue) | |
| 103 self.message = newValue | |
| 104 end | |
| 105 | |
| 106 | |
| 107 function addon:ShowOptionsGUI() | |
| 108 InterfaceOptionsFrame_OpenToCategory(self.optionsFrame) | |
| 109 end | |
| 110 | |
| 111 function addon:GetDebug(info) | |
| 112 return self.db.char.debug | |
| 113 end | |
| 114 | |
| 115 function addon:SetDebug(info, input) | |
| 116 self.db.char.debug = input | |
| 117 local value = "off" | |
| 118 if input then | |
| 119 value = "on" | |
| 120 end | |
| 121 self:Print("Debugging is now: " .. value) | |
| 122 end | |
| 123 | |
| 124 | |
| 125 -- ================ DEBUG ================ | |
| 126 addon.OriginalRegisterEvent = addon.RegisterEvent | |
| 127 addon.OriginalUnregisterEvent = addon.UnregisterEvent | |
| 128 | |
| 129 function addon:RegisterEvent(event, callback, arg) | |
| 130 self:Debug("RegisterEvent " .. event ) | |
| 131 if arg ~= nil then | |
| 132 addon:OriginalRegisterEvent(event, callback, arg) | |
| 133 elseif callback ~= nil then | |
| 134 addon:OriginalRegisterEvent(event, callback) | |
| 135 else | |
| 136 addon:OriginalRegisterEvent(event) | |
| 137 end | |
| 138 end | |
| 139 | |
| 140 function addon:UnregisterEvent(event) | |
| 141 self:Debug("UnregisterEvent " .. event ) | |
| 142 addon:OriginalUnregisterEvent (event) | |
| 143 end | |
| 144 | |
| 145 -- ================ DEBUG ================ | |
| 146 | |
| 147 function addon:FormatMoney(money) | |
| 148 return Altoholic:GetMoneyString(money, WHITE, false) | |
| 149 end | |
| 150 | |
| 151 function addon:GetCurrentInventory() | |
| 152 local i = {} | |
| 153 local link | |
| 154 | |
| 155 for bagID = 0, NUM_BAG_SLOTS do | |
| 156 bagSize=GetContainerNumSlots(bagID) | |
| 157 for slotID = 0, bagSize do | |
| 158 itemID = GetContainerItemID(bagID, slotID); | |
| 159 | |
| 160 if itemID ~= nil then | |
| 161 _, itemCount, _, _, _= GetContainerItemInfo(bagID, slotID); | |
| 162 name = GetItemInfo(itemID) | |
| 163 if i[name] == nil then | |
| 164 i[name] = 0 | |
| 165 end | |
| 166 i[name] = i[name] + (itemCount or 0) | |
| 167 end | |
| 168 | |
| 169 end | |
| 170 | |
| 171 end | |
| 172 return {items = i, money = GetMoney()} | |
| 173 end | |
| 174 | |
| 175 function addon:GetInventoryDiff(pastInventory, current) | |
| 176 if current == nil then | |
| 177 current = self:GetCurrentInventory() | |
| 178 end | |
| 179 local diff = {} | |
| 180 | |
| 181 for name, count in pairs(current.items) do | |
| 182 if pastInventory.items[name] == nil then | |
| 183 diff[name] = count | |
| 184 self:Debug("1 diff[" .. name .. "]=" .. diff[name]) | |
| 185 elseif count - pastInventory.items[name] ~= 0 then | |
| 186 diff[name] = count - pastInventory.items[name] | |
| 187 self:Debug("2 diff[" .. name .. "]=" .. diff[name]) | |
| 188 end | |
| 189 end | |
| 190 | |
| 191 for name, count in pairs(pastInventory.items) do | |
| 192 if current.items[name] == nil then | |
| 193 diff[name] = -count | |
| 194 self:Debug("3 diff[" .. name .. "]=" .. diff[name]) | |
| 195 elseif current.items[name] - count ~= 0 then | |
| 196 diff[name] = current.items[name] - pastInventory.items[name] | |
| 197 self:Debug("4 diff[" .. name .. "]=" .. diff[name]) | |
| 198 end | |
| 199 end | |
| 200 | |
| 201 local moneyDiff = current.money - pastInventory.money | |
| 202 | |
| 203 return {items = diff, money = moneyDiff} | |
| 204 end | |
| 205 | |
| 206 | |
| 207 function addon:ScanMail() | |
| 208 local results = {} | |
| 209 for mailIndex = 1, GetInboxNumItems() or 0 do | |
| 210 local sender, msgSubject, msgMoney, msgCOD, _, msgItem, _, _, msgText, _, isGM = select(3, GetInboxHeaderInfo(mailIndex)) | |
| 211 local mailType = Postal:GetMailType(msgSubject) | |
| 212 | |
| 213 if mailType == "NonAHMail" then | |
| 214 -- Don't know how to handle these yet | |
| 215 elseif mailType == "AHSuccess" then | |
| 216 local invoiceType, itemName, playerName, bid, buyout, deposit, consignment = GetInboxInvoiceInfo(mailIndex); | |
| 217 if results[itemName] == nil then | |
| 218 results[itemName] = 0 | |
| 219 end | |
| 220 results[itemName] = results[itemName] + deposit + buyout - consignment | |
| 221 | |
| 222 elseif mailType == "AHWon" then | |
| 223 local invoiceType, itemName, playerName, bid, buyout, deposit, consignment = GetInboxInvoiceInfo(mailIndex); | |
| 224 if results[itemName] == nil then | |
| 225 results[itemName] = 0 | |
| 226 end | |
| 227 results[itemName] = results[itemName] - bid | |
| 228 elseif mailType == "AHExpired" or mailType == "AHCancelled" then | |
| 229 -- These should be handled when you pay the deposit at the AH | |
| 230 else | |
| 231 self:Debug("Unhandled mail type: " .. mailType) | |
| 232 self:Debug(msgSubject) | |
| 233 end | |
| 234 | |
| 235 end | |
| 236 return results | |
| 237 end | |
| 238 | |
| 239 function addon:MAIL_SHOW() | |
| 240 self:Debug("MAIL_SHOW") | |
| 241 self.lastMailScan = self:ScanMail() | |
| 242 self:UnregisterEvent("MAIL_SHOW") | |
| 243 self:RegisterEvent("MAIL_CLOSED") | |
| 244 self:RegisterEvent("MAIL_INBOX_UPDATE") | |
| 245 self:Debug("MAIL_SHOW complete") | |
| 246 -- the mail scanner will handle everything | |
| 247 -- self:UnwatchBags() | |
| 248 end | |
| 249 | |
| 250 function addon:MAIL_CLOSED() | |
| 251 addon:UnregisterEvent("MAIL_CLOSED") | |
| 252 self:UnregisterEvent("MAIL_INBOX_UPDATE") | |
| 253 self:RegisterEvent("MAIL_SHOW") | |
| 254 -- self:WatchBags() | |
| 255 end | |
| 256 | |
| 257 function addon:MAIL_INBOX_UPDATE() | |
| 258 local newScan = addon:ScanMail() | |
| 259 local diff | |
| 260 for item, total in pairs(self.lastMailScan) do | |
| 261 | |
| 262 if newScan[item] == nil then | |
| 263 newScan[item] = 0 | |
| 264 end | |
| 265 diff = total - newScan[item] | |
| 266 if diff ~= 0 then | |
| 267 self:SaveValue(item, diff) | |
| 268 end | |
| 269 | |
| 270 end | |
| 271 | |
| 272 self.lastMailScan = newScan | |
| 273 end | |
| 274 | |
| 275 function addon:SaveValue(item, value) | |
| 276 local item_account = self.db.factionrealm.item_account | |
| 277 if item_account[item] == nil then | |
| 278 item_account[item] = 0 | |
| 279 end | |
| 280 item_account[item] = item_account[item] + value | |
| 281 | |
| 282 if item_account[item] >= 0 then | |
| 283 item_account[item] = nil | |
| 284 end | |
| 285 end | |
| 286 | |
| 287 function addon:OnEnable() | |
| 288 self:Debug("Hello, world! OnEnable") | |
| 289 end | |
| 290 | |
| 291 function addon:Debug(msg) | |
| 292 if self.db.char.debug then | |
| 293 self:Print(msg) | |
| 294 end | |
| 295 end | |
| 296 | |
| 297 function addon:WatchBags() | |
| 298 if self.watch_handle == nil then | |
| 299 self.lastInventory = self:GetCurrentInventory() | |
| 300 self.watch_handle = self:RegisterBucketEvent({"BAG_UPDATE", "PLAYER_MONEY"}, 0.2, "UpdateAudit") | |
| 301 end | |
| 302 end | |
| 303 | |
| 304 function addon:UnwatchBags() | |
| 305 if self.watch_handle ~= nil then | |
| 306 self:UnregisterBucket(self.watch_handle) | |
| 307 self.watch_handle = nil | |
| 308 end | |
| 309 end | |
| 310 | |
| 311 function addon:UpdateAudit() | |
| 312 self:Debug("UpdateAudit") | |
| 313 local currentInventory = self:GetCurrentInventory() | |
| 314 local diff = addon:GetInventoryDiff(self.lastInventory, currentInventory) | |
| 315 -- this is only here for debugging | |
| 316 self.lastdiff = diff | |
| 317 | |
| 318 if abs(diff.money) > 0 and IA_tcount(diff.items) == 1 then | |
| 319 self:Debug("purchase or sale") | |
| 320 | |
| 321 for itemName, count in pairs(diff.items) do | |
| 322 self:SaveValue(itemName, diff.money) | |
| 323 end | |
| 324 elseif IA_tcount(diff.items) > 1 then | |
| 325 local positive, negative = {}, {} | |
| 326 local positiveCount, negativeCount = 0, 0 | |
| 327 for item, count in pairs(diff.items) do | |
| 328 if count > 0 then | |
| 329 positive[item] = count | |
| 330 positiveCount = positiveCount + count | |
| 331 elseif count < 0 then | |
| 332 negative[item] = count | |
| 333 negativeCount = negativeCount + abs(count) | |
| 334 end | |
| 335 end | |
| 336 | |
| 337 if IA_tcount(positive) > 0 and IA_tcount(negative) > 0 then | |
| 338 -- we must have created/converted something | |
| 339 self:Debug("conversion") | |
| 340 local totalChange = 0 | |
| 341 for itemName, change in pairs(negative) do | |
| 342 local _, itemCost, count = self:GetItemCost(itemName, change) | |
| 343 self:SaveValue(itemName, abs(itemCost * change)) | |
| 344 | |
| 345 totalChange = totalChange + abs(itemCost * change) | |
| 346 end | |
| 347 | |
| 348 self:Debug("totalChange") | |
| 349 self:Debug(totalChange) | |
| 350 | |
| 351 local valuePerItem = totalChange / positiveCount | |
| 352 self:Debug(valuePerItem ) | |
| 353 for itemName, change in pairs(positive) do | |
| 354 self:Debug(itemName) | |
| 355 self:Debug(0-abs(valuePerItem * change)) | |
| 356 self:SaveValue(itemName, 0-abs(valuePerItem * change)) | |
| 357 end | |
| 358 end | |
| 359 end | |
| 360 | |
| 361 self.lastInventory = currentInventory | |
| 362 end | |
| 363 -- /run ItemAuditor.db.factionrealm.item_account["Tiger Lily"] = -586625 | |
| 364 -- /run ItemAuditor.db.factionrealm.item_account["Icy Pigment"] = -12303 | |
| 365 -- /run ItemAuditor.db.factionrealm.item_account["Azure Pigment"] = -258357 | |
| 366 | |
| 367 function addon:GetItemCost(itemName, countModifier) | |
| 368 local invested = abs(self.db.factionrealm.item_account[itemName] or 0) | |
| 369 | |
| 370 if invested > 0 then | |
| 371 local _, itemLink = GetItemInfo (itemName); | |
| 372 local _, _, _, _, Id = string.find(itemLink, "|?c?f?f?(%x*)|?H?([^:]*):?(%d+):?(%d*):?(%d*):?(%d*):?(%d*):?(%d*):?(%-?%d*):?(%-?%d*):?(%d*)|?h?%[?([^%[%]]*)%]?|?h?|?r?") | |
| 373 local count = Altoholic:GetItemCount(tonumber(Id)) | |
| 374 if countModifier ~= nil then | |
| 375 count = count - countModifier | |
| 376 end | |
| 377 if count == 0 then | |
| 378 self.db.factionrealm.item_account[itemName] = nil | |
| 379 self:Print("You ran out of " .. itemName .. "and never recovered " .. self:FormatMoney(invested)) | |
| 380 return 0, 0, 0 | |
| 381 end | |
| 382 return ceil(invested), ceil(invested/count), count | |
| 383 end | |
| 384 return 0, 0, 0 | |
| 385 end | |
| 386 | |
| 387 function addon:ShowTooltip(tip, link, num) | |
| 388 if (link == nil) then | |
| 389 return; | |
| 390 end | |
| 391 | |
| 392 local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, _, _, _, _, itemVendorPrice = GetItemInfo (link); | |
| 393 -- local _, _, Color, Ltype, Id, Enchant, Gem1, Gem2, Gem3, Gem4, Suffix, Unique, LinkLvl, Name = string.find(link, "|?c?f?f?(%x*)|?H?([^:]*):?(%d+):?(%d*):?(%d*):?(%d*):?(%d*):?(%d*):?(%-?%d*):?(%-?%d*):?(%d*)|?h?%[?([^%[%]]*)%]?|?h?|?r?") | |
| 394 | |
| 395 local investedTotal, investedPerItem, count = self:GetItemCost(itemName) | |
| 396 | |
| 397 local AHCut = 0.05 | |
| 398 local keep = 1 - AHCut | |
| 399 | |
| 400 if investedTotal > 0 then | |
| 401 tip:AddDoubleLine("\124cffffffffIA: Total Invested", self:FormatMoney(investedTotal)); | |
| 402 tip:AddDoubleLine("\124cffffffffIA: Invested/Item (" .. count .. ")", self:FormatMoney(ceil(investedPerItem))); | |
| 403 tip:AddDoubleLine("\124cffffffffIA: Minimum faction AH Price: ", self:FormatMoney(ceil(investedPerItem/keep))) | |
| 404 tip:Show() | |
| 405 end | |
| 406 end | |
| 407 | |
| 408 local function ShowTipWithPricing(tip, link, num) | |
| 409 addon:ShowTooltip(tip, link, num) | |
| 410 end | |
| 411 | |
| 412 hooksecurefunc (GameTooltip, "SetBagItem", | |
| 413 function(tip, bag, slot) | |
| 414 local _, num = GetContainerItemInfo(bag, slot); | |
| 415 ShowTipWithPricing (tip, GetContainerItemLink(bag, slot), num); | |
| 416 end | |
| 417 ); | |
| 418 | |
| 419 | |
| 420 hooksecurefunc (GameTooltip, "SetAuctionItem", | |
| 421 function (tip, type, index) | |
| 422 ShowTipWithPricing (tip, GetAuctionItemLink(type, index)); | |
| 423 end | |
| 424 ); | |
| 425 | |
| 426 hooksecurefunc (GameTooltip, "SetAuctionSellItem", | |
| 427 function (tip) | |
| 428 local name, _, count = GetAuctionSellItemInfo(); | |
| 429 local __, link = GetItemInfo(name); | |
| 430 ShowTipWithPricing (tip, link, num); | |
| 431 end | |
| 432 ); | |
| 433 | |
| 434 | |
| 435 hooksecurefunc (GameTooltip, "SetLootItem", | |
| 436 function (tip, slot) | |
| 437 if LootSlotIsItem(slot) then | |
| 438 local link, _, num = GetLootSlotLink(slot); | |
| 439 ShowTipWithPricing (tip, link, num); | |
| 440 end | |
| 441 end | |
| 442 ); | |
| 443 | |
| 444 hooksecurefunc (GameTooltip, "SetLootRollItem", | |
| 445 function (tip, slot) | |
| 446 local _, _, num = GetLootRollItemInfo(slot); | |
| 447 ShowTipWithPricing (tip, GetLootRollItemLink(slot), num); | |
| 448 end | |
| 449 ); | |
| 450 | |
| 451 | |
| 452 hooksecurefunc (GameTooltip, "SetInventoryItem", | |
| 453 function (tip, unit, slot) | |
| 454 ShowTipWithPricing (tip, GetInventoryItemLink(unit, slot), GetInventoryItemCount(unit, slot)); | |
| 455 end | |
| 456 ); | |
| 457 | |
| 458 hooksecurefunc (GameTooltip, "SetGuildBankItem", | |
| 459 function (tip, tab, slot) | |
| 460 local _, num = GetGuildBankItemInfo(tab, slot); | |
| 461 ShowTipWithPricing (tip, GetGuildBankItemLink(tab, slot), num); | |
| 462 end | |
| 463 ); | |
| 464 | |
| 465 hooksecurefunc (GameTooltip, "SetTradeSkillItem", | |
| 466 function (tip, skill, id) | |
| 467 local link = GetTradeSkillItemLink(skill); | |
| 468 local num = GetTradeSkillNumMade(skill); | |
| 469 if id then | |
| 470 link = GetTradeSkillReagentItemLink(skill, id); | |
| 471 num = select (3, GetTradeSkillReagentInfo(skill, id)); | |
| 472 end | |
| 473 | |
| 474 ShowTipWithPricing (tip, link, num); | |
| 475 end | |
| 476 ); | |
| 477 | |
| 478 hooksecurefunc (GameTooltip, "SetTradePlayerItem", | |
| 479 function (tip, id) | |
| 480 local _, _, num = GetTradePlayerItemInfo(id); | |
| 481 ShowTipWithPricing (tip, GetTradePlayerItemLink(id), num); | |
| 482 end | |
| 483 ); | |
| 484 | |
| 485 hooksecurefunc (GameTooltip, "SetTradeTargetItem", | |
| 486 function (tip, id) | |
| 487 local _, _, num = GetTradeTargetItemInfo(id); | |
| 488 ShowTipWithPricing (tip, GetTradeTargetItemLink(id), num); | |
| 489 end | |
| 490 ); | |
| 491 | |
| 492 hooksecurefunc (GameTooltip, "SetQuestItem", | |
| 493 function (tip, type, index) | |
| 494 local _, _, num = GetQuestItemInfo(type, index); | |
| 495 ShowTipWithPricing (tip, GetQuestItemLink(type, index), num); | |
| 496 end | |
| 497 ); | |
| 498 | |
| 499 hooksecurefunc (GameTooltip, "SetQuestLogItem", | |
| 500 function (tip, type, index) | |
| 501 local num, _; | |
| 502 if type == "choice" then | |
| 503 _, _, num = GetQuestLogChoiceInfo(index); | |
| 504 else | |
| 505 _, _, num = GetQuestLogRewardInfo(index) | |
| 506 end | |
| 507 | |
| 508 ShowTipWithPricing (tip, GetQuestLogItemLink(type, index), num); | |
| 509 end | |
| 510 ); | |
| 511 | |
| 512 hooksecurefunc (GameTooltip, "SetInboxItem", | |
| 513 function (tip, index, attachIndex) | |
| 514 local _, _, num = GetInboxItem(index, attachIndex); | |
| 515 ShowTipWithPricing (tip, GetInboxItemLink(index, attachIndex), num); | |
| 516 end | |
| 517 ); | |
| 518 | |
| 519 hooksecurefunc (GameTooltip, "SetSendMailItem", | |
| 520 function (tip, id) | |
| 521 local name, _, num = GetSendMailItem(id) | |
| 522 local name, link = GetItemInfo(name); | |
| 523 ShowTipWithPricing (tip, link, num); | |
| 524 end | |
| 525 ); | |
| 526 | |
| 527 hooksecurefunc (GameTooltip, "SetHyperlink", | |
| 528 function (tip, itemstring, num) | |
| 529 local name, link = GetItemInfo (itemstring); | |
| 530 ShowTipWithPricing (tip, link, num); | |
| 531 end | |
| 532 ); | |
| 533 | |
| 534 hooksecurefunc (ItemRefTooltip, "SetHyperlink", | |
| 535 function (tip, itemstring) | |
| 536 local name, link = GetItemInfo (itemstring); | |
| 537 ShowTipWithPricing (tip, link); | |
| 538 end | |
| 539 ); |
