Lordz.io

ESP, SPEEDHACK, AUTOARMY, AUTOUPGRADE, UI PANEL

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

})();