/FrameXML/ChatFrame.lua

http://github.com/tekkub/wow-ui-source · Lua · 4851 lines · 4492 code · 280 blank · 79 comment · 789 complexity · 4f79ea23a3e48194a24c3afba9adeb72 MD5 · raw file

  1. MESSAGE_SCROLLBUTTON_INITIAL_DELAY = 0;
  2. MESSAGE_SCROLLBUTTON_SCROLL_DELAY = 0.05;
  3. CHAT_BUTTON_FLASH_TIME = 0.5;
  4. CHAT_TELL_ALERT_TIME = 300;
  5. NUM_CHAT_WINDOWS = 10;
  6. DEFAULT_CHAT_FRAME = ChatFrame1;
  7. NUM_REMEMBERED_TELLS = 10;
  8. MAX_WOW_CHAT_CHANNELS = 10;
  9. CHAT_TIMESTAMP_FORMAT = nil; -- gets set from Interface Options
  10. CHAT_SHOW_IME = false;
  11. MAX_CHARACTER_NAME_BYTES = 305;
  12. --DEBUG FIXME FOR TESTING
  13. CHAT_OPTIONS = {
  14. ONE_EDIT_AT_A_TIME = "old"
  15. };
  16. -- Table for event indexed chatFilters.
  17. -- Format ["CHAT_MSG_SYSTEM"] = { function1, function2, function3 }
  18. -- filter, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 = function1 (self, event, ...) if filter then return true end return false, ... end
  19. local chatFilters = {};
  20. -- These hash tables are to improve performance of common lookups
  21. -- if you change what these tables point to (ie slash command, emote, chat)
  22. -- then you need to invalidate the entry in the hash table
  23. local hash_SecureCmdList = {}
  24. --Note: These need to remain global for AddOns
  25. hash_SlashCmdList = {} --[localizedCommand] -> function
  26. hash_EmoteTokenList = {}
  27. hash_ChatTypeInfoList = {} --[localizedCommand] -> identifier (Stores all slash commands)
  28. ChatTypeInfo = { };
  29. ChatTypeInfo["SYSTEM"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  30. ChatTypeInfo["SAY"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  31. ChatTypeInfo["PARTY"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  32. ChatTypeInfo["RAID"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  33. ChatTypeInfo["GUILD"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  34. ChatTypeInfo["OFFICER"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  35. ChatTypeInfo["YELL"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  36. ChatTypeInfo["WHISPER"] = { sticky = 1, flashTab = true, flashTabOnGeneral = true };
  37. ChatTypeInfo["SMART_WHISPER"] = ChatTypeInfo["WHISPER"];
  38. ChatTypeInfo["WHISPER_INFORM"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  39. ChatTypeInfo["REPLY"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  40. ChatTypeInfo["EMOTE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  41. ChatTypeInfo["TEXT_EMOTE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  42. ChatTypeInfo["MONSTER_SAY"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  43. ChatTypeInfo["MONSTER_PARTY"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  44. ChatTypeInfo["MONSTER_YELL"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  45. ChatTypeInfo["MONSTER_WHISPER"] = { sticky = 0, flashTab = true, flashTabOnGeneral = true };
  46. ChatTypeInfo["MONSTER_EMOTE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  47. ChatTypeInfo["CHANNEL"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  48. ChatTypeInfo["CHANNEL_JOIN"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  49. ChatTypeInfo["CHANNEL_LEAVE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  50. ChatTypeInfo["CHANNEL_LIST"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  51. ChatTypeInfo["CHANNEL_NOTICE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  52. ChatTypeInfo["CHANNEL_NOTICE_USER"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  53. ChatTypeInfo["TARGETICONS"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  54. ChatTypeInfo["AFK"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  55. ChatTypeInfo["DND"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  56. ChatTypeInfo["IGNORED"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  57. ChatTypeInfo["SKILL"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  58. ChatTypeInfo["LOOT"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  59. ChatTypeInfo["CURRENCY"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  60. ChatTypeInfo["MONEY"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  61. ChatTypeInfo["OPENING"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  62. ChatTypeInfo["TRADESKILLS"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  63. ChatTypeInfo["PET_INFO"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  64. ChatTypeInfo["COMBAT_MISC_INFO"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  65. ChatTypeInfo["COMBAT_XP_GAIN"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  66. ChatTypeInfo["COMBAT_HONOR_GAIN"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  67. ChatTypeInfo["COMBAT_FACTION_CHANGE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  68. ChatTypeInfo["BG_SYSTEM_NEUTRAL"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  69. ChatTypeInfo["BG_SYSTEM_ALLIANCE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  70. ChatTypeInfo["BG_SYSTEM_HORDE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  71. ChatTypeInfo["RAID_LEADER"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  72. ChatTypeInfo["RAID_WARNING"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  73. ChatTypeInfo["RAID_BOSS_WHISPER"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  74. ChatTypeInfo["RAID_BOSS_EMOTE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  75. ChatTypeInfo["QUEST_BOSS_EMOTE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  76. ChatTypeInfo["FILTERED"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  77. ChatTypeInfo["INSTANCE_CHAT"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  78. ChatTypeInfo["INSTANCE_CHAT_LEADER"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  79. ChatTypeInfo["RESTRICTED"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  80. ChatTypeInfo["CHANNEL1"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  81. ChatTypeInfo["CHANNEL2"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  82. ChatTypeInfo["CHANNEL3"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  83. ChatTypeInfo["CHANNEL4"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  84. ChatTypeInfo["CHANNEL5"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  85. ChatTypeInfo["CHANNEL6"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  86. ChatTypeInfo["CHANNEL7"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  87. ChatTypeInfo["CHANNEL8"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  88. ChatTypeInfo["CHANNEL9"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  89. ChatTypeInfo["CHANNEL10"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
  90. ChatTypeInfo["ACHIEVEMENT"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  91. ChatTypeInfo["GUILD_ACHIEVEMENT"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  92. ChatTypeInfo["PARTY_LEADER"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  93. ChatTypeInfo["BN_WHISPER"] = { sticky = 1, flashTab = true, flashTabOnGeneral = true };
  94. ChatTypeInfo["BN_WHISPER_INFORM"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  95. ChatTypeInfo["BN_ALERT"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  96. ChatTypeInfo["BN_BROADCAST"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  97. ChatTypeInfo["BN_BROADCAST_INFORM"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  98. ChatTypeInfo["BN_INLINE_TOAST_ALERT"] = { sticky = 0, flashTab = true, flashTabOnGeneral = false };
  99. ChatTypeInfo["BN_INLINE_TOAST_BROADCAST"] = { sticky = 0, flashTab = true, flashTabOnGeneral = false };
  100. ChatTypeInfo["BN_INLINE_TOAST_BROADCAST_INFORM"] = { sticky = 0, flashTab = true, flashTabOnGeneral = false };
  101. ChatTypeInfo["BN_WHISPER_PLAYER_OFFLINE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  102. ChatTypeInfo["COMBAT_GUILD_XP_GAIN"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  103. ChatTypeInfo["PET_BATTLE_COMBAT_LOG"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  104. ChatTypeInfo["PET_BATTLE_INFO"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
  105. ChatTypeInfo["GUILD_ITEM_LOOTED"] = ChatTypeInfo["GUILD_ACHIEVEMENT"];
  106. --NEW_CHAT_TYPE -Add the info here.
  107. ChatTypeGroup = {};
  108. ChatTypeGroup["SYSTEM"] = {
  109. "CHAT_MSG_SYSTEM",
  110. "TIME_PLAYED_MSG",
  111. "PLAYER_LEVEL_UP",
  112. "UNIT_LEVEL",
  113. "CHARACTER_POINTS_CHANGED",
  114. "CHAT_MSG_BN_WHISPER_PLAYER_OFFLINE",
  115. "QUEST_TURNED_IN",
  116. };
  117. ChatTypeGroup["SAY"] = {
  118. "CHAT_MSG_SAY",
  119. };
  120. ChatTypeGroup["EMOTE"] = {
  121. "CHAT_MSG_EMOTE",
  122. "CHAT_MSG_TEXT_EMOTE",
  123. };
  124. ChatTypeGroup["YELL"] = {
  125. "CHAT_MSG_YELL",
  126. };
  127. ChatTypeGroup["WHISPER"] = {
  128. "CHAT_MSG_WHISPER",
  129. "CHAT_MSG_WHISPER_INFORM",
  130. "CHAT_MSG_AFK",
  131. "CHAT_MSG_DND",
  132. };
  133. ChatTypeGroup["PARTY"] = {
  134. "CHAT_MSG_PARTY",
  135. "CHAT_MSG_MONSTER_PARTY",
  136. };
  137. ChatTypeGroup["PARTY_LEADER"] = {
  138. "CHAT_MSG_PARTY_LEADER",
  139. };
  140. ChatTypeGroup["RAID"] = {
  141. "CHAT_MSG_RAID",
  142. };
  143. ChatTypeGroup["RAID_LEADER"] = {
  144. "CHAT_MSG_RAID_LEADER",
  145. };
  146. ChatTypeGroup["RAID_WARNING"] = {
  147. "CHAT_MSG_RAID_WARNING",
  148. };
  149. ChatTypeGroup["INSTANCE_CHAT"] = {
  150. "CHAT_MSG_INSTANCE_CHAT",
  151. };
  152. ChatTypeGroup["INSTANCE_CHAT_LEADER"] = {
  153. "CHAT_MSG_INSTANCE_CHAT_LEADER",
  154. };
  155. ChatTypeGroup["GUILD"] = {
  156. "CHAT_MSG_GUILD",
  157. "GUILD_MOTD",
  158. };
  159. ChatTypeGroup["OFFICER"] = {
  160. "CHAT_MSG_OFFICER",
  161. };
  162. ChatTypeGroup["MONSTER_SAY"] = {
  163. "CHAT_MSG_MONSTER_SAY",
  164. };
  165. ChatTypeGroup["MONSTER_YELL"] = {
  166. "CHAT_MSG_MONSTER_YELL",
  167. };
  168. ChatTypeGroup["MONSTER_EMOTE"] = {
  169. "CHAT_MSG_MONSTER_EMOTE",
  170. };
  171. ChatTypeGroup["MONSTER_WHISPER"] = {
  172. "CHAT_MSG_MONSTER_WHISPER",
  173. };
  174. ChatTypeGroup["MONSTER_BOSS_EMOTE"] = {
  175. "CHAT_MSG_RAID_BOSS_EMOTE",
  176. };
  177. ChatTypeGroup["MONSTER_BOSS_WHISPER"] = {
  178. "CHAT_MSG_RAID_BOSS_WHISPER",
  179. };
  180. ChatTypeGroup["ERRORS"] = {
  181. "CHAT_MSG_RESTRICTED",
  182. "CHAT_MSG_FILTERED",
  183. };
  184. ChatTypeGroup["AFK"] = {
  185. "CHAT_MSG_AFK",
  186. };
  187. ChatTypeGroup["DND"] = {
  188. "CHAT_MSG_DND",
  189. };
  190. ChatTypeGroup["IGNORED"] = {
  191. "CHAT_MSG_IGNORED",
  192. };
  193. ChatTypeGroup["BG_HORDE"] = {
  194. "CHAT_MSG_BG_SYSTEM_HORDE",
  195. };
  196. ChatTypeGroup["BG_ALLIANCE"] = {
  197. "CHAT_MSG_BG_SYSTEM_ALLIANCE",
  198. };
  199. ChatTypeGroup["BG_NEUTRAL"] = {
  200. "CHAT_MSG_BG_SYSTEM_NEUTRAL",
  201. };
  202. ChatTypeGroup["COMBAT_XP_GAIN"] = {
  203. "CHAT_MSG_COMBAT_XP_GAIN";
  204. }
  205. ChatTypeGroup["COMBAT_HONOR_GAIN"] = {
  206. "CHAT_MSG_COMBAT_HONOR_GAIN";
  207. }
  208. ChatTypeGroup["COMBAT_FACTION_CHANGE"] = {
  209. "CHAT_MSG_COMBAT_FACTION_CHANGE";
  210. };
  211. ChatTypeGroup["SKILL"] = {
  212. "CHAT_MSG_SKILL",
  213. };
  214. ChatTypeGroup["LOOT"] = {
  215. "CHAT_MSG_LOOT",
  216. };
  217. ChatTypeGroup["CURRENCY"] = {
  218. "CHAT_MSG_CURRENCY",
  219. };
  220. ChatTypeGroup["MONEY"] = {
  221. "CHAT_MSG_MONEY",
  222. };
  223. ChatTypeGroup["OPENING"] = {
  224. "CHAT_MSG_OPENING";
  225. };
  226. ChatTypeGroup["TRADESKILLS"] = {
  227. "CHAT_MSG_TRADESKILLS";
  228. };
  229. ChatTypeGroup["PET_INFO"] = {
  230. "CHAT_MSG_PET_INFO";
  231. };
  232. ChatTypeGroup["COMBAT_MISC_INFO"] = {
  233. "CHAT_MSG_COMBAT_MISC_INFO";
  234. };
  235. ChatTypeGroup["ACHIEVEMENT"] = {
  236. "CHAT_MSG_ACHIEVEMENT";
  237. };
  238. ChatTypeGroup["GUILD_ACHIEVEMENT"] = {
  239. "CHAT_MSG_GUILD_ACHIEVEMENT",
  240. "CHAT_MSG_GUILD_ITEM_LOOTED",
  241. };
  242. ChatTypeGroup["CHANNEL"] = {
  243. "CHAT_MSG_CHANNEL_JOIN",
  244. "CHAT_MSG_CHANNEL_LEAVE",
  245. "CHAT_MSG_CHANNEL_NOTICE",
  246. "CHAT_MSG_CHANNEL_NOTICE_USER",
  247. "CHAT_MSG_CHANNEL_LIST",
  248. };
  249. ChatTypeGroup["TARGETICONS"] = {
  250. "CHAT_MSG_TARGETICONS"
  251. };
  252. ChatTypeGroup["BN_WHISPER"] = {
  253. "CHAT_MSG_BN_WHISPER",
  254. "CHAT_MSG_BN_WHISPER_INFORM",
  255. };
  256. ChatTypeGroup["BN_INLINE_TOAST_ALERT"] = {
  257. "CHAT_MSG_BN_INLINE_TOAST_ALERT",
  258. "CHAT_MSG_BN_INLINE_TOAST_BROADCAST",
  259. "CHAT_MSG_BN_INLINE_TOAST_BROADCAST_INFORM",
  260. };
  261. ChatTypeGroup["COMBAT_GUILD_XP_GAIN"] = {
  262. "CHAT_MSG_COMBAT_GUILD_XP_GAIN",
  263. };
  264. ChatTypeGroup["PET_BATTLE_COMBAT_LOG"] = {
  265. "CHAT_MSG_PET_BATTLE_COMBAT_LOG",
  266. };
  267. ChatTypeGroup["PET_BATTLE_INFO"] = {
  268. "CHAT_MSG_PET_BATTLE_INFO",
  269. };
  270. --NEW_CHAT_TYPE - Add the chat type above.
  271. ChatTypeGroupInverted = {};
  272. for group, values in pairs(ChatTypeGroup) do
  273. for _, value in pairs(values) do
  274. ChatTypeGroupInverted[value] = group;
  275. end
  276. end
  277. CHAT_CATEGORY_LIST = {
  278. PARTY = { "PARTY_LEADER", "PARTY_GUIDE", "MONSTER_PARTY" },
  279. RAID = { "RAID_LEADER", "RAID_WARNING" },
  280. GUILD = { "GUILD_ACHIEVEMENT", "GUILD_ITEM_LOOTED" },
  281. WHISPER = { "WHISPER_INFORM", "AFK", "DND" },
  282. CHANNEL = { "CHANNEL_JOIN", "CHANNEL_LEAVE", "CHANNEL_NOTICE", "CHANNEL_USER" },
  283. INSTANCE_CHAT = { "INSTANCE_CHAT_LEADER" },
  284. BN_WHISPER = { "BN_WHISPER_INFORM" },
  285. };
  286. CHAT_INVERTED_CATEGORY_LIST = {};
  287. for category, sublist in pairs(CHAT_CATEGORY_LIST) do
  288. for _, item in pairs(sublist) do
  289. CHAT_INVERTED_CATEGORY_LIST[item] = category;
  290. end
  291. end
  292. function Chat_GetChatCategory(chatType)
  293. return CHAT_INVERTED_CATEGORY_LIST[chatType] or chatType;
  294. end
  295. -- list of text emotes that we want to show on the Emote submenu (these have anims)
  296. EmoteList = {
  297. "WAVE",
  298. "BOW",
  299. "DANCE",
  300. "APPLAUD",
  301. "BEG",
  302. "CHICKEN",
  303. "CRY",
  304. "EAT",
  305. "FLEX",
  306. "KISS",
  307. "LAUGH",
  308. "POINT",
  309. "ROAR",
  310. "RUDE",
  311. "SALUTE",
  312. "SHY",
  313. "TALK",
  314. "STAND",
  315. "SIT",
  316. "SLEEP",
  317. "KNEEL",
  318. };
  319. -- list of text emotes that we want to show on the Speech submenu (these have sounds)
  320. TextEmoteSpeechList = {
  321. "HELPME",
  322. "INCOMING",
  323. "CHARGE",
  324. "FLEE",
  325. "ATTACKMYTARGET",
  326. "OOM",
  327. "FOLLOW",
  328. "WAIT",
  329. "HEALME",
  330. "CHEER",
  331. "OPENFIRE",
  332. "RASP",
  333. "HELLO",
  334. "BYE",
  335. "NOD",
  336. "NO",
  337. "THANK",
  338. "WELCOME",
  339. "CONGRATULATE",
  340. "FLIRT",
  341. "JOKE",
  342. "TRAIN",
  343. };
  344. -- These are text emote tokens - add new ones at the bottom of the list!
  345. EMOTE1_TOKEN = "AGREE";
  346. EMOTE2_TOKEN = "AMAZE";
  347. EMOTE3_TOKEN = "ANGRY";
  348. EMOTE4_TOKEN = "APOLOGIZE";
  349. EMOTE5_TOKEN = "APPLAUD";
  350. EMOTE6_TOKEN = "BASHFUL";
  351. EMOTE7_TOKEN = "BECKON";
  352. EMOTE8_TOKEN = "BEG";
  353. EMOTE9_TOKEN = "BITE";
  354. EMOTE10_TOKEN = "BLEED";
  355. EMOTE11_TOKEN = "BLINK";
  356. EMOTE12_TOKEN = "BLUSH";
  357. EMOTE13_TOKEN = "BONK";
  358. EMOTE14_TOKEN = "BORED";
  359. EMOTE15_TOKEN = "BOUNCE";
  360. EMOTE16_TOKEN = "BRB";
  361. EMOTE17_TOKEN = "BOW";
  362. EMOTE18_TOKEN = "BURP";
  363. EMOTE19_TOKEN = "BYE";
  364. EMOTE20_TOKEN = "CACKLE";
  365. EMOTE21_TOKEN = "CHEER";
  366. EMOTE22_TOKEN = "CHICKEN";
  367. EMOTE23_TOKEN = "CHUCKLE";
  368. EMOTE24_TOKEN = "CLAP";
  369. EMOTE25_TOKEN = "CONFUSED";
  370. EMOTE26_TOKEN = "CONGRATULATE";
  371. EMOTE27_TOKEN = "UNUSED";
  372. EMOTE28_TOKEN = "COUGH";
  373. EMOTE29_TOKEN = "COWER";
  374. EMOTE30_TOKEN = "CRACK";
  375. EMOTE31_TOKEN = "CRINGE";
  376. EMOTE32_TOKEN = "CRY";
  377. EMOTE33_TOKEN = "CURIOUS";
  378. EMOTE34_TOKEN = "CURTSEY";
  379. EMOTE35_TOKEN = "DANCE";
  380. EMOTE36_TOKEN = "DRINK";
  381. EMOTE37_TOKEN = "DROOL";
  382. EMOTE38_TOKEN = "EAT";
  383. EMOTE39_TOKEN = "EYE";
  384. EMOTE40_TOKEN = "FART";
  385. EMOTE41_TOKEN = "FIDGET";
  386. EMOTE42_TOKEN = "FLEX";
  387. EMOTE43_TOKEN = "FROWN";
  388. EMOTE44_TOKEN = "GASP";
  389. EMOTE45_TOKEN = "GAZE";
  390. EMOTE46_TOKEN = "GIGGLE";
  391. EMOTE47_TOKEN = "GLARE";
  392. EMOTE48_TOKEN = "GLOAT";
  393. EMOTE49_TOKEN = "GREET";
  394. EMOTE50_TOKEN = "GRIN";
  395. EMOTE51_TOKEN = "GROAN";
  396. EMOTE52_TOKEN = "GROVEL";
  397. EMOTE53_TOKEN = "GUFFAW";
  398. EMOTE54_TOKEN = "HAIL";
  399. EMOTE55_TOKEN = "HAPPY";
  400. EMOTE56_TOKEN = "HELLO";
  401. EMOTE57_TOKEN = "HUG";
  402. EMOTE58_TOKEN = "HUNGRY";
  403. EMOTE59_TOKEN = "KISS";
  404. EMOTE60_TOKEN = "KNEEL";
  405. EMOTE61_TOKEN = "LAUGH";
  406. EMOTE62_TOKEN = "LAYDOWN";
  407. EMOTE63_TOKEN = "MASSAGE";
  408. EMOTE64_TOKEN = "MOAN";
  409. EMOTE65_TOKEN = "MOON";
  410. EMOTE66_TOKEN = "MOURN";
  411. EMOTE67_TOKEN = "NO";
  412. EMOTE68_TOKEN = "NOD";
  413. EMOTE69_TOKEN = "NOSEPICK";
  414. EMOTE70_TOKEN = "PANIC";
  415. EMOTE71_TOKEN = "PEER";
  416. EMOTE72_TOKEN = "PLEAD";
  417. EMOTE73_TOKEN = "POINT";
  418. EMOTE74_TOKEN = "POKE";
  419. EMOTE75_TOKEN = "PRAY";
  420. EMOTE76_TOKEN = "ROAR";
  421. EMOTE77_TOKEN = "ROFL";
  422. EMOTE78_TOKEN = "RUDE";
  423. EMOTE79_TOKEN = "SALUTE";
  424. EMOTE80_TOKEN = "SCRATCH";
  425. EMOTE81_TOKEN = "SEXY";
  426. EMOTE82_TOKEN = "SHAKE";
  427. EMOTE83_TOKEN = "SHOUT";
  428. EMOTE84_TOKEN = "SHRUG";
  429. EMOTE85_TOKEN = "SHY";
  430. EMOTE86_TOKEN = "SIGH";
  431. EMOTE87_TOKEN = "SIT";
  432. EMOTE88_TOKEN = "SLEEP";
  433. EMOTE89_TOKEN = "SNARL";
  434. EMOTE90_TOKEN = "SPIT";
  435. EMOTE91_TOKEN = "STARE";
  436. EMOTE92_TOKEN = "SURPRISED";
  437. EMOTE93_TOKEN = "SURRENDER";
  438. EMOTE94_TOKEN = "TALK";
  439. EMOTE95_TOKEN = "TALKEX";
  440. EMOTE96_TOKEN = "TALKQ";
  441. EMOTE97_TOKEN = "TAP";
  442. EMOTE98_TOKEN = "THANK";
  443. EMOTE99_TOKEN = "THREATEN";
  444. EMOTE100_TOKEN = "TIRED";
  445. EMOTE101_TOKEN = "VICTORY";
  446. EMOTE102_TOKEN = "WAVE";
  447. EMOTE103_TOKEN = "WELCOME";
  448. EMOTE104_TOKEN = "WHINE";
  449. EMOTE105_TOKEN = "WHISTLE";
  450. EMOTE106_TOKEN = "WORK";
  451. EMOTE107_TOKEN = "YAWN";
  452. EMOTE108_TOKEN = "BOGGLE";
  453. EMOTE109_TOKEN = "CALM";
  454. EMOTE110_TOKEN = "COLD";
  455. EMOTE111_TOKEN = "COMFORT";
  456. EMOTE112_TOKEN = "CUDDLE";
  457. EMOTE113_TOKEN = "DUCK";
  458. EMOTE114_TOKEN = "INSULT";
  459. EMOTE115_TOKEN = "INTRODUCE";
  460. EMOTE116_TOKEN = "JK";
  461. EMOTE117_TOKEN = "LICK";
  462. EMOTE118_TOKEN = "LISTEN";
  463. EMOTE119_TOKEN = "LOST";
  464. EMOTE120_TOKEN = "MOCK";
  465. EMOTE121_TOKEN = "PONDER";
  466. EMOTE122_TOKEN = "POUNCE";
  467. EMOTE123_TOKEN = "PRAISE";
  468. EMOTE124_TOKEN = "PURR";
  469. EMOTE125_TOKEN = "PUZZLE";
  470. EMOTE126_TOKEN = "RAISE";
  471. EMOTE127_TOKEN = "READY";
  472. EMOTE128_TOKEN = "SHIMMY";
  473. EMOTE129_TOKEN = "SHIVER";
  474. EMOTE130_TOKEN = "SHOO";
  475. EMOTE131_TOKEN = "SLAP";
  476. EMOTE132_TOKEN = "SMIRK";
  477. EMOTE133_TOKEN = "SNIFF";
  478. EMOTE134_TOKEN = "SNUB";
  479. EMOTE135_TOKEN = "SOOTHE";
  480. EMOTE136_TOKEN = "STINK";
  481. EMOTE137_TOKEN = "TAUNT";
  482. EMOTE138_TOKEN = "TEASE";
  483. EMOTE139_TOKEN = "THIRSTY";
  484. EMOTE140_TOKEN = "VETO";
  485. EMOTE141_TOKEN = "SNICKER";
  486. EMOTE142_TOKEN = "TICKLE";
  487. EMOTE143_TOKEN = "STAND";
  488. EMOTE144_TOKEN = "VIOLIN";
  489. EMOTE145_TOKEN = "SMILE";
  490. EMOTE146_TOKEN = "RASP";
  491. EMOTE147_TOKEN = "GROWL";
  492. EMOTE148_TOKEN = "BARK";
  493. EMOTE149_TOKEN = "PITY";
  494. EMOTE150_TOKEN = "SCARED";
  495. EMOTE151_TOKEN = "FLOP";
  496. EMOTE152_TOKEN = "LOVE";
  497. EMOTE153_TOKEN = "MOO";
  498. EMOTE154_TOKEN = "COMMEND";
  499. EMOTE155_TOKEN = "TRAIN";
  500. EMOTE156_TOKEN = "HELPME";
  501. EMOTE157_TOKEN = "INCOMING";
  502. EMOTE158_TOKEN = "OPENFIRE";
  503. EMOTE159_TOKEN = "CHARGE";
  504. EMOTE160_TOKEN = "FLEE";
  505. EMOTE161_TOKEN = "ATTACKMYTARGET";
  506. EMOTE162_TOKEN = "OOM";
  507. EMOTE163_TOKEN = "FOLLOW";
  508. EMOTE164_TOKEN = "WAIT";
  509. EMOTE165_TOKEN = "FLIRT";
  510. EMOTE166_TOKEN = "HEALME";
  511. EMOTE167_TOKEN = "JOKE";
  512. EMOTE168_TOKEN = "WINK";
  513. EMOTE169_TOKEN = "PAT";
  514. EMOTE170_TOKEN = "GOLFCLAP";
  515. EMOTE171_TOKEN = "MOUNTSPECIAL";
  516. EMOTE304_TOKEN = "INCOMING";
  517. EMOTE306_TOKEN = "FLEE";
  518. EMOTE368_TOKEN = "BLAME"
  519. EMOTE369_TOKEN = "BLANK"
  520. EMOTE370_TOKEN = "BRANDISH"
  521. EMOTE371_TOKEN = "BREATH"
  522. EMOTE372_TOKEN = "DISAGREE"
  523. EMOTE373_TOKEN = "DOUBT"
  524. EMOTE374_TOKEN = "EMBARRASS"
  525. EMOTE375_TOKEN = "ENCOURAGE"
  526. EMOTE376_TOKEN = "ENEMY"
  527. EMOTE377_TOKEN = "EYEBROW"
  528. EMOTE380_TOKEN = "HIGHFIVE"
  529. EMOTE381_TOKEN = "ABSENT"
  530. EMOTE382_TOKEN = "ARM"
  531. EMOTE383_TOKEN = "AWE"
  532. EMOTE384_TOKEN = "BACKPACK"
  533. EMOTE385_TOKEN = "BADFEELING"
  534. EMOTE386_TOKEN = "CHALLENGE"
  535. EMOTE387_TOKEN = "CHUG"
  536. EMOTE389_TOKEN = "DING"
  537. EMOTE390_TOKEN = "FACEPALM"
  538. EMOTE391_TOKEN = "FAINT"
  539. EMOTE392_TOKEN = "GO"
  540. EMOTE393_TOKEN = "GOING"
  541. EMOTE394_TOKEN = "GLOWER"
  542. EMOTE395_TOKEN = "HEADACHE"
  543. EMOTE396_TOKEN = "HICCUP"
  544. EMOTE398_TOKEN = "HISS"
  545. EMOTE399_TOKEN = "HOLDHAND"
  546. EMOTE401_TOKEN = "HURRY"
  547. EMOTE402_TOKEN = "IDEA"
  548. EMOTE403_TOKEN = "JEALOUS"
  549. EMOTE404_TOKEN = "LUCK"
  550. EMOTE405_TOKEN = "MAP"
  551. EMOTE406_TOKEN = "MERCY"
  552. EMOTE407_TOKEN = "MUTTER"
  553. EMOTE408_TOKEN = "NERVOUS"
  554. EMOTE409_TOKEN = "OFFER"
  555. EMOTE410_TOKEN = "PET"
  556. EMOTE411_TOKEN = "PINCH"
  557. EMOTE413_TOKEN = "PROUD"
  558. EMOTE414_TOKEN = "PROMISE"
  559. EMOTE415_TOKEN = "PULSE"
  560. EMOTE416_TOKEN = "PUNCH"
  561. EMOTE417_TOKEN = "POUT"
  562. EMOTE418_TOKEN = "REGRET"
  563. EMOTE420_TOKEN = "REVENGE"
  564. EMOTE421_TOKEN = "ROLLEYES"
  565. EMOTE422_TOKEN = "RUFFLE"
  566. EMOTE423_TOKEN = "SAD"
  567. EMOTE424_TOKEN = "SCOFF"
  568. EMOTE425_TOKEN = "SCOLD"
  569. EMOTE426_TOKEN = "SCOWL"
  570. EMOTE427_TOKEN = "SEARCH"
  571. EMOTE428_TOKEN = "SHAKEFIST"
  572. EMOTE429_TOKEN = "SHIFTY"
  573. EMOTE430_TOKEN = "SHUDDER"
  574. EMOTE431_TOKEN = "SIGNAL"
  575. EMOTE432_TOKEN = "SILENCE"
  576. EMOTE433_TOKEN = "SING"
  577. EMOTE434_TOKEN = "SMACK"
  578. EMOTE435_TOKEN = "SNEAK"
  579. EMOTE436_TOKEN = "SNEEZE"
  580. EMOTE437_TOKEN = "SNORT"
  581. EMOTE438_TOKEN = "SQUEAL"
  582. EMOTE440_TOKEN = "SUSPICIOUS"
  583. EMOTE441_TOKEN = "THINK"
  584. EMOTE442_TOKEN = "TRUCE"
  585. EMOTE443_TOKEN = "TWIDDLE"
  586. EMOTE444_TOKEN = "WARN"
  587. EMOTE445_TOKEN = "SNAP"
  588. EMOTE446_TOKEN = "CHARM"
  589. EMOTE447_TOKEN = "COVEREARS"
  590. EMOTE448_TOKEN = "CROSSARMS"
  591. EMOTE449_TOKEN = "LOOK"
  592. EMOTE450_TOKEN = "OBJECT"
  593. EMOTE451_TOKEN = "SWEAT"
  594. EMOTE452_TOKEN = "YW"
  595. EMOTE453_TOKEN = "READ"
  596. EMOTE454_TOKEN = "FORTHEALLIANCE"
  597. EMOTE455_TOKEN = "FORTHEHORDE"
  598. EMOTE517_TOKEN = "WHOA"
  599. EMOTE518_TOKEN = "OOPS"
  600. -- NOTE: This indices used to iterate the tokens may not be contiguous, keep that in mind when updating this value.
  601. local MAXEMOTEINDEX = 518;
  602. ICON_LIST = {
  603. "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1:",
  604. "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_2:",
  605. "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_3:",
  606. "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_4:",
  607. "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_5:",
  608. "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_6:",
  609. "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_7:",
  610. "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_8:",
  611. }
  612. --Links tags from Global Strings to indicies for entries in ICON_LIST. This way addons can easily replace icons
  613. ICON_TAG_LIST =
  614. {
  615. [strlower(ICON_TAG_RAID_TARGET_STAR1)] = 1,
  616. [strlower(ICON_TAG_RAID_TARGET_STAR2)] = 1,
  617. [strlower(ICON_TAG_RAID_TARGET_CIRCLE1)] = 2,
  618. [strlower(ICON_TAG_RAID_TARGET_CIRCLE2)] = 2,
  619. [strlower(ICON_TAG_RAID_TARGET_DIAMOND1)] = 3,
  620. [strlower(ICON_TAG_RAID_TARGET_DIAMOND2)] = 3,
  621. [strlower(ICON_TAG_RAID_TARGET_TRIANGLE1)] = 4,
  622. [strlower(ICON_TAG_RAID_TARGET_TRIANGLE2)] = 4,
  623. [strlower(ICON_TAG_RAID_TARGET_MOON1)] = 5,
  624. [strlower(ICON_TAG_RAID_TARGET_MOON2)] = 5,
  625. [strlower(ICON_TAG_RAID_TARGET_SQUARE1)] = 6,
  626. [strlower(ICON_TAG_RAID_TARGET_SQUARE2)] = 6,
  627. [strlower(ICON_TAG_RAID_TARGET_CROSS1)] = 7,
  628. [strlower(ICON_TAG_RAID_TARGET_CROSS2)] = 7,
  629. [strlower(ICON_TAG_RAID_TARGET_SKULL1)] = 8,
  630. [strlower(ICON_TAG_RAID_TARGET_SKULL2)] = 8,
  631. [strlower(RAID_TARGET_1)] = 1,
  632. [strlower(RAID_TARGET_2)] = 2,
  633. [strlower(RAID_TARGET_3)] = 3,
  634. [strlower(RAID_TARGET_4)] = 4,
  635. [strlower(RAID_TARGET_5)] = 5,
  636. [strlower(RAID_TARGET_6)] = 6,
  637. [strlower(RAID_TARGET_7)] = 7,
  638. [strlower(RAID_TARGET_8)] = 8,
  639. }
  640. GROUP_TAG_LIST =
  641. {
  642. [strlower(GROUP1_CHAT_TAG1)] = 1,
  643. [strlower(GROUP1_CHAT_TAG2)] = 1,
  644. [strlower(GROUP2_CHAT_TAG1)] = 2,
  645. [strlower(GROUP2_CHAT_TAG2)] = 2,
  646. [strlower(GROUP3_CHAT_TAG1)] = 3,
  647. [strlower(GROUP3_CHAT_TAG2)] = 3,
  648. [strlower(GROUP4_CHAT_TAG1)] = 4,
  649. [strlower(GROUP4_CHAT_TAG2)] = 4,
  650. [strlower(GROUP5_CHAT_TAG1)] = 5,
  651. [strlower(GROUP5_CHAT_TAG2)] = 5,
  652. [strlower(GROUP6_CHAT_TAG1)] = 6,
  653. [strlower(GROUP6_CHAT_TAG2)] = 6,
  654. [strlower(GROUP7_CHAT_TAG1)] = 7,
  655. [strlower(GROUP7_CHAT_TAG2)] = 7,
  656. [strlower(GROUP8_CHAT_TAG1)] = 8,
  657. [strlower(GROUP8_CHAT_TAG2)] = 8,
  658. --Language independent:
  659. ["g1"] = 1;
  660. ["g2"] = 2;
  661. ["g3"] = 3;
  662. ["g4"] = 4;
  663. ["g5"] = 5;
  664. ["g6"] = 6;
  665. ["g7"] = 7;
  666. ["g8"] = 8;
  667. };
  668. GROUP_LANGUAGE_INDEPENDENT_STRINGS =
  669. {
  670. "g1",
  671. "g2",
  672. "g3",
  673. "g4",
  674. "g5",
  675. "g6",
  676. "g7",
  677. "g8",
  678. };
  679. --
  680. -- CastSequence support
  681. --
  682. local CastSequenceManager;
  683. local CastSequenceTable = {};
  684. local CastSequenceFreeList = {};
  685. local function CreateCanonicalActions(entry, ...)
  686. entry.spells = {};
  687. entry.spellNames = {};
  688. entry.items = {};
  689. local count = 0;
  690. for i=1, select("#", ...) do
  691. local action = strlower(strtrim((select(i, ...))));
  692. if ( action and action ~="" ) then
  693. count = count + 1;
  694. if ( GetItemInfo(action) or select(3, SecureCmdItemParse(action)) ) then
  695. entry.items[count] = action;
  696. entry.spells[count] = strlower(GetItemSpell(action) or "");
  697. entry.spellNames[count] = entry.spells[count];
  698. else
  699. entry.spells[count] = action;
  700. entry.spellNames[count] = gsub(action, "!*(.*)", "%1");
  701. end
  702. end
  703. end
  704. end
  705. local function SetCastSequenceIndex(entry, index)
  706. entry.index = index;
  707. entry.pending = nil;
  708. end
  709. local function ResetCastSequence(sequence, entry)
  710. SetCastSequenceIndex(entry, 1);
  711. CastSequenceFreeList[sequence] = entry;
  712. CastSequenceTable[sequence] = nil;
  713. end
  714. local function SetNextCastSequence(sequence, entry)
  715. if ( entry.index == #entry.spells ) then
  716. ResetCastSequence(sequence, entry);
  717. else
  718. SetCastSequenceIndex(entry, entry.index + 1);
  719. end
  720. end
  721. local function CastSequenceManager_OnEvent(self, event, ...)
  722. -- Reset all sequences when the player dies
  723. if ( event == "PLAYER_DEAD" ) then
  724. for sequence, entry in pairs(CastSequenceTable) do
  725. ResetCastSequence(sequence, entry);
  726. end
  727. return;
  728. end
  729. -- Increment sequences for spells which succeed.
  730. if ( event == "UNIT_SPELLCAST_SENT" or
  731. event == "UNIT_SPELLCAST_SUCCEEDED" or
  732. event == "UNIT_SPELLCAST_INTERRUPTED" or
  733. event == "UNIT_SPELLCAST_FAILED" or
  734. event == "UNIT_SPELLCAST_FAILED_QUIET" ) then
  735. local unit, name, rank, castID, _;
  736. if ( event == "UNIT_SPELLCAST_SENT" ) then
  737. unit, name, rank, _, castID = ...;
  738. else
  739. unit, name, rank, castID = ...;
  740. end
  741. if ( not name ) then
  742. -- This was a server-side only spell affecting the player somehow, don't do anything with cast sequencing, just bail.
  743. return;
  744. end
  745. if ( unit == "player" or unit == "pet" ) then
  746. name, rank = strlower(name), strlower(rank);
  747. local nameplus = name.."()";
  748. local fullname = name.."("..rank..")";
  749. for sequence, entry in pairs(CastSequenceTable) do
  750. local entryName = entry.spellNames[entry.index];
  751. if ( entryName == name or entryName == nameplus or entryName == fullname ) then
  752. if ( event == "UNIT_SPELLCAST_SENT" ) then
  753. entry.pending = castID;
  754. elseif ( entry.pending == castID ) then
  755. entry.pending = nil;
  756. if ( event == "UNIT_SPELLCAST_SUCCEEDED" ) then
  757. SetNextCastSequence(sequence, entry);
  758. end
  759. end
  760. end
  761. end
  762. end
  763. return;
  764. end
  765. -- Handle reset events
  766. local reset = "";
  767. if ( event == "PLAYER_TARGET_CHANGED" ) then
  768. reset = "target";
  769. elseif ( event == "PLAYER_REGEN_ENABLED" ) then
  770. reset = "combat";
  771. end
  772. for sequence, entry in pairs(CastSequenceTable) do
  773. if ( strfind(entry.reset, reset, 1, true) ) then
  774. ResetCastSequence(sequence, entry);
  775. end
  776. end
  777. end
  778. local function CastSequenceManager_OnUpdate(self, elapsed)
  779. elapsed = self.elapsed + elapsed;
  780. if ( elapsed < 1 ) then
  781. self.elapsed = elapsed;
  782. return;
  783. end
  784. for sequence, entry in pairs(CastSequenceTable) do
  785. if ( entry.timeout ) then
  786. if ( elapsed >= entry.timeout ) then
  787. ResetCastSequence(sequence, entry);
  788. else
  789. entry.timeout = entry.timeout - elapsed;
  790. end
  791. end
  792. end
  793. self.elapsed = 0;
  794. end
  795. local function ExecuteCastSequence(sequence, target)
  796. if ( not CastSequenceManager ) then
  797. CastSequenceManager = CreateFrame("Frame");
  798. CastSequenceManager.elapsed = 0;
  799. CastSequenceManager:RegisterEvent("PLAYER_DEAD");
  800. CastSequenceManager:RegisterEvent("UNIT_SPELLCAST_SENT");
  801. CastSequenceManager:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED");
  802. CastSequenceManager:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED");
  803. CastSequenceManager:RegisterEvent("UNIT_SPELLCAST_FAILED");
  804. CastSequenceManager:RegisterEvent("UNIT_SPELLCAST_FAILED_QUIET");
  805. CastSequenceManager:RegisterEvent("PLAYER_TARGET_CHANGED");
  806. CastSequenceManager:RegisterEvent("PLAYER_REGEN_ENABLED");
  807. CastSequenceManager:SetScript("OnEvent", CastSequenceManager_OnEvent);
  808. CastSequenceManager:SetScript("OnUpdate", CastSequenceManager_OnUpdate);
  809. end
  810. local entry = CastSequenceTable[sequence];
  811. if ( not entry ) then
  812. entry = CastSequenceFreeList[sequence];
  813. if ( not entry ) then
  814. local reset, spells = strmatch(sequence, "^reset=([^%s]+)%s*(.*)");
  815. if ( not reset ) then
  816. spells = sequence;
  817. end
  818. entry = {};
  819. CreateCanonicalActions(entry, strsplit(",", spells));
  820. entry.reset = strlower(reset or "");
  821. end
  822. CastSequenceTable[sequence] = entry;
  823. entry.index = 1;
  824. end
  825. -- Don't do anything if this entry is still pending
  826. if ( entry.pending ) then
  827. return;
  828. end
  829. -- See if modified click restarts the sequence
  830. if ( (IsShiftKeyDown() and strfind(entry.reset, "shift", 1, true)) or
  831. (IsControlKeyDown() and strfind(entry.reset, "ctrl", 1, true)) or
  832. (IsAltKeyDown() and strfind(entry.reset, "alt", 1, true)) ) then
  833. SetCastSequenceIndex(entry, 1);
  834. end
  835. -- Reset the timeout each time the sequence is used
  836. local timeout = strmatch(entry.reset, "(%d+)");
  837. if ( timeout ) then
  838. entry.timeout = CastSequenceManager.elapsed + tonumber(timeout);
  839. end
  840. -- Execute the sequence!
  841. local item, spell = entry.items[entry.index], entry.spells[entry.index];
  842. if ( item ) then
  843. local name, bag, slot = SecureCmdItemParse(item);
  844. if ( slot ) then
  845. if ( name ) then
  846. spell = strlower(GetItemSpell(name) or "");
  847. else
  848. spell = "";
  849. end
  850. entry.spellNames[entry.index] = spell;
  851. end
  852. if ( IsEquippableItem(name) and not IsEquippedItem(name) ) then
  853. EquipItemByName(name);
  854. else
  855. SecureCmdUseItem(name, bag, slot, target);
  856. end
  857. else
  858. CastSpellByName(spell, target);
  859. end
  860. end
  861. function QueryCastSequence(sequence)
  862. local index = 1;
  863. local item, spell;
  864. local entry = CastSequenceTable[sequence];
  865. if ( entry ) then
  866. if ( (IsShiftKeyDown() and strfind(entry.reset, "shift", 1, true)) or
  867. (IsControlKeyDown() and strfind(entry.reset, "ctrl", 1, true)) or
  868. (IsAltKeyDown() and strfind(entry.reset, "alt", 1, true)) ) then
  869. index = 1;
  870. else
  871. index = entry.index;
  872. end
  873. item, spell = entry.items[index], entry.spells[index];
  874. else
  875. entry = CastSequenceFreeList[sequence];
  876. if ( entry ) then
  877. item, spell = entry.items[index], entry.spells[index];
  878. else
  879. local reset, spells = strmatch(sequence, "^reset=([^%s]+)%s*(.*)");
  880. if ( not reset ) then
  881. spells = sequence;
  882. end
  883. local action = strlower(strtrim((strsplit(",", spells))));
  884. if ( GetItemInfo(action) or select(3, SecureCmdItemParse(action)) ) then
  885. item, spell = action, strlower(GetItemSpell(action) or "");
  886. else
  887. item, spell = nil, action;
  888. end
  889. end
  890. end
  891. if ( item ) then
  892. local name, bag, slot = SecureCmdItemParse(item);
  893. if ( slot ) then
  894. if ( name ) then
  895. spell = strlower(GetItemSpell(name) or "");
  896. else
  897. spell = "";
  898. end
  899. end
  900. end
  901. return index, item, spell;
  902. end
  903. local CastRandomManager;
  904. local CastRandomTable = {};
  905. local function CastRandomManager_OnEvent(self, event, ...)
  906. local unit, name, rank = ...;
  907. if ( not name ) then
  908. -- This was a server-side only spell affecting the player somehow, don't do anything with cast sequencing, just bail.
  909. return;
  910. end
  911. if ( unit == "player" ) then
  912. name, rank = strlower(name), strlower(rank);
  913. local nameplus = name.."()";
  914. local fullname = name.."("..rank..")";
  915. for sequence, entry in pairs(CastRandomTable) do
  916. if ( entry.pending and entry.value ) then
  917. local entryName = strlower(entry.value);
  918. if ( entryName == name or entryName == nameplus or entryName == fullname ) then
  919. entry.pending = nil;
  920. if ( event == "UNIT_SPELLCAST_SUCCEEDED" ) then
  921. entry.value = nil;
  922. end
  923. end
  924. end
  925. end
  926. end
  927. end
  928. local function ExecuteCastRandom(actions)
  929. if ( not CastRandomManager ) then
  930. CastRandomManager = CreateFrame("Frame");
  931. CastRandomManager:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED");
  932. CastRandomManager:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED");
  933. CastRandomManager:RegisterEvent("UNIT_SPELLCAST_FAILED");
  934. CastRandomManager:RegisterEvent("UNIT_SPELLCAST_FAILED_QUIET");
  935. CastRandomManager:SetScript("OnEvent", CastRandomManager_OnEvent);
  936. end
  937. local entry = CastRandomTable[actions];
  938. if ( not entry ) then
  939. entry = {};
  940. CreateCanonicalActions(entry, strsplit(",", actions));
  941. CastRandomTable[actions] = entry;
  942. end
  943. if ( not entry.value ) then
  944. entry.value = entry.spellNames[random(#entry.spellNames)];
  945. end
  946. entry.pending = true;
  947. return entry.value;
  948. end
  949. function GetRandomArgument(...)
  950. return (select(random(select("#", ...)), ...));
  951. end
  952. -- Slash commands that are protected from tampering
  953. local SecureCmdList = { };
  954. function IsSecureCmd(command)
  955. command = strupper(command);
  956. -- first check the hash table
  957. if ( hash_SecureCmdList[command] ) then
  958. return true;
  959. end
  960. for index, value in pairs(SecureCmdList) do
  961. local i = 1;
  962. local cmdString = _G["SLASH_"..index..i];
  963. while ( cmdString ) do
  964. cmdString = strupper(cmdString);
  965. if ( cmdString == command ) then
  966. return true;
  967. end
  968. i = i + 1;
  969. cmdString = _G["SLASH_"..index..i];
  970. end
  971. end
  972. end
  973. function SecureCmdItemParse(item)
  974. if ( not item ) then
  975. return nil, nil, nil;
  976. end
  977. local bag, slot = strmatch(item, "^(%d+)%s+(%d+)$");
  978. if ( not bag ) then
  979. slot = strmatch(item, "^(%d+)$");
  980. end
  981. if ( bag ) then
  982. item = GetContainerItemLink(bag, slot);
  983. elseif ( slot ) then
  984. item = GetInventoryItemLink("player", slot);
  985. end
  986. return item, bag, slot;
  987. end
  988. function SecureCmdUseItem(name, bag, slot, target)
  989. if ( bag ) then
  990. UseContainerItem(bag, slot, target);
  991. elseif ( slot ) then
  992. UseInventoryItem(slot, target);
  993. else
  994. UseItemByName(name, target);
  995. end
  996. end
  997. --These functions are terrible, but they support legacy slash commands.
  998. function ValueToBoolean(valueToCheck, defaultValue, defaultReturn)
  999. if ( type(valueToCheck) == "nil" ) then
  1000. return false;
  1001. elseif ( type(valueToCheck) == "boolean" ) then
  1002. return valueToCheck;
  1003. elseif ( type(valueToCheck) == "number" ) then
  1004. return valueToCheck ~= 0;
  1005. elseif ( type(valueToCheck) == "string" ) then
  1006. return StringToBoolean(valueToCheck, defaultReturn);
  1007. else
  1008. return defaultReturn;
  1009. end
  1010. end
  1011. function StringToBoolean(stringToCheck, defaultReturn)
  1012. stringToCheck = string.lower(stringToCheck);
  1013. local firstChar = string.sub(stringToCheck, 1, 1);
  1014. if ( firstChar == "0" or firstChar == "n" or firstChar == "f" or stringToCheck == "off" or stringToCheck == "disabled" ) then
  1015. return false;
  1016. elseif ( firstChar == "1" or firstChar == "2" or firstChar == "3" or firstChar == "4" or firstChar == "5" or
  1017. firstChar == "6" or firstChar == "7" or firstChar == "8" or firstChar == "9" or firstChar == "y" or
  1018. firstChar == "t" or stringToCheck == "on" or stringToCheck == "enabled" ) then
  1019. return true;
  1020. end
  1021. return defaultReturn;
  1022. end
  1023. SecureCmdList["STARTATTACK"] = function(msg)
  1024. local action, target = SecureCmdOptionParse(msg);
  1025. if ( action ) then
  1026. if ( not target or target == "target" ) then
  1027. target = action;
  1028. end
  1029. StartAttack(target);
  1030. end
  1031. end
  1032. SecureCmdList["STOPATTACK"] = function(msg)
  1033. if ( SecureCmdOptionParse(msg) ) then
  1034. StopAttack();
  1035. end
  1036. end
  1037. -- We want to prefer spells for /cast and items for /use but we can use either
  1038. SecureCmdList["CAST"] = function(msg)
  1039. local action, target = SecureCmdOptionParse(msg);
  1040. if ( action ) then
  1041. local spell = GetSpellInfo(action)
  1042. local name, bag, slot = SecureCmdItemParse(action);
  1043. if ( spell ) then
  1044. CastSpellByName(action, target);
  1045. elseif ( slot or GetItemInfo(name) ) then
  1046. SecureCmdUseItem(name, bag, slot, target);
  1047. end
  1048. end
  1049. end
  1050. SecureCmdList["USE"] = function(msg)
  1051. local action, target = SecureCmdOptionParse(msg);
  1052. if ( action ) then
  1053. local name, bag, slot = SecureCmdItemParse(action);
  1054. if ( slot or GetItemInfo(name) ) then
  1055. SecureCmdUseItem(name, bag, slot, target);
  1056. else
  1057. CastSpellByName(action, target);
  1058. end
  1059. end
  1060. end
  1061. SecureCmdList["CASTRANDOM"] = function(msg)
  1062. local actions, target = SecureCmdOptionParse(msg);
  1063. if ( actions ) then
  1064. local action = ExecuteCastRandom(actions);
  1065. local name, bag, slot = SecureCmdItemParse(action);
  1066. if ( slot or GetItemInfo(name) ) then
  1067. SecureCmdUseItem(name, bag, slot, target);
  1068. else
  1069. CastSpellByName(action, target);
  1070. end
  1071. end
  1072. end
  1073. SecureCmdList["USERANDOM"] = SecureCmdList["CASTRANDOM"];
  1074. SecureCmdList["CASTSEQUENCE"] = function(msg)
  1075. local sequence, target = SecureCmdOptionParse(msg);
  1076. if ( sequence and sequence ~= "" ) then
  1077. ExecuteCastSequence(sequence, target);
  1078. end
  1079. end
  1080. SecureCmdList["STOPCASTING"] = function(msg)
  1081. if ( SecureCmdOptionParse(msg) ) then
  1082. SpellStopCasting();
  1083. end
  1084. end
  1085. SecureCmdList["STOPSPELLTARGET"] = function(msg)
  1086. if ( SecureCmdOptionParse(msg) ) then
  1087. SpellStopTargeting();
  1088. end
  1089. end
  1090. SecureCmdList["CANCELAURA"] = function(msg)
  1091. local spell = SecureCmdOptionParse(msg);
  1092. if ( spell ) then
  1093. local name, rank = strmatch(spell, "([^(]+)[(]([^)]+)[)]");
  1094. if ( not name ) then
  1095. name = spell;
  1096. end
  1097. CancelUnitBuff("player", name, rank);
  1098. end
  1099. end
  1100. SecureCmdList["CANCELFORM"] = function(msg)
  1101. if ( SecureCmdOptionParse(msg) ) then
  1102. CancelShapeshiftForm();
  1103. end
  1104. end
  1105. SecureCmdList["EQUIP"] = function(msg)
  1106. local item = SecureCmdOptionParse(msg);
  1107. if ( item ) then
  1108. EquipItemByName((SecureCmdItemParse(item)));
  1109. end
  1110. end
  1111. SecureCmdList["EQUIP_TO_SLOT"] = function(msg)
  1112. local action = SecureCmdOptionParse(msg);
  1113. if ( action ) then
  1114. local slot, item = strmatch(action, "^(%d+)%s+(.*)");
  1115. if ( item ) then
  1116. if ( PaperDoll_IsEquippedSlot(slot) ) then
  1117. EquipItemByName(SecureCmdItemParse(item), slot);
  1118. else
  1119. -- user specified a bad slot number (slot that you can't equip an item to)
  1120. ChatFrame_DisplayUsageError(format(ERROR_SLASH_EQUIP_TO_SLOT, EQUIPPED_FIRST, EQUIPPED_LAST));
  1121. end
  1122. elseif ( slot ) then
  1123. -- user specified a slot but not an item
  1124. ChatFrame_DisplayUsageError(format(ERROR_SLASH_EQUIP_TO_SLOT, EQUIPPED_FIRST, EQUIPPED_LAST));
  1125. end
  1126. end
  1127. end
  1128. SecureCmdList["CHANGEACTIONBAR"] = function(msg)
  1129. local page = SecureCmdOptionParse(msg);
  1130. if ( page and page ~= "" ) then
  1131. page = tonumber(page);
  1132. if (page and page >= 1 and page <= NUM_ACTIONBAR_PAGES) then
  1133. ChangeActionBarPage(page);
  1134. else
  1135. ChatFrame_DisplayUsageError(format(ERROR_SLASH_CHANGEACTIONBAR, 1, NUM_ACTIONBAR_PAGES));
  1136. end
  1137. end
  1138. end
  1139. SecureCmdList["SWAPACTIONBAR"] = function(msg)
  1140. local action = SecureCmdOptionParse(msg);
  1141. if ( action ) then
  1142. local a, b = strmatch(action, "(%d+)%s+(%d+)");
  1143. if ( a and b ) then
  1144. a = tonumber(a);
  1145. b = tonumber(b);
  1146. if ( ( a and a >= 1 and a <= NUM_ACTIONBAR_PAGES ) and ( b and b >= 1 and b <= NUM_ACTIONBAR_PAGES ) ) then
  1147. if ( GetActionBarPage() == a ) then
  1148. ChangeActionBarPage(b);
  1149. else
  1150. ChangeActionBarPage(a);
  1151. end
  1152. else
  1153. ChatFrame_DisplayUsageError(format(ERROR_SLASH_SWAPACTIONBAR, 1, NUM_ACTIONBAR_PAGES));
  1154. end
  1155. end
  1156. end
  1157. end
  1158. SecureCmdList["TARGET"] = function(msg)
  1159. local action, target = SecureCmdOptionParse(msg);
  1160. if ( action ) then
  1161. if ( not target or target == "target" ) then
  1162. target = action;
  1163. end
  1164. TargetUnit(target);
  1165. end
  1166. end
  1167. SecureCmdList["TARGET_EXACT"] = function(msg)
  1168. local action, target = SecureCmdOptionParse(msg);
  1169. if ( action ) then
  1170. if ( not target or target == "target" ) then
  1171. target = action;
  1172. end
  1173. TargetUnit(target, true);
  1174. end
  1175. end
  1176. SecureCmdList["TARGET_NEAREST_ENEMY"] = function(msg)
  1177. local action = SecureCmdOptionParse(msg);
  1178. if ( action ) then
  1179. TargetNearestEnemy(ValueToBoolean(action, false));
  1180. end
  1181. end
  1182. SecureCmdList["TARGET_NEAREST_ENEMY_PLAYER"] = function(msg)
  1183. local action = SecureCmdOptionParse(msg);
  1184. if ( action ) then
  1185. TargetNearestEnemyPlayer(ValueToBoolean(action, false));
  1186. end
  1187. end
  1188. SecureCmdList["TARGET_NEAREST_FRIEND"] = function(msg)
  1189. local action = SecureCmdOptionParse(msg);
  1190. if ( action ) then
  1191. TargetNearestFriend(ValueToBoolean(action, false));
  1192. end
  1193. end
  1194. SecureCmdList["TARGET_NEAREST_FRIEND_PLAYER"] = function(msg)
  1195. local action = SecureCmdOptionParse(msg);
  1196. if ( action ) then
  1197. TargetNearestFriendPlayer(ValueToBoolean(action, false));
  1198. end
  1199. end
  1200. SecureCmdList["TARGET_NEAREST_PARTY"] = function(msg)
  1201. local action = SecureCmdOptionParse(msg);
  1202. if ( action ) then
  1203. TargetNearestPartyMember(ValueToBoolean(action, false));
  1204. end
  1205. end
  1206. SecureCmdList["TARGET_NEAREST_RAID"] = function(msg)
  1207. local action = SecureCmdOptionParse(msg);
  1208. if ( action ) then
  1209. TargetNearestRaidMember(ValueToBoolean(action, false));
  1210. end
  1211. end
  1212. SecureCmdList["CLEARTARGET"] = function(msg)
  1213. if ( SecureCmdOptionParse(msg) ) then
  1214. ClearTarget();
  1215. end
  1216. end
  1217. SecureCmdList["TARGET_LAST_TARGET"] = function(msg)
  1218. if ( SecureCmdOptionParse(msg) ) then
  1219. TargetLastTarget();
  1220. end
  1221. end
  1222. SecureCmdList["TARGET_LAST_ENEMY"] = function(msg)
  1223. local action = SecureCmdOptionParse(msg);
  1224. if ( action ) then
  1225. TargetLastEnemy(action);
  1226. end
  1227. end
  1228. SecureCmdList["TARGET_LAST_FRIEND"] = function(msg)
  1229. local action = SecureCmdOptionParse(msg);
  1230. if ( action ) then
  1231. TargetLastFriend(action);
  1232. end
  1233. end
  1234. SecureCmdList["ASSIST"] = function(msg)
  1235. if ( msg == "" ) then
  1236. AssistUnit();
  1237. else
  1238. local action, target = SecureCmdOptionParse(msg);
  1239. if ( action ) then
  1240. if ( not target ) then
  1241. target = action;
  1242. end
  1243. AssistUnit(target);
  1244. end
  1245. end
  1246. end
  1247. SecureCmdList["FOCUS"] = function(msg)
  1248. if ( msg == "" ) then
  1249. FocusUnit();
  1250. else
  1251. local action, target = SecureCmdOptionParse(msg);
  1252. if ( action ) then
  1253. if ( not target or target == "focus" ) then
  1254. target = action;
  1255. end
  1256. FocusUnit(target);
  1257. end
  1258. end
  1259. end
  1260. SecureCmdList["CLEARFOCUS"] = function(msg)
  1261. if ( SecureCmdOptionParse(msg) ) then
  1262. ClearFocus();
  1263. end
  1264. end
  1265. SecureCmdList["MAINTANKON"] = function(msg)
  1266. local action, target = SecureCmdOptionParse(msg);
  1267. if ( action ) then
  1268. if ( not target ) then
  1269. target = action;
  1270. end
  1271. if ( target == "" ) then
  1272. target = "target";
  1273. end
  1274. SetPartyAssignment("MAINTANK", target);
  1275. end
  1276. end
  1277. SecureCmdList["MAINTANKOFF"] = function(msg)
  1278. local action, target = SecureCmdOptionParse(msg);
  1279. if ( action ) then
  1280. if ( not target ) then
  1281. target = action;
  1282. end
  1283. if ( target == "" ) then
  1284. target = "target";
  1285. end
  1286. ClearPartyAssignment("MAINTANK", target);
  1287. end
  1288. end
  1289. SecureCmdList["MAINASSISTON"] = function(msg)
  1290. local action, target = SecureCmdOptionParse(msg);
  1291. if ( action ) then
  1292. if ( not target ) then
  1293. target = action;
  1294. end
  1295. if ( target == "" ) then
  1296. target = "target";
  1297. end
  1298. SetPartyAssignment("MAINASSIST", target);
  1299. end
  1300. end
  1301. SecureCmdList["MAINASSISTOFF"] = function(msg)
  1302. local action, target = SecureCmdOptionParse(msg);
  1303. if ( action ) then
  1304. if ( not target ) then
  1305. target = action;
  1306. end
  1307. if ( target == "" ) then
  1308. target = "target";
  1309. end
  1310. ClearPartyAssignment("MAINASSIST", target);
  1311. end
  1312. end
  1313. SecureCmdList["DUEL"] = function(msg)
  1314. StartDuel(msg)
  1315. end
  1316. SecureCmdList["DUEL_CANCEL"] = function(msg)
  1317. CancelDuel()
  1318. end
  1319. SecureCmdList["PET_ATTACK"] = function(msg)
  1320. local action, target = SecureCmdOptionParse(msg);
  1321. if ( action ) then
  1322. if ( not target or target == "pettarget" ) then
  1323. target = action;
  1324. end
  1325. PetAttack(target);
  1326. end
  1327. end
  1328. SecureCmdList["PET_FOLLOW"] = function(msg)
  1329. if ( SecureCmdOptionParse(msg) ) then
  1330. PetFollow();
  1331. end
  1332. end
  1333. SecureCmdList["PET_MOVE_TO"] = function(msg)
  1334. local action, target = SecureCmdOptionParse(msg);
  1335. if ( action ) then
  1336. PetMoveTo(target);
  1337. end
  1338. end
  1339. SecureCmdList["PET_STAY"] = function(msg)
  1340. if ( SecureCmdOptionParse(msg) ) then
  1341. PetWait();
  1342. end
  1343. end
  1344. SecureCmdList["PET_PASSIVE"] = function(msg)
  1345. if ( SecureCmdOptionParse(msg) ) then
  1346. PetPassiveMode();
  1347. end
  1348. end
  1349. SecureCmdList["PET_DEFENSIVE"] = function(msg)
  1350. if ( SecureCmdOptionParse(msg) ) then
  1351. PetDefensiveMode();
  1352. end
  1353. end
  1354. SecureCmdList["PET_AGGRESSIVE"] = function(msg)
  1355. if ( SecureCmdOptionParse(msg) ) then
  1356. PetAggressiveMode();
  1357. end
  1358. end
  1359. SecureCmdList["PET_ASSIST"] = function(msg)
  1360. if ( SecureCmdOptionParse(msg) ) then
  1361. PetAssistMode();
  1362. end
  1363. end
  1364. SecureCmdList["PET_AUTOCASTON"] = function(msg)
  1365. local spell = SecureCmdOptionParse(msg);
  1366. if ( spell ) then
  1367. EnableSpellAutocast(spell);
  1368. end
  1369. end
  1370. SecureCmdList["PET_AUTOCASTOFF"] = function(msg)
  1371. local spell = SecureCmdOptionParse(msg);
  1372. if ( spell ) then
  1373. DisableSpellAutocast(spell);
  1374. end
  1375. end
  1376. SecureCmdList["PET_AUTOCASTTOGGLE"] = function(msg)
  1377. local spell = SecureCmdOptionParse(msg);
  1378. if ( spell ) then
  1379. ToggleSpellAutocast(spell);
  1380. end
  1381. end
  1382. SecureCmdList["STOPMACRO"] = function(msg)
  1383. if ( SecureCmdOptionParse(msg) ) then
  1384. StopMacro();
  1385. end
  1386. end
  1387. SecureCmdList["CANCELQUEUEDSPELL"] = function(msg)
  1388. if ( SecureCmdOptionParse(msg) ) then
  1389. SpellCancelQueuedSpell();
  1390. end
  1391. end
  1392. SecureCmdList["CLICK"] = function(msg)
  1393. local action = SecureCmdOptionParse(msg);
  1394. if ( action and action ~= "" ) then
  1395. local name, mouseButton, down = strmatch(action, "([^%s]+)%s+([^%s]+)%s*(.*)");
  1396. if ( not name ) then
  1397. name = action;
  1398. end
  1399. local button = GetClickFrame(name);
  1400. if ( button and button:IsObjectType("Button") and not button:IsForbidden() ) then
  1401. button:Click(mouseButton, down);
  1402. end
  1403. end
  1404. end
  1405. SecureCmdList["EQUIP_SET"] = function(msg)
  1406. local set = SecureCmdOptionParse(msg);
  1407. if ( set and set ~= "" ) then
  1408. EquipmentManager_EquipSet(set);
  1409. end
  1410. end
  1411. SecureCmdList["WORLD_MARKER"] = function(msg)
  1412. local marker = SecureCmdOptionParse(msg);
  1413. if ( tonumber(marker) ) then
  1414. PlaceRaidMarker(tonumber(marker));
  1415. end
  1416. end
  1417. SecureCmdList["CLEAR_WORLD_MARKER"] = function(msg)
  1418. local marker = SecureCmdOptionParse(msg);
  1419. if ( tonumber(marker) ) then
  1420. ClearRaidMarker(tonumber(marker));
  1421. elseif ( type(marker) == "string" and strtrim(strlower(marker)) == strlower(ALL) ) then
  1422. ClearRaidMarker(nil); --Clear all world markers.
  1423. end
  1424. end
  1425. SecureCmdList["SUMMON_BATTLE_PET"] = function(msg)
  1426. local pet = SecureCmdOptionParse(msg);
  1427. if ( type(pet) == "string" ) then
  1428. local _, petID = C_PetJournal.FindPetIDByName(string.trim(pet));
  1429. if ( petID ) then
  1430. C_PetJournal.SummonPetByGUID(petID);
  1431. else
  1432. C_PetJournal.SummonPetByGUID(pet);
  1433. end
  1434. end
  1435. end
  1436. SecureCmdList["RANDOMPET"] = function(msg)
  1437. if ( SecureCmdOptionParse(msg) ) then
  1438. C_PetJournal.SummonRandomPet(true);
  1439. end
  1440. end
  1441. SecureCmdList["RANDOMFAVORITEPET"] = function(msg)
  1442. if ( SecureCmdOptionParse(msg) ) then
  1443. C_PetJournal.SummonRandomPet(false);
  1444. end
  1445. end
  1446. SecureCmdList["DISMISSBATTLEPET"] = function(msg)
  1447. if ( SecureCmdOptionParse(msg) ) then
  1448. local petID = C_PetJournal.GetSummonedPetGUID();
  1449. if ( petID ) then
  1450. C_PetJournal.SummonPetByGUID(petID);
  1451. end
  1452. end
  1453. end
  1454. SecureCmdList["PET_DISMISS"] = function(msg)
  1455. if ( PetCanBeAbandoned() ) then
  1456. CastSpellByID(HUNTER_DISMISS_PET);
  1457. else
  1458. PetDismiss();
  1459. end
  1460. end
  1461. SecureCmdList["USE_TOY"] = function(msg)
  1462. local toyName = SecureCmdOptionParse(msg);
  1463. if ( toyName and toyName ~= "" ) then
  1464. UseToyByName(toyName)
  1465. end
  1466. end
  1467. -- Pre-populate the secure command hash table
  1468. for index, value in pairs(SecureCmdList) do
  1469. local i = 1;
  1470. local cmdString = _G["SLASH_"..index..i];
  1471. while ( cmdString ) do
  1472. cmdString = strupper(cmdString);
  1473. hash_SecureCmdList[cmdString] = value; -- add to hash
  1474. i = i + 1;
  1475. cmdString = _G["SLASH_"..index..i];
  1476. end
  1477. end
  1478. -- Slash commands
  1479. SlashCmdList = { };
  1480. SlashCmdList["CONSOLE"] = function(msg)
  1481. ConsoleExec(msg);
  1482. end
  1483. SlashCmdList["CHATLOG"] = function(msg)
  1484. local info = ChatTypeInfo["SYSTEM"];
  1485. if ( LoggingChat() ) then
  1486. LoggingChat(false);
  1487. DEFAULT_CHAT_FRAME:AddMessage(CHATLOGDISABLED, info.r, info.g, info.b, info.id);
  1488. else
  1489. LoggingChat(true);
  1490. DEFAULT_CHAT_FRAME:AddMessage(CHATLOGENABLED, info.r, info.g, info.b, info.id);
  1491. end
  1492. end
  1493. SlashCmdList["COMBATLOG"] = function(msg)
  1494. local info = ChatTypeInfo["SYSTEM"];
  1495. if ( LoggingCombat() ) then
  1496. LoggingCombat(false);
  1497. DEFAULT_CHAT_FRAME:AddMessage(COMBATLOGDISABLED, info.r, info.g, info.b, info.id);
  1498. else
  1499. LoggingCombat(true);
  1500. DEFAULT_CHAT_FRAME:AddMessage(COMBATLOGENABLED, info.r, info.g, info.b, info.id);
  1501. end
  1502. end
  1503. SlashCmdList["INVITE"] = function(msg)
  1504. if(msg == "") then
  1505. msg = GetUnitName("target", true)
  1506. end
  1507. if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
  1508. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1509. return;
  1510. end
  1511. InviteToGroup(msg);
  1512. end
  1513. SlashCmdList["REQUEST_INVITE"] = function(msg)
  1514. if(msg == "") then
  1515. msg = GetUnitName("target", true)
  1516. end
  1517. if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
  1518. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1519. return;
  1520. end
  1521. RequestInviteFromUnit(msg);
  1522. end
  1523. SlashCmdList["UNINVITE"] = function(msg)
  1524. if(msg == "") then
  1525. msg = GetUnitName("target", true);
  1526. end
  1527. UninviteUnit(msg);
  1528. end
  1529. SlashCmdList["PROMOTE"] = function(msg)
  1530. PromoteToLeader(msg);
  1531. end
  1532. SlashCmdList["REPLY"] = function(msg, editBox)
  1533. local lastTell = ChatEdit_GetLastTellTarget();
  1534. if ( lastTell ) then
  1535. msg = SubstituteChatMessageBeforeSend(msg);
  1536. SendChatMessage(msg, "WHISPER", editBox.languageID, lastTell);
  1537. else
  1538. -- error message
  1539. end
  1540. end
  1541. SlashCmdList["HELP"] = function(msg)
  1542. ChatFrame_DisplayHelpText(DEFAULT_CHAT_FRAME);
  1543. end
  1544. SlashCmdList["MACROHELP"] = function(msg)
  1545. ChatFrame_DisplayMacroHelpText(DEFAULT_CHAT_FRAME);
  1546. end
  1547. SlashCmdList["TIME"] = function(msg)
  1548. ChatFrame_DisplayGameTime(DEFAULT_CHAT_FRAME);
  1549. end
  1550. SlashCmdList["PLAYED"] = function(msg)
  1551. RequestTimePlayed();
  1552. end
  1553. SlashCmdList["FOLLOW"] = function(msg)
  1554. FollowUnit(msg);
  1555. end
  1556. SlashCmdList["TRADE"] = function(msg)
  1557. InitiateTrade("target");
  1558. end
  1559. SlashCmdList["INSPECT"] = function(msg)
  1560. if (IsKioskModeEnabled()) then
  1561. return;
  1562. end
  1563. InspectUnit("target");
  1564. end
  1565. SlashCmdList["LOGOUT"] = function(msg)
  1566. Logout();
  1567. end
  1568. SlashCmdList["QUIT"] = function(msg)
  1569. if (IsKioskModeEnabled()) then
  1570. return;
  1571. end
  1572. Quit();
  1573. end
  1574. SlashCmdList["JOIN"] = function(msg)
  1575. local name = gsub(msg, "%s*([^%s]+).*", "%1");
  1576. local password = gsub(msg, "%s*([^%s]+)%s*(.*)", "%2");
  1577. if(strlen(name) <= 0) then
  1578. local joinhelp = CHAT_JOIN_HELP;
  1579. local info = ChatTypeInfo["SYSTEM"];
  1580. DEFAULT_CHAT_FRAME:AddMessage(joinhelp, info.r, info.g, info.b, info.id);
  1581. else
  1582. local zoneChannel, channelName = JoinPermanentChannel(name, password, DEFAULT_CHAT_FRAME:GetID(), 1);
  1583. if ( channelName ) then
  1584. name = channelName;
  1585. end
  1586. if ( not zoneChannel ) then
  1587. local info = ChatTypeInfo["CHANNEL"];
  1588. DEFAULT_CHAT_FRAME:AddMessage(CHAT_INVALID_NAME_NOTICE, info.r, info.g, info.b, info.id);
  1589. return;
  1590. end
  1591. local i = 1;
  1592. while ( DEFAULT_CHAT_FRAME.channelList[i] ) do
  1593. i = i + 1;
  1594. end
  1595. DEFAULT_CHAT_FRAME.channelList[i] = name;
  1596. DEFAULT_CHAT_FRAME.zoneChannelList[i] = zoneChannel;
  1597. end
  1598. end
  1599. SlashCmdList["LEAVE"] = function(msg)
  1600. local name = strmatch(msg, "%s*([^%s]+)");
  1601. if ( name ) then
  1602. LeaveChannelByName(name);
  1603. end
  1604. end
  1605. SlashCmdList["LIST_CHANNEL"] = function(msg)
  1606. local name = strmatch(msg, "%s*([^%s]+)");
  1607. if ( name ) then
  1608. ListChannelByName(name);
  1609. else
  1610. ListChannels();
  1611. end
  1612. end
  1613. SlashCmdList["CHAT_HELP"] =
  1614. function(msg)
  1615. ChatFrame_DisplayChatHelp(DEFAULT_CHAT_FRAME)
  1616. end
  1617. SlashCmdList["CHAT_PASSWORD"] =
  1618. function(msg)
  1619. local name = gsub(msg, "%s*([^%s]+).*", "%1");
  1620. local password = gsub(msg, "%s*([^%s]+)%s*(.*)", "%2");
  1621. SetChannelPassword(name, password);
  1622. end
  1623. SlashCmdList["CHAT_OWNER"] =
  1624. function(msg)
  1625. local channel = gsub(msg, "%s*([^%s]+).*", "%1");
  1626. local newOwner = gsub(msg, "%s*([^%s]+)%s*(.*)", "%2");
  1627. if ( not channel or not newOwner ) then
  1628. return;
  1629. end
  1630. local newOwnerLen = strlen(newOwner);
  1631. if ( newOwnerLen > MAX_CHARACTER_NAME_BYTES ) then
  1632. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1633. return;
  1634. end
  1635. if ( strlen(channel) > 0 ) then
  1636. if ( newOwnerLen > 0 ) then
  1637. SetChannelOwner(channel, newOwner);
  1638. else
  1639. DisplayChannelOwner(channel);
  1640. end
  1641. end
  1642. end
  1643. SlashCmdList["CHAT_MODERATOR"] =
  1644. function(msg)
  1645. local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
  1646. if ( not channel or not player ) then
  1647. return;
  1648. end
  1649. if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
  1650. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1651. return;
  1652. end
  1653. ChannelModerator(channel, player);
  1654. end
  1655. SlashCmdList["CHAT_UNMODERATOR"] =
  1656. function(msg)
  1657. local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
  1658. if ( not channel or not player ) then
  1659. return;
  1660. end
  1661. if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
  1662. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1663. return;
  1664. end
  1665. if ( channel and player ) then
  1666. ChannelUnmoderator(channel, player);
  1667. end
  1668. end
  1669. SlashCmdList["CHAT_MUTE"] =
  1670. function(msg)
  1671. local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
  1672. if ( not channel or not player ) then
  1673. return;
  1674. end
  1675. if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
  1676. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1677. return;
  1678. end
  1679. if ( channel and player ) then
  1680. ChannelMute(channel, player);
  1681. end
  1682. end
  1683. SlashCmdList["CHAT_UNMUTE"] =
  1684. function(msg)
  1685. local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
  1686. if ( not channel or not player ) then
  1687. return;
  1688. end
  1689. if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
  1690. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1691. return;
  1692. end
  1693. if ( channel and player ) then
  1694. ChannelUnmute(channel, player);
  1695. end
  1696. end
  1697. SlashCmdList["CHAT_CINVITE"] =
  1698. function(msg)
  1699. local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
  1700. if ( not channel or not player ) then
  1701. return;
  1702. end
  1703. if ( channel and player ) then
  1704. if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
  1705. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1706. return;
  1707. end
  1708. ChannelInvite(channel, player);
  1709. end
  1710. end
  1711. SlashCmdList["CHAT_KICK"] =
  1712. function(msg)
  1713. local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
  1714. if ( not channel or not player ) then
  1715. return;
  1716. end
  1717. if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
  1718. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1719. return;
  1720. end
  1721. if ( channel and player ) then
  1722. ChannelKick(channel, player);
  1723. end
  1724. end
  1725. SlashCmdList["CHAT_BAN"] =
  1726. function(msg)
  1727. local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
  1728. if ( not channel or not player ) then
  1729. return;
  1730. end
  1731. if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
  1732. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1733. return;
  1734. end
  1735. if ( channel and player ) then
  1736. ChannelBan(channel, player);
  1737. end
  1738. end
  1739. SlashCmdList["CHAT_UNBAN"] =
  1740. function(msg)
  1741. local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
  1742. if ( not channel or not player ) then
  1743. return;
  1744. end
  1745. if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
  1746. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1747. return;
  1748. end
  1749. if ( channel and player ) then
  1750. ChannelUnban(channel, player);
  1751. end
  1752. end
  1753. SlashCmdList["CHAT_ANNOUNCE"] =
  1754. function(msg)
  1755. local channel = strmatch(msg, "%s*([^%s]+)");
  1756. if ( channel ) then
  1757. ChannelToggleAnnouncements(channel);
  1758. end
  1759. end
  1760. SlashCmdList["GUILD_INVITE"] = function(msg)
  1761. if(msg == "") then
  1762. msg = GetUnitName("target", true);
  1763. end
  1764. if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
  1765. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1766. return;
  1767. end
  1768. GuildInvite(msg);
  1769. end
  1770. SlashCmdList["GUILD_UNINVITE"] = function(msg)
  1771. if(msg == "") then
  1772. msg = UnitName("target");
  1773. end
  1774. if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
  1775. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1776. return;
  1777. end
  1778. GuildUninvite(msg);
  1779. end
  1780. SlashCmdList["GUILD_PROMOTE"] = function(msg)
  1781. if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
  1782. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1783. return;
  1784. end
  1785. GuildPromote(msg);
  1786. end
  1787. SlashCmdList["GUILD_DEMOTE"] = function(msg)
  1788. if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
  1789. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1790. return;
  1791. end
  1792. GuildDemote(msg);
  1793. end
  1794. SlashCmdList["GUILD_LEADER"] = function(msg)
  1795. if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
  1796. ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
  1797. return;
  1798. end
  1799. GuildSetLeader(msg);
  1800. end
  1801. SlashCmdList["GUILD_MOTD"] = function(msg)
  1802. GuildSetMOTD(msg)
  1803. end
  1804. SlashCmdList["GUILD_LEAVE"] = function(msg)
  1805. GuildLeave();
  1806. end
  1807. SlashCmdList["GUILD_DISBAND"] = function(msg)
  1808. if ( IsGuildLeader() ) then
  1809. StaticPopup_Show("CONFIRM_GUILD_DISBAND");
  1810. end
  1811. end
  1812. SlashCmdList["GUILD_INFO"] = function(msg)
  1813. GuildInfo();
  1814. end
  1815. SlashCmdList["GUILD_ROSTER"] = function(msg)
  1816. if ( IsInGuild() ) then
  1817. GuildFrame_LoadUI();
  1818. if ( GuildFrame ) then
  1819. GuildFrameTab2:Click();
  1820. ShowUIPanel(GuildFrame);
  1821. end
  1822. end
  1823. end
  1824. --SlashCmdList["GUILD_HELP"] = function(msg)
  1825. -- ChatFrame_DisplayGuildHelp(DEFAULT_CHAT_FRAME);
  1826. --end
  1827. SlashCmdList["CHAT_AFK"] = function(msg)
  1828. SendChatMessage(msg, "AFK");
  1829. end
  1830. SlashCmdList["CHAT_DND"] = function(msg)
  1831. SendChatMessage(msg, "DND");
  1832. end
  1833. SlashCmdList["WHO"] = function(msg)
  1834. if (IsKioskModeEnabled()) then
  1835. return;
  1836. end
  1837. if ( msg == "" ) then
  1838. msg = WhoFrame_GetDefaultWhoCommand();
  1839. ShowWhoPanel();
  1840. end
  1841. WhoFrameEditBox:SetText(msg);
  1842. SendWho(msg);
  1843. end
  1844. SlashCmdList["CHANNEL"] = function(msg, editBox)
  1845. msg = SubstituteChatMessageBeforeSend(msg);
  1846. SendChatMessage(msg, "CHANNEL", editBox.languageID, editBox:GetAttribute("channelTarget"));
  1847. end
  1848. SlashCmdList["FRIENDS"] = function(msg)
  1849. local player, note = strmatch(msg, "%s*([^%s]+)%s*(.*)");
  1850. if ( player ~= "" or UnitIsPlayer("target") ) then
  1851. AddOrRemoveFriend(player, note);
  1852. else
  1853. ToggleFriendsPanel();
  1854. end
  1855. end
  1856. SlashCmdList["REMOVEFRIEND"] = function(msg)
  1857. RemoveFriend(msg);
  1858. end
  1859. SlashCmdList["IGNORE"] = function(msg)
  1860. if ( msg ~= "" or UnitIsPlayer("target") ) then
  1861. local bNetIDAccount = BNet_GetBNetIDAccount(msg);
  1862. if ( bNetIDAccount ) then
  1863. if ( BNIsFriend(bNetIDAccount) ) then
  1864. SendSystemMessage(ERR_CANNOT_IGNORE_BN_FRIEND);
  1865. else
  1866. BNSetBlocked(bNetIDAccount, not BNIsBlocked(bNetIDAccount));
  1867. end
  1868. else
  1869. AddOrDelIgnore(msg);
  1870. end
  1871. else
  1872. ToggleIgnorePanel();
  1873. end
  1874. end
  1875. SlashCmdList["UNIGNORE"] = function(msg)
  1876. if ( msg ~= "" or UnitIsPlayer("target") ) then
  1877. DelIgnore(msg);
  1878. else
  1879. ToggleIgnorePanel();
  1880. end
  1881. end
  1882. SlashCmdList["SCRIPT"] = function(msg)
  1883. if ( not ScriptsDisallowedForBeta() ) then
  1884. if ( not AreDangerousScriptsAllowed() ) then
  1885. StaticPopup_Show("DANGEROUS_SCRIPTS_WARNING");
  1886. return;
  1887. end
  1888. RunScript(msg);
  1889. end
  1890. end
  1891. SlashCmdList["LOOT_FFA"] = function(msg)
  1892. SetLootMethod("freeforall");
  1893. end
  1894. SlashCmdList["LOOT_MASTER"] = function(msg)
  1895. SetLootMethod("master", msg, 1);
  1896. end
  1897. SlashCmdList["LOOT_GROUP"] = function(msg)
  1898. SetLootMethod("group");
  1899. end
  1900. SlashCmdList["LOOT_SETTHRESHOLD"] = function(msg)
  1901. if ( not msg ) then
  1902. local info = ChatTypeInfo["SYSTEM"];
  1903. DEFAULT_CHAT_FRAME:AddMessage(format(ERROR_SLASH_LOOT_SETTHRESHOLD, MIN_LOOT_THRESHOLD, MAX_LOOT_THRESHOLD), info.r, info.g, info.b, info.id);
  1904. return;
  1905. end
  1906. local MIN_LOOT_THRESHOLD = 2; -- "good" item quality
  1907. local MAX_LOOT_THRESHOLD = 6; -- "artifact" item quality
  1908. local threshold = strmatch(msg, "(%d+)");
  1909. threshold = tonumber(threshold);
  1910. if ( threshold and threshold >= MIN_LOOT_THRESHOLD and threshold <= MAX_LOOT_THRESHOLD ) then
  1911. -- try to match a threshold number first
  1912. SetLootThreshold(threshold);
  1913. else
  1914. msg = strupper(msg);
  1915. if ( msg == strupper(ITEM_QUALITY2_DESC) ) then
  1916. SetLootThreshold(2);
  1917. elseif ( msg == strupper(ITEM_QUALITY3_DESC) ) then
  1918. SetLootThreshold(3);
  1919. elseif ( msg == strupper(ITEM_QUALITY4_DESC) ) then
  1920. SetLootThreshold(4);
  1921. elseif ( msg == strupper(ITEM_QUALITY5_DESC) ) then
  1922. SetLootThreshold(5);
  1923. elseif ( msg == strupper(ITEM_QUALITY6_DESC) ) then
  1924. SetLootThreshold(6);
  1925. else
  1926. -- no matches found
  1927. local info = ChatTypeInfo["SYSTEM"];
  1928. DEFAULT_CHAT_FRAME:AddMessage(format(ERROR_SLASH_LOOT_SETTHRESHOLD, MIN_LOOT_THRESHOLD, MAX_LOOT_THRESHOLD), info.r, info.g, info.b, info.id);
  1929. end
  1930. end
  1931. end
  1932. SlashCmdList["RANDOM"] = function(msg)
  1933. local num1 = gsub(msg, "(%s*)(%d+)(.*)", "%2", 1);
  1934. local rest = gsub(msg, "(%s*)(%d+)(.*)", "%3", 1);
  1935. local num2 = "";
  1936. local numSubs;
  1937. if ( strlen(rest) > 0 ) then
  1938. num2, numSubs = gsub(msg, "(%s*)(%d+)([-%s]+)(%d+)(.*)", "%4", 1);
  1939. if ( numSubs == 0 ) then
  1940. num2 = "";
  1941. end
  1942. end
  1943. if ( num1 == "" and num2 == "" ) then
  1944. RandomRoll("1", "100");
  1945. elseif ( num2 == "" ) then
  1946. RandomRoll("1", num1);
  1947. else
  1948. RandomRoll(num1, num2);
  1949. end
  1950. end
  1951. SlashCmdList["MACRO"] = function(msg)
  1952. ShowMacroFrame();
  1953. end
  1954. SlashCmdList["PVP"] = function(msg)
  1955. TogglePVP();
  1956. end
  1957. SlashCmdList["RAID_INFO"] = function(msg)
  1958. RaidFrame.slashCommand = 1;
  1959. if ( ( GetNumSavedInstances() + GetNumSavedWorldBosses() > 0 ) and not RaidInfoFrame:IsVisible() ) then
  1960. ToggleRaidFrame();
  1961. RaidInfoFrame:Show();
  1962. elseif ( not RaidFrame:IsVisible() ) then
  1963. ToggleRaidFrame();
  1964. end
  1965. end
  1966. SlashCmdList["READYCHECK"] = function(msg)
  1967. if ( UnitIsGroupLeader("player") or UnitIsGroupAssistant("player") ) then
  1968. DoReadyCheck();
  1969. end
  1970. end
  1971. --[[All of this information is obtainable through the armory now.
  1972. SlashCmdList["SAVEGUILDROSTER"] = function(msg)
  1973. SaveGuildRoster();
  1974. end]]
  1975. SlashCmdList["DUNGEONS"] = function(msg)
  1976. ToggleLFDParentFrame();
  1977. end
  1978. SlashCmdList["BENCHMARK"] = function(msg)
  1979. SetTaxiBenchmarkMode(ValueToBoolean(msg), true);
  1980. end
  1981. SlashCmdList["DISMOUNT"] = function(msg)
  1982. if ( SecureCmdOptionParse(msg) ) then
  1983. Dismount();
  1984. end
  1985. end
  1986. SlashCmdList["LEAVEVEHICLE"] = function(msg)
  1987. if ( SecureCmdOptionParse(msg) ) then
  1988. VehicleExit();
  1989. end
  1990. end
  1991. SlashCmdList["RESETCHAT"] = function(msg)
  1992. FCF_ResetAllWindows();
  1993. end
  1994. SlashCmdList["ENABLE_ADDONS"] = function(msg)
  1995. EnableAllAddOns(msg);
  1996. ReloadUI();
  1997. end
  1998. SlashCmdList["DISABLE_ADDONS"] = function(msg)
  1999. DisableAllAddOns(msg);
  2000. ReloadUI();
  2001. end
  2002. SlashCmdList["STOPWATCH"] = function(msg)
  2003. if ( not IsAddOnLoaded("Blizzard_TimeManager") ) then
  2004. UIParentLoadAddOn("Blizzard_TimeManager");
  2005. end
  2006. if ( StopwatchFrame ) then
  2007. local text = strmatch(msg, "%s*([^%s]+)%s*");
  2008. if ( text ) then
  2009. text = strlower(text);
  2010. -- in any of the following cases, the stopwatch will be shown
  2011. StopwatchFrame:Show();
  2012. -- try to match a command
  2013. local function MatchCommand(param, text)
  2014. local i, compare;
  2015. i = 1;
  2016. repeat
  2017. compare = _G[param..i];
  2018. if ( compare and compare == text ) then
  2019. return true;
  2020. end
  2021. i = i + 1;
  2022. until ( not compare );
  2023. return false;
  2024. end
  2025. if ( MatchCommand("SLASH_STOPWATCH_PARAM_PLAY", text) ) then
  2026. Stopwatch_Play();
  2027. return;
  2028. end
  2029. if ( MatchCommand("SLASH_STOPWATCH_PARAM_PAUSE", text) ) then
  2030. Stopwatch_Pause();
  2031. return;
  2032. end
  2033. if ( MatchCommand("SLASH_STOPWATCH_PARAM_STOP", text) ) then
  2034. Stopwatch_Clear();
  2035. return;
  2036. end
  2037. -- try to match a countdown
  2038. -- kinda ghetto, but hey, it's simple and it works =)
  2039. local hour, minute, second = strmatch(msg, "(%d+):(%d+):(%d+)");
  2040. if ( not hour ) then
  2041. minute, second = strmatch(msg, "(%d+):(%d+)");
  2042. if ( not minute ) then
  2043. second = strmatch(msg, "(%d+)");
  2044. end
  2045. end
  2046. Stopwatch_StartCountdown(tonumber(hour), tonumber(minute), tonumber(second));
  2047. else
  2048. Stopwatch_Toggle();
  2049. end
  2050. end
  2051. end
  2052. SlashCmdList["CALENDAR"] = function(msg)
  2053. if ( not IsAddOnLoaded("Blizzard_Calendar") ) then
  2054. UIParentLoadAddOn("Blizzard_Calendar");
  2055. end
  2056. if ( Calendar_Toggle ) then
  2057. Calendar_Toggle();
  2058. end
  2059. end
  2060. SlashCmdList["ACHIEVEMENTUI"] = function(msg)
  2061. ToggleAchievementFrame();
  2062. end
  2063. SlashCmdList["SET_TITLE"] = function(msg)
  2064. local name = SecureCmdOptionParse(msg);
  2065. if ( name and name ~= "") then
  2066. if(not SetTitleByName(name)) then
  2067. UIErrorsFrame:AddMessage(TITLE_DOESNT_EXIST, 1.0, 0.1, 0.1, 1.0);
  2068. end
  2069. else
  2070. SetCurrentTitle(-1)
  2071. end
  2072. end
  2073. SlashCmdList["USE_TALENT_SPEC"] = function(msg)
  2074. local group = SecureCmdOptionParse(msg);
  2075. if ( group ) then
  2076. local groupNumber = tonumber(group);
  2077. if ( groupNumber ) then
  2078. --SetActiveSpecGroup(groupNumber);
  2079. end
  2080. end
  2081. end
  2082. -- easier method to turn on/off errors for macros
  2083. SlashCmdList["UI_ERRORS_OFF"] = function(msg)
  2084. UIErrorsFrame:UnregisterEvent("UI_ERROR_MESSAGE");
  2085. SetCVar("Sound_EnableSFX", "0");
  2086. end
  2087. SlashCmdList["UI_ERRORS_ON"] = function(msg)
  2088. UIErrorsFrame:RegisterEvent("UI_ERROR_MESSAGE");
  2089. SetCVar("Sound_EnableSFX", "1");
  2090. end
  2091. SlashCmdList["FRAMESTACK"] = function(msg)
  2092. UIParentLoadAddOn("Blizzard_DebugTools");
  2093. local showHiddenArg, showRegionsArg = strmatch(msg, "^%s*(%S+)%s+(%S+)%s*$");
  2094. if ( not showHiddenArg or not showRegionsArg ) then
  2095. showHiddenArg = strmatch(msg, "^%s*(%S+)%s*$");
  2096. showRegionsArg = "1";
  2097. end
  2098. local showHidden = showHiddenArg == "true" or showHiddenArg == "1";
  2099. local showRegions = showRegions == "true" or showRegionsArg == "1";
  2100. FrameStackTooltip_Toggle(showHidden, showRegions);
  2101. end
  2102. SlashCmdList["EVENTTRACE"] = function(msg)
  2103. UIParentLoadAddOn("Blizzard_DebugTools");
  2104. EventTraceFrame_HandleSlashCmd(msg);
  2105. end
  2106. SlashCmdList["DUMP"] = function(msg)
  2107. if (not IsKioskModeEnabled() and not ScriptsDisallowedForBeta()) then
  2108. if ( not AreDangerousScriptsAllowed() ) then
  2109. StaticPopup_Show("DANGEROUS_SCRIPTS_WARNING");
  2110. return;
  2111. end
  2112. UIParentLoadAddOn("Blizzard_DebugTools");
  2113. DevTools_DumpCommand(msg);
  2114. end
  2115. end
  2116. SlashCmdList["RELOAD"] = function(msg)
  2117. ConsoleExec("reloadui");
  2118. end
  2119. SlashCmdList["WARGAME"] = function(msg)
  2120. -- Parameters are (playername, area, isTournamentMode). Since the player name can be multiple words,
  2121. -- we pass in theses parameters as a whitespace delimited string and let the C side tokenize it
  2122. StartWarGameByName(msg);
  2123. end
  2124. SlashCmdList["SPECTATOR_WARGAME"] = function(msg)
  2125. local target1, target2, size, area, isTournamentMode = strmatch(msg, "^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s*([^%s]*)%s*([^%s]*)")
  2126. if (not target1 or not target2 or not size) then
  2127. return;
  2128. end
  2129. local bnetIDGameAccount1 = BNet_GetBNetIDGameAccount(target1) or BNet_GetBNetIDAccount(target1);
  2130. if not bnetIDGameAccount1 then
  2131. ConsolePrint("Failed to find StartSpectatorWarGame target1:", target1);
  2132. end
  2133. local bnetIDGameAccount2 = BNet_GetBNetIDGameAccount(target2) or BNet_GetBNetIDAccount(target2);
  2134. if not bnetIDGameAccount2 then
  2135. ConsolePrint("Failed to find StartSpectatorWarGame target2:", target2);
  2136. end
  2137. if (area == "" or area == "nil" or area == "0") then area = nil end
  2138. StartSpectatorWarGame(bnetIDGameAccount1 or target1, bnetIDGameAccount2 or target2, size, area, ValueToBoolean(isTournamentMode));
  2139. end
  2140. SlashCmdList["GUILDFINDER"] = function(msg)
  2141. if ( GameLimitedMode_IsActive() ) then
  2142. UIErrorsFrame:AddMessage(ERR_RESTRICTED_ACCOUNT_TRIAL, 1.0, 0.1, 0.1, 1.0);
  2143. else
  2144. ToggleGuildFinder();
  2145. end
  2146. end
  2147. SlashCmdList["TARGET_MARKER"] = function(msg)
  2148. local marker, target = SecureCmdOptionParse(msg);
  2149. if ( not target ) then
  2150. target = "target";
  2151. end
  2152. if ( tonumber(marker) ) then
  2153. SetRaidTarget(target, tonumber(marker)); --Using /tm 0 will clear the target marker.
  2154. end
  2155. end
  2156. SlashCmdList["OPEN_LOOT_HISTORY"] = function(msg)
  2157. ToggleLootHistoryFrame();
  2158. end
  2159. SlashCmdList["RAIDFINDER"] = function(msg)
  2160. PVEFrame_ToggleFrame("GroupFinderFrame", RaidFinderFrame);
  2161. end
  2162. SlashCmdList["SHARE"] = function(msg)
  2163. -- Allow if any social platforms are enabled (currently only Twitter)
  2164. if (C_Social.IsSocialEnabled()) then
  2165. SocialFrame_LoadUI();
  2166. Social_ToggleShow(msg);
  2167. end
  2168. end
  2169. function ChatFrame_SetupListProxyTable(list)
  2170. if ( getmetatable(list) ) then
  2171. return;
  2172. end
  2173. setmetatable(list, { __index = {} });
  2174. end
  2175. function ChatFrame_ImportListToHash(list, hash)
  2176. for k, v in pairs(list) do
  2177. local i = 1;
  2178. local tag = _G["SLASH_"..k..i];
  2179. while(tag) do
  2180. tag = strupper(tag);
  2181. if ( hash ) then
  2182. hash[tag] = v;
  2183. end
  2184. hash_ChatTypeInfoList[tag] = k; --Also need to import it here for all types.
  2185. i = i + 1;
  2186. tag = _G["SLASH_"..k..i];
  2187. end
  2188. --Add the item we removed to the proxy table.
  2189. local proxyTable = getmetatable(list).__index;
  2190. proxyTable[k] = v;
  2191. end
  2192. table.wipe(list);
  2193. end
  2194. function ChatFrame_ImportEmoteTokensToHash()
  2195. -- Hook up per-faction emotes before we build the emote list hash.
  2196. local factionGroup = UnitFactionGroup("player");
  2197. EMOTE454_TOKEN = nil; -- "FORTHEALLIANCE"
  2198. EMOTE455_TOKEN = nil; -- "FORTHEHORDE"
  2199. if ( factionGroup == "Alliance" ) then
  2200. EMOTE454_TOKEN = "FORTHEALLIANCE";
  2201. TextEmoteSpeechList[#TextEmoteSpeechList + 1] = "FORTHEALLIANCE";
  2202. elseif ( factionGroup == "Horde" ) then
  2203. EMOTE455_TOKEN = "FORTHEHORDE";
  2204. TextEmoteSpeechList[#TextEmoteSpeechList + 1] = "FORTHEHORDE";
  2205. end
  2206. local i = 1;
  2207. local j = 1;
  2208. local cmdString = _G["EMOTE"..i.."_CMD"..j];
  2209. while ( i <= MAXEMOTEINDEX ) do
  2210. local token = _G["EMOTE"..i.."_TOKEN"];
  2211. -- if the code in here changes - change the corresponding code above
  2212. if ( token and cmdString) then
  2213. hash_EmoteTokenList[strupper(cmdString)] = token; -- add to hash
  2214. end
  2215. j = j + 1;
  2216. cmdString = _G["EMOTE"..i.."_CMD"..j];
  2217. if ( not cmdString ) then
  2218. i = i + 1;
  2219. j = 1;
  2220. cmdString = _G["EMOTE"..i.."_CMD"..j];
  2221. end
  2222. end
  2223. end
  2224. function ChatFrame_ImportAllListsToHash()
  2225. ChatFrame_ImportListToHash(SecureCmdList, hash_SecureCmdList);
  2226. ChatFrame_ImportListToHash(SlashCmdList, hash_SlashCmdList);
  2227. ChatFrame_ImportListToHash(ChatTypeInfo);
  2228. end
  2229. ChatFrame_SetupListProxyTable(SecureCmdList);
  2230. ChatFrame_SetupListProxyTable(SlashCmdList);
  2231. ChatFrame_SetupListProxyTable(ChatTypeInfo);
  2232. for index, value in pairs(ChatTypeInfo) do
  2233. value.r = 1.0;
  2234. value.g = 1.0;
  2235. value.b = 1.0;
  2236. value.id = GetChatTypeIndex(index);
  2237. end
  2238. ChatFrame_ImportAllListsToHash();
  2239. ChatFrame_ImportEmoteTokensToHash();
  2240. -- ChatFrame functions
  2241. function ChatFrame_OnLoad(self)
  2242. self:SetTimeVisible(120.0);
  2243. self:SetMaxLines(128);
  2244. self:SetFontObject(ChatFontNormal);
  2245. self:SetIndentedWordWrap(true);
  2246. self:SetJustifyH("LEFT");
  2247. self.flashTimer = 0;
  2248. self:RegisterEvent("PLAYER_ENTERING_WORLD");
  2249. self:RegisterEvent("UPDATE_CHAT_COLOR");
  2250. self:RegisterEvent("UPDATE_CHAT_WINDOWS");
  2251. self:RegisterEvent("CHAT_MSG_CHANNEL");
  2252. self:RegisterEvent("ZONE_UNDER_ATTACK");
  2253. self:RegisterEvent("UPDATE_INSTANCE_INFO");
  2254. self:RegisterEvent("NEW_TITLE_EARNED");
  2255. self:RegisterEvent("OLD_TITLE_LOST");
  2256. self:RegisterEvent("UPDATE_CHAT_COLOR_NAME_BY_CLASS");
  2257. self:RegisterEvent("VARIABLES_LOADED");
  2258. self:RegisterEvent("CHAT_SERVER_DISCONNECTED");
  2259. self:RegisterEvent("CHAT_SERVER_RECONNECTED");
  2260. self:RegisterEvent("BN_CONNECTED");
  2261. self:RegisterEvent("BN_DISCONNECTED");
  2262. self:RegisterEvent("PLAYER_REPORT_SUBMITTED");
  2263. self:RegisterEvent("NEUTRAL_FACTION_SELECT_RESULT");
  2264. self:RegisterEvent("CHARACTER_UPGRADE_SPELL_TIER_SET");
  2265. self:RegisterEvent("ALTERNATIVE_DEFAULT_LANGUAGE_CHANGED");
  2266. self.tellTimer = GetTime();
  2267. self.channelList = {};
  2268. self.zoneChannelList = {};
  2269. self.messageTypeList = {};
  2270. self.defaultLanguage = GetDefaultLanguage(); --If PLAYER_ENTERING_WORLD hasn't been called yet, this is nil, but it'll be fixed whent he event is fired.
  2271. self.alternativeDefaultLanguage = GetAlternativeDefaultLanguage();
  2272. end
  2273. function ChatFrame_RegisterForMessages(self, ...)
  2274. local messageGroup;
  2275. local index = 1;
  2276. for i=1, select("#", ...) do
  2277. messageGroup = ChatTypeGroup[select(i, ...)];
  2278. if ( messageGroup ) then
  2279. self.messageTypeList[index] = select(i, ...);
  2280. for index, value in pairs(messageGroup) do
  2281. self:RegisterEvent(value);
  2282. end
  2283. index = index + 1;
  2284. end
  2285. end
  2286. end
  2287. function ChatFrame_RegisterForChannels(self, ...)
  2288. local index = 1;
  2289. for i=1, select("#", ...), 2 do
  2290. self.channelList[index], self.zoneChannelList[index] = select(i, ...);
  2291. index = index + 1;
  2292. end
  2293. end
  2294. function ChatFrame_AddMessageGroup(chatFrame, group)
  2295. local info = ChatTypeGroup[group];
  2296. if ( info ) then
  2297. tinsert(chatFrame.messageTypeList, group);
  2298. for index, value in pairs(info) do
  2299. chatFrame:RegisterEvent(value);
  2300. end
  2301. AddChatWindowMessages(chatFrame:GetID(), group);
  2302. end
  2303. end
  2304. function ChatFrame_AddSingleMessageType(chatFrame, messageType)
  2305. local group = ChatTypeGroupInverted[messageType];
  2306. local info = ChatTypeGroup[group];
  2307. if ( info ) then
  2308. if (not tContains(chatFrame.messageTypeList, group)) then
  2309. tinsert(chatFrame.messageTypeList, group);
  2310. end
  2311. for index, value in pairs(info) do
  2312. if (value == messageType) then
  2313. chatFrame:RegisterEvent(value);
  2314. end
  2315. end
  2316. end
  2317. end
  2318. function ChatFrame_RemoveMessageGroup(chatFrame, group)
  2319. local info = ChatTypeGroup[group];
  2320. if ( info ) then
  2321. for index, value in pairs(chatFrame.messageTypeList) do
  2322. if ( strupper(value) == strupper(group) ) then
  2323. chatFrame.messageTypeList[index] = nil;
  2324. end
  2325. end
  2326. for index, value in pairs(info) do
  2327. chatFrame:UnregisterEvent(value);
  2328. end
  2329. RemoveChatWindowMessages(chatFrame:GetID(), group);
  2330. end
  2331. end
  2332. function ChatFrame_RemoveAllMessageGroups(chatFrame)
  2333. for index, value in pairs(chatFrame.messageTypeList) do
  2334. for eventIndex, eventValue in pairs(ChatTypeGroup[value]) do
  2335. chatFrame:UnregisterEvent(eventValue);
  2336. end
  2337. RemoveChatWindowMessages(chatFrame:GetID(), value);
  2338. end
  2339. chatFrame.messageTypeList = {};
  2340. end
  2341. function ChatFrame_AddChannel(chatFrame, channel)
  2342. local zoneChannel = AddChatWindowChannel(chatFrame:GetID(), channel);
  2343. if ( zoneChannel ) then
  2344. local i = 1;
  2345. while ( chatFrame.channelList[i] ) do
  2346. i = i + 1;
  2347. end
  2348. chatFrame.channelList[i] = channel;
  2349. chatFrame.zoneChannelList[i] = zoneChannel;
  2350. end
  2351. end
  2352. function ChatFrame_RemoveChannel(chatFrame, channel)
  2353. for index, value in pairs(chatFrame.channelList) do
  2354. if ( strupper(channel) == strupper(value) ) then
  2355. chatFrame.channelList[index] = nil;
  2356. chatFrame.zoneChannelList[index] = nil;
  2357. end
  2358. end
  2359. RemoveChatWindowChannel(chatFrame:GetID(), channel);
  2360. end
  2361. function ChatFrame_RemoveAllChannels(chatFrame)
  2362. for index, value in pairs(chatFrame.channelList) do
  2363. RemoveChatWindowChannel(chatFrame:GetID(), value);
  2364. end
  2365. chatFrame.channelList = {};
  2366. chatFrame.zoneChannelList = {};
  2367. end
  2368. function ChatFrame_AddPrivateMessageTarget(chatFrame, chatTarget)
  2369. ChatFrame_RemoveExcludePrivateMessageTarget(chatFrame, chatTarget);
  2370. if ( chatFrame.privateMessageList ) then
  2371. chatFrame.privateMessageList[strlower(chatTarget)] = true;
  2372. else
  2373. chatFrame.privateMessageList = { [strlower(chatTarget)] = true };
  2374. end
  2375. end
  2376. function ChatFrame_RemovePrivateMessageTarget(chatFrame, chatTarget)
  2377. if ( chatFrame.privateMessageList ) then
  2378. chatFrame.privateMessageList[strlower(chatTarget)] = nil;
  2379. end
  2380. end
  2381. function ChatFrame_ExcludePrivateMessageTarget(chatFrame, chatTarget)
  2382. ChatFrame_RemovePrivateMessageTarget(chatFrame, chatTarget);
  2383. if ( chatFrame.excludePrivateMessageList ) then
  2384. chatFrame.excludePrivateMessageList[strlower(chatTarget)] = true;
  2385. else
  2386. chatFrame.excludePrivateMessageList = { [strlower(chatTarget)] = true };
  2387. end
  2388. end
  2389. function ChatFrame_RemoveExcludePrivateMessageTarget(chatFrame, chatTarget)
  2390. if ( chatFrame.excludePrivateMessageList ) then
  2391. chatFrame.excludePrivateMessageList[strlower(chatTarget)] = nil;
  2392. end
  2393. end
  2394. function ChatFrame_ReceiveAllPrivateMessages(chatFrame)
  2395. chatFrame.privateMessageList = nil;
  2396. chatFrame.excludePrivateMessageList = nil;
  2397. end
  2398. -- Set up a private editbox to handle macro execution
  2399. do
  2400. local function GetDefaultChatEditBox(field)
  2401. return DEFAULT_CHAT_FRAME.editBox;
  2402. end
  2403. local editbox = CreateFrame("Editbox", "MacroEditBox");
  2404. editbox:RegisterEvent("EXECUTE_CHAT_LINE");
  2405. editbox:SetScript("OnEvent",
  2406. function(self,event,line)
  2407. if ( event == "EXECUTE_CHAT_LINE" ) then
  2408. local defaulteditbox = securecall(GetDefaultChatEditBox);
  2409. self:SetAttribute("chatType", defaulteditbox:GetAttribute("chatType"));
  2410. self:SetAttribute("tellTarget", defaulteditbox:GetAttribute("tellTarget"));
  2411. self:SetAttribute("channelTarget", defaulteditbox:GetAttribute("channelTarget"));
  2412. self:SetText(line);
  2413. ChatEdit_SendText(self);
  2414. end
  2415. end
  2416. );
  2417. editbox:Hide();
  2418. end
  2419. function ChatFrame_OnEvent(self, event, ...)
  2420. if ( ChatFrame_ConfigEventHandler(self, event, ...) ) then
  2421. return;
  2422. end
  2423. if ( ChatFrame_SystemEventHandler(self, event, ...) ) then
  2424. return
  2425. end
  2426. if ( ChatFrame_MessageEventHandler(self, event, ...) ) then
  2427. return
  2428. end
  2429. end
  2430. function ChatFrame_UpdateColorByID(self, chatTypeID, r, g, b)
  2431. local function TransformColorByID(text, messageR, messageG, messageB, messageChatTypeID, messageAccessID, lineID)
  2432. if messageChatTypeID == chatTypeID then
  2433. return true, r, g, b;
  2434. end
  2435. return false;
  2436. end
  2437. self:AdjustMessageColors(TransformColorByID);
  2438. end
  2439. function ChatFrame_ConfigEventHandler(self, event, ...)
  2440. if ( event == "PLAYER_ENTERING_WORLD" ) then
  2441. self.defaultLanguage = GetDefaultLanguage();
  2442. self.alternativeDefaultLanguage = GetAlternativeDefaultLanguage();
  2443. return true;
  2444. elseif ( event == "NEUTRAL_FACTION_SELECT_RESULT" ) then
  2445. self.defaultLanguage = GetDefaultLanguage();
  2446. self.alternativeDefaultLanguage = GetAlternativeDefaultLanguage();
  2447. return true;
  2448. elseif ( event == "ALTERNATIVE_DEFAULT_LANGUAGE_CHANGED" ) then
  2449. self.alternativeDefaultLanguage = GetAlternativeDefaultLanguage();
  2450. return true;
  2451. elseif ( event == "UPDATE_CHAT_WINDOWS" ) then
  2452. local name, fontSize, r, g, b, a, shown, locked = FCF_GetChatWindowInfo(self:GetID());
  2453. if ( fontSize > 0 ) then
  2454. local fontFile, unused, fontFlags = self:GetFont();
  2455. self:SetFont(fontFile, fontSize, fontFlags);
  2456. end
  2457. if ( shown and not self.minimized ) then
  2458. self:Show();
  2459. end
  2460. -- Do more stuff!!!
  2461. ChatFrame_RegisterForMessages(self, GetChatWindowMessages(self:GetID()));
  2462. ChatFrame_RegisterForChannels(self, GetChatWindowChannels(self:GetID()));
  2463. -- GMOTD may have arrived before this frame registered for the event
  2464. if ( not self.checkedGMOTD and self:IsEventRegistered("GUILD_MOTD") ) then
  2465. self.checkedGMOTD = true;
  2466. ChatFrame_DisplayGMOTD(self, GetGuildRosterMOTD());
  2467. end
  2468. return true;
  2469. end
  2470. local arg1, arg2, arg3, arg4 = ...;
  2471. if ( event == "UPDATE_CHAT_COLOR" ) then
  2472. local info = ChatTypeInfo[strupper(arg1)];
  2473. if ( info ) then
  2474. info.r = arg2;
  2475. info.g = arg3;
  2476. info.b = arg4;
  2477. ChatFrame_UpdateColorByID(self, info.id, info.r, info.g, info.b);
  2478. if ( strupper(arg1) == "WHISPER" ) then
  2479. info = ChatTypeInfo["REPLY"];
  2480. if ( info ) then
  2481. info.r = arg2;
  2482. info.g = arg3;
  2483. info.b = arg4;
  2484. ChatFrame_UpdateColorByID(self, info.id, info.r, info.g, info.b);
  2485. end
  2486. end
  2487. end
  2488. return true;
  2489. elseif ( event == "UPDATE_CHAT_COLOR_NAME_BY_CLASS" ) then
  2490. local info = ChatTypeInfo[strupper(arg1)];
  2491. if ( info ) then
  2492. info.colorNameByClass = arg2;
  2493. if ( strupper(arg1) == "WHISPER" ) then
  2494. info = ChatTypeInfo["REPLY"];
  2495. if ( info ) then
  2496. info.colorNameByClass = arg2;
  2497. end
  2498. end
  2499. end
  2500. return true;
  2501. elseif ( event == "VARIABLES_LOADED" ) then
  2502. if ( GetCVarBool("chatMouseScroll") ) then
  2503. self:SetScript("OnMouseWheel", FloatingChatFrame_OnMouseScroll);
  2504. self:EnableMouseWheel(true);
  2505. end
  2506. self:UnregisterEvent("VARIABLES_LOADED");
  2507. return true;
  2508. end
  2509. end
  2510. function ChatFrame_SystemEventHandler(self, event, ...)
  2511. if ( event == "TIME_PLAYED_MSG" ) then
  2512. local arg1, arg2 = ...;
  2513. ChatFrame_DisplayTimePlayed(self, arg1, arg2);
  2514. return true;
  2515. elseif ( event == "PLAYER_LEVEL_UP" ) then
  2516. local level, arg2, arg3, arg4, arg5, arg6, arg7, arg8 = ...;
  2517. LevelUpDisplay_ChatPrint(self, level, LEVEL_UP_TYPE_CHARACTER)
  2518. return true;
  2519. elseif ( event == "QUEST_TURNED_IN" ) then
  2520. local questID, xp, money = ...;
  2521. if questID == WORLD_QUESTS_AVAILABLE_QUEST_ID then
  2522. LevelUpDisplay_ChatPrint(self, nil, TOAST_WORLD_QUESTS_UNLOCKED)
  2523. end
  2524. return true;
  2525. elseif (event == "UNIT_LEVEL" ) then
  2526. local arg1 = ...;
  2527. if (arg1 == "pet" and UnitName("pet") ~= UNKNOWNOBJECT) then
  2528. LevelUpDisplay_ChatPrint(self, UnitLevel("pet"), LEVEL_UP_TYPE_PET);
  2529. end
  2530. elseif ( event == "CHARACTER_UPGRADE_SPELL_TIER_SET" ) then
  2531. local tierIndex = ...;
  2532. if (tierIndex > 0) then
  2533. LevelUpDisplay_ChatPrint(self, tierIndex, LEVEL_UP_TYPE_SPELL_BUCKET);
  2534. end
  2535. return true;
  2536. elseif ( event == "CHARACTER_POINTS_CHANGED" ) then
  2537. local arg1 = ...;
  2538. local info = ChatTypeInfo["SYSTEM"];
  2539. return true;
  2540. elseif ( event == "GUILD_MOTD" ) then
  2541. ChatFrame_DisplayGMOTD(self, ...);
  2542. return true;
  2543. elseif ( event == "ZONE_UNDER_ATTACK" ) then
  2544. local arg1 = ...;
  2545. local info = ChatTypeInfo["SYSTEM"];
  2546. self:AddMessage(format(ZONE_UNDER_ATTACK, arg1), info.r, info.g, info.b, info.id);
  2547. return true;
  2548. elseif ( event == "UPDATE_INSTANCE_INFO" ) then
  2549. if ( RaidFrame.hasRaidInfo ) then
  2550. local info = ChatTypeInfo["SYSTEM"];
  2551. if ( RaidFrame.slashCommand and GetNumSavedInstances() + GetNumSavedWorldBosses() == 0 and self == DEFAULT_CHAT_FRAME) then
  2552. self:AddMessage(NO_RAID_INSTANCES_SAVED, info.r, info.g, info.b, info.id);
  2553. RaidFrame.slashCommand = nil;
  2554. end
  2555. end
  2556. return true;
  2557. elseif ( event == "NEW_TITLE_EARNED" ) then
  2558. local arg1 = ...;
  2559. local info = ChatTypeInfo["SYSTEM"];
  2560. self:AddMessage(format(NEW_TITLE_EARNED, arg1), info.r, info.g, info.b, info.id);
  2561. return true;
  2562. elseif ( event == "OLD_TITLE_LOST" ) then
  2563. local arg1 = ...;
  2564. local info = ChatTypeInfo["SYSTEM"];
  2565. self:AddMessage(format(OLD_TITLE_LOST, arg1), info.r, info.g, info.b, info.id);
  2566. return true;
  2567. elseif ( event == "CHAT_SERVER_DISCONNECTED" ) then
  2568. local info = ChatTypeInfo["SYSTEM"];
  2569. local isInitialMessage = ...;
  2570. self:AddMessage(CHAT_SERVER_DISCONNECTED_MESSAGE, info.r, info.g, info.b, info.id);
  2571. return true;
  2572. elseif ( event == "CHAT_SERVER_RECONNECTED" ) then
  2573. local info = ChatTypeInfo["SYSTEM"];
  2574. self:AddMessage(CHAT_SERVER_RECONNECTED_MESSAGE, info.r, info.g, info.b, info.id);
  2575. return true;
  2576. elseif ( event == "BN_CONNECTED" ) then
  2577. local info = ChatTypeInfo["SYSTEM"];
  2578. self:AddMessage(BN_CHAT_CONNECTED, info.r, info.g, info.b, info.id);
  2579. elseif ( event == "BN_DISCONNECTED" ) then
  2580. local info = ChatTypeInfo["SYSTEM"];
  2581. self:AddMessage(BN_CHAT_DISCONNECTED, info.r, info.g, info.b, info.id);
  2582. elseif ( event == "PLAYER_REPORT_SUBMITTED" ) then
  2583. local guid = ...;
  2584. FCF_RemoveAllMessagesFromChanSender(self, guid);
  2585. return true;
  2586. end
  2587. end
  2588. function GetColoredName(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)
  2589. local chatType = strsub(event, 10);
  2590. if ( strsub(chatType, 1, 7) == "WHISPER" ) then
  2591. chatType = "WHISPER";
  2592. end
  2593. if ( strsub(chatType, 1, 7) == "CHANNEL" ) then
  2594. chatType = "CHANNEL"..arg8;
  2595. end
  2596. local info = ChatTypeInfo[chatType];
  2597. --ambiguate guild chat names
  2598. if (chatType == "GUILD") then
  2599. arg2 = Ambiguate(arg2, "guild")
  2600. else
  2601. arg2 = Ambiguate(arg2, "none")
  2602. end
  2603. if ( info and info.colorNameByClass and arg12 ) then
  2604. local localizedClass, englishClass, localizedRace, englishRace, sex = GetPlayerInfoByGUID(arg12)
  2605. if ( englishClass ) then
  2606. local classColorTable = RAID_CLASS_COLORS[englishClass];
  2607. if ( not classColorTable ) then
  2608. return arg2;
  2609. end
  2610. return string.format("\124cff%.2x%.2x%.2x", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255)..arg2.."\124r"
  2611. end
  2612. end
  2613. return arg2;
  2614. end
  2615. function RemoveExtraSpaces(str)
  2616. return string.gsub(str, " +", " "); --Replace all instances of 5+ spaces with only 4 spaces.
  2617. end
  2618. function RemoveNewlines(str)
  2619. return string.gsub(str, "\n", "");
  2620. end
  2621. function ChatFrame_DisplayGMOTD(frame, gmotd)
  2622. if ( gmotd and (strlen(gmotd) > 0) ) then
  2623. local info = ChatTypeInfo["GUILD"];
  2624. local string = format(GUILD_MOTD_TEMPLATE, gmotd);
  2625. frame:AddMessage(string, info.r, info.g, info.b, info.id);
  2626. end
  2627. end
  2628. function ChatFrame_GetMobileEmbeddedTexture(r, g, b)
  2629. r, g, b = floor(r * 255), floor(g * 255), floor(b * 255);
  2630. return format("|TInterface\\ChatFrame\\UI-ChatIcon-ArmoryChat:14:14:0:0:16:16:0:16:0:16:%d:%d:%d|t", r, g, b);
  2631. end
  2632. function ChatFrame_MessageEventHandler(self, event, ...)
  2633. if ( strsub(event, 1, 8) == "CHAT_MSG" ) then
  2634. local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17 = ...;
  2635. if (arg16) then
  2636. -- hiding sender in letterbox: do NOT even show in chat window (only shows in cinematic frame)
  2637. return true;
  2638. end
  2639. local type = strsub(event, 10);
  2640. local info = ChatTypeInfo[type];
  2641. local filter = false;
  2642. if ( chatFilters[event] ) then
  2643. local newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14;
  2644. for _, filterFunc in next, chatFilters[event] do
  2645. filter, newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14 = filterFunc(self, event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
  2646. if ( filter ) then
  2647. return true;
  2648. elseif ( newarg1 ) then
  2649. arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 = newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14;
  2650. end
  2651. end
  2652. end
  2653. local coloredName = GetColoredName(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
  2654. local channelLength = strlen(arg4);
  2655. local infoType = type;
  2656. if ( (strsub(type, 1, 7) == "CHANNEL") and (type ~= "CHANNEL_LIST") and ((arg1 ~= "INVITE") or (type ~= "CHANNEL_NOTICE_USER")) ) then
  2657. if ( arg1 == "WRONG_PASSWORD" ) then
  2658. local staticPopup = _G[StaticPopup_Visible("CHAT_CHANNEL_PASSWORD") or ""];
  2659. if ( staticPopup and strupper(staticPopup.data) == strupper(arg9) ) then
  2660. -- Don't display invalid password messages if we're going to prompt for a password (bug 102312)
  2661. return;
  2662. end
  2663. end
  2664. local found = 0;
  2665. for index, value in pairs(self.channelList) do
  2666. if ( channelLength > strlen(value) ) then
  2667. -- arg9 is the channel name without the number in front...
  2668. if ( ((arg7 > 0) and (self.zoneChannelList[index] == arg7)) or (strupper(value) == strupper(arg9)) ) then
  2669. found = 1;
  2670. infoType = "CHANNEL"..arg8;
  2671. info = ChatTypeInfo[infoType];
  2672. if ( (type == "CHANNEL_NOTICE") and (arg1 == "YOU_LEFT") ) then
  2673. self.channelList[index] = nil;
  2674. self.zoneChannelList[index] = nil;
  2675. end
  2676. break;
  2677. end
  2678. end
  2679. end
  2680. if ( (found == 0) or not info ) then
  2681. return true;
  2682. end
  2683. end
  2684. local chatGroup = Chat_GetChatCategory(type);
  2685. local chatTarget;
  2686. if ( chatGroup == "CHANNEL" ) then
  2687. chatTarget = tostring(arg8);
  2688. elseif ( chatGroup == "WHISPER" or chatGroup == "BN_WHISPER" ) then
  2689. if(not(strsub(arg2, 1, 2) == "|K")) then
  2690. chatTarget = strupper(arg2);
  2691. else
  2692. chatTarget = arg2;
  2693. end
  2694. end
  2695. if ( FCFManager_ShouldSuppressMessage(self, chatGroup, chatTarget) ) then
  2696. return true;
  2697. end
  2698. if ( chatGroup == "WHISPER" or chatGroup == "BN_WHISPER" ) then
  2699. if ( self.privateMessageList and not self.privateMessageList[strlower(arg2)] ) then
  2700. return true;
  2701. elseif ( self.excludePrivateMessageList and self.excludePrivateMessageList[strlower(arg2)]
  2702. and ( (chatGroup == "WHISPER" and GetCVar("whisperMode") ~= "popout_and_inline") or (chatGroup == "BN_WHISPER" and GetCVar("whisperMode") ~= "popout_and_inline") ) ) then
  2703. return true;
  2704. end
  2705. end
  2706. if (self.privateMessageList) then
  2707. -- Dedicated BN whisper windows need online/offline messages for only that player
  2708. if ( (chatGroup == "BN_INLINE_TOAST_ALERT" or chatGroup == "BN_WHISPER_PLAYER_OFFLINE") and not self.privateMessageList[strlower(arg2)] ) then
  2709. return true;
  2710. end
  2711. -- HACK to put certain system messages into dedicated whisper windows
  2712. if ( chatGroup == "SYSTEM") then
  2713. local matchFound = false;
  2714. local message = strlower(arg1);
  2715. for playerName, _ in pairs(self.privateMessageList) do
  2716. local playerNotFoundMsg = strlower(format(ERR_CHAT_PLAYER_NOT_FOUND_S, playerName));
  2717. local charOnlineMsg = strlower(format(ERR_FRIEND_ONLINE_SS, playerName, playerName));
  2718. local charOfflineMsg = strlower(format(ERR_FRIEND_OFFLINE_S, playerName));
  2719. if ( message == playerNotFoundMsg or message == charOnlineMsg or message == charOfflineMsg) then
  2720. matchFound = true;
  2721. break;
  2722. end
  2723. end
  2724. if (not matchFound) then
  2725. return true;
  2726. end
  2727. end
  2728. end
  2729. if ( type == "SYSTEM" or type == "SKILL" or type == "CURRENCY" or type == "MONEY" or
  2730. type == "OPENING" or type == "TRADESKILLS" or type == "PET_INFO" or type == "TARGETICONS" or type == "BN_WHISPER_PLAYER_OFFLINE") then
  2731. self:AddMessage(arg1, info.r, info.g, info.b, info.id);
  2732. elseif (type == "LOOT") then
  2733. -- Append [Share] hyperlink if this is a valid social item and you are the looter.
  2734. -- arg5 contains the name of the player who looted
  2735. if (C_Social.IsSocialEnabled() and UnitName("player") == arg5) then
  2736. local itemID, creationContext = GetItemInfoFromHyperlink(arg1);
  2737. if (itemID and C_Social.GetLastItem() == itemID) then
  2738. arg1 = arg1 .. " " .. Social_GetShareItemLink(itemID, creationContext, true);
  2739. end
  2740. end
  2741. self:AddMessage(arg1, info.r, info.g, info.b, info.id);
  2742. elseif ( strsub(type,1,7) == "COMBAT_" ) then
  2743. self:AddMessage(arg1, info.r, info.g, info.b, info.id);
  2744. elseif ( strsub(type,1,6) == "SPELL_" ) then
  2745. self:AddMessage(arg1, info.r, info.g, info.b, info.id);
  2746. elseif ( strsub(type,1,10) == "BG_SYSTEM_" ) then
  2747. self:AddMessage(arg1, info.r, info.g, info.b, info.id);
  2748. elseif ( strsub(type,1,11) == "ACHIEVEMENT" ) then
  2749. -- Append [Share] hyperlink
  2750. if (arg12 == UnitGUID("player") and C_Social.IsSocialEnabled()) then
  2751. local achieveID = GetAchievementInfoFromHyperlink(arg1);
  2752. if (achieveID) then
  2753. arg1 = arg1 .. " " .. Social_GetShareAchievementLink(achieveID, true);
  2754. end
  2755. end
  2756. self:AddMessage(format(arg1, "|Hplayer:"..arg2.."|h".."["..coloredName.."]".."|h"), info.r, info.g, info.b, info.id);
  2757. elseif ( strsub(type,1,18) == "GUILD_ACHIEVEMENT" ) then
  2758. local message = format(arg1, "|Hplayer:"..arg2.."|h".."["..coloredName.."]".."|h");
  2759. if (C_Social.IsSocialEnabled()) then
  2760. local achieveID = GetAchievementInfoFromHyperlink(arg1);
  2761. if (achieveID) then
  2762. local isGuildAchievement = select(12, GetAchievementInfo(achieveID));
  2763. if (isGuildAchievement) then
  2764. message = message .. " " .. Social_GetShareAchievementLink(achieveID, true);
  2765. end
  2766. end
  2767. end
  2768. self:AddMessage(message, info.r, info.g, info.b, info.id);
  2769. elseif ( type == "IGNORED" ) then
  2770. self:AddMessage(format(CHAT_IGNORED, arg2), info.r, info.g, info.b, info.id);
  2771. elseif ( type == "FILTERED" ) then
  2772. self:AddMessage(format(CHAT_FILTERED, arg2), info.r, info.g, info.b, info.id);
  2773. elseif ( type == "RESTRICTED" ) then
  2774. self:AddMessage(CHAT_RESTRICTED_TRIAL, info.r, info.g, info.b, info.id);
  2775. elseif ( type == "CHANNEL_LIST") then
  2776. if(channelLength > 0) then
  2777. self:AddMessage(format(_G["CHAT_"..type.."_GET"]..arg1, tonumber(arg8), arg4), info.r, info.g, info.b, info.id);
  2778. else
  2779. self:AddMessage(arg1, info.r, info.g, info.b, info.id);
  2780. end
  2781. elseif (type == "CHANNEL_NOTICE_USER") then
  2782. local globalstring = _G["CHAT_"..arg1.."_NOTICE_BN"];
  2783. if ( not globalstring ) then
  2784. globalstring = _G["CHAT_"..arg1.."_NOTICE"];
  2785. end
  2786. if(strlen(arg5) > 0) then
  2787. -- TWO users in this notice (E.G. x kicked y)
  2788. self:AddMessage(format(globalstring, arg8, arg4, arg2, arg5), info.r, info.g, info.b, info.id);
  2789. elseif ( arg1 == "INVITE" ) then
  2790. self:AddMessage(format(globalstring, arg4, arg2), info.r, info.g, info.b, info.id);
  2791. else
  2792. self:AddMessage(format(globalstring, arg8, arg4, arg2), info.r, info.g, info.b, info.id);
  2793. end
  2794. if ( arg1 == "INVITE" and GetCVarBool("blockChannelInvites") ) then
  2795. self:AddMessage(CHAT_MSG_BLOCK_CHAT_CHANNEL_INVITE, info.r, info.g, info.b, info.id);
  2796. end
  2797. elseif (type == "CHANNEL_NOTICE") then
  2798. local globalstring = _G["CHAT_"..arg1.."_NOTICE_BN"];
  2799. if( arg1 == "TRIAL_RESTRICTED" ) then
  2800. globalstring = CHAT_TRIAL_RESTRICTED_NOTICE_TRIAL;
  2801. else
  2802. if ( not globalstring ) then
  2803. globalstring = _G["CHAT_"..arg1.."_NOTICE"];
  2804. end
  2805. end
  2806. local accessID = ChatHistory_GetAccessID(Chat_GetChatCategory(type), arg8);
  2807. local typeID = ChatHistory_GetAccessID(infoType, arg8, arg12);
  2808. self:AddMessage(format(globalstring, arg8, arg4), info.r, info.g, info.b, info.id, accessID, typeID);
  2809. elseif ( type == "BN_INLINE_TOAST_ALERT" ) then
  2810. local globalstring = _G["BN_INLINE_TOAST_"..arg1];
  2811. local message;
  2812. if ( arg1 == "FRIEND_REQUEST" ) then
  2813. message = globalstring;
  2814. elseif ( arg1 == "FRIEND_PENDING" ) then
  2815. message = format(BN_INLINE_TOAST_FRIEND_PENDING, BNGetNumFriendInvites());
  2816. elseif ( arg1 == "FRIEND_REMOVED" or arg1 == "BATTLETAG_FRIEND_REMOVED" ) then
  2817. message = format(globalstring, arg2);
  2818. elseif ( arg1 == "FRIEND_ONLINE" or arg1 == "FRIEND_OFFLINE") then
  2819. local _, accountName, battleTag, _, characterName, _, client = BNGetFriendInfoByID(arg13);
  2820. if (client and client ~= "") then
  2821. local _, _, battleTag = BNGetFriendInfoByID(arg13);
  2822. characterName = BNet_GetValidatedCharacterName(characterName, battleTag, client) or "";
  2823. local characterNameText = BNet_GetClientEmbeddedTexture(client, 14)..characterName;
  2824. local playerLink = format("|HBNplayer:%s:%s:%s:%s:%s|h[%s] (%s)|h", arg2, arg13, arg11, Chat_GetChatCategory(type), 0, arg2, characterNameText);
  2825. message = format(globalstring, playerLink);
  2826. else
  2827. local playerLink = format("|HBNplayer:%s:%s:%s:%s:%s|h[%s]|h", arg2, arg13, arg11, Chat_GetChatCategory(type), 0, arg2);
  2828. message = format(globalstring, playerLink);
  2829. end
  2830. else
  2831. local playerLink = format("|HBNplayer:%s:%s:%s:%s:%s|h[%s]|h", arg2, arg13, arg11, Chat_GetChatCategory(type), 0, arg2);
  2832. message = format(globalstring, playerLink);
  2833. end
  2834. self:AddMessage(message, info.r, info.g, info.b, info.id);
  2835. elseif ( type == "BN_INLINE_TOAST_BROADCAST" ) then
  2836. if ( arg1 ~= "" ) then
  2837. arg1 = RemoveExtraSpaces(arg1);
  2838. arg1 = RemoveNewlines(arg1);
  2839. local playerLink = format("|HBNplayer:%s:%s:%s:%s:%s|h[%s]|h", arg2, arg13, arg11, Chat_GetChatCategory(type), 0, arg2);
  2840. self:AddMessage(format(BN_INLINE_TOAST_BROADCAST, playerLink, arg1), info.r, info.g, info.b, info.id);
  2841. end
  2842. elseif ( type == "BN_INLINE_TOAST_BROADCAST_INFORM" ) then
  2843. if ( arg1 ~= "" ) then
  2844. arg1 = RemoveExtraSpaces(arg1);
  2845. self:AddMessage(BN_INLINE_TOAST_BROADCAST_INFORM, info.r, info.g, info.b, info.id);
  2846. end
  2847. else
  2848. local body;
  2849. local _, fontHeight = FCF_GetChatWindowInfo(self:GetID());
  2850. if ( fontHeight == 0 ) then
  2851. --fontHeight will be 0 if it's still at the default (14)
  2852. fontHeight = 14;
  2853. end
  2854. -- Add AFK/DND flags
  2855. local pflag;
  2856. if(strlen(arg6) > 0) then
  2857. if ( arg6 == "GM" ) then
  2858. --If it was a whisper, dispatch it to the GMChat addon.
  2859. if ( type == "WHISPER" ) then
  2860. return;
  2861. end
  2862. --Add Blizzard Icon, this was sent by a GM
  2863. pflag = "|TInterface\\ChatFrame\\UI-ChatIcon-Blizz:12:20:0:0:32:16:4:28:0:16|t ";
  2864. elseif ( arg6 == "DEV" ) then
  2865. --Add Blizzard Icon, this was sent by a Dev
  2866. pflag = "|TInterface\\ChatFrame\\UI-ChatIcon-Blizz:12:20:0:0:32:16:4:28:0:16|t ";
  2867. else
  2868. pflag = _G["CHAT_FLAG_"..arg6];
  2869. end
  2870. else
  2871. pflag = "";
  2872. end
  2873. if ( type == "WHISPER_INFORM" and GMChatFrame_IsGM and GMChatFrame_IsGM(arg2) ) then
  2874. return;
  2875. end
  2876. local showLink = 1;
  2877. if ( strsub(type, 1, 7) == "MONSTER" or strsub(type, 1, 9) == "RAID_BOSS") then
  2878. showLink = nil;
  2879. else
  2880. arg1 = gsub(arg1, "%%", "%%%%");
  2881. end
  2882. -- Search for icon links and replace them with texture links.
  2883. for tag in string.gmatch(arg1, "%b{}") do
  2884. local term = strlower(string.gsub(tag, "[{}]", ""));
  2885. -- If arg17 is true, don't convert to raid icons
  2886. if ( not arg17 and ICON_TAG_LIST[term] and ICON_LIST[ICON_TAG_LIST[term]] ) then
  2887. arg1 = string.gsub(arg1, tag, ICON_LIST[ICON_TAG_LIST[term]] .. "0|t");
  2888. elseif ( GROUP_TAG_LIST[term] ) then
  2889. local groupIndex = GROUP_TAG_LIST[term];
  2890. local groupList = "[";
  2891. for i=1, GetNumGroupMembers() do
  2892. local name, rank, subgroup, level, class, classFileName = GetRaidRosterInfo(i);
  2893. if ( name and subgroup == groupIndex ) then
  2894. local classColorTable = RAID_CLASS_COLORS[classFileName];
  2895. if ( classColorTable ) then
  2896. name = string.format("\124cff%.2x%.2x%.2x%s\124r", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255, name);
  2897. end
  2898. groupList = groupList..(groupList == "[" and "" or PLAYER_LIST_DELIMITER)..name;
  2899. end
  2900. end
  2901. groupList = groupList.."]";
  2902. arg1 = string.gsub(arg1, tag, groupList);
  2903. end
  2904. end
  2905. --Remove groups of many spaces
  2906. arg1 = RemoveExtraSpaces(arg1);
  2907. local playerLink;
  2908. if ( type ~= "BN_WHISPER" and type ~= "BN_WHISPER_INFORM" ) then
  2909. playerLink = "|Hplayer:"..arg2..":"..arg11..":"..chatGroup..(chatTarget and ":"..chatTarget or "").."|h";
  2910. else
  2911. playerLink = "|HBNplayer:"..arg2..":"..arg13..":"..arg11..":"..chatGroup..(chatTarget and ":"..chatTarget or "").."|h";
  2912. end
  2913. local message = arg1;
  2914. if ( arg14 ) then --isMobile
  2915. message = ChatFrame_GetMobileEmbeddedTexture(info.r, info.g, info.b)..message;
  2916. end
  2917. local relevantDefaultLanguage = self.defaultLanguage;
  2918. if ( (type == "SAY") or (type == "YELL") ) then
  2919. relevantDefaultLanguage = self.alternativeDefaultLanguage;
  2920. end
  2921. if ( (strlen(arg3) > 0) and (arg3 ~= relevantDefaultLanguage) ) then
  2922. local languageHeader = "["..arg3.."] ";
  2923. if ( showLink and (strlen(arg2) > 0) ) then
  2924. body = format(_G["CHAT_"..type.."_GET"]..languageHeader..message, pflag..playerLink.."["..coloredName.."]".."|h");
  2925. else
  2926. body = format(_G["CHAT_"..type.."_GET"]..languageHeader..message, pflag..arg2);
  2927. end
  2928. else
  2929. if ( not showLink or strlen(arg2) == 0 ) then
  2930. if ( type == "TEXT_EMOTE" ) then
  2931. body = message;
  2932. else
  2933. body = format(_G["CHAT_"..type.."_GET"]..message, pflag..arg2, arg2);
  2934. end
  2935. else
  2936. if ( type == "EMOTE" ) then
  2937. body = format(_G["CHAT_"..type.."_GET"]..message, pflag..playerLink..coloredName.."|h");
  2938. elseif ( type == "TEXT_EMOTE") then
  2939. body = string.gsub(message, arg2, pflag..playerLink..coloredName.."|h", 1);
  2940. elseif (type == "GUILD_ITEM_LOOTED") then
  2941. body = string.gsub(message, "$s", "|Hplayer:"..arg2.."|h".."["..coloredName.."]".."|h");
  2942. else
  2943. body = format(_G["CHAT_"..type.."_GET"]..message, pflag..playerLink.."["..coloredName.."]".."|h");
  2944. end
  2945. end
  2946. end
  2947. -- Add Channel
  2948. arg4 = gsub(arg4, "%s%-%s.*", "");
  2949. if(channelLength > 0) then
  2950. body = "|Hchannel:channel:"..arg8.."|h["..arg4.."]|h "..body;
  2951. end
  2952. --Add Timestamps
  2953. if ( CHAT_TIMESTAMP_FORMAT ) then
  2954. body = BetterDate(CHAT_TIMESTAMP_FORMAT, time())..body;
  2955. end
  2956. local accessID = ChatHistory_GetAccessID(chatGroup, chatTarget);
  2957. local typeID = ChatHistory_GetAccessID(infoType, chatTarget, arg12 or arg13);
  2958. self:AddMessage(body, info.r, info.g, info.b, info.id, accessID, typeID);
  2959. end
  2960. if ( type == "WHISPER" or type == "BN_WHISPER" ) then
  2961. --BN_WHISPER FIXME
  2962. ChatEdit_SetLastTellTarget(arg2, type);
  2963. if ( self.tellTimer and (GetTime() > self.tellTimer) ) then
  2964. PlaySound("TellMessage");
  2965. end
  2966. self.tellTimer = GetTime() + CHAT_TELL_ALERT_TIME;
  2967. --FCF_FlashTab(self);
  2968. FlashClientIcon();
  2969. end
  2970. if ( not self:IsShown() ) then
  2971. if ( (self == DEFAULT_CHAT_FRAME and info.flashTabOnGeneral) or (self ~= DEFAULT_CHAT_FRAME and info.flashTab) ) then
  2972. if ( not CHAT_OPTIONS.HIDE_FRAME_ALERTS or type == "WHISPER" or type == "BN_WHISPER" ) then --BN_WHISPER FIXME
  2973. if (not FCFManager_ShouldSuppressMessageFlash(self, chatGroup, chatTarget) ) then
  2974. FCF_StartAlertFlash(self);
  2975. end
  2976. end
  2977. end
  2978. end
  2979. return true;
  2980. end
  2981. end
  2982. function ChatFrame_AddMessageEventFilter (event, filter)
  2983. assert(event and filter);
  2984. if ( chatFilters[event] ) then
  2985. -- Only allow a filter to be added once
  2986. for index, filterFunc in next, chatFilters[event] do
  2987. if ( filterFunc == filter ) then
  2988. return;
  2989. end
  2990. end
  2991. else
  2992. chatFilters[event] = {};
  2993. end
  2994. tinsert(chatFilters[event], filter);
  2995. end
  2996. function ChatFrame_RemoveMessageEventFilter (event, filter)
  2997. assert(event and filter);
  2998. if ( chatFilters[event] ) then
  2999. for index, filterFunc in next, chatFilters[event] do
  3000. if ( filterFunc == filter ) then
  3001. tremove(chatFilters[event], index);
  3002. end
  3003. end
  3004. if ( #chatFilters[event] == 0 ) then
  3005. chatFilters[event] = nil;
  3006. end
  3007. end
  3008. end
  3009. function ChatFrame_GetMessageEventFilters (event)
  3010. assert(event);
  3011. return chatFilters[event];
  3012. end
  3013. function ChatFrame_OnUpdate(self, elapsedSec)
  3014. local flash = _G[self:GetName().."ButtonFrameBottomButtonFlash"];
  3015. if ( not flash ) then
  3016. return;
  3017. end
  3018. if ( self:AtBottom() ) then
  3019. if ( flash:IsShown() ) then
  3020. flash:Hide();
  3021. end
  3022. return;
  3023. end
  3024. local flashTimer = self.flashTimer + elapsedSec;
  3025. if ( flashTimer < CHAT_BUTTON_FLASH_TIME ) then
  3026. self.flashTimer = flashTimer;
  3027. return;
  3028. end
  3029. while ( flashTimer >= CHAT_BUTTON_FLASH_TIME ) do
  3030. flashTimer = flashTimer - CHAT_BUTTON_FLASH_TIME;
  3031. end
  3032. self.flashTimer = flashTimer;
  3033. if ( flash:IsShown() ) then
  3034. flash:Hide();
  3035. else
  3036. flash:Show();
  3037. end
  3038. end
  3039. function ChatFrame_OnHyperlinkShow(self, link, text, button)
  3040. SetItemRef(link, text, button, self);
  3041. end
  3042. function ChatFrame_OnMouseWheel(value)
  3043. if ( value > 0 ) then
  3044. SELECTED_DOCK_FRAME:ScrollUp();
  3045. elseif ( value < 0 ) then
  3046. SELECTED_DOCK_FRAME:ScrollDown();
  3047. end
  3048. end
  3049. function ChatFrame_OpenChat(text, chatFrame)
  3050. local editBox = ChatEdit_ChooseBoxForSend(chatFrame);
  3051. ChatEdit_ActivateChat(editBox);
  3052. editBox.setText = 1;
  3053. editBox.text = text;
  3054. if ( editBox:GetAttribute("chatType") == editBox:GetAttribute("stickyType") ) then
  3055. if ( (editBox:GetAttribute("stickyType") == "PARTY") and (not IsInGroup(LE_PARTY_CATEGORY_HOME)) or
  3056. (editBox:GetAttribute("stickyType") == "RAID") and (not IsInRaid(LE_PARTY_CATEGORY_HOME)) or
  3057. (editBox:GetAttribute("stickyType") == "INSTANCE_CHAT") and (not IsInGroup(LE_PARTY_CATEGORY_INSTANCE))) then
  3058. editBox:SetAttribute("chatType", "SAY");
  3059. end
  3060. end
  3061. ChatEdit_UpdateHeader(editBox);
  3062. return editBox;
  3063. end
  3064. function ChatFrame_ScrollToBottom()
  3065. SELECTED_DOCK_FRAME:ScrollToBottom();
  3066. end
  3067. function ChatFrame_ScrollUp()
  3068. SELECTED_DOCK_FRAME:ScrollUp();
  3069. end
  3070. function ChatFrame_ScrollDown()
  3071. SELECTED_DOCK_FRAME:ScrollDown();
  3072. end
  3073. --used for chatframe and combat log
  3074. function MessageFrameScrollButton_OnLoad(self)
  3075. self.clickDelay = MESSAGE_SCROLLBUTTON_INITIAL_DELAY;
  3076. self:RegisterForClicks("LeftButtonDown", "LeftButtonUp", "RightButtonUp", "RightButtonDown");
  3077. end
  3078. --Controls scrolling for chatframe and combat log
  3079. function MessageFrameScrollButton_OnUpdate(self, elapsed)
  3080. if (self:GetButtonState() == "PUSHED") then
  3081. self.clickDelay = self.clickDelay - elapsed;
  3082. if ( self.clickDelay < 0 ) then
  3083. local name = self:GetName();
  3084. if ( name == self:GetParent():GetName().."DownButton" ) then
  3085. self:GetParent():GetParent():ScrollDown();
  3086. elseif ( name == self:GetParent():GetName().."UpButton" ) then
  3087. self:GetParent():GetParent():ScrollUp();
  3088. end
  3089. self.clickDelay = MESSAGE_SCROLLBUTTON_SCROLL_DELAY;
  3090. end
  3091. end
  3092. end
  3093. function ChatFrame_OpenMenu()
  3094. ChatMenu:Show();
  3095. end
  3096. function ChatFrameMenu_UpdateAnchorPoint()
  3097. --Update the menu anchor point
  3098. if ( FCF_GetButtonSide(DEFAULT_CHAT_FRAME) == "right" ) then
  3099. ChatMenu:ClearAllPoints();
  3100. ChatMenu:SetPoint("BOTTOMRIGHT", ChatFrameMenuButton, "TOPLEFT");
  3101. else
  3102. ChatMenu:ClearAllPoints();
  3103. ChatMenu:SetPoint("BOTTOMLEFT", ChatFrameMenuButton, "TOPRIGHT");
  3104. end
  3105. end
  3106. function ChatFrame_SendTell(name, chatFrame)
  3107. local editBox = ChatEdit_ChooseBoxForSend(chatFrame);
  3108. --DEBUG FIXME - for now, we're not going to remove spaces from names. We need to make sure X-server still works.
  3109. -- Remove spaces from the server name for slash command parsing
  3110. --name = gsub(name, " ", "");
  3111. if ( editBox ~= ChatEdit_GetActiveWindow() ) then
  3112. ChatFrame_OpenChat(SLASH_WHISPER1.." "..name.." ", chatFrame);
  3113. else
  3114. editBox:SetText(SLASH_WHISPER1.." "..name.." ");
  3115. end
  3116. ChatEdit_ParseText(editBox, 0);
  3117. end
  3118. function ChatFrame_SendSmartTell(name, chatFrame)
  3119. local editBox = ChatEdit_ChooseBoxForSend(chatFrame);
  3120. --DEBUG FIXME - for now, we're not going to remove spaces from names. We need to make sure X-server still works.
  3121. -- Remove spaces from the server name for slash command parsing
  3122. --name = gsub(name, " ", "");
  3123. if ( editBox ~= ChatEdit_GetActiveWindow() ) then
  3124. ChatFrame_OpenChat(SLASH_SMART_WHISPER1.." "..name.." ", chatFrame);
  3125. else
  3126. editBox:SetText(SLASH_SMART_WHISPER1.." "..name.." ");
  3127. end
  3128. ChatEdit_ParseText(editBox, 0);
  3129. end
  3130. function ChatFrame_ReplyTell(chatFrame)
  3131. local editBox = ChatEdit_ChooseBoxForSend(chatFrame);
  3132. local lastTell, lastTellType = ChatEdit_GetLastTellTarget();
  3133. if ( lastTell ) then
  3134. --BN_WHISPER FIXME
  3135. editBox:SetAttribute("chatType", lastTellType);
  3136. editBox:SetAttribute("tellTarget", lastTell);
  3137. ChatEdit_UpdateHeader(editBox);
  3138. if ( editBox ~= ChatEdit_GetActiveWindow() ) then
  3139. ChatFrame_OpenChat("", chatFrame);
  3140. end
  3141. else
  3142. -- Error message
  3143. end
  3144. end
  3145. function ChatFrame_ReplyTell2(chatFrame)
  3146. local editBox = ChatEdit_ChooseBoxForSend(chatFrame);
  3147. local lastTold, lastToldType = ChatEdit_GetLastToldTarget();
  3148. if ( lastTold ) then
  3149. --BN_WHISPER FIXME
  3150. editBox:SetAttribute("chatType", lastToldType);
  3151. editBox:SetAttribute("tellTarget", lastTold);
  3152. ChatEdit_UpdateHeader(editBox);
  3153. if ( editBox ~= ChatEdit_GetActiveWindow() ) then
  3154. ChatFrame_OpenChat("", chatFrame);
  3155. end
  3156. else
  3157. -- Error message
  3158. end
  3159. end
  3160. function ChatFrame_DisplayHelpTextSimple(frame)
  3161. if ( not frame ) then
  3162. return;
  3163. end
  3164. local info = ChatTypeInfo["SYSTEM"];
  3165. frame:AddMessage(HELP_TEXT_SIMPLE, info.r, info.g, info.b, info.id);
  3166. end
  3167. function ChatFrame_DisplayHelpText(frame)
  3168. if ( not frame ) then
  3169. return;
  3170. end
  3171. local info = ChatTypeInfo["SYSTEM"];
  3172. local i = 1;
  3173. local text = _G["HELP_TEXT_LINE"..i];
  3174. while text do
  3175. frame:AddMessage(text, info.r, info.g, info.b, info.id);
  3176. i = i + 1;
  3177. text = _G["HELP_TEXT_LINE"..i];
  3178. end
  3179. end
  3180. function ChatFrame_DisplayMacroHelpText(frame)
  3181. if ( not frame ) then
  3182. return;
  3183. end
  3184. local info = ChatTypeInfo["SYSTEM"];
  3185. local i = 1;
  3186. local text = _G["MACRO_HELP_TEXT_LINE"..i];
  3187. while text do
  3188. frame:AddMessage(text, info.r, info.g, info.b, info.id);
  3189. i = i + 1;
  3190. text = _G["MACRO_HELP_TEXT_LINE"..i];
  3191. end
  3192. end
  3193. function ChatFrame_DisplayChatHelp(frame)
  3194. if ( not frame ) then
  3195. return;
  3196. end
  3197. local info = ChatTypeInfo["SYSTEM"];
  3198. local i = 1;
  3199. local text = _G["CHAT_HELP_TEXT_LINE"..i];
  3200. while text do
  3201. frame:AddMessage(text, info.r, info.g, info.b, info.id);
  3202. i = i + 1;
  3203. -- hack fix for removing a line without causing localization problems
  3204. if ( i == 15 ) then
  3205. i = i + 1;
  3206. end
  3207. text = _G["CHAT_HELP_TEXT_LINE"..i];
  3208. end
  3209. end
  3210. function ChatFrame_DisplayGuildHelp(frame)
  3211. if ( not frame ) then
  3212. return;
  3213. end
  3214. local info = ChatTypeInfo["SYSTEM"];
  3215. local i = 1;
  3216. local text = _G["GUILD_HELP_TEXT_LINE"..i];
  3217. while text do
  3218. frame:AddMessage(text, info.r, info.g, info.b, info.id);
  3219. i = i + 1;
  3220. text = _G["GUILD_HELP_TEXT_LINE"..i];
  3221. end
  3222. end
  3223. function ChatFrame_DisplayGameTime(frame)
  3224. if ( not frame ) then
  3225. return;
  3226. end
  3227. local info = ChatTypeInfo["SYSTEM"];
  3228. frame:AddMessage(GameTime_GetGameTime(true), info.r, info.g, info.b, info.id);
  3229. end
  3230. function ChatFrame_TimeBreakDown(time)
  3231. local days = floor(time / (60 * 60 * 24));
  3232. local hours = floor((time - (days * (60 * 60 * 24))) / (60 * 60));
  3233. local minutes = floor((time - (days * (60 * 60 * 24)) - (hours * (60 * 60))) / 60);
  3234. local seconds = mod(time, 60);
  3235. return days, hours, minutes, seconds;
  3236. end
  3237. function ChatFrame_DisplayTimePlayed(self, totalTime, levelTime)
  3238. local info = ChatTypeInfo["SYSTEM"];
  3239. local d;
  3240. local h;
  3241. local m;
  3242. local s;
  3243. d, h, m, s = ChatFrame_TimeBreakDown(totalTime);
  3244. local string = format(TIME_PLAYED_TOTAL, format(TIME_DAYHOURMINUTESECOND, d, h, m, s));
  3245. self:AddMessage(string, info.r, info.g, info.b, info.id);
  3246. d, h, m, s = ChatFrame_TimeBreakDown(levelTime);
  3247. local string = format(TIME_PLAYED_LEVEL, format(TIME_DAYHOURMINUTESECOND, d, h, m, s));
  3248. self:AddMessage(string, info.r, info.g, info.b, info.id);
  3249. end
  3250. function ChatFrame_ChatPageUp()
  3251. SELECTED_CHAT_FRAME:PageUp();
  3252. end
  3253. function ChatFrame_ChatPageDown()
  3254. SELECTED_CHAT_FRAME:PageDown();
  3255. end
  3256. function ChatFrame_DisplayUsageError(messageTag)
  3257. ChatFrame_DisplaySystemMessageInPrimary(messageTag);
  3258. end
  3259. function ChatFrame_DisplaySystemMessageInPrimary(messageTag)
  3260. local info = ChatTypeInfo["SYSTEM"];
  3261. DEFAULT_CHAT_FRAME:AddMessage(messageTag, info.r, info.g, info.b, info.id);
  3262. end
  3263. -- ChatEdit functions
  3264. local ChatEdit_LastTell = {};
  3265. local ChatEdit_LastTellType = {};
  3266. for i = 1, NUM_REMEMBERED_TELLS, 1 do
  3267. ChatEdit_LastTell[i] = "";
  3268. ChatEdit_LastTellType[i] = "";
  3269. end
  3270. local ChatEdit_LastTold;
  3271. local ChatEdit_LastToldType;
  3272. function ChatEdit_OnLoad(self)
  3273. self:SetFrameLevel(self.chatFrame:GetFrameLevel()+1);
  3274. self:SetAttribute("chatType", "SAY");
  3275. self:SetAttribute("stickyType", "SAY");
  3276. self.chatLanguage = GetDefaultLanguage();
  3277. self:RegisterEvent("UPDATE_CHAT_COLOR");
  3278. self.addSpaceToAutoComplete = true;
  3279. self.addHighlightedText = true;
  3280. if ( CHAT_OPTIONS.ONE_EDIT_AT_A_TIME == "many" ) then
  3281. self:Show();
  3282. end
  3283. self:SetParent(UIParent);
  3284. end
  3285. function ChatEdit_OnEvent(self, event, ...)
  3286. if ( event == "UPDATE_CHAT_COLOR" ) then
  3287. local chatType = ...;
  3288. if ( self:IsShown() ) then
  3289. ChatEdit_UpdateHeader(self);
  3290. end
  3291. end
  3292. end
  3293. function ChatEdit_OnUpdate(self, elapsedSec)
  3294. if ( self.setText == 1) then
  3295. self:SetText(self.text);
  3296. self.setText = 0;
  3297. ChatEdit_ParseText(self, 0, true);
  3298. end
  3299. end
  3300. function ChatEdit_OnShow(self)
  3301. ChatEdit_ResetChatType(self);
  3302. end
  3303. function ChatEdit_ResetChatType(self)
  3304. if ( self:GetAttribute("chatType") == "PARTY" and (not IsInGroup(LE_PARTY_CATEGORY_HOME)) ) then
  3305. self:SetAttribute("chatType", "SAY");
  3306. end
  3307. if ( self:GetAttribute("chatType") == "RAID" and (not IsInRaid(LE_PARTY_CATEGORY_HOME)) ) then
  3308. self:SetAttribute("chatType", "SAY");
  3309. end
  3310. if ( (self:GetAttribute("chatType") == "GUILD" or self:GetAttribute("chatType") == "OFFICER") and not IsInGuild() ) then
  3311. self:SetAttribute("chatType", "SAY");
  3312. end
  3313. if ( self:GetAttribute("chatType") == "INSTANCE_CHAT" and (not IsInGroup(LE_PARTY_CATEGORY_INSTANCE)) ) then
  3314. self:SetAttribute("chatType", "SAY");
  3315. end
  3316. self.lastTabComplete = nil;
  3317. self.tabCompleteText = nil;
  3318. self.tabCompleteTableIndex = 1;
  3319. ChatEdit_UpdateHeader(self);
  3320. ChatEdit_OnInputLanguageChanged(self);
  3321. --[[if ( CHAT_OPTIONS.ONE_EDIT_AT_A_TIME == "old") then
  3322. self:SetFocus();
  3323. end]]
  3324. end
  3325. function ChatEdit_OnHide(self)
  3326. if ( ACTIVE_CHAT_EDIT_BOX == self ) then
  3327. ChatEdit_DeactivateChat(self);
  3328. end
  3329. if ( LAST_ACTIVE_CHAT_EDIT_BOX == self and self:IsShown() ) then --Our parent was hidden. Let's find a new default frame.
  3330. --We'll go with the active dock frame since people think of that as the primary chat.
  3331. ChatEdit_SetLastActiveWindow(FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK).editBox);
  3332. end
  3333. end
  3334. function ChatEdit_OnEditFocusGained(self)
  3335. ChatEdit_ActivateChat(self);
  3336. end
  3337. function ChatEdit_OnEditFocusLost(self)
  3338. AutoCompleteEditBox_OnEditFocusLost(self);
  3339. ChatEdit_DeactivateChat(self);
  3340. end
  3341. function ChatEdit_ActivateChat(editBox)
  3342. if ( ACTIVE_CHAT_EDIT_BOX and ACTIVE_CHAT_EDIT_BOX ~= editBox ) then
  3343. ChatEdit_DeactivateChat(ACTIVE_CHAT_EDIT_BOX);
  3344. end
  3345. ACTIVE_CHAT_EDIT_BOX = editBox;
  3346. ChatEdit_SetLastActiveWindow(editBox);
  3347. --Stop any sort of fading
  3348. UIFrameFadeRemoveFrame(editBox);
  3349. editBox:Show();
  3350. editBox:SetFocus();
  3351. editBox:SetFrameStrata("DIALOG");
  3352. editBox:Raise();
  3353. editBox.header:Show();
  3354. editBox.focusLeft:Show();
  3355. editBox.focusRight:Show();
  3356. editBox.focusMid:Show();
  3357. editBox:SetAlpha(1.0);
  3358. ChatEdit_UpdateHeader(editBox);
  3359. if ( CHAT_SHOW_IME ) then
  3360. _G[editBox:GetName().."Language"]:Show();
  3361. end
  3362. end
  3363. local function ChatEdit_SetDeactivated(editBox)
  3364. editBox:SetFrameStrata("LOW");
  3365. if ( GetCVar("chatStyle") == "classic" and not editBox.isGM ) then
  3366. editBox:Hide();
  3367. else
  3368. editBox:SetText("");
  3369. editBox.header:Hide();
  3370. if ( not editBox.isGM ) then
  3371. editBox:SetAlpha(0.35);
  3372. end
  3373. editBox:ClearFocus();
  3374. editBox.focusLeft:Hide();
  3375. editBox.focusRight:Hide();
  3376. editBox.focusMid:Hide();
  3377. ChatEdit_ResetChatTypeToSticky(editBox);
  3378. ChatEdit_ResetChatType(editBox);
  3379. end
  3380. _G[editBox:GetName().."Language"]:Hide();
  3381. end
  3382. function ChatEdit_DeactivateChat(editBox)
  3383. if ( ACTIVE_CHAT_EDIT_BOX == editBox ) then
  3384. ACTIVE_CHAT_EDIT_BOX = nil;
  3385. end
  3386. ChatEdit_SetDeactivated(editBox);
  3387. end
  3388. function ChatEdit_ChooseBoxForSend(preferredChatFrame)
  3389. if ( GetCVar("chatStyle") == "classic" ) then
  3390. return DEFAULT_CHAT_FRAME.editBox;
  3391. elseif ( preferredChatFrame and preferredChatFrame:IsShown() ) then
  3392. return preferredChatFrame.editBox;
  3393. elseif ( ChatEdit_GetLastActiveWindow() and ChatEdit_GetLastActiveWindow():GetParent():IsShown() ) then
  3394. return ChatEdit_GetLastActiveWindow();
  3395. else
  3396. return FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK).editBox;
  3397. end
  3398. end
  3399. function ChatEdit_SetLastActiveWindow(editBox)
  3400. local previousValue = LAST_ACTIVE_CHAT_EDIT_BOX;
  3401. if ( LAST_ACTIVE_CHAT_EDIT_BOX and not LAST_ACTIVE_CHAT_EDIT_BOX.isGM and LAST_ACTIVE_CHAT_EDIT_BOX ~= editBox ) then
  3402. if ( GetCVar("chatStyle") == "im" ) then
  3403. LAST_ACTIVE_CHAT_EDIT_BOX:Hide();
  3404. end
  3405. end
  3406. LAST_ACTIVE_CHAT_EDIT_BOX = editBox;
  3407. if ( editBox and GetCVar("chatStyle") == "im" and ACTIVE_CHAT_EDIT_BOX ~= editBox ) then
  3408. editBox:Show();
  3409. ChatEdit_SetDeactivated(editBox);
  3410. end
  3411. if ( previousValue ) then
  3412. FCFClickAnywhereButton_UpdateState(previousValue.chatFrame.clickAnywhereButton);
  3413. end
  3414. if ( editBox ) then
  3415. FCFClickAnywhereButton_UpdateState(editBox.chatFrame.clickAnywhereButton);
  3416. end
  3417. end
  3418. function ChatEdit_GetActiveWindow()
  3419. return ACTIVE_CHAT_EDIT_BOX;
  3420. end
  3421. function ChatEdit_GetLastActiveWindow()
  3422. return LAST_ACTIVE_CHAT_EDIT_BOX;
  3423. end
  3424. function ChatEdit_FocusActiveWindow()
  3425. local active = ChatEdit_GetActiveWindow()
  3426. if ( active ) then
  3427. ChatEdit_ActivateChat(active);
  3428. end
  3429. end
  3430. function ChatEdit_InsertLink(text)
  3431. if ( not text ) then
  3432. return false;
  3433. end
  3434. local activeWindow = ChatEdit_GetActiveWindow();
  3435. if ( activeWindow ) then
  3436. -- add a space for proper parsing
  3437. activeWindow:Insert(" "..text);
  3438. return true;
  3439. end
  3440. if ( BrowseName and BrowseName:IsVisible() ) then
  3441. local item;
  3442. if ( strfind(text, "battlepet:") ) then
  3443. local petName = strmatch(text, "%[(.+)%]");
  3444. item = petName;
  3445. elseif ( strfind(text, "item:", 1, true) ) then
  3446. item = GetItemInfo(text);
  3447. end
  3448. if ( item ) then
  3449. BrowseName:SetText(item);
  3450. return true;
  3451. end
  3452. end
  3453. if ( MacroFrameText and MacroFrameText:HasFocus() ) then
  3454. local item;
  3455. if ( strfind(text, "item:", 1, true) ) then
  3456. item = GetItemInfo(text);
  3457. end
  3458. local cursorPosition = MacroFrameText:GetCursorPosition();
  3459. if (cursorPosition == 0 or strsub(MacroFrameText:GetText(), cursorPosition, cursorPosition) == "\n" ) then
  3460. if ( item ) then
  3461. if ( GetItemSpell(text) ) then
  3462. MacroFrameText:Insert(SLASH_USE1.." "..item.."\n");
  3463. else
  3464. MacroFrameText:Insert(SLASH_EQUIP1.." "..item.."\n");
  3465. end
  3466. else
  3467. MacroFrameText:Insert(SLASH_CAST1.." "..text.."\n");
  3468. end
  3469. else
  3470. MacroFrameText:Insert(item or text);
  3471. end
  3472. return true;
  3473. end
  3474. if ( TradeSkillFrame and TradeSkillFrame.SearchBox:HasFocus() ) then
  3475. local item;
  3476. if ( strfind(text, "item:", 1, true) ) then
  3477. item = GetItemInfo(text);
  3478. end
  3479. if ( item ) then
  3480. TradeSkillFrame.SearchBox:SetText(item);
  3481. return true;
  3482. end
  3483. end
  3484. return false;
  3485. end
  3486. function ChatEdit_TryInsertChatLink(link)
  3487. if ( IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow() and link ) then
  3488. ChatEdit_InsertLink(link);
  3489. return true;
  3490. end
  3491. end
  3492. function ChatEdit_TryInsertQuestLinkForQuestID(questID)
  3493. return ChatEdit_TryInsertChatLink(GetQuestLink(questID));
  3494. end
  3495. function ChatEdit_GetLastTellTarget()
  3496. for i=1, #ChatEdit_LastTell do
  3497. local value = ChatEdit_LastTell[i];
  3498. if ( value ~= "" ) then
  3499. return value, ChatEdit_LastTellType[i];
  3500. end
  3501. end
  3502. return nil;
  3503. end
  3504. function ChatEdit_SetLastTellTarget(target, chatType)
  3505. local found = #ChatEdit_LastTell;
  3506. for i=1, #ChatEdit_LastTell do
  3507. local tellTarget, tellChatType = ChatEdit_LastTell[i], ChatEdit_LastTellType[i];
  3508. if ( strupper(target) == strupper(tellTarget) and strupper(chatType) == strupper(tellChatType) ) then
  3509. found = i;
  3510. break;
  3511. end
  3512. end
  3513. for i = found, 2, -1 do
  3514. ChatEdit_LastTell[i] = ChatEdit_LastTell[i-1];
  3515. ChatEdit_LastTellType[i] = ChatEdit_LastTellType[i-1];
  3516. end
  3517. ChatEdit_LastTell[1] = target;
  3518. ChatEdit_LastTellType[1] = chatType;
  3519. end
  3520. function ChatEdit_GetNextTellTarget(target, chatType)
  3521. if ( not target or target == "" ) then
  3522. return ChatEdit_LastTell[1], ChatEdit_LastTellType[1];
  3523. end
  3524. for i = 1, #ChatEdit_LastTell - 1, 1 do
  3525. if ( ChatEdit_LastTell[i] == "" ) then
  3526. break;
  3527. elseif ( strupper(target) == strupper(ChatEdit_LastTell[i]) and
  3528. strupper(chatType) == strupper(ChatEdit_LastTellType[i]) ) then
  3529. if ( ChatEdit_LastTell[i+1] ~= "" ) then
  3530. return ChatEdit_LastTell[i+1], ChatEdit_LastTellType[i+1];
  3531. else
  3532. break;
  3533. end
  3534. end
  3535. end
  3536. return ChatEdit_LastTell[1], ChatEdit_LastTellType[1];
  3537. end
  3538. function ChatEdit_GetLastToldTarget()
  3539. return ChatEdit_LastTold, ChatEdit_LastToldType;
  3540. end
  3541. function ChatEdit_SetLastToldTarget(name, chatType)
  3542. ChatEdit_LastTold = name;
  3543. ChatEdit_LastToldType = chatType;
  3544. end
  3545. function ChatEdit_UpdateHeader(editBox)
  3546. local type = editBox:GetAttribute("chatType");
  3547. if ( not type ) then
  3548. return;
  3549. end
  3550. local info = ChatTypeInfo[type];
  3551. local header = _G[editBox:GetName().."Header"];
  3552. local headerSuffix = _G[editBox:GetName().."HeaderSuffix"];
  3553. if ( not header ) then
  3554. return;
  3555. end
  3556. header:SetWidth(0);
  3557. --BN_WHISPER FIXME
  3558. if ( type == "SMART_WHISPER" ) then
  3559. --If we have a bnetIDAccount or this name, it's a BN whisper.
  3560. if ( BNet_GetBNetIDAccount(editBox:GetAttribute("tellTarget")) ) then
  3561. editBox:SetAttribute("chatType", "BN_WHISPER");
  3562. else
  3563. editBox:SetAttribute("chatType", "WHISPER");
  3564. end
  3565. ChatEdit_UpdateHeader(editBox);
  3566. return;
  3567. elseif ( type == "WHISPER" ) then
  3568. header:SetFormattedText(CHAT_WHISPER_SEND, editBox:GetAttribute("tellTarget"));
  3569. elseif ( type == "BN_WHISPER" ) then
  3570. local name = editBox:GetAttribute("tellTarget");
  3571. header:SetFormattedText(CHAT_BN_WHISPER_SEND, name);
  3572. elseif ( type == "EMOTE" ) then
  3573. header:SetFormattedText(CHAT_EMOTE_SEND, UnitName("player"));
  3574. elseif ( type == "CHANNEL" ) then
  3575. local channel, channelName, instanceID = GetChannelName(editBox:GetAttribute("channelTarget"));
  3576. if ( channelName ) then
  3577. if ( instanceID > 0 ) then
  3578. channelName = channelName.." "..instanceID;
  3579. end
  3580. info = ChatTypeInfo["CHANNEL"..channel];
  3581. editBox:SetAttribute("channelTarget", channel);
  3582. header:SetFormattedText(CHAT_CHANNEL_SEND, channel, channelName);
  3583. end
  3584. elseif ( (type == "PARTY") and
  3585. (not IsInGroup(LE_PARTY_CATEGORY_HOME) and IsInGroup(LE_PARTY_CATEGORY_INSTANCE)) ) then
  3586. --Smartly switch to instance chat
  3587. editBox:SetAttribute("chatType", "INSTANCE_CHAT");
  3588. ChatEdit_UpdateHeader(editBox);
  3589. return;
  3590. elseif ( (type == "RAID") and
  3591. (not IsInRaid(LE_PARTY_CATEGORY_HOME) and IsInRaid(LE_PARTY_CATEGORY_INSTANCE)) ) then
  3592. --Smartly switch to instance chat
  3593. editBox:SetAttribute("chatType", "INSTANCE_CHAT");
  3594. ChatEdit_UpdateHeader(editBox);
  3595. return;
  3596. elseif ( (type == "INSTANCE_CHAT") and
  3597. (IsInGroup(LE_PARTY_CATEGORY_HOME) and not IsInGroup(LE_PARTY_CATEGORY_INSTANCE)) )then
  3598. if ( IsInRaid(LE_PARTY_CATEGORY_HOME) ) then
  3599. editBox:SetAttribute("chatType", "RAID");
  3600. else
  3601. editBox:SetAttribute("chatType", "PARTY");
  3602. end
  3603. ChatEdit_UpdateHeader(editBox);
  3604. return;
  3605. else
  3606. header:SetText(_G["CHAT_"..type.."_SEND"]);
  3607. end
  3608. local headerWidth = (header:GetRight() or 0) - (header:GetLeft() or 0);
  3609. local editBoxWidth = editBox:GetRight() - editBox:GetLeft();
  3610. if ( headerWidth > editBoxWidth / 2 ) then
  3611. header:SetWidth(editBoxWidth / 2);
  3612. headerSuffix:Show();
  3613. else
  3614. headerSuffix:Hide();
  3615. end
  3616. header:SetTextColor(info.r, info.g, info.b);
  3617. headerSuffix:SetTextColor(info.r, info.g, info.b);
  3618. editBox:SetTextInsets(15 + header:GetWidth() + (headerSuffix:IsShown() and headerSuffix:GetWidth() or 0), 13, 0, 0);
  3619. editBox:SetTextColor(info.r, info.g, info.b);
  3620. editBox.focusLeft:SetVertexColor(info.r, info.g, info.b);
  3621. editBox.focusRight:SetVertexColor(info.r, info.g, info.b);
  3622. editBox.focusMid:SetVertexColor(info.r, info.g, info.b);
  3623. end
  3624. function ChatEdit_AddHistory(editBox)
  3625. local text = "";
  3626. local type = editBox:GetAttribute("chatType");
  3627. local header = _G["SLASH_"..type.."1"];
  3628. if ( header ) then
  3629. text = header;
  3630. end
  3631. if ( type == "WHISPER" ) then
  3632. text = text.." "..editBox:GetAttribute("tellTarget");
  3633. elseif ( type == "CHANNEL" ) then
  3634. text = "/"..editBox:GetAttribute("channelTarget");
  3635. end
  3636. local editBoxText = editBox:GetText();
  3637. if ( strlen(editBoxText) > 0 ) then
  3638. text = text.." "..editBox:GetText();
  3639. end
  3640. if ( strlen(text) > 0 ) then
  3641. editBox:AddHistoryLine(text);
  3642. end
  3643. end
  3644. function ChatEdit_SendText(editBox, addHistory)
  3645. ChatEdit_ParseText(editBox, 1);
  3646. local type = editBox:GetAttribute("chatType");
  3647. local text = editBox:GetText();
  3648. if ( strfind(text, "%s*[^%s]+") ) then
  3649. text = SubstituteChatMessageBeforeSend(text);
  3650. --BN_WHISPER FIXME
  3651. if ( type == "WHISPER") then
  3652. local target = editBox:GetAttribute("tellTarget");
  3653. ChatEdit_SetLastToldTarget(target, type);
  3654. SendChatMessage(text, type, editBox.languageID, target);
  3655. elseif ( type == "BN_WHISPER" ) then
  3656. local target = editBox:GetAttribute("tellTarget");
  3657. local bnetIDAccount = BNet_GetBNetIDAccount(target);
  3658. if ( bnetIDAccount ) then
  3659. ChatEdit_SetLastToldTarget(target, type);
  3660. BNSendWhisper(bnetIDAccount, text);
  3661. else
  3662. local info = ChatTypeInfo["SYSTEM"]
  3663. editBox.chatFrame:AddMessage(format(BN_UNABLE_TO_RESOLVE_NAME, target), info.r, info.g, info.b);
  3664. end
  3665. elseif ( type == "CHANNEL") then
  3666. SendChatMessage(text, type, editBox.languageID, editBox:GetAttribute("channelTarget"));
  3667. else
  3668. SendChatMessage(text, type, editBox.languageID);
  3669. end
  3670. if ( addHistory ) then
  3671. ChatEdit_AddHistory(editBox);
  3672. end
  3673. end
  3674. end
  3675. function ChatEdit_OnEnterPressed(self)
  3676. if(AutoCompleteEditBox_OnEnterPressed(self)) then
  3677. return;
  3678. end
  3679. ChatEdit_SendText(self, 1);
  3680. local type = self:GetAttribute("chatType");
  3681. local chatFrame = self:GetParent();
  3682. if ( chatFrame.isTemporary and chatFrame.chatType ~= "PET_BATTLE_COMBAT_LOG" ) then --Temporary window sticky types never change.
  3683. self:SetAttribute("stickyType", chatFrame.chatType);
  3684. --BN_WHISPER FIXME
  3685. if ( chatFrame.chatType == "WHISPER" or chatFrame.chatType == "BN_WHISPER" ) then
  3686. self:SetAttribute("tellTarget", chatFrame.chatTarget);
  3687. end
  3688. elseif ( ChatTypeInfo[type].sticky == 1 ) then
  3689. self:SetAttribute("stickyType", type);
  3690. end
  3691. ChatEdit_ClearChat(self);
  3692. end
  3693. function ChatEdit_ClearChat(editBox)
  3694. ChatEdit_ResetChatTypeToSticky(editBox);
  3695. if ( not editBox.isGM and (GetCVar("chatStyle") ~= "im" or editBox == MacroEditBox) ) then
  3696. editBox:SetText("");
  3697. editBox:Hide();
  3698. else
  3699. ChatEdit_DeactivateChat(editBox);
  3700. end
  3701. end
  3702. function ChatEdit_OnEscapePressed(editBox)
  3703. if ( not AutoCompleteEditBox_OnEscapePressed(editBox) ) then
  3704. ChatEdit_ClearChat(editBox);
  3705. end
  3706. end
  3707. function ChatEdit_ResetChatTypeToSticky(editBox)
  3708. editBox:SetAttribute("chatType", editBox:GetAttribute("stickyType"));
  3709. end
  3710. function ChatEdit_OnSpacePressed(self)
  3711. ChatEdit_ParseText(self, 0);
  3712. end
  3713. function ChatEdit_CustomTabPressed(self)
  3714. end
  3715. local tabCompleteTables = { hash_ChatTypeInfoList, hash_EmoteTokenList };
  3716. function ChatEdit_SecureTabPressed(self)
  3717. local chatType = self:GetAttribute("chatType");
  3718. if ( chatType == "WHISPER" or chatType == "BN_WHISPER" ) then
  3719. local newTarget, newTargetType = ChatEdit_GetNextTellTarget(self:GetAttribute("tellTarget"), chatType);
  3720. if ( newTarget and newTarget ~= "" ) then
  3721. self:SetAttribute("chatType", newTargetType);
  3722. self:SetAttribute("tellTarget", newTarget);
  3723. ChatEdit_UpdateHeader(self);
  3724. end
  3725. return;
  3726. end
  3727. local text = self.tabCompleteText;
  3728. if ( not text ) then
  3729. text = self:GetText();
  3730. self.tabCompleteText = text;
  3731. end
  3732. if ( strsub(text, 1, 1) ~= "/" ) then
  3733. return;
  3734. end
  3735. ChatFrame_ImportAllListsToHash();
  3736. local lastTabComplete = self.lastTabComplete;
  3737. -- If the string is in the format "/cmd blah", command will be "/cmd"
  3738. local command = strmatch(text, "^(/[^%s]+)") or "";
  3739. local cmdString = lastTabComplete;
  3740. repeat --The outer loop lets us go through multiple hash tables of commands.
  3741. repeat --Loop through this table to find matching items.
  3742. cmdString = next(tabCompleteTables[self.tabCompleteTableIndex], cmdString);
  3743. until ( not cmdString or strfind(cmdString, strupper(command), 1, 1) ); --Either we finished going through this table or we found a match.
  3744. if ( not cmdString ) then --Nothing else in the current table, move to the next one.
  3745. self.tabCompleteTableIndex = self.tabCompleteTableIndex + 1;
  3746. end
  3747. until ( cmdString or self.tabCompleteTableIndex > #tabCompleteTables );
  3748. self.lastTabComplete = cmdString;
  3749. if ( cmdString ) then
  3750. self.ignoreTextChange = 1;
  3751. self:SetText(strlower(cmdString));
  3752. else
  3753. self.tabCompleteTableIndex = 1;
  3754. self:SetText(self.tabCompleteText);
  3755. end
  3756. end
  3757. function ChatEdit_OnTabPressed(self)
  3758. if ( not AutoCompleteEditBox_OnTabPressed(self) ) then
  3759. if ( securecall("ChatEdit_CustomTabPressed", self) ) then
  3760. return;
  3761. end
  3762. ChatEdit_SecureTabPressed(self);
  3763. end
  3764. end
  3765. function ChatEdit_OnTextChanged(self, userInput)
  3766. ChatEdit_ParseText(self, 0);
  3767. if ( not self.ignoreTextChange ) then
  3768. self.lastTabComplete = nil;
  3769. self.tabCompleteText = nil;
  3770. self.tabCompleteTableIndex = 1;
  3771. end
  3772. self.ignoreTextChange = nil;
  3773. local regex = "^((/[^%s]+)%s+(.+))"
  3774. local full, command, target = strmatch(self:GetText(), regex);
  3775. if ( not target or (strsub(target, 1, 1) == "|") ) then
  3776. AutoComplete_HideIfAttachedTo(self);
  3777. return;
  3778. end
  3779. if ( userInput ) then
  3780. self.autoCompleteXOffset = 35;
  3781. AutoComplete_Update(self, target, self:GetUTF8CursorPosition() - strlenutf8(command) - 1);
  3782. end
  3783. end
  3784. local symbols = {"%%", "%*", "%+", "%-", "%?", "%(", "%)", "%[", "%]", "%$", "%^"} --% has to be escaped first or everything is ruined
  3785. local replacements = {"%%%%", "%%%*", "%%%+", "%%%-", "%%%?", "%%%(", "%%%)", "%%%[", "%%%]", "%%%$", "%%%^"}
  3786. function escapePatternSymbols(text)
  3787. for i=1, #symbols do
  3788. text = text:gsub(symbols[i], replacements[i])
  3789. end
  3790. return text
  3791. end
  3792. function ChatEdit_OnChar(self)
  3793. local regex = "^((/[^%s]+)%s+(.+))$"
  3794. local text, command, target = strmatch(self:GetText(), regex);
  3795. if (command) then
  3796. self.command = command
  3797. else
  3798. self.command = nil;
  3799. end
  3800. if (command and target and self.autoCompleteParams) then --if they typed a command with a autocompletable target
  3801. local utf8Position = self:GetUTF8CursorPosition();
  3802. local nameToShow = GetAutoCompleteResults(target, self.autoCompleteParams.include, self.autoCompleteParams.exclude, 1, utf8Position)[1];
  3803. if (nameToShow and nameToShow.name) then
  3804. local name = Ambiguate(nameToShow.name, "all");
  3805. --We're going to be setting the text programatically which will clear the userInput flag on the editBox.
  3806. --So we want to manually update the dropdown before we change the text.
  3807. AutoComplete_Update(self, target, utf8Position - strlenutf8(command) - 1);
  3808. target = escapePatternSymbols(target)
  3809. local highlightRegex = "^"..target.."(.*)";
  3810. local nameEnding = name:match(highlightRegex)
  3811. if (not nameEnding) then
  3812. return;
  3813. end
  3814. local newText = text..nameEnding;
  3815. self:SetText(newText);
  3816. self:HighlightText(strlen(text), strlen(newText));
  3817. self:SetCursorPosition(strlen(text));
  3818. end
  3819. end
  3820. end
  3821. function ChatEdit_OnTextSet(self)
  3822. ChatEdit_ParseText(self, 0);
  3823. end
  3824. function ChatEdit_LanguageShow()
  3825. CHAT_SHOW_IME = true;
  3826. end
  3827. function ChatEdit_OnInputLanguageChanged(self)
  3828. local button = _G[self:GetName().."Language"];
  3829. local variable = _G["INPUT_"..self:GetInputLanguage()];
  3830. button:SetText(variable);
  3831. end
  3832. local function processChatType(editBox, msg, index, send)
  3833. editBox.autoCompleteParams = AUTOCOMPLETE_LIST[index];
  3834. -- this is a special function for "ChatEdit_HandleChatType"
  3835. if ( ChatTypeInfo[index] ) then
  3836. if ( index == "WHISPER" or index == "SMART_WHISPER" ) then
  3837. local targetFound, target, chatType, parsedMsg = ChatEdit_ExtractTellTarget(editBox, msg, index);
  3838. if ( targetFound ) then
  3839. editBox:SetAttribute("tellTarget", target);
  3840. editBox:SetAttribute("chatType", chatType);
  3841. editBox:SetText(parsedMsg);
  3842. ChatEdit_UpdateHeader(editBox);
  3843. elseif ( send == 1 ) then
  3844. ChatEdit_ClearChat(editBox);
  3845. end
  3846. elseif ( index == "REPLY" ) then
  3847. local lastTell, lastTellType = ChatEdit_GetLastTellTarget();
  3848. if ( lastTell ) then
  3849. --BN_WHISPER FIXME
  3850. editBox:SetAttribute("chatType", lastTellType);
  3851. editBox:SetAttribute("tellTarget", lastTell);
  3852. editBox:SetText(msg);
  3853. ChatEdit_UpdateHeader(editBox);
  3854. else
  3855. if ( send == 1 ) then
  3856. ChatEdit_ClearChat(editBox);
  3857. end
  3858. end
  3859. elseif (index == "CHANNEL") then
  3860. ChatEdit_ExtractChannel(editBox, msg);
  3861. else
  3862. editBox:SetAttribute("chatType", index);
  3863. editBox:SetText(msg);
  3864. ChatEdit_UpdateHeader(editBox);
  3865. end
  3866. return true;
  3867. end
  3868. return false;
  3869. end
  3870. function ChatEdit_HandleChatType(editBox, msg, command, send)
  3871. local channel = strmatch(command, "/([0-9]+)");
  3872. if( channel ) then
  3873. local chanNum = tonumber(channel);
  3874. if ( chanNum > 0 and chanNum <= MAX_WOW_CHAT_CHANNELS ) then
  3875. local channelNum, channelName = GetChannelName(channel);
  3876. if ( channelNum > 0 ) then
  3877. editBox:SetAttribute("channelTarget", channelNum);
  3878. editBox:SetAttribute("chatType", "CHANNEL");
  3879. editBox:SetText(msg);
  3880. ChatEdit_UpdateHeader(editBox);
  3881. return true;
  3882. end
  3883. end
  3884. else
  3885. -- first check the hash table
  3886. ChatFrame_ImportAllListsToHash();
  3887. if ( hash_ChatTypeInfoList[command] ) then
  3888. return processChatType(editBox, msg, hash_ChatTypeInfoList[command], send);
  3889. end
  3890. end
  3891. --This isn't one we found in our list, so we're not going to autocomplete.
  3892. editBox.autoCompleteParams = nil;
  3893. return false;
  3894. end
  3895. function ChatEdit_ParseText(editBox, send, parseIfNoSpaces)
  3896. local text = editBox:GetText();
  3897. if ( strlen(text) <= 0 ) then
  3898. return;
  3899. end
  3900. if ( strsub(text, 1, 1) ~= "/" ) then
  3901. return;
  3902. end
  3903. --Do not bother parsing if there is no space in the message and we aren't sending.
  3904. if ( send ~= 1 and not parseIfNoSpaces and not strfind(text, "%s") ) then
  3905. return;
  3906. end
  3907. -- If the string is in the format "/cmd blah", command will be "/cmd"
  3908. local command = strmatch(text, "^(/[^%s]+)") or "";
  3909. local msg = "";
  3910. if ( command ~= text ) then
  3911. msg = strsub(text, strlen(command) + 2);
  3912. end
  3913. command = strupper(command);
  3914. -- Check and see if we've got secure commands to run before we look for chat types or slash commands.
  3915. -- This hash table is prepopulated, unlike the other ones, since nobody can add secure commands. (See line 1205 or thereabouts)
  3916. -- We don't want this code to run unless send is 1, but we need ChatEdit_HandleChatType to run when send is 1 as well, which is why we
  3917. -- didn't just move ChatEdit_HandleChatType inside the send == 0 conditional, which could have also solved the problem with insecure
  3918. -- code having the ability to affect secure commands.
  3919. if ( send == 1 and hash_SecureCmdList[command] ) then
  3920. hash_SecureCmdList[command](strtrim(msg));
  3921. editBox:AddHistoryLine(text);
  3922. ChatEdit_ClearChat(editBox);
  3923. return;
  3924. end
  3925. ChatFrame_ImportAllListsToHash();
  3926. -- Handle chat types. No need for a securecall here, since we should be done with anything secure.
  3927. if ( ChatEdit_HandleChatType(editBox, msg, command, send) ) then
  3928. return;
  3929. end
  3930. if ( send == 0 ) then
  3931. return;
  3932. end
  3933. -- Check the hash tables for slash commands and emotes to see if we've run this before.
  3934. if ( hash_SlashCmdList[command] ) then
  3935. -- if the code in here changes - change the corresponding code below
  3936. hash_SlashCmdList[command](strtrim(msg), editBox);
  3937. editBox:AddHistoryLine(text);
  3938. ChatEdit_ClearChat(editBox);
  3939. return;
  3940. elseif ( hash_EmoteTokenList[command] ) then
  3941. -- if the code in here changes - change the corresponding code below
  3942. local restricted = DoEmote(hash_EmoteTokenList[command], msg);
  3943. -- If the emote is restricted, we want to treat it as if the player entered an unrecognized chat command.
  3944. if ( not restricted ) then
  3945. editBox:AddHistoryLine(text);
  3946. ChatEdit_ClearChat(editBox);
  3947. return;
  3948. end
  3949. end
  3950. -- Unrecognized chat command, show simple help text
  3951. if ( editBox.chatFrame ) then
  3952. ChatFrame_DisplayHelpTextSimple(editBox.chatFrame);
  3953. end
  3954. -- Reset the chat type and clear the edit box's contents
  3955. ChatEdit_ClearChat(editBox);
  3956. return;
  3957. end
  3958. function SubstituteChatMessageBeforeSend(msg)
  3959. for tag in string.gmatch(msg, "%b{}") do
  3960. local term = strlower(string.gsub(tag, "[{}]", ""));
  3961. if ( GROUP_TAG_LIST[term] ) then
  3962. local groupIndex = GROUP_TAG_LIST[term];
  3963. msg = string.gsub(msg, tag, "{"..GROUP_LANGUAGE_INDEPENDENT_STRINGS[groupIndex].."}");
  3964. end
  3965. end
  3966. return msg;
  3967. end
  3968. function ChatEdit_ExtractTellTarget(editBox, msg, chatType)
  3969. local tellTargetExtractionAutoComplete;
  3970. if ( chatType == "WHISPER" ) then
  3971. tellTargetExtractionAutoComplete = AUTOCOMPLETE_LIST.WHISPER_EXTRACT;
  3972. else
  3973. tellTargetExtractionAutoComplete = AUTOCOMPLETE_LIST.SMART_WHISPER_EXTRACT;
  3974. end
  3975. -- Grab the string after the slash command
  3976. local target = strmatch(msg, "%s*(.*)");
  3977. --If we haven't even finished one word, we aren't done.
  3978. if ( not target or not strfind(target, "%s") ) then
  3979. return false;
  3980. end
  3981. if((strsub(target, 1, 1) == "|") and not(strsub(target, 1, 2) == "|K")) then
  3982. return false;
  3983. end
  3984. if ( #GetAutoCompleteResults(target, tellTargetExtractionAutoComplete.include, tellTargetExtractionAutoComplete.exclude, 1, nil, true) > 0 ) then
  3985. --Even if there's a space, we still want to let the person keep typing -- they may be trying to type whatever is in AutoComplete.
  3986. return false;
  3987. end
  3988. if(strsub(target, 1, 2) == "|K") then
  3989. target, msg = BNTokenFindName(target);
  3990. --If there is a space just after the name (to trigger a parse), remove it.
  3991. if ( strsub(msg, 1, 1) == " " ) then
  3992. msg = strsub(msg, 2);
  3993. end
  3994. else
  3995. --Keep pulling off everything after the last space until we either have something on the AutoComplete list or only a single word is left.
  3996. while ( strfind(target, "%s") ) do
  3997. --Pull off everything after the last space.
  3998. target = strmatch(target, "(.+)%s+[^%s]*");
  3999. if ( #GetAutoCompleteResults(target, tellTargetExtractionAutoComplete.include, tellTargetExtractionAutoComplete.exclude, 1, nil, true) > 0 ) then
  4000. break;
  4001. end
  4002. end
  4003. msg = strsub(msg, strlen(target) + 2);
  4004. end
  4005. if ( chatType ~= "WHISPER" and BNet_GetBNetIDAccount(target) ) then --"WHISPER" forces character whisper
  4006. chatType = "BN_WHISPER";
  4007. else
  4008. chatType = "WHISPER";
  4009. end
  4010. return true, target, chatType, msg;
  4011. end
  4012. function ChatEdit_ExtractChannel(editBox, msg)
  4013. local target = strmatch(msg, "%s*([^%s]+)");
  4014. if ( not target ) then
  4015. return;
  4016. end
  4017. local channelNum, channelName = GetChannelName(target);
  4018. if ( channelNum <= 0 ) then
  4019. return;
  4020. end
  4021. msg = strsub(msg, strlen(target) + 2);
  4022. editBox:SetAttribute("channelTarget", channelNum);
  4023. editBox:SetAttribute("chatType", "CHANNEL");
  4024. editBox:SetText(msg);
  4025. ChatEdit_UpdateHeader(editBox);
  4026. end
  4027. -- Chat menu functions
  4028. function ChatMenu_SetChatType(chatFrame, type)
  4029. local editBox = ChatFrame_OpenChat("");
  4030. editBox:SetAttribute("chatType", type);
  4031. ChatEdit_UpdateHeader(editBox);
  4032. end
  4033. function ChatMenu_Say(self)
  4034. ChatMenu_SetChatType(self:GetParent().chatFrame, "SAY");
  4035. end
  4036. function ChatMenu_Party(self)
  4037. ChatMenu_SetChatType(self:GetParent().chatFrame, "PARTY");
  4038. end
  4039. function ChatMenu_Raid(self)
  4040. ChatMenu_SetChatType(self:GetParent().chatFrame, "RAID");
  4041. end
  4042. function ChatMenu_InstanceChat(self)
  4043. ChatMenu_SetChatType(self:GetParent().chatFrame, "INSTANCE_CHAT");
  4044. end
  4045. function ChatMenu_Guild(self)
  4046. ChatMenu_SetChatType(self:GetParent().chatFrame, "GUILD");
  4047. end
  4048. function ChatMenu_Yell(self)
  4049. ChatMenu_SetChatType(self:GetParent().chatFrame, "YELL");
  4050. end
  4051. function ChatMenu_Whisper(self)
  4052. local editBox = ChatFrame_OpenChat(SLASH_SMART_WHISPER1.." ");
  4053. editBox:SetText(SLASH_SMART_WHISPER1.." "..editBox:GetText());
  4054. end
  4055. function ChatMenu_Emote(self)
  4056. ChatMenu_SetChatType(self:GetParent().chatFrame, "EMOTE");
  4057. end
  4058. function ChatMenu_Reply(self)
  4059. ChatFrame_ReplyTell();
  4060. end
  4061. function ChatMenu_VoiceMacro(self)
  4062. ChatMenu_SetChatType(self:GetParent().chatFrame, "YELL");
  4063. end
  4064. function ChatMenu_OnLoad(self)
  4065. self.chatFrame = DEFAULT_CHAT_FRAME;
  4066. UIMenu_Initialize(self);
  4067. UIMenu_AddButton(self, SAY_MESSAGE, SLASH_SAY1, ChatMenu_Say);
  4068. UIMenu_AddButton(self, PARTY_MESSAGE, SLASH_PARTY1, ChatMenu_Party);
  4069. UIMenu_AddButton(self, RAID_MESSAGE, SLASH_RAID1, ChatMenu_Raid);
  4070. UIMenu_AddButton(self, INSTANCE_CHAT_MESSAGE, SLASH_INSTANCE_CHAT1, ChatMenu_InstanceChat);
  4071. UIMenu_AddButton(self, GUILD_MESSAGE, SLASH_GUILD1, ChatMenu_Guild);
  4072. UIMenu_AddButton(self, YELL_MESSAGE, SLASH_YELL1, ChatMenu_Yell);
  4073. UIMenu_AddButton(self, WHISPER_MESSAGE, SLASH_SMART_WHISPER1, ChatMenu_Whisper);
  4074. UIMenu_AddButton(self, EMOTE_MESSAGE, SLASH_EMOTE1, ChatMenu_Emote, "EmoteMenu");
  4075. UIMenu_AddButton(self, REPLY_MESSAGE, SLASH_REPLY1, ChatMenu_Reply);
  4076. UIMenu_AddButton(self, LANGUAGE, nil, nil, "LanguageMenu");
  4077. UIMenu_AddButton(self, VOICEMACRO_LABEL, nil, nil, "VoiceMacroMenu");
  4078. UIMenu_AddButton(self, MACRO, SLASH_MACRO1, ShowMacroFrame);
  4079. UIMenu_AutoSize(self);
  4080. end
  4081. function ChatMenu_OnShow(self)
  4082. UIMenu_OnShow(self);
  4083. EmoteMenu:Hide();
  4084. LanguageMenu:Hide();
  4085. VoiceMacroMenu:Hide();
  4086. self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
  4087. self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
  4088. end
  4089. function EmoteMenu_Click(self)
  4090. DoEmote(EmoteList[self:GetID()]);
  4091. ChatMenu:Hide();
  4092. end
  4093. function TextEmoteSort(token1, token2)
  4094. local i = 1;
  4095. local string1, string2;
  4096. local token = _G["EMOTE"..i.."_TOKEN"];
  4097. while ( i <= MAXEMOTEINDEX ) do
  4098. if ( token == token1 ) then
  4099. string1 = _G["EMOTE"..i.."_CMD1"];
  4100. if ( string2 ) then
  4101. break;
  4102. end
  4103. end
  4104. if ( token == token2 ) then
  4105. string2 = _G["EMOTE"..i.."_CMD1"];
  4106. if ( string1 ) then
  4107. break;
  4108. end
  4109. end
  4110. i = i + 1;
  4111. token = _G["EMOTE"..i.."_TOKEN"];
  4112. end
  4113. return string1 < string2;
  4114. end
  4115. function OnMenuLoad(self,list,func)
  4116. sort(list, TextEmoteSort);
  4117. UIMenu_Initialize(self);
  4118. self.parentMenu = "ChatMenu";
  4119. for index, value in pairs(list) do
  4120. local i = 1;
  4121. local token = _G["EMOTE"..i.."_TOKEN"];
  4122. while ( i < MAXEMOTEINDEX ) do
  4123. if ( token == value ) then
  4124. break;
  4125. end
  4126. i = i + 1;
  4127. token = _G["EMOTE"..i.."_TOKEN"];
  4128. end
  4129. local label = _G["EMOTE"..i.."_CMD1"];
  4130. if ( not label ) then
  4131. label = value;
  4132. end
  4133. UIMenu_AddButton(self, label, nil, func);
  4134. end
  4135. UIMenu_AutoSize(self);
  4136. end
  4137. function EmoteMenu_OnLoad(self)
  4138. OnMenuLoad(self, EmoteList, EmoteMenu_Click);
  4139. end
  4140. function LanguageMenu_OnLoad(self)
  4141. UIMenu_Initialize(self);
  4142. self.parentMenu = "ChatMenu";
  4143. self:RegisterEvent("PLAYER_ENTERING_WORLD");
  4144. self:RegisterEvent("LANGUAGE_LIST_CHANGED");
  4145. self:RegisterEvent("NEUTRAL_FACTION_SELECT_RESULT");
  4146. end
  4147. function VoiceMacroMenu_Click(self)
  4148. DoEmote(TextEmoteSpeechList[self:GetID()]);
  4149. ChatMenu:Hide();
  4150. end
  4151. function VoiceMacroMenu_OnLoad(self)
  4152. OnMenuLoad(self, TextEmoteSpeechList, VoiceMacroMenu_Click);
  4153. end
  4154. function LanguageMenu_OnEvent(self, event, ...)
  4155. if ( event == "PLAYER_ENTERING_WORLD" ) then
  4156. self:Hide();
  4157. UIMenu_Initialize(self);
  4158. LanguageMenu_LoadLanguages(self);
  4159. self:GetParent().chatFrame.editBox.language, self:GetParent().chatFrame.editBox.languageID = GetDefaultLanguage();
  4160. return;
  4161. end
  4162. if ( event == "LANGUAGE_LIST_CHANGED" ) then
  4163. self:Hide();
  4164. UIMenu_Initialize(self);
  4165. LanguageMenu_LoadLanguages(self);
  4166. return;
  4167. end
  4168. if ( event == "NEUTRAL_FACTION_SELECT_RESULT" ) then
  4169. self:Hide();
  4170. self:GetParent().chatFrame.editBox.language, self:GetParent().chatFrame.editBox.languageID = GetDefaultLanguage();
  4171. return;
  4172. end
  4173. end
  4174. function LanguageMenu_LoadLanguages(self)
  4175. local numLanguages = GetNumLanguages();
  4176. local i;
  4177. local editBoxLanguageID = self:GetParent().chatFrame.editBox.languageID;
  4178. local languageKnown = false;
  4179. for i = 1, numLanguages, 1 do
  4180. local language, languageID = GetLanguageByIndex(i);
  4181. UIMenu_AddButton(self, language, nil, LanguageMenu_Click);
  4182. if ( languageID == editBoxLanguageID ) then
  4183. languageKnown = true;
  4184. end
  4185. end
  4186. if ( languageKnown ~= true ) then
  4187. self:GetParent().chatFrame.editBox.language, self:GetParent().chatFrame.editBox.languageID = GetLanguageByIndex(1);
  4188. end
  4189. UIMenu_AutoSize(self);
  4190. end
  4191. function LanguageMenu_Click(self)
  4192. self:GetParent():GetParent().chatFrame.editBox.language, self:GetParent():GetParent().chatFrame.editBox.languageID = GetLanguageByIndex(self:GetID());
  4193. ChatMenu:Hide();
  4194. end
  4195. function ChatFrame_ActivateCombatMessages(chatFrame)
  4196. ChatFrame_AddMessageGroup(chatFrame, "OPENING");
  4197. ChatFrame_AddMessageGroup(chatFrame, "TRADESKILLS");
  4198. ChatFrame_AddMessageGroup(chatFrame, "PET_INFO");
  4199. ChatFrame_AddMessageGroup(chatFrame, "COMBAT_MISC_INFO");
  4200. ChatFrame_AddMessageGroup(chatFrame, "COMBAT_XP_GAIN");
  4201. ChatFrame_AddMessageGroup(chatFrame, "COMBAT_GUILD_XP_GAIN");
  4202. ChatFrame_AddMessageGroup(chatFrame, "COMBAT_HONOR_GAIN");
  4203. ChatFrame_AddMessageGroup(chatFrame, "COMBAT_FACTION_CHANGE");
  4204. end
  4205. function ChatChannelDropDown_Show(chatFrame, chatType, chatTarget, chatName)
  4206. HideDropDownMenu(1);
  4207. ChatChannelDropDown.initialize = ChatChannelDropDown_Initialize;
  4208. ChatChannelDropDown.displayMode = "MENU";
  4209. ChatChannelDropDown.chatType = chatType;
  4210. ChatChannelDropDown.chatTarget = chatTarget;
  4211. ChatChannelDropDown.chatName = chatName;
  4212. ChatChannelDropDown.chatFrame = chatFrame;
  4213. ToggleDropDownMenu(1, nil, ChatChannelDropDown, "cursor");
  4214. end
  4215. function ChatChannelDropDown_Initialize()
  4216. local frame = ChatChannelDropDown;
  4217. local info = UIDropDownMenu_CreateInfo();
  4218. info.text = frame.chatName;
  4219. info.notCheckable = true;
  4220. info.isTitle = true;
  4221. UIDropDownMenu_AddButton(info, 1);
  4222. info = UIDropDownMenu_CreateInfo();
  4223. info.text = MOVE_TO_NEW_WINDOW;
  4224. info.notCheckable = 1;
  4225. info.func = ChatChannelDropDown_PopOutChat;
  4226. info.arg1 = frame.chatType;
  4227. info.arg2 = frame.chatTarget;
  4228. if ( FCF_GetNumActiveChatFrames() == NUM_CHAT_WINDOWS ) then
  4229. info.disabled = 1;
  4230. end
  4231. UIDropDownMenu_AddButton(info);
  4232. end
  4233. function ChatChannelDropDown_PopOutChat(self, chatType, chatTarget)
  4234. local sourceChatFrame = ChatChannelDropDown.chatFrame;
  4235. local windowName;
  4236. if ( chatType == "CHANNEL" ) then
  4237. windowName = Chat_GetChannelShortcutName(chatTarget);
  4238. else
  4239. windowName = _G[chatType];
  4240. end
  4241. local frame = FCF_OpenNewWindow(windowName);
  4242. FCF_CopyChatSettings(frame, sourceChatFrame);
  4243. ChatFrame_RemoveAllMessageGroups(frame);
  4244. ChatFrame_RemoveAllChannels(frame);
  4245. ChatFrame_ReceiveAllPrivateMessages(frame);
  4246. ChatFrame_AddMessageGroup(frame, chatType);
  4247. if ( CHAT_CATEGORY_LIST[chatType] ) then
  4248. for _, chat in pairs(CHAT_CATEGORY_LIST[chatType]) do
  4249. ChatFrame_AddMessageGroup(frame, chat);
  4250. end
  4251. end
  4252. frame.editBox:SetAttribute("chatType", chatType);
  4253. frame.editBox:SetAttribute("stickyType", chatType);
  4254. if ( chatType == "CHANNEL" ) then
  4255. frame.editBox:SetAttribute("channelTarget", chatTarget);
  4256. ChatFrame_AddChannel(frame, Chat_GetChannelShortcutName(chatTarget));
  4257. end
  4258. if ( chatType == "PET_BATTLE_COMBAT_LOG" or chatType == "PET_BATTLE_INFO" ) then
  4259. frame.editBox:SetAttribute("chatType", "SAY");
  4260. frame.editBox:SetAttribute("stickyType", "SAY");
  4261. end
  4262. --Remove the things popped out from the source chat frame.
  4263. if ( chatType == "CHANNEL" ) then
  4264. ChatFrame_RemoveChannel(sourceChatFrame, Chat_GetChannelShortcutName(chatTarget));
  4265. else
  4266. ChatFrame_RemoveMessageGroup(sourceChatFrame, chatType);
  4267. if ( CHAT_CATEGORY_LIST[chatType] ) then
  4268. for _, chat in pairs(CHAT_CATEGORY_LIST[chatType]) do
  4269. ChatFrame_RemoveMessageGroup(sourceChatFrame, chat);
  4270. end
  4271. end
  4272. end
  4273. --Copy over messages
  4274. local accessID = ChatHistory_GetAccessID(chatType, chatTarget);
  4275. for i = 1, sourceChatFrame:GetNumMessages() do
  4276. local text, r, g, b, chatTypeID, messageAccessID, lineID = sourceChatFrame:GetMessageInfo(i);
  4277. if messageAccessID == accessID then
  4278. frame:AddMessage(text, r, g, b, chatTypeID, messageAccessID, lineID);
  4279. end
  4280. end
  4281. --Remove the messages from the old frame.
  4282. sourceChatFrame:RemoveMessagesByPredicate(function(text, r, g, b, chatTypeID, messageAccessID, lineID) return messageAccessID == accessID; end);
  4283. end
  4284. function Chat_GetChannelShortcutName(index)
  4285. local _, name = GetChannelName(index);
  4286. name = strtrim(name:match("([^%-]+)"));
  4287. return name;
  4288. end
  4289. function ChatChannelDropDown_PopInChat(self, chatType, chatTarget)
  4290. --PopOutChat_PopInChat(chatType, chatTarget);
  4291. end
  4292. function Chat_GetColoredChatName(chatType, chatTarget)
  4293. if ( chatType == "CHANNEL" ) then
  4294. local info = ChatTypeInfo["CHANNEL"..chatTarget];
  4295. local colorString = format("|cff%02x%02x%02x", info.r * 255, info.g * 255, info.b * 255);
  4296. local chanNum, channelName = GetChannelName(chatTarget);
  4297. return format("%s|Hchannel:channel:%d|h[%d. %s]|h|r", colorString, chanNum, chanNum, gsub(channelName, "%s%-%s.*", "")); --The gsub removes zone-specific markings (e.g. "General - Ironforge" to "General")
  4298. elseif ( chatType == "WHISPER" ) then
  4299. local info = ChatTypeInfo["WHISPER"];
  4300. local colorString = format("|cff%02x%02x%02x", info.r * 255, info.g * 255, info.b * 255);
  4301. return format("%s[%s] |Hplayer:%3$s|h[%3$s]|h|r", colorString, _G[chatType], chatTarget);
  4302. else
  4303. local info = ChatTypeInfo[chatType];
  4304. local colorString = format("|cff%02x%02x%02x", info.r * 255, info.g * 255, info.b * 255);
  4305. return format("%s|Hchannel:%s|h[%s]|h|r", colorString, chatType, _G[chatType]);
  4306. end
  4307. end
  4308. --------------------------------------------------------------------------------
  4309. -- Social share link functions
  4310. --------------------------------------------------------------------------------
  4311. SHARE_ICON_COLOR = "ffffd200";
  4312. SHARE_ICON_TEXT = "|TInterface\\ChatFrame\\UI-ChatIcon-Share:18:18|t";
  4313. function Social_GetShareItemLink(itemID, creationContext, earned)
  4314. if (creationContext == nil) then
  4315. creationContext = "";
  4316. end
  4317. local earnedNum = 0;
  4318. if (earned) then
  4319. earnedNum = 1;
  4320. end
  4321. return format("|c%s|Hshareitem:%d:%d:%s|h%s|h|r", SHARE_ICON_COLOR, itemID, earnedNum, creationContext, SHARE_ICON_TEXT);
  4322. end
  4323. function Social_GetShareAchievementLink(achievementID, earned)
  4324. local earnedNum = 0;
  4325. if (earned) then
  4326. earnedNum = 1;
  4327. end
  4328. return format("|c%s|Hshareachieve:%d:%d|h%s|h|r", SHARE_ICON_COLOR, achievementID, earnedNum, SHARE_ICON_TEXT);
  4329. end
  4330. function Social_GetShareScreenshotLink()
  4331. local index = C_Social.GetLastScreenshot();
  4332. return format("|c%s|Hsharess:%d|h%s|h|r", SHARE_ICON_COLOR, index, SHARE_ICON_TEXT);
  4333. end