Alguien Client - Survev.io Client

A client to enhance the survev.io in-game experience with many features, as well as future features.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Alguien Client - Survev.io Client
// @namespace    https://github.com/SoyAlguien0/AlguienClient
// @version      0.0.4
// @description  A client to enhance the survev.io in-game experience with many features, as well as future features.
// @author       SoyAlguien
// @license      AGPL-3.0
// @require      https://update.greasyfork.org/scripts/391611/743919/WSHook.js
// @run-at       document-end
// @match        *://survev.io/*
// @match        *://66.179.254.36/*
// @match        *://expandedwater.online/*
// @grant        none
// ==/UserScript==

class PingTest {
    constructor(selectedServer) {
        this.ptcDataBuf = new ArrayBuffer(1);
        this.test = {
            region: selectedServer.region,
            url: `wss://${selectedServer.url}/ptc`,
            ping: 9999,
            ws: null,
            sendTime: 0,
            retryCount: 0,
        };
    }
    startPingTest() {
        if (!this.test.ws) {
            const ws = new WebSocket(this.test.url);
            ws.binaryType = "arraybuffer";
            ws.onopen = () => {
                this.sendPing();
                this.test.retryCount = 0;
            };
            ws.onmessage = () => {
                const elapsed = (Date.now() - this.test.sendTime) / 1e3;
                this.test.ping = Math.round(elapsed * 1000);
                this.test.retryCount = 0;
                setTimeout(() => this.sendPing(), 200);
            };
            ws.onerror = () => {
                this.test.ping = null;
                this.test.retryCount++;
                if (this.test.retryCount < 5) {
                    setTimeout(() => this.startPingTest(), 2000);
                }
                else {
                    try {
                        ws.close();
                    }
                    catch { }
                    this.test.ws = null;
                }
            };
            ws.onclose = () => {
                this.test.ws = null;
            };
            this.test.ws = ws;
        }
    }
    sendPing() {
        if (this.test.ws && this.test.ws.readyState === WebSocket.OPEN) {
            this.test.sendTime = Date.now();
            this.test.ws.send(this.ptcDataBuf);
        }
    }
    getPingResult() {
        return {
            region: this.test.region,
            ping: this.test.ping,
        };
    }
}
class GameMod {
    constructor() {
        this.fpsCounter = null;
        this.pingCounter = null;
        this.killsCounter = null;
        this.menu = null;
        this.currentServer = null;
        this.pingTest = null;
        const settings = this.getSettings();
        this.kills = 0;
        this.isFpsVisible = true;
        this.isPingVisible = true;
        this.isKillsVisible = true;
        this.isMenuVisible = true;
        this.isClean = false;
        this.isFpsUncapped = settings["fps-uncap"] !== undefined ? !!settings["fps-uncap"] : true;
        this.setAnimationFrameCallback();
        this.initCounter("fpsCounter", this.updateFpsVisibility.bind(this));
        this.initCounter("pingCounter", this.updatePingVisibility.bind(this));
        this.initCounter("killsCounter", this.updateKillsVisibility.bind(this));
        this.initMenu();
        this.loadBackgroundFromLocalStorage();
        this.loadLocalStorage();
        this.startUpdateLoop();
        this.setupWeaponBorderHandler();
        this.setupKeyListeners();
    }
    init() {
        this.startUpdateLoop();
        this.pingShow();
        this.customUiElements();
    }
    getSettings() {
        return JSON.parse(localStorage.getItem("gameSettings") || "{}");
    }
    saveSettings() {
        localStorage.setItem("gameSettings", JSON.stringify({ "fps-uncap": this.isFpsUncapped }));
    }
    initCounter(id, updateVisibilityFn) {
        const el = document.createElement("div");
        el.id = id;
        Object.assign(el.style, {
            color: "white",
            backgroundColor: "rgba(0, 0, 0, 0.2)",
            padding: "5px 10px",
            marginTop: "10px",
            borderRadius: "5px",
            fontFamily: "Arial, sans-serif",
            fontSize: "14px",
            zIndex: "10000",
            pointerEvents: "none",
        });
        const uiTopLeft = document.getElementById("ui-top-left");
        if (uiTopLeft)
            uiTopLeft.appendChild(el);
        if (id === "fpsCounter")
            this.fpsCounter = el;
        if (id === "pingCounter")
            this.pingCounter = el;
        if (id === "killsCounter")
            this.killsCounter = el;
        updateVisibilityFn();
    }
    updateFpsVisibility() {
        this.updateVisibility("fpsCounter", this.isFpsVisible);
    }
    updateFpsToggle() {
        this.animationFrameCallback = this.isFpsUncapped
            ? (callback) => setTimeout(callback, 1)
            : (callback) => requestAnimationFrame(callback);
    }
    updatePingVisibility() {
        this.updateVisibility("pingCounter", this.isPingVisible);
    }
    updateKillsVisibility() {
        this.updateVisibility("killsCounter", this.isKillsVisible);
    }
    updateVisibility(id, isVisible) {
        const el = this[id];
        if (el) {
            el.style.display = isVisible ? "block" : "none";
            el.style.backgroundColor = isVisible ? "rgba(0, 0, 0, 0.2)" : "transparent";
        }
    }
    setAnimationFrameCallback() {
        this.animationFrameCallback = (callback) => setTimeout(callback, 1);
    }
    getKills() {
        const killElement = document.querySelector(".ui-player-kills.js-ui-player-kills");
        if (killElement) {
            const kills = Number.parseInt(killElement.textContent || "", 10);
            return Number.isNaN(kills) ? 0 : kills;
        }
        return 0;
    }
    startPingTest() {
        const currentUrl = globalThis.location.href;
        const isSpecialUrl = /\/#\w+/.test(currentUrl);
        const teamSelectElement = document.getElementById("team-server-select");
        const mainSelectElement = document.getElementById("server-select-main");
        const region = isSpecialUrl && teamSelectElement ? teamSelectElement.value : mainSelectElement ? mainSelectElement.value : null;
        if (region && region !== this.currentServer) {
            this.currentServer = region;
            this.resetPing();
            const servers = [
                { region: "NA", url: "usr.mathsiscoolfun.com:8001" },
                { region: "EU", url: "eur.mathsiscoolfun.com:8001" },
                { region: "Asia", url: "asr.mathsiscoolfun.com:8001" },
                { region: "SA", url: "sa.mathsiscoolfun.com:8001" },
            ];
            const selectedServer = servers.find((server) => region.toUpperCase() === server.region.toUpperCase());
            if (selectedServer) {
                this.pingTest = new PingTest(selectedServer);
                this.pingTest.startPingTest();
            }
            else {
                this.resetPing();
            }
        }
    }
    resetPing() {
        if (this.pingTest?.test.ws) {
            try {
                this.pingTest.test.ws.close();
            }
            catch { }
            this.pingTest.test.ws = null;
        }
        this.pingTest = null;
    }
    saveBackgroundToLocalStorage(value) {
        if (typeof value === "string") {
            localStorage.setItem("lastBackgroundType", "url");
            localStorage.setItem("lastBackgroundValue", value);
        }
        else {
            localStorage.setItem("lastBackgroundType", "local");
            const reader = new FileReader();
            reader.onload = () => {
                if (typeof reader.result === "string")
                    localStorage.setItem("lastBackgroundValue", reader.result);
            };
            reader.readAsDataURL(value);
        }
    }
    loadBackgroundFromLocalStorage() {
        const backgroundType = localStorage.getItem("lastBackgroundType");
        const backgroundValue = localStorage.getItem("lastBackgroundValue");
        const backgroundElement = document.getElementById("background");
        if (backgroundElement && backgroundType && backgroundValue) {
            backgroundElement.style.backgroundImage = `url(${backgroundValue})`;
        }
    }
    loadLocalStorage() {
        try {
            const savedSettings = JSON.parse(localStorage.getItem("userSettings") || "null");
            if (savedSettings) {
                this.isFpsVisible = savedSettings.isFpsVisible ?? this.isFpsVisible;
                this.isPingVisible = savedSettings.isPingVisible ?? this.isPingVisible;
                this.isKillsVisible = savedSettings.isKillsVisible ?? this.isKillsVisible;
                this.isClean = savedSettings.isClean ?? this.isClean;
            }
        }
        catch { }
        this.updateKillsVisibility();
        this.updateFpsVisibility();
        this.updatePingVisibility();
    }
    updateHealthBars() {
        const healthBars = document.querySelectorAll("#ui-health-container");
        healthBars.forEach((container) => {
            const bar = container.querySelector("#ui-health-actual");
            if (bar) {
                const width = Math.round(Number.parseFloat(bar.style.width || "0"));
                let percentageText = container.querySelector(".health-text");
                if (!percentageText) {
                    percentageText = document.createElement("span");
                    percentageText.classList.add("health-text");
                    Object.assign(percentageText.style, {
                        width: "100%",
                        textAlign: "center",
                        marginTop: "5px",
                        color: "#333",
                        fontSize: "20px",
                        fontWeight: "bold",
                        position: "absolute",
                        zIndex: "10",
                    });
                    container.appendChild(percentageText);
                }
                percentageText.textContent = `${width}%`;
            }
        });
    }
    updateBoostBars() {
        const boostCounter = document.querySelector("#ui-boost-counter");
        if (!boostCounter)
            return;
        const boostBars = boostCounter.querySelectorAll(".ui-boost-base .ui-bar-inner");
        let totalBoost = 0;
        const weights = [25, 25, 40, 10];
        boostBars.forEach((bar, index) => {
            const width = Number.parseFloat(bar.style.width || "0");
            if (!Number.isNaN(width))
                totalBoost += width * (weights[index] / 100);
        });
        const averageBoost = Math.round(totalBoost);
        let boostDisplay = boostCounter.querySelector(".boost-display");
        if (!boostDisplay) {
            boostDisplay = document.createElement("div");
            boostDisplay.classList.add("boost-display");
            Object.assign(boostDisplay.style, {
                position: "absolute",
                bottom: "75px",
                right: "335px",
                color: "#FF901A",
                backgroundColor: "rgba(0, 0, 0, 0.4)",
                padding: "5px 10px",
                borderRadius: "5px",
                fontFamily: "Arial, sans-serif",
                fontSize: "14px",
                zIndex: "10",
                textAlign: "center",
            });
            boostCounter.appendChild(boostDisplay);
        }
        boostDisplay.textContent = `AD: ${averageBoost}%`;
    }
    setupWeaponBorderHandler() {
        const weaponContainers = Array.from(document.getElementsByClassName("ui-weapon-switch"));
        weaponContainers.forEach((container) => {
            container.style.border = container.id === "ui-weapon-id-4" ? "3px solid #2f4032" : "3px solid #FFFFFF";
        });
        const weaponNames = Array.from(document.getElementsByClassName("ui-weapon-name"));
        weaponNames.forEach((weaponNameElement) => {
            const weaponContainer = weaponNameElement.closest(".ui-weapon-switch");
            if (!weaponContainer)
                return;
            const observer = new MutationObserver(() => {
                const weaponName = (weaponNameElement.textContent || "").trim();
                let border = "#FFFFFF";
                switch (weaponName.toUpperCase()) {
                    case "CZ-3A1":
                    case "G18C":
                    case "M9":
                    case "M93R":
                    case "MAC-10":
                    case "MP5":
                    case "P30L":
                    case "DUAL P30L":
                    case "UMP9":
                    case "VECTOR":
                    case "VSS":
                    case "FLAMETHROWER":
                        border = "#FFAE00";
                        break;
                    case "AK-47":
                    case "OT-38":
                    case "OTS-38":
                    case "M39 EMR":
                    case "DP-28":
                    case "MOSIN-NAGANT":
                    case "SCAR-H":
                    case "SV-98":
                    case "M1 GARAND":
                    case "PKP PECHENEG":
                    case "AN-94":
                    case "BAR M1918":
                    case "BLR 81":
                    case "SVD-63":
                    case "M134":
                    case "GROZA":
                    case "GROZA-S":
                        border = "#007FFF";
                        break;
                    case "FAMAS":
                    case "M416":
                    case "M249":
                    case "QBB-97":
                    case "MK 12 SPR":
                    case "M4A1-S":
                    case "SCOUT ELITE":
                    case "L86A2":
                        border = "#0f690d";
                        break;
                    case "M870":
                    case "MP220":
                    case "SAIGA-12":
                    case "SPAS-12":
                    case "USAS-12":
                    case "SUPER 90":
                    case "LASR GUN":
                    case "M1100":
                        border = "#FF0000";
                        break;
                    case "MODEL 94":
                    case "PEACEMAKER":
                    case "MK45G":
                    case "M1911":
                    case "M1A1":
                        border = "#800080";
                        break;
                    case "DEAGLE 50":
                    case "RAINBOW BLASTER":
                        border = "#000000";
                        break;
                    case "AWM-S":
                    case "MK 20 SSR":
                        border = "#808000";
                        break;
                    case "POTATO CANNON":
                    case "SPUD GUN":
                        border = "#A52A2A";
                        break;
                    case "FLARE GUN":
                        border = "#FF4500";
                        break;
                    case "M79":
                        border = "#008080";
                        break;
                    case "HEART CANNON":
                        border = "#FFC0CB";
                        break;
                    default:
                        break;
                }
                if (weaponContainer.id !== "ui-weapon-id-4") {
                    weaponContainer.style.border = `3px solid ${border}`;
                }
            });
            observer.observe(weaponNameElement, { childList: true, characterData: true, subtree: true });
        });
    }
    updateUiElements() {
        const currentUrl = globalThis.location.href;
        const isSpecialUrl = /\/#\w+/.test(currentUrl);
        const playerOptions = document.getElementById("player-options");
        if (!playerOptions)
            return;
        const teamMenuContents = document.getElementById("team-menu-contents");
        const startMenuContainer = document.querySelector("#start-menu .play-button-container");
        if (isSpecialUrl && teamMenuContents && playerOptions.parentNode !== teamMenuContents) {
            teamMenuContents.appendChild(playerOptions);
        }
        else if (!isSpecialUrl && startMenuContainer && playerOptions.parentNode !== startMenuContainer) {
            const firstChild = startMenuContainer.firstChild;
            startMenuContainer.insertBefore(playerOptions, firstChild);
        }
        const teamMenu = document.getElementById("team-menu");
        if (teamMenu)
            teamMenu.style.height = "355px";
        const menuBlocks = document.querySelectorAll(".menu-block");
        menuBlocks.forEach((block) => { block.style.maxHeight = "355px"; });
    }
    updateCleanMode() {
        const leftColumn = document.getElementById("left-column");
        const newsBlock = document.getElementById("news-block");
        if (this.isClean) {
            if (leftColumn)
                leftColumn.style.display = "none";
            if (newsBlock)
                newsBlock.style.display = "none";
        }
        else {
            if (leftColumn)
                leftColumn.style.display = "block";
            if (newsBlock)
                newsBlock.style.display = "block";
        }
    }
    setupKeyListeners() {
        document.addEventListener("keydown", (event) => {
            if (event.key.toLowerCase() === "p")
                this.toggleMenuVisibility();
        });
    }
    initMenu() {
        const menu = document.createElement("div");
        menu.id = "soyAlguienMenu";
        Object.assign(menu.style, {
            backgroundColor: "rgba(0, 0, 0, 0.5)",
            padding: "15px",
            marginLeft: "15px",
            borderRadius: "10px",
            boxShadow: "0 4px 10px rgba(0, 0, 0, 0.3)",
            zIndex: "10001",
            width: "250px",
            fontFamily: "Arial, sans-serif",
            color: "#fff",
            maxHeight: "400px",
            overflowY: "auto",
        });
        const title = document.createElement("h2");
        title.textContent = "SoyAlguien Client";
        Object.assign(title.style, {
            margin: "0 0 10px",
            textAlign: "center",
            fontSize: "18px",
            color: "#FFAE00",
        });
        menu.appendChild(title);
        const updateLocalStorage = () => {
            localStorage.setItem("userSettings", JSON.stringify({
                isFpsVisible: this.isFpsVisible,
                isPingVisible: this.isPingVisible,
                isKillsVisible: this.isKillsVisible,
                isClean: this.isClean,
            }));
        };
        this.loadLocalStorage();
        const createToggleButton = (text, stateKey, onClick) => {
            const button = document.createElement("button");
            const state = !!this[stateKey];
            button.textContent = `${text} ${state ? "✅" : "❌"}`;
            Object.assign(button.style, {
                backgroundColor: state ? "#4CAF50" : "#FF0000",
                border: "none",
                color: "#fff",
                padding: "10px",
                borderRadius: "5px",
                width: "100%",
                marginBottom: "10px",
                fontSize: "14px",
                cursor: "pointer",
            });
            button.onclick = () => {
                this[stateKey] = !this[stateKey];
                onClick();
                const newState = !!this[stateKey];
                button.textContent = `${text} ${newState ? "✅" : "❌"}`;
                button.style.backgroundColor = newState ? "#4CAF50" : "#FF0000";
                updateLocalStorage();
            };
            return button;
        };
        menu.appendChild(createToggleButton("Show FPS", "isFpsVisible", this.updateFpsVisibility.bind(this)));
        menu.appendChild(createToggleButton("Show Ping", "isPingVisible", this.updatePingVisibility.bind(this)));
        menu.appendChild(createToggleButton("Show Kills", "isKillsVisible", this.updateKillsVisibility.bind(this)));
        menu.appendChild(createToggleButton("Clean Menu", "isClean", this.updateCleanMode.bind(this)));
        const hideShowToggle = document.createElement("button");
        hideShowToggle.textContent = `👀 Hide/Show Menu [P]`;
        Object.assign(hideShowToggle.style, {
            backgroundColor: "#6F42C1",
            border: "none",
            color: "#fff",
            padding: "10px",
            borderRadius: "5px",
            width: "100%",
            marginBottom: "10px",
            fontSize: "14px",
            cursor: "pointer",
        });
        hideShowToggle.onclick = () => this.toggleMenuVisibility();
        menu.appendChild(hideShowToggle);
        const backgroundToggle = document.createElement("button");
        backgroundToggle.textContent = `🎨 Change Background`;
        Object.assign(backgroundToggle.style, {
            backgroundColor: "#007BFF",
            border: "none",
            color: "#fff",
            padding: "10px",
            borderRadius: "5px",
            width: "100%",
            marginBottom: "10px",
            fontSize: "14px",
            cursor: "pointer",
        });
        backgroundToggle.onclick = () => {
            const backgroundElement = document.getElementById("background");
            if (!backgroundElement) {
                alert("Element with id 'background' not found.");
                return;
            }
            const choice = prompt("Enter '1' to provide a URL or '2' to upload a local image:");
            if (choice === "1") {
                const newBackgroundUrl = prompt("Enter the URL of the new background image:");
                if (newBackgroundUrl) {
                    backgroundElement.style.backgroundImage = `url(${newBackgroundUrl})`;
                    this.saveBackgroundToLocalStorage(newBackgroundUrl);
                    alert("Background updated successfully!");
                }
            }
            else if (choice === "2") {
                const fileInput = document.createElement("input");
                fileInput.type = "file";
                fileInput.accept = "image/*";
                fileInput.onchange = (event) => {
                    const file = event.target.files?.[0];
                    if (file) {
                        const reader = new FileReader();
                        reader.onload = () => {
                            if (typeof reader.result === "string") {
                                backgroundElement.style.backgroundImage = `url(${reader.result})`;
                                this.saveBackgroundToLocalStorage(file);
                                alert("Background updated successfully!");
                            }
                        };
                        reader.readAsDataURL(file);
                    }
                };
                fileInput.click();
            }
        };
        menu.appendChild(backgroundToggle);
        const moreSettingsButton = document.createElement("button");
        moreSettingsButton.textContent = "⚙️ More Settings";
        Object.assign(moreSettingsButton.style, {
            backgroundColor: "#1D1616",
            border: "none",
            color: "#fff",
            padding: "10px",
            borderRadius: "5px",
            width: "100%",
            fontSize: "14px",
            cursor: "pointer",
        });
        moreSettingsButton.onclick = () => this.openSubMenu();
        menu.appendChild(moreSettingsButton);
        globalThis.onload = () => {
            const savedBackground = localStorage.getItem("backgroundImage");
            if (savedBackground) {
                const backgroundElement = document.getElementById("background");
                if (backgroundElement)
                    backgroundElement.style.backgroundImage = `url(${savedBackground})`;
            }
        };
        const startRowTop = document.getElementById("start-row-top");
        if (startRowTop)
            startRowTop.appendChild(menu);
        this.menu = menu;
    }
    openSubMenu() {
        const overlay = document.createElement("div");
        const savedOpacity = localStorage.getItem("opacity") ?? "1";
        const savedScale = localStorage.getItem("scale") ?? "0.8";
        Object.assign(overlay.style, {
            position: "fixed",
            top: "0",
            left: "0",
            width: "100%",
            height: "100%",
            backgroundColor: "rgba(0, 0, 0, 0.7)",
            zIndex: "10002",
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
        });
        const subMenu = document.createElement("div");
        Object.assign(subMenu.style, {
            backgroundColor: "#333",
            padding: "20px",
            borderRadius: "15px",
            width: "400px",
            color: "#fff",
            textAlign: "left",
            zIndex: "10003",
            boxShadow: "0 4px 15px rgba(0, 0, 0, 0.5)",
        });
        const createSectionHeader = (text) => {
            const header = document.createElement("h3");
            header.textContent = text;
            Object.assign(header.style, {
                fontSize: "18px",
                fontWeight: "bold",
                color: "#FFD700",
                marginBottom: "10px",
            });
            return header;
        };
        const createSettingItem = (id, label, checked) => {
            const wrapper = document.createElement("div");
            Object.assign(wrapper.style, {
                display: "flex",
                alignItems: "center",
                padding: "10px",
                marginBottom: "10px",
                borderRadius: "8px",
                backgroundColor: "#444",
            });
            const checkbox = document.createElement("input");
            checkbox.id = id;
            checkbox.type = "checkbox";
            checkbox.checked = checked;
            Object.assign(checkbox.style, { marginRight: "10px", cursor: "pointer" });
            const labelText = document.createElement("p");
            labelText.textContent = label;
            Object.assign(labelText.style, { margin: "0", fontSize: "16px", color: "#fff" });
            wrapper.appendChild(checkbox);
            wrapper.appendChild(labelText);
            return wrapper;
        };
        const createCustomSlider = (id, min, max, step, value, onChange) => {
            const wrapper = document.createElement("div");
            Object.assign(wrapper.style, {
                display: "flex",
                alignItems: "center",
                justifyContent: "space-between",
                marginBottom: "10px",
            });
            const slider = document.createElement("input");
            slider.type = "range";
            slider.id = id;
            slider.min = String(min);
            (slider).max = String(max);
            (slider).step = String(step);
            (slider).value = value;
            Object.assign(slider.style, { flex: "1", marginRight: "10px" });
            const valueLabel = document.createElement("span");
            valueLabel.textContent = value;
            Object.assign(valueLabel.style, { minWidth: "30px", textAlign: "right", color: "#fff" });
            slider.oninput = () => {
                valueLabel.textContent = (slider).value;
                onChange((slider).value);
            };
            wrapper.appendChild(slider);
            wrapper.appendChild(valueLabel);
            return wrapper;
        };
        const titleClient = document.createElement("h2");
        titleClient.textContent = "Client Settings";
        Object.assign(titleClient.style, {
            margin: "0 0 20px",
            fontSize: "24px",
            fontWeight: "bold",
            color: "#FFAE00",
            textAlign: "center",
        });
        subMenu.appendChild(titleClient);
        subMenu.appendChild(createSectionHeader("FPS Uncap"));
        subMenu.appendChild(createSettingItem("fps-uncap", "Enable/disable FPS uncap", this.isFpsUncapped));
        const titleUI = document.createElement("h2");
        titleUI.textContent = "UI Settings";
        Object.assign(titleUI.style, {
            margin: "20px 0 20px",
            fontSize: "24px",
            fontWeight: "bold",
            color: "#FFAE00",
            textAlign: "center",
        });
        subMenu.appendChild(titleUI);
        subMenu.appendChild(createSectionHeader("Opacity"));
        subMenu.appendChild(createCustomSlider("opacity-slider", 0, 1, 0.01, savedOpacity, (value) => localStorage.setItem("opacity", value)));
        subMenu.appendChild(createSectionHeader("Scale"));
        subMenu.appendChild(createCustomSlider("scale-slider", 0.5, 1, 0.01, savedScale, (value) => localStorage.setItem("scale", value)));
        const closeButton = document.createElement("button");
        closeButton.textContent = "Close";
        Object.assign(closeButton.style, {
            backgroundColor: "#FF4D4D",
            border: "none",
            color: "#fff",
            padding: "10px 20px",
            borderRadius: "8px",
            marginTop: "20px",
            cursor: "pointer",
            fontSize: "16px",
            fontWeight: "bold",
            transition: "background-color 0.3s ease",
            width: "100%",
        });
        closeButton.onmouseenter = () => { closeButton.style.backgroundColor = "#FF3333"; };
        closeButton.onmouseleave = () => { closeButton.style.backgroundColor = "#FF4D4D"; };
        closeButton.onclick = () => {
            if (overlay.parentElement)
                document.body.removeChild(overlay);
        };
        subMenu.appendChild(closeButton);
        overlay.appendChild(subMenu);
        document.body.appendChild(overlay);
        this.attachSettingsEvents();
    }
    customUiElements() {
        const scale = parseFloat(localStorage.getItem("scale") || "0.8");
        const opacity = parseFloat(localStorage.getItem("opacity") || "1");
        const healthBoost = document.getElementById("ui-bottom-center-0");
        if (healthBoost) {
            healthBoost.style.transform = `translateX(-50%) scale(${scale})`;
            healthBoost.style.opacity = String(opacity);
            healthBoost.style.bottom = globalThis.innerWidth > 1200 ? `-${(1 - scale) * 20 + 2}px` : "";
        }
        const weapon = document.getElementById("ui-weapon-container");
        if (weapon) {
            weapon.style.scale = String(scale);
            weapon.style.opacity = String(opacity);
            weapon.style.transformOrigin = "right";
        }
        const inventory = document.getElementById("ui-right-center");
        if (inventory) {
            inventory.style.scale = String(scale * 1.1);
            inventory.style.opacity = String(opacity);
            inventory.style.marginTop = `-${(1 - scale) * 100}px`;
        }
        const info = document.getElementById("ui-top-left");
        if (info) {
            info.style.transformOrigin = "top left";
            info.style.scale = String(scale * 1.1);
            info.style.opacity = String(opacity);
        }
        const players = document.getElementById("ui-leaderboard-wrapper");
        if (players) {
            players.style.scale = String(scale);
            players.style.opacity = String(opacity);
            players.style.transformOrigin = "top right";
        }
        const killfeed = document.getElementById("ui-killfeed-wrapper");
        if (killfeed) {
            killfeed.style.scale = String(scale);
            killfeed.style.opacity = String(opacity);
            killfeed.style.transformOrigin = "right";
        }
        const ammo = document.getElementById("ui-equipped-ammo-wrapper");
        if (ammo) {
            ammo.style.opacity = String(opacity);
            ammo.style.transform = `translateX(-50%) scale(${scale})`;
            const bottomValue = 62 - (1 - scale) * 20;
            ammo.style.bottom = `${bottomValue}px`;
        }
        const gears = document.getElementById("ui-bottom-center-right");
        if (gears) {
            gears.style.opacity = String(opacity);
            gears.style.scale = String(scale);
        }
        const scopes = document.getElementById("ui-top-center-scopes");
        if (scopes) {
            scopes.style.opacity = String(opacity);
            scopes.style.scale = String(scale);
        }
    }
    attachSettingsEvents() {
        const fpsUncapCheckbox = document.querySelector("#fps-uncap");
        if (fpsUncapCheckbox) {
            fpsUncapCheckbox.addEventListener("change", (event) => {
                const target = event.target;
                this.isFpsUncapped = target.checked;
                this.saveSettings();
            });
        }
        const opacitySlider = document.querySelector("#opacity-slider");
        if (opacitySlider) {
            opacitySlider.addEventListener("input", (event) => {
                const target = event.target;
                localStorage.setItem("opacity", target.value);
                this.customUiElements();
            });
        }
        const scaleSlider = document.querySelector("#scale-slider");
        if (scaleSlider) {
            scaleSlider.addEventListener("input", (event) => {
                const target = event.target;
                localStorage.setItem("scale", target.value);
                this.customUiElements();
            });
        }
    }
    toggleMenuVisibility() {
        if (!this.menu)
            return;
        const isVisible = this.menu.style.display !== "none";
        this.menu.style.display = isVisible ? "none" : "block";
    }
    startUpdateLoop() {
        let lastFrameTime = performance.now();
        let frameCount = 0;
        let fps = 0;
        const loop = () => {
            const now = performance.now();
            const delta = now - lastFrameTime;
            frameCount++;
            if (delta >= 1000) {
                fps = Math.round((frameCount * 1000) / delta) * 2;
                frameCount = 0;
                lastFrameTime = now;
                this.kills = this.getKills();
                if (this.isFpsVisible && this.fpsCounter) {
                    this.fpsCounter.textContent = `FPS: ${Math.round(fps / 2)}`;
                }
                if (this.isKillsVisible && this.killsCounter) {
                    this.killsCounter.textContent = `Kills: ${this.kills}`;
                }
                if (this.isPingVisible && this.pingCounter && this.pingTest) {
                    const result = this.pingTest.getPingResult();
                    this.pingCounter.textContent = `PING: ${result.ping} ms`;
                }
            }
            this.startPingTest();
            this.updateFpsToggle();
            this.animationFrameCallback(() => loop());
            this.updateUiElements();
            this.updateCleanMode();
            this.updateBoostBars();
            this.updateHealthBars();
        };
        loop();
    }
    pingShow() {
        const serverSelect = document.getElementById("server-select-main");
        if (!serverSelect)
            return;
        const updateOptionWithPing = (optionElement, ping) => {
            const pingText = ` (${ping} ms)`;
            const originalText = optionElement.textContent?.replace(/\(\d+ ms\)/g, "").trim() || "";
            optionElement.textContent = `${originalText}${pingText}`;
            if (ping > 300) {
                optionElement.style.color = "red";
            }
            else if (ping > 200) {
                optionElement.style.color = "orange";
            }
            else if (ping > 100) {
                optionElement.style.color = "yellow";
            }
            else {
                optionElement.style.color = "green";
            }
        };
        const servers = [
            { region: "NA", url: "usr.mathsiscoolfun.com:8001" },
            { region: "EU", url: "eur.mathsiscoolfun.com:8001" },
            { region: "Asia", url: "asr.mathsiscoolfun.com:8001" },
            { region: "SA", url: "sa.mathsiscoolfun.com:8001" },
        ];
        servers.forEach((server) => {
            const pingTest = new PingTest(server);
            pingTest.startPingTest();
            const intervalId = globalThis.setInterval(() => {
                const pingResult = pingTest.getPingResult();
                if (pingResult.ping !== 9999 && pingResult.ping !== null) {
                    const optionElement = serverSelect.querySelector(`option[value="${server.region.toLowerCase()}"]`);
                    if (optionElement) {
                        updateOptionWithPing(optionElement, pingResult.ping);
                    }
                    clearInterval(intervalId);
                }
            }, 2000);
        });
    }
}
const gameMod = new GameMod();