diff --git a/resources/modmenu/client.js b/resources/modmenu/client.js index dd9feef..f37163f 100644 --- a/resources/modmenu/client.js +++ b/resources/modmenu/client.js @@ -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 { diff --git a/resources/modmenu/server.js b/resources/modmenu/server.js index 6c69d6a..8de2c14 100644 --- a/resources/modmenu/server.js +++ b/resources/modmenu/server.js @@ -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); });