Precise slither

Simplified client for slither.io

// ==UserScript==
// @name         Precise slither
// @namespace    precise_slither
// @version      0.2
// @description  Simplified client for slither.io
// @author       Sr_2_0
// @match        *://slither.com/io
// @match        *://slither.io/
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // you can change these values
    const serverIpAndPortForInputField_29 = '57.129.37.42:444';
    const maxFps_29 = 40;

    // rewrite original slither client
    document.getElementsByTagName('html')[0].innerHTML = `
        <head>
            <title>precise slither</title>
        </head>
        <body>
        </body>
    `;

    let ws_29;

    let myId_29 = -1;
    let myIdWas_29 = false;

    let snakes_29 = [];
    let preys_29 = [];
    let sectors_29 = [];
    let foods_29 = [];
    let foods_c_29 = 0;

    let grd_29 = 16384;
    let mscps_29 = 0;
    let fmlts_29 = [];
    let fpsls_29 = [];
    let sector_size_29 = 480;
    let spangdv_29 = 4.8;
    let nsp1_29 = 4.25;
    let nsp2_29 = .5;
    let nsp3_29 = 12;
    let mamu_29 = .033;
    let mamu2_29 = .028;
    let cst_29 = .43;
    let protocol_version_29 = 2;

    let real_flux_grd_29 = grd_29;
    let rfgrdForMinimap_29 = real_flux_grd_29;

    let playersInfo_29 = "";

    let minimapObjs_29 = [];

    let vfr_29 = 0;
    let vfrb_29 = 0;
    let fr_29 = 0;
    let lfr_29 = 0;

    let ltm_29 = Date.now();

    let last_ping_mtm_29 = 0;
    let wfpr_29 = false;

    let last_accel_mtm_29 = 0;
    let lstSnddAclState_29 = false;
    let acceleration_29 = false;

    let last_e_mtm_29 = 0;
    let prevComndForEang_29 = -1;
    let whereMouseX_29 = -1;
    let whereMouseY_29 = -1;

    let oefTimerId_29;
    let oefTimerStarted_29 = false;

    let lastStartOtrisTime_29;

    let currentFps_29 = 0;
    let currentFpsLastShowTime_29 = 0;

    let gameExists_29 = false;
    let wantCloseCurrentGame_29 = false;
    let wantNewGame_29 = false;
    let buttonFunctionality_29 = true;

    let xx_29 = 0;
    let yy_29 = 0;
    let cm1_29;

    const pi2_29 = 2 * Math.PI;

    function prepareNewGame_29() {
        gameExists_29 = true;
        myIdWas_29 = false;
        snakes_29 = [];
        preys_29 = [];
        sectors_29 = [];
        foods_29 = [];
        foods_c_29 = 0;
        xx_29 = 0;
        yy_29 = 0;
        playersInfo_29 = "";
        minimapObjs_29 = [];
        last_ping_mtm_29 = 0;
        wfpr_29 = false;
        last_accel_mtm_29 = 0;
        lstSnddAclState_29 = false;
        acceleration_29 = false;
        last_e_mtm_29 = 0;
        prevComndForEang_29 = -1;
        whereMouseX_29 = -1;
        whereMouseY_29 = -1;
        connect_29();
    }

    function decodeSecret_29(sv, idba) {
        function qff9x_29(b) {
            eval(b);
            if (0 < idba.length) {
                b = 0;
                for (let d, a, e, c = 0; c < idba.length; c++) {
                    d = 65,
                    a = idba[c],
                    97 <= a && (d += 32, a -= 32),
                    a -= 65,
                    0 == c && (b = 2 + a),
                    e = a + b,
                    e %= 26,
                    b += 3 + a,
                    idba[c] = e + d;
                }
            }
        };
        let a = "", b;
        for (let d = 0, e = 23, f = 0, g = 0; g < sv.length; ) {
            b = sv[g],
            g++,
            96 >= b && (b += 32),
            b = (b - 97 - e) % 26,
            0 > b && (b += 26),
            d *= 16,
            d += b,
            e += 17,
            1 == f ? (a += String.fromCharCode(d), f = d = 0) : f++;
        }
        qff9x_29(a);
        for (a = 0; a < sv.length; a++)
            if (b = sv[a], 65 > b || 122 < b)
                return !1;
        return !0;
    };

    // needed to calculate a score
    function setMscps_29(nmscps) {
        if (nmscps != mscps_29) {
            mscps_29 = nmscps;
            fmlts_29 = [];
            fpsls_29 = [];
            for (let i = 0; i <= mscps_29; i++) {
                if (i >= mscps_29)
                    fmlts_29.push(fmlts_29[i - 1]);
                else
                    fmlts_29.push(Math.pow(1 - i / mscps_29, 2.25));
                if (i == 0)
                    fpsls_29.push(0);
                else
                    fpsls_29.push(fpsls_29[i - 1] + 1 / fmlts_29[i - 1])
            }
            let t_fmlt = fmlts_29[fmlts_29.length - 1];
            let t_fpsl = fpsls_29[fpsls_29.length - 1];
            for (let i = 0; i < 2048; i++) {
                fmlts_29.push(t_fmlt);
                fpsls_29.push(t_fpsl)
            }
        }
    }

    function newSnake_29(id, xx, yy, cv, ang, pts) {
        let o = {};
        o.id = id;
        o.xx = xx;
        o.yy = yy;
        o.chl = 0;
        o.tsp = 0;
        o.sc = 1;
        o.ssp = nsp1_29 + nsp2_29 * o.sc;
        o.fsp = o.ssp + .1;
        o.msp = nsp3_29;
        o.msl = 42;
        o.fam = 0;
        o.rsc = 0;
        o.ang = ang;
        o.eang = ang;
        o.wang = ang;
        o.sp = 2;
        if (pts) {
            o.pts = pts;
            o.sct = pts.length;
        } else {
            o.pts = [];
            o.sct = 0
        }
        o.tl = o.sct + o.fam;
        o.cfl = o.tl;
        o.scang = 1;
        snakes_29.push(o);
        return o;
    }

    function newPrey_29(id, xx, yy, rad, dir, wang, ang, speed) {
        let pr = {};
        pr.id = id;
        pr.xx = xx;
        pr.yy = yy;
        pr.sz = rad;
        pr.dir = dir;
        pr.wang = wang;
        pr.ang = ang;
        pr.sp = speed;
        preys_29.push(pr);
        return pr;
    }

    function newFood_29(id, xx, yy, rad) {
        let fo = {};
        fo.id = id;
        fo.xx = xx;
        fo.yy = yy;
        fo.sz = rad;
        foods_29[foods_c_29++] = fo;
        return fo;
    }

    // function is executed before each frame is drawn
    function oef_29() {
        let ctm = Date.now();
        vfr_29 = (ctm - ltm_29) / 8;
        if (vfr_29 > 5)
            vfr_29 = 5;
        if (vfr_29 < 1.56)
            vfr_29 = 1.56;
        ltm_29 = ctm;
        lfr_29 = fr_29;
        fr_29 += vfr_29;
        vfrb_29 = Math.floor(fr_29) - Math.floor(lfr_29);

        if (!wantCloseCurrentGame_29 && !wfpr_29) {
            if (ctm - last_ping_mtm_29 > 250) {
                last_ping_mtm_29 = ctm;
                wfpr_29 = true;
                const ba = new Uint8Array([251]);
                ws_29.send(ba);
            }
        }
        if (!wantCloseCurrentGame_29 && acceleration_29 != lstSnddAclState_29 && ctm - last_accel_mtm_29 > 150) {
            lstSnddAclState_29 = acceleration_29;
            last_accel_mtm_29 = ctm;
            let ba = new Uint8Array(1);
            if (acceleration_29)
                ba[0] = 253;
            else
                ba[0] = 254;
            ws_29.send(ba);
        }
        if (!wantCloseCurrentGame_29 && ctm - last_e_mtm_29 > 100 && whereMouseX_29 != -1 && whereMouseY_29 != -1) {
            let centerX = playingArenaWidth / 2;
            let centerY = playingArenaHeight / 2;
            let differeX = whereMouseX_29 - centerX;
            let differeY = whereMouseY_29 - centerY;
            let angle = Math.atan2(differeY, differeX);
            if (angle < 0)
                angle += Math.PI * 2;
            let angleInt = Math.round(angle / Math.PI / 2 * 256);
            if (angleInt == 51) {
                if (angle < Math.PI * 2 / 256 * 51)
                    angleInt = 50;
            }
            else if (angleInt >= 52 && angleInt <= 101) {
                angleInt -= 1;
            }
            else if (angleInt == 102) {
                if (angle < Math.PI * 2 / 256 * 102)
                    angleInt = 100;
                else
                    angleInt = 101;
            }
            else if (angleInt >= 103 && angleInt <= 152) {
                angleInt -= 2;
            }
            else if (angleInt == 153) {
                if (angle < Math.PI * 2 / 256 * 153)
                    angleInt = 150;
                else
                    angleInt = 151;
            }
            else if (angleInt >= 154 && angleInt <= 203) {
                angleInt -= 3;
            }
            else if (angleInt == 204) {
                if (angle < Math.PI * 2 / 256 * 204)
                    angleInt = 200;
                else
                    angleInt = 201;
            }
            else if (angleInt >= 205 && angleInt <= 254) {
                angleInt -= 4;
            }
            else if (angleInt == 255) {
                if (angle < Math.PI * 2 / 256 * 255)
                    angleInt = 250;
                else
                    angleInt = 0;
            }
            else if (angleInt == 256) {
                angleInt = 0;
            }
            if (angleInt != prevComndForEang_29) {
                prevComndForEang_29 = angleInt;
                last_e_mtm_29 = ctm;
                let ba = new Uint8Array([angleInt]);
                ws_29.send(ba);
            }
        }

        let mang, vang;
        for (let i = snakes_29.length - 1; i >= 0; i--) {
            let o = snakes_29[i];
            mang = mamu_29 * vfr_29 * o.scang * o.spang;
            let csp = o.sp * vfr_29 / 4;
            if (csp > o.msl)
                csp = o.msl;
            if (o.tsp != o.sp)
                if (o.tsp < o.sp) {
                    o.tsp += .3 * vfr_29;
                    if (o.tsp > o.sp)
                        o.tsp = o.sp;
                } else {
                    o.tsp -= .3 * vfr_29;
                    if (o.tsp < o.sp)
                        o.tsp = o.sp;
                }
            o.cfl = o.tl;
            if (o.dir == 1) {
                o.ang -= mang;
                if (o.ang < 0 || o.ang >= pi2_29)
                    o.ang %= pi2_29;
                if (o.ang < 0)
                    o.ang += pi2_29;
                vang = (o.wang - o.ang) % pi2_29;
                if (vang < 0)
                    vang += pi2_29;
                if (vang > Math.PI)
                    vang -= pi2_29;
                if (vang > 0) {
                    o.ang = o.wang;
                    o.dir = 0
                }
            } else if (o.dir == 2) {
                o.ang += mang;
                if (o.ang < 0 || o.ang >= pi2_29)
                    o.ang %= pi2_29;
                if (o.ang < 0)
                    o.ang += pi2_29;
                vang = (o.wang - o.ang) % pi2_29;
                if (vang < 0)
                    vang += pi2_29;
                if (vang > Math.PI)
                    vang -= pi2_29;
                if (vang < 0) {
                    o.ang = o.wang;
                    o.dir = 0
                }
            } else
                o.ang = o.wang;
            let po = o.pts[o.pts.length - 1];
            o.xx += Math.cos(o.ang) * csp;
            o.yy += Math.sin(o.ang) * csp;
            o.chl += csp / o.msl
            if (vfrb_29 > 0) {
                for (let j = o.pts.length - 1; j >= 0; j--) {
                    let po = o.pts[j];
                    if (po.dying) {
                        po.da += .0015 * vfrb_29;
                        if (po.da > 1) {
                            o.pts.splice(j, 1);
                        }
                    }
                }
            }
        }
        for (let i = preys_29.length - 1; i >= 0; i--) {
            let pr = preys_29[i];
            mang = mamu2_29 * vfr_29;
            let csp = pr.sp * vfr_29 / 4;
            if (pr.dir == 1) {
                pr.ang -= mang;
                if (pr.ang < 0 || pr.ang >= pi2_29)
                    pr.ang %= pi2_29;
                if (pr.ang < 0)
                    pr.ang += pi2_29;
                vang = (pr.wang - pr.ang) % pi2_29;
                if (vang < 0)
                    vang += pi2_29;
                if (vang > Math.PI)
                    vang -= pi2_29;
                if (vang > 0) {
                    pr.ang = pr.wang;
                    pr.dir = 0
                }
            } else if (pr.dir == 2) {
                pr.ang += mang;
                if (pr.ang < 0 || pr.ang >= pi2_29)
                    pr.ang %= pi2_29;
                if (pr.ang < 0)
                    pr.ang += pi2_29;
                vang = (pr.wang - pr.ang) % pi2_29;
                if (vang < 0)
                    vang += pi2_29;
                if (vang > Math.PI)
                    vang -= pi2_29;
                if (vang < 0) {
                    pr.ang = pr.wang;
                    pr.dir = 0
                }
            } else
                pr.ang = pr.wang;
            pr.xx += Math.cos(pr.ang) * csp;
            pr.yy += Math.sin(pr.ang) * csp;
        }
        vfr_29 = 0;
        vfrb_29 = 0;
        drawFrame();
        oefTimerId_29 = setTimeout(oef_29, Math.max(lastStartOtrisTime_29 + (1000 / maxFps_29) - Date.now(), 0));
        if (wantCloseCurrentGame_29 && ws_29.readyState === WebSocket.OPEN)
            ws_29.close();
    }

    function connect_29() {
        ws_29 = new WebSocket("ws://" + serverIpAndPortField.value + "/slither");
        ws_29.binaryType = "arraybuffer";
        ws_29.onopen = function() {
            const ba = new Uint8Array([99, 4]);
            ws_29.send(ba);
        };
        ws_29.onmessage = function(e) {
            let a = new Uint8Array(e.data);
            if (a.length >= 2) {
                let cmd = String.fromCharCode(a[2]);
                let m = 3;
                let alen = a.length;
                let plen = a.length - 2;
                let dlen = a.length - 3;

                // initial setup
                if (cmd == "a") {
                    grd_29 = a[m] << 16 | a[m + 1] << 8 | a[m + 2];
                    m += 3;
                    real_flux_grd_29 = grd_29;
                    rfgrdForMinimap_29 = real_flux_grd_29;
                    let nmscps = a[m] << 8 | a[m + 1];
                    m += 2;
                    sector_size_29 = a[m] << 8 | a[m + 1];
                    m += 2;
                    m += 2;
                    spangdv_29 = a[m] / 10;
                    m++;
                    nsp1_29 = (a[m] << 8 | a[m + 1]) / 100;
                    m += 2;
                    nsp2_29 = (a[m] << 8 | a[m + 1]) / 100;
                    m += 2;
                    nsp3_29 = (a[m] << 8 | a[m + 1]) / 100;
                    m += 2;
                    mamu_29 = (a[m] << 8 | a[m + 1]) / 1E3;
                    m += 2;
                    mamu2_29 = (a[m] << 8 | a[m + 1]) / 1E3;
                    m += 2;
                    cst_29 = (a[m] << 8 | a[m + 1]) / 1E3;
                    m += 2;
                    if (m < alen) {
                        protocol_version_29 = a[m];
                        m++;
                        if (protocol_version_29 != 13) {
                            ws_29.close();
                        }
                    }
                    setMscps_29(nmscps);
                }
                // snake rotation
                else if (cmd == "e" || cmd == "E" || cmd == "3" || cmd == "4" || cmd == "5") {
                    let id = a[m] << 8 | a[m + 1];
                    m += 2;
                    let dir = -1;
                    let ang = -1;
                    let wang = -1;
                    let speed = -1;
                    if (protocol_version_29 >= 6)
                        if (plen == 6) {
                            if (cmd == "e")
                                dir = 1;
                            else
                                dir = 2;
                            ang = a[m] * 2 * Math.PI / 256;
                            m++;
                            wang = a[m] * 2 * Math.PI / 256;
                            m++;
                            speed = a[m] / 18;
                            m++
                        } else if (plen == 5)
                            if (cmd == "e") {
                                ang = a[m] * 2 * Math.PI / 256;
                                m++;
                                speed = a[m] / 18;
                                m++
                            } else if (cmd == "E") {
                                dir = 1;
                                wang = a[m] * 2 * Math.PI / 256;
                                m++;
                                speed = a[m] / 18;
                                m++
                            } else if (cmd == "4") {
                                dir = 2;
                                wang = a[m] * 2 * Math.PI / 256;
                                m++;
                                speed = a[m] / 18;
                                m++
                            } else if (cmd == "3") {
                                dir = 1;
                                ang = a[m] * 2 * Math.PI / 256;
                                m++;
                                wang = a[m] * 2 * Math.PI / 256;
                                m++
                            } else {
                                if (cmd == "5") {
                                    dir = 2;
                                    ang = a[m] * 2 * Math.PI / 256;
                                    m++;
                                    wang = a[m] * 2 * Math.PI / 256;
                                    m++
                                }
                            }
                        else {
                            if (plen == 4)
                                if (cmd == "e") {
                                    ang = a[m] * 2 * Math.PI / 256;
                                    m++
                                } else if (cmd == "E") {
                                    dir = 1;
                                    wang = a[m] * 2 * Math.PI / 256;
                                    m++
                                } else if (cmd == "4") {
                                    dir = 2;
                                    wang = a[m] * 2 * Math.PI / 256;
                                    m++
                                } else if (cmd == "3") {
                                    speed = a[m] / 18;
                                    m++
                                }
                        }
                    else if (protocol_version_29 >= 3) {
                        if (cmd != "3")
                            if (plen == 8 || plen == 7 || plen == 6 && cmd != "3" || plen == 5 && cmd != "3")
                                if (cmd == "e")
                                    dir = 1;
                                else
                                    dir = 2;
                        if (plen == 8 || plen == 7 || plen == 5 && cmd == "3" || plen == 6 && cmd == "3") {
                            ang = (a[m] << 8 | a[m + 1]) * 2 * Math.PI / 65535;
                            m += 2
                        }
                        if (plen == 8 || plen == 7 || plen == 5 && cmd != "3" || plen == 6 && cmd != "3") {
                            wang = (a[m] << 8 | a[m + 1]) * 2 * Math.PI / 65535;
                            m += 2
                        }
                        if (plen == 8 || plen == 6 || plen == 4) {
                            speed = a[m] / 18;
                            m++
                        }
                    } else {
                        if (dlen == 11 || dlen == 8 || dlen == 9 || dlen == 6) {
                            dir = a[m] - 48;
                            m++
                        }
                        if (dlen == 11 || dlen == 7 || dlen == 9 || dlen == 5) {
                            ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                            m += 3
                        }
                        if (dlen == 11 || dlen == 8 || dlen == 9 || dlen == 6) {
                            wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                            m += 3
                        }
                        if (dlen == 11 || dlen == 7 || dlen == 8 || dlen == 4) {
                            speed = (a[m] << 8 | a[m + 1]) / 1E3;
                            m += 2
                        }
                    }
                    let o;
                    for (let i = snakes_29.length - 1; i >= 0; i--) {
                        if (snakes_29[i].id == id) {
                            o = snakes_29[i];
                            break;
                        }
                    }
                    if (o) {
                        if (dir != -1)
                           o.dir = dir;
                        if (ang != -1) {
                            o.ang = ang
                        }
                        if (wang != -1) {
                            o.wang = wang;
                            o.eang = wang;
                        }
                        if (speed != -1) {
                            o.sp = speed;
                            o.spang = o.sp / spangdv_29;
                            if (o.spang > 1)
                                o.spang = 1;
                        }
                    }
                }
                // pre-init response
                else if (cmd == "6") {
                    let server_version = new Uint8Array(alen - m);
                    for (let i = 0; m < alen; i++) {
                        server_version[i] = a[m];
                        m++;
                    }
                    let idba = new Uint8Array(24);
                    decodeSecret_29(server_version, idba);
                    ws_29.send(idba);

                    const lgba = new Uint8Array([115, 12, 1, 2, 116, 116, 0, 255]);
                    ws_29.send(lgba);

                    // send first ping
                    last_ping_mtm_29 = Date.now();
                    wfpr_29 = true;
                    const ba = new Uint8Array([251]);
                    ws_29.send(ba);
                }
                // update snake last body part fullness (fam)
                else if (cmd == "h") {
                    let id = a[m] << 8 | a[m + 1];
                    m += 2;
                    let fam = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 16777215;
                    m += 3;
                    let o;
                    for (let i = snakes_29.length - 1; i >= 0; i--) {
                        if (snakes_29[i].id == id) {
                            o = snakes_29[i];
                            break;
                        }
                    }
                    if (o) {
                        o.fam = fam;
                        o.tl = o.sct + o.fam;
                    }
                }
                // remove snake part
                else if (cmd == "r") {
                    let id = a[m] << 8 | a[m + 1];
                    m += 2;
                    let o;
                    for (let i = snakes_29.length - 1; i >= 0; i--) {
                        if (snakes_29[i].id == id) {
                            o = snakes_29[i];
                            break;
                        }
                    }
                    if (o) {
                        if (dlen >= 4) {
                            o.fam = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 16777215;
                            m += 3
                        }
                        for (let j = 0; j < o.pts.length; j++)
                            if (!o.pts[j].dying) {
                                o.pts[j].dying = true;
                                o.sct--;
                                o.sc = Math.min(6, 1 + (o.sct - 2) / 106);
                                o.scang = .13 + .87 * Math.pow((7 - o.sc) / 6, 2);
                                o.ssp = nsp1_29 + nsp2_29 * o.sc;
                                o.fsp = o.ssp + .1;
                                break;
                            }
                        o.tl = o.sct + o.fam;
                    }
                }
                // update number of snake parts that you lost while spinning in a closed circle (rsc)
                else if (cmd == "R") {
                    for (let i = snakes_29.length - 1; i >= 0; i--) {
                        if (snakes_29[i].id == myId_29) {
                            snakes_29[i].rsc = a[m];
                            break;
                        }
                    }
                    m++;
                }
                // move or increase snake
                else if (cmd == "g" || cmd == "n" || cmd == "G" || cmd == "N") {
                    let adding_only = cmd == "n" || cmd == "N";
                    let id = a[m] << 8 | a[m + 1];
                    m += 2;
                    let o;
                    for (let i = snakes_29.length - 1; i >= 0; i--) {
                        if (snakes_29[i].id == id) {
                            o = snakes_29[i];
                            break;
                        }
                    }
                    if (o) {
                        if (adding_only)
                            o.sct++;
                        else
                            for (let j = 0; j < o.pts.length; j++)
                                if (!o.pts[j].dying) {
                                    o.pts[j].dying = true;
                                    break
                                }
                        let po = o.pts[o.pts.length - 1];
                        let lpo = po;
                        let mpo;
                        let mv;
                        let lmpo;
                        if (protocol_version_29 >= 3)
                            if (cmd == "g" || cmd == "n") {
                                xx_29 = a[m] << 8 | a[m + 1];
                                m += 2;
                                yy_29 = a[m] << 8 | a[m + 1];
                                m += 2
                            } else {
                                xx_29 = lpo.xx + a[m] - 128;
                                m++;
                                yy_29 = lpo.yy + a[m] - 128;
                                m++;
                            }
                        else {
                            xx_29 = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
                            m += 3;
                            yy_29 = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
                            m += 3
                        }
                        if (adding_only) {
                            o.fam = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 16777215;
                            m += 3
                        }
                        po = {};
                        po.xx = xx_29;
                        po.yy = yy_29;
                        po.da = 0;
                        o.pts.push(po);
                        let k = o.pts.length - 3;
                        let n;
                        if (k >= 1) {
                            lmpo = o.pts[k];
                            n = 0;
                            mv = 0;
                            for (let j = k - 1; j >= 0; j--) {
                                mpo = o.pts[j];
                                n++;
                                if (n <= 4)
                                    mv = cst_29 * n / 4;
                                mpo.xx += (lmpo.xx - mpo.xx) * mv;
                                mpo.yy += (lmpo.yy - mpo.yy) * mv;
                                lmpo = mpo;
                            }
                        }
                        o.sc = Math.min(6, 1 + (o.sct - 2) / 106);
                        o.scang = .13 + .87 * Math.pow((7 - o.sc) / 6, 2);
                        o.ssp = nsp1_29 + nsp2_29 * o.sc;
                        o.fsp = o.ssp + .1;
                        if (adding_only)
                            o.tl = o.sct + o.fam;
                        o.chl = 0;
                        o.xx = xx_29;
                        o.yy = yy_29;
                    }
                }
                // leaderboard
                else if (cmd == "l") {
                    playersInfo_29 = "";
                    let nc = 0;
                    let pos = 0;
                    let v;
                    let score;
                    let my_pos = a[m];
                    m++;
                    let rank = a[m] << 8 | a[m + 1];
                    m += 2;
                    let snake_count = a[m] << 8 | a[m + 1];
                    m += 2;
                    while (m < alen) {
                        let sct = a[m] << 8 | a[m + 1];
                        m += 2;
                        let fam = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 16777215;
                        m += 3;
                        m++;
                        let nl = a[m];
                        m++;
                        pos++;
                        let nk = "";
                        for (let j = 0; j < nl; j++) {
                            v = a[m];
                            nk += String.fromCharCode(v);
                            m++;
                        }
                        if (pos == my_pos) {
                            nk = "tt";
                        }
                        nc++;
                        score = Math.floor((fpsls_29[sct] + fam / fmlts_29[sct] - 1) * 15 - 5) / 1;
                        playersInfo_29 += nc + "    " + score + "          " + nk + "\n";
                    }
                    playersInfo_29 += "\n " + rank + " / " + snake_count;
                }
                // add sector (for foods)
                else if (cmd == "W") {
                    xx_29 = a[m];
                    m++;
                    yy_29 = a[m];
                    m++;
                    let o = {};
                    o.xx = xx_29;
                    o.yy = yy_29;
                    sectors_29.push(o)
                }
                // remove sector (for foods)
                else if (cmd == "w") {
                    xx_29 = a[m];
                    m++;
                    yy_29 = a[m];
                    m++;
                    cm1_29 = foods_c_29 - 1;
                    for (let i = cm1_29; i >= 0; i--) {
                        let fo = foods_29[i];
                        if (fo.sx == xx_29)
                            if (fo.sy == yy_29)
                                if (i == cm1_29) {
                                    foods_29[i] = null;
                                    foods_c_29--;
                                    cm1_29--;
                                } else {
                                    foods_29[i] = foods_29[cm1_29];
                                    foods_29[cm1_29] = null;
                                    foods_c_29--;
                                    cm1_29--;
                                }
                    }
                    for (let i = sectors_29.length - 1; i >= 0; i--) {
                        let o = sectors_29[i];
                        if (o.xx == xx_29)
                            if (o.yy == yy_29)
                                sectors_29.splice(i, 1);
                    }
                }
                // pong
                else if (cmd == "p") {
                    wfpr_29 = false;
                }
                // update minimap
                else if (cmd == "M") {
                    rfgrdForMinimap_29 = real_flux_grd_29;
                    minimapObjs_29 = [];
                    let moInd = 0;
                    const u_m = [64, 32, 16, 8, 4, 2, 1];
                    let sz = a[m] << 8 | a[m + 1];
                    m += 2;
                    if (sz > 512)
                        sz = 512;
                    minimapObjs_29[moInd] = {};
                    minimapObjs_29[moInd].sz = sz;
                    moInd++;
                    let i;
                    let k = 0;
                    let xx = sz - 1;
                    let yy = sz - 1;
                    while (m < alen) {
                        if (yy < 0)
                            break;
                        k = a[m++];
                        if (k >= 128) {
                            if (k == 255)
                                k = 126 * a[m++];
                            else
                                k -= 128;
                            for (i = 0; i < k; i++) {
                                xx--;
                                if (xx < 0) {
                                    xx = sz - 1;
                                    yy--;
                                    if (yy < 0)
                                        break;
                                }
                            }
                        } else
                            for (i = 0; i < 7; i++) {
                                if ((k & u_m[i]) > 0) {
                                    minimapObjs_29[moInd] = {};
                                    minimapObjs_29[moInd].xx = xx;
                                    minimapObjs_29[moInd].yy = yy;
                                    moInd++;
                                }
                                xx--;
                                if (xx < 0) {
                                    xx = sz - 1;
                                    yy--;
                                    if (yy < 0)
                                        break;
                                }
                            }
                    }
                }
                // add/remove snake
                else if (cmd == "s") {
                    let id = a[m] << 8 | a[m + 1];
                    m += 2;
                    if (myIdWas_29 == false) {
                        myId_29 = id;
                        myIdWas_29 = true;
                    }
                    if (dlen > 6) {
                        let ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                        m += 3;
                        let dir = a[m] - 48;
                        m++;
                        let wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                        m += 3;
                        let speed = (a[m] << 8 | a[m + 1]) / 1E3;
                        m += 2;
                        let fam = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 16777215;
                        m += 3;
                        let cv = a[m];
                        m++;
                        let pts = [];
                        let snx = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
                        m += 3;
                        let sny = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
                        m += 3;
                        let nl = a[m];
                        m++;
                        let nk = "";
                        for (let j = 0; j < nl; j++) {
                            nk += String.fromCharCode(a[m]);
                            m++
                        }
                        let skl = a[m];
                        m++;
                        m += skl;
                        m++;
                        xx_29 = 0;
                        yy_29 = 0;
                        let fp = false;
                        while (m < alen) {
                            if (!fp) {
                                xx_29 = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
                                m += 3;
                                yy_29 = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
                                m += 3;
                                fp = true
                            } else {
                                xx_29 += (a[m] - 127) / 2;
                                m++;
                                yy_29 += (a[m] - 127) / 2;
                                m++
                            }
                            let po = {};
                            po.dying = false;
                            po.xx = xx_29;
                            po.yy = yy_29;
                            po.da = 0;
                            pts.push(po)
                        }
                        let o = newSnake_29(id, snx, sny, cv, ang, pts);
                        o.nk = nk;
                        o.eang = o.wang = wang;
                        o.sp = speed;
                        o.spang = o.sp / spangdv_29;
                        if (o.spang > 1)
                            o.spang = 1;
                        o.fam = fam;
                        o.sc = Math.min(6, 1 + (o.sct - 2) / 106);
                        o.scang = .13 + .87 * Math.pow((7 - o.sc) / 6, 2);
                        o.ssp = nsp1_29 + nsp2_29 * o.sc;
                        o.fsp = o.ssp + .1;
                        o.tl = o.sct + o.fam;
                    } else {
                        m++;
                        for (let i = snakes_29.length - 1; i >= 0; i--) {
                            if (snakes_29[i].id == id) {
                                snakes_29.splice(i, 1);
                                break;
                            }
                        }
                    }
                    if (!oefTimerStarted_29) {
                        oefTimerStarted_29 = true;
                        oef_29();
                    }
                    buttonFunctionality_29 = true;
                }
                // add food
                else if (cmd == "F") {
                    let gsi = false;
                    let sx, sy;
                    while (m < alen) {
                        m++;
                        xx_29 = a[m] << 8 | a[m + 1];
                        m += 2;
                        yy_29 = a[m] << 8 | a[m + 1];
                        m += 2;
                        let rad = a[m] / 5;
                        m++;
                        let id = yy_29 * grd_29 * 3 + xx_29;
                        if (rad > 0) {
                            let fo = newFood_29(id, xx_29, yy_29, rad);
                            if (!gsi) {
                                gsi = true;
                                sx = Math.floor(xx_29 / sector_size_29);
                                sy = Math.floor(yy_29 / sector_size_29);
                            }
                            fo.sx = sx;
                            fo.sy = sy;
                        }
                        else {
                            if (!gsi) {
                                gsi = true;
                                sx = Math.floor(xx_29 / sector_size_29);
                                sy = Math.floor(yy_29 / sector_size_29);
                            }
                        }
                    }
                }
                // add food
                else if (cmd == "b" || cmd == "f") {
                    m++;
                    if (dlen > 4) {
                        xx_29 = a[m] << 8 | a[m + 1];
                        m += 2;
                        yy_29 = a[m] << 8 | a[m + 1];
                        m += 2;
                        let id = yy_29 * grd_29 * 3 + xx_29;
                        let rad = a[m] / 5;
                        m++;
                        if (rad > 0) {
                            let fo = newFood_29(id, xx_29, yy_29, rad);
                            fo.sx = Math.floor(xx_29 / sector_size_29);
                            fo.sy = Math.floor(yy_29 / sector_size_29);
                        }
                    }
                }
                // food eaten
                else if (cmd == "c") {
                    let xx = a[m] << 8 | a[m + 1];
                    m += 2;
                    let yy = a[m] << 8 | a[m + 1];
                    m += 2;
                    let id = yy * grd_29 * 3 + xx
                    cm1_29 = foods_c_29 - 1;
                    for (let i = cm1_29; i >= 0; i--) {
                        let fo = foods_29[i];
                        if (fo.id == id) {
                            if (m + 2 <= alen) {
                                m += 2;
                            }
                            if (i == cm1_29) {
                                foods_29[i] = null;
                                foods_c_29--;
                                cm1_29--;
                            } else {
                                foods_29[i] = foods_29[cm1_29];
                                foods_29[cm1_29] = null;
                                foods_c_29--;
                                cm1_29--;
                            }
                            break;
                        }
                    }
                }
                // update prey
                else if (cmd == "j") {
                    let id = a[m] << 8 | a[m + 1];
                    m += 2;
                    xx_29 = 1 + (a[m] << 8 | a[m + 1]) * 3;
                    m += 2;
                    yy_29 = 1 + (a[m] << 8 | a[m + 1]) * 3;
                    m += 2;
                    let pr = null;
                    for (let i = preys_29.length - 1; i >= 0; i--)
                        if (preys_29[i].id == id) {
                            pr = preys_29[i];
                            break;
                        }
                    if (pr) {
                        if (dlen == 15) {
                            pr.dir = a[m] - 48;
                            m++;
                            pr.ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                            m += 3;
                            pr.wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                            m += 3;
                            pr.sp = (a[m] << 8 | a[m + 1]) / 1E3;
                            m += 2
                        } else if (dlen == 11) {
                            pr.ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                            m += 3;
                            pr.sp = (a[m] << 8 | a[m + 1]) / 1E3;
                            m += 2
                        } else if (dlen == 12) {
                            pr.dir = a[m] - 48;
                            m++;
                            pr.wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                            m += 3;
                            pr.sp = (a[m] << 8 | a[m + 1]) / 1E3;
                            m += 2
                        } else if (dlen == 13) {
                            pr.dir = a[m] - 48;
                            m++;
                            pr.ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                            m += 3;
                            pr.wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                            m += 3
                        } else if (dlen == 9) {
                            pr.ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                            m += 3
                        } else if (dlen == 10) {
                            pr.dir = a[m] - 48;
                            m++;
                            pr.wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                            m += 3
                        } else if (dlen == 8) {
                            pr.sp = (a[m] << 8 | a[m + 1]) / 1E3;
                            m += 2
                        }
                        pr.xx = xx_29;
                        pr.yy = yy_29;
                    }
                }
                // add/remove prey
                else if (cmd == "y") {
                    let id = a[m] << 8 | a[m + 1];
                    m += 2;
                    if (dlen == 2)
                        for (let i = preys_29.length - 1; i >= 0; i--) {
                            let pr = preys_29[i];
                            if (pr.id == id) {
                                preys_29.splice(i, 1);
                                break;
                            }
                        }
                    else if (dlen == 4) {
                        m += 2;
                        for (let i = preys_29.length - 1; i >= 0; i--) {
                            let pr = preys_29[i];
                            if (pr.id == id) {
                                preys_29.splice(i, 1);
                                break;
                            }
                        }
                    } else {
                        m++;
                        xx_29 = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
                        m += 3;
                        yy_29 = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
                        m += 3;
                        let rad = a[m] / 5;
                        m++;
                        let dir = a[m] - 48;
                        m++;
                        let wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                        m += 3;
                        let ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
                        m += 3;
                        let speed = (a[m] << 8 | a[m + 1]) / 1E3;
                        m += 2;
                        newPrey_29(id, xx_29, yy_29, rad, dir, wang, ang, speed)
                    }
                }
                // update map border
                else if (cmd == "z") {
                    real_flux_grd_29 = a[m] << 16 | a[m + 1] << 8 | a[m + 2];
                }
            }
        };
        ws_29.onerror = function(error) {
            console.error('WebSocket error: ', error);
        };
        ws_29.onclose = function() {
            if (oefTimerStarted_29) {
                clearTimeout(oefTimerId_29);
            }
            oefTimerStarted_29 = false;
            wantCloseCurrentGame_29 = false;
            gameExists_29 = false;
            buttonFunctionality_29 = true;

            if (wantNewGame_29) {
                buttonFunctionality_29 = false;
                wantNewGame_29 = false;
                prepareNewGame_29();
            }
        };
    };


    let playingArenaWidth = Math.ceil(window.innerWidth);
    let playingArenaHeight = Math.ceil(window.innerHeight);
    let plArCanv = document.createElement('canvas');
    plArCanv.style.position = 'fixed';
    plArCanv.style.left = '0px';
    plArCanv.style.top = '0px';
    plArCanv.width = playingArenaWidth;
    plArCanv.height = playingArenaHeight;
    plArCanv.style.zIndex = 1;
    document.body.appendChild(plArCanv);
    let ctx = plArCanv.getContext('2d');
    let zoom = 0.3;
    let centerSiX = 20000;
    let centerSiY = 20000;
    let strokeMoveWas;

    function drawFrame() {
        if (playingArenaWidth !== Math.ceil(window.innerWidth)) {
            playingArenaWidth = Math.ceil(window.innerWidth);
            plArCanv.width = playingArenaWidth;
        }
        if (playingArenaHeight !== Math.ceil(window.innerHeight)) {
            playingArenaHeight = Math.ceil(window.innerHeight);
            plArCanv.height = playingArenaHeight;
        }
        let mySnake;
        let finded = false;
        for (let i = 0; i < snakes_29.length; i++) {
            if (snakes_29[i].id == myId_29 && snakes_29[i].pts.length >= 1) {
                mySnake = snakes_29[i];
                finded = true;
                break;
            }
        }
        if (!finded && gameExists_29) {
            wantCloseCurrentGame_29 = true;
            return;
        }
        if (mySnake) {
            centerSiX = mySnake.xx;
            centerSiY = mySnake.yy;
        }
        const leftSiX = centerSiX - ((playingArenaWidth / 2) / zoom);
        const topSiY = centerSiY - ((playingArenaHeight / 2) / zoom);
        const rightSiX = centerSiX + ((playingArenaWidth / 2) / zoom);
        const bottomSiY = centerSiY + ((playingArenaHeight / 2) / zoom);

        const currentTime = Date.now();
        if (currentTime - currentFpsLastShowTime_29 > 200) {
            currentFps_29 = Math.round(1000 / (currentTime - lastStartOtrisTime_29));
            currentFpsLastShowTime_29 = currentTime;
        }
        lastStartOtrisTime_29 = currentTime;
        
        // drawing background
        const lightSquareColor = 'rgb(255,255,255)';
        let darkSquareColor;
        if (wfpr_29 && Date.now() - last_ping_mtm_29 > 500)
            darkSquareColor = 'rgb(255,235,235)';
        else
            darkSquareColor = 'rgb(235,235,235)';
        const smallSquareSizeSi = 220;
        const smallSquareSizePi = smallSquareSizeSi * zoom;
        const startCoordSiX = smallSquareSizeSi * Math.floor(leftSiX / smallSquareSizeSi);
        const startCoordSiY = smallSquareSizeSi * Math.floor(topSiY / smallSquareSizeSi);
        ctx.fillStyle = lightSquareColor;
        ctx.fillRect(0, 0, playingArenaWidth, playingArenaHeight);
        ctx.fillStyle = darkSquareColor;
        for (let i = startCoordSiX; i < rightSiX; i += smallSquareSizeSi) {
            for (let j = startCoordSiY; j < bottomSiY; j += smallSquareSizeSi) {
                if ((i % (smallSquareSizeSi * 2) !== 0 && j % (smallSquareSizeSi * 2) === 0) || (i % (smallSquareSizeSi * 2) === 0 && j % (smallSquareSizeSi * 2) !== 0)) {
                    ctx.fillRect(playingArenaWidth / 2 - ((centerSiX - i) * zoom), playingArenaHeight / 2 - ((centerSiY - j) * zoom), smallSquareSizePi, smallSquareSizePi);
                }
            }
        }

        // drawing foods
        ctx.fillStyle = 'blue';
        let foodSide;
        for (let i = 0; i < foods_c_29; i++) {
            foodSide = foods_29[i].sz * 0.5 * zoom;
            ctx.fillRect(siToPiX(foods_29[i].xx) - foodSide / 2, siToPiY(foods_29[i].yy) - foodSide / 2, foodSide, foodSide);
        }

        // drawing preys
        ctx.fillStyle = 'rgba(165,42,42,0.7)';
        let preyRad;
        for (let i = 0; i < preys_29.length; i++) {
            preyRad = preys_29[i].sz * 2;
            ctx.beginPath();
            ctx.arc(siToPiX(preys_29[i].xx), siToPiY(preys_29[i].yy), preyRad * zoom, 0, 2*Math.PI);
            ctx.fill();
        }
        ctx.strokeStyle = 'rgb(36,255,255)';
        ctx.lineWidth = 1;
        let preyAngLineLen;
        for (let i = 0; i < preys_29.length; i++) {
            preyAngLineLen = preys_29[i].sp * 9.2;
            strokeMoveWas = false;
            ctx.beginPath();
            addPointToPolyline(preys_29[i].xx + preyAngLineLen * Math.cos(preys_29[i].ang), preys_29[i].yy + preyAngLineLen * Math.sin(preys_29[i].ang));
            addPointToPolyline(preys_29[i].xx, preys_29[i].yy);
            ctx.stroke();
        }
        ctx.strokeStyle = 'red';
        ctx.lineWidth = 1;
        const preyWangLineLen = 25;
        for (let i = 0; i < preys_29.length; i++) {
            strokeMoveWas = false;
            ctx.beginPath();
            addPointToPolyline(preys_29[i].xx + preyWangLineLen * Math.cos(preys_29[i].wang), preys_29[i].yy + preyWangLineLen * Math.sin(preys_29[i].wang));
            addPointToPolyline(preys_29[i].xx, preys_29[i].yy);
            ctx.stroke();
        }

        // drawing snakes
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';
        for (let i = 0; i < snakes_29.length; i++) {
            if (snakes_29[i].pts.length >= 2) {
                const lineNearHeadLen = distBetwCoords(snakes_29[i].xx, snakes_29[i].yy, snakes_29[i].pts[snakes_29[i].pts.length-1].xx, snakes_29[i].pts[snakes_29[i].pts.length-1].yy);
                let oneFreshPartLen;
                if (snakes_29[i].sct <= 1) oneFreshPartLen = 42.000;
                if (snakes_29[i].sct == 2) oneFreshPartLen = 37.485;
                if (snakes_29[i].sct == 3) oneFreshPartLen = 32.970;
                if (snakes_29[i].sct == 4) oneFreshPartLen = 28.455;
                if (snakes_29[i].sct >= 5) oneFreshPartLen = 23.940;
                const lineNearHeadInFam = lineNearHeadLen / oneFreshPartLen;
                const snakeLenghtInParts = Math.max(snakes_29[i].sct + snakes_29[i].fam - Math.max(lineNearHeadInFam, 0), 1);
                let predSnakeLen = distBetwCoords(snakes_29[i].xx, snakes_29[i].yy, snakes_29[i].pts[snakes_29[i].pts.length - 1].xx, snakes_29[i].pts[snakes_29[i].pts.length - 1].yy);
                let j;
                for (j = snakes_29[i].pts.length - 2; j >= Math.max(snakes_29[i].pts.length - Math.floor(snakeLenghtInParts) - 2, 0); j--) {
                    predSnakeLen += distBetwCoords(snakes_29[i].pts[j].xx, snakes_29[i].pts[j].yy, snakes_29[i].pts[j+1].xx, snakes_29[i].pts[j+1].yy);
                }
                if (snakeLenghtInParts % 1 > 0 && j >= 0) {
                    let intermedX = snakes_29[i].pts[j+1].xx + (snakes_29[i].pts[j].xx - snakes_29[i].pts[j+1].xx) * (snakeLenghtInParts % 1) / 1;
                    let intermedY = snakes_29[i].pts[j+1].yy + (snakes_29[i].pts[j].yy - snakes_29[i].pts[j+1].yy) * (snakeLenghtInParts % 1) / 1;
                    predSnakeLen += distBetwCoords(intermedX, intermedY, snakes_29[i].pts[j+1].xx, snakes_29[i].pts[j+1].yy);
                }
                let newSnakeLen;
                if (predSnakeLen <= 240) {
                    let bottomEdge = 80;
                    let topEdge = 240;
                    let newBottomEdge = predSnakeLen * 0.50;
                    let newTopEdge = predSnakeLen;
                    newSnakeLen = newBottomEdge + ((newTopEdge - newBottomEdge) * (predSnakeLen - bottomEdge) / (topEdge - bottomEdge));
                }
                else {
                    newSnakeLen = predSnakeLen;
                }

                if (snakes_29[i].id === myId_29)
                    ctx.strokeStyle = createRgbaStr(255, 0, 255, 0.8,  128, 0, 128, 0.8,  snakes_29[i].sp);
                else
                    ctx.strokeStyle = createRgbaStr(0, 128, 0, 0.9,  128, 0, 0, 0.9,  snakes_29[i].sp);
                ctx.lineWidth = snakes_29[i].sc * 31 * zoom;
                strokeMoveWas = false;
                ctx.beginPath();
                addPointToPolyline(snakes_29[i].xx, snakes_29[i].yy);
                if (newSnakeLen < lineNearHeadLen) {
                    const distKf = newSnakeLen / distBetwCoords(snakes_29[i].xx, snakes_29[i].yy, snakes_29[i].pts[snakes_29[i].pts.length - 1].xx, snakes_29[i].pts[snakes_29[i].pts.length - 1].yy);
                    addPointToPolyline(getIntermed(snakes_29[i].xx, snakes_29[i].pts[snakes_29[i].pts.length - 1].xx, distKf), getIntermed(snakes_29[i].yy, snakes_29[i].pts[snakes_29[i].pts.length - 1].yy, distKf));
                }
                else {
                    newSnakeLen -= lineNearHeadLen;
                    addPointToPolyline(snakes_29[i].pts[snakes_29[i].pts.length - 1].xx, snakes_29[i].pts[snakes_29[i].pts.length - 1].yy);
                }
                for (let j = snakes_29[i].pts.length - 2; j >= 0; j--) {
                    const temp = distBetwCoords(snakes_29[i].pts[j].xx, snakes_29[i].pts[j].yy, snakes_29[i].pts[j+1].xx, snakes_29[i].pts[j+1].yy);
                    if (newSnakeLen < temp) {
                        const distKf = newSnakeLen / distBetwCoords(snakes_29[i].pts[j+1].xx, snakes_29[i].pts[j+1].yy, snakes_29[i].pts[j].xx, snakes_29[i].pts[j].yy);
                        addPointToPolyline(getIntermed(snakes_29[i].pts[j+1].xx, snakes_29[i].pts[j].xx, distKf), getIntermed(snakes_29[i].pts[j+1].yy, snakes_29[i].pts[j].yy, distKf));
                        break;
                    }
                    addPointToPolyline(snakes_29[i].pts[j].xx, snakes_29[i].pts[j].yy);
                    newSnakeLen -= temp;
                }
                function getIntermed (X1orY1, X2orY2, distKoef) {
                    return X1orY1 + (X2orY2 - X1orY1) * distKoef;
                }
                ctx.stroke();
            }
        }
        ctx.lineCap = 'butt';
        ctx.lineJoin = 'miter';
        ctx.strokeStyle = 'rgb(36,255,255)';
        ctx.lineWidth = 1;
        const snakeAngLineLen = 100;
        for (let i = 0; i < snakes_29.length; i++) {
            if (snakes_29[i].pts.length >= 2) {
                strokeMoveWas = false;
                ctx.beginPath();
                addPointToPolyline(snakes_29[i].xx + snakeAngLineLen * Math.cos(snakes_29[i].ang), snakes_29[i].yy + snakeAngLineLen * Math.sin(snakes_29[i].ang));
                addPointToPolyline(snakes_29[i].xx, snakes_29[i].yy);
                ctx.stroke();
            }
        }
        ctx.strokeStyle = 'red';
        ctx.lineWidth = 1;
        const snakeWangLineLen = 50;
        for (let i = 0; i < snakes_29.length; i++) {
            if (snakes_29[i].pts.length >= 2) {
                if (snakes_29[i].id === myId_29)
                    ctx.strokeStyle = 'rgb(36,255,255)';
                strokeMoveWas = false;
                ctx.beginPath();
                addPointToPolyline(snakes_29[i].xx + snakeWangLineLen * Math.cos(snakes_29[i].eang), snakes_29[i].yy + snakeWangLineLen * Math.sin(snakes_29[i].eang));
                addPointToPolyline(snakes_29[i].xx, snakes_29[i].yy);
                ctx.stroke();
                if (snakes_29[i].id === myId_29)
                    ctx.strokeStyle = 'red';
            }
        }
        ctx.fillStyle = 'rgba(0,0,0,0.5)';
        ctx.textAlign = "center";
        for (let i = 0; i < snakes_29.length; i++) {
            if (snakes_29[i].pts.length >= 2) {
                ctx.font = 37 * zoom + "px sans-serif";
                ctx.fillText(snakes_29[i].nk, siToPiX(snakes_29[i].xx), siToPiY(snakes_29[i].yy) + 67 * zoom);
            }
        }

        // drawing map border
        if ((real_flux_grd_29 - distBetwCoords(0, 0, centerSiX - grd_29, centerSiY - grd_29)) * zoom < distBetwCoords(playingArenaWidth / 2, playingArenaHeight / 2, 0, 0)) {
            ctx.strokeStyle = 'orange';
            const edgeLineWidth = 30 * zoom;
            ctx.lineWidth = edgeLineWidth;
            ctx.beginPath();
            ctx.arc(siToPiX(grd_29), siToPiY(grd_29), real_flux_grd_29 * zoom + edgeLineWidth / 2, 0, 2*Math.PI);
            ctx.stroke();
        }

        // drawing minimap
        const mmapScale = 2;
        let mmapBeginX;
        let mmapBeginY;
        if (minimapObjs_29.length >= 1) {
            mmapBeginX = playingArenaWidth - minimapObjs_29[0].sz * mmapScale + 0;
            mmapBeginY = playingArenaHeight - minimapObjs_29[0].sz * mmapScale + 0;

            const mmapEdgeLineWidth = 2.5;
            ctx.lineWidth = mmapEdgeLineWidth;
            ctx.beginPath();
            ctx.arc(mmapBeginX + ((minimapObjs_29[0].sz - 0.5) * mmapScale) / 2, mmapBeginY + ((minimapObjs_29[0].sz - 0.5) * mmapScale) / 2, ((minimapObjs_29[0].sz - 1) / 2 * mmapScale) * real_flux_grd_29 / rfgrdForMinimap_29 + mmapEdgeLineWidth / 2, 0, 2*Math.PI);
            ctx.fillStyle = 'rgba(255,255,255,0.2)';
            ctx.fill();
            ctx.strokeStyle = 'rgba(255,165,0,1)';
            ctx.stroke();
        }
        ctx.fillStyle = 'rgba(0,0,0,0.8)';
        for (let i = 1; i < minimapObjs_29.length; i++) {
            ctx.fillRect(mmapBeginX + minimapObjs_29[i].xx * mmapScale, mmapBeginY + minimapObjs_29[i].yy * mmapScale, mmapScale, mmapScale);
        }
        if (minimapObjs_29.length >= 1 && mySnake) {
            ctx.fillStyle = 'rgba(255,0,70,0.8)';
            const radius = 3;
            ctx.beginPath();
            ctx.arc(mmapBeginX + ((minimapObjs_29[0].sz - 0.5) * mmapScale) / 2 + (mySnake.xx - grd_29) * ((minimapObjs_29[0].sz - 1) * mmapScale) / (rfgrdForMinimap_29 * 2), mmapBeginY + ((minimapObjs_29[0].sz - 0.5) * mmapScale) / 2 + (mySnake.yy - grd_29) * ((minimapObjs_29[0].sz - 1) * mmapScale) / (rfgrdForMinimap_29 * 2), radius, 0, 2*Math.PI);
            ctx.fill();
        }

        // drawing fps and zoom info
        ctx.fillStyle = 'rgb(0,0,0)';
        ctx.font = "11px sans-serif";
        ctx.fillText("fps:  " + currentFps_29 + "      zoom:  " + zoom.toFixed(2), 310, 15);

        // drawing leaderboard, rank, score
        let myLenghtInfo = "";
        if (mySnake) {
            const sct = mySnake.sct + mySnake.rsc;
            const score = Math.floor((fpsls_29[sct] + mySnake.fam / fmlts_29[sct] - 1) * 15 - 5) / 1;
            myLenghtInfo = " " + score + "        " + mySnake.rsc;
        }
        const infoText = playersInfo_29 == "" ? myLenghtInfo : playersInfo_29 + "\n" + myLenghtInfo;
        ctx.textAlign = "left";
        ctx.fillStyle = 'rgb(30,60,255)';
        infoText.split('\n').forEach((line, index) => ctx.fillText(line, 10, 15 + index * 14));

        function addPointToPolyline(slx, sly) {
            const piX = (slx - leftSiX) * zoom;
            const piY = (sly - topSiY) * zoom;
            if (strokeMoveWas) {
                ctx.lineTo(piX, piY);
            }
            else {
                ctx.moveTo(piX, piY);
                strokeMoveWas = true;
            }
        }
        function siToPiX(siX) {
            return (siX - leftSiX) * zoom;
        }
        function siToPiY(siY) {
            return (siY - topSiY) * zoom;
        }
        function distBetwCoords(x1, y1, x2, y2) {
            return Math.sqrt(Math.pow(Math.abs(x1-x2), 2) + Math.pow(Math.abs(y2-y1), 2));
        }
        function createRgbaStr(r1, g1, b1, a1,  r2, g2, b2, a2,  speed) {
            function clcParam(paramDownPoint, paramUpPoint) {
                const speedDownPoint = 5.5;
                const speedUpPoint = 14;
                const speDif = speedUpPoint - speedDownPoint;
                const prmDif = paramUpPoint - paramDownPoint;
                return paramDownPoint + (prmDif * (speed - speedDownPoint) / speDif);
            }
            return 'rgba(' + clcParam(r1, r2) + ',' + clcParam(g1, g2) + ',' + clcParam(b1, b2) + ',' + clcParam(a1, a2) + ')';
        }
    }

    const serverIpAndPortField = document.createElement('input');
    serverIpAndPortField.type = 'text';
    serverIpAndPortField.placeholder = '57.129.37.42:444';
    serverIpAndPortField.value = serverIpAndPortForInputField_29;
    serverIpAndPortField.style.position = 'fixed';
    serverIpAndPortField.style.right = '10px';
    serverIpAndPortField.style.top = '7px';
    serverIpAndPortField.style.width = '130px';
    serverIpAndPortField.style.height = '20px';
    serverIpAndPortField.style.background = 'rgba(255,255,255,0.2)';
    serverIpAndPortField.style.border = '2px solid rgb(140,140,140)';
    serverIpAndPortField.style.borderRadius = '5px';
    serverIpAndPortField.style.color = 'rgb(50,50,50)';
    serverIpAndPortField.style.zIndex = 2;
    document.body.appendChild(serverIpAndPortField);

    const stopGameBtn = document.createElement('button');
    stopGameBtn.textContent = 'Stop the game';
    stopGameBtn.style.position = 'fixed';
    stopGameBtn.style.right = '10px';
    stopGameBtn.style.top = '35px';
    stopGameBtn.style.width = '130px';
    stopGameBtn.style.height = '20px';
    stopGameBtn.style.background = 'rgba(255,255,255,0.2)';
    stopGameBtn.style.border = '2px solid rgb(140,140,140)';
    stopGameBtn.style.borderRadius = '10px';
    stopGameBtn.style.color = 'rgb(140,140,140)';
    stopGameBtn.style.zIndex = 2;
    document.body.appendChild(stopGameBtn);

    const newGameBtn = document.createElement('button');
    newGameBtn.textContent = 'New game';
    newGameBtn.style.position = 'fixed';
    newGameBtn.style.right = '10px';
    newGameBtn.style.top = '63px';
    newGameBtn.style.width = '130px';
    newGameBtn.style.height = '20px';
    newGameBtn.style.background = 'rgba(255,255,255,0.2)';
    newGameBtn.style.border = '2px solid rgb(140,140,140)';
    newGameBtn.style.borderRadius = '10px';
    newGameBtn.style.color = 'rgb(140,140,140)';
    newGameBtn.style.zIndex = 2;
    document.body.appendChild(newGameBtn);

    window.onwheel = function(e) {
        const minZoom = 0.01;
        const maxZoom = 5.0;
        let consideredZoom;
        if (e.deltaY > 0) {
            consideredZoom = zoom - (zoom / 10.0);
            if (consideredZoom >= minZoom)
                zoom = consideredZoom;
        }
        else {
            consideredZoom = zoom + (zoom / 9.0);
            if (consideredZoom <= maxZoom)
                zoom = consideredZoom;
        }
    };

    window.onmousedown = function(e) {
        acceleration_29 = true;
    };

    window.onmouseup = function(e) {
        acceleration_29 = false;
    };

    window.onmousemove = function(e) {
        whereMouseX_29 = e.clientX;
        whereMouseY_29 = e.clientY;
    };

    stopGameBtn.onclick = function() {
        if (buttonFunctionality_29) {
            if (gameExists_29) {
                wantCloseCurrentGame_29 = true;
            }
        }
    };

    newGameBtn.onclick = function() {
        if (buttonFunctionality_29) {
            buttonFunctionality_29 = false;
            if (gameExists_29) {
                wantCloseCurrentGame_29 = true;
                wantNewGame_29 = true;
            }
            else {
                prepareNewGame_29();
            }
        }
    };

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址