// ==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);
});
})();