# HG changeset patch # User James D. Callahan III # Date 1335516543 18000 # Node ID d9375a4730423a78175c6ddfab14bd82a52b38f9 # Parent 2e4d83460542fe21d99ed29983c02c85ed93bcd8 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. diff -r 2e4d83460542 -r d9375a473042 Constants.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Constants.lua Fri Apr 27 03:49:03 2012 -0500 @@ -0,0 +1,67 @@ +----------------------------------------------------------------------- +-- Upvalued Lua API. +----------------------------------------------------------------------- +local _G = getfenv(0) + +local bit = _G.bit + + +----------------------------------------------------------------------- +-- AddOn namespace. +----------------------------------------------------------------------- +local ADDON_NAME, private = ... + +local LibStub = _G.LibStub + + +----------------------------------------------------------------------- +-- Constants. +----------------------------------------------------------------------- +private.UNIT_TYPES = { + PLAYER = 0, + OBJECT = 1, + NPC = 3, + PET = 4, + VEHICLE = 5, +} + + +private.ACTION_TYPE_FLAGS = { + ITEM = 0x00000001, + NPC = 0x00000002, + OBJECT = 0x00000004, + ZONE = 0x00000008, +} + + +private.SPELL_LABELS_BY_NAME = { + [_G.GetSpellInfo(13262)] = "DISENCHANT", + [_G.GetSpellInfo(4036)] = "ENGINEERING", + [_G.GetSpellInfo(7620)] = "FISHING", + [_G.GetSpellInfo(2366)] = "HERB_GATHERING", + [_G.GetSpellInfo(51005)] = "MILLING", + [_G.GetSpellInfo(605)] = "MIND_CONTROL", + [_G.GetSpellInfo(2575)] = "MINING", + [_G.GetSpellInfo(3365)] = "OPENING", + [_G.GetSpellInfo(921)] = "PICK_POCKET", + [_G.GetSpellInfo(31252)] = "PROSPECTING", + [_G.GetSpellInfo(73979)] = "SEARCHING_FOR_ARTIFACTS", + [_G.GetSpellInfo(8613)] = "SKINNING", +} + +local AF = private.ACTION_TYPE_FLAGS + +private.SPELL_FLAGS_BY_LABEL = { + DISENCHANT = AF.ITEM, + ENGINEERING = AF.NPC, + FISHING = AF.ZONE, + HERB_GATHERING = bit.bxor(AF.NPC, AF.OBJECT), + MILLING = AF.ITEM, + MIND_CONTROL = AF.NPC, + MINING = bit.bxor(AF.NPC, AF.OBJECT), + OPENING = AF.OBJECT, + PICK_POCKET = AF.NPC, + PROSPECTING = AF.ITEM, + SEARCHING_FOR_ARTIFACTS = AF.OBJECT, + SKINNING = AF.NPC, +} diff -r 2e4d83460542 -r d9375a473042 Main.lua --- a/Main.lua Thu Apr 26 13:03:54 2012 -0500 +++ b/Main.lua Fri Apr 27 03:49:03 2012 -0500 @@ -4,6 +4,12 @@ local _G = getfenv(0) local pairs = _G.pairs +local tonumber = _G.tonumber + +local bit = _G.bit +local math = _G.math +local table = _G.table + ----------------------------------------------------------------------- -- AddOn namespace. @@ -13,11 +19,6 @@ local LibStub = _G.LibStub local WDP = LibStub("AceAddon-3.0"):NewAddon(ADDON_NAME, "AceEvent-3.0", "AceTimer-3.0") ------------------------------------------------------------------------ --- Function declarations. ------------------------------------------------------------------------ -local HandleSpellFailure -local HandleZoneChange ----------------------------------------------------------------------- -- Local constants. @@ -32,7 +33,8 @@ } -local EVENT_MAPPING = {-- ARTIFACT_COMPLETE = true, +local EVENT_MAPPING = { + -- ARTIFACT_COMPLETE = true, -- ARTIFACT_HISTORY_READY = true, -- AUCTION_HOUSE_SHOW = true, -- BANKFRAME_OPENED = true, @@ -54,7 +56,7 @@ -- ITEM_TEXT_BEGIN = true, -- LOCALPLAYER_PET_RENAMED = true, -- LOOT_CLOSED = true, - -- LOOT_OPENED = true, + LOOT_OPENED = true, -- MAIL_SHOW = true, -- MERCHANT_SHOW = true, -- MERCHANT_UPDATE = true, @@ -75,22 +77,78 @@ -- TRADE_SKILL_UPDATE = true, -- TRAINER_SHOW = true, -- UNIT_QUEST_LOG_CHANGED = true, - -- UNIT_SPELLCAST_FAILED = HandleSpellFailure, - -- UNIT_SPELLCAST_FAILED_QUIET = HandleSpellFailure, - -- UNIT_SPELLCAST_INTERRUPTED = HandleSpellFailure, - -- UNIT_SPELLCAST_SENT = true, - -- UNIT_SPELLCAST_SUCCEEDED = true, + UNIT_SPELLCAST_FAILED = "HandleSpellFailure", + UNIT_SPELLCAST_FAILED_QUIET = "HandleSpellFailure", + UNIT_SPELLCAST_INTERRUPTED = "HandleSpellFailure", + UNIT_SPELLCAST_SENT = true, + UNIT_SPELLCAST_SUCCEEDED = true, -- ZONE_CHANGED = HandleZoneChange, -- ZONE_CHANGED_NEW_AREA = HandleZoneChange, } +local AF = private.ACTION_TYPE_FLAGS ----------------------------------------------------------------------- -- Local variables. ----------------------------------------------------------------------- local db local durability_timer_handle +local action_data = {} +do + local UNIT_TYPE_BITMASK = 0x007 + + function WDP:ParseGUID(guid) + local types = private.UNIT_TYPES + local unit_type = _G.bit.band(tonumber(guid:sub(1, 5)), UNIT_TYPE_BITMASK) + + if unit_type ~= types.PLAYER or unit_type ~= types.OBJECT or unit_type ~= types.PET then + return unit_type, tonumber(guid:sub(-12, -9), 16) + end + + return unit_type + end +end -- do-block + + +----------------------------------------------------------------------- +-- Helper Functions. +----------------------------------------------------------------------- +local function CurrentLocationData() + local map_level = _G.GetCurrentMapDungeonLevel() or 0 + local x, y = _G.GetPlayerMapPosition("player") + + x = x or 0 + y = y or 0 + + if x == 0 and y == 0 then + for level_index = 1, _G.GetNumDungeonMapLevels() do + _G.SetDungeonMapLevel(level_index) + x, y = _G.GetPlayerMapPosition("player") + + if x and y and (x > 0 or y > 0) then + _G.SetDungeonMapLevel(map_level) + map_level = level_index + break + end + end + end + + if _G.DungeonUsesTerrainMap() then + map_level = map_level - 1 + end + + return _G.GetRealZoneText(), math.floor(x * 1000 + 0.5), math.floor(y * 1000 + 0.5), map_level or 0 +end + + +local function ItemLinkToID(item_link) + if not item_link then + return + end + local id = item_link:match("item:(%d+)") + return id and tonumber(id) or nil +end ----------------------------------------------------------------------- -- Methods. @@ -102,7 +160,7 @@ function WDP:OnEnable() for event_name, mapping in pairs(EVENT_MAPPING) do - self:RegisterEvent(event_name, (type(mapping) ~= "boolean") and mapping or nil) + self:RegisterEvent(event_name, (_G.type(mapping) ~= "boolean") and mapping or nil) end durability_timer_handle = self:ScheduleRepeatingTimer("ProcessDurability", 30) end @@ -122,20 +180,20 @@ function WDP:ProcessDurability() for slot_index = 0, _G.INVSLOT_LAST_EQUIPPED do - local item_id = _G.GetInventoryItemID("player", slot_index); + local item_id = _G.GetInventoryItemID("player", slot_index) if item_id and item_id > 0 then - local _, max_durability = _G.GetInventoryItemDurability(slot_index); + local _, max_durability = _G.GetInventoryItemDurability(slot_index) RecordDurability(item_id, max_durability) end end for bag_index = 0, _G.NUM_BAG_SLOTS do for slot_index = 1, _G.GetContainerNumSlots(bag_index) do - local item_id = _G.GetContainerItemID(bag_index, slot_index); + local item_id = _G.GetContainerItemID(bag_index, slot_index) if item_id and item_id > 0 then - local _, max_durability = _G.GetContainerItemDurability(bag_index, slot_index); + local _, max_durability = _G.GetContainerItemDurability(bag_index, slot_index) RecordDurability(item_id, max_durability) end end @@ -146,53 +204,167 @@ ----------------------------------------------------------------------- -- Event handlers. ----------------------------------------------------------------------- -function WDP:AUCTION_HOUSE_SHOW() +function WDP:CHAT_MSG_SYSTEM(event_name, message, sender_name, language) end -function WDP:CHAT_MSG_MONSTER_EMOTE() +local re_gold = _G.GOLD_AMOUNT:gsub("%%d", "(%%d+)") +local re_silver = _G.SILVER_AMOUNT:gsub("%%d", "(%%d+)") +local re_copper = _G.COPPER_AMOUNT:gsub("%%d", "(%%d+)") + + +local function _moneyMatch(money, re) + return money:match(re) or 0 end -function WDP:CHAT_MSG_MONSTER_SAY() +local function _toCopper(money) + if not money then + return 0 + end + + return _moneyMatch(money, re_gold) * 10000 + _moneyMatch(money, re_silver) * 100 + _moneyMatch(money, re_copper) end -function WDP:CHAT_MSG_MONSTER_WHISPER() +local LOOT_VERIFY_FUNCS = { + [AF.NPC] = function() + local fishing_loot = _G.IsFishingLoot() + + if not fishing_loot and _G.UnitExists("target") and not _G.UnitIsFriend("player", "target") and _G.UnitIsDead("target") then + if _G.UnitIsPlayer("target") or _G.UnitPlayerControlled("target") then + return false + end + local unit_type, id_num = WDP:ParseGUID(_G.UnitGUID("target")) + action_data.id_num = id_num + end + return true + end, +} + +local LOOT_UPDATE_FUNCS = { + [AF.NPC] = function() + local npc = db.npcs[action_data.id_num] + + if not npc then + db.npcs[action_data.id_num] = {} + npc = db.npcs[action_data.id_num] + end + npc.drops = npc.drops or {} + + for index = 1, #action_data.drops do + table.insert(npc.drops, action_data.drops[index]) + end + end, +} + + +function WDP:LOOT_OPENED() + if not action_data.type then + action_data.type = AF.NPC + end + local verify_func = LOOT_VERIFY_FUNCS[action_data.type] + local update_func = LOOT_UPDATE_FUNCS[action_data.type] + + if not verify_func or not update_func or not verify_func() then + return + end + + local loot_registry = {} + action_data.drops = {} + + for loot_slot = 1, _G.GetNumLootItems() do + local texture, item, quantity, quality, locked = _G.GetLootSlotInfo(loot_slot) + + if _G.LootSlotIsItem(loot_slot) then + local item_id = ItemLinkToID(_G.GetLootSlotLink(loot_slot)) + loot_registry[item_id] = (loot_registry[item_id]) or 0 + quantity + elseif _G.LootSlotIsCoin(loot_slot) then + table.insert(action_data.drops, ("money:%d"):format(_toCopper(item))) + elseif _G.LootSlotIsCurrency(loot_slot) then + end + end + + for item_id, quantity in pairs(loot_registry) do + table.insert(action_data.drops, ("%d:%d"):format(item_id, quantity)) + end + update_func() end -function WDP:CHAT_MSG_MONSTER_YELL() +function WDP:UNIT_SPELLCAST_SENT(event_name, unit_id, spell_name, spell_rank, target_name, spell_line) + if private.tracked_line or unit_id ~= "player" then + return + end + local spell_label = private.SPELL_LABELS_BY_NAME[spell_name] + + if not spell_label then + return + end + action_data.type = nil -- This will be set as appropriate below + + local tt_item_name, tt_item_link = _G.GameTooltip:GetItem() + local tt_unit_name, tt_unit_id = _G.GameTooltip:GetUnit() + + if not tt_unit_name and _G.UnitName("target") == target_name then + tt_unit_name = target_name + tt_unit_id = "target" + end + local spell_flags = private.SPELL_FLAGS_BY_LABEL[spell_label] + + if not tt_item_name and not tt_unit_name then + if target_name == "" then + return + end + + local zone_name, x, y, map_level = CurrentLocationData() + + if bit.band(spell_flags, AF.OBJECT) == AF.OBJECT then + action_data.map_level = map_level + action_data.name = target_name + action_data.type = AF.OBJECT + action_data.x = x + action_data.y = y + action_data.zone = zone_name + print("Found spell flagged for OBJECT") + elseif bit.band(spell_flags, AF.ZONE) == AF.ZONE then + print("Found spell flagged for ZONE") + end + elseif tt_unit_name and not tt_item_name then + if bit.band(spell_flags, AF.NPC) == AF.NPC then + print("Found spell flagged for NPC") + end + elseif bit.band(spell_flags, AF.ITEM) == AF.ITEM then + print("Found spell flagged for ITEM") + else + print(("%s: We have an issue with types and flags."), event_name) + end + + print(("%s: '%s', '%s', '%s', '%s', '%s'"):format(event_name, unit_id, spell_name, spell_rank, target_name, spell_line)) + private.tracked_line = spell_line end -function WDP:CHAT_MSG_SYSTEM(event, message, sender_name, language) +function WDP:UNIT_SPELLCAST_SUCCEEDED(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id) + if unit_id ~= "player" then + return + end + + if action_data.type == AF.OBJECT then + end + + if private.SPELL_LABELS_BY_NAME[spell_name] then + print(("%s: '%s', '%s', '%s', '%s', '%s'"):format(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id)) + end + private.tracked_line = nil end +function WDP:HandleSpellFailure(event_name, unit_id, spell_name, spell_rank, spell_line, spell_id) + if unit_id ~= "player" then + return + end -function WDP:GOSSIP_SHOW() + if private.tracked_line == spell_line then + private.tracked_line = nil + end end - - -function WDP:ADDON_ALIVE() -end - - -function WDP:PLAYER_LOGIN() -end - - -function WDP:PLAYER_LOGOUT() -end - - -function WDP:PLAYER_TARGET_CHANGED() -end - - -function WDP:QUEST_LOG_UPDATE() -end - - -function WDP:TRADE_SKILL_UPDATE() -end diff -r 2e4d83460542 -r d9375a473042 WoWDBProfiler.toc --- a/WoWDBProfiler.toc Thu Apr 26 13:03:54 2012 -0500 +++ b/WoWDBProfiler.toc Fri Apr 27 03:49:03 2012 -0500 @@ -8,4 +8,5 @@ libs.xml +Constants.lua Main.lua