comparison AskMrRobot.lua @ 17:e77e01abce98

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