Guest User

Untitled

a guest
Jun 26th, 2017
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 42.55 KB | None | 0 0
  1. // ==UserScript==
  2. // @name PS
  3. // @namespace k
  4. // @match http://*.psim.us/
  5. // @version 1
  6. // @grant none
  7. // ==/UserScript==
  8.  
  9.  
  10. var pmLogs = {};
  11. window.app.customOpts = {
  12. rps: false,
  13. bj: false,
  14. uno: false,
  15. rpsCount: 0,
  16. btCounter: 0,
  17. ignorePMFrom: [],
  18. monsToCheck: [],
  19. monsToEvolve: [],
  20. };
  21. if (window.localStorage['pms']) pmLogs = JSON.parse(window.localStorage['pms']);
  22.  
  23. addGlobalStyle('.pm-logs {background: rgba(108, 106, 106, 0.52);};');
  24. addGlobalStyle('.userbar {position: absolute; top: 12px; right: 47px; font-weight: bold;};');
  25. addGlobalStyle('.userbar2 {position: absolute; top: 12px; right: 17px; font-weight: bold;};');
  26. addGlobalStyle('.userbar2 button.icon {height: 25px;width: 27px;font-size: 16px;text-align: center;padding: 0;};');
  27.  
  28. /*
  29. * PM Logging
  30. */
  31.  
  32. window.resetPMLogs = function () {
  33. pmLogs = {};
  34. window.localStorage['pms'] = "{}";
  35. }
  36.  
  37. window.logPM = function logPM(windowName, message) {
  38. if (~windowName.indexOf('news')) return;
  39. if (!pmLogs[windowName]) pmLogs[windowName] = [];
  40. pmLogs[windowName].push(message);
  41. if (pmLogs[windowName].length > 50) pmLogs[windowName].splice(0, 1);
  42. window.localStorage['pms'] = JSON.stringify(pmLogs);
  43. }
  44.  
  45. window.room.openPM = function (name, dontFocus) {
  46. var userid = toId(name);
  47. var $pmWindow = this.$pmBox.find('.pm-window-' + userid);
  48. if (!$pmWindow.length) {
  49. var group = name.charAt(0);
  50. if (group === ' ') {
  51. group = '';
  52. } else {
  53. group = '<small>' + Tools.escapeHTML(group) + '</small>';
  54. }
  55. var buf = '<div class="pm-window pm-window-' + userid + '" data-userid="' + userid + '" data-name="' + name + '">';
  56. buf += '<h3><button class="closebutton" href="' + app.root + 'teambuilder" tabindex="-1"><i class="fa fa-times-circle"></i></button>';
  57. buf += '<button class="minimizebutton" href="' + app.root + 'teambuilder" tabindex="-1"><i class="fa fa-minus-circle"></i></button>';
  58. buf += group + Tools.escapeHTML(name.substr(1)) + '</h3>';
  59. buf += '<div class="pm-log"><div class="inner"></div></div>';
  60. buf += '<div class="pm-log-add"><form class="chatbox nolabel"><textarea class="textbox" type="text" size="70" autocomplete="off" name="message"></textarea></form></div></div>';
  61. $pmWindow = $(buf).prependTo(this.$pmBox);
  62. $pmWindow.find('textarea').autoResize({
  63. animate: false,
  64. extraSpace: 0
  65. });
  66. // create up/down history for this PM
  67. this.chatHistories[userid] = new ChatHistory();
  68. if (pmLogs[userid]) {
  69. var $chat = $pmWindow.find('.inner');
  70. for (var u in pmLogs[userid]) {
  71. $chat.append(pmLogs[userid][u]);
  72. }
  73. }
  74. } else {
  75. $pmWindow.show();
  76. if (!dontFocus) {
  77. var $chatFrame = $pmWindow.find('.pm-log');
  78. var $chat = $pmWindow.find('.inner');
  79. $chatFrame.scrollTop($chat.height());
  80. }
  81. }
  82. if (!dontFocus) this.$el.scrollTop(0);
  83. return $pmWindow;
  84. }
  85.  
  86.  
  87. window.room.addPM = function (name, message, target) {
  88. var userid = toUserid(name);
  89. if (app.ignore[userid] && name.substr(0, 1) in {' ': 1, '!': 1, '✖': 1, '‽': 1}) return;
  90.  
  91. var isSelf = (toId(name) === app.user.get('userid'));
  92. var oName = isSelf ? target : name;
  93. Storage.logChat('pm-' + toId(oName), '' + name + ': ' + message);
  94.  
  95. var $pmWindow = this.openPM(oName, true);
  96. var $chatFrame = $pmWindow.find('.pm-log');
  97. var $chat = $pmWindow.find('.inner');
  98.  
  99. var autoscroll = ($chatFrame.scrollTop() + 60 >= $chat.height() - $chatFrame.height());
  100.  
  101. var parsedMessage = Tools.parseChatMessage(message, name, ChatRoom.getTimestamp('pms'));
  102. if (!$.isArray(parsedMessage)) parsedMessage = [parsedMessage];
  103. for (var i = 0; i < parsedMessage.length; i++) {
  104. if (!parsedMessage[i]) continue;
  105. $chat.append(parsedMessage[i]);
  106. logPM(toId(oName), '<div class="pm-logs">' + parsedMessage[i] + '</div>');
  107. }
  108.  
  109. var $lastMessage = $chat.children().last();
  110. var textContent = $lastMessage.html().indexOf('<span class="spoiler">') >= 0 ? '(spoiler)' : $lastMessage.children().last().text();
  111. if (textContent && app.curSideRoom && app.curSideRoom.addPM && Tools.prefs('inchatpm')) {
  112. app.curSideRoom.addPM(name, textContent, target);
  113. }
  114.  
  115. if (!isSelf && textContent) {
  116. this.notifyOnce("PM from " + name, "\"" + textContent + "\"", 'pm');
  117. }
  118.  
  119. if (autoscroll) {
  120. $chatFrame.scrollTop($chat.height());
  121. }
  122.  
  123. if (!$pmWindow.hasClass('focused') && name.substr(1) !== app.user.get('name')) {
  124. $pmWindow.find('h3').addClass('pm-notifying');
  125. }
  126. }
  127.  
  128. /*
  129. * Options
  130. */
  131.  
  132. window.app.topbar.updateUserbar = function () {
  133. var buf = '';
  134. var name = ' ' + app.user.get('name');
  135. var color = hashColor(app.user.get('userid'));
  136. if (!app.user.loaded) {
  137. buf = '<button disabled>Loading...</button>';
  138. } else if (app.user.get('named')) {
  139. buf = '<span class="username" data-name="' + Tools.escapeHTML(name) + '" style="' + color + '"><i class="fa fa-user" style="color:#779EC5"></i> ' + Tools.escapeHTML(name) + '</span>';
  140. } else {
  141. buf = '<button name="login">Choose name</button>';
  142. }
  143. buf += ' <button class="icon button" name="openSounds" title="Sound"><i class="' + (Tools.prefs('mute') ? 'fa fa-volume-off' : 'fa fa-volume-up') + '"></i></button> <button class="icon button" name="openOptions" title="Options"><i class="fa fa-cog"></i></button>';
  144. buf += ' <button class="icon button" name="openCustomOptions" title="Custom Options"><i class="fa fa-cog"></i></button>'
  145. this.$userbar.html(buf);
  146. }
  147.  
  148. window.app.topbar.openCustomOptions = function () {
  149. app.addPopup(CustomOptionsPopup);
  150. }
  151.  
  152. window.CustomOptionsPopup = this.CustomOptionsPopup = window.Popup.extend({
  153. initialize: function (data) {
  154. app.user.on('change', this.update, this);
  155. this.update();
  156. },
  157. events: {
  158. 'change input[name=noanim]': 'setNoanim',
  159. 'change input[name=bwgfx]': 'setBwgfx',
  160. 'change input[name=nopastgens]': 'setNopastgens',
  161. 'change input[name=notournaments]': 'setNotournaments',
  162. 'change input[name=inchatpm]': 'setInchatpm',
  163. 'change input[name=dark]': 'setDark',
  164. 'change input[name=temporarynotifications]': 'setTemporaryNotifications',
  165. 'change select[name=bg]': 'setBg',
  166. 'change select[name=timestamps-lobby]': 'setTimestampsLobby',
  167. 'change select[name=timestamps-pms]': 'setTimestampsPMs',
  168. 'change input[name=logchat]': 'setLogChat',
  169. 'change input[name=selfhighlight]': 'setSelfHighlight',
  170. 'click img': 'avatars'
  171. },
  172. update: function () {
  173. var buf = '';
  174. var timestamps = this.timestamps = (Tools.prefs('timestamps') || {});
  175. buf += '<p>Marketplace:</p>';
  176. buf += '<p><label class="optlabel">Autojoin Giveaways: <button name="joinGiveaways" ' + (Tools.prefs('joinGiveaways') ? 'disabled' : '') + '>On</button> <button name="joinGiveaways" ' + (Tools.prefs('joinGiveaways') ? '' : 'disabled') + '>Off</button></label></p>';
  177. buf += '<p><label class="optlabel">Auto Blackjack: <button name="toggleBJ" ' + (app.customOpts.bj ? 'disabled' : '') + '>On</button> <button name="toggleBJ" ' + (app.customOpts.bj ? '' : 'disabled') + '>Off</button></label></p>';
  178. buf += '<p><label class="optlabel">Auto Uno: <button name="toggleUno" ' + (app.customOpts.uno ? 'disabled' : '') + '>On</button> <button name="toggleUno" ' + (app.customOpts.uno ? '' : 'disabled') + '>Off</button></label></p>';
  179. buf += '<p>Experience Grinding:</p>';
  180. buf += '<p><label class="optlabel">Auto RPS: <button name="toggleRPS" ' + (app.customOpts.rps ? 'disabled' : '') + '>On</button> <button name="toggleRPS" ' + (app.customOpts.rps ? '' : 'disabled') + '>Off</button></label></p>';
  181. buf += '<p><label class="optlabel">Auto BT: <button name="toggleBT" ' + (app.customOpts.bt ? 'disabled' : '') + '>On</button> <button name="toggleBT" ' + (app.customOpts.bt ? '' : 'disabled') + '>Off</button></label></p>';
  182. buf += '<p>RPS Messages: ' + app.customOpts.rpsCount + '</p>';
  183. buf += '<p>BT Messages: ' + app.customOpts.btCounter + '</p>';
  184. buf += '<p>Misc:</p>';
  185. buf += '<p><label class="optlabel"><button name="massPM">Mass PM</button></label></p>';
  186. buf += '<p><label class="optlabel"><button name="buyEggs">Buy All Eggs</button></label></p>';
  187. buf += '<p><label class="optlabel"><button name="findMons">Evolve All Pets</button></label></p>';
  188. this.$el.html(buf).css('min-width', 160);
  189. },
  190. toggleRPS: function () {
  191. app.customOpts.rps = !app.customOpts.rps;
  192. if (app.customOpts.rps) {
  193. app.send('/rps search');
  194. } else {
  195. app.send('/rps endsearch');
  196. }
  197. this.update();
  198. },
  199. toggleBJ: function () {
  200. app.customOpts.bj = !app.customOpts.bj;
  201. this.update();
  202. },
  203. toggleBT: function () {
  204. app.customOpts.bt = !app.customOpts.bt;
  205. if (app.customOpts.bt) {
  206. app.send('/bt set battlefactory');
  207. app.send('/bt');
  208. }
  209. this.update();
  210. },
  211. toggleUno: function () {
  212. app.customOpts.uno = !app.customOpts.uno;
  213. this.update();
  214. },
  215. joinGiveaways: function () {
  216. var toggle = !Tools.prefs('joinGiveaways');
  217. Tools.prefs('joinGiveaways', toggle);
  218. this.update();
  219. },
  220. buyEggs: function () {
  221. if (app.customOpts.buyingEggs) return this.close();
  222. app.customOpts.buyingEggs = true;
  223. app.send('/pets');
  224. this.close();
  225. },
  226. findMons: function () {
  227. if (app.customOpts.findMons) return this.close();
  228. app.customOpts.findMons = true;
  229. app.send('/pets');
  230. this.close();
  231. },
  232. massPM: function () {
  233. this.close();
  234. app.addPopup(app.massPMPopup);
  235. }
  236. });
  237.  
  238. window.app.receive = function (data) {
  239. var roomid = '';
  240. var autojoined = false;
  241. if (data.trim() === 'You are now searching for a game of Rock/Paper/Scissors (ladder).') return;
  242. if (data.substr(0, 1) === '>') {
  243. var nlIndex = data.indexOf('\n');
  244. if (nlIndex < 0) return;
  245. roomid = toRoomid(data.substr(1, nlIndex - 1));
  246. data = data.substr(nlIndex + 1);
  247. }
  248. if (data.substr(0, 6) === '|init|') {
  249. if (!roomid) roomid = 'lobby';
  250. var roomType = data.substr(6);
  251. var roomTypeLFIndex = roomType.indexOf('\n');
  252. if (roomTypeLFIndex >= 0) roomType = roomType.substr(0, roomTypeLFIndex);
  253. roomType = toId(roomType);
  254. if (this.rooms[roomid] || roomid === 'staff' || roomid === 'upperstaff') {
  255. // autojoin rooms are joined in background
  256. this.addRoom(roomid, roomType, true);
  257. } else {
  258. this.joinRoom(roomid, roomType, true);
  259. }
  260. if (roomType === 'chat') autojoined = true;
  261. } else if ((data + '|').substr(0, 8) === '|expire|') {
  262. var room = this.rooms[roomid];
  263. if (room) {
  264. room.expired = (data.substr(8) || true);
  265. if (room.updateUser) room.updateUser();
  266. }
  267. return;
  268. } else if ((data + '|').substr(0, 8) === '|deinit|' || (data + '|').substr(0, 8) === '|noinit|') {
  269. if (!roomid) roomid = 'lobby';
  270.  
  271. if (this.rooms[roomid] && this.rooms[roomid].expired) {
  272. // expired rooms aren't closed when left
  273. return;
  274. }
  275.  
  276. var isdeinit = (data.charAt(1) === 'd');
  277. data = data.substr(8);
  278. var pipeIndex = data.indexOf('|');
  279. var errormessage;
  280. if (pipeIndex >= 0) {
  281. errormessage = data.substr(pipeIndex + 1);
  282. data = data.substr(0, pipeIndex);
  283. }
  284. // handle error codes here
  285. // data is the error code
  286. if (data === 'namerequired') {
  287. var self = this;
  288. this.once('init:choosename', function () {
  289. self.send('/join ' + roomid);
  290. });
  291. } else if (data !== 'namepending') {
  292. if (isdeinit) { // deinit
  293. if (this.rooms[roomid] && this.rooms[roomid].type === 'chat') {
  294. this.removeRoom(roomid, true);
  295. this.updateAutojoin();
  296. } else {
  297. this.removeRoom(roomid, true);
  298. }
  299. } else { // noinit
  300. this.unjoinRoom(roomid);
  301. if (roomid === 'lobby') this.joinRoom('rooms');
  302. }
  303. if (errormessage) {
  304. if (data === 'nonexistent' && Config.server.id && roomid.slice(0, 7) === 'battle-') {
  305. var replayid = roomid.slice(7);
  306. if (Config.server.id !== 'showdown') replayid = Config.server.id + '-' + replayid;
  307. var replayLink = 'http://replay.pokemonshowdown.com/' + replayid;
  308. errormessage += '\n\nYou might want to try the replay: ' + replayLink;
  309. }
  310. this.addPopupMessage(errormessage);
  311. }
  312. }
  313. return;
  314. } else if (data.substr(0, 3) === '|N|') {
  315. var names = data.substr(1).split('|');
  316. if (app.ignore[toUserid(names[2])]) {
  317. app.ignore[toUserid(names[1])] = 1;
  318. }
  319. }
  320. if (roomid) {
  321. if (this.rooms[roomid]) {
  322. this.rooms[roomid].receive(data);
  323. }
  324. if (autojoined) this.updateAutojoin();
  325. return;
  326. }
  327.  
  328. // Since roomid is blank, it could be either a global message or
  329. // a lobby message. (For bandwidth reasons, lobby messages can
  330. // have blank roomids.)
  331.  
  332. // If it starts with a messagetype in the global messagetype
  333. // list, we'll assume global; otherwise, we'll assume lobby.
  334.  
  335. var parts;
  336. if (data.charAt(0) === '|') {
  337. parts = data.substr(1).split('|');
  338. } else {
  339. parts = [];
  340. }
  341.  
  342. switch (parts[0]) {
  343. case 'challstr':
  344. if (parts[2]) {
  345. this.user.receiveChallstr(parts[1] + '|' + parts[2]);
  346. } else {
  347. this.user.receiveChallstr(parts[1]);
  348. }
  349. break;
  350.  
  351. case 'formats':
  352. this.parseFormats(parts);
  353. break;
  354.  
  355. case 'updateuser':
  356. setTimeout(function () {app.topbar.updateUserbar();}, 5000);
  357. var nlIndex = data.indexOf('\n');
  358. if (nlIndex > 0) {
  359. this.receive(data.substr(nlIndex + 1));
  360. nlIndex = parts[3].indexOf('\n');
  361. parts[3] = parts[3].substr(0, nlIndex);
  362. }
  363. var name = parts[1];
  364. var named = !!+parts[2];
  365.  
  366. var userid = toUserid(name);
  367. if (userid === this.user.get('userid') && name !== this.user.get('name')) {
  368. $.post(app.user.getActionPHP(), {
  369. act: 'changeusername',
  370. username: name
  371. }, function () {}, 'text');
  372. }
  373.  
  374. this.user.set({
  375. name: name,
  376. userid: userid,
  377. named: named,
  378. avatar: parts[3]
  379. });
  380. this.user.setPersistentName(named ? name : null);
  381. if (named) {
  382. this.trigger('init:choosename');
  383. }
  384. if (app.ignore[toUserid(name)]) {
  385. delete app.ignore[toUserid(name)];
  386. }
  387. break;
  388.  
  389. case 'nametaken':
  390. app.addPopup(LoginPopup, {name: parts[1] || '', error: parts[2] || ''});
  391. break;
  392.  
  393. case 'queryresponse':
  394. var responseData = JSON.parse(data.substr(16 + parts[1].length));
  395. app.trigger('response:' + parts[1], responseData);
  396. break;
  397.  
  398. case 'updatechallenges':
  399. if (this.rooms['']) {
  400. this.rooms[''].updateChallenges($.parseJSON(data.substr(18)));
  401. }
  402. break;
  403.  
  404. case 'updatesearch':
  405. if (this.rooms['']) {
  406. this.rooms[''].updateSearch($.parseJSON(data.substr(14)));
  407. }
  408. break;
  409.  
  410. case 'popup':
  411. var maxWidth;
  412. var type = 'semimodal';
  413. data = data.substr(7);
  414. if (data.substr(0, 6) === '|wide|') {
  415. data = data.substr(6);
  416. maxWidth = 960;
  417. }
  418. if (data.substr(0, 7) === '|modal|') {
  419. data = data.substr(7);
  420. type = 'modal';
  421. }
  422. if (data.substr(0, 6) === '|html|') {
  423. data = data.substr(6);
  424. if (app.customOpts.bt) {
  425. if (data.match(/\"\/petbattles choose [a-z]+\"/g)) {
  426. app.send(data.match(/\"\/petbattles choose [a-z]+\"/g)[0].replace(/\"/g, ''));
  427. app.customOpts.btCounter++;
  428. return;
  429. }
  430. if (app.customOpts.bt && data.match(/has won the battle\!/g)) {
  431. app.send('/bt');
  432. app.customOpts.btCounter++;
  433. return;
  434. }
  435. }
  436. if (app.customOpts.buyingEggs && data.match(/₽[0-9]+/)) {
  437. var money = Number(data.match(/₽[0-9]+/)[0].replace(/₽/, ''));
  438. if (money > 250) {
  439. app.send('/pets buyegg');
  440. } else {
  441. app.customOpts.buyingEggs = false;
  442. }
  443. }
  444. if (app.customOpts.findMons && data.match(/₽[0-9]+/)) {
  445. console.log('finding mons');
  446. var ids = [];
  447. data = data.replace(/<button name=send value="\/pets viewmon m-[a0-z9]+-[a0-z9]+-[a0-z9]+-[a0-z9]+-[a0-z9]+" class="card\-button" ><div style="height:80px; width: 80px; background\-image: url\('http:\/\/cdn\.bulbagarden\.net\/upload\/d\/dc\/Spr_3r_Egg\.png'\); background\-repeat: no\-repeat; background\-size: contain; background\-position: center"><\/div><\/button>/g, '');
  448. var matches = data.match(/\/pets viewmon m-[a0-z9]+-[a0-z9]+-[a0-z9]+-[a0-z9]+-[a0-z9]+/g);
  449. for (var u in matches) {
  450. app.customOpts.monsToCheck.push(matches[u].replace(/\/pets viewmon /, ''));
  451. }
  452. app.customOpts.findMons = false;
  453. if (app.customOpts.monsToCheck.length > 0) {
  454. app.customOpts.checkMons = true;
  455. console.log('mons found: checkMons true');
  456. app.send('/pets viewmon ' + app.customOpts.monsToCheck[0]);
  457. }
  458. }
  459. if (app.customOpts.checkMons && data.match(/₽[0-9]+/) && data.match(/\/pets evolve m-[a0-z9]+-[a0-z9]+-[a0-z9]+-[a0-z9]+-[a0-z9]+, [a-z]+/)) {
  460. console.log('evolving mon');
  461. app.customOpts.monsToEvolve.push(data.match(/\/pets evolve m-[a0-z9]+-[a0-z9]+-[a0-z9]+-[a0-z9]+-[a0-z9]+, [a-z]+/)[0]);
  462. app.customOpts.monsToCheck.splice(0, 1);
  463. if (app.customOpts.monsToCheck.length > 0) {
  464. app.send('/pets viewmon ' + app.customOpts.monsToCheck[0]);
  465. console.log('viewing next mon');
  466. } else {
  467. console.log('out of mons to check');
  468. app.customOpts.checkMons = false;
  469. evolveMons();
  470. }
  471. }
  472. if (app.customOpts.checkMons && data.match(/₽[0-9]+/) && data.match(/(Unable to evolve|\(Requires [0-9]+ more EXP to evolve\))/)) {
  473. console.log('unable to evolve');
  474. app.customOpts.monsToCheck.splice(0, 1);
  475. if (app.customOpts.monsToCheck.length > 0) {
  476. console.log('checking next mon');
  477. app.send('/pets viewmon ' + app.customOpts.monsToCheck[0]);
  478. } else {
  479. console.log('out of mons to check 2');
  480. app.customOpts.checkMons = false;
  481. evolveMons();
  482. }
  483. }
  484. app.addPopup(Popup, {
  485. type: type,
  486. maxWidth: maxWidth,
  487. htmlMessage: Tools.sanitizeHTML(data)
  488. });
  489. } else {
  490. app.addPopup(Popup, {
  491. type: type,
  492. maxWidth: maxWidth,
  493. message: data.replace(/\|\|/g, '\n')
  494. });
  495. }
  496. if (this.rooms['']) this.rooms[''].resetPending();
  497. break;
  498.  
  499. case 'disconnect':
  500. app.trigger('init:socketclosed', Tools.sanitizeHTML(data.substr(12)));
  501. break;
  502.  
  503. case 'pm':
  504. var dataLines = data.split('\n');
  505. for (var i = 0; i < dataLines.length; i++) {
  506. parts = dataLines[i].slice(1).split('|');
  507. var message = parts.slice(3).join('|');
  508. if (~app.customOpts.ignorePMFrom.indexOf(toId(parts[2]))) {
  509. app.customOpts.ignorePMFrom.splice(app.customOpts.ignorePMFrom.indexOf(toId(parts[1])), 1);
  510. return;
  511. }
  512. if (message.match(/\/rps choose P [A-Z]+-[0-9]+/)) {
  513. let rpsId = message.match(/\/rps choose P [A-Z]+-[0-9]+/)[0].split(' ').pop();
  514. let rpsChoices = ['R', 'P', 'S'];
  515. app.send('/rps choose ' + rpsChoices[Math.floor(Math.random() * rpsChoices.length)] + ' ' + rpsId);
  516. }
  517. if (app.customOpts.rps && parts[1] === '~Rock/Paper/Scissors Host' && data.match(/(You have lost the game against|You have won the game against|The game with)/)) {
  518. app.send('/rps search');
  519. }
  520. if (parts[1] === '~Rock/Paper/Scissors Host') {
  521. app.customOpts.rpsCount++;
  522. continue;
  523. }
  524. if (app.customOpts.bj && toId(parts[1]) === 'afterlifeguardian' && data.match(/Your hand is/)) {
  525. var id = toId(message.match(/\[[a-z]+\]/)[0]);
  526. var score = Number(message.split(' ').pop());
  527. if (score < 22) {
  528. if (score >= 18) {
  529. setTimeout(function () {
  530. app.send('.stay', id);
  531. }, randomNumber(5, 15) * 1000);
  532. } else {
  533. setTimeout(function () {
  534. app.send('.hit', id);
  535. }, randomNumber(5, 15) * 1000);
  536. }
  537. }
  538. }
  539. this.rooms[''].addPM(parts[1], message, parts[2]);
  540. if (toUserid(parts[1]) !== app.user.get('userid')) {
  541. app.user.lastPM = toUserid(parts[1]);
  542. }
  543. }
  544. break;
  545.  
  546. case 'roomerror':
  547. // deprecated; use |deinit| or |noinit|
  548. this.unjoinRoom(parts[1]);
  549. this.addPopupMessage(parts.slice(2).join('|'));
  550. break;
  551.  
  552. case 'refresh':
  553. // refresh the page
  554. document.location.reload(true);
  555. break;
  556.  
  557. case 'c':
  558. case 'chat':
  559. if (parts[1] === '~') {
  560. if (parts[2].substr(0, 6) === '/warn ') {
  561. app.addPopup(RulesPopup, {warning: parts[2].substr(6)});
  562. break;
  563. }
  564. }
  565.  
  566. /* fall through */
  567. default:
  568. // the messagetype wasn't in our list of recognized global
  569. // messagetypes; so the message is presumed to be for the
  570. // lobby.
  571. if (this.rooms['lobby']) {
  572. this.rooms['lobby'].receive(data);
  573. }
  574. break;
  575. }
  576. }
  577.  
  578.  
  579. window.ChatRoom = this.ChatRoom = ConsoleRoom.extend({
  580. minWidth: 320,
  581. minMainWidth: 580,
  582. maxWidth: 1024,
  583. isSideRoom: true,
  584. initialize: function () {
  585. var buf = '<div class="tournament-wrapper"></div><div class="chat-log"><div class="inner"></div></div></div><div class="chat-log-add">Connecting...</div><ul class="userlist"></ul>';
  586. this.$el.addClass('ps-room-light').html(buf);
  587.  
  588. this.$chatAdd = this.$('.chat-log-add');
  589. this.$chatFrame = this.$('.chat-log');
  590. this.$chat = this.$('.inner');
  591. this.$chatbox = null;
  592.  
  593. this.$tournamentWrapper = this.$('.tournament-wrapper');
  594. this.tournamentBox = null;
  595.  
  596. this.users = {};
  597. this.userCount = {};
  598.  
  599. this.$joinLeave = null;
  600. this.joinLeave = {
  601. 'join': [],
  602. 'leave': []
  603. };
  604.  
  605. this.$userList = this.$('.userlist');
  606. this.userList = new UserList({
  607. el: this.$userList,
  608. room: this
  609. });
  610. },
  611. updateLayout: function () {
  612. if (this.$el.width() >= 570) {
  613. this.userList.show();
  614. this.$chatFrame.addClass('hasuserlist');
  615. this.$chatAdd.addClass('hasuserlist');
  616. this.$tournamentWrapper.addClass('hasuserlist');
  617. } else {
  618. this.userList.hide();
  619. this.$chatFrame.removeClass('hasuserlist');
  620. this.$chatAdd.removeClass('hasuserlist');
  621. this.$tournamentWrapper.removeClass('hasuserlist');
  622. }
  623. this.$chatFrame.scrollTop(this.$chat.height());
  624. if (this.tournamentBox) this.tournamentBox.updateLayout();
  625. },
  626. show: function () {
  627. Room.prototype.show.apply(this, arguments);
  628. this.updateLayout();
  629. },
  630. join: function () {
  631. app.send('/join ' + this.id);
  632. },
  633. leave: function () {
  634. app.send('/leave ' + this.id);
  635. app.updateAutojoin();
  636. },
  637. receive: function (data) {
  638. this.add(data);
  639. },
  640. add: function (log) {
  641. if (typeof log === 'string') log = log.split('\n');
  642. var autoscroll = false;
  643. if (this.$chatFrame.scrollTop() + 60 >= this.$chat.height() - this.$chatFrame.height()) {
  644. autoscroll = true;
  645. }
  646. var userlist = '';
  647. for (var i = 0; i < log.length; i++) {
  648. if (log[i].substr(0, 7) === '|users|') {
  649. userlist = log[i];
  650. } else {
  651. this.addRow(log[i]);
  652. }
  653. }
  654. if (userlist) this.addRow(userlist);
  655. if (autoscroll) {
  656. this.$chatFrame.scrollTop(this.$chat.height());
  657. }
  658. var $children = this.$chat.children();
  659. if ($children.length > 900) {
  660. $children.slice(0, 100).remove();
  661. }
  662. },
  663. addPM: function (user, message, pm) {
  664. var autoscroll = false;
  665. if (this.$chatFrame.scrollTop() + 60 >= this.$chat.height() - this.$chatFrame.height()) {
  666. autoscroll = true;
  667. }
  668. this.addChat(user, message, pm);
  669. if (autoscroll) {
  670. this.$chatFrame.scrollTop(this.$chat.height());
  671. }
  672. if (!app.focused && !Tools.prefs('mute') && Tools.prefs('notifvolume')) {
  673. soundManager.getSoundById('notif').setVolume(Tools.prefs('notifvolume')).play();
  674. }
  675. },
  676. addRow: function (line) {
  677. var name, name2, room, action, silent, oldid;
  678. var self = this;
  679. if (line && typeof line === 'string') {
  680. if (line.substr(0, 1) !== '|') line = '||' + line;
  681. var row = line.substr(1).split('|');
  682. switch (row[0]) {
  683. case 'init':
  684. // ignore (handled elsewhere)
  685. break;
  686.  
  687. case 'title':
  688. this.title = row[1];
  689. app.roomTitleChanged(this);
  690. app.topbar.updateTabbar();
  691. break;
  692.  
  693. case 'c':
  694. case 'chat':
  695. if (/[a-zA-Z0-9]/.test(row[1].charAt(0))) row[1] = ' ' + row[1];
  696. this.addChat(row[1], row.slice(2).join('|'));
  697. break;
  698.  
  699. case ':':
  700. this.timeOffset = ~~(Date.now() / 1000) - (parseInt(row[1], 10) || 0);
  701. break;
  702. case 'c:':
  703. if (/[a-zA-Z0-9]/.test(row[2].charAt(0))) row[2] = ' ' + row[2];
  704. var msgTime = this.timeOffset + (parseInt(row[1], 10) || 0);
  705. this.addChat(row[2], row.slice(3).join('|'), false, msgTime);
  706. if (app.customOpts.bj && toId(row[2]) === 'afterlifeguardian' && (row.slice(3).join('|').trim() === 'A new game of blackjack is starting. do +join to join the game!' || row.slice(3).join('|').trim() === 'A new game of blakejack is starting. do +join to join the game!')) {
  707. setTimeout(function () {
  708. app.send('.join', self.id);
  709. }, randomNumber(5, 30) * 1000);
  710. }
  711. break;
  712.  
  713. case 'tc':
  714. if (/[a-zA-Z0-9]/.test(row[2].charAt(0))) row[2] = ' ' + row[2];
  715. var msgTime = row[1] ? ~~(Date.now() / 1000) - (parseInt(row[1], 10) || 0) : 0;
  716. this.addChat(row[2], row.slice(3).join('|'), false, msgTime);
  717. break;
  718.  
  719. case 'b':
  720. case 'B':
  721. var id = row[1];
  722. name = row[2];
  723. name2 = row[3];
  724. silent = (row[0] === 'B');
  725.  
  726. var matches = ChatRoom.parseBattleID(id);
  727. if (!matches) {
  728. return; // bogus room ID could be used to inject JavaScript
  729. }
  730. var format = Tools.escapeFormat(matches ? matches[1] : '');
  731.  
  732. if (silent && !Tools.prefs('showbattles')) return;
  733.  
  734. this.addJoinLeave();
  735. var battletype = 'Battle';
  736. if (format) {
  737. battletype = format + ' battle';
  738. if (format === 'Random Battle') battletype = 'Random Battle';
  739. }
  740. this.$chat.append('<div class="notice"><a href="' + app.root + id + '" class="ilink">' + battletype + ' started between <strong style="' + hashColor(toUserid(name)) + '">' + Tools.escapeHTML(name) + '</strong> and <strong style="' + hashColor(toUserid(name2)) + '">' + Tools.escapeHTML(name2) + '</strong>.</a></div>');
  741. break;
  742.  
  743. case 'j':
  744. case 'join':
  745. case 'J':
  746. this.addJoinLeave('join', row[1], null, row[0] === 'J');
  747. break;
  748.  
  749. case 'l':
  750. case 'leave':
  751. case 'L':
  752. this.addJoinLeave('leave', row[1], null, row[0] === 'L');
  753. break;
  754.  
  755. case 'n':
  756. case 'name':
  757. case 'N':
  758. this.addJoinLeave('rename', row[1], row[2], true);
  759. break;
  760.  
  761.  
  762. case 'users':
  763. this.parseUserList(row[1]);
  764. break;
  765.  
  766. case 'usercount':
  767. if (this.id === 'lobby') {
  768. this.userCount.globalUsers = parseInt(row[1], 10);
  769. this.userList.updateUserCount();
  770. }
  771. break;
  772.  
  773. case 'formats':
  774. // deprecated; please send formats to the global room
  775. app.parseFormats(row);
  776. break;
  777.  
  778. case 'raw':
  779. case 'html':
  780. this.$chat.append('<div class="notice">' + Tools.sanitizeHTML(row.slice(1).join('|')) + '</div>');
  781. var id = this.id;
  782. if (app.customOpts.uno && row.slice(1).join('|').match(/A new game of UNO is starting!/)) {
  783. setTimeout(function () {
  784. app.send('/uno join', id);
  785. }, randomNumber(5, 30) * 1000);
  786. }
  787. break;
  788.  
  789. case 'error':
  790. this.$chat.append('<div class="notice message-error">' + Tools.escapeHTML(row.slice(1).join('|')) + '</div>');
  791. break;
  792.  
  793. case 'uhtml':
  794. this.$chat.append('<div class="notice uhtml-' + toId(row[1]) + '">' + Tools.sanitizeHTML(row.slice(2).join('|')) + '</div>');
  795. var html = row.slice(2).join('|');
  796. if (html.match(/<button name="send" value="\/giveaway joinlottery">/) && Tools.prefs('joinGiveaways')) {
  797. app.send('/giveaway joinlottery', this.id);
  798. }
  799. if (app.customOpts.uno && html.match(/y [A0-Z9](\+[A0-Z9]|[A0-Z9])/g)) {
  800. parseUno(html, this.id);
  801. }
  802. break;
  803.  
  804. case 'uhtmlchange':
  805. var $elements = this.$chat.find('div.uhtml-' + toId(row[1]));
  806. if (!$elements.length) break;
  807. $elements.html(Tools.sanitizeHTML(row.slice(2).join('|')));
  808. var html = row.slice(2).join('|');
  809. if (app.customOpts.uno && html.match(/y [A0-Z9](\+[A0-Z9]|[A0-Z9])/g)) {
  810. parseUno(html, this.id);
  811. }
  812. break;
  813.  
  814. case 'unlink':
  815. // note: this message has global effects, but it's handled here
  816. // so that it can be included in the scrollback buffer.
  817. if (Tools.prefs('nounlink')) return;
  818. var user = toId(row[2]) || toId(row[1]);
  819. var $messages = $('.chatmessage-' + user);
  820. if (!$messages.length) break;
  821. $messages.find('a').contents().unwrap();
  822. if (row[2]) {
  823. // there used to be a condition for
  824. // row[1] === 'roomhide'
  825. // but it's now always applied
  826. $messages = this.$chat.find('.chatmessage-' + user);
  827. if (!$messages.length) break;
  828. $messages.hide().addClass('revealed').find('button').parent().remove();
  829. this.$chat.children().last().append(' <button name="toggleMessages" value="' + user + '" class="subtle"><small>(' + $messages.length + ' line' + ($messages.length > 1 ? 's' : '') + ' from ' + user + ' hidden)</small></button>');
  830. }
  831. break;
  832.  
  833. case 'tournament':
  834. case 'tournaments':
  835. if (Tools.prefs('notournaments')) break;
  836. if (!this.tournamentBox) this.tournamentBox = new TournamentBox(this, this.$tournamentWrapper);
  837. if (!this.tournamentBox.parseMessage(row.slice(1), row[0] === 'tournaments')) break;
  838. // fallthrough in case of unparsed message
  839.  
  840. case '':
  841. this.$chat.append('<div class="notice">' + Tools.escapeHTML(row.slice(1).join('|')) + '</div>');
  842. break;
  843.  
  844. default:
  845. this.$chat.append('<div class="notice"><code>|' + Tools.escapeHTML(row.join('|')) + '</code></div>');
  846. break;
  847. }
  848. }
  849. },
  850. toggleMessages: function (user, button) {
  851. var $messages = this.$('.chatmessage-' + user + '.revealed');
  852. var $button = $(button);
  853. if (!$messages.is(':hidden')) {
  854. $messages.hide();
  855. $button.html('<small>(' + ($messages.length) + ' line' + ($messages.length !== 1 ? 's' : '') + ' from ' + user + ' hidden)</small>');
  856. } else {
  857. $button.html('<small>(Hide ' + ($messages.length) + ' line' + ($messages.length !== 1 ? 's' : '') + ' from ' + user + ')</small>');
  858. $messages.show();
  859. }
  860. },
  861. tournamentButton: function (val, button) {
  862. if (this.tournamentBox) this.tournamentBox[$(button).data('type')](val, button);
  863. },
  864. parseUserList: function (userList) {
  865. this.userCount = {};
  866. this.users = {};
  867. var commaIndex = userList.indexOf(',');
  868. if (commaIndex >= 0) {
  869. this.userCount.users = parseInt(userList.substr(0, commaIndex), 10);
  870. var users = userList.substr(commaIndex + 1).split(',');
  871. for (var i = 0, len = users.length; i < len; i++) {
  872. if (users[i]) this.users[toId(users[i])] = users[i];
  873. }
  874. } else {
  875. this.userCount.users = parseInt(userList, 10);
  876. this.userCount.guests = this.userCount.users;
  877. }
  878. this.userList.construct();
  879. },
  880. addJoinLeave: function (action, name, oldid, silent) {
  881. var userid = toUserid(name);
  882. if (!action) {
  883. this.$joinLeave = null;
  884. this.joinLeave = {
  885. 'join': [],
  886. 'leave': []
  887. };
  888. return;
  889. } else if (action === 'join') {
  890. if (oldid) delete this.users[toUserid(oldid)];
  891. if (!this.users[userid]) this.userCount.users++;
  892. this.users[userid] = name;
  893. this.userList.add(userid);
  894. this.userList.updateUserCount();
  895. this.userList.updateNoUsersOnline();
  896. } else if (action === 'leave') {
  897. if (this.users[userid]) this.userCount.users--;
  898. delete this.users[userid];
  899. this.userList.remove(userid);
  900. this.userList.updateUserCount();
  901. this.userList.updateNoUsersOnline();
  902. } else if (action === 'rename') {
  903. if (oldid) delete this.users[toUserid(oldid)];
  904. this.users[userid] = name;
  905. this.userList.remove(oldid);
  906. this.userList.add(userid);
  907. return;
  908. }
  909. var allShowjoins = Tools.prefs('showjoins') || {};
  910. var showjoins = allShowjoins[Config.server.id];
  911. if (silent && (!showjoins || (!showjoins['global'] && !showjoins[this.id]) || showjoins[this.id] === 0)) {
  912. return;
  913. }
  914. if (!this.$joinLeave) {
  915. this.$chat.append('<div class="message"><small>Loading...</small></div>');
  916. this.$joinLeave = this.$chat.children().last();
  917. }
  918. this.joinLeave[action].push(name);
  919. var message = '';
  920. if (this.joinLeave['join'].length) {
  921. var preList = this.joinLeave['join'];
  922. var list = [];
  923. var named = {};
  924. for (var j = 0; j < preList.length; j++) {
  925. if (!named[preList[j]]) list.push(preList[j]);
  926. named[preList[j]] = true;
  927. }
  928. for (var j = 0; j < list.length; j++) {
  929. if (j >= 5) {
  930. message += ', and ' + (list.length - 5) + ' others';
  931. break;
  932. }
  933. if (j > 0) {
  934. if (j == 1 && list.length == 2) {
  935. message += ' and ';
  936. } else if (j == list.length - 1) {
  937. message += ', and ';
  938. } else {
  939. message += ', ';
  940. }
  941. }
  942. message += Tools.escapeHTML(list[j]);
  943. }
  944. message += ' joined';
  945. }
  946. if (this.joinLeave['leave'].length) {
  947. if (this.joinLeave['join'].length) {
  948. message += '; ';
  949. }
  950. var preList = this.joinLeave['leave'];
  951. var list = [];
  952. var named = {};
  953. for (var j = 0; j < preList.length; j++) {
  954. if (!named[preList[j]]) list.push(preList[j]);
  955. named[preList[j]] = true;
  956. }
  957. for (var j = 0; j < list.length; j++) {
  958. if (j >= 5) {
  959. message += ', and ' + (list.length - 5) + ' others';
  960. break;
  961. }
  962. if (j > 0) {
  963. if (j == 1 && list.length == 2) {
  964. message += ' and ';
  965. } else if (j == list.length - 1) {
  966. message += ', and ';
  967. } else {
  968. message += ', ';
  969. }
  970. }
  971. message += Tools.escapeHTML(list[j]);
  972. }
  973. message += ' left<br />';
  974. }
  975. this.$joinLeave.html('<small style="color: #555555">' + message + '</small>');
  976. },
  977. addChat: function (name, message, pm, msgTime) {
  978. var userid = toUserid(name);
  979.  
  980. if (app.ignore[userid] && (name.charAt(0) === ' ' || name.charAt(0) === '+')) return;
  981.  
  982. // Add this user to the list of people who have spoken recently.
  983. this.markUserActive(userid);
  984.  
  985. this.$joinLeave = null;
  986. this.joinLeave = {
  987. 'join': [],
  988. 'leave': []
  989. };
  990.  
  991. if (pm) {
  992. var pmuserid = toUserid(pm);
  993. var oName = pmuserid === app.user.get('userid') ? name : pm;
  994. var clickableName = '<span class="username" data-name="' + Tools.escapeHTML(name) + '">' + Tools.escapeHTML(name.substr(1)) + '</span>';
  995. this.$chat.append(
  996. '<div class="chat chatmessage-' + toId(name) + '">' + ChatRoom.getTimestamp('lobby', msgTime) +
  997. '<strong style="' + hashColor(userid) + '">' + clickableName + ':</strong>' +
  998. '<span class="message-pm"><i class="pmnote" data-name="' + Tools.escapeHTML(oName) + '">(Private to ' + Tools.escapeHTML(pm) + ')</i> ' + Tools.parseMessage(message) + '</span>' +
  999. '</div>'
  1000. );
  1001. return; // PMs independently notify in the man menu; no need to make them notify again with `inchatpm`.
  1002. }
  1003.  
  1004. var lastMessageDates = Tools.prefs('logtimes') || (Tools.prefs('logtimes', {}), Tools.prefs('logtimes'));
  1005. if (!lastMessageDates[Config.server.id]) lastMessageDates[Config.server.id] = {};
  1006. var lastMessageDate = lastMessageDates[Config.server.id][this.id] || 0;
  1007. var mayNotify = msgTime > lastMessageDate && userid !== app.user.get('userid');
  1008.  
  1009. if (app.focused && (this === app.curSideRoom || this === app.curRoom)) {
  1010. this.lastMessageDate = 0;
  1011. lastMessageDates[Config.server.id][this.id] = msgTime;
  1012. Storage.prefs.save();
  1013. } else {
  1014. // To be saved on focus
  1015. this.lastMessageDate = Math.max(this.lastMessageDate || 0, msgTime);
  1016. }
  1017.  
  1018. var isHighlighted = userid !== app.user.get('userid') && this.getHighlight(message);
  1019. var parsedMessage = Tools.parseChatMessage(message, name, ChatRoom.getTimestamp('chat', msgTime), isHighlighted);
  1020. if (!$.isArray(parsedMessage)) parsedMessage = [parsedMessage];
  1021. for (var i = 0; i < parsedMessage.length; i++) {
  1022. if (!parsedMessage[i]) continue;
  1023. this.$chat.append(parsedMessage[i]);
  1024. }
  1025.  
  1026. if (mayNotify && isHighlighted) {
  1027. if (!Tools.prefs('mute') && Tools.prefs('notifvolume')) {
  1028. soundManager.getSoundById('notif').setVolume(Tools.prefs('notifvolume')).play();
  1029. }
  1030. var $lastMessage = this.$chat.children().last();
  1031. var notifyTitle = "Mentioned by " + name + (this.id === 'lobby' ? '' : " in " + this.title);
  1032. var notifyText = $lastMessage.html().indexOf('<span class="spoiler">') >= 0 ? '(spoiler)' : $lastMessage.children().last().text();
  1033. this.notifyOnce(notifyTitle, "\"" + notifyText + "\"", 'highlight');
  1034. } else if (mayNotify && name !== '~') { // |c:|~| prefixes a system message
  1035. this.subtleNotifyOnce();
  1036. }
  1037.  
  1038. if (message.slice(0, 4) === '/me ' || message.slice(0, 5) === '/mee') {
  1039. Storage.logChat(this.id, '* ' + name + (message.slice(0, 4) === '/me ' ? ' ' : '') + message);
  1040. } else if (message.slice(0, 5) === '/log ') {
  1041. Storage.logChat(this.id, '' + message.slice(5));
  1042. } else {
  1043. Storage.logChat(this.id, '' + name + ': ' + message);
  1044. }
  1045. },
  1046. destroy: function (alreadyLeft) {
  1047. if (this.tournamentBox) {
  1048. app.user.off('saveteams', this.tournamentBox.updateTeams, this.tournamentBox);
  1049. }
  1050. ConsoleRoom.prototype.destroy.call(this, alreadyLeft);
  1051. },
  1052. }, {
  1053. getTimestamp: function (section, msgTime) {
  1054. var pref = Tools.prefs('timestamps') || {};
  1055. var sectionPref = ((section === 'pms') ? pref.pms : pref.lobby) || 'off';
  1056. if ((sectionPref === 'off') || (sectionPref === undefined)) return '';
  1057.  
  1058. var date = (msgTime && !isNaN(msgTime) ? new Date(msgTime * 1000) : new Date());
  1059. var components = [date.getHours(), date.getMinutes()];
  1060. if (sectionPref === 'seconds') {
  1061. components.push(date.getSeconds());
  1062. }
  1063. return '<small>[' + components.map(
  1064. function (x) { return (x < 10) ? '0' + x : x; }
  1065. ).join(':') + '] </small>';
  1066. },
  1067. parseBattleID: function (id) {
  1068. if (id.lastIndexOf('-') > 6) {
  1069. return id.match(/^battle\-([a-z0-9]*)\-?[0-9]*$/);
  1070. }
  1071. return id.match(/^battle\-([a-z0-9]*[a-z])[0-9]*$/);
  1072. }
  1073. });
  1074.  
  1075. /*
  1076. * Mass PM
  1077. */
  1078.  
  1079. /*
  1080.  
  1081. <select name="cars">
  1082. <option value="volvo">Volvo</option>
  1083. <option value="saab">Saab</option>
  1084. <option value="fiat">Fiat</option>
  1085. <option v
  1086.  
  1087. */
  1088.  
  1089. var MassPMPopup = app.massPMPopup = Popup.extend({
  1090. type: 'semimodal',
  1091. initialize: function (data) {
  1092. var buf = '<form>';
  1093. var rooms = [];
  1094. for (var u in app.rooms) {
  1095. if (!app.rooms[u].title || app.rooms[u].title.length < 1) continue;
  1096. rooms.push(app.rooms[u].title);
  1097. }
  1098. if (data.error) {
  1099. buf += '<p class="error">' + data.error + '</p>';
  1100. }
  1101. buf += '<p>Mass PM:</p>'
  1102. buf += '<p>Room: <select name="room">';
  1103. for (var i in rooms) buf += '<option value="' + toId(rooms[i]) + '">' + Tools.escapeHTML(rooms[i]) + '</option>';
  1104. buf += '</select></p>';
  1105. buf += '<p>Message: <label><input class="textbox autofocus" name="message"/></label></p>';
  1106. buf += '<p>PM Staff: <label><input type="checkbox" name="staff"/></label></p>';
  1107. buf += '<p class="buttonbar"><button type="submit"><strong>Submit</strong></button> <button name="close">Cancel</button></p></form>';
  1108. this.$el.html(buf);
  1109. },
  1110. submit: function (data) {
  1111. if (!data.message) {
  1112. return app.addPopup(MassPMPopup, {error: "Message may not be blank"});
  1113. }
  1114. massPM(data.message, data.room, (data.staff ? true : false));
  1115. this.close();
  1116. }
  1117. });
  1118.  
  1119.  
  1120. /*
  1121. * Functions
  1122. */
  1123.  
  1124. function evolveMons() {
  1125. if (app.customOpts.monsToEvolve.length < 1) return;
  1126. app.customOpts.evolveTimer = setInterval(function () {
  1127. if (app.customOpts.monsToEvolve.length < 1) return clearInterval(app.customOpts.evolveTimer);
  1128. app.send(app.customOpts.monsToEvolve[0]);
  1129. app.customOpts.monsToEvolve.splice(0, 1);
  1130. }, 600);
  1131. }
  1132.  
  1133. function massPM(message, room, pmStaff) {
  1134. var users = [];
  1135. for (var u in app.rooms[toId(room)].users) {
  1136. if (!pmStaff && app.rooms[toId(room)].users[u].charAt(0) !== ' ' || toId(app.rooms[toId(room)].users[u]) === toId(app.user.get('name'))) continue;
  1137. users.push(app.rooms[toId(room)].users[u]);
  1138. }
  1139. var messages = [];
  1140. for (var i in users) {
  1141. app.customOpts.ignorePMFrom.push(toId(users[i]));
  1142. messages.push('/msg ' + users[i] + ', ' + message);
  1143. }
  1144. app.customOpts.pmTimer = setInterval(function () {
  1145. if (!messages[0]) return clearInterval(app.customOpts.pmTimer);
  1146. app.send(messages[0]);
  1147. messages.splice(0, 1);
  1148. }, 600);
  1149. }
  1150.  
  1151. function parseUno(html, id) {
  1152. var cards = html.match(/y [A0-Z9](\+[A0-Z9]|[A0-Z9])/g)
  1153. var colour = html.match(/background: [a-z]+/)[0].replace(/background: /, '');
  1154. var type = html.match(/(white">|white" size=6>|black">|black" size=6>|size=4>)(\+4|S|W|R|\+[0-9]|[0-9])/)[0].replace(/(white">|white" size=6>|black">|black" size=6>|size=4>)/, '');
  1155. var drawn = html.match(/You have drawn/);
  1156. var newColour = '';
  1157. var played;
  1158. if (type === '+4' || type === 'W') newColour = html.match(/Change to: <font color="[a-z]+/)[0].replace(/Change to: <font color="/, '');
  1159. for (var u in cards) cards[u] = cards[u].replace(/y /, '');
  1160.  
  1161. console.log('uno cards: ' + cards.join(', '));
  1162. console.log('uno colour: ' + colour);
  1163. console.log('uno type: ' + type);
  1164. console.log('uno newColour: ' + newColour);
  1165.  
  1166. for (var i in cards) {
  1167. if (cards[i].charAt(0) === 'W' || cards[i].charAt(0) === '+') continue;
  1168. console.log('uno currentCard: ' + cards[i]);
  1169. if ((cards[i].charAt(0).toLowerCase() === colour.charAt(0) && colour !== 'black') || cards[i].charAt(0).toLowerCase() === newColour.charAt(0)) { // card matches played card colour
  1170. console.log('uno: card matches target card colour');
  1171. setTimeout(function () {
  1172. app.send('/uno play ' + cards[i], id);
  1173. }, randomNumber(5, 15) * 1000);
  1174. played = true;
  1175. break;
  1176. }
  1177. if ((colour !== 'black' && cards[i].charAt(0).toLowerCase() === colour.charAt(0).toLowerCase()) || cards[i] === type) { // card matches played card number/type
  1178. console.log('uno: card matches number/type');
  1179. setTimeout(function () {
  1180. app.send('/uno play ' + cards[i], id);
  1181. }, randomNumber(5, 15) * 1000);
  1182. played = true;
  1183. break;
  1184. }
  1185. if (cards[i].substr(1, 2) === '+2' && type === '+2') {
  1186. console.log('top card +2; playing our +2 (no colour match)');
  1187. setTimeout(function () {
  1188. app.send('/uno play ' + cards[i], id);
  1189. }, randomNumber(5, 15) * 1000);
  1190. played = true;
  1191. break;
  1192. }
  1193. if (cards[i].charAt(1) === type) { // matching numbers
  1194. console.log('uno: (' + cards[i] + ') (' + type + ')');
  1195. setTimeout(function () {
  1196. app.send('/uno play ' + cards[i], id);
  1197. }, randomNumber(5, 15) * 1000);
  1198. played = true;
  1199. break;
  1200. }
  1201. }
  1202. for (var o in cards) {
  1203. console.log('uno wildcard played');
  1204. if (cards[i] === 'W+4' || cards[i] === 'WW') { // we have a wildcard; play it
  1205. console.log('uno: we have +4; playing it');
  1206. var changeTo = 'R';
  1207. for (var c in cards) {
  1208. if (cards[c].charAt(0) in ['R', 'B', 'G', 'Y']) changeTo = cards[c].charAt(0);
  1209. }
  1210. setTimeout(function () {
  1211. app.send('/uno play ' + cards[i] + ' ' + changeTo, id);
  1212. }, randomNumber(5, 15) * 1000);
  1213. played = true;
  1214. break;
  1215. }
  1216. }
  1217. if (!played) {
  1218. if (!drawn) {
  1219. setTimeout(function () {
  1220. app.send('/uno draw', id);
  1221. }, randomNumber(5, 15) * 1000);
  1222. } else {
  1223. setTimeout(function () {
  1224. app.send('/uno pass', id);
  1225. }, randomNumber(3, 7) * 1000);
  1226. }
  1227. }
  1228. }
  1229.  
  1230. function randomNumber(min, max) {
  1231. return Math.floor(Math.random() * (max - min + 1) + min);
  1232. }
  1233.  
  1234. function randomString(length) {
  1235. return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1);
  1236. }
  1237.  
  1238. function addGlobalStyle(css) {
  1239. var head, style;
  1240. head = document.getElementsByTagName('head')[0];
  1241. if (!head) { return; }
  1242. style = document.createElement('style');
  1243. style.type = 'text/css';
  1244. style.innerHTML = css;
  1245. head.appendChild(style);
  1246. }
Add Comment
Please, Sign In to add comment