Fix mod menu issues: vehicle spawn, god mode, skins, and phone

- Fix vehicle spawning to use Vec3 for position parameter
- Warp player into spawned vehicle automatically
- Fix skin change to use player index 0 for changePlayerModel
- Fix suicide using explodeCharHead native
- Fix god mode using setCharInvincible native properly
- Fix vehicle god mode using setCarCanBeDamaged native
- Rename "Indestructible" to "God Mode" in vehicle options
- Fix nitro boost using vehicle velocity instead of force
- Add ExecuteTeleportToPlayer handler for network teleport
- Disable phone when menu is open using setPlayerControlForTextChat
- Block UP arrow from triggering phone while menu is open
This commit is contained in:
Claude
2026-01-13 09:42:47 +00:00
parent 3443ed5a17
commit 33cbef2eb4

View File

@@ -190,7 +190,7 @@ 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: "Indestructible", 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" }
] ]
}, },
@@ -317,24 +317,36 @@ addEventHandler("OnKeyUp", function(event, key, scanCode, mods) {
menuStack = []; menuStack = [];
// Show cursor and DISABLE controls (second param = false disables controls) // Show cursor and DISABLE controls (second param = false disables controls)
gui.showCursor(true, false); gui.showCursor(true, false);
// Disable phone
natives.setPlayerControlForTextChat(0, false);
} else { } else {
// Hide cursor and ENABLE controls (second param = true enables controls) // Hide cursor and ENABLE controls (second param = true enables controls)
gui.showCursor(false, true); gui.showCursor(false, true);
// Re-enable phone
natives.setPlayerControlForTextChat(0, true);
} }
return; return;
} }
if (!menuOpen) return; if (!menuOpen) return;
// Navigation // Block phone popup - consume UP key event when menu is open
if (key === SDLK_UP) { if (key === SDLK_UP) {
navigateUp(); navigateUp();
event.preventDefault = true;
return;
} else if (key === SDLK_DOWN) { } else if (key === SDLK_DOWN) {
navigateDown(); navigateDown();
event.preventDefault = true;
return;
} else if (key === SDLK_RETURN || key === SDLK_KP_ENTER) { } else if (key === SDLK_RETURN || key === SDLK_KP_ENTER) {
selectItem(); selectItem();
event.preventDefault = true;
return;
} else if (key === SDLK_BACKSPACE || key === SDLK_ESCAPE) { } else if (key === SDLK_BACKSPACE || key === SDLK_ESCAPE) {
goBack(); goBack();
event.preventDefault = true;
return;
} }
}); });
@@ -657,12 +669,14 @@ addNetworkHandler("ModMenu:ExecuteSelfOption", function(option) {
showNotification("All weapons given!"); showNotification("All weapons given!");
break; break;
case "wanted": case "wanted":
natives.alterWantedLevel(localPlayer, 0); natives.alterWantedLevel(0, 0);
natives.applyWantedLevelChangeNow(localPlayer); natives.applyWantedLevelChangeNow(0);
showNotification("Wanted cleared!"); showNotification("Wanted cleared!");
break; break;
case "suicide": case "suicide":
localPlayer.health = 0; // Kill the player properly using explode head native
natives.explodeCharHead(localPlayer);
showNotification("Goodbye!");
break; break;
} }
} catch(e) { } catch(e) {
@@ -684,6 +698,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 // Vehicle model hashes for GTA IV
const vehicleHashes = { const vehicleHashes = {
"infernus": 0x18F25AC7, "infernus": 0x18F25AC7,
@@ -740,16 +777,16 @@ addNetworkHandler("ModMenu:ExecuteSpawnVehicle", function(vehicleName) {
let pos = localPlayer.position; let pos = localPlayer.position;
let heading = localPlayer.heading || 0; let heading = localPlayer.heading || 0;
// Spawn position slightly in front of player // Spawn position at player location
let spawnX = pos.x + (Math.sin(heading) * 5); let spawnPos = new Vec3(pos.x, pos.y, pos.z);
let spawnY = pos.y + (Math.cos(heading) * 5);
let spawnZ = pos.z;
// Use native to create car // Use native to create car with Vec3 position
let vehicle = natives.createCar(modelHash, spawnX, spawnY, spawnZ, true); let vehicle = natives.createCar(modelHash, spawnPos, true);
if (vehicle) { if (vehicle) {
natives.setCarHeading(vehicle, heading); natives.setCarHeading(vehicle, heading);
// Warp player into the vehicle
natives.warpCharIntoCar(localPlayer, vehicle);
showNotification("Spawned!"); showNotification("Spawned!");
} else { } else {
showNotification("Failed"); showNotification("Failed");
@@ -780,8 +817,13 @@ addNetworkHandler("ModMenu:ExecuteVehicleOption", function(option) {
showNotification("Vehicle flipped!"); showNotification("Vehicle flipped!");
break; break;
case "nitro": case "nitro":
// Boost vehicle forward // Boost vehicle forward using velocity
natives.applyForceToCar(veh, 0, 0, 50, 0, 0, 0); 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!"); showNotification("NITRO!");
break; break;
} }
@@ -850,7 +892,8 @@ addNetworkHandler("ModMenu:ExecuteSkinChange", function(skinId) {
let skins = [-1667301416, -163448165, 1936355839, -1938475496, 970234525]; let skins = [-1667301416, -163448165, 1936355839, -1938475496, 970234525];
skinId = skins[Math.floor(Math.random() * skins.length)]; skinId = skins[Math.floor(Math.random() * skins.length)];
} }
natives.changePlayerModel(localPlayer, skinId); // GTA IV uses changePlayerModel with player index 0
natives.changePlayerModel(0, skinId);
showNotification("Skin changed!"); showNotification("Skin changed!");
} catch(e) { } catch(e) {
console.log("[ModMenu] Skin change error: " + e); console.log("[ModMenu] Skin change error: " + e);
@@ -969,20 +1012,44 @@ addEventHandler("OnDrawnHUD", function(event) {
// TOGGLE EFFECTS // TOGGLE EFFECTS
// ============================================================================ // ============================================================================
// Track last god mode state to only call native when changed
let lastGodMode = false;
let lastVehGodMode = false;
addEventHandler("OnProcess", function(event) { addEventHandler("OnProcess", function(event) {
if (!localPlayer) return; if (!localPlayer) return;
// Player god mode - use invincibility native
if (toggleStates.godMode !== lastGodMode) {
natives.setCharInvincible(localPlayer, toggleStates.godMode);
lastGodMode = toggleStates.godMode;
}
// Keep health topped up in god mode as backup
if (toggleStates.godMode) { if (toggleStates.godMode) {
localPlayer.health = 200; if (localPlayer.health < 200) localPlayer.health = 200;
localPlayer.armour = 100; if (localPlayer.armour < 100) localPlayer.armour = 100;
} }
// Never wanted - clear wanted level
if (toggleStates.neverWanted) { if (toggleStates.neverWanted) {
localPlayer.wantedLevel = 0; natives.clearWantedLevel(0);
} }
if (localPlayer.vehicle && toggleStates.vehGodMode) { // Vehicle god mode
localPlayer.vehicle.health = 1000; if (localPlayer.vehicle) {
if (toggleStates.vehGodMode !== lastVehGodMode) {
natives.setCarCanBeDamaged(localPlayer.vehicle, !toggleStates.vehGodMode);
lastVehGodMode = toggleStates.vehGodMode;
}
if (toggleStates.vehGodMode) {
natives.fixCar(localPlayer.vehicle);
}
}
// Disable phone when menu is open
if (menuOpen) {
natives.setPlayerControlForTextChat(0, false);
} }
}); });