DiepShadow (Fixed)

Press CTRL + I to activate. Create cool glow or 3D effects using this tool. Fixed for modern diep.io

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

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

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

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

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

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.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         DiepShadow (Fixed)
// @namespace    *://diep.io/*
// @version      1.4
// @description  Press CTRL + I to activate. Create cool glow or 3D effects using this tool. Fixed for modern diep.io
// @author       Binary (maintained and fixed by razor)
// @match        *://diep.io/*
// @match        *://localhost:8080/*
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    var hotkey_activate_sequence = function(event) { // CTRL + I
        if (event.ctrlKey && !event.altKey && !event.shiftKey && event.code === 'KeyI' && !event.repeat) {
            event.preventDefault();
            return true;
        }
    };

    var localStorage_key = 'diepshadow_preferences';
    var version = '1.4';

    var presets = [{
        name: 'funny 1',
        description: 'yeah',
        shadowBlur: 0,
        shadowOffsetX: 8,
        shadowOffsetY: 8,
        shadowStrength: 1,
        shadowColor: 'rgb(35,14,53)'
    },{
        name: 'funny 2',
        description: 'yeah',
        shadowBlur: 0,
        shadowOffsetX: 8,
        shadowOffsetY: 8,
        shadowStrength: 1,
        shadowColor: 'rgb(24,1,55)'
    }];

    var storageSettings;
    try{
        storageSettings = JSON.parse(window.localStorage.getItem(localStorage_key));
    }catch(e){storageSettings = {}}
    if(!(storageSettings instanceof Object)) storageSettings = {};
    var booleanOrDefault = function(key, defaultValue){
        if(typeof storageSettings[key] === 'boolean') return storageSettings[key];
        return defaultValue;
    };
    var numberOrDefault = function(key, defaultValue){
        if(typeof storageSettings[key] === 'number' && !isNaN(storageSettings[key])) return storageSettings[key];
        return defaultValue;
    };
    var settings = {
        enableShadow: booleanOrDefault('enableShadow', true),
        enableSaving: booleanOrDefault('enableSaving', true),
        shadowBlur: numberOrDefault('shadowBlur', 0),
        shadowOffsetX: numberOrDefault('shadowOffsetX', 8),
        shadowOffsetY: numberOrDefault('shadowOffsetY', 8),
        shadowStrength: numberOrDefault('shadowStrength', 1),
        shadowColor: typeof storageSettings.shadowColor === 'string' ? storageSettings.shadowColor : 'rgb(24,1,55)'
    };

    // ==== INTERCEPT CANVAS CONTEXT BEFORE PAGE LOADS ====

    var OriginalGetContext = HTMLCanvasElement.prototype.getContext;
    var OriginalFill = CanvasRenderingContext2D.prototype.fill;
    var OriginalStroke = CanvasRenderingContext2D.prototype.stroke;
    var OriginalFillRect = CanvasRenderingContext2D.prototype.fillRect;
    var OriginalFillText = CanvasRenderingContext2D.prototype.fillText;

    var trackedContexts = new WeakMap();

    function getShadowSettings() {
        if (!settings.enableShadow) {
            return {
                shadowBlur: 0,
                shadowColor: 'rgba(0,0,0,0)',
                shadowOffsetX: 0,
                shadowOffsetY: 0
            };
        }
        return {
            shadowBlur: settings.shadowBlur,
            shadowColor: settings.shadowColor
                .replace('rgb(', 'rgba(')
                .replace(')', ',' + settings.shadowStrength + ')'),
            shadowOffsetX: settings.shadowOffsetX,
            shadowOffsetY: settings.shadowOffsetY
        };
    }

    function applyShadow(ctx) {
        var shadow = getShadowSettings();
        ctx.shadowBlur = shadow.shadowBlur;
        ctx.shadowColor = shadow.shadowColor;
        ctx.shadowOffsetX = shadow.shadowOffsetX;
        ctx.shadowOffsetY = shadow.shadowOffsetY;
    }

    function removeShadow(ctx) {
        ctx.shadowBlur = 0;
        ctx.shadowColor = 'rgba(0,0,0,0)';
        ctx.shadowOffsetX = 0;
        ctx.shadowOffsetY = 0;
    }

    // Intercept getContext
    HTMLCanvasElement.prototype.getContext = function() {
        var ctx = OriginalGetContext.apply(this, arguments);

        if (ctx && arguments[0] === '2d' && !trackedContexts.has(ctx)) {
            trackedContexts.set(ctx, true);
            console.log('DiepShadow: New 2D context detected');
        }

        return ctx;
    };

    // Only apply shadow to fill operations (not strokes)
    CanvasRenderingContext2D.prototype.fill = function() {
        applyShadow(this);
        var result = OriginalFill.apply(this, arguments);
        removeShadow(this);
        return result;
    };

    CanvasRenderingContext2D.prototype.fillRect = function() {
        applyShadow(this);
        var result = OriginalFillRect.apply(this, arguments);
        removeShadow(this);
        return result;
    };

    CanvasRenderingContext2D.prototype.fillText = function() {
        applyShadow(this);
        var result = OriginalFillText.apply(this, arguments);
        removeShadow(this);
        return result;
    };

    // Make sure stroke operations DON'T have shadow
    CanvasRenderingContext2D.prototype.stroke = function() {
        removeShadow(this);
        return OriginalStroke.apply(this, arguments);
    };

    console.log('DiepShadow: Canvas hooks installed at document-start');

    // ==== UI SETUP (runs when DOM is ready) ====

    function initUI() {
        var wrapper = document.createElement('div');
        wrapper.style.position = 'fixed';
        wrapper.style.backgroundColor = '#a3bfce';
        wrapper.style.padding = '10px';
        wrapper.style.top = '0px';
        wrapper.style.right = '0px';
        wrapper.style.bottom = '0px';
        wrapper.style.overflowY = 'auto';
        wrapper.style.overflowX = 'hidden';
        wrapper.style.fontFamily = 'Ubuntu';
        wrapper.style.display = 'none';
        wrapper.style.zIndex = '999999';
        wrapper.style.width = '460px';

        var checkbox_inputs = {};
        var addCheckboxInput = function(displayText, name) {
            checkbox_inputs[name] = document.createElement('input');
            var enableShadowLabel = document.createElement('label');
            var enableShadowText = document.createTextNode(displayText);
            checkbox_inputs[name].type = 'checkbox';
            checkbox_inputs[name].checked = settings[name];
            enableShadowLabel.style.display = 'block';
            enableShadowLabel.style.width = 'fit-content';
            enableShadowLabel.appendChild(checkbox_inputs[name]);
            enableShadowLabel.appendChild(enableShadowText);
            wrapper.appendChild(enableShadowLabel);

            checkbox_inputs[name].addEventListener('change', function() {
                settings[name] = checkbox_inputs[name].checked;
                saveSettings(true);
                console.log('DiepShadow: Setting changed -', name, '=', settings[name]);
            });
        };
        var sliders = {};
        var addSliderInput = function(displayText, name, min, max, step) {
            var slider = document.createElement('input');
            slider.type = 'range';
            slider.style.verticalAlign = 'middle';
            slider.style.width = '250px';
            slider.style.transform = 'none';
            slider.min = min;
            slider.max = max;
            slider.step = step;
            var label = document.createElement('label');
            var displayTextSpan = document.createElement('span');
            var displayValueSpan = document.createElement('span');
            label.style.display = 'block';
            label.style.width = 'fit-content';

            displayTextSpan.style.width = '140px';
            displayTextSpan.style.display = 'inline-block';
            displayTextSpan.textContent = displayText;

            displayValueSpan.style.width = '30px';
            displayValueSpan.style.display = 'inline-block';
            displayValueSpan.style.textAlign = 'center';

            label.appendChild(displayTextSpan);
            label.appendChild(displayValueSpan);
            label.appendChild(slider);
            wrapper.appendChild(label);

            sliders[name] = {
                addonchange: function(callback) {
                    var listener = function() {
                        displayValueSpan.textContent = slider.value;
                        callback(parseFloat(slider.value));
                    };
                    slider.addEventListener('change', listener);
                    slider.addEventListener('input', listener);
                },
                setValue: function(newValue) {
                    slider.value = newValue;
                    displayValueSpan.textContent = newValue;
                    slider.dispatchEvent(new window.Event('input', { bubbles: true }));
                }
            };
            sliders[name].setValue(settings[name]);
            sliders[name].addonchange(function(newValue) {
                settings[name] = newValue;
                saveSettings();
                console.log('DiepShadow: Setting changed -', name, '=', newValue);
            });
        };
        var colors = {};
        var addColorInput = function(displayText, name) {
            var colorInput = document.createElement('input');
            colorInput.type = 'color';
            colorInput.style.verticalAlign = 'middle';
            var label = document.createElement('label');
            var displayTextSpan = document.createElement('span');
            label.style.display = 'block';
            label.style.width = 'fit-content';

            displayTextSpan.style.width = '170px';
            displayTextSpan.style.display = 'inline-block';
            displayTextSpan.textContent = displayText;

            label.appendChild(displayTextSpan);
            label.appendChild(colorInput);
            wrapper.appendChild(label);

            colors[name] = {
                addonchange: function(callback) {
                    var listener = function() {
                        callback(hexToRgb(colorInput.value));
                    };
                    colorInput.addEventListener('change', listener);
                    colorInput.addEventListener('input', listener);
                },
                setValue: function(newValue) {
                    colorInput.value = newValue;
                    colorInput.dispatchEvent(new window.Event('input', { bubbles: true }));
                }
            };
            colors[name].setValue(rgbToHex(settings[name]));
            colors[name].addonchange(function(newValue) {
                settings[name] = newValue;
                saveSettings();
                console.log('DiepShadow: Color changed -', name, '=', newValue);
            });
        };
        var addPreset = function(eachPreset){
            var presetWrap = document.createElement('div');
            var name = document.createElement('p');
            var description = document.createElement('p');
            var demo_lighttheme = document.createElement('p');
            var demo_darktheme = document.createElement('p');
            var btn = document.createElement('p');

            presetWrap.style.marginTop = '20px';
            presetWrap.style.borderTop = '2px solid black';

            name.textContent = 'Preset name: ' + eachPreset.name;
            name.style.width = '440px';
            name.style.margin = '5px 0px';

            description.textContent = 'Preset description: ' + eachPreset.description;
            description.style.width = '440px';
            description.style.margin = '5px 0px';

            var applyThemeToDemo = function(element){
                element.style.textShadow =
                    eachPreset.shadowOffsetX + 'px ' +
                    eachPreset.shadowOffsetY + 'px ' +
                    eachPreset.shadowBlur + 'px ' +
                    eachPreset.shadowColor.replace('rgb(', 'rgba(').replace(')', ',' + eachPreset.shadowStrength + ')');
                element.style.padding = '0px 20px 5px 7px';
                element.style.display = 'inline-block';
                element.style.borderRadius = '8px';
                element.style.margin = '0px';
                element.style.fontSize = '40px';
                element.style.webkitTextStrokeWidth = '3px';
            };

            applyThemeToDemo(demo_lighttheme);
            demo_lighttheme.textContent = '\u2B24';
            demo_lighttheme.style.backgroundColor = '#cdcdcd';
            demo_lighttheme.style.webkitTextStrokeColor = '#0084a6';
            demo_lighttheme.style.color = '#00b1de';

            applyThemeToDemo(demo_darktheme);
            demo_darktheme.textContent = '\u2B24';
            demo_darktheme.style.backgroundColor = 'black';
            demo_darktheme.style.webkitTextStrokeColor = '#0084a6';
            demo_darktheme.style.color = 'black';
            demo_darktheme.style.marginLeft = '5px';

            btn.style.marginTop = '5px';
            btn.style.width = 'fit-content';
            btn.style.cursor = 'pointer';
            btn.style.color = '#004981';
            btn.textContent = 'Load preset';

            presetWrap.appendChild(name);
            presetWrap.appendChild(description);
            presetWrap.appendChild(demo_lighttheme);
            presetWrap.appendChild(demo_darktheme);
            presetWrap.appendChild(btn);

            wrapper.appendChild(presetWrap);

            btn.addEventListener('click', function() {
                sliders['shadowBlur'].setValue(eachPreset.shadowBlur);
                sliders['shadowOffsetX'].setValue(eachPreset.shadowOffsetX);
                sliders['shadowOffsetY'].setValue(eachPreset.shadowOffsetY);
                sliders['shadowStrength'].setValue(eachPreset.shadowStrength);
                colors['shadowColor'].setValue(rgbToHex(eachPreset.shadowColor));
                saveSettings();
            });
        };
        var addSeparator = function(height, parentElement = wrapper) {
            var separator = document.createElement('div');
            separator.style.height = height + 'px';
            parentElement.appendChild(separator);
        };

        var versionHeader = document.createElement('p');
        versionHeader.style.margin = '0px';
        versionHeader.style.fontSize = '12px';
        versionHeader.style.position = 'absolute';
        versionHeader.style.right = '10px';
        versionHeader.textContent = 'Version: ' + version;
        wrapper.appendChild(versionHeader);

        var hotkeyTip = document.createElement('p');
        hotkeyTip.style.margin = '0px';
        hotkeyTip.style.fontSize = '12px';
        hotkeyTip.style.position = 'absolute';
        hotkeyTip.textContent = 'Press CTRL + i to activate';
        wrapper.appendChild(hotkeyTip);

        var heading = document.createElement('h1');
        heading.textContent = 'DiepShadow';
        heading.style.filter = 'drop-shadow(5px 0px 2px black)';
        heading.style.color = 'white';
        wrapper.appendChild(heading);

        var warning = document.createElement('p');
        warning.style.color = '#bb1e1e';
        warning.appendChild(document.createTextNode('Warning: canvas\'s shadowBlur function is very CPU heavy.'));
        addSeparator(0, warning);
        warning.appendChild(document.createTextNode('Do not use if your computer is a turtle'));
        wrapper.appendChild(warning);

        var statusText = document.createElement('p');
        statusText.style.color = '#00aa00';
        statusText.style.fontWeight = 'bold';
        statusText.textContent = '✓ Shadow on fills only (v4)';
        wrapper.appendChild(statusText);

        addCheckboxInput('Enable DiepShadow', 'enableShadow');
        addCheckboxInput('Enable saving', 'enableSaving');

        addSeparator(16);

        addSliderInput('Shadow Radius: ', 'shadowBlur', 0, 200, 1);
        addSliderInput('Shadow X Offset: ', 'shadowOffsetX', -50, 50, 1);
        addSliderInput('Shadow Y Offset: ', 'shadowOffsetY', -50, 50, 1);
        addSliderInput('Shadow Strength: ', 'shadowStrength', 0, 1, 0.01);
        addColorInput('Shadow Color: ', 'shadowColor');

        var darkDemoNotice = document.createElement('p');
        darkDemoNotice.textContent = 'Note: Dark mode colors are taken from Diep.Style';
        wrapper.appendChild(darkDemoNotice);

        presets.forEach(addPreset);

        document.body.appendChild(wrapper);

        var isDisplaying = false;
        document.addEventListener('keydown', function(event) {
            if (!hotkey_activate_sequence(event)) return;
            if (isDisplaying) {
                isDisplaying = false;
                wrapper.style.display = 'none';
            }
            else {
                isDisplaying = true;
                wrapper.style.display = 'block';
            }
        });

        console.log('DiepShadow: UI initialized');
    }

    function saveSettings(bypass) {
        if (!settings.enableSaving && !bypass) return;
        window.localStorage.setItem(localStorage_key, JSON.stringify(settings));
    }

    // Helper functions
    function hexToRgb(hex) {
        var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return `rgb(${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt(result[3], 16)})`;
    }

    function componentToHex(c) {
        var hex = parseInt(c).toString(16);
        return hex.length == 1 ? "0" + hex : hex;
    }

    function rgbToHex(rgb) {
        var rgbsplit = rgb.split('rgb(')[1].replace(')', '').split(',');
        return "#" + componentToHex(rgbsplit[0]) + componentToHex(rgbsplit[1]) + componentToHex(rgbsplit[2]);
    }

    // Initialize UI when DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initUI);
    } else {
        initUI();
    }

    console.log('DiepShadow v' + version + ' loaded successfully!');
    console.log('Current settings:', settings);
})();