Add self options and fix network player list

Self Options (new):
- Invincible toggle (setCharInvincible + setCharProofs)
- Super Run toggle (setCharMoveAnimSpeedMultiplier at 3x)
- No Ragdoll toggle (setPedCanRagdoll + switchPedToAnimated)

Network Options (fixed):
- Auto-refresh player list when entering network menu
- Show player count in menu header
- Direct teleport to player action (no submenu)
- Server now sends target position directly for teleport
- Added debug logging for player list retrieval
- Show helpful message when no players found
This commit is contained in:
Claude
2026-01-13 14:03:59 +00:00
parent 8e7d49a48c
commit 0e0a001fff
2 changed files with 103 additions and 15 deletions

View File

@@ -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" }
@@ -312,6 +317,9 @@ const menuData = {
// Toggle states
let toggleStates = {
godMode: false,
invincible: false,
superRun: false,
noRagdoll: false,
neverWanted: false,
vehGodMode: false,
driveOnWater: false,
@@ -465,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
// ============================================================================
@@ -499,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;
@@ -616,8 +639,7 @@ function selectItem() {
break;
case "refresh_players":
triggerNetworkEvent("ModMenu:GetPlayers");
showNotification("Refreshing...");
refreshPlayerList();
break;
case "teleport_to_player":
@@ -627,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!");
@@ -1124,8 +1153,11 @@ addEventHandler("OnDrawnHUD", function(event) {
// TOGGLE EFFECTS
// ============================================================================
// Track last god mode state to only call native when changed
// 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;
@@ -1134,7 +1166,7 @@ addEventHandler("OnProcess", function(event) {
if (!localPlayer) return;
processCounter++;
// Player god mode - use invincibility native
// Player god mode - use invincibility native + health
if (toggleStates.godMode !== lastGodMode) {
try {
natives.setCharInvincible(localPlayer, toggleStates.godMode);
@@ -1148,6 +1180,45 @@ addEventHandler("OnProcess", function(event) {
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) {
try {

View File

@@ -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);
});