您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Advanced bot for the Stake Mines game with customizable, savable strategies including static, random, and hybrid tile selection.
// ==UserScript== // @name Stake Mines Bot // @namespace http://tampermonkey.net/ // @version 1.9 // @description Advanced bot for the Stake Mines game with customizable, savable strategies including static, random, and hybrid tile selection. // @author shdw_lol & Gemini // @license MIT // @match *://stake.com/casino/games/mines* // @match *://stake.us/casino/games/mines* // @grant GM_addStyle // @run-at document-idle // ==/UserScript== (function() { 'use strict'; // --- CONFIGURATION & STATE --- const SELECTORS = { betButton: '[data-testid="bet-button"]', cashoutButton: '[data-testid="cashout-button"]', amountInput: '[data-testid="input-game-amount"]', minesCountInput: '[data-testid="mines-count"]', profitDisplay: '[data-testid="profit-input"]', gameGrid: '[data-testid="game-mines"]', allGameTiles: '[data-testid="game-mines"] > button', activeTiles: '[data-testid="mines-tile"]:not([disabled])', revealedMine: '.mine.revealed', }; const state = { running: false, pausedForManual: false, baseBet: 0.01, currentBet: 0.01, betCount: 0, totalProfit: 0, winStreak: 0, lossStreak: 0, lastBetWasWin: null, tileHighlight: null, }; let activeStrategy = {}; let savedStrategies = {}; let logEntries = []; let manualLossObserver = null; // --- UI (HTML & CSS) --- const botHtml = ` <div id="mines-bot-window" class="bot-window"> <div id="bot-header" class="bot-header"> <span>Stake Mines Bot <span id="bot-status-indicator"></span> <span id="profit-loss-display"></span></span> <div class="window-controls"> <button id="minimize-btn" class="window-btn" title="Minimize">—</button> <button id="close-btn" class="window-btn" title="Close">×</button> </div> </div> <div id="bot-main-content" class="bot-content"> <div class="bot-tabs"> <button class="bot-tab-btn active" data-tab="main">Auto</button> <button class="bot-tab-btn" data-tab="strategy">Strategy</button> <button class="bot-tab-btn" data-tab="log">Log</button> </div> <!-- Main Auto Tab --> <div id="tab-main" class="bot-tab-content active"> <div class="bot-input-group"><label>Base Bet Amount</label><input type="number" id="base-bet" class="bot-input" value="0.01" step="0.01"></div> <div class="bot-input-group"> <label>Strategy</label> <select id="auto-strategy-select" class="bot-input"></select> </div> <div id="no-strategy-container"> <div class="bot-input-group"> <label>Number of Random Tiles to Pick</label> <input type="number" id="simple-random-count" class="bot-input" value="3" min="1" max="24"> </div> </div> <hr> <div class="bot-input-group on-action"><label>On Win</label><select id="on-win-action" class="bot-input"><option value="reset">Reset to Base</option><option value="increase">Increase by %</option></select><input type="number" id="on-win-increase" class="bot-input" value="0" min="0"></div> <div class="bot-input-group on-action"><label>On Loss</label><select id="on-loss-action" class="bot-input"><option value="increase">Increase by %</option><option value="reset">Reset to Base</option></select><input type="number" id="on-loss-increase" class="bot-input" value="100" min="0"></div> <hr> <div class="bot-input-group"><label>Stop on Profit > </label><input type="number" id="stop-profit" class="bot-input" value="0" placeholder="0 = off"></div> <div class="bot-input-group"><label>Stop on Loss < </label><input type="number" id="stop-loss" class="bot-input" value="0" placeholder="0 = off"></div> <button id="start-stop-btn" class="bot-btn bot-btn-primary">Start Auto</button> <button id="cashout-now-btn" class="bot-btn bot-btn-secondary" style="display: none;">Cashout Now & Continue</button> </div> <!-- Strategy Tab --> <div id="tab-strategy" class="bot-tab-content"> <div class="bot-input-group"> <label>Your Saved Strategies</label> <select id="strategy-list" class="bot-input"></select> </div> <div class="btn-grid"> <button id="create-strategy-btn" class="bot-btn bot-btn-secondary">Create New Strategy</button> <button id="edit-strategy-btn" class="bot-btn bot-btn-secondary">Edit Selected</button> </div> <button id="delete-strategy-btn" class="bot-btn bot-btn-danger">Delete Selected</button> <hr> <div id="strategy-editor-container" style="display: none;"> <div class="bot-input-group"><label>Strategy Name</label><input type="text" id="strategy-name" class="bot-input" placeholder="My Awesome Strategy"></div> <div class="bot-input-group"> <label>Tile Selection Mode</label> <select id="tile-mode" class="bot-input"> <option value="static">Static</option> <option value="random">Random</option> <option value="hybrid">Hybrid</option> </select> </div> <div id="static-picker-container"> <label>Static Tiles (Hover to preview)</label> <div id="tile-picker-grid"></div> </div> <div id="random-picker-container" class="bot-input-group" style="display:none;"> <label>Number of Random Tiles to Pick</label> <input type="number" id="random-tile-count" class="bot-input" value="3" min="1" max="24"> </div> <div class="bot-input-group" id="gem-target-container"> <label>Total Tiles to Pick</label> <input type="number" id="gem-target" class="bot-input" value="5" min="1" max="24"> </div> <div class="bot-input-group"> <label>After Picking Tiles...</label> <select id="after-reveal-action" class="bot-input"> <option value="cashout">Auto-Cashout</option> <option value="manual">Pause for Manual</option> </select> </div> <div class="bot-input-group"> <label>Delay Between Clicks (ms)</label> <input type="number" id="click-delay" class="bot-input" value="200" min="50"> </div> <button id="save-strategy-btn" class="bot-btn bot-btn-primary">Save Strategy</button> <button id="cancel-edit-btn" class="bot-btn bot-btn-secondary">Cancel</button> </div> </div> <!-- Log Tab --> <div id="tab-log" class="bot-tab-content"> <div id="log-container"></div> <div class="btn-grid"> <button id="reset-stats-btn" class="bot-btn bot-btn-danger">Reset Stats</button> <button id="save-log-btn" class="bot-btn bot-btn-secondary">Save Log</button> </div> </div> </div> <div id="mines-bot-minimized-bar" style="display: none;"> <span>Mines Bot</span> <button id="maximize-btn" class="window-btn" title="Maximize">□</button> </div> </div> <div id="tile-highlight-overlay"></div> `; const botCss = ` :root { --bg-primary: #0F212E; --bg-secondary: #213743; --accent-green: #00b373; --accent-red: #e53e3e; --accent-yellow: #FFC107; --accent-blue: #3498db; } .bot-window { position: fixed; top: 100px; right: 20px; width: 400px; background-color: var(--bg-primary); border-radius: 8px; z-index: 9999; color: #fff; font-family: 'Inter', sans-serif; box-shadow: 0 5px 15px rgba(0,0,0,0.5); display: flex; flex-direction: column; max-height: 85vh; } .bot-header { padding: 10px 15px; cursor: move; background-color: var(--bg-secondary); font-weight: 600; user-select: none; display: flex; justify-content: space-between; align-items: center; } #bot-status-indicator { font-weight: normal; font-size: 12px; opacity: 0.8; margin-left: 8px; } #profit-loss-display { font-weight: 600; font-size: 12px; margin-left: 10px; } #profit-loss-display.profit { color: var(--accent-green); } #profit-loss-display.loss { color: var(--accent-red); } .window-controls { display: flex; gap: 8px; } .window-btn { background: none; border: none; color: #b1bad3; font-size: 20px; cursor: pointer; line-height: 1; padding: 0 5px; } .bot-content { padding: 15px; flex-grow: 1; display: flex; flex-direction: column; min-height: 0; } .bot-tabs { display: flex; margin-bottom: 15px; background-color: var(--bg-primary); border-radius: 20px; padding: 4px; border: 1px solid var(--bg-secondary); } .bot-tab-btn { flex: 1; padding: 8px; cursor: pointer; background: transparent; border: none; color: #b1bad3; border-radius: 20px; font-weight: 500; transition: all 0.2s ease-in-out; font-size: 13px; } .bot-tab-btn.active { background-color: var(--bg-secondary); color: #fff; } .bot-tab-content { display: none; } .bot-tab-content.active { display: block; flex: 1; min-height: 0; overflow-y: auto; padding-right: 10px; } .bot-input-group { margin-bottom: 12px; display: flex; flex-direction: column; } .bot-input-group label { margin-bottom: 5px; font-size: 14px; color: #b1bad3; } .bot-input { width: 100%; padding: 8px; background-color: var(--bg-primary); border: 1px solid var(--bg-secondary); border-radius: 4px; color: #fff; box-sizing: border-box; } .bot-input-group.on-action { display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center; } .bot-input-group.on-action label { grid-column: 1 / 2; } .bot-btn { width: 100%; padding: 12px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 600; margin-top: 10px; } .bot-btn:disabled { background-color: #4A5568 !important; cursor: not-allowed; opacity: 0.7; } .bot-btn-primary { background-color: var(--accent-green); color: #fff; } .bot-btn-danger { background-color: var(--accent-red); color: #fff; } .bot-btn-secondary { background-color: var(--bg-secondary); color: #fff; } #log-container { height: 350px; overflow-y: auto; padding: 8px; background-color: var(--bg-primary); border: 1px solid var(--bg-secondary); border-radius: 4px; font-size: 12px; line-height: 1.5; } #log-container p { margin: 0 0 5px 0; } #log-container p.log-win { color: var(--accent-green); } #log-container p.log-loss { color: var(--accent-red); } #log-container p.log-info { color: var(--accent-yellow); } hr { border: none; border-top: 1px solid var(--bg-secondary); margin: 15px 0; } .btn-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } #tile-picker-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 5px; padding: 5px; background-color: var(--bg-secondary); border-radius: 4px; } .picker-tile { width: 100%; aspect-ratio: 1 / 1; background-color: var(--bg-primary); border: 1px solid #4a5568; border-radius: 4px; cursor: pointer; transition: background-color 0.2s; } .picker-tile.selected { background-color: var(--accent-blue); border-color: #fff; } #mines-bot-minimized-bar { position: fixed; top: 100px; right: 20px; background-color: var(--bg-secondary); border-radius: 8px; z-index: 9999; color: #fff; font-family: 'Inter', sans-serif; box-shadow: 0 5px 15px rgba(0,0,0,0.5); display: none; justify-content: space-between; align-items: center; padding: 8px 12px; cursor: move; } #tile-highlight-overlay { position: fixed; background-color: rgba(255, 193, 7, 0.5); border: 2px solid var(--accent-yellow); z-index: 9998; pointer-events: none; display: none; border-radius: 4px; transition: all 0.05s linear; } `; // --- CORE LOGIC --- function init() { if (document.getElementById('mines-bot-window')) return; document.body.insertAdjacentHTML('beforeend', botHtml); GM_addStyle(botCss); state.tileHighlight = document.getElementById('tile-highlight-overlay'); createTilePicker(); loadStrategies(); populateStrategyDropdowns(); handleAutoStrategyChange(); setupEventListeners(); makeDraggable(document.getElementById('mines-bot-window'), document.getElementById('bot-header')); makeDraggable(document.getElementById('mines-bot-minimized-bar'), document.getElementById('mines-bot-minimized-bar')); document.getElementById('mines-bot-window').style.display = 'flex'; log("Mines Bot Initialized.", "info"); } function setupEventListeners() { document.getElementById('minimize-btn').addEventListener('click', minimizeBot); document.getElementById('maximize-btn').addEventListener('click', maximizeBot); document.getElementById('close-btn').addEventListener('click', () => document.getElementById('mines-bot-window').remove()); document.querySelectorAll('.bot-tab-btn').forEach(btn => { btn.addEventListener('click', (e) => { const tabName = e.target.dataset.tab; document.querySelectorAll('.bot-tab-btn, .bot-tab-content').forEach(el => el.classList.remove('active')); e.target.classList.add('active'); document.getElementById(`tab-${tabName}`).classList.add('active'); }); }); document.getElementById('start-stop-btn').addEventListener('click', toggleBot); document.getElementById('cashout-now-btn').addEventListener('click', handleManualCashout); const autoStrategySelect = document.getElementById('auto-strategy-select'); const strategyListSelect = document.getElementById('strategy-list'); autoStrategySelect.addEventListener('change', () => { strategyListSelect.value = autoStrategySelect.value; handleAutoStrategyChange(); }); strategyListSelect.addEventListener('change', () => { autoStrategySelect.value = strategyListSelect.value; handleAutoStrategyChange(); }); document.getElementById('create-strategy-btn').addEventListener('click', () => showStrategyEditor(false)); document.getElementById('edit-strategy-btn').addEventListener('click', () => showStrategyEditor(true)); document.getElementById('cancel-edit-btn').addEventListener('click', hideStrategyEditor); document.getElementById('tile-mode').addEventListener('change', updateStrategyUI); document.getElementById('save-strategy-btn').addEventListener('click', saveStrategy); document.getElementById('delete-strategy-btn').addEventListener('click', deleteStrategy); document.getElementById('reset-stats-btn').addEventListener('click', resetState); document.getElementById('save-log-btn').addEventListener('click', saveLogToFile); } function toggleBot() { if (state.running) { stopBot("Stopped by user."); } else { startBot(); } } function startBot() { state.running = true; const btn = document.getElementById('start-stop-btn'); btn.textContent = 'Stop Auto'; btn.classList.remove('bot-btn-primary'); btn.classList.add('bot-btn-danger'); updateSettingsFromUI(); resetState(); const strategyName = document.getElementById('auto-strategy-select').value; if (strategyName === 'none') { log(`Bot started with NO STRATEGY. Picking ${document.getElementById('simple-random-count').value} random tiles.`, "info"); } else { log(`Bot started with strategy: "${strategyName}"`, "info"); } runGameRound(); } function stopBot(reason) { state.running = false; state.pausedForManual = false; stopManualLossDetector(); const btn = document.getElementById('start-stop-btn'); btn.textContent = 'Start Auto'; btn.classList.add('bot-btn-primary'); btn.classList.remove('bot-btn-danger'); document.getElementById('cashout-now-btn').style.display = 'none'; updateStatus("Stopped"); log(reason, "info"); } async function runGameRound() { if (!state.running) return; if (activeStrategy.stopProfit > 0 && state.totalProfit >= activeStrategy.stopProfit) { stopBot(`Take Profit target of ${activeStrategy.stopProfit} reached.`); return; } if (activeStrategy.stopLoss > 0 && state.totalProfit <= -activeStrategy.stopLoss) { stopBot(`Stop Loss target of -${activeStrategy.stopLoss} reached.`); return; } updateStatus("Starting round..."); await setBetAmount(state.currentBet); const valueSetCorrectly = await waitForValue(SELECTORS.amountInput, state.currentBet); if (!valueSetCorrectly) { stopBot("Error: Failed to set bet amount correctly."); return; } const betButton = document.querySelector(SELECTORS.betButton); if (!betButton || betButton.disabled) { await sleep(1000); if (state.running) runGameRound(); return; } betButton.click(); await waitForTrue(() => document.querySelector(SELECTORS.activeTiles), 2000); const tilesToClick = determineTilesToClick(); if (tilesToClick.length === 0) { stopBot("Error: Strategy resulted in 0 tiles to click."); return; } updateStatus(`Picking ${tilesToClick.length} tiles...`); let gemsFound = 0; let roundLost = false; for (const tileIndex of tilesToClick) { if (!state.running) return; const allTiles = document.querySelectorAll(SELECTORS.activeTiles); const tile = allTiles[tileIndex]; if (tile) { tile.click(); if (await checkForMine(500)) { roundLost = true; break; } gemsFound++; await sleep(activeStrategy.clickDelay); } } await sleep(250); if (roundLost) { handleRoundEnd(false); } else { const isGameOver = await checkForMine(100); const cashoutButton = document.querySelector(SELECTORS.cashoutButton); const isGameActive = cashoutButton && !cashoutButton.disabled; if (isGameOver || !isGameActive) { log("Failsafe triggered: Game ended on last click.", "info"); handleRoundEnd(false); } else if (activeStrategy.afterRevealAction === 'manual') { state.pausedForManual = true; updateStatus(`Paused. ${gemsFound} gems found. Cashout or continue manually.`); log(`Paused for manual action. Profit if cashout: ${getProfitValue()}`, "info"); document.getElementById('cashout-now-btn').style.display = 'block'; startManualLossDetector(); } else { updateStatus("Cashing out..."); cashoutButton.click(); handleRoundEnd(true); } } } async function handleRoundEnd(isWin) { state.betCount++; const profit = isWin ? getProfitValue(true) : -state.currentBet; state.totalProfit += profit; state.lastBetWasWin = isWin; if (isWin) { state.winStreak++; state.lossStreak = 0; log(`Round #${state.betCount} WIN. Profit: ${profit.toFixed(8)}`, "win"); } else { state.lossStreak++; state.winStreak = 0; log(`Round #${state.betCount} LOSS. Lost: ${state.currentBet.toFixed(8)}`, "loss"); } updateProfitDisplay(); updateNextBetAmount(isWin); await waitForTrue(() => { const btn = document.querySelector(SELECTORS.betButton); return btn && !btn.disabled; }, 5000); if (state.running) { setTimeout(runGameRound, 1000); } } function handleManualCashout() { stopManualLossDetector(); document.querySelector(SELECTORS.cashoutButton)?.click(); state.pausedForManual = false; document.getElementById('cashout-now-btn').style.display = 'none'; updateStatus("Cashed out. Continuing..."); handleRoundEnd(true); } // --- STRATEGY & TILE LOGIC --- function determineTilesToClick() { const strategyName = document.getElementById('auto-strategy-select').value; if (strategyName === 'none') { const count = parseInt(document.getElementById('simple-random-count').value) || 1; return getRandomTiles(count, []); } const { tileMode, staticTiles, randomTileCount, gemTarget } = activeStrategy; const maxGems = 25 - getMinesCount(); let targetCount = 0; if (tileMode === 'hybrid') { targetCount = (staticTiles?.length || 0) + (randomTileCount || 0); } else { targetCount = gemTarget; } const target = Math.min(targetCount, maxGems); let staticPicks = staticTiles || []; let finalPicks = []; if (tileMode === 'static') { finalPicks = staticPicks.slice(0, target); } else if (tileMode === 'random') { finalPicks = getRandomTiles(target, []); } else if (tileMode === 'hybrid') { finalPicks = [...staticPicks]; const randomNeeded = target - finalPicks.length; if (randomNeeded > 0) { finalPicks.push(...getRandomTiles(randomNeeded, finalPicks)); } } return finalPicks; } function getRandomTiles(count, exclude = []) { const available = []; for (let i = 0; i < 25; i++) { if (!exclude.includes(i)) { available.push(i); } } const randomTiles = []; for (let i = 0; i < count && available.length > 0; i++) { const randomIndex = Math.floor(Math.random() * available.length); randomTiles.push(available.splice(randomIndex, 1)[0]); } return randomTiles; } function createTilePicker() { const grid = document.getElementById('tile-picker-grid'); for (let i = 0; i < 25; i++) { const tile = document.createElement('div'); tile.className = 'picker-tile'; tile.dataset.index = i; tile.addEventListener('click', () => tile.classList.toggle('selected')); tile.addEventListener('mouseover', () => highlightGameTile(i, true)); tile.addEventListener('mouseout', () => highlightGameTile(i, false)); grid.appendChild(tile); } } function highlightGameTile(index, show) { if (!state.tileHighlight) return; if (!show) { state.tileHighlight.style.display = 'none'; return; } const gameTiles = document.querySelectorAll(SELECTORS.allGameTiles); const targetTile = gameTiles[index]; if (targetTile) { const rect = targetTile.getBoundingClientRect(); Object.assign(state.tileHighlight.style, { display: 'block', width: `${rect.width}px`, height: `${rect.height}px`, top: `${rect.top}px`, left: `${rect.left}px`, }); } } function updateStrategyUI() { const mode = document.getElementById('tile-mode').value; document.getElementById('static-picker-container').style.display = (mode === 'static' || mode === 'hybrid') ? 'block' : 'none'; document.getElementById('random-picker-container').style.display = (mode === 'random' || mode === 'hybrid') ? 'block' : 'none'; document.getElementById('gem-target-container').style.display = (mode === 'static' || mode === 'random') ? 'block' : 'none'; if (mode === 'hybrid') { document.querySelector('#gem-target-container label').textContent = 'This mode adds random tiles to your static selection.'; } else { document.querySelector('#gem-target-container label').textContent = 'Total Tiles to Pick'; } } // --- DATA & SETTINGS MANAGEMENT --- function updateSettingsFromUI() { const stratName = document.getElementById('auto-strategy-select').value; if (stratName !== 'none') { activeStrategy = savedStrategies[stratName]; } else { activeStrategy = {}; // Clear if no strategy is selected } // Always update these from the main tab activeStrategy.baseBet = parseFloat(document.getElementById('base-bet').value); activeStrategy.onWinAction = document.getElementById('on-win-action').value; activeStrategy.onWinIncrease = parseFloat(document.getElementById('on-win-increase').value); activeStrategy.onLossAction = document.getElementById('on-loss-action').value; activeStrategy.onLossIncrease = parseFloat(document.getElementById('on-loss-increase').value); activeStrategy.stopProfit = parseFloat(document.getElementById('stop-profit').value); activeStrategy.stopLoss = parseFloat(document.getElementById('stop-loss').value); state.baseBet = activeStrategy.baseBet; state.currentBet = activeStrategy.baseBet; } function loadStrategy(name) { const strat = savedStrategies[name]; if (!strat) return; document.getElementById('strategy-name').value = name; document.getElementById('tile-mode').value = strat.tileMode; document.getElementById('random-tile-count').value = strat.randomTileCount; document.getElementById('gem-target').value = strat.gemTarget; document.getElementById('after-reveal-action').value = strat.afterRevealAction; document.getElementById('click-delay').value = strat.clickDelay; document.querySelectorAll('#tile-picker-grid .picker-tile').forEach(tile => { tile.classList.toggle('selected', strat.staticTiles.includes(parseInt(tile.dataset.index))); }); updateStrategyUI(); } function saveStrategy() { const name = document.getElementById('strategy-name').value.trim(); if (!name) { alert("Please enter a name for the strategy."); return; } savedStrategies[name] = { name: name, tileMode: document.getElementById('tile-mode').value, staticTiles: Array.from(document.querySelectorAll('#tile-picker-grid .picker-tile.selected')).map(t => parseInt(t.dataset.index)), randomTileCount: parseInt(document.getElementById('random-tile-count').value), gemTarget: parseInt(document.getElementById('gem-target').value), afterRevealAction: document.getElementById('after-reveal-action').value, clickDelay: parseInt(document.getElementById('click-delay').value), }; localStorage.setItem('stakeMinesBotStrategies', JSON.stringify(savedStrategies)); populateStrategyDropdowns(); document.getElementById('strategy-list').value = name; document.getElementById('auto-strategy-select').value = name; log(`Strategy "${name}" saved.`, "info"); hideStrategyEditor(); } function deleteStrategy() { const name = document.getElementById('strategy-list').value; if (name && name !== 'none' && confirm(`Are you sure you want to delete the strategy "${name}"?`)) { delete savedStrategies[name]; localStorage.setItem('stakeMinesBotStrategies', JSON.stringify(savedStrategies)); populateStrategyDropdowns(); log(`Strategy "${name}" deleted.`, "info"); } } function loadStrategies() { const saved = localStorage.getItem('stakeMinesBotStrategies'); if (saved) { savedStrategies = JSON.parse(saved); } } function populateStrategyDropdowns() { const autoSelect = document.getElementById('auto-strategy-select'); const stratSelect = document.getElementById('strategy-list'); const currentAutoVal = autoSelect.value; const currentStratVal = stratSelect.value; autoSelect.innerHTML = '<option value="none">No Strategy (Random Pick)</option>'; stratSelect.innerHTML = ''; for (const name in savedStrategies) { autoSelect.add(new Option(name, name)); stratSelect.add(new Option(name, name)); } autoSelect.value = savedStrategies[currentAutoVal] ? currentAutoVal : 'none'; stratSelect.value = savedStrategies[currentStratVal] ? currentStratVal : ''; } function showStrategyEditor(isEditing) { if (isEditing) { const selectedStrategy = document.getElementById('strategy-list').value; if (!selectedStrategy) { alert("Please select a strategy to edit."); return; } loadStrategy(selectedStrategy); } else { // Clear the form for a new strategy document.getElementById('strategy-name').value = ''; document.getElementById('tile-mode').value = 'static'; document.querySelectorAll('.picker-tile.selected').forEach(t => t.classList.remove('selected')); document.getElementById('random-tile-count').value = 3; document.getElementById('gem-target').value = 5; updateStrategyUI(); } document.getElementById('strategy-editor-container').style.display = 'block'; } function hideStrategyEditor() { document.getElementById('strategy-editor-container').style.display = 'none'; } function handleAutoStrategyChange() { const strategyName = document.getElementById('auto-strategy-select').value; document.getElementById('no-strategy-container').style.display = strategyName === 'none' ? 'block' : 'none'; } // --- HELPER & UTILITY FUNCTIONS --- function startManualLossDetector() { const gameGrid = document.querySelector(SELECTORS.gameGrid); if (!gameGrid) return; manualLossObserver = new MutationObserver((mutations) => { for (const mutation of mutations) { if (mutation.target.matches(SELECTORS.revealedMine)) { log("Manual loss detected. Restarting bot...", "info"); state.pausedForManual = false; document.getElementById('cashout-now-btn').style.display = 'none'; stopManualLossDetector(); handleRoundEnd(false); break; } } }); manualLossObserver.observe(gameGrid, { subtree: true, attributes: true, attributeFilter: ['class'] }); } function stopManualLossDetector() { if (manualLossObserver) { manualLossObserver.disconnect(); manualLossObserver = null; } } async function checkForMine(timeout = 500) { const startTime = Date.now(); while (Date.now() - startTime < timeout) { if (document.querySelector(SELECTORS.revealedMine)) { return true; } await sleep(50); } return false; } async function waitForTrue(conditionFn, timeout = 2000) { const startTime = Date.now(); while (Date.now() - startTime < timeout) { if (conditionFn()) { return true; } await sleep(50); } return false; } async function waitForValue(selector, expectedValue, timeout = 2000) { const input = document.querySelector(selector); if (!input) return false; const startTime = Date.now(); const targetValue = parseFloat(expectedValue.toFixed(8)); while (Date.now() - startTime < timeout) { const currentValue = parseFloat(input.value); if (currentValue === targetValue) { return true; } await sleep(50); } log(`Timeout waiting for bet amount to update to ${targetValue}. Current value: ${input.value}`, 'error'); return false; } function updateNextBetAmount(isWin) { if (isWin) { state.currentBet = activeStrategy.onWinAction === 'reset' ? state.baseBet : state.currentBet * (1 + activeStrategy.onWinIncrease / 100); } else { state.currentBet = activeStrategy.onLossAction === 'reset' ? state.baseBet : state.currentBet * (1 + activeStrategy.onLossIncrease / 100); } state.currentBet = Math.max(0.00000001, state.currentBet); } function getProfitValue(isWin = false) { const el = document.querySelector(SELECTORS.cashoutButton); if (!el) return 0; const match = el.textContent.match(/[\d.]+/); return match ? parseFloat(match[0]) : 0; } function getMinesCount() { const el = document.querySelector(SELECTORS.minesCountInput); return el ? parseInt(el.value) || 3 : 3; } async function setBetAmount(amount) { const input = document.querySelector(SELECTORS.amountInput); const gameGrid = document.querySelector(SELECTORS.gameGrid); if (input && gameGrid) { input.focus(); const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set; nativeInputValueSetter.call(input, amount.toFixed(8)); input.dispatchEvent(new Event('input', { bubbles: true })); await sleep(50); gameGrid.click(); } } function resetState() { state.betCount = 0; state.totalProfit = 0; state.winStreak = 0; state.lossStreak = 0; updateProfitDisplay(); } function updateProfitDisplay() { const el = document.getElementById('profit-loss-display'); const profit = state.totalProfit; el.textContent = `${profit >= 0 ? '+' : ''}${profit.toFixed(8)}`; el.className = profit > 0 ? 'profit' : (profit < 0 ? 'loss' : ''); } function updateStatus(text) { document.getElementById('bot-status-indicator').textContent = `- ${text}`; } function log(message, type) { const container = document.getElementById('log-container'); const entry = document.createElement('p'); const timestamp = new Date().toLocaleTimeString(); entry.innerHTML = `[${timestamp}] ${message}`; entry.className = `log-${type}`; container.appendChild(entry); container.scrollTop = container.scrollHeight; logEntries.push(`[${timestamp}] ${message}`); } function saveLogToFile() { const blob = new Blob([logEntries.join('\n')], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `stake_mines_bot_log_${new Date().toISOString()}.txt`; a.click(); URL.revokeObjectURL(url); } function minimizeBot() { document.getElementById('bot-main-content').style.display = 'none'; document.getElementById('mines-bot-minimized-bar').style.display = 'flex'; } function maximizeBot() { document.getElementById('bot-main-content').style.display = 'block'; document.getElementById('mines-bot-minimized-bar').style.display = 'none'; } function makeDraggable(element, handle) { let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; handle.onmousedown = (e) => { e.preventDefault(); pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = () => { document.onmouseup = null; document.onmousemove = null; }; document.onmousemove = (e) => { e.preventDefault(); pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; element.style.top = (element.offsetTop - pos2) + "px"; element.style.left = (element.offsetLeft - pos1) + "px"; }; }; } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // --- SCRIPT INITIALIZATION --- window.addEventListener('load', () => { setTimeout(init, 2000); }); })();