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