Agar Extras

Improves the functionality and aesthetic of agar.io

  1. // ==UserScript==
  2. // @name Agar Extras
  3. // @description Improves the functionality and aesthetic of agar.io
  4. // @include *agar.io/*
  5. // @grant none
  6. // @run-at document-start
  7. // @version 1.7
  8. // @author Tom Burris
  9. // @namespace https://greasyfork.org/en/users/46159
  10. // @icon http://bit.ly/2oT4wRk
  11. // @compatible chrome
  12. // ==/UserScript==
  13.  
  14. "use strict";
  15.  
  16. const byId = (id, prnt) => (prnt || document).getElementById(id);
  17. const byClass = (clss, prnt) => (prnt || document).getElementsByClassName(clss);
  18. const byTag = (tag, prnt) => (prnt || document).getElementsByTagName(tag);
  19. const hsl = hue => `hsl(${hue},100%,50%)`;
  20. const listen = (elm, evnt, cb) => elm.addEventListener(evnt, cb);
  21.  
  22. /* document-start */
  23. (() => {
  24. const WebSocketOld = WebSocket;
  25. window.WebSocket = function(url) {
  26. window.wsURL = byId("wsTextInput").value = url;
  27. /*.replace(/\?.*$/, "")*/
  28. return new WebSocketOld(window.wsURL);
  29. };
  30. })();
  31.  
  32. /* document-end */
  33. listen(document, "DOMContentLoaded", () => {
  34. let css = "";
  35.  
  36. const nick = byId("nick");
  37. const profilePanel = byClass("agario-profile-panel")[0];
  38. const dailyQuests = byId("dailyQuests");
  39. const potionsBtn = byId("potions");
  40. const timers = byClass("timer menu-timer");
  41. const shopPanel = byClass("agario-shop-panel")[0];
  42. const options = byId("options");
  43. const rightPanel = byId("rightPanel");
  44. const playBtn = byClass("btn-play")[0];
  45. const prevent = event => event.preventDefault();
  46. const spectateBtn = byClass("btn-spectate")[0];
  47. const loginBtn = byClass("btn-login-play")[0];
  48. const subscribeBox = byId("agarYoutube");
  49.  
  50. /* Fixes */
  51. css += "body {line-height: normal !important;}"; // blurry font.
  52. nick.type = "text"; // improper input.
  53.  
  54. /* Compact Left Panel */
  55. css += ".quest-timer {width: auto; margin-left: 20px;}";
  56. profilePanel.appendChild(dailyQuests);
  57. dailyQuests.appendChild(timers[0]);
  58. profilePanel.appendChild(potionsBtn);
  59. potionsBtn.appendChild(timers[1]);
  60. const shopStuff = shopPanel.childNodes;
  61. while (shopStuff.length) {
  62. profilePanel.appendChild(shopStuff[0]);
  63. }
  64. css += "#freeCoins, #dailyQuests, #potions {margin: 0 0 5px 0;}";
  65. css += "#dailyquests-panel, .agario-shop-panel, #giftButton {display: none !important;}";
  66.  
  67. /* Center Options */
  68. css += `#tags-container {display: none;} #options {margin-left: 25px;}`;
  69. for (let span of byTag("span", options)) {
  70. if (span.textContent == "Show Online Status") {
  71. span.textContent = "Show Online";
  72. }
  73. }
  74.  
  75. /* Add Acid Mode */
  76. let acidLabel = document.createElement("label");
  77. acidLabel.innerHTML = `<input type="checkbox" id="acidMode" style="margin-top: 1px"><span>Acid mode</span>`;
  78. options.appendChild(acidLabel);
  79. const acidCheckbox = byId("acidMode");
  80. listen(acidCheckbox, "click", () => window.core.setAcid(window.checkbox.checked));
  81.  
  82. /* FPS */
  83. let fpsBox = document.createElement("div");
  84. fpsBox.style = `
  85. position: absolute;
  86. top: 0px;
  87. left: 0px;
  88. color: white;
  89. background: black;
  90. `;
  91. document.body.appendChild(fpsBox);
  92. let frames = 0;
  93. setInterval(() => {
  94. fpsBox.textContent = "fps: " + frames;
  95. fpsBox.style.color = hsl(frames * 2);
  96. frames = 0;
  97. }, 1E3);
  98. const clearRectOld = CanvasRenderingContext2D.prototype.clearRect;
  99. CanvasRenderingContext2D.prototype.clearRect = function() {
  100. if (this.canvas === window.canvas) {
  101. frames++;
  102. }
  103. return clearRectOld.apply(this, arguments);
  104. };
  105.  
  106. /* Server Connection */
  107. let wsBox = document.createElement("div");
  108. wsBox.innerHTML = `<input type="text" id="wsTextInput" class="agario-panel agario-side-panel" spellcheck="false"></input>`;
  109. rightPanel.appendChild(wsBox);
  110. const wsTextInput = byId("wsTextInput");
  111. listen(wsTextInput, "focus", wsTextInput.select.bind(wsTextInput));
  112. listen(wsTextInput, "blur", () => wsTextInput.value = window.wsURL);
  113. listen(wsTextInput, "keypress", ({keyCode: code}) => {
  114. if (code == 13) {
  115. window.core.disconnect();
  116. window.core.connect(wsTextInput.value);
  117. playBtn.click();
  118. }
  119. });
  120. css += `
  121. #wsTextInput {
  122. text-overflow: ellipsis;
  123. padding: 6px;
  124. display: inline-block;
  125. width: 293px;
  126. height: 34px;
  127. }
  128. #wsTextInput:focus {
  129. outline: 0px !important;
  130. box-shadow: 0 0 3px 1px white;
  131. }
  132. ::selection {
  133. background: #0d0 !important;
  134. }
  135. `;
  136.  
  137. /* Mouse Controls */
  138. const speed = 50;
  139. const eject = () => {
  140. if (ejectDown) {
  141. window.core.eject();
  142. setTimeout(eject, speed);
  143. }
  144. };
  145. let ejectDown = false;
  146. window.canvas.addEventListener("mousedown", ({which}) => {
  147. if (which === 1) window.core.split();
  148. else if (which === 3) eject(ejectDown = true);
  149. });
  150. listen(window, "mouseup", ({which}) => which === 3 && (ejectDown = false));
  151. window.canvas.addEventListener("contextmenu", prevent);
  152. window.canvas.addEventListener("dragstart", prevent);
  153.  
  154. /* Freeze */
  155. listen(window, "keydown", ({key}) => {
  156. if (key === "p") window.canvas.dispatchEvent(new MouseEvent("mousemove", {
  157. clientX: window.innerWidth / 2,
  158. clientY: window.innerHeight / 2
  159. }));
  160. });
  161.  
  162. /* Arrow Keys */
  163. const keychange = ({keyCode: code, type}) => {
  164. const dir = code - 37;
  165. if (dir >= 0 && dir < 4 && (!keysDown[dir] || type == "keyup")) {
  166. keysDown[dir] = type == "keydown";
  167. update();
  168. }
  169. };
  170. const update = () => {
  171. let pos = [window.innerWidth / 2, window.innerHeight / 2];
  172. for (let n = 4; n--;) {
  173. if (keysDown[n]) {
  174. const min = Math.min(window.innerWidth, window.innerHeight);
  175. pos[n % 2] += [-1, 1][n / 2 | 0] * min / 2;
  176. }
  177. }
  178. window.canvas.dispatchEvent(new MouseEvent("mousemove", {
  179. clientX: pos[0],
  180. clientY: pos[1]
  181. }));
  182. };
  183. const keysDown = [];
  184. listen(document, "keydown", keychange);
  185. listen(document, "keyup", keychange);
  186.  
  187. /* Music Player */
  188. const src = "//www.youtube.com/embed/TBGdEeYPYgg" + "?controls=0;";
  189. const player = document.createElement("div");
  190. player.className = "agario-panel agario-side-panel";
  191. player.style = "padding: 0px; width: 293px; height: 168px; margin-top: 5px;";
  192. player.innerHTML = `<iframe id="YTVideo" src="${src}" style="border: 0px; width: 100%; height: 100%;"></iframe>`;
  193. rightPanel.appendChild(player);
  194.  
  195. /* Ubuntu Font */
  196. css += "@import url('https://fonts.googleapis.com/css?family=Ubuntu');";
  197. css += "body {font-family: 'Ubuntu', sans-serif !important;}";
  198. css += "#statsSubtext {white-space: nowrap;}";
  199.  
  200. /* Vertically center main panel */
  201. css += `
  202. #helloContainer {
  203. position: relative;
  204. top: 50% !important;
  205. transform: perspective(1px) translate(-50%, -50%) !important;
  206. display: inline-block !important;
  207. width: auto !important;
  208. }
  209. #leftPanel {
  210. margin: 0px;
  211. width: 222px;
  212. }
  213. `;
  214.  
  215. /* Always display settings and intructions, also move the login button */
  216. css += `
  217. #settings {
  218. display: block !important;
  219. }
  220. .btn-settings {
  221. display: none;
  222. }
  223. .btn-play-guest {
  224. width: 100%;
  225. margin: 0px !important;
  226. }
  227. .btn-play {
  228. width: 100% !important;
  229. margin: 0px !important;
  230. }
  231. .btn-login-play {
  232. width: 110px !important;
  233. float: right;
  234. }
  235. #instructions,
  236. #options,
  237. .text-muted,
  238. #mainPanel {
  239. cursor: default !important;
  240. }
  241. input,
  242. select {
  243. cursor: pointer !important;
  244. }
  245. `;
  246. spectateBtn.parentNode.appendChild(loginBtn);
  247.  
  248. /* Darken Stuff */
  249. css += `
  250. select,
  251. .agario-panel,
  252. .shop-blocker,
  253. #blocker,
  254. input[type=text],
  255. footer,
  256. .progress,
  257. .party-token,
  258. .agario-profile-picture {
  259. background: black !important;
  260. color: white !important;
  261. border: 0px !important;
  262. border-radius: 0px !important;
  263. outline: 1px solid white !important;
  264. }
  265. span {
  266. color: white !important;
  267. }
  268. .party-icon-back {
  269. background: black !important;
  270. }
  271. .btn {
  272. border-radius: 0px !important;
  273. }
  274. `;
  275.  
  276. /* Hide Static Ads */
  277. css += `
  278. .agario-promo-container,
  279. #advertisement,
  280. .diep-cross,
  281. #promo-badge-container,
  282. #agario-web-incentive,
  283. #mcbanners-container,
  284. #adsBottom {
  285. display: none !important;
  286. }
  287. `;
  288. subscribeBox.parentElement.style.display = "none";
  289.  
  290. /* Append CSS To DOM */
  291. const style = document.createElement("style");
  292. style.innerHTML = css;
  293. document.head.appendChild(style);
  294. });
  295.  
  296. /* document-idle */
  297. listen(window, "load", () => {
  298. // The page javascript changes the textContent (I think).
  299. byClass("btn-login-play")[0].textContent = "Login";
  300.  
  301. /* Remove Video Ads */
  302. const good = () => {
  303. window.MC.notifyFullscreenAdFinished();
  304. //window.onDone();
  305. };
  306. window.initAdsController = good;
  307. window.requestAds = good;
  308. window.onAdLoaded = good;
  309. //window.adSlots = {};
  310. //window.googleAdsModule = {};
  311. //window.mc.Events.ads = {};
  312. //window.mc.services.ads = {};
  313. window.openOfferwall = good;
  314. window.openVideoAd = good;
  315. window.refreshAd = good;
  316. //window.supersonicAds = {};
  317. //window.startAd = function() {}; // banner.js line 1
  318. //console.log("%cDone!", "color:black;font-weight:bold;font-size:20px;");
  319. });