annotate Main.lua @ 558:d423605eccf0

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