Greasy Fork

Greasy Fork is available in English.

DiepBox by Cazka

made with much love

当前为 2021-04-08 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         DiepBox by Cazka
// @description  made with much love
// @version      0.1.10
// @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;

        button.remove();
        button.active = false;

        this._buttons.splice(index, 1);
    }
    reset() {
        for (let i = 1, n = this._buttons.length; i < n; i++) {
            this.removeButton(this._buttons[1]);
        }
    }

    _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._fov;

        this._minimapHook();
        this._arrowHook();
        this._viewportHook();
        this._fovHook();
    }
    get x() {
        return this._pointX ? (this._pointX - this._x00) / this._minimapWidth : 0;
    }
    get y() {
        return this._pointY ? (this._pointY - this._y00) / this._minimapHeight : 0;
    }
    get x_previous() {
        return this._pointX_previous ? (this._pointX_previous - this._x00) / this._minimapWidth : 0;
    }
    get y_previous() {
        return this._pointY_previous ? (this._pointY_previous - this._y00) / this._minimapHeight : 0;
    }
    get scale() {
        return {
            x: this._viewportWidth / this._minimapWidth,
            y: this._viewportHeight / this._minimapHeight,
        };
    }
    get fov() {
        return this._fov;
    }

    _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);
    }
    _fovHook() {
        const calculateFov = (fov) => {
            this._fov = fov * 10;
        }
        function onstroke() {
            if (this.fillStyle === '#cdcdcd') {
                calculateFov(this.globalAlpha);
            }
        }
        this._ctxHook('stroke', onstroke)
    }
    _ctxHook(method, hook) {
        const target = window.CanvasRenderingContext2D.prototype;
        target[method] = new Proxy(target[method], {
            apply(target, thisArg, args) {
                args = hook.call(thisArg, args) || 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[6].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[6].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);
    }
    static add(u, v) {
        return {
            x: u.x + v.x,
            y: u.y + v.y,
        }
    }
    static subtract(u, v) {
        return {
            x: u.x - v.x,
            y: u.y - v.y
        }
    }
    static scale(r, v) {
        return {
            x: r * v.x,
            y: r * v.y,
        }
    }
    static dot(u, v) {
        return u.x * v.x + u.y * v.y;
    }
    static distance(u, v) {
        return Vector.length(Vector.subtract(u, v));
    }
    static distanceLine(a, n, p) {
        const r = Vector.dot(n, Vector.subtract(a, p)) / -Vector.dot(n, n);
        const point = Vector.add(a, Vector.scale(r, n));
        const distance = Vector.distance(point, p);
        return {
            r,
            point,
            distance,
        }
    }
}
class Arena {
    static get BLOCKSIZE() {
        return 50;
    }
    static scale(x, y) {
        return {
            x: Math.floor(22300 * (x - 0.5) + 0.5),
            y: Math.floor(22300 * (y - 0.5) + 0.5),
        }
    }
    static unscale(x, y) {
        return {
            x: (x / 22300) + 0.5,
            y: (y / 22300) + 0.5
        }
    }
}
class Player {
    constructor() {
        this._minimap = new Minimap();
        this._gamepad = new DiepGamepad();

        this._mouse = {
            x: 0,
            y: 0,
        };
        this._inputs = {
            left: false,
            down: false,
            up: false,
            right: false,
        }

        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() {
        const position = Arena.scale(this._minimap.x, this._minimap.y);
        const previous = Arena.scale(this._minimap.x_previous, this._minimap.y_previous);
        return {
            x: position.x,
            y: position.y,
            x_previous: previous.x,
            y_previous: previous.y,
        }
    }
    get mouse() {
        return this.toArenaPos(this._mouse.x, this._mouse.y);
    }

    get inputs() {
        return this._inputs;
    }

    toScreenPos(x, y) {
        const unscale = Arena.unscale(x, y);
        x = unscale.x;
        y = unscale.y;

        let position = this.position;
        position = Arena.unscale(position.x, position.y);
        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) {
        let position = this.position;
        position = Arena.unscale(position.x, position.y);
        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 Arena.scale(x, y);
    }
    moveTo(x, y) {
        const position = this.position;

        const deltaX = x - position.x;
        const deltaY = y - position.y;
        const length = Vector.length({ x: deltaX, y: deltaY });

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

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

        this._gamepad.x = x;
        this._gamepad.y = y;
    }
    lookAt(x, y) {
        const position = this.position;

        const a = window.innerHeight / 1080;
        const b = window.innerWidth / 1920;
        const c = (b < a) ? a : b;

        let x_axes = ((((x - position.x) / c) * this._minimap.fov) / 1200) / 1.1;
        let y_axes = ((((y - position.y) / c) * this._minimap.fov) / 1200) / 1.1;

        const length = Vector.length({ x: x_axes, y: y_axes });

        if (length != 0 && length < 0.1) {
            x_axes *= 0.11 / length;
            y_axes *= 0.11 / length;
        }

        this._gamepad.mx = x_axes;
        this._gamepad.my = y_axes;
    }
    findBestPos(targetPosition, inputs) {
        const TOLERANCE = 200;
        //Strategies:
        //(1) Dont move to target if to close [removed]
        //(2) copy movement vector if to close [removed]
        //(3) predict future position
        //(4) make way when target moves to my direction
        //(5) dont do (2). create new vector through player inputs instead. this makes better predictions.
        const me = this.position;
        const target = {
            x: targetPosition.x,
            y: targetPosition.y,
            x_previous: targetPosition.x_previous,
            y_previous: targetPosition.y_previous,
        }

        const distance = Vector.distance(me, target);

        const targetVector = Vector.subtract({ x: target.x, y: target.y }, { x: target.x_previous, y: target.y_previous });

        // (4)
        if (distance < 4 * TOLERANCE && Vector.length(targetVector) > 2) {
            const { r, point, distance } = Vector.distanceLine(target, targetVector, me);

            if (distance < 75 && r > 0) {
                return Vector.add(me, Vector.subtract(me, point));
            }
        }
        // (5)
        if (distance < TOLERANCE) {
            let x = inputs.left ? -1 : 0;
            x += inputs.right ? 1 : 0;
            let y = inputs.up ? -1 : 0;
            y += inputs.down ? 1 : 0;
            return Vector.add(me, { x, y });
        }

        // (3)
        return Vector.add(target, Vector.scale(50, targetVector));
    }
    _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) {
        switch (e.keyCode) {
            case 37:
            case 65:
                this._inputs.left = true;
                break;
            case 40:
            case 83:
                this._inputs.down = true;
                break;
            case 38:
            case 87:
                this._inputs.up = true;
                break;
            case 39:
            case 68:
                this._inputs.right = true;
                break;
        }

        this.onkeyDown && this.onkeyDown(e.keyCode);
    }
    _onkeyup(e) {
        switch (e.keyCode) {
            case 37:
            case 65:
                this._inputs.left = false;
                break;
            case 40:
            case 83:
                this._inputs.down = false;
                break;
            case 38:
            case 87:
                this._inputs.up = false;
                break;
            case 39:
            case 68:
                this._inputs.right = false;
                break;
        }

        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
    * inputs: [left, down, up, right]
    */
    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;
            this.inputs;
        } 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);
    }
    set inputs(inputs) {
        GM_setValue('inputs', [
            inputs.left,
            inputs.down,
            inputs.up,
            inputs.right,
        ]);
    }

    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;
    }
    get inputs() {
        const inputs = GM_getValue('inputs');
        return {
            left: inputs[0],
            down: inputs[1],
            up: inputs[2],
            right: inputs[3],
        }
    }

    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 = 'player';
        this.inputs = { left: false, down: false, up: false, right: false };
    }
    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 = true;
const debugger_mouse = document.body.appendChild(document.createElement('div'));
function DEBUG_MousePosition(x, y, info = '') {
    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 = '👆 ' + info;
}
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, info = '') {
    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 = '🟢 ' + info;

    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 = '🔵';
}
const debugger_safezone = document.body.appendChild(document.createElement('div'));
function DEBUG_Safezone(x = -100, y = -100, radius = 0, info = '') {
    if (!DEBUG) return;
    debugger_safezone.style.pointerEvents = 'none';
    debugger_safezone.style.position = 'absolute';
    debugger_safezone.style.zIndex = '99999';
    debugger_safezone.style.left = `${x - 11}px`;
    debugger_safezone.style.top = `${x - 12}px`;
    debugger_safezone.style.width = `${radius}px`;
    debugger_safezone.style.height = `${radius}px`;
    debugger_safezone.style['-webkit-border-radius'] = `${radius / 2}px`;
    debugger_safezone.style['-moz-border-radius'] = `${radius / 2}px`;
    debugger_safezone.style['border-radius'] = `${radius / 2}px`
    debugger_safezone.style.background = 'red';
    debugger_safezone.style.opacity = 0.3;
}
/*
*   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 onbtnAfk() {
    this.active = !this.active;
    if (this.active) {
        player.useGamepad = true;
        this.position = player.position;
        this.mouse = player.mouse;
        this.innerHTML = 'AFK: ON';
    } else {
        player.useGamepad = false;
        this.innerHTML = 'AFK: 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 onbtnDiscord() {
    window.open('https://discord.gg/5q2E3Sx');
}
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, 65, 83, 87, 68, 37, 40, 38, 39].includes(new_value)) return;

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

        if (storage.multibox) {
            if ([1, 32].includes(new_value)) player._gamepad.leftMouse = true;
            else if ([3, 16].includes(new_value)) player._gamepad.rightMouse = true;

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

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

        if (storage.multibox) {
            if ([1, 32].includes(new_value)) player._gamepad.leftMouse = false;
            else if ([3, 16].includes(new_value)) 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');
    btnAfk = gui.addButton('AFK: OFF', onbtnAfk, 'KeyQ');
    btnToggleClump = gui.addButton('Clump: Player', onbtnToggleClump);
    btnDiscord = gui.addButton('Discord', onbtnDiscord);
}
function mainLoop() {
    if (!unsafeWindow.input) return;

    if (player.isMaster) {
        storage.position = player.position;
        storage.inputs = player.inputs;

        if (!btnAfk.active) storage.mouse = player.mouse;

        if (btnAfk.active) {
            if (Vector.distance(btnAfk.position, player.position) > 50) {
                player.moveTo(btnAfk.position.x, btnAfk.position.y);
            } else {
                player.moveTo(player.position.x, player.position.y);
            }
            player.lookAt(btnAfk.mouse.x, btnAfk.mouse.y);
        }
    } else {
        const clumpMode = storage.clumpMode;
        const mouse = storage.mouse;
        let position;
        let bestPosition;

        if (clumpMode === 'player') {
            position = storage.position;
            bestPosition = player.findBestPos(position, storage.inputs);
        } 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, `(${mouse.x}, ${mouse.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, `(${bestPosition.x}, ${bestPosition.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;
let btnAfk;
let btnDiscord;

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);
    },
});