annotate Main.lua @ 4:24a1d78e2e8c

Trimmed out things which aren't quite needed yet and fixed some library path issues.
author James D. Callahan III <jcallahan@curse.com>
date Fri, 27 Apr 2012 21:25:14 -0500
parents a9b84f0d8235
children 59400bdcf95c
rev   line source
jcallahan@0 1 -----------------------------------------------------------------------
jcallahan@0 2 -- Upvalued Lua API.
jcallahan@0 3 -----------------------------------------------------------------------
jcallahan@0 4 local _G = getfenv(0)
jcallahan@0 5
jcallahan@0 6 local pairs = _G.pairs
jcallahan@1 7 local tonumber = _G.tonumber
jcallahan@1 8
jcallahan@1 9 local bit = _G.bit
jcallahan@1 10 local math = _G.math
jcallahan@1 11 local table = _G.table
jcallahan@1 12
jcallahan@0 13
jcallahan@0 14 -----------------------------------------------------------------------
jcallahan@0 15 -- AddOn namespace.
jcallahan@0 16 -----------------------------------------------------------------------
jcallahan@0 17 local ADDON_NAME, private = ...
jcallahan@0 18
jcallahan@0 19 local LibStub = _G.LibStub
jcallahan@0 20 local WDP = LibStub("AceAddon-3.0"):NewAddon(ADDON_NAME, "AceEvent-3.0", "AceTimer-3.0")
jcallahan@0 21
jcallahan@4 22 local DatamineTT = _G.CreateFrame("GameTooltip", "WDPDatamineTT", _G.UIParent, "GameTooltipTemplate")
jcallahan@0 23
jcallahan@0 24 -----------------------------------------------------------------------
jcallahan@0 25 -- Local constants.
jcallahan@0 26 -----------------------------------------------------------------------
jcallahan@0 27 local DATABASE_DEFAULTS = {
jcallahan@0 28 global = {
jcallahan@0 29 items = {},
jcallahan@0 30 npcs = {},
jcallahan@0 31 objects = {},
jcallahan@0 32 quests = {},
jcallahan@0 33 }
jcallahan@0 34 }
jcallahan@0 35
jcallahan@0 36
jcallahan@1 37 local EVENT_MAPPING = {
jcallahan@1 38 LOOT_OPENED = true,
jcallahan@4 39 MERCHANT_UPDATE = true,
jcallahan@2 40 PLAYER_TARGET_CHANGED = true,
jcallahan@4 41 UNIT_QUEST_LOG_CHANGED = true,
jcallahan@1 42 UNIT_SPELLCAST_FAILED = "HandleSpellFailure",
jcallahan@1 43 UNIT_SPELLCAST_FAILED_QUIET = "HandleSpellFailure",
jcallahan@1 44 UNIT_SPELLCAST_INTERRUPTED = "HandleSpellFailure",
jcallahan@1 45 UNIT_SPELLCAST_SENT = true,
jcallahan@1 46 UNIT_SPELLCAST_SUCCEEDED = true,
jcallahan@0 47 }
jcallahan@0 48
jcallahan@4 49
jcallahan@1 50 local AF = private.ACTION_TYPE_FLAGS
jcallahan@0 51
jcallahan@4 52
jcallahan@0 53 -----------------------------------------------------------------------
jcallahan@0 54 -- Local variables.
jcallahan@0 55 -----------------------------------------------------------------------
jcallahan@0 56 local db
jcallahan@0 57 local durability_timer_handle
jcallahan@2 58 local target_location_timer_handle
jcallahan@1 59 local action_data = {}
jcallahan@0 60
jcallahan@1 61
jcallahan@1 62 -----------------------------------------------------------------------
jcallahan@1 63 -- Helper Functions.
jcallahan@1 64 -----------------------------------------------------------------------
jcallahan@1 65 local function CurrentLocationData()
jcallahan@1 66 local map_level = _G.GetCurrentMapDungeonLevel() or 0
jcallahan@1 67 local x, y = _G.GetPlayerMapPosition("player")
jcallahan@1 68
jcallahan@1 69 x = x or 0
jcallahan@1 70 y = y or 0
jcallahan@1 71
jcallahan@1 72 if x == 0 and y == 0 then
jcallahan@1 73 for level_index = 1, _G.GetNumDungeonMapLevels() do
jcallahan@1 74 _G.SetDungeonMapLevel(level_index)
jcallahan@1 75 x, y = _G.GetPlayerMapPosition("player")
jcallahan@1 76
jcallahan@1 77 if x and y and (x > 0 or y > 0) then
jcallahan@1 78 _G.SetDungeonMapLevel(map_level)
jcallahan@1 79 map_level = level_index
jcallahan@1 80 break
jcallahan@1 81 end
jcallahan@1 82 end
jcallahan@1 83 end
jcallahan@1 84
jcallahan@1 85 if _G.DungeonUsesTerrainMap() then
jcallahan@1 86 map_level = map_level - 1
jcallahan@1 87 end
jcallahan@2 88 return _G.GetRealZoneText(), ("%.2f"):format(x * 100), ("%.2f"):format(y * 100), map_level or 0
jcallahan@1 89 end
jcallahan@1 90
jcallahan@1 91
jcallahan@1 92 local function ItemLinkToID(item_link)
jcallahan@1 93 if not item_link then
jcallahan@1 94 return
jcallahan@1 95 end
jcallahan@1 96 local id = item_link:match("item:(%d+)")
jcallahan@1 97 return id and tonumber(id) or nil
jcallahan@1 98 end
jcallahan@0 99
jcallahan@4 100
jcallahan@4 101 do
jcallahan@4 102 local UNIT_TYPE_BITMASK = 0x007
jcallahan@4 103
jcallahan@4 104 function WDP:ParseGUID(guid)
jcallahan@4 105 local types = private.UNIT_TYPES
jcallahan@4 106 local unit_type = _G.bit.band(tonumber(guid:sub(1, 5)), UNIT_TYPE_BITMASK)
jcallahan@4 107
jcallahan@4 108 if unit_type ~= types.PLAYER or unit_type ~= types.OBJECT or unit_type ~= types.PET then
jcallahan@4 109 return unit_type, tonumber(guid:sub(-12, -9), 16)
jcallahan@4 110 end
jcallahan@4 111
jcallahan@4 112 return unit_type
jcallahan@4 113 end
jcallahan@4 114 end -- do-block
jcallahan@4 115
jcallahan@4 116
jcallahan@0 117 -----------------------------------------------------------------------
jcallahan@0 118 -- Methods.
jcallahan@0 119 -----------------------------------------------------------------------
jcallahan@0 120 function WDP:OnInitialize()
jcallahan@0 121 db = LibStub("AceDB-3.0"):New("WoWDBProfilerData", DATABASE_DEFAULTS, "Default").global
jcallahan@0 122 end
jcallahan@0 123
jcallahan@0 124
jcallahan@0 125 function WDP:OnEnable()
jcallahan@0 126 for event_name, mapping in pairs(EVENT_MAPPING) do
jcallahan@1 127 self:RegisterEvent(event_name, (_G.type(mapping) ~= "boolean") and mapping or nil)
jcallahan@0 128 end
jcallahan@0 129 durability_timer_handle = self:ScheduleRepeatingTimer("ProcessDurability", 30)
jcallahan@2 130 target_location_timer_handle = self:ScheduleRepeatingTimer("UpdateTargetLocation", 0.2)
jcallahan@0 131 end
jcallahan@0 132
jcallahan@0 133
jcallahan@0 134 local function RecordDurability(item_id, durability)
jcallahan@0 135 if not durability or durability <= 0 then
jcallahan@0 136 return
jcallahan@0 137 end
jcallahan@0 138
jcallahan@0 139 if not db.items[item_id] then
jcallahan@0 140 db.items[item_id] = {}
jcallahan@0 141 end
jcallahan@0 142 db.items[item_id].durability = durability
jcallahan@0 143 end
jcallahan@0 144
jcallahan@0 145
jcallahan@0 146 function WDP:ProcessDurability()
jcallahan@0 147 for slot_index = 0, _G.INVSLOT_LAST_EQUIPPED do
jcallahan@1 148 local item_id = _G.GetInventoryItemID("player", slot_index)
jcallahan@0 149
jcallahan@0 150 if item_id and item_id > 0 then
jcallahan@1 151 local _, max_durability = _G.GetInventoryItemDurability(slot_index)
jcallahan@0 152 RecordDurability(item_id, max_durability)
jcallahan@0 153 end
jcallahan@0 154 end
jcallahan@0 155
jcallahan@0 156 for bag_index = 0, _G.NUM_BAG_SLOTS do
jcallahan@0 157 for slot_index = 1, _G.GetContainerNumSlots(bag_index) do
jcallahan@1 158 local item_id = _G.GetContainerItemID(bag_index, slot_index)
jcallahan@0 159
jcallahan@0 160 if item_id and item_id > 0 then
jcallahan@1 161 local _, max_durability = _G.GetContainerItemDurability(bag_index, slot_index)
jcallahan@0 162 RecordDurability(item_id, max_durability)
jcallahan@0 163 end
jcallahan@0 164 end
jcallahan@0 165 end
jcallahan@0 166 end
jcallahan@0 167
jcallahan@0 168
jcallahan@2 169 function WDP:UpdateTargetLocation()
jcallahan@2 170 if not _G.UnitExists("target") or _G.UnitPlayerControlled("target") or _G.UnitIsTapped("target") then
jcallahan@2 171 return
jcallahan@2 172 end
jcallahan@2 173
jcallahan@2 174 for index = 1, 4 do
jcallahan@2 175 if not _G.CheckInteractDistance("target", index) then
jcallahan@2 176 return
jcallahan@2 177 end
jcallahan@2 178 end
jcallahan@2 179
jcallahan@2 180 local unit_type, unit_idnum = self:ParseGUID(_G.UnitGUID("target"))
jcallahan@2 181
jcallahan@2 182 if unit_type ~= private.UNIT_TYPES.NPC or not unit_idnum then
jcallahan@2 183 return
jcallahan@2 184 end
jcallahan@2 185 local zone_name, x, y, map_level = CurrentLocationData()
jcallahan@2 186 local npc_data = db.npcs[unit_idnum].stats[("level_%d"):format(_G.UnitLevel("target"))]
jcallahan@2 187
jcallahan@2 188 if not npc_data.locations then
jcallahan@2 189 npc_data.locations = {}
jcallahan@2 190 end
jcallahan@2 191
jcallahan@2 192 if not npc_data.locations[zone_name] then
jcallahan@2 193 npc_data.locations[zone_name] = {}
jcallahan@2 194 end
jcallahan@2 195 npc_data.locations[zone_name][("%s:%s:%s"):format(map_level, x, y)] = true
jcallahan@2 196 end
jcallahan@2 197
jcallahan@2 198
jcallahan@0 199 -----------------------------------------------------------------------
jcallahan@0 200 -- Event handlers.
jcallahan@0 201 -----------------------------------------------------------------------
jcallahan@1 202 local re_gold = _G.GOLD_AMOUNT:gsub("%%d", "(%%d+)")
jcallahan@1 203 local re_silver = _G.SILVER_AMOUNT:gsub("%%d", "(%%d+)")
jcallahan@1 204 local re_copper = _G.COPPER_AMOUNT:gsub("%%d", "(%%d+)")
jcallahan@1 205
jcallahan@1 206
jcallahan@1 207 local function _moneyMatch(money, re)
jcallahan@1 208 return money:match(re) or 0
jcallahan@0 209 end
jcallahan@0 210
jcallahan@0 211
jcallahan@1 212 local function _toCopper(money)
jcallahan@1 213 if not money then
jcallahan@1 214 return 0
jcallahan@1 215 end
jcallahan@1 216
jcallahan@1 217 return _moneyMatch(money, re_gold) * 10000 + _moneyMatch(money, re_silver) * 100 + _moneyMatch(money, re_copper)
jcallahan@0 218 end
jcallahan@0 219
jcallahan@0 220
jcallahan@1 221 local LOOT_VERIFY_FUNCS = {
jcallahan@1 222 [AF.NPC] = function()
jcallahan@1 223 local fishing_loot = _G.IsFishingLoot()
jcallahan@1 224
jcallahan@1 225 if not fishing_loot and _G.UnitExists("target") and not _G.UnitIsFriend("player", "target") and _G.UnitIsDead("target") then
jcallahan@1 226 if _G.UnitIsPlayer("target") or _G.UnitPlayerControlled("target") then
jcallahan@1 227 return false
jcallahan@1 228 end
jcallahan@1 229 local unit_type, id_num = WDP:ParseGUID(_G.UnitGUID("target"))
jcallahan@1 230 action_data.id_num = id_num
jcallahan@1 231 end
jcallahan@1 232 return true
jcallahan@1 233 end,
jcallahan@1 234 }
jcallahan@1 235
jcallahan@4 236
jcallahan@1 237 local LOOT_UPDATE_FUNCS = {
jcallahan@1 238 [AF.NPC] = function()
jcallahan@1 239 local npc = db.npcs[action_data.id_num]
jcallahan@1 240
jcallahan@1 241 if not npc then
jcallahan@1 242 db.npcs[action_data.id_num] = {}
jcallahan@1 243 npc = db.npcs[action_data.id_num]
jcallahan@1 244 end
jcallahan@1 245 npc.drops = npc.drops or {}
jcallahan@1 246
jcallahan@1 247 for index = 1, #action_data.drops do
jcallahan@1 248 table.insert(npc.drops, action_data.drops[index])
jcallahan@1 249 end
jcallahan@1 250 end,
jcallahan@1 251 }
jcallahan@1 252
jcallahan@1 253
jcallahan@1 254 function WDP:LOOT_OPENED()
jcallahan@1 255 if not action_data.type then
jcallahan@1 256 action_data.type = AF.NPC
jcallahan@1 257 end
jcallahan@1 258 local verify_func = LOOT_VERIFY_FUNCS[action_data.type]
jcallahan@2 259 local update_func = LOOT_UPDATE_FUNCS[action_data.type]
jcallahan@1 260
jcallahan@1 261 if not verify_func or not update_func or not verify_func() then
jcallahan@1 262 return
jcallahan@1 263 end
jcallahan@1 264
jcallahan@1 265 local loot_registry = {}
jcallahan@1 266 action_data.drops = {}
jcallahan@1 267
jcallahan@1 268 for loot_slot = 1, _G.GetNumLootItems() do
jcallahan@1 269 local texture, item, quantity, quality, locked = _G.GetLootSlotInfo(loot_slot)
jcallahan@1 270
jcallahan@1 271 if _G.LootSlotIsItem(loot_slot) then
jcallahan@1 272 local item_id = ItemLinkToID(_G.GetLootSlotLink(loot_slot))
jcallahan@1 273 loot_registry[item_id] = (loot_registry[item_id]) or 0 + quantity
jcallahan@1 274 elseif _G.LootSlotIsCoin(loot_slot) then
jcallahan@1 275 table.insert(action_data.drops, ("money:%d"):format(_toCopper(item)))
jcallahan@1 276 elseif _G.LootSlotIsCurrency(loot_slot) then
jcallahan@1 277 end
jcallahan@1 278 end
jcallahan@1 279
jcallahan@1 280 for item_id, quantity in pairs(loot_registry) do
jcallahan@1 281 table.insert(action_data.drops, ("%d:%d"):format(item_id, quantity))
jcallahan@1 282 end
jcallahan@1 283 update_func()
jcallahan@0 284 end
jcallahan@0 285
jcallahan@0 286
jcallahan@4 287 function WDP:MERCHANT_UPDATE()
jcallahan@4 288 local unit_type, unit_idnum = self:ParseGUID(_G.UnitGUID("target"))
jcallahan@4 289
jcallahan@4 290 if unit_type ~= private.UNIT_TYPES.NPC or not unit_idnum then
jcallahan@4 291 return
jcallahan@4 292 end
jcallahan@4 293
jcallahan@4 294 for index = 1, _G.GetMerchantNumItems() do
jcallahan@4 295 local _, _, copper_price, stack_size, num_available, _, extended_cost = _G.GetMerchantItemInfo(index)
jcallahan@4 296 end
jcallahan@4 297 end
jcallahan@4 298
jcallahan@4 299
jcallahan@2 300 local GENDER_NAMES = {
jcallahan@2 301 "UNKNOWN",
jcallahan@2 302 "MALE",
jcallahan@2 303 "FEMALE",
jcallahan@2 304 }
jcallahan@2 305
jcallahan@2 306
jcallahan@2 307 local REACTION_NAMES = {
jcallahan@2 308 "HATED",
jcallahan@2 309 "HOSTILE",
jcallahan@2 310 "UNFRIENDLY",
jcallahan@2 311 "NEUTRAL",
jcallahan@2 312 "FRIENDLY",
jcallahan@2 313 "HONORED",
jcallahan@2 314 "REVERED",
jcallahan@2 315 "EXALTED",
jcallahan@2 316 }
jcallahan@2 317
jcallahan@2 318
jcallahan@2 319 local POWER_TYPE_NAMES = {
jcallahan@2 320 ["0"] = "MANA",
jcallahan@2 321 ["1"] = "RAGE",
jcallahan@2 322 ["2"] = "FOCUS",
jcallahan@2 323 ["3"] = "ENERGY",
jcallahan@2 324 ["6"] = "RUNIC_POWER",
jcallahan@2 325 }
jcallahan@2 326
jcallahan@2 327
jcallahan@2 328 function WDP:PLAYER_TARGET_CHANGED()
jcallahan@2 329 if not _G.UnitExists("target") or _G.UnitPlayerControlled("target") then
jcallahan@2 330 return
jcallahan@2 331 end
jcallahan@2 332 local unit_type, unit_idnum = self:ParseGUID(_G.UnitGUID("target"))
jcallahan@2 333
jcallahan@2 334 if unit_type ~= private.UNIT_TYPES.NPC or not unit_idnum then
jcallahan@2 335 return
jcallahan@2 336 end
jcallahan@2 337
jcallahan@2 338 local npc = db.npcs[unit_idnum]
jcallahan@2 339
jcallahan@2 340 if not npc then
jcallahan@2 341 db.npcs[unit_idnum] = {}
jcallahan@2 342 npc = db.npcs[unit_idnum]
jcallahan@2 343 end
jcallahan@2 344 local _, class_token = _G.UnitClass("target")
jcallahan@2 345 npc.class = class_token
jcallahan@2 346 -- TODO: Add faction here
jcallahan@2 347 npc.gender = GENDER_NAMES[_G.UnitSex("target")] or "UNDEFINED"
jcallahan@3 348 npc.is_pvp = _G.UnitIsPVP("target") and true or nil
jcallahan@2 349 npc.reaction = ("%s:%s:%s"):format(_G.UnitLevel("player"), _G.UnitFactionGroup("player"), REACTION_NAMES[_G.UnitReaction("player", "target")])
jcallahan@2 350 npc.stats = npc.stats or {}
jcallahan@2 351
jcallahan@2 352 local npc_level = ("level_%d"):format(_G.UnitLevel("target"))
jcallahan@2 353
jcallahan@2 354 if not npc.stats[npc_level] then
jcallahan@2 355 npc.stats[npc_level] = {
jcallahan@2 356 max_health = _G.UnitHealthMax("target"),
jcallahan@2 357 }
jcallahan@3 358
jcallahan@3 359 local max_power = _G.UnitManaMax("target")
jcallahan@3 360
jcallahan@3 361 if max_power > 0 then
jcallahan@3 362 local power_type = _G.UnitPowerType("target")
jcallahan@3 363 npc.stats[npc_level].power = ("%s:%d"):format(POWER_TYPE_NAMES[_G.tostring(power_type)] or power_type, max_power)
jcallahan@3 364 end
jcallahan@2 365 end
jcallahan@2 366 end
jcallahan@2 367
jcallahan@2 368
jcallahan@4 369 function WDP:QUEST_LOG_UPDATE()
jcallahan@4 370 self:UnregisterEvent("QUEST_LOG_UPDATE")
jcallahan@4 371 end
jcallahan@4 372
jcallahan@4 373
jcallahan@4 374 function WDP:UNIT_QUEST_LOG_CHANGED(event, unit_id)
jcallahan@4 375 if unit_id ~= "player" then
jcallahan@4 376 return
jcallahan@4 377 end
jcallahan@4 378 self:RegisterEvent("QUEST_LOG_UPDATE")
jcallahan@4 379 end
jcallahan@4 380
jcallahan@4 381
jcallahan@1 382 function WDP:UNIT_SPELLCAST_SENT(event_name, unit_id, spell_name, spell_rank, target_name, spell_line)
jcallahan@1 383 if private.tracked_line or unit_id ~= "player" then
jcallahan@1 384 return
jcallahan@1 385 end
jcallahan@1 386 local spell_label = private.SPELL_LABELS_BY_NAME[spell_name]
jcallahan@1 387
jcallahan@1 388 if not spell_label then
jcallahan@1 389 return
jcallahan@1 390 end
jcallahan@1 391 action_data.type = nil -- This will be set as appropriate below
jcallahan@1 392
jcallahan@1 393 local tt_item_name, tt_item_link = _G.GameTooltip:GetItem()
jcallahan@1 394 local tt_unit_name, tt_unit_id = _G.GameTooltip:GetUnit()
jcallahan@1 395
jcallahan@1 396 if not tt_unit_name and _G.UnitName("target") == target_name then
jcallahan@1 397 tt_unit_name = target_name
jcallahan@1 398 tt_unit_id = "target"
jcallahan@1 399 end
jcallahan@1 400 local spell_flags = private.SPELL_FLAGS_BY_LABEL[spell_label]
jcallahan@1 401
jcallahan@1 402 if not tt_item_name and not tt_unit_name then
jcallahan@1 403 if target_name == "" then
jcallahan@1 404 return
jcallahan@1 405 end
jcallahan@1 406
jcallahan@1 407 local zone_name, x, y, map_level = CurrentLocationData()
jcallahan@1 408
jcallahan@1 409 if bit.band(spell_flags, AF.OBJECT) == AF.OBJECT then
jcallahan@1 410 action_data.map_level = map_level
jcallahan@1 411 action_data.name = target_name
jcallahan@1 412 action_data.type = AF.OBJECT
jcallahan@1 413 action_data.x = x
jcallahan@1 414 action_data.y = y
jcallahan@1 415 action_data.zone = zone_name
jcallahan@2 416 print(("Found spell flagged for OBJECT: %s (%s, %s)"):format(zone_name, x, y))
jcallahan@1 417 elseif bit.band(spell_flags, AF.ZONE) == AF.ZONE then
jcallahan@1 418 print("Found spell flagged for ZONE")
jcallahan@1 419 end
jcallahan@1 420 elseif tt_unit_name and not tt_item_name then
jcallahan@1 421 if bit.band(spell_flags, AF.NPC) == AF.NPC then
jcallahan@1 422 print("Found spell flagged for NPC")
jcallahan@1 423 end
jcallahan@1 424 elseif bit.band(spell_flags, AF.ITEM) == AF.ITEM then
jcallahan@1 425 print("Found spell flagged for ITEM")
jcallahan@1 426 else
jcallahan@1 427 print(("%s: We have an issue with types and flags."), event_name)
jcallahan@1 428 end
jcallahan@1 429
jcallahan@1 430 print(("%s: '%s', '%s', '%s', '%s', '%s'"):format(event_name, unit_id, spell_name, spell_rank, target_name, spell_line))
jcallahan@1 431 private.tracked_line = spell_line
jcallahan@0 432 end
jcallahan@0 433
jcallahan@0 434
jcallahan@1 435 function WDP:UNIT_SPELLCAST_SUCCEEDED(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id)
jcallahan@1 436 if unit_id ~= "player" then
jcallahan@1 437 return
jcallahan@1 438 end
jcallahan@1 439
jcallahan@1 440 if action_data.type == AF.OBJECT then
jcallahan@1 441 end
jcallahan@1 442
jcallahan@1 443 if private.SPELL_LABELS_BY_NAME[spell_name] then
jcallahan@1 444 print(("%s: '%s', '%s', '%s', '%s', '%s'"):format(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id))
jcallahan@1 445 end
jcallahan@1 446 private.tracked_line = nil
jcallahan@0 447 end
jcallahan@0 448
jcallahan@1 449 function WDP:HandleSpellFailure(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id)
jcallahan@1 450 if unit_id ~= "player" then
jcallahan@1 451 return
jcallahan@1 452 end
jcallahan@0 453
jcallahan@1 454 if private.tracked_line == spell_line then
jcallahan@1 455 private.tracked_line = nil
jcallahan@1 456 end
jcallahan@0 457 end