[NEWEST] #1 🏆 Chess.com Cheat/Bot!

Chess.com Bot/Cheat that finds the best move!

  1. // ==UserScript==
  2. // @name [NEWEST] #1 🏆 Chess.com Cheat/Bot!
  3. // @namespace Admin0
  4. // @version 2.0.0
  5. // @description Chess.com Bot/Cheat that finds the best move!
  6. // @author Admin0
  7. // @license Chess.com Bot/Cheat © 2024 by Admin0, © All Rights Reserved
  8. // @match https://www.chess.com/play/*
  9. // @match https://www.chess.com/game/*
  10. // @match https://www.chess.com/puzzles/*
  11. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_xmlhttpRequest
  15. // @grant GM_getResourceText
  16. // @grant GM_registerMenuCommand
  17. // @resource stockfish.js https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/9.0.0/stockfish.js
  18. // @require https://greatest.deepsurf.us/scripts/445697/code/index.js
  19. // @require https://code.jquery.com/jquery-3.6.0.min.js
  20. // @run-at document-start
  21. // ==/UserScript==
  22.  
  23. // CLEAN REWRITE - CHESS.COM THEMED VERSION 2.0
  24.  
  25. const currentVersion = '2.0.0';
  26.  
  27. function main() {
  28. // Core variables setup
  29. var stockfishObjectURL;
  30. var engine = document.engine = {};
  31. var myVars = document.myVars = {};
  32. myVars.autoMove = GM_getValue('autoMove', false); // Load saved autoMove
  33. myVars.suggestMove = GM_getValue('suggestMove', false); // Load saved suggestMove
  34. myVars.autoMatch = GM_getValue('autoMatch', false); // Load saved autoMatch
  35. myVars.customDepth = GM_getValue('customDepth', 11); // Load saved depth, default to 11
  36. myVars.bestMoveHighlightColor = GM_getValue('bestMoveHighlightColor', '#7fa650'); // Chess.com green
  37. myVars.panelPosition = GM_getValue('panelPositionType', 'draggable'); // Position type: 'right' or 'draggable'
  38. var myFunctions = document.myFunctions = {};
  39. var lastValue = GM_getValue('customDepth', 11); // Also initialize lastValue with saved/default depth
  40.  
  41. // Core chess engine logic from Script3 (the working one)
  42. // Track active highlights to prevent stacking
  43. myVars.activeHighlights = [];
  44.  
  45. myFunctions.color = function(dat) {
  46. console.log("[Move] Processing:", dat);
  47. console.log("[Highlight] Attempting highlight on board element:", board ? board.nodeName : 'Board not found!'); // Diagnostic log
  48. let response = dat;
  49. let res1 = response.substring(0, 2); // From square
  50. let res2 = response.substring(2, 4); // To square
  51.  
  52. // Execute move if auto-move is enabled
  53. if (myVars.autoMove === true) {
  54. myFunctions.movePiece(res1, res2);
  55. }
  56.  
  57. // Reset thinking state
  58. isThinking = false;
  59.  
  60. // Convert chess notation to Chess.com's grid system
  61. res1 = res1.replace(/^a/, "1")
  62. .replace(/^b/, "2")
  63. .replace(/^c/, "3")
  64. .replace(/^d/, "4")
  65. .replace(/^e/, "5")
  66. .replace(/^f/, "6")
  67. .replace(/^g/, "7")
  68. .replace(/^h/, "8");
  69. res2 = res2.replace(/^a/, "1")
  70. .replace(/^b/, "2")
  71. .replace(/^c/, "3")
  72. .replace(/^d/, "4")
  73. .replace(/^e/, "5")
  74. .replace(/^f/, "6")
  75. .replace(/^g/, "7")
  76. .replace(/^h/, "8");
  77.  
  78. // Clear any existing highlights to prevent stacking
  79. myFunctions.clearHighlights();
  80.  
  81. // Highlight destination square with improved styling
  82. const destHighlight = $('<div class="highlight square-' + res2 + ' bro" style="background-color: ' + myVars.bestMoveHighlightColor + '; opacity: 0; border-radius: 5px; box-shadow: inset 0 0 5px rgba(255,255,255,0.5); data-test-element="highlight"></div>');
  83. $(board.nodeName).prepend(destHighlight);
  84. myVars.activeHighlights.push(destHighlight);
  85.  
  86. // Animate the destination highlight
  87. destHighlight.animate({
  88. opacity: 0.7
  89. }, 300);
  90.  
  91. // Highlight origin square with improved styling
  92. const originHighlight = $('<div class="highlight square-' + res1 + ' bro" style="background-color: ' + myVars.bestMoveHighlightColor + '; opacity: 0; border-radius: 5px; box-shadow: inset 0 0 5px rgba(255,255,255,0.5); data-test-element="highlight"></div>');
  93. $(board.nodeName).prepend(originHighlight);
  94. myVars.activeHighlights.push(originHighlight);
  95.  
  96. // Animate the origin highlight
  97. originHighlight.animate({
  98. opacity: 0.7
  99. }, 300);
  100.  
  101. // Set timeout to clear highlights after delay
  102. setTimeout(function() {
  103. myFunctions.clearHighlights();
  104. }, 1800);
  105. };
  106.  
  107. // Function to clear all active highlights with fade-out animation
  108. myFunctions.clearHighlights = function() {
  109. if (myVars.activeHighlights && myVars.activeHighlights.length > 0) {
  110. myVars.activeHighlights.forEach(function(highlight) {
  111. // Animate fade out
  112. highlight.animate({
  113. opacity: 0
  114. }, 300, function() {
  115. // Remove after animation completes
  116. $(this).remove();
  117. });
  118. });
  119. myVars.activeHighlights = [];
  120. }
  121. // Also fade out and remove any other highlights that might be present
  122. $('.highlight.bro').animate({
  123. opacity: 0
  124. }, 300, function() {
  125. $(this).remove();
  126. });
  127. };
  128.  
  129. // Move execution function from Script3
  130. myFunctions.movePiece = function(from, to) {
  131. console.log("[Move] Executing move from", from, "to", to);
  132. try {
  133. // Get legal moves from the game
  134. let legalMoves = board.game.getLegalMoves();
  135.  
  136. // Find our move in legal moves
  137. for (let each = 0; each < legalMoves.length; each++) {
  138. if (legalMoves[each].from === from && legalMoves[each].to === to) {
  139. let move = legalMoves[each];
  140.  
  141. // Check for promotion (pawn to last rank)
  142. let promotion = undefined;
  143. let piece = board.game.getPiece(from);
  144. if (piece && piece.type === 'p' && (to[1] === '8' || to[1] === '1')) {
  145. promotion = 'q'; // Default promote to queen
  146. console.log("[Move] Promoting pawn to queen");
  147. }
  148.  
  149. // Execute the move
  150. board.game.move({
  151. from: move.from,
  152. to: move.to,
  153. promotion: promotion,
  154. animate: false,
  155. userGenerated: true
  156. });
  157. console.log("[Move] Executed successfully");
  158. return;
  159. }
  160. }
  161. console.warn("[Move] No legal move found:", from, to);
  162. } catch (error) {
  163. console.error("[Move] Error executing move:", error);
  164. }
  165. };
  166.  
  167. // Enhanced parser to capture top moves
  168. function parser(e) {
  169. console.log("[Engine] Message:", e.data);
  170.  
  171. // Track top moves during analysis
  172. if (e.data.includes('info depth') && e.data.includes('pv')) {
  173. try {
  174. // Extract move data from engine output
  175. const parts = e.data.split(' ');
  176. const depthIndex = parts.indexOf('depth');
  177. const scoreIndex = parts.indexOf('score');
  178. const pvIndex = parts.indexOf('pv');
  179.  
  180. if (depthIndex >= 0 && scoreIndex >= 0 && pvIndex >= 0) {
  181. const depth = parseInt(parts[depthIndex + 1]);
  182. const scoreType = parts[scoreIndex + 1]; // cp or mate
  183. const scoreValue = parseInt(parts[scoreIndex + 2]);
  184. const move = parts[pvIndex + 1];
  185.  
  186. // Format evaluation text
  187. let evalText = '';
  188. if (scoreType === 'cp') {
  189. // Convert centipawns to pawns with + or - sign
  190. const pawns = (scoreValue / 100).toFixed(2);
  191. evalText = (pawns > 0 ? '+' : '') + pawns;
  192. } else if (scoreType === 'mate') {
  193. // Show mate in X
  194. evalText = 'M' + (scoreValue > 0 ? '+' : '') + scoreValue;
  195. }
  196.  
  197. // Store in top moves array if this is a new depth
  198. if (!myVars.topMoves) {
  199. myVars.topMoves = [];
  200. }
  201.  
  202. // Add to top moves if it's a new depth or replace existing entry
  203. const existingIndex = myVars.topMoves.findIndex(m => m.move === move);
  204. if (existingIndex >= 0) {
  205. // Update existing move with new evaluation
  206. myVars.topMoves[existingIndex] = { move, evalText, depth, score: scoreValue };
  207. } else {
  208. // Add new move
  209. myVars.topMoves.push({ move, evalText, depth, score: scoreValue });
  210. }
  211.  
  212. // Sort by score (higher is better)
  213. myVars.topMoves.sort((a, b) => b.score - a.score);
  214.  
  215. // Keep only top 2 moves
  216. myVars.topMoves = myVars.topMoves.slice(0, 2);
  217.  
  218. // Update UI if elements exist
  219. if (document.getElementById('topMove1') && myVars.topMoves.length > 0) {
  220. for (let i = 0; i < Math.min(2, myVars.topMoves.length); i++) {
  221. const moveElem = document.getElementById(`topMove${i+1}`);
  222. const evalElem = document.getElementById(`topMoveEval${i+1}`);
  223.  
  224. if (moveElem && evalElem) {
  225. moveElem.innerText = myVars.topMoves[i].move;
  226. evalElem.innerText = myVars.topMoves[i].evalText;
  227. }
  228. }
  229. }
  230. }
  231. } catch (error) {
  232. console.error("[Engine] Error parsing move info:", error);
  233. }
  234. }
  235.  
  236. // Process best move when analysis is complete
  237. if (e.data.includes('bestmove')) {
  238. console.log("[Engine] Found best move:", e.data);
  239. const bestMove = e.data.split(' ')[1];
  240. myFunctions.color(bestMove);
  241. isThinking = false;
  242.  
  243. // Clear top moves array for next analysis
  244. myVars.topMoves = [];
  245. }
  246. }
  247.  
  248. // Engine load function from Script3
  249. myFunctions.loadChessEngine = function() {
  250. console.log("[Engine] Loading Stockfish...");
  251. try {
  252. if (!stockfishObjectURL) {
  253. stockfishObjectURL = URL.createObjectURL(new Blob([GM_getResourceText('stockfish.js')], {type: 'application/javascript'}));
  254. }
  255.  
  256. engine.engine = new Worker(stockfishObjectURL);
  257.  
  258. engine.engine.onmessage = e => {
  259. parser(e);
  260. };
  261.  
  262. engine.engine.onerror = e => {
  263. console.error("[Engine] Error:", e);
  264. isThinking = false;
  265. };
  266.  
  267. engine.engine.postMessage('ucinewgame');
  268. console.log("[Engine] Loaded successfully");
  269. } catch (error) {
  270. console.error("[Engine] Load failed:", error);
  271. }
  272. };
  273.  
  274. // Engine reload function
  275. myFunctions.reloadChessEngine = function() {
  276. console.log("[Engine] Reloading...");
  277. try {
  278. if (engine.engine) {
  279. engine.engine.terminate();
  280. }
  281. isThinking = false;
  282. stockfishObjectURL = null; // Force recreation
  283. setTimeout(() => {
  284. myFunctions.loadChessEngine();
  285. console.log("[Engine] Reloaded successfully");
  286. }, 100);
  287. } catch (error) {
  288. console.error("[Engine] Reload failed:", error);
  289. }
  290. };
  291.  
  292. // Run engine at specified depth
  293. myFunctions.runChessEngine = function(depth) {
  294. console.log("[Engine] Running at depth", depth);
  295. let fen = board.game.getFEN();
  296. console.log("[Engine] Position:", fen);
  297.  
  298. engine.engine.postMessage(`position fen ${fen}`);
  299. isThinking = true;
  300. engine.engine.postMessage(`go depth ${depth}`);
  301. lastValue = depth;
  302. };
  303.  
  304. // Auto run function
  305. myFunctions.autoRun = function(depth) {
  306. if (board.game.getTurn() == board.game.getPlayingAs()) {
  307. myFunctions.runChessEngine(depth || myVars.customDepth);
  308. }
  309. };
  310.  
  311. // Function to handle delayed auto-run
  312. function other(delay) {
  313. let endTime = Date.now() + delay;
  314. let timer = setInterval(() => {
  315. if (Date.now() >= endTime) {
  316. myFunctions.autoRun(myVars.customDepth);
  317. canGo = true;
  318. clearInterval(timer);
  319. }
  320. }, 10);
  321. }
  322.  
  323. // Auto start new game
  324. myFunctions.startNewGame = function() {
  325. console.log("[Match] Starting new game...");
  326.  
  327. // Find New Game button in different places
  328. const modalNewGameButton = $('.game-over-modal-content .game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])');
  329. if (modalNewGameButton.length) {
  330. modalNewGameButton[0].click();
  331. console.log("[Match] Clicked New Game from modal");
  332. myVars.hasAutoMatched = true;
  333. myVars.gameEnded = false;
  334. return;
  335. }
  336.  
  337. const newGameButton = $('.game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])');
  338. if (newGameButton.length) {
  339. newGameButton[0].click();
  340. console.log("[Match] Clicked New Game button");
  341. myVars.hasAutoMatched = true;
  342. myVars.gameEnded = false;
  343. return;
  344. }
  345.  
  346. console.log("[Match] No New Game button found");
  347. };
  348.  
  349. // Function to handle spinner visibility
  350. myFunctions.spinner = function() {
  351. if (loaded && $('#overlay').length) {
  352. $('#overlay').css('display', isThinking ? 'block' : 'none');
  353. }
  354. };
  355.  
  356. // Handle keyboard shortcuts
  357. document.onkeydown = function(e) {
  358. const depthKeys = {
  359. 81: 1, 87: 2, 69: 3, 82: 4, 84: 5, 89: 6, 85: 7, 73: 8, 79: 9, 80: 10,
  360. 65: 11, 83: 12, 68: 13, 70: 14, 71: 15, 72: 16, 74: 17, 75: 18, 76: 19,
  361. 90: 20, 88: 21, 67: 22, 86: 23, 66: 24, 78: 25, 77: 26, 187: 100
  362. };
  363.  
  364. if (depthKeys[e.keyCode]) {
  365. myVars.customDepth = depthKeys[e.keyCode];
  366. if (loaded) {
  367. $('#depthValue').text(myVars.customDepth);
  368. }
  369. GM_setValue('customDepth', myVars.customDepth); // Save the new depth
  370. location.reload(); // Reload the page
  371. }
  372.  
  373. // Toggle UI with ESC
  374. if (e.keyCode === 27 && loaded) {
  375. $('#chessBot').toggle();
  376. }
  377. };
  378.  
  379. // UI Creation function - CHESS.COM THEMED
  380. var loaded = false;
  381. myFunctions.loadEx = function() {
  382. if (loaded) return;
  383.  
  384. try {
  385. console.log("[UI] Creating Chess.com themed interface...");
  386. board = $('chess-board')[0] || $('wc-chess-board')[0];
  387. if (!board) {
  388. console.warn("[UI] Board not found yet");
  389. return;
  390. }
  391.  
  392. myVars.board = board;
  393.  
  394. // Create main container with Chess.com styling
  395. const panel = document.createElement('div');
  396. panel.id = 'chessBot';
  397. // Load saved panel dimensions or use defaults
  398. const savedDimensions = GM_getValue('panelDimensions', {
  399. width: 220,
  400. height: 400,
  401. minWidth: 180,
  402. minHeight: 300
  403. });
  404.  
  405. // Get panel position type
  406. const positionType = myVars.panelPosition; // 'right', 'bottom', or 'draggable'
  407.  
  408. // Set initial position and dimensions based on position type
  409. let positionCSS = '';
  410. let dimensionsCSS = '';
  411.  
  412. if (positionType === 'right') {
  413. // Right mode: Full height on right side
  414. positionCSS = `
  415. right: 20px;
  416. top: 20px;
  417. bottom: 20px;
  418. transform: none;
  419. `;
  420. dimensionsCSS = `
  421. width: 280px;
  422. height: auto;
  423. overflow-y: auto;
  424. `;
  425. } else { // draggable (default)
  426. // Get saved position for draggable mode
  427. const savedPosition = GM_getValue('panelPosition', {
  428. top: 100,
  429. left: window.innerWidth - savedDimensions.width - 20,
  430. right: 'auto'
  431. });
  432.  
  433. positionCSS = `
  434. right: ${savedPosition.right};
  435. top: ${savedPosition.top}px;
  436. left: ${savedPosition.left}px;
  437. transform: none;
  438. `;
  439. dimensionsCSS = `
  440. width: ${savedDimensions.width}px;
  441. height: ${savedDimensions.height}px;
  442. `;
  443. }
  444.  
  445. // If position type is invalid, default to draggable
  446. if (positionType !== 'right' && positionType !== 'draggable') {
  447. myVars.panelPosition = 'draggable';
  448. GM_setValue('panelPositionType', 'draggable');
  449. }
  450.  
  451. panel.style = `
  452. position: fixed;
  453. ${positionCSS}
  454. ${dimensionsCSS}
  455. min-width: ${positionType === 'bottom' ? 'auto' : savedDimensions.minWidth + 'px'};
  456. min-height: ${positionType === 'right' ? 'auto' : savedDimensions.minHeight + 'px'};
  457. background-color: #312e2b;
  458. color: #bababa;
  459. font-family: "Segoe UI", Arial, sans-serif;
  460. z-index: 9999;
  461. padding: 15px;
  462. border-radius: 8px;
  463. box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
  464. font-size: 14px;
  465. display: flex;
  466. flex-direction: column;
  467. overflow: hidden;
  468. `;
  469.  
  470. // Create header
  471. const header = document.createElement('div');
  472. header.style = `
  473. display: flex;
  474. justify-content: space-between;
  475. align-items: center;
  476. margin-bottom: 15px;
  477. border-bottom: 1px solid #464442;
  478. padding-bottom: 10px;
  479. `;
  480.  
  481. const title = document.createElement('h2');
  482. title.innerText = 'Chess.com Bot';
  483. title.style = `
  484. margin: 0;
  485. font-size: 18px;
  486. font-weight: 600;
  487. color: #bababa;
  488. `;
  489.  
  490. const version = document.createElement('span');
  491. version.innerText = 'v2.0.0';
  492. version.style = `
  493. font-size: 12px;
  494. opacity: 0.8;
  495. color: #bababa;
  496. `;
  497.  
  498. // Create a container for title and version
  499. const titleContainer = document.createElement('div');
  500. titleContainer.style = `
  501. display: flex;
  502. align-items: baseline;
  503. gap: 8px;
  504. `;
  505.  
  506. titleContainer.appendChild(title);
  507. titleContainer.appendChild(version);
  508.  
  509. // Add title container to the left side of header
  510. header.appendChild(titleContainer);
  511. panel.appendChild(header);
  512.  
  513. // Create spinner overlay
  514. const overlay = document.createElement('div');
  515. overlay.id = 'overlay';
  516. overlay.style = `
  517. position: absolute;
  518. top: 0;
  519. left: 0;
  520. right: 0;
  521. bottom: 0;
  522. background-color: rgba(49, 46, 43, 0.85);
  523. z-index: 10000;
  524. display: none;
  525. border-radius: 5px;
  526. `;
  527.  
  528. const spinner = document.createElement('div');
  529. spinner.style = `
  530. position: absolute;
  531. top: 50%;
  532. left: 50%;
  533. width: 40px;
  534. height: 40px;
  535. margin-top: -20px;
  536. margin-left: -20px;
  537. border: 3px solid #bababa;
  538. border-top-color: #7fa650;
  539. border-radius: 50%;
  540. animation: spin 1s infinite linear;
  541. `;
  542.  
  543. const spinStyle = document.createElement('style');
  544. spinStyle.textContent = `
  545. @keyframes spin {
  546. 0% { transform: rotate(0deg); }
  547. 100% { transform: rotate(360deg); }
  548. }
  549. `;
  550.  
  551. document.head.appendChild(spinStyle);
  552. overlay.appendChild(spinner);
  553. panel.appendChild(overlay);
  554.  
  555. // Create scrollable content container
  556. const scrollContainer = document.createElement('div');
  557. scrollContainer.className = 'scroll-container';
  558. scrollContainer.style = `
  559. flex: 1;
  560. overflow-y: auto;
  561. overflow-x: hidden;
  562. padding-right: 5px; /* Add space for scrollbar */
  563. margin-right: -5px; /* Compensate for padding */
  564. scrollbar-width: thin; /* Firefox */
  565. scrollbar-color: #464442 #312e2b; /* Firefox */
  566. `;
  567.  
  568. // Add custom scrollbar styles
  569. const scrollbarStyle = document.createElement('style');
  570. scrollbarStyle.textContent = `
  571. .scroll-container::-webkit-scrollbar {
  572. width: 6px;
  573. }
  574. .scroll-container::-webkit-scrollbar-track {
  575. background: #312e2b;
  576. }
  577. .scroll-container::-webkit-scrollbar-thumb {
  578. background-color: #464442;
  579. border-radius: 3px;
  580. }
  581. .scroll-container::-webkit-scrollbar-thumb:hover {
  582. background-color: #5d5955;
  583. }
  584. `;
  585. document.head.appendChild(scrollbarStyle);
  586.  
  587. panel.appendChild(scrollContainer);
  588.  
  589. // Create collapsible content sections
  590. const createSection = (title) => {
  591. const section = document.createElement('div');
  592. section.className = 'collapsible-section';
  593. section.style = `
  594. margin-bottom: 15px;
  595. `;
  596.  
  597. const sectionHeader = document.createElement('div');
  598. sectionHeader.className = 'section-header';
  599. sectionHeader.style = `
  600. display: flex;
  601. justify-content: space-between;
  602. align-items: center;
  603. cursor: pointer;
  604. border-bottom: 1px solid #464442;
  605. padding-bottom: 5px;
  606. user-select: none;
  607. `;
  608.  
  609. const sectionTitle = document.createElement('h3');
  610. sectionTitle.innerText = title;
  611. sectionTitle.style = `
  612. margin: 0;
  613. font-size: 16px;
  614. color: #bababa;
  615. `;
  616.  
  617. const collapseIcon = document.createElement('span');
  618. collapseIcon.className = 'collapse-icon';
  619. collapseIcon.innerHTML = '▼'; // Down arrow for expanded
  620. collapseIcon.style = `
  621. font-size: 12px;
  622. color: #bababa;
  623. transition: transform 0.3s;
  624. `;
  625.  
  626. sectionHeader.appendChild(sectionTitle);
  627. sectionHeader.appendChild(collapseIcon);
  628.  
  629. const sectionContent = document.createElement('div');
  630. sectionContent.className = 'section-content';
  631. sectionContent.style = `
  632. margin-top: 10px;
  633. overflow: hidden;
  634. transition: max-height 0.3s ease-out, opacity 0.3s ease-out;
  635. max-height: 1000px; /* Start expanded */
  636. opacity: 1;
  637. visibility: visible;
  638. `;
  639.  
  640. // Toggle collapse on header click with improved animation
  641. sectionHeader.addEventListener('click', function() {
  642. const isCollapsed = sectionContent.style.maxHeight === '0px' || !sectionContent.style.maxHeight;
  643.  
  644. if (isCollapsed) {
  645. // Expand - use scrollHeight to determine the actual height needed
  646. sectionContent.style.maxHeight = sectionContent.scrollHeight + 'px';
  647. sectionContent.style.opacity = '1';
  648. sectionContent.style.visibility = 'visible';
  649. collapseIcon.innerHTML = '▼';
  650. collapseIcon.style.transform = 'rotate(0deg)';
  651.  
  652. // Update maxHeight after content changes (for dynamic content)
  653. setTimeout(() => {
  654. sectionContent.style.maxHeight = sectionContent.scrollHeight + 'px';
  655. }, 50);
  656. } else {
  657. // Collapse with smooth animation
  658. sectionContent.style.maxHeight = '0px';
  659. sectionContent.style.opacity = '0';
  660. // Don't hide immediately to allow animation to complete
  661. setTimeout(() => {
  662. if (sectionContent.style.maxHeight === '0px') {
  663. sectionContent.style.visibility = 'hidden';
  664. }
  665. }, 300);
  666. collapseIcon.innerHTML = '▶';
  667. collapseIcon.style.transform = 'rotate(-90deg)';
  668. }
  669.  
  670. // Save collapsed state
  671. const collapsedSections = GM_getValue('collapsedSections', {});
  672. collapsedSections[title] = !isCollapsed;
  673. GM_setValue('collapsedSections', collapsedSections);
  674. });
  675.  
  676. section.appendChild(sectionHeader);
  677. section.appendChild(sectionContent);
  678.  
  679. // Set initial collapse state from saved preferences
  680. const collapsedSections = GM_getValue('collapsedSections', {});
  681. if (collapsedSections[title]) {
  682. sectionContent.style.maxHeight = '0px';
  683. sectionContent.style.opacity = '0';
  684. sectionContent.style.visibility = 'hidden';
  685. collapseIcon.innerHTML = '▶';
  686. collapseIcon.style.transform = 'rotate(-90deg)';
  687. } else {
  688. // Make sure expanded sections have proper height
  689. setTimeout(() => {
  690. if (sectionContent.style.maxHeight !== '0px') {
  691. sectionContent.style.maxHeight = sectionContent.scrollHeight + 'px';
  692. }
  693. }, 50);
  694. }
  695.  
  696. // Return the content div instead of the section
  697. return {
  698. section: section,
  699. content: sectionContent
  700. };
  701. };
  702.  
  703. // Create depth section
  704. const depthSectionObj = createSection('Engine Depth');
  705. const depthSection = depthSectionObj.section;
  706. const depthContent = depthSectionObj.content;
  707.  
  708. const depthDisplay = document.createElement('div');
  709. depthDisplay.style = `
  710. display: flex;
  711. justify-content: space-between;
  712. align-items: center;
  713. margin-bottom: 10px;
  714. background-color: #3a3634;
  715. padding: 8px 12px;
  716. border-radius: 4px;
  717. `;
  718.  
  719. const depthLabel = document.createElement('span');
  720. depthLabel.innerText = 'Current Depth:';
  721.  
  722. const depthValue = document.createElement('span');
  723. depthValue.id = 'depthValue';
  724. depthValue.innerText = myVars.customDepth;
  725. depthValue.style = `
  726. font-weight: bold;
  727. color: #7fa650;
  728. `;
  729.  
  730. depthDisplay.appendChild(depthLabel);
  731. depthDisplay.appendChild(depthValue);
  732.  
  733. // Removed "Press A-Z keys" message
  734.  
  735. const depthInput = document.createElement('div');
  736. depthInput.style = `
  737. display: flex;
  738. align-items: center;
  739. margin-top: 10px;
  740. `;
  741.  
  742. const depthInputLabel = document.createElement('label');
  743. depthInputLabel.innerText = 'Set Depth:';
  744. depthInputLabel.style = 'margin-right: 10px;';
  745.  
  746. const depthInputField = document.createElement('input');
  747. depthInputField.type = 'number';
  748. depthInputField.id = 'customDepthInput';
  749. depthInputField.min = '1';
  750. depthInputField.max = '100';
  751. depthInputField.value = myVars.customDepth;
  752. depthInputField.style = `
  753. background-color: #3a3634;
  754. border: 1px solid #464442;
  755. color: #bababa;
  756. padding: 5px;
  757. border-radius: 3px;
  758. width: 60px;
  759. `;
  760.  
  761. depthInputField.addEventListener('change', function() {
  762. const value = parseInt(this.value);
  763. if (!isNaN(value) && value >= 1 && value <= 100) {
  764. myVars.customDepth = value;
  765. depthValue.innerText = value;
  766. GM_setValue('customDepth', myVars.customDepth); // Save the new depth
  767. location.reload(); // Reload the page
  768. } else {
  769. this.value = GM_getValue('customDepth', 11); // Reset to saved value if input is invalid
  770. }
  771. });
  772.  
  773. depthInput.appendChild(depthInputLabel);
  774. depthInput.appendChild(depthInputField);
  775.  
  776. depthContent.appendChild(depthDisplay);
  777. depthContent.appendChild(depthInput);
  778. scrollContainer.appendChild(depthSection);
  779.  
  780. // Create game options section
  781. const optionsSectionObj = createSection('Game Options');
  782. const optionsSection = optionsSectionObj.section;
  783. const optionsContent = optionsSectionObj.content;
  784.  
  785. const createCheckbox = (id, label) => {
  786. const container = document.createElement('div');
  787. container.style = `
  788. display: flex;
  789. align-items: center;
  790. margin-bottom: 10px;
  791. cursor: pointer;
  792. `;
  793.  
  794. const checkbox = document.createElement('input');
  795. checkbox.type = 'checkbox';
  796. checkbox.id = id;
  797. checkbox.style = `
  798. margin-right: 10px;
  799. cursor: pointer;
  800. `;
  801.  
  802. const checkLabel = document.createElement('label');
  803. checkLabel.htmlFor = id;
  804. checkLabel.innerText = label;
  805. checkLabel.style = 'cursor: pointer;';
  806.  
  807. container.appendChild(checkbox);
  808. container.appendChild(checkLabel);
  809. return container;
  810. };
  811.  
  812. const autoRunCheck = createCheckbox('suggestMove', 'Enable Suggested Move');
  813. const autoMoveCheck = createCheckbox('autoMove', 'Enable auto move');
  814. const autoMatchCheck = createCheckbox('autoMatch', 'Enable auto match');
  815.  
  816. optionsContent.appendChild(autoRunCheck);
  817. optionsContent.appendChild(autoMoveCheck);
  818. optionsContent.appendChild(autoMatchCheck);
  819. scrollContainer.appendChild(optionsSection);
  820.  
  821. // Set initial state from loaded vars
  822. autoRunCheck.querySelector('input').checked = myVars.suggestMove;
  823. autoMoveCheck.querySelector('input').checked = myVars.autoMove;
  824. autoMatchCheck.querySelector('input').checked = myVars.autoMatch;
  825.  
  826. // Create delay section
  827. const delaySectionObj = createSection('Suggestion Delay');
  828. const delaySection = delaySectionObj.section;
  829. const delayContent = delaySectionObj.content;
  830.  
  831. const createDelayInput = (id, label, defaultValue) => {
  832. const container = document.createElement('div');
  833. container.style = `
  834. display: flex;
  835. align-items: center;
  836. margin-bottom: 10px;
  837. `;
  838.  
  839. const inputLabel = document.createElement('label');
  840. inputLabel.htmlFor = id;
  841. inputLabel.innerText = label;
  842. inputLabel.style = `
  843. flex: 1;
  844. `;
  845.  
  846. const input = document.createElement('input');
  847. input.type = 'number';
  848. input.id = id;
  849. input.min = '0.1';
  850. input.step = '0.1';
  851. input.value = defaultValue;
  852. input.style = `
  853. background-color: #3a3634;
  854. border: 1px solid #464442;
  855. color: #bababa;
  856. padding: 5px;
  857. border-radius: 3px;
  858. width: 60px;
  859. `;
  860.  
  861. container.appendChild(inputLabel);
  862. container.appendChild(input);
  863. return container;
  864. };
  865.  
  866. const minDelayInput = createDelayInput('timeDelayMin', 'Min Delay (s):', '0.1');
  867. const maxDelayInput = createDelayInput('timeDelayMax', 'Max Delay (s):', '1.0');
  868.  
  869. delayContent.appendChild(minDelayInput);
  870. delayContent.appendChild(maxDelayInput);
  871. scrollContainer.appendChild(delaySection);
  872.  
  873. // Create a settings button in the header (icon button)
  874. const settingsButton = document.createElement('button');
  875. settingsButton.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" stroke="#bababa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M19.4 15C19.2669 15.3016 19.2272 15.6362 19.286 15.9606C19.3448 16.285 19.4995 16.5843 19.73 16.82L19.79 16.88C19.976 17.0657 20.1235 17.2863 20.2241 17.5291C20.3248 17.7719 20.3766 18.0322 20.3766 18.295C20.3766 18.5578 20.3248 18.8181 20.2241 19.0609C20.1235 19.3037 19.976 19.5243 19.79 19.71C19.6043 19.896 19.3837 20.0435 19.1409 20.1441C18.8981 20.2448 18.6378 20.2966 18.375 20.2966C18.1122 20.2966 17.8519 20.2448 17.6091 20.1441C17.3663 20.0435 17.1457 19.896 16.96 19.71L16.9 19.65C16.6643 19.4195 16.365 19.2648 16.0406 19.206C15.7162 19.1472 15.3816 19.1869 15.08 19.32C14.7842 19.4468 14.532 19.6572 14.3543 19.9255C14.1766 20.1938 14.0813 20.5082 14.08 20.83V21C14.08 21.5304 13.8693 22.0391 13.4942 22.4142C13.1191 22.7893 12.6104 23 12.08 23C11.5496 23 11.0409 22.7893 10.6658 22.4142C10.2907 22.0391 10.08 21.5304 10.08 21V20.91C10.0723 20.579 9.96512 20.258 9.77251 19.9887C9.5799 19.7194 9.31074 19.5143 9 19.4C8.69838 19.2669 8.36381 19.2272 8.03941 19.286C7.71502 19.3448 7.41568 19.4995 7.18 19.73L7.12 19.79C6.93425 19.976 6.71368 20.1235 6.47088 20.2241C6.22808 20.3248 5.96783 20.3766 5.705 20.3766C5.44217 20.3766 5.18192 20.3248 4.93912 20.2241C4.69632 20.1235 4.47575 19.976 4.29 19.79C4.10405 19.6043 3.95653 19.3837 3.85588 19.1409C3.75523 18.8981 3.70343 18.6378 3.70343 18.375C3.70343 18.1122 3.75523 17.8519 3.85588 17.6091C3.95653 17.3663 4.10405 17.1457 4.29 16.96L4.35 16.9C4.58054 16.6643 4.73519 16.365 4.794 16.0406C4.85282 15.7162 4.81312 15.3816 4.68 15.08C4.55324 14.7842 4.34276 14.532 4.07447 14.3543C3.80618 14.1766 3.49179 14.0813 3.17 14.08H3C2.46957 14.08 1.96086 13.8693 1.58579 13.4942C1.21071 13.1191 1 12.6104 1 12.08C1 11.5496 1.21071 11.0409 1.58579 10.6658C1.96086 10.2907 2.46957 10.08 3 10.08H3.09C3.42099 10.0723 3.742 9.96512 4.0113 9.77251C4.28059 9.5799 4.48572 9.31074 4.6 9C4.73312 8.69838 4.77282 8.36381 4.714 8.03941C4.65519 7.71502 4.50054 7.41568 4.27 7.18L4.21 7.12C4.02405 6.93425 3.87653 6.71368 3.77588 6.47088C3.67523 6.22808 3.62343 5.96783 3.62343 5.705C3.62343 5.44217 3.67523 5.18192 3.77588 4.93912C3.87653 4.69632 4.02405 4.47575 4.21 4.29C4.39575 4.10405 4.61632 3.95653 4.85912 3.85588C5.10192 3.75523 5.36217 3.70343 5.625 3.70343C5.88783 3.70343 6.14808 3.75523 6.39088 3.85588C6.63368 3.95653 6.85425 4.10405 7.04 4.29L7.1 4.35C7.33568 4.58054 7.63502 4.73519 7.95941 4.794C8.28381 4.85282 8.61838 4.81312 8.92 4.68H9C9.29577 4.55324 9.54802 4.34276 9.72569 4.07447C9.90337 3.80618 9.99872 3.49179 10 3.17V3C10 2.46957 10.2107 1.96086 10.5858 1.58579C10.9609 1.21071 11.4696 1 12 1C12.5304 1 13.0391 1.21071 13.4142 1.58579C13.7893 1.96086 14 2.46957 14 3V3.09C14.0013 3.41179 14.0966 3.72618 14.2743 3.99447C14.452 4.26276 14.7042 4.47324 15 4.6C15.3016 4.73312 15.6362 4.77282 15.9606 4.714C16.285 4.65519 16.5843 4.50054 16.82 4.27L16.88 4.21C17.0657 4.02405 17.2863 3.87653 17.5291 3.77588C17.7719 3.67523 18.0322 3.62343 18.295 3.62343C18.5578 3.62343 18.8181 3.67523 19.0609 3.77588C19.3037 3.87653 19.5243 4.02405 19.71 4.21C19.896 4.39575 20.0435 4.61632 20.1441 4.85912C20.2448 5.10192 20.2966 5.36217 20.2966 5.625C20.2966 5.88783 20.2448 6.14808 20.1441 6.39088C20.0435 6.63368 19.896 6.85425 19.71 7.04L19.65 7.1C19.4195 7.33568 19.2648 7.63502 19.206 7.95941C19.1472 8.28381 19.1869 8.61838 19.32 8.92V9C19.4468 9.29577 19.6572 9.54802 19.9255 9.72569C20.1938 9.90337 20.5082 9.99872 20.83 10H21C21.5304 10 22.0391 10.2107 22.4142 10.5858C22.7893 10.9609 23 11.4696 23 12C23 12.5304 22.7893 13.0391 22.4142 13.4142C22.0391 13.7893 21.5304 14 21 14H20.91C20.5882 14.0013 20.2738 14.0966 20.0055 14.2743C19.7372 14.452 19.5268 14.7042 19.4 15Z" stroke="#bababa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
  876. settingsButton.title = 'Settings';
  877. settingsButton.style = `
  878. background: #3a3634;
  879. border: 1px solid #464442;
  880. color: #bababa;
  881. width: 28px;
  882. height: 28px;
  883. cursor: pointer;
  884. margin-right: 10px;
  885. border-radius: 3px;
  886. display: flex;
  887. align-items: center;
  888. justify-content: center;
  889. padding: 0;
  890. `;
  891.  
  892. // Create settings screen (initially hidden)
  893. const settingsScreen = document.createElement('div');
  894. settingsScreen.id = 'chessBot-settings';
  895. settingsScreen.style = `
  896. position: fixed;
  897. top: 0;
  898. left: 0;
  899. right: 0;
  900. bottom: 0;
  901. background-color: rgba(0, 0, 0, 0.7);
  902. z-index: 10000;
  903. display: none;
  904. `;
  905.  
  906. // Settings panel
  907. const settingsPanel = document.createElement('div');
  908. settingsPanel.style = `
  909. position: absolute;
  910. top: 50%;
  911. left: 50%;
  912. transform: translate(-50%, -50%);
  913. background-color: #312e2b;
  914. width: 300px;
  915. border-radius: 5px;
  916. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
  917. padding: 15px;
  918. color: #bababa;
  919. font-family: "Segoe UI", Arial, sans-serif;
  920. `;
  921.  
  922. // Settings title
  923. const settingsTitle = document.createElement('div');
  924. settingsTitle.innerText = 'Settings';
  925. settingsTitle.style = `
  926. font-size: 16px;
  927. font-weight: bold;
  928. margin-bottom: 15px;
  929. padding-bottom: 10px;
  930. border-bottom: 1px solid #464442;
  931. color: #bababa;
  932. `;
  933. settingsPanel.appendChild(settingsTitle);
  934.  
  935. // Panel position settings
  936. const positionTitle = document.createElement('div');
  937. positionTitle.innerText = 'Panel Position';
  938. positionTitle.style = `
  939. font-weight: bold;
  940. margin-bottom: 10px;
  941. color: #bababa;
  942. `;
  943. settingsPanel.appendChild(positionTitle);
  944.  
  945. // Position radio buttons
  946. const positionContainer = document.createElement('div');
  947. positionContainer.style = `
  948. margin-bottom: 20px;
  949. `;
  950.  
  951. // Draggable option
  952. const draggableContainer = document.createElement('div');
  953. draggableContainer.style = `
  954. display: flex;
  955. align-items: center;
  956. margin-bottom: 8px;
  957. `;
  958.  
  959. const draggableRadio = document.createElement('input');
  960. draggableRadio.type = 'radio';
  961. draggableRadio.id = 'positionDraggable';
  962. draggableRadio.name = 'panelPosition';
  963. draggableRadio.value = 'draggable';
  964. draggableRadio.checked = myVars.panelPosition === 'draggable';
  965. draggableRadio.style.marginRight = '8px';
  966.  
  967. const draggableLabel = document.createElement('label');
  968. draggableLabel.htmlFor = 'positionDraggable';
  969. draggableLabel.innerText = 'Draggable (Move Freely)';
  970. draggableLabel.style.color = '#bababa';
  971.  
  972. draggableContainer.appendChild(draggableRadio);
  973. draggableContainer.appendChild(draggableLabel);
  974. positionContainer.appendChild(draggableContainer);
  975.  
  976. // Right option
  977. const rightContainer = document.createElement('div');
  978. rightContainer.style = `
  979. display: flex;
  980. align-items: center;
  981. `;
  982.  
  983. const rightRadio = document.createElement('input');
  984. rightRadio.type = 'radio';
  985. rightRadio.id = 'positionRight';
  986. rightRadio.name = 'panelPosition';
  987. rightRadio.value = 'right';
  988. rightRadio.checked = myVars.panelPosition === 'right';
  989. rightRadio.style.marginRight = '8px';
  990.  
  991. const rightLabel = document.createElement('label');
  992. rightLabel.htmlFor = 'positionRight';
  993. rightLabel.innerText = 'Right Side';
  994. rightLabel.style.color = '#bababa';
  995.  
  996. rightContainer.appendChild(rightRadio);
  997. rightContainer.appendChild(rightLabel);
  998. positionContainer.appendChild(rightContainer);
  999.  
  1000. // Add position container to panel
  1001. settingsPanel.appendChild(positionContainer);
  1002.  
  1003. // Highlight color settings
  1004. const colorTitle = document.createElement('div');
  1005. colorTitle.innerText = 'Highlight Color';
  1006. colorTitle.style = `
  1007. font-weight: bold;
  1008. margin-bottom: 10px;
  1009. color: #bababa;
  1010. `;
  1011. settingsPanel.appendChild(colorTitle);
  1012.  
  1013. // Color picker with improved UI
  1014. const colorContainer = document.createElement('div');
  1015. colorContainer.style = `
  1016. display: flex;
  1017. flex-direction: column;
  1018. margin-bottom: 20px;
  1019. `;
  1020.  
  1021. // Color presets
  1022. const presetColors = ['#7fa650', '#f1c40f', '#e74c3c', '#3498db', '#9b59b6'];
  1023. const presetContainer = document.createElement('div');
  1024. presetContainer.style = `
  1025. display: flex;
  1026. margin-bottom: 10px;
  1027. gap: 8px;
  1028. `;
  1029.  
  1030. presetColors.forEach(color => {
  1031. const preset = document.createElement('div');
  1032. preset.style = `
  1033. width: 24px;
  1034. height: 24px;
  1035. background-color: ${color};
  1036. border-radius: 4px;
  1037. cursor: pointer;
  1038. border: 2px solid ${color === myVars.bestMoveHighlightColor ? '#bababa' : 'transparent'};
  1039. `;
  1040. preset.addEventListener('click', function() {
  1041. colorInput.value = color;
  1042. colorValue.innerText = color;
  1043. myVars.bestMoveHighlightColor = color;
  1044.  
  1045. // Update borders
  1046. presetContainer.querySelectorAll('div').forEach(el => {
  1047. el.style.border = '2px solid transparent';
  1048. });
  1049. preset.style.border = '2px solid #bababa';
  1050. });
  1051. presetContainer.appendChild(preset);
  1052. });
  1053.  
  1054. colorContainer.appendChild(presetContainer);
  1055.  
  1056. // Custom color picker
  1057. const customColorContainer = document.createElement('div');
  1058. customColorContainer.style = `
  1059. display: flex;
  1060. align-items: center;
  1061. `;
  1062.  
  1063. const colorInput = document.createElement('input');
  1064. colorInput.type = 'color';
  1065. colorInput.value = myVars.bestMoveHighlightColor;
  1066. colorInput.style = `
  1067. width: 30px;
  1068. height: 30px;
  1069. margin-right: 10px;
  1070. padding: 0;
  1071. border: none;
  1072. cursor: pointer;
  1073. `;
  1074.  
  1075. const colorValue = document.createElement('span');
  1076. colorValue.innerText = myVars.bestMoveHighlightColor;
  1077. colorValue.style = `
  1078. font-family: monospace;
  1079. color: #bababa;
  1080. `;
  1081.  
  1082. customColorContainer.appendChild(colorInput);
  1083. customColorContainer.appendChild(colorValue);
  1084. colorContainer.appendChild(customColorContainer);
  1085.  
  1086. settingsPanel.appendChild(colorContainer);
  1087.  
  1088. // Save and close buttons
  1089. const buttonContainer = document.createElement('div');
  1090. buttonContainer.style = `
  1091. display: flex;
  1092. justify-content: space-between;
  1093. margin-top: 10px;
  1094. `;
  1095.  
  1096. const saveButton = document.createElement('button');
  1097. saveButton.innerText = 'Save';
  1098. saveButton.style = `
  1099. background: #7fa650;
  1100. border: none;
  1101. color: white;
  1102. padding: 8px 15px;
  1103. border-radius: 3px;
  1104. cursor: pointer;
  1105. font-weight: bold;
  1106. `;
  1107.  
  1108. const closeButton = document.createElement('button');
  1109. closeButton.innerText = 'Cancel';
  1110. closeButton.style = `
  1111. background: #3a3634;
  1112. border: 1px solid #464442;
  1113. color: #bababa;
  1114. padding: 8px 15px;
  1115. border-radius: 3px;
  1116. cursor: pointer;
  1117. `;
  1118.  
  1119. buttonContainer.appendChild(saveButton);
  1120. buttonContainer.appendChild(closeButton);
  1121. settingsPanel.appendChild(buttonContainer);
  1122.  
  1123. // Add settings panel to screen
  1124. settingsScreen.appendChild(settingsPanel);
  1125. document.body.appendChild(settingsScreen);
  1126.  
  1127. // Event listeners
  1128. settingsButton.addEventListener('click', function() {
  1129. // Reset form values to current settings
  1130. draggableRadio.checked = myVars.panelPosition === 'draggable';
  1131. rightRadio.checked = myVars.panelPosition === 'right';
  1132. colorInput.value = myVars.bestMoveHighlightColor;
  1133. colorValue.innerText = myVars.bestMoveHighlightColor;
  1134.  
  1135. // Show settings
  1136. settingsScreen.style.display = 'block';
  1137. });
  1138.  
  1139. closeButton.addEventListener('click', function() {
  1140. settingsScreen.style.display = 'none';
  1141. });
  1142.  
  1143. // Update color value when input changes
  1144. colorInput.addEventListener('input', function() {
  1145. colorValue.innerText = this.value;
  1146.  
  1147. // Update preset borders
  1148. presetContainer.querySelectorAll('div').forEach(el => {
  1149. el.style.border = '2px solid transparent';
  1150. });
  1151.  
  1152. // Check if the color matches any preset
  1153. const matchingPreset = Array.from(presetContainer.querySelectorAll('div'))
  1154. .find(el => el.style.backgroundColor === this.value);
  1155.  
  1156. if (matchingPreset) {
  1157. matchingPreset.style.border = '2px solid #bababa';
  1158. }
  1159. });
  1160.  
  1161. saveButton.addEventListener('click', function() {
  1162. // Save position setting
  1163. if (draggableRadio.checked) {
  1164. myVars.panelPosition = 'draggable';
  1165. GM_setValue('panelPositionType', 'draggable');
  1166. } else if (rightRadio.checked) {
  1167. myVars.panelPosition = 'right';
  1168. GM_setValue('panelPositionType', 'right');
  1169. }
  1170.  
  1171. // Save color setting
  1172. myVars.bestMoveHighlightColor = colorInput.value;
  1173. GM_setValue('bestMoveHighlightColor', colorInput.value);
  1174.  
  1175. // Clear any existing content and show loading overlay
  1176. settingsPanel.innerHTML = '';
  1177.  
  1178. // Create loading overlay
  1179. const loadingOverlay = document.createElement('div');
  1180. loadingOverlay.style = `
  1181. position: absolute;
  1182. top: 0;
  1183. left: 0;
  1184. right: 0;
  1185. bottom: 0;
  1186. background-color: rgba(49, 46, 43, 0.95);
  1187. display: flex;
  1188. align-items: center;
  1189. justify-content: center;
  1190. z-index: 10002;
  1191. border-radius: 5px;
  1192. `;
  1193.  
  1194. const saveMessage = document.createElement('div');
  1195. saveMessage.innerText = 'Settings saved. Reloading page...';
  1196. saveMessage.style = `
  1197. color: #7fa650;
  1198. font-weight: bold;
  1199. font-size: 16px;
  1200. text-align: center;
  1201. `;
  1202.  
  1203. loadingOverlay.appendChild(saveMessage);
  1204. settingsScreen.appendChild(loadingOverlay);
  1205.  
  1206. // Reload page after 1 second
  1207. setTimeout(function() {
  1208. location.reload();
  1209. }, 1000);
  1210. });
  1211.  
  1212. // Add settings button to the right side of the header
  1213. header.appendChild(settingsButton);
  1214.  
  1215. // Create buttons section
  1216. const actionsSectionObj = createSection('Actions');
  1217. const actionsSection = actionsSectionObj.section;
  1218. const actionsContent = actionsSectionObj.content;
  1219.  
  1220. const createButton = (text, onClick, primary = false) => {
  1221. const button = document.createElement('button');
  1222. button.innerText = text;
  1223. button.addEventListener('click', onClick);
  1224. button.style = `
  1225. background-color: ${primary ? '#7fa650' : '#5d5955'};
  1226. color: #fff;
  1227. border: none;
  1228. padding: 10px;
  1229. margin-bottom: 10px;
  1230. border-radius: 3px;
  1231. width: 100%;
  1232. cursor: pointer;
  1233. font-weight: ${primary ? 'bold' : 'normal'};
  1234. transition: background-color 0.2s;
  1235. `;
  1236.  
  1237. button.addEventListener('mouseover', function() {
  1238. this.style.backgroundColor = primary ? '#8fb761' : '#6e6a66';
  1239. });
  1240.  
  1241. button.addEventListener('mouseout', function() {
  1242. this.style.backgroundColor = primary ? '#7fa650' : '#5d5955';
  1243. });
  1244.  
  1245. return button;
  1246. };
  1247.  
  1248. const reloadButton = createButton('Reload Chess Engine', () => myFunctions.reloadChessEngine(), true);
  1249. const issueButton = createButton('Report an Issue', () => {
  1250. window.open('https://greatest.deepsurf.us/en/scripts/534105-chess-com-bot-cheat-by-admin0/feedback', '_blank');
  1251. });
  1252.  
  1253. const updateButton = createButton('Check for Updates', () => {
  1254. window.open('https://greatest.deepsurf.us/en/scripts/534105-chess-com-bot-cheat-by-admin0', '_blank');
  1255. });
  1256.  
  1257. actionsContent.appendChild(reloadButton);
  1258. actionsContent.appendChild(issueButton);
  1259. actionsContent.appendChild(updateButton);
  1260. scrollContainer.appendChild(actionsSection);
  1261.  
  1262. // Create Top Moves section
  1263. const topMovesSectionObj = createSection('Top Moves');
  1264. const topMovesSection = topMovesSectionObj.section;
  1265. const topMovesContent = topMovesSectionObj.content;
  1266.  
  1267. // Create container for top moves display
  1268. const topMovesContainer = document.createElement('div');
  1269. topMovesContainer.style = `
  1270. background-color: #3a3634;
  1271. border-radius: 4px;
  1272. padding: 10px;
  1273. `;
  1274.  
  1275. // Create header for top moves
  1276. const topMovesHeader = document.createElement('div');
  1277. topMovesHeader.style = `
  1278. display: flex;
  1279. justify-content: space-between;
  1280. margin-bottom: 8px;
  1281. font-size: 12px;
  1282. color: #bababa;
  1283. opacity: 0.8;
  1284. `;
  1285.  
  1286. const moveHeader = document.createElement('span');
  1287. moveHeader.innerText = 'Move';
  1288.  
  1289. const evalHeader = document.createElement('span');
  1290. evalHeader.innerText = 'Evaluation';
  1291.  
  1292. topMovesHeader.appendChild(moveHeader);
  1293. topMovesHeader.appendChild(evalHeader);
  1294. topMovesContainer.appendChild(topMovesHeader);
  1295.  
  1296. // Create elements for top 2 moves
  1297. for (let i = 1; i <= 2; i++) {
  1298. const moveRow = document.createElement('div');
  1299. moveRow.style = `
  1300. display: flex;
  1301. justify-content: space-between;
  1302. align-items: center;
  1303. padding: 8px 0;
  1304. border-top: 1px solid #464442;
  1305. `;
  1306.  
  1307. const moveNumber = document.createElement('span');
  1308. moveNumber.style = `
  1309. background-color: ${i === 1 ? '#7fa650' : '#5d5955'};
  1310. color: white;
  1311. width: 20px;
  1312. height: 20px;
  1313. border-radius: 50%;
  1314. display: flex;
  1315. align-items: center;
  1316. justify-content: center;
  1317. font-size: 12px;
  1318. margin-right: 8px;
  1319. `;
  1320. moveNumber.innerText = i;
  1321.  
  1322. const moveText = document.createElement('span');
  1323. moveText.id = `topMove${i}`;
  1324. moveText.innerText = '...';
  1325. moveText.style = `
  1326. font-family: monospace;
  1327. font-weight: ${i === 1 ? 'bold' : 'normal'};
  1328. `;
  1329.  
  1330. const moveLeft = document.createElement('div');
  1331. moveLeft.style = `
  1332. display: flex;
  1333. align-items: center;
  1334. `;
  1335. moveLeft.appendChild(moveNumber);
  1336. moveLeft.appendChild(moveText);
  1337.  
  1338. const evalText = document.createElement('span');
  1339. evalText.id = `topMoveEval${i}`;
  1340. evalText.innerText = '...';
  1341. evalText.style = `
  1342. font-family: monospace;
  1343. color: ${i === 1 ? '#7fa650' : '#bababa'};
  1344. `;
  1345.  
  1346. moveRow.appendChild(moveLeft);
  1347. moveRow.appendChild(evalText);
  1348. topMovesContainer.appendChild(moveRow);
  1349. }
  1350.  
  1351. topMovesContent.appendChild(topMovesContainer);
  1352. scrollContainer.appendChild(topMovesSection);
  1353.  
  1354. // Make the header draggable only in draggable mode
  1355. header.style.cursor = positionType === 'draggable' ? 'move' : 'default';
  1356. header.style.userSelect = 'none'; // Prevent text selection during drag
  1357.  
  1358. // No visual indicator here - we'll add a single one later
  1359.  
  1360. // Make panel draggable with improved handling (only when in draggable mode)
  1361. let isDragging = false;
  1362. let offsetX, offsetY;
  1363.  
  1364. // Only set up dragging if in draggable mode
  1365. if (positionType === 'draggable') {
  1366. // Use mousedown on header for dragging
  1367. header.addEventListener('mousedown', function(e) {
  1368. // Only initiate drag if clicking on the header itself, the drag handle, or its children
  1369. if (e.target === header || e.target === dragHandle || e.target === gripIcon || e.target === title || e.target === version) {
  1370. e.preventDefault(); // Prevent text selection during drag
  1371. isDragging = true;
  1372.  
  1373. // Calculate offset from the panel's top-left corner
  1374. const rect = panel.getBoundingClientRect();
  1375. offsetX = e.clientX - rect.left;
  1376. offsetY = e.clientY - rect.top;
  1377.  
  1378. // No appearance change during drag - keep solid
  1379.  
  1380. // Capture mouse events on the entire document
  1381. document.addEventListener('mousemove', handleDrag);
  1382. document.addEventListener('mouseup', stopDrag);
  1383. }
  1384. });
  1385.  
  1386. // Handle dragging
  1387. function handleDrag(e) {
  1388. if (!isDragging) return;
  1389.  
  1390. const newLeft = e.clientX - offsetX;
  1391. const newTop = e.clientY - offsetY;
  1392.  
  1393. // Keep panel within viewport bounds
  1394. const maxX = window.innerWidth - panel.offsetWidth;
  1395. const maxY = window.innerHeight - panel.offsetHeight;
  1396.  
  1397. panel.style.right = 'auto';
  1398. panel.style.top = Math.max(0, Math.min(newTop, maxY)) + 'px';
  1399. panel.style.left = Math.max(0, Math.min(newLeft, maxX)) + 'px';
  1400. panel.style.transform = 'none';
  1401. }
  1402.  
  1403. // Stop dragging
  1404. function stopDrag() {
  1405. if (!isDragging) return;
  1406.  
  1407. isDragging = false;
  1408.  
  1409. // Save position with more details
  1410. const rect = panel.getBoundingClientRect();
  1411. GM_setValue('panelPosition', {
  1412. top: rect.top,
  1413. left: rect.left,
  1414. right: 'auto'
  1415. });
  1416.  
  1417. // Remove temporary event listeners
  1418. document.removeEventListener('mousemove', handleDrag);
  1419. document.removeEventListener('mouseup', stopDrag);
  1420. }
  1421.  
  1422. // Add a clean, modern drag handle
  1423. const dragHandle = document.createElement('div');
  1424. dragHandle.style = `
  1425. display: flex;
  1426. flex-direction: column;
  1427. justify-content: center;
  1428. gap: 3px;
  1429. margin-right: 8px;
  1430. cursor: move;
  1431. user-select: none;
  1432. width: 16px;
  1433. height: 16px;
  1434. `;
  1435.  
  1436. // Create a simple grip icon for the drag handle
  1437. const gripIcon = document.createElement('div');
  1438. gripIcon.innerHTML = '≡'; // Unicode triple bar character
  1439. gripIcon.style = ``;
  1440. dragHandle.appendChild(gripIcon);
  1441.  
  1442. header.insertBefore(dragHandle, header.firstChild);
  1443. }
  1444.  
  1445. // Add footer (outside scroll container)
  1446. const footer = document.createElement('div');
  1447. footer.style = `
  1448. margin-top: 10px;
  1449. padding-top: 8px;
  1450. border-top: 1px solid #464442;
  1451. font-size: 11px;
  1452. text-align: center;
  1453. opacity: 0.7;
  1454. flex-shrink: 0; /* Prevent footer from shrinking */
  1455. position: relative; /* For resize handle positioning */
  1456. `;
  1457.  
  1458. footer.innerText = 'Press ESC to toggle interface';
  1459. panel.appendChild(footer);
  1460.  
  1461. // Use browser's native resize functionality instead of custom handle
  1462. if (positionType === 'draggable') {
  1463. // Set panel to be resizable using browser's native resize
  1464. panel.style.resize = 'both';
  1465. panel.style.overflow = 'auto';
  1466.  
  1467. // Add event listener to save dimensions when resizing stops
  1468. let resizeTimeout;
  1469. const saveResizedDimensions = function() {
  1470. // Save new dimensions
  1471. const width = panel.offsetWidth;
  1472. const height = panel.offsetHeight;
  1473.  
  1474. GM_setValue('panelDimensions', {
  1475. width: width,
  1476. height: height,
  1477. minWidth: savedDimensions.minWidth,
  1478. minHeight: savedDimensions.minHeight
  1479. });
  1480. };
  1481.  
  1482. // Use resize observer to detect when resizing happens
  1483. const resizeObserver = new ResizeObserver(function() {
  1484. // Clear previous timeout
  1485. clearTimeout(resizeTimeout);
  1486.  
  1487. // Set new timeout to save dimensions after resizing stops
  1488. resizeTimeout = setTimeout(saveResizedDimensions, 500);
  1489. });
  1490.  
  1491. // Start observing the panel
  1492. resizeObserver.observe(panel);
  1493. }
  1494.  
  1495. // Append panel to body
  1496. document.body.appendChild(panel);
  1497.  
  1498. loaded = true;
  1499. console.log("[UI] Chess.com themed interface created successfully");
  1500. } catch (error) {
  1501. console.error("[UI] Error creating interface:", error);
  1502. }
  1503. };
  1504.  
  1505. // Main interval loop
  1506. const waitForChessBoard = setInterval(() => {
  1507. if (loaded) {
  1508. board = $('chess-board')[0] || $('wc-chess-board')[0];
  1509.  
  1510. // Read checkbox states directly from DOM
  1511. try {
  1512. myVars.suggestMove = document.getElementById('suggestMove').checked;
  1513. myVars.autoMove = document.getElementById('autoMove').checked;
  1514. myVars.autoMatch = document.getElementById('autoMatch').checked;
  1515.  
  1516. // Save the current state
  1517. GM_setValue('suggestMove', myVars.suggestMove);
  1518. GM_setValue('autoMove', myVars.autoMove);
  1519. GM_setValue('autoMatch', myVars.autoMatch);
  1520.  
  1521. // Read delay values
  1522. let minDelay = parseFloat(document.getElementById('timeDelayMin').value) || 0.1;
  1523. let maxDelay = parseFloat(document.getElementById('timeDelayMax').value) || 1.0;
  1524. myVars.delay = Math.random() * (maxDelay - minDelay) + minDelay;
  1525. } catch (e) {
  1526. console.warn("[UI] Error reading UI state:", e);
  1527. }
  1528.  
  1529. // Update spinner
  1530. myVars.isThinking = isThinking;
  1531. myFunctions.spinner();
  1532.  
  1533. // Check for game over
  1534. const gameOverModal = $('.game-over-modal-content');
  1535. if (gameOverModal.length > 0 && !myVars.gameEnded) {
  1536. console.log("[Game] Game over detected");
  1537. myVars.gameEnded = true;
  1538. myVars.hasAutoMatched = false;
  1539. }
  1540.  
  1541. // Check turn
  1542. try {
  1543. if (!myVars.gameEnded && board && board.game) {
  1544. myTurn = (board.game.getTurn() == board.game.getPlayingAs());
  1545. } else {
  1546. myTurn = false;
  1547. }
  1548. } catch (e) {
  1549. myTurn = false;
  1550. }
  1551.  
  1552. // Log state (for debugging)
  1553. console.log(`[State] SuggestMove:${myVars.suggestMove} AutoMove:${myVars.autoMove} AutoMatch:${myVars.autoMatch} MyTurn:${myTurn} Thinking:${isThinking} CanGo:${canGo}`);
  1554.  
  1555. // Make sure engine is loaded
  1556. if (!engine.engine) {
  1557. myFunctions.loadChessEngine();
  1558. }
  1559.  
  1560. // Auto Run Logic (Now Suggested Move Logic)
  1561. if (myVars.suggestMove && canGo && !isThinking && myTurn && !myVars.gameEnded) {
  1562. console.log("[Auto] Triggering suggested move analysis...");
  1563. canGo = false;
  1564. const currentDelay = myVars.delay * 1000;
  1565. other(currentDelay);
  1566. }
  1567.  
  1568. // Auto Match Logic
  1569. if (myVars.autoMatch && myVars.gameEnded && !myVars.hasAutoMatched) {
  1570. console.log("[Auto] Triggering auto match...");
  1571. myFunctions.startNewGame();
  1572. }
  1573. } else if ($('chess-board, wc-chess-board').length > 0) {
  1574. // Try to load UI if not loaded yet
  1575. myFunctions.loadEx();
  1576. }
  1577. }, 100);
  1578. }
  1579.  
  1580. // Global variables
  1581. var isThinking = false;
  1582. var canGo = true;
  1583. var myTurn = false;
  1584. var board;
  1585.  
  1586. // Add CSS to hide the menu icon
  1587. const hideMenuStyle = document.createElement('style');
  1588. hideMenuStyle.textContent = `
  1589. .GM_menuCommand,
  1590. #GM_menu,
  1591. #GM_menu_button,
  1592. .tampermonkey-menu-button,
  1593. div[id^="tampermonkey-menu"],
  1594. div[class^="tampermonkey-menu"],
  1595. div[style*="position: fixed; right: auto; top: 59px; left: 420px;"],
  1596. div[style*="position:fixed;right:auto;top:59px;left:420px;"],
  1597. div[style*="z-index: 9999"]:not(#chessBot):not(#overlay):not(#chessBot-settings),
  1598. div[id$="-menu"],
  1599. div[class$="-menu"],
  1600. div[style*="=="],
  1601. div[style*="$0"] {
  1602. display: none !important;
  1603. opacity: 0 !important;
  1604. visibility: hidden !important;
  1605. pointer-events: none !important;
  1606. }
  1607. `;
  1608. document.head.appendChild(hideMenuStyle);
  1609.  
  1610. // Register menu commands but they'll be hidden by CSS
  1611. function registerHiddenMenuCommands() {
  1612. // Register menu commands for functionality but they'll be hidden
  1613. GM_registerMenuCommand("Chess.com Bot v2.0.0", function() {
  1614. // Toggle visibility of the bot panel
  1615. const panel = document.getElementById('chessBot');
  1616. if (panel) {
  1617. panel.style.display = panel.style.display === 'none' ? 'flex' : 'none';
  1618. }
  1619. });
  1620. }
  1621.  
  1622. // Call this after the document is loaded
  1623. setTimeout(registerHiddenMenuCommands, 1000);
  1624.  
  1625. // Function to remove specific unwanted elements
  1626. function removeUnwantedElements() {
  1627. // Find and remove elements with style containing "=="
  1628. const elements = document.querySelectorAll('div');
  1629. for (const el of elements) {
  1630. if (el.getAttribute('style') &&
  1631. (el.getAttribute('style').includes('==') ||
  1632. el.getAttribute('style').includes('$0'))) {
  1633. el.remove();
  1634. }
  1635. }
  1636.  
  1637. // Keep checking periodically
  1638. setTimeout(removeUnwantedElements, 1000);
  1639. }
  1640.  
  1641. // Start removing unwanted elements
  1642. setTimeout(removeUnwantedElements, 500);
  1643.  
  1644. // Start the script
  1645. window.addEventListener("load", (event) => {
  1646. console.log("[Script] Chess.com Bot v2.0.0 starting...");
  1647. main();
  1648. });