annotate Main.lua @ 22:7e4ce6371608

Take instance difficulty into account for locations. Record locations based on GUID within the NPC id so only one set of location data exists per unique NPC.
author James D. Callahan III <jcallahan@curse.com>
date Thu, 10 May 2012 12:00:50 -0500
parents a82c5d1134db
children 2ff0171bddae
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@5 23 DatamineTT:SetOwner(_G.WorldFrame, "ANCHOR_NONE")
jcallahan@5 24
jcallahan@0 25
jcallahan@0 26 -----------------------------------------------------------------------
jcallahan@0 27 -- Local constants.
jcallahan@0 28 -----------------------------------------------------------------------
jcallahan@0 29 local DATABASE_DEFAULTS = {
jcallahan@0 30 global = {
jcallahan@0 31 items = {},
jcallahan@0 32 npcs = {},
jcallahan@0 33 objects = {},
jcallahan@0 34 quests = {},
jcallahan@17 35 zones = {},
jcallahan@0 36 }
jcallahan@0 37 }
jcallahan@0 38
jcallahan@0 39
jcallahan@1 40 local EVENT_MAPPING = {
jcallahan@18 41 COMBAT_TEXT_UPDATE = true,
jcallahan@13 42 LOOT_CLOSED = true,
jcallahan@1 43 LOOT_OPENED = true,
jcallahan@7 44 MERCHANT_SHOW = "UpdateMerchantItems",
jcallahan@7 45 MERCHANT_UPDATE = "UpdateMerchantItems",
jcallahan@2 46 PLAYER_TARGET_CHANGED = true,
jcallahan@9 47 QUEST_COMPLETE = true,
jcallahan@9 48 QUEST_DETAIL = true,
jcallahan@9 49 QUEST_LOG_UPDATE = true,
jcallahan@4 50 UNIT_QUEST_LOG_CHANGED = true,
jcallahan@1 51 UNIT_SPELLCAST_FAILED = "HandleSpellFailure",
jcallahan@1 52 UNIT_SPELLCAST_FAILED_QUIET = "HandleSpellFailure",
jcallahan@1 53 UNIT_SPELLCAST_INTERRUPTED = "HandleSpellFailure",
jcallahan@1 54 UNIT_SPELLCAST_SENT = true,
jcallahan@1 55 UNIT_SPELLCAST_SUCCEEDED = true,
jcallahan@0 56 }
jcallahan@0 57
jcallahan@4 58
jcallahan@1 59 local AF = private.ACTION_TYPE_FLAGS
jcallahan@0 60
jcallahan@4 61
jcallahan@0 62 -----------------------------------------------------------------------
jcallahan@0 63 -- Local variables.
jcallahan@0 64 -----------------------------------------------------------------------
jcallahan@0 65 local db
jcallahan@0 66 local durability_timer_handle
jcallahan@2 67 local target_location_timer_handle
jcallahan@1 68 local action_data = {}
jcallahan@20 69 local faction_names = {}
jcallahan@0 70
jcallahan@1 71
jcallahan@1 72 -----------------------------------------------------------------------
jcallahan@1 73 -- Helper Functions.
jcallahan@1 74 -----------------------------------------------------------------------
jcallahan@19 75 local function DBEntry(data_type, unit_id)
jcallahan@19 76 if not data_type or not unit_id then
jcallahan@6 77 return
jcallahan@6 78 end
jcallahan@19 79 local unit = db[data_type][unit_id]
jcallahan@6 80
jcallahan@10 81 if not unit then
jcallahan@19 82 db[data_type][unit_id] = {}
jcallahan@19 83 unit = db[data_type][unit_id]
jcallahan@6 84 end
jcallahan@10 85 return unit
jcallahan@6 86 end
jcallahan@6 87
jcallahan@6 88
jcallahan@22 89 local function InstanceDifficultyToken()
jcallahan@22 90 local _, instance_type, instance_difficulty, difficulty_name, _, _, is_dynamic = _G.GetInstanceInfo()
jcallahan@22 91 if difficulty_name == "" then
jcallahan@22 92 difficulty_name = "NONE"
jcallahan@22 93 end
jcallahan@22 94 return ("%s:%s:%s"):format(instance_type:upper(), difficulty_name:upper():gsub(" ", "_"), _G.tostring(is_dynamic))
jcallahan@22 95 end
jcallahan@22 96
jcallahan@22 97
jcallahan@1 98 local function CurrentLocationData()
jcallahan@1 99 local map_level = _G.GetCurrentMapDungeonLevel() or 0
jcallahan@1 100 local x, y = _G.GetPlayerMapPosition("player")
jcallahan@1 101
jcallahan@1 102 x = x or 0
jcallahan@1 103 y = y or 0
jcallahan@1 104
jcallahan@1 105 if x == 0 and y == 0 then
jcallahan@1 106 for level_index = 1, _G.GetNumDungeonMapLevels() do
jcallahan@1 107 _G.SetDungeonMapLevel(level_index)
jcallahan@1 108 x, y = _G.GetPlayerMapPosition("player")
jcallahan@1 109
jcallahan@1 110 if x and y and (x > 0 or y > 0) then
jcallahan@1 111 _G.SetDungeonMapLevel(map_level)
jcallahan@1 112 map_level = level_index
jcallahan@1 113 break
jcallahan@1 114 end
jcallahan@1 115 end
jcallahan@1 116 end
jcallahan@1 117
jcallahan@1 118 if _G.DungeonUsesTerrainMap() then
jcallahan@1 119 map_level = map_level - 1
jcallahan@1 120 end
jcallahan@22 121 return _G.GetRealZoneText(), ("%.2f"):format(x * 100), ("%.2f"):format(y * 100), map_level or 0, InstanceDifficultyToken()
jcallahan@1 122 end
jcallahan@1 123
jcallahan@1 124
jcallahan@1 125 local function ItemLinkToID(item_link)
jcallahan@1 126 if not item_link then
jcallahan@1 127 return
jcallahan@1 128 end
jcallahan@7 129 return tonumber(item_link:match("item:(%d+)"))
jcallahan@1 130 end
jcallahan@0 131
jcallahan@4 132
jcallahan@4 133 do
jcallahan@4 134 local UNIT_TYPE_BITMASK = 0x007
jcallahan@4 135
jcallahan@4 136 function WDP:ParseGUID(guid)
jcallahan@5 137 if not guid then
jcallahan@5 138 return
jcallahan@5 139 end
jcallahan@4 140 local types = private.UNIT_TYPES
jcallahan@4 141 local unit_type = _G.bit.band(tonumber(guid:sub(1, 5)), UNIT_TYPE_BITMASK)
jcallahan@4 142
jcallahan@10 143 if unit_type ~= types.PLAYER and unit_type ~= types.PET then
jcallahan@4 144 return unit_type, tonumber(guid:sub(-12, -9), 16)
jcallahan@4 145 end
jcallahan@4 146
jcallahan@4 147 return unit_type
jcallahan@4 148 end
jcallahan@4 149 end -- do-block
jcallahan@4 150
jcallahan@4 151
jcallahan@10 152 local function UpdateObjectLocation(identifier)
jcallahan@10 153 if not identifier then
jcallahan@10 154 return
jcallahan@10 155 end
jcallahan@22 156 local zone_name, x, y, map_level, instance_token = CurrentLocationData()
jcallahan@19 157 local object = DBEntry("objects", identifier)
jcallahan@11 158 object.locations = object.locations or {}
jcallahan@10 159
jcallahan@11 160 if not object.locations[zone_name] then
jcallahan@11 161 object.locations[zone_name] = {}
jcallahan@10 162 end
jcallahan@22 163 object.locations[zone_name][("%s:%s:%s:%s"):format(instance_token, map_level, x, y)] = true
jcallahan@10 164 end
jcallahan@10 165
jcallahan@10 166
jcallahan@19 167 local function HandleItemUse(item_link, bag_index, slot_index)
jcallahan@19 168 if not item_link then
jcallahan@19 169 return
jcallahan@19 170 end
jcallahan@19 171 local item_id = ItemLinkToID(item_link)
jcallahan@19 172
jcallahan@19 173 if not bag_index or not slot_index then
jcallahan@19 174 for new_bag_index = 0, _G.NUM_BAG_FRAMES do
jcallahan@19 175 for new_slot_index = 1, _G.GetContainerNumSlots(new_bag_index) do
jcallahan@19 176 if item_id == ItemLinkToID(_G.GetContainerItemLink(new_bag_index, new_slot_index)) then
jcallahan@19 177 bag_index = new_bag_index
jcallahan@19 178 slot_index = new_slot_index
jcallahan@19 179 break
jcallahan@19 180 end
jcallahan@19 181 end
jcallahan@19 182 end
jcallahan@19 183 end
jcallahan@19 184
jcallahan@19 185 if not bag_index or not slot_index then
jcallahan@19 186 return
jcallahan@19 187 end
jcallahan@19 188 local _, _, _, _, _, is_lootable = _G.GetContainerItemInfo(bag_index, slot_index)
jcallahan@19 189
jcallahan@19 190 if not is_lootable then
jcallahan@19 191 return
jcallahan@19 192 end
jcallahan@19 193 DatamineTT:ClearLines()
jcallahan@19 194 DatamineTT:SetBagItem(bag_index, slot_index)
jcallahan@19 195
jcallahan@19 196 for line_index = 1, DatamineTT:NumLines() do
jcallahan@19 197 local current_line = _G["WDPDatamineTTTextLeft" .. line_index]
jcallahan@19 198
jcallahan@19 199 if not current_line then
jcallahan@19 200 break
jcallahan@19 201 end
jcallahan@19 202
jcallahan@19 203 if current_line:GetText() == _G.ITEM_OPENABLE then
jcallahan@19 204 table.wipe(action_data)
jcallahan@19 205 action_data.type = AF.ITEM
jcallahan@19 206 action_data.item_id = item_id
jcallahan@19 207 action_data.loot_type = "contains"
jcallahan@19 208 break
jcallahan@19 209 end
jcallahan@19 210 end
jcallahan@19 211 end
jcallahan@19 212
jcallahan@19 213
jcallahan@20 214 local function UpdateFactionNames()
jcallahan@20 215 for faction_index = 1, 1000 do
jcallahan@20 216 local faction_name, _, _, _, _, _, _, _, is_header = _G.GetFactionInfo(faction_index)
jcallahan@20 217
jcallahan@20 218 if faction_name and not is_header then
jcallahan@20 219 faction_names[faction_name] = true
jcallahan@20 220 elseif not faction_name then
jcallahan@20 221 break
jcallahan@20 222 end
jcallahan@20 223 end
jcallahan@20 224 end
jcallahan@20 225
jcallahan@20 226
jcallahan@0 227 -----------------------------------------------------------------------
jcallahan@0 228 -- Methods.
jcallahan@0 229 -----------------------------------------------------------------------
jcallahan@0 230 function WDP:OnInitialize()
jcallahan@0 231 db = LibStub("AceDB-3.0"):New("WoWDBProfilerData", DATABASE_DEFAULTS, "Default").global
jcallahan@14 232
jcallahan@14 233 local raw_db = _G["WoWDBProfilerData"]
jcallahan@14 234
jcallahan@18 235 local build_num = tonumber(private.build_num)
jcallahan@14 236
jcallahan@14 237 if raw_db.build_num and raw_db.build_num < build_num then
jcallahan@14 238 for entry in pairs(DATABASE_DEFAULTS.global) do
jcallahan@14 239 db[entry] = {}
jcallahan@14 240 end
jcallahan@14 241 raw_db.build_num = build_num
jcallahan@14 242 elseif not raw_db.build_num then
jcallahan@14 243 raw_db.build_num = build_num
jcallahan@14 244 end
jcallahan@0 245 end
jcallahan@0 246
jcallahan@0 247
jcallahan@0 248 function WDP:OnEnable()
jcallahan@0 249 for event_name, mapping in pairs(EVENT_MAPPING) do
jcallahan@1 250 self:RegisterEvent(event_name, (_G.type(mapping) ~= "boolean") and mapping or nil)
jcallahan@0 251 end
jcallahan@0 252 durability_timer_handle = self:ScheduleRepeatingTimer("ProcessDurability", 30)
jcallahan@2 253 target_location_timer_handle = self:ScheduleRepeatingTimer("UpdateTargetLocation", 0.2)
jcallahan@19 254
jcallahan@19 255 _G.hooksecurefunc("UseContainerItem", function(bag_index, slot_index, target_unit)
jcallahan@19 256 if target_unit then
jcallahan@19 257 return
jcallahan@19 258 end
jcallahan@19 259 HandleItemUse(_G.GetContainerItemLink(bag_index, slot_index), bag_index, slot_index)
jcallahan@19 260 end)
jcallahan@19 261
jcallahan@19 262 _G.hooksecurefunc("UseItemByName", function(identifier, target_unit)
jcallahan@19 263 if target_unit then
jcallahan@19 264 return
jcallahan@19 265 end
jcallahan@19 266 local _, item_link = _G.GetItemInfo(identifier)
jcallahan@19 267 HandleItemUse(item_link)
jcallahan@19 268 end)
jcallahan@0 269 end
jcallahan@0 270
jcallahan@0 271
jcallahan@0 272 local function RecordDurability(item_id, durability)
jcallahan@0 273 if not durability or durability <= 0 then
jcallahan@0 274 return
jcallahan@0 275 end
jcallahan@0 276
jcallahan@0 277 if not db.items[item_id] then
jcallahan@0 278 db.items[item_id] = {}
jcallahan@0 279 end
jcallahan@0 280 db.items[item_id].durability = durability
jcallahan@0 281 end
jcallahan@0 282
jcallahan@0 283
jcallahan@0 284 function WDP:ProcessDurability()
jcallahan@0 285 for slot_index = 0, _G.INVSLOT_LAST_EQUIPPED do
jcallahan@1 286 local item_id = _G.GetInventoryItemID("player", slot_index)
jcallahan@0 287
jcallahan@0 288 if item_id and item_id > 0 then
jcallahan@1 289 local _, max_durability = _G.GetInventoryItemDurability(slot_index)
jcallahan@0 290 RecordDurability(item_id, max_durability)
jcallahan@0 291 end
jcallahan@0 292 end
jcallahan@0 293
jcallahan@0 294 for bag_index = 0, _G.NUM_BAG_SLOTS do
jcallahan@0 295 for slot_index = 1, _G.GetContainerNumSlots(bag_index) do
jcallahan@1 296 local item_id = _G.GetContainerItemID(bag_index, slot_index)
jcallahan@0 297
jcallahan@0 298 if item_id and item_id > 0 then
jcallahan@1 299 local _, max_durability = _G.GetContainerItemDurability(bag_index, slot_index)
jcallahan@0 300 RecordDurability(item_id, max_durability)
jcallahan@0 301 end
jcallahan@0 302 end
jcallahan@0 303 end
jcallahan@0 304 end
jcallahan@0 305
jcallahan@0 306
jcallahan@2 307 function WDP:UpdateTargetLocation()
jcallahan@22 308 local is_dead = _G.UnitIsDead("target")
jcallahan@22 309
jcallahan@22 310 if not _G.UnitExists("target") or _G.UnitPlayerControlled("target") or (_G.UnitIsTapped("target") and not is_dead) then
jcallahan@2 311 return
jcallahan@2 312 end
jcallahan@2 313
jcallahan@2 314 for index = 1, 4 do
jcallahan@2 315 if not _G.CheckInteractDistance("target", index) then
jcallahan@2 316 return
jcallahan@2 317 end
jcallahan@2 318 end
jcallahan@22 319 local target_guid = _G.UnitGUID("target")
jcallahan@22 320 local unit_type, unit_idnum = self:ParseGUID(target_guid)
jcallahan@2 321
jcallahan@2 322 if unit_type ~= private.UNIT_TYPES.NPC or not unit_idnum then
jcallahan@2 323 return
jcallahan@2 324 end
jcallahan@22 325 local zone_name, x, y, map_level, instance_token = CurrentLocationData()
jcallahan@22 326 local npc_data = DBEntry("npcs", unit_idnum).encounter_data[("level_%d"):format(_G.UnitLevel("target"))]
jcallahan@6 327 npc_data.locations = npc_data.locations or {}
jcallahan@2 328
jcallahan@2 329 if not npc_data.locations[zone_name] then
jcallahan@2 330 npc_data.locations[zone_name] = {}
jcallahan@2 331 end
jcallahan@22 332
jcallahan@22 333 -- Only record corpse location if there is no entry for this GUID.
jcallahan@22 334 if is_dead and npc_data.locations[zone_name][target_guid] then
jcallahan@22 335 return
jcallahan@22 336 end
jcallahan@22 337 npc_data.locations[zone_name][target_guid] = ("%s:%s:%s:%s"):format(instance_token, map_level, x, y)
jcallahan@2 338 end
jcallahan@2 339
jcallahan@2 340
jcallahan@0 341 -----------------------------------------------------------------------
jcallahan@0 342 -- Event handlers.
jcallahan@0 343 -----------------------------------------------------------------------
jcallahan@18 344 function WDP:COMBAT_TEXT_UPDATE(event, message_type, faction_name, amount)
jcallahan@21 345 local npc = DBEntry("npcs", action_data.id_num)
jcallahan@21 346
jcallahan@21 347 if not npc then
jcallahan@21 348 return
jcallahan@21 349 end
jcallahan@22 350 npc.encounter_data[action_data.npc_level].reputations = npc.encounter_data[action_data.npc_level].reputations or {}
jcallahan@22 351 npc.encounter_data[action_data.npc_level].reputations[faction_name] = amount
jcallahan@18 352 end
jcallahan@18 353
jcallahan@18 354
jcallahan@13 355 function WDP:LOOT_CLOSED()
jcallahan@18 356 -- table.wipe(action_data)
jcallahan@0 357 end
jcallahan@0 358
jcallahan@0 359
jcallahan@13 360 do
jcallahan@13 361 local re_gold = _G.GOLD_AMOUNT:gsub("%%d", "(%%d+)")
jcallahan@13 362 local re_silver = _G.SILVER_AMOUNT:gsub("%%d", "(%%d+)")
jcallahan@13 363 local re_copper = _G.COPPER_AMOUNT:gsub("%%d", "(%%d+)")
jcallahan@13 364
jcallahan@13 365
jcallahan@13 366 local function _moneyMatch(money, re)
jcallahan@13 367 return money:match(re) or 0
jcallahan@1 368 end
jcallahan@1 369
jcallahan@0 370
jcallahan@13 371 local function _toCopper(money)
jcallahan@13 372 if not money then
jcallahan@13 373 return 0
jcallahan@13 374 end
jcallahan@0 375
jcallahan@13 376 return _moneyMatch(money, re_gold) * 10000 + _moneyMatch(money, re_silver) * 100 + _moneyMatch(money, re_copper)
jcallahan@1 377 end
jcallahan@1 378
jcallahan@1 379
jcallahan@13 380 local LOOT_VERIFY_FUNCS = {
jcallahan@16 381 [AF.ITEM] = function()
jcallahan@16 382 local locked_item_id
jcallahan@16 383
jcallahan@16 384 for bag_index = 0, _G.NUM_BAG_FRAMES do
jcallahan@16 385 for slot_index = 1, _G.GetContainerNumSlots(bag_index) do
jcallahan@16 386 local _, _, is_locked = _G.GetContainerItemInfo(bag_index, slot_index)
jcallahan@16 387
jcallahan@16 388 if is_locked then
jcallahan@16 389 locked_item_id = ItemLinkToID(_G.GetContainerItemLink(bag_index, slot_index))
jcallahan@16 390 end
jcallahan@16 391 end
jcallahan@16 392 end
jcallahan@16 393
jcallahan@16 394 if not locked_item_id or (action_data.item_id and action_data.item_id ~= locked_item_id) then
jcallahan@16 395 return false
jcallahan@16 396 end
jcallahan@16 397 action_data.item_id = locked_item_id
jcallahan@16 398 return true
jcallahan@16 399 end,
jcallahan@13 400 [AF.NPC] = function()
jcallahan@17 401 if not _G.UnitExists("target") or _G.UnitIsFriend("player", "target") or _G.UnitIsPlayer("target") or _G.UnitPlayerControlled("target") then
jcallahan@15 402 return false
jcallahan@13 403 end
jcallahan@15 404 local unit_type, id_num = WDP:ParseGUID(_G.UnitGUID("target"))
jcallahan@15 405 action_data.id_num = id_num
jcallahan@13 406 return true
jcallahan@13 407 end,
jcallahan@14 408 [AF.OBJECT] = true,
jcallahan@17 409 [AF.ZONE] = function()
jcallahan@17 410 return action_data.loot_type and _G.IsFishingLoot()
jcallahan@17 411 end,
jcallahan@13 412 }
jcallahan@13 413
jcallahan@13 414
jcallahan@22 415 local function GenericLootUpdate(data_type)
jcallahan@22 416 local entry = DBEntry(data_type, action_data.id_num)
jcallahan@22 417
jcallahan@22 418 if not entry then
jcallahan@22 419 return
jcallahan@22 420 end
jcallahan@22 421 local loot_type = action_data.loot_type or "drops"
jcallahan@22 422 entry[loot_type] = entry[loot_type] or {}
jcallahan@22 423
jcallahan@22 424 for index = 1, #action_data.loot_list do
jcallahan@22 425 table.insert(entry[loot_type], action_data.loot_list[index])
jcallahan@22 426 end
jcallahan@22 427 end
jcallahan@22 428
jcallahan@22 429
jcallahan@13 430 local LOOT_UPDATE_FUNCS = {
jcallahan@16 431 [AF.ITEM] = function()
jcallahan@19 432 local item = DBEntry("items", action_data.item_id)
jcallahan@19 433 local loot_type = action_data.loot_type or "drops"
jcallahan@16 434 item[loot_type] = item[loot_type] or {}
jcallahan@16 435
jcallahan@17 436 for index = 1, #action_data.loot_list do
jcallahan@17 437 table.insert(item[loot_type], action_data.loot_list[index])
jcallahan@16 438 end
jcallahan@16 439 end,
jcallahan@13 440 [AF.NPC] = function()
jcallahan@22 441 GenericLootUpdate("npcs")
jcallahan@13 442 end,
jcallahan@13 443 [AF.OBJECT] = function()
jcallahan@22 444 GenericLootUpdate("objects")
jcallahan@17 445 end,
jcallahan@17 446 [AF.ZONE] = function()
jcallahan@17 447 local loot_type = action_data.loot_type or "drops"
jcallahan@19 448 local zone = DBEntry("zones", action_data.zone)
jcallahan@17 449 zone[loot_type] = zone[loot_type] or {}
jcallahan@17 450
jcallahan@22 451 local location_data = ("%s:%s:%s:%s"):format(action_data.instance_token, action_data.map_level, action_data.x, action_data.y)
jcallahan@17 452 local loot_data = zone[loot_type][location_data]
jcallahan@17 453
jcallahan@17 454 if not loot_data then
jcallahan@17 455 zone[loot_type][location_data] = {}
jcallahan@17 456 loot_data = zone[loot_type][location_data]
jcallahan@17 457 end
jcallahan@17 458
jcallahan@17 459 for index = 1, #action_data.loot_list do
jcallahan@17 460 table.insert(loot_data, action_data.loot_list[index])
jcallahan@13 461 end
jcallahan@13 462 end,
jcallahan@13 463 }
jcallahan@13 464
jcallahan@13 465
jcallahan@13 466 function WDP:LOOT_OPENED()
jcallahan@18 467 if action_data.looting then
jcallahan@18 468 return
jcallahan@18 469 end
jcallahan@18 470
jcallahan@13 471 if not action_data.type then
jcallahan@13 472 action_data.type = AF.NPC
jcallahan@1 473 end
jcallahan@13 474 local verify_func = LOOT_VERIFY_FUNCS[action_data.type]
jcallahan@13 475 local update_func = LOOT_UPDATE_FUNCS[action_data.type]
jcallahan@13 476
jcallahan@14 477 if not verify_func or not update_func then
jcallahan@13 478 return
jcallahan@13 479 end
jcallahan@13 480
jcallahan@14 481 if _G.type(verify_func) == "function" and not verify_func() then
jcallahan@14 482 return
jcallahan@14 483 end
jcallahan@18 484 -- TODO: Remove this check once the MoP client goes live
jcallahan@18 485 local wow_version = private.wow_version
jcallahan@13 486 local loot_registry = {}
jcallahan@17 487 action_data.loot_list = {}
jcallahan@18 488 action_data.looting = true
jcallahan@13 489
jcallahan@18 490 if wow_version == "5.0.1" then
jcallahan@18 491 for loot_slot = 1, _G.GetNumLootItems() do
jcallahan@18 492 local icon_texture, item_text, quantity, quality, locked = _G.GetLootSlotInfo(loot_slot)
jcallahan@13 493
jcallahan@18 494 local slot_type = _G.GetLootSlotType(loot_slot)
jcallahan@18 495
jcallahan@18 496 if slot_type == _G.LOOT_SLOT_ITEM then
jcallahan@18 497 local item_id = ItemLinkToID(_G.GetLootSlotLink(loot_slot))
jcallahan@18 498 loot_registry[item_id] = (loot_registry[item_id]) or 0 + quantity
jcallahan@18 499 elseif slot_type == _G.LOOT_SLOT_MONEY then
jcallahan@18 500 table.insert(action_data.loot_list, ("money:%d"):format(_toCopper(item_text)))
jcallahan@18 501 elseif slot_type == _G.LOOT_SLOT_CURRENCY then
jcallahan@18 502 table.insert(action_data.loot_list, ("currency:%d:%s"):format(quantity, icon_texture:match("[^\\]+$"):lower()))
jcallahan@18 503 end
jcallahan@18 504 end
jcallahan@18 505 else
jcallahan@18 506 for loot_slot = 1, _G.GetNumLootItems() do
jcallahan@18 507 local icon_texture, item_text, quantity, quality, locked = _G.GetLootSlotInfo(loot_slot)
jcallahan@18 508 if _G.LootSlotIsItem(loot_slot) then
jcallahan@18 509 local item_id = ItemLinkToID(_G.GetLootSlotLink(loot_slot))
jcallahan@18 510 loot_registry[item_id] = (loot_registry[item_id]) or 0 + quantity
jcallahan@18 511 elseif _G.LootSlotIsCoin(loot_slot) then
jcallahan@18 512 table.insert(action_data.loot_list, ("money:%d"):format(_toCopper(item_text)))
jcallahan@18 513 elseif _G.LootSlotIsCurrency(loot_slot) then
jcallahan@18 514 table.insert(action_data.loot_list, ("currency:%d:%s"):format(quantity, icon_texture:match("[^\\]+$"):lower()))
jcallahan@18 515 end
jcallahan@13 516 end
jcallahan@13 517 end
jcallahan@13 518
jcallahan@13 519 for item_id, quantity in pairs(loot_registry) do
jcallahan@17 520 table.insert(action_data.loot_list, ("%d:%d"):format(item_id, quantity))
jcallahan@13 521 end
jcallahan@13 522 update_func()
jcallahan@1 523 end
jcallahan@13 524 end -- do-block
jcallahan@0 525
jcallahan@0 526
jcallahan@5 527 local POINT_MATCH_PATTERNS = {
jcallahan@5 528 ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING:gsub("%%d", "(%%d+)")), -- May no longer be necessary
jcallahan@5 529 ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_3V3:gsub("%%d", "(%%d+)")), -- May no longer be necessary
jcallahan@5 530 ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_5V5:gsub("%%d", "(%%d+)")), -- May no longer be necessary
jcallahan@5 531 ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_BG:gsub("%%d", "(%%d+)")),
jcallahan@5 532 ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_3V3_BG:gsub("%%d", "(%%d+)")),
jcallahan@5 533 }
jcallahan@5 534
jcallahan@5 535
jcallahan@7 536 function WDP:UpdateMerchantItems()
jcallahan@4 537 local unit_type, unit_idnum = self:ParseGUID(_G.UnitGUID("target"))
jcallahan@4 538
jcallahan@4 539 if unit_type ~= private.UNIT_TYPES.NPC or not unit_idnum then
jcallahan@4 540 return
jcallahan@4 541 end
jcallahan@19 542 local merchant = DBEntry("npcs", unit_idnum)
jcallahan@6 543 merchant.sells = merchant.sells or {}
jcallahan@5 544
jcallahan@5 545 for item_index = 1, _G.GetMerchantNumItems() do
jcallahan@5 546 local _, _, copper_price, stack_size, num_available, _, extended_cost = _G.GetMerchantItemInfo(item_index)
jcallahan@5 547 local item_id = ItemLinkToID(_G.GetMerchantItemLink(item_index))
jcallahan@5 548
jcallahan@5 549 if item_id and item_id > 0 then
jcallahan@5 550 local price_string = copper_price
jcallahan@5 551
jcallahan@5 552 if extended_cost then
jcallahan@5 553 local bg_points = 0
jcallahan@5 554 local personal_points = 0
jcallahan@5 555
jcallahan@5 556 DatamineTT:ClearLines()
jcallahan@5 557 DatamineTT:SetMerchantItem(item_index)
jcallahan@5 558
jcallahan@5 559 for line_index = 1, DatamineTT:NumLines() do
jcallahan@5 560 local current_line = _G["WDPDatamineTTTextLeft" .. line_index]
jcallahan@5 561
jcallahan@5 562 if not current_line then
jcallahan@5 563 break
jcallahan@5 564 end
jcallahan@5 565 local breakout
jcallahan@5 566
jcallahan@5 567 for match_index = 1, #POINT_MATCH_PATTERNS do
jcallahan@5 568 local match1, match2 = current_line:GetText():match(POINT_MATCH_PATTERNS[match_index])
jcallahan@5 569 personal_points = personal_points + (match1 or 0)
jcallahan@5 570 bg_points = bg_points + (match2 or 0)
jcallahan@5 571
jcallahan@5 572 if match1 or match2 then
jcallahan@5 573 breakout = true
jcallahan@5 574 break
jcallahan@5 575 end
jcallahan@5 576 end
jcallahan@5 577
jcallahan@5 578 if breakout then
jcallahan@5 579 break
jcallahan@5 580 end
jcallahan@5 581 end
jcallahan@5 582 local currency_list = {}
jcallahan@5 583
jcallahan@5 584 price_string = ("%s:%s:%s"):format(price_string, bg_points, personal_points)
jcallahan@5 585
jcallahan@5 586 for cost_index = 1, _G.GetMerchantItemCostInfo(item_index) do
jcallahan@5 587 local icon_texture, amount_required, currency_link = _G.GetMerchantItemCostItem(item_index, cost_index)
jcallahan@5 588 local currency_id = currency_link and ItemLinkToID(currency_link) or nil
jcallahan@5 589
jcallahan@5 590 if not currency_id or currency_id < 1 then
jcallahan@5 591 if not icon_texture then
jcallahan@5 592 return
jcallahan@5 593 end
jcallahan@5 594 currency_id = icon_texture:match("[^\\]+$"):lower()
jcallahan@5 595 end
jcallahan@5 596 currency_list[#currency_list + 1] = ("(%s:%s)"):format(amount_required, currency_id)
jcallahan@5 597 end
jcallahan@5 598
jcallahan@5 599 for currency_index = 1, #currency_list do
jcallahan@5 600 price_string = ("%s:%s"):format(price_string, currency_list[currency_index])
jcallahan@5 601 end
jcallahan@5 602 end
jcallahan@6 603 merchant.sells[("%s:%s:[%s]"):format(item_id, stack_size, price_string)] = num_available
jcallahan@5 604 end
jcallahan@4 605 end
jcallahan@14 606
jcallahan@14 607 if _G.CanMerchantRepair() then
jcallahan@14 608 merchant.can_repair = true
jcallahan@14 609 end
jcallahan@4 610 end
jcallahan@4 611
jcallahan@4 612
jcallahan@18 613 do
jcallahan@18 614 local GENDER_NAMES = {
jcallahan@18 615 "UNKNOWN",
jcallahan@18 616 "MALE",
jcallahan@18 617 "FEMALE",
jcallahan@18 618 }
jcallahan@2 619
jcallahan@2 620
jcallahan@18 621 local REACTION_NAMES = {
jcallahan@18 622 "HATED",
jcallahan@18 623 "HOSTILE",
jcallahan@18 624 "UNFRIENDLY",
jcallahan@18 625 "NEUTRAL",
jcallahan@18 626 "FRIENDLY",
jcallahan@18 627 "HONORED",
jcallahan@18 628 "REVERED",
jcallahan@18 629 "EXALTED",
jcallahan@18 630 }
jcallahan@2 631
jcallahan@2 632
jcallahan@18 633 local POWER_TYPE_NAMES = {
jcallahan@18 634 ["0"] = "MANA",
jcallahan@18 635 ["1"] = "RAGE",
jcallahan@18 636 ["2"] = "FOCUS",
jcallahan@18 637 ["3"] = "ENERGY",
jcallahan@18 638 ["6"] = "RUNIC_POWER",
jcallahan@18 639 }
jcallahan@2 640
jcallahan@2 641
jcallahan@18 642 function WDP:PLAYER_TARGET_CHANGED()
jcallahan@18 643 if not _G.UnitExists("target") or _G.UnitPlayerControlled("target") then
jcallahan@18 644 return
jcallahan@18 645 end
jcallahan@18 646 local unit_type, unit_idnum = self:ParseGUID(_G.UnitGUID("target"))
jcallahan@2 647
jcallahan@18 648 if unit_type ~= private.UNIT_TYPES.NPC or not unit_idnum then
jcallahan@18 649 return
jcallahan@18 650 end
jcallahan@19 651 local npc = DBEntry("npcs", unit_idnum)
jcallahan@18 652 local _, class_token = _G.UnitClass("target")
jcallahan@18 653 npc.class = class_token
jcallahan@20 654
jcallahan@20 655 UpdateFactionNames()
jcallahan@20 656 DatamineTT:ClearLines()
jcallahan@20 657 DatamineTT:SetUnit("target")
jcallahan@20 658
jcallahan@20 659 for line_index = 1, DatamineTT:NumLines() do
jcallahan@20 660 local current_line = _G["WDPDatamineTTTextLeft" .. line_index]
jcallahan@20 661
jcallahan@20 662 if not current_line then
jcallahan@20 663 break
jcallahan@20 664 end
jcallahan@20 665 local line_text = current_line:GetText()
jcallahan@20 666
jcallahan@20 667 if faction_names[line_text] then
jcallahan@20 668 npc.faction = line_text
jcallahan@20 669 break
jcallahan@20 670 end
jcallahan@20 671 end
jcallahan@18 672 npc.gender = GENDER_NAMES[_G.UnitSex("target")] or "UNDEFINED"
jcallahan@18 673 npc.is_pvp = _G.UnitIsPVP("target") and true or nil
jcallahan@18 674 npc.reaction = ("%s:%s:%s"):format(_G.UnitLevel("player"), _G.UnitFactionGroup("player"), REACTION_NAMES[_G.UnitReaction("player", "target")])
jcallahan@22 675 npc.encounter_data = npc.encounter_data or {}
jcallahan@2 676
jcallahan@18 677 local npc_level = ("level_%d"):format(_G.UnitLevel("target"))
jcallahan@3 678
jcallahan@22 679 if not npc.encounter_data[npc_level] then
jcallahan@22 680 npc.encounter_data[npc_level] = {
jcallahan@18 681 max_health = _G.UnitHealthMax("target"),
jcallahan@18 682 }
jcallahan@3 683
jcallahan@18 684 local max_power = _G.UnitManaMax("target")
jcallahan@18 685
jcallahan@18 686 if max_power > 0 then
jcallahan@18 687 local power_type = _G.UnitPowerType("target")
jcallahan@22 688 npc.encounter_data[npc_level].power = ("%s:%d"):format(POWER_TYPE_NAMES[_G.tostring(power_type)] or power_type, max_power)
jcallahan@18 689 end
jcallahan@3 690 end
jcallahan@21 691 table.wipe(action_data)
jcallahan@21 692 action_data.type = AF.NPC
jcallahan@21 693 action_data.id_num = unit_idnum
jcallahan@21 694 action_data.npc_level = npc_level
jcallahan@2 695 end
jcallahan@18 696 end -- do-block
jcallahan@2 697
jcallahan@12 698 do
jcallahan@12 699 local function UpdateQuestJuncture(point)
jcallahan@12 700 local unit_name = _G.UnitName("questnpc")
jcallahan@9 701
jcallahan@12 702 if not unit_name then
jcallahan@12 703 return
jcallahan@12 704 end
jcallahan@12 705 local unit_type, unit_id = WDP:ParseGUID(_G.UnitGUID("questnpc"))
jcallahan@9 706
jcallahan@12 707 if unit_type == private.UNIT_TYPES.OBJECT then
jcallahan@12 708 UpdateObjectLocation(unit_id)
jcallahan@12 709 end
jcallahan@19 710 local quest = DBEntry("quests", _G.GetQuestID())
jcallahan@12 711 quest[point] = quest[point] or {}
jcallahan@12 712 quest[point][("%s:%d"):format(private.UNIT_TYPE_NAMES[unit_type + 1], unit_id)] = true
jcallahan@12 713 end
jcallahan@10 714
jcallahan@12 715
jcallahan@12 716 function WDP:QUEST_COMPLETE()
jcallahan@12 717 UpdateQuestJuncture("end")
jcallahan@10 718 end
jcallahan@10 719
jcallahan@12 720
jcallahan@12 721 function WDP:QUEST_DETAIL()
jcallahan@12 722 UpdateQuestJuncture("begin")
jcallahan@10 723 end
jcallahan@12 724 end -- do-block
jcallahan@9 725
jcallahan@9 726
jcallahan@4 727 function WDP:QUEST_LOG_UPDATE()
jcallahan@4 728 self:UnregisterEvent("QUEST_LOG_UPDATE")
jcallahan@4 729 end
jcallahan@4 730
jcallahan@4 731
jcallahan@4 732 function WDP:UNIT_QUEST_LOG_CHANGED(event, unit_id)
jcallahan@4 733 if unit_id ~= "player" then
jcallahan@4 734 return
jcallahan@4 735 end
jcallahan@4 736 self:RegisterEvent("QUEST_LOG_UPDATE")
jcallahan@4 737 end
jcallahan@4 738
jcallahan@4 739
jcallahan@1 740 function WDP:UNIT_SPELLCAST_SENT(event_name, unit_id, spell_name, spell_rank, target_name, spell_line)
jcallahan@1 741 if private.tracked_line or unit_id ~= "player" then
jcallahan@1 742 return
jcallahan@1 743 end
jcallahan@1 744 local spell_label = private.SPELL_LABELS_BY_NAME[spell_name]
jcallahan@1 745
jcallahan@1 746 if not spell_label then
jcallahan@1 747 return
jcallahan@1 748 end
jcallahan@18 749 table.wipe(action_data)
jcallahan@1 750
jcallahan@1 751 local tt_item_name, tt_item_link = _G.GameTooltip:GetItem()
jcallahan@1 752 local tt_unit_name, tt_unit_id = _G.GameTooltip:GetUnit()
jcallahan@1 753
jcallahan@1 754 if not tt_unit_name and _G.UnitName("target") == target_name then
jcallahan@1 755 tt_unit_name = target_name
jcallahan@1 756 tt_unit_id = "target"
jcallahan@1 757 end
jcallahan@1 758 local spell_flags = private.SPELL_FLAGS_BY_LABEL[spell_label]
jcallahan@1 759
jcallahan@16 760 if tt_unit_name and not tt_item_name then
jcallahan@16 761 if bit.band(spell_flags, AF.NPC) == AF.NPC then
jcallahan@16 762 if not tt_unit_id or tt_unit_name ~= target_name then
jcallahan@16 763 return
jcallahan@16 764 end
jcallahan@16 765 action_data.type = AF.NPC
jcallahan@16 766 action_data.loot_type = spell_label:lower()
jcallahan@16 767 end
jcallahan@16 768 elseif bit.band(spell_flags, AF.ITEM) == AF.ITEM then
jcallahan@16 769 action_data.type = AF.ITEM
jcallahan@16 770 action_data.loot_type = spell_label:lower()
jcallahan@16 771
jcallahan@16 772 if tt_item_name and tt_item_name == target_name then
jcallahan@16 773 action_data.item_id = ItemLinkToID(tt_item_link)
jcallahan@16 774 elseif target_name and target_name ~= "" then
jcallahan@16 775 local _, target_item_link = _G.GetItemInfo(target_name)
jcallahan@16 776 action_data.item_id = ItemLinkToID(target_item_link)
jcallahan@16 777 end
jcallahan@16 778 elseif not tt_item_name and not tt_unit_name then
jcallahan@22 779 local zone_name, x, y, map_level, instance_token = CurrentLocationData()
jcallahan@1 780
jcallahan@22 781 action_data.instance_token = instance_token
jcallahan@17 782 action_data.map_level = map_level
jcallahan@17 783 action_data.name = target_name
jcallahan@17 784 action_data.x = x
jcallahan@17 785 action_data.y = y
jcallahan@17 786 action_data.zone = zone_name
jcallahan@17 787
jcallahan@1 788 if bit.band(spell_flags, AF.OBJECT) == AF.OBJECT then
jcallahan@17 789 if target_name == "" then
jcallahan@17 790 return
jcallahan@17 791 end
jcallahan@11 792 local identifier = ("%s:%s"):format(spell_label, target_name)
jcallahan@11 793 UpdateObjectLocation(identifier)
jcallahan@11 794
jcallahan@1 795 action_data.type = AF.OBJECT
jcallahan@11 796 action_data.identifier = identifier
jcallahan@1 797 elseif bit.band(spell_flags, AF.ZONE) == AF.ZONE then
jcallahan@17 798 action_data.type = AF.ZONE
jcallahan@17 799 action_data.loot_type = spell_label:lower()
jcallahan@1 800 end
jcallahan@1 801 end
jcallahan@1 802
jcallahan@18 803 -- print(("%s: '%s', '%s', '%s', '%s', '%s'"):format(event_name, unit_id, spell_name, spell_rank, target_name, spell_line))
jcallahan@1 804 private.tracked_line = spell_line
jcallahan@0 805 end
jcallahan@0 806
jcallahan@0 807
jcallahan@1 808 function WDP:UNIT_SPELLCAST_SUCCEEDED(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id)
jcallahan@1 809 if unit_id ~= "player" then
jcallahan@1 810 return
jcallahan@1 811 end
jcallahan@1 812
jcallahan@18 813 -- if private.SPELL_LABELS_BY_NAME[spell_name] then
jcallahan@18 814 -- print(("%s: '%s', '%s', '%s', '%s', '%s'"):format(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id))
jcallahan@18 815 -- end
jcallahan@1 816 private.tracked_line = nil
jcallahan@0 817 end
jcallahan@0 818
jcallahan@1 819 function WDP:HandleSpellFailure(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id)
jcallahan@1 820 if unit_id ~= "player" then
jcallahan@1 821 return
jcallahan@1 822 end
jcallahan@0 823
jcallahan@1 824 if private.tracked_line == spell_line then
jcallahan@1 825 private.tracked_line = nil
jcallahan@1 826 end
jcallahan@0 827 end