Survev.io Counters | Anniversary Edition

Give survev.io better experience

// ==UserScript==
// @name         Survev.io Counters | Anniversary Edition
// @namespace    http://tampermonkey.net/
// @license      MIT
// @version      5.0.0
// @description  Give survev.io better experience
// @author       chess5321, .junako, asultra, samerkizi and wzld are in Discord
// @match        https://survev.io/
// @icon         https://cdn.discordapp.com/icons/947128006030282792/c80363d8d6dea22ef392c4d325e0c9f4.png?size=64
// @grant        GM_addStyle
// ==/UserScript==

/* #FPS Booster (if u want to use this, u have to delete #Uncap FPS!)
(function() {
    'use strict';
    let MAX = 120; //frame rate you desire
    requestAnimationFrame = e => setTimeout(e, 1e3 / MAX);
})();*/
/*#Uncap FPS*/
(function() {
    'use strict';

    function uncapFPS() {
        window.requestAnimationFrame = function(callback) {
            return setTimeout(callback, 1);
        };
    }
    uncapFPS();
})();
/*CSS*/
(function() {
    'use strict';
    GM_addStyle(`
        #background {
            filter: brightness(1);
        }
        #start-overlay {
            background-color: #0000;
        }
        #TOS,
        #start-bottom-middle,
        #ui-game {
            opacity: 0.5;
        }
        body > div:nth-child(6),
        body > div:nth-child(7) {
            opacity: 0.75;
        }
        .menu-block {
            transform: scale(1) !important;
        }

        #modal-customize {
            backdrop-filter: brightness(0.65) !important;
        }

        .btns-double-row {
            display: block !important;
        }

        .ui-keybind-container>.btn-keybind-desc-selected {
            animation: pulseKeybind 1.25s linear infinite !important;
        }

        @keyframes pulseKeybind {
            0% {
                background-color: #202124;
            }

            50% {
                background-color: #35363a;
            }

            100% {
                background-color: #202124;
            }
        }

        input[type="checkbox"],
        input[type="range_"],
        input[type="textbox"],
        .ui-emote-quarter .ui-emote-hl,
        #customize-emote-autos .ui-emote-hl,
        .ui-emote-middle,
        .ui-team-ping-middle {
            filter: grayscale(1) !important;
        }

        input[type=text]:focus {
            border: none !important;
        }

        /*untouchable*/
        /*
        #ui-weapon-id-1, #ui-weapon-id-2, #ui-weapon-id-3, #ui-weapon-id-4, .ui-zoom-inactive, .ui-zoom-active,#ui-settings-container-desktop>.ui-settings-button, #ui-equipped-ammo, #ui-bullet-counter #ui-current-clip, #ui-interaction, #ui-lower-center, #ui-interaction-press {
            pointer-events: none !important;
        }
        */

        /*setting*/
        #start-bottom-right {
            transition: 0.3s !important;
            opacity: 0 !important;
        }

        #btn-game-tabs>.btn-game-container>.btn-game-menu-selected,
        .btn-hollow-selected,
        .ui-outline-hover:hover,
        #color-picker-hex {
            border-color: #202124 !important;
        }

        .customize-list-item-selected {
            border-color: #FFD700 !important;
        }

        .btn-game-container>.btn-game-menu {
            border-color: #35363a !important;
        }

        .btn-hollow {
            border-color: #35363a;
        }

        #start-bottom-right:hover {
            opacity: 1 !important;
        }

        /*text*/
        .news-header,
        .news-paragraph>.highlight,
        .ui-stats-header-title,
        .ui-stats-info-player-name {
            color: #FFD700 !important;
        }

        /*inside ig*/
        .modal-header,
        .modal-footer,
        .modal-content-right {
            background-color: rgba(26, 27, 29, 0.65) !important;
        }

        .slider,
        .slider::-webkit-slider-thumb {
            background-color: rgb(26, 27, 29) !important;
        }

        .modal-body,
        .modal-customize-cat-selected {
            background-color: rgba(53, 54, 58, 0.65) !important;
        }

        .modal-content-shadow {
            box-shadow: none;
        }

        .menu-option:focus {
            box-shadow: 0 0 1px 1px #FFD700;
        }

        .modal-customize-cat-connect {
            background: #FFD700 !important;
        }

        /*color*/
        .btn-green,
        #ui-modal-keybind-footer>.btn-game-menu,
        .btn-start-mute,
        .btn-team-option,
        .ui-keybind-container>.btn-keybind-desc,
        #btn-customize,
        #btn-team-mobile-link-leave,
        #btn-team-leave,
        #ui-modal-keybind-footer>.btn-game-menu:last-child,
        .btn-settings,
        .btn-keybind,
        #btn-start-fullscreen,
        #btn-game-fullscreen,
        .audio-on-icon,
        #btn-game-quit,
        #btn-game-resume,
        #ui-spectate-buttons>.menu-option,
        #ui-game-tab-keybinds>.btn-keybind-restore {
            background-color: #35363a !important;
            border-bottom: 2px solid #202124 !important;
            box-shadow: inset 0 -2px #202124 !important;
        }
        .player-name-input,
        #team-link-input,
        .player-name-input,
        .name-self,
        .name-self:hover,
        .team-menu-member>.menu-option,
        #keybind-code-input,
        #color-picker-hex {
            background-color: #35363a !important;
            color: #ffd700 !important;
        }

        /*
        .btn-settings {
            background-image: url(../img/gui/cog.svg) !important;
        }
        .btn-keybind {
            background-image: url(../img/gui/keyboard.svg) !important;
        }
        #btn-start-fullscreen, #btn-game-fullscreen {
            background-image: url(../img/gui/minimize.svg) !important;
        }
        .audio-on-icon {
            background-image: url(../img/gui/audio-on.svg) !important;
        }
        .audio-off-icon {
            background-image: url(../img/gui/audio-off.svg) !important;
        }
        #btn-game-quit {
            background-image: url(../img/gui/quit.svg) !important;
        }
        #btn-game-resume {
            background-image: url(../img/gui/resume.svg) !important;
        }
        */
        /*others*/
        #ad-block-left,
        #social-share-block {
            pointer-events: none !important;
            opacity: 0 !important;
        }

        #btn-help,
        #start-help,
        .icon-submit-name-change,
        #start-bottom-right > a,
        #start-bottom-right > a > div {
            display: none !important;
        }

        #start-row-top {
            position_: relative !important;
            left_: 331px !important;
        }

        #team-menu,
        #team-mobile-link {
            position: relative !important;
            right: 165px !important;
        }

        #btn-team-mobile-link-leave {
            position: relative !important;
            left: 206px !important;
            bottom: 0px !important;
        }

        #news-block, #start-menu {
            opacity: 0 !important;
            transition: 0.3s !important;
        }

        #news-block:hover, #start-menu:hover {
            opacity: 1 !important;
        }
    `);
})();
/*BGeffect
(function() {
	// bg effect
	document.addEventListener("mousemove", (e => {
		const n = e.clientX / window.innerWidth * 100,
			t = e.clientY / window.innerHeight * 100;
		document.getElementById("background").style.transform = `translate(-${n/10}%, -${t/10}%)`
	}));
	GM_addStyle(`
        #background {
            width: 111.090775988% !important;
            height: 111.090775988% !important;
        }
    `);
})();
*/
/*RandomBG*/
(function() {
    var preImages = [
        'https://i.imgur.com/N9mhKPf.png',
        'https://i.imgur.com/ZwWc1V6.png',
        'https://i.imgur.com/ECmba9f.png',
        'https://i.imgur.com/aFpnqJh.png',
        'https://i.imgur.com/83OJWoB.png',
        'https://i.imgur.com/9d2Ovts.png',
        'https://i.imgur.com/RhtMT8x.png',
        'https://i.imgur.com/AkqE1MW.png',
        'https://i.imgur.com/1QYyOVm.png',
        'https://i.imgur.com/7fHEEwN.png',
        'https://i.imgur.com/GOTXovX.png',
        'https://i.imgur.com/MK7KzfH.png',
        'https://i.imgur.com/cVXsZuK.png',
        'https://i.imgur.com/nI4potb.png'
    ];

    // Preload images function using Promise to ensure all images are loaded
    function preloadImages(images) {
        return Promise.all(images.map(url => {
            return new Promise((resolve, reject) => {
                const img = new Image();
                img.onload = resolve;
                img.onerror = reject;
                img.src = url;
            });
        }));
    }

    preloadImages(preImages)
        .then(() => {
            console.log("All images preloaded!");
        })
        .catch((error) => {
            console.error("Error loading images:", error);
        });

    const DEFAULT_INDEX = 0,
        UPLOAD_INDEX = 15,
        URL_INDEX = 16;
    const STORAGE_KEY = "customBackground";
    const RANDOM_BACKGROUND_KEY = "useRandomBackground";
    const backgroundElement = document.getElementById("background");

    function setRandomBackground() {
        const randomImage = preImages[Math.floor(Math.random() * preImages.length)];
        backgroundElement.style.backgroundImage = `url(${randomImage})`;
    }

    const setBackground = (index) => {
        let url;
        if (index === DEFAULT_INDEX) {
            setRandomBackground();
            localStorage.setItem(RANDOM_BACKGROUND_KEY, "true"); // Mark to use random background on future page loads
            localStorage.removeItem(STORAGE_KEY); // Remove the custom background if set
        } else if (index > 0 && index <= preImages.length) {
            url = preImages[index - 1];
            backgroundElement.style.backgroundImage = `url(${url})`;
            localStorage.setItem(STORAGE_KEY, url);
            localStorage.removeItem(RANDOM_BACKGROUND_KEY); // Remove the random background marker
        } else if (index === UPLOAD_INDEX) {
            const fileInput = document.createElement('input');
            fileInput.type = 'file';
            fileInput.accept = 'image/*';
            fileInput.onchange = (e) => {
                const file = e.target.files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = (ev) => {
                        url = ev.target.result;
                        backgroundElement.style.backgroundImage = `url(${url})`;
                        localStorage.setItem(STORAGE_KEY, url);
                        localStorage.removeItem(RANDOM_BACKGROUND_KEY); // Remove the random background marker
                    };
                    reader.readAsDataURL(file);
                }
            };
            fileInput.click();
        } else if (index === URL_INDEX) {
            url = prompt("Enter the URL of the new background image:");
            if (url) {
                backgroundElement.style.backgroundImage = `url(${url})`;
                alert("Background updated successfully!");
                localStorage.setItem(STORAGE_KEY, url);
                localStorage.removeItem(RANDOM_BACKGROUND_KEY); // Remove the random background marker
            }
        }
    };

    document.addEventListener('keydown', (e) => {
        if (e.altKey && e.key.toLowerCase() === 't') {
            const input = parseInt(prompt('Enter a number (0-16):\n0: Random background\n1-14: Predefined backgrounds\n15: Upload your own image\n16: URL image'), 10);
            if (!isNaN(input) && input >= 0 && input <= 16) {
                setBackground(input);
            } else {
                alert('Invalid input. Please enter a number between 0 and 16.');
            }
        }
    });


    window.onload = () => {
        const savedBackground = localStorage.getItem(STORAGE_KEY);
        const useRandomBackground = localStorage.getItem(RANDOM_BACKGROUND_KEY);

        if (useRandomBackground === "true") {
            // If random background is marked, set a random background on page load
            setRandomBackground();
        } else if (savedBackground) {
            backgroundElement.style.backgroundImage = `url(${savedBackground})`;
        }
    };
})();
/*#FPS Counter*/
(function() {
    // Create FPS display
    const fpsDisplay = document.createElement('div');
    fpsDisplay.style.position = 'absolute';
    fpsDisplay.style.top = '60%'; // Middle of the screen vertically
    fpsDisplay.style.left = '10px'; // Left side of the screen
    fpsDisplay.style.transform = 'translateY(-50%)'; // Centers it vertically based on the top position
    fpsDisplay.style.color = 'white';
    fpsDisplay.style.fontSize = '14px'; // Smaller font size
    fpsDisplay.style.fontFamily = '"roboto condensed", sans-serif'; // Regular Arial font without bold
    fpsDisplay.style.textShadow = '1px 1px 2px black'; // Slight shadow for visibility
    fpsDisplay.style.backgroundColor = 'rgba(0, 0, 0, 0.3)';
    fpsDisplay.style.padding = '3px 5px'; // Padding around the text
    fpsDisplay.style.borderRadius = '5px'; // Slightly rounded corners for styling
    fpsDisplay.style.zIndex = '10000'; // Ensure the FPS display is on top
    fpsDisplay.innerHTML = `0 FPS`;
    document.body.appendChild(fpsDisplay);
    // Update FPS
    let times = [];
    const getFPS = () => {
        window.requestAnimationFrame(() => {
            const now = performance.now();

            while (times.length > 0 && times[0] <= now - 1000) times.shift();
            times.push(now);
            fpsDisplay.innerHTML = `${times.length} FPS`;
            if (times.length <= 30) {
                fpsDisplay.style.color = "red";
            } else {
                fpsDisplay.style.color = "white";
            }
            getFPS();
        });
    }
    getFPS();
})();

/*#LAT Counter*/
(function() {
    const pingDisplay = document.createElement('div');
    pingDisplay.style.position = 'absolute';
    pingDisplay.style.top = 'calc(60% + 25px)'; // Positioned below FPS counter
    pingDisplay.style.left = '10px'; // Align with FPS counter
    pingDisplay.style.transform = 'translateY(-50%)'; // Centers it vertically based on the top position
    pingDisplay.style.color = 'white'; // Yellow color for ping counter
    pingDisplay.style.fontSize = '14px'; // Same font size as FPS counter
    pingDisplay.style.fontFamily = '"roboto condensed", sans-serif'; // Regular Arial font
    pingDisplay.style.textShadow = '1px 1px 2px black'; // Slight shadow for visibility
    pingDisplay.style.backgroundColor = 'rgba(0, 0, 0, 0.3)';
    pingDisplay.style.padding = '3px 5px'; // Padding around the text
    pingDisplay.style.borderRadius = '5px'; // Slightly rounded corners for styling
    pingDisplay.style.zIndex = '10000'; // Ensure the Ping display is on top
    pingDisplay.innerHTML = `Waiting for a game start...`; // Use backticks for string interpolation
    document.body.appendChild(pingDisplay);

    var sendTime, receiveTime, timeout, region, DOM_observer, ws;
    var teamJoined = document.getElementById("msg-wait-reason"),
        endBtn = document.getElementById("ui-stats-options");

    window.onload = () => {
        var strtBtn = document.getElementsByClassName("btn-green btn-darken menu-option");
        var strtBtnArray = [strtBtn[0], strtBtn[1], strtBtn[2]];
        strtBtnArray.forEach((btn) => {
            btn.onclick = () => {
                region = document.getElementById("server-select-main").value;
                getPing();
            };
        });
        strtBtn[3].onclick = () => {
            region = document.getElementById("team-server-select").value;
            getPing();
        };
    };

    document.getElementById("btn-game-quit").onclick = () => {
        ws.close()
    };
    document.getElementById("btn-spectate-quit").onclick = () => {
        ws.close()
    };
    DOM_observer = new MutationObserver((mutations) => {
        if (mutations[0].addedNodes.length === 1) {
            endBtn.getElementsByTagName("a")[0].onclick = () => {
                ws.close()
            };
        } else if (mutations[0].addedNodes.length === 3) {
            region = document.getElementById("team-server-select").value;
            delayConnect();
        };
    });
    DOM_observer.observe(endBtn, {
        childList: true
    });
    DOM_observer.observe(teamJoined, {
        childList: true
    });

    function wsUrl() {
        var wsUrl, wsRegion;
        if (region === 'na') {
            wsRegion = 'usr';
        } else if (region === 'eu') {
            wsRegion = 'eur';
        } else if (region === 'asia') {
            wsRegion = 'asr';
        } else if (region === 'sa') {
            wsRegion = 'sa';
        };
        wsUrl = `wss://${wsRegion}.mathsiscoolfun.com:8001/ptc`;
        return wsUrl;
    };

    function delayConnect() {
        timeout = setTimeout(getPing, 2500);
    };

    function doSend(message) {
        if (ws.readyState === 1) {
            sendTime = Date.now();
            ws.send(message);
        };
    };

    function getPing() {
        var ping, url = wsUrl();
        ws = new WebSocket(url);

        ws.onopen = () => {
            clearTimeout(timeout);
            doSend(new ArrayBuffer(1));
        };

        ws.onclose = (evt) => {
            if (evt.code === 1005) {
                pingDisplay.innerHTML = `Waiting for a game start...`;
                pingDisplay.style.color = "white";
            } else if (evt.code === 1006) {
                ws = null;
                delayConnect();
            };
        };

        ws.onmessage = () => {
        	receiveTime = Date.now();
        	ping = receiveTime - sendTime;
            if (ping >= 120) {
                pingDisplay.style.color = "red";
            } else if (ping >= 90 && ping < 120) {
                pingDisplay.style.color = "orange";
            } else {
                pingDisplay.style.color = "white";
            }
        	pingDisplay.innerHTML = `${ping} ms`;
        	setTimeout(() => {
        		doSend(new ArrayBuffer(1))
        	}, 1500);
        };

        ws.onerror = () => {
            pingDisplay.innerHTML = `NaN ms`;
            pingDisplay.style.color = "white";
        };
    };
})();

/*#HP&AD Counter*/
! function() {
    "use strict";
    var e = 0,
        t = document.createElement("span");
    t.style = "display:block;position:fixed;z-index: 2;margin:6px 0 0 0;right: 15px;mix-blend-mode: difference;font-weight: bold;font-size:large;";
    document.querySelector("#ui-health-container").appendChild(t);
    var n = document.createElement("span");
    n.style = "display:block;position:fixed;z-index: 2;margin:6px 0 0 0;left: 15px;mix-blend-mode: difference;font-weight: bold;font-size: large;";
    document.querySelector("#ui-health-container").appendChild(n);
    setInterval((function() {
        var i = document.getElementById("ui-health-actual").style.width.slice(0, -1);
        e !== i && (e = i, t.innerHTML = Number.parseFloat(i).toFixed(1));
        var o = 25 * document.getElementById("ui-boost-counter-0").querySelector(".ui-bar-inner").style.width.slice(0, -1) / 100 + 25 * document.getElementById("ui-boost-counter-1").querySelector(".ui-bar-inner").style.width.slice(0, -1) / 100 + 37.5 * document.getElementById("ui-boost-counter-2").querySelector(".ui-bar-inner").style.width.slice(0, -1) / 100 + 12.5 * document.getElementById("ui-boost-counter-3").querySelector(".ui-bar-inner").style.width.slice(0, -1) / 100;
        n.innerHTML = Math.round(o)
    }))
}();

/*Make things easy xlibizitoynetly*/
function delAds(e) {
    document.getElementById(e) && document.getElementById(e).remove()
}
setInterval(function() {
    var adsA = document.getElementsByClassName("ad-block-leaderboard-bottom")[0];
    delAds("leaderboard-front");
    delAds("adunit");
    delAds("ui-stats-ad-container-desktop");
    adsA && adsA.remove();
}, 1000);

/*
#Credits
- Asphixia (wzld): LAT counter based on NARS code and BG effects
- Junako (.junako): FPS counter based on Quintec Music FPS code
- Asultra (asultra): CSS theme based on Junako's CSS and BG effects
- sk (samerkizi): Creator of HP&AD counter
- Blubbled: Creator of Uncap FPS - https://greasyfork.org/en/scripts/493862-uncap-fps-for-suroi
- chess5321: Ideamaker

Join ASR (Surviv.io Asia Confederation): https://discord.gg/5FhUFBydUe
*/