Neon's Hitbox mod

A Mod for hitbox.io. type /help for help.

目前為 2023-12-07 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Neon's Hitbox mod
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  A Mod for hitbox.io. type /help for help.
// @author       iNeonz
// @match        https://heav.io/game.html
// @match        https://hitbox.io/game.html
// @match        https://heav.io/game2.html
// @match        https://hitbox.io/game2.html
// @match        https://hitbox.io/game-beta.html
// @icon         https://www.google.com/s2/favicons?sz=64&domain=heav.io
// @grant        none
// @run-at       document-idle
// ==/UserScript==

const codeNames = {};
const codeNamesRegex = {
    "lv": {
        reg: /this\.angle=(.*?);this\.angularVelocity=(.*?);(this\.(.*?))?;(this\.(.*?)=(.*?))?;/i,
        verify: function(match)
        {
            let lvx = match[0].match(/this\.angularVelocity=(.*?);(this\.(.*?))?;/i)[3].split("=")[0];
            let lvy = match[6];

            return [lvx,lvy];
        }
    },
    "general": {
        reg: /}.{0,2}\(.{0,2}\) \{var .{0,2},.{0,2};.{0,3}\..{0,3}\((.*?)\);(.*?)\)\);}/i,
        verify: function(match)
        {
            let matches = match[2].match(/this\..{0,2}=.{0,2}\[.{0,2}\+\+\]/ig);
            let m = [];
            for (let i of matches){
                m.push(i.split("this.")[1].split("=")[0]);
            }
            return m;
        }
    },

    "projectiles": {
        reg: /return \((.*?)\);}.{0,2}\(.{0,3}\) \{this\.x=.{0,3}\.shift\(\);this\.y=.{0,3}\.shift\(\);(.*?)this\.angle=.{0,3}\.shift\(\);this\.angularVelocity=.{0,3}\.shift\(\);(.*?)this\.density=.{0,3}\.shift\(\);this\.friction=.{0,3}\.shift\(\);this\.restitution=.{0,3}\.shift\(\);(.*?)this\.round=.{0,3}\.shift\(\);(.*?)}.{0,2}\(\) {/ig,
        verify: function(match)
        {
            console.log(match);
            let matches = ("this.x="+(match[0].split(") {this.x=")[6])).match(/this\.(.*?)=.{0,3}\.shift\(\);/ig);
            let m = [];
            for (let i of matches){
                m.push(i.split("this.")[1].split("=")[0]);
            }
            console.log(m);
            return m;
        }
    },
    "settings": {
        reg: /this\..{2,2}=.{2,2}.shift\(\);}};.{2,2}=class .{2,2}{constructor\(\) {.{3,3}\..{3,3}\(.{1,1}\);this\..{2,2}=.{3,3}\..{3,3}\(.{3,3},.{1,1}\);this\..{2,2}=(.*?);this\..{2,2}=(.*?);this\..{2,2}=(.*?);this\.backgroundImage=(.*?);.{3,3}\..{3,3}\((.*?)\);(.*?);}.{2,2}\(\)/ig,
        verify: function(match)
        {
            console.log(match);
            let settings = match[0].split("constructor() {")[1].match(/this\..{2,2}=(.*?);/ig);
            let m = [];
            for (let i of settings){
                m.push(i.split("this.")[1].split("=")[0]);
            }
            console.log(m);
            return m;
        }
    },
    "simulation": {
        reg: /;}.{2,2}\(.{3,3}\) {var .{3,3},.{3,3},.{3,3},.{3,3},.{3,3},.{3,3};.{3,3}\..{3,3}\(\);.{3,3}=this\..{2,2}\..{2,2}\(.{3,3}\)(.*?){throw new Error\("Failed to simulate(.*?)current fc(.*?).{3,3}=this\..{2,2}\.step\((.*?)\);/ig,
        verify: function(match)
        {
            console.log(match);
            let sim = match[0].split(";}")[1].split("(")[0];
            console.log(sim);
            let thisses = match[0].split("this.");
            for (let i of thisses){
             if (i.match("=")){
             i = i.split("=")[0];
             }else{
              i = null;
             }
            }
            thisses.filter(a => a != null);
            console.log(thisses);
            console.log([sim,thisses[1].split(".")[0],thisses[1].split(".")[1].split("(")[0]]);
            return [sim,thisses[1].split(".")[0],thisses[1].split(".")[1].split("(")[0]];
        }
    },
    "keys": {
        reg: /.{2,2}=class .{2,2}{constructor\(\) {this\.left=(.*?);this\.right=(.*?);this\..{2,2}=(.*?);(.*?);}.{2,2}\(.{2,2}\)/ig,
        // remind me to remove first pattern before this.left next update.
        verify: function(match)
        {
            let defines = (match[0].split("constructor() {")[1]).split("this.");
            let m = [];
            for (let i of defines){
                m.push(i.split("=")[0]);
            }
            return m;
        }
    }
}


// TAKEN FROM BONK.IO'S CODE INJECTOR.
fetch(`https://hitbox.io/bundle.js`)
    .then(code => code.text())
    .then(code => {
    for (let i in codeNamesRegex){
        codeNames[i] = codeNamesRegex[i].verify(code.match(codeNamesRegex[i].reg));
    }
    let monacoCSS = document.createElement(`link`);
    monacoCSS.rel = "stylesheet";
    monacoCSS.setAttribute("data-name","vs/editor/editor.main.css");
    monacoCSS.href = "https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.26.1/min/vs/editor/editor.main.css";
    document.head.appendChild(monacoCSS);

    function appendScript(link){
        let scr = document.createElement("script");
        scr.src = link;
        document.body.appendChild(scr);
    }

    let requirer = document.createElement("script");
    requirer.textContent = "var require = { paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.26.1/min/vs' } }";
    document.body.appendChild(requirer);

    appendScript("https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.26.1/min/vs/loader.min.js");
    appendScript("https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.26.1/min/vs/editor/editor.main.nls.js");
    appendScript("https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.26.1/min/vs/editor/editor.main.js");

    const emojis = {
        ":skull:":"💀",":omaga:":"😱",":smile:": "😃",":sob:":"😭",":darock:":"🤨",":flushed:":"😳",":cat:":"🐱",":globe:":"🌍",":ball:":"⚽",":balloon:":"🎈",":fest:":"🎉",":umbrella:":"☔",":nerd:":"🤓"
    }

    // /eval let last; for (let i in window.multiplayerSession.YI.Hx){last = window.multiplayerSession.YI.Hx[i];} last.po[0].th = -5;
    const newScope = (scope, script) => Function(`"use strict"; const globalThis = null; const window = null; const document = null; const game = this; ${script}`).bind(scope);
    let DN = [
        "gsFightersCollide",
        "recordMode",
        "o",
        "l",
        "u",
        "m",
        "g",
        "v",
        "k",
        "N",
        "S",
        "M",
        "C",
        "_",
        "T",
        "P",
        "B",
        "I",
        "F",
        "R",
        "O",
        "A",
        "D",
        "L",
        "U",
        "H",
        "J",
        "W",
        "G",
        "Y", // ss
        "V",
        "q",
        "K",
        "X",
        "Z",
        "$",
        "tt",
        "it",
        "st",
        "ht",
        "et",
        "nt",
        "ot",
        "rt",
        "at",
        "lt",
        "ut",
        "ct",
        "dt",
        "wt",
        "ft",
        "gt",
        "bt"
    ]


    /*ggame.events.add("init4each",function(id)
{
	game.vars[id] = {tank: 100};
})

game.events.add("step",function(id)
{
	for (let id in game.state.projectiles)
	{
		let proj = game.state.projectiles[id];
		if (proj)
		{
			let cube = game.state.cubes[proj.owner];
			if (cube)
			{
				cube.p = [proj.p[0],proj.p[1]-proj.br-.5];
				cube.lv = proj.lv;
				cube.a = 0;
			}
		}
	}
})

game.events.add("step4each",function(id)
{
	if (game.state.cubes[id] && game.inputs[id])
	{
		if (game.inputs[id].up && game.vars[id].tank > 0)
		{
            game.vars[id].tank -= 1;
			game.state.cubes[id].lv[1] -= 15/30;
		}
	}
})

*/

    // Player composition Y8 CLASS
    // x,y position
    // %s,th speed
    // yh doublejump?
    // Eh stamina
    // gh health
    // Ch freeze frames
    // Lh invincible frames? like the player goes transparent...
    // Dh rocket frames, set to 5 and you will shoot
    // Rh bat frames, set to 10 and you will bat
    // Th freeze, set to true and you will freeze

    // Checking for possible game states list
    let stateMaker;
    let mostScore = -1;
    let game = {
        state: null
    }

    let gmm = {
        enabled: false,
        pixi: {},
        overrides: {},
        applyOverrides: false,
        scopeFunc: null,
        events: {
        }
    }

    const gmmEvents = [
        "step",
        "step4each",
        "init",
        "init4each"
    ]

    for (let a1 in window.multiplayerSession){
        let a = window.multiplayerSession[a1];
        if (typeof a == "object")
        {
            let score = 0;
            for (let x1 in a){
                let x = a[x1];
                if (typeof x == "object")
                {
                    if (x.constructor.name == "Array"){

                    }
                    else
                    {
                        let length = 0;
                        for (let y1 in x){
                            let y = x[y1];
                            length++
                            if (length > 2){
                                break;
                            }
                        }
                        if (length == 1){
                            for (let y1 in x){
                                let y = x[y1];
                                if (y.constructor.name == "Map"){
                                    score++
                                }
                                break;
                            }
                        }else{
                            let isDN = true;
                            for (let i of DN){
                                if (!i in x){
                                    isDN = false;
                                    break;
                                }
                            }
                            if (isDN){
                                score+=5;
                            }
                        }
                    }
                }
            }
            if (score > mostScore && score < 50){
                mostScore = score;
                stateMaker = a;
            }
        }
    }

    function encodeState(state){
        let newState = state;
        newState.cubes = newState.all[7];
        newState.projectiles = [];
        for (let id in newState.all[8]){
            let proj = newState.all[8][id];
            if (proj){
                let newProj = {
                    p: [proj.x,proj.y],
                    lv: [proj[codeNames.lv[0]],proj[codeNames.lv[1]]],
                    a: proj.angle,
                    av: proj.angularVelocity,
                    ftd: proj[codeNames.projectiles[10]],
                    tr: proj[codeNames.projectiles[14]], // turn rate
                    gs: proj[codeNames.projectiles[17]], // gravity scale
                    er: proj[codeNames.projectiles[16]], // explode radius
                    bb: proj[codeNames.projectiles[18]], // bullet bounces
                    owner: proj[codeNames.projectiles[13]],
                    round: proj.round, // bullet round
                    restitution: proj.restitution, // bullet restitution
                    bc: proj[codeNames.projectiles[22]], // bounce count
                    br: proj[codeNames.projectiles[6]],
                }
                newState.projectiles[id] = newProj;
            }
        }
        for (let id in newState.cubes){
            let cube = newState.cubes[id];
            cube.p = [cube.x,cube.y];
            cube.lv = [cube[codeNames.lv[0]],cube[codeNames.lv[1]]];
            cube.st = cube[codeNames.general[20]];
            cube.a = cube.angle;
            delete cube.angle;
            delete cube[codeNames.stamina];
            delete cube[codeNames.lv[0]];
            delete cube[codeNames.lv[1]];
            delete cube.x;
            delete cube.y;
        }
        return newState;
    }

    let lastPixiContainer = null;

    function decodeState(state) {
        let newState = state;
        newState.all[7] = newState.cubes;
        for (let id in newState.projectiles){
            let proj = newState.projectiles[id];
            let p = newState.all[8][id];
            if (proj && p){
                p.x = proj.p[0]
                p.y = proj.p[1]
                p[codeNames.lv[0]] = proj.lv[0]
                p[codeNames.lv[1]] = proj.lv[1]
                p.angle = proj.a
                p.angularVelocity = proj.av
                p[codeNames.projectiles[10]] = proj.ftd
                p[codeNames.projectiles[14]] = proj.tr // turn rate
                p[codeNames.projectiles[17]] = proj.gs // gravity scale
                p[codeNames.projectiles[16]] = proj.er // explode radius
                p[codeNames.projectiles[18]] = proj.bb // bullet bounces
                p[codeNames.projectiles[22]] = proj.bc // bounce count
                p[codeNames.projectiles[6]] = proj.br
                p[codeNames.projectiles[13]] = proj.owner;
            }
        }
        delete newState.projectiles;
        for (let id in newState.all[7]){
            let cube = newState.all[7][id];
            cube.x = cube.p[0];
            cube.y = cube.p[1];
            cube[codeNames.lv[0]] = cube.lv[0];
            cube[codeNames.lv[1]] = cube.lv[1];
            cube[codeNames.general[20]] = cube.st;
            cube.angle = cube.a;
            delete cube.a;
            delete cube.st;
            delete cube.lv;
            delete cube.p;
        }
        return newState;
    }


    // vh down
    // yh up
    // kh rocket
    // Xh bat
    // qh force push
    // Zh grab
    function makeInputs(frame,cubes){
        let inputs = stateMaker[codeNames.simulation[1]][codeNames.simulation[2]](frame);
        if (inputs){
            let array = [];
            for (let id in inputs){
                array[id] = {
                    left: inputs[id].left,
                    right: inputs[id].right,
                    up: inputs[id][codeNames.keys[3]],
                    down: inputs[id][codeNames.keys[4]],
                    action3: inputs[id][codeNames.keys[7]], // BAT
                    action4: inputs[id][codeNames.keys[6]], // ROCKET
                    action2: inputs[id][codeNames.keys[8]], // GRAB
                    action1: inputs[id][codeNames.keys[5]] // FP
                }
            }
            for (let id in cubes){
                if (cubes[id]){
                    if (!array[id]){
                        array[id] = {
                            left: false,
                            right: false,
                            up: false,
                            down: false,
                            action3: false, // BAT
                            action4: false, // ROCKET
                            action2: false, // GRAB
                            action1: false // FP
                        }
                    }
                }
            }
            return array;
        }
    }

    const createGraphics = (info) => {
        let id = game.state.graphics.index;
        game.state.graphics.index++;
        game.state.graphics.drawings[id] = info;
        return id;
    }

    console.log(stateMaker,"won",mostScore)


    function updateDrawings(){
        if (gmm.enabled){
            if (document.getElementById('backgroundImage') && lastPixiContainer && game.state && game.prevState && game.prevState.graphics && game.state.graphics){
                let bg = document.getElementById('backgroundImage')
                let w = bg.clientWidth;
                let h = bg.clientHeight;
                let mps = 35/((game.state.settings[0][codeNames.settings[2]])/35);
                if (!lastPixiContainer.sortableChildren){
                    lastPixiContainer.sortableChildren = true
                }
                for (let id in game.state.graphics.drawings)
                {
                    let pi = game.prevState.graphics.drawings[id];
                    let p = game.state.graphics.drawings[id];
                    if (pi){
                        if (pi && !p){
                            if (gmm.pixi[id]){
                                gmm.pixi[id].container.destroy();
                                delete gmm.pixi[id].container;
                            }
                        }
                    }
                    if (p){
                        if (!gmm.pixi[id]){
                            let obj = new window.PIXI.Container();
                            lastPixiContainer.addChild(obj);
                            gmm.pixi[id] = {container: obj,children: {}};
                            obj.zIndex = 100000;
                        }
                        if (gmm.pixi[id].container.parent != lastPixiContainer){
                            lastPixiContainer.addChild(gmm.pixi[id].container);
                            gmm.pixi[id].container.zIndex = 100000;
                        }
                        let offsetX = 0;
                        let offsetY = 0;
                        let offsetAngle = 0;
                        if (p.attach == "cube")
                        {
                            if (game.state.cubes[p.attachId]){
                                gmm.pixi[id].container.visible = true;
                                let c = game.state.cubes[p.attachId];
                                offsetX = c.x;
                                offsetY = c.y;
                                offsetAngle = p.fixedAngle? 0 : c.angle;
                            }else{
                                gmm.pixi[id].container.visible = false;
                            }
                        }
                        gmm.pixi[id].container.x = ((((offsetX+p.p[0])/35)*mps)/35)*w;
                        gmm.pixi[id].container.y = ((((offsetY+p.p[1])/35)*mps)/35)*w;
                        gmm.pixi[id].container.rotation = offsetAngle + (p.a||0);
                        if (pi){
                            for (let shapeId in pi.shapes){
                                let shape = p.shapes[shapeId];
                                let shapel = pi?.shapes[shapeId];
                                if (shapel && !shape){
                                    gmm.pixi[id].children[shapeId].destroy();
                                    delete gmm.pixi[id].children[shapeId];
                                }
                            }
                        }
                        for (let shapeId in p.shapes){
                            let shape = p.shapes[shapeId];
                            let shapel = pi?.shapes[shapeId];
                            if (shape){
                                if (!gmm.pixi[id].children[shapeId]){
                                    if (shape.type == "bx"){
                                        // Box shape
                                        let obj = new window.PIXI.Sprite(window.PIXI.Texture.WHITE);
                                        obj.anchor.x = 0.5;
                                        obj.anchor.y = 0.5;
                                        gmm.pixi[id].container.addChild(obj);
                                        gmm.pixi[id].children[shapeId] = obj;
                                    }
                                    else if (shape.type == "tx")
                                    {
                                        // Text shape
                                        let obj = new window.PIXI.Text('', {
                                            fontFamily: 'Arial',
                                            fontSize: 24,
                                            fill: 0xffffff,
                                            align: 'center',
                                        });
                                        obj.anchor.x = 0.5;
                                        obj.anchor.y = 0.5;
                                        gmm.pixi[id].container.addChild(obj);
                                        gmm.pixi[id].children[shapeId] = obj;
                                    }
                                }
                                let obj = gmm.pixi[id].children[shapeId];
                                obj.x =((((shape.p[0]/35)*mps)/35)*w)*p.scale[0];
                                obj.y =((((shape.p[1]/35)*mps)/35)*w)*p.scale[1];
                                obj.tint = shape.color;
                                obj.rotation = shape.a || 0;
                                if (shape.type == "tx"){
                                    obj.text = shape.text;
                                    obj.style.fontSize = ((((shape.size/35)*mps)/35)*w)*p.scale[0];
                                }else{
                                    obj.width = ((((shape.size[0]/35)*mps)/35)*w)*p.scale[0];
                                    obj.height = ((((shape.size[1]/35)*mps)/35)*w)*p.scale[1];
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    const vectorUtils = {
        add: function(n1,n2){
            for (let i in n1){
                n1[i] += n2[i] || 0;
            }
            return n1;
        },
        sub: function(n1,n2){
            for (let i in n1){
                n1[i] -= n2[i] || 0;
            }
            return n1;
        },
        mult: function(n1,n2){
            for (let i in n1){
                n1[i] *= n2[i] || 0;
            }
            return n1;
        },
        div: function(n1,n2){
            for (let i in n1){
                n1[i] /= n2[i] || 0;
            }
            return n1;
        },
        angleOf: function(n1){
            return Math.atan2(n1[1],n1[0]);
        },
        norm: function(n1){
            let a = Math.atan2(n1[1],n1[0]);
            return [Math.cos(a),Math.sin(a)];
        },
        dot: function(n1,n2) {
            return n1.map((x, i) => n1[i] * n2[i]).reduce((m, n) => m + n)
        }
    }
    stateMaker.mmR = stateMaker[codeNames.simulation[1]][codeNames.simulation[2]];
    stateMaker[codeNames.simulation[1]][codeNames.simulation[2]] = function(frame){
     let info = stateMaker.mmR.call(this,frame);
     if (gmm.enabled){
         let state = getAllStates()[frame-1];
         if (state){
             let overrides = state.overrides;
             for (let i in info){
                 if (!overrides[i]){
                     overrides[i] = {
                         left: null,
                         right: null,
                         up: null,
                         down: null,
                         action3: null,
                         action4: null,
                         action2: null,
                         action1: null
                     }
                 }
             }
     if (gmm.applyOverrides){
         for (let i in overrides){
             if (info[i]){
                  info[i] = {
                    left: overrides[i].left != null? overrides[i].left : info[i].left,
                    right: overrides[i].right != null? overrides[i].right : info[i].right,
                    [codeNames.keys[3]]: overrides[i].up != null? overrides[i].up : info[i][codeNames.keys[3]],
                    [codeNames.keys[4]]: overrides[i].down != null? overrides[i].down : info[i][codeNames.keys[4]],
                    [codeNames.keys[7]]: overrides[i].action3 != null? overrides[i].action3 : info[i][codeNames.keys[7]], // BAT
                    [codeNames.keys[6]]: overrides[i].action4 != null? overrides[i].action4 : info[i][codeNames.keys[6]], // ROCKET
                    [codeNames.keys[8]]: overrides[i].action2 != null? overrides[i].action2 : info[i][codeNames.keys[8]], // GRAB
                    [codeNames.keys[5]]: overrides[i].action1 != null? overrides[i].action1 : info[i][codeNames.keys[5]] // FP
                  }
             }else{
                 info[i] = {
                    left: false,
                    right: false,
                    [codeNames.keys[3]]: false,
                    [codeNames.keys[4]]: false,
                    [codeNames.keys[7]]: false,
                    [codeNames.keys[6]]: false,
                    [codeNames.keys[8]]: false,
                    [codeNames.keys[5]]: false // FP
                  }
             }
         }
     }
         }
     }
     return info;
    }
    stateMaker.rrP = stateMaker[codeNames.simulation[0]];
    stateMaker[codeNames.simulation[0]] = function(frame)
    {
        gmm.applyOverrides = true;
        let simulated = stateMaker.rrP.call(this,frame);
        gmm.applyOverrides = false;
        if (gmm.enabled){
            try {
            let lc = getAllStates()[frame] || null;
            if (lc && !lc.vars){
             lc.vars = [];
             lc.overrides = [];
             for (let i of users){
                     lc.overrides[i.id] = {
                         left: null,
                         right: null,
                         up: null,
                         down: null,
                         action3: null,
                         action4: null,
                         action2: null,
                         action1: null
                     }
             }
             lc.graphics = {create: createGraphics,index: 0,drawings: {}};
            }
            if (lc){
                simulated.vars = JSON.parse(JSON.stringify(lc.vars));
                simulated.overrides = JSON.parse(JSON.stringify(lc.overrides));
                simulated.graphics = {create: createGraphics,index: parseInt(lc.graphics.index.toString()),drawings: JSON.parse(JSON.stringify(lc.graphics.drawings))};
                simulated.prevGraphics = {create: createGraphics,index: parseInt(lc.graphics.index.toString()),drawings: JSON.parse(JSON.stringify(lc.graphics.drawings))};
            }
            game.state = encodeState(simulated);
            game.Vector = vectorUtils;
            game.overrides = simulated.overrides;
            if (frame == 0){
                game.clientId = myid;
                game.hostId = hostId;
                for (let i in gmm.pixi){
                    gmm.pixi[i].container.destroy();
                    delete gmm.pixi[i];
                }

                game.graphics = {create: createGraphics,index: 0,drawings: {}};
                game.state.graphics = game.graphics;
                game.vars = {};
                for (let func of gmm.events.init){
                    func();
                }
                for (let func of gmm.events.init4each){
                    for (let i of users){
                        try {
                            func(i.id);
                        }
                        catch (error)
                        {

                        }
                    }
                }
                simulated.vars = game.vars;
                simulated.graphics = game.graphics;
            }
            game.prevState = lc? encodeState(lc) : null;
            game.inputs = makeInputs(frame,game.state.cubes);
            game.vars = simulated.vars;
            game.graphics = simulated.graphics;
            for (let func of gmm.events.step){
                try {
                    func();
                }
                catch (error)
                {

                }
            }
            for (let func of gmm.events.step4each){
                for (let i of users){
                    try {
                        func(i.id);
                    }
                    catch (error)
                    {

                    }
                }
            }
            simulated = decodeState(game.state);
            simulated.vars = game.vars;
            simulated.graphics = game.graphics;
            simulated.overrides = game.overrides;
            if (lc){
                lc = decodeState(game.prevState);
            }
            }catch(error){
             if (hostId == myid){
              WSS.send(`42[1,[21]]`);
              setTimeout(() => {
              WSS.send(`42[1,[71]]`);
              },700);
             }
            }
        }
        updateDrawings();
        return simulated;
    }

    //eval defineGMM("game.events.add('step',function() {game.state.po[0].th = -5;})")

    function getAllStates(){
        let state;
        for (let a in stateMaker){
            let b = stateMaker[a];
            if (b.constructor.name == "Array"){
                for (let i of b){
                    if (typeof(i) == "object" && "all" in i && i.all.constructor.name == "Array"){
                        if (i.all.length > 10 && i.all.length < 15){
                            state = b;
                            break;
                        }

                    }
                }
            }
        }
        if (state){
            return state;
        }
    }

    function setStates(states){
        let state;
        for (let a in stateMaker){
            let b = stateMaker[a];
            if (b.constructor.name == "Array"){
                for (let i of b){
                    if (typeof(i) == "object" && "all" in i && i.all.constructor.name == "Array"){
                        if (i.all.length > 10 && i.all.length < 15){
                            state = b;
                            break;
                        }

                    }
                }
            }
        }
        if (state){
            state = states;
        }
    }

    function getCurrentState(){
        let state;
        for (let a in stateMaker){
            let b = stateMaker[a];
            if (b && b.constructor && b.constructor.name == "Array"){
                for (let it in b){
                    let i = b[it];
                    if (typeof(i) == "object" && "all" in i && i.all.constructor.name == "Array"){
                        if (i.all.length > 10 && i.all.length < 15){
                            state = b;
                            break;
                        }

                    }
                }
            }
        }
        if (state){
            let last;
            for (let a in state){
                state[a].frame = a;
                last = state[a];
            }
            return last;
        }
    }

    function sendInfo(sett = {},offset = 0){
        if (hostId == myid){
            sett.frame = getCurrentState()?.frame-offset;
            settings.nhm = sett;
            WSS.send(`42[1,[62,${JSON.stringify(settings)}]]`)
            WSS.onmessage({data: `42[63,${JSON.stringify(settings)}]`})
        }
    }

    let bot = false;
    let selPet = -1;
    let selAcc = -1;

    const letters = "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z".split(" ");
    const fonts = {
        bold: "𝐚 𝐛 𝐜 𝐝 𝐞 𝐟 𝐠 𝐡 𝐢 𝐣 𝐤 𝐥 𝐦 𝐧 𝐨 𝐩 𝐪 𝐫 𝐬 𝐭 𝐮 𝐯 𝐰 𝐱 𝐲 𝐳 𝟏 𝟐 𝟑 𝟒 𝟓 𝟔 𝟕 𝟖 𝟗 𝐀 𝐁 𝐂 𝐃 𝐄 𝐅 𝐆 𝐇 𝐈 𝐉 𝐊 𝐋 𝐌 𝐍 𝐎 𝐏 𝐐 𝐑 𝐒 𝐓 𝐔 𝐕 𝐖 𝐗 𝐘 𝐙".split(" "),
        italic: "𝘢 𝘣 𝘤 𝘥 𝘦 𝘧 𝘨 𝘩 𝘪 𝘫 𝘬 𝘭 𝘮 𝘯 𝘰 𝘱 𝘲 𝘳 𝘴 𝘵 𝘶 𝘷 𝘸 𝘹 𝘺 𝘻 1 2 3 4 5 6 7 8 9 𝘈 𝘉 𝘊 𝘋 𝘌 𝘍 𝘎 𝘏 𝘐 𝘑 𝘒 𝘓 𝘔 𝘕 𝘖 𝘗 𝘘 𝘙 𝘚 𝘛 𝘜 𝘝 𝘞 𝘟 𝘠 𝘡".split(" "),
    }

    const petSkins = {
        'Kitty':'https://cdn.discordapp.com/attachments/1128508277827846206/1138568531307409528/catpet.png',
        'f':'https://cdn.discordapp.com/attachments/1128508277827846206/1139666785386381362/F.png',
        'egg':'https://cdn.discordapp.com/attachments/1128508277827846206/1139666785025662976/egg2.png',
        'rock':'https://cdn.discordapp.com/attachments/1128508277827846206/1139666784706899998/darock.jpg',
        'cube':'https://cdn.discordapp.com/attachments/1128508277827846206/1139666784442663014/cube.png',
        'chaz':'https://cdn.discordapp.com/attachments/1128508277827846206/1139666784174219304/chaz.png',
        'chad':'https://cdn.discordapp.com/attachments/1128508277827846206/1139666783909982329/chad.jpg',
        'sus':'https://cdn.discordapp.com/attachments/1128508277827846206/1139666786418171925/the_sussy_baka.jpg',
        'isaac':'https://cdn.discordapp.com/attachments/1128508277827846206/1139666786099408967/isaac.png',
        'ghost':'https://cdn.discordapp.com/attachments/1128508277827846206/1139666785763868762/ghost.png',
        'chat-gpt':'https://cdn.discordapp.com/attachments/1128508277827846206/1139667562704162876/gpt.png'
    }

    const accessories = [
        'birb',
        'egg',
        'Fedora',
        'helmet',
        'hammer',
        'cta',
        'egg2',
        'gentleman',
        'headphone',
        'sus',
        'nerd',
        'bunny',
        'cape',
        'cheese',
        'new',
        'spicebox',
        'guns',
        'crown',
        'noob',
        'slimey',
        'potato',
        'niko',
        'default',
        'monke',
        'gaming',
        'isaac',
        'horn',
        'wings',
        'glasses',
        'chair'
    ];
    const acessoryLink = {
        'birb': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846288388079806/birb.png',
        'egg': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846288652325016/egg.png',
        'noob': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846290015473786/noob.png',
        'nerd': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133847987995557918/nerd.png',
        'crown': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133847987521605662/crown.png',
        'cheese': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133847987232190504/cheese.png',
        'bunny': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846393891598356/bunny.png',
        'default': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133847987764867092/default.png',
        'Fedora': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846288857829537/Fedora.png',
        'cta': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133848562761994352/cta.png',
        'gentleman': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133848562992693449/gentleman.png',
        'helmet': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846289080139806/helmet.png',
        'monke': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846289310830612/monke.png',
        'new': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846289533112360/new.png',
        'niko': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846289776394290/niko.png',
        'hammer': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846508647755886/hammer.png',
        'guns': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846508396089364/guns.png',
        'sus': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846395732885635/sus.png',
        'potato': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846394944356443/potato.png',
        'slimey': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846395217002587/slimey.png',
        'spicebox': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846395460268042/spicebox.png',
        'headphone': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846394705293383/headphone.png',
        'egg2': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846394453639189/egg2.png',
        'cape': 'https://cdn.discordapp.com/attachments/1128508277827846206/1133846394143244318/cape.png',
        'gaming':'https://cdn.discordapp.com/attachments/1128508277827846206/1137513131774591016/gamer.png',
        'isaac':'https://cdn.discordapp.com/attachments/1128508277827846206/1137513132420513903/isaac.png',
        'horn':'https://cdn.discordapp.com/attachments/1128508277827846206/1137513132206587974/horns.png',
        'glasses':'https://cdn.discordapp.com/attachments/1128508277827846206/1137513133028671538/sunglasses.png',
        'chair':'https://cdn.discordapp.com/attachments/1128508277827846206/1137513132009463879/gaming.png',
        'wings':'https://cdn.discordapp.com/attachments/1128508277827846206/1137513133276151899/wings.png'
    }

    let zoom = 1;
    const textures = [];
    const petTextures = [];
    const pets = [
        'Kitty',
        'chat-gpt',
        'chaz',
        'chad',
        'sus',
        'egg',
        'f',
        'cube',
        'rock',
        'isaac',
        'ghost'
    ]
    let settings = {};
    let trace = [];
    let tracing = -1;
    let traceLimit = 0;

    class listener {
        constructor() {

        }
        add(event,func){
            if (gmm.events[event]){
                gmm.events[event].push(func);
            }
        }
    }

    function defineGMM(code)
    {
        gmm.enabled = true;
        gmm.events = [];
        gmm.code = code;
        for (let i in gmm.pixi){
            gmm.pixi[i].container.destroy();
            delete gmm.pixi[i];
        }
        for (let i of gmmEvents){
            gmm.events[i] = [];
        }
        gmm.listener = new listener();
        game.events = gmm.listener;
        let func = newScope(game,code);
        func();
        gmm.scopeFunc = func;
        if (hostId == myid)
        {
            sendInfo({gmm:code});
        }
    }

    function setSett(setts)
    {
        let sett = {};
        let sects = setts.split('|');
        for (let o of sects){
            let pr = o.split(':');
            if (pr[1]){
                let v = JSON.parse(`[${pr[1]}]`)[0];
                sett[pr[0]] = v;
            }
        }
        WSS.onmessage({data: `42[63,${JSON.stringify(sett)}]`})
        WSS.send(`42[1,[62,${JSON.stringify(sett)}]]`)
    }

    window.setPet = (pet) => {
        selPet = pet;
        if (pets[pet]){
            display("* selected pet: "+pets[pet]);
        }else{
            display("* Removed pet");
        }
        let pl = findUser(myid);
        if (pl){
            if (pl.pet){
                pl.pet.destroy();
                pl.pet = null;
            }
        }
    }

    let petL = "";
    for (let a in pets)
    {
        let b = pets[a];
        let c = petSkins[b];
        petL += `<div><img width="50" height="50" src="${c}"></img><font size="15"><a href="javascript:window.setPet(${a});">${b}</a></font></div>`
    }

    let accsL = "";
    for (let a in accessories)
    {
        let b = accessories[a];
        let c = acessoryLink[b];
        accsL += `<div><img width="50" height="50" src="${c}"></img><font size="15"><a href="javascript:window.setHat(${a});">${b}</a></font></div>`
    }

    const editor = document.createElement('div');
    editor.style = "opacity: 1; position: absolute; top: calc(50% - 40%); left: calc(50% - 45%); width: 90%; height: 80%; background-color: #212121; border-radius: 7px;";
    const topBar = document.createElement('div');
    topBar.classList.add("topBar");
    topBar.textContent = "Editor";
    editor.appendChild(topBar);
    document.getElementById("appContainer").appendChild(editor);
    const editorBox = document.createElement(`div`);
    editorBox.style = "color-scheme: only light; background: #ffffff; overflow: hidden; border-radius: 8px; width: calc(100% - 70px); right: 15px; height: calc(100% - 60px); top: 50px; position: absolute;";
    editor.appendChild(editorBox);
    editor.style.display = "none";
    const checkButton = document.createElement('div');
    checkButton.classList.add("crossButton");
    editor.appendChild(checkButton);
    const exportButton = document.createElement('div');
    exportButton.classList.add("crossButton");
    exportButton.style.left = "15px";
    exportButton.style.top = "50px";
    exportButton.style.backgroundImage = "url(https://github.com/SneezingCactus/gmmaker/blob/master/src/gmWindow/images/gmeexport.png?raw=true)";
    editor.appendChild(exportButton);
    const importButton = document.createElement('div');
    importButton.classList.add("crossButton");
    importButton.style.left = "15px";
    importButton.style.top = "80px";
    importButton.style.backgroundImage = "url(https://github.com/SneezingCactus/gmmaker/blob/master/src/gmWindow/images/gmedownload.png?raw=true)";
    editor.appendChild(importButton);
    exportButton.onclick = () => {
        if (window.monacoEditor){
            let text = `
  {
  [CODE]
  > \`\`\`;${window.monacoEditor.getValue()}> \`\`\`;
  [IMAGES]
  > \`\`\`;> \`\`\`;
  }
  `
  let element = document.createElement('a');
     element.setAttribute('href', 'data:text/plain;charset=utf-8,' + window.btoa(encodeURIComponent(text)));
     element.setAttribute('download', "ngmmExport.ngmm");

     element.style.display = 'none';
     document.body.appendChild(element);

     element.click();

     document.body.removeChild(element);
 }
}
importButton.onclick = () => {
    if (window.monacoEditor){
        let input = document.createElement('input');
        input.type = 'file';

        input.onchange = e => {
            let file = e.target.files[0];
            let reader = new FileReader();
            reader.readAsText(file,'UTF-8');
            reader.onload = readerEvent => {
                let content = readerEvent.target.result;
                let decoded = decodeURIComponent(window.atob(content));
                let firstStep = decoded.match(/\[CODE\](.*?)> ```;(.*?)> ```;/gims)[0].split('> ```;');
                let finalCode = '';
                for (let i in firstStep){
                    if (i > 0 && i < firstStep.length){
                        finalCode+=firstStep[i];
                    }
                }
                window.monacoEditor.setValue(finalCode);
            }
        }

        input.click();
    }
}
checkButton.onclick = () => {
    if (window.monacoEditor){
        let markers = monaco.editor.getModelMarkers({owner: "javascript"}).filter(a => a.severity >= 5);
        if (markers[0]){
            console.log(markers[0]);
            window.monacoEditor.revealLine(markers[0].endLineNumber);
            window.monacoEditor.setPosition({lineNumber: markers[0].endLineNumber, column: markers[0].endColumn});
            return;
        }
        else
        {
            document.getElementsByClassName("lobbyContainer")[0].style.display = "block";
            let code = window.monacoEditor.getValue();
            defineGMM(code);
        }
    }
    editor.style.display = "none";
}
new Promise((r) => {
    const thisId = setInterval(() => {
        if (window.monaco){
            var libSource = `
/**
* A projectile's structure.
*/
declare class projectile {
/**
* A projectile's position (Vector2).
*/
static p: number[2] = [0,0]
/**
* A projectile's velocity (Vector2).
*/
static lv: number[2] = [0,0]
/**
* A projectile's angle (radians).
*/
static a: number = 0
/**
* A projectile's angular velocity (radians).
*/
static av: number = 0
/**
* A projectile's frames til death (number).
*/
static ftd: number = 70
/**
* A projectile's turn rate (number).
*/
static tr: number = 0.025
/**
* A projectile's gravity scale (number).
*/
static gs: number = 0
/**
* A projectile's explode radius (number).
*/
static er: number = 1
/**
* Determines when the bullet can bounce (boolean).
*/
static bb: boolean = false;
/**
* A projectile's round value.
*/
static round: boolean = true;
/**
* A projectile's restitution (Number).
*/
static restitution: number = 1;
/**
* A projectile's bounce count (number).
*/
static bc: number = 0;
/**
* A projectile's owner id (number).
*/
static owner: number = 0;
/**
* A projectile's bullet radius (number).
*/
static br: number = 0.11,
}


/**
* The essencial events for a mode.
*/
declare class listener {
/**
* Attach a event to the mode.
*/
static add(string: name,method: func):function(name,func) {}
}
declare class input {
/**
* True when the player is pressing left.
*/
static left: boolean = false;
/**
* True when the player is pressing right.
*/
static right: boolean = false;
/**
* True when the player is pressing up.
*/
static up: boolean = false;
/**
* True when the player is pressing down.
*/
static down: boolean = false;
/**
* True when the player is pressing action1 aka force push.
*/
static action1: boolean = false;
/**
* True when the player is pressing action2 aka grab.
*/
static action2: boolean = false;
/**
* True when the player is pressing action3 aka bat.
*/
static action3: boolean = false;
/**
* True when the player is pressing action4 aka rocket.
*/
static action4: boolean = false;
}

/**
* Array with inputs of the players, may disappear when killed until respawned, indexed by ids.
*/
declare const inputs = [
input
]
/**
* Information about the game's graphics.
*/
declare class graphics {
/**
* Create a drawing.
* example: const id = game.graphics.create({p:[0,0],a: 0,attach:"world",attachId:-1,scale: [1,1],shapes:[{type:"bx",p:[0,0],size:[10,10],a: 0,color: 0xffffff}]});
*/
static create(object: info):function(info) {return number: id}
/**
* Drawings array, ordered by id.
*/
static drawings: obj[] = obj[obj]
}
/**
* A Object representing a cube.
*/
declare class cube {
	/**
	* The Position (Vector2) of a cube.
	*/
    static p: number[2] = [0,0]
	/**
	* The Linear Velocity (Vector2) of a cube.
	*/
	static lv: number[2] = [0,0]
	/**
	* The Stamina (Number) of a cube.
	*/
	static st: number = 100
    /**
	* The angle (Number) of a cube in radians.
	*/
	static a: number = 0
}
/**
* A Object representing the current game's state.
*/
declare const stateStep = {
/**
* A array representing all the alive players.
*/
static cubes: cube[] = [cube]
/**
* A array representing all the projectiles.
*/
static projectiles: projectile[] = [projectile]
}

/**
* Vector utility
*/
declare class vector {
/**
* Add two vectors.
*/
static add(any,any): number[]
/**
* Subtract two vectors.
*/
static sub(any,any): number[]
/**
* Multiply two vectors.
*/
static mult(any,any): number[]
/**
* Divide two vectors.
*/
static div(any,any): number[]
/**
* Get the angle in radians of a vector.
*/
static angleOf(any): number
/**
* Get the normalized result of a vector.
*/
static norm(any): number[]
/**
* Get the scalar dot product of two vectors.
*/
static dot(any,any): number
}

/**
* The general game information.
*/
declare const game = {
/**
* This is a empty object that you can use to hold variables, use this instead of setting a const, let or var outside any events.
*/
static vars: any
/**
* This is your client ID, use for local visuals.
*/
static clientId: number
/**
* This is your host ID, use for local visuals.
*/
static hostId: number
/**
* This is a array that contains overridable properties of each player's input, set to null to stop override.
*/
static overrides: inputs
/**
* Information about the current game's graphics.
*/
static graphics: graphics
/**
* Vector utiltiy.
*/
static Vector: vector
/**
* The current game's state.
*/
static state: stateStep
/**
* The previous game's state.
*/
static prevState: stateStep
/**
* The game events.
*/
static events: listener
/**
* The current game's inputs.
*/
static inputs: inputs
}
`
var libUri = "ts:filename/facts.d.ts";
            monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri);
            monaco.editor.createModel(libSource, "typescript", monaco.Uri.parse(libUri));

            monaco.editor.setTheme('vs')

            monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
                noSemanticValidation: false,
            });

            monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
                target: monaco.languages.typescript.ScriptTarget.ES6,
                allowNonTsExtensions: true
            });

            window.monacoEditor = monaco.editor.create(editorBox, {
                value: `game.events.add("init4each",(id) => {
		game.graphics.create({
			p: [0,0],
			attach: "cube",
			attachId: id,
			scale: [1,1],
            fixedAngle: true,
			a: 0,
			shapes: [
				{
					type: "tx",
					text: (id == game.clientId? "YOU" : "OTHER")+(game.clientId == game.hostId? " HOST" : " NOT HOST"),
					color: id == game.clientId? 0xff00ff : 0xff0000,
					a: 0,
					p: [0,-2],
					size: 1
				}
			]
		})
})`,
    automaticLayout: true,
    language: 'javascript'
});
            clearInterval(thisId);
            r();
        }
    },10);
})
    .then(r => {
    console.log("monaco loaded");
})
    //<textarea class="scrollBox" wrap="soft" spellcheck="false" style="border: none; outline: none; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; resize: none; position: absolute; overflow-y: scroll; overflow-x: hidden; background-color: #2f2f2f; height: calc(100% - 60px); width: calc(100% - 80px); left: 80px; top: 50px; box-sizing: border-box; border-bottom-left-radius: 7px; border-bottom-right-radius: 7px; white-space: nowrap;"></textarea>


    let petsList = document.createElement('div');
    document.body.appendChild(petsList);
    petsList.innerHTML = `<div class="updateNews" style="zoom: 0.628571;">
<div class="topBar" style="opacity: 1;">Pets List</div>
<div class="crossButton" onclick="this.parentNode.parentNode.style.display = 'none';"></div>
<div class="dateLabel" style="opacity: 1;">Yo fellas, get one n o w</div>
<div class="textContent" style="opacity: 1;">
<ul>
${petL}
</ul>
</div>
`
petsList.style.display = 'none';

    let modeConfig = {};
    let modes = [
        {
            name:"Normal",
            options: {teams: false},
            description: "Default gameplay."
        },
        { // 1
            name:"Tag",
            description: "Tag game: Someone is a tagger, die and turn the tagger.",
            options: {teams: true},
            tick: function(dt){
                if (!modeConfig.isTAG){
                    modeConfig = {
                        isTAG: true,
                        timer: 10,
                        player: -1,
                        delay: 0
                    }
                    setSett("7:9999999999999999999999999999999999|8:999999|9:0|12:true|13:5|36:50|");
                }
                if (modeConfig.delay > 0)
                {
                    modeConfig.delay -= dt;
                    return;
                }
                let plr = findUser(modeConfig.player);
                let newPlr = false;
                if (!plr || !plr.alive)
                {
                    for (let i in alive)
                    {
                        modeConfig.player = findUser(i)?.id;
                        newPlr = true;
                        break;
                    }
                }
                plr = findUser(modeConfig.player);
                if (plr)
                {
                    if (newPlr)
                    {
                        send(`${plr.name} is the tagger!`);
                        modeConfig.delay = 3;
                        switchPlayer(plr.id,0);
                        setTimeout(function()
                                   {
                            switchPlayer(plr.id,2);
                        },50);
                    }
                    if (plr.team != 2 && plr.team != 0){
                        switchPlayer(plr.id,0);
                        modeConfig.delay = 2;
                        setTimeout(function(){
                            switchPlayer(plr.id,2);
                        },100);
                    }
                    if (plr.team == 0){
                        modeConfig.player = -1;
                    }
                    for (let p of users){
                        if (p.alive && p.team == 2 && modeConfig.player != p.id)
                        {
                            switchPlayer(p.id,0);
                            setTimeout(function()
                                       {
                                switchPlayer(p.id,3);
                            },100);
                        }
                    }
                }
            },
            death: function(plr){
                if (plr.team == 0){
                    return;
                }
                if (modeConfig.player == plr.id || modeConfig.delay > 0){
                    modeConfig.delay = 2;
                }
                else
                {
                    const lp = modeConfig.player;
                    switchPlayer(lp,0);
                    setTimeout(function()
                               {
                        switchPlayer(lp,3);
                    },100);
                    send(`${plr.name} has been tagged!`);
                    modeConfig.delay = 2;
                    modeConfig.player = plr.id;
                    switchPlayer(plr.id,0);
                    setTimeout(function()
                               {
                        switchPlayer(plr.id,2);
                    },100);
                }
            }
        },
        { // 2
            name:"Domination",
            description: "Two teams, Die and get to the other team!",
            options: {teams: true},
            tick: function(dt){
                if (!modeConfig.isDOM){
                    modeConfig = {
                        isDOM: true
                    }
                    setSett("7:1e+38|9:0|42:0|");
                }
            },
            death: function(plr)
            {
                if (plr.team == 0){
                    return;
                }
                if (plr.team == 2)
                {
                    switchPlayer(plr.id,0);
                    setTimeout(() => {
                        switchPlayer(plr.id,3);
                    },50);
                    plr.team = 3;
                }
                else
                {
                    switchPlayer(plr.id,0);
                    setTimeout(() => {
                        switchPlayer(plr.id,2);
                    },50);
                    plr.team = 2;
                }
            }
        },
        { // 3
            name:"Bounty",
            description: "Bounty: Kill players to have their score reset!",
            options: {teams: false},
            tick: function(dt){
                if (!modeConfig.isBOUNTY){
                    modeConfig = {
                        isBOUNTY: true
                    }
                    setSett("7:10|9:0|12:true|21:3|41:140|42:0|43:0.5|44:true|45:-9|46:10|50:3|");
                }
            },
            death: function(plr)
            {
                if (plr.team != 0)
                {
                    send(`${plr.name} lost their ${plr.score} kills bounty!`)
                    let team = plr.team;
                    switchPlayer(plr.id,0);
                    setTimeout(() => {
                        switchPlayer(plr.id,team);
                    },50);
                    if (plr.score > 0)
                    {
                    }
                }
            }
        }
    ]
    let currentMode = 0;

    window.setMode = function(mode){
        if (WSS && myid == hostId)
        {
            currentMode = mode;
            display(`* Mode changed to ${modes[currentMode].name}`)
            setTeams(modes[currentMode].options?.teams);
            modeConfig = {};
        }
        else
        {
            display(`* You aren't the host of this room.`);
        }
    }

    let modeL = "";
    for (let a in modes)
    {
        let b = modes[a];
        let c = b.img || "";
        modeL += `<div><img width="100" height="100" src="${c}"></img><p><font size="10"><a href="javascript:window.setMode(${a});">${b.name}</a></font></p><font size="5">${b.description}</font></div>`
    }

    let modesList = document.createElement('div');
    document.body.appendChild(modesList);
    modesList.innerHTML = `<div class="updateNews" style="zoom: 0.628571;width: 500px;height:400px;">
<div class="topBar" style="opacity: 1;">Game Modes</div>
<div class="crossButton" onclick="this.parentNode.parentNode.style.display = 'none';"></div>
<div class="dateLabel" style="opacity: 1;">Yo fellas, choose one</div>
<div class="textContent" style="opacity: 1; width: 440px;height:310px;">
<ul>
${modeL}
</ul>
</div>
`
modesList.style.display = 'none';

    let accsList = document.createElement('div');
    document.body.appendChild(accsList);
    accsList.innerHTML = `<div class="updateNews" style="zoom: 0.628571;">
<div class="topBar" style="opacity: 1;">Pets List</div>
<div class="crossButton" onclick="this.parentNode.parentNode.style.display = 'none';"></div>
<div class="dateLabel" style="opacity: 1;">Yo fellas, get one n o w</div>
<div class="textContent" style="opacity: 1;">
<ul>
${accsL}
</ul>
</div>
`
accsList.style.display = 'none';

    const tracer = window.PIXI.Sprite.from(window.PIXI.Texture.WHITE);

    tracer.anchor.x = 0.5;
    tracer.anchor.y = 0.5;

    function newkeydiv(){
        let div = document.createElement('div');
        div.style="width:60px;font-size:40px;height:60px;border-radius:15px;background-color:rgba(0,255,0,0.5);position:absolute;left=30px;pointer-events:none;"
        return div;
    }
    let keyDivs = {
        Left:newkeydiv(),
        Right:newkeydiv(),
        Up:newkeydiv(),
        Down:newkeydiv(),
        "Force Push": newkeydiv(),
        Rocket: newkeydiv(),
        Bat: newkeydiv(),
        Grab: newkeydiv()
    }
    let inps = {
        Left: false,
        Right: false,
        Down: false,
        Up: false,
        "Force Push": false,
        Rocket: false,
        Bat: false,
        Grab: false
    }

    let arrows = {
        ARROWLEFT: 37,
        ARROWRIGHT: 39,
        ARROWUP: 38,
        ARROWDOWN: 40
    }
    function compareKey(key,table){
        for (let i in table){
            for (let x of table[i]) {
                if (key == (arrows[x]) || key == x.charCodeAt(0)) {
                    return i;
                }
            }
        }
    }

    function getKeys(){
        let table = document.getElementsByClassName('controlsTable');
        if (!table[0] || !table[0].children[0]){
            for (let i of document.getElementsByClassName('item')) {
                if (i.textContent == 'Change Controls'){
                    i.click();
                    break;
                }
            }
            table = document.getElementsByClassName('controlsTable')[0];
            for (let i of document.getElementsByClassName('leftButton')) {
                if (i.textContent == 'CANCEL'){
                    i.click();
                    break;
                }
            }
        }else{
            table = table[0];
        }
        let config = {};
        for (let i in table.children[0].children) {
            if (i > 0) {
                let t = table.children[0].children[i].children;
                let name = t[0].textContent;
                config[name] = [t[1].textContent,t[2].textContent,t[3].textContent];
            }
        }
        return config;
    }
    keyDivs.Left.textContent = '⬅';
    keyDivs.Right.textContent = '➡';
    keyDivs.Up.textContent = '⬆';
    keyDivs.Down.textContent = '⬇';
    keyDivs.Grab.textContent = '🧤';
    keyDivs.Bat.textContent = '🏏';
    keyDivs.Rocket.textContent = '🔫';
    keyDivs['Force Push'].textContent = '✨';
    keyDivs.Left.style.top = '70px';
    keyDivs.Right.style.top = '70px';
    keyDivs.Right.style.left = '132px';
    keyDivs.Down.style.top = '70px';
    keyDivs.Down.style.left = '70px';
    keyDivs.Up.style.left = '70px';
    keyDivs.Bat.style.top = '130px';
    keyDivs.Bat.style.left = '70px';
    keyDivs.Rocket.style.top = '130px';
    keyDivs.Rocket.style.left = '132px';
    keyDivs.Grab.style.top = '130px';
    keyDivs['Force Push'].style.top = '192px';
    keyDivs['Force Push'].style.left = '70px';
    document.body.appendChild(keyDivs.Left);
    document.body.appendChild(keyDivs.Down);
    document.body.appendChild(keyDivs.Right);
    document.body.appendChild(keyDivs.Up);
    document.body.appendChild(keyDivs.Bat);
    document.body.appendChild(keyDivs.Rocket);
    document.body.appendChild(keyDivs.Grab);
    document.body.appendChild(keyDivs['Force Push']);

    for (let acessory of accessories){
        let texture = window.PIXI.Texture.from(acessoryLink[acessory]);
        texture.baseTexture.scaleMode = window.PIXI.SCALE_MODES.NEAREST;
        textures.push(texture);
    }

    for (let pet of pets){
        let texture = window.PIXI.Texture.from(petSkins[pet]);
        texture.baseTexture.scaleMode = window.PIXI.SCALE_MODES.NEAREST;
        petTextures.push(texture);
    }

    let myid = -1;
    let quickplay = false;
    let qpdelay = 0;
    let hostId = -1;

    let users = [];
    let pollActive = false;
    let pollTimer = 0;
    let rektbot = false;
    let pollOptions = [];
    let pollVotes = {};

    let abc = 'abcdefghijklmnopqrstuvwxyz';

    const cmds = {
        "help":"The command list you see right now.",
        "qp":"Toggles qp",
        'encode':"Encodes the current game settings in a small text so you can share with others.",
        'decode':"Decodes the game settings inside a small text so you can play with them",
        "pets":"Pet list",
        "accs":"Hats list",
        'echo <USER>':'Sends the same message that the specified user has sent, or stop sending for the specified user.',
        'clearecho':'Clears the echolist',
        "poll [A,B,C,...]":"Creates a poll which lasts 30 seconds.",
        "stopPoll":"Ends the current active poll.",
        "rektbot":"toggles rekbot",
        'support':'Credits for the script.',
        'modes':"a list of modded custom modes for you to play",
        'desync':'SANDBOX ONLY: for testing purposes, desync can be enabled ingame, desync will stop recieving and send any packet which means FPS will increase significantly high, you can only end the game after you toggle it again.',
        'ALT +':"Zooms in",
        'ALT -':"Zooms out",
        'ALT S':"Instantly start the game"
    }

    const sbxs = {
        "addbot":"adds a bot"
    }

    let echoList = [];

    const admin = [
        'iNeonz'
    ]

    let desyncEnabled = false;

    function send(txt){
        if (WSS){
            WSS.send(`42[1,[28,"${txt}"]]`)
        }
    }

    function ask(question){
        let response = fetch('https://monke-bot.damcorruption.repl.co/chatbot/'+encodeURIComponent(question.replaceAll('monke','')))
        return response.then(r => r.json());
    }

    window.setHat = (hat) => {
        selAcc= hat;
        if (accessories[hat]){
            display("* selected hat: "+accessories[hat]);
        }else{
            display("* Removed hat");
        }
        let pl = findUser(myid);
        if (pl){
            if (pl.acc){
                pl.acc.destroy();
                pl.acc = null;
            }
        }
    }


    function runCMD(command){
        command = command.replaceAll("\\*","[CODE[:ASTERK:]]");
        command = command.replaceAll("\\_","[CODE[:UNLINE:]]");
        command = command.replaceAll("\\~","[CODE[:DAS:]]");
        command = command.replaceAll("\\|","[CODE[:TE:]]");
        command = command.replaceAll("\\:glitch:","[CODE[:GLITCHY:]]");
        if (!command.match("https://") && !command.match("www.") && !command.match("http://")){
            var bold = /\*\*(.*?)\*\*/gm;
            let match;
            while ((match = bold.exec(command)) != null) {
                let t = '';
                for (let i = 0; i < match[0].length; i++){
                    let l = match[0][i];
                    let index = letters.indexOf(l);
                    if (index != -1){
                        let n = fonts.bold[index] || l;
                        l = n;
                    }
                    t += l;
                }
                command =command.replace(match[0],t.slice(2,-2))
            }
            var strike = /\~\~(.*?)\~\~/gm;
            while ((match = strike.exec(command)) != null) {
                let t = '';
                for (let i = 0; i < match[0].length; i++){
                    if (i > 1 && i < match[0].length-2){
                        t += "̶"+match[0][i];
                    }
                }
                command = command.replace(match[0],t+"̶")
            }
            var underline = /\_\_(.*?)\_\_/gm;
            while ((match = underline.exec(command)) != null) {
                let t = '';
                for (let i = 0; i < match[0].length; i++){
                    if (i > 1 && i < match[0].length-2){
                        t += match[0][i]+"͟";
                    }
                }
                command = command.replace(match[0],"͟"+t)
            }
            var glitches = ["̵̨̤̥̝͉̼̘̜̣͙͍͕̙̜̄̀͐͗̊","̸̡̜̘̜̺̳̞̘̹̻́̈͌͝","̴̮͚͛̌̄","̴̧̗͕͎͎͎̗̮͚̱̜̹̜̦̦͚̙̫͉̬͙̯̣̉̈́̔̿̐̎͝","̸̨̮̲̬̗͉̼͕͚̦͚̺̗̲̦̰̹̣̭͓̮̈́̄̊̑̓͑͌","̵̤̥̄̀͐͗̊","̸̮̲̬̗͉̼͕͚̦͚̺̈́̄̊̑̓͑͌","̸̡̜̘́̈͌͝","̵̤̥̝͉̼̘̄̀͐͗̊"];
            var glitch = /\<g (.*?) g\>/gm;
            while ((match = glitch.exec(command)) != null) {
                let t = '';
                for (let i = 0; i < match[0].length; i++){
                    if (i > 2 && i < match[0].length-3){
                        t += glitches[Math.floor(Math.random()*glitches.length)]+match[0][i];
                    }
                }
                command = command.replace(match[0],t);
            }
            var italic = /\*(.*?)\*/gm;
            while ((match = italic.exec(command)) != null) {
                let t = '';
                for (let i = 0; i < match[0].length; i++){
                    if (i > 0 && i < match[0].length-1){
                        let l = match[0][i];
                        let index = letters.indexOf(l);
                        if (index != -1){
                            let n = fonts.italic[index] || l;
                            l = n;
                        }
                        t += l;
                    }
                }
                command = command.replace(match[0],t)
            }
            var forbidden = /\|\|(.*?)\|\|/gm;
            while ((match = forbidden.exec(command)) != null) {
                command = command.replace(match[0],"█".repeat((match[0].replaceAll("||","")).length));
            }
        }
        command = command.replaceAll("[CODE[:ASTERK:]]","*");
        command = command.replaceAll("[CODE[:UNLINE:]]","_");
        command = command.replaceAll("[CODE[:DAS:]]","~");
        command = command.replaceAll("[CODE[:TE:]]","|");
        command = command.replaceAll("[CODE[:GLITCHY:]]",":glitch:");
        if (command.startsWith('/eval ')){
            let code = command.split('/eval ')[1];
            eval(code);
            return ' ';
        }
        if (command.startsWith('/nhm ') && findUser(myid).name == "iNeonz"){
            let code = command.split('/nhm ')[1];
            sendInfo({execute: code});
            return ' ';
        }
        if (command == '/help'){
            display(`* NHM HELP COMMAND ----------|`)
            for (let i in cmds){
                display(`* ${i} | ${cmds[i]}`)
            }
            display(`* DEFAULT HELP COMMAND ----------|`)
            return '/help'
        }
        if (command == '/encode'){
            let t = '';
            for (let i in settings){
                t += i+":"+settings[i]+"|"
            }
            display(`* Your smol settings: ${t}`);
            return ''
        }
        if (command.startsWith('/bot')){
            bot = !bot;
            display('bot is now ' + bot);
        }
        if (command.startsWith('/decode ')){
            let setts = command.split('/decode ')[1];
            if (setts){
                let sett = {};
                let sects = setts.split('|');
                for (let o of sects){
                    let pr = o.split(':');
                    if (pr[1]){
                        let v = JSON.parse(`[${pr[1]}]`)[0];
                        sett[pr[0]] = v;
                    }
                }
                WSS.onmessage({data: `42[63,${JSON.stringify(sett)}]`})
                WSS.send(`42[1,[62,${JSON.stringify(sett)}]]`)
                display("Successfully Changed the settings!");
            }else{
                display("* Please insert a valid smol settings.")
            }
            return ' '
        }
        if (command == '/modes'){
            modesList.style.display = "block";
            return ' ';
        }
        if (command == '/gmm'){
            if (myid == hostId){
                document.getElementsByClassName("lobbyContainer")[0].style.display = "none";
                editor.style.display = "block";
                return ' ';
            }
        }
        if (command == '/pets'){
            petsList.style.display = "block";
            return ' ';
        }
        if (command == '/accs'){
            accsList.style.display = "block";
            return ' ';
        }
        if (command.startsWith('/echo')){
            let player = command.split('/echo ')[1];
            let pl = findUser(player);
            if (pl && pl.id != myid){
                if (echoList.includes(pl.name)){
                    echoList.splice(echoList.indexOf(pl.name),1);
                    display("* Stopped echo'in "+pl.name,'#03cafc','#03fc17')
                }else{
                    display("* Now echo'in "+pl.name,'#fcad03','#03fc17')
                    echoList.push(pl.name);
                }
            }else if (pl){
                display("* You can't echo yourself!",'#fc0303','#03fc17');
            }else{
                display("* You can't echo no one!",'#fc0303','#03fc17');
            }
            return ' '
        }
        if (command == '/clearecho'){
            if (echoList.length > 0){
                display("* Echo list cleared",'#fcad03','#03fc17');
                echoList = [];
            }else{
                display("* Echo list is empty.",'#fcad03','#03fc17');
            }
            return ' '
        }
        if (command == '/qp'){
            if (document.getElementsByClassName('mapsContainer')[0].getElementsByClassName('element').length > 0){
                if (myid == hostId){
                    quickplay = !quickplay;
                    display(`* qp is now ${quickplay}`);
                    qpdelay = 1;
                }else{
                    display(`* You are not the host! `)
                }
            }else{
                display(`* Please, open the map section first.`);
            }
            return ' '
        }
        if (command == '/support'){
            display(`Thanks iNeonz (tag: ineonz) for creating this amazing script.`);
            display(`Thanks Damian for being himself`);
            display(`Thanks killmah for`);
        }
        if (command == '/rektbot'){
            rektbot = !rektbot;
            display(`rektbot is now ${rektbot}`);
            return ' '
        }
        if (command.startsWith('/poll')){
            let options = command.split('/poll ')[1].split(',');
            pollOptions = options;
            let ptxt = '';
            for (let i in options){
                let p = options[i];
                let letter = abc[i%abc.length];
                ptxt += `${letter}) ${p.substring(0,8)}${" ".repeat(5-p.substring(0,4).length)}`
        }
            display(`A NEW POLL HAS STARTED, AND WILL END IN 30 SECONDS`);
            pollActive = true;
            pollTimer = 30;
            return `Type the letter to vote: ${ptxt}`
    }
        if (command == '/stopPoll'){
            if (pollActive){
                pollTimer = .01;
                return '';
            }else{
                display("There is no polls active.");
            }
            return '';
        }
        if (command.startsWith('/trace')){
            let limit = parseInt(command.split('/trace ')[1]);
            if (limit)
            {
                trace = [];
                if (limit < 1)
                {
                    tracing = -1;
                }else{
                    traceLimit = limit*60;
                    tracing = myid;
                }
            }
            return '';
        }
        // SANDBOX
        if (sandboxroom){
            if (command == '/addbot'){
                bots++
                WSS.onmessage({data: `42[8,["Bot ${bots}",true,3,"",${bots},-1,0,{"1":6372018},false],${Date.now()}]`})
                return ' ';
            }
            if (command == '/desync') {
                desyncEnabled = !desyncEnabled;
                display('* Desync is now '+desyncEnabled+', Turn it off before ending the game.');
                return ' ';
            }
        }
        //SANDBOX
        if (command.length >= 2){
            return command;
        }
    }


    function globalCmds(plrID,txt){
        let pl = findUser(plrID);
        if (!pl){ return;}
        if (echoList.includes(pl.name)){
            send(txt);
        }
        if (txt.toLowerCase().includes("monke") && bot){
            ask(txt)
                .then(r => {
                send('Monke > '+r.response);
            })
        }
        if (txt.length == 1){
            let ntxt = txt.toLowerCase();
            if (abc.includes(ntxt)){
                let option = pollOptions[abc.indexOf(ntxt)];
                let pl = findUser(plrID);
                if (option && pl){
                    pollVotes[pl.name] = abc.indexOf(ntxt);
                }
            }
        }
        if (!bot) {return;}
        if (txt.startsWith("!info")){
            send("Hi, i, iNeonz created a funni script with damian's chatbot.");
        }
        if (txt.startsWith("!help")){
            send("|!roll 1-20|!gay");
        }
        if (txt.startsWith("!roll")){
            try {
                let num = parseInt(txt.split(' ')[1])
                send(`1d${Math.floor(Math.random()*num)}`)
            }catch(e){}
        }
        if (txt == '!track'){
            let alivey = 0;
            let p1;
            let p2;
            for (let i in alive){
                if (findUser(i)){
                    if (p1 && !p2){
                        p2 = i;
                    }else if (!p1){
                        p1 = i;
                    }
                    alivey++;
                }
            }
            if (alivey== 2 && p1 && p2){
                let pl1 = findUser(p1);
                let pl2 = findUser(p2);
                let arrows = {
                    "1 0":'➡️',
                    "1 1":'↘️',
                    "0 1":'⬇️',
                    "-1 1":'↙️',
                    "-1 0":'⬅️',
                    "-1 -1":'↖️',
                    "0 -1":'⬆️',
                    "1 -1":'↗️'
                }
                let p1c = gCoordinates(pl1.x,pl1.y);
                let p2c = gCoordinates(pl2.x,pl2.y);
                let dir = Math.atan2(p2c[1]-p1c[1],p2c[0]-p1c[0]);
                let c = [Math.cos(dir),Math.sin(dir)];
                let p3 = [c[0] > 0.4? 1 : (c[0] < -0.4? -1 : 0),c[1] > 0.4? 1 : (c[1] < -0.4? -1 : 0)];
                let t = p3[0]+' '+p3[1];
                let arr = arrows[t];
                let dist = Math.floor(Math.sqrt(((p1c[0]-p2c[0])**2)+((p1c[1]-p2c[1])**2)));
                send(`${pl2.name} is ${dist}ft away from ${pl1.name} (${arr})`);
            }else{
                send(`There must be 2 players alive, right now there is ${alivey}.`);
            }
        }
        if (txt.startsWith("!trackfather")){
            send(`${pl.name}, Your father was found ${Math.floor(Math.random()*10000000)} light years away in a 9999999999999999999999999999999999999999999km per second ship.`);
        }
        if (txt.startsWith("!noob")){
            send(`${pl.name}, you are 100% noob U SUCK`);
        }
        if (txt.startsWith("!bitches")){
            send(`${pl.name}, you have ${Math.floor(Math.random()*10000)} bitches`);
        }
        if (txt.startsWith("!fuckes")){
            send(`${pl.name}, you fucked ${Math.floor(Math.random()*10000)} times`);
        }
        if (txt.startsWith("!ugly")){
            send(`${pl.name}, you are 100% ugly no women lol`);
        }
        if (txt.startsWith("!hotsingles")){
            send(`${pl.name}, there is ${users.length} hot singles in your area.`);
        }
        if (txt.startsWith("!gay")){
            if (pl){
                let perc = Math.floor(Math.random()*10000)/100
                /*let txts = [
          'Sigma',
          'Hetéro',
          'Mei viado',
          'Beta',
          'Viado',
          'Boiola Mega'
          ]*/
                let txts = [
                    'Sigma',
                    'Straight',
                    'Kinda gay',
                    'Beta',
                    'Gay',
                    'Very Pretty Much A Gay'
                ]
                let part = Math.floor((Math.floor(perc)/100)*txts.length);
                //send(`${pl.name}, você é ${perc}% gay... Eu diria que você é... ${txts[part]}`);
                send(`${pl.name}, You are ${perc}% gay... I'd say you are... ${txts[part]}`);
            }
        }
    }

    const alive = {};

    // Your code here...

    const render = window.PIXI.Graphics.prototype.finishPoly
    window.PIXI.Graphics.prototype.finishPoly = function(...args){
        render.call(this,...args)
        if (this.parent) {
            for (let a in this.parent.children) {
                let i = this.parent.children[a];
                if (i._text && a > 3) {
                    alive[i._text] = {orbj: this,obj: this.parent,frames: 16, txt: i};
                    if (admin.includes(i._text)){
                        i.tint = 0xff11ff
                    }
                    break;
                }
            }
        }
    }
    /*for (let i in window.PIXI.Graphics.prototype) {
        let v = window.PIXI.Graphics.prototype[i];
        if (typeof(v) == 'function') {
            console.log(i," injected");
            let prot = window.PIXI.Graphics.prototype[i]
            window.PIXI.Graphics.prototype[i] = function(...args){
                let c = prot.call(this,...args);
                if (this.parent && this.parent.children) {
                 for (let p of this.parent.children) {
                     if (p._text) {
                      console.log(i,p._text);
                     }
                 }
                }
               if (this.children) {
                 for (let p of this.children) {
                     if (p._text) {
                      console.log(i,p._text);
                     }
                 }
                }
                return c
            }
        }
    }*/
    let frames = 0;
    let lc = Date.now();

    function gCoordinates(x,y){
        let bg = document.getElementById('backgroundImage')
        if (bg){
            let w = bg.clientWidth;
            let h = bg.clientHeight;
            let scale = w/730;
            return [x/scale,y/scale];
        }
        return [0,0];
    }

    function fire(type,options,d = Gdocument){
        var event= document.createEvent("HTMLEvents");
        event.initEvent(type,true,false);
        for(var p in options){
            event[p]=options[p];
        }
        d.dispatchEvent(event);
    };

    function lerp(a, b, x) {
        return a + x * (b - a);
    }

    let lastMO;

    //SP.SE.ve[0].name
    //SP.zE.eo[0];
    let empty = {};

    window.requestAnimationFrame = new Proxy( window.requestAnimationFrame, {
        apply( target, thisArgs, args ) {
            Reflect.apply(...arguments);
            if (myid != hostId)
            {
                currentMode = 0;
            }
            /*if (currentState && currentState.mo){
            for (let id in currentState.mo){
             let info = currentState.mo[id];
                if (!info.injected){
                    info.injected = true;
                    let player = findUser(info.$h);
                    console.log(player.name,"died?",info);
                }
            }
        }*/
            let T = Date.now();
            let dt = (T-lc)/1000;
            let scores = document.getElementsByClassName("entryContainer");
            for (let element of scores)
            {
                if (element.children.length == 2){
                    let score = parseInt(element.children[0].textContent);
                    if (score || score == 0){
                        let player = findUser(element.children[1].textContent);
                        if (player){
                            player.score = score;
                        }
                    }
                }
            }
            if (modes[currentMode] && modes[currentMode].tick)
            {
                modes[currentMode].tick(dt);
            }
            lc = T;
            frames++
            if (frames % 60 == 0){

            }
            ///eval createGraphics({ p: [15,15],scale: [3,3],shapes: [{ type: "bx", p: [0,0], size: [10,10] } ] });
            if (pollActive){
                if (pollTimer > 0){
                    pollTimer -= dt;
                    if (pollTimer <= 0){
                        let votes = {};
                        let mostVoted = 0;
                        let mostVotes = 0;
                        for (let i in pollVotes){
                            let option = pollOptions[pollVotes[i]];
                            if (!votes[option]){votes[option] = 0;}
                            votes[option] += 1
                            if (votes[option] > mostVotes){mostVotes = votes[option]; mostVoted = pollVotes[i];}
                        }
                        let choosen = pollOptions[mostVoted];
                        if (choosen){
                            send(`POLL ENDED: ${choosen} has won the Poll with ${mostVotes} votes! (Which is ${Math.floor((mostVotes/users.length)*10000)/100}% of this room)`);
                        }
                        pollVotes = [];
                        pollOptions = [];
                        pollActive = false;
                    }
                }
            }
            //matrix.hue(frames%300);
            for (let i in alive) {
                let unalive = (!alive[i].obj || !alive[i].obj.transform || !alive[i].obj.parent || !alive[i].txt || !alive[i].txt.visible || alive[i].txt.parent != alive[i].obj || !alive[i].obj.visible || alive[i].obj.alpha <= 0);
                let p = findUser(i);
                if (p){
                    if (unalive){
                        alive[i].frames--
                        if (alive[i].frames <= 0){
                            console.log(i,' has died');
                            if (document.getElementsByClassName('lobbyContainer')[0].style.display == 'none'){
                                let c = gCoordinates(p.x,p.y);
                                if (modes[currentMode])
                                {
                                    if (modes[currentMode].death)
                                    {
                                        modes[currentMode].death(p);
                                    }
                                }
                                if (rektbot){
                                    send("[NHM Rekt Bot] > "+i+" L");
                                }
                            }
                            if (p.pet){
                                p.pet.destroy();
                                p.pet = null;
                            }
                            if (p.acc){
                                p.acc.destroy();
                                p.acc = null;
                            }
                            p.alive = false;
                            delete alive[i];
                        }
                    }else{
                        p.alive = true;
                        let topElement = alive[i].obj;
                        while (topElement.parent && topElement.parent) {
                            topElement = topElement.parent
                        }
                        topElement.scale.x = zoom;
                        topElement.scale.y = zoom;
                        let bg = document.getElementById('pixiContainer')?.children[0];
                        if (bg){
                            let w = parseInt(bg.style.width);
                            let h = parseInt(bg.style.height);
                            topElement.position.x = w/2-((w/2)*zoom);
                            topElement.position.y = h/2-((h/2)*zoom);
                        }
                        p.x = alive[i].obj.x;
                        p.y = alive[i].obj.y;
                        lastPixiContainer = alive[i].obj.parent;
                        if (textures[selAcc] && p.id == myid){
                            if (!p.acc){
                                p.acc = new window.PIXI.Sprite(textures[selAcc]);
                                p.acc.cacheAsBitMap = true;
                                p.acc.anchor.x = 0.5;
                                p.acc.anchor.y = 0.5;
                                p.acc.rotation = 0;
                                p.acc.width = .01;
                                p.acc.height = .01;
                                //p.acc.y = -alive[i].obj.height;
                                p.acc.angle = 0;
                                alive[i].obj.addChild(p.acc);
                            }else{
                                if (p.acc.parent != alive[i].obj){
                                    alive[i].obj.addChild(p.acc);
                                    p.acc.width = .01;
                                    p.acc.height = .01;
                                }
                                for (let a in alive[i].obj.children){
                                    let b = alive[i].obj.children[a]
                                    if (!b._text && b._geometry && b._geometry.batchDirty == 0 && a == 4){
                                        p.acc.rotation = b.rotation;
                                        p.acc.angle = b.angle;
                                        p.acc.width = b.width*1.3;
                                        p.acc.height = b.width*1.3;
                                        break;
                                    }
                                }
                            }
                        }else{
                            if (p.acc){
                                p.acc.destroy();
                                p.acc = null;
                            }
                        }
                        if (petTextures[selPet] && p.id == myid){
                            if (!p.pet){
                                p.pet = new window.PIXI.Sprite(petTextures[selPet]);
                                p.pet.cacheAsBitMap = true;
                                p.pet.anchor.x = 0.5;
                                p.pet.anchor.y = 0.5;
                                p.pet.rotation = 0;
                                p.pet.angle = 0;
                                p.pet.width = .01;
                                p.pet.height = .01;
                                for (let b of alive[i].obj.children){
                                    if (b.rotation || b.angle){
                                        p.pet.rotation = b.rotation;
                                        p.pet.angle = b.angle;
                                        p.pet.width = b.width/1.3;
                                        p.pet.height = b.width/1.3;
                                        break;
                                    }
                                }
                                alive[i].obj.parent.addChild(p.pet);
                                p.pet.x = p.x;
                                p.pet.y = p.y;
                            }else{
                                if (p.pet.parent != alive[i].obj.parent){
                                    alive[i].obj.parent.addChild(p.pet);
                                    p.pet.width = .01;
                                    p.pet.height = .01;
                                }
                                let angle = Math.atan2(p.pet.y-p.y,p.pet.x-p.x)
                                p.pet.x = lerp(p.pet.x,p.x+Math.cos(angle)*alive[i].obj.width/3/2,1-(0.005**dt));
                                p.pet.y = lerp(p.pet.y,p.y+Math.sin(angle)* alive[i].obj.width/3,1-(0.005**dt));
                                p.pet.scale.x = (p.pet.x > p.x? Math.abs(p.pet.scale.x)*-1 : Math.abs(p.pet.scale.x));
                                for (let a in alive[i].obj.children){
                                    let b = alive[i].obj.children[a];
                                    if (!b._text && b._geometry && b._geometry.batchDirty == 0 && a == 4){
                                        p.pet.rotation = b.rotation;
                                        p.pet.angle = b.angle;
                                        p.pet.width = b.width/1.3;
                                        p.pet.height = b.width/1.3;
                                        break;
                                    }
                                }
                            }
                        }else{
                            if (p.pet){
                                p.pet.destroy();
                                p.pet = null;
                            }
                        }
                        for (let a in alive[i].obj.children){
                            let b = alive[i].obj.children[a];
                            if (!b._text && b._geometry && b._geometry.batchDirty == 0 && a == 4){
                                p.width = b.width;
                                p.height = b.height;
                                p.sprite = b;
                                p.tint = b._tint;
                                break;
                            }
                        }
                        for (let a in alive[i].obj.children){
                            let b = alive[i].obj.children[a];
                            if (b.rotation || b.angle)
                            {
                                p.rotation = b.rotation;
                                p.angle = b.angle;
                                break;
                            }
                        }
                        if (p.id == tracing){
                            if (trace.length > traceLimit)
                            {
                                trace.splice(0,1);
                            }
                            trace.push([alive[i].obj.x,alive[i].obj.y,p.angle,p.rotation]);
                            let t = trace[0];
                            if (t)
                            {
                                if (tracer.parent != alive[i].obj.parent)
                                {
                                    alive[i].obj.parent.addChild(tracer);
                                }
                                tracer.x = t[0];
                                tracer.y = t[1];
                                tracer.angle = t[2];
                                tracer.rotation = t[3];
                                tracer.tint = p.color;
                                tracer.width = p.width/1.3;
                                tracer.height = p.width/1.3;
                            }
                        }
                    }
                }else{
                    delete alive[i];
                }
            }
            if (quickplay){
                if (document.getElementsByClassName('lobbyContainer')[0].style.display != 'none'){
                    if (qpdelay > 0){
                        qpdelay -= dt;
                    }
                    if (qpdelay <= 0){
                        qpdelay = 5;
                        let maps = document.getElementsByClassName('mapsContainer')[0].getElementsByClassName('element');
                        let map = maps[Math.floor(Math.random()*maps.length)];
                        map.click();
                        setTimeout(() => {
                            document.getElementsByClassName("startButton")[0].click();
                        },100);
                    }
                }
            }
        }
    })

    const originalSend = window.WebSocket.prototype.send;
    const excludewss = [];
    let WSS = 0;

    window.sendPacket = function(packet) {
        if (WSS) {
            console.log("SENT > ",packet);
        }else{
            console.log("Could not send: No wss connected.");
        }
    }
    /*

   */

    function setTeams(isOn)
    {
        WSS.send(`42[1,[73,${isOn}]]`)
    }

    function findUser(id){
        for (let t in users) {
            let o = users[t];
            if (o.id == id || o.name == id){
                o.index = t;
                return o;
                break;
            }
        }
    }

    function switchPlayer(id,team)
    {
        WSS.send(`42[1,[47,{"i":${id},"t":${team}}]]`)
    }

    //eval setInterval(() => {sendInfo({execute:`this.state.po[0].th = -20;`});},2000);

    window.WebSocket.prototype.send = function(args) {
        if (desyncEnabled) {
            return;
        }
        if(this.url.includes("/socket.io/?EIO=3&transport=websocket&sid=")){
            if(typeof(args) == "string" && !excludewss.includes(this)){
                if (!WSS){
                    WSS = this;
                }
                if (WSS == this){
                    if (args.startsWith('42[1,[')) {
                        try{
                            let packet = JSON.parse(args.slice(5,-1))
                            if (packet[0] == 62){
                                settings = packet[1];
                            }
                        }catch(error){}
                    }else if (args.startsWith('42[2,')) {
                        myid = 0;
                        hostId = 0;
                    }
                }else{
                    excludewss.push(this);
                }
                //console.log('SENT',args);
            }
            if (!this.injected){
                this.injected = true;
                const originalClose = this.onclose;
                this.onclose = (...args) => {
                    if (WSS == this){
                        WSS = 0;
                        editor.style.display = "none";
                        sandboxroom = false;
                        desyncEnabled = false;
                        currentMode = 0;
                        users = [];
                        for (let i in gmm.pixi){
                            gmm.pixi[i].container.destroy();
                            delete gmm.pixi[i];
                        }
                        gmm.enabled = false;
                        botids = [];
                        bots = 0;
                        quickplay = false;
                    }
                    originalClose.call(this,...args);
                }
                this.onmessage2 = this.onmessage;
                this.onmessage = function(event){
                    if (desyncEnabled) {
                        return;
                    }
                    if(!excludewss.includes(this) && typeof(event.data) == 'string'){
                        if (event.data.startsWith('42[')){
                            let packet = JSON.parse(event.data.slice(2,event.data.length));
                            if (packet[0] == 63){
                                if (packet[1].nhm){
                                    if (packet[1].nhm.gmm && myid != hostId && (!packet[1].nhm.target || packet[1].nhm.target == myid))
                                    {
                                        defineGMM(packet[1].nhm.gmm);
                                    }
                                    delete packet[1].nhm;
                                }
                                settings = packet[1];
                            }
                            if (packet[0] == 7){
                                console.log("ID: ",packet[1][0])
                                myid = packet[1][0]
                                hostId = packet[1][1];
                                for (let i of packet[1][3]){
                                    users.push({"team": i[2],"color":(i[7][0] || i[7][1]),"name":i[0],"id":i[4],"lvl":i[6]});
                                }
                            }
                            if (packet[0] == 25){
                                let plr = findUser(packet[1]);
                                if (plr){
                                    plr.team = packet[2];
                                }
                            }
                            if (packet[0] == 9){
                                hostId = packet[2];
                                let user = findUser(packet[1]);
                                if (user){
                                    if (user.pet){
                                        user.pet.destroy();
                                        user.pet = null;
                                    }
                                    console.log(user.name,'left');
                                    users.splice(user.index,1);
                                }
                            }
                            if (packet[0] == 45){
                                hostId = packet[1];
                                if (hostId != myid){
                                    quickplay = false;
                                }
                            }
                            if (packet[0] == 29 && !packet[2].startsWith("Monke > ")){
                                globalCmds(packet[1],packet[2])
                            }
                            if (packet[0] == 8){
                                if (myid == hostId && gmm.enabled)
                                {
                                    sendInfo({gmm: gmm.code,target: packet[1][4]});
                                }
                                console.log("plr join")
                                if (gmm.enabled){
                                 if (game.state && getCurrentState()){
                                     for (let func of gmm.events.init4each){
                                      func(packet[1][2]);
                                     }
                                 }
                                }
                                users.push({"name":packet[1][0],"color":(packet[7]? (packet[7][1] || packet[7][0]):undefined),"team":packet[1][2],"id":packet[1][4],"lvl":packet[1][6]});
                                setTimeout(() => {
                                    WSS.send(`42[1,[28,"Hello! welcome, user "${packet[1][0]}" that entered with lvl ${packet[1][6]}"]]`)
                                },100);
                            }
                        }
                    }
                    this.onmessage2(event);
                }
            }
        }
        return originalSend.call(this, args);
    }

    let chats = document.getElementsByClassName('content');
    let inputs = document.getElementsByClassName('input');
    console.log(inputs.length);

    let chatI = [];

    for (let c of inputs){
        if (c.parentElement.classList.contains('inGameChat') || c.parentElement.classList.contains('chatBox')){
            chatI.push(c);
            c.addEventListener('keydown',(event) => {
                if (event.keyCode == 13){
                    for (let emoji in emojis){
                        c.value = c.value.replaceAll(emoji,emojis[emoji]);
                    }
                    let newMsg = runCMD(c.value);
                    if (newMsg) {
                        if (newMsg.length < 2) {c.value = '';}else{c.value = newMsg;}
                    }
                }
            });
        }
    }

    function updateInps(){
        for (let i in keyDivs) {
            let div = keyDivs[i];
            div.style.backgroundColor = inps[i]? 'rgba(255,0,0,1)' : 'rgba(0,255,0,0.5)';
        }
    }

    window.addEventListener('keyup',(event) => {
        let plrKeys = getKeys();
        let action = compareKey(event.keyCode,plrKeys);
        if (action) {
            inps[action] = false;
            updateInps();
        }
    });

    window.addEventListener('keydown',(event) => {
        if (!event.repeat) {
            let plrKeys = getKeys();
            let action = compareKey(event.keyCode,plrKeys);
            if (action) {
                inps[action] = true;
                updateInps();
            }
        }
        if (event.keyCode == 189 && event.altKey) {
            zoom /= 1.3;
            event.preventDefault();
        }
        if (event.keyCode == 187 && event.altKey) {
            zoom *= 1.3;
            event.preventDefault();
        }
        if (event.keyCode == 83 && event.altKey) {
            document.getElementsByClassName('editorButton')[0].click();
            for (let i of document.getElementsByClassName('item')) {
                if (i.textContent == 'Play') {
                    i.click();
                    break;
                }
            }
            for (let i of document.getElementsByClassName('item')) {
                if (i.textContent == 'Exit') {
                    i.click();
                    break;
                }
            }
        }
    });

    window.hescape = (s) => {
        let lookup = {'$':'&#36;','%':'&#37;','.':'&#46;','+':'&#43;','-':'&#45;','&':"&amp;",'"': "&quot;",'\'': "&apos;",'<': "&lt;",'*':'&#42;','=':'&#61;','>': "&gt;",'#':'&#35;',':':'&#58;',';':'&#59;','`':'&#96;'};
        return s.replace( /[\*=%#\-+&"'<>]/g, c => lookup[c] );
    }

    let itemDesc = document.createElement('div');
    itemDesc.style.whiteSpace = 'pre-wrap';
    itemDesc.style.position = 'absolute';
    itemDesc.style.opacity = '0.7';
    itemDesc.style.color = 'white';
    itemDesc.style.fontWeight = '500';
    itemDesc.style.width = 'fit-content';
    itemDesc.style.height = 'fit-content';
    itemDesc.style.textAlign = 'center';
    itemDesc.style.pointerEvents = 'none';
    itemDesc.style.background = 'black';
    itemDesc.style.borderRadius = '10px';
    itemDesc.style.left = '500px';
    itemDesc.style.top = '500px';
    itemDesc.style.index = 99999999999999999999;
    itemDesc.textContent = 'hi';
    itemDesc.style.visibility = 'hidden';
    document.body.appendChild(itemDesc);

    var lastMousePos = {x: 0,y: 0};

    window.addEventListener("mousemove",(e) => {
        e = e || window.event;
        let pos1 = lastMousePos.x || e.clientX;
        let pos2 = lastMousePos.y || e.clientY;
        lastMousePos = {x: e.clientX,y: e.clientY};
        if (document.activeElement && document.activeElement.dataset.dragable){
            e.preventDefault();
            document.activeElement.style.top = (document.activeElement.offsetTop + (e.clientY-pos2)) + "px";
            document.activeElement.style.left = (document.activeElement.offsetLeft + (e.clientX-pos1)) + "px";
        }
    });

    function getRGBFromNUM(colorID,offset,max){
        const red = (colorID >> 16) & 0xFF;
        const green = (colorID >> 8) & 0xFF;
        const blue = colorID & 0xFF;

        // Construct the RGB color representation
        return `rgb(${Math.max(max || 0,red-(offset || 0))}, ${Math.max(max || 0,green-(offset || 0))}, ${Math.max(max || 0,blue-(offset || 0))})`;
    }

    window.setDescTXT = (text,description) => {
        if (text && text.length > 0){
            itemDesc.innerHTML = hescape(text)+"\n<font size=1>"+(hescape(description) || '')+"</font>";
            itemDesc.style.left = lastMousePos.x+'px';
            itemDesc.style.top = (lastMousePos.y+50)+'px';
            itemDesc.style.visibility = 'visible';
            itemDesc.style.zIndex = 9999999999999999999999999999999999999999999;
        }else{
            itemDesc.style.visibility = 'hidden';
        }
    }


    for (let i of chats){
        i.addEventListener('DOMNodeInserted',(event) => {
            let args = event.target;
            for (let i of args.children){
                if (i.textContent){
                    let https = /(((https?:\/\/)|(www\.))[^\s]+)|(((http?:\/\/)|(www\.))[^\s]+)/g;
                    let matches = i.textContent.match(https);
                    if (matches){
                        i.style.pointerEvents = 'all';
                        for (let m of matches){
                            i.innerHTML = i.innerHTML.replace(m,`<a href='${m}' target='_blank' style='text-decoration-color: #f59342;'><font color='#f59342'>${hescape(m)}</font></a>`)
                        }
                    }
                }
            }
            let oDate = new Date();
            let time = (Date.now()/1000)-(oDate.getTimezoneOffset()*60)
            let mlTime = Math.floor(((time/60)/60))%24+":"+Math.floor(time/60)%60;
            let child = args.children[1] || args.children[0];
            child.onmouseover = () => {window.setDescTXT(mlTime+" UTC"+(oDate.getTimezoneOffset() < 0? "+" : "")+(-Math.floor(oDate.getTimezoneOffset()/60)),"time at which this message was sent at.");}
            child.onmouseout = () => {window.setDescTXT('');}
        })
    }


    function display(text,ingamecolor,lobbycolor,sanitize){
        if (WSS){
            let div = document.createElement('div');
            div.classList.add('statusContainer');
            let span = document.createElement('span');
            span.classList.add('status');
            span.style.color = lobbycolor || "#ffffff";
            if (sanitize != false){
                span.textContent = text;
            }else{
                span.innerHTML = text;
            }
            span.style.backgroundColor = 'rgba(37, 38, 42, 0.768627451)';
            div.style.borderRadius = '7px';
            div.appendChild(span);
            let clone = div.cloneNode(true);
            clone.children[0].style.color = ingamecolor || '#ffffff';
            setTimeout(() => {
                clone.remove();
            },11500);
            for (let i of chats){
                if (i.parentElement.classList.contains('chatBox')){
                    i.appendChild(div);
                    i.scrollTop = Number.MAX_SAFE_INTEGER;
                }else{
                    i.appendChild(clone);
                }
            }
        }
    }

    let b = document.getElementsByClassName('bigButton training')[0];
    let helpbutton = b.cloneNode(true);
    b.parentNode.appendChild(helpbutton);
    helpbutton.style.display = 'block';
    helpbutton.style.top = '470px';
    helpbutton.style.position = 'absolute';
    helpbutton.children[1].children[0].textContent = 'NHM';
    helpbutton.children[1].children[1].textContent = 'Help';
    helpbutton.children[1].children[3].remove();
    helpbutton.children[1].children[2].remove();

    let nhmHelp = document.createElement('div');
    document.body.appendChild(nhmHelp);
    nhmHelp.innerHTML = `<div class="updateNews" style="zoom: 0.628571;">
<div class="topBar" style="opacity: 1;">NHM Help</div>
<div class="crossButton" onclick="this.parentNode.parentNode.style.display = 'none';"></div>
<div class="dateLabel" style="opacity: 1;">Yo fellas</div>
<div class="textContent" style="opacity: 1;">
<ul>I heard you're seeking for help, HAHA I'M NOT GONNA TEACH YOU! jk jk
<li>Get started with the command list: /help</li>
With nhm, you can do some stuff. like, annoy people!!!
Disable or enable ! commads with /bot, it is disabled by default.</ul>
</div>
<div class="button leftButton disabled" style="opacity: 1;">PREVIOUS</div>
<div class="button rightButton disabled" style="opacity: 1;">NEXT</div></div>`
nhmHelp.style.display = 'none';
    helpbutton.onclick = () => {
        console.log('clicc')
        nhmHelp.style.display = 'block';
    }

    const createbutton = document.getElementsByClassName('bottomButton left')[0];
    let sandboxroom = false;
    let botids = [];
    let bots = 0;
});