// ============================================================================ // MD REVOLUTION MOD MENU - Client Side (MDB Trident Style) // MADE BY - DEVILSDESIGN & IIV_NATHAN_VII & SHOCKixiXixiWAVE (Original Template) // Steel Blue / Gold / Orange color scheme with flash effects // Press F5 to open/close menu, Arrow keys to navigate, Enter to select // ============================================================================ // Menu state let menuOpen = false; let currentMenu = "main"; let selectedIndex = 0; let menuStack = []; let scrollOffset = 0; // ============================================================================ // MDB TRIDENT COLOR DEFINITIONS (Exact from MDB_Template.c) // ============================================================================ const MDB = { // Primary Colors Gold: { r: 164, g: 134, b: 35 }, Steelblue: { r: 70, g: 130, b: 180 }, DevilsRed: { r: 153, g: 0, b: 0 }, Chocolate: { r: 210, g: 105, b: 30 }, // Header Colors Header: { r: 177, g: 19, b: 26 }, SubHeader: { r: 58, g: 95, b: 205 }, // Line Colors (White separator) Line: { r: 255, g: 255, b: 255 }, // Item Colors Item: { r: 180, g: 180, b: 180 }, ItemHighlight: { r: 255, g: 143, b: 0 }, ScrollItem: { r: 255, g: 255, b: 255 }, SubMenu: { r: 139, g: 134, b: 130 }, // Bool/Toggle Colors Bool: { r: 255, g: 128, b: 0 }, // JumpOver (Section headers) JumpOver: { r: 58, g: 95, b: 205 }, // Stats Colors StatsItem: { r: 255, g: 255, b: 255 }, StatsValue: { r: 255, g: 143, b: 0 }, StatsYes: { r: 204, g: 0, b: 0 }, // Red for "Yes/Active" StatsNo: { r: 0, g: 204, b: 0 }, // Green for "No/Inactive" // Alert Colors Alert: { r: 255, g: 0, b: 0 }, Ghost: { r: 0, g: 102, b: 204 }, Holy: { r: 127, g: 0, b: 255 }, // Misc Orange: { r: 255, g: 69, b: 0 }, MicTalk: { r: 255, g: 140, b: 0 }, HasMic: { r: 255, g: 255, b: 255 } }; // ============================================================================ // MDB ANIMATION STATE // ============================================================================ let animTime = 0; let smoothScrollY = 0; let targetScrollY = 0; let titlePulse = 0; let menuOpenAnim = 0; let selectedPulse = 0; let colorShift = 0; let particleTime = 0; let screenShake = 0; let flashAlpha = 0; let currentDescription = ""; // MDB Flashing/Glowing Effects (from MDB_Template.c) let FlashingGhost = 200; // Ranges 150-255, used for header text flash let FlashingGhostIncrement = true; let Glowing = 100; // Ranges 0-190, used for scrollbar glow let GlowingIncrement = true; let Rotating360 = 0; // For spinning icons let Fading_100 = 100; // Fade in effect let Fading_150 = 150; // Fade in effect let dropdown_y = 1.2; // Dropdown animation // Enhanced UI Animation State let borderGlow = 0; // Animated border glow (0-1) let borderGlowIncrement = true; let cornerPulse = 0; // Corner decoration pulse let headerWaveOffset = 0; // Header wave animation let scrollbarPulse = 0; // Scrollbar glow pulse let logoRotation = 0; // Logo rotation angle let statsUpdateTime = 0; // Stats panel update timer let particleArray = []; // Particle system let bannerShimmer = 0; // Banner shimmer effect let footerPulse = 0; // Footer pulse animation let itemHoverScale = []; // Per-item hover scale // ============================================================================ // THEME SYSTEM // ============================================================================ let currentTheme = "trident"; // Default theme - Trident style // Trident-style color scheme const themes = { // Primary Trident theme - Steel Blue with Gold/Orange accents (MDB Style) trident: { primary: { r: 70, g: 130, b: 180 }, // Steelblue accent: { r: 164, g: 134, b: 35 }, // Gold (exact MDB) highlight: { r: 255, g: 143, b: 0 }, // Item Highlight (exact MDB) name: "Trident" }, black: { primary: { r: 80, g: 80, b: 80 }, accent: { r: 150, g: 150, b: 150 }, highlight: { r: 200, g: 200, b: 200 }, name: "Black" }, red: { primary: { r: 200, g: 30, b: 30 }, accent: { r: 255, g: 80, b: 80 }, highlight: { r: 255, g: 120, b: 80 }, name: "Red" }, blue: { primary: { r: 30, g: 80, b: 200 }, accent: { r: 80, g: 150, b: 255 }, highlight: { r: 100, g: 200, b: 255 }, name: "Blue" }, green: { primary: { r: 30, g: 160, b: 60 }, accent: { r: 80, g: 220, b: 100 }, highlight: { r: 120, g: 255, b: 120 }, name: "Green" }, purple: { primary: { r: 120, g: 40, b: 180 }, accent: { r: 180, g: 100, b: 255 }, highlight: { r: 220, g: 150, b: 255 }, name: "Purple" }, pink: { primary: { r: 200, g: 60, b: 120 }, accent: { r: 255, g: 120, b: 180 }, highlight: { r: 255, g: 180, b: 200 }, name: "Pink" }, gold: { primary: { r: 180, g: 140, b: 30 }, accent: { r: 255, g: 200, b: 80 }, highlight: { r: 255, g: 220, b: 100 }, name: "Gold" }, gray: { primary: { r: 100, g: 100, b: 110 }, accent: { r: 160, g: 160, b: 170 }, highlight: { r: 200, g: 200, b: 210 }, name: "Gray" } }; function getTheme() { return themes[currentTheme] || themes.trident; } // Info bar configuration let infoBar = { height: 50 }; // Item descriptions const itemDescriptions = { // Player Options "player_god": "โšก Makes you invincible - you won't take any damage from bullets, explosions, or falls!", "player_noragdoll": "๐Ÿ›ก๏ธ Prevents your character from falling down when hit - stay on your feet always!", "player_superrun": "๐Ÿƒ Gives you super-speed running abilities - run faster than normal!", "player_neverwanted": "๐Ÿšซ Removes wanted levels permanently - police won't chase you!", "player_addhealth": "๐Ÿ’Š Restores your health to maximum - heals all injuries!", "player_addarmor": "๐Ÿ›ก๏ธ Adds full armor protection - bulletproof vest equipped!", "player_wanted": "โญ Set your wanted level from 0-6 stars - more stars = more police!", "player_teleport": "๐Ÿ“ Instantly teleport to any location on the map!", // Vehicle Options "spawn_vehicle": "๐Ÿš— Spawn any vehicle instantly - appears right next to you!", "veh_repair": "๐Ÿ”ง Fully repairs your current vehicle to 100% condition!", "veh_flip": "๐Ÿ”„ Flips your vehicle upright if it's upside down!", "veh_delete": "๐Ÿ’ฅ Removes all vehicles you spawned - clean up the streets!", "veh_color": "๐ŸŽจ Changes your vehicle's primary and secondary colors!", "veh_god": "๐Ÿ›ก๏ธ Makes your current vehicle indestructible - no damage!", "veh_neverdirty": "๐Ÿงผ Keeps your vehicle permanently clean and shiny!", "veh_nitro": "๐Ÿš€ Gives your vehicle instant speed boost - hold accelerator!", "veh_drift": "๐Ÿ Enables drift mode - slide around corners like a pro!", "veh_rainbow": "๐ŸŒˆ Makes your vehicle cycle through rainbow colors!", "veh_neon": "๐Ÿ’ก Adds neon underglow effects to your vehicle!", "veh_rpg": "๐Ÿ’ฅ Shoots RPG rockets from your vehicle - explosive ammo!", "veh_ghost": "๐Ÿ‘ป Vehicle becomes ghost - pass through everything!", "veh_flip": "๐Ÿ”„ Quick vehicle flip - gets you back on track instantly!", "veh_repair": "๐Ÿ”ง Instant full repair - no more engine damage!", "veh_siren": "๐Ÿš” Activates police sirens and emergency lights!", // Weapon Options "weapon_all": "๐Ÿ”ซ Gives you every weapon in the game - full arsenal!", "weapon_remove": "๐Ÿšซ Removes all weapons from your inventory - go peaceful!", "weapon_rpg": "๐Ÿ’ฅ Gives RPG with unlimited explosive rockets!", "weapon_sniper": "๐Ÿ”ญ Gives you a powerful sniper rifle for long-range kills!", "weapon_shotgun": "๐Ÿ”ซ Gives you a shotgun - devastating close range damage!", "weapon_machine": "๐Ÿ”ซ Gives you a machine gun - rapid fire automatic weapon!", "weapon_pistol": "๐Ÿ”ซ Gives you a pistol - reliable sidearm weapon!", "weapon_explosive": "๐Ÿ’ฃ Makes all your weapons explosive - bullets explode on impact!", // World Options "world_time": "๐Ÿ• Changes time of day - set any hour from midnight to midnight!", "world_weather": "๐ŸŒค Changes weather conditions - control rain, sun, storms!", "world_clear_area": "๐Ÿงน Clears all objects, vehicles, and peds around you!", "world_clear_vehicles": "๐Ÿš— Removes all vehicles in the area - clean streets!", "world_clear_peds": "๐Ÿšถ Removes all pedestrians in the area - empty streets!", "world_clear_objects": "๐Ÿ“ฆ Removes all objects in the area - clean environment!", "world_traffic": "๐Ÿšฆ Enables/disables traffic - control city vehicle flow!", "world_traffic_density": "๐Ÿ“Š Controls how many vehicles spawn - from empty to heavy traffic!", "world_timecycle": "๐ŸŽจ Applies visual time effects - day/night/cinematic filters!", "sky_color": "๐ŸŒˆ Changes sky color to different atmospheric effects!", // Fun Options "fun_launch": "๐Ÿš€ Launches you high into the sky - super jump effect!", "fun_superjump": "๐Ÿฆ˜ Gives you massive jumping ability - reach rooftops easily!", "fun_ragdoll": "๐Ÿคธ Makes your character go limp and fall - ragdoll physics!", "fun_explode": "๐Ÿ’ฅ Creates explosion at your position - destructive fun!", "fun_random_explosion": "๐Ÿ’ฃ Spawns random explosions nearby - chaos mode!", "fun_car_rain": "๐Ÿš— Makes vehicles rain from the sky - vehicle shower!", "fun_ped_invasion": "๐Ÿ‘ฅ Spawns many pedestrians around you - crowd control!", "fun_gang": "๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Creates a gang of armed NPCs - backup crew!", "fun_army": "โš”๏ธ Deploys military forces around you - army protection!", "fun_money_rain": "๐Ÿ’ฐ Makes money pickups fall from the sky - get rich!", "fun_weapon_shower": "๐Ÿ”ซ Drops weapons from above - weapon rain effect!", "fun_screen_shake": "๐Ÿ“ณ Shakes the screen violently - earthquake effect!", "fun_flash": "๐Ÿ’ก Creates bright camera flash - temporary blindness!", "fun_drunk": "๐Ÿบ Makes screen wobble - drunk vision effect!", "fun_matrix": "๐Ÿ’ป Matrix digital rain effect - sci-fi visual!", "fun_thermal": "๐ŸŒก๏ธ Thermal vision mode - see heat signatures!", "fun_night": "๐ŸŒ™ Night vision mode - see clearly in darkness!", // Toggle States "godMode": "๐Ÿ›ก๏ธ GOD MODE - Complete invincibility and unlimited health!", "invincible": "โšก INVINCIBLE - Cannot be killed or damaged!", "superRun": "๐Ÿƒ SUPER SPEED - Run 3x faster than normal!", "noRagdoll": "๐Ÿšถ NO RAGDOLL - Never fall down, always stay standing!", "neverWanted": "๐Ÿšซ NEVER WANTED - Police ignore you completely!", "vehGodMode": "๐Ÿ›ก๏ธ VEHICLE GOD MODE - Your car can't be destroyed!", "driveOnWater": "๐ŸŒŠ DRIVE ON WATER - Cars float and work on water!", "rainbowCar": "๐ŸŒˆ RAINBOW CAR - Vehicle cycles through all colors!", "driftMode": "๐Ÿ DRIFT MODE - Easy drifting and skidding!", "neonLights": "๐Ÿ’ก NEON LIGHTS - Glowing underglow effects!", "flyMode": "โœˆ๏ธ FLY MODE - Move freely through the air!", "vehShootRPG": "๐Ÿ’ฅ VEHICLE ROCKETS - Your car shoots explosive ammo!", "rainbowSky": "๐ŸŒˆ RAINBOW SKY - Sky cycles through rainbow colors!", "explosiveAmmo": "๐Ÿ’ฃ EXPLOSIVE AMMO - All bullets create explosions!", "moonGravity": "๐ŸŒ™ MOON GRAVITY - Low gravity physics, super jumps!", "drunkMode": "๐Ÿบ DRUNK MODE - Screen wobbles and controls reversed!", "matrixMode": "๐Ÿ’ป MATRIX MODE - Digital rain effect overlay!", "thermalVision": "๐ŸŒก๏ธ THERMAL VISION - See heat signatures in dark!", "nightVision": "๐ŸŒ™ NIGHT VISION - Enhanced vision in darkness!", // Handling Editor descriptions "handling_reset": "๐Ÿ”„ RESET - Restore all handling values to vehicle defaults!", "handling_preset": "โšก PRESET - Apply a pre-configured handling setup instantly!", "handling_set": "๐ŸŽ›๏ธ ADJUST - Modify this handling parameter value!", "handling_traction_max": "๐ŸŽ๏ธ TRACTION MAX - Maximum grip your tyres can achieve!", "handling_traction_min": "๐ŸŽ๏ธ TRACTION MIN - Minimum grip when sliding or braking!", "handling_traction_bias": "โš–๏ธ TRACTION BIAS - Front vs rear grip distribution!", "handling_traction_loss": "๐Ÿ’จ TRACTION LOSS - How easily tyres lose grip!", "handling_susp_force": "๐Ÿ”ง SUSPENSION FORCE - Spring stiffness for bumps!", "handling_susp_height": "๐Ÿ“ SUSPENSION HEIGHT - Ride height of the vehicle!", "handling_susp_damp": "๐ŸŽฏ DAMPING - Suspension bounce control!", "handling_power": "โšก ENGINE POWER - Acceleration and torque!", "handling_speed": "๐Ÿš€ TOP SPEED - Maximum velocity limit!", "handling_brake": "๐Ÿ›‘ BRAKE FORCE - Stopping power of brakes!", "handling_mass": "โš–๏ธ MASS - Vehicle weight affects grip and momentum!", "handling_com": "๐ŸŽฏ CENTER OF MASS - Affects roll and flip tendency!", "handling_steering": "๐ŸŽฎ STEERING - How far wheels can turn!" }; let matrixEffect = 0; // Font for text rendering (will be loaded on resource start) let menuFont = null; let titleFont = null; // Menu dimensions in pixels - positioned on right side const menu = { x: 1050, y: 100, width: 340, headerHeight: 60, itemHeight: 42, footerHeight: 35, maxVisibleItems: 11 }; // Player list cache let playerList = []; // Vehicle handling values let handlingMods = { grip: 1.0, acceleration: 1.0, topSpeed: 1.0, braking: 1.0 }; // ============================================================================ // HANDLING EDITOR SYSTEM // ============================================================================ let handlingEditorActive = false; let handlingEditorAnim = 0; let handlingValues = { // Traction & Grip tractionCurveMax: 2.0, tractionCurveMin: 1.8, tractionBias: 0.5, // Suspension suspensionForce: 2.0, suspensionCompDamp: 1.0, suspensionReboundDamp: 1.2, suspensionUpperLimit: 0.12, suspensionLowerLimit: -0.10, suspensionRaise: 0.0, // Engine & Speed driveForce: 0.25, driveInertia: 1.0, initialDriveMaxVel: 200.0, brakeForce: 0.8, // Mass & Weight mass: 1500.0, centreOfMassZ: 0.0, // Handling feel steeringLock: 35.0, tractionLoss: 0.8 }; // Store original values for reset let originalHandlingValues = null; // Visual feedback colors based on values let tyreGlowColors = { fr: {r:0,g:255,b:100}, fl: {r:0,g:255,b:100}, rr: {r:0,g:255,b:100}, rl: {r:0,g:255,b:100} }; let engineGlow = { r: 255, g: 100, b: 0, intensity: 0 }; let brakeGlow = { r: 255, g: 50, b: 0, intensity: 0 }; let suspensionOffset = 0; let carRotationAngle = 0; // Currently selected handling parameter for highlighting let selectedHandlingParam = ""; // ============================================================================ // MENU DATA STRUCTURE // ============================================================================ const menuData = { main: { title: "MD REVOLUTION", items: [ { label: "Self Options", action: "submenu", target: "self" }, { label: "Vehicle Spawner", action: "submenu", target: "vehicles" }, { label: "Vehicle Options", action: "submenu", target: "vehicleOptions" }, { label: "Network Options", action: "submenu", target: "network" }, { label: "Teleport Locations", action: "submenu", target: "teleport" }, { label: "World Options", action: "submenu", target: "world" }, { label: "Weapons", action: "submenu", target: "weapons" }, { label: "Fun Options", action: "submenu", target: "fun" }, { label: "--- Settings ---", action: "none" }, { label: "Mod Menu Theme", action: "submenu", target: "themes" } ] }, themes: { title: "MOD MENU THEME", items: [ { label: "Trident (Default)", action: "theme", value: "trident" }, { label: "Black", action: "theme", value: "black" }, { label: "Red", action: "theme", value: "red" }, { label: "Blue", action: "theme", value: "blue" }, { label: "Green", action: "theme", value: "green" }, { label: "Purple", action: "theme", value: "purple" }, { label: "Pink", action: "theme", value: "pink" }, { label: "Gold", action: "theme", value: "gold" }, { label: "Gray", action: "theme", value: "gray" } ] }, self: { title: "SELF OPTIONS", items: [ { label: "Restore Health", action: "self_health" }, { label: "Restore Armor", action: "self_armor" }, { label: "Max Health & Armor", action: "self_max" }, { label: "Give All Weapons", action: "self_weapons" }, { label: "Clear Wanted Level", action: "self_wanted" }, { label: "--- Toggles ---", action: "none" }, { label: "God Mode", action: "toggle", target: "godMode", state: false }, { label: "Invincible", action: "toggle", target: "invincible", state: false }, { label: "Super Run", action: "toggle", target: "superRun", state: false }, { label: "No Ragdoll", action: "toggle", target: "noRagdoll", state: false }, { label: "Never Wanted", action: "toggle", target: "neverWanted", state: false }, { label: "Invisible", action: "toggle", target: "invisible", state: false }, { label: "Infinite Sprint", action: "toggle", target: "infiniteSprint", state: false }, { label: "Freeze Position", action: "toggle", target: "freezePlayer", state: false }, { label: "--- Actions ---", action: "none" }, { label: "Set On Fire", action: "self_fire" }, { label: "Clear Tasks", action: "self_cleartasks" }, { label: "Respawn", action: "self_respawn" }, { label: "Suicide", action: "self_suicide" }, { label: "Change Skin", action: "submenu", target: "skins" } ] }, skins: { title: "PLAYER SKINS", items: [ { label: "--- Story Characters ---", action: "none" }, { label: "Niko Bellic", action: "skin", value: -1667301416 }, { label: "Roman Bellic", action: "skin", value: -163448165 }, { label: "Little Jacob", action: "skin", value: 1936355839 }, { label: "Brucie Kibbutz", action: "skin", value: -1938475496 }, { label: "Playboy X", action: "skin", value: 970234525 }, { label: "Johnny Klebitz", action: "skin", value: -1784875845 }, { label: "Luis Lopez", action: "skin", value: -1403507487 }, { label: "--- Male NPCs ---", action: "none" }, { label: "Police Officer", action: "skin", value: -1320879687 }, { label: "Doctor", action: "skin", value: 1669579652 }, { label: "Fireman", action: "skin", value: -335476819 }, { label: "Security Guard", action: "skin", value: 1581098148 }, { label: "Businessman", action: "skin", value: -1191636209 }, { label: "Street Guy", action: "skin", value: -1850653608 }, { label: "Hobo", action: "skin", value: -1183939691 }, { label: "Biker", action: "skin", value: 1830507291 }, { label: "--- Female NPCs ---", action: "none" }, { label: "Business Woman", action: "skin", value: -1847203044 }, { label: "Street Woman", action: "skin", value: -2043953294 }, { label: "Rich Woman", action: "skin", value: -1171014612 }, { label: "Shop Girl", action: "skin", value: -1611704378 }, { label: "Nurse", action: "skin", value: 1567728751 }, { label: "Tourist Woman", action: "skin", value: -1507724086 }, { label: "Jogger Woman", action: "skin", value: -1813105079 }, { label: "--- Random Skins ---", action: "none" }, { label: "Random Skin", action: "skin_random" }, { label: "Random Male", action: "skin_random_mp_boy" }, { label: "Random Female", action: "skin_random_mp_girl" } ] }, vehicles: { title: "VEHICLE SPAWNER", items: [ { label: "Sports Cars", action: "submenu", target: "veh_sports" }, { label: "Muscle Cars", action: "submenu", target: "veh_muscle" }, { label: "Sedans", action: "submenu", target: "veh_sedans" }, { label: "SUVs & Trucks", action: "submenu", target: "veh_suv" }, { label: "Compacts", action: "submenu", target: "veh_compacts" }, { label: "Motorcycles", action: "submenu", target: "veh_bikes" }, { label: "Emergency", action: "submenu", target: "veh_emergency" }, { label: "Aircraft", action: "submenu", target: "veh_aircraft" }, { label: "Boats", action: "submenu", target: "veh_boats" }, { label: "Commercial", action: "submenu", target: "veh_commercial" }, { label: "Special", action: "submenu", target: "veh_special" }, { label: "Taxis", action: "submenu", target: "veh_taxis" }, { label: "--- Vehicle Options ---", action: "none" }, { label: "Delete My Vehicles", action: "vehicle_delete" }, { label: "Repair Current", action: "veh_repair" }, { label: "Flip Current", action: "veh_flip" } ] }, veh_sports: { title: "SPORTS CARS", items: [ { label: "Infernus", action: "spawn_vehicle", value: "infernus" }, { label: "Turismo", action: "spawn_vehicle", value: "turismo" }, { label: "Comet", action: "spawn_vehicle", value: "comet" }, { label: "Banshee", action: "spawn_vehicle", value: "banshee" }, { label: "Sultan", action: "spawn_vehicle", value: "sultan" }, { label: "Coquette", action: "spawn_vehicle", value: "coquette" }, { label: "Super GT", action: "spawn_vehicle", value: "super gt" }, { label: "Sultan RS", action: "spawn_vehicle", value: "sultan rs" } ] }, veh_muscle: { title: "MUSCLE CARS", items: [ { label: "Buccaneer", action: "spawn_vehicle", value: "buccaneer" }, { label: "Dukes", action: "spawn_vehicle", value: "dukes" }, { label: "Faction", action: "spawn_vehicle", value: "faction" }, { label: "Ruiner", action: "spawn_vehicle", value: "ruiner" }, { label: "Sabre", action: "spawn_vehicle", value: "sabre" }, { label: "Sabre GT", action: "spawn_vehicle", value: "sabregt" }, { label: "Vigero", action: "spawn_vehicle", value: "vigero" }, { label: "Phoenix", action: "spawn_vehicle", value: "phoenix" } ] }, veh_suv: { title: "SUVs & TRUCKS", items: [ { label: "Patriot", action: "spawn_vehicle", value: "patriot" }, { label: "Cavalcade", action: "spawn_vehicle", value: "cavalcade" }, { label: "Huntley", action: "spawn_vehicle", value: "huntley" }, { label: "Landstalker", action: "spawn_vehicle", value: "landstalker" }, { label: "Rancher", action: "spawn_vehicle", value: "rancher" }, { label: "Bobcat", action: "spawn_vehicle", value: "bobcat" } ] }, veh_bikes: { title: "MOTORCYCLES", items: [ { label: "NRG 900", action: "spawn_vehicle", value: "nrg900" }, { label: "PCJ 600", action: "spawn_vehicle", value: "pcj" }, { label: "Sanchez", action: "spawn_vehicle", value: "sanchez" }, { label: "Faggio", action: "spawn_vehicle", value: "faggio" }, { label: "Freeway", action: "spawn_vehicle", value: "freeway" } ] }, veh_emergency: { title: "EMERGENCY", items: [ { label: "Police Cruiser", action: "spawn_vehicle", value: "police" }, { label: "Police Cruiser 2", action: "spawn_vehicle", value: "police2" }, { label: "FBI Car", action: "spawn_vehicle", value: "fbi" }, { label: "NOOSE Cruiser", action: "spawn_vehicle", value: "noose" }, { label: "Ambulance", action: "spawn_vehicle", value: "ambulance" }, { label: "Fire Truck", action: "spawn_vehicle", value: "firetruk" }, { label: "Taxi", action: "spawn_vehicle", value: "taxi" }, { label: "Stretch Limo", action: "spawn_vehicle", value: "stretch" } ] }, veh_aircraft: { title: "AIRCRAFT", items: [ { label: "Annihilator", action: "spawn_vehicle", value: "annihilator" }, { label: "Maverick", action: "spawn_vehicle", value: "maverick" }, { label: "Police Maverick", action: "spawn_vehicle", value: "polmav" }, { label: "Tour Maverick", action: "spawn_vehicle", value: "tourmav" } ] }, veh_boats: { title: "BOATS", items: [ { label: "Dinghy", action: "spawn_vehicle", value: "dinghy" }, { label: "Jetmax", action: "spawn_vehicle", value: "jetmax" }, { label: "Marquis", action: "spawn_vehicle", value: "marquis" }, { label: "Predator", action: "spawn_vehicle", value: "predator" }, { label: "Reefer", action: "spawn_vehicle", value: "reefer" }, { label: "Squalo", action: "spawn_vehicle", value: "squalo" }, { label: "Tropic", action: "spawn_vehicle", value: "tropic" }, { label: "Tuga", action: "spawn_vehicle", value: "tuga" } ] }, veh_sedans: { title: "SEDANS", items: [ { label: "Admiral", action: "spawn_vehicle", value: "admiral" }, { label: "Cavalcade", action: "spawn_vehicle", value: "cavalcade" }, { label: "Cognoscenti", action: "spawn_vehicle", value: "cognoscenti" }, { label: "Emperor", action: "spawn_vehicle", value: "emperor" }, { label: "Esperanto", action: "spawn_vehicle", value: "esperanto" }, { label: "Feroci", action: "spawn_vehicle", value: "feroci" }, { label: "Feltzer", action: "spawn_vehicle", value: "feltzer" }, { label: "Intruder", action: "spawn_vehicle", value: "intruder" }, { label: "Landstalker", action: "spawn_vehicle", value: "landstalker" }, { label: "Lokus", action: "spawn_vehicle", value: "lokus" }, { label: "Marbella", action: "spawn_vehicle", value: "marbella" }, { label: "Merit", action: "spawn_vehicle", value: "merit" }, { label: "Oracle", action: "spawn_vehicle", value: "oracle" }, { label: "Pinnacle", action: "spawn_vehicle", value: "pinnacle" }, { label: "Premiere", action: "spawn_vehicle", value: "premiere" }, { label: "Presidente", action: "spawn_vehicle", value: "presidente" }, { label: "Primo", action: "spawn_vehicle", value: "primo" }, { label: "Rebla", action: "spawn_vehicle", value: "rebla" }, { label: "Romero", action: "spawn_vehicle", value: "romero" }, { label: "Schafter", action: "spawn_vehicle", value: "schafter" }, { label: "Sentinel", action: "spawn_vehicle", value: "sentinel" }, { label: "Solair", action: "spawn_vehicle", value: "solair" }, { label: "Stratum", action: "spawn_vehicle", value: "stratum" }, { label: "Stretch", action: "spawn_vehicle", value: "stretch" }, { label: "Vincent", action: "spawn_vehicle", value: "vincent" }, { label: "Virgo", action: "spawn_vehicle", value: "virgo" }, { label: "Willard", action: "spawn_vehicle", value: "willard" }, { label: "Washington", action: "spawn_vehicle", value: "washington" } ] }, veh_compacts: { title: "COMPACTS", items: [ { label: "Blista", action: "spawn_vehicle", value: "blista" }, { label: "Futo", action: "spawn_vehicle", value: "futo" }, { label: "Ingot", action: "spawn_vehicle", value: "ingot" }, { label: "PMP 600", action: "spawn_vehicle", value: "pmp 600" }, { label: "Sultan RS", action: "spawn_vehicle", value: "sultan rs" } ] }, veh_commercial: { title: "COMMERCIAL", items: [ { label: "Airtug", action: "spawn_vehicle", value: "airtug" }, { label: "Benson", action: "spawn_vehicle", value: "benson" }, { label: "Biff", action: "spawn_vehicle", value: "biff" }, { label: "Boxville", action: "spawn_vehicle", value: "boxville" }, { label: "Burrito", action: "spawn_vehicle", value: "burrito" }, { label: "Burrito 2", action: "spawn_vehicle", value: "burrito2" }, { label: "Cabby", action: "spawn_vehicle", value: "cabby" }, { label: "Flatbed", action: "spawn_vehicle", value: "flatbed" }, { label: "Forklift", action: "spawn_vehicle", value: "forklift" }, { label: "Mule", action: "spawn_vehicle", value: "mule" }, { label: "Packer", action: "spawn_vehicle", value: "packer" }, { label: "Pony", action: "spawn_vehicle", value: "pony" }, { label: "Speedo", action: "spawn_vehicle", value: "speedo" }, { label: "Stockade", action: "spawn_vehicle", value: "stockade" }, { label: "Trashmaster", action: "spawn_vehicle", value: "trashmaster" }, { label: "Yankee", action: "spawn_vehicle", value: "yankee" } ] }, veh_special: { title: "SPECIAL VEHICLES", items: [ { label: "Mr Tasty", action: "spawn_vehicle", value: "mr tasty" }, { label: "Cablecar", action: "spawn_vehicle", value: "cablecar" }, { label: "Subway", action: "spawn_vehicle", value: "subway" }, { label: "El Train", action: "spawn_vehicle", value: "el train" } ] }, veh_taxis: { title: "TAXIS", items: [ { label: "Taxi", action: "spawn_vehicle", value: "taxi" }, { label: "Taxi 2", action: "spawn_vehicle", value: "taxi2" }, { label: "Roman's Taxi", action: "spawn_vehicle", value: "roman's taxi" } ] }, vehicleOptions: { title: "VEHICLE OPTIONS", items: [ { label: "Repair Vehicle", action: "veh_repair" }, { label: "Flip Vehicle", action: "veh_flip" }, { label: "Vehicle Colors", action: "submenu", target: "veh_colors" }, { label: "Handling Editor", action: "submenu", target: "handlingEditor" }, { label: "God Mode", action: "toggle", target: "vehGodMode", state: false }, { label: "Nitro Boost", action: "veh_nitro" }, { label: "Drive On Water", action: "toggle", target: "driveOnWater", state: false }, { label: "Rainbow Color", action: "toggle", target: "rainbowCar", state: false }, { label: "Drift Mode", action: "toggle", target: "driftMode", state: false }, { label: "Neon Lights", action: "submenu", target: "veh_neons" }, { label: "Fly Mode", action: "toggle", target: "flyMode", state: false }, { label: "Shoot RPG", action: "toggle", target: "vehShootRPG", state: false }, { label: "--- Quick Actions ---", action: "none" }, { label: "Lock Doors", action: "veh_lock" }, { label: "Unlock Doors", action: "veh_unlock" }, { label: "Toggle Engine", action: "veh_engine" }, { label: "Pop Tires", action: "veh_poptires" }, { label: "Fix Tires", action: "veh_fixtires" } ] }, handlingEditor: { title: "HANDLING EDITOR", items: [ { label: "--- Presets ---", action: "none" }, { label: "Reset to Default", action: "handling_reset" }, { label: "Race Setup", action: "handling_preset", value: "race" }, { label: "Drift Setup", action: "handling_preset", value: "drift" }, { label: "Off-Road Setup", action: "handling_preset", value: "offroad" }, { label: "Low Rider", action: "handling_preset", value: "lowrider" }, { label: "--- Traction & Grip ---", action: "none" }, { label: "Traction Max", action: "submenu", target: "handling_traction_max" }, { label: "Traction Min", action: "submenu", target: "handling_traction_min" }, { label: "Traction Bias (F/R)", action: "submenu", target: "handling_traction_bias" }, { label: "Traction Loss", action: "submenu", target: "handling_traction_loss" }, { label: "--- Suspension ---", action: "none" }, { label: "Suspension Force", action: "submenu", target: "handling_susp_force" }, { label: "Suspension Height", action: "submenu", target: "handling_susp_height" }, { label: "Suspension Damping", action: "submenu", target: "handling_susp_damp" }, { label: "--- Engine & Speed ---", action: "none" }, { label: "Engine Power", action: "submenu", target: "handling_power" }, { label: "Top Speed", action: "submenu", target: "handling_speed" }, { label: "Brake Force", action: "submenu", target: "handling_brake" }, { label: "--- Weight & Balance ---", action: "none" }, { label: "Vehicle Mass", action: "submenu", target: "handling_mass" }, { label: "Center of Mass", action: "submenu", target: "handling_com" }, { label: "--- Steering ---", action: "none" }, { label: "Steering Lock", action: "submenu", target: "handling_steering" } ] }, handling_traction_max: { title: "TRACTION MAX", items: [ { label: "Ice (0.5)", action: "handling_set", param: "tractionCurveMax", value: 0.5 }, { label: "Very Low (1.0)", action: "handling_set", param: "tractionCurveMax", value: 1.0 }, { label: "Low (1.5)", action: "handling_set", param: "tractionCurveMax", value: 1.5 }, { label: "Default (2.0)", action: "handling_set", param: "tractionCurveMax", value: 2.0 }, { label: "Medium (2.5)", action: "handling_set", param: "tractionCurveMax", value: 2.5 }, { label: "High (3.0)", action: "handling_set", param: "tractionCurveMax", value: 3.0 }, { label: "Very High (3.5)", action: "handling_set", param: "tractionCurveMax", value: 3.5 }, { label: "Racing Slicks (4.0)", action: "handling_set", param: "tractionCurveMax", value: 4.0 }, { label: "Glue (5.0)", action: "handling_set", param: "tractionCurveMax", value: 5.0 } ] }, handling_traction_min: { title: "TRACTION MIN", items: [ { label: "Ice (0.3)", action: "handling_set", param: "tractionCurveMin", value: 0.3 }, { label: "Very Low (0.8)", action: "handling_set", param: "tractionCurveMin", value: 0.8 }, { label: "Low (1.2)", action: "handling_set", param: "tractionCurveMin", value: 1.2 }, { label: "Default (1.8)", action: "handling_set", param: "tractionCurveMin", value: 1.8 }, { label: "Medium (2.2)", action: "handling_set", param: "tractionCurveMin", value: 2.2 }, { label: "High (2.8)", action: "handling_set", param: "tractionCurveMin", value: 2.8 }, { label: "Very High (3.5)", action: "handling_set", param: "tractionCurveMin", value: 3.5 } ] }, handling_traction_bias: { title: "TRACTION BIAS", items: [ { label: "Full Front (0.0)", action: "handling_set", param: "tractionBias", value: 0.0 }, { label: "Front Heavy (0.3)", action: "handling_set", param: "tractionBias", value: 0.3 }, { label: "Balanced (0.5)", action: "handling_set", param: "tractionBias", value: 0.5 }, { label: "Rear Heavy (0.7)", action: "handling_set", param: "tractionBias", value: 0.7 }, { label: "Full Rear (1.0)", action: "handling_set", param: "tractionBias", value: 1.0 } ] }, handling_traction_loss: { title: "TRACTION LOSS", items: [ { label: "No Loss (0.0)", action: "handling_set", param: "tractionLoss", value: 0.0 }, { label: "Minimal (0.4)", action: "handling_set", param: "tractionLoss", value: 0.4 }, { label: "Default (0.8)", action: "handling_set", param: "tractionLoss", value: 0.8 }, { label: "Loose (1.2)", action: "handling_set", param: "tractionLoss", value: 1.2 }, { label: "Drifty (1.6)", action: "handling_set", param: "tractionLoss", value: 1.6 }, { label: "Ice Mode (2.0)", action: "handling_set", param: "tractionLoss", value: 2.0 } ] }, handling_susp_force: { title: "SUSPENSION FORCE", items: [ { label: "Soft (0.5)", action: "handling_set", param: "suspensionForce", value: 0.5 }, { label: "Comfort (1.0)", action: "handling_set", param: "suspensionForce", value: 1.0 }, { label: "Default (2.0)", action: "handling_set", param: "suspensionForce", value: 2.0 }, { label: "Firm (3.0)", action: "handling_set", param: "suspensionForce", value: 3.0 }, { label: "Sport (4.0)", action: "handling_set", param: "suspensionForce", value: 4.0 }, { label: "Race (5.0)", action: "handling_set", param: "suspensionForce", value: 5.0 }, { label: "Rock Solid (8.0)", action: "handling_set", param: "suspensionForce", value: 8.0 } ] }, handling_susp_height: { title: "SUSPENSION HEIGHT", items: [ { label: "Slammed (-0.15)", action: "handling_set", param: "suspensionRaise", value: -0.15 }, { label: "Low (-0.10)", action: "handling_set", param: "suspensionRaise", value: -0.10 }, { label: "Lowered (-0.05)", action: "handling_set", param: "suspensionRaise", value: -0.05 }, { label: "Default (0.0)", action: "handling_set", param: "suspensionRaise", value: 0.0 }, { label: "Raised (0.05)", action: "handling_set", param: "suspensionRaise", value: 0.05 }, { label: "High (0.10)", action: "handling_set", param: "suspensionRaise", value: 0.10 }, { label: "Off-Road (0.15)", action: "handling_set", param: "suspensionRaise", value: 0.15 }, { label: "Monster (0.25)", action: "handling_set", param: "suspensionRaise", value: 0.25 } ] }, handling_susp_damp: { title: "SUSPENSION DAMPING", items: [ { label: "Bouncy (0.3)", action: "handling_set", param: "suspensionCompDamp", value: 0.3 }, { label: "Soft (0.6)", action: "handling_set", param: "suspensionCompDamp", value: 0.6 }, { label: "Default (1.0)", action: "handling_set", param: "suspensionCompDamp", value: 1.0 }, { label: "Sport (1.5)", action: "handling_set", param: "suspensionCompDamp", value: 1.5 }, { label: "Race (2.0)", action: "handling_set", param: "suspensionCompDamp", value: 2.0 }, { label: "Stiff (3.0)", action: "handling_set", param: "suspensionCompDamp", value: 3.0 } ] }, handling_power: { title: "ENGINE POWER", items: [ { label: "Weak (0.10)", action: "handling_set", param: "driveForce", value: 0.10 }, { label: "Low (0.18)", action: "handling_set", param: "driveForce", value: 0.18 }, { label: "Default (0.25)", action: "handling_set", param: "driveForce", value: 0.25 }, { label: "Tuned (0.35)", action: "handling_set", param: "driveForce", value: 0.35 }, { label: "Sport (0.45)", action: "handling_set", param: "driveForce", value: 0.45 }, { label: "Super (0.60)", action: "handling_set", param: "driveForce", value: 0.60 }, { label: "Hyper (0.80)", action: "handling_set", param: "driveForce", value: 0.80 }, { label: "Rocket (1.20)", action: "handling_set", param: "driveForce", value: 1.20 } ] }, handling_speed: { title: "TOP SPEED", items: [ { label: "Slow (100)", action: "handling_set", param: "initialDriveMaxVel", value: 100.0 }, { label: "City (140)", action: "handling_set", param: "initialDriveMaxVel", value: 140.0 }, { label: "Default (200)", action: "handling_set", param: "initialDriveMaxVel", value: 200.0 }, { label: "Fast (250)", action: "handling_set", param: "initialDriveMaxVel", value: 250.0 }, { label: "Super (300)", action: "handling_set", param: "initialDriveMaxVel", value: 300.0 }, { label: "Hyper (400)", action: "handling_set", param: "initialDriveMaxVel", value: 400.0 }, { label: "Insane (500)", action: "handling_set", param: "initialDriveMaxVel", value: 500.0 } ] }, handling_brake: { title: "BRAKE FORCE", items: [ { label: "Weak (0.3)", action: "handling_set", param: "brakeForce", value: 0.3 }, { label: "Low (0.5)", action: "handling_set", param: "brakeForce", value: 0.5 }, { label: "Default (0.8)", action: "handling_set", param: "brakeForce", value: 0.8 }, { label: "Strong (1.2)", action: "handling_set", param: "brakeForce", value: 1.2 }, { label: "Race (1.6)", action: "handling_set", param: "brakeForce", value: 1.6 }, { label: "Ceramic (2.0)", action: "handling_set", param: "brakeForce", value: 2.0 }, { label: "Instant Stop (3.0)", action: "handling_set", param: "brakeForce", value: 3.0 } ] }, handling_mass: { title: "VEHICLE MASS", items: [ { label: "Feather (500)", action: "handling_set", param: "mass", value: 500.0 }, { label: "Light (1000)", action: "handling_set", param: "mass", value: 1000.0 }, { label: "Default (1500)", action: "handling_set", param: "mass", value: 1500.0 }, { label: "Heavy (2000)", action: "handling_set", param: "mass", value: 2000.0 }, { label: "Truck (3000)", action: "handling_set", param: "mass", value: 3000.0 }, { label: "Tank (5000)", action: "handling_set", param: "mass", value: 5000.0 } ] }, handling_com: { title: "CENTER OF MASS", items: [ { label: "Very Low (-0.3)", action: "handling_set", param: "centreOfMassZ", value: -0.3 }, { label: "Low (-0.15)", action: "handling_set", param: "centreOfMassZ", value: -0.15 }, { label: "Default (0.0)", action: "handling_set", param: "centreOfMassZ", value: 0.0 }, { label: "High (0.15)", action: "handling_set", param: "centreOfMassZ", value: 0.15 }, { label: "Very High (0.3)", action: "handling_set", param: "centreOfMassZ", value: 0.3 } ] }, handling_steering: { title: "STEERING LOCK", items: [ { label: "Tight (25)", action: "handling_set", param: "steeringLock", value: 25.0 }, { label: "Default (35)", action: "handling_set", param: "steeringLock", value: 35.0 }, { label: "Loose (45)", action: "handling_set", param: "steeringLock", value: 45.0 }, { label: "Wide (55)", action: "handling_set", param: "steeringLock", value: 55.0 }, { label: "Extreme (70)", action: "handling_set", param: "steeringLock", value: 70.0 } ] }, veh_neons: { title: "NEON LIGHTS", items: [ { label: "Toggle Neons", action: "toggle", target: "neonLights", state: false }, { label: "Red Neons", action: "neon_color", value: { r: 255, g: 0, b: 0 } }, { label: "Blue Neons", action: "neon_color", value: { r: 0, g: 100, b: 255 } }, { label: "Green Neons", action: "neon_color", value: { r: 0, g: 255, b: 0 } }, { label: "Purple Neons", action: "neon_color", value: { r: 255, g: 0, b: 255 } }, { label: "Pink Neons", action: "neon_color", value: { r: 255, g: 100, b: 200 } }, { label: "Yellow Neons", action: "neon_color", value: { r: 255, g: 255, b: 0 } }, { label: "White Neons", action: "neon_color", value: { r: 255, g: 255, b: 255 } }, { label: "Cyan Neons", action: "neon_color", value: { r: 0, g: 255, b: 255 } }, { label: "Orange Neons", action: "neon_color", value: { r: 255, g: 150, b: 0 } } ] }, veh_colors: { title: "VEHICLE COLORS", items: [ { label: "Black", action: "veh_color", value: [0, 0] }, { label: "White", action: "veh_color", value: [18, 18] }, { label: "Dark Gray", action: "veh_color", value: [4, 4] }, { label: "Light Gray", action: "veh_color", value: [8, 8] }, { label: "Silver", action: "veh_color", value: [12, 12] }, { label: "Red", action: "veh_color", value: [27, 27] }, { label: "Dark Red", action: "veh_color", value: [28, 28] }, { label: "Candy Red", action: "veh_color", value: [30, 30] }, { label: "Orange", action: "veh_color", value: [36, 36] }, { label: "Yellow", action: "veh_color", value: [89, 89] }, { label: "Bright Yellow", action: "veh_color", value: [91, 91] }, { label: "Green", action: "veh_color", value: [50, 50] }, { label: "Dark Green", action: "veh_color", value: [52, 52] }, { label: "Lime Green", action: "veh_color", value: [55, 55] }, { label: "Blue", action: "veh_color", value: [62, 62] }, { label: "Dark Blue", action: "veh_color", value: [64, 64] }, { label: "Light Blue", action: "veh_color", value: [73, 73] }, { label: "Bright Blue", action: "veh_color", value: [82, 82] }, { label: "Purple", action: "veh_color", value: [99, 99] }, { label: "Pink", action: "veh_color", value: [100, 100] }, { label: "Hot Pink", action: "veh_color", value: [101, 101] }, { label: "Brown", action: "veh_color", value: [45, 45] }, { label: "Beige", action: "veh_color", value: [44, 44] }, { label: "Gold", action: "veh_color", value: [37, 37] }, { label: "--- Two Tone ---", action: "none" }, { label: "Black/Red", action: "veh_color", value: [0, 27] }, { label: "Black/White", action: "veh_color", value: [0, 18] }, { label: "Red/Black", action: "veh_color", value: [27, 0] }, { label: "Blue/White", action: "veh_color", value: [62, 18] }, { label: "Green/White", action: "veh_color", value: [50, 18] }, { label: "Random", action: "veh_color_random" } ] }, network: { title: "NETWORK OPTIONS", items: [ { label: "Refresh Player List", action: "refresh_players" }, { label: "--- Players ---", action: "none" } ] }, teleport: { title: "TELEPORT LOCATIONS", items: [ { label: "Star Junction", action: "teleport", value: { x: -252.0, y: 947.0, z: 15.0 } }, { label: "Middle Park", action: "teleport", value: { x: -365.0, y: 1163.0, z: 14.0 } }, { label: "Airport", action: "teleport", value: { x: 2140.0, y: 465.0, z: 6.0 } }, { label: "Broker Bridge", action: "teleport", value: { x: 932.0, y: -495.0, z: 15.0 } }, { label: "Alderney City", action: "teleport", value: { x: -1149.0, y: 380.0, z: 21.0 } }, { label: "Happiness Island", action: "teleport", value: { x: -722.0, y: -17.0, z: 3.0 } } ] }, world: { title: "WORLD OPTIONS", items: [ { label: "--- Time Control ---", action: "none" }, { label: "Dawn (5:00)", action: "world_time", value: 5 }, { label: "Morning (8:00)", action: "world_time", value: 8 }, { label: "Noon (12:00)", action: "world_time", value: 12 }, { label: "Afternoon (15:00)", action: "world_time", value: 15 }, { label: "Evening (18:00)", action: "world_time", value: 18 }, { label: "Dusk (20:00)", action: "world_time", value: 20 }, { label: "Night (0:00)", action: "world_time", value: 0 }, { label: "Midnight (23:00)", action: "world_time", value: 23 }, { label: "--- Weather Control ---", action: "none" }, { label: "Sunny/Clear", action: "world_weather", value: 1 }, { label: "Cloudy", action: "world_weather", value: 3 }, { label: "Overcast", action: "world_weather", value: 2 }, { label: "Light Rain", action: "world_weather", value: 4 }, { label: "Heavy Rain", action: "world_weather", value: 5 }, { label: "Thunderstorm", action: "world_weather", value: 7 }, { label: "Foggy", action: "world_weather", value: 6 }, { label: "Snowy", action: "world_weather", value: 8 }, { label: "--- Environment ---(WIP)", action: "none" }, { label: "Clear Area", action: "world_clear_area" }, { label: "Clear Vehicles", action: "world_clear_vehicles" }, { label: "Clear Peds", action: "world_clear_peds" }, { label: "Clear Objects", action: "world_clear_objects" }, { label: "Traffic ON", action: "world_traffic", value: true }, { label: "Traffic OFF", action: "world_traffic", value: false }, { label: "Set Traffic Density", action: "submenu", target: "world_traffic_density" }, { label: "--- Visual Effects ---(WIP)", action: "none" }, { label: "Rainbow Sky", action: "toggle", target: "rainbowSky", state: false }, { label: "Sky Colors", action: "submenu", target: "sky_colors" }, { label: "Timecycle Modifier", action: "submenu", target: "world_timecycles" } ] }, sky_colors: { title: "SKY COLORS (WIP)", items: [ { label: "Default Sky", action: "sky_color", value: 0 }, { label: "Red Sky", action: "sky_color", value: 1 }, { label: "Blue Sky", action: "sky_color", value: 2 }, { label: "Green Sky", action: "sky_color", value: 3 }, { label: "Purple Sky", action: "sky_color", value: 4 }, { label: "Orange Sky", action: "sky_color", value: 5 }, { label: "Pink Sky", action: "sky_color", value: 6 }, { label: "Yellow Sky", action: "sky_color", value: 7 }, { label: "Cyan Sky", action: "sky_color", value: 8 }, { label: "Black Sky", action: "sky_color", value: 9 }, { label: "White Sky", action: "sky_color", value: 10 } ] }, world_traffic_density: { title: "TRAFFIC DENSITY(WIP)", items: [ { label: "No Traffic", action: "world_traffic_density", value: 0.0 }, { label: "Very Light", action: "world_traffic_density", value: 0.2 }, { label: "Light", action: "world_traffic_density", value: 0.4 }, { label: "Normal", action: "world_traffic_density", value: 0.6 }, { label: "Heavy", action: "world_traffic_density", value: 0.8 }, { label: "Very Heavy", action: "world_traffic_density", value: 1.0 }, { label: "Maximum", action: "world_traffic_density", value: 1.5 } ] }, world_timecycles: { title: "TIMECYCLE MODIFIERS", items: [ { label: "Default", action: "world_timecycle", value: "default" }, { label: "Bright", action: "world_timecycle", value: "bright" }, { label: "Dark", action: "world_timecycle", value: "dark" }, { label: "Foggy", action: "world_timecycle", value: "foggy" }, { label: "Hazy", action: "world_timecycle", value: "hazy" }, { label: "Night", action: "world_timecycle", value: "night" }, { label: "Sunset", action: "world_timecycle", value: "sunset" }, { label: "Sunrise", action: "world_timecycle", value: "sunrise" }, { label: "Clear Modifier", action: "world_timecycle_clear" } ] }, weapons: { title: "WEAPONS", items: [ { label: "Get All Weapons", action: "weapon_all" }, { label: "Remove All Weapons", action: "weapon_remove" }, { label: "--- Weapon Toggles ---", action: "none" }, { label: "Unlimited Ammo", action: "toggle", target: "unlimitedAmmo", state: false }, { label: "No Reload", action: "toggle", target: "noReload", state: false }, { label: "Explosive Ammo", action: "toggle", target: "explosiveAmmo", state: false }, { label: "Fire Bullets", action: "toggle", target: "fireBullets", state: false }, { label: "--- Give Weapon ---", action: "none" }, { label: "Baseball Bat", action: "weapon", value: 2 }, { label: "Knife", action: "weapon", value: 3 }, { label: "Grenades", action: "weapon", value: 4 }, { label: "Pistol", action: "weapon", value: 5 }, { label: "Desert Eagle", action: "weapon", value: 6 }, { label: "Shotgun", action: "weapon", value: 9 }, { label: "SMG", action: "weapon", value: 12 }, { label: "Assault Rifle", action: "weapon", value: 14 }, { label: "Sniper Rifle", action: "weapon", value: 16 }, { label: "RPG", action: "weapon", value: 18 } ] }, fun: { title: "FUN OPTIONS", items: [ { label: "--- Physics Fun ---", action: "none" }, { label: "Launch Me Up", action: "fun_launch" }, { label: "Super Jump", action: "fun_superjump" }, { label: "Moon Gravity", action: "toggle", target: "moonGravity", state: false }, { label: "Drunk Mode", action: "toggle", target: "drunkMode", state: false }, { label: "Spinbot", action: "toggle", target: "spinbot", state: false }, { label: "Ragdoll", action: "fun_ragdoll" }, { label: "--- Chaos Mode ---(WIP)", action: "none" }, { label: "Explode Me", action: "fun_explode" }, { label: "Random Explosion", action: "fun_random_explosion" }, { label: "Car Rain", action: "fun_car_rain" }, { label: "Ped Invasion", action: "fun_ped_invasion" }, { label: "Weapon Shower", action: "fun_weapon_shower" }, { label: "--- Spawning ---(WIP)", action: "none" }, { label: "Spawn Random Ped", action: "fun_ped" }, { label: "Spawn Gang", action: "fun_gang" }, { label: "Spawn Army", action: "fun_army" }, { label: "Spawn Money Rain", action: "fun_money_rain" }, { label: "--- Visual Effects ---(WIP)", action: "none" }, { label: "Screen Shake", action: "fun_screen_shake" }, { label: "Flash Screen", action: "fun_flash" }, { label: "Matrix Mode", action: "toggle", target: "matrixMode", state: false }, { label: "Thermal Vision", action: "toggle", target: "thermalVision", state: false }, { label: "Night Vision", action: "toggle", target: "nightVision", state: false } ] } }; // Enhanced toggle states let toggleStates = { godMode: false, invincible: false, superRun: false, noRagdoll: false, neverWanted: false, invisible: false, infiniteSprint: false, freezePlayer: false, vehGodMode: false, driveOnWater: false, rainbowCar: false, driftMode: false, neonLights: false, flyMode: false, vehShootRPG: false, rainbowSky: false, explosiveAmmo: false, unlimitedAmmo: false, noReload: false, fireBullets: false, moonGravity: false, drunkMode: false, spinbot: false, matrixMode: false, thermalVision: false, nightVision: false }; // Neon objects storage let neonObjects = []; let neonColor = { r: 255, g: 0, b: 255 }; // Default purple // Rainbow color cycling let rainbowHue = 0; let skyColorIndex = 0; // Sky colors for selection const skyColors = [ { name: "Default", r: -1, g: -1, b: -1 }, { name: "Red", r: 255, g: 50, b: 50 }, { name: "Blue", r: 50, g: 100, b: 255 }, { name: "Green", r: 50, g: 255, b: 100 }, { name: "Purple", r: 180, g: 50, b: 255 }, { name: "Orange", r: 255, g: 150, b: 50 }, { name: "Pink", r: 255, g: 100, b: 200 }, { name: "Yellow", r: 255, g: 255, b: 100 }, { name: "Cyan", r: 100, g: 255, b: 255 } ]; // Last shot time for RPG vehicle let lastVehShot = 0; // ============================================================================ // FONT LOADING // ============================================================================ addEventHandler("OnResourceReady", function(event, resource) { // Use built-in default font (no external TTF file needed) // Signature: lucasFont.createDefaultFont(float size, string family, [string style = "Regular"]) try { menuFont = lucasFont.createDefaultFont(16.0, "Arial", "Regular"); if (menuFont != null) { console.log("[ModMenu] Default font created successfully"); } } catch(e) { console.log("[ModMenu] Could not create default font: " + e); // Try alternative font try { menuFont = lucasFont.createDefaultFont(16.0, "Tahoma"); console.log("[ModMenu] Fallback font created"); } catch(e2) { console.log("[ModMenu] Fallback font also failed: " + e2); } } if (menuFont == null) { console.log("[ModMenu] Font creation failed - text won't render"); } }); // ============================================================================ // INPUT HANDLING // ============================================================================ addEventHandler("OnKeyUp", function(event, key, scanCode, mods) { // F5 to toggle menu (NOT F6) if (key === SDLK_F5) { menuOpen = !menuOpen; if (menuOpen) { currentMenu = "main"; selectedIndex = 0; scrollOffset = 0; menuStack = []; // Show cursor only - NO second param to avoid pause menu gui.showCursor(true); // Block phone when menu opens try { natives.destroyMobilePhone(); } catch(e) {} } else { // Hide cursor only gui.showCursor(false); } return; } // Block phone on ANY key press while menu is open if (menuOpen) { try { natives.destroyMobilePhone(); } catch(e) {} } if (!menuOpen) return; // Navigation - simple key handling if (key === SDLK_UP) { navigateUp(); } else if (key === SDLK_DOWN) { navigateDown(); } else if (key === SDLK_RETURN || key === SDLK_KP_ENTER) { selectItem(); } else if (key === SDLK_BACKSPACE || key === SDLK_ESCAPE) { goBack(); } }); function navigateUp() { let items = getCurrentMenuItems(); do { selectedIndex--; if (selectedIndex < 0) { selectedIndex = items.length - 1; } } while (items[selectedIndex] && items[selectedIndex].action === "none"); updateScroll(items); } function navigateDown() { let items = getCurrentMenuItems(); do { selectedIndex++; if (selectedIndex >= items.length) { selectedIndex = 0; } } while (items[selectedIndex] && items[selectedIndex].action === "none"); updateScroll(items); } function updateScroll(items) { if (selectedIndex < scrollOffset) { scrollOffset = selectedIndex; } else if (selectedIndex >= scrollOffset + menu.maxVisibleItems) { scrollOffset = selectedIndex - menu.maxVisibleItems + 1; } } function goBack() { if (menuStack.length > 0) { let prev = menuStack.pop(); currentMenu = prev.menu; selectedIndex = prev.index; scrollOffset = prev.scroll; } else { menuOpen = false; // IMPORTANT: Enable controls when closing menu gui.showCursor(false); } } function getCurrentMenuItems() { if (currentMenu === "network") { return getNetworkMenuItems(); } return menuData[currentMenu] ? menuData[currentMenu].items : []; } function getNetworkMenuItems() { let items = [ { label: "Refresh Player List", action: "refresh_players" }, { label: "--- Players (" + playerList.length + ") ---", action: "none" } ]; for (let i = 0; i < playerList.length; i++) { items.push({ label: playerList[i].name + " [ID: " + playerList[i].id + "]", action: "teleport_to_player_direct", playerData: playerList[i] }); } if (playerList.length === 0) { items.push({ label: "(No players found)", action: "none" }); items.push({ label: "(Click Refresh above)", action: "none" }); } return items; } // Refresh player list function function refreshPlayerList() { // Request player list from server triggerNetworkEvent("ModMenu:GetPlayers"); showNotification("Refreshing players..."); } // ============================================================================ // ACTION HANDLING // ============================================================================ let selectedPlayer = null; // Update current description function updateDescription() { let items = getCurrentMenuItems(); let item = items[selectedIndex]; if (!item) { currentDescription = ""; return; } // Get description based on action or target if (item.action === "toggle") { currentDescription = itemDescriptions[item.target] || ""; } else if (itemDescriptions[item.action]) { currentDescription = itemDescriptions[item.action] || ""; } else if (itemDescriptions[item.value]) { currentDescription = itemDescriptions[item.value] || ""; } else { currentDescription = ""; } } function selectItem() { let items = getCurrentMenuItems(); let item = items[selectedIndex]; if (!item || item.action === "none") return; // Update description before handling action updateDescription(); switch (item.action) { case "submenu": if (item.target === "player_options" && item.playerData) { selectedPlayer = item.playerData; openPlayerMenu(item.playerData); } else { menuStack.push({ menu: currentMenu, index: selectedIndex, scroll: scrollOffset }); currentMenu = item.target; selectedIndex = 0; scrollOffset = 0; // Auto-refresh player list when entering network menu if (item.target === "network") { refreshPlayerList(); } // Activate handling editor visualization when entering handling menus if (item.target === "handlingEditor" || item.target.startsWith("handling_")) { handlingEditorActive = true; // Highlight the relevant parameter in the visualization if (item.target.includes("traction")) { selectedHandlingParam = "traction"; } else if (item.target.includes("susp")) { selectedHandlingParam = "suspension"; } else if (item.target.includes("power") || item.target.includes("speed")) { selectedHandlingParam = "engine"; } else if (item.target.includes("brake")) { selectedHandlingParam = "brakes"; } else if (item.target.includes("mass") || item.target.includes("com")) { selectedHandlingParam = "weight"; } else if (item.target.includes("steering")) { selectedHandlingParam = "steering"; } else { selectedHandlingParam = ""; } } } break; case "toggle": toggleStates[item.target] = !toggleStates[item.target]; item.state = toggleStates[item.target]; triggerNetworkEvent("ModMenu:Toggle", item.target, toggleStates[item.target]); break; case "spawn_vehicle": triggerNetworkEvent("ModMenu:SpawnVehicle", item.value); showNotification("Spawning: " + item.label); break; case "teleport": triggerNetworkEvent("ModMenu:Teleport", item.value.x, item.value.y, item.value.z); showNotification("Teleporting..."); break; case "self_health": triggerNetworkEvent("ModMenu:SelfOption", "health"); showNotification("Health restored!"); break; case "self_armor": triggerNetworkEvent("ModMenu:SelfOption", "armor"); showNotification("Armor restored!"); break; case "self_max": triggerNetworkEvent("ModMenu:SelfOption", "max"); showNotification("Max health & armor!"); break; case "self_weapons": triggerNetworkEvent("ModMenu:SelfOption", "weapons"); showNotification("All weapons given!"); break; case "self_wanted": triggerNetworkEvent("ModMenu:SelfOption", "wanted"); showNotification("Wanted cleared!"); break; case "self_respawn": triggerNetworkEvent("ModMenu:SelfOption", "respawn"); showNotification("Respawning..."); break; case "self_suicide": triggerNetworkEvent("ModMenu:SelfOption", "suicide"); break; case "self_fire": try { natives.startCharFire(localPlayer); showNotification("You're on fire!"); } catch(e) {} break; case "self_cleartasks": try { natives.clearCharTasks(localPlayer); showNotification("Tasks cleared!"); } catch(e) {} break; case "skin": triggerNetworkEvent("ModMenu:ChangeSkin", item.value); showNotification("Skin changed!"); break; case "skin_random": triggerNetworkEvent("ModMenu:ChangeSkin", "random"); showNotification("Random skin!"); break; case "skin_random_mp_boy": triggerNetworkEvent("ModMenu:ChangeSkin", "random_mp_boy"); showNotification("Random MP Boy!"); break; case "skin_random_mp_girl": triggerNetworkEvent("ModMenu:ChangeSkin", "random_mp_girl"); showNotification("Random MP Girl!"); break; case "veh_repair": triggerNetworkEvent("ModMenu:VehicleOption", "repair"); showNotification("Repaired!"); break; case "veh_flip": triggerNetworkEvent("ModMenu:VehicleOption", "flip"); showNotification("Flipped!"); break; case "veh_nitro": triggerNetworkEvent("ModMenu:VehicleOption", "nitro"); showNotification("NITRO!"); break; case "veh_lock": if (localPlayer.vehicle) { try { natives.lockCarDoors(localPlayer.vehicle, 2); showNotification("Doors locked!"); } catch(e) {} } break; case "veh_unlock": if (localPlayer.vehicle) { try { natives.lockCarDoors(localPlayer.vehicle, 1); showNotification("Doors unlocked!"); } catch(e) {} } break; case "veh_engine": if (localPlayer.vehicle) { try { let isOn = natives.isCarEngineOn(localPlayer.vehicle); natives.switchCarEngine(localPlayer.vehicle, !isOn); showNotification(isOn ? "Engine off!" : "Engine on!"); } catch(e) {} } break; case "veh_poptires": if (localPlayer.vehicle) { try { natives.burstCarTyre(localPlayer.vehicle, 0); natives.burstCarTyre(localPlayer.vehicle, 1); natives.burstCarTyre(localPlayer.vehicle, 2); natives.burstCarTyre(localPlayer.vehicle, 3); showNotification("Tires popped!"); } catch(e) {} } break; case "veh_fixtires": if (localPlayer.vehicle) { try { natives.fixCarTyre(localPlayer.vehicle, 0); natives.fixCarTyre(localPlayer.vehicle, 1); natives.fixCarTyre(localPlayer.vehicle, 2); natives.fixCarTyre(localPlayer.vehicle, 3); showNotification("Tires fixed!"); } catch(e) {} } break; case "veh_color": triggerNetworkEvent("ModMenu:VehicleColor", item.value[0], item.value[1]); showNotification("Color changed!"); break; case "veh_color_random": let c1 = Math.floor(Math.random() * 132); let c2 = Math.floor(Math.random() * 132); triggerNetworkEvent("ModMenu:VehicleColor", c1, c2); showNotification("Random color!"); break; case "vehicle_delete": triggerNetworkEvent("ModMenu:DeleteVehicles"); showNotification("Deleted!"); break; case "world_time": triggerNetworkEvent("ModMenu:WorldTime", item.value); showNotification("Time: " + item.value + ":00"); break; case "world_weather": triggerNetworkEvent("ModMenu:WorldWeather", item.value); showNotification("Weather changed!"); break; case "weapon": triggerNetworkEvent("ModMenu:GiveWeapon", item.value); showNotification("Weapon given!"); break; case "weapon_all": triggerNetworkEvent("ModMenu:SelfOption", "weapons"); showNotification("All weapons!"); break; case "weapon_remove": try { natives.removeAllCharWeapons(localPlayer); showNotification("Weapons removed!"); } catch(e) {} break; case "refresh_players": refreshPlayerList(); break; case "teleport_to_player": if (selectedPlayer) { triggerNetworkEvent("ModMenu:TeleportToPlayer", selectedPlayer.id); showNotification("Teleporting to " + selectedPlayer.name); } break; case "teleport_to_player_direct": if (item.playerData) { triggerNetworkEvent("ModMenu:TeleportToPlayer", item.playerData.id); showNotification("Teleporting to " + item.playerData.name); } break; case "fun_launch": triggerNetworkEvent("ModMenu:Fun", "launch"); showNotification("LAUNCH!"); break; case "fun_explode": triggerNetworkEvent("ModMenu:Fun", "explode"); break; case "fun_ped": triggerNetworkEvent("ModMenu:Fun", "ped"); showNotification("Ped spawned!"); break; case "fun_ragdoll": triggerNetworkEvent("ModMenu:Fun", "ragdoll"); break; case "neon_color": neonColor = item.value; showNotification("Neon color: " + item.label.replace(" Neons", "")); break; case "sky_color": skyColorIndex = item.value; if (skyColorIndex === 0) { // Reset to default try { natives.releaseSkybox(); } catch(e) {} showNotification("Default sky"); } else { showNotification("Sky: " + item.value); } break; case "world_clear_area": if (localPlayer) { try { let pos = localPlayer.position; natives.clearArea(pos.x, pos.y, pos.z, 50.0, true); showNotification("Area cleared!"); } catch(e) {} } break; case "world_clear_vehicles": try { let pos = localPlayer ? localPlayer.position : new Vec3(0, 0, 0); natives.clearAreaOfCars(pos.x, pos.y, pos.z, 100.0); showNotification("Vehicles cleared!"); } catch(e) {} break; case "world_clear_peds": try { let pos = localPlayer ? localPlayer.position : new Vec3(0, 0, 0); natives.clearAreaOfChars(pos.x, pos.y, pos.z, 100.0); showNotification("Peds cleared!"); } catch(e) {} break; case "world_clear_objects": try { let pos = localPlayer ? localPlayer.position : new Vec3(0, 0, 0); natives.clearAreaOfObjects(pos.x, pos.y, pos.z, 100.0); showNotification("Objects cleared!"); } catch(e) {} break; case "world_traffic": try { natives.setTrafficEnabled(item.value); showNotification("Traffic: " + (item.value ? "ENABLED" : "DISABLED")); } catch(e) {} break; case "world_traffic_density": try { natives.trafficDensity(item.value); showNotification("Traffic density: " + item.value); } catch(e) {} break; case "world_timecycle": try { if (item.value === "clear") { natives.clearTimecycleModifier(); showNotification("Timecycle cleared!"); } else { natives.setTimecycleModifier(item.value); showNotification("Timecycle: " + item.value); } } catch(e) {} break; case "world_timecycle_clear": try { natives.clearTimecycleModifier(); showNotification("Timecycle cleared!"); } catch(e) {} break; case "fun_superjump": if (localPlayer) { try { let vel = localPlayer.velocity; vel.z = 15.0; localPlayer.velocity = vel; showNotification("SUPER JUMP!"); } catch(e) {} } break; case "fun_random_explosion": if (localPlayer) { try { let pos = localPlayer.position; let offsetX = (Math.random() - 0.5) * 20; let offsetY = (Math.random() - 0.5) * 20; natives.addExplosion(pos.x + offsetX, pos.y + offsetY, pos.z, Math.floor(Math.random() * 26), 5.0, true, false, 1.0); showNotification("Random explosion!"); } catch(e) {} } break; case "fun_car_rain": try { let pos = localPlayer ? localPlayer.position : new Vec3(0, 0, 0); let carModels = ["infernus", "banshee", "sultan"]; for (let i = 0; i < 10; i++) { let randomModel = carModels[Math.floor(Math.random() * carModels.length)]; let spawnX = pos.x + (Math.random() - 0.5) * 30; let spawnY = pos.y + (Math.random() - 0.5) * 30; let spawnZ = pos.z + 10 + Math.random() * 20; let modelHash = vehicleHashes[randomModel]; if (modelHash) { natives.requestModel(modelHash); setTimeout(() => { if (natives.hasModelLoaded(modelHash)) { let car = natives.createCar(modelHash, new Vec3(spawnX, spawnY, spawnZ), true); if (car) { let vel = new Vec3((Math.random() - 0.5) * 5, (Math.random() - 0.5) * 5, -10); car.velocity = vel; } natives.markModelAsNoLongerNeeded(modelHash); } }, 500); } } showNotification("CAR RAIN!"); screenShake = 1.0; } catch(e) {} break; case "fun_ped_invasion": try { let pos = localPlayer ? localPlayer.position : new Vec3(0, 0, 0); for (let i = 0; i < 20; i++) { let spawnX = pos.x + (Math.random() - 0.5) * 50; let spawnY = pos.y + (Math.random() - 0.5) * 50; let spawnZ = pos.z; let ped = natives.createChar(4, -1, new Vec3(spawnX, spawnY, spawnZ), true); if (ped) { natives.warpCharIntoCar(ped, localPlayer.vehicle); } } showNotification("PED INVASION!"); screenShake = 0.5; } catch(e) {} break; case "fun_gang": try { let pos = localPlayer ? localPlayer.position : new Vec3(0, 0, 0); for (let i = 0; i < 8; i++) { let spawnX = pos.x + (Math.random() - 0.5) * 20; let spawnY = pos.y + (Math.random() - 0.5) * 20; let spawnZ = pos.z; let ped = natives.createChar(4, -1, new Vec3(spawnX, spawnY, spawnZ), true); if (ped) { natives.giveWeaponToChar(ped, 14, 500, false); // AK47 natives.giveWeaponToChar(ped, 18, 10, false); // RPG } } showNotification("GANG SPAWNED!"); screenShake = 0.3; } catch(e) {} break; case "fun_army": try { let pos = localPlayer ? localPlayer.position : new Vec3(0, 0, 0); let armyModels = ["fbi", "police", "nstockade"]; for (let i = 0; i < 15; i++) { let spawnX = pos.x + (Math.random() - 0.5) * 40; let spawnY = pos.y + (Math.random() - 0.5) * 40; let spawnZ = pos.z; let ped = natives.createChar(4, -1, new Vec3(spawnX, spawnY, spawnZ), true); if (ped) { natives.giveWeaponToChar(ped, 14, 1000, false); // AK47 natives.giveWeaponToChar(ped, 16, 100, false); // Sniper natives.giveWeaponToChar(ped, 18, 50, false); // RPG } } showNotification("ARMY DEPLOYED!"); screenShake = 0.8; } catch(e) {} break; case "fun_money_rain": try { let pos = localPlayer ? localPlayer.position : new Vec3(0, 0, 0); for (let i = 0; i < 50; i++) { let spawnX = pos.x + (Math.random() - 0.5) * 30; let spawnY = pos.y + (Math.random() - 0.5) * 30; let spawnZ = pos.z + 10 + Math.random() * 30; natives.createMoneyPickup(new Vec3(spawnX, spawnY, spawnZ), 100, true); } showNotification("MONEY RAIN! $$$"); flashAlpha = 0.5; } catch(e) {} break; case "fun_weapon_shower": try { let pos = localPlayer ? localPlayer.position : new Vec3(0, 0, 0); let weapons = [5, 6, 9, 12, 14, 16, 18]; // Pistol, Deagle, Shotgun, SMG, AK, Sniper, RPG for (let i = 0; i < 30; i++) { let spawnX = pos.x + (Math.random() - 0.5) * 25; let spawnY = pos.y + (Math.random() - 0.5) * 25; let spawnZ = pos.z + 10 + Math.random() * 25; let weaponId = weapons[Math.floor(Math.random() * weapons.length)]; natives.createPickup(weaponId, 2, new Vec3(spawnX, spawnY, spawnZ), true); } showNotification("WEAPON SHOWER!"); screenShake = 0.4; } catch(e) {} break; case "fun_screen_shake": screenShake = 1.5; showNotification("SCREEN SHAKE!"); break; case "fun_flash": flashAlpha = 1.0; showNotification("FLASH!"); break; case "theme": currentTheme = item.value; showNotification("Theme: " + themes[item.value].name); break; // ============================================================================ // HANDLING EDITOR ACTIONS // ============================================================================ case "handling_set": if (localPlayer && localPlayer.vehicle) { handlingValues[item.param] = item.value; selectedHandlingParam = item.param; applyHandlingValue(item.param, item.value); showNotification(item.param + ": " + item.value); // Trigger visual feedback updateHandlingVisuals(item.param, item.value); } else { showNotification("Get in a vehicle first!"); } break; case "handling_reset": if (localPlayer && localPlayer.vehicle) { resetHandlingToDefault(); showNotification("Handling reset to default!"); } else { showNotification("Get in a vehicle first!"); } break; case "handling_preset": if (localPlayer && localPlayer.vehicle) { applyHandlingPreset(item.value); showNotification("Applied: " + item.label); } else { showNotification("Get in a vehicle first!"); } break; } } function openPlayerMenu(playerData) { menuData.player_options = { title: playerData.name, items: [ { label: "Teleport to Player", action: "teleport_to_player" } ] }; menuStack.push({ menu: currentMenu, index: selectedIndex, scroll: scrollOffset }); currentMenu = "player_options"; selectedIndex = 0; scrollOffset = 0; } // ============================================================================ // NETWORK HANDLERS // ============================================================================ addNetworkHandler("ModMenu:PlayerList", function(playerNames, playerIds) { playerList = []; // Parse pipe-separated strings if (playerNames && playerNames.length > 0) { let names = playerNames.split("|"); let ids = playerIds.split("|"); for (let i = 0; i < names.length; i++) { playerList.push({ name: names[i], id: parseInt(ids[i]) }); } } showNotification("Found " + playerList.length + " players"); console.log("[ModMenu] Player list updated: " + playerList.length + " players"); }); addNetworkHandler("ModMenu:Notification", function(msg) { showNotification(msg); }); // ============================================================================ // EXECUTE HANDLERS - Client-side natives execution // ============================================================================ // Execute weather change using GTA IV native addNetworkHandler("ModMenu:ExecuteWeather", function(weatherId) { try { natives.forceWeatherNow(weatherId); showNotification("Weather changed!"); } catch(e) { console.log("[ModMenu] Weather error: " + e); } }); // Execute time change using GTA IV native addNetworkHandler("ModMenu:ExecuteTime", function(hour) { try { natives.forceTimeOfDay(hour, 0); showNotification("Time: " + hour + ":00"); } catch(e) { console.log("[ModMenu] Time error: " + e); } }); // Execute self options using natives addNetworkHandler("ModMenu:ExecuteSelfOption", function(option) { if (!localPlayer) { showNotification("Player not ready"); return; } try { switch(option) { case "health": localPlayer.health = 200; showNotification("Health restored!"); break; case "armor": localPlayer.armour = 100; showNotification("Armor restored!"); break; case "max": localPlayer.health = 200; localPlayer.armour = 100; showNotification("Max health & armor!"); break; case "weapons": // Give weapons using natives natives.giveWeaponToChar(localPlayer, 5, 500, false); // Pistol natives.giveWeaponToChar(localPlayer, 6, 500, false); // Deagle natives.giveWeaponToChar(localPlayer, 9, 100, false); // Shotgun natives.giveWeaponToChar(localPlayer, 12, 500, false); // SMG natives.giveWeaponToChar(localPlayer, 14, 500, false); // AK natives.giveWeaponToChar(localPlayer, 16, 50, false); // Sniper natives.giveWeaponToChar(localPlayer, 18, 10, false); // RPG showNotification("All weapons given!"); break; case "wanted": natives.alterWantedLevel(0, 0); natives.applyWantedLevelChangeNow(0); showNotification("Wanted cleared!"); break; case "suicide": // Kill the player properly using explode head native natives.explodeCharHead(localPlayer); showNotification("Goodbye!"); break; } } catch(e) { console.log("[ModMenu] Self option error: " + e); showNotification("Action failed"); } }); // Execute teleport - with multiple fallback methods addNetworkHandler("ModMenu:ExecuteTeleport", function(x, y, z) { if (!localPlayer) { showNotification("Player not ready!"); return; } console.log("[ModMenu] Executing teleport to: " + x + ", " + y + ", " + z); try { // Method 1: Direct position set let pos = new Vec3(x, y, z); // Check if player is in vehicle if (localPlayer.vehicle) { // Teleport the vehicle instead try { localPlayer.vehicle.position = pos; showNotification("Teleported (in vehicle)!"); console.log("[ModMenu] Teleported vehicle successfully"); return; } catch(e) { console.log("[ModMenu] Vehicle teleport failed, trying player: " + e); } } // Try direct position assignment localPlayer.position = pos; showNotification("Teleported!"); console.log("[ModMenu] Teleported player successfully"); } catch(e) { console.log("[ModMenu] Teleport error: " + e); // Method 2: Try using native try { natives.setCharCoordinates(localPlayer, x, y, z); showNotification("Teleported!"); console.log("[ModMenu] Teleported using native successfully"); } catch(e2) { console.log("[ModMenu] Native teleport also failed: " + e2); showNotification("Teleport failed!"); } } }); // Execute teleport to player - get target player position and teleport addNetworkHandler("ModMenu:ExecuteTeleportToPlayer", function(targetId) { if (!localPlayer) return; try { // Find the target player in the player list let clients = getClients(); for (let i = 0; i < clients.length; i++) { if (clients[i].index == targetId && clients[i].player) { let targetPos = clients[i].player.position; let pos = new Vec3(targetPos.x + 2, targetPos.y, targetPos.z); localPlayer.position = pos; showNotification("Teleported to player!"); return; } } showNotification("Player not found"); } catch(e) { console.log("[ModMenu] Teleport to player error: " + e); showNotification("Teleport failed"); } }); // Vehicle model names (cleaned up for proper spawning) const vehicleModels = [ // Sports Cars "infernus", "turismo", "comet", "banshee", "sultan", "coquette", // Muscle Cars "buccaneer", "dukes", "faction", "ruiner", "sabre", "sabregt", "vigero", // Sedans "admiral", "cavalcade", "cognoscenti", "emperor", "esperanto", "feroci", "feltzer", "intruder", "landstalker", "lokus", "marbella", "merit", "oracle", "pinnacle", "premiere", "presidente", "primo", "rebla", "romero", "schafter", "sentinel", "solair", "stratum", "stretch", "vincent", "virgo", "willard", "washington", // SUVs & Trucks "bobcat", "boxville", "biff", "burrito", "chavos", "dilettante", "flatbed", "forklift", "habanero", "huntley", "moonbeam", "mule", "packer", "patriot", "perennial", "pony", "rancher", "speedo", "stockade", "trashmaster", "yankee", // Compacts "blista", "futo", "ingot", "pmp600", "sultanrs", // Motorcycles "faggio", "hellfury", "nrg900", "pcj600", "sanchez", "zombie", // Emergency "ambulance", "firetruk", "police", "police2", "police3", "police4", "nstockade", "pstockade", "fbi", "noose", // Helicopters "annihilator", "maverick", "polmav", "tourmav", // Boats "dinghy", "jetmax", "marquis", "predator", "reefer", "squalo", "tropic", "tuga", // Commercial "airtug", "benson", "biff", "boxville", "burrito", "burrito2", "cabby", "flatbed", "forklift", "mule", "packer", "pony", "speedo", "stockade", "trashmaster", "yankee", // Special "mrtasty", "cablecar", "subway", "eltrain", // Taxis "taxi", "taxi2", "romantaxi" ]; // Vehicle model hashes - SIGNED 32-bit integers from GTAConnected wiki // DO NOT use 0x prefix with decimal numbers! Use actual values. const vehicleHashes = { // Sports Cars "infernus": 418536135, "turismo": -1896659641, "comet": 1063483177, "banshee": -1041692462, "sultan": 970598228, "coquette": 108773431, "supergt": 1821991593, "futo": 2016857647, // Muscle Cars "buccaneer": -682211828, "dukes": 723973206, "faction": -2119578145, "fortune": 627033353, "ruiner": -227741703, "sabre": -449022887, "sabregt": -1685021548, "stallion": 1923400478, "vigero": -825837129, // Sedans "admiral": 1264341792, "cognoscenti": -2030171296, "emperor": -685276541, "esperanto": -276900515, "feroci": 974744810, "feltzer": -1097828879, "intruder": 886934177, "lokus": -37030056, "marbella": 1304597482, "merit": -1260881538, "oracle": 1348744438, "pinnacle": 131140572, "premier": -1883869285, "presidente": -1962071130, "primo": -1150599089, "rebla": 83136452, "romero": 627094268, "schafter": -322343873, "sentinel": 1349725314, "solair": 1344573448, "stratum": 1723137093, "stretch": -1961627517, "vincent": -583281407, "virgo": -498054846, "willard": 1937616578, "washington": 1777363799, // SUVs & Trucks "bobcat": 1075851868, "cavalcade": 2006918058, "habanero": 884422927, "huntley": 486987393, "landstalker": 1269098716, "patriot": -808457413, "rancher": 1390084576, // Vans & Commercial "benson": 2053223216, "biff": 850991848, "boxville": -1987130134, "burrito": -1346687836, "burrito2": -907477130, "cabby": 1884962369, "flatbed": 1353720154, "forklift": 1491375716, "moonbeam": 525509695, "mule": 904750859, "packer": 569305213, "perennial": -2077743597, "pony": -119658072, "speedo": -810318068, "stockade": 1747439474, "trashmaster": 1917016601, "yankee": -1099960214, // Compacts "blista": -344943009, "chavos": -67282078, "dilettante": -1130810103, "ingot": -1289722222, "pmp600": 1376298265, "sultanrs": -295689028, // Motorcycles "bobber": -1830458836, "faggio": -1842748181, "freeway": 1534326199, "hellfury": 584879743, "nrg900": 1203311498, "pcj600": -909201658, "sanchez": 788045382, "zombie": -570033273, // Emergency "ambulance": 1171614426, "firetruk": 1938952078, "police": 2046537925, "police2": -1627000575, "policepatriot": -350085182, "fbi": 1127131465, "noose": 148777611, "nstockade": -1900572838, "pstockade": 1911513875, // Helicopters "annihilator": 837858166, "maverick": -1660661558, "polmav": 353883353, "tourmav": 2027357303, // Boats "dinghy": 1033245328, "jetmax": 861409633, "marquis": -1043459709, "predator": -488123221, "reefer": 1759673526, "squalo": 400514754, "tropic": 290013743, "tuga": 1064455782, // Commercial & Special "airtug": 1560980623, "bus": -713569950, "mrtasty": 583100975, // Trains (may not spawn) "cablecar": -960289747, "subway": 800869680, "eltrain": -1953988645, // Taxis "taxi": -956048545, "taxi2": 1208856469, "romantaxi": -1932515764 }; // Execute vehicle spawn using natives addNetworkHandler("ModMenu:ExecuteSpawnVehicle", function(vehicleName) { try { if (!localPlayer) { showNotification("Not ready"); return; } // Clean up vehicle name and map to correct hash let cleanName = vehicleName.replace(/[^a-zA-Z0-9]/g, '').toLowerCase(); let modelHash = vehicleHashes[cleanName]; if (!modelHash) { showNotification("Unknown vehicle: " + cleanName); return; } console.log("[ModMenu] Spawning vehicle: " + vehicleName + " (hash: " + modelHash + ")"); // Request the model first natives.requestModel(modelHash); // Wait for model to load then spawn let attempts = 0; let spawnInterval = setInterval(function() { attempts++; if (natives.hasModelLoaded(modelHash)) { clearInterval(spawnInterval); let pos = localPlayer.position; let heading = localPlayer.heading || 0; // Spawn position in front of player let spawnX = pos.x + Math.sin(-heading) * 5; let spawnY = pos.y + Math.cos(-heading) * 5; let spawnZ = pos.z + 0.5; // Create spawn position as Vec3 (GTAConnected requires Vec3) let spawnPos = new Vec3(spawnX, spawnY, spawnZ); // Create the car - GTAConnected: createCar(hash, Vec3, bool) let vehicle = natives.createCar(modelHash, spawnPos, true); if (vehicle) { // Set vehicle heading to match player natives.setCarHeading(vehicle, heading); // Warp player into the vehicle natives.warpCharIntoCar(localPlayer, vehicle); showNotification("Spawned: " + vehicleName); console.log("[ModMenu] Vehicle spawned successfully"); } else { showNotification("Failed to create vehicle"); } // Mark model as no longer needed natives.markModelAsNoLongerNeeded(modelHash); } else if (attempts > 100) { clearInterval(spawnInterval); showNotification("Model load timeout for: " + vehicleName); } }, 50); // Check every 50ms instead of 100ms } catch(e) { console.log("[ModMenu] Vehicle spawn error: " + e); showNotification("Error: " + e); } }); // Execute vehicle options addNetworkHandler("ModMenu:ExecuteVehicleOption", function(option) { if (!localPlayer || !localPlayer.vehicle) { showNotification("Get in a vehicle first!"); return; } try { let veh = localPlayer.vehicle; switch(option) { case "repair": natives.fixCar(veh); showNotification("Vehicle repaired!"); break; case "flip": let rot = veh.rotation; veh.rotation = new Vec3(0, 0, rot.z); showNotification("Vehicle flipped!"); break; case "nitro": // Boost vehicle forward using velocity let heading = veh.heading || 0; let speed = 50.0; let vx = Math.sin(heading) * speed * -1; let vy = Math.cos(heading) * speed; let vel = new Vec3(vx, vy, 5); veh.velocity = vel; showNotification("NITRO!"); break; } } catch(e) { console.log("[ModMenu] Vehicle option error: " + e); } }); // Execute vehicle color change addNetworkHandler("ModMenu:ExecuteVehicleColor", function(color1, color2) { if (!localPlayer || !localPlayer.vehicle) { showNotification("Get in a vehicle first!"); return; } try { natives.changeCarColour(localPlayer.vehicle, color1, color2); showNotification("Color changed!"); } catch(e) { console.log("[ModMenu] Color change error: " + e); } }); // Execute weapon give addNetworkHandler("ModMenu:ExecuteGiveWeapon", function(weaponId) { if (!localPlayer) return; try { natives.giveWeaponToChar(localPlayer, weaponId, 500, false); showNotification("Weapon given!"); } catch(e) { console.log("[ModMenu] Weapon error: " + e); } }); // Execute fun options addNetworkHandler("ModMenu:ExecuteFun", function(option) { if (!localPlayer) return; try { let pos = localPlayer.position; switch(option) { case "launch": let launchPos = new Vec3(pos.x, pos.y, pos.z + 50); localPlayer.position = launchPos; showNotification("LAUNCH!"); break; case "explode": natives.addExplosion(pos.x, pos.y, pos.z, 0, 5.0, true, false, 1.0); break; case "ragdoll": natives.switchPedToRagdoll(localPlayer, 1000, 1000, 0, true, true, false); break; } } catch(e) { console.log("[ModMenu] Fun option error: " + e); } }); // GTA IV Character Model Hashes (verified working) // Male models const SKIN_NIKO = -1667301416; const SKIN_ROMAN = -163448165; const SKIN_JACOB = 1936355839; const SKIN_BRUCIE = -1938475496; const SKIN_PLAYBOY = 970234525; const SKIN_JOHNNY = -1784875845; const SKIN_LUIS = -1403507487; const SKIN_COP = -1320879687; const SKIN_DOCTOR = 1669579652; const SKIN_FIREMAN = -335476819; const SKIN_SECURITY = 1581098148; const SKIN_BUSINESS = -1191636209; const SKIN_STREET = -1850653608; const SKIN_HOBO = -1183939691; const SKIN_BIKER = 1830507291; // Female models - verified GTA IV peds const SKIN_F_BUSINESS = -1847203044; const SKIN_F_STREET = -2043953294; const SKIN_F_RICH = -1171014612; const SKIN_F_SHOP = -1611704378; const SKIN_F_NURSE = 1567728751; const SKIN_F_HOOKER = -639476421; const SKIN_F_TOURIST = -1507724086; const SKIN_F_JOGGER = -1813105079; // Arrays for random selection const mpBoySkins = [ SKIN_NIKO, SKIN_ROMAN, SKIN_JACOB, SKIN_BRUCIE, SKIN_PLAYBOY, SKIN_JOHNNY, SKIN_LUIS, SKIN_COP, SKIN_DOCTOR, SKIN_FIREMAN, SKIN_SECURITY, SKIN_BUSINESS, SKIN_STREET, SKIN_HOBO, SKIN_BIKER ]; const mpGirlSkins = [ SKIN_F_BUSINESS, SKIN_F_STREET, SKIN_F_RICH, SKIN_F_SHOP, SKIN_F_NURSE, SKIN_F_HOOKER, SKIN_F_TOURIST, SKIN_F_JOGGER ]; // Execute skin change addNetworkHandler("ModMenu:ExecuteSkinChange", function(skinId) { if (!localPlayer) return; try { if (skinId === "random") { // Random from all skins let allSkins = mpBoySkins.concat(mpGirlSkins); skinId = allSkins[Math.floor(Math.random() * allSkins.length)]; } else if (skinId === "random_mp_boy") { // Random male skin skinId = mpBoySkins[Math.floor(Math.random() * mpBoySkins.length)]; } else if (skinId === "random_mp_girl") { // Random female skin skinId = mpGirlSkins[Math.floor(Math.random() * mpGirlSkins.length)]; } console.log("[ModMenu] Changing skin to: " + skinId); // Request and load the model natives.requestModel(skinId); // Use interval to check if model is loaded let attempts = 0; let loadInterval = setInterval(function() { attempts++; try { // Try to load all objects natives.loadAllObjectsNow(); // Check if we can change model now if (attempts > 5) { clearInterval(loadInterval); // Change player model natives.changePlayerModel(0, skinId); console.log("[ModMenu] Skin changed successfully"); } } catch(e) { console.log("[ModMenu] Skin load attempt " + attempts + ": " + e); } if (attempts > 20) { clearInterval(loadInterval); console.log("[ModMenu] Skin load timeout"); } }, 50); } catch(e) { console.log("[ModMenu] Skin change error: " + e); showNotification("Skin change failed"); } }); // ============================================================================ // RENDERING - MD REVOLUTION MOD MENU (Trident Style) // Steel Blue primary, Gold/Orange accents, Flash effects // ============================================================================ // MDB Animation Effects Update (from MDB_Template.c Menu_Effects) addEventHandler("OnProcess", function(event) { // Update animation time animTime += 0.02; titlePulse += 0.04; selectedPulse += 0.06; colorShift += 0.01; particleTime += 0.05; // ===== MDB FlashingGhost Effect (150-255 range) ===== // Used for header text pulsing if (FlashingGhost >= 255) FlashingGhostIncrement = false; else if (FlashingGhost < 150) FlashingGhostIncrement = true; if (FlashingGhostIncrement) { if (FlashingGhost > 240) { FlashingGhost += (255 - FlashingGhost); FlashingGhostIncrement = false; } else { FlashingGhost += 2; } } else { FlashingGhost -= 2; } // ===== MDB Glowing Effect (0-190 range) ===== // Used for scrollbar glow if (Glowing >= 190) GlowingIncrement = false; if (Glowing <= 0) GlowingIncrement = true; if (GlowingIncrement) { if (Glowing > 185) Glowing++; else Glowing += 2; } else { if (Glowing < 10) Glowing--; else Glowing -= 2; } // ===== MDB Rotating Icon Effect ===== if (Rotating360 >= 360) Rotating360 = 0; else Rotating360 += 5; // ===== MDB Fading Effects ===== if (Fading_100 < 255) Fading_100 += 5; if (Fading_150 < 255) Fading_150 += 5; // ===== MDB Dropdown Animation ===== if (dropdown_y > 0.96) dropdown_y -= 0.01; else dropdown_y = 0.95; // ===== Enhanced UI Animations ===== // Border glow effect (0-1 smooth pulse) if (borderGlow >= 1) borderGlowIncrement = false; else if (borderGlow <= 0) borderGlowIncrement = true; borderGlow += borderGlowIncrement ? 0.015 : -0.015; // Corner pulse effect cornerPulse = (cornerPulse + 0.03) % (Math.PI * 2); // Header wave animation headerWaveOffset = (headerWaveOffset + 0.05) % (Math.PI * 2); // Scrollbar pulse scrollbarPulse = (scrollbarPulse + 0.08) % (Math.PI * 2); // Logo rotation (slow spin) logoRotation = (logoRotation + 0.5) % 360; // Banner shimmer effect bannerShimmer = (bannerShimmer + 0.04) % (Math.PI * 2); // Footer pulse footerPulse = (footerPulse + 0.05) % (Math.PI * 2); // Stats update timer statsUpdateTime += 0.02; // Screen shake decay if (screenShake > 0) { screenShake -= 0.1; if (screenShake < 0) screenShake = 0; } // Flash effect decay if (flashAlpha > 0) { flashAlpha -= 0.05; if (flashAlpha < 0) flashAlpha = 0; } // Matrix effect if (toggleStates.matrixMode) { matrixEffect += 0.1; } else { matrixEffect *= 0.9; } // Apply continuous effects when menu is closed if (!menuOpen && localPlayer) { try { // Moon gravity if (toggleStates.moonGravity) { localPlayer.gravity = 0.1; } else if (localPlayer.gravity !== 9.8) { localPlayer.gravity = 9.8; } // Drunk mode - wobble effect if (toggleStates.drunkMode) { try { natives.setGameCamShake(true, 2); natives.shakeCam(1, 100); } catch(e) { try { natives.setGameCamHeading(Math.sin(animTime * 3) * 5); } catch(e2) {} } } // Night Vision - using timecycle modifier as alternative if (toggleStates.nightVision) { try { // Try native first natives.setNightvision(true); } catch(e) { try { // Alternative: use timecycle for green tint effect natives.setTimecycleModifier("nightvision"); } catch(e2) {} } } // Thermal Vision - using timecycle modifier as alternative if (toggleStates.thermalVision) { try { // Try native first natives.setInfaredvision(true); } catch(e) { try { // Alternative: use timecycle for thermal effect natives.setTimecycleModifier("thermal"); } catch(e2) {} } } // Clear vision effects when both disabled if (!toggleStates.nightVision && !toggleStates.thermalVision) { try { natives.setNightvision(false); natives.setInfaredvision(false); } catch(e) {} } // Screen shake effect - apply camera shake if (screenShake > 0.01) { try { let shakeAmount = screenShake * 50; natives.shakeCam(1, Math.floor(shakeAmount)); } catch(e) { try { // Alternative: move camera slightly natives.setGameCamShake(true, Math.floor(screenShake * 3)); } catch(e2) {} } } } catch(e) {} } // Smooth scroll interpolation - very smooth smoothScrollY += (targetScrollY - smoothScrollY) * 0.15; // Menu open animation - smooth transition if (menuOpen && menuOpenAnim < 1) { menuOpenAnim += 0.08; if (menuOpenAnim > 1) { menuOpenAnim = 1; } } else if (!menuOpen && menuOpenAnim > 0) { menuOpenAnim -= 0.12; if (menuOpenAnim < 0) menuOpenAnim = 0; } }); // Enhanced eye-melting menu rendering (optimized) addEventHandler("OnDrawnHUD", function(event) { if (menuOpenAnim <= 0) return; let currentData = menuData[currentMenu]; let items = getCurrentMenuItems(); let title = currentData ? currentData.title : currentMenu.toUpperCase(); let visibleCount = Math.min(items.length, menu.maxVisibleItems); let totalHeight = menu.headerHeight + (visibleCount * menu.itemHeight) + menu.footerHeight; let animAlpha = Math.floor(255 * menuOpenAnim); // Calculate animated position (smooth slide in from right) let slideOffset = (1 - menuOpenAnim) * 120; let baseX = menu.x + slideOffset; let baseY = menu.y; // ===== ENHANCED OUTER GLOW/SHADOW ===== let glowIntensity = 0.3 + borderGlow * 0.2; let outerGlowColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(40 * glowIntensity * menuOpenAnim)); drawRect(baseX - 8, baseY - 8, menu.width + 16, totalHeight + 26, outerGlowColor); let shadowBg = toColour(0, 0, 0, Math.floor(120 * menuOpenAnim)); drawRect(baseX - 4, baseY - 4, menu.width + 8, totalHeight + 18, shadowBg); // ===== MDB WINDOW BACKGROUND - Enhanced gradient-style ===== let windowBgColor = toColour(MDB.Steelblue.r, MDB.Steelblue.g, MDB.Steelblue.b, Math.floor(190 * menuOpenAnim)); drawRect(baseX, baseY, menu.width, totalHeight + 10, windowBgColor); // Inner darker panel for depth let innerBgColor = toColour(30, 50, 70, Math.floor(100 * menuOpenAnim)); drawRect(baseX + 3, baseY + 3, menu.width - 6, totalHeight + 4, innerBgColor); // ===== ANIMATED BORDER ===== let borderAlpha = Math.floor((180 + borderGlow * 75) * menuOpenAnim); let borderColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, borderAlpha); // Top border drawRect(baseX, baseY, menu.width, 2, borderColor); // Bottom border drawRect(baseX, baseY + totalHeight + 8, menu.width, 2, borderColor); // Left border drawRect(baseX, baseY, 2, totalHeight + 10, borderColor); // Right border drawRect(baseX + menu.width - 2, baseY, 2, totalHeight + 10, borderColor); // ===== DECORATIVE CORNER ELEMENTS ===== let cornerSize = 12; let cornerAlpha = Math.floor((200 + Math.sin(cornerPulse) * 55) * menuOpenAnim); let cornerColor = toColour(255, 200, 100, cornerAlpha); // Top-left corner drawRect(baseX, baseY, cornerSize, 3, cornerColor); drawRect(baseX, baseY, 3, cornerSize, cornerColor); // Top-right corner drawRect(baseX + menu.width - cornerSize, baseY, cornerSize, 3, cornerColor); drawRect(baseX + menu.width - 3, baseY, 3, cornerSize, cornerColor); // Bottom-left corner drawRect(baseX, baseY + totalHeight + 7, cornerSize, 3, cornerColor); drawRect(baseX, baseY + totalHeight + 10 - cornerSize, 3, cornerSize, cornerColor); // Bottom-right corner drawRect(baseX + menu.width - cornerSize, baseY + totalHeight + 7, cornerSize, 3, cornerColor); drawRect(baseX + menu.width - 3, baseY + totalHeight + 10 - cornerSize, 3, cornerSize, cornerColor); // ===== ENHANCED HEADER BANNER ===== let headerY = baseY + 5; // Header background gradient let headerBg1 = toColour(40, 60, 90, Math.floor(220 * menuOpenAnim)); let headerBg2 = toColour(60, 90, 130, Math.floor(220 * menuOpenAnim)); drawRect(baseX + 4, headerY - 2, menu.width - 8, 55, headerBg1); // Header shimmer effect let shimmerX = baseX + 4 + ((Math.sin(bannerShimmer) + 1) * 0.5) * (menu.width - 80); let shimmerColor = toColour(255, 255, 255, Math.floor(30 * menuOpenAnim)); drawRect(shimmerX, headerY - 2, 60, 55, shimmerColor); // "MD" Prefix - Enhanced with glow let shadowColor = toColour(0, 0, 0, Math.floor(255 * menuOpenAnim)); drawText("MD", baseX + 13, headerY + 3, shadowColor, 28); drawText("MD", baseX + 11, headerY + 1, shadowColor, 28); // Main "MD" in bright Steelblue let mdGlowColor = toColour(100, 160, 220, Math.floor(FlashingGhost * menuOpenAnim)); let mdColor = toColour(MDB.Steelblue.r + 30, MDB.Steelblue.g + 30, MDB.Steelblue.b + 30, animAlpha); drawText("MD", baseX + 10, headerY, mdGlowColor, 28); drawText("MD", baseX + 10, headerY, mdColor, 28); // "REVOLUTION" - Enhanced with glow effect drawText("REVOLUTION", baseX + 58, headerY + 8, shadowColor, 20); drawText("REVOLUTION", baseX + 56, headerY + 6, shadowColor, 20); // Main header in Gold with enhanced FlashingGhost effect let headerGlowColor = toColour(255, 200, 100, Math.floor(FlashingGhost * 0.7 * menuOpenAnim)); let headerGoldColor = toColour(MDB.Gold.r + 40, MDB.Gold.g + 40, MDB.Gold.b, Math.floor(FlashingGhost * menuOpenAnim)); drawText("REVOLUTION", baseX + 55, headerY + 5, headerGlowColor, 20); drawText("REVOLUTION", baseX + 55, headerY + 5, headerGoldColor, 20); // Version badge - Enhanced with box let badgeX = baseX + menu.width - 78; let badgeY = headerY + 18; let badgeBg = toColour(MDB.Steelblue.r, MDB.Steelblue.g, MDB.Steelblue.b, Math.floor(200 * menuOpenAnim)); drawRect(badgeX - 4, badgeY - 2, 70, 18, badgeBg); let versionColor = toColour(255, 255, 255, animAlpha); drawText("TRIDENT", badgeX, badgeY + 2, versionColor, 11); // Sub Header - Enhanced with underline effect let subHeaderColor = toColour(MDB.SubHeader.r + 40, MDB.SubHeader.g + 40, MDB.SubHeader.b + 40, animAlpha); let subHeaderText = currentMenu === "main" ? "MAJOR DISTRIBUTION" : title; let subHeaderX = baseX + (menu.width / 2) - (subHeaderText.length * 3.5); drawText(subHeaderText, subHeaderX + 1, headerY + 40, shadowColor, 12); drawText(subHeaderText, subHeaderX, headerY + 39, subHeaderColor, 12); // ===== ENHANCED WHITE LINE SEPARATOR ===== // Gradient-style separator let lineColorL = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(200 * menuOpenAnim)); let lineColorC = toColour(MDB.Line.r, MDB.Line.g, MDB.Line.b, animAlpha); let lineColorR = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(200 * menuOpenAnim)); drawRect(baseX + 10, baseY + menu.headerHeight - 5, 30, 2, lineColorL); drawRect(baseX + 40, baseY + menu.headerHeight - 5, menu.width - 80, 2, lineColorC); drawRect(baseX + menu.width - 40, baseY + menu.headerHeight - 5, 30, 2, lineColorR); // Add glow line under let glowLineColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(60 * borderGlow * menuOpenAnim)); drawRect(baseX + 10, baseY + menu.headerHeight - 3, menu.width - 20, 3, glowLineColor); // ===== MDB MENU ITEMS ===== let yPos = baseY + menu.headerHeight; targetScrollY = scrollOffset * menu.itemHeight; for (let i = scrollOffset; i < scrollOffset + visibleCount && i < items.length; i++) { let item = items[i]; let isSelected = (i === selectedIndex); let itemY = yPos + (i - scrollOffset) * menu.itemHeight; if (isSelected) { // ===== ENHANCED SELECTED ITEM - Multi-layer glow effect ===== // Outer glow let outerGlowAlpha = Math.floor((80 + Math.sin(scrollbarPulse) * 40) * menuOpenAnim); let outerGlowCol = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, outerGlowAlpha); drawRect(baseX + 4, itemY - 2, menu.width - 8, menu.itemHeight + 2, outerGlowCol); // Main selection background with enhanced Glowing effect let scrollbarAlpha = Math.floor((160 + Math.sin(scrollbarPulse) * 30) * menuOpenAnim); let scrollbarColor = toColour(Glowing, Glowing + 30, 220, scrollbarAlpha); drawRect(baseX + 6, itemY, menu.width - 12, menu.itemHeight - 2, scrollbarColor); // Inner highlight line (top) let highlightLineColor = toColour(255, 255, 255, Math.floor(100 * menuOpenAnim)); drawRect(baseX + 8, itemY + 1, menu.width - 16, 1, highlightLineColor); // Left accent bar let accentColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, animAlpha); drawRect(baseX + 6, itemY + 2, 3, menu.itemHeight - 6, accentColor); } else if (item.action === "none") { // ===== MDB Separator/JumpOver - Enhanced with subtle line ===== let sepLineColor = toColour(MDB.JumpOver.r, MDB.JumpOver.g, MDB.JumpOver.b, Math.floor(80 * menuOpenAnim)); drawRect(baseX + 20, itemY + menu.itemHeight - 4, menu.width - 40, 1, sepLineColor); } // Normal items have no background in MDB style (transparent over Steelblue window) // ===== MDB ITEM TEXT ===== let textX = baseX + 22; if (item.action === "none") { // ===== MDB JumpOver/Separator Text - JumpOver color (58,95,205) ===== let jumpOverColor = toColour(MDB.JumpOver.r, MDB.JumpOver.g, MDB.JumpOver.b, animAlpha); drawText(item.label, baseX + 20, itemY + 12, jumpOverColor, 12); } else if (item.action === "toggle" && toggleStates[item.target]) { // ===== MDB Toggle ON - ItemHighlight color (255,143,0) with FlashingGhost ===== let highlightColor = toColour(MDB.ItemHighlight.r, MDB.ItemHighlight.g, MDB.ItemHighlight.b, animAlpha); drawText(item.label, textX, itemY + 12, highlightColor, 14); } else if (isSelected) { // ===== MDB Selected Item Text - ScrollItem white (255,255,255) ===== let selectedTextColor = toColour(MDB.ScrollItem.r, MDB.ScrollItem.g, MDB.ScrollItem.b, animAlpha); drawText(item.label, textX, itemY + 12, selectedTextColor, 14); } else { // ===== MDB Normal Item Text - Item gray (180,180,180) ===== let normalTextColor = toColour(MDB.Item.r, MDB.Item.g, MDB.Item.b, animAlpha); drawText(item.label, textX, itemY + 12, normalTextColor, 14); } // ===== MDB TOGGLE INDICATORS - Bool color (255,128,0) arrow ===== if (item.action === "toggle") { let isOn = toggleStates[item.target]; // Draw arrow indicator like MDB (arrowLeftRight sprite equivalent) let arrowColor = toColour(MDB.Bool.r, MDB.Bool.g, MDB.Bool.b, Math.floor(Fading_100 * menuOpenAnim)); drawText(">", baseX + 12, itemY + 12, arrowColor, 12); // Status text on right side let stateX = baseX + menu.width - 50; if (isOn) { // MDB ON state - ItemHighlight with FlashingGhost let onColor = toColour(MDB.ItemHighlight.r, MDB.ItemHighlight.g, MDB.ItemHighlight.b, Math.floor(FlashingGhost * menuOpenAnim)); drawText("ON", stateX, itemY + 12, onColor, 12); } else { // MDB OFF state - gray let offColor = toColour(MDB.Item.r, MDB.Item.g, MDB.Item.b, animAlpha); drawText("OFF", stateX, itemY + 12, offColor, 12); } } // ===== MDB Submenu Arrow ===== if (item.action === "submenu") { let arrowX = baseX + menu.width - 25; // MDB uses spinning blip icon, we'll use animated arrow let arrowColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, animAlpha); drawText(">", arrowX, itemY + 12, arrowColor, 14); } } // ===== ENHANCED FOOTER ===== let footerY = yPos + visibleCount * menu.itemHeight; // Footer background with gradient effect let footerBgColor = toColour(30, 50, 70, Math.floor(180 * menuOpenAnim)); drawRect(baseX + 4, footerY + 2, menu.width - 8, menu.footerHeight - 4, footerBgColor); // Footer top line let footerLineColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor((150 + Math.sin(footerPulse) * 50) * menuOpenAnim)); drawRect(baseX + 10, footerY + 2, menu.width - 20, 1, footerLineColor); // Navigation hints with icons let helperTextColor = toColour(MDB.StatsItem.r, MDB.StatsItem.g, MDB.StatsItem.b, Math.floor(220 * menuOpenAnim)); let helperAccentColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(220 * menuOpenAnim)); // Draw key hints drawText("[", baseX + 12, footerY + 12, helperAccentColor, 10); drawText("UP/DOWN", baseX + 18, footerY + 12, helperTextColor, 10); drawText("]", baseX + 68, footerY + 12, helperAccentColor, 10); drawText("Navigate", baseX + 76, footerY + 12, helperTextColor, 9); drawText("[", baseX + 130, footerY + 12, helperAccentColor, 10); drawText("ENTER", baseX + 136, footerY + 12, helperTextColor, 10); drawText("]", baseX + 172, footerY + 12, helperAccentColor, 10); drawText("Select", baseX + 180, footerY + 12, helperTextColor, 9); drawText("[", baseX + 225, footerY + 12, helperAccentColor, 10); drawText("BACK", baseX + 231, footerY + 12, helperTextColor, 10); drawText("]", baseX + 260, footerY + 12, helperAccentColor, 10); drawText("Return", baseX + 268, footerY + 12, helperTextColor, 9); // ===== ENHANCED SCROLLBAR (RIGHT SIDE) ===== if (items.length > menu.maxVisibleItems) { let scrollbarX = baseX + menu.width - 10; let scrollbarY = baseY + menu.headerHeight + 5; let scrollbarH = visibleCount * menu.itemHeight - 10; let maxScroll = items.length - visibleCount; let scrollProgress = scrollOffset / maxScroll; let thumbH = Math.max(30, scrollbarH * (visibleCount / items.length)); let thumbY = scrollbarY + scrollProgress * (scrollbarH - thumbH); // Scrollbar track let trackColor = toColour(40, 40, 50, Math.floor(150 * menuOpenAnim)); drawRect(scrollbarX, scrollbarY, 5, scrollbarH, trackColor); // Scrollbar thumb with glow let thumbGlowAlpha = Math.floor((60 + Math.sin(scrollbarPulse) * 30) * menuOpenAnim); let thumbGlowColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, thumbGlowAlpha); drawRect(scrollbarX - 1, thumbY - 1, 7, thumbH + 2, thumbGlowColor); let thumbColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(220 * menuOpenAnim)); drawRect(scrollbarX, thumbY, 5, thumbH, thumbColor); // Up arrow - Gold color, show when not at top if (scrollOffset > 0) { let upArrowY = baseY + menu.headerHeight + 2; let upArrowColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(FlashingGhost * menuOpenAnim)); drawText("^", baseX + menu.width / 2 - 5, upArrowY, upArrowColor, 14); } // Down arrow - Gold color, show when not at bottom if (scrollOffset < maxScroll) { let downArrowY = footerY - 16; let downArrowColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(FlashingGhost * menuOpenAnim)); drawText("v", baseX + menu.width / 2 - 5, downArrowY, downArrowColor, 14); } // Page indicator let pageText = (scrollOffset + 1) + "/" + (maxScroll + 1); let pageColor = toColour(150, 150, 160, Math.floor(180 * menuOpenAnim)); drawText(pageText, baseX + menu.width - 45, footerY + 12, pageColor, 9); } // ===== ENHANCED INFO BAR ===== if (currentDescription && currentDescription.length > 0) { let infoY = baseY + totalHeight + 15; let infoBarHeight = infoBar.height + 5; // Shadow let infoShadow = toColour(0, 0, 0, Math.floor(100 * menuOpenAnim)); drawRect(baseX - 2, infoY - 2, menu.width + 4, infoBarHeight + 4, infoShadow); // Background - Enhanced with gradient look let infoBgColor = toColour(MDB.Steelblue.r - 20, MDB.Steelblue.g - 20, MDB.Steelblue.b - 20, Math.floor(200 * menuOpenAnim)); drawRect(baseX, infoY, menu.width, infoBarHeight, infoBgColor); // Border let infoBorderColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(180 * menuOpenAnim)); drawRect(baseX, infoY, menu.width, 2, infoBorderColor); drawRect(baseX, infoY + infoBarHeight - 2, menu.width, 2, infoBorderColor); drawRect(baseX, infoY, 2, infoBarHeight, infoBorderColor); drawRect(baseX + menu.width - 2, infoY, 2, infoBarHeight, infoBorderColor); // "INFO" label box let infoLabelBg = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(200 * menuOpenAnim)); drawRect(baseX + 8, infoY + 6, 40, 16, infoLabelBg); let infoLabelColor = toColour(0, 0, 0, animAlpha); drawText("INFO", baseX + 12, infoY + 8, infoLabelColor, 10); // Description text - white with shadow let descShadow = toColour(0, 0, 0, Math.floor(200 * menuOpenAnim)); let descColor = toColour(MDB.StatsItem.r, MDB.StatsItem.g, MDB.StatsItem.b, animAlpha); drawText(currentDescription, baseX + 13, infoY + 28, descShadow, 11); drawText(currentDescription, baseX + 12, infoY + 27, descColor, 11); } }); // ============================================================================ // VISUAL EFFECTS OVERLAY - Flash, Matrix, Screen Effects // ============================================================================ addEventHandler("OnDrawnHUD", function(event) { let screenWidth = 1920; let screenHeight = 1080; try { screenWidth = game.width || 1920; screenHeight = game.height || 1080; } catch(e) {} // Flash Screen Effect - white overlay that fades out if (flashAlpha > 0.01) { let flashColor = toColour(255, 255, 255, Math.floor(flashAlpha * 255)); drawRect(0, 0, screenWidth, screenHeight, flashColor); } // Screen Shake Visual Effect - draw offset overlay if (screenShake > 0.01) { // Apply visual shake by drawing slightly offset let shakeX = (Math.random() - 0.5) * screenShake * 20; let shakeY = (Math.random() - 0.5) * screenShake * 20; // Draw subtle edge distortion let edgeColor = toColour(0, 0, 0, Math.floor(screenShake * 50)); drawRect(shakeX, shakeY, 10, screenHeight, edgeColor); drawRect(screenWidth - 10 + shakeX, shakeY, 10, screenHeight, edgeColor); } // Matrix Mode - Digital rain effect if (toggleStates.matrixMode) { // Draw matrix-style falling characters let matrixColor = toColour(0, 255, 65, 150); let matrixBgColor = toColour(0, 30, 10, 100); // Draw dark green overlay drawRect(0, 0, screenWidth, screenHeight, matrixBgColor); // Draw vertical lines simulating matrix rain for (let col = 0; col < 40; col++) { let x = col * 48; let offset = (matrixEffect * 50 + col * 73) % screenHeight; // Draw fading trail for (let i = 0; i < 15; i++) { let y = (offset + i * 30) % screenHeight; let alpha = Math.max(0, 150 - i * 10); let charColor = toColour(0, 255, 65, alpha); // Draw small rectangles as "characters" drawRect(x, y, 8, 12, charColor); } } // Add scanline effect for (let y = 0; y < screenHeight; y += 4) { let scanlineColor = toColour(0, 0, 0, 30); drawRect(0, y, screenWidth, 2, scanlineColor); } } // Night Vision Overlay - green tint effect if native doesn't work if (toggleStates.nightVision) { let nvColor = toColour(0, 80, 0, 60); drawRect(0, 0, screenWidth, screenHeight, nvColor); // Add grain effect for (let i = 0; i < 50; i++) { let grainX = Math.random() * screenWidth; let grainY = Math.random() * screenHeight; let grainColor = toColour(100, 255, 100, Math.floor(Math.random() * 30)); drawRect(grainX, grainY, 2, 2, grainColor); } } // Thermal Vision Overlay - color bands if native doesn't work if (toggleStates.thermalVision) { let thermalColor = toColour(100, 50, 150, 40); drawRect(0, 0, screenWidth, screenHeight, thermalColor); // Add heat shimmer effect for (let i = 0; i < 30; i++) { let heatX = Math.random() * screenWidth; let heatY = Math.random() * screenHeight; let heatW = 20 + Math.random() * 40; let heatH = 10 + Math.random() * 20; let r = 200 + Math.floor(Math.random() * 55); let g = 100 + Math.floor(Math.random() * 100); let b = Math.floor(Math.random() * 50); let heatColor = toColour(r, g, b, 20); drawRect(heatX, heatY, heatW, heatH, heatColor); } } }); // ============================================================================ // PLAYER STATS PANEL - Shows player info when menu is open // ============================================================================ addEventHandler("OnDrawnHUD", function(event) { if (menuOpenAnim <= 0) return; if (!localPlayer) return; let alpha = Math.floor(255 * menuOpenAnim); let theme = getTheme(); // Panel position (top-left of screen) let panelX = 30; let panelY = 100; let panelW = 220; let panelH = 240; // Slide in animation from left let slideOffset = (1 - menuOpenAnim) * -100; panelX += slideOffset; // ===== PANEL SHADOW ===== let shadowColor = toColour(0, 0, 0, Math.floor(100 * menuOpenAnim)); drawRect(panelX - 3, panelY - 3, panelW + 6, panelH + 6, shadowColor); // ===== PANEL BACKGROUND ===== let bgColor = toColour(MDB.Steelblue.r - 30, MDB.Steelblue.g - 30, MDB.Steelblue.b - 30, Math.floor(200 * menuOpenAnim)); drawRect(panelX, panelY, panelW, panelH, bgColor); // Inner panel let innerBg = toColour(20, 35, 55, Math.floor(150 * menuOpenAnim)); drawRect(panelX + 3, panelY + 3, panelW - 6, panelH - 6, innerBg); // ===== PANEL BORDER ===== let borderCol = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor((180 + borderGlow * 50) * menuOpenAnim)); drawRect(panelX, panelY, panelW, 2, borderCol); drawRect(panelX, panelY + panelH - 2, panelW, 2, borderCol); drawRect(panelX, panelY, 2, panelH, borderCol); drawRect(panelX + panelW - 2, panelY, 2, panelH, borderCol); // Corner accents let cornerCol = toColour(255, 200, 100, Math.floor((200 + Math.sin(cornerPulse) * 55) * menuOpenAnim)); drawRect(panelX, panelY, 10, 2, cornerCol); drawRect(panelX, panelY, 2, 10, cornerCol); drawRect(panelX + panelW - 10, panelY, 10, 2, cornerCol); drawRect(panelX + panelW - 2, panelY, 2, 10, cornerCol); // ===== HEADER ===== let headerBg = toColour(MDB.Steelblue.r, MDB.Steelblue.g, MDB.Steelblue.b, Math.floor(220 * menuOpenAnim)); drawRect(panelX + 4, panelY + 4, panelW - 8, 28, headerBg); let titleCol = toColour(255, 255, 255, alpha); let titleShadow = toColour(0, 0, 0, alpha); drawText("PLAYER STATUS", panelX + 11, panelY + 10, titleShadow, 13); drawText("PLAYER STATUS", panelX + 10, panelY + 9, titleCol, 13); // ===== STATS CONTENT ===== let contentY = panelY + 40; let labelCol = toColour(MDB.Item.r, MDB.Item.g, MDB.Item.b, alpha); let valueCol = toColour(255, 255, 255, alpha); let rowH = 24; // Health bar drawText("Health", panelX + 12, contentY, labelCol, 10); let health = localPlayer.health || 0; let maxHealth = 200; let healthPct = Math.min(1, health / maxHealth); let healthBarBg = toColour(40, 40, 50, alpha); drawRect(panelX + 12, contentY + 14, panelW - 24, 8, healthBarBg); let healthCol = healthPct > 0.5 ? toColour(50, 200, 50, alpha) : healthPct > 0.25 ? toColour(255, 200, 0, alpha) : toColour(255, 50, 50, alpha); drawRect(panelX + 12, contentY + 14, (panelW - 24) * healthPct, 8, healthCol); drawText(Math.floor(health), panelX + panelW - 40, contentY, valueCol, 10); contentY += rowH + 4; // Armor bar drawText("Armor", panelX + 12, contentY, labelCol, 10); let armor = localPlayer.armour || 0; let armorPct = Math.min(1, armor / 100); drawRect(panelX + 12, contentY + 14, panelW - 24, 8, healthBarBg); let armorCol = toColour(100, 150, 255, alpha); drawRect(panelX + 12, contentY + 14, (panelW - 24) * armorPct, 8, armorCol); drawText(Math.floor(armor), panelX + panelW - 40, contentY, valueCol, 10); contentY += rowH + 8; // Separator line let sepCol = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(100 * menuOpenAnim)); drawRect(panelX + 10, contentY, panelW - 20, 1, sepCol); contentY += 8; // Wanted Level drawText("Wanted Level", panelX + 12, contentY, labelCol, 10); let wanted = 0; try { wanted = localPlayer.wantedLevel || 0; } catch(e) {} // Draw stars for (let i = 0; i < 6; i++) { let starCol = i < wanted ? toColour(255, 200, 0, alpha) : toColour(60, 60, 70, alpha); drawRect(panelX + 100 + i * 18, contentY + 2, 12, 12, starCol); } contentY += rowH; // Vehicle Status drawText("Vehicle", panelX + 12, contentY, labelCol, 10); let vehStatus = "On Foot"; let vehStatusCol = toColour(150, 150, 150, alpha); if (localPlayer.vehicle) { vehStatus = "In Vehicle"; vehStatusCol = toColour(100, 255, 100, alpha); } drawText(vehStatus, panelX + 100, contentY, vehStatusCol, 10); contentY += rowH; // Active Toggles Counter drawText("Active Mods", panelX + 12, contentY, labelCol, 10); let activeCount = 0; for (let key in toggleStates) { if (toggleStates[key]) activeCount++; } let modCountCol = activeCount > 0 ? toColour(MDB.ItemHighlight.r, MDB.ItemHighlight.g, MDB.ItemHighlight.b, alpha) : valueCol; drawText(activeCount.toString(), panelX + 100, contentY, modCountCol, 10); contentY += rowH + 8; // ===== CLOCK / TIME DISPLAY ===== let clockY = panelY + panelH - 35; drawRect(panelX + 10, clockY - 5, panelW - 20, 1, sepCol); // Get current time let now = new Date(); let hours = now.getHours().toString().padStart(2, '0'); let mins = now.getMinutes().toString().padStart(2, '0'); let secs = now.getSeconds().toString().padStart(2, '0'); let timeStr = hours + ":" + mins + ":" + secs; // Time display with pulsing colon effect let clockBg = toColour(MDB.Steelblue.r, MDB.Steelblue.g, MDB.Steelblue.b, Math.floor(180 * menuOpenAnim)); drawRect(panelX + panelW / 2 - 45, clockY, 90, 22, clockBg); let clockCol = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, alpha); let clockShadow = toColour(0, 0, 0, alpha); drawText(timeStr, panelX + panelW / 2 - 35, clockY + 5, clockShadow, 14); drawText(timeStr, panelX + panelW / 2 - 36, clockY + 4, clockCol, 14); // Date let dateCol = toColour(150, 150, 160, Math.floor(180 * menuOpenAnim)); let dateStr = (now.getMonth() + 1) + "/" + now.getDate() + "/" + now.getFullYear(); drawText(dateStr, panelX + 12, clockY + 6, dateCol, 9); }); // ============================================================================ // ACTIVE TOGGLES INDICATOR - Shows active mods in corner // ============================================================================ addEventHandler("OnDrawnHUD", function(event) { if (menuOpen) return; // Don't show when menu is open if (!localPlayer) return; // Count active toggles let activeToggles = []; if (toggleStates.godMode) activeToggles.push("GOD"); if (toggleStates.invincible) activeToggles.push("INV"); if (toggleStates.superRun) activeToggles.push("SPD"); if (toggleStates.neverWanted) activeToggles.push("NW"); if (toggleStates.invisible) activeToggles.push("INV"); if (toggleStates.vehGodMode) activeToggles.push("VGOD"); if (toggleStates.driftMode) activeToggles.push("DRFT"); if (toggleStates.rainbowCar) activeToggles.push("RGB"); if (toggleStates.flyMode) activeToggles.push("FLY"); if (activeToggles.length === 0) return; // Position in top-right corner let indicatorX = 1680; let indicatorY = 20; // Background let bgColor = toColour(0, 0, 0, 150); let bgWidth = 80; let bgHeight = 20 + activeToggles.length * 16; drawRect(indicatorX, indicatorY, bgWidth, bgHeight, bgColor); // Border let borderColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, 180); drawRect(indicatorX, indicatorY, bgWidth, 2, borderColor); drawRect(indicatorX, indicatorY + bgHeight - 2, bgWidth, 2, borderColor); drawRect(indicatorX, indicatorY, 2, bgHeight, borderColor); drawRect(indicatorX + bgWidth - 2, indicatorY, 2, bgHeight, borderColor); // Title let titleColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, 255); drawText("ACTIVE", indicatorX + 18, indicatorY + 4, titleColor, 9); // List active toggles let listY = indicatorY + 20; for (let i = 0; i < activeToggles.length; i++) { let toggleColor = toColour(MDB.ItemHighlight.r, MDB.ItemHighlight.g, MDB.ItemHighlight.b, Math.floor(200 + Math.sin(animTime * 3 + i) * 55)); drawText(activeToggles[i], indicatorX + 8, listY + i * 16, toggleColor, 10); } }); // ============================================================================ // BOTTOM SCREEN BANNER - Shows when menu is open // ============================================================================ addEventHandler("OnDrawnHUD", function(event) { if (menuOpenAnim <= 0) return; let screenWidth = 1920; let screenHeight = 1080; try { screenWidth = game.width || 1920; screenHeight = game.height || 1080; } catch(e) {} let alpha = Math.floor(255 * menuOpenAnim); let bannerH = 45; let bannerY = screenHeight - bannerH - 10; // Slide up animation let slideOffset = (1 - menuOpenAnim) * 60; bannerY += slideOffset; // Banner background let bannerBg = toColour(0, 0, 0, Math.floor(180 * menuOpenAnim)); drawRect(0, bannerY, screenWidth, bannerH, bannerBg); // Top border with gradient let borderL = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor((180 + borderGlow * 50) * menuOpenAnim)); let borderC = toColour(MDB.Steelblue.r, MDB.Steelblue.g, MDB.Steelblue.b, alpha); drawRect(0, bannerY, screenWidth * 0.3, 2, borderL); drawRect(screenWidth * 0.3, bannerY, screenWidth * 0.4, 2, borderC); drawRect(screenWidth * 0.7, bannerY, screenWidth * 0.3, 2, borderL); // Left logo let logoShadow = toColour(0, 0, 0, alpha); let logoGold = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, alpha); let logoBlue = toColour(MDB.Steelblue.r + 40, MDB.Steelblue.g + 40, MDB.Steelblue.b + 40, alpha); drawText("MD", 21, bannerY + 12, logoShadow, 18); drawText("MD", 20, bannerY + 11, logoBlue, 18); drawText("REVOLUTION", 58, bannerY + 15, logoShadow, 14); drawText("REVOLUTION", 57, bannerY + 14, logoGold, 14); // Center text - server info let centerText = "GTA CONNECTED"; let centerX = screenWidth / 2 - centerText.length * 4; let centerCol = toColour(MDB.SubHeader.r, MDB.SubHeader.g, MDB.SubHeader.b, alpha); drawText(centerText, centerX + 1, bannerY + 16, logoShadow, 12); drawText(centerText, centerX, bannerY + 15, centerCol, 12); // Right side - F5 hint let hintCol = toColour(150, 150, 160, alpha); let keyCol = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, alpha); drawText("Press", screenWidth - 150, bannerY + 15, hintCol, 10); drawText("[F5]", screenWidth - 115, bannerY + 15, keyCol, 10); drawText("to close", screenWidth - 80, bannerY + 15, hintCol, 10); // Animated bottom line let lineAlpha = Math.floor((150 + Math.sin(footerPulse) * 60) * menuOpenAnim); let lineCol = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, lineAlpha); drawRect(0, bannerY + bannerH - 2, screenWidth, 2, lineCol); }); // ============================================================================ // MENU PARTICLE EFFECTS - Subtle floating particles // ============================================================================ addEventHandler("OnDrawnHUD", function(event) { if (menuOpenAnim <= 0.1) return; let baseX = menu.x; let baseY = menu.y; let alpha = Math.floor(255 * menuOpenAnim); // Generate particles around the menu for (let i = 0; i < 8; i++) { let angle = (animTime * 0.5 + i * 0.785) % (Math.PI * 2); let radius = 180 + Math.sin(animTime + i) * 30; let px = baseX + menu.width / 2 + Math.cos(angle) * radius; let py = baseY + 250 + Math.sin(angle) * 100; // Floating particle let particleAlpha = Math.floor((40 + Math.sin(animTime * 2 + i) * 25) * menuOpenAnim); let particleSize = 3 + Math.sin(animTime + i * 0.5) * 2; // Gold particles let pColor = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, particleAlpha); drawRect(px, py, particleSize, particleSize, pColor); } // Subtle sparkle effects on corners let sparkleTime = animTime * 3; for (let i = 0; i < 4; i++) { let sparkleAlpha = Math.floor(Math.max(0, Math.sin(sparkleTime + i * 1.57) * 80) * menuOpenAnim); if (sparkleAlpha > 10) { let sx, sy; switch(i) { case 0: sx = baseX - 5; sy = baseY - 5; break; case 1: sx = baseX + menu.width + 2; sy = baseY - 5; break; case 2: sx = baseX - 5; sy = baseY + 450; break; case 3: sx = baseX + menu.width + 2; sy = baseY + 450; break; } let sparkleCol = toColour(255, 255, 200, sparkleAlpha); drawRect(sx, sy, 4, 4, sparkleCol); drawRect(sx - 1, sy + 1, 6, 2, sparkleCol); drawRect(sx + 1, sy - 1, 2, 6, sparkleCol); } } }); // ============================================================================ // MENU TITLE BADGE (Above main menu) // ============================================================================ addEventHandler("OnDrawnHUD", function(event) { if (menuOpenAnim <= 0) return; let alpha = Math.floor(255 * menuOpenAnim); let slideOffset = (1 - menuOpenAnim) * 120; let baseX = menu.x + slideOffset; let baseY = menu.y - 50; // Slide down animation let slideDown = (1 - menuOpenAnim) * -30; baseY += slideDown; // Badge background let badgeBg = toColour(MDB.DevilsRed.r, MDB.DevilsRed.g, MDB.DevilsRed.b, Math.floor(220 * menuOpenAnim)); drawRect(baseX + menu.width / 2 - 80, baseY, 160, 35, badgeBg); // Border glow let borderGlowCol = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor((100 + borderGlow * 80) * menuOpenAnim)); drawRect(baseX + menu.width / 2 - 82, baseY - 2, 164, 2, borderGlowCol); drawRect(baseX + menu.width / 2 - 82, baseY + 35, 164, 2, borderGlowCol); drawRect(baseX + menu.width / 2 - 82, baseY - 2, 2, 39, borderGlowCol); drawRect(baseX + menu.width / 2 + 80, baseY - 2, 2, 39, borderGlowCol); // Badge text let badgeShadow = toColour(0, 0, 0, alpha); let badgeText = toColour(255, 255, 255, alpha); drawText("TRIDENT EDITION", baseX + menu.width / 2 - 60, baseY + 11, badgeShadow, 13); drawText("TRIDENT EDITION", baseX + menu.width / 2 - 61, baseY + 10, badgeText, 13); // Version number let versionCol = toColour(MDB.Gold.r, MDB.Gold.g, MDB.Gold.b, Math.floor(FlashingGhost * menuOpenAnim)); drawText("v2.0", baseX + menu.width / 2 + 48, baseY + 12, versionCol, 10); }); // Draw rectangle using graphics API function drawRect(x, y, w, h, colour) { try { let pos = new Vec2(x, y); let size = new Vec2(w, h); graphics.drawRectangle(null, pos, size, colour, colour, colour, colour); } catch(e) {} } // Draw gradient rectangle (left color to right color) function drawGradientRect(x, y, w, h, colourLeft, colourRight) { try { let pos = new Vec2(x, y); let size = new Vec2(w, h); graphics.drawRectangle(null, pos, size, colourLeft, colourRight, colourLeft, colourRight); } catch(e) {} } // Draw text using loaded font or fallback function drawText(text, x, y, colour, size) { if (menuFont != null) { try { let pos = new Vec2(x, y); menuFont.render(text, pos, menu.width, 0.0, 0.0, size, colour, false, false, false, true); } catch(e) {} } } // ============================================================================ // NOTIFICATIONS (stub - notifications removed, function kept for compatibility) // ============================================================================ function showNotification(text) { // Notifications removed - toggle states now shown in menu labels } // ============================================================================ // TOGGLE EFFECTS // ============================================================================ // Track last toggle states to only call native when changed let lastGodMode = false; let lastInvincible = false; let lastSuperRun = false; let lastNoRagdoll = false; let lastVehGodMode = false; let lastDriftMode = false; let lastInvisible = false; let processCounter = 0; // Spinbot speed control (lower = slower) let spinbotSpeed = 2; addEventHandler("OnProcess", function(event) { if (!localPlayer) return; processCounter++; // Player god mode - use invincibility native + health if (toggleStates.godMode !== lastGodMode) { try { natives.setCharInvincible(localPlayer, toggleStates.godMode); } catch(e) {} lastGodMode = toggleStates.godMode; } // Keep health topped up in god mode as backup if (toggleStates.godMode) { if (localPlayer.health < 200) localPlayer.health = 200; if (localPlayer.armour < 100) localPlayer.armour = 100; } // Invincible toggle - separate from god mode, just invincibility if (toggleStates.invincible !== lastInvincible) { try { natives.setCharInvincible(localPlayer, toggleStates.invincible); natives.setCharProofs(localPlayer, toggleStates.invincible, toggleStates.invincible, toggleStates.invincible, toggleStates.invincible, toggleStates.invincible); } catch(e) {} lastInvincible = toggleStates.invincible; } // Super Run - increase movement speed if (toggleStates.superRun !== lastSuperRun) { try { if (toggleStates.superRun) { natives.setCharMoveAnimSpeedMultiplier(localPlayer, 3.0); } else { natives.setCharMoveAnimSpeedMultiplier(localPlayer, 1.0); } } catch(e) {} lastSuperRun = toggleStates.superRun; } // No Ragdoll - prevent ragdoll using multiple methods if (toggleStates.noRagdoll !== lastNoRagdoll) { try { // Use GTA IV specific natives natives.setCharCanBeKnockedOffBike(localPlayer, !toggleStates.noRagdoll); natives.setCharWillFlyThroughWindscreen(localPlayer, !toggleStates.noRagdoll); } catch(e) {} lastNoRagdoll = toggleStates.noRagdoll; } // Keep preventing ragdoll every frame if (toggleStates.noRagdoll) { try { // Multiple approaches for GTA IV ragdoll prevention natives.setCharCanBeKnockedOffBike(localPlayer, false); natives.setCharWillFlyThroughWindscreen(localPlayer, false); // Unlock ragdoll to reset it, then prevent natives.unlockRagdoll(localPlayer, true); // Make character not fall from hits natives.setCharNeverTargetted(localPlayer, false); // If currently in ragdoll, recover try { if (natives.isPedRagdoll(localPlayer)) { natives.switchPedToAnimated(localPlayer, true); } } catch(e2) {} // Alternative: task to stand up try { natives.taskSetCharDecisionMaker(localPlayer, 0); } catch(e3) {} } catch(e) {} } // Never wanted - clear wanted level if (toggleStates.neverWanted) { try { natives.clearWantedLevel(0); } catch(e) { localPlayer.wantedLevel = 0; } } // Invisible - make player invisible if (toggleStates.invisible) { try { natives.setCharVisible(localPlayer, false); } catch(e) {} } else { try { natives.setCharVisible(localPlayer, true); } catch(e) {} } // Infinite Sprint - never get tired if (toggleStates.infiniteSprint) { try { natives.setCharNeverTired(localPlayer, true); } catch(e) {} } // Freeze Position - lock player in place if (toggleStates.freezePlayer) { try { natives.freezeCharPosition(localPlayer, true); } catch(e) {} } else { try { natives.freezeCharPosition(localPlayer, false); } catch(e) {} } // Fire Bullets - set bullets on fire if (toggleStates.fireBullets) { try { natives.setCharShootRate(localPlayer, 100); } catch(e) {} } // Unlimited Ammo - add ammo for all weapon types if (toggleStates.unlimitedAmmo && processCounter % 30 === 0) { try { // Add ammo for common weapon IDs (pistol, shotgun, smg, rifle, sniper, rpg) let weaponIds = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]; for (let i = 0; i < weaponIds.length; i++) { natives.addAmmoToChar(localPlayer, weaponIds[i], 999); } } catch(e) {} } // No Reload - keep ammo in clip full if (toggleStates.noReload && processCounter % 5 === 0) { try { natives.setCharAmmoInClip(localPlayer, 999); } catch(e) {} } // Spinbot - rotate character heading if (toggleStates.spinbot) { try { let currentHeading = localPlayer.heading || 0; localPlayer.heading = (currentHeading + 10) % 360; } catch(e) {} } // Vehicle-specific toggles if (localPlayer.vehicle) { let veh = localPlayer.vehicle; // Vehicle god mode if (toggleStates.vehGodMode !== lastVehGodMode) { try { natives.setCarCanBeDamaged(veh, !toggleStates.vehGodMode); } catch(e) {} lastVehGodMode = toggleStates.vehGodMode; } if (toggleStates.vehGodMode) { try { natives.fixCar(veh); } catch(e) {} } // Drive on water - keep vehicle above water level if (toggleStates.driveOnWater) { try { let pos = veh.position; let waterZ = 0; // Sea level in GTA IV if (pos.z < waterZ + 1) { // Keep car floating on water let vel = veh.velocity; veh.position = new Vec3(pos.x, pos.y, waterZ + 0.8); // Maintain forward momentum but cancel downward if (vel.z < 0) { veh.velocity = new Vec3(vel.x, vel.y, 0); } } } catch(e) {} } // Rainbow car color - cycle through colors if (toggleStates.rainbowCar && processCounter % 5 === 0) { try { rainbowHue = (rainbowHue + 3) % 360; let rgb = hsvToRgb(rainbowHue, 1, 1); // Use closest GTA color (cycle through color indices) let colorIndex = Math.floor(rainbowHue / 3) % 132; natives.changeCarColour(veh, colorIndex, colorIndex); } catch(e) {} } // Drift mode - reduce traction if (toggleStates.driftMode !== lastDriftMode) { try { if (toggleStates.driftMode) { // Make car slide more natives.setCarCanBeVisiblyDamaged(veh, false); } } catch(e) {} lastDriftMode = toggleStates.driftMode; } if (toggleStates.driftMode) { // Apply sideways slip when turning try { let vel = veh.velocity; let speed = Math.sqrt(vel.x * vel.x + vel.y * vel.y); if (speed > 10) { // Add slight sideways force for drift effect let heading = veh.heading || 0; let slideX = Math.cos(heading) * 0.5; let slideY = -Math.sin(heading) * 0.5; veh.velocity = new Vec3(vel.x + slideX, vel.y + slideY, vel.z); } } catch(e) {} } // ===== HANDLING EDITOR EFFECTS ===== // Apply acceleration boost when driveForce is modified if (handlingMods.acceleration > 1.0) { try { let vel = veh.velocity; let speed = Math.sqrt(vel.x * vel.x + vel.y * vel.y); // Only boost when accelerating (moving forward) if (speed > 1 && speed < 50) { let heading = veh.heading || 0; let boostFactor = (handlingMods.acceleration - 1.0) * 0.05; let boostX = Math.sin(heading) * -boostFactor * speed; let boostY = Math.cos(heading) * boostFactor * speed; veh.velocity = new Vec3(vel.x + boostX, vel.y + boostY, vel.z); } } catch(e) {} } // Apply top speed limiting/boosting if (handlingMods.topSpeed !== 1.0) { try { let vel = veh.velocity; let speed = Math.sqrt(vel.x * vel.x + vel.y * vel.y); let maxSpeed = 35 * handlingMods.topSpeed; // Base max ~35 m/s (~126 km/h) // If going too fast for the setting, slow down if (speed > maxSpeed && handlingMods.topSpeed < 1.0) { let factor = maxSpeed / speed; veh.velocity = new Vec3(vel.x * factor, vel.y * factor, vel.z); } // If speed boost is enabled and accelerating, add forward push else if (handlingMods.topSpeed > 1.0 && speed > 20 && speed < maxSpeed) { let heading = veh.heading || 0; let pushFactor = (handlingMods.topSpeed - 1.0) * 0.02; let pushX = Math.sin(heading) * -pushFactor * speed; let pushY = Math.cos(heading) * pushFactor * speed; veh.velocity = new Vec3(vel.x + pushX, vel.y + pushY, vel.z); } } catch(e) {} } // Apply enhanced braking if (handlingMods.braking > 1.0) { // Braking effect is passive - applied when vehicle is slowing down // This would need input detection to work properly } // Fly mode - WASD controls altitude if (toggleStates.flyMode) { try { let pos = veh.position; let vel = veh.velocity; let heading = veh.heading || 0; // Anti-gravity - keep vehicle airborne if (vel.z < 0) { veh.velocity = new Vec3(vel.x, vel.y, vel.z * 0.5); } // Lift vehicle veh.position = new Vec3(pos.x, pos.y, pos.z + 0.1); // Apply forward force based on heading let forwardX = Math.sin(heading) * -2; let forwardY = Math.cos(heading) * 2; veh.velocity = new Vec3(vel.x + forwardX * 0.1, vel.y + forwardY * 0.1, 0.5); } catch(e) {} } // Vehicle shoots RPG if (toggleStates.vehShootRPG) { let now = Date.now(); if (now - lastVehShot > 500) { // Fire every 500ms when key held try { let pos = veh.position; let heading = veh.heading || 0; // Shoot from front of vehicle let frontX = pos.x + Math.sin(heading) * -5; let frontY = pos.y + Math.cos(heading) * 5; let fromPos = new Vec3(frontX, frontY, pos.z + 1); let toX = frontX + Math.sin(heading) * -100; let toY = frontY + Math.cos(heading) * 100; let toPos = new Vec3(toX, toY, pos.z + 1); // Shoot projectile natives.shootSingleBulletBetweenCoords( fromPos.x, fromPos.y, fromPos.z, toPos.x, toPos.y, toPos.z, 100, true, 18, localPlayer, true, true, 100 ); lastVehShot = now; } catch(e) {} } } } // Rainbow sky effect if (toggleStates.rainbowSky && processCounter % 3 === 0) { try { rainbowHue = (rainbowHue + 2) % 360; let rgb = hsvToRgb(rainbowHue, 0.7, 1); natives.setSkyboxTint(rgb.r, rgb.g, rgb.b); } catch(e) {} } // Static sky color if (!toggleStates.rainbowSky && skyColorIndex > 0) { try { let color = skyColors[skyColorIndex]; natives.setSkyboxTint(color.r, color.g, color.b); } catch(e) {} } // COMPLETELY disable phone when menu is open if (menuOpen) { try { // Multiple methods to kill phone natives.destroyMobilePhone(); natives.scriptIsUsingMobilePhone(true); // Block player input to phone natives.taskUseMobilePhone(localPlayer, false); // Force phone off if (natives.getPlayerIsUsingMobilePhone(0)) { natives.destroyMobilePhone(); } } catch(e) {} } }); // HSV to RGB conversion for rainbow effects function hsvToRgb(h, s, v) { let r, g, b; let i = Math.floor(h / 60) % 6; let f = h / 60 - i; let p = v * (1 - s); let q = v * (1 - f * s); let t = v * (1 - (1 - f) * s); switch (i) { case 0: r = v; g = t; b = p; break; case 1: r = q; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = q; b = v; break; case 4: r = t; g = p; b = v; break; case 5: r = v; g = p; b = q; break; } return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) }; } // Neon lights rendering - draw colored lights under vehicle using drawLightWithRange addEventHandler("OnProcess", function(event) { if (!toggleStates.neonLights || !localPlayer || !localPlayer.vehicle) return; try { let veh = localPlayer.vehicle; let pos = veh.position; let heading = veh.heading || 0; // Convert heading to radians for rotation let cosH = Math.cos(heading); let sinH = Math.sin(heading); // Neon light positions relative to vehicle center // Format: { x: side offset, y: front/back, z: height, range: light radius } let neonPoints = [ // Left side strip (front to back) { x: -1.2, y: 1.5, z: -0.4, range: 3.0 }, { x: -1.2, y: 0.5, z: -0.4, range: 3.0 }, { x: -1.2, y: -0.5, z: -0.4, range: 3.0 }, { x: -1.2, y: -1.5, z: -0.4, range: 3.0 }, // Right side strip (front to back) { x: 1.2, y: 1.5, z: -0.4, range: 3.0 }, { x: 1.2, y: 0.5, z: -0.4, range: 3.0 }, { x: 1.2, y: -0.5, z: -0.4, range: 3.0 }, { x: 1.2, y: -1.5, z: -0.4, range: 3.0 }, // Front strip { x: -0.6, y: 2.0, z: -0.4, range: 2.5 }, { x: 0.6, y: 2.0, z: -0.4, range: 2.5 }, // Rear strip { x: -0.6, y: -2.0, z: -0.4, range: 2.5 }, { x: 0.6, y: -2.0, z: -0.4, range: 2.5 } ]; // Draw each neon light point for (let i = 0; i < neonPoints.length; i++) { let point = neonPoints[i]; // Rotate point by vehicle heading let worldX = pos.x + (point.x * cosH - point.y * sinH); let worldY = pos.y + (point.x * sinH + point.y * cosH); let worldZ = pos.z + point.z; // Draw light with range (GTA IV native) // drawLightWithRange(x, y, z, r, g, b, range, intensity) try { natives.drawLightWithRange( worldX, worldY, worldZ, neonColor.r, neonColor.g, neonColor.b, point.range, 1.0 ); } catch(e1) { // Fallback: try alternate parameter order try { natives.drawLightWithRange( worldX, worldY, worldZ, neonColor.r / 255, neonColor.g / 255, neonColor.b / 255, point.range, 100.0 ); } catch(e2) {} } } } catch(e) { console.log("[ModMenu] Neon error: " + e); } }); // Explosive ammo - detect player shooting let lastPlayerPos = null; addEventHandler("OnPedWeaponShoot", function(event, ped, weapon) { if (!toggleStates.explosiveAmmo) return; if (ped !== localPlayer) return; try { // Create explosion at impact point // Since we can't get exact impact, create small explosion in front let pos = localPlayer.position; let heading = localPlayer.heading || 0; let dist = 20; // Distance in front let expX = pos.x + Math.sin(heading) * -dist; let expY = pos.y + Math.cos(heading) * dist; // Small delay then explode setTimeout(function() { try { natives.addExplosion(expX, expY, pos.z, 0, 2.0, true, false, 0.5); } catch(e) {} }, 100); } catch(e) {} }); // ============================================================================ // INITIALIZATION // ============================================================================ // ============================================================================ // HANDLING EDITOR FUNCTIONS // ============================================================================ // Apply a single handling value to the current vehicle // Uses verified GTA IV natives and GTA Connected OOP properties function applyHandlingValue(param, value) { if (!localPlayer || !localPlayer.vehicle) return; let veh = localPlayer.vehicle; try { switch(param) { case "tractionCurveMax": // SET_CAR_TRACTION - Verified GTA IV native // Multiplies the vehicle's traction try { natives.setCarTraction(veh, value); } catch(e) { console.log("[Handling] setCarTraction failed: " + e); } break; case "tractionCurveMin": // Apply combined with max for overall grip feel try { let combinedTraction = (handlingValues.tractionCurveMax + value) / 2; natives.setCarTraction(veh, combinedTraction); } catch(e) {} break; case "tractionBias": // Adjust traction based on front/rear distribution // Lower values = more rear grip, higher = more front try { let adjustedTraction = handlingValues.tractionCurveMax * (0.5 + (value - 0.5) * 0.5); natives.setCarTraction(veh, adjustedTraction); } catch(e) {} break; case "tractionLoss": // Higher values = easier to lose traction // Apply reduced traction based on loss value try { let lossTraction = handlingValues.tractionCurveMax / (1 + (value - 0.8)); natives.setCarTraction(veh, Math.max(0.3, lossTraction)); } catch(e) {} break; case "suspensionForce": // Visual feedback - suspension stiffness affects bounce animation suspensionOffset = (value - 2.0) * 0.02; // Stiffer = less bounce break; case "suspensionRaise": // Visual suspension height offset suspensionOffset = value; break; case "suspensionCompDamp": // Affects bounce feel - stored for visual animation break; case "driveForce": // Engine power - affects acceleration multiplier handlingMods.acceleration = value / 0.25; // For actual speed boost, we'll apply this in the process loop break; case "initialDriveMaxVel": // Top speed - store multiplier for speed limiting handlingMods.topSpeed = value / 200.0; break; case "brakeForce": // Brake strength multiplier handlingMods.braking = value / 0.8; break; case "mass": // SET_CAR_MASS or use OOP property try { // Try native first natives.setCarMass(veh, value); } catch(e1) { // Fallback to OOP property if available try { veh.mass = value; } catch(e2) { console.log("[Handling] mass set failed: " + e2); } } break; case "centreOfMassZ": // Try OOP property for center of mass try { if (veh.centerOfMass) { let com = veh.centerOfMass; veh.centerOfMass = new Vec3(com.x, com.y, value); } } catch(e) {} break; case "steeringLock": // Steering angle - visual/stored only // GTA IV doesn't have a runtime native for this break; } } catch(e) { console.log("[HandlingEditor] Error applying " + param + ": " + e); } } // Reset handling to default values function resetHandlingToDefault() { handlingValues = { tractionCurveMax: 2.0, tractionCurveMin: 1.8, tractionBias: 0.5, suspensionForce: 2.0, suspensionCompDamp: 1.0, suspensionReboundDamp: 1.2, suspensionUpperLimit: 0.12, suspensionLowerLimit: -0.10, suspensionRaise: 0.0, driveForce: 0.25, driveInertia: 1.0, initialDriveMaxVel: 200.0, brakeForce: 0.8, mass: 1500.0, centreOfMassZ: 0.0, steeringLock: 35.0, tractionLoss: 0.8 }; // Reset visual feedback tyreGlowColors = { fr: {r:0,g:255,b:100}, fl: {r:0,g:255,b:100}, rr: {r:0,g:255,b:100}, rl: {r:0,g:255,b:100} }; engineGlow.intensity = 0; brakeGlow.intensity = 0; suspensionOffset = 0; selectedHandlingParam = ""; // Apply defaults to vehicle if (localPlayer && localPlayer.vehicle) { let veh = localPlayer.vehicle; // Reset traction try { natives.setCarTraction(veh, 2.0); } catch(e) { console.log("[Handling] Reset traction failed: " + e); } // Reset mass try { natives.setCarMass(veh, 1500.0); } catch(e1) { try { veh.mass = 1500.0; } catch(e2) {} } // Repair vehicle to reset any damage-based handling issues try { natives.fixCar(veh); } catch(e) {} } // Reset handling mods (independent from drift mode toggle) handlingMods = { grip: 1.0, acceleration: 1.0, topSpeed: 1.0, braking: 1.0 }; console.log("[Handling] Reset to defaults"); } // Apply handling presets function applyHandlingPreset(preset) { switch(preset) { case "race": handlingValues.tractionCurveMax = 3.5; handlingValues.tractionCurveMin = 3.0; handlingValues.suspensionForce = 4.0; handlingValues.suspensionCompDamp = 2.0; handlingValues.suspensionRaise = -0.05; handlingValues.driveForce = 0.50; handlingValues.initialDriveMaxVel = 300.0; handlingValues.brakeForce = 1.5; handlingValues.mass = 1200.0; break; case "drift": handlingValues.tractionCurveMax = 1.5; handlingValues.tractionCurveMin = 1.0; handlingValues.tractionLoss = 1.8; handlingValues.tractionBias = 0.7; handlingValues.suspensionForce = 3.0; handlingValues.driveForce = 0.40; handlingValues.brakeForce = 1.0; // Low traction values create drift feeling without needing drift mode toggle break; case "offroad": handlingValues.tractionCurveMax = 2.5; handlingValues.suspensionForce = 1.5; handlingValues.suspensionCompDamp = 0.6; handlingValues.suspensionRaise = 0.12; handlingValues.driveForce = 0.35; handlingValues.mass = 2000.0; break; case "lowrider": handlingValues.suspensionForce = 0.8; handlingValues.suspensionCompDamp = 0.4; handlingValues.suspensionRaise = -0.12; handlingValues.driveForce = 0.20; handlingValues.initialDriveMaxVel = 150.0; break; } // Apply all values for (let param in handlingValues) { applyHandlingValue(param, handlingValues[param]); } // Update visuals updateAllHandlingVisuals(); } // Update visual feedback based on parameter function updateHandlingVisuals(param, value) { switch(param) { case "tractionCurveMax": case "tractionCurveMin": case "tractionLoss": // Tyre color: Red = low grip, Green = high grip let gripFactor = Math.min(1, Math.max(0, (value - 0.5) / 4.0)); let r = Math.floor(255 * (1 - gripFactor)); let g = Math.floor(255 * gripFactor); tyreGlowColors.fr = tyreGlowColors.fl = tyreGlowColors.rr = tyreGlowColors.rl = {r: r, g: g, b: 50}; break; case "tractionBias": // Front vs rear tyre colors let frontGrip = 1 - value; let rearGrip = value; tyreGlowColors.fr = tyreGlowColors.fl = {r: Math.floor(255 * (1 - frontGrip)), g: Math.floor(255 * frontGrip), b: 50}; tyreGlowColors.rr = tyreGlowColors.rl = {r: Math.floor(255 * (1 - rearGrip)), g: Math.floor(255 * rearGrip), b: 50}; break; case "driveForce": // Engine glow intensity based on power engineGlow.intensity = Math.min(1, value / 0.5); engineGlow.r = 255; engineGlow.g = Math.floor(100 + 100 * (1 - engineGlow.intensity)); engineGlow.b = 0; break; case "brakeForce": // Brake glow brakeGlow.intensity = Math.min(1, value / 2.0); break; case "suspensionRaise": suspensionOffset = value; break; case "mass": // Heavier = darker shadow/glow underneath break; } } // Update all visuals based on current handling values function updateAllHandlingVisuals() { updateHandlingVisuals("tractionCurveMax", handlingValues.tractionCurveMax); updateHandlingVisuals("driveForce", handlingValues.driveForce); updateHandlingVisuals("brakeForce", handlingValues.brakeForce); updateHandlingVisuals("suspensionRaise", handlingValues.suspensionRaise); } // Check if we're in a handling editor submenu function isInHandlingEditor() { return currentMenu === "handlingEditor" || currentMenu.startsWith("handling_"); } // ============================================================================ // HANDLING EDITOR VISUALIZATION - Clean & Informative // ============================================================================ // Render the handling editor visualization addEventHandler("OnDrawnHUD", function(event) { // Only render when in handling editor menus and menu is open if (!menuOpen || !isInHandlingEditor()) { handlingEditorAnim = Math.max(0, handlingEditorAnim - 0.15); if (handlingEditorAnim <= 0) return; } else { handlingEditorAnim = Math.min(1, handlingEditorAnim + 0.12); } let theme = getTheme(); let alpha = Math.floor(255 * handlingEditorAnim); // Panel position (left side of screen) let panelX = 40; let panelY = 120; let panelW = 380; let panelH = 520; // Slide in animation let slideOffset = (1 - handlingEditorAnim) * -150; panelX += slideOffset; // ===== PANEL BACKGROUND ===== let bgColor = toColour(15, 15, 20, Math.floor(235 * handlingEditorAnim)); drawRect(panelX, panelY, panelW, panelH, bgColor); // Border let borderColor = toColour(theme.primary.r, theme.primary.g, theme.primary.b, Math.floor(alpha * 0.8)); drawRect(panelX, panelY, panelW, 2, borderColor); drawRect(panelX, panelY + panelH - 2, panelW, 2, borderColor); drawRect(panelX, panelY, 2, panelH, borderColor); drawRect(panelX + panelW - 2, panelY, 2, panelH, borderColor); // ===== HEADER ===== let headerBg = toColour(25, 25, 35, alpha); drawRect(panelX + 2, panelY + 2, panelW - 4, 35, headerBg); let titleColor = toColour(255, 255, 255, alpha); drawText("HANDLING TUNER", panelX + 12, panelY + 10, titleColor, 16); // Vehicle status let statusText = "NO VEHICLE"; let statusColor = toColour(255, 80, 80, alpha); if (localPlayer && localPlayer.vehicle) { statusText = "ACTIVE"; statusColor = toColour(80, 255, 80, alpha); } drawText(statusText, panelX + panelW - 70, panelY + 12, statusColor, 11); // ===== TOP-DOWN CAR DIAGRAM ===== let carCenterX = panelX + panelW / 2; let carCenterY = panelY + 130; let carW = 70; let carH = 120; let carX = carCenterX - carW / 2; let carY = carCenterY - carH / 2; // Suspension height visual offset (subtle) let suspOffset = suspensionOffset * 30; carY += suspOffset; // Car body outline let bodyOutline = toColour(60, 60, 70, alpha); drawRect(carX - 1, carY - 1, carW + 2, carH + 2, bodyOutline); // Car body let bodyColor = toColour(50, 50, 60, alpha); drawRect(carX, carY, carW, carH, bodyColor); // Windshield let glassColor = toColour(80, 100, 120, alpha); drawRect(carX + 10, carY + 25, carW - 20, 25, glassColor); drawRect(carX + 12, carY + carH - 35, carW - 24, 18, glassColor); // ===== WHEELS WITH GRIP INDICATOR ===== let wheelW = 18; let wheelH = 30; let wheels = [ { x: carX - wheelW + 3, y: carY + 12, color: tyreGlowColors.fl, label: "FL" }, { x: carX + carW - 3, y: carY + 12, color: tyreGlowColors.fr, label: "FR" }, { x: carX - wheelW + 3, y: carY + carH - 12 - wheelH, color: tyreGlowColors.rl, label: "RL" }, { x: carX + carW - 3, y: carY + carH - 12 - wheelH, color: tyreGlowColors.rr, label: "RR" } ]; for (let i = 0; i < wheels.length; i++) { let w = wheels[i]; // Wheel background let wheelBg = toColour(25, 25, 30, alpha); drawRect(w.x, w.y, wheelW, wheelH, wheelBg); // Grip indicator bar on wheel (colored based on traction) let gripBarH = Math.floor(wheelH * 0.8); let gripColor = toColour(w.color.r, w.color.g, w.color.b, alpha); drawRect(w.x + 2, w.y + (wheelH - gripBarH) / 2, 4, gripBarH, gripColor); // Wheel outline let wheelOutline = toColour(80, 80, 90, alpha); drawRect(w.x, w.y, wheelW, 1, wheelOutline); drawRect(w.x, w.y + wheelH - 1, wheelW, 1, wheelOutline); } // ===== TRACTION BIAS ARROWS ===== let biasY = carCenterY; let frontBias = 1 - handlingValues.tractionBias; let rearBias = handlingValues.tractionBias; // Front bias indicator (above car) let frontArrowColor = toColour(100, 200, 100, Math.floor(alpha * frontBias)); drawRect(carCenterX - 15, carY - 15, 30, 3, frontArrowColor); drawText(Math.floor(frontBias * 100) + "%", carCenterX - 12, carY - 28, frontArrowColor, 9); // Rear bias indicator (below car) let rearArrowColor = toColour(100, 200, 100, Math.floor(alpha * rearBias)); drawRect(carCenterX - 15, carY + carH + 12, 30, 3, rearArrowColor); drawText(Math.floor(rearBias * 100) + "%", carCenterX - 12, carY + carH + 18, rearArrowColor, 9); // Center of mass indicator let comY = carCenterY + (handlingValues.centreOfMassZ * 50); let comColor = toColour(255, 200, 0, alpha); drawRect(carCenterX - 4, comY - 4, 8, 8, comColor); // ===== DATA TABLE ===== let tableX = panelX + 15; let tableY = panelY + 210; let labelCol = toColour(160, 160, 170, alpha); let valueCol = toColour(255, 255, 255, alpha); let rowH = 22; // Section: Traction let sectionColor = toColour(theme.accent.r, theme.accent.g, theme.accent.b, alpha); drawText("TRACTION", tableX, tableY, sectionColor, 11); tableY += 18; drawText("Grip Level:", tableX, tableY, labelCol, 10); drawText(handlingValues.tractionCurveMax.toFixed(2), tableX + 140, tableY, valueCol, 10); let gripDesc = handlingValues.tractionCurveMax < 1.5 ? "Slippery" : handlingValues.tractionCurveMax < 2.5 ? "Normal" : handlingValues.tractionCurveMax < 3.5 ? "High" : "Maximum"; drawText(gripDesc, tableX + 200, tableY, toColour(tyreGlowColors.fr.r, tyreGlowColors.fr.g, tyreGlowColors.fr.b, alpha), 10); tableY += rowH; drawText("Traction Loss:", tableX, tableY, labelCol, 10); drawText(handlingValues.tractionLoss.toFixed(2), tableX + 140, tableY, valueCol, 10); let lossDesc = handlingValues.tractionLoss < 0.5 ? "Stable" : handlingValues.tractionLoss < 1.0 ? "Normal" : "Drifty"; drawText(lossDesc, tableX + 200, tableY, labelCol, 10); tableY += rowH; drawText("Bias (F/R):", tableX, tableY, labelCol, 10); drawText(Math.floor(frontBias * 100) + "/" + Math.floor(rearBias * 100), tableX + 140, tableY, valueCol, 10); tableY += rowH + 8; // Section: Engine drawText("ENGINE", tableX, tableY, sectionColor, 11); tableY += 18; drawText("Power:", tableX, tableY, labelCol, 10); drawText(handlingValues.driveForce.toFixed(2), tableX + 140, tableY, valueCol, 10); let powerPct = Math.floor((handlingValues.driveForce / 1.2) * 100); let powerColor = powerPct > 100 ? toColour(255, 150, 0, alpha) : valueCol; drawText(powerPct + "%", tableX + 200, tableY, powerColor, 10); tableY += rowH; drawText("Top Speed:", tableX, tableY, labelCol, 10); drawText(handlingValues.initialDriveMaxVel.toFixed(0) + " km/h", tableX + 140, tableY, valueCol, 10); tableY += rowH; drawText("Brake Force:", tableX, tableY, labelCol, 10); drawText(handlingValues.brakeForce.toFixed(2), tableX + 140, tableY, valueCol, 10); let brakePct = Math.floor((handlingValues.brakeForce / 3.0) * 100); drawText(brakePct + "%", tableX + 200, tableY, valueCol, 10); tableY += rowH + 8; // Section: Suspension drawText("SUSPENSION", tableX, tableY, sectionColor, 11); tableY += 18; drawText("Height:", tableX, tableY, labelCol, 10); let heightDesc = handlingValues.suspensionRaise < -0.08 ? "Slammed" : handlingValues.suspensionRaise < -0.02 ? "Low" : handlingValues.suspensionRaise < 0.02 ? "Stock" : handlingValues.suspensionRaise < 0.08 ? "Raised" : "Lifted"; drawText(heightDesc, tableX + 140, tableY, valueCol, 10); drawText((handlingValues.suspensionRaise >= 0 ? "+" : "") + handlingValues.suspensionRaise.toFixed(2), tableX + 200, tableY, labelCol, 10); tableY += rowH; drawText("Stiffness:", tableX, tableY, labelCol, 10); let stiffDesc = handlingValues.suspensionForce < 1.5 ? "Soft" : handlingValues.suspensionForce < 3.0 ? "Normal" : handlingValues.suspensionForce < 5.0 ? "Firm" : "Race"; drawText(stiffDesc, tableX + 140, tableY, valueCol, 10); drawText(handlingValues.suspensionForce.toFixed(1), tableX + 200, tableY, labelCol, 10); tableY += rowH + 8; // Section: Weight drawText("WEIGHT", tableX, tableY, sectionColor, 11); tableY += 18; drawText("Mass:", tableX, tableY, labelCol, 10); drawText(handlingValues.mass.toFixed(0) + " kg", tableX + 140, tableY, valueCol, 10); let massDesc = handlingValues.mass < 1000 ? "Light" : handlingValues.mass < 2000 ? "Normal" : handlingValues.mass < 3500 ? "Heavy" : "Tank"; drawText(massDesc, tableX + 200, tableY, labelCol, 10); tableY += rowH; drawText("CoM Height:", tableX, tableY, labelCol, 10); let comDesc = handlingValues.centreOfMassZ < -0.1 ? "Low" : handlingValues.centreOfMassZ < 0.1 ? "Center" : "High"; drawText(comDesc, tableX + 140, tableY, valueCol, 10); tableY += rowH + 8; // ===== LIVE VEHICLE DATA ===== if (localPlayer && localPlayer.vehicle) { let veh = localPlayer.vehicle; drawText("LIVE DATA", tableX, tableY, sectionColor, 11); tableY += 18; try { let vel = veh.velocity; let speed = Math.sqrt(vel.x * vel.x + vel.y * vel.y) * 3.6; // m/s to km/h drawText("Speed:", tableX, tableY, labelCol, 10); drawText(speed.toFixed(0) + " km/h", tableX + 140, tableY, toColour(0, 200, 255, alpha), 10); tableY += rowH; } catch(e) {} try { let health = veh.health; drawText("Health:", tableX, tableY, labelCol, 10); let healthColor = health > 700 ? toColour(0, 255, 0, alpha) : health > 300 ? toColour(255, 200, 0, alpha) : toColour(255, 50, 50, alpha); drawText(health.toFixed(0), tableX + 140, tableY, healthColor, 10); } catch(e) {} } // ===== FOOTER ===== let footerY = panelY + panelH - 22; let footerColor = toColour(100, 100, 110, alpha); drawText("Changes apply in real-time", tableX, footerY, footerColor, 9); }); addEventHandler("OnResourceStart", function(event, resource) { console.log("[ModMenu] Client loaded - Press F5 to open menu"); }); console.log("[ModMenu] Script initialized");