Загрузка данных


(function () {

  let teleportCoords = null;
  let guiOpen = false;
  let browser = null;

  let bindSaveKey = null;
  let bindTeleportKey = null;
  let bindAttachKey = null;
  let bindThrowKey = null;
  let bindTPToPlayerKey = null;
  let bindAAALoopKey = null;

  let espCarsEnabled = false;

  let menuPos = { x: 0.3, y: 0.3 };

  let currentTab = 'teleport';

  let attachedVehicles = [];
  let attachedTarget = null;

  let tpTarget = null;
  
  let savedAttachId = '';
  let savedTpId = '';
  let savedLoopTargetId = '';

  let spamActive = false;
  let loopTargetId = null;

  // Изменено с HOME (0x24) на F8 (0x77)
  const MENU_KEY = 0x77; // F8

  mp.keys.bind(MENU_KEY, true, () => {
    guiOpen ? closeMenu() : openMenu();
  });

  const ui = `
  <!DOCTYPE html><html><head><meta charset="utf-8">
  <style>
  *{box-sizing:border-box}
  html,body{margin:0;width:100%;height:100%;background:transparent;overflow:hidden;font-family:Consolas}
  *{user-select:none;-webkit-user-select:none;-ms-user-select:none;-moz-user-select:none;}
  body{ -webkit-touch-callout:none; -webkit-user-drag:none; }

  #win{
    position:absolute;
    width:520px;
    height:350px;
    background:#0b0b0b;
    color:#fff;
    border-radius:8px;
    border:1px solid #2a2a2a;
    display:flex;

    opacity:0;
    transform:scale(0.8);
    transition: opacity 250ms ease, transform 250ms ease;
  }

  #win.open{
    opacity:1;
    transform:scale(1);
  }

  #sidebar{width:120px;background:#0f0f0f;border-right:1px solid #2a2a2a}
  .side-tab{padding:12px;text-align:center;cursor:pointer;opacity:.6;border-bottom:1px solid #2a2a2a}
  .side-tab.active{background:#1e3a8a;opacity:1}
  #content{flex:1;padding:10px}
  #head{display:flex;align-items:center;cursor:move;user-select:none;margin-bottom:10px}
  #head svg{margin-right:6px}
  .row{display:flex;align-items:center;margin-bottom:10px}
  .label{flex:1}
  input{background:#111;color:#fff;border:1px solid #333;padding:4px 10px;width:170px;text-align:center;cursor:pointer}
  .section{display:none}
  .section.active{display:block}
  .toggle-on{background:#1e3a8a}

  .note{
    font-size:11px;
    opacity:0.6;
    margin-top:6px;
  }
  </style>
  </head>
  <body>

  <div id="win">
    <div id="sidebar">
      <div class="side-tab active" onclick="setTab('teleport')">Телепорт</div>
      <div class="side-tab" onclick="setTab('attach')">Приклеить</div>
      <div class="side-tab" onclick="setTab('extra')">Телепорт на игрока</div>
      <div class="side-tab" onclick="setTab('slapper')">Слаппер</div>
    </div>

    <div id="content">
      <div id="head">
        <svg width="22" height="22" viewBox="0 0 45 48" fill="white">
          <path d="M4.6875 35.5L0 43H45L40.3125 35.5H22.5H4.6875Z"/>
          <path d="M14 14L5 5V24L13 32H25L14 21V14Z"/>
          <path d="M31 14L40 5V24L32 32L30 32L25 27L31 21V14Z"/>
          <path d="M18 19.5L22.5 24L27 19.5V12.5L22.5 8L18 12.5V19.5Z"/>
        </svg>
        <b>menu vehicle</b>
      </div>

      <div id="teleport" class="section active">

        <div class="row">
          <div class="label">ESP</div>
          <input id="espCars" readonly onselectstart="return false" onmousedown="return false" value="Выключено" onclick="toggleESP()">
        </div>

        <div class="row">
          <div class="label">Сохранить координаты</div>
          <input id="bindSave" readonly onselectstart="return false" onmousedown="return false" onclick="listenKey('save')">
        </div>

        <div class="row">
          <div class="label">Телепорт машин</div>
          <input id="bindTeleport" readonly onselectstart="return false" onmousedown="return false" onclick="listenKey('teleport')">
        </div>

        <div class="row">
          <div class="label">Подбрасывание машин</div>
          <input id="bindThrow" readonly onselectstart="return false" onmousedown="return false" onclick="listenKey('throw')">
        </div>

        <div class="row">
          <div class="label">Удалить все бинды</div>
          <input id="resetBinds" readonly onselectstart="return false" onmousedown="return false" value="СБРОСИТЬ" onclick="resetBinds()">
        </div>
      </div>

      <div id="attach" class="section">
        <div class="row">
          <div class="label">ID игрока</div>
          <input id="targetId" value="" placeholder="Введите ID" oninput="setTarget(this.value)">
        </div>

        <div class="row">
          <div class="label">Бинд приклеить</div>
          <input id="bindAttach" readonly onselectstart="return false" onmousedown="return false" onclick="listenKey('attach')">
        </div>

        <div class="note">Машина приклеивается к игроку</div>
      </div>

      <div id="extra" class="section">
        <div class="row">
          <div class="label">ID игрока</div>
          <input id="tpId" value="" placeholder="Введите ID" oninput="setTpTarget(this.value)">
        </div>

        <div class="row">
          <div class="label">Бинд телепорта к игроку</div>
          <input id="bindTPToPlayer" readonly onselectstart="return false" onmousedown="return false" onclick="listenKey('tpto')">
        </div>

        <div class="note">Машина телепортируется на игрока</div>
      </div>

      <div id="slapper" class="section">
        <div class="row">
          <div class="label">ID игрока</div>
          <input id="loopTargetId" value="" placeholder="Введите ID" oninput="setLoopTarget(this.value)">
        </div>

        <div class="row">
          <div class="label">Бинд вкл/выкл</div>
          <input id="bindAAALoop" readonly onselectstart="return false" onmousedown="return false" onclick="listenKey('aaaloop')">
        </div>

      </div>

    </div>
  </div>

  <script>
  const w = win;
  const h = head;
  let drag=false, ox=0, oy=0;
  let listening=null;

  function setTab(t){
    document.querySelectorAll('.side-tab').forEach(e=>e.classList.remove('active'));
    document.querySelectorAll('.section').forEach(e=>e.classList.remove('active'));
    document.querySelector('[onclick="setTab(\\''+t+'\\')"]').classList.add('active');
    document.getElementById(t).classList.add('active');

    mp.trigger('menu:setTab', t);
  }

  window.setBind=(t,n)=>{
    if(t==='save') bindSave.value=n;
    if(t==='teleport') bindTeleport.value=n;
    if(t==='attach') bindAttach.value=n;
    if(t==='throw') bindThrow.value=n;
    if(t==='tpto') bindTPToPlayer.value=n;
    if(t==='aaaloop') bindAAALoop.value=n;
  };

  window.setESP=(state)=>{
    espCars.value = state ? 'Включено' : 'Выключено';
    espCars.className = state ? 'toggle-on' : '';
  };

  window.toggleESP=()=>{
    mp.trigger('menu:toggleESP');
  };

  window.setPos=(x,y)=>{
    w.style.left=(innerWidth*x)+'px';
    w.style.top=(innerHeight*y)+'px';
  };

  window.listenKey=t=>{
    listening=t;
    if(t==='save') bindSave.value='НАЖМИ КЛАВИШУ';
    if(t==='teleport') bindTeleport.value='НАЖМИ КЛАВИШУ';
    if(t==='attach') bindAttach.value='НАЖМИ КЛАВИШУ';
    if(t==='throw') bindThrow.value='НАЖМИ КЛАВИШУ';
    if(t==='tpto') bindTPToPlayer.value='НАЖМИ КЛАВИШУ';
    if(t==='aaaloop') bindAAALoop.value='НАЖМИ КЛАВИШУ';
  };

  window.resetBinds=()=>{
    mp.trigger('menu:resetBinds');
  };

  window.setTarget=(id)=>{
    mp.trigger('attach:setTarget', id);
  };

  window.setTpTarget=(id)=>{
    mp.trigger('tpto:setTarget', id);
  };
  
  window.setLoopTarget=(id)=>{
    mp.trigger('slapper:setLoopTarget', id);
  };

  document.onkeydown=e=>{
    if(!listening) return;
    if(e.key === 'F8' || e.key === 'Escape'){ listening=null; return; }

    let name=e.key.toUpperCase();
    if(name===' ')name='SPACE';
    if(name==='CONTROL')name='CTRL';
    if(name==='SHIFT')name='SHIFT';
    if(name==='ALT')name='ALT';

    mp.trigger('menu:setBind',listening,e.keyCode,name);
    listening=null;
  };

  h.onmousedown=e=>{
    drag=true;
    ox=e.clientX-w.offsetLeft;
    oy=e.clientY-w.offsetTop;
  };
  document.onmouseup=()=>drag=false;
  document.onmousemove=e=>{
    if(drag){
      w.style.left=e.clientX-ox+'px';
      w.style.top=e.clientY-oy+'px';
      mp.trigger('menu:savePos',w.offsetLeft/innerWidth,w.offsetTop/innerHeight);
    }
  };

  document.addEventListener('contextmenu', event => event.preventDefault());
  </script>
  </body></html>
  `;

  function openMenu(){
    if(browser) return;
    browser = mp.browsers.new("data:text/html,"+encodeURIComponent(ui));
    guiOpen = true;
    mp.gui.cursor.show(true,true);

    setTimeout(()=>{
      browser.execute(`setBind('save','${getKeyName(bindSaveKey)}')`);
      browser.execute(`setBind('teleport','${getKeyName(bindTeleportKey)}')`);
      browser.execute(`setBind('attach','${getKeyName(bindAttachKey)}')`);
      browser.execute(`setBind('throw','${getKeyName(bindThrowKey)}')`);
      browser.execute(`setBind('tpto','${getKeyName(bindTPToPlayerKey)}')`);
      browser.execute(`setBind('aaaloop','${getKeyName(bindAAALoopKey)}')`);
      browser.execute(`setESP(${espCarsEnabled})`);
      browser.execute(`setPos(${menuPos.x},${menuPos.y})`);
      browser.execute(`document.getElementById('win').classList.add('open');`);
      browser.execute(`setTab('${currentTab}');`);
      
      browser.execute(`
        if (document.getElementById('targetId')) document.getElementById('targetId').value = '${savedAttachId}';
        if (document.getElementById('tpId')) document.getElementById('tpId').value = '${savedTpId}';
        if (document.getElementById('loopTargetId')) document.getElementById('loopTargetId').value = '${savedLoopTargetId}';
      `);
    },50);
  }

  function closeMenu(){
    if(!browser) return;

    browser.execute(`document.getElementById('win').classList.remove('open');`);

    setTimeout(()=>{
      browser.destroy();
      browser=null;
      guiOpen=false;
      mp.gui.cursor.show(false,false);
    }, 250);
  }

  function rebind(){
    if(bindSaveKey) mp.keys.unbind(bindSaveKey,true);
    if(bindTeleportKey) mp.keys.unbind(bindTeleportKey,true);
    if(bindAttachKey) mp.keys.unbind(bindAttachKey,true);
    if(bindThrowKey) mp.keys.unbind(bindThrowKey,true);
    if(bindTPToPlayerKey) mp.keys.unbind(bindTPToPlayerKey,true);
    if(bindAAALoopKey) mp.keys.unbind(bindAAALoopKey,true);

    if(bindSaveKey) mp.keys.bind(bindSaveKey,true,() => { if(!guiOpen) saveCoords(); });
    if(bindTeleportKey) mp.keys.bind(bindTeleportKey,true,() => { if(!guiOpen) teleportCars(); });
    if(bindAttachKey) mp.keys.bind(bindAttachKey,true,() => { if(!guiOpen) attachCars(); });
    if(bindThrowKey) mp.keys.bind(bindThrowKey,true,() => { if(!guiOpen) throwCars(); });
    if(bindTPToPlayerKey) mp.keys.bind(bindTPToPlayerKey,true,() => { if(!guiOpen) teleportCarsToPlayer(); });
    if(bindAAALoopKey) mp.keys.bind(bindAAALoopKey,true,() => { if(!guiOpen) toggleSpam(); });
  }
  rebind();

  function saveCoords(){
    teleportCoords = mp.players.local.position;
    mp.gui.chat.push("Координаты сохранены");
  }

  function teleportCars(){
    if(!teleportCoords)
      return mp.gui.chat.push("Сначала сохраните координаты");

    let count = 0;
    const p = mp.players.local.position;

    mp.vehicles.forEachInStreamRange(v=>{
      if(!v.controller || v.controller.remoteId !== mp.players.local.remoteId) return;

      if(mp.dist(p.x,p.y,p.z,v.position.x,v.position.y,v.position.z) <= 380){
        v.setCoordsNoOffset(
          teleportCoords.x,
          teleportCoords.y,
          teleportCoords.z,
          false,false,false
        );
        count++;
      }
    });

    mp.gui.chat.push(`Машины телепортированы (${count})`);
  }

  function attachCars(){
    if (!attachedTarget || !mp.players.exists(attachedTarget)) {
      mp.gui.chat.push("Сначала выбери цель через ввод ID.");
      return;
    }

    const player = mp.players.local;
    const headBone = attachedTarget.getBoneIndex(12844);

    mp.vehicles.forEachInStreamRange(vehicle => {
      if (!vehicle || !mp.vehicles.exists(vehicle)) return;

      if (vehicle.controller && vehicle.controller.remoteId === player.remoteId) {
        if (attachedVehicles.includes(vehicle)) return;

        vehicle.attachTo(
          attachedTarget.handle,
          headBone,
          0, 0, 0.5,
          0, 0, 0,
          false, false, false, false,
          2, true
        );

        attachedVehicles.push(vehicle);
      }
    });

    mp.gui.chat.push(`Приклеено: ${attachedVehicles.length}`);
  }

  function throwCars(){
    const player = mp.players.local;
    const playerPos = player.position;
    const radius = 380.0;
    let count = 0;

    mp.vehicles.forEachInStreamRange(veh => {
      if (!veh.controller || veh.controller.remoteId !== player.remoteId) return;

      const dist = mp.game.gameplay.getDistanceBetweenCoords(
        playerPos.x, playerPos.y, playerPos.z,
        veh.position.x, veh.position.y, veh.position.z,
        true
      );

      if (dist <= radius) {
        veh.setVelocity(0, 0, 70);
        count++;
      }
    });

    mp.gui.chat.push(`Подброшено машин: ${count}`);
  }

  function teleportCarsToPlayer(){
    if (!tpTarget || !mp.players.exists(tpTarget)) {
      mp.gui.chat.push("Игрок не найден (ID не в стриме или не существует).");
      return;
    }

    const player = mp.players.local;
    const playerPos = player.position;
    const radius = 380.0;
    let count = 0;

    const targetPos = tpTarget.position;

    mp.vehicles.forEachInStreamRange(veh => {
      if (!veh.controller || veh.controller.remoteId !== player.remoteId) return;

      const dist = mp.game.gameplay.getDistanceBetweenCoords(
        playerPos.x, playerPos.y, playerPos.z,
        veh.position.x, veh.position.y, veh.position.z,
        true
      );

      if (dist <= radius) {
        veh.setCoordsNoOffset(targetPos.x, targetPos.y, targetPos.z + 1, false, false, false);
        count++;
      }
    });

    mp.gui.chat.push(`Телепортировано машин: ${count}`);
  }

  function toggleSpam(){
    spamActive = !spamActive;
    mp.gui.chat.push(spamActive ? "Слаппер включен" : "Слаппер выключен");
  }

  const drawCarsESP = () => {
    const p = mp.players.local.position;

    mp.vehicles.forEachInStreamRange(v=>{
      if(!v.controller || v.controller.remoteId !== mp.players.local.remoteId) return;

      if(mp.dist(p.x,p.y,p.z,v.position.x,v.position.y,v.position.z) < 380){
        mp.game.graphics.drawText(
          "TP",
          [v.position.x, v.position.y, v.position.z],
          { font:4, color:[255,255,255,255], scale:[0.35,0.35], outline:true }
        );
      }
    });
  };

  mp.events.add("render", () => {
    if(espCarsEnabled) drawCarsESP();

    if (!spamActive) return;

    const targetPlayer = mp.players.atRemoteId(loopTargetId);
    if (!targetPlayer) return;

    let controlledVehicle = null;

    mp.vehicles.forEach(vehicle => {
        if (vehicle.controller &&
            vehicle.controller.remoteId === mp.players.local.remoteId) {
            controlledVehicle = vehicle;
        }
    });

    if (!controlledVehicle) return;

    const pos = targetPlayer.position;

    controlledVehicle.setCoordsNoOffset(
        pos.x,
        pos.y,
        pos.z - 3,
        false,
        false,
        false
    );

    controlledVehicle.setVelocity(0, 0, 70);
  });

  mp.events.add('menu:setBind',(type,keyCode,keyName)=>{
    if(type==='save') bindSaveKey = keyCode;
    if(type==='teleport') bindTeleportKey = keyCode;
    if(type==='attach') bindAttachKey = keyCode;
    if(type==='throw') bindThrowKey = keyCode;
    if(type==='tpto') bindTPToPlayerKey = keyCode;
    if(type==='aaaloop') bindAAALoopKey = keyCode;

    rebind();
    browser?.execute(`setBind('${type}','${keyName}')`);
  });

  mp.events.add('menu:toggleESP',()=>{
    espCarsEnabled = !espCarsEnabled;
    browser?.execute(`setESP(${espCarsEnabled})`);
    mp.gui.chat.push(espCarsEnabled ? 'Включено' : 'Выключено');
  });

  mp.events.add('menu:setTab',(tab)=>{
    currentTab = tab;
  });

  mp.events.add('menu:savePos',(x,y)=>{ menuPos={x,y}; });

  mp.events.add('menu:resetBinds',()=>{
    if(bindSaveKey) mp.keys.unbind(bindSaveKey,true);
    if(bindTeleportKey) mp.keys.unbind(bindTeleportKey,true);
    if(bindAttachKey) mp.keys.unbind(bindAttachKey,true);
    if(bindThrowKey) mp.keys.unbind(bindThrowKey,true);
    if(bindTPToPlayerKey) mp.keys.unbind(bindTPToPlayerKey,true);
    if(bindAAALoopKey) mp.keys.unbind(bindAAALoopKey,true);

    bindSaveKey = null;
    bindTeleportKey = null;
    bindAttachKey = null;
    bindThrowKey = null;
    bindTPToPlayerKey = null;
    bindAAALoopKey = null;

    browser?.execute(`setBind('save','---')`);
    browser?.execute(`setBind('teleport','---')`);
    browser?.execute(`setBind('attach','---')`);
    browser?.execute(`setBind('throw','---')`);
    browser?.execute(`setBind('tpto','---')`);
    browser?.execute(`setBind('aaaloop','---')`);

    mp.gui.chat.push("Все пользовательские бинды удалены");
  });

  mp.events.add('attach:setTarget', (id) => {
    savedAttachId = id;
    const targetId = parseInt(id);
    if (isNaN(targetId)) return;

    const target = mp.players.atRemoteId(targetId);
    if (!target || !mp.players.exists(target)) return;

    attachedTarget = target;
  });

  mp.events.add('tpto:setTarget', (id) => {
    savedTpId = id;
    const targetId = parseInt(id);
    if (isNaN(targetId)) return;

    const target = mp.players.toArray().find(p => p.remoteId === targetId);
    if (!target || !mp.players.exists(target)) return;

    tpTarget = target;
  });
  
  mp.events.add('slapper:setLoopTarget', (id) => {
    savedLoopTargetId = id;
    const targetId = parseInt(id);
    if (isNaN(targetId)) return;
    
    loopTargetId = targetId;
  });

  function getKeyName(code){
    if(!code) return '---';
    if(code>=48 && code<=57) return String.fromCharCode(code);
    if(code>=65 && code<=90) return String.fromCharCode(code);
    const f={0x70:'F1',0x71:'F2',0x72:'F3',0x73:'F4',0x74:'F5',
             0x75:'F6',0x76:'F7',0x77:'F8',0x78:'F9',0x79:'F10',
             0x7A:'F11',0x7B:'F12'};
    return f[code]||'KEY';
  }

})();