Bubble.am+

Mod that adds useful things to the game

目前为 2021-05-25 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Bubble.am+
  3. // @namespace https://discord.gg/p56aQHNU9U
  4. // @version 1.2
  5. // @description Mod that adds useful things to the game
  6. // @author DD7
  7. // @require https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.min.js
  8. // @match *://bubble.am/*
  9. // @run-at document-start
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. const modName = 'plus';
  14. if((location.host === 'bubble.am' && location.pathname === '/') || location.pathname.length > 10) {
  15. window.stop();
  16. document.documentElement.innerHTML = "";
  17. location.href = `http://bubble.am/${modName}${location.hash}`;
  18. }
  19.  
  20. window.customColor = false;
  21. window.transparentMines = false;
  22. window.noGrid = false;
  23. window.macro = false;
  24.  
  25. const getColorValue = getCookie("cellsColor");
  26. if(getColorValue === null) setCookie("cellsColor", "rgba(31, 95, 255, 1)", 30);
  27. window.cellsColor = getColorValue;
  28.  
  29. let splitInterval = null;
  30. let splitSwitch = false;
  31. const keys = {
  32. q: false,
  33. a: false,
  34. s: false,
  35. d: false
  36. }
  37.  
  38. const styles = `
  39. body.dark-mode ::-webkit-scrollbar {
  40. width: 5px;
  41. height: 5px;
  42. }
  43.  
  44. body.dark-mode ::-webkit-scrollbar-button {
  45. width: 0px;
  46. height: 0px;
  47. }
  48.  
  49. body.dark-mode ::-webkit-scrollbar-thumb {
  50. background: #38a2ff;
  51. border: 0px none #ffffff;
  52. border-radius: 50px;
  53. }
  54.  
  55. body.dark-mode ::-webkit-scrollbar-thumb:hover {
  56. background: #0082f4;
  57. }
  58.  
  59. body.dark-mode ::-webkit-scrollbar-thumb:active {
  60. background: #005fb2;
  61. }
  62.  
  63. body.dark-mode ::-webkit-scrollbar-track {
  64. background: #505050;
  65. border: 0px none #ffffff;
  66. border-radius: 50px;
  67. }
  68. body.dark-mode ::-webkit-scrollbar-track:hover {
  69. background: #505050;
  70. }
  71.  
  72. body.dark-mode ::-webkit-scrollbar-track:active {
  73. background: #505050;
  74. }
  75.  
  76. body.dark-mode ::-webkit-scrollbar-corner {
  77. background: transparent;
  78. }
  79.  
  80. body.dark-mode {
  81. color: #EDEDED !important;
  82. }
  83.  
  84. body.dark-mode .main-panel {
  85. color: #EDEDED !important;
  86. background: #111111;
  87. }
  88.  
  89. body.dark-mode .form-control {
  90. color: #fff !important;
  91. background: #222222;
  92. border: none !important;
  93. }
  94.  
  95. body.dark-mode #radio_mode .gm-s {
  96. background: #222222;
  97. border: 1px solid #555555;
  98. }
  99.  
  100. body.dark-mode .bb-panel {
  101. background: #111111;
  102. }
  103.  
  104. body.dark-mode .btn-primary {
  105. background-color: #2753CC;
  106. border: none;
  107. }
  108.  
  109. body.dark-mode .btn-primary:hover {
  110. background-color: #1F42A2;
  111. }
  112.  
  113. body.dark-mode .btn-success {
  114. background-color: #45CB27;
  115. border: none;
  116. }
  117.  
  118. body.dark-mode .btn-success:hover {
  119. background-color: #369E1E;
  120. }
  121.  
  122. body.dark-mode .btn-settings {
  123. background-color: #27CCC9;
  124. border: none;
  125. height: auto;
  126. }
  127.  
  128. body.dark-mode .btn-settings:hover {
  129. background-color: #1FA29F;
  130. }
  131.  
  132. body.dark-mode .btn-warning {
  133. background-color: #CCA027;
  134. border: none;
  135. }
  136.  
  137. body.dark-mode .btn-warning:hover {
  138. background-color: #A27F1F;
  139. }
  140.  
  141. body.dark-mode .btn-danger {
  142. background-color: #CC2727;
  143. border: none;
  144. }
  145.  
  146. body.dark-mode .btn-danger:hover {
  147. background-color: #A21F1F;
  148. }
  149.  
  150. body.dark-mode .friends-online {
  151. background: #111111;
  152. }
  153.  
  154. body.dark-mode .bub-table-list {
  155. border: 1px solid #333333;
  156. }
  157.  
  158. body.dark-mode .table-striped>tbody>tr:nth-child(odd) {
  159. background-color: #161616;
  160. }
  161.  
  162. body.dark-mode .table-striped>tbody>tr:nth-child(even) {
  163. background-color: #111111 !important;
  164. }
  165.  
  166. body.dark-mode .table>thead>tr>th, body.dark-mode .table>tbody>tr>th, body.dark-mode .table>tfoot>tr>th, body.dark-mode .table>thead>tr>td, body.dark-mode .table>tbody>tr>td, body.dark-mode .table>tfoot>tr>td {
  167. border: none;
  168. }
  169.  
  170. body.dark-mode .dropdown-menu {
  171. background: #111111 !important;
  172. }
  173.  
  174. body.dark-mode .dropdown-menu>li>a {
  175. color: #EDEDED;
  176. }
  177.  
  178. body.dark-mode .dropdown-menu>li>a:hover, body.dark-mode .dropdown-menu>li>a:focus {
  179. color: #EDEDED;
  180. background: #222222;
  181. }
  182.  
  183. body.dark-mode .table>thead>tr>td.warning,body.dark-mode .table>tbody>tr>td.warning,body.dark-mode .table>tfoot>tr>td.warning,body.dark-mode .table>thead>tr>th.warning,body.dark-mode .table>tbody>tr>th.warning,body.dark-mode .table>tfoot>tr>th.warning, body.dark-mode .table>thead>tr.warning>td, body.dark-mode .table>tbody>tr.warning>td, body.dark-mode .table>tfoot>tr.warning>td,body.dark-mode .table>thead>tr.warning>th,body.dark-mode .table>tbody>tr.warning>th,body.dark-mode .table>tfoot>tr.warning>th {
  184. background: #ae8800 !important;
  185. }
  186.  
  187. body.dark-mode .nav-tabs>li.active>a, body.dark-mode .nav-tabs>li.active>a:hover, body.dark-mode .nav-tabs>li.active>a:focus {
  188. color: #EDEDED;
  189. background: #222222;
  190. border: 1px solid transparent;
  191. }
  192.  
  193. body.dark-mode .nav>li>a:hover, body.dark-mode .nav>li>a:focus {
  194. color: #EDEDED;
  195. background: #222222;
  196. border: 1px solid transparent;
  197. }
  198.  
  199. body.dark-mode .modal-content {
  200. background: #111111;
  201. }
  202.  
  203. body.dark-mode .modal-header {
  204. border-bottom: 1px solid #555555;
  205. }
  206.  
  207. body.dark-mode .panel-default {
  208. border: 1px solid #555555;
  209. }
  210.  
  211. body.dark-mode .panel-default>.panel-heading {
  212. background: #111111;
  213. border: none;
  214. }
  215.  
  216. body.dark-mode #tournament-modal .panel-body {
  217. background: #161616;
  218. }
  219.  
  220. body.dark-mode .tright {
  221. color: #EDEDED;
  222. }
  223.  
  224. body.dark-mode .modeinfo {
  225. color: #385DFF;
  226. }
  227.  
  228. body.dark-mode #battle_chat {
  229. background: #111111;
  230. color: #EDEDED;
  231. }
  232.  
  233. body.dark-mode .close {
  234. color: #EDEDED;
  235. opacity: 1;
  236. }
  237.  
  238. body.dark-mode #connecting div {
  239. background: #111111 !important;
  240. }
  241.  
  242. body.dark-mode #statsChartText, body.dark-mode #statsText {
  243. color: #EDEDED;
  244. }
  245.  
  246. body.dark-mode #statsSubtext {
  247. color: #ccc;
  248. }
  249.  
  250. body.dark-mode .user-notif div.info {
  251. background: #111111;
  252. border: none;
  253. }
  254.  
  255. body.dark-mode .user-notif div.warning {
  256. background: #ae8800;
  257. border: none;
  258. }
  259.  
  260. body.dark-mode .user-notif div:hover, body.dark-mode .user-notif div.odd {
  261. border-left: 1px solid #0083e8 !important;
  262. }
  263.  
  264. body.dark-mode .exp-bar .progress-bar {
  265. background-color: #1e6db7;
  266. }
  267.  
  268. body.dark-mode #tournament-modal .panel-heading {
  269. color: #DEDEDE !important;
  270. }
  271.  
  272. body.dark-mode .nav-tabs>li {
  273. margin-bottom: 0;
  274. }
  275.  
  276. body.dark-mode hr {
  277. border-top: 1px solid #555555;
  278. }
  279. `
  280.  
  281. function getCookie(name) {
  282. let v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
  283. return v ? v[2] : null;
  284. }
  285.  
  286. function setCookie(name, value, days) {
  287. const d = new Date;
  288. d.setTime(d.getTime() + 24*60*60*1000*days);
  289. document.cookie = name + "=" + value + ";path=/;expires=" + d.toGMTString();
  290. }
  291.  
  292. function addStyle(styleString) {
  293. const style = document.createElement("style");
  294. style.textContent = styleString;
  295. document.head.append(style);
  296. }
  297.  
  298. function getModConfig(cookie) {
  299. cookie = cookie || "mod";
  300. var config = $.cookie(cookie);
  301. if (typeof (config) != "undefined") {
  302. config = atob(config);
  303. return $.parseJSON(config);
  304. }
  305. return false;
  306. }
  307.  
  308. function setModConfig(option, value, cookie, expires, path) {
  309. if(typeof (option) == "undefined" || typeof (value) == "undefined") {
  310. return false;
  311. }
  312.  
  313. cookie = cookie || "mod";
  314. expires = expires || 356;
  315. path = path || '/';
  316. config = getModConfig(cookie);
  317.  
  318. if(config) {
  319. config[option] = value;
  320. } else {
  321. config = {};
  322. config[option] = value;
  323. }
  324. config = JSON.stringify(config);
  325. config = btoa(config);
  326. $.cookie(cookie, config, {
  327. expires: expires,
  328. path: path
  329. });
  330.  
  331. return true;
  332. }
  333.  
  334. function restoreModConfig() {
  335. const modConfig = getModConfig();
  336.  
  337. if(modConfig) {
  338. for(let prop in modConfig) {
  339. if(modConfig.hasOwnProperty(prop)) $("#mod_" + prop).prop("checked", modConfig[prop]).change();
  340. }
  341. }
  342. }
  343.  
  344. window.setCustomColor = function(a) {
  345. window.customColor = a;
  346. a === true ? $("#colorPanel").show() : $("#colorPanel").hide()
  347. setModConfig("CustomColor", a);
  348. }
  349.  
  350. window.setTransparentMines = function(a) {
  351. window.transparentMines = a;
  352. setModConfig("TransparentMines", a);
  353. }
  354.  
  355. window.setNoGrid = function(a) {
  356. window.noGrid = a;
  357. setModConfig("NoGrid", a);
  358. }
  359.  
  360. window.setMacro = function(a) {
  361. window.macro = a;
  362. setModConfig("Macro", a);
  363. }
  364.  
  365. window.setDarkMenu = function(a) {
  366. window.darkMenu = a;
  367. a === true ? $("body").addClass("dark-mode") : $("body").removeClass("dark-mode")
  368. setModConfig("DarkMenu", a);
  369. }
  370.  
  371. function modifyCore(core) {
  372. core = core.replace(/(.*)(m\.color)(.*)/, `
  373. $&
  374.  
  375. if(h.length > 0 && m.name === h[0].name && !m.f && cellsColor !== undefined && cellsColor !== null && window.customColor === true) {
  376. m.color = window.cellsColor;
  377. }
  378. `)
  379.  
  380. core = core.replace(/(bb\s\?)(.*)/, `
  381. if(bb) {
  382. a.fillStyle = "#FFFFFF";
  383. a.strokeStyle = "#AAAAAA";
  384. if(this.f && window.transparentMines === true) a.globalAlpha = 0.2;
  385. } else {
  386. a.fillStyle = this.color;
  387. a.strokeStyle = this.color;
  388. if(this.f && window.transparentMines === true) a.globalAlpha = 0.2;
  389. }
  390. `);
  391.  
  392. core = core.replace(/(.*)(var\sa\s=\sl\s\/\sg)(.+)(\n.*\n.*)/gm, `
  393. if(window.noGrid === false) {
  394. $&
  395. }
  396. `);
  397.  
  398. return core;
  399. }
  400.  
  401. function split(times) {
  402. for(let i = 0; i < times; i++) {
  403. setTimeout(function() {
  404. $("body").trigger($.Event("keydown", { keyCode: 32 }));
  405. $("body").trigger($.Event("keyup", { keyCode: 32 }));
  406. }, 50 * i);
  407. }
  408. }
  409.  
  410. function goTo(x, y) {
  411. x = window.innerWidth / x; y = window.innerHeight / y;
  412. $("canvas").trigger($.Event("mousemove", {clientX: x, clientY: y}));
  413. }
  414.  
  415. function keydown(e) {
  416. const chat = document.querySelector("#chat_textbox");
  417. if(chat === document.activeElement || !window.macro) return;
  418.  
  419. const key = e.key.toString().toLowerCase();
  420.  
  421. if(keys.hasOwnProperty(key)) {
  422. keys[key] = true;
  423. }
  424. switch(key) {
  425. case "shift":
  426. if(splitSwitch) break;
  427.  
  428. splitSwitch = true;
  429. splitInterval = setInterval(() => {
  430. $("body").trigger($.Event("keydown", { keyCode: 32 }));
  431. $("body").trigger($.Event("keyup", { keyCode: 32 }));
  432. }, 4);
  433. break;
  434. case "1":
  435. split(1);
  436. break;
  437.  
  438. case "2":
  439. split(2);
  440. break;
  441.  
  442. case "3":
  443. split(3);
  444. break;
  445.  
  446. case "4":
  447. split(4);
  448. break;
  449.  
  450. case "5":
  451. split(5);
  452. break;
  453.  
  454. case "q":
  455. goTo(3, -0);
  456. break;
  457. case "a":
  458. goTo(-0, 8);
  459. break;
  460. case "s":
  461. goTo(2, 0.6);
  462. break;
  463.  
  464. case "d":
  465. goTo(0, 5);
  466. break;
  467. }
  468.  
  469. switch(true) {
  470. case keys["a"] && keys["q"]:
  471. goTo(-0, -0);
  472. break;
  473.  
  474. case keys["a"] && keys["s"]:
  475. goTo(-0, 0);
  476. break;
  477.  
  478. case keys["q"] && keys["d"]:
  479. goTo(0, -0);
  480. break;
  481.  
  482. case keys["s"] && keys["d"]:
  483. goTo(0, 0);
  484. break;
  485. }
  486. }
  487.  
  488. function keyup(e) {
  489. const chat = document.querySelector("#chat_textbox");
  490. if(chat === document.activeElement || !window.macro) return;
  491.  
  492. const key = e.key.toString().toLowerCase();
  493.  
  494. if(keys.hasOwnProperty(key)) {
  495. keys[key] = false;
  496. }
  497.  
  498. switch(key) {
  499. case "shift":
  500. clearInterval(splitInterval);
  501. splitSwitch = false;
  502. break;
  503. }
  504. }
  505.  
  506. function initMacro() {
  507. document.addEventListener("keydown", keydown);
  508. document.addEventListener("keyup", keyup);
  509. }
  510.  
  511. function initUI() {
  512. $("#formStd h2").html("Bubble.am+");
  513. $(".settings_checkboxes").append(`
  514. <label>
  515. <input id="mod_Macro" type="checkbox" onchange="setMacro($(this).is(':checked'));"> Makro
  516. </label>
  517. <label>
  518. <input id="mod_TransparentMines" type="checkbox" onchange="setTransparentMines($(this).is(':checked'));"> Przezroczyste miny
  519. </label>
  520. <label>
  521. <input id="mod_NoGrid" type="checkbox" onchange="setNoGrid($(this).is(':checked'));"> Bez siatki
  522. </label>
  523. <label>
  524. <input id="mod_CustomColor" type="checkbox" onchange="setCustomColor($(this).is(':checked'));"> Niestandardowy kolor kulki
  525. </label>
  526. <label>
  527. <input id="mod_DarkMenu" type="checkbox" onchange="setDarkMenu($(this).is(':checked'));"> Ciemna wersja menu
  528. </label>
  529. `);
  530. }
  531.  
  532. function initStyles() {
  533. addStyle(styles);
  534. $("head").append("<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/nano.min.css'/>");
  535. }
  536.  
  537. function initColorPicker() {
  538. $('.settings_checkboxes').after(`<div id="colorPanel" style="display: none;"><p style="float: left; line-height: 2.6rem; margin-right: 0.8rem;">Wybierz swój kolor: </p> <div id="colorMod"></div></div>`);
  539.  
  540. const pickr = Pickr.create({
  541. el: "#colorMod",
  542. theme: "nano",
  543. container: "body",
  544. swatches: null,
  545. default: cellsColor,
  546. components: {
  547. preview: true,
  548. opacity: false,
  549. hue: true,
  550. interaction: {
  551. hex: true,
  552. rgba: true,
  553. hsla: false,
  554. hsva: false,
  555. cmyk: false,
  556. input: true,
  557. clear: false,
  558. save: true
  559. }
  560. }
  561. });
  562.  
  563. pickr.on("save", (color, instance) => {
  564. cellsColor = color.toRGBA().toString(3);
  565. setCookie("cellsColor", cellsColor);
  566. }).on("change", (color, instance) => {
  567. setCookie("cellsColor", cellsColor);
  568. });
  569. }
  570.  
  571. function init() {
  572. initMacro();
  573. initUI();
  574. initStyles();
  575. initColorPicker();
  576. }
  577.  
  578. const request = new XMLHttpRequest();
  579. const url = "http://bubble.am";
  580. request.open("get", url, true);
  581. request.send();
  582. request.onload = function(e) {
  583. const newCore = modifyCore(this.responseText);
  584.  
  585. document.open();
  586. document.write(newCore);
  587. document.close();
  588.  
  589. window.onload = function() {
  590. init();
  591. restoreModConfig();
  592. }
  593. }
  594.  
  595. console.log("Created by DD7");