Slither.io Enhancer (Background Changer Auto Play Bot + Zoom + FPS Counter)

Adds background color changer (left side) Auto Play Bot and a rainbow FPS counter to slither.io

  1. // ==UserScript==
  2. // @name Slither.io Enhancer (Background Changer Auto Play Bot + Zoom + FPS Counter)
  3. // @namespace http://tampermonkey.net/
  4. // @version 3.2
  5. // @description Adds background color changer (left side) Auto Play Bot and a rainbow FPS counter to slither.io
  6. // @author Eliott Valette Jadob Lane
  7. // @match http://slither.com/io
  8. // @grant none
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. // ===== Background Color Changer =====
  16. function createBackgroundChanger() {
  17. const colors = {
  18. Default: '#1a1a1a',
  19. Light: '#f0f0f0',
  20. Navy: '#001f3f',
  21. Green: '#2ecc40',
  22. Purple: '#7f00ff',
  23. Pink: '#ff69b4',
  24. Cyan: '#00ffff',
  25. Red: '#ff4136',
  26. Orange: '#ff851b',
  27. Yellow: '#ffdc00',
  28. Lime: '#01ff70',
  29. Teal: '#39cccc',
  30. Indigo: '#4b0082',
  31. Brown: '#8b4513',
  32. Gray: '#aaaaaa',
  33. Blue: '#00008B',
  34. };
  35.  
  36. const container = document.createElement('div');
  37. container.style.position = 'fixed';
  38. container.style.top = '50%';
  39. container.style.left = '10px';
  40. container.style.transform = 'translateY(-50%)';
  41. container.style.zIndex = '9999';
  42. container.style.background = 'rgba(0, 0, 0, 0.6)';
  43. container.style.padding = '8px';
  44. container.style.borderRadius = '5px';
  45. container.style.color = '#fff';
  46. container.style.fontFamily = 'Arial, sans-serif';
  47. container.style.fontSize = '14px';
  48.  
  49. const label = document.createElement('label');
  50. label.textContent = 'Background: ';
  51. label.style.marginRight = '5px';
  52.  
  53. const select = document.createElement('select');
  54. for (let name in colors) {
  55. const option = document.createElement('option');
  56. option.value = colors[name];
  57. option.textContent = name;
  58. select.appendChild(option);
  59. }
  60.  
  61. select.addEventListener('change', function() {
  62. document.body.style.backgroundColor = select.value;
  63. });
  64.  
  65. container.appendChild(label);
  66. container.appendChild(select);
  67. document.body.appendChild(container);
  68.  
  69. select.addEventListener('keydown', function(event) {
  70. if (event.key === ' ' || event.keyCode === 32) {
  71. event.preventDefault();
  72. }
  73. });
  74. }
  75.  
  76. // ===== Initialize After Page Load =====
  77. window.addEventListener('load', function() {
  78. createBackgroundChanger();
  79.  
  80. // ===== Rainbow FPS Counter =====
  81. const fpsDisplay = document.createElement('div');
  82. fpsDisplay.style.position = 'fixed';
  83. fpsDisplay.style.top = '10px';
  84. fpsDisplay.style.right = '10px';
  85. fpsDisplay.style.zIndex = '10000';
  86. fpsDisplay.style.fontFamily = 'Arial, sans-serif';
  87. fpsDisplay.style.fontSize = '16px';
  88. fpsDisplay.style.fontWeight = 'bold';
  89. fpsDisplay.style.padding = '5px 10px';
  90. fpsDisplay.style.borderRadius = '5px';
  91. fpsDisplay.style.background = 'rgba(0, 0, 0, 0.5)';
  92. document.body.appendChild(fpsDisplay);
  93.  
  94. let lastFrameTime = performance.now();
  95. let frames = 0;
  96. let fps = 0;
  97. let hue = 0;
  98.  
  99. function updateFPS() {
  100. const now = performance.now();
  101. frames++;
  102. if (now - lastFrameTime >= 1000) {
  103. fps = frames;
  104. frames = 0;
  105. lastFrameTime = now;
  106. }
  107.  
  108. hue = (hue + 1) % 360;
  109. fpsDisplay.style.color = `hsl(${hue}, 100%, 60%)`;
  110. fpsDisplay.textContent = `FPS: ${fps}`;
  111.  
  112. requestAnimationFrame(updateFPS);
  113. }
  114.  
  115. requestAnimationFrame(updateFPS);
  116.  
  117. // ===== Extra Bottom Space =====
  118. // Custom log function (only displays if "logDebugging" is enabled)
  119. window.log = (...args) => window.logDebugging && console.log(...args);
  120.  
  121. // Functions to save and load preferences in localStorage
  122. const savePreference = (key, value) => localStorage.setItem(key, value);
  123. const loadPreference = (key, def) => JSON.parse(localStorage.getItem(key)) ?? def;
  124.  
  125. let Logger = 0;
  126. let IsBotActive = true;
  127. let targetFood = null;
  128. let targetFoodTimestamp = 0;
  129. let blacklistedFoods = {};
  130. let criticDanger = false;
  131.  
  132. // Ajout des variables et fonctions pour le zoom
  133. window.zoomMultiplier = 1.0;
  134.  
  135. window.updateZoom = function() {
  136. window.gsc = window.zoomMultiplier;
  137. const zoomElement = document.getElementById("bot_zoom_overlay");
  138. if (zoomElement) {
  139. zoomElement.textContent = `Zoom: ${window.zoomMultiplier.toFixed(1)} (a to zoom, e to zoom out, z to reset)`;
  140. }
  141. };
  142.  
  143. window.recursiveZoomUpdate = function() {
  144. window.gsc = window.zoomMultiplier;
  145. requestAnimationFrame(window.recursiveZoomUpdate);
  146. };
  147.  
  148. window.resetZoom = function() {
  149. window.zoomMultiplier = 1.0;
  150. window.updateZoom();
  151. };
  152.  
  153. window.adjustZoom = function(amount) {
  154. window.zoomMultiplier = Math.max(0.2, Math.min(3.0, window.zoomMultiplier + amount));
  155. window.updateZoom();
  156. };
  157.  
  158. // Add listener to memorize real mouse position
  159. window.mousePos = { x: 0, y: 0 };
  160. document.addEventListener('mousemove', function(e) {
  161. window.mousePos = { x: e.clientX, y: e.clientY };
  162. });
  163.  
  164. // Variable to memorize bot target position (the "bot mouse pose")
  165. window.botTargetPos = null;
  166.  
  167. console.log('Bot Starting');
  168.  
  169. /*
  170. ===================================================
  171. Section 2: Window Object Debug Scan
  172. ===================================================
  173. After 5 seconds, scans the window object to find
  174. potential snake objects (presence of xx and yy)
  175. */
  176. setTimeout(() => {
  177. for (let key in window) {
  178. try {
  179. let val = window[key];
  180. if (val && typeof val === 'object') {
  181. // Checks if the object has coordinates
  182. if ('xx' in val && 'yy' in val) {
  183. console.log(`🟢 Snake? -> window.${key}`, val);
  184. }
  185. // Checks if the object is an array of objects with coordinates
  186. if (Array.isArray(val) && val.length > 0 && val[0] && 'xx' in val[0] && 'yy' in val[0]) {
  187. console.log(`🍏 Array of objects with coords? -> window.${key}`, val);
  188. }
  189. }
  190. } catch (e) {
  191. // In case of error, move to next property
  192. }
  193. }
  194. }, 5000);
  195.  
  196. /*
  197. ===================================================
  198. Section 3: Improved Interface Overlay
  199. ===================================================
  200. Creation of a unique container that displays bot status,
  201. coordinates and enemy count in real-time.
  202. */
  203. (function setupOverlayUI() {
  204. // Creation of main container with semi-transparent background
  205. const overlayContainer = document.createElement('div');
  206. overlayContainer.id = 'bot-overlay-container';
  207. overlayContainer.style.cssText = `
  208. position: fixed;
  209. top: 10px;
  210. left: 10px;
  211. background: rgba(0, 0, 0, 0.5);
  212. padding: 10px;
  213. border-radius: 5px;
  214. z-index: 9999;
  215. font-family: Arial, sans-serif;
  216. color: #FFF;
  217. font-size: 14px;
  218. `;
  219. document.body.appendChild(overlayContainer);
  220.  
  221. // Creation of sub-elements for status, coordinates and enemy count
  222. const statusDiv = document.createElement('div');
  223. statusDiv.id = 'bot_status_overlay';
  224. statusDiv.textContent = 'Status: BOT ON (To Toggle - Press t)';
  225. overlayContainer.appendChild(statusDiv);
  226.  
  227. // Ajout de l'élément de zoom dans le conteneur principal
  228. const zoomDiv = document.createElement('div');
  229. zoomDiv.id = 'bot_zoom_overlay';
  230. zoomDiv.textContent = `Zoom: ${window.zoomMultiplier.toFixed(1)} (a to zoom, e to zoom out, z to reset)`;
  231. overlayContainer.appendChild(zoomDiv);
  232.  
  233. const coordsDiv = document.createElement('div');
  234. coordsDiv.id = 'bot_coords_overlay';
  235. coordsDiv.textContent = 'Coords: loading...';
  236. overlayContainer.appendChild(coordsDiv);
  237.  
  238. const enemyDiv = document.createElement('div');
  239. enemyDiv.id = 'bot_enemies_overlay';
  240. enemyDiv.textContent = 'Enemies: loading...';
  241. overlayContainer.appendChild(enemyDiv);
  242.  
  243. const nearEnemiesDiv = document.createElement('div');
  244. nearEnemiesDiv.id = 'bot_enemies_near_overlay';
  245. nearEnemiesDiv.textContent = 'Enemies (Near): loading...';
  246. overlayContainer.appendChild(nearEnemiesDiv);
  247.  
  248. const midEnemiesDiv = document.createElement('div');
  249. midEnemiesDiv.id = 'bot_enemies_mid_overlay';
  250. midEnemiesDiv.textContent = 'Enemies (Mid): loading...';
  251. overlayContainer.appendChild(midEnemiesDiv);
  252.  
  253. const farEnemiesDiv = document.createElement('div');
  254. farEnemiesDiv.id = 'bot_enemies_far_overlay';
  255. farEnemiesDiv.textContent = 'Enemies (Far): loading...';
  256. overlayContainer.appendChild(farEnemiesDiv);
  257.  
  258. const criticDangerDiv = document.createElement('div');
  259. criticDangerDiv.id = 'bot_critic_danger_overlay';
  260. criticDangerDiv.textContent = 'Danger: loading...';
  261. overlayContainer.appendChild(criticDangerDiv);
  262.  
  263. // Continuous overlay update via requestAnimationFrame
  264. function updateOverlay() {
  265. if (window.slither && typeof window.slither.xx === 'number') {
  266. statusDiv.textContent = IsBotActive ? 'Status: BOT ON (To Turn OFF - Press t)' : 'Status: BOT OFF (To Turn ON - Press t)';
  267. coordsDiv.textContent = `Coords: ${Math.round(window.slither.xx)} / ${Math.round(window.slither.yy)}`;
  268. criticDangerDiv.textContent = `Danger: ${criticDanger}`;
  269. }
  270. if (Array.isArray(window.slithers) && window.slither) {
  271. const self = window.slither;
  272. // Building enemy lists based on distance from their body points
  273. const nearEnemies = [];
  274. const midEnemies = [];
  275. const farEnemies = [];
  276. window.slithers.forEach(e => {
  277. if (!e || typeof e.xx !== 'number' || typeof e.yy !== 'number' || e.xx === self.xx)
  278. return;
  279. const bodyPoints = getEnemyBodyPoints(e);
  280. let minDistance = Infinity;
  281. let closestPoint = null;
  282. bodyPoints.forEach(p => {
  283. const dx = p.xx - self.xx;
  284. const dy = p.yy - self.yy;
  285. const dist = Math.sqrt(dx * dx + dy * dy);
  286. if (dist < minDistance) {
  287. minDistance = dist;
  288. closestPoint = p;
  289. }
  290. });
  291. if (closestPoint) {
  292. if (minDistance < 300) {
  293. nearEnemies.push({ enemy: e, dist: minDistance, point: closestPoint });
  294. } else if (minDistance >= 300 && minDistance <= 700) {
  295. midEnemies.push({ enemy: e, dist: minDistance, point: closestPoint });
  296. } else if (minDistance > 700) {
  297. farEnemies.push({ enemy: e, dist: minDistance, point: closestPoint });
  298. }
  299. }
  300. });
  301. enemyDiv.textContent = 'Enemies: ' + window.slithers.length;
  302. nearEnemiesDiv.textContent = 'Enemies (Near): ' + nearEnemies.map(e => e.enemy.id || `(${Math.round(e.point.xx)},${Math.round(e.point.yy)})`).join(', ');
  303. midEnemiesDiv.textContent = 'Enemies (Mid): ' + midEnemies.map(e => e.enemy.id || `(${Math.round(e.point.xx)},${Math.round(e.point.yy)})`).join(', ');
  304. farEnemiesDiv.textContent = 'Enemies (Far): ' + farEnemies.map(e => e.enemy.id || `(${Math.round(e.point.xx)},${Math.round(e.point.yy)})`).join(', ');
  305. }
  306. requestAnimationFrame(updateOverlay);
  307. }
  308. requestAnimationFrame(updateOverlay);
  309. })();
  310.  
  311. /*
  312. ===================================================
  313. Section 4: World to Screen Coordinate Conversion
  314. ===================================================
  315. Utility function to convert game coordinates
  316. (in "world") to screen coordinates.
  317. */
  318. const worldToScreen = (xx, yy) => {
  319. const mapX = (xx - window.view_xx) * window.gsc + window.mww2;
  320. const mapY = (yy - window.view_yy) * window.gsc + window.mhh2;
  321. return { x: mapX, y: mapY };
  322. };
  323.  
  324. /*
  325. ===================================================
  326. Section 5: Enemy Processing
  327. ===================================================
  328. Functions to extract enemy body points and
  329. calculate line color based on distance.
  330. */
  331.  
  332. // Gets enemy body points by traversing its segments
  333. function getEnemyBodyPoints(enemy) {
  334. const points = [];
  335. if (!enemy.pts) return points;
  336.  
  337. for (const segment of enemy.pts) {
  338. if (!segment.fxs || !segment.fys) continue;
  339.  
  340. // Sampling: we get about 10% of the segment points
  341. const step = Math.max(1, Math.floor(segment.fxs.length / 10));
  342. for (let i = 0; i < segment.fxs.length; i += step) {
  343. const x = segment.xx + segment.fxs[i];
  344. const y = segment.yy + segment.fys[i];
  345.  
  346. if (isFinite(x) && isFinite(y)) {
  347. points.push({ xx: x, yy: y });
  348. }
  349. }
  350. }
  351. return points;
  352. }
  353.  
  354. // Calculates a color transitioning from red (close) to green (far)
  355. function DangerColor(start, end) {
  356. const dx = end.x - start.x;
  357. const dy = end.y - start.y;
  358. const dist = Math.sqrt(dx * dx + dy * dy);
  359. const maxDist = 3000; // Maximum distance to fully transition to green
  360. const dangerRatio = Math.max(0, Math.min(1, 1 - dist / maxDist));
  361. const r = Math.floor(255 * dangerRatio);
  362. const g = Math.floor(255 * (1 - dangerRatio));
  363. return `rgb(${r},${g},0)`;
  364. }
  365.  
  366. /*
  367. ===================================================
  368. Section 6: Drawing Lines to Enemies and Food
  369. ===================================================
  370. Two functions to draw lines between the player and:
  371. - Enemies (by choosing the closest point of each enemy)
  372. - Food (with a custom color)
  373. */
  374. // Draws lines connecting the player to enemies
  375. function drawAllEnemyLines(start, enemyList) {
  376. let canvas = document.getElementById('bot-line-overlay');
  377. if (!canvas) {
  378. canvas = document.createElement('canvas');
  379. canvas.id = 'bot-line-overlay';
  380. canvas.style.cssText = `
  381. position: fixed;
  382. top: 0;
  383. left: 0;
  384. pointer-events: none;
  385. z-index: 9998;
  386. `;
  387. document.body.appendChild(canvas);
  388.  
  389. // Resize canvas when window is resized
  390. window.addEventListener('resize', () => {
  391. canvas.width = window.innerWidth;
  392. canvas.height = window.innerHeight;
  393. });
  394. canvas.width = window.innerWidth;
  395. canvas.height = window.innerHeight;
  396. }
  397.  
  398. const ctx = canvas.getContext('2d');
  399. ctx.clearRect(0, 0, canvas.width, canvas.height);
  400.  
  401. // Si le bot est OFF, on trie les ennemis par distance et on garde les 5 plus proches
  402. let enemiesToDraw = enemyList;
  403. if (!IsBotActive) {
  404. enemiesToDraw = enemyList
  405. .map(enemy => {
  406. const body_points = getEnemyBodyPoints(enemy);
  407. let min_dist = Infinity;
  408. body_points.forEach(p => {
  409. const dx = p.xx - window.slither.xx;
  410. const dy = p.yy - window.slither.yy;
  411. const d = dx * dx + dy * dy;
  412. if (d < min_dist) min_dist = d;
  413. });
  414. return { enemy, min_dist };
  415. })
  416. .sort((a, b) => a.min_dist - b.min_dist)
  417. .slice(0, 5)
  418. .map(obj => obj.enemy);
  419. }
  420.  
  421. enemiesToDraw.forEach(enemy => {
  422. const body_points = getEnemyBodyPoints(enemy);
  423. let min_dist = Infinity;
  424. let min_dist_point = null;
  425. body_points.forEach(p => {
  426. const screenPoint = worldToScreen(p.xx, p.yy);
  427. const dx = screenPoint.x - start.x;
  428. const dy = screenPoint.y - start.y;
  429. const d = dx * dx + dy * dy;
  430. if (d < min_dist && d > 0) {
  431. min_dist = d;
  432. min_dist_point = screenPoint;
  433. }
  434. });
  435. if (Logger < 100) {
  436. console.log('min_dist', min_dist);
  437. Logger++;
  438. }
  439. if (min_dist_point) {
  440. ctx.beginPath();
  441. ctx.moveTo(start.x, start.y);
  442. ctx.lineTo(min_dist_point.x, min_dist_point.y);
  443. ctx.strokeStyle = DangerColor(start, min_dist_point);
  444. ctx.lineWidth = 1.5;
  445. ctx.stroke();
  446. }
  447. });
  448. }
  449.  
  450.  
  451. // Draws lines connecting the player to food particles
  452. function drawAllFoodLines(start, foodList) {
  453. let canvas = document.getElementById('bot-line-overlay-food');
  454. if (!canvas) {
  455. canvas = document.createElement('canvas');
  456. canvas.id = 'bot-line-overlay-food';
  457. canvas.style.cssText = `
  458. position: fixed;
  459. top: 0;
  460. left: 0;
  461. pointer-events: none;
  462. z-index: 9997;
  463. `;
  464. document.body.appendChild(canvas);
  465.  
  466. window.addEventListener('resize', () => {
  467. canvas.width = window.innerWidth;
  468. canvas.height = window.innerHeight;
  469. });
  470. canvas.width = window.innerWidth;
  471. canvas.height = window.innerHeight;
  472. }
  473.  
  474. const ctx = canvas.getContext('2d');
  475. ctx.clearRect(0, 0, canvas.width, canvas.height);
  476.  
  477. foodList.forEach(food => {
  478. const end = worldToScreen(food.xx, food.yy);
  479. ctx.beginPath();
  480. ctx.moveTo(start.x, start.y);
  481. ctx.lineTo(end.x, end.y);
  482. ctx.strokeStyle = 'cyan';
  483. ctx.lineWidth = 1;
  484. ctx.stroke();
  485. });
  486. }
  487.  
  488. /*
  489. ===================================================
  490. Section 7: Animation Loop for Line Drawing
  491. ===================================================
  492. Uses requestAnimationFrame for smooth animation.
  493. */
  494. (function updateEnemyLines() {
  495. function update() {
  496. if (
  497. window.slither &&
  498. window.slither.xx !== undefined &&
  499. window.view_xx !== undefined &&
  500. Array.isArray(window.slithers)
  501. ) {
  502. const selfScreen = worldToScreen(window.slither.xx, window.slither.yy);
  503. const validEnemies = window.slithers.filter(e =>
  504. e &&
  505. typeof e.xx === 'number' &&
  506. typeof e.yy === 'number' &&
  507. window.slither.xx !== e.xx
  508. );
  509. drawAllEnemyLines(selfScreen, validEnemies);
  510. }
  511. requestAnimationFrame(update);
  512. }
  513. requestAnimationFrame(update);
  514. })();
  515.  
  516. (function updateFoodTargetLine() {
  517. let canvas = document.getElementById('bot-line-overlay-food');
  518. if (!canvas) {
  519. canvas = document.createElement('canvas');
  520. canvas.id = 'bot-line-overlay-food';
  521. canvas.style.cssText = `
  522. position: fixed;
  523. top: 0;
  524. left: 0;
  525. pointer-events: none;
  526. z-index: 9997;
  527. `;
  528. document.body.appendChild(canvas);
  529. canvas.width = window.innerWidth;
  530. canvas.height = window.innerHeight;
  531. window.addEventListener('resize', () => {
  532. canvas.width = window.innerWidth;
  533. canvas.height = window.innerHeight;
  534. });
  535. }
  536.  
  537. function update() {
  538. const ctx = canvas.getContext('2d');
  539. ctx.clearRect(0, 0, canvas.width, canvas.height);
  540. if (window.slither && typeof window.slither.xx === 'number' && targetFood) {
  541. const selfScreen = worldToScreen(window.slither.xx, window.slither.yy);
  542. const end = worldToScreen(targetFood.xx, targetFood.yy);
  543. ctx.beginPath();
  544. ctx.moveTo(selfScreen.x, selfScreen.y);
  545. ctx.lineTo(end.x, end.y);
  546. ctx.strokeStyle = 'cyan';
  547. ctx.lineWidth = 1;
  548. ctx.stroke();
  549. }
  550. requestAnimationFrame(update);
  551. }
  552. requestAnimationFrame(update);
  553. })();
  554.  
  555. /*
  556. ===================================================
  557. Section 8: Line between Snake and Real Mouse
  558. ===================================================
  559. Draws a magenta line between the snake and the real mouse position.
  560. */
  561. (function updateMouseLine() {
  562. let canvas = document.getElementById('bot-line-mouse');
  563. if (!canvas) {
  564. canvas = document.createElement('canvas');
  565. canvas.id = 'bot-line-mouse';
  566. canvas.style.cssText = `
  567. position: fixed;
  568. top: 0;
  569. left: 0;
  570. pointer-events: none;
  571. z-index: 9996;
  572. `;
  573. document.body.appendChild(canvas);
  574. canvas.width = window.innerWidth;
  575. canvas.height = window.innerHeight;
  576. window.addEventListener('resize', () => {
  577. canvas.width = window.innerWidth;
  578. canvas.height = window.innerHeight;
  579. });
  580. }
  581. function update() {
  582. const ctx = canvas.getContext('2d');
  583. ctx.clearRect(0, 0, canvas.width, canvas.height);
  584. if (window.slither && typeof window.slither.xx === 'number' && window.mousePos) {
  585. const selfScreen = worldToScreen(window.slither.xx, window.slither.yy);
  586. ctx.beginPath();
  587. ctx.moveTo(selfScreen.x, selfScreen.y);
  588. ctx.lineTo(window.mousePos.x, window.mousePos.y);
  589. ctx.strokeStyle = 'magenta';
  590. ctx.lineWidth = 2;
  591. ctx.stroke();
  592. }
  593. requestAnimationFrame(update);
  594. }
  595. requestAnimationFrame(update);
  596. })();
  597.  
  598. /*
  599. ===================================================
  600. Section 9: Line between Snake and Bot Mouse Position
  601. ===================================================
  602. Draws a yellow line between the snake and the bot's target position.
  603. */
  604. (function updateBotMouseLine() {
  605. let canvas = document.getElementById('bot-line-botmouse');
  606. if (!canvas) {
  607. canvas = document.createElement('canvas');
  608. canvas.id = 'bot-line-botmouse';
  609. canvas.style.cssText = `
  610. position: fixed;
  611. top: 0;
  612. left: 0;
  613. pointer-events: none;
  614. z-index: 9995;
  615. `;
  616. document.body.appendChild(canvas);
  617. canvas.width = window.innerWidth;
  618. canvas.height = window.innerHeight;
  619. window.addEventListener('resize', () => {
  620. canvas.width = window.innerWidth;
  621. canvas.height = window.innerHeight;
  622. });
  623. }
  624. function update() {
  625. const ctx = canvas.getContext('2d');
  626. ctx.clearRect(0, 0, canvas.width, canvas.height);
  627. if (window.slither && typeof window.slither.xx === 'number' && window.botTargetPos) {
  628. const selfScreen = worldToScreen(window.slither.xx, window.slither.yy);
  629. const targetScreen = worldToScreen(window.botTargetPos.x, window.botTargetPos.y);
  630. ctx.beginPath();
  631. ctx.moveTo(selfScreen.x, selfScreen.y);
  632. ctx.lineTo(targetScreen.x, targetScreen.y);
  633. ctx.strokeStyle = 'yellow';
  634. ctx.lineWidth = 2;
  635. ctx.stroke();
  636. }
  637. requestAnimationFrame(update);
  638. }
  639. requestAnimationFrame(update);
  640. })();
  641.  
  642. /*
  643. ===================================================
  644. Section 10: FoodBot - Automatic Movement Towards Food
  645. ===================================================
  646. Detects the closest enemy and chooses a food particle
  647. located in the opposite direction to move the mouse (and thus the snake).
  648. */
  649.  
  650. // Simulates a mouse movement event towards a given position in the world
  651. function moveMouseToward(worldX, worldY) {
  652. // Updates the bot's target position
  653. window.botTargetPos = { x: worldX, y: worldY };
  654.  
  655. const screenX = (worldX - window.view_xx) * window.gsc + window.mww2;
  656. const screenY = (worldY - window.view_yy) * window.gsc + window.mhh2;
  657.  
  658. const event = new MouseEvent('mousemove', {
  659. clientX: screenX,
  660. clientY: screenY,
  661. bubbles: true
  662. });
  663. window.dispatchEvent(event);
  664. }
  665.  
  666. // Declare a variable for the FoodBot interval
  667. let foodBotInterval = null;
  668.  
  669. // The function containing the FoodBot update code
  670. function foodBotUpdate() {
  671. if (
  672. window.slither &&
  673. typeof window.slither.xx === 'number' &&
  674. Array.isArray(window.foods)
  675. ) {
  676. const self = window.slither;
  677. const now = Date.now();
  678.  
  679. // Building the list of enemies with their closest body point
  680. let enemyList = [];
  681. if (Array.isArray(window.slithers)) {
  682. window.slithers.forEach(enemy => {
  683. if (!enemy || typeof enemy.xx !== 'number' || typeof enemy.yy !== 'number' || enemy.xx === self.xx)
  684. return;
  685. const bodyPoints = getEnemyBodyPoints(enemy);
  686. if (bodyPoints.length === 0) return;
  687. let bestPoint = null;
  688. let bestDistance = Infinity;
  689. let bestDx = 0, bestDy = 0;
  690. bodyPoints.forEach(p => {
  691. const dx = p.xx - self.xx;
  692. const dy = p.yy - self.yy;
  693. const d = Math.sqrt(dx * dx + dy * dy);
  694. if (d < bestDistance) {
  695. bestDistance = d;
  696. bestPoint = p;
  697. bestDx = dx;
  698. bestDy = dy;
  699. }
  700. });
  701. if (bestPoint) {
  702. enemyList.push({ point: bestPoint, distance: bestDistance, dx: bestDx, dy: bestDy });
  703. }
  704. });
  705. }
  706.  
  707. // Utility function to choose the best food in SAFE mode
  708. // This targets foods with the largest size and high local density (grouping)
  709. function chooseBestFood(foods) {
  710. // D'abord, filtrer les nourritures pour ne garder que celles à moins de 100 pixels du joueur
  711. const maxPlayerDistance = 300;
  712. const nearbyFoods = foods.filter(f => {
  713. if (!f || typeof f.xx !== 'number' || typeof f.yy !== 'number') return false;
  714. const dx = f.xx - self.xx;
  715. const dy = f.yy - self.yy;
  716. const d = Math.sqrt(dx * dx + dy * dy);
  717. return d <= maxPlayerDistance;
  718. });
  719.  
  720. // Si aucune nourriture à proximité, retourner null
  721. if (nearbyFoods.length === 0) return null;
  722.  
  723. let bestFood = null;
  724. let bestScore = -Infinity;
  725. const groupRadius = 60; // rayon pour déterminer le groupement
  726.  
  727. nearbyFoods.forEach(f => {
  728. if (!f || typeof f.xx !== 'number' || typeof f.yy !== 'number' || typeof f.sz !== 'number') return;
  729. let groupCount = 0;
  730.  
  731. // Compter combien d'autres nourritures sont proches de celle-ci
  732. nearbyFoods.forEach(other => {
  733. if (other === f) return;
  734. const dx = other.xx - f.xx;
  735. const dy = other.yy - f.yy;
  736. const d = Math.sqrt(dx * dx + dy * dy);
  737. if (d < groupRadius) {
  738. groupCount++;
  739. groupCount += 1/(d+1e-5) * 100;
  740. }
  741. });
  742.  
  743. const score = f.sz + groupCount; // combine taille et densité
  744. if (score > bestScore) {
  745. bestScore = score;
  746. bestFood = f;
  747. }
  748. });
  749.  
  750. return bestFood;
  751. }
  752.  
  753. // Filter the food list to exclude blacklisted ones
  754. let availableFoods = window.foods.filter(f => {
  755. return (
  756. f &&
  757. typeof f.xx === 'number' &&
  758. typeof f.yy === 'number' &&
  759. !(blacklistedFoods[`${f.xx}_${f.yy}`] && now < blacklistedFoods[`${f.xx}_${f.yy}`])
  760. );
  761. });
  762.  
  763. let target = null;
  764.  
  765. if (enemyList.length === 0) {
  766. // No nearby enemies (safe mode): target food with highest value (size + grouping)
  767. target = chooseBestFood(availableFoods);
  768. } else {
  769. // Separate enemies by distance
  770. const enemiesWithin300 = enemyList.filter(e => e.distance < 300);
  771. const enemiesBetween300And700 = enemyList.filter(e => e.distance >= 300 && e.distance <= 700);
  772. // Case 3: If there are one or more enemies in the <300 range, run away
  773. if (enemiesWithin300.length > 0) {
  774. let totalWeight = 0;
  775. let avgX = 0;
  776. let avgY = 0;
  777.  
  778. enemiesWithin300.forEach(e => {
  779. const weight = 1 / (e.distance + 1e-5); // Closer = more weight
  780. const normX = e.dx / e.distance;
  781. const normY = e.dy / e.distance;
  782. avgX += normX * weight;
  783. avgY += normY * weight;
  784. totalWeight += weight;
  785. });
  786.  
  787. if (totalWeight > 0) {
  788. avgX /= totalWeight;
  789. avgY /= totalWeight;
  790. }
  791.  
  792. const scale = 150;
  793. const runAwayX = self.xx - avgX * scale;
  794. const runAwayY = self.yy - avgY * scale;
  795. moveMouseToward(runAwayX, runAwayY);
  796. targetFood = null;
  797. return;
  798. }
  799.  
  800. // Case 2: No critical enemies (<300) but at least one between 300 and 700
  801. if (enemiesBetween300And700.length > 0) {
  802. enemiesBetween300And700.sort((a, b) => a.distance - b.distance);
  803. const closest = enemiesBetween300And700[0];
  804. // Calculate opposite vector from enemy body point
  805. const vecX = self.xx - closest.point.xx;
  806. const vecY = self.yy - closest.point.yy;
  807. const vecLength = Math.sqrt(vecX * vecX + vecY * vecY);
  808. const normX = vecLength ? vecX / vecLength : 0;
  809. const normY = vecLength ? vecY / vecLength : 0;
  810. // Only keep foods in the opposite direction
  811. const filteredFoods = availableFoods.filter(f => {
  812. const foodVecX = f.xx - self.xx;
  813. const foodVecY = f.yy - self.yy;
  814. const dot = foodVecX * normX + foodVecY * normY;
  815. return dot > 0;
  816. });
  817. target = filteredFoods.length ? chooseBestFood(filteredFoods) : chooseBestFood(availableFoods);
  818. } else {
  819. // Case 1: All enemies are beyond 700: choose nearest food
  820. target = chooseBestFood(availableFoods);
  821. }
  822. }
  823.  
  824. // Blacklist mechanism if the same target is aimed at for more than 2 seconds
  825. if (
  826. target &&
  827. targetFood &&
  828. target.xx === targetFood.xx &&
  829. target.yy === targetFood.yy
  830. ) {
  831. if (now - targetFoodTimestamp >= 2000) {
  832. const key = `${targetFood.xx}_${targetFood.yy}`;
  833. blacklistedFoods[key] = now + 2000;
  834. const alternatives = availableFoods.filter(
  835. f => !(f.xx === targetFood.xx && f.yy === targetFood.yy)
  836. );
  837. if (alternatives.length > 0) {
  838. target = chooseBestFood(alternatives);
  839. targetFoodTimestamp = now;
  840. } else {
  841. target = null;
  842. }
  843. }
  844. } else {
  845. targetFoodTimestamp = now;
  846. }
  847.  
  848. if (target) {
  849. moveMouseToward(target.xx, target.yy);
  850. targetFood = target;
  851. }
  852. }
  853. }
  854.  
  855. // Start FoodBot by launching the setInterval
  856. function startFoodBot() {
  857. if (!foodBotInterval) {
  858. foodBotInterval = setInterval(foodBotUpdate, 20);
  859. }
  860. }
  861.  
  862. // Stop FoodBot
  863. function stopFoodBot() {
  864. if (foodBotInterval) {
  865. clearInterval(foodBotInterval);
  866. foodBotInterval = null;
  867. }
  868. }
  869.  
  870. // On startup, if bot is enabled, launch FoodBot
  871. if (IsBotActive) {
  872. startFoodBot();
  873.  
  874. // Initialise Zoom overlay
  875. window.recursiveZoomUpdate();
  876. }
  877.  
  878. // Modifier le gestionnaire d'événements de touches pour ajouter les commandes de zoom
  879. document.addEventListener('keydown', (e) => {
  880. // Here we use the "t" key to toggle the bot (you can modify according to your needs)
  881. if (e.key.toLowerCase() === 't') {
  882. IsBotActive = !IsBotActive;
  883. if (IsBotActive) {
  884. startFoodBot();
  885. } else {
  886. stopFoodBot();
  887. }
  888. }
  889.  
  890. // Ajout des touches pour le zoom
  891. if (e.key.toLowerCase() === 'a') {
  892. window.adjustZoom(0.1);
  893. } else if (e.key.toLowerCase() === 'e') {
  894. window.adjustZoom(-0.1);
  895. } else if (e.key.toLowerCase() === 'z') {
  896. window.resetZoom();
  897. }
  898. });
  899. });
  900. })();