Slither.io Trainer Hack

A Trainer to help you play on slither.io.Reveal the positions of worms close to you.Shows where's the closest and biggest food near you, and can also create 2 danger zone circles around you.

当前为 2024-08-13 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Slither.io Trainer Hack
  3. // @namespace slithertrainer
  4. // @version 7
  5. // @description A Trainer to help you play on slither.io.Reveal the positions of worms close to you.Shows where's the closest and biggest food near you, and can also create 2 danger zone circles around you.
  6. // @author hacker09
  7. // @match http://slither.com/io
  8. // @icon https://slither.io/s/favicon.png
  9. // @license Mozilla Public License Version 2.0
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. /*
  14. Copyright (c) 2016 Ermiya Eskandary & Théophile Cailliau and other contributors
  15. This Source Code Form is subject to the terms of the Mozilla Public
  16. License, v. 2.0. If a copy of the MPL was not distributed with this
  17. file, You can obtain one at http://mozilla.org/MPL/2.0/.
  18. */
  19.  
  20. const TARGET_FPS = 30;
  21.  
  22. window.log = function() {};
  23.  
  24. window.getSnakeLength = function() {
  25. return (Math.floor(
  26. 150 *
  27. (window.fpsls[window.snake.sct] + window.snake.fam / window.fmlts[window.snake.sct] - 1) -
  28. 50) / 10);
  29. };
  30. window.getSnakeWidth = function(sc) {
  31. if (sc === undefined) sc = window.snake.sc;
  32. return sc * 29.0;
  33. };
  34.  
  35. var canvas = window.canvas = (function() {
  36. return {
  37. // Ratio of screen size divided by canvas size.
  38. canvasRatio: {
  39. x: window.mc.width / window.ww,
  40. y: window.mc.height / window.hh
  41. },
  42.  
  43. // Convert snake-relative coordinates to absolute screen coordinates.
  44. mouseToScreen: function(point) {
  45. var screenX = point.x + (window.ww / 2);
  46. var screenY = point.y + (window.hh / 2);
  47. return {
  48. x: screenX,
  49. y: screenY
  50. };
  51. },
  52.  
  53. // Convert screen coordinates to canvas coordinates.
  54. screenToCanvas: function(point) {
  55. var canvasX = window.csc *
  56. (point.x * canvas.canvasRatio.x) - parseInt(window.mc.style.left);
  57. var canvasY = window.csc *
  58. (point.y * canvas.canvasRatio.y) - parseInt(window.mc.style.top);
  59. return {
  60. x: canvasX,
  61. y: canvasY
  62. };
  63. },
  64.  
  65. // Convert map coordinates to mouse coordinates.
  66. mapToMouse: function(point) {
  67. var mouseX = (point.x - window.snake.xx) * window.gsc;
  68. var mouseY = (point.y - window.snake.yy) * window.gsc;
  69. return {
  70. x: mouseX,
  71. y: mouseY
  72. };
  73. },
  74.  
  75. // Map cordinates to Canvas cordinate shortcut
  76. mapToCanvas: function(point) {
  77. var c = canvas.mapToMouse(point);
  78. c = canvas.mouseToScreen(c);
  79. c = canvas.screenToCanvas(c);
  80. return c;
  81. },
  82.  
  83. // Map to Canvas coordinate conversion for drawing circles.
  84. // Radius also needs to scale by .gsc
  85. circleMapToCanvas: function(circle) {
  86. var newCircle = canvas.mapToCanvas(circle);
  87. return canvas.circle(
  88. newCircle.x,
  89. newCircle.y,
  90. circle.radius * window.gsc
  91. );
  92. },
  93.  
  94. // Constructor for point type
  95. point: function(x, y) {
  96. var p = {
  97. x: Math.round(x),
  98. y: Math.round(y)
  99. };
  100.  
  101. return p;
  102. },
  103.  
  104. // Constructor for rect type
  105. rect: function(x, y, w, h) {
  106. var r = {
  107. x: Math.round(x),
  108. y: Math.round(y),
  109. width: Math.round(w),
  110. height: Math.round(h)
  111. };
  112.  
  113. return r;
  114. },
  115.  
  116. // Constructor for circle type
  117. circle: function(x, y, r) {
  118. var c = {
  119. x: Math.round(x),
  120. y: Math.round(y),
  121. radius: Math.round(r)
  122. };
  123.  
  124. return c;
  125. },
  126.  
  127. // Fast atan2
  128. fastAtan2: function(y, x) {
  129. const QPI = Math.PI / 4;
  130. const TQPI = 3 * Math.PI / 4;
  131. var r = 0.0;
  132. var angle = 0.0;
  133. var abs_y = Math.abs(y) + 1e-10;
  134. if (x < 0) {
  135. r = (x + abs_y) / (abs_y - x);
  136. angle = TQPI;
  137. } else {
  138. r = (x - abs_y) / (x + abs_y);
  139. angle = QPI;
  140. }
  141. angle += (0.1963 * r * r - 0.9817) * r;
  142. if (y < 0) {
  143. return -angle;
  144. }
  145.  
  146. return angle;
  147. },
  148.  
  149. // Adjusts zoom in response to the mouse wheel.
  150. setZoom: function(e) {
  151. // Scaling ratio
  152. if (window.gsc) {
  153. window.gsc *= Math.pow(0.9, e.wheelDelta / -120 || e.detail / 2 || 0);
  154. window.desired_gsc = window.gsc;
  155. }
  156. },
  157.  
  158. // Restores zoom to the default value.
  159. resetZoom: function() {
  160. window.gsc = 0.9;
  161. window.desired_gsc = 0.9;
  162. },
  163.  
  164. // Maintains Zoom
  165. maintainZoom: function() {
  166. if (window.desired_gsc !== undefined) {
  167. window.gsc = window.desired_gsc;
  168. }
  169. },
  170.  
  171. // Sets background to the given image URL.
  172. // Defaults to slither.io's own background.
  173. setBackground: function(url) {
  174. url = typeof url !== 'undefined' ? url : '/s/bg45.jpg';
  175. window.ii.src = url;
  176. },
  177.  
  178. // Draw a rectangle on the canvas.
  179. drawRect: function(rect, color, fill, alpha) {
  180. if (alpha === undefined) alpha = 1;
  181.  
  182. var context = window.mc.getContext('2d');
  183. var lc = canvas.mapToCanvas({
  184. x: rect.x,
  185. y: rect.y
  186. });
  187.  
  188. context.save();
  189. context.globalAlpha = alpha;
  190. context.strokeStyle = color;
  191. context.rect(lc.x, lc.y, rect.width * window.gsc, rect.height * window.gsc);
  192. context.stroke();
  193. if (fill) {
  194. context.fillStyle = color;
  195. context.fill();
  196. }
  197. context.restore();
  198. },
  199.  
  200. // Draw a circle on the canvas.
  201. drawCircle: function(circle, color, fill, alpha) {
  202. if (alpha === undefined) alpha = 1;
  203. if (circle.radius === undefined) circle.radius = 5;
  204.  
  205. var context = window.mc.getContext('2d');
  206. var drawCircle = canvas.circleMapToCanvas(circle);
  207.  
  208. context.save();
  209. context.globalAlpha = alpha;
  210. context.beginPath();
  211. context.strokeStyle = color;
  212. context.arc(drawCircle.x, drawCircle.y, drawCircle.radius, 0, Math.PI * 2);
  213. context.stroke();
  214. if (fill) {
  215. context.fillStyle = color;
  216. context.fill();
  217. }
  218. context.restore();
  219. },
  220.  
  221. // Draw an angle.
  222. // @param {number} start -- where to start the angle
  223. // @param {number} angle -- width of the angle
  224. // @param {bool} danger -- green if false, red if true
  225. drawAngle: function(start, angle, color, fill, alpha) {
  226. if (alpha === undefined) alpha = 0.6;
  227.  
  228. var context = window.mc.getContext('2d');
  229.  
  230. context.save();
  231. context.globalAlpha = alpha;
  232. context.beginPath();
  233. context.moveTo(window.mc.width / 2, window.mc.height / 2);
  234. context.arc(window.mc.width / 2, window.mc.height / 2, window.gsc * 100, start, angle);
  235. context.lineTo(window.mc.width / 2, window.mc.height / 2);
  236. context.closePath();
  237. context.stroke();
  238. if (fill) {
  239. context.fillStyle = color;
  240. context.fill();
  241. }
  242. context.restore();
  243. },
  244.  
  245. // Draw a line on the canvas.
  246. drawLine: function(p1, p2, color, width) {
  247. if (width === undefined) width = 5;
  248.  
  249. var context = window.mc.getContext('2d');
  250. var dp1 = canvas.mapToCanvas(p1);
  251. var dp2 = canvas.mapToCanvas(p2);
  252.  
  253. context.save();
  254. context.beginPath();
  255. context.lineWidth = width * window.gsc;
  256. context.strokeStyle = color;
  257. context.moveTo(dp1.x, dp1.y);
  258. context.lineTo(dp2.x, dp2.y);
  259. context.stroke();
  260. context.restore();
  261. },
  262.  
  263. // Given the start and end of a line, is point left.
  264. isLeft: function(start, end, point) {
  265. return ((end.x - start.x) * (point.y - start.y) -
  266. (end.y - start.y) * (point.x - start.x)) > 0;
  267.  
  268. },
  269.  
  270. // Get distance squared
  271. getDistance2: function(x1, y1, x2, y2) {
  272. var distance2 = Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2);
  273. return distance2;
  274. },
  275.  
  276. getDistance2FromSnake: function(point) {
  277. point.distance = canvas.getDistance2(window.snake.xx, window.snake.yy,
  278. point.xx, point.yy);
  279. return point;
  280. },
  281.  
  282. // Check if point in Rect
  283. pointInRect: function(point, rect) {
  284. if (rect.x <= point.x && rect.y <= point.y &&
  285. rect.x + rect.width >= point.x && rect.y + rect.height >= point.y) {
  286. return true;
  287. }
  288. return false;
  289. },
  290.  
  291. // Check if circles intersect
  292. circleIntersect: function(circle1, circle2) {
  293. var bothRadii = circle1.radius + circle2.radius;
  294.  
  295. // Pretends the circles are squares for a quick collision check.
  296. // If it collides, do the more expensive circle check.
  297. if (circle1.x + bothRadii > circle2.x &&
  298. circle1.y + bothRadii > circle2.y &&
  299. circle1.x < circle2.x + bothRadii &&
  300. circle1.y < circle2.y + bothRadii) {
  301.  
  302. var distance2 = canvas.getDistance2(circle1.x, circle1.y, circle2.x, circle2.y);
  303.  
  304. if (distance2 < bothRadii * bothRadii) {
  305. if (window.visualDebugging) {
  306. var collisionPointCircle = canvas.circle(
  307. ((circle1.x * circle2.radius) + (circle2.x * circle1.radius)) /
  308. bothRadii,
  309. ((circle1.y * circle2.radius) + (circle2.y * circle1.radius)) /
  310. bothRadii,
  311. 5
  312. );
  313. canvas.drawCircle(circle2, 'red', true);
  314. canvas.drawCircle(collisionPointCircle, 'cyan', true);
  315. }
  316. return true;
  317. }
  318. }
  319. return false;
  320. }
  321. };
  322. })();
  323.  
  324. var bot = window.bot = (function() {
  325. return {
  326. isBotRunning: false,
  327. isBotEnabled: true,
  328. lookForFood: false,
  329. collisionPoints: [],
  330. collisionAngles: [],
  331. scores: [],
  332. foodTimeout: undefined,
  333. sectorBoxSide: 0,
  334. defaultAccel: 0,
  335. sectorBox: {},
  336. currentFood: {},
  337. MID_X: 0,
  338. MID_Y: 0,
  339. MAP_R: 0,
  340.  
  341. quickRespawn: function() {
  342. window.dead_mtm = 0;
  343. window.login_fr = 0;
  344.  
  345. bot.isBotRunning = false;
  346. window.forcing = true;
  347. window.connect();
  348. window.forcing = false;
  349. },
  350.  
  351. // Avoid headPoint
  352. avoidHeadPoint: function(collisionPoint) {},
  353.  
  354. // Avoid collison point by ang
  355. // ang radians <= Math.PI (180deg)
  356. avoidCollisionPoint: function(collisionPoint, ang) {},
  357.  
  358. // Sorting by property 'distance'
  359. sortDistance: function(a, b) {
  360. return a.distance - b.distance;
  361. },
  362.  
  363. // get collision angle index, expects angle +/i 0 to Math.PI
  364. getAngleIndex: function(angle) {
  365. const ARCSIZE = Math.PI / 4;
  366. var index;
  367.  
  368. if (angle < 0) {
  369. angle += 2 * Math.PI;
  370. }
  371.  
  372. index = Math.round(angle * (1 / ARCSIZE));
  373.  
  374. if (index === (2 * Math.PI) / ARCSIZE) {
  375. return 0;
  376. }
  377. return index;
  378. },
  379.  
  380. // Add to collisionAngles if distance is closer
  381. addCollisionAngle: function(sp) {
  382. var ang = canvas.fastAtan2(
  383. Math.round(sp.yy - window.snake.yy),
  384. Math.round(sp.xx - window.snake.xx));
  385. var aIndex = bot.getAngleIndex(ang);
  386.  
  387. var actualDistance = Math.round(
  388. sp.distance - (Math.pow(window.getSnakeWidth(window.snakes[sp.snake].sc), 2) / 2));
  389.  
  390. if (bot.collisionAngles[aIndex] === undefined) {
  391. bot.collisionAngles[aIndex] = {
  392. x: Math.round(sp.xx),
  393. y: Math.round(sp.yy),
  394. ang: ang,
  395. snake: sp.snake,
  396. distance: actualDistance
  397. };
  398. } else if (bot.collisionAngles[aIndex].distance > sp.distance) {
  399. bot.collisionAngles[aIndex].x = Math.round(sp.xx);
  400. bot.collisionAngles[aIndex].y = Math.round(sp.yy);
  401. bot.collisionAngles[aIndex].ang = ang;
  402. bot.collisionAngles[aIndex].snake = sp.snake;
  403. bot.collisionAngles[aIndex].distance = actualDistance;
  404. }
  405. },
  406.  
  407. // Get closest collision point per snake.
  408. getCollisionPoints: function() {
  409. var scPoint;
  410.  
  411. bot.collisionPoints = [];
  412. bot.collisionAngles = [];
  413.  
  414.  
  415. for (var snake = 0, ls = window.snakes.length; snake < ls; snake++) {
  416. scPoint = undefined;
  417.  
  418. if (window.snakes[snake].id !== window.snake.id &&
  419. window.snakes[snake].alive_amt === 1) {
  420. if (window.visualDebugging) {
  421. canvas.drawCircle(canvas.circle(
  422. window.snakes[snake].xx,
  423. window.snakes[snake].yy,
  424. window.getSnakeWidth(window.snakes[snake].sc) / 2),
  425. 'red', false);
  426. }
  427. scPoint = {
  428. xx: window.snakes[snake].xx,
  429. yy: window.snakes[snake].yy,
  430. snake: snake
  431. };
  432. canvas.getDistance2FromSnake(scPoint);
  433. bot.addCollisionAngle(scPoint);
  434.  
  435. for (var pts = 0, lp = window.snakes[snake].pts.length; pts < lp; pts++) {
  436. if (!window.snakes[snake].pts[pts].dying &&
  437. canvas.pointInRect({
  438. x: window.snakes[snake].pts[pts].xx,
  439. y: window.snakes[snake].pts[pts].yy
  440. }, bot.sectorBox)
  441. ) {
  442. var collisionPoint = {
  443. xx: window.snakes[snake].pts[pts].xx,
  444. yy: window.snakes[snake].pts[pts].yy,
  445. snake: snake
  446. };
  447.  
  448. if (window.visualDebugging && true === false) {
  449. canvas.drawCircle(canvas.circle(
  450. collisionPoint.xx,
  451. collisionPoint.yy,
  452. window.getSnakeWidth(window.snakes[snake].sc) / 2),
  453. '#00FF00', false);
  454. }
  455.  
  456. canvas.getDistance2FromSnake(collisionPoint);
  457. bot.addCollisionAngle(collisionPoint);
  458.  
  459. if (scPoint === undefined ||
  460. scPoint.distance > collisionPoint.distance) {
  461. scPoint = collisionPoint;
  462. }
  463. }
  464. }
  465. }
  466. if (scPoint !== undefined) {
  467. bot.collisionPoints.push(scPoint);
  468. if (window.visualDebugging) {
  469. canvas.drawCircle(canvas.circle(
  470. scPoint.xx,
  471. scPoint.yy,
  472. window.getSnakeWidth(window.snakes[scPoint.snake].sc) / 2
  473. ), 'red', false);
  474. }
  475. }
  476. }
  477.  
  478. if (canvas.getDistance2(bot.MID_X, bot.MID_Y, window.snake.xx, window.snake.yy) >
  479. Math.pow(bot.MAP_R - 1000, 2)) {
  480. var midAng = canvas.fastAtan2(
  481. window.snake.yy - bot.MID_X, window.snake.xx - bot.MID_Y);
  482. scPoint = {
  483. xx: bot.MID_X + bot.MAP_R * Math.cos(midAng),
  484. yy: bot.MID_Y + bot.MAP_R * Math.sin(midAng),
  485. snake: -1
  486. };
  487. bot.collisionPoints.push(scPoint);
  488. if (window.visualDebugging) {
  489. canvas.drawCircle(canvas.circle(
  490. scPoint.xx,
  491. scPoint.yy,
  492. window.getSnakeWidth(1) * 5
  493. ), 'yellow', false);
  494. }
  495. }
  496.  
  497.  
  498. bot.collisionPoints.sort(bot.sortDistance);
  499. if (window.visualDebugging) {
  500. for (var i = 0; i < bot.collisionAngles.length; i++) {
  501. if (bot.collisionAngles[i] !== undefined) {
  502. canvas.drawLine({
  503. x: window.snake.xx,
  504. y: window.snake.yy
  505. }, {
  506. x: bot.collisionAngles[i].x,
  507. y: bot.collisionAngles[i].y
  508. },
  509. '#99ffcc', 2);
  510. }
  511. }
  512. }
  513. },
  514.  
  515. // Checks to see if you are going to collide with anything in the collision detection radius
  516. checkCollision: function(r) {
  517. if (!window.collisionDetection) return false;
  518.  
  519. r = Number(r);
  520. var xx = Number(window.snake.xx.toFixed(3));
  521. var yy = Number(window.snake.yy.toFixed(3));
  522.  
  523. window.snake.cos = Math.cos(window.snake.ang).toFixed(3);
  524. window.snake.sin = Math.sin(window.snake.ang).toFixed(3);
  525.  
  526. const speedMult = window.snake.sp / 5.78;
  527. const widthMult = window.getSnakeWidth();
  528.  
  529. var headCircle = canvas.circle(
  530. xx, yy,
  531. speedMult * r / 2 * widthMult / 2
  532. );
  533.  
  534. var fullHeadCircle = canvas.circle(
  535. xx, yy,
  536. r * widthMult / 2
  537. );
  538.  
  539. var sidecircle_r = canvas.circle(
  540. window.snake.lnp.xx -
  541. ((window.snake.lnp.yy + window.snake.sin * window.getSnakeWidth()) -
  542. window.snake.lnp.yy),
  543. window.snake.lnp.yy +
  544. ((window.snake.lnp.xx + window.snake.cos * window.getSnakeWidth()) -
  545. window.snake.lnp.xx),
  546. window.getSnakeWidth() * speedMult
  547. );
  548.  
  549. var sidecircle_l = canvas.circle(
  550. window.snake.lnp.xx +
  551. ((window.snake.lnp.yy + window.snake.sin * window.getSnakeWidth()) -
  552. window.snake.lnp.yy),
  553. window.snake.lnp.yy -
  554. ((window.snake.lnp.xx + window.snake.cos * window.getSnakeWidth()) -
  555. window.snake.lnp.xx),
  556. window.getSnakeWidth() * speedMult
  557. );
  558.  
  559. window.snake.sidecircle_r = sidecircle_r;
  560. window.snake.sidecircle_l = sidecircle_l;
  561.  
  562. if (window.visualDebugging) {
  563. canvas.drawCircle(fullHeadCircle, 'red');
  564. canvas.drawCircle(headCircle, 'blue', false);
  565. // canvas.drawCircle(sidecircle_r, 'orange', true, 0.3);
  566. // canvas.drawCircle(sidecircle_l, 'orange', true, 0.3);
  567. }
  568.  
  569. bot.getCollisionPoints();
  570. if (bot.collisionPoints.length === 0) return false;
  571.  
  572. for (var i = 0; i < bot.collisionPoints.length; i++) {
  573. // -1 snake is special case for non snake object.
  574. var colR = bot.collisionPoints[i].snake === -1 ? window.getSnakeWidth(1) * 5 :
  575. window.getSnakeWidth(window.snakes[bot.collisionPoints[i].snake].sc) / 2;
  576.  
  577. var collisionCircle = canvas.circle(
  578. bot.collisionPoints[i].xx,
  579. bot.collisionPoints[i].yy,
  580. colR
  581. );
  582.  
  583. if (canvas.circleIntersect(headCircle, collisionCircle)) {
  584. window.setAcceleration(bot.defaultAccel);
  585. bot.avoidCollisionPoint(bot.collisionPoints[i]);
  586. return true;
  587. }
  588.  
  589. if (bot.collisionPoints[i].snake !== -1) {
  590. var eHeadCircle = canvas.circle(
  591. window.snakes[bot.collisionPoints[i].snake].xx,
  592. window.snakes[bot.collisionPoints[i].snake].yy,
  593. colR
  594. );
  595. }
  596. }
  597. window.setAcceleration(bot.defaultAccel);
  598. return false;
  599. },
  600.  
  601. sortScore: function(a, b) {
  602. return b.score - a.score;
  603. },
  604.  
  605. // 2.546 ~ 1 / (Math.PI / 8) - round angle difference up to nearest 22.5 degrees.
  606. // Round food up to nearest 5, square for distance^2
  607. scoreFood: function(f) {
  608. f.score = Math.pow(Math.ceil(f.sz / 5) * 5, 2) /
  609. f.distance / (Math.ceil(f.da * 2.546) / 2.546);
  610. },
  611.  
  612. computeFoodGoal: function() {
  613. var foodClusters = [];
  614. var foodGetIndex = [];
  615. var fi = 0;
  616. var sw = window.getSnakeWidth();
  617.  
  618. for (var i = 0; i < window.foods.length && window.foods[i] !== null; i++) {
  619. var a;
  620. var da;
  621. var distance;
  622. var sang = window.snake.ehang;
  623. var f = window.foods[i];
  624.  
  625. if (!f.eaten &&
  626. !(
  627. canvas.circleIntersect(
  628. canvas.circle(f.xx, f.yy, 2),
  629. window.snake.sidecircle_l) ||
  630. canvas.circleIntersect(
  631. canvas.circle(f.xx, f.yy, 2),
  632. window.snake.sidecircle_r))) {
  633.  
  634. var cx = Math.round(Math.round(f.xx / sw) * sw);
  635. var cy = Math.round(Math.round(f.yy / sw) * sw);
  636. var csz = Math.round(f.sz);
  637.  
  638. if (foodGetIndex[cx + '|' + cy] === undefined) {
  639. foodGetIndex[cx + '|' + cy] = fi;
  640. a = canvas.fastAtan2(cy - window.snake.yy, cx - window.snake.xx);
  641. da = Math.min(
  642. (2 * Math.PI) - Math.abs(a - sang), Math.abs(a - sang));
  643. distance = Math.round(
  644. canvas.getDistance2(cx, cy, window.snake.xx, window.snake.yy));
  645. foodClusters[fi] = {
  646. x: cx,
  647. y: cy,
  648. a: a,
  649. da: da,
  650. sz: csz,
  651. distance: distance,
  652. score: 0.0
  653. };
  654. fi++;
  655. } else {
  656. foodClusters[foodGetIndex[cx + '|' + cy]].sz += csz;
  657. }
  658. }
  659. }
  660.  
  661. foodClusters.forEach(bot.scoreFood);
  662. foodClusters.sort(bot.sortScore);
  663.  
  664. for (i = 0; i < foodClusters.length; i++) {
  665. var aIndex = bot.getAngleIndex(foodClusters[i].a);
  666. if (bot.collisionAngles[aIndex] === undefined ||
  667. (bot.collisionAngles[aIndex].distance - Math.pow(window.getSnakeWidth(), 2) >
  668. foodClusters[i].distance && foodClusters[i].sz > 10)
  669. ) {
  670. bot.currentFood = foodClusters[i];
  671. return;
  672. }
  673. }
  674. bot.currentFood = {
  675. x: bot.MID_X,
  676. y: bot.MID_Y
  677. };
  678. },
  679.  
  680. foodAccel: function() {
  681. var aIndex = 0;
  682.  
  683. if (bot.currentFood && bot.currentFood.sz > 60) {
  684. aIndex = bot.getAngleIndex(bot.currentFood.a);
  685.  
  686. if (
  687. bot.collisionAngles[aIndex] && bot.collisionAngles[aIndex].distance >
  688. bot.currentFood.distance * 2) {
  689. return 1;
  690. }
  691.  
  692. if (bot.collisionAngles[aIndex] === undefined) {
  693. return 1;
  694. }
  695. }
  696.  
  697. return bot.defaultAccel;
  698. },
  699.  
  700. // Loop version of collision check
  701. collisionLoop: function() {
  702. if (bot.checkCollision(window.collisionRadiusMultiplier)) {
  703. bot.lookForFood = false;
  704. if (bot.foodTimeout) {
  705. window.clearTimeout(bot.foodTimeout);
  706. bot.foodTimeout = window.setTimeout(bot.foodTimer, 1000 / TARGET_FPS * 4);
  707. }
  708. } else {
  709. bot.lookForFood = true;
  710. if (bot.foodTimeout === undefined) {
  711. bot.foodTimeout = window.setTimeout(bot.foodTimer, 1000 / TARGET_FPS * 4);
  712. }
  713. window.setAcceleration(bot.foodAccel());
  714. }
  715. },
  716.  
  717. // Timer version of food check
  718. foodTimer: function() {
  719. if (window.playing && bot.lookForFood &&
  720. window.snake !== null && window.snake.alive_amt === 1) {
  721. bot.computeFoodGoal();
  722. window.goalCoordinates = bot.currentFood;
  723. }
  724. bot.foodTimeout = undefined;
  725. }
  726. };
  727. })();
  728.  
  729. var userInterface = window.userInterface = (function() {
  730. // Save the original slither.io functions so we can modify them, or reenable them later.
  731. var original_keydown = document.onkeydown;
  732. var original_onmouseDown = window.onmousedown;
  733. var original_oef = window.oef;
  734. var original_redraw = window.redraw;
  735. var original_onmousemove = window.onmousemove;
  736.  
  737. window.oef = function() {};
  738. window.redraw = function() {};
  739.  
  740. return {
  741. overlays: {},
  742.  
  743. initOverlays: function() {
  744. var botOverlay = document.createElement('div');
  745. botOverlay.style.position = 'fixed';
  746. botOverlay.style.right = '5px';
  747. botOverlay.style.bottom = '112px';
  748. botOverlay.style.width = '150px';
  749. botOverlay.style.height = '85px';
  750. // botOverlay.style.background = 'rgba(0, 0, 0, 0.5)';
  751. botOverlay.style.color = '#C0C0C0';
  752. botOverlay.style.fontFamily = 'Consolas, Verdana';
  753. botOverlay.style.zIndex = 999;
  754. botOverlay.style.fontSize = '14px';
  755. botOverlay.style.padding = '5px';
  756. botOverlay.style.borderRadius = '5px';
  757. botOverlay.className = 'nsi';
  758. document.body.appendChild(botOverlay);
  759.  
  760. var serverOverlay = document.createElement('div');
  761. serverOverlay.style.position = 'fixed';
  762. serverOverlay.style.right = '5px';
  763. serverOverlay.style.bottom = '5px';
  764. serverOverlay.style.width = '160px';
  765. serverOverlay.style.height = '14px';
  766. serverOverlay.style.color = '#C0C0C0';
  767. serverOverlay.style.fontFamily = 'Consolas, Verdana';
  768. serverOverlay.style.zIndex = 999;
  769. serverOverlay.style.fontSize = '14px';
  770. serverOverlay.className = 'nsi';
  771. document.body.appendChild(serverOverlay);
  772. var prefOverlay = document.createElement('div');
  773. prefOverlay.style.position = 'fixed';
  774. prefOverlay.style.left = '10px';
  775. prefOverlay.style.top = '75px';
  776. prefOverlay.style.width = '260px';
  777. prefOverlay.style.height = '210px';
  778. // prefOverlay.style.background = 'rgba(0, 0, 0, 0.5)';
  779. prefOverlay.style.color = '#C0C0C0';
  780. prefOverlay.style.fontFamily = 'Consolas, Verdana';
  781. prefOverlay.style.zIndex = 999;
  782. prefOverlay.style.fontSize = '14px';
  783. prefOverlay.style.padding = '5px';
  784. prefOverlay.style.borderRadius = '5px';
  785. prefOverlay.className = 'nsi';
  786. document.body.appendChild(prefOverlay);
  787.  
  788. var statsOverlay = document.createElement('div');
  789. statsOverlay.style.position = 'fixed';
  790. statsOverlay.style.left = '10px';
  791. statsOverlay.style.top = '295px';
  792. statsOverlay.style.width = '140px';
  793. statsOverlay.style.height = '210px';
  794. // statsOverlay.style.background = 'rgba(0, 0, 0, 0.5)';
  795. statsOverlay.style.color = '#C0C0C0';
  796. statsOverlay.style.fontFamily = 'Consolas, Verdana';
  797. statsOverlay.style.zIndex = 998;
  798. statsOverlay.style.fontSize = '14px';
  799. statsOverlay.style.padding = '5px';
  800. statsOverlay.style.borderRadius = '5px';
  801. statsOverlay.className = 'nsi';
  802. document.body.appendChild(statsOverlay);
  803.  
  804. userInterface.overlays.botOverlay = botOverlay;
  805. userInterface.overlays.serverOverlay = serverOverlay;
  806. userInterface.overlays.prefOverlay = prefOverlay;
  807. userInterface.overlays.statsOverlay = statsOverlay;
  808. },
  809.  
  810. toggleOverlays: function() {
  811. Object.keys(userInterface.overlays).forEach(function(okey) {
  812. var oVis = userInterface.overlays[okey].style.visibility !== 'hidden' ?
  813. 'hidden' : 'visible';
  814. userInterface.overlays[okey].style.visibility = oVis;
  815. window.visualDebugging = oVis === 'visible';
  816. });
  817. },
  818.  
  819. // Save variable to local storage
  820. savePreference: function(item, value) {
  821. window.localStorage.setItem(item, value);
  822. userInterface.onPrefChange();
  823. },
  824.  
  825. // Load a variable from local storage
  826. loadPreference: function(preference, defaultVar) {
  827. var savedItem = window.localStorage.getItem(preference);
  828. if (savedItem !== null) {
  829. if (savedItem === 'true') {
  830. window[preference] = true;
  831. } else if (savedItem === 'false') {
  832. window[preference] = false;
  833. } else {
  834. window[preference] = savedItem;
  835. }
  836. window.log('Setting found for ' + preference + ': ' + window[preference]);
  837. } else {
  838. window[preference] = defaultVar;
  839. window.log('No setting found for ' + preference +
  840. '. Used default: ' + window[preference]);
  841. }
  842. userInterface.onPrefChange();
  843. return window[preference];
  844. },
  845.  
  846. // Saves username when you click on "Play" button
  847. playButtonClickListener: function() {
  848. userInterface.saveNick();
  849. userInterface.loadPreference('autoRespawn', false);
  850. userInterface.onPrefChange();
  851. },
  852.  
  853. // Preserve nickname
  854. saveNick: function() {
  855. var nick = document.getElementById('nick').value;
  856. userInterface.savePreference('savedNick', nick);
  857. },
  858.  
  859. // Hide top score
  860. hideTop: function() {
  861. var nsidivs = document.querySelectorAll('div.nsi');
  862. for (var i = 0; i < nsidivs.length; i++) {
  863. if (nsidivs[i].style.top === '4px' && nsidivs[i].style.width === '300px') {
  864. nsidivs[i].style.visibility = 'hidden';
  865. bot.isTopHidden = true;
  866. window.topscore = nsidivs[i];
  867. }
  868. }
  869. },
  870.  
  871. // Store FPS data
  872. framesPerSecond: {
  873. fps: 0,
  874. fpsTimer: function() {
  875. if (window.playing && window.fps && window.lrd_mtm) {
  876. if (Date.now() - window.lrd_mtm > 970) {
  877. userInterface.framesPerSecond.fps = window.fps;
  878. }
  879. }
  880. }
  881. },
  882.  
  883. onkeydown: function(e) {
  884. // Original slither.io onkeydown function + whatever is under it
  885. original_keydown(e);
  886. if (window.playing) {
  887. // Letter `T` to toggle bot
  888. if (e.keyCode === 84) {
  889. bot.isBotEnabled = !bot.isBotEnabled;
  890. }
  891. // Letter 'U' to toggle debugging (console)
  892. if (e.keyCode === 85) {
  893. window.logDebugging = !window.logDebugging;
  894. console.log('Log debugging set to: ' + window.logDebugging);
  895. userInterface.savePreference('logDebugging', window.logDebugging);
  896. }
  897. // Letter 'Y' to toggle debugging (visual)
  898. if (e.keyCode === 89) {
  899. window.visualDebugging = !window.visualDebugging;
  900. console.log('Visual debugging set to: ' + window.visualDebugging);
  901. userInterface.savePreference('visualDebugging', window.visualDebugging);
  902. }
  903. // Letter 'I' to toggle autorespawn
  904. if (e.keyCode === 73) {
  905. window.autoRespawn = !window.autoRespawn;
  906. console.log('Automatic Respawning set to: ' + window.autoRespawn);
  907. userInterface.savePreference('autoRespawn', window.autoRespawn);
  908. }
  909. // Letter 'H' to toggle hidden mode
  910. if (e.keyCode === 72) {
  911. userInterface.toggleOverlays();
  912. }
  913. // Letter 'O' to change rendermode (visual)
  914. if (e.keyCode === 79) {
  915. userInterface.toggleMobileRendering(!window.mobileRender);
  916. }
  917. // Letter 'C' to toggle Collision detection / enemy avoidance
  918. if (e.keyCode === 67) {
  919. window.collisionDetection = !window.collisionDetection;
  920. console.log('collisionDetection set to: ' + window.collisionDetection);
  921. userInterface.savePreference('collisionDetection', window.collisionDetection);
  922. }
  923. // Letter 'A' to increase collision detection radius
  924. if (e.keyCode === 65) {
  925. window.collisionRadiusMultiplier++;
  926. console.log(
  927. 'collisionRadiusMultiplier set to: ' + window.collisionRadiusMultiplier);
  928. userInterface.savePreference(
  929. 'collisionRadiusMultiplier', window.collisionRadiusMultiplier);
  930. }
  931. // Letter 'S' to decrease collision detection radius
  932. if (e.keyCode === 83) {
  933. if (window.collisionRadiusMultiplier > 1) {
  934. window.collisionRadiusMultiplier--;
  935. console.log(
  936. 'collisionRadiusMultiplier set to: ' +
  937. window.collisionRadiusMultiplier);
  938. userInterface.savePreference(
  939. 'collisionRadiusMultiplier', window.collisionRadiusMultiplier);
  940. }
  941. }
  942. // Letter 'Z' to reset zoom
  943. if (e.keyCode === 90) {
  944. canvas.resetZoom();
  945. }
  946. // Letter 'Q' to quit to main menu
  947. if (e.keyCode === 81) {
  948. window.autoRespawn = false;
  949. userInterface.quit();
  950. }
  951. // 'ESC' to quickly respawn
  952. if (e.keyCode === 27) {
  953. bot.quickRespawn();
  954. }
  955. // Save nickname when you press "Enter"
  956. if (e.keyCode === 13) {
  957. userInterface.saveNick();
  958. }
  959. userInterface.onPrefChange();
  960. }
  961. },
  962.  
  963. // Manual mobile rendering
  964. toggleMobileRendering: function(mobileRendering) {
  965. window.mobileRender = mobileRendering;
  966. window.log('Mobile rendering set to: ' + window.mobileRender);
  967. userInterface.savePreference('mobileRender', window.mobileRender);
  968. // Set render mode
  969. if (window.mobileRender) {
  970. canvas.setBackground(
  971. 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs');
  972. window.render_mode = 1;
  973. window.want_quality = 0;
  974. window.high_quality = false;
  975. } else {
  976. canvas.setBackground();
  977. window.render_mode = 2;
  978. window.want_quality = 1;
  979. window.high_quality = true;
  980. }
  981. },
  982.  
  983. onPrefChange: function() {
  984. // Set static display options here.
  985. var oContent = [];
  986. var ht = userInterface.handleTextColor;
  987.  
  988. oContent.push('version: ' + GM_info.script.version);
  989. oContent.push('[T] Enable / disable bot: ' + ht(bot.isBotEnabled));
  990. oContent.push('[C] collision detection on/off: ' + ht(window.collisionDetection));
  991. oContent.push('[O] Mobile version on/off: ' + ht(window.mobileRender));
  992. oContent.push('[A/S] Radius multiplier (S-less, A-Greater): ' + window.collisionRadiusMultiplier);
  993. oContent.push('[I] Auto spawn on / off: ' + ht(window.autoRespawn));
  994. oContent.push('[Y] Visual debugging on / off: ' + ht(window.visualDebugging));
  995. oContent.push('[U] debug log: ' + ht(window.logDebugging));
  996. oContent.push('[Wheel(mouse)] Zoom (zoom in on top, zoom out down');
  997. oContent.push('[Z] Reset Zoom.');
  998. oContent.push('[ESC] Respawn');
  999. oContent.push('[Q] Exit to menu.');
  1000.  
  1001. userInterface.overlays.prefOverlay.innerHTML = oContent.join('<br/>');
  1002. },
  1003.  
  1004. onFrameUpdate: function() {
  1005. // Botstatus overlay
  1006. var oContent = [];
  1007.  
  1008. if (window.playing && window.snake !== null) {
  1009. oContent.push('fps: ' + userInterface.framesPerSecond.fps);
  1010.  
  1011. // Display the X and Y of the snake
  1012. oContent.push('x: ' +
  1013. (Math.round(window.snake.xx) || 0) + ' y: ' +
  1014. (Math.round(window.snake.yy) || 0));
  1015.  
  1016. if (window.goalCoordinates) {
  1017. oContent.push('target');
  1018. oContent.push('x: ' + window.goalCoordinates.x + ' y: ' +
  1019. window.goalCoordinates.y);
  1020. if (window.goalCoordinates.sz) {
  1021. oContent.push('sz: ' + window.goalCoordinates.sz);
  1022. }
  1023. }
  1024.  
  1025. if (window.bso !== undefined && userInterface.overlays.serverOverlay.innerHTML !==
  1026. window.bso.ip + ':' + window.bso.po) {
  1027. userInterface.overlays.serverOverlay.innerHTML =
  1028. window.bso.ip + ':' + window.bso.po;
  1029. }
  1030. }
  1031.  
  1032. userInterface.overlays.botOverlay.innerHTML = oContent.join('<br/>');
  1033.  
  1034.  
  1035. if (window.playing && window.visualDebugging) {
  1036. // Only draw the goal when a bot has a goal.
  1037. if (window.goalCoordinates && bot.isBotEnabled) {
  1038. var headCoord = {
  1039. x: window.snake.xx,
  1040. y: window.snake.yy
  1041. };
  1042. canvas.drawLine(
  1043. headCoord,
  1044. window.goalCoordinates,
  1045. 'green');
  1046. canvas.drawCircle(window.goalCoordinates, 'red', true);
  1047. }
  1048. }
  1049. },
  1050.  
  1051. oefTimer: function() {
  1052. var start = Date.now();
  1053. canvas.maintainZoom();
  1054. original_oef();
  1055. original_redraw();
  1056.  
  1057. if (window.playing && bot.isBotEnabled && window.snake !== null) {
  1058. window.onmousemove = function() {};
  1059. bot.isBotRunning = true;
  1060. bot.collisionLoop();
  1061. } else if (bot.isBotEnabled && bot.isBotRunning) {
  1062. bot.isBotRunning = false;
  1063. if (window.lastscore && window.lastscore.childNodes[1]) {
  1064. bot.scores.push(parseInt(window.lastscore.childNodes[1].innerHTML));
  1065. bot.scores.sort(function(a, b) {
  1066. return b - a;
  1067. });
  1068. userInterface.updateStats();
  1069. }
  1070.  
  1071. if (window.autoRespawn) {
  1072. window.connect();
  1073. }
  1074. }
  1075.  
  1076. if (!bot.isBotEnabled || bot.isBotRunning) {
  1077. window.onmousemove = original_onmousemove;
  1078. }
  1079.  
  1080. userInterface.onFrameUpdate();
  1081. setTimeout(userInterface.oefTimer, (1000 / TARGET_FPS) - (Date.now() - start));
  1082. },
  1083.  
  1084. // Quit to menu
  1085. quit: function() {
  1086. if (window.playing && window.resetGame) {
  1087. window.want_close_socket = true;
  1088. window.dead_mtm = 0;
  1089. if (window.play_btn) {
  1090. window.play_btn.setEnabled(true);
  1091. }
  1092. window.resetGame();
  1093. }
  1094. },
  1095.  
  1096. // Update the relation between the screen and the canvas.
  1097. onresize: function() {
  1098. window.resize();
  1099. // Canvas different size from the screen (often bigger).
  1100. canvas.canvasRatio = {
  1101. x: window.mc.width / window.ww,
  1102. y: window.mc.height / window.hh
  1103. };
  1104. },
  1105.  
  1106. handleTextColor: function(enabled) {
  1107. return '<span style=\"color:' +
  1108. (enabled ? 'green;\">enabled' : 'red;\">disabled') + '</span>';
  1109. }
  1110. };
  1111. })();
  1112.  
  1113. // Main
  1114. (function() {
  1115. window.play_btn.btnf.addEventListener('click', userInterface.playButtonClickListener);
  1116. document.onkeydown = userInterface.onkeydown;
  1117. window.onmousedown = userInterface.onmousedown;
  1118. window.addEventListener('mouseup', userInterface.onmouseup);
  1119. window.onresize = userInterface.onresize;
  1120.  
  1121. // Hide top score
  1122. userInterface.hideTop();
  1123.  
  1124. // Overlays
  1125. userInterface.initOverlays();
  1126.  
  1127. // Load preferences
  1128. userInterface.loadPreference('logDebugging', true);
  1129. userInterface.loadPreference('visualDebugging', true);
  1130. userInterface.loadPreference('autoRespawn', true);
  1131. userInterface.loadPreference('mobileRender', true);
  1132. userInterface.loadPreference('collisionDetection', true);
  1133. userInterface.loadPreference('collisionRadiusMultiplier', 10);
  1134. window.nick.value = userInterface.loadPreference('savedNick', 'Slither.io Trainer Hack');
  1135.  
  1136. // Listener for mouse wheel scroll - used for setZoom function
  1137. document.body.addEventListener('mousewheel', canvas.setZoom);
  1138. document.body.addEventListener('DOMMouseScroll', canvas.setZoom);
  1139.  
  1140. // Set render mode
  1141. if (window.mobileRender) {
  1142. userInterface.toggleMobileRendering(false);
  1143. } else {
  1144. userInterface.toggleMobileRendering(true);
  1145. }
  1146.  
  1147. // Unblocks all skins without the need for FB sharing.
  1148. window.localStorage.setItem('edttsg', '1');
  1149.  
  1150. // Remove social
  1151. window.social.remove();
  1152.  
  1153. // Maintain fps
  1154. setInterval(userInterface.framesPerSecond.fpsTimer, 80);
  1155.  
  1156. // Start!
  1157. userInterface.oefTimer();
  1158. })();