Greasy Fork

Hammer Senpa.io Mod - Enhanced UI & Fast Mode

Tweaks Senpa.io UI: draggable mod box, fast mode, visual enhancements, help menu

目前为 2025-04-21 提交的版本。查看 最新版本

// ==UserScript==
// @name         Hammer Senpa.io Mod - Enhanced UI & Fast Mode
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  Tweaks Senpa.io UI: draggable mod box, fast mode, visual enhancements, help menu
// @author       Hammer
// @match        https://senpa.io/*
// @grant        GM_addStyle
// ==/UserScript==

(function () {
    'use strict';

    const localStorageKey = 'modBoxPosition';
    let optimizationEnabled = true;
    let fxOn = true;
    let isFrozen = false;
    let fastMode = false;

    function savePosition(x, y) {
        localStorage.setItem(localStorageKey, JSON.stringify({ x, y }));
    }

    function loadPosition() {
        const pos = localStorage.getItem(localStorageKey);
        return pos ? JSON.parse(pos) : null;
    }

    const smallGui = document.createElement('div');
    smallGui.id = 'small-gui';
    Object.assign(smallGui.style, {
        position: 'fixed',
        width: '70px',
        height: '50px',
        backgroundColor: 'rgba(0, 0, 0, 0.7)',
        color: 'white',
        textAlign: 'center',
        fontSize: '14px',
        borderRadius: '5px',
        cursor: 'grab',
        zIndex: '9999',
        border: '2px solid red',
        transition: 'top 0.3s ease, left 0.3s ease'
    });
    smallGui.innerText = 'Mods';
    document.body.appendChild(smallGui);

    const helpBox = document.createElement('div');
    helpBox.innerText = `
Mod Features:
✔ FPS Optimization: Hides backgrounds, ads, & animations
✔ FX Toggle: Adds visual contrast for better vision
✔ Freeze on Death: Prevents respawn inputs for 3 seconds
✔ Fast Mode: Removes unnecessary UI but allows respawn
✔ Draggable GUI: Move and place mod menu where you like
`;
    Object.assign(helpBox.style, {
        backgroundColor: '#fff',
        color: '#000',
        padding: '10px',
        borderRadius: '8px',
        fontSize: '12px',
        marginTop: '10px',
        display: 'none',
        whiteSpace: 'pre-wrap'
    });

    const guiContainer = document.createElement('div');
    guiContainer.id = 'gui-container';
    Object.assign(guiContainer.style, {
        position: 'fixed',
        width: '250px',
        backgroundColor: 'rgba(0, 0, 0, 0.85)',
        color: 'white',
        padding: '20px',
        borderRadius: '10px',
        zIndex: '9999',
        display: 'none',
        fontFamily: 'Arial, sans-serif',
        border: '2px solid red',
        transition: 'top 0.3s ease, left 0.3s ease'
    });

    const closeButton = document.createElement('button');
    closeButton.innerText = 'X';
    Object.assign(closeButton.style, {
        backgroundColor: '#dc3545',
        color: 'white',
        border: 'none',
        padding: '5px',
        borderRadius: '50%',
        cursor: 'pointer',
        position: 'absolute',
        top: '10px',
        right: '10px'
    });
    closeButton.onclick = () => {
        guiContainer.style.display = 'none';
        helpBox.style.display = 'none';
    };

    function createToggleButton(textOn, textOff, initial, callback) {
        const btn = document.createElement('button');
        btn.innerText = initial ? textOff : textOn;
        btn.style.backgroundColor = initial ? '#28a745' : '#dc3545';
        btn.style.color = 'white';
        btn.style.border = 'none';
        btn.style.padding = '10px';
        btn.style.borderRadius = '5px';
        btn.style.cursor = 'pointer';
        btn.style.marginBottom = '10px';
        btn.style.width = '100%';
        btn.addEventListener('click', () => {
            const state = callback();
            btn.innerText = state ? textOff : textOn;
            btn.style.backgroundColor = state ? '#28a745' : '#dc3545';
        });
        return btn;
    }

    function enableOptimization() {
        document.querySelectorAll('.ad, .sidebar, .popup').forEach(e => e.remove());
        document.body.style.backgroundImage = 'none';
        document.querySelectorAll('img').forEach(img => img.src = '');
        const style = document.createElement('style');
        style.innerHTML = `
            * {
                animation: none !important;
                transition: none !important;
                box-shadow: none !important;
            }
            canvas {
                image-rendering: optimizeSpeed;
                will-change: transform;
            }
            body, html {
                background: #000 !important;
                overflow: hidden;
                margin: 0;
                padding: 0;
            }
        `;
        document.head.appendChild(style);
        document.querySelectorAll('audio').forEach(a => a.pause());
    }

    function disableOptimization() {
        const style = document.createElement('style');
        style.innerHTML = `
            * {
                animation: initial !important;
                transition: initial !important;
            }
        `;
        document.head.appendChild(style);
    }

    function applyVisualEffects() {
        const canvas = document.querySelector('canvas');
        if (canvas) {
            canvas.style.filter = fxOn ? 'brightness(1.1) contrast(1.2) saturate(1.1)' : 'none';
        }
    }

    function freezeOnDeath() {
        if (!isFrozen) return;
        const prevent = e => e.preventDefault();
        document.addEventListener('keydown', prevent);
        document.addEventListener('mousemove', prevent);
        document.addEventListener('mousedown', prevent);
        setTimeout(() => {
            document.removeEventListener('keydown', prevent);
            document.removeEventListener('mousemove', prevent);
            document.removeEventListener('mousedown', prevent);
        }, 3000);
    }

    function enableFastMode() {
        document.querySelectorAll('img, .ad, .sidebar, .middle, .popup, .footer, .header, .menu, .info').forEach(e => e.remove());
    }

    guiContainer.appendChild(closeButton);
    guiContainer.appendChild(createToggleButton('Enable FPS Optimization', 'Disable FPS Optimization', optimizationEnabled, () => {
        optimizationEnabled = !optimizationEnabled;
        optimizationEnabled ? enableOptimization() : disableOptimization();
        return optimizationEnabled;
    }));
    guiContainer.appendChild(createToggleButton('Enable FX', 'Disable FX', fxOn, () => {
        fxOn = !fxOn;
        applyVisualEffects();
        return fxOn;
    }));
    guiContainer.appendChild(createToggleButton('Freeze on Death', 'Unfreeze on Death', isFrozen, () => {
        isFrozen = !isFrozen;
        return isFrozen;
    }));
    guiContainer.appendChild(createToggleButton('Enable Fast Mode', 'Disable Fast Mode', fastMode, () => {
        fastMode = !fastMode;
        if (fastMode) enableFastMode();
        return fastMode;
    }));

    const helpBtn = document.createElement('button');
    helpBtn.innerText = 'Help';
    Object.assign(helpBtn.style, {
        backgroundColor: '#ffffff',
        color: '#000',
        padding: '10px',
        borderRadius: '5px',
        cursor: 'pointer',
        marginTop: '10px',
        width: '100%'
    });
    helpBtn.onclick = () => helpBox.style.display = helpBox.style.display === 'none' ? 'block' : 'none';
    guiContainer.appendChild(helpBtn);
    guiContainer.appendChild(helpBox);
    document.body.appendChild(guiContainer);

    smallGui.addEventListener('click', () => {
        const isHidden = guiContainer.style.display === 'none';
        guiContainer.style.display = isHidden ? 'block' : 'none';
        helpBox.style.display = 'none';
    });

    // Load saved position or default to bottom right
    const saved = loadPosition();
    if (saved) {
        smallGui.style.top = saved.y + 'px';
        smallGui.style.left = saved.x + 'px';
        guiContainer.style.top = saved.y + 60 + 'px';
        guiContainer.style.left = saved.x + 'px';
    } else {
        smallGui.style.bottom = '20px';
        smallGui.style.right = '20px';
    }

    // Draggable
    let dragging = false, offsetX, offsetY;
    smallGui.addEventListener('mousedown', (e) => {
        dragging = true;
        offsetX = e.clientX - smallGui.offsetLeft;
        offsetY = e.clientY - smallGui.offsetTop;
        smallGui.style.cursor = 'grabbing';
    });

    document.addEventListener('mousemove', (e) => {
        if (!dragging) return;
        const x = e.clientX - offsetX;
        const y = e.clientY - offsetY;
        smallGui.style.left = x + 'px';
        smallGui.style.top = y + 'px';
        smallGui.style.right = 'auto';
        smallGui.style.bottom = 'auto';
        guiContainer.style.left = x + 'px';
        guiContainer.style.top = y + 60 + 'px';
    });

    document.addEventListener('mouseup', () => {
        if (dragging) {
            savePosition(parseInt(smallGui.style.left), parseInt(smallGui.style.top));
        }
        dragging = false;
        smallGui.style.cursor = 'grab';
    });

    const observer = new MutationObserver(() => {
        const middleAd = document.querySelector('.middle, .middle-panel, .ad-middle');
        if (middleAd) middleAd.remove();

        const inGame = document.querySelector('.player');
        if (inGame) {
            const savedPos = loadPosition();
            if (!savedPos) {
                smallGui.style.bottom = '20px';
                smallGui.style.right = '20px';
                guiContainer.style.bottom = '80px';
                guiContainer.style.right = '20px';
            }
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });

    setInterval(() => {
        const dead = document.querySelector('.dead');
        if (dead && isFrozen) freezeOnDeath();
    }, 1000);

    if (optimizationEnabled) enableOptimization();
    if (fxOn) applyVisualEffects();
})();