annotate Main.lua @ 495:1d1bbcad6563

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