Загрузка данных
if (window.minerInterval) clearInterval(window.minerInterval);
if (window.oreCheckInterval) clearInterval(window.oreCheckInterval);
(function() {
'use strict';
console.log("⛏️ Авто-шахтер v32.1 (фикс приоритета сундука) запущен.");
const CLICK_COOLDOWN = 4000;
const POST_ROCK_PAUSE = 3000;
const LIFT_CHECK_COOLDOWN = 2000;
const FLOOR_CHANGE_TIMEOUT = 15000;
const FLOOR_SETTLE_MS = 3000;
const NO_ORE_LIFT_COOLDOWN = 15000;
const ORE_CHECK_INTERVAL = 2000;
const PRIO_CHEST = -2;
const PRIO_UNKNOWN = -1;
const PRIO_IRON = 0;
const PRIO_COAL = 1;
const PRIO_OTHER = 2;
const PRIO_STONE = 3;
let lastClickTime = 0;
let wasDigging = false;
let pauseUntil = 0;
let lastLiftCheck = 0;
let lastKnownFloor = null;
let lastFloorChangeAt = 0;
let liftAttemptedAt = 0;
let pendingTargetFloor = null;
let liftInProgress = false;
let lastNoOreLiftAttempt = 0;
let lastHeartbeat = 0;
let walkStartTime = 0;
let currentTargetPriority = PRIO_UNKNOWN;
let oreCheckCount = 0;
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
function isVisible(el) {
if (!el || !el.isConnected) return false;
const r = el.getBoundingClientRect();
if (r.width < 2 || r.height < 2) return false;
if (r.right < 0 || r.bottom < 0 || r.left > window.innerWidth || r.top > window.innerHeight) return false;
const cs = getComputedStyle(el);
return cs.visibility !== 'hidden' && cs.display !== 'none' && cs.opacity !== '0';
}
function norm(el) { return (el.textContent || '').replace(/\s+/g, ' ').trim(); }
function findClickableByText(text) {
const wanted = text.toLowerCase();
const nodes = document.querySelectorAll('button, [role="button"], .btn, .mn-btn, a, div, span, li');
let best = null;
let bestKids = Infinity;
for (const el of nodes) {
const t = norm(el);
if (!t || t.length > 40) continue;
if (t.toLowerCase() !== wanted) continue;
if (!isVisible(el)) continue;
const kids = el.querySelectorAll('*').length;
if (kids < bestKids) { best = el; bestKids = kids; }
}
return best;
}
async function waitFor(fn, timeout = 2000, interval = 100) {
const start = Date.now();
while (Date.now() - start < timeout) {
const v = fn();
if (v) return v;
await sleep(interval);
}
return null;
}
function getCurrentFloor() {
const el = document.querySelector('[data-mn="floor"]');
if (el) {
const m = el.textContent.match(/(\d+)/);
if (m) return parseInt(m[1], 10);
}
return lastKnownFloor;
}
function getLiftRange() {
const lift = document.querySelector('[data-obj="lift"]');
if (!lift) return null;
for (const t of lift.querySelectorAll('text, span, b')) {
const m = (t.textContent || '').match(/(\d+)\s*[-–—]\s*(\d+)/);
if (m) return { min: +m[1], max: +m[2], raw: t.textContent.trim() };
}
return null;
}
function getLiftClickTarget() {
const lift = document.querySelector('[data-obj="lift"]');
if (!lift) return null;
for (const t of lift.querySelectorAll('text')) {
if (t.textContent.trim() === 'ЛИФТ') return t;
}
return lift;
}
function findFloorButton(floor) {
const byRide = document.querySelector(`[data-mn-ride="${floor}"]`);
if (byRide && isVisible(byRide)) return byRide;
const nodes = document.querySelectorAll('button, [role="button"], .btn, .mn-win div, .mn-win span, .mn-win a');
for (const el of nodes) {
if (norm(el) === String(floor) && isVisible(el)) return el;
}
return null;
}
async function tryGoUp(targetFloor) {
if (liftInProgress) return false;
liftInProgress = true;
currentTargetPriority = PRIO_UNKNOWN;
pendingTargetFloor = targetFloor;
liftAttemptedAt = Date.now();
try {
let floorBtn = findFloorButton(targetFloor);
if (floorBtn) {
console.log(`🔼 Лифт: этаж ${targetFloor} виден сразу, клик`);
simulateRealClick(floorBtn);
await sleep(1200);
lastKnownFloor = targetFloor;
lastFloorChangeAt = Date.now();
pendingTargetFloor = null;
return true;
}
let etazhi = findClickableByText('Этажи');
if (!etazhi) {
const target = getLiftClickTarget();
if (!target) { pendingTargetFloor = null; return false; }
simulateRealClick(target);
await sleep(400);
etazhi = await waitFor(() => findClickableByText('Этажи'), 2000, 100);
}
if (etazhi) {
simulateRealClick(etazhi);
await sleep(400);
}
floorBtn = await waitFor(() => findFloorButton(targetFloor), 2500, 100);
if (floorBtn) {
console.log(`🔼 Лифт: перехожу на этаж ${targetFloor}`);
simulateRealClick(floorBtn);
await sleep(1200);
lastKnownFloor = targetFloor;
lastFloorChangeAt = Date.now();
pendingTargetFloor = null;
return true;
}
pendingTargetFloor = null;
return false;
} catch (e) {
pendingTargetFloor = null;
return false;
} finally {
liftInProgress = false;
}
}
function simulateRealClick(element) {
if (!element) return false;
let target = element;
let rect = target.getBoundingClientRect();
if (rect.width < 2 || rect.height < 2) {
const inner = element.querySelector('use');
if (inner) {
target = inner;
rect = inner.getBoundingClientRect();
}
}
if (rect.width < 2 || rect.height < 2) {
console.warn('[КЛИК] Элемент невидим, пропуск');
return false;
}
const x = rect.left + rect.width / 2;
const y = rect.top + rect.height / 2;
const finalTarget = document.elementFromPoint(x, y) || target;
const opts = {
bubbles: true, cancelable: true, view: window,
clientX: x, clientY: y, screenX: x, screenY: y,
pointerId: 1, pointerType: 'mouse', isPrimary: true, button: 0, buttons: 1
};
finalTarget.dispatchEvent(new PointerEvent('pointerdown', opts));
finalTarget.dispatchEvent(new MouseEvent('mousedown', opts));
finalTarget.dispatchEvent(new PointerEvent('pointerup', opts));
finalTarget.dispatchEvent(new MouseEvent('mouseup', opts));
finalTarget.dispatchEvent(new MouseEvent('click', opts));
return true;
}
function getPlayerPos() {
const me = document.querySelector('.mn-h.me');
if (!me) return null;
const m = me.style.transform.match(/translate\(([\d.-]+)px,\s*([\d.-]+)px\)/);
if (!m) return null;
return { x: parseFloat(m[1]), y: parseFloat(m[2]) };
}
function getRockPos(el) {
const l = el.style?.left?.match(/([\d.-]+)px/);
const t = el.style?.top?.match(/([\d.-]+)px/);
if (!l || !t) return null;
return { x: parseFloat(l[1]), y: parseFloat(t[1]) };
}
function distance(a, b) {
if (!a || !b) return Infinity;
return Math.hypot(a.x - b.x, a.y - b.y);
}
function getPriority(html) {
if (html.includes('mrc-grotto') || html.includes('mrc-stone') || html.includes('fill="#ffd27a"'))
return PRIO_CHEST;
if (html.includes('mro-iron')) return PRIO_IRON;
if (html.includes('mro-coal')) return PRIO_COAL;
if (/mro-(?!coal|iron)[a-z]+/i.test(html)) return PRIO_OTHER;
return PRIO_STONE;
}
function getPriorityName(p) {
if (p === PRIO_CHEST) return '💰 Сундук';
if (p === PRIO_IRON) return '🪨 Железо';
if (p === PRIO_COAL) return '⚫ Уголь';
if (p === PRIO_OTHER) return '🔸 Другая руда';
if (p === PRIO_UNKNOWN) return '❓ Неизвестно';
return '⏳ Камень';
}
function scanRocks() {
return Array.from(document.querySelectorAll('.mn-rk.hit'));
}
function pickBest(rocks) {
const player = getPlayerPos();
return rocks
.map(r => ({
el: r, rk: r.getAttribute('data-rk'),
priority: getPriority(r.innerHTML),
dist: distance(player, getRockPos(r))
}))
.sort((a, b) => a.priority !== b.priority ? a.priority - b.priority : a.dist - b.dist)[0];
}
window.goNextFloor = function() {
const cur = getCurrentFloor() ?? lastKnownFloor;
const range = getLiftRange();
if (cur === null) { console.log("❌ Этаж не определён."); return; }
const target = cur + 1;
if (range && target > range.max) {
console.log(`⚠️ Выше некуда! Максимум: ${range.max}`);
return;
}
console.log(`🔼 Подъём с ${cur} на ${target}...`);
tryGoUp(target);
};
window.goFloor = function(floorNum) {
const target = parseInt(floorNum, 10);
if (isNaN(target)) { console.log("❌ goFloor(N)"); return; }
const cur = getCurrentFloor() ?? lastKnownFloor;
const range = getLiftRange();
if (cur === target) { console.log(`⚠️ Ты уже на ${target}.`); return; }
if (range && (target < range.min || target > range.max)) {
console.log(`⚠️ Этаж ${target} вне диапазона (${range.min}-${range.max})`);
return;
}
console.log(`🛗 Переход на ${target}...`);
tryGoUp(target);
};
window.oreCheckInterval = setInterval(() => {
if (liftInProgress) return;
if (!document.querySelector('.mn-h.me.dig')) return;
if (currentTargetPriority === PRIO_CHEST) return;
oreCheckCount++;
const currentRocks = scanRocks();
let targetMaxPriority;
if (currentTargetPriority === PRIO_IRON) targetMaxPriority = PRIO_CHEST;
else if (currentTargetPriority === PRIO_COAL) targetMaxPriority = PRIO_IRON;
else targetMaxPriority = PRIO_OTHER;
const betterOres = currentRocks.filter(r => getPriority(r.innerHTML) <= targetMaxPriority);
if (betterOres.length > 0) {
oreCheckCount = 0;
const t = pickBest(betterOres);
console.log(`🏆 Найдено лучше! → ${getPriorityName(t.priority)}`);
currentTargetPriority = t.priority;
simulateRealClick(t.el);
lastClickTime = Date.now();
} else {
console.log(`🔍 Проверок: ${oreCheckCount}, улучшений нет.`);
}
}, ORE_CHECK_INTERVAL);
window.minerInterval = setInterval(() => {
const now = Date.now();
if (now - lastHeartbeat > 10000) {
lastHeartbeat = now;
console.log(`💓 Бот работает. Этаж: ${getCurrentFloor() ?? '?'}`);
}
if (liftInProgress) return;
if (pendingTargetFloor != null) {
const cur = getCurrentFloor();
if (cur != null && cur >= pendingTargetFloor) {
console.log(`✅ Достигнут этаж ${cur}`);
pendingTargetFloor = null;
lastKnownFloor = cur;
lastFloorChangeAt = now;
currentTargetPriority = PRIO_UNKNOWN;
} else if (now - liftAttemptedAt > FLOOR_CHANGE_TIMEOUT) {
pendingTargetFloor = null;
} else {
return;
}
}
if (now - lastLiftCheck > LIFT_CHECK_COOLDOWN) {
lastLiftCheck = now;
const cur = getCurrentFloor();
if (cur != null && cur !== lastKnownFloor) {
console.log(`🔼 Этаж: ${lastKnownFloor} → ${cur}`);
lastKnownFloor = cur;
lastFloorChangeAt = now;
currentTargetPriority = PRIO_UNKNOWN;
}
}
const isDigging = !!document.querySelector('.mn-h.me.dig');
if (isDigging) { wasDigging = true; return; }
if (wasDigging && !isDigging) {
const hasOres = scanRocks().some(r => getPriority(r.innerHTML) <= PRIO_OTHER);
if (!hasOres) pauseUntil = now + POST_ROCK_PAUSE;
wasDigging = false;
}
if (now < pauseUntil) return;
const isWalking = !!document.querySelector('.mn-h.me.walk');
if (isWalking) {
if (!walkStartTime) walkStartTime = now;
if (now - walkStartTime < 10000) return;
} else {
walkStartTime = 0;
}
if (now - lastClickTime < CLICK_COOLDOWN) return;
const rocks = scanRocks();
const ores = rocks.filter(r => getPriority(r.innerHTML) <= PRIO_OTHER);
if (ores.length > 0) {
const t = pickBest(ores);
currentTargetPriority = t.priority;
if (simulateRealClick(t.el)) {
lastClickTime = now;
console.log(`⛏️ Копаю: ${getPriorityName(t.priority)}`);
}
return;
}
const cur = getCurrentFloor() ?? lastKnownFloor;
const range = getLiftRange();
const justArrived = (now - lastFloorChangeAt < FLOOR_SETTLE_MS);
if (cur != null && range && range.max >= cur + 1 && !justArrived && now - lastNoOreLiftAttempt > NO_ORE_LIFT_COOLDOWN) {
lastNoOreLiftAttempt = now;
tryGoUp(cur + 1);
return;
}
if (rocks.length > 0) {
const t = pickBest(rocks);
currentTargetPriority = t.priority;
if (simulateRealClick(t.el)) {
lastClickTime = now;
console.log(`⏳ Копаю камень (руды нет)`);
}
}
}, 1500);
})();