Jump to content

[HELP] Car spawning system not working.


Moony

Recommended Posts

Hello, everybody!

I'm following this tutorial to make a GUI with a car spawning function.

Copy/pasting everything works up until the gridlist. The click doesn't. Could there be a mistake?

I recreated the script on my own following step by step:
- Client-side -

Spoiler

local vehiclesTable = {
	["Sparrow"] = 469,
	["Stuntplane"] = 513,
	["BF-400"] = 581,
	["Freeway"] = 463,
	["Speeder"] = 452,
	["Jester"] = 559,
	["Sabre"] = 475,
	["Police Ranger"] = 599,
	["Utility Van"] = 552,
	["Tug"] = 583
}

function vehSelection()
	vehList = guiCreateWindow(0.06, 0.33, 0.31, 0.30, "Vehiculos", true)
	guiWindowSetSizable(vehList, false)

	botonCrear = guiCreateButton(149, 260, 101, 31, "Crear", false, vehList)
	lista = guiCreateGridList(0.06, 0.12, 0.87, 0.69, true, vehList)
	guiGridListAddColumn(lista, "Coches", 0.9)

	guiSetVisible(vehList,false)
	
	populateGridlist()
end
addEventHandler ("onClientResourceStart", getRootElement(), vehSelection)

function showVehicleSelection()
	if (guiGetVisible(vehList) == false) then
	guiSetVisible (vehList, true)
	showCursor (true)
	else
	guiSetVisible (vehList, false)
	showCursor (false)
	end
end
addCommandHandler("veh",showVehicleSelection)

function populateGridlist()
	-- loop through the table
	for name,vehicle in pairs(vehiclesTable) do
		-- add a new row to the gridlist
		local row = guiGridListAddRow(lista)

		-- set the text in the first column to the vehicle name
		guiGridListSetItemText(lista,row,1,name,false,false)
		-- set the text in the second column to the vehicle type
		guiGridListSetItemText(lista,row,2,getVehicleType(vehicle),false,false)
		
		-- set the data for gridlist slot as the vehicle id
		guiGridListSetItemData(lista,row,1,tostring(vehicle))
	end
end

function createVehicleHandler(button,state)
	if button == "left" and state == "up" then
		-- get the selected item in the gridlist
		local row,col = guiGridListGetSelectedItem(lista)
		
		-- if something is selected
		if row and col and row ~= -1 and col ~= -1 then
			-- get the vehicle id data from the gridlist that is selected
			local selected = guiGridListGetItemData(lista,row,col)
			
			-- make sure the vehicle id is a number not a string
			selected = tonumber(selected)
						
			-- get the players position and rotation
			local rotz = getPedRotation(getLocalPlayer())
			local x,y,z = getElementPosition(getLocalPlayer())
			-- find the position directly infront of the player
			x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3)
			y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3)
			
			if selected and x and y and z then
				-- trigger the server
				triggerServerEvent("createVehicleFromGUI",getRootElement(),selected,x,y,z)
				
				-- hide the gui and the cursor
				guiSetVisible(windowVehicleSelection,false)
				showCursor(false,false)
			else
				outputChatBox("Invalid arguments.")
			end
		else
			-- otherwise, output a message to the player
			outputChatBox("Please select a vehicle.")
		end
	end
end

 

And here is the problematic part:

Spoiler

function createVehicleHandler(button,state)
	if button == "left" and state == "up" then
		-- get the selected item in the gridlist
		local row,col = guiGridListGetSelectedItem(lista)
		
		-- if something is selected
		if row and col and row ~= -1 and col ~= -1 then
			-- get the vehicle id data from the gridlist that is selected
			local selected = guiGridListGetItemData(glista,row,col)
			
			-- make sure the vehicle id is a number not a string
			selected = tonumber(selected)
						
			-- get the players position and rotation
			local rotz = getPedRotation(getLocalPlayer())
			local x,y,z = getElementPosition(getLocalPlayer())
			-- find the position directly infront of the player
			x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3)
			y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3)
			
			if selected and x and y and z then
				-- trigger the server
				triggerServerEvent("createVehicleFromGUI",getRootElement(),selected,x,y,z)
				
				-- hide the gui and the cursor
				guiSetVisible(lista,false)
				showCursor(false,false)
			else
				outputChatBox("Invalid arguments.")
			end
		else
			-- otherwise, output a message to the player
			outputChatBox("Please select a vehicle.")
		end
	end
end

 

The GUI elements are the same. The only thing that changes are the names. Naturally, it should work by simply replacing the names. However, I believe there might be a mistake on the original script.
With everything as it is, I can show and hide the GUI, and click on any vehicle. If I purposely trigger an output, nothing happens.

So, waddaya think?

Link to comment

Dear Moony,

let me ask you a simple question because I have not yet tried this amazing tutorial (it is pretty long but looks thorough, thx for sharing!).

Do you have the following script line after your createVehicleHandler function definition:

addEventHandler("onClientGUIDoubleClick",lista,createVehicleHandler,false)

 

  • Thanks 1
Link to comment
10 minutes ago, The_GTA said:

Do you have the following script line after your createVehicleHandler function definition:


addEventHandler("onClientGUIDoubleClick",lista,createVehicleHandler,false)

 

Though I did forget to add the event handler (which is actually 'onClientGUIClick'), adding it doesn't fix the issue.

addEventHandler("onClientGUIClick", botonCrear, "up", createVehicleHandler,false)

DB 3: expected element at argument 2 is nil. Line number is the event handler I just added.
I tried removing the "up" argument, but nothing changes.

Link to comment

Sorry for not investigating this tutorial that thoughly but you have to add the code inside the vehSelection function. Otherwise it does not work because the GUI has not been created yet.

-- Put createVehicleHandler here.
-- Put populateGridlist here
-- Etc.

function vehSelection()
	vehList = guiCreateWindow(0.06, 0.33, 0.31, 0.30, "Vehiculos", true)
	guiWindowSetSizable(vehList, false)

	botonCrear = guiCreateButton(149, 260, 101, 31, "Crear", false, vehList)
	lista = guiCreateGridList(0.06, 0.12, 0.87, 0.69, true, vehList)
	guiGridListAddColumn(lista, "Coches", 0.9)

	guiSetVisible(vehList,false)
	
	populateGridlist()
  
    addEventHandler("onClientGUIClick",botonCrear,createVehicleHandler,false)
end

-- Etc.

Explanation: if you put code inside the onClientResourceStart event handler then the code is called after all scripts have been loaded/executed. This is useful if you want to wait until MTA has loaded all custom resource functions into _G before starting your code. Putting code into the event handler is not a requirement but a recommendation.

  • Thanks 1
Link to comment

It works now.

I have a doubt.
I have a very basic script that pops up a help memo (similar to the F9 help menu):

function openHelp (key, keystate)
	if (guiGetVisible(helper) == false) then
	guiSetVisible (helper, true)
	showCursor (true)
	else
	guiSetVisible (helper, false)
	showCursor (false)
	end
end
bindKey("F9", "down", openHelp)

Above it, the elements:

helper = guiCreateWindow(0.19, 0.20, 0.63, 0.64, "-- 'El Final de la Bala' --", true)
guiWindowSetSizable(helper, false)

tabs = guiCreateTabPanel(0.03, 0.05, 0.94, 0.91, true, helper)

welcomeTab = guiCreateTab("Bienvenido", tabs)
welcomeMemo = guiCreateMemo(0.01, 0.04, 0.98, 0.93, welcome, true, welcomeTab)
guiMemoSetReadOnly (welcomeMemo, true)

rulesTab = guiCreateTab("Reglas", tabs)
rulesMemo = guiCreateMemo(0.01, 0.04, 0.98, 0.93, rules, true, rulesTab)
guiMemoSetReadOnly (rulesMemo, true)

functionsTab = guiCreateTab("Funciones", tabs)
functionsMemo = guiCreateMemo(0.01, 0.04, 0.98, 0.93, functions, true, functionsTab)
guiMemoSetReadOnly (functionsMemo, true)

locationsTab = guiCreateTab("Locaciones", tabs)
locationsMemo = guiCreateMemo(0.01, 0.04, 0.98, 0.93, locations, true, locationsTab)
guiMemoSetReadOnly (locationsMemo, true)

guiSetVisible(helper, false)

These elements are placed as seen: without a 'function' header, nor any kind of event handler. However, this works just fine. The player can click through each tab and open/close the memo.
Why is it not the same with the spawn panel? Why does it fail when the 'onClientGUIClick' is outside the creation function? I still don't quite get the difference. I had imagined that the event call would be called regardless of its position.

 

Link to comment
41 minutes ago, Moony said:

These elements are placed as seen: without a 'function' header, nor any kind of event handler. However, this works just fine. The player can click through each tab and open/close the memo.

Why is it not the same with the spawn panel? Why does it fail when the 'onClientGUIClick' is outside the creation function? I still don't quite get the difference. I had imagined that the event call would be called regardless of its position.

 

Great to hear that it works now :)

Let me try to explain to you the difference between the creation function and without a 'function' header.

First, let's see the facts. The creation function is called when the "onClientResourceStart" event is triggered. Your placed elements outside of a function are executed when the script is loaded. I think you have to understand that the GUI variables ("lista", etc) are only available after the creation code has been executed.

If you want to convert the tutorial script to your approach without a 'function' header, you can do the following (edited your script from the top post):

 
local vehiclesTable = {
	["Sparrow"] = 469,
	["Stuntplane"] = 513,
	["BF-400"] = 581,
	["Freeway"] = 463,
	["Speeder"] = 452,
	["Jester"] = 559,
	["Sabre"] = 475,
	["Police Ranger"] = 599,
	["Utility Van"] = 552,
	["Tug"] = 583
}

function showVehicleSelection()
	if (guiGetVisible(vehList) == false) then
	guiSetVisible (vehList, true)
	showCursor (true)
	else
	guiSetVisible (vehList, false)
	showCursor (false)
	end
end
addCommandHandler("veh",showVehicleSelection)

function populateGridlist()
	-- loop through the table
	for name,vehicle in pairs(vehiclesTable) do
		-- add a new row to the gridlist
		local row = guiGridListAddRow(lista)

		-- set the text in the first column to the vehicle name
		guiGridListSetItemText(lista,row,1,name,false,false)
		-- set the text in the second column to the vehicle type
		guiGridListSetItemText(lista,row,2,getVehicleType(vehicle),false,false)
		
		-- set the data for gridlist slot as the vehicle id
		guiGridListSetItemData(lista,row,1,tostring(vehicle))
	end
end

function createVehicleHandler(button,state)
	if button == "left" and state == "up" then
		-- get the selected item in the gridlist
		local row,col = guiGridListGetSelectedItem(lista)
		
		-- if something is selected
		if row and col and row ~= -1 and col ~= -1 then
			-- get the vehicle id data from the gridlist that is selected
			local selected = guiGridListGetItemData(lista,row,col)
			
			-- make sure the vehicle id is a number not a string
			selected = tonumber(selected)
						
			-- get the players position and rotation
			local rotz = getPedRotation(getLocalPlayer())
			local x,y,z = getElementPosition(getLocalPlayer())
			-- find the position directly infront of the player
			x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3)
			y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3)
			
			if selected and x and y and z then
				-- trigger the server
				triggerServerEvent("createVehicleFromGUI",getRootElement(),selected,x,y,z)
				
				-- hide the gui and the cursor
				guiSetVisible(windowVehicleSelection,false)
				showCursor(false,false)
			else
				outputChatBox("Invalid arguments.")
			end
		else
			-- otherwise, output a message to the player
			outputChatBox("Please select a vehicle.")
		end
	end
end

-- Create the GUI here.
do
	vehList = guiCreateWindow(0.06, 0.33, 0.31, 0.30, "Vehiculos", true)
	guiWindowSetSizable(vehList, false)

	botonCrear = guiCreateButton(149, 260, 101, 31, "Crear", false, vehList)
	lista = guiCreateGridList(0.06, 0.12, 0.87, 0.69, true, vehList)
	guiGridListAddColumn(lista, "Coches", 0.9)

	guiSetVisible(vehList,false)
	
	populateGridlist()
	
	addEventHandler("onClientGUIClick", botonCrear, createVehicleHandler, false)
end

Both ways have no significant differences in the functionality. You could say that too many event handlers pollute the event system. It is good practice to try to implement it both ways. But I usually resort to without a 'function' header in my code. Then you have to put global functions in a specific order: if function A depends on function B, then function B has to be written earlier in the code than function A.

I hope that my explanation has helped you understand more of Lua and MTA :) 

Edited by The_GTA
  • Thanks 1
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...