| 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@74 | 19 -- TODO: Remove this once 5.0.4 hits Live. | 
| jcallahan@74 | 20 if private.wow_version == "4.3.4" then | 
| jcallahan@74 | 21     return | 
| jcallahan@74 | 22 end | 
| jcallahan@74 | 23 | 
| jcallahan@0 | 24 local LibStub = _G.LibStub | 
| jcallahan@0 | 25 local WDP = LibStub("AceAddon-3.0"):NewAddon(ADDON_NAME, "AceEvent-3.0", "AceTimer-3.0") | 
| jcallahan@0 | 26 | 
| jcallahan@48 | 27 local deformat = LibStub("LibDeformat-3.0") | 
| jcallahan@48 | 28 | 
| jcallahan@4 | 29 local DatamineTT = _G.CreateFrame("GameTooltip", "WDPDatamineTT", _G.UIParent, "GameTooltipTemplate") | 
| jcallahan@5 | 30 DatamineTT:SetOwner(_G.WorldFrame, "ANCHOR_NONE") | 
| jcallahan@5 | 31 | 
| jcallahan@0 | 32 | 
| jcallahan@0 | 33 ----------------------------------------------------------------------- | 
| jcallahan@0 | 34 -- Local constants. | 
| jcallahan@0 | 35 ----------------------------------------------------------------------- | 
| jcallahan@74 | 36 local DB_VERSION = 4 | 
| jcallahan@63 | 37 | 
| jcallahan@0 | 38 local DATABASE_DEFAULTS = { | 
| jcallahan@0 | 39     global = { | 
| jcallahan@0 | 40         items = {}, | 
| jcallahan@0 | 41         npcs = {}, | 
| jcallahan@0 | 42         objects = {}, | 
| jcallahan@0 | 43         quests = {}, | 
| jcallahan@17 | 44         zones = {}, | 
| jcallahan@0 | 45     } | 
| jcallahan@0 | 46 } | 
| jcallahan@0 | 47 | 
| jcallahan@0 | 48 | 
| jcallahan@1 | 49 local EVENT_MAPPING = { | 
| jcallahan@56 | 50     BLACK_MARKET_ITEM_UPDATE = true, | 
| jcallahan@48 | 51     CHAT_MSG_LOOT = true, | 
| jcallahan@40 | 52     CHAT_MSG_SYSTEM = true, | 
| jcallahan@23 | 53     COMBAT_LOG_EVENT_UNFILTERED = true, | 
| jcallahan@18 | 54     COMBAT_TEXT_UPDATE = true, | 
| jcallahan@42 | 55     ITEM_TEXT_BEGIN = true, | 
| jcallahan@1 | 56     LOOT_OPENED = true, | 
| jcallahan@7 | 57     MERCHANT_SHOW = "UpdateMerchantItems", | 
| jcallahan@61 | 58     MERCHANT_UPDATE = "UpdateMerchantItems", | 
| jcallahan@25 | 59     PET_BAR_UPDATE = true, | 
| jcallahan@2 | 60     PLAYER_TARGET_CHANGED = true, | 
| jcallahan@9 | 61     QUEST_COMPLETE = true, | 
| jcallahan@9 | 62     QUEST_DETAIL = true, | 
| jcallahan@9 | 63     QUEST_LOG_UPDATE = true, | 
| jcallahan@27 | 64     TRAINER_SHOW = true, | 
| jcallahan@4 | 65     UNIT_QUEST_LOG_CHANGED = true, | 
| jcallahan@1 | 66     UNIT_SPELLCAST_FAILED = "HandleSpellFailure", | 
| jcallahan@1 | 67     UNIT_SPELLCAST_FAILED_QUIET = "HandleSpellFailure", | 
| jcallahan@1 | 68     UNIT_SPELLCAST_INTERRUPTED = "HandleSpellFailure", | 
| jcallahan@1 | 69     UNIT_SPELLCAST_SENT = true, | 
| jcallahan@1 | 70     UNIT_SPELLCAST_SUCCEEDED = true, | 
| jcallahan@0 | 71 } | 
| jcallahan@0 | 72 | 
| jcallahan@4 | 73 | 
| jcallahan@1 | 74 local AF = private.ACTION_TYPE_FLAGS | 
| jcallahan@0 | 75 | 
| jcallahan@4 | 76 | 
| jcallahan@27 | 77 local PLAYER_CLASS = _G.select(2, _G.UnitClass("player")) | 
| jcallahan@34 | 78 local PLAYER_GUID = _G.UnitGUID("player") | 
| jcallahan@39 | 79 local PLAYER_RACE = _G.select(2, _G.UnitRace("player")) | 
| jcallahan@27 | 80 | 
| jcallahan@0 | 81 ----------------------------------------------------------------------- | 
| jcallahan@0 | 82 -- Local variables. | 
| jcallahan@0 | 83 ----------------------------------------------------------------------- | 
| jcallahan@0 | 84 local db | 
| jcallahan@0 | 85 local durability_timer_handle | 
| jcallahan@2 | 86 local target_location_timer_handle | 
| jcallahan@1 | 87 local action_data = {} | 
| jcallahan@40 | 88 local currently_drunk | 
| jcallahan@32 | 89 local faction_standings = {} | 
| jcallahan@67 | 90 local reputation_npc_id | 
| jcallahan@0 | 91 | 
| jcallahan@1 | 92 | 
| jcallahan@1 | 93 ----------------------------------------------------------------------- | 
| jcallahan@1 | 94 -- Helper Functions. | 
| jcallahan@1 | 95 ----------------------------------------------------------------------- | 
| jcallahan@39 | 96 local ActualCopperCost | 
| jcallahan@39 | 97 do | 
| jcallahan@39 | 98     local BARTERING_SPELL_ID = 83964 | 
| jcallahan@39 | 99 | 
| jcallahan@39 | 100     local STANDING_DISCOUNTS = { | 
| jcallahan@39 | 101         HATED = 0, | 
| jcallahan@39 | 102         HOSTILE = 0, | 
| jcallahan@39 | 103         UNFRIENDLY = 0, | 
| jcallahan@39 | 104         NEUTRAL = 0, | 
| jcallahan@39 | 105         FRIENDLY = 0.05, | 
| jcallahan@39 | 106         HONORED = 0.1, | 
| jcallahan@39 | 107         REVERED = 0.15, | 
| jcallahan@39 | 108         EXALTED = 0.2, | 
| jcallahan@39 | 109     } | 
| jcallahan@39 | 110 | 
| jcallahan@39 | 111 | 
| jcallahan@39 | 112     function ActualCopperCost(copper_cost, rep_standing) | 
| jcallahan@39 | 113         if not copper_cost or copper_cost == 0 then | 
| jcallahan@39 | 114             return 0 | 
| jcallahan@39 | 115         end | 
| jcallahan@39 | 116         local modifier = 1 | 
| jcallahan@39 | 117 | 
| jcallahan@39 | 118         if _G.IsSpellKnown(BARTERING_SPELL_ID) then | 
| jcallahan@39 | 119             modifier = modifier - 0.1 | 
| jcallahan@39 | 120         end | 
| jcallahan@39 | 121 | 
| jcallahan@39 | 122         if rep_standing then | 
| jcallahan@39 | 123             if PLAYER_RACE == "Goblin" then | 
| jcallahan@39 | 124                 modifier = modifier - STANDING_DISCOUNTS["EXALTED"] | 
| jcallahan@39 | 125             elseif STANDING_DISCOUNTS[rep_standing] then | 
| jcallahan@39 | 126                 modifier = modifier - STANDING_DISCOUNTS[rep_standing] | 
| jcallahan@39 | 127             end | 
| jcallahan@39 | 128         end | 
| jcallahan@39 | 129         return math.floor(copper_cost / modifier) | 
| jcallahan@39 | 130     end | 
| jcallahan@39 | 131 end -- do-block | 
| jcallahan@39 | 132 | 
| jcallahan@39 | 133 | 
| jcallahan@29 | 134 local function InstanceDifficultyToken() | 
| jcallahan@29 | 135     local _, instance_type, instance_difficulty, difficulty_name, _, _, is_dynamic = _G.GetInstanceInfo() | 
| jcallahan@59 | 136     if not difficulty_name or difficulty_name == "" then | 
| jcallahan@29 | 137         difficulty_name = "NONE" | 
| jcallahan@29 | 138     end | 
| jcallahan@59 | 139 | 
| jcallahan@59 | 140     if not instance_type or instance_type == "" then | 
| jcallahan@59 | 141         instance_type = "NONE" | 
| jcallahan@59 | 142     end | 
| jcallahan@29 | 143     return ("%s:%s:%s"):format(instance_type:upper(), difficulty_name:upper():gsub(" ", "_"), _G.tostring(is_dynamic)) | 
| jcallahan@29 | 144 end | 
| jcallahan@29 | 145 | 
| jcallahan@29 | 146 | 
| jcallahan@19 | 147 local function DBEntry(data_type, unit_id) | 
| jcallahan@19 | 148     if not data_type or not unit_id then | 
| jcallahan@6 | 149         return | 
| jcallahan@6 | 150     end | 
| jcallahan@19 | 151     local unit = db[data_type][unit_id] | 
| jcallahan@6 | 152 | 
| jcallahan@10 | 153     if not unit then | 
| jcallahan@19 | 154         db[data_type][unit_id] = {} | 
| jcallahan@19 | 155         unit = db[data_type][unit_id] | 
| jcallahan@6 | 156     end | 
| jcallahan@10 | 157     return unit | 
| jcallahan@6 | 158 end | 
| jcallahan@6 | 159 | 
| jcallahan@6 | 160 | 
| jcallahan@29 | 161 local function NPCEntry(identifier) | 
| jcallahan@29 | 162     local npc = DBEntry("npcs", identifier) | 
| jcallahan@29 | 163 | 
| jcallahan@29 | 164     if not npc then | 
| jcallahan@29 | 165         return | 
| jcallahan@22 | 166     end | 
| jcallahan@29 | 167     local instance_token = InstanceDifficultyToken() | 
| jcallahan@29 | 168     npc.encounter_data = npc.encounter_data or {} | 
| jcallahan@29 | 169     npc.encounter_data[instance_token] = npc.encounter_data[instance_token] or {} | 
| jcallahan@30 | 170     npc.encounter_data[instance_token].stats = npc.encounter_data[instance_token].stats or {} | 
| jcallahan@29 | 171     return npc | 
| jcallahan@22 | 172 end | 
| jcallahan@22 | 173 | 
| jcallahan@22 | 174 | 
| jcallahan@1 | 175 local function CurrentLocationData() | 
| jcallahan@1 | 176     local map_level = _G.GetCurrentMapDungeonLevel() or 0 | 
| jcallahan@1 | 177     local x, y = _G.GetPlayerMapPosition("player") | 
| jcallahan@1 | 178 | 
| jcallahan@1 | 179     x = x or 0 | 
| jcallahan@1 | 180     y = y or 0 | 
| jcallahan@1 | 181 | 
| jcallahan@1 | 182     if x == 0 and y == 0 then | 
| jcallahan@1 | 183         for level_index = 1, _G.GetNumDungeonMapLevels() do | 
| jcallahan@1 | 184             _G.SetDungeonMapLevel(level_index) | 
| jcallahan@1 | 185             x, y = _G.GetPlayerMapPosition("player") | 
| jcallahan@1 | 186 | 
| jcallahan@1 | 187             if x and y and (x > 0 or y > 0) then | 
| jcallahan@1 | 188                 _G.SetDungeonMapLevel(map_level) | 
| jcallahan@1 | 189                 map_level = level_index | 
| jcallahan@1 | 190                 break | 
| jcallahan@1 | 191             end | 
| jcallahan@1 | 192         end | 
| jcallahan@1 | 193     end | 
| jcallahan@1 | 194 | 
| jcallahan@1 | 195     if _G.DungeonUsesTerrainMap() then | 
| jcallahan@1 | 196         map_level = map_level - 1 | 
| jcallahan@1 | 197     end | 
| jcallahan@31 | 198     local x = _G.floor(x * 1000) | 
| jcallahan@31 | 199     local y = _G.floor(y * 1000) | 
| jcallahan@28 | 200 | 
| jcallahan@31 | 201     if x % 2 ~= 0 then | 
| jcallahan@31 | 202         x = x + 1 | 
| jcallahan@28 | 203     end | 
| jcallahan@28 | 204 | 
| jcallahan@31 | 205     if y % 2 ~= 0 then | 
| jcallahan@31 | 206         y = y + 1 | 
| jcallahan@28 | 207     end | 
| jcallahan@31 | 208     return _G.GetRealZoneText(), _G.GetCurrentMapAreaID(), x, y, map_level, InstanceDifficultyToken() | 
| jcallahan@1 | 209 end | 
| jcallahan@1 | 210 | 
| jcallahan@1 | 211 | 
| jcallahan@1 | 212 local function ItemLinkToID(item_link) | 
| jcallahan@1 | 213     if not item_link then | 
| jcallahan@1 | 214         return | 
| jcallahan@1 | 215     end | 
| jcallahan@7 | 216     return tonumber(item_link:match("item:(%d+)")) | 
| jcallahan@1 | 217 end | 
| jcallahan@0 | 218 | 
| jcallahan@4 | 219 | 
| jcallahan@34 | 220 local ParseGUID | 
| jcallahan@4 | 221 do | 
| jcallahan@4 | 222     local UNIT_TYPE_BITMASK = 0x007 | 
| jcallahan@4 | 223 | 
| jcallahan@34 | 224     function ParseGUID(guid) | 
| jcallahan@5 | 225         if not guid then | 
| jcallahan@5 | 226             return | 
| jcallahan@5 | 227         end | 
| jcallahan@4 | 228         local types = private.UNIT_TYPES | 
| jcallahan@4 | 229         local unit_type = _G.bit.band(tonumber(guid:sub(1, 5)), UNIT_TYPE_BITMASK) | 
| jcallahan@4 | 230 | 
| jcallahan@10 | 231         if unit_type ~= types.PLAYER and unit_type ~= types.PET then | 
| jcallahan@66 | 232             return unit_type, tonumber(guid:sub(6, 10), 16) | 
| jcallahan@4 | 233         end | 
| jcallahan@4 | 234         return unit_type | 
| jcallahan@4 | 235     end | 
| jcallahan@4 | 236 end -- do-block | 
| jcallahan@4 | 237 | 
| jcallahan@4 | 238 | 
| jcallahan@34 | 239 local UpdateNPCLocation | 
| jcallahan@34 | 240 do | 
| jcallahan@34 | 241     local COORD_MAX = 5 | 
| jcallahan@34 | 242 | 
| jcallahan@34 | 243     function UpdateNPCLocation(unit_idnum) | 
| jcallahan@34 | 244         local zone_name, area_id, x, y, map_level, difficulty_token = CurrentLocationData() | 
| jcallahan@34 | 245         local npc_data = NPCEntry(unit_idnum).encounter_data[difficulty_token].stats[("level_%d"):format(_G.UnitLevel("target"))] | 
| jcallahan@34 | 246         local zone_token = ("%s:%d"):format(zone_name, area_id) | 
| jcallahan@34 | 247         npc_data.locations = npc_data.locations or {} | 
| jcallahan@34 | 248 | 
| jcallahan@34 | 249         local zone_data = npc_data.locations[zone_token] | 
| jcallahan@34 | 250 | 
| jcallahan@34 | 251         if not zone_data then | 
| jcallahan@34 | 252             zone_data = {} | 
| jcallahan@34 | 253             npc_data.locations[zone_token] = zone_data | 
| jcallahan@34 | 254         end | 
| jcallahan@34 | 255 | 
| jcallahan@34 | 256         for location_token in pairs(zone_data) do | 
| jcallahan@34 | 257             local loc_level, loc_x, loc_y = (":"):split(location_token) | 
| jcallahan@34 | 258             loc_level = tonumber(loc_level) | 
| jcallahan@34 | 259 | 
| jcallahan@34 | 260             if map_level == loc_level and math.abs(x - loc_x) <= COORD_MAX and math.abs(y - loc_y) <= COORD_MAX then | 
| jcallahan@34 | 261                 return | 
| jcallahan@34 | 262             end | 
| jcallahan@34 | 263         end | 
| jcallahan@34 | 264         zone_data[("%s:%s:%s"):format(map_level, x, y)] = true | 
| jcallahan@34 | 265     end | 
| jcallahan@34 | 266 end -- do-block | 
| jcallahan@34 | 267 | 
| jcallahan@34 | 268 | 
| jcallahan@52 | 269 local function UpdateDBEntryLocation(entry_type, identifier) | 
| jcallahan@10 | 270     if not identifier then | 
| jcallahan@10 | 271         return | 
| jcallahan@10 | 272     end | 
| jcallahan@31 | 273     local zone_name, area_id, x, y, map_level, difficulty_token = CurrentLocationData() | 
| jcallahan@41 | 274     local entry = DBEntry(entry_type, identifier) | 
| jcallahan@41 | 275     entry[difficulty_token] = entry[difficulty_token] or {} | 
| jcallahan@52 | 276     entry[difficulty_token].locations = entry[difficulty_token].locations or {} | 
| jcallahan@10 | 277 | 
| jcallahan@31 | 278     local zone_token = ("%s:%d"):format(zone_name, area_id) | 
| jcallahan@52 | 279     local zone_data = entry[difficulty_token].locations[zone_token] | 
| jcallahan@24 | 280 | 
| jcallahan@31 | 281     if not zone_data then | 
| jcallahan@31 | 282         zone_data = {} | 
| jcallahan@52 | 283         entry[difficulty_token].locations[zone_token] = zone_data | 
| jcallahan@10 | 284     end | 
| jcallahan@41 | 285     local location_token = ("%s:%s:%s"):format(map_level, x, y) | 
| jcallahan@41 | 286     zone_data[location_token] = zone_data[location_token] or true | 
| jcallahan@41 | 287     return zone_data | 
| jcallahan@10 | 288 end | 
| jcallahan@10 | 289 | 
| jcallahan@10 | 290 | 
| jcallahan@19 | 291 local function HandleItemUse(item_link, bag_index, slot_index) | 
| jcallahan@19 | 292     if not item_link then | 
| jcallahan@19 | 293         return | 
| jcallahan@19 | 294     end | 
| jcallahan@19 | 295     local item_id = ItemLinkToID(item_link) | 
| jcallahan@19 | 296 | 
| jcallahan@19 | 297     if not bag_index or not slot_index then | 
| jcallahan@19 | 298         for new_bag_index = 0, _G.NUM_BAG_FRAMES do | 
| jcallahan@19 | 299             for new_slot_index = 1, _G.GetContainerNumSlots(new_bag_index) do | 
| jcallahan@19 | 300                 if item_id == ItemLinkToID(_G.GetContainerItemLink(new_bag_index, new_slot_index)) then | 
| jcallahan@19 | 301                     bag_index = new_bag_index | 
| jcallahan@19 | 302                     slot_index = new_slot_index | 
| jcallahan@19 | 303                     break | 
| jcallahan@19 | 304                 end | 
| jcallahan@19 | 305             end | 
| jcallahan@19 | 306         end | 
| jcallahan@19 | 307     end | 
| jcallahan@19 | 308 | 
| jcallahan@19 | 309     if not bag_index or not slot_index then | 
| jcallahan@19 | 310         return | 
| jcallahan@19 | 311     end | 
| jcallahan@19 | 312     local _, _, _, _, _, is_lootable = _G.GetContainerItemInfo(bag_index, slot_index) | 
| jcallahan@19 | 313 | 
| jcallahan@19 | 314     if not is_lootable then | 
| jcallahan@19 | 315         return | 
| jcallahan@19 | 316     end | 
| jcallahan@19 | 317     DatamineTT:ClearLines() | 
| jcallahan@19 | 318     DatamineTT:SetBagItem(bag_index, slot_index) | 
| jcallahan@19 | 319 | 
| jcallahan@19 | 320     for line_index = 1, DatamineTT:NumLines() do | 
| jcallahan@19 | 321         local current_line = _G["WDPDatamineTTTextLeft" .. line_index] | 
| jcallahan@19 | 322 | 
| jcallahan@19 | 323         if not current_line then | 
| jcallahan@19 | 324             break | 
| jcallahan@19 | 325         end | 
| jcallahan@19 | 326 | 
| jcallahan@19 | 327         if current_line:GetText() == _G.ITEM_OPENABLE then | 
| jcallahan@19 | 328             table.wipe(action_data) | 
| jcallahan@19 | 329             action_data.type = AF.ITEM | 
| jcallahan@28 | 330             action_data.identifier = item_id | 
| jcallahan@25 | 331             action_data.label = "contains" | 
| jcallahan@19 | 332             break | 
| jcallahan@19 | 333         end | 
| jcallahan@19 | 334     end | 
| jcallahan@19 | 335 end | 
| jcallahan@19 | 336 | 
| jcallahan@19 | 337 | 
| jcallahan@39 | 338 local UnitFactionStanding | 
| jcallahan@32 | 339 local UpdateFactionData | 
| jcallahan@32 | 340 do | 
| jcallahan@32 | 341     local MAX_FACTION_INDEX = 1000 | 
| jcallahan@20 | 342 | 
| jcallahan@32 | 343     local STANDING_NAMES = { | 
| jcallahan@32 | 344         "HATED", | 
| jcallahan@32 | 345         "HOSTILE", | 
| jcallahan@32 | 346         "UNFRIENDLY", | 
| jcallahan@32 | 347         "NEUTRAL", | 
| jcallahan@32 | 348         "FRIENDLY", | 
| jcallahan@32 | 349         "HONORED", | 
| jcallahan@32 | 350         "REVERED", | 
| jcallahan@32 | 351         "EXALTED", | 
| jcallahan@32 | 352     } | 
| jcallahan@32 | 353 | 
| jcallahan@39 | 354 | 
| jcallahan@39 | 355     function UnitFactionStanding(unit) | 
| jcallahan@39 | 356         UpdateFactionData() | 
| jcallahan@39 | 357         DatamineTT:ClearLines() | 
| jcallahan@39 | 358         DatamineTT:SetUnit(unit) | 
| jcallahan@39 | 359 | 
| jcallahan@39 | 360         for line_index = 1, DatamineTT:NumLines() do | 
| jcallahan@64 | 361             local faction_name = _G["WDPDatamineTTTextLeft" .. line_index]:GetText():trim() | 
| jcallahan@39 | 362 | 
| jcallahan@39 | 363             if faction_name and faction_standings[faction_name] then | 
| jcallahan@39 | 364                 return faction_name, faction_standings[faction_name] | 
| jcallahan@39 | 365             end | 
| jcallahan@39 | 366         end | 
| jcallahan@39 | 367     end | 
| jcallahan@39 | 368 | 
| jcallahan@39 | 369 | 
| jcallahan@32 | 370     function UpdateFactionData() | 
| jcallahan@32 | 371         for faction_index = 1, MAX_FACTION_INDEX do | 
| jcallahan@32 | 372             local faction_name, _, current_standing, _, _, _, _, _, is_header = _G.GetFactionInfo(faction_index) | 
| jcallahan@32 | 373 | 
| jcallahan@32 | 374             if faction_name and not is_header then | 
| jcallahan@32 | 375                 faction_standings[faction_name] = STANDING_NAMES[current_standing] | 
| jcallahan@32 | 376             elseif not faction_name then | 
| jcallahan@32 | 377                 break | 
| jcallahan@32 | 378             end | 
| jcallahan@20 | 379         end | 
| jcallahan@20 | 380     end | 
| jcallahan@32 | 381 end -- do-block | 
| jcallahan@20 | 382 | 
| jcallahan@48 | 383 | 
| jcallahan@75 | 384 local GenericLootUpdate | 
| jcallahan@75 | 385 do | 
| jcallahan@77 | 386     local function LootTable(entry, loot_type, top_field) | 
| jcallahan@75 | 387         if top_field then | 
| jcallahan@75 | 388             entry[top_field] = entry[top_field] or {} | 
| jcallahan@75 | 389             entry[top_field][loot_type] = entry[top_field][loot_type] or {} | 
| jcallahan@75 | 390             return entry[top_field][loot_type] | 
| jcallahan@75 | 391         end | 
| jcallahan@48 | 392         entry[loot_type] = entry[loot_type] or {} | 
| jcallahan@75 | 393         return entry[loot_type] | 
| jcallahan@48 | 394     end | 
| jcallahan@48 | 395 | 
| jcallahan@75 | 396     function GenericLootUpdate(data_type, top_field) | 
| jcallahan@75 | 397         local loot_type = action_data.label or "drops" | 
| jcallahan@75 | 398         local loot_count = ("%s_count"):format(loot_type) | 
| jcallahan@77 | 399         local source_list = {} | 
| jcallahan@75 | 400 | 
| jcallahan@75 | 401         for source_id, loot_data in pairs(action_data.loot_sources) do | 
| jcallahan@75 | 402             local entry = DBEntry(data_type, source_id) | 
| jcallahan@75 | 403 | 
| jcallahan@75 | 404             if entry then | 
| jcallahan@77 | 405                 local loot_table = LootTable(entry, loot_type, top_field) | 
| jcallahan@77 | 406 | 
| jcallahan@77 | 407                 if not source_list[source_id] then | 
| jcallahan@77 | 408                     if top_field then | 
| jcallahan@77 | 409                         entry[top_field][loot_count] = (entry[top_field][loot_count] or 0) + 1 | 
| jcallahan@77 | 410                     else | 
| jcallahan@77 | 411                         entry[loot_count] = (entry[loot_count] or 0) + 1 | 
| jcallahan@77 | 412                     end | 
| jcallahan@77 | 413                     source_list[source_id] = true | 
| jcallahan@77 | 414                 end | 
| jcallahan@75 | 415                 UpdateDBEntryLocation(data_type, source_id) | 
| jcallahan@75 | 416 | 
| jcallahan@75 | 417                 for item_id, quantity in pairs(loot_data) do | 
| jcallahan@75 | 418                     table.insert(loot_table, ("%d:%d"):format(item_id, quantity)) | 
| jcallahan@75 | 419                 end | 
| jcallahan@75 | 420             end | 
| jcallahan@75 | 421         end | 
| jcallahan@75 | 422         -- TODO: Remove this when GetLootSourceInfo() has values for money | 
| jcallahan@75 | 423         local entry = DBEntry(data_type, action_data.identifier) | 
| jcallahan@75 | 424 | 
| jcallahan@75 | 425         if not entry then | 
| jcallahan@75 | 426             return | 
| jcallahan@75 | 427         end | 
| jcallahan@77 | 428         local loot_table = LootTable(entry, loot_type, top_field) | 
| jcallahan@77 | 429 | 
| jcallahan@77 | 430         if not source_list[action_data.identifier] then | 
| jcallahan@77 | 431             if top_field then | 
| jcallahan@77 | 432                 entry[top_field][loot_count] = (entry[top_field][loot_count] or 0) + 1 | 
| jcallahan@77 | 433             else | 
| jcallahan@77 | 434                 entry[loot_count] = (entry[loot_count] or 0) + 1 | 
| jcallahan@77 | 435             end | 
| jcallahan@77 | 436         end | 
| jcallahan@75 | 437 | 
| jcallahan@75 | 438         for index = 1, #action_data.loot_list do | 
| jcallahan@75 | 439             table.insert(loot_table, action_data.loot_list[index]) | 
| jcallahan@75 | 440         end | 
| jcallahan@48 | 441     end | 
| jcallahan@75 | 442 end -- do-block | 
| jcallahan@48 | 443 | 
| jcallahan@0 | 444 ----------------------------------------------------------------------- | 
| jcallahan@0 | 445 -- Methods. | 
| jcallahan@0 | 446 ----------------------------------------------------------------------- | 
| jcallahan@0 | 447 function WDP:OnInitialize() | 
| jcallahan@0 | 448     db = LibStub("AceDB-3.0"):New("WoWDBProfilerData", DATABASE_DEFAULTS, "Default").global | 
| jcallahan@14 | 449 | 
| jcallahan@14 | 450     local raw_db = _G["WoWDBProfilerData"] | 
| jcallahan@18 | 451     local build_num = tonumber(private.build_num) | 
| jcallahan@14 | 452 | 
| jcallahan@74 | 453     -- TODO: Merge this with the DB version check when MoP goes live. | 
| jcallahan@35 | 454     --    if raw_db.build_num and raw_db.build_num < build_num then | 
| jcallahan@74 | 455     if raw_db.version and raw_db.version < DB_VERSION then | 
| jcallahan@74 | 456         for entry in pairs(DATABASE_DEFAULTS.global) do | 
| jcallahan@74 | 457             db[entry] = {} | 
| jcallahan@74 | 458         end | 
| jcallahan@74 | 459     end | 
| jcallahan@35 | 460     raw_db.build_num = build_num | 
| jcallahan@63 | 461     raw_db.version = DB_VERSION | 
| jcallahan@0 | 462 end | 
| jcallahan@0 | 463 | 
| jcallahan@0 | 464 | 
| jcallahan@0 | 465 function WDP:OnEnable() | 
| jcallahan@0 | 466     for event_name, mapping in pairs(EVENT_MAPPING) do | 
| jcallahan@1 | 467         self:RegisterEvent(event_name, (_G.type(mapping) ~= "boolean") and mapping or nil) | 
| jcallahan@0 | 468     end | 
| jcallahan@0 | 469     durability_timer_handle = self:ScheduleRepeatingTimer("ProcessDurability", 30) | 
| jcallahan@31 | 470     target_location_timer_handle = self:ScheduleRepeatingTimer("UpdateTargetLocation", 0.5) | 
| jcallahan@19 | 471 | 
| jcallahan@19 | 472     _G.hooksecurefunc("UseContainerItem", function(bag_index, slot_index, target_unit) | 
| jcallahan@19 | 473         if target_unit then | 
| jcallahan@19 | 474             return | 
| jcallahan@19 | 475         end | 
| jcallahan@19 | 476         HandleItemUse(_G.GetContainerItemLink(bag_index, slot_index), bag_index, slot_index) | 
| jcallahan@19 | 477     end) | 
| jcallahan@19 | 478 | 
| jcallahan@19 | 479     _G.hooksecurefunc("UseItemByName", function(identifier, target_unit) | 
| jcallahan@19 | 480         if target_unit then | 
| jcallahan@19 | 481             return | 
| jcallahan@19 | 482         end | 
| jcallahan@19 | 483         local _, item_link = _G.GetItemInfo(identifier) | 
| jcallahan@19 | 484         HandleItemUse(item_link) | 
| jcallahan@19 | 485     end) | 
| jcallahan@0 | 486 end | 
| jcallahan@0 | 487 | 
| jcallahan@0 | 488 | 
| jcallahan@0 | 489 local function RecordDurability(item_id, durability) | 
| jcallahan@0 | 490     if not durability or durability <= 0 then | 
| jcallahan@0 | 491         return | 
| jcallahan@0 | 492     end | 
| jcallahan@0 | 493 | 
| jcallahan@0 | 494     if not db.items[item_id] then | 
| jcallahan@0 | 495         db.items[item_id] = {} | 
| jcallahan@0 | 496     end | 
| jcallahan@0 | 497     db.items[item_id].durability = durability | 
| jcallahan@0 | 498 end | 
| jcallahan@0 | 499 | 
| jcallahan@0 | 500 | 
| jcallahan@0 | 501 function WDP:ProcessDurability() | 
| jcallahan@0 | 502     for slot_index = 0, _G.INVSLOT_LAST_EQUIPPED do | 
| jcallahan@1 | 503         local item_id = _G.GetInventoryItemID("player", slot_index) | 
| jcallahan@0 | 504 | 
| jcallahan@0 | 505         if item_id and item_id > 0 then | 
| jcallahan@1 | 506             local _, max_durability = _G.GetInventoryItemDurability(slot_index) | 
| jcallahan@0 | 507             RecordDurability(item_id, max_durability) | 
| jcallahan@0 | 508         end | 
| jcallahan@0 | 509     end | 
| jcallahan@0 | 510 | 
| jcallahan@0 | 511     for bag_index = 0, _G.NUM_BAG_SLOTS do | 
| jcallahan@0 | 512         for slot_index = 1, _G.GetContainerNumSlots(bag_index) do | 
| jcallahan@1 | 513             local item_id = _G.GetContainerItemID(bag_index, slot_index) | 
| jcallahan@0 | 514 | 
| jcallahan@0 | 515             if item_id and item_id > 0 then | 
| jcallahan@1 | 516                 local _, max_durability = _G.GetContainerItemDurability(bag_index, slot_index) | 
| jcallahan@0 | 517                 RecordDurability(item_id, max_durability) | 
| jcallahan@0 | 518             end | 
| jcallahan@0 | 519         end | 
| jcallahan@0 | 520     end | 
| jcallahan@0 | 521 end | 
| jcallahan@0 | 522 | 
| jcallahan@0 | 523 | 
| jcallahan@2 | 524 function WDP:UpdateTargetLocation() | 
| jcallahan@40 | 525     if currently_drunk or not _G.UnitExists("target") or _G.UnitPlayerControlled("target") or (_G.UnitIsTapped("target") and not _G.UnitIsDead("target")) then | 
| jcallahan@2 | 526         return | 
| jcallahan@2 | 527     end | 
| jcallahan@2 | 528 | 
| jcallahan@2 | 529     for index = 1, 4 do | 
| jcallahan@2 | 530         if not _G.CheckInteractDistance("target", index) then | 
| jcallahan@2 | 531             return | 
| jcallahan@2 | 532         end | 
| jcallahan@2 | 533     end | 
| jcallahan@40 | 534     local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("target")) | 
| jcallahan@2 | 535 | 
| jcallahan@40 | 536     if not unit_idnum or unit_type ~= private.UNIT_TYPES.NPC then | 
| jcallahan@2 | 537         return | 
| jcallahan@2 | 538     end | 
| jcallahan@34 | 539     UpdateNPCLocation(unit_idnum) | 
| jcallahan@2 | 540 end | 
| jcallahan@2 | 541 | 
| jcallahan@2 | 542 | 
| jcallahan@0 | 543 ----------------------------------------------------------------------- | 
| jcallahan@0 | 544 -- Event handlers. | 
| jcallahan@0 | 545 ----------------------------------------------------------------------- | 
| jcallahan@56 | 546 function WDP:BLACK_MARKET_ITEM_UPDATE(event) | 
| jcallahan@56 | 547     local num_items = _G.C_BlackMarket.GetNumItems() | 
| jcallahan@56 | 548 | 
| jcallahan@56 | 549     for index = 1, num_items do | 
| jcallahan@56 | 550         local name, texture, quantity, item_type, is_usable, level, level_type, seller_name, min_bid, min_increment, current_bid, has_high_bid, num_bids, time_left, item_link, market_id = _G.C_BlackMarket.GetItemInfoByIndex(index); | 
| jcallahan@56 | 551 | 
| jcallahan@56 | 552         if item_link then | 
| jcallahan@56 | 553             DBEntry("items", ItemLinkToID(item_link)).black_market = seller_name or "UNKNOWN" | 
| jcallahan@56 | 554         end | 
| jcallahan@56 | 555     end | 
| jcallahan@56 | 556 end | 
| jcallahan@56 | 557 | 
| jcallahan@56 | 558 | 
| jcallahan@75 | 559 function WDP:CHAT_MSG_LOOT(event_name, message) | 
| jcallahan@48 | 560     if action_data.spell_label ~= "EXTRACT_GAS" then | 
| jcallahan@48 | 561         return | 
| jcallahan@48 | 562     end | 
| jcallahan@48 | 563     local item_link, quantity = deformat(message, _G.LOOT_ITEM_PUSHED_SELF_MULTIPLE) | 
| jcallahan@48 | 564 | 
| jcallahan@48 | 565     if not item_link then | 
| jcallahan@48 | 566         quantity, item_link = 1, deformat(message, _G.LOOT_ITEM_PUSHED_SELF) | 
| jcallahan@48 | 567     end | 
| jcallahan@48 | 568 | 
| jcallahan@48 | 569     if not item_link then | 
| jcallahan@48 | 570         return | 
| jcallahan@48 | 571     end | 
| jcallahan@48 | 572     local item_id = ItemLinkToID(item_link) | 
| jcallahan@48 | 573 | 
| jcallahan@48 | 574     if not item_id then | 
| jcallahan@48 | 575         return | 
| jcallahan@48 | 576     end | 
| jcallahan@48 | 577     action_data.loot_list = { | 
| jcallahan@48 | 578         ("%d:%d"):format(item_id, quantity) | 
| jcallahan@48 | 579     } | 
| jcallahan@48 | 580     GenericLootUpdate("zones") | 
| jcallahan@48 | 581     table.wipe(action_data) | 
| jcallahan@48 | 582 end | 
| jcallahan@48 | 583 | 
| jcallahan@48 | 584 | 
| jcallahan@23 | 585 do | 
| jcallahan@40 | 586     local SOBER_MATCH = _G.DRUNK_MESSAGE_ITEM_SELF1:gsub("%%s", ".+") | 
| jcallahan@40 | 587 | 
| jcallahan@40 | 588     local DRUNK_COMPARES = { | 
| jcallahan@40 | 589         _G.DRUNK_MESSAGE_SELF2, | 
| jcallahan@40 | 590         _G.DRUNK_MESSAGE_SELF3, | 
| jcallahan@40 | 591         _G.DRUNK_MESSAGE_SELF4, | 
| jcallahan@40 | 592     } | 
| jcallahan@40 | 593 | 
| jcallahan@40 | 594     local DRUNK_MATCHES = { | 
| jcallahan@40 | 595         _G.DRUNK_MESSAGE_SELF2:gsub("%%s", ".+"), | 
| jcallahan@40 | 596         _G.DRUNK_MESSAGE_SELF3:gsub("%%s", ".+"), | 
| jcallahan@40 | 597         _G.DRUNK_MESSAGE_SELF4:gsub("%%s", ".+"), | 
| jcallahan@40 | 598     } | 
| jcallahan@40 | 599 | 
| jcallahan@40 | 600     function WDP:CHAT_MSG_SYSTEM(event, message) | 
| jcallahan@40 | 601         if currently_drunk then | 
| jcallahan@40 | 602             if message == _G.DRUNK_MESSAGE_SELF1 or message:match(SOBER_MATCH) then | 
| jcallahan@40 | 603                 currently_drunk = nil | 
| jcallahan@40 | 604             end | 
| jcallahan@40 | 605             return | 
| jcallahan@40 | 606         end | 
| jcallahan@40 | 607 | 
| jcallahan@40 | 608         for index = 1, #DRUNK_MATCHES do | 
| jcallahan@40 | 609             if message == DRUNK_COMPARES[index] or message:match(DRUNK_MATCHES[index]) then | 
| jcallahan@40 | 610                 currently_drunk = true | 
| jcallahan@40 | 611                 break | 
| jcallahan@40 | 612             end | 
| jcallahan@40 | 613         end | 
| jcallahan@40 | 614     end | 
| jcallahan@40 | 615 end | 
| jcallahan@40 | 616 | 
| jcallahan@40 | 617 -- do-block | 
| jcallahan@40 | 618 | 
| jcallahan@40 | 619 do | 
| jcallahan@23 | 620     local FLAGS_NPC = bit.bor(_G.COMBATLOG_OBJECT_TYPE_GUARDIAN, _G.COMBATLOG_OBJECT_CONTROL_NPC) | 
| jcallahan@23 | 621     local FLAGS_NPC_CONTROL = bit.bor(_G.COMBATLOG_OBJECT_AFFILIATION_OUTSIDER, _G.COMBATLOG_OBJECT_CONTROL_NPC) | 
| jcallahan@23 | 622 | 
| jcallahan@23 | 623     local function RecordNPCSpell(sub_event, source_guid, source_name, source_flags, dest_guid, dest_name, dest_flags, spell_id, spell_name) | 
| jcallahan@23 | 624         if not spell_id then | 
| jcallahan@23 | 625             return | 
| jcallahan@23 | 626         end | 
| jcallahan@34 | 627         local source_type, source_id = ParseGUID(source_guid) | 
| jcallahan@23 | 628 | 
| jcallahan@23 | 629         if not source_id or source_type ~= private.UNIT_TYPES.NPC then | 
| jcallahan@23 | 630             return | 
| jcallahan@23 | 631         end | 
| jcallahan@23 | 632 | 
| jcallahan@23 | 633         if bit.band(FLAGS_NPC_CONTROL, source_flags) == FLAGS_NPC_CONTROL and bit.band(FLAGS_NPC, source_flags) ~= 0 then | 
| jcallahan@29 | 634             local encounter_data = NPCEntry(source_id).encounter_data[InstanceDifficultyToken()] | 
| jcallahan@28 | 635             encounter_data.spells = encounter_data.spells or {} | 
| jcallahan@28 | 636             encounter_data.spells[spell_id] = (encounter_data.spells[spell_id] or 0) + 1 | 
| jcallahan@23 | 637         end | 
| jcallahan@23 | 638     end | 
| jcallahan@23 | 639 | 
| jcallahan@23 | 640     local COMBAT_LOG_FUNCS = { | 
| jcallahan@23 | 641         SPELL_AURA_APPLIED = RecordNPCSpell, | 
| jcallahan@23 | 642         SPELL_CAST_START = RecordNPCSpell, | 
| jcallahan@48 | 643         SPELL_CAST_SUCCESS = RecordNPCSpell, | 
| jcallahan@65 | 644         UNIT_DIED = function(sub_event, source_guid, source_name, source_flags, dest_guid, dest_name, dest_flags, spell_id, spell_name) | 
| jcallahan@65 | 645             local unit_type, unit_idnum = ParseGUID(dest_guid) | 
| jcallahan@65 | 646 | 
| jcallahan@65 | 647             if unit_type ~= private.UNIT_TYPES.NPC or not unit_idnum then | 
| jcallahan@67 | 648                 reputation_npc_id = nil | 
| jcallahan@65 | 649                 return | 
| jcallahan@65 | 650             end | 
| jcallahan@67 | 651             reputation_npc_id = unit_idnum | 
| jcallahan@65 | 652         end, | 
| jcallahan@23 | 653     } | 
| jcallahan@23 | 654 | 
| jcallahan@23 | 655 | 
| jcallahan@23 | 656     function WDP:COMBAT_LOG_EVENT_UNFILTERED(event, time_stamp, sub_event, hide_caster, source_guid, source_name, source_flags, source_raid_flags, dest_guid, dest_name, dest_flags, dest_raid_flags, ...) | 
| jcallahan@23 | 657         local combat_log_func = COMBAT_LOG_FUNCS[sub_event] | 
| jcallahan@23 | 658 | 
| jcallahan@23 | 659         if not combat_log_func then | 
| jcallahan@23 | 660             return | 
| jcallahan@23 | 661         end | 
| jcallahan@23 | 662         combat_log_func(sub_event, source_guid, source_name, source_flags, dest_guid, dest_name, dest_flags, ...) | 
| jcallahan@23 | 663     end | 
| jcallahan@23 | 664 | 
| jcallahan@44 | 665     local DIPLOMACY_SPELL_ID = 20599 | 
| jcallahan@44 | 666     local MR_POP_RANK1_SPELL_ID = 78634 | 
| jcallahan@44 | 667     local MR_POP_RANK2_SPELL_ID = 78635 | 
| jcallahan@44 | 668 | 
| jcallahan@44 | 669     local REP_BUFFS = { | 
| jcallahan@44 | 670         [_G.GetSpellInfo(30754)] = "CENARION_FAVOR", | 
| jcallahan@44 | 671         [_G.GetSpellInfo(24705)] = "GRIM_VISAGE", | 
| jcallahan@44 | 672         [_G.GetSpellInfo(32098)] = "HONOR_HOLD_FAVOR", | 
| jcallahan@44 | 673         [_G.GetSpellInfo(39913)] = "NAZGRELS_FERVOR", | 
| jcallahan@44 | 674         [_G.GetSpellInfo(39953)] = "SONG_OF_BATTLE", | 
| jcallahan@44 | 675         [_G.GetSpellInfo(61849)] = "SPIRIT_OF_SHARING", | 
| jcallahan@44 | 676         [_G.GetSpellInfo(32096)] = "THRALLMARS_FAVOR", | 
| jcallahan@44 | 677         [_G.GetSpellInfo(39911)] = "TROLLBANES_COMMAND", | 
| jcallahan@44 | 678         [_G.GetSpellInfo(95987)] = "UNBURDENED", | 
| jcallahan@44 | 679         [_G.GetSpellInfo(100951)] = "WOW_ANNIVERSARY", | 
| jcallahan@44 | 680     } | 
| jcallahan@44 | 681 | 
| jcallahan@44 | 682 | 
| jcallahan@44 | 683     local FACTION_NAMES = { | 
| jcallahan@44 | 684         CENARION_CIRCLE = _G.GetFactionInfoByID(609), | 
| jcallahan@44 | 685         HONOR_HOLD = _G.GetFactionInfoByID(946), | 
| jcallahan@44 | 686         THE_SHATAR = _G.GetFactionInfoByID(935), | 
| jcallahan@44 | 687         THRALLMAR = _G.GetFactionInfoByID(947), | 
| jcallahan@44 | 688     } | 
| jcallahan@44 | 689 | 
| jcallahan@44 | 690 | 
| jcallahan@44 | 691     local MODIFIERS = { | 
| jcallahan@44 | 692         CENARION_FAVOR = { | 
| jcallahan@44 | 693             faction = FACTION_NAMES.CENARION_CIRCLE, | 
| jcallahan@44 | 694             modifier = 0.25, | 
| jcallahan@44 | 695         }, | 
| jcallahan@44 | 696         GRIM_VISAGE = { | 
| jcallahan@44 | 697             modifier = 0.1, | 
| jcallahan@44 | 698         }, | 
| jcallahan@44 | 699         HONOR_HOLD_FAVOR = { | 
| jcallahan@44 | 700             faction = FACTION_NAMES.HONOR_HOLD, | 
| jcallahan@44 | 701             modifier = 0.25, | 
| jcallahan@44 | 702         }, | 
| jcallahan@44 | 703         NAZGRELS_FERVOR = { | 
| jcallahan@44 | 704             faction = FACTION_NAMES.THRALLMAR, | 
| jcallahan@44 | 705             modifier = 0.1, | 
| jcallahan@44 | 706         }, | 
| jcallahan@44 | 707         SONG_OF_BATTLE = { | 
| jcallahan@44 | 708             faction = FACTION_NAMES.THE_SHATAR, | 
| jcallahan@44 | 709             modifier = 0.1, | 
| jcallahan@44 | 710         }, | 
| jcallahan@44 | 711         SPIRIT_OF_SHARING = { | 
| jcallahan@44 | 712             modifier = 0.1, | 
| jcallahan@44 | 713         }, | 
| jcallahan@44 | 714         THRALLMARS_FAVOR = { | 
| jcallahan@44 | 715             faction = FACTION_NAMES.THRALLMAR, | 
| jcallahan@44 | 716             modifier = 0.25, | 
| jcallahan@44 | 717         }, | 
| jcallahan@44 | 718         TROLLBANES_COMMAND = { | 
| jcallahan@44 | 719             faction = FACTION_NAMES.HONOR_HOLD, | 
| jcallahan@44 | 720             modifier = 0.1, | 
| jcallahan@44 | 721         }, | 
| jcallahan@44 | 722         UNBURDENED = { | 
| jcallahan@44 | 723             modifier = 0.1, | 
| jcallahan@44 | 724         }, | 
| jcallahan@44 | 725         WOW_ANNIVERSARY = { | 
| jcallahan@44 | 726             modifier = 0.08, | 
| jcallahan@44 | 727         } | 
| jcallahan@44 | 728     } | 
| jcallahan@44 | 729 | 
| jcallahan@44 | 730 | 
| jcallahan@44 | 731     function WDP:COMBAT_TEXT_UPDATE(event, message_type, faction_name, amount) | 
| jcallahan@67 | 732         if message_type ~= "FACTION" or not reputation_npc_id then | 
| jcallahan@44 | 733             return | 
| jcallahan@44 | 734         end | 
| jcallahan@44 | 735         UpdateFactionData() | 
| jcallahan@44 | 736 | 
| jcallahan@46 | 737         if not faction_name or not faction_standings[faction_name] then | 
| jcallahan@46 | 738             return | 
| jcallahan@46 | 739         end | 
| jcallahan@67 | 740         local npc = NPCEntry(reputation_npc_id) | 
| jcallahan@46 | 741 | 
| jcallahan@44 | 742         if not npc then | 
| jcallahan@44 | 743             return | 
| jcallahan@44 | 744         end | 
| jcallahan@44 | 745         local modifier = 1 | 
| jcallahan@44 | 746 | 
| jcallahan@44 | 747         if _G.IsSpellKnown(DIPLOMACY_SPELL_ID) then | 
| jcallahan@44 | 748             modifier = modifier + 0.1 | 
| jcallahan@44 | 749         end | 
| jcallahan@44 | 750 | 
| jcallahan@44 | 751         if _G.IsSpellKnown(MR_POP_RANK2_SPELL_ID) then | 
| jcallahan@44 | 752             modifier = modifier + 0.1 | 
| jcallahan@44 | 753         elseif _G.IsSpellKnown(MR_POP_RANK1_SPELL_ID) then | 
| jcallahan@44 | 754             modifier = modifier + 0.05 | 
| jcallahan@44 | 755         end | 
| jcallahan@44 | 756 | 
| jcallahan@44 | 757         for buff_name, buff_label in pairs(REP_BUFFS) do | 
| jcallahan@44 | 758             if _G.UnitBuff("player", buff_name) then | 
| jcallahan@44 | 759                 local modded_faction = MODIFIERS[buff_label].faction | 
| jcallahan@44 | 760 | 
| jcallahan@44 | 761                 if not modded_faction or faction_name == modded_faction then | 
| jcallahan@44 | 762                     modifier = modifier + MODIFIERS[buff_label].modifier | 
| jcallahan@44 | 763                 end | 
| jcallahan@44 | 764             end | 
| jcallahan@44 | 765         end | 
| jcallahan@65 | 766         npc.reputations = npc.reputations or {} | 
| jcallahan@65 | 767         npc.reputations[("%s:%s"):format(faction_name, faction_standings[faction_name])] = math.floor(amount / modifier) | 
| jcallahan@67 | 768         reputation_npc_id = nil | 
| jcallahan@32 | 769     end | 
| jcallahan@44 | 770 end -- do-block | 
| jcallahan@18 | 771 | 
| jcallahan@18 | 772 | 
| jcallahan@42 | 773 function WDP:ITEM_TEXT_BEGIN() | 
| jcallahan@42 | 774     local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("npc")) | 
| jcallahan@42 | 775 | 
| jcallahan@42 | 776     if not unit_idnum or unit_type ~= private.UNIT_TYPES.OBJECT or _G.UnitName("npc") ~= _G.ItemTextGetItem() then | 
| jcallahan@42 | 777         return | 
| jcallahan@42 | 778     end | 
| jcallahan@42 | 779     UpdateDBEntryLocation("objects", unit_idnum) | 
| jcallahan@42 | 780 end | 
| jcallahan@42 | 781 | 
| jcallahan@42 | 782 | 
| jcallahan@13 | 783 do | 
| jcallahan@40 | 784     local RE_GOLD = _G.GOLD_AMOUNT:gsub("%%d", "(%%d+)") | 
| jcallahan@40 | 785     local RE_SILVER = _G.SILVER_AMOUNT:gsub("%%d", "(%%d+)") | 
| jcallahan@40 | 786     local RE_COPPER = _G.COPPER_AMOUNT:gsub("%%d", "(%%d+)") | 
| jcallahan@13 | 787 | 
| jcallahan@13 | 788 | 
| jcallahan@13 | 789     local function _moneyMatch(money, re) | 
| jcallahan@13 | 790         return money:match(re) or 0 | 
| jcallahan@1 | 791     end | 
| jcallahan@1 | 792 | 
| jcallahan@0 | 793 | 
| jcallahan@13 | 794     local function _toCopper(money) | 
| jcallahan@13 | 795         if not money then | 
| jcallahan@13 | 796             return 0 | 
| jcallahan@13 | 797         end | 
| jcallahan@40 | 798         return _moneyMatch(money, RE_GOLD) * 10000 + _moneyMatch(money, RE_SILVER) * 100 + _moneyMatch(money, RE_COPPER) | 
| jcallahan@1 | 799     end | 
| jcallahan@1 | 800 | 
| jcallahan@1 | 801 | 
| jcallahan@13 | 802     local LOOT_VERIFY_FUNCS = { | 
| jcallahan@16 | 803         [AF.ITEM] = function() | 
| jcallahan@16 | 804             local locked_item_id | 
| jcallahan@16 | 805 | 
| jcallahan@16 | 806             for bag_index = 0, _G.NUM_BAG_FRAMES do | 
| jcallahan@16 | 807                 for slot_index = 1, _G.GetContainerNumSlots(bag_index) do | 
| jcallahan@16 | 808                     local _, _, is_locked = _G.GetContainerItemInfo(bag_index, slot_index) | 
| jcallahan@16 | 809 | 
| jcallahan@16 | 810                     if is_locked then | 
| jcallahan@16 | 811                         locked_item_id = ItemLinkToID(_G.GetContainerItemLink(bag_index, slot_index)) | 
| jcallahan@16 | 812                     end | 
| jcallahan@16 | 813                 end | 
| jcallahan@16 | 814             end | 
| jcallahan@16 | 815 | 
| jcallahan@28 | 816             if not locked_item_id or (action_data.identifier and action_data.identifier ~= locked_item_id) then | 
| jcallahan@16 | 817                 return false | 
| jcallahan@16 | 818             end | 
| jcallahan@28 | 819             action_data.identifier = locked_item_id | 
| jcallahan@16 | 820             return true | 
| jcallahan@16 | 821         end, | 
| jcallahan@13 | 822         [AF.NPC] = function() | 
| jcallahan@17 | 823             if not _G.UnitExists("target") or _G.UnitIsFriend("player", "target") or _G.UnitIsPlayer("target") or _G.UnitPlayerControlled("target") then | 
| jcallahan@15 | 824                 return false | 
| jcallahan@13 | 825             end | 
| jcallahan@34 | 826             local unit_type, id_num = ParseGUID(_G.UnitGUID("target")) | 
| jcallahan@27 | 827             action_data.identifier = id_num | 
| jcallahan@13 | 828             return true | 
| jcallahan@13 | 829         end, | 
| jcallahan@14 | 830         [AF.OBJECT] = true, | 
| jcallahan@17 | 831         [AF.ZONE] = function() | 
| jcallahan@38 | 832             return _G.IsFishingLoot() | 
| jcallahan@17 | 833         end, | 
| jcallahan@13 | 834     } | 
| jcallahan@13 | 835 | 
| jcallahan@13 | 836 | 
| jcallahan@13 | 837     local LOOT_UPDATE_FUNCS = { | 
| jcallahan@16 | 838         [AF.ITEM] = function() | 
| jcallahan@28 | 839             GenericLootUpdate("items") | 
| jcallahan@28 | 840         end, | 
| jcallahan@28 | 841         [AF.NPC] = function() | 
| jcallahan@75 | 842             local difficulty_token = InstanceDifficultyToken() | 
| jcallahan@75 | 843             local loot_type = action_data.label or "drops" | 
| jcallahan@77 | 844             local source_list = {} | 
| jcallahan@75 | 845 | 
| jcallahan@75 | 846             for source_id, loot_data in pairs(action_data.loot_sources) do | 
| jcallahan@75 | 847                 local npc = NPCEntry(source_id) | 
| jcallahan@75 | 848 | 
| jcallahan@75 | 849                 if npc then | 
| jcallahan@75 | 850                     local encounter_data = npc.encounter_data[difficulty_token] | 
| jcallahan@75 | 851                     encounter_data[loot_type] = encounter_data[loot_type] or {} | 
| jcallahan@75 | 852 | 
| jcallahan@77 | 853                     if not source_list[source_id] then | 
| jcallahan@77 | 854                         encounter_data.loot_counts = encounter_data.loot_counts or {} | 
| jcallahan@77 | 855                         encounter_data.loot_counts[loot_type] = (encounter_data.loot_counts[loot_type] or 0) + 1 | 
| jcallahan@77 | 856                         source_list[source_id] = true | 
| jcallahan@77 | 857                     end | 
| jcallahan@77 | 858 | 
| jcallahan@75 | 859                     for item_id, quantity in pairs(loot_data) do | 
| jcallahan@75 | 860                         table.insert(encounter_data[loot_type], ("%d:%d"):format(item_id, quantity)) | 
| jcallahan@75 | 861                     end | 
| jcallahan@75 | 862                 end | 
| jcallahan@75 | 863             end | 
| jcallahan@75 | 864 | 
| jcallahan@75 | 865             -- TODO: Remove this when GetLootSourceInfo() has values for money | 
| jcallahan@29 | 866             local npc = NPCEntry(action_data.identifier) | 
| jcallahan@28 | 867 | 
| jcallahan@28 | 868             if not npc then | 
| jcallahan@28 | 869                 return | 
| jcallahan@28 | 870             end | 
| jcallahan@75 | 871             local encounter_data = npc.encounter_data[difficulty_token] | 
| jcallahan@29 | 872             encounter_data[loot_type] = encounter_data[loot_type] or {} | 
| jcallahan@16 | 873 | 
| jcallahan@77 | 874             if not source_list[action_data.identifier] then | 
| jcallahan@77 | 875                 encounter_data.loot_counts = encounter_data.loot_counts or {} | 
| jcallahan@77 | 876                 encounter_data.loot_counts[loot_type] = (encounter_data.loot_counts[loot_type] or 0) + 1 | 
| jcallahan@77 | 877             end | 
| jcallahan@77 | 878 | 
| jcallahan@17 | 879             for index = 1, #action_data.loot_list do | 
| jcallahan@29 | 880                 table.insert(encounter_data[loot_type], action_data.loot_list[index]) | 
| jcallahan@16 | 881             end | 
| jcallahan@16 | 882         end, | 
| jcallahan@13 | 883         [AF.OBJECT] = function() | 
| jcallahan@28 | 884             GenericLootUpdate("objects", InstanceDifficultyToken()) | 
| jcallahan@17 | 885         end, | 
| jcallahan@17 | 886         [AF.ZONE] = function() | 
| jcallahan@41 | 887             local location_token = ("%s:%s:%s"):format(action_data.map_level, action_data.x, action_data.y) | 
| jcallahan@41 | 888 | 
| jcallahan@41 | 889             -- This will start life as a boolean true. | 
| jcallahan@41 | 890             if _G.type(action_data.zone_data[location_token]) ~= "table" then | 
| jcallahan@41 | 891                 action_data.zone_data[location_token] = { | 
| jcallahan@41 | 892                     drops = {} | 
| jcallahan@41 | 893                 } | 
| jcallahan@41 | 894             end | 
| jcallahan@41 | 895             local loot_count = ("%s_count"):format(action_data.label or "drops") | 
| jcallahan@41 | 896             action_data.zone_data[location_token][loot_count] = (action_data.zone_data[location_token][loot_count] or 0) + 1 | 
| jcallahan@41 | 897 | 
| jcallahan@41 | 898             for index = 1, #action_data.loot_list do | 
| jcallahan@41 | 899                 table.insert(action_data.zone_data[location_token].drops, action_data.loot_list[index]) | 
| jcallahan@41 | 900             end | 
| jcallahan@13 | 901         end, | 
| jcallahan@13 | 902     } | 
| jcallahan@13 | 903 | 
| jcallahan@13 | 904 | 
| jcallahan@13 | 905     function WDP:LOOT_OPENED() | 
| jcallahan@18 | 906         if action_data.looting then | 
| jcallahan@18 | 907             return | 
| jcallahan@18 | 908         end | 
| jcallahan@18 | 909 | 
| jcallahan@13 | 910         if not action_data.type then | 
| jcallahan@13 | 911             action_data.type = AF.NPC | 
| jcallahan@1 | 912         end | 
| jcallahan@13 | 913         local verify_func = LOOT_VERIFY_FUNCS[action_data.type] | 
| jcallahan@13 | 914         local update_func = LOOT_UPDATE_FUNCS[action_data.type] | 
| jcallahan@13 | 915 | 
| jcallahan@14 | 916         if not verify_func or not update_func then | 
| jcallahan@13 | 917             return | 
| jcallahan@13 | 918         end | 
| jcallahan@13 | 919 | 
| jcallahan@14 | 920         if _G.type(verify_func) == "function" and not verify_func() then | 
| jcallahan@14 | 921             return | 
| jcallahan@14 | 922         end | 
| jcallahan@17 | 923         action_data.loot_list = {} | 
| jcallahan@75 | 924         action_data.loot_sources = {} | 
| jcallahan@18 | 925         action_data.looting = true | 
| jcallahan@13 | 926 | 
| jcallahan@55 | 927         for loot_slot = 1, _G.GetNumLootItems() do | 
| jcallahan@55 | 928             local icon_texture, item_text, quantity, quality, locked = _G.GetLootSlotInfo(loot_slot) | 
| jcallahan@55 | 929             local slot_type = _G.GetLootSlotType(loot_slot) | 
| jcallahan@13 | 930 | 
| jcallahan@77 | 931             -- TODO: Move LOOT_SLOT_X checks within loop when money is detectable via GetLootSourceInfo | 
| jcallahan@77 | 932             if slot_type == _G.LOOT_SLOT_ITEM then | 
| jcallahan@77 | 933                 local sources = { | 
| jcallahan@77 | 934                     _G.GetLootSourceInfo(loot_slot) | 
| jcallahan@77 | 935                 } | 
| jcallahan@75 | 936 | 
| jcallahan@75 | 937                 -- TODO: Remove debugging | 
| jcallahan@77 | 938                 --            print(("Loot slot %d: Source count: %d"):format(loot_slot, floor((#sources / 2) + 0.5))) | 
| jcallahan@75 | 939 | 
| jcallahan@77 | 940                 -- Odd index is GUID, even is count. | 
| jcallahan@77 | 941                 for source_index = 1, #sources, 2 do | 
| jcallahan@77 | 942                     local source_type, source_id = ParseGUID(sources[source_index]) | 
| jcallahan@77 | 943                     local source_count = sources[source_index + 1] | 
| jcallahan@77 | 944                     local source_key = ("%s:%d"):format(private.UNIT_TYPE_NAMES[source_type + 1], source_id) | 
| jcallahan@77 | 945                     -- TODO: Remove debugging | 
| jcallahan@77 | 946                     --                print(("GUID: %s - Type:ID: %s - Amount: %d"):format(sources[source_index], source_key, source_count)) | 
| jcallahan@77 | 947 | 
| jcallahan@77 | 948                     -- Items return the player as the source, so we need to replace the nil ID with the item's ID (disenchant, milling, etc) | 
| jcallahan@77 | 949                     if not source_id then | 
| jcallahan@77 | 950                         source_id = action_data.identifier | 
| jcallahan@77 | 951                     elseif action_data.type == AF.OBJECT then | 
| jcallahan@77 | 952                         source_id = ("%s:%s"):format(action_data.spell_label, source_id) | 
| jcallahan@77 | 953                     end | 
| jcallahan@77 | 954                     local item_id = ItemLinkToID(_G.GetLootSlotLink(loot_slot)) | 
| jcallahan@77 | 955                     action_data.loot_sources[source_id] = action_data.loot_sources[source_id] or {} | 
| jcallahan@77 | 956                     action_data.loot_sources[source_id][item_id] = action_data.loot_sources[source_id][item_id] or 0 + source_count | 
| jcallahan@75 | 957                 end | 
| jcallahan@77 | 958             elseif slot_type == _G.LOOT_SLOT_MONEY then | 
| jcallahan@77 | 959                 table.insert(action_data.loot_list, ("money:%d"):format(_toCopper(item_text))) | 
| jcallahan@77 | 960             elseif slot_type == _G.LOOT_SLOT_CURRENCY then | 
| jcallahan@77 | 961                 table.insert(action_data.loot_list, ("currency:%d:%s"):format(quantity, icon_texture:match("[^\\]+$"):lower())) | 
| jcallahan@13 | 962             end | 
| jcallahan@13 | 963         end | 
| jcallahan@13 | 964         update_func() | 
| jcallahan@1 | 965     end | 
| jcallahan@13 | 966 end -- do-block | 
| jcallahan@0 | 967 | 
| jcallahan@0 | 968 | 
| jcallahan@44 | 969 do | 
| jcallahan@44 | 970     local POINT_MATCH_PATTERNS = { | 
| jcallahan@44 | 971         ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING:gsub("%%d", "(%%d+)")), -- May no longer be necessary | 
| jcallahan@44 | 972         ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_3V3:gsub("%%d", "(%%d+)")), -- May no longer be necessary | 
| jcallahan@44 | 973         ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_5V5:gsub("%%d", "(%%d+)")), -- May no longer be necessary | 
| jcallahan@44 | 974         ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_BG:gsub("%%d", "(%%d+)")), | 
| jcallahan@44 | 975         ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_3V3_BG:gsub("%%d", "(%%d+)")), | 
| jcallahan@44 | 976     } | 
| jcallahan@5 | 977 | 
| jcallahan@68 | 978     local ITEM_REQ_REPUTATION_MATCH = "Requires (.-) %- (.*)" | 
| jcallahan@68 | 979 | 
| jcallahan@44 | 980     function WDP:UpdateMerchantItems(event) | 
| jcallahan@44 | 981         local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("target")) | 
| jcallahan@4 | 982 | 
| jcallahan@44 | 983         if unit_type ~= private.UNIT_TYPES.NPC or not unit_idnum then | 
| jcallahan@44 | 984             return | 
| jcallahan@44 | 985         end | 
| jcallahan@55 | 986         local current_filters = _G.GetMerchantFilter() | 
| jcallahan@44 | 987         local _, merchant_standing = UnitFactionStanding("target") | 
| jcallahan@44 | 988         local merchant = NPCEntry(unit_idnum) | 
| jcallahan@44 | 989         merchant.sells = merchant.sells or {} | 
| jcallahan@5 | 990 | 
| jcallahan@57 | 991         _G.SetMerchantFilter(_G.LE_LOOT_FILTER_ALL) | 
| jcallahan@57 | 992         _G.MerchantFrame_Update() | 
| jcallahan@57 | 993 | 
| jcallahan@57 | 994         local num_items = _G.GetMerchantNumItems() | 
| jcallahan@35 | 995 | 
| jcallahan@44 | 996         for item_index = 1, num_items do | 
| jcallahan@44 | 997             local _, _, copper_price, stack_size, num_available, _, extended_cost = _G.GetMerchantItemInfo(item_index) | 
| jcallahan@44 | 998             local item_id = ItemLinkToID(_G.GetMerchantItemLink(item_index)) | 
| jcallahan@5 | 999 | 
| jcallahan@44 | 1000             if item_id and item_id > 0 then | 
| jcallahan@44 | 1001                 local price_string = ActualCopperCost(copper_price, merchant_standing) | 
| jcallahan@5 | 1002 | 
| jcallahan@68 | 1003                 DatamineTT:ClearLines() | 
| jcallahan@68 | 1004                 DatamineTT:SetMerchantItem(item_index) | 
| jcallahan@68 | 1005 | 
| jcallahan@68 | 1006                 local num_lines = DatamineTT:NumLines() | 
| jcallahan@68 | 1007 | 
| jcallahan@68 | 1008                 for line_index = 1, num_lines do | 
| jcallahan@68 | 1009                     local current_line = _G["WDPDatamineTTTextLeft" .. line_index] | 
| jcallahan@68 | 1010 | 
| jcallahan@68 | 1011                     if not current_line then | 
| jcallahan@68 | 1012                         break | 
| jcallahan@68 | 1013                     end | 
| jcallahan@68 | 1014                     local faction, reputation = current_line:GetText():match(ITEM_REQ_REPUTATION_MATCH) | 
| jcallahan@68 | 1015 | 
| jcallahan@68 | 1016                     if faction or reputation then | 
| jcallahan@68 | 1017                         DBEntry("items", item_id).req_reputation = ("%s:%s"):format(faction:gsub("-", ""), reputation:upper()) | 
| jcallahan@68 | 1018                         break | 
| jcallahan@68 | 1019                     end | 
| jcallahan@68 | 1020                 end | 
| jcallahan@68 | 1021 | 
| jcallahan@44 | 1022                 if extended_cost then | 
| jcallahan@53 | 1023                     local battleground_rating = 0 | 
| jcallahan@53 | 1024                     local personal_rating = 0 | 
| jcallahan@53 | 1025                     local required_season_amount | 
| jcallahan@5 | 1026 | 
| jcallahan@68 | 1027                     for line_index = 1, num_lines do | 
| jcallahan@44 | 1028                         local current_line = _G["WDPDatamineTTTextLeft" .. line_index] | 
| jcallahan@5 | 1029 | 
| jcallahan@44 | 1030                         if not current_line then | 
| jcallahan@44 | 1031                             break | 
| jcallahan@44 | 1032                         end | 
| jcallahan@53 | 1033                         required_season_amount = current_line:GetText():match("Requires earning a total of (%d+)\n(.-) for the season.") | 
| jcallahan@5 | 1034 | 
| jcallahan@44 | 1035                         for match_index = 1, #POINT_MATCH_PATTERNS do | 
| jcallahan@44 | 1036                             local match1, match2 = current_line:GetText():match(POINT_MATCH_PATTERNS[match_index]) | 
| jcallahan@53 | 1037                             personal_rating = personal_rating + (match1 or 0) | 
| jcallahan@53 | 1038                             battleground_rating = battleground_rating + (match2 or 0) | 
| jcallahan@5 | 1039 | 
| jcallahan@44 | 1040                             if match1 or match2 then | 
| jcallahan@44 | 1041                                 break | 
| jcallahan@44 | 1042                             end | 
| jcallahan@44 | 1043                         end | 
| jcallahan@5 | 1044                     end | 
| jcallahan@44 | 1045                     local currency_list = {} | 
| jcallahan@44 | 1046                     local item_count = _G.GetMerchantItemCostInfo(item_index) | 
| jcallahan@50 | 1047 | 
| jcallahan@50 | 1048                     -- Keeping this around in case Blizzard makes the two points diverge at some point. | 
| jcallahan@53 | 1049                     --                    price_string = ("%s:%s:%s:%s"):format(price_string, battleground_rating, personal_rating, required_season_amount or 0) | 
| jcallahan@53 | 1050                     price_string = ("%s:%s:%s"):format(price_string, personal_rating, required_season_amount or 0) | 
| jcallahan@5 | 1051 | 
| jcallahan@44 | 1052                     for cost_index = 1, item_count do | 
| jcallahan@44 | 1053                         local icon_texture, amount_required, currency_link = _G.GetMerchantItemCostItem(item_index, cost_index) | 
| jcallahan@44 | 1054                         local currency_id = currency_link and ItemLinkToID(currency_link) or nil | 
| jcallahan@44 | 1055 | 
| jcallahan@44 | 1056                         if (not currency_id or currency_id < 1) and icon_texture then | 
| jcallahan@44 | 1057                             currency_id = icon_texture:match("[^\\]+$"):lower() | 
| jcallahan@44 | 1058                         end | 
| jcallahan@44 | 1059 | 
| jcallahan@44 | 1060                         if currency_id then | 
| jcallahan@44 | 1061                             currency_list[#currency_list + 1] = ("(%s:%s)"):format(amount_required, currency_id) | 
| jcallahan@44 | 1062                         end | 
| jcallahan@44 | 1063                     end | 
| jcallahan@44 | 1064 | 
| jcallahan@44 | 1065                     for currency_index = 1, #currency_list do | 
| jcallahan@44 | 1066                         price_string = ("%s:%s"):format(price_string, currency_list[currency_index]) | 
| jcallahan@5 | 1067                     end | 
| jcallahan@5 | 1068                 end | 
| jcallahan@61 | 1069                 merchant.sells[item_id] = ("%s:%s:[%s]"):format(num_available, stack_size, price_string) | 
| jcallahan@44 | 1070             end | 
| jcallahan@44 | 1071         end | 
| jcallahan@5 | 1072 | 
| jcallahan@44 | 1073         if _G.CanMerchantRepair() then | 
| jcallahan@44 | 1074             merchant.can_repair = true | 
| jcallahan@5 | 1075         end | 
| jcallahan@57 | 1076         _G.SetMerchantFilter(current_filters) | 
| jcallahan@57 | 1077         _G.MerchantFrame_Update() | 
| jcallahan@4 | 1078     end | 
| jcallahan@44 | 1079 end -- do-block | 
| jcallahan@4 | 1080 | 
| jcallahan@25 | 1081 function WDP:PET_BAR_UPDATE() | 
| jcallahan@25 | 1082     if not action_data.label or not action_data.label == "mind_control" then | 
| jcallahan@25 | 1083         return | 
| jcallahan@25 | 1084     end | 
| jcallahan@34 | 1085     local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("pet")) | 
| jcallahan@25 | 1086 | 
| jcallahan@25 | 1087     if unit_type ~= private.UNIT_TYPES.NPC or not unit_idnum then | 
| jcallahan@25 | 1088         return | 
| jcallahan@25 | 1089     end | 
| jcallahan@29 | 1090     NPCEntry(unit_idnum).mind_control = true | 
| jcallahan@25 | 1091     table.wipe(action_data) | 
| jcallahan@25 | 1092 end | 
| jcallahan@25 | 1093 | 
| jcallahan@25 | 1094 | 
| jcallahan@18 | 1095 do | 
| jcallahan@18 | 1096     local GENDER_NAMES = { | 
| jcallahan@18 | 1097         "UNKNOWN", | 
| jcallahan@18 | 1098         "MALE", | 
| jcallahan@18 | 1099         "FEMALE", | 
| jcallahan@18 | 1100     } | 
| jcallahan@2 | 1101 | 
| jcallahan@2 | 1102 | 
| jcallahan@18 | 1103     local REACTION_NAMES = { | 
| jcallahan@18 | 1104         "HATED", | 
| jcallahan@18 | 1105         "HOSTILE", | 
| jcallahan@18 | 1106         "UNFRIENDLY", | 
| jcallahan@18 | 1107         "NEUTRAL", | 
| jcallahan@18 | 1108         "FRIENDLY", | 
| jcallahan@18 | 1109         "HONORED", | 
| jcallahan@18 | 1110         "REVERED", | 
| jcallahan@18 | 1111         "EXALTED", | 
| jcallahan@18 | 1112     } | 
| jcallahan@2 | 1113 | 
| jcallahan@2 | 1114 | 
| jcallahan@18 | 1115     local POWER_TYPE_NAMES = { | 
| jcallahan@18 | 1116         ["0"] = "MANA", | 
| jcallahan@18 | 1117         ["1"] = "RAGE", | 
| jcallahan@18 | 1118         ["2"] = "FOCUS", | 
| jcallahan@18 | 1119         ["3"] = "ENERGY", | 
| jcallahan@18 | 1120         ["6"] = "RUNIC_POWER", | 
| jcallahan@18 | 1121     } | 
| jcallahan@2 | 1122 | 
| jcallahan@2 | 1123 | 
| jcallahan@18 | 1124     function WDP:PLAYER_TARGET_CHANGED() | 
| jcallahan@40 | 1125         if not _G.UnitExists("target") or _G.UnitPlayerControlled("target") or currently_drunk then | 
| jcallahan@18 | 1126             return | 
| jcallahan@18 | 1127         end | 
| jcallahan@34 | 1128         local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("target")) | 
| jcallahan@2 | 1129 | 
| jcallahan@18 | 1130         if unit_type ~= private.UNIT_TYPES.NPC or not unit_idnum then | 
| jcallahan@18 | 1131             return | 
| jcallahan@18 | 1132         end | 
| jcallahan@29 | 1133         local npc = NPCEntry(unit_idnum) | 
| jcallahan@18 | 1134         local _, class_token = _G.UnitClass("target") | 
| jcallahan@18 | 1135         npc.class = class_token | 
| jcallahan@39 | 1136         npc.faction = UnitFactionStanding("target") | 
| jcallahan@26 | 1137         npc.genders = npc.genders or {} | 
| jcallahan@26 | 1138         npc.genders[GENDER_NAMES[_G.UnitSex("target")] or "UNDEFINED"] = true | 
| jcallahan@18 | 1139         npc.is_pvp = _G.UnitIsPVP("target") and true or nil | 
| jcallahan@18 | 1140         npc.reaction = ("%s:%s:%s"):format(_G.UnitLevel("player"), _G.UnitFactionGroup("player"), REACTION_NAMES[_G.UnitReaction("player", "target")]) | 
| jcallahan@2 | 1141 | 
| jcallahan@30 | 1142         local encounter_data = npc.encounter_data[InstanceDifficultyToken()].stats | 
| jcallahan@18 | 1143         local npc_level = ("level_%d"):format(_G.UnitLevel("target")) | 
| jcallahan@3 | 1144 | 
| jcallahan@28 | 1145         if not encounter_data[npc_level] then | 
| jcallahan@28 | 1146             encounter_data[npc_level] = { | 
| jcallahan@18 | 1147                 max_health = _G.UnitHealthMax("target"), | 
| jcallahan@18 | 1148             } | 
| jcallahan@3 | 1149 | 
| jcallahan@18 | 1150             local max_power = _G.UnitManaMax("target") | 
| jcallahan@18 | 1151 | 
| jcallahan@18 | 1152             if max_power > 0 then | 
| jcallahan@18 | 1153                 local power_type = _G.UnitPowerType("target") | 
| jcallahan@28 | 1154                 encounter_data[npc_level].power = ("%s:%d"):format(POWER_TYPE_NAMES[_G.tostring(power_type)] or power_type, max_power) | 
| jcallahan@18 | 1155             end | 
| jcallahan@3 | 1156         end | 
| jcallahan@21 | 1157         table.wipe(action_data) | 
| jcallahan@21 | 1158         action_data.type = AF.NPC | 
| jcallahan@27 | 1159         action_data.identifier = unit_idnum | 
| jcallahan@21 | 1160         action_data.npc_level = npc_level | 
| jcallahan@31 | 1161 | 
| jcallahan@31 | 1162         self:UpdateTargetLocation() | 
| jcallahan@2 | 1163     end | 
| jcallahan@18 | 1164 end -- do-block | 
| jcallahan@2 | 1165 | 
| jcallahan@12 | 1166 do | 
| jcallahan@12 | 1167     local function UpdateQuestJuncture(point) | 
| jcallahan@12 | 1168         local unit_name = _G.UnitName("questnpc") | 
| jcallahan@9 | 1169 | 
| jcallahan@12 | 1170         if not unit_name then | 
| jcallahan@12 | 1171             return | 
| jcallahan@12 | 1172         end | 
| jcallahan@34 | 1173         local unit_type, unit_id = ParseGUID(_G.UnitGUID("questnpc")) | 
| jcallahan@9 | 1174 | 
| jcallahan@12 | 1175         if unit_type == private.UNIT_TYPES.OBJECT then | 
| jcallahan@38 | 1176             UpdateDBEntryLocation("objects", unit_id) | 
| jcallahan@12 | 1177         end | 
| jcallahan@19 | 1178         local quest = DBEntry("quests", _G.GetQuestID()) | 
| jcallahan@12 | 1179         quest[point] = quest[point] or {} | 
| jcallahan@12 | 1180         quest[point][("%s:%d"):format(private.UNIT_TYPE_NAMES[unit_type + 1], unit_id)] = true | 
| jcallahan@24 | 1181 | 
| jcallahan@24 | 1182         return quest | 
| jcallahan@12 | 1183     end | 
| jcallahan@10 | 1184 | 
| jcallahan@12 | 1185 | 
| jcallahan@12 | 1186     function WDP:QUEST_COMPLETE() | 
| jcallahan@67 | 1187         -- Make sure the quest NPC isn't erroneously recorded as giving reputation for quests which award it. | 
| jcallahan@67 | 1188         reputation_npc_id = nil | 
| jcallahan@12 | 1189         UpdateQuestJuncture("end") | 
| jcallahan@10 | 1190     end | 
| jcallahan@10 | 1191 | 
| jcallahan@12 | 1192 | 
| jcallahan@12 | 1193     function WDP:QUEST_DETAIL() | 
| jcallahan@24 | 1194         local quest = UpdateQuestJuncture("begin") | 
| jcallahan@24 | 1195 | 
| jcallahan@46 | 1196         if not quest then | 
| jcallahan@46 | 1197             return | 
| jcallahan@46 | 1198         end | 
| jcallahan@24 | 1199         quest.classes = quest.classes or {} | 
| jcallahan@27 | 1200         quest.classes[PLAYER_CLASS] = true | 
| jcallahan@24 | 1201 | 
| jcallahan@24 | 1202         local _, race = _G.UnitRace("player") | 
| jcallahan@24 | 1203         quest.races = quest.races or {} | 
| jcallahan@24 | 1204         quest.races[race] = true | 
| jcallahan@10 | 1205     end | 
| jcallahan@12 | 1206 end -- do-block | 
| jcallahan@9 | 1207 | 
| jcallahan@9 | 1208 | 
| jcallahan@4 | 1209 function WDP:QUEST_LOG_UPDATE() | 
| jcallahan@38 | 1210     local selected_quest = _G.GetQuestLogSelection() -- Save current selection to be restored when we're done. | 
| jcallahan@36 | 1211     local entry_index, processed_quests = 1, 0 | 
| jcallahan@36 | 1212     local _, num_quests = _G.GetNumQuestLogEntries() | 
| jcallahan@36 | 1213 | 
| jcallahan@36 | 1214     while processed_quests <= num_quests do | 
| jcallahan@36 | 1215         local _, _, _, _, is_header, _, _, _, quest_id = _G.GetQuestLogTitle(entry_index) | 
| jcallahan@36 | 1216 | 
| jcallahan@36 | 1217         if not is_header then | 
| jcallahan@36 | 1218             _G.SelectQuestLogEntry(entry_index); | 
| jcallahan@36 | 1219 | 
| jcallahan@36 | 1220             local quest = DBEntry("quests", quest_id) | 
| jcallahan@36 | 1221             quest.timer = _G.GetQuestLogTimeLeft() | 
| jcallahan@37 | 1222             quest.can_share = _G.GetQuestLogPushable() and true or nil | 
| jcallahan@36 | 1223             processed_quests = processed_quests + 1 | 
| jcallahan@36 | 1224         end | 
| jcallahan@36 | 1225         entry_index = entry_index + 1 | 
| jcallahan@36 | 1226     end | 
| jcallahan@36 | 1227     _G.SelectQuestLogEntry(selected_quest) | 
| jcallahan@4 | 1228     self:UnregisterEvent("QUEST_LOG_UPDATE") | 
| jcallahan@4 | 1229 end | 
| jcallahan@4 | 1230 | 
| jcallahan@4 | 1231 | 
| jcallahan@4 | 1232 function WDP:UNIT_QUEST_LOG_CHANGED(event, unit_id) | 
| jcallahan@4 | 1233     if unit_id ~= "player" then | 
| jcallahan@4 | 1234         return | 
| jcallahan@4 | 1235     end | 
| jcallahan@4 | 1236     self:RegisterEvent("QUEST_LOG_UPDATE") | 
| jcallahan@4 | 1237 end | 
| jcallahan@4 | 1238 | 
| jcallahan@4 | 1239 | 
| jcallahan@27 | 1240 function WDP:TRAINER_SHOW() | 
| jcallahan@34 | 1241     local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("target")) | 
| jcallahan@29 | 1242     local npc = NPCEntry(unit_idnum) | 
| jcallahan@58 | 1243 | 
| jcallahan@58 | 1244     if not npc then | 
| jcallahan@58 | 1245         return | 
| jcallahan@58 | 1246     end | 
| jcallahan@27 | 1247     npc.teaches = npc.teaches or {} | 
| jcallahan@27 | 1248 | 
| jcallahan@27 | 1249     -- Get the initial trainer filters | 
| jcallahan@27 | 1250     local available = _G.GetTrainerServiceTypeFilter("available") | 
| jcallahan@27 | 1251     local unavailable = _G.GetTrainerServiceTypeFilter("unavailable") | 
| jcallahan@27 | 1252     local used = _G.GetTrainerServiceTypeFilter("used") | 
| jcallahan@27 | 1253 | 
| jcallahan@27 | 1254     -- Clear the trainer filters | 
| jcallahan@27 | 1255     _G.SetTrainerServiceTypeFilter("available", 1) | 
| jcallahan@27 | 1256     _G.SetTrainerServiceTypeFilter("unavailable", 1) | 
| jcallahan@27 | 1257     _G.SetTrainerServiceTypeFilter("used", 1) | 
| jcallahan@27 | 1258 | 
| jcallahan@27 | 1259     for index = 1, _G.GetNumTrainerServices(), 1 do | 
| jcallahan@27 | 1260         local spell_name, rank_name, _, _, required_level = _G.GetTrainerServiceInfo(index) | 
| jcallahan@27 | 1261 | 
| jcallahan@27 | 1262         if spell_name then | 
| jcallahan@27 | 1263             DatamineTT:ClearLines() | 
| jcallahan@27 | 1264             DatamineTT:SetTrainerService(index) | 
| jcallahan@27 | 1265 | 
| jcallahan@27 | 1266             local _, _, spell_id = DatamineTT:GetSpell() | 
| jcallahan@27 | 1267 | 
| jcallahan@43 | 1268             if spell_id then | 
| jcallahan@43 | 1269                 local profession, min_skill = _G.GetTrainerServiceSkillReq(index) | 
| jcallahan@43 | 1270                 profession = profession or "General" | 
| jcallahan@43 | 1271 | 
| jcallahan@43 | 1272                 local class_professions = npc.teaches[PLAYER_CLASS] | 
| jcallahan@43 | 1273                 if not class_professions then | 
| jcallahan@43 | 1274                     npc.teaches[PLAYER_CLASS] = {} | 
| jcallahan@43 | 1275                     class_professions = npc.teaches[PLAYER_CLASS] | 
| jcallahan@43 | 1276                 end | 
| jcallahan@43 | 1277 | 
| jcallahan@43 | 1278                 local profession_skills = class_professions[profession] | 
| jcallahan@43 | 1279                 if not profession_skills then | 
| jcallahan@43 | 1280                     class_professions[profession] = {} | 
| jcallahan@43 | 1281                     profession_skills = class_professions[profession] | 
| jcallahan@43 | 1282                 end | 
| jcallahan@43 | 1283                 profession_skills[spell_id] = ("%d:%d"):format(required_level, min_skill) | 
| jcallahan@27 | 1284             end | 
| jcallahan@27 | 1285         end | 
| jcallahan@27 | 1286     end | 
| jcallahan@27 | 1287 | 
| jcallahan@27 | 1288     -- Reset the filters to what they were before | 
| jcallahan@27 | 1289     _G.SetTrainerServiceTypeFilter("available", available or 0) | 
| jcallahan@27 | 1290     _G.SetTrainerServiceTypeFilter("unavailable", unavailable or 0) | 
| jcallahan@27 | 1291     _G.SetTrainerServiceTypeFilter("used", used or 0) | 
| jcallahan@27 | 1292 end | 
| jcallahan@27 | 1293 | 
| jcallahan@27 | 1294 | 
| jcallahan@1 | 1295 function WDP:UNIT_SPELLCAST_SENT(event_name, unit_id, spell_name, spell_rank, target_name, spell_line) | 
| jcallahan@1 | 1296     if private.tracked_line or unit_id ~= "player" then | 
| jcallahan@1 | 1297         return | 
| jcallahan@1 | 1298     end | 
| jcallahan@1 | 1299     local spell_label = private.SPELL_LABELS_BY_NAME[spell_name] | 
| jcallahan@1 | 1300 | 
| jcallahan@1 | 1301     if not spell_label then | 
| jcallahan@1 | 1302         return | 
| jcallahan@1 | 1303     end | 
| jcallahan@18 | 1304     table.wipe(action_data) | 
| jcallahan@1 | 1305 | 
| jcallahan@1 | 1306     local tt_item_name, tt_item_link = _G.GameTooltip:GetItem() | 
| jcallahan@1 | 1307     local tt_unit_name, tt_unit_id = _G.GameTooltip:GetUnit() | 
| jcallahan@1 | 1308 | 
| jcallahan@1 | 1309     if not tt_unit_name and _G.UnitName("target") == target_name then | 
| jcallahan@1 | 1310         tt_unit_name = target_name | 
| jcallahan@1 | 1311         tt_unit_id = "target" | 
| jcallahan@1 | 1312     end | 
| jcallahan@1 | 1313     local spell_flags = private.SPELL_FLAGS_BY_LABEL[spell_label] | 
| jcallahan@28 | 1314     local zone_name, area_id, x, y, map_level, instance_token = CurrentLocationData() | 
| jcallahan@28 | 1315 | 
| jcallahan@28 | 1316     action_data.instance_token = instance_token | 
| jcallahan@28 | 1317     action_data.map_level = map_level | 
| jcallahan@28 | 1318     action_data.x = x | 
| jcallahan@28 | 1319     action_data.y = y | 
| jcallahan@28 | 1320     action_data.zone = ("%s:%d"):format(zone_name, area_id) | 
| jcallahan@76 | 1321     action_data.spell_label = spell_label | 
| jcallahan@76 | 1322     action_data.label = spell_label:lower() | 
| jcallahan@1 | 1323 | 
| jcallahan@16 | 1324     if tt_unit_name and not tt_item_name then | 
| jcallahan@16 | 1325         if bit.band(spell_flags, AF.NPC) == AF.NPC then | 
| jcallahan@16 | 1326             if not tt_unit_id or tt_unit_name ~= target_name then | 
| jcallahan@16 | 1327                 return | 
| jcallahan@16 | 1328             end | 
| jcallahan@16 | 1329             action_data.type = AF.NPC | 
| jcallahan@25 | 1330             action_data.unit_name = tt_unit_name | 
| jcallahan@16 | 1331         end | 
| jcallahan@16 | 1332     elseif bit.band(spell_flags, AF.ITEM) == AF.ITEM then | 
| jcallahan@16 | 1333         action_data.type = AF.ITEM | 
| jcallahan@16 | 1334 | 
| jcallahan@16 | 1335         if tt_item_name and tt_item_name == target_name then | 
| jcallahan@28 | 1336             action_data.identifier = ItemLinkToID(tt_item_link) | 
| jcallahan@16 | 1337         elseif target_name and target_name ~= "" then | 
| jcallahan@16 | 1338             local _, target_item_link = _G.GetItemInfo(target_name) | 
| jcallahan@28 | 1339             action_data.identifier = ItemLinkToID(target_item_link) | 
| jcallahan@16 | 1340         end | 
| jcallahan@16 | 1341     elseif not tt_item_name and not tt_unit_name then | 
| jcallahan@17 | 1342         action_data.name = target_name | 
| jcallahan@17 | 1343 | 
| jcallahan@1 | 1344         if bit.band(spell_flags, AF.OBJECT) == AF.OBJECT then | 
| jcallahan@17 | 1345             if target_name == "" then | 
| jcallahan@17 | 1346                 return | 
| jcallahan@17 | 1347             end | 
| jcallahan@1 | 1348             action_data.type = AF.OBJECT | 
| jcallahan@1 | 1349         elseif bit.band(spell_flags, AF.ZONE) == AF.ZONE then | 
| jcallahan@38 | 1350             local identifier = ("%s:%s"):format(spell_label, _G["GameTooltipTextLeft1"]:GetText() or "NONE") -- Possible fishing pool name. | 
| jcallahan@52 | 1351             action_data.zone_data = UpdateDBEntryLocation("zones", identifier) | 
| jcallahan@17 | 1352             action_data.type = AF.ZONE | 
| jcallahan@38 | 1353             action_data.identifier = identifier | 
| jcallahan@1 | 1354         end | 
| jcallahan@1 | 1355     end | 
| jcallahan@1 | 1356     private.tracked_line = spell_line | 
| jcallahan@0 | 1357 end | 
| jcallahan@0 | 1358 | 
| jcallahan@0 | 1359 | 
| jcallahan@1 | 1360 function WDP:UNIT_SPELLCAST_SUCCEEDED(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id) | 
| jcallahan@1 | 1361     if unit_id ~= "player" then | 
| jcallahan@1 | 1362         return | 
| jcallahan@1 | 1363     end | 
| jcallahan@1 | 1364     private.tracked_line = nil | 
| jcallahan@0 | 1365 end | 
| jcallahan@0 | 1366 | 
| jcallahan@1 | 1367 function WDP:HandleSpellFailure(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id) | 
| jcallahan@1 | 1368     if unit_id ~= "player" then | 
| jcallahan@1 | 1369         return | 
| jcallahan@1 | 1370     end | 
| jcallahan@0 | 1371 | 
| jcallahan@1 | 1372     if private.tracked_line == spell_line then | 
| jcallahan@1 | 1373         private.tracked_line = nil | 
| jcallahan@1 | 1374     end | 
| jcallahan@0 | 1375 end |