EvoWare

Killaura, Bot, Dodge, ESP, Zoom, Auto-Respawn and more. Buy me a coffee :) paypal.me/Izkuh Support : Patreon.com/EvoWareV1

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

Advertisement:

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

Advertisement:

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         EvoWare
// @namespace    http://tampermonkey.net/
// @version      1.6
// @description  Killaura, Bot, Dodge, ESP, Zoom, Auto-Respawn and more. Buy me a coffee :) paypal.me/Izkuh Support : Patreon.com/EvoWareV1
// @author       #Ex
// @match        https://evowars.io/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=evowars.io
// @grant        none
// @license      GPL-3.0
// ==/UserScript==

(function () {
    'use strict';

    const iframe = document.createElement('iframe');
    iframe.id = 'evoware-frame';
    iframe.style.cssText = `position:fixed!important;top:50px!important;left:50px!important;width:600px!important;height:690px!important;border:none!important;z-index:2147483647!important;background:transparent!important;pointer-events:auto!important;transition:opacity 0.15s!important;`;
    document.body.appendChild(iframe);
    const doc = iframe.contentDocument || iframe.contentWindow.document;
    doc.open();
    doc.write(`<!DOCTYPE html><html><head><style>
        *{margin:0;padding:0;box-sizing:border-box}
        html,body{height:100%;width:100%}
        body{background:rgba(8,4,16,0.96);font-family:'Segoe UI',Arial,sans-serif;color:#b8a0d0;border-radius:12px;border:1px solid #4a2080;box-shadow:0 0 40px rgba(100,20,200,0.4);display:flex;flex-direction:column}
        #drag-bar{height:42px;padding:0 16px;font-size:14px;font-weight:600;color:#c8b0f0;border-bottom:1px solid #4a2080;cursor:grab;display:flex;align-items:center;justify-content:space-between;user-select:none;background:linear-gradient(180deg,rgba(30,10,50,0.98),rgba(20,5,35,0.98));flex-shrink:0;border-radius:12px 12px 0 0}
        #drag-bar:active{cursor:grabbing}
        .body{display:flex;flex:1;background:rgba(12,6,22,0.96);overflow:hidden;border-radius:0 0 12px 12px}
        .content{display:flex;padding:14px;gap:14px;overflow-y:auto;flex:1}
        .col{flex:1;display:flex;flex-direction:column;gap:10px;min-width:0}
        .st{font-size:11px;font-weight:700;letter-spacing:1.5px;margin-bottom:4px;text-transform:uppercase;color:#7050b0}
        .sec{background:rgba(18,10,30,0.9);border-radius:8px;padding:12px 14px;display:flex;flex-direction:column;gap:10px;border:1px solid #302050}
        .row{display:flex;justify-content:space-between;align-items:center;font-size:13px;color:#c8b8e0;user-select:none;gap:12px}
        .tgl{position:relative;width:56px;height:28px;display:inline-block;cursor:pointer;flex-shrink:0}
        .tgl input{opacity:0;width:0;height:0;position:absolute}
        .sld{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background:#2a1840;transition:0.2s;border-radius:28px}
        .sld:before{position:absolute;content:"";height:22px;width:22px;left:3px;bottom:3px;background:#6040a0;transition:0.2s;border-radius:50%}
        input:checked+.sld{background:#7c3aed;box-shadow:0 0 8px rgba(124,58,237,0.5)}
        input:checked+.sld:before{transform:translateX(28px);background:#fff}
        .rw{display:flex;align-items:center;gap:8px;flex:1;position:relative}
        .slider-wrap{position:relative;width:100%;height:22px}
        .slider-wrap input[type=range]{position:absolute;width:100%;top:50%;transform:translateY(-50%);-webkit-appearance:none;appearance:none;background:transparent;pointer-events:none;z-index:2;height:6px}
        .slider-wrap input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;border-radius:50%;background:#7c3aed;cursor:pointer;pointer-events:auto;border:1px solid #a78bfa;box-shadow:0 0 6px rgba(124,58,237,0.4)}
        .slider-track-bg{position:absolute;top:50%;transform:translateY(-50%);width:100%;height:4px;background:#2a1840;border-radius:3px;z-index:1}
        .slider-track-fill{position:absolute;top:50%;transform:translateY(-50%);height:4px;background:#7c3aed;border-radius:3px;z-index:1;box-shadow:0 0 6px rgba(124,58,237,0.3)}
        .val{color:#8060c0;font-size:11px;min-width:32px;text-align:right;flex-shrink:0}
        .stat-val{font-weight:600;font-size:12px}
        .help{display:inline-block;width:16px;height:16px;border-radius:50%;background:#4a2080;color:#c8b0f0;text-align:center;line-height:16px;font-size:11px;font-weight:700;cursor:help;margin-left:4px;position:relative}
        .help:hover::after{content:attr(data-tip);position:absolute;left:22px;top:-6px;background:#1a0a2e;color:#fff;padding:6px 10px;border-radius:6px;font-size:11px;white-space:nowrap;z-index:10;border:1px solid #7c3aed;max-width:200px;white-space:normal}
        select{background:#2a1840;color:#c8b8e0;border:1px solid #4a2080;border-radius:4px;padding:3px 6px;font-size:11px;outline:none}
        select option{background:#1a0a2e}
        ::-webkit-scrollbar{width:4px}
        ::-webkit-scrollbar-track{background:#1a0a2e}
        ::-webkit-scrollbar-thumb{background:#4a2080;border-radius:4px}
        .hotkey-row{background:rgba(124,58,237,0.15);border:1px solid #7c3aed;border-radius:6px;padding:8px 12px;margin-top:4px}
        .hotkey-btn{background:#2a1840;border:1px solid #7c3aed;color:#c8b8e0;padding:4px 12px;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600}
        .hotkey-btn:hover{background:#7c3aed;color:#fff}
        .hotkey-display{background:#1a0a2e;border:1px solid #4a2080;border-radius:4px;padding:4px 12px;font-family:monospace;font-size:12px;min-width:80px;text-align:center}
        .waiting-txt{color:#22c55e;font-size:11px}
    </style></head><body>
        <div id="drag-bar"><span>⚔ EvoWare</span><span style="font-size:10px;color:#6040a0;font-weight:400">INSERT/hotkey toggle · Drag to move</span></div>
        <div class="body"><div class="content">
            <div class="col">
                <div><div class="st">Combat</div><div class="sec">
                    <div class="row"><span>Bot<span class="help" data-tip="Auto-moves, hunts enemies, collects food [F key]">?</span></span><label class="tgl"><input type="checkbox" id="tgl-bot"><span class="sld"></span></label></div>
                    <div class="row"><span>Killaura<span class="help" data-tip="Auto-aim & attack nearest enemy in range">?</span></span><label class="tgl"><input type="checkbox" id="tgl-killaura"><span class="sld"></span></label></div>
                    <div class="row"><span>Target Level</span><span class="val" id="val-lvlrange">0-100</span></div>
                    <div class="slider-wrap"><div class="slider-track-bg"></div><div class="slider-track-fill" id="track-lvl"></div><input type="range" id="rng-lvlmin" min="0" max="100" value="0" step="1"><input type="range" id="rng-lvlmax" min="0" max="100" value="100" step="1"></div>
                    <div class="row"><span>Dodge<span class="help" data-tip="Pushes you away from incoming attacks">?</span></span><label class="tgl"><input type="checkbox" id="tgl-dodgeatk"><span class="sld"></span></label></div>
                    <div class="row"><span>Dodge on CD<span class="help" data-tip="Only dodge when your attack is on cooldown">?</span></span><label class="tgl"><input type="checkbox" id="tgl-dodgecd"><span class="sld"></span></label></div>
                    <div class="row"><span>Auto Respawn<span class="help" data-tip="Auto-clicks Play after death">?</span></span><label class="tgl"><input type="checkbox" id="tgl-autorespawn"><span class="sld"></span></label></div>
                    <div class="row"><span>Swing Angle<span class="help" data-tip="Aim offset applied to attack direction">?</span></span><div class="rw"><div class="slider-wrap"><div class="slider-track-bg"></div><div class="slider-track-fill" id="track-offset"></div><input type="range" id="rng-offset" min="0" max="360" value="135"></div><span class="val" id="val-offset">135°</span></div></div>
                </div></div>
                <div><div class="st">Bot Config</div><div class="sec">
                    <div class="row"><span>Max Higher Lvl<span class="help" data-tip="Attack enemies up to N levels above you (Max=any)">?</span></span><div class="rw"><div class="slider-wrap"><div class="slider-track-bg"></div><div class="slider-track-fill" id="track-maxhigher"></div><input type="range" id="rng-maxhigher" min="0" max="20" value="0" step="1"></div><span class="val" id="val-maxhigher">0</span></div></div>
                    <div class="row"><span>Min Lower Lvl<span class="help" data-tip="Ignore enemies more than N levels below you (All=any)">?</span></span><div class="rw"><div class="slider-wrap"><div class="slider-track-bg"></div><div class="slider-track-fill" id="track-minlower"></div><input type="range" id="rng-minlower" min="0" max="20" value="0" step="1"></div><span class="val" id="val-minlower">0</span></div></div>
                    <div class="row"><span>Safe Distance<span class="help" data-tip="How far to keep from dangerous enemies (multiplier)">?</span></span><div class="rw"><div class="slider-wrap"><div class="slider-track-bg"></div><div class="slider-track-fill" id="track-safedist"></div><input type="range" id="rng-safedist" min="1" max="3" step="0.1" value="2"></div><span class="val" id="val-safedist">2.0x</span></div></div>
                    <div class="row"><span>Avoid Strength<span class="help" data-tip="How hard to turn away from threats">?</span></span><div class="rw"><div class="slider-wrap"><div class="slider-track-bg"></div><div class="slider-track-fill" id="track-avoidstr"></div><input type="range" id="rng-avoidstr" min="0" max="100" step="1" value="50"></div><span class="val" id="val-avoidstr">50%</span></div></div>
                    <div class="row"><span>Sprint<span class="help" data-tip="When to right-click for speed boost">?</span></span><select id="sel-sprintmode"><option value="0">Always</option><option value="1" selected>Towards Enemy</option><option value="2">Never</option></select></div>
                    <div class="row"><span>Collect Food<span class="help" data-tip="Move towards food when no enemy nearby">?</span></span><label class="tgl"><input type="checkbox" id="tgl-collectfood" checked><span class="sld"></span></label></div>
                    <div class="row"><span>Flee Danger<span class="help" data-tip="Run from enemies too strong to fight">?</span></span><label class="tgl"><input type="checkbox" id="tgl-fleedanger"><span class="sld"></span></label></div>
                    <div class="row"><span>Skip Teammates<span class="help" data-tip="In Team mode, do not attack same-color allies">?</span></span><label class="tgl"><input type="checkbox" id="tgl-skipteam" checked><span class="sld"></span></label></div>
                </div></div>
            </div>
            <div class="col">
                <div><div class="st">Visuals</div><div class="sec">
                    <div class="row"><span>Enemy Range<span class="help" data-tip="Show enemy attack radius circle">?</span></span><label class="tgl"><input type="checkbox" id="tgl-enemyrange"><span class="sld"></span></label></div>
                    <div class="row"><span>Attack Timer<span class="help" data-tip="Show enemy attack cooldown ring">?</span></span><label class="tgl"><input type="checkbox" id="tgl-cooldown"><span class="sld"></span></label></div>
                    <div class="row"><span>Tracers<span class="help" data-tip="Draw lines to each enemy">?</span></span><label class="tgl"><input type="checkbox" id="tgl-tracers"><span class="sld"></span></label></div>
                    <div class="row"><span>Hitboxes<span class="help" data-tip="Show enemy collision circles">?</span></span><label class="tgl"><input type="checkbox" id="tgl-hitboxes"><span class="sld"></span></label></div>
                    <div class="row"><span>Target Glow<span class="help" data-tip="Glow highlight on current target">?</span></span><label class="tgl"><input type="checkbox" id="tgl-killable"><span class="sld"></span></label></div>
                </div></div>
                <div><div class="st">Settings</div><div class="sec">
                    <div class="row"><span>Zoom<span class="help" data-tip="Camera zoom level">?</span></span><div class="rw"><div class="slider-wrap"><div class="slider-track-bg"></div><div class="slider-track-fill" id="track-zoom"></div><input type="range" id="rng-zoom" min="0.2" max="3" step="0.05" value="0.5"></div><span class="val" id="val-zoom">0.50x</span></div></div>
                </div></div>
                <div><div class="st">Hotkey</div><div class="sec">
                    <div class="hotkey-row">
                        <div class="row"><span>Menu Toggle</span><button class="hotkey-btn" id="change-hotkey">Set</button></div>
                        <div class="row" style="margin-top:8px"><span>Current:</span><span class="hotkey-display" id="current-hotkey">Insert</span></div>
                        <div class="row" style="margin-top:4px"><span class="waiting-txt" id="waiting-status"></span></div>
                    </div>
                </div></div>
                <div><div class="st">Info</div><div class="sec">
                    <div class="row"><span>Level</span><span class="stat-val" style="color:#a78bfa" id="txt-level">--</span></div>
                    <div class="row"><span>Range</span><span class="stat-val" style="color:#c084fc" id="txt-range">--</span></div>
                    <div class="row"><span>Target</span><span class="stat-val" style="color:#e879f9" id="txt-target">--</span></div>
                    <div class="row"><span>Nearby</span><span class="stat-val" style="color:#a78bfa" id="txt-nearby">0</span></div>
                    <div class="row"><span>Bot</span><span class="stat-val" style="color:#4ade80" id="txt-botstate">OFF</span></div>
                </div></div>
            </div>
        </div></div>
        <script>
            function S(t,d){window.parent.postMessage({evoware:1,type:t,data:d},'*')}
            const D=document.getElementById('drag-bar');let dr=false,sx,sy,sl,st2;
            D.addEventListener('mousedown',function(e){if(['INPUT','LABEL','SELECT','BUTTON'].includes(e.target.tagName))return;dr=true;sx=e.clientX;sy=e.clientY;const f=window.parent.document.getElementById('evoware-frame');sl=f.offsetLeft;st2=f.offsetTop;e.preventDefault()});
            window.addEventListener('mousemove',function(e){if(!dr)return;const f=window.parent.document.getElementById('evoware-frame');let nx=sl+(e.clientX-sx),ny=st2+(e.clientY-sy);nx=Math.max(0,Math.min(nx,window.parent.innerWidth-f.offsetWidth));ny=Math.max(0,Math.min(ny,window.parent.innerHeight-f.offsetHeight));f.style.left=nx+'px';f.style.top=ny+'px'});
            window.addEventListener('mouseup',function(){dr=false});
            function UR(r,t,min,max,vel,suf,cb){const v=parseFloat(r.value);t.style.left='0%';t.style.width=((v-min)/(max-min)*100)+'%';vel.textContent=(suf==='°'?parseInt(v):parseFloat(v).toFixed(suf==='x'?2:0))+suf;if(cb)cb(v);}
            const rM=document.getElementById('rng-lvlmin'),rX=document.getElementById('rng-lvlmax'),tL=document.getElementById('track-lvl'),vL=document.getElementById('val-lvlrange');
            function uL(){let mn=parseInt(rM.value),mx=parseInt(rX.value);if(mn>mx){[mn,mx]=[mx,mn];rM.value=mn;rX.value=mx;}tL.style.left=(mn)+'%';tL.style.width=(mx-mn)+'%';vL.textContent=mn+'-'+mx;S('lvlrange',{min:mn,max:mx});}
            rM.addEventListener('input',uL);rX.addEventListener('input',uL);uL();
            const rO=document.getElementById('rng-offset'),tO=document.getElementById('track-offset'),vO=document.getElementById('val-offset');
            UR(rO,tO,0,360,vO,'°',v=>S('offset',v));rO.addEventListener('input',()=>UR(rO,tO,0,360,vO,'°',v=>S('offset',v)));
            const rZ=document.getElementById('rng-zoom'),tZ=document.getElementById('track-zoom'),vZ=document.getElementById('val-zoom');
            UR(rZ,tZ,0.2,3,vZ,'x',v=>S('zoom',v));rZ.addEventListener('input',()=>UR(rZ,tZ,0.2,3,vZ,'x',v=>S('zoom',v)));
            const rH=document.getElementById('rng-maxhigher'),tH=document.getElementById('track-maxhigher'),vH=document.getElementById('val-maxhigher');
            function uH(){const v=parseInt(rH.value);tH.style.width=(v/20*100)+'%';vH.textContent=v>=20?'Max':v;S('maxhigher',v);}
            rH.addEventListener('input',uH);uH();
            const rL2=document.getElementById('rng-minlower'),tL2=document.getElementById('track-minlower'),vL2=document.getElementById('val-minlower');
            function uL2(){const v=parseInt(rL2.value);tL2.style.width=(v/20*100)+'%';vL2.textContent=v>=20?'All':v;S('minlower',v);}
            rL2.addEventListener('input',uL2);uL2();
            const rS=document.getElementById('rng-safedist'),tS=document.getElementById('track-safedist'),vS=document.getElementById('val-safedist');
            UR(rS,tS,1,3,vS,'x',v=>S('safedist',v));rS.addEventListener('input',()=>UR(rS,tS,1,3,vS,'x',v=>S('safedist',v)));
            const rA=document.getElementById('rng-avoidstr'),tA=document.getElementById('track-avoidstr'),vA=document.getElementById('val-avoidstr');
            UR(rA,tA,0,100,vA,'%',v=>S('avoidstr',v));rA.addEventListener('input',()=>UR(rA,tA,0,100,vA,'%',v=>S('avoidstr',v)));
            ['bot','killaura','dodgeatk','dodgecd','autorespawn','collectfood','fleedanger','enemyrange','cooldown','tracers','hitboxes','killable','skipteam'].forEach(id=>{
                const el=document.getElementById('tgl-'+id);if(el)el.addEventListener('change',function(){S(id,this.checked);});
            });
            document.getElementById('sel-sprintmode').addEventListener('change',function(){S('sprintmode',parseInt(this.value))});
            let waiting=false;
            const curDisp=document.getElementById('current-hotkey'),waitStatus=document.getElementById('waiting-status'),changeBtn=document.getElementById('change-hotkey');
            function getKeyDisplay(k){const m={'Insert':'Insert','Delete':'Del','Home':'Home','End':'End','PageUp':'PgUp','PageDown':'PgDn','ArrowUp':'\u2191','ArrowDown':'\u2193','ArrowLeft':'\u2190','ArrowRight':'\u2192',' ':'Space','Escape':'Esc'};return m[k]||(k.length===1?k.toUpperCase():k);}
            function saveHotkey(k){localStorage.setItem('evoware_toggle_key',k);curDisp.textContent=getKeyDisplay(k);window.parent.postMessage({evoware:1,type:'hotkeyChanged',data:k},'*');}
            function loadHotkey(){const s=localStorage.getItem('evoware_toggle_key');curDisp.textContent=getKeyDisplay(s||'Insert');return s||'Insert';}
            changeBtn.addEventListener('click',function(){waiting=true;waitStatus.textContent='Press any key...';changeBtn.textContent='Waiting...';});
            document.addEventListener('keydown',function(e){if(!waiting)return;e.preventDefault();e.stopPropagation();const k=e.key===' '?' ':e.key;saveHotkey(k);waiting=false;waitStatus.textContent='';changeBtn.textContent='Set';});
            loadHotkey();
            window.addEventListener('message',function(e){
                if(!e.data||!e.data.evoware)return;
                const d=e.data;
                if(d.type==='updateStats'){
                    document.getElementById('txt-level').textContent=d.level;
                    document.getElementById('txt-range').textContent=d.range;
                    document.getElementById('txt-target').textContent=d.target;
                    document.getElementById('txt-nearby').textContent=d.nearby;
                    document.getElementById('txt-botstate').textContent=d.botstate;
                    document.getElementById('txt-botstate').style.color=d.botstate==='ON'?'#4ade80':'#ef4444';
                }
                if(d.type==='updateBot'){document.getElementById('tgl-bot').checked=d.checked;document.getElementById('txt-botstate').textContent=d.checked?'ON':'OFF';document.getElementById('txt-botstate').style.color=d.checked?'#4ade80':'#ef4444';}
                if(d.type==='updateKillaura'){document.getElementById('tgl-killaura').checked=d.checked;}
                if(d.type==='updateAutorespawn'){document.getElementById('tgl-autorespawn').checked=d.checked;}
                if(d.type==='updateDodge'){document.getElementById('tgl-dodgeatk').checked=d.checked;}
                if(d.type==='updateCollectFood'){document.getElementById('tgl-collectfood').checked=d.checked;}
                if(d.type==='updateFlee'){document.getElementById('tgl-fleedanger').checked=d.checked;}
            });
        <\/script></body></html>`);
    doc.close();

    let rt, pType, gameCanvas;
    let showTracers = false, showHitboxes = false, showKillable = false, showEnemyRange = false, showCooldown = false;
    let botActive = false, killaura = false, dodgeAttacks = false, dodgeOnCD = false, autoRespawn = false;
    let offset = 135, zoomLevel = 0.5, lvlMin = 0, lvlMax = 100;
    let maxHigherLevel = 0, minLowerLevel = 0, safeDistMult = 2.0, avoidStrength = 0.5;
    let collectFood = true, sprintMode = 1, fleeDanger = false, skipTeammates = true;
    let target = null, targetLevel = 0, menuVisible = true;
    let currentAngle = null, rightHeld = false;
    let lastAttackTime = 0, lastDodge = 0, lastRespawnTry = 0;
    let gameStartTime = 0;
    let enemyTimers = new Map(), enemyPrevAngle = new Map(), enemyPrevDist = new Map(), enemySpawnTime = new Map();
    let nc = 0, isDead = false, deathTime = 0, boostTimeout = null, toggleKey = 'Insert';
    let lastDrawTime = 0, lastStatsTime = 0, lastFoodScanTime = 0, foodScanFrame = 0, cachedFoodPos = null;
    let stuckCount = 0, lastSelfPos = { x: 0, y: 0 }, lastSelfPosTime = 0;

    function loadToggleKey() { const s = localStorage.getItem('evoware_toggle_key'); if (s) toggleKey = s; }
    loadToggleKey();

    function getAttackCooldown(lv) {
        return lv <= 5 ? 800 : lv <= 10 ? 1100 : lv <= 15 ? 1400 : lv <= 20 ? 1700 :
               lv <= 25 ? 2000 : lv <= 30 ? 2300 : lv <= 35 ? 2600 : lv <= 40 ? 2900 :
               lv <= 45 ? 3200 : lv <= 50 ? 3500 : lv <= 55 ? 3800 : lv <= 60 ? 4100 :
               lv <= 65 ? 4400 : lv <= 70 ? 4700 : lv <= 75 ? 5000 : lv <= 80 ? 5300 :
               lv <= 85 ? 5600 : lv <= 90 ? 5900 : lv <= 95 ? 6200 : 6500;
    }

    function applyZoom() {
        if (!rt?.running_layout?.layers) return;
        for (const l of rt.running_layout.layers) {
            if (l?.scale !== undefined) { l.scale = zoomLevel; if (l.setZIndicesStaleFrom) l.setZIndicesStaleFrom(0); }
        }
        rt.redraw = true;
    }

    function computeRange(sz, lv) {
        if (!sz) return 0;
        let m = 2.18 - Math.min(lv, 100) * 0.0034;
        if (m < 1.85) m = 1.85;
        if (lv >= 25) m += 0.04;
        if (lv >= 45) m += 0.04;
        if (lv >= 70) m += 0.05;
        return sz * m;
    }

    function gs(obj) {
        if (!obj) return { lv: 0, sz: 0, rng: 0 };
        let lv = 0, sz = obj.width || 0;
        try {
            if (obj.instance_vars) {
                let lvs = [];
                for (let i = 0; i < obj.instance_vars.length; i++) {
                    const v = obj.instance_vars[i];
                    if (typeof v === 'number' && v >= 1 && v <= 200 && Number.isInteger(v)) lvs.push({ i, v });
                }
                if (lvs.length) {
                    lvs.sort((a, b) => b.v - a.v);
                    const early = lvs.filter(l => l.i < 15);
                    lv = early.length >= 2 ? early[1].v : (early.length === 1 ? early[0].v + 1 : lvs[0].v + 1);
                }
            }
        } catch (e) {}
        if (!lv && sz > 0) lv = Math.max(1, Math.floor(sz / 3.5));
        return { lv, sz, rng: computeRange(sz, lv) };
    }

    function getColorTag(obj) {
        try {
            if (obj.colorRgb !== undefined) return obj.colorRgb;
            if (obj.color !== undefined) return obj.color;
            if (obj.effects && obj.effects[0] && obj.effects[0].parameters) return obj.effects[0].parameters.join(',');
        } catch (e) {}
        return null;
    }

    function isTeammate(self, p) {
        if (!skipTeammates) return false;
        const a = getColorTag(self), b = getColorTag(p);
        if (a === null || b === null) return false;
        return a === b;
    }

    function getPlayer() {
        if (!rt?.running_layout || !pType) return null;
        const instances = pType.instances;
        let self = null, md = Infinity;
        for (let i = 0; i < instances.length; i++) {
            const p = instances[i]; if (!p) continue;
            const d = Math.hypot(p.x - rt.running_layout.scrollX, p.y - rt.running_layout.scrollY);
            if (d < md && d < 500) { md = d; self = p; }
        }
        return self;
    }

    function sendStats() {
        const self = getPlayer();
        const ps = self ? gs(self) : null;
        iframe.contentWindow.postMessage({
            evoware: 1, type: 'updateStats',
            level: ps ? 'Lv.' + ps.lv : '--',
            range: ps ? Math.floor(ps.rng) + 'u' : '--',
            target: targetLevel > 0 ? 'Lv.' + targetLevel : '--',
            nearby: nc,
            botstate: botActive ? 'ON' : 'OFF'
        }, '*');
    }

    function simMouse(type, clientX, clientY, button = 0, buttons = 0) {
        if (!gameCanvas) return;
        const opts = { bubbles: true, cancelable: true, view: window, clientX, clientY, button, buttons };
        gameCanvas.dispatchEvent(new MouseEvent(type, opts));
        document.dispatchEvent(new MouseEvent(type, opts));
    }

    function worldToScreen(wx, wy, self) {
        const rect = gameCanvas.getBoundingClientRect();
        const sc = self.layer.getScale();
        return { x: rect.left + rect.width / 2 + (wx - self.x) * sc, y: rect.top + rect.height / 2 + (wy - self.y) * sc };
    }

    function ensureRightHold(shouldHold) {
        if (!gameCanvas) return;
        const rect = gameCanvas.getBoundingClientRect();
        const cx = rect.left + rect.width / 2, cy = rect.top + rect.height / 2;
        if (shouldHold && !rightHeld) { simMouse('mousedown', cx, cy, 2, 2); rightHeld = true; }
        else if (!shouldHold && rightHeld) { simMouse('mouseup', cx, cy, 2, 0); rightHeld = false; }
    }

    function forceReleaseRight() {
        if (gameCanvas && rightHeld) {
            const rect = gameCanvas.getBoundingClientRect();
            simMouse('mouseup', rect.left + rect.width / 2, rect.top + rect.height / 2, 2, 0);
        }
        rightHeld = false;
    }

    function updateSpawnTimes() {
        if (!pType) return;
        const now = performance.now(), aliveUIDs = new Set();
        for (let i = 0; i < pType.instances.length; i++) {
            const p = pType.instances[i]; if (!p || p.width <= 0) continue;
            aliveUIDs.add(p.uid);
            if (!enemySpawnTime.has(p.uid)) enemySpawnTime.set(p.uid, now);
        }
        for (const uid of enemySpawnTime.keys()) { if (!aliveUIDs.has(uid)) enemySpawnTime.delete(uid); }
    }

    function isRecentlySpawned(uid) {
        const spawn = enemySpawnTime.get(uid);
        return spawn ? (performance.now() - spawn) < 1200 : false;
    }

    function performAttack(p, self, ps, sc, vx, vy) {
        const dx = p.x - self.x, dy = p.y - self.y;
        const at = Math.atan2(dy, dx);
        const or = (offset * Math.PI) / 180;
        self.angle = ((at + or) % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2);
        const ex = vx + dx * sc, ey = vy + dy * sc;
        simMouse('mousemove', ex, ey);
        simMouse('mousedown', ex, ey, 0, 1);
        simMouse('mouseup', ex, ey, 0, 0);
        lastAttackTime = performance.now();
    }

    function killAll() {
        const self = getPlayer(); if (!self) return;
        const ps = gs(self); if (!ps.sz) return;
        const now = performance.now();
        if (now - lastAttackTime < getAttackCooldown(ps.lv)) return;
        const rect = gameCanvas.getBoundingClientRect();
        const sc = self.layer.getScale();
        const vx = rect.left + rect.width / 2, vy = rect.top + rect.height / 2;
        const instances = pType.instances;
        let bestTarget = null, bestDist = Infinity;
        for (let i = 0; i < instances.length; i++) {
            const p = instances[i]; if (!p || p.uid === self.uid || p.width <= 0) continue;
            if (isRecentlySpawned(p.uid)) continue;
            if (isTeammate(self, p)) continue;
            const dist = Math.hypot(p.x - self.x, p.y - self.y);
            if (dist > ps.rng * 1.06) continue;
            const es = gs(p);
            if (es.lv < lvlMin || es.lv > lvlMax) continue;
            if (dist < bestDist) { bestDist = dist; bestTarget = p; }
        }
        if (!bestTarget) { target = null; targetLevel = 0; return; }
        target = bestTarget; targetLevel = gs(target).lv;
        performAttack(bestTarget, self, ps, sc, vx, vy);
    }

    function getThreats(self, ps) {
        if (!self || !pType) return [];
        const threats = [], instances = pType.instances;
        for (let i = 0; i < instances.length; i++) {
            const p = instances[i]; if (!p || p.uid === self.uid || p.width <= 0) continue;
            if (isTeammate(self, p)) continue;
            const dx = p.x - self.x, dy = p.y - self.y, dist = Math.hypot(dx, dy);
            const es = gs(p);
            if (dist > es.rng * 1.5) continue;
            let isAttacking = false, isBoosting = false;
            const angle = p.angle || 0, prevAngle = enemyPrevAngle.get(p.uid);
            if (prevAngle !== undefined) {
                const nd = Math.min(Math.abs(angle - prevAngle), Math.PI * 2 - Math.abs(angle - prevAngle));
                if (nd > 0.15) {
                    const ata = Math.atan2(dy, dx);
                    if (Math.abs(angle - ata) < 0.8 || dist < es.rng) isAttacking = true;
                }
            }
            enemyPrevAngle.set(p.uid, angle);
            const prevDist = enemyPrevDist.get(p.uid);
            if (prevDist !== undefined && (prevDist - dist) > 20 && dist < es.rng * 1.2) isBoosting = true;
            enemyPrevDist.set(p.uid, dist);
            if (isAttacking || isBoosting || dist < ps.rng * 0.8) threats.push({ dx, dy, dist, es, isAttacking, isBoosting });
        }
        const alive = new Set();
        for (let i = 0; i < pType.instances.length; i++) { const p = pType.instances[i]; if (p?.uid && p.width > 0) alive.add(p.uid); }
        for (const uid of enemyPrevAngle.keys()) { if (!alive.has(uid)) enemyPrevAngle.delete(uid); }
        for (const uid of enemyPrevDist.keys()) { if (!alive.has(uid)) enemyPrevDist.delete(uid); }
        return threats;
    }

    function tryDodge(self) {
        const now = performance.now();
        if (!dodgeAttacks || now - lastDodge < 500) return false;
        if (dodgeOnCD && now - lastAttackTime < 300) return false;
        const ps = gs(self);
        const threats = getThreats(self, ps);
        if (!threats.length) return false;
        let bestThreat = null;
        for (const t of threats) { if (!bestThreat || t.dist < bestThreat.dist) bestThreat = t; }
        const urgent = bestThreat.isAttacking || bestThreat.isBoosting || bestThreat.dist < ps.rng;
        if (!urgent) return false;
        const swarm = threats.length > 1;
        const ourCdRem = Math.max(0, getAttackCooldown(ps.lv) - (now - lastAttackTime));
        if (!swarm && killaura && ourCdRem < bestThreat.dist * 0.5 - 150) return false;
        const pushStr = swarm ? 20 : 14;
        const pushX = -(bestThreat.dx / bestThreat.dist) * pushStr;
        const pushY = -(bestThreat.dy / bestThreat.dist) * pushStr;
        const perpX = -bestThreat.dy / bestThreat.dist * pushStr * 0.6;
        const perpY = bestThreat.dx / bestThreat.dist * pushStr * 0.6;
        self.x += pushX + perpX; self.y += pushY + perpY;
        if (rt?.running_layout) { rt.running_layout.scrollX += pushX + perpX; rt.running_layout.scrollY += pushY + perpY; }
        if (!botActive) {
            if (boostTimeout) clearTimeout(boostTimeout);
            const rect = gameCanvas.getBoundingClientRect();
            const cx = rect.left + rect.width / 2, cy = rect.top + rect.height / 2;
            if (rightHeld) { simMouse('mouseup', cx, cy, 2, 0); rightHeld = false; }
            simMouse('mousedown', cx, cy, 2, 2);
            boostTimeout = setTimeout(() => { simMouse('mouseup', cx, cy, 2, 0); boostTimeout = null; }, 150);
        }
        lastDodge = now;
        return true;
    }

    function findPlayButtonRect() {
        const all = document.querySelectorAll('div');
        for (const el of all) {
            if ((el.textContent || '').trim().toUpperCase() !== 'PLAY') continue;
            const style = window.getComputedStyle(el);
            if (style.display === 'none' || style.visibility === 'hidden') continue;
            if (el.offsetParent === null && style.position !== 'fixed') continue;
            const r = el.getBoundingClientRect();
            if (r.width > 0 && r.height > 0) return r;
        }
        return null;
    }

    function clickAt(cx, cy) {
        const o = { bubbles: true, cancelable: true, view: window, clientX: cx, clientY: cy, button: 0, buttons: 1 };
        document.dispatchEvent(new MouseEvent('mousemove', o));
        document.dispatchEvent(new MouseEvent('mousedown', o));
        document.dispatchEvent(new MouseEvent('mouseup', o));
        document.dispatchEvent(new MouseEvent('click', o));
        if (gameCanvas) {
            gameCanvas.dispatchEvent(new MouseEvent('mousemove', o));
            gameCanvas.dispatchEvent(new MouseEvent('mousedown', o));
            gameCanvas.dispatchEvent(new MouseEvent('mouseup', o));
            gameCanvas.dispatchEvent(new MouseEvent('click', o));
        }
    }

    function tryRespawn() {
        const now = performance.now();
        if (now - deathTime < 1100) return;
        if (now - lastRespawnTry < 1600) return;
        lastRespawnTry = now;
        if (!gameCanvas || !gameCanvas.isConnected) { const lc = rt?.canvas; if (lc) gameCanvas = lc; }
        if (!gameCanvas) return;
        for (const key of [{ key: 'Enter', keyCode: 13 }, { key: ' ', keyCode: 32 }]) {
            document.dispatchEvent(new KeyboardEvent('keydown', { ...key, bubbles: true, cancelable: true }));
            document.dispatchEvent(new KeyboardEvent('keyup', { ...key, bubbles: true, cancelable: true }));
            gameCanvas.dispatchEvent(new KeyboardEvent('keydown', { ...key, bubbles: true, cancelable: true }));
            gameCanvas.dispatchEvent(new KeyboardEvent('keyup', { ...key, bubbles: true, cancelable: true }));
        }
        const tryClick = (attempt) => {
            if (getPlayer()) return;
            const r = findPlayButtonRect();
            if (r) {
                clickAt(r.left + r.width / 2, r.top + r.height / 2);
            } else if (attempt === 0 && gameCanvas) {
                const rect = gameCanvas.getBoundingClientRect();
                const cx = rect.left + rect.width / 2, cy = rect.top + rect.height / 2;
                [[-40,-80],[0,-40],[0,0],[0,40],[0,80],[60,-40],[-60,-40],[0,120]].forEach(([dx,dy],i) => {
                    setTimeout(() => { if (!getPlayer()) clickAt(cx + dx, cy + dy); }, i * 50);
                });
            }
        };
        for (let i = 0; i < 6; i++) setTimeout(() => tryClick(i), i * 120);
    }

    const FOOD_COLORS = [
        [0xb9,0x5a,0xd9],[0xea,0xea,0xea],[0xfd,0xaf,0xa3],
        [0x7e,0xf0,0x88],[0xf8,0xf8,0x9e],[0x91,0xf3,0xf5],[0x7f,0x7f,0x7e]
    ];
    function isFoodColor(r, g, b) {
        for (const [fr,fg,fb] of FOOD_COLORS) if (Math.abs(r-fr)<30 && Math.abs(g-fg)<30 && Math.abs(b-fb)<30) return true;
        return false;
    }
    function findClosestFood(self) {
        if (!gameCanvas) return null;
        let ctx2 = null;
        try { ctx2 = gameCanvas.getContext('2d', { willReadFrequently: true }); } catch(e) { return null; }
        if (!ctx2) return null;
        const rect = gameCanvas.getBoundingClientRect();
        const sc = self.layer.getScale();
        const cx = rect.left + rect.width / 2, cy = rect.top + rect.height / 2;
        const maxRadius = Math.min(500, Math.max(rect.width, rect.height) / 2);
        let bestDistSq = Infinity, bestPos = null;
        for (let r = 20; r <= maxRadius; r += 20) {
            const steps = Math.max(16, Math.floor(r * 0.5));
            for (let i = 0; i < steps; i++) {
                const angle = (i / steps) * Math.PI * 2;
                const px = cx + Math.cos(angle) * r, py = cy + Math.sin(angle) * r;
                if (px < 0 || py < 0 || px >= gameCanvas.width || py >= gameCanvas.height) continue;
                try {
                    const d = ctx2.getImageData(px, py, 1, 1).data;
                    if (isFoodColor(d[0], d[1], d[2])) {
                        const wx = self.x + (px - cx) / sc, wy = self.y + (py - cy) / sc;
                        const dsq = (wx-self.x)**2 + (wy-self.y)**2;
                        if (dsq < bestDistSq) { bestDistSq = dsq; bestPos = { x: wx, y: wy }; }
                    }
                } catch(e) {}
            }
            if (bestDistSq < r*r) break;
        }
        return bestPos;
    }

    function smoothTurn(desired) {
        let diff = desired - currentAngle;
        while (diff > Math.PI) diff -= Math.PI * 2;
        while (diff < -Math.PI) diff += Math.PI * 2;
        const maxTurn = 0.35;
        if (Math.abs(diff) > maxTurn) diff = Math.sign(diff) * maxTurn;
        currentAngle += diff;
        currentAngle = ((currentAngle % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2);
    }

    function placeCursor(self) {
        const pos = worldToScreen(self.x + Math.cos(currentAngle) * 100, self.y + Math.sin(currentAngle) * 100, self);
        simMouse('mousemove', pos.x, pos.y);
    }

    function checkStuck(self) {
        const now = performance.now();
        if (now - lastSelfPosTime < 1200) return;
        const moved = Math.hypot(self.x - lastSelfPos.x, self.y - lastSelfPos.y);
        if (moved < 12 && botActive && !isDead) {
            stuckCount++;
            currentAngle = Math.random() * Math.PI * 2;
            cachedFoodPos = null;
            if (stuckCount >= 4) {
                self.x += Math.cos(currentAngle) * 20; self.y += Math.sin(currentAngle) * 20;
                if (rt?.running_layout) { rt.running_layout.scrollX += Math.cos(currentAngle) * 20; rt.running_layout.scrollY += Math.sin(currentAngle) * 20; }
                stuckCount = 0;
            }
        } else { stuckCount = 0; }
        lastSelfPos = { x: self.x, y: self.y }; lastSelfPosTime = now;
    }

    function autoHunt() {
        const self = getPlayer(); if (!self) return;
        const ps = gs(self); if (!ps.sz) return;
        if (currentAngle === null) currentAngle = self.angle || 0;
        checkStuck(self);

        const MAP_SIZE = 5000, MARGIN = 400;
        let edgePushX = 0, edgePushY = 0;
        if (self.x < MARGIN) edgePushX = 1; else if (self.x > MAP_SIZE - MARGIN) edgePushX = -1;
        if (self.y < MARGIN) edgePushY = 1; else if (self.y > MAP_SIZE - MARGIN) edgePushY = -1;

        const maxTargetLv = maxHigherLevel >= 20 ? Infinity : ps.lv + maxHigherLevel;
        const minTargetLv = minLowerLevel >= 20 ? -Infinity : ps.lv - minLowerLevel;
        const now = performance.now();
        const cd = getAttackCooldown(ps.lv);
        const onCD = now - lastAttackTime < cd;
        const cdRem = onCD ? cd - (now - lastAttackTime) : 0;
        const instances = pType.instances;

        let nearbyAttackers = 0, avgX = 0, avgY = 0;
        for (let i = 0; i < instances.length; i++) {
            const p = instances[i]; if (!p || p.uid === self.uid || p.width <= 0) continue;
            if (isTeammate(self, p)) continue;
            const e_rng = computeRange(p.width || 0, gs(p).lv);
            const dist = Math.hypot(p.x - self.x, p.y - self.y);
            if (dist < e_rng * 1.15) { nearbyAttackers++; avgX += p.x; avgY += p.y; }
        }
        if (nearbyAttackers >= 2) {
            avgX /= nearbyAttackers; avgY /= nearbyAttackers;
            smoothTurn(Math.atan2(self.y - avgY, self.x - avgX));
            placeCursor(self); ensureRightHold(true);
            target = null; targetLevel = 0; return;
        }

        if (fleeDanger) {
            for (let i = 0; i < instances.length; i++) {
                const p = instances[i]; if (!p || p.uid === self.uid || p.width <= 0) continue;
                if (isTeammate(self, p)) continue;
                const es = gs(p);
                if (es.lv <= maxTargetLv) continue;
                const dx = self.x - p.x, dy = self.y - p.y, dist = Math.hypot(dx, dy);
                if (dist < es.rng * 2.0 && dist > 0.01) {
                    smoothTurn(Math.atan2(dy, dx)); placeCursor(self);
                    ensureRightHold(sprintMode !== 2); return;
                }
            }
        }

        let bestTarget = null, bestScore = -Infinity;
        for (let i = 0; i < instances.length; i++) {
            const p = instances[i]; if (!p || p.uid === self.uid || p.width <= 0) continue;
            if (isRecentlySpawned(p.uid)) continue;
            if (isTeammate(self, p)) continue;
            const es = gs(p);
            if (es.lv < lvlMin || es.lv > lvlMax) continue;
            if (es.lv > maxTargetLv || es.lv < minTargetLv) continue;
            const dist = Math.hypot(p.x - self.x, p.y - self.y);
            const score = (8000 - dist) - Math.max(0, es.lv - ps.lv) * 600;
            if (score > bestScore) { bestScore = score; bestTarget = p; }
        }

        let avoidAngle = 0, avoidWeight = 0;
        for (let i = 0; i < instances.length; i++) {
            const p = instances[i]; if (!p || p.uid === self.uid || p.width <= 0) continue;
            if (isTeammate(self, p)) continue;
            const es = gs(p);
            if (es.lv <= maxTargetLv) continue;
            const dx = self.x - p.x, dy = self.y - p.y, dist = Math.hypot(dx, dy);
            const safeDist = es.rng * safeDistMult + es.sz * 0.5;
            if (dist < safeDist && dist > 0.01) {
                const w = (safeDist - dist) / safeDist;
                if (w > avoidWeight) { avoidWeight = w * avoidStrength; avoidAngle = Math.atan2(dy, dx); }
            }
        }

        if (onCD && cdRem > 300 && bestTarget) {
            const dist = Math.hypot(bestTarget.x - self.x, bestTarget.y - self.y);
            if (dist < ps.rng * 1.15) {
                smoothTurn(Math.atan2(self.y - bestTarget.y, self.x - bestTarget.x));
                placeCursor(self); ensureRightHold(sprintMode !== 2);
                target = bestTarget; targetLevel = gs(bestTarget).lv; return;
            }
        }

        let goalAngle;
        if (bestTarget) {
            target = bestTarget; targetLevel = gs(bestTarget).lv;
            goalAngle = Math.atan2(bestTarget.y - self.y, bestTarget.x - self.x);
            cachedFoodPos = null;
        } else {
            target = null; targetLevel = 0;
            if (collectFood && (foodScanFrame++ % 10 === 0 || now - lastFoodScanTime > 500)) {
                lastFoodScanTime = now; cachedFoodPos = findClosestFood(self);
            }
            if (collectFood && cachedFoodPos) goalAngle = Math.atan2(cachedFoodPos.y - self.y, cachedFoodPos.x - self.x);
            else if (edgePushX !== 0 || edgePushY !== 0) goalAngle = Math.atan2(edgePushY, edgePushX);
            else goalAngle = currentAngle + (Math.random() - 0.5) * 0.1;
        }

        let finalAngle = goalAngle;
        if (avoidWeight > 0.05) {
            let diff = avoidAngle - goalAngle;
            while (diff > Math.PI) diff -= Math.PI * 2;
            while (diff < -Math.PI) diff += Math.PI * 2;
            finalAngle = goalAngle + diff * Math.min(avoidWeight, 0.85);
        }
        smoothTurn(finalAngle); placeCursor(self);

        let sprint = false;
        switch (sprintMode) { case 0: sprint = true; break; case 1: sprint = !!bestTarget; break; case 2: sprint = false; break; }
        ensureRightHold(sprint);

        if (bestTarget && !killaura) {
            const dist = Math.hypot(bestTarget.x - self.x, bestTarget.y - self.y);
            if (dist <= ps.rng * 0.97 && !onCD) {
                const rect = gameCanvas.getBoundingClientRect();
                const sc = self.layer.getScale();
                const vx = rect.left + rect.width / 2, vy = rect.top + rect.height / 2;
                performAttack(bestTarget, self, ps, sc, vx, vy);
            }
        }
    }

    function updateTimers() {
        if (!pType || !gameStartTime) return;
        const instances = pType.instances;
        for (let i = 0; i < instances.length; i++) {
            const p = instances[i]; if (!p?.uid || p.width <= 0) continue;
            if (!enemyTimers.has(p.uid)) { const es = gs(p); enemyTimers.set(p.uid, { cd: getAttackCooldown(es.lv) }); }
        }
        const alive = new Set();
        for (let i = 0; i < instances.length; i++) { const p = instances[i]; if (p?.uid && p.width > 0) alive.add(p.uid); }
        for (const uid of enemyTimers.keys()) { if (!alive.has(uid)) enemyTimers.delete(uid); }
    }

    const esp = document.createElement('canvas');
    const ctx = esp.getContext('2d');
    esp.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:999998;';
    esp.width = innerWidth; esp.height = innerHeight;
    document.body.appendChild(esp);
    window.addEventListener('resize', () => { esp.width = innerWidth; esp.height = innerHeight; });

    function draw() {
        const now = performance.now();
        if (now - lastDrawTime < 16) return;
        lastDrawTime = now;
        if (!rt?.running_layout || !pType) return;
        const self = getPlayer(); if (!self) return;
        const ps = gs(self);
        const rect = gameCanvas.getBoundingClientRect();
        const sc = self.layer.getScale();
        const vx = rect.left + rect.width / 2, vy = rect.top + rect.height / 2;
        const instances = pType.instances;
        ctx.clearRect(0, 0, esp.width, esp.height);
        let nearby = 0;

        if (dodgeAttacks) {
            const sr = Math.max(ps.rng, 80) * 1.5 * sc;
            ctx.beginPath(); ctx.arc(vx, vy, sr, 0, Math.PI * 2);
            ctx.strokeStyle = dodgeOnCD ? 'rgba(251,191,36,0.4)' : 'rgba(74,222,128,0.4)';
            ctx.lineWidth = 2; ctx.setLineDash([5, 5]); ctx.stroke(); ctx.setLineDash([]);
        }
        if (killaura || botActive) {
            ctx.beginPath(); ctx.arc(vx, vy, ps.rng * sc, 0, Math.PI * 2);
            ctx.strokeStyle = 'rgba(124,58,237,0.3)'; ctx.lineWidth = 1.5;
            ctx.setLineDash([4, 4]); ctx.stroke(); ctx.setLineDash([]);
        }
        if (target && (killaura || botActive)) {
            const angle = self.angle || 0, bl = ps.sz * 0.9 * sc;
            const dx = target.x - self.x, dy = target.y - self.y, da = Math.atan2(dy, dx);
            ctx.beginPath(); ctx.moveTo(vx, vy); ctx.lineTo(vx + Math.cos(da) * bl, vy + Math.sin(da) * bl);
            ctx.strokeStyle = 'rgba(255,255,255,0.3)'; ctx.lineWidth = 1.5; ctx.setLineDash([2, 2]); ctx.stroke();
            ctx.beginPath(); ctx.moveTo(vx, vy); ctx.lineTo(vx + Math.cos(angle) * bl, vy + Math.sin(angle) * bl);
            ctx.strokeStyle = '#a855f7'; ctx.lineWidth = 3; ctx.setLineDash([]); ctx.stroke();
            const or2 = (offset * Math.PI) / 180;
            ctx.beginPath(); ctx.moveTo(vx, vy); ctx.lineTo(vx + Math.cos(da + or2) * bl, vy + Math.sin(da + or2) * bl);
            ctx.strokeStyle = '#22c55e'; ctx.lineWidth = 2; ctx.setLineDash([3, 3]); ctx.stroke(); ctx.setLineDash([]);
        }

        for (let i = 0; i < instances.length; i++) {
            const p = instances[i]; if (!p || p.uid === self.uid || p.width <= 0) continue;
            const es = gs(p); if (es.lv <= 0) continue;
            const px = vx + (p.x - self.x) * sc, py = vy + (p.y - self.y) * sc;
            const dist = Math.hypot(p.x - self.x, p.y - self.y);
            const inRng = dist <= ps.rng, killable = es.lv <= ps.lv, danger = es.lv > ps.lv * 1.3;
            if (inRng) nearby++;
            if (showCooldown) {
                const t = enemyTimers.get(p.uid);
                if (t) {
                    const elapsed = (now - gameStartTime) % t.cd, remaining = t.cd - elapsed, pct = elapsed / t.cd;
                    ctx.beginPath(); ctx.arc(px, py, 28, 0, Math.PI * 2);
                    ctx.strokeStyle = 'rgba(255,255,255,0.08)'; ctx.lineWidth = 2.5; ctx.stroke();
                    ctx.beginPath(); ctx.arc(px, py, 28, -Math.PI / 2, -Math.PI / 2 + Math.PI * 2 * pct);
                    ctx.strokeStyle = pct < 0.15 ? '#22c55e' : '#f59e0b'; ctx.lineWidth = 2.5; ctx.stroke();
                    ctx.fillStyle = '#fff'; ctx.font = 'bold 9px Arial'; ctx.textAlign = 'center';
                    ctx.fillText((remaining / 1000).toFixed(1) + 's', px, py - 34);
                }
            }
            if (showKillable && inRng) {
                ctx.beginPath(); ctx.arc(px, py, 22, 0, Math.PI * 2);
                if (killable) {
                    ctx.shadowColor = '#22c55e'; ctx.shadowBlur = 15;
                    ctx.strokeStyle = '#22c55e'; ctx.lineWidth = 3; ctx.stroke(); ctx.shadowBlur = 0;
                } else if (danger) {
                    ctx.shadowColor = '#ef4444'; ctx.shadowBlur = 15;
                    ctx.strokeStyle = '#ef4444'; ctx.lineWidth = 3; ctx.setLineDash([4, 4]); ctx.stroke(); ctx.setLineDash([]); ctx.shadowBlur = 0;
                }
            }
            if (showEnemyRange && es.rng > 0) {
                ctx.beginPath(); ctx.arc(px, py, es.rng * sc, 0, Math.PI * 2);
                ctx.strokeStyle = dist < es.rng ? 'rgba(255,60,60,0.9)' : 'rgba(255,60,60,0.5)';
                ctx.lineWidth = 2; ctx.setLineDash([2, 2]); ctx.stroke(); ctx.setLineDash([]);
            }
            if (showHitboxes) {
                const r = (p.width / 2) * sc * 1.5;
                ctx.beginPath(); ctx.arc(px, py, r, 0, Math.PI * 2);
                ctx.fillStyle = killable ? 'rgba(34,197,94,0.08)' : 'rgba(124,58,237,0.08)'; ctx.fill();
                ctx.strokeStyle = killable ? '#22c55e' : '#a855f7'; ctx.lineWidth = 1; ctx.stroke();
            }
            if (showTracers) {
                ctx.beginPath(); ctx.moveTo(vx, vy); ctx.lineTo(px, py);
                ctx.strokeStyle = inRng ? (killable ? 'rgba(34,197,94,0.6)' : 'rgba(168,85,247,0.5)') : 'rgba(168,85,247,0.12)';
                ctx.lineWidth = inRng ? 1.5 : 0.5; ctx.stroke();
            }
            if (target && p.uid === target.uid) {
                ctx.beginPath(); ctx.arc(px, py, 26, 0, Math.PI * 2);
                ctx.strokeStyle = '#a855f7'; ctx.lineWidth = 2.5; ctx.setLineDash([3, 3]); ctx.stroke(); ctx.setLineDash([]);
                ctx.fillStyle = '#fff'; ctx.font = 'bold 10px Arial'; ctx.textAlign = 'center';
                ctx.fillText('Lv.' + es.lv, px, py - 30);
            }
        }
        nc = nearby;
    }

    function enableBotMode(enable) {
        if (enable) {
            killaura = true; dodgeAttacks = true; autoRespawn = true; collectFood = true; fleeDanger = true;
            if (maxHigherLevel === 0) maxHigherLevel = 5;
            if (avoidStrength === 0.5) avoidStrength = 0.7;
            iframe.contentWindow.postMessage({ evoware: 1, type: 'updateKillaura', checked: true }, '*');
            iframe.contentWindow.postMessage({ evoware: 1, type: 'updateDodge', checked: true }, '*');
            iframe.contentWindow.postMessage({ evoware: 1, type: 'updateAutorespawn', checked: true }, '*');
            iframe.contentWindow.postMessage({ evoware: 1, type: 'updateCollectFood', checked: true }, '*');
            iframe.contentWindow.postMessage({ evoware: 1, type: 'updateFlee', checked: true }, '*');
        }
        botActive = enable;
        if (!botActive) { target = null; targetLevel = 0; forceReleaseRight(); }
        iframe.contentWindow.postMessage({ evoware: 1, type: 'updateBot', checked: botActive }, '*');
    }

    function loop() {
        try {
            if (rt?.running_layout && pType) {
                if (!gameStartTime) gameStartTime = performance.now();
                applyZoom(); updateTimers(); updateSpawnTimes();
                const self = getPlayer();
                if (!self) {
                    if (!isDead) { isDead = true; deathTime = performance.now(); forceReleaseRight(); currentAngle = null; target = null; targetLevel = 0; cachedFoodPos = null; stuckCount = 0; }
                    ctx.clearRect(0, 0, esp.width, esp.height);
                    if (autoRespawn) tryRespawn();
                } else {
                    if (isDead) { isDead = false; currentAngle = Math.random() * Math.PI * 2; lastSelfPos = { x: self.x, y: self.y }; lastSelfPosTime = performance.now(); stuckCount = 0; }
                    updateEntities(self);
                    const needDraw = showTracers || showHitboxes || showKillable || showEnemyRange || showCooldown || killaura || botActive || dodgeAttacks;
                    if (needDraw) draw(); else ctx.clearRect(0, 0, esp.width, esp.height);
                    if (dodgeAttacks) tryDodge(self);
                    if (killaura) killAll();
                    if (botActive) autoHunt();
                    const now = performance.now();
                    if (now - lastStatsTime > 200) { lastStatsTime = now; sendStats(); }
                }
            }
        } catch (e) {}
        requestAnimationFrame(loop);
    }

    function updateEntities(self) {
        if (!pType) return;
        const now = performance.now();
        for (let i = 0; i < pType.instances.length; i++) {
            const p = pType.instances[i]; if (!p || p.width <= 0 || p.uid === self.uid) continue;
        }
    }

    const init = setInterval(() => {
        if (window.cr_getC2Runtime && (rt = window.cr_getC2Runtime())) {
            clearInterval(init);
            gameCanvas = rt.canvas;
            for (const t of rt.types_by_index) { if (t?.instvar_sids?.length === 72) { pType = t; break; } }
            if (!pType) {
                for (const t of rt.types_by_index) {
                    if (t?.instances?.length > 0) {
                        const inst = t.instances[0];
                        if (inst.x !== undefined && inst.y !== undefined && inst.width !== undefined && inst.angle !== undefined) { pType = t; break; }
                    }
                }
            }
            loop();
        }
    }, 500);

    window.addEventListener('message', function (e) {
        if (!e.data || !e.data.evoware) return;
        const { type, data } = e.data;
        switch (type) {
            case 'bot':           enableBotMode(data); break;
            case 'killaura':      killaura = data; if (!killaura && !botActive) { target = null; targetLevel = 0; } break;
            case 'dodgeatk':      dodgeAttacks = data; if (!dodgeAttacks && boostTimeout) { clearTimeout(boostTimeout); boostTimeout = null; } break;
            case 'dodgecd':       dodgeOnCD = data; break;
            case 'autorespawn':   autoRespawn = data; break;
            case 'maxhigher':     maxHigherLevel = parseInt(data); break;
            case 'minlower':      minLowerLevel = parseInt(data); break;
            case 'safedist':      safeDistMult = parseFloat(data); break;
            case 'avoidstr':      avoidStrength = parseInt(data) / 100; break;
            case 'collectfood':   collectFood = data; break;
            case 'sprintmode':    sprintMode = parseInt(data); break;
            case 'fleedanger':    fleeDanger = data; break;
            case 'skipteam':      skipTeammates = data; break;
            case 'lvlrange':      lvlMin = data.min; lvlMax = data.max; break;
            case 'enemyrange':    showEnemyRange = data; break;
            case 'cooldown':      showCooldown = data; break;
            case 'tracers':       showTracers = data; break;
            case 'hitboxes':      showHitboxes = data; break;
            case 'killable':      showKillable = data; break;
            case 'offset':        offset = data; break;
            case 'zoom':          zoomLevel = data; break;
            case 'hotkeyChanged': toggleKey = data; localStorage.setItem('evoware_toggle_key', toggleKey); break;
        }
    });

    document.addEventListener('keydown', function (e) {
        if (e.key === toggleKey || e.key === 'Insert') {
            e.preventDefault(); e.stopPropagation();
            menuVisible = !menuVisible;
            iframe.style.opacity = menuVisible ? '1' : '0';
            iframe.style.pointerEvents = menuVisible ? 'auto' : 'none';
            return;
        }
        if ((e.key === 'f' || e.key === 'F') &&
            document.activeElement?.tagName !== 'INPUT' &&
            document.activeElement?.tagName !== 'TEXTAREA') {
            e.preventDefault(); e.stopPropagation();
            enableBotMode(!botActive);
        }
    }, true);

})();