// ==UserScript==
// @name Chess.com Bot/Cheat (by Wayron)
// @namespace Admin0
// @version 2.0.0
// @description Chess.com Bot/Cheat that finds the best move!
// @author Admin0
// @license Chess.com Bot/Cheat © 2024 by Admin0, © All Rights Reserved
// @match https://www.chess.com/play/*
// @match https://www.chess.com/game/*
// @match https://www.chess.com/puzzles/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant GM_getResourceText
// @grant GM_registerMenuCommand
// @resource stockfish.js https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/9.0.0/stockfish.js
// @require https://greatest.deepsurf.us/scripts/445697/code/index.js
// @require https://code.jquery.com/jquery-3.6.0.min.js
// @run-at document-start
// ==/UserScript==
// CLEAN REWRITE - CHESS.COM THEMED VERSION 2.0
const currentVersion = '2.0.0';
function main() {
// Core variables setup
var stockfishObjectURL;
var engine = document.engine = {};
var myVars = document.myVars = {};
myVars.autoMove = GM_getValue('autoMove', false); // Load saved autoMove
myVars.suggestMove = GM_getValue('suggestMove', false); // Load saved suggestMove
myVars.autoMatch = GM_getValue('autoMatch', false); // Load saved autoMatch
myVars.customDepth = GM_getValue('customDepth', 11); // Load saved depth, default to 11
myVars.bestMoveHighlightColor = GM_getValue('bestMoveHighlightColor', '#7fa650'); // Chess.com green
myVars.panelPosition = GM_getValue('panelPositionType', 'draggable'); // Position type: 'right' or 'draggable'
var myFunctions = document.myFunctions = {};
var lastValue = GM_getValue('customDepth', 11); // Also initialize lastValue with saved/default depth
// Core chess engine logic from Script3 (the working one)
// Track active highlights to prevent stacking
myVars.activeHighlights = [];
myFunctions.color = function(dat) {
console.log("[Move] Processing:", dat);
console.log("[Highlight] Attempting highlight on board element:", board ? board.nodeName : 'Board not found!'); // Diagnostic log
let response = dat;
let res1 = response.substring(0, 2); // From square
let res2 = response.substring(2, 4); // To square
// Execute move if auto-move is enabled
if (myVars.autoMove === true) {
myFunctions.movePiece(res1, res2);
}
// Reset thinking state
isThinking = false;
// Convert chess notation to Chess.com's grid system
res1 = res1.replace(/^a/, "1")
.replace(/^b/, "2")
.replace(/^c/, "3")
.replace(/^d/, "4")
.replace(/^e/, "5")
.replace(/^f/, "6")
.replace(/^g/, "7")
.replace(/^h/, "8");
res2 = res2.replace(/^a/, "1")
.replace(/^b/, "2")
.replace(/^c/, "3")
.replace(/^d/, "4")
.replace(/^e/, "5")
.replace(/^f/, "6")
.replace(/^g/, "7")
.replace(/^h/, "8");
// Clear any existing highlights to prevent stacking
myFunctions.clearHighlights();
// Highlight destination square with improved styling
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>');
$(board.nodeName).prepend(destHighlight);
myVars.activeHighlights.push(destHighlight);
// Animate the destination highlight
destHighlight.animate({
opacity: 0.7
}, 300);
// Highlight origin square with improved styling
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>');
$(board.nodeName).prepend(originHighlight);
myVars.activeHighlights.push(originHighlight);
// Animate the origin highlight
originHighlight.animate({
opacity: 0.7
}, 300);
// Set timeout to clear highlights after delay
setTimeout(function() {
myFunctions.clearHighlights();
}, 1800);
};
// Function to clear all active highlights with fade-out animation
myFunctions.clearHighlights = function() {
if (myVars.activeHighlights && myVars.activeHighlights.length > 0) {
myVars.activeHighlights.forEach(function(highlight) {
// Animate fade out
highlight.animate({
opacity: 0
}, 300, function() {
// Remove after animation completes
$(this).remove();
});
});
myVars.activeHighlights = [];
}
// Also fade out and remove any other highlights that might be present
$('.highlight.bro').animate({
opacity: 0
}, 300, function() {
$(this).remove();
});
};
// Move execution function from Script3
myFunctions.movePiece = function(from, to) {
console.log("[Move] Executing move from", from, "to", to);
try {
// Get legal moves from the game
let legalMoves = board.game.getLegalMoves();
// Find our move in legal moves
for (let each = 0; each < legalMoves.length; each++) {
if (legalMoves[each].from === from && legalMoves[each].to === to) {
let move = legalMoves[each];
// Check for promotion (pawn to last rank)
let promotion = undefined;
let piece = board.game.getPiece(from);
if (piece && piece.type === 'p' && (to[1] === '8' || to[1] === '1')) {
promotion = 'q'; // Default promote to queen
console.log("[Move] Promoting pawn to queen");
}
// Execute the move
board.game.move({
from: move.from,
to: move.to,
promotion: promotion,
animate: false,
userGenerated: true
});
console.log("[Move] Executed successfully");
return;
}
}
console.warn("[Move] No legal move found:", from, to);
} catch (error) {
console.error("[Move] Error executing move:", error);
}
};
// Enhanced parser to capture top moves
function parser(e) {
console.log("[Engine] Message:", e.data);
// Track top moves during analysis
if (e.data.includes('info depth') && e.data.includes('pv')) {
try {
// Extract move data from engine output
const parts = e.data.split(' ');
const depthIndex = parts.indexOf('depth');
const scoreIndex = parts.indexOf('score');
const pvIndex = parts.indexOf('pv');
if (depthIndex >= 0 && scoreIndex >= 0 && pvIndex >= 0) {
const depth = parseInt(parts[depthIndex + 1]);
const scoreType = parts[scoreIndex + 1]; // cp or mate
const scoreValue = parseInt(parts[scoreIndex + 2]);
const move = parts[pvIndex + 1];
// Format evaluation text
let evalText = '';
if (scoreType === 'cp') {
// Convert centipawns to pawns with + or - sign
const pawns = (scoreValue / 100).toFixed(2);
evalText = (pawns > 0 ? '+' : '') + pawns;
} else if (scoreType === 'mate') {
// Show mate in X
evalText = 'M' + (scoreValue > 0 ? '+' : '') + scoreValue;
}
// Store in top moves array if this is a new depth
if (!myVars.topMoves) {
myVars.topMoves = [];
}
// Add to top moves if it's a new depth or replace existing entry
const existingIndex = myVars.topMoves.findIndex(m => m.move === move);
if (existingIndex >= 0) {
// Update existing move with new evaluation
myVars.topMoves[existingIndex] = { move, evalText, depth, score: scoreValue };
} else {
// Add new move
myVars.topMoves.push({ move, evalText, depth, score: scoreValue });
}
// Sort by score (higher is better)
myVars.topMoves.sort((a, b) => b.score - a.score);
// Keep only top 2 moves
myVars.topMoves = myVars.topMoves.slice(0, 2);
// Update UI if elements exist
if (document.getElementById('topMove1') && myVars.topMoves.length > 0) {
for (let i = 0; i < Math.min(2, myVars.topMoves.length); i++) {
const moveElem = document.getElementById(`topMove${i+1}`);
const evalElem = document.getElementById(`topMoveEval${i+1}`);
if (moveElem && evalElem) {
moveElem.innerText = myVars.topMoves[i].move;
evalElem.innerText = myVars.topMoves[i].evalText;
}
}
}
}
} catch (error) {
console.error("[Engine] Error parsing move info:", error);
}
}
// Process best move when analysis is complete
if (e.data.includes('bestmove')) {
console.log("[Engine] Found best move:", e.data);
const bestMove = e.data.split(' ')[1];
myFunctions.color(bestMove);
isThinking = false;
// Clear top moves array for next analysis
myVars.topMoves = [];
}
}
// Engine load function from Script3
myFunctions.loadChessEngine = function() {
console.log("[Engine] Loading Stockfish...");
try {
if (!stockfishObjectURL) {
stockfishObjectURL = URL.createObjectURL(new Blob([GM_getResourceText('stockfish.js')], {type: 'application/javascript'}));
}
engine.engine = new Worker(stockfishObjectURL);
engine.engine.onmessage = e => {
parser(e);
};
engine.engine.onerror = e => {
console.error("[Engine] Error:", e);
isThinking = false;
};
engine.engine.postMessage('ucinewgame');
console.log("[Engine] Loaded successfully");
} catch (error) {
console.error("[Engine] Load failed:", error);
}
};
// Engine reload function
myFunctions.reloadChessEngine = function() {
console.log("[Engine] Reloading...");
try {
if (engine.engine) {
engine.engine.terminate();
}
isThinking = false;
stockfishObjectURL = null; // Force recreation
setTimeout(() => {
myFunctions.loadChessEngine();
console.log("[Engine] Reloaded successfully");
}, 100);
} catch (error) {
console.error("[Engine] Reload failed:", error);
}
};
// Run engine at specified depth
myFunctions.runChessEngine = function(depth) {
console.log("[Engine] Running at depth", depth);
let fen = board.game.getFEN();
console.log("[Engine] Position:", fen);
engine.engine.postMessage(`position fen ${fen}`);
isThinking = true;
engine.engine.postMessage(`go depth ${depth}`);
lastValue = depth;
};
// Auto run function
myFunctions.autoRun = function(depth) {
if (board.game.getTurn() == board.game.getPlayingAs()) {
myFunctions.runChessEngine(depth || myVars.customDepth);
}
};
// Function to handle delayed auto-run
function other(delay) {
let endTime = Date.now() + delay;
let timer = setInterval(() => {
if (Date.now() >= endTime) {
myFunctions.autoRun(myVars.customDepth);
canGo = true;
clearInterval(timer);
}
}, 10);
}
// Auto start new game
myFunctions.startNewGame = function() {
console.log("[Match] Starting new game...");
// Find New Game button in different places
const modalNewGameButton = $('.game-over-modal-content .game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])');
if (modalNewGameButton.length) {
modalNewGameButton[0].click();
console.log("[Match] Clicked New Game from modal");
myVars.hasAutoMatched = true;
myVars.gameEnded = false;
return;
}
const newGameButton = $('.game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])');
if (newGameButton.length) {
newGameButton[0].click();
console.log("[Match] Clicked New Game button");
myVars.hasAutoMatched = true;
myVars.gameEnded = false;
return;
}
console.log("[Match] No New Game button found");
};
// Function to handle spinner visibility
myFunctions.spinner = function() {
if (loaded && $('#overlay').length) {
$('#overlay').css('display', isThinking ? 'block' : 'none');
}
};
// Handle keyboard shortcuts
document.onkeydown = function(e) {
const depthKeys = {
81: 1, 87: 2, 69: 3, 82: 4, 84: 5, 89: 6, 85: 7, 73: 8, 79: 9, 80: 10,
65: 11, 83: 12, 68: 13, 70: 14, 71: 15, 72: 16, 74: 17, 75: 18, 76: 19,
90: 20, 88: 21, 67: 22, 86: 23, 66: 24, 78: 25, 77: 26, 187: 100
};
if (depthKeys[e.keyCode]) {
myVars.customDepth = depthKeys[e.keyCode];
if (loaded) {
$('#depthValue').text(myVars.customDepth);
}
GM_setValue('customDepth', myVars.customDepth); // Save the new depth
location.reload(); // Reload the page
}
// Toggle UI with ESC
if (e.keyCode === 27 && loaded) {
$('#chessBot').toggle();
}
};
// UI Creation function - CHESS.COM THEMED
var loaded = false;
myFunctions.loadEx = function() {
if (loaded) return;
try {
console.log("[UI] Creating Chess.com themed interface...");
board = $('chess-board')[0] || $('wc-chess-board')[0];
if (!board) {
console.warn("[UI] Board not found yet");
return;
}
myVars.board = board;
// Create main container with Chess.com styling
const panel = document.createElement('div');
panel.id = 'chessBot';
// Load saved panel dimensions or use defaults
const savedDimensions = GM_getValue('panelDimensions', {
width: 220,
height: 400,
minWidth: 180,
minHeight: 300
});
// Get panel position type
const positionType = myVars.panelPosition; // 'right', 'bottom', or 'draggable'
// Set initial position and dimensions based on position type
let positionCSS = '';
let dimensionsCSS = '';
if (positionType === 'right') {
// Right mode: Full height on right side
positionCSS = `
right: 20px;
top: 20px;
bottom: 20px;
transform: none;
`;
dimensionsCSS = `
width: 280px;
height: auto;
overflow-y: auto;
`;
} else { // draggable (default)
// Get saved position for draggable mode
const savedPosition = GM_getValue('panelPosition', {
top: 100,
left: window.innerWidth - savedDimensions.width - 20,
right: 'auto'
});
positionCSS = `
right: ${savedPosition.right};
top: ${savedPosition.top}px;
left: ${savedPosition.left}px;
transform: none;
`;
dimensionsCSS = `
width: ${savedDimensions.width}px;
height: ${savedDimensions.height}px;
`;
}
// If position type is invalid, default to draggable
if (positionType !== 'right' && positionType !== 'draggable') {
myVars.panelPosition = 'draggable';
GM_setValue('panelPositionType', 'draggable');
}
panel.style = `
position: fixed;
${positionCSS}
${dimensionsCSS}
min-width: ${positionType === 'bottom' ? 'auto' : savedDimensions.minWidth + 'px'};
min-height: ${positionType === 'right' ? 'auto' : savedDimensions.minHeight + 'px'};
background-color: #312e2b;
color: #bababa;
font-family: "Segoe UI", Arial, sans-serif;
z-index: 9999;
padding: 15px;
border-radius: 8px;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
font-size: 14px;
display: flex;
flex-direction: column;
overflow: hidden;
`;
// Create header
const header = document.createElement('div');
header.style = `
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
border-bottom: 1px solid #464442;
padding-bottom: 10px;
`;
const title = document.createElement('h2');
title.innerText = 'Chess.com Bot';
title.style = `
margin: 0;
font-size: 18px;
font-weight: 600;
color: #bababa;
`;
const version = document.createElement('span');
version.innerText = 'v2.0.0';
version.style = `
font-size: 12px;
opacity: 0.8;
color: #bababa;
`;
// Create a container for title and version
const titleContainer = document.createElement('div');
titleContainer.style = `
display: flex;
align-items: baseline;
gap: 8px;
`;
titleContainer.appendChild(title);
titleContainer.appendChild(version);
// Add title container to the left side of header
header.appendChild(titleContainer);
panel.appendChild(header);
// Create spinner overlay
const overlay = document.createElement('div');
overlay.id = 'overlay';
overlay.style = `
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(49, 46, 43, 0.85);
z-index: 10000;
display: none;
border-radius: 5px;
`;
const spinner = document.createElement('div');
spinner.style = `
position: absolute;
top: 50%;
left: 50%;
width: 40px;
height: 40px;
margin-top: -20px;
margin-left: -20px;
border: 3px solid #bababa;
border-top-color: #7fa650;
border-radius: 50%;
animation: spin 1s infinite linear;
`;
const spinStyle = document.createElement('style');
spinStyle.textContent = `
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
`;
document.head.appendChild(spinStyle);
overlay.appendChild(spinner);
panel.appendChild(overlay);
// Create scrollable content container
const scrollContainer = document.createElement('div');
scrollContainer.className = 'scroll-container';
scrollContainer.style = `
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding-right: 5px; /* Add space for scrollbar */
margin-right: -5px; /* Compensate for padding */
scrollbar-width: thin; /* Firefox */
scrollbar-color: #464442 #312e2b; /* Firefox */
`;
// Add custom scrollbar styles
const scrollbarStyle = document.createElement('style');
scrollbarStyle.textContent = `
.scroll-container::-webkit-scrollbar {
width: 6px;
}
.scroll-container::-webkit-scrollbar-track {
background: #312e2b;
}
.scroll-container::-webkit-scrollbar-thumb {
background-color: #464442;
border-radius: 3px;
}
.scroll-container::-webkit-scrollbar-thumb:hover {
background-color: #5d5955;
}
`;
document.head.appendChild(scrollbarStyle);
panel.appendChild(scrollContainer);
// Create collapsible content sections
const createSection = (title) => {
const section = document.createElement('div');
section.className = 'collapsible-section';
section.style = `
margin-bottom: 15px;
`;
const sectionHeader = document.createElement('div');
sectionHeader.className = 'section-header';
sectionHeader.style = `
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
border-bottom: 1px solid #464442;
padding-bottom: 5px;
user-select: none;
`;
const sectionTitle = document.createElement('h3');
sectionTitle.innerText = title;
sectionTitle.style = `
margin: 0;
font-size: 16px;
color: #bababa;
`;
const collapseIcon = document.createElement('span');
collapseIcon.className = 'collapse-icon';
collapseIcon.innerHTML = '▼'; // Down arrow for expanded
collapseIcon.style = `
font-size: 12px;
color: #bababa;
transition: transform 0.3s;
`;
sectionHeader.appendChild(sectionTitle);
sectionHeader.appendChild(collapseIcon);
const sectionContent = document.createElement('div');
sectionContent.className = 'section-content';
sectionContent.style = `
margin-top: 10px;
overflow: hidden;
transition: max-height 0.3s ease-out, opacity 0.3s ease-out;
max-height: 1000px; /* Start expanded */
opacity: 1;
visibility: visible;
`;
// Toggle collapse on header click with improved animation
sectionHeader.addEventListener('click', function() {
const isCollapsed = sectionContent.style.maxHeight === '0px' || !sectionContent.style.maxHeight;
if (isCollapsed) {
// Expand - use scrollHeight to determine the actual height needed
sectionContent.style.maxHeight = sectionContent.scrollHeight + 'px';
sectionContent.style.opacity = '1';
sectionContent.style.visibility = 'visible';
collapseIcon.innerHTML = '▼';
collapseIcon.style.transform = 'rotate(0deg)';
// Update maxHeight after content changes (for dynamic content)
setTimeout(() => {
sectionContent.style.maxHeight = sectionContent.scrollHeight + 'px';
}, 50);
} else {
// Collapse with smooth animation
sectionContent.style.maxHeight = '0px';
sectionContent.style.opacity = '0';
// Don't hide immediately to allow animation to complete
setTimeout(() => {
if (sectionContent.style.maxHeight === '0px') {
sectionContent.style.visibility = 'hidden';
}
}, 300);
collapseIcon.innerHTML = '▶';
collapseIcon.style.transform = 'rotate(-90deg)';
}
// Save collapsed state
const collapsedSections = GM_getValue('collapsedSections', {});
collapsedSections[title] = !isCollapsed;
GM_setValue('collapsedSections', collapsedSections);
});
section.appendChild(sectionHeader);
section.appendChild(sectionContent);
// Set initial collapse state from saved preferences
const collapsedSections = GM_getValue('collapsedSections', {});
if (collapsedSections[title]) {
sectionContent.style.maxHeight = '0px';
sectionContent.style.opacity = '0';
sectionContent.style.visibility = 'hidden';
collapseIcon.innerHTML = '▶';
collapseIcon.style.transform = 'rotate(-90deg)';
} else {
// Make sure expanded sections have proper height
setTimeout(() => {
if (sectionContent.style.maxHeight !== '0px') {
sectionContent.style.maxHeight = sectionContent.scrollHeight + 'px';
}
}, 50);
}
// Return the content div instead of the section
return {
section: section,
content: sectionContent
};
};
// Create depth section
const depthSectionObj = createSection('Engine Depth');
const depthSection = depthSectionObj.section;
const depthContent = depthSectionObj.content;
const depthDisplay = document.createElement('div');
depthDisplay.style = `
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
background-color: #3a3634;
padding: 8px 12px;
border-radius: 4px;
`;
const depthLabel = document.createElement('span');
depthLabel.innerText = 'Current Depth:';
const depthValue = document.createElement('span');
depthValue.id = 'depthValue';
depthValue.innerText = myVars.customDepth;
depthValue.style = `
font-weight: bold;
color: #7fa650;
`;
depthDisplay.appendChild(depthLabel);
depthDisplay.appendChild(depthValue);
// Removed "Press A-Z keys" message
const depthInput = document.createElement('div');
depthInput.style = `
display: flex;
align-items: center;
margin-top: 10px;
`;
const depthInputLabel = document.createElement('label');
depthInputLabel.innerText = 'Set Depth:';
depthInputLabel.style = 'margin-right: 10px;';
const depthInputField = document.createElement('input');
depthInputField.type = 'number';
depthInputField.id = 'customDepthInput';
depthInputField.min = '1';
depthInputField.max = '100';
depthInputField.value = myVars.customDepth;
depthInputField.style = `
background-color: #3a3634;
border: 1px solid #464442;
color: #bababa;
padding: 5px;
border-radius: 3px;
width: 60px;
`;
depthInputField.addEventListener('change', function() {
const value = parseInt(this.value);
if (!isNaN(value) && value >= 1 && value <= 100) {
myVars.customDepth = value;
depthValue.innerText = value;
GM_setValue('customDepth', myVars.customDepth); // Save the new depth
location.reload(); // Reload the page
} else {
this.value = GM_getValue('customDepth', 11); // Reset to saved value if input is invalid
}
});
depthInput.appendChild(depthInputLabel);
depthInput.appendChild(depthInputField);
depthContent.appendChild(depthDisplay);
depthContent.appendChild(depthInput);
scrollContainer.appendChild(depthSection);
// Create game options section
const optionsSectionObj = createSection('Game Options');
const optionsSection = optionsSectionObj.section;
const optionsContent = optionsSectionObj.content;
const createCheckbox = (id, label) => {
const container = document.createElement('div');
container.style = `
display: flex;
align-items: center;
margin-bottom: 10px;
cursor: pointer;
`;
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = id;
checkbox.style = `
margin-right: 10px;
cursor: pointer;
`;
const checkLabel = document.createElement('label');
checkLabel.htmlFor = id;
checkLabel.innerText = label;
checkLabel.style = 'cursor: pointer;';
container.appendChild(checkbox);
container.appendChild(checkLabel);
return container;
};
const autoRunCheck = createCheckbox('suggestMove', 'Enable Suggested Move');
const autoMoveCheck = createCheckbox('autoMove', 'Enable auto move');
const autoMatchCheck = createCheckbox('autoMatch', 'Enable auto match');
optionsContent.appendChild(autoRunCheck);
optionsContent.appendChild(autoMoveCheck);
optionsContent.appendChild(autoMatchCheck);
scrollContainer.appendChild(optionsSection);
// Set initial state from loaded vars
autoRunCheck.querySelector('input').checked = myVars.suggestMove;
autoMoveCheck.querySelector('input').checked = myVars.autoMove;
autoMatchCheck.querySelector('input').checked = myVars.autoMatch;
// Create delay section
const delaySectionObj = createSection('Suggestion Delay');
const delaySection = delaySectionObj.section;
const delayContent = delaySectionObj.content;
const createDelayInput = (id, label, defaultValue) => {
const container = document.createElement('div');
container.style = `
display: flex;
align-items: center;
margin-bottom: 10px;
`;
const inputLabel = document.createElement('label');
inputLabel.htmlFor = id;
inputLabel.innerText = label;
inputLabel.style = `
flex: 1;
`;
const input = document.createElement('input');
input.type = 'number';
input.id = id;
input.min = '0.1';
input.step = '0.1';
input.value = defaultValue;
input.style = `
background-color: #3a3634;
border: 1px solid #464442;
color: #bababa;
padding: 5px;
border-radius: 3px;
width: 60px;
`;
container.appendChild(inputLabel);
container.appendChild(input);
return container;
};
const minDelayInput = createDelayInput('timeDelayMin', 'Min Delay (s):', '0.1');
const maxDelayInput = createDelayInput('timeDelayMax', 'Max Delay (s):', '1.0');
delayContent.appendChild(minDelayInput);
delayContent.appendChild(maxDelayInput);
scrollContainer.appendChild(delaySection);
// Create a settings button in the header (icon button)
const settingsButton = document.createElement('button');
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>';
settingsButton.title = 'Settings';
settingsButton.style = `
background: #3a3634;
border: 1px solid #464442;
color: #bababa;
width: 28px;
height: 28px;
cursor: pointer;
margin-right: 10px;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
`;
// Create settings screen (initially hidden)
const settingsScreen = document.createElement('div');
settingsScreen.id = 'chessBot-settings';
settingsScreen.style = `
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
z-index: 10000;
display: none;
`;
// Settings panel
const settingsPanel = document.createElement('div');
settingsPanel.style = `
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #312e2b;
width: 300px;
border-radius: 5px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
padding: 15px;
color: #bababa;
font-family: "Segoe UI", Arial, sans-serif;
`;
// Settings title
const settingsTitle = document.createElement('div');
settingsTitle.innerText = 'Settings';
settingsTitle.style = `
font-size: 16px;
font-weight: bold;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #464442;
color: #bababa;
`;
settingsPanel.appendChild(settingsTitle);
// Panel position settings
const positionTitle = document.createElement('div');
positionTitle.innerText = 'Panel Position';
positionTitle.style = `
font-weight: bold;
margin-bottom: 10px;
color: #bababa;
`;
settingsPanel.appendChild(positionTitle);
// Position radio buttons
const positionContainer = document.createElement('div');
positionContainer.style = `
margin-bottom: 20px;
`;
// Draggable option
const draggableContainer = document.createElement('div');
draggableContainer.style = `
display: flex;
align-items: center;
margin-bottom: 8px;
`;
const draggableRadio = document.createElement('input');
draggableRadio.type = 'radio';
draggableRadio.id = 'positionDraggable';
draggableRadio.name = 'panelPosition';
draggableRadio.value = 'draggable';
draggableRadio.checked = myVars.panelPosition === 'draggable';
draggableRadio.style.marginRight = '8px';
const draggableLabel = document.createElement('label');
draggableLabel.htmlFor = 'positionDraggable';
draggableLabel.innerText = 'Draggable (Move Freely)';
draggableLabel.style.color = '#bababa';
draggableContainer.appendChild(draggableRadio);
draggableContainer.appendChild(draggableLabel);
positionContainer.appendChild(draggableContainer);
// Right option
const rightContainer = document.createElement('div');
rightContainer.style = `
display: flex;
align-items: center;
`;
const rightRadio = document.createElement('input');
rightRadio.type = 'radio';
rightRadio.id = 'positionRight';
rightRadio.name = 'panelPosition';
rightRadio.value = 'right';
rightRadio.checked = myVars.panelPosition === 'right';
rightRadio.style.marginRight = '8px';
const rightLabel = document.createElement('label');
rightLabel.htmlFor = 'positionRight';
rightLabel.innerText = 'Right Side';
rightLabel.style.color = '#bababa';
rightContainer.appendChild(rightRadio);
rightContainer.appendChild(rightLabel);
positionContainer.appendChild(rightContainer);
// Add position container to panel
settingsPanel.appendChild(positionContainer);
// Highlight color settings
const colorTitle = document.createElement('div');
colorTitle.innerText = 'Highlight Color';
colorTitle.style = `
font-weight: bold;
margin-bottom: 10px;
color: #bababa;
`;
settingsPanel.appendChild(colorTitle);
// Color picker with improved UI
const colorContainer = document.createElement('div');
colorContainer.style = `
display: flex;
flex-direction: column;
margin-bottom: 20px;
`;
// Color presets
const presetColors = ['#7fa650', '#f1c40f', '#e74c3c', '#3498db', '#9b59b6'];
const presetContainer = document.createElement('div');
presetContainer.style = `
display: flex;
margin-bottom: 10px;
gap: 8px;
`;
presetColors.forEach(color => {
const preset = document.createElement('div');
preset.style = `
width: 24px;
height: 24px;
background-color: ${color};
border-radius: 4px;
cursor: pointer;
border: 2px solid ${color === myVars.bestMoveHighlightColor ? '#bababa' : 'transparent'};
`;
preset.addEventListener('click', function() {
colorInput.value = color;
colorValue.innerText = color;
myVars.bestMoveHighlightColor = color;
// Update borders
presetContainer.querySelectorAll('div').forEach(el => {
el.style.border = '2px solid transparent';
});
preset.style.border = '2px solid #bababa';
});
presetContainer.appendChild(preset);
});
colorContainer.appendChild(presetContainer);
// Custom color picker
const customColorContainer = document.createElement('div');
customColorContainer.style = `
display: flex;
align-items: center;
`;
const colorInput = document.createElement('input');
colorInput.type = 'color';
colorInput.value = myVars.bestMoveHighlightColor;
colorInput.style = `
width: 30px;
height: 30px;
margin-right: 10px;
padding: 0;
border: none;
cursor: pointer;
`;
const colorValue = document.createElement('span');
colorValue.innerText = myVars.bestMoveHighlightColor;
colorValue.style = `
font-family: monospace;
color: #bababa;
`;
customColorContainer.appendChild(colorInput);
customColorContainer.appendChild(colorValue);
colorContainer.appendChild(customColorContainer);
settingsPanel.appendChild(colorContainer);
// Save and close buttons
const buttonContainer = document.createElement('div');
buttonContainer.style = `
display: flex;
justify-content: space-between;
margin-top: 10px;
`;
const saveButton = document.createElement('button');
saveButton.innerText = 'Save';
saveButton.style = `
background: #7fa650;
border: none;
color: white;
padding: 8px 15px;
border-radius: 3px;
cursor: pointer;
font-weight: bold;
`;
const closeButton = document.createElement('button');
closeButton.innerText = 'Cancel';
closeButton.style = `
background: #3a3634;
border: 1px solid #464442;
color: #bababa;
padding: 8px 15px;
border-radius: 3px;
cursor: pointer;
`;
buttonContainer.appendChild(saveButton);
buttonContainer.appendChild(closeButton);
settingsPanel.appendChild(buttonContainer);
// Add settings panel to screen
settingsScreen.appendChild(settingsPanel);
document.body.appendChild(settingsScreen);
// Event listeners
settingsButton.addEventListener('click', function() {
// Reset form values to current settings
draggableRadio.checked = myVars.panelPosition === 'draggable';
rightRadio.checked = myVars.panelPosition === 'right';
colorInput.value = myVars.bestMoveHighlightColor;
colorValue.innerText = myVars.bestMoveHighlightColor;
// Show settings
settingsScreen.style.display = 'block';
});
closeButton.addEventListener('click', function() {
settingsScreen.style.display = 'none';
});
// Update color value when input changes
colorInput.addEventListener('input', function() {
colorValue.innerText = this.value;
// Update preset borders
presetContainer.querySelectorAll('div').forEach(el => {
el.style.border = '2px solid transparent';
});
// Check if the color matches any preset
const matchingPreset = Array.from(presetContainer.querySelectorAll('div'))
.find(el => el.style.backgroundColor === this.value);
if (matchingPreset) {
matchingPreset.style.border = '2px solid #bababa';
}
});
saveButton.addEventListener('click', function() {
// Save position setting
if (draggableRadio.checked) {
myVars.panelPosition = 'draggable';
GM_setValue('panelPositionType', 'draggable');
} else if (rightRadio.checked) {
myVars.panelPosition = 'right';
GM_setValue('panelPositionType', 'right');
}
// Save color setting
myVars.bestMoveHighlightColor = colorInput.value;
GM_setValue('bestMoveHighlightColor', colorInput.value);
// Clear any existing content and show loading overlay
settingsPanel.innerHTML = '';
// Create loading overlay
const loadingOverlay = document.createElement('div');
loadingOverlay.style = `
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(49, 46, 43, 0.95);
display: flex;
align-items: center;
justify-content: center;
z-index: 10002;
border-radius: 5px;
`;
const saveMessage = document.createElement('div');
saveMessage.innerText = 'Settings saved. Reloading page...';
saveMessage.style = `
color: #7fa650;
font-weight: bold;
font-size: 16px;
text-align: center;
`;
loadingOverlay.appendChild(saveMessage);
settingsScreen.appendChild(loadingOverlay);
// Reload page after 1 second
setTimeout(function() {
location.reload();
}, 1000);
});
// Add settings button to the right side of the header
header.appendChild(settingsButton);
// Create buttons section
const actionsSectionObj = createSection('Actions');
const actionsSection = actionsSectionObj.section;
const actionsContent = actionsSectionObj.content;
const createButton = (text, onClick, primary = false) => {
const button = document.createElement('button');
button.innerText = text;
button.addEventListener('click', onClick);
button.style = `
background-color: ${primary ? '#7fa650' : '#5d5955'};
color: #fff;
border: none;
padding: 10px;
margin-bottom: 10px;
border-radius: 3px;
width: 100%;
cursor: pointer;
font-weight: ${primary ? 'bold' : 'normal'};
transition: background-color 0.2s;
`;
button.addEventListener('mouseover', function() {
this.style.backgroundColor = primary ? '#8fb761' : '#6e6a66';
});
button.addEventListener('mouseout', function() {
this.style.backgroundColor = primary ? '#7fa650' : '#5d5955';
});
return button;
};
const reloadButton = createButton('Reload Chess Engine', () => myFunctions.reloadChessEngine(), true);
const issueButton = createButton('Report an Issue', () => {
window.open('https://greatest.deepsurf.us/en/scripts/534105-chess-com-bot-cheat-by-admin0/feedback', '_blank');
});
const updateButton = createButton('Check for Updates', () => {
window.open('https://greatest.deepsurf.us/en/scripts/534105-chess-com-bot-cheat-by-admin0', '_blank');
});
actionsContent.appendChild(reloadButton);
actionsContent.appendChild(issueButton);
actionsContent.appendChild(updateButton);
scrollContainer.appendChild(actionsSection);
// Create Top Moves section
const topMovesSectionObj = createSection('Top Moves');
const topMovesSection = topMovesSectionObj.section;
const topMovesContent = topMovesSectionObj.content;
// Create container for top moves display
const topMovesContainer = document.createElement('div');
topMovesContainer.style = `
background-color: #3a3634;
border-radius: 4px;
padding: 10px;
`;
// Create header for top moves
const topMovesHeader = document.createElement('div');
topMovesHeader.style = `
display: flex;
justify-content: space-between;
margin-bottom: 8px;
font-size: 12px;
color: #bababa;
opacity: 0.8;
`;
const moveHeader = document.createElement('span');
moveHeader.innerText = 'Move';
const evalHeader = document.createElement('span');
evalHeader.innerText = 'Evaluation';
topMovesHeader.appendChild(moveHeader);
topMovesHeader.appendChild(evalHeader);
topMovesContainer.appendChild(topMovesHeader);
// Create elements for top 2 moves
for (let i = 1; i <= 2; i++) {
const moveRow = document.createElement('div');
moveRow.style = `
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-top: 1px solid #464442;
`;
const moveNumber = document.createElement('span');
moveNumber.style = `
background-color: ${i === 1 ? '#7fa650' : '#5d5955'};
color: white;
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
margin-right: 8px;
`;
moveNumber.innerText = i;
const moveText = document.createElement('span');
moveText.id = `topMove${i}`;
moveText.innerText = '...';
moveText.style = `
font-family: monospace;
font-weight: ${i === 1 ? 'bold' : 'normal'};
`;
const moveLeft = document.createElement('div');
moveLeft.style = `
display: flex;
align-items: center;
`;
moveLeft.appendChild(moveNumber);
moveLeft.appendChild(moveText);
const evalText = document.createElement('span');
evalText.id = `topMoveEval${i}`;
evalText.innerText = '...';
evalText.style = `
font-family: monospace;
color: ${i === 1 ? '#7fa650' : '#bababa'};
`;
moveRow.appendChild(moveLeft);
moveRow.appendChild(evalText);
topMovesContainer.appendChild(moveRow);
}
topMovesContent.appendChild(topMovesContainer);
scrollContainer.appendChild(topMovesSection);
// Make the header draggable only in draggable mode
header.style.cursor = positionType === 'draggable' ? 'move' : 'default';
header.style.userSelect = 'none'; // Prevent text selection during drag
// No visual indicator here - we'll add a single one later
// Make panel draggable with improved handling (only when in draggable mode)
let isDragging = false;
let offsetX, offsetY;
// Only set up dragging if in draggable mode
if (positionType === 'draggable') {
// Use mousedown on header for dragging
header.addEventListener('mousedown', function(e) {
// Only initiate drag if clicking on the header itself, the drag handle, or its children
if (e.target === header || e.target === dragHandle || e.target === gripIcon || e.target === title || e.target === version) {
e.preventDefault(); // Prevent text selection during drag
isDragging = true;
// Calculate offset from the panel's top-left corner
const rect = panel.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
// No appearance change during drag - keep solid
// Capture mouse events on the entire document
document.addEventListener('mousemove', handleDrag);
document.addEventListener('mouseup', stopDrag);
}
});
// Handle dragging
function handleDrag(e) {
if (!isDragging) return;
const newLeft = e.clientX - offsetX;
const newTop = e.clientY - offsetY;
// Keep panel within viewport bounds
const maxX = window.innerWidth - panel.offsetWidth;
const maxY = window.innerHeight - panel.offsetHeight;
panel.style.right = 'auto';
panel.style.top = Math.max(0, Math.min(newTop, maxY)) + 'px';
panel.style.left = Math.max(0, Math.min(newLeft, maxX)) + 'px';
panel.style.transform = 'none';
}
// Stop dragging
function stopDrag() {
if (!isDragging) return;
isDragging = false;
// Save position with more details
const rect = panel.getBoundingClientRect();
GM_setValue('panelPosition', {
top: rect.top,
left: rect.left,
right: 'auto'
});
// Remove temporary event listeners
document.removeEventListener('mousemove', handleDrag);
document.removeEventListener('mouseup', stopDrag);
}
// Add a clean, modern drag handle
const dragHandle = document.createElement('div');
dragHandle.style = `
display: flex;
flex-direction: column;
justify-content: center;
gap: 3px;
margin-right: 8px;
cursor: move;
user-select: none;
width: 16px;
height: 16px;
`;
// Create a simple grip icon for the drag handle
const gripIcon = document.createElement('div');
gripIcon.innerHTML = '≡'; // Unicode triple bar character
gripIcon.style = ``;
dragHandle.appendChild(gripIcon);
header.insertBefore(dragHandle, header.firstChild);
}
// Add footer (outside scroll container)
const footer = document.createElement('div');
footer.style = `
margin-top: 10px;
padding-top: 8px;
border-top: 1px solid #464442;
font-size: 11px;
text-align: center;
opacity: 0.7;
flex-shrink: 0; /* Prevent footer from shrinking */
position: relative; /* For resize handle positioning */
`;
footer.innerText = 'Press ESC to toggle interface';
panel.appendChild(footer);
// Use browser's native resize functionality instead of custom handle
if (positionType === 'draggable') {
// Set panel to be resizable using browser's native resize
panel.style.resize = 'both';
panel.style.overflow = 'auto';
// Add event listener to save dimensions when resizing stops
let resizeTimeout;
const saveResizedDimensions = function() {
// Save new dimensions
const width = panel.offsetWidth;
const height = panel.offsetHeight;
GM_setValue('panelDimensions', {
width: width,
height: height,
minWidth: savedDimensions.minWidth,
minHeight: savedDimensions.minHeight
});
};
// Use resize observer to detect when resizing happens
const resizeObserver = new ResizeObserver(function() {
// Clear previous timeout
clearTimeout(resizeTimeout);
// Set new timeout to save dimensions after resizing stops
resizeTimeout = setTimeout(saveResizedDimensions, 500);
});
// Start observing the panel
resizeObserver.observe(panel);
}
// Append panel to body
document.body.appendChild(panel);
loaded = true;
console.log("[UI] Chess.com themed interface created successfully");
} catch (error) {
console.error("[UI] Error creating interface:", error);
}
};
// Main interval loop
const waitForChessBoard = setInterval(() => {
if (loaded) {
board = $('chess-board')[0] || $('wc-chess-board')[0];
// Read checkbox states directly from DOM
try {
myVars.suggestMove = document.getElementById('suggestMove').checked;
myVars.autoMove = document.getElementById('autoMove').checked;
myVars.autoMatch = document.getElementById('autoMatch').checked;
// Save the current state
GM_setValue('suggestMove', myVars.suggestMove);
GM_setValue('autoMove', myVars.autoMove);
GM_setValue('autoMatch', myVars.autoMatch);
// Read delay values
let minDelay = parseFloat(document.getElementById('timeDelayMin').value) || 0.1;
let maxDelay = parseFloat(document.getElementById('timeDelayMax').value) || 1.0;
myVars.delay = Math.random() * (maxDelay - minDelay) + minDelay;
} catch (e) {
console.warn("[UI] Error reading UI state:", e);
}
// Update spinner
myVars.isThinking = isThinking;
myFunctions.spinner();
// Check for game over
const gameOverModal = $('.game-over-modal-content');
if (gameOverModal.length > 0 && !myVars.gameEnded) {
console.log("[Game] Game over detected");
myVars.gameEnded = true;
myVars.hasAutoMatched = false;
}
// Check turn
try {
if (!myVars.gameEnded && board && board.game) {
myTurn = (board.game.getTurn() == board.game.getPlayingAs());
} else {
myTurn = false;
}
} catch (e) {
myTurn = false;
}
// Log state (for debugging)
console.log(`[State] SuggestMove:${myVars.suggestMove} AutoMove:${myVars.autoMove} AutoMatch:${myVars.autoMatch} MyTurn:${myTurn} Thinking:${isThinking} CanGo:${canGo}`);
// Make sure engine is loaded
if (!engine.engine) {
myFunctions.loadChessEngine();
}
// Auto Run Logic (Now Suggested Move Logic)
if (myVars.suggestMove && canGo && !isThinking && myTurn && !myVars.gameEnded) {
console.log("[Auto] Triggering suggested move analysis...");
canGo = false;
const currentDelay = myVars.delay * 1000;
other(currentDelay);
}
// Auto Match Logic
if (myVars.autoMatch && myVars.gameEnded && !myVars.hasAutoMatched) {
console.log("[Auto] Triggering auto match...");
myFunctions.startNewGame();
}
} else if ($('chess-board, wc-chess-board').length > 0) {
// Try to load UI if not loaded yet
myFunctions.loadEx();
}
}, 100);
}
// Global variables
var isThinking = false;
var canGo = true;
var myTurn = false;
var board;
// Add CSS to hide the menu icon
const hideMenuStyle = document.createElement('style');
hideMenuStyle.textContent = `
.GM_menuCommand,
#GM_menu,
#GM_menu_button,
.tampermonkey-menu-button,
div[id^="tampermonkey-menu"],
div[class^="tampermonkey-menu"],
div[style*="position: fixed; right: auto; top: 59px; left: 420px;"],
div[style*="position:fixed;right:auto;top:59px;left:420px;"],
div[style*="z-index: 9999"]:not(#chessBot):not(#overlay):not(#chessBot-settings),
div[id$="-menu"],
div[class$="-menu"],
div[style*="=="],
div[style*="$0"] {
display: none !important;
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
`;
document.head.appendChild(hideMenuStyle);
// Register menu commands but they'll be hidden by CSS
function registerHiddenMenuCommands() {
// Register menu commands for functionality but they'll be hidden
GM_registerMenuCommand("Chess.com Bot v2.0.0", function() {
// Toggle visibility of the bot panel
const panel = document.getElementById('chessBot');
if (panel) {
panel.style.display = panel.style.display === 'none' ? 'flex' : 'none';
}
});
}
// Call this after the document is loaded
setTimeout(registerHiddenMenuCommands, 1000);
// Function to remove specific unwanted elements
function removeUnwantedElements() {
// Find and remove elements with style containing "=="
const elements = document.querySelectorAll('div');
for (const el of elements) {
if (el.getAttribute('style') &&
(el.getAttribute('style').includes('==') ||
el.getAttribute('style').includes('$0'))) {
el.remove();
}
}
// Keep checking periodically
setTimeout(removeUnwantedElements, 1000);
}
// Start removing unwanted elements
setTimeout(removeUnwantedElements, 500);
// Start the script
window.addEventListener("load", (event) => {
console.log("[Script] Chess.com Bot v2.0.0 starting...");
main();
});