comparison AskMrRobot.lua @ 11:ece9167c0d1c v1.2.14.0

Localization support, combat log features (wipe command, aura/pet tracking, and realm detection).
author yellowfive
date Thu, 10 Jul 2014 12:24:59 -0700
parents ec731d2fe6ba
children bb0c8ce689d1
comparison
equal deleted inserted replaced
10:ef8b45e96b08 11:ece9167c0d1c
1 local _, AskMrRobot = ... 1 local _, AskMrRobot = ...
2 local L = AskMrRobot.L;
2 3
3 AskMrRobot.eventListener = CreateFrame("FRAME"); -- Need a frame to respond to events 4 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("ADDON_LOADED"); -- Fired when saved variables are loaded
5 AskMrRobot.eventListener:RegisterEvent("ITEM_PUSH"); 6 AskMrRobot.eventListener:RegisterEvent("ITEM_PUSH");
6 AskMrRobot.eventListener:RegisterEvent("DELETE_ITEM_CONFIRM"); 7 AskMrRobot.eventListener:RegisterEvent("DELETE_ITEM_CONFIRM");
10 AskMrRobot.eventListener:RegisterEvent("PLAYERBANKSLOTS_CHANGED"); 11 AskMrRobot.eventListener:RegisterEvent("PLAYERBANKSLOTS_CHANGED");
11 AskMrRobot.eventListener:RegisterEvent("CHARACTER_POINTS_CHANGED"); 12 AskMrRobot.eventListener:RegisterEvent("CHARACTER_POINTS_CHANGED");
12 AskMrRobot.eventListener:RegisterEvent("CONFIRM_TALENT_WIPE"); 13 AskMrRobot.eventListener:RegisterEvent("CONFIRM_TALENT_WIPE");
13 AskMrRobot.eventListener:RegisterEvent("PLAYER_TALENT_UPDATE"); 14 AskMrRobot.eventListener:RegisterEvent("PLAYER_TALENT_UPDATE");
14 AskMrRobot.eventListener:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED"); 15 AskMrRobot.eventListener:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED");
16 AskMrRobot.eventListener:RegisterEvent("PLAYER_ENTERING_WORLD");
15 AskMrRobot.eventListener:RegisterEvent("PLAYER_LOGOUT"); -- Fired when about to log out 17 AskMrRobot.eventListener:RegisterEvent("PLAYER_LOGOUT"); -- Fired when about to log out
16 AskMrRobot.eventListener:RegisterEvent("PLAYER_LEVEL_UP"); 18 AskMrRobot.eventListener:RegisterEvent("PLAYER_LEVEL_UP");
17 --AskMrRobot.eventListener:RegisterEvent("GET_ITEM_INFO_RECEIVED") 19 --AskMrRobot.eventListener:RegisterEvent("GET_ITEM_INFO_RECEIVED")
18 AskMrRobot.eventListener:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED") 20 AskMrRobot.eventListener:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
19 AskMrRobot.eventListener:RegisterEvent("SOCKET_INFO_UPDATE") 21 AskMrRobot.eventListener:RegisterEvent("SOCKET_INFO_UPDATE")
20 AskMrRobot.eventListener:RegisterEvent("SOCKET_INFO_CLOSE") 22 AskMrRobot.eventListener:RegisterEvent("SOCKET_INFO_CLOSE")
21 AskMrRobot.eventListener:RegisterEvent("BAG_UPDATE") 23 AskMrRobot.eventListener:RegisterEvent("BAG_UPDATE")
22 AskMrRobot.eventListener:RegisterEvent("ITEM_UNLOCKED") 24 AskMrRobot.eventListener:RegisterEvent("ITEM_UNLOCKED")
23 --AskMrRobot.eventListener:RegisterEvent("PLAYER_REGEN_DISABLED") 25 AskMrRobot.eventListener:RegisterEvent("PLAYER_REGEN_DISABLED")
24 AskMrRobot.eventListener:RegisterEvent("ENCOUNTER_START") 26 --AskMrRobot.eventListener:RegisterEvent("ENCOUNTER_START")
25 AskMrRobot.eventListener:RegisterEvent("CHAT_MSG_ADDON") 27 AskMrRobot.eventListener:RegisterEvent("CHAT_MSG_ADDON")
26 AskMrRobot.eventListener:RegisterEvent("UPDATE_INSTANCE_INFO") 28 AskMrRobot.eventListener:RegisterEvent("UPDATE_INSTANCE_INFO")
27 AskMrRobot.eventListener:RegisterEvent("PLAYER_DIFFICULTY_CHANGED") 29 AskMrRobot.eventListener:RegisterEvent("PLAYER_DIFFICULTY_CHANGED")
28 30
29 AskMrRobot.AddonName = ... 31 AskMrRobot.AddonName = ...
47 MogushanVaults = 1008, 49 MogushanVaults = 1008,
48 SiegeOfOrgrimmar = 1136, 50 SiegeOfOrgrimmar = 1136,
49 TerraceOfEndlessSpring = 996, 51 TerraceOfEndlessSpring = 996,
50 ThroneOfThunder = 1098 52 ThroneOfThunder = 1098
51 } 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
52 70
53 -- upgrade id -> upgrade level 71 -- upgrade id -> upgrade level
54 local upgradeTable = { 72 local upgradeTable = {
55 [0] = 0, 73 [0] = 0,
56 [1] = 1, -- 1/1 -> 8 74 [1] = 1, -- 1/1 -> 8
94 [495] = 1, 112 [495] = 1,
95 [496] = 2, 113 [496] = 2,
96 [497] = 3, 114 [497] = 3,
97 [498] = 4, 115 [498] = 4,
98 [504] = 3, 116 [504] = 3,
99 [505] = 4 117 [505] = 4,
118 [506] = 5,
119 [507] = 6
100 } 120 }
101 121
102 local professionIds = { 122 local professionIds = {
103 ["None"] = 0, 123 ["None"] = 0,
104 ["Mining"] = 1, 124 ["Mining"] = 1,
154 174
155 function AskMrRobot.eventListener:OnEvent(event, ...) 175 function AskMrRobot.eventListener:OnEvent(event, ...)
156 if event == "ADDON_LOADED" then 176 if event == "ADDON_LOADED" then
157 local addon = select(1, ...) 177 local addon = select(1, ...)
158 if (addon == "AskMrRobot") then 178 if (addon == "AskMrRobot") then
159 print("Loaded Ask Mr. Robot " .. GetAddOnMetadata(AskMrRobot.AddonName, "Version")) 179 print(L.AMR_ON_EVENT_LOADED.format(GetAddOnMetadata(AskMrRobot.AddonName, "Version")))
160 180
161 -- listen for messages from other AMR addons 181 -- listen for messages from other AMR addons
162 RegisterAddonMessagePrefix(AskMrRobot.ChatPrefix) 182 RegisterAddonMessagePrefix(AskMrRobot.ChatPrefix)
163 183
164 AmrRealmName = GetRealmName() 184 AmrRealmName = GetRealmName()
165 AmrCharacterName = UnitName("player") 185 AmrCharacterName = UnitName("player")
166 186
167 if not AmrLogData then AmrLogData = {} end 187 AskMrRobot.CombatLogTab.InitializeVariable()
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 188
173 if not AmrIconInfo then AmrIconInfo = {} end 189 if not AmrIconInfo then AmrIconInfo = {} end
174 if not AmrBankItems then AmrBankItems = {} end 190 if not AmrBankItems then AmrBankItems = {} end
175 if not AmrCurrencies then AmrCurrencies = {} end 191 if not AmrCurrencies then AmrCurrencies = {} end
176 if not AmrSpecializations then AmrSpecializations = {} end 192 if not AmrSpecializations then AmrSpecializations = {} end
178 if not AmrGlyphs then AmrGlyphs = {} end 194 if not AmrGlyphs then AmrGlyphs = {} end
179 if not AmrTalents then AmrTalents = {} end 195 if not AmrTalents then AmrTalents = {} end
180 if not AmrBankItemsAndCounts then AmrBankItemsAndCounts = {} end 196 if not AmrBankItemsAndCounts then AmrBankItemsAndCounts = {} end
181 if not AmrImportString then AmrImportString = "" end 197 if not AmrImportString then AmrImportString = "" end
182 if not AmrImportDate then AmrImportDate = "" 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
183 if not AmrSendSettings then 203 if not AmrSendSettings then
184 AmrSendSettings = { 204 AmrSendSettings = {
185 SendGems = true, 205 SendGems = true,
186 SendEnchants = true, 206 SendEnchants = true,
187 SendEnchantMaterials = true, 207 SendEnchantMaterials = true,
193 amrLDB = LibStub("LibDataBroker-1.1"):NewDataObject("AskMrRobot", { 213 amrLDB = LibStub("LibDataBroker-1.1"):NewDataObject("AskMrRobot", {
194 type = "launcher", 214 type = "launcher",
195 text = "Ask Mr. Robot", 215 text = "Ask Mr. Robot",
196 icon = "Interface\\AddOns\\AskMrRobot\\Media\\icon", 216 icon = "Interface\\AddOns\\AskMrRobot\\Media\\icon",
197 OnClick = function() 217 OnClick = function()
198 218 if IsControlKeyDown() then
199 if IsModifiedClick("CHATLINK") then 219 AskMrRobot_ReforgeFrame.combatLogTab:LogWipe()
220 elseif IsModifiedClick("CHATLINK") then
200 OnExport() 221 OnExport()
201 else 222 else
202 AskMrRobot_ReforgeFrame:Toggle() 223 AskMrRobot_ReforgeFrame:Toggle()
203 end 224 end
204 end, 225 end,
205 OnTooltipShow = function(tt) 226 OnTooltipShow = function(tt)
206 tt:AddLine("Ask Mr. Robot", 1, 1, 1); 227 tt:AddLine("Ask Mr. Robot", 1, 1, 1);
207 tt:AddLine(" "); 228 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.") 229 tt:AddLine(L.AMR_ON_EVENT_TOOLTIP)
209 end 230 end
210 }); 231 });
211 232
212 233
213 AskMrRobot.AmrUpdateMinimap() 234 AskMrRobot.AmrUpdateMinimap()
244 --GetLevel(); 265 --GetLevel();
245 elseif event == "ITEM_UNLOCKED" then 266 elseif event == "ITEM_UNLOCKED" then
246 AskMrRobot.On_ITEM_UNLOCKED() 267 AskMrRobot.On_ITEM_UNLOCKED()
247 elseif event == "PLAYER_LOGOUT" then 268 elseif event == "PLAYER_LOGOUT" then
248 -- doing nothing right now, but leaving this in case we need something here 269 -- doing nothing right now, but leaving this in case we need something here
249 elseif event == "ENCOUNTER_START" then 270 elseif event == "PLAYER_ENTERING_WORLD" then
250 -- send data about this character when a boss fight starts 271
251 AskMrRobot.SaveAll() 272 -- delete entries that are more than 10 days old to prevent the table from growing indefinitely
252 AskMrRobot.ExportToAddonChat(time()) 273 local now = time()
274 local oldDuration = 60 * 60 * 24 * 10
275 local entryTime
276 repeat
277 -- parse entry and get time
278 local parts = {}
279 for part in string.gmatch(AmrSettings.Logins[1], "([^;]+)") do
280 tinsert(parts, part)
281 end
282 entryTime = tonumber(parts[3])
283
284 -- entries are in order, remove first entry if it is old
285 if difftime(now, entryTime) > oldDuration then
286 tremove(AmrSettings.Logins, 1)
287 end
288 until #AmrSettings.Logins == 0 or difftime(now, entryTime) <= oldDuration
289
290 -- record the time a player logs in, used to figure out which player logged which parts of their log file
291 local key = AmrRealmName .. ";" .. AmrCharacterName .. ";"
292 local loginData = key .. time()
293 if AmrSettings.Logins and #AmrSettings.Logins > 0 then
294 local last = AmrSettings.Logins[#AmrSettings.Logins]
295 if string.len(last) >= string.len(key) and string.sub(last, 1, string.len(key)) ~= key then
296 table.insert(AmrSettings.Logins, loginData)
297 end
298 else
299 table.insert(AmrSettings.Logins, loginData)
300 end
301
302 elseif event == "PLAYER_REGEN_DISABLED" then
303
304 -- send data about this character when a player enters combat in a supported zone
305 if AskMrRobot.IsSupportedInstance() then
306 local t = time()
307 AskMrRobot.SaveAll()
308 AskMrRobot.ExportToAddonChat(t)
309 AskMrRobot.ExportLoggingData(t)
310 end
311
253 elseif event == "CHAT_MSG_ADDON" then 312 elseif event == "CHAT_MSG_ADDON" then
254 local chatPrefix, message = select(1, ...) 313 local chatPrefix, message = select(1, ...)
255 local isLogging = AskMrRobot_ReforgeFrame.combatLogTab:IsLogging() 314 local isLogging = AskMrRobot_ReforgeFrame.combatLogTab:IsLogging()
256 if (isLogging and chatPrefix == AskMrRobot.ChatPrefix) then 315 if (isLogging and chatPrefix == AskMrRobot.ChatPrefix) then
257 AskMrRobot_ReforgeFrame.combatLogTab:ReadAddonMessage(message) 316 AskMrRobot_ReforgeFrame.combatLogTab:ReadAddonMessage(message)
258 end 317 end
259 elseif event == "UPDATE_INSTANCE_INFO" or event == "PLAYER_DIFFICULTY_CHANGED" then 318 elseif event == "UPDATE_INSTANCE_INFO" or event == "PLAYER_DIFFICULTY_CHANGED" then
260 AskMrRobot_ReforgeFrame.combatLogTab:UpdateAutoLogging() 319 AskMrRobot_ReforgeFrame.combatLogTab:UpdateAutoLogging()
285 AskMrRobot_ReforgeFrame:Show() 344 AskMrRobot_ReforgeFrame:Show()
286 elseif msg == 'hide' then 345 elseif msg == 'hide' then
287 AskMrRobot_ReforgeFrame:Hide() 346 AskMrRobot_ReforgeFrame:Hide()
288 elseif msg == 'export' then 347 elseif msg == 'export' then
289 OnExport() 348 OnExport()
349 elseif msg == 'wipe' then
350 AskMrRobot_ReforgeFrame.combatLogTab:LogWipe()
351 elseif msg == 'unwipe' then
352 AskMrRobot_ReforgeFrame.combatLogTab:LogUnwipe()
290 else 353 else
291 print('Available AskMrRobot slash commands:\n' .. 354 print(L.AMR_SLASH_COMMAND_TEXT_1 .. L.AMR_SLASH_COMMAND_TEXT_2 .. L.AMR_SLASH_COMMAND_TEXT_3 .. L.AMR_SLASH_COMMAND_TEXT_4 .. L.AMR_SLASH_COMMAND_TEXT_5 .. L.AMR_SLASH_COMMAND_TEXT_6 .. L.AMR_SLASH_COMMAND_TEXT_7)
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 355 end
297 end 356 end
298 357
299 function AskMrRobot.SaveAll() 358 function AskMrRobot.SaveAll()
300 AskMrRobot.ScanBank() 359 AskMrRobot.ScanBank()
311 --ReloadUI() 370 --ReloadUI()
312 end 371 end
313 372
314 local function InitIcon() 373 local function InitIcon()
315 icon = LibStub("LibDBIcon-1.0"); 374 icon = LibStub("LibDBIcon-1.0");
316 icon:Register("AskMrRobot", amrLDB, AmrIconInfo); 375 icon:Register("AskMrRobot", amrLDB, AmrIconInfo);
317 end 376 end
318 377
319 function AskMrRobot.AmrUpdateMinimap() 378 function AskMrRobot.AmrUpdateMinimap()
320 if (AmrOptions.hideMapIcon) then 379 if AmrOptions.hideMapIcon then
321 if (icon) then 380 if icon then
322 icon:Hide("AskMrRobot"); 381 icon:Hide("AskMrRobot");
323 end 382 end
324 else 383 else
325 if (not icon) then 384 if not icon then
326 InitIcon() 385 InitIcon()
386 end
387 --if AskMrRobot_ReforgeFrame.combatLogTab:IsLogging() then
388 if AskMrRobot.CombatLogTab.IsLogging(nil) then
389 amrLDB.icon = 'Interface\\AddOns\\AskMrRobot\\Media\\icon_green'
390 else
391 amrLDB.icon = 'Interface\\AddOns\\AskMrRobot\\Media\\icon'
327 end 392 end
328 icon:Show("AskMrRobot"); 393 icon:Show("AskMrRobot");
329 end 394 end
330 end 395 end
331 396
720 785
721 table.insert(fields, AmrLevel) 786 table.insert(fields, AmrLevel)
722 787
723 local profs = {} 788 local profs = {}
724 local noprofs = true 789 local noprofs = true
725 for k, v in pairs(AmrProfessions) do 790 if AmrProfessions then
726 local profval = professionIds[k] 791 for k, v in pairs(AmrProfessions) do
727 if profval ~= nil then 792 local profval = professionIds[k]
728 noprofs = false 793 if profval ~= nil then
729 table.insert(profs, profval .. ":" .. v) 794 noprofs = false
730 end 795 table.insert(profs, profval .. ":" .. v)
731 end 796 end
797 end
798 end
732 799
733 if noprofs then 800 if noprofs then
734 table.insert(profs, "0:0") 801 table.insert(profs, "0:0")
735 end 802 end
736 803
748 table.insert(fields, "_") 815 table.insert(fields, "_")
749 end 816 end
750 817
751 -- convert items to parsed objects, sorted by id 818 -- convert items to parsed objects, sorted by id
752 local itemObjects = {} 819 local itemObjects = {}
753 for k, v in pairs(AmrEquipedItems) do 820 if AmrEquipedItems then
754 local itemData = parseItemLink(v) 821 for k, v in pairs(AmrEquipedItems) do
755 itemData.slot = k 822 local itemData = parseItemLink(v)
756 table.insert(itemObjects, itemData) 823 itemData.slot = k
757 end 824 table.insert(itemObjects, itemData)
825 end
826 end
758 827
759 -- if desired, include bank/bag items too 828 -- if desired, include bank/bag items too
760 if includeInventory then 829 if includeInventory then
761 for i, v in ipairs(AmrBagItems) do 830 if AmrBagItems then
762 local itemData = parseItemLink(v) 831 for i, v in ipairs(AmrBagItems) do
763 if itemData.itemId ~= nil then 832 local itemData = parseItemLink(v)
764 table.insert(itemObjects, itemData) 833 if itemData.itemId ~= nil then
765 end 834 table.insert(itemObjects, itemData)
766 end 835 end
767 for i, v in ipairs(AmrBankItems) do 836 end
768 local itemData = parseItemLink(v) 837 end
769 if itemData.itemId ~= nil then 838 if AmrBankItems then
770 table.insert(itemObjects, itemData) 839 for i, v in ipairs(AmrBankItems) do
771 end 840 local itemData = parseItemLink(v)
772 end 841 if itemData.itemId ~= nil then
842 table.insert(itemObjects, itemData)
843 end
844 end
845 end
773 end 846 end
774 847
775 -- sort by item id so we can compress it more easily 848 -- sort by item id so we can compress it more easily
776 table.sort(itemObjects, function(a, b) return a.itemId < b.itemId end) 849 table.sort(itemObjects, function(a, b) return a.itemId < b.itemId end)
777 850
807 end 880 end
808 if itemData.reforgeId ~= 0 then table.insert(itemParts, "r" .. (itemData.reforgeId - 113)) end 881 if itemData.reforgeId ~= 0 then table.insert(itemParts, "r" .. (itemData.reforgeId - 113)) end
809 882
810 table.insert(fields, table.concat(itemParts, "")) 883 table.insert(fields, table.concat(itemParts, ""))
811 end 884 end
812 885
813 return "$" .. table.concat(fields, ";") .. "$" 886 return "$" .. table.concat(fields, ";") .. "$"
814 end 887 end
815 888
889 local function GetPlayerExtraData(data, index)
890
891 local unitId = "raid" .. index
892
893 local guid = UnitGUID(unitId)
894 if guid == nil then
895 return nil
896 end
897
898 local fields = {}
899
900 local buffs = {}
901 for i=1,40 do
902 local _,_,_,count,_,_,_,_,_,_,spellId = UnitAura(unitId, i, "HELPFUL")
903 table.insert(buffs, spellId)
904 end
905 if #buffs == 0 then
906 table.insert(fields, "_")
907 else
908 table.insert(fields, toCompressedNumberList(buffs))
909 end
910
911 local petGuid = UnitGUID("raidpet" .. index)
912 if petGuid then
913 table.insert(fields, guid .. "," .. petGuid)
914 else
915 table.insert(fields, '_')
916 end
917
918 local name = GetRaidRosterInfo(index)
919 local realm = GetRealmName()
920 local splitPos = string.find(name, "-")
921 if splitPos ~= nil then
922 realm = string.sub(name, splitPos + 1)
923 name = string.sub(name, 1, splitPos - 1)
924 end
925
926 data[realm .. ":" .. name] = table.concat(fields, ";")
927 end
928
929 function AskMrRobot.ExportLoggingData(timestamp)
930
931 local isLogging = AskMrRobot_ReforgeFrame.combatLogTab:IsLogging()
932 if not isLogging then
933 return
934 end
935
936 -- we only get extra information for people if in a raid
937 if not IsInRaid() then
938 return
939 end
940
941 local data = {}
942 for i = 1,40 do
943 GetPlayerExtraData(data, i)
944 end
945
946 AskMrRobot.CombatLogTab.SaveExtras(data, timestamp)
947 end
948
816 function AskMrRobot.ExportToAddonChat(timestamp) 949 function AskMrRobot.ExportToAddonChat(timestamp)
817 local data = AskMrRobot.ExportToCompressedString(false) 950 local msg = AskMrRobot.ExportToCompressedString(false)
818 local msgPrefix = timestamp .. "\n" .. AmrRealmName .. "\n" .. AmrCharacterName .. "\n" 951 local msgPrefix = timestamp .. "\n" .. AmrRealmName .. "\n" .. AmrCharacterName .. "\n"
819 952
820 -- break the data into 250 character chunks (to deal with the short limit on addon message size) 953 -- break the data into 250 character chunks (to deal with the short limit on addon message size)
821 local chunks = {} 954 local chunks = {}
822 local i = 1 955 local i = 1
823 local length = string.len(data) 956 local length = string.len(msg)
824 local chunkLen = 249 - string.len(msgPrefix) 957 local chunkLen = 249 - string.len(msgPrefix)
825 while (i <= length) do 958 while (i <= length) do
826 local endpos = math.min(i + chunkLen, length) 959 local endpos = math.min(i + chunkLen, length)
827 table.insert(chunks, msgPrefix .. string.sub(data, i, endpos)) 960 table.insert(chunks, msgPrefix .. string.sub(msg, i, endpos))
828 i = endpos + 1 961 i = endpos + 1
829 end 962 end
830 963
831 for i, v in ipairs(chunks) do 964 for i, v in ipairs(chunks) do
832 SendAddonMessage(AskMrRobot.ChatPrefix, v, "RAID") 965 SendAddonMessage(AskMrRobot.ChatPrefix, v, "RAID")