ESP, SPEEDHACK, AUTOARMY, AUTOUPGRADE, UI PANEL
// ==UserScript==
// @name Lordz.io
// @namespace
// @version 2026-03-13
// @description ESP, SPEEDHACK, AUTOARMY, AUTOUPGRADE, UI PANEL
// @author Blisma
// @match *://lordz.io/*
// @match *://www.lordz.io/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=lordz.io
// @grant none
// @namespace https://greasyfork.org/users/1418784
// ==/UserScript==
(function () {
const UNITS = [
{ key: 't', label: 'Soldier', cost: 15 },
{ key: 'y', label: 'Knight', cost: 75 },
{ key: 'u', label: 'Archer', cost: 125 },
{ key: 'i', label: 'Barbarian', cost: 350 },
{ key: 'm', label: 'Mage', cost: 450 },
{ key: 'o', label: 'Dragon', cost: 2500 },
{ key: 'p', label: 'Ballista', cost: 1000 },
{ key: 's', label: 'Sapper', cost: 150 },
{ key: 'k', label: 'Troll', cost: 3000 },
];
const PRESETS = {
pvp: [
{ key:'s', amount:10 }, { key:'m', amount:15 },
{ key:'u', amount:15 }, { key:'i', amount:10 },
],
raid: [
{ key:'k', amount:5 }, { key:'p', amount:20 },
{ key:'i', amount:10 },
],
win: [
{ key:'k', amount:5 }, { key:'p', amount:20 },
{ key:'o', amount:12 }, { key:'y', amount:20 },
{ key:'i', amount:12 },
],
};
const state = {
autoArmy: false,
espEnabled: false,
autoUpgrade: false,
gold: 0,
buyInterval: null,
espInterval: null,
upgradeInterval: null,
goldInterval: null,
buyDelay: 800,
spendThreshold: 15,
mode: 'free',
unitAmounts: Object.fromEntries(UNITS.map(u => [u.key, 5])),
enabledUnits: new Set(UNITS.map(u => u.key)),
queuePos: 0,
queueBought: 0,
};
function buildQueue() {
if (state.mode !== 'free') return PRESETS[state.mode] || [];
return [...state.enabledUnits].map(k => ({ key: k, amount: state.unitAmounts[k] || 5 }));
}
function pressKey(key) {
const kc = key.toUpperCase().charCodeAt(0);
const opts = { key, code: 'Key' + key.toUpperCase(), keyCode: kc, which: kc, bubbles: true, cancelable: true };
const canvas = document.querySelector('canvas:not(#lh-esp)');
canvas && canvas.focus && canvas.focus();
[canvas, document, window].forEach(t => {
if (!t) return;
t.dispatchEvent(new KeyboardEvent('keydown', opts));
t.dispatchEvent(new KeyboardEvent('keypress', { ...opts, charCode: kc }));
t.dispatchEvent(new KeyboardEvent('keyup', opts));
});
}
function getGold() {
const allEls = Array.from(document.querySelectorAll('*'));
for (const el of allEls) {
if (el.closest('#gs-overlay')) continue;
if (el.children.length > 2) continue;
const txt = (el.textContent || '').trim();
if (!/^\d[\d,]*$/.test(txt)) continue;
const n = parseInt(txt.replace(/,/g, ''));
if (n < 0 || n > 9999999) continue;
const rect = el.getBoundingClientRect();
if (rect.width < 5 || rect.height < 5) continue;
if (rect.bottom > window.innerHeight * 0.75 && rect.left > window.innerWidth * 0.55) {
return n;
}
}
return state.gold;
}
function startGoldPolling() {
if (state.goldInterval) return;
state.goldInterval = setInterval(() => {
const g = getGold();
state.gold = g;
const el = document.getElementById('gs-gold-val');
if (el) el.textContent = g > 0 ? g.toLocaleString() : '? (canvas only)';
}, 400);
}
function tryBuyUnit() {
const queue = buildQueue();
if (!queue.length) return;
if (state.queuePos >= queue.length) { state.queuePos = 0; state.queueBought = 0; }
const step = queue[state.queuePos];
const unit = UNITS.find(u => u.key === step.key);
if (!unit) { state.queuePos++; state.queueBought = 0; return; }
const gold = state.gold;
if (gold !== 0 && gold < unit.cost) return;
pressKey(unit.key);
state.queueBought++;
gsLog(`[${unit.key.toUpperCase()}] ${unit.label} ${state.queueBought}/${step.amount}`, 'buy');
if (state.queueBought >= step.amount) {
state.queuePos = (state.queuePos + 1) % queue.length;
state.queueBought = 0;
}
}
function startAutoArmy() {
if (state.buyInterval) return;
state.buyInterval = setInterval(tryBuyUnit, state.buyDelay);
gsLog('Auto-Army started', 'sys');
}
function stopAutoArmy() {
clearInterval(state.buyInterval);
state.buyInterval = null;
gsLog('Auto-Army stopped', 'sys');
}
function tryUpgrade() {
const upgradeBtns = Array.from(document.querySelectorAll('*')).filter(el => {
if (el.closest('#gs-overlay')) return false;
const txt = (el.textContent || '').toLowerCase();
return txt.includes('upgrade') || txt.includes('lvl') || txt.includes('level up');
});
if (upgradeBtns.length > 0) {
const el = upgradeBtns[0];
el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
el.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
el.dispatchEvent(new MouseEvent('click', { bubbles: true }));
gsLog('Clicked upgrade button', 'upg');
}
}
function startAutoUpgrade() {
if (state.upgradeInterval) return;
state.upgradeInterval = setInterval(tryUpgrade, 1500);
gsLog('Auto-Upgrade started', 'upg');
}
function stopAutoUpgrade() {
clearInterval(state.upgradeInterval);
state.upgradeInterval = null;
gsLog('Auto-Upgrade stopped', 'sys');
}
function buildESPCanvas() {
let c = document.getElementById('lh-esp');
if (!c) {
c = document.createElement('canvas');
c.id = 'lh-esp';
c.style.cssText = 'position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:9998;';
c.width = window.innerWidth;
c.height = window.innerHeight;
document.body.appendChild(c);
}
return c;
}
function drawESP() {
const c = buildESPCanvas();
const ctx = c.getContext('2d');
ctx.clearRect(0, 0, c.width, c.height);
if (!document.querySelector('canvas:not(#lh-esp)')) return;
const cx = c.width / 2, cy = c.height / 2;
ctx.save();
ctx.beginPath();
ctx.arc(cx, cy, 9, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(57,255,106,0.85)';
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 1.5;
ctx.stroke();
ctx.font = 'bold 11px monospace';
ctx.strokeStyle = 'rgba(0,0,0,0.85)';
ctx.lineWidth = 3;
ctx.fillStyle = 'rgba(57,255,106,0.95)';
ctx.strokeText('YOU', cx + 14, cy + 4);
ctx.fillText('YOU', cx + 14, cy + 4);
ctx.font = '10px monospace';
ctx.fillStyle = 'rgba(255,255,80,0.45)';
ctx.fillText('ESP ACTIVE — enemy positions require Unity WASM hook', 12, c.height - 32);
ctx.restore();
}
function startESP() {
buildESPCanvas();
state.espInterval = setInterval(drawESP, 100);
gsLog('ESP enabled', 'sys');
}
function stopESP() {
clearInterval(state.espInterval);
state.espInterval = null;
const c = document.getElementById('lh-esp');
if (c) c.getContext('2d').clearRect(0, 0, c.width, c.height);
gsLog('ESP disabled', 'sys');
}
window.addEventListener('resize', () => {
const c = document.getElementById('lh-esp');
if (c) { c.width = window.innerWidth; c.height = window.innerHeight; }
});
const pn = performance.now.bind(performance);
let lastReal = pn(), lastScaled = pn(), curSpeed = 1;
document.speedMltp = () => document.getElementById('speedHack')?.checked ? 500 : 1;
performance.now = function () {
const real = pn();
lastScaled += (real - lastReal) * curSpeed;
lastReal = real;
curSpeed = document.speedMltp();
return lastScaled;
};
function gsLog(msg, type = 'sys') {
const el = document.getElementById('gs-log');
if (!el) return;
const line = document.createElement('div');
line.className = 'gs-log-line ' + type;
line.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
el.prepend(line);
while (el.children.length > 40) el.removeChild(el.lastChild);
}
const CSS = `
@import url('https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Bebas+Neue&family=DM+Sans:wght@300;400;500&display=swap');
:root {
--gs-accent:#39FF6A; --gs-accent-dim:rgba(57,255,106,0.12); --gs-accent-glow:rgba(57,255,106,0.35);
--gs-surface:#0d0d0f; --gs-surface2:#161618; --gs-surface3:#1e1e21;
--gs-border:rgba(255,255,255,0.07); --gs-border-accent:rgba(57,255,106,0.3);
--gs-text:#f0f0f0; --gs-text-dim:rgba(240,240,240,0.4); --gs-text-mid:rgba(240,240,240,0.65);
--gs-danger:#FF4757; --gs-speed:#FFD93D;
}
@keyframes gs-fadeIn{from{opacity:0;transform:translateY(-8px) scale(.98)}to{opacity:1;transform:none}}
@keyframes gs-pulse{0%,100%{box-shadow:0 0 0 0 var(--gs-accent-glow)}50%{box-shadow:0 0 0 6px transparent}}
@keyframes gs-scan{0%{transform:translateY(-100%)}100%{transform:translateY(900px)}}
@keyframes gs-blink{0%,100%,49%{opacity:1}50%{opacity:0}}
@keyframes gs-ticker{from{transform:translateX(0)}to{transform:translateX(-50%)}}
#gs-overlay{
display:none;position:fixed;inset:0;z-index:99999;
background:rgba(0,0,0,0.78);backdrop-filter:blur(6px);
align-items:center;justify-content:center;font-family:'DM Sans',sans-serif;
}
#gs-overlay.open{display:flex}
#gs-panel{
width:min(520px,96vw);background:var(--gs-surface);
border:1px solid var(--gs-border);border-radius:16px;overflow:hidden;
box-shadow:0 40px 80px rgba(0,0,0,.7),0 0 0 1px rgba(255,255,255,.04);
animation:gs-fadeIn .22s cubic-bezier(.25,.46,.45,.94);
max-height:92vh;overflow-y:auto;position:relative;
}
#gs-panel::-webkit-scrollbar{width:4px}
#gs-panel::-webkit-scrollbar-thumb{background:var(--gs-border);border-radius:2px}
#gs-scanline{position:absolute;inset:0;pointer-events:none;z-index:10;overflow:hidden;border-radius:16px}
#gs-scanline::after{
content:'';position:absolute;left:0;right:0;height:80px;
background:linear-gradient(to bottom,transparent,rgba(57,255,106,.025),transparent);
animation:gs-scan 4s linear infinite;
}
#gs-header{
background:var(--gs-surface2);border-bottom:1px solid var(--gs-border);
padding:18px 22px 16px;display:flex;align-items:center;justify-content:space-between;
position:sticky;top:0;z-index:20;
}
#gs-header::before{
content:'';position:absolute;inset:0;pointer-events:none;
background:radial-gradient(ellipse at 80% 0%,rgba(57,255,106,.07) 0%,transparent 70%);
}
#gs-title-group{display:flex;align-items:center;gap:12px}
#gs-icon{
width:34px;height:34px;background:var(--gs-accent-dim);border:1px solid var(--gs-border-accent);
border-radius:8px;display:flex;align-items:center;justify-content:center;
color:var(--gs-accent);font-size:15px;
}
#gs-title{font-family:'Bebas Neue',sans-serif;font-size:22px;letter-spacing:2px;color:var(--gs-text);line-height:1}
#gs-subtitle{font-family:'DM Mono',monospace;font-size:11px;color:var(--gs-text-dim);letter-spacing:1px;margin-top:2px}
#gs-close{
width:30px;height:30px;background:transparent;border:1px solid var(--gs-border);
border-radius:8px;color:var(--gs-text-dim);cursor:pointer;
display:flex;align-items:center;justify-content:center;font-size:14px;transition:all .15s;
}
#gs-close:hover{border-color:var(--gs-danger);color:var(--gs-danger);background:rgba(255,71,87,.08)}
#gs-ticker-wrap{
background:var(--gs-surface2);border-bottom:1px solid var(--gs-border);
overflow:hidden;height:28px;display:flex;align-items:center;
}
#gs-ticker-inner{
display:flex;white-space:nowrap;animation:gs-ticker 22s linear infinite;
font-family:'DM Mono',monospace;font-size:10px;letter-spacing:1.5px;
color:var(--gs-text-dim);text-transform:uppercase;
}
.gs-tick-item{padding:0 24px}
.gs-tick-dot{color:var(--gs-accent)}
#gs-body{padding:16px 20px;display:flex;flex-direction:column;gap:8px}
.gs-section-label{
font-family:'DM Mono',monospace;font-size:10px;letter-spacing:1.5px;
color:var(--gs-text-dim);text-transform:uppercase;padding:4px 0 2px;
}
.gs-row{
background:var(--gs-surface2);border:1px solid var(--gs-border);
border-radius:12px;padding:13px 15px;
display:flex;align-items:center;justify-content:space-between;
transition:border-color .2s,background .2s;cursor:default;
}
.gs-row:hover{border-color:rgba(255,255,255,.12);background:var(--gs-surface3)}
.gs-row.active-row{border-color:var(--gs-border-accent)}
.gs-row.active-esp{border-color:rgba(56,189,248,0.35)}
.gs-row.active-upg{border-color:rgba(167,139,250,0.35)}
.gs-row-label{display:flex;align-items:center;gap:10px}
.gs-row-icon{
width:30px;height:30px;border-radius:7px;background:var(--gs-surface3);
display:flex;align-items:center;justify-content:center;
font-size:13px;border:1px solid var(--gs-border);flex-shrink:0;transition:all .2s;
}
.active-row .gs-row-icon{background:var(--gs-accent-dim);border-color:var(--gs-border-accent)}
.active-esp .gs-row-icon{background:rgba(56,189,248,0.1);border-color:rgba(56,189,248,0.3)}
.active-upg .gs-row-icon{background:rgba(167,139,250,0.1);border-color:rgba(167,139,250,0.3)}
.gs-row-name{font-size:13.5px;font-weight:500;color:var(--gs-text);letter-spacing:.1px}
.gs-row-desc{font-size:11px;color:var(--gs-text-dim);margin-top:2px;font-family:'DM Mono',monospace;letter-spacing:.3px}
.gs-toggle{position:relative;width:44px;height:24px;flex-shrink:0}
.gs-toggle input{position:absolute;opacity:0;width:0;height:0}
.gs-toggle-track{
position:absolute;inset:0;background:var(--gs-surface3);
border:1px solid var(--gs-border);border-radius:12px;cursor:pointer;transition:all .2s;
}
.gs-toggle-track::after{
content:'';position:absolute;top:3px;left:3px;width:16px;height:16px;
border-radius:50%;background:rgba(255,255,255,.25);transition:all .2s;
}
.gs-toggle input:checked+.gs-toggle-track{background:var(--gs-accent);border-color:var(--gs-accent)}
.gs-toggle input:checked+.gs-toggle-track::after{transform:translateX(20px);background:#000}
.gs-toggle-esp input:checked+.gs-toggle-track{background:#38bdf8;border-color:#38bdf8}
.gs-toggle-upg input:checked+.gs-toggle-track{background:#a78bfa;border-color:#a78bfa}
.gs-toggle-speed input:checked+.gs-toggle-track{background:var(--gs-speed);border-color:var(--gs-speed)}
#gs-speed-status{
border:1px solid var(--gs-border);border-radius:12px;background:var(--gs-surface2);
padding:12px 16px;display:flex;align-items:center;justify-content:space-between;
font-family:'DM Mono',monospace;
}
#gs-speed-label{font-size:11px;color:var(--gs-text-dim);letter-spacing:1px;text-transform:uppercase}
#gs-speed-val{font-size:20px;font-family:'Bebas Neue',sans-serif;color:var(--gs-text-dim);letter-spacing:2px;transition:color .3s}
#gs-speed-val.boosted{color:var(--gs-speed);animation:gs-pulse 1.2s ease-in-out infinite;text-shadow:0 0 12px var(--gs-speed)}
#gs-speed-bars{display:flex;gap:3px;align-items:flex-end}
.gs-bar{width:4px;border-radius:2px;background:var(--gs-border);transition:background .3s}
.gs-bar.lit{background:var(--gs-speed)}
.gs-gold-display{
border:1px solid var(--gs-border);border-radius:12px;background:var(--gs-surface2);
padding:10px 16px;display:flex;align-items:center;justify-content:space-between;
font-family:'DM Mono',monospace;
}
.gs-gold-label{font-size:11px;color:var(--gs-text-dim);letter-spacing:1px;text-transform:uppercase}
#gs-gold-val{font-size:20px;font-family:'Bebas Neue',sans-serif;color:var(--gs-speed);letter-spacing:2px}
.gs-unit-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:5px}
.gs-unit-chip{
background:var(--gs-surface3);border:1px solid var(--gs-border);
border-radius:8px;padding:6px 8px;cursor:pointer;
display:flex;flex-direction:column;align-items:center;gap:2px;
transition:all .15s;user-select:none;
}
.gs-unit-chip:hover{border-color:rgba(255,255,255,.15)}
.gs-unit-chip.selected{border-color:var(--gs-border-accent);background:var(--gs-accent-dim)}
.gs-unit-chip-key{font-family:'DM Mono',monospace;font-size:10px;color:var(--gs-text-dim);background:var(--gs-surface);border-radius:3px;padding:1px 5px;border:1px solid var(--gs-border)}
.gs-unit-chip.selected .gs-unit-chip-key{color:var(--gs-accent);border-color:var(--gs-border-accent)}
.gs-unit-chip-label{font-size:9px;color:var(--gs-text-dim);font-family:'DM Mono',monospace;text-align:center}
.gs-unit-chip.selected .gs-unit-chip-label{color:var(--gs-accent)}
.gs-unit-chip-cost{font-size:9px;color:var(--gs-speed);font-family:'DM Mono',monospace}
.gs-priority-list{display:flex;flex-direction:column;gap:3px}
.gs-priority-item{
display:flex;align-items:center;gap:8px;background:var(--gs-surface3);
border:1px solid var(--gs-border);border-radius:7px;padding:5px 8px;
cursor:grab;font-size:11px;user-select:none;
font-family:'DM Mono',monospace;color:var(--gs-text-mid);transition:opacity .15s;
}
.gs-priority-item:hover{border-color:rgba(255,255,255,.12)}
.gs-priority-item.dragging{opacity:.35}
.gs-priority-num{color:var(--gs-text-dim);min-width:14px;text-align:center}
.gs-priority-name{flex:1;color:var(--gs-text)}
.gs-priority-cost{color:var(--gs-speed)}
.gs-priority-key{
font-family:'DM Mono',monospace;font-size:9px;color:var(--gs-text-dim);
background:var(--gs-surface);border-radius:3px;padding:1px 5px;border:1px solid var(--gs-border);
}
.gs-slider-row{display:flex;flex-direction:column;gap:4px}
.gs-slider-header{display:flex;justify-content:space-between;align-items:center}
.gs-slider-label{font-size:11px;color:var(--gs-text-dim);font-family:'DM Mono',monospace;letter-spacing:.5px}
.gs-slider-val{font-size:11px;color:var(--gs-accent);font-family:'DM Mono',monospace}
input[type=range].gs-range{
-webkit-appearance:none;width:100%;height:4px;
background:var(--gs-surface3);border-radius:2px;outline:none;border:1px solid var(--gs-border);
}
input[type=range].gs-range::-webkit-slider-thumb{
-webkit-appearance:none;width:14px;height:14px;border-radius:50%;
background:var(--gs-accent);cursor:pointer;border:2px solid var(--gs-surface);
box-shadow:0 0 6px var(--gs-accent-glow);
}
.gs-quickbuy-grid{display:grid;grid-template-columns:1fr 1fr;gap:4px}
.gs-qbtn{
background:var(--gs-surface3);border:1px solid var(--gs-border);
border-radius:7px;padding:5px 6px;cursor:pointer;color:var(--gs-text-mid);
font-family:'DM Mono',monospace;font-size:10px;letter-spacing:.3px;
transition:all .15s;text-align:center;
}
.gs-qbtn:hover{border-color:var(--gs-border-accent);color:var(--gs-accent);background:var(--gs-accent-dim)}
.gs-qbtn-building{border-color:rgba(167,139,250,0.15);color:rgba(167,139,250,0.7)}
.gs-qbtn-building:hover{border-color:rgba(167,139,250,0.4);color:#a78bfa;background:rgba(167,139,250,0.08)}
.gs-log{
background:var(--gs-surface2);border:1px solid var(--gs-border);border-radius:8px;
padding:8px 10px;max-height:90px;overflow-y:auto;
font-family:'DM Mono',monospace;font-size:10px;color:var(--gs-text-dim);
display:flex;flex-direction:column;gap:2px;
}
.gs-log::-webkit-scrollbar{width:3px}
.gs-log::-webkit-scrollbar-thumb{background:var(--gs-border)}
.gs-log-line.buy{color:var(--gs-accent)}
.gs-log-line.upg{color:#a78bfa}
.gs-log-line.sys{color:var(--gs-text-dim)}
.gs-log-line.warn{color:#FFD93D}
.gs-probe-btn{
width:100%;background:var(--gs-surface3);border:1px dashed rgba(255,211,61,0.35);
border-radius:8px;padding:8px;cursor:pointer;color:#FFD93D;
font-family:'DM Mono',monospace;font-size:11px;letter-spacing:.5px;
transition:all .15s;text-align:center;
}
.gs-probe-btn:hover{background:rgba(255,211,61,0.08);border-color:rgba(255,211,61,0.6)}
#gs-footer{
padding:14px 22px;border-top:1px solid var(--gs-border);
display:flex;align-items:center;justify-content:space-between;
position:sticky;bottom:0;background:var(--gs-surface);z-index:20;
}
#gs-keyhints{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.gs-key{
font-family:'DM Mono',monospace;font-size:10px;color:var(--gs-text-dim);
background:var(--gs-surface3);border:1px solid var(--gs-border);
border-radius:5px;padding:2px 7px;letter-spacing:.5px;
}
.gs-cursor{animation:gs-blink 1.2s step-end infinite}
#gs-version{font-family:'DM Mono',monospace;font-size:10px;color:var(--gs-text-dim);letter-spacing:1px}
.gs-mode-btn{
background:var(--gs-surface3);border:1px solid var(--gs-border);border-radius:7px;
padding:6px 0;cursor:pointer;color:var(--gs-text-mid);
font-family:'DM Mono',monospace;font-size:11px;letter-spacing:.5px;transition:all .15s;
}
.gs-mode-btn:hover{border-color:rgba(255,255,255,.15);color:var(--gs-text)}
.gs-mode-btn.active{background:var(--gs-accent-dim);border-color:var(--gs-border-accent);color:var(--gs-accent)}
.gs-unit-row{display:flex;align-items:center;gap:8px;}
.gs-unit-toggle{
font-family:'DM Mono',monospace;font-size:11px;font-weight:500;
background:var(--gs-surface3);border:1px solid var(--gs-border);border-radius:5px;
padding:3px 8px;cursor:pointer;color:var(--gs-text-dim);transition:all .15s;flex-shrink:0;min-width:28px;text-align:center;
}
.gs-unit-toggle.on{background:var(--gs-accent-dim);border-color:var(--gs-border-accent);color:var(--gs-accent)}
.gs-unit-name{font-family:'DM Mono',monospace;font-size:10px;color:var(--gs-text-mid);flex:1;}
.gs-unit-cost{font-family:'DM Mono',monospace;font-size:10px;color:var(--gs-speed);min-width:40px;text-align:right;}
.gs-unit-amount{
width:44px;background:var(--gs-surface3);border:1px solid var(--gs-border);
border-radius:5px;padding:3px 5px;color:var(--gs-text);font-family:'DM Mono',monospace;
font-size:11px;text-align:center;outline:none;
}
.gs-unit-amount:focus{border-color:var(--gs-border-accent);}
`;
const TICKERS = ['SYSTEM ACTIVE','DOM BUTTON CLICK ENABLED','AUTO-ARMY READY','ESP OVERLAY READY','SPEED OVERRIDE READY','ENGINE HOOK ACTIVE','UNIT DATA VERIFIED'];
const tickerHTML = [...TICKERS,...TICKERS].map((t,i) =>
i%2===1 ? `<span class="gs-tick-item gs-tick-dot">◆</span>` : `<span class="gs-tick-item">${t}</span>`
).join('');
const quickUnitsHTML = UNITS.map(u =>
`<button class="gs-qbtn" onclick="window.lhBuy('${u.key}')">[${u.key.toUpperCase()}] ${u.label} <span style="color:var(--gs-speed)">${u.cost}g</span></button>`
).join('');
const HTML = `<div id="gs-overlay">
<div id="gs-panel">
<div id="gs-scanline"></div>
<div id="gs-header">
<div id="gs-title-group">
<div id="gs-icon">⚙</div>
<div>
<div id="gs-title">Lordz Mod</div>
<div id="gs-subtitle">GAME CONFIG <span class="gs-cursor">▮</span></div>
</div>
</div>
<button id="gs-close">✕</button>
</div>
<div id="gs-ticker-wrap"><div id="gs-ticker-inner">${tickerHTML}</div></div>
<div id="gs-body">
<div class="gs-gold-display">
<div><div class="gs-gold-label">Gold</div><div id="gs-gold-val">—</div></div>
<span style="font-size:22px">💰</span>
</div>
<div class="gs-section-label">Automation</div>
<div class="gs-row" id="gs-army-row">
<div class="gs-row-label">
<div class="gs-row-icon" id="gs-army-icon">⚔</div>
<div>
<div class="gs-row-name">Auto-Army</div>
<div class="gs-row-desc">clicks hotbar buttons directly — no fake key events</div>
</div>
</div>
<label class="gs-toggle"><input type="checkbox" id="autoArmy"><div class="gs-toggle-track"></div></label>
</div>
<div class="gs-row" id="gs-upg-row">
<div class="gs-row-label">
<div class="gs-row-icon">🏗</div>
<div>
<div class="gs-row-name">Auto-Upgrade</div>
<div class="gs-row-desc">scans DOM for upgrade buttons near buildings</div>
</div>
</div>
<label class="gs-toggle gs-toggle-upg"><input type="checkbox" id="autoUpgrade"><div class="gs-toggle-track"></div></label>
</div>
<div class="gs-row" id="gs-esp-row">
<div class="gs-row-label">
<div class="gs-row-icon" id="gs-esp-icon">👁</div>
<div>
<div class="gs-row-name">ESP Overlay</div>
<div class="gs-row-desc">canvas overlay — enemy data needs Unity WASM hook</div>
</div>
</div>
<label class="gs-toggle gs-toggle-esp"><input type="checkbox" id="espToggle"><div class="gs-toggle-track"></div></label>
</div>
<div class="gs-section-label">Speed Hack</div>
<div class="gs-row" id="gs-speed-row">
<div class="gs-row-label">
<div class="gs-row-icon" id="gs-speed-icon">⚡</div>
<div>
<div class="gs-row-name">Speed Hack</div>
<div class="gs-row-desc">performance.now() × 500x multiplier</div>
</div>
</div>
<label class="gs-toggle gs-toggle-speed"><input type="checkbox" id="speedHack"><div class="gs-toggle-track"></div></label>
</div>
<div id="gs-speed-status">
<div><div id="gs-speed-label">Current Multiplier</div><div id="gs-speed-val">1×</div></div>
<div id="gs-speed-bars">
${[6,9,12,16,20,24,28].map((h,i)=>`<div class="gs-bar${i===0?' lit':''}" style="height:${h}px" id="gs-b${i+1}"></div>`).join('')}
</div>
</div>
<div class="gs-section-label">Army Mode</div>
<div style="background:var(--gs-surface2);border:1px solid var(--gs-border);border-radius:12px;padding:13px 15px;">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:4px;margin-bottom:10px;">
<button class="gs-mode-btn active" id="mode-free" onclick="window.gsSetMode('free')">Free</button>
<button class="gs-mode-btn" id="mode-pvp" onclick="window.gsSetMode('pvp')">PvP</button>
<button class="gs-mode-btn" id="mode-raid" onclick="window.gsSetMode('raid')">Base Raid</button>
<button class="gs-mode-btn" id="mode-win" onclick="window.gsSetMode('win')">Game Win</button>
</div>
<div id="gs-mode-desc" style="font-size:10px;color:var(--gs-text-dim);font-family:'DM Mono',monospace;letter-spacing:.3px;line-height:1.6;"></div>
</div>
<div id="gs-free-config">
<div class="gs-section-label">Unit Amounts</div>
<div style="background:var(--gs-surface2);border:1px solid var(--gs-border);border-radius:12px;padding:13px 15px;">
<div style="font-size:10px;color:var(--gs-text-dim);font-family:'DM Mono',monospace;margin-bottom:10px;letter-spacing:.3px">click key to toggle on/off — set amount per cycle</div>
<div id="gs-unit-amount-grid" style="display:flex;flex-direction:column;gap:5px;"></div>
</div>
</div>
<div class="gs-slider-row">
<div class="gs-slider-header">
<span class="gs-slider-label">Buy Delay</span>
<span class="gs-slider-val" id="gs-delay-val">800ms</span>
</div>
<input type="range" class="gs-range" id="gs-delay" min="0" max="2000" value="800">
</div>
<div class="gs-section-label">Quick Buy</div>
<div style="background:var(--gs-surface2);border:1px solid var(--gs-border);border-radius:12px;padding:12px 14px;">
<div class="gs-quickbuy-grid">${quickUnitsHTML}</div>
</div>
<div class="gs-section-label">Activity Log</div>
<div style="background:var(--gs-surface2);border:1px solid rgba(255,211,61,0.2);border-radius:12px;padding:12px 14px;">
<div style="font-size:11px;font-weight:500;color:#FFD93D;margin-bottom:8px;">🎯 Calibration</div>
<div style="font-size:10px;color:var(--gs-text-dim);font-family:'DM Mono',monospace;margin-bottom:10px;letter-spacing:.3px">T button calibrated at x=528 y=898. Adjust spacing if clicks miss.</div>
<div class="gs-slider-row" style="margin-bottom:8px;">
<div class="gs-slider-header">
<span class="gs-slider-label">Button Spacing (px)</span>
<span class="gs-slider-val" id="gs-spacing-val">72px</span>
</div>
<input type="range" class="gs-range" id="gs-spacing" min="50" max="100" value="72">
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:4px;">
<button class="gs-probe-btn" onclick="window.gsTestClick('t')" style="font-size:10px;padding:6px;">🖱 Test T button</button>
<button class="gs-probe-btn" onclick="window.gsTestClick('c')" style="font-size:10px;padding:6px;">🖱 Test C button</button>
</div>
</div>
<div class="gs-log" id="gs-log" style="max-height:140px;"></div>
</div>
<div id="gs-footer">
<div id="gs-keyhints">
<span class="gs-key">F2</span>
<span style="font-size:11px;color:var(--gs-text-dim)">/</span>
<span class="gs-key">ESC</span>
<span style="font-size:10px;color:var(--gs-text-dim);margin-left:2px">— toggle panel</span>
</div>
<div id="gs-version">v4.1.0 <span class="gs-cursor">▮</span></div>
</div>
</div>
</div>`;
const styleEl = document.createElement('style');
styleEl.textContent = CSS;
document.head.appendChild(styleEl);
const host = document.createElement('div');
host.innerHTML = HTML;
document.body.appendChild(host);
const overlay = document.getElementById('gs-overlay');
const closeBtn = document.getElementById('gs-close');
const speedHackCb = document.getElementById('speedHack');
const autoArmyCb = document.getElementById('autoArmy');
const autoUpgCb = document.getElementById('autoUpgrade');
const espCb = document.getElementById('espToggle');
const speedRow = document.getElementById('gs-speed-row');
const armyRow = document.getElementById('gs-army-row');
const upgRow = document.getElementById('gs-upg-row');
const espRow = document.getElementById('gs-esp-row');
const speedValEl = document.getElementById('gs-speed-val');
const bars = [1,2,3,4,5,6,7].map(i => document.getElementById('gs-b' + i));
const delaySlider = document.getElementById('gs-delay');
closeBtn.addEventListener('click', () => overlay.classList.remove('open'));
overlay.addEventListener('click', e => { if (e.target === overlay) overlay.classList.remove('open'); });
document.addEventListener('keydown', e => {
if (e.key === 'F2' || e.keyCode === 113 || e.keyCode === 27)
overlay.classList.contains('open') ? overlay.classList.remove('open') : overlay.classList.add('open');
});
speedHackCb.addEventListener('change', () => {
const on = speedHackCb.checked;
speedValEl.textContent = on ? '500×' : '1×';
speedValEl.className = on ? 'boosted' : '';
speedRow.className = 'gs-row' + (on ? ' active-row' : '');
document.getElementById('gs-speed-icon').textContent = on ? '🚀' : '⚡';
bars.forEach((b,i) => b.className = 'gs-bar' + ((on ? i<7 : i<1) ? ' lit' : ''));
});
speedRow.addEventListener('click', e => {
if (e.target.closest('.gs-toggle')) return;
speedHackCb.checked = !speedHackCb.checked;
speedHackCb.dispatchEvent(new Event('change'));
});
autoArmyCb.addEventListener('change', () => {
state.autoArmy = autoArmyCb.checked;
autoArmyCb.checked ? startAutoArmy() : stopAutoArmy();
armyRow.className = 'gs-row' + (autoArmyCb.checked ? ' active-row' : '');
});
armyRow.addEventListener('click', e => {
if (e.target.closest('.gs-toggle')) return;
autoArmyCb.checked = !autoArmyCb.checked;
autoArmyCb.dispatchEvent(new Event('change'));
});
espCb.addEventListener('change', () => {
espCb.checked ? startESP() : stopESP();
espRow.className = 'gs-row' + (espCb.checked ? ' active-esp' : '');
document.getElementById('gs-esp-icon').textContent = espCb.checked ? '🔍' : '👁';
});
espRow.addEventListener('click', e => {
if (e.target.closest('.gs-toggle')) return;
espCb.checked = !espCb.checked;
espCb.dispatchEvent(new Event('change'));
});
autoUpgCb.addEventListener('change', () => {
autoUpgCb.checked ? startAutoUpgrade() : stopAutoUpgrade();
upgRow.className = 'gs-row' + (autoUpgCb.checked ? ' active-upg' : '');
});
upgRow.addEventListener('click', e => {
if (e.target.closest('.gs-toggle')) return;
autoUpgCb.checked = !autoUpgCb.checked;
autoUpgCb.dispatchEvent(new Event('change'));
});
delaySlider.oninput = () => {
state.buyDelay = parseInt(delaySlider.value);
document.getElementById('gs-delay-val').textContent = state.buyDelay + 'ms';
if (state.autoArmy) { stopAutoArmy(); startAutoArmy(); }
};
const PRESET_DESC = {
free: 'Buys each enabled unit the set number of times per cycle, then loops.',
pvp: '10× Archer → 15× Cannon → 15× Tower → 10× Ballista → loop',
raid: '5× King → 20× Knight → 10× Ballista → loop',
win: '5× King → 20× Knight → 12× Giant → 20× Catapult → 12× Ballista → loop',
};
window.gsSetMode = function(mode) {
state.mode = mode;
state.queuePos = 0;
state.queueBought = 0;
document.querySelectorAll('.gs-mode-btn').forEach(b => b.classList.remove('active'));
const btn = document.getElementById('mode-' + mode);
if (btn) btn.classList.add('active');
const desc = document.getElementById('gs-mode-desc');
if (desc) desc.textContent = PRESET_DESC[mode] || '';
const cfg = document.getElementById('gs-free-config');
if (cfg) cfg.style.display = mode === 'free' ? '' : 'none';
gsLog('Mode: ' + mode, 'sys');
};
window.lhBuy = function(key) {
pressKey(key);
const unit = UNITS.find(u => u.key === key);
if (unit) gsLog(`Manual: [${key.toUpperCase()}] ${unit.label}`, 'buy');
};
function buildUnitAmountGrid() {
const grid = document.getElementById('gs-unit-amount-grid');
if (!grid) return;
grid.innerHTML = '';
UNITS.forEach(unit => {
const row = document.createElement('div');
row.className = 'gs-unit-row';
const on = state.enabledUnits.has(unit.key);
row.innerHTML = `
<button class="gs-unit-toggle ${on ? 'on' : ''}" id="utog-${unit.key}" onclick="window.gsToggleUnit('${unit.key}')">${unit.key.toUpperCase()}</button>
<span class="gs-unit-name">${unit.label}</span>
<span class="gs-unit-cost">${unit.cost}g</span>
<input class="gs-unit-amount" id="uamt-${unit.key}" type="number" min="1" max="20" value="${state.unitAmounts[unit.key] || 5}"
onchange="window.gsSetAmount('${unit.key}', this.value)"
oninput="window.gsSetAmount('${unit.key}', this.value)">
`;
grid.appendChild(row);
});
}
window.gsToggleUnit = function(key) {
if (state.enabledUnits.has(key)) state.enabledUnits.delete(key);
else state.enabledUnits.add(key);
const btn = document.getElementById('utog-' + key);
if (btn) btn.className = 'gs-unit-toggle ' + (state.enabledUnits.has(key) ? 'on' : '');
state.queuePos = 0; state.queueBought = 0;
};
window.gsSetAmount = function(key, val) {
const n = Math.max(1, Math.min(20, parseInt(val) || 1));
state.unitAmounts[key] = n;
state.queuePos = 0; state.queueBought = 0;
};
startGoldPolling();
function waitForGame() {
if (document.querySelector('canvas')) {
buildUnitAmountGrid();
window.gsSetMode('free');
gsLog('v5.0.0 loaded — F2 to open panel', 'sys');
} else {
setTimeout(waitForGame, 500);
}
}
waitForGame();
})();