annotate Main.lua @ 500:26ee8074e5ba

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