Slither Full Auto Bot (Responsive Overlay)

Slither.com/io Bot with improved overlay and comments

目前為 2025-03-27 提交的版本,檢視 最新版本

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

QingJ © 2025

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