annotate Main.lua @ 487:b661f10e04d9

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