Greasy Fork is available in English.

Blubbled's UI Mod v2

Adds some QoL features, such as always showing kill count, green health bar, etc

// ==UserScript==
// @name         Blubbled's UI Mod v2
// @namespace    http://tampermonkey.net/
// @version      2
// @description  Adds some QoL features, such as always showing kill count, green health bar, etc
// @author       Blubbled
// @match        https://suroi.io/*
// @grant        none
// @license MIT
// ==/UserScript==



(function() {

    'use strict';

    function periodicallyShowKillCounter() {
        showKillCounter();
        setTimeout(periodicallyShowKillCounter, 100);
    }

    function showKillCounter() {
        var killCounter = document.getElementById('kill-counter');
        if (killCounter) {
            killCounter.style.display = 'flex';
            killCounter.style.alignItems = 'center';
            var skullIcon = killCounter.querySelector('img');
            if (skullIcon) {
                skullIcon.style.marginRight = '5px';
            }
            var counterText = killCounter.querySelector('.counter-text');
            if (counterText) {
                counterText.style.minWidth = '30px';
            }
        }
    }
    var actionTimer;
    var countdownElement;

    function startActionTimer() {
        var countdownValue = 4;
        countdownElement = document.createElement('div');
        countdownElement.id = 'action-countdown';
        countdownElement.textContent = countdownValue;
        countdownElement.style.position = 'fixed';
        countdownElement.style.top = '50%';
        countdownElement.style.left = '50%';
        countdownElement.style.transform = 'translate(-50%, -170%)';
        countdownElement.style.fontSize = '24px';
        countdownElement.style.fontWeight = 'bold';
        countdownElement.style.color = 'white';
        countdownElement.style.zIndex = '9999'; 
        document.body.appendChild(countdownElement);

        actionTimer = setInterval(function() {
            countdownValue -= 0.1;
            countdownElement.textContent = countdownValue.toFixed(1);
            if (countdownValue <= 0) {
                clearInterval(actionTimer);
                actionTimer = null;

                countdownElement.parentNode.removeChild(countdownElement);
            }
        }, 100);
    }




    //function handleMouseDown(event) {
    //    console.log('Mouse down event detected');
//
//        if (event.button === 0){
 //           var weaponSlot = document.getElementById('weapon-slot-4');
  //          if (weaponSlot.classList.contains('active')) {
   //             console.log('Starting action timer');
  //              startActionTimer();
   //         }
    //    }
   // }


   // function handleMouseUp(event) {
   //     console.log('Mouse up event detected');

    //    if (event.button === 0) {

    //        if (actionTimer) {
    //            console.log('Clearing action timer');
    //            clearInterval(actionTimer);
    //            actionTimer = null;

     //           if (countdownElement) {
     //               countdownElement.parentNode.removeChild(countdownElement);
     //               countdownElement = null;
     //           }
     //   }
  //  }

  //  window.addEventListener('mousedown', handleMouseDown);
    //window.addEventListener('mouseup', handleMouseUp);


    function addAdditionalUI() {
        var additionalText = document.createElement('h1');
        additionalText.textContent = "Technical UI pack by Blubbled ";
        var joinLink = document.createElement('a');
        joinLink.textContent = "[JOIN ZESK]";
        joinLink.href = "https://discord.gg/msNbP9Nt2r";
        joinLink.style.color = 'blue';
        joinLink.style.textDecoration = 'underline';
        joinLink.style.marginLeft = '5px';
        additionalText.appendChild(joinLink);
        additionalText.style.position = 'fixed';
        additionalText.style.top = '10px';
        additionalText.style.right = '10px';
        additionalText.style.color = '#ffffff';
        additionalText.style.zIndex = '9999';
        additionalText.style.display = 'none';
        document.body.appendChild(additionalText);

        var masterVolumeSlider = document.getElementById('slider-master-volume');
        var sfxVolumeSlider = document.getElementById('slider-sfx-volume');
        var musicVolumeSlider = document.getElementById('slider-music-volume');
        var uiScaleSlider = document.getElementById('slider-ui-scale');
        var minimapTransparencySlider = document.getElementById('slider-minimap-transparency');
        var bigMapTransparencySlider = document.getElementById('slider-big-map-transparency');

        if (masterVolumeSlider && sfxVolumeSlider && musicVolumeSlider && uiScaleSlider && minimapTransparencySlider && bigMapTransparencySlider) {
            masterVolumeSlider.step = 0.01;
            sfxVolumeSlider.step = 0.01;
            musicVolumeSlider.step = 0.01;
            uiScaleSlider.step = 0.01;
            minimapTransparencySlider.step = 0.01;
            bigMapTransparencySlider.step = 0.01;
        }
    }

    function replaceWithHeader() {
        var customHeader = document.createElement('h1');
        customHeader.textContent = "Technical UI pack by Blubbled ";
        var joinLink = document.createElement('a');
        joinLink.textContent = "[JOIN ZESK]";
        joinLink.href = "https://discord.gg/msNbP9Nt2r";
        joinLink.style.color = 'blue';
        joinLink.style.textDecoration = 'underline';
        joinLink.style.marginLeft = '5px';
        customHeader.appendChild(joinLink);
        customHeader.style.position = 'fixed';
        customHeader.style.top = '10px';
        customHeader.style.right = '10px';
        customHeader.style.color = '#ffffff';
        customHeader.style.zIndex = '9999';
        var elementToReplace = document.querySelector('a[href="./changelog/"][target="_blank"][rel="noopener noreferrer"]');
        if (elementToReplace) {
            elementToReplace.parentNode.replaceChild(customHeader, elementToReplace);
        }
    }






    var settingsTabsContainer = document.getElementById('settings-tabs-container');
    var modSettingsTabButton = document.createElement('button');
    modSettingsTabButton.className = 'tab';
    modSettingsTabButton.id = 'tab-mod-settings';
    modSettingsTabButton.innerHTML = '<i class="fa-solid fa-gear"></i>Mod Settings';
    settingsTabsContainer.querySelector('#settings-tab-bar').appendChild(modSettingsTabButton);

    var modSettingsTabContent = document.createElement('div');
    modSettingsTabContent.className = 'tab-content';
    modSettingsTabContent.id = 'tab-mod-settings-content';
    modSettingsTabContent.style.display = 'none';

    var modSettingsContent = document.createElement('div');




    modSettingsTabContent.appendChild(modSettingsContent);
    settingsTabsContainer.querySelector('#settings-tabs').appendChild(modSettingsTabContent);



//player info
    function togglePlayerInfo(enabled) {
        if (enabled) {
            var healthBarPercentageCopy = document.createElement('span');
            healthBarPercentageCopy.id = 'health-bar-percentage-copy';
            healthBarPercentageCopy.classList.add('unselectable');
            healthBarPercentageCopy.style.position = 'fixed';
            healthBarPercentageCopy.style.top = '50%';
            healthBarPercentageCopy.style.left = '46.2%';
            healthBarPercentageCopy.style.transform = 'translate(-50%, -50%)';
            healthBarPercentageCopy.style.fontSize = '20px';
            healthBarPercentageCopy.style.fontWeight = 'bold';

            function updateHealthBarPercentageCopy() {
                var healthBarPercentageValue = document.getElementById('health-bar-percentage').textContent;
                var healthBarColor = document.getElementById('health-bar').style.backgroundColor;

                healthBarPercentageCopy.textContent = healthBarPercentageValue + "➕";
                healthBarPercentageCopy.style.color = healthBarColor;
            }

            healthBarPercentageCopy.style.webkitTouchCallout = 'none'; /* iOS Safari */
            healthBarPercentageCopy.style.webkitUserSelect = 'none'; /* Safari */
            healthBarPercentageCopy.style.userSelect = 'none'; /* Standard syntax */

            updateHealthBarPercentageCopy();
            document.body.appendChild(healthBarPercentageCopy);

            var observer1 = new MutationObserver(updateHealthBarPercentageCopy);
            var targetNode1 = document.getElementById('health-bar-percentage');
            observer1.observe(targetNode1, { childList: true, subtree: true });

            var adrenalineBarPercentageCopy = document.createElement('span');
            adrenalineBarPercentageCopy.id = 'adrenaline-bar-percentage-copy';
            adrenalineBarPercentageCopy.classList.add('unselectable');
            adrenalineBarPercentageCopy.style.position = 'fixed';
            adrenalineBarPercentageCopy.style.top = '50%';
            adrenalineBarPercentageCopy.style.right = '46.2%';
            adrenalineBarPercentageCopy.style.transform = 'translate(50%, -50%)';
            adrenalineBarPercentageCopy.style.fontSize = '20px';
            adrenalineBarPercentageCopy.style.fontWeight = 'bold';

            function updateAdrenalineBarPercentageCopy() {
                var adrenalineBarPercentageValue = document.getElementById('adrenaline-bar-percentage').textContent;
                var adrenalineBarColor = document.getElementById('adrenaline-bar').style.backgroundColor;

                adrenalineBarPercentageCopy.textContent = adrenalineBarPercentageValue + "⚡";
                adrenalineBarPercentageCopy.style.color = adrenalineBarColor;
            }

            adrenalineBarPercentageCopy.style.webkitTouchCallout = 'none'; /* iOS Safari */
            adrenalineBarPercentageCopy.style.webkitUserSelect = 'none'; /* Safari */
            adrenalineBarPercentageCopy.style.userSelect = 'none'; /* Standard syntax */

            updateAdrenalineBarPercentageCopy();
            document.body.appendChild(adrenalineBarPercentageCopy);

            var observer2 = new MutationObserver(updateAdrenalineBarPercentageCopy);
            var targetNode2 = document.getElementById('adrenaline-bar-percentage');
            observer2.observe(targetNode2, { childList: true, subtree: true });
        } else {
          
            var healthBarPercentageCopy = document.getElementById('health-bar-percentage-copy');
            if (healthBarPercentageCopy) {
                healthBarPercentageCopy.parentNode.removeChild(healthBarPercentageCopy);
            }

            var adrenalineBarPercentageCopy = document.getElementById('adrenaline-bar-percentage-copy');
            if (adrenalineBarPercentageCopy) {
                adrenalineBarPercentageCopy.parentNode.removeChild(adrenalineBarPercentageCopy);
            }
        }
    }


    
    function createTextDistanceSlider() {
        var slider = document.createElement('input');
        slider.type = 'range';
        slider.min = '-100'; 
        slider.max = '100';
        slider.value = '0'; 
        slider.id = 'textDistanceSlider';
        slider.style.position = 'fixed';
        slider.style.top = '26.2%'; 
        slider.style.left = 'auto'; 
        slider.style.right = '28.5%'; 
        slider.style.transform = 'translate(50%, -50%)';
        slider.style.width = '180px';
      
        slider.addEventListener('input', function() {
            var distance = this.value;
         
            var healthBarPercentageCopy = document.getElementById('health-bar-percentage-copy');
            var adrenalineBarPercentageCopy = document.getElementById('adrenaline-bar-percentage-copy');
            if (healthBarPercentageCopy && adrenalineBarPercentageCopy) {
                healthBarPercentageCopy.style.left = (46.2 + parseInt(distance)) + '%';
                adrenalineBarPercentageCopy.style.right = (46.2 + parseInt(distance)) + '%';
            }
        });

        return slider;
    }

    var modSettingsContent = document.getElementById('tab-mod-settings-content');
    if (modSettingsContent) {
        var slider = createTextDistanceSlider();
        modSettingsContent.appendChild(slider);
    }


//text colors
    function createToggleCustomTextColorSetting() {
        var toggleSetting = document.createElement('div');
        toggleSetting.className = 'modal-item';
        toggleSetting.style.marginBottom = '10px';
        toggleSetting.innerHTML = `
            <input type="checkbox" id="toggle-custom-text-color" ${localStorage.getItem('customTextColorEnabled') === 'true' ? 'checked' : ''}>
            <label for="text-color-picker" style="font-weight: bold; margin-left: 0px;">Text Color</label>
            <input type="color" id="text-color-picker" value="${localStorage.getItem('textColor') || '#ffffff'}" style="margin-left: -100px;">

        `;
        toggleSetting.querySelector('#toggle-custom-text-color').addEventListener('change', function() {
            updateCustomTextColorSetting(this.checked);
        });
        toggleSetting.querySelector('#text-color-picker').addEventListener('input', function() {
            updateTextColorSetting(this.value);
        });
        return toggleSetting;
    }

    function updateCustomTextColorSetting(enabled) {
        localStorage.setItem('customTextColorEnabled', enabled);
        if (enabled) {
            applyCustomTextColor();
        } else {
            disableCustomTextColor();
        }
    }

    function applyCustomTextColor() {
        var customTextColor = localStorage.getItem('textColor') || '#ffffff';
        applyTextColor(customTextColor);
    }

    function disableCustomTextColor() {
        var countElements = document.querySelectorAll('.item-count, #fps-counter, #coordinates-hud, #ping-counter');
        countElements.forEach(function(element) {
            element.style.color = ''; 
        });
    }

    function updateTextColorSetting(color) {
        localStorage.setItem('textColor', color);
        if (localStorage.getItem('customTextColorEnabled') === 'true') {
            applyCustomTextColor();
        }
    }

    function applyTextColor(color) {
        var countElements = document.querySelectorAll('.item-count');
        countElements.forEach(function(element) {
            element.style.color = color;
        });

        var fpsElement = document.getElementById('fps-counter');
        var coordsElement = document.getElementById('coordinates-hud');
        var pingElement = document.getElementById('ping-counter');

        if (fpsElement) {
            fpsElement.style.color = color;
        }

        if (coordsElement) {
            coordsElement.style.color = color;
        }

        if (pingElement) {
            pingElement.style.color = color;
        }
    }

    modSettingsContent.appendChild(createToggleCustomTextColorSetting());
    if (localStorage.getItem('customTextColorEnabled') === 'true') {
        applyCustomTextColor();
    }


    var playerInfoEnabled = localStorage.getItem('playerInfoEnabled') === 'true';
 
    togglePlayerInfo(playerInfoEnabled);

 
    function updatePlayerInfoSetting(enabled) {
        localStorage.setItem('playerInfoEnabled', enabled);
     
        togglePlayerInfo(enabled);
    }


    function createPlayerInfoSetting() {
        var playerInfoSetting = document.createElement('div');
        playerInfoSetting.className = 'modal-item checkbox-setting';
        playerInfoSetting.style.marginBottom = '10px';
        playerInfoSetting.innerHTML = `
        <label>
            <span class="setting-title" style="margin-right: 10px;">Info on Player</span>
            <input type="checkbox" id="toggle-player-info" ${playerInfoEnabled ? 'checked' : ''} style="margin-left: auto; margin-right: -0px; ">
        </label>
    `;
        playerInfoSetting.querySelector('#toggle-player-info').addEventListener('change', function() {
            updatePlayerInfoSetting(this.checked);
        });
        return playerInfoSetting;
    }

    modSettingsContent.appendChild(createPlayerInfoSetting());

//uncap fps
    function toggleUncappedFPS(enabled) {
        if (enabled) {
            window.requestAnimationFrame = function(callback) {
                return setTimeout(callback, 1);
            };
        } else {
            window.requestAnimationFrame = function(callback) {
                return setTimeout(callback, 1000 / 60);
            };
        }
    }


    var uncappedFPSEnabled = localStorage.getItem('uncappedFPSEnabled') === 'true';
    toggleUncappedFPS(uncappedFPSEnabled);


    function updateUncappedFPSSetting(enabled) {
        localStorage.setItem('uncappedFPSEnabled', enabled);
        toggleUncappedFPS(enabled);
    }


    function createUncappedFPSSetting() {
        var uncappedFPSSetting = document.createElement('div');
        uncappedFPSSetting.className = 'modal-item checkbox-setting';
        uncappedFPSSetting.style.marginBottom = '10px';
        uncappedFPSSetting.innerHTML = `
            <label>
                <span class="setting-title" style="margin-right: 10px;">Uncapped FPS</span>
                <input type="checkbox" id="toggle-uncapped-fps" ${uncappedFPSEnabled ? 'checked' : ''} style="margin-left: auto; margin-right: -0px; ">
            </label>
        `;
        uncappedFPSSetting.querySelector('#toggle-uncapped-fps').addEventListener('change', function() {
            updateUncappedFPSSetting(this.checked);
        });
        return uncappedFPSSetting;
    }

    var gunSwitchDelayMap = {
        "AK-47": 400,
        "ARX-160": 400,
        "AUG": 400,
        "ACR": 400,
        "M3K": 700,
        "Model 37": 900,
        "HP18": 400,
        "Flues": 250,
        "Vepr-12": 650,
        "Mosin-Nagant": 900,
        "Tango 51": 900,
        "CZ-600": 600,
        "Barrett M95": 900,
        "M1895": 250,
        "G19": 250,
        "Radio": 250,
        "CZ-75A": 250,
        "SAF-200": 300,
        "M16A4": 400,
        "Micro Uzi": 300,
        "Vector": 300,
        "PP-19": 300,
        "MP40": 300,
        "MCX Spear": 400,
        "Lewis Gun": 400,
        "Stoner 63": 400,
        "MG5": 400,
        "Negev": 400,
        "MG36": 400,
        "M1 Garand": 400,
        "VSS": 400,
        "SR-25": 400,
        "Mini-14": 400,
        "Model 89": 400,
        "USAS-12": 400,
        "G17 (scoped)": 250,
        "Death Ray": 500,
        "Destroyer Of Worlds": 100
    };



    function startCountdownAbovePlayer(countdownValue) {
        var countdownElement = document.createElement('div');
        countdownElement.id = 'weapon-switch-countdown';
        countdownElement.textContent = countdownValue.toFixed(1);
        countdownElement.style.position = 'fixed';
        countdownElement.style.top = '45%';
        countdownElement.style.left = '50%';
        countdownElement.style.transform = 'translate(-50%, -170%)';
        countdownElement.style.fontSize = '24px';
        countdownElement.style.fontWeight = 'bold';
        countdownElement.style.color = 'white';
        countdownElement.style.zIndex = '9999';
        document.body.appendChild(countdownElement);

        var countdownTimer = setInterval(function() {
            countdownValue -= 0.1;
            countdownElement.textContent = countdownValue.toFixed(1);
            if (countdownValue <= 0) {
                clearInterval(countdownTimer);
                countdownElement.parentNode.removeChild(countdownElement);
            }
        }, 100);
    }

    var countdownActive1 = false;
    var countdownActive2 = false;
    var countdownInterval1;
    var countdownInterval2;
    var lastDetectionTimestamp = 0;

    function detectActiveWeaponAndStartCountdown() {

        var currentTimestamp = Date.now();

        if (currentTimestamp - lastDetectionTimestamp < 10) {
            return;
        }

        lastDetectionTimestamp = currentTimestamp;

        var weaponSlot1 = document.getElementById('weapon-slot-1');
        var weaponSlot2 = document.getElementById('weapon-slot-2');

        if (weaponSlot1 && weaponSlot1.classList.contains('active')) {
            var itemNameElement = weaponSlot1.querySelector('.item-name');
            if (itemNameElement) {
                var itemName = itemNameElement.textContent.trim();
                var switchDelay = gunSwitchDelayMap[itemName];
                if (switchDelay !== undefined) {
                    if (!countdownActive1) {
                        var countdownValue = switchDelay / 1000;
                        startCountdownAbovePlayer(countdownValue);
                        countdownActive1 = true;
                    } else {
                    }
                } else {
                }
            } else {
            }
        } else {
            countdownActive1 = false;
            clearInterval(countdownInterval1);
        }

        if (weaponSlot2 && weaponSlot2.classList.contains('active')) {
            var itemNameElement = weaponSlot2.querySelector('.item-name');
            if (itemNameElement) {
                var itemName = itemNameElement.textContent.trim();
                var switchDelay = gunSwitchDelayMap[itemName];
                if (switchDelay !== undefined) {
                    if (!countdownActive2) {
                        var countdownValue = switchDelay / 1000;
                        startCountdownAbovePlayer(countdownValue);
                        countdownActive2 = true;
                    } else {
                    }
                } else {
                }
            } else {
            }
        } else {
            countdownActive2 = false;
            clearInterval(countdownInterval2);
        }
    }

    setInterval(detectActiveWeaponAndStartCountdown, 1);

    function toggleSwitchDelay(enabled) {
        if (enabled) {
            document.addEventListener('click', detectActiveWeaponAndStartCountdown);
        } else {

            document.removeEventListener('click', detectActiveWeaponAndStartCountdown);
            var existingCountdownElement = document.getElementById('weapon-switch-countdown');
            if (existingCountdownElement) {
                existingCountdownElement.parentNode.removeChild(existingCountdownElement);
            }
        }
    }

    var switchDelayEnabled = localStorage.getItem('switchDelayEnabled') === 'true';


    toggleSwitchDelay(switchDelayEnabled);


    function updateSwitchDelaySetting(enabled) {
        localStorage.setItem('switchDelayEnabled', enabled);
        toggleSwitchDelay(enabled);
    }


    function createSwitchDelaySetting() {
        var switchDelaySetting = document.createElement('div');
        switchDelaySetting.className = 'modal-item checkbox-setting';
        switchDelaySetting.style.marginBottom = '10px';
        switchDelaySetting.innerHTML = `
    <label>
        <span class="setting-title" style="margin-right: 10px;">Enable switchDelay</span>
        <input type="checkbox" id="toggle-switch-delay" ${switchDelayEnabled ? 'checked' : ''} style="margin-left: auto; margin-right: -0px; ">
    </label>
`;
        switchDelaySetting.querySelector('#toggle-switch-delay').addEventListener('change', function() {
            updateSwitchDelaySetting(this.checked);
        });
        return switchDelaySetting;
    }

    var modSettingsContent = document.getElementById('tab-mod-settings-content');
    if (modSettingsContent) {
        modSettingsContent.appendChild(createSwitchDelaySetting());
    }



    modSettingsContent.appendChild(createUncappedFPSSetting());

    showKillCounter();
    addAdditionalUI();

    createUncappedFPSSetting()





    periodicallyShowKillCounter();
    document.addEventListener('DOMContentLoaded', addAdditionalUI);
    window.addEventListener('popstate', showKillCounter);
    replaceWithHeader();
})();