Fix mod menu client-side drawing API errors

- Remove gta.setCursorEnabled (not available in GTAC)
- Use gui.showCursor with proper checks
- Fix drawing functions to use natives API with correct parameters
- Add fallback drawing methods with try-catch
- Use GTA IV native text/rect drawing functions
This commit is contained in:
Claude
2026-01-10 23:28:55 +00:00
parent dad2741754
commit fee097c7db

View File

@@ -10,7 +10,7 @@ let currentMenu = "main";
let selectedIndex = 0; let selectedIndex = 0;
let menuStack = []; // For back navigation let menuStack = []; // For back navigation
// Menu colors // Menu colors (RGBA)
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),
@@ -40,7 +40,6 @@ let scrollOffset = 0;
// Player list cache // Player list cache
let playerList = []; let playerList = [];
let lastPlayerUpdate = 0;
// Vehicle handling values // Vehicle handling values
let handlingMods = { let handlingMods = {
@@ -78,8 +77,8 @@ const menuData = {
{ label: "Max Health & Armor", action: "self_max" }, { label: "Max Health & Armor", action: "self_max" },
{ label: "Give All Weapons", action: "self_weapons" }, { label: "Give All Weapons", action: "self_weapons" },
{ label: "Clear Wanted Level", action: "self_wanted" }, { label: "Clear Wanted Level", action: "self_wanted" },
{ label: "Never Wanted", action: "toggle", target: "neverWanted", state: false },
{ 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: "Infinite Ammo", action: "toggle", target: "infiniteAmmo", state: false }, { label: "Infinite Ammo", action: "toggle", target: "infiniteAmmo", state: false },
{ label: "Super Jump", action: "toggle", target: "superJump", state: false }, { label: "Super Jump", action: "toggle", target: "superJump", state: false },
{ label: "Fast Run", action: "toggle", target: "fastRun", state: false }, { label: "Fast Run", action: "toggle", target: "fastRun", state: false },
@@ -308,7 +307,6 @@ const menuData = {
items: [ items: [
{ label: ">> Refresh Player List <<", action: "refresh_players" }, { label: ">> Refresh Player List <<", action: "refresh_players" },
{ label: "--- Players Online ---", action: "none" } { label: "--- Players Online ---", action: "none" }
// Players will be added dynamically
] ]
}, },
@@ -332,8 +330,7 @@ const menuData = {
{ label: "Westdyke", action: "teleport", value: { x: -1745.0, y: 1157.0, z: 25.0 } }, { label: "Westdyke", action: "teleport", value: { x: -1745.0, y: 1157.0, z: 25.0 } },
{ label: "-- Special --", action: "none" }, { label: "-- Special --", action: "none" },
{ label: "Helipad (High)", action: "teleport", value: { x: -290.0, y: -400.0, z: 81.0 } }, { 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 } }, { label: "Tower Top", action: "teleport", value: { x: 237.0, y: 1002.0, z: 200.0 } }
{ label: "Waypoint (Marker)", action: "teleport_waypoint" }
] ]
}, },
@@ -424,9 +421,14 @@ addEventHandler("OnKeyUp", function(event, key, scanCode, mods) {
selectedIndex = 0; selectedIndex = 0;
scrollOffset = 0; scrollOffset = 0;
menuStack = []; menuStack = [];
gta.setCursorEnabled(true); // Show cursor - use gui if available
if (typeof gui !== "undefined" && gui.showCursor) {
gui.showCursor(true, true);
}
} else { } else {
gta.setCursorEnabled(false); if (typeof gui !== "undefined" && gui.showCursor) {
gui.showCursor(false, false);
}
} }
return; return;
} }
@@ -443,7 +445,6 @@ addEventHandler("OnKeyUp", function(event, key, scanCode, mods) {
} else if (key === SDLK_BACKSPACE || key === SDLK_ESCAPE) { } else if (key === SDLK_BACKSPACE || key === SDLK_ESCAPE) {
goBack(); goBack();
} else if (key === SDLK_LEFT) { } else if (key === SDLK_LEFT) {
// For sliders/adjustable options
adjustValue(-1); adjustValue(-1);
} else if (key === SDLK_RIGHT) { } else if (key === SDLK_RIGHT) {
adjustValue(1); adjustValue(1);
@@ -490,7 +491,9 @@ function goBack() {
scrollOffset = prev.scroll; scrollOffset = prev.scroll;
} else { } else {
menuOpen = false; menuOpen = false;
gta.setCursorEnabled(false); if (typeof gui !== "undefined" && gui.showCursor) {
gui.showCursor(false, false);
}
} }
} }
@@ -523,6 +526,9 @@ function getNetworkMenuItems() {
// ACTION HANDLING // ACTION HANDLING
// ============================================================================ // ============================================================================
// Selected player for network options
let selectedPlayer = null;
function selectItem() { function selectItem() {
let items = getCurrentMenuItems(); let items = getCurrentMenuItems();
let item = items[selectedIndex]; let item = items[selectedIndex];
@@ -531,7 +537,6 @@ function selectItem() {
switch (item.action) { switch (item.action) {
case "submenu": case "submenu":
if (item.target === "player_options" && item.playerData) { if (item.target === "player_options" && item.playerData) {
// Store selected player for network options
selectedPlayer = item.playerData; selectedPlayer = item.playerData;
openPlayerMenu(item.playerData); openPlayerMenu(item.playerData);
} else { } else {
@@ -559,11 +564,6 @@ function selectItem() {
showNotification("Teleporting to: " + item.label); showNotification("Teleporting to: " + item.label);
break; break;
case "teleport_waypoint":
triggerNetworkEvent("ModMenu:TeleportWaypoint");
showNotification("Teleporting to waypoint...");
break;
case "self_health": case "self_health":
triggerNetworkEvent("ModMenu:SelfOption", "health"); triggerNetworkEvent("ModMenu:SelfOption", "health");
showNotification("Health restored!"); showNotification("Health restored!");
@@ -725,7 +725,6 @@ function selectItem() {
} }
function adjustValue(direction) { function adjustValue(direction) {
// For handling options when using left/right keys
let items = getCurrentMenuItems(); let items = getCurrentMenuItems();
let item = items[selectedIndex]; let item = items[selectedIndex];
if (!item) return; if (!item) return;
@@ -738,11 +737,7 @@ function adjustValue(direction) {
} }
} }
// Selected player for network options
let selectedPlayer = null;
function openPlayerMenu(playerData) { function openPlayerMenu(playerData) {
// Create dynamic player options menu
menuData.player_options = { menuData.player_options = {
title: playerData.name, title: playerData.name,
items: [ items: [
@@ -772,7 +767,7 @@ addNetworkHandler("ModMenu:Notification", function(message) {
}); });
// ============================================================================ // ============================================================================
// RENDERING // RENDERING - Using correct GTAC drawing API
// ============================================================================ // ============================================================================
addEventHandler("OnDrawnHUD", function(event) { addEventHandler("OnDrawnHUD", function(event) {
@@ -787,11 +782,11 @@ addEventHandler("OnDrawnHUD", function(event) {
let totalHeight = menu.headerHeight + (visibleCount * menu.itemHeight) + menu.footerHeight; let totalHeight = menu.headerHeight + (visibleCount * menu.itemHeight) + menu.footerHeight;
// Draw background // Draw background
drawing.drawRectangle(null, menu.x - 5, menu.y - 5, menu.width + 10, totalHeight + 10, colors.background, colors.background, 0, 0, 0, false); drawRect(menu.x - 5, menu.y - 5, menu.width + 10, totalHeight + 10, colors.background);
// Draw header // Draw header
drawing.drawRectangle(null, menu.x, menu.y, menu.width, menu.headerHeight, colors.header, colors.header, 0, 0, 0, false); drawRect(menu.x, menu.y, menu.width, menu.headerHeight, colors.header);
drawing.drawText(title, menu.x + menu.width / 2, menu.y + 8, menu.width, menu.headerHeight, colors.headerText, 1.0, 1, true, false, false, true); drawText(title, menu.x + menu.width / 2, menu.y + 10, colors.headerText, true, 1.0);
// Draw items // Draw items
let yPos = menu.y + menu.headerHeight; let yPos = menu.y + menu.headerHeight;
@@ -802,46 +797,102 @@ addEventHandler("OnDrawnHUD", function(event) {
let textColor = isSelected ? colors.itemTextSelected : colors.itemText; let textColor = isSelected ? colors.itemTextSelected : colors.itemText;
// Draw item background // Draw item background
drawing.drawRectangle(null, menu.x, yPos, menu.width, menu.itemHeight, bgColor, bgColor, 0, 0, 0, false); drawRect(menu.x, yPos, menu.width, menu.itemHeight, bgColor);
// Draw item text // Build label with state indicators
let label = item.label; let label = item.label;
// Add toggle state indicator
if (item.action === "toggle") { if (item.action === "toggle") {
let state = toggleStates[item.target]; let state = toggleStates[item.target];
label += state ? " [ON]" : " [OFF]"; label += state ? " [ON]" : " [OFF]";
} }
// Add handling value indicator
if (item.action === "handling" && handlingMods[item.target] !== undefined) { if (item.action === "handling" && handlingMods[item.target] !== undefined) {
label += " [" + handlingMods[item.target].toFixed(1) + "]"; label += " [" + handlingMods[item.target].toFixed(1) + "]";
} }
// Add submenu indicator
if (item.action === "submenu") { if (item.action === "submenu") {
label += " >>"; label += " >>";
} }
drawing.drawText(label, menu.x + 15, yPos + 8, menu.width - 30, menu.itemHeight, textColor, 0.9, 1, true, false, false, false); drawText(label, menu.x + 15, yPos + 8, textColor, false, 0.9);
yPos += menu.itemHeight; yPos += menu.itemHeight;
} }
// Draw footer // Draw footer
drawing.drawRectangle(null, menu.x, yPos, menu.width, menu.footerHeight, colors.footer, colors.footer, 0, 0, 0, false); 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);
// Footer text with controls // Draw scroll indicator
let footerText = "UP/DOWN: Navigate | ENTER: Select | BACKSPACE: Back";
drawing.drawText(footerText, menu.x + menu.width / 2, yPos + 7, menu.width, menu.footerHeight, colors.footerText, 0.6, 1, true, false, false, true);
// Draw scroll indicator if needed
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;
drawing.drawText(scrollText, menu.x + menu.width - 70, menu.y + 12, 60, 20, colors.subText, 0.7, 1, true, false, false, false); drawText(scrollText, menu.x + menu.width - 50, menu.y + 12, colors.subText, false, 0.7);
} }
}); });
// Helper drawing functions using native drawing
function drawRect(x, y, width, height, colour) {
// Use natives for drawing rectangles
if (typeof natives !== "undefined" && natives.drawRect) {
// GTA IV native drawing - normalized coordinates (0-1)
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) {
// Use natives for drawing text
if (typeof natives !== "undefined" && natives.setTextScale) {
let screenW = game.width || 1920;
let screenH = game.height || 1080;
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
}
}
}
// ============================================================================ // ============================================================================
// NOTIFICATIONS // NOTIFICATIONS
// ============================================================================ // ============================================================================
@@ -854,12 +905,9 @@ function showNotification(text) {
time: Date.now(), time: Date.now(),
duration: 3000 duration: 3000
}); });
// Clean old notifications
let now = Date.now();
notifications = notifications.filter(n => now - n.time < n.duration);
} }
// Draw notifications
addEventHandler("OnDrawnHUD", function(event) { addEventHandler("OnDrawnHUD", function(event) {
let now = Date.now(); let now = Date.now();
let yPos = 200; let yPos = 200;
@@ -873,15 +921,17 @@ addEventHandler("OnDrawnHUD", function(event) {
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, alpha + 55);
drawing.drawRectangle(null, 10, yPos, 300, 30, bgColor, bgColor, 0, 0, 0, false); drawRect(10, yPos, 300, 30, bgColor);
drawing.drawText(notif.text, 20, yPos + 6, 280, 25, textColor, 0.8, 1, true, false, false, false); drawText(notif.text, 20, yPos + 6, textColor, false, 0.8);
yPos += 35; yPos += 35;
} }
} }
// Clean expired // Clean expired notifications
notifications = notifications.filter(n => now - n.time < n.duration); notifications = notifications.filter(function(n) {
return now - n.time < n.duration;
});
}); });
// ============================================================================ // ============================================================================
@@ -902,15 +952,10 @@ addEventHandler("OnProcess", function(event) {
localPlayer.wantedLevel = 0; localPlayer.wantedLevel = 0;
} }
// Super Jump (handled via natives if available) // Vehicle God Mode
// Fast Run (handled via natives if available) if (localPlayer.vehicle && toggleStates.vehGodMode) {
// Drift Mode & Vehicle God Mode
if (localPlayer.vehicle) {
if (toggleStates.vehGodMode) {
localPlayer.vehicle.health = 1000; localPlayer.vehicle.health = 1000;
} }
}
}); });
// ============================================================================ // ============================================================================
@@ -922,8 +967,4 @@ addEventHandler("OnResourceStart", function(event, resource) {
console.log("[ModMenu] Press F5 to open the menu"); console.log("[ModMenu] Press F5 to open the menu");
}); });
addEventHandler("OnLocalPlayerSpawn", function(event) { console.log("[ModMenu] Client loaded - Press F5 to open menu!");
showNotification("Press F5 to open Mod Menu");
});
console.log("[ModMenu] Client script loaded - Press F5 to open menu!");