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