mirror of
https://github.com/iDisaster/GTAConnected.git
synced 2026-03-09 18:05:22 +00:00
Merge pull request #3 from iDisaster/claude/enhance-gta-server-9Dezg
Claude/enhance gta server 9 dezg
This commit is contained in:
@@ -8,36 +8,34 @@
|
|||||||
let menuOpen = false;
|
let menuOpen = false;
|
||||||
let currentMenu = "main";
|
let currentMenu = "main";
|
||||||
let selectedIndex = 0;
|
let selectedIndex = 0;
|
||||||
let menuStack = []; // For back navigation
|
let menuStack = [];
|
||||||
|
let scrollOffset = 0;
|
||||||
|
|
||||||
// Menu colors (RGBA)
|
// Font for text rendering (will be loaded on resource start)
|
||||||
|
let menuFont = null;
|
||||||
|
|
||||||
|
// Menu colors using toColour for integer format
|
||||||
const colors = {
|
const colors = {
|
||||||
background: toColour(20, 20, 20, 200),
|
background: toColour(20, 20, 20, 200),
|
||||||
header: toColour(200, 50, 50, 255),
|
header: toColour(200, 50, 50, 255),
|
||||||
headerText: toColour(255, 255, 255, 255),
|
item: toColour(40, 40, 40, 200),
|
||||||
itemBg: toColour(40, 40, 40, 200),
|
selected: toColour(200, 50, 50, 220),
|
||||||
itemBgSelected: toColour(200, 50, 50, 220),
|
text: toColour(255, 255, 255, 255),
|
||||||
itemText: toColour(255, 255, 255, 255),
|
|
||||||
itemTextSelected: toColour(255, 255, 255, 255),
|
|
||||||
footer: toColour(30, 30, 30, 200),
|
footer: toColour(30, 30, 30, 200),
|
||||||
footerText: toColour(180, 180, 180, 255),
|
subText: toColour(180, 180, 180, 255)
|
||||||
subText: toColour(150, 150, 150, 255)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Menu dimensions
|
// Menu dimensions in pixels - positioned on right side
|
||||||
const menu = {
|
const menu = {
|
||||||
x: 50,
|
x: 1050,
|
||||||
y: 100,
|
y: 120,
|
||||||
width: 300,
|
width: 320,
|
||||||
headerHeight: 40,
|
headerHeight: 45,
|
||||||
itemHeight: 35,
|
itemHeight: 38,
|
||||||
footerHeight: 30,
|
footerHeight: 32,
|
||||||
maxVisibleItems: 12
|
maxVisibleItems: 12
|
||||||
};
|
};
|
||||||
|
|
||||||
// Scroll offset for long menus
|
|
||||||
let scrollOffset = 0;
|
|
||||||
|
|
||||||
// Player list cache
|
// Player list cache
|
||||||
let playerList = [];
|
let playerList = [];
|
||||||
|
|
||||||
@@ -79,9 +77,6 @@ const menuData = {
|
|||||||
{ label: "Clear Wanted Level", action: "self_wanted" },
|
{ label: "Clear Wanted Level", action: "self_wanted" },
|
||||||
{ label: "God Mode", action: "toggle", target: "godMode", state: false },
|
{ label: "God Mode", action: "toggle", target: "godMode", state: false },
|
||||||
{ label: "Never Wanted", action: "toggle", target: "neverWanted", state: false },
|
{ label: "Never Wanted", action: "toggle", target: "neverWanted", state: false },
|
||||||
{ label: "Infinite Ammo", action: "toggle", target: "infiniteAmmo", state: false },
|
|
||||||
{ label: "Super Jump", action: "toggle", target: "superJump", state: false },
|
|
||||||
{ label: "Fast Run", action: "toggle", target: "fastRun", state: false },
|
|
||||||
{ label: "Respawn", action: "self_respawn" },
|
{ label: "Respawn", action: "self_respawn" },
|
||||||
{ label: "Suicide", action: "self_suicide" },
|
{ label: "Suicide", action: "self_suicide" },
|
||||||
{ label: "Change Skin", action: "submenu", target: "skins" }
|
{ label: "Change Skin", action: "submenu", target: "skins" }
|
||||||
@@ -99,11 +94,6 @@ const menuData = {
|
|||||||
{ label: "Johnny Klebitz", action: "skin", value: -1784875845 },
|
{ label: "Johnny Klebitz", action: "skin", value: -1784875845 },
|
||||||
{ label: "Luis Lopez", action: "skin", value: -1403507487 },
|
{ label: "Luis Lopez", action: "skin", value: -1403507487 },
|
||||||
{ label: "Police Officer", action: "skin", value: -1320879687 },
|
{ label: "Police Officer", action: "skin", value: -1320879687 },
|
||||||
{ label: "NOOSE", action: "skin", value: -1306011498 },
|
|
||||||
{ label: "Paramedic", action: "skin", value: 2136829318 },
|
|
||||||
{ label: "Firefighter", action: "skin", value: 1616659040 },
|
|
||||||
{ label: "Business Man", action: "skin", value: -268651930 },
|
|
||||||
{ label: "Hobo", action: "skin", value: 1943617350 },
|
|
||||||
{ label: "Random Skin", action: "skin_random" }
|
{ label: "Random Skin", action: "skin_random" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -112,15 +102,12 @@ const menuData = {
|
|||||||
title: "VEHICLE SPAWNER",
|
title: "VEHICLE SPAWNER",
|
||||||
items: [
|
items: [
|
||||||
{ label: "Sports Cars", action: "submenu", target: "veh_sports" },
|
{ label: "Sports Cars", action: "submenu", target: "veh_sports" },
|
||||||
{ label: "Super Cars", action: "submenu", target: "veh_super" },
|
|
||||||
{ label: "Muscle Cars", action: "submenu", target: "veh_muscle" },
|
{ label: "Muscle Cars", action: "submenu", target: "veh_muscle" },
|
||||||
{ label: "SUVs & Trucks", action: "submenu", target: "veh_suv" },
|
{ label: "SUVs & Trucks", action: "submenu", target: "veh_suv" },
|
||||||
{ label: "Sedans & Compacts", action: "submenu", target: "veh_sedan" },
|
|
||||||
{ label: "Motorcycles", action: "submenu", target: "veh_bikes" },
|
{ label: "Motorcycles", action: "submenu", target: "veh_bikes" },
|
||||||
{ label: "Emergency Vehicles", action: "submenu", target: "veh_emergency" },
|
{ label: "Emergency", action: "submenu", target: "veh_emergency" },
|
||||||
{ label: "Aircraft", action: "submenu", target: "veh_aircraft" },
|
{ label: "Aircraft", action: "submenu", target: "veh_aircraft" },
|
||||||
{ label: "Boats", action: "submenu", target: "veh_boats" },
|
{ label: "Boats", action: "submenu", target: "veh_boats" },
|
||||||
{ label: "Special Vehicles", action: "submenu", target: "veh_special" },
|
|
||||||
{ label: "Delete My Vehicles", action: "vehicle_delete" }
|
{ label: "Delete My Vehicles", action: "vehicle_delete" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -134,23 +121,10 @@ const menuData = {
|
|||||||
{ label: "Banshee", action: "spawn_vehicle", value: "banshee" },
|
{ label: "Banshee", action: "spawn_vehicle", value: "banshee" },
|
||||||
{ label: "Sultan", action: "spawn_vehicle", value: "sultan" },
|
{ label: "Sultan", action: "spawn_vehicle", value: "sultan" },
|
||||||
{ label: "Coquette", action: "spawn_vehicle", value: "coquette" },
|
{ label: "Coquette", action: "spawn_vehicle", value: "coquette" },
|
||||||
{ label: "Feltzer", action: "spawn_vehicle", value: "feltzer" },
|
|
||||||
{ label: "F620", action: "spawn_vehicle", value: "f620" },
|
|
||||||
{ label: "Buffalo", action: "spawn_vehicle", value: "buffalo" }
|
{ label: "Buffalo", action: "spawn_vehicle", value: "buffalo" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
veh_super: {
|
|
||||||
title: "SUPER CARS",
|
|
||||||
items: [
|
|
||||||
{ label: "Entity XF", action: "spawn_vehicle", value: "entityxf" },
|
|
||||||
{ label: "Adder", action: "spawn_vehicle", value: "adder" },
|
|
||||||
{ label: "Vacca", action: "spawn_vehicle", value: "vacca" },
|
|
||||||
{ label: "Bullet", action: "spawn_vehicle", value: "bullet" },
|
|
||||||
{ label: "Cheetah", action: "spawn_vehicle", value: "cheetah" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
veh_muscle: {
|
veh_muscle: {
|
||||||
title: "MUSCLE CARS",
|
title: "MUSCLE CARS",
|
||||||
items: [
|
items: [
|
||||||
@@ -158,10 +132,7 @@ const menuData = {
|
|||||||
{ label: "Stallion", action: "spawn_vehicle", value: "stalion" },
|
{ label: "Stallion", action: "spawn_vehicle", value: "stalion" },
|
||||||
{ label: "Vigero", action: "spawn_vehicle", value: "vigero" },
|
{ label: "Vigero", action: "spawn_vehicle", value: "vigero" },
|
||||||
{ label: "Dukes", action: "spawn_vehicle", value: "dukes" },
|
{ label: "Dukes", action: "spawn_vehicle", value: "dukes" },
|
||||||
{ label: "Ruiner", action: "spawn_vehicle", value: "ruiner" },
|
{ label: "Phoenix", action: "spawn_vehicle", value: "phoenix" }
|
||||||
{ label: "Phoenix", action: "spawn_vehicle", value: "phoenix" },
|
|
||||||
{ label: "Gauntlet", action: "spawn_vehicle", value: "gauntlet" },
|
|
||||||
{ label: "Dominator", action: "spawn_vehicle", value: "dominator" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -170,26 +141,8 @@ const menuData = {
|
|||||||
items: [
|
items: [
|
||||||
{ label: "Patriot", action: "spawn_vehicle", value: "patriot" },
|
{ label: "Patriot", action: "spawn_vehicle", value: "patriot" },
|
||||||
{ label: "Cavalcade", action: "spawn_vehicle", value: "cavalcade" },
|
{ label: "Cavalcade", action: "spawn_vehicle", value: "cavalcade" },
|
||||||
{ label: "Granger", action: "spawn_vehicle", value: "granger" },
|
|
||||||
{ label: "Huntley", action: "spawn_vehicle", value: "huntley" },
|
{ label: "Huntley", action: "spawn_vehicle", value: "huntley" },
|
||||||
{ label: "Landstalker", action: "spawn_vehicle", value: "landstalker" },
|
{ label: "Landstalker", action: "spawn_vehicle", value: "landstalker" }
|
||||||
{ label: "Habanero", action: "spawn_vehicle", value: "habanero" },
|
|
||||||
{ label: "Serrano", action: "spawn_vehicle", value: "serrano" },
|
|
||||||
{ label: "Rebla", action: "spawn_vehicle", value: "rebla" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
veh_sedan: {
|
|
||||||
title: "SEDANS & COMPACTS",
|
|
||||||
items: [
|
|
||||||
{ label: "Oracle", action: "spawn_vehicle", value: "oracle" },
|
|
||||||
{ label: "Schafter", action: "spawn_vehicle", value: "schafter" },
|
|
||||||
{ label: "Admiral", action: "spawn_vehicle", value: "admiral" },
|
|
||||||
{ label: "Vincent", action: "spawn_vehicle", value: "vincent" },
|
|
||||||
{ label: "Presidente", action: "spawn_vehicle", value: "presidente" },
|
|
||||||
{ label: "Cognoscenti", action: "spawn_vehicle", value: "cognoscenti" },
|
|
||||||
{ label: "Blista", action: "spawn_vehicle", value: "blista" },
|
|
||||||
{ label: "Premier", action: "spawn_vehicle", value: "premier" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -199,26 +152,17 @@ const menuData = {
|
|||||||
{ label: "NRG 900", action: "spawn_vehicle", value: "nrg900" },
|
{ label: "NRG 900", action: "spawn_vehicle", value: "nrg900" },
|
||||||
{ label: "PCJ 600", action: "spawn_vehicle", value: "pcj600" },
|
{ label: "PCJ 600", action: "spawn_vehicle", value: "pcj600" },
|
||||||
{ label: "Sanchez", action: "spawn_vehicle", value: "sanchez" },
|
{ label: "Sanchez", action: "spawn_vehicle", value: "sanchez" },
|
||||||
{ label: "Faggio", action: "spawn_vehicle", value: "faggio" },
|
{ label: "Faggio", action: "spawn_vehicle", value: "faggio" }
|
||||||
{ label: "Bati", action: "spawn_vehicle", value: "bati" },
|
|
||||||
{ label: "Akuma", action: "spawn_vehicle", value: "akuma" },
|
|
||||||
{ label: "Double T", action: "spawn_vehicle", value: "double" },
|
|
||||||
{ label: "Hakuchou", action: "spawn_vehicle", value: "hakuchou" },
|
|
||||||
{ label: "Hexer", action: "spawn_vehicle", value: "hexer" },
|
|
||||||
{ label: "Daemon", action: "spawn_vehicle", value: "daemon" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
veh_emergency: {
|
veh_emergency: {
|
||||||
title: "EMERGENCY VEHICLES",
|
title: "EMERGENCY",
|
||||||
items: [
|
items: [
|
||||||
{ label: "Police Cruiser", action: "spawn_vehicle", value: "police" },
|
{ label: "Police Cruiser", action: "spawn_vehicle", value: "police" },
|
||||||
{ label: "Police Buffalo", action: "spawn_vehicle", value: "police2" },
|
|
||||||
{ label: "FBI Car", action: "spawn_vehicle", value: "fbi" },
|
{ label: "FBI Car", action: "spawn_vehicle", value: "fbi" },
|
||||||
{ label: "NOOSE Cruiser", action: "spawn_vehicle", value: "noose" },
|
|
||||||
{ label: "Ambulance", action: "spawn_vehicle", value: "ambulance" },
|
{ label: "Ambulance", action: "spawn_vehicle", value: "ambulance" },
|
||||||
{ label: "Fire Truck", action: "spawn_vehicle", value: "firetruk" },
|
{ label: "Fire Truck", action: "spawn_vehicle", value: "firetruk" }
|
||||||
{ label: "Enforcer (SWAT)", action: "spawn_vehicle", value: "enforcer" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -227,9 +171,7 @@ const menuData = {
|
|||||||
items: [
|
items: [
|
||||||
{ label: "Annihilator", action: "spawn_vehicle", value: "annihilator" },
|
{ label: "Annihilator", action: "spawn_vehicle", value: "annihilator" },
|
||||||
{ label: "Maverick", action: "spawn_vehicle", value: "maverick" },
|
{ label: "Maverick", action: "spawn_vehicle", value: "maverick" },
|
||||||
{ label: "Police Maverick", action: "spawn_vehicle", value: "polmav" },
|
{ label: "Police Maverick", action: "spawn_vehicle", value: "polmav" }
|
||||||
{ label: "Buzzard", action: "spawn_vehicle", value: "buzzard" },
|
|
||||||
{ label: "Shamal (Jet)", action: "spawn_vehicle", value: "shamal" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -237,26 +179,8 @@ const menuData = {
|
|||||||
title: "BOATS",
|
title: "BOATS",
|
||||||
items: [
|
items: [
|
||||||
{ label: "Jetmax", action: "spawn_vehicle", value: "jetmax" },
|
{ label: "Jetmax", action: "spawn_vehicle", value: "jetmax" },
|
||||||
{ label: "Marquis", action: "spawn_vehicle", value: "marquis" },
|
|
||||||
{ label: "Predator", action: "spawn_vehicle", value: "predator" },
|
{ label: "Predator", action: "spawn_vehicle", value: "predator" },
|
||||||
{ label: "Tropic", action: "spawn_vehicle", value: "tropic" },
|
{ label: "Tropic", action: "spawn_vehicle", value: "tropic" }
|
||||||
{ label: "Dinghy", action: "spawn_vehicle", value: "dinghy" },
|
|
||||||
{ label: "Squalo", action: "spawn_vehicle", value: "squalo" },
|
|
||||||
{ label: "Reefer", action: "spawn_vehicle", value: "reefer" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
veh_special: {
|
|
||||||
title: "SPECIAL VEHICLES",
|
|
||||||
items: [
|
|
||||||
{ label: "Taxi", action: "spawn_vehicle", value: "taxi" },
|
|
||||||
{ label: "Stretch Limo", action: "spawn_vehicle", value: "stretch" },
|
|
||||||
{ label: "Bus", action: "spawn_vehicle", value: "bus" },
|
|
||||||
{ label: "Trashmaster", action: "spawn_vehicle", value: "trashmaster" },
|
|
||||||
{ label: "Forklift", action: "spawn_vehicle", value: "forklift" },
|
|
||||||
{ label: "Caddy", action: "spawn_vehicle", value: "caddy" },
|
|
||||||
{ label: "Bulldozer", action: "spawn_vehicle", value: "bulldozer" },
|
|
||||||
{ label: "Phantom", action: "spawn_vehicle", value: "phantom" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -265,22 +189,9 @@ const menuData = {
|
|||||||
items: [
|
items: [
|
||||||
{ 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: "Clean Vehicle", action: "veh_clean" },
|
|
||||||
{ label: "Max Upgrade", action: "veh_upgrade" },
|
|
||||||
{ label: "Vehicle Colors", action: "submenu", target: "veh_colors" },
|
{ label: "Vehicle Colors", action: "submenu", target: "veh_colors" },
|
||||||
{ label: "--- Handling ---", action: "none" },
|
|
||||||
{ label: "Drift Mode", action: "toggle", target: "driftMode", state: false },
|
|
||||||
{ label: "Grip +", action: "handling", target: "grip", delta: 0.2 },
|
|
||||||
{ label: "Grip -", action: "handling", target: "grip", delta: -0.2 },
|
|
||||||
{ label: "Acceleration +", action: "handling", target: "acceleration", delta: 0.5 },
|
|
||||||
{ label: "Acceleration -", action: "handling", target: "acceleration", delta: -0.5 },
|
|
||||||
{ label: "Top Speed +", action: "handling", target: "topSpeed", delta: 0.3 },
|
|
||||||
{ label: "Top Speed -", action: "handling", target: "topSpeed", delta: -0.3 },
|
|
||||||
{ label: "Reset Handling", action: "handling_reset" },
|
|
||||||
{ label: "--- Special ---", action: "none" },
|
|
||||||
{ label: "Indestructible", action: "toggle", target: "vehGodMode", state: false },
|
{ label: "Indestructible", action: "toggle", target: "vehGodMode", state: false },
|
||||||
{ label: "Nitro Boost", action: "veh_nitro" },
|
{ label: "Nitro Boost", action: "veh_nitro" }
|
||||||
{ label: "Super Brakes", action: "toggle", target: "superBrakes", state: false }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -293,11 +204,6 @@ const menuData = {
|
|||||||
{ label: "Blue", action: "veh_color", value: [51, 51] },
|
{ label: "Blue", action: "veh_color", value: [51, 51] },
|
||||||
{ label: "Yellow", action: "veh_color", value: [42, 42] },
|
{ label: "Yellow", action: "veh_color", value: [42, 42] },
|
||||||
{ label: "Green", action: "veh_color", value: [53, 53] },
|
{ label: "Green", action: "veh_color", value: [53, 53] },
|
||||||
{ label: "Orange", action: "veh_color", value: [38, 38] },
|
|
||||||
{ label: "Purple", action: "veh_color", value: [61, 61] },
|
|
||||||
{ label: "Pink", action: "veh_color", value: [68, 68] },
|
|
||||||
{ label: "Gold", action: "veh_color", value: [37, 37] },
|
|
||||||
{ label: "Chrome", action: "veh_color", value: [120, 120] },
|
|
||||||
{ label: "Random", action: "veh_color_random" }
|
{ label: "Random", action: "veh_color_random" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -305,50 +211,34 @@ const menuData = {
|
|||||||
network: {
|
network: {
|
||||||
title: "NETWORK OPTIONS",
|
title: "NETWORK OPTIONS",
|
||||||
items: [
|
items: [
|
||||||
{ label: ">> Refresh Player List <<", action: "refresh_players" },
|
{ label: "Refresh Player List", action: "refresh_players" },
|
||||||
{ label: "--- Players Online ---", action: "none" }
|
{ label: "--- Players ---", action: "none" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
teleport: {
|
teleport: {
|
||||||
title: "TELEPORT LOCATIONS",
|
title: "TELEPORT LOCATIONS",
|
||||||
items: [
|
items: [
|
||||||
{ label: "-- Algonquin --", action: "none" },
|
|
||||||
{ label: "Star Junction", action: "teleport", value: { x: -252.0, y: 947.0, z: 15.0 } },
|
{ 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: "Middle Park", action: "teleport", value: { x: -365.0, y: 1163.0, z: 14.0 } },
|
||||||
{ label: "Rotterdam Tower", action: "teleport", value: { x: 237.0, y: 1002.0, z: 18.0 } },
|
|
||||||
{ label: "Chinatown", action: "teleport", value: { x: -141.0, y: 289.0, z: 14.0 } },
|
|
||||||
{ label: "Happiness Island", action: "teleport", value: { x: -722.0, y: -17.0, z: 3.0 } },
|
|
||||||
{ label: "-- Broker --", action: "none" },
|
|
||||||
{ label: "Broker Bridge", action: "teleport", value: { x: 932.0, y: -495.0, z: 15.0 } },
|
|
||||||
{ label: "Hove Beach", action: "teleport", value: { x: 1017.0, y: -505.0, z: 19.0 } },
|
|
||||||
{ label: "Airport", action: "teleport", value: { x: 2140.0, y: 465.0, z: 6.0 } },
|
{ label: "Airport", action: "teleport", value: { x: 2140.0, y: 465.0, z: 6.0 } },
|
||||||
{ label: "-- Bohan --", action: "none" },
|
{ label: "Broker Bridge", action: "teleport", value: { x: 932.0, y: -495.0, z: 15.0 } },
|
||||||
{ label: "South Bohan", action: "teleport", value: { x: 1243.0, y: -196.0, z: 26.0 } },
|
|
||||||
{ label: "-- Alderney --", action: "none" },
|
|
||||||
{ label: "Alderney City", action: "teleport", value: { x: -1149.0, y: 380.0, z: 21.0 } },
|
{ label: "Alderney City", action: "teleport", value: { x: -1149.0, y: 380.0, z: 21.0 } },
|
||||||
{ label: "Westdyke", action: "teleport", value: { x: -1745.0, y: 1157.0, z: 25.0 } },
|
{ label: "Happiness Island", action: "teleport", value: { x: -722.0, y: -17.0, z: 3.0 } }
|
||||||
{ label: "-- Special --", action: "none" },
|
|
||||||
{ label: "Helipad (High)", action: "teleport", value: { x: -290.0, y: -400.0, z: 81.0 } },
|
|
||||||
{ label: "Tower Top", action: "teleport", value: { x: 237.0, y: 1002.0, z: 200.0 } }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
world: {
|
world: {
|
||||||
title: "WORLD OPTIONS",
|
title: "WORLD OPTIONS",
|
||||||
items: [
|
items: [
|
||||||
{ label: "-- Time --", action: "none" },
|
|
||||||
{ label: "Morning (8:00)", action: "world_time", value: 8 },
|
{ label: "Morning (8:00)", action: "world_time", value: 8 },
|
||||||
{ label: "Noon (12:00)", action: "world_time", value: 12 },
|
{ label: "Noon (12:00)", action: "world_time", value: 12 },
|
||||||
{ label: "Evening (18:00)", action: "world_time", value: 18 },
|
{ label: "Evening (18:00)", action: "world_time", value: 18 },
|
||||||
{ label: "Night (0:00)", action: "world_time", value: 0 },
|
{ label: "Night (0:00)", action: "world_time", value: 0 },
|
||||||
{ label: "-- Weather --", action: "none" },
|
|
||||||
{ label: "Extra Sunny", action: "world_weather", value: 0 },
|
|
||||||
{ label: "Sunny", action: "world_weather", value: 1 },
|
{ label: "Sunny", action: "world_weather", value: 1 },
|
||||||
{ label: "Cloudy", action: "world_weather", value: 3 },
|
{ label: "Cloudy", action: "world_weather", value: 3 },
|
||||||
{ label: "Rainy", action: "world_weather", value: 4 },
|
{ label: "Rainy", action: "world_weather", value: 4 },
|
||||||
{ label: "Thunder", action: "world_weather", value: 7 },
|
{ label: "Thunder", action: "world_weather", value: 7 }
|
||||||
{ label: "Foggy", action: "world_weather", value: 6 }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -356,26 +246,13 @@ const menuData = {
|
|||||||
title: "WEAPONS",
|
title: "WEAPONS",
|
||||||
items: [
|
items: [
|
||||||
{ label: "Get All Weapons", action: "weapon_all" },
|
{ label: "Get All Weapons", action: "weapon_all" },
|
||||||
{ label: "-- Melee --", action: "none" },
|
|
||||||
{ label: "Baseball Bat", action: "weapon", value: 1 },
|
|
||||||
{ label: "Knife", action: "weapon", value: 2 },
|
|
||||||
{ label: "-- Pistols --", action: "none" },
|
|
||||||
{ label: "Pistol", action: "weapon", value: 5 },
|
{ label: "Pistol", action: "weapon", value: 5 },
|
||||||
{ label: "Desert Eagle", action: "weapon", value: 6 },
|
{ label: "Desert Eagle", action: "weapon", value: 6 },
|
||||||
{ label: "-- Shotguns --", action: "none" },
|
|
||||||
{ label: "Shotgun", action: "weapon", value: 9 },
|
{ label: "Shotgun", action: "weapon", value: 9 },
|
||||||
{ label: "Combat Shotgun", action: "weapon", value: 10 },
|
|
||||||
{ label: "-- SMGs --", action: "none" },
|
|
||||||
{ label: "Micro SMG", action: "weapon", value: 11 },
|
|
||||||
{ label: "SMG", action: "weapon", value: 12 },
|
{ label: "SMG", action: "weapon", value: 12 },
|
||||||
{ label: "-- Rifles --", action: "none" },
|
|
||||||
{ label: "Assault Rifle", action: "weapon", value: 14 },
|
{ label: "Assault Rifle", action: "weapon", value: 14 },
|
||||||
{ label: "Carbine Rifle", action: "weapon", value: 15 },
|
|
||||||
{ label: "Sniper Rifle", action: "weapon", value: 16 },
|
{ label: "Sniper Rifle", action: "weapon", value: 16 },
|
||||||
{ label: "-- Explosives --", action: "none" },
|
{ label: "RPG", action: "weapon", value: 18 }
|
||||||
{ label: "RPG", action: "weapon", value: 18 },
|
|
||||||
{ label: "Grenades", action: "weapon", value: 19 },
|
|
||||||
{ label: "Molotov", action: "weapon", value: 20 }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -384,12 +261,8 @@ const menuData = {
|
|||||||
items: [
|
items: [
|
||||||
{ label: "Launch Me Up", action: "fun_launch" },
|
{ label: "Launch Me Up", action: "fun_launch" },
|
||||||
{ label: "Explode Me", action: "fun_explode" },
|
{ label: "Explode Me", action: "fun_explode" },
|
||||||
{ label: "Spawn Random Ped", action: "fun_ped" },
|
{ label: "Spawn Ped", action: "fun_ped" },
|
||||||
{ label: "Ragdoll", action: "fun_ragdoll" },
|
{ label: "Ragdoll", action: "fun_ragdoll" }
|
||||||
{ label: "Clear Area Peds", action: "fun_clearpeds" },
|
|
||||||
{ label: "Clear Area Vehicles", action: "fun_clearvehicles" },
|
|
||||||
{ label: "Chaos Mode", action: "toggle", target: "chaosMode", state: false },
|
|
||||||
{ label: "Drunk Mode", action: "toggle", target: "drunkMode", state: false }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -398,16 +271,29 @@ const menuData = {
|
|||||||
let toggleStates = {
|
let toggleStates = {
|
||||||
godMode: false,
|
godMode: false,
|
||||||
neverWanted: false,
|
neverWanted: false,
|
||||||
infiniteAmmo: false,
|
vehGodMode: false
|
||||||
superJump: false,
|
|
||||||
fastRun: false,
|
|
||||||
driftMode: false,
|
|
||||||
vehGodMode: false,
|
|
||||||
superBrakes: false,
|
|
||||||
chaosMode: false,
|
|
||||||
drunkMode: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// FONT LOADING
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
addEventHandler("OnResourceReady", function(event, resource) {
|
||||||
|
// Use built-in default font (no external TTF file needed)
|
||||||
|
try {
|
||||||
|
menuFont = lucasFont.createDefaultFont(16.0, "Tahoma", false, false);
|
||||||
|
if (menuFont != null) {
|
||||||
|
console.log("[ModMenu] Default font created successfully");
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
console.log("[ModMenu] Could not create default font: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menuFont == null) {
|
||||||
|
console.log("[ModMenu] Font creation failed - text won't render");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// INPUT HANDLING
|
// INPUT HANDLING
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -421,14 +307,11 @@ addEventHandler("OnKeyUp", function(event, key, scanCode, mods) {
|
|||||||
selectedIndex = 0;
|
selectedIndex = 0;
|
||||||
scrollOffset = 0;
|
scrollOffset = 0;
|
||||||
menuStack = [];
|
menuStack = [];
|
||||||
// Show cursor - use gui if available
|
// Show cursor and DISABLE controls (second param = false disables controls)
|
||||||
if (typeof gui !== "undefined" && gui.showCursor) {
|
gui.showCursor(true, false);
|
||||||
gui.showCursor(true, true);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (typeof gui !== "undefined" && gui.showCursor) {
|
// Hide cursor and ENABLE controls (second param = true enables controls)
|
||||||
gui.showCursor(false, false);
|
gui.showCursor(false, true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -444,10 +327,6 @@ addEventHandler("OnKeyUp", function(event, key, scanCode, mods) {
|
|||||||
selectItem();
|
selectItem();
|
||||||
} else if (key === SDLK_BACKSPACE || key === SDLK_ESCAPE) {
|
} else if (key === SDLK_BACKSPACE || key === SDLK_ESCAPE) {
|
||||||
goBack();
|
goBack();
|
||||||
} else if (key === SDLK_LEFT) {
|
|
||||||
adjustValue(-1);
|
|
||||||
} else if (key === SDLK_RIGHT) {
|
|
||||||
adjustValue(1);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -459,7 +338,6 @@ function navigateUp() {
|
|||||||
selectedIndex = items.length - 1;
|
selectedIndex = items.length - 1;
|
||||||
}
|
}
|
||||||
} while (items[selectedIndex] && items[selectedIndex].action === "none");
|
} while (items[selectedIndex] && items[selectedIndex].action === "none");
|
||||||
|
|
||||||
updateScroll(items);
|
updateScroll(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,7 +349,6 @@ function navigateDown() {
|
|||||||
selectedIndex = 0;
|
selectedIndex = 0;
|
||||||
}
|
}
|
||||||
} while (items[selectedIndex] && items[selectedIndex].action === "none");
|
} while (items[selectedIndex] && items[selectedIndex].action === "none");
|
||||||
|
|
||||||
updateScroll(items);
|
updateScroll(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,9 +368,8 @@ function goBack() {
|
|||||||
scrollOffset = prev.scroll;
|
scrollOffset = prev.scroll;
|
||||||
} else {
|
} else {
|
||||||
menuOpen = false;
|
menuOpen = false;
|
||||||
if (typeof gui !== "undefined" && gui.showCursor) {
|
// IMPORTANT: Enable controls when closing menu
|
||||||
gui.showCursor(false, false);
|
gui.showCursor(false, true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,10 +382,9 @@ function getCurrentMenuItems() {
|
|||||||
|
|
||||||
function getNetworkMenuItems() {
|
function getNetworkMenuItems() {
|
||||||
let items = [
|
let items = [
|
||||||
{ label: ">> Refresh Player List <<", action: "refresh_players" },
|
{ label: "Refresh Player List", action: "refresh_players" },
|
||||||
{ label: "--- Players Online ---", action: "none" }
|
{ label: "--- Players ---", action: "none" }
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let i = 0; i < playerList.length; i++) {
|
for (let i = 0; i < playerList.length; i++) {
|
||||||
items.push({
|
items.push({
|
||||||
label: playerList[i].name,
|
label: playerList[i].name,
|
||||||
@@ -518,7 +393,6 @@ function getNetworkMenuItems() {
|
|||||||
playerData: playerList[i]
|
playerData: playerList[i]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,7 +400,6 @@ function getNetworkMenuItems() {
|
|||||||
// ACTION HANDLING
|
// ACTION HANDLING
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// Selected player for network options
|
|
||||||
let selectedPlayer = null;
|
let selectedPlayer = null;
|
||||||
|
|
||||||
function selectItem() {
|
function selectItem() {
|
||||||
@@ -561,7 +434,7 @@ function selectItem() {
|
|||||||
|
|
||||||
case "teleport":
|
case "teleport":
|
||||||
triggerNetworkEvent("ModMenu:Teleport", item.value.x, item.value.y, item.value.z);
|
triggerNetworkEvent("ModMenu:Teleport", item.value.x, item.value.y, item.value.z);
|
||||||
showNotification("Teleporting to: " + item.label);
|
showNotification("Teleporting...");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "self_health":
|
case "self_health":
|
||||||
@@ -586,7 +459,7 @@ function selectItem() {
|
|||||||
|
|
||||||
case "self_wanted":
|
case "self_wanted":
|
||||||
triggerNetworkEvent("ModMenu:SelfOption", "wanted");
|
triggerNetworkEvent("ModMenu:SelfOption", "wanted");
|
||||||
showNotification("Wanted level cleared!");
|
showNotification("Wanted cleared!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "self_respawn":
|
case "self_respawn":
|
||||||
@@ -605,32 +478,22 @@ function selectItem() {
|
|||||||
|
|
||||||
case "skin_random":
|
case "skin_random":
|
||||||
triggerNetworkEvent("ModMenu:ChangeSkin", "random");
|
triggerNetworkEvent("ModMenu:ChangeSkin", "random");
|
||||||
showNotification("Random skin applied!");
|
showNotification("Random skin!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "veh_repair":
|
case "veh_repair":
|
||||||
triggerNetworkEvent("ModMenu:VehicleOption", "repair");
|
triggerNetworkEvent("ModMenu:VehicleOption", "repair");
|
||||||
showNotification("Vehicle repaired!");
|
showNotification("Repaired!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "veh_flip":
|
case "veh_flip":
|
||||||
triggerNetworkEvent("ModMenu:VehicleOption", "flip");
|
triggerNetworkEvent("ModMenu:VehicleOption", "flip");
|
||||||
showNotification("Vehicle flipped!");
|
showNotification("Flipped!");
|
||||||
break;
|
|
||||||
|
|
||||||
case "veh_clean":
|
|
||||||
triggerNetworkEvent("ModMenu:VehicleOption", "clean");
|
|
||||||
showNotification("Vehicle cleaned!");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "veh_upgrade":
|
|
||||||
triggerNetworkEvent("ModMenu:VehicleOption", "upgrade");
|
|
||||||
showNotification("Vehicle upgraded!");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "veh_nitro":
|
case "veh_nitro":
|
||||||
triggerNetworkEvent("ModMenu:VehicleOption", "nitro");
|
triggerNetworkEvent("ModMenu:VehicleOption", "nitro");
|
||||||
showNotification("NITRO BOOST!");
|
showNotification("NITRO!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "veh_color":
|
case "veh_color":
|
||||||
@@ -642,29 +505,17 @@ function selectItem() {
|
|||||||
let c1 = Math.floor(Math.random() * 132);
|
let c1 = Math.floor(Math.random() * 132);
|
||||||
let c2 = Math.floor(Math.random() * 132);
|
let c2 = Math.floor(Math.random() * 132);
|
||||||
triggerNetworkEvent("ModMenu:VehicleColor", c1, c2);
|
triggerNetworkEvent("ModMenu:VehicleColor", c1, c2);
|
||||||
showNotification("Random color applied!");
|
showNotification("Random color!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "vehicle_delete":
|
case "vehicle_delete":
|
||||||
triggerNetworkEvent("ModMenu:DeleteVehicles");
|
triggerNetworkEvent("ModMenu:DeleteVehicles");
|
||||||
showNotification("Vehicles deleted!");
|
showNotification("Deleted!");
|
||||||
break;
|
|
||||||
|
|
||||||
case "handling":
|
|
||||||
handlingMods[item.target] = Math.max(0.1, Math.min(5.0, handlingMods[item.target] + item.delta));
|
|
||||||
triggerNetworkEvent("ModMenu:Handling", item.target, handlingMods[item.target]);
|
|
||||||
showNotification(item.target + ": " + handlingMods[item.target].toFixed(1));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "handling_reset":
|
|
||||||
handlingMods = { grip: 1.0, acceleration: 1.0, topSpeed: 1.0, braking: 1.0, driftMode: false };
|
|
||||||
triggerNetworkEvent("ModMenu:HandlingReset");
|
|
||||||
showNotification("Handling reset!");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "world_time":
|
case "world_time":
|
||||||
triggerNetworkEvent("ModMenu:WorldTime", item.value);
|
triggerNetworkEvent("ModMenu:WorldTime", item.value);
|
||||||
showNotification("Time set to: " + item.value + ":00");
|
showNotification("Time: " + item.value + ":00");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "world_weather":
|
case "world_weather":
|
||||||
@@ -674,23 +525,23 @@ function selectItem() {
|
|||||||
|
|
||||||
case "weapon":
|
case "weapon":
|
||||||
triggerNetworkEvent("ModMenu:GiveWeapon", item.value);
|
triggerNetworkEvent("ModMenu:GiveWeapon", item.value);
|
||||||
showNotification("Weapon given: " + item.label);
|
showNotification("Weapon given!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "weapon_all":
|
case "weapon_all":
|
||||||
triggerNetworkEvent("ModMenu:SelfOption", "weapons");
|
triggerNetworkEvent("ModMenu:SelfOption", "weapons");
|
||||||
showNotification("All weapons given!");
|
showNotification("All weapons!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "refresh_players":
|
case "refresh_players":
|
||||||
triggerNetworkEvent("ModMenu:GetPlayers");
|
triggerNetworkEvent("ModMenu:GetPlayers");
|
||||||
showNotification("Refreshing player list...");
|
showNotification("Refreshing...");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "teleport_to_player":
|
case "teleport_to_player":
|
||||||
if (selectedPlayer) {
|
if (selectedPlayer) {
|
||||||
triggerNetworkEvent("ModMenu:TeleportToPlayer", selectedPlayer.id);
|
triggerNetworkEvent("ModMenu:TeleportToPlayer", selectedPlayer.id);
|
||||||
showNotification("Teleporting to: " + selectedPlayer.name);
|
showNotification("Teleporting to " + selectedPlayer.name);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -711,29 +562,6 @@ function selectItem() {
|
|||||||
case "fun_ragdoll":
|
case "fun_ragdoll":
|
||||||
triggerNetworkEvent("ModMenu:Fun", "ragdoll");
|
triggerNetworkEvent("ModMenu:Fun", "ragdoll");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "fun_clearpeds":
|
|
||||||
triggerNetworkEvent("ModMenu:Fun", "clearpeds");
|
|
||||||
showNotification("Area cleared!");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "fun_clearvehicles":
|
|
||||||
triggerNetworkEvent("ModMenu:Fun", "clearvehicles");
|
|
||||||
showNotification("Vehicles cleared!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function adjustValue(direction) {
|
|
||||||
let items = getCurrentMenuItems();
|
|
||||||
let item = items[selectedIndex];
|
|
||||||
if (!item) return;
|
|
||||||
|
|
||||||
if (item.action === "handling") {
|
|
||||||
let delta = item.delta * direction;
|
|
||||||
handlingMods[item.target] = Math.max(0.1, Math.min(5.0, handlingMods[item.target] + delta));
|
|
||||||
triggerNetworkEvent("ModMenu:Handling", item.target, handlingMods[item.target]);
|
|
||||||
showNotification(item.target + ": " + handlingMods[item.target].toFixed(1));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,12 +569,9 @@ function openPlayerMenu(playerData) {
|
|||||||
menuData.player_options = {
|
menuData.player_options = {
|
||||||
title: playerData.name,
|
title: playerData.name,
|
||||||
items: [
|
items: [
|
||||||
{ label: "Teleport to Player", action: "teleport_to_player" },
|
{ label: "Teleport to Player", action: "teleport_to_player" }
|
||||||
{ label: "Spectate Player", action: "spectate_player" },
|
|
||||||
{ label: "Copy Position", action: "copy_pos" }
|
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
menuStack.push({ menu: currentMenu, index: selectedIndex, scroll: scrollOffset });
|
menuStack.push({ menu: currentMenu, index: selectedIndex, scroll: scrollOffset });
|
||||||
currentMenu = "player_options";
|
currentMenu = "player_options";
|
||||||
selectedIndex = 0;
|
selectedIndex = 0;
|
||||||
@@ -754,7 +579,7 @@ function openPlayerMenu(playerData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// NETWORK EVENT HANDLERS
|
// NETWORK HANDLERS
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
addNetworkHandler("ModMenu:PlayerList", function(players) {
|
addNetworkHandler("ModMenu:PlayerList", function(players) {
|
||||||
@@ -762,12 +587,12 @@ addNetworkHandler("ModMenu:PlayerList", function(players) {
|
|||||||
showNotification("Found " + players.length + " players");
|
showNotification("Found " + players.length + " players");
|
||||||
});
|
});
|
||||||
|
|
||||||
addNetworkHandler("ModMenu:Notification", function(message) {
|
addNetworkHandler("ModMenu:Notification", function(msg) {
|
||||||
showNotification(message);
|
showNotification(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// RENDERING - Using correct GTAC drawing API
|
// RENDERING
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
addEventHandler("OnDrawnHUD", function(event) {
|
addEventHandler("OnDrawnHUD", function(event) {
|
||||||
@@ -777,7 +602,6 @@ addEventHandler("OnDrawnHUD", function(event) {
|
|||||||
let items = getCurrentMenuItems();
|
let items = getCurrentMenuItems();
|
||||||
let title = currentData ? currentData.title : currentMenu.toUpperCase();
|
let title = currentData ? currentData.title : currentMenu.toUpperCase();
|
||||||
|
|
||||||
// Calculate visible items
|
|
||||||
let visibleCount = Math.min(items.length, menu.maxVisibleItems);
|
let visibleCount = Math.min(items.length, menu.maxVisibleItems);
|
||||||
let totalHeight = menu.headerHeight + (visibleCount * menu.itemHeight) + menu.footerHeight;
|
let totalHeight = menu.headerHeight + (visibleCount * menu.itemHeight) + menu.footerHeight;
|
||||||
|
|
||||||
@@ -786,111 +610,54 @@ addEventHandler("OnDrawnHUD", function(event) {
|
|||||||
|
|
||||||
// Draw header
|
// Draw header
|
||||||
drawRect(menu.x, menu.y, menu.width, menu.headerHeight, colors.header);
|
drawRect(menu.x, menu.y, menu.width, menu.headerHeight, colors.header);
|
||||||
drawText(title, menu.x + menu.width / 2, menu.y + 10, colors.headerText, true, 1.0);
|
drawText(title, menu.x + 10, menu.y + 12, colors.text, 18);
|
||||||
|
|
||||||
// Draw items
|
// Draw items
|
||||||
let yPos = menu.y + menu.headerHeight;
|
let yPos = menu.y + menu.headerHeight;
|
||||||
for (let i = scrollOffset; i < scrollOffset + visibleCount && i < items.length; i++) {
|
for (let i = scrollOffset; i < scrollOffset + visibleCount && i < items.length; i++) {
|
||||||
let item = items[i];
|
let item = items[i];
|
||||||
let isSelected = (i === selectedIndex);
|
let isSelected = (i === selectedIndex);
|
||||||
let bgColor = isSelected ? colors.itemBgSelected : colors.itemBg;
|
let bgColor = isSelected ? colors.selected : colors.item;
|
||||||
let textColor = isSelected ? colors.itemTextSelected : colors.itemText;
|
|
||||||
|
|
||||||
// Draw item background
|
|
||||||
drawRect(menu.x, yPos, menu.width, menu.itemHeight, bgColor);
|
drawRect(menu.x, yPos, menu.width, menu.itemHeight, bgColor);
|
||||||
|
|
||||||
// Build label with state indicators
|
|
||||||
let label = item.label;
|
let label = item.label;
|
||||||
|
|
||||||
if (item.action === "toggle") {
|
if (item.action === "toggle") {
|
||||||
let state = toggleStates[item.target];
|
label += toggleStates[item.target] ? " [ON]" : " [OFF]";
|
||||||
label += state ? " [ON]" : " [OFF]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.action === "handling" && handlingMods[item.target] !== undefined) {
|
|
||||||
label += " [" + handlingMods[item.target].toFixed(1) + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.action === "submenu") {
|
if (item.action === "submenu") {
|
||||||
label += " >>";
|
label += " >>";
|
||||||
}
|
}
|
||||||
|
|
||||||
drawText(label, menu.x + 15, yPos + 8, textColor, false, 0.9);
|
drawText(label, menu.x + 15, yPos + 10, colors.text, 14);
|
||||||
|
|
||||||
yPos += menu.itemHeight;
|
yPos += menu.itemHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw footer
|
// Draw footer
|
||||||
drawRect(menu.x, yPos, menu.width, menu.footerHeight, colors.footer);
|
drawRect(menu.x, yPos, menu.width, menu.footerHeight, colors.footer);
|
||||||
drawText("UP/DOWN: Navigate | ENTER: Select | BACKSPACE: Back", menu.x + menu.width / 2, yPos + 8, colors.footerText, true, 0.6);
|
drawText("UP/DOWN | ENTER | BACKSPACE", menu.x + 10, yPos + 8, colors.subText, 12);
|
||||||
|
|
||||||
// Draw scroll indicator
|
// Scroll indicator
|
||||||
if (items.length > menu.maxVisibleItems) {
|
if (items.length > menu.maxVisibleItems) {
|
||||||
let scrollText = (scrollOffset + 1) + "-" + Math.min(scrollOffset + visibleCount, items.length) + " / " + items.length;
|
let scrollText = (scrollOffset + 1) + "-" + Math.min(scrollOffset + visibleCount, items.length) + "/" + items.length;
|
||||||
drawText(scrollText, menu.x + menu.width - 50, menu.y + 12, colors.subText, false, 0.7);
|
drawText(scrollText, menu.x + menu.width - 60, menu.y + 12, colors.subText, 12);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Helper drawing functions using native drawing
|
// Draw rectangle using graphics API
|
||||||
function drawRect(x, y, width, height, colour) {
|
function drawRect(x, y, w, h, colour) {
|
||||||
// Use natives for drawing rectangles
|
let pos = new Vec2(x, y);
|
||||||
if (typeof natives !== "undefined" && natives.drawRect) {
|
let size = new Vec2(w, h);
|
||||||
// GTA IV native drawing - normalized coordinates (0-1)
|
graphics.drawRectangle(null, pos, size, colour, colour, colour, colour);
|
||||||
let screenW = game.width || 1920;
|
|
||||||
let screenH = game.height || 1080;
|
|
||||||
|
|
||||||
let nx = (x + width/2) / screenW;
|
|
||||||
let ny = (y + height/2) / screenH;
|
|
||||||
let nw = width / screenW;
|
|
||||||
let nh = height / screenH;
|
|
||||||
|
|
||||||
// Extract RGBA from colour
|
|
||||||
let r = (colour >> 24) & 0xFF;
|
|
||||||
let g = (colour >> 16) & 0xFF;
|
|
||||||
let b = (colour >> 8) & 0xFF;
|
|
||||||
let a = colour & 0xFF;
|
|
||||||
|
|
||||||
natives.drawRect(nx, ny, nw, nh, r, g, b, a);
|
|
||||||
} else {
|
|
||||||
// Fallback to graphics drawing
|
|
||||||
try {
|
|
||||||
graphics.drawRectangle(null, [x, y], [width, height], colour, colour, 0, 0, 0);
|
|
||||||
} catch(e) {
|
|
||||||
// Silent fail
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawText(text, x, y, colour, centered, scale) {
|
// Draw text using loaded font or fallback
|
||||||
// Use natives for drawing text
|
function drawText(text, x, y, colour, size) {
|
||||||
if (typeof natives !== "undefined" && natives.setTextScale) {
|
if (menuFont != null) {
|
||||||
let screenW = game.width || 1920;
|
let pos = new Vec2(x, y);
|
||||||
let screenH = game.height || 1080;
|
menuFont.render(text, pos, menu.width, 0.0, 0.0, size, colour, false, false, false, true);
|
||||||
|
|
||||||
let nx = x / screenW;
|
|
||||||
let ny = y / screenH;
|
|
||||||
|
|
||||||
let r = (colour >> 24) & 0xFF;
|
|
||||||
let g = (colour >> 16) & 0xFF;
|
|
||||||
let b = (colour >> 8) & 0xFF;
|
|
||||||
let a = colour & 0xFF;
|
|
||||||
|
|
||||||
natives.setTextFont(0);
|
|
||||||
natives.setTextScale(scale || 0.35, scale || 0.35);
|
|
||||||
natives.setTextColour(r, g, b, a);
|
|
||||||
if (centered) {
|
|
||||||
natives.setTextCentre(true);
|
|
||||||
}
|
|
||||||
natives.setTextDropshadow(2, 0, 0, 0, 255);
|
|
||||||
natives.displayTextWithLiteralString(nx, ny, "STRING", text);
|
|
||||||
} else {
|
|
||||||
// Fallback
|
|
||||||
try {
|
|
||||||
graphics.drawText(text, [x, y], colour, scale || 1.0, "arial", centered || false);
|
|
||||||
} catch(e) {
|
|
||||||
// Silent fail
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// If no font, text won't render but menu boxes will still show
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -907,7 +674,6 @@ function showNotification(text) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw notifications
|
|
||||||
addEventHandler("OnDrawnHUD", function(event) {
|
addEventHandler("OnDrawnHUD", function(event) {
|
||||||
let now = Date.now();
|
let now = Date.now();
|
||||||
let yPos = 200;
|
let yPos = 200;
|
||||||
@@ -919,40 +685,35 @@ addEventHandler("OnDrawnHUD", function(event) {
|
|||||||
if (elapsed < notif.duration) {
|
if (elapsed < notif.duration) {
|
||||||
let alpha = elapsed < notif.duration - 500 ? 200 : Math.floor(200 * (notif.duration - elapsed) / 500);
|
let alpha = elapsed < notif.duration - 500 ? 200 : Math.floor(200 * (notif.duration - elapsed) / 500);
|
||||||
let bgColor = toColour(20, 20, 20, alpha);
|
let bgColor = toColour(20, 20, 20, alpha);
|
||||||
let textColor = toColour(255, 255, 100, alpha + 55);
|
let textColor = toColour(255, 255, 100, Math.min(255, alpha + 55));
|
||||||
|
|
||||||
drawRect(10, yPos, 300, 30, bgColor);
|
|
||||||
drawText(notif.text, 20, yPos + 6, textColor, false, 0.8);
|
|
||||||
|
|
||||||
|
drawRect(10, yPos, 280, 30, bgColor);
|
||||||
|
drawText(notif.text, 20, yPos + 8, textColor, 14);
|
||||||
yPos += 35;
|
yPos += 35;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean expired notifications
|
|
||||||
notifications = notifications.filter(function(n) {
|
notifications = notifications.filter(function(n) {
|
||||||
return now - n.time < n.duration;
|
return now - n.time < n.duration;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// TOGGLE EFFECTS (Client-side processing)
|
// TOGGLE EFFECTS
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
addEventHandler("OnProcess", function(event) {
|
addEventHandler("OnProcess", function(event) {
|
||||||
if (!localPlayer) return;
|
if (!localPlayer) return;
|
||||||
|
|
||||||
// God Mode
|
|
||||||
if (toggleStates.godMode) {
|
if (toggleStates.godMode) {
|
||||||
localPlayer.health = 200;
|
localPlayer.health = 200;
|
||||||
localPlayer.armour = 100;
|
localPlayer.armour = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never Wanted
|
|
||||||
if (toggleStates.neverWanted) {
|
if (toggleStates.neverWanted) {
|
||||||
localPlayer.wantedLevel = 0;
|
localPlayer.wantedLevel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vehicle God Mode
|
|
||||||
if (localPlayer.vehicle && toggleStates.vehGodMode) {
|
if (localPlayer.vehicle && toggleStates.vehGodMode) {
|
||||||
localPlayer.vehicle.health = 1000;
|
localPlayer.vehicle.health = 1000;
|
||||||
}
|
}
|
||||||
@@ -963,8 +724,7 @@ addEventHandler("OnProcess", function(event) {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
addEventHandler("OnResourceStart", function(event, resource) {
|
addEventHandler("OnResourceStart", function(event, resource) {
|
||||||
console.log("[ModMenu] Client script loaded!");
|
console.log("[ModMenu] Client loaded - Press F5 to open menu");
|
||||||
console.log("[ModMenu] Press F5 to open the menu");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("[ModMenu] Client loaded - Press F5 to open menu!");
|
console.log("[ModMenu] Script initialized");
|
||||||
|
|||||||
Reference in New Issue
Block a user