Jump to content

RACE Map Panel script by Grok


Recommended Posts

Hey there!

I told you before in some other post that I used Grok for scripting. He nearly pulled off a very nice Racing map panel. However there is a slight problem - when you buy the map, money goes away (money is inside the script too I think when you win a race it gives you certain amount) and map doesn't play or its not set. If you guys have any idea how can it be fixed, lmk. By the way, to get this kinda script you need around 2 hours on Grok for him to properly understand MTA scripting

Codes:

server.lua

local moneyFile = "money.xml"
local nextMapQueue = nil -- Store the next map if race resource isn't running

-- Load player's money from XML
function loadPlayerMoney(player)
    local serial = getPlayerSerial(player)
    local xml = xmlLoadFile(moneyFile) or xmlCreateFile(moneyFile, "money")
    if not xml then
        outputDebugString("Failed to load or create money.xml", 1)
        return
    end
    local node = xmlFindChild(xml, serial, 0) or xmlCreateChild(xml, serial)
    local money = tonumber(xmlNodeGetValue(node)) or 0
    setElementData(player, "money", money)
    xmlSaveFile(xml)
    xmlUnloadFile(xml)
end

-- Save player's money to XML
function savePlayerMoney(player)
    local serial = getPlayerSerial(player)
    local money = getElementData(player, "money") or 0
    local xml = xmlLoadFile(moneyFile) or xmlCreateFile(moneyFile, "money")
    if not xml then
        outputDebugString("Failed to load or create money.xml", 1)
        return
    end
    local node = xmlFindChild(xml, serial, 0) or xmlCreateChild(xml, serial)
    xmlNodeSetValue(node, tostring(money))
    xmlSaveFile(xml)
    xmlUnloadFile(xml)
end

-- Handle player join
addEventHandler("onPlayerJoin", root, function()
    loadPlayerMoney(source)
end)

-- Handle player quit
addEventHandler("onPlayerQuit", root, function()
    savePlayerMoney(source)
end)

-- Fetch all race map resources
function getMapList()
    local mapList = {}
    local resources = getResources()
    if not resources then
        outputDebugString("Failed to get resources - check ACL permissions for 'function.getResources'!", 1)
        return mapList
    end

    local includedCount = 0
    local excludedCount = 0

    for i, resource in ipairs(resources) do
        local resName = getResourceName(resource)
        -- Skip system resources, our own resource, and known gamemodes
        if resName ~= "race_map_panel" and 
           not resName:find("^%[") and 
           resName ~= "csrw" and 
           resName ~= "race" and 
           resName ~= "play" and 
           resName ~= "assault" and 
           resName ~= "destructionderby" and 
           resName ~= "ctf" and 
           resName ~= "as-cliff" and 
           resName ~= "ctf-goldcove" then
            local metaPath = ":" .. resName .. "/meta.xml"
            local metaFile = xmlLoadFile(metaPath)
            if metaFile then
                -- Check if the resource is a gamemode
                local infoNode = xmlFindChild(metaFile, "info", 0)
                local isGamemode = false
                if infoNode then
                    local resType = xmlNodeGetAttribute(infoNode, "type")
                    if resType and resType:lower() == "gamemode" then
                        isGamemode = true
                        excludedCount = excludedCount + 1
                    end
                end

                if not isGamemode then
                    local isRaceMap = false
                    local hasMapFile = false
                    local gamemodesValue = nil

                    -- Check for <map> element with a .map file
                    local mapNode = xmlFindChild(metaFile, "map", 0)
                    if mapNode then
                        local mapSrc = xmlNodeGetAttribute(mapNode, "src")
                        if mapSrc and mapSrc:find("%.map$") then
                            hasMapFile = true
                        end
                    end

                    -- Check for #gamemodes setting
                    local settingsNode = xmlFindChild(metaFile, "settings", 0)
                    if settingsNode then
                        local settingNodes = xmlNodeGetChildren(settingsNode)
                        for j, setting in ipairs(settingNodes) do
                            local settingName = xmlNodeGetAttribute(setting, "name")
                            local settingValue = xmlNodeGetAttribute(setting, "value")
                            if settingName == "#gamemodes" then
                                gamemodesValue = settingValue
                                -- Parse the gamemodes value (e.g., '[ "race" ]' or '[ "race", "assault" ]')
                                local gamemodes = settingValue:gsub("%[", ""):gsub("%]", ""):gsub('"', ""):gsub(" ", "")
                                local gamemodeList = split(gamemodes, ",")
                                if #gamemodeList == 1 and gamemodeList[1]:lower() == "race" then
                                    isRaceMap = true
                                end
                                break
                            end
                        end
                    end

                    -- If no #gamemodes setting, assume it's a race map if the name suggests it
                    if hasMapFile and not gamemodesValue then
                        if resName:find("^%[race%]") or resName:find("race-") then
                            isRaceMap = true
                        end
                    end

                    -- Include or exclude the map
                    if hasMapFile and isRaceMap then
                        includedCount = includedCount + 1
                        local mapInfo = {
                            resourceName = resName, -- Store the actual resource name
                            name = resName, -- Default to resource name
                            author = "Unknown",
                            cost = math.random(300, 1000) -- Random cost
                        }
                        
                        if infoNode then
                            local author = xmlNodeGetAttribute(infoNode, "author")
                            local name = xmlNodeGetAttribute(infoNode, "name")
                            if author then mapInfo.author = author end
                            if name then mapInfo.name = name end
                        end
                        
                        table.insert(mapList, mapInfo)
                    else
                        excludedCount = excludedCount + 1
                    end
                end
                xmlUnloadFile(metaFile)
            else
                excludedCount = excludedCount + 1
            end
        else
            excludedCount = excludedCount + 1
        end
    end
    outputDebugString("INFO: Total race maps found: " .. #mapList .. " (Included: " .. includedCount .. ", Excluded: " .. excludedCount .. ")", 3)
    return mapList
end

-- Send map list and player money to client
addEvent("requestMapList", true)
addEventHandler("requestMapList", root, function()
    local mapList = getMapList()
    local player = source
    local money = getElementData(player, "money") or 0
    triggerClientEvent(player, "receiveMapList", player, mapList)
    triggerClientEvent(player, "receivePlayerMoney", player, money)
end)

-- Send player money to client
addEvent("requestPlayerMoney", true)
addEventHandler("requestPlayerMoney", root, function()
    local player = source
    local money = getElementData(player, "money") or 0
    triggerClientEvent(player, "receivePlayerMoney", player, money)
end)

-- Function to set the next map
function setNextMapIfPossible(mapResource, mapDisplayName, player)
    local raceResource = getResourceFromName("race")
    outputDebugString("DEBUG: Attempting to set next map to " .. getResourceName(mapResource) .. " for player " .. getPlayerName(player), 3)
    if raceResource and getResourceState(raceResource) == "running" then
        outputDebugString("DEBUG: Race resource is running, calling queueNextMap", 3)
        local success, errorMsg = pcall(function()
            return exports.race:queueNextMap(mapResource) -- Updated to queueNextMap
        end)
        if success and errorMsg then
            outputDebugString("DEBUG: Successfully queued next map to " .. getResourceName(mapResource) .. " for player " .. getPlayerName(player), 3)
            outputChatBox(getPlayerName(player) .. " has queued the next map to '" .. mapDisplayName .. "'!", root, 255, 255, 0)
            nextMapQueue = nil -- Clear the queue since the map was set
            return true
        else
            outputDebugString("DEBUG: Failed to queue next map to " .. getResourceName(mapResource) .. " - queueNextMap failed: " .. (errorMsg or "unknown error"), 1)
            outputChatBox("Failed to queue the next map (queueNextMap failed). Please try again.", player, 255, 0, 0)
            return false
        end
    else
        outputDebugString("DEBUG: Race resource not running (state: " .. (raceResource and getResourceState(raceResource) or "not found") .. "). Queuing map " .. getResourceName(mapResource), 1)
        nextMapQueue = { resource = mapResource, displayName = mapDisplayName, player = player }
        outputChatBox("Race gamemode not running. Your map '" .. mapDisplayName .. "' will be set as the next map when the gamemode starts.", player, 255, 255, 0)
        return false
    end
end

-- Handle map purchase and set as next map
addEvent("onPlayerBuyMap", true)
addEventHandler("onPlayerBuyMap", root, function(mapResourceName, mapDisplayName, cost)
    local player = source
    local money = getElementData(player, "money") or 0
    if money >= cost then
        setElementData(player, "money", money - cost)
        savePlayerMoney(player)
        
        -- Set the purchased map as the next map
        local mapResource = getResourceFromName(mapResourceName)
        if mapResource then
            setNextMapIfPossible(mapResource, mapDisplayName, player)
        else
            outputDebugString("DEBUG: Map resource " .. mapResourceName .. " not found for player " .. getPlayerName(player), 1)
            outputChatBox("Map resource not found. Please try again.", player, 255, 0, 0)
        end
        
        triggerClientEvent(player, "onMapPurchaseSuccess", player, mapDisplayName)
        outputChatBox("You now have $" .. (money - cost), player, 0, 255, 0)
    else
        triggerClientEvent(player, "onMapPurchaseFail", player)
    end
end)

-- Try to set the queued map when the race gamemode starts
addEventHandler("onResourceStart", root, function(startedResource)
    local resourceName = getResourceName(startedResource)
    if resourceName == "race" and nextMapQueue then
        outputDebugString("DEBUG: Race resource started. Attempting to set queued map " .. getResourceName(nextMapQueue.resource), 3)
        setNextMapIfPossible(nextMapQueue.resource, nextMapQueue.displayName, nextMapQueue.player)
    end
end)

-- Try to set the queued map when the current map ends
addEvent("onRaceEnd", true)
addEventHandler("onRaceEnd", root, function(winner)
    outputDebugString("DEBUG: onRaceEnd triggered with winner " .. getPlayerName(winner), 3)
    local player = winner
    local money = getElementData(player, "money") or 0
    local reward = 1000
    setElementData(player, "money", money + reward)
    savePlayerMoney(player)
    outputChatBox("You won the race and earned $" .. reward .. "! Total: $" .. (money + reward), player, 0, 255, 0)
    triggerClientEvent(player, "receivePlayerMoney", player, money + reward)

    -- Try to set the queued map if it exists
    if nextMapQueue then
        outputDebugString("DEBUG: Race ended. Attempting to set queued map " .. getResourceName(nextMapQueue.resource), 3)
        setNextMapIfPossible(nextMapQueue.resource, nextMapQueue.displayName, nextMapQueue.player)
    end
end)

-- Handle race win detected by client
addEvent("onClientPlayerRaceWin", true)
addEventHandler("onClientPlayerRaceWin", root, function()
    outputDebugString("DEBUG: onClientPlayerRaceWin triggered for " .. getPlayerName(source), 3)
    local player = source
    local money = getElementData(player, "money") or 0
    local reward = 1000
    setElementData(player, "money", money + reward)
    savePlayerMoney(player)
    outputChatBox("You won the race and earned $" .. reward .. "! Total: $" .. (money + reward), player, 0, 255, 0)
    triggerClientEvent(player, "receivePlayerMoney", player, money + reward)
end)

-- Hook into possible race gamemode events (for debugging)
addEvent("onPlayerFinish", true)
addEventHandler("onPlayerFinish", root, function(rank)
    outputDebugString("DEBUG: onPlayerFinish triggered for " .. getPlayerName(source) .. " with rank " .. rank, 3)
    if rank == 1 then
        local player = source
        local money = getElementData(player, "money") or 0
        local reward = 1000
        setElementData(player, "money", money + reward)
        savePlayerMoney(player)
        outputChatBox("You won the race and earned $" .. reward .. "! Total: $" .. (money + reward), player, 0, 255, 0)
        triggerClientEvent(player, "receivePlayerMoney", player, money + reward)
    end
end)

addEvent("onPlayerWin", true)
addEventHandler("onPlayerWin", root, function()
    outputDebugString("DEBUG: onPlayerWin triggered for " .. getPlayerName(source), 3)
    local player = source
    local money = getElementData(player, "money") or 0
    local reward = 1000
    setElementData(player, "money", money + reward)
    savePlayerMoney(player)
    outputChatBox("You won the race and earned $" .. reward .. "! Total: $" .. (money + reward), player, 0, 255, 0)
    triggerClientEvent(player, "receivePlayerMoney", player, money + reward)
end)

addEvent("onPlayerRaceFinish", true)
addEventHandler("onPlayerRaceFinish", root, function(rank)
    outputDebugString("DEBUG: onPlayerRaceFinish triggered for " .. getPlayerName(source) .. " with rank " .. rank, 3)
    if rank == 1 then
        local player = source
        local money = getElementData(player, "money") or 0
        local reward = 1000
        setElementData(player, "money", money + reward)
        savePlayerMoney(player)
        outputChatBox("You won the race and earned $" .. reward .. "! Total: $" .. (money + reward), player, 0, 255, 0)
        triggerClientEvent(player, "receivePlayerMoney", player, money + reward)
    end
end)

addEvent("onPlayerVictory", true)
addEventHandler("onPlayerVictory", root, function()
    outputDebugString("DEBUG: onPlayerVictory triggered for " .. getPlayerName(source), 3)
    local player = source
    local money = getElementData(player, "money") or 0
    local reward = 1000
    setElementData(player, "money", money + reward)
    savePlayerMoney(player)
    outputChatBox("You won the race and earned $" .. reward .. "! Total: $" .. (money + reward), player, 0, 255, 0)
    triggerClientEvent(player, "receivePlayerMoney", player, money + reward)
end)

addEvent("onPlayerWinDD", true)
addEventHandler("onPlayerWinDD", root, function()
    outputDebugString("DEBUG: onPlayerWinDD triggered for " .. getPlayerName(source), 3)
    local player = source
    local money = getElementData(player, "money") or 0
    local reward = 1000
    setElementData(player, "money", money + reward)
    savePlayerMoney(player)
    outputChatBox("You won the race and earned $" .. reward .. "! Total: $" .. (money + reward), player, 0, 255, 0)
    triggerClientEvent(player, "receivePlayerMoney", player, money + reward)
end)

-- Debug command to simulate a race win (admin only)
addCommandHandler("winrace", function(player)
    if not hasObjectPermissionTo(player, "general.adminpanel") then
        outputChatBox("You do not have permission to use this command!", player, 255, 0, 0)
        return
    end
    outputDebugString("DEBUG: Simulating race win for " .. getPlayerName(player), 3)
    local money = getElementData(player, "money") or 0
    local reward = 1000
    setElementData(player, "money", money + reward)
    savePlayerMoney(player)
    outputChatBox("You won the race and earned $" .. reward .. "! Total: $" .. (money + reward), player, 0, 255, 0)
    triggerClientEvent(player, "receivePlayerMoney", player, money + reward)
end)

-- Debug command to check money
addCommandHandler("money", function(player)
    local money = getElementData(player, "money") or 0
    outputChatBox("Your money: $" .. money, player, 255, 255, 0)
end)

client.lua

local screenW, screenH = guiGetScreenSize()
local mapPanelVisible = false
local selectedMap = nil
local maps = {}
local playerMoney = 0

-- Create the map panel GUI
function createMapPanel()
    if mapPanelVisible then return end
    
    mapPanelWindow = guiCreateWindow((screenW - 400) / 2, (screenH - 300) / 2, 400, 300, "Map Panel", false)
    guiWindowSetSizable(mapPanelWindow, false)
    
    mapGrid = guiCreateGridList(10, 30, 380, 150, false, mapPanelWindow)
    guiGridListAddColumn(mapGrid, "Map Name", 0.5)
    guiGridListAddColumn(mapGrid, "Author", 0.3)
    guiGridListAddColumn(mapGrid, "Cost", 0.2)
    
    for i, map in ipairs(maps) do
        local row = guiGridListAddRow(mapGrid)
        guiGridListSetItemText(mapGrid, row, 1, map.name, false, false)
        guiGridListSetItemText(mapGrid, row, 2, map.author or "Unknown", false, false)
        guiGridListSetItemText(mapGrid, row, 3, tostring(map.cost), false, false)
    end
    
    moneyLabel = guiCreateLabel(10, 190, 380, 20, "Your Money: $" .. playerMoney, false, mapPanelWindow)
    infoLabel = guiCreateLabel(10, 210, 380, 20, "Select a map to see details.", false, mapPanelWindow)
    buyButton = guiCreateButton(10, 230, 180, 30, "Buy Map", false, mapPanelWindow)
    quitButton = guiCreateButton(200, 230, 180, 30, "Quit", false, mapPanelWindow)
    
    addEventHandler("onClientGUIClick", mapGrid, onMapSelect, false)
    addEventHandler("onClientGUIClick", buyButton, buyMap, false)
    addEventHandler("onClientGUIClick", quitButton, closeMapPanel, false)
    
    mapPanelVisible = true
    showCursor(true) -- Show the cursor when the panel opens
    if #maps == 0 then
        outputChatBox("No maps found on the server!", 255, 0, 0)
    end
end

-- Handle map selection
function onMapSelect()
    local row = guiGridListGetSelectedItem(mapGrid)
    if row ~= -1 then
        selectedMap = maps[row + 1]
        guiSetText(infoLabel, "Name: " .. selectedMap.name .. " | Author: " .. (selectedMap.author or "Unknown") .. " | Cost: $" .. selectedMap.cost)
    end
end

-- Buy the selected map
function buyMap()
    if not selectedMap then
        outputChatBox("Please select a map first!", 255, 0, 0)
        return
    end
    triggerServerEvent("onPlayerBuyMap", localPlayer, selectedMap.resourceName, selectedMap.name, selectedMap.cost)
end

-- Close the panel
function closeMapPanel()
    if mapPanelWindow then
        destroyElement(mapPanelWindow)
        mapPanelVisible = false
        selectedMap = nil
        showCursor(false) -- Hide the cursor when the panel closes
    end
end

-- Toggle the map panel with F3
addEventHandler("onClientResourceStart", resourceRoot, function()
    bindKey("f3", "down", function()
        if mapPanelVisible then
            closeMapPanel()
        else
            triggerServerEvent("requestMapList", localPlayer)
        end
    end)
    setTimer(function()
        outputChatBox("Press F3 to open the Map Panel!", 255, 255, 0)
    end, 5000, 1)
end)

-- Receive map list from server
addEvent("receiveMapList", true)
addEventHandler("receiveMapList", root, function(mapList)
    maps = mapList
    outputChatBox("Received " .. #maps .. " maps from server.", 0, 255, 0)
    createMapPanel()
end)

-- Receive player money from server
addEvent("receivePlayerMoney", true)
addEventHandler("receivePlayerMoney", root, function(money)
    playerMoney = money
    if moneyLabel and isElement(moneyLabel) then
        guiSetText(moneyLabel, "Your Money: $" .. playerMoney)
    end
end)

-- Handle successful purchase response from server
addEvent("onMapPurchaseSuccess", true)
addEventHandler("onMapPurchaseSuccess", root, function(mapDisplayName)
    outputChatBox("Map '" .. mapDisplayName .. "' purchased successfully and set as the next map!", 0, 255, 0)
    triggerServerEvent("requestPlayerMoney", localPlayer)
    closeMapPanel()
end)

-- Handle insufficient funds
addEvent("onMapPurchaseFail", true)
addEventHandler("onMapPurchaseFail", root, function()
    outputChatBox("Not enough money to buy this map!", 255, 0, 0)
end)

-- Detect "You have won the race!" message
addEventHandler("onClientChatMessage", root, function(message)
    if message == "You have won the race!" then
        triggerServerEvent("onClientPlayerRaceWin", localPlayer)
    end
end)

It also creates money.xml which stores money, and I tried AI to understand that I wanted to pick up the money from the users account (when you add it via admin panel for example) but I couldn't. I'm also wondering if you guys could make this script better anyhow?

I recommend debugscript 3 too

Thanks for any help.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...