mirror of
https://github.com/iDisaster/GTAConnected.git
synced 2026-03-08 09:25:23 +00:00
Merge pull request #5 from iDisaster/claude/enhance-gta-server-9Dezg
Claude/enhance gta server 9 dezg
This commit is contained in:
@@ -75,8 +75,13 @@ const menuData = {
|
||||
{ label: "Max Health & Armor", action: "self_max" },
|
||||
{ label: "Give All Weapons", action: "self_weapons" },
|
||||
{ label: "Clear Wanted Level", action: "self_wanted" },
|
||||
{ label: "--- Toggles ---", action: "none" },
|
||||
{ label: "God Mode", action: "toggle", target: "godMode", state: false },
|
||||
{ label: "Invincible", action: "toggle", target: "invincible", state: false },
|
||||
{ label: "Super Run", action: "toggle", target: "superRun", state: false },
|
||||
{ label: "No Ragdoll", action: "toggle", target: "noRagdoll", state: false },
|
||||
{ label: "Never Wanted", action: "toggle", target: "neverWanted", state: false },
|
||||
{ label: "--- Actions ---", action: "none" },
|
||||
{ label: "Respawn", action: "self_respawn" },
|
||||
{ label: "Suicide", action: "self_suicide" },
|
||||
{ label: "Change Skin", action: "submenu", target: "skins" }
|
||||
@@ -190,8 +195,30 @@ const menuData = {
|
||||
{ label: "Repair Vehicle", action: "veh_repair" },
|
||||
{ label: "Flip Vehicle", action: "veh_flip" },
|
||||
{ label: "Vehicle Colors", action: "submenu", target: "veh_colors" },
|
||||
{ label: "Indestructible", action: "toggle", target: "vehGodMode", state: false },
|
||||
{ label: "Nitro Boost", action: "veh_nitro" }
|
||||
{ label: "God Mode", action: "toggle", target: "vehGodMode", state: false },
|
||||
{ label: "Nitro Boost", action: "veh_nitro" },
|
||||
{ label: "Drive On Water", action: "toggle", target: "driveOnWater", state: false },
|
||||
{ label: "Rainbow Color", action: "toggle", target: "rainbowCar", state: false },
|
||||
{ label: "Drift Mode", action: "toggle", target: "driftMode", state: false },
|
||||
{ label: "Neon Lights", action: "submenu", target: "veh_neons" },
|
||||
{ label: "Fly Mode", action: "toggle", target: "flyMode", state: false },
|
||||
{ label: "Shoot RPG", action: "toggle", target: "vehShootRPG", state: false }
|
||||
]
|
||||
},
|
||||
|
||||
veh_neons: {
|
||||
title: "NEON LIGHTS",
|
||||
items: [
|
||||
{ label: "Toggle Neons", action: "toggle", target: "neonLights", state: false },
|
||||
{ label: "Red Neons", action: "neon_color", value: { r: 255, g: 0, b: 0 } },
|
||||
{ label: "Blue Neons", action: "neon_color", value: { r: 0, g: 100, b: 255 } },
|
||||
{ label: "Green Neons", action: "neon_color", value: { r: 0, g: 255, b: 0 } },
|
||||
{ label: "Purple Neons", action: "neon_color", value: { r: 255, g: 0, b: 255 } },
|
||||
{ label: "Pink Neons", action: "neon_color", value: { r: 255, g: 100, b: 200 } },
|
||||
{ label: "Yellow Neons", action: "neon_color", value: { r: 255, g: 255, b: 0 } },
|
||||
{ label: "White Neons", action: "neon_color", value: { r: 255, g: 255, b: 255 } },
|
||||
{ label: "Cyan Neons", action: "neon_color", value: { r: 0, g: 255, b: 255 } },
|
||||
{ label: "Orange Neons", action: "neon_color", value: { r: 255, g: 150, b: 0 } }
|
||||
]
|
||||
},
|
||||
|
||||
@@ -238,7 +265,25 @@ const menuData = {
|
||||
{ label: "Sunny", action: "world_weather", value: 1 },
|
||||
{ label: "Cloudy", action: "world_weather", value: 3 },
|
||||
{ label: "Rainy", action: "world_weather", value: 4 },
|
||||
{ label: "Thunder", action: "world_weather", value: 7 }
|
||||
{ label: "Thunder", action: "world_weather", value: 7 },
|
||||
{ label: "--- Sky Effects ---", action: "none" },
|
||||
{ label: "Rainbow Sky", action: "toggle", target: "rainbowSky", state: false },
|
||||
{ label: "Sky Colors", action: "submenu", target: "sky_colors" }
|
||||
]
|
||||
},
|
||||
|
||||
sky_colors: {
|
||||
title: "SKY COLORS",
|
||||
items: [
|
||||
{ label: "Default Sky", action: "sky_color", value: 0 },
|
||||
{ label: "Red Sky", action: "sky_color", value: 1 },
|
||||
{ label: "Blue Sky", action: "sky_color", value: 2 },
|
||||
{ label: "Green Sky", action: "sky_color", value: 3 },
|
||||
{ label: "Purple Sky", action: "sky_color", value: 4 },
|
||||
{ label: "Orange Sky", action: "sky_color", value: 5 },
|
||||
{ label: "Pink Sky", action: "sky_color", value: 6 },
|
||||
{ label: "Yellow Sky", action: "sky_color", value: 7 },
|
||||
{ label: "Cyan Sky", action: "sky_color", value: 8 }
|
||||
]
|
||||
},
|
||||
|
||||
@@ -246,6 +291,8 @@ const menuData = {
|
||||
title: "WEAPONS",
|
||||
items: [
|
||||
{ label: "Get All Weapons", action: "weapon_all" },
|
||||
{ label: "Explosive Ammo", action: "toggle", target: "explosiveAmmo", state: false },
|
||||
{ label: "--- Give Weapon ---", action: "none" },
|
||||
{ label: "Pistol", action: "weapon", value: 5 },
|
||||
{ label: "Desert Eagle", action: "weapon", value: 6 },
|
||||
{ label: "Shotgun", action: "weapon", value: 9 },
|
||||
@@ -270,10 +317,45 @@ const menuData = {
|
||||
// Toggle states
|
||||
let toggleStates = {
|
||||
godMode: false,
|
||||
invincible: false,
|
||||
superRun: false,
|
||||
noRagdoll: false,
|
||||
neverWanted: false,
|
||||
vehGodMode: false
|
||||
vehGodMode: false,
|
||||
driveOnWater: false,
|
||||
rainbowCar: false,
|
||||
driftMode: false,
|
||||
neonLights: false,
|
||||
flyMode: false,
|
||||
vehShootRPG: false,
|
||||
rainbowSky: false,
|
||||
explosiveAmmo: false
|
||||
};
|
||||
|
||||
// Neon objects storage
|
||||
let neonObjects = [];
|
||||
let neonColor = { r: 255, g: 0, b: 255 }; // Default purple
|
||||
|
||||
// Rainbow color cycling
|
||||
let rainbowHue = 0;
|
||||
let skyColorIndex = 0;
|
||||
|
||||
// Sky colors for selection
|
||||
const skyColors = [
|
||||
{ name: "Default", r: -1, g: -1, b: -1 },
|
||||
{ name: "Red", r: 255, g: 50, b: 50 },
|
||||
{ name: "Blue", r: 50, g: 100, b: 255 },
|
||||
{ name: "Green", r: 50, g: 255, b: 100 },
|
||||
{ name: "Purple", r: 180, g: 50, b: 255 },
|
||||
{ name: "Orange", r: 255, g: 150, b: 50 },
|
||||
{ name: "Pink", r: 255, g: 100, b: 200 },
|
||||
{ name: "Yellow", r: 255, g: 255, b: 100 },
|
||||
{ name: "Cyan", r: 100, g: 255, b: 255 }
|
||||
];
|
||||
|
||||
// Last shot time for RPG vehicle
|
||||
let lastVehShot = 0;
|
||||
|
||||
// ============================================================================
|
||||
// FONT LOADING
|
||||
// ============================================================================
|
||||
@@ -326,7 +408,7 @@ addEventHandler("OnKeyUp", function(event, key, scanCode, mods) {
|
||||
|
||||
if (!menuOpen) return;
|
||||
|
||||
// Navigation
|
||||
// Navigation - simple key handling
|
||||
if (key === SDLK_UP) {
|
||||
navigateUp();
|
||||
} else if (key === SDLK_DOWN) {
|
||||
@@ -391,19 +473,29 @@ function getCurrentMenuItems() {
|
||||
function getNetworkMenuItems() {
|
||||
let items = [
|
||||
{ label: "Refresh Player List", action: "refresh_players" },
|
||||
{ label: "--- Players ---", action: "none" }
|
||||
{ label: "--- Players (" + playerList.length + ") ---", action: "none" }
|
||||
];
|
||||
for (let i = 0; i < playerList.length; i++) {
|
||||
items.push({
|
||||
label: playerList[i].name,
|
||||
action: "submenu",
|
||||
target: "player_options",
|
||||
label: playerList[i].name + " [ID: " + playerList[i].id + "]",
|
||||
action: "teleport_to_player_direct",
|
||||
playerData: playerList[i]
|
||||
});
|
||||
}
|
||||
if (playerList.length === 0) {
|
||||
items.push({ label: "(No players found)", action: "none" });
|
||||
items.push({ label: "(Click Refresh above)", action: "none" });
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
// Refresh player list function
|
||||
function refreshPlayerList() {
|
||||
// Request player list from server
|
||||
triggerNetworkEvent("ModMenu:GetPlayers");
|
||||
showNotification("Refreshing players...");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ACTION HANDLING
|
||||
// ============================================================================
|
||||
@@ -425,6 +517,11 @@ function selectItem() {
|
||||
currentMenu = item.target;
|
||||
selectedIndex = 0;
|
||||
scrollOffset = 0;
|
||||
|
||||
// Auto-refresh player list when entering network menu
|
||||
if (item.target === "network") {
|
||||
refreshPlayerList();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -542,8 +639,7 @@ function selectItem() {
|
||||
break;
|
||||
|
||||
case "refresh_players":
|
||||
triggerNetworkEvent("ModMenu:GetPlayers");
|
||||
showNotification("Refreshing...");
|
||||
refreshPlayerList();
|
||||
break;
|
||||
|
||||
case "teleport_to_player":
|
||||
@@ -553,6 +649,13 @@ function selectItem() {
|
||||
}
|
||||
break;
|
||||
|
||||
case "teleport_to_player_direct":
|
||||
if (item.playerData) {
|
||||
triggerNetworkEvent("ModMenu:TeleportToPlayer", item.playerData.id);
|
||||
showNotification("Teleporting to " + item.playerData.name);
|
||||
}
|
||||
break;
|
||||
|
||||
case "fun_launch":
|
||||
triggerNetworkEvent("ModMenu:Fun", "launch");
|
||||
showNotification("LAUNCH!");
|
||||
@@ -570,6 +673,24 @@ function selectItem() {
|
||||
case "fun_ragdoll":
|
||||
triggerNetworkEvent("ModMenu:Fun", "ragdoll");
|
||||
break;
|
||||
|
||||
case "neon_color":
|
||||
neonColor = item.value;
|
||||
showNotification("Neon color: " + item.label.replace(" Neons", ""));
|
||||
break;
|
||||
|
||||
case "sky_color":
|
||||
skyColorIndex = item.value;
|
||||
if (skyColorIndex === 0) {
|
||||
// Reset to default
|
||||
try {
|
||||
natives.releaseSkybox();
|
||||
} catch(e) {}
|
||||
showNotification("Default sky");
|
||||
} else {
|
||||
showNotification("Sky: " + skyColors[item.value].name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -657,12 +778,14 @@ addNetworkHandler("ModMenu:ExecuteSelfOption", function(option) {
|
||||
showNotification("All weapons given!");
|
||||
break;
|
||||
case "wanted":
|
||||
natives.alterWantedLevel(localPlayer, 0);
|
||||
natives.applyWantedLevelChangeNow(localPlayer);
|
||||
natives.alterWantedLevel(0, 0);
|
||||
natives.applyWantedLevelChangeNow(0);
|
||||
showNotification("Wanted cleared!");
|
||||
break;
|
||||
case "suicide":
|
||||
localPlayer.health = 0;
|
||||
// Kill the player properly using explode head native
|
||||
natives.explodeCharHead(localPlayer);
|
||||
showNotification("Goodbye!");
|
||||
break;
|
||||
}
|
||||
} catch(e) {
|
||||
@@ -684,6 +807,29 @@ addNetworkHandler("ModMenu:ExecuteTeleport", function(x, y, z) {
|
||||
}
|
||||
});
|
||||
|
||||
// Execute teleport to player - get target player position and teleport
|
||||
addNetworkHandler("ModMenu:ExecuteTeleportToPlayer", function(targetId) {
|
||||
if (!localPlayer) return;
|
||||
|
||||
try {
|
||||
// Find the target player in the player list
|
||||
let clients = getClients();
|
||||
for (let i = 0; i < clients.length; i++) {
|
||||
if (clients[i].index == targetId && clients[i].player) {
|
||||
let targetPos = clients[i].player.position;
|
||||
let pos = new Vec3(targetPos.x + 2, targetPos.y, targetPos.z);
|
||||
localPlayer.position = pos;
|
||||
showNotification("Teleported to player!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
showNotification("Player not found");
|
||||
} catch(e) {
|
||||
console.log("[ModMenu] Teleport to player error: " + e);
|
||||
showNotification("Teleport failed");
|
||||
}
|
||||
});
|
||||
|
||||
// Vehicle model hashes for GTA IV
|
||||
const vehicleHashes = {
|
||||
"infernus": 0x18F25AC7,
|
||||
@@ -737,26 +883,42 @@ addNetworkHandler("ModMenu:ExecuteSpawnVehicle", function(vehicleName) {
|
||||
return;
|
||||
}
|
||||
|
||||
let pos = localPlayer.position;
|
||||
let heading = localPlayer.heading || 0;
|
||||
// Request the model first
|
||||
natives.requestModel(modelHash);
|
||||
|
||||
// Spawn position slightly in front of player
|
||||
let spawnX = pos.x + (Math.sin(heading) * 5);
|
||||
let spawnY = pos.y + (Math.cos(heading) * 5);
|
||||
let spawnZ = pos.z;
|
||||
// Wait for model to load then spawn
|
||||
let attempts = 0;
|
||||
let spawnInterval = setInterval(function() {
|
||||
attempts++;
|
||||
if (natives.hasModelLoaded(modelHash)) {
|
||||
clearInterval(spawnInterval);
|
||||
|
||||
// Use native to create car
|
||||
let vehicle = natives.createCar(modelHash, spawnX, spawnY, spawnZ, true);
|
||||
let pos = localPlayer.position;
|
||||
let heading = localPlayer.heading || 0;
|
||||
let spawnPos = new Vec3(pos.x, pos.y, pos.z + 1);
|
||||
|
||||
if (vehicle) {
|
||||
natives.setCarHeading(vehicle, heading);
|
||||
showNotification("Spawned!");
|
||||
} else {
|
||||
showNotification("Failed");
|
||||
}
|
||||
// Create the car
|
||||
let vehicle = natives.createCar(modelHash, spawnPos, true);
|
||||
|
||||
if (vehicle) {
|
||||
natives.setCarHeading(vehicle, heading);
|
||||
// Warp player into the vehicle
|
||||
natives.warpCharIntoCar(localPlayer, vehicle);
|
||||
showNotification("Spawned: " + vehicleName);
|
||||
} else {
|
||||
showNotification("Failed to create");
|
||||
}
|
||||
|
||||
// Mark model as no longer needed
|
||||
natives.markModelAsNoLongerNeeded(modelHash);
|
||||
} else if (attempts > 50) {
|
||||
clearInterval(spawnInterval);
|
||||
showNotification("Model load timeout");
|
||||
}
|
||||
}, 100);
|
||||
} catch(e) {
|
||||
console.log("[ModMenu] Vehicle error: " + e);
|
||||
showNotification("Error");
|
||||
showNotification("Error: " + e);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -780,8 +942,13 @@ addNetworkHandler("ModMenu:ExecuteVehicleOption", function(option) {
|
||||
showNotification("Vehicle flipped!");
|
||||
break;
|
||||
case "nitro":
|
||||
// Boost vehicle forward
|
||||
natives.applyForceToCar(veh, 0, 0, 50, 0, 0, 0);
|
||||
// Boost vehicle forward using velocity
|
||||
let heading = veh.heading || 0;
|
||||
let speed = 50.0;
|
||||
let vx = Math.sin(heading) * speed * -1;
|
||||
let vy = Math.cos(heading) * speed;
|
||||
let vel = new Vec3(vx, vy, 5);
|
||||
veh.velocity = vel;
|
||||
showNotification("NITRO!");
|
||||
break;
|
||||
}
|
||||
@@ -850,8 +1017,25 @@ addNetworkHandler("ModMenu:ExecuteSkinChange", function(skinId) {
|
||||
let skins = [-1667301416, -163448165, 1936355839, -1938475496, 970234525];
|
||||
skinId = skins[Math.floor(Math.random() * skins.length)];
|
||||
}
|
||||
natives.changePlayerModel(localPlayer, skinId);
|
||||
showNotification("Skin changed!");
|
||||
|
||||
// Request the model first
|
||||
natives.requestModel(skinId);
|
||||
|
||||
// Wait for model to load then change skin
|
||||
let attempts = 0;
|
||||
let skinInterval = setInterval(function() {
|
||||
attempts++;
|
||||
if (natives.hasModelLoaded(skinId)) {
|
||||
clearInterval(skinInterval);
|
||||
// Change player model using player index 0
|
||||
natives.changePlayerModel(0, skinId);
|
||||
natives.markModelAsNoLongerNeeded(skinId);
|
||||
showNotification("Skin changed!");
|
||||
} else if (attempts > 50) {
|
||||
clearInterval(skinInterval);
|
||||
showNotification("Skin load failed");
|
||||
}
|
||||
}, 100);
|
||||
} catch(e) {
|
||||
console.log("[ModMenu] Skin change error: " + e);
|
||||
}
|
||||
@@ -969,21 +1153,309 @@ addEventHandler("OnDrawnHUD", function(event) {
|
||||
// TOGGLE EFFECTS
|
||||
// ============================================================================
|
||||
|
||||
// Track last toggle states to only call native when changed
|
||||
let lastGodMode = false;
|
||||
let lastInvincible = false;
|
||||
let lastSuperRun = false;
|
||||
let lastNoRagdoll = false;
|
||||
let lastVehGodMode = false;
|
||||
let lastDriftMode = false;
|
||||
let processCounter = 0;
|
||||
|
||||
addEventHandler("OnProcess", function(event) {
|
||||
if (!localPlayer) return;
|
||||
processCounter++;
|
||||
|
||||
// Player god mode - use invincibility native + health
|
||||
if (toggleStates.godMode !== lastGodMode) {
|
||||
try {
|
||||
natives.setCharInvincible(localPlayer, toggleStates.godMode);
|
||||
} catch(e) {}
|
||||
lastGodMode = toggleStates.godMode;
|
||||
}
|
||||
|
||||
// Keep health topped up in god mode as backup
|
||||
if (toggleStates.godMode) {
|
||||
localPlayer.health = 200;
|
||||
localPlayer.armour = 100;
|
||||
if (localPlayer.health < 200) localPlayer.health = 200;
|
||||
if (localPlayer.armour < 100) localPlayer.armour = 100;
|
||||
}
|
||||
|
||||
// Invincible toggle - separate from god mode, just invincibility
|
||||
if (toggleStates.invincible !== lastInvincible) {
|
||||
try {
|
||||
natives.setCharInvincible(localPlayer, toggleStates.invincible);
|
||||
natives.setCharProofs(localPlayer, toggleStates.invincible, toggleStates.invincible, toggleStates.invincible, toggleStates.invincible, toggleStates.invincible);
|
||||
} catch(e) {}
|
||||
lastInvincible = toggleStates.invincible;
|
||||
}
|
||||
|
||||
// Super Run - increase movement speed
|
||||
if (toggleStates.superRun !== lastSuperRun) {
|
||||
try {
|
||||
if (toggleStates.superRun) {
|
||||
natives.setCharMoveAnimSpeedMultiplier(localPlayer, 3.0);
|
||||
} else {
|
||||
natives.setCharMoveAnimSpeedMultiplier(localPlayer, 1.0);
|
||||
}
|
||||
} catch(e) {}
|
||||
lastSuperRun = toggleStates.superRun;
|
||||
}
|
||||
|
||||
// No Ragdoll - prevent ragdoll
|
||||
if (toggleStates.noRagdoll !== lastNoRagdoll) {
|
||||
try {
|
||||
natives.setPedCanRagdoll(localPlayer, !toggleStates.noRagdoll);
|
||||
} catch(e) {}
|
||||
lastNoRagdoll = toggleStates.noRagdoll;
|
||||
}
|
||||
// Keep preventing ragdoll every frame
|
||||
if (toggleStates.noRagdoll) {
|
||||
try {
|
||||
natives.setPedCanRagdoll(localPlayer, false);
|
||||
// Cancel any active ragdoll
|
||||
if (natives.isPedRagdoll(localPlayer)) {
|
||||
natives.switchPedToAnimated(localPlayer, true);
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// Never wanted - clear wanted level
|
||||
if (toggleStates.neverWanted) {
|
||||
localPlayer.wantedLevel = 0;
|
||||
try {
|
||||
natives.clearWantedLevel(0);
|
||||
} catch(e) {
|
||||
localPlayer.wantedLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (localPlayer.vehicle && toggleStates.vehGodMode) {
|
||||
localPlayer.vehicle.health = 1000;
|
||||
// Vehicle-specific toggles
|
||||
if (localPlayer.vehicle) {
|
||||
let veh = localPlayer.vehicle;
|
||||
|
||||
// Vehicle god mode
|
||||
if (toggleStates.vehGodMode !== lastVehGodMode) {
|
||||
try {
|
||||
natives.setCarCanBeDamaged(veh, !toggleStates.vehGodMode);
|
||||
} catch(e) {}
|
||||
lastVehGodMode = toggleStates.vehGodMode;
|
||||
}
|
||||
if (toggleStates.vehGodMode) {
|
||||
try { natives.fixCar(veh); } catch(e) {}
|
||||
}
|
||||
|
||||
// Drive on water - keep vehicle above water level
|
||||
if (toggleStates.driveOnWater) {
|
||||
try {
|
||||
let pos = veh.position;
|
||||
let waterZ = 0; // Sea level in GTA IV
|
||||
if (pos.z < waterZ + 1) {
|
||||
// Keep car floating on water
|
||||
let vel = veh.velocity;
|
||||
veh.position = new Vec3(pos.x, pos.y, waterZ + 0.8);
|
||||
// Maintain forward momentum but cancel downward
|
||||
if (vel.z < 0) {
|
||||
veh.velocity = new Vec3(vel.x, vel.y, 0);
|
||||
}
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// Rainbow car color - cycle through colors
|
||||
if (toggleStates.rainbowCar && processCounter % 5 === 0) {
|
||||
try {
|
||||
rainbowHue = (rainbowHue + 3) % 360;
|
||||
let rgb = hsvToRgb(rainbowHue, 1, 1);
|
||||
// Use closest GTA color (cycle through color indices)
|
||||
let colorIndex = Math.floor(rainbowHue / 3) % 132;
|
||||
natives.changeCarColour(veh, colorIndex, colorIndex);
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// Drift mode - reduce traction
|
||||
if (toggleStates.driftMode !== lastDriftMode) {
|
||||
try {
|
||||
if (toggleStates.driftMode) {
|
||||
// Make car slide more
|
||||
natives.setCarCanBeVisiblyDamaged(veh, false);
|
||||
}
|
||||
} catch(e) {}
|
||||
lastDriftMode = toggleStates.driftMode;
|
||||
}
|
||||
if (toggleStates.driftMode) {
|
||||
// Apply sideways slip when turning
|
||||
try {
|
||||
let vel = veh.velocity;
|
||||
let speed = Math.sqrt(vel.x * vel.x + vel.y * vel.y);
|
||||
if (speed > 10) {
|
||||
// Add slight sideways force for drift effect
|
||||
let heading = veh.heading || 0;
|
||||
let slideX = Math.cos(heading) * 0.5;
|
||||
let slideY = -Math.sin(heading) * 0.5;
|
||||
veh.velocity = new Vec3(vel.x + slideX, vel.y + slideY, vel.z);
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// Fly mode - WASD controls altitude
|
||||
if (toggleStates.flyMode) {
|
||||
try {
|
||||
let pos = veh.position;
|
||||
let vel = veh.velocity;
|
||||
let heading = veh.heading || 0;
|
||||
|
||||
// Anti-gravity - keep vehicle airborne
|
||||
if (vel.z < 0) {
|
||||
veh.velocity = new Vec3(vel.x, vel.y, vel.z * 0.5);
|
||||
}
|
||||
|
||||
// Lift vehicle
|
||||
veh.position = new Vec3(pos.x, pos.y, pos.z + 0.1);
|
||||
|
||||
// Apply forward force based on heading
|
||||
let forwardX = Math.sin(heading) * -2;
|
||||
let forwardY = Math.cos(heading) * 2;
|
||||
veh.velocity = new Vec3(vel.x + forwardX * 0.1, vel.y + forwardY * 0.1, 0.5);
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// Vehicle shoots RPG
|
||||
if (toggleStates.vehShootRPG) {
|
||||
let now = Date.now();
|
||||
if (now - lastVehShot > 500) { // Fire every 500ms when key held
|
||||
try {
|
||||
let pos = veh.position;
|
||||
let heading = veh.heading || 0;
|
||||
// Shoot from front of vehicle
|
||||
let frontX = pos.x + Math.sin(heading) * -5;
|
||||
let frontY = pos.y + Math.cos(heading) * 5;
|
||||
let fromPos = new Vec3(frontX, frontY, pos.z + 1);
|
||||
let toX = frontX + Math.sin(heading) * -100;
|
||||
let toY = frontY + Math.cos(heading) * 100;
|
||||
let toPos = new Vec3(toX, toY, pos.z + 1);
|
||||
|
||||
// Shoot projectile
|
||||
natives.shootSingleBulletBetweenCoords(
|
||||
fromPos.x, fromPos.y, fromPos.z,
|
||||
toPos.x, toPos.y, toPos.z,
|
||||
100, true, 18, localPlayer, true, true, 100
|
||||
);
|
||||
lastVehShot = now;
|
||||
} catch(e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rainbow sky effect
|
||||
if (toggleStates.rainbowSky && processCounter % 3 === 0) {
|
||||
try {
|
||||
rainbowHue = (rainbowHue + 2) % 360;
|
||||
let rgb = hsvToRgb(rainbowHue, 0.7, 1);
|
||||
natives.setSkyboxTint(rgb.r, rgb.g, rgb.b);
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// Static sky color
|
||||
if (!toggleStates.rainbowSky && skyColorIndex > 0) {
|
||||
try {
|
||||
let color = skyColors[skyColorIndex];
|
||||
natives.setSkyboxTint(color.r, color.g, color.b);
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// Block phone input when menu is open
|
||||
if (menuOpen) {
|
||||
try {
|
||||
natives.destroyMobilePhone();
|
||||
} catch(e) {}
|
||||
}
|
||||
});
|
||||
|
||||
// HSV to RGB conversion for rainbow effects
|
||||
function hsvToRgb(h, s, v) {
|
||||
let r, g, b;
|
||||
let i = Math.floor(h / 60) % 6;
|
||||
let f = h / 60 - i;
|
||||
let p = v * (1 - s);
|
||||
let q = v * (1 - f * s);
|
||||
let t = v * (1 - (1 - f) * s);
|
||||
|
||||
switch (i) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5: r = v; g = p; b = q; break;
|
||||
}
|
||||
|
||||
return {
|
||||
r: Math.round(r * 255),
|
||||
g: Math.round(g * 255),
|
||||
b: Math.round(b * 255)
|
||||
};
|
||||
}
|
||||
|
||||
// Neon lights rendering - draw colored lights under vehicle
|
||||
addEventHandler("OnDrawnHUD", function(event) {
|
||||
if (!toggleStates.neonLights || !localPlayer || !localPlayer.vehicle) return;
|
||||
|
||||
try {
|
||||
let veh = localPlayer.vehicle;
|
||||
let pos = veh.position;
|
||||
|
||||
// Draw light coronas under the car (simulated neons)
|
||||
let offsets = [
|
||||
{ x: 1.5, y: 2, z: -0.3 }, // Front right
|
||||
{ x: -1.5, y: 2, z: -0.3 }, // Front left
|
||||
{ x: 1.5, y: -2, z: -0.3 }, // Rear right
|
||||
{ x: -1.5, y: -2, z: -0.3 }, // Rear left
|
||||
{ x: 0, y: 2.5, z: -0.3 }, // Front center
|
||||
{ x: 0, y: -2.5, z: -0.3 } // Rear center
|
||||
];
|
||||
|
||||
let heading = veh.heading || 0;
|
||||
let cosH = Math.cos(heading);
|
||||
let sinH = Math.sin(heading);
|
||||
|
||||
for (let i = 0; i < offsets.length; i++) {
|
||||
let off = offsets[i];
|
||||
// Rotate offset by vehicle heading
|
||||
let worldX = pos.x + (off.x * cosH - off.y * sinH);
|
||||
let worldY = pos.y + (off.x * sinH + off.y * cosH);
|
||||
let worldZ = pos.z + off.z;
|
||||
|
||||
// Draw corona/light at position
|
||||
natives.drawCorona(
|
||||
worldX, worldY, worldZ,
|
||||
50.0, 0, 0,
|
||||
neonColor.r, neonColor.g, neonColor.b
|
||||
);
|
||||
}
|
||||
} catch(e) {}
|
||||
});
|
||||
|
||||
// Explosive ammo - detect player shooting
|
||||
let lastPlayerPos = null;
|
||||
addEventHandler("OnPedWeaponShoot", function(event, ped, weapon) {
|
||||
if (!toggleStates.explosiveAmmo) return;
|
||||
if (ped !== localPlayer) return;
|
||||
|
||||
try {
|
||||
// Create explosion at impact point
|
||||
// Since we can't get exact impact, create small explosion in front
|
||||
let pos = localPlayer.position;
|
||||
let heading = localPlayer.heading || 0;
|
||||
let dist = 20; // Distance in front
|
||||
let expX = pos.x + Math.sin(heading) * -dist;
|
||||
let expY = pos.y + Math.cos(heading) * dist;
|
||||
|
||||
// Small delay then explode
|
||||
setTimeout(function() {
|
||||
try {
|
||||
natives.addExplosion(expX, expY, pos.z, 0, 2.0, true, false, 0.5);
|
||||
} catch(e) {}
|
||||
}, 100);
|
||||
} catch(e) {}
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -139,9 +139,15 @@ addNetworkHandler("ModMenu:TeleportToPlayer", function(client, targetId) {
|
||||
let clients = getClients();
|
||||
for (let i = 0; i < clients.length; i++) {
|
||||
if (clients[i].index == targetId) {
|
||||
triggerNetworkEvent("ModMenu:Notification", client, "Teleporting to: " + clients[i].name);
|
||||
// Client will handle the actual teleport
|
||||
triggerNetworkEvent("ModMenu:ExecuteTeleportToPlayer", client, targetId);
|
||||
// Get target player's position from server
|
||||
if (clients[i].player) {
|
||||
let targetPos = clients[i].player.position;
|
||||
triggerNetworkEvent("ModMenu:Notification", client, "Teleporting to: " + clients[i].name);
|
||||
// Send position directly to client
|
||||
triggerNetworkEvent("ModMenu:ExecuteTeleport", client, targetPos.x + 2, targetPos.y, targetPos.z);
|
||||
} else {
|
||||
triggerNetworkEvent("ModMenu:Notification", client, "Player not spawned!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -156,13 +162,24 @@ addNetworkHandler("ModMenu:GetPlayers", function(client) {
|
||||
let clients = getClients();
|
||||
let playerList = [];
|
||||
|
||||
console.log("[ModMenu] Getting players, found " + clients.length + " clients");
|
||||
|
||||
for (let i = 0; i < clients.length; i++) {
|
||||
playerList.push({
|
||||
id: clients[i].index,
|
||||
name: clients[i].name
|
||||
});
|
||||
let c = clients[i];
|
||||
// Skip the requesting player (optional - include self for testing)
|
||||
// if (c.index === client.index) continue;
|
||||
|
||||
// Only add players with valid data
|
||||
if (c && c.name) {
|
||||
playerList.push({
|
||||
id: c.index,
|
||||
name: c.name || ("Player " + c.index)
|
||||
});
|
||||
console.log("[ModMenu] Added player: " + c.name + " (ID: " + c.index + ")");
|
||||
}
|
||||
}
|
||||
|
||||
console.log("[ModMenu] Sending " + playerList.length + " players to " + client.name);
|
||||
triggerNetworkEvent("ModMenu:PlayerList", client, playerList);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user