Killaura, dodging, ESP, zoom, auto‑respawn and much more.| NEW: predictive dodge, custom hotkey (for opening and closing the menu), faster/lighter ESP, fixed dodge toggles and improved killaura. Buy me a coffee :) paypal.me/Izkuh
// ==UserScript==
// @name EvoWare
// @namespace http://tampermonkey.net/
// @version 2026-05-25
// @description Killaura, dodging, ESP, zoom, auto‑respawn and much more.| NEW: predictive dodge, custom hotkey (for opening and closing the menu), faster/lighter ESP, fixed dodge toggles and improved killaura. Buy me a coffee :) paypal.me/Izkuh
// @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:560px!important;height:600px!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}
::-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>Drag</span></div>
<div class="body"><div class="content">
<div class="col">
<div><div class="st">Combat</div><div class="sec">
<div class="row"><span>Killaura<span class="help" data-tip="Auto-aim & attack">?</span></span><label class="tgl"><input type="checkbox" id="tgl-killaura"><span class="sld"></span></label></div>
<div class="row"><span>Target Level<span class="help" data-tip="Min/Max enemy level to attack">?</span></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="Turn & boost away from threats">?</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="Dodge only while attack recharging">?</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-click 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 from target 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">Visuals</div><div class="sec">
<div class="row"><span>Enemy Range<span class="help" data-tip="Show enemy attack radius">?</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">?</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="Line 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 size">?</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="Highlight current target">?</span></span><label class="tgl"><input type="checkbox" id="tgl-killable"><span class="sld"></span></label></div>
</div></div>
</div>
<div class="col">
<div><div class="st">Settings</div><div class="sec">
<div class="row"><span>Zoom<span class="help" data-tip="Adjust camera zoom">?</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>Toggle Key</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" id="txt-level">--</span></div>
<div class="row"><span>Range</span><span class="stat-val" id="txt-range">--</span></div>
<div class="row"><span>Nearby</span><span class="stat-val" id="txt-nearby">0</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,st;
D.addEventListener('mousedown',function(e){if(e.target.tagName==='INPUT'||e.target.tagName==='LABEL')return;dr=true;sx=e.clientX;sy=e.clientY;const f=window.parent.document.getElementById('evoware-frame');sl=f.offsetLeft;st=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=st+(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):v.toFixed(2))+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/100*100)+'%';tL.style.width=((mx-mn)/100*100)+'%';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,'°',function(v){S('offset',v)});rO.addEventListener('input',function(){UR(rO,tO,0,360,vO,'°',function(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',function(v){S('zoom',v)});rZ.addEventListener('input',function(){UR(rZ,tZ,0.2,3,vZ,'x',function(v){S('zoom',v)})});
document.getElementById('tgl-killaura').addEventListener('change',function(){S('killaura',this.checked)});
document.getElementById('tgl-dodgeatk').addEventListener('change',function(){S('dodgeatk',this.checked)});
document.getElementById('tgl-dodgecd').addEventListener('change',function(){S('dodgecd',this.checked)});
document.getElementById('tgl-autorespawn').addEventListener('change',function(){S('autorespawn',this.checked)});
document.getElementById('tgl-enemyrange').addEventListener('change',function(){S('enemyrange',this.checked)});
document.getElementById('tgl-cooldown').addEventListener('change',function(){S('cooldown',this.checked)});
document.getElementById('tgl-tracers').addEventListener('change',function(){S('tracers',this.checked)});
document.getElementById('tgl-hitboxes').addEventListener('change',function(){S('hitboxes',this.checked)});
document.getElementById('tgl-killable').addEventListener('change',function(){S('killable',this.checked)});
let waiting=false;
const curDisp=document.getElementById('current-hotkey');
const waitStatus=document.getElementById('waiting-status');
const changeBtn=document.getElementById('change-hotkey');
function getKeyDisplay(k){const m={'Insert':'Insert','Delete':'Del','Home':'Home','End':'End','PageUp':'PgUp','PageDown':'PgDn','ArrowUp':'↑','ArrowDown':'↓','ArrowLeft':'←','ArrowRight':'→',' ':'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({type:'hotkeyChanged',key: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...';});
function captureKey(e){if(!waiting)return;e.preventDefault();e.stopPropagation();let k=e.key;if(k===' ')k=' ';if(k&&k!=='Insert')saveHotkey(k);waiting=false;waitStatus.textContent='';changeBtn.textContent='Set';}
document.addEventListener('keydown',captureKey);
loadHotkey();
window.addEventListener('message',function(e){if(!e.data||!e.data.evoware)return;if(e.data.type==='updateStats'){document.getElementById('txt-level').textContent=e.data.level;document.getElementById('txt-range').textContent=e.data.range;document.getElementById('txt-nearby').textContent=e.data.nearby}});
<\/script></body></html>`);
doc.close();
let rt, pType, gameCanvas;
let showTracers = false, showHitboxes = false, showKillable = false, showEnemyRange = false, showCooldown = false;
let killaura = false, dodgeAttacks = false, dodgeOnCD = false;
let autoRespawn = false;
let offset = 135, zoomLevel = 0.5, lvlMin = 0, lvlMax = 100;
let target = null, targetLevel = 0, menuVisible = true;
let lastDodge = 0, dodgeCD = 1200;
let lastAttackTime = 0;
let enemyTimers = new Map(), gameStartTime = 0;
let enemyPrevAngle = new Map();
let enemyPrevDist = new Map();
let lastRespawnTry = 0;
let boostTimeout = null;
let toggleKey = 'Insert';
let lastDrawTime = 0;
let drawThrottle = 16;
let lastDodgeCheck = 0;
let dodgeCheckThrottle = 30;
let lastStatsUpdate = 0;
let statsThrottle = 200;
function loadToggleKey(){const s=localStorage.getItem('evoware_toggle_key');if(s)toggleKey=s;}
loadToggleKey();
const getAttackCooldown = (level) => Math.max(100, level * 100);
function applyZoom() {
if (rt?.running_layout?.layers) {
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 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: sz * 2.2 };
}
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 updateStats() {
const self = getPlayer();
if (!self) {
iframe.contentWindow.postMessage({ evoware: 1, type: 'updateStats', level: '--', range: '--', nearby: 0 }, '*');
return;
}
const ps = gs(self);
let nearby = 0;
const instances = pType.instances;
for (let i = 0; i < instances.length; i++) {
const p = instances[i];
if (!p || p.uid === self.uid) continue;
if (p.width <= 0) continue;
const dist = Math.hypot(p.x - self.x, p.y - self.y);
if (dist <= ps.rng) nearby++;
}
iframe.contentWindow.postMessage({
evoware: 1, type: 'updateStats',
level: 'Lv.' + ps.lv,
range: Math.floor(ps.rng) + 'u',
nearby: nearby
}, '*');
}
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 killAll() {
const self = getPlayer(); if (!self) return;
const ps = gs(self); if (!ps) 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;
let bestDist = Infinity;
for (let i = 0; i < instances.length; i++) {
const p = instances[i]; if (!p || p.uid === self.uid) continue;
if (p.width <= 0) continue;
const dist = Math.hypot(p.x - self.x, p.y - self.y);
if (dist > ps.rng) 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;
const dx = target.x - self.x, dy = target.y - self.y;
const angleToTarget = Math.atan2(dy, dx);
const offsetRad = (offset * Math.PI) / 180;
self.angle = ((angleToTarget + offsetRad) % (Math.PI * 2) + (Math.PI * 2)) % (Math.PI * 2);
const sx = vx + (target.x - self.x) * sc;
const sy = vy + (target.y - self.y) * sc;
simMouse('mousedown', sx, sy, 0, 1);
simMouse('mouseup', sx, sy, 0, 0);
lastAttackTime = performance.now();
}
function getThreats(self, ps) {
if (!self || !pType) return [];
const threats = [];
const instances = pType.instances;
for (let i = 0; i < instances.length; i++) {
const p = instances[i];
if (!p || p.uid === self.uid) continue;
if (p.width <= 0) continue;
const dx = p.x - self.x;
const dy = p.y - self.y;
const dist = Math.hypot(dx, dy);
const es = gs(p);
const threatRange = es.rng * 1.5;
if (dist > threatRange) continue;
if (es.lv < lvlMin || es.lv > lvlMax) continue;
let isAttacking = false;
let isBoosting = false;
const angle = p.angle || 0;
const prevAngle = enemyPrevAngle.get(p.uid);
if (prevAngle !== undefined) {
const angleDiff = Math.abs(angle - prevAngle);
const ndiff = Math.min(angleDiff, Math.PI * 2 - angleDiff);
if (ndiff > 0.15) {
const angleToUs = Math.atan2(dy, dx);
const facingUs = Math.abs(angle - angleToUs) < 0.8;
if (facingUs || dist < es.rng) {
isAttacking = true;
}
}
}
enemyPrevAngle.set(p.uid, angle);
const prevDist = enemyPrevDist.get(p.uid);
if (prevDist !== undefined) {
const distChange = prevDist - dist;
if (distChange > 20 && dist < es.rng * 1.2) {
isBoosting = true;
}
}
enemyPrevDist.set(p.uid, dist);
threats.push({ dx, dy, dist, es, isAttacking, isBoosting });
}
const alive = new Set();
for (let i = 0; i < instances.length; i++) { const p = instances[i]; if (p && 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) return false;
if (now - lastDodge < dodgeCD) return false;
if (dodgeOnCD) {
const timeSinceAttack = now - lastAttackTime;
if (timeSinceAttack < 300) return false;
}
const ps = gs(self);
const threats = getThreats(self, ps);
if (threats.length === 0) return false;
let urgent = false;
let closestThreat = null;
for (const t of threats) {
if (t.isAttacking && t.dist < t.es.rng) urgent = true;
if (t.isBoosting && t.dist < t.es.rng * 1.2) urgent = true;
if (closestThreat === null || t.dist < closestThreat.dist) {
closestThreat = t;
}
}
if (urgent || (closestThreat && closestThreat.dist < ps.rng)) {
const escapeAngle = Math.atan2(-closestThreat.dy, -closestThreat.dx);
self.angle = escapeAngle;
const pushStrength = Math.min(12, 8 + (ps.rng - closestThreat.dist) / 20);
const pushX = -closestThreat.dx / closestThreat.dist * pushStrength;
const pushY = -closestThreat.dy / closestThreat.dist * pushStrength;
self.x += pushX;
self.y += pushY;
if (rt?.running_layout) {
rt.running_layout.scrollX += pushX;
rt.running_layout.scrollY += pushY;
}
if (boostTimeout) clearTimeout(boostTimeout);
const rect = gameCanvas.getBoundingClientRect();
const cx = rect.left + rect.width/2;
const cy = rect.top + rect.height/2;
simMouse('mousedown', cx, cy, 2, 2);
boostTimeout = setTimeout(() => {
simMouse('mouseup', cx, cy, 2, 0);
boostTimeout = null;
}, 150);
lastDodge = now;
return true;
}
return false;
}
function tryRespawn() {
const now = performance.now();
if (now - lastRespawnTry < 2500) return;
lastRespawnTry = now;
const rect = gameCanvas.getBoundingClientRect();
const cx = rect.left + rect.width/2;
const cy = rect.top + rect.height/2;
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', keyCode: 13, bubbles: true }));
document.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', keyCode: 13, bubbles: true }));
const offsets = [0, -30, 30, -60, 60];
offsets.forEach((offY, idx) => {
setTimeout(() => {
simMouse('mousedown', cx, cy + offY, 0, 1);
simMouse('mouseup', cx, cy + offY, 0, 0);
}, idx * 80);
});
}
function updateTimers() {
if (!pType || !gameStartTime) return;
const instances = pType.instances;
for (let i = 0; i < instances.length; i++) {
const p = instances[i]; if (!p || !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 && 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() {
if (!rt?.running_layout || !pType) return;
const now = performance.now();
if (now - lastDrawTime < drawThrottle) return;
lastDrawTime = now;
const instances = pType.instances;
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;
const vy = rect.top + rect.height / 2;
ctx.clearRect(0, 0, esp.width, esp.height);
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) {
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 (killaura && target) {
const angle = self.angle || 0;
const bl2 = (ps.sz * 0.9) * sc;
const dx = target.x - self.x;
const dy = target.y - self.y;
const da = Math.atan2(dy, dx);
ctx.beginPath();
ctx.moveTo(vx, vy);
ctx.lineTo(vx + Math.cos(da) * bl2, vy + Math.sin(da) * bl2);
ctx.strokeStyle = "rgba(255,255,255,0.4)";
ctx.lineWidth = 1.5;
ctx.setLineDash([2, 2]);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(vx, vy);
ctx.lineTo(vx + Math.cos(angle) * bl2, vy + Math.sin(angle) * bl2);
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) * bl2, vy + Math.sin(da + or2) * bl2);
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) continue;
if (p.width <= 0) continue;
const es = gs(p);
if (es.lv <= 0) continue;
const px = vx + (p.x - self.x) * sc;
const py = vy + (p.y - self.y) * sc;
const dist = Math.hypot(p.x - self.x, p.y - self.y);
const inRng = dist <= ps.rng;
const killable = es.lv <= ps.lv;
const danger = es.lv > ps.lv * 1.3;
if (showCooldown) {
const t = enemyTimers.get(p.uid);
if (t) {
const elapsed = (performance.now() - gameStartTime) % t.cd;
const remaining = t.cd - elapsed;
const 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 (killaura && 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);
}
}
}
function loop() {
try {
if (rt?.running_layout) {
if (!gameStartTime) gameStartTime = performance.now();
applyZoom();
updateTimers();
const now = performance.now();
if (now - lastStatsUpdate >= statsThrottle) {
lastStatsUpdate = now;
updateStats();
}
const needDraw = showTracers || showHitboxes || showKillable || showEnemyRange || showCooldown || killaura || dodgeAttacks;
if (needDraw) draw(); else ctx.clearRect(0, 0, esp.width, esp.height);
if (pType) {
const self = getPlayer();
if (self) {
if (killaura) killAll();
if (now - lastDodgeCheck >= dodgeCheckThrottle) {
lastDodgeCheck = now;
if (dodgeAttacks) {
tryDodge(self);
}
}
} else {
if (autoRespawn) tryRespawn();
}
}
}
} catch (e) {}
requestAnimationFrame(loop);
}
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 i = t.instances[0];
if (i.x !== undefined && i.y !== undefined && i.width !== undefined && i.angle !== undefined) {
pType = t; break;
}
}
}
}
loop();
}
}, 500);
window.addEventListener('message', function(e) {
if (!e.data || !e.data.evoware) return;
switch (e.data.type) {
case 'killaura': killaura = e.data.data; if (!killaura) { target = null; targetLevel = 0; } break;
case 'dodgeatk': dodgeAttacks = e.data.data; if (!dodgeAttacks && boostTimeout) clearTimeout(boostTimeout); break;
case 'dodgecd': dodgeOnCD = e.data.data; break;
case 'autorespawn': autoRespawn = e.data.data; break;
case 'lvlrange': lvlMin = e.data.data.min; lvlMax = e.data.data.max; break;
case 'enemyrange': showEnemyRange = e.data.data; break;
case 'cooldown': showCooldown = e.data.data; break;
case 'tracers': showTracers = e.data.data; break;
case 'hitboxes': showHitboxes = e.data.data; break;
case 'killable': showKillable = e.data.data; break;
case 'offset': offset = e.data.data; break;
case 'zoom': zoomLevel = e.data.data; break;
}
});
window.addEventListener('message', function(e) {
if (e.data && e.data.type === 'hotkeyChanged') {
toggleKey = e.data.key;
localStorage.setItem('evoware_toggle_key', toggleKey);
}
});
document.addEventListener('keydown', function(e) {
if (e.key === toggleKey) {
e.preventDefault();
e.stopPropagation();
menuVisible = !menuVisible;
iframe.style.opacity = menuVisible ? '1' : '0';
iframe.style.pointerEvents = menuVisible ? 'auto' : 'none';
}
}, true);
})();