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