From fcf859046e1bd6039799acc4df7869e7c60c6c00 Mon Sep 17 00:00:00 2001 From: iDisaster <96336276+iDisaster@users.noreply.github.com> Date: Sun, 18 Jan 2026 20:37:49 +0400 Subject: [PATCH] Add files via upload --- Trident/menu.js | 889 ++++++++++++++++++++++++++++++++++++++++++++ Trident/player.js | 508 +++++++++++++++++++++++++ Trident/teleport.js | 276 ++++++++++++++ Trident/vehicle.js | 604 ++++++++++++++++++++++++++++++ Trident/weapon.js | 286 ++++++++++++++ Trident/world.js | 488 ++++++++++++++++++++++++ 6 files changed, 3051 insertions(+) create mode 100644 Trident/menu.js create mode 100644 Trident/player.js create mode 100644 Trident/teleport.js create mode 100644 Trident/vehicle.js create mode 100644 Trident/weapon.js create mode 100644 Trident/world.js diff --git a/Trident/menu.js b/Trident/menu.js new file mode 100644 index 0000000..dd4d988 --- /dev/null +++ b/Trident/menu.js @@ -0,0 +1,889 @@ +/** + * MD TRIDENT Menu - GTAConnected Port + * Original by DEVILSDESIGN, IIV_NATHAN_VII, SHOCKixiXixiWAVE + * Ported for GTA IV GTAConnected Server + */ + +// ============================================================================ +// MENU CONFIGURATION & CONSTANTS +// ============================================================================ + +const MENU_CONFIG = { + // Menu Position + posX: 0.695, + posY: 0.155, + + // Menu Dimensions + width: 0.25, + itemHeight: 0.028, + headerHeight: 0.067, + + // Max items visible + maxVisibleItems: 12, + startScrolling: 8, + + // Colors (RGBA) + colors: { + background: [70, 130, 180, 180], // Steel Blue + header: [164, 134, 35, 255], // Gold + subHeader: [58, 95, 205, 255], // Royal Blue + item: [180, 180, 180, 255], // Gray + itemHighlight: [255, 143, 0, 255], // Orange + scrollbar: [100, 100, 200, 150], // Light Blue + line: [255, 255, 255, 255], // White + bool: [255, 128, 0, 255], // Orange + submenu: [139, 134, 130, 255], // Gray + jumpover: [58, 95, 205, 255], // Blue + error: [177, 19, 26, 255], // Red + boolOn: [0, 204, 0, 255], // Green + boolOff: [204, 0, 0, 255], // Red + }, + + // Text Sizes + textSize: { + header: 0.45, + subHeader: 0.32, + item: 0.35, + version: 0.95 + }, + + // Header text + headerText: "TRIDENT", + subHeaderText: "MD EXTEND+ v13", + versionText: "MD" +}; + +// ============================================================================ +// MENU ITEM TYPES +// ============================================================================ + +const ITEM_TYPE = { + SUBMENU: 1, + FUNCTION: 2, + BOOL: 3, + VALUE_NUM: 4, + VALUE_STRING: 5, + VEHICLE: 6, + PLAYER: 7, + JUMPOVER: 8, + ERROR: 9, + NOT_PRESENT: 10 +}; + +// ============================================================================ +// MENU STATE +// ============================================================================ + +let menuState = { + isOpen: false, + currentLevel: 0, + selectedIndex: 0, + scrollOffset: 0, + items: [], + menuStack: [], + lastSelected: [], + glowValue: 0, + glowIncrement: true, + flashValue: 255, + flashIncrement: false, + + // Player selection for network options + selectedPlayer: null, + + // Input state + inputCooldown: 0, + holdCounter: 0, + pressCounter: 2, + pressMultiplier: 1 +}; + +// ============================================================================ +// MENU ITEMS DATA +// ============================================================================ + +function createMenuItem(name, type, options = {}) { + return { + name: name, + type: type, + action: options.action || null, + submenu: options.submenu || null, + value: options.value !== undefined ? options.value : 0, + maxValue: options.maxValue || 0, + minValue: options.minValue || 0, + boolState: options.boolState || false, + stringValues: options.stringValues || [], + vehicleModel: options.vehicleModel || 0, + playerId: options.playerId || -1 + }; +} + +// ============================================================================ +// MAIN MENU STRUCTURE +// ============================================================================ + +function getMainMenuItems() { + return [ + createMenuItem("Player Options", ITEM_TYPE.SUBMENU, { submenu: "player" }), + createMenuItem("Network Options", ITEM_TYPE.SUBMENU, { submenu: "network" }), + createMenuItem("Vehicle Garage", ITEM_TYPE.SUBMENU, { submenu: "vehicle" }), + createMenuItem("Weapon Options", ITEM_TYPE.SUBMENU, { submenu: "weapon" }), + createMenuItem("Teleport Options", ITEM_TYPE.SUBMENU, { submenu: "teleport" }), + createMenuItem("Weather / Time", ITEM_TYPE.SUBMENU, { submenu: "weather" }), + createMenuItem("Model Changer", ITEM_TYPE.SUBMENU, { submenu: "model" }), + createMenuItem("Animations", ITEM_TYPE.SUBMENU, { submenu: "animation" }), + createMenuItem("Object Spawner", ITEM_TYPE.SUBMENU, { submenu: "objects" }), + createMenuItem("~~ M E N U S E T T I N G S ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Menu Settings", ITEM_TYPE.SUBMENU, { submenu: "settings" }), + createMenuItem("~~ C R E D I T S ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Credits", ITEM_TYPE.SUBMENU, { submenu: "credits" }) + ]; +} + +// ============================================================================ +// DRAWING FUNCTIONS +// ============================================================================ + +function drawRect(x, y, width, height, r, g, b, a) { + natives.DRAW_RECT(x, y, width, height, r, g, b, a); +} + +function drawText(text, x, y, size, r, g, b, a, centered = false, rightJustify = false) { + natives.SET_TEXT_FONT(0); + natives.SET_TEXT_SCALE(size, size); + natives.SET_TEXT_COLOUR(r, g, b, a); + + if (centered) { + natives.SET_TEXT_CENTRE(true); + } + if (rightJustify) { + natives.SET_TEXT_RIGHT_JUSTIFY(true); + natives.SET_TEXT_WRAP(0.0, x); + } + + natives.SET_TEXT_DROPSHADOW(0, 0, 0, 0, 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(x, y, "STRING", text); +} + +function setupDraw(sizeX, sizeY, r, g, b, a) { + natives.SET_TEXT_FONT(0); + natives.SET_TEXT_SCALE(sizeX, sizeY); + natives.SET_TEXT_COLOUR(r, g, b, a); + natives.SET_TEXT_DROPSHADOW(0, 0, 0, 0, 255); +} + +// ============================================================================ +// MENU RENDERING +// ============================================================================ + +function renderMenu() { + if (!menuState.isOpen) return; + + updateEffects(); + + let posX = MENU_CONFIG.posX; + let posY = MENU_CONFIG.posY; + let width = MENU_CONFIG.width; + + // Calculate window height based on visible items + let visibleCount = Math.min(menuState.items.length, MENU_CONFIG.maxVisibleItems); + let windowHeight = MENU_CONFIG.headerHeight + (visibleCount * MENU_CONFIG.itemHeight) + 0.02; + + // Draw background window + let bgColor = MENU_CONFIG.colors.background; + drawRect( + posX + width / 2, + posY + windowHeight / 2, + width, + windowHeight, + bgColor[0], bgColor[1], bgColor[2], bgColor[3] + ); + + // Draw header + renderHeader(posX, posY); + + // Draw separator line + let lineY = posY + MENU_CONFIG.headerHeight; + drawRect( + posX + width / 2, + lineY, + width, + 0.002, + MENU_CONFIG.colors.line[0], + MENU_CONFIG.colors.line[1], + MENU_CONFIG.colors.line[2], + MENU_CONFIG.colors.line[3] + ); + + // Draw items + renderItems(posX, lineY + 0.01); + + // Draw scroll indicators if needed + if (menuState.items.length > MENU_CONFIG.maxVisibleItems) { + renderScrollIndicators(posX, posY, windowHeight); + } + + // Draw helper text at bottom + renderHelperText(); +} + +function renderHeader(x, y) { + let headerColor = MENU_CONFIG.colors.header; + let subHeaderColor = MENU_CONFIG.colors.subHeader; + + // MD Text (version prefix) + setupDraw(0.42, 0.95, subHeaderColor[0], subHeaderColor[1], subHeaderColor[2], 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(x + 0.02, y + 0.005, "STRING", MENU_CONFIG.versionText); + + // Header Text (TRIDENT) + setupDraw(0.303, 0.45, headerColor[0], headerColor[1], headerColor[2], menuState.flashValue); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(x + 0.055, y + 0.01, "STRING", MENU_CONFIG.headerText); + + // Sub Header (version/description) + setupDraw(0.2, 0.32, subHeaderColor[0], subHeaderColor[1], subHeaderColor[2], 255); + natives.SET_TEXT_CENTRE(true); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(x + MENU_CONFIG.width / 2, y + 0.04, "STRING", MENU_CONFIG.subHeaderText); +} + +function renderItems(startX, startY) { + let items = menuState.items; + let scrollOffset = menuState.scrollOffset; + let selectedIndex = menuState.selectedIndex; + + let visibleCount = Math.min(items.length, MENU_CONFIG.maxVisibleItems); + let itemY = startY; + + for (let i = 0; i < visibleCount; i++) { + let itemIndex = scrollOffset + i; + if (itemIndex >= items.length) break; + + let item = items[itemIndex]; + let isSelected = (itemIndex === selectedIndex); + + // Draw selection highlight + if (isSelected) { + drawRect( + startX + MENU_CONFIG.width / 2, + itemY + MENU_CONFIG.itemHeight / 2, + MENU_CONFIG.width, + MENU_CONFIG.itemHeight, + menuState.glowValue, + menuState.glowValue, + 200, + 150 + ); + } + + // Render item based on type + renderItem(item, startX, itemY, isSelected); + + itemY += MENU_CONFIG.itemHeight; + } +} + +function renderItem(item, x, y, isSelected) { + let textX = x + 0.02; + let textY = y + 0.003; + + let color; + let text = item.name; + + switch (item.type) { + case ITEM_TYPE.SUBMENU: + color = isSelected ? MENU_CONFIG.colors.itemHighlight : MENU_CONFIG.colors.submenu; + setupDraw(0.19, 0.35, color[0], color[1], color[2], 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(textX, textY, "STRING", "MD " + text + " >>"); + break; + + case ITEM_TYPE.FUNCTION: + color = isSelected ? MENU_CONFIG.colors.itemHighlight : MENU_CONFIG.colors.item; + setupDraw(0.19, 0.35, color[0], color[1], color[2], 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(textX, textY, "STRING", text); + break; + + case ITEM_TYPE.BOOL: + color = item.boolState ? MENU_CONFIG.colors.boolOn : MENU_CONFIG.colors.boolOff; + if (isSelected) color = MENU_CONFIG.colors.itemHighlight; + setupDraw(0.19, 0.35, color[0], color[1], color[2], 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(textX, textY, "STRING", text); + + // Draw ON/OFF indicator + let stateText = item.boolState ? "ON" : "OFF"; + let stateColor = item.boolState ? MENU_CONFIG.colors.boolOn : MENU_CONFIG.colors.boolOff; + setupDraw(0.19, 0.35, stateColor[0], stateColor[1], stateColor[2], 255); + natives.SET_TEXT_RIGHT_JUSTIFY(true); + natives.SET_TEXT_WRAP(0.0, x + MENU_CONFIG.width - 0.02); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(0.0, textY, "STRING", stateText); + break; + + case ITEM_TYPE.VALUE_NUM: + color = isSelected ? MENU_CONFIG.colors.itemHighlight : MENU_CONFIG.colors.item; + setupDraw(0.19, 0.35, color[0], color[1], color[2], 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(textX, textY, "STRING", text); + + // Draw value + setupDraw(0.19, 0.35, 255, 255, 255, 255); + natives.SET_TEXT_RIGHT_JUSTIFY(true); + natives.SET_TEXT_WRAP(0.0, x + MENU_CONFIG.width - 0.02); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(0.0, textY, "STRING", "< " + item.value.toString() + " >"); + break; + + case ITEM_TYPE.VALUE_STRING: + color = isSelected ? MENU_CONFIG.colors.itemHighlight : MENU_CONFIG.colors.item; + setupDraw(0.19, 0.35, color[0], color[1], color[2], 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(textX, textY, "STRING", text); + + // Draw string value + let strValue = item.stringValues[item.value] || "None"; + setupDraw(0.19, 0.35, 255, 255, 255, 255); + natives.SET_TEXT_RIGHT_JUSTIFY(true); + natives.SET_TEXT_WRAP(0.0, x + MENU_CONFIG.width - 0.02); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(0.0, textY, "STRING", "< " + strValue + " >"); + break; + + case ITEM_TYPE.VEHICLE: + color = isSelected ? MENU_CONFIG.colors.itemHighlight : MENU_CONFIG.colors.item; + setupDraw(0.19, 0.35, color[0], color[1], color[2], 255); + // Get vehicle display name + let vehName = natives.GET_DISPLAY_NAME_FROM_VEHICLE_MODEL(item.vehicleModel); + let displayName = natives.GET_STRING_FROM_TEXT_FILE(vehName) || text; + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(textX, textY, "STRING", displayName); + break; + + case ITEM_TYPE.PLAYER: + // Get player color + let playerColor = getPlayerColor(item.playerId); + if (isSelected) playerColor = MENU_CONFIG.colors.itemHighlight; + setupDraw(0.19, 0.35, playerColor[0], playerColor[1], playerColor[2], 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(textX, textY, "STRING", text); + break; + + case ITEM_TYPE.JUMPOVER: + color = MENU_CONFIG.colors.jumpover; + setupDraw(0.21, 0.385, color[0], color[1], color[2], menuState.flashValue); + natives.SET_TEXT_CENTRE(true); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(x + MENU_CONFIG.width / 2, textY, "STRING", text); + break; + + case ITEM_TYPE.ERROR: + color = MENU_CONFIG.colors.error; + setupDraw(0.19, 0.35, color[0], color[1], menuState.glowValue, 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(textX, textY, "STRING", text); + break; + + case ITEM_TYPE.NOT_PRESENT: + color = MENU_CONFIG.colors.error; + setupDraw(0.19, 0.35, color[0], menuState.glowValue, menuState.glowValue, 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(textX, textY, "STRING", text + " (N/A)"); + break; + + default: + color = MENU_CONFIG.colors.item; + setupDraw(0.19, 0.35, color[0], color[1], color[2], 255); + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(textX, textY, "STRING", text); + } +} + +function renderScrollIndicators(x, y, height) { + // Draw scroll position indicator + let totalItems = menuState.items.length; + let visibleItems = MENU_CONFIG.maxVisibleItems; + let scrollOffset = menuState.scrollOffset; + + let scrollBarHeight = height - MENU_CONFIG.headerHeight - 0.04; + let scrollThumbHeight = (visibleItems / totalItems) * scrollBarHeight; + let scrollThumbY = y + MENU_CONFIG.headerHeight + 0.02 + (scrollOffset / (totalItems - visibleItems)) * (scrollBarHeight - scrollThumbHeight); + + // Draw scroll track + drawRect( + x + MENU_CONFIG.width - 0.008, + y + MENU_CONFIG.headerHeight + scrollBarHeight / 2, + 0.004, + scrollBarHeight, + 50, 50, 50, 150 + ); + + // Draw scroll thumb + drawRect( + x + MENU_CONFIG.width - 0.008, + scrollThumbY + scrollThumbHeight / 2, + 0.004, + scrollThumbHeight, + MENU_CONFIG.colors.header[0], + MENU_CONFIG.colors.header[1], + MENU_CONFIG.colors.header[2], + 255 + ); +} + +function renderHelperText() { + let y = 0.92; + + setupDraw(0.15, 0.28, 255, 255, 255, 200); + + if (menuState.currentLevel === 0) { + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(0.3, y, "STRING", "UP/DOWN: Navigate | ENTER: Select | BACKSPACE: Close"); + } else { + natives.DISPLAY_TEXT_WITH_LITERAL_STRING(0.3, y, "STRING", "UP/DOWN: Navigate | ENTER: Select | BACKSPACE: Back"); + } +} + +// ============================================================================ +// MENU EFFECTS +// ============================================================================ + +function updateEffects() { + // Glow effect + if (menuState.glowIncrement) { + menuState.glowValue += 3; + if (menuState.glowValue >= 190) { + menuState.glowIncrement = false; + } + } else { + menuState.glowValue -= 3; + if (menuState.glowValue <= 0) { + menuState.glowIncrement = true; + } + } + + // Flash effect + if (menuState.flashIncrement) { + menuState.flashValue += 3; + if (menuState.flashValue >= 255) { + menuState.flashIncrement = false; + } + } else { + menuState.flashValue -= 2; + if (menuState.flashValue <= 150) { + menuState.flashIncrement = true; + } + } +} + +// ============================================================================ +// MENU INPUT HANDLING +// ============================================================================ + +function handleMenuInput() { + if (menuState.inputCooldown > 0) { + menuState.inputCooldown--; + } + + // Open/Close menu with specific key combo (F5 or Insert) + if (natives.IS_GAME_KEYBOARD_KEY_JUST_PRESSED(0x74) || // F5 + natives.IS_GAME_KEYBOARD_KEY_JUST_PRESSED(0x2D)) { // Insert + toggleMenu(); + return; + } + + if (!menuState.isOpen) return; + + // Navigation + if (isInputPressed("up")) { + navigateUp(); + } + if (isInputPressed("down")) { + navigateDown(); + } + if (isInputPressed("left")) { + adjustValue(-1); + } + if (isInputPressed("right")) { + adjustValue(1); + } + + // Selection + if (isInputJustPressed("select")) { + selectItem(); + menuState.inputCooldown = 8; + } + + // Back + if (isInputJustPressed("back")) { + goBack(); + menuState.inputCooldown = 8; + } +} + +function isInputPressed(action) { + let pressed = false; + let justPressed = false; + + switch (action) { + case "up": + pressed = natives.IS_GAME_KEYBOARD_KEY_PRESSED(0x26) || // UP Arrow + natives.IS_BUTTON_PRESSED(0, 1); // DPAD UP + justPressed = natives.IS_GAME_KEYBOARD_KEY_JUST_PRESSED(0x26) || + natives.IS_BUTTON_JUST_PRESSED(0, 1); + break; + case "down": + pressed = natives.IS_GAME_KEYBOARD_KEY_PRESSED(0x28) || // DOWN Arrow + natives.IS_BUTTON_PRESSED(0, 2); // DPAD DOWN + justPressed = natives.IS_GAME_KEYBOARD_KEY_JUST_PRESSED(0x28) || + natives.IS_BUTTON_JUST_PRESSED(0, 2); + break; + case "left": + pressed = natives.IS_GAME_KEYBOARD_KEY_PRESSED(0x25) || // LEFT Arrow + natives.IS_BUTTON_PRESSED(0, 3); // DPAD LEFT + justPressed = natives.IS_GAME_KEYBOARD_KEY_JUST_PRESSED(0x25) || + natives.IS_BUTTON_JUST_PRESSED(0, 3); + break; + case "right": + pressed = natives.IS_GAME_KEYBOARD_KEY_PRESSED(0x27) || // RIGHT Arrow + natives.IS_BUTTON_PRESSED(0, 4); // DPAD RIGHT + justPressed = natives.IS_GAME_KEYBOARD_KEY_JUST_PRESSED(0x27) || + natives.IS_BUTTON_JUST_PRESSED(0, 4); + break; + } + + // Handle press with repeat + if (justPressed) { + menuState.holdCounter = 0; + menuState.pressCounter = 2; + menuState.pressMultiplier = 1; + return true; + } + + if (pressed && menuState.inputCooldown === 0) { + menuState.holdCounter++; + if (menuState.holdCounter > 15) { + menuState.pressCounter++; + menuState.pressCounter *= menuState.pressMultiplier; + + if (menuState.holdCounter > 40) { + menuState.pressMultiplier = 2; + menuState.holdCounter = 16; + } + + if (menuState.pressCounter > 6) { + menuState.inputCooldown = 3; + return true; + } + } + } else if (!pressed) { + menuState.holdCounter = 0; + menuState.pressMultiplier = 1; + } + + return false; +} + +function isInputJustPressed(action) { + switch (action) { + case "select": + return natives.IS_GAME_KEYBOARD_KEY_JUST_PRESSED(0x0D) || // Enter + natives.IS_BUTTON_JUST_PRESSED(0, 16); // A button + case "back": + return natives.IS_GAME_KEYBOARD_KEY_JUST_PRESSED(0x08) || // Backspace + natives.IS_BUTTON_JUST_PRESSED(0, 32); // B button + } + return false; +} + +// ============================================================================ +// MENU NAVIGATION +// ============================================================================ + +function toggleMenu() { + menuState.isOpen = !menuState.isOpen; + + if (menuState.isOpen) { + openMenu(); + } else { + closeMenu(); + } +} + +function openMenu() { + menuState.isOpen = true; + menuState.currentLevel = 0; + menuState.items = getMainMenuItems(); + menuState.selectedIndex = 0; + menuState.scrollOffset = 0; + menuState.menuStack = []; + menuState.lastSelected = []; + + // Block weapon switching while menu is open + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.BLOCK_PED_WEAPON_SWITCHING(playerPed, true); + + // Play open sound + natives.PLAY_AUDIO_EVENT("FRONTEND_MENU_MP_READY"); + + // Notification + showNotification("~b~MD TRIDENT ~s~Menu Opened"); +} + +function closeMenu() { + menuState.isOpen = false; + + // Unblock weapon switching + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.BLOCK_PED_WEAPON_SWITCHING(playerPed, false); + + // Play close sound + natives.PLAY_AUDIO_EVENT("FRONTEND_MENU_MP_UNREADY"); +} + +function navigateUp() { + // Skip jumpover items + do { + if (menuState.selectedIndex === 0) { + menuState.selectedIndex = menuState.items.length - 1; + // Adjust scroll for wrap-around + if (menuState.items.length > MENU_CONFIG.maxVisibleItems) { + menuState.scrollOffset = menuState.items.length - MENU_CONFIG.maxVisibleItems; + } + } else { + menuState.selectedIndex--; + // Adjust scroll + if (menuState.selectedIndex < menuState.scrollOffset) { + menuState.scrollOffset = menuState.selectedIndex; + } + } + } while (menuState.items[menuState.selectedIndex].type === ITEM_TYPE.JUMPOVER); + + natives.PLAY_AUDIO_EVENT("RADIO_RETUNE_BEEP"); +} + +function navigateDown() { + // Skip jumpover items + do { + if (menuState.selectedIndex === menuState.items.length - 1) { + menuState.selectedIndex = 0; + menuState.scrollOffset = 0; + } else { + menuState.selectedIndex++; + // Adjust scroll + if (menuState.selectedIndex >= menuState.scrollOffset + MENU_CONFIG.maxVisibleItems) { + menuState.scrollOffset = menuState.selectedIndex - MENU_CONFIG.maxVisibleItems + 1; + } + } + } while (menuState.items[menuState.selectedIndex].type === ITEM_TYPE.JUMPOVER); + + natives.PLAY_AUDIO_EVENT("RADIO_RETUNE_BEEP"); +} + +function adjustValue(delta) { + let item = menuState.items[menuState.selectedIndex]; + + if (item.type === ITEM_TYPE.VALUE_NUM) { + item.value += delta; + if (item.value > item.maxValue) item.value = item.minValue; + if (item.value < item.minValue) item.value = item.maxValue; + natives.PLAY_AUDIO_EVENT("RADIO_RETUNE_BEEP"); + } else if (item.type === ITEM_TYPE.VALUE_STRING) { + item.value += delta; + if (item.value >= item.stringValues.length) item.value = 0; + if (item.value < 0) item.value = item.stringValues.length - 1; + natives.PLAY_AUDIO_EVENT("RADIO_RETUNE_BEEP"); + } +} + +function selectItem() { + let item = menuState.items[menuState.selectedIndex]; + + if (item.type === ITEM_TYPE.JUMPOVER || item.type === ITEM_TYPE.NOT_PRESENT) { + return; + } + + natives.PLAY_AUDIO_EVENT("FRONTEND_MENU_MP_SERVER_HIGHLIGHT"); + + if (item.type === ITEM_TYPE.SUBMENU) { + // Save current state + menuState.menuStack.push({ + items: menuState.items, + selectedIndex: menuState.selectedIndex, + scrollOffset: menuState.scrollOffset + }); + + // Load submenu + menuState.items = getSubmenuItems(item.submenu); + menuState.selectedIndex = 0; + menuState.scrollOffset = 0; + menuState.currentLevel++; + + } else if (item.type === ITEM_TYPE.BOOL) { + item.boolState = !item.boolState; + if (item.action) { + item.action(item.boolState); + } + + } else if (item.type === ITEM_TYPE.FUNCTION) { + if (item.action) { + item.action(); + } + + } else if (item.type === ITEM_TYPE.VALUE_NUM || item.type === ITEM_TYPE.VALUE_STRING) { + if (item.action) { + item.action(item.value); + } + + } else if (item.type === ITEM_TYPE.VEHICLE) { + if (item.action) { + item.action(item.vehicleModel); + } else { + spawnVehicle(item.vehicleModel); + } + + } else if (item.type === ITEM_TYPE.PLAYER) { + menuState.selectedPlayer = item.playerId; + if (item.action) { + item.action(item.playerId); + } + } +} + +function goBack() { + if (menuState.currentLevel === 0) { + closeMenu(); + return; + } + + // Restore previous state + let prevState = menuState.menuStack.pop(); + if (prevState) { + menuState.items = prevState.items; + menuState.selectedIndex = prevState.selectedIndex; + menuState.scrollOffset = prevState.scrollOffset; + menuState.currentLevel--; + } + + natives.PLAY_AUDIO_EVENT("RADIO_RETUNE_BEEP"); +} + +// ============================================================================ +// SUBMENU DEFINITIONS +// ============================================================================ + +function getSubmenuItems(submenuId) { + switch (submenuId) { + case "player": + return getPlayerMenuItems(); + case "network": + return getNetworkMenuItems(); + case "vehicle": + return getVehicleMenuItems(); + case "weapon": + return getWeaponMenuItems(); + case "teleport": + return getTeleportMenuItems(); + case "weather": + return getWeatherMenuItems(); + case "model": + return getModelMenuItems(); + case "animation": + return getAnimationMenuItems(); + case "objects": + return getObjectMenuItems(); + case "settings": + return getSettingsMenuItems(); + case "credits": + return getCreditsMenuItems(); + // Vehicle sub-categories + case "vehicle_sports": + return getSportsVehicleItems(); + case "vehicle_muscle": + return getMuscleVehicleItems(); + case "vehicle_suv": + return getSUVVehicleItems(); + case "vehicle_sedan": + return getSedanVehicleItems(); + case "vehicle_emergency": + return getEmergencyVehicleItems(); + case "vehicle_bikes": + return getBikeVehicleItems(); + case "vehicle_boats": + return getBoatVehicleItems(); + case "vehicle_helicopters": + return getHelicopterVehicleItems(); + default: + return [createMenuItem("Not Implemented", ITEM_TYPE.ERROR)]; + } +} + +// ============================================================================ +// UTILITY FUNCTIONS +// ============================================================================ + +function showNotification(text) { + natives.PRINT_STRING_WITH_LITERAL_STRING_NOW("STRING", text, 3000, true); +} + +function getPlayerColor(playerId) { + let r = 255, g = 255, b = 255; + // Try to get player color + try { + let result = natives.GET_PLAYER_RGB_COLOUR(playerId); + if (result) { + r = result[0] || 255; + g = result[1] || 255; + b = result[2] || 255; + } + } catch (e) { + // Default white if failed + } + return [r, g, b, 255]; +} + +function spawnVehicle(modelHash) { + // Get player position and heading + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + let pos = natives.GET_CHAR_COORDINATES(playerPed); + let heading = natives.GET_CHAR_HEADING(playerPed); + + // Request model + natives.REQUEST_MODEL(modelHash); + + // Wait for model to load (simplified - actual implementation should use async) + let attempts = 0; + while (!natives.HAS_MODEL_LOADED(modelHash) && attempts < 100) { + natives.WAIT(10); + attempts++; + } + + if (!natives.HAS_MODEL_LOADED(modelHash)) { + showNotification("~r~Failed to load vehicle model!"); + return; + } + + // Create vehicle in front of player + let spawnX = pos[0] + Math.sin(heading * Math.PI / 180) * 5; + let spawnY = pos[1] + Math.cos(heading * Math.PI / 180) * 5; + let spawnZ = pos[2]; + + let vehicle = natives.CREATE_CAR(modelHash, spawnX, spawnY, spawnZ, true, true); + + if (vehicle) { + natives.SET_CAR_HEADING(vehicle, heading); + natives.SET_CAR_ON_GROUND_PROPERLY(vehicle); + showNotification("~g~Vehicle spawned!"); + } + + // Mark model as no longer needed + natives.MARK_MODEL_AS_NO_LONGER_NEEDED(modelHash); +} + +// ============================================================================ +// EVENT HANDLERS +// ============================================================================ + +addEventHandler("OnProcess", function(event) { + handleMenuInput(); +}); + +addEventHandler("OnDrawnHUD", function(event) { + renderMenu(); +}); + +// ============================================================================ +// EXPORTS +// ============================================================================ + +// Export menu state and functions for other scripts +this.menuState = menuState; +this.showNotification = showNotification; +this.createMenuItem = createMenuItem; +this.ITEM_TYPE = ITEM_TYPE; +this.toggleMenu = toggleMenu; diff --git a/Trident/player.js b/Trident/player.js new file mode 100644 index 0000000..e80a239 --- /dev/null +++ b/Trident/player.js @@ -0,0 +1,508 @@ +/** + * MD TRIDENT - Player Options Module + * GTAConnected Port for GTA IV + */ + +// ============================================================================ +// PLAYER OPTIONS STATE +// ============================================================================ + +let playerOptions = { + godmode: false, + neverWanted: false, + infiniteAmmo: false, + superRun: false, + superJump: false, + superPunch: false, + invisible: false, + flyMode: false, + inferno: false, + forceField: false, + juggernaut: false, + rapidFire: false, + autoAim: false, + gravity: true, + slowMotion: false +}; + +// Fly mode state +let flyModeState = { + active: false, + camera: null, + pitch: 0, + speed: 1.0 +}; + +// ============================================================================ +// PLAYER MENU ITEMS +// ============================================================================ + +function getPlayerMenuItems() { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + return [ + createMenuItem("~~ PLAYER PROTECTION ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("God Mode", ITEM_TYPE.BOOL, { + boolState: playerOptions.godmode, + action: toggleGodMode + }), + createMenuItem("Juggernaut (Auto Health/Armor)", ITEM_TYPE.BOOL, { + boolState: playerOptions.juggernaut, + action: toggleJuggernaut + }), + createMenuItem("Never Wanted", ITEM_TYPE.BOOL, { + boolState: playerOptions.neverWanted, + action: toggleNeverWanted + }), + + createMenuItem("~~ PLAYER ABILITIES ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Super Run", ITEM_TYPE.BOOL, { + boolState: playerOptions.superRun, + action: toggleSuperRun + }), + createMenuItem("Super Jump", ITEM_TYPE.BOOL, { + boolState: playerOptions.superJump, + action: toggleSuperJump + }), + createMenuItem("Super Punch", ITEM_TYPE.BOOL, { + boolState: playerOptions.superPunch, + action: toggleSuperPunch + }), + createMenuItem("Fly Mode", ITEM_TYPE.BOOL, { + boolState: playerOptions.flyMode, + action: toggleFlyMode + }), + + createMenuItem("~~ PLAYER EFFECTS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Invisible", ITEM_TYPE.BOOL, { + boolState: playerOptions.invisible, + action: toggleInvisible + }), + createMenuItem("Inferno Mode", ITEM_TYPE.BOOL, { + boolState: playerOptions.inferno, + action: toggleInferno + }), + createMenuItem("Force Field", ITEM_TYPE.BOOL, { + boolState: playerOptions.forceField, + action: toggleForceField + }), + + createMenuItem("~~ PLAYER PHYSICS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Normal Gravity", ITEM_TYPE.BOOL, { + boolState: playerOptions.gravity, + action: toggleGravity + }), + createMenuItem("Slow Motion", ITEM_TYPE.BOOL, { + boolState: playerOptions.slowMotion, + action: toggleSlowMotion + }), + + createMenuItem("~~ PLAYER ACTIONS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Give Health", ITEM_TYPE.FUNCTION, { action: giveHealth }), + createMenuItem("Give Armor", ITEM_TYPE.FUNCTION, { action: giveArmor }), + createMenuItem("Give All Weapons", ITEM_TYPE.FUNCTION, { action: giveAllWeapons }), + createMenuItem("Remove All Weapons", ITEM_TYPE.FUNCTION, { action: removeAllWeapons }), + createMenuItem("Spawn Money", ITEM_TYPE.FUNCTION, { action: spawnMoney }), + createMenuItem("Fix Player", ITEM_TYPE.FUNCTION, { action: fixPlayer }), + createMenuItem("Change to Niko", ITEM_TYPE.FUNCTION, { action: changeToNiko }), + createMenuItem("Explode Self", ITEM_TYPE.FUNCTION, { action: explodeSelf }), + createMenuItem("Resurrect", ITEM_TYPE.FUNCTION, { action: resurrectPlayer }), + + createMenuItem("~~ WANTED LEVEL ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Set Wanted Level", ITEM_TYPE.VALUE_NUM, { + value: 0, + minValue: 0, + maxValue: 6, + action: setWantedLevel + }), + createMenuItem("Clear Wanted Level", ITEM_TYPE.FUNCTION, { action: clearWantedLevel }) + ]; +} + +// ============================================================================ +// TOGGLE FUNCTIONS +// ============================================================================ + +function toggleGodMode(state) { + playerOptions.godmode = state; + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + natives.SET_CHAR_INVINCIBLE(playerPed, state); + natives.SET_PLAYER_NEVER_GETS_TIRED(playerId, state); + natives.SET_PLAYER_FAST_RELOAD(playerId, state); + natives.SET_CHAR_NEVER_TARGETTED(playerPed, state); + natives.ENABLE_MAX_AMMO_CAP(!state); + + showNotification(state ? "~g~God Mode ~s~ON" : "~r~God Mode ~s~OFF"); +} + +function toggleJuggernaut(state) { + playerOptions.juggernaut = state; + showNotification(state ? "~g~Juggernaut ~s~ON" : "~r~Juggernaut ~s~OFF"); +} + +function toggleNeverWanted(state) { + playerOptions.neverWanted = state; + if (state) { + natives.CLEAR_WANTED_LEVEL(natives.GET_PLAYER_ID()); + } + showNotification(state ? "~g~Never Wanted ~s~ON" : "~r~Never Wanted ~s~OFF"); +} + +function toggleSuperRun(state) { + playerOptions.superRun = state; + showNotification(state ? "~g~Super Run ~s~ON (Hold LB/RB + A)" : "~r~Super Run ~s~OFF"); +} + +function toggleSuperJump(state) { + playerOptions.superJump = state; + showNotification(state ? "~g~Super Jump ~s~ON (Hold LB/RB + X)" : "~r~Super Jump ~s~OFF"); +} + +function toggleSuperPunch(state) { + playerOptions.superPunch = state; + showNotification(state ? "~g~Super Punch ~s~ON (Hold LB + B)" : "~r~Super Punch ~s~OFF"); +} + +function toggleFlyMode(state) { + playerOptions.flyMode = state; + flyModeState.active = state; + + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + if (state) { + // Create fly mode camera + flyModeState.camera = natives.CREATE_CAM(14); + natives.SET_CAM_ACTIVE(flyModeState.camera, true); + natives.SET_CAM_PROPAGATE(flyModeState.camera, true); + natives.ACTIVATE_SCRIPTED_CAMS(true, true); + natives.ATTACH_CAM_TO_PED(flyModeState.camera, playerPed); + natives.POINT_CAM_AT_PED(flyModeState.camera, playerPed); + flyModeState.pitch = 0; + showNotification("~g~Fly Mode ~s~ON"); + } else { + // Destroy fly mode camera + if (flyModeState.camera) { + natives.SET_CAM_ACTIVE(flyModeState.camera, false); + natives.SET_CAM_PROPAGATE(flyModeState.camera, false); + natives.ACTIVATE_SCRIPTED_CAMS(false, false); + natives.DESTROY_CAM(flyModeState.camera); + flyModeState.camera = null; + } + natives.FREEZE_CHAR_POSITION(playerPed, false); + showNotification("~r~Fly Mode ~s~OFF"); + } +} + +function toggleInvisible(state) { + playerOptions.invisible = state; + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.SET_CHAR_VISIBLE(playerPed, !state); + showNotification(state ? "~g~Invisible ~s~ON" : "~r~Invisible ~s~OFF"); +} + +function toggleInferno(state) { + playerOptions.inferno = state; + showNotification(state ? "~g~Inferno Mode ~s~ON" : "~r~Inferno Mode ~s~OFF"); +} + +function toggleForceField(state) { + playerOptions.forceField = state; + if (state && !playerOptions.godmode) { + toggleGodMode(true); + showNotification("~y~God Mode auto-enabled for Force Field"); + } + showNotification(state ? "~g~Force Field ~s~ON" : "~r~Force Field ~s~OFF"); +} + +function toggleGravity(state) { + playerOptions.gravity = state; + natives.SET_GRAVITY_OFF(!state); + showNotification(state ? "~g~Gravity ~s~ON" : "~r~Gravity ~s~OFF"); +} + +function toggleSlowMotion(state) { + playerOptions.slowMotion = state; + natives.SET_TIME_SCALE(state ? 0.3 : 1.0); + showNotification(state ? "~g~Slow Motion ~s~ON" : "~r~Slow Motion ~s~OFF"); +} + +// ============================================================================ +// ACTION FUNCTIONS +// ============================================================================ + +function giveHealth() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.SET_CHAR_HEALTH(playerPed, 200); + showNotification("~g~Health restored!"); +} + +function giveArmor() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.ADD_ARMOUR_TO_CHAR(playerPed, 100); + showNotification("~g~Armor added!"); +} + +function giveAllWeapons() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + let episode = natives.GET_CURRENT_EPISODE(); + natives.GIVE_EPISODIC_WEAPONS_TO_CHAR(playerPed, episode); + showNotification("~g~All weapons given!"); +} + +function removeAllWeapons() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.REMOVE_ALL_CHAR_WEAPONS(playerPed); + showNotification("~r~All weapons removed!"); +} + +function spawnMoney() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + for (let i = 0; i < 4; i++) { + natives.GIVE_CASH_PICKUP_TO_CHAR(playerPed, 10000); + } + showNotification("~g~Money spawned around you!"); +} + +function fixPlayer() { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + natives.SET_CHAR_HEALTH(playerPed, 200); + natives.ADD_ARMOUR_TO_CHAR(playerPed, 100); + natives.CLEAR_CHAR_TASKS(playerPed); + natives.CLEAR_CHAR_TASKS_IMMEDIATELY(playerPed); + + showNotification("~g~Player fixed!"); +} + +function changeToNiko() { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + // MODEL_PLAYER is Niko's model hash + let nikoModel = natives.GET_HASH_KEY("PLAYER"); + natives.REQUEST_MODEL(nikoModel); + + let attempts = 0; + while (!natives.HAS_MODEL_LOADED(nikoModel) && attempts < 100) { + natives.WAIT(10); + attempts++; + } + + if (natives.HAS_MODEL_LOADED(nikoModel)) { + natives.CHANGE_PLAYER_MODEL(playerId, nikoModel); + natives.SET_CHAR_HEALTH(playerPed, 200); + natives.ADD_ARMOUR_TO_CHAR(playerPed, 100); + natives.MARK_MODEL_AS_NO_LONGER_NEEDED(nikoModel); + showNotification("~g~Changed to Niko!"); + } else { + showNotification("~r~Failed to load model!"); + } +} + +function explodeSelf() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + let pos = natives.GET_CHAR_COORDINATES(playerPed); + + natives.ADD_EXPLOSION(pos[0], pos[1], pos[2], 2, 10.0, true, false, 0.7); + showNotification("~r~BOOM!"); +} + +function resurrectPlayer() { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + let pos = natives.GET_CHAR_COORDINATES(playerPed); + + natives.RESURRECT_NETWORK_PLAYER(playerId, pos[0], pos[1], pos[2], 0); + natives.SET_CHAR_HEALTH(playerPed, 200); + showNotification("~g~Resurrected!"); +} + +function setWantedLevel(level) { + let playerId = natives.GET_PLAYER_ID(); + natives.ALTER_WANTED_LEVEL(playerId, level); + natives.APPLY_WANTED_LEVEL_CHANGE_NOW(playerId); + showNotification("~b~Wanted level set to: ~s~" + level); +} + +function clearWantedLevel() { + let playerId = natives.GET_PLAYER_ID(); + natives.CLEAR_WANTED_LEVEL(playerId); + showNotification("~g~Wanted level cleared!"); +} + +// ============================================================================ +// PLAYER OPTIONS LOOP +// ============================================================================ + +function playerOptionsLoop() { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + if (!natives.DOES_CHAR_EXIST(playerPed)) return; + + // God Mode maintenance + if (playerOptions.godmode) { + natives.SET_CHAR_INVINCIBLE(playerPed, true); + } + + // Juggernaut (auto health/armor) + if (playerOptions.juggernaut) { + let health = natives.GET_CHAR_HEALTH(playerPed); + let armor = natives.GET_CHAR_ARMOUR(playerPed); + + if (health < 200) natives.SET_CHAR_HEALTH(playerPed, 200); + if (armor < 100) natives.ADD_ARMOUR_TO_CHAR(playerPed, 100 - armor); + } + + // Never Wanted + if (playerOptions.neverWanted) { + natives.CLEAR_WANTED_LEVEL(playerId); + } + + // Infinite Ammo + if (playerOptions.infiniteAmmo && natives.IS_CHAR_SHOOTING(playerPed)) { + let weapon = natives.GET_CURRENT_CHAR_WEAPON(playerPed); + if (weapon !== 16 && weapon !== 17) { // Not grenade or molotov + let maxAmmo = natives.GET_MAX_AMMO_IN_CLIP(playerPed, weapon); + natives.SET_AMMO_IN_CLIP(playerPed, weapon, maxAmmo); + } + } + + // Super Powers (only when not in vehicle) + let inVehicle = natives.IS_CHAR_IN_ANY_CAR(playerPed); + if (!inVehicle) { + let lbPressed = natives.IS_BUTTON_PRESSED(0, 256); // LB + let rbPressed = natives.IS_BUTTON_PRESSED(0, 512); // RB + + // Super Run (LB/RB + A) + if (playerOptions.superRun && (lbPressed || rbPressed) && natives.IS_BUTTON_PRESSED(0, 16)) { + let force = lbPressed ? 100.0 : 10.0; + natives.APPLY_FORCE_TO_PED(playerPed, true, 0.0, force, 0.0, 0.0, 0.0, 0.0, true, true, true, true); + } + + // Super Jump (LB/RB + X) + if (playerOptions.superJump && (lbPressed || rbPressed) && natives.IS_BUTTON_PRESSED(0, 64)) { + let upForce = lbPressed ? 11.0 : 50.0; + let fwdForce = lbPressed ? 1.2 : 0.0; + natives.APPLY_FORCE_TO_PED(playerPed, true, 0.0, fwdForce, upForce, 0.0, 0.0, 0.0, true, true, true, true); + } + + // Super Punch (LB + B with fist) + if (playerOptions.superPunch && lbPressed && natives.IS_BUTTON_PRESSED(0, 32)) { + let weapon = natives.GET_CURRENT_CHAR_WEAPON(playerPed); + if (weapon === 0) { // Unarmed + let offset = natives.GET_OFFSET_FROM_CHAR_IN_WORLD_COORDS(playerPed, 0, 2, 0); + natives.ADD_EXPLOSION(offset[0], offset[1], offset[2], 2, 10, false, true, 0); + } + } + } + + // Inferno Mode + if (playerOptions.inferno) { + let pos = natives.GET_CHAR_COORDINATES(playerPed); + natives.ADD_EXPLOSION(pos[0], pos[1], pos[2], 5, 7.5, true, false, 0.0); + } + + // Force Field + if (playerOptions.forceField) { + let pos = natives.GET_CHAR_COORDINATES(playerPed); + natives.ADD_EXPLOSION(pos[0], pos[1], pos[2], 2, 10.0, false, true, 0.0); + } + + // Fly Mode + if (flyModeState.active) { + processFlyMode(); + } +} + +// ============================================================================ +// FLY MODE PROCESSING +// ============================================================================ + +function processFlyMode() { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + if (!flyModeState.camera) return; + + natives.FREEZE_CHAR_POSITION(playerPed, true); + + let pos = natives.GET_CHAR_COORDINATES(playerPed); + let heading = natives.GET_CHAR_HEADING(playerPed); + + // Get analog stick input + let sticks = natives.GET_POSITION_OF_ANALOGUE_STICKS(0); + let leftX = sticks[0] || 0; + let leftY = sticks[1] || 0; + let rightX = sticks[2] || 0; + let rightY = sticks[3] || 0; + + // Adjust heading with right stick + heading = heading - (rightX * 0.035); + if (heading > 360) heading -= 360; + if (heading < 0) heading += 360; + + // Adjust pitch + flyModeState.pitch = flyModeState.pitch - (rightY * 0.035); + if (flyModeState.pitch < -70) flyModeState.pitch = -70; + if (flyModeState.pitch > 70) flyModeState.pitch = 70; + + // Speed modifiers + let moveSpeed = 1.0; + if (natives.IS_BUTTON_PRESSED(0, 512)) moveSpeed = 4.0; // RB - Fast + if (natives.IS_BUTTON_PRESSED(0, 256)) moveSpeed = 0.25; // LB - Slow + + // Calculate movement + let moveTrig = (leftY * 0.0133) * Math.cos(flyModeState.pitch * Math.PI / 180); + let newX = pos[0] + (moveSpeed * ((moveTrig * Math.sin(heading * Math.PI / 180)) + (leftX * 0.0133) * Math.cos(heading * Math.PI / 180))); + let newY = pos[1] - (moveSpeed * ((moveTrig * Math.cos(heading * Math.PI / 180)) - (leftX * 0.0133) * Math.sin(heading * Math.PI / 180))); + let newZ = pos[2] - (moveSpeed * ((leftY * 0.0133) * Math.sin(flyModeState.pitch * Math.PI / 180))); + + // Height adjustment with triggers + let lt = natives.GET_CONTROL_VALUE(0, 6); // LT + let rt = natives.GET_CONTROL_VALUE(0, 5); // RT + newZ = newZ + (moveSpeed * ((rt * 0.0025) - (lt * 0.0025))); + + // Update position + natives.SET_CHAR_COORDINATES_NO_OFFSET(playerPed, newX, newY, newZ); + natives.SET_CHAR_HEADING(playerPed, heading); + + // Update camera + let camDistance = 4.0; + let camOffsetTrig = camDistance * Math.cos((flyModeState.pitch - 18) * Math.PI / 180); + let camOffsetX = camOffsetTrig * Math.sin(heading * Math.PI / 180); + let camOffsetY = -camOffsetTrig * Math.cos(heading * Math.PI / 180); + let camOffsetZ = -camDistance * Math.sin((flyModeState.pitch - 18) * Math.PI / 180); + + natives.SET_CAM_ATTACH_OFFSET(flyModeState.camera, camOffsetX, camOffsetY, camOffsetZ); + + // Exit fly mode with all shoulder buttons + if (natives.IS_BUTTON_PRESSED(0, 256) && natives.IS_BUTTON_PRESSED(0, 512) && + natives.IS_BUTTON_PRESSED(0, 1024) && natives.IS_BUTTON_PRESSED(0, 2048)) { + toggleFlyMode(false); + } +} + +// ============================================================================ +// EVENT HANDLERS +// ============================================================================ + +addEventHandler("OnProcess", function(event) { + playerOptionsLoop(); +}); + +// ============================================================================ +// EXPORTS +// ============================================================================ + +this.playerOptions = playerOptions; +this.getPlayerMenuItems = getPlayerMenuItems; +this.toggleGodMode = toggleGodMode; +this.toggleNeverWanted = toggleNeverWanted; +this.giveHealth = giveHealth; +this.giveArmor = giveArmor; diff --git a/Trident/teleport.js b/Trident/teleport.js new file mode 100644 index 0000000..730962d --- /dev/null +++ b/Trident/teleport.js @@ -0,0 +1,276 @@ +/** + * MD TRIDENT - Teleport Options Module + * GTAConnected Port for GTA IV + */ + +// ============================================================================ +// TELEPORT LOCATIONS (Liberty City) +// ============================================================================ + +const TELEPORT_LOCATIONS = { + // Broker/Dukes + BROKER_SAFEHOUSE: { x: 875.59, y: -482.13, z: 15.65, name: "Broker Safehouse" }, + ROTTERDAM_HILL: { x: 1030.25, y: -618.87, z: 25.12, name: "Rotterdam Hill" }, + EAST_HOOK: { x: 1224.36, y: -244.15, z: 20.34, name: "East Hook" }, + STEINWAY: { x: 1414.54, y: 498.27, z: 35.76, name: "Steinway" }, + DUKES_BAY_BRIDGE: { x: 1586.32, y: 1231.45, z: 22.89, name: "Dukes Bay Bridge" }, + + // Bohan + BOHAN_SAFEHOUSE: { x: 579.45, y: 1436.32, z: 16.87, name: "Bohan Safehouse" }, + NORTHERN_GARDENS: { x: 428.67, y: 1652.43, z: 17.54, name: "Northern Gardens" }, + SOUTH_BOHAN: { x: 715.23, y: 1245.67, z: 15.43, name: "South Bohan" }, + + // Algonquin + MIDDLE_PARK: { x: -21.45, y: 532.87, z: 15.23, name: "Middle Park" }, + STAR_JUNCTION: { x: -234.56, y: 234.78, z: 14.67, name: "Star Junction (Times Sq)" }, + ALGONQUIN_SAFEHOUSE: { x: -432.12, y: 1245.43, z: 20.34, name: "Algonquin Safehouse" }, + HAPPINESS_ISLAND: { x: -1032.45, y: -721.34, z: 4.21, name: "Happiness Island" }, + STATUE_OF_HAPPINESS: { x: -1032.45, y: -721.34, z: 96.45, name: "Statue of Happiness (Top)" }, + LIBERTY_FERRY_TERMINAL: { x: -784.56, y: -286.43, z: 5.67, name: "Liberty Ferry Terminal" }, + AIRPORT: { x: 2165.34, y: 487.65, z: 6.23, name: "Francis Intl Airport" }, + + // Alderney + ALDERNEY_SAFEHOUSE: { x: -1134.56, y: 743.21, z: 21.45, name: "Alderney Safehouse" }, + WESTDYKE: { x: -1423.67, y: 1234.56, z: 23.78, name: "Westdyke" }, + ACTER_INDUSTRIAL: { x: -1087.32, y: 256.78, z: 17.34, name: "Acter Industrial" }, + PORT_TUDOR: { x: -1256.43, y: -78.65, z: 6.54, name: "Port Tudor" }, + + // Special + HOSPITAL: { x: 1197.23, y: -476.54, z: 18.76, name: "Hospital" }, + POLICE_STATION: { x: 945.67, y: -367.89, z: 15.43, name: "Police Station" }, + BOWLING_ALLEY: { x: 754.32, y: -612.45, z: 12.34, name: "Bowling Alley" }, + BURGER_SHOT: { x: 1087.65, y: -234.56, z: 17.89, name: "Burger Shot" } +}; + +// ============================================================================ +// TELEPORT MENU ITEMS +// ============================================================================ + +function getTeleportMenuItems() { + return [ + createMenuItem("~~ QUICK TELEPORTS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Teleport to Waypoint", ITEM_TYPE.FUNCTION, { action: teleportToWaypoint }), + createMenuItem("Teleport Forward", ITEM_TYPE.FUNCTION, { action: teleportForward }), + + createMenuItem("~~ BROKER / DUKES ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Broker Safehouse", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.BROKER_SAFEHOUSE) + }), + createMenuItem("Rotterdam Hill", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.ROTTERDAM_HILL) + }), + createMenuItem("East Hook", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.EAST_HOOK) + }), + createMenuItem("Steinway", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.STEINWAY) + }), + + createMenuItem("~~ BOHAN ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Bohan Safehouse", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.BOHAN_SAFEHOUSE) + }), + createMenuItem("Northern Gardens", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.NORTHERN_GARDENS) + }), + createMenuItem("South Bohan", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.SOUTH_BOHAN) + }), + + createMenuItem("~~ ALGONQUIN ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Middle Park", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.MIDDLE_PARK) + }), + createMenuItem("Star Junction (Times Sq)", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.STAR_JUNCTION) + }), + createMenuItem("Algonquin Safehouse", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.ALGONQUIN_SAFEHOUSE) + }), + createMenuItem("Happiness Island", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.HAPPINESS_ISLAND) + }), + createMenuItem("Statue of Happiness (Top)", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.STATUE_OF_HAPPINESS) + }), + createMenuItem("Francis Intl Airport", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.AIRPORT) + }), + + createMenuItem("~~ ALDERNEY ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Alderney Safehouse", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.ALDERNEY_SAFEHOUSE) + }), + createMenuItem("Westdyke", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.WESTDYKE) + }), + createMenuItem("Acter Industrial", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.ACTER_INDUSTRIAL) + }), + createMenuItem("Port Tudor", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.PORT_TUDOR) + }), + + createMenuItem("~~ SERVICES ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Hospital", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.HOSPITAL) + }), + createMenuItem("Police Station", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.POLICE_STATION) + }), + createMenuItem("Bowling Alley", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.BOWLING_ALLEY) + }), + createMenuItem("Burger Shot", ITEM_TYPE.FUNCTION, { + action: () => teleportTo(TELEPORT_LOCATIONS.BURGER_SHOT) + }), + + createMenuItem("~~ COORDINATES ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Save Current Position", ITEM_TYPE.FUNCTION, { action: saveCurrentPosition }), + createMenuItem("Teleport to Saved Position", ITEM_TYPE.FUNCTION, { action: teleportToSavedPosition }) + ]; +} + +// ============================================================================ +// SAVED POSITIONS +// ============================================================================ + +let savedPositions = []; +let lastSavedPosition = null; + +// ============================================================================ +// TELEPORT FUNCTIONS +// ============================================================================ + +function teleportTo(location) { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + let inVehicle = natives.IS_CHAR_IN_ANY_CAR(playerPed); + + if (inVehicle) { + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + natives.SET_CAR_COORDINATES_NO_OFFSET(vehicle, location.x, location.y, location.z); + natives.SET_CAR_ON_GROUND_PROPERLY(vehicle); + } else { + natives.SET_CHAR_COORDINATES_NO_OFFSET(playerPed, location.x, location.y, location.z); + } + + showNotification("~g~Teleported to: ~s~" + location.name); +} + +function teleportToWaypoint() { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + // Check if waypoint is set + let blipInfo = natives.GET_FIRST_BLIP_INFO_ID(8); // 8 = waypoint blip + if (!blipInfo || blipInfo === 0) { + showNotification("~r~No waypoint set!"); + return; + } + + let blipCoords = natives.GET_BLIP_INFO_ID_COORD(blipInfo); + if (!blipCoords) { + showNotification("~r~Could not get waypoint coordinates!"); + return; + } + + // Get ground Z at waypoint + let groundZ = natives.GET_GROUND_Z_FOR_3D_COORD(blipCoords[0], blipCoords[1], 1000.0); + let targetZ = groundZ ? groundZ + 1.0 : blipCoords[2] + 1.0; + + let inVehicle = natives.IS_CHAR_IN_ANY_CAR(playerPed); + + if (inVehicle) { + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + natives.SET_CAR_COORDINATES_NO_OFFSET(vehicle, blipCoords[0], blipCoords[1], targetZ); + natives.SET_CAR_ON_GROUND_PROPERLY(vehicle); + } else { + natives.SET_CHAR_COORDINATES_NO_OFFSET(playerPed, blipCoords[0], blipCoords[1], targetZ); + } + + showNotification("~g~Teleported to waypoint!"); +} + +function teleportForward() { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + let pos = natives.GET_CHAR_COORDINATES(playerPed); + let heading = natives.GET_CHAR_HEADING(playerPed); + + // Calculate position 10 units forward + let radians = heading * Math.PI / 180; + let newX = pos[0] - Math.sin(radians) * 10; + let newY = pos[1] + Math.cos(radians) * 10; + let newZ = pos[2]; + + // Get ground Z at new position + let groundZ = natives.GET_GROUND_Z_FOR_3D_COORD(newX, newY, pos[2] + 100); + if (groundZ) { + newZ = groundZ + 1.0; + } + + let inVehicle = natives.IS_CHAR_IN_ANY_CAR(playerPed); + + if (inVehicle) { + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + natives.SET_CAR_COORDINATES_NO_OFFSET(vehicle, newX, newY, newZ); + } else { + natives.SET_CHAR_COORDINATES_NO_OFFSET(playerPed, newX, newY, newZ); + } + + showNotification("~g~Teleported forward!"); +} + +function saveCurrentPosition() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + let pos = natives.GET_CHAR_COORDINATES(playerPed); + let heading = natives.GET_CHAR_HEADING(playerPed); + + lastSavedPosition = { + x: pos[0], + y: pos[1], + z: pos[2], + heading: heading, + name: "Saved Position " + (savedPositions.length + 1) + }; + + savedPositions.push(lastSavedPosition); + + showNotification("~g~Position saved! ~s~(" + pos[0].toFixed(2) + ", " + pos[1].toFixed(2) + ", " + pos[2].toFixed(2) + ")"); +} + +function teleportToSavedPosition() { + if (!lastSavedPosition) { + showNotification("~r~No position saved!"); + return; + } + + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + let inVehicle = natives.IS_CHAR_IN_ANY_CAR(playerPed); + + if (inVehicle) { + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + natives.SET_CAR_COORDINATES_NO_OFFSET(vehicle, lastSavedPosition.x, lastSavedPosition.y, lastSavedPosition.z); + natives.SET_CAR_HEADING(vehicle, lastSavedPosition.heading); + natives.SET_CAR_ON_GROUND_PROPERLY(vehicle); + } else { + natives.SET_CHAR_COORDINATES_NO_OFFSET(playerPed, lastSavedPosition.x, lastSavedPosition.y, lastSavedPosition.z); + natives.SET_CHAR_HEADING(playerPed, lastSavedPosition.heading); + } + + showNotification("~g~Teleported to saved position!"); +} + +// ============================================================================ +// EXPORTS +// ============================================================================ + +this.getTeleportMenuItems = getTeleportMenuItems; +this.teleportTo = teleportTo; +this.teleportToWaypoint = teleportToWaypoint; +this.TELEPORT_LOCATIONS = TELEPORT_LOCATIONS; diff --git a/Trident/vehicle.js b/Trident/vehicle.js new file mode 100644 index 0000000..57eee81 --- /dev/null +++ b/Trident/vehicle.js @@ -0,0 +1,604 @@ +/** + * MD TRIDENT - Vehicle Options Module + * GTAConnected Port for GTA IV + */ + +// ============================================================================ +// VEHICLE MODEL HASHES (GTA IV) +// ============================================================================ + +const VEHICLE_MODELS = { + // Sports Cars + BANSHEE: 0xC1E908D2, + COMET: 0x067BC037, + COQUETTE: 0x067BC037, + FELTZER: 0x8F5B9FB5, + INFERNUS: 0x18F25AC7, + SULTAN: 0x39DA2754, + SULTANRS: 0xEE6024BC, + SUPERGT: 0x42F2ED16, + TURISMO: 0x185484E1, + SENTINEL: 0x50732C82, + + // Muscle Cars + BUCCANEER: 0xD756460C, + DUKES: 0x2B26F456, + FACTION: 0x81A9CDDF, + MANANA: 0x81634188, + PEYOTE: 0x6D19CCBC, + RUINER: 0xF26CEFF9, + SABRE: 0x9B909C94, + SABREGT: 0x9B909C94, + STALION: 0x72A4C31E, + VIGERO: 0xCEC6B9B7, + VIRGO: 0xE2504942, + VOODOO: 0x1F3766E3, + + // SUVs and Off-Road + BOBCAT: 0x31F0B376, + CAVALCADE: 0x779F23AA, + HABANERO: 0x34B7390F, + HUNTLEY: 0x1D06D681, + LANDSTALKER: 0x4BA4E8DC, + PATRIOT: 0xCFCFEB3B, + RANCHER: 0x6210CBB0, + REBLA: 0x4C489021, + + // Sedans + ADMIRAL: 0x32B29A4B, + CHAVOS: 0xE8A8BDA8, + COGNOSCENTI: 0x86FE0B60, + EMPEROR: 0xD7278283, + ESPERANTO: 0xFF8C6ED1, + FEROCI: 0x1AD3D617, + INGOT: 0xB3206692, + INTRUDER: 0x34DD8AA1, + LOKUS: 0xCB3C7191, + ORACLE: 0x506434F6, + PINNACLE: 0x874D2A8B, + PMP600: 0x700E514C, + PREMIER: 0x8FB66F9B, + SCHAFTER: 0xB52B5113, + VINCENT: 0x9D0450CA, + WASHINGTON: 0x69F06B57, + + // Emergency Vehicles + AMBULANCE: 0x45D56ADA, + FBI: 0x432EA949, + FIRETRUK: 0x73920F8E, + NOOSE: 0xB4F32720, + POLICE: 0x79FBB0C5, + POLICE2: 0x9F05F101, + POLPATRIOT: 0xCFCFEB3B, + + // Commercial + BENSON: 0xB7B2BBE7, + BOXVILLE: 0x898ECCEA, + BURRITO: 0xAFBB2CA4, + FLATBED: 0x50B0215A, + MULE: 0x35ED670B, + PACKER: 0x21EEE87D, + PHANTOM: 0x809AA4CB, + PONY: 0xF8DE29A8, + SPEEDO: 0xCFB3870C, + STOCKADE: 0x6827CF72, + YANKEE: 0x3D236D91, + + // Public Service + BUS: 0xD577C962, + CABBY: 0x3FC5D440, + ROMERO: 0x2560B2FC, + TAXI: 0xC703DB5F, + STRETCH: 0x8B13F083, + TRASH: 0x72435A19, + + // Bikes + FAGGIO: 0x9229E4EB, + NRG900: 0x6F946279, + PCJ: 0xC9CEAF06, + SANCHEZ: 0x2EF89E46, + ZOMBIEB: 0xDE05FB87, + HELLFURY: 0x6598A42B, + BOBBER: 0x67B52491, + + // Boats + DINGHY: 0x3D961290, + JETMAX: 0x33581161, + MARQUIS: 0xC1CE1183, + PREDATOR: 0xE2E7D4AB, + REEFER: 0x1D97DCAF, + SQUALO: 0x17DF5EC2, + TROPIC: 0x1149422F, + TUGA: 0x82CAC433, + + // Helicopters + ANNIHILATOR: 0x31F0B376, + MAVERICK: 0x9D0450CA, + POLMAV: 0x1517D4D9, + TOURMAV: 0x73232612 +}; + +// ============================================================================ +// VEHICLE OPTIONS STATE +// ============================================================================ + +let vehicleOptions = { + godmode: false, + speedBoost: false, + autoFlip: false, + autoFix: false, + rainbow: false, + invisible: false, + engineAlwaysOn: false, + nitro: false +}; + +// ============================================================================ +// VEHICLE MENU ITEMS +// ============================================================================ + +function getVehicleMenuItems() { + return [ + createMenuItem("~~ SPAWN VEHICLES ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Quick Spawner (Favorites)", ITEM_TYPE.SUBMENU, { submenu: "vehicle_favorites" }), + createMenuItem("Sports Cars", ITEM_TYPE.SUBMENU, { submenu: "vehicle_sports" }), + createMenuItem("Muscle / Vintage", ITEM_TYPE.SUBMENU, { submenu: "vehicle_muscle" }), + createMenuItem("SUVs / Off-Road", ITEM_TYPE.SUBMENU, { submenu: "vehicle_suv" }), + createMenuItem("Sedans", ITEM_TYPE.SUBMENU, { submenu: "vehicle_sedan" }), + createMenuItem("Emergency Vehicles", ITEM_TYPE.SUBMENU, { submenu: "vehicle_emergency" }), + createMenuItem("Bikes", ITEM_TYPE.SUBMENU, { submenu: "vehicle_bikes" }), + createMenuItem("Boats", ITEM_TYPE.SUBMENU, { submenu: "vehicle_boats" }), + createMenuItem("Helicopters", ITEM_TYPE.SUBMENU, { submenu: "vehicle_helicopters" }), + createMenuItem("Commercial", ITEM_TYPE.SUBMENU, { submenu: "vehicle_commercial" }), + + createMenuItem("~~ VEHICLE OPTIONS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Vehicle God Mode", ITEM_TYPE.BOOL, { + boolState: vehicleOptions.godmode, + action: toggleVehicleGodMode + }), + createMenuItem("Speed Boost", ITEM_TYPE.BOOL, { + boolState: vehicleOptions.speedBoost, + action: toggleSpeedBoost + }), + createMenuItem("Auto Flip", ITEM_TYPE.BOOL, { + boolState: vehicleOptions.autoFlip, + action: toggleAutoFlip + }), + createMenuItem("Auto Repair", ITEM_TYPE.BOOL, { + boolState: vehicleOptions.autoFix, + action: toggleAutoFix + }), + createMenuItem("Rainbow Car", ITEM_TYPE.BOOL, { + boolState: vehicleOptions.rainbow, + action: toggleRainbow + }), + createMenuItem("Invisible Vehicle", ITEM_TYPE.BOOL, { + boolState: vehicleOptions.invisible, + action: toggleVehicleInvisible + }), + + createMenuItem("~~ VEHICLE ACTIONS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Repair Vehicle", ITEM_TYPE.FUNCTION, { action: repairVehicle }), + createMenuItem("Flip Vehicle", ITEM_TYPE.FUNCTION, { action: flipVehicle }), + createMenuItem("Clean Vehicle", ITEM_TYPE.FUNCTION, { action: cleanVehicle }), + createMenuItem("Maximize Performance", ITEM_TYPE.FUNCTION, { action: maxPerformance }), + createMenuItem("Delete Vehicle", ITEM_TYPE.FUNCTION, { action: deleteVehicle }), + createMenuItem("Teleport to Nearest Vehicle", ITEM_TYPE.FUNCTION, { action: teleportToNearestVehicle }) + ]; +} + +// ============================================================================ +// VEHICLE CATEGORY ITEMS +// ============================================================================ + +function getFavoriteVehicleItems() { + return [ + createMenuItem("Comet", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.COMET, action: spawnVehicleAction }), + createMenuItem("Turismo", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.TURISMO, action: spawnVehicleAction }), + createMenuItem("Infernus", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.INFERNUS, action: spawnVehicleAction }), + createMenuItem("Super GT", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SUPERGT, action: spawnVehicleAction }), + createMenuItem("Sultan RS", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SULTANRS, action: spawnVehicleAction }), + createMenuItem("Oracle", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.ORACLE, action: spawnVehicleAction }), + createMenuItem("Patriot", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.PATRIOT, action: spawnVehicleAction }), + createMenuItem("FBI", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.FBI, action: spawnVehicleAction }), + createMenuItem("Bus", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.BUS, action: spawnVehicleAction }), + createMenuItem("NRG 900", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.NRG900, action: spawnVehicleAction }), + createMenuItem("Maverick", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.MAVERICK, action: spawnVehicleAction }), + createMenuItem("Annihilator", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.ANNIHILATOR, action: spawnVehicleAction }) + ]; +} + +function getSportsVehicleItems() { + return [ + createMenuItem("Banshee", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.BANSHEE, action: spawnVehicleAction }), + createMenuItem("Comet", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.COMET, action: spawnVehicleAction }), + createMenuItem("Coquette", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.COQUETTE, action: spawnVehicleAction }), + createMenuItem("Feltzer", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.FELTZER, action: spawnVehicleAction }), + createMenuItem("Infernus", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.INFERNUS, action: spawnVehicleAction }), + createMenuItem("Sultan", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SULTAN, action: spawnVehicleAction }), + createMenuItem("Sultan RS", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SULTANRS, action: spawnVehicleAction }), + createMenuItem("Super GT", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SUPERGT, action: spawnVehicleAction }), + createMenuItem("Turismo", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.TURISMO, action: spawnVehicleAction }), + createMenuItem("Sentinel", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SENTINEL, action: spawnVehicleAction }) + ]; +} + +function getMuscleVehicleItems() { + return [ + createMenuItem("Buccaneer", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.BUCCANEER, action: spawnVehicleAction }), + createMenuItem("Dukes", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.DUKES, action: spawnVehicleAction }), + createMenuItem("Faction", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.FACTION, action: spawnVehicleAction }), + createMenuItem("Manana", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.MANANA, action: spawnVehicleAction }), + createMenuItem("Peyote", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.PEYOTE, action: spawnVehicleAction }), + createMenuItem("Ruiner", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.RUINER, action: spawnVehicleAction }), + createMenuItem("Sabre", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SABRE, action: spawnVehicleAction }), + createMenuItem("Stallion", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.STALION, action: spawnVehicleAction }), + createMenuItem("Vigero", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.VIGERO, action: spawnVehicleAction }), + createMenuItem("Virgo", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.VIRGO, action: spawnVehicleAction }), + createMenuItem("Voodoo", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.VOODOO, action: spawnVehicleAction }) + ]; +} + +function getSUVVehicleItems() { + return [ + createMenuItem("Bobcat", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.BOBCAT, action: spawnVehicleAction }), + createMenuItem("Cavalcade", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.CAVALCADE, action: spawnVehicleAction }), + createMenuItem("Habanero", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.HABANERO, action: spawnVehicleAction }), + createMenuItem("Huntley", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.HUNTLEY, action: spawnVehicleAction }), + createMenuItem("Landstalker", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.LANDSTALKER, action: spawnVehicleAction }), + createMenuItem("Patriot", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.PATRIOT, action: spawnVehicleAction }), + createMenuItem("Rancher", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.RANCHER, action: spawnVehicleAction }), + createMenuItem("Rebla", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.REBLA, action: spawnVehicleAction }) + ]; +} + +function getSedanVehicleItems() { + return [ + createMenuItem("Admiral", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.ADMIRAL, action: spawnVehicleAction }), + createMenuItem("Chavos", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.CHAVOS, action: spawnVehicleAction }), + createMenuItem("Cognoscenti", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.COGNOSCENTI, action: spawnVehicleAction }), + createMenuItem("Emperor", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.EMPEROR, action: spawnVehicleAction }), + createMenuItem("Esperanto", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.ESPERANTO, action: spawnVehicleAction }), + createMenuItem("Feroci", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.FEROCI, action: spawnVehicleAction }), + createMenuItem("Ingot", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.INGOT, action: spawnVehicleAction }), + createMenuItem("Intruder", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.INTRUDER, action: spawnVehicleAction }), + createMenuItem("Lokus", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.LOKUS, action: spawnVehicleAction }), + createMenuItem("Oracle", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.ORACLE, action: spawnVehicleAction }), + createMenuItem("Pinnacle", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.PINNACLE, action: spawnVehicleAction }), + createMenuItem("Premier", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.PREMIER, action: spawnVehicleAction }), + createMenuItem("Schafter", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SCHAFTER, action: spawnVehicleAction }), + createMenuItem("Washington", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.WASHINGTON, action: spawnVehicleAction }) + ]; +} + +function getEmergencyVehicleItems() { + return [ + createMenuItem("Ambulance", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.AMBULANCE, action: spawnVehicleAction }), + createMenuItem("FBI", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.FBI, action: spawnVehicleAction }), + createMenuItem("Fire Truck", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.FIRETRUK, action: spawnVehicleAction }), + createMenuItem("NOOSE", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.NOOSE, action: spawnVehicleAction }), + createMenuItem("Police", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.POLICE, action: spawnVehicleAction }), + createMenuItem("Police 2", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.POLICE2, action: spawnVehicleAction }), + createMenuItem("Police Patriot", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.POLPATRIOT, action: spawnVehicleAction }) + ]; +} + +function getBikeVehicleItems() { + return [ + createMenuItem("Faggio", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.FAGGIO, action: spawnVehicleAction }), + createMenuItem("NRG 900", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.NRG900, action: spawnVehicleAction }), + createMenuItem("PCJ", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.PCJ, action: spawnVehicleAction }), + createMenuItem("Sanchez", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SANCHEZ, action: spawnVehicleAction }), + createMenuItem("Zombie B", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.ZOMBIEB, action: spawnVehicleAction }), + createMenuItem("Hellfury", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.HELLFURY, action: spawnVehicleAction }), + createMenuItem("Bobber", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.BOBBER, action: spawnVehicleAction }) + ]; +} + +function getBoatVehicleItems() { + return [ + createMenuItem("Dinghy", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.DINGHY, action: spawnVehicleAction }), + createMenuItem("Jetmax", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.JETMAX, action: spawnVehicleAction }), + createMenuItem("Marquis", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.MARQUIS, action: spawnVehicleAction }), + createMenuItem("Predator", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.PREDATOR, action: spawnVehicleAction }), + createMenuItem("Reefer", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.REEFER, action: spawnVehicleAction }), + createMenuItem("Squalo", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SQUALO, action: spawnVehicleAction }), + createMenuItem("Tropic", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.TROPIC, action: spawnVehicleAction }), + createMenuItem("Tuga", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.TUGA, action: spawnVehicleAction }) + ]; +} + +function getHelicopterVehicleItems() { + return [ + createMenuItem("Annihilator", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.ANNIHILATOR, action: spawnVehicleAction }), + createMenuItem("Maverick", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.MAVERICK, action: spawnVehicleAction }), + createMenuItem("Police Maverick", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.POLMAV, action: spawnVehicleAction }), + createMenuItem("Tour Maverick", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.TOURMAV, action: spawnVehicleAction }) + ]; +} + +function getCommercialVehicleItems() { + return [ + createMenuItem("Benson", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.BENSON, action: spawnVehicleAction }), + createMenuItem("Boxville", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.BOXVILLE, action: spawnVehicleAction }), + createMenuItem("Burrito", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.BURRITO, action: spawnVehicleAction }), + createMenuItem("Flatbed", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.FLATBED, action: spawnVehicleAction }), + createMenuItem("Mule", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.MULE, action: spawnVehicleAction }), + createMenuItem("Packer", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.PACKER, action: spawnVehicleAction }), + createMenuItem("Phantom", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.PHANTOM, action: spawnVehicleAction }), + createMenuItem("Pony", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.PONY, action: spawnVehicleAction }), + createMenuItem("Speedo", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.SPEEDO, action: spawnVehicleAction }), + createMenuItem("Stockade", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.STOCKADE, action: spawnVehicleAction }), + createMenuItem("Yankee", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.YANKEE, action: spawnVehicleAction }), + createMenuItem("Bus", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.BUS, action: spawnVehicleAction }), + createMenuItem("Taxi", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.TAXI, action: spawnVehicleAction }), + createMenuItem("Stretch", ITEM_TYPE.VEHICLE, { vehicleModel: VEHICLE_MODELS.STRETCH, action: spawnVehicleAction }) + ]; +} + +// ============================================================================ +// TOGGLE FUNCTIONS +// ============================================================================ + +function toggleVehicleGodMode(state) { + vehicleOptions.godmode = state; + showNotification(state ? "~g~Vehicle God Mode ~s~ON" : "~r~Vehicle God Mode ~s~OFF"); +} + +function toggleSpeedBoost(state) { + vehicleOptions.speedBoost = state; + showNotification(state ? "~g~Speed Boost ~s~ON (Press Shift)" : "~r~Speed Boost ~s~OFF"); +} + +function toggleAutoFlip(state) { + vehicleOptions.autoFlip = state; + showNotification(state ? "~g~Auto Flip ~s~ON" : "~r~Auto Flip ~s~OFF"); +} + +function toggleAutoFix(state) { + vehicleOptions.autoFix = state; + showNotification(state ? "~g~Auto Repair ~s~ON" : "~r~Auto Repair ~s~OFF"); +} + +function toggleRainbow(state) { + vehicleOptions.rainbow = state; + showNotification(state ? "~g~Rainbow Car ~s~ON" : "~r~Rainbow Car ~s~OFF"); +} + +function toggleVehicleInvisible(state) { + vehicleOptions.invisible = state; + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + if (natives.IS_CHAR_IN_ANY_CAR(playerPed)) { + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + natives.SET_CAR_VISIBLE(vehicle, !state); + } + showNotification(state ? "~g~Invisible Vehicle ~s~ON" : "~r~Invisible Vehicle ~s~OFF"); +} + +// ============================================================================ +// ACTION FUNCTIONS +// ============================================================================ + +function spawnVehicleAction(modelHash) { + spawnVehicleForPlayer(modelHash); +} + +function spawnVehicleForPlayer(modelHash) { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + let pos = natives.GET_CHAR_COORDINATES(playerPed); + let heading = natives.GET_CHAR_HEADING(playerPed); + + // Request model + natives.REQUEST_MODEL(modelHash); + + // Wait for model to load + let attempts = 0; + while (!natives.HAS_MODEL_LOADED(modelHash) && attempts < 100) { + natives.WAIT(10); + attempts++; + } + + if (!natives.HAS_MODEL_LOADED(modelHash)) { + showNotification("~r~Failed to load vehicle model!"); + return null; + } + + // Calculate spawn position in front of player + let radians = heading * Math.PI / 180; + let spawnX = pos[0] - Math.sin(radians) * 5; + let spawnY = pos[1] + Math.cos(radians) * 5; + let spawnZ = pos[2]; + + // Create vehicle + let vehicle = natives.CREATE_CAR(modelHash, spawnX, spawnY, spawnZ, true, true); + + if (vehicle) { + natives.SET_CAR_HEADING(vehicle, heading); + natives.SET_CAR_ON_GROUND_PROPERLY(vehicle); + + // Get vehicle display name + let vehName = natives.GET_DISPLAY_NAME_FROM_VEHICLE_MODEL(modelHash); + let displayName = natives.GET_STRING_FROM_TEXT_FILE(vehName) || "Vehicle"; + + showNotification("~g~Spawned: ~s~" + displayName); + } + + // Mark model as no longer needed + natives.MARK_MODEL_AS_NO_LONGER_NEEDED(modelHash); + + return vehicle; +} + +function repairVehicle() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + if (!natives.IS_CHAR_IN_ANY_CAR(playerPed)) { + showNotification("~r~You are not in a vehicle!"); + return; + } + + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + natives.FIX_CAR(vehicle); + natives.SET_CAR_ENGINE_ON(vehicle, true, true); + showNotification("~g~Vehicle repaired!"); +} + +function flipVehicle() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + if (!natives.IS_CHAR_IN_ANY_CAR(playerPed)) { + showNotification("~r~You are not in a vehicle!"); + return; + } + + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + let heading = natives.GET_CAR_HEADING(vehicle); + natives.SET_VEHICLE_QUATERNION(vehicle, 0, 0, 0, 0); + natives.SET_CAR_HEADING(vehicle, heading); + natives.SET_CAR_ON_GROUND_PROPERLY(vehicle); + showNotification("~g~Vehicle flipped!"); +} + +function cleanVehicle() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + if (!natives.IS_CHAR_IN_ANY_CAR(playerPed)) { + showNotification("~r~You are not in a vehicle!"); + return; + } + + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + natives.SET_VEHICLE_DIRT_LEVEL(vehicle, 0); + showNotification("~g~Vehicle cleaned!"); +} + +function maxPerformance() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + if (!natives.IS_CHAR_IN_ANY_CAR(playerPed)) { + showNotification("~r~You are not in a vehicle!"); + return; + } + + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + // Set max performance (if supported) + natives.FIX_CAR(vehicle); + natives.SET_CAR_ENGINE_ON(vehicle, true, true); + showNotification("~g~Vehicle maxed out!"); +} + +function deleteVehicle() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + if (!natives.IS_CHAR_IN_ANY_CAR(playerPed)) { + showNotification("~r~You are not in a vehicle!"); + return; + } + + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + + // Eject player first + natives.TASK_LEAVE_CAR_IMMEDIATELY(playerPed, vehicle); + natives.WAIT(500); + + natives.DELETE_CAR(vehicle); + showNotification("~g~Vehicle deleted!"); +} + +function teleportToNearestVehicle() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + let pos = natives.GET_CHAR_COORDINATES(playerPed); + + let vehicle = natives.GET_CLOSEST_CAR(pos[0], pos[1], pos[2], 100.0, false, 70); + + if (vehicle && natives.DOES_VEHICLE_EXIST(vehicle)) { + natives.WARP_CHAR_INTO_CAR(playerPed, vehicle); + showNotification("~g~Teleported to nearest vehicle!"); + } else { + showNotification("~r~No vehicle found nearby!"); + } +} + +// ============================================================================ +// VEHICLE OPTIONS LOOP +// ============================================================================ + +let rainbowColor = 0; + +function vehicleOptionsLoop() { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + if (!natives.IS_CHAR_IN_ANY_CAR(playerPed)) return; + + let vehicle = natives.GET_CAR_CHAR_IS_USING(playerPed); + + // Vehicle God Mode + if (vehicleOptions.godmode) { + natives.SET_CAR_CAN_BE_DAMAGED(vehicle, false); + natives.SET_CAR_CAN_BE_VISIBLY_DAMAGED(vehicle, false); + let health = natives.GET_CAR_HEALTH(vehicle); + if (health < 1000) { + natives.SET_CAR_HEALTH(vehicle, 1000); + } + } + + // Speed Boost + if (vehicleOptions.speedBoost) { + if (natives.IS_GAME_KEYBOARD_KEY_PRESSED(0x10)) { // Shift + natives.APPLY_FORCE_TO_CAR(vehicle, true, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0, true, true, true, true); + } + } + + // Auto Flip + if (vehicleOptions.autoFlip) { + if (!natives.IS_CAR_UPRIGHT(vehicle)) { + let heading = natives.GET_CAR_HEADING(vehicle); + natives.SET_VEHICLE_QUATERNION(vehicle, 0, 0, 0, 0); + natives.SET_CAR_HEADING(vehicle, heading); + natives.SET_CAR_ON_GROUND_PROPERLY(vehicle); + } + } + + // Auto Fix + if (vehicleOptions.autoFix) { + let health = natives.GET_CAR_HEALTH(vehicle); + if (health < 800) { + natives.FIX_CAR(vehicle); + } + } + + // Rainbow Car + if (vehicleOptions.rainbow) { + rainbowColor = (rainbowColor + 1) % 134; + natives.CHANGE_CAR_COLOUR(vehicle, rainbowColor, rainbowColor); + } + + // Invisible Vehicle (maintain state) + if (vehicleOptions.invisible) { + natives.SET_CAR_VISIBLE(vehicle, false); + } +} + +// ============================================================================ +// EVENT HANDLERS +// ============================================================================ + +addEventHandler("OnProcess", function(event) { + vehicleOptionsLoop(); +}); + +// ============================================================================ +// EXPORTS +// ============================================================================ + +this.vehicleOptions = vehicleOptions; +this.getVehicleMenuItems = getVehicleMenuItems; +this.getFavoriteVehicleItems = getFavoriteVehicleItems; +this.getSportsVehicleItems = getSportsVehicleItems; +this.getMuscleVehicleItems = getMuscleVehicleItems; +this.getSUVVehicleItems = getSUVVehicleItems; +this.getSedanVehicleItems = getSedanVehicleItems; +this.getEmergencyVehicleItems = getEmergencyVehicleItems; +this.getBikeVehicleItems = getBikeVehicleItems; +this.getBoatVehicleItems = getBoatVehicleItems; +this.getHelicopterVehicleItems = getHelicopterVehicleItems; +this.getCommercialVehicleItems = getCommercialVehicleItems; +this.spawnVehicleForPlayer = spawnVehicleForPlayer; diff --git a/Trident/weapon.js b/Trident/weapon.js new file mode 100644 index 0000000..0e25685 --- /dev/null +++ b/Trident/weapon.js @@ -0,0 +1,286 @@ +/** + * MD TRIDENT - Weapon Options Module + * GTAConnected Port for GTA IV + */ + +// ============================================================================ +// WEAPON HASHES (GTA IV) +// ============================================================================ + +const WEAPONS = { + // Melee + UNARMED: 0, + BASEBALLBAT: 1, + POOLCUE: 2, + KNIFE: 3, + + // Handguns + GLOCK: 4, + DESERTEAGLE: 5, + PISTOL44: 6, + + // SMGs + MICRO_UZI: 7, + MP5: 8, + SMG: 9, + + // Shotguns + SAWNOFF: 10, + BARETTA: 11, + COMBATSHOTGUN: 12, + + // Rifles + M4: 13, + AK47: 14, + + // Snipers + SNIPER: 15, + M40A1: 16, + PSG1: 17, + + // Heavy + RPG: 18, + + // Thrown + GRENADE: 16, + MOLOTOV: 17 +}; + +// ============================================================================ +// WEAPON OPTIONS STATE +// ============================================================================ + +let weaponOptions = { + infiniteAmmo: false, + rapidFire: false, + explosiveAmmo: false, + oneHitKill: false +}; + +// ============================================================================ +// WEAPON MENU ITEMS +// ============================================================================ + +function getWeaponMenuItems() { + return [ + createMenuItem("~~ WEAPON OPTIONS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Infinite Ammo", ITEM_TYPE.BOOL, { + boolState: weaponOptions.infiniteAmmo, + action: toggleInfiniteAmmo + }), + createMenuItem("Rapid Fire", ITEM_TYPE.BOOL, { + boolState: weaponOptions.rapidFire, + action: toggleRapidFire + }), + createMenuItem("Explosive Ammo", ITEM_TYPE.BOOL, { + boolState: weaponOptions.explosiveAmmo, + action: toggleExplosiveAmmo + }), + createMenuItem("One Hit Kill", ITEM_TYPE.BOOL, { + boolState: weaponOptions.oneHitKill, + action: toggleOneHitKill + }), + + createMenuItem("~~ GIVE WEAPONS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Give All Weapons", ITEM_TYPE.FUNCTION, { action: giveAllWeaponsAction }), + createMenuItem("Give Handguns", ITEM_TYPE.FUNCTION, { action: giveHandguns }), + createMenuItem("Give SMGs", ITEM_TYPE.FUNCTION, { action: giveSMGs }), + createMenuItem("Give Shotguns", ITEM_TYPE.FUNCTION, { action: giveShotguns }), + createMenuItem("Give Rifles", ITEM_TYPE.FUNCTION, { action: giveRifles }), + createMenuItem("Give Snipers", ITEM_TYPE.FUNCTION, { action: giveSnipers }), + createMenuItem("Give Heavy Weapons", ITEM_TYPE.FUNCTION, { action: giveHeavy }), + createMenuItem("Give Thrown Weapons", ITEM_TYPE.FUNCTION, { action: giveThrown }), + createMenuItem("Give Melee Weapons", ITEM_TYPE.FUNCTION, { action: giveMelee }), + + createMenuItem("~~ AMMO ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Max Ammo All Weapons", ITEM_TYPE.FUNCTION, { action: maxAmmoAllWeapons }), + createMenuItem("Remove All Weapons", ITEM_TYPE.FUNCTION, { action: removeAllWeaponsAction }), + + createMenuItem("~~ INDIVIDUAL WEAPONS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Spawn: Baseball Bat", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.BASEBALLBAT) }), + createMenuItem("Spawn: Knife", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.KNIFE) }), + createMenuItem("Spawn: Glock", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.GLOCK) }), + createMenuItem("Spawn: Desert Eagle", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.DESERTEAGLE) }), + createMenuItem("Spawn: Micro Uzi", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.MICRO_UZI) }), + createMenuItem("Spawn: MP5", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.MP5) }), + createMenuItem("Spawn: Sawn-off", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.SAWNOFF) }), + createMenuItem("Spawn: Combat Shotgun", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.COMBATSHOTGUN) }), + createMenuItem("Spawn: M4", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.M4) }), + createMenuItem("Spawn: AK-47", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.AK47) }), + createMenuItem("Spawn: Sniper Rifle", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.SNIPER) }), + createMenuItem("Spawn: RPG", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.RPG) }), + createMenuItem("Spawn: Grenades", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.GRENADE) }), + createMenuItem("Spawn: Molotovs", ITEM_TYPE.FUNCTION, { action: () => giveWeapon(WEAPONS.MOLOTOV) }) + ]; +} + +// ============================================================================ +// TOGGLE FUNCTIONS +// ============================================================================ + +function toggleInfiniteAmmo(state) { + weaponOptions.infiniteAmmo = state; + showNotification(state ? "~g~Infinite Ammo ~s~ON" : "~r~Infinite Ammo ~s~OFF"); +} + +function toggleRapidFire(state) { + weaponOptions.rapidFire = state; + showNotification(state ? "~g~Rapid Fire ~s~ON" : "~r~Rapid Fire ~s~OFF"); +} + +function toggleExplosiveAmmo(state) { + weaponOptions.explosiveAmmo = state; + showNotification(state ? "~g~Explosive Ammo ~s~ON" : "~r~Explosive Ammo ~s~OFF"); +} + +function toggleOneHitKill(state) { + weaponOptions.oneHitKill = state; + showNotification(state ? "~g~One Hit Kill ~s~ON" : "~r~One Hit Kill ~s~OFF"); +} + +// ============================================================================ +// WEAPON FUNCTIONS +// ============================================================================ + +function giveWeapon(weaponId, ammo = 9999) { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.GIVE_WEAPON_TO_CHAR(playerPed, weaponId, ammo, false); + showNotification("~g~Weapon given!"); +} + +function giveAllWeaponsAction() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + let episode = natives.GET_CURRENT_EPISODE(); + natives.GIVE_EPISODIC_WEAPONS_TO_CHAR(playerPed, episode); + showNotification("~g~All weapons given!"); +} + +function giveHandguns() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.GLOCK, 9999, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.DESERTEAGLE, 9999, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.PISTOL44, 9999, false); + showNotification("~g~Handguns given!"); +} + +function giveSMGs() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.MICRO_UZI, 9999, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.MP5, 9999, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.SMG, 9999, false); + showNotification("~g~SMGs given!"); +} + +function giveShotguns() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.SAWNOFF, 9999, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.BARETTA, 9999, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.COMBATSHOTGUN, 9999, false); + showNotification("~g~Shotguns given!"); +} + +function giveRifles() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.M4, 9999, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.AK47, 9999, false); + showNotification("~g~Rifles given!"); +} + +function giveSnipers() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.SNIPER, 9999, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.M40A1, 9999, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.PSG1, 9999, false); + showNotification("~g~Sniper rifles given!"); +} + +function giveHeavy() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.RPG, 9999, false); + showNotification("~g~Heavy weapons given!"); +} + +function giveThrown() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.GRENADE, 25, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.MOLOTOV, 25, false); + showNotification("~g~Thrown weapons given!"); +} + +function giveMelee() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.BASEBALLBAT, 1, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.POOLCUE, 1, false); + natives.GIVE_WEAPON_TO_CHAR(playerPed, WEAPONS.KNIFE, 1, false); + showNotification("~g~Melee weapons given!"); +} + +function maxAmmoAllWeapons() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + + // Add ammo to all weapon types + for (let weaponId = 1; weaponId <= 18; weaponId++) { + if (natives.HAS_CHAR_GOT_WEAPON(playerPed, weaponId)) { + natives.ADD_AMMO_TO_CHAR(playerPed, weaponId, 9999); + } + } + + showNotification("~g~Max ammo added to all weapons!"); +} + +function removeAllWeaponsAction() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.REMOVE_ALL_CHAR_WEAPONS(playerPed); + showNotification("~r~All weapons removed!"); +} + +// ============================================================================ +// WEAPON OPTIONS LOOP +// ============================================================================ + +function weaponOptionsLoop() { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + + if (!natives.DOES_CHAR_EXIST(playerPed)) return; + + // Infinite Ammo + if (weaponOptions.infiniteAmmo && natives.IS_CHAR_SHOOTING(playerPed)) { + let weapon = natives.GET_CURRENT_CHAR_WEAPON(playerPed); + if (weapon !== WEAPONS.GRENADE && weapon !== WEAPONS.MOLOTOV) { + let maxAmmo = natives.GET_MAX_AMMO_IN_CLIP(playerPed, weapon); + if (maxAmmo) { + natives.SET_AMMO_IN_CLIP(playerPed, weapon, maxAmmo); + } + } + } + + // Explosive Ammo + if (weaponOptions.explosiveAmmo && natives.IS_CHAR_SHOOTING(playerPed)) { + let weapon = natives.GET_CURRENT_CHAR_WEAPON(playerPed); + if (weapon !== WEAPONS.GRENADE && weapon !== WEAPONS.MOLOTOV && weapon !== WEAPONS.RPG) { + // Get aimed position and create explosion + let aimPos = natives.GET_PED_BONE_COORDS(playerPed, 57, 0, 0, 50); + if (aimPos) { + natives.ADD_EXPLOSION(aimPos[0], aimPos[1], aimPos[2], 2, 1.0, true, false, 0.5); + } + } + } +} + +// ============================================================================ +// EVENT HANDLERS +// ============================================================================ + +addEventHandler("OnProcess", function(event) { + weaponOptionsLoop(); +}); + +// ============================================================================ +// EXPORTS +// ============================================================================ + +this.weaponOptions = weaponOptions; +this.getWeaponMenuItems = getWeaponMenuItems; +this.giveAllWeaponsAction = giveAllWeaponsAction; +this.removeAllWeaponsAction = removeAllWeaponsAction; diff --git a/Trident/world.js b/Trident/world.js new file mode 100644 index 0000000..2d14490 --- /dev/null +++ b/Trident/world.js @@ -0,0 +1,488 @@ +/** + * MD TRIDENT - World Options Module (Weather & Time) + * GTAConnected Port for GTA IV + */ + +// ============================================================================ +// WEATHER TYPES (GTA IV) +// ============================================================================ + +const WEATHER_TYPES = { + EXTRA_SUNNY: 0, + SUNNY: 1, + SUNNY_WINDY: 2, + CLOUDY: 3, + RAINING: 4, + DRIZZLE: 5, + FOGGY: 6, + THUNDERSTORM: 7, + EXTRA_SUNNY_2: 8, + SUNNY_WINDY_2: 9 +}; + +const WEATHER_NAMES = [ + "Extra Sunny", + "Sunny", + "Sunny Windy", + "Cloudy", + "Raining", + "Drizzle", + "Foggy", + "Thunderstorm", + "Extra Sunny 2", + "Sunny Windy 2" +]; + +// ============================================================================ +// WORLD OPTIONS STATE +// ============================================================================ + +let worldOptions = { + timeFrozen: false, + weatherLocked: false, + currentWeather: 1, + currentHour: 12, + currentMinute: 0 +}; + +// ============================================================================ +// WEATHER MENU ITEMS +// ============================================================================ + +function getWeatherMenuItems() { + return [ + createMenuItem("~~ TIME CONTROL ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Set Hour", ITEM_TYPE.VALUE_NUM, { + value: worldOptions.currentHour, + minValue: 0, + maxValue: 23, + action: setHour + }), + createMenuItem("Set Minute", ITEM_TYPE.VALUE_NUM, { + value: worldOptions.currentMinute, + minValue: 0, + maxValue: 59, + action: setMinute + }), + createMenuItem("Freeze Time", ITEM_TYPE.BOOL, { + boolState: worldOptions.timeFrozen, + action: toggleFreezeTime + }), + + createMenuItem("~~ QUICK TIME ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Morning (06:00)", ITEM_TYPE.FUNCTION, { action: () => setTimeQuick(6, 0) }), + createMenuItem("Noon (12:00)", ITEM_TYPE.FUNCTION, { action: () => setTimeQuick(12, 0) }), + createMenuItem("Evening (18:00)", ITEM_TYPE.FUNCTION, { action: () => setTimeQuick(18, 0) }), + createMenuItem("Midnight (00:00)", ITEM_TYPE.FUNCTION, { action: () => setTimeQuick(0, 0) }), + createMenuItem("Night (22:00)", ITEM_TYPE.FUNCTION, { action: () => setTimeQuick(22, 0) }), + + createMenuItem("~~ WEATHER CONTROL ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Select Weather", ITEM_TYPE.VALUE_STRING, { + value: worldOptions.currentWeather, + stringValues: WEATHER_NAMES, + action: setWeather + }), + createMenuItem("Lock Weather", ITEM_TYPE.BOOL, { + boolState: worldOptions.weatherLocked, + action: toggleLockWeather + }), + + createMenuItem("~~ QUICK WEATHER ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Extra Sunny", ITEM_TYPE.FUNCTION, { action: () => setWeatherQuick(WEATHER_TYPES.EXTRA_SUNNY) }), + createMenuItem("Sunny", ITEM_TYPE.FUNCTION, { action: () => setWeatherQuick(WEATHER_TYPES.SUNNY) }), + createMenuItem("Cloudy", ITEM_TYPE.FUNCTION, { action: () => setWeatherQuick(WEATHER_TYPES.CLOUDY) }), + createMenuItem("Raining", ITEM_TYPE.FUNCTION, { action: () => setWeatherQuick(WEATHER_TYPES.RAINING) }), + createMenuItem("Thunderstorm", ITEM_TYPE.FUNCTION, { action: () => setWeatherQuick(WEATHER_TYPES.THUNDERSTORM) }), + createMenuItem("Foggy", ITEM_TYPE.FUNCTION, { action: () => setWeatherQuick(WEATHER_TYPES.FOGGY) }), + createMenuItem("Drizzle", ITEM_TYPE.FUNCTION, { action: () => setWeatherQuick(WEATHER_TYPES.DRIZZLE) }), + + createMenuItem("~~ WORLD OPTIONS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Random Weather", ITEM_TYPE.FUNCTION, { action: randomWeather }), + createMenuItem("Release Weather Lock", ITEM_TYPE.FUNCTION, { action: releaseWeather }), + createMenuItem("Clear Area of Peds", ITEM_TYPE.FUNCTION, { action: clearAreaPeds }), + createMenuItem("Clear Area of Vehicles", ITEM_TYPE.FUNCTION, { action: clearAreaVehicles }) + ]; +} + +// ============================================================================ +// TIME FUNCTIONS +// ============================================================================ + +function setHour(hour) { + worldOptions.currentHour = hour; + natives.SET_TIME_OF_DAY(hour, worldOptions.currentMinute); + showNotification("~b~Time set to: ~s~" + hour.toString().padStart(2, '0') + ":" + worldOptions.currentMinute.toString().padStart(2, '0')); +} + +function setMinute(minute) { + worldOptions.currentMinute = minute; + natives.SET_TIME_OF_DAY(worldOptions.currentHour, minute); + showNotification("~b~Time set to: ~s~" + worldOptions.currentHour.toString().padStart(2, '0') + ":" + minute.toString().padStart(2, '0')); +} + +function setTimeQuick(hour, minute) { + worldOptions.currentHour = hour; + worldOptions.currentMinute = minute; + natives.SET_TIME_OF_DAY(hour, minute); + showNotification("~b~Time set to: ~s~" + hour.toString().padStart(2, '0') + ":" + minute.toString().padStart(2, '0')); +} + +function toggleFreezeTime(state) { + worldOptions.timeFrozen = state; + // In GTA IV, we control time by repeatedly setting it in the loop + showNotification(state ? "~g~Time Frozen ~s~ON" : "~r~Time Frozen ~s~OFF"); +} + +// ============================================================================ +// WEATHER FUNCTIONS +// ============================================================================ + +function setWeather(weatherIndex) { + worldOptions.currentWeather = weatherIndex; + natives.FORCE_WEATHER_NOW(weatherIndex); + showNotification("~b~Weather set to: ~s~" + WEATHER_NAMES[weatherIndex]); +} + +function setWeatherQuick(weatherType) { + worldOptions.currentWeather = weatherType; + natives.FORCE_WEATHER_NOW(weatherType); + worldOptions.weatherLocked = true; + showNotification("~b~Weather set to: ~s~" + WEATHER_NAMES[weatherType]); +} + +function toggleLockWeather(state) { + worldOptions.weatherLocked = state; + if (state) { + worldOptions.currentWeather = natives.GET_CURRENT_WEATHER() || 1; + } + showNotification(state ? "~g~Weather Locked ~s~ON" : "~r~Weather Locked ~s~OFF"); +} + +function releaseWeather() { + worldOptions.weatherLocked = false; + natives.RELEASE_WEATHER(); + showNotification("~g~Weather released!"); +} + +function randomWeather() { + let randomType = Math.floor(Math.random() * 8); + setWeatherQuick(randomType); +} + +// ============================================================================ +// WORLD CLEANUP FUNCTIONS +// ============================================================================ + +function clearAreaPeds() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + let pos = natives.GET_CHAR_COORDINATES(playerPed); + + natives.CLEAR_AREA_OF_CHARS(pos[0], pos[1], pos[2], 100.0); + showNotification("~g~Area cleared of peds!"); +} + +function clearAreaVehicles() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + let pos = natives.GET_CHAR_COORDINATES(playerPed); + + natives.CLEAR_AREA_OF_CARS(pos[0], pos[1], pos[2], 100.0); + showNotification("~g~Area cleared of vehicles!"); +} + +// ============================================================================ +// WORLD OPTIONS LOOP +// ============================================================================ + +function worldOptionsLoop() { + // Freeze Time + if (worldOptions.timeFrozen) { + natives.SET_TIME_OF_DAY(worldOptions.currentHour, worldOptions.currentMinute); + } + + // Lock Weather + if (worldOptions.weatherLocked) { + natives.FORCE_WEATHER_NOW(worldOptions.currentWeather); + } +} + +// ============================================================================ +// ADDITIONAL MENU ITEMS +// ============================================================================ + +function getModelMenuItems() { + return [ + createMenuItem("~~ PLAYER MODELS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Change to Niko", ITEM_TYPE.FUNCTION, { action: changeToNiko }), + createMenuItem("Change to Random Ped", ITEM_TYPE.FUNCTION, { action: changeToRandomPed }), + createMenuItem("Reset Model", ITEM_TYPE.FUNCTION, { action: resetModel }), + + createMenuItem("~~ PRESET MODELS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Police Officer", ITEM_TYPE.FUNCTION, { action: () => changeToModel("M_Y_COP") }), + createMenuItem("NOOSE Officer", ITEM_TYPE.FUNCTION, { action: () => changeToModel("M_Y_SWAT") }), + createMenuItem("Paramedic", ITEM_TYPE.FUNCTION, { action: () => changeToModel("M_M_PARAMEDIC") }), + createMenuItem("Fireman", ITEM_TYPE.FUNCTION, { action: () => changeToModel("M_Y_FIREMAN") }), + createMenuItem("Business Man", ITEM_TYPE.FUNCTION, { action: () => changeToModel("M_M_BUSINESSMAN") }), + createMenuItem("Homeless", ITEM_TYPE.FUNCTION, { action: () => changeToModel("M_O_HOMELESS") }), + createMenuItem("Biker", ITEM_TYPE.FUNCTION, { action: () => changeToModel("M_Y_GBIK01") }), + createMenuItem("Mafia", ITEM_TYPE.FUNCTION, { action: () => changeToModel("M_M_PRICH_01") }) + ]; +} + +function getAnimationMenuItems() { + return [ + createMenuItem("~~ ANIMATIONS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Play: Wave", ITEM_TYPE.FUNCTION, { action: () => playAnimation("amb@wave") }), + createMenuItem("Play: Cheer", ITEM_TYPE.FUNCTION, { action: () => playAnimation("amb@cheering") }), + createMenuItem("Play: Dance", ITEM_TYPE.FUNCTION, { action: () => playAnimation("amb@dancing_fem") }), + createMenuItem("Play: Sit Down", ITEM_TYPE.FUNCTION, { action: () => playAnimation("amb@sitting") }), + createMenuItem("Play: Smoking", ITEM_TYPE.FUNCTION, { action: () => playAnimation("amb@smoking") }), + createMenuItem("Play: Push Ups", ITEM_TYPE.FUNCTION, { action: () => playAnimation("amb@pushups") }), + createMenuItem("Clear Animation", ITEM_TYPE.FUNCTION, { action: clearAnimation }) + ]; +} + +function getObjectMenuItems() { + return [ + createMenuItem("~~ OBJECT SPAWNER ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Spawn: Barrel", ITEM_TYPE.FUNCTION, { action: () => spawnObject("prop_barrel_01") }), + createMenuItem("Spawn: Cone", ITEM_TYPE.FUNCTION, { action: () => spawnObject("prop_cone") }), + createMenuItem("Spawn: Ramp", ITEM_TYPE.FUNCTION, { action: () => spawnObject("prop_ramp") }), + createMenuItem("Spawn: Fence", ITEM_TYPE.FUNCTION, { action: () => spawnObject("prop_fence") }), + + createMenuItem("~~ OBJECT MANAGEMENT ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Delete Nearest Object", ITEM_TYPE.FUNCTION, { action: deleteNearestObject }), + createMenuItem("Delete All Spawned Objects", ITEM_TYPE.FUNCTION, { action: deleteAllSpawnedObjects }) + ]; +} + +function getSettingsMenuItems() { + return [ + createMenuItem("~~ MENU SETTINGS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Menu Position X", ITEM_TYPE.VALUE_NUM, { + value: Math.floor(MENU_CONFIG.posX * 100), + minValue: 0, + maxValue: 100, + action: (val) => { MENU_CONFIG.posX = val / 100; } + }), + createMenuItem("Menu Position Y", ITEM_TYPE.VALUE_NUM, { + value: Math.floor(MENU_CONFIG.posY * 100), + minValue: 0, + maxValue: 100, + action: (val) => { MENU_CONFIG.posY = val / 100; } + }), + createMenuItem("Reset Menu Position", ITEM_TYPE.FUNCTION, { action: resetMenuPosition }), + + createMenuItem("~~ GAME SETTINGS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Toggle HUD", ITEM_TYPE.FUNCTION, { action: toggleHUD }), + createMenuItem("Toggle Radar", ITEM_TYPE.FUNCTION, { action: toggleRadar }) + ]; +} + +function getCreditsMenuItems() { + return [ + createMenuItem("~~ MD TRIDENT ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Version: v13 GTAConnected Port", ITEM_TYPE.ERROR), + createMenuItem("~~ ORIGINAL AUTHORS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("DEVILSDESIGN", ITEM_TYPE.ERROR), + createMenuItem("IIV_NATHAN_VII", ITEM_TYPE.ERROR), + createMenuItem("SHOCKixiXixiWAVE", ITEM_TYPE.ERROR), + createMenuItem("~~ PORTED FOR ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("GTAConnected GTA IV Server", ITEM_TYPE.ERROR), + createMenuItem("~~ THANK YOU ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Thanks for using MD TRIDENT!", ITEM_TYPE.ERROR) + ]; +} + +function getNetworkMenuItems() { + // Get list of players for network options + let items = [ + createMenuItem("~~ NETWORK OPTIONS ~~", ITEM_TYPE.JUMPOVER), + createMenuItem("Player List", ITEM_TYPE.SUBMENU, { submenu: "player_list" }), + createMenuItem("Spectate Player", ITEM_TYPE.FUNCTION, { action: spectatePlayer }), + createMenuItem("Stop Spectating", ITEM_TYPE.FUNCTION, { action: stopSpectating }) + ]; + + return items; +} + +// ============================================================================ +// HELPER FUNCTIONS +// ============================================================================ + +function changeToModel(modelName) { + let playerId = natives.GET_PLAYER_ID(); + let modelHash = natives.GET_HASH_KEY(modelName); + + natives.REQUEST_MODEL(modelHash); + + let attempts = 0; + while (!natives.HAS_MODEL_LOADED(modelHash) && attempts < 100) { + natives.WAIT(10); + attempts++; + } + + if (natives.HAS_MODEL_LOADED(modelHash)) { + natives.CHANGE_PLAYER_MODEL(playerId, modelHash); + natives.MARK_MODEL_AS_NO_LONGER_NEEDED(modelHash); + showNotification("~g~Changed model to: ~s~" + modelName); + } else { + showNotification("~r~Failed to load model!"); + } +} + +function changeToNiko() { + changeToModel("PLAYER"); +} + +function changeToRandomPed() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.SET_CHAR_RANDOM_COMPONENT_VARIATION(playerPed); + showNotification("~g~Random variation applied!"); +} + +function resetModel() { + let playerId = natives.GET_PLAYER_ID(); + let defaultModel = natives.GET_PLAYERSETTINGS_MODEL_CHOICE(); + natives.CHANGE_PLAYER_MODEL(playerId, defaultModel); + showNotification("~g~Model reset!"); +} + +function playAnimation(animName) { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.REQUEST_ANIMS(animName); + + let attempts = 0; + while (!natives.HAVE_ANIMS_LOADED(animName) && attempts < 100) { + natives.WAIT(10); + attempts++; + } + + if (natives.HAVE_ANIMS_LOADED(animName)) { + natives.TASK_PLAY_ANIM(playerPed, animName, animName, 4.0, false, false, false, false, -1); + showNotification("~g~Playing animation!"); + } else { + showNotification("~r~Failed to load animation!"); + } +} + +function clearAnimation() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + natives.CLEAR_CHAR_TASKS(playerPed); + showNotification("~g~Animation cleared!"); +} + +let spawnedObjects = []; + +function spawnObject(objectName) { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + let pos = natives.GET_OFFSET_FROM_CHAR_IN_WORLD_COORDS(playerPed, 0, 3, 0); + + let modelHash = natives.GET_HASH_KEY(objectName); + natives.REQUEST_MODEL(modelHash); + + let attempts = 0; + while (!natives.HAS_MODEL_LOADED(modelHash) && attempts < 100) { + natives.WAIT(10); + attempts++; + } + + if (natives.HAS_MODEL_LOADED(modelHash)) { + let obj = natives.CREATE_OBJECT(modelHash, pos[0], pos[1], pos[2], true, true); + if (obj) { + spawnedObjects.push(obj); + natives.PLACE_OBJECT_ON_GROUND_PROPERLY(obj); + showNotification("~g~Object spawned!"); + } + natives.MARK_MODEL_AS_NO_LONGER_NEEDED(modelHash); + } else { + showNotification("~r~Failed to load object!"); + } +} + +function deleteNearestObject() { + let playerPed = natives.GET_PLAYER_PED(natives.GET_PLAYER_ID()); + let pos = natives.GET_CHAR_COORDINATES(playerPed); + + let obj = natives.GET_CLOSEST_OBJECT_OF_TYPE(pos[0], pos[1], pos[2], 10.0, 0, false); + if (obj && natives.DOES_OBJECT_EXIST(obj)) { + natives.DELETE_OBJECT(obj); + showNotification("~g~Object deleted!"); + } else { + showNotification("~r~No object found nearby!"); + } +} + +function deleteAllSpawnedObjects() { + for (let obj of spawnedObjects) { + if (natives.DOES_OBJECT_EXIST(obj)) { + natives.DELETE_OBJECT(obj); + } + } + spawnedObjects = []; + showNotification("~g~All spawned objects deleted!"); +} + +function resetMenuPosition() { + MENU_CONFIG.posX = 0.695; + MENU_CONFIG.posY = 0.155; + showNotification("~g~Menu position reset!"); +} + +let hudVisible = true; +function toggleHUD() { + hudVisible = !hudVisible; + natives.DISPLAY_HUD(hudVisible); + showNotification(hudVisible ? "~g~HUD Visible" : "~r~HUD Hidden"); +} + +let radarVisible = true; +function toggleRadar() { + radarVisible = !radarVisible; + natives.DISPLAY_RADAR(radarVisible); + showNotification(radarVisible ? "~g~Radar Visible" : "~r~Radar Hidden"); +} + +let spectating = false; +let spectateTarget = null; + +function spectatePlayer() { + // TODO: Implement player list selection for spectating + showNotification("~y~Select a player to spectate from Player List"); +} + +function stopSpectating() { + if (spectating) { + let playerId = natives.GET_PLAYER_ID(); + let playerPed = natives.GET_PLAYER_PED(playerId); + natives.SET_CAMERA_CONTROLS_DISABLED_WITH_PLAYER_CONTROLS(false); + natives.SET_PLAYER_CONTROL(playerId, true); + spectating = false; + spectateTarget = null; + showNotification("~g~Stopped spectating!"); + } else { + showNotification("~r~Not currently spectating!"); + } +} + +// ============================================================================ +// EVENT HANDLERS +// ============================================================================ + +addEventHandler("OnProcess", function(event) { + worldOptionsLoop(); +}); + +// ============================================================================ +// EXPORTS +// ============================================================================ + +this.worldOptions = worldOptions; +this.getWeatherMenuItems = getWeatherMenuItems; +this.getModelMenuItems = getModelMenuItems; +this.getAnimationMenuItems = getAnimationMenuItems; +this.getObjectMenuItems = getObjectMenuItems; +this.getSettingsMenuItems = getSettingsMenuItems; +this.getCreditsMenuItems = getCreditsMenuItems; +this.getNetworkMenuItems = getNetworkMenuItems; +this.setWeather = setWeather; +this.setTimeQuick = setTimeQuick;