Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * @name KBM AA
- * @description Emulates an Xbox controller
- * Press PageUp to open/close the settings menu.(entire script is made with ai except this top part)
- * improvements are mouse movement feels more normal and fixed deadzone making it feel weird also pls use builder pro and use pageup on your keyboard to open/close the GUI for customizing binds and sensitivity
- */
- (function() {
- 'use strict';
- // --- Primary Toggle ---
- const KBM_AA_ENABLED = true;
- // --- Default Configuration ---
- const DEFAULT_KEY_BINDS = {
- FIRE: 'mouse0', ADS: 't', JUMP: ' ', SPRINT: 'shift', CROUCH: 'control',
- RELOAD: 'r', USE: 'e', EDIT: 'g', WALL: 'z', RAMP: 'x', FLOOR: 'c', ROOF: 'v',
- };
- const DEFAULT_SENSITIVITY = { X: 8.5, Y: 8.5, ADS_MULTIPLIER: 85 };
- // --- "Virtual Cronus Zen" (Movement-Based Aim Assist) ---
- const VIRTUAL_ZEN_SETTINGS = {
- ENABLE_STRAFE_AIM_ASSIST: true, STRAFE_AIM_ASSIST_KEY: 'q', STRAFE_AIM_ASSIST_STRENGTH: 0.05,
- STRAFE_AIM_ASSIST_ADS_MULTIPLIER: 1.3, ENABLE_MOVEMENT_VERTICAL_AIM_ASSIST: true,
- FORWARD_AIM_DOWN_STRENGTH: 0.09, BACKWARD_AIM_UP_STRENGTH: 0.09, STRAFE_LOOK_STRENGTH: 0.10,
- };
- // --- Backend ---
- const ADVANCED = { POLLING_RATE_MS: 16, CONNECTION_DISPATCH_RATE_MS: 100, SENS_BASE_MULTIPLIER: 0.0018 };
- const CONTROLLER_BUTTON_MAP = {
- A: 0, B: 1, X: 2, Y: 3, LB: 4, RB: 5, LT: 6, RT: 7, L_STICK: 10, R_STICK: 11,
- };
- const BIND_ACTION_TO_BUTTON = {
- JUMP: CONTROLLER_BUTTON_MAP.A, EDIT: CONTROLLER_BUTTON_MAP.B, RELOAD: CONTROLLER_BUTTON_MAP.X,
- USE: CONTROLLER_BUTTON_MAP.X, WALL: CONTROLLER_BUTTON_MAP.RT, ADS: CONTROLLER_BUTTON_MAP.LT,
- RAMP: CONTROLLER_BUTTON_MAP.LT, ROOF: CONTROLLER_BUTTON_MAP.LB, FLOOR: CONTROLLER_BUTTON_MAP.RB,
- SPRINT: CONTROLLER_BUTTON_MAP.L_STICK, CROUCH: CONTROLLER_BUTTON_MAP.R_STICK,
- FIRE: CONTROLLER_BUTTON_MAP.RT,
- };
- // --- Script State ---
- let keyMap = {}, mouseMap = {}, currentBinds = {}, currentSens = {};
- const controllerState = {
- axes: [0.0, 0.0, 0.0, 0.0],
- buttons: Array(17).fill(false).map((_, i) => ({ pressed: false, touched: false, value: 0.0, index: i })),
- axisKeyPresses: { 0: { neg: false, pos: false }, 1: { neg: false, pos: false } },
- mouseDeltaX: 0, mouseDeltaY: 0, isConnected: true, timestamp: performance.now(),
- isAimAssistMacroActive: false,
- };
- let pointerLocked = false, stateIntervalId = null, connectionIntervalId = null, gameAreaElement = null;
- const originalGetGamepads = navigator.getGamepads?.bind(navigator);
- // --- Core Logic ---
- function generateMappings() {
- keyMap = {
- 'w': { t: 'a', a: 1, v: -1 }, 'a': { t: 'a', a: 0, v: -1 },
- 's': { t: 'a', a: 1, v: 1 }, 'd': { t: 'a', a: 0, v: 1 },
- };
- mouseMap = {};
- for (const action in currentBinds) {
- const key = currentBinds[action].toLowerCase();
- const buttonIndex = BIND_ACTION_TO_BUTTON[action];
- if (buttonIndex !== undefined) {
- if (key.startsWith('mouse')) {
- mouseMap[parseInt(key.replace('mouse', ''), 10)] = { t: 'b', i: buttonIndex };
- } else {
- keyMap[key] = { t: 'b', i: buttonIndex };
- }
- }
- }
- }
- function createGamepadObject() {
- return {
- axes: controllerState.axes, buttons: controllerState.buttons, connected: controllerState.isConnected,
- id: "Xbox Controller (XInput STANDARD GAMEPAD)", index: 0, mapping: "standard", timestamp: controllerState.timestamp,
- };
- }
- function updateAndSimulateGamepad() {
- let scriptSensX = currentSens.X * ADVANCED.SENS_BASE_MULTIPLIER, scriptSensY = currentSens.Y * ADVANCED.SENS_BASE_MULTIPLIER;
- const isADS = controllerState.buttons[BIND_ACTION_TO_BUTTON.ADS]?.pressed || false;
- if (isADS) { const m = currentSens.ADS_MULTIPLIER / 100; scriptSensX *= m; scriptSensY *= m; }
- let finalTargetRX = 0, finalTargetRY = 0;
- if (pointerLocked) {
- finalTargetRX = controllerState.mouseDeltaX * scriptSensX; finalTargetRY = controllerState.mouseDeltaY * scriptSensY;
- if (VIRTUAL_ZEN_SETTINGS.ENABLE_STRAFE_AIM_ASSIST && controllerState.isAimAssistMacroActive) {
- const s = VIRTUAL_ZEN_SETTINGS.STRAFE_AIM_ASSIST_STRENGTH * (isADS ? VIRTUAL_ZEN_SETTINGS.STRAFE_AIM_ASSIST_ADS_MULTIPLIER : 1);
- if (controllerState.axisKeyPresses[0].neg) finalTargetRX += s; else if (controllerState.axisKeyPresses[0].pos) finalTargetRX -= s;
- }
- if (VIRTUAL_ZEN_SETTINGS.ENABLE_MOVEMENT_VERTICAL_AIM_ASSIST) {
- if (controllerState.axisKeyPresses[1].neg) finalTargetRY += VIRTUAL_ZEN_SETTINGS.FORWARD_AIM_DOWN_STRENGTH;
- else if (controllerState.axisKeyPresses[1].pos) finalTargetRY -= VIRTUAL_ZEN_SETTINGS.BACKWARD_AIM_UP_STRENGTH;
- }
- if (controllerState.axisKeyPresses[0].neg) finalTargetRX += VIRTUAL_ZEN_SETTINGS.STRAFE_LOOK_STRENGTH;
- else if (controllerState.axisKeyPresses[0].pos) finalTargetRX -= VIRTUAL_ZEN_SETTINGS.STRAFE_LOOK_STRENGTH;
- controllerState.mouseDeltaX = 0; controllerState.mouseDeltaY = 0;
- }
- controllerState.axes[2] = Math.max(-1, Math.min(1, finalTargetRX));
- controllerState.axes[3] = Math.max(-1, Math.min(1, finalTargetRY));
- controllerState.timestamp = performance.now();
- }
- // --- Event Handlers (Unified and Bulletproofed) ---
- function handleKeyEvent(event, isDown) {
- if (event.key === 'PageUp' && isDown) { toggleUI(); return; }
- const gui = document.getElementById('kbm-aa-gui');
- if (gui && gui.style.display === 'flex') { if (event.key === 'Escape') { toggleUI(); } return; }
- const key = event.key.toLowerCase();
- if (key === VIRTUAL_ZEN_SETTINGS.STRAFE_AIM_ASSIST_KEY) {
- event.preventDefault(); event.stopPropagation();
- controllerState.isAimAssistMacroActive = isDown; return;
- }
- const mappedKey = (key.startsWith('control') ? 'control' : key);
- const mapping = keyMap[mappedKey];
- if (mapping) {
- event.preventDefault(); event.stopPropagation();
- if (mapping.t === 'b') {
- const button = controllerState.buttons[mapping.i];
- if (button.pressed !== isDown) { button.pressed = isDown; button.touched = isDown; button.value = isDown ? 1.0 : 0.0; }
- } else if (mapping.t === 'a') {
- const axisState = controllerState.axisKeyPresses[mapping.a];
- if (mapping.v < 0) axisState.neg = isDown; else axisState.pos = isDown;
- controllerState.axes[mapping.a] = axisState.neg ? -1 : (axisState.pos ? 1 : 0);
- }
- }
- }
- function handleMouseEvent(event, isDown) {
- const gui = document.getElementById('kbm-aa-gui');
- if (gui && gui.style.display === 'flex') return;
- const mapping = mouseMap[event.button];
- if (mapping) {
- event.preventDefault(); event.stopPropagation();
- if (!pointerLocked && isDown) return;
- const button = controllerState.buttons[mapping.i];
- if (button.pressed !== isDown) { button.pressed = isDown; button.touched = isDown; button.value = isDown ? 1.0 : 0.0; }
- }
- }
- function handleMouseMove(event) {
- const gui = document.getElementById('kbm-aa-gui');
- if (gui && gui.style.display === 'flex') return;
- if (pointerLocked) {
- controllerState.mouseDeltaX += event.movementX || 0;
- controllerState.mouseDeltaY += event.movementY || 0;
- }
- }
- function handlePointerLockChange() {
- pointerLocked = (document.pointerLockElement === gameAreaElement);
- if (!pointerLocked) {
- Object.assign(controllerState, { mouseDeltaX: 0, mouseDeltaY: 0, isAimAssistMacroActive: false });
- Object.values(mouseMap).forEach(m => { const b = controllerState.buttons[m.i]; b.pressed = b.touched = false; b.value = 0.0; });
- }
- }
- function requestPointerLock() {
- if (!pointerLocked) {
- gameAreaElement.requestPointerLock().catch(e => console.error("Pointer lock failed:", e));
- }
- }
- // --- GUI Functions ---
- function toggleUI() { const gui = document.getElementById('kbm-aa-gui'); if (gui) { gui.style.display = gui.style.display === 'flex' ? 'none' : 'flex'; } }
- function saveSettings() {
- for (const action in DEFAULT_KEY_BINDS) { currentBinds[action] = document.getElementById(`bind-${action}`).value; }
- currentSens.X = parseFloat(document.getElementById('sens-x').value);
- currentSens.Y = parseFloat(document.getElementById('sens-y').value);
- currentSens.ADS_MULTIPLIER = parseFloat(document.getElementById('sens-ads').value);
- localStorage.setItem('kbm-aa-binds', JSON.stringify(currentBinds));
- localStorage.setItem('kbm-aa-sens', JSON.stringify(currentSens));
- generateMappings();
- const saveButton = document.getElementById('kbm-aa-save-btn');
- saveButton.textContent = 'Saved!';
- setTimeout(() => { saveButton.textContent = 'Save and Close'; toggleUI(); }, 1000);
- }
- function loadSettings() {
- const savedBinds = localStorage.getItem('kbm-aa-binds'); const savedSens = localStorage.getItem('kbm-aa-sens');
- currentBinds = savedBinds ? JSON.parse(savedBinds) : { ...DEFAULT_KEY_BINDS };
- currentSens = savedSens ? JSON.parse(savedSens) : { ...DEFAULT_SENSITIVITY };
- }
- function createConfigUI() {
- if (document.getElementById('kbm-aa-gui')) return;
- let bindsHTML = '';
- for (const action in DEFAULT_KEY_BINDS) { bindsHTML += `<div class="kbm-aa-row"><label>${action}</label><input type="text" id="bind-${action}" value="${currentBinds[action] || ''}"></div>`; }
- const uiHTML = `<div id="kbm-aa-gui-content"><h2>KBM AA Settings</h2><p>Press PageUp to toggle menu. Settings are saved automatically.</p><div class="kbm-aa-section"><h3>Sensitivity</h3><div class="kbm-aa-row"><label>X Sensitivity (%)</label><input type="range" id="sens-x" min="1" max="30" step="0.1" value="${currentSens.X}"><span id="sens-x-val">${currentSens.X}</span></div><div class="kbm-aa-row"><label>Y Sensitivity (%)</label><input type="range" id="sens-y" min="1" max="30" step="0.1" value="${currentSens.Y}"><span id="sens-y-val">${currentSens.Y}</span></div><div class="kbm-aa-row"><label>ADS Multiplier (%)</label><input type="range" id="sens-ads" min="10" max="100" step="1" value="${currentSens.ADS_MULTIPLIER}"><span id="sens-ads-val">${currentSens.ADS_MULTIPLIER}</span></div></div><div class="kbm-aa-section"><h3>Key Binds</h3>${bindsHTML}</div><button id="kbm-aa-save-btn">Save and Close</button></div>`;
- const style = document.createElement('style');
- style.id = 'kbm-aa-style';
- style.textContent = `#kbm-aa-gui { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); justify-content: center; align-items: center; z-index: 99999; color: #fff; font-family: sans-serif; } #kbm-aa-gui-content { background: #1c1c1c; padding: 20px; border-radius: 8px; width: 400px; max-height: 80vh; overflow-y: auto; border: 1px solid #444; } .kbm-aa-section { margin-bottom: 20px; } .kbm-aa-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .kbm-aa-row label { flex-basis: 40%; } .kbm-aa-row input[type="text"] { width: 100px; padding: 5px; background: #333; border: 1px solid #555; color: #fff; border-radius: 4px; } .kbm-aa-row input[type="range"] { flex-grow: 1; } #kbm-aa-save-btn { width: 100%; padding: 10px; background: #5a9; border: none; color: #fff; border-radius: 4px; cursor: pointer; font-size: 16px; }`;
- document.head.appendChild(style);
- const guiContainer = document.createElement('div'); guiContainer.id = 'kbm-aa-gui'; guiContainer.innerHTML = uiHTML; document.body.appendChild(guiContainer);
- document.getElementById('kbm-aa-save-btn').addEventListener('click', saveSettings);
- document.getElementById('sens-x').addEventListener('input', (e) => { document.getElementById('sens-x-val').textContent = e.target.value; });
- document.getElementById('sens-y').addEventListener('input', (e) => { document.getElementById('sens-y-val').textContent = e.target.value; });
- document.getElementById('sens-ads').addEventListener('input', (e) => { document.getElementById('sens-ads-val').textContent = e.target.value; });
- }
- // --- Initialization & Shutdown ---
- function initialize() {
- gameAreaElement = document.getElementById('game-stream') || document.querySelector('video') || document.body;
- if (!gameAreaElement) { console.error("KBM AA Script: Could not find a suitable game element to attach to."); return; }
- loadSettings(); createConfigUI(); generateMappings();
- navigator.getGamepads = () => [createGamepadObject(), null, null, null];
- window.addEventListener('keydown', (e) => handleKeyEvent(e, true), true); window.addEventListener('keyup', (e) => handleKeyEvent(e, false), true);
- gameAreaElement.addEventListener('mousemove', handleMouseMove, true);
- gameAreaElement.addEventListener('mousedown', (e) => handleMouseEvent(e, true), true); gameAreaElement.addEventListener('mouseup', (e) => handleMouseEvent(e, false), true);
- document.addEventListener('pointerlockchange', handlePointerLockChange, false);
- gameAreaElement.addEventListener('click', requestPointerLock, false);
- stateIntervalId = setInterval(updateAndSimulateGamepad, ADVANCED.POLLING_RATE_MS);
- connectionIntervalId = setInterval(() => { window.dispatchEvent(new CustomEvent('gamepadconnected', { detail: { gamepad: createGamepadObject() } })) }, ADVANCED.CONNECTION_DISPATCH_RATE_MS);
- }
- window.stopKbmAa = function() {
- if (!stateIntervalId) return;
- clearInterval(stateIntervalId); clearInterval(connectionIntervalId); stateIntervalId = null; connectionIntervalId = null;
- // Listeners are now anonymous, so we can't remove them one by one. A page refresh is the cleanest way to stop.
- // For a true "stop", a more complex listener management system would be needed, but this prevents errors.
- if (originalGetGamepads) navigator.getGamepads = originalGetGamepads; else delete navigator.getGamepads;
- const gui = document.getElementById('kbm-aa-gui'); if (gui) gui.remove();
- const style = document.getElementById('kbm-aa-style'); if (style) style.remove();
- if (document.pointerLockElement) document.exitPointerLock();
- // The most reliable way to stop is to reload the page, but for a soft stop we just nullify the intervals.
- };
- if (KBM_AA_ENABLED) {
- if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(initialize, 500); }
- else { document.addEventListener('DOMContentLoaded', () => setTimeout(initialize, 500)); }
- }
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement