Greasy Fork is available in English.

TagPro GroPro

Enhance your group experience!

Bu scripti kur?
Yazarın tavsiye ettiği betik

Siz bunuda beğenebilirsiniz: TagPro RL Chat.

Bu scripti kur
  1. // ==UserScript==
  2. // @name TagPro GroPro
  3. // @version 1.6
  4. // @description Enhance your group experience!
  5. // @author Ko
  6. // @supportURL https://www.reddit.com/message/compose/?to=Wilcooo
  7. // @website https://redd.it/7rbvi4
  8. // @icon https://raw.githubusercontent.com/wilcooo/TagPro-ScriptResources/master/gropro.png
  9. // @match *://*.koalabeast.com/*
  10. // @match *://*.jukejuice.com/*
  11. // @match *://*.newcompte.fr/*
  12. // @grant GM_notification
  13. // @grant GM_xmlhttpRequest
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // @license MIT
  17. // @require https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.0/socket.io.slim.js
  18. // @require https://greasyfork.org/scripts/371240/code/TagPro%20Userscript%20Library.js
  19. // @connect koalabeast.com
  20. // @connect script.google.com
  21. // @connect script.googleusercontent.com
  22. // @namespace https://greasyfork.org/users/152992
  23. // ==/UserScript==
  24.  
  25.  
  26.  
  27. /* todo
  28.  
  29. Use TPUL's GroupComm:
  30. ready states
  31. description
  32.  
  33. Kicking should also make a "doink" sound
  34.  
  35. */
  36.  
  37.  
  38.  
  39. // =====SETTINGS SECTION=====
  40.  
  41.  
  42. // I use tpul for this userscripts' options.
  43. // see: https://github.com/wilcooo/TagPro-UserscriptLibrary
  44.  
  45. var settings = tpul.settings.addSettings({
  46. id: 'GroPro',
  47. title: "Configure GroPro",
  48. tooltipText: "GroPro",
  49. icon: "https://raw.githubusercontent.com/wilcooo/TagPro-ScriptResources/master/gropro.png",
  50.  
  51.  
  52. fields: {
  53. show_notifications: {
  54. label: 'Notify chat messages while doing something else',
  55. type: 'checkbox',
  56. default: true,
  57. },
  58. sound_on_chat: {
  59. label: '"Bwep" whenever someone sends a message',
  60. type: 'checkbox',
  61. default: true,
  62. },
  63. sound_on_join: {
  64. label: '"Dink" whenever someone joins',
  65. type: 'checkbox',
  66. default: true,
  67. },
  68. sound_on_left: {
  69. label: '"Donk" whenever someone leaves',
  70. type: 'checkbox',
  71. default: true,
  72. },
  73. color_names: {
  74. label: 'Color names in chat',
  75. type: 'checkbox',
  76. default: true,
  77. },
  78. show_timestamps: {
  79. label: 'Show timestamps in chat',
  80. type: 'checkbox',
  81. default: true,
  82. },
  83. show_seconds: {
  84. label: 'Show seconds on those timestamps',
  85. type: 'checkbox',
  86. default: true,
  87. },
  88. fade_read_chats: {
  89. label: 'Fade those timestamps when you\'ve read it',
  90. type: 'checkbox',
  91. default: true,
  92. },
  93. chat_history: {
  94. label: 'Use the up/down keys to resend messages (console-like)',
  95. type: 'checkbox',
  96. default: true,
  97. },
  98. prevent_scroll: {
  99. label: 'Show an arrow when new chats arrive, while you\'re reading old chats',
  100. type: 'checkbox',
  101. default: true,
  102. },
  103. /*groups_on_home: {
  104. label: 'Show available groups (worldwide) on the homepage',
  105. type: 'checkbox',
  106. default: true,
  107. },
  108. groups_on_find: {
  109. label: 'Show available groups (worldwide) while finding a game',
  110. type: 'checkbox',
  111. default: true,
  112. },
  113. groups_in_group: {
  114. label: 'Show available groups (worldwide) while in a group',
  115. type: 'checkbox',
  116. default: true,
  117. },
  118. position: {
  119. label: 'Position of the groups on the homepage',
  120. type: 'select',
  121. options: ['top','bottom'],
  122. default: 'top',
  123. },*/
  124. show_description: {
  125. label: 'Show the group\'s description, and enables you to set one',
  126. type: 'checkbox',
  127. default: true,
  128. },
  129. show_ready_states: {
  130. label: 'Show which players are ready',
  131. type: 'checkbox',
  132. default: true,
  133. },
  134. show_ready_btn: {
  135. label: 'Show an "I\'m ready!" button',
  136. type: 'checkbox',
  137. default: true,
  138. },
  139. show_play_btn: {
  140. label: 'Show a "Join a pub" button, which will take only you to the joiner.',
  141. type: 'checkbox',
  142. default: true,
  143. },
  144. show_someball_btn: {
  145. label: 'Show an "Add Some Ball" button, in case you need more players to launch',
  146. type: 'checkbox',
  147. default: true,
  148. }
  149. },
  150.  
  151. events: {
  152. open: function () {
  153.  
  154. // Changing the layout a bit after the config panel is opened...
  155.  
  156. [...this.frame.getElementsByClassName('field_label')].forEach( function(el) {
  157. el.classList.remove('col-xs-4');
  158. el.classList.add('col-xs-8');
  159. el.nextElementSibling.classList.remove('col-xs-8');
  160. el.nextElementSibling.classList.add('col-xs-4');
  161. } );
  162. },
  163. save: function() {
  164.  
  165. // Making sure (most) options take effect immediately after a save...
  166.  
  167. show_notifications = settings.get("show_notifications");
  168. sound_on_chat = settings.get("sound_on_chat");
  169. sound_on_join = settings.get("sound_on_join");
  170. sound_on_left = settings.get("sound_on_left");
  171. show_timestamps = settings.get("show_timestamps");
  172. show_seconds = settings.get("show_seconds");
  173. fade_read_chats = settings.get("fade_read_chats");
  174. chat_history = settings.get("chat_history");
  175. prevent_scroll = settings.get("prevent_scroll");
  176. /*position = settings.get("position");
  177. groups_on_home = settings.get("groups_on_home");
  178. groups_on_find = settings.get("groups_on_find");
  179. groups_in_group = settings.get("groups_in_group");*/
  180. show_ready_states = settings.get("show_ready_states");
  181. show_ready_btn = settings.get("show_ready_btn");
  182. show_play_btn = settings.get("show_play_btn");
  183. show_someball_btn = settings.get("show_someball_btn");
  184.  
  185.  
  186. /*// Update the position of the groups if necessary:
  187.  
  188. var groups_div = document.getElementById('GroPro-groups');
  189.  
  190. if (window.location.pathname === '/' && groups_on_home ||
  191. window.location.pathname.match(/^\/groups\/[a-z]{8}$/) && groups_in_group ||
  192. window.location.pathname === '/games/find' && groups_on_find ) {
  193.  
  194. if (groups_div) {
  195. var pos = document.getElementById('userscript-'+position);
  196. if (insertBefore) pos.insertBefore(groups_div, pos.firstChild);
  197. else pos.append(groups_div);
  198. pos.classList.remove('hidden');
  199. groups_div.classList.remove('hidden');
  200. } else show_groups();
  201. }
  202.  
  203. if (window.location.pathname === '/' && !groups_on_home ||
  204. window.location.pathname.match(/^\/groups\/[a-z]{8}$/) && !groups_in_group ||
  205. window.location.pathname === '/games/find' && !groups_on_find ) {
  206.  
  207. groups_div.classList.add('hidden');
  208. }*/
  209.  
  210.  
  211. // Some options need a refresh, show a warning when they're changed:
  212.  
  213. if (color_names != settings.get("color_names") ||
  214. show_description != settings.get("show_description") ||
  215. show_ready_btn != settings.get("show_ready_btn") ||
  216. show_play_btn != settings.get("show_play_btn") ||
  217. show_someball_btn != settings.get("show_someball_btn")) {
  218.  
  219. if (tpul.playerLocation == 'group')
  220. setTimeout(tpul.notify, 1500, "Some settings might only take effect after a refresh", "warning");
  221. }
  222. },
  223. }
  224. });
  225.  
  226.  
  227. var show_notifications = settings.get("show_notifications");
  228. var sound_on_chat = settings.get("sound_on_chat");
  229. var sound_on_join = settings.get("sound_on_join");
  230. var sound_on_left = settings.get("sound_on_left");
  231. var color_names = settings.get("color_names");
  232. var show_timestamps = settings.get("show_timestamps");
  233. var show_seconds = settings.get("show_seconds");
  234. var fade_read_chats = settings.get("fade_read_chats");
  235. var chat_history = settings.get("chat_history");
  236. var prevent_scroll = settings.get("prevent_scroll");
  237. /*var groups_on_home = settings.get("groups_on_home");
  238. var groups_on_find = settings.get("groups_on_find");
  239. var groups_in_group = settings.get("groups_in_group");
  240. var position = settings.get("position");*/
  241. var show_description = settings.get("show_description");
  242. var show_ready_states = settings.get("show_ready_states");
  243. var show_ready_btn = settings.get("show_ready_btn");
  244. var show_play_btn = settings.get("show_play_btn");
  245. var show_someball_btn = settings.get("show_someball_btn");
  246.  
  247.  
  248. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  249. // ### --- SOUNDS --- ### //
  250. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //
  251. // //
  252. var chat_sound = new Audio('https://raw.githubusercontent.com/wilcooo/TagPro-ScriptResources/master/chat.mp3'); // //
  253. var left_sound = new Audio('https://raw.githubusercontent.com/wilcooo/TagPro-ScriptResources/master/left.mp3'); // //
  254. var join_sound = new Audio('https://raw.githubusercontent.com/wilcooo/TagPro-ScriptResources/master/joined.mp3'); // //
  255. // //
  256. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //
  257. // //
  258. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265. //////////////////////////////////////
  266. // SCROLL FURTHER AT YOUR OWN RISK! //
  267. //////////////////////////////////////
  268.  
  269.  
  270.  
  271.  
  272. var short_name = 'gropro'; // An alphabetic (no spaces/numbers, preferably lowercase) distinctive name for the script.
  273. var version = GM_info.script.version; // The version number is automatically fetched from the metadata.
  274. tagpro.ready(function(){ tagpro.scripts = Object.assign( tagpro.scripts || {}, {short_name:{version:version}} ); });
  275. console.log('START: ' + GM_info.script.name + ' (v' + version + ' by ' + GM_info.script.author + ')');
  276.  
  277.  
  278.  
  279.  
  280.  
  281. if (tpul.playerLocation == 'groups') { // If we are on the groups selection page
  282. }
  283.  
  284. else if (tpul.playerLocation == 'group') { // If we are in a group
  285.  
  286. //if (groups_in_group) show_groups();
  287.  
  288. tagpro.ready( function(){
  289.  
  290.  
  291.  
  292.  
  293. // Keep track of all interesting variables.
  294. // TagPro does this too, but it's hidden :(
  295. // Thats why we do this ourselfs too :)
  296.  
  297. var group = tagpro.group = Object.assign(tagpro.group, {
  298. self: null,
  299. players: {},
  300. privateGame: $(".group.container").hasClass("js-private-game"),
  301. privateGroup: false,
  302. currentGamePort: null,
  303. chat: [],
  304. selfAssignment: false,
  305. settings: {},
  306. maxPlayers: 0,
  307. maxSpectators: 0,
  308. });
  309.  
  310. var socket = group.socket;
  311.  
  312. socket.on('chat', function(chat) {
  313. chat.time = Date.now(); // This is not in the original TagPro code, but it's handy
  314. group.chat.push(chat);
  315. });
  316.  
  317. socket.on('port', function(port) {
  318. group.currentGamePort = port;
  319. });
  320.  
  321. socket.on('member', function(member) {
  322. if (!group.players[member.id]) send_description(); // Not original TP code either
  323.  
  324. // This is slightly altered to allow a 'ready' variable to persist
  325. group.players[member.id] = Object.assign(group.players[member.id] || {}, member);
  326.  
  327. if (group.self) group.self = group.players[group.self.id];
  328. });
  329.  
  330. socket.on('removed', function(removed) {
  331. delete group.players[removed.id];
  332. });
  333.  
  334. socket.on('full', function() {
  335. alert('GroPro: This group is full :(');
  336. });
  337.  
  338. socket.on('banned', function() {
  339. alert('GroPro: You got banned :(');
  340. });
  341.  
  342. socket.on('you', function(you) {
  343. group.self = group.players[you];
  344. });
  345.  
  346. socket.on('private', function(private){
  347. group.privateGame = private.isPrivate;
  348. group.maxSpectators = private.maxSpectators;
  349. group.maxPlayers = private.maxPlayers;
  350. group.selfAssignment = private.selfAssignment;
  351. group.noScript = private.noScript;
  352. group.respawnWarnings = private.respawnWarnings;
  353. });
  354.  
  355. socket.on('setting', function(setting) {
  356. group.settings[setting.name] = setting.value;
  357. });
  358.  
  359. socket.on('publicGroup', function(publicGroup) {
  360. group.public = publicGroup;
  361. });
  362.  
  363.  
  364.  
  365. var chat_log = document.getElementsByClassName('js-chat-log')[0];
  366.  
  367.  
  368.  
  369.  
  370.  
  371. // Show notifications on receiving chats // Play sound
  372. function notify(chat){
  373. if (show_notifications && !document.hasFocus()) {
  374. // GM_notification( text, title, icon (defaults to script icon), onclick)
  375. GM_notification( chat.message, chat.from || group.settings.groupName, null, window.focus );
  376. }
  377.  
  378. // Play a sound
  379. if (chat.from && sound_on_chat) chat_sound.play();
  380. //has been kicked from the group.
  381. else if (sound_on_left && (chat.message.endsWith(' has left the group.') || chat.message.endsWith(' has been kicked from the group.')) )
  382. left_sound.play();
  383. else if (sound_on_join && chat.message.endsWith(' has joined the group.'))
  384. join_sound.play();
  385. else if (sound_on_chat) chat_sound.play();
  386. }
  387.  
  388.  
  389.  
  390.  
  391.  
  392. // This function will fade the timestamp when you've seen the message
  393. function fadeTimestamp(t) {
  394.  
  395. // If the window isn't focussed
  396. if(!document.hasFocus()) {
  397. return window.addEventListener("focus", function() {
  398. fadeTimestamp(t);
  399. }, {once:true});
  400. }
  401.  
  402. // If the chat row is not in view (due to scrolling)
  403. if ( t[0].offsetTop < chat_log.scrollTop || t[0].offsetTop > chat_log.scrollTop + chat_log.clientHeight ) {
  404. return chat_log.addEventListener("scroll", function(){
  405. fadeTimestamp(t);
  406. }, {once:true});
  407. }
  408.  
  409. // Wait 3 secs, and fade if the document is still focussed
  410. else {
  411. setTimeout( function(){
  412. if (document.hasFocus())
  413. t.fadeTo("slow",0.4);
  414. else fadeTimestamp(t);
  415. }, 3000);
  416. }
  417. }
  418.  
  419.  
  420.  
  421.  
  422.  
  423. // Don't scroll down when reading old messages
  424.  
  425. var scrolled = true;
  426.  
  427. chat_log.addEventListener("scroll", function(){
  428. scrolled = chat_log.scrollTop >= chat_log.scrollHeight - chat_log.clientHeight;
  429. if (scrolled) arrow.style.display = 'none';
  430. });
  431.  
  432. function scrollChat() {
  433. if (!prevent_scroll || scrolled)
  434. chat_log.scrollTop = chat_log.scrollHeight;
  435.  
  436. else {arrow.style.display = '';}
  437. }
  438.  
  439. var last_chat = '';
  440.  
  441. // Show an arrow instead, that'll bring you back down
  442.  
  443. $('<img id="chat-log-arrow" style="position:absolute;right:30px;top:150px;display:none" src="https://raw.githubusercontent.com/wilcooo/TagPro-ScriptResources/master/arrow.png">').appendTo(chat_log);
  444. var arrow = document.getElementById('chat-log-arrow');
  445. arrow.style.cursor = 'pointer';
  446. arrow.title = 'New messages!';
  447. arrow.onclick = function(){
  448. chat_log.scrollTop = chat_log.scrollHeight;
  449. arrow.style.display = 'none';
  450. };
  451.  
  452.  
  453.  
  454.  
  455.  
  456. // This function receives all chat messages
  457.  
  458. function handleChat(chat) {
  459.  
  460. var player = group.players[Object.keys(group.players).filter( id => group.players[id].name == chat.from )[0]];
  461. var match;
  462.  
  463. // Append messages starting with ⋯
  464. var last = group.chat[group.chat.length-1] || {from:null};
  465.  
  466. if ( chat.message.startsWith('⋯') && last.from == chat.from && last.time > Date.now()-5) {
  467. last_chat = last_chat + chat.message.slice(1);
  468. $(".js-chat-log .chat-message").last().text( last_chat );
  469.  
  470. scrollChat();
  471.  
  472. return;
  473. }
  474.  
  475. // Handle commands (DEPRECATED, USE THE NEW COMMANDS SYSTEM!)
  476. if ( ( match = chat.message.match(/^\[GroPro:(\w{1,11})\](.{0,100})$/) ) ) { // If the message is of the form [GroPro:xxx]yyy
  477. var command = match[1], // the xxx part
  478. value = match[2]; // the yyy part
  479.  
  480. if (command=='description' && player.leader) {
  481. group.description = value;
  482.  
  483. if (show_description) update_gd();
  484.  
  485. return;
  486. }
  487.  
  488. if (command=='ready') {
  489. player.ready = true;
  490. updateReadyStates();
  491. if (!value) return;
  492. }
  493.  
  494. if (command=='notready') {
  495. player.ready = false;
  496. updateReadyStates();
  497. if (!value) return;
  498. }
  499.  
  500. var warning = tagpro.helpers.displayError('Someone sent an unrecognizable command (as you can see in chat). The sender probably doesn\'t know what GroPro is, or you don\'t have the latest version installed.');
  501. warning[0].onclick = ()=>warning.fadeOut(); // Click to hide
  502. warning[0].style.cursor = 'pointer';
  503. warning[0].title = 'Click to hide';
  504. }
  505.  
  506. // Handle an actual message
  507. last_chat = chat.message;
  508.  
  509.  
  510. var timestamp;
  511.  
  512. if (show_timestamps) {
  513. var time = new Date().toTimeString().substr(0, show_seconds ? 8 : 5 );
  514. timestamp = $("<span></span>").addClass("timestamp").text( time );
  515. if (fade_read_chats) fadeTimestamp(timestamp);
  516. }
  517.  
  518. var player_name = null;
  519. if (chat.from) {
  520. var team = player && player.team+1 ? " team-"+player.team : "";
  521.  
  522. player_name = $("<span></span>").addClass("player-name" + team).text(chat.from + ": ");
  523. }
  524.  
  525. var chat_message = $("<span></span>").text(chat.message).addClass("chat-message");
  526. $("<div></div>").addClass("chat-line").append(timestamp).append(player_name).append(chat_message).appendTo(chat_log);
  527.  
  528. scrollChat();
  529.  
  530. notify(chat);
  531. }
  532.  
  533. // Replace TagPro's function that puts chats in the chat-log
  534. socket.listeners('chat')[0] = handleChat;
  535.  
  536. // Find the correct styleSheet
  537. for (var styleSheet of document.styleSheets) if (styleSheet.href.includes('/style.css')) break;
  538.  
  539. // Add a rule to the sheet for the timestamp and player names
  540. styleSheet.insertRule(".group .chat-log .timestamp { margin-right: 5px; color: Yellow; }");
  541.  
  542. if (color_names) {
  543. styleSheet.insertRule(".group .chat-log .player-name { color: #4c4c4c }"); // Gray
  544. styleSheet.insertRule(".group .chat-log .player-name.team-0 { color: #8BC34A; }"); // Green
  545. styleSheet.insertRule(".group .chat-log .player-name.team-1 { color: #D32F2F; }"); // Red
  546. styleSheet.insertRule(".group .chat-log .player-name.team-2 { color: #1976D2; }"); // Blue
  547. styleSheet.insertRule(".group .chat-log .player-name.team-3 { color: #e0e0e0; }"); // White
  548. }
  549.  
  550.  
  551.  
  552.  
  553. // The New Commands System (using 'touch' events / location). Max 12 chars per message!
  554.  
  555. // TODO
  556.  
  557.  
  558.  
  559.  
  560.  
  561. // Split long messages, so that you can send those too
  562. // Also save all sent messages
  563. // for the history option
  564.  
  565. var sent = [], hist = -1, curr = "";
  566.  
  567. $('.js-chat-input').off('keydown'); // Remove old handler
  568.  
  569. document.getElementsByClassName('js-chat-input')[0].onkeydown = function(key){
  570. if (key.which == 13) { // ENTER
  571. sent.unshift(this.value);
  572. hist = -1;
  573.  
  574. if (this.value.length <= 120) socket.emit("chat", this.value);
  575. else {
  576. var cut, chats = [ this.value.slice( 0, 120 ) ];
  577. while ((cut = this.value.slice( chats.length*119+1 ))) {
  578. chats.push( '⋯' + cut.slice(0,119) );
  579. }
  580.  
  581. for (var c of chats) socket.emit("chat", c);
  582. }
  583. this.value = "";
  584.  
  585. //chat_log.scrollTop = chat_log.scrollHeight;
  586. }
  587.  
  588. if (chat_history && key.which == 38) { // ARROW-UP
  589. if (hist == -1) curr = this.value;
  590. if (hist < sent.length-1) {
  591. this.value = sent[ ++hist ];
  592. key.preventDefault(); // Prevent the caret/cursor to jump to the start
  593. }
  594. }
  595. if (chat_history && key.which == 40) { // ARROW-DOWN
  596. if (hist > -1) {
  597. this.value = sent[ --hist ] || curr;
  598. key.preventDefault(); // Prevent the caret to jump to the end
  599. }
  600. }
  601. };
  602.  
  603.  
  604.  
  605.  
  606.  
  607. // Group description
  608.  
  609. document.getElementsByClassName('js-chat-input')[0].placeholder = 'Send a message';
  610.  
  611. if (show_description) {
  612.  
  613. $(`
  614. <div id="gd-container" class="col-md-12" style="display:none"><hr>
  615. <h3 style="float:left;font-size:16px">Group Description</h3>
  616. <div id="gd-btns" style="display:none;float:right;margin-bottom:14px">
  617. <a id="gd-save" class="btn btn-default">Save</a>
  618. <a id="gd-cancel" class="btn btn-default">Cancel</a>
  619. </div>
  620. <textarea readonly id="gd-text" maxlength=100 placeholder="Group description (this is also sent to those without the script)" type="text" style="background:#212121;width:100%;padding:5px 10px;resize:vertical" class="chat"></textarea>
  621. <hr></div>`).insertAfter(document.getElementById('group-chat').parentNode);
  622.  
  623. var gd_container = document.getElementById('gd-container');
  624. var gd_text = document.getElementById('gd-text');
  625. var gd_save = document.getElementById('gd-save');
  626. var gd_cancel = document.getElementById('gd-cancel');
  627. var gd_btns = document.getElementById('gd-btns');
  628.  
  629. gd_save.onclick = function(){
  630. if (gd_text.value != group.description)
  631. socket.emit('chat', "[GroPro:description]"+gd_text.value);
  632.  
  633. gd_btns.style.display = 'none';
  634. };
  635.  
  636. gd_cancel.onclick = function(){
  637. update_gd();
  638.  
  639. gd_btns.style.display = 'none';
  640. };
  641.  
  642. socket.once('you', function(you){
  643.  
  644. update_gd();
  645. socket.on('member', function(member){
  646. if (member.id == group.self.id)
  647. update_gd(false);
  648. });
  649. });
  650. }
  651.  
  652. group.description = "";
  653.  
  654. function editDescription(){
  655. // Show the save/cancel buttons
  656. gd_btns.style.display = '';
  657. }
  658.  
  659. function onLeader(){
  660. gd_text.readOnly = false;
  661. gd_text.onfocus = editDescription;
  662. }
  663.  
  664. function onNonLeader(){
  665. gd_text.readOnly = true;
  666. gd_text.onfocus = null;
  667. gd_text.value = group.description;
  668.  
  669. gd_btns.style.display = 'none';
  670. }
  671.  
  672. function update_gd(text=true) {
  673.  
  674. if (!show_description) return;
  675.  
  676. if (group.description || group.self.leader)
  677. gd_container.style.display = ''; //show
  678. else
  679. gd_container.style.display = 'none'; //hide
  680.  
  681. if (group.self.leader) {
  682. gd_text.readOnly = false;
  683. gd_text.onfocus = editDescription;
  684. } else {
  685. gd_text.readOnly = true;
  686. gd_text.onfocus = null;
  687.  
  688. gd_btns.style.display = 'none';
  689. }
  690.  
  691. if (text) gd_text.value = group.description;
  692. }
  693.  
  694. function send_description() {
  695.  
  696. if (group.self && group.self.leader && group.description ) {
  697. socket.emit('chat', "[GroPro:description]"+gd_text.value);
  698. }
  699. }
  700.  
  701.  
  702.  
  703.  
  704.  
  705.  
  706. // Play (only you) button
  707.  
  708. if (show_play_btn) {
  709.  
  710. //<button id="launch-private-btn" class="btn btn-primary js-socket-btn start-game" data-event="groupPlay" onclick="this.blur();">Launch Game</button>
  711.  
  712. var play_public_btn = document.createElement('a');
  713. play_public_btn.className = 'btn btn-primary';
  714. play_public_btn.innerText = 'Join a Pub';
  715. play_public_btn.title = 'Only you.\nYou will stay in the group.';
  716. play_public_btn.href = '/games/find';
  717. var play_private_btn = play_public_btn.cloneNode(true);
  718.  
  719. var launch_public_btn = document.getElementById('launch-public-btn');
  720. var launch_private_btn = document.getElementById('launch-private-btn');
  721.  
  722. launch_public_btn.parentElement.appendChild( play_public_btn );
  723. launch_private_btn.parentElement.appendChild( play_private_btn );
  724. }
  725.  
  726.  
  727.  
  728.  
  729.  
  730. // Add Some Ball button
  731.  
  732. if (show_someball_btn) {
  733.  
  734. // This function is all the code we need to add a Some Ball
  735. function addSomeBall(){
  736. var http = new XMLHttpRequest()
  737. http.open('GET','http://free.pagepeeker.com/v2/thumbs.php?size=t&url=' + location.href + '?r=pagekeeperyoucancontactmeonreddituWILCOOO' + Math.random())
  738. http.send()
  739. this.blur()
  740. }
  741.  
  742. // The rest is just adding & styling the button
  743. var add_someball_btn = document.createElement('button')
  744. add_someball_btn.title = "For when you need more players to launch.\nThe some ball will leave after a minute."
  745. add_someball_btn.className = "btn btn-default"
  746. add_someball_btn.onclick = addSomeBall
  747.  
  748. add_someball_btn.innerHTML += ' <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="80pt" height="80pt" viewBox="0 0 80 80"> <g transform="translate(0,80)scale(0.1,-0.1)"><path d="M207 638 c-19 -45 -37 -89 -39 -97 -8 -36 195 -61 337 -42 133 18 131 14 85 118 -22 49 -46 92 -54 97 -9 7 -35 3 -76 -9 -55 -17 -67 -17 -108 -5 -108 30 -104 32 -145 -62z"/><path d="M75 474 c-162 -49 -56 -92 251 -101 251 -8 446 15 461 53 8 22 -5 31 -69 48 -54 14 -60 13 -110 -7 -46 -18 -73 -21 -213 -21 -141 0 -166 3 -215 22 -30 12 -55 22 -55 21 0 0 -22 -7 -50 -15z"/><path d="M40 305 c0 -8 9 -15 20 -15 18 0 20 -7 20 -80 0 -107 13 -120 121 -120 43 0 89 5 103 11 30 14 56 65 56 108 0 29 2 31 40 31 l40 0 0 -44 c0 -33 6 -52 24 -73 23 -26 30 -28 113 -31 122 -5 134 5 141 116 3 61 8 82 18 82 8 0 14 7 14 15 0 13 -46 15 -355 15 -309 0 -355 -2 -355 -15z m280 -73 c0 -91 -13 -102 -116 -102 l-84 0 0 80 0 80 100 0 100 0 0 -58z m360 -6 c0 -97 1 -96 -95 -96 -96 0 -106 7 -113 80 -7 79 -7 80 108 80 l100 0 0 -64z"/></g></svg> '
  749. add_someball_btn.innerHTML += ' Add Some Ball '
  750.  
  751. document.getElementsByClassName('player-settings')[0].appendChild(add_someball_btn)
  752. }
  753.  
  754.  
  755.  
  756.  
  757.  
  758.  
  759.  
  760. // Ready button
  761.  
  762. // First, add the button
  763.  
  764. if (show_ready_btn) {
  765.  
  766. var ready_public_btn = document.createElement('label');
  767. ready_public_btn.className = 'btn btn-default group-setting';
  768. ready_public_btn.style.marginRight = '14px';
  769. ready_public_btn.innerHTML = '<input type="checkbox" style="margin:0;vertical-align:middle"> I\'m Ready!';
  770. var ready_private_btn = ready_public_btn.cloneNode(true);
  771.  
  772. var launch_public_btn = document.getElementById('launch-public-btn');
  773. var launch_private_btn = document.getElementById('launch-private-btn');
  774.  
  775. launch_public_btn.parentElement.insertBefore( ready_public_btn, launch_public_btn);
  776. launch_private_btn.parentElement.insertBefore( ready_private_btn, launch_private_btn);
  777.  
  778. var ready_public_box = ready_public_btn.getElementsByTagName('input')[0];
  779. var ready_private_box = ready_private_btn.getElementsByTagName('input')[0];
  780.  
  781. var ready_state = false;
  782. var last_clicked;
  783.  
  784. ready_public_btn.onchange = ready_private_btn.onchange = function(change){
  785.  
  786. // Find out what your new readystate is
  787. ready_state = change.target.checked;
  788.  
  789. // Update both buttons accordingly (one of them obviously is already right)
  790. ready_public_btn.getElementsByTagName('input')[0].checked = ready_state;
  791. ready_private_btn.getElementsByTagName('input')[0].checked = ready_state;
  792.  
  793. // Disable the buttons for a few seconds to prevent spamming
  794. console.log(ready_public_btn.style.cursor);
  795. ready_public_btn.style.cursor = 'wait';
  796. ready_private_btn.style.cursor = 'wait';
  797.  
  798. ready_public_box.style.cursor = 'wait';
  799. ready_private_box.style.cursor = 'wait';
  800.  
  801. ready_public_box.disabled = true;
  802. ready_private_box.disabled = true;
  803.  
  804. setTimeout(function(){
  805. ready_public_btn.style.cursor = '';
  806. ready_private_btn.style.cursor = '';
  807.  
  808. ready_public_box.style.cursor = '';
  809. ready_private_box.style.cursor = '';
  810.  
  811. ready_public_box.disabled = false;
  812. ready_private_box.disabled = false;
  813. },3000);
  814.  
  815. // Warn if the state is changed right after the delay runs out
  816. if (last_clicked > Date.now() - 6000) {
  817. let warning = tagpro.helpers.displayError('Please don\'t change your ready-state more often than needed. Players without the script receive a chat message every time you change it. Thank you :)');
  818. warning[0].onclick = ()=>warning.fadeOut(); // Click to hide
  819. warning[0].style.cursor = 'pointer';
  820. warning[0].title = 'Click to hide';
  821. }
  822. last_clicked = Date.now();
  823.  
  824. // Tell it to the world
  825. socket.emit('chat', ready_state ? "[GroPro:ready]" : "[GroPro:notready]");
  826.  
  827. };
  828. }
  829.  
  830. for (var event of ['port','member','removed','you','private'])
  831. socket.on(event, updateReadyStates);
  832.  
  833. // This function updates the ready tag beneath each player
  834.  
  835. function updateReadyStates(){
  836.  
  837. if (!show_ready_states) return;
  838.  
  839. for (var player_item of document.getElementsByClassName('player-item')) {
  840. var player = group.players[ $(player_item).data('model') && $(player_item).data('model').id ];
  841.  
  842. var location = player_item.getElementsByClassName('player-location')[0];
  843.  
  844. if (player.ready && player.location == "page") {
  845. location.innerText = 'Ready!';
  846. location.style.color = '#8BC34A';
  847. }
  848.  
  849. else {
  850. switch (player.location) {
  851. case "page":
  852. location.innerText = "In Here";
  853. break;
  854. case "joining":
  855. location.innerText = "Joining a Game";
  856. break;
  857. case "game":
  858. location.innerText = "In a Game";
  859. }
  860. location.style.color = '';
  861. }
  862. }
  863. }
  864. } );
  865. }
  866.  
  867.  
  868.  
  869. else if (tpul.playerLocation == 'find') { // In the process of joining a game
  870. }
  871.  
  872.  
  873.  
  874. else if (tpul.playerLocation == 'game') { // If we are in a game
  875.  
  876.  
  877.  
  878.  
  879. /*if ( hide_system_messages && tagpro.group.socket ) {
  880.  
  881. var org_handleChat = tagpro.group.socket.listeners('chat')[0];
  882.  
  883. tagpro.group.socket.listeners('chat')[0] = function(chat) {
  884.  
  885. // Throw away messages of the form [GroPro:xxx]yyy
  886. if ( ( match = chat.message.match(/^\[GroPro:(\w{1,11})\](.{0,100})$/) ) ) return;
  887.  
  888. else org_handleChat(chat);
  889. };
  890.  
  891. }*/
  892.  
  893.  
  894.  
  895.  
  896. }
  897.  
  898. else if (tpul.playerLocation == 'home') { // If we are on the homepage
  899. }
  900.  
  901.  
  902. else { // If we are on any other page of the server
  903. }