Mercurial > wow > askmrrobot
changeset 0:ec731d2fe6ba
Version 1.2.12.0
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AskMrRobot.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,1245 @@ +local _, AskMrRobot = ... + +AskMrRobot.eventListener = CreateFrame("FRAME"); -- Need a frame to respond to events +AskMrRobot.eventListener:RegisterEvent("ADDON_LOADED"); -- Fired when saved variables are loaded +AskMrRobot.eventListener:RegisterEvent("ITEM_PUSH"); +AskMrRobot.eventListener:RegisterEvent("DELETE_ITEM_CONFIRM"); +AskMrRobot.eventListener:RegisterEvent("UNIT_INVENTORY_CHANGED"); +AskMrRobot.eventListener:RegisterEvent("BANKFRAME_OPENED"); +AskMrRobot.eventListener:RegisterEvent("BANKFRAME_CLOSED"); +AskMrRobot.eventListener:RegisterEvent("PLAYERBANKSLOTS_CHANGED"); +AskMrRobot.eventListener:RegisterEvent("CHARACTER_POINTS_CHANGED"); +AskMrRobot.eventListener:RegisterEvent("CONFIRM_TALENT_WIPE"); +AskMrRobot.eventListener:RegisterEvent("PLAYER_TALENT_UPDATE"); +AskMrRobot.eventListener:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED"); +AskMrRobot.eventListener:RegisterEvent("PLAYER_LOGOUT"); -- Fired when about to log out +AskMrRobot.eventListener:RegisterEvent("PLAYER_LEVEL_UP"); +--AskMrRobot.eventListener:RegisterEvent("GET_ITEM_INFO_RECEIVED") +AskMrRobot.eventListener:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED") +AskMrRobot.eventListener:RegisterEvent("SOCKET_INFO_UPDATE") +AskMrRobot.eventListener:RegisterEvent("SOCKET_INFO_CLOSE") +AskMrRobot.eventListener:RegisterEvent("BAG_UPDATE") +AskMrRobot.eventListener:RegisterEvent("ITEM_UNLOCKED") +--AskMrRobot.eventListener:RegisterEvent("PLAYER_REGEN_DISABLED") +AskMrRobot.eventListener:RegisterEvent("ENCOUNTER_START") +AskMrRobot.eventListener:RegisterEvent("CHAT_MSG_ADDON") +AskMrRobot.eventListener:RegisterEvent("UPDATE_INSTANCE_INFO") +AskMrRobot.eventListener:RegisterEvent("PLAYER_DIFFICULTY_CHANGED") + +AskMrRobot.AddonName = ... +AskMrRobot.ChatPrefix = "_AMR" + +local amrLDB +local icon +local reforgequeue +local reforgeFrame = nil +local LoggingCombat = _G.LoggingCombat + +AskMrRobot.itemDiffs = { + items = {}, -- slotNum -> nil (no change) or current <item id>, optimized <item id> + enchants = {}, -- slotNum -> nil (no change) or current <enchant id>, optimized <enchant id> + gems = {}, -- slotNum -> nil (no change) or ? + reforges = {} -- slotNum -> nil (no change) or current <reforge id>, optimized <reforge id> +} + +AskMrRobot.instanceIds = { + HeartOfFear = 1009, + MogushanVaults = 1008, + SiegeOfOrgrimmar = 1136, + TerraceOfEndlessSpring = 996, + ThroneOfThunder = 1098 +} + +-- upgrade id -> upgrade level +local upgradeTable = { + [0] = 0, + [1] = 1, -- 1/1 -> 8 + [373] = 1, -- 1/2 -> 4 + [374] = 2, -- 2/2 -> 8 + [375] = 1, -- 1/3 -> 4 + [376] = 2, -- 2/3 -> 4 + [377] = 3, -- 3/3 -> 4 + [378] = 1, -- 1/1 -> 7 + [379] = 1, -- 1/2 -> 4 + [380] = 2, -- 2/2 -> 4 + [445] = 0, -- 0/2 -> 0 + [446] = 1, -- 1/2 -> 4 + [447] = 2, -- 2/2 -> 8 + [451] = 0, -- 0/1 -> 0 + [452] = 1, -- 1/1 -> 8 + [453] = 0, -- 0/2 -> 0 + [454] = 1, -- 1/2 -> 4 + [455] = 2, -- 2/2 -> 8 + [456] = 0, -- 0/1 -> 0 + [457] = 1, -- 1/1 -> 8 + [458] = 0, -- 0/4 -> 0 + [459] = 1, -- 1/4 -> 4 + [460] = 2, -- 2/4 -> 8 + [461] = 3, -- 3/4 -> 12 + [462] = 4, -- 4/4 -> 16 + [465] = 0, -- 0/2 -> 0 + [466] = 1, -- 1/2 -> 4 + [467] = 2, -- 2/2 -> 8 + [468] = 0, -- 0/4 -> 0 + [469] = 1, -- 1/4 -> 4 + [470] = 2, -- 2/4 -> 8 + [471] = 3, -- 3/4 -> 12 + [472] = 4, -- 4/4 -> 16 + [476] = 0, -- ? -> 0 + [479] = 0, -- ? -> 0 + [491] = 0, -- ? -> 0 + [492] = 1, -- ? -> 0 + [493] = 2, -- ? -> 0 + [494] = 0, + [495] = 1, + [496] = 2, + [497] = 3, + [498] = 4, + [504] = 3, + [505] = 4 +} + +local professionIds = { + ["None"] = 0, + ["Mining"] = 1, + ["Skinning"] = 2, + ["Herbalism"] = 3, + ["Enchanting"] = 4, + ["Jewelcrafting"] = 5, + ["Engineering"] = 6, + ["Blacksmithing"] = 7, + ["Leatherworking"] = 8, + ["Inscription"] = 9, + ["Tailoring"] = 10, + ["Alchemy"] = 11, + ["Fishing"] = 12, + ["Cooking"] = 13, + ["First Aid"] = 14, + ["Archaeology"] = 15 +} + +local raceIds = { + ["None"] = 0, + ["BloodElf"] = 1, + ["Draenei"] = 2, + ["Dwarf"] = 3, + ["Gnome"] = 4, + ["Human"] = 5, + ["NightElf"] = 6, + ["Orc"] = 7, + ["Tauren"] = 8, + ["Troll"] = 9, + ["Scourge"] = 10, + ["Undead"] = 10, + ["Goblin"] = 11, + ["Worgen"] = 12, + ["Pandaren"] = 13 +} + +local factionIds = { + ["None"] = 0, + ["Alliance"] = 1, + ["Horde"] = 2 +} + +local function OnExport() + if (AmrOptions.exportToClient) then + AskMrRobot.SaveAll() + ReloadUI() + else + AskMrRobot_ReforgeFrame:Show() + AskMrRobot_ReforgeFrame:ShowTab("export") + end +end + +function AskMrRobot.eventListener:OnEvent(event, ...) + if event == "ADDON_LOADED" then + local addon = select(1, ...) + if (addon == "AskMrRobot") then + print("Loaded Ask Mr. Robot " .. GetAddOnMetadata(AskMrRobot.AddonName, "Version")) + + -- listen for messages from other AMR addons + RegisterAddonMessagePrefix(AskMrRobot.ChatPrefix) + + AmrRealmName = GetRealmName() + AmrCharacterName = UnitName("player") + + if not AmrLogData then AmrLogData = {} end + if not AmrLogData._autoLog then AmrLogData._autoLog = {} end + if not AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] then + AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] = "disabled" + end + + if not AmrIconInfo then AmrIconInfo = {} end + if not AmrBankItems then AmrBankItems = {} end + if not AmrCurrencies then AmrCurrencies = {} end + if not AmrSpecializations then AmrSpecializations = {} end + if not AmrOptions then AmrOptions = {} end + if not AmrGlyphs then AmrGlyphs = {} end + if not AmrTalents then AmrTalents = {} end + if not AmrBankItemsAndCounts then AmrBankItemsAndCounts = {} end + if not AmrImportString then AmrImportString = "" end + if not AmrImportDate then AmrImportDate = "" end + if not AmrSendSettings then + AmrSendSettings = { + SendGems = true, + SendEnchants = true, + SendEnchantMaterials = true, + SendToType = "a friend", + SendTo = "" + } + end + + amrLDB = LibStub("LibDataBroker-1.1"):NewDataObject("AskMrRobot", { + type = "launcher", + text = "Ask Mr. Robot", + icon = "Interface\\AddOns\\AskMrRobot\\Media\\icon", + OnClick = function() + + if IsModifiedClick("CHATLINK") then + OnExport() + else + AskMrRobot_ReforgeFrame:Toggle() + end + end, + OnTooltipShow = function(tt) + tt:AddLine("Ask Mr. Robot", 1, 1, 1); + tt:AddLine(" "); + tt:AddLine("Left Click to open the Ask Mr. Robot window.\n\nShift + Left Click to export your bag and bank data.") + end + }); + + + AskMrRobot.AmrUpdateMinimap() + + AskMrRobot_ReforgeFrame = AskMrRobot.AmrUI:new() + + -- remember the import settings between sessions + AskMrRobot_ReforgeFrame.summaryTab.importDate = AmrImportDate or "" + AskMrRobot_ReforgeFrame.buttons[2]:Click() + + -- the previous import string is loaded when the UI is first shown, otherwise the game spams events and it lags + end + + elseif event == "ITEM_PUSH" or event == "DELETE_ITEM_CONFIRM" or event == "UNIT_INVENTORY_CHANGED" or event == "SOCKET_INFO_CLOSE" or event == "PLAYER_SPECIALIZATION_CHANGED" or event == "BAG_UPDATE" then + if AskMrRobot_ReforgeFrame then + AskMrRobot_ReforgeFrame:OnUpdate() + end + --AskMrRobot.SaveBags(); + --AskMrRobot.SaveEquiped(); + --AskMrRonot.GetCurrencies(); + --AskMrRobot.GetGold(); + elseif event == "BANKFRAME_OPENED" or event == "PLAYERBANKSLOTS_CHANGED" then + --print("Scanning Bank: " .. event); + AskMrRobot.ScanBank(); + elseif event == "BANKFRAME_CLOSED" then + --print("Stop Scanning Bank"); + --inBank = false; + elseif event == "CHARACTER_POINTS_CHANGED" or event == "CONFIRM_TALENT_WIPE" or event == "PLAYER_TALENT_UPDATE" or event == "ACTIVE_TALENT_GROUP_CHANGED" then + --AskMrRobot.GetAmrSpecializations(); + if AskMrRobot_ReforgeFrame then + AskMrRobot_ReforgeFrame:OnUpdate() + end + elseif event == "PLAYER_LEVEL_UP" then + --GetLevel(); + elseif event == "ITEM_UNLOCKED" then + AskMrRobot.On_ITEM_UNLOCKED() + elseif event == "PLAYER_LOGOUT" then + -- doing nothing right now, but leaving this in case we need something here + elseif event == "ENCOUNTER_START" then + -- send data about this character when a boss fight starts + AskMrRobot.SaveAll() + AskMrRobot.ExportToAddonChat(time()) + elseif event == "CHAT_MSG_ADDON" then + local chatPrefix, message = select(1, ...) + local isLogging = AskMrRobot_ReforgeFrame.combatLogTab:IsLogging() + if (isLogging and chatPrefix == AskMrRobot.ChatPrefix) then + AskMrRobot_ReforgeFrame.combatLogTab:ReadAddonMessage(message) + end + elseif event == "UPDATE_INSTANCE_INFO" or event == "PLAYER_DIFFICULTY_CHANGED" then + AskMrRobot_ReforgeFrame.combatLogTab:UpdateAutoLogging() + end + +end + +AskMrRobot.eventListener:SetScript("OnEvent", AskMrRobot.eventListener.OnEvent); + +local function parseItemLink(input) + local itemId, enchantId, gemEnchantId1, gemEnchantId2, gemEnchantId3, gemEnchantId4, suffixId, _, _, reforgeId, upgradeId = string.match(input, "^|.-|Hitem:(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(-?%d+):(-?%d+):(-?%d+):(%d+):(%d+)|"); + local item = {} + item.itemId = tonumber(itemId) + item.suffixId = tonumber(suffixId) + item.enchantId = tonumber(enchantId) + item.reforgeId = tonumber(reforgeId) + item.upgradeId = tonumber(upgradeId) + item.gemEnchantIds = { tonumber(gemEnchantId1), tonumber(gemEnchantId2), tonumber(gemEnchantId3), tonumber(gemEnchantId4) } + return item +end + +SLASH_AMR1 = "/amr"; +function SlashCmdList.AMR(msg) + + if msg == 'toggle' then + AskMrRobot_ReforgeFrame:Toggle() + elseif msg == 'show' then + AskMrRobot_ReforgeFrame:Show() + elseif msg == 'hide' then + AskMrRobot_ReforgeFrame:Hide() + elseif msg == 'export' then + OnExport() + else + print('Available AskMrRobot slash commands:\n' .. + ' /amr show -- show the main window\n' .. + ' /amr hide -- hide the main window\n' .. + ' /amr toggle -- toggle the main window\n' .. + ' /amr export -- export bag and bank data (uses your last selected method and either opens the copy/paste window, or saves and reloads ui)') + end +end + +function AskMrRobot.SaveAll() + AskMrRobot.ScanBank() + AskMrRobot.SaveBags() + AskMrRobot.SaveEquiped() + AskMrRobot.GetCurrencies() + AskMrRobot.GetGold() + AskMrRobot.GetAmrSpecializations() + AskMrRobot.GetAmrProfessions() + AskMrRobot.GetRace() + AskMrRobot.GetLevel() + AskMrRobot.GetAmrGlyphs() + AskMrRobot.GetAmrTalents() + --ReloadUI() +end + +local function InitIcon() + icon = LibStub("LibDBIcon-1.0"); + icon:Register("AskMrRobot", amrLDB, AmrIconInfo); +end + +function AskMrRobot.AmrUpdateMinimap() + if (AmrOptions.hideMapIcon) then + if (icon) then + icon:Hide("AskMrRobot"); + end + else + if (not icon) then + InitIcon() + end + icon:Show("AskMrRobot"); + end +end + +local function getToolTipText(tip) + return EnumerateTooltipLines_helper(tip:GetRegions()) +end + +local bagItems = {} +local bagItemsWithCount = {} + +function AskMrRobot.ScanBag(bagId) + local numSlots = GetContainerNumSlots(bagId); + for slotId = 1, numSlots do + local _, itemCount, _, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId); + if itemLink ~= nil then + local itemData = parseItemLink(itemLink) + if itemData.itemId ~= nil then + tinsert(bagItems, itemLink); + tinsert(bagItemsWithCount, {link = itemLink, count = itemCount}) + end + end + end +end + +local BACKPACK_CONTAINER = 0; +local BANK_CONTAINER = -1; + +function AskMrRobot.ScanEquiped() + local equipedItems = {}; + for slotNum = 1, #AskMrRobot.slotIds do + local slotId = AskMrRobot.slotIds[slotNum]; + local itemLink = GetInventoryItemLink("player", slotId); + if (itemLink ~= nil) then + equipedItems[slotId .. ""] = itemLink; + end + end + return equipedItems +end + +function AskMrRobot.SaveEquiped() + AmrEquipedItems = AskMrRobot.ScanEquiped(); +end + +function AskMrRobot.ScanBags() + bagItems = {} + bagItemsWithCount = {} + + AskMrRobot.ScanBag(BACKPACK_CONTAINER); -- backpack + + for bagId = 1, NUM_BAG_SLOTS do + AskMrRobot.ScanBag(bagId); + end + + + return bagItems, bagItemsWithCount +end + +function AskMrRobot.SaveBags() + AmrBagItems, _ = AskMrRobot.ScanBags() +end + +function AskMrRobot.GetGold() + AmrGold = GetMoney(); +end + +local lastBankBagId = nil; +local lastBankSlotId = nil; +local bankItems = {}; +local bankItemsAndCount = {}; +AmrBankItemsAndCounts = {}; + +local function ScanBankBag(bagId) + local numSlots = GetContainerNumSlots(bagId); + for slotId = 1, numSlots do + local _, itemCount, _, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId); + if itemLink ~= nil then + local itemData = parseItemLink(itemLink) + if itemData.itemId ~= nil then + lastBankBagId = bagId; + lastBankSlotId = slotId; + tinsert(bankItems, itemLink); + tinsert(bankItemsAndCount, {link = itemLink, count = itemCount}) + end + end + end +end + +function AskMrRobot.ScanBank() + + bankItems = {}; + bankItemsAndCount = {} + + ScanBankBag(BANK_CONTAINER); + for bagId = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do + ScanBankBag(bagId); + end + + -- see if the scan completed before the window closed + if lastBankBagId ~= nil then + local itemLink = GetContainerItemLink(lastBankBagId, lastBankSlotId); + if itemLink ~= nil then --still open + AmrBankItems = bankItems; + AmrBankItemsAndCounts = bankItemsAndCount + end + end +end + +local function GetCurrencyAmount(index) + local localized_label, amount, icon_file_name = GetCurrencyInfo(index); + return amount; +end + +function AskMrRobot.GetCurrencies() + local currencies = {}; + local currencyList = {61, 81, 241, 361, 384, 394, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 416, 515, 614, 615, 676, 679}; + + for i, currency in pairs(currencyList) do + local amount = GetCurrencyAmount(currency); + if amount ~= 0 then + currencies[currencyList[i]] = amount; + end + end + AmrCurrencies = currencies; +end + +local function GetAmrSpecialization(specGroup) + local spec = GetSpecialization(false, false, specGroup); + return spec and GetSpecializationInfo(spec); +end + +function AskMrRobot.GetAmrSpecializations() + + AmrSpecializations = {}; + + AmrActiveSpec = GetActiveSpecGroup(); + + for group = 1, 2 do + AmrSpecializations[group .. ""] = GetAmrSpecialization(group) + end + +-- Death Knight +-- 250 - Blood +-- 251 - Frost +-- 252 - Unholy +-- Druid +-- 102 - Balance +-- 103 - Feral Combat +-- 104 - Guardian +-- 105 - Restoration +-- Hunter +-- 253 - Beast Mastery +-- 254 - Marksmanship +-- 255 - Survival +-- Mage +-- 62 - Arcane +-- 63 - Fire +-- 64 - Frost +-- Monk +-- 268 - Brewmaster +-- 269 - Windwalker +-- 270 - Mistweaver +-- Paladin +-- 65 - Holy +-- 66 - Protection +-- 70 - Retribution +-- Priest +-- 256 Discipline +-- 257 Holy +-- 258 Shadow +-- Rogue +-- 259 - Assassination +-- 260 - Combat +-- 261 - Subtlety +-- Shaman +-- 262 - Elemental +-- 263 - Enhancement +-- 264 - Restoration +-- Warlock +-- 265 - Affliction +-- 266 - Demonology +-- 267 - Destruction +-- Warrior +-- 71 - Arms +-- 72 - Fury +-- 73 - Protection +end + +function AskMrRobot.GetAmrProfessions() + + local profMap = { + [794] = "Archaeology", + [171] = "Alchemy", + [164] = "Blacksmithing", + [185] = "Cooking", + [333] = "Enchanting", + [202] = "Engineering", + [129] = "First Aid", + [356] = "Fishing", + [182] = "Herbalism", + [773] = "Inscription", + [755] = "Jewelcrafting", + [165] = "Leatherworking", + [186] = "Mining", + [393] = "Skinning", + [197] = "Tailoring" + } + + local prof1, prof2, archaeology, fishing, cooking, firstAid = GetProfessions(); + AmrProfessions = {}; + if prof1 then + local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(prof1); + if profMap[skillLine] ~= nil then + AmrProfessions[profMap[skillLine]] = skillLevel; + end + end + if prof2 then + local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(prof2); + if profMap[skillLine] ~= nil then + AmrProfessions[profMap[skillLine]] = skillLevel; + end + end + if archaeology then + local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(archaeology); + if profMap[skillLine] ~= nil then + AmrProfessions[profMap[skillLine]] = skillLevel; + end + end + if fishing then + local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(fishing); + if profMap[skillLine] ~= nil then + AmrProfessions[profMap[skillLine]] = skillLevel; + end + end + if cooking then + local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(cooking); + if profMap[skillLine] ~= nil then + AmrProfessions[profMap[skillLine]] = skillLevel; + end + end + if firstAid then + local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(firstAid); + if profMap[skillLine] ~= nil then + AmrProfessions[profMap[skillLine]] = skillLevel; + end + end +end + +function AskMrRobot.GetRace() + local race, raceEn = UnitRace("player"); + AmrRace = raceEn; + AmrFaction = UnitFactionGroup("player"); +end + +function AskMrRobot.GetLevel() + AmrLevel = UnitLevel("player"); +end + +local SlotNames = { + "HeadSlot", + "NeckSlot", + "ShoulderSlot", + "ShirtSlot", + "ChestSlot", + "WaistSlot", + "LegsSlot", + "FeetSlot", + "WristSlot", + "HandsSlot", + "Finger0Slot", + "Finger1Slot", + "Trinket0Slot", + "Trinket1Slot", + "BackSlot", + "MainHandSlot", + "SecondaryHandSlot", +-- "RangedSlot", + "TabardSlot", +} + +local function GetAmrTalentsForSpec(spec) + local talentInfo = {} + local maxTiers = 6 + for talent = 1, GetNumTalents() do + local name, texture, tier, column, selected, available = GetTalentInfo(talent, false, spec) + if tier > maxTiers then + maxTiers = tier + end + if selected then + talentInfo[tier] = column + end + end + + local str = "" + for i = 1, maxTiers do + if talentInfo[i] then + str = str .. talentInfo[i] + else + str = str .. '0' + end + end + + return str +end + +function AskMrRobot.GetAmrTalents() + AmrTalents = {} + for spec = 1, GetNumSpecGroups() do + AmrTalents[spec] = GetAmrTalentsForSpec(spec); + end +end + +local function GetAmrGlyphsForSpec(spec) + local glyphs = {} + for i = 1, NUM_GLYPH_SLOTS do + local _, _, _, glyphSpellID, _, glyphID = GetGlyphSocketInfo(i, spec) + if (glyphID) then + tinsert(glyphs, glyphSpellID) + end + end + return glyphs; +end + +function AskMrRobot.GetAmrGlyphs() + AmrGlyphs = {} + for spec = 1, GetNumSpecGroups() do + AmrGlyphs[spec] = GetAmrGlyphsForSpec(spec) + end +end + +--[[ +local function ItemLinkToExportString(itemLink, slot) + local itemData = parseItemLink(itemLink) + local ret = {} + table.insert(ret, slot) + table.insert(ret, itemData.itemId) + table.insert(ret, itemData.suffixId) + table.insert(ret, itemData.upgradeId) + table.insert(ret, itemData.gemEnchantIds[1]) + table.insert(ret, itemData.gemEnchantIds[2]) + table.insert(ret, itemData.gemEnchantIds[3]) + table.insert(ret, itemData.enchantId) + table.insert(ret, itemData.reforgeId) + return table.concat(ret, ":") +end +]] + +local function toCompressedNumberList(list) + -- ensure the values are numbers, sorted from lowest to highest + local nums = {} + for i, v in ipairs(list) do + table.insert(nums, tonumber(v)) + end + table.sort(nums) + + local ret = {} + local prev = 0 + for i, v in ipairs(nums) do + local diff = v - prev + table.insert(ret, diff) + prev = v + end + + return table.concat(ret, ",") +end + +-- create a more compact but less readable string +function AskMrRobot.ExportToCompressedString(includeInventory) + local fields = {} + + -- compressed string uses a fixed order rather than inserting identifiers + table.insert(fields, GetAddOnMetadata(AskMrRobot.AddonName, "Version")) + table.insert(fields, AmrRealmName) + table.insert(fields, AmrCharacterName) + + -- guild name + local guildName = GetGuildInfo("player") + if guildName == nil then + table.insert(fields, "") + else + table.insert(fields, guildName) + end + + -- race, default to pandaren if we can't read it for some reason + local raceval = raceIds[AmrRace] + if raceval == nil then raceval = 13 end + table.insert(fields, raceval) + + -- faction, default to alliance if we can't read it for some reason + raceval = factionIds[AmrFaction] + if raceval == nil then raceval = 1 end + table.insert(fields, raceval) + + table.insert(fields, AmrLevel) + + local profs = {} + local noprofs = true + for k, v in pairs(AmrProfessions) do + local profval = professionIds[k] + if profval ~= nil then + noprofs = false + table.insert(profs, profval .. ":" .. v) + end + end + + if noprofs then + table.insert(profs, "0:0") + end + + table.insert(fields, table.concat(profs, ",")) + + if (AmrActiveSpec ~= nil) then + table.insert(fields, AmrActiveSpec) + table.insert(fields, AmrSpecializations[AmrActiveSpec .. ""]) + table.insert(fields, AmrTalents[AmrActiveSpec]) + table.insert(fields, toCompressedNumberList(AmrGlyphs[AmrActiveSpec])) + else + table.insert(fields, "_") + table.insert(fields, "_") + table.insert(fields, "_") + table.insert(fields, "_") + end + + -- convert items to parsed objects, sorted by id + local itemObjects = {} + for k, v in pairs(AmrEquipedItems) do + local itemData = parseItemLink(v) + itemData.slot = k + table.insert(itemObjects, itemData) + end + + -- if desired, include bank/bag items too + if includeInventory then + for i, v in ipairs(AmrBagItems) do + local itemData = parseItemLink(v) + if itemData.itemId ~= nil then + table.insert(itemObjects, itemData) + end + end + for i, v in ipairs(AmrBankItems) do + local itemData = parseItemLink(v) + if itemData.itemId ~= nil then + table.insert(itemObjects, itemData) + end + end + end + + -- sort by item id so we can compress it more easily + table.sort(itemObjects, function(a, b) return a.itemId < b.itemId end) + + -- append to the export string + local prevItemId = 0 + local prevGemId = 0 + local prevEnchantId = 0 + for i, itemData in ipairs(itemObjects) do + + local itemParts = {} + + table.insert(itemParts, itemData.itemId - prevItemId) + prevItemId = itemData.itemId + + if itemData.slot ~= nil then table.insert(itemParts, "s" .. itemData.slot) end + if itemData.suffixId ~= 0 then table.insert(itemParts, "f" .. itemData.suffixId) end + if upgradeTable[itemData.upgradeId] ~= 0 then table.insert(itemParts, "u" .. upgradeTable[itemData.upgradeId]) end + if itemData.gemEnchantIds[1] ~= 0 then + table.insert(itemParts, "a" .. (itemData.gemEnchantIds[1] - prevGemId)) + prevGemId = itemData.gemEnchantIds[1] + end + if itemData.gemEnchantIds[2] ~= 0 then + table.insert(itemParts, "b" .. (itemData.gemEnchantIds[2] - prevGemId)) + prevGemId = itemData.gemEnchantIds[2] + end + if itemData.gemEnchantIds[3] ~= 0 then + table.insert(itemParts, "c" .. (itemData.gemEnchantIds[3] - prevGemId)) + prevGemId = itemData.gemEnchantIds[3] + end + if itemData.enchantId ~= 0 then + table.insert(itemParts, "e" .. (itemData.enchantId - prevEnchantId)) + prevEnchantId = itemData.enchantId + end + if itemData.reforgeId ~= 0 then table.insert(itemParts, "r" .. (itemData.reforgeId - 113)) end + + table.insert(fields, table.concat(itemParts, "")) + end + + return "$" .. table.concat(fields, ";") .. "$" +end + +function AskMrRobot.ExportToAddonChat(timestamp) + local data = AskMrRobot.ExportToCompressedString(false) + local msgPrefix = timestamp .. "\n" .. AmrRealmName .. "\n" .. AmrCharacterName .. "\n" + + -- break the data into 250 character chunks (to deal with the short limit on addon message size) + local chunks = {} + local i = 1 + local length = string.len(data) + local chunkLen = 249 - string.len(msgPrefix) + while (i <= length) do + local endpos = math.min(i + chunkLen, length) + table.insert(chunks, msgPrefix .. string.sub(data, i, endpos)) + i = endpos + 1 + end + + for i, v in ipairs(chunks) do + SendAddonMessage(AskMrRobot.ChatPrefix, v, "RAID") + end + + -- send a completion message + SendAddonMessage(AskMrRobot.ChatPrefix, msgPrefix .. "done", "RAID") +end + +-- Create an export string that can be copied to the website +function AskMrRobot.ExportToString() + + --[[ + local fields = {} + + fields["realm"] = AmrRealmName + fields["name"] = AmrCharacterName + fields["race"] = AmrRace + fields["faction"] = AmrFaction + fields["level"] = AmrLevel + + local profs = {} + for k, v in pairs(AmrProfessions) do + table.insert(profs, k .. ":" .. v) + end + fields["professions"] = table.concat(profs, ",") + + if (AmrActiveSpec ~= nil) then + fields["activespec"] = AmrActiveSpec + fields["spec"] = AmrSpecializations[AmrActiveSpec .. ""] + fields["talents"] = AmrTalents[AmrActiveSpec] + fields["glyphs"] = table.concat(AmrGlyphs[AmrActiveSpec], ",") + end + + local items = {} + for k, v in pairs(AmrEquipedItems) do + table.insert(items, ItemLinkToExportString(v, k)) + end + for i, v in ipairs(AmrBagItems) do + table.insert(items, ItemLinkToExportString(v, "-1")) + end + for i, v in ipairs(AmrBankItems) do + table.insert(items, ItemLinkToExportString(v, "-1")) + end + fields["items"] = table.concat(items, "_") + + local fieldList = {} + for k, v in pairs(fields) do + table.insert(fieldList, k .. "=" .. v) + end + ]] + + --return table.concat(fieldList, ";") + + return AskMrRobot.ExportToCompressedString(true) + --return AskMrRobot.ExportToAddonChat(time()) +end + +local function parseGlyphs(input) + local glyphs = {} + for glyph in string.gmatch(input, "([^,]+)") do + tinsert(glyphs, glyph) + end + table.sort(glyphs) + return glyphs +end + +local function parseProfessions(input) + local professions = {} + for prof, v in string.gmatch(input, "([^:,]+):([^,]+)") do + professions[prof] = tonumber(v); + end + return professions; +end + +local gemColorMapping = { + y = 'Yellow', + b = 'Blue', + r = 'Red', + h = 'Hydraulic', + p = 'Prismatic', + m = 'Meta', + c = 'Cogwheel' +} + +local function parseAmrItem(input) + local slot, itemId, suffixList, upgradeId, gemColorString, gemEnchantIdString, gemIdString, enchantId, reforgeId = string.match(input, "^(%d+):(%d+):([^:]+):([^:]+):([^:]+):([^:]+):([^:]+):(%d+):(%d+)"); + -- parse the gem enchant ids out of their comma seperated list + local gems = {} + for gemEnchantId in string.gmatch(gemEnchantIdString, '(%d+)') do + tinsert(gems, {enchantId = tonumber(gemEnchantId), id = 0}) + end + -- make sure we have 4 gem ids + for i = #gems + 1, 4 do + tinsert(gems, {enchantId = 0, id = 0}) + end + -- parse the gem ids out of their comma seperated list + local gemIds = {} + i = 1 + for gemId in string.gmatch(gemIdString, '(%d+)') do + gems[i].id = tonumber(gemId) + i = i + 1 + end + i = 1 + for gemColor in string.gmatch(gemColorString, '([^,])') do + gems[i].color = gemColorMapping[gemColor] + i = i + 1 + end + + -- parse the possible suffixes out of their comma seperated list and put them in a set (number -> bool) + local suffixes = {} + for suffixId in string.gmatch(suffixList, '(%-?%d+)') do + suffixes[tonumber(suffixId)] = true + end + + local item = { + itemId = tonumber(itemId), + suffixes = suffixes, + upgradeId = tonumber(upgradeId), + gems = gems, + enchantId = tonumber(enchantId), + reforgeId = tonumber(reforgeId) + } + return slot, item +end + + +function AskMrRobot.parseAmr(input) + local parsedInput = {} + parsedInput.items = {} + for k, v in string.gmatch(input, "([^=;]+)=([^;]*)") do + if (k == 'item') then + local slot, item = parseAmrItem(v); + parsedInput.items[AskMrRobot.slotIdToSlotNum[tonumber(slot) + 1]] = item; + elseif (k == 'glyphs') then + parsedInput.glyphs = parseGlyphs(v) + elseif (k == 'professions') then + parsedInput.professions = parseProfessions(v) + else + parsedInput[k]=v + end + end + return parsedInput +end + +function AskMrRobot.validateRealm(realm) + return realm == GetRealmName(); +end + +function AskMrRobot.validateCharacterName(characterName) + return UnitName("player") == characterName +end + +function AskMrRobot.validateRace(race) + local _, raceEn = UnitRace("player") + return raceEn == race or (raceEn == "Scourge" and race == "Undead") +end + +function AskMrRobot.validateFaction(faction) + return faction == UnitFactionGroup("player") +end + +function AskMrRobot.validateSpec(spec) + if spec == 'nil' then + spec = nil + end + local currentSpec = GetAmrSpecialization(GetActiveSpecGroup()) + return (not currentSpec and not spec) or tostring(currentSpec) == spec +end + +function AskMrRobot.validateTalents(talents) + if talents == nil then + talents = '' + end + return talents == GetAmrTalentsForSpec(GetActiveSpecGroup()) +end + +function AskMrRobot.validateGlyphs(glyphs) + if (glyphs == nil) then + glyphs = {}; + end + local currentGlyphs = GetAmrGlyphsForSpec(GetActiveSpecGroup()) + table.sort(glyphs, function(a,b) return tostring(a) < tostring(b) end) + table.sort(currentGlyphs, function(a,b) return tostring(a) < tostring(b) end) + + if #glyphs ~= #currentGlyphs then + return false + end + for i = 1, #glyphs do + if tostring(glyphs[i]) ~= tostring(currentGlyphs[i]) then + return false + end + end + + return true +end + +local function getPrimaryProfessions() + local profs = {} + local prof1, prof2 = GetProfessions() + local profMap = { + [794] = "Archaeology", + [171] = "Alchemy", + [164] = "Blacksmithing", + [185] = "Cooking", + [333] = "Enchanting", + [202] = "Engineering", + [129] = "First Aid", + [356] = "Fishing", + [182] = "Herbalism", + [773] = "Inscription", + [755] = "Jewelcrafting", + [165] = "Leatherworking", + [186] = "Mining", + [393] = "Skinning", + [197] = "Tailoring" + } + + if prof1 then + local _, _, skillLevel, _, _, _, skillLine = GetProfessionInfo(prof1); + if profMap[skillLine] ~= nil then + profs[profMap[skillLine]] = skillLevel + end + end + if prof2 then + local _, _, skillLevel, _, _, _, skillLine = GetProfessionInfo(prof2); + if profMap[skillLine] ~= nil then + profs[profMap[skillLine]] = skillLevel + end + end + return profs; +end + +local professionThresholds = { + Leatherworking = 575, + Inscription = 600, + Alchemy = 50, + Enchanting = 550, + Jewelcrafting = 550, + Blacksmithing = 550, + Tailoring = 550 +} + +function AskMrRobot.validateProfessions(professions) + local currentProfessions = getPrimaryProfessions() + if #currentProfessions ~= #professions then + return false + end + for k, v in pairs(professions) do + if currentProfessions[k] then + local threshold = professionThresholds[k] + if not threshold then + threshold = 1 + end + -- compare the desired profession against the threshold + local desired = v >= threshold + -- compare the current profession against the threshold + local has = currentProfessions[k] and currentProfessions[k] >= threshold + -- if the current value is on the other side of the threshold + -- then we don't match + if desired ~= has then + return false + end + else + return false + end + end + return true +end + +function AskMrRobot.populateItemDiffs(amrItem, itemLink, slotNum) + AskMrRobot.itemDiffs.items[slotNum] = nil + AskMrRobot.itemDiffs.gems[slotNum] = nil + AskMrRobot.itemDiffs.enchants[slotNum] = nil + AskMrRobot.itemDiffs.reforges[slotNum] = nil + + local needsUpgrade = false + local aSuffix = 0 + if amrItem then + for k,v in pairs(amrItem.suffixes) do + aSuffix = k + end + end + + if itemLink == nil then + if amrItem ~= nil then + AskMrRobot.itemDiffs.items[slotNum] = { + current = nil, + optimized = { itemId = amrItem.itemId, upgradeId = amrItem.upgradeId, suffixId = aSuffix }, + needsUpgrade = false + } + end + return + end + local item = parseItemLink(itemLink) + local isItemBad = false + + if amrItem == nil or item.itemId ~= amrItem.itemId then + isItemBad = true + else + if item.suffixId == 0 then + if #amrItem.suffixes > 0 then + isItemBad = true + end + else + if not amrItem.suffixes[item.suffixId] then + isItemBad = true + end + end + if not isItemBad and upgradeTable[item.upgradeId] ~= upgradeTable[amrItem.upgradeId] then + isItemBad = true + needsUpgrade = true + end + end + + if isItemBad then + AskMrRobot.itemDiffs.items[slotNum] = { + current = item.itemId, + optimized = { itemId = amrItem and amrItem.itemId or 0, upgradeId = amrItem and amrItem.upgradeId or 0, suffixId = aSuffix }, + needsUpgrade = needsUpgrade + } + return + end + + local badGemCount, gemInfo = AskMrRobot.MatchesGems(itemLink, item.gemEnchantIds, amrItem.gems) + if badGemCount > 0 then + AskMrRobot.itemDiffs.gems[slotNum] = gemInfo + end + + if item.enchantId ~= amrItem.enchantId then + AskMrRobot.itemDiffs.enchants[slotNum] = { + current = item.enchantId, + optimized = amrItem.enchantId + } + end + + if item.reforgeId ~= amrItem.reforgeId then + AskMrRobot.itemDiffs.reforges[slotNum] = { + current = item.reforgeId, + optimized = amrItem.reforgeId + } + end +end + +--[[ +function AskMrRobot.StartLogging() + if not LoggingCombat() then + LoggingCombat(1) + print("Started Combat Logging") + end +end + +function AskMrRobot.FinishLogging() + if LoggingCombat() then + LoggingCombat(0) + print("Finished Combat Logging") + end +end + +-- local difficultyLookup = { +-- DUNGEON_DIFFICULTY1, +-- DUNGEON_DIFFICULTY2, +-- RAID_DIFFICULTY_10PLAYER, +-- RAID_DIFFICULTY_25PLAYER, +-- RAID_DIFFICULTY_10PLAYER_HEROIC, +-- RAID_DIFFICULTY_25PLAYER_HEROIC, +-- RAID_FINDER, +-- CHALLENGE_MODE, +-- RAID_DIFFICULTY_40PLAYER, +-- nil, +-- nil, -- Norm scen +-- nil, -- heroic scen +-- nil, +-- PLAYER_DIFFICULTY4 +-- } + +--http://wowpedia.org/InstanceMapID +local instanceMaps = { + HeartOfFear = 1009, + MogushanVaults = 1008, + SiegeOfOrgrimmar = 1136, + TerraceOfEndlessSpring = 996, + ThroneOfThunder = 1098 +} + +function AskMrRobot.UpdateLogging() + + -- get the info about the instance + --local zone, zonetype, difficultyIndex, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID = GetInstanceInfo() + local zone, _, difficultyIndex, _, _, _, _, instanceMapID = GetInstanceInfo() + --local difficulty = difficultyIndex + -- Unless Blizzard fixes scenarios to not return nil, let's hardcode this into returning "scenario" -Znuff + --if zonetype == nil and difficultyIndex == 1 then + --zonetype = "scenario" + --end + + -- if nothing has changed, then bail + --if (not zone) and difficulty == 0 then return end + if zone == AskMrRobot.lastzone and difficultyIndex == AskMrRobot.lastdiff then + -- do nothing if the zone hasn't ACTUALLY changed + -- otherwise we may override the user's manual enable/disable + return + end + + AskMrRobot.lastzone = zone + AskMrRobot.lastdiff = difficultyIndex + + if AmrOptions.autoLog[tonumber(instanceMapID)] then + if instanceMapID == instanceMaps.SiegeOfOrgrimmar then + AskMrRobot.StartLogging() + else + AskMrRobot.FinishLogging() + end + end +end +]]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AskMrRobot.toc Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,47 @@ +## Interface: 50400 +## Title: Ask Mr. Robot +## Author: Team Robot, Inc. +## Version: 1.2.12.0 +## Notes: Exports/Imports data to/from askmrrobot.com. +## URL: www.askmrrobot.com +## DefaultState: Enabled +## LoadOnDemand: 0 +## SavedVariablesPerCharacter: AmrBagItems,AmrBankItems,AmrEquipedItems,AmrGold,AmrRealmName,AmrCharacterName,AmrIconInfo,AmrCurrencies,AmrProfessions,AmrSpecializations,AmrRace,AmrLevel,AmrFaction,AmrActiveSpec,AmrOptions,AmrGlyphs,AmrTalents,AmrBankItemsAndCounts,AmrImportString,AmrImportDate,AmrSendSettings,AmrLogData + +#@no-lib-strip@ +Libs\LibStub\Libstub.lua +Libs\CallbackHandler-1.0\CallbackHandler-1.0.lua +#@end-no-lib-strip@ + +Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua + +#@no-lib-strip@ +Libs\LibDBIcon-1.0\LibDBIcon-1.0.lua +#@end-no-lib-strip@ + +wait.lua +sort.lua +enchants.lua +gems.lua +ui\Components.lua +ui\RobotStamp.lua +ui\ItemTooltipFrame.lua +ui\ItemLinkText.lua +ui\ItemIcon.lua +ui\GemIcon.lua +ui\EnchantLinkText.lua +ui\JewelPanel.lua +ui\SummaryTab.lua +ui\GemTab.lua +ui\EnchantTab.lua +ui\HelpTab.lua +ui\ImportTab.lua +ui\ExportTab.lua +ui\ReforgesTab.lua +ui\ShoppingListTab.lua +ui\CombatLogTab.lua +AskMrRobotUi.lua +AskMrRobot.lua +config.lua +AskMrRobot.xml +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AskMrRobot.xml Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,9 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> + <GameTooltip name="MyScanningTooltip" inherits="GameTooltipTemplate"> + <Scripts> + <Onload> + self:SetOwner(WorldFrame, "ANCHOR_NONE"); + </Onload> + </Scripts> + </GameTooltip> +</Ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AskMrRobotUi.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,495 @@ +local _, AskMrRobot = ... + +local showImportDetailsError = nil +local showImportErrorTab = nil + +AskMrRobot.AmrUI = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +function AskMrRobot.AmrUI:swapSimilarSlotsIfNeeded(slotName1, slotName2) + local slotId1 = GetInventorySlotInfo(slotName1) + local slotId2 = GetInventorySlotInfo(slotName2) + local slotNum1 = AskMrRobot.slotIdToSlotNum[slotId1] + local slotNum2 = AskMrRobot.slotIdToSlotNum[slotId2] + + local itemLink1 = GetInventoryItemLink("player", slotId1) + local itemLink2 = GetInventoryItemLink("player", slotId2) + + -- see how bad the items are in the original order + AskMrRobot.populateItemDiffs(self.importedItems[slotNum1], itemLink1, slotNum1) + AskMrRobot.populateItemDiffs(self.importedItems[slotNum2], itemLink2, slotNum2) + + local badCountOriginalOrder = 0 + if AskMrRobot.itemDiffs.items[slotNum1] then badCountOriginalOrder = badCountOriginalOrder + 1 end + if AskMrRobot.itemDiffs.items[slotNum2] then badCountOriginalOrder = badCountOriginalOrder + 1 end + + -- try the order swapped + AskMrRobot.populateItemDiffs(self.importedItems[slotNum1], itemLink2, slotNum1) + AskMrRobot.populateItemDiffs(self.importedItems[slotNum2], itemLink1, slotNum2) + + local badCountNewOrder = 0 + if AskMrRobot.itemDiffs.items[slotNum1] then badCountNewOrder = badCountNewOrder + 1 end + if AskMrRobot.itemDiffs.items[slotNum2] then badCountNewOrder = badCountNewOrder + 1 end + + -- if the items were less bad in the new order, swap the imported items + if badCountNewOrder < badCountOriginalOrder then + local tempItem = self.importedItems[slotNum1] + self.importedItems[slotNum1] = self.importedItems[slotNum2] + self.importedItems[slotNum2] = tempItem + end +end + +function AskMrRobot.AmrUI:displayImportItems() + if not self.importedItems then + return false + end + + --see if rings or trinkets are swapped, and alter self.importedItems accordingly + self:swapSimilarSlotsIfNeeded("Finger0Slot", "Finger1Slot") + self:swapSimilarSlotsIfNeeded("Trinket0Slot", "Trinket1Slot") + + for slotNum = 1, #AskMrRobot.slotIds do + if AskMrRobot.OptimizationSlots[slotNum] then + local slotId = AskMrRobot.slotIds[slotNum] + local itemLink = GetInventoryItemLink("player", slotId) + AskMrRobot.populateItemDiffs(self.importedItems[slotNum], itemLink, slotNum) + end + end + + self.summaryTab:showBadItems() + + -- if there are incorrect items equiped, display errors on other tabs + if AskMrRobot.itemDiffs and AskMrRobot.itemDiffs.items then + for k,v in pairs(AskMrRobot.itemDiffs.items) do + if not v.needsUpgrade then + self.hasImportError = true + end + end + end + + if self.hasImportError then + showImportDetailsError() + else + self.gemTab:Update() + self.enchantTab:showBadEnchants() + self.reforgeTab:Render() + self.shoppingTab:Update() + end +end + +function AskMrRobot.AmrUI:showImportError(text, ...) + self.summaryTab:showImportError(text, ...) + if text then + self.hasImportError = true + showImportDetailsError() + else + self.hasImportError = false + end +end + +function AskMrRobot.AmrUI:showImportWarning(text, ...) + self.summaryTab:showImportWarning(text, ...) + self.hasImportError = false + if text then + showImportDetailsError() + end +end + +function AskMrRobot.AmrUI:validateInput(input) + + self.importedItems = nil + self.mostlySuccess = false + + local parsed = AskMrRobot.parseAmr(input) + + if not parsed.realm then + self:showImportError("Oops, you didn't have proper import text", "Please go back to AskMrRobot.com and grab optimizations for this character") + elseif not AskMrRobot.validateCharacterName(parsed.name) then + self:showImportError("Oops, you've imported optimizations for " .. parsed.name, "Please go back to AskMrRobot.com and grab optimizations for this character, who is much better looking anyway!") + elseif not AskMrRobot.validateRace(parsed.race) then + self:showImportError("It looks like your race may have changed, which affects the optimizations.", "Right now, Mr. Robot thinks you are a " .. parsed.race) + elseif not AskMrRobot.validateFaction(parsed.faction) then + self:showImportError("It looks like your faction may have changed.", "Right now, Mr. Robot thinks you belong to the " .. parsed.faction) + elseif not AskMrRobot.validateProfessions(parsed.professions) then + self:showImportError("Your professions have changed, which affects the optimizations.", "You will need to make sure your in-game professions match the professions on AskMrRobot.com when importing.") + elseif not AskMrRobot.validateSpec(parsed.spec) then + if parsed.spec and parsed.spec ~= 'nil' then + local _, specName = GetSpecializationInfoByID(parsed.spec) + self:showImportError("WARNING! Please check your character before proceeding:", "Change your spec to " .. specName .. ".") + else + self:showImportError("WARNING! Please check your character before proceeding:", "AskMrRobot.com did not expect to see a specialization.") + end + self.mostlySuccess = true + self.summaryTab.badRealm = nil + self.summaryTab.badTalents = nil + self.summaryTab.badGlyphs = nil + AmrImportString = input + else + self.summaryTab.badRealm = not AskMrRobot.validateRealm(parsed.realm) and parsed.realm + self.summaryTab.badTalents = not AskMrRobot.validateTalents(parsed.talents) + self.summaryTab.badGlyphs = not AskMrRobot.validateGlyphs(parsed.glyphs) + self.mostlySuccess = true + self:showImportError(nil) + AmrImportString = input + self.importedItems = parsed.items + return self:displayImportItems() + end + return false +end + +local function createImportDetailsErrorTab(reforgeFrame) + local tab = CreateFrame("Frame", nil, reforgeFrame) + tab:SetPoint("TOPLEFT") + tab:SetPoint("BOTTOMRIGHT") + tab:Hide() + + local text = tab:CreateFontString("AmrImportDetailsText1", "ARTWORK", "GameFontNormalLarge") + text:SetPoint("TOPLEFT", 0, -5) + text:SetText("Help") + + local errorText1 = tab:CreateFontString("AmrImportDetailsText2", "ARTWORK", "GameFontRed") + errorText1:SetPoint("TOPLEFT", "AmrImportDetailsText1", "BOTTOMLEFT", 0, -20) + errorText1:SetText('You have no optimizations imported. Click the "Import" tab to get started.') + errorText1:SetPoint("RIGHT", -10, 0) + errorText1:SetWidth(errorText1:GetWidth()) + errorText1:SetJustifyH("LEFT") + + showImportDetailsError = function() + errorText1:SetText("I can't optimize yet. Please go to the summary tab for more information.") + end + + showImportErrorTab = function(tabName) + if not tabName then + tab:Hide() + else + text:SetText(tabName) + tab:Show() + end + end + + return tab +end + +function AskMrRobot.AmrUI:createTabButtons() + local importTabButton = CreateFrame("Button", "AmrImportTabButton", self, "OptionsListButtonTemplate") + + local buttons = {} + self.hasImportError = true + + local function onTabButtonClick(clickedButton, event, ...) + showImportErrorTab(nil) + for i = 1, #buttons do + local button = buttons[i] + if clickedButton == button then + button.highlight:SetVertexColor(1, 1, 0) + button:LockHighlight() + if self.hasImportError and button.isImportDetails then + showImportErrorTab(button:GetText()) + elseif button.element then + button.element:Show() + end + else + button.highlight:SetVertexColor(.196, .388, .8) + button:UnlockHighlight() + if button.element then + button.element:Hide() + end + end + end + end + + local function createButton(text, spacing, isImportDetails) + local lastButton = #buttons + local i = lastButton + 1 + local tabButton = CreateFrame("Button", "AmrTabButton" .. i, self, "OptionsListButtonTemplate") + tabButton.isImportDetails = isImportDetails + tabButton:SetText(text) + tabText = tabButton:GetFontString() + tabText:SetPoint("LEFT", 6, 0) + if i == 1 then + tabButton:SetPoint("TOPLEFT", 2, spacing) + else + tabButton:SetPoint("TOPLEFT", "AmrTabButton" .. lastButton, "BOTTOMLEFT", 0, spacing) + end + tabButton:SetWidth(125) + tabButton:SetHeight(20) + tinsert(buttons, tabButton) + tabButton:SetScript("OnClick", onTabButtonClick) + end + + createButton("Import", -35, false) + createButton("Summary", -20, false) + createButton("Gems", 0, true) + createButton("Enchants", 0, true) + createButton("Reforges", 0, true) + createButton("Shopping List", 0, true) + createButton("Best in Bags", -20, false) + createButton("Combat Log", 0, false) + createButton("Help", -20, false) + + return buttons +end + +function AskMrRobot.AmrUI:new() + local o = AskMrRobot.Frame:new("AskMrRobot_Dialog", nil, "BasicFrameTemplateWithInset") + + -- use the AmrUI class + setmetatable(o, { __index = AskMrRobot.AmrUI }) + + o:RegisterForDrag("LeftButton"); + o:SetWidth(600) + o:SetHeight(530) + o.InsetBg:SetPoint("TOPLEFT", 125, -24) + + o:SetParent("UIParent") + o:SetPoint("CENTER") + o:Hide() + o:EnableMouse(true) + o:EnableKeyboard(true) + o.hideOnEscape = 1 + o:SetMovable(true) + o:SetToplevel(true) + + --o:SetScript("OnEscapePressed", function) + o:SetScript("OnDragStart", AskMrRobot.AmrUI.OnDragStart) + o:SetScript("OnDragStop", AskMrRobot.AmrUI.OnDragStop) + o:SetScript("OnHide", AskMrRobot.AmrUI.OnHide) + -- make the UI show the first tab when its opened + o:SetScript("OnShow", AskMrRobot.AmrUI.OnShow) + + o:RegisterEvent("AUCTION_HOUSE_CLOSED") + o:RegisterEvent("AUCTION_HOUSE_SHOW") + o:RegisterEvent("FORGE_MASTER_OPENED") + o:RegisterEvent("FORGE_MASTER_CLOSED") + o:RegisterEvent("SOCKET_INFO_UPDATE") + o:RegisterEvent("SOCKET_INFO_CLOSE") + + o:SetScript("OnEvent", function(...) + o:OnEvent(...) + end) + + tinsert(UISpecialFrames, o:GetName()) + + -- title + o.TitleText:SetText("Ask Mr. Robot " .. GetAddOnMetadata(AskMrRobot.AddonName, "Version")) + + -- create the tab buttons + o.buttons = o:createTabButtons() + + local tabArea = AskMrRobot.Frame:new(nil, o) + tabArea:SetPoint("TOPLEFT", 140, -30) + tabArea:SetPoint("BOTTOMRIGHT") + + createImportDetailsErrorTab(tabArea) + + -- create the import tab and associated it with the import tab button + o.importTab = AskMrRobot.ImportTab:new(tabArea) + o.buttons[1].element = o.importTab + o.importTab.scrollFrame.EditBox:SetScript("OnEscapePressed", function() + o:Hide() + end) + + o.importTab.button:SetScript("OnClick", function(...) + o.summaryTab.importDate = date() + AmrImportDate = o.summaryTab.importDate + o:OnUpdate() + if o.mostlySuccess then + -- save import between sessions + AmrImportString = o.importTab.scrollFrame.EditBox:GetText() + AmrImportDate = o.summaryTab.importDate + end + o:ShowTab("summary") + end) + + o.summaryTab = AskMrRobot.SummaryTab:new(tabArea) + o.buttons[2].element = o.summaryTab + + o.gemTab = AskMrRobot.GemTab:new(nil, tabArea) + o.buttons[3].element = o.gemTab + + o.enchantTab = AskMrRobot.EnchantTab:new(tabArea) + o.buttons[4].element = o.enchantTab + + o.reforgeTab = AskMrRobot.ReforgesTab:new(tabArea) + o.buttons[5].element = o.reforgeTab + + o.shoppingTab = AskMrRobot.ShoppingListTab:new(tabArea) + o.buttons[6].element = o.shoppingTab + + o.shoppingTab.sendTo:SetScript("OnEscapePressed", function() + o:Hide() + end) + + o.exportTab = AskMrRobot.ExportTab:new(tabArea) + o.buttons[7].element = o.exportTab + + o.combatLogTab = AskMrRobot.CombatLogTab:new(tabArea) + o.buttons[8].element = o.combatLogTab + + o.helpTab = AskMrRobot.HelpTab:new(tabArea) + o.buttons[9].element = o.helpTab + + o.isSocketWindowVisible = false + o.isReforgeVisible = false + o.isAuctionHouseVisible = false + + --hide the UI + o:Hide() + + o:ShowTab("import") + + o.initialize = false + + return o +end + +function AskMrRobot.AmrUI:OnUpdate() + local input = self.importTab.scrollFrame.EditBox:GetText() + if input and input:len() > 0 then + self:validateInput(input) + end +end + +function AskMrRobot.AmrUI:OnShow() + + if not self.initialized then + -- remember the import settings between sessions + self.importTab.scrollFrame.EditBox:SetText(AmrImportString or "") + self.initialized = true + end + + self:OnUpdate() +end + +function AskMrRobot.AmrUI:OnDragStart() + if not self.isLocked then + self:StartMoving(); + end +end + +function AskMrRobot.AmrUI:OnDragStop() + self:StopMovingOrSizing() +end + +function AskMrRobot.AmrUI:OnHide() + self.visible = false + self:StopMovingOrSizing() +end + +function AskMrRobot.AmrUI:ShowReforgeFrame() + self.visible = true + self:Show() +end + +function AskMrRobot.AmrUI:Toggle() + if self.visible then + self:Hide() + else + self:ShowReforgeFrame() + end +end + +local nameToButtonNumber = { + import = 1, + summary = 2, + gems = 3, + enchants = 4, + reforges = 5, + shopping = 6, + export = 7, + combatLog = 8, + help = 9 +} + +function AskMrRobot.AmrUI:ShowTab(tabName) + local buttonNumber = nameToButtonNumber[tabName] + if buttonNumber then + self.buttons[buttonNumber]:Click() + end +end + +function AskMrRobot.AmrUI:OnEvent(frame, event, ...) + local handler = self["On_" .. event] + if handler then + handler(self, ...) + end +end + +function AskMrRobot.AmrUI:On_AUCTION_HOUSE_SHOW() + self.isAuctionHouseVisible = true + if self.mostlySuccess then + local showTab = self.visible + if not AmrOptions.manualShowShop and not self.visible then + + -- show if there is anything to buy + if self.shoppingTab:HasStuffToBuy() then + self:Show() + showTab = true + end + end + + if showTab then + self:ShowTab("shopping") + end + end +end + +function AskMrRobot.AmrUI:On_AUCTION_HOUSE_CLOSED() + self.isAuctionHouseVisible = false + if self.isReforgeVisible then + self:ShowTab("reforges") + elseif self.isSocketWindowVisible then + self:ShowTab("gems") + end +end + +function AskMrRobot.AmrUI:On_FORGE_MASTER_OPENED() + self.isReforgeVisible = true + if self.mostlySuccess then + local showTab = self.visible + if not AmrOptions.manualShowReforge and not self.visible then + + -- see if there are any reforges to do + local reforgeCount = 0 + for slotNum, badReforge in pairs(AskMrRobot.itemDiffs.reforges) do + reforgeCount = reforgeCount + 1 + end + + if reforgeCount > 0 then + self:Show() + showTab = true + end + end + + if showTab then + self:ShowTab("reforges") + end + end +end + +function AskMrRobot.AmrUI:On_FORGE_MASTER_CLOSED() + self.isReforgeVisible = false + if self.isAuctionHouseVisible then + self:ShowTab("shopping") + elseif self.isSocketWindowVisible then + self:ShowTab("gems") + end +end + +function AskMrRobot.AmrUI:On_SOCKET_INFO_UPDATE() + self.isSocketWindowVisible = true + if self.mostlySuccess then + if not self.visible then + self:Show() + end + self:ShowTab("gems") + end +end + +function AskMrRobot.AmrUI:On_SOCKET_INFO_CLOSE() + self.isSocketWindowVisible = false + if self.isAuctionHouseVisible then + self:ShowTab("shopping") + elseif self.isReforgeVisible then + self:ShowTab("reforges") + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,114 @@ +local addonName, AskMrRobot = ... + +--if not addon.healthCheck then return end +local L = AskMrRobot.L + +local wow_ver = select(4, GetBuildInfo()) +local wow_500 = wow_ver >= 50000 +local UIPanelButtonTemplate = wow_500 and "UIPanelButtonTemplate" or "UIPanelButtonTemplate2" + +local frame = CreateFrame("Frame", nil, InterfaceOptionsFramePanelContainer) +frame.name = addonName +frame:Hide() + +-- Credits to Ace3, Tekkub, cladhaire and Tuller for some of the widget stuff. + +local function newCheckbox(label, tooltipTitle, description, onClick) + local check = CreateFrame("CheckButton", "AmrCheck" .. label, frame, "InterfaceOptionsCheckButtonTemplate") + check:SetScript("OnClick", function(self) + PlaySound(self:GetChecked() and "igMainMenuOptionCheckBoxOn" or "igMainMenuOptionCheckBoxOff") + onClick(self, self:GetChecked() and true or false) + end) + check.label = _G[check:GetName() .. "Text"] + check.label:SetText(label) + check.tooltipText = tooltipTitle + check.tooltipRequirement = description + return check +end + +frame:SetScript("OnShow", function(frame) + local title = frame:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge") + title:SetPoint("TOPLEFT", 16, -16) + title:SetText(addonName) + + local subTitleWrapper = CreateFrame("Frame", nil, frame) + subTitleWrapper:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8) + subTitleWrapper:SetPoint("RIGHT", -16, 0) + local subtitle = subTitleWrapper:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall") + subtitle:SetPoint("TOPLEFT", subTitleWrapper) + subtitle:SetWidth(subTitleWrapper:GetRight() - subTitleWrapper:GetLeft()) + subtitle:SetJustifyH("LEFT") + subtitle:SetNonSpaceWrap(false) + subtitle:SetJustifyV("TOP") + subtitle:SetText("Mr. Robot's addon can export your item information to his website, and import your optimizations into the game.") + subTitleWrapper:SetHeight(subtitle:GetHeight()) + + local autoPopup = newCheckbox( + "Show minimap icon", + "Minimap Icon", + "Show the Ask Mr. Robot minimap icon.", + function(self, value) + if AmrOptions.hideMapIcon then + AmrOptions.hideMapIcon = false + else + AmrOptions.hideMapIcon = true + end + AskMrRobot.AmrUpdateMinimap(); + end + ) + autoPopup:SetChecked(not AmrOptions.hideMapIcon) + autoPopup:SetPoint("TOPLEFT", subTitleWrapper, "BOTTOMLEFT", -2, -16) + + local autoReforge = newCheckbox( + "Automatically show Mr. Robot's reforge window at the reforger", + "Auto-Show Reforges", + "When you have suggested reforges left to complete, automatically show Mr. Robot's reforge window when you visit a reforger.", + function(self, value) + if AmrOptions.manualShowReforge then + AmrOptions.manualShowReforge = false + else + AmrOptions.manualShowReforge = true + end + end + ) + autoReforge:SetChecked(not AmrOptions.manualShowReforge) + autoReforge:SetPoint("TOPLEFT", subTitleWrapper, "BOTTOMLEFT", -2, -52) + + local autoAh = newCheckbox( + "Automatically show Mr. Robot's shopping list at the auction house", + "Auto-Show Shopping List", + "When your shopping list still has things left to buy, automatically show Mr. Robot's shopping list when you visit the auction house.", + function(self, value) + if AmrOptions.manualShowShop then + AmrOptions.manualShowShop = false + else + AmrOptions.manualShowShop = true + end + end + ) + autoAh:SetChecked(not AmrOptions.manualShowShop) + autoAh:SetPoint("TOPLEFT", subTitleWrapper, "BOTTOMLEFT", -2, -88) + + --[[ + AmrOptions.autoLog = AmrOptions.autoLog or {} + + local autoCombatLog = newCheckbox( + "Automatically turn on combat logging for Siege of Orgrimmar", + "Automatically Log Siege of Orgrimmar", + "When entering Siege of Orgrimmar, combat logging will be turned on. When leaving Siege of Orgrimmar, combat logging will be turned off.", + function(self, value) + if AmrOptions.autoLog[1136] then + AmrOptions.autoLog[1136] = false + else + AmrOptions.autoLog[1136] = true + end + end + ) + autoCombatLog:SetChecked(AmrOptions.autoLog[1136]) + autoCombatLog:SetPoint("TOPLEFT", subTitleWrapper, "BOTTOMLEFT", -2, -124) + ]] + + frame:SetScript("OnShow", nil) +end) +InterfaceOptions_AddCategory(frame) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/enchants.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,4247 @@ +local _, AskMrRobot = ... + +local enchantNames = { +[-1000]="Belt Buckle", +[2]="Frostbrand", +[5]="Flametongue", +[13]="Sharpened (+3 Damage)", +[14]="Sharpened (+4 Damage)", +[15]="8 Armor", +[16]="16 Armor", +[17]="24 Armor", +[18]="32 Armor", +[19]="Weighted (+2 Damage)", +[20]="Weighted (+3 Damage)", +[21]="Weighted (+4 Damage)", +[24]="+5 Mana", +[25]="Shadow Oil", +[26]="Frost Oil", +[27]="Sundered", +[28]="+4 All Resistances", +[30]="Scope (+1 Damage)", +[31]="+4 Beastslaying", +[32]="Scope (+2 Damage)", +[33]="Scope (+3 Damage)", +[34]="20 Haste", +[36]="Enchant: Fiery Blaze", +[37]="Steel Weapon Chain", +[38]="5 Dodge", +[39]="Sharpened (+1 Damage)", +[40]="Sharpened (+2 Damage)", +[41]="+5 Health", +[43]="Iron Spike (8-12)", +[44]="Absorption (10)", +[63]="Absorption (25)", +[64]="3 Spirit", +[65]="+1 All Resistances", +[66]="1 Stam", +[67]="+1 Damage", +[68]="1 Str", +[69]="2 Str", +[70]="3 Str", +[71]="1 Stam", +[72]="2 Stam", +[73]="3 Stam", +[74]="1 Agi", +[75]="2 Agi", +[76]="3 Agi", +[77]="+2 Damage", +[78]="+3 Damage", +[79]="1 Int", +[80]="2 Int", +[81]="3 Int", +[82]="1 Spirit", +[83]="2 Spirit", +[84]="3 Spirit", +[85]="3 Armor", +[86]="8 Armor", +[87]="12 Armor", +[89]="16 Armor", +[90]="4 Agi", +[91]="5 Agi", +[92]="6 Agi", +[93]="7 Agi", +[94]="4 Int", +[95]="5 Int", +[96]="6 Int", +[97]="7 Int", +[98]="4 Spirit", +[99]="5 Spirit", +[100]="6 Spirit", +[101]="7 Spirit", +[102]="4 Stam", +[103]="5 Stam", +[104]="6 Stam", +[105]="7 Stam", +[106]="4 Str", +[107]="5 Str", +[108]="6 Str", +[109]="7 Str", +[110]="1 Dodge", +[111]="2 Dodge", +[112]="3 Dodge", +[113]="4 Dodge", +[114]="5 Dodge", +[115]="6 Dodge", +[116]="7 Dodge", +[117]="+4 Damage", +[118]="+5 Damage", +[119]="+6 Damage", +[120]="+7 Damage", +[121]="20 Armor", +[122]="24 Armor", +[123]="28 Armor", +[125]="+1 Sword Skill", +[126]="+2 Sword Skill", +[127]="+3 Sword Skill", +[128]="+4 Sword Skill", +[129]="+5 Sword Skill", +[130]="+6 Sword Skill", +[131]="+7 Sword Skill", +[132]="+1 Two-Handed Sword Skill", +[133]="+2 Two-Handed Sword Skill", +[134]="+3 Two-Handed Sword Skill", +[135]="+4 Two-Handed Sword Skill", +[136]="+5 Two-Handed Sword Skill", +[137]="+6 Two-Handed Sword Skill", +[138]="+7 Two-Handed Sword Skill", +[139]="+1 Mace Skill", +[140]="+2 Mace Skill", +[141]="+3 Mace Skill", +[142]="+4 Mace Skill", +[143]="+5 Mace Skill", +[144]="+6 Mace Skill", +[145]="+7 Mace Skill", +[146]="+1 Two-Handed Mace Skill", +[147]="+2 Two-Handed Mace Skill", +[148]="+3 Two-Handed Mace Skill", +[149]="+4 Two-Handed Mace Skill", +[150]="+5 Two-Handed Mace Skill", +[151]="+6 Two-Handed Mace Skill", +[152]="+7 Two-Handed Mace Skill", +[153]="+1 Axe Skill", +[154]="+2 Axe Skill", +[155]="+3 Axe Skill", +[156]="+4 Axe Skill", +[157]="+5 Axe Skill", +[158]="+6 Ase Skill", +[159]="+7 Axe Skill", +[160]="+1 Two-Handed Axe Skill", +[161]="+2 Two-Handed Axe Skill", +[162]="+3 Two-Handed Axe Skill", +[163]="+4 Two-Handed Axe Skill", +[164]="+5 Two-Handed Axe Skill", +[165]="+6 Two-Handed Axe Skill", +[166]="+7 Two-Handed Axe Skill", +[167]="+1 Dagger Skill", +[168]="+2 Dagger Skill", +[169]="+3 Dagger Skill", +[170]="+4 Dagger Skill", +[171]="+5 Dagger Skill", +[172]="+6 Dagger Skill", +[173]="+7 Dagger Skill", +[174]="+1 Gun Skill", +[175]="+2 Gun Skill", +[176]="+3 Gun Skill", +[177]="+4 Gun Skill", +[178]="+5 Gun Skill", +[179]="+6 Gun Skill", +[180]="+7 Gun Skill", +[181]="+1 Bow Skill", +[182]="+2 Bow Skill", +[183]="+3 Bow Skill", +[184]="+4 Bow Skill", +[185]="+5 Bow Skill", +[186]="+6 Bow Skill", +[187]="+7 Bow Skill", +[188]="+2 Beast Slaying", +[189]="+4 Beast Slaying", +[190]="+6 Beast Slaying", +[191]="+8 Beast Slaying", +[192]="+10 Beast Slaying", +[193]="+12 Beast Slaying", +[194]="+14 Beast Slaying", +[195]="14 Crit", +[196]="28 Crit", +[197]="42 Crit", +[198]="56 Crit", +[199]="10% On Get Hit: Shadow Bolt (10 Damage)", +[200]="10% On Get Hit: Shadow Bolt (20 Damage)", +[201]="10% On Get Hit: Shadow Bolt (30 Damage)", +[202]="10% On Get Hit: Shadow Bolt (40 Damage)", +[203]="10% On Get Hit: Shadow Bolt (50 Damage)", +[204]="10% On Get Hit: Shadow Bolt (60 Damage)", +[205]="10% On Get Hit: Shadow Bolt (70 Damage)", +[206]="1 SP", +[207]="2 SP", +[208]="4 SP", +[209]="5 SP", +[210]="6 SP", +[211]="7 SP", +[212]="8 SP", +[213]="+1 Fire Spell Damage", +[214]="+3 Fire Spell Damage", +[215]="+4 Fire Spell Damage", +[216]="+6 Fire Spell Damage", +[217]="+7 Fire Spell Damage", +[218]="+9 Fire Spell Damage", +[219]="+10 Fire Spell Damage", +[220]="+1 Nature Spell Damage", +[221]="+3 Nature Spell Damage", +[222]="+4 Nature Spell Damage", +[223]="+6 Nature Spell Damage", +[224]="+7 Nature Spell Damage", +[225]="+9 Nature Spell Damage", +[226]="+10 Nature Spell Damage", +[227]="+1 Frost Spell Damage", +[228]="+3 Frost Spell Damage", +[229]="+4 Frost Spell Damage", +[230]="+6 Frost Spell Damage", +[231]="+7 Frost Spell Damage", +[232]="+9 Frost Spell Damage", +[233]="+10 Frost Spell Damage", +[234]="+1 Shadow Spell Damage", +[235]="+3 Shadow Spell Damage", +[236]="+4 Shadow Spell Damage", +[237]="+6 Shadow Spell Damage", +[238]="+7 Shadow Spell Damage", +[239]="+9 Shadow Spell Damage", +[240]="+10 Shadow Spell Damage", +[241]="+2 Weapon Damage", +[242]="+15 Health", +[243]="1 Spirit", +[244]="4 Int", +[245]="5 Armor", +[246]="+20 Mana", +[247]="1 Agi", +[248]="1 Str", +[249]="+2 Beastslaying", +[250]="+1 Weapon Damage", +[251]="1 Int", +[252]="6 Spirit", +[253]="Absorption (50)", +[254]="+25 Health", +[255]="3 Spirit", +[256]="+5 Fire Resistance", +[257]="10 Armor", +[263]="Fishing Lure (+25 Fishing Skill)", +[264]="Fishing Lure (+50 Fishing Skill)", +[265]="Fishing Lure (+75 Fishing Skill)", +[266]="Fishing Lure (+100 Fishing Skill)", +[283]="Windfury", +[286]="+2 Weapon Fire Damage", +[287]="+4 Weapon Fire Damage", +[288]="+6 Weapon Fire Damage", +[289]="+8 Weapon Fire Damage", +[290]="+0 Weapon Fire Damage", +[291]="+12 Weapon Fire Damage", +[292]="+14 Weapon Fire Damage", +[303]="Orb of Fire", +[343]="8 Agi", +[344]="32 Armor", +[345]="40 Armor", +[346]="36 Armor", +[347]="44 Armor", +[348]="48 Armor", +[349]="9 Agi", +[350]="8 Int", +[351]="8 Spirit", +[352]="8 Str", +[353]="8 Stam", +[354]="9 Int", +[355]="9 Spirit", +[356]="9 Stam", +[357]="9 Str", +[358]="10 Agi", +[359]="10 Int", +[360]="10 Spirit", +[361]="10 Stam", +[362]="10 Str", +[363]="11 Agi", +[364]="11 Int", +[365]="11 Spirit", +[366]="11 Stam", +[367]="11 Str", +[368]="12 Agi", +[369]="12 Int", +[370]="12 Spirit", +[371]="12 Stam", +[372]="12 Str", +[383]="52 Armor", +[384]="56 Armor", +[385]="60 Armor", +[386]="16 Armor", +[387]="17 Armor", +[388]="18 Armor", +[389]="19 Armor", +[403]="13 Agi", +[404]="14 Agi", +[405]="13 Int", +[406]="14 Int", +[407]="13 Spirit", +[408]="14 Spirit", +[409]="13 Stam", +[410]="13 Str", +[411]="14 Stam", +[412]="14 Str", +[423]="1 SP", +[424]="2 SP", +[425]="Black Temple Dummy", +[426]="5 SP", +[427]="6 SP", +[428]="7 SP", +[429]="8 SP", +[430]="9 SP", +[431]="11 SP", +[432]="12 SP", +[433]="+11 Fire Spell Damage", +[434]="+13 Fire Spell Damage", +[435]="+14 Fire Spell Damage", +[436]="70 Crit", +[437]="+11 Frost Spell Damage", +[438]="+13 Frost Spell Damage", +[439]="+14 Frost Spell Damage", +[440]="9 SP", +[441]="11 SP", +[442]="12 SP", +[443]="+11 Nature Spell Damage", +[444]="+13 Nature Spell Damage", +[445]="+14 Nature Spell Damage", +[446]="+11 Shadow Spell Damage", +[447]="+13 Shadow Spell Damage", +[448]="+14 Shadow Spell Damage", +[463]="Mithril Spike (16-20)", +[464]="+4% Mount Speed", +[483]="Sharpened (+6 Damage)", +[484]="Weighted (+6 Damage)", +[583]="1 Agi, 1 Spirit", +[584]="1 Agi, 1 Int", +[585]="1 Agi, 1 Stam", +[586]="1 Agi, 1 Str", +[587]="1 Int, 1 Spirit", +[588]="1 Int, 1 Stam", +[589]="1 Int, 1 Str", +[590]="1 Stam, 1 Spirit", +[591]="1 Str, 1 Spirit", +[592]="1 Stam, 1 Str", +[663]="Scope (+5 Damage)", +[664]="Scope (+7 Damage)", +[684]="15 Str", +[723]="3 Int", +[724]="3 Stam", +[743]="+2 Stealth", +[744]="20 Armor", +[763]="+5 Shield Block", +[783]="10 Armor", +[803]="Fiery Weapon", +[804]="+10 Shadow Resistance", +[805]="+4 Weapon Damage", +[823]="3 Str", +[843]="+30 Mana", +[844]="+2 Mining", +[845]="+2 Herbalism", +[846]="+5 Fishing", +[847]="1 Str, 1 Agi, 1 Stam, 1 Int, 1 Spirit", +[848]="30 Armor", +[849]="3 Agi", +[850]="+35 Health", +[851]="5 Spirit", +[852]="5 Stam", +[853]="+6 Beastslaying", +[854]="+6 Elemental Slayer", +[855]="+5 Fire Resistance", +[856]="5 Str", +[857]="+50 Mana", +[863]="10 Parry", +[864]="+4 Weapon Damage", +[865]="+5 Skinning", +[866]="2 Str, 2 Agi, 2 Stam, 2 Int, 2 Spirit", +[883]="15 Agi", +[884]="50 Armor", +[903]="+3 All Resistances", +[904]="5 Agi", +[905]="5 Int", +[906]="+5 Mining", +[907]="7 Spirit", +[908]="+50 Health", +[909]="+5 Herbalism", +[910]="8 Agi, 8 Dodge", +[911]=", Run Speed", +[912]="Demonslaying", +[913]="+65 Mana", +[923]="5 Dodge", +[924]="2 Dodge", +[925]="3 Dodge", +[926]="+8 Frost Resistance", +[927]="7 Str", +[928]="3 Str, 3 Agi, 3 Stam, 3 Int, 3 Spirit", +[929]="7 Stam", +[930]="+2% Mount Speed", +[931]="10 Haste", +[943]="+3 Weapon Damage", +[963]="+7 Weapon Damage", +[983]="16 Agi", +[1003]="Venomhide Poison", +[1043]="16 Str", +[1044]="17 Str", +[1045]="18 Str", +[1046]="19 Str", +[1047]="20 Str", +[1048]="21 Str", +[1049]="22 Str", +[1050]="23 Str", +[1051]="24 Str", +[1052]="25 Str", +[1053]="26 Str", +[1054]="27 Str", +[1055]="28 Str", +[1056]="29 Str", +[1057]="30 Str", +[1058]="31 Str", +[1059]="32 Str", +[1060]="33 Str", +[1061]="34 Str", +[1062]="35 Str", +[1063]="36 Str", +[1064]="37 Str", +[1065]="38 Str", +[1066]="39 Str", +[1067]="40 Str", +[1068]="15 Stam", +[1069]="16 Stam", +[1070]="17 Stam", +[1071]="18 Stam", +[1072]="19 Stam", +[1073]="20 Stam", +[1074]="21 Stam", +[1075]="22 Stam", +[1076]="23 Stam", +[1077]="24 Stam", +[1078]="25 Stam", +[1079]="26 Stam", +[1080]="27 Stam", +[1081]="28 Stam", +[1082]="29 Stam", +[1083]="30 Stam", +[1084]="31 Stam", +[1085]="32 Stam", +[1086]="33 Stam", +[1087]="34 Stam", +[1088]="35 Stam", +[1089]="36 Stam", +[1090]="37 Stam", +[1091]="38 Stam", +[1092]="39 Stam", +[1093]="40 Stam", +[1094]="17 Agi", +[1095]="18 Agi", +[1096]="19 Agi", +[1097]="20 Agi", +[1098]="21 Agi", +[1099]="22 Agi", +[1100]="23 Agi", +[1101]="24 Agi", +[1102]="25 Agi", +[1103]="26 Agi", +[1104]="27 Agi", +[1105]="28 Agi", +[1106]="29 Agi", +[1107]="30 Agi", +[1108]="31 Agi", +[1109]="32 Agi", +[1110]="33 Agi", +[1111]="34 Agi", +[1112]="35 Agi", +[1113]="36 Agi", +[1114]="37 Agi", +[1115]="38 Agi", +[1116]="39 Agi", +[1117]="40 Agi", +[1118]="15 Int", +[1119]="16 Int", +[1120]="17 Int", +[1121]="18 Int", +[1122]="19 Int", +[1123]="20 Int", +[1124]="21 Int", +[1125]="22 Int", +[1126]="23 Int", +[1127]="24 Int", +[1128]="25 Int", +[1129]="26 Int", +[1130]="27 Int", +[1131]="28 Int", +[1132]="29 Int", +[1133]="30 Int", +[1134]="31 Int", +[1135]="32 Int", +[1136]="33 Int", +[1137]="34 Int", +[1138]="35 Int", +[1139]="36 Int", +[1140]="37 Int", +[1141]="38 Int", +[1142]="39 Int", +[1143]="40 Int", +[1144]="15 Spirit", +[1145]="16 Spirit", +[1146]="17 Spirit", +[1147]="18 Spirit", +[1148]="19 Spirit", +[1149]="20 Spirit", +[1150]="21 Spirit", +[1151]="22 Spirit", +[1152]="23 Spirit", +[1153]="24 Spirit", +[1154]="25 Spirit", +[1155]="26 Spirit", +[1156]="27 Spirit", +[1157]="28 Spirit", +[1158]="29 Spirit", +[1159]="30 Spirit", +[1160]="31 Spirit", +[1161]="32 Spirit", +[1162]="33 Spirit", +[1163]="34 Spirit", +[1164]="36 Spirit", +[1165]="37 Spirit", +[1166]="38 Spirit", +[1167]="39 Spirit", +[1168]="40 Spirit", +[1183]="35 Spirit", +[1203]="41 Str", +[1204]="42 Str", +[1205]="43 Str", +[1206]="44 Str", +[1207]="45 Str", +[1208]="46 Str", +[1209]="41 Stam", +[1210]="42 Stam", +[1211]="43 Stam", +[1212]="44 Stam", +[1213]="45 Stam", +[1214]="46 Stam", +[1215]="41 Agi", +[1216]="42 Agi", +[1217]="43 Agi", +[1218]="44 Agi", +[1219]="45 Agi", +[1220]="46 Agi", +[1221]="41 Int", +[1222]="42 Int", +[1223]="43 Int", +[1224]="44 Int", +[1225]="45 Int", +[1226]="46 Int", +[1227]="41 Spirit", +[1228]="42 Spirit", +[1229]="43 Spirit", +[1230]="44 Spirit", +[1231]="45 Spirit", +[1232]="46 Spirit", +[1243]="+1 Arcane Resistance", +[1244]="+2 Arcane Resistance", +[1245]="+3 Arcane Resistance", +[1246]="+4 Arcane Resistance", +[1247]="+5 Arcane Resistance", +[1248]="+6 Arcane Resistance", +[1249]="+7 Arcane Resistance", +[1250]="+8 Arcane Resistance", +[1251]="+9 Arcane Resistance", +[1252]="+10 Arcane Resistance", +[1253]="+11 Arcane Resistance", +[1254]="+12 Arcane Resistance", +[1255]="+13 Arcane Resistance", +[1256]="+14 Arcane Resistance", +[1257]="+15 Arcane Resistance", +[1258]="+16 Arcane Resistance", +[1259]="+17 Arcane Resistance", +[1260]="+18 Arcane Resistance", +[1261]="+19 Arcane Resistance", +[1262]="+20 Arcane Resistance", +[1263]="+21 Arcane Resistance", +[1264]="+22 Arcane Resistance", +[1265]="+23 Arcane Resistance", +[1266]="+24 Arcane Resistance", +[1267]="+25 Arcane Resistance", +[1268]="+26 Arcane Resistance", +[1269]="+27 Arcane Resistance", +[1270]="+28 Arcane Resistance", +[1271]="+29 Arcane Resistance", +[1272]="+30 Arcane Resistance", +[1273]="+31 Arcane Resistance", +[1274]="+32 Arcane Resistance", +[1275]="+33 Arcane Resistance", +[1276]="+34 Arcane Resistance", +[1277]="+35 Arcane Resistance", +[1278]="+36 Arcane Resistance", +[1279]="+37 Arcane Resistance", +[1280]="+38 Arcane Resistance", +[1281]="+39 Arcane Resistance", +[1282]="+40 Arcane Resistance", +[1283]="+41 Arcane Resistance", +[1284]="+42 Arcane Resistance", +[1285]="+43 Arcane Resistance", +[1286]="+44 Arcane Resistance", +[1287]="+45 Arcane Resistance", +[1288]="+46 Arcane Resistance", +[1289]="+1 Frost Resistance", +[1290]="+2 Frost Resistance", +[1291]="+3 Frost Resistance", +[1292]="+4 Frost Resistance", +[1293]="+5 Frost Resistance", +[1294]="+6 Frost Resistance", +[1295]="+7 Frost Resistance", +[1296]="+8 Frost Resistance", +[1297]="+9 Frost Resistance", +[1298]="+10 Frost Resistance", +[1299]="+11 Frost Resistance", +[1300]="+12 Frost Resistance", +[1301]="+13 Frost Resistance", +[1302]="+14 Frost Resistance", +[1303]="+15 Frost Resistance", +[1304]="+16 Frost Resistance", +[1305]="+17 Frost Resistance", +[1306]="+18 Frost Resistance", +[1307]="+19 Frost Resistance", +[1308]="+20 Frost Resistance", +[1309]="+21 Frost Resistance", +[1310]="+22 Frost Resistance", +[1311]="+23 Frost Resistance", +[1312]="+24 Frost Resistance", +[1313]="+25 Frost Resistance", +[1314]="+26 Frost Resistance", +[1315]="+27 Frost Resistance", +[1316]="+28 Frost Resistance", +[1317]="+29 Frost Resistance", +[1318]="+30 Frost Resistance", +[1319]="+31 Frost Resistance", +[1320]="+32 Frost Resistance", +[1321]="+33 Frost Resistance", +[1322]="+34 Frost Resistance", +[1323]="+35 Frost Resistance", +[1324]="+36 Frost Resistance", +[1325]="+37 Frost Resistance", +[1326]="+38 Frost Resistance", +[1327]="+39 Frost Resistance", +[1328]="+40 Frost Resistance", +[1329]="+41 Frost Resistance", +[1330]="+42 Frost Resistance", +[1331]="+43 Frost Resistance", +[1332]="+44 Frost Resistance", +[1333]="+45 Frost Resistance", +[1334]="+46 Frost Resistance", +[1335]="+1 Fire Resistance", +[1336]="+2 Fire Resistance", +[1337]="+3 Fire Resistance", +[1338]="+4 Fire Resistance", +[1339]="+5 Fire Resistance", +[1340]="+6 Fire Resistance", +[1341]="+7 Fire Resistance", +[1342]="+8 Fire Resistance", +[1343]="+9 Fire Resistance", +[1344]="+10 Fire Resistance", +[1345]="+11 Fire Resistance", +[1346]="+12 Fire Resistance", +[1347]="+13 Fire Resistance", +[1348]="+14 Fire Resistance", +[1349]="+15 Fire Resistance", +[1350]="+16 Fire Resistance", +[1351]="+17 Fire Resistance", +[1352]="+18 Fire Resistance", +[1353]="+19 Fire Resistance", +[1354]="+20 Fire Resistance", +[1355]="+21 Fire Resistance", +[1356]="+22 Fire Resistance", +[1357]="+23 Fire Resistance", +[1358]="+24 Fire Resistance", +[1359]="+25 Fire Resistance", +[1360]="+26 Fire Resistance", +[1361]="+27 Fire Resistance", +[1362]="+28 Fire Resistance", +[1363]="+29 Fire Resistance", +[1364]="+30 Fire Resistance", +[1365]="+31 Fire Resistance", +[1366]="+32 Fire Resistance", +[1367]="+33 Fire Resistance", +[1368]="+34 Fire Resistance", +[1369]="+35 Fire Resistance", +[1370]="+36 Fire Resistance", +[1371]="+37 Fire Resistance", +[1372]="+38 Fire Resistance", +[1373]="+39 Fire Resistance", +[1374]="+40 Fire Resistance", +[1375]="+41 Fire Resistance", +[1376]="+42 Fire Resistance", +[1377]="+43 Fire Resistance", +[1378]="+44 Fire Resistance", +[1379]="+45 Fire Resistance", +[1380]="+46 Fire Resistance", +[1381]="+1 Nature Resistance", +[1382]="+2 Nature Resistance", +[1383]="+3 Nature Resistance", +[1384]="+4 Nature Resistance", +[1385]="+5 Nature Resistance", +[1386]="+6 Nature Resistance", +[1387]="+7 Nature Resistance", +[1388]="+8 Nature Resistance", +[1389]="+9 Nature Resistance", +[1390]="+10 Nature Resistance", +[1391]="+11 Nature Resistance", +[1392]="+12 Nature Resistance", +[1393]="+13 Nature Resistance", +[1394]="+14 Nature Resistance", +[1395]="+15 Nature Resistance", +[1396]="+16 Nature Resistance", +[1397]="+17 Nature Resistance", +[1398]="+18 Nature Resistance", +[1399]="+19 Nature Resistance", +[1400]="+20 Nature Resistance", +[1401]="+21 Nature Resistance", +[1402]="+22 Nature Resistance", +[1403]="+23 Nature Resistance", +[1404]="+24 Nature Resistance", +[1405]="+25 Nature Resistance", +[1406]="+26 Nature Resistance", +[1407]="+27 Nature Resistance", +[1408]="+28 Nature Resistance", +[1409]="+29 Nature Resistance", +[1410]="+30 Nature Resistance", +[1411]="+31 Nature Resistance", +[1412]="+32 Nature Resistance", +[1413]="+33 Nature Resistance", +[1414]="+34 Nature Resistance", +[1415]="+35 Nature Resistance", +[1416]="+36 Nature Resistance", +[1417]="+37 Nature Resistance", +[1418]="+38 Nature Resistance", +[1419]="+39 Nature Resistance", +[1420]="+40 Nature Resistance", +[1421]="+41 Nature Resistance", +[1422]="+42 Nature Resistance", +[1423]="+43 Nature Resistance", +[1424]="+44 Nature Resistance", +[1425]="+45 Nature Resistance", +[1426]="+46 Nature Resistance", +[1427]="+1 Shadow Resistance", +[1428]="+2 Shadow Resistance", +[1429]="+3 Shadow Resistance", +[1430]="+4 Shadow Resistance", +[1431]="+5 Shadow Resistance", +[1432]="+6 Shadow Resistance", +[1433]="+7 Shadow Resistance", +[1434]="+8 Shadow Resistance", +[1435]="+9 Shadow Resistance", +[1436]="+10 Shadow Resistance", +[1437]="+11 Shadow Resistance", +[1438]="+12 Shadow Resistance", +[1439]="+13 Shadow Resistance", +[1440]="+14 Shadow Resistance", +[1441]="+15 Shadow Resistance", +[1442]="+16 Shadow Resistance", +[1443]="+17 Shadow Resistance", +[1444]="+18 Shadow Resistance", +[1445]="+19 Shadow Resistance", +[1446]="+20 Shadow Resistance", +[1447]="+21 Shadow Resistance", +[1448]="+22 Shadow Resistance", +[1449]="+23 Shadow Resistance", +[1450]="+24 Shadow Resistance", +[1451]="+25 Shadow Resistance", +[1452]="+26 Resist Shadow", +[1453]="+27 Shadow Resistance", +[1454]="+28 Shadow Resistance", +[1455]="+29 Shadow Resistance", +[1456]="+30 Shadow Resistance", +[1457]="+31 Shadow Resistance", +[1458]="+32 Shadow Resistance", +[1459]="+33 Shadow Resistance", +[1460]="+34 Shadow Resistance", +[1461]="+35 Shadow Resistance", +[1462]="+36 Shadow Resistance", +[1463]="+37 Shadow Resistance", +[1464]="+38 Shadow Resistance", +[1465]="+39 Shadow Resistance", +[1466]="+40 Shadow Resistance", +[1467]="+41 Shadow Resistance", +[1468]="+42 Shadow Resistance", +[1469]="+43 Shadow Resistance", +[1470]="+44 Shadow Resistance", +[1471]="+45 Shadow Resistance", +[1472]="+46 Shadow Resistance", +[1483]="+150 Mana", +[1503]="+100 Health", +[1504]="125 Armor", +[1505]="+20 Fire Resistance", +[1506]="8 Str", +[1507]="8 Stam", +[1508]="8 Agi", +[1509]="8 Int", +[1510]="8 Spirit", +[1523]="+85 Mana and +14 Fire Resistance", +[1524]="+75 Health and +14 Fire Resistance", +[1525]="110 Armor", +[1526]="10 Str", +[1527]="10 Stam", +[1528]="10 Agi", +[1529]="10 Int", +[1530]="10 Spirit", +[1531]="10 Str, 10 Stam", +[1532]="15 Str", +[1543]="15 Int", +[1563]="2 AP", +[1583]="4 AP", +[1584]="6 AP", +[1585]="8 AP", +[1586]="10 AP", +[1587]="12 AP", +[1588]="14 AP", +[1589]="16 AP", +[1590]="18 AP", +[1591]="20 AP", +[1592]="22 AP", +[1593]="24 AP", +[1594]="26 AP", +[1595]="28 AP", +[1596]="30 AP", +[1597]="32 AP", +[1598]="34 AP", +[1599]="36 AP", +[1600]="38 AP", +[1601]="32 AP", +[1602]="42 AP", +[1603]="44 AP", +[1604]="46 AP", +[1605]="48 AP", +[1606]="50 AP", +[1607]="52 AP", +[1608]="54 AP", +[1609]="56 AP", +[1610]="58 AP", +[1611]="60 AP", +[1612]="62 AP", +[1613]="64 AP", +[1614]="66 AP", +[1615]="68 AP", +[1616]="70 AP", +[1617]="72 AP", +[1618]="74 AP", +[1619]="76 AP", +[1620]="78 AP", +[1621]="80 AP", +[1622]="82 AP", +[1623]="84 AP", +[1624]="86 AP", +[1625]="88 AP", +[1626]="90 AP", +[1627]="92 AP", +[1643]="Sharpened (+8 Damage)", +[1703]="Weighted (+8 Damage)", +[1704]="Thorium Spike (20-30)", +[1723]="Omen of Clarity", +[1743]="MHTest02", +[1763]="Cold Blood", +[1803]="Firestone 1", +[1823]="Firestone 2", +[1824]="Firestone 3", +[1825]="Firestone 4", +[1843]="40 Armor", +[1883]="7 Int", +[1884]="9 Spirit", +[1885]="9 Str", +[1886]="9 Stam", +[1887]="7 Agi", +[1888]="+5 All Resistances", +[1889]="70 Armor", +[1890]="10 Stam, 10 Spirit", +[1891]="4 Str, 4 Agi, 4 Stam, 4 Int, 4 Spirit", +[1892]="+100 Health", +[1893]="+100 Mana", +[1894]="Icy Chill", +[1895]="+9 Damage", +[1896]="+9 Weapon Damage", +[1897]="+5 Weapon Damage", +[1898]="Lifestealing", +[1899]="Unholy Weapon", +[1900]="Crusader", +[1901]="9 Int", +[1903]="9 Spirit", +[1904]="9 Int", +[1923]="+3 Fire Resistance", +[1943]="12 Dodge", +[1944]="8 Dodge", +[1945]="9 Dodge", +[1946]="10 Dodge", +[1947]="11 Dodge", +[1948]="13 Dodge", +[1949]="14 Dodge", +[1950]="15 Dodge", +[1951]="18 Dodge", +[1952]="20 Dodge", +[1953]="22 Dodge", +[1954]="25 Dodge", +[1955]="32 Dodge", +[1956]="17 Dodge", +[1957]="18 Dodge", +[1958]="19 Dodge", +[1959]="21 Dodge", +[1960]="23 Dodge", +[1961]="24 Dodge", +[1962]="26 Dodge", +[1963]="27 Dodge", +[1964]="28 Dodge", +[1965]="29 Dodge", +[1966]="30 Dodge", +[1967]="31 Dodge", +[1968]="33 Dodge", +[1969]="34 Dodge", +[1970]="35 Dodge", +[1971]="36 Dodge", +[1972]="37 Dodge", +[1973]="38 Dodge", +[1983]="+5 Block", +[1984]="+10 Block", +[1985]="+15 Block", +[1986]="+20 Block", +[1987]="Block Level 14", +[1988]="Block Level 15", +[1989]="Block Level 16", +[1990]="Block Level 17", +[1991]="Block Level 18", +[1992]="Block Level 19", +[1993]="Block Level 20", +[1994]="Block Level 21", +[1995]="Block Level 22", +[1996]="Block Level 23", +[1997]="Block Level 24", +[1998]="Block Level 25", +[1999]="Block Level 26", +[2000]="Block Level 27", +[2001]="Block Level 28", +[2002]="Block Level 29", +[2003]="Block Level 30", +[2004]="Block Level 31", +[2005]="Block Level 32", +[2006]="Block Level 33", +[2007]="Block Level 34", +[2008]="Block Level 35", +[2009]="Block Level 36", +[2010]="Block Level 37", +[2011]="Block Level 38", +[2012]="Block Level 39", +[2013]="Block Level 40", +[2014]="Block Level 41", +[2015]="Block Level 42", +[2016]="Block Level 43", +[2017]="Block Level 44", +[2018]="Block Level 45", +[2019]="Block Level 46", +[2020]="Block Level 47", +[2021]="Block Level 48", +[2022]="Block Level 49", +[2023]="Block Level 50", +[2024]="Block Level 51", +[2025]="Block Level 52", +[2026]="Block Level 53", +[2027]="Block Level 54", +[2028]="Block Level 55", +[2029]="Block Level 56", +[2030]="Block Level 57", +[2031]="Block Level 58", +[2032]="Block Level 59", +[2033]="Block Level 60", +[2034]="Block Level 61", +[2035]="Block Level 62", +[2036]="Block Level 63", +[2037]="Block Level 64", +[2038]="Block Level 65", +[2039]="Block Level 66", +[2040]="+2 Ranged Attack Power", +[2041]="+5 Ranged Attack Power", +[2042]="+7 Ranged Attack Power", +[2043]="+10 Ranged Attack Power", +[2044]="+12 Ranged Attack Power", +[2045]="+14 Ranged Attack Power", +[2046]="+17 Ranged Attack Power", +[2047]="+19 Ranged Attack Power", +[2048]="+22 Ranged Attack Power", +[2049]="+24 Ranged Attack Power", +[2050]="+26 Ranged Attack Power", +[2051]="+29 Ranged Attack Power", +[2052]="+31 Ranged Attack Power", +[2053]="+34 Ranged Attack Power", +[2054]="+36 Ranged Attack Power", +[2055]="+38 Ranged Attack Power", +[2056]="+41 Ranged Attack Power", +[2057]="+43 Ranged Attack Power", +[2058]="+46 Ranged Attack Power", +[2059]="+48 Ranged Attack Power", +[2060]="+50 Ranged Attack Power", +[2061]="+53 Ranged Attack Power", +[2062]="+55 Ranged Attack Power", +[2063]="+58 Ranged Attack Power", +[2064]="+60 Ranged Attack Power", +[2065]="+62 Ranged Attack Power", +[2066]="+65 Ranged Attack Power", +[2067]="+67 Ranged Attack Power", +[2068]="+70 Ranged Attack Power", +[2069]="+72 Ranged Attack Power", +[2070]="+74 Ranged Attack Power", +[2071]="+77 Ranged Attack Power", +[2072]="+79 Ranged Attack Power", +[2073]="+82 Ranged Attack Power", +[2074]="+84 Ranged Attack Power", +[2075]="+86 Ranged Attack Power", +[2076]="+89 Ranged Attack Power", +[2077]="+91 Ranged Attack Power", +[2078]="12 Dodge", +[2079]="+1 Arcane Spell Damage", +[2080]="+3 Arcane Spell Damage", +[2081]="+4 Arcane Spell Damage", +[2082]="+6 Arcane Spell Damage", +[2083]="+7 Arcane Spell Damage", +[2084]="+9 Arcane Spell Damage", +[2085]="+10 Arcane Spell Damage", +[2086]="+11 Arcane Spell Damage", +[2087]="+13 Arcane Spell Damage", +[2088]="+14 Arcane Spell Damage", +[2089]="+16 Arcane Spell Damage", +[2090]="+17 Arcane Spell Damage", +[2091]="+19 Arcane Spell Damage", +[2092]="+20 Arcane Spell Damage", +[2093]="+21 Arcane Spell Damage", +[2094]="+23 Arcane Spell Damage", +[2095]="+24 Arcane Spell Damage", +[2096]="+26 Arcane Spell Damage", +[2097]="+27 Arcane Spell Damage", +[2098]="+29 Arcane Spell Damage", +[2099]="+30 Arcane Spell Damage", +[2100]="+31 Arcane Spell Damage", +[2101]="+33 Arcane Spell Damage", +[2102]="+34 Arcane Spell Damage", +[2103]="+36 Arcane Spell Damage", +[2104]="+37 Arcane Spell Damage", +[2105]="+39 Arcane Spell Damage", +[2106]="+40 Arcane Spell Damage", +[2107]="+41 Arcane Spell Damage", +[2108]="+43 Arcane Spell Damage", +[2109]="+44 Arcane Spell Damage", +[2110]="+46 Arcane Spell Damage", +[2111]="+47 Arcane Spell Damage", +[2112]="+49 Arcane Spell Damage", +[2113]="+50 Arcane Spell Damage", +[2114]="+51 Arcane Spell Damage", +[2115]="+53 Arcane Spell Damage", +[2116]="+54 Arcane Spell Damage", +[2117]="+1 Shadow Spell Damage", +[2118]="+3 Shadow Spell Damage", +[2119]="+4 Shadow Spell Damage", +[2120]="+6 Shadow Spell Damage", +[2121]="+7 Shadow Spell Damage", +[2122]="+9 Shadow Spell Damage", +[2123]="+10 Shadow Spell Damage", +[2124]="+11 Shadow Spell Damage", +[2125]="+13 Shadow Spell Damage", +[2126]="+14 Shadow Spell Damage", +[2127]="+16 Shadow Spell Damage", +[2128]="+17 Shadow Spell Damage", +[2129]="+19 Shadow Spell Damage", +[2130]="+20 Shadow Spell Damage", +[2131]="+21 Shadow Spell Damage", +[2132]="+23 Shadow Spell Damage", +[2133]="+24 Shadow Spell Damage", +[2134]="+26 Shadow Spell Damage", +[2135]="+27 Shadow Spell Damage", +[2136]="+29 Shadow Spell Damage", +[2137]="+30 Shadow Spell Damage", +[2138]="+31 Shadow Spell Damage", +[2139]="+33 Shadow Spell Damage", +[2140]="+34 Shadow Spell Damage", +[2141]="+36 Shadow Spell Damage", +[2142]="+37 Shadow Spell Damage", +[2143]="+39 Shadow Spell Damage", +[2144]="+40 Shadow Spell Damage", +[2145]="+41 Shadow Spell Damage", +[2146]="+43 Shadow Spell Damage", +[2147]="+44 Shadow Spell Damage", +[2148]="+46 Shadow Spell Damage", +[2149]="+47 Shadow Spell Damage", +[2150]="+49 Shadow Spell Damage", +[2151]="+50 Shadow Spell Damage", +[2152]="+51 Shadow Spell Damage", +[2153]="+53 Shadow Spell Damage", +[2154]="+54 Shadow Spell Damage", +[2155]="+1 Fire Spell Damage", +[2156]="+3 Fire Spell Damage", +[2157]="+4 Fire Spell Damage", +[2158]="+6 Fire Spell Damage", +[2159]="+7 Fire Spell Damage", +[2160]="+9 Fire Spell Damage", +[2161]="+10 Fire Spell Damage", +[2162]="+11 Fire Spell Damage", +[2163]="+13 Fire Spell Damage", +[2164]="+14 Fire Spell Damage", +[2165]="+16 Fire Spell Damage", +[2166]="+17 Fire Spell Damage", +[2167]="+19 Fire Spell Damage", +[2168]="+20 Fire Spell Damage", +[2169]="+21 Fire Spell Damage", +[2170]="+23 Fire Spell Damage", +[2171]="+24 Fire Spell Damage", +[2172]="+26 Fire Spell Damage", +[2173]="+27 Fire Spell Damage", +[2174]="+29 Fire Spell Damage", +[2175]="+30 Fire Spell Damage", +[2176]="+31 Fire Spell Damage", +[2177]="+33 Fire Spell Damage", +[2178]="+34 Fire Spell Damage", +[2179]="+36 Fire Spell Damage", +[2180]="+37 Fire Spell Damage", +[2181]="+39 Fire Spell Damage", +[2182]="+40 Fire Spell Damage", +[2183]="+41 Fire Spell Damage", +[2184]="+43 Fire Spell Damage", +[2185]="+44 Fire Spell Damage", +[2186]="+46 Fire Spell Damage", +[2187]="+47 Fire Spell Damage", +[2188]="+49 Fire Spell Damage", +[2189]="+50 Fire Spell Damage", +[2190]="+51 Fire Spell Damage", +[2191]="+53 Fire Spell Damage", +[2192]="+54 Fire Spell Damage", +[2193]="+1 Holy Spell Damage", +[2194]="+3 Holy Spell Damage", +[2195]="+4 Holy Spell Damage", +[2196]="+6 Holy Spell Damage", +[2197]="+7 Holy Spell Damage", +[2198]="+9 Holy Spell Damage", +[2199]="+10 Holy Spell Damage", +[2200]="+11 Holy Spell Damage", +[2201]="+13 Holy Spell Damage", +[2202]="+14 Holy Spell Damage", +[2203]="+16 Holy Spell Damage", +[2204]="+17 Holy Spell Damage", +[2205]="+19 Holy Spell Damage", +[2206]="+20 Holy Spell Damage", +[2207]="+21 Holy Spell Damage", +[2208]="+23 Holy Spell Damage", +[2209]="+24 Holy Spell Damage", +[2210]="+26 Holy Spell Damage", +[2211]="+27 Holy Spell Damage", +[2212]="+29 Holy Spell Damage", +[2213]="+30 Holy Spell Damage", +[2214]="+31 Holy Spell Damage", +[2215]="+33 Holy Spell Damage", +[2216]="+34 Holy Spell Damage", +[2217]="+36 Holy Spell Damage", +[2218]="+37 Holy Spell Damage", +[2219]="+39 Holy Spell Damage", +[2220]="+40 Holy Spell Damage", +[2221]="+41 Holy Spell Damage", +[2222]="+43 Holy Spell Damage", +[2223]="+44 Holy Spell Damage", +[2224]="+46 Holy Spell Damage", +[2225]="+47 Holy Spell Damage", +[2226]="+49 Holy Spell Damage", +[2227]="+50 Holy Spell Damage", +[2228]="+51 Holy Spell Damage", +[2229]="+53 Holy Spell Damage", +[2230]="+54 Holy Spell Damage", +[2231]="+1 Frost Spell Damage", +[2232]="+3 Frost Spell Damage", +[2233]="+4 Frost Spell Damage", +[2234]="+6 Frost Spell Damage", +[2235]="+7 Frost Spell Damage", +[2236]="+9 Frost Spell Damage", +[2237]="+10 Frost Spell Damage", +[2238]="+11 Frost Spell Damage", +[2239]="+13 Frost Spell Damage", +[2240]="+14 Frost Spell Damage", +[2241]="+16 Frost Spell Damage", +[2242]="+17 Frost Spell Damage", +[2243]="+19 Frost Spell Damage", +[2244]="+20 Frost Spell Damage", +[2245]="+21 Frost Spell Damage", +[2246]="+23 Frost Spell Damage", +[2247]="+24 Frost Spell Damage", +[2248]="+26 Frost Spell Damage", +[2249]="+27 Frost Spell Damage", +[2250]="+29 Frost Spell Damage", +[2251]="+30 Frost Spell Damage", +[2252]="+31 Frost Spell Damage", +[2253]="+33 Frost Spell Damage", +[2254]="+34 Frost Spell Damage", +[2255]="+36 Frost Spell Damage", +[2256]="+37 Frost Spell Damage", +[2257]="+39 Frost Spell Damage", +[2258]="+40 Frost Spell Damage", +[2259]="+41 Frost Spell Damage", +[2260]="+43 Frost Spell Damage", +[2261]="+44 Frost Spell Damage", +[2262]="+46 Frost Spell Damage", +[2263]="+47 Frost Spell Damage", +[2264]="+49 Frost Spell Damage", +[2265]="+50 Frost Spell Damage", +[2266]="+51 Frost Spell Damage", +[2267]="+53 Frost Spell Damage", +[2268]="+54 Frost Spell Damage", +[2269]="+1 Nature Spell Damage", +[2270]="+3 Nature Spell Damage", +[2271]="+4 Nature Spell Damage", +[2272]="+6 Nature Spell Damage", +[2273]="+7 Nature Spell Damage", +[2274]="+9 Nature Spell Damage", +[2275]="+10 Nature Spell Damage", +[2276]="+11 Nature Spell Damage", +[2277]="+13 Nature Spell Damage", +[2278]="+14 Nature Spell Damage", +[2279]="+16 Nature Spell Damage", +[2280]="+17 Nature Spell Damage", +[2281]="+19 Nature Spell Damage", +[2282]="+20 Nature Spell Damage", +[2283]="+21 Nature Spell Damage", +[2284]="+23 Nature Spell Damage", +[2285]="+24 Nature Spell Damage", +[2286]="+26 Nature Spell Damage", +[2287]="+27 Nature Spell Damage", +[2288]="+29 Nature Spell Damage", +[2289]="+30 Nature Spell Damage", +[2290]="+31 Nature Spell Damage", +[2291]="+33 Nature Spell Damage", +[2292]="+34 Nature Spell Damage", +[2293]="+36 Nature Spell Damage", +[2294]="+37 Nature Spell Damage", +[2295]="+39 Nature Spell Damage", +[2296]="+40 Nature Spell Damage", +[2297]="+41 Nature Spell Damage", +[2298]="+43 Nature Spell Damage", +[2299]="+44 Nature Spell Damage", +[2300]="+46 Nature Spell Damage", +[2301]="+47 Nature Spell Damage", +[2302]="+49 Nature Spell Damage", +[2303]="+50 Nature Spell Damage", +[2304]="+51 Nature Spell Damage", +[2305]="+53 Nature Spell Damage", +[2306]="+54 Nature Spell Damage", +[2307]="1 SP", +[2308]="2 SP", +[2309]="4 SP", +[2310]="5 SP", +[2311]="6 SP", +[2312]="7 SP", +[2313]="8 SP", +[2314]="9 SP", +[2315]="11 SP", +[2316]="12 SP", +[2317]="13 SP", +[2318]="14 SP", +[2319]="15 SP", +[2320]="16 SP", +[2321]="18 SP", +[2322]="19 SP", +[2323]="20 SP", +[2324]="21 SP", +[2325]="22 SP", +[2326]="23 SP", +[2327]="25 SP", +[2328]="26 SP", +[2329]="27 SP", +[2330]="28 SP", +[2331]="29 SP", +[2332]="30 SP", +[2333]="32 SP", +[2334]="33 SP", +[2335]="34 SP", +[2336]="35 SP", +[2337]="36 SP", +[2338]="37 SP", +[2339]="39 SP", +[2340]="40 SP", +[2341]="41 SP", +[2342]="42 SP", +[2343]="43 SP", +[2344]="44 SP", +[2363]="+1 mana every 5 sec.", +[2364]="+1 mana every 5 sec.", +[2365]="+1 mana every 5 sec.", +[2366]="+2 mana every 5 sec.", +[2367]="+2 mana every 5 sec.", +[2368]="+2 mana every 5 sec.", +[2369]="+3 mana every 5 sec.", +[2370]="+3 mana every 5 sec.", +[2371]="+4 mana every 5 sec.", +[2372]="+4 mana every 5 sec.", +[2373]="+4 mana every 5 sec.", +[2374]="+5 mana every 5 sec.", +[2375]="+5 mana every 5 sec.", +[2376]="+6 mana every 5 sec.", +[2377]="+6 mana every 5 sec.", +[2378]="+6 mana every 5 sec.", +[2379]="+7 mana every 5 sec.", +[2380]="+7 mana every 5 sec.", +[2381]="20 Spirit", +[2382]="+8 mana every 5 sec.", +[2383]="+8 mana every 5 sec.", +[2384]="+9 mana every 5 sec.", +[2385]="+9 mana every 5 sec.", +[2386]="24 Spirit", +[2387]="25 Spirit", +[2388]="26 Spirit", +[2389]="27 Spirit", +[2390]="28 Spirit", +[2391]="29 Spirit", +[2392]="30 Spirit", +[2393]="31 Spirit", +[2394]="32 Spirit", +[2395]="33 Spirit", +[2396]="+14 mana every 5 sec.", +[2397]="+14 mana every 5 sec.", +[2398]="+14 mana every 5 sec.", +[2399]="+15 mana every 5 sec.", +[2400]="+15 mana every 5 sec.", +[2401]="+1 health every 5 sec.", +[2402]="+1 health every 5 sec.", +[2403]="+1 health every 5 sec.", +[2404]="+1 health every 5 sec.", +[2405]="+1 health every 5 sec.", +[2406]="+2 health every 5 sec.", +[2407]="+2 health every 5 sec.", +[2408]="+2 health every 5 sec.", +[2409]="+2 health every 5 sec.", +[2410]="+3 health every 5 sec.", +[2411]="+3 health every 5 sec.", +[2412]="+5 health every 5 sec.", +[2413]="+5 health every 5 sec.", +[2414]="+4 health every 5 sec.", +[2415]="+4 health every 5 sec.", +[2416]="+4 health every 5 sec.", +[2417]="+4 health every 5 sec.", +[2418]="+5 health every 5 sec.", +[2419]="+5 health every 5 sec.", +[2420]="+5 health every 5 sec.", +[2421]="+5 health every 5 sec.", +[2422]="+6 health every 5 sec.", +[2423]="+6 health every 5 sec.", +[2424]="+6 health every 5 sec.", +[2425]="+6 health every 5 sec.", +[2426]="+7 health every 5 sec.", +[2427]="+7 health every 5 sec.", +[2428]="+7 health every 5 sec.", +[2429]="+7 health every 5 sec.", +[2430]="+8 health every 5 sec.", +[2431]="+8 health every 5 sec.", +[2432]="+8 health every 5 sec.", +[2433]="+8 health every 5 sec.", +[2434]="+9 health every 5 sec.", +[2435]="+9 health every 5 sec.", +[2436]="+9 health every 5 sec.", +[2437]="+9 health every 5 sec.", +[2438]="+10 health every 5 sec.", +[2443]="+7 Frost Spell Damage", +[2463]="+7 Fire Resistance", +[2483]="+5 Fire Resistance", +[2484]="+5 Frost Resistance", +[2485]="+5 Arcane Resistance", +[2486]="+5 Nature Resistance", +[2487]="+5 Shadow Resistance", +[2488]="+5 All Resistances", +[2503]="5 Dodge", +[2504]="30 SP", +[2505]="29 SP", +[2506]="+28 Melee Critical Strike", +[2523]="30 Hit", +[2543]="10 Haste", +[2544]="8 SP", +[2545]="12 Dodge", +[2563]="15 Str", +[2564]="15 Agi", +[2565]="9 Spirit", +[2566]="13 SP", +[2567]="20 Spirit", +[2568]="22 Int", +[2583]="10 Dodge", +[2584]="10 Int, 10 Dodge", +[2585]="28 AP, 12 Dodge", +[2586]="10 Stam, 10 Hit", +[2587]="13 SP, 15 Int", +[2588]="18 SP, 8 Hit", +[2589]="18 SP, 10 Stam", +[2590]="10 Int, 10 Spirit", +[2591]="10 Int", +[2603]="+2 Fishing", +[2604]="18 SP", +[2605]="18 SP", +[2606]="30 AP", +[2607]="12 SP", +[2608]="13 SP", +[2609]="15 SP", +[2610]="14 SP", +[2611]="zzOLDBlank", +[2612]="18 SP", +[2613]="+2% Threat", +[2614]="+20 Shadow Spell Power", +[2615]="+20 Frost Spell Power", +[2616]="+20 Fire Spell Power", +[2617]="16 SP", +[2618]="15 Agi", +[2619]="+15 Fire Resistance", +[2620]="+15 Nature Resistance", +[2621]="2% Reduced Threat", +[2622]="12 Dodge", +[2623]="Minor Wizard Oil", +[2624]="Minor Mana Oil", +[2625]="Lesser Mana Oil", +[2626]="Lesser Wizard Oil", +[2627]="Wizard Oil", +[2628]="Brilliant Wizard Oil", +[2629]="Brilliant Mana Oil", +[2645]="Firestone 5", +[2646]="25 Agi", +[2647]="12 Str", +[2648]="14 Dodge", +[2649]="12 Stam", +[2650]="15 SP", +[2651]="12 SP", +[2652]="11 SP", +[2653]="12 Dodge", +[2654]="12 Int", +[2655]="15 Parry", +[2656]="10 Stam, 10 Spirit", +[2657]="12 Agi", +[2658]="10 Hit, 10 Crit", +[2659]="+150 Health", +[2660]="+150 Mana", +[2661]="6 Str, 6 Agi, 6 Stam, 6 Int, 6 Spirit", +[2662]="120 Armor", +[2663]="+7 Resist All", +[2664]="+7 Resist All", +[2665]="35 Spirit", +[2666]="30 Int", +[2667]="70 AP", +[2668]="20 Str", +[2669]="40 SP", +[2670]="35 Agi", +[2671]="+50 Arcane and Fire Spell Power", +[2672]="+54 Shadow and Frost Spell Power", +[2673]="Mongoose", +[2674]="Spellsurge", +[2675]="Battlemaster", +[2676]="Superior Mana Oil", +[2677]="Superior Mana Oil", +[2678]="Superior Wizard Oil", +[2679]="12 Spirit", +[2680]="+7 Resist All", +[2681]="+10 Nature Resistance", +[2682]="+10 Frost Resistance", +[2683]="+10 Shadow Resistance", +[2684]="+100 Attack Power vs Undead", +[2685]="+60 Spell Power vs Undead", +[2686]="8 Str", +[2687]="8 Agi", +[2688]="8 Stam", +[2689]="+8 mana every 5 sec.", +[2690]="6 Int", +[2691]="6 Str", +[2692]="7 Int", +[2693]="6 Agi", +[2694]="6 Int", +[2695]="6 Crit", +[2696]="6 Dodge", +[2697]="6 Hit", +[2698]="9 Stam", +[2699]="6 Spirit", +[2700]="6 PvP Pow", +[2701]="6 Spirit", +[2702]="12 Agi", +[2703]="+4 Agility per different colored gem", +[2704]="+12 Strength if 4 blue gems equipped", +[2705]="3 Int, 3 Haste", +[2706]="4 Stam, 3 Dodge", +[2707]="3 Int, 3 Spirit", +[2708]="3 Int, 4 Stam", +[2709]="3 Int, 3 Spirit", +[2710]="3 Agi, 4 Stam", +[2711]="3 Str, 4 Stam", +[2712]="Sharpened (+12 Damage)", +[2713]="14 Crit", +[2714]="Felsteel Spike (26-38)", +[2715]="16 SP", +[2716]="16 Stam, 100 Armor", +[2717]="26 AP, 14 Crit", +[2718]="Lesser Rune of Warding", +[2719]="Lesser Ward of Shielding", +[2720]="Greater Ward of Shielding", +[2721]="15 SP, 14 Crit", +[2722]="Scope (+10 Damage)", +[2723]="Scope (+12 Damage)", +[2724]="28 Crit", +[2725]="8 Str", +[2726]="8 Agi", +[2727]="8 Int", +[2728]="8 Int", +[2729]="8 Agi", +[2730]="8 Dodge", +[2731]="12 Stam", +[2732]="8 Spirit", +[2733]="8 Spirit", +[2734]="8 Int", +[2735]="8 Crit", +[2736]="8 Crit", +[2737]="8 Dodge", +[2738]="4 Str, 6 Stam", +[2739]="4 Agi, 6 Stam", +[2740]="5 Int, 6 Stam", +[2741]="4 Int, 4 Spirit", +[2742]="4 Int, 4 Haste", +[2743]="6 Stam, 4 Dodge", +[2744]="4 Int, 4 Spirit", +[2745]="25 SP, 15 Stam", +[2746]="35 SP, 20 Stam", +[2747]="25 SP, 15 Stam", +[2748]="35 SP, 20 Stam", +[2749]="12 Int", +[2750]="6 mana per 5 sec.", +[2751]="14 Crit", +[2752]="3 Str, 3 Crit", +[2753]="4 Str, 4 Crit", +[2754]="8 Parry", +[2755]="3 Agi, 3 Hit", +[2756]="4 Agi, 4 Hit", +[2757]="4 Stam, 3 Crit", +[2758]="6 Stam, 4 Crit", +[2759]="8 Resil", +[2760]="3 Int, 3 Crit", +[2761]="4 Int, 4 Crit", +[2762]="3 PvP Pow, 3 Crit", +[2763]="4 PvP Pow, 4 Crit", +[2764]="8 Hit", +[2765]="8 PvP Pow", +[2766]="8 Int", +[2767]="8 Hit", +[2768]="16 SP", +[2769]="11 Hit", +[2770]="7 SP", +[2771]="8 Crit", +[2772]="14 Crit", +[2773]="16 Crit", +[2774]="11 Int", +[2775]="11 Crit", +[2776]="8 Spirit", +[2777]="13 Spirit", +[2778]="13 PvP Pow", +[2779]="16 Spirit", +[2780]="16 PvP Pow", +[2781]="19 Stam", +[2782]="10 Agi", +[2783]="14 Hit", +[2784]="12 Hit", +[2785]="13 Hit", +[2786]="7 Hit", +[2787]="8 Crit", +[2788]="9 Resil", +[2789]="15 Resil", +[2790]="ZZOLDLesser Rune of Warding", +[2791]="Greater Rune of Warding", +[2792]="8 Stam", +[2793]="8 Dodge", +[2794]="8 Spirit", +[2795]="Comfortable Insoles", +[2796]="15 Dodge", +[2797]="9 Dodge", +[2798]="1 Int", +[2799]="1 Stam", +[2800]="1 Armor", +[2801]="8 Resil", +[2802]="1 Agi", +[2803]="1 Stam", +[2804]="1 Int", +[2805]="1 Str", +[2806]="1 Spirit", +[2807]="+1 Arcane Damage", +[2808]="+1 Fire Damage", +[2809]="+1 Nature Damage", +[2810]="+1 Frost Damage", +[2811]="+1 Shadow Damage", +[2812]="+1 Healing", +[2813]="1 Dodge", +[2814]="+1 Health per 5 sec.", +[2815]="1 Dodge", +[2816]="+1 Mana Per 5 sec.", +[2817]="+1 Arcane Resistance", +[2818]="+1 Fire Resistance", +[2819]="+1 Frost Resistance", +[2820]="+1 Nature Resistance", +[2821]="+1 Shadow Resistance", +[2822]="1 Crit", +[2823]="1 Crit", +[2824]="1 SP", +[2825]="1 AP", +[2826]="+1 Block", +[2827]="14 Crit", +[2828]="Chance to Increase Spell Cast Speed", +[2829]="12 Crit", +[2830]="12 Crit", +[2831]="18 Stam", +[2832]="12 Int", +[2833]="12 Dodge", +[2834]="+3 Melee Damage and Chance to Stun Target", +[2835]="12 Int", +[2836]="3 mana per 5 sec.", +[2837]="7 Spirit", +[2838]="7 Crit", +[2839]="14 Crit", +[2840]="21 Stam", +[2841]="10 Stam", +[2842]="8 Spirit", +[2843]="8 Crit", +[2844]="8 Hit", +[2845]="11 Hit", +[2846]="4 mana per 5 sec.", +[2847]="4 mana per 5 sec.", +[2848]="5 mana per 5 sec.", +[2849]="7 Dodge", +[2850]="13 Crit", +[2851]="19 Stam", +[2852]="7 mana per 5 sec", +[2853]="8 mana per 5 sec", +[2854]="3 mana per 5 sec", +[2855]="5 mana per 5 sec.", +[2856]="4 Resil", +[2857]="2 Crit", +[2858]="2 Crit", +[2859]="3 Resil", +[2860]="3 Hit", +[2861]="3 Dodge", +[2862]="3 Resil", +[2863]="3 Int", +[2864]="4 Crit", +[2865]="4 Spirit", +[2866]="3 Spirit", +[2867]="2 Resil", +[2868]="6 Stam", +[2869]="4 Int", +[2870]="3 Parry", +[2871]="4 Dodge", +[2872]="5 SP", +[2873]="4 Hit", +[2874]="4 Crit", +[2875]="3 Crit", +[2876]="3 Dodge", +[2877]="4 Agi", +[2878]="4 Resil", +[2879]="3 Str", +[2880]="3 Hit", +[2881]="2 Spirit", +[2882]="6 Stam", +[2883]="4 Stam", +[2884]="2 Crit", +[2885]="2 Crit", +[2886]="2 Hit", +[2887]="3 Crit", +[2888]="+6 Block Value", +[2889]="5 SP", +[2890]="4 Spirit", +[2891]="10 Resil", +[2892]="4 Str", +[2893]="3 Agi", +[2894]="7 Str", +[2895]="4 Stam", +[2896]="7 Int", +[2897]="3 Stam", +[2898]="3 Stam, 4 Crit", +[2899]="3 Stam, 4 Crit", +[2900]="4 SP", +[2901]="2 SP", +[2902]="2 Crit", +[2906]="1 Stam, 1 Int", +[2907]="2 Parry", +[2908]="4 Hit", +[2909]="2 Hit", +[2910]="3 SP", +[2911]="10 Str", +[2912]="10 Int", +[2913]="10 Crit", +[2914]="10 Crit", +[2915]="5 Str", +[2916]="5 Int, 5 Crit", +[2917]="gem test enchantment", +[2918]="3 Stam", +[2919]="7 Str", +[2921]="3 Stam, 4 Crit", +[2922]="7 Str", +[2923]="3 Stam, 4 Crit", +[2924]="7 Int", +[2925]="3 Stam", +[2926]="2 Dodge", +[2927]="4 Str", +[2928]="10 Int", +[2929]="+2 Weapon Damage", +[2930]="10 Int", +[2931]="4 Str, 4 Agi, 4 Stam, 4 Int, 4 Spirit", +[2932]="4 Dodge", +[2933]="15 Resil", +[2934]="10 Crit", +[2935]="15 Hit", +[2936]="8 AP", +[2937]="20 SP", +[2938]="16 PvP Pow", +[2939]="6 Agi, Run Speed", +[2940]="9 Stam, Run Speed", +[2941]="2 Hit", +[2942]="6 Crit", +[2943]="7 Agi", +[2944]="7 Agi", +[2945]="10 Agi", +[2946]="5 Agi, 5 Crit", +[2947]="+3 Resist All", +[2948]="+4 Resist All", +[2949]="10 Agi", +[2950]="10 Crit", +[2951]="4 Crit", +[2952]="4 Crit", +[2953]="2 SP", +[2954]="Weighted (+12 Damage)", +[2955]="14 Crit", +[2956]="4 Str", +[2957]="4 Agi", +[2958]="4 Int", +[2959]="4 Int", +[2960]="4 Agi", +[2961]="6 Stam", +[2962]="4 Spirit", +[2963]="4 Spirit", +[2964]="4 Int", +[2965]="4 Crit", +[2966]="4 Hit", +[2967]="4 Crit", +[2968]="4 Dodge", +[2969]="10 Crit", +[2970]="10 Int", +[2971]="6 Agi", +[2972]="+4 Block", +[2973]="6 AP", +[2974]="4 SP", +[2975]="+5 Block Value", +[2976]="2 Dodge", +[2977]="13 Dodge", +[2978]="15 Stam, 15 Dodge", +[2979]="15 SP", +[2980]="15 Int, 10 Spirit", +[2981]="15 SP", +[2982]="18 SP, 10 Crit", +[2983]="26 AP", +[2984]="8 Stam", +[2985]="8 Stam", +[2986]="30 AP, 10 Crit", +[2987]="8 Stam", +[2988]="8 Stam", +[2989]="8 Stam", +[2990]="13 Dodge", +[2991]="15 Parry, 10 Dodge", +[2992]="12 Spirit", +[2993]="10 Int, 16 Spirit", +[2994]="13 Crit", +[2995]="12 SP, 15 Crit", +[2996]="13 Crit", +[2997]="20 AP, 15 Crit", +[2998]="+7 All Resistances", +[2999]="16 Parry, 17 Dodge", +[3000]="18 Stam, 12 Resil", +[3001]="16 Int, 18 Spirit", +[3002]="22 SP, 14 Hit", +[3003]="34 AP, 16 Hit", +[3004]="18 Stam, 20 Resil", +[3005]="+20 Nature Resistance", +[3006]="+20 Arcane Resistance", +[3007]="+20 Fire Resistance", +[3008]="+20 Frost Resistance", +[3009]="+20 Shadow Resistance", +[3010]="40 AP, 10 Crit", +[3011]="30 Stam, 10 Agi", +[3012]="50 AP, 12 Crit", +[3013]="40 Stam, 12 Agi", +[3015]="2 Str", +[3016]="2 Int", +[3017]="+3 Block", +[3021]="Rockbiter", +[3045]="5 Str, 6 Stam", +[3046]="5 Int, 4 Haste", +[3047]="6 Stam, 5 Crit", +[3048]="5 Agi, 6 Stam", +[3049]="5 Crit, 4 Spirit", +[3050]="5 Int, 4 Haste", +[3051]="5 Int, 6 Stam", +[3052]="5 Agi, 4 Hit", +[3053]="5 Parry, 4 Dodge", +[3054]="5 Int, 6 Stam", +[3055]="5 Agi, 4 Hit", +[3056]="5 Parry, 4 Dodge", +[3057]="5 Str, 4 Hit", +[3058]="5 Crit, 4 Spirit", +[3059]="5 Crit", +[3060]="6 Stam, 5 Dodge", +[3061]="5 Int, 4 Hit", +[3062]="6 Stam, 5 Crit", +[3063]="6 Stam, 5 Parry", +[3064]="5 Int, 5 Spirit", +[3065]="8 Str", +[3066]="5 Int, 5 PvP Pow", +[3067]="5 Agi, 6 Stam", +[3068]="5 Dodge, 4 Hit", +[3069]="5 Int, 4 Resil", +[3070]="5 Agi, 4 Crit", +[3071]="5 Int, 6 Stam", +[3072]="5 Str, 4 Crit", +[3073]="4 Agi, 5 Dodge", +[3074]="5 Int, 4 Spirit", +[3075]="5 Str, 4 Dodge", +[3076]="5 Int, 4 Crit", +[3077]="5 Int, 4 Spirit", +[3078]="6 Stam, 5 Dodge", +[3079]="5 Agi, 4 Resil", +[3080]="6 Stam, 5 Resil", +[3081]="5 Int, 4 Crit", +[3082]="6 Stam, 5 Dodge", +[3083]="5 Int, 4 Spirit", +[3084]="5 Resil, 6 Stam", +[3085]="6 Stam, 5 Crit", +[3086]="5 Int, 4 Spirit", +[3087]="5 Str, 4 Resil", +[3088]="5 Hit, 4 Dodge", +[3089]="5 Hit, 4 Haste", +[3090]="4 Resil, 5 Parry", +[3091]="5 PvP Pow, 5 Crit", +[3092]="3 Crit", +[3093]="+150 Attack Power vs Undead and Demons", +[3094]="4 Exp", +[3095]="+8 Resist All", +[3096]="17 Str, 16 Int", +[3097]="2 Spirit", +[3098]="2 SP", +[3099]="5 Int, 6 Stam", +[3100]="5 Int, 6 Stam", +[3101]="5 Str, 6 Stam", +[3102]="Poison", +[3103]="8 Str", +[3104]="6 Hit", +[3105]="8 Hit", +[3106]="3 Agi, 4 Stam", +[3107]="4 Agi, 6 Stam", +[3108]="3 Agi, 4 Stam", +[3109]="4 Agi, 4 Hit", +[3110]="3 Int, 3 Hit", +[3111]="4 Int, 4 Hit", +[3112]="4 Agi, 4 Crit", +[3113]="3 Agi, 3 Crit", +[3114]="4 AP", +[3115]="10 Str", +[3116]="10 Agi", +[3117]="10 Int", +[3118]="10 Int", +[3119]="10 Agi", +[3120]="10 Dodge", +[3121]="10 Parry", +[3122]="15 Stam", +[3123]="10 Spirit", +[3124]="10 Spirit", +[3125]="10 PvP Pow", +[3126]="10 Int", +[3127]="10 Crit", +[3128]="10 Hit", +[3129]="10 Crit", +[3130]="10 Dodge", +[3131]="10 Resil", +[3132]="10 Hit", +[3133]="5 Str, 7 Stam", +[3134]="5 Agi, 7 Stam", +[3135]="5 Agi, 7 Stam", +[3136]="5 Agi, 5 Hit", +[3137]="5 Int, 7 Stam", +[3138]="5 Int, 5 Spirit", +[3139]="5 Str, 5 Crit", +[3140]="5 Int, 5 Crit", +[3141]="5 Int, 5 Haste", +[3142]="5 Agi, 5 Hit", +[3143]="5 Int, 5 Hit", +[3144]="5 Agi, 5 Crit", +[3145]="7 Stam, 5 Dodge", +[3146]="5 PvP Pow, 5 Crit", +[3147]="5 Int, 5 Spirit", +[3148]="7 Stam, 5 Crit", +[3149]="2 Agi", +[3150]="14 Spirit", +[3151]="2 SP", +[3152]="2 Crit", +[3153]="2 SP", +[3154]="12 Agi", +[3155]="Chance to Increase Melee/Ranged Attack Speed", +[3156]="5 Agi, 6 Stam", +[3157]="4 Int, 6 Stam", +[3158]="5 Int, 4 Spirit", +[3159]="5 Agi, 4 Crit", +[3160]="5 Int, 4 Haste", +[3161]="4 Stam, 4 Crit", +[3162]="12 Crit", +[3163]="12 Int", +[3164]="3 Stam", +[3197]="10 Agi", +[3198]="5 SP", +[3199]="170 Armor", +[3200]="5 SP, 4 Spirit", +[3201]="3 Int, 3 Spirit", +[3202]="4 Int, 4 Spirit", +[3204]="3 Crit", +[3205]="3 Crit", +[3206]="8 Agi", +[3207]="12 Str", +[3208]="12 Agi", +[3209]="12 Agi", +[3210]="12 Int", +[3211]="12 Int", +[3212]="18 Stam", +[3213]="+6 Mana every 5 seconds", +[3214]="12 Spirit", +[3215]="12 Resil", +[3216]="12 Int", +[3217]="12 Crit", +[3218]="12 Hit", +[3219]="12 Hit", +[3220]="12 Crit", +[3221]="12 Dodge", +[3222]="20 Agi", +[3223]="Adamantite Weapon Chain", +[3224]="6 Agi", +[3225]="Executioner", +[3226]="4 Resil, 6 Stam", +[3227]="10 Crit", +[3228]="34 AP", +[3229]="12 Resil", +[3230]="+20 Frost Resistance", +[3231]="15 Exp", +[3232]="15 Stam, Run Speed", +[3233]="+250 Mana", +[3234]="20 Hit", +[3235]="+12 Resist All", +[3236]="+200 Health", +[3237]="+10 Weapon Damage", +[3238]="Gatherer", +[3239]="Icebreaker Weapon", +[3240]="23 SP", +[3241]="Lifeward", +[3242]="+5 Resist All", +[3243]="28 PvP Pow", +[3244]="14 Stam, 14 Spirit", +[3245]="20 Resil", +[3246]="28 SP", +[3247]="+140 Attack Power versus Undead", +[3248]="18 Exp", +[3249]="16 Crit", +[3250]="Icewalker", +[3251]="Giantslaying", +[3252]="8 All Stats", +[3253]="10 Parry", +[3254]="4 Str, 4 Agi, 4 Stam, 4 Int, 4 Spirit", +[3255]="55 SP, 20 Spirit", +[3256]="10 Agi, 40 Armor", +[3257]="54 SP", +[3258]="18 SP", +[3259]="22 Stam", +[3260]="24 Stam", +[3261]="12 Crit", +[3262]="15 Stam", +[3263]="4 Crit", +[3264]="150 Armor", +[3265]="Blessed Weapon Coating", +[3266]="Righteous Weapon Coating", +[3267]="4 Haste", +[3268]="15 Stam", +[3269]="+3 Fishing", +[3270]="8 Haste", +[3271]="4 Int, 4 Haste", +[3272]="6 Stam, 4 Haste", +[3273]="Deathfrost", +[3274]="12 Dodge", +[3275]="12 Int", +[3276]="20 AP", +[3277]="12 SP", +[3278]="12 SP", +[3279]="3 SP", +[3280]="6 Stam, 4 Dodge", +[3281]="10 Agi", +[3282]="10 Int", +[3283]="10 Int", +[3284]="5 Resil, 7 Stam", +[3285]="7 Stam, 5 Haste", +[3286]="5 Int, 5 Haste", +[3287]="10 Haste", +[3288]="Test Riding Crop Enchant", +[3289]="+10% Mount Speed", +[3290]="Use: Reduce your fall speed for 10 sec. (5 Min Cooldown) (5 Min Cooldown)", +[3292]="34 Agi", +[3293]="51 Stam", +[3294]="25 Stam", +[3295]="16 Haste", +[3296]="10 Spirit", +[3297]="+275 Health", +[3298]="Exceptional Mana Oil", +[3299]="Exceptional Wizard Oil", +[3300]="19 SP", +[3301]="6 Crit", +[3302]="8 Dodge", +[3303]="8 Haste", +[3304]="8 Dodge", +[3305]="12 Stam", +[3306]="2 mana per 5 sec.", +[3307]="9 Stam", +[3308]="4 Haste", +[3309]="6 Haste", +[3310]="6 Int", +[3311]="6 Spirit", +[3312]="8 Str", +[3313]="8 Agi", +[3314]="8 Crit", +[3315]="+3% Mount Speed", +[3316]="6 Crit", +[3317]="21 Stam", +[3318]="5 Int, 5 Spirit", +[3319]="Test Add Sockets Enchant", +[3320]="Test Skill Req Enchant", +[3321]="150 Armor", +[3322]="Frozen Rune Weapon", +[3324]="10 Crit", +[3325]="45 Stam, 15 Agi", +[3326]="55 AP, 15 Crit", +[3327]="55 Stam, 22 Agi", +[3328]="75 AP, 22 Crit", +[3329]="12 Stam", +[3330]="18 Stam", +[3331]="72 Stam, 35 Agi", +[3332]="100 AP, 36 Crit", +[3333]="QA Test Blank Purple Gem Enchant", +[3334]="Northrend Flight", +[3335]="10 Agi", +[3336]="10 Crit", +[3337]="5 Agi, 5 Crit", +[3338]="5 Int, 5 Crit", +[3339]="10 Int", +[3340]="10 Crit", +[3341]="Frozen Rune Weapon 2", +[3342]="Frozen Rune Weapon 3", +[3343]="Frozen Rune Weapon 4", +[3344]="Frozen Rune Weapon 5", +[3345]="Earthliving", +[3351]="6 Hit", +[3352]="8 Spirit", +[3353]="8 Int", +[3354]="12 Stam", +[3355]="6 Agi", +[3356]="12 AP", +[3357]="6 Str", +[3358]="6 Dodge", +[3359]="4 Parry", +[3360]="8 Parry", +[3361]="+6 Block", +[3362]="6 Exp", +[3363]="+9 Block Value", +[3364]="Empower Rune Weapon", +[3365]="Swordshattering", +[3366]="Lichbane", +[3367]="Spellshattering", +[3368]="Fallen Crusader", +[3369]="Cinderglacier", +[3370]="Razorice", +[3371]="12 Str", +[3374]="12 Agi", +[3375]="12 Agi", +[3376]="12 Dodge", +[3377]="12 Parry", +[3378]="12 Crit", +[3379]="12 Exp", +[3380]="12 Int", +[3381]="12 Int", +[3382]="12 Crit", +[3383]="12 Hit", +[3384]="12 Dodge", +[3385]="12 Resil", +[3386]="12 Haste", +[3387]="18 Stam", +[3388]="12 Spirit", +[3389]="12 Spirit", +[3390]="12 PvP Pow", +[3391]="9 Stam, 6 Crit", +[3392]="6 Str, 9 Stam", +[3393]="6 Agi, 9 Stam", +[3394]="6 Int, 9 Stam", +[3395]="6 Agi, 9 Stam", +[3396]="9 Stam, 6 Dodge", +[3397]="9 Stam, 6 Parry", +[3398]="9 Stam, 6 Exp", +[3399]="6 Int, 6 Spirit", +[3400]="6 Agi, 6 Hit", +[3401]="6 Int, 6 Spirit", +[3402]="6 Agi, 6 Hit", +[3403]="6 Int, 6 PvP Pow", +[3404]="6 Int, 6 Haste", +[3405]="6 Str, 6 Crit", +[3406]="6 Agi, 6 Hit", +[3407]="6 Str, 6 Dodge", +[3408]="6 Str, 6 Resil", +[3409]="6 Str, 6 Haste", +[3410]="6 Agi, 6 Crit", +[3411]="6 Str, 6 Hit", +[3412]="6 Agi, 6 Resil", +[3413]="6 Agi, 6 Haste", +[3414]="6 Int, 6 Crit", +[3415]="6 Int, 6 Hit", +[3416]="6 Int, 6 Resil", +[3417]="6 Int, 6 Haste", +[3418]="6 Dodge, 6 Parry", +[3419]="6 Parry, 6 Dodge", +[3420]="6 Exp, 6 Hit", +[3421]="6 Exp, 6 Dodge", +[3422]="6 Agi, 6 Crit", +[3423]="6 Agi, 6 Hit", +[3424]="6 Agi, 6 Resil", +[3426]="6 Agi, 6 Haste", +[3427]="6 Int, 9 Stam", +[3428]="9 Stam, 6 Crit", +[3429]="6 Hit, 6 Dodge", +[3430]="9 Stam, 6 Dodge", +[3431]="6 Resil, 9 Stam", +[3432]="9 Stam, 6 Haste", +[3433]="6 Int, 6 Spirit", +[3434]="6 Crit, 6 Spirit", +[3435]="6 Hit, 6 Haste", +[3436]="6 Resil, 6 Spirit", +[3437]="6 Haste, 6 Spirit", +[3438]="6 Int, 6 Spirit", +[3439]="6 Crit, 6 Spirit", +[3440]="6 Hit, 6 Haste", +[3441]="6 Resil, 6 Spirit", +[3442]="6 Haste, 6 Spirit", +[3443]="6 PvP Pow, 6 Crit", +[3444]="6 PvP Pow, 6 Crit", +[3445]="6 PvP Pow, 6 Haste", +[3446]="16 Str", +[3447]="16 Agi", +[3448]="16 Int", +[3449]="16 Agi", +[3450]="16 Dodge", +[3451]="16 Parry", +[3452]="16 Crit", +[3453]="16 Exp", +[3454]="24 Stam", +[3455]="16 Spirit", +[3456]="16 Spirit", +[3457]="16 PvP Pow", +[3458]="16 Int", +[3459]="16 Crit", +[3460]="16 Hit", +[3461]="16 Dodge", +[3462]="16 Resil", +[3463]="16 Haste", +[3464]="8 Str, 12 Stam", +[3465]="8 Agi, 12 Stam", +[3466]="8 Int, 12 Stam", +[3467]="8 Agi, 12 Stam", +[3468]="12 Stam, 8 Dodge", +[3469]="12 Stam, 8 Parry", +[3470]="12 Stam, 8 Crit", +[3471]="12 Stam, 8 Exp", +[3472]="8 Int, 8 Spirit", +[3473]="8 Int, 8 Spirit", +[3474]="8 Agi, 8 Hit", +[3475]="8 Agi, 8 Hit", +[3476]="8 Int, 8 PvP Pow", +[3477]="8 Str, 8 Crit", +[3478]="8 Str, 8 Hit", +[3479]="8 Str, 8 Dodge", +[3480]="8 Str, 8 Resil", +[3481]="8 Str, 8 Haste", +[3482]="8 Agi, 8 Crit", +[3483]="8 Agi, 8 Hit", +[3484]="8 Agi, 8 Resil", +[3485]="8 Agi, 8 Haste", +[3486]="8 Int, 8 Haste", +[3487]="8 Int, 8 Crit", +[3488]="8 Int, 8 Hit", +[3489]="8 Int, 8 Resil", +[3490]="8 Int, 8 Haste", +[3491]="8 Agi, 8 Crit", +[3492]="8 Agi, 8 Hit", +[3493]="8 Agi, 8 Resil", +[3494]="8 Agi, 8 Haste", +[3495]="8 Dodge, 8 Parry", +[3496]="8 Parry, 8 Dodge", +[3497]="8 Exp, 8 Hit", +[3498]="8 Exp, 8 Dodge", +[3499]="8 Int, 12 Stam", +[3500]="12 Stam, 8 Crit", +[3501]="8 Hit, 8 Dodge", +[3502]="12 Stam, 8 Dodge", +[3503]="8 Resil, 12 Stam", +[3504]="12 Stam, 8 Haste", +[3505]="8 Int, 8 Spirit", +[3506]="8 Crit, 8 Spirit", +[3507]="8 Hit, 8 Haste", +[3508]="8 Resil, 8 Spirit", +[3509]="8 Haste, 8 Spirit", +[3510]="8 Int, 8 Spirit", +[3511]="8 Crit, 8 Spirit", +[3512]="8 Hit, 8 Haste", +[3513]="8 Resil, 8 Spirit", +[3514]="8 Haste, 8 Spirit", +[3515]="8 PvP Pow, 8 Crit", +[3516]="8 PvP Pow, 8 Crit", +[3517]="8 PvP Pow, 8 Haste", +[3518]="20 Str", +[3519]="20 Agi", +[3520]="20 Int", +[3521]="20 Agi", +[3522]="20 Dodge", +[3523]="20 Parry", +[3524]="20 Exp", +[3525]="20 Crit", +[3526]="20 Int", +[3527]="20 Crit", +[3528]="20 Hit", +[3529]="20 Dodge", +[3530]="20 Resil", +[3531]="20 Haste", +[3532]="30 Stam", +[3533]="20 Spirit", +[3534]="20 Spirit", +[3535]="20 PvP Pow", +[3536]="10 Str, 15 Stam", +[3537]="10 Agi, 15 Stam", +[3538]="10 Int, 15 Stam", +[3539]="10 Agi, 15 Stam", +[3540]="15 Stam, 10 Dodge", +[3541]="15 Stam, 10 Parry", +[3542]="15 Stam, 10 Exp", +[3543]="15 Stam, 10 Crit", +[3544]="10 Agi, 10 Hit", +[3545]="10 Int, 10 Spirit", +[3546]="10 Int, 10 Spirit", +[3547]="10 Agi, 10 Hit", +[3548]="10 Int, 10 PvP Pow", +[3549]="10 Str, 10 Crit", +[3550]="10 Str, 10 Hit", +[3551]="10 Str, 10 Dodge", +[3552]="10 Str, 10 Resil", +[3553]="10 Str, 10 Haste", +[3554]="10 Agi, 10 Crit", +[3555]="10 Agi, 10 Hit", +[3556]="10 Agi, 10 Resil", +[3557]="10 Agi, 10 Haste", +[3558]="10 Int, 10 Spirit", +[3559]="10 Int, 10 Crit", +[3560]="10 Int, 10 Hit", +[3561]="10 Int, 10 Resil", +[3563]="10 Int, 10 Haste", +[3564]="10 Agi, 10 Crit", +[3565]="10 Agi, 10 Hit", +[3566]="10 Agi, 10 Resil", +[3567]="10 Agi, 10 Haste", +[3568]="10 Dodge, 10 Parry", +[3569]="10 Parry, 10 Dodge", +[3570]="10 Exp, 10 Hit", +[3571]="10 Exp, 10 Dodge", +[3572]="10 Int, 15 Stam", +[3573]="15 Stam, 10 Crit", +[3574]="10 Hit, 10 Dodge", +[3575]="15 Stam, 10 Dodge", +[3576]="10 Resil, 15 Stam", +[3577]="15 Stam, 10 Haste", +[3578]="10 Int, 10 Spirit", +[3579]="10 Crit, 10 Spirit", +[3580]="10 Hit, 10 Haste", +[3581]="10 Resil, 10 Spirit", +[3582]="10 Haste, 10 Spirit", +[3583]="10 Int, 10 Spirit", +[3584]="10 Crit, 10 Spirit", +[3585]="10 Hit, 10 Haste", +[3586]="10 Resil, 10 Spirit", +[3587]="10 Haste, 10 Spirit", +[3588]="10 PvP Pow, 10 Crit", +[3589]="10 PvP Pow, 10 Crit", +[3590]="10 PvP Pow, 10 Haste", +[3591]="4 Int", +[3592]="+100 Spell Power vs Undead", +[3593]="+170 Attack Power vs Undead", +[3594]="Swordbreaking", +[3595]="Spellbreaking", +[3596]="5 SP", +[3597]="Master Firestone", +[3599]="Use: Stuns all nearby Mechanical units for 3 sec. (1 Min Cooldown)", +[3600]="6 Resil", +[3601]="Use: Detatch and throw a thermal grenade, inflicting 10,000 Fire damage and incapacitating targets for 3 sec in a 3 yard radius. Any damage will break the effect. (1 Min Cooldown)", +[3602]="7 SP", +[3603]="Use: Fires an explosive rocket at an enemy for 1,165 Fire damage. (45 Sec Cooldown)", +[3604]="Use: Increases your haste by 240 for 12 sec. (1 Min Cooldown)", +[3605]="Use: Reduces your falling speed for 30 sec. (1 Min Cooldown)", +[3607]="40 Haste", +[3608]="40 Crit", +[3609]="Firestone", +[3610]="Firestone", +[3611]="Greater Firestone", +[3612]="Major Firestone", +[3613]="Fel Firestone", +[3614]="Grand Firestone", +[3615]="Spellstone", +[3616]="Greater Spellstone", +[3617]="Major Spellstone", +[3618]="Master Spellstone", +[3619]="Demonic Spellstone", +[3620]="Grand Spellstone", +[3621]="21 Crit", +[3622]="25 Crit", +[3623]="21 Int", +[3624]="21 Crit", +[3625]="21 Crit", +[3626]="21 Int", +[3627]="21 Int", +[3628]="21 Agi", +[3630]="21 Dodge", +[3631]="21 Dodge", +[3632]="21 Int", +[3633]="22 Spirit", +[3634]="32 Stam", +[3635]="21 Int", +[3636]="21 Crit", +[3637]="32 Stam", +[3638]="21 Crit", +[3639]="21 Int", +[3640]="21 Haste", +[3641]="21 Crit", +[3642]="32 Stam", +[3643]="Chance to Increase Melee/Ranged Attack Speed", +[3644]="14 Agi", +[3646]="14 Dodge", +[3647]="14 Exp", +[3648]="14 Parry", +[3649]="14 Str", +[3650]="14 Int", +[3651]="14 Agi", +[3652]="14 Crit", +[3653]="14 Spirit", +[3654]="14 Spirit", +[3655]="21 Stam", +[3656]="14 PvP Pow", +[3657]="14 Crit", +[3658]="14 Dodge", +[3659]="14 Haste", +[3660]="14 Hit", +[3661]="14 Int", +[3662]="14 Resil", +[3663]="7 Agi, 7 Hit", +[3664]="7 Agi, 10 Stam", +[3665]="10 Stam, 7 Crit", +[3666]="7 Agi, 7 Hit", +[3667]="7 Agi, 10 Stam", +[3668]="10 Stam, 7 Dodge", +[3669]="10 Stam, 7 Exp", +[3670]="10 Stam, 7 Parry", +[3671]="7 Str, 10 Stam", +[3672]="7 Int, 7 Spirit", +[3673]="7 Int, 7 Spirit", +[3674]="7 Int, 7 PvP Pow", +[3675]="7 Int, 10 Stam", +[3676]="14 AP, 7 Crit", +[3677]="7 Agi, 7 Haste", +[3678]="7 Agi, 7 Haste", +[3679]="7 Agi, 7 Hit", +[3680]="7 Agi, 7 Resil", +[3681]="7 Str, 7 Crit", +[3682]="7 Str, 7 Hit", +[3683]="7 Str, 7 Dodge", +[3684]="7 Str, 7 Resil", +[3685]="7 Str, 7 Haste", +[3686]="7 Agi, 7 Crit", +[3687]="7 Agi, 7 Hit", +[3688]="7 Agi, 7 Resil", +[3689]="7 Int, 7 Spirit", +[3690]="7 Int, 7 Crit", +[3691]="7 Int, 7 Hit", +[3692]="7 Int, 7 Resil", +[3693]="7 Int, 7 Haste", +[3694]="7 Dodge, 7 Parry", +[3695]="7 Parry, 7 Dodge", +[3696]="7 Exp, 7 Hit", +[3697]="7 Exp, 7 Dodge", +[3698]="7 Crit, 7 Spirit", +[3699]="10 Stam, 7 Crit", +[3700]="10 Stam, 7 Dodge", +[3701]="7 Haste, 7 Spirit", +[3702]="10 Stam, 7 Haste", +[3703]="7 Hit, 7 Haste", +[3704]="7 Hit, 7 Dodge", +[3705]="7 Int, 7 Spirit", +[3706]="7 Int, 10 Stam", +[3707]="7 Resil, 7 Spirit", +[3708]="7 Resil, 10 Stam", +[3709]="7 PvP Pow, 7 Crit", +[3710]="7 Crit, 7 Spirit", +[3711]="7 Int, 7 Spirit", +[3712]="7 Hit, 7 Haste", +[3713]="7 Resil, 7 Spirit", +[3714]="7 Haste, 7 Spirit", +[3715]="7 PvP Pow, 7 Crit", +[3716]="7 PvP Pow, 7 Haste", +[3717]="Socket Bracer", +[3718]="35 SP, 12 Spirit", +[3719]="50 SP, 20 Spirit", +[3720]="35 SP, 20 Stam", +[3721]="50 SP, 30 Stam", +[3722]="Lightweave 1", +[3723]="Socket Gloves", +[3726]="1 Haste", +[3727]="1 Hit", +[3728]="Darkglow 1", +[3729]="Socket Belt", +[3730]="Swordguard 1", +[3731]="28 Hit", +[3732]="34 Str", +[3733]="34 Agi", +[3734]="34 Int", +[3735]="34 Spirit", +[3736]="34 Spirit", +[3737]="34 Int", +[3738]="34 Crit", +[3739]="34 Haste", +[3740]="34 Dodge", +[3741]="34 Parry", +[3742]="34 Hit", +[3743]="34 Dodge", +[3744]="34 Resil", +[3745]="34 Crit", +[3746]="34 Exp", +[3747]="34 PvP Pow", +[3748]="Titanium Spike (45-67)", +[3749]="4 Str, 4 Agi, 4 Stam, 4 Int, 4 Spirit", +[3750]="6 Str, 6 Agi, 6 Stam, 6 Int, 6 Spirit", +[3751]="6 Dodge", +[3752]="5 SP", +[3753]="9 SP", +[3754]="24 AP", +[3755]="28 AP", +[3756]="130 AP", +[3757]="102 Stam", +[3758]="57 Int", +[3759]="102 Stam", +[3760]="102 Stam", +[3761]="102 Stam", +[3762]="102 Stam", +[3763]="102 Stam", +[3764]="12 AP", +[3765]="4 Crit", +[3766]="12 Stam", +[3767]="7 Agi, 7 Crit", +[3775]="30 SP, 15 Crit", +[3776]="45 AP, 15 Crit", +[3777]="22 Stam, 20 Dodge", +[3778]="8 Exp", +[3788]="25 Hit, 25 Crit", +[3789]="Berserking", +[3790]="Black Magic", +[3791]="30 Stam", +[3792]="20 Resil", +[3793]="40 AP, 15 Resil", +[3794]="23 SP, 15 Resil", +[3795]="50 AP, 20 Resil", +[3796]="29 SP, 20 Resil", +[3797]="29 SP, 20 Resil", +[3798]="17 Crit", +[3799]="17 Int", +[3800]="17 Crit", +[3801]="17 Crit", +[3802]="17 Int", +[3803]="17 Crit", +[3804]="26 Stam", +[3805]="17 Int", +[3806]="18 SP, 10 Crit", +[3807]="15 Int, 10 Spirit", +[3808]="40 AP, 15 Crit", +[3809]="21 Int, 16 Spirit", +[3810]="24 SP, 15 Crit", +[3811]="22 Stam, 20 Dodge", +[3812]="30 Stam", +[3813]="30 Stam", +[3814]="30 Stam", +[3815]="30 Stam", +[3816]="30 Stam", +[3817]="50 AP, 20 Crit", +[3818]="37 Stam, 20 Dodge", +[3819]="26 Int, 20 Spirit", +[3820]="26 Int, 20 Crit", +[3821]="8 Resil", +[3822]="55 Stam, 22 Agi", +[3823]="75 AP, 22 Crit", +[3824]="24 AP", +[3825]="15 Haste", +[3826]="12 Hit, 12 Crit", +[3827]="110 AP", +[3828]="85 AP", +[3829]="35 AP", +[3830]="50 SP", +[3831]="23 Haste", +[3832]="10 All Stats", +[3833]="65 AP", +[3834]="63 SP", +[3835]="120 AP, 15 Crit", +[3836]="60 Int, 15 Spirit", +[3837]="60 Dodge, 15 Parry", +[3838]="70 SP, 15 Crit", +[3839]="40 AP", +[3840]="20 Int", +[3841]="23 SP", +[3842]="30 Stam, 25 Resil", +[3843]="Scope (+15 Damage)", +[3844]="45 Spirit", +[3845]="50 AP", +[3846]="40 SP", +[3847]="Stoneskin Gargoyle", +[3848]="Socket Staff", +[3849]="Titanium Plating", +[3850]="40 Stam", +[3851]="50 Stam", +[3852]="30 Stam, 15 Resil", +[3853]="40 Resil, 28 Stam", +[3854]="81 SP", +[3855]="69 SP", +[3856]="100 Agi", +[3857]="6 Dodge", +[3858]="5 Hit", +[3859]="Use: Reduces your falling speed for 30 sec. (1 Min Cooldown)", +[3860]="Use: Increases your armor by 700 for 14 sec. (1 Min Cooldown)", +[3861]="20 Str", +[3862]="20 Agi", +[3863]="30 Stam", +[3864]="20 Spirit", +[3865]="20 Int", +[3866]="20 Int", +[3867]="20 Hit", +[3868]="Fishing Lure (+100 Fishing Skill)", +[3869]="Blade Ward", +[3870]="Blood Draining", +[3871]="6 Parry", +[3872]="50 SP, 20 Spirit", +[3873]="50 SP, 30 Stam", +[3874]="130 AP", +[3875]="30 AP, 10 Crit", +[3876]="15 Dodge, 10 Parry", +[3877]="16 AP", +[3879]="10 All Stats", +[3880]="6 Crit", +[3881]="+17 Mana every 5 seconds", +[3882]="8 Crit", +[3883]="Nerubian Carapace", +[3884]="24 Stam, 24 Agi", +[3885]="15 Mastery, 15 Spirit", +[3886]="15 Mastery, 15 Hit", +[3887]="18 Mastery, 17 Spirit", +[3888]="18 Mastery, 17 Hit", +[3889]="30 Str", +[3890]="30 Agi", +[3891]="30 Parry", +[3892]="30 Int", +[3893]="30 Exp", +[3894]="45 Stam", +[3895]="30 Spirit", +[3896]="30 PvP Pow", +[3897]="30 Hit", +[3898]="30 Dodge", +[3899]="30 Resil", +[3900]="30 Haste", +[3901]="30 Mastery", +[3902]="15 Str, 23 Stam", +[3903]="23 Stam, 15 Parry", +[3904]="15 Agi, 23 Stam", +[3905]="15 Int, 23 Stam", +[3906]="23 Stam, 15 Exp", +[3907]="15 Int, 15 Spirit", +[3908]="15 Str, 15 Hit", +[3909]="15 Agi, 15 Hit", +[3910]="15 Parry, 15 Hit", +[3911]="15 Int, 15 Hit", +[3912]="15 Exp, 15 Hit", +[3913]="15 Agi, 15 Dodge", +[3914]="15 Exp, 15 Dodge", +[3915]="15 Str, 15 Crit", +[3916]="15 Agi, 15 Crit", +[3917]="15 Int, 15 Crit", +[3918]="15 Str, 15 Haste", +[3919]="15 Agi, 15 Haste", +[3920]="15 Int, 15 Haste", +[3921]="15 Str, 15 Mastery", +[3922]="15 Agi, 15 Mastery", +[3923]="15 Parry, 15 Mastery", +[3924]="15 Int, 15 Mastery", +[3925]="15 Exp, 15 Mastery", +[3926]="23 Stam, 15 Dodge", +[3927]="15 Dodge, 15 Hit", +[3928]="23 Stam, 15 Crit", +[3929]="15 Crit, 15 Hit", +[3930]="15 Resil, 23 Stam", +[3931]="23 Stam, 15 Haste", +[3932]="15 Haste, 15 Hit", +[3933]="23 Stam, 15 Mastery", +[3936]="30 Crit", +[3937]="18 Str, 17 Hit", +[3938]="18 Int, 17 Spirit", +[3939]="26 Stam, 18 Exp", +[3940]="18 Int, 26 Stam", +[3941]="26 Stam, 18 Parry", +[3942]="18 Agi, 23 Stam", +[3943]="18 Str, 26 Stam", +[3944]="35 Mastery", +[3945]="35 Haste", +[3946]="35 Resil", +[3947]="35 Crit", +[3948]="35 Dodge", +[3949]="35 Hit", +[3950]="35 PvP Pow", +[3951]="35 Spirit", +[3952]="53 Stam", +[3953]="35 Exp", +[3954]="35 Int", +[3955]="35 Parry", +[3956]="35 Agi", +[3957]="35 Str", +[3958]="26 Stam, 18 Mastery", +[3959]="18 Haste, 17 Hit", +[3960]="26 Stam, 18 Haste", +[3961]="18 Resil, 26 Stam", +[3962]="18 Crit, 17 Hit", +[3963]="26 Stam, 18 Crit", +[3964]="18 Dodge, 17 Hit", +[3965]="26 Stam, 18 Dodge", +[3966]="18 Exp, 17 Mastery", +[3967]="18 Int, 17 Mastery", +[3968]="18 Parry, 17 Mastery", +[3969]="18 Agi, 17 Mastery", +[3970]="18 Str, 17 Mastery", +[3971]="18 Int, 17 Haste", +[3972]="18 Agi, 17 Haste", +[3973]="18 Str, 17 Haste", +[3974]="18 Int, 17 Crit", +[3975]="18 Agi, 17 Crit", +[3976]="18 Str, 17 Crit", +[3977]="18 Exp, 17 Dodge", +[3978]="18 Agi, 17 Dodge", +[3979]="18 Exp, 17 Hit", +[3980]="18 Int, 17 Hit", +[3981]="18 Parry, 17 Hit", +[3982]="18 Agi, 17 Hit", +[3983]="20 Exp, 20 Hit", +[3984]="30 Stam, 20 Parry", +[3985]="20 Str, 20 Hit", +[3986]="20 Int, 20 Hit", +[3987]="20 Agi, 20 Hit", +[3988]="30 Stam, 20 Exp", +[3989]="20 Parry, 20 Hit", +[3990]="20 Int, 20 Spirit", +[3991]="20 Agi, 30 Stam", +[3992]="20 Str, 30 Stam", +[3993]="20 Int, 30 Stam", +[3994]="40 Str", +[3995]="40 Int", +[3996]="40 Agi", +[3997]="40 Parry", +[3998]="40 Exp", +[3999]="40 Mastery", +[4000]="40 Resil", +[4001]="40 Haste", +[4002]="40 Crit", +[4003]="40 Dodge", +[4004]="40 Hit", +[4005]="60 Stam", +[4006]="40 Spirit", +[4007]="40 PvP Pow", +[4008]="20 Agi, 20 Mastery", +[4009]="20 Int, 20 Mastery", +[4010]="20 Int, 20 Haste", +[4011]="20 Agi, 20 Crit", +[4012]="20 Agi, 20 Haste", +[4013]="20 Str, 20 Haste", +[4014]="20 Parry, 20 Mastery", +[4015]="20 Str, 20 Crit", +[4016]="20 Exp, 20 Mastery", +[4017]="20 Agi, 20 Dodge", +[4018]="20 Int, 20 Crit", +[4019]="20 Str, 20 Mastery", +[4020]="20 Exp, 20 Dodge", +[4021]="30 Stam, 20 Haste", +[4022]="30 Stam, 20 Crit", +[4023]="20 Haste, 20 Hit", +[4024]="20 Dodge, 20 Hit", +[4025]="20 Crit, 20 Hit", +[4026]="30 Stam, 20 Mastery", +[4027]="30 Stam, 20 Dodge", +[4028]="20 Mastery, 20 Hit", +[4029]="20 Resil, 30 Stam", +[4030]="20 Mastery, 20 Spirit", +[4031]="67 Str", +[4032]="67 Int", +[4033]="67 Agi", +[4034]="67 Parry", +[4035]="67 Mastery", +[4036]="67 Resil", +[4037]="67 Exp", +[4038]="67 Haste", +[4039]="67 Hit", +[4040]="67 Crit", +[4041]="101 Stam", +[4042]="67 Spirit", +[4043]="67 PvP Pow", +[4044]="67 Dodge", +[4045]="54 Mastery", +[4046]="54 Crit", +[4047]="54 Int", +[4048]="81 Stam", +[4049]="81 Stam", +[4050]="81 Stam", +[4051]="54 Int", +[4052]="54 Spirit", +[4053]="54 Crit", +[4054]="81 Stam", +[4055]="54 Crit", +[4056]="54 Crit", +[4057]="54 Int", +[4058]="1 Exp", +[4059]="1 Mastery", +[4060]="1 Parry", +[4061]="50 Mastery", +[4062]="30 Stam, Run Speed", +[4063]="15 All Stats", +[4064]="56 PvP Pow", +[4065]="50 Haste", +[4066]="Mending", +[4067]="Avalanche", +[4068]="50 Haste", +[4069]="50 Haste", +[4070]="55 Stam", +[4071]="50 Crit", +[4072]="30 Int", +[4073]="16 Stam", +[4074]="Elemental Slayer", +[4075]="35 Str", +[4076]="35 Agi", +[4077]="40 Resil", +[4078]="40 Str", +[4079]="40 Agi", +[4080]="40 Int", +[4081]="60 Stam", +[4082]="50 Exp", +[4083]="Hurricane", +[4084]="Heartsong", +[4085]="50 Mastery", +[4086]="50 Dodge", +[4087]="50 Crit", +[4088]="40 Spirit", +[4089]="50 Hit", +[4090]="30 Stam", +[4091]="40 Int", +[4092]="50 Hit", +[4093]="50 Spirit", +[4094]="50 Mastery", +[4095]="50 Exp", +[4096]="50 Int", +[4097]="Power Torrent", +[4098]="Windwalk", +[4099]="Landslide", +[4100]="65 Crit", +[4101]="65 Crit", +[4102]="20 All Stats", +[4103]="75 Stam", +[4104]="35 Mastery, Run Speed", +[4105]="25 Agi, Run Speed", +[4106]="50 Str", +[4107]="65 Mastery", +[4108]="65 Haste", +[4109]="55 Int, 45 Spirit", +[4110]="95 Int, 55 Spirit", +[4111]="55 Int, 65 Stam", +[4112]="95 Int, 80 Stam", +[4113]="95 Int, 80 Stam", +[4114]="95 Int, 55 Spirit", +[4115]="Lightweave 2", +[4116]="Darkglow 2", +[4117]="Swordguard Embroidery", +[4118]="Swordguard 2", +[4119]="50 Str", +[4120]="36 Stam", +[4121]="44 Stam", +[4122]="110 AP, 45 Crit", +[4123]="10 Mastery", +[4124]="85 Stam, 45 Agi", +[4125]="30 Spirit", +[4126]="190 AP, 55 Crit", +[4127]="145 Stam, 55 Agi", +[4128]="30 Haste", +[4129]="20 Spirit", +[4130]="20 Crit", +[4131]="10 Crit", +[4132]="30 Crit", +[4134]="30 Stam", +[4135]="10 Str", +[4136]="20 Str", +[4137]="20 Mastery", +[4138]="30 Mastery", +[4139]="20 Parry", +[4140]="20 Haste", +[4141]="20 Hit", +[4142]="10 Spirit", +[4143]="10 Int", +[4144]="20 Int", +[4145]="30 Agi", +[4146]="10 Haste", +[4147]="10 Parry", +[4148]="30 Parry", +[4149]="20 Int", +[4150]="30 Int", +[4151]="10 Crit", +[4152]="20 Crit", +[4153]="30 Crit", +[4154]="15 Stam", +[4155]="10 Dodge", +[4156]="20 Dodge", +[4157]="30 Dodge", +[4158]="30 Str", +[4159]="45 Stam", +[4160]="10 Hit", +[4161]="20 Hit", +[4162]="30 Hit", +[4163]="10 Exp", +[4164]="20 Exp", +[4165]="30 Exp", +[4166]="208 Dodge", +[4167]="208 Crit", +[4168]="208 Haste", +[4169]="208 Mastery", +[4170]="208 Exp", +[4171]="208 Parry", +[4172]="208 Hit", +[4173]="208 Spirit", +[4175]="Gnomish X-Ray", +[4176]="88 Hit", +[4177]="88 Haste", +[4178]="900 Armor", +[4179]="Use: Increases your Intellect, Agility, or Strength by 480 for 10 sec. Your highest stat is always chosen. (1 Min Cooldown)", +[4180]="Use: Increases your armor by 1,500 for 13 sec. (1 Min Cooldown)", +[4181]="Use: Fires an electrified ball at an enemy for 4,800 Nature damage. (2 Min Cooldown)", +[4184]="10 Resil", +[4185]="20 Resil", +[4186]="30 Resil", +[4187]="Use: Activates a personal invisibility field. Cannot be used in combat. (3 Min Cooldown)", +[4188]="Use: Protects you with a shield of force that stops 18,000 damage for 8 sec. The strong magnetic field sometimes has strange side effects... (5 Min Cooldown)", +[4189]="195 Stam", +[4190]="130 Agi", +[4191]="130 Str", +[4192]="130 Int", +[4193]="130 Agi, 25 Mastery", +[4194]="130 Str, 25 Crit", +[4195]="195 Stam, 25 Dodge", +[4196]="130 Int, 25 Haste", +[4197]="45 Stam, 20 Dodge", +[4198]="75 Stam, 25 Dodge", +[4199]="30 Int, 20 Haste", +[4200]="50 Int, 25 Haste", +[4201]="30 Str, 20 Crit", +[4202]="50 Str, 25 Crit", +[4203]="30 Agi, 20 Mastery", +[4204]="50 Agi, 25 Mastery", +[4205]="30 Agi, 20 Mastery", +[4206]="90 Stam, 35 Dodge", +[4207]="60 Int, 35 Crit", +[4208]="60 Str, 35 Mastery", +[4209]="60 Agi, 35 Haste", +[4211]="10 Haste", +[4212]="7 Str", +[4213]="7 Str", +[4214]="Use: Summons a Cardboard Assassin to draw the attention of enemies. (5 Min Cooldown)", +[4215]="Elementium Spike (90-133)", +[4216]="Pyrium Spike (210-350)", +[4217]="40 Hit", +[4222]="Use: Engage in mental combat with a humanoid target in an attempt to pacify or control them. (10 Min Cooldown)", +[4223]="Use: Greatly increase your run speed for 5 sec. (3 Min Cooldown)", +[4225]="Fishing Lure (+150 Fishing Skill)", +[4227]="130 Agi", +[4236]="20 Int, 20 Resil", +[4237]="20 Agi, 20 Resil", +[4238]="20 Str, 20 Resil", +[4239]="208 Resil", +[4244]="20 Resil, 20 PvP Pow", +[4245]="60 Int, 35 Resil", +[4246]="60 Agi, 35 Resil", +[4247]="60 Str, 35 Resil", +[4248]="50 Int, 25 Resil", +[4249]="50 Str, 25 Resil", +[4250]="50 Agi, 25 Resil", +[4251]="54 Agi", +[4252]="54 Str", +[4253]="54 Int", +[4256]="50 Str", +[4257]="50 Int", +[4258]="50 Agi", +[4259]="+1 Fishing", +[4262]="30 Stam", +[4263]="20 Spirit", +[4264]="Fishing Lure (+15 Fishing Skill)", +[4265]="50 Int", +[4266]="50 Agi", +[4267]="Flintlocke's", +[4270]="145 Stam, 55 Dodge", +[4273]="50 Hit", +[4274]="50 PvP Pow", +[4275]="50 Spirit", +[4276]="75 Stam", +[4277]="25 Spirit, 25 Crit", +[4278]="25 Crit, 25 Hit", +[4279]="25 Haste, 25 Hit", +[4280]="25 Hit, 25 Mastery", +[4281]="25 PvP Pow, 25 Mastery", +[4282]="25 Spirit, 25 Mastery", +[4283]="25 Resil, 25 Hit", +[4284]="25 PvP Pow, 25 Resil", +[4285]="25 Resil, 25 Spirit", +[4286]="25 PvP Pow, 25 Crit", +[4287]="25 PvP Pow, 25 Haste", +[4288]="25 Haste, 25 Spirit", +[4289]="37 Stam, 25 Crit", +[4290]="37 Stam, 25 Dodge", +[4291]="37 Stam, 25 Haste", +[4292]="25 Hit, 25 Dodge", +[4293]="37 Stam, 25 Mastery", +[4294]="25 Resil, 37 Stam", +[4295]="25 Agi, 25 Crit", +[4296]="25 Exp, 25 Crit", +[4297]="25 Int, 25 Crit", +[4298]="25 Str, 25 Crit", +[4299]="25 Agi, 25 Dodge", +[4300]="25 Exp, 25 Dodge", +[4301]="25 Parry, 25 Dodge", +[4302]="25 Str, 25 Dodge", +[4303]="25 Agi, 25 Haste", +[4304]="25 Exp, 25 Haste", +[4305]="25 Int, 25 Haste", +[4306]="25 Str, 25 Haste", +[4307]="25 Agi, 25 Mastery", +[4308]="25 Exp, 25 Mastery", +[4309]="25 Int, 25 Mastery", +[4310]="25 Parry, 25 Mastery", +[4311]="25 Str, 25 Mastery", +[4312]="25 Agi, 25 Resil", +[4313]="25 Resil, 25 Exp", +[4314]="25 Int, 25 Resil", +[4315]="25 Resil, 25 Parry", +[4316]="25 Str, 25 Resil", +[4317]="25 Agi, 25 Hit", +[4318]="25 Exp, 25 Hit", +[4319]="25 Int, 25 Hit", +[4320]="25 Parry, 25 Hit", +[4321]="25 Str, 25 Hit", +[4322]="25 Int, 25 PvP Pow", +[4323]="25 Int, 25 Spirit", +[4324]="25 Agi, 37 Stam", +[4325]="37 Stam, 25 Exp", +[4326]="25 Int, 37 Stam", +[4327]="37 Stam, 25 Parry", +[4328]="25 Str, 37 Stam", +[4329]="50 Agi", +[4330]="50 Exp", +[4331]="50 Int", +[4332]="50 Parry", +[4333]="50 Str", +[4334]="50 Crit", +[4335]="50 Dodge", +[4336]="50 Haste", +[4337]="50 Mastery", +[4338]="50 Resil", +[4359]="160 Agi", +[4360]="160 Int", +[4361]="240 Stam", +[4411]="170 Mastery", +[4412]="170 Dodge", +[4414]="180 Int", +[4415]="180 Str", +[4416]="180 Agi", +[4417]="200 Resil", +[4418]="200 Spirit", +[4419]="80 All Stats", +[4420]="300 Stam", +[4421]="180 Hit", +[4422]="200 Stam", +[4423]="180 Int", +[4424]="180 Crit", +[4426]="175 Haste", +[4427]="175 Hit", +[4428]="140 Agi, Run Speed", +[4429]="140 Mastery, Run Speed", +[4430]="170 Haste", +[4431]="170 Exp", +[4432]="170 Str", +[4433]="170 Mastery", +[4434]="165 Int", +[4435]="145 Stam, 55 Dodge", +[4436]="145 Stam, 55 Agi", +[4437]="190 AP, 55 Crit", +[4438]="145 Stam, 55 Dodge", +[4439]="145 Stam, 55 Agi", +[4440]="190 AP, 55 Crit", +[4441]="Windsong", +[4442]="Jade Spirit", +[4443]="Elemental Force", +[4444]="Dancing Steel", +[4445]="Colossus", +[4446]="River's Song", +[4453]="240 Hit", +[4454]="240 PvP Pow", +[4455]="240 Spirit", +[4456]="180 Stam", +[4457]="120 Spirit, 120 Crit", +[4458]="120 Crit, 120 Hit", +[4459]="120 Haste, 120 Hit", +[4460]="120 Hit, 120 Mastery", +[4461]="120 PvP Pow, 120 Mastery", +[4462]="120 Spirit, 120 Mastery", +[4463]="120 Resil, 120 Hit", +[4464]="120 PvP Pow, 120 Resil", +[4465]="120 Resil, 120 Spirit", +[4466]="120 PvP Pow, 120 Crit", +[4467]="120 PvP Pow, 120 Haste", +[4468]="120 Haste, 120 Spirit", +[4469]="90 Stam, 120 Crit", +[4470]="90 Stam, 120 Dodge", +[4471]="90 Stam, 120 Haste", +[4472]="90 Stam, 120 Hit", +[4473]="90 Stam, 120 Mastery", +[4474]="120 Resil, 90 Stam", +[4475]="60 Agi, 120 Crit", +[4476]="120 Exp, 120 Crit", +[4477]="60 Int, 120 Crit", +[4478]="60 Str, 120 Crit", +[4479]="60 Agi, 120 Dodge", +[4480]="120 Exp, 120 Dodge", +[4481]="120 Parry, 120 Dodge", +[4482]="60 Str, 120 Dodge", +[4483]="60 Agi, 120 Haste", +[4484]="120 Exp, 120 Haste", +[4485]="60 Int, 120 Haste", +[4486]="60 Str, 120 Haste", +[4487]="60 Agi, 120 Mastery", +[4488]="120 Exp, 120 Mastery", +[4489]="60 Int, 120 Mastery", +[4490]="120 Parry, 120 Mastery", +[4491]="60 Str, 120 Mastery", +[4492]="60 Agi, 120 Resil", +[4493]="120 Resil, 120 Exp", +[4494]="60 Int, 120 Resil", +[4495]="120 Resil, 120 Parry", +[4496]="60 Str, 120 Resil", +[4497]="60 Agi, 120 Hit", +[4498]="120 Exp, 120 Hit", +[4499]="60 Int, 120 Hit", +[4500]="120 Parry, 120 Hit", +[4501]="60 Str, 120 Hit", +[4502]="60 Int, 120 PvP Pow", +[4503]="60 Int, 120 Spirit", +[4504]="60 Agi, 90 Stam", +[4505]="90 Stam, 120 Exp", +[4506]="60 Int, 90 Stam", +[4507]="90 Stam, 120 Parry", +[4508]="60 Str, 90 Stam", +[4509]="120 Agi", +[4511]="240 Exp", +[4512]="120 Int", +[4513]="240 Parry", +[4514]="120 Str", +[4515]="240 Crit", +[4516]="240 Dodge", +[4517]="240 Haste", +[4518]="240 Mastery", +[4519]="240 Resil", +[4520]="320 Hit", +[4521]="320 PvP Pow", +[4522]="320 Spirit", +[4523]="240 Stam", +[4524]="160 Spirit, 160 Crit", +[4525]="160 Crit, 160 Hit", +[4526]="160 Haste, 160 Hit", +[4527]="160 Hit, 160 Mastery", +[4528]="160 PvP Pow, 160 Mastery", +[4529]="160 Spirit, 160 Mastery", +[4530]="160 Resil, 160 Hit", +[4531]="160 PvP Pow, 160 Resil", +[4532]="160 Resil, 160 Spirit", +[4533]="160 PvP Pow, 160 Crit", +[4535]="160 PvP Pow, 160 Haste", +[4536]="160 Haste, 160 Spirit", +[4537]="120 Stam, 160 Crit", +[4538]="120 Stam, 160 Dodge", +[4539]="120 Stam, 160 Haste", +[4540]="120 Stam, 160 Hit", +[4541]="120 Stam, 160 Mastery", +[4542]="160 Resil, 120 Stam", +[4543]="80 Agi, 160 Crit", +[4544]="160 Exp, 160 Crit", +[4545]="80 Int, 160 Crit", +[4546]="80 Str, 160 Crit", +[4547]="80 Agi, 160 Dodge", +[4548]="160 Exp, 160 Dodge", +[4549]="160 Parry, 160 Dodge", +[4550]="80 Str, 160 Dodge", +[4551]="80 Agi, 160 Haste", +[4552]="160 Exp, 160 Haste", +[4553]="80 Int, 160 Haste", +[4554]="80 Str, 160 Haste", +[4555]="80 Agi, 160 Mastery", +[4556]="160 Exp, 160 Mastery", +[4557]="80 Int, 160 Mastery", +[4558]="160 Parry, 160 Mastery", +[4559]="80 Str, 160 Mastery", +[4560]="80 Agi, 160 Resil", +[4561]="160 Resil, 160 Exp", +[4562]="80 Int, 160 Resil", +[4563]="160 Resil, 160 Parry", +[4564]="80 Str, 160 Resil", +[4565]="80 Agi, 160 Hit", +[4566]="160 Exp, 160 Hit", +[4567]="80 Int, 160 Hit", +[4568]="160 Parry, 160 Hit", +[4569]="80 Str, 160 Hit", +[4570]="80 Int, 160 PvP Pow", +[4571]="80 Int, 160 Spirit", +[4572]="80 Agi, 120 Stam", +[4573]="120 Stam, 160 Exp", +[4574]="80 Int, 120 Stam", +[4575]="120 Stam, 160 Parry", +[4576]="80 Str, 120 Stam", +[4577]="160 Agi", +[4578]="320 Exp", +[4579]="160 Int", +[4580]="320 Parry", +[4581]="160 Str", +[4582]="320 Crit", +[4583]="320 Dodge", +[4584]="320 Haste", +[4585]="320 Mastery", +[4586]="320 Resil", +[4587]="320 Hit", +[4588]="320 PvP Pow", +[4589]="320 Spirit", +[4590]="240 Stam", +[4591]="160 Spirit, 160 Crit", +[4592]="160 Crit, 160 Hit", +[4593]="160 Haste, 160 Hit", +[4594]="160 Hit, 160 Mastery", +[4595]="160 PvP Pow, 160 Mastery", +[4596]="160 Spirit, 160 Mastery", +[4597]="160 Resil, 160 Hit", +[4598]="160 PvP Pow, 160 Resil", +[4599]="160 Resil, 160 Spirit", +[4600]="160 PvP Pow, 160 Crit", +[4601]="160 PvP Pow, 160 Haste", +[4602]="160 Haste, 160 Spirit", +[4603]="120 Stam, 160 Crit", +[4604]="120 Stam, 160 Dodge", +[4605]="120 Stam, 160 Haste", +[4606]="120 Stam, 160 Hit", +[4607]="120 Stam, 160 Mastery", +[4608]="160 Resil, 120 Stam", +[4609]="80 Agi, 160 Crit", +[4610]="160 Exp, 160 Crit", +[4611]="80 Int, 160 Crit", +[4612]="80 Str, 160 Crit", +[4613]="80 Agi, 160 Dodge", +[4614]="160 Exp, 160 Dodge", +[4615]="160 Parry, 160 Dodge", +[4616]="80 Str, 160 Dodge", +[4617]="80 Agi, 160 Haste", +[4618]="160 Exp, 160 Haste", +[4619]="80 Int, 160 Haste", +[4620]="80 Str, 160 Haste", +[4621]="80 Agi, 160 Mastery", +[4622]="160 Exp, 160 Mastery", +[4623]="80 Int, 160 Mastery", +[4624]="160 Parry, 160 Mastery", +[4625]="80 Str, 160 Mastery", +[4626]="80 Agi, 160 Resil", +[4627]="160 Resil, 160 Exp", +[4628]="80 Int, 160 Resil", +[4629]="160 Resil, 160 Parry", +[4630]="80 Str, 160 Resil", +[4631]="80 Agi, 160 Hit", +[4632]="160 Exp, 160 Hit", +[4633]="80 Int, 160 Hit", +[4634]="160 Parry, 160 Hit", +[4635]="80 Str, 160 Hit", +[4636]="80 Int, 160 PvP Pow", +[4637]="80 Int, 160 Spirit", +[4638]="80 Agi, 120 Stam", +[4640]="80 Int, 120 Stam", +[4641]="120 Stam, 160 Parry", +[4642]="80 Str, 120 Stam", +[4643]="160 Agi", +[4644]="160 Int", +[4645]="320 Parry", +[4646]="160 Str", +[4647]="320 Crit", +[4648]="320 Dodge", +[4649]="320 Haste", +[4650]="320 Mastery", +[4651]="320 Resil", +[4652]="120 Stam, 160 Exp", +[4653]="320 Exp", +[4654]="24 Hit", +[4655]="216 Int", +[4656]="216 Agi", +[4657]="216 Str", +[4658]="216 Int", +[4659]="432 Mastery", +[4660]="432 Spirit", +[4661]="432 Crit", +[4662]="324 Stam", +[4664]="432 Crit", +[4665]="432 Crit", +[4666]="216 Int", +[4667]="324 Stam", +[4668]="432 Dodge", +[4669]="324 Stam", +[4671]="10 Str", +[4672]="25 Resil, 25 Hit", +[4673]="25 PvP Pow, 25 Mastery", +[4674]="25 Agi, 25 Resil", +[4675]="25 Int, 25 PvP Pow", +[4676]="50 Resil", +[4677]="25 PvP Pow, 25 Crit", +[4678]="25 Str, 25 Resil", +[4679]="25 PvP Pow, 25 Haste", +[4680]="25 Resil, 25 Parry", +[4681]="25 Resil, 37 Stam", +[4682]="50 PvP Pow", +[4683]="25 Resil, 25 Exp", +[4684]="25 Resil, 25 Spirit", +[4685]="25 PvP Pow, 25 Resil", +[4686]="25 Int, 25 Resil", +[4687]="160 Agi", +[4688]="Samurai", +[4697]="Use: Increases your dodge by 480 for 10 sec. (1 Min Cooldown)", +[4698]="Use: Launches a cluster of highly explosive fireworks that detonate on impact for 14,000 Fire damage over 3 sec. (45 Sec Cooldown)", +[4699]="Blastington's", +[4700]="Mirror Scope", +[4701]="200 Str", +[4702]="400 Str", +[4717]="Pandamonium", +[4719]="Placeholder Shoulder Enchant", +[4720]="+5 Health", +[4721]="1 Stam", +[4722]="1 Stam", +[4723]="+2 Weapon Damage", +[4724]="1 Agi", +[4725]="1 Agi", +[4726]="3 Spirit", +[4727]="3 Spirit", +[4728]="3 Spirit", +[4729]="3 Int", +[4730]="3 Stam", +[4731]="3 Stam", +[4732]="+5 Fishing", +[4733]="30 Armor", +[4734]="3 Agi", +[4735]="5 Spirit", +[4736]="5 Spirit", +[4737]="5 Stam", +[4738]="5 Stam", +[4739]="5 Str", +[4740]="5 Agi", +[4741]="7 Spirit", +[4742]="7 Str", +[4743]="7 Stam", +[4744]="7 Stam", +[4745]="+3 Weapon Damage", +[4746]="+7 Weapon Damage", +[4747]="16 Agi", +[4748]="16 Agi", +[4750]="Use: Injects a Mythical Healing Potion directly into your bloodstream, increasing potency and healing you for 30,000. (1 Min Cooldown)", +[4753]="1 Str, 1 Agi, 1 Stam, 1 Int, 1 Spirit", +[4755]="3 Str, 3 Agi, 3 Stam, 3 Int, 3 Spirit", +[4757]="5 Str, 5 Agi, 5 Stam, 5 Int, 5 Spirit", +[4759]="7 Str, 7 Agi, 7 Stam, 7 Int, 7 Spirit", +[4760]="9 Str, 9 Agi, 9 Stam, 9 Int, 9 Spirit", +[4761]="3 Str, 3 Agi, 3 Stam, 3 Int, 3 Spirit", +[4762]="5 Str, 5 Agi, 5 Stam, 5 Int, 5 Spirit", +[4803]="200 Str, 100 Crit", +[4804]="200 Agi, 100 Crit", +[4805]="300 Stam, 100 Dodge", +[4806]="200 Int, 100 Crit", +[4807]="160 Str", +[4808]="Magic Weapon", +[4810]="320 Str", +[4811]="320 Int", +[4812]="320 Agi", +[4813]="480 Parry", +[4814]="480 Mastery", +[4815]="480 Exp", +[4816]="480 Haste", +[4817]="480 Hit", +[4818]="480 Crit", +[4819]="480 Dodge", +[4820]="480 Stam", +[4821]="480 Spirit", +[4822]="285 Agi, 165 Crit", +[4823]="285 Str, 165 Crit", +[4824]="430 Stam, 165 Dodge", +[4825]="285 Int, 165 Crit", +[4826]="285 Int, 165 Spirit", +[4827]="60 Agi", +[4828]="120 Agi", +[4829]="180 Agi", +[4830]="60 Str", +[4831]="60 Int", +[4832]="90 Stam", +[4833]="60 Crit", +[4834]="60 Mastery", +[4835]="60 Hit", +[4836]="60 Haste", +[4837]="60 Exp", +[4838]="60 Spirit", +[4839]="60 Dodge", +[4840]="60 Parry", +[4841]="60 PvP Pow", +[4842]="60 Resil", +[4843]="120 Crit", +[4844]="120 Dodge", +[4845]="120 Exp", +[4846]="120 Haste", +[4847]="120 Hit", +[4848]="120 Int", +[4849]="120 Mastery", +[4850]="120 Parry", +[4851]="120 Resil", +[4852]="120 Spirit", +[4853]="120 Str", +[4854]="180 Stam", +[4855]="180 Crit", +[4856]="180 Dodge", +[4857]="180 Exp", +[4858]="180 Haste", +[4859]="180 Hit", +[4860]="180 Int", +[4861]="180 Mastery", +[4862]="180 Parry", +[4863]="180 Resil", +[4864]="120 PvP Pow", +[4865]="180 PvP Pow", +[4866]="180 Spirit", +[4867]="270 Stam", +[4868]="180 Str", +[4869]="150 Stam", +[4870]="250 Stam, 100 Dodge", +[4871]="170 Agi, 100 Crit", +[4872]="170 Str, 100 Crit", +[4873]="57 Agi", +[4874]="57 Str", +[4875]="500 Agi", +[4877]="500 Int", +[4878]="750 Stam", +[4879]="500 Str", +[4880]="285 Agi, 165 Crit", +[4881]="285 Str, 165 Crit", +[4882]="430 Stam, 165 Dodge", +[4883]="95 Agi, 55 Crit", +[4884]="143 Stam, 55 Dodge", +[4885]="95 Str, 55 Crit", +[4886]="37 Agi, 22 Crit", +[4887]="55 Stam, 22 Dodge", +[4888]="37 Str, 22 Crit", +[4891]="Pandaren Fishing Lure", +[4892]="Lightweave 3", +[4893]="Darkglow 3", +[4894]="Swordguard 3", +[4895]="285 Int, 165 Crit", +[4896]="285 Int, 165 Spirit", +[4897]="Use: Reduces your falling speed for 2 min. (3 Min Cooldown)", +[4898]="Use: Increases your Intellect, Agility, or Strength by 1,920 for 10 sec. Your highest stat is always chosen. (1 Min Cooldown)", +[4899]="600 Parry", +[4900]="600 Mastery", +[4901]="600 Exp", +[4902]="600 Haste", +[4903]="600 Hit", +[4904]="600 Crit", +[4905]="600 Spirit", +[4906]="600 Dodge", +[4907]="120 Str, 80 Crit", +[4908]="120 Agi, 80 Crit", +[4909]="120 Int, 80 Crit", +[4910]="180 Stam, 80 Dodge", +[4911]="520 Str, 100 Crit", +[4912]="780 Stam, 100 Dodge", +[4913]="520 Str, 100 Crit", +[4914]="520 Agi, 100 Crit", +[4915]="520 Int, 100 Crit", +[4916]="520 Spirit, 100 Crit", +[4918]="200 Exp", +[4919]="Fishing Lure (+150 Fishing Skill)", +[4920]="+10 Maximum Health", +[4921]="200 Exp, 200 Hit", +[4922]="150 Stam, 200 Parry", +[4923]="100 Str, 200 Hit", +[4924]="100 Agi, 200 Hit", +[4925]="150 Stam, 200 Exp", +[4926]="100 Int, 200 Spirit", +[4927]="200 Parry, 200 Hit", +[4928]="100 Agi, 150 Stam", +[4929]="100 Str, 150 Stam", +[4930]="100 Int, 150 Stam", +[4931]="100 Int, 200 Hit", +[4932]="200 Resil, 200 Hit", +[4933]="200 PvP Pow, 200 Mastery", +[4934]="200 Haste, 200 Spirit", +[4935]="100 Str, 200 Hit", +[4936]="150 Stam, 200 Haste", +[4937]="150 Stam, 200 Crit", +[4938]="200 Haste, 200 Hit", +[4939]="200 Spirit, 200 Crit", +[4940]="150 Stam, 200 Hit", +[4941]="200 Crit, 200 Hit", +[4942]="150 Stam, 200 Mastery", +[4943]="200 PvP Pow, 200 Crit", +[4944]="150 Stam, 200 Dodge", +[4945]="200 Hit, 200 Mastery", +[4946]="200 PvP Pow, 200 Haste", +[4947]="200 Resil, 150 Stam", +[4948]="200 Resil, 200 Spirit", +[4949]="200 PvP Pow, 200 Resil", +[4950]="200 Spirit, 200 Mastery", +[4951]="100 Agi, 200 Mastery", +[4952]="100 Int, 200 Mastery", +[4953]="100 Str, 200 Dodge", +[4954]="200 Exp, 200 Crit", +[4955]="100 Agi, 200 Crit", +[4956]="100 Agi, 200 Haste", +[4957]="100 Str, 200 Haste", +[4958]="200 Parry, 200 Mastery", +[4959]="100 Str, 200 Crit", +[4960]="200 Exp, 200 Mastery", +[4961]="100 Agi, 200 Resil", +[4962]="100 Agi, 200 Dodge", +[4963]="100 Int, 200 Crit", +[4964]="100 Int, 200 Haste", +[4965]="200 Exp, 200 Dodge", +[4966]="100 Str, 200 Resil", +[4967]="100 Str, 200 Mastery", +[4968]="200 Resil, 200 Parry", +[4969]="200 Parry, 200 Dodge", +[4970]="200 Resil, 200 Exp", +[4971]="200 Exp, 200 Haste", +[4972]="100 Int, 200 Resil", +[4973]="100 Int, 200 PvP Pow", +[4984]="80 Str, 160 PvP Pow", +[4985]="60 Str, 120 PvP Pow", +[4986]="80 Str, 160 PvP Pow", +[4987]="100 Str, 200 PvP Pow", +[4988]="60 Agi, 120 PvP Pow", +[4989]="80 Agi, 160 PvP Pow", +[4990]="80 Agi, 160 PvP Pow", +[4991]="100 Agi, 200 PvP Pow", +[4992]="254 Str", +[4993]="170 Parry", +[4994]="Breath of the Agile Prince", +[4996]="500 Agi", +[4997]="500 Str", +[4998]="500 Int", +[5000]="Use: Allows you to walk on water and increases swim speed for up to 6 sec. (30 Sec Cooldown)", +[5001]="Ghost Iron Spike (600-1000)", +[5002]="Socket Belt", +[5003]="170 Int, 100 Crit", +[5004]="170 Int, 100 Spirit", +[5030]="324 Stam", +[5031]="324 Int", +[5032]="324 Crit", +[5033]="324 Crit", +[5034]="665 PvP Pow, 775 Resil", +[5035]="Tyranny", +[5125]="Bloody Dancing Steel"} + +local enchantItemIds = { + [-1000]=90046, + [1099]=44457, + [1597]=44469, + [3222]=38967, + [3246]=38979, + [3260]=34207, + [3845]=44815, + [3850]=44944, + [4061]=52687, + [4062]=52743, + [4063]=52744, + [4064]=52745, + [4065]=52746, + [4066]=52747, + [4067]=45872, + [4068]=52749, + [4069]=52750, + [4070]=52751, + [4071]=52752, + [4072]=52753, + [4073]=52754, + [4075]=52756, + [4076]=52757, + [4077]=52758, + [4082]=52759, + [4083]=52760, + [4084]=52761, + [4085]=52762, + [4086]=52763, + [4087]=52764, + [4088]=52765, + [4089]=52766, + [4090]=52767, + [4091]=52768, + [4092]=52769, + [4093]=52770, + [4094]=52771, + [4095]=52772, + [4096]=52773, + [4097]=52774, + [4098]=52775, + [4099]=52776, + [4100]=52777, + [4101]=52778, + [4102]=52779, + [4103]=52780, + [4104]=52782, + [4105]=52781, + [4106]=52783, + [4107]=52784, + [4108]=52785, + [4109]=54449, + [4110]=54450, + [4111]=54447, + [4112]=54448, + [4122]=56502, + [4124]=56503, + [4126]=56550, + [4127]=56551, + [4175]=59594, + [4176]=59595, + [4177]=59596, + [4197]=62321, + [4198]=62333, + [4199]=62342, + [4200]=62343, + [4201]=62344, + [4202]=62345, + [4204]=62346, + [4205]=62347, + [4217]=55057, + [4227]=68134, + [4248]=68772, + [4249]=68773, + [4250]=68774, + [4256]=68788, + [4257]=68786, + [4258]=68784, + [4267]=70139, + [4270]=71720, + [4411]=74700, + [4412]=74701, + [4414]=74703, + [4415]=74704, + [4416]=74705, + [4417]=74706, + [4418]=74707, + [4419]=74708, + [4420]=74709, + [4421]=74710, + [4422]=74711, + [4423]=74712, + [4424]=74713, + [4426]=74715, + [4427]=74716, + [4428]=74717, + [4429]=74718, + [4430]=74719, + [4431]=74720, + [4432]=74721, + [4433]=74722, + [4434]=74729, + [4441]=74723, + [4442]=74724, + [4443]=74725, + [4444]=74726, + [4445]=74727, + [4446]=74728, + [4699]=77529, + [4700]=77531, + [4803]=83006, + [4804]=83007, + [4805]=87560, + [4806]=87559, + [4822]=83764, + [4823]=83765, + [4824]=83763, + [4825]=82445, + [4826]=82444, + [4869]=85559, + [4870]=85570, + [4871]=85569, + [4872]=85568, + [4907]=87580, + [4908]=87579, + [4909]=87578, + [4910]=87577, + [4912]=87581, + [4913]=87585, + [4914]=87584, + [4915]=87582, + [4918]=86597, + [4993]=89737, + [5003]=82443, + [5004]=82442, + [5035]=95349, + [5125]=98163} + +local enchantSpellIds = { + [-1000]=122632, + [1099]=60663, + [1597]=60763, + [3222]=44529, + [3246]=44592, + [3255]=56039, + [3260]=44770, + [3365]=53323, + [3368]=53344, + [3369]=53341, + [3370]=53343, + [3594]=54446, + [3722]=55642, + [3728]=55769, + [3730]=55776, + [3757]=57690, + [3758]=57691, + [3845]=44575, + [3847]=62158, + [3850]=62256, + [3873]=56034, + [3883]=70164, + [4061]=74132, + [4062]=74189, + [4063]=74191, + [4064]=74192, + [4065]=74193, + [4066]=74195, + [4067]=74197, + [4068]=74198, + [4069]=74199, + [4070]=74200, + [4071]=74201, + [4072]=74202, + [4073]=74207, + [4075]=74212, + [4076]=74213, + [4077]=74214, + [4078]=74215, + [4079]=74216, + [4080]=74217, + [4081]=74218, + [4082]=74220, + [4083]=74223, + [4084]=74225, + [4085]=74226, + [4086]=74229, + [4087]=74230, + [4088]=74231, + [4089]=74232, + [4090]=74234, + [4091]=74235, + [4092]=44488, + [4093]=74237, + [4094]=74238, + [4095]=74239, + [4096]=74240, + [4097]=74242, + [4098]=74244, + [4099]=74246, + [4100]=74247, + [4101]=74248, + [4102]=74250, + [4103]=74251, + [4104]=74253, + [4105]=74252, + [4106]=74254, + [4107]=74255, + [4108]=74256, + [4109]=75255, + [4110]=75310, + [4111]=75250, + [4112]=75309, + [4113]=75154, + [4114]=75155, + [4115]=74172, + [4116]=75175, + [4118]=75177, + [4122]=78419, + [4124]=78420, + [4126]=78477, + [4127]=78478, + [4175]=84428, + [4176]=84408, + [4177]=84410, + [4189]=85007, + [4190]=85008, + [4191]=85009, + [4192]=85010, + [4193]=86375, + [4194]=86401, + [4195]=86402, + [4196]=86403, + [4217]=76442, + [4227]=95741, + [4256]=96261, + [4257]=96262, + [4258]=96264, + [4267]=100587, + [4270]=101599, + [4359]=103461, + [4360]=103462, + [4361]=103463, + [4411]=104338, + [4412]=104385, + [4414]=104389, + [4415]=104390, + [4416]=104391, + [4417]=104392, + [4418]=104393, + [4419]=104395, + [4420]=104397, + [4421]=104398, + [4422]=104401, + [4423]=104403, + [4424]=104404, + [4426]=104407, + [4427]=104408, + [4428]=104409, + [4429]=104414, + [4430]=104416, + [4431]=104417, + [4432]=104419, + [4433]=104420, + [4434]=104445, + [4441]=104425, + [4442]=104427, + [4443]=104430, + [4444]=104434, + [4445]=104440, + [4446]=104442, + [4699]=127115, + [4700]=127116, + [4803]=126997, + [4804]=126996, + [4805]=126994, + [4806]=126995, + [4807]=103465, + [4822]=124129, + [4823]=124127, + [4824]=124128, + [4825]=125555, + [4826]=125554, + [4869]=124628, + [4870]=124125, + [4871]=124124, + [4872]=124126, + [4873]=57683, + [4874]=124549, + [4875]=124551, + [4877]=124552, + [4878]=124553, + [4879]=124554, + [4880]=124559, + [4881]=124561, + [4882]=124563, + [4883]=124564, + [4884]=124565, + [4885]=124566, + [4886]=124567, + [4887]=124568, + [4888]=124569, + [4892]=125481, + [4893]=125482, + [4894]=125489, + [4895]=125496, + [4896]=125497, + [4907]=127016, + [4908]=127017, + [4909]=127018, + [4910]=127019, + [4912]=127024, + [4913]=127020, + [4914]=127021, + [4915]=127023, + [4918]=131929, + [4993]=130758, + [5003]=125553, + [5004]=125552, + [5035]=139631, + [5125]=142468} + +local enchantMaterials = { + [-1000]={[72104]=1}, + [1099]={[34054]=8, [34055]=2, [34052]=2}, + [1597]={[34055]=4, [34052]=4}, + [3222]={[34052]=1, [34055]=4}, + [3246]={[34054]=4, [34056]=1}, + [3255]={[38426]=1}, + [3260]={[23793]=4, [22452]=3}, + [3722]={[38426]=1}, + [3728]={[38426]=1}, + [3730]={[38426]=1}, + [3757]={[38426]=1}, + [3758]={[38426]=1}, + [3845]={[34055]=6, [34054]=24}, + [3850]={[34055]=4, [34057]=1}, + [3873]={[38426]=1}, + [4061]={[52718]=1, [52555]=1}, + [4062]={[52555]=2}, + [4063]={[52718]=2}, + [4064]={[52555]=3}, + [4065]={[52718]=1, [52555]=2}, + [4066]={[52719]=3, [52555]=11}, + [4067]={[52719]=6, [52555]=4}, + [4068]={[52718]=1, [52555]=4}, + [4069]={[52719]=1, [52555]=2}, + [4070]={[52555]=5, [52718]=1}, + [4071]={[52718]=2, [52555]=4}, + [4072]={[52555]=6}, + [4073]={[52719]=1, [52327]=15}, + [4075]={[52719]=2, [52555]=3}, + [4076]={[52719]=2, [52555]=4}, + [4077]={[52555]=9}, + [4078]={[52721]=1}, + [4079]={[52721]=1}, + [4080]={[52721]=1}, + [4081]={[52721]=1}, + [4082]={[52719]=2, [52555]=5}, + [4083]={[52721]=6, [52328]=6}, + [4084]={[52721]=3, [52719]=3, [52555]=9, [52329]=3}, + [4085]={[52555]=12}, + [4086]={[52719]=5, [52328]=1}, + [4087]={[52555]=8, [52719]=2}, + [4088]={[52555]=10, [52719]=2}, + [4089]={[52719]=1, [52555]=12}, + [4090]={[52555]=8, [52719]=3}, + [4091]={[52719]=4, [52555]=6}, + [4092]={[52719]=2, [52555]=2, [58094]=1}, + [4093]={[52719]=3, [52555]=9}, + [4094]={[52719]=3, [52555]=10}, + [4095]={[52719]=6, [52555]=4}, + [4096]={[52555]=9, [52719]=4}, + [4097]={[52722]=4, [52721]=8, [52555]=14}, + [4098]={[52722]=6, [52721]=6, [52719]=4}, + [4099]={[52722]=5, [52721]=5, [52719]=5, [52555]=6}, + [4100]={[52722]=5}, + [4101]={[52722]=1, [52721]=2, [52719]=3, [52555]=15}, + [4102]={[52722]=3, [52721]=3}, + [4103]={[52555]=10, [52721]=4, [52722]=2}, + [4104]={[52722]=1, [52721]=2, [52719]=10}, + [4105]={[52722]=1, [52721]=2, [52719]=7, [52555]=5}, + [4106]={[52722]=2, [52719]=8, [52555]=4}, + [4107]={[52722]=2, [52719]=5, [52555]=10}, + [4108]={[52722]=1, [52721]=2, [52719]=4, [52555]=12}, + [4109]={[53643]=3, [52326]=6}, + [4110]={[54440]=1}, + [4111]={[53643]=3, [52325]=6}, + [4112]={[54440]=1}, + [4113]={[38426]=2}, + [4114]={[38426]=2}, + [4115]={[38426]=2}, + [4116]={[38426]=2}, + [4118]={[38426]=2}, + [4122]={[52976]=6, [52325]=4}, + [4124]={[52976]=6, [52326]=4}, + [4126]={[52979]=20, [52980]=1}, + [4127]={[52980]=1, [52325]=20}, + [4189]={[38426]=1}, + [4190]={[38426]=1}, + [4191]={[38426]=1}, + [4192]={[38426]=1}, + [4217]={[51950]=1}, + [4227]={[52721]=3, [52719]=3, [52555]=3}, + [4256]={[52722]=2, [52555]=6, [52327]=25}, + [4257]={[52722]=2, [52326]=15, [52719]=4, [52555]=4}, + [4258]={[52722]=2, [52555]=12, [52328]=15}, + [4270]={[52980]=1, [52327]=20}, + [4359]={[74249]=2}, + [4360]={[74249]=2}, + [4361]={[74249]=2}, + [4411]={[74249]=4}, + [4412]={[74249]=8, [74250]=2}, + [4414]={[74248]=3}, + [4415]={[74248]=3}, + [4416]={[74248]=3}, + [4417]={[74249]=3, [74250]=1}, + [4418]={[74249]=4}, + [4419]={[74249]=2, [74250]=3}, + [4420]={[74249]=4, [74250]=1}, + [4421]={[74249]=7}, + [4422]={[74247]=2}, + [4423]={[74249]=3, [74250]=3}, + [4424]={[74250]=1}, + [4426]={[74249]=2, [74250]=1}, + [4427]={[74249]=2, [74250]=1}, + [4428]={[74247]=2}, + [4429]={[74249]=4, [74250]=3}, + [4430]={[74249]=4}, + [4431]={[74250]=2}, + [4432]={[74249]=3, [74250]=1, [74247]=1}, + [4433]={[74250]=3}, + [4434]={[74250]=3}, + [4441]={[74249]=12, [74247]=1}, + [4442]={[74250]=4, [74248]=10}, + [4443]={[74250]=3}, + [4444]={[74249]=12, [74248]=10}, + [4445]={[74247]=3}, + [4446]={[74250]=50, [76138]=1}, + [4699]={[72096]=27, [76131]=2, [76061]=1}, + [4700]={[72096]=12, [76133]=2}, + [4803]={[39354]=1, [79255]=3}, + [4804]={[39354]=1, [79255]=3}, + [4805]={[39354]=1, [79255]=3}, + [4806]={[39354]=1, [79255]=3}, + [4807]={[74249]=2}, + [4822]={[72163]=1, [76061]=1}, + [4823]={[72163]=1, [76061]=1}, + [4824]={[72163]=1, [76061]=1}, + [4825]={[82447]=1}, + [4826]={[82447]=1}, + [4869]={[72120]=4}, + [4870]={[79101]=12}, + [4871]={[72120]=12}, + [4872]={[72120]=12}, + [4873]={[38426]=1}, + [4874]={[38426]=1}, + [4875]={[38426]=1}, + [4877]={[38426]=1}, + [4878]={[38426]=1}, + [4879]={[38426]=1}, + [4880]={[38426]=1}, + [4881]={[38426]=1}, + [4882]={[38426]=1}, + [4883]={[38426]=1}, + [4884]={[38426]=1}, + [4885]={[38426]=1}, + [4886]={[38426]=1}, + [4887]={[38426]=1}, + [4888]={[38426]=1}, + [4892]={[38426]=3}, + [4893]={[38426]=3}, + [4894]={[38426]=3}, + [4895]={[38426]=3}, + [4896]={[38426]=3}, + [4907]={[39354]=1, [79254]=3}, + [4908]={[39354]=1, [79254]=3}, + [4909]={[39354]=1, [79254]=3}, + [4910]={[39354]=1, [79254]=3}, + [4912]={[39354]=1, [79254]=3}, + [4913]={[39354]=1, [79254]=3}, + [4914]={[39354]=1, [79254]=3}, + [4915]={[39354]=1, [79254]=3}, + [4918]={[72104]=1}, + [4993]={[74250]=3, [74247]=1}, + [5003]={[72988]=20}, + [5004]={[72988]=20}, + [5035]={[74249]=12, [74248]=10}, + [5125]={[74249]=12, [74248]=10}} + +local enchantIconNames = { +'ability_parry', +'inv_belt_42', +'inv_belt_42c', +'inv_belt_robe_pvpmage_d_01', +'inv_bracer_69', +'inv_enchant_formulagood_01', +'inv_enchant_formulasuperior_01', +'inv_inscription_runescrolloffortitude_blue', +'inv_inscription_runescrolloffortitude_yellow', +'inv_misc_armorkit_08', +'inv_misc_armorkit_26', +'inv_misc_armorkit_28', +'inv_misc_armorkit_29', +'inv_misc_armorkit_mop_00', +'inv_misc_armorkit_mop_01', +'inv_misc_armorkit_mop_02', +'inv_misc_armorkit_mop_04', +'inv_misc_cataclysmarmorkit_01', +'inv_misc_cataclysmarmorkit_02', +'inv_misc_cataclysmarmorkit_08', +'inv_misc_cataclysmarmorkit_10', +'inv_misc_cataclysmarmorkit_11', +'inv_misc_cataclysmarmorkit_12', +'inv_misc_enggizmos_37', +'inv_misc_gem_bloodstone_02', +'inv_misc_gem_crystal_01', +'inv_misc_gem_emeraldrough_02', +'inv_misc_gem_goldendraenite_01', +'inv_misc_mastersinscription', +'inv_misc_monsterscales_14', +'inv_misc_monsterscales_20', +'inv_misc_note_01', +'inv_misc_pelt_10', +'inv_misc_pelt_11', +'inv_misc_pelt_12', +'inv_misc_pelt_13', +'inv_misc_scopea', +'inv_misc_scopeb', +'inv_misc_scopec', +'inv_misc_steelweaponchain', +'inv_misc_thread_01', +'inv_misc_thread_eternium', +'inv_sword_130', +'inv_sword_61', +'item_spellcloththread', +'spell_fire_masterofelements', +'spell_frost_frostarmor', +'spell_holy_greaterheal', +'spell_holy_retributionaura', +'spell_nature_astralrecal', +'spell_nature_astralrecalgroup', +'spell_shadow_chilltouch', +'trade_engraving'} + +local enchantIconIndexes = { +[-1000]=4, +[1099]=48, +[1597]=6, +[3222]=48, +[3246]=48, +[3255]=51, +[3260]=10, +[3365]=1, +[3368]=49, +[3369]=52, +[3370]=47, +[3594]=1, +[3722]=41, +[3728]=41, +[3730]=41, +[3757]=33, +[3758]=34, +[3845]=6, +[3847]=43, +[3850]=7, +[3873]=51, +[3883]=44, +[4061]=48, +[4062]=48, +[4063]=48, +[4064]=48, +[4065]=48, +[4066]=48, +[4067]=48, +[4068]=48, +[4069]=48, +[4070]=48, +[4071]=48, +[4072]=48, +[4073]=48, +[4075]=48, +[4076]=48, +[4077]=48, +[4078]=48, +[4079]=48, +[4080]=48, +[4081]=48, +[4082]=48, +[4083]=48, +[4084]=48, +[4085]=48, +[4086]=48, +[4087]=48, +[4088]=48, +[4089]=48, +[4090]=48, +[4091]=48, +[4092]=48, +[4093]=48, +[4094]=48, +[4095]=48, +[4096]=48, +[4097]=6, +[4098]=6, +[4099]=6, +[4100]=6, +[4101]=6, +[4102]=6, +[4103]=6, +[4104]=6, +[4105]=6, +[4106]=6, +[4107]=6, +[4108]=6, +[4109]=50, +[4110]=51, +[4111]=45, +[4112]=42, +[4113]=51, +[4114]=51, +[4115]=41, +[4116]=41, +[4118]=41, +[4122]=11, +[4124]=13, +[4126]=30, +[4127]=31, +[4175]=37, +[4176]=39, +[4177]=24, +[4189]=33, +[4190]=36, +[4191]=35, +[4192]=34, +[4193]=29, +[4194]=29, +[4195]=29, +[4196]=29, +[4197]=26, +[4198]=26, +[4199]=25, +[4200]=25, +[4201]=27, +[4202]=27, +[4204]=28, +[4205]=28, +[4206]=46, +[4207]=46, +[4208]=46, +[4209]=46, +[4217]=40, +[4227]=48, +[4256]=7, +[4257]=7, +[4258]=7, +[4267]=38, +[4270]=20, +[4359]=32, +[4360]=32, +[4361]=32, +[4411]=32, +[4412]=32, +[4414]=7, +[4415]=7, +[4416]=7, +[4417]=32, +[4418]=32, +[4419]=32, +[4420]=32, +[4421]=32, +[4422]=32, +[4423]=32, +[4424]=32, +[4426]=32, +[4427]=32, +[4428]=32, +[4429]=32, +[4430]=32, +[4431]=32, +[4432]=32, +[4433]=32, +[4434]=32, +[4441]=7, +[4442]=7, +[4443]=7, +[4444]=7, +[4445]=7, +[4446]=7, +[4699]=38, +[4700]=37, +[4803]=9, +[4804]=9, +[4805]=9, +[4806]=9, +[4807]=32, +[4822]=19, +[4823]=17, +[4824]=15, +[4825]=2, +[4826]=3, +[4869]=12, +[4870]=14, +[4871]=18, +[4872]=16, +[4873]=36, +[4874]=35, +[4875]=36, +[4877]=34, +[4878]=33, +[4879]=35, +[4880]=23, +[4881]=22, +[4882]=21, +[4883]=23, +[4884]=21, +[4885]=22, +[4886]=23, +[4887]=21, +[4888]=22, +[4892]=41, +[4893]=41, +[4894]=41, +[4895]=51, +[4896]=51, +[4907]=8, +[4908]=8, +[4909]=8, +[4910]=8, +[4912]=29, +[4913]=29, +[4914]=29, +[4915]=29, +[4918]=40, +[4993]=48, +[5003]=42, +[5004]=5, +[5035]=53, +[5125]=7} +-- return 'none', the name of the enchant, or 'unknown (id)' +function AskMrRobot.getEnchantName(enchantId) + if enchantId == 0 then return 'none' end + local enchantName = enchantNames[enchantId] + if not enchantName then return 'unknown (' .. enchantId .. ')' end + return enchantName +end + +-- return the spell id, if we have it, otherwise nil +function AskMrRobot.getEnchantSpellId(enchantId) + if not enchantId then return nil end + return enchantSpellIds[enchantId] +end + +-- return the item id, if we have it, otherwise nil +function AskMrRobot.getEnchantItemId(enchantId) + if not enchantId then return nil end + return enchantItemIds[enchantId] +end + +-- return the enchant icon, if we have it, otherwise nil +function AskMrRobot.getEnchantIcon(enchantId) + if not enchantId then return nil end + local index = enchantIconIndexes[enchantId] + if not index then return nil end + return enchantIconNames[index] +end + +-- material list -> itemId -> count +function AskMrRobot.addEnchantMaterials(materialList, enchantId) + local materials = enchantMaterials[enchantId] + if materials then + for materialId, count in pairs(materials) do + local existingCount = materialList[materialId] + if existingCount then + existingCount.total = existingCount.total + count + else + materialList[materialId] = {count = 0, total = count} + end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gems.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,3094 @@ +local _, AskMrRobot = ... + +local gemToColor = { +[22459]="Prismatic", +[22460]="Prismatic", +[23094]="Red", +[23095]="Red", +[23096]="Red", +[23097]="Red", +[23098]="Orange", +[23099]="Orange", +[23100]="Purple", +[23101]="Orange", +[23103]="Green", +[23104]="Green", +[23105]="Green", +[23106]="Purple", +[23108]="Purple", +[23109]="Purple", +[23110]="Purple", +[23111]="Purple", +[23113]="Red", +[23114]="Yellow", +[23115]="Yellow", +[23116]="Blue", +[23118]="Blue", +[23119]="Blue", +[23120]="Blue", +[23121]="Blue", +[23233]="Red", +[23234]="Blue", +[23235]="Yellow", +[24027]="Red", +[24028]="Red", +[24029]="Red", +[24030]="Red", +[24031]="Red", +[24032]="Yellow", +[24033]="Blue", +[24035]="Blue", +[24036]="Red", +[24037]="Blue", +[24039]="Blue", +[24047]="Red", +[24048]="Yellow", +[24050]="Yellow", +[24051]="Blue", +[24052]="Yellow", +[24053]="Yellow", +[24054]="Purple", +[24055]="Purple", +[24056]="Purple", +[24057]="Purple", +[24058]="Orange", +[24059]="Orange", +[24060]="Orange", +[24061]="Purple", +[24062]="Green", +[24065]="Purple", +[24066]="Green", +[24067]="Green", +[25890]="Meta", +[25893]="Meta", +[25894]="Meta", +[25895]="Meta", +[25896]="Meta", +[25897]="Meta", +[25898]="Meta", +[25899]="Meta", +[25901]="Meta", +[27679]="Yellow", +[27777]="Red", +[27785]="Green", +[27786]="Green", +[27809]="Green", +[27812]="Red", +[27820]="Green", +[27863]="Blue", +[27864]="Blue", +[28118]="Red", +[28119]="Yellow", +[28120]="Yellow", +[28123]="Orange", +[28290]="Yellow", +[28360]="Red", +[28361]="Red", +[28362]="Red", +[28363]="Orange", +[28458]="Red", +[28459]="Red", +[28460]="Red", +[28461]="Red", +[28462]="Red", +[28463]="Blue", +[28464]="Blue", +[28465]="Blue", +[28466]="Red", +[28467]="Yellow", +[28468]="Blue", +[28469]="Yellow", +[28470]="Yellow", +[28556]="Meta", +[28557]="Meta", +[28595]="Red", +[30546]="Purple", +[30547]="Orange", +[30548]="Green", +[30549]="Purple", +[30550]="Green", +[30551]="Orange", +[30552]="Purple", +[30553]="Purple", +[30554]="Orange", +[30555]="Purple", +[30556]="Purple", +[30558]="Orange", +[30559]="Purple", +[30560]="Green", +[30563]="Green", +[30564]="Purple", +[30565]="Green", +[30566]="Purple", +[30571]="Red", +[30572]="Purple", +[30573]="Purple", +[30574]="Purple", +[30575]="Green", +[30581]="Orange", +[30582]="Orange", +[30583]="Purple", +[30584]="Orange", +[30585]="Orange", +[30586]="Purple", +[30587]="Orange", +[30588]="Orange", +[30589]="Purple", +[30590]="Green", +[30591]="Orange", +[30592]="Green", +[30593]="Orange", +[30594]="Green", +[30598]="Red", +[30600]="Purple", +[30601]="Green", +[30602]="Green", +[30603]="Purple", +[30604]="Orange", +[30605]="Green", +[30606]="Green", +[30607]="Orange", +[30608]="Green", +[31116]="Purple", +[31117]="Purple", +[31118]="Purple", +[31860]="Blue", +[31861]="Blue", +[31862]="Purple", +[31863]="Purple", +[31864]="Purple", +[31865]="Purple", +[31866]="Purple", +[31867]="Purple", +[31868]="Orange", +[31869]="Orange", +[32193]="Red", +[32194]="Red", +[32195]="Red", +[32196]="Red", +[32197]="Red", +[32198]="Yellow", +[32199]="Red", +[32200]="Blue", +[32201]="Blue", +[32202]="Blue", +[32203]="Blue", +[32204]="Red", +[32205]="Yellow", +[32206]="Blue", +[32207]="Yellow", +[32208]="Yellow", +[32209]="Yellow", +[32210]="Blue", +[32211]="Purple", +[32212]="Purple", +[32213]="Purple", +[32214]="Purple", +[32215]="Purple", +[32216]="Purple", +[32217]="Orange", +[32218]="Orange", +[32219]="Orange", +[32220]="Purple", +[32221]="Purple", +[32222]="Orange", +[32223]="Green", +[32224]="Green", +[32225]="Purple", +[32226]="Green", +[32409]="Meta", +[32410]="Meta", +[32634]="Purple", +[32635]="Purple", +[32636]="Purple", +[32637]="Orange", +[32638]="Orange", +[32639]="Green", +[32640]="Meta", +[32641]="Meta", +[32735]="Red", +[32833]="Purple", +[32836]="Purple", +[33060]="Yellow", +[33131]="Red", +[33132]="Red", +[33133]="Red", +[33134]="Red", +[33135]="Blue", +[33137]="Blue", +[33138]="Yellow", +[33139]="Red", +[33140]="Yellow", +[33141]="Blue", +[33142]="Yellow", +[33143]="Yellow", +[33144]="Yellow", +[33782]="Green", +[34220]="Meta", +[34256]="Blue", +[34831]="Blue", +[34967]="Yellow", +[35315]="Yellow", +[35316]="Orange", +[35318]="Green", +[35487]="Red", +[35488]="Red", +[35489]="Red", +[35501]="Meta", +[35503]="Meta", +[35707]="Green", +[35758]="Green", +[35759]="Green", +[35760]="Orange", +[35761]="Yellow", +[36766]="Red", +[36767]="Blue", +[37430]="Blue", +[37503]="Purple", +[38292]="Red", +[38545]="Red", +[38546]="Yellow", +[38547]="Orange", +[38548]="Orange", +[38549]="Red", +[38550]="Yellow", +[39900]="Red", +[39905]="Red", +[39906]="Red", +[39907]="Yellow", +[39908]="Red", +[39909]="Yellow", +[39910]="Red", +[39911]="Red", +[39912]="Red", +[39914]="Yellow", +[39915]="Blue", +[39916]="Yellow", +[39917]="Yellow", +[39918]="Yellow", +[39919]="Blue", +[39920]="Blue", +[39927]="Blue", +[39932]="Blue", +[39933]="Green", +[39934]="Purple", +[39935]="Purple", +[39936]="Purple", +[39937]="Purple", +[39938]="Green", +[39939]="Purple", +[39940]="Purple", +[39941]="Purple", +[39942]="Purple", +[39943]="Purple", +[39944]="Purple", +[39945]="Purple", +[39946]="Orange", +[39947]="Orange", +[39948]="Purple", +[39949]="Orange", +[39950]="Orange", +[39951]="Orange", +[39952]="Orange", +[39953]="Purple", +[39954]="Orange", +[39955]="Orange", +[39956]="Orange", +[39957]="Purple", +[39958]="Orange", +[39959]="Orange", +[39960]="Orange", +[39961]="Purple", +[39962]="Orange", +[39963]="Orange", +[39964]="Orange", +[39965]="Orange", +[39966]="Purple", +[39967]="Orange", +[39968]="Purple", +[39974]="Green", +[39975]="Green", +[39976]="Green", +[39977]="Green", +[39978]="Green", +[39979]="Purple", +[39980]="Green", +[39981]="Green", +[39982]="Green", +[39983]="Green", +[39984]="Purple", +[39985]="Green", +[39986]="Green", +[39988]="Green", +[39989]="Green", +[39990]="Green", +[39991]="Green", +[39992]="Green", +[39996]="Red", +[39997]="Red", +[39998]="Red", +[39999]="Red", +[40000]="Yellow", +[40001]="Red", +[40002]="Yellow", +[40003]="Red", +[40008]="Blue", +[40009]="Blue", +[40010]="Blue", +[40011]="Blue", +[40012]="Red", +[40013]="Yellow", +[40014]="Blue", +[40015]="Yellow", +[40016]="Yellow", +[40017]="Yellow", +[40022]="Purple", +[40023]="Purple", +[40024]="Purple", +[40025]="Purple", +[40026]="Purple", +[40027]="Purple", +[40028]="Purple", +[40029]="Purple", +[40030]="Purple", +[40031]="Green", +[40032]="Purple", +[40033]="Green", +[40034]="Purple", +[40037]="Orange", +[40038]="Purple", +[40039]="Orange", +[40040]="Orange", +[40041]="Orange", +[40043]="Orange", +[40044]="Purple", +[40045]="Orange", +[40046]="Orange", +[40047]="Orange", +[40048]="Orange", +[40049]="Purple", +[40050]="Orange", +[40051]="Orange", +[40052]="Orange", +[40053]="Purple", +[40054]="Orange", +[40055]="Orange", +[40056]="Orange", +[40057]="Orange", +[40058]="Purple", +[40059]="Orange", +[40085]="Purple", +[40086]="Green", +[40088]="Green", +[40089]="Green", +[40090]="Green", +[40091]="Green", +[40092]="Purple", +[40094]="Purple", +[40095]="Green", +[40096]="Green", +[40098]="Green", +[40099]="Green", +[40100]="Green", +[40101]="Green", +[40102]="Green", +[40103]="Green", +[40104]="Green", +[40105]="Green", +[40106]="Green", +[40111]="Red", +[40112]="Red", +[40113]="Red", +[40114]="Red", +[40115]="Yellow", +[40116]="Red", +[40117]="Yellow", +[40118]="Red", +[40119]="Blue", +[40120]="Blue", +[40121]="Blue", +[40122]="Blue", +[40123]="Red", +[40124]="Yellow", +[40125]="Blue", +[40126]="Yellow", +[40127]="Yellow", +[40128]="Yellow", +[40129]="Purple", +[40130]="Purple", +[40131]="Purple", +[40132]="Purple", +[40133]="Purple", +[40134]="Purple", +[40135]="Purple", +[40136]="Purple", +[40137]="Purple", +[40138]="Green", +[40139]="Purple", +[40140]="Green", +[40141]="Purple", +[40142]="Orange", +[40143]="Purple", +[40144]="Orange", +[40145]="Orange", +[40146]="Orange", +[40147]="Orange", +[40148]="Purple", +[40149]="Orange", +[40150]="Orange", +[40151]="Purple", +[40152]="Orange", +[40153]="Purple", +[40154]="Orange", +[40155]="Orange", +[40156]="Orange", +[40157]="Purple", +[40158]="Orange", +[40159]="Orange", +[40160]="Orange", +[40161]="Orange", +[40162]="Purple", +[40163]="Orange", +[40164]="Purple", +[40165]="Green", +[40166]="Green", +[40167]="Green", +[40168]="Green", +[40169]="Green", +[40170]="Purple", +[40171]="Green", +[40172]="Green", +[40173]="Green", +[40174]="Green", +[40175]="Purple", +[40176]="Green", +[40177]="Green", +[40178]="Green", +[40179]="Green", +[40180]="Green", +[40181]="Green", +[40182]="Green", +[41285]="Meta", +[41307]="Meta", +[41333]="Meta", +[41335]="Meta", +[41339]="Meta", +[41375]="Meta", +[41376]="Meta", +[41377]="Meta", +[41378]="Meta", +[41379]="Meta", +[41380]="Meta", +[41381]="Meta", +[41382]="Meta", +[41385]="Meta", +[41389]="Meta", +[41395]="Meta", +[41396]="Meta", +[41397]="Meta", +[41398]="Meta", +[41400]="Meta", +[41401]="Meta", +[41429]="Orange", +[41432]="Red", +[41433]="Red", +[41434]="Red", +[41435]="Red", +[41436]="Yellow", +[41437]="Red", +[41438]="Red", +[41439]="Yellow", +[41440]="Blue", +[41441]="Blue", +[41442]="Blue", +[41443]="Blue", +[41444]="Red", +[41445]="Yellow", +[41446]="Yellow", +[41447]="Blue", +[41448]="Yellow", +[41449]="Yellow", +[41450]="Purple", +[41451]="Purple", +[41452]="Purple", +[41453]="Purple", +[41454]="Purple", +[41455]="Purple", +[41456]="Green", +[41457]="Purple", +[41458]="Green", +[41459]="Purple", +[41460]="Purple", +[41461]="Purple", +[41462]="Purple", +[41463]="Purple", +[41464]="Green", +[41465]="Green", +[41466]="Green", +[41467]="Green", +[41468]="Green", +[41469]="Green", +[41470]="Green", +[41471]="Green", +[41472]="Green", +[41473]="Purple", +[41474]="Green", +[41475]="Green", +[41476]="Green", +[41477]="Green", +[41478]="Green", +[41479]="Purple", +[41480]="Green", +[41481]="Green", +[41482]="Purple", +[41483]="Orange", +[41484]="Orange", +[41485]="Orange", +[41486]="Orange", +[41487]="Orange", +[41488]="Purple", +[41489]="Orange", +[41490]="Orange", +[41491]="Purple", +[41492]="Orange", +[41493]="Orange", +[41494]="Purple", +[41495]="Orange", +[41496]="Purple", +[41497]="Orange", +[41498]="Orange", +[41499]="Orange", +[41500]="Orange", +[41501]="Orange", +[41502]="Purple", +[42142]="Red", +[42143]="Red", +[42144]="Red", +[42145]="Blue", +[42146]="Blue", +[42148]="Red", +[42149]="Yellow", +[42150]="Yellow", +[42151]="Yellow", +[42152]="Red", +[42153]="Yellow", +[42154]="Red", +[42155]="Blue", +[42156]="Blue", +[42157]="Yellow", +[42158]="Yellow", +[42701]="Prismatic", +[42702]="Prismatic", +[44066]="Yellow", +[44076]="Meta", +[44078]="Meta", +[44081]="Meta", +[44082]="Meta", +[44084]="Meta", +[44087]="Meta", +[44088]="Meta", +[44089]="Meta", +[45862]="Red", +[45879]="Red", +[45880]="Blue", +[45881]="Blue", +[45882]="Red", +[45883]="Red", +[45987]="Blue", +[49110]="Prismatic", +[52070]="Purple", +[52081]="Red", +[52082]="Red", +[52083]="Red", +[52084]="Red", +[52085]="Red", +[52086]="Blue", +[52087]="Blue", +[52088]="Blue", +[52089]="Blue", +[52090]="Yellow", +[52091]="Yellow", +[52092]="Yellow", +[52093]="Yellow", +[52094]="Yellow", +[52095]="Purple", +[52096]="Purple", +[52097]="Purple", +[52098]="Purple", +[52099]="Purple", +[52100]="Purple", +[52101]="Purple", +[52102]="Purple", +[52103]="Purple", +[52104]="Purple", +[52105]="Purple", +[52106]="Orange", +[52107]="Orange", +[52108]="Orange", +[52109]="Orange", +[52110]="Orange", +[52111]="Orange", +[52112]="Orange", +[52113]="Orange", +[52114]="Orange", +[52115]="Orange", +[52116]="Orange", +[52117]="Orange", +[52118]="Orange", +[52119]="Green", +[52120]="Green", +[52121]="Green", +[52122]="Green", +[52123]="Green", +[52124]="Green", +[52125]="Green", +[52126]="Green", +[52127]="Green", +[52128]="Green", +[52129]="Green", +[52130]="Green", +[52131]="Green", +[52132]="Green", +[52133]="Green", +[52134]="Green", +[52135]="Green", +[52136]="Green", +[52137]="Green", +[52138]="Green", +[52139]="Orange", +[52140]="Orange", +[52141]="Orange", +[52142]="Orange", +[52143]="Orange", +[52144]="Orange", +[52145]="Orange", +[52146]="Orange", +[52147]="Orange", +[52148]="Orange", +[52149]="Orange", +[52150]="Orange", +[52151]="Orange", +[52152]="Purple", +[52153]="Purple", +[52154]="Purple", +[52155]="Purple", +[52156]="Purple", +[52157]="Purple", +[52158]="Purple", +[52159]="Purple", +[52160]="Purple", +[52161]="Purple", +[52162]="Purple", +[52163]="Yellow", +[52164]="Yellow", +[52165]="Yellow", +[52166]="Yellow", +[52167]="Yellow", +[52168]="Blue", +[52169]="Blue", +[52170]="Blue", +[52171]="Blue", +[52172]="Red", +[52173]="Red", +[52174]="Red", +[52175]="Red", +[52176]="Red", +[52203]="Purple", +[52204]="Orange", +[52205]="Orange", +[52206]="Red", +[52207]="Red", +[52208]="Orange", +[52209]="Orange", +[52210]="Purple", +[52211]="Orange", +[52212]="Red", +[52213]="Purple", +[52214]="Orange", +[52215]="Orange", +[52216]="Red", +[52217]="Purple", +[52218]="Green", +[52219]="Yellow", +[52220]="Purple", +[52221]="Purple", +[52222]="Orange", +[52223]="Green", +[52224]="Orange", +[52225]="Green", +[52226]="Yellow", +[52227]="Green", +[52228]="Green", +[52229]="Orange", +[52230]="Red", +[52231]="Green", +[52232]="Yellow", +[52233]="Green", +[52234]="Purple", +[52235]="Blue", +[52236]="Purple", +[52237]="Green", +[52238]="Purple", +[52239]="Orange", +[52240]="Orange", +[52241]="Yellow", +[52242]="Blue", +[52243]="Purple", +[52244]="Blue", +[52245]="Green", +[52246]="Blue", +[52247]="Yellow", +[52248]="Purple", +[52249]="Orange", +[52250]="Green", +[52255]="Red", +[52257]="Red", +[52258]="Red", +[52259]="Red", +[52260]="Red", +[52261]="Blue", +[52262]="Blue", +[52263]="Blue", +[52264]="Blue", +[52265]="Yellow", +[52266]="Yellow", +[52267]="Yellow", +[52268]="Yellow", +[52269]="Yellow", +[52289]="Meta", +[52291]="Meta", +[52292]="Meta", +[52293]="Meta", +[52294]="Meta", +[52295]="Meta", +[52296]="Meta", +[52297]="Meta", +[52298]="Meta", +[52299]="Meta", +[52300]="Meta", +[52301]="Meta", +[52302]="Meta", +[54616]="Red", +[59477]="Cogwheel", +[59478]="Cogwheel", +[59479]="Cogwheel", +[59480]="Cogwheel", +[59489]="Cogwheel", +[59491]="Cogwheel", +[59493]="Cogwheel", +[59496]="Cogwheel", +[63696]="Red", +[63697]="Red", +[68356]="Orange", +[68357]="Orange", +[68358]="Orange", +[68660]="Cogwheel", +[68741]="Green", +[68778]="Meta", +[68779]="Meta", +[68780]="Meta", +[69922]="Red", +[69923]="Red", +[71817]="Blue", +[71818]="Blue", +[71819]="Blue", +[71820]="Blue", +[71822]="Green", +[71823]="Green", +[71824]="Green", +[71825]="Green", +[71826]="Green", +[71827]="Green", +[71828]="Green", +[71829]="Green", +[71830]="Green", +[71831]="Green", +[71832]="Green", +[71833]="Green", +[71834]="Green", +[71835]="Green", +[71836]="Green", +[71837]="Green", +[71838]="Green", +[71839]="Green", +[71840]="Orange", +[71841]="Orange", +[71842]="Orange", +[71843]="Orange", +[71844]="Orange", +[71845]="Orange", +[71846]="Orange", +[71847]="Orange", +[71848]="Orange", +[71849]="Orange", +[71850]="Orange", +[71851]="Orange", +[71852]="Orange", +[71853]="Orange", +[71854]="Orange", +[71855]="Orange", +[71856]="Orange", +[71857]="Orange", +[71858]="Orange", +[71859]="Orange", +[71860]="Orange", +[71861]="Orange", +[71862]="Purple", +[71863]="Purple", +[71864]="Purple", +[71865]="Purple", +[71866]="Purple", +[71867]="Purple", +[71868]="Purple", +[71869]="Purple", +[71870]="Purple", +[71871]="Purple", +[71872]="Purple", +[71873]="Purple", +[71874]="Yellow", +[71875]="Yellow", +[71876]="Yellow", +[71877]="Yellow", +[71878]="Yellow", +[71879]="Red", +[71880]="Red", +[71881]="Red", +[71882]="Red", +[71883]="Red", +[76502]="Blue", +[76504]="Blue", +[76505]="Blue", +[76506]="Blue", +[76507]="Green", +[76508]="Green", +[76509]="Green", +[76510]="Green", +[76511]="Green", +[76512]="Green", +[76513]="Green", +[76514]="Green", +[76515]="Green", +[76517]="Green", +[76518]="Green", +[76519]="Green", +[76520]="Green", +[76521]="Green", +[76522]="Green", +[76523]="Green", +[76524]="Green", +[76525]="Green", +[76526]="Orange", +[76527]="Orange", +[76528]="Orange", +[76529]="Orange", +[76530]="Orange", +[76531]="Orange", +[76532]="Orange", +[76533]="Orange", +[76534]="Orange", +[76535]="Orange", +[76536]="Orange", +[76537]="Orange", +[76538]="Orange", +[76539]="Orange", +[76540]="Orange", +[76541]="Orange", +[76542]="Orange", +[76543]="Orange", +[76544]="Orange", +[76545]="Orange", +[76546]="Orange", +[76547]="Orange", +[76548]="Purple", +[76549]="Purple", +[76550]="Purple", +[76551]="Purple", +[76552]="Purple", +[76553]="Purple", +[76554]="Purple", +[76555]="Purple", +[76556]="Purple", +[76557]="Purple", +[76558]="Purple", +[76559]="Purple", +[76560]="Red", +[76561]="Red", +[76562]="Red", +[76563]="Red", +[76564]="Red", +[76565]="Yellow", +[76566]="Yellow", +[76567]="Yellow", +[76568]="Yellow", +[76569]="Yellow", +[76570]="Blue", +[76571]="Blue", +[76572]="Blue", +[76573]="Blue", +[76574]="Green", +[76575]="Green", +[76576]="Green", +[76577]="Green", +[76578]="Green", +[76579]="Green", +[76580]="Green", +[76581]="Green", +[76582]="Green", +[76583]="Green", +[76584]="Green", +[76585]="Green", +[76586]="Green", +[76587]="Green", +[76588]="Green", +[76589]="Green", +[76590]="Green", +[76591]="Green", +[76592]="Orange", +[76593]="Orange", +[76594]="Orange", +[76595]="Orange", +[76596]="Orange", +[76597]="Orange", +[76598]="Orange", +[76599]="Orange", +[76600]="Orange", +[76601]="Orange", +[76602]="Orange", +[76603]="Orange", +[76604]="Orange", +[76605]="Orange", +[76606]="Orange", +[76607]="Orange", +[76608]="Orange", +[76609]="Orange", +[76610]="Orange", +[76611]="Orange", +[76612]="Orange", +[76613]="Orange", +[76614]="Purple", +[76615]="Purple", +[76616]="Purple", +[76617]="Purple", +[76618]="Purple", +[76619]="Purple", +[76620]="Purple", +[76621]="Purple", +[76622]="Purple", +[76623]="Purple", +[76624]="Purple", +[76625]="Purple", +[76626]="Red", +[76627]="Red", +[76628]="Red", +[76629]="Red", +[76630]="Red", +[76631]="Yellow", +[76632]="Yellow", +[76633]="Yellow", +[76634]="Yellow", +[76635]="Yellow", +[76636]="Blue", +[76637]="Blue", +[76638]="Blue", +[76639]="Blue", +[76640]="Green", +[76641]="Green", +[76642]="Green", +[76643]="Green", +[76644]="Green", +[76645]="Green", +[76646]="Green", +[76647]="Green", +[76648]="Green", +[76649]="Green", +[76650]="Green", +[76651]="Green", +[76652]="Green", +[76653]="Green", +[76654]="Green", +[76655]="Green", +[76656]="Green", +[76657]="Green", +[76658]="Orange", +[76659]="Orange", +[76660]="Orange", +[76661]="Orange", +[76662]="Orange", +[76663]="Orange", +[76664]="Orange", +[76665]="Orange", +[76666]="Orange", +[76667]="Orange", +[76668]="Orange", +[76669]="Orange", +[76670]="Orange", +[76671]="Orange", +[76672]="Orange", +[76673]="Orange", +[76674]="Orange", +[76675]="Orange", +[76676]="Orange", +[76677]="Orange", +[76678]="Orange", +[76679]="Orange", +[76680]="Purple", +[76681]="Purple", +[76682]="Purple", +[76683]="Purple", +[76684]="Purple", +[76685]="Purple", +[76686]="Purple", +[76687]="Purple", +[76688]="Purple", +[76689]="Purple", +[76690]="Purple", +[76691]="Purple", +[76692]="Red", +[76693]="Red", +[76694]="Red", +[76695]="Red", +[76696]="Red", +[76697]="Yellow", +[76698]="Yellow", +[76699]="Yellow", +[76700]="Yellow", +[76701]="Yellow", +[76879]="Meta", +[76884]="Meta", +[76885]="Meta", +[76886]="Meta", +[76887]="Meta", +[76888]="Meta", +[76890]="Meta", +[76891]="Meta", +[76892]="Meta", +[76893]="Meta", +[76894]="Meta", +[76895]="Meta", +[76896]="Meta", +[76897]="Meta", +[77130]="Green", +[77131]="Green", +[77132]="Orange", +[77133]="Purple", +[77134]="Yellow", +[77136]="Orange", +[77137]="Green", +[77138]="Orange", +[77139]="Green", +[77140]="Blue", +[77141]="Orange", +[77142]="Green", +[77143]="Green", +[77144]="Orange", +[77154]="Green", +[77540]="Cogwheel", +[77541]="Cogwheel", +[77542]="Cogwheel", +[77543]="Cogwheel", +[77544]="Cogwheel", +[77545]="Cogwheel", +[77546]="Cogwheel", +[77547]="Cogwheel", +[83141]="Red", +[83142]="Yellow", +[83143]="Yellow", +[83144]="Blue", +[83145]="Yellow", +[83146]="Yellow", +[83147]="Red", +[83148]="Blue", +[83149]="Blue", +[83150]="Red", +[83151]="Red", +[83152]="Red", +[88911]="Green", +[88912]="Green", +[88913]="Green", +[88914]="Green", +[88915]="Green", +[88916]="Green", +[88917]="Green", +[88918]="Green", +[88919]="Green", +[88920]="Green", +[88921]="Green", +[88922]="Green", +[88923]="Green", +[88924]="Green", +[88925]="Green", +[88926]="Green", +[88927]="Green", +[88928]="Green", +[88930]="Orange", +[88931]="Orange", +[88932]="Orange", +[88933]="Orange", +[88934]="Orange", +[88935]="Orange", +[88936]="Orange", +[88937]="Orange", +[88938]="Orange", +[88939]="Orange", +[88940]="Orange", +[88941]="Orange", +[88942]="Orange", +[88943]="Orange", +[88944]="Orange", +[88945]="Orange", +[88946]="Orange", +[88947]="Orange", +[88948]="Orange", +[88949]="Orange", +[88950]="Orange", +[88951]="Orange", +[88952]="Purple", +[88953]="Purple", +[88954]="Purple", +[88955]="Purple", +[88956]="Purple", +[88958]="Purple", +[88959]="Purple", +[88960]="Purple", +[88961]="Purple", +[88962]="Purple", +[88963]="Purple", +[88987]="Purple", +[89674]="Purple", +[89675]="Purple", +[89676]="Purple", +[89677]="Purple", +[89678]="Purple", +[89679]="Purple", +[89680]="Purple", +[89681]="Purple", +[89873]="Hydraulic", +[89881]="Hydraulic", +[89882]="Hydraulic", +[93364]="Hydraulic", +[93365]="Hydraulic", +[93366]="Hydraulic", +[93404]="Orange", +[93405]="Orange", +[93406]="Orange", +[93408]="Purple", +[93409]="Purple", +[93410]="Purple", +[93705]="Green", +[93706]="Green", +[93707]="Green", +[93708]="Green", +[95344]="Meta", +[95345]="Meta", +[95346]="Meta", +[95347]="Meta", +[95348]="Meta"} + +AskMrRobot.alternateGemName = { +[23094]="6 Int", +[23095]="6 Str", +[23096]="7 Int", +[23097]="6 Agi", +[23098]="3 Str, 6 Crit", +[23099]="3 Int, 6 Haste", +[23100]="3 Agi, 6 Hit", +[23101]="6 Int, 3 Crit", +[23103]="3 PvP Pow, 6 Crit", +[23104]="4 Stam, 6 Crit", +[23105]="4 Stam, 6 Dodge", +[23106]="3 Int, 6 Spirit", +[23108]="3 Int, 4 Stam", +[23109]="3 Int, 6 Spirit", +[23110]="3 Agi, 4 Stam", +[23111]="3 Str, 4 Stam", +[23113]="6 Int", +[23114]="12 Crit", +[23115]="12 Dodge", +[23116]="12 Hit", +[23118]="9 Stam", +[23119]="12 Spirit", +[23120]="6 PvP Pow", +[23121]="12 Spirit", +[23233]="8 Str", +[23234]="8 Agi", +[23235]="8 Stam", +[24027]="8 Str", +[24028]="8 Agi", +[24029]="8 Int", +[24030]="8 Int", +[24031]="8 Agi", +[24032]="16 Dodge", +[24033]="12 Stam", +[24035]="16 Spirit", +[24036]="16 Parry", +[24037]="16 Spirit", +[24039]="8 PvP Pow", +[24047]="8 Int", +[24048]="16 Crit", +[24050]="16 Crit", +[24051]="16 Hit", +[24052]="16 Dodge", +[24053]="8 Resil", +[24054]="4 Str, 6 Stam", +[24055]="4 Agi, 6 Stam", +[24056]="5 Int, 6 Stam", +[24057]="4 Int, 8 Spirit", +[24058]="8 Str, 4 Crit", +[24059]="4 Int, 8 Crit", +[24060]="4 Int, 8 Haste", +[24061]="4 Agi, 8 Hit", +[24062]="6 Stam, 8 Dodge", +[24065]="4 Int, 8 Spirit", +[24066]="4 PvP Pow, 8 Crit", +[24067]="6 Stam, 8 Crit", +[25890]="28 Crit, 1% Reflect", +[25894]="24 Crit", +[25895]="24 Crit, Snare", +[25896]="18 Stam, Stun", +[25897]="12 Int, 2% Threat", +[25898]="24 Dodge", +[25901]="12 Int", +[27679]="10 Resil", +[27777]="7 Int", +[27785]="3 Stam, 4 Crit", +[27786]="3 Stam, 4 Crit", +[27809]="3 Stam, 4 Crit", +[27812]="7 Int", +[27820]="3 Stam, 4 Crit", +[28118]="10 Int", +[28119]="10 Crit", +[28120]="10 Crit", +[28123]="5 Int, 5 Crit", +[28290]="12 Crit", +[28360]="7 Agi", +[28361]="7 Agi", +[28362]="10 Agi", +[28363]="5 Agi, 5 Crit", +[28458]="4 Str", +[28459]="4 Agi", +[28460]="4 Int", +[28461]="4 Int", +[28462]="4 Agi", +[28463]="6 Stam", +[28464]="8 Spirit", +[28465]="8 Spirit", +[28466]="4 Int", +[28467]="8 Crit", +[28468]="8 Hit", +[28469]="8 Crit", +[28470]="8 Dodge", +[28556]="10 Crit", +[28557]="10 Int", +[28595]="6 Agi", +[30546]="5 Str, 6 Stam", +[30547]="5 Int, 4 Haste", +[30548]="6 Stam, 10 Crit", +[30549]="5 Agi, 6 Stam", +[30550]="10 Crit, 8 Spirit", +[30551]="5 Int, 4 Haste", +[30552]="5 Int, 6 Stam", +[30553]="5 Agi, 4 Hit", +[30554]="5 Parry, 4 Dodge", +[30555]="5 Int, 6 Stam", +[30556]="5 Agi, 4 Hit", +[30558]="5 Parry, 4 Dodge", +[30559]="5 Str, 4 Hit", +[30560]="5 Crit, 4 Spirit", +[30563]="6 Stam, 5 Dodge", +[30564]="5 Int, 4 Hit", +[30565]="6 Stam, 5 Crit", +[30566]="6 Stam, 5 Parry", +[30571]="8 Str", +[30572]="5 Int, 10 Spirit", +[30573]="5 Int, 5 PvP Pow", +[30574]="5 Agi, 6 Stam", +[30575]="5 Dodge, 4 Hit", +[30581]="5 Int, 4 Resil", +[30582]="5 Agi, 4 Crit", +[30583]="5 Int, 6 Stam", +[30584]="5 Str, 4 Crit", +[30585]="4 Agi, 5 Dodge", +[30586]="5 Int, 4 Spirit", +[30587]="5 Str, 4 Dodge", +[30588]="5 Int, 4 Crit", +[30589]="5 Int, 4 Spirit", +[30590]="6 Stam, 5 Dodge", +[30591]="5 Agi, 4 Resil", +[30592]="6 Stam, 5 Resil", +[30593]="5 Int, 4 Crit", +[30594]="6 Stam, 5 Dodge", +[30598]="8 Str", +[30600]="5 Int, 4 Spirit", +[30601]="5 Resil, 6 Stam", +[30602]="6 Stam, 5 Crit", +[30603]="5 Int, 8 Spirit", +[30604]="5 Str, 4 Resil", +[30605]="10 Hit, 8 Dodge", +[30606]="10 Hit, 8 Haste", +[30607]="4 Resil, 5 Parry", +[30608]="5 PvP Pow, 5 Crit", +[31116]="5 Int, 6 Stam", +[31117]="5 Int, 6 Stam", +[31118]="5 Str, 6 Stam", +[31860]="12 Hit", +[31861]="16 Hit", +[31862]="3 Agi, 4 Stam", +[31863]="4 Agi, 6 Stam", +[31864]="3 Agi, 4 Stam", +[31865]="4 Agi, 8 Hit", +[31866]="3 Int, 6 Hit", +[31867]="4 Int, 8 Hit", +[31868]="4 Agi, 8 Crit", +[31869]="6 Agi, 3 Crit", +[32193]="10 Str", +[32194]="10 Agi", +[32195]="10 Int", +[32196]="10 Int", +[32197]="20 Agi", +[32198]="20 Dodge", +[32199]="20 Parry", +[32200]="15 Stam", +[32201]="20 Spirit", +[32202]="20 Spirit", +[32203]="10 PvP Pow", +[32204]="10 Int", +[32205]="20 Crit", +[32206]="20 Hit", +[32207]="20 Crit", +[32208]="20 Dodge", +[32209]="10 Resil", +[32210]="20 Hit", +[32211]="5 Str, 7 Stam", +[32212]="5 Agi, 7 Stam", +[32213]="5 Agi, 7 Stam", +[32214]="5 Agi, 10 Hit", +[32215]="5 Int, 7 Stam", +[32216]="5 Int, 10 Spirit", +[32217]="5 Str, 10 Crit", +[32218]="5 Int, 10 Crit", +[32219]="5 Int, 10 Haste", +[32220]="5 Agi, 10 Hit", +[32221]="5 Int, 10 Hit", +[32222]="5 Agi, 10 Crit", +[32223]="7 Stam, 10 Dodge", +[32224]="5 PvP Pow, 10 Crit", +[32225]="5 Int, 10 Spirit", +[32226]="7 Stam, 10 Crit", +[32409]="12 Agi", +[32634]="5 Agi, 6 Stam", +[32635]="4 Int, 6 Stam", +[32636]="5 Int, 4 Spirit", +[32637]="5 Agi, 8 Crit", +[32638]="5 Int, 4 Haste", +[32639]="4 Stam, 4 Crit", +[32640]="12 Crit", +[32641]="12 Int", +[32735]="10 Agi", +[32833]="3 Int, 6 Spirit", +[32836]="4 Int, 8 Spirit", +[33060]="8 Agi", +[33131]="12 Agi", +[33132]="12 Agi", +[33133]="12 Int", +[33134]="12 Int", +[33135]="18 Stam", +[33137]="24 Spirit", +[33138]="12 Resil", +[33139]="12 Int", +[33140]="24 Crit", +[33141]="24 Hit", +[33142]="24 Hit", +[33143]="24 Crit", +[33144]="24 Dodge", +[33782]="4 Resil, 6 Stam", +[34220]="24 Crit, 3% Crit Efct", +[34256]="15 Stam", +[34831]="15 Stam", +[35315]="16 Haste", +[35316]="4 Int, 8 Haste", +[35318]="6 Stam, 8 Haste", +[35487]="10 Agi", +[35488]="10 Int", +[35489]="10 Int", +[35501]="24 Dodge, 1% Block", +[35503]="12 Int, 2% Mana", +[35707]="6 Stam, 4 Dodge", +[35758]="5 Resil, 7 Stam", +[35759]="7 Stam, 5 Haste", +[35760]="5 Int, 10 Haste", +[35761]="20 Haste", +[36766]="34 Agi", +[36767]="51 Stam", +[37430]="24 Stam", +[37503]="5 Int, 10 Spirit", +[38292]="150 Armor", +[38545]="10 Agi", +[38546]="10 Crit", +[38547]="5 Agi, 5 Crit", +[38548]="5 Int, 5 Crit", +[38549]="10 Int", +[38550]="10 Crit", +[39900]="12 Str", +[39905]="12 Agi", +[39906]="12 Agi", +[39907]="24 Dodge", +[39908]="24 Parry", +[39909]="24 Crit", +[39910]="24 Exp", +[39911]="12 Int", +[39912]="12 Int", +[39914]="24 Crit", +[39915]="24 Hit", +[39916]="24 Dodge", +[39917]="12 Resil", +[39918]="24 Haste", +[39919]="18 Stam", +[39920]="24 Spirit", +[39927]="24 Spirit", +[39932]="12 PvP Pow", +[39933]="9 Stam, 12 Crit", +[39934]="6 Str, 9 Stam", +[39935]="6 Agi, 9 Stam", +[39936]="6 Int, 9 Stam", +[39937]="6 Agi, 9 Stam", +[39938]="9 Stam, 12 Dodge", +[39939]="9 Stam, 12 Parry", +[39940]="9 Stam, 12 Exp", +[39941]="6 Int, 12 Spirit", +[39942]="6 Agi, 12 Hit", +[39943]="6 Int, 12 Spirit", +[39944]="6 Agi, 12 Hit", +[39945]="6 Int, 6 PvP Pow", +[39946]="6 Int, 12 Haste", +[39947]="6 Str, 12 Crit", +[39948]="6 Str, 12 Hit", +[39949]="6 Str, 12 Dodge", +[39950]="6 Str, 6 Resil", +[39951]="6 Str, 12 Haste", +[39952]="6 Agi, 12 Crit", +[39953]="6 Agi, 12 Hit", +[39954]="6 Agi, 6 Resil", +[39955]="6 Agi, 12 Haste", +[39956]="6 Int, 12 Crit", +[39957]="6 Int, 12 Hit", +[39958]="6 Int, 6 Resil", +[39959]="6 Int, 12 Haste", +[39960]="6 Agi, 12 Crit", +[39961]="6 Agi, 12 Hit", +[39962]="6 Agi, 6 Resil", +[39963]="6 Agi, 12 Haste", +[39964]="12 Dodge, 12 Parry", +[39965]="12 Parry, 12 Dodge", +[39966]="12 Exp, 12 Hit", +[39967]="12 Exp, 12 Dodge", +[39968]="6 Int, 9 Stam", +[39974]="9 Stam, 12 Crit", +[39975]="12 Hit, 12 Dodge", +[39976]="9 Stam, 12 Dodge", +[39977]="6 Resil, 9 Stam", +[39978]="9 Stam, 12 Haste", +[39979]="6 Int, 12 Spirit", +[39980]="12 Crit, 12 Spirit", +[39981]="12 Hit, 12 Haste", +[39982]="6 Resil, 12 Spirit", +[39983]="12 Haste, 12 Spirit", +[39984]="6 Int, 12 Spirit", +[39985]="12 Crit, 12 Spirit", +[39986]="12 Hit, 12 Haste", +[39988]="6 Resil, 12 Spirit", +[39989]="12 Haste, 12 Spirit", +[39990]="6 PvP Pow, 12 Crit", +[39991]="6 PvP Pow, 12 Crit", +[39992]="6 PvP Pow, 12 Haste", +[39996]="16 Str", +[39997]="16 Agi", +[39998]="16 Int", +[39999]="16 Agi", +[40000]="32 Dodge", +[40001]="32 Parry", +[40002]="32 Crit", +[40003]="32 Exp", +[40008]="24 Stam", +[40009]="32 Spirit", +[40010]="32 Spirit", +[40011]="16 PvP Pow", +[40012]="16 Int", +[40013]="32 Crit", +[40014]="32 Hit", +[40015]="32 Dodge", +[40016]="16 Resil", +[40017]="32 Haste", +[40022]="8 Str, 12 Stam", +[40023]="8 Agi, 12 Stam", +[40024]="8 Agi, 16 Hit", +[40025]="8 Int, 12 Stam", +[40026]="8 Int, 16 Spirit", +[40027]="8 Int, 16 Spirit", +[40028]="8 Int, 8 PvP Pow", +[40029]="8 Agi, 12 Stam", +[40030]="8 Agi, 16 Hit", +[40031]="12 Stam, 16 Dodge", +[40032]="12 Stam, 16 Parry", +[40033]="12 Stam, 16 Crit", +[40034]="12 Stam, 16 Exp", +[40037]="8 Str, 16 Crit", +[40038]="8 Str, 16 Hit", +[40039]="8 Str, 16 Dodge", +[40040]="8 Str, 8 Resil", +[40041]="8 Str, 16 Haste", +[40043]="8 Agi, 16 Crit", +[40044]="8 Agi, 16 Hit", +[40045]="8 Agi, 8 Resil", +[40046]="8 Agi, 16 Haste", +[40047]="8 Int, 16 Haste", +[40048]="8 Int, 16 Crit", +[40049]="8 Int, 16 Hit", +[40050]="8 Int, 8 Resil", +[40051]="8 Int, 16 Haste", +[40052]="8 Agi, 16 Crit", +[40053]="8 Agi, 16 Hit", +[40054]="8 Agi, 8 Resil", +[40055]="8 Agi, 16 Haste", +[40056]="16 Dodge, 16 Parry", +[40057]="16 Parry, 16 Dodge", +[40058]="16 Exp, 16 Hit", +[40059]="16 Exp, 16 Dodge", +[40085]="8 Int, 12 Stam", +[40086]="12 Stam, 16 Crit", +[40088]="16 Hit, 16 Dodge", +[40089]="12 Stam, 16 Dodge", +[40090]="8 Resil, 12 Stam", +[40091]="12 Stam, 16 Haste", +[40092]="8 Int, 16 Spirit", +[40094]="8 Int, 16 Spirit", +[40095]="16 Crit, 16 Spirit", +[40096]="16 Crit, 16 Spirit", +[40098]="8 PvP Pow, 16 Crit", +[40099]="16 Hit, 16 Haste", +[40100]="16 Hit, 16 Haste", +[40101]="8 PvP Pow, 16 Crit", +[40102]="8 Resil, 16 Spirit", +[40103]="16 Resil, 8 Spirit", +[40104]="16 Haste, 16 Spirit", +[40105]="16 Haste, 16 Spirit", +[40106]="8 PvP Pow, 16 Haste", +[40111]="20 Str", +[40112]="20 Agi", +[40113]="20 Int", +[40114]="20 Agi", +[40115]="40 Dodge", +[40116]="40 Parry", +[40117]="40 Crit", +[40118]="40 Exp", +[40119]="30 Stam", +[40120]="40 Spirit", +[40121]="40 Spirit", +[40122]="20 PvP Pow", +[40123]="20 Int", +[40124]="40 Crit", +[40125]="40 Hit", +[40126]="40 Dodge", +[40127]="20 Resil", +[40128]="40 Haste", +[40129]="10 Str, 15 Stam", +[40130]="10 Agi, 15 Stam", +[40131]="10 Agi, 20 Hit", +[40132]="10 Int, 15 Stam", +[40133]="10 Int, 20 Spirit", +[40134]="10 Int, 20 Spirit", +[40135]="10 Int, 10 PvP Pow", +[40136]="10 Agi, 15 Stam", +[40137]="10 Agi, 20 Hit", +[40138]="15 Stam, 20 Dodge", +[40139]="15 Stam, 20 Parry", +[40140]="15 Stam, 20 Crit", +[40141]="15 Stam, 20 Exp", +[40142]="10 Str, 20 Crit", +[40143]="10 Str, 20 Hit", +[40144]="10 Str, 20 Dodge", +[40145]="10 Str, 10 Resil", +[40146]="10 Str, 20 Haste", +[40147]="10 Agi, 20 Crit", +[40148]="10 Agi, 20 Hit", +[40149]="10 Agi, 10 Resil", +[40150]="10 Agi, 20 Haste", +[40151]="10 Int, 20 Spirit", +[40152]="10 Int, 20 Crit", +[40153]="10 Int, 20 Hit", +[40154]="10 Int, 10 Resil", +[40155]="10 Int, 10 Haste", +[40156]="10 Agi, 20 Crit", +[40157]="10 Agi, 20 Hit", +[40158]="10 Agi, 10 Resil", +[40159]="10 Agi, 20 Haste", +[40160]="20 Dodge, 20 Parry", +[40161]="20 Parry, 20 Dodge", +[40162]="20 Exp, 20 Hit", +[40163]="20 Exp, 20 Dodge", +[40164]="10 Int, 15 Stam", +[40165]="15 Stam, 20 Crit", +[40166]="20 Hit, 20 Dodge", +[40167]="15 Stam, 20 Dodge", +[40168]="10 Resil, 15 Stam", +[40169]="15 Stam, 20 Haste", +[40170]="10 Int, 20 Spirit", +[40171]="20 Crit, 20 Spirit", +[40172]="20 Hit, 20 Haste", +[40173]="10 Resil, 20 Spirit", +[40174]="20 Haste, 20 Spirit", +[40175]="10 Int, 20 Spirit", +[40176]="20 Crit, 20 Spirit", +[40177]="20 Hit, 20 Haste", +[40178]="10 Resil, 20 Spirit", +[40179]="10 Haste, 20 Spirit", +[40180]="10 PvP Pow, 20 Crit", +[40181]="10 PvP Pow, 20 Crit", +[40182]="10 PvP Pow, 20 Haste", +[41285]="42 Crit, 3% Crit Efct", +[41307]="50 Crit, 1% Reflect", +[41333]="21 Int, 2% Mana", +[41335]="42 Crit, Snare", +[41339]="42 Crit", +[41375]="21 Int", +[41376]="42 Spirit, 3% Crit Efct", +[41377]="32 Stam", +[41378]="21 Int, Silence", +[41379]="42 Crit, Fear", +[41380]="32 Stam, 2% Armor", +[41381]="42 Crit", +[41382]="21 Int", +[41385]="42 Haste", +[41389]="42 Crit", +[41395]="21 Int, 2% Threat", +[41396]="42 Dodge, 1% Block", +[41397]="32 Stam, Stun", +[41398]="21 Agi", +[41401]="21 Int", +[41429]="7 Agi, 14 Crit", +[41432]="14 Str", +[41433]="14 Agi", +[41434]="14 Agi", +[41435]="28 Parry", +[41436]="28 Crit", +[41437]="28 Exp", +[41438]="14 Int", +[41439]="28 Dodge", +[41440]="28 Spirit", +[41441]="21 Stam", +[41442]="28 Spirit", +[41443]="14 PvP Pow", +[41444]="14 Int", +[41445]="14 Resil", +[41446]="28 Haste", +[41447]="28 Hit", +[41448]="28 Crit", +[41449]="28 Dodge", +[41450]="7 Agi, 10 Stam", +[41451]="10 Stam, 14 Parry", +[41452]="7 Int, 10 Stam", +[41453]="10 Stam, 14 Exp", +[41454]="7 Agi, 14 Hit", +[41455]="7 Int, 7 PvP Pow", +[41456]="10 Stam, 14 Crit", +[41457]="7 Int, 14 Spirit", +[41458]="10 Stam, 14 Dodge", +[41459]="7 Int, 14 Spirit", +[41460]="7 Agi, 10 Stam", +[41461]="7 Str, 10 Stam", +[41462]="7 Agi, 14 Hit", +[41463]="7 Int, 14 Spirit", +[41464]="10 Stam, 14 Dodge", +[41465]="14 Haste, 14 Spirit", +[41466]="10 Stam, 14 Haste", +[41467]="14 Haste, 14 Spirit", +[41468]="10 Stam, 14 Crit", +[41469]="14 Hit, 14 Haste", +[41470]="14 Crit, 14 Spirit", +[41471]="7 Resil, 14 Spirit", +[41472]="7 PvP Pow, 14 Crit", +[41473]="7 Int, 14 Spirit", +[41474]="7 PvP Pow, 14 Haste", +[41475]="14 Hit, 14 Haste", +[41476]="7 Resil, 10 Stam", +[41477]="14 Crit, 14 Spirit", +[41478]="7 PvP Pow, 14 Crit", +[41479]="7 Int, 10 Stam", +[41480]="7 Resil, 14 Spirit", +[41481]="14 Hit, 14 Dodge", +[41482]="14 Exp, 14 Hit", +[41483]="7 Str, 7 Dodge", +[41484]="7 Agi, 14 Crit", +[41485]="7 Agi, 14 Haste", +[41486]="7 Int, 7 Resil", +[41487]="7 Agi, 7 Resil", +[41488]="7 Str, 14 Hit", +[41489]="7 Str, 14 Haste", +[41490]="14 Parry, 14 Dodge", +[41491]="7 Agi, 14 Hit", +[41492]="7 Str, 14 Crit", +[41493]="7 Agi, 7 Resil", +[41494]="7 Int, 14 Spirit", +[41495]="7 Int, 14 Crit", +[41496]="7 Agi, 14 Hit", +[41497]="7 Int, 14 Haste", +[41498]="14 Exp, 14 Dodge", +[41499]="7 Str, 7 Resil", +[41500]="14 Dodge, 14 Parry", +[41501]="7 Agi, 14 Haste", +[41502]="7 Int, 14 Hit", +[42142]="34 Str", +[42143]="34 Agi", +[42144]="34 Int", +[42145]="68 Spirit", +[42146]="68 Spirit", +[42148]="34 Int", +[42149]="68 Crit", +[42150]="68 Haste", +[42151]="68 Dodge", +[42152]="68 Parry", +[42153]="68 Crit", +[42154]="68 Exp", +[42155]="34 PvP Pow", +[42156]="68 Hit", +[42157]="68 Dodge", +[42158]="34 Resil", +[42701]="12 Str, 12 Agi, 12 Stam, 12 Int, 12 Spirit", +[42702]="64 Str, 64 Agi, 64 Stam, 64 Int, 64 Spirit", +[44066]="20 Resil", +[44076]="17 Crit", +[44078]="17 Int", +[44081]="17 Crit, Snare", +[44082]="17 Crit, Fear", +[44084]="17 Int, Silence", +[44087]="17 Crit", +[44088]="26 Stam, Stun", +[44089]="17 Int", +[45862]="20 Str", +[45879]="20 Agi", +[45880]="30 Stam", +[45881]="40 Spirit", +[45882]="20 Int", +[45883]="20 Int", +[45987]="40 Hit", +[49110]="0 Str, 0 Agi, 0 Stam, 0 Int, 0 Spirit", +[52070]="24 Stam, 24 Agi", +[52081]="30 Str", +[52082]="30 Agi", +[52083]="60 Parry", +[52084]="30 Int", +[52085]="60 Exp", +[52086]="45 Stam", +[52087]="60 Spirit", +[52088]="30 PvP Pow", +[52089]="60 Hit", +[52090]="60 Dodge", +[52091]="60 Crit", +[52092]="30 Resil", +[52093]="60 Haste", +[52094]="60 Mastery", +[52095]="15 Str, 23 Stam", +[52096]="15 Agi, 23 Stam", +[52097]="23 Stam, 30 Parry", +[52098]="15 Int, 23 Stam", +[52099]="23 Stam, 30 Exp", +[52100]="15 Int, 30 Spirit", +[52101]="15 Str, 30 Hit", +[52102]="15 Agi, 30 Hit", +[52103]="30 Parry, 30 Hit", +[52104]="15 Int, 30 Hit", +[52105]="30 Exp, 30 Hit", +[52106]="15 Agi, 30 Dodge", +[52107]="30 Exp, 30 Dodge", +[52108]="15 Str, 30 Crit", +[52109]="15 Agi, 30 Crit", +[52110]="15 Int, 30 Crit", +[52111]="15 Str, 30 Haste", +[52112]="15 Agi, 30 Haste", +[52113]="15 Int, 30 Haste", +[52114]="15 Str, 30 Mastery", +[52115]="15 Agi, 30 Mastery", +[52116]="30 Parry, 30 Mastery", +[52117]="15 Int, 30 Mastery", +[52118]="30 Exp, 30 Mastery", +[52119]="23 Stam, 30 Dodge", +[52120]="30 Dodge, 30 Hit", +[52121]="23 Stam, 30 Crit", +[52122]="30 Crit, 30 Hit", +[52123]="15 Resil, 23 Stam", +[52124]="23 Stam, 30 Haste", +[52125]="30 Haste, 30 Hit", +[52126]="23 Stam, 30 Mastery", +[52127]="30 Mastery, 30 Spirit", +[52128]="30 Mastery, 30 Hit", +[52129]="35 Mastery, 35 Hit", +[52130]="35 Mastery, 35 Spirit", +[52131]="26 Stam, 35 Mastery", +[52132]="35 Haste, 35 Hit", +[52133]="26 Stam, 35 Haste", +[52134]="18 Resil, 26 Stam", +[52135]="35 Crit, 35 Hit", +[52136]="26 Stam, 35 Crit", +[52137]="35 Dodge, 35 Hit", +[52138]="26 Stam, 35 Dodge", +[52139]="35 Exp, 35 Mastery", +[52140]="18 Int, 35 Mastery", +[52141]="35 Parry, 35 Mastery", +[52142]="18 Agi, 35 Mastery", +[52143]="18 Str, 35 Mastery", +[52144]="18 Int, 35 Haste", +[52145]="18 Agi, 35 Haste", +[52146]="18 Str, 35 Haste", +[52147]="18 Int, 35 Crit", +[52148]="18 Agi, 35 Crit", +[52149]="18 Str, 35 Crit", +[52150]="35 Exp, 35 Dodge", +[52151]="18 Agi, 35 Dodge", +[52152]="35 Exp, 35 Hit", +[52153]="18 Int, 35 Hit", +[52154]="35 Parry, 35 Hit", +[52155]="17 Agi, 35 Hit", +[52156]="18 Str, 35 Hit", +[52157]="18 Int, 35 Spirit", +[52158]="26 Stam, 35 Exp", +[52159]="18 Int, 26 Stam", +[52160]="26 Stam, 35 Parry", +[52161]="18 Agi, 26 Stam", +[52162]="18 Str, 26 Stam", +[52163]="70 Mastery", +[52164]="70 Haste", +[52165]="35 Resil", +[52166]="70 Crit", +[52167]="70 Dodge", +[52168]="70 Hit", +[52169]="35 PvP Pow", +[52170]="70 Spirit", +[52171]="53 Stam", +[52172]="70 Exp", +[52173]="35 Int", +[52174]="70 Parry", +[52175]="35 Agi", +[52176]="35 Str", +[52203]="40 Exp, 40 Hit", +[52204]="20 Agi, 40 Mastery", +[52205]="20 Int, 40 Mastery", +[52206]="40 Str", +[52207]="40 Int", +[52208]="20 Int, 40 Haste", +[52209]="20 Agi, 40 Crit", +[52210]="30 Stam, 40 Parry", +[52211]="20 Agi, 40 Haste", +[52212]="40 Agi", +[52213]="20 Str, 40 Hit", +[52214]="20 Str, 40 Haste", +[52215]="40 Parry, 40 Mastery", +[52216]="80 Parry", +[52217]="20 Int, 40 Hit", +[52218]="30 Stam, 40 Haste", +[52219]="80 Mastery", +[52220]="20 Agi, 40 Hit", +[52221]="30 Stam, 40 Exp", +[52222]="20 Str, 40 Crit", +[52223]="30 Stam, 40 Crit", +[52224]="40 Exp, 40 Mastery", +[52225]="40 Haste, 40 Hit", +[52226]="40 Resil", +[52227]="40 Dodge, 40 Hit", +[52228]="40 Crit, 40 Hit", +[52229]="20 Agi, 40 Dodge", +[52230]="80 Exp", +[52231]="30 Stam, 20 Mastery", +[52232]="80 Haste", +[52233]="30 Stam, 40 Dodge", +[52234]="40 Parry, 40 Hit", +[52235]="80 Hit", +[52236]="20 Int, 40 Spirit", +[52237]="40 Mastery, 40 Hit", +[52238]="20 Agi, 30 Stam", +[52239]="20 Int, 40 Crit", +[52240]="20 Str, 40 Mastery", +[52241]="80 Crit", +[52242]="60 Stam", +[52243]="20 Str, 30 Stam", +[52244]="80 Spirit", +[52245]="20 Resil, 30 Stam", +[52246]="40 PvP Pow", +[52247]="80 Dodge", +[52248]="20 Int, 30 Stam", +[52249]="40 Exp, 40 Dodge", +[52250]="40 Mastery, 40 Spirit", +[52255]="67 Str", +[52257]="67 Int", +[52258]="67 Agi", +[52259]="67 Parry", +[52260]="134 Exp", +[52261]="101 Stam", +[52262]="134 Spirit", +[52263]="67 PvP Pow", +[52264]="134 Hit", +[52265]="134 Dodge", +[52266]="134 Crit", +[52267]="67 Resil", +[52268]="134 Haste", +[52269]="134 Mastery", +[52289]="108 Mastery, Run Speed", +[52291]="108 Crit, 3% Crit Efct", +[52292]="54 Int, 2% Threat", +[52293]="81 Stam, 1% Block", +[52294]="81 Stam, 2% Armor", +[52295]="81 Stam", +[52296]="54 Int, 2% Mana", +[52297]="108 Spirit, 3% Crit Efct", +[52298]="108 Crit, 1% Reflect", +[52299]="81 Stam, Stun", +[52300]="108 Crit, Snare", +[52301]="108 Crit, Fear", +[52302]="54 Int, Silence", +[54616]="50 Str", +[59477]="208 Dodge", +[59478]="208 Crit", +[59479]="208 Haste", +[59480]="208 Mastery", +[59489]="208 Exp", +[59491]="208 Parry", +[59493]="208 Hit", +[59496]="208 Spirit", +[63696]="7 Str", +[63697]="7 Str", +[68356]="20 Int, 20 Resil", +[68357]="20 Agi, 20 Resil", +[68358]="20 Str, 20 Resil", +[68660]="52 Resil", +[68741]="20 Resil, 20 PvP Pow", +[68778]="54 Agi, 3% Crit Efct", +[68779]="54 Str, 3% Crit Efct", +[68780]="54 Int, 3% Crit Efct", +[69922]="50 Int", +[69923]="50 Agi", +[71817]="100 Hit", +[71818]="100 PvP Pow", +[71819]="100 Spirit", +[71820]="75 Stam", +[71822]="50 Spirit, 50 Crit", +[71823]="50 Crit, 50 Hit", +[71824]="50 Haste, 50 Hit", +[71825]="50 Hit, 50 Mastery", +[71826]="25 PvP Pow, 50 Mastery", +[71827]="50 Spirit, 50 Mastery", +[71828]="25 Resil, 50 Hit", +[71829]="25 PvP Pow, 25 Resil", +[71830]="25 Resil, 50 Spirit", +[71831]="25 PvP Pow, 50 Crit", +[71832]="25 PvP Pow, 50 Haste", +[71833]="50 Haste, 50 Spirit", +[71834]="37 Stam, 50 Crit", +[71835]="37 Stam, 50 Dodge", +[71836]="37 Stam, 50 Haste", +[71837]="50 Hit, 50 Dodge", +[71838]="37 Stam, 50 Mastery", +[71839]="25 Resil, 37 Stam", +[71840]="25 Agi, 50 Crit", +[71841]="50 Exp, 50 Crit", +[71842]="25 Int, 50 Crit", +[71843]="25 Str, 50 Crit", +[71844]="25 Agi, 50 Dodge", +[71845]="50 Exp, 50 Dodge", +[71846]="50 Parry, 50 Dodge", +[71847]="25 Str, 50 Dodge", +[71848]="25 Agi, 50 Haste", +[71849]="50 Exp, 50 Haste", +[71850]="25 Int, 50 Haste", +[71851]="25 Str, 50 Haste", +[71852]="25 Agi, 50 Mastery", +[71853]="50 Exp, 50 Mastery", +[71854]="25 Int, 50 Mastery", +[71855]="50 Parry, 50 Mastery", +[71856]="25 Str, 50 Mastery", +[71857]="25 Agi, 25 Resil", +[71858]="25 Resil, 50 Exp", +[71859]="25 Int, 25 Resil", +[71860]="25 Resil, 50 Parry", +[71861]="25 Str, 25 Resil", +[71862]="25 Agi, 50 Hit", +[71863]="50 Exp, 50 Hit", +[71864]="25 Int, 50 Hit", +[71865]="50 Parry, 50 Hit", +[71866]="25 Str, 50 Hit", +[71867]="25 Int, 25 PvP Pow", +[71868]="25 Int, 50 Spirit", +[71869]="25 Agi, 37 Stam", +[71870]="37 Stam, 50 Exp", +[71871]="25 Int, 37 Stam", +[71872]="37 Stam, 50 Parry", +[71873]="25 Str, 37 Stam", +[71874]="100 Crit", +[71875]="100 Dodge", +[71876]="100 Haste", +[71877]="100 Mastery", +[71878]="50 Resil", +[71879]="50 Agi", +[71880]="100 Exp", +[71881]="50 Int", +[71882]="100 Parry", +[71883]="50 Str", +[76502]="240 Hit", +[76504]="120 PvP Pow", +[76505]="240 Spirit", +[76506]="180 Stam", +[76507]="120 Spirit, 120 Crit", +[76508]="120 Crit, 120 Hit", +[76509]="120 Haste, 120 Hit", +[76510]="120 Hit, 120 Mastery", +[76511]="60 PvP Pow, 120 Mastery", +[76512]="120 Spirit, 120 Mastery", +[76513]="60 Resil, 120 Hit", +[76514]="60 PvP Pow, 60 Resil", +[76515]="60 Resil, 120 Spirit", +[76517]="60 PvP Pow, 120 Crit", +[76518]="60 PvP Pow, 120 Haste", +[76519]="120 Haste, 120 Spirit", +[76520]="90 Stam, 120 Crit", +[76521]="90 Stam, 120 Dodge", +[76522]="90 Stam, 120 Haste", +[76523]="90 Stam, 120 Hit", +[76524]="90 Stam, 120 Mastery", +[76525]="60 Resil, 90 Stam", +[76526]="60 Agi, 120 Crit", +[76527]="120 Exp, 120 Crit", +[76528]="60 Int, 120 Crit", +[76529]="60 Str, 120 Crit", +[76530]="60 Agi, 120 Dodge", +[76531]="120 Exp, 120 Dodge", +[76532]="120 Parry, 120 Dodge", +[76533]="60 Str, 120 Dodge", +[76534]="60 Agi, 120 Haste", +[76535]="120 Exp, 120 Haste", +[76536]="60 Int, 120 Haste", +[76537]="60 Str, 120 Haste", +[76538]="60 Agi, 120 Mastery", +[76539]="120 Exp, 120 Mastery", +[76540]="60 Int, 120 Mastery", +[76541]="120 Parry, 120 Mastery", +[76542]="60 Str, 120 Mastery", +[76543]="60 Agi, 60 Resil", +[76544]="60 Resil, 120 Exp", +[76545]="60 Int, 60 Resil", +[76546]="60 Resil, 120 Parry", +[76547]="60 Str, 60 Resil", +[76548]="60 Agi, 120 Hit", +[76549]="120 Exp, 120 Hit", +[76550]="60 Int, 120 Hit", +[76551]="120 Parry, 120 Hit", +[76552]="60 Str, 120 Hit", +[76553]="60 Int, 60 PvP Pow", +[76554]="60 Int, 120 Spirit", +[76555]="60 Agi, 90 Stam", +[76556]="90 Stam, 120 Exp", +[76557]="60 Int, 90 Stam", +[76558]="90 Stam, 120 Parry", +[76559]="60 Str, 90 Stam", +[76560]="120 Agi", +[76561]="240 Exp", +[76562]="120 Int", +[76563]="240 Parry", +[76564]="120 Str", +[76565]="240 Crit", +[76566]="240 Dodge", +[76567]="240 Haste", +[76568]="240 Mastery", +[76569]="120 Resil", +[76570]="320 Hit", +[76571]="160 PvP Pow", +[76572]="320 Spirit", +[76573]="240 Stam", +[76574]="160 Spirit, 160 Crit", +[76575]="160 Crit, 160 Hit", +[76576]="160 Haste, 160 Hit", +[76577]="160 Hit, 160 Mastery", +[76578]="80 PvP Pow, 160 Mastery", +[76579]="160 Spirit, 160 Mastery", +[76580]="80 Resil, 160 Hit", +[76581]="80 PvP Pow, 80 Resil", +[76582]="80 Resil, 160 Spirit", +[76583]="80 PvP Pow, 160 Crit", +[76584]="80 PvP Pow, 160 Haste", +[76585]="160 Haste, 160 Spirit", +[76586]="120 Stam, 160 Crit", +[76587]="120 Stam, 160 Dodge", +[76588]="120 Stam, 160 Haste", +[76589]="120 Stam, 160 Hit", +[76590]="120 Stam, 160 Mastery", +[76591]="80 Resil, 120 Stam", +[76592]="80 Agi, 160 Crit", +[76593]="160 Exp, 160 Crit", +[76594]="80 Int, 160 Crit", +[76595]="80 Str, 160 Crit", +[76596]="80 Agi, 160 Dodge", +[76597]="160 Exp, 160 Dodge", +[76598]="160 Parry, 160 Dodge", +[76599]="80 Str, 160 Dodge", +[76600]="80 Agi, 160 Haste", +[76601]="160 Exp, 160 Haste", +[76602]="80 Int, 160 Haste", +[76603]="80 Str, 160 Haste", +[76604]="80 Agi, 160 Mastery", +[76605]="160 Exp, 160 Mastery", +[76606]="80 Int, 160 Mastery", +[76607]="160 Parry, 160 Mastery", +[76608]="80 Str, 160 Mastery", +[76609]="80 Agi, 80 Resil", +[76610]="80 Resil, 160 Exp", +[76611]="80 Int, 80 Resil", +[76612]="80 Resil, 160 Parry", +[76613]="80 Str, 80 Resil", +[76614]="80 Agi, 160 Hit", +[76615]="160 Exp, 160 Hit", +[76616]="80 Int, 160 Hit", +[76617]="160 Parry, 160 Hit", +[76618]="80 Str, 160 Hit", +[76619]="80 Int, 80 PvP Pow", +[76620]="80 Int, 160 Spirit", +[76621]="80 Agi, 120 Stam", +[76622]="120 Stam, 160 Exp", +[76623]="80 Int, 120 Stam", +[76624]="120 Stam, 160 Parry", +[76625]="80 Str, 120 Stam", +[76626]="160 Agi", +[76627]="320 Exp", +[76628]="160 Int", +[76629]="320 Parry", +[76630]="160 Str", +[76631]="320 Crit", +[76632]="320 Dodge", +[76633]="320 Haste", +[76634]="320 Mastery", +[76635]="160 Resil", +[76636]="320 Hit", +[76637]="160 PvP Pow", +[76638]="320 Spirit", +[76639]="240 Stam", +[76640]="160 Spirit, 160 Crit", +[76641]="160 Crit, 160 Hit", +[76642]="160 Haste, 160 Hit", +[76643]="160 Hit, 160 Mastery", +[76644]="80 PvP Pow, 160 Mastery", +[76645]="160 Spirit, 160 Mastery", +[76646]="80 Resil, 160 Hit", +[76647]="80 PvP Pow, 80 Resil", +[76648]="80 Resil, 160 Spirit", +[76649]="80 PvP Pow, 160 Crit", +[76650]="80 PvP Pow, 160 Haste", +[76651]="160 Haste, 160 Spirit", +[76652]="120 Stam, 160 Crit", +[76653]="120 Stam, 160 Dodge", +[76654]="120 Stam, 160 Haste", +[76655]="120 Stam, 160 Hit", +[76656]="120 Stam, 160 Mastery", +[76657]="80 Resil, 120 Stam", +[76658]="80 Agi, 160 Crit", +[76659]="160 Exp, 160 Crit", +[76660]="80 Int, 160 Crit", +[76661]="80 Str, 160 Crit", +[76662]="80 Agi, 160 Dodge", +[76663]="160 Exp, 160 Dodge", +[76664]="160 Parry, 160 Dodge", +[76665]="80 Str, 160 Dodge", +[76666]="80 Agi, 160 Haste", +[76667]="160 Exp, 160 Haste", +[76668]="80 Int, 160 Haste", +[76669]="80 Str, 160 Haste", +[76670]="80 Agi, 160 Mastery", +[76671]="160 Exp, 160 Mastery", +[76672]="80 Int, 160 Mastery", +[76673]="160 Parry, 160 Mastery", +[76674]="80 Str, 160 Mastery", +[76675]="80 Agi, 80 Resil", +[76676]="80 Resil, 160 Exp", +[76677]="80 Int, 80 Resil", +[76678]="80 Resil, 160 Parry", +[76679]="80 Str, 80 Resil", +[76680]="80 Agi, 160 Hit", +[76681]="160 Exp, 160 Hit", +[76682]="80 Int, 160 Hit", +[76683]="160 Parry, 160 Hit", +[76684]="80 Str, 160 Hit", +[76685]="80 Int, 80 PvP Pow", +[76686]="80 Int, 160 Spirit", +[76687]="80 Agi, 120 Stam", +[76688]="120 Stam, 160 Exp", +[76689]="80 Int, 120 Stam", +[76690]="120 Stam, 160 Parry", +[76691]="80 Str, 120 Stam", +[76692]="160 Agi", +[76693]="320 Exp", +[76694]="160 Int", +[76695]="320 Parry", +[76696]="160 Str", +[76697]="320 Crit", +[76698]="320 Dodge", +[76699]="320 Haste", +[76700]="320 Mastery", +[76701]="160 Resil", +[76879]="216 Int, 2% Mana", +[76884]="216 Agi, 3% Crit Efct", +[76885]="216 Int, 3% Crit Efct", +[76886]="216 Str, 3% Crit Efct", +[76887]="432 Mastery, Run Speed", +[76888]="432 Spirit, 3% Crit Efct", +[76890]="432 Crit, 1% Reflect", +[76891]="324 Stam, Stun", +[76892]="432 Crit, Snare", +[76893]="432 Crit, Fear", +[76894]="216 Int, Silence", +[76895]="324 Stam, 2% Armor", +[76896]="432 Dodge, 1% Block", +[76897]="324 Stam", +[77130]="25 Resil, 50 Hit", +[77131]="25 PvP Pow, 50 Mastery", +[77132]="25 Agi, 25 Resil", +[77133]="25 Int, 25 PvP Pow", +[77134]="50 Resil", +[77136]="25 Str, 25 Resil", +[77137]="25 PvP Pow, 50 Haste", +[77138]="25 Resil, 50 Parry", +[77139]="25 Resil, 37 Stam", +[77140]="50 PvP Pow", +[77141]="25 Resil, 50 Exp", +[77142]="25 Resil, 50 Spirit", +[77143]="25 PvP Pow, 25 Resil", +[77144]="25 Int, 25 Resil", +[77154]="25 PvP Pow, 50 Crit", +[77540]="600 Dodge", +[77541]="600 Crit", +[77542]="600 Haste", +[77543]="600 Exp", +[77544]="600 Parry", +[77545]="600 Hit", +[77546]="600 Spirit", +[77547]="600 Mastery", +[83141]="320 Str", +[83142]="480 Haste", +[83143]="480 Mastery", +[83144]="480 Hit", +[83145]="480 Dodge", +[83146]="480 Crit", +[83147]="480 Exp", +[83148]="480 Stam", +[83149]="480 Spirit", +[83150]="320 Int", +[83151]="320 Agi", +[83152]="480 Parry", +[88911]="100 Resil, 200 Hit", +[88912]="100 PvP Pow, 200 Mastery", +[88913]="200 Haste, 200 Spirit", +[88914]="150 Stam, 200 Haste", +[88915]="150 Stam, 200 Crit", +[88916]="200 Haste, 200 Hit", +[88917]="200 Spirit, 200 Crit", +[88918]="150 Stam, 200 Hit", +[88919]="200 Crit, 200 Hit", +[88920]="150 Stam, 200 Mastery", +[88921]="100 PvP Pow, 200 Crit", +[88922]="150 Stam, 200 Dodge", +[88923]="200 Hit, 200 Mastery", +[88924]="100 PvP Pow, 200 Haste", +[88925]="100 Resil, 150 Stam", +[88926]="100 Resil, 200 Spirit", +[88927]="100 PvP Pow, 100 Resil", +[88928]="200 Spirit, 200 Mastery", +[88930]="100 Agi, 200 Mastery", +[88931]="100 Int, 200 Mastery", +[88932]="100 Str, 200 Dodge", +[88933]="200 Exp, 200 Crit", +[88934]="100 Agi, 200 Crit", +[88935]="100 Agi, 200 Haste", +[88936]="100 Str, 200 Haste", +[88937]="200 Parry, 200 Mastery", +[88938]="100 Str, 200 Crit", +[88939]="200 Exp, 200 Mastery", +[88940]="100 Agi, 100 Resil", +[88941]="100 Agi, 200 Dodge", +[88942]="100 Int, 200 Crit", +[88943]="100 Int, 200 Haste", +[88944]="200 Exp, 200 Dodge", +[88945]="100 Str, 100 Resil", +[88946]="100 Str, 200 Mastery", +[88947]="100 Resil, 200 Parry", +[88948]="200 Parry, 200 Dodge", +[88949]="100 Resil, 200 Exp", +[88950]="200 Exp, 200 Haste", +[88951]="100 Int, 100 Resil", +[88952]="200 Exp, 200 Hit", +[88953]="150 Stam, 200 Parry", +[88954]="100 Str, 200 Hit", +[88955]="100 Agi, 200 Hit", +[88956]="150 Stam, 200 Exp", +[88958]="100 Int, 200 Spirit", +[88959]="200 Parry, 200 Hit", +[88960]="100 Agi, 150 Stam", +[88961]="100 Str, 150 Stam", +[88962]="100 Int, 150 Stam", +[88963]="100 Int, 200 Hit", +[88987]="100 Int, 100 PvP Pow", +[89674]="80 Str, 80 PvP Pow", +[89675]="60 Str, 60 PvP Pow", +[89676]="80 Str, 80 PvP Pow", +[89677]="100 Str, 100 PvP Pow", +[89678]="60 Agi, 60 PvP Pow", +[89679]="80 Agi, 80 PvP Pow", +[89680]="80 Agi, 80 PvP Pow", +[89681]="100 Agi, 100 PvP Pow", +[89873]="500 Agi", +[89881]="500 Str", +[89882]="500 Int", +[93364]="550 Agi", +[93365]="550 Str", +[93366]="550 Int", +[93404]="160 Str, 160 Resil", +[93405]="160 Agi, 160 Resil", +[93406]="160 Int, 160 Resil", +[93408]="160 Str, 160 PvP Pow", +[93409]="160 Agi, 160 PvP Pow", +[93410]="160 Int, 160 PvP Pow", +[93705]="160 Hit, 160 Dodge", +[93706]="120 Hit, 120 Dodge", +[93707]="160 Hit, 160 Dodge", +[93708]="200 Hit, 200 Dodge", +[95344]="Indomitable", +[95345]="Courageous", +[95346]="Capacitive", +[95347]="Sinister", +[95348]="665 PvP Pow, 775 Resil"} + +AskMrRobot.gemDuplicates = { +[76570]=76636, +[76571]=76637, +[76572]=76638, +[76573]=76639, +[76574]=76640, +[76575]=76641, +[76576]=76642, +[76577]=76643, +[76578]=76644, +[76579]=76645, +[76580]=76646, +[76581]=76647, +[76582]=76648, +[76583]=76649, +[76584]=76650, +[76585]=76651, +[76586]=76652, +[76587]=76653, +[76588]=76654, +[76589]=76655, +[76590]=76656, +[76591]=76657, +[76592]=76658, +[76593]=76659, +[76594]=76660, +[76595]=76661, +[76596]=76662, +[76597]=76663, +[76598]=76664, +[76599]=76665, +[76600]=76666, +[76601]=76667, +[76602]=76668, +[76603]=76669, +[76604]=76670, +[76605]=76671, +[76606]=76672, +[76607]=76673, +[76608]=76674, +[76609]=76675, +[76610]=76676, +[76611]=76677, +[76612]=76678, +[76613]=76679, +[76614]=76680, +[76615]=76681, +[76616]=76682, +[76617]=76683, +[76618]=76684, +[76619]=76685, +[76620]=76686, +[76621]=76687, +[76622]=76688, +[76623]=76689, +[76624]=76690, +[76625]=76691, +[76626]=76692, +[76627]=76693, +[76628]=76694, +[76629]=76695, +[76630]=76696, +[76631]=76697, +[76632]=76698, +[76633]=76699, +[76634]=76700, +[76635]=76701, +[76636]=76570, +[76637]=76571, +[76638]=76572, +[76639]=76573, +[76640]=76574, +[76641]=76575, +[76642]=76576, +[76643]=76577, +[76644]=76578, +[76645]=76579, +[76646]=76580, +[76647]=76581, +[76648]=76582, +[76649]=76583, +[76650]=76584, +[76651]=76585, +[76652]=76586, +[76653]=76587, +[76654]=76588, +[76655]=76589, +[76656]=76590, +[76657]=76591, +[76658]=76592, +[76659]=76593, +[76660]=76594, +[76661]=76595, +[76662]=76596, +[76663]=76597, +[76664]=76598, +[76665]=76599, +[76666]=76600, +[76667]=76601, +[76668]=76602, +[76669]=76603, +[76670]=76604, +[76671]=76605, +[76672]=76606, +[76673]=76607, +[76674]=76608, +[76675]=76609, +[76676]=76610, +[76677]=76611, +[76678]=76612, +[76679]=76613, +[76680]=76614, +[76681]=76615, +[76682]=76616, +[76683]=76617, +[76684]=76618, +[76685]=76619, +[76686]=76620, +[76687]=76621, +[76688]=76622, +[76689]=76623, +[76690]=76624, +[76691]=76625, +[76692]=76626, +[76693]=76627, +[76694]=76628, +[76695]=76629, +[76696]=76630, +[76697]=76631, +[76698]=76632, +[76699]=76633, +[76700]=76634, +[76701]=76635, +[89674]=89676, +[89676]=89674, +[89679]=89680, +[89680]=89679, +[93705]=93707, +[93707]=93705} + +local gemEnchantDuplicates = { +[4520]=4587, +[4521]=4588, +[4522]=4589, +[4523]=4590, +[4524]=4591, +[4525]=4592, +[4526]=4593, +[4527]=4594, +[4528]=4595, +[4529]=4596, +[4530]=4597, +[4531]=4598, +[4532]=4599, +[4533]=4600, +[4535]=4601, +[4536]=4602, +[4537]=4603, +[4538]=4604, +[4539]=4605, +[4540]=4606, +[4541]=4607, +[4542]=4608, +[4543]=4609, +[4544]=4610, +[4545]=4611, +[4546]=4612, +[4547]=4613, +[4548]=4614, +[4549]=4615, +[4550]=4616, +[4551]=4617, +[4552]=4618, +[4553]=4619, +[4554]=4620, +[4555]=4621, +[4556]=4622, +[4557]=4623, +[4558]=4624, +[4559]=4625, +[4560]=4626, +[4561]=4627, +[4562]=4628, +[4563]=4629, +[4564]=4630, +[4565]=4631, +[4566]=4632, +[4567]=4633, +[4568]=4634, +[4569]=4635, +[4570]=4636, +[4571]=4637, +[4572]=4638, +[4573]=4652, +[4574]=4640, +[4575]=4641, +[4576]=4642, +[4577]=4643, +[4578]=4653, +[4579]=4644, +[4580]=4645, +[4581]=4646, +[4582]=4647, +[4583]=4648, +[4584]=4649, +[4585]=4650, +[4586]=4651, +[4587]=4520, +[4588]=4521, +[4589]=4522, +[4590]=4523, +[4591]=4524, +[4592]=4525, +[4593]=4526, +[4594]=4527, +[4595]=4528, +[4596]=4529, +[4597]=4530, +[4598]=4531, +[4599]=4532, +[4600]=4533, +[4601]=4535, +[4602]=4536, +[4603]=4537, +[4604]=4538, +[4605]=4539, +[4606]=4540, +[4607]=4541, +[4608]=4542, +[4609]=4543, +[4610]=4544, +[4611]=4545, +[4612]=4546, +[4613]=4547, +[4614]=4548, +[4615]=4549, +[4616]=4550, +[4617]=4551, +[4618]=4552, +[4619]=4553, +[4620]=4554, +[4621]=4555, +[4622]=4556, +[4623]=4557, +[4624]=4558, +[4625]=4559, +[4626]=4560, +[4627]=4561, +[4628]=4562, +[4629]=4563, +[4630]=4564, +[4631]=4565, +[4632]=4566, +[4633]=4567, +[4634]=4568, +[4635]=4569, +[4636]=4570, +[4637]=4571, +[4638]=4572, +[4652]=4573, +[4640]=4574, +[4641]=4575, +[4642]=4576, +[4643]=4577, +[4653]=4578, +[4644]=4579, +[4645]=4580, +[4646]=4581, +[4647]=4582, +[4648]=4583, +[4649]=4584, +[4650]=4585, +[4651]=4586, +[4984]=4986, +[4986]=4984, +[4989]=4990, +[4990]=4989, +[5024]=5026, +[5026]=5024} + +local perfectGems = { +[76570]=1, +[76571]=1, +[76572]=1, +[76573]=1, +[76574]=1, +[76575]=1, +[76576]=1, +[76577]=1, +[76578]=1, +[76579]=1, +[76580]=1, +[76581]=1, +[76582]=1, +[76583]=1, +[76584]=1, +[76585]=1, +[76586]=1, +[76587]=1, +[76588]=1, +[76589]=1, +[76590]=1, +[76591]=1, +[76592]=1, +[76593]=1, +[76594]=1, +[76595]=1, +[76596]=1, +[76597]=1, +[76598]=1, +[76599]=1, +[76600]=1, +[76601]=1, +[76602]=1, +[76603]=1, +[76604]=1, +[76605]=1, +[76606]=1, +[76607]=1, +[76608]=1, +[76609]=1, +[76610]=1, +[76611]=1, +[76612]=1, +[76613]=1, +[76614]=1, +[76615]=1, +[76616]=1, +[76617]=1, +[76618]=1, +[76619]=1, +[76620]=1, +[76621]=1, +[76622]=1, +[76623]=1, +[76624]=1, +[76625]=1, +[76626]=1, +[76627]=1, +[76628]=1, +[76629]=1, +[76630]=1, +[76631]=1, +[76632]=1, +[76633]=1, +[76634]=1, +[76635]=1, +[89676]=1, +[89679]=1, +[93707]=1} + +AskMrRobot.JewelcrafterGems = { +[36766]=1, +[36767]=1, +[42142]=1, +[42143]=1, +[42144]=1, +[42145]=1, +[42146]=1, +[42148]=1, +[42149]=1, +[42150]=1, +[42151]=1, +[42152]=1, +[42153]=1, +[42154]=1, +[42155]=1, +[42156]=1, +[42157]=1, +[42158]=1, +[52255]=1, +[52257]=1, +[52258]=1, +[52259]=1, +[52260]=1, +[52261]=1, +[52262]=1, +[52263]=1, +[52264]=1, +[52265]=1, +[52266]=1, +[52267]=1, +[52268]=1, +[52269]=1, +[83141]=1, +[83142]=1, +[83143]=1, +[83144]=1, +[83145]=1, +[83146]=1, +[83147]=1, +[83148]=1, +[83149]=1, +[83150]=1, +[83151]=1, +[83152]=1, +[93404]=1, +[93405]=1, +[93406]=1, +[93408]=1, +[93409]=1, +[93410]=1} + +local function DoGemsMatch(gemIdA, gemIdB) + return gemIdA == gemIdB or (gemIdA and gemIdB and gemIdA == AskMrRobot.gemDuplicates[gemIdB]) +end + +local function DoGemEnchantsMatch(gemEnchantIdA, gemEnchantIdB) + return gemEnchantIdA == gemEnchantIdB or (gemEnchantIdA and gemEnchantIdB and gemEnchantIdA == gemEnchantDuplicates[gemEnchantIdB]) +end + +local function GemMatchesSocket(gemId, socketColor) + local gemColor = gemToColor[gemId] + if socketColor == 'Red' then + return gemColor =='Red' or gemColor == 'Orange' or gemColor == 'Purple' + elseif socketColor == 'Yellow' then + return gemColor == 'Yellow' or gemColor == 'Orange' or gemColor == 'Green' + elseif socketColor == 'Blue' then + return gemColor == 'Blue' or gemColor == 'Purple' or gemColor == 'Green' + elseif socketColor == 'Prismatic' then + return gemColor == 'Prismatic' or gemColor == 'Orange' or gemColor == 'Green' or gemColor == 'Purple' or gemColor == 'Red' or gemColor == 'Yellow' or gemColor == 'Blue' + else + return gemColor == socketColor + end +end + +local function CanInsertGem(gemId, socketColor) + local gemColor = gemToColor[gemId] + return gemColor == socketColor or ((socketColor == 'Red' or socketColor == 'Yellow' or socketColor == 'Blue' or socketColor == 'Prismatic') + and (gemColor == 'Orange' or gemColor == 'Green' or gemColor == 'Purple' or gemColor == 'Red' or gemColor == 'Yellow' or gemColor == 'Blue')) +end + +-- in: [{id (gemId), color (socketColor)}] +-- out: bool +local function AmrExpectsSocketBonus(gems) + local i + for i = 1, #gems do + local gem = gems[i] + if gem.color and not GemMatchesSocket(gem.id, gem.color) then + return false + end + end + return true +end + +local function GetGemPermuations(gems) + local count = 0 + local i + for i = 1, #gems do + if gems[i].color then + count = count + 1 + end + end + if count == 0 then + return {} + elseif count == 1 then + return { { gems[1] } } + elseif count == 2 then + return { { gems[1], gems[2] } , { gems[2], gems[1] } } + elseif count == 3 then + return { { gems[1], gems[2], gems[3] } , { gems[1], gems[3], gems[2] }, + { gems[2], gems[1], gems[3] } , { gems[2], gems[3], gems[1] }, + { gems[3], gems[1], gems[2] } , { gems[3], gems[2], gems[1] } + } + end +end + +local function GetMatchingGems(gems, bonus) + local perms = GetGemPermuations(gems) + local i, j + local valid = {} + for i = 1, #perms do + local isValid = true + for j = 1, #perms[i] do + if bonus then + if not GemMatchesSocket(perms[i][j].id, gems[j].color) then + isValid = false + break + end + elseif not CanInsertGem(perms[i][j].id, gems[j].color) then + isValid = false + break + end + end + if isValid then + tinsert(valid, perms[i]) + end + end + return valid +end + +local function GetBestGems(existingItemLink, gems, bonus) + local perms = GetMatchingGems(gems, bonus) + local bestScore = -1 + local bestPerm = gems + for i = 1, #perms do + local score = 0 + for j = 1, #perms[i] do + local existingGemLink = select(2, GetItemGem(existingItemLink, j)) + if existingGemLink then + local existingGemId = AskMrRobot.getItemIdFromLink(existingGemLink) + if DoGemsMatch(perms[i][j].id, existingGemId) then + score = score + 1 + end + end + end + if score > bestScore then + bestScore = score + bestPerm = perms[i] + end + end + + local result = {} --make a new variable, because we don't want to change the original objects + for i = 1, #bestPerm do + --restore the color from the original. This only really changes when bonus is false + result[i] = {id = bestPerm[i].id, enchantId = bestPerm[i].enchantId, color = gems[i].color} + end + return result +end + +local function GetBadGems(existingItemLink, existingGemEnchantIds, gems) + local i + + local badGemCount = 0 + local result = { optimized = gems, current = existingGemEnchantIds, badGems = {}} + for i = 1, #gems do + -- get the current gem in the specified slot + local existingGemLink = select(2, GetItemGem(existingItemLink, i)) + local existingGemId = existingGemLink and AskMrRobot.getItemIdFromLink(existingGemLink) or 0 + gems[i].matched = DoGemsMatch(existingGemId, gems[i].id) + if not gems[i].matched then + result.badGems[i] = true + badGemCount = badGemCount + 1 + end + end + result.current.link = existingItemLink + + return badGemCount, result +end + +-- returns badGemCount and {optimized:[], current:[], badGems[]} +function AskMrRobot.MatchesGems(existingItemLink, existingGemEnchantIds, gems) + local bonus = AmrExpectsSocketBonus(gems) + local reorderedGems = GetBestGems(existingItemLink, gems, bonus) + return GetBadGems(existingItemLink, existingGemEnchantIds, reorderedGems) +end + + +local preferPerfectGems = false + +local function findItemInBag(bagId, itemId) + local numSlots = GetContainerNumSlots(bagId); + local lockedSlotId = nil + for slotId = 1, numSlots do + local _, itemCount, locked, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId); + if itemLink ~= nil then + local bagItemId = AskMrRobot.getItemIdFromLink(itemLink) + if itemId == bagItemId then + if locked then + lockedSlotId = slotId + else + return slotId, false + end + end + end + end + return lockedSlotId, lockedSlotId ~= nil +end + +-- returns bagId, badSlotId, isLocked +local function findItem(itemId) + local lockedSlotId, lockedBagId = nil, nil + local bagSlot, locked = findItemInBag(BACKPACK_CONTAINER, itemId) -- backpack + if bagSlot then + if locked then + lockedBagId = BACKPACK_CONTAINER + lockedSlotId = badGems + else + return BACKPACK_CONTAINER, bagSlot, false + end + end + + for bagId = 1, NUM_BAG_SLOTS do + bagSlot, locked = findItemInBag(bagId, itemId) + if locked then + lockedBagId = bagId + lockedSlotId = badGems + elseif bagSlot then + return bagId, bagSlot, false + end + end + + return lockedBagId, lockedSlotId, lockedSlotId ~= nil +end + +local autoGemCoRoutine = nil +local autoGemTime = nil + +local function checkAutoGemTimeout() + if autoGemTime and difftime(time(), autoGemTime) >= 5 then + autoGemTime = nil + autoGemCoRoutine = nil + return true + end + return false +end + +local function autoGemHelper(inventorySlotId, gemInfo, gemSlot) + -- get the gem id to socket + local gemId = gemInfo.optimized[gemSlot].id + + --loop forever until we get the item unlocked + while true do + --if preferPerfectGems then + --end + + -- attempt to find the gem in inventory + local bagId, bagSlot, locked = findItem(gemId) + local dupId = AskMrRobot.gemDuplicates[gemId] + if dupId ~= nil then + local bagId2, bagSlot2, locked2 = findItem(dupId) + if bagId == nil or (bagId2 ~= nil and perfectGems[dupId] == 1 and preferPerfectGems) then + bagId = bagId2 + bagSlot = bagSlot2 + locked = locked2 + end + end + + if locked or IsInventoryItemLocked(inventorySlotId) then + coroutine.yield() + if checkAutoGemTimeout() then + return + end + else + -- if found... + if bagId then + ClearCursor() + -- launch the gem ui with the item + SocketInventoryItem(inventorySlotId) + + if GetNumSockets() < gemSlot then + print('Ask Mr Robot: Something is wrong. There are not enough sockets on this item.') + + CloseSocketInfo() + ClearCursor() + return + end + + -- grab the gem from a bag + PickupContainerItem(bagId, bagSlot) + -- put the gem in the socket + ClickSocketButton(gemSlot) + -- -- save the changes + AcceptSockets() + -- close the UI + CloseSocketInfo() + ClearCursor() + end + break + end + end +end + +local function autoGem() + --http://wowprogramming.com/docs/api_categories#socket + for slotNum, gemInfo in AskMrRobot.sortSlots(AskMrRobot.itemDiffs.gems) do + local inventorySlotId = GetInventorySlotInfo(AskMrRobot.slotNames[slotNum]) + + -- do non-JC gems first + for gemSlot in pairs(gemInfo.badGems) do + if gemInfo.badGems[gemSlot] == true then + local gemId = gemInfo.optimized[gemSlot].id + if not AskMrRobot.JewelcrafterGems[gemId] then + autoGemHelper(inventorySlotId, gemInfo, gemSlot) + end + end + end + end + + for slotNum, gemInfo in AskMrRobot.sortSlots(AskMrRobot.itemDiffs.gems) do + local inventorySlotId = GetInventorySlotInfo(AskMrRobot.slotNames[slotNum]) + + -- do JC gems next + for gemSlot in pairs(gemInfo.badGems) do + if gemInfo.badGems[gemSlot] == true then + local gemId = gemInfo.optimized[gemSlot].id + if AskMrRobot.JewelcrafterGems[gemId] then + autoGemHelper(inventorySlotId, gemInfo, gemSlot) + end + end + end + end +end + +local function resumeAutoGemming() + if not autoGemCoRoutine then + return + end + if coroutine.status(autoGemCoRoutine) == 'dead' then + autoGemCoRoutine = nil + StaticPopup_Show('AUTOGEM_FINISHED') + return + end + if coroutine.status(autoGemCoRoutine) == 'suspended' then + coroutine.resume(autoGemCoRoutine) + if coroutine.status(autoGemCoRoutine) == 'dead' then + autoGemCoRoutine = nil + StaticPopup_Show('AUTOGEM_FINISHED') + end + return + end +end + +function AskMrRobot.AutoGem(preferPerfectGems1) + preferPerfectGems = preferPerfectGems1 + checkAutoGemTimeout() + if autoGemCoRoutine then + if coroutine.status(autoGemCoRoutine) == 'dead' then + autoGemCoRoutine = nil + else + return false + end + end + autoGemTime = time() + autoGemCoRoutine = coroutine.create(autoGem) + resumeAutoGemming() + return true +end + +function AskMrRobot.On_ITEM_UNLOCKED() + resumeAutoGemming() +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,240 @@ +--[[ $Id: CallbackHandler-1.0.lua 14 2010-08-09 00:43:38Z mikk $ ]] +local MAJOR, MINOR = "CallbackHandler-1.0", 6 +local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) + +if not CallbackHandler then return end -- No upgrade needed + +local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} + +-- Lua APIs +local tconcat = table.concat +local assert, error, loadstring = assert, error, loadstring +local setmetatable, rawset, rawget = setmetatable, rawset, rawget +local next, select, pairs, type, tostring = next, select, pairs, type, tostring + +-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded +-- List them here for Mikk's FindGlobals script +-- GLOBALS: geterrorhandler + +local xpcall = xpcall + +local function errorhandler(err) + return geterrorhandler()(err) +end + +local function CreateDispatcher(argCount) + local code = [[ + local next, xpcall, eh = ... + + local method, ARGS + local function call() method(ARGS) end + + local function dispatch(handlers, ...) + local index + index, method = next(handlers) + if not method then return end + local OLD_ARGS = ARGS + ARGS = ... + repeat + xpcall(call, eh) + index, method = next(handlers, index) + until not method + ARGS = OLD_ARGS + end + + return dispatch + ]] + + local ARGS, OLD_ARGS = {}, {} + for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end + code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", ")) + return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler) +end + +local Dispatchers = setmetatable({}, {__index=function(self, argCount) + local dispatcher = CreateDispatcher(argCount) + rawset(self, argCount, dispatcher) + return dispatcher +end}) + +-------------------------------------------------------------------------- +-- CallbackHandler:New +-- +-- target - target object to embed public APIs in +-- RegisterName - name of the callback registration API, default "RegisterCallback" +-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback" +-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API. + +function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused) + -- TODO: Remove this after beta has gone out + assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused") + + RegisterName = RegisterName or "RegisterCallback" + UnregisterName = UnregisterName or "UnregisterCallback" + if UnregisterAllName==nil then -- false is used to indicate "don't want this method" + UnregisterAllName = "UnregisterAllCallbacks" + end + + -- we declare all objects and exported APIs inside this closure to quickly gain access + -- to e.g. function names, the "target" parameter, etc + + + -- Create the registry object + local events = setmetatable({}, meta) + local registry = { recurse=0, events=events } + + -- registry:Fire() - fires the given event/message into the registry + function registry:Fire(eventname, ...) + if not rawget(events, eventname) or not next(events[eventname]) then return end + local oldrecurse = registry.recurse + registry.recurse = oldrecurse + 1 + + Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...) + + registry.recurse = oldrecurse + + if registry.insertQueue and oldrecurse==0 then + -- Something in one of our callbacks wanted to register more callbacks; they got queued + for eventname,callbacks in pairs(registry.insertQueue) do + local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. + for self,func in pairs(callbacks) do + events[eventname][self] = func + -- fire OnUsed callback? + if first and registry.OnUsed then + registry.OnUsed(registry, target, eventname) + first = nil + end + end + end + registry.insertQueue = nil + end + end + + -- Registration of a callback, handles: + -- self["method"], leads to self["method"](self, ...) + -- self with function ref, leads to functionref(...) + -- "addonId" (instead of self) with function ref, leads to functionref(...) + -- all with an optional arg, which, if present, gets passed as first argument (after self if present) + target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]]) + if type(eventname) ~= "string" then + error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2) + end + + method = method or eventname + + local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. + + if type(method) ~= "string" and type(method) ~= "function" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2) + end + + local regfunc + + if type(method) == "string" then + -- self["method"] calling style + if type(self) ~= "table" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2) + elseif self==target then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2) + elseif type(self[method]) ~= "function" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) + end + + if select("#",...)>=1 then -- this is not the same as testing for arg==nil! + local arg=select(1,...) + regfunc = function(...) self[method](self,arg,...) end + else + regfunc = function(...) self[method](self,...) end + end + else + -- function ref with self=object or self="addonId" or self=thread + if type(self)~="table" and type(self)~="string" and type(self)~="thread" then + error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2) + end + + if select("#",...)>=1 then -- this is not the same as testing for arg==nil! + local arg=select(1,...) + regfunc = function(...) method(arg,...) end + else + regfunc = method + end + end + + + if events[eventname][self] or registry.recurse<1 then + -- if registry.recurse<1 then + -- we're overwriting an existing entry, or not currently recursing. just set it. + events[eventname][self] = regfunc + -- fire OnUsed callback? + if registry.OnUsed and first then + registry.OnUsed(registry, target, eventname) + end + else + -- we're currently processing a callback in this registry, so delay the registration of this new entry! + -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency + registry.insertQueue = registry.insertQueue or setmetatable({},meta) + registry.insertQueue[eventname][self] = regfunc + end + end + + -- Unregister a callback + target[UnregisterName] = function(self, eventname) + if not self or self==target then + error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2) + end + if type(eventname) ~= "string" then + error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2) + end + if rawget(events, eventname) and events[eventname][self] then + events[eventname][self] = nil + -- Fire OnUnused callback? + if registry.OnUnused and not next(events[eventname]) then + registry.OnUnused(registry, target, eventname) + end + end + if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then + registry.insertQueue[eventname][self] = nil + end + end + + -- OPTIONAL: Unregister all callbacks for given selfs/addonIds + if UnregisterAllName then + target[UnregisterAllName] = function(...) + if select("#",...)<1 then + error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) + end + if select("#",...)==1 and ...==target then + error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) + end + + + for i=1,select("#",...) do + local self = select(i,...) + if registry.insertQueue then + for eventname, callbacks in pairs(registry.insertQueue) do + if callbacks[self] then + callbacks[self] = nil + end + end + end + for eventname, callbacks in pairs(events) do + if callbacks[self] then + callbacks[self] = nil + -- Fire OnUnused callback? + if registry.OnUnused and not next(callbacks) then + registry.OnUnused(registry, target, eventname) + end + end + end + end + end + end + + return registry +end + + +-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it +-- try to upgrade old implicit embeds since the system is selfcontained and +-- relies on closures to work. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,4 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="CallbackHandler-1.0.lua"/> +</Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/LibDBIcon-1.0/LibDBIcon-1.0.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,344 @@ +--[[ +Name: DBIcon-1.0 +Revision: $Rev: 25 $ +Author(s): Rabbit (rabbit.magtheridon@gmail.com) +Description: Allows addons to register to recieve a lightweight minimap icon as an alternative to more heavy LDB displays. +Dependencies: LibStub +License: GPL v2 or later. +]] + +--[[ +Copyright (C) 2008-2011 Rabbit + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]] + +----------------------------------------------------------------------- +-- DBIcon-1.0 +-- +-- Disclaimer: Most of this code was ripped from Barrel but fixed, streamlined +-- and cleaned up a lot so that it no longer sucks. +-- + +local DBICON10 = "LibDBIcon-1.0" +local DBICON10_MINOR = tonumber(("$Rev: 25 $"):match("(%d+)")) +if not LibStub then error(DBICON10 .. " requires LibStub.") end +local ldb = LibStub("LibDataBroker-1.1", true) +if not ldb then error(DBICON10 .. " requires LibDataBroker-1.1.") end +local lib = LibStub:NewLibrary(DBICON10, DBICON10_MINOR) +if not lib then return end + +lib.disabled = lib.disabled or nil +lib.objects = lib.objects or {} +lib.callbackRegistered = lib.callbackRegistered or nil +lib.notCreated = lib.notCreated or {} + +function lib:IconCallback(event, name, key, value, dataobj) + if lib.objects[name] then + if key == "icon" then + lib.objects[name].icon:SetTexture(value) + elseif key == "iconCoords" then + lib.objects[name].icon:UpdateCoord() + end + end +end +if not lib.callbackRegistered then + ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__icon", "IconCallback") + ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconCoords", "IconCallback") + lib.callbackRegistered = true +end + +-- Tooltip code ripped from StatBlockCore by Funkydude +local function getAnchors(frame) + local x, y = frame:GetCenter() + if not x or not y then return "CENTER" end + local hhalf = (x > UIParent:GetWidth()*2/3) and "RIGHT" or (x < UIParent:GetWidth()/3) and "LEFT" or "" + local vhalf = (y > UIParent:GetHeight()/2) and "TOP" or "BOTTOM" + return vhalf..hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP")..hhalf +end + +local function onEnter(self) + if self.isMoving then return end + local obj = self.dataObject + if obj.OnTooltipShow then + GameTooltip:SetOwner(self, "ANCHOR_NONE") + GameTooltip:SetPoint(getAnchors(self)) + obj.OnTooltipShow(GameTooltip) + GameTooltip:Show() + elseif obj.OnEnter then + obj.OnEnter(self) + end +end + +local function onLeave(self) + local obj = self.dataObject + GameTooltip:Hide() + if obj.OnLeave then obj.OnLeave(self) end +end + +-------------------------------------------------------------------------------- + +local onClick, onMouseUp, onMouseDown, onDragStart, onDragEnd, updatePosition + +do + local minimapShapes = { + ["ROUND"] = {true, true, true, true}, + ["SQUARE"] = {false, false, false, false}, + ["CORNER-TOPLEFT"] = {false, false, false, true}, + ["CORNER-TOPRIGHT"] = {false, false, true, false}, + ["CORNER-BOTTOMLEFT"] = {false, true, false, false}, + ["CORNER-BOTTOMRIGHT"] = {true, false, false, false}, + ["SIDE-LEFT"] = {false, true, false, true}, + ["SIDE-RIGHT"] = {true, false, true, false}, + ["SIDE-TOP"] = {false, false, true, true}, + ["SIDE-BOTTOM"] = {true, true, false, false}, + ["TRICORNER-TOPLEFT"] = {false, true, true, true}, + ["TRICORNER-TOPRIGHT"] = {true, false, true, true}, + ["TRICORNER-BOTTOMLEFT"] = {true, true, false, true}, + ["TRICORNER-BOTTOMRIGHT"] = {true, true, true, false}, + } + + function updatePosition(button) + local angle = math.rad(button.db and button.db.minimapPos or button.minimapPos or 225) + local x, y, q = math.cos(angle), math.sin(angle), 1 + if x < 0 then q = q + 1 end + if y > 0 then q = q + 2 end + local minimapShape = GetMinimapShape and GetMinimapShape() or "ROUND" + local quadTable = minimapShapes[minimapShape] + if quadTable[q] then + x, y = x*80, y*80 + else + local diagRadius = 103.13708498985 --math.sqrt(2*(80)^2)-10 + x = math.max(-80, math.min(x*diagRadius, 80)) + y = math.max(-80, math.min(y*diagRadius, 80)) + end + button:SetPoint("CENTER", Minimap, "CENTER", x, y) + end +end + +function onClick(self, b) if self.dataObject.OnClick then self.dataObject.OnClick(self, b) end end +function onMouseDown(self) self.isMouseDown = true; self.icon:UpdateCoord() end +function onMouseUp(self) self.isMouseDown = false; self.icon:UpdateCoord() end + +do + local function onUpdate(self) + local mx, my = Minimap:GetCenter() + local px, py = GetCursorPosition() + local scale = Minimap:GetEffectiveScale() + px, py = px / scale, py / scale + if self.db then + self.db.minimapPos = math.deg(math.atan2(py - my, px - mx)) % 360 + else + self.minimapPos = math.deg(math.atan2(py - my, px - mx)) % 360 + end + updatePosition(self) + end + + function onDragStart(self) + self:LockHighlight() + self.isMouseDown = true + self.icon:UpdateCoord() + self:SetScript("OnUpdate", onUpdate) + self.isMoving = true + GameTooltip:Hide() + end +end + +function onDragStop(self) + self:SetScript("OnUpdate", nil) + self.isMouseDown = false + self.icon:UpdateCoord() + self:UnlockHighlight() + self.isMoving = nil +end + +local defaultCoords = {0, 1, 0, 1} +local function updateCoord(self) + local coords = self:GetParent().dataObject.iconCoords or defaultCoords + local deltaX, deltaY = 0, 0 + if not self:GetParent().isMouseDown then + deltaX = (coords[2] - coords[1]) * 0.05 + deltaY = (coords[4] - coords[3]) * 0.05 + end + self:SetTexCoord(coords[1] + deltaX, coords[2] - deltaX, coords[3] + deltaY, coords[4] - deltaY) +end + +local function createButton(name, object, db) + local button = CreateFrame("Button", "LibDBIcon10_"..name, Minimap) + button.dataObject = object + button.db = db + button:SetFrameStrata("MEDIUM") + button:SetWidth(31); button:SetHeight(31) + button:SetFrameLevel(8) + button:RegisterForClicks("anyUp") + button:RegisterForDrag("LeftButton") + button:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight") + local overlay = button:CreateTexture(nil, "OVERLAY") + overlay:SetWidth(53); overlay:SetHeight(53) + overlay:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder") + overlay:SetPoint("TOPLEFT") + local background = button:CreateTexture(nil, "BACKGROUND") + background:SetWidth(20); background:SetHeight(20) + background:SetTexture("Interface\\Minimap\\UI-Minimap-Background") + background:SetPoint("TOPLEFT", 7, -5) + local icon = button:CreateTexture(nil, "ARTWORK") + icon:SetWidth(17); icon:SetHeight(17) + icon:SetTexture(object.icon) + icon:SetPoint("TOPLEFT", 7, -6) + button.icon = icon + button.isMouseDown = false + + icon.UpdateCoord = updateCoord + icon:UpdateCoord() + + button:SetScript("OnEnter", onEnter) + button:SetScript("OnLeave", onLeave) + button:SetScript("OnClick", onClick) + if not db or not db.lock then + button:SetScript("OnDragStart", onDragStart) + button:SetScript("OnDragStop", onDragStop) + end + button:SetScript("OnMouseDown", onMouseDown) + button:SetScript("OnMouseUp", onMouseUp) + + lib.objects[name] = button + + if lib.loggedIn then + updatePosition(button) + if not db or not db.hide then button:Show() + else button:Hide() end + end +end + +-- We could use a metatable.__index on lib.objects, but then we'd create +-- the icons when checking things like :IsRegistered, which is not necessary. +local function check(name) + if lib.notCreated[name] then + createButton(name, lib.notCreated[name][1], lib.notCreated[name][2]) + lib.notCreated[name] = nil + end +end + +lib.loggedIn = lib.loggedIn or false +-- Wait a bit with the initial positioning to let any GetMinimapShape addons +-- load up. +if not lib.loggedIn then + local f = CreateFrame("Frame") + f:SetScript("OnEvent", function() + for _, object in pairs(lib.objects) do + updatePosition(object) + if not lib.disabled and (not object.db or not object.db.hide) then object:Show() + else object:Hide() end + end + lib.loggedIn = true + f:SetScript("OnEvent", nil) + f = nil + end) + f:RegisterEvent("PLAYER_LOGIN") +end + +local function getDatabase(name) + return lib.notCreated[name] and lib.notCreated[name][2] or lib.objects[name].db +end + +function lib:Register(name, object, db) + if not object.icon then error("Can't register LDB objects without icons set!") end + if lib.objects[name] or lib.notCreated[name] then error("Already registered, nubcake.") end + if not lib.disabled and (not db or not db.hide) then + createButton(name, object, db) + else + lib.notCreated[name] = {object, db} + end +end + +function lib:Lock(name) + if not lib:IsRegistered(name) then return end + if lib.objects[name] then + lib.objects[name]:SetScript("OnDragStart", nil) + lib.objects[name]:SetScript("OnDragStop", nil) + end + local db = getDatabase(name) + if db then db.lock = true end +end + +function lib:Unlock(name) + if not lib:IsRegistered(name) then return end + if lib.objects[name] then + lib.objects[name]:SetScript("OnDragStart", onDragStart) + lib.objects[name]:SetScript("OnDragStop", onDragStop) + end + local db = getDatabase(name) + if db then db.lock = nil end +end + +function lib:Hide(name) + if not lib.objects[name] then return end + lib.objects[name]:Hide() +end +function lib:Show(name) + if lib.disabled then return end + check(name) + lib.objects[name]:Show() + updatePosition(lib.objects[name]) +end +function lib:IsRegistered(name) + return (lib.objects[name] or lib.notCreated[name]) and true or false +end +function lib:Refresh(name, db) + if lib.disabled then return end + check(name) + local button = lib.objects[name] + if db then button.db = db end + updatePosition(button) + if not button.db or not button.db.hide then + button:Show() + else + button:Hide() + end + if not button.db or not button.db.lock then + button:SetScript("OnDragStart", onDragStart) + button:SetScript("OnDragStop", onDragStop) + else + button:SetScript("OnDragStart", nil) + button:SetScript("OnDragStop", nil) + end +end +function lib:GetMinimapButton(name) + return lib.objects[name] +end + +function lib:EnableLibrary() + lib.disabled = nil + for name, object in pairs(lib.objects) do + if not object.db or not object.db.hide then + object:Show() + updatePosition(object) + end + end + for name, data in pairs(lib.notCreated) do + if not data.db or not data.db.hide then + createButton(name, data[1], data[2]) + lib.notCreated[name] = nil + end + end +end + +function lib:DisableLibrary() + lib.disabled = true + for name, object in pairs(lib.objects) do + object:Hide() + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/LibDataBroker-1.1/LibDataBroker-1.1.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,90 @@ + +assert(LibStub, "LibDataBroker-1.1 requires LibStub") +assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0") + +local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4) +if not lib then return end +oldminor = oldminor or 0 + + +lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib) +lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {} +local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks + +if oldminor < 2 then + lib.domt = { + __metatable = "access denied", + __index = function(self, key) return attributestorage[self] and attributestorage[self][key] end, + } +end + +if oldminor < 3 then + lib.domt.__newindex = function(self, key, value) + if not attributestorage[self] then attributestorage[self] = {} end + if attributestorage[self][key] == value then return end + attributestorage[self][key] = value + local name = namestorage[self] + if not name then return end + callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self) + callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self) + callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self) + callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self) + end +end + +if oldminor < 2 then + function lib:NewDataObject(name, dataobj) + if self.proxystorage[name] then return end + + if dataobj then + assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table") + self.attributestorage[dataobj] = {} + for i,v in pairs(dataobj) do + self.attributestorage[dataobj][i] = v + dataobj[i] = nil + end + end + dataobj = setmetatable(dataobj or {}, self.domt) + self.proxystorage[name], self.namestorage[dataobj] = dataobj, name + self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj) + return dataobj + end +end + +if oldminor < 1 then + function lib:DataObjectIterator() + return pairs(self.proxystorage) + end + + function lib:GetDataObjectByName(dataobjectname) + return self.proxystorage[dataobjectname] + end + + function lib:GetNameByDataObject(dataobject) + return self.namestorage[dataobject] + end +end + +if oldminor < 4 then + local next = pairs(attributestorage) + function lib:pairs(dataobject_or_name) + local t = type(dataobject_or_name) + assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)") + + local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name + assert(attributestorage[dataobj], "Data object not found") + + return next, attributestorage[dataobj], nil + end + + local ipairs_iter = ipairs(attributestorage) + function lib:ipairs(dataobject_or_name) + local t = type(dataobject_or_name) + assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)") + + local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name + assert(attributestorage[dataobj], "Data object not found") + + return ipairs_iter, attributestorage[dataobj], 0 + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/LibDataBroker-1.1/README.textile Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,13 @@ +LibDataBroker is a small WoW addon library designed to provide a "MVC":http://en.wikipedia.org/wiki/Model-view-controller interface for use in various addons. +LDB's primary goal is to "detach" plugins for TitanPanel and FuBar from the display addon. +Plugins can provide data into a simple table, and display addons can receive callbacks to refresh their display of this data. +LDB also provides a place for addons to register "quicklaunch" functions, removing the need for authors to embed many large libraries to create minimap buttons. +Users who do not wish to be "plagued" by these buttons simply do not install an addon to render them. + +Due to it's simple generic design, LDB can be used for any design where you wish to have an addon notified of changes to a table. + +h2. Links + +* "API documentation":http://github.com/tekkub/libdatabroker-1-1/wikis/api +* "Data specifications":http://github.com/tekkub/libdatabroker-1-1/wikis/data-specifications +* "Addons using LDB":http://github.com/tekkub/libdatabroker-1-1/wikis/addons-using-ldb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/LibStub/LibStub.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,51 @@ +-- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $ +-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info +-- LibStub is hereby placed in the Public Domain +-- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! +local LibStub = _G[LIBSTUB_MAJOR] + +-- Check to see is this version of the stub is obsolete +if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + -- LibStub:NewLibrary(major, minor) + -- major (string) - the major version of the library + -- minor (string or number ) - the minor version of the library + -- + -- returns nil if a newer or same version of the lib is already present + -- returns empty library object or old library object if upgrade is needed + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + -- LibStub:GetLibrary(major, [silent]) + -- major (string) - the major version of the library + -- silent (boolean) - if true, library is optional, silently return nil if its not found + -- + -- throws an error if the library can not be found (except silent is set) + -- returns the library object if found + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(("Cannot find a library instance of %q."):format(tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + -- LibStub:IterateLibraries() + -- + -- Returns an iterator for the currently registered libraries + function LibStub:IterateLibraries() + return pairs(self.libs) + end + + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/LibStub/LibStub.toc Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,13 @@ +## Interface: 50001 +## Title: Lib: LibStub +## Notes: Universal Library Stub +## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel +## X-Website: http://www.wowace.com/addons/libstub/ +## X-Category: Library +## X-License: Public Domain +## X-Curse-Packaged-Version: 1.0.3-50001 +## X-Curse-Project-Name: LibStub +## X-Curse-Project-ID: libstub +## X-Curse-Repository-ID: wow/libstub/mainline + +LibStub.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/LibStub/tests/test.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,41 @@ +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy +assert(lib) -- should return the library table +assert(not oldMinor) -- should not return the old minor, since it didn't exist + +-- the following is to create data and then be able to check if the same data exists after the fact +function lib:MyMethod() +end +local MyMethod = lib.MyMethod +lib.MyTable = {} +local MyTable = lib.MyTable + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail +assert(not newLib) -- should not return since out of date + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail +assert(not newLib) -- should not return since out of date + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version +assert(newLib) -- library table +assert(rawequal(newLib, lib)) -- should be the same reference as the previous +assert(newOldMinor == 1) -- should return the minor version of the previous version + +assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved +assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number) +assert(newLib) -- library table +assert(newOldMinor == 2) -- previous version was 2 + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number) +assert(newLib) +assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string) + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string +assert(newLib) +assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string) \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/LibStub/tests/test2.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,27 @@ +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +for major, library in LibStub:IterateLibraries() do + -- check that MyLib doesn't exist yet, by iterating through all the libraries + assert(major ~= "MyLib") +end + +assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking +assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error. +local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib +assert(lib) -- check it exists +assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference + +assert(LibStub:NewLibrary("MyLib", 2)) -- create a new version + +local count=0 +for major, library in LibStub:IterateLibraries() do + -- check that MyLib exists somewhere in the libraries, by iterating through all the libraries + if major == "MyLib" then -- we found it! + count = count +1 + assert(rawequal(library, lib)) -- verify that the references are equal + end +end +assert(count == 1) -- verify that we actually found it, and only once
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/LibStub/tests/test3.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,14 @@ +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +local proxy = newproxy() -- non-string + +assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata +local success, ret = pcall(LibStub.GetLibrary, proxy, true) +assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered. + +assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it. + +assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/LibStub/tests/test4.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,41 @@ +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + + +-- Pretend like loaded libstub is old and doesn't have :IterateLibraries +assert(LibStub.minor) +LibStub.minor = LibStub.minor - 0.0001 +LibStub.IterateLibraries = nil + +loadfile("../LibStub.lua")() + +assert(type(LibStub.IterateLibraries)=="function") + + +-- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created +LibStub.IterateLibraries = 123 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +-- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created +LibStub.minor = LibStub.minor + 0.0001 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +-- Again with a huge number +LibStub.minor = LibStub.minor + 1234567890 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +print("OK") \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sort.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,31 @@ +local _, AskMrRobot = ... + +function AskMrRobot.spairs(t, order) + -- collect the keys + local keys = {} + for k in pairs(t) do keys[#keys+1] = k end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a,b) return order(t, a, b) end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] + end + end +end + +function AskMrRobot.sortSlots(t) + return AskMrRobot.spairs(t, function(x, a, b) + if a == nil and b == nil then return 0 end + return AskMrRobot.sortedSlots[a] < AskMrRobot.sortedSlots[b] + end) +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/CombatLogTab.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,303 @@ +local _, AskMrRobot = ... + +-- initialize the ExportTab class +AskMrRobot.CombatLogTab = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +-- helper to create text for this tab +local function CreateText(tab, font, relativeTo, xOffset, yOffset, text) + local t = tab:CreateFontString(nil, "ARTWORK", font) + t:SetPoint("TOPLEFT", relativeTo, "BOTTOMLEFT", xOffset, yOffset) + t:SetPoint("RIGHT", tab, "RIGHT", -25, 0) + t:SetWidth(t:GetWidth()) + t:SetJustifyH("LEFT") + t:SetText(text) + + return t +end + +local function newCheckbox(tab, label, tooltipTitle, description, onClick) + local check = CreateFrame("CheckButton", "AmrCheck" .. label, tab, "InterfaceOptionsCheckButtonTemplate") + check:SetScript("OnClick", function(self) + PlaySound(self:GetChecked() and "igMainMenuOptionCheckBoxOn" or "igMainMenuOptionCheckBoxOff") + onClick(self, self:GetChecked() and true or false) + end) + check.label = _G[check:GetName() .. "Text"] + check.label:SetText(label) + check.tooltipText = tooltipTitle + check.tooltipRequirement = description + return check +end + +function AskMrRobot.CombatLogTab:new(parent) + + local tab = AskMrRobot.Frame:new(nil, parent) + setmetatable(tab, { __index = AskMrRobot.CombatLogTab }) + tab:SetPoint("TOPLEFT") + tab:SetPoint("BOTTOMRIGHT") + tab:Hide() + + local text = tab:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge") + text:SetPoint("TOPLEFT", 0, -5) + text:SetText("Combat Logging") + + local manulText = CreateText(tab, "GameFontWhite", text, 0, -15, "Manual:") + manulText:SetJustifyV("MIDDLE") + manulText:SetHeight(30) + + local btn = CreateFrame("Button", "AmrCombatLogStart", tab, "UIPanelButtonTemplate") + btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 75, -15) + btn:SetText("Start Logging") + btn:SetWidth(120) + btn:SetHeight(30) + tab.btnStart = btn + + btn:SetScript("OnClick", function() + tab:StartLogging() + end) + + btn = CreateFrame("Button", "AmrCombatLogEnd", tab, "UIPanelButtonTemplate") + btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 225, -15) + btn:SetText("Stop Logging") + btn:SetWidth(120) + btn:SetHeight(30) + tab.btnEnd = btn + + btn:SetScript("OnClick", function() + tab:StopLogging() + end) + + local autoText = CreateText(tab, "GameFontWhite", text, 0, -50, "Automatic:") + autoText:SetJustifyV("MIDDLE") + autoText:SetHeight(28) + + local autoChk = newCheckbox(tab, + "Always log Siege of Orgrimmar", + "Auto-Log Siege of Orgrimmar", + "Automatically start logging when you enter SoO and stop when you leave SoO.\n\nNote that you should disable similar features in other addons to avoid conflicts.", + function(self, value) + if value then + AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] = "enabled" + else + AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] = "disabled" + end + + AmrLogData._lastZone = nil + AmrLogData._lastDiff = nil + tab:UpdateAutoLogging() + end + ) + autoChk:SetChecked(AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] == "enabled") + autoChk:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 75, -50) + autoChk:SetHeight(30) + + text = CreateText(tab, "GameFontNormalLarge", text, 0, -100, "Character Data") + + btn = CreateFrame("Button", "AmrCombatLogSaveCharData", tab, "UIPanelButtonTemplate") + btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 0, -5) + btn:SetText("Save Character Data") + btn:SetWidth(150) + btn:SetHeight(30) + + btn:SetScript("OnClick", function() + -- reload the UI will save character data to disk + ReloadUI() + end) + + text = CreateText(tab, "GameFontNormalLarge", btn, 0, -30, "INSTRUCTIONS") + text = CreateText(tab, "GameFontWhite", text, 0, -10, "1. Use the Start/Stop buttons or check 'Always log Siege of Orgrimmar'.") + text = CreateText(tab, "GameFontWhite", text, 0, -10, "2. When you are ready to upload, press 'Save Character Data'. *") + text = CreateText(tab, "GameFontWhite", text, 0, -10, "3. Exit World of Warcraft. **") + text = CreateText(tab, "GameFontWhite", text, 0, -10, "4. Launch the Ask Mr. Robot client and follow the instructions. ***") + + text = CreateText(tab, "GameFontNormalSmall", text, 0, -30, "|c00999999* This will reload your UI to ensure that all collected data is saved to disk. This step is not necessary if you log out of the game before uploading.|r") + text = CreateText(tab, "GameFontNormalSmall", text, 0, -10, "|c00999999** Exiting WoW before uploading your combat log is optional, but highly recommended. This prevents your log file from getting ridiculously large and slowing down your uploads.|r") + text = CreateText(tab, "GameFontNormalSmall", text, 0, -10, "|c00999999*** You can download the client program at|r |c003333ffhttp://www.askmrrobot.com/wow/combatlog/upload|r|c00999999.|r") + + --[[ + btn = CreateFrame("Button", "AmrCombatLogTest", tab, "UIPanelButtonTemplate") + btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 0, -15) + btn:SetText("Test") + btn:SetWidth(120) + btn:SetHeight(30) + + btn:SetScript("OnClick", function() + AskMrRobot.ExportToAddonChat(time()) + end) + ]] + + -- when we start up, ensure that logging is still enabled if it was enabled when they last used the addon + if (tab:IsLogging()) then + SetCVar("advancedCombatLogging", 1) + LoggingCombat(true) + end + + -- if auto-logging is enabled, do a check when the addon is loaded to make sure that state is set correctly + if AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] == "enabled" then + tab:UpdateAutoLogging() + end + + tab:SetScript("OnShow", function() + tab:Update() + end) + + return tab +end + +function AskMrRobot.CombatLogTab:IsLogging() + return AmrLogData._logging == true +end + +function AskMrRobot.CombatLogTab:StartLogging() + + -- archive the current logging session so that users don't accidentally blow away data before uploading it + if AmrLogData._current2 ~= nil then + if not AmrLogData._history2 then AmrLogData._history2 = {} end + + -- add new entries + for name, timeList in AskMrRobot.spairs(AmrLogData._current2) do + if not AmrLogData._history2[name] then AmrLogData._history2[name] = {} end + for timestamp, dataString in AskMrRobot.spairs(timeList) do + AmrLogData._history2[name][timestamp] = dataString + end + end + + -- delete entries that are more than 10 days old + local now = time() + local interval = 60 * 60 * 24 * 10 + for name, timeList in AskMrRobot.spairs(AmrLogData._history2) do + for timestamp, dataString in AskMrRobot.spairs(timeList) do + if difftime(now, tonumber(timestamp)) > interval then + timeList[timestamp] = nil + end + end + + local count = 0 + for timestamp, dataString in pairs(timeList) do + count = count + 1 + end + if count == 0 then + AmrLogData._history2[name] = nil + end + end + end + + -- clean up old-style logging data from previous versions of the addon + for k, v in AskMrRobot.spairs(AmrLogData) do + if k ~= "_logging" and k ~= "_autoLog" and k ~= "_lastZone" and k ~= "_lastDiff" and k ~= "_current2" and k ~= "_history2" then + AmrLogData[k] = nil + end + end + + -- start a new logging session + AmrLogData._current2 = {} + AmrLogData._logging = true + + -- always enable advanced combat logging via our addon, gathers more detailed data for better analysis + SetCVar("advancedCombatLogging", 1) + + LoggingCombat(true) + self:Update() + + print("You are now logging combat, and Mr. Robot is logging character data for your raid.") +end + +function AskMrRobot.CombatLogTab:StopLogging() + LoggingCombat(false) + AmrLogData._logging = false + self:Update() + + print("Combat logging has been stopped.") +end + +-- update the panel and state +function AskMrRobot.CombatLogTab:Update() + local isLogging = self:IsLogging() + + if isLogging then + self.btnStart:Disable() + self.btnEnd:Enable() + else + self.btnStart:Enable() + self.btnEnd:Disable() + end +end + +-- called to update logging state when auto-logging is enabled +function AskMrRobot.CombatLogTab:UpdateAutoLogging() + + -- get the info about the instance + --local zone, zonetype, difficultyIndex, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID = GetInstanceInfo() + local zone, _, difficultyIndex, _, _, _, _, instanceMapID = GetInstanceInfo() + --local difficulty = difficultyIndex + -- Unless Blizzard fixes scenarios to not return nil, let's hardcode this into returning "scenario" -Znuff + --if zonetype == nil and difficultyIndex == 1 then + --zonetype = "scenario" + --end + + if zone == AmrLogData._lastZone and difficultyIndex == AmrLogData._lastDiff then + -- do nothing if the zone hasn't actually changed, otherwise we may override the user's manual enable/disable + return + end + + AmrLogData._lastZone = zone + AmrLogData._lastDiff = difficultyIndex + + if AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] == "enabled" then + if tonumber(instanceMapID) == AskMrRobot.instanceIds.SiegeOfOrgrimmar then + -- if in SoO, make sure logging is on + if not self:IsLogging() then + self:StartLogging() + end + else + -- not in SoO, turn logging off + if self:IsLogging() then + self:StopLogging() + end + end + end + +end + +-- read a message sent to the addon channel with a player's info at the time an encounter started +function AskMrRobot.CombatLogTab:ReadAddonMessage(message) + + -- message will be of format: timestamp\nrealm\nname\n[stuff] + local parts = {} + for part in string.gmatch(message, "([^\n]+)") do + tinsert(parts, part) + end + + local timestamp = parts[1] + local name = parts[2] .. ":" .. parts[3] + local data = parts[4] + + if (data == "done") then + -- we have finished receiving this message; now process it to reduce the amount of duplicate data + local setup = AmrLogData._current2[name][timestamp] + + if (AmrLogData._previousSetup == nil) then + AmrLogData._previousSetup = {} + end + + local previousSetup = AmrLogData._previousSetup[name] + + if (previousSetup == setup) then + -- if the last-seen setup for this player is the same as the current one, we don't need this entry + AmrLogData._current2[name][timestamp] = nil + else + -- record the last-seen setup + AmrLogData._previousSetup[name] = setup + end + else + -- concatenate messages with the same timestamp+name + if (AmrLogData._current2[name] == nil) then + AmrLogData._current2[name] = {} + end + + if (AmrLogData._current2[name][timestamp] == nil) then + AmrLogData._current2[name][timestamp] = data + else + AmrLogData._current2[name][timestamp] = AmrLogData._current2[name][timestamp] .. data + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/Components.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,162 @@ +local _, AskMrRobot = ... + +local unresolvedItemIds = {} + +-- Create a new class that inherits from a base class +function AskMrRobot.inheritsFrom( baseClass ) + + -- The following lines are equivalent to the SimpleClass example: + + -- Create the table and metatable representing the class. + local new_class = {} + + -- Note that this function uses class_mt as an upvalue, so every instance + -- of the class will share the same metatable. + -- + -- function new_class:create(o) + -- o = o or {} + -- setmetatable( o, class_mt ) + -- return o + -- end + + -- The following is the key to implementing inheritance: + + -- The __index member of the new class's metatable references the + -- base class. This implies that all methods of the base class will + -- be exposed to the sub-class, and that the sub-class can override + -- any of these methods. + -- + if baseClass then + setmetatable( new_class, { __index = baseClass } ) + end + + return new_class +end + +local itemInfoFrame = nil; + +local function onGetItemInfoReceived(arg1, arg2, arg3) + -- since wow is awesome, it doesn't tell us *which* item id was just resolved, so we have to look at them all + for itemId, callbacks in pairs(unresolvedItemIds) do + -- attempt to get the item info AGAIN + local a, b, c, d, e, f, g, h, i, j, k = GetItemInfo(itemId) + -- if we got item info... + if a then + -- remove the callbacks from the list + unresolvedItemIds[itemId] = nil + + -- call each callback + for i = 1, #callbacks do + callbacks[i](a, b, c, d, e, f, g, h, i, j, k) + end + end + end +end + + +function AskMrRobot.RegisterItemInfoCallback(itemId, callback) + if not itemId then + return + end + + if not itemInfoFrame then + waitFrame = CreateFrame("Frame","WaitFrame", UIParent); + waitFrame:RegisterEvent("GET_ITEM_INFO_RECEIVED") + waitFrame:SetScript("OnEvent", onGetItemInfoReceived); + end + + + -- get the list of registered callbacks for this particular item + local list = unresolvedItemIds[itemId] + -- if there was a list, then just add the callback to the list + if list then + tinsert(list, callback) + else + -- there wasn't a list, so make a new one with this callback + unresolvedItemIds[itemId] = { callback } + end +end + +function AskMrRobot.getItemIdFromLink(item) + if not item then return 0 end + local id = tonumber (item:match ("item:(%d+):%d+:%d+:%d+:%d+:%d+:%-?%d+:%-?%d+:%d+:%d+")) + return (id and id ~= 0 and id or 0) +end + +-- initialize the Frame class (inherit from a dummy frame) +AskMrRobot.Frame = AskMrRobot.inheritsFrom(CreateFrame("Frame")) + +-- Frame contructor +function AskMrRobot.Frame:new(name, parentFrame, inheritsFrame) + -- create a new frame (if one isn't supplied) + local o = CreateFrame("Frame", name, parentFrame, inheritsFrame) + + -- use the Frame class + setmetatable(o, { __index = AskMrRobot.Frame }) + + -- return the instance of the Frame + return o +end + +local MAINHAND = nil +local OFFHAND = nil + +AskMrRobot.slotNames = {"HeadSlot", "NeckSlot", "ShoulderSlot", "BackSlot", "ChestSlot", "ShirtSlot", "TabardSlot", "WristSlot", "HandsSlot", "WaistSlot", "LegsSlot", "FeetSlot", "Finger0Slot", "Finger1Slot", "Trinket0Slot", "Trinket1Slot", "MainHandSlot", "SecondaryHandSlot", "AmmoSlot" }; +AskMrRobot.OptimizationSlots = {} +AskMrRobot.slotIdToSlotNum = {} +AskMrRobot.slotIds = {}; +for slotNum = 1, #AskMrRobot.slotNames do + local slotId = GetInventorySlotInfo(AskMrRobot.slotNames[slotNum]) + AskMrRobot.slotIds[slotNum] = slotId + AskMrRobot.slotIdToSlotNum[slotId] = slotNum + local slotName = AskMrRobot.slotNames[slotNum] + if slotName == "MainHandSlot" then + MAINHAND = slotNum + end + if slotName == "SecondaryHandSlot" then + OFFHAND = slotNum + end + if slotName ~= "TabardSlot" and slotName ~= "AmmoSlot" and slotName ~= "ShirtSlot" then + AskMrRobot.OptimizationSlots[slotNum] = true + end + +end + +AskMrRobot.sortedSlots = {[MAINHAND] = 1, [OFFHAND] = 2} + +local i = 3 +for slotNum = 1, #AskMrRobot.slotNames do + if slotNum ~= MAINHAND and slotNum ~= OFFHAND then + AskMrRobot.sortedSlots[slotNum] = i + i = i + 1 + end +end + + +-- initialize the Frame class (inherit from a dummy frame) +AskMrRobot.FontString = AskMrRobot.inheritsFrom(AskMrRobot.Frame:new():CreateFontString(nil, "ARTWORK", "GameFontNormal")) + +-- Frame contructor +function AskMrRobot.FontString:new(parentFrame, name, layer, style, fontSize) + + local o = parentFrame:CreateFontString(name, layer, style) -- create a new frame (if one isn't supplied) + + -- use the fontstring class + setmetatable(o, { __index = AskMrRobot.FontString }) + + if fontSize then + o:SetFontSize(fontSize) + end + + return o +end + +function AskMrRobot.FontString:SetFontSize(fontSize) + local file, _, flags = self:GetFont() + self:SetFont(file, fontSize, flags) +end + +function AskMrRobot.SetFontSize(fontString, fontSize) + local file, _, flags = fontString:GetFont() + fontString:SetFont(file, fontSize, flags) +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/EnchantLinkText.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,96 @@ +local _, AskMrRobot = ... + +AskMrRobot.EnchantLinkText = AskMrRobot.inheritsFrom(AskMrRobot.ItemTooltipFrame) + +function AskMrRobot.EnchantLinkText:new(name, parent) + local o = AskMrRobot.ItemTooltipFrame:new(name, parent) + + -- use the ItemLinkText class + setmetatable(o, { __index = AskMrRobot.EnchantLinkText }) + + -- the item text + o.itemText = AskMrRobot.FontString:new(o, nil, "ARTWORK", "GameFontWhite") + o.itemText:SetPoint("TOPLEFT") + o.itemText:SetPoint("BOTTOMRIGHT") + o.itemText:SetJustifyH("LEFT") + + return o +end + +function AskMrRobot.EnchantLinkText:SetEnchantId(enchantId) + self.itemName = nil + if enchantId and enchantId ~= 0 then + local spellId = AskMrRobot.getEnchantSpellId(enchantId) + local link = nil + if spellId then + link = 'enchant:' .. spellId + end + self:SetItemLink(link) + if self.useSpellName then + local spellName = spellId and select(1, GetSpellInfo(spellId)) + self.itemText:SetText(spellName) + self.itemName = spellName + else + self.itemName = AskMrRobot.getEnchantName(enchantId) + self.itemText:SetText(self.itemName) + end + else + self:SetItemLink(nil) + self.itemText:SetText('') + end +end + +function AskMrRobot.EnchantLinkText:SetFontSize(fontSize) + self.itemText:SetFontSize(fontSize) +end + +function AskMrRobot.EnchantLinkText:UseSpellName() + self.useSpellName = true +end + +AskMrRobot.EnchantLinkIconAndText = AskMrRobot.inheritsFrom(AskMrRobot.EnchantLinkText) + +function AskMrRobot.EnchantLinkIconAndText:new(name, parent) + local o = AskMrRobot.EnchantLinkText:new(name, parent) + + -- use the EnchantLinkIconAndText class + setmetatable(o, { __index = AskMrRobot.EnchantLinkIconAndText }) + + o.iconFrame = AskMrRobot.Frame:new(nil, o) + o.iconFrame:SetPoint("TOPLEFT", 0, 5) + o.iconFrame:SetWidth(24) + o.iconFrame:SetHeight(24) + + o.icon = o.iconFrame:CreateTexture(nil, "BACKGROUND") + o.icon:SetPoint("TOPLEFT") + o.icon:SetPoint("BOTTOMRIGHT") + + o.itemText:SetPoint("TOPLEFT", o.iconFrame, "TOPRIGHT", 4, -5) + + o:SetRoundBorder() + + return o +end + +function AskMrRobot.EnchantLinkIconAndText:SetRoundBorder() + self.iconFrame:SetBackdrop({edgeFile = "Interface\\AddOns\\AskMrRobot\\Media\\round-edge", edgeSize = 8}) +end + +function AskMrRobot.EnchantLinkIconAndText:SetSquareBorder() + self.iconFrame:SetBackdrop({edgeFile = "Interface\\AddOns\\AskMrRobot\\Media\\square-edge", edgeSize = 8}) +end + +function AskMrRobot.EnchantLinkIconAndText:SetEnchantId(enchantId) + AskMrRobot.EnchantLinkText.SetEnchantId(self, enchantId) + if enchantId and enchantId ~= 0 then + local texture = AskMrRobot.getEnchantIcon(enchantId) + self.icon:SetTexture('Interface/Icons/' .. texture) + self.iconFrame:Show() + else + self.iconFrame:Hide() + end +end + +function AskMrRobot.EnchantLinkIconAndText:SetFontSize(fontSize) + self.itemText:SetFontSize(fontSize) +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/EnchantTab.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,106 @@ +local _, AskMrRobot = ... + +-- initialize the EnchantTab class +AskMrRobot.EnchantTab = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +function AskMrRobot.EnchantTab:new(parent) + + local tab = AskMrRobot.Frame:new(nil, parent) + setmetatable(tab, { __index = AskMrRobot.EnchantTab }) + tab:SetPoint("TOPLEFT") + tab:SetPoint("BOTTOMRIGHT") + tab:Hide() + + + local text = tab:CreateFontString("AmrEnchantsText1", "ARTWORK", "GameFontNormalLarge") + text:SetPoint("TOPLEFT", 0, -5) + text:SetText("Enchants") + + tab.stamp = AskMrRobot.RobotStamp:new(nil, tab) + tab.stamp:Hide() + tab.stamp.smallText:SetText("Your enchants are 100% optimal!") + tab.stamp:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 2, -15) + tab.stamp:SetPoint("RIGHT", tab, "RIGHT", -20, 0) + + tab.slotHeader = tab:CreateFontString("AmrBadEnchantSlotHeader", "ARTWORK", "GameFontNormal") + tab.slotHeader:SetPoint("TOPLEFT", "AmrEnchantsText1", "BOTTOMLEFT", 0, -20) + tab.slotHeader:SetText("Slot") + tab.slotHeader:SetWidth(90) + tab.slotHeader:SetJustifyH("LEFT") + + tab.currentHeader = tab:CreateFontString("AmrBadEnchantCurrentHeader", "ARTWORK", "GameFontNormal") + tab.currentHeader:SetText("Current") + tab.currentHeader:SetPoint("TOPLEFT", "AmrBadEnchantSlotHeader", "TOPLEFT", 100, 0) + tab.currentHeader:SetWidth(120) + tab.currentHeader:SetJustifyH("LEFT") + + tab.optimizedHeader = tab:CreateFontString("AmrBadEnchantOptimizedHeader", "ARTWORK", "GameFontNormal") + tab.optimizedHeader:SetPoint("TOPLEFT", "AmrBadEnchantCurrentHeader", "TOPLEFT", 140, 0) + tab.optimizedHeader:SetPoint("RIGHT", -30, 0) + tab.optimizedHeader:SetText("Optimized") + tab.optimizedHeader:SetJustifyH("LEFT") + + tab.badEnchantSlots = {} + tab.badEnchantCurrent = {} + tab.badEnchantOptimized = {} + + for i = 1, #AskMrRobot.slotNames do + local itemText = tab:CreateFontString(nil, "ARTWORK", "GameFontWhite") + itemText:SetPoint("TOPLEFT", "AmrBadEnchantSlotHeader", "TOPLEFT", 0, -26 * i) + itemText:SetPoint("BOTTOMRIGHT", "AmrBadEnchantSlotHeader", "BOTTOMRIGHT", 0, -26 * i) + itemText:SetJustifyH("LEFT") + itemText:SetText("TestSlot") + tinsert(tab.badEnchantSlots, itemText) + + itemText = AskMrRobot.EnchantLinkText:new(nil, tab) + itemText:SetPoint("TOPLEFT", "AmrBadEnchantCurrentHeader", "TOPLEFT", 0, -26 * i) + itemText:SetPoint("BOTTOMRIGHT", "AmrBadEnchantCurrentHeader", "BOTTOMRIGHT", 0, -26 * i) + tinsert(tab.badEnchantCurrent, itemText) + + itemText = AskMrRobot.EnchantLinkIconAndText:new(nil, tab) + itemText:SetPoint("TOPLEFT", "AmrBadEnchantOptimizedHeader", "TOPLEFT", 0, -26 * i) + itemText:SetPoint("BOTTOMRIGHT", "AmrBadEnchantOptimizedHeader", "BOTTOMRIGHT", 0, -26 * i) + tinsert(tab.badEnchantOptimized, itemText) + end + + return tab +end + +function AskMrRobot.EnchantTab:showBadEnchants() + + local badEnchants = AskMrRobot.itemDiffs.enchants + + local i = 1 + + -- for all the bad items + for slotNum, badEnchant in AskMrRobot.sortSlots(badEnchants) do + self.badEnchantSlots[i]:SetText(_G[strupper(AskMrRobot.slotNames[slotNum])]) + self.badEnchantSlots[i]:Show() + + self.badEnchantCurrent[i]:SetEnchantId(badEnchant.current) + + self.badEnchantOptimized[i]:SetEnchantId(badEnchant.optimized) + i = i + 1 + end + + -- hide / show the headers + if i == 1 then + self.optimizedHeader:Hide() + self.currentHeader:Hide() + self.slotHeader:Hide() + self.stamp:Show() + else + self.optimizedHeader:Show() + self.currentHeader:Show() + self.slotHeader:Show() + self.stamp:Hide() + end + + -- hide the remaining slots + while i <= #self.badEnchantSlots do + self.badEnchantSlots[i]:Hide() + self.badEnchantCurrent[i]:SetEnchantId(nil) + self.badEnchantOptimized[i]:SetEnchantId(nil) + i = i + 1 + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/ExportTab.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,158 @@ +local _, AskMrRobot = ... + +-- initialize the ExportTab class +AskMrRobot.ExportTab = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +-- helper to create text for this tab +local function CreateText(state, tab, font, relativeTo, xOffset, yOffset, text) + local t = tab:CreateFontString(nil, "ARTWORK", font) + t:SetPoint("TOPLEFT", relativeTo, "BOTTOMLEFT", xOffset, yOffset) + t:SetPoint("RIGHT", tab, "RIGHT", -25, 0) + t:SetWidth(t:GetWidth()) + t:SetJustifyH("LEFT") + t:SetText(text) + + if (state ~= nil) then + table.insert(state, t) + end + + return t +end + +function AskMrRobot.ExportTab:new(parent) + + local tab = AskMrRobot.Frame:new(nil, parent) + setmetatable(tab, { __index = AskMrRobot.ExportTab }) + tab:SetPoint("TOPLEFT") + tab:SetPoint("BOTTOMRIGHT") + tab:Hide() + + -- used to toggle between the two states... could use like, tabs or a UI panel or something, but then I would have to read more pseudo-documentation. + tab.manualElements = {} + tab.autoElements = {} + + local text = tab:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge") + text:SetPoint("TOPLEFT", 0, -5) + text:SetText("Export Gear for Best in Bags") + + local chooseText = CreateText(nil, tab, "GameFontWhite", text, 0, -15, "Choose a method:") + chooseText:SetJustifyV("MIDDLE") + chooseText:SetHeight(30) + + local btn = CreateFrame("Button", "AmrExportManual", tab, "UIPanelButtonTemplate") + btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 125, -15) + btn:SetText("Copy/Paste") + btn:SetWidth(120) + btn:SetHeight(30) + tab.btnManual = btn + + btn:SetScript("OnClick", function() + AmrOptions.exportToClient = false + tab:Update() + end) + + btn = CreateFrame("Button", "AmrExportAuto", tab, "UIPanelButtonTemplate") + btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 275, -15) + btn:SetText("AMR Client") + btn:SetWidth(120) + btn:SetHeight(30) + tab.btnAuto = btn + + btn:SetScript("OnClick", function() + AmrOptions.exportToClient = true + tab:Update() + end) + + -- copy/paste + text = CreateText(tab.manualElements, tab, "GameFontNormalLarge", chooseText, 0, -20, "COPY/PASTE EXPORT") + local text2 = CreateText(tab.manualElements, tab, "GameFontWhite", text, 0, -15, "1. Open your bank") + text = CreateText(tab.manualElements, tab, "GameFontWhite", text2, 0, -15, "2. Copy the text below by pressing Ctrl+C (or Cmd+C on a Mac)") + + local txtExportString = CreateFrame("ScrollFrame", "AmrScrollFrame", tab, "InputScrollFrameTemplate") + txtExportString:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 12, -10) + txtExportString:SetPoint("RIGHT", -25, 0) + txtExportString:SetWidth(txtExportString:GetWidth()) + txtExportString:SetHeight(50) + txtExportString.EditBox:SetWidth(txtExportString:GetWidth()) + txtExportString.EditBox:SetMaxLetters(0) + txtExportString.CharCount:Hide() + tab.txtExportString = txtExportString + table.insert(tab.manualElements, txtExportString) + + txtExportString.EditBox:SetScript("OnEscapePressed", function() + AskMrRobot_ReforgeFrame:Hide() + end) + + text = CreateText(tab.manualElements, tab, "GameFontWhite", txtExportString, -12, -20, "3. Go to AskMrRobot.com and paste into the IMPORT window") + text2 = CreateText(tab.manualElements, tab, "GameFontWhite", text, 10, -5, "(located to the right of your character name near the top of the web page, see screenshot)") + + local image = tab:CreateTexture(nil, "BACKGROUND") + image:SetPoint("TOPLEFT", text2, "BOTTOMLEFT", 2, -10) + image:SetTexture("Interface\\AddOns\\AskMrRobot\\Media\\BiBScreen") + table.insert(tab.manualElements, image) + + text = CreateText(tab.manualElements, tab, "GameFontWhite", text2, 0, -120, "NOTE: If you change something while this window is open, press the Update button below to generate a new export string.") + + btn = CreateFrame("Button", "AmrUpdateExportString", tab, "UIPanelButtonTemplate") + btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 0, -5) + btn:SetText("Update") + btn:SetWidth(120) + btn:SetHeight(25) + table.insert(tab.manualElements, btn) + + btn:SetScript("OnClick", function() + tab:Update() + end) + + -- amr client + text = CreateText(tab.autoElements, tab, "GameFontNormalLarge", chooseText, 0, -20, "AMR CLIENT EXPORT") + text2 = CreateText(tab.autoElements, tab, "GameFontWhite", text, 0, -15, "1. Open your bank") + text = CreateText(tab.autoElements, tab, "GameFontWhite", text2, 0, -15, "2. Press the button below to update your AskMrRobot.lua file") + + btn = CreateFrame("Button", "AmrExportFile", tab, "UIPanelButtonTemplate") + btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 12, -10) + btn:SetText("Export to File") + btn:SetWidth(180) + btn:SetHeight(25) + table.insert(tab.autoElements, btn) + + btn:SetScript("OnClick", function() + AskMrRobot.SaveAll() + ReloadUI() + end) + + text = CreateText(tab.autoElements, tab, "GameFontWhite", btn, -12, -20, "3. Go to AskMrRobot.com and press REFRESH") + text2 = CreateText(tab.autoElements, tab, "GameFontWhite", text, 10, -5, "(located to the right of your character name near the top of the web page, see screenshot:)") + + image = tab:CreateTexture(nil, "BACKGROUND") + image:SetPoint("TOPLEFT", text2, "BOTTOMLEFT", 2, -10) + image:SetTexture("Interface\\AddOns\\AskMrRobot\\Media\\BiBScreen") + table.insert(tab.autoElements, image) + + tab:SetScript("OnShow", function() + tab:Update() + end) + + return tab +end + +-- update the panel and state +function AskMrRobot.ExportTab:Update() + + if (AmrOptions.exportToClient) then + for i, v in ipairs(self.manualElements) do v:Hide() end + for i, v in ipairs(self.autoElements) do v:Show() end + self.btnManual:UnlockHighlight() + self.btnAuto:LockHighlight() + else + for i, v in ipairs(self.autoElements) do v:Hide() end + for i, v in ipairs(self.manualElements) do v:Show() end + self.btnAuto:UnlockHighlight() + self.btnManual:LockHighlight() + + AskMrRobot.SaveAll() + self.txtExportString.EditBox:SetText(AskMrRobot.ExportToString()) + self.txtExportString.EditBox:HighlightText() + self.txtExportString.EditBox:SetFocus() + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/GemIcon.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,84 @@ +local _, AskMrRobot = ... + +local primaryGemTexture = "Interface\\ItemSocketingFrame\\UI-ItemSockets"; +local engineeringGemTexture = "Interface\\ItemSocketingFrame\\UI-EngineeringSockets"; + +GEM_TYPE_INFO = { + Yellow = {tex=primaryGemTexture, left=0, right=0.16796875, top=0.640625, bottom=0.80859375, r=0.97, g=0.82, b=0.29, OBLeft=0.7578125, OBRight=0.9921875, OBTop=0, OBBottom=0.22265625}, + Red = {tex=primaryGemTexture, left=0.1796875, right=0.34375, top=0.640625, bottom=0.80859375, r=1, g=0.47, b=0.47, OBLeft=0.7578125, OBRight=0.9921875, OBTop=0.4765625, OBBottom=0.69921875}, + Blue = {tex=primaryGemTexture,left=0.3515625, right=0.51953125, top=0.640625, bottom=0.80859375, r=0.47, g=0.67, b=1, OBLeft=0.7578125, OBRight=0.9921875, OBTop=0.23828125, OBBottom=0.4609375}, + Hydraulic = {tex=engineeringGemTexture, left=0.01562500, right=0.68750000, top=0.50000000, bottom=0.58398438, r=1, g=1, b=1, OBLeft=0.01562500, OBRight=0.93750000, OBTop=0.11132813, OBBottom=0.21679688}, + Cogwheel = {tex=engineeringGemTexture, left=0.01562500, right=0.68750000, top=0.41210938, bottom=0.49609375, r=1, g=1, b=1, OBLeft=0.01562500, OBRight=0.78125000, OBTop=0.31640625, OBBottom=0.40820313}, + Meta = {tex=primaryGemTexture, left=0.171875, right=0.3984375, top=0.40234375, bottom=0.609375, r=1, g=1, b=1, OBLeft=0.7578125, OBRight=0.9921875, OBTop=0, OBBottom=0.22265625}, + Prismatic = {tex=engineeringGemTexture, left=0.01562500, right=0.68750000, top=0.76367188, bottom=0.84765625, r=1, g=1, b=1, OBLeft=0.01562500, OBRight=0.68750000, OBTop=0.58789063, OBBottom=0.67187500} +} + +AskMrRobot.GemIcon = AskMrRobot.inheritsFrom(AskMrRobot.ItemIcon) + +-- item icon contructor +function AskMrRobot.GemIcon:new(name, parent) + -- create a new frame (if one isn't supplied) + local o = AskMrRobot.ItemIcon:new(name, parent) + + -- use the ItemIcon class + setmetatable(o, { __index = AskMrRobot.GemIcon }) + + -- add the overlay for the + o.openBracket = o:CreateTexture(nil, "ARTWORK") + o.openBracket:SetPoint("TOPLEFT") + o.openBracket:SetPoint("BOTTOMRIGHT") + + -- return the instance of the GemIcon + return o +end + +function AskMrRobot.GemIcon:UpdateGemStuff() + local info = GEM_TYPE_INFO[self.color] + + if self.itemLink then + -- hide the 2nd half of the empty gem icon + self.openBracket:Hide() + + if info then + self:SetBackdropBorderColor(info.r, info.g, info.b) + end + else + if info then + -- set the empty gem background texture + self.itemIcon:SetTexture(info.tex) + self.itemIcon:SetTexCoord(info.left, info.right, info.top, info.bottom) + + -- set the empty gem overlay + self.openBracket:SetTexture(info.tex) + self.openBracket:SetTexCoord(info.OBLeft, info.OBRight, info.OBTop, info.OBBottom) + self.openBracket:Show() + + --hide the border (the empty gem icon has a border) + self:SetBackdropBorderColor(0,0,0,0) + + -- set the empty gem background texture + self.itemIcon:SetTexture(info.tex) + self.itemIcon:SetTexCoord(info.left, info.right, info.top, info.bottom) + + -- set the empty gem overlay + self.openBracket:SetTexture(info.tex) + self.openBracket:SetTexCoord(info.OBLeft, info.OBRight, info.OBTop, info.OBBottom) + self.openBracket:Show() + else + self.openBracket:Hide() + end + + self:SetBackdropBorderColor(0,0,0,0) + end + +end + +function AskMrRobot.GemIcon:SetItemLink(link) + AskMrRobot.ItemIcon.SetItemLink(self, link) + self:UpdateGemStuff() +end + +function AskMrRobot.GemIcon:SetGemColor(color) + self.color = color + self:UpdateGemStuff() +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/GemTab.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,195 @@ +local _, AskMrRobot = ... + +StaticPopupDialogs["AUTOGEM_FINISHED"] = { + text = "Mr. Robot finished auto-gemming. \rIf some items aren't gemmed, you may need to acquire more gems. \rIf your belt isn't gemmed, you may still need to buy a belt buckle.", + button1 = "Ok", + timeout = 0, + whileDead = true, + hideOnEscape = true, + preferredIndex = 3, -- avoid some UI taint, see http://www.wowace.com/announcements/how-to-avoid-some-ui-taint/ +} + +StaticPopupDialogs["AUTOGEM_ONCE"] = { + text = "Autogemming already in progress.", + button1 = "Ok", + timeout = 0, + whileDead = true, + hideOnEscape = true, + preferredIndex = 3, -- avoid some UI taint, see http://www.wowace.com/announcements/how-to-avoid-some-ui-taint/ +} + +-- initialize the GemTab class +AskMrRobot.GemTab = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +local MAX_SLOTS = 4 + +-- GemTab contructor +function AskMrRobot.GemTab:new(name, parent) + -- create a new frame (if one isn't supplied) + local tab = AskMrRobot.Frame:new(name, parent) + tab:SetPoint("TOPLEFT") + tab:SetPoint("BOTTOMRIGHT") + -- use the GemTab class + setmetatable(tab, { __index = AskMrRobot.GemTab }) + tab:Hide() + + local text = tab:CreateFontString("AmrGemsText1", "ARTWORK", "GameFontNormalLarge") + text:SetPoint("TOPLEFT", 0, -5) + text:SetText("Gems") + + tab.stamp = AskMrRobot.RobotStamp:new(nil, tab) + tab.stamp:Hide() + tab.stamp.smallText:SetText("Your gems are 100% optimal! You are truly, truly outrageous.") + tab.stamp:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 2, -15) + tab.stamp:SetPoint("RIGHT", tab, "RIGHT", -20, 0) + + text = tab:CreateFontString("AmrGemsText2", "ARTWORK", "GameFontWhite") + text:SetText("You have X gems to optimize") + text:SetPoint("TOPLEFT", "AmrGemsText1", "BOTTOMLEFT", 0, -20) + text:SetWidth(200) + text:SetJustifyH("LEFT") + tab.gemsTextToOptimize = text + + -- autogem button + tab.button = CreateFrame("Button", "AmrAutoGemButton", tab, "UIPanelButtonTemplate") + tab.button:SetPoint("TOP", "AmrGemsText1", "BOTTOM", 0, -16) + tab.button:SetPoint("RIGHT", -40, 0) + tab.button:SetText("Auto Gem! (BETA)") + tab.button:SetWidth(150) + tab.button:SetHeight(20) + tab.button:SetScript("OnClick", function() tab:startAutoGem() end) + tab.button:Hide() + + -- autogem checkbox button + tab.usePerfectButton = CreateFrame("CheckButton", "AmrUsePerfectButton", tab, "ChatConfigCheckButtonTemplate") + tab.preferPerfects = true + tab.usePerfectButton:SetChecked(tab.preferPerfects) + tab.usePerfectButton:SetPoint("TOPLEFT", "AmrAutoGemButton", "BOTTOMLEFT", 0, -4) + tab.usePerfectButton:SetScript("OnClick", function () tab.preferPerfects = tab.usePerfectButton:GetChecked() end) + local text3 = getglobal(tab.usePerfectButton:GetName() .. 'Text') + text3:SetText("Prefer Perfect") + text3:SetWidth(150) + text3:SetPoint("TOPLEFT", tab.usePerfectButton, "TOPRIGHT", 2, -4) + tab.usePerfectButton:Hide() + + tab.gemSlotHeader = tab:CreateFontString("AmrBadGemSlot0", "ARTWORK", "GameFontNormal") + tab.gemSlotHeader:SetPoint("TOPLEFT", "AmrGemsText2", "BOTTOMLEFT", 0, -20) + tab.gemSlotHeader:SetText("Slot") + tab.gemSlotHeader:SetWidth(90) + tab.gemSlotHeader:SetJustifyH("LEFT") + tab.gemSlotHeader:Hide() + tab.gemCurrentHeader = tab:CreateFontString("AmrBadGemCurrent0_1", "ARTWORK", "GameFontNormal") + tab.gemCurrentHeader:SetPoint("TOPLEFT", "AmrBadGemSlot0", "TOPLEFT", 88, 0) + tab.gemCurrentHeader:SetWidth(110) + tab.gemCurrentHeader:SetText("Current") + tab.gemCurrentHeader:SetJustifyH("LEFT") + tab.gemCurrentHeader:Hide() + tab.gemOptimizedHeader = tab:CreateFontString("AmrBadGemOptimized0_1", "ARTWORK", "GameFontNormal") + tab.gemOptimizedHeader:SetPoint("TOPLEFT", "AmrBadGemCurrent0_1", "TOPLEFT", 70, 0) + tab.gemOptimizedHeader:SetPoint("RIGHT", -30, 0) + tab.gemOptimizedHeader:SetText("Optimized") + tab.gemOptimizedHeader:SetJustifyH("LEFT") + tab.gemOptimizedHeader:Hide() + + tab.fauxScroll = CreateFrame("ScrollFrame", "testme", tab, "FauxScrollFrameTemplate") + tab.fauxScroll:SetPoint("BOTTOMRIGHT", -40, 15) + tab.fauxScroll:SetPoint("TOPLEFT", "AmrBadGemSlot0", "BOTTOMLEFT", -12, -5) + tab.fauxScroll.parent = tab + tab.fauxScroll:SetScript("OnVerticalScroll", AskMrRobot.GemTab.OnVerticalScroll) + + tab.jewelPanels = {} + for i = 1, MAX_SLOTS do + + tab.jewelPanels[i] = AskMrRobot.JewelPanel:new("AmrBadGemSlot" .. i, tab) + if i == 1 then + tab.jewelPanels[i]:SetPoint("TOPLEFT", "AmrBadGemSlot" .. (i-1), "BOTTOMLEFT", -12, -5) + --tab.jewelPanels[i]:SetPoint("TOPLEFT") + else + tab.jewelPanels[i]:SetPoint("TOPLEFT", "AmrBadGemSlot" .. (i-1), "BOTTOMLEFT", 0, -5) + end + tab.jewelPanels[i]:SetPoint("RIGHT", -40, 0) + end + + return tab +end + +function AskMrRobot.GemTab:startAutoGem() + if AskMrRobot.AutoGem(self.preferPerfects) == false then + StaticPopup_Show("AUTOGEM_ONCE") + end +end + +function AskMrRobot.GemTab:Update() + self.count = 0 + + local i = 1 + local badGemTotal = 0 + + if AskMrRobot.itemDiffs.gems then + for slotNum, badGems in AskMrRobot.sortSlots(AskMrRobot.itemDiffs.gems) do + self.count = self.count + 1 + if i <= MAX_SLOTS then + self.jewelPanels[i]:Show() + end + for k, v in pairs(badGems.badGems) do + badGemTotal = badGemTotal + 1 + end + i = i + 1 + end + end + + self.gemsTextToOptimize:SetFormattedText("You have %d \1244gem:gems; to optimize", badGemTotal) + + --hide/show the headers, depending on if we have any bad gems + if self.count == 0 then + self.gemSlotHeader:Hide() + self.gemCurrentHeader:Hide() + self.gemOptimizedHeader:Hide() + self.gemsTextToOptimize:Hide() + self.button:Hide() + self.usePerfectButton:Hide() + self.stamp:Show() + else + self.gemSlotHeader:Show() + self.gemCurrentHeader:Show() + self.gemOptimizedHeader:Show() + self.gemsTextToOptimize:Show() + self.button:Show() + self.usePerfectButton:Show() + self.stamp:Hide() + end + + for i = self.count + 1, MAX_SLOTS do + self.jewelPanels[i]:Hide() + i = i + 1 + end + + AskMrRobot.GemTab.OnUpdate(self.fauxScroll, self.count, #self.jewelPanels, self.jewelPanels[1]:GetHeight()) +end + +function AskMrRobot.GemTab.OnVerticalScroll(scrollframe, offset) + local self = scrollframe.parent + FauxScrollFrame_OnVerticalScroll(self.fauxScroll, offset, self.jewelPanels[1]:GetHeight(), AskMrRobot.GemTab.OnUpdate) +end + +function AskMrRobot.GemTab.OnUpdate(scrollframe) + local self = scrollframe.parent + FauxScrollFrame_Update(self.fauxScroll, self.count, #self.jewelPanels, self.jewelPanels[1]:GetHeight()) + local offset = FauxScrollFrame_GetOffset(scrollframe) + + local i = 1 + for slotNum, badGems in AskMrRobot.sortSlots(AskMrRobot.itemDiffs.gems) do + if offset > 0 then + offset = offset - 1 + else + + if i > MAX_SLOTS then + break + end + + self.jewelPanels[i]:SetItemLink(_G[strupper(AskMrRobot.slotNames[slotNum])], badGems.current.link ) + self.jewelPanels[i]:SetOptimizedGems(badGems.optimized, badGems.badGems) + i = i + 1 + end + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/HelpTab.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,37 @@ +local _, AskMrRobot = ... + +-- initialize the HelpTab class +AskMrRobot.HelpTab = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +function AskMrRobot.HelpTab:new(parent) + + local tab = AskMrRobot.Frame:new(nil, parent) + setmetatable(tab, { __index = AskMrRobot.HelpTab }) + tab:SetPoint("TOPLEFT") + tab:SetPoint("BOTTOMRIGHT") + tab:Hide() + + local text = tab:CreateFontString("AmrHelpText1", "ARTWORK", "GameFontNormalLarge") + text:SetPoint("TOPLEFT", 0, -5) + text:SetText("Help") + + local text2 = tab:CreateFontString(nil, "ARTWORK", "GameFontWhite") + text2:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 0, -20) + text2:SetPoint("RIGHT", tab, "RIGHT", -25, -20) + text2:SetWidth(text2:GetWidth()) + text2:SetText("Visit |c003333ffhttp://blog.askmrrobot.com/addon/|r for a full tutorial and to ask questions.\r\r" .. + "|c00999999Q:|r Do I have to get a new text-string every time I need to optimize?\r" .. + '|c0066dd66A:|r Yes. Go to the website and click the green "Update from Armory" button to the left of your character to make sure you have the most up-to-date gear. Optimize your gear and then click the "Export to Addon" button to get your new text-string.\r\r' .. + "|c00999999Q:|r The belt buckle didn't show up in my list.\r" .. + "|c0066dd66A:|r Correct, it's actually quite hard to detect it's status in-game, believe it or not. But we're working on a clever way to detect it!\r\r".. + "|c00999999Q:|r My cogwheels/tinkers didn't show up.\r".. + "|c0066dd66A:|r Correct, we're working on adding those into the list as well... the problem is Mr. Robot has been using them to build other robots...\r\r".. + "|c00999999Q:|r Can I send my shopping list to an alt?\r".. + '|c0066dd66A:|r Yes, go to the shopping list tab and select the "mail" option in the drop down. You can mail the list to your alt.\r\r'.. + "|c00999999Q:|r I am in the middle of a raid and just won a piece of loot. Can I optimize really quick\r".. + "|c0066dd66A:|r Yes! You'll want to read the tutorial on that here: |c003333ffhttp://blog.askmrrobot.com/addon#raid|r") + --text2:SetHeight(100) + text2:SetJustifyH("LEFT") + + return tab +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/ImportTab.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,64 @@ +local _, AskMrRobot = ... + +-- initialize the ImportTab class +AskMrRobot.ImportTab = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +function AskMrRobot.ImportTab:new(parent) + + local tab = AskMrRobot.Frame:new(nil, parent) + setmetatable(tab, { __index = AskMrRobot.ImportTab }) + tab:SetPoint("TOPLEFT") + tab:SetPoint("BOTTOMRIGHT") + tab:Hide() + + -- import button + tab.button = CreateFrame("Button", "AmrImportButton", tab, "UIPanelButtonTemplate") + tab.button:SetPoint("BOTTOM") + tab.button:SetText("Import!") + tab.button:SetWidth(100) + tab.button:SetHeight(20) + tab.button:SetPoint("BOTTOM", 0, 15) + + local text = tab:CreateFontString("AmrImportText1", "ARTWORK", "GameFontNormalLarge") + text:SetPoint("TOPLEFT", 0, -5) + text:SetFormattedText("Import Mr. Robot's optimizations") + + text = tab:CreateFontString("AmrImportText2", "ARTWORK", "GameFontWhite") + text:SetPoint("TOPLEFT", "AmrImportText1", "BOTTOMLEFT", 0, -20) + text:SetPoint("RIGHT", 0, -20) + text:SetWidth(text:GetWidth()) + text:SetJustifyH("LEFT") + text:SetText("1. Go to our website, optimize, then click the 'export to addon' button found just above the stats section.") + + local image = tab:CreateTexture(nil, "BACKGROUND") + image:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 16, -10) + image:SetTexture("Interface\\AddOns\\AskMrRobot\\Media\\AddonExport") + image:SetSize(256, 256) + + text = tab:CreateFontString("AmrImportText3", "ARTWORK", "GameFontWhite") + text:SetPoint("TOPLEFT", image, "BOTTOMLEFT", -16, 24) + text:SetPoint("RIGHT", -15, 40) + text:SetWidth(text:GetWidth()) + text:SetJustifyH("LEFT") + text:SetText("2. A window will popup, copy the text from that window.\r\r3. Return here and paste the text into the window below. To paste it, hold ctrl + v, or on a mac apple + v.\r\r4. Click the 'Import' button below") + + local scrollFrame = CreateFrame("ScrollFrame", "AmrImportScrollFrame", tab, "InputScrollFrameTemplate") + scrollFrame:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 5, -10) + scrollFrame:SetPoint("BOTTOM", "AmrImportButton", "TOP", 0, 10) + scrollFrame:SetPoint("RIGHT", -30, 0) + scrollFrame:SetWidth(430) + scrollFrame.EditBox:SetWidth(scrollFrame:GetWidth()) + scrollFrame.EditBox:SetMaxLetters(1100) + scrollFrame.CharCount:Hide() + scrollFrame.EditBox.PromptText:SetText("Paste text from AskMrRobot.com here.") + scrollFrame.EditBox:SetFocus() + scrollFrame.EditBox:HighlightText() + tab.scrollFrame = scrollFrame + + tab:SetScript("OnShow", function() + tab.scrollFrame.EditBox:HighlightText() + tab.scrollFrame.EditBox:SetFocus() + end) + + return tab +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/ItemIcon.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,40 @@ +local _, AskMrRobot = ... + +-- initialize the ItemIcon class (inherit from a dummy frame) +AskMrRobot.ItemIcon = AskMrRobot.inheritsFrom(AskMrRobot.ItemTooltipFrame) + +-- item icon contructor +function AskMrRobot.ItemIcon:new(name, parent) + -- create a new frame (if one isn't supplied) + local o = AskMrRobot.ItemTooltipFrame:new(name, parent) + + -- use the ItemIcon class + setmetatable(o, { __index = AskMrRobot.ItemIcon }) + + -- the item icon + o.itemIcon = o:CreateTexture(nil, "BACKGROUND") + o.itemIcon:SetPoint("TOPLEFT") + o.itemIcon:SetPoint("BOTTOMRIGHT") + + -- return the instance of the ItemIcon + return o +end + +function AskMrRobot.ItemIcon:SetRoundBorder() + self:SetBackdrop({edgeFile = "Interface\\AddOns\\AskMrRobot\\Media\\round-edge", edgeSize = 8}) +end + +function AskMrRobot.ItemIcon:SetSquareBorder() + self:SetBackdrop({edgeFile = "Interface\\AddOns\\AskMrRobot\\Media\\square-edge", edgeSize = 8}) +end + +-- set the item icon and tooltip from the specified item link +function AskMrRobot.ItemIcon:SetItemLink(link) + AskMrRobot.ItemTooltipFrame.SetItemLink(self, link) + if link then + self.itemIcon:SetTexture(GetItemIcon(AskMrRobot.getItemIdFromLink(link))) + self.itemIcon:SetTexCoord(0, 1, 0, 1) + else + self.itemIcon:SetTexture(nil) + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/ItemLinkText.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,60 @@ +local _, AskMrRobot = ... + +AskMrRobot.ItemLinkText = AskMrRobot.inheritsFrom(AskMrRobot.ItemTooltipFrame) + +function AskMrRobot.ItemLinkText:new(name, parent) + local o = AskMrRobot.ItemTooltipFrame:new(name, parent) + + -- use the ItemLinkText class + setmetatable(o, { __index = AskMrRobot.ItemLinkText }) + + -- the item text + o.itemText = AskMrRobot.FontString:new(o, nil, "ARTWORK", "GameFontWhite") + o.itemText:SetPoint("TOPLEFT") + o.itemText:SetPoint("BOTTOMRIGHT") + o.itemText:SetJustifyH("LEFT") + + return o +end + +function AskMrRobot.ItemLinkText:SetFormat(formatText) + self.formatText = formatText +end + +function AskMrRobot.ItemLinkText:SetItemId(itemId, upgradeId, suffixId) + AskMrRobot.ItemTooltipFrame.SetItemLink(self, link) + self.itemName = nil + if itemId > 0 then + local linkTemplate = "item:%d:0:0:0:0:0:%d:0:%d:0:%d" + local itemName, itemLink = GetItemInfo(linkTemplate:format(itemId, suffixId, UnitLevel("player"), upgradeId)) + self:SetItemLink(itemLink) + if itemLink then + self.itemName = itemName + if self.formatText then + self.itemText:SetFormattedText(self.formatText, itemLink:gsub("%[", ""):gsub("%]", "")) + else + self.itemText:SetText(itemLink:gsub("%[", ""):gsub("%]", "")) + end + else + self.itemText:SetFormattedText("unknown (%d)", itemId) + self.itemText:SetTextColor(1,1,1) + AskMrRobot.RegisterItemInfoCallback(itemId, function(name, itemLink2) + if self.formatText then + self.itemText:SetFormattedText(self.formatText, itemLink2:gsub("%[", ""):gsub("%]", "")) + else + self.itemText:SetText(itemLink2:gsub("%[", ""):gsub("%]", "")) + end + self:SetItemLink(itemLink2) + self.itemName = name + end) + end + else + self.itemText:SetText("empty") + self.itemText:SetTextColor(0.5,0.5,0.5) + self:SetItemLink(nil) + end +end + +function AskMrRobot.ItemLinkText:SetFontSize(fontSize) + self.itemText:SetFontSize(fontSize) +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/ItemTooltipFrame.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,46 @@ +local _, AskMrRobot = ... + +-- initialize the ItemLink class +AskMrRobot.ItemTooltipFrame = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +-- item link contructor +function AskMrRobot.ItemTooltipFrame:new(name, parent) + -- create a new frame + local o = AskMrRobot.Frame:new(name, parent) + + -- use the ItemTooltipFrame class + setmetatable(o, { __index = AskMrRobot.ItemTooltipFrame }) + + o.tooltipShown = false + + -- initialize the enter/leave scripts for showing the tooltips + o:SetScript("OnEnter", AskMrRobot.ItemTooltipFrame.OnEnterTooltipFrame) + o:SetScript("OnLeave", AskMrRobot.ItemTooltipFrame.OnLeaveTooltipFrame) + + -- return the instance of the ItemTooltipFrame + return o +end + +function AskMrRobot.ItemTooltipFrame:OnEnterTooltipFrame() + if self.itemLink then + GameTooltip:SetOwner(self, "ANCHOR_CURSOR") + + GameTooltip:SetHyperlink(self.itemLink) + + GameTooltip:Show() + self.tooltipShown = true + end +end + +function AskMrRobot.ItemTooltipFrame:OnLeaveTooltipFrame() + GameTooltip:Hide() + self.tooltipShown = false +end + +-- set the tooltip from the specified item link +function AskMrRobot.ItemTooltipFrame:SetItemLink(link) + if self.tooltipShown then + GameTooltip:Hide() + end + self.itemLink = link +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/JewelPanel.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,186 @@ +local _, AskMrRobot = ... + +local MAX_GEMS_PER_SLOT = 3 + +-- make the JewelPanel inherit from a dummy frame +AskMrRobot.JewelPanel = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +-- JewelPanel constructor +function AskMrRobot.JewelPanel:new (name, parent) + -- create a new frame if one isn't supplied + local o = AskMrRobot.Frame:new(name, parent) + + -- make the object a JewelPanel instanct + setmetatable(o, { __index = AskMrRobot.JewelPanel}) + + -- set the height and border of the newly created jewel frame + o:SetHeight(95) + o:SetBackdrop({edgeFile = "Interface/Tooltips/UI-Tooltip-Border", edgeSize = 16}) + + -- setup the slot name + o._slotName = o:CreateFontString(nil, "ARTWORK", "GameFontWhite") + o._slotName:SetPoint("TOPLEFT", 11, -10) + o._slotName:SetWidth(80) + o._slotName:SetJustifyH("LEFT") + + -- setup the item icon frame + o._itemIcon = AskMrRobot.ItemIcon:new() + o._itemIcon:SetParent(o) + o._itemIcon:SetRoundBorder() + o._itemIcon:SetPoint("TOPLEFT", 9, -32) + o._itemIcon:SetWidth(48) + o._itemIcon:SetHeight(48) + + -- initialize the current gems array + o._currentGems = {} + o._optimizedGemText = {} + o._optimizedGemIcons = {} + -- for each row of gems + for i = 1, MAX_GEMS_PER_SLOT do + -- create an item icon for the currently equiped gem + local gemIcon = AskMrRobot.GemIcon:new(nil, o) + gemIcon:SetPoint("TOPLEFT", 100, 18 - 27 * i) + gemIcon:SetWidth(24) + gemIcon:SetHeight(24) + gemIcon:SetRoundBorder() + o._currentGems[i] = gemIcon + + -- create an item icon for the optimized gem + gemIcon = AskMrRobot.GemIcon:new(nil, o) + gemIcon:SetPoint("TOPLEFT", 170, 18 - 27 * i) + gemIcon:SetWidth(24) + gemIcon:SetHeight(24) + gemIcon:SetRoundBorder() + o._optimizedGemIcons[i] = gemIcon + + -- create the optimized gem text + local gemText = o:CreateFontString(nil, "ARTWORK", "GameFontWhite") + gemText:SetPoint("TOPLEFT", 200, 12 - 27 * i) + gemText:SetPoint("RIGHT", -30) + gemText:SetJustifyH("LEFT") + o._optimizedGemText[i] = gemText + end + + -- return the JewelPanel instance + return o +end + +-- set the item link for this JewelPanel +-- this updates the item icon, the slot name, and the tooltip +function AskMrRobot.JewelPanel:SetItemLink(slotName, itemLink) + -- set the item icon and the tooltip + self._itemIcon:SetItemLink(itemLink) + + if itemLink then + local _, _, rarity = GetItemInfo(itemLink) + if rarity then + local r,g,b = GetItemQualityColor(rarity) + self._itemIcon:SetBackdropBorderColor(r,g,b,1) + else + self._itemIcon:SetBackdropBorderColor(1,1,1,1) + end + else + self._itemIcon:SetBackdropBorderColor(1,1,1,1) + end + + -- set the slot name + self._slotName:SetText(slotName) +end + +-- set the optimized gem information (array of {id, color, enchantId}) +-- SetItemLink must be called first +function AskMrRobot.JewelPanel:SetOptimizedGems(optimizedGems, showGems) + + -- get the item link + local itemLink = self._itemIcon.itemLink + + if not itemLink then return end + + -- for all of the gem rows in this control + local itemId = AskMrRobot.getItemIdFromLink(itemLink) + + local gemCount = 0 + + for i = 1, MAX_GEMS_PER_SLOT do + -- get the optimized text, optimized icon, and current icon for the row + local text = self._optimizedGemText[i] + local optimizedIcon = self._optimizedGemIcons[i] + local currentIcon = self._currentGems[i] + + -- get the current gem in the specified slot + local currentGemLink = select(2, GetItemGem(itemLink, i)) + + -- if there is a gem to add (or remove) + --if i <= #optimizedGems or currentGemLink then + if i <= #optimizedGems or currentGemLink then + -- set the current gem icon / tooltip + currentIcon:SetItemLink(currentGemLink) + + local currentGemId = AskMrRobot.getItemIdFromLink(currentGemLink) + + local optimizedGemLink = nil + if i <= #optimizedGems then + -- make a link for the optimized gem + optimizedGemLink = select(2, GetItemInfo(optimizedGems[i].id)) + + if not optimizedGemLink and optimizedGems[i].id and itemId then + AskMrRobot.RegisterItemInfoCallback(optimizedGems[i].id, function(name, link) + optimizedIcon:SetItemLink(link) + end) + end + end + + if showGems[i] and optimizedGems[i] and optimizedGems[i].color then + gemCount = gemCount + 1 + -- set the optimized gem text + text:SetTextColor(1,1,1) + text:SetText(AskMrRobot.alternateGemName[optimizedGems[i].id] or (optimizedGems[i].enchantId ~= 0 and AskMrRobot.getEnchantName(optimizedGems[i].enchantId)) or GetItemInfo(optimizedGems[i].id)) + currentIcon:Show() + + -- load the item image / tooltip + optimizedIcon:SetItemLink(optimizedGemLink) + optimizedIcon:Show() + optimizedIcon:SetBackdropBorderColor(1,1,1) + currentIcon:SetBackdropBorderColor(1,1,1) + else + if optimizedGems[i] and optimizedGems[i].color then + text:SetText("no change") + text:SetTextColor(0.5,0.5,0.5) + currentIcon:Show() + gemCount = gemCount + 1 + else + text:SetText('') + currentIcon:Hide() + end + optimizedIcon:SetItemLink(nil) + optimizedIcon:Hide() + end + + currentIcon:SetGemColor(optimizedGems[i] and optimizedGems[i].color) + optimizedIcon:SetGemColor(optimizedGems[i] and optimizedGems[i].color) + + -- show the gem row + text:Show() + else + -- hide the gem row + text:Hide() + optimizedIcon:Hide() + currentIcon:Hide() + end + end + + local y1 = 0 + local y2 = 0 + if gemCount == 1 then + y1 = 27 + elseif gemCount == 2 then + y1 = 9 + y2 = 4 + end + + for i = 1, MAX_GEMS_PER_SLOT do + self._optimizedGemText[i]:SetPoint("TOPLEFT", 200, 12 - (27 + y2) * i - y1) + self._optimizedGemIcons[i]:SetPoint("TOPLEFT", 170, 18 - (27 + y2) * i - y1) + self._currentGems[i]:SetPoint("TOPLEFT", 100, 18 - (27 + y2) * i - y1) + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/ReforgesTab.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,504 @@ +local _, AskMrRobot = ... + +-------------------------------------------------------------------- +-- Local Reforge Utility Code +-------------------------------------------------------------------- + +StaticPopupDialogs["REFORGE_TAB_PLEASE_OPEN"] = { + text = "You need to open the reforge window for this to work", + button1 = "Ok", + timeout = 0, + whileDead = true, + hideOnEscape = true, + preferredIndex = 3, -- avoid some UI taint, see http://www.wowace.com/announcements/how-to-avoid-some-ui-taint/ +} + +--from LibReforge +local SPI = 1 +local DODGE = 2 +local PARRY = 3 +local HIT = 4 +local CRIT = 5 +local HASTE = 6 +local EXP = 7 +local MASTERY = 8 + +--from LibReforge +local StatNames = { + ITEM_MOD_SPIRIT_SHORT, + ITEM_MOD_DODGE_RATING_SHORT, + ITEM_MOD_PARRY_RATING_SHORT, + ITEM_MOD_HIT_RATING_SHORT, + ITEM_MOD_CRIT_RATING_SHORT, + ITEM_MOD_HASTE_RATING_SHORT, + ITEM_MOD_EXPERTISE_RATING_SHORT, + ITEM_MOD_MASTERY_RATING_SHORT +} +StatNames[0] = NONE +local StatToString = { + "ITEM_MOD_SPIRIT_SHORT", + "ITEM_MOD_DODGE_RATING_SHORT", + "ITEM_MOD_PARRY_RATING_SHORT", + "ITEM_MOD_HIT_RATING_SHORT", + "ITEM_MOD_CRIT_RATING_SHORT", + "ITEM_MOD_HASTE_RATING_SHORT", + "ITEM_MOD_EXPERTISE_RATING_SHORT", + "ITEM_MOD_MASTERY_RATING_SHORT" +} + + +local REFORGE_TABLE_BASE = 112 +local REFORGE_TABLE = { + {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}, + {2, 1}, {2, 3}, {2, 4}, {2, 5}, {2, 6}, {2, 7}, {2, 8}, + {3, 1}, {3, 2}, {3, 4}, {3, 5}, {3, 6}, {3, 7}, {3, 8}, + {4, 1}, {4, 2}, {4, 3}, {4, 5}, {4, 6}, {4, 7}, {4, 8}, + {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 6}, {5, 7}, {5, 8}, + {6, 1}, {6, 2}, {6, 3}, {6, 4}, {6, 5}, {6, 7}, {6, 8}, + {7, 1}, {7, 2}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 8}, + {8, 1}, {8, 2}, {8, 3}, {8, 4}, {8, 5}, {8, 6}, {8, 7}, +} + +--------------- returns the index into the REFORGE_TABLE or nil +-- returns the reforge id or 0 +local function GetReforgeIdForItem(item) + local id = tonumber(item:match("item:%d+:%d+:%d+:%d+:%d+:%d+:%-?%d+:%-?%d+:%d+:(%d+)")) + return (id and id ~= 0 and id or 0) +end + +local function GetReforgeIdFromStats(fromStat, toStat) + if (toStat > fromStat) then + return REFORGE_TABLE_BASE + 7 * (fromStat - 1) + toStat - 1; + else + return REFORGE_TABLE_BASE + 7 * (fromStat - 1) + toStat; + end +end + + +-------------------------------------------------------------------- +-- Initialization +-------------------------------------------------------------------- +AskMrRobot.ReforgesTab = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +function AskMrRobot.ReforgesTab:new(parent) + + local tab = AskMrRobot.Frame:new(nil, parent) + setmetatable(tab, { __index = AskMrRobot.ReforgesTab }) + tab:SetPoint("TOPLEFT") + tab:SetPoint("BOTTOMRIGHT") + tab:Hide() + + local text = tab:CreateFontString("AmrReforgesHeader", "ARTWORK", "GameFontNormalLarge") + text:SetPoint("TOPLEFT", 0, -5) + text:SetText("Reforges") + + tab.stamp = AskMrRobot.RobotStamp:new(nil, tab) + tab.stamp:Hide() + tab.stamp.smallText:SetText("Your reforges are 100% optimal!") + tab.stamp:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 2, -15) + tab.stamp:SetPoint("RIGHT", tab, "RIGHT", -20, 0) + + tab.reforgeDetails = tab:CreateFontString("AmrReforgeDetails", "ARTWORK", "GameFontWhite") + tab.reforgeDetails:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 0, -15) + tab.reforgeDetails:SetPoint("RIGHT", -30, 0) + tab.reforgeDetails:SetWordWrap(true) + tab.reforgeDetails:SetJustifyH("LEFT") + tab.reforgeDetails:SetText('Open a reforge window, then click the "Reforge!" button to do it automatically.') + tab.reforgeDetails:SetHeight(50) + + tab.reforgeButton = CreateFrame("Button", "AmrReforgeButton", tab, "UIPanelButtonTemplate") + tab.reforgeButton:SetText("Reforge!") + tab.reforgeButton:SetPoint("TOPLEFT", 0, -80) + tab.reforgeButton:SetWidth(140) + tab.reforgeButton:SetHeight(20) + tab.reforgeButton:SetScript("OnClick", function() + tab:OnReforge() + end) + + tab.reforgeCost = tab:CreateFontString(nil, "ARTWORK", "GameFontNormal") + tab.reforgeCost:SetPoint("TOPLEFT", tab.reforgeButton, "TOPRIGHT", 25, 0) + tab.reforgeCost:SetPoint("BOTTOM", tab.reforgeButton, "BOTTOM", 0, 0) + tab.reforgeCost:SetPoint("RIGHT", tab, "RIGHT", -30, 0) + tab.reforgeCost:SetText('') + + tab.slotHeader = tab:CreateFontString(nil, "ARTWORK", "GameFontNormal") + tab.slotHeader:SetText("Slot") + tab.slotHeader:SetPoint("TOPLEFT", tab.reforgeButton, "BOTTOMLEFT", 0, -30) + + tab.reforgeHeader = tab:CreateFontString(nil, "ARTWORK", "GameFontNormal") + tab.reforgeHeader:SetText("Optimal Reforge") + tab.reforgeHeader:SetPoint("TOPLEFT", tab.slotHeader, "TOPLEFT", 100, 0) + + -- pre-allocate a visual element for all possible slots; showBadReforges will set text and show the number that are needed, and hide the rest + tab.slots = {} + tab.optimized = {} + + for i = 1, #AskMrRobot.slotNames do + tab.slots[i] = tab:CreateFontString(nil, "ARTWORK", "GameFontWhite") + tab.slots[i]:SetPoint("TOPLEFT", tab.slotHeader, "TOPLEFT", 0, -20 * i) + tab.slots[i]:Hide() + + tab.optimized[i] = tab:CreateFontString(nil, "ARTWORK", "GameFontWhite") + tab.optimized[i]:SetPoint("TOPLEFT", tab.reforgeHeader, "TOPLEFT", 0, -20 * i) + tab.optimized[i]:Hide() + end + + tab:RegisterEvent("FORGE_MASTER_ITEM_CHANGED") + tab:RegisterEvent("FORGE_MASTER_SET_ITEM") + tab:RegisterEvent("FORGE_MASTER_OPENED") + tab:RegisterEvent("FORGE_MASTER_CLOSED") + + tab:SetScript("OnEvent", function(...) + tab:OnEvent(...) + end) + + + -- initialize stat required for performing the reforges + tab.state = {} + tab:ResetState() + + + return tab +end + + +-------------------------------------------------------------------- +-- Rendering +-------------------------------------------------------------------- + +local function GetReforgeString(fromId, toId) + if toId == 0 then + return "Restore" + end + local pair = REFORGE_TABLE[toId - REFORGE_TABLE_BASE] + + local text = _G[StatToString[pair[1]]] .. ' -> ' .. _G[StatToString[pair[2]]] + --print('from ' .. fromId) + if fromId == 0 then + return text + end + return 'Restore, then ' .. text +end + +-- draw all of the reforges that still need to be performed +function AskMrRobot.ReforgesTab:Render() + + local reforges = AskMrRobot.itemDiffs.reforges + local i = 1 + local cost = 0 + + -- for all the bad items + for slotNum, badReforge in AskMrRobot.sortSlots(reforges) do + + self.optimized[i]:SetText(GetReforgeString(badReforge.current, badReforge.optimized)) + self.optimized[i]:Show() + + self.slots[i]:SetText(_G[strupper(AskMrRobot.slotNames[slotNum])]) + self.slots[i]:Show() + + -- Restore is free, so only add cost for non-restore reforges + if badReforge.optimized > 0 then + local slotId = AskMrRobot.slotIds[slotNum] + local itemLink = GetInventoryItemLink("player", slotId) + cost = cost + (itemLink and select (11, GetItemInfo(itemLink)) or 0) + end + + i = i + 1 + end + + self.reforgeCost:SetText("Total reforge cost: ~" .. math.ceil(cost / 10000) .. " Gold") + + -- hide / show the headers + if i == 1 then + self.reforgeHeader:Hide() + self.slotHeader:Hide() + self.reforgeButton:Hide() + self.reforgeCost:Hide() + self.reforgeDetails:Hide() + self.stamp:Show() + else + self.stamp:Hide() + self.reforgeButton:Show() + self.reforgeCost:Show() + self.reforgeHeader:Show() + self.reforgeDetails:Show() + self.slotHeader:Show() + end + + -- hide the remaining slots + while i <= #self.slots do + self.optimized[i]:Hide() + self.slots[i]:Hide() + i = i + 1 + end +end + +-------------------------------------------------------------------- +-- Reforge Logic +-------------------------------------------------------------------- + +-- reset state for a fresh pass at automatic reforging +function AskMrRobot.ReforgesTab:ResetState() + + self.state.queue = {} -- list of all reforges actions that still need to be performed + self.state.currentItem = nil -- the current item we are trying to reforge + self.state.pendingSlot = nil -- the slot that we have requested to place into the reforger + self.state.currentSlot = nil -- the current slot in the reforger + self.state.pendingReforge = -1 -- the reforge that we have requested to perform on the current item +end + +-- refresh the queue of reforges that still need to be performed +function AskMrRobot.ReforgesTab:RefreshQueue() + + -- clear the queue + self.state.queue = {} + + local reforges = AskMrRobot.itemDiffs.reforges + + -- add all reforges that need updating to the reforge queue + for slotNum, badReforge in AskMrRobot.sortSlots(reforges) do + self:AddToReforgeQueue(slotNum, badReforge.optimized); + end +end + +function AskMrRobot.ReforgesTab:AddToReforgeQueue(itemSlot, reforgeId) + + -- the game's slot id, not the same as the ids that we use on our servers + local gameSlot = AskMrRobot.slotIds[itemSlot] + + local item = GetInventoryItemLink("player", gameSlot) + if item == nil then + --print ('no item') + return + end + + local current = GetReforgeIdForItem(item) + + if current ~= reforgeId then + -- restore first + if current ~= 0 and reforgeId ~= 0 then + tinsert(self.state.queue, { ["slot"] = gameSlot, ["reforge"] = 0 }) + end + + -- then reforge to the specified reforge + tinsert(self.state.queue, { ["slot"] = gameSlot, ["reforge"] = reforgeId }) + end +end + +function AskMrRobot.ReforgesTab:IsQueueEmpty() + return self.state.queue == nil or #self.state.queue == 0 or self.state.queue == {}; +end + +-- returns true if we are waiting on the game to finish a pending async reforge operation +function AskMrRobot.ReforgesTab:HasPendingOperation() + + -- waiting for an item to be placed into the reforger + if self.state.pendingSlot then + return true + end + + -- waiting for a reforge to be completed + if self.state.pendingReforge ~= -1 then + return true + end + + return false +end + +-- put the next item in the reforge queue into the game's reforge UI +function AskMrRobot.ReforgesTab:PutNextItemInForge() + + if self:IsQueueEmpty() or self:HasPendingOperation() then + return + end + + -- get the first action in the queue + local currentAction = self.state.queue[1] + local itemSlot = currentAction.slot + + local item = GetInventoryItemLink("player", itemSlot) + + -- set current item that we are trying to reforge + self.state.currentItem = item + + -- if this item isn't already in the reforger, put it in + if self.state.currentSlot ~= itemSlot then + ClearCursor() -- make sure no item is selected + SetReforgeFromCursorItem() -- pick up the old item (calling this with an item already in the reforger will put it back on the mouse cursor) + ClearCursor() -- clear the cursor to finish removing any current item from the game reforge UI + PickupInventoryItem(itemSlot) -- pick up the right equipped item + + -- pending, listen for an event from the game to complete setting this item into the reforger + self.state.pendingSlot = itemSlot + + SetReforgeFromCursorItem() -- put the item into the reforger, and wait for the FORGE_MASTER_SET_ITEM event, which calls DoReforge + end + +end + +-- an item is in the reforger, ready to be reforged, so do it +function AskMrRobot.ReforgesTab:DoReforge() + + if self:IsQueueEmpty() or self:HasPendingOperation() then + return + end + + local currentAction = self.state.queue[1] + local desiredReforge = currentAction.reforge + + -- the index that needs to be provided to WoW's ReforgeItem method, corresponds to one of the options in the game reforge UI + local reforgeIndex = -1 + + if desiredReforge ~= 0 then + local targetFrom = REFORGE_TABLE[desiredReforge - REFORGE_TABLE_BASE][1]; + local targetTo = REFORGE_TABLE[desiredReforge - REFORGE_TABLE_BASE][2]; + + for i=1, GetNumReforgeOptions() do + local from, _, _, to, _, _ = GetReforgeOptionInfo(i) + --print(i .. ': ' .. from .. " -> " .. to) + if StatNames[targetFrom] == from and StatNames[targetTo] == to then + reforgeIndex = i + break + end + end + else + reforgeIndex = 0 + end + + if reforgeIndex == -1 then + -- we couldn't do this reforge... we either had a bad reforge (wrong stats on an item), or the game had no options in the UI for some reason + + -- remove the item from the reforge window + ClearCursor() + SetReforgeFromCursorItem() + ClearCursor() + + -- reset state and quit reforging (clears the queue) + self:ResetState() + + else + + local currentReforge = GetReforgeIdForItem(self.state.currentItem); + if currentReforge == desiredReforge then + -- we already have this reforge on the item... probably shouldn't ever happen, but if it does, recalculate and start over + tremove(self.state.queue, 1) + + -- remove the item from the reforge window + ClearCursor() + SetReforgeFromCursorItem() + ClearCursor() + + -- update the state of the entire UI, and start again with the next required reforge + AskMrRobot_ReforgeFrame:OnUpdate() + self:OnReforge() + + else + -- we have a reforge (or restore) to do, kick it off and wait for CheckReforge to respond to completion + self:TryReforge(reforgeIndex) + end + + end + +end + +-- wraps WoW API call to ReforgeItem, fires a manual timeout in case the UI does not raise an event +function AskMrRobot.ReforgesTab:TryReforge(reforgeIndex) + + -- we have a reforge (or restore) to do, kick it off and wait for FORGE_MASTER_ITEM_CHANGED, which calls CheckReforge + self.state.pendingReforge = reforgeIndex + ReforgeItem(reforgeIndex) + + -- sometimes the game doesn't send the FORGE_MASTER_ITEM_CHANGED event, so also check after a delay also + AskMrRobot.wait(0.250, AskMrRobot.ReforgesTab.CheckReforge, self) + +end + +-- check that a requested reforge has been completed +function AskMrRobot.ReforgesTab:CheckReforge() + + if self:IsQueueEmpty() or self.state.pendingReforge == -1 then + + -- responding to a reforge that the user has manually performed, update the UI and terminate any automatic process that is going on + AskMrRobot_ReforgeFrame:OnUpdate() + self:ResetState() + + else + -- responding to a reforge that we have initiated + + local currentReforge, icon, name, quality, bound, cost = GetReforgeItemInfo(); + if currentReforge == self.state.pendingReforge then + tremove(self.state.queue, 1) + + -- remove the item from the reforge window + ClearCursor() + SetReforgeFromCursorItem() + ClearCursor() + + -- update the state of the entire UI, and start again with the next required reforge + AskMrRobot_ReforgeFrame:OnUpdate() + self:OnReforge() + else + -- try again + self:TryReforge(self.state.pendingReforge) + end + end + +end + + +-------------------------------------------------------------------- +-- Event Handling +-------------------------------------------------------------------- + +-- event called when the Mr. Robot Reforge button is clicked, kicks off automatic reforge +function AskMrRobot.ReforgesTab:OnReforge() + + -- need to be at a reforger for this to work + if not self.isReforgeOpen then + StaticPopup_Show("REFORGE_TAB_PLEASE_OPEN") + return + end + + -- reset state and refresh the queue of reforges that still need to be done + self:ResetState() + self:RefreshQueue() + + -- get goin, put the first item in the reforger + self:PutNextItemInForge() +end + +function AskMrRobot.ReforgesTab:On_FORGE_MASTER_SET_ITEM() + + if self.state.pendingSlot then + + -- we have successfully finished placing an item into the reforger + self.state.currentSlot = self.state.pendingSlot + + -- indicate that we are no longer waiting for an item + self.state.pendingSlot = nil + + -- now reforge it + self:DoReforge() + end + +end + +function AskMrRobot.ReforgesTab:On_FORGE_MASTER_ITEM_CHANGED() + self:CheckReforge() +end + +function AskMrRobot.ReforgesTab:On_FORGE_MASTER_OPENED() + self.isReforgeOpen = true +end + +function AskMrRobot.ReforgesTab:On_FORGE_MASTER_CLOSED() + self.isReforgeOpen = false +end + +function AskMrRobot.ReforgesTab:OnEvent(frame, event, ...) + --print("EVENT " .. event) + local handler = self["On_" .. event] + if handler then + handler(self, ...) + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/RobotStamp.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,38 @@ +local _, AskMrRobot = ... + +-- initialize the RobotStamp class (inherit from Frame) +AskMrRobot.RobotStamp = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +-- item icon contructor +function AskMrRobot.RobotStamp:new(name, parent) + -- create a new frame (if one isn't supplied) + local o = AskMrRobot.Frame:new(name, parent) + + -- use the RobotStamp class + setmetatable(o, { __index = AskMrRobot.RobotStamp }) + + o:SetPoint("TOPLEFT", parent, "TOPLEFT") + o:SetPoint("RIGHT", parent, "RIGHT") + o:SetHeight(80); + + o.bigText = o:CreateFontString(nil, "ARTWORK", "GameFontNormalHuge") + o.bigText:SetTextColor(7/255, 166/255, 11/255) + local file, _, flags = o.bigText:GetFont() + o.bigText:SetFont(file, 24, flags) + o.bigText:SetText("ROBOT STAMP OF APPROVAL") + o.bigText:SetPoint("TOPLEFT", o, "TOPLEFT", 15, -20) + o.bigText:SetPoint("RIGHT", o, "RIGHT", -15, 0) + + o.smallText = o:CreateFontString(nil, "ARTWORK", "GameFontWhite") + o.smallText:SetText("Your gems are 100% optimal! You are truly, truly outrageous.") + o.smallText:SetPoint("TOPLEFT", o.bigText, "BOTTOMLEFT", 0, -7) + o.smallText:SetPoint("RIGHT", o, "RIGHT", -15, 0) + o.smallText:SetWidth(o.smallText:GetWidth()) + o.smallText:SetJustifyH("CENTER") + + o:SetBackdrop({edgeFile = "Interface\\AddOns\\AskMrRobot\\Media\\round-edge-big", edgeSize = 16}) + o:SetBackdropBorderColor(7/255, 166/255, 11/255) + + -- return the instance of the RobotStamp + return o +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/ShoppingListTab.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,917 @@ +local _, AskMrRobot = ... + +-- initialize the ShoppingListTab class +AskMrRobot.ShoppingListTab = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +StaticPopupDialogs["SHOPPING_TAB_PLEASE_OPEN"] = { + text = "You need to open the mail window for this to work", + button1 = "Ok", + timeout = 0, + whileDead = true, + hideOnEscape = true, + preferredIndex = 3, -- avoid some UI taint, see http://www.wowace.com/announcements/how-to-avoid-some-ui-taint/ +} + +function AskMrRobot.ShoppingListTab:new(parent) + + local tab = AskMrRobot.Frame:new(nil, parent) + setmetatable(tab, { __index = AskMrRobot.ShoppingListTab }) + tab:SetPoint("TOPLEFT") + tab:SetPoint("BOTTOMRIGHT") + tab:Hide() + tab:RegisterEvent("AUCTION_HOUSE_CLOSED") + tab:RegisterEvent("AUCTION_HOUSE_SHOW") + tab:RegisterEvent("MAIL_SHOW") + tab:RegisterEvent("MAIL_CLOSED") + + tab.isAuctionHouseVisible = false + + tab:SetScript("OnEvent", function(...) + tab:OnEvent(...) + end) + + tab.shoppingListHeader = AskMrRobot.FontString:new(tab, nil, "ARTWORK", "GameFontNormalLarge") + tab.shoppingListHeader:SetPoint("TOPLEFT", 0, -5) + tab.shoppingListHeader:SetText("Shopping List") + + tab.shoppingPanel = AskMrRobot.Frame:new(nil, tab) + tab.shoppingPanel:SetPoint("TOPLEFT", tab.shoppingListHeader, "BOTTOMLEFT", 0, -10) + tab.shoppingPanel:SetPoint("BOTTOMRIGHT", tab, "BOTTOMRIGHT", -20, 17) + + + tab.sendButton = CreateFrame("Button", "AmrSendButton", tab.shoppingPanel, "UIPanelButtonTemplate") + tab.sendButton:SetText("send it!") + tab.sendButton:SetPoint("BOTTOMLEFT", 0, 0) + tab.sendButton:SetHeight(25) + tab.sendButton:SetNormalFontObject("GameFontNormalLarge") + tab.sendButton:SetHighlightFontObject("GameFontHighlightLarge") + tab.sendButton:SetWidth(150) + tab.sendButton:SetScript("OnClick", function() + tab:Send() + end) + + tab.enchantMaterialsCheckbox = CreateFrame("CheckButton", "AmrEnchantMaterialsCheckbox", tab.shoppingPanel, "ChatConfigCheckButtonTemplate"); + tab.enchantMaterialsCheckbox:SetChecked(AmrSendSettings.SendEnchantMaterials) + tab.enchantMaterialsCheckbox:SetScript("OnClick", function () AmrSendSettings.SendEnchantMaterials = tab.enchantMaterialsCheckbox:GetChecked() end) + tab.enchantMaterialsCheckbox:SetPoint("TOPLEFT", tab.sendButton, "TOPLEFT", 0, 25) + local text3 = getglobal(tab.enchantMaterialsCheckbox:GetName() .. 'Text') + text3:SetFontObject("GameFontHighlightLarge") + text3:SetText("Enchant Materials") + text3:SetWidth(150) + text3:SetPoint("TOPLEFT", tab.enchantMaterialsCheckbox, "TOPRIGHT", 2, -4) + + + tab.enchantsCheckbox = CreateFrame("CheckButton", "AmrEnchantsCheckbox", tab.shoppingPanel, "ChatConfigCheckButtonTemplate"); + tab.enchantsCheckbox:SetChecked(AmrSendSettings.SendEnchants) + tab.enchantsCheckbox:SetScript("OnClick", function () AmrSendSettings.SendEnchants = tab.enchantsCheckbox:GetChecked() end) + tab.enchantsCheckbox:SetPoint("TOPLEFT", tab.sendButton, "TOPLEFT", 0, 50) + local text2 = getglobal(tab.enchantsCheckbox:GetName() .. 'Text') + text2:SetFontObject("GameFontHighlightLarge") + text2:SetText("Enchants") + text2:SetWidth(150) + text2:SetPoint("TOPLEFT", tab.enchantsCheckbox, "TOPRIGHT", 2, -4) + + + + tab.gemsCheckbox = CreateFrame("CheckButton", "AmrGemsCheckbox", tab.shoppingPanel, "ChatConfigCheckButtonTemplate"); + tab.gemsCheckbox:SetPoint("TOPLEFT", tab.sendButton, "TOPLEFT", 0, 75) + tab.gemsCheckbox:SetChecked(AmrSendSettings.SendGems) + tab.gemsCheckbox:SetScript("OnClick", function () AmrSendSettings.SendGems = tab.gemsCheckbox:GetChecked() end) + local text = getglobal(tab.gemsCheckbox:GetName() .. 'Text') + text:SetFontObject("GameFontHighlightLarge") + text:SetText("Gems") + text:SetWidth(150) + text:SetPoint("TOPLEFT", tab.gemsCheckbox, "TOPRIGHT", 2, -4) + + + tab.sendMessage4 = AskMrRobot.FontString:new(tab.shoppingPanel, nil, "ARTWORK", "GameFontHighlightLarge") + tab.sendMessage4:SetText("Include:") + tab.sendMessage4:SetPoint("TOPLEFT", tab.gemsCheckbox, "TOPLEFT", 0, 20) + + + tab.sendMessage3 = AskMrRobot.FontString:new(tab.shoppingPanel, nil, "ARTWORK", "GameFontHighlightLarge") + tab.sendMessage3:SetText("Send list to") + tab.sendMessage3:SetPoint("TOPLEFT", tab.sendMessage4, "TOPLEFT", 0, 25) + + + tab.sendMessage2 = AskMrRobot.FontString:new(tab.shoppingPanel, nil, "ARTWORK", "GameFontNormal") + tab.sendMessage2:SetTextColor(.5,.5,.5) + tab.sendMessage2:SetText("Whisper to a friend or send to a channel, like /raid or /guild.") + tab.sendMessage2:SetPoint("TOPLEFT", tab.sendMessage3, "TOPLEFT", 0, 25) + + + tab.sendMessage1 = AskMrRobot.FontString:new(tab.shoppingPanel, nil, "ARTWORK", "GameFontNormalLarge") + tab.sendMessage1:SetTextColor(0,1,0) + tab.sendMessage1:SetText("Send to a Jewelcraft or Enchanter friend :)") + tab.sendMessage1:SetPoint("TOPLEFT", tab.sendMessage2, "TOPLEFT", 0, 25) + + + tab.scrollFrame = CreateFrame("ScrollFrame", "AmrScrollFrame", tab.shoppingPanel, "UIPanelScrollFrameTemplate") + tab.scrollFrame:SetPoint("TOPLEFT", 0, 0) + tab.scrollFrame:SetPoint("RIGHT", -20, 0) + tab.scrollFrame:SetPoint("BOTTOM", tab.sendMessage1, "TOP", 0, 10) + + tab.scrollParent = AskMrRobot.Frame:new(nil, tab.shoppingPanel) + tab.scrollParent:SetPoint("TOPLEFT", 0, 0) + tab.scrollParent:SetWidth(tab:GetWidth() - 20) + tab.scrollParent:SetHeight(500) + tab.scrollFrame:SetScrollChild(tab.scrollParent) + + -- magic to get the scrollbar to work with the scrollwheel... + tab.scrollFrame:SetScript("OnMouseWheel", function(arg1, arg2) + ScrollFrameTemplate_OnMouseWheel(arg1, arg2, arg1.ScrollBar) + end) + + tab.gemsHeader = AskMrRobot.FontString:new(tab.scrollParent, nil, "ARTWORK", "GameFontNormalLarge") + tab.gemsHeader:SetText("Gems") + tab.gemsHeader:SetPoint("TOPLEFT", tab.scrollParent, "TOPLEFT", 0, 0) + + tab.gemsQuantityHeader = AskMrRobot.FontString:new(tab.scrollParent, nil, "ARTWORK", "GameFontNormalLarge") + tab.gemsQuantityHeader:SetText("Total") + tab.gemsQuantityHeader:SetPoint("TOPLEFT", tab.scrollParent, "TOPLEFT", 370, 0) + + tab.enchantsHeader = AskMrRobot.FontString:new(tab.scrollParent, nil, "ARTWORK", "GameFontNormalLarge") + tab.enchantsHeader:SetText("Enchants") + + tab.enchantsQuantityHeader = AskMrRobot.FontString:new(tab.scrollParent, nil, "ARTWORK", "GameFontNormalLarge") + tab.enchantsQuantityHeader:SetText("Total") + tab.enchantsQuantityHeader:SetPoint("TOPLEFT", tab.enchantsHeader, "TOPLEFT", 370, 0) + + tab.enchantMaterialsHeader = AskMrRobot.FontString:new(tab.scrollParent, nil, "ARTWORK", "GameFontNormalLarge") + tab.enchantMaterialsHeader:SetText("Enchant Materials") + + tab.enchantMaterialsQuantityHeader = AskMrRobot.FontString:new(tab.scrollParent, nil, "ARTWORK", "GameFontNormalLarge") + tab.enchantMaterialsQuantityHeader:SetText("Total") + tab.enchantMaterialsQuantityHeader:SetPoint("TOPLEFT", tab.enchantMaterialsHeader, "TOPLEFT", 370, 0) + + tab.stamp = AskMrRobot.RobotStamp:new(nil, tab) + tab.stamp:Hide() + tab.stamp.bigText:SetText("YOUR SHOPPING IS ALL DONE!") + tab.stamp.smallText:SetText("Unless you want to buy me a birthday present! I like titanium bolts and robot dogs... Or was it titanium dogs and robot bolts...") + tab.stamp:SetPoint("TOPLEFT", tab.shoppingListHeader, "BOTTOMLEFT", 2, -15) + tab.stamp:SetPoint("RIGHT", tab, "RIGHT", -30, 0) + tab.stamp:SetHeight(92) + + tab.gemIcons = {} + tab.gemLinks = {} + tab.gemQuantity = {} + tab.enchantIcons = {} + tab.enchantLinks = {} + tab.enchantQuantity = {} + tab.enchantMaterialIcons = {} + tab.enchantMaterialLinks = {} + tab.enchantMaterialQuantity = {} + + -- Create the dropdown, and configure its appearance + tab.dropDown = CreateFrame("FRAME", "AmrSendType", tab.shoppingPanel, "UIDropDownMenuTemplate") + tab.dropDown:SetPoint("TOPLEFT", tab.sendMessage3, "TOPRIGHT", 0, 5) + UIDropDownMenu_SetWidth(tab.dropDown, 140) + UIDropDownMenu_SetText(tab.dropDown, AmrSendSettings.SendToType) + + local text = getglobal(tab.dropDown:GetName() .. 'Text') + text:SetFontObject("GameFontHighlightLarge") + + local AddButton = function(list, optionText) + local info = UIDropDownMenu_CreateInfo() + info.justifyH = "RIGHT" + info.text = optionText + info.checked = AmrSendSettings.SendToType == optionText + info.arg1 = optionText + info.func = list.SetValue + info.owner = list + info.fontObject = "GameFontHighlightLarge" + info.minWidth = 140 + return info + end + + -- Create and bind the initialization function to the dropdown menu + UIDropDownMenu_Initialize(tab.dropDown, function(self, level, menuList) + UIDropDownMenu_AddButton(AddButton(self, "a friend")) + UIDropDownMenu_AddButton(AddButton(self, "party")) + UIDropDownMenu_AddButton(AddButton(self, "raid")) + UIDropDownMenu_AddButton(AddButton(self, "guild")) + UIDropDownMenu_AddButton(AddButton(self, "channel")) + UIDropDownMenu_AddButton(AddButton(self, "mail")) + end) + + function tab.dropDown:SetValue(newValue) + AmrSendSettings.SendToType = newValue + -- Update the text; if we merely wanted it to display newValue, we would not need to do this + UIDropDownMenu_SetText(tab.dropDown, AmrSendSettings.SendToType) + -- Because this is called from a sub-menu, only that menu level is closed by default. + -- Close the entire menu with this next call + CloseDropDownMenus() + end + + tab.sendTo = CreateFrame("EditBox", "AmrSendTo", tab.shoppingPanel, "InputBoxTemplate" ) + tab.sendTo:SetPoint("TOPLEFT", tab.dropDown, "TOPRIGHT", 0, 0) + tab.sendTo:SetPoint("RIGHT", 0, 0) + tab.sendTo:SetHeight(30) + tab.sendTo:SetText(AmrSendSettings.SendTo or "") + tab.sendTo:SetFontObject("GameFontHighlightLarge") + tab.sendTo:SetAutoFocus(false) + tab.sendTo:SetScript("OnChar", function() + AmrSendSettings.SendTo = tab.sendTo:GetText() + end) + + tab.messageQueue = {} + return tab +end + +-- display a gem icon in a row +-- gemInfo is {id, enchantId, color, count } +function AskMrRobot.ShoppingListTab:SetGemIcon(row, gemInfo) + -- get gem icon for the row + local gemIcon = self.gemIcons[row] + + -- if we don't have one + if gemIcon == nil then + -- make one + gemIcon = AskMrRobot.GemIcon:new(nil, self.scrollParent) + self.gemIcons[row] = gemIcon + gemIcon:SetScript("OnMouseDown", function() + self:SearchForGem(row) + end) + + -- position it + local previous = self.gemsHeader + if row > 1 then + previous = self.gemIcons[row - 1] + end + gemIcon:SetPoint("TOPLEFT", previous, "BOTTOMLEFT", 0, -7) + + -- size it + gemIcon:SetWidth(24) + gemIcon:SetHeight(24) + + -- give it a nice border + gemIcon:SetRoundBorder() + end + + gemIcon:Show() + + -- make a link for the optimized gem + gemLink = select(2, GetItemInfo(gemInfo.id)) + + -- set the link (tooltip + icon) + gemIcon:SetItemLink(gemLink) + gemIcon:SetGemColor(gemInfo.color) + + -- if we didn't get one, its because WoW is slow + if not gemLink and gemInfo.id then + -- when WoW finally returns the link, set the icon / tooltip + AskMrRobot.RegisterItemInfoCallback(gemInfo.id, function(name, link) + gemIcon:SetItemLink(link) + end) + end + +end + + +-- display a gem icon in a row +-- gemInfo is {id, enchantId, color, count } +function AskMrRobot.ShoppingListTab:SetGemText(row, gemInfo) + -- get gem icon for the row + local gemText = self.gemLinks[row] + + -- if we don't have one + if gemText == nil then + -- make one + gemText = AskMrRobot.ItemLinkText:new(nil, self.scrollParent) + self.gemLinks[row] = gemText + gemText:SetScript("OnMouseDown", function() + self:SearchForGem(row) + end) + + -- position it + local previous = self.gemsHeader + if row > 1 then + previous = self.gemIcons[row - 1] + end + gemText:SetPoint("TOPLEFT", previous, "BOTTOMLEFT", 30, -8) + gemText:SetPoint("RIGHT", self, "RIGHT", -70, 0) + gemText:SetHeight(18) + gemText:SetFontSize(15) + end + + gemText:Show() + + gemText:SetItemId(gemInfo.id) +end + +-- display a gem icon in a row +-- gemInfo is {id, enchantId, color, count } +function AskMrRobot.ShoppingListTab:SetGemQuantity(row, qty, total) + if qty > total then qty = total end + + -- get gem icon for the row + local gemText = self.gemQuantity[row] + + -- if we don't have one + if gemText == nil then + -- make one + gemText = AskMrRobot.FontString:new(self.scrollParent, nil, "ARTWORK", "GameFontNormalLarge") + self.gemQuantity[row] = gemText + + -- position it + local previous = self.gemsHeader + if row > 1 then + previous = self.gemIcons[row - 1] + end + gemText:SetPoint("TOPLEFT", previous, "BOTTOMLEFT", 370, -8) + gemText:SetHeight(18) + gemText:SetFontSize(15) + end + + gemText:SetText('' .. qty .. '/' .. total) + if qty == total then + gemText:SetTextColor(0,1,0) + else + gemText:SetTextColor(1,0,0) + end + gemText:Show() +end + + +-- display an enchant icon in a row +function AskMrRobot.ShoppingListTab:SetEnchantIcon(row, enchantId) + + -- get enchant icon for the row + local enchantIcon = self.enchantIcons[row] + + -- if we don't have one + if enchantIcon == nil then + -- make one + enchantIcon = AskMrRobot.EnchantLinkIconAndText:new(nil, self.scrollParent) + self.enchantIcons[row] = enchantIcon + enchantIcon:SetScript("OnMouseDown", function() + self:SearchForEnchant(row) + end) + + -- position it + if row == 1 then + enchantIcon:SetPoint("TOPLEFT", self.enchantsHeader, "BOTTOMLEFT", 0, -12) + enchantIcon:SetPoint("RIGHT", self.scrollParent, "RIGHT", -30, 0) + else + enchantIcon:SetPoint("TOPLEFT", self.enchantIcons[row - 1], "BOTTOMLEFT", 0, -7) + enchantIcon:SetPoint("RIGHT", self.scrollParent, "RIGHT", -30, 0) + end + + -- size it + enchantIcon:SetWidth(24) + enchantIcon:SetHeight(24) + enchantIcon:SetFontSize(15) + + -- give it a nice border + enchantIcon:SetRoundBorder() + + enchantIcon:UseSpellName() + end + + enchantIcon:SetEnchantId(enchantId) + + enchantIcon:Show() +end + +-- display a gem icon in a row +-- gemInfo is {id, enchantId, color, count } +function AskMrRobot.ShoppingListTab:SetEnchantQuantity(row, qty, total) + if qty > total then qty = total end + + -- get gem icon for the row + local enchantText = self.enchantQuantity[row] + + -- if we don't have one + if enchantText == nil then + -- make one + enchantText = AskMrRobot.FontString:new(self.scrollParent, nil, "ARTWORK", "GameFontNormalLarge") + self.enchantQuantity[row] = enchantText + + -- position it + local previous = self.enchantsHeader + if row > 1 then + previous = self.enchantIcons[row - 1] + end + enchantText:SetPoint("TOPLEFT", previous, "BOTTOMLEFT", 370, -8) + enchantText:SetHeight(18) + enchantText:SetFontSize(15) + end + + enchantText:SetText('' .. qty .. '/' .. total) + if qty == total then + enchantText:SetTextColor(0,1,0) + else + enchantText:SetTextColor(1,0,0) + end + enchantText:Show() +end + +function AskMrRobot.ShoppingListTab:SearchForItem(itemName) + if self.isAuctionHouseVisible then + QueryAuctionItems(itemName, nil, nil, 0, 0, 0, 0, 0, 0, 0) + end +end + +function AskMrRobot.ShoppingListTab:SearchForGem(row) + self:SearchForItem(self.gemLinks[row].itemName) +end + +function AskMrRobot.ShoppingListTab:SearchForEnchant(row) + self:SearchForItem(self.enchantIcons[row].itemName) +end + +function AskMrRobot.ShoppingListTab:SearchForEnchantMaterial(row) + self:SearchForItem(self.enchantMaterialLinks[row].itemName) +end + + +-- display an enchant material icon in a row +function AskMrRobot.ShoppingListTab:SetEnchantMaterialIcon(row, itemId) + -- get enchant material icon for the row + local materialIcon = self.enchantMaterialIcons[row] + + -- if we don't have one + if materialIcon == nil then + -- make one + materialIcon = AskMrRobot.ItemIcon:new(nil, self.scrollParent) + self.enchantMaterialIcons[row] = materialIcon + materialIcon:SetScript("OnMouseDown", function() + self:SearchForEnchantMaterial(row) + end) + + -- position it + local previous = self.enchantMaterialsHeader + if row > 1 then + previous = self.enchantMaterialIcons[row - 1] + end + materialIcon:SetPoint("TOPLEFT", previous, "BOTTOMLEFT", 0, -7) + + -- size it + materialIcon:SetWidth(24) + materialIcon:SetHeight(24) + + -- give it a nice border + materialIcon:SetRoundBorder() + end + + materialIcon:Show() + + -- make a link for the optimized gem + local itemLink = select(2, GetItemInfo(itemId)) + + materialIcon:SetItemLink(itemLink) + + -- if we didn't get one, its because WoW is slow + if not itemLink and itemId then + -- when WoW finally returns the link, set the icon / tooltip + AskMrRobot.RegisterItemInfoCallback(itemId, function(name, link) + materialIcon:SetItemLink(link) + end) + end +end + + +-- display an enchant material link in a row +function AskMrRobot.ShoppingListTab:SetEnchantMaterialLink(row, itemId) + -- get gem icon for the row + local materialLink = self.enchantMaterialLinks[row] + + -- if we don't have one + if materialLink == nil then + -- make one + materialLink = AskMrRobot.ItemLinkText:new(nil, self.scrollParent) + self.enchantMaterialLinks[row] = materialLink + materialLink:SetScript("OnMouseDown", function() + self:SearchForEnchantMaterial(row) + end) + + -- position it + local previous = self.enchantMaterialsHeader + if row > 1 then + previous = self.enchantMaterialIcons[row - 1] + end + materialLink:SetPoint("TOPLEFT", previous, "BOTTOMLEFT", 30, -8) + materialLink:SetPoint("RIGHT", self, "RIGHT", -30, 0) + materialLink:SetHeight(18) + materialLink:SetFontSize(15) + end + + materialLink:Show() + + materialLink:SetItemId(itemId) + materialLink.itemId = itemId +end + +-- display a gem icon in a row +-- gemInfo is {id, enchantId, color, count } +function AskMrRobot.ShoppingListTab:SetEnchantMaterialQuantity(row, qty, total) + if qty > total then qty = total end + + -- get gem icon for the row + local enchantText = self.enchantMaterialQuantity[row] + + -- if we don't have one + if enchantText == nil then + -- make one + enchantText = AskMrRobot.FontString:new(self.scrollParent, nil, "ARTWORK", "GameFontNormalLarge") + self.enchantMaterialQuantity[row] = enchantText + + -- position it + local previous = self.enchantMaterialsHeader + if row > 1 then + previous = self.enchantMaterialIcons[row - 1] + end + enchantText:SetPoint("TOPLEFT", previous, "BOTTOMLEFT", 370, -8) + enchantText:SetHeight(18) + enchantText:SetFontSize(15) + end + + enchantText:SetText('' .. qty .. '/' .. total) + if qty == total then + enchantText:SetTextColor(0,1,0) + else + enchantText:SetTextColor(1,0,0) + end + enchantText:Show() +end + +function AskMrRobot.ShoppingListTab:HasStuffToBuy() + + local gemList, enchantList, enchantMaterials = self:CalculateItems() + + local count = 0 + for gemId, gemInfo in AskMrRobot.spairs(gemList) do + count = count + gemInfo.total - gemInfo.count + end + for slot, enchant in AskMrRobot.spairs(enchantList) do + count = count + enchant.total - enchant.count + end + + return count > 0 +end + +function AskMrRobot.ShoppingListTab:CalculateItems() + -- build a map of missing gem-ids -> {id, color, enchantid, count, total} + local gemList = {} + for slotNum, badGems in pairs(AskMrRobot.itemDiffs.gems) do + --badGems: {current: array of enchant ids, optimized: (array of {id, color, enchantId}) + for i = 1, #badGems.optimized do + if badGems.badGems[i] then + local goodGem = badGems.optimized[i] + if goodGem.id ~= 0 then + local gem = gemList[goodGem.id] + if gem == nil then + gemList[goodGem.id] = {id = goodGem.id, enchantId = goodGem.enchantId, color = goodGem.color, count = 0, total = 1} + else + gem.total = gem.total + 1 + end + end + end + end + end + + local enchantList = {} + for slot, enchantData in AskMrRobot.sortSlots(AskMrRobot.itemDiffs.enchants) do + local id = AskMrRobot.getEnchantItemId(enchantData.optimized) or enchantData.optimized + local qty = enchantList[id] + if qty then + qty.total = qty.total + 1 + else + qty = { count = 0, total = 1, optimized = enchantData.optimized } + enchantList[id] = qty + end + end + + local enchantMaterials = {} + for slot, enchantData in pairs(AskMrRobot.itemDiffs.enchants) do + AskMrRobot.addEnchantMaterials(enchantMaterials, enchantData.optimized) + end + + --substract any inventory we already have in the bank + for i = 1, #AmrBankItemsAndCounts do + local itemId = AskMrRobot.getItemIdFromLink(AmrBankItemsAndCounts[i].link) + if itemId then + local gem = gemList[itemId] + if gem then + gem.count = gem.count + AmrBankItemsAndCounts[i].count + else + local alternateGemId = AskMrRobot.gemDuplicates[itemId] + if alternateGemId then + gem = gemList[alternateGemId] + if gem then + gem.count = gem.count + AmrBankItemsAndCounts[i].count + end + end + end + local material = enchantMaterials[itemId] + if material then + material.count = material.count + AmrBankItemsAndCounts[i].count + end + local enchant = enchantList[itemId] + if enchant then + enchant.count = enchant.count + AmrBankItemsAndCounts[i].count + end + end + end + + local _ , bagItemsWithCount = AskMrRobot.ScanBags() + + --substract any inventory we already have in bags + for i = 1, #bagItemsWithCount do + local itemId = AskMrRobot.getItemIdFromLink(bagItemsWithCount[i].link) + if itemId then + local gem = gemList[itemId] + if gem then + gem.count = gem.count + bagItemsWithCount[i].count + else + local alternateGemId = AskMrRobot.gemDuplicates[itemId] + if alternateGemId then + gem = gemList[alternateGemId] + if gem then + gem.count = gem.count + bagItemsWithCount[i].count + end + end + end + local material = enchantMaterials[itemId] + if material then + material.count = material.count + bagItemsWithCount[i].count + end + local enchant = enchantList[itemId] + if enchant then + enchant.count = enchant.count + bagItemsWithCount[i].count + end + end + end + + return gemList, enchantList, enchantMaterials +end + +function AskMrRobot.ShoppingListTab:Update() + + local gemList, enchantList, enchantMaterials = self:CalculateItems() + + -- update the UI + local lastControl = nil + local row = 1 + for gemId, gemInfo in AskMrRobot.spairs(gemList) do + self:SetGemIcon(row, gemInfo) + self:SetGemText(row, gemInfo) + self:SetGemQuantity(row, gemInfo.count, gemInfo.total) + lastControl = self.gemIcons[row] + row = row + 1 + end + + -- hide any extra gem icons + for i = row, #self.gemIcons do + self.gemIcons[i]:Hide() + self.gemLinks[i]:Hide() + self.gemQuantity[i]:Hide() + end + + -- hide / show the gems header, and position the enchant headers + if row > 1 then + self.gemsHeader:Show() + self.gemsQuantityHeader:Show() + self.enchantsHeader:SetPoint("TOPLEFT", self.gemIcons[row - 1], "BOTTOMLEFT", 0, -15) + else + self.gemsHeader:Hide() + self.gemsQuantityHeader:Hide() + self.enchantsHeader:SetPoint("TOPLEFT", self.scrollParent, "TOPLEFT", 0, 0) + end + + row = 1 + for slot, enchant in AskMrRobot.spairs(enchantList) do + self:SetEnchantIcon(row, enchant.optimized) + self:SetEnchantQuantity(row, enchant.count, enchant.total) + lastControl = self.enchantIcons[row] + row = row + 1 + end + + -- hide any extra enchant icons + for i = row, #self.enchantIcons do + self.enchantIcons[i]:Hide() + self.enchantQuantity[i]:Hide() + end + + -- hide / show the enchants header, and position the enchant materials headers + if row > 1 then + self.enchantsHeader:Show() + self.enchantsQuantityHeader:Show() + self.enchantMaterialsHeader:SetPoint("TOPLEFT", self.enchantIcons[row - 1], "BOTTOMLEFT", 0, -15) + else + self.enchantsHeader:Hide() + self.enchantsQuantityHeader:Hide() + self.enchantMaterialsHeader:SetPoint("TOPLEFT", self.scrollParent, "TOPLEFT", 0, 0) + end + + row = 1 + for itemId, count in AskMrRobot.spairs(enchantMaterials) do + self:SetEnchantMaterialIcon(row, itemId) + self:SetEnchantMaterialLink(row, itemId) + self:SetEnchantMaterialQuantity(row, count.count, count.total) + lastControl = self.enchantMaterialIcons[row] + row = row + 1 + end + + for i = row, #self.enchantMaterialIcons do + self.enchantMaterialIcons[i]:Hide() + self.enchantMaterialLinks[i]:Hide() + self.enchantMaterialQuantity[i]:Hide() + end + + if row == 1 then + self.enchantMaterialsHeader:Hide() + self.enchantMaterialsQuantityHeader:Hide() + else + self.enchantMaterialsHeader:Show() + self.enchantMaterialsQuantityHeader:Show() + end + + -- fix up the scrollbar length + if lastControl then + local height = self.scrollParent:GetTop() - lastControl:GetBottom() + self.scrollParent:SetHeight(height) + if height < self.scrollFrame:GetHeight() then + self.scrollFrame.ScrollBar:Hide() + else + self.scrollFrame:Show() + self.scrollFrame.ScrollBar:Show() + end + self.stamp:Hide() + self.shoppingPanel:Show() + else + self.scrollFrame.ScrollBar:Hide() + self.shoppingPanel:Hide() + self.stamp:Show() + end +end + + +function AskMrRobot.ShoppingListTab:OnEvent(frame, event, ...) + local handler = self["On_" .. event] + if handler then + handler(self, ...) + end +end + +function AskMrRobot.ShoppingListTab:On_MAIL_SHOW() + self.mailOpen = true +end + +function AskMrRobot.ShoppingListTab:On_MAIL_CLOSED() + self.mailOpen = nil +end + +function AskMrRobot.ShoppingListTab:On_AUCTION_HOUSE_SHOW() + self.isAuctionHouseVisible = true +end + +function AskMrRobot.ShoppingListTab:On_AUCTION_HOUSE_CLOSED() + self.isAuctionHouseVisible = false +end + +function AskMrRobot.ShoppingListTab:sendMail() + + -- need mail window to be open for this to work + if not self.mailOpen then + StaticPopup_Show("SHOPPING_TAB_PLEASE_OPEN") + return + end + + local message = "Mr. Robot says I need the following to optimize my gear:\n" + + local gemList, enchantList, enchantMaterials = self:CalculateItems() + + if AmrSendSettings.SendGems then + for k,v in pairs(gemList) do + --exclude jewelcrafter gems + if not AskMrRobot.JewelcrafterGems[k] then + local needed = v.total - v.count + if needed > 0 then + local itemName = GetItemInfo(k) + if itemName then + message = message .. "\n" .. needed .. "x " .. itemName + end + end + end + end + end + + if AmrSendSettings.SendEnchants then + for k,v in pairs(enchantList) do + local needed = v.total - v.count + if needed > 0 then + local itemName = GetItemInfo(k) + if itemName then + message = message .. "\n" .. needed .. "x " .. itemName + end + end + end + end + + if AmrSendSettings.SendEnchantMaterials then + for k,v in pairs(enchantMaterials) do + local needed = v.total - v.count + if needed > 0 then + local itemName = GetItemInfo(k) + if itemName then + message = message .. "\n" .. needed .. "x " .. itemName + end + end + end + end + + MailFrameTab_OnClick(nil, 2) + if AmrSendSettings.SendGems then + if AmrSendSettings.SendEnchants then + SendMailSubjectEditBox:SetText('Request for gems and enchants') + else + SendMailSubjectEditBox:SetText('Request for gems') + end + else + SendMailSubjectEditBox:SetText('Request for enchants') + end + SendMailNameEditBox:SetText(AmrSendSettings.SendTo) + SendMailBodyEditBox:SetText(message) +end + +function AskMrRobot.ShoppingListTab:Send() + local chatType = nil + if AmrSendSettings.SendToType == "party" then + chatType = "PARTY" + elseif AmrSendSettings.SendToType == "guild" then + chatType = "GUILD" + elseif AmrSendSettings.SendToType == "raid" then + chatType = "RAID" + elseif AmrSendSettings.SendToType == "channel" then + chatType = "CHANNEL" + elseif AmrSendSettings.SendToType == "mail" then + self:sendMail() + return + else + chatType = "WHISPER" + end + + local message = "Mr. Robot says I need" + local count = 0 + + + local gemList, enchantList, enchantMaterials = self:CalculateItems() + + local items = {} + if AmrSendSettings.SendGems then + for k,v in pairs(gemList) do + if not AskMrRobot.JewelcrafterGems[k] then + local needed = v.total - v.count + if needed > 0 then + tinsert(items, {id = k, needed = needed}) + end + end + end + end + + if AmrSendSettings.SendEnchants then + for k,v in pairs(enchantList) do + local needed = v.total - v.count + if needed > 0 then + tinsert(items, {id = k, needed = needed}) + end + end + end + + if AmrSendSettings.SendEnchantMaterials then + for k,v in pairs(enchantMaterials) do + local needed = v.total - v.count + if needed > 0 then + tinsert(items, {id = k, needed = needed}) + end + end + end + + for i, entry in ipairs(items) do + local _, link = GetItemInfo(entry.id) + if link then + message = message .. " " .. entry.needed .. "x " .. link + count = count + 1 + if count == 2 then + tinsert(self.messageQueue, {message = message, chatType = chatType, chatChannel = AmrSendSettings.SendTo}) + count = 0 + message = "Mr. Robot says I need" + end + end + end + + if count > 0 then + tinsert(self.messageQueue, {message = message, chatType = chatType, chatChannel = AmrSendSettings.SendTo}) + end + + self:SendNextMessage() +end + +function AskMrRobot.ShoppingListTab:SendNextMessage() + while #self.messageQueue > 0 do + local entry = self.messageQueue[1] + table.remove(self.messageQueue, 1) + SendChatMessage(entry.message, entry.chatType, nil, entry.chatChannel) + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/SummaryTab.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,454 @@ +local _, AskMrRobot = ... + +AskMrRobot.SummaryTab = AskMrRobot.inheritsFrom(AskMrRobot.Frame) + +function AskMrRobot.SummaryTab:new(parent) + + local tab = AskMrRobot.Frame:new(nil, parent) + setmetatable(tab, { __index = AskMrRobot.SummaryTab }) + tab:SetPoint("TOPLEFT") + tab:SetPoint("BOTTOMRIGHT") + tab:Hide() + + + tab.importDate = "" + + local text = tab:CreateFontString("AmrSummaryText1", "ARTWORK", "GameFontNormalLarge") + text:SetPoint("TOPLEFT", 0, -5) + text:SetFormattedText("Summary") + + -- error text + tab.errorText1 = tab:CreateFontString("AmrSummaryErrorText1", "ARTWORK", "GameFontRedLarge") + tab.errorText1:SetPoint("TOPLEFT", "AmrSummaryText1", "BOTTOMLEFT", 0, -20) + tab.errorText1:SetText("You have no optimizations imported.") + tab.errorText1:SetPoint("RIGHT", -20, 0) + tab.errorText1:SetWidth(tab.errorText1:GetWidth()) + tab.errorText1:SetWordWrap(true) + tab.errorText1:SetJustifyH("LEFT") + + tab.errorText2 = tab:CreateFontString("AmrSummaryErrorText2", "ARTWORK", "GameFontWhite") + tab.errorText2:SetPoint("TOPLEFT", "AmrSummaryErrorText1", "BOTTOMLEFT", 0, -15) + tab.errorText2:SetPoint("RIGHT", -20, 0) + tab.errorText2:SetWidth(tab.errorText2:GetWidth()) + tab.errorText2:SetJustifyH("LEFT") + tab.errorText2:SetText('Click the "Import" tab to get started.') + + -- bad items + tab.badItemSlots = {} + tab.badItemNames = {} + + local itemText = tab:CreateFontString("AmrBadItemSlot0", "ARTWORK", "GameFontNormal") + itemText:SetPoint("TOPLEFT", "AmrSummaryErrorText2", "BOTTOMLEFT", 0, -20) + itemText:SetText("Slot") + itemText:SetWidth(100) + itemText:SetJustifyH("LEFT") + itemText:Hide() + tinsert(tab.badItemSlots, itemText) + + itemText = tab:CreateFontString("AmrBadItemName0", "ARTWORK", "GameFontNormal") + itemText:SetPoint("TOPLEFT", "AmrBadItemSlot0", "TOPLEFT", 120, 0) + itemText:SetPoint("RIGHT", -30, 0) + itemText:SetText("Item Name") + itemText:SetJustifyH("LEFT") + itemText:Hide() + tinsert(tab.badItemNames, itemText) + + itemText = tab:CreateFontString(nil, "ARTWORK", "GameFontWhite") + itemText:SetPoint("LEFT", 0, 0) + itemText:SetPoint("RIGHT", -30, 0) + itemText:SetPoint("TOP", "AmrBadItemSlot0", "TOP", 0, 0 ) + itemText:SetText("Please upgrade the following items:") + itemText:SetJustifyH("LEFT") + itemText:Hide() + tab.upgradeInstructions = itemText + + itemText = tab:CreateFontString(nil, "ARTWORK", "GameFontNormal") + itemText:SetPoint("LEFT", "AmrBadItemSlot0", "LEFT", 0, -20) + itemText:SetPoint("RIGHT", "AmrBadItemSlot0", "RIGHT", 0, -20) + itemText:SetPoint("TOP", tab.upgradeInstructions, "BOTTOM", 0, -10 ) + itemText:SetHeight(20) + itemText:SetText("Slot") + itemText:SetJustifyH("LEFT") + itemText:Hide() + tab.upgradeSlotHeader = itemText + + itemText = tab:CreateFontString(nil, "ARTWORK", "GameFontNormal") + itemText:SetPoint("LEFT", "AmrBadItemName0", "LEFT", 0, 0) + itemText:SetPoint("RIGHT", "AmrBadItemName0", "RIGHT", 0, 0) + itemText:SetPoint("TOP", tab.upgradeSlotHeader, "TOP", 0, 0) + itemText:SetPoint("BOTTOM", tab.upgradeSlotHeader, "BOTTOM", 0, 0) + itemText:SetText("Item Name") + itemText:SetJustifyH("LEFT") + itemText:Hide() + tab.upgradeItemHeader = itemText + + for i = 1, #AskMrRobot.slotNames do + local itemText = tab:CreateFontString("AmrBadItemSlot" .. i, "ARTWORK", "GameFontWhite") + itemText:SetPoint("TOPLEFT", "AmrBadItemSlot" .. (i-1), "BOTTOMLEFT", 0, -5) + itemText:SetPoint("TOPRIGHT", "AmrBadItemSlot" .. (i-1), "BOTTOMRIGHT", 0, -5) + itemText:SetJustifyH("LEFT") + itemText:Hide() + tinsert(tab.badItemSlots, itemText) + + itemText = AskMrRobot.ItemLinkText:new(nil, tab) + itemText:SetPoint("LEFT", "AmrBadItemName0", "TOPLEFT", 0, 0) + itemText:SetPoint("RIGHT", "AmrBadItemName0", "BOTTOMRIGHT", 0, 0) + itemText:SetPoint("TOP", "AmrBadItemSlot" .. i, 0, 0) + itemText:SetPoint("BOTTOM", "AmrBadItemSlot" .. i, 0, 0) + itemText:Hide() + tinsert(tab.badItemNames, itemText) + end + + tab.upgradeItemSlots = {} + tab.upgradeItemNames = {} + for i = 1, #AskMrRobot.slotNames do + local itemText = tab:CreateFontString(nil, "ARTWORK", "GameFontWhite") + if i == 1 then + itemText:SetPoint("TOPLEFT", tab.upgradeSlotHeader, "BOTTOMLEFT", 0, -5) + itemText:SetPoint("TOPRIGHT", tab.upgradeSlotHeader, "BOTTOMRIGHT", 0, -5) + else + itemText:SetPoint("TOPLEFT", tab.upgradeItemSlots[i-1], "BOTTOMLEFT", 0, -5) + itemText:SetPoint("TOPRIGHT", tab.upgradeItemSlots[i-1], "BOTTOMRIGHT", 0, -5) + end + itemText:SetJustifyH("LEFT") + itemText:Hide() + tinsert(tab.upgradeItemSlots, itemText) + + itemText = AskMrRobot.ItemLinkText:new(nil, tab) + itemText:SetFormat("|cff00ff00Upgrade|r %s") + itemText:SetPoint("LEFT", tab.upgradeItemHeader, "LEFT", 0, 0) + itemText:SetPoint("RIGHT", tab.upgradeItemHeader, "RIGHT", 0, 0) + itemText:SetPoint("TOP", tab.upgradeItemSlots[i], 0, 0) + itemText:SetPoint("BOTTOM", tab.upgradeItemSlots[i], 0, 0) + itemText:Hide() + tinsert(tab.upgradeItemNames, itemText) + end + + tab.importInfo = tab:CreateFontString(nil, "ARTWORK", "GameFontNormal") + tab.importInfo:SetText("Last import: ?\rThese optimizations are for ?") + tab.importInfo:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 0, -20) + tab.importInfo:SetJustifyH("LEFT") + tab.importInfo:Hide() + + tab.specIcon = tab:CreateTexture(nil, "BACKGROUND") + tab.specIcon:SetPoint("TOPLEFT") + tab.specIcon:SetWidth(64) + tab.specIcon:SetHeight(64) + tab.specIcon:SetPoint("TOPLEFT", tab.importInfo, "BOTTOMLEFT", 0, -10) + tab.specIcon:Hide() + + tab.stamp = AskMrRobot.RobotStamp:new(nil, tab) + tab.stamp:Hide() + tab.stamp.smallText:SetText("Congratulations! You are 100% optimal") + tab.stamp:SetPoint("TOPLEFT", tab.specIcon, "BOTTOMLEFT", 2, -25) + tab.stamp:SetPoint("RIGHT", tab, "RIGHT", -20, 0) + tab.stamp:Hide() + + tab.specText = tab:CreateFontString(nil, "ARTWORK", "GameFontHighlightLarge") + local Path, Size, Flags = tab.specText:GetFont() + tab.specText:SetFont(Path, 24, Flags); + tab.specText:SetPoint("LEFT", tab.specIcon, "RIGHT", 10, 0) + tab.specText:SetText("?") + tab.specText:Hide() + + tab.optimizationSummary = tab:CreateFontString(nil, "ARTWORK", "GameFontNormal") + tab.optimizationSummary:SetPoint("TOPLEFT", tab.specIcon, "BOTTOMLEFT", 0, -15) + tab.optimizationSummary:SetText("You have ? optimizations to make:") + tab.optimizationSummary:Hide() + + tab.gemCount = tab:CreateFontString(nil, "ARTWORK", "GameFontWhite") + tab.gemCount:SetPoint("TOPLEFT", tab.optimizationSummary, "BOTTOMLEFT", 0, -15) + tab.gemCount:SetText("? gems") + tab.gemCount:Hide() + + tab.enchantCount = tab:CreateFontString(nil, "ARTWORK", "GameFontWhite") + tab.enchantCount:SetPoint("TOPLEFT", tab.gemCount, "BOTTOMLEFT", 0, -5) + tab.enchantCount:SetText("? enchants") + tab.enchantCount:Hide() + + tab.reforgeCount = tab:CreateFontString(nil, "ARTWORK", "GameFontWhite") + tab.reforgeCount:SetPoint("TOPLEFT", tab.enchantCount, "BOTTOMLEFT", 0, -5) + tab.reforgeCount:SetText("? reforges") + tab.reforgeCount:Hide() + + tab.instructions = tab:CreateFontString(nil, "ARTWORK", "GameFontWhite") + tab.instructions:SetPoint("TOPLEFT", tab.reforgeCount, "BOTTOMLEFT", 0, -15) + tab.instructions:SetText("View the Gem, Enchant and Reforge tabs for suggested optimizations.") + tab.instructions:Hide() + + return tab +end + +function AskMrRobot.SummaryTab:getSpecIcon(specId) + for i = 1, GetNumSpecializations() do + local id, _, _, icon = GetSpecializationInfo(i) + if id == specId then + return icon + end + end + return nil +end + +function AskMrRobot.SummaryTab:showBadItems() + local badItems = AskMrRobot.itemDiffs.items + + local i = 2 + + -- for all the bad items + for slotNum, badItem in AskMrRobot.sortSlots(badItems) do + if not badItem.needsUpgrade then + self.badItemSlots[i]:SetText(_G[strupper(AskMrRobot.slotNames[slotNum])]) + self.badItemSlots[i]:Show() + if badItem.optimized then + self.badItemNames[i]:SetItemId(badItem.optimized.itemId, badItem.optimized.upgradeId, badItem.optimized.suffixId) + else + self.badItemNames[i]:SetItemId(nil, 0, 0) + end + self.badItemNames[i]:Show() + i = i + 1 + end + end + + -- for all the upgrade items + local j = 1 + for slotNum, badItem in AskMrRobot.sortSlots(badItems) do + if badItem.needsUpgrade then + self.upgradeItemSlots[j]:SetText(_G[strupper(AskMrRobot.slotNames[slotNum])]) + self.upgradeItemSlots[j]:Show() + if badItem.optimized then + self.upgradeItemNames[j]:SetItemId(badItem.optimized.itemId, badItem.optimized.upgradeId, badItem.optimized.suffixId) + else + self.upgradeItemNames[j]:SetItemId(nil, 0, 0) + end + self.upgradeItemNames[j]:Show() + j = j + 1 + end + end + + -- hide / show the headers + if i == 2 and j == 1 then + self.badItemSlots[1]:Hide() + self.badItemNames[1]:Hide() + self:showImportError(nil) + self.importInfo:Show() + self.specIcon:Show() + self.optimizationSummary:Show() + self.gemCount:Show() + self.enchantCount:Show() + self.reforgeCount:Show() + self.instructions:Show() + self.specText:Show() + + local gemCount = 0 + for slotNum, badGems in pairs(AskMrRobot.itemDiffs.gems) do + for k, v in pairs(badGems.badGems) do + gemCount = gemCount + 1 + end + end + + self.gemCount:SetFormattedText("%d \1244gem:gems;", gemCount) + + local enchantCount = 0 + for slotNum, badEnchant in pairs(AskMrRobot.itemDiffs.enchants) do + enchantCount = enchantCount + 1 + end + + self.enchantCount:SetFormattedText("%d \1244enchant:enchants;", enchantCount) + + local reforgeCount = 0 + for slotNum, badReforge in pairs(AskMrRobot.itemDiffs.reforges) do + reforgeCount = reforgeCount + 1 + end + + self.reforgeCount:SetFormattedText("%d \1244reforge:reforges;", reforgeCount) + self.optimizationSummary:SetFormattedText("You have %d \1244optimization:optimizations; to make:", gemCount + enchantCount + reforgeCount) + + if gemCount + enchantCount + reforgeCount == 0 then + self.stamp:Show() + self.optimizationSummary:Hide() + self.enchantCount:Hide() + self.reforgeCount:Hide() + self.instructions:Hide() + self.gemCount:Hide() + else + self.stamp:Hide() + self.optimizationSummary:Show() + self.enchantCount:Show() + self.reforgeCount:Show() + self.instructions:Show() + self.gemCount:Show() + end + + local activeSpecGroup = GetActiveSpecGroup() + + if activeSpecGroup == nil then + self.importInfo:SetFormattedText("Last import: %s\rThese optimizations are for %s", self.importDate, UnitName("player")) + else + self.importInfo:SetFormattedText("Last import: %s\rThese optimizations are for %s's...", self.importDate, UnitName("player")) + local spec = GetSpecialization(false, false, group); + if spec then + local _, name, _, icon = GetSpecializationInfo(spec); + if activeSpecGroup == 1 then + self.specText:SetFormattedText("Primary Spec - %s", name) + else + self.specText:SetFormattedText("Secondary Spec - %s", name) + end + self.specIcon:SetTexture(icon) + end + end + + + --local currentSpec = GetAmrSpecialization(GetActiveSpecGroup()) + --return (not currentSpec and not spec) or tostring(currentSpec) == spec + else + self.importInfo:Hide() + self.specIcon:Hide() + self.optimizationSummary:Hide() + self.gemCount:Hide() + self.enchantCount:Hide() + self.reforgeCount:Hide() + self.instructions:Hide() + self.specText:Hide() + end + + if i == 2 then + self.badItemSlots[1]:Hide() + self.badItemNames[1]:Hide() + else + self.badItemSlots[1]:Show() + self.badItemNames[1]:Show() + local warnings = {} + if self.badRealm then + tinsert(warnings, "a different realm: " .. self.badRealm) + end + if self.badTalents then + tinsert(warnings, "different talents") + end + if self.badGlyphs then + tinsert(warnings, "different glyphs") + end + local message = "Mr. Robot optimized a different set of gear" + if #warnings > 0 then + message = message .. " (and " + for k = 1, #warnings do + if k > 1 then + message = message .. ', ' + end + message = message .. warnings[k] + end + message = message .. ")" + end + message = message .. ". Please equip the following items before proceeding with the optimizations." + self:showImportWarning("WARNING: Please check your character before proceeding:", message) + end + + if j == 1 then + self.upgradeItemHeader:Hide() + self.upgradeSlotHeader:Hide() + self.upgradeInstructions:Hide() + else + if i == 2 then + local warnings = {} + if self.badRealm then + tinsert(warnings, "a different realm: " .. self.badRealm) + end + if self.badTalents then + tinsert(warnings, "different talents") + end + if self.badGlyphs then + tinsert(warnings, "different glyphs") + end + local message = nil + if #warnings > 0 then + message = "Mr. Robot optimized for " + for k = 1, #warnings do + if k > 1 then + message = message .. ', ' + end + message = message .. warnings[k] + end + message = message .. "." + end + self:showImportWarning("WARNING: Please check your character before proceeding:", message) + end + self.upgradeItemHeader:Show() + self.upgradeSlotHeader:Show() + self.upgradeInstructions:Show() + if i == 2 then + self.upgradeInstructions:SetPoint("TOP", self.badItemSlots[1], "TOP", 0, 0) + self.errorText2:Hide() + else + self.upgradeInstructions:SetPoint("TOP", self.badItemSlots[i], "BOTTOM", 0, -20) + end + end + + -- hide the remaining slots + while i <= #self.badItemSlots do + self.badItemSlots[i]:Hide() + self.badItemNames[i]:Hide() + i = i + 1 + end + + -- hide the remaining slots + while j <= #self.upgradeItemSlots do + self.upgradeItemSlots[j]:Hide() + self.upgradeItemNames[j]:Hide() + j = j + 1 + end +end + + +function AskMrRobot.SummaryTab:showImportError(text, text2) + self.stamp:Hide() + self.gemCount:Hide() + self.instructions:Hide() + self.reforgeCount:Hide() + self.enchantCount:Hide() + self.optimizationSummary:Hide() + if text then + self.errorText1:Show() + self.errorText1:SetText('Error! Your import did not work:|n|n' .. text) + self.errorText1:Show() + self.errorText2:SetText(text2) + self.errorText2:Show() + self.importInfo:Hide() + self.upgradeSlotHeader:Hide() + self.upgradeItemHeader:Hide() + self.upgradeInstructions:Hide() + self.specIcon:Hide() + self.specText:Hide() + else + self.errorText1:Hide() + self.errorText2:Hide() + self.importInfo:Show() + end + for i = 1, #AskMrRobot.slotNames + 1 do + self.badItemSlots[i]:Hide() + self.badItemNames[i]:Hide() + end + for i = 1, #AskMrRobot.slotNames do + self.upgradeItemSlots[i]:Hide() + self.upgradeItemNames[i]:Hide() + end +end + +function AskMrRobot.SummaryTab:showImportWarning (text, text2) + self.stamp:Hide() + self.hasImportError = false + self.gemCount:Hide() + self.instructions:Hide() + self.reforgeCount:Hide() + self.enchantCount:Hide() + self.specIcon:Hide() + self.specText:Hide() + self.optimizationSummary:Hide() + if text then + self.errorText1:SetText(text) + self.errorText1:Show() + self.errorText2:SetText(text2) + self.errorText2:Show() + else + self.errorText1:Hide() + self.errorText2:Hide() + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wait.lua Tue May 20 21:43:23 2014 -0500 @@ -0,0 +1,33 @@ +local _, AskMrRobot = ... + +local waitTable = {}; +local waitFrame = nil; + +function AskMrRobot.wait(delay, func, ...) + if(type(delay)~="number" or type(func)~="function") then + print("Bad Arguments to amr__wait"); + return false; + end + if(waitFrame == nil) then + waitFrame = CreateFrame("Frame","WaitFrame", UIParent); + waitFrame:SetScript("OnUpdate",function (self,elapse) + local count = #waitTable; + local i = 1; + while(i<=count) do + local waitRecord = tremove(waitTable,i); + local d = tremove(waitRecord,1); + local f = tremove(waitRecord,1); + local p = tremove(waitRecord,1); + if(d>elapse) then + tinsert(waitTable,i,{d-elapse,f,p}); + i = i + 1; + else + count = count - 1; + f(unpack(p)); + end + end + end); + end + tinsert(waitTable,{delay,func,{...}}); + return true; +end