Advertisement
FlyFar

Slither.IO Hack

Jul 27th, 2023
1,289
1
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 55.35 KB | Cybersecurity | 1 0
  1.  
  2. // ==UserScript==
  3. // @name         Slither.io-bot
  4. // @namespace    http://slither.io/
  5. // @version      1.2.9
  6. // @description  Slither.io bot
  7. // @author       unknown
  8. // @match        http://slither.io/
  9. // @grant        none
  10. // ==/UserScript==
  11.  
  12. /*
  13. Override bot options here
  14. Uncomment variables you wish to change from their default values
  15. Changes you make here will be kept between script versions
  16. */
  17. var customBotOptions = {
  18.     // target fps
  19.     // targetFps: 30,
  20.     // size of arc for collisionAngles
  21.     // arcSize: Math.PI / 8,
  22.     // radius multiple for circle intersects
  23.     // radiusMult: 10,
  24.     // food cluster size to trigger acceleration
  25.     // foodAccelSize: 60,
  26.     // maximum angle of food to trigger acceleration
  27.     // foodAccelAngle:  Math.PI / 3,
  28.     // how many frames per food check
  29.     // foodFrames: 4,
  30.     // round food cluster size up to the nearest
  31.     // foodRoundSize: 5,
  32.     // round food angle up to nearest for angle difference scoring
  33.     // foodRoundAngle: Math.PI / 8,
  34.     // food clusters at or below this size won't be considered
  35.     // if there is a collisionAngle
  36.     // foodSmallSize: 10,
  37.     // angle or higher where enemy heady is considered in the rear
  38.     // rearHeadAngle: 3 * Math.PI / 4,
  39.     // attack emeny rear head at this angle
  40.     // rearHeadDir: Math.PI / 2,
  41.     // quick radius toggle size in approach mode
  42.     // radiusApproachSize: 5,
  43.     // quick radius toggle size in avoid mode
  44.     // radiusAvoidSize: 25,
  45.     // uncomment to quickly revert to the default options
  46.     // if you update the script while this is active,
  47.     // you will lose your custom options
  48.     // useDefaults: true
  49. };
  50.  
  51. // Custom logging function - disabled by default
  52. window.log = function() {
  53.     if (window.logDebugging) {
  54.         console.log.apply(console, arguments);
  55.     }
  56. };
  57.  
  58. var canvasUtil = window.canvasUtil = (function() {
  59.     return {
  60.         // Ratio of screen size divided by canvas size.
  61.         canvasRatio: {
  62.             x: window.mc.width / window.ww,
  63.             y: window.mc.height / window.hh
  64.         },
  65.  
  66.         // Set direction of snake towards the virtual mouse coordinates
  67.         setMouseCoordinates: function(point) {
  68.             window.xm = point.x;
  69.             window.ym = point.y;
  70.         },
  71.  
  72.         // Convert snake-relative coordinates to absolute screen coordinates.
  73.         mouseToScreen: function(point) {
  74.             var screenX = point.x + (window.ww / 2);
  75.             var screenY = point.y + (window.hh / 2);
  76.             return {
  77.                 x: screenX,
  78.                 y: screenY
  79.             };
  80.         },
  81.  
  82.         // Convert screen coordinates to canvas coordinates.
  83.         screenToCanvas: function(point) {
  84.             var canvasX = window.csc *
  85.                 (point.x * canvasUtil.canvasRatio.x) - parseInt(window.mc.style.left);
  86.             var canvasY = window.csc *
  87.                 (point.y * canvasUtil.canvasRatio.y) - parseInt(window.mc.style.top);
  88.             return {
  89.                 x: canvasX,
  90.                 y: canvasY
  91.             };
  92.         },
  93.  
  94.         // Convert map coordinates to mouse coordinates.
  95.         mapToMouse: function(point) {
  96.             var mouseX = (point.x - window.snake.xx) * window.gsc;
  97.             var mouseY = (point.y - window.snake.yy) * window.gsc;
  98.             return {
  99.                 x: mouseX,
  100.                 y: mouseY
  101.             };
  102.         },
  103.  
  104.         // Map coordinates to Canvas coordinates.
  105.         mapToCanvas: function(point) {
  106.             var c = canvasUtil.mapToMouse(point);
  107.             c = canvasUtil.mouseToScreen(c);
  108.             c = canvasUtil.screenToCanvas(c);
  109.             return c;
  110.         },
  111.  
  112.         // Map to Canvas coordinates conversion for drawing circles.
  113.         circleMapToCanvas: function(circle) {
  114.             var newCircle = canvasUtil.mapToCanvas(circle);
  115.             return canvasUtil.circle(
  116.                 newCircle.x,
  117.                 newCircle.y,
  118.                 // Radius also needs to scale by .gsc
  119.                 circle.radius * window.gsc
  120.             );
  121.         },
  122.  
  123.         // Constructor for point type
  124.         point: function(x, y) {
  125.             var p = {
  126.                 x: Math.round(x),
  127.                 y: Math.round(y)
  128.             };
  129.  
  130.             return p;
  131.         },
  132.  
  133.         // Constructor for rect type
  134.         rect: function(x, y, w, h) {
  135.             var r = {
  136.                 x: Math.round(x),
  137.                 y: Math.round(y),
  138.                 width: Math.round(w),
  139.                 height: Math.round(h)
  140.             };
  141.  
  142.             return r;
  143.         },
  144.  
  145.         // Constructor for circle type
  146.         circle: function(x, y, r) {
  147.             var c = {
  148.                 x: Math.round(x),
  149.                 y: Math.round(y),
  150.                 radius: Math.round(r)
  151.             };
  152.  
  153.             return c;
  154.         },
  155.  
  156.         // Fast atan2
  157.         fastAtan2: function(y, x) {
  158.             const QPI = Math.PI / 4;
  159.             const TQPI = 3 * Math.PI / 4;
  160.             var r = 0.0;
  161.             var angle = 0.0;
  162.             var abs_y = Math.abs(y) + 1e-10;
  163.             if (x < 0) {
  164.                 r = (x + abs_y) / (abs_y - x);
  165.                 angle = TQPI;
  166.             } else {
  167.                 r = (x - abs_y) / (x + abs_y);
  168.                 angle = QPI;
  169.             }
  170.             angle += (0.1963 * r * r - 0.9817) * r;
  171.             if (y < 0) {
  172.                 return -angle;
  173.             }
  174.  
  175.             return angle;
  176.         },
  177.  
  178.         // Adjusts zoom in response to the mouse wheel.
  179.         setZoom: function(e) {
  180.             // Scaling ratio
  181.             if (window.gsc) {
  182.                 window.gsc *= Math.pow(0.9, e.wheelDelta / -120 || e.detail / 2 || 0);
  183.                 window.desired_gsc = window.gsc;
  184.             }
  185.         },
  186.  
  187.         // Restores zoom to the default value.
  188.         resetZoom: function() {
  189.             window.gsc = 0.9;
  190.             window.desired_gsc = 0.9;
  191.         },
  192.  
  193.         // Maintains Zoom
  194.         maintainZoom: function() {
  195.             if (window.desired_gsc !== undefined) {
  196.                 window.gsc = window.desired_gsc;
  197.             }
  198.         },
  199.  
  200.         // Sets background to the given image URL.
  201.         // Defaults to slither.io's own background.
  202.         setBackground: function(url) {
  203.             url = typeof url !== 'undefined' ? url : '/s/bg45.jpg';
  204.             window.ii.src = url;
  205.         },
  206.  
  207.         // Draw a rectangle on the canvas.
  208.         drawRect: function(rect, color, fill, alpha) {
  209.             if (alpha === undefined) alpha = 1;
  210.  
  211.             var context = window.mc.getContext('2d');
  212.             var lc = canvasUtil.mapToCanvas({
  213.                 x: rect.x,
  214.                 y: rect.y
  215.             });
  216.  
  217.             context.save();
  218.             context.globalAlpha = alpha;
  219.             context.strokeStyle = color;
  220.             context.rect(lc.x, lc.y, rect.width * window.gsc, rect.height * window.gsc);
  221.             context.stroke();
  222.             if (fill) {
  223.                 context.fillStyle = color;
  224.                 context.fill();
  225.             }
  226.             context.restore();
  227.         },
  228.  
  229.         // Draw a circle on the canvas.
  230.         drawCircle: function(circle, color, fill, alpha) {
  231.             if (alpha === undefined) alpha = 1;
  232.             if (circle.radius === undefined) circle.radius = 5;
  233.  
  234.             var context = window.mc.getContext('2d');
  235.             var drawCircle = canvasUtil.circleMapToCanvas(circle);
  236.  
  237.             context.save();
  238.             context.globalAlpha = alpha;
  239.             context.beginPath();
  240.             context.strokeStyle = color;
  241.             context.arc(drawCircle.x, drawCircle.y, drawCircle.radius, 0, Math.PI * 2);
  242.             context.stroke();
  243.             if (fill) {
  244.                 context.fillStyle = color;
  245.                 context.fill();
  246.             }
  247.             context.restore();
  248.         },
  249.  
  250.         // Draw an angle.
  251.         // @param {number} start -- where to start the angle
  252.         // @param {number} angle -- width of the angle
  253.         // @param {String|CanvasGradient|CanvasPattern} color
  254.         // @param {boolean} fill
  255.         // @param {number} alpha
  256.         drawAngle: function(start, angle, color, fill, alpha) {
  257.             if (alpha === undefined) alpha = 0.6;
  258.  
  259.             var context = window.mc.getContext('2d');
  260.  
  261.             context.save();
  262.             context.globalAlpha = alpha;
  263.             context.beginPath();
  264.             context.moveTo(window.mc.width / 2, window.mc.height / 2);
  265.             context.arc(window.mc.width / 2, window.mc.height / 2, window.gsc * 100, start, angle);
  266.             context.lineTo(window.mc.width / 2, window.mc.height / 2);
  267.             context.closePath();
  268.             context.stroke();
  269.             if (fill) {
  270.                 context.fillStyle = color;
  271.                 context.fill();
  272.             }
  273.             context.restore();
  274.         },
  275.  
  276.         // Draw a line on the canvas.
  277.         drawLine: function(p1, p2, color, width) {
  278.             if (width === undefined) width = 5;
  279.  
  280.             var context = window.mc.getContext('2d');
  281.             var dp1 = canvasUtil.mapToCanvas(p1);
  282.             var dp2 = canvasUtil.mapToCanvas(p2);
  283.  
  284.             context.save();
  285.             context.beginPath();
  286.             context.lineWidth = width * window.gsc;
  287.             context.strokeStyle = color;
  288.             context.moveTo(dp1.x, dp1.y);
  289.             context.lineTo(dp2.x, dp2.y);
  290.             context.stroke();
  291.             context.restore();
  292.         },
  293.  
  294.         // Given the start and end of a line, is point left.
  295.         isLeft: function(start, end, point) {
  296.             return ((end.x - start.x) * (point.y - start.y) -
  297.                 (end.y - start.y) * (point.x - start.x)) > 0;
  298.  
  299.         },
  300.  
  301.         // Get distance squared
  302.         getDistance2: function(x1, y1, x2, y2) {
  303.             var distance2 = Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2);
  304.             return distance2;
  305.         },
  306.  
  307.         getDistance2FromSnake: function(point) {
  308.             point.distance = canvasUtil.getDistance2(window.snake.xx, window.snake.yy,
  309.                 point.xx, point.yy);
  310.             return point;
  311.         },
  312.  
  313.         // Check if point in Rect
  314.         pointInRect: function(point, rect) {
  315.             if (rect.x <= point.x && rect.y <= point.y &&
  316.                 rect.x + rect.width >= point.x && rect.y + rect.height >= point.y) {
  317.                 return true;
  318.             }
  319.             return false;
  320.         },
  321.  
  322.         // Check if circles intersect
  323.         circleIntersect: function(circle1, circle2) {
  324.             var bothRadii = circle1.radius + circle2.radius;
  325.             var dx = circle1.x - circle2.x;
  326.             var dy = circle1.y - circle2.y;
  327.  
  328.             // Pretends the circles are squares for a quick collision check.
  329.             // If it collides, do the more expensive circle check.
  330.             if (dx + bothRadii > 0 && dy + bothRadii > 0 &&
  331.                 dx - bothRadii < 0 && dy - bothRadii < 0) {
  332.  
  333.                 var distance2 = canvasUtil.getDistance2(circle1.x, circle1.y, circle2.x, circle2.y);
  334.  
  335.                 if (distance2 < bothRadii * bothRadii) {
  336.                     if (window.visualDebugging) {
  337.                         var collisionPointCircle = canvasUtil.circle(
  338.                             ((circle1.x * circle2.radius) + (circle2.x * circle1.radius)) /
  339.                             bothRadii,
  340.                             ((circle1.y * circle2.radius) + (circle2.y * circle1.radius)) /
  341.                             bothRadii,
  342.                             5
  343.                         );
  344.                         canvasUtil.drawCircle(circle2, 'red', true);
  345.                         canvasUtil.drawCircle(collisionPointCircle, 'cyan', true);
  346.                     }
  347.                     return true;
  348.                 }
  349.             }
  350.             return false;
  351.         }
  352.     };
  353. })();
  354.  
  355. var bot = window.bot = (function() {
  356.     return {
  357.         isBotRunning: false,
  358.         isBotEnabled: true,
  359.         lookForFood: false,
  360.         collisionPoints: [],
  361.         collisionAngles: [],
  362.         scores: [],
  363.         foodTimeout: undefined,
  364.         sectorBoxSide: 0,
  365.         defaultAccel: 0,
  366.         sectorBox: {},
  367.         currentFood: {},
  368.         opt: {
  369.             // These are the bot's default options
  370.             // If you wish to customise these, use
  371.             // customBotOptions above
  372.             targetFps: 30,
  373.             arcSize: Math.PI / 8,
  374.             radiusMult: 10,
  375.             foodAccelSize: 60,
  376.             foodAccelAngle: Math.PI / 3,
  377.             foodFrames: 4,
  378.             foodRoundSize: 5,
  379.             foodRoundAngle: Math.PI / 8,
  380.             foodSmallSize: 10,
  381.             rearHeadAngle: 3 * Math.PI / 4,
  382.             rearHeadDir: Math.PI / 2,
  383.             radiusApproachSize: 5,
  384.             radiusAvoidSize: 25
  385.         },
  386.         MID_X: 0,
  387.         MID_Y: 0,
  388.         MAP_R: 0,
  389.  
  390.         getSnakeWidth: function(sc) {
  391.             if (sc === undefined) sc = window.snake.sc;
  392.             return Math.round(sc * 29.0);
  393.         },
  394.  
  395.         quickRespawn: function() {
  396.             window.dead_mtm = 0;
  397.             window.login_fr = 0;
  398.  
  399.             bot.isBotRunning = false;
  400.             window.forcing = true;
  401.             window.connect();
  402.             window.forcing = false;
  403.         },
  404.  
  405.         // angleBetween - get the smallest angle between two angles (0-pi)
  406.         angleBetween: function(a1, a2) {
  407.             var r1 = 0.0;
  408.             var r2 = 0.0;
  409.  
  410.             r1 = (a1 - a2) % Math.PI;
  411.             r2 = (a2 - a1) % Math.PI;
  412.  
  413.             return r1 < r2 ? -r1 : r2;
  414.         },
  415.  
  416.         // Avoid headPoint
  417.         avoidHeadPoint: function(collisionPoint) {
  418.             var cehang = canvasUtil.fastAtan2(
  419.                 collisionPoint.yy - window.snake.yy, collisionPoint.xx - window.snake.xx);
  420.             var diff = bot.angleBetween(window.snake.ehang, cehang);
  421.  
  422.             if (Math.abs(diff) > bot.opt.rearHeadAngle) {
  423.                 var dir = diff > 0 ? -bot.opt.rearHeadDir : bot.opt.rearHeadDir;
  424.                 bot.changeHeading(dir);
  425.             } else {
  426.                 bot.avoidCollisionPoint(collisionPoint);
  427.             }
  428.         },
  429.  
  430.         // Change heading by ang
  431.         // +0-pi turn left
  432.         // -0-pi turn right
  433.  
  434.         changeHeading: function(angle) {
  435.             var heading = {
  436.                 x: window.snake.xx + 500 * bot.cos,
  437.                 y: window.snake.yy + 500 * bot.sin
  438.             };
  439.  
  440.             var cos = Math.cos(-angle);
  441.             var sin = Math.sin(-angle);
  442.  
  443.             window.goalCoordinates = {
  444.                 x: Math.round(
  445.                     cos * (heading.x - window.snake.xx) -
  446.                     sin * (heading.y - window.snake.yy) + window.snake.xx),
  447.                 y: Math.round(
  448.                     sin * (heading.x - window.snake.xx) +
  449.                     cos * (heading.y - window.snake.yy) + window.snake.yy)
  450.             };
  451.  
  452.             canvasUtil.setMouseCoordinates(canvasUtil.mapToMouse(window.goalCoordinates));
  453.         },
  454.  
  455.         // Avoid collision point by ang
  456.         // ang radians <= Math.PI (180deg)
  457.         avoidCollisionPoint: function(collisionPoint, ang) {
  458.             if (ang === undefined || ang > Math.PI) {
  459.                 ang = Math.PI;
  460.             }
  461.  
  462.             var end = {
  463.                 x: window.snake.xx + 2000 * bot.cos,
  464.                 y: window.snake.yy + 2000 * bot.sin
  465.             };
  466.  
  467.             if (window.visualDebugging) {
  468.                 canvasUtil.drawLine({
  469.                     x: window.snake.xx,
  470.                     y: window.snake.yy
  471.                 },
  472.                     end,
  473.                     'orange', 5);
  474.                 canvasUtil.drawLine({
  475.                     x: window.snake.xx,
  476.                     y: window.snake.yy
  477.                 }, {
  478.                     x: collisionPoint.xx,
  479.                     y: collisionPoint.yy
  480.                 },
  481.                     'red', 5);
  482.             }
  483.  
  484.             var cos = Math.cos(ang);
  485.             var sin = Math.sin(ang);
  486.  
  487.             if (canvasUtil.isLeft({
  488.                 x: window.snake.xx,
  489.                 y: window.snake.yy
  490.             }, end, {
  491.                 x: collisionPoint.xx,
  492.                 y: collisionPoint.yy
  493.             })) {
  494.                 sin = -sin;
  495.             }
  496.  
  497.             window.goalCoordinates = {
  498.                 x: Math.round(
  499.                     cos * (collisionPoint.xx - window.snake.xx) -
  500.                     sin * (collisionPoint.yy - window.snake.yy) + window.snake.xx),
  501.                 y: Math.round(
  502.                     sin * (collisionPoint.xx - window.snake.xx) +
  503.                     cos * (collisionPoint.yy - window.snake.yy) + window.snake.yy)
  504.             };
  505.  
  506.             canvasUtil.setMouseCoordinates(canvasUtil.mapToMouse(window.goalCoordinates));
  507.         },
  508.  
  509.         // Sorting by  property 'distance'
  510.         sortDistance: function(a, b) {
  511.             return a.distance - b.distance;
  512.         },
  513.  
  514.         // get collision angle index, expects angle +/i 0 to Math.PI
  515.         getAngleIndex: function(angle) {
  516.             const ARCSIZE = bot.opt.arcSize;
  517.             var index;
  518.  
  519.             if (angle < 0) {
  520.                 angle += 2 * Math.PI;
  521.             }
  522.  
  523.             index = Math.round(angle * (1 / ARCSIZE));
  524.  
  525.             if (index === (2 * Math.PI) / ARCSIZE) {
  526.                 return 0;
  527.             }
  528.             return index;
  529.         },
  530.  
  531.         // Add to collisionAngles if distance is closer
  532.         addCollisionAngle: function(sp) {
  533.             var ang = canvasUtil.fastAtan2(
  534.                 Math.round(sp.yy - window.snake.yy),
  535.                 Math.round(sp.xx - window.snake.xx));
  536.             var aIndex = bot.getAngleIndex(ang);
  537.  
  538.             var actualDistance = Math.round(Math.pow(
  539.                 Math.sqrt(sp.distance) - sp.radius, 2));
  540.  
  541.             if (bot.collisionAngles[aIndex] === undefined) {
  542.                 bot.collisionAngles[aIndex] = {
  543.                     x: Math.round(sp.xx),
  544.                     y: Math.round(sp.yy),
  545.                     ang: ang,
  546.                     snake: sp.snake,
  547.                     distance: actualDistance
  548.                 };
  549.             } else if (bot.collisionAngles[aIndex].distance > sp.distance) {
  550.                 bot.collisionAngles[aIndex].x = Math.round(sp.xx);
  551.                 bot.collisionAngles[aIndex].y = Math.round(sp.yy);
  552.                 bot.collisionAngles[aIndex].ang = ang;
  553.                 bot.collisionAngles[aIndex].snake = sp.snake;
  554.                 bot.collisionAngles[aIndex].distance = actualDistance;
  555.             }
  556.         },
  557.  
  558.         // Get closest collision point per snake.
  559.         getCollisionPoints: function() {
  560.             var scPoint;
  561.  
  562.             bot.collisionPoints = [];
  563.             bot.collisionAngles = [];
  564.  
  565.             for (var snake = 0, ls = window.snakes.length; snake < ls; snake++) {
  566.                 scPoint = undefined;
  567.  
  568.                 if (window.snakes[snake].id !== window.snake.id &&
  569.                     window.snakes[snake].alive_amt === 1) {
  570.  
  571.                     scPoint = {
  572.                         xx: window.snakes[snake].xx,
  573.                         yy: window.snakes[snake].yy,
  574.                         snake: snake,
  575.                         radius: bot.getSnakeWidth(window.snakes[snake].sc) / 2
  576.                     };
  577.                     canvasUtil.getDistance2FromSnake(scPoint);
  578.                     bot.addCollisionAngle(scPoint);
  579.                     if (window.visualDebugging) {
  580.                         canvasUtil.drawCircle(canvasUtil.circle(
  581.                                 scPoint.xx,
  582.                                 scPoint.yy,
  583.                                 scPoint.radius),
  584.                             'red', false);
  585.                     }
  586.  
  587.                     for (var pts = 0, lp = window.snakes[snake].pts.length; pts < lp; pts++) {
  588.                         if (!window.snakes[snake].pts[pts].dying &&
  589.                             canvasUtil.pointInRect({
  590.                                 x: window.snakes[snake].pts[pts].xx,
  591.                                 y: window.snakes[snake].pts[pts].yy
  592.                             }, bot.sectorBox)
  593.                         ) {
  594.                             var collisionPoint = {
  595.                                 xx: window.snakes[snake].pts[pts].xx,
  596.                                 yy: window.snakes[snake].pts[pts].yy,
  597.                                 snake: snake,
  598.                                 radius: bot.getSnakeWidth(window.snakes[snake].sc) / 2
  599.                             };
  600.  
  601.                             if (window.visualDebugging && true === false) {
  602.                                 canvasUtil.drawCircle(canvasUtil.circle(
  603.                                         collisionPoint.xx,
  604.                                         collisionPoint.yy,
  605.                                         collisionPoint.radius),
  606.                                     '#00FF00', false);
  607.                             }
  608.  
  609.                             canvasUtil.getDistance2FromSnake(collisionPoint);
  610.                             bot.addCollisionAngle(collisionPoint);
  611.  
  612.                             if (scPoint === undefined ||
  613.                                 scPoint.distance > collisionPoint.distance) {
  614.                                 scPoint = collisionPoint;
  615.                             }
  616.                         }
  617.                     }
  618.                 }
  619.                 if (scPoint !== undefined) {
  620.                     bot.collisionPoints.push(scPoint);
  621.                     if (window.visualDebugging) {
  622.                         canvasUtil.drawCircle(canvasUtil.circle(
  623.                             scPoint.xx,
  624.                             scPoint.yy,
  625.                             scPoint.radius
  626.                         ), 'red', false);
  627.                     }
  628.                 }
  629.             }
  630.  
  631.             // WALL
  632.             if (canvasUtil.getDistance2(bot.MID_X, bot.MID_Y, window.snake.xx, window.snake.yy) >
  633.                 Math.pow(bot.MAP_R - 1000, 2)) {
  634.                 var midAng = canvasUtil.fastAtan2(
  635.                     window.snake.yy - bot.MID_X, window.snake.xx - bot.MID_Y);
  636.                 scPoint = {
  637.                     xx: bot.MID_X + bot.MAP_R * Math.cos(midAng),
  638.                     yy: bot.MID_Y + bot.MAP_R * Math.sin(midAng),
  639.                     snake: -1,
  640.                     radius: bot.snakeWidth
  641.                 };
  642.                 canvasUtil.getDistance2FromSnake(scPoint);
  643.                 bot.collisionPoints.push(scPoint);
  644.                 bot.addCollisionAngle(scPoint);
  645.                 if (window.visualDebugging) {
  646.                     canvasUtil.drawCircle(canvasUtil.circle(
  647.                         scPoint.xx,
  648.                         scPoint.yy,
  649.                         scPoint.radius
  650.                     ), 'yellow', false);
  651.                 }
  652.             }
  653.  
  654.             bot.collisionPoints.sort(bot.sortDistance);
  655.             if (window.visualDebugging) {
  656.                 for (var i = 0; i < bot.collisionAngles.length; i++) {
  657.                     if (bot.collisionAngles[i] !== undefined) {
  658.                         canvasUtil.drawLine({
  659.                             x: window.snake.xx,
  660.                             y: window.snake.yy
  661.                         }, {
  662.                             x: bot.collisionAngles[i].x,
  663.                             y: bot.collisionAngles[i].y
  664.                         },
  665.                             '#99ffcc', 2);
  666.                     }
  667.                 }
  668.             }
  669.         },
  670.  
  671.         // Checks to see if you are going to collide with anything in the collision detection radius
  672.         checkCollision: function() {
  673.             var headCircle = canvasUtil.circle(
  674.                 window.snake.xx, window.snake.yy,
  675.                 bot.speedMult * bot.opt.radiusMult / 2 * bot.snakeRadius
  676.             );
  677.  
  678.             var fullHeadCircle = canvasUtil.circle(
  679.                 window.snake.xx, window.snake.yy,
  680.                 bot.opt.radiusMult * bot.snakeRadius
  681.             );
  682.  
  683.             if (window.visualDebugging) {
  684.                 canvasUtil.drawCircle(fullHeadCircle, 'red');
  685.                 canvasUtil.drawCircle(headCircle, 'blue', false);
  686.             }
  687.  
  688.             bot.getCollisionPoints();
  689.             if (bot.collisionPoints.length === 0) return false;
  690.  
  691.             for (var i = 0; i < bot.collisionPoints.length; i++) {
  692.                 var collisionCircle = canvasUtil.circle(
  693.                     bot.collisionPoints[i].xx,
  694.                     bot.collisionPoints[i].yy,
  695.                     bot.collisionPoints[i].radius
  696.                 );
  697.  
  698.                 if (canvasUtil.circleIntersect(headCircle, collisionCircle)) {
  699.                     window.setAcceleration(bot.defaultAccel);
  700.                     bot.avoidCollisionPoint(bot.collisionPoints[i]);
  701.                     return true;
  702.                 }
  703.  
  704.                 // snake -1 is special case for non snake object.
  705.                 if (bot.collisionPoints[i].snake !== -1) {
  706.                     var enemyHeadCircle = canvasUtil.circle(
  707.                         window.snakes[bot.collisionPoints[i].snake].xx,
  708.                         window.snakes[bot.collisionPoints[i].snake].yy,
  709.                         bot.collisionPoints[i].radius
  710.                     );
  711.  
  712.                     if (canvasUtil.circleIntersect(fullHeadCircle, enemyHeadCircle)) {
  713.                         if (window.snakes[bot.collisionPoints[i].snake].sp > 10) {
  714.                             window.setAcceleration(1);
  715.                         } else {
  716.                             window.setAcceleration(bot.defaultAccel);
  717.                         }
  718.                         bot.avoidHeadPoint({
  719.                             xx: window.snakes[bot.collisionPoints[i].snake].xx,
  720.                             yy: window.snakes[bot.collisionPoints[i].snake].yy
  721.                         });
  722.                         return true;
  723.                     }
  724.                 }
  725.             }
  726.             window.setAcceleration(bot.defaultAccel);
  727.             return false;
  728.         },
  729.  
  730.         sortScore: function(a, b) {
  731.             return b.score - a.score;
  732.         },
  733.  
  734.         // Round angle difference up to nearest foodRoundAngle degrees.
  735.         // Round food up to nearest foodRoundsz, square for distance^2
  736.         scoreFood: function(f) {
  737.             f.score = Math.pow(Math.ceil(f.sz / bot.opt.foodRoundSize) * bot.opt.foodRoundSize, 2) /
  738.                 f.distance / (Math.ceil(f.da / bot.opt.foodRoundAngle) * bot.opt.foodRoundAngle);
  739.         },
  740.  
  741.         computeFoodGoal: function() {
  742.             var foodClusters = [];
  743.             var foodGetIndex = [];
  744.             var fi = 0;
  745.             var sw = bot.snakeWidth;
  746.  
  747.             for (var i = 0; i < window.foods.length && window.foods[i] !== null; i++) {
  748.                 var a;
  749.                 var da;
  750.                 var distance;
  751.                 var sang = window.snake.ehang;
  752.                 var f = window.foods[i];
  753.  
  754.                 if (!f.eaten &&
  755.                     !(
  756.                         canvasUtil.circleIntersect(
  757.                             canvasUtil.circle(f.xx, f.yy, 2),
  758.                             bot.sidecircle_l) ||
  759.                         canvasUtil.circleIntersect(
  760.                             canvasUtil.circle(f.xx, f.yy, 2),
  761.                             bot.sidecircle_r))) {
  762.  
  763.                     var cx = Math.round(Math.round(f.xx / sw) * sw);
  764.                     var cy = Math.round(Math.round(f.yy / sw) * sw);
  765.                     var csz = Math.round(f.sz);
  766.  
  767.                     if (foodGetIndex[cx + '|' + cy] === undefined) {
  768.                         foodGetIndex[cx + '|' + cy] = fi;
  769.                         a = canvasUtil.fastAtan2(cy - window.snake.yy, cx - window.snake.xx);
  770.                         da = Math.min(
  771.                             (2 * Math.PI) - Math.abs(a - sang), Math.abs(a - sang));
  772.                         distance = Math.round(
  773.                             canvasUtil.getDistance2(cx, cy, window.snake.xx, window.snake.yy));
  774.                         foodClusters[fi] = {
  775.                             x: cx,
  776.                             y: cy,
  777.                             a: a,
  778.                             da: da,
  779.                             sz: csz,
  780.                             distance: distance,
  781.                             score: 0.0
  782.                         };
  783.                         fi++;
  784.                     } else {
  785.                         foodClusters[foodGetIndex[cx + '|' + cy]].sz += csz;
  786.                     }
  787.                 }
  788.             }
  789.  
  790.             foodClusters.forEach(bot.scoreFood);
  791.             foodClusters.sort(bot.sortScore);
  792.  
  793.             for (i = 0; i < foodClusters.length; i++) {
  794.                 var aIndex = bot.getAngleIndex(foodClusters[i].a);
  795.                 if (bot.collisionAngles[aIndex] === undefined ||
  796.                     (Math.sqrt(bot.collisionAngles[aIndex].distance) -
  797.                         bot.snakeRadius * bot.opt.radiusMult / 2 >
  798.                         Math.sqrt(foodClusters[i].distance) &&
  799.                         foodClusters[i].sz > bot.opt.foodSmallSize)
  800.                 ) {
  801.                     bot.currentFood = foodClusters[i];
  802.                     return;
  803.                 }
  804.             }
  805.             bot.currentFood = {
  806.                 x: bot.MID_X,
  807.                 y: bot.MID_Y
  808.             };
  809.         },
  810.  
  811.         foodAccel: function() {
  812.             var aIndex = 0;
  813.  
  814.             if (bot.currentFood && bot.currentFood.sz > bot.opt.foodAccelSize) {
  815.                 aIndex = bot.getAngleIndex(bot.currentFood.a);
  816.  
  817.                 if (
  818.                     bot.collisionAngles[aIndex] && bot.collisionAngles[aIndex].distance >
  819.                     bot.currentFood.distance + bot.snakeWidth * bot.opt.radiusMult &&
  820.                     bot.currentFood.da < bot.opt.foodAccelAngle) {
  821.                     return 1;
  822.                 }
  823.  
  824.                 if (bot.collisionAngles[aIndex] === undefined) {
  825.                     return 1;
  826.                 }
  827.             }
  828.  
  829.             return bot.defaultAccel;
  830.         },
  831.  
  832.         every: function() {
  833.             bot.MID_X = window.grd;
  834.             bot.MID_Y = window.grd;
  835.             bot.MAP_R = window.grd * 0.98;
  836.  
  837.             bot.sectorBoxSide = Math.floor(Math.sqrt(window.sectors.length)) * window.sector_size;
  838.             bot.sectorBox = canvasUtil.rect(
  839.                 window.snake.xx - (bot.sectorBoxSide / 2),
  840.                 window.snake.yy - (bot.sectorBoxSide / 2),
  841.                 bot.sectorBoxSide, bot.sectorBoxSide);
  842.             // if (window.visualDebugging) canvasUtil.drawRect(bot.sectorBox, '#c0c0c0', true, 0.1);
  843.  
  844.             bot.cos = Math.cos(window.snake.ang);
  845.             bot.sin = Math.sin(window.snake.ang);
  846.  
  847.             bot.speedMult = window.snake.sp / 5.78;
  848.             bot.snakeRadius = bot.getSnakeWidth() / 2;
  849.             bot.snakeWidth = bot.getSnakeWidth();
  850.  
  851.             bot.sidecircle_r = canvasUtil.circle(
  852.                 window.snake.lnp.xx -
  853.                 ((window.snake.lnp.yy + bot.sin * bot.snakeWidth) -
  854.                     window.snake.lnp.yy),
  855.                 window.snake.lnp.yy +
  856.                 ((window.snake.lnp.xx + bot.cos * bot.snakeWidth) -
  857.                     window.snake.lnp.xx),
  858.                 bot.snakeWidth * bot.speedMult
  859.             );
  860.  
  861.             bot.sidecircle_l = canvasUtil.circle(
  862.                 window.snake.lnp.xx +
  863.                 ((window.snake.lnp.yy + bot.sin * bot.snakeWidth) -
  864.                     window.snake.lnp.yy),
  865.                 window.snake.lnp.yy -
  866.                 ((window.snake.lnp.xx + bot.cos * bot.snakeWidth) -
  867.                     window.snake.lnp.xx),
  868.                 bot.snakeWidth * bot.speedMult
  869.             );
  870.         },
  871.  
  872.         // Main bot
  873.         go: function() {
  874.             bot.every();
  875.  
  876.             if (bot.checkCollision()) {
  877.                 bot.lookForFood = false;
  878.                 if (bot.foodTimeout) {
  879.                     window.clearTimeout(bot.foodTimeout);
  880.                     bot.foodTimeout = window.setTimeout(
  881.                         bot.foodTimer, 1000 / bot.opt.targetFps * bot.opt.foodFrames);
  882.                 }
  883.             } else {
  884.                 bot.lookForFood = true;
  885.                 if (bot.foodTimeout === undefined) {
  886.                     bot.foodTimeout = window.setTimeout(
  887.                         bot.foodTimer, 1000 / bot.opt.targetFps * bot.opt.foodFrames);
  888.                 }
  889.                 window.setAcceleration(bot.foodAccel());
  890.             }
  891.         },
  892.  
  893.         // Timer version of food check
  894.         foodTimer: function() {
  895.             if (window.playing && bot.lookForFood &&
  896.                 window.snake !== null && window.snake.alive_amt === 1) {
  897.                 bot.computeFoodGoal();
  898.                 window.goalCoordinates = bot.currentFood;
  899.                 canvasUtil.setMouseCoordinates(canvasUtil.mapToMouse(window.goalCoordinates));
  900.             }
  901.             bot.foodTimeout = undefined;
  902.         }
  903.     };
  904. })();
  905.  
  906. var userInterface = window.userInterface = (function() {
  907.     // Save the original slither.io functions so we can modify them, or reenable them later.
  908.     var original_keydown = document.onkeydown;
  909.     var original_onmouseDown = window.onmousedown;
  910.     var original_oef = window.oef;
  911.     var original_redraw = window.redraw;
  912.     var original_onmousemove = window.onmousemove;
  913.  
  914.     window.oef = function() {};
  915.     window.redraw = function() {};
  916.  
  917.     return {
  918.         overlays: {},
  919.  
  920.         initOverlays: function() {
  921.             var botOverlay = document.createElement('div');
  922.             botOverlay.style.position = 'fixed';
  923.             botOverlay.style.right = '5px';
  924.             botOverlay.style.bottom = '112px';
  925.             botOverlay.style.width = '150px';
  926.             botOverlay.style.height = '85px';
  927.             // botOverlay.style.background = 'rgba(0, 0, 0, 0.5)';
  928.             botOverlay.style.color = '#C0C0C0';
  929.             botOverlay.style.fontFamily = 'Consolas, Verdana';
  930.             botOverlay.style.zIndex = 999;
  931.             botOverlay.style.fontSize = '14px';
  932.             botOverlay.style.padding = '5px';
  933.             botOverlay.style.borderRadius = '5px';
  934.             botOverlay.className = 'nsi';
  935.             document.body.appendChild(botOverlay);
  936.  
  937.             var serverOverlay = document.createElement('div');
  938.             serverOverlay.style.position = 'fixed';
  939.             serverOverlay.style.right = '5px';
  940.             serverOverlay.style.bottom = '5px';
  941.             serverOverlay.style.width = '160px';
  942.             serverOverlay.style.height = '14px';
  943.             serverOverlay.style.color = '#C0C0C0';
  944.             serverOverlay.style.fontFamily = 'Consolas, Verdana';
  945.             serverOverlay.style.zIndex = 999;
  946.             serverOverlay.style.fontSize = '14px';
  947.             serverOverlay.className = 'nsi';
  948.             document.body.appendChild(serverOverlay);
  949.  
  950.             var prefOverlay = document.createElement('div');
  951.             prefOverlay.style.position = 'fixed';
  952.             prefOverlay.style.left = '10px';
  953.             prefOverlay.style.top = '75px';
  954.             prefOverlay.style.width = '260px';
  955.             prefOverlay.style.height = '210px';
  956.             // prefOverlay.style.background = 'rgba(0, 0, 0, 0.5)';
  957.             prefOverlay.style.color = '#C0C0C0';
  958.             prefOverlay.style.fontFamily = 'Consolas, Verdana';
  959.             prefOverlay.style.zIndex = 999;
  960.             prefOverlay.style.fontSize = '14px';
  961.             prefOverlay.style.padding = '5px';
  962.             prefOverlay.style.borderRadius = '5px';
  963.             prefOverlay.className = 'nsi';
  964.             document.body.appendChild(prefOverlay);
  965.  
  966.             var statsOverlay = document.createElement('div');
  967.             statsOverlay.style.position = 'fixed';
  968.             statsOverlay.style.left = '10px';
  969.             statsOverlay.style.top = '340px';
  970.             statsOverlay.style.width = '140px';
  971.             statsOverlay.style.height = '210px';
  972.             // statsOverlay.style.background = 'rgba(0, 0, 0, 0.5)';
  973.             statsOverlay.style.color = '#C0C0C0';
  974.             statsOverlay.style.fontFamily = 'Consolas, Verdana';
  975.             statsOverlay.style.zIndex = 998;
  976.             statsOverlay.style.fontSize = '14px';
  977.             statsOverlay.style.padding = '5px';
  978.             statsOverlay.style.borderRadius = '5px';
  979.             statsOverlay.className = 'nsi';
  980.             document.body.appendChild(statsOverlay);
  981.  
  982.             userInterface.overlays.botOverlay = botOverlay;
  983.             userInterface.overlays.serverOverlay = serverOverlay;
  984.             userInterface.overlays.prefOverlay = prefOverlay;
  985.             userInterface.overlays.statsOverlay = statsOverlay;
  986.         },
  987.  
  988.         toggleOverlays: function() {
  989.             Object.keys(userInterface.overlays).forEach(function(okey) {
  990.                 var oVis = userInterface.overlays[okey].style.visibility !== 'hidden' ?
  991.                     'hidden' : 'visible';
  992.                 userInterface.overlays[okey].style.visibility = oVis;
  993.                 window.visualDebugging = oVis === 'visible';
  994.             });
  995.         },
  996.         toggleLeaderboard: function() {
  997.             window.leaderboard = !window.leaderboard;
  998.             window.log('Leaderboard set to: ' + window.leaderboard);
  999.             userInterface.savePreference('leaderboard', window.leaderboard);
  1000.             if (window.leaderboard) {
  1001.                 // window.lbh.style.display = 'block';
  1002.                 // window.lbs.style.display = 'block';
  1003.                 // window.lbp.style.display = 'block';
  1004.                 window.lbn.style.display = 'block';
  1005.             } else {
  1006.                 // window.lbh.style.display = 'none';
  1007.                 // window.lbs.style.display = 'none';
  1008.                 // window.lbp.style.display = 'none';
  1009.                 window.lbn.style.display = 'none';
  1010.             }
  1011.         },
  1012.         removeLogo: function() {
  1013.             if (typeof window.showlogo_iv !== 'undefined') {
  1014.                 window.ncka = window.lgss = window.lga = 1;
  1015.                 clearInterval(window.showlogo_iv);
  1016.                 showLogo(true);
  1017.             }
  1018.         },
  1019.         // Save variable to local storage
  1020.         savePreference: function(item, value) {
  1021.             window.localStorage.setItem(item, value);
  1022.             userInterface.onPrefChange();
  1023.         },
  1024.  
  1025.         // Load a variable from local storage
  1026.         loadPreference: function(preference, defaultVar) {
  1027.             var savedItem = window.localStorage.getItem(preference);
  1028.             if (savedItem !== null) {
  1029.                 if (savedItem === 'true') {
  1030.                     window[preference] = true;
  1031.                 } else if (savedItem === 'false') {
  1032.                     window[preference] = false;
  1033.                 } else {
  1034.                     window[preference] = savedItem;
  1035.                 }
  1036.                 window.log('Setting found for ' + preference + ': ' + window[preference]);
  1037.             } else {
  1038.                 window[preference] = defaultVar;
  1039.                 window.log('No setting found for ' + preference +
  1040.                     '. Used default: ' + window[preference]);
  1041.             }
  1042.             userInterface.onPrefChange();
  1043.             return window[preference];
  1044.         },
  1045.  
  1046.         // Saves username when you click on "Play" button
  1047.         playButtonClickListener: function() {
  1048.             userInterface.saveNick();
  1049.             userInterface.loadPreference('autoRespawn', false);
  1050.             userInterface.onPrefChange();
  1051.         },
  1052.  
  1053.         // Preserve nickname
  1054.         saveNick: function() {
  1055.             var nick = document.getElementById('nick').value;
  1056.             userInterface.savePreference('savedNick', nick);
  1057.         },
  1058.  
  1059.         // Hide top score
  1060.         hideTop: function() {
  1061.             var nsidivs = document.querySelectorAll('div.nsi');
  1062.             for (var i = 0; i < nsidivs.length; i++) {
  1063.                 if (nsidivs[i].style.top === '4px' && nsidivs[i].style.width === '300px') {
  1064.                     nsidivs[i].style.visibility = 'hidden';
  1065.                     bot.isTopHidden = true;
  1066.                     window.topscore = nsidivs[i];
  1067.                 }
  1068.             }
  1069.         },
  1070.  
  1071.         // Store FPS data
  1072.         framesPerSecond: {
  1073.             fps: 0,
  1074.             fpsTimer: function() {
  1075.                 if (window.playing && window.fps && window.lrd_mtm) {
  1076.                     if (Date.now() - window.lrd_mtm > 970) {
  1077.                         userInterface.framesPerSecond.fps = window.fps;
  1078.                     }
  1079.                 }
  1080.             }
  1081.         },
  1082.  
  1083.         onkeydown: function(e) {
  1084.             // Original slither.io onkeydown function + whatever is under it
  1085.             original_keydown(e);
  1086.             if (window.playing) {
  1087.                 // Letter `T` to toggle bot
  1088.                 if (e.keyCode === 84) {
  1089.                     bot.isBotEnabled = !bot.isBotEnabled;
  1090.                 }
  1091.                 // Letter 'U' to toggle debugging (console)
  1092.                 if (e.keyCode === 85) {
  1093.                     window.logDebugging = !window.logDebugging;
  1094.                     window.log('Log debugging set to: ' + window.logDebugging);
  1095.                     userInterface.savePreference('logDebugging', window.logDebugging);
  1096.                 }
  1097.                 // Letter 'Y' to toggle debugging (visual)
  1098.                 if (e.keyCode === 89) {
  1099.                     window.visualDebugging = !window.visualDebugging;
  1100.                     window.log('Visual debugging set to: ' + window.visualDebugging);
  1101.                     userInterface.savePreference('visualDebugging', window.visualDebugging);
  1102.                 }
  1103.                 // Letter 'G' to toggle leaderboard
  1104.                 if (e.keyCode === 71) {
  1105.                     userInterface.toggleLeaderboard(!window.leaderboard);
  1106.                 }
  1107.                 // Letter 'I' to toggle autorespawn
  1108.                 if (e.keyCode === 73) {
  1109.                     window.autoRespawn = !window.autoRespawn;
  1110.                     window.log('Automatic Respawning set to: ' + window.autoRespawn);
  1111.                     userInterface.savePreference('autoRespawn', window.autoRespawn);
  1112.                 }
  1113.                 // Letter 'H' to toggle hidden mode
  1114.                 if (e.keyCode === 72) {
  1115.                     userInterface.toggleOverlays();
  1116.                 }
  1117.                 // Letter 'B' to prompt for a custom background url
  1118.                 if (e.keyCode === 66) {
  1119.                     var url = prompt('Please enter a background url:');
  1120.                     if (url !== null) {
  1121.                         canvasUtil.setBackground(url);
  1122.                     }
  1123.                 }
  1124.                 // Letter 'O' to change rendermode (visual)
  1125.                 if (e.keyCode === 79) {
  1126.                     userInterface.toggleMobileRendering(!window.mobileRender);
  1127.                 }
  1128.                 // Letter 'A' to increase collision detection radius
  1129.                 if (e.keyCode === 65) {
  1130.                     bot.opt.radiusMult++;
  1131.                     window.log(
  1132.                         'radiusMult set to: ' + bot.opt.radiusMult);
  1133.                 }
  1134.                 // Letter 'S' to decrease collision detection radius
  1135.                 if (e.keyCode === 83) {
  1136.                     if (bot.opt.radiusMult > 1) {
  1137.                         bot.opt.radiusMult--;
  1138.                         window.log(
  1139.                             'radiusMult set to: ' +
  1140.                             bot.opt.radiusMult);
  1141.                     }
  1142.                 }
  1143.                 // Letter 'D' to quick toggle collision radius
  1144.                 if (e.keyCode === 68) {
  1145.                     if (bot.opt.radiusMult >
  1146.                         ((bot.opt.radiusAvoidSize - bot.opt.radiusApproachSize) /
  1147.                             2 + bot.opt.radiusApproachSize)) {
  1148.                         bot.opt.radiusMult = bot.opt.radiusApproachSize;
  1149.                     } else {
  1150.                         bot.opt.radiusMult = bot.opt.radiusAvoidSize;
  1151.                     }
  1152.                     window.log(
  1153.                         'radiusMult set to: ' + bot.opt.radiusMult);
  1154.                 }
  1155.                 // Letter 'Z' to reset zoom
  1156.                 if (e.keyCode === 90) {
  1157.                     canvasUtil.resetZoom();
  1158.                 }
  1159.                 // Letter 'Q' to quit to main menu
  1160.                 if (e.keyCode === 81) {
  1161.                     window.autoRespawn = false;
  1162.                     userInterface.quit();
  1163.                 }
  1164.                 // 'ESC' to quickly respawn
  1165.                 if (e.keyCode === 27) {
  1166.                     bot.quickRespawn();
  1167.                 }
  1168.                 // Save nickname when you press "Enter"
  1169.                 if (e.keyCode === 13) {
  1170.                     userInterface.saveNick();
  1171.                 }
  1172.                 userInterface.onPrefChange();
  1173.             }
  1174.         },
  1175.  
  1176.         onmousedown: function(e) {
  1177.             if (window.playing) {
  1178.                 switch (e.which) {
  1179.                     // "Left click" to manually speed up the slither
  1180.                     case 1:
  1181.                         bot.defaultAccel = 1;
  1182.                         if (!bot.isBotEnabled) {
  1183.                             original_onmouseDown(e);
  1184.                         }
  1185.                         break;
  1186.                         // "Right click" to toggle bot in addition to the letter "T"
  1187.                     case 3:
  1188.                         bot.isBotEnabled = !bot.isBotEnabled;
  1189.                         break;
  1190.                 }
  1191.             } else {
  1192.                 original_onmouseDown(e);
  1193.             }
  1194.             userInterface.onPrefChange();
  1195.         },
  1196.  
  1197.         onmouseup: function() {
  1198.             bot.defaultAccel = 0;
  1199.         },
  1200.  
  1201.         // Manual mobile rendering
  1202.         toggleMobileRendering: function(mobileRendering) {
  1203.             window.mobileRender = mobileRendering;
  1204.             window.log('Mobile rendering set to: ' + window.mobileRender);
  1205.             userInterface.savePreference('mobileRender', window.mobileRender);
  1206.             // Set render mode
  1207.             if (window.mobileRender) {
  1208.                 window.render_mode = 1;
  1209.                 window.want_quality = 0;
  1210.                 window.high_quality = false;
  1211.             } else {
  1212.                 window.render_mode = 2;
  1213.                 window.want_quality = 1;
  1214.                 window.high_quality = true;
  1215.             }
  1216.         },
  1217.  
  1218.         // Update stats overlay.
  1219.         updateStats: function() {
  1220.             var oContent = [];
  1221.             var median;
  1222.  
  1223.             if (bot.scores.length === 0) return;
  1224.             median = Math.round((bot.scores[Math.floor((bot.scores.length - 1) / 2)] +
  1225.                      bot.scores[Math.ceil((bot.scores.length - 1) / 2)]) / 2);
  1226.  
  1227.             oContent.push('games played: ' + bot.scores.length);
  1228.             oContent.push('a: ' + Math.round(
  1229.                 bot.scores.reduce(function(a, b) { return a + b; }) / (bot.scores.length)) +
  1230.                 ' m: ' + median);
  1231.  
  1232.             for (var i = 0; i < bot.scores.length && i < 10; i++) {
  1233.                 oContent.push(i + 1 + '. ' + bot.scores[i]);
  1234.             }
  1235.  
  1236.             userInterface.overlays.statsOverlay.innerHTML = oContent.join('<br/>');
  1237.         },
  1238.  
  1239.         onPrefChange: function() {
  1240.             // Set static display options here.
  1241.             var oContent = [];
  1242.             var ht = userInterface.handleTextColor;
  1243.  
  1244.             oContent.push('version: ' + GM_info.script.version);
  1245.             oContent.push('[T / Right click] bot: ' + ht(bot.isBotEnabled));
  1246.             oContent.push('[O] mobile rendering: ' + ht(window.mobileRender));
  1247.             oContent.push('[A/S] radius multiplier: ' + bot.opt.radiusMult);
  1248.             oContent.push('[D] quick radius change ' +
  1249.                 bot.opt.radiusApproachSize + '/' + bot.opt.radiusAvoidSize);
  1250.             oContent.push('[I] auto respawn: ' + ht(window.autoRespawn));
  1251.             oContent.push('[G] leaderboard overlay: ' + ht(window.leaderboard));
  1252.             oContent.push('[Y] visual debugging: ' + ht(window.visualDebugging));
  1253.             oContent.push('[U] log debugging: ' + ht(window.logDebugging));
  1254.             oContent.push('[H] overlays');
  1255.             oContent.push('[B] change background');
  1256.             oContent.push('[Mouse Wheel] zoom');
  1257.             oContent.push('[Z] reset zoom');
  1258.             oContent.push('[ESC] quick respawn');
  1259.             oContent.push('[Q] quit to menu');
  1260.  
  1261.             userInterface.overlays.prefOverlay.innerHTML = oContent.join('<br/>');
  1262.         },
  1263.  
  1264.         onFrameUpdate: function() {
  1265.             // Botstatus overlay
  1266.             var oContent = [];
  1267.  
  1268.             if (window.playing && window.snake !== null) {
  1269.                 oContent.push('fps: ' + userInterface.framesPerSecond.fps);
  1270.  
  1271.                 // Display the X and Y of the snake
  1272.                 oContent.push('x: ' +
  1273.                     (Math.round(window.snake.xx) || 0) + ' y: ' +
  1274.                     (Math.round(window.snake.yy) || 0));
  1275.  
  1276.                 if (window.goalCoordinates) {
  1277.                     oContent.push('target');
  1278.                     oContent.push('x: ' + window.goalCoordinates.x + ' y: ' +
  1279.                         window.goalCoordinates.y);
  1280.                     if (window.goalCoordinates.sz) {
  1281.                         oContent.push('sz: ' + window.goalCoordinates.sz);
  1282.                     }
  1283.                 }
  1284.  
  1285.                 if (window.bso !== undefined && userInterface.overlays.serverOverlay.innerHTML !==
  1286.                     window.bso.ip + ':' + window.bso.po) {
  1287.                     userInterface.overlays.serverOverlay.innerHTML =
  1288.                         window.bso.ip + ':' + window.bso.po;
  1289.                 }
  1290.             }
  1291.  
  1292.             userInterface.overlays.botOverlay.innerHTML = oContent.join('<br/>');
  1293.  
  1294.             if (window.playing && window.visualDebugging) {
  1295.                 // Only draw the goal when a bot has a goal.
  1296.                 if (window.goalCoordinates && bot.isBotEnabled) {
  1297.                     var headCoord = {
  1298.                         x: window.snake.xx,
  1299.                         y: window.snake.yy
  1300.                     };
  1301.                     canvasUtil.drawLine(
  1302.                         headCoord,
  1303.                         window.goalCoordinates,
  1304.                         'green');
  1305.                     canvasUtil.drawCircle(window.goalCoordinates, 'red', true);
  1306.                 }
  1307.             }
  1308.         },
  1309.  
  1310.         oefTimer: function() {
  1311.             var start = Date.now();
  1312.             canvasUtil.maintainZoom();
  1313.             original_oef();
  1314.             original_redraw();
  1315.  
  1316.             if (window.playing && bot.isBotEnabled && window.snake !== null) {
  1317.                 window.onmousemove = function() {};
  1318.                 bot.isBotRunning = true;
  1319.                 bot.go();
  1320.             } else if (bot.isBotEnabled && bot.isBotRunning) {
  1321.                 bot.isBotRunning = false;
  1322.                 if (window.lastscore && window.lastscore.childNodes[1]) {
  1323.                     bot.scores.push(parseInt(window.lastscore.childNodes[1].innerHTML));
  1324.                     bot.scores.sort(function(a, b) {
  1325.                         return b - a;
  1326.                     });
  1327.                     userInterface.updateStats();
  1328.                 }
  1329.  
  1330.                 if (window.autoRespawn) {
  1331.                     window.connect();
  1332.                 }
  1333.             }
  1334.  
  1335.             if (!bot.isBotEnabled || !bot.isBotRunning) {
  1336.                 window.onmousemove = original_onmousemove;
  1337.             }
  1338.  
  1339.             userInterface.onFrameUpdate();
  1340.             setTimeout(userInterface.oefTimer, (1000 / bot.opt.targetFps) - (Date.now() - start));
  1341.         },
  1342.  
  1343.         // Quit to menu
  1344.         quit: function() {
  1345.             if (window.playing && window.resetGame) {
  1346.                 window.want_close_socket = true;
  1347.                 window.dead_mtm = 0;
  1348.                 if (window.play_btn) {
  1349.                     window.play_btn.setEnabled(true);
  1350.                 }
  1351.                 window.resetGame();
  1352.             }
  1353.         },
  1354.  
  1355.         // Update the relation between the screen and the canvas.
  1356.         onresize: function() {
  1357.             window.resize();
  1358.             // Canvas different size from the screen (often bigger).
  1359.             canvasUtil.canvasRatio = {
  1360.                 x: window.mc.width / window.ww,
  1361.                 y: window.mc.height / window.hh
  1362.             };
  1363.         },
  1364.         // Handles the text color of the bot preferences
  1365.         // enabled = green
  1366.         // disabled = red
  1367.         handleTextColor: function(enabled) {
  1368.             return '<span style=\"color:' +
  1369.                 (enabled ? 'green;\">enabled' : 'red;\">disabled') + '</span>';
  1370.         }
  1371.     };
  1372. })();
  1373.  
  1374. // Main
  1375. (function() {
  1376.     window.play_btn.btnf.addEventListener('click', userInterface.playButtonClickListener);
  1377.     document.onkeydown = userInterface.onkeydown;
  1378.     window.onmousedown = userInterface.onmousedown;
  1379.     window.addEventListener('mouseup', userInterface.onmouseup);
  1380.     window.onresize = userInterface.onresize;
  1381.  
  1382.     // Hide top score
  1383.     userInterface.hideTop();
  1384.  
  1385.     // Overlays
  1386.     userInterface.initOverlays();
  1387.  
  1388.     // Load preferences
  1389.     userInterface.loadPreference('logDebugging', false);
  1390.     userInterface.loadPreference('visualDebugging', false);
  1391.     userInterface.loadPreference('autoRespawn', false);
  1392.     userInterface.loadPreference('mobileRender', false);
  1393.     userInterface.loadPreference('leaderboard', true);
  1394.     window.nick.value = userInterface.loadPreference('savedNick', 'Slither.io-bot');
  1395.  
  1396.     // Don't load saved options or apply custom options if
  1397.     // the user wants to use default options
  1398.     if (typeof(customBotOptions.useDefaults) !== 'undefined'
  1399.        && customBotOptions.useDefaults === true) {
  1400.         window.log('Ignoring saved / customised options per user request');
  1401.     } else {
  1402.         // Load saved options, if any
  1403.         var savedOptions = userInterface.loadPreference('options', null);
  1404.         if (savedOptions !== null) { // If there were saved options
  1405.             // Parse the options and overwrite the default bot options
  1406.             savedOptions = JSON.parse(savedOptions);
  1407.             if (Object.keys(savedOptions).length !== 0
  1408.                 && savedOptions.constructor === Object) {
  1409.                 Object.keys(savedOptions).forEach(function(key) {
  1410.                     window.bot.opt[key] = savedOptions[key];
  1411.                 });
  1412.             }
  1413.             window.log('Found saved settings, overwriting default bot options');
  1414.         } else {
  1415.             window.log('No saved settings, using default bot options');
  1416.         }
  1417.  
  1418.         // Has the user customised the options?
  1419.         if (Object.keys(customBotOptions).length !== 0
  1420.             && customBotOptions.constructor === Object) {
  1421.             Object.keys(customBotOptions).forEach(function(key) {
  1422.                 window.bot.opt[key] = customBotOptions[key];
  1423.             });
  1424.             window.log('Custom settings found, overwriting current bot options');
  1425.         }
  1426.     }
  1427.  
  1428.     // Save the bot options
  1429.     userInterface.savePreference('options', JSON.stringify(window.bot.opt));
  1430.     window.log('Saving current bot options');
  1431.  
  1432.     // Listener for mouse wheel scroll - used for setZoom function
  1433.     document.body.addEventListener('mousewheel', canvasUtil.setZoom);
  1434.     document.body.addEventListener('DOMMouseScroll', canvasUtil.setZoom);
  1435.  
  1436.     // Set render mode
  1437.     if (window.mobileRender) {
  1438.         userInterface.toggleMobileRendering(true);
  1439.     } else {
  1440.         userInterface.toggleMobileRendering(false);
  1441.     }
  1442.     // Remove laggy logo animation
  1443.     userInterface.removeLogo();
  1444.     // Unblocks all skins without the need for FB sharing.
  1445.     window.localStorage.setItem('edttsg', '1');
  1446.  
  1447.     // Remove social
  1448.     window.social.remove();
  1449.  
  1450.     // Maintain fps
  1451.     setInterval(userInterface.framesPerSecond.fpsTimer, 80);
  1452.  
  1453.     // Start!
  1454.     userInterface.oefTimer();
  1455. })();
Advertisement
Comments
Add Comment
Please, Sign In to add comment
Advertisement