Загрузка данных


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