annotate AskMrRobot.lua @ 11:ece9167c0d1c v1.2.14.0

Localization support, combat log features (wipe command, aura/pet tracking, and realm detection).
author yellowfive
date Thu, 10 Jul 2014 12:24:59 -0700
parents ec731d2fe6ba
children bb0c8ce689d1
rev   line source
adam@0 1 local _, AskMrRobot = ...
yellowfive@11 2 local L = AskMrRobot.L;
adam@0 3
adam@0 4 AskMrRobot.eventListener = CreateFrame("FRAME"); -- Need a frame to respond to events
adam@0 5 AskMrRobot.eventListener:RegisterEvent("ADDON_LOADED"); -- Fired when saved variables are loaded
adam@0 6 AskMrRobot.eventListener:RegisterEvent("ITEM_PUSH");
adam@0 7 AskMrRobot.eventListener:RegisterEvent("DELETE_ITEM_CONFIRM");
adam@0 8 AskMrRobot.eventListener:RegisterEvent("UNIT_INVENTORY_CHANGED");
adam@0 9 AskMrRobot.eventListener:RegisterEvent("BANKFRAME_OPENED");
adam@0 10 AskMrRobot.eventListener:RegisterEvent("BANKFRAME_CLOSED");
adam@0 11 AskMrRobot.eventListener:RegisterEvent("PLAYERBANKSLOTS_CHANGED");
adam@0 12 AskMrRobot.eventListener:RegisterEvent("CHARACTER_POINTS_CHANGED");
adam@0 13 AskMrRobot.eventListener:RegisterEvent("CONFIRM_TALENT_WIPE");
adam@0 14 AskMrRobot.eventListener:RegisterEvent("PLAYER_TALENT_UPDATE");
adam@0 15 AskMrRobot.eventListener:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED");
yellowfive@11 16 AskMrRobot.eventListener:RegisterEvent("PLAYER_ENTERING_WORLD");
adam@0 17 AskMrRobot.eventListener:RegisterEvent("PLAYER_LOGOUT"); -- Fired when about to log out
adam@0 18 AskMrRobot.eventListener:RegisterEvent("PLAYER_LEVEL_UP");
adam@0 19 --AskMrRobot.eventListener:RegisterEvent("GET_ITEM_INFO_RECEIVED")
adam@0 20 AskMrRobot.eventListener:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
adam@0 21 AskMrRobot.eventListener:RegisterEvent("SOCKET_INFO_UPDATE")
adam@0 22 AskMrRobot.eventListener:RegisterEvent("SOCKET_INFO_CLOSE")
adam@0 23 AskMrRobot.eventListener:RegisterEvent("BAG_UPDATE")
adam@0 24 AskMrRobot.eventListener:RegisterEvent("ITEM_UNLOCKED")
yellowfive@11 25 AskMrRobot.eventListener:RegisterEvent("PLAYER_REGEN_DISABLED")
yellowfive@11 26 --AskMrRobot.eventListener:RegisterEvent("ENCOUNTER_START")
adam@0 27 AskMrRobot.eventListener:RegisterEvent("CHAT_MSG_ADDON")
adam@0 28 AskMrRobot.eventListener:RegisterEvent("UPDATE_INSTANCE_INFO")
adam@0 29 AskMrRobot.eventListener:RegisterEvent("PLAYER_DIFFICULTY_CHANGED")
adam@0 30
adam@0 31 AskMrRobot.AddonName = ...
adam@0 32 AskMrRobot.ChatPrefix = "_AMR"
adam@0 33
adam@0 34 local amrLDB
adam@0 35 local icon
adam@0 36 local reforgequeue
adam@0 37 local reforgeFrame = nil
adam@0 38 local LoggingCombat = _G.LoggingCombat
adam@0 39
adam@0 40 AskMrRobot.itemDiffs = {
adam@0 41 items = {}, -- slotNum -> nil (no change) or current <item id>, optimized <item id>
adam@0 42 enchants = {}, -- slotNum -> nil (no change) or current <enchant id>, optimized <enchant id>
adam@0 43 gems = {}, -- slotNum -> nil (no change) or ?
adam@0 44 reforges = {} -- slotNum -> nil (no change) or current <reforge id>, optimized <reforge id>
adam@0 45 }
adam@0 46
adam@0 47 AskMrRobot.instanceIds = {
adam@0 48 HeartOfFear = 1009,
adam@0 49 MogushanVaults = 1008,
adam@0 50 SiegeOfOrgrimmar = 1136,
adam@0 51 TerraceOfEndlessSpring = 996,
adam@0 52 ThroneOfThunder = 1098
adam@0 53 }
adam@0 54
yellowfive@11 55 -- instances that we currently support logging for
yellowfive@11 56 AskMrRobot.supportedInstanceIds = {
yellowfive@11 57 [1136] = true
yellowfive@11 58 }
yellowfive@11 59
yellowfive@11 60 -- returns true if currently in a supported instance
yellowfive@11 61 function AskMrRobot.IsSupportedInstance()
yellowfive@11 62
yellowfive@11 63 local zone, _, difficultyIndex, _, _, _, _, instanceMapID = GetInstanceInfo()
yellowfive@11 64 if AskMrRobot.supportedInstanceIds[tonumber(instanceMapID)] then
yellowfive@11 65 return true
yellowfive@11 66 else
yellowfive@11 67 return false
yellowfive@11 68 end
yellowfive@11 69 end
yellowfive@11 70
adam@0 71 -- upgrade id -> upgrade level
adam@0 72 local upgradeTable = {
adam@0 73 [0] = 0,
adam@0 74 [1] = 1, -- 1/1 -> 8
adam@0 75 [373] = 1, -- 1/2 -> 4
adam@0 76 [374] = 2, -- 2/2 -> 8
adam@0 77 [375] = 1, -- 1/3 -> 4
adam@0 78 [376] = 2, -- 2/3 -> 4
adam@0 79 [377] = 3, -- 3/3 -> 4
adam@0 80 [378] = 1, -- 1/1 -> 7
adam@0 81 [379] = 1, -- 1/2 -> 4
adam@0 82 [380] = 2, -- 2/2 -> 4
adam@0 83 [445] = 0, -- 0/2 -> 0
adam@0 84 [446] = 1, -- 1/2 -> 4
adam@0 85 [447] = 2, -- 2/2 -> 8
adam@0 86 [451] = 0, -- 0/1 -> 0
adam@0 87 [452] = 1, -- 1/1 -> 8
adam@0 88 [453] = 0, -- 0/2 -> 0
adam@0 89 [454] = 1, -- 1/2 -> 4
adam@0 90 [455] = 2, -- 2/2 -> 8
adam@0 91 [456] = 0, -- 0/1 -> 0
adam@0 92 [457] = 1, -- 1/1 -> 8
adam@0 93 [458] = 0, -- 0/4 -> 0
adam@0 94 [459] = 1, -- 1/4 -> 4
adam@0 95 [460] = 2, -- 2/4 -> 8
adam@0 96 [461] = 3, -- 3/4 -> 12
adam@0 97 [462] = 4, -- 4/4 -> 16
adam@0 98 [465] = 0, -- 0/2 -> 0
adam@0 99 [466] = 1, -- 1/2 -> 4
adam@0 100 [467] = 2, -- 2/2 -> 8
adam@0 101 [468] = 0, -- 0/4 -> 0
adam@0 102 [469] = 1, -- 1/4 -> 4
adam@0 103 [470] = 2, -- 2/4 -> 8
adam@0 104 [471] = 3, -- 3/4 -> 12
adam@0 105 [472] = 4, -- 4/4 -> 16
adam@0 106 [476] = 0, -- ? -> 0
adam@0 107 [479] = 0, -- ? -> 0
adam@0 108 [491] = 0, -- ? -> 0
adam@0 109 [492] = 1, -- ? -> 0
adam@0 110 [493] = 2, -- ? -> 0
adam@0 111 [494] = 0,
adam@0 112 [495] = 1,
adam@0 113 [496] = 2,
adam@0 114 [497] = 3,
adam@0 115 [498] = 4,
adam@0 116 [504] = 3,
yellowfive@11 117 [505] = 4,
yellowfive@11 118 [506] = 5,
yellowfive@11 119 [507] = 6
adam@0 120 }
adam@0 121
adam@0 122 local professionIds = {
adam@0 123 ["None"] = 0,
adam@0 124 ["Mining"] = 1,
adam@0 125 ["Skinning"] = 2,
adam@0 126 ["Herbalism"] = 3,
adam@0 127 ["Enchanting"] = 4,
adam@0 128 ["Jewelcrafting"] = 5,
adam@0 129 ["Engineering"] = 6,
adam@0 130 ["Blacksmithing"] = 7,
adam@0 131 ["Leatherworking"] = 8,
adam@0 132 ["Inscription"] = 9,
adam@0 133 ["Tailoring"] = 10,
adam@0 134 ["Alchemy"] = 11,
adam@0 135 ["Fishing"] = 12,
adam@0 136 ["Cooking"] = 13,
adam@0 137 ["First Aid"] = 14,
adam@0 138 ["Archaeology"] = 15
adam@0 139 }
adam@0 140
adam@0 141 local raceIds = {
adam@0 142 ["None"] = 0,
adam@0 143 ["BloodElf"] = 1,
adam@0 144 ["Draenei"] = 2,
adam@0 145 ["Dwarf"] = 3,
adam@0 146 ["Gnome"] = 4,
adam@0 147 ["Human"] = 5,
adam@0 148 ["NightElf"] = 6,
adam@0 149 ["Orc"] = 7,
adam@0 150 ["Tauren"] = 8,
adam@0 151 ["Troll"] = 9,
adam@0 152 ["Scourge"] = 10,
adam@0 153 ["Undead"] = 10,
adam@0 154 ["Goblin"] = 11,
adam@0 155 ["Worgen"] = 12,
adam@0 156 ["Pandaren"] = 13
adam@0 157 }
adam@0 158
adam@0 159 local factionIds = {
adam@0 160 ["None"] = 0,
adam@0 161 ["Alliance"] = 1,
adam@0 162 ["Horde"] = 2
adam@0 163 }
adam@0 164
adam@0 165 local function OnExport()
adam@0 166 if (AmrOptions.exportToClient) then
adam@0 167 AskMrRobot.SaveAll()
adam@0 168 ReloadUI()
adam@0 169 else
adam@0 170 AskMrRobot_ReforgeFrame:Show()
adam@0 171 AskMrRobot_ReforgeFrame:ShowTab("export")
adam@0 172 end
adam@0 173 end
adam@0 174
adam@0 175 function AskMrRobot.eventListener:OnEvent(event, ...)
adam@0 176 if event == "ADDON_LOADED" then
adam@0 177 local addon = select(1, ...)
adam@0 178 if (addon == "AskMrRobot") then
yellowfive@11 179 print(L.AMR_ON_EVENT_LOADED.format(GetAddOnMetadata(AskMrRobot.AddonName, "Version")))
adam@0 180
adam@0 181 -- listen for messages from other AMR addons
adam@0 182 RegisterAddonMessagePrefix(AskMrRobot.ChatPrefix)
adam@0 183
adam@0 184 AmrRealmName = GetRealmName()
adam@0 185 AmrCharacterName = UnitName("player")
adam@0 186
yellowfive@11 187 AskMrRobot.CombatLogTab.InitializeVariable()
adam@0 188
adam@0 189 if not AmrIconInfo then AmrIconInfo = {} end
adam@0 190 if not AmrBankItems then AmrBankItems = {} end
adam@0 191 if not AmrCurrencies then AmrCurrencies = {} end
adam@0 192 if not AmrSpecializations then AmrSpecializations = {} end
adam@0 193 if not AmrOptions then AmrOptions = {} end
adam@0 194 if not AmrGlyphs then AmrGlyphs = {} end
adam@0 195 if not AmrTalents then AmrTalents = {} end
adam@0 196 if not AmrBankItemsAndCounts then AmrBankItemsAndCounts = {} end
adam@0 197 if not AmrImportString then AmrImportString = "" end
adam@0 198 if not AmrImportDate then AmrImportDate = "" end
yellowfive@11 199
yellowfive@11 200 if not AmrSettings then AmrSettings = {} end
yellowfive@11 201 if not AmrSettings.Logins then AmrSettings.Logins = {} end
yellowfive@11 202
adam@0 203 if not AmrSendSettings then
adam@0 204 AmrSendSettings = {
adam@0 205 SendGems = true,
adam@0 206 SendEnchants = true,
adam@0 207 SendEnchantMaterials = true,
adam@0 208 SendToType = "a friend",
adam@0 209 SendTo = ""
adam@0 210 }
adam@0 211 end
adam@0 212
adam@0 213 amrLDB = LibStub("LibDataBroker-1.1"):NewDataObject("AskMrRobot", {
adam@0 214 type = "launcher",
adam@0 215 text = "Ask Mr. Robot",
adam@0 216 icon = "Interface\\AddOns\\AskMrRobot\\Media\\icon",
adam@0 217 OnClick = function()
yellowfive@11 218 if IsControlKeyDown() then
yellowfive@11 219 AskMrRobot_ReforgeFrame.combatLogTab:LogWipe()
yellowfive@11 220 elseif IsModifiedClick("CHATLINK") then
adam@0 221 OnExport()
adam@0 222 else
adam@0 223 AskMrRobot_ReforgeFrame:Toggle()
adam@0 224 end
adam@0 225 end,
adam@0 226 OnTooltipShow = function(tt)
adam@0 227 tt:AddLine("Ask Mr. Robot", 1, 1, 1);
adam@0 228 tt:AddLine(" ");
yellowfive@11 229 tt:AddLine(L.AMR_ON_EVENT_TOOLTIP)
adam@0 230 end
adam@0 231 });
adam@0 232
adam@0 233
adam@0 234 AskMrRobot.AmrUpdateMinimap()
adam@0 235
adam@0 236 AskMrRobot_ReforgeFrame = AskMrRobot.AmrUI:new()
adam@0 237
adam@0 238 -- remember the import settings between sessions
adam@0 239 AskMrRobot_ReforgeFrame.summaryTab.importDate = AmrImportDate or ""
adam@0 240 AskMrRobot_ReforgeFrame.buttons[2]:Click()
adam@0 241
adam@0 242 -- the previous import string is loaded when the UI is first shown, otherwise the game spams events and it lags
adam@0 243 end
adam@0 244
adam@0 245 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
adam@0 246 if AskMrRobot_ReforgeFrame then
adam@0 247 AskMrRobot_ReforgeFrame:OnUpdate()
adam@0 248 end
adam@0 249 --AskMrRobot.SaveBags();
adam@0 250 --AskMrRobot.SaveEquiped();
adam@0 251 --AskMrRonot.GetCurrencies();
adam@0 252 --AskMrRobot.GetGold();
adam@0 253 elseif event == "BANKFRAME_OPENED" or event == "PLAYERBANKSLOTS_CHANGED" then
adam@0 254 --print("Scanning Bank: " .. event);
adam@0 255 AskMrRobot.ScanBank();
adam@0 256 elseif event == "BANKFRAME_CLOSED" then
adam@0 257 --print("Stop Scanning Bank");
adam@0 258 --inBank = false;
adam@0 259 elseif event == "CHARACTER_POINTS_CHANGED" or event == "CONFIRM_TALENT_WIPE" or event == "PLAYER_TALENT_UPDATE" or event == "ACTIVE_TALENT_GROUP_CHANGED" then
adam@0 260 --AskMrRobot.GetAmrSpecializations();
adam@0 261 if AskMrRobot_ReforgeFrame then
adam@0 262 AskMrRobot_ReforgeFrame:OnUpdate()
adam@0 263 end
adam@0 264 elseif event == "PLAYER_LEVEL_UP" then
adam@0 265 --GetLevel();
adam@0 266 elseif event == "ITEM_UNLOCKED" then
adam@0 267 AskMrRobot.On_ITEM_UNLOCKED()
adam@0 268 elseif event == "PLAYER_LOGOUT" then
adam@0 269 -- doing nothing right now, but leaving this in case we need something here
yellowfive@11 270 elseif event == "PLAYER_ENTERING_WORLD" then
yellowfive@11 271
yellowfive@11 272 -- delete entries that are more than 10 days old to prevent the table from growing indefinitely
yellowfive@11 273 local now = time()
yellowfive@11 274 local oldDuration = 60 * 60 * 24 * 10
yellowfive@11 275 local entryTime
yellowfive@11 276 repeat
yellowfive@11 277 -- parse entry and get time
yellowfive@11 278 local parts = {}
yellowfive@11 279 for part in string.gmatch(AmrSettings.Logins[1], "([^;]+)") do
yellowfive@11 280 tinsert(parts, part)
yellowfive@11 281 end
yellowfive@11 282 entryTime = tonumber(parts[3])
yellowfive@11 283
yellowfive@11 284 -- entries are in order, remove first entry if it is old
yellowfive@11 285 if difftime(now, entryTime) > oldDuration then
yellowfive@11 286 tremove(AmrSettings.Logins, 1)
yellowfive@11 287 end
yellowfive@11 288 until #AmrSettings.Logins == 0 or difftime(now, entryTime) <= oldDuration
yellowfive@11 289
yellowfive@11 290 -- record the time a player logs in, used to figure out which player logged which parts of their log file
yellowfive@11 291 local key = AmrRealmName .. ";" .. AmrCharacterName .. ";"
yellowfive@11 292 local loginData = key .. time()
yellowfive@11 293 if AmrSettings.Logins and #AmrSettings.Logins > 0 then
yellowfive@11 294 local last = AmrSettings.Logins[#AmrSettings.Logins]
yellowfive@11 295 if string.len(last) >= string.len(key) and string.sub(last, 1, string.len(key)) ~= key then
yellowfive@11 296 table.insert(AmrSettings.Logins, loginData)
yellowfive@11 297 end
yellowfive@11 298 else
yellowfive@11 299 table.insert(AmrSettings.Logins, loginData)
yellowfive@11 300 end
yellowfive@11 301
yellowfive@11 302 elseif event == "PLAYER_REGEN_DISABLED" then
yellowfive@11 303
yellowfive@11 304 -- send data about this character when a player enters combat in a supported zone
yellowfive@11 305 if AskMrRobot.IsSupportedInstance() then
yellowfive@11 306 local t = time()
yellowfive@11 307 AskMrRobot.SaveAll()
yellowfive@11 308 AskMrRobot.ExportToAddonChat(t)
yellowfive@11 309 AskMrRobot.ExportLoggingData(t)
yellowfive@11 310 end
yellowfive@11 311
adam@0 312 elseif event == "CHAT_MSG_ADDON" then
adam@0 313 local chatPrefix, message = select(1, ...)
yellowfive@11 314 local isLogging = AskMrRobot_ReforgeFrame.combatLogTab:IsLogging()
adam@0 315 if (isLogging and chatPrefix == AskMrRobot.ChatPrefix) then
adam@0 316 AskMrRobot_ReforgeFrame.combatLogTab:ReadAddonMessage(message)
adam@0 317 end
adam@0 318 elseif event == "UPDATE_INSTANCE_INFO" or event == "PLAYER_DIFFICULTY_CHANGED" then
adam@0 319 AskMrRobot_ReforgeFrame.combatLogTab:UpdateAutoLogging()
adam@0 320 end
adam@0 321
adam@0 322 end
adam@0 323
adam@0 324 AskMrRobot.eventListener:SetScript("OnEvent", AskMrRobot.eventListener.OnEvent);
adam@0 325
adam@0 326 local function parseItemLink(input)
adam@0 327 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+)|");
adam@0 328 local item = {}
adam@0 329 item.itemId = tonumber(itemId)
adam@0 330 item.suffixId = tonumber(suffixId)
adam@0 331 item.enchantId = tonumber(enchantId)
adam@0 332 item.reforgeId = tonumber(reforgeId)
adam@0 333 item.upgradeId = tonumber(upgradeId)
adam@0 334 item.gemEnchantIds = { tonumber(gemEnchantId1), tonumber(gemEnchantId2), tonumber(gemEnchantId3), tonumber(gemEnchantId4) }
adam@0 335 return item
adam@0 336 end
adam@0 337
adam@0 338 SLASH_AMR1 = "/amr";
adam@0 339 function SlashCmdList.AMR(msg)
adam@0 340
adam@0 341 if msg == 'toggle' then
adam@0 342 AskMrRobot_ReforgeFrame:Toggle()
adam@0 343 elseif msg == 'show' then
adam@0 344 AskMrRobot_ReforgeFrame:Show()
adam@0 345 elseif msg == 'hide' then
adam@0 346 AskMrRobot_ReforgeFrame:Hide()
adam@0 347 elseif msg == 'export' then
adam@0 348 OnExport()
yellowfive@11 349 elseif msg == 'wipe' then
yellowfive@11 350 AskMrRobot_ReforgeFrame.combatLogTab:LogWipe()
yellowfive@11 351 elseif msg == 'unwipe' then
yellowfive@11 352 AskMrRobot_ReforgeFrame.combatLogTab:LogUnwipe()
adam@0 353 else
yellowfive@11 354 print(L.AMR_SLASH_COMMAND_TEXT_1 .. L.AMR_SLASH_COMMAND_TEXT_2 .. L.AMR_SLASH_COMMAND_TEXT_3 .. L.AMR_SLASH_COMMAND_TEXT_4 .. L.AMR_SLASH_COMMAND_TEXT_5 .. L.AMR_SLASH_COMMAND_TEXT_6 .. L.AMR_SLASH_COMMAND_TEXT_7)
adam@0 355 end
adam@0 356 end
adam@0 357
adam@0 358 function AskMrRobot.SaveAll()
adam@0 359 AskMrRobot.ScanBank()
adam@0 360 AskMrRobot.SaveBags()
adam@0 361 AskMrRobot.SaveEquiped()
adam@0 362 AskMrRobot.GetCurrencies()
adam@0 363 AskMrRobot.GetGold()
adam@0 364 AskMrRobot.GetAmrSpecializations()
adam@0 365 AskMrRobot.GetAmrProfessions()
adam@0 366 AskMrRobot.GetRace()
adam@0 367 AskMrRobot.GetLevel()
adam@0 368 AskMrRobot.GetAmrGlyphs()
adam@0 369 AskMrRobot.GetAmrTalents()
adam@0 370 --ReloadUI()
adam@0 371 end
adam@0 372
adam@0 373 local function InitIcon()
adam@0 374 icon = LibStub("LibDBIcon-1.0");
yellowfive@11 375 icon:Register("AskMrRobot", amrLDB, AmrIconInfo);
adam@0 376 end
adam@0 377
yellowfive@11 378 function AskMrRobot.AmrUpdateMinimap()
yellowfive@11 379 if AmrOptions.hideMapIcon then
yellowfive@11 380 if icon then
adam@0 381 icon:Hide("AskMrRobot");
adam@0 382 end
adam@0 383 else
yellowfive@11 384 if not icon then
adam@0 385 InitIcon()
adam@0 386 end
yellowfive@11 387 --if AskMrRobot_ReforgeFrame.combatLogTab:IsLogging() then
yellowfive@11 388 if AskMrRobot.CombatLogTab.IsLogging(nil) then
yellowfive@11 389 amrLDB.icon = 'Interface\\AddOns\\AskMrRobot\\Media\\icon_green'
yellowfive@11 390 else
yellowfive@11 391 amrLDB.icon = 'Interface\\AddOns\\AskMrRobot\\Media\\icon'
yellowfive@11 392 end
adam@0 393 icon:Show("AskMrRobot");
adam@0 394 end
adam@0 395 end
adam@0 396
adam@0 397 local function getToolTipText(tip)
adam@0 398 return EnumerateTooltipLines_helper(tip:GetRegions())
adam@0 399 end
adam@0 400
adam@0 401 local bagItems = {}
adam@0 402 local bagItemsWithCount = {}
adam@0 403
adam@0 404 function AskMrRobot.ScanBag(bagId)
adam@0 405 local numSlots = GetContainerNumSlots(bagId);
adam@0 406 for slotId = 1, numSlots do
adam@0 407 local _, itemCount, _, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId);
adam@0 408 if itemLink ~= nil then
adam@0 409 local itemData = parseItemLink(itemLink)
adam@0 410 if itemData.itemId ~= nil then
adam@0 411 tinsert(bagItems, itemLink);
adam@0 412 tinsert(bagItemsWithCount, {link = itemLink, count = itemCount})
adam@0 413 end
adam@0 414 end
adam@0 415 end
adam@0 416 end
adam@0 417
adam@0 418 local BACKPACK_CONTAINER = 0;
adam@0 419 local BANK_CONTAINER = -1;
adam@0 420
adam@0 421 function AskMrRobot.ScanEquiped()
adam@0 422 local equipedItems = {};
adam@0 423 for slotNum = 1, #AskMrRobot.slotIds do
adam@0 424 local slotId = AskMrRobot.slotIds[slotNum];
adam@0 425 local itemLink = GetInventoryItemLink("player", slotId);
adam@0 426 if (itemLink ~= nil) then
adam@0 427 equipedItems[slotId .. ""] = itemLink;
adam@0 428 end
adam@0 429 end
adam@0 430 return equipedItems
adam@0 431 end
adam@0 432
adam@0 433 function AskMrRobot.SaveEquiped()
adam@0 434 AmrEquipedItems = AskMrRobot.ScanEquiped();
adam@0 435 end
adam@0 436
adam@0 437 function AskMrRobot.ScanBags()
adam@0 438 bagItems = {}
adam@0 439 bagItemsWithCount = {}
adam@0 440
adam@0 441 AskMrRobot.ScanBag(BACKPACK_CONTAINER); -- backpack
adam@0 442
adam@0 443 for bagId = 1, NUM_BAG_SLOTS do
adam@0 444 AskMrRobot.ScanBag(bagId);
adam@0 445 end
adam@0 446
adam@0 447
adam@0 448 return bagItems, bagItemsWithCount
adam@0 449 end
adam@0 450
adam@0 451 function AskMrRobot.SaveBags()
adam@0 452 AmrBagItems, _ = AskMrRobot.ScanBags()
adam@0 453 end
adam@0 454
adam@0 455 function AskMrRobot.GetGold()
adam@0 456 AmrGold = GetMoney();
adam@0 457 end
adam@0 458
adam@0 459 local lastBankBagId = nil;
adam@0 460 local lastBankSlotId = nil;
adam@0 461 local bankItems = {};
adam@0 462 local bankItemsAndCount = {};
adam@0 463 AmrBankItemsAndCounts = {};
adam@0 464
adam@0 465 local function ScanBankBag(bagId)
adam@0 466 local numSlots = GetContainerNumSlots(bagId);
adam@0 467 for slotId = 1, numSlots do
adam@0 468 local _, itemCount, _, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId);
adam@0 469 if itemLink ~= nil then
adam@0 470 local itemData = parseItemLink(itemLink)
adam@0 471 if itemData.itemId ~= nil then
adam@0 472 lastBankBagId = bagId;
adam@0 473 lastBankSlotId = slotId;
adam@0 474 tinsert(bankItems, itemLink);
adam@0 475 tinsert(bankItemsAndCount, {link = itemLink, count = itemCount})
adam@0 476 end
adam@0 477 end
adam@0 478 end
adam@0 479 end
adam@0 480
adam@0 481 function AskMrRobot.ScanBank()
adam@0 482
adam@0 483 bankItems = {};
adam@0 484 bankItemsAndCount = {}
adam@0 485
adam@0 486 ScanBankBag(BANK_CONTAINER);
adam@0 487 for bagId = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do
adam@0 488 ScanBankBag(bagId);
adam@0 489 end
adam@0 490
adam@0 491 -- see if the scan completed before the window closed
adam@0 492 if lastBankBagId ~= nil then
adam@0 493 local itemLink = GetContainerItemLink(lastBankBagId, lastBankSlotId);
adam@0 494 if itemLink ~= nil then --still open
adam@0 495 AmrBankItems = bankItems;
adam@0 496 AmrBankItemsAndCounts = bankItemsAndCount
adam@0 497 end
adam@0 498 end
adam@0 499 end
adam@0 500
adam@0 501 local function GetCurrencyAmount(index)
adam@0 502 local localized_label, amount, icon_file_name = GetCurrencyInfo(index);
adam@0 503 return amount;
adam@0 504 end
adam@0 505
adam@0 506 function AskMrRobot.GetCurrencies()
adam@0 507 local currencies = {};
adam@0 508 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};
adam@0 509
adam@0 510 for i, currency in pairs(currencyList) do
adam@0 511 local amount = GetCurrencyAmount(currency);
adam@0 512 if amount ~= 0 then
adam@0 513 currencies[currencyList[i]] = amount;
adam@0 514 end
adam@0 515 end
adam@0 516 AmrCurrencies = currencies;
adam@0 517 end
adam@0 518
adam@0 519 local function GetAmrSpecialization(specGroup)
adam@0 520 local spec = GetSpecialization(false, false, specGroup);
adam@0 521 return spec and GetSpecializationInfo(spec);
adam@0 522 end
adam@0 523
adam@0 524 function AskMrRobot.GetAmrSpecializations()
adam@0 525
adam@0 526 AmrSpecializations = {};
adam@0 527
adam@0 528 AmrActiveSpec = GetActiveSpecGroup();
adam@0 529
adam@0 530 for group = 1, 2 do
adam@0 531 AmrSpecializations[group .. ""] = GetAmrSpecialization(group)
adam@0 532 end
adam@0 533
adam@0 534 -- Death Knight
adam@0 535 -- 250 - Blood
adam@0 536 -- 251 - Frost
adam@0 537 -- 252 - Unholy
adam@0 538 -- Druid
adam@0 539 -- 102 - Balance
adam@0 540 -- 103 - Feral Combat
adam@0 541 -- 104 - Guardian
adam@0 542 -- 105 - Restoration
adam@0 543 -- Hunter
adam@0 544 -- 253 - Beast Mastery
adam@0 545 -- 254 - Marksmanship
adam@0 546 -- 255 - Survival
adam@0 547 -- Mage
adam@0 548 -- 62 - Arcane
adam@0 549 -- 63 - Fire
adam@0 550 -- 64 - Frost
adam@0 551 -- Monk
adam@0 552 -- 268 - Brewmaster
adam@0 553 -- 269 - Windwalker
adam@0 554 -- 270 - Mistweaver
adam@0 555 -- Paladin
adam@0 556 -- 65 - Holy
adam@0 557 -- 66 - Protection
adam@0 558 -- 70 - Retribution
adam@0 559 -- Priest
adam@0 560 -- 256 Discipline
adam@0 561 -- 257 Holy
adam@0 562 -- 258 Shadow
adam@0 563 -- Rogue
adam@0 564 -- 259 - Assassination
adam@0 565 -- 260 - Combat
adam@0 566 -- 261 - Subtlety
adam@0 567 -- Shaman
adam@0 568 -- 262 - Elemental
adam@0 569 -- 263 - Enhancement
adam@0 570 -- 264 - Restoration
adam@0 571 -- Warlock
adam@0 572 -- 265 - Affliction
adam@0 573 -- 266 - Demonology
adam@0 574 -- 267 - Destruction
adam@0 575 -- Warrior
adam@0 576 -- 71 - Arms
adam@0 577 -- 72 - Fury
adam@0 578 -- 73 - Protection
adam@0 579 end
adam@0 580
adam@0 581 function AskMrRobot.GetAmrProfessions()
adam@0 582
adam@0 583 local profMap = {
adam@0 584 [794] = "Archaeology",
adam@0 585 [171] = "Alchemy",
adam@0 586 [164] = "Blacksmithing",
adam@0 587 [185] = "Cooking",
adam@0 588 [333] = "Enchanting",
adam@0 589 [202] = "Engineering",
adam@0 590 [129] = "First Aid",
adam@0 591 [356] = "Fishing",
adam@0 592 [182] = "Herbalism",
adam@0 593 [773] = "Inscription",
adam@0 594 [755] = "Jewelcrafting",
adam@0 595 [165] = "Leatherworking",
adam@0 596 [186] = "Mining",
adam@0 597 [393] = "Skinning",
adam@0 598 [197] = "Tailoring"
adam@0 599 }
adam@0 600
adam@0 601 local prof1, prof2, archaeology, fishing, cooking, firstAid = GetProfessions();
adam@0 602 AmrProfessions = {};
adam@0 603 if prof1 then
adam@0 604 local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(prof1);
adam@0 605 if profMap[skillLine] ~= nil then
adam@0 606 AmrProfessions[profMap[skillLine]] = skillLevel;
adam@0 607 end
adam@0 608 end
adam@0 609 if prof2 then
adam@0 610 local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(prof2);
adam@0 611 if profMap[skillLine] ~= nil then
adam@0 612 AmrProfessions[profMap[skillLine]] = skillLevel;
adam@0 613 end
adam@0 614 end
adam@0 615 if archaeology then
adam@0 616 local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(archaeology);
adam@0 617 if profMap[skillLine] ~= nil then
adam@0 618 AmrProfessions[profMap[skillLine]] = skillLevel;
adam@0 619 end
adam@0 620 end
adam@0 621 if fishing then
adam@0 622 local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(fishing);
adam@0 623 if profMap[skillLine] ~= nil then
adam@0 624 AmrProfessions[profMap[skillLine]] = skillLevel;
adam@0 625 end
adam@0 626 end
adam@0 627 if cooking then
adam@0 628 local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(cooking);
adam@0 629 if profMap[skillLine] ~= nil then
adam@0 630 AmrProfessions[profMap[skillLine]] = skillLevel;
adam@0 631 end
adam@0 632 end
adam@0 633 if firstAid then
adam@0 634 local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(firstAid);
adam@0 635 if profMap[skillLine] ~= nil then
adam@0 636 AmrProfessions[profMap[skillLine]] = skillLevel;
adam@0 637 end
adam@0 638 end
adam@0 639 end
adam@0 640
adam@0 641 function AskMrRobot.GetRace()
adam@0 642 local race, raceEn = UnitRace("player");
adam@0 643 AmrRace = raceEn;
adam@0 644 AmrFaction = UnitFactionGroup("player");
adam@0 645 end
adam@0 646
adam@0 647 function AskMrRobot.GetLevel()
adam@0 648 AmrLevel = UnitLevel("player");
adam@0 649 end
adam@0 650
adam@0 651 local SlotNames = {
adam@0 652 "HeadSlot",
adam@0 653 "NeckSlot",
adam@0 654 "ShoulderSlot",
adam@0 655 "ShirtSlot",
adam@0 656 "ChestSlot",
adam@0 657 "WaistSlot",
adam@0 658 "LegsSlot",
adam@0 659 "FeetSlot",
adam@0 660 "WristSlot",
adam@0 661 "HandsSlot",
adam@0 662 "Finger0Slot",
adam@0 663 "Finger1Slot",
adam@0 664 "Trinket0Slot",
adam@0 665 "Trinket1Slot",
adam@0 666 "BackSlot",
adam@0 667 "MainHandSlot",
adam@0 668 "SecondaryHandSlot",
adam@0 669 -- "RangedSlot",
adam@0 670 "TabardSlot",
adam@0 671 }
adam@0 672
adam@0 673 local function GetAmrTalentsForSpec(spec)
adam@0 674 local talentInfo = {}
adam@0 675 local maxTiers = 6
adam@0 676 for talent = 1, GetNumTalents() do
adam@0 677 local name, texture, tier, column, selected, available = GetTalentInfo(talent, false, spec)
adam@0 678 if tier > maxTiers then
adam@0 679 maxTiers = tier
adam@0 680 end
adam@0 681 if selected then
adam@0 682 talentInfo[tier] = column
adam@0 683 end
adam@0 684 end
adam@0 685
adam@0 686 local str = ""
adam@0 687 for i = 1, maxTiers do
adam@0 688 if talentInfo[i] then
adam@0 689 str = str .. talentInfo[i]
adam@0 690 else
adam@0 691 str = str .. '0'
adam@0 692 end
adam@0 693 end
adam@0 694
adam@0 695 return str
adam@0 696 end
adam@0 697
adam@0 698 function AskMrRobot.GetAmrTalents()
adam@0 699 AmrTalents = {}
adam@0 700 for spec = 1, GetNumSpecGroups() do
adam@0 701 AmrTalents[spec] = GetAmrTalentsForSpec(spec);
adam@0 702 end
adam@0 703 end
adam@0 704
adam@0 705 local function GetAmrGlyphsForSpec(spec)
adam@0 706 local glyphs = {}
adam@0 707 for i = 1, NUM_GLYPH_SLOTS do
adam@0 708 local _, _, _, glyphSpellID, _, glyphID = GetGlyphSocketInfo(i, spec)
adam@0 709 if (glyphID) then
adam@0 710 tinsert(glyphs, glyphSpellID)
adam@0 711 end
adam@0 712 end
adam@0 713 return glyphs;
adam@0 714 end
adam@0 715
adam@0 716 function AskMrRobot.GetAmrGlyphs()
adam@0 717 AmrGlyphs = {}
adam@0 718 for spec = 1, GetNumSpecGroups() do
adam@0 719 AmrGlyphs[spec] = GetAmrGlyphsForSpec(spec)
adam@0 720 end
adam@0 721 end
adam@0 722
adam@0 723 --[[
adam@0 724 local function ItemLinkToExportString(itemLink, slot)
adam@0 725 local itemData = parseItemLink(itemLink)
adam@0 726 local ret = {}
adam@0 727 table.insert(ret, slot)
adam@0 728 table.insert(ret, itemData.itemId)
adam@0 729 table.insert(ret, itemData.suffixId)
adam@0 730 table.insert(ret, itemData.upgradeId)
adam@0 731 table.insert(ret, itemData.gemEnchantIds[1])
adam@0 732 table.insert(ret, itemData.gemEnchantIds[2])
adam@0 733 table.insert(ret, itemData.gemEnchantIds[3])
adam@0 734 table.insert(ret, itemData.enchantId)
adam@0 735 table.insert(ret, itemData.reforgeId)
adam@0 736 return table.concat(ret, ":")
adam@0 737 end
adam@0 738 ]]
adam@0 739
adam@0 740 local function toCompressedNumberList(list)
adam@0 741 -- ensure the values are numbers, sorted from lowest to highest
adam@0 742 local nums = {}
adam@0 743 for i, v in ipairs(list) do
adam@0 744 table.insert(nums, tonumber(v))
adam@0 745 end
adam@0 746 table.sort(nums)
adam@0 747
adam@0 748 local ret = {}
adam@0 749 local prev = 0
adam@0 750 for i, v in ipairs(nums) do
adam@0 751 local diff = v - prev
adam@0 752 table.insert(ret, diff)
adam@0 753 prev = v
adam@0 754 end
adam@0 755
adam@0 756 return table.concat(ret, ",")
adam@0 757 end
adam@0 758
adam@0 759 -- create a more compact but less readable string
adam@0 760 function AskMrRobot.ExportToCompressedString(includeInventory)
adam@0 761 local fields = {}
adam@0 762
adam@0 763 -- compressed string uses a fixed order rather than inserting identifiers
adam@0 764 table.insert(fields, GetAddOnMetadata(AskMrRobot.AddonName, "Version"))
adam@0 765 table.insert(fields, AmrRealmName)
adam@0 766 table.insert(fields, AmrCharacterName)
adam@0 767
adam@0 768 -- guild name
adam@0 769 local guildName = GetGuildInfo("player")
adam@0 770 if guildName == nil then
adam@0 771 table.insert(fields, "")
adam@0 772 else
adam@0 773 table.insert(fields, guildName)
adam@0 774 end
adam@0 775
adam@0 776 -- race, default to pandaren if we can't read it for some reason
adam@0 777 local raceval = raceIds[AmrRace]
adam@0 778 if raceval == nil then raceval = 13 end
adam@0 779 table.insert(fields, raceval)
adam@0 780
adam@0 781 -- faction, default to alliance if we can't read it for some reason
adam@0 782 raceval = factionIds[AmrFaction]
adam@0 783 if raceval == nil then raceval = 1 end
adam@0 784 table.insert(fields, raceval)
adam@0 785
adam@0 786 table.insert(fields, AmrLevel)
adam@0 787
adam@0 788 local profs = {}
adam@0 789 local noprofs = true
yellowfive@11 790 if AmrProfessions then
yellowfive@11 791 for k, v in pairs(AmrProfessions) do
yellowfive@11 792 local profval = professionIds[k]
yellowfive@11 793 if profval ~= nil then
yellowfive@11 794 noprofs = false
yellowfive@11 795 table.insert(profs, profval .. ":" .. v)
yellowfive@11 796 end
yellowfive@11 797 end
yellowfive@11 798 end
adam@0 799
adam@0 800 if noprofs then
adam@0 801 table.insert(profs, "0:0")
adam@0 802 end
adam@0 803
adam@0 804 table.insert(fields, table.concat(profs, ","))
adam@0 805
adam@0 806 if (AmrActiveSpec ~= nil) then
adam@0 807 table.insert(fields, AmrActiveSpec)
adam@0 808 table.insert(fields, AmrSpecializations[AmrActiveSpec .. ""])
adam@0 809 table.insert(fields, AmrTalents[AmrActiveSpec])
adam@0 810 table.insert(fields, toCompressedNumberList(AmrGlyphs[AmrActiveSpec]))
adam@0 811 else
adam@0 812 table.insert(fields, "_")
adam@0 813 table.insert(fields, "_")
adam@0 814 table.insert(fields, "_")
adam@0 815 table.insert(fields, "_")
adam@0 816 end
adam@0 817
adam@0 818 -- convert items to parsed objects, sorted by id
adam@0 819 local itemObjects = {}
yellowfive@11 820 if AmrEquipedItems then
yellowfive@11 821 for k, v in pairs(AmrEquipedItems) do
yellowfive@11 822 local itemData = parseItemLink(v)
yellowfive@11 823 itemData.slot = k
yellowfive@11 824 table.insert(itemObjects, itemData)
yellowfive@11 825 end
yellowfive@11 826 end
adam@0 827
adam@0 828 -- if desired, include bank/bag items too
adam@0 829 if includeInventory then
yellowfive@11 830 if AmrBagItems then
yellowfive@11 831 for i, v in ipairs(AmrBagItems) do
yellowfive@11 832 local itemData = parseItemLink(v)
yellowfive@11 833 if itemData.itemId ~= nil then
yellowfive@11 834 table.insert(itemObjects, itemData)
yellowfive@11 835 end
yellowfive@11 836 end
yellowfive@11 837 end
yellowfive@11 838 if AmrBankItems then
yellowfive@11 839 for i, v in ipairs(AmrBankItems) do
yellowfive@11 840 local itemData = parseItemLink(v)
yellowfive@11 841 if itemData.itemId ~= nil then
yellowfive@11 842 table.insert(itemObjects, itemData)
yellowfive@11 843 end
yellowfive@11 844 end
yellowfive@11 845 end
adam@0 846 end
adam@0 847
adam@0 848 -- sort by item id so we can compress it more easily
adam@0 849 table.sort(itemObjects, function(a, b) return a.itemId < b.itemId end)
adam@0 850
adam@0 851 -- append to the export string
adam@0 852 local prevItemId = 0
adam@0 853 local prevGemId = 0
adam@0 854 local prevEnchantId = 0
adam@0 855 for i, itemData in ipairs(itemObjects) do
adam@0 856
adam@0 857 local itemParts = {}
adam@0 858
adam@0 859 table.insert(itemParts, itemData.itemId - prevItemId)
adam@0 860 prevItemId = itemData.itemId
adam@0 861
adam@0 862 if itemData.slot ~= nil then table.insert(itemParts, "s" .. itemData.slot) end
adam@0 863 if itemData.suffixId ~= 0 then table.insert(itemParts, "f" .. itemData.suffixId) end
adam@0 864 if upgradeTable[itemData.upgradeId] ~= 0 then table.insert(itemParts, "u" .. upgradeTable[itemData.upgradeId]) end
adam@0 865 if itemData.gemEnchantIds[1] ~= 0 then
adam@0 866 table.insert(itemParts, "a" .. (itemData.gemEnchantIds[1] - prevGemId))
adam@0 867 prevGemId = itemData.gemEnchantIds[1]
adam@0 868 end
adam@0 869 if itemData.gemEnchantIds[2] ~= 0 then
adam@0 870 table.insert(itemParts, "b" .. (itemData.gemEnchantIds[2] - prevGemId))
adam@0 871 prevGemId = itemData.gemEnchantIds[2]
adam@0 872 end
adam@0 873 if itemData.gemEnchantIds[3] ~= 0 then
adam@0 874 table.insert(itemParts, "c" .. (itemData.gemEnchantIds[3] - prevGemId))
adam@0 875 prevGemId = itemData.gemEnchantIds[3]
adam@0 876 end
adam@0 877 if itemData.enchantId ~= 0 then
adam@0 878 table.insert(itemParts, "e" .. (itemData.enchantId - prevEnchantId))
adam@0 879 prevEnchantId = itemData.enchantId
adam@0 880 end
adam@0 881 if itemData.reforgeId ~= 0 then table.insert(itemParts, "r" .. (itemData.reforgeId - 113)) end
adam@0 882
adam@0 883 table.insert(fields, table.concat(itemParts, ""))
adam@0 884 end
yellowfive@11 885
adam@0 886 return "$" .. table.concat(fields, ";") .. "$"
adam@0 887 end
adam@0 888
yellowfive@11 889 local function GetPlayerExtraData(data, index)
yellowfive@11 890
yellowfive@11 891 local unitId = "raid" .. index
yellowfive@11 892
yellowfive@11 893 local guid = UnitGUID(unitId)
yellowfive@11 894 if guid == nil then
yellowfive@11 895 return nil
yellowfive@11 896 end
yellowfive@11 897
yellowfive@11 898 local fields = {}
yellowfive@11 899
yellowfive@11 900 local buffs = {}
yellowfive@11 901 for i=1,40 do
yellowfive@11 902 local _,_,_,count,_,_,_,_,_,_,spellId = UnitAura(unitId, i, "HELPFUL")
yellowfive@11 903 table.insert(buffs, spellId)
yellowfive@11 904 end
yellowfive@11 905 if #buffs == 0 then
yellowfive@11 906 table.insert(fields, "_")
yellowfive@11 907 else
yellowfive@11 908 table.insert(fields, toCompressedNumberList(buffs))
yellowfive@11 909 end
yellowfive@11 910
yellowfive@11 911 local petGuid = UnitGUID("raidpet" .. index)
yellowfive@11 912 if petGuid then
yellowfive@11 913 table.insert(fields, guid .. "," .. petGuid)
yellowfive@11 914 else
yellowfive@11 915 table.insert(fields, '_')
yellowfive@11 916 end
yellowfive@11 917
yellowfive@11 918 local name = GetRaidRosterInfo(index)
yellowfive@11 919 local realm = GetRealmName()
yellowfive@11 920 local splitPos = string.find(name, "-")
yellowfive@11 921 if splitPos ~= nil then
yellowfive@11 922 realm = string.sub(name, splitPos + 1)
yellowfive@11 923 name = string.sub(name, 1, splitPos - 1)
yellowfive@11 924 end
yellowfive@11 925
yellowfive@11 926 data[realm .. ":" .. name] = table.concat(fields, ";")
yellowfive@11 927 end
yellowfive@11 928
yellowfive@11 929 function AskMrRobot.ExportLoggingData(timestamp)
yellowfive@11 930
yellowfive@11 931 local isLogging = AskMrRobot_ReforgeFrame.combatLogTab:IsLogging()
yellowfive@11 932 if not isLogging then
yellowfive@11 933 return
yellowfive@11 934 end
yellowfive@11 935
yellowfive@11 936 -- we only get extra information for people if in a raid
yellowfive@11 937 if not IsInRaid() then
yellowfive@11 938 return
yellowfive@11 939 end
yellowfive@11 940
yellowfive@11 941 local data = {}
yellowfive@11 942 for i = 1,40 do
yellowfive@11 943 GetPlayerExtraData(data, i)
yellowfive@11 944 end
yellowfive@11 945
yellowfive@11 946 AskMrRobot.CombatLogTab.SaveExtras(data, timestamp)
yellowfive@11 947 end
yellowfive@11 948
adam@0 949 function AskMrRobot.ExportToAddonChat(timestamp)
yellowfive@11 950 local msg = AskMrRobot.ExportToCompressedString(false)
adam@0 951 local msgPrefix = timestamp .. "\n" .. AmrRealmName .. "\n" .. AmrCharacterName .. "\n"
adam@0 952
adam@0 953 -- break the data into 250 character chunks (to deal with the short limit on addon message size)
adam@0 954 local chunks = {}
adam@0 955 local i = 1
yellowfive@11 956 local length = string.len(msg)
adam@0 957 local chunkLen = 249 - string.len(msgPrefix)
adam@0 958 while (i <= length) do
adam@0 959 local endpos = math.min(i + chunkLen, length)
yellowfive@11 960 table.insert(chunks, msgPrefix .. string.sub(msg, i, endpos))
adam@0 961 i = endpos + 1
adam@0 962 end
adam@0 963
adam@0 964 for i, v in ipairs(chunks) do
adam@0 965 SendAddonMessage(AskMrRobot.ChatPrefix, v, "RAID")
adam@0 966 end
adam@0 967
adam@0 968 -- send a completion message
adam@0 969 SendAddonMessage(AskMrRobot.ChatPrefix, msgPrefix .. "done", "RAID")
adam@0 970 end
adam@0 971
adam@0 972 -- Create an export string that can be copied to the website
adam@0 973 function AskMrRobot.ExportToString()
adam@0 974
adam@0 975 --[[
adam@0 976 local fields = {}
adam@0 977
adam@0 978 fields["realm"] = AmrRealmName
adam@0 979 fields["name"] = AmrCharacterName
adam@0 980 fields["race"] = AmrRace
adam@0 981 fields["faction"] = AmrFaction
adam@0 982 fields["level"] = AmrLevel
adam@0 983
adam@0 984 local profs = {}
adam@0 985 for k, v in pairs(AmrProfessions) do
adam@0 986 table.insert(profs, k .. ":" .. v)
adam@0 987 end
adam@0 988 fields["professions"] = table.concat(profs, ",")
adam@0 989
adam@0 990 if (AmrActiveSpec ~= nil) then
adam@0 991 fields["activespec"] = AmrActiveSpec
adam@0 992 fields["spec"] = AmrSpecializations[AmrActiveSpec .. ""]
adam@0 993 fields["talents"] = AmrTalents[AmrActiveSpec]
adam@0 994 fields["glyphs"] = table.concat(AmrGlyphs[AmrActiveSpec], ",")
adam@0 995 end
adam@0 996
adam@0 997 local items = {}
adam@0 998 for k, v in pairs(AmrEquipedItems) do
adam@0 999 table.insert(items, ItemLinkToExportString(v, k))
adam@0 1000 end
adam@0 1001 for i, v in ipairs(AmrBagItems) do
adam@0 1002 table.insert(items, ItemLinkToExportString(v, "-1"))
adam@0 1003 end
adam@0 1004 for i, v in ipairs(AmrBankItems) do
adam@0 1005 table.insert(items, ItemLinkToExportString(v, "-1"))
adam@0 1006 end
adam@0 1007 fields["items"] = table.concat(items, "_")
adam@0 1008
adam@0 1009 local fieldList = {}
adam@0 1010 for k, v in pairs(fields) do
adam@0 1011 table.insert(fieldList, k .. "=" .. v)
adam@0 1012 end
adam@0 1013 ]]
adam@0 1014
adam@0 1015 --return table.concat(fieldList, ";")
adam@0 1016
adam@0 1017 return AskMrRobot.ExportToCompressedString(true)
adam@0 1018 --return AskMrRobot.ExportToAddonChat(time())
adam@0 1019 end
adam@0 1020
adam@0 1021 local function parseGlyphs(input)
adam@0 1022 local glyphs = {}
adam@0 1023 for glyph in string.gmatch(input, "([^,]+)") do
adam@0 1024 tinsert(glyphs, glyph)
adam@0 1025 end
adam@0 1026 table.sort(glyphs)
adam@0 1027 return glyphs
adam@0 1028 end
adam@0 1029
adam@0 1030 local function parseProfessions(input)
adam@0 1031 local professions = {}
adam@0 1032 for prof, v in string.gmatch(input, "([^:,]+):([^,]+)") do
adam@0 1033 professions[prof] = tonumber(v);
adam@0 1034 end
adam@0 1035 return professions;
adam@0 1036 end
adam@0 1037
adam@0 1038 local gemColorMapping = {
adam@0 1039 y = 'Yellow',
adam@0 1040 b = 'Blue',
adam@0 1041 r = 'Red',
adam@0 1042 h = 'Hydraulic',
adam@0 1043 p = 'Prismatic',
adam@0 1044 m = 'Meta',
adam@0 1045 c = 'Cogwheel'
adam@0 1046 }
adam@0 1047
adam@0 1048 local function parseAmrItem(input)
adam@0 1049 local slot, itemId, suffixList, upgradeId, gemColorString, gemEnchantIdString, gemIdString, enchantId, reforgeId = string.match(input, "^(%d+):(%d+):([^:]+):([^:]+):([^:]+):([^:]+):([^:]+):(%d+):(%d+)");
adam@0 1050 -- parse the gem enchant ids out of their comma seperated list
adam@0 1051 local gems = {}
adam@0 1052 for gemEnchantId in string.gmatch(gemEnchantIdString, '(%d+)') do
adam@0 1053 tinsert(gems, {enchantId = tonumber(gemEnchantId), id = 0})
adam@0 1054 end
adam@0 1055 -- make sure we have 4 gem ids
adam@0 1056 for i = #gems + 1, 4 do
adam@0 1057 tinsert(gems, {enchantId = 0, id = 0})
adam@0 1058 end
adam@0 1059 -- parse the gem ids out of their comma seperated list
adam@0 1060 local gemIds = {}
adam@0 1061 i = 1
adam@0 1062 for gemId in string.gmatch(gemIdString, '(%d+)') do
adam@0 1063 gems[i].id = tonumber(gemId)
adam@0 1064 i = i + 1
adam@0 1065 end
adam@0 1066 i = 1
adam@0 1067 for gemColor in string.gmatch(gemColorString, '([^,])') do
adam@0 1068 gems[i].color = gemColorMapping[gemColor]
adam@0 1069 i = i + 1
adam@0 1070 end
adam@0 1071
adam@0 1072 -- parse the possible suffixes out of their comma seperated list and put them in a set (number -> bool)
adam@0 1073 local suffixes = {}
adam@0 1074 for suffixId in string.gmatch(suffixList, '(%-?%d+)') do
adam@0 1075 suffixes[tonumber(suffixId)] = true
adam@0 1076 end
adam@0 1077
adam@0 1078 local item = {
adam@0 1079 itemId = tonumber(itemId),
adam@0 1080 suffixes = suffixes,
adam@0 1081 upgradeId = tonumber(upgradeId),
adam@0 1082 gems = gems,
adam@0 1083 enchantId = tonumber(enchantId),
adam@0 1084 reforgeId = tonumber(reforgeId)
adam@0 1085 }
adam@0 1086 return slot, item
adam@0 1087 end
adam@0 1088
adam@0 1089
adam@0 1090 function AskMrRobot.parseAmr(input)
adam@0 1091 local parsedInput = {}
adam@0 1092 parsedInput.items = {}
adam@0 1093 for k, v in string.gmatch(input, "([^=;]+)=([^;]*)") do
adam@0 1094 if (k == 'item') then
adam@0 1095 local slot, item = parseAmrItem(v);
adam@0 1096 parsedInput.items[AskMrRobot.slotIdToSlotNum[tonumber(slot) + 1]] = item;
adam@0 1097 elseif (k == 'glyphs') then
adam@0 1098 parsedInput.glyphs = parseGlyphs(v)
adam@0 1099 elseif (k == 'professions') then
adam@0 1100 parsedInput.professions = parseProfessions(v)
adam@0 1101 else
adam@0 1102 parsedInput[k]=v
adam@0 1103 end
adam@0 1104 end
adam@0 1105 return parsedInput
adam@0 1106 end
adam@0 1107
adam@0 1108 function AskMrRobot.validateRealm(realm)
adam@0 1109 return realm == GetRealmName();
adam@0 1110 end
adam@0 1111
adam@0 1112 function AskMrRobot.validateCharacterName(characterName)
adam@0 1113 return UnitName("player") == characterName
adam@0 1114 end
adam@0 1115
adam@0 1116 function AskMrRobot.validateRace(race)
adam@0 1117 local _, raceEn = UnitRace("player")
adam@0 1118 return raceEn == race or (raceEn == "Scourge" and race == "Undead")
adam@0 1119 end
adam@0 1120
adam@0 1121 function AskMrRobot.validateFaction(faction)
adam@0 1122 return faction == UnitFactionGroup("player")
adam@0 1123 end
adam@0 1124
adam@0 1125 function AskMrRobot.validateSpec(spec)
adam@0 1126 if spec == 'nil' then
adam@0 1127 spec = nil
adam@0 1128 end
adam@0 1129 local currentSpec = GetAmrSpecialization(GetActiveSpecGroup())
adam@0 1130 return (not currentSpec and not spec) or tostring(currentSpec) == spec
adam@0 1131 end
adam@0 1132
adam@0 1133 function AskMrRobot.validateTalents(talents)
adam@0 1134 if talents == nil then
adam@0 1135 talents = ''
adam@0 1136 end
adam@0 1137 return talents == GetAmrTalentsForSpec(GetActiveSpecGroup())
adam@0 1138 end
adam@0 1139
adam@0 1140 function AskMrRobot.validateGlyphs(glyphs)
adam@0 1141 if (glyphs == nil) then
adam@0 1142 glyphs = {};
adam@0 1143 end
adam@0 1144 local currentGlyphs = GetAmrGlyphsForSpec(GetActiveSpecGroup())
adam@0 1145 table.sort(glyphs, function(a,b) return tostring(a) < tostring(b) end)
adam@0 1146 table.sort(currentGlyphs, function(a,b) return tostring(a) < tostring(b) end)
adam@0 1147
adam@0 1148 if #glyphs ~= #currentGlyphs then
adam@0 1149 return false
adam@0 1150 end
adam@0 1151 for i = 1, #glyphs do
adam@0 1152 if tostring(glyphs[i]) ~= tostring(currentGlyphs[i]) then
adam@0 1153 return false
adam@0 1154 end
adam@0 1155 end
adam@0 1156
adam@0 1157 return true
adam@0 1158 end
adam@0 1159
adam@0 1160 local function getPrimaryProfessions()
adam@0 1161 local profs = {}
adam@0 1162 local prof1, prof2 = GetProfessions()
adam@0 1163 local profMap = {
adam@0 1164 [794] = "Archaeology",
adam@0 1165 [171] = "Alchemy",
adam@0 1166 [164] = "Blacksmithing",
adam@0 1167 [185] = "Cooking",
adam@0 1168 [333] = "Enchanting",
adam@0 1169 [202] = "Engineering",
adam@0 1170 [129] = "First Aid",
adam@0 1171 [356] = "Fishing",
adam@0 1172 [182] = "Herbalism",
adam@0 1173 [773] = "Inscription",
adam@0 1174 [755] = "Jewelcrafting",
adam@0 1175 [165] = "Leatherworking",
adam@0 1176 [186] = "Mining",
adam@0 1177 [393] = "Skinning",
adam@0 1178 [197] = "Tailoring"
adam@0 1179 }
adam@0 1180
adam@0 1181 if prof1 then
adam@0 1182 local _, _, skillLevel, _, _, _, skillLine = GetProfessionInfo(prof1);
adam@0 1183 if profMap[skillLine] ~= nil then
adam@0 1184 profs[profMap[skillLine]] = skillLevel
adam@0 1185 end
adam@0 1186 end
adam@0 1187 if prof2 then
adam@0 1188 local _, _, skillLevel, _, _, _, skillLine = GetProfessionInfo(prof2);
adam@0 1189 if profMap[skillLine] ~= nil then
adam@0 1190 profs[profMap[skillLine]] = skillLevel
adam@0 1191 end
adam@0 1192 end
adam@0 1193 return profs;
adam@0 1194 end
adam@0 1195
adam@0 1196 local professionThresholds = {
adam@0 1197 Leatherworking = 575,
adam@0 1198 Inscription = 600,
adam@0 1199 Alchemy = 50,
adam@0 1200 Enchanting = 550,
adam@0 1201 Jewelcrafting = 550,
adam@0 1202 Blacksmithing = 550,
adam@0 1203 Tailoring = 550
adam@0 1204 }
adam@0 1205
adam@0 1206 function AskMrRobot.validateProfessions(professions)
adam@0 1207 local currentProfessions = getPrimaryProfessions()
adam@0 1208 if #currentProfessions ~= #professions then
adam@0 1209 return false
adam@0 1210 end
adam@0 1211 for k, v in pairs(professions) do
adam@0 1212 if currentProfessions[k] then
adam@0 1213 local threshold = professionThresholds[k]
adam@0 1214 if not threshold then
adam@0 1215 threshold = 1
adam@0 1216 end
adam@0 1217 -- compare the desired profession against the threshold
adam@0 1218 local desired = v >= threshold
adam@0 1219 -- compare the current profession against the threshold
adam@0 1220 local has = currentProfessions[k] and currentProfessions[k] >= threshold
adam@0 1221 -- if the current value is on the other side of the threshold
adam@0 1222 -- then we don't match
adam@0 1223 if desired ~= has then
adam@0 1224 return false
adam@0 1225 end
adam@0 1226 else
adam@0 1227 return false
adam@0 1228 end
adam@0 1229 end
adam@0 1230 return true
adam@0 1231 end
adam@0 1232
adam@0 1233 function AskMrRobot.populateItemDiffs(amrItem, itemLink, slotNum)
adam@0 1234 AskMrRobot.itemDiffs.items[slotNum] = nil
adam@0 1235 AskMrRobot.itemDiffs.gems[slotNum] = nil
adam@0 1236 AskMrRobot.itemDiffs.enchants[slotNum] = nil
adam@0 1237 AskMrRobot.itemDiffs.reforges[slotNum] = nil
adam@0 1238
adam@0 1239 local needsUpgrade = false
adam@0 1240 local aSuffix = 0
adam@0 1241 if amrItem then
adam@0 1242 for k,v in pairs(amrItem.suffixes) do
adam@0 1243 aSuffix = k
adam@0 1244 end
adam@0 1245 end
adam@0 1246
adam@0 1247 if itemLink == nil then
adam@0 1248 if amrItem ~= nil then
adam@0 1249 AskMrRobot.itemDiffs.items[slotNum] = {
adam@0 1250 current = nil,
adam@0 1251 optimized = { itemId = amrItem.itemId, upgradeId = amrItem.upgradeId, suffixId = aSuffix },
adam@0 1252 needsUpgrade = false
adam@0 1253 }
adam@0 1254 end
adam@0 1255 return
adam@0 1256 end
adam@0 1257 local item = parseItemLink(itemLink)
adam@0 1258 local isItemBad = false
adam@0 1259
adam@0 1260 if amrItem == nil or item.itemId ~= amrItem.itemId then
adam@0 1261 isItemBad = true
adam@0 1262 else
adam@0 1263 if item.suffixId == 0 then
adam@0 1264 if #amrItem.suffixes > 0 then
adam@0 1265 isItemBad = true
adam@0 1266 end
adam@0 1267 else
adam@0 1268 if not amrItem.suffixes[item.suffixId] then
adam@0 1269 isItemBad = true
adam@0 1270 end
adam@0 1271 end
adam@0 1272 if not isItemBad and upgradeTable[item.upgradeId] ~= upgradeTable[amrItem.upgradeId] then
adam@0 1273 isItemBad = true
adam@0 1274 needsUpgrade = true
adam@0 1275 end
adam@0 1276 end
adam@0 1277
adam@0 1278 if isItemBad then
adam@0 1279 AskMrRobot.itemDiffs.items[slotNum] = {
adam@0 1280 current = item.itemId,
adam@0 1281 optimized = { itemId = amrItem and amrItem.itemId or 0, upgradeId = amrItem and amrItem.upgradeId or 0, suffixId = aSuffix },
adam@0 1282 needsUpgrade = needsUpgrade
adam@0 1283 }
adam@0 1284 return
adam@0 1285 end
adam@0 1286
adam@0 1287 local badGemCount, gemInfo = AskMrRobot.MatchesGems(itemLink, item.gemEnchantIds, amrItem.gems)
adam@0 1288 if badGemCount > 0 then
adam@0 1289 AskMrRobot.itemDiffs.gems[slotNum] = gemInfo
adam@0 1290 end
adam@0 1291
adam@0 1292 if item.enchantId ~= amrItem.enchantId then
adam@0 1293 AskMrRobot.itemDiffs.enchants[slotNum] = {
adam@0 1294 current = item.enchantId,
adam@0 1295 optimized = amrItem.enchantId
adam@0 1296 }
adam@0 1297 end
adam@0 1298
adam@0 1299 if item.reforgeId ~= amrItem.reforgeId then
adam@0 1300 AskMrRobot.itemDiffs.reforges[slotNum] = {
adam@0 1301 current = item.reforgeId,
adam@0 1302 optimized = amrItem.reforgeId
adam@0 1303 }
adam@0 1304 end
adam@0 1305 end
adam@0 1306
adam@0 1307 --[[
adam@0 1308 function AskMrRobot.StartLogging()
adam@0 1309 if not LoggingCombat() then
adam@0 1310 LoggingCombat(1)
adam@0 1311 print("Started Combat Logging")
adam@0 1312 end
adam@0 1313 end
adam@0 1314
adam@0 1315 function AskMrRobot.FinishLogging()
adam@0 1316 if LoggingCombat() then
adam@0 1317 LoggingCombat(0)
adam@0 1318 print("Finished Combat Logging")
adam@0 1319 end
adam@0 1320 end
adam@0 1321
adam@0 1322 -- local difficultyLookup = {
adam@0 1323 -- DUNGEON_DIFFICULTY1,
adam@0 1324 -- DUNGEON_DIFFICULTY2,
adam@0 1325 -- RAID_DIFFICULTY_10PLAYER,
adam@0 1326 -- RAID_DIFFICULTY_25PLAYER,
adam@0 1327 -- RAID_DIFFICULTY_10PLAYER_HEROIC,
adam@0 1328 -- RAID_DIFFICULTY_25PLAYER_HEROIC,
adam@0 1329 -- RAID_FINDER,
adam@0 1330 -- CHALLENGE_MODE,
adam@0 1331 -- RAID_DIFFICULTY_40PLAYER,
adam@0 1332 -- nil,
adam@0 1333 -- nil, -- Norm scen
adam@0 1334 -- nil, -- heroic scen
adam@0 1335 -- nil,
adam@0 1336 -- PLAYER_DIFFICULTY4
adam@0 1337 -- }
adam@0 1338
adam@0 1339 --http://wowpedia.org/InstanceMapID
adam@0 1340 local instanceMaps = {
adam@0 1341 HeartOfFear = 1009,
adam@0 1342 MogushanVaults = 1008,
adam@0 1343 SiegeOfOrgrimmar = 1136,
adam@0 1344 TerraceOfEndlessSpring = 996,
adam@0 1345 ThroneOfThunder = 1098
adam@0 1346 }
adam@0 1347
adam@0 1348 function AskMrRobot.UpdateLogging()
adam@0 1349
adam@0 1350 -- get the info about the instance
adam@0 1351 --local zone, zonetype, difficultyIndex, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID = GetInstanceInfo()
adam@0 1352 local zone, _, difficultyIndex, _, _, _, _, instanceMapID = GetInstanceInfo()
adam@0 1353 --local difficulty = difficultyIndex
adam@0 1354 -- Unless Blizzard fixes scenarios to not return nil, let's hardcode this into returning "scenario" -Znuff
adam@0 1355 --if zonetype == nil and difficultyIndex == 1 then
adam@0 1356 --zonetype = "scenario"
adam@0 1357 --end
adam@0 1358
adam@0 1359 -- if nothing has changed, then bail
adam@0 1360 --if (not zone) and difficulty == 0 then return end
adam@0 1361 if zone == AskMrRobot.lastzone and difficultyIndex == AskMrRobot.lastdiff then
adam@0 1362 -- do nothing if the zone hasn't ACTUALLY changed
adam@0 1363 -- otherwise we may override the user's manual enable/disable
adam@0 1364 return
adam@0 1365 end
adam@0 1366
adam@0 1367 AskMrRobot.lastzone = zone
adam@0 1368 AskMrRobot.lastdiff = difficultyIndex
adam@0 1369
adam@0 1370 if AmrOptions.autoLog[tonumber(instanceMapID)] then
adam@0 1371 if instanceMapID == instanceMaps.SiegeOfOrgrimmar then
adam@0 1372 AskMrRobot.StartLogging()
adam@0 1373 else
adam@0 1374 AskMrRobot.FinishLogging()
adam@0 1375 end
adam@0 1376 end
adam@0 1377 end
adam@0 1378 ]]