CowzHacks

Auto farm, zoom, xray and other

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name        CowzHacks
// @namespace   Violentmonkey Scripts
// @match       *://cowz.io/*
// @icon        https://cowz.io/favicon.ico
// @grant       unsafeWindow
// @version     0.2
// @author      Drik
// @description Auto farm, zoom, xray and other
// @run-at      document-start
// @license     MIT
// ==/UserScript==

// version 0.2: better auto farm, new auto loot, better aimbot, upraged all functions

(() => {
    'use strict';

    const uw = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;

    const MIN_Z = 0x0,
        MAX_Z = 0x14,
        STEP = 0x1 / 0x2;

    const CELL = 0x18;
    const WORLD = 0x400;
    const GRID_N = Math.ceil(WORLD / CELL);

    const ARRIVE_DIST = 0xC;
    const REPLAN_TICKS = 0x5A;
    const STUCK_FRAMES = 0x96;
    const NAV_STUCK_MOVE = 0x4;
    const PHASE_TIMEOUT = 0x3C;
    const ATTACK_TIMEOUT = 0x258;
    const LOOT_TIMEOUT = 0xC8;
    const WANDER_TIMEOUT = 0x190;
    const DROP_WAIT = 0xA;
    const LOOT_REFRESH = 0x28;

    const LOOT_BLACKLIST = new Set([
        'club_01', 'club_02', 'club_03',
        'padded_armor_01', 'padded_armor_02', 'padded_armor_03',
        'leather_gloves_01', 'leather_gloves_02', 'leather_gloves_03',
    ]);

    let tZ = 1;
    let xOn = false,
        mOn = false,
        fcOn = false;
    let farmOn = false,
        lootOn = false,
        AimBotOn = false;
    let menuVisible = true;
    let ba = null,
        bv = null;
    const fcPos = {
        x: 0,
        y: 0
    };
    const keys = {};
    let last = performance.now();

    let navPath = [],
        navWpIdx = 0,
        navDrag = null;
    let navReplan = 0,
        navGoal = null;
    let navStuckTk = 0,
        navStuckX = 0,
        navStuckY = 0;

    const FS = {
        IDLE: 0,
        ATTACK: 1,
        DROP_WAIT: 2,
        LOOT: 3,
        WANDER: 4
    };
    let fState = FS.IDLE;
    let fMob = null;
    let fPhase = 0,
        fDrag = null;
    let fStuckCk = 0,
        fStuckCnt = 0,
        fLx = 0,
        fLy = 0;
    let lastMobZone = null,
        wanderGoalPos = null;
    let phaseTimer = 0,
        attackTimer = 0,
        wanderTimer = 0;
    let dropWaitTimer = 0;
    let clickConfirmed = false;


    let lootQueue = [];
    let lootItem = null;
    let lootTimer = 0;
    let lootRefresh = 0;

    const lootDone = new Set();

    const walkCache = new Map();

    const clamp = (n, a, b) => Math.min(b, Math.max(a, n));
    const vlen = v => Math.hypot(v.x, v.y);
    const vsub = (a, b) => ({
        x: a.x - b.x,
        y: a.y - b.y
    });
    const vdist = (a, b) => vlen(vsub(a, b));
    const lerp = (a, b, t) => a + (b - a) * t;

    const getCam = () => {
        try {
            return uw.game?.camera || null;
        } catch {
            return null;
        }
    };
    const getVis = () => {
        try {
            return uw.game?.visibility || null;
        } catch {
            return null;
        }
    };
    const getPlayer = () => {
        try {
            return uw.game?.playerBarn?.getLocalPlayer() || null;
        } catch {
            return null;
        }
    };
    const getMobs = () => {
        try {
            return uw.game?.mobBarn?.mobs || [];
        } catch {
            return [];
        }
    };
    const getItems = () => {
        try {
            return uw.game?.itemBarn?.items || [];
        } catch {
            return [];
        }
    };
    const getInput = () => {
        try {
            return uw.game?.input || null;
        } catch {
            return null;
        }
    };
    const getGeo = () => {
        try {
            return uw.game?.geoBarn || null;
        } catch {
            return null;
        }
    };
    const getSel = () => {
        try {
            return uw.game?.selection || null;
        } catch {
            return null;
        }
    };

    function hasWall(a, b) {
        const geo = getGeo();
        if (!geo) return false;
        try {
            const dx = b.x - a.x,
                dy = b.y - a.y,
                dist = Math.hypot(dx, dy);
            if (dist < 1) return false;
            return !!geo.raycast(a, {
                x: dx / dist,
                y: dy / dist
            }, dist, {
                colMask: 2
            });
        } catch {
            return false;
        }
    }

    function ci(gx, gy) {
        return gy * GRID_N + gx;
    }

    function cellCenter(gx, gy) {
        return {
            x: gx * CELL + CELL / 2,
            y: gy * CELL + CELL / 2
        };
    }

    function worldToGrid(wx, wy) {
        return {
            gx: Math.floor(wx / CELL),
            gy: Math.floor(wy / CELL)
        };
    }

    function isWalkable(gx, gy) {
        if (gx < 0 || gy < 0 || gx >= GRID_N || gy >= GRID_N) return false;
        const k = ci(gx, gy);
        if (walkCache.has(k)) return walkCache.get(k);
        const c = cellCenter(gx, gy),
            r = CELL * 0.45;
        const blocked = hasWall(c, {
                x: c.x + r,
                y: c.y
            }) || hasWall(c, {
                x: c.x - r,
                y: c.y
            }) ||
            hasWall(c, {
                x: c.x,
                y: c.y + r
            }) || hasWall(c, {
                x: c.x,
                y: c.y - r
            });
        walkCache.set(k, !blocked);
        return !blocked;
    }

    function heuristic(ax, ay, bx, by) {
        const dx = Math.abs(ax - bx),
            dy = Math.abs(ay - by);
        return (dx + dy) + (Math.SQRT2 - 2) * Math.min(dx, dy);
    }

    function astar(from, to) {
        const sg = worldToGrid(from.x, from.y),
            eg = worldToGrid(to.x, to.y);
        const open = new Map(),
            closed = new Set();
        const start = ci(sg.gx, sg.gy),
            goal = ci(eg.gx, eg.gy);
        open.set(start, {
            g: 0,
            f: heuristic(sg.gx, sg.gy, eg.gx, eg.gy),
            gx: sg.gx,
            gy: sg.gy,
            _p: null
        });
        const dirs = [
            [1, 0],
            [-1, 0],
            [0, 1],
            [0, -1],
            [1, 1],
            [1, -1],
            [-1, 1],
            [-1, -1]
        ];
        let iters = 0;
        while (open.size > 0 && iters++ < 2000) {
            let bestK = null,
                bestF = Infinity;
            for (const [k, v] of open) {
                if (v.f < bestF) {
                    bestF = v.f;
                    bestK = k;
                }
            }
            const cur = open.get(bestK);
            open.delete(bestK);
            closed.add(bestK);
            if (bestK === goal) {
                const path = [];
                let node = cur;
                while (node) {
                    path.unshift(cellCenter(node.gx, node.gy));
                    node = node._p;
                }
                path[0] = from;
                path.push(to);
                return stringPull(path);
            }
            for (const [dx, dy] of dirs) {
                const nx = cur.gx + dx,
                    ny = cur.gy + dy,
                    nk = ci(nx, ny);
                if (closed.has(nk) || !isWalkable(nx, ny)) continue;
                const cost = (Math.abs(dx) + Math.abs(dy) === 2) ? Math.SQRT2 : 1;
                const g = cur.g + cost;
                if (!open.has(nk) || g < open.get(nk).g)
                    open.set(nk, {
                        g,
                        f: g + heuristic(nx, ny, eg.gx, eg.gy),
                        gx: nx,
                        gy: ny,
                        _p: cur
                    });
            }
        }
        return null;
    }

    function stringPull(path) {
        if (!path || path.length < 3) return path || [];
        const result = [path[0]];
        let i = 0;
        while (i < path.length - 1) {
            let j = path.length - 1;
            while (j > i + 1 && hasWall(path[i], path[j])) j--;
            result.push(path[j]);
            i = j;
        }
        return result;
    }

    function planPath(from, to) {
        if (!hasWall(from, to)) return [from, to];
        const raw = astar(from, to);
        return (raw && raw.length > 0) ? raw : null;
    }

    function navStart(goal) {
        const p = getPlayer();
        if (!p?.pos) return false;
        const path = planPath({
            x: p.pos.x,
            y: p.pos.y
        }, goal);
        if (!path || path.length < 2) return false;
        navPath = path;
        navWpIdx = 1;
        navGoal = goal;
        navReplan = 0;
        navStuckTk = 0;
        navStuckX = p.pos.x;
        navStuckY = p.pos.y;
        navDragTo(navPath[1]);
        return true;
    }

    function navDragTo(wp) {
        const c = getCam(),
            i = getInput();
        if (!c || !i) return;
        const sc = c.worldToScreen(wp);
        const sx = Math.round(sc.x),
            sy = Math.round(sc.y);
        if (navDrag && !navDrag.isDead) {
            navDrag.pos.x = sx;
            navDrag.pos.y = sy;
            navDrag.posStart.x = sx;
            navDrag.posStart.y = sy;
            i.mousePos.x = sx;
            i.mousePos.y = sy;
        } else {
            closeNavDrag();
            i.mousePos.x = sx;
            i.mousePos.y = sy;
            const pos = {
                    x: sx,
                    y: sy
                },
                now = performance.now();
            navDrag = {
                pos: {
                    ...pos
                },
                posOld: {
                    ...pos
                },
                posStart: {
                    ...pos
                },
                isNew: true,
                isDead: false,
                button: 0,
                clickCount: 1,
                startTime: now,
                captureId: 0,
                groupId: 0,
                ownerId: 0,
                hoverId: 0,
                tags: []
            };
            i.mouseButtons[0] = true;
            i.mouseDragEvents.push(navDrag);
            const cl = i.mouseButtonClicks[0] || {
                pos: {
                    ...pos
                },
                time: now,
                count: 0
            };
            cl.count = 1;
            cl.time = now;
            cl.pos = {
                ...pos
            };
            navDrag.clickCount = cl.count;
            i.mouseButtonClicks[0] = cl;
        }
    }

    function closeNavDrag() {
        const i = getInput();
        if (navDrag) {
            navDrag.isDead = true;
            navDrag.isNew = false;
            navDrag = null;
        }
        if (i) i.mouseButtons[0] = false;
    }

    function navStop() {
        closeNavDrag();
        navPath = [];
        navWpIdx = 0;
        navGoal = null;
        navReplan = 0;
    }

    function tickNav() {
        if (!navGoal || !farmOn) return;
        const p = getPlayer();
        if (!p?.pos) return;
        const pos = p.pos;
        navStuckTk++;
        if (navStuckTk % STUCK_FRAMES === 0) {
            const moved = vdist(pos, {
                x: navStuckX,
                y: navStuckY
            });
            if (moved < NAV_STUCK_MOVE) {
                walkCache.clear();
                const jitter = {
                    x: clamp(navGoal.x + (Math.random() - 0.5) * CELL * 3, 10, WORLD - 10),
                    y: clamp(navGoal.y + (Math.random() - 0.5) * CELL * 3, 10, WORLD - 10)
                };
                navStart(jitter);
                return;
            }
            navStuckX = pos.x;
            navStuckY = pos.y;
        }
        if (navWpIdx >= navPath.length) {
            navStop();
            return;
        }
        const wp = navPath[navWpIdx];
        if (vdist(pos, wp) < ARRIVE_DIST) {
            navWpIdx++;
            if (navWpIdx >= navPath.length) {
                navStop();
                return;
            }
            navDragTo(navPath[navWpIdx]);
            return;
        }
        navReplan++;
        if (navReplan >= REPLAN_TICKS) {
            navReplan = 0;
            const fresh = stringPull([{
                x: pos.x,
                y: pos.y
            }, ...navPath.slice(navWpIdx)]);
            if (fresh && fresh.length > 1) {
                navPath = [{
                    x: pos.x,
                    y: pos.y
                }, ...fresh.slice(1)];
                navWpIdx = 1;
            }
        }
        navDragTo(navPath[navWpIdx] || navGoal);
    }

    function checkClick(id) {
        const sel = getSel();
        if (!sel) return false;
        return sel.targetEntityId === id || sel.selectEntityId === id;
    }

    function mobValid(m) {
        return !!(m && m.entityActive && !m.dead && m.pos?.x != null);
    }

    function farmStuck() {
        const p = getPlayer();
        if (!p?.pos) return false;
        fStuckCk++;
        if (fStuckCk < 120) return false;
        fStuckCk = 0;
        const d = vdist(p.pos, {
            x: fLx,
            y: fLy
        });
        fLx = p.pos.x;
        fLy = p.pos.y;
        if (d < 2) {
            fStuckCnt++;
            if (fStuckCnt >= 3) {
                fStuckCnt = 0;
                return true;
            }
        } else fStuckCnt = 0;
        return false;
    }

    function nearestMob(ignoreWalls) {
        const p = getPlayer();
        if (!p?.pos) return null;
        const px = p.pos.x,
            py = p.pos.y;
        let best = null,
            bestScore = -Infinity;
        for (const m of getMobs()) {
            if (!mobValid(m)) continue;
            if (!ignoreWalls && hasWall({
                    x: px,
                    y: py
                }, {
                    x: m.pos.x,
                    y: m.pos.y
                })) continue;
            const dist = Math.hypot(m.pos.x - px, m.pos.y - py);
            const hpPct = m.lifeMax > 0 ? m.life / m.lifeMax : 1;
            const s = -dist * 0.8 - hpPct * 50;
            if (s > bestScore) {
                bestScore = s;
                best = m;
            }
        }
        return best;
    }


    function scanAllLoot() {
        const p = getPlayer();
        const px = p?.pos?.x ?? 0,
            py = p?.pos?.y ?? 0;
        return getItems()
            .filter(it => {
                if (!it.entityActive || it.dead) return false;
                if (LOOT_BLACKLIST.has(it.item?.type)) return false;
                if (it.pos?.x == null) return false;
                if (lootDone.has(it.entityId)) return false;
                return true;
            })
            .sort((a, b) => {
                const rDiff = (b.item?.rarity ?? 0) - (a.item?.rarity ?? 0);
                if (rDiff !== 0) return rDiff;
                const da = Math.hypot(a.pos.x - px, a.pos.y - py);
                const db = Math.hypot(b.pos.x - px, b.pos.y - py);
                return da - db;
            });
    }


    function refreshLootQueue() {
        const fresh = scanAllLoot();

        lootQueue = lootQueue.filter(q => q.entityActive && !q.dead);

        const inQueue = new Set(lootQueue.map(q => q.entityId));
        for (const it of fresh) {
            if (!inQueue.has(it.entityId)) lootQueue.push(it);
        }

        const px = getPlayer()?.pos?.x ?? 0,
            py = getPlayer()?.pos?.y ?? 0;
        lootQueue.sort((a, b) => {
            const rDiff = (b.item?.rarity ?? 0) - (a.item?.rarity ?? 0);
            if (rDiff !== 0) return rDiff;
            return Math.hypot(a.pos.x - px, a.pos.y - py) - Math.hypot(b.pos.x - px, b.pos.y - py);
        });
    }

    function setTarget(id) {
        const g = uw.game;
        if (!g) return;
        g.selection.targetEntityId = id;
        g.selection.setTarget = true;
    }

    function makeDrag(wx, wy) {
        const c = getCam(),
            i = getInput();
        if (!c || !i) return null;
        const sc = c.worldToScreen({
            x: wx,
            y: wy
        });
        const sx = Math.round(sc.x),
            sy = Math.round(sc.y);
        i.mousePos.x = sx;
        i.mousePos.y = sy;
        const pos = {
                x: sx,
                y: sy
            },
            now = performance.now();
        const evt = {
            pos: {
                ...pos
            },
            posOld: {
                ...pos
            },
            posStart: {
                ...pos
            },
            isNew: true,
            isDead: false,
            button: 0,
            clickCount: 1,
            startTime: now,
            captureId: 0,
            groupId: 0,
            ownerId: 0,
            hoverId: 0,
            tags: []
        };
        i.mouseButtons[0] = true;
        i.mouseDragEvents.push(evt);
        const cl = i.mouseButtonClicks[0] || {
            pos: {
                ...pos
            },
            time: now,
            count: 0
        };
        cl.count = 1;
        cl.time = now;
        cl.pos = {
            ...pos
        };
        evt.clickCount = cl.count;
        i.mouseButtonClicks[0] = cl;
        return evt;
    }

    function fakeClick(e) {
        const mx = e.pos?.x,
            my = e.pos?.y;
        if (mx == null) return null;
        return makeDrag(mx, my);
    }

    function closeClick(evt) {
        const i = getInput();
        if (!i || !evt) return;
        evt.isDead = true;
        evt.isNew = false;
        i.mouseButtons[0] = false;
    }

    function wanderGoal() {
        const p = getPlayer();
        if (!p?.pos) return null;
        const base = lastMobZone || {
            x: p.pos.x,
            y: p.pos.y
        };
        for (let a = 0; a < 16; a++) {
            const angle = Math.random() * Math.PI * 2,
                dist = 80 + Math.random() * 300;
            const tx = clamp(base.x + Math.cos(angle) * dist, 20, WORLD - 20);
            const ty = clamp(base.y + Math.sin(angle) * dist, 20, WORLD - 20);
            if (!hasWall(p.pos, {
                    x: tx,
                    y: ty
                })) return {
                x: tx,
                y: ty
            };
            const mid = {
                x: lerp(p.pos.x, tx, 0.5) + (Math.random() - 0.5) * CELL,
                y: lerp(p.pos.y, ty, 0.5) + (Math.random() - 0.5) * CELL
            };
            if (!hasWall(p.pos, mid) && !hasWall(mid, {
                    x: tx,
                    y: ty
                })) return {
                x: tx,
                y: ty
            };
        }
        return null;
    }

    function resetFarm() {
        closeClick(fDrag);
        fDrag = null;
        navStop();
        fMob = null;
        fPhase = 0;
        fStuckCk = 0;
        fStuckCnt = 0;
        phaseTimer = 0;
        attackTimer = 0;
        wanderTimer = 0;
        dropWaitTimer = 0;
        lootQueue = [];
        lootItem = null;
        lootTimer = 0;
        lootRefresh = 0;
        lootDone.clear();
        clickConfirmed = false;
        setTarget(0);
        fState = FS.IDLE;
    }

    function setFS(s) {
        fState = s;
        phaseTimer = 0;
    }


    function tickLoot() {
        if (!lootOn || !farmOn) return;
        const p = getPlayer();
        if (!p || p.dead) return;


        if (fState === FS.ATTACK) return;

        lootRefresh++;
        if (lootRefresh >= LOOT_REFRESH) {
            lootRefresh = 0;
            refreshLootQueue();
        }


        if (lootItem && (!lootItem.entityActive || lootItem.dead)) {
            lootDone.add(lootItem.entityId);
            lootItem = null;
            lootQueue = lootQueue.filter(q => q.entityId !== lootItem?.entityId);
            closeClick(fDrag);
            fDrag = null;
            lootTimer = 0;
        }

        if (lootQueue.length === 0) {

            if (fState === FS.DROP_WAIT || fState === FS.LOOT) {
                setFS(FS.IDLE);
            }
            return;
        }


        while (lootQueue.length > 0 && (!lootQueue[0].entityActive || lootQueue[0].dead)) {
            lootDone.add(lootQueue[0].entityId);
            lootQueue.shift();
        }
        if (lootQueue.length === 0) return;

        const it = lootQueue[0];
        if (lootItem?.entityId !== it.entityId) {
            closeClick(fDrag);
            fDrag = null;
            lootItem = it;
            lootTimer = 0;
        }

        lootTimer++;


        if (lootTimer > LOOT_TIMEOUT) {
            lootDone.add(it.entityId);
            lootQueue.shift();
            lootItem = null;
            lootTimer = 0;
            closeClick(fDrag);
            fDrag = null;
            return;
        }


        if (lootTimer === 1 || lootTimer % 30 === 0) {
            setTarget(it.entityId);
            closeClick(fDrag);
            fDrag = fakeClick(it);
            requestAnimationFrame(() => {
                closeClick(fDrag);
                fDrag = null;
            });
        }
    }

    function tickFarm() {
        if (!farmOn) return;
        const p = getPlayer();
        if (!p || p.dead) return;
        const pos = p.pos;
        phaseTimer++;

        if (fState === FS.IDLE) {

            if (lootOn) {
                refreshLootQueue();
                if (lootQueue.length > 0) {
                    setFS(FS.LOOT);
                    return;
                }
            }
            fMob = nearestMob(false);
            if (fMob) {
                lastMobZone = {
                    x: fMob.pos.x,
                    y: fMob.pos.y
                };
                navStop();
                fLx = pos.x;
                fLy = pos.y;
                fPhase = 0;
                attackTimer = 0;
                clickConfirmed = false;
                setFS(FS.ATTACK);
                return;
            }
            wanderGoalPos = wanderGoal();
            wanderTimer = 0;
            if (wanderGoalPos) navStart(wanderGoalPos);
            setFS(FS.WANDER);
        } else if (fState === FS.WANDER) {
            wanderTimer++;

            if (lootOn && wanderTimer % LOOT_REFRESH === 0) {
                refreshLootQueue();
                if (lootQueue.length > 0) {
                    navStop();
                    setFS(FS.LOOT);
                    return;
                }
            }
            fMob = nearestMob(false);
            if (fMob) {
                navStop();
                wanderGoalPos = null;
                setFS(FS.IDLE);
                return;
            }
            const arrived = wanderGoalPos && vdist(pos, wanderGoalPos) < ARRIVE_DIST;
            if (arrived || wanderTimer > WANDER_TIMEOUT || !navGoal) {
                navStop();
                wanderGoalPos = wanderGoal();
                wanderTimer = 0;
                if (wanderGoalPos) navStart(wanderGoalPos);
                return;
            }
            if (wanderTimer % 60 === 0) {
                const any = nearestMob(true);
                if (any && !hasWall(pos, any.pos)) {
                    navStop();
                    setFS(FS.IDLE);
                    return;
                }
            }
            if (!navGoal && wanderGoalPos) navStart(wanderGoalPos);
        } else if (fState === FS.ATTACK) {
            attackTimer++;
            if (!mobValid(fMob)) {
                closeClick(fDrag);
                fDrag = null;
                setTarget(0);
                fMob = null;
                fPhase = 0;
                dropWaitTimer = 0;
                setFS(FS.DROP_WAIT);
                return;
            }
            if (attackTimer > ATTACK_TIMEOUT) {
                closeClick(fDrag);
                fDrag = null;
                setTarget(0);
                fMob = null;
                fPhase = 0;
                walkCache.clear();
                setFS(FS.IDLE);
                return;
            }
            if (phaseTimer > PHASE_TIMEOUT && fPhase !== 2) {
                closeClick(fDrag);
                fDrag = null;
                fPhase = 0;
                phaseTimer = 0;
                return;
            }
            if (farmStuck()) {
                resetFarm();
                return;
            }

            if (!fMob.dead) {
                if (attackTimer % 60 === 0 && hasWall(pos, fMob.pos)) {
                    closeClick(fDrag);
                    fDrag = null;
                    setTarget(0);
                    const path = planPath(pos, fMob.pos);
                    if (path && path.length > 1) {
                        navPath = path;
                        navWpIdx = 1;
                        navGoal = fMob.pos;
                        navReplan = 0;
                        navDragTo(navPath[1]);
                    } else {
                        fMob = null;
                        fPhase = 0;
                        setFS(FS.IDLE);
                    }
                    return;
                }
                navStop();
                if (fPhase === 0) {
                    setTarget(fMob.entityId);
                    fDrag = fakeClick(fMob);
                    clickConfirmed = false;
                    fPhase = 1;
                    phaseTimer = 0;
                } else if (fPhase === 1) {
                    if (!clickConfirmed) {
                        clickConfirmed = checkClick(fMob.entityId);
                        if (!clickConfirmed && phaseTimer > PHASE_TIMEOUT) {
                            closeClick(fDrag);
                            fDrag = null;
                            setTarget(fMob.entityId);
                            fDrag = fakeClick(fMob);
                            phaseTimer = 0;
                            return;
                        }
                    }
                    closeClick(fDrag);
                    fDrag = null;
                    fPhase = 2;
                    phaseTimer = 0;
                } else {
                    setTarget(fMob.entityId);
                    if (attackTimer % 30 === 0 && !checkClick(fMob.entityId)) {
                        setTarget(fMob.entityId);
                        fDrag = fakeClick(fMob);
                        requestAnimationFrame(() => {
                            closeClick(fDrag);
                            fDrag = null;
                        });
                    }
                }
            } else {
                closeClick(fDrag);
                fDrag = null;
                setTarget(0);
                attackTimer = 0;
                dropWaitTimer = 0;
                setFS(FS.DROP_WAIT);
            }
        } else if (fState === FS.DROP_WAIT) {
            dropWaitTimer++;
            if (dropWaitTimer >= DROP_WAIT) {
                if (lootOn) {
                    refreshLootQueue();
                    if (lootQueue.length > 0) {
                        fMob = null;
                        fPhase = 0;
                        setFS(FS.LOOT);
                        return;
                    }
                }
                fMob = null;
                fPhase = 0;
                setFS(FS.IDLE);
            }
        } else if (fState === FS.LOOT) {
            if (lootQueue.length === 0 && lootItem == null) {
                setFS(FS.IDLE);
            }
        }
    }

    function updateLabel() {
        const el = document.getElementById('zlbl');
        if (el) el.textContent = tZ.toFixed(1).replace(/\.0$/, '');
    }

    function applyZ() {
        const c = getCam();
        if (c) try {
            c.z = tZ;
        } catch {}
    }

    function zoomBy(d) {
        tZ = clamp(+(tZ + d).toFixed(2), MIN_Z, MAX_Z);
        updateLabel();
    }

    function nudgeZoom() {
        const c = getCam();
        if (!c) return;
        try {
            c.z = tZ + 0.01;
            requestAnimationFrame(() => {
                try {
                    c.z = tZ;
                } catch {}
            });
        } catch {}
    }

    function applyV() {
        const v = getVis();
        if (!v) return;
        if (!ba) {
            ba = v.cellGameAlpha.slice();
            bv = v.cellVis.slice();
        }
        if (xOn) v.cellGameAlpha.fill(-Infinity);
        if (mOn) v.cellVis.fill(-Infinity);
    }

    function restoreA() {
        const v = getVis();
        if (v && ba) v.cellGameAlpha.fill(ba);
    }

    function restoreM() {
        const v = getVis();
        if (v && bv) v.cellVis.fill(bv);
    }

    const ARROW_KEYS = ['arrowup', 'arrowdown', 'arrowleft', 'arrowright'];

    function enableFreeCam() {
        const p = getPlayer(),
            c = getCam();
        if (p?.bodyPos) {
            fcPos.x = p.bodyPos.x;
            fcPos.y = p.bodyPos.y;
        } else if (c) {
            fcPos.x = c.pos.x;
            fcPos.y = c.pos.y;
        }
        updateFcHint();
    }

    function updateFcHint() {
        const el = document.getElementById('fc-hint');
        if (!el) return;
        el.textContent = fcOn ? '↑↓←→' : '';
        el.style.color = fcOn ? '#82aaff' : 'rgba(255,255,255,0.35)';
    }

    function tickFreeCam() {
        if (!fcOn) return;
        const p = getPlayer(),
            c = getCam();
        if (!p || !c) return;
        const sp = 0.7 * tZ;
        if (keys['arrowup']) fcPos.y += sp;
        if (keys['arrowdown']) fcPos.y -= sp;
        if (keys['arrowleft']) fcPos.x -= sp;
        if (keys['arrowright']) fcPos.x += sp;
        try {
            if (p.bodyPos) {
                p.bodyPos.x = fcPos.x;
                p.bodyPos.y = fcPos.y;
            }
            c.pos.x = fcPos.x;
            c.pos.y = fcPos.y;
        } catch {}
    }

    function tickAimBot() {
        if (!AimBotOn) return;
        const p = getPlayer();
        if (!p?.pos) return;
        let best = null,
            bd = Infinity;
        for (const m of getMobs()) {
            if (!m.entityActive || m.dead) continue;
            if (hasWall({
                    x: p.pos.x,
                    y: p.pos.y
                }, {
                    x: m.pos?.x ?? 0,
                    y: m.pos?.y ?? 0
                })) continue;
            const d = Math.hypot((m.pos?.x ?? 0) - p.pos.x, (m.pos?.y ?? 0) - p.pos.y);
            if (d < bd) {
                bd = d;
                best = m;
            }
        }
        if (!best) return;
        const c = getCam(),
            i = getInput();
        if (!c || !i) return;
        const sc = c.worldToScreen({
            x: best.pos.x,
            y: best.pos.y
        });
        i.mousePos.x = Math.round(sc.x);
        i.mousePos.y = Math.round(sc.y);
    }

    function toggleMenu() {
        menuVisible = !menuVisible;
        const box = document.getElementById('zm');
        if (box) box.style.display = menuVisible ? 'flex' : 'none';
    }

    function setLootVisible(v) {
        const row = document.getElementById('loot-row');
        if (row) row.style.display = v ? 'flex' : 'none';
        if (!v) {
            lootOn = false;
            const cb = document.getElementById('lt');
            if (cb) cb.checked = false;
        }
    }

    function handleZoomWheel(e) {
        if (!e.ctrlKey || e.__zmHandled) return;
        e.__zmHandled = true;
        if (e.cancelable) e.preventDefault();
        e.stopPropagation();
        e.stopImmediatePropagation();
        zoomBy(e.deltaY < 0 ? -STEP : STEP);
    }

    window.addEventListener('keydown', e => {
        const k = e.key.toLowerCase();
        if (e.key === 'F10') {
            e.preventDefault();
            toggleMenu();
            return;
        }
        if (e.ctrlKey) {
            const plus = e.key === '+' || e.key === '=' || e.code === 'Equal';
            const minus = e.key === '-' || e.code === 'Minus';
            if (plus || minus) {
                e.preventDefault();
                e.stopImmediatePropagation();
                zoomBy(plus ? STEP : -STEP);
                return;
            }
        }
        if (fcOn && ARROW_KEYS.includes(k)) {
            e.preventDefault();
            e.stopImmediatePropagation();
        }
        keys[k] = true;
    }, true);
    window.addEventListener('keyup', e => {
        keys[e.key.toLowerCase()] = false;
    }, true);
    document.addEventListener('wheel', handleZoomWheel, {
        capture: true,
        passive: false
    });
    window.addEventListener('wheel', handleZoomWheel, {
        capture: true,
        passive: false
    });
    document.addEventListener('mousewheel', handleZoomWheel, {
        capture: true,
        passive: false
    });

    const st = document.createElement('style');
    st.textContent = `#zm {
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 99999;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 238px;
  padding: 10px;
  border-radius: 12px;
  background: rgba(20, 20, 28, 0.96);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(10px);
  font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
  color: #e6edf3;
  user-select: none;
}
#zm,
#zm * {
  box-sizing: border-box;
}
#zm .toprow {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  align-items: center;
}
#zm .stat {
  color: #7ee787;
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}
#zm .stat span {
  display: inline-block;
  min-width: 34px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: #fff;
  font-weight: 600;
}
#zm .zrow {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}
#zm .zhint {
  color: rgba(255, 255, 255, 0.55);
  font-size: 11px;
}
#zm .zval {
  color: #58a6ff;
  font-size: 13px;
  font-weight: 600;
  min-width: 40px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
#zm .sep {
  width: 100%;
  height: 1px;
  background: rgba(255, 255, 255, 0.12);
}
#zm .controls {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
#zm label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 13px;
  cursor: pointer;
  color: #f0f6fc;
  padding: 6px 8px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.04);
}
#zm label:hover {
  background: rgba(255, 255, 255, 0.07);
}
#zm label .left {
  display: flex;
  align-items: center;
  gap: 8px;
}
#zm input[type="checkbox"] {
  accent-color: #58a6ff;
  margin: 0;
}
#zm #fc-hint {
  font-size: 12px;
  min-width: 42px;
  text-align: right;
}
#zm label.farm-label {
  color: #ff7b72;
}
#zm label.farm-label.active {
  color: #ff3b3b;
  text-shadow: 0 0 8px rgba(255, 60, 60, 0.8);
}
#zm label.loot-label {
  color: #f0a040;
  padding-left: 24px;
}
#zm label.loot-label.active {
  color: #ffb84d;
  text-shadow: 0 0 8px rgba(255, 180, 60, 0.7);
}
#zm-hint {
  position: fixed;
  bottom: 60px;
  left: 8px;
  z-index: 99999;
  font-family: system-ui, -apple-system, sans-serif;
  font-size: 15px;
  color: red;
  pointer-events: none;
  user-select: none;
}
`;
    document.documentElement.appendChild(st);

    const hint = document.createElement('div');
    hint.id = 'zm-hint';
    hint.textContent = 'F10 - open/close menu';
    document.documentElement.appendChild(hint);

    const box = document.createElement('div');
    box.id = 'zm';
    box.innerHTML = `
    <div class="toprow">
      <span class="stat">FPS: <span id="fps">0</span></span>
      <span class="stat">PING: <span id="ping">0</span></span>
    </div>
    <div class="sep"></div>
    <div class="zrow">
      <span class="zhint">Zoom</span>
      <span class="zhint">Ctrl\xb1 / Scroll</span>
      <span class="zval" id="zlbl">${tZ}</span>
    </div>
    <div class="sep"></div>
    <div class="controls">
      <label><span class="left"><input type="checkbox" id="zx"> xray</span></label>
      <label><span class="left"><input type="checkbox" id="xm"> xray map</span></label>
      <label><span class="left"><input type="checkbox" id="fc"> free camera</span><span id="fc-hint"></span></label>
      <label><span class="left"><input type="checkbox" id="AimBot"> AimBot</span></label>
      <label class="farm-label" id="farm-label"><span class="left"><input type="checkbox" id="fm"> auto farm</span></label>
      <label class="loot-label" id="loot-row" style="display:none"><span class="left"><input type="checkbox" id="lt"> auto loot</span></label>
    </div>
  `;
    document.documentElement.appendChild(box);

    const fpsNode = box.querySelector('#fps'),
        pingNode = box.querySelector('#ping');
    const zx = box.querySelector('#zx'),
        xm = box.querySelector('#xm');
    const fc = box.querySelector('#fc'),
        fm = box.querySelector('#fm');
    const lt = box.querySelector('#lt'),
        aimCb = box.querySelector('#AimBot');
    const farmLabel = box.querySelector('#farm-label'),
        lootLabel = box.querySelector('#loot-row');

    zx.onchange = () => {
        xOn = zx.checked;
        if (!xOn) restoreA();
    };
    xm.onchange = () => {
        mOn = xm.checked;
        if (!mOn) restoreM();
        nudgeZoom();
    };
    fc.onchange = () => {
        fcOn = fc.checked;
        fcOn ? enableFreeCam() : updateFcHint();
    };
    aimCb.onchange = () => {
        AimBotOn = aimCb.checked;
    };
    fm.onchange = () => {
        farmOn = fm.checked;
        farmLabel.classList.toggle('active', farmOn);
        setLootVisible(farmOn);
        if (!farmOn) resetFarm();
    };
    lt.onchange = () => {
        lootOn = lt.checked;
        lootLabel.classList.toggle('active', lootOn);
        if (lootOn) {
            lootDone.clear();
            refreshLootQueue();
        }
    };

    const stop = e => e.stopPropagation();
    ['pointerdown', 'pointerup', 'mousedown', 'mouseup', 'click', 'dblclick', 'contextmenu', 'wheel', 'touchstart', 'touchend', 'touchmove']
    .forEach(ev => box.addEventListener(ev, stop));

    function tickHUD() {
        if (!uw.game?.inGame) return;
        const t = performance.now(),
            dt = t - last;
        last = t;
        if (fpsNode && dt > 0 && dt < 1000) fpsNode.textContent = (1000 / dt).toFixed(1);
        const pings = uw.game?.netGraph?.pings;
        if (pings?.length && pingNode) pingNode.textContent = Number(pings[pings.length - 1]).toFixed(0);
    }

    function loop() {
        applyZ();
        applyV();
        tickFreeCam();
        tickAimBot();
        tickNav();
        tickFarm();
        tickLoot();
        tickHUD();
        requestAnimationFrame(loop);
    }
    updateLabel();
    requestAnimationFrame(loop);
})();

(() => {
    'use strict';

    function apply() {
        const title = document.querySelector("#landing-start-title");
        if (title && !title._edited) {
            title.textContent = "CowzHacks";
            title._edited = true;
        }

        const news = document.querySelector("#landing-news-container");
        if (news && !news._moved) {
            news.style.transform = "translateX(40px)";
            news._moved = true;
        }
    }

    const mo = new MutationObserver(() => apply());

    mo.observe(document.documentElement, {
        childList: true,
        subtree: true
    });

    apply();
})();


(() => {
    'use strict';

    let cached = null;

    try {
        const raw = sessionStorage.getItem('_si');
        if (raw) cached = JSON.parse(raw);
    } catch {}

    const origFetch = unsafeWindow.fetch.bind(unsafeWindow);

    const live = origFetch('/api/site_info', {
            cache: 'no-store',
            priority: 'high'
        })
        .then(r => r.json())
        .then(data => {
            cached = data;
            try {
                sessionStorage.setItem('_si', JSON.stringify(data));
            } catch {}
            return data;
        })
        .catch(() => null);

    unsafeWindow.fetch = function(url, opts) {
        if (typeof url === 'string' && url.includes('/api/site_info')) {
            if (cached) {
                return Promise.resolve(new Response(JSON.stringify(cached), {
                    status: 200,
                    headers: {
                        'Content-Type': 'application/json'
                    }
                }));
            }
            return live.then(data =>
                data ?
                new Response(JSON.stringify(data), {
                    status: 200,
                    headers: {
                        'Content-Type': 'application/json'
                    }
                }) :
                origFetch(url, opts)
            );
        }
        return origFetch(url, opts);
    };
})();