Blubbled's UI Mod v2

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==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();
})();