SkidWare ModMenu - diep.io

Spinner, Aimbot, AutoFarm

// ==UserScript==
// @license MIT
// @name         SkidWare ModMenu - diep.io
// @namespace    bo$$
// @version      v1.1.0
// @description  Spinner, Aimbot, AutoFarm
// @author       Dreamy @C:Mi300(Aimbot+Fov)
// @match        https://diep.io/*
// @match        https://staging.diep.io/*
// @match        https://diep-io.rivet.game/*
// @icon         https://gamesense.pub/favicon.ico
// @grant        none
// @run-at       document-start
// ==/UserScript==

// mi300's discord - https://discord.gg/S4CA5w9p8p
// my discord - https://discord.gg/NBN3jgQDGe
const FOV_UPDATE_INTERVAL = 16.6;
const FOV_LERP = 0.1;
let setFov = 0.5;
let foxv = 0.5;
let keyStates = new Map();

const onWheelEvent = event => {setFov += -Math.sign(event.deltaY) * 0.02 * Math.log10(setFov / 0.55 + 1)}
const onKeyDown = event => {keyStates.set(event.keyCode, 1)}
const onKeyUp = event => {keyStates.set(event.keyCode, 0)}

function updateFov(){
  if(typeof window.extern === 'undefined')return;
  if(!window.extern.doesHaveTank())return;
  if(keyStates.get(187)) setFov += 0.01 * Math.log10(setFov / 0.55 + 1);
  if(keyStates.get(189)) setFov -= 0.01 * Math.log10(setFov / 0.55 + 1);

  foxv += (setFov - foxv) * FOV_LERP;
  window.extern.setScreensizeZoom(1, foxv);
}
function init(){
  document.addEventListener("wheel", onWheelEvent);
  document.addEventListener("keydown", onKeyDown);
  document.addEventListener("keyup", onKeyUp);
  setInterval(updateFov, FOV_UPDATE_INTERVAL);
}
init();

let a;
class _a {
  constructor() {
    this.p = {};
    this.v = false;
    document.addEventListener("DOMContentLoaded", this.tu.bind(this));
  }

  tu() {
    if (this.v) return;
    this.v = true;
    const originalGetElementById = HTMLDocument.prototype.getElementById;
    HTMLDocument.prototype.getElementById = function (id) {
      const elem = originalGetElementById.call(document, id);
      if (id === "canvas") return wrapCanvas(elem);
      return elem;
    };

    const originalCreateElement = HTMLDocument.prototype.createElement;
    HTMLDocument.prototype.createElement = function (tag) {
      const elem = originalCreateElement.call(document, tag);
      if (tag === "canvas") return wrapCanvas(elem);
      return elem;
    };

    function wrapCanvas(origCanvas) {
      class HTMLCanvasElementProxy {}
      let proxyCanvas = new HTMLCanvasElementProxy();
      proxyCanvas.width = origCanvas.width;
      proxyCanvas.height = origCanvas.height;
      proxyCanvas.transferControlToOffscreen = origCanvas.transferControlToOffscreen.bind(origCanvas);
      proxyCanvas.toDataURL = origCanvas.toDataURL.bind(origCanvas);
      proxyCanvas.toBlob = origCanvas.toBlob.bind(origCanvas);
      proxyCanvas.captureStream = origCanvas.captureStream.bind(origCanvas);

      proxyCanvas.getContext = function (...args) {
        let ctx = origCanvas.getContext(...args);
        if (args[0] !== "2d") return ctx;
        return new Proxy(ctx, {
          get: function (target, prop) {
            const original = target[prop];
            if (typeof original !== "function") return original;
            if (Object.keys(a.p).includes(prop)) {
              return function (...pArgs) {
                let skip = false;
                a.p[prop].forEach((hook) => {
                  const result = hook(ctx, ...pArgs);
                  if (!result) {
                    skip = true;
                  } else {
                    [ctx, pArgs] = result;
                  }
                });
                if (skip) return;
                return original.apply(target, pArgs);
              };
            }
            return original.bind(target);
          },
          set: function (target, prop, value) {
            target[prop] = value;
            return true;
          },
        });
      };
      return proxyCanvas;
    }

    createUnifiedMenu();
  }

  _(methodName, hookFn) {
    if (Object.keys(a.p).includes(methodName)) {
      a.p[methodName].push(hookFn);
    } else {
      a.p[methodName] = [hookFn];
    }
  }
}
a = new _a();

let spinSpeed = 0.80; 
let isSpinning = false;
let spinAngle = 0;
let isShooting = false;
let isFiring = false;
let isAimbotActive = false;
let playerTank = "Tank";
let playerLevel = 1;
let playerX = 0;
let playerY = 0;
let arrowPos = [0, 0];
let minimapPos = [0, 0];
let minimapSize = [0, 0];
let fov = 0.5;
let text = [];
let tankShapes = [];
let lastPlayers = [];
let players = [];
let lastArc = [Infinity, Infinity];
let mousePressed = false;
let mouseLocked = false;
let mouseX = 0;
let mouseY = 0;
let isAutoFarm = false;  
let neutralSquares = [];  
let neutralPentagons = []; 
let neutralTriangles = [];
let farmPriority = "pentagon";
let isDebug = false;
let hasJoined = false;
const averageEnemyDodgeTime = 1750;
const destroyerAccuracy = true;
const playerVelocityPredictionSampleSize = 50;
const arenaSize = 26000;
const gameStyle = {
  ren_grid_base_alpha: 0.05,
  square: "#ffe869",
  triangle: "#fc7677",
  pentagon: "#768dfc",
  teamBlue: "#00b2e1",
  teamRed: "#f14e54",
  teamPurple: "#bf7ff5",
  teamGreen: "#00e16e",
};
let teamColor = "";
const bulletSpeedOffsets = {
  Skimmer: 0.5,
  Factory: 0.56,
  Annihilator: 0.7,
  Streamliner: 1.1,
  "Auto Gunner": 1.1,
  Gunner: 1.1,
  Predator: 1.4,
  Mothership: 0.48,
  Manager: 0.8,
  Hybrid: 0.7,
  Ranger: 1.5,
  Stalker: 1.5,
  Assassin: 1.5,
  Sniper: 1.5,
  Hunter: 1.4,
  Necromancer: 0.72,
  "Arena Closer": 2,
  Overlord: 0.8,
  Overseer: 0.8,
  Destroyer: 0.7,
};
const predatorStackTime = [
  [50, 500, 1400, 2800],
  [50, 500, 1300, 2700],
  [50, 400, 1200, 2450],
  [50, 300, 1100, 2200],
  [50, 300, 1000, 2100],
  [50, 300, 900, 1800],
  [50, 300, 800, 1700],
  [50, 300, 750, 1500],
];
const hunterStackTime = [
  [50, 1200],
  [50, 1100],
  [50, 1000],
  [50, 950],
  [50, 800],
  [50, 725],
  [50, 700],
  [50, 625],
];
const buildStatLevels = [
  2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
  23, 24, 25, 26, 27, 28, 30, 33, 36, 39, 42, 45,
];
const statNumbers = {
  1: "healthRegen",
  2: "maxHealth",
  3: "bodyDamage",
  4: "bulletSpeed",
  5: "bulletPenetration",
  6: "bulletDamage",
  7: "reload",
  8: "movementSpeed",
};

function getUpgrades() {
  let upgrades = 0;
  for (let i = 0; i < buildStatLevels.length; ++i) {
    upgrades++;
    if (playerLevel < buildStatLevels[i]) break;
  }
  return upgrades;
}
function canUpgrade() {
  const rawStats = window.extern.get_convar("game_stats_build");
  return getUpgrades() - 1 > rawStats.length;
}
function truncateStats() {
  const rawStats = window.extern.get_convar("game_stats_build");
  return rawStats.slice(0, getUpgrades());
}
function getStats() {
  const rawStats = window.extern.get_convar("game_stats_build");
  let stats = {
    healthRegen: 0,
    maxHealth: 0,
    bodyDamage: 0,
    bulletSpeed: 0,
    bulletPenetration: 0,
    bulletDamage: 0,
    reload: 0,
    movementSpeed: 0,
  };
  for (let i = 0; i < rawStats.length; ++i) {
    ++stats[statNumbers[rawStats[i]]];
  }
  return stats;
}

let forcingU = false;
function forceU() {
  if (canUpgrade()) {
    forcingU = true;
    window.extern.onKeyDown(21, 1);
  } else if (forcingU) {
    forcingU = false;
    window.extern.onKeyUp(21, 1);
  }
}
function getTankBulletSpeedOffset(tank) {
  return bulletSpeedOffsets[tank] || 1;
}
function calculateMainBulletSpeed() {
  const speedstat = getStats().bulletSpeed;
  return (
    (20 + speedstat * 3 * getTankBulletSpeedOffset(playerTank)) * 0.03
  );
}
function getDistance(x1, y1, x2, y2) {
  const distX = x1 - x2;
  const distY = y1 - y2;
  return Math.hypot(distX, distY);
}

function calculateTime(player) {
  const distance = getDistance(playerX, playerY, player.wx, player.wy);
  const bulletSpeed = calculateMainBulletSpeed();
  const playerVel = getDistVel(player);
  const relativeBulletToTargetVel = bulletSpeed - playerVel;
  return distance / relativeBulletToTargetVel;
}

function predictPlayer(player, time) {
  const [velX, velY] =
    typeof player.velocity === "undefined"
      ? [0, 0]
      : [(player.velocity[0] || 0), (player.velocity[1] || 0)];
  return [player.wx + time * velX, player.wy + time * velY];
}

function getDistVel(player) {
  let dd = 0;
  let dataPoints = 0;
  for (let i = 1; i < player.positionTable.length; ++i) {
    if (!player.positionTable[i] || !player.positionTable[i - 1]) continue;
    const d =
      getDistance(
        playerX,
        playerY,
        player.positionTable[i].x,
        player.positionTable[i].y
      ) -
      getDistance(
        playerX,
        playerY,
        player.positionTable[i - 1].x,
        player.positionTable[i - 1].y
      );
    const dt =
      player.positionTable[i].timestamp - player.positionTable[i - 1].timestamp;
    dd += d / dt;
    dataPoints++;
  }
  return dataPoints > 0 ? dd / dataPoints : 0;
}

function getPlayerWeight(player) {
  const distanceWeight =
    (1 / getDistance(playerX, playerY, player.wx, player.wy)) * 1000;
  const scoreWeight = Math.min(23536, Math.max(0, player.score || 0)) / 100000;
  return distanceWeight + scoreWeight;
}

function setPlayerPos() {
  const dx = arrowPos[0] - minimapPos[0];
  const dy = arrowPos[1] - minimapPos[1];
  playerX = (dx / minimapSize[0]) * arenaSize;
  playerY = (dy / minimapSize[1]) * arenaSize;
}

function getRenderedWorldPosition(x, y) {
  const mainCanvas = document.getElementById("canvas");
  const midX = x - mainCanvas.width / 2;
  const midY = y - mainCanvas.height / 2;
  const scaledX = midX / (fov / 2.8);
  const scaledY = midY / (fov / 2.8);
  return [playerX + scaledX, playerY + scaledY];
}

function worldToCanvasPosition(x, y) {
  const mainCanvas = document.getElementById("canvas");
  const deltaX = x - playerX;
  const deltaY = y - playerY;
  return [
    mainCanvas.width / 2 + deltaX * (fov / 2.8),
    mainCanvas.height / 2 + deltaY * (fov / 2.8),
  ];
}

function worldToMousePosition(x, y) {
  const deltaX = x - playerX;
  const deltaY = y - playerY;
  return [
    window.innerWidth / 2 + deltaX * (fov / 2.8),
    window.innerHeight / 2 + deltaY * (fov / 2.8),
  ];
}

function parseDiepScore(s) {
  let scoreMultiplier = 1;
  if (s[s.length - 1] === "k") scoreMultiplier = 1000;
  else if (s[s.length - 1] === "m") scoreMultiplier = 1000000;
  else if (!s.includes(".")) {
    if (isNaN(s)) return null;
    const toInt = parseInt(s, 10);
    return isNaN(toInt) ? null : toInt;
  } else return null;
  const toFloat = parseFloat(s.slice(0, -1));
  if (isNaN(toFloat)) return null;
  return toFloat * scoreMultiplier;
}

function getClosestText(arr, x, y) {
  return arr.reduce(function (acc, cur) {
    if (!acc) return cur;
    const distAcc = getDistance(x, y, acc.mx, acc.my);
    const distCur = getDistance(x, y, cur.mx, cur.my);
    return distAcc > distCur ? cur : acc;
  }, null);
}

function getPlayers() {
  lastPlayers = players;
  players = [];
  for (let aIndex = 0; aIndex < tankShapes.length; ++aIndex) {
    if (tankShapes[aIndex].radius / fov < 19) continue;
    const scoreTextPos = [
      tankShapes[aIndex].x,
      tankShapes[aIndex].y - tankShapes[aIndex].radius * 1.3,
    ];
    const nameTextPos = [
      tankShapes[aIndex].x,
      tankShapes[aIndex].y - tankShapes[aIndex].radius * 2,
    ];
    const closestScoreText = getClosestText(text, ...scoreTextPos);
    const closestNameText = getClosestText(text, ...nameTextPos);
    const distToScore = closestScoreText
      ? getDistance(
          ...scoreTextPos,
          closestScoreText.mx,
          closestScoreText.my
        )
      : Infinity;
    const distToName = closestNameText
      ? getDistance(...nameTextPos, closestNameText.mx, closestNameText.my)
      : Infinity;

    let score = "";
    let name = "";
    if (distToScore < 25) {
      score = parseDiepScore(closestScoreText ? closestScoreText.text : "-1");
    }
    if (distToName < 25) {
      name = closestNameText ? closestNameText.text : "";
    }
    if (score !== "") {
      const [wx, wy] = getRenderedWorldPosition(
        tankShapes[aIndex].x,
        tankShapes[aIndex].y
      );
      players.push({
        wx,
        wy,
        x: tankShapes[aIndex].x,
        y: tankShapes[aIndex].y,
        radius: tankShapes[aIndex].radius,
        name,
        score,
        velocity: undefined,
        teammate: tankShapes[aIndex].fillStyle === gameStyle[teamColor],
      });
    }
  }
}

function matchPlayers() {
  for (let i = 0; i < players.length; ++i) {
    const [x, y] = [players[i].wx, players[i].wy];
    const lastPlayer = lastPlayers.reduce((acc, cur) => {
      if (!acc) return cur;
      const distAcc = getDistance(x, y, acc.wx, acc.wy);
      const distCur = getDistance(x, y, cur.wx, cur.wy);
      return distAcc > distCur ? cur : acc;
    }, null);
    if (
      lastPlayer &&
      getDistance(
        players[i].wx,
        players[i].wy,
        lastPlayer.wx,
        lastPlayer.wy
      ) < 25
    ) {
      players[i].teammate = lastPlayer.teammate || players[i].teammate;
      players[i].positionTable = lastPlayer.positionTable.concat();
      players[i].positionTable.push({
        x: players[i].wx,
        y: players[i].wy,
        timestamp: performance.now(),
      });
      players[i].positionTable.shift();
      players[i].velocity = getVelocity(players[i]);
    } else {
      players[i].positionTable = Array.from(
        new Array(playerVelocityPredictionSampleSize),
        () => null
      );
    }
  }
}

function getVelocity(player) {
  let tx = 0,
    ty = 0;
  let dataPoints = 0;
  for (let i = 1; i < player.positionTable.length; ++i) {
    if (!player.positionTable[i] || !player.positionTable[i - 1]) continue;
    const dx = player.positionTable[i].x - player.positionTable[i - 1].x;
    const dy = player.positionTable[i].y - player.positionTable[i - 1].y;
    const dt =
      player.positionTable[i].timestamp - player.positionTable[i - 1].timestamp;
    tx += dx / dt;
    ty += dy / dt;
    dataPoints++;
  }
  return dataPoints > 0 ? [tx / dataPoints, ty / dataPoints] : [0, 0];
}

function renderOverlay(player, tx, ty, px, py) {
  if (!isDebug) return;
  const ctx = document.getElementById("canvas").getContext("2d");
  const [stx, sty] = worldToCanvasPosition(tx, ty);
  const [spx, spy] = worldToCanvasPosition(px, py);
  ctx.beginPath();
  ctx.arc(stx, sty, 25, Math.PI * 2, 0, 1);
  ctx.globalAlpha = 0.35;
  ctx.fillStyle = "#ff5294";
  ctx.fill();
  ctx.beginPath();
  ctx.arc(spx, spy, 25, Math.PI * 2, 0, 1);
  ctx.fillStyle = "#52e8ff";
  ctx.fill();
  ctx.globalAlpha = 1;
  ctx.beginPath();
  ctx.moveTo(stx, sty);
  ctx.lineTo(spx, spy);
  ctx.strokeStyle = "#000000";
  ctx.lineWidth = 1;
  ctx.stroke();
}

function aim() {
  const target = players
    .filter(plr => !plr.teammate)
    .reduce((acc, cur) => {
      if (!acc) return cur;
      return getPlayerWeight(cur) > getPlayerWeight(acc) ? cur : acc;
    }, null);
  const enemyMightDodge =
    destroyerAccuracy &&
    !!target &&
    ["Destroyer", "Hybrid", "Annihilator"].includes(playerTank) &&
    calculateTime(target) >= averageEnemyDodgeTime;

  if (!target || enemyMightDodge || !isAimbotActive || mousePressed) {
    if (mouseLocked) {
      mouseLocked = false;
      window.extern.onTouchMove(-1, mouseX, mouseY, true);
      setTimeout(() => {
        window.extern.onKeyUp(36);
      }, 80);
    }
    return;
  }
  if (!mouseLocked) {
    mouseLocked = true;
    setTimeout(() => {
      isFiring = true;
      window.extern.onKeyDown(36);
    }, 80);
  }

  const [sPX, sPY] = worldToMousePosition(target.wx, target.wy);

  if (sPX != null && sPY != null) {
    if (typeof window.extern.onTouchMove === "function") {
      window.extern.onTouchMove(-1, sPX, sPY, true);
    } else if (typeof window.extern.onMouseMove === "function") {
      window.extern.onMouseMove(sPX, sPY);
    } else {
      window.extern.onTouchMove(-1, sPX, sPY, true);
    }

    setTimeout(() => {
      isFiring = true;
      window.extern.onKeyDown(36);
      setTimeout(() => {
        window.extern.onKeyUp(36);
      }, 50);
    }, 10);
  }
  renderOverlay(target, target.wx, target.wy, target.wx, target.wy);
}

function stack() {
  if (!(window && window.extern)) return;
  const reload = getStats().reload;
  window.extern.onKeyUp(36); // release fire

  if (playerTank === "Hunter") {
    shoot(hunterStackTime[reload][0]);
    setTimeout(() => {
      window.extern.onKeyDown(5);
      window.extern.onKeyUp(5);
    }, hunterStackTime[reload][1]);
  } else if (playerTank === "Predator") {
    shoot(predatorStackTime[reload][0]);
    setTimeout(() => {
      shoot(predatorStackTime[reload][1]);
    }, predatorStackTime[reload][2]);
    setTimeout(() => {
      window.extern.onKeyDown(5);
      window.extern.onKeyUp(5);
    }, predatorStackTime[reload][3]);
  }
}
function shoot(t) {
  isFiring = true;
  window.extern.onKeyDown(36);
  setTimeout(() => {
    window.extern.onKeyUp(36);
  }, t);
}

document.addEventListener("mousedown", function (ev) {
  mousePressed = true;
  if (ev.button === 0) {
    if (mouseLocked) {
      isFiring = true;
      window.extern.onKeyDown(36);
      setTimeout(() => {
        window.extern.onKeyDown(36);
      }, 10);
    }
  }
});
document.addEventListener("mouseup", function (ev) {
  mousePressed = false;
  if (ev.button === 0) {
    window.extern.onKeyUp(36);
  }
});
document.addEventListener("touchstart", function (ev) {
  isShooting = true;
});
document.addEventListener("touchend", function (ev) {
  isShooting = false;
});
document.addEventListener(
  "mousemove",
  function (ev) {
    if (isSpinning) {
      ev.stopImmediatePropagation();
      ev.preventDefault();
    }
  },
  true
);
document.addEventListener(
  "touchmove",
  function (ev) {
    if (isSpinning) {
      ev.stopImmediatePropagation();
      ev.preventDefault();
    }
  },
  true
);
// yes
const KeyToToggleAimbot = "KeyU";
const KeyToStack       = "KeyI";
const KeyToToggleMenu  = "KeyM";

document.addEventListener("keydown", function (ev) {
  if (ev.code === KeyToToggleAimbot) {
    isAimbotActive ^= 1;
    if (window.__common__ && window.__common__.active_gamemode === "sandbox") {
      window.extern &&
        window.extern.inGameNotification(
          "Aimbot Doesn't Work in Sandbox",
          0xF533FF
        );
      isAimbotActive = 0;
    } else {
      window.extern &&
        window.extern.inGameNotification(
          isAimbotActive ? "Aimbot: ON" : "Aimbot: OFF",
          0xF533FF
        );
    }
    const aimbotCheckbox = document.getElementById("aimbot-checkbox");
    if (aimbotCheckbox) aimbotCheckbox.checked = Boolean(isAimbotActive);
  }
  else if (ev.code === KeyToStack) {
    if (["Hunter", "Predator"].includes(playerTank)) {
      stack();
      window.extern &&
        window.extern.inGameNotification("Stacking Bullets...", 0xF533FF);
    }
  }
  else if (ev.code === KeyToToggleMenu) {
    if (!menuContainer) return;
    const isHidden = menuContainer.style.display === "none";
    menuContainer.style.display = isHidden ? "block" : "none";
  }
});
// why am I even doing this?
let ctxTransform;
a._("setTransform", (context, ...args) => {
  ctxTransform = args;
  return [context, args];
});

a._("drawImage", (context, ...args) => {
  if (args[0].renderMethod) {
    const x = ctxTransform[4] + args[1];
    const y = ctxTransform[5] + args[2];
    if (args[0].renderMethod.method === "text") {
      text.push({
        x,
        y,
        cw: args[0].width,
        ch: args[0].height,
        mx: x + args[0].width / 4,
        my: y + args[0].height / 4,
        text: args[0].renderMethod.text,
      });
    }
  }
  return [context, args];
});

a._("strokeText", (context, ...args) => {
  if (context.canvas.id !== "canvas") {
    context.canvas.renderMethod = {
      method: "text",
      text: args[0],
      args,
      fillStyle: context.fillStyle,
    };
    if (args[0].startsWith("Lvl ")) {
      if (args[0][5] === " ") {
        playerLevel = Number(args[0].slice(4, 5));
        playerTank = args[0].slice(6);
      } else {
        playerLevel = Number(args[0].slice(4, 6));
        playerTank = args[0].slice(7);
      }
    }
  }
  return [context, args];
});
a._("arc", (context, ...args) => {
  if (
    context.canvas.id === "canvas" &&
    ctxTransform[4] === lastArc[0] &&
    ctxTransform[5] === lastArc[1]
  ) {
    tankShapes.push({
      x: ctxTransform[4],
      y: ctxTransform[5],
      radius: Math.hypot(ctxTransform[1], ctxTransform[0]),
      fillStyle: context.fillStyle,
    });
    lastArc = [Infinity, Infinity];
  } else {
    lastArc = [ctxTransform[4], ctxTransform[5]];
  }
  return [context, args];
});
// maybe my sister looks hot
a._("stroke", (context, ...args) => {
  if (
    ["#cccccc", "#cdcdcd"].includes(context.fillStyle) &&
    context.strokeStyle === "#000000"
  ) {
    fov = context.globalAlpha / gameStyle.ren_grid_base_alpha;
  }
  return [context, args];
});

a._("strokeRect", (context, ...args) => {
  const t = context.getTransform();
  minimapPos = [t.e, t.f];
  minimapSize = [t.a, t.d];
  return [context, args];
});

// yes i will kill myself one day
let position = 0;
let vertex = [];

a._("beginPath", (context, ...args) => {
  position = 0;
  vertex = [];
  return [context, args];
});
a._("moveTo", (context, ...args) => {
  position = 1;
  vertex.push(args);
  return [context, args];
});
a._("lineTo", (context, ...args) => {
  position++;
  vertex.push(args);
  return [context, args];
});
a._("fill", (context, ...args) => {
  if (
    context.fillStyle === "#000000" &&
    context.globalAlpha > 0.949 &&
    position === 3
  ) {
    arrowPos = getAverage(vertex);
    setPlayerPos();
  }
  else if (
    position === 4 &&
    context.fillStyle &&
    context.fillStyle.toLowerCase().includes("ffe869")
  ) {
    const [rawX, rawY] = getAverage(vertex);
    const centerX = ctxTransform[4] + rawX;
    const centerY = ctxTransform[5] + rawY;
    neutralSquares.push([centerX, centerY]);
  }
  else if (
    position === 5 &&
    context.fillStyle &&
    context.fillStyle.toLowerCase().includes("768dfc")
  ) {
    const [rawX, rawY] = getAverage(vertex);
    const centerX = ctxTransform[4] + rawX;
    const centerY = ctxTransform[5] + rawY;
    neutralPentagons.push([centerX, centerY]);
  }

  else if (
    position === 3 &&
    context.fillStyle &&
    context.fillStyle.toLowerCase().includes("fc7677")
  ) {
    const [rawX, rawY] = getAverage(vertex);
    const centerX = ctxTransform[4] + rawX;
    const centerY = ctxTransform[5] + rawY;
    neutralTriangles.push([centerX, centerY]);
  }

  return [context, args];
});

function getAverage(points) {
  let tx = 0,
    ty = 0;
  points.forEach((point) => {
    tx += point[0];
    ty += point[1];
  });
  return [tx / points.length, ty / points.length];
}

// i hate niggers btw
function onFrame() {
  window.requestAnimationFrame(onFrame);

  getPlayers();
  matchPlayers();

  if (isDebug) {
    const ctx = document.getElementById("canvas").getContext("2d");
    ctx.save();
    ctx.strokeStyle = "#FF0000";
    ctx.lineWidth = 1;
    const centerX = ctx.canvas.width / 2;
    const centerY = ctx.canvas.height / 2;
    players.forEach((plr) => {
      if (!plr.teammate) {
        ctx.beginPath();
        ctx.moveTo(centerX, centerY);
        ctx.lineTo(plr.x, plr.y);
        ctx.stroke();
      }
    });
    ctx.restore();
  }

  forceU();
  aim();
  text = [];
  tankShapes = [];
  getTeam();

  if (isAutoFarm && window.extern && window.extern.doesHaveTank()) {
    if (isDebug) {
      const ctx = document.getElementById("canvas").getContext("2d");
      ctx.save();
      const centerX = ctx.canvas.width / 2;
      const centerY = ctx.canvas.height / 2;

      ctx.strokeStyle = "#9600D6";
      ctx.lineWidth = 1;
      neutralPentagons.forEach(([cx, cy]) => {
        ctx.beginPath();
        ctx.moveTo(centerX, centerY);
        ctx.lineTo(cx, cy);
        ctx.stroke();
      });

      ctx.strokeStyle = "#00FF00";
      ctx.lineWidth = 1;
      neutralSquares.forEach(([cx, cy]) => {
        ctx.beginPath();
        ctx.moveTo(centerX, centerY);
        ctx.lineTo(cx, cy);
        ctx.stroke();
      });
      ctx.strokeStyle = "#FF9900";
      ctx.lineWidth = 1;
      neutralTriangles.forEach(([cx, cy]) => {
        ctx.beginPath();
        ctx.moveTo(centerX, centerY);
        ctx.lineTo(cx, cy);
        ctx.stroke();
      });

      ctx.restore();
    }

    let targetWorld = null;

    if (farmPriority === "pentagon" && neutralPentagons.length > 0) {
      targetWorld = nearestShapeWorld(neutralPentagons);
    } else if (farmPriority === "square" && neutralSquares.length > 0) {
      targetWorld = nearestShapeWorld(neutralSquares);
    } else if (farmPriority === "triangle" && neutralTriangles.length > 0) {
      targetWorld = nearestShapeWorld(neutralTriangles);
    }
    if (!targetWorld) {
      if (farmPriority !== "pentagon" && neutralPentagons.length > 0) {
        targetWorld = nearestShapeWorld(neutralPentagons);
      } else if (farmPriority !== "square" && neutralSquares.length > 0) {
        targetWorld = nearestShapeWorld(neutralSquares);
      } else if (farmPriority !== "triangle" && neutralTriangles.length > 0) {
        targetWorld = nearestShapeWorld(neutralTriangles);
      }
    }
    if (targetWorld) {
      const [sPX, sPY] = worldToMousePosition(targetWorld[0], targetWorld[1]);
      if (sPX != null && sPY != null) {
        isFiring = true;
        window.extern.onTouchMove(-1, sPX, sPY, true);
        window.extern.onKeyDown(36);
        setTimeout(() => {
          window.extern.onKeyUp(36);
        }, 50);
      }
    }
  }
  neutralSquares = [];
  neutralPentagons = [];
  neutralTriangles = [];
  if (
    isSpinning &&
    !isShooting &&
    !isFiring &&
    window.extern &&
    window.extern.doesHaveTank()
  ) {
    spinAngle += spinSpeed;
    const cx = window.innerWidth / 2;
    const cy = window.innerHeight / 2;
    const radius = 120;
    const targetX = cx + radius * Math.cos(spinAngle);
    const targetY = cy + radius * Math.sin(spinAngle);
    if (typeof window.extern.onTouchMove === "function") {
      window.extern.onTouchMove(-1, targetX, targetY, true);
    } else if (typeof window.extern.onMouseMove === "function") {
      window.extern.onMouseMove(targetX, targetY);
    }
  }

  if (window.extern && window.extern.doesHaveTank() && !hasJoined) {
    hasJoined = true;
    window.extern.inGameNotification("Welcome to SkidWare. Press M for menu.", 0x6670ff);
  }
}

function nearestShapeWorld(arr) {
  let nearest = null;
  let nearestDist = Infinity;
  for (const [cx, cy] of arr) {
    const [wx, wy] = getRenderedWorldPosition(cx, cy);
    const dist = getDistance(playerX, playerY, wx, wy);
    if (dist < nearestDist) {
      nearestDist = dist;
      nearest = [wx, wy];
    }
  }
  return nearest;
}


function onGameStart() {
  if (typeof extern === "undefined") return;
  clearInterval(checkGameStart);
  window.requestAnimationFrame(onFrame);

  window.extern.onKeyDown = new Proxy(window.extern.onKeyDown, {
    apply: function (method, context, args) {
      if (args[0] === 36) {
        isFiring = true;
      }
      if (args[0] === 21 && !args[1]) return;
      return Reflect.apply(method, context, args);
    },
  });
  window.extern.onKeyUp = new Proxy(window.extern.onKeyUp, {
    apply: function (method, context, args) {
      if (args[0] === 36) {
        isFiring = false;
      }
      if (args[0] === 21 && !args[1]) return;
      return Reflect.apply(method, context, args);
    },
  });

  const mouseHandler = {
    apply: function (method, context, args) {
      if (!args[3]) {
        [mouseX, mouseY] = [args[1], args[2]];
        if (mouseLocked) return;
      }
      return Reflect.apply(method, context, args);
    },
  };
  window.extern.onTouchStart = new Proxy(window.extern.onTouchStart, mouseHandler);
  window.extern.onTouchMove  = new Proxy(window.extern.onTouchMove,  mouseHandler);
  window.extern.onTouchEnd   = new Proxy(window.extern.onTouchEnd,   mouseHandler);

  window.extern.set_convar = new Proxy(window.extern.set_convar, {
    apply: function (method, context, args) {
      gameStyle[args[0]] = args[1];
      return Reflect.apply(method, context, args);
    },
  });

  window.extern.execute = new Proxy(window.extern.execute, {
    apply: function (method, context, args) {
      if (args[0].startsWith("net_replace_color 3 ")) {
        gameStyle.teamBlue =
          args[0][20] === "0" ? "#" + args[0].slice(22) : args[0].slice(20);
      }
      if (args[0].startsWith("net_replace_color 4 ")) {
        gameStyle.teamRed =
          args[0][20] === "0" ? "#" + args[0].slice(22) : args[0].slice(20);
      }
      if (args[0].startsWith("net_replace_color 5 ")) {
        gameStyle.teamPurple =
          args[0][20] === "0" ? "#" + args[0].slice(22) : args[0].slice(20);
      }
      if (args[0].startsWith("net_replace_color 6 ")) {
        gameStyle.teamGreen =
          args[0][20] === "0" ? "#" + args[0].slice(22) : args[0].slice(20);
      }
      if (args[0].startsWith("net_replace_color 8 ")) {
        gameStyle.square =
          args[0][20] === "0" ? "#" + args[0].slice(22) : args[0].slice(20);
      }
      if (args[0].startsWith("net_replace_color 9 ")) {
        gameStyle.triangle =
          args[0][20] === "0" ? "#" + args[0].slice(22) : args[0].slice(20);
      }
      if (args[0].startsWith("net_replace_color 10 ")) {
        gameStyle.pentagon =
          args[0][21] === "0" ? "#" + args[0].slice(23) : args[0].slice(21);
      }
      return Reflect.apply(method, context, args);
    },
  });
}

const checkGameStart = setInterval(onGameStart, 400);

function getTeam() {
  const partyLinkButton = document.getElementById("copy-party-link");
  if (!partyLinkButton) return;
  switch (partyLinkButton.className) {
    case "active blue":
      teamColor = "teamBlue";
      break;
    case "active purple":
      teamColor = "teamPurple";
      break;
    case "active green":
      teamColor = "teamGreen";
      break;
    case "active red":
      teamColor = "teamRed";
      break;
  }
}

let menuContainer = null;
let isBlackBg = false;
let blackBgDiv = null;

// menu full chatgpt
function createUnifiedMenu() {
  const styleEl = document.createElement("style");
  styleEl.textContent = `
    /* ===================== skeet.cc-Style Menu (30% Bigger & Draggable) ===================== */

    @font-face {
      font-family: 'SkeetFont';
      src: local('Segoe UI'), local('Arial'), sans-serif;
      /* Fallback: system sans-serif if Segoe UI not present */
    }

    /* ── Main Menu Container ───────────────────────────────────────────────────── */
    .skeet-menu {
      position: fixed;
      /* Initial position at 50px, 50px; will be overridden during dragging */
      top: 50px;
      left: 50px;
      width: 494px;                    /* 380px * 1.3 */
      background-color: #1b1b1b;
      border: 1px solid #2f2f2f;
      border-radius: 6px;
      box-shadow: 0 0 12px rgba(0, 0, 0, 0.7);
      font-family: 'SkeetFont', sans-serif;
      color: #e0e0e0;
      font-size: 17px;                 /* 13px * 1.3 */
      user-select: none;
      display: none;                   /* hidden by default; toggled with “M” */
      pointer-events: auto;
      z-index: 9999;
    }

    /* ── Drag Handle (26px high) ─────────────────────────────────────────────────── */
    .skeet-drag-handle {
      height: 26px;                    /* 20px * 1.3 */
      background-color: #2f2f2f;
      border-bottom: 1px solid #2f2f2f;
      cursor: move;
      text-align: center;
      line-height: 26px;               /* same as height, to center text vertically */
      font-size: 17px;                 /* 13px * 1.3 */
      font-weight: 500;
      color: #e0e0e0;
      user-select: none;
    }

    /* ── Sidebar (104px-wide Text Tabs) ────────────────────────────────────────── */
    .skeet-sidebar {
      float: left;
      width: 104px;                    /* 80px * 1.3 */
      background-color: #171717;
      border-right: 1px solid #2f2f2f;
      display: flex;
      flex-direction: column;
      align-items: center;
      padding-top: 16px;               /* 12px * 1.3 */
    }

    .skeet-sidebar button {
      width: 83px;                     /* 64px * 1.3 ≈ 83 */
      height: 42px;                    /* 32px * 1.3 ≈ 42 */
      margin: 8px 0;                   /* 6px * 1.3 ≈ 8 */
      background-color: transparent;
      border: none;
      outline: none;
      cursor: pointer;
      transition: background-color 0.15s ease, color 0.15s ease;
      color: #888888;
      font-size: 17px;                 /* 13px * 1.3 ≈ 17 */
      font-weight: 500;
    }

    .skeet-sidebar button:hover,
    .skeet-sidebar button.active {
      background-color: #2f2f2f;
      color: #00b4ff;
      border-radius: 4px;
    }

    /* ── Content Area (Remaining ≈390px) ────────────────────────────────────────── */
    .skeet-content {
      margin-left: 104px;              /* leave room for sidebar */
      padding: 21px;                   /* 16px * 1.3 ≈ 21 */
      box-sizing: border-box;
    }

    /* Hide all sections by default; only the “.active” one displays */
    .skeet-section {
      display: none;
    }
    .skeet-section.active {
      display: block;
    }

    .skeet-content .section-title {
      font-size: 21px;                 /* 16px * 1.3 ≈ 21 */
      font-weight: 600;
      color: #ffffff;
      margin-bottom: 13px;             /* 10px * 1.3 ≈ 13 */
    }

    /* ── Section Header ───────────────────────────────────────────────────────── */
    .skeet-section .header {
      font-size: 18px;                 /* 14px * 1.3 ≈ 18 */
      font-weight: 500;
      margin-bottom: 10px;             /* 8px * 1.3 ≈ 10 */
      color: #e0e0e0;
    }

    /* ── Toggle Labels (Checkbox + Text) ───────────────────────────────────────── */
    .skeet-toggle-label {
      display: flex;
      align-items: center;
      margin-bottom: 10px;             /* 8px * 1.3 ≈ 10 */
      cursor: pointer;
    }
    .skeet-toggle-label input[type="checkbox"] {
      width: 18px;                     /* 14px * 1.3 ≈ 18 */
      height: 18px;                    /* 14px * 1.3 ≈ 18 */
      margin-right: 10px;              /* 8px * 1.3 ≈ 10 */
      accent-color: #00b4ff;
      cursor: pointer;
      outline: none;
    }
    .skeet-toggle-label span {
      font-size: 17px;                 /* 13px * 1.3 ≈ 17 */
      color: #e0e0e0;
    }

    /* ── Slider (Range Input) ─────────────────────────────────────────────────── */
    .skeet-slider-container {
      display: flex;
      align-items: center;
      margin-bottom: 15px;             /* 12px * 1.3 ≈ 15 */
    }
    .skeet-slider-container span {
      margin-right: 10px;              /* 8px * 1.3 ≈ 10 */
      font-size: 16px;                 /* 12px * 1.3 ≈ 16 */
      color: #cccccc;
      min-width: 91px;                 /* 70px * 1.3 ≈ 91 */
    }
    .skeet-slider {
      flex: 1;
      -webkit-appearance: none;
      width: 100%;
      height: 5px;                     /* 4px * 1.3 ≈ 5 */
      background: #2f2f2f;
      border-radius: 3px;
      cursor: pointer;
      outline: none;
    }
    .skeet-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px;                     /* 12px * 1.3 ≈ 16 */
      height: 16px;                    /* 12px * 1.3 ≈ 16 */
      border-radius: 50%;
      background: #00b4ff;
      border: 1px solid #1b1b1b;
      cursor: pointer;
      margin-top: -5px;                /* center thumb (≈ half the thumb height) */
    }
    .skeet-slider::-moz-range-thumb {
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: #00b4ff;
      border: 1px solid #1b1b1b;
      cursor: pointer;
    }

    /* ── Buttons (Load/Save/Stack etc.) ───────────────────────────────────────── */
    .skeet-button {
      display: inline-block;
      background-color: #2f2f2f;
      color: #e0e0e0;
      font-size: 15px;                 /* 12px * 1.3 ≈ 15 */
      padding: 8px 16px;               /* 6px*1.3≈8  & 12px*1.3≈16 */
      margin-top: 8px;                 /* 6px * 1.3 ≈ 8 */
      border: 1px solid #3f3f3f;
      border-radius: 4px;
      cursor: pointer;
      transition: background-color 0.15s ease, border-color 0.15s ease;
    }
    .skeet-button:hover {
      background-color: #3f3f3f;
      border-color: #5f5f5f;
    }
    .skeet-button:active {
      background-color: #5f5f5f;
      border-color: #7f7f7f;
    }

    /* ── Radio Buttons for Farming Priority ───────────────────────────────────── */
    .skeet-radio-group {
      margin-bottom: 10px; /* some spacing */
    }
    .skeet-radio-label {
      display: flex;
      align-items: center;
      margin-right: 20px;
      cursor: pointer;
      font-size: 17px; /* 13px * 1.3 */
      color: #e0e0e0;
    }
    .skeet-radio-label input[type="radio"] {
      margin-right: 8px;
      accent-color: #00b4ff;
      cursor: pointer;
      outline: none;
    }

    /* ── Focus Ring for Keyboard Navigation ──────────────────────────────────── */
    .skeet-menu input:focus-visible,
    .skeet-menu button:focus-visible {
      outline: 2px solid #00b4ff;
      outline-offset: 1px;
    }
  `;
  document.head.appendChild(styleEl);

  menuContainer = document.createElement("div");
  menuContainer.classList.add("skeet-menu");

  const dragHandle = document.createElement("div");
  dragHandle.classList.add("skeet-drag-handle");
  dragHandle.innerText = "Skid Ware";
  menuContainer.appendChild(dragHandle);
  const sidebar = document.createElement("div");
  sidebar.classList.add("skeet-sidebar");

  const tabs = [
    { id: "tab-spin",    label: "Spin"    },
    { id: "tab-aim",     label: "Aim"     },
    { id: "tab-farm",    label: "Farm"    },
    { id: "tab-visuals", label: "Visuals" },
  ];

  tabs.forEach((t, idx) => {
    const btn = document.createElement("button");
    btn.id = t.id + "-btn";
    btn.innerText = t.label;
    btn.title = t.label;
    if (idx === 0) btn.classList.add("active");
    btn.addEventListener("click", () => switchTab(t.id));
    sidebar.appendChild(btn);
  });
  menuContainer.appendChild(sidebar);

  const content = document.createElement("div");
  content.classList.add("skeet-content");
  const spinSection = document.createElement("div");
  spinSection.id = "tab-spin";
  spinSection.classList.add("skeet-section", "active"); 

  const spinTitle = document.createElement("div");
  spinTitle.classList.add("section-title");
  spinTitle.innerText = "Spinner Settings:";
  spinSection.appendChild(spinTitle);

  const spinHeader = document.createElement("div");
  spinHeader.classList.add("header");
  spinHeader.innerText = "• Enable / Disable Spinner:";
  spinSection.appendChild(spinHeader);

  const spinToggleLabel = document.createElement("label");
  spinToggleLabel.classList.add("skeet-toggle-label");
  const spinCheckbox = document.createElement("input");
  spinCheckbox.type = "checkbox";
  spinCheckbox.id = "spinner-checkbox";
  spinCheckbox.checked = isSpinning;
  const spinLabelText = document.createElement("span");
  spinLabelText.innerText = "Enable Spinner";
  spinToggleLabel.appendChild(spinCheckbox);
  spinToggleLabel.appendChild(spinLabelText);
  spinSection.appendChild(spinToggleLabel);

  spinCheckbox.addEventListener("change", function () {
    isSpinning = this.checked;
    if (window.extern) {
      window.extern.inGameNotification(
        isSpinning ? "Spinner: ON" : "Spinner: OFF",
        0xF533FF
      );
    }
  });

  const spinSpeedHeader = document.createElement("div");
  spinSpeedHeader.classList.add("header");
  spinSpeedHeader.innerText = "• Spin Speed:";
  spinSection.appendChild(spinSpeedHeader);

  const spinSpeedContainer = document.createElement("div");
  spinSpeedContainer.classList.add("skeet-slider-container");
  const speedLabelText = document.createElement("span");
  speedLabelText.innerText = `Speed: ${spinSpeed.toFixed(2)}`;
  const spinSlider = document.createElement("input");
  spinSlider.type = "range";
  spinSlider.min = "0";
  spinSlider.max = "2";
  spinSlider.step = "0.01";
  spinSlider.value = spinSpeed.toString();
  spinSlider.classList.add("skeet-slider");

  spinSlider.addEventListener("input", (ev) => {
    spinSpeed = parseFloat(ev.target.value);
    speedLabelText.innerText = `Speed: ${spinSpeed.toFixed(2)}`;
  });
  ["mousedown", "mousemove", "mouseup", "touchstart", "touchmove", "touchend"].forEach((evt) => {
    spinSlider.addEventListener(evt, (e) => e.stopPropagation(), { capture: true, passive: false });
  });

  spinSpeedContainer.appendChild(speedLabelText);
  spinSpeedContainer.appendChild(spinSlider);
  spinSection.appendChild(spinSpeedContainer);

  content.appendChild(spinSection);

  const aimSection = document.createElement("div");
  aimSection.id = "tab-aim";
  aimSection.classList.add("skeet-section");

  const aimTitle = document.createElement("div");
  aimTitle.classList.add("section-title");
  aimTitle.innerText = "Aimbot Settings:";
  aimSection.appendChild(aimTitle);

  const aimHeader = document.createElement("div");
  aimHeader.classList.add("header");
  aimHeader.innerText = "• Enable / Disable Aimbot:";
  aimSection.appendChild(aimHeader);

  const aimToggleLabel = document.createElement("label");
  aimToggleLabel.classList.add("skeet-toggle-label");
  const aimCheckbox = document.createElement("input");
  aimCheckbox.type = "checkbox";
  aimCheckbox.id = "aimbot-checkbox";
  aimCheckbox.checked = isAimbotActive;
  const aimLabelText = document.createElement("span");
  aimLabelText.innerText = "Enable Aimbot";
  aimToggleLabel.appendChild(aimCheckbox);
  aimToggleLabel.appendChild(aimLabelText);
  aimSection.appendChild(aimToggleLabel);

  aimCheckbox.addEventListener("change", function () {
    isAimbotActive = this.checked;
    if (window.extern) {
      window.extern.inGameNotification(
        isAimbotActive ? "Aimbot: ON" : "Aimbot: OFF",
        0xF533FF
      );
    }
  });

  const stackHeader = document.createElement("div");
  stackHeader.classList.add("header");
  stackHeader.innerText = "• Manual Stack (Hunter/Predator):";
  aimSection.appendChild(stackHeader);

  const stackButton = document.createElement("button");
  stackButton.innerText = "Stack Bullets";
  stackButton.classList.add("skeet-button");
  stackButton.addEventListener("click", () => {
    if (["Hunter", "Predator"].includes(playerTank)) {
      stack();
      window.extern &&
        window.extern.inGameNotification("Stacking Bullets...", 0xF533FF);
    } else {
      window.extern &&
        window.extern.inGameNotification("Not Hunter/Predator", 0xF533FF);
    }
  });
  aimSection.appendChild(stackButton);

  content.appendChild(aimSection);

  const farmSection = document.createElement("div");
  farmSection.id = "tab-farm";
  farmSection.classList.add("skeet-section");

  const farmTitle = document.createElement("div");
  farmTitle.classList.add("section-title");
  farmTitle.innerText = "AutoFarm:";
  farmSection.appendChild(farmTitle);

  const farmHeader = document.createElement("div");
  farmHeader.classList.add("header");
  farmHeader.innerText = "• Enable / Disable AutoFarm:";
  farmSection.appendChild(farmHeader);

  const farmToggleLabel = document.createElement("label");
  farmToggleLabel.classList.add("skeet-toggle-label");
  const farmCheckbox = document.createElement("input");
  farmCheckbox.type = "checkbox";
  farmCheckbox.id = "autofarm-checkbox";
  farmCheckbox.checked = isAutoFarm;
  const farmLabelText = document.createElement("span");
  farmLabelText.innerText = "Enable AutoFarm";
  farmToggleLabel.appendChild(farmCheckbox);
  farmToggleLabel.appendChild(farmLabelText);
  farmSection.appendChild(farmToggleLabel);

  farmCheckbox.addEventListener("change", function () {
    isAutoFarm = this.checked;
    if (window.extern) {
      window.extern.inGameNotification(
        isAutoFarm ? "AutoFarm: ON" : "AutoFarm: OFF",
        0xF533FF
      );
    }
  });

  const priorityContainer = document.createElement("div");
  priorityContainer.classList.add("skeet-radio-group");
  const priorityLabel = document.createElement("div");
  priorityLabel.classList.add("header");
  priorityLabel.innerText = "• Farming Priority:";
  farmSection.appendChild(priorityLabel);

  const pentRadioLabel = document.createElement("label");
  pentRadioLabel.classList.add("skeet-radio-label");
  const pentRadio = document.createElement("input");
  pentRadio.type = "radio";
  pentRadio.name = "farm-priority";
  pentRadio.id = "farm-priority-pentagon";
  pentRadio.value = "pentagon";
  pentRadio.checked = (farmPriority === "pentagon");
  const pentLabelText = document.createElement("span");
  pentLabelText.innerText = "Prioritize Pentagons";
  pentRadioLabel.appendChild(pentRadio);
  pentRadioLabel.appendChild(pentLabelText);
  priorityContainer.appendChild(pentRadioLabel);

  pentRadio.addEventListener("change", function () {
    if (this.checked) {
      farmPriority = "pentagon";
      if (window.extern) {
        window.extern.inGameNotification("FarmPriority: Pentagons", 0xF533FF);
      }
    }
  });
  const sqRadioLabel = document.createElement("label");
  sqRadioLabel.classList.add("skeet-radio-label");
  const sqRadio = document.createElement("input");
  sqRadio.type = "radio";
  sqRadio.name = "farm-priority";
  sqRadio.id = "farm-priority-square";
  sqRadio.value = "square";
  sqRadio.checked = (farmPriority === "square");
  const sqLabelText = document.createElement("span");
  sqLabelText.innerText = "Prioritize Squares";
  sqRadioLabel.appendChild(sqRadio);
  sqRadioLabel.appendChild(sqLabelText);
  priorityContainer.appendChild(sqRadioLabel);

  sqRadio.addEventListener("change", function () {
    if (this.checked) {
      farmPriority = "square";
      if (window.extern) {
        window.extern.inGameNotification("FarmPriority: Squares", 0xF533FF);
      }
    }

  });
  const triRadioLabel = document.createElement("label");
  triRadioLabel.classList.add("skeet-radio-label");
  const triRadio = document.createElement("input");
  triRadio.type = "radio";
  triRadio.name = "farm-priority";
  triRadio.id = "farm-priority-triangle";
  triRadio.value = "triangle";
  triRadio.checked = (farmPriority === "triangle");
  const triLabelText = document.createElement("span");
  triLabelText.innerText = "Prioritize Triangles";
  triRadioLabel.appendChild(triRadio);
  triRadioLabel.appendChild(triLabelText);
  priorityContainer.appendChild(triRadioLabel);

  triRadio.addEventListener("change", function () {
    if (this.checked) {
      farmPriority = "triangle";
      if (window.extern) {
        window.extern.inGameNotification("FarmPriority: Triangles", 0xF533FF);
      }
    }
  });

  farmSection.appendChild(priorityContainer);
  content.appendChild(farmSection);
  const visualsSection = document.createElement("div");
  visualsSection.id = "tab-visuals";
  visualsSection.classList.add("skeet-section");

  const visualsTitle = document.createElement("div");
  visualsTitle.classList.add("section-title");
  visualsTitle.innerText = "Debug / Visuals:";
  visualsSection.appendChild(visualsTitle);

  const visualsHeader = document.createElement("div");
  visualsHeader.classList.add("header");
  visualsHeader.innerText = "• Enable / Disable Debug Lines:";
  visualsSection.appendChild(visualsHeader);

  const visualsToggleLabel = document.createElement("label");
  visualsToggleLabel.classList.add("skeet-toggle-label");
  const visualsCheckbox = document.createElement("input");
  visualsCheckbox.type = "checkbox";
  visualsCheckbox.id = "debug-checkbox";
  visualsCheckbox.checked = isDebug;
  const visualsLabelText = document.createElement("span");
  visualsLabelText.innerText = "Enable Debug Lines";
  visualsToggleLabel.appendChild(visualsCheckbox);
  visualsToggleLabel.appendChild(visualsLabelText);
  visualsSection.appendChild(visualsToggleLabel);

  visualsCheckbox.addEventListener("change", function () {
    isDebug = this.checked;
    if (window.extern) {
      window.extern.inGameNotification(
        isDebug ? "Debug Lines: ON" : "Debug Lines: OFF",
        0xF533FF
      );
    }
  });
  const blackBgToggleLabel = document.createElement("label");
  blackBgToggleLabel.classList.add("skeet-toggle-label");
  const blackBgCheckbox = document.createElement("input");
  blackBgCheckbox.type = "checkbox";
  blackBgCheckbox.id = "blackbg-checkbox";
  blackBgCheckbox.checked = isBlackBg;
  const blackBgLabelText = document.createElement("span");
  blackBgLabelText.innerText = "Black Background (buggy on aim)";
  blackBgToggleLabel.appendChild(blackBgCheckbox);
  blackBgToggleLabel.appendChild(blackBgLabelText);
  visualsSection.appendChild(blackBgToggleLabel);

  blackBgCheckbox.addEventListener("change", function () {
    isBlackBg = this.checked;
    if (window.input && typeof window.input.set_convar === "function") {
        window.input.set_convar("ren_background_color",
                                isBlackBg ? "#000000" : "#CDCDCD");
    }
    if (window.extern) {
      window.extern.inGameNotification(
        isBlackBg ? "Black background: ON" : "Black background: OFF",
        0xF533FF
      );
    }
  });
  content.appendChild(visualsSection);
  menuContainer.appendChild(content);
  document.body.appendChild(menuContainer);
  function switchTab(activeId) {
    tabs.forEach((t) => {
      const btn = document.getElementById(t.id + "-btn");
      if (t.id === activeId) btn.classList.add("active");
      else btn.classList.remove("active");
    });
    tabs.forEach((t) => {
      const section = document.getElementById(t.id);
      if (t.id === activeId) section.classList.add("active");
      else section.classList.remove("active");
    });
  }
  let isDragging = false;
  let dragOffsetX = 0;
  let dragOffsetY = 0;

  dragHandle.addEventListener("mousedown", function (e) {
    isDragging = true;
    const rect = menuContainer.getBoundingClientRect();
    dragOffsetX = e.clientX - rect.left;
    dragOffsetY = e.clientY - rect.top;
    document.addEventListener("mousemove", onMouseMove);
    document.addEventListener("mouseup", onMouseUp);
    e.preventDefault();
  });

  function onMouseMove(e) {
    if (!isDragging) return;
    const newLeft = e.clientX - dragOffsetX;
    const newTop = e.clientY - dragOffsetY;
    menuContainer.style.left = newLeft + "px";
    menuContainer.style.top = newTop + "px";
  }

  function onMouseUp() {
    isDragging = false;
    document.removeEventListener("mousemove", onMouseMove);
    document.removeEventListener("mouseup", onMouseUp);
  }
}

// https://discord.gg/NBN3jgQDGe

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址