annotate Main.lua @ 584:be7931f9225c tip

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