comparison Main.lua @ 1:d9375a473042

Handle looting items and money from NPCs. Beginning of handling for looting from objects and gathering (mining, herbalism) from NPCs among other spell-related obtaining methods.
author James D. Callahan III <jcallahan@curse.com>
date Fri, 27 Apr 2012 03:49:03 -0500
parents 2e4d83460542
children d563ea0ec911
comparison
equal deleted inserted replaced
0:2e4d83460542 1:d9375a473042
2 -- Upvalued Lua API. 2 -- Upvalued Lua API.
3 ----------------------------------------------------------------------- 3 -----------------------------------------------------------------------
4 local _G = getfenv(0) 4 local _G = getfenv(0)
5 5
6 local pairs = _G.pairs 6 local pairs = _G.pairs
7 local tonumber = _G.tonumber
8
9 local bit = _G.bit
10 local math = _G.math
11 local table = _G.table
12
7 13
8 ----------------------------------------------------------------------- 14 -----------------------------------------------------------------------
9 -- AddOn namespace. 15 -- AddOn namespace.
10 ----------------------------------------------------------------------- 16 -----------------------------------------------------------------------
11 local ADDON_NAME, private = ... 17 local ADDON_NAME, private = ...
12 18
13 local LibStub = _G.LibStub 19 local LibStub = _G.LibStub
14 local WDP = LibStub("AceAddon-3.0"):NewAddon(ADDON_NAME, "AceEvent-3.0", "AceTimer-3.0") 20 local WDP = LibStub("AceAddon-3.0"):NewAddon(ADDON_NAME, "AceEvent-3.0", "AceTimer-3.0")
15 21
16 -----------------------------------------------------------------------
17 -- Function declarations.
18 -----------------------------------------------------------------------
19 local HandleSpellFailure
20 local HandleZoneChange
21 22
22 ----------------------------------------------------------------------- 23 -----------------------------------------------------------------------
23 -- Local constants. 24 -- Local constants.
24 ----------------------------------------------------------------------- 25 -----------------------------------------------------------------------
25 local DATABASE_DEFAULTS = { 26 local DATABASE_DEFAULTS = {
30 quests = {}, 31 quests = {},
31 } 32 }
32 } 33 }
33 34
34 35
35 local EVENT_MAPPING = {-- ARTIFACT_COMPLETE = true, 36 local EVENT_MAPPING = {
37 -- ARTIFACT_COMPLETE = true,
36 -- ARTIFACT_HISTORY_READY = true, 38 -- ARTIFACT_HISTORY_READY = true,
37 -- AUCTION_HOUSE_SHOW = true, 39 -- AUCTION_HOUSE_SHOW = true,
38 -- BANKFRAME_OPENED = true, 40 -- BANKFRAME_OPENED = true,
39 -- BATTLEFIELDS_SHOW = true, 41 -- BATTLEFIELDS_SHOW = true,
40 -- CHAT_MSG_ADDON = true, 42 -- CHAT_MSG_ADDON = true,
52 -- GOSSIP_ENTER_CODE = true, 54 -- GOSSIP_ENTER_CODE = true,
53 -- GOSSIP_SHOW = true, 55 -- GOSSIP_SHOW = true,
54 -- ITEM_TEXT_BEGIN = true, 56 -- ITEM_TEXT_BEGIN = true,
55 -- LOCALPLAYER_PET_RENAMED = true, 57 -- LOCALPLAYER_PET_RENAMED = true,
56 -- LOOT_CLOSED = true, 58 -- LOOT_CLOSED = true,
57 -- LOOT_OPENED = true, 59 LOOT_OPENED = true,
58 -- MAIL_SHOW = true, 60 -- MAIL_SHOW = true,
59 -- MERCHANT_SHOW = true, 61 -- MERCHANT_SHOW = true,
60 -- MERCHANT_UPDATE = true, 62 -- MERCHANT_UPDATE = true,
61 -- OPEN_TABARD_FRAME = true, 63 -- OPEN_TABARD_FRAME = true,
62 -- PET_BAR_UPDATE = true, 64 -- PET_BAR_UPDATE = true,
73 -- TAXIMAP_OPENED = true, 75 -- TAXIMAP_OPENED = true,
74 -- TRADE_SKILL_SHOW = true, 76 -- TRADE_SKILL_SHOW = true,
75 -- TRADE_SKILL_UPDATE = true, 77 -- TRADE_SKILL_UPDATE = true,
76 -- TRAINER_SHOW = true, 78 -- TRAINER_SHOW = true,
77 -- UNIT_QUEST_LOG_CHANGED = true, 79 -- UNIT_QUEST_LOG_CHANGED = true,
78 -- UNIT_SPELLCAST_FAILED = HandleSpellFailure, 80 UNIT_SPELLCAST_FAILED = "HandleSpellFailure",
79 -- UNIT_SPELLCAST_FAILED_QUIET = HandleSpellFailure, 81 UNIT_SPELLCAST_FAILED_QUIET = "HandleSpellFailure",
80 -- UNIT_SPELLCAST_INTERRUPTED = HandleSpellFailure, 82 UNIT_SPELLCAST_INTERRUPTED = "HandleSpellFailure",
81 -- UNIT_SPELLCAST_SENT = true, 83 UNIT_SPELLCAST_SENT = true,
82 -- UNIT_SPELLCAST_SUCCEEDED = true, 84 UNIT_SPELLCAST_SUCCEEDED = true,
83 -- ZONE_CHANGED = HandleZoneChange, 85 -- ZONE_CHANGED = HandleZoneChange,
84 -- ZONE_CHANGED_NEW_AREA = HandleZoneChange, 86 -- ZONE_CHANGED_NEW_AREA = HandleZoneChange,
85 } 87 }
86 88
89 local AF = private.ACTION_TYPE_FLAGS
87 90
88 ----------------------------------------------------------------------- 91 -----------------------------------------------------------------------
89 -- Local variables. 92 -- Local variables.
90 ----------------------------------------------------------------------- 93 -----------------------------------------------------------------------
91 local db 94 local db
92 local durability_timer_handle 95 local durability_timer_handle
93 96 local action_data = {}
97
98 do
99 local UNIT_TYPE_BITMASK = 0x007
100
101 function WDP:ParseGUID(guid)
102 local types = private.UNIT_TYPES
103 local unit_type = _G.bit.band(tonumber(guid:sub(1, 5)), UNIT_TYPE_BITMASK)
104
105 if unit_type ~= types.PLAYER or unit_type ~= types.OBJECT or unit_type ~= types.PET then
106 return unit_type, tonumber(guid:sub(-12, -9), 16)
107 end
108
109 return unit_type
110 end
111 end -- do-block
112
113
114 -----------------------------------------------------------------------
115 -- Helper Functions.
116 -----------------------------------------------------------------------
117 local function CurrentLocationData()
118 local map_level = _G.GetCurrentMapDungeonLevel() or 0
119 local x, y = _G.GetPlayerMapPosition("player")
120
121 x = x or 0
122 y = y or 0
123
124 if x == 0 and y == 0 then
125 for level_index = 1, _G.GetNumDungeonMapLevels() do
126 _G.SetDungeonMapLevel(level_index)
127 x, y = _G.GetPlayerMapPosition("player")
128
129 if x and y and (x > 0 or y > 0) then
130 _G.SetDungeonMapLevel(map_level)
131 map_level = level_index
132 break
133 end
134 end
135 end
136
137 if _G.DungeonUsesTerrainMap() then
138 map_level = map_level - 1
139 end
140
141 return _G.GetRealZoneText(), math.floor(x * 1000 + 0.5), math.floor(y * 1000 + 0.5), map_level or 0
142 end
143
144
145 local function ItemLinkToID(item_link)
146 if not item_link then
147 return
148 end
149 local id = item_link:match("item:(%d+)")
150 return id and tonumber(id) or nil
151 end
94 152
95 ----------------------------------------------------------------------- 153 -----------------------------------------------------------------------
96 -- Methods. 154 -- Methods.
97 ----------------------------------------------------------------------- 155 -----------------------------------------------------------------------
98 function WDP:OnInitialize() 156 function WDP:OnInitialize()
100 end 158 end
101 159
102 160
103 function WDP:OnEnable() 161 function WDP:OnEnable()
104 for event_name, mapping in pairs(EVENT_MAPPING) do 162 for event_name, mapping in pairs(EVENT_MAPPING) do
105 self:RegisterEvent(event_name, (type(mapping) ~= "boolean") and mapping or nil) 163 self:RegisterEvent(event_name, (_G.type(mapping) ~= "boolean") and mapping or nil)
106 end 164 end
107 durability_timer_handle = self:ScheduleRepeatingTimer("ProcessDurability", 30) 165 durability_timer_handle = self:ScheduleRepeatingTimer("ProcessDurability", 30)
108 end 166 end
109 167
110 168
120 end 178 end
121 179
122 180
123 function WDP:ProcessDurability() 181 function WDP:ProcessDurability()
124 for slot_index = 0, _G.INVSLOT_LAST_EQUIPPED do 182 for slot_index = 0, _G.INVSLOT_LAST_EQUIPPED do
125 local item_id = _G.GetInventoryItemID("player", slot_index); 183 local item_id = _G.GetInventoryItemID("player", slot_index)
126 184
127 if item_id and item_id > 0 then 185 if item_id and item_id > 0 then
128 local _, max_durability = _G.GetInventoryItemDurability(slot_index); 186 local _, max_durability = _G.GetInventoryItemDurability(slot_index)
129 RecordDurability(item_id, max_durability) 187 RecordDurability(item_id, max_durability)
130 end 188 end
131 end 189 end
132 190
133 for bag_index = 0, _G.NUM_BAG_SLOTS do 191 for bag_index = 0, _G.NUM_BAG_SLOTS do
134 for slot_index = 1, _G.GetContainerNumSlots(bag_index) do 192 for slot_index = 1, _G.GetContainerNumSlots(bag_index) do
135 local item_id = _G.GetContainerItemID(bag_index, slot_index); 193 local item_id = _G.GetContainerItemID(bag_index, slot_index)
136 194
137 if item_id and item_id > 0 then 195 if item_id and item_id > 0 then
138 local _, max_durability = _G.GetContainerItemDurability(bag_index, slot_index); 196 local _, max_durability = _G.GetContainerItemDurability(bag_index, slot_index)
139 RecordDurability(item_id, max_durability) 197 RecordDurability(item_id, max_durability)
140 end 198 end
141 end 199 end
142 end 200 end
143 end 201 end
144 202
145 203
146 ----------------------------------------------------------------------- 204 -----------------------------------------------------------------------
147 -- Event handlers. 205 -- Event handlers.
148 ----------------------------------------------------------------------- 206 -----------------------------------------------------------------------
149 function WDP:AUCTION_HOUSE_SHOW() 207 function WDP:CHAT_MSG_SYSTEM(event_name, message, sender_name, language)
150 end 208 end
151 209
152 210
153 function WDP:CHAT_MSG_MONSTER_EMOTE() 211 local re_gold = _G.GOLD_AMOUNT:gsub("%%d", "(%%d+)")
154 end 212 local re_silver = _G.SILVER_AMOUNT:gsub("%%d", "(%%d+)")
155 213 local re_copper = _G.COPPER_AMOUNT:gsub("%%d", "(%%d+)")
156 214
157 function WDP:CHAT_MSG_MONSTER_SAY() 215
158 end 216 local function _moneyMatch(money, re)
159 217 return money:match(re) or 0
160 218 end
161 function WDP:CHAT_MSG_MONSTER_WHISPER() 219
162 end 220
163 221 local function _toCopper(money)
164 222 if not money then
165 function WDP:CHAT_MSG_MONSTER_YELL() 223 return 0
166 end 224 end
167 225
168 226 return _moneyMatch(money, re_gold) * 10000 + _moneyMatch(money, re_silver) * 100 + _moneyMatch(money, re_copper)
169 function WDP:CHAT_MSG_SYSTEM(event, message, sender_name, language) 227 end
170 end 228
171 229
172 230 local LOOT_VERIFY_FUNCS = {
173 function WDP:GOSSIP_SHOW() 231 [AF.NPC] = function()
174 end 232 local fishing_loot = _G.IsFishingLoot()
175 233
176 234 if not fishing_loot and _G.UnitExists("target") and not _G.UnitIsFriend("player", "target") and _G.UnitIsDead("target") then
177 function WDP:ADDON_ALIVE() 235 if _G.UnitIsPlayer("target") or _G.UnitPlayerControlled("target") then
178 end 236 return false
179 237 end
180 238 local unit_type, id_num = WDP:ParseGUID(_G.UnitGUID("target"))
181 function WDP:PLAYER_LOGIN() 239 action_data.id_num = id_num
182 end 240 end
183 241 return true
184 242 end,
185 function WDP:PLAYER_LOGOUT() 243 }
186 end 244
187 245 local LOOT_UPDATE_FUNCS = {
188 246 [AF.NPC] = function()
189 function WDP:PLAYER_TARGET_CHANGED() 247 local npc = db.npcs[action_data.id_num]
190 end 248
191 249 if not npc then
192 250 db.npcs[action_data.id_num] = {}
193 function WDP:QUEST_LOG_UPDATE() 251 npc = db.npcs[action_data.id_num]
194 end 252 end
195 253 npc.drops = npc.drops or {}
196 254
197 function WDP:TRADE_SKILL_UPDATE() 255 for index = 1, #action_data.drops do
198 end 256 table.insert(npc.drops, action_data.drops[index])
257 end
258 end,
259 }
260
261
262 function WDP:LOOT_OPENED()
263 if not action_data.type then
264 action_data.type = AF.NPC
265 end
266 local verify_func = LOOT_VERIFY_FUNCS[action_data.type]
267 local update_func = LOOT_UPDATE_FUNCS[action_data.type]
268
269 if not verify_func or not update_func or not verify_func() then
270 return
271 end
272
273 local loot_registry = {}
274 action_data.drops = {}
275
276 for loot_slot = 1, _G.GetNumLootItems() do
277 local texture, item, quantity, quality, locked = _G.GetLootSlotInfo(loot_slot)
278
279 if _G.LootSlotIsItem(loot_slot) then
280 local item_id = ItemLinkToID(_G.GetLootSlotLink(loot_slot))
281 loot_registry[item_id] = (loot_registry[item_id]) or 0 + quantity
282 elseif _G.LootSlotIsCoin(loot_slot) then
283 table.insert(action_data.drops, ("money:%d"):format(_toCopper(item)))
284 elseif _G.LootSlotIsCurrency(loot_slot) then
285 end
286 end
287
288 for item_id, quantity in pairs(loot_registry) do
289 table.insert(action_data.drops, ("%d:%d"):format(item_id, quantity))
290 end
291 update_func()
292 end
293
294
295 function WDP:UNIT_SPELLCAST_SENT(event_name, unit_id, spell_name, spell_rank, target_name, spell_line)
296 if private.tracked_line or unit_id ~= "player" then
297 return
298 end
299 local spell_label = private.SPELL_LABELS_BY_NAME[spell_name]
300
301 if not spell_label then
302 return
303 end
304 action_data.type = nil -- This will be set as appropriate below
305
306 local tt_item_name, tt_item_link = _G.GameTooltip:GetItem()
307 local tt_unit_name, tt_unit_id = _G.GameTooltip:GetUnit()
308
309 if not tt_unit_name and _G.UnitName("target") == target_name then
310 tt_unit_name = target_name
311 tt_unit_id = "target"
312 end
313 local spell_flags = private.SPELL_FLAGS_BY_LABEL[spell_label]
314
315 if not tt_item_name and not tt_unit_name then
316 if target_name == "" then
317 return
318 end
319
320 local zone_name, x, y, map_level = CurrentLocationData()
321
322 if bit.band(spell_flags, AF.OBJECT) == AF.OBJECT then
323 action_data.map_level = map_level
324 action_data.name = target_name
325 action_data.type = AF.OBJECT
326 action_data.x = x
327 action_data.y = y
328 action_data.zone = zone_name
329 print("Found spell flagged for OBJECT")
330 elseif bit.band(spell_flags, AF.ZONE) == AF.ZONE then
331 print("Found spell flagged for ZONE")
332 end
333 elseif tt_unit_name and not tt_item_name then
334 if bit.band(spell_flags, AF.NPC) == AF.NPC then
335 print("Found spell flagged for NPC")
336 end
337 elseif bit.band(spell_flags, AF.ITEM) == AF.ITEM then
338 print("Found spell flagged for ITEM")
339 else
340 print(("%s: We have an issue with types and flags."), event_name)
341 end
342
343 print(("%s: '%s', '%s', '%s', '%s', '%s'"):format(event_name, unit_id, spell_name, spell_rank, target_name, spell_line))
344 private.tracked_line = spell_line
345 end
346
347
348 function WDP:UNIT_SPELLCAST_SUCCEEDED(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id)
349 if unit_id ~= "player" then
350 return
351 end
352
353 if action_data.type == AF.OBJECT then
354 end
355
356 if private.SPELL_LABELS_BY_NAME[spell_name] then
357 print(("%s: '%s', '%s', '%s', '%s', '%s'"):format(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id))
358 end
359 private.tracked_line = nil
360 end
361
362 function WDP:HandleSpellFailure(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id)
363 if unit_id ~= "player" then
364 return
365 end
366
367 if private.tracked_line == spell_line then
368 private.tracked_line = nil
369 end
370 end