| jcallahan@246 | 1 -- LUA API ------------------------------------------------------------ | 
| jcallahan@246 | 2 | 
| jcallahan@0 | 3 local _G = getfenv(0) | 
| jcallahan@0 | 4 | 
| jcallahan@0 | 5 local pairs = _G.pairs | 
| jcallahan@312 | 6 local tostring = _G.tostring | 
| 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@78 | 13 local select = _G.select | 
| jcallahan@306 | 14 local unpack = _G.unpack | 
| jcallahan@78 | 15 | 
| jcallahan@0 | 16 | 
| jcallahan@246 | 17 -- ADDON NAMESPACE ---------------------------------------------------- | 
| jcallahan@246 | 18 | 
| jcallahan@0 | 19 local ADDON_NAME, private = ... | 
| jcallahan@0 | 20 | 
| jcallahan@0 | 21 local LibStub = _G.LibStub | 
| jcallahan@249 | 22 local WDP = LibStub("AceAddon-3.0"):NewAddon(ADDON_NAME, "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0") | 
| jcallahan@0 | 23 | 
| jcallahan@48 | 24 local deformat = LibStub("LibDeformat-3.0") | 
| jcallahan@115 | 25 local LPJ = LibStub("LibPetJournal-2.0") | 
| jcallahan@141 | 26 local MapData = LibStub("LibMapData-1.0") | 
| jcallahan@48 | 27 | 
| jcallahan@4 | 28 local DatamineTT = _G.CreateFrame("GameTooltip", "WDPDatamineTT", _G.UIParent, "GameTooltipTemplate") | 
| jcallahan@5 | 29 DatamineTT:SetOwner(_G.WorldFrame, "ANCHOR_NONE") | 
| jcallahan@5 | 30 | 
| jcallahan@0 | 31 | 
| jcallahan@246 | 32 -- CONSTANTS ---------------------------------------------------------- | 
| jcallahan@246 | 33 | 
| jcallahan@246 | 34 local AF = private.ACTION_TYPE_FLAGS | 
| jcallahan@246 | 35 local CLIENT_LOCALE = _G.GetLocale() | 
| jcallahan@313 | 36 local DB_VERSION = 18 | 
| jcallahan@246 | 37 local DEBUGGING = false | 
| jcallahan@156 | 38 local EVENT_DEBUG = false | 
| jcallahan@322 | 39 | 
| jcallahan@246 | 40 local OBJECT_ID_ANVIL = 192628 | 
| jcallahan@322 | 41 local OBJECT_ID_FISHING_BOBBER = 35591 | 
| jcallahan@246 | 42 local OBJECT_ID_FORGE = 1685 | 
| jcallahan@322 | 43 | 
| jcallahan@246 | 44 local PLAYER_CLASS = _G.select(2, _G.UnitClass("player")) | 
| jcallahan@246 | 45 local PLAYER_FACTION = _G.UnitFactionGroup("player") | 
| jcallahan@300 | 46 local PLAYER_GUID | 
| jcallahan@246 | 47 local PLAYER_NAME = _G.UnitName("player") | 
| jcallahan@246 | 48 local PLAYER_RACE = _G.select(2, _G.UnitRace("player")) | 
| jcallahan@246 | 49 | 
| jcallahan@326 | 50 local SPELL_ID_DISGUISE = 121308 | 
| jcallahan@326 | 51 | 
| jcallahan@246 | 52 local ALLOWED_LOCALES = { | 
| jcallahan@246 | 53     enUS = true, | 
| jcallahan@246 | 54     enGB = true, | 
| jcallahan@246 | 55 } | 
| jcallahan@157 | 56 | 
| jcallahan@0 | 57 local DATABASE_DEFAULTS = { | 
| jcallahan@128 | 58     char = {}, | 
| jcallahan@0 | 59     global = { | 
| jcallahan@270 | 60         config = { | 
| jcallahan@270 | 61             minimap_icon = { | 
| jcallahan@270 | 62                 hide = true, | 
| jcallahan@270 | 63             }, | 
| jcallahan@270 | 64         }, | 
| jcallahan@0 | 65         items = {}, | 
| jcallahan@0 | 66         npcs = {}, | 
| jcallahan@0 | 67         objects = {}, | 
| jcallahan@0 | 68         quests = {}, | 
| jcallahan@167 | 69         spells = {}, | 
| jcallahan@17 | 70         zones = {}, | 
| jcallahan@0 | 71     } | 
| jcallahan@0 | 72 } | 
| jcallahan@0 | 73 | 
| jcallahan@1 | 74 local EVENT_MAPPING = { | 
| jcallahan@90 | 75     AUCTION_HOUSE_SHOW = true, | 
| jcallahan@90 | 76     BANKFRAME_OPENED = true, | 
| jcallahan@90 | 77     BATTLEFIELDS_SHOW = true, | 
| jcallahan@56 | 78     BLACK_MARKET_ITEM_UPDATE = true, | 
| jcallahan@48 | 79     CHAT_MSG_LOOT = true, | 
| jcallahan@95 | 80     CHAT_MSG_MONSTER_SAY = "RecordQuote", | 
| jcallahan@95 | 81     CHAT_MSG_MONSTER_WHISPER = "RecordQuote", | 
| jcallahan@95 | 82     CHAT_MSG_MONSTER_YELL = "RecordQuote", | 
| jcallahan@40 | 83     CHAT_MSG_SYSTEM = true, | 
| jcallahan@23 | 84     COMBAT_LOG_EVENT_UNFILTERED = true, | 
| jcallahan@18 | 85     COMBAT_TEXT_UPDATE = true, | 
| jcallahan@140 | 86     CURSOR_UPDATE = true, | 
| jcallahan@90 | 87     FORGE_MASTER_OPENED = true, | 
| jcallahan@90 | 88     GOSSIP_SHOW = true, | 
| jcallahan@290 | 89     GROUP_ROSTER_UPDATE = true, | 
| jcallahan@93 | 90     GUILDBANKFRAME_OPENED = true, | 
| jcallahan@42 | 91     ITEM_TEXT_BEGIN = true, | 
| jcallahan@189 | 92     ITEM_UPGRADE_MASTER_OPENED = true, | 
| jcallahan@124 | 93     LOOT_CLOSED = true, | 
| jcallahan@1 | 94     LOOT_OPENED = true, | 
| jcallahan@89 | 95     MAIL_SHOW = true, | 
| jcallahan@133 | 96     MERCHANT_CLOSED = true, | 
| jcallahan@7 | 97     MERCHANT_SHOW = "UpdateMerchantItems", | 
| jcallahan@61 | 98     MERCHANT_UPDATE = "UpdateMerchantItems", | 
| jcallahan@25 | 99     PET_BAR_UPDATE = true, | 
| jcallahan@115 | 100     PET_JOURNAL_LIST_UPDATE = true, | 
| jcallahan@156 | 101     PLAYER_REGEN_DISABLED = true, | 
| jcallahan@156 | 102     PLAYER_REGEN_ENABLED = true, | 
| jcallahan@2 | 103     PLAYER_TARGET_CHANGED = true, | 
| jcallahan@9 | 104     QUEST_COMPLETE = true, | 
| jcallahan@9 | 105     QUEST_DETAIL = true, | 
| jcallahan@9 | 106     QUEST_LOG_UPDATE = true, | 
| jcallahan@97 | 107     QUEST_PROGRESS = true, | 
| jcallahan@178 | 108     SHOW_LOOT_TOAST = true, | 
| jcallahan@306 | 109     SPELL_CONFIRMATION_PROMPT = true, | 
| jcallahan@88 | 110     TAXIMAP_OPENED = true, | 
| jcallahan@92 | 111     TRADE_SKILL_SHOW = true, | 
| jcallahan@167 | 112     TRAINER_CLOSED = true, | 
| jcallahan@27 | 113     TRAINER_SHOW = true, | 
| jcallahan@90 | 114     TRANSMOGRIFY_OPEN = true, | 
| jcallahan@246 | 115     UNIT_PET = true, | 
| jcallahan@4 | 116     UNIT_QUEST_LOG_CHANGED = true, | 
| jcallahan@1 | 117     UNIT_SPELLCAST_FAILED = "HandleSpellFailure", | 
| jcallahan@1 | 118     UNIT_SPELLCAST_FAILED_QUIET = "HandleSpellFailure", | 
| jcallahan@1 | 119     UNIT_SPELLCAST_INTERRUPTED = "HandleSpellFailure", | 
| jcallahan@1 | 120     UNIT_SPELLCAST_SENT = true, | 
| jcallahan@1 | 121     UNIT_SPELLCAST_SUCCEEDED = true, | 
| jcallahan@90 | 122     VOID_STORAGE_OPEN = true, | 
| jcallahan@299 | 123     ZONE_CHANGED = "HandleZoneChange", | 
| jcallahan@299 | 124     ZONE_CHANGED_INDOORS = "HandleZoneChange", | 
| jcallahan@299 | 125     ZONE_CHANGED_NEW_AREA = "HandleZoneChange", | 
| jcallahan@0 | 126 } | 
| jcallahan@0 | 127 | 
| jcallahan@4 | 128 | 
| jcallahan@246 | 129 -- VARIABLES ---------------------------------------------------------- | 
| jcallahan@246 | 130 | 
| jcallahan@92 | 131 local anvil_spell_ids = {} | 
| jcallahan@92 | 132 local currently_drunk | 
| jcallahan@128 | 133 local char_db | 
| jcallahan@128 | 134 local global_db | 
| jcallahan@299 | 135 local group_member_guids = {} | 
| jcallahan@246 | 136 local group_owner_guids_to_pet_guids = {} | 
| jcallahan@246 | 137 local group_pet_guids = {} | 
| jcallahan@299 | 138 local in_instance | 
| jcallahan@187 | 139 local item_process_timer_handle | 
| jcallahan@92 | 140 local faction_standings = {} | 
| jcallahan@92 | 141 local forge_spell_ids = {} | 
| jcallahan@95 | 142 local languages_known = {} | 
| jcallahan@317 | 143 local boss_loot_toasting = {} | 
| jcallahan@306 | 144 local loot_toast_container_timer_handle | 
| jcallahan@307 | 145 local loot_toast_data | 
| jcallahan@307 | 146 local loot_toast_data_timer_handle | 
| jcallahan@95 | 147 local name_to_id_map = {} | 
| jcallahan@306 | 148 local killed_boss_id_timer_handle | 
| jcallahan@177 | 149 local killed_npc_id | 
| jcallahan@2 | 150 local target_location_timer_handle | 
| jcallahan@86 | 151 local current_target_id | 
| jcallahan@126 | 152 local current_area_id | 
| jcallahan@131 | 153 local current_loot | 
| jcallahan@1 | 154 | 
| jcallahan@312 | 155 | 
| jcallahan@121 | 156 -- Data for our current action. Including possible values as a reference. | 
| jcallahan@122 | 157 local current_action = { | 
| jcallahan@121 | 158     identifier = nil, | 
| jcallahan@121 | 159     loot_label = nil, | 
| jcallahan@121 | 160     loot_list = nil, | 
| jcallahan@121 | 161     loot_sources = nil, | 
| jcallahan@121 | 162     map_level = nil, | 
| jcallahan@121 | 163     spell_label = nil, | 
| jcallahan@123 | 164     target_type = nil, | 
| jcallahan@121 | 165     x = nil, | 
| jcallahan@121 | 166     y = nil, | 
| jcallahan@121 | 167     zone_data = nil, | 
| jcallahan@121 | 168 } | 
| jcallahan@92 | 169 | 
| jcallahan@246 | 170 | 
| jcallahan@246 | 171 -- HELPERS ------------------------------------------------------------ | 
| jcallahan@246 | 172 | 
| jcallahan@245 | 173 local function Debug(message, ...) | 
| jcallahan@306 | 174     if not DEBUGGING or not message or not ... then | 
| jcallahan@151 | 175         return | 
| jcallahan@151 | 176     end | 
| jcallahan@306 | 177     local args = { ... } | 
| jcallahan@306 | 178 | 
| jcallahan@306 | 179     for index = 1, #args do | 
| jcallahan@306 | 180         if args[index] == nil then | 
| jcallahan@306 | 181             args[index] = "nil" | 
| jcallahan@306 | 182         end | 
| jcallahan@306 | 183     end | 
| jcallahan@306 | 184     _G.print(message:format(unpack(args))) | 
| jcallahan@151 | 185 end | 
| jcallahan@151 | 186 | 
| jcallahan@151 | 187 | 
| jcallahan@169 | 188 local TradeSkillExecutePer | 
| jcallahan@169 | 189 do | 
| jcallahan@169 | 190     local header_list = {} | 
| jcallahan@169 | 191 | 
| jcallahan@169 | 192     function TradeSkillExecutePer(iter_func) | 
| jcallahan@169 | 193         if not _G.TradeSkillFrame or not _G.TradeSkillFrame:IsVisible() then | 
| jcallahan@169 | 194             return | 
| jcallahan@169 | 195         end | 
| jcallahan@167 | 196         -- Clear the search box focus so the scan will have correct results. | 
| jcallahan@167 | 197         local search_box = _G.TradeSkillFrameSearchBox | 
| jcallahan@167 | 198         search_box:SetText("") | 
| jcallahan@169 | 199 | 
| jcallahan@167 | 200         _G.TradeSkillSearch_OnTextChanged(search_box) | 
| jcallahan@167 | 201         search_box:ClearFocus() | 
| jcallahan@167 | 202         search_box:GetScript("OnEditFocusLost")(search_box) | 
| jcallahan@169 | 203 | 
| jcallahan@169 | 204         table.wipe(header_list) | 
| jcallahan@169 | 205 | 
| jcallahan@169 | 206         -- Save the current state of the TradeSkillFrame so it can be restored after we muck with it. | 
| jcallahan@169 | 207         local have_materials = _G.TradeSkillFrame.filterTbl.hasMaterials | 
| jcallahan@169 | 208         local have_skillup = _G.TradeSkillFrame.filterTbl.hasSkillUp | 
| jcallahan@169 | 209 | 
| jcallahan@169 | 210         if have_materials then | 
| jcallahan@169 | 211             _G.TradeSkillFrame.filterTbl.hasMaterials = false | 
| jcallahan@169 | 212             _G.TradeSkillOnlyShowMakeable(false) | 
| jcallahan@169 | 213         end | 
| jcallahan@169 | 214 | 
| jcallahan@169 | 215         if have_skillup then | 
| jcallahan@169 | 216             _G.TradeSkillFrame.filterTbl.hasSkillUp = false | 
| jcallahan@169 | 217             _G.TradeSkillOnlyShowSkillUps(false) | 
| jcallahan@169 | 218         end | 
| jcallahan@169 | 219         _G.SetTradeSkillInvSlotFilter(0, 1, 1) | 
| jcallahan@169 | 220         _G.TradeSkillUpdateFilterBar() | 
| jcallahan@169 | 221         _G.TradeSkillFrame_Update() | 
| jcallahan@169 | 222 | 
| jcallahan@169 | 223         -- Expand all headers so we can see all the recipes there are | 
| jcallahan@169 | 224         for tradeskill_index = 1, _G.GetNumTradeSkills() do | 
| jcallahan@169 | 225             local name, tradeskill_type, _, is_expanded = _G.GetTradeSkillInfo(tradeskill_index) | 
| jcallahan@169 | 226 | 
| jcallahan@169 | 227             if tradeskill_type == "header" or tradeskill_type == "subheader" then | 
| jcallahan@169 | 228                 if not is_expanded then | 
| jcallahan@169 | 229                     header_list[name] = true | 
| jcallahan@169 | 230                     _G.ExpandTradeSkillSubClass(tradeskill_index) | 
| jcallahan@169 | 231                 end | 
| jcallahan@169 | 232             elseif iter_func(name, tradeskill_index) then | 
| jcallahan@169 | 233                 break | 
| jcallahan@169 | 234             end | 
| jcallahan@169 | 235         end | 
| jcallahan@169 | 236 | 
| jcallahan@169 | 237         -- Restore the state of the things we changed. | 
| jcallahan@169 | 238         for tradeskill_index = 1, _G.GetNumTradeSkills() do | 
| jcallahan@169 | 239             local name, tradeskill_type, _, is_expanded = _G.GetTradeSkillInfo(tradeskill_index) | 
| jcallahan@169 | 240 | 
| jcallahan@169 | 241             if header_list[name] then | 
| jcallahan@169 | 242                 _G.CollapseTradeSkillSubClass(tradeskill_index) | 
| jcallahan@169 | 243             end | 
| jcallahan@169 | 244         end | 
| jcallahan@169 | 245         _G.TradeSkillFrame.filterTbl.hasMaterials = have_materials | 
| jcallahan@169 | 246         _G.TradeSkillOnlyShowMakeable(have_materials) | 
| jcallahan@169 | 247         _G.TradeSkillFrame.filterTbl.hasSkillUp = have_skillup | 
| jcallahan@169 | 248         _G.TradeSkillOnlyShowSkillUps(have_skillup) | 
| jcallahan@169 | 249 | 
| jcallahan@169 | 250         _G.TradeSkillUpdateFilterBar() | 
| jcallahan@169 | 251         _G.TradeSkillFrame_Update() | 
| jcallahan@167 | 252     end | 
| jcallahan@169 | 253 end -- do-block | 
| jcallahan@167 | 254 | 
| jcallahan@167 | 255 | 
| jcallahan@39 | 256 local ActualCopperCost | 
| jcallahan@39 | 257 do | 
| jcallahan@39 | 258     local BARTERING_SPELL_ID = 83964 | 
| jcallahan@39 | 259 | 
| jcallahan@39 | 260     local STANDING_DISCOUNTS = { | 
| jcallahan@39 | 261         HATED = 0, | 
| jcallahan@39 | 262         HOSTILE = 0, | 
| jcallahan@39 | 263         UNFRIENDLY = 0, | 
| jcallahan@39 | 264         NEUTRAL = 0, | 
| jcallahan@39 | 265         FRIENDLY = 0.05, | 
| jcallahan@39 | 266         HONORED = 0.1, | 
| jcallahan@39 | 267         REVERED = 0.15, | 
| jcallahan@39 | 268         EXALTED = 0.2, | 
| jcallahan@39 | 269     } | 
| jcallahan@39 | 270 | 
| jcallahan@39 | 271 | 
| jcallahan@39 | 272     function ActualCopperCost(copper_cost, rep_standing) | 
| jcallahan@39 | 273         if not copper_cost or copper_cost == 0 then | 
| jcallahan@39 | 274             return 0 | 
| jcallahan@39 | 275         end | 
| jcallahan@39 | 276         local modifier = 1 | 
| jcallahan@39 | 277 | 
| jcallahan@39 | 278         if _G.IsSpellKnown(BARTERING_SPELL_ID) then | 
| jcallahan@39 | 279             modifier = modifier - 0.1 | 
| jcallahan@39 | 280         end | 
| jcallahan@39 | 281 | 
| jcallahan@39 | 282         if rep_standing then | 
| jcallahan@39 | 283             if PLAYER_RACE == "Goblin" then | 
| jcallahan@39 | 284                 modifier = modifier - STANDING_DISCOUNTS["EXALTED"] | 
| jcallahan@39 | 285             elseif STANDING_DISCOUNTS[rep_standing] then | 
| jcallahan@39 | 286                 modifier = modifier - STANDING_DISCOUNTS[rep_standing] | 
| jcallahan@39 | 287             end | 
| jcallahan@39 | 288         end | 
| jcallahan@39 | 289         return math.floor(copper_cost / modifier) | 
| jcallahan@39 | 290     end | 
| jcallahan@39 | 291 end -- do-block | 
| jcallahan@39 | 292 | 
| jcallahan@39 | 293 | 
| jcallahan@317 | 294 -- constant for duplicate boss data; a dirty hack to get around world bosses that cannot be identified individually and cannot be linked on wowdb because they are not in a raid | 
| jcallahan@317 | 295 local DUPLICATE_WORLD_BOSS_IDS = { | 
| jcallahan@317 | 296     [71952] = { 71953, 71954, 71955, }, | 
| jcallahan@317 | 297 } | 
| jcallahan@317 | 298 | 
| jcallahan@317 | 299 | 
| jcallahan@153 | 300 -- Called on a timer | 
| jcallahan@177 | 301 local function ClearKilledNPC() | 
| jcallahan@177 | 302     killed_npc_id = nil | 
| jcallahan@177 | 303 end | 
| jcallahan@177 | 304 | 
| jcallahan@177 | 305 | 
| jcallahan@203 | 306 local function ClearKilledBossID() | 
| jcallahan@306 | 307     if killed_boss_id_timer_handle then | 
| jcallahan@306 | 308         WDP:CancelTimer(killed_boss_id_timer_handle) | 
| jcallahan@320 | 309         killed_boss_id_timer_handle = nil | 
| jcallahan@306 | 310     end | 
| jcallahan@324 | 311 | 
| jcallahan@317 | 312     table.wipe(boss_loot_toasting) | 
| jcallahan@203 | 313     private.raid_finder_boss_id = nil | 
| jcallahan@203 | 314     private.world_boss_id = nil | 
| jcallahan@306 | 315 end | 
| jcallahan@306 | 316 | 
| jcallahan@306 | 317 | 
| jcallahan@306 | 318 local function ClearLootToastContainerID() | 
| jcallahan@306 | 319     if loot_toast_container_timer_handle then | 
| jcallahan@306 | 320         WDP:CancelTimer(loot_toast_container_timer_handle) | 
| jcallahan@324 | 321         loot_toast_container_timer_handle = nil | 
| jcallahan@306 | 322     end | 
| jcallahan@324 | 323 | 
| jcallahan@306 | 324     private.container_loot_toasting = false | 
| jcallahan@306 | 325     private.loot_toast_container_id = nil | 
| jcallahan@203 | 326 end | 
| jcallahan@203 | 327 | 
| jcallahan@203 | 328 | 
| jcallahan@307 | 329 local function ClearLootToastData() | 
| jcallahan@307 | 330     -- cancel existing timer if found | 
| jcallahan@307 | 331     if loot_toast_data_timer_handle then | 
| jcallahan@307 | 332         WDP:CancelTimer(loot_toast_data_timer_handle) | 
| jcallahan@320 | 333         loot_toast_data_timer_handle = nil | 
| jcallahan@307 | 334     end | 
| jcallahan@307 | 335 | 
| jcallahan@320 | 336     if loot_toast_data then | 
| jcallahan@320 | 337         table.wipe(loot_toast_data) | 
| jcallahan@320 | 338     end | 
| jcallahan@307 | 339 end | 
| jcallahan@307 | 340 | 
| jcallahan@307 | 341 | 
| jcallahan@29 | 342 local function InstanceDifficultyToken() | 
| jcallahan@233 | 343     local _, instance_type, instance_difficulty, _, _, _, is_dynamic = _G.GetInstanceInfo() | 
| jcallahan@59 | 344 | 
| jcallahan@59 | 345     if not instance_type or instance_type == "" then | 
| jcallahan@59 | 346         instance_type = "NONE" | 
| jcallahan@59 | 347     end | 
| jcallahan@312 | 348     return ("%s:%d:%s"):format(instance_type:upper(), instance_difficulty, tostring(is_dynamic)) | 
| jcallahan@29 | 349 end | 
| jcallahan@29 | 350 | 
| jcallahan@29 | 351 | 
| jcallahan@19 | 352 local function DBEntry(data_type, unit_id) | 
| jcallahan@19 | 353     if not data_type or not unit_id then | 
| jcallahan@6 | 354         return | 
| jcallahan@6 | 355     end | 
| jcallahan@289 | 356     local category = global_db[data_type] | 
| jcallahan@289 | 357 | 
| jcallahan@289 | 358     if not category then | 
| jcallahan@289 | 359         category = {} | 
| jcallahan@289 | 360         global_db[data_type] = category | 
| jcallahan@289 | 361     end | 
| jcallahan@289 | 362     local unit = category[unit_id] | 
| jcallahan@6 | 363 | 
| jcallahan@10 | 364     if not unit then | 
| jcallahan@187 | 365         unit = {} | 
| jcallahan@289 | 366         category[unit_id] = unit | 
| jcallahan@6 | 367     end | 
| jcallahan@10 | 368     return unit | 
| jcallahan@6 | 369 end | 
| jcallahan@270 | 370 | 
| jcallahan@263 | 371 private.DBEntry = DBEntry | 
| jcallahan@6 | 372 | 
| jcallahan@214 | 373 local NPCEntry | 
| jcallahan@214 | 374 do | 
| jcallahan@214 | 375     local npc_prototype = {} | 
| jcallahan@214 | 376     local npc_meta = { | 
| jcallahan@214 | 377         __index = npc_prototype | 
| jcallahan@214 | 378     } | 
| jcallahan@6 | 379 | 
| jcallahan@214 | 380     function NPCEntry(identifier) | 
| jcallahan@227 | 381         local npc = DBEntry("npcs", identifier) | 
| jcallahan@29 | 382 | 
| jcallahan@214 | 383         if not npc then | 
| jcallahan@214 | 384             return | 
| jcallahan@214 | 385         end | 
| jcallahan@227 | 386         return _G.setmetatable(npc, npc_meta) | 
| jcallahan@22 | 387     end | 
| jcallahan@214 | 388 | 
| jcallahan@248 | 389     function npc_prototype:EncounterData(difficulty_token) | 
| jcallahan@214 | 390         self.encounter_data = self.encounter_data or {} | 
| jcallahan@248 | 391         self.encounter_data[difficulty_token] = self.encounter_data[difficulty_token] or {} | 
| jcallahan@248 | 392         self.encounter_data[difficulty_token].stats = self.encounter_data[difficulty_token].stats or {} | 
| jcallahan@248 | 393 | 
| jcallahan@248 | 394         return self.encounter_data[difficulty_token] | 
| jcallahan@214 | 395     end | 
| jcallahan@22 | 396 end | 
| jcallahan@22 | 397 | 
| jcallahan@22 | 398 | 
| jcallahan@1 | 399 local function CurrentLocationData() | 
| jcallahan@161 | 400     if _G.GetCurrentMapAreaID() ~= current_area_id then | 
| jcallahan@145 | 401         return _G.GetRealZoneText(), current_area_id, 0, 0, 0, InstanceDifficultyToken() | 
| jcallahan@145 | 402     end | 
| jcallahan@1 | 403     local map_level = _G.GetCurrentMapDungeonLevel() or 0 | 
| jcallahan@1 | 404     local x, y = _G.GetPlayerMapPosition("player") | 
| jcallahan@1 | 405 | 
| jcallahan@1 | 406     x = x or 0 | 
| jcallahan@1 | 407     y = y or 0 | 
| jcallahan@1 | 408 | 
| jcallahan@1 | 409     if x == 0 and y == 0 then | 
| jcallahan@1 | 410         for level_index = 1, _G.GetNumDungeonMapLevels() do | 
| jcallahan@1 | 411             _G.SetDungeonMapLevel(level_index) | 
| jcallahan@1 | 412             x, y = _G.GetPlayerMapPosition("player") | 
| jcallahan@1 | 413 | 
| jcallahan@1 | 414             if x and y and (x > 0 or y > 0) then | 
| jcallahan@1 | 415                 _G.SetDungeonMapLevel(map_level) | 
| jcallahan@1 | 416                 map_level = level_index | 
| jcallahan@1 | 417                 break | 
| jcallahan@1 | 418             end | 
| jcallahan@1 | 419         end | 
| jcallahan@1 | 420     end | 
| jcallahan@1 | 421 | 
| jcallahan@1 | 422     if _G.DungeonUsesTerrainMap() then | 
| jcallahan@1 | 423         map_level = map_level - 1 | 
| jcallahan@1 | 424     end | 
| jcallahan@31 | 425     local x = _G.floor(x * 1000) | 
| jcallahan@31 | 426     local y = _G.floor(y * 1000) | 
| jcallahan@28 | 427 | 
| jcallahan@31 | 428     if x % 2 ~= 0 then | 
| jcallahan@31 | 429         x = x + 1 | 
| jcallahan@28 | 430     end | 
| jcallahan@28 | 431 | 
| jcallahan@31 | 432     if y % 2 ~= 0 then | 
| jcallahan@31 | 433         y = y + 1 | 
| jcallahan@28 | 434     end | 
| jcallahan@126 | 435     return _G.GetRealZoneText(), current_area_id, x, y, map_level, InstanceDifficultyToken() | 
| jcallahan@1 | 436 end | 
| jcallahan@1 | 437 | 
| jcallahan@1 | 438 | 
| jcallahan@312 | 439 local function CurrencyLinkToTexture(currency_link) | 
| jcallahan@312 | 440     if not currency_link then | 
| jcallahan@312 | 441         return | 
| jcallahan@312 | 442     end | 
| jcallahan@312 | 443     local _, _, texture_path = _G.GetCurrencyInfo(tonumber(currency_link:match("currency:(%d+)"))) | 
| jcallahan@312 | 444     return texture_path:match("[^\\]+$"):lower() | 
| jcallahan@312 | 445 end | 
| jcallahan@312 | 446 | 
| jcallahan@312 | 447 | 
| jcallahan@1 | 448 local function ItemLinkToID(item_link) | 
| jcallahan@1 | 449     if not item_link then | 
| jcallahan@1 | 450         return | 
| jcallahan@1 | 451     end | 
| jcallahan@7 | 452     return tonumber(item_link:match("item:(%d+)")) | 
| jcallahan@1 | 453 end | 
| jcallahan@270 | 454 | 
| jcallahan@260 | 455 private.ItemLinkToID = ItemLinkToID | 
| jcallahan@4 | 456 | 
| jcallahan@171 | 457 local function UnitTypeIsNPC(unit_type) | 
| jcallahan@171 | 458     return unit_type == private.UNIT_TYPES.NPC or unit_type == private.UNIT_TYPES.VEHICLE | 
| jcallahan@171 | 459 end | 
| jcallahan@171 | 460 | 
| jcallahan@171 | 461 | 
| jcallahan@34 | 462 local ParseGUID | 
| jcallahan@4 | 463 do | 
| jcallahan@229 | 464     local UNIT_TYPES = private.UNIT_TYPES | 
| jcallahan@4 | 465     local UNIT_TYPE_BITMASK = 0x007 | 
| jcallahan@4 | 466 | 
| jcallahan@281 | 467     local NPC_ID_MAPPING = { | 
| jcallahan@281 | 468         [62164] = 63191, -- Garalon | 
| jcallahan@281 | 469     } | 
| jcallahan@281 | 470 | 
| jcallahan@281 | 471 | 
| jcallahan@34 | 472     function ParseGUID(guid) | 
| jcallahan@5 | 473         if not guid then | 
| jcallahan@5 | 474             return | 
| jcallahan@5 | 475         end | 
| jcallahan@229 | 476         local bitfield = tonumber(guid:sub(1, 5)) | 
| jcallahan@4 | 477 | 
| jcallahan@229 | 478         if not bitfield then | 
| jcallahan@229 | 479             return UNIT_TYPES.UNKNOWN | 
| jcallahan@229 | 480         end | 
| jcallahan@229 | 481         local unit_type = _G.bit.band(bitfield, UNIT_TYPE_BITMASK) | 
| jcallahan@229 | 482 | 
| jcallahan@229 | 483         if unit_type ~= UNIT_TYPES.PLAYER and unit_type ~= UNIT_TYPES.PET then | 
| jcallahan@281 | 484             local unit_idnum = tonumber(guid:sub(6, 10), 16) | 
| jcallahan@281 | 485             local id_mapping = NPC_ID_MAPPING[unit_idnum] | 
| jcallahan@281 | 486 | 
| jcallahan@281 | 487             if id_mapping and UnitTypeIsNPC(unit_type) then | 
| jcallahan@281 | 488                 unit_idnum = id_mapping | 
| jcallahan@281 | 489             end | 
| jcallahan@281 | 490             return unit_type, unit_idnum | 
| jcallahan@4 | 491         end | 
| jcallahan@4 | 492         return unit_type | 
| jcallahan@4 | 493     end | 
| jcallahan@249 | 494 | 
| jcallahan@249 | 495     private.ParseGUID = ParseGUID | 
| jcallahan@4 | 496 end -- do-block | 
| jcallahan@4 | 497 | 
| jcallahan@4 | 498 | 
| jcallahan@141 | 499 local UpdateDBEntryLocation | 
| jcallahan@141 | 500 do | 
| jcallahan@141 | 501     -- Fishing node coordinate code based on code in GatherMate2 with permission from Kagaro. | 
| jcallahan@141 | 502     local function FishingCoordinates(x, y, yard_width, yard_height) | 
| jcallahan@141 | 503         local facing = _G.GetPlayerFacing() | 
| jcallahan@141 | 504 | 
| jcallahan@141 | 505         if not facing then | 
| jcallahan@141 | 506             return x, y | 
| jcallahan@141 | 507         end | 
| jcallahan@246 | 508         local rad = facing + math.pi | 
| jcallahan@141 | 509         return x + math.sin(rad) * 15 / yard_width, y + math.cos(rad) * 15 / yard_height | 
| jcallahan@10 | 510     end | 
| jcallahan@10 | 511 | 
| jcallahan@24 | 512 | 
| jcallahan@141 | 513     function UpdateDBEntryLocation(entry_type, identifier) | 
| jcallahan@141 | 514         if not identifier then | 
| jcallahan@141 | 515             return | 
| jcallahan@141 | 516         end | 
| jcallahan@141 | 517         local zone_name, area_id, x, y, map_level, difficulty_token = CurrentLocationData() | 
| jcallahan@141 | 518         local entry = DBEntry(entry_type, identifier) | 
| jcallahan@141 | 519         entry[difficulty_token] = entry[difficulty_token] or {} | 
| jcallahan@141 | 520         entry[difficulty_token].locations = entry[difficulty_token].locations or {} | 
| jcallahan@141 | 521 | 
| jcallahan@141 | 522         local zone_token = ("%s:%d"):format(zone_name, area_id) | 
| jcallahan@141 | 523         local zone_data = entry[difficulty_token].locations[zone_token] | 
| jcallahan@141 | 524 | 
| jcallahan@141 | 525         if not zone_data then | 
| jcallahan@141 | 526             zone_data = {} | 
| jcallahan@141 | 527             entry[difficulty_token].locations[zone_token] = zone_data | 
| jcallahan@141 | 528         end | 
| jcallahan@141 | 529 | 
| jcallahan@141 | 530         -- Special case for Fishing. | 
| jcallahan@141 | 531         if current_action.spell_label == "FISHING" then | 
| jcallahan@141 | 532             local yard_width, yard_height = MapData:MapArea(area_id, map_level) | 
| jcallahan@141 | 533 | 
| jcallahan@141 | 534             if yard_width > 0 and yard_height > 0 then | 
| jcallahan@141 | 535                 x, y = FishingCoordinates(x, y, yard_width, yard_height) | 
| jcallahan@141 | 536                 current_action.x = x | 
| jcallahan@141 | 537                 current_action.y = y | 
| jcallahan@141 | 538             end | 
| jcallahan@141 | 539         end | 
| jcallahan@141 | 540         local location_token = ("%d:%d:%d"):format(map_level, x, y) | 
| jcallahan@141 | 541 | 
| jcallahan@141 | 542         zone_data[location_token] = zone_data[location_token] or true | 
| jcallahan@141 | 543         return zone_data | 
| jcallahan@10 | 544     end | 
| jcallahan@141 | 545 end -- do-block | 
| jcallahan@10 | 546 | 
| jcallahan@10 | 547 | 
| jcallahan@19 | 548 local function HandleItemUse(item_link, bag_index, slot_index) | 
| jcallahan@19 | 549     if not item_link then | 
| jcallahan@19 | 550         return | 
| jcallahan@19 | 551     end | 
| jcallahan@19 | 552     local item_id = ItemLinkToID(item_link) | 
| jcallahan@19 | 553 | 
| jcallahan@19 | 554     if not bag_index or not slot_index then | 
| jcallahan@19 | 555         for new_bag_index = 0, _G.NUM_BAG_FRAMES do | 
| jcallahan@19 | 556             for new_slot_index = 1, _G.GetContainerNumSlots(new_bag_index) do | 
| jcallahan@19 | 557                 if item_id == ItemLinkToID(_G.GetContainerItemLink(new_bag_index, new_slot_index)) then | 
| jcallahan@19 | 558                     bag_index = new_bag_index | 
| jcallahan@19 | 559                     slot_index = new_slot_index | 
| jcallahan@19 | 560                     break | 
| jcallahan@19 | 561                 end | 
| jcallahan@19 | 562             end | 
| jcallahan@19 | 563         end | 
| jcallahan@19 | 564     end | 
| jcallahan@19 | 565 | 
| jcallahan@19 | 566     if not bag_index or not slot_index then | 
| jcallahan@19 | 567         return | 
| jcallahan@19 | 568     end | 
| jcallahan@19 | 569     local _, _, _, _, _, is_lootable = _G.GetContainerItemInfo(bag_index, slot_index) | 
| jcallahan@19 | 570 | 
| jcallahan@19 | 571     if not is_lootable then | 
| jcallahan@19 | 572         return | 
| jcallahan@19 | 573     end | 
| jcallahan@19 | 574     DatamineTT:ClearLines() | 
| jcallahan@19 | 575     DatamineTT:SetBagItem(bag_index, slot_index) | 
| jcallahan@19 | 576 | 
| jcallahan@19 | 577     for line_index = 1, DatamineTT:NumLines() do | 
| jcallahan@19 | 578         local current_line = _G["WDPDatamineTTTextLeft" .. line_index] | 
| jcallahan@19 | 579 | 
| jcallahan@19 | 580         if not current_line then | 
| jcallahan@324 | 581             Debug("HandleItemUse: Item with ID %d and link %s had an invalid tooltip.", item_id, item_link, _G.ITEM_OPENABLE) | 
| jcallahan@324 | 582             return | 
| jcallahan@19 | 583         end | 
| jcallahan@306 | 584 | 
| jcallahan@306 | 585         if current_line:GetText() == _G.ITEM_OPENABLE then | 
| jcallahan@122 | 586             table.wipe(current_action) | 
| jcallahan@312 | 587             current_loot = nil | 
| jcallahan@312 | 588 | 
| jcallahan@123 | 589             current_action.target_type = AF.ITEM | 
| jcallahan@122 | 590             current_action.identifier = item_id | 
| jcallahan@122 | 591             current_action.loot_label = "contains" | 
| jcallahan@324 | 592             return | 
| jcallahan@19 | 593         end | 
| jcallahan@19 | 594     end | 
| jcallahan@324 | 595 | 
| jcallahan@324 | 596     Debug("HandleItemUse: Item with ID %d and link %s did not have a tooltip that contained the string %s.", item_id, item_link, _G.ITEM_OPENABLE) | 
| jcallahan@19 | 597 end | 
| jcallahan@19 | 598 | 
| jcallahan@19 | 599 | 
| jcallahan@39 | 600 local UnitFactionStanding | 
| jcallahan@32 | 601 local UpdateFactionData | 
| jcallahan@32 | 602 do | 
| jcallahan@32 | 603     local MAX_FACTION_INDEX = 1000 | 
| jcallahan@20 | 604 | 
| jcallahan@32 | 605     local STANDING_NAMES = { | 
| jcallahan@32 | 606         "HATED", | 
| jcallahan@32 | 607         "HOSTILE", | 
| jcallahan@32 | 608         "UNFRIENDLY", | 
| jcallahan@32 | 609         "NEUTRAL", | 
| jcallahan@32 | 610         "FRIENDLY", | 
| jcallahan@32 | 611         "HONORED", | 
| jcallahan@32 | 612         "REVERED", | 
| jcallahan@32 | 613         "EXALTED", | 
| jcallahan@32 | 614     } | 
| jcallahan@32 | 615 | 
| jcallahan@39 | 616 | 
| jcallahan@39 | 617     function UnitFactionStanding(unit) | 
| jcallahan@135 | 618         local unit_name = _G.UnitName(unit) | 
| jcallahan@39 | 619         UpdateFactionData() | 
| jcallahan@39 | 620         DatamineTT:ClearLines() | 
| jcallahan@39 | 621         DatamineTT:SetUnit(unit) | 
| jcallahan@39 | 622 | 
| jcallahan@39 | 623         for line_index = 1, DatamineTT:NumLines() do | 
| jcallahan@64 | 624             local faction_name = _G["WDPDatamineTTTextLeft" .. line_index]:GetText():trim() | 
| jcallahan@39 | 625 | 
| jcallahan@135 | 626             if faction_name and faction_name ~= unit_name and faction_standings[faction_name] then | 
| jcallahan@39 | 627                 return faction_name, faction_standings[faction_name] | 
| jcallahan@39 | 628             end | 
| jcallahan@39 | 629         end | 
| jcallahan@39 | 630     end | 
| jcallahan@39 | 631 | 
| jcallahan@39 | 632 | 
| jcallahan@32 | 633     function UpdateFactionData() | 
| jcallahan@32 | 634         for faction_index = 1, MAX_FACTION_INDEX do | 
| jcallahan@32 | 635             local faction_name, _, current_standing, _, _, _, _, _, is_header = _G.GetFactionInfo(faction_index) | 
| jcallahan@32 | 636 | 
| jcallahan@86 | 637             if faction_name then | 
| jcallahan@32 | 638                 faction_standings[faction_name] = STANDING_NAMES[current_standing] | 
| jcallahan@32 | 639             elseif not faction_name then | 
| jcallahan@32 | 640                 break | 
| jcallahan@32 | 641             end | 
| jcallahan@20 | 642         end | 
| jcallahan@20 | 643     end | 
| jcallahan@32 | 644 end -- do-block | 
| jcallahan@20 | 645 | 
| jcallahan@48 | 646 | 
| jcallahan@75 | 647 local GenericLootUpdate | 
| jcallahan@75 | 648 do | 
| jcallahan@77 | 649     local function LootTable(entry, loot_type, top_field) | 
| jcallahan@75 | 650         if top_field then | 
| jcallahan@75 | 651             entry[top_field] = entry[top_field] or {} | 
| jcallahan@75 | 652             entry[top_field][loot_type] = entry[top_field][loot_type] or {} | 
| jcallahan@75 | 653             return entry[top_field][loot_type] | 
| jcallahan@75 | 654         end | 
| jcallahan@48 | 655         entry[loot_type] = entry[loot_type] or {} | 
| jcallahan@75 | 656         return entry[loot_type] | 
| jcallahan@48 | 657     end | 
| jcallahan@48 | 658 | 
| jcallahan@75 | 659     function GenericLootUpdate(data_type, top_field) | 
| jcallahan@132 | 660         local loot_type = current_loot.label | 
| jcallahan@75 | 661         local loot_count = ("%s_count"):format(loot_type) | 
| jcallahan@77 | 662         local source_list = {} | 
| jcallahan@75 | 663 | 
| jcallahan@131 | 664         if current_loot.sources then | 
| jcallahan@131 | 665             for source_guid, loot_data in pairs(current_loot.sources) do | 
| jcallahan@304 | 666                 local source_id | 
| jcallahan@78 | 667 | 
| jcallahan@131 | 668                 if current_loot.target_type == AF.ITEM then | 
| jcallahan@119 | 669                     -- Items return the player as the source, so we need to use the item's ID (disenchant, milling, etc) | 
| jcallahan@131 | 670                     source_id = current_loot.identifier | 
| jcallahan@131 | 671                 elseif current_loot.target_type == AF.OBJECT then | 
| jcallahan@131 | 672                     source_id = ("%s:%s"):format(current_loot.spell_label, select(2, ParseGUID(source_guid))) | 
| jcallahan@119 | 673                 else | 
| jcallahan@119 | 674                     source_id = select(2, ParseGUID(source_guid)) | 
| jcallahan@119 | 675                 end | 
| jcallahan@304 | 676                 local entry = DBEntry(data_type, source_id) | 
| jcallahan@75 | 677 | 
| jcallahan@119 | 678                 if entry then | 
| jcallahan@119 | 679                     local loot_table = LootTable(entry, loot_type, top_field) | 
| jcallahan@77 | 680 | 
| jcallahan@304 | 681                     if not source_list[source_id] then | 
| jcallahan@119 | 682                         if top_field then | 
| jcallahan@119 | 683                             entry[top_field][loot_count] = (entry[top_field][loot_count] or 0) + 1 | 
| jcallahan@306 | 684                         elseif not private.container_loot_toasting then | 
| jcallahan@119 | 685                             entry[loot_count] = (entry[loot_count] or 0) + 1 | 
| jcallahan@119 | 686                         end | 
| jcallahan@304 | 687                         source_list[source_id] = true | 
| jcallahan@77 | 688                     end | 
| jcallahan@119 | 689                     UpdateDBEntryLocation(data_type, source_id) | 
| jcallahan@75 | 690 | 
| jcallahan@309 | 691                     if current_loot.target_type == AF.ZONE then | 
| jcallahan@309 | 692                         for item_id, quantity in pairs(loot_data) do | 
| jcallahan@309 | 693                             table.insert(loot_table, ("%d:%d"):format(item_id, quantity)) | 
| jcallahan@309 | 694                         end | 
| jcallahan@309 | 695                     else | 
| jcallahan@308 | 696                         for loot_token, quantity in pairs(loot_data) do | 
| jcallahan@308 | 697                             local label, currency_texture = (":"):split(loot_token) | 
| jcallahan@308 | 698 | 
| jcallahan@308 | 699                             if label == "currency" and currency_texture then | 
| jcallahan@308 | 700                                 table.insert(loot_table, ("currency:%d:%s"):format(quantity, currency_texture)) | 
| jcallahan@308 | 701                             elseif loot_token == "money" then | 
| jcallahan@308 | 702                                 table.insert(loot_table, ("money:%d"):format(quantity)) | 
| jcallahan@308 | 703                             else | 
| jcallahan@308 | 704                                 table.insert(loot_table, ("%d:%d"):format(loot_token, quantity)) | 
| jcallahan@308 | 705                             end | 
| jcallahan@308 | 706                         end | 
| jcallahan@119 | 707                     end | 
| jcallahan@75 | 708                 end | 
| jcallahan@75 | 709             end | 
| jcallahan@75 | 710         end | 
| jcallahan@121 | 711 | 
| jcallahan@121 | 712         -- This is used for Gas Extractions. | 
| jcallahan@131 | 713         if #current_loot.list <= 0 then | 
| jcallahan@78 | 714             return | 
| jcallahan@78 | 715         end | 
| jcallahan@82 | 716         local entry | 
| jcallahan@82 | 717 | 
| jcallahan@82 | 718         -- At this point we only have a name if it's an object. | 
| jcallahan@131 | 719         if current_loot.target_type == AF.OBJECT then | 
| jcallahan@131 | 720             entry = DBEntry(data_type, ("%s:%s"):format(current_loot.spell_label, current_loot.object_name)) | 
| jcallahan@82 | 721         else | 
| jcallahan@131 | 722             entry = DBEntry(data_type, current_loot.identifier) | 
| jcallahan@82 | 723         end | 
| jcallahan@75 | 724 | 
| jcallahan@75 | 725         if not entry then | 
| jcallahan@75 | 726             return | 
| jcallahan@75 | 727         end | 
| jcallahan@77 | 728         local loot_table = LootTable(entry, loot_type, top_field) | 
| jcallahan@77 | 729 | 
| jcallahan@307 | 730         if current_loot.identifier then | 
| jcallahan@307 | 731             if not source_list[current_loot.identifier] then | 
| jcallahan@307 | 732                 if top_field then | 
| jcallahan@307 | 733                     entry[top_field][loot_count] = (entry[top_field][loot_count] or 0) + 1 | 
| jcallahan@307 | 734                 else | 
| jcallahan@307 | 735                     entry[loot_count] = (entry[loot_count] or 0) + 1 | 
| jcallahan@307 | 736                 end | 
| jcallahan@307 | 737                 source_list[current_loot.identifier] = true | 
| jcallahan@77 | 738             end | 
| jcallahan@77 | 739         end | 
| jcallahan@75 | 740 | 
| jcallahan@131 | 741         for index = 1, #current_loot.list do | 
| jcallahan@131 | 742             table.insert(loot_table, current_loot.list[index]) | 
| jcallahan@75 | 743         end | 
| jcallahan@48 | 744     end | 
| jcallahan@75 | 745 end -- do-block | 
| jcallahan@48 | 746 | 
| jcallahan@97 | 747 | 
| jcallahan@97 | 748 local ReplaceKeywords | 
| jcallahan@97 | 749 do | 
| jcallahan@97 | 750     local KEYWORD_SUBSTITUTIONS = { | 
| jcallahan@97 | 751         class = PLAYER_CLASS, | 
| jcallahan@97 | 752         name = PLAYER_NAME, | 
| jcallahan@97 | 753         race = PLAYER_RACE, | 
| jcallahan@97 | 754     } | 
| jcallahan@97 | 755 | 
| jcallahan@97 | 756 | 
| jcallahan@97 | 757     function ReplaceKeywords(text) | 
| jcallahan@97 | 758         if not text or text == "" then | 
| jcallahan@97 | 759             return "" | 
| jcallahan@97 | 760         end | 
| jcallahan@97 | 761 | 
| jcallahan@97 | 762         for category, lookup in pairs(KEYWORD_SUBSTITUTIONS) do | 
| jcallahan@97 | 763             local category_format = ("<%s>"):format(category) | 
| jcallahan@97 | 764             text = text:gsub(lookup, category_format):gsub(lookup:lower(), category_format) | 
| jcallahan@97 | 765         end | 
| jcallahan@97 | 766         return text | 
| jcallahan@97 | 767     end | 
| jcallahan@97 | 768 end -- do-block | 
| jcallahan@97 | 769 | 
| jcallahan@97 | 770 | 
| jcallahan@154 | 771 -- Contains a dirty hack due to Blizzard's strange handling of Micro Dungeons; GetMapInfo() will not return correct information | 
| jcallahan@154 | 772 -- unless the WorldMapFrame is shown. | 
| jcallahan@143 | 773 do | 
| jcallahan@143 | 774     -- MapFileName = MapAreaID | 
| jcallahan@143 | 775     local MICRO_DUNGEON_IDS = { | 
| jcallahan@143 | 776         ShrineofTwoMoons = 903, | 
| jcallahan@143 | 777         ShrineofSevenStars = 905, | 
| jcallahan@143 | 778     } | 
| jcallahan@126 | 779 | 
| jcallahan@299 | 780     local function SetCurrentAreaID() | 
| jcallahan@156 | 781         if private.in_combat then | 
| jcallahan@156 | 782             private.set_area_id = true | 
| jcallahan@156 | 783             return | 
| jcallahan@156 | 784         end | 
| jcallahan@155 | 785         local map_area_id = _G.GetCurrentMapAreaID() | 
| jcallahan@155 | 786 | 
| jcallahan@155 | 787         if map_area_id == current_area_id then | 
| jcallahan@155 | 788             return | 
| jcallahan@155 | 789         end | 
| jcallahan@143 | 790         local world_map = _G.WorldMapFrame | 
| jcallahan@143 | 791         local map_visible = world_map:IsVisible() | 
| jcallahan@312 | 792         local sfx_value = tonumber(_G.GetCVar("Sound_EnableSFX")) | 
| jcallahan@143 | 793 | 
| jcallahan@143 | 794         if not map_visible then | 
| jcallahan@143 | 795             _G.SetCVar("Sound_EnableSFX", 0) | 
| jcallahan@143 | 796             world_map:Show() | 
| jcallahan@143 | 797         end | 
| jcallahan@143 | 798         local micro_dungeon_id = MICRO_DUNGEON_IDS[select(5, _G.GetMapInfo())] | 
| jcallahan@143 | 799 | 
| jcallahan@154 | 800         _G.SetMapToCurrentZone() | 
| jcallahan@154 | 801 | 
| jcallahan@143 | 802         if micro_dungeon_id then | 
| jcallahan@143 | 803             current_area_id = micro_dungeon_id | 
| jcallahan@143 | 804         else | 
| jcallahan@143 | 805             current_area_id = _G.GetCurrentMapAreaID() | 
| jcallahan@143 | 806         end | 
| jcallahan@143 | 807 | 
| jcallahan@154 | 808         if map_visible then | 
| jcallahan@154 | 809             _G.SetMapByID(map_area_id) | 
| jcallahan@154 | 810         else | 
| jcallahan@143 | 811             world_map:Hide() | 
| jcallahan@143 | 812             _G.SetCVar("Sound_EnableSFX", sfx_value) | 
| jcallahan@143 | 813         end | 
| jcallahan@143 | 814     end | 
| jcallahan@299 | 815 | 
| jcallahan@299 | 816     function WDP:HandleZoneChange(event_name) | 
| jcallahan@299 | 817         in_instance = _G.IsInInstance() | 
| jcallahan@299 | 818         SetCurrentAreaID() | 
| jcallahan@299 | 819     end | 
| jcallahan@154 | 820 end | 
| jcallahan@126 | 821 | 
| jcallahan@301 | 822 local function InitializeCurrentLoot() | 
| jcallahan@301 | 823     current_loot = { | 
| jcallahan@301 | 824         list = {}, | 
| jcallahan@301 | 825         sources = {}, | 
| jcallahan@301 | 826         identifier = current_action.identifier, | 
| jcallahan@301 | 827         label = current_action.loot_label or "drops", | 
| jcallahan@301 | 828         map_level = current_action.map_level, | 
| jcallahan@301 | 829         object_name = current_action.object_name, | 
| jcallahan@301 | 830         spell_label = current_action.spell_label, | 
| jcallahan@301 | 831         target_type = current_action.target_type, | 
| jcallahan@301 | 832         x = current_action.x, | 
| jcallahan@301 | 833         y = current_action.y, | 
| jcallahan@301 | 834         zone_data = current_action.zone_data, | 
| jcallahan@301 | 835     } | 
| jcallahan@301 | 836 | 
| jcallahan@301 | 837     table.wipe(current_action) | 
| jcallahan@301 | 838 end | 
| jcallahan@246 | 839 | 
| jcallahan@246 | 840 -- METHODS ------------------------------------------------------------ | 
| jcallahan@246 | 841 | 
| jcallahan@0 | 842 function WDP:OnInitialize() | 
| jcallahan@128 | 843     local db = LibStub("AceDB-3.0"):New("WoWDBProfilerData", DATABASE_DEFAULTS, "Default") | 
| jcallahan@270 | 844     private.db = db | 
| jcallahan@128 | 845     global_db = db.global | 
| jcallahan@128 | 846     char_db = db.char | 
| jcallahan@14 | 847 | 
| jcallahan@270 | 848     local raw_db = _G.WoWDBProfilerData | 
| jcallahan@18 | 849     local build_num = tonumber(private.build_num) | 
| jcallahan@14 | 850 | 
| jcallahan@136 | 851     if (raw_db.version and raw_db.version < DB_VERSION) or (raw_db.build_num and raw_db.build_num < build_num) then | 
| jcallahan@74 | 852         for entry in pairs(DATABASE_DEFAULTS.global) do | 
| jcallahan@128 | 853             global_db[entry] = {} | 
| jcallahan@74 | 854         end | 
| jcallahan@74 | 855     end | 
| jcallahan@35 | 856     raw_db.build_num = build_num | 
| jcallahan@63 | 857     raw_db.version = DB_VERSION | 
| jcallahan@249 | 858 | 
| jcallahan@312 | 859     private.InitializeCommentSystem() | 
| jcallahan@312 | 860     self:RegisterChatCommand("comment", private.ProcessCommentCommand) | 
| jcallahan@0 | 861 end | 
| jcallahan@0 | 862 | 
| jcallahan@0 | 863 | 
| jcallahan@153 | 864 function WDP:EventDispatcher(...) | 
| jcallahan@153 | 865     local event_name = ... | 
| jcallahan@153 | 866 | 
| jcallahan@153 | 867     if DEBUGGING then | 
| jcallahan@154 | 868         if event_name == "COMBAT_LOG_EVENT_UNFILTERED" then | 
| jcallahan@154 | 869             Debug(event_name) | 
| jcallahan@154 | 870         else | 
| jcallahan@154 | 871             Debug(...) | 
| jcallahan@153 | 872         end | 
| jcallahan@153 | 873     end | 
| jcallahan@153 | 874     local func = EVENT_MAPPING[event_name] | 
| jcallahan@153 | 875 | 
| jcallahan@153 | 876     if _G.type(func) == "boolean" then | 
| jcallahan@153 | 877         self[event_name](self, ...) | 
| jcallahan@153 | 878     elseif _G.type(func) == "function" then | 
| jcallahan@159 | 879         self[func](self, ...) | 
| jcallahan@153 | 880     end | 
| jcallahan@153 | 881 end | 
| jcallahan@153 | 882 | 
| jcallahan@153 | 883 | 
| jcallahan@0 | 884 function WDP:OnEnable() | 
| jcallahan@300 | 885     PLAYER_GUID = _G.UnitGUID("player") | 
| jcallahan@300 | 886 | 
| jcallahan@0 | 887     for event_name, mapping in pairs(EVENT_MAPPING) do | 
| jcallahan@156 | 888         if EVENT_DEBUG then | 
| jcallahan@153 | 889             self:RegisterEvent(event_name, "EventDispatcher") | 
| jcallahan@153 | 890         else | 
| jcallahan@153 | 891             self:RegisterEvent(event_name, (_G.type(mapping) ~= "boolean") and mapping or nil) | 
| jcallahan@153 | 892         end | 
| jcallahan@0 | 893     end | 
| jcallahan@95 | 894 | 
| jcallahan@95 | 895     for index = 1, _G.GetNumLanguages() do | 
| jcallahan@95 | 896         languages_known[_G.GetLanguageByIndex(index)] = true | 
| jcallahan@95 | 897     end | 
| jcallahan@187 | 898     item_process_timer_handle = self:ScheduleRepeatingTimer("ProcessItems", 30) | 
| jcallahan@31 | 899     target_location_timer_handle = self:ScheduleRepeatingTimer("UpdateTargetLocation", 0.5) | 
| jcallahan@19 | 900 | 
| jcallahan@19 | 901     _G.hooksecurefunc("UseContainerItem", function(bag_index, slot_index, target_unit) | 
| jcallahan@19 | 902         if target_unit then | 
| jcallahan@19 | 903             return | 
| jcallahan@19 | 904         end | 
| jcallahan@19 | 905         HandleItemUse(_G.GetContainerItemLink(bag_index, slot_index), bag_index, slot_index) | 
| jcallahan@19 | 906     end) | 
| jcallahan@19 | 907 | 
| jcallahan@19 | 908     _G.hooksecurefunc("UseItemByName", function(identifier, target_unit) | 
| jcallahan@19 | 909         if target_unit then | 
| jcallahan@19 | 910             return | 
| jcallahan@19 | 911         end | 
| jcallahan@19 | 912         local _, item_link = _G.GetItemInfo(identifier) | 
| jcallahan@19 | 913         HandleItemUse(item_link) | 
| jcallahan@19 | 914     end) | 
| jcallahan@263 | 915 | 
| jcallahan@299 | 916     self:HandleZoneChange("OnEnable") | 
| jcallahan@290 | 917     self:GROUP_ROSTER_UPDATE() | 
| jcallahan@0 | 918 end | 
| jcallahan@0 | 919 | 
| jcallahan@0 | 920 | 
| jcallahan@219 | 921 local ScrapeItemUpgradeStats | 
| jcallahan@219 | 922 do | 
| jcallahan@219 | 923     local intermediary = {} | 
| jcallahan@219 | 924 | 
| jcallahan@220 | 925     function ScrapeItemUpgradeStats(item_id, upgrade_id, reforge_id) | 
| jcallahan@220 | 926         if not ALLOWED_LOCALES[CLIENT_LOCALE] then | 
| jcallahan@220 | 927             return | 
| jcallahan@220 | 928         end | 
| jcallahan@219 | 929         local create_entry | 
| jcallahan@219 | 930 | 
| jcallahan@219 | 931         table.wipe(intermediary) | 
| jcallahan@219 | 932 | 
| jcallahan@219 | 933         for line_index = 1, DatamineTT:NumLines() do | 
| jcallahan@293 | 934             local left_text = _G["WDPDatamineTTTextLeft" .. line_index]:GetText():trim() | 
| jcallahan@293 | 935 | 
| jcallahan@293 | 936             if not left_text or left_text == "" or left_text:find("Socket") or left_text:find("Set:") then | 
| jcallahan@293 | 937                 break | 
| jcallahan@219 | 938             end | 
| jcallahan@219 | 939             local amount, stat = left_text:match("+(.-) (.*)") | 
| jcallahan@219 | 940 | 
| jcallahan@219 | 941             if amount and stat then | 
| jcallahan@220 | 942                 if reforge_id and reforge_id ~= 0 then | 
| jcallahan@220 | 943                     local reforge_string = stat:find("Reforged") | 
| jcallahan@220 | 944 | 
| jcallahan@220 | 945                     if reforge_string then | 
| jcallahan@220 | 946                         stat = stat:sub(0, reforge_string - 3) | 
| jcallahan@220 | 947                         intermediary.reforge_id = reforge_id | 
| jcallahan@220 | 948                     end | 
| jcallahan@219 | 949                 end | 
| jcallahan@219 | 950                 create_entry = true | 
| jcallahan@295 | 951                 intermediary[stat:lower():gsub(" ", "_"):gsub("|r", "")] = tonumber((amount:gsub(",", ""))) | 
| jcallahan@219 | 952             end | 
| jcallahan@219 | 953         end | 
| jcallahan@219 | 954 | 
| jcallahan@219 | 955         if not create_entry then | 
| jcallahan@219 | 956             return | 
| jcallahan@219 | 957         end | 
| jcallahan@219 | 958         local item = DBEntry("items", item_id) | 
| jcallahan@225 | 959         item.upgrade_id = upgrade_id | 
| jcallahan@219 | 960         item.upgrades = item.upgrades or {} | 
| jcallahan@219 | 961         item.upgrades[upgrade_id] = item.upgrades[upgrade_id] or {} | 
| jcallahan@219 | 962 | 
| jcallahan@219 | 963         for stat, amount in pairs(intermediary) do | 
| jcallahan@219 | 964             item.upgrades[upgrade_id][stat] = amount | 
| jcallahan@219 | 965         end | 
| jcallahan@219 | 966     end | 
| jcallahan@220 | 967 end | 
| jcallahan@220 | 968 | 
| jcallahan@220 | 969 -- do-block | 
| jcallahan@219 | 970 | 
| jcallahan@219 | 971 | 
| jcallahan@187 | 972 local function RecordItemData(item_id, item_link, durability) | 
| jcallahan@191 | 973     local item_string = select(3, item_link:find("^|%x+|H(.+)|h%[.+%]")) | 
| jcallahan@219 | 974     local item | 
| jcallahan@0 | 975 | 
| jcallahan@191 | 976     if item_string then | 
| jcallahan@220 | 977         local _, _, _, _, _, _, _, suffix_id, unique_id, _, reforge_id, upgrade_id = (":"):split(item_string) | 
| jcallahan@201 | 978         suffix_id = tonumber(suffix_id) | 
| jcallahan@219 | 979         upgrade_id = tonumber(upgrade_id) | 
| jcallahan@199 | 980 | 
| jcallahan@201 | 981         if suffix_id and suffix_id ~= 0 then | 
| jcallahan@219 | 982             item = DBEntry("items", item_id) | 
| jcallahan@201 | 983             item.suffix_id = suffix_id | 
| jcallahan@201 | 984             item.unique_id = bit.band(unique_id, 0xFFFF) | 
| jcallahan@201 | 985         end | 
| jcallahan@191 | 986 | 
| jcallahan@219 | 987         if upgrade_id and upgrade_id ~= 0 then | 
| jcallahan@220 | 988             DatamineTT:SetHyperlink(item_link) | 
| jcallahan@220 | 989             ScrapeItemUpgradeStats(item_id, upgrade_id, reforge_id) | 
| jcallahan@191 | 990         end | 
| jcallahan@0 | 991     end | 
| jcallahan@212 | 992 | 
| jcallahan@212 | 993     if durability and durability > 0 then | 
| jcallahan@219 | 994         item = item or DBEntry("items", item_id) | 
| jcallahan@212 | 995         item.durability = durability | 
| jcallahan@212 | 996     end | 
| jcallahan@0 | 997 end | 
| jcallahan@0 | 998 | 
| jcallahan@0 | 999 | 
| jcallahan@187 | 1000 function WDP:ProcessItems() | 
| jcallahan@187 | 1001     for slot_index = _G.INVSLOT_FIRST_EQUIPPED, _G.INVSLOT_LAST_EQUIPPED do | 
| jcallahan@1 | 1002         local item_id = _G.GetInventoryItemID("player", slot_index) | 
| jcallahan@0 | 1003 | 
| jcallahan@0 | 1004         if item_id and item_id > 0 then | 
| jcallahan@1 | 1005             local _, max_durability = _G.GetInventoryItemDurability(slot_index) | 
| jcallahan@187 | 1006             RecordItemData(item_id, _G.GetInventoryItemLink("player", slot_index), max_durability) | 
| jcallahan@0 | 1007         end | 
| jcallahan@0 | 1008     end | 
| jcallahan@0 | 1009 | 
| jcallahan@0 | 1010     for bag_index = 0, _G.NUM_BAG_SLOTS do | 
| jcallahan@0 | 1011         for slot_index = 1, _G.GetContainerNumSlots(bag_index) do | 
| jcallahan@1 | 1012             local item_id = _G.GetContainerItemID(bag_index, slot_index) | 
| jcallahan@0 | 1013 | 
| jcallahan@0 | 1014             if item_id and item_id > 0 then | 
| jcallahan@1 | 1015                 local _, max_durability = _G.GetContainerItemDurability(bag_index, slot_index) | 
| jcallahan@187 | 1016                 RecordItemData(item_id, _G.GetContainerItemLink(bag_index, slot_index), max_durability) | 
| jcallahan@0 | 1017             end | 
| jcallahan@0 | 1018         end | 
| jcallahan@0 | 1019     end | 
| jcallahan@0 | 1020 end | 
| jcallahan@0 | 1021 | 
| jcallahan@118 | 1022 | 
| jcallahan@215 | 1023 local TargetedNPC | 
| jcallahan@118 | 1024 do | 
| jcallahan@118 | 1025     local GENDER_NAMES = { | 
| jcallahan@118 | 1026         "UNKNOWN", | 
| jcallahan@118 | 1027         "MALE", | 
| jcallahan@118 | 1028         "FEMALE", | 
| jcallahan@118 | 1029     } | 
| jcallahan@118 | 1030 | 
| jcallahan@118 | 1031 | 
| jcallahan@118 | 1032     local REACTION_NAMES = { | 
| jcallahan@118 | 1033         "HATED", | 
| jcallahan@118 | 1034         "HOSTILE", | 
| jcallahan@118 | 1035         "UNFRIENDLY", | 
| jcallahan@118 | 1036         "NEUTRAL", | 
| jcallahan@118 | 1037         "FRIENDLY", | 
| jcallahan@118 | 1038         "HONORED", | 
| jcallahan@118 | 1039         "REVERED", | 
| jcallahan@118 | 1040         "EXALTED", | 
| jcallahan@118 | 1041     } | 
| jcallahan@118 | 1042 | 
| jcallahan@118 | 1043 | 
| jcallahan@118 | 1044     local POWER_TYPE_NAMES = { | 
| jcallahan@118 | 1045         ["0"] = "MANA", | 
| jcallahan@118 | 1046         ["1"] = "RAGE", | 
| jcallahan@118 | 1047         ["2"] = "FOCUS", | 
| jcallahan@118 | 1048         ["3"] = "ENERGY", | 
| jcallahan@118 | 1049         ["6"] = "RUNIC_POWER", | 
| jcallahan@118 | 1050     } | 
| jcallahan@118 | 1051 | 
| jcallahan@118 | 1052 | 
| jcallahan@215 | 1053     function TargetedNPC() | 
| jcallahan@118 | 1054         if not _G.UnitExists("target") or _G.UnitPlayerControlled("target") or currently_drunk then | 
| jcallahan@118 | 1055             current_target_id = nil | 
| jcallahan@118 | 1056             return | 
| jcallahan@118 | 1057         end | 
| jcallahan@118 | 1058         local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("target")) | 
| jcallahan@118 | 1059 | 
| jcallahan@171 | 1060         if not unit_idnum or not UnitTypeIsNPC(unit_type) then | 
| jcallahan@118 | 1061             return | 
| jcallahan@118 | 1062         end | 
| jcallahan@118 | 1063         current_target_id = unit_idnum | 
| jcallahan@118 | 1064 | 
| jcallahan@118 | 1065         local npc = NPCEntry(unit_idnum) | 
| jcallahan@118 | 1066         local _, class_token = _G.UnitClass("target") | 
| jcallahan@118 | 1067         npc.class = class_token | 
| jcallahan@118 | 1068         npc.faction = UnitFactionStanding("target") | 
| jcallahan@118 | 1069         npc.genders = npc.genders or {} | 
| jcallahan@118 | 1070         npc.genders[GENDER_NAMES[_G.UnitSex("target")] or "UNDEFINED"] = true | 
| jcallahan@118 | 1071         npc.is_pvp = _G.UnitIsPVP("target") and true or nil | 
| jcallahan@118 | 1072         npc.reaction = ("%s:%s:%s"):format(_G.UnitLevel("player"), _G.UnitFactionGroup("player"), REACTION_NAMES[_G.UnitReaction("player", "target")]) | 
| jcallahan@118 | 1073 | 
| jcallahan@248 | 1074         local encounter_data = npc:EncounterData(InstanceDifficultyToken()).stats | 
| jcallahan@118 | 1075         local npc_level = ("level_%d"):format(_G.UnitLevel("target")) | 
| jcallahan@250 | 1076         local level_data = encounter_data[npc_level] | 
| jcallahan@250 | 1077 | 
| jcallahan@250 | 1078         if not level_data then | 
| jcallahan@250 | 1079             level_data = {} | 
| jcallahan@250 | 1080             encounter_data[npc_level] = level_data | 
| jcallahan@250 | 1081         end | 
| jcallahan@257 | 1082         level_data.max_health = level_data.max_health or _G.UnitHealthMax("target") | 
| jcallahan@257 | 1083 | 
| jcallahan@257 | 1084         if not level_data.power then | 
| jcallahan@257 | 1085             local max_power = _G.UnitManaMax("target") | 
| jcallahan@257 | 1086 | 
| jcallahan@257 | 1087             if max_power > 0 then | 
| jcallahan@257 | 1088                 local power_type = _G.UnitPowerType("target") | 
| jcallahan@312 | 1089                 level_data.power = ("%s:%d"):format(POWER_TYPE_NAMES[tostring(power_type)] or power_type, max_power) | 
| jcallahan@257 | 1090             end | 
| jcallahan@118 | 1091         end | 
| jcallahan@118 | 1092         name_to_id_map[_G.UnitName("target")] = unit_idnum | 
| jcallahan@118 | 1093         return npc, unit_idnum | 
| jcallahan@118 | 1094     end | 
| jcallahan@118 | 1095 end -- do-block | 
| jcallahan@118 | 1096 | 
| jcallahan@118 | 1097 | 
| jcallahan@113 | 1098 do | 
| jcallahan@113 | 1099     local COORD_MAX = 5 | 
| jcallahan@0 | 1100 | 
| jcallahan@113 | 1101     function WDP:UpdateTargetLocation() | 
| jcallahan@113 | 1102         if currently_drunk or not _G.UnitExists("target") or _G.UnitPlayerControlled("target") or (_G.UnitIsTapped("target") and not _G.UnitIsDead("target")) then | 
| jcallahan@2 | 1103             return | 
| jcallahan@2 | 1104         end | 
| jcallahan@113 | 1105 | 
| jcallahan@113 | 1106         for index = 1, 4 do | 
| jcallahan@113 | 1107             if not _G.CheckInteractDistance("target", index) then | 
| jcallahan@113 | 1108                 return | 
| jcallahan@113 | 1109             end | 
| jcallahan@113 | 1110         end | 
| jcallahan@215 | 1111         local npc = TargetedNPC() | 
| jcallahan@113 | 1112 | 
| jcallahan@113 | 1113         if not npc then | 
| jcallahan@113 | 1114             return | 
| jcallahan@113 | 1115         end | 
| jcallahan@113 | 1116         local zone_name, area_id, x, y, map_level, difficulty_token = CurrentLocationData() | 
| jcallahan@248 | 1117         local npc_data = npc:EncounterData(difficulty_token).stats[("level_%d"):format(_G.UnitLevel("target"))] | 
| jcallahan@113 | 1118         local zone_token = ("%s:%d"):format(zone_name, area_id) | 
| jcallahan@118 | 1119         npc_data.locations = npc_data.locations or {} -- TODO: Fix this. It is broken. Possibly something to do with the timed updates. | 
| jcallahan@113 | 1120 | 
| jcallahan@113 | 1121         local zone_data = npc_data.locations[zone_token] | 
| jcallahan@113 | 1122 | 
| jcallahan@113 | 1123         if not zone_data then | 
| jcallahan@113 | 1124             zone_data = {} | 
| jcallahan@113 | 1125             npc_data.locations[zone_token] = zone_data | 
| jcallahan@113 | 1126         end | 
| jcallahan@113 | 1127 | 
| jcallahan@113 | 1128         for location_token in pairs(zone_data) do | 
| jcallahan@113 | 1129             local loc_level, loc_x, loc_y = (":"):split(location_token) | 
| jcallahan@113 | 1130             loc_level = tonumber(loc_level) | 
| jcallahan@113 | 1131 | 
| jcallahan@113 | 1132             if map_level == loc_level and math.abs(x - loc_x) <= COORD_MAX and math.abs(y - loc_y) <= COORD_MAX then | 
| jcallahan@113 | 1133                 return | 
| jcallahan@113 | 1134             end | 
| jcallahan@113 | 1135         end | 
| jcallahan@141 | 1136         zone_data[("%d:%d:%d"):format(map_level, x, y)] = true | 
| jcallahan@2 | 1137     end | 
| jcallahan@113 | 1138 end -- do-block | 
| jcallahan@2 | 1139 | 
| jcallahan@118 | 1140 | 
| jcallahan@246 | 1141 -- EVENT HANDLERS ----------------------------------------------------- | 
| jcallahan@246 | 1142 | 
| jcallahan@90 | 1143 function WDP:BLACK_MARKET_ITEM_UPDATE(event_name) | 
| jcallahan@243 | 1144     if not ALLOWED_LOCALES[CLIENT_LOCALE] then | 
| jcallahan@243 | 1145         return | 
| jcallahan@243 | 1146     end | 
| jcallahan@282 | 1147     local num_items = _G.C_BlackMarket.GetNumItems() or 0 | 
| jcallahan@56 | 1148 | 
| jcallahan@56 | 1149     for index = 1, num_items do | 
| jcallahan@56 | 1150         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 | 1151 | 
| jcallahan@56 | 1152         if item_link then | 
| jcallahan@56 | 1153             DBEntry("items", ItemLinkToID(item_link)).black_market = seller_name or "UNKNOWN" | 
| jcallahan@56 | 1154         end | 
| jcallahan@56 | 1155     end | 
| jcallahan@56 | 1156 end | 
| jcallahan@56 | 1157 | 
| jcallahan@56 | 1158 | 
| jcallahan@298 | 1159 local function UpdateUnitPet(unit_guid, unit_id) | 
| jcallahan@246 | 1160     local current_pet_guid = group_owner_guids_to_pet_guids[unit_guid] | 
| jcallahan@246 | 1161 | 
| jcallahan@246 | 1162     if current_pet_guid then | 
| jcallahan@246 | 1163         group_owner_guids_to_pet_guids[unit_guid] = nil | 
| jcallahan@246 | 1164         group_pet_guids[current_pet_guid] = nil | 
| jcallahan@246 | 1165     end | 
| jcallahan@246 | 1166     local pet_guid = _G.UnitGUID(unit_id .. "pet") | 
| jcallahan@246 | 1167 | 
| jcallahan@246 | 1168     if pet_guid then | 
| jcallahan@296 | 1169         group_owner_guids_to_pet_guids[unit_guid] = pet_guid | 
| jcallahan@246 | 1170         group_pet_guids[pet_guid] = true | 
| jcallahan@246 | 1171     end | 
| jcallahan@246 | 1172 end | 
| jcallahan@246 | 1173 | 
| jcallahan@246 | 1174 | 
| jcallahan@298 | 1175 function WDP:GROUP_ROSTER_UPDATE(event_name) | 
| jcallahan@298 | 1176     local is_raid = _G.IsInRaid() | 
| jcallahan@298 | 1177     local unit_type = is_raid and "raid" or "party" | 
| jcallahan@298 | 1178     local group_size = is_raid and _G.GetNumGroupMembers() or _G.GetNumSubgroupMembers() | 
| jcallahan@298 | 1179 | 
| jcallahan@299 | 1180     table.wipe(group_member_guids) | 
| jcallahan@298 | 1181 | 
| jcallahan@298 | 1182     for index = 1, group_size do | 
| jcallahan@298 | 1183         local unit_id = unit_type .. index | 
| jcallahan@298 | 1184         local unit_guid = _G.UnitGUID(unit_id) | 
| jcallahan@298 | 1185 | 
| jcallahan@299 | 1186         group_member_guids[unit_guid] = true | 
| jcallahan@298 | 1187         UpdateUnitPet(unit_guid, unit_id) | 
| jcallahan@298 | 1188     end | 
| jcallahan@299 | 1189     group_member_guids[PLAYER_GUID] = true | 
| jcallahan@298 | 1190 end | 
| jcallahan@298 | 1191 | 
| jcallahan@298 | 1192 | 
| jcallahan@298 | 1193 function WDP:UNIT_PET(event_name, unit_id) | 
| jcallahan@298 | 1194     UpdateUnitPet(_G.UnitGUID(unit_id), unit_id) | 
| jcallahan@298 | 1195 end | 
| jcallahan@298 | 1196 | 
| jcallahan@298 | 1197 | 
| jcallahan@178 | 1198 function WDP:SHOW_LOOT_TOAST(event_name, loot_type, item_link, quantity) | 
| jcallahan@312 | 1199     if not loot_type or (loot_type ~= "item" and loot_type ~= "money" and loot_type ~= "currency") then | 
| jcallahan@306 | 1200         Debug("%s: loot_type is %s. Item link is %s, and quantity is %d.", event_name, loot_type, item_link, quantity) | 
| jcallahan@306 | 1201         return | 
| jcallahan@306 | 1202     end | 
| jcallahan@301 | 1203     local container_id = private.loot_toast_container_id | 
| jcallahan@317 | 1204     local npc_id = private.raid_finder_boss_id or private.world_boss_id | 
| jcallahan@317 | 1205 | 
| jcallahan@317 | 1206     if npc_id then | 
| jcallahan@317 | 1207         -- slightly messy hack to workaround duplicate world bosses | 
| jcallahan@317 | 1208         local upper_limit = 0 | 
| jcallahan@317 | 1209         if DUPLICATE_WORLD_BOSS_IDS[npc_id] then | 
| jcallahan@317 | 1210             upper_limit = #DUPLICATE_WORLD_BOSS_IDS[npc_id] | 
| jcallahan@317 | 1211         end | 
| jcallahan@317 | 1212         for i = 0, upper_limit do | 
| jcallahan@317 | 1213             local temp_npc_id = npc_id | 
| jcallahan@317 | 1214 | 
| jcallahan@317 | 1215             if i > 0 then | 
| jcallahan@317 | 1216                 temp_npc_id = DUPLICATE_WORLD_BOSS_IDS[npc_id][i] | 
| jcallahan@312 | 1217             end | 
| jcallahan@317 | 1218 | 
| jcallahan@317 | 1219             local npc = NPCEntry(temp_npc_id) | 
| jcallahan@317 | 1220             if npc then | 
| jcallahan@317 | 1221                 local loot_label = "drops" | 
| jcallahan@317 | 1222                 local encounter_data = npc:EncounterData(InstanceDifficultyToken()) | 
| jcallahan@317 | 1223                 encounter_data[loot_label] = encounter_data[loot_label] or {} | 
| jcallahan@317 | 1224                 encounter_data.loot_counts = encounter_data.loot_counts or {} | 
| jcallahan@317 | 1225 | 
| jcallahan@317 | 1226                 if loot_type == "item" then | 
| jcallahan@317 | 1227                     local item_id = ItemLinkToID(item_link) | 
| jcallahan@317 | 1228                     if item_id then | 
| jcallahan@317 | 1229                         Debug("%s: %s X %d (%d)", event_name, item_link, quantity, item_id) | 
| jcallahan@317 | 1230                         table.insert(encounter_data[loot_label], ("%d:%d"):format(item_id, quantity)) | 
| jcallahan@317 | 1231                     else | 
| jcallahan@317 | 1232                         Debug("%s: ItemID is nil, from item link %s", event_name, item_link) | 
| jcallahan@317 | 1233                         return | 
| jcallahan@317 | 1234                     end | 
| jcallahan@317 | 1235                 elseif loot_type == "money" then | 
| jcallahan@317 | 1236                     Debug("%s: money X %d", event_name, quantity) | 
| jcallahan@317 | 1237                     table.insert(encounter_data[loot_label], ("money:%d"):format(quantity)) | 
| jcallahan@317 | 1238                 elseif loot_type == "currency" then | 
| jcallahan@317 | 1239                     local currency_texture = CurrencyLinkToTexture(item_link) | 
| jcallahan@317 | 1240                     if currency_texture and currency_texture ~= "" then | 
| jcallahan@317 | 1241                         Debug("%s: %s X %d", event_name, currency_texture, quantity) | 
| jcallahan@317 | 1242                         -- workaround for Patch 5.4.0 bug with Flexible raid Siege of Orgrimmar bosses and Valor Points | 
| jcallahan@317 | 1243                         if quantity > 1000 and currency_texture == "pvecurrency-valor" then | 
| jcallahan@317 | 1244                             quantity = math.floor(quantity / 100) | 
| jcallahan@317 | 1245                         end | 
| jcallahan@317 | 1246                         table.insert(encounter_data[loot_label], ("currency:%d:%s"):format(quantity, currency_texture)) | 
| jcallahan@317 | 1247                     else | 
| jcallahan@317 | 1248                         Debug("%s: Currency texture is nil, from currency link %s", event_name, item_link) | 
| jcallahan@317 | 1249                         return | 
| jcallahan@317 | 1250                     end | 
| jcallahan@317 | 1251                 end | 
| jcallahan@317 | 1252 | 
| jcallahan@317 | 1253                 if not boss_loot_toasting[temp_npc_id] then | 
| jcallahan@317 | 1254                     encounter_data.loot_counts[loot_label] = (encounter_data.loot_counts[loot_label] or 0) + 1 | 
| jcallahan@317 | 1255                     boss_loot_toasting[temp_npc_id] = true -- Do not count further loots until timer expires or another boss is killed | 
| jcallahan@317 | 1256                 end | 
| jcallahan@312 | 1257             end | 
| jcallahan@312 | 1258         end | 
| jcallahan@301 | 1259     elseif container_id then | 
| jcallahan@305 | 1260         InitializeCurrentLoot() | 
| jcallahan@305 | 1261 | 
| jcallahan@306 | 1262         -- Fake the loot characteristics to match that of an actual container item | 
| jcallahan@306 | 1263         current_loot.identifier = container_id | 
| jcallahan@306 | 1264         current_loot.label = "contains" | 
| jcallahan@306 | 1265         current_loot.target_type = AF.ITEM | 
| jcallahan@306 | 1266 | 
| jcallahan@312 | 1267         current_loot.sources[container_id] = current_loot.sources[container_id] or {} | 
| jcallahan@312 | 1268 | 
| jcallahan@301 | 1269         if loot_type == "item" then | 
| jcallahan@312 | 1270             local item_id = ItemLinkToID(item_link) | 
| jcallahan@312 | 1271             if item_id then | 
| jcallahan@312 | 1272                 Debug("%s: %s X %d (%d)", event_name, item_link, quantity, item_id) | 
| jcallahan@312 | 1273                 current_loot.sources[container_id][item_id] = current_loot.sources[container_id][item_id] or 0 + quantity | 
| jcallahan@312 | 1274             else | 
| jcallahan@301 | 1275                 Debug("%s: ItemID is nil, from item link %s", event_name, item_link) | 
| jcallahan@312 | 1276                 current_loot = nil | 
| jcallahan@301 | 1277                 return | 
| jcallahan@301 | 1278             end | 
| jcallahan@301 | 1279         elseif loot_type == "money" then | 
| jcallahan@312 | 1280             Debug("%s: money X %d", event_name, quantity) | 
| jcallahan@312 | 1281             current_loot.sources[container_id]["money"] = current_loot.sources[container_id]["money"] or 0 + quantity | 
| jcallahan@312 | 1282         elseif loot_type == "currency" then | 
| jcallahan@312 | 1283             local currency_texture = CurrencyLinkToTexture(item_link) | 
| jcallahan@312 | 1284             if currency_texture and currency_texture ~= "" then | 
| jcallahan@312 | 1285                 Debug("%s: %s X %d", event_name, currency_texture, quantity) | 
| jcallahan@312 | 1286                 local currency_token = ("currency:%s"):format(currency_texture) | 
| jcallahan@312 | 1287                 current_loot.sources[container_id][currency_token] = current_loot.sources[container_id][currency_token] or 0 + quantity | 
| jcallahan@312 | 1288             else | 
| jcallahan@312 | 1289                 Debug("%s: Currency texture is nil, from currency link %s", event_name, item_link) | 
| jcallahan@312 | 1290                 current_loot = nil | 
| jcallahan@312 | 1291                 return | 
| jcallahan@312 | 1292             end | 
| jcallahan@301 | 1293         end | 
| jcallahan@312 | 1294 | 
| jcallahan@301 | 1295         GenericLootUpdate("items") | 
| jcallahan@301 | 1296         current_loot = nil | 
| jcallahan@307 | 1297         private.container_loot_toasting = true -- Do not count further loots until timer expires or another container is opened | 
| jcallahan@301 | 1298     else | 
| jcallahan@307 | 1299         Debug("%s: NPC and Container are nil, storing loot toast data for 5 seconds.", event_name) | 
| jcallahan@307 | 1300 | 
| jcallahan@307 | 1301         loot_toast_data = loot_toast_data or {} | 
| jcallahan@312 | 1302         loot_toast_data[#loot_toast_data + 1] = { loot_type, item_link, quantity } | 
| jcallahan@307 | 1303 | 
| jcallahan@307 | 1304         loot_toast_data_timer_handle = WDP:ScheduleTimer(ClearLootToastData, 5) | 
| jcallahan@178 | 1305     end | 
| jcallahan@178 | 1306 end | 
| jcallahan@178 | 1307 | 
| jcallahan@178 | 1308 | 
| jcallahan@179 | 1309 do | 
| jcallahan@179 | 1310     local CHAT_MSG_LOOT_UPDATE_FUNCS = { | 
| jcallahan@179 | 1311         [AF.NPC] = function(item_id, quantity) | 
| jcallahan@245 | 1312             Debug("CHAT_MSG_LOOT: %d (%d)", item_id, quantity) | 
| jcallahan@179 | 1313         end, | 
| jcallahan@179 | 1314         [AF.ZONE] = function(item_id, quantity) | 
| jcallahan@312 | 1315             InitializeCurrentLoot() | 
| jcallahan@312 | 1316             current_loot.list[1] = ("%d:%d"):format(item_id, quantity) | 
| jcallahan@179 | 1317             GenericLootUpdate("zones") | 
| jcallahan@312 | 1318             current_loot = nil | 
| jcallahan@179 | 1319         end, | 
| jcallahan@179 | 1320     } | 
| jcallahan@177 | 1321 | 
| jcallahan@177 | 1322 | 
| jcallahan@179 | 1323     function WDP:CHAT_MSG_LOOT(event_name, message) | 
| jcallahan@179 | 1324         local category | 
| jcallahan@177 | 1325 | 
| jcallahan@179 | 1326         if current_action.spell_label ~= "EXTRACT_GAS" then | 
| jcallahan@179 | 1327             category = AF.ZONE | 
| jcallahan@179 | 1328         elseif private.raid_finder_boss_id then | 
| jcallahan@179 | 1329             category = AF.NPC | 
| jcallahan@179 | 1330         end | 
| jcallahan@179 | 1331         local update_func = CHAT_MSG_LOOT_UPDATE_FUNCS[category] | 
| jcallahan@177 | 1332 | 
| jcallahan@179 | 1333         if not category or not update_func then | 
| jcallahan@179 | 1334             return | 
| jcallahan@179 | 1335         end | 
| jcallahan@179 | 1336         local item_link, quantity = deformat(message, _G.LOOT_ITEM_PUSHED_SELF_MULTIPLE) | 
| jcallahan@179 | 1337 | 
| jcallahan@179 | 1338         if not item_link then | 
| jcallahan@179 | 1339             quantity, item_link = 1, deformat(message, _G.LOOT_ITEM_PUSHED_SELF) | 
| jcallahan@179 | 1340         end | 
| jcallahan@179 | 1341         local item_id = ItemLinkToID(item_link) | 
| jcallahan@179 | 1342 | 
| jcallahan@179 | 1343         if not item_id then | 
| jcallahan@179 | 1344             return | 
| jcallahan@179 | 1345         end | 
| jcallahan@179 | 1346         update_func(item_id, quantity) | 
| jcallahan@177 | 1347     end | 
| jcallahan@48 | 1348 end | 
| jcallahan@48 | 1349 | 
| jcallahan@312 | 1350 | 
| jcallahan@97 | 1351 function WDP:RecordQuote(event_name, message, source_name, language_name) | 
| jcallahan@112 | 1352     if not ALLOWED_LOCALES[CLIENT_LOCALE] or not source_name or not name_to_id_map[source_name] or (language_name ~= "" and not languages_known[language_name]) then | 
| jcallahan@97 | 1353         return | 
| jcallahan@95 | 1354     end | 
| jcallahan@97 | 1355     local npc = NPCEntry(name_to_id_map[source_name]) | 
| jcallahan@97 | 1356     npc.quotes = npc.quotes or {} | 
| jcallahan@97 | 1357     npc.quotes[event_name] = npc.quotes[event_name] or {} | 
| jcallahan@97 | 1358     npc.quotes[event_name][ReplaceKeywords(message)] = true | 
| jcallahan@97 | 1359 end | 
| jcallahan@95 | 1360 | 
| jcallahan@95 | 1361 | 
| jcallahan@95 | 1362 do | 
| jcallahan@40 | 1363     local SOBER_MATCH = _G.DRUNK_MESSAGE_ITEM_SELF1:gsub("%%s", ".+") | 
| jcallahan@40 | 1364 | 
| jcallahan@40 | 1365     local DRUNK_COMPARES = { | 
| jcallahan@40 | 1366         _G.DRUNK_MESSAGE_SELF2, | 
| jcallahan@40 | 1367         _G.DRUNK_MESSAGE_SELF3, | 
| jcallahan@40 | 1368         _G.DRUNK_MESSAGE_SELF4, | 
| jcallahan@40 | 1369     } | 
| jcallahan@40 | 1370 | 
| jcallahan@40 | 1371     local DRUNK_MATCHES = { | 
| jcallahan@254 | 1372         (_G.DRUNK_MESSAGE_SELF2:gsub("%%s", ".+")), | 
| jcallahan@254 | 1373         (_G.DRUNK_MESSAGE_SELF3:gsub("%%s", ".+")), | 
| jcallahan@254 | 1374         (_G.DRUNK_MESSAGE_SELF4:gsub("%%s", ".+")), | 
| jcallahan@40 | 1375     } | 
| jcallahan@40 | 1376 | 
| jcallahan@167 | 1377     local RECIPE_MATCH = _G.ERR_LEARN_RECIPE_S:gsub("%%s", "(.*)") | 
| jcallahan@167 | 1378 | 
| jcallahan@167 | 1379 | 
| jcallahan@167 | 1380     local function RecordDiscovery(tradeskill_name, tradeskill_index) | 
| jcallahan@167 | 1381         if tradeskill_name == private.discovered_recipe_name then | 
| jcallahan@167 | 1382             DBEntry("spells", tonumber(_G.GetTradeSkillRecipeLink(tradeskill_index):match("^|c%x%x%x%x%x%x%x%x|H%w+:(%d+)"))).discovery = ("%d:%d"):format(private.previous_spell_id, private.profession_level) | 
| jcallahan@167 | 1383 | 
| jcallahan@167 | 1384             private.discovered_recipe_name = nil | 
| jcallahan@167 | 1385             private.profession_level = nil | 
| jcallahan@167 | 1386             private.previous_spell_id = nil | 
| jcallahan@169 | 1387 | 
| jcallahan@169 | 1388             return true | 
| jcallahan@167 | 1389         end | 
| jcallahan@167 | 1390     end | 
| jcallahan@167 | 1391 | 
| jcallahan@167 | 1392 | 
| jcallahan@167 | 1393     local function IterativeRecordDiscovery() | 
| jcallahan@167 | 1394         TradeSkillExecutePer(RecordDiscovery) | 
| jcallahan@167 | 1395     end | 
| jcallahan@167 | 1396 | 
| jcallahan@167 | 1397 | 
| jcallahan@92 | 1398     function WDP:CHAT_MSG_SYSTEM(event_name, message) | 
| jcallahan@167 | 1399         if not private.trainer_shown then | 
| jcallahan@167 | 1400             local recipe_name = message:match(RECIPE_MATCH) | 
| jcallahan@167 | 1401 | 
| jcallahan@167 | 1402             if recipe_name and private.previous_spell_id then | 
| jcallahan@167 | 1403                 local profession_name, prof_level = _G.GetTradeSkillLine() | 
| jcallahan@167 | 1404 | 
| jcallahan@167 | 1405                 if profession_name == _G.UNKNOWN then | 
| jcallahan@167 | 1406                     return | 
| jcallahan@167 | 1407                 end | 
| jcallahan@167 | 1408                 private.discovered_recipe_name = recipe_name | 
| jcallahan@167 | 1409                 private.profession_level = prof_level | 
| jcallahan@167 | 1410 | 
| jcallahan@167 | 1411                 self:ScheduleTimer(IterativeRecordDiscovery, 0.2) | 
| jcallahan@167 | 1412             end | 
| jcallahan@167 | 1413         end | 
| jcallahan@167 | 1414 | 
| jcallahan@40 | 1415         if currently_drunk then | 
| jcallahan@40 | 1416             if message == _G.DRUNK_MESSAGE_SELF1 or message:match(SOBER_MATCH) then | 
| jcallahan@40 | 1417                 currently_drunk = nil | 
| jcallahan@40 | 1418             end | 
| jcallahan@40 | 1419             return | 
| jcallahan@40 | 1420         end | 
| jcallahan@40 | 1421 | 
| jcallahan@40 | 1422         for index = 1, #DRUNK_MATCHES do | 
| jcallahan@40 | 1423             if message == DRUNK_COMPARES[index] or message:match(DRUNK_MATCHES[index]) then | 
| jcallahan@40 | 1424                 currently_drunk = true | 
| jcallahan@40 | 1425                 break | 
| jcallahan@40 | 1426             end | 
| jcallahan@40 | 1427         end | 
| jcallahan@40 | 1428     end | 
| jcallahan@40 | 1429 end | 
| jcallahan@40 | 1430 | 
| jcallahan@307 | 1431 | 
| jcallahan@307 | 1432 do -- do-block | 
| jcallahan@23 | 1433     local FLAGS_NPC = bit.bor(_G.COMBATLOG_OBJECT_TYPE_GUARDIAN, _G.COMBATLOG_OBJECT_CONTROL_NPC) | 
| jcallahan@23 | 1434     local FLAGS_NPC_CONTROL = bit.bor(_G.COMBATLOG_OBJECT_AFFILIATION_OUTSIDER, _G.COMBATLOG_OBJECT_CONTROL_NPC) | 
| jcallahan@23 | 1435 | 
| jcallahan@23 | 1436     local function RecordNPCSpell(sub_event, source_guid, source_name, source_flags, dest_guid, dest_name, dest_flags, spell_id, spell_name) | 
| jcallahan@326 | 1437         if not spell_id or spell_id == SPELL_ID_DISGUISE then | 
| jcallahan@23 | 1438             return | 
| jcallahan@23 | 1439         end | 
| jcallahan@34 | 1440         local source_type, source_id = ParseGUID(source_guid) | 
| jcallahan@23 | 1441 | 
| jcallahan@171 | 1442         if not source_id or not UnitTypeIsNPC(source_type) then | 
| jcallahan@23 | 1443             return | 
| jcallahan@23 | 1444         end | 
| jcallahan@23 | 1445 | 
| jcallahan@23 | 1446         if bit.band(FLAGS_NPC_CONTROL, source_flags) == FLAGS_NPC_CONTROL and bit.band(FLAGS_NPC, source_flags) ~= 0 then | 
| jcallahan@248 | 1447             local encounter_data = NPCEntry(source_id):EncounterData(InstanceDifficultyToken()) | 
| jcallahan@28 | 1448             encounter_data.spells = encounter_data.spells or {} | 
| jcallahan@28 | 1449             encounter_data.spells[spell_id] = (encounter_data.spells[spell_id] or 0) + 1 | 
| jcallahan@23 | 1450         end | 
| jcallahan@23 | 1451     end | 
| jcallahan@23 | 1452 | 
| jcallahan@115 | 1453     local HEAL_BATTLE_PETS_SPELL_ID = 125801 | 
| jcallahan@115 | 1454 | 
| jcallahan@246 | 1455     local previous_combat_event = {} | 
| jcallahan@246 | 1456 | 
| jcallahan@23 | 1457     local COMBAT_LOG_FUNCS = { | 
| jcallahan@23 | 1458         SPELL_AURA_APPLIED = RecordNPCSpell, | 
| jcallahan@23 | 1459         SPELL_CAST_START = RecordNPCSpell, | 
| jcallahan@115 | 1460         SPELL_CAST_SUCCESS = function(sub_event, source_guid, source_name, source_flags, dest_guid, dest_name, dest_flags, spell_id, spell_name) | 
| jcallahan@115 | 1461             if spell_id == HEAL_BATTLE_PETS_SPELL_ID then | 
| jcallahan@115 | 1462                 local unit_type, unit_idnum = ParseGUID(source_guid) | 
| jcallahan@115 | 1463 | 
| jcallahan@171 | 1464                 if unit_idnum and UnitTypeIsNPC(unit_type) then | 
| jcallahan@115 | 1465                     NPCEntry(unit_idnum).stable_master = true | 
| jcallahan@115 | 1466                 end | 
| jcallahan@115 | 1467             end | 
| jcallahan@115 | 1468             RecordNPCSpell(sub_event, source_guid, source_name, source_flags, dest_guid, dest_name, dest_flags, spell_id, spell_name) | 
| jcallahan@115 | 1469         end, | 
| jcallahan@65 | 1470         UNIT_DIED = function(sub_event, source_guid, source_name, source_flags, dest_guid, dest_name, dest_flags, spell_id, spell_name) | 
| jcallahan@65 | 1471             local unit_type, unit_idnum = ParseGUID(dest_guid) | 
| jcallahan@65 | 1472 | 
| jcallahan@171 | 1473             if not unit_idnum or not UnitTypeIsNPC(unit_type) then | 
| jcallahan@245 | 1474                 Debug("%s: %s is not an NPC, or has no ID.", sub_event, dest_name or _G.UNKNOWN) | 
| jcallahan@177 | 1475                 ClearKilledNPC() | 
| jcallahan@98 | 1476                 private.harvesting = nil | 
| jcallahan@65 | 1477                 return | 
| jcallahan@65 | 1478             end | 
| jcallahan@177 | 1479 | 
| jcallahan@246 | 1480             if source_guid == "" then | 
| jcallahan@246 | 1481                 source_guid = nil | 
| jcallahan@246 | 1482             end | 
| jcallahan@246 | 1483             local killer_guid = source_guid or previous_combat_event.source_guid | 
| jcallahan@246 | 1484             local killer_name = source_name or previous_combat_event.source_name | 
| jcallahan@246 | 1485 | 
| jcallahan@299 | 1486             if not previous_combat_event.party_damage then | 
| jcallahan@312 | 1487                 --Debug("%s: %s was killed by %s (not group member or pet).", sub_event, dest_name or _G.UNKNOWN, killer_name or _G.UNKNOWN) -- broken in Patch 5.4 | 
| jcallahan@299 | 1488                 table.wipe(previous_combat_event) | 
| jcallahan@217 | 1489                 ClearKilledNPC() | 
| jcallahan@306 | 1490             else | 
| jcallahan@317 | 1491                 --Debug("%s: %s was killed by %s.", sub_event, dest_name or _G.UNKNOWN, killer_name or _G.UNKNOWN) -- broken in Patch 5.4 | 
| jcallahan@177 | 1492             end | 
| jcallahan@177 | 1493             killed_npc_id = unit_idnum | 
| jcallahan@177 | 1494             WDP:ScheduleTimer(ClearKilledNPC, 0.1) | 
| jcallahan@65 | 1495         end, | 
| jcallahan@23 | 1496     } | 
| jcallahan@23 | 1497 | 
| jcallahan@23 | 1498 | 
| jcallahan@246 | 1499     local NON_DAMAGE_EVENTS = { | 
| jcallahan@246 | 1500         SPELL_AURA_APPLIED = true, | 
| jcallahan@246 | 1501         SPELL_AURA_REMOVED = true, | 
| jcallahan@246 | 1502         SPELL_AURA_REMOVED_DOSE = true, | 
| jcallahan@246 | 1503         SPELL_CAST_FAILED = true, | 
| jcallahan@246 | 1504         SWING_MISSED = true, | 
| jcallahan@246 | 1505     } | 
| jcallahan@246 | 1506 | 
| jcallahan@299 | 1507     local DAMAGE_EVENTS = { | 
| jcallahan@299 | 1508         RANGE_DAMAGE = true, | 
| jcallahan@299 | 1509         SPELL_BUILDING_DAMAGE = true, | 
| jcallahan@299 | 1510         SPELL_DAMAGE = true, | 
| jcallahan@299 | 1511         SPELL_PERIODIC_DAMAGE = true, | 
| jcallahan@299 | 1512         SWING_DAMAGE = true, | 
| jcallahan@299 | 1513     } | 
| jcallahan@299 | 1514 | 
| jcallahan@246 | 1515 | 
| jcallahan@92 | 1516     function WDP:COMBAT_LOG_EVENT_UNFILTERED(event_name, 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 | 1517         local combat_log_func = COMBAT_LOG_FUNCS[sub_event] | 
| jcallahan@23 | 1518 | 
| jcallahan@23 | 1519         if not combat_log_func then | 
| jcallahan@299 | 1520             if DAMAGE_EVENTS[sub_event] then | 
| jcallahan@299 | 1521                 table.wipe(previous_combat_event) | 
| jcallahan@246 | 1522                 previous_combat_event.source_name = source_name | 
| jcallahan@299 | 1523 | 
| jcallahan@299 | 1524                 if source_guid ~= dest_guid and (in_instance or group_member_guids[source_guid] or group_pet_guids[source_guid]) then | 
| jcallahan@299 | 1525                     previous_combat_event.party_damage = true | 
| jcallahan@299 | 1526                 end | 
| jcallahan@246 | 1527             end | 
| jcallahan@23 | 1528             return | 
| jcallahan@23 | 1529         end | 
| jcallahan@23 | 1530         combat_log_func(sub_event, source_guid, source_name, source_flags, dest_guid, dest_name, dest_flags, ...) | 
| jcallahan@297 | 1531 | 
| jcallahan@297 | 1532         if NON_DAMAGE_EVENTS[sub_event] then | 
| jcallahan@297 | 1533             table.wipe(previous_combat_event) | 
| jcallahan@297 | 1534         end | 
| jcallahan@23 | 1535     end | 
| jcallahan@23 | 1536 | 
| jcallahan@44 | 1537     local DIPLOMACY_SPELL_ID = 20599 | 
| jcallahan@44 | 1538     local MR_POP_RANK1_SPELL_ID = 78634 | 
| jcallahan@44 | 1539     local MR_POP_RANK2_SPELL_ID = 78635 | 
| jcallahan@44 | 1540 | 
| jcallahan@44 | 1541     local REP_BUFFS = { | 
| jcallahan@44 | 1542         [_G.GetSpellInfo(30754)] = "CENARION_FAVOR", | 
| jcallahan@44 | 1543         [_G.GetSpellInfo(24705)] = "GRIM_VISAGE", | 
| jcallahan@44 | 1544         [_G.GetSpellInfo(32098)] = "HONOR_HOLD_FAVOR", | 
| jcallahan@44 | 1545         [_G.GetSpellInfo(39913)] = "NAZGRELS_FERVOR", | 
| jcallahan@44 | 1546         [_G.GetSpellInfo(39953)] = "SONG_OF_BATTLE", | 
| jcallahan@44 | 1547         [_G.GetSpellInfo(61849)] = "SPIRIT_OF_SHARING", | 
| jcallahan@44 | 1548         [_G.GetSpellInfo(32096)] = "THRALLMARS_FAVOR", | 
| jcallahan@44 | 1549         [_G.GetSpellInfo(39911)] = "TROLLBANES_COMMAND", | 
| jcallahan@44 | 1550         [_G.GetSpellInfo(95987)] = "UNBURDENED", | 
| jcallahan@44 | 1551         [_G.GetSpellInfo(100951)] = "WOW_ANNIVERSARY", | 
| jcallahan@44 | 1552     } | 
| jcallahan@44 | 1553 | 
| jcallahan@44 | 1554 | 
| jcallahan@44 | 1555     local FACTION_NAMES = { | 
| jcallahan@44 | 1556         CENARION_CIRCLE = _G.GetFactionInfoByID(609), | 
| jcallahan@44 | 1557         HONOR_HOLD = _G.GetFactionInfoByID(946), | 
| jcallahan@44 | 1558         THE_SHATAR = _G.GetFactionInfoByID(935), | 
| jcallahan@44 | 1559         THRALLMAR = _G.GetFactionInfoByID(947), | 
| jcallahan@44 | 1560     } | 
| jcallahan@44 | 1561 | 
| jcallahan@44 | 1562 | 
| jcallahan@44 | 1563     local MODIFIERS = { | 
| jcallahan@44 | 1564         CENARION_FAVOR = { | 
| jcallahan@44 | 1565             faction = FACTION_NAMES.CENARION_CIRCLE, | 
| jcallahan@44 | 1566             modifier = 0.25, | 
| jcallahan@44 | 1567         }, | 
| jcallahan@44 | 1568         GRIM_VISAGE = { | 
| jcallahan@44 | 1569             modifier = 0.1, | 
| jcallahan@44 | 1570         }, | 
| jcallahan@44 | 1571         HONOR_HOLD_FAVOR = { | 
| jcallahan@44 | 1572             faction = FACTION_NAMES.HONOR_HOLD, | 
| jcallahan@44 | 1573             modifier = 0.25, | 
| jcallahan@44 | 1574         }, | 
| jcallahan@44 | 1575         NAZGRELS_FERVOR = { | 
| jcallahan@44 | 1576             faction = FACTION_NAMES.THRALLMAR, | 
| jcallahan@44 | 1577             modifier = 0.1, | 
| jcallahan@44 | 1578         }, | 
| jcallahan@44 | 1579         SONG_OF_BATTLE = { | 
| jcallahan@44 | 1580             faction = FACTION_NAMES.THE_SHATAR, | 
| jcallahan@44 | 1581             modifier = 0.1, | 
| jcallahan@44 | 1582         }, | 
| jcallahan@44 | 1583         SPIRIT_OF_SHARING = { | 
| jcallahan@44 | 1584             modifier = 0.1, | 
| jcallahan@44 | 1585         }, | 
| jcallahan@44 | 1586         THRALLMARS_FAVOR = { | 
| jcallahan@44 | 1587             faction = FACTION_NAMES.THRALLMAR, | 
| jcallahan@44 | 1588             modifier = 0.25, | 
| jcallahan@44 | 1589         }, | 
| jcallahan@44 | 1590         TROLLBANES_COMMAND = { | 
| jcallahan@44 | 1591             faction = FACTION_NAMES.HONOR_HOLD, | 
| jcallahan@44 | 1592             modifier = 0.1, | 
| jcallahan@44 | 1593         }, | 
| jcallahan@44 | 1594         UNBURDENED = { | 
| jcallahan@44 | 1595             modifier = 0.1, | 
| jcallahan@44 | 1596         }, | 
| jcallahan@44 | 1597         WOW_ANNIVERSARY = { | 
| jcallahan@44 | 1598             modifier = 0.08, | 
| jcallahan@44 | 1599         } | 
| jcallahan@44 | 1600     } | 
| jcallahan@44 | 1601 | 
| jcallahan@44 | 1602 | 
| jcallahan@92 | 1603     function WDP:COMBAT_TEXT_UPDATE(event_name, message_type, faction_name, amount) | 
| jcallahan@177 | 1604         if message_type ~= "FACTION" or not killed_npc_id then | 
| jcallahan@44 | 1605             return | 
| jcallahan@44 | 1606         end | 
| jcallahan@44 | 1607         UpdateFactionData() | 
| jcallahan@44 | 1608 | 
| jcallahan@46 | 1609         if not faction_name or not faction_standings[faction_name] then | 
| jcallahan@46 | 1610             return | 
| jcallahan@46 | 1611         end | 
| jcallahan@177 | 1612         local npc = NPCEntry(killed_npc_id) | 
| jcallahan@177 | 1613         ClearKilledNPC() | 
| jcallahan@46 | 1614 | 
| jcallahan@44 | 1615         if not npc then | 
| jcallahan@98 | 1616             private.harvesting = nil | 
| jcallahan@44 | 1617             return | 
| jcallahan@44 | 1618         end | 
| jcallahan@98 | 1619         npc.harvested = private.harvesting | 
| jcallahan@98 | 1620         private.harvesting = nil | 
| jcallahan@98 | 1621 | 
| jcallahan@44 | 1622         local modifier = 1 | 
| jcallahan@44 | 1623 | 
| jcallahan@44 | 1624         if _G.IsSpellKnown(DIPLOMACY_SPELL_ID) then | 
| jcallahan@44 | 1625             modifier = modifier + 0.1 | 
| jcallahan@44 | 1626         end | 
| jcallahan@44 | 1627 | 
| jcallahan@44 | 1628         if _G.IsSpellKnown(MR_POP_RANK2_SPELL_ID) then | 
| jcallahan@44 | 1629             modifier = modifier + 0.1 | 
| jcallahan@44 | 1630         elseif _G.IsSpellKnown(MR_POP_RANK1_SPELL_ID) then | 
| jcallahan@44 | 1631             modifier = modifier + 0.05 | 
| jcallahan@44 | 1632         end | 
| jcallahan@44 | 1633 | 
| jcallahan@44 | 1634         for buff_name, buff_label in pairs(REP_BUFFS) do | 
| jcallahan@44 | 1635             if _G.UnitBuff("player", buff_name) then | 
| jcallahan@44 | 1636                 local modded_faction = MODIFIERS[buff_label].faction | 
| jcallahan@44 | 1637 | 
| jcallahan@44 | 1638                 if not modded_faction or faction_name == modded_faction then | 
| jcallahan@44 | 1639                     modifier = modifier + MODIFIERS[buff_label].modifier | 
| jcallahan@44 | 1640                 end | 
| jcallahan@44 | 1641             end | 
| jcallahan@44 | 1642         end | 
| jcallahan@65 | 1643         npc.reputations = npc.reputations or {} | 
| jcallahan@65 | 1644         npc.reputations[("%s:%s"):format(faction_name, faction_standings[faction_name])] = math.floor(amount / modifier) | 
| jcallahan@32 | 1645     end | 
| jcallahan@44 | 1646 end -- do-block | 
| jcallahan@18 | 1647 | 
| jcallahan@18 | 1648 | 
| jcallahan@140 | 1649 function WDP:CURSOR_UPDATE(event_name) | 
| jcallahan@141 | 1650     if current_action.fishing_target or _G.Minimap:IsMouseOver() or current_action.spell_label ~= "FISHING" then | 
| jcallahan@140 | 1651         return | 
| jcallahan@140 | 1652     end | 
| jcallahan@140 | 1653     local text = _G["GameTooltipTextLeft1"]:GetText() | 
| jcallahan@140 | 1654 | 
| jcallahan@140 | 1655     if not text or text == "Fishing Bobber" then | 
| jcallahan@140 | 1656         text = "NONE" | 
| jcallahan@140 | 1657     else | 
| jcallahan@140 | 1658         current_action.fishing_target = true | 
| jcallahan@140 | 1659     end | 
| jcallahan@140 | 1660     current_action.identifier = ("%s:%s"):format(current_action.spell_label, text) | 
| jcallahan@140 | 1661 end | 
| jcallahan@140 | 1662 | 
| jcallahan@140 | 1663 | 
| jcallahan@92 | 1664 function WDP:ITEM_TEXT_BEGIN(event_name) | 
| jcallahan@42 | 1665     local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("npc")) | 
| jcallahan@42 | 1666 | 
| jcallahan@42 | 1667     if not unit_idnum or unit_type ~= private.UNIT_TYPES.OBJECT or _G.UnitName("npc") ~= _G.ItemTextGetItem() then | 
| jcallahan@42 | 1668         return | 
| jcallahan@42 | 1669     end | 
| jcallahan@42 | 1670     UpdateDBEntryLocation("objects", unit_idnum) | 
| jcallahan@42 | 1671 end | 
| jcallahan@42 | 1672 | 
| jcallahan@42 | 1673 | 
| jcallahan@13 | 1674 do | 
| jcallahan@176 | 1675     local LOOT_OPENED_VERIFY_FUNCS = { | 
| jcallahan@324 | 1676         -- Item containers can be AOE-looted in Patch 5.4.2 if the user clicks fast enough, but this verification still works as long as they both have loot. | 
| jcallahan@16 | 1677         [AF.ITEM] = function() | 
| jcallahan@16 | 1678             local locked_item_id | 
| jcallahan@16 | 1679 | 
| jcallahan@16 | 1680             for bag_index = 0, _G.NUM_BAG_FRAMES do | 
| jcallahan@16 | 1681                 for slot_index = 1, _G.GetContainerNumSlots(bag_index) do | 
| jcallahan@324 | 1682                     local _, _, is_locked, _, _, is_lootable = _G.GetContainerItemInfo(bag_index, slot_index) | 
| jcallahan@324 | 1683 | 
| jcallahan@324 | 1684                     if is_locked and is_lootable then | 
| jcallahan@16 | 1685                         locked_item_id = ItemLinkToID(_G.GetContainerItemLink(bag_index, slot_index)) | 
| jcallahan@165 | 1686                         break | 
| jcallahan@16 | 1687                     end | 
| jcallahan@16 | 1688                 end | 
| jcallahan@165 | 1689 | 
| jcallahan@165 | 1690                 if locked_item_id then | 
| jcallahan@165 | 1691                     break | 
| jcallahan@165 | 1692                 end | 
| jcallahan@16 | 1693             end | 
| jcallahan@16 | 1694 | 
| jcallahan@122 | 1695             if not locked_item_id or (current_action.identifier and current_action.identifier ~= locked_item_id) then | 
| jcallahan@16 | 1696                 return false | 
| jcallahan@16 | 1697             end | 
| jcallahan@122 | 1698             current_action.identifier = locked_item_id | 
| jcallahan@16 | 1699             return true | 
| jcallahan@16 | 1700         end, | 
| jcallahan@322 | 1701         [AF.NPC] = true, | 
| jcallahan@14 | 1702         [AF.OBJECT] = true, | 
| jcallahan@17 | 1703         [AF.ZONE] = function() | 
| jcallahan@140 | 1704             current_action.zone_data = UpdateDBEntryLocation("zones", current_action.identifier) | 
| jcallahan@210 | 1705             return _G.IsFishingLoot() | 
| jcallahan@17 | 1706         end, | 
| jcallahan@13 | 1707     } | 
| jcallahan@13 | 1708 | 
| jcallahan@13 | 1709 | 
| jcallahan@176 | 1710     local LOOT_OPENED_UPDATE_FUNCS = { | 
| jcallahan@16 | 1711         [AF.ITEM] = function() | 
| jcallahan@28 | 1712             GenericLootUpdate("items") | 
| jcallahan@28 | 1713         end, | 
| jcallahan@28 | 1714         [AF.NPC] = function() | 
| jcallahan@75 | 1715             local difficulty_token = InstanceDifficultyToken() | 
| jcallahan@312 | 1716             local loot_label = current_loot.label | 
| jcallahan@77 | 1717             local source_list = {} | 
| jcallahan@75 | 1718 | 
| jcallahan@131 | 1719             for source_guid, loot_data in pairs(current_loot.sources) do | 
| jcallahan@78 | 1720                 local source_id = select(2, ParseGUID(source_guid)) | 
| jcallahan@75 | 1721                 local npc = NPCEntry(source_id) | 
| jcallahan@75 | 1722 | 
| jcallahan@75 | 1723                 if npc then | 
| jcallahan@248 | 1724                     local encounter_data = npc:EncounterData(difficulty_token) | 
| jcallahan@312 | 1725                     encounter_data[loot_label] = encounter_data[loot_label] or {} | 
| jcallahan@75 | 1726 | 
| jcallahan@78 | 1727                     if not source_list[source_guid] then | 
| jcallahan@77 | 1728                         encounter_data.loot_counts = encounter_data.loot_counts or {} | 
| jcallahan@312 | 1729                         encounter_data.loot_counts[loot_label] = (encounter_data.loot_counts[loot_label] or 0) + 1 | 
| jcallahan@312 | 1730                         source_list[source_guid] = true | 
| jcallahan@77 | 1731                     end | 
| jcallahan@77 | 1732 | 
| jcallahan@309 | 1733                     for loot_token, quantity in pairs(loot_data) do | 
| jcallahan@312 | 1734                         local loot_type, currency_texture = (":"):split(loot_token) | 
| jcallahan@312 | 1735 | 
| jcallahan@312 | 1736                         if loot_type == "currency" and currency_texture then | 
| jcallahan@312 | 1737                             table.insert(encounter_data[loot_label], ("currency:%d:%s"):format(quantity, currency_texture)) | 
| jcallahan@309 | 1738                         elseif loot_token == "money" then | 
| jcallahan@312 | 1739                             table.insert(encounter_data[loot_label], ("money:%d"):format(quantity)) | 
| jcallahan@309 | 1740                         else | 
| jcallahan@312 | 1741                             table.insert(encounter_data[loot_label], ("%d:%d"):format(loot_token, quantity)) | 
| jcallahan@309 | 1742                         end | 
| jcallahan@75 | 1743                     end | 
| jcallahan@75 | 1744                 end | 
| jcallahan@75 | 1745             end | 
| jcallahan@16 | 1746         end, | 
| jcallahan@13 | 1747         [AF.OBJECT] = function() | 
| jcallahan@28 | 1748             GenericLootUpdate("objects", InstanceDifficultyToken()) | 
| jcallahan@17 | 1749         end, | 
| jcallahan@17 | 1750         [AF.ZONE] = function() | 
| jcallahan@141 | 1751             local location_token = ("%d:%d:%d"):format(current_loot.map_level, current_loot.x, current_loot.y) | 
| jcallahan@41 | 1752 | 
| jcallahan@41 | 1753             -- This will start life as a boolean true. | 
| jcallahan@131 | 1754             if _G.type(current_loot.zone_data[location_token]) ~= "table" then | 
| jcallahan@131 | 1755                 current_loot.zone_data[location_token] = { | 
| jcallahan@41 | 1756                     drops = {} | 
| jcallahan@41 | 1757                 } | 
| jcallahan@41 | 1758             end | 
| jcallahan@132 | 1759             local loot_count = ("%s_count"):format(current_loot.label) | 
| jcallahan@131 | 1760             current_loot.zone_data[location_token][loot_count] = (current_loot.zone_data[location_token][loot_count] or 0) + 1 | 
| jcallahan@41 | 1761 | 
| jcallahan@131 | 1762             if current_loot.sources then | 
| jcallahan@131 | 1763                 for source_guid, loot_data in pairs(current_loot.sources) do | 
| jcallahan@131 | 1764                     for item_id, quantity in pairs(loot_data) do | 
| jcallahan@131 | 1765                         table.insert(current_loot.zone_data[location_token].drops, ("%d:%d"):format(item_id, quantity)) | 
| jcallahan@131 | 1766                     end | 
| jcallahan@131 | 1767                 end | 
| jcallahan@131 | 1768             end | 
| jcallahan@131 | 1769 | 
| jcallahan@131 | 1770             if #current_loot.list <= 0 then | 
| jcallahan@131 | 1771                 return | 
| jcallahan@131 | 1772             end | 
| jcallahan@131 | 1773 | 
| jcallahan@131 | 1774             for index = 1, #current_loot.list do | 
| jcallahan@131 | 1775                 table.insert(current_loot.zone_data[location_token].drops, current_loot.loot_list[index]) | 
| jcallahan@41 | 1776             end | 
| jcallahan@13 | 1777         end, | 
| jcallahan@13 | 1778     } | 
| jcallahan@13 | 1779 | 
| jcallahan@79 | 1780     -- Prevent opening the same loot window multiple times from recording data multiple times. | 
| jcallahan@79 | 1781     local loot_guid_registry = {} | 
| jcallahan@124 | 1782 | 
| jcallahan@124 | 1783 | 
| jcallahan@124 | 1784     function WDP:LOOT_CLOSED(event_name) | 
| jcallahan@131 | 1785         current_loot = nil | 
| jcallahan@131 | 1786         table.wipe(current_action) | 
| jcallahan@124 | 1787     end | 
| jcallahan@124 | 1788 | 
| jcallahan@13 | 1789 | 
| jcallahan@322 | 1790     local function ExtrapolatedCurrentActionFromLootData(event_name) | 
| jcallahan@322 | 1791         local extrapolated_guid_registry = {} | 
| jcallahan@322 | 1792         local num_guids = 0 | 
| jcallahan@322 | 1793 | 
| jcallahan@322 | 1794         table.wipe(current_action) | 
| jcallahan@322 | 1795 | 
| jcallahan@322 | 1796         for loot_slot = 1, _G.GetNumLootItems() do | 
| jcallahan@322 | 1797             local loot_info = { | 
| jcallahan@322 | 1798                 _G.GetLootSourceInfo(loot_slot) | 
| jcallahan@322 | 1799             } | 
| jcallahan@322 | 1800 | 
| jcallahan@322 | 1801             for loot_index = 1, #loot_info, 2 do | 
| jcallahan@322 | 1802                 local source_guid = loot_info[loot_index] | 
| jcallahan@322 | 1803 | 
| jcallahan@322 | 1804                 if not extrapolated_guid_registry[source_guid] then | 
| jcallahan@322 | 1805                     local unit_type, unit_idnum = ParseGUID(source_guid) | 
| jcallahan@322 | 1806 | 
| jcallahan@322 | 1807                     if unit_type and unit_idnum then | 
| jcallahan@322 | 1808                         extrapolated_guid_registry[source_guid] = { | 
| jcallahan@322 | 1809                             unit_type, | 
| jcallahan@322 | 1810                             unit_idnum | 
| jcallahan@322 | 1811                         } | 
| jcallahan@322 | 1812 | 
| jcallahan@322 | 1813                         num_guids = num_guids + 1 | 
| jcallahan@322 | 1814                     end | 
| jcallahan@322 | 1815                 end | 
| jcallahan@322 | 1816             end | 
| jcallahan@322 | 1817         end | 
| jcallahan@322 | 1818         local log_source = event_name .. "- ExtrapolatedCurrentActionFromLootData" | 
| jcallahan@322 | 1819 | 
| jcallahan@322 | 1820         if num_guids == 0 then | 
| jcallahan@322 | 1821             Debug("%s: No GUIDs found in loot. Blank loot window?", log_source) | 
| jcallahan@322 | 1822             return false | 
| jcallahan@322 | 1823         end | 
| jcallahan@326 | 1824 | 
| jcallahan@326 | 1825         if private.previous_spell_id and private.EXTRAPOLATION_BANNED_SPELL_IDS[private.previous_spell_id] then | 
| jcallahan@326 | 1826             Debug("%s: Problematic spell id %s found. Loot extrapolation for this set of loot would have run an increased risk of introducing bad data into the system.", log_source, private.previous_spell_id) | 
| jcallahan@326 | 1827             return false | 
| jcallahan@326 | 1828         end | 
| jcallahan@326 | 1829 | 
| jcallahan@322 | 1830         local num_npcs = 0 | 
| jcallahan@322 | 1831         local num_objects = 0 | 
| jcallahan@324 | 1832         local num_itemcontainers = 0 | 
| jcallahan@322 | 1833 | 
| jcallahan@322 | 1834         for source_guid, guid_data in pairs(extrapolated_guid_registry) do | 
| jcallahan@322 | 1835             local unit_type = guid_data[1] | 
| jcallahan@324 | 1836             local loot_label = (unit_type == private.UNIT_TYPES.OBJECT) and "opening" or (UnitTypeIsNPC(unit_type) and "drops") or ((unit_type == private.UNIT_TYPES.PLAYER) and "contains") | 
| jcallahan@322 | 1837 | 
| jcallahan@322 | 1838             if loot_label then | 
| jcallahan@322 | 1839                 local unit_idnum = guid_data[2] | 
| jcallahan@322 | 1840 | 
| jcallahan@322 | 1841                 if loot_guid_registry[loot_label] and loot_guid_registry[loot_label][source_guid] then | 
| jcallahan@322 | 1842                     Debug("%s: Previously scanned loot for unit with GUID %s and identifier %s.", log_source, source_guid, unit_idnum) | 
| jcallahan@322 | 1843                 elseif unit_type == private.UNIT_TYPES.OBJECT and unit_idnum ~= OBJECT_ID_FISHING_BOBBER then | 
| jcallahan@322 | 1844                     current_action.loot_label = loot_label | 
| jcallahan@322 | 1845                     current_action.spell_label = "OPENING" | 
| jcallahan@322 | 1846                     current_action.target_type = AF.OBJECT | 
| jcallahan@322 | 1847                     current_action.identifier = unit_idnum | 
| jcallahan@322 | 1848                     num_objects = num_objects + 1 | 
| jcallahan@322 | 1849                 elseif UnitTypeIsNPC(unit_type) then | 
| jcallahan@322 | 1850                     current_action.loot_label = loot_label | 
| jcallahan@322 | 1851                     current_action.target_type = AF.NPC | 
| jcallahan@322 | 1852                     current_action.identifier = unit_idnum | 
| jcallahan@322 | 1853                     num_npcs = num_npcs + 1 | 
| jcallahan@324 | 1854                 -- Item container GUIDs are currently of the 'PLAYER' type; this may be unintended and could change in the future. | 
| jcallahan@324 | 1855                 elseif unit_type == private.UNIT_TYPES.PLAYER then | 
| jcallahan@324 | 1856                     current_action.loot_label = loot_label | 
| jcallahan@324 | 1857                     current_action.target_type = AF.ITEM | 
| jcallahan@324 | 1858                     -- current_action.identifier assigned during loot verification. | 
| jcallahan@324 | 1859                     num_itemcontainers = num_itemcontainers + 1 | 
| jcallahan@322 | 1860                 end | 
| jcallahan@322 | 1861             else | 
| jcallahan@322 | 1862                 -- Bail here; not only do we not know what this unit is, but we don't want to attribute loot to something that doesn't actually drop it. | 
| jcallahan@322 | 1863                 Debug("%s: Unit with GUID %s has unsupported type for looting.", log_source, source_guid) | 
| jcallahan@322 | 1864                 return false | 
| jcallahan@322 | 1865             end | 
| jcallahan@322 | 1866         end | 
| jcallahan@322 | 1867 | 
| jcallahan@322 | 1868         if not current_action.target_type then | 
| jcallahan@322 | 1869             Debug("%s: Failure to obtain target_type.", log_source) | 
| jcallahan@322 | 1870             return false | 
| jcallahan@322 | 1871         end | 
| jcallahan@322 | 1872 | 
| jcallahan@322 | 1873         -- We can't figure out what dropped the loot. This shouldn't ever happen, but hey - Blizzard does some awesome stuff on occasion. | 
| jcallahan@324 | 1874         if (num_npcs > 0 and num_objects + num_itemcontainers > 0) or (num_objects > 0 and num_npcs + num_itemcontainers > 0) or (num_itemcontainers > 0 and num_npcs + num_objects > 0) then | 
| jcallahan@324 | 1875             Debug("%s: Mixed target types are not supported. NPCs - %d, Objects - %d, Item Containers - %d.", log_source, num_npcs, num_objects, num_itemcontainers) | 
| jcallahan@322 | 1876             return false | 
| jcallahan@322 | 1877         end | 
| jcallahan@322 | 1878 | 
| jcallahan@322 | 1879         Debug("%s: Successfully extrapolated information for current_action.", log_source) | 
| jcallahan@322 | 1880         return true | 
| jcallahan@322 | 1881     end | 
| jcallahan@322 | 1882 | 
| jcallahan@322 | 1883 | 
| jcallahan@92 | 1884     function WDP:LOOT_OPENED(event_name) | 
| jcallahan@132 | 1885         if current_loot then | 
| jcallahan@322 | 1886             current_loot = nil | 
| jcallahan@322 | 1887             Debug("%s: Previous loot did not process in time for this event. Attempting to extrapolate current_action from loot data.", event_name) | 
| jcallahan@322 | 1888 | 
| jcallahan@322 | 1889             if not ExtrapolatedCurrentActionFromLootData(event_name) then | 
| jcallahan@322 | 1890                 Debug("%s: Unable to extrapolate current_action. Aborting attempts to handle loot for now.", event_name) | 
| jcallahan@322 | 1891                 return | 
| jcallahan@322 | 1892             end | 
| jcallahan@18 | 1893         end | 
| jcallahan@151 | 1894 | 
| jcallahan@151 | 1895         if not current_action.target_type then | 
| jcallahan@322 | 1896             Debug("%s: No target type found. Attempting to extrapolate current_action from loot data.", event_name) | 
| jcallahan@322 | 1897 | 
| jcallahan@322 | 1898             if not ExtrapolatedCurrentActionFromLootData(event_name) then | 
| jcallahan@322 | 1899                 Debug("%s: Unable to extrapolate current_action. Aborting attempts to handle loot for now.", event_name) | 
| jcallahan@322 | 1900                 return | 
| jcallahan@322 | 1901             end | 
| jcallahan@151 | 1902         end | 
| jcallahan@176 | 1903         local verify_func = LOOT_OPENED_VERIFY_FUNCS[current_action.target_type] | 
| jcallahan@176 | 1904         local update_func = LOOT_OPENED_UPDATE_FUNCS[current_action.target_type] | 
| jcallahan@13 | 1905 | 
| jcallahan@14 | 1906         if not verify_func or not update_func then | 
| jcallahan@322 | 1907             Debug("%s: The current action's target type is unsupported or nil.", event_name) | 
| jcallahan@13 | 1908             return | 
| jcallahan@13 | 1909         end | 
| jcallahan@13 | 1910 | 
| jcallahan@14 | 1911         if _G.type(verify_func) == "function" and not verify_func() then | 
| jcallahan@324 | 1912             Debug("%s: The current action type, %s, is supported but has failed loot verification.", event_name, private.ACTION_TYPE_NAMES[current_action.target_type]) | 
| jcallahan@14 | 1913             return | 
| jcallahan@14 | 1914         end | 
| jcallahan@80 | 1915         local guids_used = {} | 
| jcallahan@132 | 1916 | 
| jcallahan@301 | 1917         InitializeCurrentLoot() | 
| jcallahan@217 | 1918         loot_guid_registry[current_loot.label] = loot_guid_registry[current_loot.label] or {} | 
| jcallahan@217 | 1919 | 
| jcallahan@55 | 1920         for loot_slot = 1, _G.GetNumLootItems() do | 
| jcallahan@302 | 1921             local icon_texture, item_text, slot_quantity, quality, locked = _G.GetLootSlotInfo(loot_slot) | 
| jcallahan@55 | 1922             local slot_type = _G.GetLootSlotType(loot_slot) | 
| jcallahan@237 | 1923             local loot_info = { | 
| jcallahan@237 | 1924                 _G.GetLootSourceInfo(loot_slot) | 
| jcallahan@237 | 1925             } | 
| jcallahan@13 | 1926 | 
| jcallahan@237 | 1927             -- Odd index is GUID, even is count. | 
| jcallahan@237 | 1928             for loot_index = 1, #loot_info, 2 do | 
| jcallahan@237 | 1929                 local source_guid = loot_info[loot_index] | 
| jcallahan@75 | 1930 | 
| jcallahan@237 | 1931                 if not loot_guid_registry[current_loot.label][source_guid] then | 
| jcallahan@237 | 1932                     local loot_quantity = loot_info[loot_index + 1] | 
| jcallahan@324 | 1933 | 
| jcallahan@324 | 1934                     -- There is a new bug in 5.4.0 that causes GetLootSlotInfo() to (rarely) return nil values for slot_quantity. | 
| jcallahan@324 | 1935                     if slot_quantity then | 
| jcallahan@324 | 1936                         -- We need slot_quantity to account for an old bug where loot_quantity is sometimes '1' for stacks of items, such as cloth. | 
| jcallahan@324 | 1937                         if slot_quantity > loot_quantity then | 
| jcallahan@324 | 1938                             loot_quantity = slot_quantity | 
| jcallahan@324 | 1939                         end | 
| jcallahan@324 | 1940 | 
| jcallahan@324 | 1941                         local source_type, source_id = ParseGUID(source_guid) | 
| jcallahan@324 | 1942                         local source_key = ("%s:%d"):format(private.UNIT_TYPE_NAMES[source_type + 1], source_id) | 
| jcallahan@324 | 1943 | 
| jcallahan@324 | 1944                         if slot_type == _G.LOOT_SLOT_ITEM then | 
| jcallahan@324 | 1945                             local item_id = ItemLinkToID(_G.GetLootSlotLink(loot_slot)) | 
| jcallahan@324 | 1946                             Debug("GUID: %s - Type:ID: %s - ItemID: %d - Amount: %d (%d)", loot_info[loot_index], source_key, item_id, loot_info[loot_index + 1], slot_quantity) | 
| jcallahan@308 | 1947                             current_loot.sources[source_guid] = current_loot.sources[source_guid] or {} | 
| jcallahan@324 | 1948                             current_loot.sources[source_guid][item_id] = current_loot.sources[source_guid][item_id] or 0 + loot_quantity | 
| jcallahan@309 | 1949                             guids_used[source_guid] = true | 
| jcallahan@324 | 1950                         elseif slot_type == _G.LOOT_SLOT_MONEY then | 
| jcallahan@324 | 1951                             Debug("GUID: %s - Type:ID: %s - Money - Amount: %d (%d)", loot_info[loot_index], source_key, loot_info[loot_index + 1], slot_quantity) | 
| jcallahan@324 | 1952                             if current_loot.target_type == AF.ZONE then | 
| jcallahan@324 | 1953                                 table.insert(current_loot.list, ("money:%d"):format(loot_quantity)) | 
| jcallahan@324 | 1954                             else | 
| jcallahan@324 | 1955                                 current_loot.sources[source_guid] = current_loot.sources[source_guid] or {} | 
| jcallahan@324 | 1956                                 current_loot.sources[source_guid]["money"] = current_loot.sources[source_guid]["money"] or 0 + loot_quantity | 
| jcallahan@324 | 1957                                 guids_used[source_guid] = true | 
| jcallahan@324 | 1958                             end | 
| jcallahan@324 | 1959                         elseif slot_type == _G.LOOT_SLOT_CURRENCY then | 
| jcallahan@324 | 1960                             -- Same bug with GetLootSlotInfo() will screw up currency when it happens, so we won't process this slot's loot. | 
| jcallahan@324 | 1961                             if icon_texture then | 
| jcallahan@324 | 1962                                 Debug("GUID: %s - Type:ID: %s - Currency: %s - Amount: %d (%d)", loot_info[loot_index], source_key, icon_texture, loot_info[loot_index + 1], slot_quantity) | 
| jcallahan@324 | 1963                                 if current_loot.target_type == AF.ZONE then | 
| jcallahan@324 | 1964                                     table.insert(current_loot.list, ("currency:%d:%s"):format(loot_quantity, icon_texture:match("[^\\]+$"):lower())) | 
| jcallahan@324 | 1965                                 else | 
| jcallahan@324 | 1966                                     local currency_token = ("currency:%s"):format(icon_texture:match("[^\\]+$"):lower()) | 
| jcallahan@324 | 1967 | 
| jcallahan@324 | 1968                                     current_loot.sources[source_guid] = current_loot.sources[source_guid] or {} | 
| jcallahan@324 | 1969                                     current_loot.sources[source_guid][currency_token] = current_loot.sources[source_guid][currency_token] or 0 + loot_quantity | 
| jcallahan@324 | 1970                                     guids_used[source_guid] = true | 
| jcallahan@324 | 1971                                 end | 
| jcallahan@324 | 1972                             else | 
| jcallahan@324 | 1973                                 Debug("%s: Slot quantity is nil for loot slot %d of the entity with GUID %s and Type:ID: %s.", event_name, loot_slot, loot_info[loot_index], source_key) | 
| jcallahan@324 | 1974                             end | 
| jcallahan@308 | 1975                         end | 
| jcallahan@324 | 1976                     else | 
| jcallahan@324 | 1977                         -- If this is nil, then the item's quantity could be wrong if loot_quantity is wrong, so we won't process this slot's loot. | 
| jcallahan@324 | 1978                         Debug("%s: Slot quantity is nil for loot slot %d of the entity with GUID %s and Type:ID: %s.", event_name, loot_slot, loot_info[loot_index], source_key) | 
| jcallahan@79 | 1979                     end | 
| jcallahan@75 | 1980                 end | 
| jcallahan@13 | 1981             end | 
| jcallahan@13 | 1982         end | 
| jcallahan@80 | 1983 | 
| jcallahan@81 | 1984         for guid in pairs(guids_used) do | 
| jcallahan@217 | 1985             loot_guid_registry[current_loot.label][guid] = true | 
| jcallahan@80 | 1986         end | 
| jcallahan@13 | 1987         update_func() | 
| jcallahan@1 | 1988     end | 
| jcallahan@13 | 1989 end -- do-block | 
| jcallahan@0 | 1990 | 
| jcallahan@0 | 1991 | 
| jcallahan@89 | 1992 function WDP:MAIL_SHOW(event_name) | 
| jcallahan@89 | 1993     local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("npc")) | 
| jcallahan@89 | 1994 | 
| jcallahan@89 | 1995     if not unit_idnum or unit_type ~= private.UNIT_TYPES.OBJECT then | 
| jcallahan@89 | 1996         return | 
| jcallahan@89 | 1997     end | 
| jcallahan@89 | 1998     UpdateDBEntryLocation("objects", unit_idnum) | 
| jcallahan@89 | 1999 end | 
| jcallahan@89 | 2000 | 
| jcallahan@89 | 2001 | 
| jcallahan@44 | 2002 do | 
| jcallahan@44 | 2003     local POINT_MATCH_PATTERNS = { | 
| jcallahan@44 | 2004         ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING:gsub("%%d", "(%%d+)")), -- May no longer be necessary | 
| jcallahan@44 | 2005         ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_3V3:gsub("%%d", "(%%d+)")), -- May no longer be necessary | 
| jcallahan@44 | 2006         ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_5V5:gsub("%%d", "(%%d+)")), -- May no longer be necessary | 
| jcallahan@44 | 2007         ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_BG:gsub("%%d", "(%%d+)")), | 
| jcallahan@44 | 2008         ("^%s$"):format(_G.ITEM_REQ_ARENA_RATING_3V3_BG:gsub("%%d", "(%%d+)")), | 
| jcallahan@44 | 2009     } | 
| jcallahan@5 | 2010 | 
| jcallahan@68 | 2011     local ITEM_REQ_REPUTATION_MATCH = "Requires (.-) %- (.*)" | 
| jcallahan@87 | 2012     local ITEM_REQ_QUEST_MATCH1 = "Requires: .*" | 
| jcallahan@87 | 2013     local ITEM_REQ_QUEST_MATCH2 = "Must have completed: .*" | 
| jcallahan@68 | 2014 | 
| jcallahan@133 | 2015     local current_merchant | 
| jcallahan@133 | 2016     local merchant_standing | 
| jcallahan@133 | 2017 | 
| jcallahan@133 | 2018     function WDP:MERCHANT_CLOSED(event_name) | 
| jcallahan@133 | 2019         current_merchant = nil | 
| jcallahan@133 | 2020         merchant_standing = nil | 
| jcallahan@133 | 2021     end | 
| jcallahan@133 | 2022 | 
| jcallahan@133 | 2023 | 
| jcallahan@89 | 2024     function WDP:UpdateMerchantItems(event_name) | 
| jcallahan@144 | 2025         if not current_merchant or event_name == "MERCHANT_SHOW" then | 
| jcallahan@195 | 2026             local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("npc")) | 
| jcallahan@4 | 2027 | 
| jcallahan@171 | 2028             if not unit_idnum or not UnitTypeIsNPC(unit_type) then | 
| jcallahan@133 | 2029                 return | 
| jcallahan@133 | 2030             end | 
| jcallahan@195 | 2031             merchant_standing = select(2, UnitFactionStanding("npc")) | 
| jcallahan@133 | 2032             current_merchant = NPCEntry(unit_idnum) | 
| jcallahan@133 | 2033             current_merchant.sells = current_merchant.sells or {} | 
| jcallahan@44 | 2034         end | 
| jcallahan@55 | 2035         local current_filters = _G.GetMerchantFilter() | 
| jcallahan@57 | 2036         _G.SetMerchantFilter(_G.LE_LOOT_FILTER_ALL) | 
| jcallahan@57 | 2037         _G.MerchantFrame_Update() | 
| jcallahan@57 | 2038 | 
| jcallahan@150 | 2039         local num_items = _G.GetMerchantNumItems() | 
| jcallahan@150 | 2040 | 
| jcallahan@44 | 2041         for item_index = 1, num_items do | 
| jcallahan@44 | 2042             local _, _, copper_price, stack_size, num_available, _, extended_cost = _G.GetMerchantItemInfo(item_index) | 
| jcallahan@44 | 2043             local item_id = ItemLinkToID(_G.GetMerchantItemLink(item_index)) | 
| jcallahan@5 | 2044 | 
| jcallahan@324 | 2045             DatamineTT:ClearLines() | 
| jcallahan@324 | 2046             DatamineTT:SetMerchantItem(item_index) | 
| jcallahan@324 | 2047 | 
| jcallahan@324 | 2048             if not item_id then | 
| jcallahan@324 | 2049                 local item_name, item_link = DatamineTT:GetItem() | 
| jcallahan@324 | 2050                 item_id = ItemLinkToID(item_link) | 
| jcallahan@324 | 2051                 Debug("%s: GetMerchantItemLink() still ocassionally fails, apparently. Failed item's ID - %s", event_name, item_id) | 
| jcallahan@324 | 2052             end | 
| jcallahan@324 | 2053 | 
| jcallahan@44 | 2054             if item_id and item_id > 0 then | 
| jcallahan@44 | 2055                 local price_string = ActualCopperCost(copper_price, merchant_standing) | 
| jcallahan@5 | 2056 | 
| jcallahan@68 | 2057                 local num_lines = DatamineTT:NumLines() | 
| jcallahan@68 | 2058 | 
| jcallahan@68 | 2059                 for line_index = 1, num_lines do | 
| jcallahan@68 | 2060                     local current_line = _G["WDPDatamineTTTextLeft" .. line_index] | 
| jcallahan@68 | 2061 | 
| jcallahan@68 | 2062                     if not current_line then | 
| jcallahan@68 | 2063                         break | 
| jcallahan@68 | 2064                     end | 
| jcallahan@68 | 2065                     local faction, reputation = current_line:GetText():match(ITEM_REQ_REPUTATION_MATCH) | 
| jcallahan@68 | 2066 | 
| jcallahan@68 | 2067                     if faction or reputation then | 
| jcallahan@68 | 2068                         DBEntry("items", item_id).req_reputation = ("%s:%s"):format(faction:gsub("-", ""), reputation:upper()) | 
| jcallahan@68 | 2069                         break | 
| jcallahan@68 | 2070                     end | 
| jcallahan@68 | 2071                 end | 
| jcallahan@68 | 2072 | 
| jcallahan@87 | 2073                 for line_index = 1, num_lines do | 
| jcallahan@87 | 2074                     local current_line = _G["WDPDatamineTTTextLeft" .. line_index] | 
| jcallahan@87 | 2075 | 
| jcallahan@87 | 2076                     if not current_line then | 
| jcallahan@87 | 2077                         break | 
| jcallahan@87 | 2078                     end | 
| jcallahan@87 | 2079                     local line_text = current_line:GetText() | 
| jcallahan@87 | 2080                     local quest_name = line_text:match(ITEM_REQ_QUEST_MATCH1) or line_text:match(ITEM_REQ_QUEST_MATCH2) | 
| jcallahan@87 | 2081 | 
| jcallahan@87 | 2082                     if quest_name then | 
| jcallahan@87 | 2083                         DBEntry("items", item_id).req_quest = ("%s"):format(quest_name:gsub("(.+): ", ""), quest_name) | 
| jcallahan@87 | 2084                         break | 
| jcallahan@87 | 2085                     end | 
| jcallahan@87 | 2086                 end | 
| jcallahan@87 | 2087 | 
| jcallahan@44 | 2088                 if extended_cost then | 
| jcallahan@53 | 2089                     local battleground_rating = 0 | 
| jcallahan@53 | 2090                     local personal_rating = 0 | 
| jcallahan@53 | 2091                     local required_season_amount | 
| jcallahan@5 | 2092 | 
| jcallahan@68 | 2093                     for line_index = 1, num_lines do | 
| jcallahan@44 | 2094                         local current_line = _G["WDPDatamineTTTextLeft" .. line_index] | 
| jcallahan@5 | 2095 | 
| jcallahan@44 | 2096                         if not current_line then | 
| jcallahan@44 | 2097                             break | 
| jcallahan@44 | 2098                         end | 
| jcallahan@53 | 2099                         required_season_amount = current_line:GetText():match("Requires earning a total of (%d+)\n(.-) for the season.") | 
| jcallahan@5 | 2100 | 
| jcallahan@44 | 2101                         for match_index = 1, #POINT_MATCH_PATTERNS do | 
| jcallahan@44 | 2102                             local match1, match2 = current_line:GetText():match(POINT_MATCH_PATTERNS[match_index]) | 
| jcallahan@53 | 2103                             personal_rating = personal_rating + (match1 or 0) | 
| jcallahan@53 | 2104                             battleground_rating = battleground_rating + (match2 or 0) | 
| jcallahan@5 | 2105 | 
| jcallahan@44 | 2106                             if match1 or match2 then | 
| jcallahan@44 | 2107                                 break | 
| jcallahan@44 | 2108                             end | 
| jcallahan@44 | 2109                         end | 
| jcallahan@5 | 2110                     end | 
| jcallahan@44 | 2111                     local currency_list = {} | 
| jcallahan@44 | 2112                     local item_count = _G.GetMerchantItemCostInfo(item_index) | 
| jcallahan@50 | 2113 | 
| jcallahan@50 | 2114                     -- Keeping this around in case Blizzard makes the two points diverge at some point. | 
| jcallahan@53 | 2115                     --                    price_string = ("%s:%s:%s:%s"):format(price_string, battleground_rating, personal_rating, required_season_amount or 0) | 
| jcallahan@53 | 2116                     price_string = ("%s:%s:%s"):format(price_string, personal_rating, required_season_amount or 0) | 
| jcallahan@5 | 2117 | 
| jcallahan@44 | 2118                     for cost_index = 1, item_count do | 
| jcallahan@324 | 2119                         -- The third return (Blizz calls "currency_link") of GetMerchantItemCostItem only returns item links as of Patch 5.3.0. | 
| jcallahan@317 | 2120                         local icon_texture, amount_required, item_link = _G.GetMerchantItemCostItem(item_index, cost_index) | 
| jcallahan@317 | 2121                         local currency_identifier = item_link and ItemLinkToID(item_link) or nil | 
| jcallahan@317 | 2122 | 
| jcallahan@317 | 2123                         if (not currency_identifier or currency_identifier < 1) and icon_texture then | 
| jcallahan@317 | 2124                             currency_identifier = icon_texture:match("[^\\]+$"):lower() | 
| jcallahan@317 | 2125                         end | 
| jcallahan@317 | 2126 | 
| jcallahan@317 | 2127                         if currency_identifier then | 
| jcallahan@317 | 2128                             currency_list[#currency_list + 1] = ("(%s:%s)"):format(amount_required, currency_identifier) | 
| jcallahan@44 | 2129                         end | 
| jcallahan@44 | 2130                     end | 
| jcallahan@44 | 2131 | 
| jcallahan@44 | 2132                     for currency_index = 1, #currency_list do | 
| jcallahan@44 | 2133                         price_string = ("%s:%s"):format(price_string, currency_list[currency_index]) | 
| jcallahan@5 | 2134                     end | 
| jcallahan@5 | 2135                 end | 
| jcallahan@133 | 2136                 current_merchant.sells[item_id] = ("%s:%s:[%s]"):format(num_available, stack_size, price_string) | 
| jcallahan@44 | 2137             end | 
| jcallahan@44 | 2138         end | 
| jcallahan@5 | 2139 | 
| jcallahan@44 | 2140         if _G.CanMerchantRepair() then | 
| jcallahan@133 | 2141             current_merchant.can_repair = true | 
| jcallahan@5 | 2142         end | 
| jcallahan@57 | 2143         _G.SetMerchantFilter(current_filters) | 
| jcallahan@57 | 2144         _G.MerchantFrame_Update() | 
| jcallahan@4 | 2145     end | 
| jcallahan@44 | 2146 end -- do-block | 
| jcallahan@4 | 2147 | 
| jcallahan@89 | 2148 | 
| jcallahan@92 | 2149 function WDP:PET_BAR_UPDATE(event_name) | 
| jcallahan@122 | 2150     if current_action.spell_label ~= "MIND_CONTROL" then | 
| jcallahan@25 | 2151         return | 
| jcallahan@25 | 2152     end | 
| jcallahan@34 | 2153     local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("pet")) | 
| jcallahan@25 | 2154 | 
| jcallahan@171 | 2155     if not unit_idnum or not UnitTypeIsNPC(unit_type) then | 
| jcallahan@25 | 2156         return | 
| jcallahan@25 | 2157     end | 
| jcallahan@29 | 2158     NPCEntry(unit_idnum).mind_control = true | 
| jcallahan@122 | 2159     table.wipe(current_action) | 
| jcallahan@25 | 2160 end | 
| jcallahan@25 | 2161 | 
| jcallahan@25 | 2162 | 
| jcallahan@115 | 2163 function WDP:PET_JOURNAL_LIST_UPDATE(event_name) | 
| jcallahan@324 | 2164     -- This function produces data currently unused by wowdb.com and it makes debugging errors in the .lua output nearly impossible due to the massive bloat. | 
| jcallahan@309 | 2165     if DEBUGGING then | 
| jcallahan@309 | 2166         return | 
| jcallahan@309 | 2167     end | 
| jcallahan@309 | 2168 | 
| jcallahan@115 | 2169     local num_pets = LPJ:NumPets() | 
| jcallahan@115 | 2170 | 
| jcallahan@115 | 2171     for index, pet_id in LPJ:IteratePetIDs() do | 
| jcallahan@115 | 2172         local _, _, is_owned, _, level, _, _, name, icon, pet_type, npc_id, _, _, is_wild = _G.C_PetJournal.GetPetInfoByIndex(index) | 
| jcallahan@115 | 2173 | 
| jcallahan@115 | 2174         if is_owned then | 
| jcallahan@115 | 2175             local health, max_health, attack, speed, rarity = _G.C_PetJournal.GetPetStats(pet_id) | 
| jcallahan@115 | 2176 | 
| jcallahan@139 | 2177             if rarity then | 
| jcallahan@139 | 2178                 local rarity_name = _G["BATTLE_PET_BREED_QUALITY" .. rarity] | 
| jcallahan@139 | 2179                 local npc = NPCEntry(npc_id) | 
| jcallahan@139 | 2180                 npc.wild_pet = is_wild or nil | 
| jcallahan@139 | 2181                 npc.battle_pet_data = npc.battle_pet_data or {} | 
| jcallahan@139 | 2182                 npc.battle_pet_data[rarity_name] = npc.battle_pet_data[rarity_name] or {} | 
| jcallahan@139 | 2183                 npc.battle_pet_data[rarity_name]["level_" .. level] = npc.battle_pet_data[rarity_name]["level_" .. level] or {} | 
| jcallahan@139 | 2184 | 
| jcallahan@139 | 2185                 local data = npc.battle_pet_data[rarity_name]["level_" .. level] | 
| jcallahan@139 | 2186                 data.max_health = max_health | 
| jcallahan@139 | 2187                 data.attack = attack | 
| jcallahan@139 | 2188                 data.speed = speed | 
| jcallahan@139 | 2189             end | 
| jcallahan@115 | 2190         end | 
| jcallahan@115 | 2191     end | 
| jcallahan@115 | 2192 end | 
| jcallahan@115 | 2193 | 
| jcallahan@115 | 2194 | 
| jcallahan@156 | 2195 function WDP:PLAYER_REGEN_DISABLED(event_name) | 
| jcallahan@156 | 2196     private.in_combat = true | 
| jcallahan@156 | 2197 end | 
| jcallahan@156 | 2198 | 
| jcallahan@156 | 2199 | 
| jcallahan@156 | 2200 function WDP:PLAYER_REGEN_ENABLED(event_name) | 
| jcallahan@156 | 2201     private.in_combat = nil | 
| jcallahan@156 | 2202 | 
| jcallahan@156 | 2203     if private.set_area_id then | 
| jcallahan@299 | 2204         self:HandleZoneChange(event_name) | 
| jcallahan@156 | 2205         private.set_area_id = nil | 
| jcallahan@156 | 2206     end | 
| jcallahan@156 | 2207 end | 
| jcallahan@156 | 2208 | 
| jcallahan@156 | 2209 | 
| jcallahan@118 | 2210 function WDP:PLAYER_TARGET_CHANGED(event_name) | 
| jcallahan@215 | 2211     if not TargetedNPC() then | 
| jcallahan@118 | 2212         return | 
| jcallahan@2 | 2213     end | 
| jcallahan@151 | 2214     current_action.target_type = AF.NPC | 
| jcallahan@118 | 2215     self:UpdateTargetLocation() | 
| jcallahan@118 | 2216 end | 
| jcallahan@2 | 2217 | 
| jcallahan@89 | 2218 | 
| jcallahan@12 | 2219 do | 
| jcallahan@12 | 2220     local function UpdateQuestJuncture(point) | 
| jcallahan@12 | 2221         local unit_name = _G.UnitName("questnpc") | 
| jcallahan@9 | 2222 | 
| jcallahan@12 | 2223         if not unit_name then | 
| jcallahan@12 | 2224             return | 
| jcallahan@12 | 2225         end | 
| jcallahan@34 | 2226         local unit_type, unit_id = ParseGUID(_G.UnitGUID("questnpc")) | 
| jcallahan@9 | 2227 | 
| jcallahan@12 | 2228         if unit_type == private.UNIT_TYPES.OBJECT then | 
| jcallahan@38 | 2229             UpdateDBEntryLocation("objects", unit_id) | 
| jcallahan@12 | 2230         end | 
| jcallahan@19 | 2231         local quest = DBEntry("quests", _G.GetQuestID()) | 
| jcallahan@12 | 2232         quest[point] = quest[point] or {} | 
| jcallahan@12 | 2233         quest[point][("%s:%d"):format(private.UNIT_TYPE_NAMES[unit_type + 1], unit_id)] = true | 
| jcallahan@24 | 2234 | 
| jcallahan@24 | 2235         return quest | 
| jcallahan@12 | 2236     end | 
| jcallahan@10 | 2237 | 
| jcallahan@12 | 2238 | 
| jcallahan@92 | 2239     function WDP:QUEST_COMPLETE(event_name) | 
| jcallahan@97 | 2240         local quest = UpdateQuestJuncture("end") | 
| jcallahan@97 | 2241 | 
| jcallahan@112 | 2242         if ALLOWED_LOCALES[CLIENT_LOCALE] then | 
| jcallahan@112 | 2243             quest.reward_text = ReplaceKeywords(_G.GetRewardText()) | 
| jcallahan@112 | 2244         end | 
| jcallahan@67 | 2245         -- Make sure the quest NPC isn't erroneously recorded as giving reputation for quests which award it. | 
| jcallahan@177 | 2246         ClearKilledNPC() | 
| jcallahan@10 | 2247     end | 
| jcallahan@10 | 2248 | 
| jcallahan@12 | 2249 | 
| jcallahan@92 | 2250     function WDP:QUEST_DETAIL(event_name) | 
| jcallahan@24 | 2251         local quest = UpdateQuestJuncture("begin") | 
| jcallahan@24 | 2252 | 
| jcallahan@46 | 2253         if not quest then | 
| jcallahan@46 | 2254             return | 
| jcallahan@46 | 2255         end | 
| jcallahan@24 | 2256         quest.classes = quest.classes or {} | 
| jcallahan@27 | 2257         quest.classes[PLAYER_CLASS] = true | 
| jcallahan@24 | 2258 | 
| jcallahan@24 | 2259         quest.races = quest.races or {} | 
| jcallahan@100 | 2260         quest.races[(PLAYER_RACE == "Pandaren") and ("%s_%s"):format(PLAYER_RACE, PLAYER_FACTION or "Neutral") or PLAYER_RACE] = true | 
| jcallahan@10 | 2261     end | 
| jcallahan@12 | 2262 end -- do-block | 
| jcallahan@9 | 2263 | 
| jcallahan@9 | 2264 | 
| jcallahan@92 | 2265 function WDP:QUEST_LOG_UPDATE(event_name) | 
| jcallahan@38 | 2266     local selected_quest = _G.GetQuestLogSelection() -- Save current selection to be restored when we're done. | 
| jcallahan@36 | 2267     local entry_index, processed_quests = 1, 0 | 
| jcallahan@36 | 2268     local _, num_quests = _G.GetNumQuestLogEntries() | 
| jcallahan@36 | 2269 | 
| jcallahan@36 | 2270     while processed_quests <= num_quests do | 
| jcallahan@36 | 2271         local _, _, _, _, is_header, _, _, _, quest_id = _G.GetQuestLogTitle(entry_index) | 
| jcallahan@36 | 2272 | 
| jcallahan@84 | 2273         if quest_id == 0 then | 
| jcallahan@84 | 2274             processed_quests = processed_quests + 1 | 
| jcallahan@84 | 2275         elseif not is_header then | 
| jcallahan@36 | 2276             _G.SelectQuestLogEntry(entry_index); | 
| jcallahan@36 | 2277 | 
| jcallahan@36 | 2278             local quest = DBEntry("quests", quest_id) | 
| jcallahan@36 | 2279             quest.timer = _G.GetQuestLogTimeLeft() | 
| jcallahan@37 | 2280             quest.can_share = _G.GetQuestLogPushable() and true or nil | 
| jcallahan@36 | 2281             processed_quests = processed_quests + 1 | 
| jcallahan@36 | 2282         end | 
| jcallahan@36 | 2283         entry_index = entry_index + 1 | 
| jcallahan@36 | 2284     end | 
| jcallahan@36 | 2285     _G.SelectQuestLogEntry(selected_quest) | 
| jcallahan@4 | 2286     self:UnregisterEvent("QUEST_LOG_UPDATE") | 
| jcallahan@4 | 2287 end | 
| jcallahan@4 | 2288 | 
| jcallahan@4 | 2289 | 
| jcallahan@97 | 2290 function WDP:QUEST_PROGRESS(event_name) | 
| jcallahan@112 | 2291     if not ALLOWED_LOCALES[CLIENT_LOCALE] then | 
| jcallahan@112 | 2292         return | 
| jcallahan@112 | 2293     end | 
| jcallahan@97 | 2294     DBEntry("quests", _G.GetQuestID()).progress_text = ReplaceKeywords(_G.GetProgressText()) | 
| jcallahan@97 | 2295 end | 
| jcallahan@97 | 2296 | 
| jcallahan@97 | 2297 | 
| jcallahan@92 | 2298 function WDP:UNIT_QUEST_LOG_CHANGED(event_name, unit_id) | 
| jcallahan@4 | 2299     if unit_id ~= "player" then | 
| jcallahan@4 | 2300         return | 
| jcallahan@4 | 2301     end | 
| jcallahan@4 | 2302     self:RegisterEvent("QUEST_LOG_UPDATE") | 
| jcallahan@4 | 2303 end | 
| jcallahan@4 | 2304 | 
| jcallahan@4 | 2305 | 
| jcallahan@92 | 2306 do | 
| jcallahan@92 | 2307     local TRADESKILL_TOOLS = { | 
| jcallahan@92 | 2308         Anvil = anvil_spell_ids, | 
| jcallahan@92 | 2309         Forge = forge_spell_ids, | 
| jcallahan@92 | 2310     } | 
| jcallahan@92 | 2311 | 
| jcallahan@92 | 2312 | 
| jcallahan@167 | 2313     local function RegisterTools(tradeskill_name, tradeskill_index) | 
| jcallahan@167 | 2314         local spell_id = tonumber(_G.GetTradeSkillRecipeLink(tradeskill_index):match("^|c%x%x%x%x%x%x%x%x|H%w+:(%d+)")) | 
| jcallahan@167 | 2315         local required_tool = _G.GetTradeSkillTools(tradeskill_index) | 
| jcallahan@167 | 2316 | 
| jcallahan@167 | 2317         if required_tool then | 
| jcallahan@167 | 2318             for tool_name, registry in pairs(TRADESKILL_TOOLS) do | 
| jcallahan@167 | 2319                 if required_tool:find(tool_name) then | 
| jcallahan@167 | 2320                     registry[spell_id] = true | 
| jcallahan@167 | 2321                 end | 
| jcallahan@167 | 2322             end | 
| jcallahan@167 | 2323         end | 
| jcallahan@167 | 2324     end | 
| jcallahan@167 | 2325 | 
| jcallahan@167 | 2326 | 
| jcallahan@92 | 2327     function WDP:TRADE_SKILL_SHOW(event_name) | 
| jcallahan@92 | 2328         local profession_name, prof_level = _G.GetTradeSkillLine() | 
| jcallahan@92 | 2329 | 
| jcallahan@92 | 2330         if profession_name == _G.UNKNOWN then | 
| jcallahan@92 | 2331             return | 
| jcallahan@92 | 2332         end | 
| jcallahan@167 | 2333         TradeSkillExecutePer(RegisterTools) | 
| jcallahan@92 | 2334     end | 
| jcallahan@92 | 2335 end -- do-block | 
| jcallahan@92 | 2336 | 
| jcallahan@92 | 2337 | 
| jcallahan@167 | 2338 function WDP:TRAINER_CLOSED(event_name) | 
| jcallahan@167 | 2339     private.trainer_shown = nil | 
| jcallahan@167 | 2340 end | 
| jcallahan@167 | 2341 | 
| jcallahan@167 | 2342 | 
| jcallahan@92 | 2343 function WDP:TRAINER_SHOW(event_name) | 
| jcallahan@232 | 2344     local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("npc")) | 
| jcallahan@164 | 2345     local trainer = NPCEntry(unit_idnum) | 
| jcallahan@58 | 2346 | 
| jcallahan@164 | 2347     if not trainer then | 
| jcallahan@58 | 2348         return | 
| jcallahan@58 | 2349     end | 
| jcallahan@232 | 2350     local trainer_standing = select(2, UnitFactionStanding("npc")) | 
| jcallahan@164 | 2351     trainer.teaches = trainer.teaches or {} | 
| jcallahan@27 | 2352 | 
| jcallahan@167 | 2353     private.trainer_shown = true | 
| jcallahan@167 | 2354 | 
| jcallahan@27 | 2355     -- Get the initial trainer filters | 
| jcallahan@27 | 2356     local available = _G.GetTrainerServiceTypeFilter("available") | 
| jcallahan@27 | 2357     local unavailable = _G.GetTrainerServiceTypeFilter("unavailable") | 
| jcallahan@27 | 2358     local used = _G.GetTrainerServiceTypeFilter("used") | 
| jcallahan@27 | 2359 | 
| jcallahan@27 | 2360     -- Clear the trainer filters | 
| jcallahan@27 | 2361     _G.SetTrainerServiceTypeFilter("available", 1) | 
| jcallahan@27 | 2362     _G.SetTrainerServiceTypeFilter("unavailable", 1) | 
| jcallahan@27 | 2363     _G.SetTrainerServiceTypeFilter("used", 1) | 
| jcallahan@27 | 2364 | 
| jcallahan@27 | 2365     for index = 1, _G.GetNumTrainerServices(), 1 do | 
| jcallahan@27 | 2366         local spell_name, rank_name, _, _, required_level = _G.GetTrainerServiceInfo(index) | 
| jcallahan@27 | 2367 | 
| jcallahan@27 | 2368         if spell_name then | 
| jcallahan@27 | 2369             DatamineTT:ClearLines() | 
| jcallahan@27 | 2370             DatamineTT:SetTrainerService(index) | 
| jcallahan@27 | 2371 | 
| jcallahan@27 | 2372             local _, _, spell_id = DatamineTT:GetSpell() | 
| jcallahan@27 | 2373 | 
| jcallahan@43 | 2374             if spell_id then | 
| jcallahan@164 | 2375                 local class_professions = trainer.teaches[PLAYER_CLASS] | 
| jcallahan@164 | 2376 | 
| jcallahan@164 | 2377                 if not class_professions then | 
| jcallahan@164 | 2378                     trainer.teaches[PLAYER_CLASS] = {} | 
| jcallahan@164 | 2379                     class_professions = trainer.teaches[PLAYER_CLASS] | 
| jcallahan@164 | 2380                 end | 
| jcallahan@43 | 2381                 local profession, min_skill = _G.GetTrainerServiceSkillReq(index) | 
| jcallahan@43 | 2382                 profession = profession or "General" | 
| jcallahan@43 | 2383 | 
| jcallahan@164 | 2384                 local profession_skills = class_professions[profession] | 
| jcallahan@43 | 2385 | 
| jcallahan@43 | 2386                 if not profession_skills then | 
| jcallahan@43 | 2387                     class_professions[profession] = {} | 
| jcallahan@43 | 2388                     profession_skills = class_professions[profession] | 
| jcallahan@43 | 2389                 end | 
| jcallahan@173 | 2390                 profession_skills[spell_id] = ("%d:%d:%d"):format(required_level, min_skill, _G.GetTrainerServiceCost(index)) | 
| jcallahan@27 | 2391             end | 
| jcallahan@27 | 2392         end | 
| jcallahan@27 | 2393     end | 
| jcallahan@27 | 2394     -- Reset the filters to what they were before | 
| jcallahan@27 | 2395     _G.SetTrainerServiceTypeFilter("available", available or 0) | 
| jcallahan@27 | 2396     _G.SetTrainerServiceTypeFilter("unavailable", unavailable or 0) | 
| jcallahan@27 | 2397     _G.SetTrainerServiceTypeFilter("used", used or 0) | 
| jcallahan@27 | 2398 end | 
| jcallahan@27 | 2399 | 
| jcallahan@27 | 2400 | 
| jcallahan@1 | 2401 function WDP:UNIT_SPELLCAST_SENT(event_name, unit_id, spell_name, spell_rank, target_name, spell_line) | 
| jcallahan@1 | 2402     if private.tracked_line or unit_id ~= "player" then | 
| jcallahan@1 | 2403         return | 
| jcallahan@1 | 2404     end | 
| jcallahan@1 | 2405     local spell_label = private.SPELL_LABELS_BY_NAME[spell_name] | 
| jcallahan@1 | 2406 | 
| jcallahan@1 | 2407     if not spell_label then | 
| jcallahan@1 | 2408         return | 
| jcallahan@1 | 2409     end | 
| jcallahan@306 | 2410 | 
| jcallahan@150 | 2411     local item_name, item_link = _G.GameTooltip:GetItem() | 
| jcallahan@150 | 2412     local unit_name, unit_id = _G.GameTooltip:GetUnit() | 
| jcallahan@1 | 2413 | 
| jcallahan@150 | 2414     if not unit_name and _G.UnitName("target") == target_name then | 
| jcallahan@150 | 2415         unit_name = target_name | 
| jcallahan@150 | 2416         unit_id = "target" | 
| jcallahan@1 | 2417     end | 
| jcallahan@1 | 2418     local spell_flags = private.SPELL_FLAGS_BY_LABEL[spell_label] | 
| jcallahan@28 | 2419     local zone_name, area_id, x, y, map_level, instance_token = CurrentLocationData() | 
| jcallahan@28 | 2420 | 
| jcallahan@205 | 2421     table.wipe(current_action) | 
| jcallahan@122 | 2422     current_action.instance_token = instance_token | 
| jcallahan@122 | 2423     current_action.map_level = map_level | 
| jcallahan@122 | 2424     current_action.x = x | 
| jcallahan@122 | 2425     current_action.y = y | 
| jcallahan@122 | 2426     current_action.zone_data = ("%s:%d"):format(zone_name, area_id) | 
| jcallahan@122 | 2427     current_action.spell_label = spell_label | 
| jcallahan@105 | 2428 | 
| jcallahan@105 | 2429     if not private.NON_LOOT_SPELL_LABELS[spell_label] then | 
| jcallahan@122 | 2430         current_action.loot_label = spell_label:lower() | 
| jcallahan@105 | 2431     end | 
| jcallahan@1 | 2432 | 
| jcallahan@151 | 2433     if unit_name and unit_name == target_name and not item_name then | 
| jcallahan@16 | 2434         if bit.band(spell_flags, AF.NPC) == AF.NPC then | 
| jcallahan@150 | 2435             if not unit_id or unit_name ~= target_name then | 
| jcallahan@16 | 2436                 return | 
| jcallahan@16 | 2437             end | 
| jcallahan@123 | 2438             current_action.target_type = AF.NPC | 
| jcallahan@16 | 2439         end | 
| jcallahan@16 | 2440     elseif bit.band(spell_flags, AF.ITEM) == AF.ITEM then | 
| jcallahan@123 | 2441         current_action.target_type = AF.ITEM | 
| jcallahan@16 | 2442 | 
| jcallahan@150 | 2443         if item_name and item_name == target_name then | 
| jcallahan@150 | 2444             current_action.identifier = ItemLinkToID(item_link) | 
| jcallahan@16 | 2445         elseif target_name and target_name ~= "" then | 
| jcallahan@150 | 2446             current_action.identifier = ItemLinkToID(select(2, _G.GetItemInfo(target_name))) | 
| jcallahan@16 | 2447         end | 
| jcallahan@150 | 2448     elseif not item_name and not unit_name then | 
| jcallahan@1 | 2449         if bit.band(spell_flags, AF.OBJECT) == AF.OBJECT then | 
| jcallahan@17 | 2450             if target_name == "" then | 
| jcallahan@17 | 2451                 return | 
| jcallahan@17 | 2452             end | 
| jcallahan@122 | 2453             current_action.object_name = target_name | 
| jcallahan@123 | 2454             current_action.target_type = AF.OBJECT | 
| jcallahan@1 | 2455         elseif bit.band(spell_flags, AF.ZONE) == AF.ZONE then | 
| jcallahan@123 | 2456             current_action.target_type = AF.ZONE | 
| jcallahan@1 | 2457         end | 
| jcallahan@1 | 2458     end | 
| jcallahan@1 | 2459     private.tracked_line = spell_line | 
| jcallahan@0 | 2460 end | 
| jcallahan@0 | 2461 | 
| jcallahan@94 | 2462 | 
| jcallahan@312 | 2463 function WDP:SPELL_CONFIRMATION_PROMPT(event_name, spell_id, confirm_type, text, duration, currency_id_cost) | 
| jcallahan@306 | 2464     if private.RAID_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP[spell_id] then | 
| jcallahan@306 | 2465         ClearKilledBossID() | 
| jcallahan@306 | 2466         ClearLootToastContainerID() | 
| jcallahan@306 | 2467         private.raid_finder_boss_id = private.RAID_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP[spell_id] | 
| jcallahan@306 | 2468     elseif private.WORLD_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP[spell_id] then | 
| jcallahan@306 | 2469         ClearKilledBossID() | 
| jcallahan@306 | 2470         ClearLootToastContainerID() | 
| jcallahan@306 | 2471         private.world_boss_id = private.WORLD_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP[spell_id] | 
| jcallahan@306 | 2472     else | 
| jcallahan@306 | 2473         Debug("%s: Spell ID %d is not a known raid or world boss 'Bonus' spell.", event_name, spell_id) | 
| jcallahan@306 | 2474         return | 
| jcallahan@1 | 2475     end | 
| jcallahan@306 | 2476 | 
| jcallahan@324 | 2477     -- Assign existing loot data to boss if it exists | 
| jcallahan@307 | 2478     if loot_toast_data then | 
| jcallahan@317 | 2479         local npc_id = private.raid_finder_boss_id or private.world_boss_id | 
| jcallahan@317 | 2480 | 
| jcallahan@324 | 2481         -- Slightly messy hack to workaround duplicate world bosses | 
| jcallahan@317 | 2482         local upper_limit = 0 | 
| jcallahan@317 | 2483         if DUPLICATE_WORLD_BOSS_IDS[npc_id] then | 
| jcallahan@317 | 2484             upper_limit = #DUPLICATE_WORLD_BOSS_IDS[npc_id] | 
| jcallahan@317 | 2485         end | 
| jcallahan@317 | 2486 | 
| jcallahan@317 | 2487         for i = 0, upper_limit do | 
| jcallahan@317 | 2488             local temp_npc_id = npc_id | 
| jcallahan@317 | 2489 | 
| jcallahan@317 | 2490             if i > 0 then | 
| jcallahan@317 | 2491                 temp_npc_id = DUPLICATE_WORLD_BOSS_IDS[npc_id][i] | 
| jcallahan@317 | 2492             end | 
| jcallahan@317 | 2493 | 
| jcallahan@317 | 2494             local npc = NPCEntry(temp_npc_id) | 
| jcallahan@317 | 2495             if npc then | 
| jcallahan@324 | 2496                 -- Create needed npc fields if required | 
| jcallahan@317 | 2497                 local loot_label = "drops" | 
| jcallahan@317 | 2498                 local encounter_data = npc:EncounterData(InstanceDifficultyToken()) | 
| jcallahan@317 | 2499                 encounter_data[loot_label] = encounter_data[loot_label] or {} | 
| jcallahan@317 | 2500                 encounter_data.loot_counts = encounter_data.loot_counts or {} | 
| jcallahan@317 | 2501 | 
| jcallahan@317 | 2502                 for index = 1, #loot_toast_data do | 
| jcallahan@317 | 2503                     local data = loot_toast_data[index] | 
| jcallahan@317 | 2504                     local loot_type = data[1] | 
| jcallahan@317 | 2505                     local hyperlink = data[2] | 
| jcallahan@317 | 2506                     local quantity = data[3] | 
| jcallahan@317 | 2507 | 
| jcallahan@317 | 2508                     if loot_type == "item" then | 
| jcallahan@317 | 2509                         local item_id = ItemLinkToID(hyperlink) | 
| jcallahan@317 | 2510                         Debug("%s: Assigned stored item loot data - %s - %d:%d", event_name, hyperlink, item_id, quantity) | 
| jcallahan@317 | 2511                         table.insert(encounter_data[loot_label], ("%d:%d"):format(item_id, quantity)) | 
| jcallahan@317 | 2512                     elseif loot_type == "money" then | 
| jcallahan@317 | 2513                         Debug("%s: Assigned stored money loot data - money:%d", event_name, quantity) | 
| jcallahan@317 | 2514                         table.insert(encounter_data[loot_label], ("money:%d"):format(quantity)) | 
| jcallahan@317 | 2515                     elseif loot_type == "currency" then | 
| jcallahan@317 | 2516                         local currency_texture = CurrencyLinkToTexture(hyperlink) | 
| jcallahan@317 | 2517                         Debug("%s: Assigned stored currency loot data - %s - currency:%d:%s", event_name, hyperlink, currency_texture, quantity) | 
| jcallahan@324 | 2518                         -- Workaround for Patch 5.4.0 bug with Flexible raid Siege of Orgrimmar bosses and Valor Points | 
| jcallahan@317 | 2519                         if quantity > 1000 and currency_texture == "pvecurrency-valor" then | 
| jcallahan@317 | 2520                             quantity = math.floor(quantity / 100) | 
| jcallahan@317 | 2521                         end | 
| jcallahan@317 | 2522                         table.insert(encounter_data[loot_label], ("currency:%d:%s"):format(quantity, currency_texture)) | 
| jcallahan@317 | 2523                     end | 
| jcallahan@307 | 2524                 end | 
| jcallahan@317 | 2525 | 
| jcallahan@317 | 2526                 if not boss_loot_toasting[temp_npc_id] then | 
| jcallahan@317 | 2527                     encounter_data.loot_counts[loot_label] = (encounter_data.loot_counts[loot_label] or 0) + 1 | 
| jcallahan@317 | 2528                     boss_loot_toasting[temp_npc_id] = true -- Do not count further loots until timer expires or another boss is killed | 
| jcallahan@317 | 2529                 end | 
| jcallahan@317 | 2530             else | 
| jcallahan@317 | 2531                 Debug("%s: NPC is nil, but we have stored loot data...", event_name) | 
| jcallahan@307 | 2532             end | 
| jcallahan@307 | 2533         end | 
| jcallahan@307 | 2534     end | 
| jcallahan@307 | 2535 | 
| jcallahan@307 | 2536     ClearLootToastData() | 
| jcallahan@307 | 2537 | 
| jcallahan@307 | 2538     killed_boss_id_timer_handle = WDP:ScheduleTimer(ClearKilledBossID, 5) -- we need to assign a handle here to cancel it later | 
| jcallahan@306 | 2539 end | 
| jcallahan@306 | 2540 | 
| jcallahan@306 | 2541 | 
| jcallahan@306 | 2542 function WDP:UNIT_SPELLCAST_SUCCEEDED(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id) | 
| jcallahan@306 | 2543     if unit_id ~= "player" then | 
| jcallahan@306 | 2544         return | 
| jcallahan@306 | 2545     end | 
| jcallahan@306 | 2546     private.tracked_line = nil | 
| jcallahan@306 | 2547     private.previous_spell_id = spell_id | 
| jcallahan@306 | 2548 | 
| jcallahan@306 | 2549     if private.LOOT_SPELL_ID_TO_ITEM_ID_MAP[spell_id] then | 
| jcallahan@306 | 2550         ClearKilledBossID() | 
| jcallahan@306 | 2551         ClearLootToastContainerID() | 
| jcallahan@307 | 2552         ClearLootToastData() | 
| jcallahan@306 | 2553 | 
| jcallahan@306 | 2554         private.loot_toast_container_id = private.LOOT_SPELL_ID_TO_ITEM_ID_MAP[spell_id] | 
| jcallahan@306 | 2555         loot_toast_container_timer_handle = WDP:ScheduleTimer(ClearLootToastContainerID, 1) -- we need to assign a handle here to cancel it later | 
| jcallahan@306 | 2556     end | 
| jcallahan@306 | 2557 | 
| jcallahan@306 | 2558     if anvil_spell_ids[spell_id] then | 
| jcallahan@306 | 2559         UpdateDBEntryLocation("objects", OBJECT_ID_ANVIL) | 
| jcallahan@306 | 2560     elseif forge_spell_ids[spell_id] then | 
| jcallahan@306 | 2561         UpdateDBEntryLocation("objects", OBJECT_ID_FORGE) | 
| jcallahan@306 | 2562     elseif spell_name:match("^Harvest.+") then | 
| jcallahan@306 | 2563         killed_npc_id = current_target_id | 
| jcallahan@306 | 2564         private.harvesting = true | 
| jcallahan@306 | 2565     end | 
| jcallahan@306 | 2566 end | 
| jcallahan@0 | 2567 | 
| jcallahan@90 | 2568 | 
| jcallahan@1 | 2569 function WDP:HandleSpellFailure(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id) | 
| jcallahan@1 | 2570     if unit_id ~= "player" then | 
| jcallahan@1 | 2571         return | 
| jcallahan@1 | 2572     end | 
| jcallahan@0 | 2573 | 
| jcallahan@1 | 2574     if private.tracked_line == spell_line then | 
| jcallahan@1 | 2575         private.tracked_line = nil | 
| jcallahan@1 | 2576     end | 
| jcallahan@147 | 2577     table.wipe(current_action) | 
| jcallahan@0 | 2578 end | 
| jcallahan@90 | 2579 | 
| jcallahan@90 | 2580 | 
| jcallahan@90 | 2581 do | 
| jcallahan@90 | 2582     local function SetUnitField(field, required_type) | 
| jcallahan@90 | 2583         local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("npc")) | 
| jcallahan@90 | 2584 | 
| jcallahan@90 | 2585         if not unit_idnum or (required_type and unit_type ~= required_type) then | 
| jcallahan@90 | 2586             return | 
| jcallahan@90 | 2587         end | 
| jcallahan@90 | 2588 | 
| jcallahan@171 | 2589         if UnitTypeIsNPC(unit_type) then | 
| jcallahan@90 | 2590             NPCEntry(unit_idnum)[field] = true | 
| jcallahan@90 | 2591         elseif unit_type == private.UNIT_TYPES.OBJECT then | 
| jcallahan@90 | 2592             DBEntry("objects", unit_idnum)[field] = true | 
| jcallahan@93 | 2593             UpdateDBEntryLocation("objects", unit_idnum) | 
| jcallahan@90 | 2594         end | 
| jcallahan@90 | 2595     end | 
| jcallahan@90 | 2596 | 
| jcallahan@90 | 2597 | 
| jcallahan@90 | 2598     function WDP:AUCTION_HOUSE_SHOW(event_name) | 
| jcallahan@90 | 2599         SetUnitField("auctioneer", private.UNIT_TYPES.NPC) | 
| jcallahan@90 | 2600     end | 
| jcallahan@90 | 2601 | 
| jcallahan@90 | 2602 | 
| jcallahan@90 | 2603     function WDP:BANKFRAME_OPENED(event_name) | 
| jcallahan@90 | 2604         SetUnitField("banker", private.UNIT_TYPES.NPC) | 
| jcallahan@90 | 2605     end | 
| jcallahan@90 | 2606 | 
| jcallahan@90 | 2607 | 
| jcallahan@90 | 2608     function WDP:BATTLEFIELDS_SHOW(event_name) | 
| jcallahan@90 | 2609         SetUnitField("battlemaster", private.UNIT_TYPES.NPC) | 
| jcallahan@90 | 2610     end | 
| jcallahan@90 | 2611 | 
| jcallahan@90 | 2612 | 
| jcallahan@92 | 2613     function WDP:FORGE_MASTER_OPENED(event_name) | 
| jcallahan@90 | 2614         SetUnitField("arcane_reforger", private.UNIT_TYPES.NPC) | 
| jcallahan@90 | 2615     end | 
| jcallahan@90 | 2616 | 
| jcallahan@90 | 2617 | 
| jcallahan@323 | 2618     local GOSSIP_SHOW_FUNCS = { | 
| jcallahan@323 | 2619         [private.UNIT_TYPES.NPC] = function(unit_idnum) | 
| jcallahan@323 | 2620             local gossip_options = { _G.GetGossipOptions() } | 
| jcallahan@323 | 2621 | 
| jcallahan@323 | 2622             for index = 2, #gossip_options, 2 do | 
| jcallahan@323 | 2623                 if gossip_options[index] == "binder" then | 
| jcallahan@323 | 2624                     SetUnitField("innkeeper", private.UNIT_TYPES.NPC) | 
| jcallahan@323 | 2625                     return | 
| jcallahan@323 | 2626                 end | 
| jcallahan@323 | 2627             end | 
| jcallahan@323 | 2628         end, | 
| jcallahan@323 | 2629         [private.UNIT_TYPES.OBJECT] = function(unit_idnum) | 
| jcallahan@323 | 2630             UpdateDBEntryLocation("objects", unit_idnum) | 
| jcallahan@323 | 2631         end, | 
| jcallahan@323 | 2632     } | 
| jcallahan@323 | 2633 | 
| jcallahan@323 | 2634 | 
| jcallahan@92 | 2635     function WDP:GOSSIP_SHOW(event_name) | 
| jcallahan@323 | 2636         local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("npc")) | 
| jcallahan@323 | 2637         if not unit_idnum then | 
| jcallahan@323 | 2638             return | 
| jcallahan@323 | 2639         end | 
| jcallahan@323 | 2640 | 
| jcallahan@323 | 2641         if GOSSIP_SHOW_FUNCS[unit_type] then | 
| jcallahan@323 | 2642             GOSSIP_SHOW_FUNCS[unit_type](unit_idnum) | 
| jcallahan@90 | 2643         end | 
| jcallahan@90 | 2644     end | 
| jcallahan@90 | 2645 | 
| jcallahan@90 | 2646 | 
| jcallahan@93 | 2647     function WDP:GUILDBANKFRAME_OPENED(event_name) | 
| jcallahan@93 | 2648         SetUnitField("guild_bank", private.UNIT_TYPES.OBJECT) | 
| jcallahan@93 | 2649     end | 
| jcallahan@93 | 2650 | 
| jcallahan@93 | 2651 | 
| jcallahan@189 | 2652     function WDP:ITEM_UPGRADE_MASTER_OPENED(event_name) | 
| jcallahan@189 | 2653         SetUnitField("item_upgrade_master", private.UNIT_TYPES.NPC) | 
| jcallahan@189 | 2654     end | 
| jcallahan@189 | 2655 | 
| jcallahan@189 | 2656 | 
| jcallahan@90 | 2657     function WDP:TAXIMAP_OPENED(event_name) | 
| jcallahan@90 | 2658         SetUnitField("flight_master", private.UNIT_TYPES.NPC) | 
| jcallahan@90 | 2659     end | 
| jcallahan@90 | 2660 | 
| jcallahan@90 | 2661 | 
| jcallahan@90 | 2662     function WDP:TRANSMOGRIFY_OPEN(event_name) | 
| jcallahan@90 | 2663         SetUnitField("transmogrifier", private.UNIT_TYPES.NPC) | 
| jcallahan@90 | 2664     end | 
| jcallahan@90 | 2665 | 
| jcallahan@90 | 2666 | 
| jcallahan@90 | 2667     function WDP:VOID_STORAGE_OPEN(event_name) | 
| jcallahan@90 | 2668         SetUnitField("void_storage", private.UNIT_TYPES.NPC) | 
| jcallahan@90 | 2669     end | 
| jcallahan@90 | 2670 end -- do-block |