Greasy Fork

Greasy Fork is available in English.

DiepBox by Cazka

made with much love

当前为 2021-03-29 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         DiepBox by Cazka
// @description  made with much love
// @version      0.1.3
// @author       Cazka#1820
// @match        *://diep.io/*
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addValueChangeListener
// @grant        GM_removeValueChangeListener
// @namespace http://greasyfork.icu/users/541070
// ==/UserScript==
'use strict';

/*
 * Feel free to use some of my code for your own multiboxing script. make sure to give credits!
 */
/*
 *   C L A S S E S
 */
class Gui {
    constructor(title) {
        this._colors = ['#E8B18A', '#E666EA', '#9566EA', '#6690EA', '#E7D063', '#EA6666', '#92EA66', '#66EAE6'];
        this._buttons = [];
        this._notifications = [];

        this._title = title;
        this._gui;
        this._guiHead;
        this._guiBody;

        this._init();
        this._enableShortcuts();
    }
    _init() {
        const nonce = `a${Math.floor(Math.random() * 1e5)}`;;
        GM_addStyle(`.${nonce} button{display:block;font-family:Ubuntu;color:#fff;text-shadow:-.1em -.1em 0 #000,0 -.1em 0 #000,.1em -.1em 0 #000,.1em 0 0 #000,.1em .1em 0 #000,0 .1em 0 #000,-.1em .1em 0 #000,-.1em 0 0 #000;opacity:.8;border:0;padding:.3em .5em;width:100%;transition:all .15s}.${nonce}{top:0;left:0;position:absolute}.${nonce} button:active:not([disabled]){filter:brightness(.9)}.${nonce} button:hover:not([disabled]):not(:active){filter:brightness(1.1)}`);

        this._gui = document.createElement('div');
        this._guiHead = document.createElement('div');
        this._guiBody = document.createElement('div');

        this._gui.className = `${nonce}`;
        this._guiBody.style.display = 'block';

        document.body.appendChild(this._gui);
        this._gui.appendChild(this._guiHead);
        this._gui.appendChild(this._guiBody);

        this._addButton(this._guiHead, this._title, () => {
            if (this._guiBody.style.display === 'block') {
                this._guiBody.style.display = 'none';
            } else {
                this._guiBody.style.display = 'block';
            }
        });
    }

    addButton(text, onclick, keyCode) {
        return this._addButton(this._guiBody, text, onclick, keyCode);
    }
    removeButton(button) {
        const index = this._buttons.findIndex((x) => x === button);
        if (index == -1) return;

        this._buttons.splice(index, 1);

        button.remove();
        button.active = false;
    }
    reset() {
        const head = this._buttons[0];
        this._buttons.forEach((x, i) => {
            if (i === 0) return;
            this.removeButton(x);
        });
        this._buttons = [head];
    }

    _addButton(parent, text, onclick, keyCode) {
        const button = document.createElement('button');
        button.innerHTML = text;
        button.keyCode = keyCode;
        button.onclick = onclick;
        button.style['background-color'] = this._colors[this._buttons.length % this._colors.length];

        parent.appendChild(button);
        this._buttons.push(button);
        return button;
    }
    _enableShortcuts() {
        document.addEventListener('keydown', (event) => {
            if (document.getElementById('textInputContainer').style.display === 'block') return;
            this._buttons.forEach((button) => {
                if (button.keyCode === event.code) button.onclick();
            });
        });
    }
}
class Minimap {
    constructor() {
        this._minimapWidth;
        this._minimapHeight;
        this._x00;
        this._y00;
        this._pointX;
        this._pointY;
        this._pointX_previous;
        this._pointY_previous;
        this._viewportWidth;
        this._viewportHeight;

        this._minimapHook();
        this._arrowHook();
        this._viewportHook();
    }
    get x() {
        return +((this._pointX - this._x00) / this._minimapWidth).toFixed(6);
    }
    get y() {
        return +((this._pointY - this._y00) / this._minimapHeight).toFixed(6);
    }
    get x_previous() {
        return +((this._pointX_previous - this._x00) / this._minimapWidth).toFixed(6);
    }
    get y_previous() {
        return +((this._pointY_previous - this._y00) / this._minimapHeight).toFixed(6);
    }
    get scale() {
        return {
            x: this._viewportWidth / this._minimapWidth,
            y: this._viewportHeight / this._minimapHeight,
        };
    }

    _minimapHook() {
        let setTransformArgs;

        const onsetTransform = (args) => {
            if (args[0] === args[3]) setTransformArgs = args;
        };
        const onstrokeRect = () => {
            if (setTransformArgs) {
                this._minimapWidth = setTransformArgs[0];
                this._minimapHeight = setTransformArgs[3];
                this._x00 = setTransformArgs[4];
                this._y00 = setTransformArgs[5];
                setTransformArgs = undefined;
            }
        };
        this._ctxHook('setTransform', onsetTransform);
        this._ctxHook('strokeRect', onstrokeRect);
    }
    _arrowHook() {
        let index = 0;
        const stack = Array(4);

        let pointA;
        let pointB;
        let pointC;

        const calculatePos = () => {
            const side1 = Math.floor(Math.sqrt(Math.pow(pointA[0] - pointB[0], 2) + Math.pow(pointA[1] - pointB[1], 2)));
            const side2 = Math.floor(Math.sqrt(Math.pow(pointA[0] - pointC[0], 2) + Math.pow(pointA[1] - pointC[1], 2)));
            const side3 = Math.floor(Math.sqrt(Math.pow(pointB[0] - pointC[0], 2) + Math.pow(pointB[1] - pointC[1], 2)));
            if (side1 == side2 && side2 == side3) return;

            this._pointX_previous = this._pointX;
            this._pointY_previous = this._pointY;

            this._pointX = (pointA[0] + pointB[0] + pointC[0]) / 3;
            this._pointY = (pointA[1] + pointB[1] + pointC[1]) / 3;
        };
        const onbeginPath = () => {
            index = 0;
            stack[index++] = 0;
        };
        const onmoveTo = (args) => {
            if (index === 1 && stack[index - 1] === 0) {
                stack[index++] = 1;
                pointA = args;
                return;
            }
            index = 0;
        };
        const onlineTo = (args) => {
            if (index === 2 && stack[index - 1] === 1) {
                stack[index++] = 2;
                pointB = args;
                return;
            }
            if (index === 3 && stack[index - 1] === 2) {
                stack[index++] = 2;
                pointC = args;
                return;
            }
            index = 0;
        };
        const onfill = () => {
            if (index === 4 && stack[index - 1] === 2) {
                calculatePos();
                return;
            }
            index = 0;
        };

        this._ctxHook('beginPath', onbeginPath);
        this._ctxHook('moveTo', onmoveTo);
        this._ctxHook('lineTo', onlineTo);
        this._ctxHook('fill', onfill);
    }
    _viewportHook() {
        let setTransformArgs;

        const onsetTransform = (args) => {
            if ((args[0] / args[3]).toFixed(4) !== (unsafeWindow.innerWidth / unsafeWindow.innerHeight).toFixed(4)) return;
            if (args[0] >= unsafeWindow.innerWidth && args[3] >= unsafeWindow.innerHeight) return;

            setTransformArgs = args;
        };
        const onfillRect = () => {
            if (setTransformArgs) {
                unsafeWindow.input.execute('ren_minimap_viewport false');
                this._viewportWidth = setTransformArgs[0];
                this._viewportHeight = setTransformArgs[3];
                setTransformArgs = undefined;
            }
        };

        this._ctxHook('setTransform', onsetTransform);
        this._ctxHook('fillRect', onfillRect);

        setTimeout(() => unsafeWindow.input.execute('ren_minimap_viewport true'), 1000);
        setInterval(() => {
            unsafeWindow.input.execute('ren_minimap_viewport true');
        }, 10000);
    }
    _ctxHook(method, callback) {
        const target = window.CanvasRenderingContext2D.prototype;
        target[method] = new Proxy(target[method], {
            apply(target, thisArg, args) {
                callback(args);
                return target.apply(thisArg, args);
            },
        });
    }
}
class DiepGamepad {
    constructor() {
        this._axes = [0, 0, 0, 0];
        this._buttons = [...Array(17)].map((x) => {
            return { pressed: false };
        });
    }

    set x(value) {
        this._axes[0] = value;
    }
    set y(value) {
        this._axes[1] = value;
    }
    set mx(value) {
        this._axes[2] = value;
    }
    set my(value) {
        this._axes[3] = value;
    }
    set leftMouse(value) {
        this._buttons[7].pressed = value;
    }
    set rightMouse(value) {
        this._buttons[5].pressed = value;
    }
    set connected(value) {
        unsafeWindow.navigator.getGamepads = () => [value ? this.toGamepad() : undefined];
    }

    get x() {
        return this._axes[0];
    }
    get y() {
        return this._axes[1];
    }
    get mx() {
        return this._axes[2];
    }
    get my() {
        return this._axes[3];
    }
    get leftMouse() {
        return this._buttons[7].pressed;
    }
    get rightMouse() {
        return this._buttons[5].pressed;
    }
    get connected() {
        return unsafeWindow.navigator.getGamepads()[0] ? true : false;
    }

    toGamepad() {
        return {
            axes: this._axes,
            buttons: this._buttons,
            mapping: 'standard',
        };
    }
}
class Vector {
    static length({ x, y }) {
        return Math.sqrt(x ** 2 + y ** 2);
    }
}
class Player {
    constructor() {
        this._minimap = new Minimap();
        this._gamepad = new DiepGamepad();

        this._mouse = {
            x: 0,
            y: 0,
        };

        unsafeWindow.addEventListener('mousemove', (e) => this._onmousemove(e));
        unsafeWindow.addEventListener('mousedown', (e) => this._onmousedown(e));
        unsafeWindow.addEventListener('mouseup', (e) => this._onmouseup(e));
        unsafeWindow.addEventListener('keydown', (e) => this._onkeydown(e));
        unsafeWindow.addEventListener('keyup', (e) => this._onkeyup(e));
    }

    set useGamepad(value) {
        this._gamepad.connected = value;
    }

    get position() {
        return {
            x: this._minimap.x,
            y: this._minimap.y,
            x_previous: this._minimap.x_previous,
            y_previous: this._minimap.y_previous,
        }
    }
    get mouse() {
        return this.toArenaPos(this._mouse.x, this._mouse.y);
    }

    toScreenPos(x, y) {
        const position = this.position;
        const scale = this._minimap.scale;

        x -= position.x;
        x /= scale.x;
        x += 0.5;
        x *= unsafeWindow.innerWidth;

        y -= position.y;
        y /= scale.y;
        y += 0.5;
        y *= unsafeWindow.innerHeight;

        return { x, y };
    }
    toArenaPos(x, y) {
        const position = this.position;
        const scale = this._minimap.scale;

        x /= unsafeWindow.innerWidth;
        x -= 0.5;
        x *= scale.x;
        x += position.x;

        y /= unsafeWindow.innerHeight;
        y -= 0.5;
        y *= scale.y;
        y += position.y;

        return { x, y }
    }
    moveTo(x, y) {
        const position = this.position;
        if (!position.x || !position.y) return;

        const deltaX = x - position.x;
        const deltaY = y - position.y;
        const length = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));

        if (length === 0) {
            this._gamepad.x = 0;
            this._gamepad.y = 0;
            return;
        }

        x = deltaX / length;
        y = deltaY / length;

        this._gamepad.x = x;
        this._gamepad.y = y;
    }
    lookAt(x, y) {
        const position = this.position;
        if (!position.x || !position.y) return;

        const deltaX = x - position.x;
        const deltaY = y - position.y;
        const length = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));

        x = deltaX * 1.05;
        y = deltaY * 1.05;

        if (length < 0.1) {
            x /= length * 9;
            y /= length * 9;
        }

        this._gamepad.mx = x;
        this._gamepad.my = y;
    }
    findBestPos(targetPosition) {
        const TOLERANCE = 0.009;
        //Strategies:
        //(1) Dont move to target if to close
        //(2) copy movement vector if to close
        //(3) predict future position
        //(4) make way when target moves to my direction?
        const me = this.position;
        const target = {
            x: targetPosition.x,
            y: targetPosition.y,
            x_previous: targetPosition.x_previous,
            y_previous: targetPosition.y_previous,
        }

        const meVector = {
            x: me.x - me.x_previous,
            y: me.y - me.y_previous
        }
        const targetVector = {
            x: target.x - target.x_previous,
            y: target.y - target.y_previous
        }
        const directionVector = {
            x: target.x - me.x,
            y: target.y - me.y
        }

        if (Vector.length(directionVector) < TOLERANCE) {
            // (2)
            me.x += targetVector.x;
            me.y += targetVector.y;
            return me;
        }

        // (3)
        target.x += targetVector.x * 25;
        target.y += targetVector.y * 25;

        return target;
    }
    _onmousemove(e) {
        this._mouse.x = e.clientX;
        this._mouse.y = e.clientY;
    }
    _onmousedown(e) {
        this.onkeyDown && this.onkeyDown(e.which);
    }
    _onmouseup(e) {
        this.onkeyUp && this.onkeyUp(e.which);
    }
    _onkeydown(e) {
        this.onkeyDown && this.onkeyDown(e.keyCode);
    }
    _onkeyup(e) {
        this.onkeyUp && this.onkeyUp(e.keyCode);
    }
}
class MultiboxStorage {
    /*
     * items in storage:
     * position: [x,y,x_previous, y_previous]
     * mouse: [x,y]
     * mutex: boolean
     * multibox: boolean
     * keyDown: Number
     * keyUp: Number
     * clumpMode: String
     */
    constructor() {
        //if the user launches this script for the first time
        try {
            this.position;
            this.mouse;
            this.multibox;
            this.mutex;
            this.keyDown;
            this.keyUp;
            this.clumpMode;
        } catch (err) {
            console.log('DiepBox Error: MultiboxStorage needs to be initialized');
            this.reset();
        }
    }

    set position(position) {
        GM_setValue('position', [
            position.x,
            position.y,
            position.x_previous,
            position.y_previous
        ]);
    }
    set mouse(mouse) {
        GM_setValue('mouse', [mouse.x, mouse.y]);
    }
    set mutex(mutex) {
        GM_setValue('mutex', mutex ? 1 : 0);
    }
    set multibox(multibox) {
        GM_setValue('multibox', multibox ? 1 : 0);
    }
    set keyDown(key) {
        GM_setValue('keyDown', key);
    }
    set keyUp(key) {
        GM_setValue('keyUp', key);
    }
    set clumpMode(mode) {
        let m = 0;
        switch (mode) {
            case 'player':
                m = 1;
                break;
            case 'mouse':
                m = 2;
                break;
            default:
                throw new Error('unsupported clump mode', mode);
        }
        if (m) GM_setValue('clumpMode', m);
    }

    get position() {
        const position = GM_getValue('position');
        return {
            x: position[0],
            y: position[1],
            x_previous: position[2],
            y_previous: position[3],
        }
    }
    get mouse() {
        const mouse = GM_getValue('mouse');
        return {
            x: mouse[0],
            y: mouse[1],
        }
    }
    get mutex() {
        const mutex = GM_getValue('mutex');
        return mutex === 1 ? true : false;
    }
    get multibox() {
        const multibox = GM_getValue('multibox');
        return multibox === 1 ? true : false;
    }
    get keyDown() {
        return GM_getValue('keyDown');
    }
    get keyUp() {
        return GM_getValue('keyUp');
    }
    get clumpMode() {
        const m = GM_getValue('clumpMode');
        let mode = '';
        switch (m) {
            case 1:
                mode = 'player';
                break;
            case 2:
                mode = 'mouse';
                break;
            default:
                throw new Error('unsupported clump mode', m);
        }
        return mode;
    }


    reset() {
        this.position = { x: 0, y: 0, x_previous: 0, y_previous: 0 };
        this.mouse = { x: 0, y: 0 };
        this.mutex = false;
        this.multibox = false;
        this.keyDown = -1;
        this.keyUp = -1;
        this.clumpMode = 'tank';
    }
    on(name, cb) {
        return GM_addValueChangeListener(name, cb);
    }
    once(name, cb) {
        const id = GM_addValueChangeListener(name, (...args) => {
            cb(...args);
            this.off(id);
        });
    }
    off(id) {
        GM_removeValueChangeListener(id);
    }
}
/*
 *   D E B U G G E R
 */
const DEBUG = false;
const debugger_mouse = document.body.appendChild(document.createElement('div'));
function DEBUG_MousePosition(x, y) {
    if (!DEBUG) return;
    debugger_mouse.style.pointerEvents = 'none';
    debugger_mouse.style.position = 'absolute';
    debugger_mouse.style.zIndex = '99999';
    debugger_mouse.style.left = `${x - 5}px`;
    debugger_mouse.style.top = `${y - 2}px`;
    debugger_mouse.innerText = '👆';
}
const debugger_pos = document.body.appendChild(document.createElement('div'));
const debugger_pos_prediction = document.body.appendChild(document.createElement('div'));
function DEBUG_PlayerPosition(x = -100, y = -100, x_prediction = -100, y_prediction = -100) {
    if (!DEBUG) return;
    debugger_pos.style.pointerEvents = 'none';
    debugger_pos.style.position = 'absolute';
    debugger_pos.style.zIndex = '99999';
    debugger_pos.style.left = `${x - 11}px`;
    debugger_pos.style.top = `${y - 12}px`;
    debugger_pos.innerText = '🟢';

    debugger_pos_prediction.style.pointerEvents = 'none';
    debugger_pos_prediction.style.position = 'absolute';
    debugger_pos_prediction.style.zIndex = '99999';
    debugger_pos_prediction.style.left = `${x_prediction - 11}px`;
    debugger_pos_prediction.style.top = `${y_prediction - 12}px`;
    debugger_pos_prediction.innerText = '🔵';
}

/*
 *   H E L P E R   F U N C T I O N S
 */
function onbtnMultibox() {
    this.active = !this.active;
    if (this.active) {
        storage.multibox = true;
        this.innerHTML = 'Multiboxing: ON';
    } else {
        storage.multibox = false;
        this.innerHTML = 'Multiboxing: OFF';
    }
}
function onbtnToggleClump() {
    this.active = !this.active;
    if (this.active) {
        storage.clumpMode = 'mouse';
        this.innerHTML = 'Clump: Mouse';
    } else {
        storage.clumpMode = 'player';
        this.innerHTML = 'Clump: Player';
    }
}
function smallBoi() {
    player.isMaster = false;

    player.useGamepad = storage.multibox;
    const multiboxListener = storage.on('multibox', (name, old_value, new_value, remote) => {
        player.useGamepad = new_value;
    });

    const keyDownListener = storage.on('keyDown', (name, old_value, new_value, remote) => {
        if ([-1, 87, 65, 83, 68].includes(new_value)) return;

        if (DEBUG) console.log('master keyDown', new_value);

        if (storage.multibox) {
            if (new_value === 1) player._gamepad.leftMouse = true;
            else if (new_value === 3) player._gamepad.rightMouse = true;

            unsafeWindow.input.keyDown(new_value);
        }
    });
    const keyUpListener = storage.on('keyUp', (name, old_value, new_value, remote) => {
        if ([-1, 87, 65, 83, 68].includes(new_value)) return;

        if (DEBUG) console.log('master keyUp', new_value);

        if (storage.multibox) {
            if (new_value === 1) player._gamepad.leftMouse = false;
            else if (new_value === 3) player._gamepad.rightMouse = false;

            unsafeWindow.input.keyUp(new_value);
        }
    });

    btnForceMaster = gui.addButton('Unlock this tab', () => {
        storage.reset();
        storage.off(multiboxListener);
        storage.off(keyDownListener);
        storage.off(keyUpListener);

        gui.reset();

        bigBoi();
    });
}
function bigBoi() {
    player.isMaster = true;
    storage.mutex = true;
    storage.clumpMode = 'player';

    storage.once('mutex', (name, old_value, new_value, remote) => {
        if (!new_value) {
            gui.reset();

            smallBoi();
        }
    });

    btnMultibox = gui.addButton('Multiboxing: OFF', onbtnMultibox, 'KeyF');
    btnToggleClump = gui.addButton('Clump: Player', onbtnToggleClump);
}
function mainLoop() {
    if (!unsafeWindow.input) return;

    if (player.isMaster) {
        storage.position = player.position;
        storage.mouse = player.mouse;
    } else {
        const clumpMode = storage.clumpMode;
        const mouse = storage.mouse;
        let position;
        let bestPosition;

        if (clumpMode === 'player') {
            position = storage.position;
            bestPosition = player.findBestPos(position);
        } else if (clumpMode === 'mouse') {
            position = mouse;
            bestPosition = position;
        } else {
            throw new Error('Unsupported clumpMode', clumpMode);
        }

        if (storage.multibox) {
            player.moveTo(bestPosition.x, bestPosition.y);
            player.lookAt(mouse.x, mouse.y);
        }

        //Debugging
        const mouseScreen = player.toScreenPos(mouse.x, mouse.y);
        DEBUG_MousePosition(mouseScreen.x, mouseScreen.y);

        const playerScreen = player.toScreenPos(position.x, position.y);
        const bestPositionScreen = player.toScreenPos(bestPosition.x, bestPosition.y);
        DEBUG_PlayerPosition(playerScreen.x, playerScreen.y, bestPositionScreen.x, bestPositionScreen.y);
    }
}

/*
 *   M A I N
 */
const gui = new Gui('DiepBox by Cazka');
const player = new Player();
const storage = new MultiboxStorage();

let btnForceMaster;
let btnMultibox;
let btnToggleClump;

if (storage.mutex) smallBoi();
else bigBoi();

unsafeWindow.addEventListener('unload', () => {
    if (player.isMaster) {
        storage.reset();
    }
});

player.onkeyDown = key => {
    if (player.isMaster) {
        storage.keyDown = key;
        storage.keyDown = -1;
    }
}
player.onkeyUp = key => {
    if (player.isMaster) {
        storage.keyUp = key;
        storage.keyUp = -1;
    }
}

// run main Loop
unsafeWindow.requestAnimationFrame = new Proxy(unsafeWindow.requestAnimationFrame, {
    apply: function (target, thisArg, args) {
        mainLoop();
        return target.apply(thisArg, args);
    },
});