Mercurial > wow > wowdb-profiler
changeset 358:703714202ffe 6.0.2-1
Merge with WoD
author | MMOSimca <MMOSimca@gmail.com> |
---|---|
date | Tue, 14 Oct 2014 00:36:05 -0400 |
parents | 3487529df8e5 (current diff) f8190e012c92 (diff) |
children | e35c15f27249 |
files | |
diffstat | 4 files changed, 728 insertions(+), 440 deletions(-) [+] |
line wrap: on
line diff
--- a/Comments.lua Wed Aug 06 04:31:49 2014 -0400 +++ b/Comments.lua Tue Oct 14 00:36:05 2014 -0400 @@ -115,7 +115,7 @@ WDP:Printf("Unable to determine unit from '%s'", unit_id) return end - local type_name = private.UNIT_TYPE_NAMES[unit_type + 1] + local type_name = private.UNIT_TYPE_NAMES[unit_type] local unit_name = is_command and _G.UnitName(unit_id) or comment_units[unit_id].name table.wipe(comment_units) @@ -198,21 +198,21 @@ local function CreateQuestComment() local index = _G.GetQuestLogSelection() - if not index or not _G.QuestLogFrame:IsShown() then - WDP:Print("You must select a quest from the Quest frame.") + if not index or not _G.QuestMapFrame:IsVisible() then + WDP:Print("You must select a quest from the World Map's Quest frame.") return end local title, _, tag, _, is_header, _, _, _, idnum = _G.GetQuestLogTitle(index) if is_header then - WDP:Print("You must select a quest from the Quest frame.") + WDP:Print("You must select a quest from the World Map's Quest frame.") return end NewComment("QUEST", title, idnum) end local function CreateAchievementComment() - if not _G.AchievementFrame or not _G.AchievementFrame:IsShown() or not _G.AchievementFrameAchievements.selection then + if not _G.AchievementFrame or not _G.AchievementFrame:IsVisible() or not _G.AchievementFrameAchievements.selection then WDP:Print("You must select an achievement from the Achievement frame.") return end @@ -319,7 +319,7 @@ end end - if _G.AchievementFrame and _G.AchievementFrame:IsShown() and _G.AchievementFrameAchievements.selection then + if _G.AchievementFrame and _G.AchievementFrame:IsVisible() and _G.AchievementFrameAchievements.selection then for _, button in next, _G.AchievementFrameAchievementsContainer.buttons do if button.selected then line = display:AddLine(("Achievement: %s"):format(button.label:GetText())) @@ -362,7 +362,7 @@ local quest_index = _G.GetQuestLogSelection() - if quest_index and _G.QuestLogFrame:IsShown() then + if quest_index and _G.QuestMapFrame:IsVisible() and not _G.QuestScrollFrame:IsVisible() then local title, _, tag, _, is_header, _, _, _, idnum = _G.GetQuestLogTitle(quest_index) if not is_header then
--- a/Constants.lua Wed Aug 06 04:31:49 2014 -0400 +++ b/Constants.lua Tue Oct 14 00:36:05 2014 -0400 @@ -13,104 +13,37 @@ ----------------------------------------------------------------------- --- Constants. +-- Game Data Constants. ----------------------------------------------------------------------- -private.wow_version, private.build_num = _G.GetBuildInfo() +-- Map of Alliance Logging NPC Summon spells to all possible Timber objectIDs of the proper tree size +private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP = { + [167902] = 234021, --{ 233604, 233922, , 234080, 234097, 234109, 234110, 234122, 234126, 234193, 234197, 237727, }, + [167969] = 234022, --{ 233634, 234000, , 234098, 234111, 234119, 234123, 234127, 234194, 234196, 234198, }, + [168201] = 234023, --{ 233625, 234007, , 234099, 234120, 234124, 234128, 234195, 234199, }, +} +-- Account for Horde spell IDs +private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[167961] = private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[167902] +private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[168043] = private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[167969] +private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[168200] = private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[168201] -private.UNIT_TYPES = { - PLAYER = 0, - OBJECT = 1, - UNKNOWN = 2, - NPC = 3, - PET = 4, - VEHICLE = 5, +-- Map of Salvage spells to item IDs of the Salvage containers (no longer loot toasts) +private.SALVAGE_SPELL_ID_TO_ITEM_ID_MAP = { + [168178] = 114116, -- Bag of Salvaged Goods + [168179] = 114119, -- Crate of Salvage + [168180] = 114120, -- Big Crate of Salvage } - -private.UNIT_TYPE_NAMES = { - "PLAYER", - "OBJECT", - "UNKNOWN", - "NPC", - "PET", - "VEHICLE", +-- Map of Garrison Cache object names to Garrison Cache object IDs +private.GARRISON_CACHE_OBJECT_NAME_TO_OBJECT_ID_MAP = { + ["Garrison Cache"] = 236916, + ["Full Garrison Cache"] = 237722, + ["Hefty Garrison Cache"] = 237723, } - - -private.ACTION_TYPE_FLAGS = { - ITEM = 0x00000001, - NPC = 0x00000002, - OBJECT = 0x00000004, - ZONE = 0x00000008, -} - - -private.ACTION_TYPE_NAMES = {} - -for name, bit in _G.pairs(private.ACTION_TYPE_FLAGS) do - private.ACTION_TYPE_NAMES[bit] = name -end - - -private.EXTRAPOLATION_BANNED_SPELL_IDS = { - [13262] = "DISENCHANT", - [4036] = "ENGINEERING", - [30427] = "EXTRACT_GAS", - [131476] = "FISHING", - [2366] = "HERB_GATHERING", - [51005] = "MILLING", - [605] = "MIND_CONTROL", - [2575] = "MINING", - [921] = "PICK_POCKET", - [31252] = "PROSPECTING", - [73979] = "SEARCHING_FOR_ARTIFACTS", - [8613] = "SKINNING", -} - - -private.SPELL_LABELS_BY_NAME = { - [_G.GetSpellInfo(13262)] = "DISENCHANT", - [_G.GetSpellInfo(4036)] = "ENGINEERING", - [_G.GetSpellInfo(30427)] = "EXTRACT_GAS", - [_G.GetSpellInfo(131476)] = "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", -} - - -private.NON_LOOT_SPELL_LABELS = { - MIND_CONTROL = true, -} - - -local AF = private.ACTION_TYPE_FLAGS - -private.SPELL_FLAGS_BY_LABEL = { - DISENCHANT = AF.ITEM, - ENGINEERING = AF.NPC, - EXTRACT_GAS = AF.ZONE, - FISHING = AF.ZONE, - HERB_GATHERING = bit.bor(AF.NPC, AF.OBJECT), - MILLING = AF.ITEM, - MIND_CONTROL = AF.NPC, - MINING = bit.bor(AF.NPC, AF.OBJECT), - OPENING = AF.OBJECT, - PICK_POCKET = AF.NPC, - PROSPECTING = AF.ITEM, - SEARCHING_FOR_ARTIFACTS = AF.OBJECT, - SKINNING = AF.NPC, -} - +private.GARRISON_CACHE_LOOT_SOURCE_ID = 10 private.LOOT_SPELL_ID_TO_ITEM_ID_MAP = { [142397] = 98134, -- Heroic Cache of Treasures + [142901] = 98546, -- Bulging Heroic Cache of Treasures [143506] = 98095, -- Brawler's Pet Supplies [143507] = 94207, -- Fabled Pandaren Pet Supplies [143508] = 89125, -- Sack of Pet Supplies @@ -122,115 +55,243 @@ [147598] = 104014, -- Pouch of Timeless Coins [149222] = 105911, -- Pouch of Enduring Wisdom [149223] = 105912, -- Oversized Pouch of Enduring Wisdom + --[168178] = 114116, -- Bag of Salvaged Goods + --[168179] = 114119, -- Crate of Salvage + --[168180] = 114120, -- Big Crate of Salvage + [171513] = 116414, -- Pet Supplies + [175767] = 118697, -- Big Bag of Pet Supplies + [178508] = 120321, -- Mystery Bag } - -private.RAID_FINDER_BOSS_IDS = { - ----------------------------------------------------------------------- - -- Mogu'shan Vaults - ----------------------------------------------------------------------- - [59915] = true, -- Jasper Guardian - [60009] = true, -- Feng the Accursed - [60043] = true, -- Jade Guardian - [60047] = true, -- Amethyst Guardian - [60051] = true, -- Cobalt Guardian - [60143] = true, -- Gara'jal the Spiritbinder - [60399] = true, -- Qin-xi - [60400] = true, -- Jan-xi - [60410] = true, -- Elegon - [60701] = true, -- Zian of the Endless Shadow - [60708] = true, -- Meng the Demented - [60709] = true, -- Qiang the Merciless - [60710] = true, -- Subetai the Swift - - ----------------------------------------------------------------------- - -- Terrace of Endless Spring - ----------------------------------------------------------------------- - [60583] = true, -- Protector Kaolan - [60585] = true, -- Elder Regail - [60586] = true, -- Elder Asani - [60999] = true, -- Sha of Fear - [62442] = true, -- Tsulong - [62983] = true, -- Lei Shi - - ----------------------------------------------------------------------- - -- Heart of Fear - ----------------------------------------------------------------------- - [62164] = true, -- Garalon - [62397] = true, -- Wind Lord Mel'jarak - [62511] = true, -- Amber-Shaper Un'sok - [62543] = true, -- Blade Lord Ta'yak - [62837] = true, -- Grand Empress Shek'zeer - [62980] = true, -- Imperial Vizier Zor'lok - - ----------------------------------------------------------------------- - -- Throne of Thunder - ----------------------------------------------------------------------- - [69465] = true, -- Jin'rokh the Breaker - [68476] = true, -- Horridon - [69078] = true, -- Sul the Sandcrawler - [69131] = true, -- Frost King Malakk - [69132] = true, -- High Priestess Mar'li - [69134] = true, -- Kazra'jin - [67977] = true, -- Tortos - [70212] = true, -- Flaming Head (of Megaera) - [70235] = true, -- Frozen Head (of Megaera) - [70247] = true, -- Venomous Head (of Megaera) - [69712] = true, -- Ji-kun - [68036] = true, -- Durumu - [69017] = true, -- Primordius - [69427] = true, -- Dark Animus - [68078] = true, -- Iron Qon - [68904] = true, -- Suen - [68905] = true, -- Lu'lin - [68397] = true, -- Lei Shen - - ----------------------------------------------------------------------- - -- Siege of Orgrimmar - ----------------------------------------------------------------------- - [71543] = true, -- Immerseus - [71475] = true, -- Rook Stonetoe (Fallen Protectors encounter) - [71479] = true, -- He Softfoot (Fallen Protectors encounter) - [71480] = true, -- Sun Tenderheart (Fallen Protectors encounter) - [71967] = true, -- Norushen (Norushen encounter) - [72276] = true, -- Amalgam of Corruption (Norushen encounter) - [71734] = true, -- Sha of Pride - [72249] = true, -- Galakras - [71466] = true, -- Iron Juggernaut - [71858] = true, -- Wavebinder Kardris (Kor'kron Dark Shaman encounter) - [71859] = true, -- Earthbreaker Haromm (Kor'kron Dark Shaman encounter) - [71515] = true, -- General Nazgrim - [71454] = true, -- Malkorok - [71889] = true, -- Secured Stockpile of Pandaren Spoils (Spoils of Pandaria encounter) - [71529] = true, -- Thok the Bloodthirsty - [71504] = true, -- Siegecrafter Blackfuse - [71152] = true, -- Skeer the Bloodseeker (Paragons of the Klaxxi encounter) - [71153] = true, -- Hisek the Swarmkeeper (Paragons of the Klaxxi encounter) - [71154] = true, -- Ka'roz the Locust (Paragons of the Klaxxi encounter) - [71155] = true, -- Korven the Prime (Paragons of the Klaxxi encounter) - [71156] = true, -- Kaz'tik the Manipulator (Paragons of the Klaxxi encounter) - [71157] = true, -- Xaril the Poisoned Mind (Paragons of the Klaxxi encounter) - [71158] = true, -- Rik'kal the Dissector (Paragons of the Klaxxi encounter) - [71160] = true, -- Iyyokuk the Lucid (Paragons of the Klaxxi encounter) - [71161] = true, -- Kil'ruk the Wind-Reaver (Paragons of the Klaxxi encounter) - [71865] = true, -- Garrosh Hellscream +private.FACTION_DATA = { + -- Used only for private.REP_BUFFS + ARGENT_CRUSADE = { 1106, _G.GetFactionInfoByID(1106) }, + BILGEWATER_CARTEL = { 1133, _G.GetFactionInfoByID(1133) }, + CENARION_CIRCLE = { 609, _G.GetFactionInfoByID(609) }, + DARKSPEAR = { 530, _G.GetFactionInfoByID(530) }, + DARNASSUS = { 69, _G.GetFactionInfoByID(69) }, + DRAGONMAW_CLAN = { 1172, _G.GetFactionInfoByID(1172) }, + EARTHEN_RING = { 1135, _G.GetFactionInfoByID(1135) }, + EBON_BLADE = { 1098, _G.GetFactionInfoByID(1098) }, + EXODAR = { 930, _G.GetFactionInfoByID(930) }, + GILNEAS = { 1134, _G.GetFactionInfoByID(1134) }, + GNOMEREGAN = { 54, _G.GetFactionInfoByID(54) }, + GUARDIANS_OF_HYJAL = { 1158, _G.GetFactionInfoByID(1158) }, + GUILD = { 1168, _G.GetFactionInfoByID(1168) }, + HONOR_HOLD = { 946, _G.GetFactionInfoByID(946) }, + HUOJIN = { 1352, _G.GetFactionInfoByID(1352) }, + IRONFORGE = { 47, _G.GetFactionInfoByID(47) }, + KIRIN_TOR = { 1090, _G.GetFactionInfoByID(1090) }, + ORGRIMMAR = { 76, _G.GetFactionInfoByID(76) }, + RAMKAHEN = { 1173, _G.GetFactionInfoByID(1173) }, + SHATAR = { 935, _G.GetFactionInfoByID(935) }, + SILVERMOON = { 911, _G.GetFactionInfoByID(911) }, + STORMWIND = { 72, _G.GetFactionInfoByID(72) }, + THERAZANE = { 1171, _G.GetFactionInfoByID(1171) }, + THRALLMAR = { 947, _G.GetFactionInfoByID(947) }, + THUNDER_BLUFF = { 81, _G.GetFactionInfoByID(81) }, + TUSHUI = { 1353, _G.GetFactionInfoByID(1353) }, + UNDERCITY = { 68, _G.GetFactionInfoByID(68) }, + WILDHAMMER_CLAN = { 1174, _G.GetFactionInfoByID(1174) }, + WYRMREST_ACCORD = { 1091, _G.GetFactionInfoByID(1091) }, + -- Commendation Factions + ANGLERS = { 1302, _G.GetFactionInfoByID(1302) }, + AUGUST_CELESTIALS = { 1341, _G.GetFactionInfoByID(1341) }, + DOMINANCE_OFFENSIVE = { 1375, _G.GetFactionInfoByID(1375) }, + GOLDEN_LOTUS = { 1269, _G.GetFactionInfoByID(1269) }, + KIRIN_TOR_OFFENSIVE = { 1387, _G.GetFactionInfoByID(1387) }, + KLAXXI = { 1337, _G.GetFactionInfoByID(1337) }, + LOREWALKERS = { 1345, _G.GetFactionInfoByID(1345) }, + OPERATION_SHIELDWALL = { 1376, _G.GetFactionInfoByID(1376) }, + ORDER_OF_THE_CLOUD_SERPENTS = { 1271, _G.GetFactionInfoByID(1271) }, + SHADO_PAN = { 1270, _G.GetFactionInfoByID(1270) }, + SHADO_PAN_ASSAULT = { 1435, _G.GetFactionInfoByID(1435) }, + SUNREAVER_ONSLAUGHT = { 1388, _G.GetFactionInfoByID(1388) }, + TILLERS = { 1272, _G.GetFactionInfoByID(1272) }, } +private.REP_BUFFS = { + -- Tabard Buffs + [_G.GetSpellInfo(93830)] = { -- BILGEWATER CARTEL TABARD + faction = private.FACTION_DATA.BILGEWATER_CARTEL[2], + ignore = true, + }, + [_G.GetSpellInfo(93827)] = { -- DARKSPEAR TABARD + faction = private.FACTION_DATA.DARKSPEAR[2], + ignore = true, + }, + [_G.GetSpellInfo(93806)] = { -- DARNASSUS TABARD + faction = private.FACTION_DATA.DARNASSUS[2], + ignore = true, + }, + [_G.GetSpellInfo(93811)] = { -- EXODAR TABARD + faction = private.FACTION_DATA.EXODAR[2], + ignore = true, + }, + [_G.GetSpellInfo(93816)] = { -- GILNEAS TABARD + faction = private.FACTION_DATA.GILNEAS[2], + ignore = true, + }, + [_G.GetSpellInfo(93821)] = { -- GNOMEREGAN TABARD + faction = private.FACTION_DATA.GNOMEREGAN[2], + ignore = true, + }, + [_G.GetSpellInfo(126436)] = { -- HUOJIN TABARD + faction = private.FACTION_DATA.HUOJIN[2], + ignore = true, + }, + [_G.GetSpellInfo(97340)] = { -- ILLUSTRIOUS GUILD TABARD + faction = private.FACTION_DATA.GUILD[2], + modifier = 1, + }, + [_G.GetSpellInfo(93805)] = { -- IRONFORGE TABARD + faction = private.FACTION_DATA.IRONFORGE[2], + ignore = true, + }, + [_G.GetSpellInfo(93825)] = { -- ORGRIMMAR TABARD + faction = private.FACTION_DATA.ORGRIMMAR[2], + ignore = true, + }, + [_G.GetSpellInfo(97341)] = { -- RENOWNED GUILD TABARD + faction = private.FACTION_DATA.GUILD[2], + modifier = 0.5, + }, + [_G.GetSpellInfo(93828)] = { -- SILVERMOON CITY TABARD + faction = private.FACTION_DATA.SILVERMOON[2], + ignore = true, + }, + [_G.GetSpellInfo(93795)] = { -- STORMWIND TABARD + faction = private.FACTION_DATA.STORMWIND[2], + ignore = true, + }, + [_G.GetSpellInfo(93337)] = { -- TABARD OF RAMKAHEN + faction = private.FACTION_DATA.RAMKAHEN[2], + ignore = true, + }, + [_G.GetSpellInfo(57819)] = { -- TABARD OF THE ARGENT CRUSADE + faction = private.FACTION_DATA.ARGENT_CRUSADE[2], + ignore = true, + }, + [_G.GetSpellInfo(94158)] = { -- TABARD OF THE DRAGONMAW CLAN + faction = private.FACTION_DATA.DRAGONMAW_CLAN[2], + ignore = true, + }, + [_G.GetSpellInfo(93339)] = { -- TABARD OF THE EARTHEN RING + faction = private.FACTION_DATA.EARTHEN_RING[2], + ignore = true, + }, + [_G.GetSpellInfo(57820)] = { -- TABARD OF THE EBON BLADE + faction = private.FACTION_DATA.EBON_BLADE[2], + ignore = true, + }, + [_G.GetSpellInfo(93341)] = { -- TABARD OF THE GUARDIANS OF HYJAL + faction = private.FACTION_DATA.GUARDIANS_OF_HYJAL[2], + ignore = true, + }, + [_G.GetSpellInfo(57821)] = { -- TABARD OF THE KIRIN TOR + faction = private.FACTION_DATA.KIRIN_TOR[2], + ignore = true, + }, + [_G.GetSpellInfo(93368)] = { -- TABARD OF THE WILDHAMMER CLAN + faction = private.FACTION_DATA.WILDHAMMER_CLAN[2], + ignore = true, + }, + [_G.GetSpellInfo(57822)] = { -- TABARD OF THE WYRMREST ACCORD + faction = private.FACTION_DATA.WYRMREST_ACCORD[2], + ignore = true, + }, + [_G.GetSpellInfo(93347)] = { -- TABARD OF THERAZANE + faction = private.FACTION_DATA.THERAZANE[2], + ignore = true, + }, + [_G.GetSpellInfo(94463)] = { -- THUNDERBLUFF TABARD + faction = private.FACTION_DATA.THUNDER_BLUFF[2], + ignore = true, + }, + [_G.GetSpellInfo(126434)] = { -- TUSHUI TABARD + faction = private.FACTION_DATA.TUSHUI[2], + ignore = true, + }, + [_G.GetSpellInfo(94462)] = { -- UNDERCITY TABARD + faction = private.FACTION_DATA.UNDERCITY[2], + ignore = true, + }, -private.WORLD_BOSS_IDS = { - [60491] = true, -- Sha of Anger - [62346] = true, -- Galleon - [69099] = true, -- Nalak - [69161] = true, -- Oondasta - [71952] = true, -- Chi-Ji - [71953] = true, -- Xuen - [71954] = true, -- Niuzao - [71955] = true, -- Yu'lon - [72057] = true, -- Ordos + -- Banner Buffs + [_G.GetSpellInfo(90216)] = { -- ALLIANCE GUILD STANDARD + ignore = true, + }, + [_G.GetSpellInfo(90708)] = { -- HORDE GUILD STANDARD + ignore = true, + }, + + -- Holiday Buffs + [_G.GetSpellInfo(136583)] = { -- DARKMOON TOP HAT + modifier = 0.1, + }, + [_G.GetSpellInfo(24705)] = { -- GRIM VISAGE + modifier = 0.1, + }, + [_G.GetSpellInfo(61849)] = { -- SPIRIT OF SHARING + modifier = 0.1, + }, + [_G.GetSpellInfo(95987)] = { -- UNBURDENED + modifier = 0.1, + }, + [_G.GetSpellInfo(46668)] = { -- WHEE! + modifier = 0.1, + }, + [_G.GetSpellInfo(100951)] = { -- WOW 8TH ANNIVERSARY + modifier = 0.08, + }, + [_G.GetSpellInfo(132700)] = { -- WOW 9TH ANNIVERSARY + modifier = 0.09, + }, + [_G.GetSpellInfo(150986)] = { -- WOW 10TH ANNIVERSARY + modifier = 0.1, + }, + + -- Situational Buffs + [_G.GetSpellInfo(39953)] = { -- ADALS SONG OF BATTLE + faction = private.FACTION_DATA.SHATAR[2], + modifier = 0.1, + }, + [_G.GetSpellInfo(30754)] = { -- CENARION FAVOR + faction = private.FACTION_DATA.CENARION_CIRCLE[2], + modifier = 0.25, + }, + [_G.GetSpellInfo(32098)] = { -- HONOR HOLD FAVOR + faction = private.FACTION_DATA.HONOR_HOLD[2], + modifier = 0.25, + }, + [_G.GetSpellInfo(39913)] = { -- NAZGRELS FERVOR + faction = private.FACTION_DATA.THRALLMAR[2], + modifier = 0.1, + }, + [_G.GetSpellInfo(32096)] = { -- THRALLMARS FAVOR + faction = private.FACTION_DATA.THRALLMAR[2], + modifier = 0.25, + }, + [_G.GetSpellInfo(39911)] = { -- TROLLBANES COMMAND + faction = private.FACTION_DATA.HONOR_HOLD[2], + modifier = 0.1, + }, } +private.RAID_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP = { + ----------------------------------------------------------------------- + -- World Bosses + ----------------------------------------------------------------------- + [132205] = 60491, -- Sha of Anger Bonus (Sha of Anger) + [132206] = 62346, -- Galleon Bonus (Galleon) + [136381] = 69099, -- Nalak Bonus (Nalak) + [137554] = 69161, -- Oondasta Bonus (Oondasta) + [148317] = 71952, -- Celestials Bonus (Chi-Ji) + [148316] = 72057, -- Ordos Bonus (Ordos) + --[????] = 81535, -- Tarlna the Ageless Bonus Loot (Tarlna the Ageless) + --[????] = 87437, -- Drov the Ruiner Bonus Loot (Drov the Ruiner) + --[????] = 87493, -- Rukhmar Bonus Loot (Rukhmar) -private.RAID_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP = { ----------------------------------------------------------------------- -- Mogu'shan Vaults ----------------------------------------------------------------------- @@ -294,13 +355,109 @@ [145918] = 71504, -- Siegecrafter Blackfuse Bonus (Siegecrafter Blackfuse) [145921] = 71161, -- Klaxxi Paragons Bonus (Kil'ruk the Wind-Reaver) [145922] = 71865, -- Garrosh Hellscream Bonus (Garrosh Hellscream) + + ----------------------------------------------------------------------- + -- Blackrock Foundry + ----------------------------------------------------------------------- + [177510] = 76877, -- Gruul Bonus Loot (Gruul) + [177511] = 77182, -- Oregorger Bonus Loot (Oregorger) + [177512] = 76809, -- Blast Furnace Loot (Foreman Feldspar) + [177513] = 76973, -- Hans'gar & Franzok Bonus Loot (Hans'gar) + [177515] = 76814, -- Flamebender Ka'graz Bonus Loot (Flamebender Ka'graz) + [177516] = 77692, -- Kromog Bonus Loot (Kromog) + [177517] = 76865, -- Beastlord Darmac Bonus Loot (Beastlord Darmac) + [177518] = 76906, -- Operator Thogar Bonus Loot (Operator Thogar) + [177519] = 77557, -- The Iron Maidens Bonus Loot (Admiral Gar'an) + [177520] = 87420, -- Blackhand Bonus Loot (Blackhand) + + ----------------------------------------------------------------------- + -- Highmaul + ----------------------------------------------------------------------- + [177503] = 87444, -- Kargath Bladefist Bonus Loot (Kargath Bladefist) + [177504] = 87447, -- Butcher Bonus Loot (The Butcher) + [177505] = 87446, -- Tectus Bonus Loot (Tectus) + [177506] = 87441, -- Brackenspore Bonus Loot (Brackenspore) + [177507] = 87449, -- Twin Ogron Bonus Loot (Twin Ogron) + [177508] = 87445, -- Ko'ragh Bonus Loot (Ko'ragh) + [177509] = 87818, -- Imperator Mar'gok Bonus Loot (Imperator Mar'gok) } -private.WORLD_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP = { - [132205] = 60491, -- Sha of Anger Bonus (Sha of Anger) - [132206] = 62346, -- Galleon Bonus (Galleon) - [136381] = 69099, -- Nalak Bonus (Nalak) - [137554] = 69161, -- Oondasta Bonus (Oondasta) - [148317] = 71952, -- Celestials Bonus (Chi-Ji) - [148316] = 72057, -- Ordos Bonus (Ordos) + +----------------------------------------------------------------------- +-- Fundamental Constants. +----------------------------------------------------------------------- +private.wow_version, private.build_num = _G.GetBuildInfo() +private.region = GetCVar("portal"):sub(0,2):upper() +-- PTR/Beta return "public-test", but they are properly called "XX" +if private.region == "PU" then private.region = "XX" end + +private.UNIT_TYPES = { + PLAYER = "Player", + OBJECT = "GameObject", + UNKNOWN = "Unknown", + NPC = "Creature", + PET = "Pet", + VEHICLE = "Vehicle", + ITEM = "Item", } + +private.UNIT_TYPE_NAMES = { + ["Player"] = "PLAYER", + ["GameObject"] = "OBJECT", + ["Unknown"] = "UNKNOWN", + ["Creature"] = "NPC", + ["Pet"] = "PET", + ["Vehicle"] = "VEHICLE", + ["Item"] = "ITEM", +} + +private.ACTION_TYPE_FLAGS = { + ITEM = 0x00000001, + NPC = 0x00000002, + OBJECT = 0x00000004, + ZONE = 0x00000008, +} + +private.ACTION_TYPE_NAMES = {} + +for name, bit in _G.pairs(private.ACTION_TYPE_FLAGS) do + private.ACTION_TYPE_NAMES[bit] = name +end + +private.SPELL_LABELS_BY_NAME = { + [_G.GetSpellInfo(13262)] = "DISENCHANT", + [_G.GetSpellInfo(4036)] = "ENGINEERING", + [_G.GetSpellInfo(30427)] = "EXTRACT_GAS", + [_G.GetSpellInfo(131476)] = "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", +} + +private.NON_LOOT_SPELL_LABELS = { + MIND_CONTROL = true, +} + +local AF = private.ACTION_TYPE_FLAGS + +private.SPELL_FLAGS_BY_LABEL = { + DISENCHANT = AF.ITEM, + ENGINEERING = AF.NPC, + EXTRACT_GAS = AF.ZONE, + FISHING = AF.ZONE, + HERB_GATHERING = bit.bor(AF.NPC, AF.OBJECT), + MILLING = AF.ITEM, + MIND_CONTROL = AF.NPC, + MINING = bit.bor(AF.NPC, AF.OBJECT), + OPENING = AF.OBJECT, + PICK_POCKET = AF.NPC, + PROSPECTING = AF.ITEM, + SEARCHING_FOR_ARTIFACTS = AF.OBJECT, + SKINNING = AF.NPC, +}
--- a/Main.lua Wed Aug 06 04:31:49 2014 -0400 +++ b/Main.lua Tue Oct 14 00:36:05 2014 -0400 @@ -10,6 +10,7 @@ local math = _G.math local table = _G.table +local next = _G.next local select = _G.select local unpack = _G.unpack @@ -47,12 +48,27 @@ local PLAYER_NAME = _G.UnitName("player") local PLAYER_RACE = _G.select(2, _G.UnitRace("player")) -local SPELL_ID_CHI_WAVE = 132464 -local SPELL_ID_DISGUISE = 121308 +local TIMBER_ITEM_ID = 114781 + +-- Ignoring NPC casts of the following spells +local CHI_WAVE_SPELL_ID = 132464 +local DISGUISE_SPELL_ID = 121308 + +-- For timer-based loot gathering of abnormal containers (that don't use SHOW_LOOT_TOAST, sadly) +local BAG_OF_SALVAGE_ITEM_ID = private.SALVAGE_SPELL_ID_TO_ITEM_ID_MAP[168178] +local CRATE_OF_SALVAGE_ITEM_ID = private.SALVAGE_SPELL_ID_TO_ITEM_ID_MAP[168179] +local BIG_CRATE_OF_SALVAGE_ITEM_ID = private.SALVAGE_SPELL_ID_TO_ITEM_ID_MAP[168180] + +-- Constant for duplicate boss data; a dirty hack to get around world bosses that cannot be identified individually and cannot be linked on wowdb because they are not in a raid +local DUPLICATE_WORLD_BOSS_IDS = { + [71952] = { 71953, 71954, 71955, }, +} local ALLOWED_LOCALES = { enUS = true, enGB = true, + enTW = true, + enCN = true, } local DATABASE_DEFAULTS = { @@ -149,6 +165,9 @@ local killed_boss_id_timer_handle local killed_npc_id local target_location_timer_handle +local last_timber_spell_id +local last_garrison_cache_object_id +local chat_loot_timer_handle local current_target_id local current_area_id local current_loot @@ -172,17 +191,22 @@ -- HELPERS ------------------------------------------------------------ local function Debug(message, ...) - if not DEBUGGING or not message or not ... then + if not DEBUGGING or not message then return end - local args = { ... } - - for index = 1, #args do - if args[index] == nil then - args[index] = "nil" + + if ... then + local args = { ... } + + for index = 1, #args do + if args[index] == nil then + args[index] = "nil" + end end + _G.print(message:format(unpack(args))) + else + _G.print(message) end - _G.print(message:format(unpack(args))) end @@ -217,7 +241,7 @@ _G.TradeSkillFrame.filterTbl.hasSkillUp = false _G.TradeSkillOnlyShowSkillUps(false) end - _G.SetTradeSkillInvSlotFilter(0, 1, 1) + _G.SetTradeSkillInvSlotFilter(0, true, true) _G.TradeSkillUpdateFilterBar() _G.TradeSkillFrame_Update() @@ -292,54 +316,6 @@ end -- do-block --- constant for duplicate boss data; a dirty hack to get around world bosses that cannot be identified individually and cannot be linked on wowdb because they are not in a raid -local DUPLICATE_WORLD_BOSS_IDS = { - [71952] = { 71953, 71954, 71955, }, -} - - --- Called on a timer -local function ClearKilledNPC() - killed_npc_id = nil -end - - -local function ClearKilledBossID() - if killed_boss_id_timer_handle then - WDP:CancelTimer(killed_boss_id_timer_handle) - killed_boss_id_timer_handle = nil - end - - table.wipe(boss_loot_toasting) - private.raid_finder_boss_id = nil - private.world_boss_id = nil -end - - -local function ClearLootToastContainerID() - if loot_toast_container_timer_handle then - WDP:CancelTimer(loot_toast_container_timer_handle) - loot_toast_container_timer_handle = nil - end - - private.container_loot_toasting = false - private.loot_toast_container_id = nil -end - - -local function ClearLootToastData() - -- cancel existing timer if found - if loot_toast_data_timer_handle then - WDP:CancelTimer(loot_toast_data_timer_handle) - loot_toast_data_timer_handle = nil - end - - if loot_toast_data then - table.wipe(loot_toast_data) - end -end - - local function InstanceDifficultyToken() local _, instance_type, instance_difficulty, _, _, _, is_dynamic = _G.GetInstanceInfo() @@ -380,11 +356,7 @@ function NPCEntry(identifier) local npc = DBEntry("npcs", identifier) - - if not npc then - return - end - return _G.setmetatable(npc, npc_meta) + return npc and _G.setmetatable(npc, npc_meta) or nil end function npc_prototype:EncounterData(difficulty_token) @@ -463,26 +435,37 @@ local ParseGUID do local UNIT_TYPES = private.UNIT_TYPES - local UNIT_TYPE_BITMASK = 0x007 local NPC_ID_MAPPING = { [62164] = 63191, -- Garalon } + local function MatchUnitTypes(unit_type_name) + if not unit_type_name then + return UNIT_TYPES.UNKNOWN + end + + for def, text in next, UNIT_TYPES do + if unit_type_name == text then + return UNIT_TYPES[def] + end + end + return UNIT_TYPES.UNKNOWN + end + + function ParseGUID(guid) if not guid then return end - local bitfield = tonumber(guid:sub(1, 5)) - - if not bitfield then - return UNIT_TYPES.UNKNOWN - end - local unit_type = _G.bit.band(bitfield, UNIT_TYPE_BITMASK) - - if unit_type ~= UNIT_TYPES.PLAYER and unit_type ~= UNIT_TYPES.PET then - local unit_idnum = tonumber(guid:sub(6, 10), 16) + + -- We might want to use some of this new information later, but leaving the returns alone for now + local unit_type_name, unk_id1, server_id, instance_id, unk_id2, unit_idnum, spawn_id = ("-"):split(guid) + + local unit_type = MatchUnitTypes(unit_type_name) + if unit_type ~= UNIT_TYPES.PLAYER and unit_type ~= UNIT_TYPES.PET and unit_type ~= UNIT_TYPES.ITEM then + local id_mapping = NPC_ID_MAPPING[unit_idnum] if id_mapping and UnitTypeIsNPC(unit_type) then @@ -583,7 +566,7 @@ local current_line = _G["WDPDatamineTTTextLeft" .. line_index] if not current_line then - Debug("HandleItemUse: Item with ID %d and link %s had an invalid tooltip.", item_id, item_link, _G.ITEM_OPENABLE) + Debug("HandleItemUse: Item with ID %d and link %s had an invalid tooltip.", item_id, item_link) return end @@ -597,7 +580,6 @@ return end end - Debug("HandleItemUse: Item with ID %d and link %s did not have a tooltip that contained the string %s.", item_id, item_link, _G.ITEM_OPENABLE) end @@ -674,7 +656,7 @@ -- Items return the player as the source, so we need to use the item's ID (disenchant, milling, etc) source_id = current_loot.identifier else - local unit_ID = select(2, ParseGUID(source_guid)) + local _, unit_ID = ParseGUID(source_guid) if unit_ID then if current_loot.target_type == AF.OBJECT then source_id = ("%s:%s"):format(current_loot.spell_label, unit_ID) @@ -805,7 +787,8 @@ _G.SetCVar("Sound_EnableSFX", 0) world_map:Show() end - local micro_dungeon_id = MICRO_DUNGEON_IDS[select(5, _G.GetMapInfo())] + local _, _, _, _, micro_dungeon_map_name = _G.GetMapInfo() + local micro_dungeon_id = MICRO_DUNGEON_IDS[micro_dungeon_map_name] _G.SetMapToCurrentZone() @@ -847,6 +830,63 @@ table.wipe(current_action) end + +-- TIMERS ------------------------------------------------------------- + +local function ClearKilledNPC() + killed_npc_id = nil +end + + +local function ClearKilledBossID() + if killed_boss_id_timer_handle then + WDP:CancelTimer(killed_boss_id_timer_handle) + killed_boss_id_timer_handle = nil + end + + table.wipe(boss_loot_toasting) + private.raid_boss_id = nil +end + + +local function ClearLootToastContainerID() + if loot_toast_container_timer_handle then + WDP:CancelTimer(loot_toast_container_timer_handle) + loot_toast_container_timer_handle = nil + end + + private.container_loot_toasting = false + private.loot_toast_container_id = nil +end + + +local function ClearLootToastData() + -- cancel existing timer if found + if loot_toast_data_timer_handle then + WDP:CancelTimer(loot_toast_data_timer_handle) + loot_toast_data_timer_handle = nil + end + + if loot_toast_data then + table.wipe(loot_toast_data) + end +end + + +local function ClearTimeBasedLootData() + Debug("ClearTimeBasedLootData: Ending salvage loot timer.") + if chat_loot_timer_handle then + WDP:CancelTimer(chat_loot_timer_handle) + chat_loot_timer_handle = nil + end + + if current_loot and current_loot.identifier and (current_loot.identifier == BAG_OF_SALVAGE_ITEM_ID or current_loot.identifier == CRATE_OF_SALVAGE_ITEM_ID or current_loot.identifier == BIG_CRATE_OF_SALVAGE_ITEM_ID) then + GenericLootUpdate("items") + end + current_loot = nil +end + + -- METHODS ------------------------------------------------------------ function WDP:OnInitialize() @@ -858,12 +898,19 @@ local raw_db = _G.WoWDBProfilerData local build_num = tonumber(private.build_num) + -- Disable if using a MoP build + if build_num < 19000 then + WDP:Disable() + return + end + if (raw_db.version and raw_db.version < DB_VERSION) or (raw_db.build_num and raw_db.build_num < build_num) then for entry in pairs(DATABASE_DEFAULTS.global) do global_db[entry] = {} end end raw_db.build_num = build_num + raw_db.region = private.region raw_db.version = DB_VERSION private.InitializeCommentSystem() @@ -949,14 +996,6 @@ local amount, stat = left_text:match("+(.-) (.*)") if amount and stat then - if reforge_id and reforge_id ~= 0 then - local reforge_string = stat:find("Reforged") - - if reforge_string then - stat = stat:sub(0, reforge_string - 3) - intermediary.reforge_id = reforge_id - end - end create_entry = true intermediary[stat:lower():gsub(" ", "_"):gsub("|r", "")] = tonumber((amount:gsub(",", ""))) end @@ -974,29 +1013,54 @@ item.upgrades[upgrade_id][stat] = amount end end -end - --- do-block - - -local function RecordItemData(item_id, item_link, durability) - local item_string = select(3, item_link:find("^|%x+|H(.+)|h%[.+%]")) +end -- do-block + + +local function RecordItemData(item_id, item_link, process_bonus_ids, durability) + local _, _, item_string = item_link:find("^|%x+|H(.+)|h%[.+%]") local item if item_string then - local _, _, _, _, _, _, _, suffix_id, unique_id, _, reforge_id, upgrade_id = (":"):split(item_string) - suffix_id = tonumber(suffix_id) - upgrade_id = tonumber(upgrade_id) - - if suffix_id and suffix_id ~= 0 then + local item_results = { (":"):split(item_string) } + + local suffix_id = tonumber(item_results[8]) + local unique_id = item_results[9] + local upgrade_id = tonumber(item_results[11]) + local instance_difficulty_id = tonumber(item_results[12]) + local num_bonus_ids = tonumber(item_results[13]) + + if not num_bonus_ids or num_bonus_ids == 0 or not process_bonus_ids then + if (suffix_id and suffix_id ~= 0) or (instance_difficulty_id and instance_difficulty_id ~= 0) then + item = DBEntry("items", item_id) + item.unique_id = bit.band(unique_id, 0xFFFF) + + if suffix_id and suffix_id ~= 0 then + item.suffix_id = suffix_id + end + + if instance_difficulty_id and instance_difficulty_id ~= 0 then + item.instance_difficulty_id = instance_difficulty_id + end + end + elseif num_bonus_ids > 0 then item = DBEntry("items", item_id) - item.suffix_id = suffix_id + item.unique_id = bit.band(unique_id, 0xFFFF) + item.instance_difficulty_id = instance_difficulty_id + + if not item.bonus_ids then + item.bonus_ids = {} + end + + for bonus_index = 1, num_bonus_ids do + item.bonus_ids[tonumber(item_results[13 + bonus_index])] = true + end + else + Debug("RecordItemData: Item_system is supposed to be 0 or positive, instead it was %s.", item_system) end - if upgrade_id and upgrade_id ~= 0 then DatamineTT:SetHyperlink(item_link) - ScrapeItemUpgradeStats(item_id, upgrade_id, reforge_id) + ScrapeItemUpgradeStats(item_id, upgrade_id) end end @@ -1013,7 +1077,7 @@ if item_id and item_id > 0 then local _, max_durability = _G.GetInventoryItemDurability(slot_index) - RecordItemData(item_id, _G.GetInventoryItemLink("player", slot_index), max_durability) + RecordItemData(item_id, _G.GetInventoryItemLink("player", slot_index), false, max_durability) end end @@ -1023,7 +1087,7 @@ if item_id and item_id > 0 then local _, max_durability = _G.GetContainerItemDurability(bag_index, slot_index) - RecordItemData(item_id, _G.GetContainerItemLink(bag_index, slot_index), max_durability) + RecordItemData(item_id, _G.GetContainerItemLink(bag_index, slot_index), false, max_durability) end end end @@ -1092,7 +1156,7 @@ level_data.max_health = level_data.max_health or _G.UnitHealthMax("target") if not level_data.power then - local max_power = _G.UnitManaMax("target") + local max_power = _G.UnitPowerMax("target") if max_power > 0 then local power_type = _G.UnitPowerType("target") @@ -1209,16 +1273,40 @@ end -function WDP:SHOW_LOOT_TOAST(event_name, loot_type, item_link, quantity) +function WDP:SHOW_LOOT_TOAST(event_name, loot_type, item_link, quantity, specID, sex, isPersonal, lootSource) if not loot_type or (loot_type ~= "item" and loot_type ~= "money" and loot_type ~= "currency") then Debug("%s: loot_type is %s. Item link is %s, and quantity is %d.", event_name, loot_type, item_link, quantity) return end local container_id = private.loot_toast_container_id - local npc_id = private.raid_finder_boss_id or private.world_boss_id - - if npc_id then - -- slightly messy hack to workaround duplicate world bosses + local npc_id = private.raid_boss_id + + -- Handle Garrison cache specially + if lootSource and last_garrison_cache_object_id and (lootSource == private.GARRISON_CACHE_LOOT_SOURCE_ID) then + -- Record location data for cache + UpdateDBEntryLocation("objects", ("OPENING:%d"):format(last_garrison_cache_object_id)) + + -- Add drop data + local currency_texture = CurrencyLinkToTexture(item_link) + if currency_texture and currency_texture ~= "" then + -- Check for top level object data + local object_entry = DBEntry("objects", ("OPENING:%d"):format(last_garrison_cache_object_id)) + local difficulty_token = InstanceDifficultyToken() + if object_entry[difficulty_token] then + -- Increment loot count + object_entry[difficulty_token]["opening_count"] = (object_entry[difficulty_token]["opening_count"] or 0) + 1 + + Debug("%s: %s X %d", event_name, currency_texture, quantity) + object_entry[difficulty_token]["opening"] = object_entry[difficulty_token]["opening"] or {} + table.insert(object_entry[difficulty_token]["opening"], ("currency:%d:%s"):format(quantity, currency_texture)) + else + Debug("%s: When handling the Garrison cache, the top level loot data was missing for objectID %d.", event_name, last_garrison_cache_object_id) + end + else + Debug("%s: Currency texture is nil, from currency link %s", event_name, item_link) + end + elseif npc_id then + -- Slightly messy hack to workaround duplicate world bosses local upper_limit = 0 if DUPLICATE_WORLD_BOSS_IDS[npc_id] then upper_limit = #DUPLICATE_WORLD_BOSS_IDS[npc_id] @@ -1241,6 +1329,7 @@ local item_id = ItemLinkToID(item_link) if item_id then Debug("%s: %s X %d (%d)", event_name, item_link, quantity, item_id) + RecordItemData(item_id, item_link, true) table.insert(encounter_data[loot_label], ("%d:%d"):format(item_id, quantity)) else Debug("%s: ItemID is nil, from item link %s", event_name, item_link) @@ -1253,10 +1342,6 @@ local currency_texture = CurrencyLinkToTexture(item_link) if currency_texture and currency_texture ~= "" then Debug("%s: %s X %d", event_name, currency_texture, quantity) - -- workaround for Patch 5.4.0 bug with Flexible raid Siege of Orgrimmar bosses and Valor Points - if quantity > 1000 and currency_texture == "pvecurrency-valor" then - quantity = math.floor(quantity / 100) - end table.insert(encounter_data[loot_label], ("currency:%d:%s"):format(quantity, currency_texture)) else Debug("%s: Currency texture is nil, from currency link %s", event_name, item_link) @@ -1284,6 +1369,7 @@ local item_id = ItemLinkToID(item_link) if item_id then Debug("%s: %s X %d (%d)", event_name, item_link, quantity, item_id) + RecordItemData(item_id, item_link, true) current_loot.sources[container_id][item_id] = current_loot.sources[container_id][item_id] or 0 + quantity else Debug("%s: ItemID is nil, from item link %s", event_name, item_link) @@ -1315,6 +1401,11 @@ loot_toast_data = loot_toast_data or {} loot_toast_data[#loot_toast_data + 1] = { loot_type, item_link, quantity } + local item_id = ItemLinkToID(item_link) + if item_id then + RecordItemData(item_id, item_link, true) + end + loot_toast_data_timer_handle = WDP:ScheduleTimer(ClearLootToastData, 5) end end @@ -1322,10 +1413,41 @@ do local CHAT_MSG_LOOT_UPDATE_FUNCS = { + [AF.ITEM] = function(item_id, quantity) + local container_id = current_loot.identifier -- For faster access, since this is going to be called 9 times in the next 3 lines + -- Verify that we're still assigning data to the right items + if container_id and (container_id == BAG_OF_SALVAGE_ITEM_ID or container_id == CRATE_OF_SALVAGE_ITEM_ID or container_id == BIG_CRATE_OF_SALVAGE_ITEM_ID) then + Debug("CHAT_MSG_LOOT: AF.ITEM %d (%d)", item_id, quantity) + current_loot.sources[container_id] = current_loot.sources[container_id] or {} + current_loot.sources[container_id][item_id] = (current_loot.sources[container_id][item_id] or 0) + quantity + else -- If not, cancel the timer and wipe the loot table early + Debug("CHAT_MSG_LOOT: We would have assigned the wrong loot to salvage crates!") + ClearTimeBasedLootData() + end + end, [AF.NPC] = function(item_id, quantity) - Debug("CHAT_MSG_LOOT: %d (%d)", item_id, quantity) + Debug("CHAT_MSG_LOOT: AF.NPC %d (%d)", item_id, quantity) + end, + [AF.OBJECT] = function(item_id, quantity) + Debug("CHAT_MSG_LOOT: AF.OBJECT %d (%d)", item_id, quantity) + --for timber_variant = 1, #private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[last_timber_spell_id] do + -- Check for top level object data + local object_entry = DBEntry("objects", ("OPENING:%s"):format(private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[last_timber_spell_id])) + local difficulty_token = InstanceDifficultyToken() + if object_entry[difficulty_token] then + -- Increment loot count + object_entry[difficulty_token]["opening_count"] = (object_entry[difficulty_token]["opening_count"] or 0) + 1 + + -- Add drop data + object_entry[difficulty_token]["opening"] = object_entry[difficulty_token]["opening"] or {} + table.insert(object_entry[difficulty_token]["opening"], ("%d:%d"):format(item_id, quantity)) + else + Debug("CHAT_MSG_LOOT: When handling timber, the top level loot data was missing for objectID %s.", private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[last_timber_spell_id]) + end + --end end, [AF.ZONE] = function(item_id, quantity) + Debug("CHAT_MSG_LOOT: AF.ZONE %d (%d)", item_id, quantity) InitializeCurrentLoot() current_loot.list[1] = ("%d:%d"):format(item_id, quantity) GenericLootUpdate("zones") @@ -1337,18 +1459,7 @@ function WDP:CHAT_MSG_LOOT(event_name, message) local category - if current_action.spell_label ~= "EXTRACT_GAS" then - category = AF.ZONE - elseif private.raid_finder_boss_id then - category = AF.NPC - end - local update_func = CHAT_MSG_LOOT_UPDATE_FUNCS[category] - - if not category or not update_func then - return - end local item_link, quantity = deformat(message, _G.LOOT_ITEM_PUSHED_SELF_MULTIPLE) - if not item_link then quantity, item_link = 1, deformat(message, _G.LOOT_ITEM_PUSHED_SELF) end @@ -1357,6 +1468,26 @@ if not item_id then return end + + -- Set update category + if last_timber_spell_id and item_id == TIMBER_ITEM_ID then + category = AF.OBJECT + -- Recently changed from ~= "EXTRACT_GAS" because of some occassional bad data, and, as far as I know, no benefit. + elseif current_action.spell_label == "FISHING" then + category = AF.ZONE + elseif private.raid_boss_id then + category = AF.NPC + elseif chat_loot_timer_handle then + category = AF.ITEM + end + + -- Take action based on update category + local update_func = CHAT_MSG_LOOT_UPDATE_FUNCS[category] + if not category or not update_func then + -- We still want to record the item's data, even if it doesn't need its drop location recorded + RecordItemData(item_id, item_link, true) + return + end update_func(item_id, quantity) end end @@ -1443,12 +1574,12 @@ end -do -- do-block +do local FLAGS_NPC = bit.bor(_G.COMBATLOG_OBJECT_TYPE_GUARDIAN, _G.COMBATLOG_OBJECT_CONTROL_NPC) local FLAGS_NPC_CONTROL = bit.bor(_G.COMBATLOG_OBJECT_AFFILIATION_OUTSIDER, _G.COMBATLOG_OBJECT_CONTROL_NPC) local function RecordNPCSpell(sub_event, source_guid, source_name, source_flags, dest_guid, dest_name, dest_flags, spell_id, spell_name) - if not spell_id or spell_id == SPELL_ID_CHI_WAVE or spell_id == SPELL_ID_DISGUISE then + if not spell_id or spell_id == CHI_WAVE_SPELL_ID or spell_id == DISGUISE_SPELL_ID then return end local source_type, source_id = ParseGUID(source_guid) @@ -1548,70 +1679,12 @@ end end + local DIPLOMACY_SPELL_ID = 20599 local MR_POP_RANK1_SPELL_ID = 78634 local MR_POP_RANK2_SPELL_ID = 78635 - - local REP_BUFFS = { - [_G.GetSpellInfo(30754)] = "CENARION_FAVOR", - [_G.GetSpellInfo(24705)] = "GRIM_VISAGE", - [_G.GetSpellInfo(32098)] = "HONOR_HOLD_FAVOR", - [_G.GetSpellInfo(39913)] = "NAZGRELS_FERVOR", - [_G.GetSpellInfo(39953)] = "SONG_OF_BATTLE", - [_G.GetSpellInfo(61849)] = "SPIRIT_OF_SHARING", - [_G.GetSpellInfo(32096)] = "THRALLMARS_FAVOR", - [_G.GetSpellInfo(39911)] = "TROLLBANES_COMMAND", - [_G.GetSpellInfo(95987)] = "UNBURDENED", - [_G.GetSpellInfo(100951)] = "WOW_ANNIVERSARY", - } - - - local FACTION_NAMES = { - CENARION_CIRCLE = _G.GetFactionInfoByID(609), - HONOR_HOLD = _G.GetFactionInfoByID(946), - THE_SHATAR = _G.GetFactionInfoByID(935), - THRALLMAR = _G.GetFactionInfoByID(947), - } - - - local MODIFIERS = { - CENARION_FAVOR = { - faction = FACTION_NAMES.CENARION_CIRCLE, - modifier = 0.25, - }, - GRIM_VISAGE = { - modifier = 0.1, - }, - HONOR_HOLD_FAVOR = { - faction = FACTION_NAMES.HONOR_HOLD, - modifier = 0.25, - }, - NAZGRELS_FERVOR = { - faction = FACTION_NAMES.THRALLMAR, - modifier = 0.1, - }, - SONG_OF_BATTLE = { - faction = FACTION_NAMES.THE_SHATAR, - modifier = 0.1, - }, - SPIRIT_OF_SHARING = { - modifier = 0.1, - }, - THRALLMARS_FAVOR = { - faction = FACTION_NAMES.THRALLMAR, - modifier = 0.25, - }, - TROLLBANES_COMMAND = { - faction = FACTION_NAMES.HONOR_HOLD, - modifier = 0.1, - }, - UNBURDENED = { - modifier = 0.1, - }, - WOW_ANNIVERSARY = { - modifier = 0.08, - } - } + local FACTION_DATA = private.FACTION_DATA + local REP_BUFFS = private.REP_BUFFS function WDP:COMBAT_TEXT_UPDATE(event_name, message_type, faction_name, amount) @@ -1635,25 +1708,48 @@ local modifier = 1 + -- Check for modifiers from known spells if _G.IsSpellKnown(DIPLOMACY_SPELL_ID) then modifier = modifier + 0.1 end - if _G.IsSpellKnown(MR_POP_RANK2_SPELL_ID) then modifier = modifier + 0.1 elseif _G.IsSpellKnown(MR_POP_RANK1_SPELL_ID) then modifier = modifier + 0.05 end - for buff_name, buff_label in pairs(REP_BUFFS) do + -- Determine faction ID + local faction_ID + for pseudo_faction_name, faction_data_table in pairs(FACTION_DATA) do + if faction_name == faction_data_table[2] then + faction_ID = faction_data_table[1] + end + end + if faction_ID and faction_ID > 0 then + -- Check for modifiers from Commendations (applied directly to the faction, account-wide) + local _, _, _, _, _, _, _, _, _, _, _, _, _, _, has_bonus_rep_gain = GetFactionInfoByID(faction_ID) + if has_bonus_rep_gain then + modifier = modifier + 1 + end + end + + -- Check for modifiers from buffs + for buff_name, buff_data_table in pairs(REP_BUFFS) do if _G.UnitBuff("player", buff_name) then - local modded_faction = MODIFIERS[buff_label].faction + local modded_faction = buff_data_table.faction if not modded_faction or faction_name == modded_faction then - modifier = modifier + MODIFIERS[buff_label].modifier + if buff_data_table.ignore then + -- Some buffs from tabards convert all rep of other factions into rep for a specific faction. + -- We can't know what faction the rep was orginally from, so we must ignore the data entirely in these cases. + return + else + modifier = modifier + buff_data_table.modifier + end end end end + npc.reputations = npc.reputations or {} npc.reputations[("%s:%s"):format(faction_name, faction_standings[faction_name])] = math.floor(amount / modifier) end @@ -1661,17 +1757,23 @@ function WDP:CURSOR_UPDATE(event_name) - if current_action.fishing_target or _G.Minimap:IsMouseOver() or current_action.spell_label ~= "FISHING" then + if current_action.fishing_target or _G.Minimap:IsMouseOver() then return end local text = _G["GameTooltipTextLeft1"]:GetText() - if not text or text == "Fishing Bobber" then - text = "NONE" - else - current_action.fishing_target = true + -- Handle Fishing + if (current_action.spell_label == "FISHING") then + if not text or text == "Fishing Bobber" then + text = "NONE" + else + current_action.fishing_target = true + end + current_action.identifier = ("%s:%s"):format(current_action.spell_label, text) + -- Handle Garrison Cache + elseif private.GARRISON_CACHE_OBJECT_NAME_TO_OBJECT_ID_MAP[text] then + last_garrison_cache_object_id = private.GARRISON_CACHE_OBJECT_NAME_TO_OBJECT_ID_MAP[text] end - current_action.identifier = ("%s:%s"):format(current_action.spell_label, text) end @@ -1731,7 +1833,7 @@ local source_list = {} for source_guid, loot_data in pairs(current_loot.sources) do - local source_id = select(2, ParseGUID(source_guid)) + local _, source_id = ParseGUID(source_guid) local npc = NPCEntry(source_id) if npc then @@ -1808,6 +1910,13 @@ local extrapolated_guid_registry = {} local num_guids = 0 + -- Loot extrapolation cannot handle objects that need special spell labels (like HERBALISM or MINING) (MIND_CONTROL is okay) + if private.SPELL_FLAGS_BY_LABEL[current_action.spell_label] and not private.NON_LOOT_SPELL_LABELS[current_action.spell_label] then + 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) + table.wipe(current_action) + return false + end + table.wipe(current_action) for loot_slot = 1, _G.GetNumLootItems() do @@ -1839,11 +1948,6 @@ return false end - if private.previous_spell_id and private.EXTRAPOLATION_BANNED_SPELL_IDS[private.previous_spell_id] then - Debug("%s: Problematic spell id %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) - return false - end - local num_npcs = 0 local num_objects = 0 local num_itemcontainers = 0 @@ -1868,8 +1972,8 @@ current_action.target_type = AF.NPC current_action.identifier = unit_idnum num_npcs = num_npcs + 1 - -- Item container GUIDs are currently of the 'PLAYER' type; this may be unintended and could change in the future. elseif unit_type == private.UNIT_TYPES.PLAYER then + -- Item container GUIDs are currently of the 'PLAYER' type; this may be unintended and could change in the future. current_action.loot_label = loot_label current_action.target_type = AF.ITEM -- current_action.identifier assigned during loot verification. @@ -1947,16 +2051,14 @@ if not loot_guid_registry[current_loot.label][source_guid] then local loot_quantity = loot_info[loot_index + 1] - -- There is a new bug in 5.4.0 that causes GetLootSlotInfo() to (rarely) return nil values for slot_quantity. if slot_quantity then -- We need slot_quantity to account for an old bug where loot_quantity is sometimes '1' for stacks of items, such as cloth. if slot_quantity > loot_quantity then loot_quantity = slot_quantity end - local source_type, source_id = ParseGUID(source_guid) - local source_key = ("%s:%d"):format(private.UNIT_TYPE_NAMES[source_type + 1], source_id) + local source_key = ("%s:%d"):format(source_type, source_id) if slot_type == _G.LOOT_SLOT_ITEM then local item_id = ItemLinkToID(_G.GetLootSlotLink(loot_slot)) @@ -1992,7 +2094,7 @@ end else -- 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. - 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) + Debug("%s: Slot quantity is nil for loot slot %d.", event_name, loot_slot) end end end @@ -2045,7 +2147,8 @@ if not unit_idnum or not UnitTypeIsNPC(unit_type) then return end - merchant_standing = select(2, UnitFactionStanding("npc")) + local _, faction_standing = UnitFactionStanding("npc") + merchant_standing = faction_standing current_merchant = NPCEntry(unit_idnum) current_merchant.sells = current_merchant.sells or {} end @@ -2065,11 +2168,7 @@ if not item_id then local item_name, item_link = DatamineTT:GetItem() item_id = ItemLinkToID(item_link) - if item_id then - Debug("%s: GetMerchantItemLink() still ocassionally fails, apparently. Failed item's ID - %s", event_name, item_id) - else - Debug("%s: GetMerchantItemLink() still ocassionally fails, apparently. Failed item's ID - nil", event_name) - end + -- GetMerchantItemLink() still ocassionally fails as of Patch 6.0.2. It fails so badly that debug functions cause considerable slowdown. end if item_id and item_id > 0 then @@ -2168,7 +2267,7 @@ function WDP:PET_BAR_UPDATE(event_name) - if current_action.spell_label ~= "MIND_CONTROL" then + if not private.NON_LOOT_SPELL_LABELS[current_action.spell_label] then return end local unit_type, unit_idnum = ParseGUID(_G.UnitGUID("pet")) @@ -2245,13 +2344,13 @@ return end local unit_type, unit_id = ParseGUID(_G.UnitGUID("questnpc")) - + Debug("UpdateQuestJuncture: Updating quest juncture for %s.", ("%s:%d"):format(private.UNIT_TYPE_NAMES[unit_type], unit_id)) if unit_type == private.UNIT_TYPES.OBJECT then UpdateDBEntryLocation("objects", unit_id) end local quest = DBEntry("quests", _G.GetQuestID()) quest[point] = quest[point] or {} - quest[point][("%s:%d"):format(private.UNIT_TYPE_NAMES[unit_type + 1], unit_id)] = true + quest[point][("%s:%d"):format(private.UNIT_TYPE_NAMES[unit_type], unit_id)] = true return quest end @@ -2289,7 +2388,7 @@ local _, num_quests = _G.GetNumQuestLogEntries() while processed_quests <= num_quests do - local _, _, _, _, is_header, _, _, _, quest_id = _G.GetQuestLogTitle(entry_index) + local _, _, _, is_header, _, _, _, quest_id = _G.GetQuestLogTitle(entry_index) if quest_id == 0 then processed_quests = processed_quests + 1 @@ -2332,13 +2431,16 @@ local function RegisterTools(tradeskill_name, tradeskill_index) - local spell_id = tonumber(_G.GetTradeSkillRecipeLink(tradeskill_index):match("^|c%x%x%x%x%x%x%x%x|H%w+:(%d+)")) - local required_tool = _G.GetTradeSkillTools(tradeskill_index) - - if required_tool then - for tool_name, registry in pairs(TRADESKILL_TOOLS) do - if required_tool:find(tool_name) then - registry[spell_id] = true + local link = _G.GetTradeSkillRecipeLink(tradeskill_index) + if link then + local spell_id = tonumber(link:match("^|c%x%x%x%x%x%x%x%x|H%w+:(%d+)")) + local required_tool = _G.GetTradeSkillTools(tradeskill_index) + + if required_tool then + for tool_name, registry in pairs(TRADESKILL_TOOLS) do + if required_tool:find(tool_name) then + registry[spell_id] = true + end end end end @@ -2368,15 +2470,15 @@ if not trainer then return end - local trainer_standing = select(2, UnitFactionStanding("npc")) + local _, trainer_standing = UnitFactionStanding("npc") trainer.teaches = trainer.teaches or {} private.trainer_shown = true -- Get the initial trainer filters - local available = _G.GetTrainerServiceTypeFilter("available") - local unavailable = _G.GetTrainerServiceTypeFilter("unavailable") - local used = _G.GetTrainerServiceTypeFilter("used") + local available = _G.GetTrainerServiceTypeFilter("available") and 1 or 0 + local unavailable = _G.GetTrainerServiceTypeFilter("unavailable") and 1 or 0 + local used = _G.GetTrainerServiceTypeFilter("used") and 1 or 0 -- Clear the trainer filters _G.SetTrainerServiceTypeFilter("available", 1) @@ -2429,6 +2531,7 @@ return end + Debug("UNIT_SPELLCAST_SENT: %s was cast.", spell_name) local item_name, item_link = _G.GameTooltip:GetItem() local unit_name, unit_id = _G.GameTooltip:GetUnit() @@ -2468,7 +2571,8 @@ if item_name and item_name == target_name then current_action.identifier = ItemLinkToID(item_link) elseif target_name and target_name ~= "" then - current_action.identifier = ItemLinkToID(select(2, _G.GetItemInfo(target_name))) + local _, item_link = _G.GetItemInfo(target_name) + current_action.identifier = ItemLinkToID(item_link) end elseif not item_name and not unit_name then if bit.band(spell_flags, AF.OBJECT) == AF.OBJECT then @@ -2489,19 +2593,15 @@ if private.RAID_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP[spell_id] then ClearKilledBossID() ClearLootToastContainerID() - private.raid_finder_boss_id = private.RAID_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP[spell_id] - elseif private.WORLD_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP[spell_id] then - ClearKilledBossID() - ClearLootToastContainerID() - private.world_boss_id = private.WORLD_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP[spell_id] + private.raid_boss_id = private.RAID_BOSS_BONUS_SPELL_ID_TO_NPC_ID_MAP[spell_id] else - Debug("%s: Spell ID %d is not a known raid or world boss 'Bonus' spell.", event_name, spell_id) + Debug("%s: Spell ID %d is not a known raid boss 'Bonus' spell.", event_name, spell_id) return end -- Assign existing loot data to boss if it exists if loot_toast_data then - local npc_id = private.raid_finder_boss_id or private.world_boss_id + local npc_id = private.raid_boss_id -- Slightly messy hack to workaround duplicate world bosses local upper_limit = 0 @@ -2571,6 +2671,16 @@ private.tracked_line = nil private.previous_spell_id = spell_id + -- Handle Logging spell casts + if private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[spell_id] then + last_timber_spell_id = spell_id + --for timber_variant = 1, #private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[spell_id] do + UpdateDBEntryLocation("objects", ("OPENING:%s"):format(private.LOGGING_SPELL_ID_TO_OBJECT_ID_MAP[spell_id])) + --end + return + end + + -- Handle Loot Toast spell casts if private.LOOT_SPELL_ID_TO_ITEM_ID_MAP[spell_id] then ClearKilledBossID() ClearLootToastContainerID() @@ -2578,6 +2688,23 @@ private.loot_toast_container_id = private.LOOT_SPELL_ID_TO_ITEM_ID_MAP[spell_id] loot_toast_container_timer_handle = WDP:ScheduleTimer(ClearLootToastContainerID, 1) -- we need to assign a handle here to cancel it later + return + end + + -- For Crates of Salvage (and potentially other items based on spell casts in the future which need manual handling) + if private.SALVAGE_SPELL_ID_TO_ITEM_ID_MAP[spell_id] then + -- Set up timer + Debug("%s: Beginning Salvage loot timer for spellID %d", event_name, spell_id) + chat_loot_timer_handle = WDP:ScheduleTimer(ClearTimeBasedLootData, 1) + + -- Standard item handling setup + table.wipe(current_action) + current_loot = nil + current_action.target_type = AF.ITEM + current_action.identifier = private.SALVAGE_SPELL_ID_TO_ITEM_ID_MAP[spell_id] + current_action.loot_label = "contains" + InitializeCurrentLoot() + return end if anvil_spell_ids[spell_id] then @@ -2586,7 +2713,7 @@ UpdateDBEntryLocation("objects", OBJECT_ID_FORGE) elseif spell_name:match("^Harvest.+") then killed_npc_id = current_target_id - private.harvesting = true + private.harvesting = true -- Used to track which NPCs can be harvested (can we get this from CreatureCache instead?) end end