mirror of
https://github.com/iDisaster/GTAConnected.git
synced 2026-03-08 09:25:23 +00:00
Enhance UI with animations, fix handling, add color slots & upgrades
- Add glowing scrollbar with pulsing animation effect - Add selection glow/breathing effect on highlighted items - Add animated accent line at header with center highlight - Add glowing toggle indicators when features are ON - Fix vehicle handling to use proper GTA Connected API: - vehicle.setSuspensionHeight() for suspension - physical.mass property for weight - physical.turnVelocity for center of mass simulation - Add custom 4-color selector (Color 1-4 slots) - Uses vehicle.colour1/2/3/4 properties - Falls back to natives.changeCarColour when needed - Add Vehicle Upgrades menu: - Performance: Nitro, Hydraulics - Wheels: 12 different wheel types - Exhausts: 5 exhaust options - Spoilers: 6 spoiler options - Roof: Scoop and vents - Side skirts: Chrome and alien variants - Remove individual or all upgrades
This commit is contained in:
@@ -62,6 +62,17 @@ let hoverAlpha = 0; // Smooth hover transition
|
|||||||
let selectionAlpha = 0; // Selection highlight alpha
|
let selectionAlpha = 0; // Selection highlight alpha
|
||||||
let smoothSelectedIndex = 0; // Smooth selection position
|
let smoothSelectedIndex = 0; // Smooth selection position
|
||||||
|
|
||||||
|
// Glowing scrollbar animation
|
||||||
|
let scrollbarGlow = 0; // Pulsing glow intensity for scrollbar
|
||||||
|
let scrollbarPulse = 0; // Pulse timer
|
||||||
|
|
||||||
|
// Selection glow animation
|
||||||
|
let selectionGlow = 0; // Pulsing glow for selected item
|
||||||
|
let selectionPulseDir = 1; // Pulse direction
|
||||||
|
|
||||||
|
// Accent line animation
|
||||||
|
let accentLineGlow = 0; // Top accent line glow effect
|
||||||
|
|
||||||
// Game feature variables (rainbow car, matrix mode)
|
// Game feature variables (rainbow car, matrix mode)
|
||||||
let rainbowHue = 0; // For rainbow car feature
|
let rainbowHue = 0; // For rainbow car feature
|
||||||
let matrixEffect = 0; // For matrix mode feature
|
let matrixEffect = 0; // For matrix mode feature
|
||||||
@@ -190,6 +201,19 @@ const itemDescriptions = {
|
|||||||
"thermalVision": "🌡️ THERMAL VISION - See heat signatures in dark!",
|
"thermalVision": "🌡️ THERMAL VISION - See heat signatures in dark!",
|
||||||
"nightVision": "🌙 NIGHT VISION - Enhanced vision in darkness!",
|
"nightVision": "🌙 NIGHT VISION - Enhanced vision in darkness!",
|
||||||
|
|
||||||
|
// Vehicle Color descriptions
|
||||||
|
"veh_color_slot": "🎨 Set individual color slot - customize each color independently!",
|
||||||
|
"veh_color_1": "🎨 PRIMARY COLOR - Main body color of the vehicle!",
|
||||||
|
"veh_color_2": "🎨 SECONDARY COLOR - Accent/trim color of the vehicle!",
|
||||||
|
"veh_color_3": "🎨 TERTIARY COLOR - Additional color detail!",
|
||||||
|
"veh_color_4": "🎨 QUATERNARY COLOR - Extra color option!",
|
||||||
|
|
||||||
|
// Vehicle Upgrade descriptions
|
||||||
|
"veh_upgrade_add": "🔧 Add upgrade - Enhance your vehicle with this mod!",
|
||||||
|
"veh_upgrade_remove": "❌ Remove upgrade - Take off this modification!",
|
||||||
|
"veh_upgrade_remove_all": "🗑️ REMOVE ALL - Strip all upgrades from vehicle!",
|
||||||
|
"veh_upgrades": "🔧 UPGRADES - Add NOS, hydraulics, wheels, spoilers and more!",
|
||||||
|
|
||||||
// Handling Editor descriptions
|
// Handling Editor descriptions
|
||||||
"handling_reset": "🔄 RESET - Restore all handling values to vehicle defaults!",
|
"handling_reset": "🔄 RESET - Restore all handling values to vehicle defaults!",
|
||||||
"handling_preset": "⚡ PRESET - Apply a pre-configured handling setup instantly!",
|
"handling_preset": "⚡ PRESET - Apply a pre-configured handling setup instantly!",
|
||||||
@@ -577,7 +601,9 @@ const menuData = {
|
|||||||
{ label: "Repair Vehicle", action: "veh_repair" },
|
{ label: "Repair Vehicle", action: "veh_repair" },
|
||||||
{ label: "Flip Vehicle", action: "veh_flip" },
|
{ label: "Flip Vehicle", action: "veh_flip" },
|
||||||
{ label: "Vehicle Colors", action: "submenu", target: "veh_colors" },
|
{ label: "Vehicle Colors", action: "submenu", target: "veh_colors" },
|
||||||
|
{ label: "Vehicle Upgrades", action: "submenu", target: "veh_upgrades" },
|
||||||
{ label: "Handling Editor", action: "submenu", target: "handlingEditor" },
|
{ label: "Handling Editor", action: "submenu", target: "handlingEditor" },
|
||||||
|
{ label: "--- Toggles ---", action: "none" },
|
||||||
{ label: "God Mode", action: "toggle", target: "vehGodMode", state: false },
|
{ label: "God Mode", action: "toggle", target: "vehGodMode", state: false },
|
||||||
{ label: "Nitro Boost", action: "veh_nitro" },
|
{ label: "Nitro Boost", action: "veh_nitro" },
|
||||||
{ label: "Drive On Water", action: "toggle", target: "driveOnWater", state: false },
|
{ label: "Drive On Water", action: "toggle", target: "driveOnWater", state: false },
|
||||||
@@ -595,6 +621,54 @@ const menuData = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
veh_upgrades: {
|
||||||
|
title: "VEHICLE UPGRADES",
|
||||||
|
items: [
|
||||||
|
{ label: "--- Performance ---", action: "none" },
|
||||||
|
{ label: "Add Nitro", action: "veh_upgrade_add", value: 1010 },
|
||||||
|
{ label: "Add Hydraulics", action: "veh_upgrade_add", value: 1087 },
|
||||||
|
{ label: "--- Wheels ---", action: "none" },
|
||||||
|
{ label: "Offroad Wheels", action: "veh_upgrade_add", value: 1025 },
|
||||||
|
{ label: "Shadow Wheels", action: "veh_upgrade_add", value: 1073 },
|
||||||
|
{ label: "Mega Wheels", action: "veh_upgrade_add", value: 1074 },
|
||||||
|
{ label: "Rimshine Wheels", action: "veh_upgrade_add", value: 1075 },
|
||||||
|
{ label: "Wires Wheels", action: "veh_upgrade_add", value: 1076 },
|
||||||
|
{ label: "Classic Wheels", action: "veh_upgrade_add", value: 1077 },
|
||||||
|
{ label: "Twist Wheels", action: "veh_upgrade_add", value: 1078 },
|
||||||
|
{ label: "Cutter Wheels", action: "veh_upgrade_add", value: 1079 },
|
||||||
|
{ label: "Switch Wheels", action: "veh_upgrade_add", value: 1080 },
|
||||||
|
{ label: "Grove Wheels", action: "veh_upgrade_add", value: 1081 },
|
||||||
|
{ label: "Import Wheels", action: "veh_upgrade_add", value: 1082 },
|
||||||
|
{ label: "Dollar Wheels", action: "veh_upgrade_add", value: 1083 },
|
||||||
|
{ label: "--- Exhausts ---", action: "none" },
|
||||||
|
{ label: "Upswept Exhaust", action: "veh_upgrade_add", value: 1018 },
|
||||||
|
{ label: "Twin Exhaust", action: "veh_upgrade_add", value: 1019 },
|
||||||
|
{ label: "Large Exhaust", action: "veh_upgrade_add", value: 1020 },
|
||||||
|
{ label: "Medium Exhaust", action: "veh_upgrade_add", value: 1021 },
|
||||||
|
{ label: "Small Exhaust", action: "veh_upgrade_add", value: 1022 },
|
||||||
|
{ label: "--- Spoilers ---", action: "none" },
|
||||||
|
{ label: "Pro Spoiler", action: "veh_upgrade_add", value: 1000 },
|
||||||
|
{ label: "Win Spoiler", action: "veh_upgrade_add", value: 1001 },
|
||||||
|
{ label: "Drag Spoiler", action: "veh_upgrade_add", value: 1002 },
|
||||||
|
{ label: "Alpha Spoiler", action: "veh_upgrade_add", value: 1003 },
|
||||||
|
{ label: "Champ Spoiler", action: "veh_upgrade_add", value: 1014 },
|
||||||
|
{ label: "Fury Spoiler", action: "veh_upgrade_add", value: 1015 },
|
||||||
|
{ label: "--- Roof ---", action: "none" },
|
||||||
|
{ label: "Roof Scoop", action: "veh_upgrade_add", value: 1006 },
|
||||||
|
{ label: "Roof Vent", action: "veh_upgrade_add", value: 1032 },
|
||||||
|
{ label: "Alien Roof Vent", action: "veh_upgrade_add", value: 1033 },
|
||||||
|
{ label: "--- Side Skirts ---", action: "none" },
|
||||||
|
{ label: "Right Alien Skirt", action: "veh_upgrade_add", value: 1007 },
|
||||||
|
{ label: "Left Alien Skirt", action: "veh_upgrade_add", value: 1017 },
|
||||||
|
{ label: "Right Chrome Skirt", action: "veh_upgrade_add", value: 1027 },
|
||||||
|
{ label: "Left Chrome Skirt", action: "veh_upgrade_add", value: 1031 },
|
||||||
|
{ label: "--- Remove Upgrades ---", action: "none" },
|
||||||
|
{ label: "Remove Nitro", action: "veh_upgrade_remove", value: 1010 },
|
||||||
|
{ label: "Remove Hydraulics", action: "veh_upgrade_remove", value: 1087 },
|
||||||
|
{ label: "Remove All Upgrades", action: "veh_upgrade_remove_all" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
handlingEditor: {
|
handlingEditor: {
|
||||||
title: "HANDLING EDITOR",
|
title: "HANDLING EDITOR",
|
||||||
items: [
|
items: [
|
||||||
@@ -808,30 +882,27 @@ const menuData = {
|
|||||||
veh_colors: {
|
veh_colors: {
|
||||||
title: "VEHICLE COLORS",
|
title: "VEHICLE COLORS",
|
||||||
items: [
|
items: [
|
||||||
|
{ label: "--- Quick Colors ---", action: "none" },
|
||||||
{ label: "Black", action: "veh_color", value: [0, 0] },
|
{ label: "Black", action: "veh_color", value: [0, 0] },
|
||||||
{ label: "White", action: "veh_color", value: [18, 18] },
|
{ label: "White", action: "veh_color", value: [18, 18] },
|
||||||
{ label: "Dark Gray", action: "veh_color", value: [4, 4] },
|
{ 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: "Silver", action: "veh_color", value: [12, 12] },
|
||||||
{ label: "Red", action: "veh_color", value: [27, 27] },
|
{ 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: "Candy Red", action: "veh_color", value: [30, 30] },
|
||||||
{ label: "Orange", action: "veh_color", value: [36, 36] },
|
{ label: "Orange", action: "veh_color", value: [36, 36] },
|
||||||
{ label: "Yellow", action: "veh_color", value: [89, 89] },
|
{ 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: "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: "Lime Green", action: "veh_color", value: [55, 55] },
|
||||||
{ label: "Blue", action: "veh_color", value: [62, 62] },
|
{ 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: "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: "Purple", action: "veh_color", value: [99, 99] },
|
||||||
{ label: "Pink", action: "veh_color", value: [100, 100] },
|
{ 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: "Gold", action: "veh_color", value: [37, 37] },
|
||||||
|
{ label: "--- Custom Color Slots ---", action: "none" },
|
||||||
|
{ label: "Color 1 (Primary)", action: "submenu", target: "veh_color_1" },
|
||||||
|
{ label: "Color 2 (Secondary)", action: "submenu", target: "veh_color_2" },
|
||||||
|
{ label: "Color 3 (Tertiary)", action: "submenu", target: "veh_color_3" },
|
||||||
|
{ label: "Color 4 (Quaternary)", action: "submenu", target: "veh_color_4" },
|
||||||
{ label: "--- Two Tone ---", action: "none" },
|
{ label: "--- Two Tone ---", action: "none" },
|
||||||
{ label: "Black/Red", action: "veh_color", value: [0, 27] },
|
{ label: "Black/Red", action: "veh_color", value: [0, 27] },
|
||||||
{ label: "Black/White", action: "veh_color", value: [0, 18] },
|
{ label: "Black/White", action: "veh_color", value: [0, 18] },
|
||||||
@@ -842,6 +913,126 @@ const menuData = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
veh_color_1: {
|
||||||
|
title: "COLOR 1 (PRIMARY)",
|
||||||
|
items: [
|
||||||
|
{ label: "Black (0)", action: "veh_color_slot", slot: 1, value: 0 },
|
||||||
|
{ label: "White (18)", action: "veh_color_slot", slot: 1, value: 18 },
|
||||||
|
{ label: "Dark Gray (4)", action: "veh_color_slot", slot: 1, value: 4 },
|
||||||
|
{ label: "Light Gray (8)", action: "veh_color_slot", slot: 1, value: 8 },
|
||||||
|
{ label: "Silver (12)", action: "veh_color_slot", slot: 1, value: 12 },
|
||||||
|
{ label: "Red (27)", action: "veh_color_slot", slot: 1, value: 27 },
|
||||||
|
{ label: "Dark Red (28)", action: "veh_color_slot", slot: 1, value: 28 },
|
||||||
|
{ label: "Candy Red (30)", action: "veh_color_slot", slot: 1, value: 30 },
|
||||||
|
{ label: "Orange (36)", action: "veh_color_slot", slot: 1, value: 36 },
|
||||||
|
{ label: "Yellow (89)", action: "veh_color_slot", slot: 1, value: 89 },
|
||||||
|
{ label: "Bright Yellow (91)", action: "veh_color_slot", slot: 1, value: 91 },
|
||||||
|
{ label: "Green (50)", action: "veh_color_slot", slot: 1, value: 50 },
|
||||||
|
{ label: "Dark Green (52)", action: "veh_color_slot", slot: 1, value: 52 },
|
||||||
|
{ label: "Lime Green (55)", action: "veh_color_slot", slot: 1, value: 55 },
|
||||||
|
{ label: "Blue (62)", action: "veh_color_slot", slot: 1, value: 62 },
|
||||||
|
{ label: "Dark Blue (64)", action: "veh_color_slot", slot: 1, value: 64 },
|
||||||
|
{ label: "Light Blue (73)", action: "veh_color_slot", slot: 1, value: 73 },
|
||||||
|
{ label: "Bright Blue (82)", action: "veh_color_slot", slot: 1, value: 82 },
|
||||||
|
{ label: "Purple (99)", action: "veh_color_slot", slot: 1, value: 99 },
|
||||||
|
{ label: "Pink (100)", action: "veh_color_slot", slot: 1, value: 100 },
|
||||||
|
{ label: "Hot Pink (101)", action: "veh_color_slot", slot: 1, value: 101 },
|
||||||
|
{ label: "Brown (45)", action: "veh_color_slot", slot: 1, value: 45 },
|
||||||
|
{ label: "Beige (44)", action: "veh_color_slot", slot: 1, value: 44 },
|
||||||
|
{ label: "Gold (37)", action: "veh_color_slot", slot: 1, value: 37 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
veh_color_2: {
|
||||||
|
title: "COLOR 2 (SECONDARY)",
|
||||||
|
items: [
|
||||||
|
{ label: "Black (0)", action: "veh_color_slot", slot: 2, value: 0 },
|
||||||
|
{ label: "White (18)", action: "veh_color_slot", slot: 2, value: 18 },
|
||||||
|
{ label: "Dark Gray (4)", action: "veh_color_slot", slot: 2, value: 4 },
|
||||||
|
{ label: "Light Gray (8)", action: "veh_color_slot", slot: 2, value: 8 },
|
||||||
|
{ label: "Silver (12)", action: "veh_color_slot", slot: 2, value: 12 },
|
||||||
|
{ label: "Red (27)", action: "veh_color_slot", slot: 2, value: 27 },
|
||||||
|
{ label: "Dark Red (28)", action: "veh_color_slot", slot: 2, value: 28 },
|
||||||
|
{ label: "Candy Red (30)", action: "veh_color_slot", slot: 2, value: 30 },
|
||||||
|
{ label: "Orange (36)", action: "veh_color_slot", slot: 2, value: 36 },
|
||||||
|
{ label: "Yellow (89)", action: "veh_color_slot", slot: 2, value: 89 },
|
||||||
|
{ label: "Bright Yellow (91)", action: "veh_color_slot", slot: 2, value: 91 },
|
||||||
|
{ label: "Green (50)", action: "veh_color_slot", slot: 2, value: 50 },
|
||||||
|
{ label: "Dark Green (52)", action: "veh_color_slot", slot: 2, value: 52 },
|
||||||
|
{ label: "Lime Green (55)", action: "veh_color_slot", slot: 2, value: 55 },
|
||||||
|
{ label: "Blue (62)", action: "veh_color_slot", slot: 2, value: 62 },
|
||||||
|
{ label: "Dark Blue (64)", action: "veh_color_slot", slot: 2, value: 64 },
|
||||||
|
{ label: "Light Blue (73)", action: "veh_color_slot", slot: 2, value: 73 },
|
||||||
|
{ label: "Bright Blue (82)", action: "veh_color_slot", slot: 2, value: 82 },
|
||||||
|
{ label: "Purple (99)", action: "veh_color_slot", slot: 2, value: 99 },
|
||||||
|
{ label: "Pink (100)", action: "veh_color_slot", slot: 2, value: 100 },
|
||||||
|
{ label: "Hot Pink (101)", action: "veh_color_slot", slot: 2, value: 101 },
|
||||||
|
{ label: "Brown (45)", action: "veh_color_slot", slot: 2, value: 45 },
|
||||||
|
{ label: "Beige (44)", action: "veh_color_slot", slot: 2, value: 44 },
|
||||||
|
{ label: "Gold (37)", action: "veh_color_slot", slot: 2, value: 37 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
veh_color_3: {
|
||||||
|
title: "COLOR 3 (TERTIARY)",
|
||||||
|
items: [
|
||||||
|
{ label: "Black (0)", action: "veh_color_slot", slot: 3, value: 0 },
|
||||||
|
{ label: "White (18)", action: "veh_color_slot", slot: 3, value: 18 },
|
||||||
|
{ label: "Dark Gray (4)", action: "veh_color_slot", slot: 3, value: 4 },
|
||||||
|
{ label: "Light Gray (8)", action: "veh_color_slot", slot: 3, value: 8 },
|
||||||
|
{ label: "Silver (12)", action: "veh_color_slot", slot: 3, value: 12 },
|
||||||
|
{ label: "Red (27)", action: "veh_color_slot", slot: 3, value: 27 },
|
||||||
|
{ label: "Dark Red (28)", action: "veh_color_slot", slot: 3, value: 28 },
|
||||||
|
{ label: "Candy Red (30)", action: "veh_color_slot", slot: 3, value: 30 },
|
||||||
|
{ label: "Orange (36)", action: "veh_color_slot", slot: 3, value: 36 },
|
||||||
|
{ label: "Yellow (89)", action: "veh_color_slot", slot: 3, value: 89 },
|
||||||
|
{ label: "Bright Yellow (91)", action: "veh_color_slot", slot: 3, value: 91 },
|
||||||
|
{ label: "Green (50)", action: "veh_color_slot", slot: 3, value: 50 },
|
||||||
|
{ label: "Dark Green (52)", action: "veh_color_slot", slot: 3, value: 52 },
|
||||||
|
{ label: "Lime Green (55)", action: "veh_color_slot", slot: 3, value: 55 },
|
||||||
|
{ label: "Blue (62)", action: "veh_color_slot", slot: 3, value: 62 },
|
||||||
|
{ label: "Dark Blue (64)", action: "veh_color_slot", slot: 3, value: 64 },
|
||||||
|
{ label: "Light Blue (73)", action: "veh_color_slot", slot: 3, value: 73 },
|
||||||
|
{ label: "Bright Blue (82)", action: "veh_color_slot", slot: 3, value: 82 },
|
||||||
|
{ label: "Purple (99)", action: "veh_color_slot", slot: 3, value: 99 },
|
||||||
|
{ label: "Pink (100)", action: "veh_color_slot", slot: 3, value: 100 },
|
||||||
|
{ label: "Hot Pink (101)", action: "veh_color_slot", slot: 3, value: 101 },
|
||||||
|
{ label: "Brown (45)", action: "veh_color_slot", slot: 3, value: 45 },
|
||||||
|
{ label: "Beige (44)", action: "veh_color_slot", slot: 3, value: 44 },
|
||||||
|
{ label: "Gold (37)", action: "veh_color_slot", slot: 3, value: 37 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
veh_color_4: {
|
||||||
|
title: "COLOR 4 (QUATERNARY)",
|
||||||
|
items: [
|
||||||
|
{ label: "Black (0)", action: "veh_color_slot", slot: 4, value: 0 },
|
||||||
|
{ label: "White (18)", action: "veh_color_slot", slot: 4, value: 18 },
|
||||||
|
{ label: "Dark Gray (4)", action: "veh_color_slot", slot: 4, value: 4 },
|
||||||
|
{ label: "Light Gray (8)", action: "veh_color_slot", slot: 4, value: 8 },
|
||||||
|
{ label: "Silver (12)", action: "veh_color_slot", slot: 4, value: 12 },
|
||||||
|
{ label: "Red (27)", action: "veh_color_slot", slot: 4, value: 27 },
|
||||||
|
{ label: "Dark Red (28)", action: "veh_color_slot", slot: 4, value: 28 },
|
||||||
|
{ label: "Candy Red (30)", action: "veh_color_slot", slot: 4, value: 30 },
|
||||||
|
{ label: "Orange (36)", action: "veh_color_slot", slot: 4, value: 36 },
|
||||||
|
{ label: "Yellow (89)", action: "veh_color_slot", slot: 4, value: 89 },
|
||||||
|
{ label: "Bright Yellow (91)", action: "veh_color_slot", slot: 4, value: 91 },
|
||||||
|
{ label: "Green (50)", action: "veh_color_slot", slot: 4, value: 50 },
|
||||||
|
{ label: "Dark Green (52)", action: "veh_color_slot", slot: 4, value: 52 },
|
||||||
|
{ label: "Lime Green (55)", action: "veh_color_slot", slot: 4, value: 55 },
|
||||||
|
{ label: "Blue (62)", action: "veh_color_slot", slot: 4, value: 62 },
|
||||||
|
{ label: "Dark Blue (64)", action: "veh_color_slot", slot: 4, value: 64 },
|
||||||
|
{ label: "Light Blue (73)", action: "veh_color_slot", slot: 4, value: 73 },
|
||||||
|
{ label: "Bright Blue (82)", action: "veh_color_slot", slot: 4, value: 82 },
|
||||||
|
{ label: "Purple (99)", action: "veh_color_slot", slot: 4, value: 99 },
|
||||||
|
{ label: "Pink (100)", action: "veh_color_slot", slot: 4, value: 100 },
|
||||||
|
{ label: "Hot Pink (101)", action: "veh_color_slot", slot: 4, value: 101 },
|
||||||
|
{ label: "Brown (45)", action: "veh_color_slot", slot: 4, value: 45 },
|
||||||
|
{ label: "Beige (44)", action: "veh_color_slot", slot: 4, value: 44 },
|
||||||
|
{ label: "Gold (37)", action: "veh_color_slot", slot: 4, value: 37 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
network: {
|
network: {
|
||||||
title: "NETWORK OPTIONS",
|
title: "NETWORK OPTIONS",
|
||||||
items: [
|
items: [
|
||||||
@@ -1440,6 +1631,86 @@ function selectItem() {
|
|||||||
showNotification("Random color!");
|
showNotification("Random color!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "veh_color_slot":
|
||||||
|
// Set individual color slot using vehicle.colour1/2/3/4
|
||||||
|
if (localPlayer && localPlayer.vehicle) {
|
||||||
|
let veh = localPlayer.vehicle;
|
||||||
|
try {
|
||||||
|
switch(item.slot) {
|
||||||
|
case 1:
|
||||||
|
veh.colour1 = item.value;
|
||||||
|
showNotification("Color 1 set to " + item.value);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
veh.colour2 = item.value;
|
||||||
|
showNotification("Color 2 set to " + item.value);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
veh.colour3 = item.value;
|
||||||
|
showNotification("Color 3 set to " + item.value);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
veh.colour4 = item.value;
|
||||||
|
showNotification("Color 4 set to " + item.value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
// Fallback using natives.changeCarColour for slots 1-2
|
||||||
|
try {
|
||||||
|
if (item.slot === 1 || item.slot === 2) {
|
||||||
|
let col1 = item.slot === 1 ? item.value : veh.colour1;
|
||||||
|
let col2 = item.slot === 2 ? item.value : veh.colour2;
|
||||||
|
natives.changeCarColour(veh, col1, col2);
|
||||||
|
showNotification("Color " + item.slot + " set!");
|
||||||
|
}
|
||||||
|
} catch(e2) {
|
||||||
|
console.log("[Color] Failed to set color slot: " + e2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "veh_upgrade_add":
|
||||||
|
// Add upgrade using vehicle.addUpgrade(upgradeId)
|
||||||
|
if (localPlayer && localPlayer.vehicle) {
|
||||||
|
try {
|
||||||
|
localPlayer.vehicle.addUpgrade(item.value);
|
||||||
|
showNotification("Upgrade added!");
|
||||||
|
} catch(e) {
|
||||||
|
console.log("[Upgrades] addUpgrade failed: " + e);
|
||||||
|
showNotification("Upgrade not available for this vehicle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "veh_upgrade_remove":
|
||||||
|
// Remove upgrade using vehicle.removeUpgrade(upgradeId)
|
||||||
|
if (localPlayer && localPlayer.vehicle) {
|
||||||
|
try {
|
||||||
|
localPlayer.vehicle.removeUpgrade(item.value);
|
||||||
|
showNotification("Upgrade removed!");
|
||||||
|
} catch(e) {
|
||||||
|
console.log("[Upgrades] removeUpgrade failed: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "veh_upgrade_remove_all":
|
||||||
|
// Remove all common upgrades
|
||||||
|
if (localPlayer && localPlayer.vehicle) {
|
||||||
|
let veh = localPlayer.vehicle;
|
||||||
|
let upgradeIds = [1010, 1087, 1025, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083,
|
||||||
|
1018, 1019, 1020, 1021, 1022, 1000, 1001, 1002, 1003, 1014, 1015, 1006, 1032, 1033,
|
||||||
|
1007, 1017, 1027, 1031];
|
||||||
|
for (let i = 0; i < upgradeIds.length; i++) {
|
||||||
|
try {
|
||||||
|
veh.removeUpgrade(upgradeIds[i]);
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
showNotification("All upgrades removed!");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case "vehicle_delete":
|
case "vehicle_delete":
|
||||||
triggerNetworkEvent("ModMenu:DeleteVehicles");
|
triggerNetworkEvent("ModMenu:DeleteVehicles");
|
||||||
showNotification("Deleted!");
|
showNotification("Deleted!");
|
||||||
@@ -2395,6 +2666,18 @@ addEventHandler("OnProcess", function(event) {
|
|||||||
// Selection alpha pulse (subtle)
|
// Selection alpha pulse (subtle)
|
||||||
selectionAlpha = 0.5 + Math.sin(animTime * 2) * 0.1;
|
selectionAlpha = 0.5 + Math.sin(animTime * 2) * 0.1;
|
||||||
|
|
||||||
|
// Scrollbar glow pulse animation
|
||||||
|
scrollbarPulse += 0.04;
|
||||||
|
scrollbarGlow = 0.5 + Math.sin(scrollbarPulse) * 0.5;
|
||||||
|
|
||||||
|
// Selection glow pulse (breathing effect)
|
||||||
|
selectionGlow += 0.025 * selectionPulseDir;
|
||||||
|
if (selectionGlow >= 1) selectionPulseDir = -1;
|
||||||
|
if (selectionGlow <= 0.3) selectionPulseDir = 1;
|
||||||
|
|
||||||
|
// Accent line glow animation
|
||||||
|
accentLineGlow = 0.7 + Math.sin(animTime * 1.5) * 0.3;
|
||||||
|
|
||||||
// Screen shake decay
|
// Screen shake decay
|
||||||
if (screenShake > 0) {
|
if (screenShake > 0) {
|
||||||
screenShake -= 0.1;
|
screenShake -= 0.1;
|
||||||
@@ -2538,10 +2821,23 @@ addEventHandler("OnDrawnHUD", function(event) {
|
|||||||
let headerBg = toColour(UI.bgPanel.r, UI.bgPanel.g, UI.bgPanel.b, Math.floor(255 * menuOpenAnim));
|
let headerBg = toColour(UI.bgPanel.r, UI.bgPanel.g, UI.bgPanel.b, Math.floor(255 * menuOpenAnim));
|
||||||
drawRect(baseX + 1, headerY + 1, menu.width - 2, headerH - 1, headerBg);
|
drawRect(baseX + 1, headerY + 1, menu.width - 2, headerH - 1, headerBg);
|
||||||
|
|
||||||
// Accent line at top of header
|
// Accent line at top of header with glow animation
|
||||||
|
let glowLineAlpha = Math.floor(60 * menuOpenAnim * accentLineGlow);
|
||||||
|
let accentGlowCol = toColour(theme.accent.r, theme.accent.g, theme.accent.b, glowLineAlpha);
|
||||||
|
drawRect(baseX - 2, headerY - 3, menu.width + 4, 8, accentGlowCol);
|
||||||
|
|
||||||
let accentCol = toColour(theme.accent.r, theme.accent.g, theme.accent.b, animAlpha);
|
let accentCol = toColour(theme.accent.r, theme.accent.g, theme.accent.b, animAlpha);
|
||||||
drawRect(baseX, headerY, menu.width, 2, accentCol);
|
drawRect(baseX, headerY, menu.width, 2, accentCol);
|
||||||
|
|
||||||
|
// Bright center highlight
|
||||||
|
let brightAccent = toColour(
|
||||||
|
Math.min(255, theme.accent.r + 80),
|
||||||
|
Math.min(255, theme.accent.g + 80),
|
||||||
|
Math.min(255, theme.accent.b + 80),
|
||||||
|
Math.floor(animAlpha * accentLineGlow)
|
||||||
|
);
|
||||||
|
drawRect(baseX + menu.width * 0.25, headerY, menu.width * 0.5, 2, brightAccent);
|
||||||
|
|
||||||
// Title text
|
// Title text
|
||||||
let logoX = baseX + 16;
|
let logoX = baseX + 16;
|
||||||
let logoY = headerY + 18;
|
let logoY = headerY + 18;
|
||||||
@@ -2582,12 +2878,29 @@ addEventHandler("OnDrawnHUD", function(event) {
|
|||||||
let itemY = yPos + (i - scrollOffset) * menu.itemHeight;
|
let itemY = yPos + (i - scrollOffset) * menu.itemHeight;
|
||||||
|
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
// Selected item - accent background
|
// Selected item - glowing accent background
|
||||||
|
let glowIntensity = 0.15 + selectionGlow * 0.15;
|
||||||
|
|
||||||
|
// Outer glow layer
|
||||||
|
let outerGlowAlpha = Math.floor(40 * menuOpenAnim * selectionGlow);
|
||||||
|
let outerGlow = toColour(theme.accent.r, theme.accent.g, theme.accent.b, outerGlowAlpha);
|
||||||
|
drawRect(baseX, itemY - 2, menu.width, menu.itemHeight + 2, outerGlow);
|
||||||
|
|
||||||
|
// Main selection background
|
||||||
let selBgAlpha = Math.floor(255 * menuOpenAnim);
|
let selBgAlpha = Math.floor(255 * menuOpenAnim);
|
||||||
let selBg = toColour(UI.bgSelected.r, UI.bgSelected.g, UI.bgSelected.b, selBgAlpha);
|
let selBg = toColour(UI.bgSelected.r, UI.bgSelected.g, UI.bgSelected.b, selBgAlpha);
|
||||||
drawRect(baseX + 1, itemY, menu.width - 2, menu.itemHeight - 2, selBg);
|
drawRect(baseX + 1, itemY, menu.width - 2, menu.itemHeight - 2, selBg);
|
||||||
|
|
||||||
// Left accent bar
|
// Inner accent overlay (subtle)
|
||||||
|
let innerGlowAlpha = Math.floor(25 * menuOpenAnim * selectionGlow);
|
||||||
|
let innerGlow = toColour(theme.accent.r, theme.accent.g, theme.accent.b, innerGlowAlpha);
|
||||||
|
drawRect(baseX + 1, itemY, menu.width - 2, menu.itemHeight - 2, innerGlow);
|
||||||
|
|
||||||
|
// Left accent bar with glow
|
||||||
|
let barGlowAlpha = Math.floor(100 * menuOpenAnim * selectionGlow);
|
||||||
|
let barGlow = toColour(theme.accent.r, theme.accent.g, theme.accent.b, barGlowAlpha);
|
||||||
|
drawRect(baseX - 2, itemY, 8, menu.itemHeight - 2, barGlow);
|
||||||
|
|
||||||
let accentBarCol = toColour(theme.accent.r, theme.accent.g, theme.accent.b, animAlpha);
|
let accentBarCol = toColour(theme.accent.r, theme.accent.g, theme.accent.b, animAlpha);
|
||||||
drawRect(baseX + 1, itemY, 3, menu.itemHeight - 2, accentBarCol);
|
drawRect(baseX + 1, itemY, 3, menu.itemHeight - 2, accentBarCol);
|
||||||
|
|
||||||
@@ -2631,7 +2944,7 @@ addEventHandler("OnDrawnHUD", function(event) {
|
|||||||
drawText(item.label, textX, textY, normCol, textSize);
|
drawText(item.label, textX, textY, normCol, textSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle status indicator
|
// Toggle status indicator with glow effects
|
||||||
if (item.action === "toggle") {
|
if (item.action === "toggle") {
|
||||||
let isOn = toggleStates[item.target];
|
let isOn = toggleStates[item.target];
|
||||||
let stateX = baseX + menu.width - 55;
|
let stateX = baseX + menu.width - 55;
|
||||||
@@ -2640,15 +2953,39 @@ addEventHandler("OnDrawnHUD", function(event) {
|
|||||||
let boxH = 20;
|
let boxH = 20;
|
||||||
|
|
||||||
if (isOn) {
|
if (isOn) {
|
||||||
// ON state - green pill
|
// ON state - green pill with pulsing glow
|
||||||
let onBg = toColour(UI.success.r, UI.success.g, UI.success.b, Math.floor(200 * menuOpenAnim));
|
let glowIntensity = 0.5 + selectionGlow * 0.5;
|
||||||
|
|
||||||
|
// Outer glow
|
||||||
|
let glowAlpha = Math.floor(50 * menuOpenAnim * glowIntensity);
|
||||||
|
let glowCol = toColour(UI.success.r, UI.success.g, UI.success.b, glowAlpha);
|
||||||
|
drawRect(stateX - 3, boxY - 3, boxW + 6, boxH + 6, glowCol);
|
||||||
|
|
||||||
|
// Main pill
|
||||||
|
let onBg = toColour(UI.success.r, UI.success.g, UI.success.b, Math.floor(220 * menuOpenAnim));
|
||||||
drawRect(stateX, boxY, boxW, boxH, onBg);
|
drawRect(stateX, boxY, boxW, boxH, onBg);
|
||||||
|
|
||||||
|
// Inner highlight
|
||||||
|
let highlightAlpha = Math.floor(80 * menuOpenAnim * glowIntensity);
|
||||||
|
let highlightCol = toColour(
|
||||||
|
Math.min(255, UI.success.r + 60),
|
||||||
|
Math.min(255, UI.success.g + 60),
|
||||||
|
Math.min(255, UI.success.b + 60),
|
||||||
|
highlightAlpha
|
||||||
|
);
|
||||||
|
drawRect(stateX + 2, boxY + 2, boxW - 4, 8, highlightCol);
|
||||||
|
|
||||||
let onText = toColour(255, 255, 255, animAlpha);
|
let onText = toColour(255, 255, 255, animAlpha);
|
||||||
drawText("ON", stateX + 12, boxY + 4, onText, 10);
|
drawText("ON", stateX + 12, boxY + 4, onText, 10);
|
||||||
} else {
|
} else {
|
||||||
// OFF state - muted
|
// OFF state - muted with subtle border
|
||||||
let offBg = toColour(UI.bgHover.r, UI.bgHover.g, UI.bgHover.b, Math.floor(180 * menuOpenAnim));
|
let offBg = toColour(UI.bgHover.r, UI.bgHover.g, UI.bgHover.b, Math.floor(180 * menuOpenAnim));
|
||||||
drawRect(stateX, boxY, boxW, boxH, offBg);
|
drawRect(stateX, boxY, boxW, boxH, offBg);
|
||||||
|
|
||||||
|
// Subtle inner shadow
|
||||||
|
let shadowCol = toColour(0, 0, 0, Math.floor(30 * menuOpenAnim));
|
||||||
|
drawRect(stateX, boxY, boxW, 2, shadowCol);
|
||||||
|
|
||||||
let offText = toColour(UI.textMuted.r, UI.textMuted.g, UI.textMuted.b, animAlpha);
|
let offText = toColour(UI.textMuted.r, UI.textMuted.g, UI.textMuted.b, animAlpha);
|
||||||
drawText("OFF", stateX + 9, boxY + 4, offText, 10);
|
drawText("OFF", stateX + 9, boxY + 4, offText, 10);
|
||||||
}
|
}
|
||||||
@@ -2694,28 +3031,56 @@ addEventHandler("OnDrawnHUD", function(event) {
|
|||||||
drawText("]", baseX + 295, hintY, hintCol, 10);
|
drawText("]", baseX + 295, hintY, hintCol, 10);
|
||||||
drawText("Return", baseX + 305, hintY, hintCol, 10);
|
drawText("Return", baseX + 305, hintY, hintCol, 10);
|
||||||
|
|
||||||
// ===== SCROLLBAR =====
|
// ===== GLOWING SCROLLBAR =====
|
||||||
if (items.length > menu.maxVisibleItems) {
|
if (items.length > menu.maxVisibleItems) {
|
||||||
let scrollbarX = baseX + menu.width - 8;
|
let scrollbarX = baseX + menu.width - 10;
|
||||||
let scrollbarY = baseY + menu.headerHeight + 8;
|
let scrollbarY = baseY + menu.headerHeight + 8;
|
||||||
let scrollbarH = visibleCount * menu.itemHeight - 16;
|
let scrollbarH = visibleCount * menu.itemHeight - 16;
|
||||||
let maxScroll = items.length - visibleCount;
|
let maxScroll = items.length - visibleCount;
|
||||||
let scrollProgress = scrollOffset / maxScroll;
|
let scrollProgress = scrollOffset / maxScroll;
|
||||||
let thumbH = Math.max(30, scrollbarH * (visibleCount / items.length));
|
let thumbH = Math.max(35, scrollbarH * (visibleCount / items.length));
|
||||||
let thumbY = scrollbarY + scrollProgress * (scrollbarH - thumbH);
|
let thumbY = scrollbarY + scrollProgress * (scrollbarH - thumbH);
|
||||||
|
|
||||||
// Track
|
// Outer glow effect for track
|
||||||
let trackBg = toColour(UI.bgHover.r, UI.bgHover.g, UI.bgHover.b, Math.floor(150 * menuOpenAnim));
|
let glowAlpha = Math.floor(30 * menuOpenAnim * scrollbarGlow);
|
||||||
drawRect(scrollbarX, scrollbarY, 4, scrollbarH, trackBg);
|
let trackGlow = toColour(theme.accent.r, theme.accent.g, theme.accent.b, glowAlpha);
|
||||||
|
drawRect(scrollbarX - 3, scrollbarY - 2, 12, scrollbarH + 4, trackGlow);
|
||||||
|
|
||||||
// Thumb
|
// Track background with subtle gradient look
|
||||||
let thumbCol = toColour(theme.accent.r, theme.accent.g, theme.accent.b, Math.floor(200 * menuOpenAnim));
|
let trackBg = toColour(UI.bgHover.r, UI.bgHover.g, UI.bgHover.b, Math.floor(180 * menuOpenAnim));
|
||||||
drawRect(scrollbarX, thumbY, 4, thumbH, thumbCol);
|
drawRect(scrollbarX, scrollbarY, 6, scrollbarH, trackBg);
|
||||||
|
|
||||||
// Page indicator
|
// Inner track line
|
||||||
|
let trackInner = toColour(UI.bgDark.r, UI.bgDark.g, UI.bgDark.b, Math.floor(150 * menuOpenAnim));
|
||||||
|
drawRect(scrollbarX + 1, scrollbarY + 1, 4, scrollbarH - 2, trackInner);
|
||||||
|
|
||||||
|
// Thumb outer glow (pulsing)
|
||||||
|
let thumbGlowAlpha = Math.floor(80 * menuOpenAnim * scrollbarGlow);
|
||||||
|
let thumbGlow = toColour(theme.accent.r, theme.accent.g, theme.accent.b, thumbGlowAlpha);
|
||||||
|
drawRect(scrollbarX - 4, thumbY - 3, 14, thumbH + 6, thumbGlow);
|
||||||
|
|
||||||
|
// Thumb mid glow
|
||||||
|
let thumbMidGlow = toColour(theme.accent.r, theme.accent.g, theme.accent.b, Math.floor(120 * menuOpenAnim * scrollbarGlow));
|
||||||
|
drawRect(scrollbarX - 2, thumbY - 1, 10, thumbH + 2, thumbMidGlow);
|
||||||
|
|
||||||
|
// Thumb main body
|
||||||
|
let thumbCol = toColour(theme.accent.r, theme.accent.g, theme.accent.b, Math.floor(255 * menuOpenAnim));
|
||||||
|
drawRect(scrollbarX, thumbY, 6, thumbH, thumbCol);
|
||||||
|
|
||||||
|
// Thumb highlight (brighter center)
|
||||||
|
let highlightAlpha = Math.floor(255 * menuOpenAnim * (0.5 + scrollbarGlow * 0.5));
|
||||||
|
let thumbHighlight = toColour(
|
||||||
|
Math.min(255, theme.accent.r + 50),
|
||||||
|
Math.min(255, theme.accent.g + 50),
|
||||||
|
Math.min(255, theme.accent.b + 50),
|
||||||
|
highlightAlpha
|
||||||
|
);
|
||||||
|
drawRect(scrollbarX + 1, thumbY + 2, 4, thumbH - 4, thumbHighlight);
|
||||||
|
|
||||||
|
// Page indicator with subtle styling
|
||||||
let pageText = (scrollOffset + 1) + "/" + (maxScroll + 1);
|
let pageText = (scrollOffset + 1) + "/" + (maxScroll + 1);
|
||||||
let pageCol = toColour(UI.textMuted.r, UI.textMuted.g, UI.textMuted.b, animAlpha);
|
let pageCol = toColour(UI.textMuted.r, UI.textMuted.g, UI.textMuted.b, animAlpha);
|
||||||
drawText(pageText, baseX + menu.width - 40, footerY + 26, pageCol, 9);
|
drawText(pageText, baseX + menu.width - 45, footerY + 26, pageCol, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== INFO BAR =====
|
// ===== INFO BAR =====
|
||||||
@@ -3582,7 +3947,12 @@ addEventHandler("OnPedWeaponShoot", function(event, ped, weapon) {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// Apply a single handling value to the current vehicle
|
// Apply a single handling value to the current vehicle
|
||||||
// Uses verified GTA IV natives and GTA Connected OOP properties
|
// Uses GTA Connected API from wiki documentation:
|
||||||
|
// - vehicle.setSuspensionHeight(suspensionId, height) - suspension height
|
||||||
|
// - physical.mass - vehicle mass (read/write)
|
||||||
|
// - physical.turnVelocity - rotational velocity Vec3
|
||||||
|
// - vehicle.strongGrip - grip on bikes (server only)
|
||||||
|
// - natives.changeCarColour - color changes
|
||||||
function applyHandlingValue(param, value) {
|
function applyHandlingValue(param, value) {
|
||||||
if (!localPlayer || !localPlayer.vehicle) return;
|
if (!localPlayer || !localPlayer.vehicle) return;
|
||||||
|
|
||||||
@@ -3592,7 +3962,6 @@ function applyHandlingValue(param, value) {
|
|||||||
switch(param) {
|
switch(param) {
|
||||||
case "tractionCurveMax":
|
case "tractionCurveMax":
|
||||||
// SET_CAR_TRACTION - Verified GTA IV native
|
// SET_CAR_TRACTION - Verified GTA IV native
|
||||||
// Multiplies the vehicle's traction
|
|
||||||
try {
|
try {
|
||||||
natives.setCarTraction(veh, value);
|
natives.setCarTraction(veh, value);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
@@ -3610,7 +3979,6 @@ function applyHandlingValue(param, value) {
|
|||||||
|
|
||||||
case "tractionBias":
|
case "tractionBias":
|
||||||
// Adjust traction based on front/rear distribution
|
// Adjust traction based on front/rear distribution
|
||||||
// Lower values = more rear grip, higher = more front
|
|
||||||
try {
|
try {
|
||||||
let adjustedTraction = handlingValues.tractionCurveMax * (0.5 + (value - 0.5) * 0.5);
|
let adjustedTraction = handlingValues.tractionCurveMax * (0.5 + (value - 0.5) * 0.5);
|
||||||
natives.setCarTraction(veh, adjustedTraction);
|
natives.setCarTraction(veh, adjustedTraction);
|
||||||
@@ -3619,7 +3987,6 @@ function applyHandlingValue(param, value) {
|
|||||||
|
|
||||||
case "tractionLoss":
|
case "tractionLoss":
|
||||||
// Higher values = easier to lose traction
|
// Higher values = easier to lose traction
|
||||||
// Apply reduced traction based on loss value
|
|
||||||
try {
|
try {
|
||||||
let lossTraction = handlingValues.tractionCurveMax / (1 + (value - 0.8));
|
let lossTraction = handlingValues.tractionCurveMax / (1 + (value - 0.8));
|
||||||
natives.setCarTraction(veh, Math.max(0.3, lossTraction));
|
natives.setCarTraction(veh, Math.max(0.3, lossTraction));
|
||||||
@@ -3627,13 +3994,24 @@ function applyHandlingValue(param, value) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "suspensionForce":
|
case "suspensionForce":
|
||||||
// Visual feedback - suspension stiffness affects bounce animation
|
// Suspension stiffness - affects bounce
|
||||||
suspensionOffset = (value - 2.0) * 0.02; // Stiffer = less bounce
|
suspensionOffset = (value - 2.0) * 0.02;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "suspensionRaise":
|
case "suspensionRaise":
|
||||||
// Visual suspension height offset
|
// Use vehicle.setSuspensionHeight for all 4 wheels
|
||||||
|
// suspensionId: 0=FL, 1=FR, 2=RL, 3=RR
|
||||||
|
try {
|
||||||
|
for (let wheelId = 0; wheelId < 4; wheelId++) {
|
||||||
|
veh.setSuspensionHeight(wheelId, value);
|
||||||
|
}
|
||||||
suspensionOffset = value;
|
suspensionOffset = value;
|
||||||
|
console.log("[Handling] Suspension height set to: " + value);
|
||||||
|
} catch(e) {
|
||||||
|
console.log("[Handling] setSuspensionHeight failed: " + e);
|
||||||
|
// Visual fallback
|
||||||
|
suspensionOffset = value;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "suspensionCompDamp":
|
case "suspensionCompDamp":
|
||||||
@@ -3643,7 +4021,6 @@ function applyHandlingValue(param, value) {
|
|||||||
case "driveForce":
|
case "driveForce":
|
||||||
// Engine power - affects acceleration multiplier
|
// Engine power - affects acceleration multiplier
|
||||||
handlingMods.acceleration = value / 0.25;
|
handlingMods.acceleration = value / 0.25;
|
||||||
// For actual speed boost, we'll apply this in the process loop
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "initialDriveMaxVel":
|
case "initialDriveMaxVel":
|
||||||
@@ -3657,14 +4034,14 @@ function applyHandlingValue(param, value) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "mass":
|
case "mass":
|
||||||
// SET_CAR_MASS or use OOP property
|
// Use physical.mass property (GTA Connected API)
|
||||||
try {
|
|
||||||
// Try native first
|
|
||||||
natives.setCarMass(veh, value);
|
|
||||||
} catch(e1) {
|
|
||||||
// Fallback to OOP property if available
|
|
||||||
try {
|
try {
|
||||||
veh.mass = value;
|
veh.mass = value;
|
||||||
|
console.log("[Handling] Mass set to: " + value);
|
||||||
|
} catch(e1) {
|
||||||
|
// Fallback to native
|
||||||
|
try {
|
||||||
|
natives.setCarMass(veh, value);
|
||||||
} catch(e2) {
|
} catch(e2) {
|
||||||
console.log("[Handling] mass set failed: " + e2);
|
console.log("[Handling] mass set failed: " + e2);
|
||||||
}
|
}
|
||||||
@@ -3672,18 +4049,27 @@ function applyHandlingValue(param, value) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "centreOfMassZ":
|
case "centreOfMassZ":
|
||||||
// Try OOP property for center of mass
|
// Adjust turn velocity to simulate center of mass change
|
||||||
|
// Higher CoM = more likely to flip
|
||||||
try {
|
try {
|
||||||
if (veh.centerOfMass) {
|
// Use turnVelocity to apply subtle rotational adjustments
|
||||||
let com = veh.centerOfMass;
|
let currentTurn = veh.turnVelocity;
|
||||||
veh.centerOfMass = new Vec3(com.x, com.y, value);
|
if (value > 0) {
|
||||||
|
// Higher center = add slight instability
|
||||||
|
let instability = value * 0.1;
|
||||||
|
veh.turnVelocity = new Vec3(
|
||||||
|
currentTurn.x * (1 + instability),
|
||||||
|
currentTurn.y * (1 + instability),
|
||||||
|
currentTurn.z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
console.log("[Handling] turnVelocity adjustment failed: " + e);
|
||||||
}
|
}
|
||||||
} catch(e) {}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "steeringLock":
|
case "steeringLock":
|
||||||
// Steering angle - visual/stored only
|
// Steering angle - visual/stored only
|
||||||
// GTA IV doesn't have a runtime native for this
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
@@ -3720,23 +4106,40 @@ function resetHandlingToDefault() {
|
|||||||
suspensionOffset = 0;
|
suspensionOffset = 0;
|
||||||
selectedHandlingParam = "";
|
selectedHandlingParam = "";
|
||||||
|
|
||||||
// Apply defaults to vehicle
|
// Apply defaults to vehicle using proper API
|
||||||
if (localPlayer && localPlayer.vehicle) {
|
if (localPlayer && localPlayer.vehicle) {
|
||||||
let veh = localPlayer.vehicle;
|
let veh = localPlayer.vehicle;
|
||||||
|
|
||||||
// Reset traction
|
// Reset traction
|
||||||
try {
|
try {
|
||||||
natives.setCarTraction(veh, 2.0);
|
natives.setCarTraction(veh, 2.0);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log("[Handling] Reset traction failed: " + e);
|
console.log("[Handling] Reset traction failed: " + e);
|
||||||
}
|
}
|
||||||
// Reset mass
|
|
||||||
try {
|
// Reset mass using physical.mass property
|
||||||
natives.setCarMass(veh, 1500.0);
|
|
||||||
} catch(e1) {
|
|
||||||
try {
|
try {
|
||||||
veh.mass = 1500.0;
|
veh.mass = 1500.0;
|
||||||
|
} catch(e1) {
|
||||||
|
try {
|
||||||
|
natives.setCarMass(veh, 1500.0);
|
||||||
} catch(e2) {}
|
} catch(e2) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset suspension height using vehicle.setSuspensionHeight
|
||||||
|
try {
|
||||||
|
for (let wheelId = 0; wheelId < 4; wheelId++) {
|
||||||
|
veh.setSuspensionHeight(wheelId, 0.0);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
console.log("[Handling] Reset suspension failed: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset turn velocity
|
||||||
|
try {
|
||||||
|
veh.turnVelocity = new Vec3(0, 0, 0);
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
// Repair vehicle to reset any damage-based handling issues
|
// Repair vehicle to reset any damage-based handling issues
|
||||||
try {
|
try {
|
||||||
natives.fixCar(veh);
|
natives.fixCar(veh);
|
||||||
|
|||||||
Reference in New Issue
Block a user