comparison AskMrRobot.lua @ 0:ec731d2fe6ba

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