Greasy Fork is available in English.

Bubble.am+

Mod that adds useful things to the game

Stan na 20-02-2021. Zobacz najnowsza wersja.

// ==UserScript==
// @name         Bubble.am+
// @namespace    https://discord.gg/p56aQHNU9U
// @version      1.1
// @description  Mod that adds useful things to the game
// @author       DD7
// @require      https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.min.js
// @match        *://bubble.am/*
// @run-at       document-start
// @grant        none
// ==/UserScript==

const modName = 'plus';
if((location.host === 'bubble.am' && location.pathname === '/') || location.pathname.length > 10) {
    window.stop();
    document.documentElement.innerHTML = "";
    location.href = `http://bubble.am/${modName}${location.hash}`;
}

window.customColor = false;
window.transparentMines = false;
window.noGrid = false;
window.macro = false;

const getColorValue = getCookie("cellsColor");
if(getColorValue === null) setCookie("cellsColor", "rgba(31, 95, 255, 1)", 30);
window.cellsColor = getColorValue;

let splitInterval = null;
let splitSwitch = false;
const keys = {
    q: false,
    a: false,
    s: false,
    d: false
}

const styles = `
    body.dark-mode ::-webkit-scrollbar {
        width: 5px;
        height: 5px;
    }

    body.dark-mode ::-webkit-scrollbar-button {
        width: 0px;
        height: 0px;
    }

    body.dark-mode ::-webkit-scrollbar-thumb {
        background: #38a2ff;
        border: 0px none #ffffff;
        border-radius: 50px;
    }

    body.dark-mode ::-webkit-scrollbar-thumb:hover {
        background: #0082f4;
    }

    body.dark-mode ::-webkit-scrollbar-thumb:active {
        background: #005fb2;
    }

    body.dark-mode ::-webkit-scrollbar-track {
        background: #505050;
        border: 0px none #ffffff;
        border-radius: 50px;
    }
    
    body.dark-mode ::-webkit-scrollbar-track:hover {
        background: #505050;
    }

    body.dark-mode ::-webkit-scrollbar-track:active {
        background: #505050;
    }

    body.dark-mode ::-webkit-scrollbar-corner {
        background: transparent;
    }

    body.dark-mode {
        color: #EDEDED !important;
    }

    body.dark-mode .main-panel {
        color: #EDEDED !important;
        background: #111111;
    }

    body.dark-mode .form-control {
        color: #fff !important;
        background: #222222;
        border: none !important;
    }

    body.dark-mode #radio_mode .gm-s {
        background: #222222;
        border: 1px solid #555555;
    }

    body.dark-mode .bb-panel {
        background: #111111;
    }

    body.dark-mode .btn-primary {
        background-color: #2753CC;
        border: none;
    }

    body.dark-mode .btn-primary:hover {
        background-color: #1F42A2;
    }

    body.dark-mode .btn-success {
        background-color: #45CB27;
        border: none;
    }

    body.dark-mode .btn-success:hover {
        background-color: #369E1E;
    }

    body.dark-mode .btn-settings {
        background-color: #27CCC9;
        border: none;
        height: auto;
    }

    body.dark-mode .btn-settings:hover {
        background-color: #1FA29F;
    }

    body.dark-mode .btn-warning {
        background-color: #CCA027;
        border: none;
    }

    body.dark-mode .btn-warning:hover {
        background-color: #A27F1F;
    }

    body.dark-mode .btn-danger {
        background-color: #CC2727;
        border: none;
    }

    body.dark-mode .btn-danger:hover {
        background-color: #A21F1F;
    }

    body.dark-mode .friends-online {
        background: #111111;
    }

    body.dark-mode .bub-table-list {
        border: 1px solid #333333;
    }

    body.dark-mode .table-striped>tbody>tr:nth-child(odd) {
        background-color: #161616;
    }

    body.dark-mode .table-striped>tbody>tr:nth-child(even) {
        background-color: #111111 !important;
    }

    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 {
        border: none;
    }

    body.dark-mode .dropdown-menu {
        background: #111111 !important;
    }

    body.dark-mode .dropdown-menu>li>a {
        color: #EDEDED;
    }

    body.dark-mode .dropdown-menu>li>a:hover, body.dark-mode .dropdown-menu>li>a:focus {
        color: #EDEDED;
        background: #222222;
    }

    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 {
        background: #ae8800 !important;
    }

    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 {
        color: #EDEDED;
        background: #222222;
        border: 1px solid transparent;
    }

    body.dark-mode .nav>li>a:hover, body.dark-mode .nav>li>a:focus {
        color: #EDEDED;
        background: #222222;
        border: 1px solid transparent;
    }

    body.dark-mode .modal-content {
        background: #111111;
    }

    body.dark-mode .modal-header {
        border-bottom: 1px solid #555555;
    }

    body.dark-mode .panel-default {
        border: 1px solid #555555;
    }

    body.dark-mode .panel-default>.panel-heading {
        background: #111111;
        border: none;
    }

    body.dark-mode #tournament-modal .panel-body {
        background: #161616;
    }

    body.dark-mode .tright {
        color: #EDEDED;
    }

    body.dark-mode .modeinfo {
        color: #385DFF;
    }

    body.dark-mode #battle_chat {
        background: #111111;
        color: #EDEDED;
    }

    body.dark-mode .close {
        color: #EDEDED;
        opacity: 1;
    }

    body.dark-mode #connecting div {
        background: #111111 !important;
    }

    body.dark-mode #statsChartText, body.dark-mode #statsText {
        color: #EDEDED;
    }

    body.dark-mode #statsSubtext {
        color: #ccc;
    }

    body.dark-mode .user-notif div.info {
        background: #111111;
        border: none;
    }

    body.dark-mode .user-notif div.warning {
        background: #ae8800;
        border: none;
    }

    body.dark-mode .user-notif div:hover, body.dark-mode .user-notif div.odd {
        border-left: 1px solid #0083e8 !important;
    }

    body.dark-mode .exp-bar .progress-bar {
        background-color: #1e6db7;
    }

    body.dark-mode #tournament-modal .panel-heading {
        color: #DEDEDE !important;
    }

    body.dark-mode .nav-tabs>li {
        margin-bottom: 0;
    }

    body.dark-mode hr {
        border-top: 1px solid #555555;
    }
`

function getCookie(name) {
    let v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
    return v ? v[2] : null;
}

function setCookie(name, value, days) {
    const d = new Date;
    d.setTime(d.getTime() + 24*60*60*1000*days);
    document.cookie = name + "=" + value + ";path=/;expires=" + d.toGMTString();
}

function addStyle(styleString) {
    const style = document.createElement("style");
    style.textContent = styleString;
    document.head.append(style);
}

function getModConfig(cookie) {
    cookie = cookie || "mod";
    var config = $.cookie(cookie);
    if (typeof (config) != "undefined") {
        config = atob(config);
        return $.parseJSON(config);
    }
    return false;
}

function setModConfig(option, value, cookie, expires, path) {
    if (typeof (option) == "undefined" || typeof (value) == "undefined") {
        return false;
    }
    cookie = cookie || "mod";
    expires = expires || 356;
    path = path || '/';
    config = getModConfig(cookie);
    if (config) {
        config[option] = value;
    } else {
        config = {};
        config[option] = value;
    }
    config = JSON.stringify(config);
    config = btoa(config);
    $.cookie(cookie, config, {
        expires: expires,
        path: path
    });

    return true;
}

function restoreModConfig() {
    const modConfig = getModConfig();

    if(modConfig) {
        for(let prop in modConfig) {
            if(modConfig.hasOwnProperty(prop)) $("#mod_" + prop).prop("checked", modConfig[prop]).change();
        } 
    }
}

window.setCustomColor = function(a) {
    window.customColor = a;
    a === true ? $("#colorPanel").show() : $("#colorPanel").hide()
    setModConfig("CustomColor", a);
}

window.setTransparentMines = function(a) {
    window.transparentMines = a;
    setModConfig("TransparentMines", a);
}

window.setNoGrid = function(a) {
    window.noGrid = a;
    setModConfig("NoGrid", a);
}

window.setMacro = function(a) {
    window.macro = a;
    setModConfig("Macro", a);
}

window.setDarkMenu = function(a) {
    window.darkMenu = a;
    a === true ? $("body").addClass("dark-mode") : $("body").removeClass("dark-mode")
    setModConfig("DarkMenu", a);
}

function modifyCore(core) {
    core = core.replace(/(.*)(m\.color)(.*)/, `
        $&

        if(h.length > 0 && m.name === h[0].name && !m.f && cellsColor !== undefined && cellsColor !== null && window.customColor === true) {
            m.color = window.cellsColor;
        }
    `)

    core = core.replace(/(bb\s\?)(.*)/, `
        if(bb) {
            a.fillStyle = "#FFFFFF";
            a.strokeStyle = "#AAAAAA";
            if(this.f && window.transparentMines === true) a.globalAlpha = 0.2;
        } else {
            a.fillStyle = this.color;
            a.strokeStyle = this.color;
            if(this.f && window.transparentMines === true) a.globalAlpha = 0.2;
        }
    `);

    core = core.replace(/(.*)(var\sa\s=\sl\s\/\sg)(.+)(\n.*\n.*)/gm, `
        if(window.noGrid === false) {
            $&
        }
    `);

    return core;
}

function split(times) {
	for(let i = 0; i < times; i++) {
		setTimeout(function() {
			$("body").trigger($.Event("keydown", { keyCode: 32 }));
			$("body").trigger($.Event("keyup", { keyCode: 32 }));
		}, 50 * i);
	}
}

function goTo(x, y) {
	x = window.innerWidth / x; y = window.innerHeight / y;
	$("canvas").trigger($.Event("mousemove", {clientX: x, clientY: y}));
}

function keydown(e) {
    const chat = document.querySelector("#chat_textbox");
    if(chat === document.activeElement || !window.macro) return;

    const key = e.key;
    
    keys[key] = true;
    switch(key) {
        case "Shift":
            if(splitSwitch) break;

            splitSwitch = true;
            splitInterval = setInterval(() => {
                $("body").trigger($.Event("keydown", { keyCode: 32 }));
                $("body").trigger($.Event("keyup", { keyCode: 32 }));
            }, 4);
            break;
        
        case "1":
            split(1);
            break;

        case "2":
            split(2);
            break;

        case "3":
            split(3);
            break;

        case "4":
            split(4);
            break;

        case "5":
            split(5);
            break;

        case "q":
            goTo(3, -0);
            break;
        
        case "a":
            goTo(-0, 8);
            break;
            
        case "s":
            goTo(2, 0.6);
            break;

        case "d":
            goTo(0, 5);
            break;
    }

    switch(true) {
        case keys["a"] && keys["q"]:
            goTo(-0, -0);
            break;

        case keys["a"] && keys["s"]:
            goTo(-0, 0);
            break;

        case keys["q"] && keys["d"]:
            goTo(0, -0);
            break;

        case keys["s"] && keys["d"]:
            goTo(0, 0);
            break;
    }
}

function keyup(e) {
    const chat = document.querySelector("#chat_textbox");
    if(chat === document.activeElement || !window.macro) return;

    const key = e.key;

    keys[e.key] = false;
    switch(key) {
        case "Shift":
            clearInterval(splitInterval);
            splitSwitch = false;
            break;
    }
}

function initMacro() {
    document.addEventListener("keydown", keydown);
    document.addEventListener("keyup", keyup);
}

function initUI() {
    $("#formStd h2").html("Bubble.am+");
    $(".settings_checkboxes").append(`
        <label>
            <input id="mod_Macro" type="checkbox" onchange="setMacro($(this).is(':checked'));"> Makro
        </label>
        <label>
            <input id="mod_TransparentMines" type="checkbox" onchange="setTransparentMines($(this).is(':checked'));"> Przezroczyste miny
        </label>
        <label>
            <input id="mod_NoGrid" type="checkbox" onchange="setNoGrid($(this).is(':checked'));"> Bez siatki
        </label>
        <label>
            <input id="mod_CustomColor" type="checkbox" onchange="setCustomColor($(this).is(':checked'));"> Niestandardowy kolor kulki
        </label>
        <label>
            <input id="mod_DarkMenu" type="checkbox" onchange="setDarkMenu($(this).is(':checked'));"> Ciemna wersja menu
        </label>
    `);
}

function initStyles() {
    addStyle(styles);
    $("head").append("<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/nano.min.css'/>");
}

function initColorPicker() {
    $('.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>`);

    const pickr = Pickr.create({
        el: "#colorMod",
        theme: "nano",
        container: "body",
        swatches: null,
        default: cellsColor,
        components: {
            preview: true,
            opacity: false,
            hue: true,
    
            interaction: {
                hex: true,
                rgba: true,
                hsla: false,
                hsva: false,
                cmyk: false,
                input: true,
                clear: false,
                save: true
            }
        }
    });

    pickr.on("save", (color, instance) => {
        cellsColor = color.toRGBA().toString(3);
        setCookie("cellsColor", cellsColor);
    }).on("change", (color, instance) => {
        setCookie("cellsColor", cellsColor);
    });
}

function init() {
    initMacro();
    initUI();
    initStyles();
    initColorPicker();
}

const request = new XMLHttpRequest();
const url = "http://bubble.am";
request.open("get", url, true);
request.send();
request.onload = function(e) {
    const newCore = modifyCore(this.responseText);

    document.open();
    document.write(newCore);
    document.close();

    window.onload = function() {
        init();
        restoreModConfig();
    }
}

console.log("Created by DD7");