Lordz.io

ESP, SPEEDHACK, AUTOARMY, AUTOUPGRADE, UI PANEL

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

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

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

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

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==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();

})();